)
type Rule struct {
- rule string
- lineno int
+ rule string
+ loc string // file name & line number
}
func (r Rule) String() string {
- return fmt.Sprintf("rule %q at line %d", r.rule, r.lineno)
+ return fmt.Sprintf("rule %q at %s", r.rule, r.loc)
}
// parse returns the matching part of the rule, additional conditions, and the result.
if op[len(op)-1] == ')' {
op = op[:len(op)-1] // rule has only opcode, e.g. (ConstNil) -> ...
}
+ loc := fmt.Sprintf("%s.rules:%d", arch.name, lineno)
if isBlock(op, arch) {
- blockrules[op] = append(blockrules[op], Rule{rule: rule, lineno: lineno})
+ blockrules[op] = append(blockrules[op], Rule{rule: rule, loc: loc})
} else {
- oprules[op] = append(oprules[op], Rule{rule: rule, lineno: lineno})
+ oprules[op] = append(oprules[op], Rule{rule: rule, loc: loc})
}
rule = ""
}
log.Fatalf("scanner failed: %v\n", err)
}
if unbalanced(rule) {
- log.Fatalf("unbalanced rule at line %d: %v\n", lineno, rule)
+ log.Fatalf("%s.rules:%d: unbalanced rule: %v\n", arch.name, lineno, rule)
}
// Order all the ops.
fmt.Fprintf(w, "// result: %s\n", result)
fmt.Fprintf(w, "for {\n")
- genMatch(w, arch, match)
+ genMatch(w, arch, match, rule.loc)
if cond != "" {
fmt.Fprintf(w, "if !(%s) {\nbreak\n}\n", cond)
}
- genResult(w, arch, result)
+ genResult(w, arch, result, rule.loc)
if *genLog {
- fmt.Fprintf(w, "fmt.Println(\"rewrite %s.rules:%d\")\n", arch.name, rule.lineno)
+ fmt.Fprintf(w, "fmt.Println(\"rewrite %s\")\n", rule.loc)
}
fmt.Fprintf(w, "return true\n")
if s[1] != "nil" {
fmt.Fprintf(w, "v := b.Control\n")
if strings.Contains(s[1], "(") {
- genMatch0(w, arch, s[1], "v", map[string]struct{}{}, false)
+ genMatch0(w, arch, s[1], "v", map[string]struct{}{}, false, rule.loc)
} else {
fmt.Fprintf(w, "%s := b.Control\n", s[1])
}
if t[1] == "nil" {
fmt.Fprintf(w, "b.SetControl(nil)\n")
} else {
- fmt.Fprintf(w, "b.SetControl(%s)\n", genResult0(w, arch, t[1], new(int), false, false))
+ fmt.Fprintf(w, "b.SetControl(%s)\n", genResult0(w, arch, t[1], new(int), false, false, rule.loc))
}
if len(newsuccs) < len(succs) {
fmt.Fprintf(w, "b.Succs = b.Succs[:%d]\n", len(newsuccs))
}
if *genLog {
- fmt.Fprintf(w, "fmt.Println(\"rewrite %s.rules:%d\")\n", arch.name, rule.lineno)
+ fmt.Fprintf(w, "fmt.Println(\"rewrite %s\")\n", rule.loc)
}
fmt.Fprintf(w, "return true\n")
}
}
-func genMatch(w io.Writer, arch arch, match string) {
- genMatch0(w, arch, match, "v", map[string]struct{}{}, true)
+func genMatch(w io.Writer, arch arch, match string, loc string) {
+ genMatch0(w, arch, match, "v", map[string]struct{}{}, true, loc)
}
-func genMatch0(w io.Writer, arch arch, match, v string, m map[string]struct{}, top bool) {
+func genMatch0(w io.Writer, arch arch, match, v string, m map[string]struct{}, top bool, loc string) {
if match[0] != '(' || match[len(match)-1] != ')' {
panic("non-compound expr in genMatch0: " + match)
}
// contained in () or {}.
s := split(match[1 : len(match)-1]) // remove parens, then split
+ // Find op record
+ var op opData
+ for _, x := range genericOps {
+ if x.name == s[0] {
+ op = x
+ break
+ }
+ }
+ for _, x := range arch.ops {
+ if x.name == s[0] {
+ op = x
+ break
+ }
+ }
+ if op.name == "" {
+ log.Fatalf("%s: unknown op %s", loc, s[0])
+ }
+
// check op
if !top {
fmt.Fprintf(w, "if %s.Op != %s {\nbreak\n}\n", v, opName(s[0], arch))
}
} else if a[0] == '[' {
// auxint restriction
+ switch op.aux {
+ case "Bool", "Int8", "Int16", "Int32", "Int64", "Int128", "Float32", "Float64", "SymOff", "SymValAndOff", "SymInt32":
+ default:
+ log.Fatalf("%s: op %s %s can't have auxint", loc, op.name, op.aux)
+ }
x := a[1 : len(a)-1] // remove []
if !isVariable(x) {
// code
}
}
} else if a[0] == '{' {
- // auxint restriction
+ // aux restriction
+ switch op.aux {
+ case "String", "Sym", "SymOff", "SymValAndOff", "SymInt32":
+ default:
+ log.Fatalf("%s: op %s %s can't have aux", loc, op.name, op.aux)
+ }
x := a[1 : len(a)-1] // remove {}
if !isVariable(x) {
// code
argname = fmt.Sprintf("%s_%d", v, argnum)
}
fmt.Fprintf(w, "%s := %s.Args[%d]\n", argname, v, argnum)
- genMatch0(w, arch, a, argname, m, false)
+ genMatch0(w, arch, a, argname, m, false, loc)
argnum++
}
}
-
- variableLength := false
- for _, op := range genericOps {
- if op.name == s[0] && op.argLength == -1 {
- variableLength = true
- break
- }
- }
- for _, op := range arch.ops {
- if op.name == s[0] && op.argLength == -1 {
- variableLength = true
- break
- }
- }
- if variableLength {
+ if op.argLength == -1 {
fmt.Fprintf(w, "if len(%s.Args) != %d {\nbreak\n}\n", v, argnum)
+ } else if int(op.argLength) != argnum {
+ log.Fatalf("%s: op %s should have %d args, has %d", loc, op.name, op.argLength, argnum)
}
}
-func genResult(w io.Writer, arch arch, result string) {
+func genResult(w io.Writer, arch arch, result string, loc string) {
move := false
if result[0] == '@' {
// parse @block directive
result = s[1]
move = true
}
- genResult0(w, arch, result, new(int), true, move)
+ genResult0(w, arch, result, new(int), true, move, loc)
}
-func genResult0(w io.Writer, arch arch, result string, alloc *int, top, move bool) string {
+func genResult0(w io.Writer, arch arch, result string, alloc *int, top, move bool, loc string) string {
// TODO: when generating a constant result, use f.constVal to avoid
// introducing copies just to clean them up again.
if result[0] != '(' {
s := split(result[1 : len(result)-1]) // remove parens, then split
+ // Find op record
+ var op opData
+ for _, x := range genericOps {
+ if x.name == s[0] {
+ op = x
+ break
+ }
+ }
+ for _, x := range arch.ops {
+ if x.name == s[0] {
+ op = x
+ break
+ }
+ }
+ if op.name == "" {
+ log.Fatalf("%s: unknown op %s", loc, s[0])
+ }
+
// Find the type of the variable.
var opType string
var typeOverride bool
fmt.Fprintf(w, "v.AddArg(%s)\n", v)
}
}
+ argnum := 0
for _, a := range s[1:] {
if a[0] == '<' {
// type restriction, handled above
} else if a[0] == '[' {
// auxint restriction
+ switch op.aux {
+ case "Bool", "Int8", "Int16", "Int32", "Int64", "Int128", "Float32", "Float64", "SymOff", "SymValAndOff", "SymInt32":
+ default:
+ log.Fatalf("%s: op %s %s can't have auxint", loc, op.name, op.aux)
+ }
x := a[1 : len(a)-1] // remove []
fmt.Fprintf(w, "%s.AuxInt = %s\n", v, x)
} else if a[0] == '{' {
// aux restriction
+ switch op.aux {
+ case "String", "Sym", "SymOff", "SymValAndOff", "SymInt32":
+ default:
+ log.Fatalf("%s: op %s %s can't have aux", loc, op.name, op.aux)
+ }
x := a[1 : len(a)-1] // remove {}
fmt.Fprintf(w, "%s.Aux = %s\n", v, x)
} else {
// regular argument (sexpr or variable)
- x := genResult0(w, arch, a, alloc, false, move)
+ x := genResult0(w, arch, a, alloc, false, move, loc)
fmt.Fprintf(w, "%s.AddArg(%s)\n", v, x)
+ argnum++
}
}
+ if op.argLength != -1 && int(op.argLength) != argnum {
+ log.Fatalf("%s: op %s should have %d args, has %d", loc, op.name, op.argLength, argnum)
+ }
return v
}
return true
}
case BlockAMD64NE:
- // match: (NE (TESTB (SETL cmp)) yes no)
+ // match: (NE (TESTB (SETL cmp) (SETL cmp)) yes no)
// cond:
// result: (LT cmp yes no)
for {
break
}
cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SETL {
+ break
+ }
+ if cmp != v_1.Args[0] {
+ break
+ }
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64LT
b.Succs[1] = no
return true
}
- // match: (NE (TESTB (SETLE cmp)) yes no)
+ // match: (NE (TESTB (SETLE cmp) (SETLE cmp)) yes no)
// cond:
// result: (LE cmp yes no)
for {
break
}
cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SETLE {
+ break
+ }
+ if cmp != v_1.Args[0] {
+ break
+ }
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64LE
b.Succs[1] = no
return true
}
- // match: (NE (TESTB (SETG cmp)) yes no)
+ // match: (NE (TESTB (SETG cmp) (SETG cmp)) yes no)
// cond:
// result: (GT cmp yes no)
for {
break
}
cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SETG {
+ break
+ }
+ if cmp != v_1.Args[0] {
+ break
+ }
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64GT
b.Succs[1] = no
return true
}
- // match: (NE (TESTB (SETGE cmp)) yes no)
+ // match: (NE (TESTB (SETGE cmp) (SETGE cmp)) yes no)
// cond:
// result: (GE cmp yes no)
for {
break
}
cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SETGE {
+ break
+ }
+ if cmp != v_1.Args[0] {
+ break
+ }
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64GE
b.Succs[1] = no
return true
}
- // match: (NE (TESTB (SETEQ cmp)) yes no)
+ // match: (NE (TESTB (SETEQ cmp) (SETEQ cmp)) yes no)
// cond:
// result: (EQ cmp yes no)
for {
break
}
cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SETEQ {
+ break
+ }
+ if cmp != v_1.Args[0] {
+ break
+ }
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64EQ
b.Succs[1] = no
return true
}
- // match: (NE (TESTB (SETNE cmp)) yes no)
+ // match: (NE (TESTB (SETNE cmp) (SETNE cmp)) yes no)
// cond:
// result: (NE cmp yes no)
for {
break
}
cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SETNE {
+ break
+ }
+ if cmp != v_1.Args[0] {
+ break
+ }
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64NE
b.Succs[1] = no
return true
}
- // match: (NE (TESTB (SETB cmp)) yes no)
+ // match: (NE (TESTB (SETB cmp) (SETB cmp)) yes no)
// cond:
// result: (ULT cmp yes no)
for {
break
}
cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SETB {
+ break
+ }
+ if cmp != v_1.Args[0] {
+ break
+ }
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64ULT
b.Succs[1] = no
return true
}
- // match: (NE (TESTB (SETBE cmp)) yes no)
+ // match: (NE (TESTB (SETBE cmp) (SETBE cmp)) yes no)
// cond:
// result: (ULE cmp yes no)
for {
break
}
cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SETBE {
+ break
+ }
+ if cmp != v_1.Args[0] {
+ break
+ }
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64ULE
b.Succs[1] = no
return true
}
- // match: (NE (TESTB (SETA cmp)) yes no)
+ // match: (NE (TESTB (SETA cmp) (SETA cmp)) yes no)
// cond:
// result: (UGT cmp yes no)
for {
break
}
cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SETA {
+ break
+ }
+ if cmp != v_1.Args[0] {
+ break
+ }
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64UGT
b.Succs[1] = no
return true
}
- // match: (NE (TESTB (SETAE cmp)) yes no)
+ // match: (NE (TESTB (SETAE cmp) (SETAE cmp)) yes no)
// cond:
// result: (UGE cmp yes no)
for {
break
}
cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SETAE {
+ break
+ }
+ if cmp != v_1.Args[0] {
+ break
+ }
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64UGE
b.Succs[1] = no
return true
}
- // match: (NE (TESTB (SETGF cmp)) yes no)
+ // match: (NE (TESTB (SETGF cmp) (SETGF cmp)) yes no)
// cond:
// result: (UGT cmp yes no)
for {
break
}
cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SETGF {
+ break
+ }
+ if cmp != v_1.Args[0] {
+ break
+ }
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64UGT
b.Succs[1] = no
return true
}
- // match: (NE (TESTB (SETGEF cmp)) yes no)
+ // match: (NE (TESTB (SETGEF cmp) (SETGEF cmp)) yes no)
// cond:
// result: (UGE cmp yes no)
for {
break
}
cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SETGEF {
+ break
+ }
+ if cmp != v_1.Args[0] {
+ break
+ }
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64UGE
b.Succs[1] = no
return true
}
- // match: (NE (TESTB (SETEQF cmp)) yes no)
+ // match: (NE (TESTB (SETEQF cmp) (SETEQF cmp)) yes no)
// cond:
// result: (EQF cmp yes no)
for {
break
}
cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SETEQF {
+ break
+ }
+ if cmp != v_1.Args[0] {
+ break
+ }
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64EQF
b.Succs[1] = no
return true
}
- // match: (NE (TESTB (SETNEF cmp)) yes no)
+ // match: (NE (TESTB (SETNEF cmp) (SETNEF cmp)) yes no)
// cond:
// result: (NEF cmp yes no)
for {
break
}
cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SETNEF {
+ break
+ }
+ if cmp != v_1.Args[0] {
+ break
+ }
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64NEF