Will help with strongly typed rewrite rules.
Change-Id: Ifbf316a49f4081322b3b8f13bc962713437d9aba
Reviewed-on: https://go-review.googlesource.com/c/go/+/227785
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Daniel Martà <mvdan@mvdan.cc>
p.From.Reg = x86.REG_AX
p.To.Type = obj.TYPE_MEM
p.To.Reg = v.Args[0].Reg()
- gc.AddAux(&p.To, v)
if logopt.Enabled() {
logopt.LogOpt(v.Pos, "nilcheck", "genssa", v.Block.Func.Name)
}
}
}
-func AuxOffset(v *ssa.Value) (offset int64) {
- if v.Aux == nil {
- return 0
- }
- n, ok := v.Aux.(*Node)
- if !ok {
- v.Fatalf("bad aux type in %s\n", v.LongString())
- }
- if n.Class() == PAUTO {
- return n.Xoffset
- }
- return 0
-}
-
// AddAux adds the offset in the aux fields (AuxInt and Aux) of v to a.
func AddAux(a *obj.Addr, v *ssa.Value) {
AddAux2(a, v, v.AuxInt)
return p + "." + s.Name
}
+// The compiler needs *Node to be assignable to cmd/compile/internal/ssa.Sym.
+func (n *Node) CanBeAnSSASym() {
+}
+
// Name holds Node fields used only by named nodes (ONAME, OTYPE, OPACK, OLABEL, some OLITERAL).
type Name struct {
Pack *Node // real package for import . names
case ssa.OpPPC64ANDCCconst:
p := s.Prog(v.Op.Asm())
p.Reg = v.Args[0].Reg()
-
- if v.Aux != nil {
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = gc.AuxOffset(v)
- } else {
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = v.AuxInt
- }
-
+ p.From.Type = obj.TYPE_CONST
+ p.From.Offset = v.AuxInt
p.To.Type = obj.TYPE_REG
p.To.Reg = ppc64.REGTMP // discard result
u.exprs(node.Lhs)
break
}
- if len(node.Lhs) != 1 {
+ lhs := node.Lhs
+ if len(lhs) == 2 && lhs[1].(*ast.Ident).Name == "_" {
+ lhs = lhs[:1]
+ }
+ if len(lhs) != 1 {
panic("no support for := with multiple names")
}
- name := node.Lhs[0].(*ast.Ident)
+ name := lhs[0].(*ast.Ident)
obj := &object{
name: name.Name,
pos: name.NamePos,
fprint(w, n)
}
fmt.Fprintf(w, "}\n")
+ case *If:
+ fmt.Fprintf(w, "if ")
+ fprint(w, n.expr)
+ fmt.Fprintf(w, " {\n")
+ fprint(w, n.stmt)
+ if n.alt != nil {
+ fmt.Fprintf(w, "} else {\n")
+ fprint(w, n.alt)
+ }
+ fmt.Fprintf(w, "}\n")
case *Case:
fmt.Fprintf(w, "case ")
fprint(w, n.expr)
fmt.Fprintf(w, "%s := ", n.name)
fprint(w, n.value)
fmt.Fprintln(w)
+ case *Declare2:
+ fmt.Fprintf(w, "%s, %s := ", n.name1, n.name2)
+ fprint(w, n.value)
+ fmt.Fprintln(w)
case *CondBreak:
fmt.Fprintf(w, "if ")
fprint(w, n.expr)
w.list = append(w.list, node)
}
-// declared reports if the body contains a Declare with the given name.
+// declared reports if the body contains a Declare or Declare2 with the given name.
func (w *bodyBase) declared(name string) bool {
if name == "nil" {
// Treat "nil" as having already been declared.
if decl, ok := s.(*Declare); ok && decl.name == name {
return true
}
+ if decl, ok := s.(*Declare2); ok && (decl.name1 == name || decl.name2 == name) {
+ return true
+ }
}
return false
}
suffix string
arglen int32 // if kind == "Value", number of args for this op
}
+ If struct {
+ expr ast.Expr
+ stmt Statement
+ alt Statement
+ }
Switch struct {
bodyBase // []*Case
expr ast.Expr
name string
value ast.Expr
}
+ Declare2 struct {
+ name1, name2 string
+ value ast.Expr
+ }
+ // TODO: implement CondBreak as If + Break instead?
CondBreak struct {
expr ast.Expr
insideCommuteLoop bool
return &Declare{name, exprf(format, a...)}
}
+// decl2f constructs a simple "name1, name2 := value" declaration, using exprf for its
+// value.
+func decl2f(name1, name2, format string, a ...interface{}) *Declare2 {
+ return &Declare2{name1, name2, exprf(format, a...)}
+}
+
// breakf constructs a simple "if cond { break }" statement, using exprf for its
// condition.
func breakf(format string, a ...interface{}) *CondBreak {
if !token.IsIdentifier(e.name) || rr.declared(e.name) {
switch e.field {
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))
- }
+ rr.add(&If{
+ expr: exprf("%s.%s == nil", v, e.field),
+ stmt: breakf("%s == nil", e.name),
+ alt: 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":
} else {
switch e.field {
case "Aux":
- if e.dclType == "interface{}" {
+ if e.dclType == "Sym" {
// TODO: kind of a hack - allows nil interface through
- rr.add(declf(e.name, "%s.%s", v, e.field))
+ rr.add(decl2f(e.name, "_", "%s.Aux.(Sym)", v))
} else {
rr.add(declf(e.name, "%s.%s.(%s)", v, e.field, e.dclType))
}
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{}"
+ return "Sym"
case "SymOff":
- return "interface{}"
+ return "Sym"
case "SymValAndOff":
- return "interface{}"
+ return "Sym"
case "Typ":
return "*types.Type"
case "TypSize":
auxFloat32 // auxInt is a float32 (encoded with math.Float64bits)
auxFloat64 // auxInt is a float64 (encoded with math.Float64bits)
auxString // aux is a string
- auxSym // aux is a symbol (a *gc.Node for locals or an *obj.LSym for globals)
+ auxSym // aux is a symbol (a *gc.Node for locals, an *obj.LSym for globals, or nil for none)
auxSymOff // aux is a symbol, auxInt is an offset
auxSymValAndOff // aux is a symbol, auxInt is a ValAndOff
auxTyp // aux is a type
SymNone SymEffect = 0
)
+// A Sym represents a symbolic offset from a base register.
+// Currently a Sym can be one of 3 things:
+// - a *gc.Node, for an offset from SP (the stack pointer)
+// - a *obj.LSym, for an offset from SB (the global pointer)
+// - nil, for no offset
+type Sym interface {
+ String() string
+ CanBeAnSSASym()
+}
+
// A ValAndOff is used by the several opcodes. It holds
// both a value and a pointer offset.
// A ValAndOff is intended to be encoded into an AuxInt field.
break
}
off := int32(l.AuxInt)
- sym := l.Aux
+ sym, _ := l.Aux.(Sym)
mem := l.Args[1]
ptr := l.Args[0]
if !(l.Uses == 1 && clobber(l)) {
v.copyOf(v0)
var _auxint ValAndOff = makeValAndOff32(int32(c), off)
v0.AuxInt = int64(_auxint)
- var _aux interface{} = sym
+ var _aux Sym = sym
v0.Aux = _aux
v0.AddArg2(ptr, mem)
return true
break
}
off := int32(l.AuxInt)
- sym := l.Aux
+ sym, _ := l.Aux.(Sym)
mem := l.Args[1]
ptr := l.Args[0]
if !(l.Uses == 1 && clobber(l)) {
v.copyOf(v0)
var _auxint ValAndOff = makeValAndOff32(c, off)
v0.AuxInt = int64(_auxint)
- var _aux interface{} = sym
+ var _aux Sym = sym
v0.Aux = _aux
v0.AddArg2(ptr, mem)
return true
break
}
off := int32(l.AuxInt)
- sym := l.Aux
+ sym, _ := l.Aux.(Sym)
mem := l.Args[1]
ptr := l.Args[0]
if !(l.Uses == 1 && clobber(l)) {
v.copyOf(v0)
var _auxint ValAndOff = makeValAndOff32(c, off)
v0.AuxInt = int64(_auxint)
- var _aux interface{} = sym
+ var _aux Sym = sym
v0.Aux = _aux
v0.AddArg2(ptr, mem)
return true
break
}
off := int32(l.AuxInt)
- sym := l.Aux
+ sym, _ := l.Aux.(Sym)
mem := l.Args[1]
ptr := l.Args[0]
if !(l.Uses == 1 && clobber(l)) {
v.copyOf(v0)
var _auxint ValAndOff = makeValAndOff32(int32(c), off)
v0.AuxInt = int64(_auxint)
- var _aux interface{} = sym
+ var _aux Sym = sym
v0.Aux = _aux
v0.AddArg2(ptr, mem)
return true
}
v.reset(OpStringMake)
v0 := b.NewValue0(v.Pos, OpAddr, typ.BytePtr)
- var _aux interface{} = fe.StringData(str)
+ var _aux Sym = fe.StringData(str)
v0.Aux = _aux
v1 := b.NewValue0(v.Pos, OpSB, typ.Uintptr)
v0.AddArg(v1)
}
v.reset(OpStringMake)
v0 := b.NewValue0(v.Pos, OpAddr, typ.BytePtr)
- var _aux interface{} = fe.StringData(str)
+ var _aux Sym = fe.StringData(str)
v0.Aux = _aux
v1 := b.NewValue0(v.Pos, OpSB, typ.Uintptr)
v0.AddArg(v1)
return s
}
-// The compiler needs LSym to satisfy fmt.Stringer, because it stores
-// an LSym in ssa.ExternSymbol.
func (s *LSym) String() string {
return s.Name
}
+// The compiler needs *LSym to be assignable to cmd/compile/internal/ssa.Sym.
+func (s *LSym) CanBeAnSSASym() {
+}
+
type Pcln struct {
Pcsp Pcdata
Pcfile Pcdata