mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: start implementing strongly typed aux and auxint fields
Right now the Aux and AuxInt fields of ssa.Values are typed as
interface{} and int64, respectively. Each rule that uses these values
must cast them to the type they actually are (*obj.LSym, or int32, or
ValAndOff, etc.), use them, and then cast them back to interface{} or
int64.
We know for each opcode what the types of the Aux and AuxInt fields
should be. So let's modify the rule generator to declare the types to
be what we know they should be, autoconverting to and from the generic
types for us. That way we can make the rules more type safe.
It's difficult to make a single CL for this, so I've coopted the "=>"
token to indicate a rule that is strongly typed. "->" rules are
processed as before. That will let us migrate a few rules at a time in
separate CLs. Hopefully we can reach a state where all rules are
strongly typed and we can drop the distinction.
This CL changes just a few rules to get a feel for what this
transition would look like.
I've decided not to put explicit types in the rules. I think it
makes the rules somewhat clearer, but definitely more verbose.
In particular, the passthrough rules that don't modify the fields
in question are verbose for no real reason.
Change-Id: I63a1b789ac5702e7caf7934cd49f784235d1d73d
Reviewed-on: https://go-review.googlesource.com/c/go/+/190197
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
parent
a1550d3ca3
commit
28157b3292
10 changed files with 234 additions and 99 deletions
|
|
@ -6658,21 +6658,21 @@ func fieldIdx(n *Node) int {
|
||||||
// It also exports a bunch of compiler services for the ssa backend.
|
// It also exports a bunch of compiler services for the ssa backend.
|
||||||
type ssafn struct {
|
type ssafn struct {
|
||||||
curfn *Node
|
curfn *Node
|
||||||
strings map[string]interface{} // map from constant string to data symbols
|
strings map[string]*obj.LSym // map from constant string to data symbols
|
||||||
scratchFpMem *Node // temp for floating point register / memory moves on some architectures
|
scratchFpMem *Node // temp for floating point register / memory moves on some architectures
|
||||||
stksize int64 // stack size for current frame
|
stksize int64 // stack size for current frame
|
||||||
stkptrsize int64 // prefix of stack containing pointers
|
stkptrsize int64 // prefix of stack containing pointers
|
||||||
log bool // print ssa debug to the stdout
|
log bool // print ssa debug to the stdout
|
||||||
}
|
}
|
||||||
|
|
||||||
// StringData returns a symbol (a *types.Sym wrapped in an interface) which
|
// StringData returns a symbol which
|
||||||
// is the data component of a global string constant containing s.
|
// is the data component of a global string constant containing s.
|
||||||
func (e *ssafn) StringData(s string) interface{} {
|
func (e *ssafn) StringData(s string) *obj.LSym {
|
||||||
if aux, ok := e.strings[s]; ok {
|
if aux, ok := e.strings[s]; ok {
|
||||||
return aux
|
return aux
|
||||||
}
|
}
|
||||||
if e.strings == nil {
|
if e.strings == nil {
|
||||||
e.strings = make(map[string]interface{})
|
e.strings = make(map[string]*obj.LSym)
|
||||||
}
|
}
|
||||||
data := stringsym(e.curfn.Pos, s)
|
data := stringsym(e.curfn.Pos, s)
|
||||||
e.strings[s] = data
|
e.strings[s] = data
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,7 @@ func checkFunc(f *Func) {
|
||||||
// Check to make sure aux values make sense.
|
// Check to make sure aux values make sense.
|
||||||
canHaveAux := false
|
canHaveAux := false
|
||||||
canHaveAuxInt := false
|
canHaveAuxInt := false
|
||||||
|
// TODO: enforce types of Aux in this switch (like auxString does below)
|
||||||
switch opcodeTable[v.Op].auxType {
|
switch opcodeTable[v.Op].auxType {
|
||||||
case auxNone:
|
case auxNone:
|
||||||
case auxBool:
|
case auxBool:
|
||||||
|
|
@ -158,7 +159,12 @@ func checkFunc(f *Func) {
|
||||||
if math.IsNaN(v.AuxFloat()) {
|
if math.IsNaN(v.AuxFloat()) {
|
||||||
f.Fatalf("value %v has an AuxInt that encodes a NaN", v)
|
f.Fatalf("value %v has an AuxInt that encodes a NaN", v)
|
||||||
}
|
}
|
||||||
case auxString, auxSym, auxTyp, auxArchSpecific:
|
case auxString:
|
||||||
|
if _, ok := v.Aux.(string); !ok {
|
||||||
|
f.Fatalf("value %v has Aux type %T, want string", v, v.Aux)
|
||||||
|
}
|
||||||
|
canHaveAux = true
|
||||||
|
case auxSym, auxTyp, auxArchSpecific:
|
||||||
canHaveAux = true
|
canHaveAux = true
|
||||||
case auxSymOff, auxSymValAndOff, auxTypSize:
|
case auxSymOff, auxSymValAndOff, auxTypSize:
|
||||||
canHaveAuxInt = true
|
canHaveAuxInt = true
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,7 @@ type Frontend interface {
|
||||||
Logger
|
Logger
|
||||||
|
|
||||||
// StringData returns a symbol pointing to the given string's contents.
|
// StringData returns a symbol pointing to the given string's contents.
|
||||||
StringData(string) interface{} // returns *gc.Sym
|
StringData(string) *obj.LSym
|
||||||
|
|
||||||
// Auto returns a Node for an auto variable of the given type.
|
// Auto returns a Node for an auto variable of the given type.
|
||||||
// The SSA compiler uses this function to allocate space for spills.
|
// The SSA compiler uses this function to allocate space for spills.
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ func (d *DummyAuto) IsAutoTmp() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (DummyFrontend) StringData(s string) interface{} {
|
func (DummyFrontend) StringData(s string) *obj.LSym {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
func (DummyFrontend) Auto(pos src.XPos, t *types.Type) GCNode {
|
func (DummyFrontend) Auto(pos src.XPos, t *types.Type) GCNode {
|
||||||
|
|
|
||||||
|
|
@ -2145,11 +2145,14 @@
|
||||||
(CMP(Q|L|W|B) l:(MOV(Q|L|W|B)load {sym} [off] ptr mem) x) && canMergeLoad(v, l) && clobber(l) -> (CMP(Q|L|W|B)load {sym} [off] ptr x mem)
|
(CMP(Q|L|W|B) l:(MOV(Q|L|W|B)load {sym} [off] ptr mem) x) && canMergeLoad(v, l) && clobber(l) -> (CMP(Q|L|W|B)load {sym} [off] ptr x mem)
|
||||||
(CMP(Q|L|W|B) x l:(MOV(Q|L|W|B)load {sym} [off] ptr mem)) && canMergeLoad(v, l) && clobber(l) -> (InvertFlags (CMP(Q|L|W|B)load {sym} [off] ptr x mem))
|
(CMP(Q|L|W|B) x l:(MOV(Q|L|W|B)load {sym} [off] ptr mem)) && canMergeLoad(v, l) && clobber(l) -> (InvertFlags (CMP(Q|L|W|B)load {sym} [off] ptr x mem))
|
||||||
|
|
||||||
(CMP(Q|L|W|B)const l:(MOV(Q|L|W|B)load {sym} [off] ptr mem) [c])
|
(CMP(Q|L)const l:(MOV(Q|L)load {sym} [off] ptr mem) [c])
|
||||||
&& l.Uses == 1
|
&& l.Uses == 1
|
||||||
&& validValAndOff(c, off)
|
&& clobber(l) =>
|
||||||
&& clobber(l) ->
|
@l.Block (CMP(Q|L)constload {sym} [makeValAndOff32(c,off)] ptr mem)
|
||||||
@l.Block (CMP(Q|L|W|B)constload {sym} [makeValAndOff(c,off)] ptr mem)
|
(CMP(W|B)const l:(MOV(W|B)load {sym} [off] ptr mem) [c])
|
||||||
|
&& l.Uses == 1
|
||||||
|
&& clobber(l) =>
|
||||||
|
@l.Block (CMP(W|B)constload {sym} [makeValAndOff32(int32(c),off)] ptr mem)
|
||||||
|
|
||||||
(CMPQload {sym} [off] ptr (MOVQconst [c]) mem) && validValAndOff(c,off) -> (CMPQconstload {sym} [makeValAndOff(c,off)] ptr mem)
|
(CMPQload {sym} [off] ptr (MOVQconst [c]) mem) && validValAndOff(c,off) -> (CMPQconstload {sym} [makeValAndOff(c,off)] ptr mem)
|
||||||
(CMPLload {sym} [off] ptr (MOVLconst [c]) mem) && validValAndOff(c,off) -> (CMPLconstload {sym} [makeValAndOff(c,off)] ptr mem)
|
(CMPLload {sym} [off] ptr (MOVLconst [c]) mem) && validValAndOff(c,off) -> (CMPLconstload {sym} [makeValAndOff(c,off)] ptr mem)
|
||||||
|
|
|
||||||
|
|
@ -873,20 +873,20 @@
|
||||||
// to other passes for optimizations.
|
// to other passes for optimizations.
|
||||||
(StringPtr (StringMake (Addr <t> {s} base) _)) -> (Addr <t> {s} base)
|
(StringPtr (StringMake (Addr <t> {s} base) _)) -> (Addr <t> {s} base)
|
||||||
(StringLen (StringMake _ (Const64 <t> [c]))) -> (Const64 <t> [c])
|
(StringLen (StringMake _ (Const64 <t> [c]))) -> (Const64 <t> [c])
|
||||||
(ConstString {s}) && config.PtrSize == 4 && s.(string) == "" ->
|
(ConstString {str}) && config.PtrSize == 4 && str == "" =>
|
||||||
(StringMake (ConstNil) (Const32 <typ.Int> [0]))
|
(StringMake (ConstNil) (Const32 <typ.Int> [0]))
|
||||||
(ConstString {s}) && config.PtrSize == 8 && s.(string) == "" ->
|
(ConstString {str}) && config.PtrSize == 8 && str == "" =>
|
||||||
(StringMake (ConstNil) (Const64 <typ.Int> [0]))
|
(StringMake (ConstNil) (Const64 <typ.Int> [0]))
|
||||||
(ConstString {s}) && config.PtrSize == 4 && s.(string) != "" ->
|
(ConstString {str}) && config.PtrSize == 4 && str != "" =>
|
||||||
(StringMake
|
(StringMake
|
||||||
(Addr <typ.BytePtr> {fe.StringData(s.(string))}
|
(Addr <typ.BytePtr> {fe.StringData(str)}
|
||||||
(SB))
|
(SB))
|
||||||
(Const32 <typ.Int> [int64(len(s.(string)))]))
|
(Const32 <typ.Int> [int32(len(str))]))
|
||||||
(ConstString {s}) && config.PtrSize == 8 && s.(string) != "" ->
|
(ConstString {str}) && config.PtrSize == 8 && str != "" =>
|
||||||
(StringMake
|
(StringMake
|
||||||
(Addr <typ.BytePtr> {fe.StringData(s.(string))}
|
(Addr <typ.BytePtr> {fe.StringData(str)}
|
||||||
(SB))
|
(SB))
|
||||||
(Const64 <typ.Int> [int64(len(s.(string)))]))
|
(Const64 <typ.Int> [int64(len(str))]))
|
||||||
|
|
||||||
// slice ops
|
// slice ops
|
||||||
// Only a few slice rules are provided here. See dec.rules for
|
// Only a few slice rules are provided here. See dec.rules for
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// rule syntax:
|
// rule syntax:
|
||||||
// sexpr [&& extra conditions] -> [@block] sexpr
|
// sexpr [&& extra conditions] -> [@block] sexpr (untyped)
|
||||||
|
// sexpr [&& extra conditions] => [@block] sexpr (typed)
|
||||||
//
|
//
|
||||||
// sexpr are s-expressions (lisp-like parenthesized groupings)
|
// sexpr are s-expressions (lisp-like parenthesized groupings)
|
||||||
// sexpr ::= [variable:](opcode sexpr*)
|
// sexpr ::= [variable:](opcode sexpr*)
|
||||||
|
|
@ -74,11 +75,14 @@ func normalizeSpaces(s string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse returns the matching part of the rule, additional conditions, and the result.
|
// parse returns the matching part of the rule, additional conditions, and the result.
|
||||||
func (r Rule) parse() (match, cond, result string) {
|
// parse also reports whether the generated code should use strongly typed aux and auxint fields.
|
||||||
s := strings.Split(r.rule, "->")
|
func (r Rule) parse() (match, cond, result string, typed bool) {
|
||||||
if len(s) != 2 {
|
arrow := "->"
|
||||||
log.Fatalf("no arrow in %s", r)
|
if strings.Contains(r.rule, "=>") {
|
||||||
|
arrow = "=>"
|
||||||
|
typed = true
|
||||||
}
|
}
|
||||||
|
s := strings.Split(r.rule, arrow)
|
||||||
match = normalizeSpaces(s[0])
|
match = normalizeSpaces(s[0])
|
||||||
result = normalizeSpaces(s[1])
|
result = normalizeSpaces(s[1])
|
||||||
cond = ""
|
cond = ""
|
||||||
|
|
@ -86,7 +90,7 @@ func (r Rule) parse() (match, cond, result string) {
|
||||||
cond = normalizeSpaces(match[i+2:])
|
cond = normalizeSpaces(match[i+2:])
|
||||||
match = normalizeSpaces(match[:i])
|
match = normalizeSpaces(match[:i])
|
||||||
}
|
}
|
||||||
return match, cond, result
|
return match, cond, result, typed
|
||||||
}
|
}
|
||||||
|
|
||||||
func genRules(arch arch) { genRulesSuffix(arch, "") }
|
func genRules(arch arch) { genRulesSuffix(arch, "") }
|
||||||
|
|
@ -112,7 +116,7 @@ func genRulesSuffix(arch arch, suff string) {
|
||||||
scanner := bufio.NewScanner(text)
|
scanner := bufio.NewScanner(text)
|
||||||
rule := ""
|
rule := ""
|
||||||
var lineno int
|
var lineno int
|
||||||
var ruleLineno int // line number of "->"
|
var ruleLineno int // line number of "->" or "=>"
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
lineno++
|
lineno++
|
||||||
line := scanner.Text()
|
line := scanner.Text()
|
||||||
|
|
@ -126,13 +130,13 @@ func genRulesSuffix(arch arch, suff string) {
|
||||||
if rule == "" {
|
if rule == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !strings.Contains(rule, "->") {
|
if !strings.Contains(rule, "->") && !strings.Contains(rule, "=>") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if ruleLineno == 0 {
|
if ruleLineno == 0 {
|
||||||
ruleLineno = lineno
|
ruleLineno = lineno
|
||||||
}
|
}
|
||||||
if strings.HasSuffix(rule, "->") {
|
if strings.HasSuffix(rule, "->") || strings.HasSuffix(rule, "=>") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if unbalanced(rule) {
|
if unbalanced(rule) {
|
||||||
|
|
@ -147,7 +151,7 @@ func genRulesSuffix(arch arch, suff string) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Do fancier value op matching.
|
// Do fancier value op matching.
|
||||||
match, _, _ := r.parse()
|
match, _, _, _ := r.parse()
|
||||||
op, oparch, _, _, _, _ := parseValue(match, arch, loc)
|
op, oparch, _, _, _, _ := parseValue(match, arch, loc)
|
||||||
opname := fmt.Sprintf("Op%s%s", oparch, op.name)
|
opname := fmt.Sprintf("Op%s%s", oparch, op.name)
|
||||||
oprules[opname] = append(oprules[opname], r)
|
oprules[opname] = append(oprules[opname], r)
|
||||||
|
|
@ -218,7 +222,7 @@ func genRulesSuffix(arch arch, suff string) {
|
||||||
log.Fatalf("unconditional rule %s is followed by other rules", rr.match)
|
log.Fatalf("unconditional rule %s is followed by other rules", rr.match)
|
||||||
}
|
}
|
||||||
rr = &RuleRewrite{loc: rule.loc}
|
rr = &RuleRewrite{loc: rule.loc}
|
||||||
rr.match, rr.cond, rr.result = rule.parse()
|
rr.match, rr.cond, rr.result, rr.typed = rule.parse()
|
||||||
pos, _ := genMatch(rr, arch, rr.match, fn.arglen >= 0)
|
pos, _ := genMatch(rr, arch, rr.match, fn.arglen >= 0)
|
||||||
if pos == "" {
|
if pos == "" {
|
||||||
pos = "v.Pos"
|
pos = "v.Pos"
|
||||||
|
|
@ -430,6 +434,8 @@ func (u *unusedInspector) node(node ast.Node) {
|
||||||
for _, stmt := range node.List {
|
for _, stmt := range node.List {
|
||||||
u.node(stmt)
|
u.node(stmt)
|
||||||
}
|
}
|
||||||
|
case *ast.DeclStmt:
|
||||||
|
u.node(node.Decl)
|
||||||
case *ast.IfStmt:
|
case *ast.IfStmt:
|
||||||
if node.Init != nil {
|
if node.Init != nil {
|
||||||
u.node(node.Init)
|
u.node(node.Init)
|
||||||
|
|
@ -524,6 +530,8 @@ func (u *unusedInspector) node(node ast.Node) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case *ast.BasicLit:
|
case *ast.BasicLit:
|
||||||
|
case *ast.ValueSpec:
|
||||||
|
u.exprs(node.Values)
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("unhandled node: %T", node))
|
panic(fmt.Sprintf("unhandled node: %T", node))
|
||||||
}
|
}
|
||||||
|
|
@ -762,6 +770,7 @@ type (
|
||||||
alloc int // for unique var names
|
alloc int // for unique var names
|
||||||
loc string // file name & line number of the original rule
|
loc string // file name & line number of the original rule
|
||||||
commuteDepth int // used to track depth of commute loops
|
commuteDepth int // used to track depth of commute loops
|
||||||
|
typed bool // aux and auxint fields should be strongly typed
|
||||||
}
|
}
|
||||||
Declare struct {
|
Declare struct {
|
||||||
name string
|
name string
|
||||||
|
|
@ -815,7 +824,7 @@ func breakf(format string, a ...interface{}) *CondBreak {
|
||||||
|
|
||||||
func genBlockRewrite(rule Rule, arch arch, data blockData) *RuleRewrite {
|
func genBlockRewrite(rule Rule, arch arch, data blockData) *RuleRewrite {
|
||||||
rr := &RuleRewrite{loc: rule.loc}
|
rr := &RuleRewrite{loc: rule.loc}
|
||||||
rr.match, rr.cond, rr.result = rule.parse()
|
rr.match, rr.cond, rr.result, rr.typed = rule.parse()
|
||||||
_, _, auxint, aux, s := extract(rr.match) // remove parens, then split
|
_, _, auxint, aux, s := extract(rr.match) // remove parens, then split
|
||||||
|
|
||||||
// check match of control values
|
// check match of control values
|
||||||
|
|
@ -972,20 +981,56 @@ func genMatch0(rr *RuleRewrite, arch arch, match, v string, cnt map[string]int,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, e := range []struct {
|
for _, e := range []struct {
|
||||||
name, field string
|
name, field, dclType string
|
||||||
}{
|
}{
|
||||||
{typ, "Type"},
|
{typ, "Type", "*types.Type"},
|
||||||
{auxint, "AuxInt"},
|
{auxint, "AuxInt", op.auxIntType()},
|
||||||
{aux, "Aux"},
|
{aux, "Aux", op.auxType()},
|
||||||
} {
|
} {
|
||||||
if e.name == "" {
|
if e.name == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if !rr.typed {
|
||||||
|
if !token.IsIdentifier(e.name) || rr.declared(e.name) {
|
||||||
|
// code or variable
|
||||||
|
rr.add(breakf("%s.%s != %s", v, e.field, e.name))
|
||||||
|
} else {
|
||||||
|
rr.add(declf(e.name, "%s.%s", v, e.field))
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.dclType == "" {
|
||||||
|
log.Fatalf("op %s has no declared type for %s", op.name, e.field)
|
||||||
|
}
|
||||||
if !token.IsIdentifier(e.name) || rr.declared(e.name) {
|
if !token.IsIdentifier(e.name) || rr.declared(e.name) {
|
||||||
// code or variable
|
switch e.field {
|
||||||
rr.add(breakf("%s.%s != %s", v, e.field, e.name))
|
case "Aux":
|
||||||
|
if e.dclType == "interface{}" {
|
||||||
|
// see TODO above
|
||||||
|
rr.add(breakf("%s.%s != %s", v, e.field, e.dclType, e.name))
|
||||||
|
} else {
|
||||||
|
rr.add(breakf("%s.%s.(%s) != %s", v, e.field, e.dclType, e.name))
|
||||||
|
}
|
||||||
|
case "AuxInt":
|
||||||
|
rr.add(breakf("%s(%s.%s) != %s", e.dclType, v, e.field, e.name))
|
||||||
|
case "Type":
|
||||||
|
rr.add(breakf("%s.%s != %s", v, e.field, e.name))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
rr.add(declf(e.name, "%s.%s", v, e.field))
|
switch e.field {
|
||||||
|
case "Aux":
|
||||||
|
if e.dclType == "interface{}" {
|
||||||
|
// TODO: kind of a hack - allows nil interface through
|
||||||
|
rr.add(declf(e.name, "%s.%s", v, e.field))
|
||||||
|
} else {
|
||||||
|
rr.add(declf(e.name, "%s.%s.(%s)", v, e.field, e.dclType))
|
||||||
|
}
|
||||||
|
case "AuxInt":
|
||||||
|
rr.add(declf(e.name, "%s(%s.%s)", e.dclType, v, e.field))
|
||||||
|
case "Type":
|
||||||
|
rr.add(declf(e.name, "%s.%s", v, e.field))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1146,10 +1191,22 @@ func genResult0(rr *RuleRewrite, arch arch, result string, top, move bool, pos s
|
||||||
}
|
}
|
||||||
|
|
||||||
if auxint != "" {
|
if auxint != "" {
|
||||||
rr.add(stmtf("%s.AuxInt = %s", v, auxint))
|
if rr.typed {
|
||||||
|
// Make sure auxint value has the right type.
|
||||||
|
rr.add(stmtf("var _auxint %s = %s", op.auxIntType(), auxint))
|
||||||
|
rr.add(stmtf("%s.AuxInt = int64(_auxint)", v))
|
||||||
|
} else {
|
||||||
|
rr.add(stmtf("%s.AuxInt = %s", v, auxint))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if aux != "" {
|
if aux != "" {
|
||||||
rr.add(stmtf("%s.Aux = %s", v, aux))
|
if rr.typed {
|
||||||
|
// Make sure aux value has the right type.
|
||||||
|
rr.add(stmtf("var _aux %s = %s", op.auxType(), aux))
|
||||||
|
rr.add(stmtf("%s.Aux = _aux", v))
|
||||||
|
} else {
|
||||||
|
rr.add(stmtf("%s.Aux = %s", v, aux))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
all := new(strings.Builder)
|
all := new(strings.Builder)
|
||||||
for i, arg := range args {
|
for i, arg := range args {
|
||||||
|
|
@ -1418,7 +1475,7 @@ func excludeFromExpansion(s string, idx []int) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
right := s[idx[1]:]
|
right := s[idx[1]:]
|
||||||
if strings.Contains(left, "&&") && strings.Contains(right, "->") {
|
if strings.Contains(left, "&&") && (strings.Contains(right, "->") || strings.Contains(right, "=>")) {
|
||||||
// Inside && conditions.
|
// Inside && conditions.
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -1521,6 +1578,7 @@ func normalizeWhitespace(x string) string {
|
||||||
x = strings.Replace(x, "[ ", "[", -1)
|
x = strings.Replace(x, "[ ", "[", -1)
|
||||||
x = strings.Replace(x, " ]", "]", -1)
|
x = strings.Replace(x, " ]", "]", -1)
|
||||||
x = strings.Replace(x, ")->", ") ->", -1)
|
x = strings.Replace(x, ")->", ") ->", -1)
|
||||||
|
x = strings.Replace(x, ")=>", ") =>", -1)
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1576,7 +1634,7 @@ func parseEllipsisRules(rules []Rule, arch arch) (newop string, ok bool) {
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
rule := rules[0]
|
rule := rules[0]
|
||||||
match, cond, result := rule.parse()
|
match, cond, result, _ := rule.parse()
|
||||||
if cond != "" || !isEllipsisValue(match) || !isEllipsisValue(result) {
|
if cond != "" || !isEllipsisValue(match) || !isEllipsisValue(result) {
|
||||||
if strings.Contains(rule.rule, "...") {
|
if strings.Contains(rule.rule, "...") {
|
||||||
log.Fatalf("%s: found ellipsis in non-ellipsis rule", rule.loc)
|
log.Fatalf("%s: found ellipsis in non-ellipsis rule", rule.loc)
|
||||||
|
|
@ -1601,7 +1659,7 @@ func isEllipsisValue(s string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkEllipsisRuleCandidate(rule Rule, arch arch) {
|
func checkEllipsisRuleCandidate(rule Rule, arch arch) {
|
||||||
match, cond, result := rule.parse()
|
match, cond, result, _ := rule.parse()
|
||||||
if cond != "" {
|
if cond != "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -1653,3 +1711,54 @@ func opByName(arch arch, name string) opData {
|
||||||
log.Fatalf("failed to find op named %s in arch %s", name, arch.name)
|
log.Fatalf("failed to find op named %s in arch %s", name, arch.name)
|
||||||
panic("unreachable")
|
panic("unreachable")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// auxType returns the Go type that this operation should store in its aux field.
|
||||||
|
func (op opData) auxType() string {
|
||||||
|
switch op.aux {
|
||||||
|
case "String":
|
||||||
|
return "string"
|
||||||
|
case "Sym":
|
||||||
|
// Note: a Sym can be an *obj.LSym, a *gc.Node, or nil.
|
||||||
|
// TODO: provide an interface for this. Use a singleton to
|
||||||
|
// represent "no offset".
|
||||||
|
return "interface{}"
|
||||||
|
case "SymOff":
|
||||||
|
return "interface{}"
|
||||||
|
case "SymValAndOff":
|
||||||
|
return "interface{}"
|
||||||
|
case "Typ":
|
||||||
|
return "*types.Type"
|
||||||
|
case "TypSize":
|
||||||
|
return "*types.Type"
|
||||||
|
default:
|
||||||
|
return "invalid"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// auxIntType returns the Go type that this operation should store in its auxInt field.
|
||||||
|
func (op opData) auxIntType() string {
|
||||||
|
switch op.aux {
|
||||||
|
//case "Bool":
|
||||||
|
case "Int8":
|
||||||
|
return "int8"
|
||||||
|
case "Int16":
|
||||||
|
return "int16"
|
||||||
|
case "Int32":
|
||||||
|
return "int32"
|
||||||
|
case "Int64":
|
||||||
|
return "int64"
|
||||||
|
//case "Int128":
|
||||||
|
//case "Float32":
|
||||||
|
//case "Float64":
|
||||||
|
case "SymOff":
|
||||||
|
return "int32"
|
||||||
|
case "SymValAndOff":
|
||||||
|
return "ValAndOff"
|
||||||
|
case "TypSize":
|
||||||
|
return "int64"
|
||||||
|
case "CCop":
|
||||||
|
return "Op"
|
||||||
|
default:
|
||||||
|
return "invalid"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,9 @@ func makeValAndOff(val, off int64) int64 {
|
||||||
}
|
}
|
||||||
return ValAndOff(val<<32 + int64(uint32(off))).Int64()
|
return ValAndOff(val<<32 + int64(uint32(off))).Int64()
|
||||||
}
|
}
|
||||||
|
func makeValAndOff32(val, off int32) ValAndOff {
|
||||||
|
return ValAndOff(int64(val)<<32 + int64(uint32(off)))
|
||||||
|
}
|
||||||
|
|
||||||
// offOnly returns the offset half of ValAndOff vo.
|
// offOnly returns the offset half of ValAndOff vo.
|
||||||
// It is intended for use in rewrite rules.
|
// It is intended for use in rewrite rules.
|
||||||
|
|
|
||||||
|
|
@ -6937,26 +6937,28 @@ func rewriteValueAMD64_OpAMD64CMPBconst(v *Value) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// match: (CMPBconst l:(MOVBload {sym} [off] ptr mem) [c])
|
// match: (CMPBconst l:(MOVBload {sym} [off] ptr mem) [c])
|
||||||
// cond: l.Uses == 1 && validValAndOff(c, off) && clobber(l)
|
// cond: l.Uses == 1 && clobber(l)
|
||||||
// result: @l.Block (CMPBconstload {sym} [makeValAndOff(c,off)] ptr mem)
|
// result: @l.Block (CMPBconstload {sym} [makeValAndOff32(int32(c),off)] ptr mem)
|
||||||
for {
|
for {
|
||||||
c := v.AuxInt
|
c := int8(v.AuxInt)
|
||||||
l := v_0
|
l := v_0
|
||||||
if l.Op != OpAMD64MOVBload {
|
if l.Op != OpAMD64MOVBload {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
off := l.AuxInt
|
off := int32(l.AuxInt)
|
||||||
sym := l.Aux
|
sym := l.Aux
|
||||||
mem := l.Args[1]
|
mem := l.Args[1]
|
||||||
ptr := l.Args[0]
|
ptr := l.Args[0]
|
||||||
if !(l.Uses == 1 && validValAndOff(c, off) && clobber(l)) {
|
if !(l.Uses == 1 && clobber(l)) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
b = l.Block
|
b = l.Block
|
||||||
v0 := b.NewValue0(l.Pos, OpAMD64CMPBconstload, types.TypeFlags)
|
v0 := b.NewValue0(l.Pos, OpAMD64CMPBconstload, types.TypeFlags)
|
||||||
v.copyOf(v0)
|
v.copyOf(v0)
|
||||||
v0.AuxInt = makeValAndOff(c, off)
|
var _auxint ValAndOff = makeValAndOff32(int32(c), off)
|
||||||
v0.Aux = sym
|
v0.AuxInt = int64(_auxint)
|
||||||
|
var _aux interface{} = sym
|
||||||
|
v0.Aux = _aux
|
||||||
v0.AddArg2(ptr, mem)
|
v0.AddArg2(ptr, mem)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -7322,26 +7324,28 @@ func rewriteValueAMD64_OpAMD64CMPLconst(v *Value) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// match: (CMPLconst l:(MOVLload {sym} [off] ptr mem) [c])
|
// match: (CMPLconst l:(MOVLload {sym} [off] ptr mem) [c])
|
||||||
// cond: l.Uses == 1 && validValAndOff(c, off) && clobber(l)
|
// cond: l.Uses == 1 && clobber(l)
|
||||||
// result: @l.Block (CMPLconstload {sym} [makeValAndOff(c,off)] ptr mem)
|
// result: @l.Block (CMPLconstload {sym} [makeValAndOff32(c,off)] ptr mem)
|
||||||
for {
|
for {
|
||||||
c := v.AuxInt
|
c := int32(v.AuxInt)
|
||||||
l := v_0
|
l := v_0
|
||||||
if l.Op != OpAMD64MOVLload {
|
if l.Op != OpAMD64MOVLload {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
off := l.AuxInt
|
off := int32(l.AuxInt)
|
||||||
sym := l.Aux
|
sym := l.Aux
|
||||||
mem := l.Args[1]
|
mem := l.Args[1]
|
||||||
ptr := l.Args[0]
|
ptr := l.Args[0]
|
||||||
if !(l.Uses == 1 && validValAndOff(c, off) && clobber(l)) {
|
if !(l.Uses == 1 && clobber(l)) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
b = l.Block
|
b = l.Block
|
||||||
v0 := b.NewValue0(l.Pos, OpAMD64CMPLconstload, types.TypeFlags)
|
v0 := b.NewValue0(l.Pos, OpAMD64CMPLconstload, types.TypeFlags)
|
||||||
v.copyOf(v0)
|
v.copyOf(v0)
|
||||||
v0.AuxInt = makeValAndOff(c, off)
|
var _auxint ValAndOff = makeValAndOff32(c, off)
|
||||||
v0.Aux = sym
|
v0.AuxInt = int64(_auxint)
|
||||||
|
var _aux interface{} = sym
|
||||||
|
v0.Aux = _aux
|
||||||
v0.AddArg2(ptr, mem)
|
v0.AddArg2(ptr, mem)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -7887,26 +7891,28 @@ func rewriteValueAMD64_OpAMD64CMPQconst(v *Value) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// match: (CMPQconst l:(MOVQload {sym} [off] ptr mem) [c])
|
// match: (CMPQconst l:(MOVQload {sym} [off] ptr mem) [c])
|
||||||
// cond: l.Uses == 1 && validValAndOff(c, off) && clobber(l)
|
// cond: l.Uses == 1 && clobber(l)
|
||||||
// result: @l.Block (CMPQconstload {sym} [makeValAndOff(c,off)] ptr mem)
|
// result: @l.Block (CMPQconstload {sym} [makeValAndOff32(c,off)] ptr mem)
|
||||||
for {
|
for {
|
||||||
c := v.AuxInt
|
c := int32(v.AuxInt)
|
||||||
l := v_0
|
l := v_0
|
||||||
if l.Op != OpAMD64MOVQload {
|
if l.Op != OpAMD64MOVQload {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
off := l.AuxInt
|
off := int32(l.AuxInt)
|
||||||
sym := l.Aux
|
sym := l.Aux
|
||||||
mem := l.Args[1]
|
mem := l.Args[1]
|
||||||
ptr := l.Args[0]
|
ptr := l.Args[0]
|
||||||
if !(l.Uses == 1 && validValAndOff(c, off) && clobber(l)) {
|
if !(l.Uses == 1 && clobber(l)) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
b = l.Block
|
b = l.Block
|
||||||
v0 := b.NewValue0(l.Pos, OpAMD64CMPQconstload, types.TypeFlags)
|
v0 := b.NewValue0(l.Pos, OpAMD64CMPQconstload, types.TypeFlags)
|
||||||
v.copyOf(v0)
|
v.copyOf(v0)
|
||||||
v0.AuxInt = makeValAndOff(c, off)
|
var _auxint ValAndOff = makeValAndOff32(c, off)
|
||||||
v0.Aux = sym
|
v0.AuxInt = int64(_auxint)
|
||||||
|
var _aux interface{} = sym
|
||||||
|
v0.Aux = _aux
|
||||||
v0.AddArg2(ptr, mem)
|
v0.AddArg2(ptr, mem)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -8257,26 +8263,28 @@ func rewriteValueAMD64_OpAMD64CMPWconst(v *Value) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// match: (CMPWconst l:(MOVWload {sym} [off] ptr mem) [c])
|
// match: (CMPWconst l:(MOVWload {sym} [off] ptr mem) [c])
|
||||||
// cond: l.Uses == 1 && validValAndOff(c, off) && clobber(l)
|
// cond: l.Uses == 1 && clobber(l)
|
||||||
// result: @l.Block (CMPWconstload {sym} [makeValAndOff(c,off)] ptr mem)
|
// result: @l.Block (CMPWconstload {sym} [makeValAndOff32(int32(c),off)] ptr mem)
|
||||||
for {
|
for {
|
||||||
c := v.AuxInt
|
c := int16(v.AuxInt)
|
||||||
l := v_0
|
l := v_0
|
||||||
if l.Op != OpAMD64MOVWload {
|
if l.Op != OpAMD64MOVWload {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
off := l.AuxInt
|
off := int32(l.AuxInt)
|
||||||
sym := l.Aux
|
sym := l.Aux
|
||||||
mem := l.Args[1]
|
mem := l.Args[1]
|
||||||
ptr := l.Args[0]
|
ptr := l.Args[0]
|
||||||
if !(l.Uses == 1 && validValAndOff(c, off) && clobber(l)) {
|
if !(l.Uses == 1 && clobber(l)) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
b = l.Block
|
b = l.Block
|
||||||
v0 := b.NewValue0(l.Pos, OpAMD64CMPWconstload, types.TypeFlags)
|
v0 := b.NewValue0(l.Pos, OpAMD64CMPWconstload, types.TypeFlags)
|
||||||
v.copyOf(v0)
|
v.copyOf(v0)
|
||||||
v0.AuxInt = makeValAndOff(c, off)
|
var _auxint ValAndOff = makeValAndOff32(int32(c), off)
|
||||||
v0.Aux = sym
|
v0.AuxInt = int64(_auxint)
|
||||||
|
var _aux interface{} = sym
|
||||||
|
v0.Aux = _aux
|
||||||
v0.AddArg2(ptr, mem)
|
v0.AddArg2(ptr, mem)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3911,69 +3911,75 @@ func rewriteValuegeneric_OpConstString(v *Value) bool {
|
||||||
config := b.Func.Config
|
config := b.Func.Config
|
||||||
fe := b.Func.fe
|
fe := b.Func.fe
|
||||||
typ := &b.Func.Config.Types
|
typ := &b.Func.Config.Types
|
||||||
// match: (ConstString {s})
|
// match: (ConstString {str})
|
||||||
// cond: config.PtrSize == 4 && s.(string) == ""
|
// cond: config.PtrSize == 4 && str == ""
|
||||||
// result: (StringMake (ConstNil) (Const32 <typ.Int> [0]))
|
// result: (StringMake (ConstNil) (Const32 <typ.Int> [0]))
|
||||||
for {
|
for {
|
||||||
s := v.Aux
|
str := v.Aux.(string)
|
||||||
if !(config.PtrSize == 4 && s.(string) == "") {
|
if !(config.PtrSize == 4 && str == "") {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
v.reset(OpStringMake)
|
v.reset(OpStringMake)
|
||||||
v0 := b.NewValue0(v.Pos, OpConstNil, typ.BytePtr)
|
v0 := b.NewValue0(v.Pos, OpConstNil, typ.BytePtr)
|
||||||
v1 := b.NewValue0(v.Pos, OpConst32, typ.Int)
|
v1 := b.NewValue0(v.Pos, OpConst32, typ.Int)
|
||||||
v1.AuxInt = 0
|
var _auxint int32 = 0
|
||||||
|
v1.AuxInt = int64(_auxint)
|
||||||
v.AddArg2(v0, v1)
|
v.AddArg2(v0, v1)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// match: (ConstString {s})
|
// match: (ConstString {str})
|
||||||
// cond: config.PtrSize == 8 && s.(string) == ""
|
// cond: config.PtrSize == 8 && str == ""
|
||||||
// result: (StringMake (ConstNil) (Const64 <typ.Int> [0]))
|
// result: (StringMake (ConstNil) (Const64 <typ.Int> [0]))
|
||||||
for {
|
for {
|
||||||
s := v.Aux
|
str := v.Aux.(string)
|
||||||
if !(config.PtrSize == 8 && s.(string) == "") {
|
if !(config.PtrSize == 8 && str == "") {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
v.reset(OpStringMake)
|
v.reset(OpStringMake)
|
||||||
v0 := b.NewValue0(v.Pos, OpConstNil, typ.BytePtr)
|
v0 := b.NewValue0(v.Pos, OpConstNil, typ.BytePtr)
|
||||||
v1 := b.NewValue0(v.Pos, OpConst64, typ.Int)
|
v1 := b.NewValue0(v.Pos, OpConst64, typ.Int)
|
||||||
v1.AuxInt = 0
|
var _auxint int64 = 0
|
||||||
|
v1.AuxInt = int64(_auxint)
|
||||||
v.AddArg2(v0, v1)
|
v.AddArg2(v0, v1)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// match: (ConstString {s})
|
// match: (ConstString {str})
|
||||||
// cond: config.PtrSize == 4 && s.(string) != ""
|
// cond: config.PtrSize == 4 && str != ""
|
||||||
// result: (StringMake (Addr <typ.BytePtr> {fe.StringData(s.(string))} (SB)) (Const32 <typ.Int> [int64(len(s.(string)))]))
|
// result: (StringMake (Addr <typ.BytePtr> {fe.StringData(str)} (SB)) (Const32 <typ.Int> [int32(len(str))]))
|
||||||
for {
|
for {
|
||||||
s := v.Aux
|
str := v.Aux.(string)
|
||||||
if !(config.PtrSize == 4 && s.(string) != "") {
|
if !(config.PtrSize == 4 && str != "") {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
v.reset(OpStringMake)
|
v.reset(OpStringMake)
|
||||||
v0 := b.NewValue0(v.Pos, OpAddr, typ.BytePtr)
|
v0 := b.NewValue0(v.Pos, OpAddr, typ.BytePtr)
|
||||||
v0.Aux = fe.StringData(s.(string))
|
var _aux interface{} = fe.StringData(str)
|
||||||
|
v0.Aux = _aux
|
||||||
v1 := b.NewValue0(v.Pos, OpSB, typ.Uintptr)
|
v1 := b.NewValue0(v.Pos, OpSB, typ.Uintptr)
|
||||||
v0.AddArg(v1)
|
v0.AddArg(v1)
|
||||||
v2 := b.NewValue0(v.Pos, OpConst32, typ.Int)
|
v2 := b.NewValue0(v.Pos, OpConst32, typ.Int)
|
||||||
v2.AuxInt = int64(len(s.(string)))
|
var _auxint int32 = int32(len(str))
|
||||||
|
v2.AuxInt = int64(_auxint)
|
||||||
v.AddArg2(v0, v2)
|
v.AddArg2(v0, v2)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// match: (ConstString {s})
|
// match: (ConstString {str})
|
||||||
// cond: config.PtrSize == 8 && s.(string) != ""
|
// cond: config.PtrSize == 8 && str != ""
|
||||||
// result: (StringMake (Addr <typ.BytePtr> {fe.StringData(s.(string))} (SB)) (Const64 <typ.Int> [int64(len(s.(string)))]))
|
// result: (StringMake (Addr <typ.BytePtr> {fe.StringData(str)} (SB)) (Const64 <typ.Int> [int64(len(str))]))
|
||||||
for {
|
for {
|
||||||
s := v.Aux
|
str := v.Aux.(string)
|
||||||
if !(config.PtrSize == 8 && s.(string) != "") {
|
if !(config.PtrSize == 8 && str != "") {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
v.reset(OpStringMake)
|
v.reset(OpStringMake)
|
||||||
v0 := b.NewValue0(v.Pos, OpAddr, typ.BytePtr)
|
v0 := b.NewValue0(v.Pos, OpAddr, typ.BytePtr)
|
||||||
v0.Aux = fe.StringData(s.(string))
|
var _aux interface{} = fe.StringData(str)
|
||||||
|
v0.Aux = _aux
|
||||||
v1 := b.NewValue0(v.Pos, OpSB, typ.Uintptr)
|
v1 := b.NewValue0(v.Pos, OpSB, typ.Uintptr)
|
||||||
v0.AddArg(v1)
|
v0.AddArg(v1)
|
||||||
v2 := b.NewValue0(v.Pos, OpConst64, typ.Int)
|
v2 := b.NewValue0(v.Pos, OpConst64, typ.Int)
|
||||||
v2.AuxInt = int64(len(s.(string)))
|
var _auxint int64 = int64(len(str))
|
||||||
|
v2.AuxInt = int64(_auxint)
|
||||||
v.AddArg2(v0, v2)
|
v.AddArg2(v0, v2)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue