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:
Keith Randall 2020-03-19 16:25:08 -07:00
parent a1550d3ca3
commit 28157b3292
10 changed files with 234 additions and 99 deletions

View file

@ -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

View file

@ -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

View file

@ -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.

View file

@ -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 {

View file

@ -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)

View file

@ -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

View file

@ -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"
}
}

View file

@ -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.

View file

@ -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
} }

View file

@ -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
} }