mirror of https://github.com/golang/go.git
cmd/compile: add LocalAddr that takes SP,mem operands
Lack of a well-defined order between VarDef and related address operations sometimes causes problems with store order and write barrier transformations; glitches in the order are made irreparable (by later optimizations) if the two parts of the glitch straddle a split in the original block caused by insertion of a write barrier diamond. Fix this by creating a LocalAddr for addresses of locals (what VarDef matters for) that takes a memory input to help make the order explicit. Addr is modified to only be legal for SB operand, so there is no overlap between Addr and LocalAddr uses (there may be some downstream cleanup from this). Changes to generic.rules and rewrite.go ensure that codegen tests continue to pass; CSE of LocalAddr is impaired, not quite sure of the cost. Fixes #26105. Change-Id: Id4192b4440aa4e9d7ba54a465c456df9b530b515 Reviewed-on: https://go-review.googlesource.com/122483 Run-TryBot: David Chase <drchase@google.com> Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
parent
bb364d49a9
commit
0029cd479e
|
|
@ -162,7 +162,7 @@ func buildssa(fn *Node, worker int) *ssa.Func {
|
|||
for _, n := range fn.Func.Dcl {
|
||||
switch n.Class() {
|
||||
case PPARAM, PPARAMOUT:
|
||||
s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, types.NewPtr(n.Type), n, s.sp)
|
||||
s.decladdrs[n] = s.entryNewValue2A(ssa.OpLocalAddr, types.NewPtr(n.Type), n, s.sp, s.startmem)
|
||||
if n.Class() == PPARAMOUT && s.canSSA(n) {
|
||||
// Save ssa-able PPARAMOUT variables so we can
|
||||
// store them back to the stack at the end of
|
||||
|
|
@ -454,6 +454,16 @@ func (s *state) newValue2(op ssa.Op, t *types.Type, arg0, arg1 *ssa.Value) *ssa.
|
|||
return s.curBlock.NewValue2(s.peekPos(), op, t, arg0, arg1)
|
||||
}
|
||||
|
||||
// newValue2Apos adds a new value with two arguments and an aux value to the current block.
|
||||
// isStmt determines whether the created values may be a statement or not
|
||||
// (i.e., false means never, yes means maybe).
|
||||
func (s *state) newValue2Apos(op ssa.Op, t *types.Type, aux interface{}, arg0, arg1 *ssa.Value, isStmt bool) *ssa.Value {
|
||||
if isStmt {
|
||||
return s.curBlock.NewValue2A(s.peekPos(), op, t, aux, arg0, arg1)
|
||||
}
|
||||
return s.curBlock.NewValue2A(s.peekPos().WithNotStmt(), op, t, aux, arg0, arg1)
|
||||
}
|
||||
|
||||
// newValue2I adds a new value with two arguments and an auxint value to the current block.
|
||||
func (s *state) newValue2I(op ssa.Op, t *types.Type, aux int64, arg0, arg1 *ssa.Value) *ssa.Value {
|
||||
return s.curBlock.NewValue2I(s.peekPos(), op, t, aux, arg0, arg1)
|
||||
|
|
@ -519,6 +529,11 @@ func (s *state) entryNewValue2(op ssa.Op, t *types.Type, arg0, arg1 *ssa.Value)
|
|||
return s.f.Entry.NewValue2(src.NoXPos, op, t, arg0, arg1)
|
||||
}
|
||||
|
||||
// entryNewValue2A adds a new value with two arguments and an aux value to the entry block.
|
||||
func (s *state) entryNewValue2A(op ssa.Op, t *types.Type, aux interface{}, arg0, arg1 *ssa.Value) *ssa.Value {
|
||||
return s.f.Entry.NewValue2A(src.NoXPos, op, t, aux, arg0, arg1)
|
||||
}
|
||||
|
||||
// const* routines add a new const value to the entry block.
|
||||
func (s *state) constSlice(t *types.Type) *ssa.Value {
|
||||
return s.f.ConstSlice(t)
|
||||
|
|
@ -2584,10 +2599,10 @@ func (s *state) assign(left *Node, right *ssa.Value, deref bool, skip skipMask)
|
|||
return
|
||||
}
|
||||
// Left is not ssa-able. Compute its address.
|
||||
addr := s.addr(left, false)
|
||||
if left.Op == ONAME && left.Class() != PEXTERN && skip == 0 {
|
||||
s.vars[&memVar] = s.newValue1Apos(ssa.OpVarDef, types.TypeMem, left, s.mem(), !left.IsAutoTmp())
|
||||
}
|
||||
addr := s.addr(left, false)
|
||||
if isReflectHeaderDataField(left) {
|
||||
// Package unsafe's documentation says storing pointers into
|
||||
// reflect.SliceHeader and reflect.StringHeader's Data fields
|
||||
|
|
@ -3655,16 +3670,17 @@ func (s *state) addr(n *Node, bounded bool) *ssa.Value {
|
|||
}
|
||||
if n == nodfp {
|
||||
// Special arg that points to the frame pointer (Used by ORECOVER).
|
||||
return s.entryNewValue1A(ssa.OpAddr, t, n, s.sp)
|
||||
return s.entryNewValue2A(ssa.OpLocalAddr, t, n, s.sp, s.startmem)
|
||||
}
|
||||
s.Fatalf("addr of undeclared ONAME %v. declared: %v", n, s.decladdrs)
|
||||
return nil
|
||||
case PAUTO:
|
||||
return s.newValue1Apos(ssa.OpAddr, t, n, s.sp, !n.IsAutoTmp())
|
||||
return s.newValue2Apos(ssa.OpLocalAddr, t, n, s.sp, s.mem(), !n.IsAutoTmp())
|
||||
|
||||
case PPARAMOUT: // Same as PAUTO -- cannot generate LEA early.
|
||||
// ensure that we reuse symbols for out parameters so
|
||||
// that cse works on their addresses
|
||||
return s.newValue1A(ssa.OpAddr, t, n, s.sp)
|
||||
return s.newValue2Apos(ssa.OpLocalAddr, t, n, s.sp, s.mem(), true)
|
||||
default:
|
||||
s.Fatalf("variable address class %v not implemented", n.Class())
|
||||
return nil
|
||||
|
|
@ -4578,8 +4594,8 @@ func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
|
|||
// unSSAable type, use temporary.
|
||||
// TODO: get rid of some of these temporaries.
|
||||
tmp = tempAt(n.Pos, s.curfn, n.Type)
|
||||
addr = s.addr(tmp, false)
|
||||
s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, tmp, s.mem())
|
||||
addr = s.addr(tmp, false)
|
||||
}
|
||||
|
||||
cond := s.newValue2(ssa.OpEqPtr, types.Types[TBOOL], itab, targetITab)
|
||||
|
|
@ -5581,7 +5597,8 @@ func (e *ssafn) Log() bool {
|
|||
// Fatal reports a compiler error and exits.
|
||||
func (e *ssafn) Fatalf(pos src.XPos, msg string, args ...interface{}) {
|
||||
lineno = pos
|
||||
Fatalf(msg, args...)
|
||||
nargs := append([]interface{}{e.curfn.funcname()}, args...)
|
||||
Fatalf("'%s': "+msg, nargs...)
|
||||
}
|
||||
|
||||
// Warnl reports a "warning", which is usually flag-triggered
|
||||
|
|
|
|||
|
|
@ -203,11 +203,23 @@ func checkFunc(f *Func) {
|
|||
if len(v.Args) == 0 {
|
||||
f.Fatalf("no args for OpAddr %s", v.LongString())
|
||||
}
|
||||
if v.Args[0].Op != OpSP && v.Args[0].Op != OpSB {
|
||||
if v.Args[0].Op != OpSB {
|
||||
f.Fatalf("bad arg to OpAddr %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
if v.Op == OpLocalAddr {
|
||||
if len(v.Args) != 2 {
|
||||
f.Fatalf("wrong # of args for OpLocalAddr %s", v.LongString())
|
||||
}
|
||||
if v.Args[0].Op != OpSP {
|
||||
f.Fatalf("bad arg 0 to OpLocalAddr %v", v)
|
||||
}
|
||||
if !v.Args[1].Type.IsMemory() {
|
||||
f.Fatalf("bad arg 1 to OpLocalAddr %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
if f.RegAlloc != nil && f.Config.SoftFloat && v.Type.IsFloat() {
|
||||
f.Fatalf("unexpected floating-point type %v", v.LongString())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ func TestCSEAuxPartitionBug(t *testing.T) {
|
|||
Valu("r4", OpAdd64, c.config.Types.Int64, 0, nil, "r1", "r2"),
|
||||
Valu("r8", OpAdd64, c.config.Types.Int64, 0, nil, "arg3", "arg2"),
|
||||
Valu("r2", OpAdd64, c.config.Types.Int64, 0, nil, "arg1", "arg2"),
|
||||
Valu("raddr", OpAddr, c.config.Types.Int64.PtrTo(), 0, nil, "sp"),
|
||||
Valu("raddr", OpLocalAddr, c.config.Types.Int64.PtrTo(), 0, nil, "sp", "start"),
|
||||
Valu("raddrdef", OpVarDef, types.TypeMem, 0, nil, "start"),
|
||||
Valu("r6", OpAdd64, c.config.Types.Int64, 0, nil, "r4", "r5"),
|
||||
Valu("r3", OpAdd64, c.config.Types.Int64, 0, nil, "arg1", "arg2"),
|
||||
|
|
@ -105,7 +105,7 @@ func TestZCSE(t *testing.T) {
|
|||
Valu("c2", OpConst64, c.config.Types.Int64, 1, nil),
|
||||
Valu("r2", OpAdd64, c.config.Types.Int64, 0, nil, "a2ld", "c2"),
|
||||
Valu("r3", OpAdd64, c.config.Types.Int64, 0, nil, "r1", "r2"),
|
||||
Valu("raddr", OpAddr, c.config.Types.Int64.PtrTo(), 0, nil, "sp"),
|
||||
Valu("raddr", OpLocalAddr, c.config.Types.Int64.PtrTo(), 0, nil, "sp", "start"),
|
||||
Valu("raddrdef", OpVarDef, types.TypeMem, 0, nil, "start"),
|
||||
Valu("rstore", OpStore, types.TypeMem, 0, c.config.Types.Int64, "raddr", "r3", "raddrdef"),
|
||||
Goto("exit")),
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ func elimDeadAutosGeneric(f *Func) {
|
|||
visit := func(v *Value) (changed bool) {
|
||||
args := v.Args
|
||||
switch v.Op {
|
||||
case OpAddr:
|
||||
case OpAddr, OpLocalAddr:
|
||||
// Propagate the address if it points to an auto.
|
||||
n, ok := v.Aux.(GCNode)
|
||||
if !ok || n.StorageClass() != ClassAuto {
|
||||
|
|
|
|||
|
|
@ -390,6 +390,19 @@ func (b *Block) NewValue2(pos src.XPos, op Op, t *types.Type, arg0, arg1 *Value)
|
|||
return v
|
||||
}
|
||||
|
||||
// NewValue2A returns a new value in the block with two arguments and one aux values.
|
||||
func (b *Block) NewValue2A(pos src.XPos, op Op, t *types.Type, aux interface{}, arg0, arg1 *Value) *Value {
|
||||
v := b.Func.newValue(op, t, b, pos)
|
||||
v.AuxInt = 0
|
||||
v.Aux = aux
|
||||
v.Args = v.argstorage[:2]
|
||||
v.argstorage[0] = arg0
|
||||
v.argstorage[1] = arg1
|
||||
arg0.Uses++
|
||||
arg1.Uses++
|
||||
return v
|
||||
}
|
||||
|
||||
// NewValue2I returns a new value in the block with two arguments and an auxint value.
|
||||
func (b *Block) NewValue2I(pos src.XPos, op Op, t *types.Type, auxint int64, arg0, arg1 *Value) *Value {
|
||||
v := b.Func.newValue(op, t, b, pos)
|
||||
|
|
|
|||
|
|
@ -356,6 +356,7 @@
|
|||
(GetCallerPC) -> (LoweredGetCallerPC)
|
||||
(GetCallerSP) -> (LoweredGetCallerSP)
|
||||
(Addr {sym} base) -> (LEAL {sym} base)
|
||||
(LocalAddr {sym} base _) -> (LEAL {sym} base)
|
||||
|
||||
// block rewrites
|
||||
(If (SETL cmp) yes no) -> (LT cmp yes no)
|
||||
|
|
|
|||
|
|
@ -455,6 +455,8 @@
|
|||
(GetCallerSP) -> (LoweredGetCallerSP)
|
||||
(Addr {sym} base) && config.PtrSize == 8 -> (LEAQ {sym} base)
|
||||
(Addr {sym} base) && config.PtrSize == 4 -> (LEAL {sym} base)
|
||||
(LocalAddr {sym} base _) && config.PtrSize == 8 -> (LEAQ {sym} base)
|
||||
(LocalAddr {sym} base _) && config.PtrSize == 4 -> (LEAL {sym} base)
|
||||
|
||||
(MOVBstore [off] {sym} ptr y:(SETL x) mem) && y.Uses == 1 -> (SETLstore [off] {sym} ptr x mem)
|
||||
(MOVBstore [off] {sym} ptr y:(SETLE x) mem) && y.Uses == 1 -> (SETLEstore [off] {sym} ptr x mem)
|
||||
|
|
|
|||
|
|
@ -253,6 +253,7 @@
|
|||
(OffPtr [off] ptr) -> (ADDconst [off] ptr)
|
||||
|
||||
(Addr {sym} base) -> (MOVWaddr {sym} base)
|
||||
(LocalAddr {sym} base _) -> (MOVWaddr {sym} base)
|
||||
|
||||
// loads
|
||||
(Load <t> ptr mem) && t.IsBoolean() -> (MOVBUload ptr mem)
|
||||
|
|
|
|||
|
|
@ -317,6 +317,7 @@
|
|||
(OffPtr [off] ptr) -> (ADDconst [off] ptr)
|
||||
|
||||
(Addr {sym} base) -> (MOVDaddr {sym} base)
|
||||
(LocalAddr {sym} base _) -> (MOVDaddr {sym} base)
|
||||
|
||||
// loads
|
||||
(Load <t> ptr mem) && t.IsBoolean() -> (MOVBUload ptr mem)
|
||||
|
|
|
|||
|
|
@ -219,6 +219,7 @@
|
|||
(OffPtr [off] ptr) -> (ADDconst [off] ptr)
|
||||
|
||||
(Addr {sym} base) -> (MOVWaddr {sym} base)
|
||||
(LocalAddr {sym} base _) -> (MOVWaddr {sym} base)
|
||||
|
||||
// loads
|
||||
(Load <t> ptr mem) && t.IsBoolean() -> (MOVBUload ptr mem)
|
||||
|
|
|
|||
|
|
@ -229,6 +229,7 @@
|
|||
(OffPtr [off] ptr) -> (ADDVconst [off] ptr)
|
||||
|
||||
(Addr {sym} base) -> (MOVVaddr {sym} base)
|
||||
(LocalAddr {sym} base _) -> (MOVVaddr {sym} base)
|
||||
|
||||
// loads
|
||||
(Load <t> ptr mem) && t.IsBoolean() -> (MOVBUload ptr mem)
|
||||
|
|
|
|||
|
|
@ -273,6 +273,7 @@
|
|||
// (MaskIfNotCarry CarrySet) -> -1
|
||||
|
||||
(Addr {sym} base) -> (MOVDaddr {sym} base)
|
||||
(LocalAddr {sym} base _) -> (MOVDaddr {sym} base)
|
||||
(OffPtr [off] ptr) -> (ADD (MOVDconst <typ.Int64> [off]) ptr)
|
||||
|
||||
// TODO: optimize these cases?
|
||||
|
|
|
|||
|
|
@ -367,6 +367,7 @@
|
|||
(GetCallerSP) -> (LoweredGetCallerSP)
|
||||
(GetCallerPC) -> (LoweredGetCallerPC)
|
||||
(Addr {sym} base) -> (MOVDaddr {sym} base)
|
||||
(LocalAddr {sym} base _) -> (MOVDaddr {sym} base)
|
||||
(ITab (Load ptr mem)) -> (MOVDload ptr mem)
|
||||
|
||||
// block rewrites
|
||||
|
|
|
|||
|
|
@ -352,6 +352,7 @@
|
|||
(GetCallerPC) -> (LoweredGetCallerPC)
|
||||
(GetCallerSP) -> (LoweredGetCallerSP)
|
||||
(Addr {sym} base) -> (LoweredAddr {sym} base)
|
||||
(LocalAddr {sym} base _) -> (LoweredAddr {sym} base)
|
||||
|
||||
// Write barrier.
|
||||
(WB {fn} destptr srcptr mem) -> (LoweredWB {fn} destptr srcptr mem)
|
||||
|
|
|
|||
|
|
@ -1370,6 +1370,8 @@
|
|||
(NeqPtr x x) -> (ConstBool [0])
|
||||
(EqPtr (Addr {a} _) (Addr {b} _)) -> (ConstBool [b2i(a == b)])
|
||||
(NeqPtr (Addr {a} _) (Addr {b} _)) -> (ConstBool [b2i(a != b)])
|
||||
(EqPtr (LocalAddr {a} _ _) (LocalAddr {b} _ _)) -> (ConstBool [b2i(a == b)])
|
||||
(NeqPtr (LocalAddr {a} _ _) (LocalAddr {b} _ _)) -> (ConstBool [b2i(a != b)])
|
||||
(EqPtr (OffPtr [o1] p1) p2) && isSamePtr(p1, p2) -> (ConstBool [b2i(o1 == 0)])
|
||||
(NeqPtr (OffPtr [o1] p1) p2) && isSamePtr(p1, p2) -> (ConstBool [b2i(o1 != 0)])
|
||||
(EqPtr (OffPtr [o1] p1) (OffPtr [o2] p2)) && isSamePtr(p1, p2) -> (ConstBool [b2i(o1 == o2)])
|
||||
|
|
@ -1377,6 +1379,11 @@
|
|||
(EqPtr (Const(32|64) [c]) (Const(32|64) [d])) -> (ConstBool [b2i(c == d)])
|
||||
(NeqPtr (Const(32|64) [c]) (Const(32|64) [d])) -> (ConstBool [b2i(c != d)])
|
||||
|
||||
(EqPtr (LocalAddr _ _) (Addr _)) -> (ConstBool [0])
|
||||
(NeqPtr (LocalAddr _ _) (Addr _)) -> (ConstBool [1])
|
||||
(EqPtr (Addr _) (LocalAddr _ _)) -> (ConstBool [0])
|
||||
(NeqPtr (Addr _) (LocalAddr _ _)) -> (ConstBool [1])
|
||||
|
||||
// Simplify address comparisons.
|
||||
(EqPtr (AddPtr p1 o1) p2) && isSamePtr(p1, p2) -> (Not (IsNonNil o1))
|
||||
(NeqPtr (AddPtr p1 o1) p2) && isSamePtr(p1, p2) -> (IsNonNil o1)
|
||||
|
|
@ -1389,6 +1396,7 @@
|
|||
(IsNonNil (ConstNil)) -> (ConstBool [0])
|
||||
(IsNonNil (Const(32|64) [c])) -> (ConstBool [b2i(c != 0)])
|
||||
(IsNonNil (Addr _)) -> (ConstBool [1])
|
||||
(IsNonNil (LocalAddr _ _)) -> (ConstBool [1])
|
||||
|
||||
// Inline small or disjoint runtime.memmove calls with constant length.
|
||||
(StaticCall {sym} s1:(Store _ (Const(64|32) [sz]) s2:(Store _ src s3:(Store {t} _ dst mem))))
|
||||
|
|
|
|||
|
|
@ -331,7 +331,8 @@ var genericOps = []opData{
|
|||
// the Aux field will be a *obj.LSym.
|
||||
// If the variable is a local, the base pointer will be SP and
|
||||
// the Aux field will be a *gc.Node.
|
||||
{name: "Addr", argLength: 1, aux: "Sym", symEffect: "Addr"}, // Address of a variable. Arg0=SP or SB. Aux identifies the variable.
|
||||
{name: "Addr", argLength: 1, aux: "Sym", symEffect: "Addr"}, // Address of a variable. Arg0=SB. Aux identifies the variable.
|
||||
{name: "LocalAddr", argLength: 2, aux: "Sym", symEffect: "Addr"}, // Address of a variable. Arg0=SP. Arg1=mem. Aux identifies the variable.
|
||||
|
||||
{name: "SP", zeroWidth: true}, // stack pointer
|
||||
{name: "SB", typ: "Uintptr", zeroWidth: true}, // static base pointer (a.k.a. globals pointer)
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ func TestLoopConditionS390X(t *testing.T) {
|
|||
Bloc("entry",
|
||||
Valu("mem", OpInitMem, types.TypeMem, 0, nil),
|
||||
Valu("SP", OpSP, c.config.Types.Uintptr, 0, nil),
|
||||
Valu("ret", OpAddr, c.config.Types.Int64.PtrTo(), 0, nil, "SP"),
|
||||
Valu("ret", OpLocalAddr, c.config.Types.Int64.PtrTo(), 0, nil, "SP", "mem"),
|
||||
Valu("N", OpArg, c.config.Types.Int64, 0, c.Frontend().Auto(src.NoXPos, c.config.Types.Int64)),
|
||||
Valu("starti", OpConst64, c.config.Types.Int64, 0, nil),
|
||||
Valu("startsum", OpConst64, c.config.Types.Int64, 0, nil),
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ func nilcheckelim(f *Func) {
|
|||
// a value resulting from taking the address of a
|
||||
// value, or a value constructed from an offset of a
|
||||
// non-nil ptr (OpAddPtr) implies it is non-nil
|
||||
if v.Op == OpAddr || v.Op == OpAddPtr {
|
||||
if v.Op == OpAddr || v.Op == OpLocalAddr || v.Op == OpAddPtr {
|
||||
nonNilValues[v.ID] = true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ func TestNilcheckPhi(t *testing.T) {
|
|||
Valu("mem", OpInitMem, types.TypeMem, 0, nil),
|
||||
Valu("sb", OpSB, c.config.Types.Uintptr, 0, nil),
|
||||
Valu("sp", OpSP, c.config.Types.Uintptr, 0, nil),
|
||||
Valu("baddr", OpAddr, c.config.Types.Bool, 0, "b", "sp"),
|
||||
Valu("baddr", OpLocalAddr, c.config.Types.Bool, 0, "b", "sp", "mem"),
|
||||
Valu("bool1", OpLoad, c.config.Types.Bool, 0, nil, "baddr", "mem"),
|
||||
If("bool1", "b1", "b2")),
|
||||
Bloc("b1",
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ func isPoorStatementOp(op Op) bool {
|
|||
switch op {
|
||||
// Note that Nilcheck often vanishes, but when it doesn't, you'd love to start the statement there
|
||||
// so that a debugger-user sees the stop before the panic, and can examine the value.
|
||||
case OpAddr, OpOffPtr, OpStructSelect, OpConstBool, OpConst8, OpConst16, OpConst32, OpConst64, OpConst32F, OpConst64F:
|
||||
case OpAddr, OpLocalAddr, OpOffPtr, OpStructSelect, OpConstBool, OpConst8, OpConst16, OpConst32, OpConst64, OpConst32F, OpConst64F:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
|
|
|||
|
|
@ -2172,6 +2172,7 @@ const (
|
|||
OpInitMem
|
||||
OpArg
|
||||
OpAddr
|
||||
OpLocalAddr
|
||||
OpSP
|
||||
OpSB
|
||||
OpLoad
|
||||
|
|
@ -27236,6 +27237,13 @@ var opcodeTable = [...]opInfo{
|
|||
symEffect: SymAddr,
|
||||
generic: true,
|
||||
},
|
||||
{
|
||||
name: "LocalAddr",
|
||||
auxType: auxSym,
|
||||
argLen: 2,
|
||||
symEffect: SymAddr,
|
||||
generic: true,
|
||||
},
|
||||
{
|
||||
name: "SP",
|
||||
argLen: 0,
|
||||
|
|
|
|||
|
|
@ -468,7 +468,7 @@ func isSamePtr(p1, p2 *Value) bool {
|
|||
switch p1.Op {
|
||||
case OpOffPtr:
|
||||
return p1.AuxInt == p2.AuxInt && isSamePtr(p1.Args[0], p2.Args[0])
|
||||
case OpAddr:
|
||||
case OpAddr, OpLocalAddr:
|
||||
// OpAddr's 0th arg is either OpSP or OpSB, which means that it is uniquely identified by its Op.
|
||||
// Checking for value equality only works after [z]cse has run.
|
||||
return p1.Aux == p2.Aux && p1.Args[0].Op == p2.Args[0].Op
|
||||
|
|
@ -506,18 +506,17 @@ func disjoint(p1 *Value, n1 int64, p2 *Value, n2 int64) bool {
|
|||
// If one pointer is on the stack and the other is an argument
|
||||
// then they can't overlap.
|
||||
switch p1.Op {
|
||||
case OpAddr:
|
||||
if p2.Op == OpAddr || p2.Op == OpSP {
|
||||
case OpAddr, OpLocalAddr:
|
||||
if p2.Op == OpAddr || p2.Op == OpLocalAddr || p2.Op == OpSP {
|
||||
return true
|
||||
}
|
||||
return p2.Op == OpArg && p1.Args[0].Op == OpSP
|
||||
case OpArg:
|
||||
if p2.Op == OpSP {
|
||||
if p2.Op == OpSP || p2.Op == OpLocalAddr {
|
||||
return true
|
||||
}
|
||||
return p2.Op == OpAddr && p2.Args[0].Op == OpSP
|
||||
case OpSP:
|
||||
return p2.Op == OpAddr || p2.Op == OpArg || p2.Op == OpSP
|
||||
return p2.Op == OpAddr || p2.Op == OpLocalAddr || p2.Op == OpArg || p2.Op == OpSP
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -441,6 +441,8 @@ func rewriteValue386(v *Value) bool {
|
|||
return rewriteValue386_OpLess8U_0(v)
|
||||
case OpLoad:
|
||||
return rewriteValue386_OpLoad_0(v)
|
||||
case OpLocalAddr:
|
||||
return rewriteValue386_OpLocalAddr_0(v)
|
||||
case OpLsh16x16:
|
||||
return rewriteValue386_OpLsh16x16_0(v)
|
||||
case OpLsh16x32:
|
||||
|
|
@ -17878,6 +17880,20 @@ func rewriteValue386_OpLoad_0(v *Value) bool {
|
|||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValue386_OpLocalAddr_0(v *Value) bool {
|
||||
// match: (LocalAddr {sym} base _)
|
||||
// cond:
|
||||
// result: (LEAL {sym} base)
|
||||
for {
|
||||
sym := v.Aux
|
||||
_ = v.Args[1]
|
||||
base := v.Args[0]
|
||||
v.reset(Op386LEAL)
|
||||
v.Aux = sym
|
||||
v.AddArg(base)
|
||||
return true
|
||||
}
|
||||
}
|
||||
func rewriteValue386_OpLsh16x16_0(v *Value) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
|
|
|
|||
|
|
@ -783,6 +783,8 @@ func rewriteValueAMD64(v *Value) bool {
|
|||
return rewriteValueAMD64_OpLess8U_0(v)
|
||||
case OpLoad:
|
||||
return rewriteValueAMD64_OpLoad_0(v)
|
||||
case OpLocalAddr:
|
||||
return rewriteValueAMD64_OpLocalAddr_0(v)
|
||||
case OpLsh16x16:
|
||||
return rewriteValueAMD64_OpLsh16x16_0(v)
|
||||
case OpLsh16x32:
|
||||
|
|
@ -56301,6 +56303,43 @@ func rewriteValueAMD64_OpLoad_0(v *Value) bool {
|
|||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64_OpLocalAddr_0(v *Value) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
config := b.Func.Config
|
||||
_ = config
|
||||
// match: (LocalAddr {sym} base _)
|
||||
// cond: config.PtrSize == 8
|
||||
// result: (LEAQ {sym} base)
|
||||
for {
|
||||
sym := v.Aux
|
||||
_ = v.Args[1]
|
||||
base := v.Args[0]
|
||||
if !(config.PtrSize == 8) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64LEAQ)
|
||||
v.Aux = sym
|
||||
v.AddArg(base)
|
||||
return true
|
||||
}
|
||||
// match: (LocalAddr {sym} base _)
|
||||
// cond: config.PtrSize == 4
|
||||
// result: (LEAL {sym} base)
|
||||
for {
|
||||
sym := v.Aux
|
||||
_ = v.Args[1]
|
||||
base := v.Args[0]
|
||||
if !(config.PtrSize == 4) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64LEAL)
|
||||
v.Aux = sym
|
||||
v.AddArg(base)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64_OpLsh16x16_0(v *Value) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
|
|
|
|||
|
|
@ -619,6 +619,8 @@ func rewriteValueARM(v *Value) bool {
|
|||
return rewriteValueARM_OpLess8U_0(v)
|
||||
case OpLoad:
|
||||
return rewriteValueARM_OpLoad_0(v)
|
||||
case OpLocalAddr:
|
||||
return rewriteValueARM_OpLocalAddr_0(v)
|
||||
case OpLsh16x16:
|
||||
return rewriteValueARM_OpLsh16x16_0(v)
|
||||
case OpLsh16x32:
|
||||
|
|
@ -19344,6 +19346,20 @@ func rewriteValueARM_OpLoad_0(v *Value) bool {
|
|||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueARM_OpLocalAddr_0(v *Value) bool {
|
||||
// match: (LocalAddr {sym} base _)
|
||||
// cond:
|
||||
// result: (MOVWaddr {sym} base)
|
||||
for {
|
||||
sym := v.Aux
|
||||
_ = v.Args[1]
|
||||
base := v.Args[0]
|
||||
v.reset(OpARMMOVWaddr)
|
||||
v.Aux = sym
|
||||
v.AddArg(base)
|
||||
return true
|
||||
}
|
||||
}
|
||||
func rewriteValueARM_OpLsh16x16_0(v *Value) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
|
|
|
|||
|
|
@ -603,6 +603,8 @@ func rewriteValueARM64(v *Value) bool {
|
|||
return rewriteValueARM64_OpLess8U_0(v)
|
||||
case OpLoad:
|
||||
return rewriteValueARM64_OpLoad_0(v)
|
||||
case OpLocalAddr:
|
||||
return rewriteValueARM64_OpLocalAddr_0(v)
|
||||
case OpLsh16x16:
|
||||
return rewriteValueARM64_OpLsh16x16_0(v)
|
||||
case OpLsh16x32:
|
||||
|
|
@ -28229,6 +28231,20 @@ func rewriteValueARM64_OpLoad_0(v *Value) bool {
|
|||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueARM64_OpLocalAddr_0(v *Value) bool {
|
||||
// match: (LocalAddr {sym} base _)
|
||||
// cond:
|
||||
// result: (MOVDaddr {sym} base)
|
||||
for {
|
||||
sym := v.Aux
|
||||
_ = v.Args[1]
|
||||
base := v.Args[0]
|
||||
v.reset(OpARM64MOVDaddr)
|
||||
v.Aux = sym
|
||||
v.AddArg(base)
|
||||
return true
|
||||
}
|
||||
}
|
||||
func rewriteValueARM64_OpLsh16x16_0(v *Value) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
|
|
|
|||
|
|
@ -213,6 +213,8 @@ func rewriteValueMIPS(v *Value) bool {
|
|||
return rewriteValueMIPS_OpLess8U_0(v)
|
||||
case OpLoad:
|
||||
return rewriteValueMIPS_OpLoad_0(v)
|
||||
case OpLocalAddr:
|
||||
return rewriteValueMIPS_OpLocalAddr_0(v)
|
||||
case OpLsh16x16:
|
||||
return rewriteValueMIPS_OpLsh16x16_0(v)
|
||||
case OpLsh16x32:
|
||||
|
|
@ -2511,6 +2513,20 @@ func rewriteValueMIPS_OpLoad_0(v *Value) bool {
|
|||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueMIPS_OpLocalAddr_0(v *Value) bool {
|
||||
// match: (LocalAddr {sym} base _)
|
||||
// cond:
|
||||
// result: (MOVWaddr {sym} base)
|
||||
for {
|
||||
sym := v.Aux
|
||||
_ = v.Args[1]
|
||||
base := v.Args[0]
|
||||
v.reset(OpMIPSMOVWaddr)
|
||||
v.Aux = sym
|
||||
v.AddArg(base)
|
||||
return true
|
||||
}
|
||||
}
|
||||
func rewriteValueMIPS_OpLsh16x16_0(v *Value) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
|
|
|
|||
|
|
@ -253,6 +253,8 @@ func rewriteValueMIPS64(v *Value) bool {
|
|||
return rewriteValueMIPS64_OpLess8U_0(v)
|
||||
case OpLoad:
|
||||
return rewriteValueMIPS64_OpLoad_0(v)
|
||||
case OpLocalAddr:
|
||||
return rewriteValueMIPS64_OpLocalAddr_0(v)
|
||||
case OpLsh16x16:
|
||||
return rewriteValueMIPS64_OpLsh16x16_0(v)
|
||||
case OpLsh16x32:
|
||||
|
|
@ -2924,6 +2926,20 @@ func rewriteValueMIPS64_OpLoad_0(v *Value) bool {
|
|||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueMIPS64_OpLocalAddr_0(v *Value) bool {
|
||||
// match: (LocalAddr {sym} base _)
|
||||
// cond:
|
||||
// result: (MOVVaddr {sym} base)
|
||||
for {
|
||||
sym := v.Aux
|
||||
_ = v.Args[1]
|
||||
base := v.Args[0]
|
||||
v.reset(OpMIPS64MOVVaddr)
|
||||
v.Aux = sym
|
||||
v.AddArg(base)
|
||||
return true
|
||||
}
|
||||
}
|
||||
func rewriteValueMIPS64_OpLsh16x16_0(v *Value) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
|
|
|
|||
|
|
@ -275,6 +275,8 @@ func rewriteValuePPC64(v *Value) bool {
|
|||
return rewriteValuePPC64_OpLess8U_0(v)
|
||||
case OpLoad:
|
||||
return rewriteValuePPC64_OpLoad_0(v)
|
||||
case OpLocalAddr:
|
||||
return rewriteValuePPC64_OpLocalAddr_0(v)
|
||||
case OpLsh16x16:
|
||||
return rewriteValuePPC64_OpLsh16x16_0(v)
|
||||
case OpLsh16x32:
|
||||
|
|
@ -3048,6 +3050,20 @@ func rewriteValuePPC64_OpLoad_0(v *Value) bool {
|
|||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValuePPC64_OpLocalAddr_0(v *Value) bool {
|
||||
// match: (LocalAddr {sym} base _)
|
||||
// cond:
|
||||
// result: (MOVDaddr {sym} base)
|
||||
for {
|
||||
sym := v.Aux
|
||||
_ = v.Args[1]
|
||||
base := v.Args[0]
|
||||
v.reset(OpPPC64MOVDaddr)
|
||||
v.Aux = sym
|
||||
v.AddArg(base)
|
||||
return true
|
||||
}
|
||||
}
|
||||
func rewriteValuePPC64_OpLsh16x16_0(v *Value) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
|
|
|
|||
|
|
@ -275,6 +275,8 @@ func rewriteValueS390X(v *Value) bool {
|
|||
return rewriteValueS390X_OpLess8U_0(v)
|
||||
case OpLoad:
|
||||
return rewriteValueS390X_OpLoad_0(v)
|
||||
case OpLocalAddr:
|
||||
return rewriteValueS390X_OpLocalAddr_0(v)
|
||||
case OpLsh16x16:
|
||||
return rewriteValueS390X_OpLsh16x16_0(v)
|
||||
case OpLsh16x32:
|
||||
|
|
@ -3477,6 +3479,20 @@ func rewriteValueS390X_OpLoad_0(v *Value) bool {
|
|||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueS390X_OpLocalAddr_0(v *Value) bool {
|
||||
// match: (LocalAddr {sym} base _)
|
||||
// cond:
|
||||
// result: (MOVDaddr {sym} base)
|
||||
for {
|
||||
sym := v.Aux
|
||||
_ = v.Args[1]
|
||||
base := v.Args[0]
|
||||
v.reset(OpS390XMOVDaddr)
|
||||
v.Aux = sym
|
||||
v.AddArg(base)
|
||||
return true
|
||||
}
|
||||
}
|
||||
func rewriteValueS390X_OpLsh16x16_0(v *Value) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
|
|
|
|||
|
|
@ -237,6 +237,8 @@ func rewriteValueWasm(v *Value) bool {
|
|||
return rewriteValueWasm_OpLess8U_0(v)
|
||||
case OpLoad:
|
||||
return rewriteValueWasm_OpLoad_0(v)
|
||||
case OpLocalAddr:
|
||||
return rewriteValueWasm_OpLocalAddr_0(v)
|
||||
case OpLsh16x16:
|
||||
return rewriteValueWasm_OpLsh16x16_0(v)
|
||||
case OpLsh16x32:
|
||||
|
|
@ -2496,6 +2498,20 @@ func rewriteValueWasm_OpLoad_0(v *Value) bool {
|
|||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueWasm_OpLocalAddr_0(v *Value) bool {
|
||||
// match: (LocalAddr {sym} base _)
|
||||
// cond:
|
||||
// result: (LoweredAddr {sym} base)
|
||||
for {
|
||||
sym := v.Aux
|
||||
_ = v.Args[1]
|
||||
base := v.Args[0]
|
||||
v.reset(OpWasmLoweredAddr)
|
||||
v.Aux = sym
|
||||
v.AddArg(base)
|
||||
return true
|
||||
}
|
||||
}
|
||||
func rewriteValueWasm_OpLsh16x16_0(v *Value) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ func rewriteValuegeneric(v *Value) bool {
|
|||
case OpEqInter:
|
||||
return rewriteValuegeneric_OpEqInter_0(v)
|
||||
case OpEqPtr:
|
||||
return rewriteValuegeneric_OpEqPtr_0(v) || rewriteValuegeneric_OpEqPtr_10(v)
|
||||
return rewriteValuegeneric_OpEqPtr_0(v) || rewriteValuegeneric_OpEqPtr_10(v) || rewriteValuegeneric_OpEqPtr_20(v)
|
||||
case OpEqSlice:
|
||||
return rewriteValuegeneric_OpEqSlice_0(v)
|
||||
case OpGeq16:
|
||||
|
|
@ -300,7 +300,7 @@ func rewriteValuegeneric(v *Value) bool {
|
|||
case OpNeqInter:
|
||||
return rewriteValuegeneric_OpNeqInter_0(v)
|
||||
case OpNeqPtr:
|
||||
return rewriteValuegeneric_OpNeqPtr_0(v) || rewriteValuegeneric_OpNeqPtr_10(v)
|
||||
return rewriteValuegeneric_OpNeqPtr_0(v) || rewriteValuegeneric_OpNeqPtr_10(v) || rewriteValuegeneric_OpNeqPtr_20(v)
|
||||
case OpNeqSlice:
|
||||
return rewriteValuegeneric_OpNeqSlice_0(v)
|
||||
case OpNilCheck:
|
||||
|
|
@ -10542,6 +10542,48 @@ func rewriteValuegeneric_OpEqPtr_0(v *Value) bool {
|
|||
v.AuxInt = b2i(a == b)
|
||||
return true
|
||||
}
|
||||
// match: (EqPtr (LocalAddr {a} _ _) (LocalAddr {b} _ _))
|
||||
// cond:
|
||||
// result: (ConstBool [b2i(a == b)])
|
||||
for {
|
||||
_ = v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
if v_0.Op != OpLocalAddr {
|
||||
break
|
||||
}
|
||||
a := v_0.Aux
|
||||
_ = v_0.Args[1]
|
||||
v_1 := v.Args[1]
|
||||
if v_1.Op != OpLocalAddr {
|
||||
break
|
||||
}
|
||||
b := v_1.Aux
|
||||
_ = v_1.Args[1]
|
||||
v.reset(OpConstBool)
|
||||
v.AuxInt = b2i(a == b)
|
||||
return true
|
||||
}
|
||||
// match: (EqPtr (LocalAddr {b} _ _) (LocalAddr {a} _ _))
|
||||
// cond:
|
||||
// result: (ConstBool [b2i(a == b)])
|
||||
for {
|
||||
_ = v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
if v_0.Op != OpLocalAddr {
|
||||
break
|
||||
}
|
||||
b := v_0.Aux
|
||||
_ = v_0.Args[1]
|
||||
v_1 := v.Args[1]
|
||||
if v_1.Op != OpLocalAddr {
|
||||
break
|
||||
}
|
||||
a := v_1.Aux
|
||||
_ = v_1.Args[1]
|
||||
v.reset(OpConstBool)
|
||||
v.AuxInt = b2i(a == b)
|
||||
return true
|
||||
}
|
||||
// match: (EqPtr (OffPtr [o1] p1) p2)
|
||||
// cond: isSamePtr(p1, p2)
|
||||
// result: (ConstBool [b2i(o1 == 0)])
|
||||
|
|
@ -10647,6 +10689,13 @@ func rewriteValuegeneric_OpEqPtr_0(v *Value) bool {
|
|||
v.AuxInt = b2i(c == d)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValuegeneric_OpEqPtr_10(v *Value) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
typ := &b.Func.Config.Types
|
||||
_ = typ
|
||||
// match: (EqPtr (Const32 [d]) (Const32 [c]))
|
||||
// cond:
|
||||
// result: (ConstBool [b2i(c == d)])
|
||||
|
|
@ -10685,13 +10734,6 @@ func rewriteValuegeneric_OpEqPtr_0(v *Value) bool {
|
|||
v.AuxInt = b2i(c == d)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValuegeneric_OpEqPtr_10(v *Value) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
typ := &b.Func.Config.Types
|
||||
_ = typ
|
||||
// match: (EqPtr (Const64 [d]) (Const64 [c]))
|
||||
// cond:
|
||||
// result: (ConstBool [b2i(c == d)])
|
||||
|
|
@ -10711,6 +10753,78 @@ func rewriteValuegeneric_OpEqPtr_10(v *Value) bool {
|
|||
v.AuxInt = b2i(c == d)
|
||||
return true
|
||||
}
|
||||
// match: (EqPtr (LocalAddr _ _) (Addr _))
|
||||
// cond:
|
||||
// result: (ConstBool [0])
|
||||
for {
|
||||
_ = v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
if v_0.Op != OpLocalAddr {
|
||||
break
|
||||
}
|
||||
_ = v_0.Args[1]
|
||||
v_1 := v.Args[1]
|
||||
if v_1.Op != OpAddr {
|
||||
break
|
||||
}
|
||||
v.reset(OpConstBool)
|
||||
v.AuxInt = 0
|
||||
return true
|
||||
}
|
||||
// match: (EqPtr (Addr _) (LocalAddr _ _))
|
||||
// cond:
|
||||
// result: (ConstBool [0])
|
||||
for {
|
||||
_ = v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
if v_0.Op != OpAddr {
|
||||
break
|
||||
}
|
||||
v_1 := v.Args[1]
|
||||
if v_1.Op != OpLocalAddr {
|
||||
break
|
||||
}
|
||||
_ = v_1.Args[1]
|
||||
v.reset(OpConstBool)
|
||||
v.AuxInt = 0
|
||||
return true
|
||||
}
|
||||
// match: (EqPtr (Addr _) (LocalAddr _ _))
|
||||
// cond:
|
||||
// result: (ConstBool [0])
|
||||
for {
|
||||
_ = v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
if v_0.Op != OpAddr {
|
||||
break
|
||||
}
|
||||
v_1 := v.Args[1]
|
||||
if v_1.Op != OpLocalAddr {
|
||||
break
|
||||
}
|
||||
_ = v_1.Args[1]
|
||||
v.reset(OpConstBool)
|
||||
v.AuxInt = 0
|
||||
return true
|
||||
}
|
||||
// match: (EqPtr (LocalAddr _ _) (Addr _))
|
||||
// cond:
|
||||
// result: (ConstBool [0])
|
||||
for {
|
||||
_ = v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
if v_0.Op != OpLocalAddr {
|
||||
break
|
||||
}
|
||||
_ = v_0.Args[1]
|
||||
v_1 := v.Args[1]
|
||||
if v_1.Op != OpAddr {
|
||||
break
|
||||
}
|
||||
v.reset(OpConstBool)
|
||||
v.AuxInt = 0
|
||||
return true
|
||||
}
|
||||
// match: (EqPtr (AddPtr p1 o1) p2)
|
||||
// cond: isSamePtr(p1, p2)
|
||||
// result: (Not (IsNonNil o1))
|
||||
|
|
@ -10774,6 +10888,13 @@ func rewriteValuegeneric_OpEqPtr_10(v *Value) bool {
|
|||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValuegeneric_OpEqPtr_20(v *Value) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
typ := &b.Func.Config.Types
|
||||
_ = typ
|
||||
// match: (EqPtr p (Const32 [0]))
|
||||
// cond:
|
||||
// result: (Not (IsNonNil p))
|
||||
|
|
@ -12525,6 +12646,19 @@ func rewriteValuegeneric_OpIsNonNil_0(v *Value) bool {
|
|||
v.AuxInt = 1
|
||||
return true
|
||||
}
|
||||
// match: (IsNonNil (LocalAddr _ _))
|
||||
// cond:
|
||||
// result: (ConstBool [1])
|
||||
for {
|
||||
v_0 := v.Args[0]
|
||||
if v_0.Op != OpLocalAddr {
|
||||
break
|
||||
}
|
||||
_ = v_0.Args[1]
|
||||
v.reset(OpConstBool)
|
||||
v.AuxInt = 1
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValuegeneric_OpIsSliceInBounds_0(v *Value) bool {
|
||||
|
|
@ -20810,6 +20944,48 @@ func rewriteValuegeneric_OpNeqPtr_0(v *Value) bool {
|
|||
v.AuxInt = b2i(a != b)
|
||||
return true
|
||||
}
|
||||
// match: (NeqPtr (LocalAddr {a} _ _) (LocalAddr {b} _ _))
|
||||
// cond:
|
||||
// result: (ConstBool [b2i(a != b)])
|
||||
for {
|
||||
_ = v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
if v_0.Op != OpLocalAddr {
|
||||
break
|
||||
}
|
||||
a := v_0.Aux
|
||||
_ = v_0.Args[1]
|
||||
v_1 := v.Args[1]
|
||||
if v_1.Op != OpLocalAddr {
|
||||
break
|
||||
}
|
||||
b := v_1.Aux
|
||||
_ = v_1.Args[1]
|
||||
v.reset(OpConstBool)
|
||||
v.AuxInt = b2i(a != b)
|
||||
return true
|
||||
}
|
||||
// match: (NeqPtr (LocalAddr {b} _ _) (LocalAddr {a} _ _))
|
||||
// cond:
|
||||
// result: (ConstBool [b2i(a != b)])
|
||||
for {
|
||||
_ = v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
if v_0.Op != OpLocalAddr {
|
||||
break
|
||||
}
|
||||
b := v_0.Aux
|
||||
_ = v_0.Args[1]
|
||||
v_1 := v.Args[1]
|
||||
if v_1.Op != OpLocalAddr {
|
||||
break
|
||||
}
|
||||
a := v_1.Aux
|
||||
_ = v_1.Args[1]
|
||||
v.reset(OpConstBool)
|
||||
v.AuxInt = b2i(a != b)
|
||||
return true
|
||||
}
|
||||
// match: (NeqPtr (OffPtr [o1] p1) p2)
|
||||
// cond: isSamePtr(p1, p2)
|
||||
// result: (ConstBool [b2i(o1 != 0)])
|
||||
|
|
@ -20915,6 +21091,9 @@ func rewriteValuegeneric_OpNeqPtr_0(v *Value) bool {
|
|||
v.AuxInt = b2i(c != d)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValuegeneric_OpNeqPtr_10(v *Value) bool {
|
||||
// match: (NeqPtr (Const32 [d]) (Const32 [c]))
|
||||
// cond:
|
||||
// result: (ConstBool [b2i(c != d)])
|
||||
|
|
@ -20953,9 +21132,6 @@ func rewriteValuegeneric_OpNeqPtr_0(v *Value) bool {
|
|||
v.AuxInt = b2i(c != d)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValuegeneric_OpNeqPtr_10(v *Value) bool {
|
||||
// match: (NeqPtr (Const64 [d]) (Const64 [c]))
|
||||
// cond:
|
||||
// result: (ConstBool [b2i(c != d)])
|
||||
|
|
@ -20975,6 +21151,78 @@ func rewriteValuegeneric_OpNeqPtr_10(v *Value) bool {
|
|||
v.AuxInt = b2i(c != d)
|
||||
return true
|
||||
}
|
||||
// match: (NeqPtr (LocalAddr _ _) (Addr _))
|
||||
// cond:
|
||||
// result: (ConstBool [1])
|
||||
for {
|
||||
_ = v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
if v_0.Op != OpLocalAddr {
|
||||
break
|
||||
}
|
||||
_ = v_0.Args[1]
|
||||
v_1 := v.Args[1]
|
||||
if v_1.Op != OpAddr {
|
||||
break
|
||||
}
|
||||
v.reset(OpConstBool)
|
||||
v.AuxInt = 1
|
||||
return true
|
||||
}
|
||||
// match: (NeqPtr (Addr _) (LocalAddr _ _))
|
||||
// cond:
|
||||
// result: (ConstBool [1])
|
||||
for {
|
||||
_ = v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
if v_0.Op != OpAddr {
|
||||
break
|
||||
}
|
||||
v_1 := v.Args[1]
|
||||
if v_1.Op != OpLocalAddr {
|
||||
break
|
||||
}
|
||||
_ = v_1.Args[1]
|
||||
v.reset(OpConstBool)
|
||||
v.AuxInt = 1
|
||||
return true
|
||||
}
|
||||
// match: (NeqPtr (Addr _) (LocalAddr _ _))
|
||||
// cond:
|
||||
// result: (ConstBool [1])
|
||||
for {
|
||||
_ = v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
if v_0.Op != OpAddr {
|
||||
break
|
||||
}
|
||||
v_1 := v.Args[1]
|
||||
if v_1.Op != OpLocalAddr {
|
||||
break
|
||||
}
|
||||
_ = v_1.Args[1]
|
||||
v.reset(OpConstBool)
|
||||
v.AuxInt = 1
|
||||
return true
|
||||
}
|
||||
// match: (NeqPtr (LocalAddr _ _) (Addr _))
|
||||
// cond:
|
||||
// result: (ConstBool [1])
|
||||
for {
|
||||
_ = v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
if v_0.Op != OpLocalAddr {
|
||||
break
|
||||
}
|
||||
_ = v_0.Args[1]
|
||||
v_1 := v.Args[1]
|
||||
if v_1.Op != OpAddr {
|
||||
break
|
||||
}
|
||||
v.reset(OpConstBool)
|
||||
v.AuxInt = 1
|
||||
return true
|
||||
}
|
||||
// match: (NeqPtr (AddPtr p1 o1) p2)
|
||||
// cond: isSamePtr(p1, p2)
|
||||
// result: (IsNonNil o1)
|
||||
|
|
@ -21032,6 +21280,9 @@ func rewriteValuegeneric_OpNeqPtr_10(v *Value) bool {
|
|||
v.AddArg(p)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValuegeneric_OpNeqPtr_20(v *Value) bool {
|
||||
// match: (NeqPtr p (Const32 [0]))
|
||||
// cond:
|
||||
// result: (IsNonNil p)
|
||||
|
|
|
|||
|
|
@ -306,7 +306,7 @@ func wbcall(pos src.XPos, b *Block, fn, typ *obj.LSym, ptr, val, mem, sp, sb *Va
|
|||
t := val.Type.Elem()
|
||||
tmp = b.Func.fe.Auto(val.Pos, t)
|
||||
mem = b.NewValue1A(pos, OpVarDef, types.TypeMem, tmp, mem)
|
||||
tmpaddr := b.NewValue1A(pos, OpAddr, t.PtrTo(), tmp, sp)
|
||||
tmpaddr := b.NewValue2A(pos, OpLocalAddr, t.PtrTo(), tmp, sp, mem)
|
||||
siz := t.Size()
|
||||
mem = b.NewValue3I(pos, OpMove, types.TypeMem, siz, tmpaddr, val, mem)
|
||||
mem.Aux = t
|
||||
|
|
@ -359,10 +359,8 @@ func IsStackAddr(v *Value) bool {
|
|||
v = v.Args[0]
|
||||
}
|
||||
switch v.Op {
|
||||
case OpSP:
|
||||
case OpSP, OpLocalAddr:
|
||||
return true
|
||||
case OpAddr:
|
||||
return v.Args[0].Op == OpSP
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
@ -374,7 +372,7 @@ func IsSanitizerSafeAddr(v *Value) bool {
|
|||
v = v.Args[0]
|
||||
}
|
||||
switch v.Op {
|
||||
case OpSP:
|
||||
case OpSP, OpLocalAddr:
|
||||
// Stack addresses are always safe.
|
||||
return true
|
||||
case OpITab, OpStringPtr, OpGetClosurePtr:
|
||||
|
|
@ -382,19 +380,14 @@ func IsSanitizerSafeAddr(v *Value) bool {
|
|||
// read-only once initialized.
|
||||
return true
|
||||
case OpAddr:
|
||||
switch v.Args[0].Op {
|
||||
case OpSP:
|
||||
sym := v.Aux.(*obj.LSym)
|
||||
// TODO(mdempsky): Find a cleaner way to
|
||||
// detect this. It would be nice if we could
|
||||
// test sym.Type==objabi.SRODATA, but we don't
|
||||
// initialize sym.Type until after function
|
||||
// compilation.
|
||||
if strings.HasPrefix(sym.Name, `"".statictmp_`) {
|
||||
return true
|
||||
case OpSB:
|
||||
sym := v.Aux.(*obj.LSym)
|
||||
// TODO(mdempsky): Find a cleaner way to
|
||||
// detect this. It would be nice if we could
|
||||
// test sym.Type==objabi.SRODATA, but we don't
|
||||
// initialize sym.Type until after function
|
||||
// compilation.
|
||||
if strings.HasPrefix(sym.Name, `"".statictmp_`) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
// compile
|
||||
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Triggers a bug in writebarrier, which inserts one
|
||||
// between (first block) OpAddr x and (second block) a VarDef x,
|
||||
// which are then in the wrong order and unable to be
|
||||
// properly scheduled.
|
||||
|
||||
package q
|
||||
|
||||
var S interface{}
|
||||
|
||||
func F(n int) {
|
||||
fun := func(x int) int {
|
||||
S = 1
|
||||
return n
|
||||
}
|
||||
i := fun(([]int{})[n])
|
||||
|
||||
var fc [2]chan int
|
||||
S = (([1][2]chan int{fc})[i][i])
|
||||
}
|
||||
Loading…
Reference in New Issue