]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: add LocalAddr that takes SP,mem operands
authorDavid Chase <drchase@google.com>
Tue, 3 Jul 2018 15:34:38 +0000 (11:34 -0400)
committerDavid Chase <drchase@google.com>
Thu, 12 Jul 2018 18:45:31 +0000 (18:45 +0000)
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>
34 files changed:
src/cmd/compile/internal/gc/ssa.go
src/cmd/compile/internal/ssa/check.go
src/cmd/compile/internal/ssa/cse_test.go
src/cmd/compile/internal/ssa/deadstore.go
src/cmd/compile/internal/ssa/func.go
src/cmd/compile/internal/ssa/gen/386.rules
src/cmd/compile/internal/ssa/gen/AMD64.rules
src/cmd/compile/internal/ssa/gen/ARM.rules
src/cmd/compile/internal/ssa/gen/ARM64.rules
src/cmd/compile/internal/ssa/gen/MIPS.rules
src/cmd/compile/internal/ssa/gen/MIPS64.rules
src/cmd/compile/internal/ssa/gen/PPC64.rules
src/cmd/compile/internal/ssa/gen/S390X.rules
src/cmd/compile/internal/ssa/gen/Wasm.rules
src/cmd/compile/internal/ssa/gen/generic.rules
src/cmd/compile/internal/ssa/gen/genericOps.go
src/cmd/compile/internal/ssa/loop_test.go
src/cmd/compile/internal/ssa/nilcheck.go
src/cmd/compile/internal/ssa/nilcheck_test.go
src/cmd/compile/internal/ssa/numberlines.go
src/cmd/compile/internal/ssa/opGen.go
src/cmd/compile/internal/ssa/rewrite.go
src/cmd/compile/internal/ssa/rewrite386.go
src/cmd/compile/internal/ssa/rewriteAMD64.go
src/cmd/compile/internal/ssa/rewriteARM.go
src/cmd/compile/internal/ssa/rewriteARM64.go
src/cmd/compile/internal/ssa/rewriteMIPS.go
src/cmd/compile/internal/ssa/rewriteMIPS64.go
src/cmd/compile/internal/ssa/rewritePPC64.go
src/cmd/compile/internal/ssa/rewriteS390X.go
src/cmd/compile/internal/ssa/rewriteWasm.go
src/cmd/compile/internal/ssa/rewritegeneric.go
src/cmd/compile/internal/ssa/writebarrier.go
test/fixedbugs/issue26105.go [new file with mode: 0644]

index ff2b93d3d4d98d0c571559a609ccbc783a713cfb..553713a1e9bbba543ee9a786e7e861249b9d8505 100644 (file)
@@ -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
index a0ef5fbced5d329f703e1ac05dc5879f4ad32239..556e7fb7f75d0e0e06d1acb8c7cd55e7562de42b 100644 (file)
@@ -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())
                        }
index adb8664945dbb24bb28de093aa48a48dcd474055..b1397019908a0c829d8a240efb969add29ef47c1 100644 (file)
@@ -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")),
index e92521a79c13508d7103346dc93ea5d25bf22f11..6359588129781458424b6100e6a270dbe2260a69 100644 (file)
@@ -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 {
index 85d41d124bd70dade812f3cb57e08e9410480f25..eb5775efcbd01876922440d98477260a5b5a6b8d 100644 (file)
@@ -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)
index 570685436a30880c7341501602e935235dc36771..65ac53268976a1d32d84e11eeb7c622431d2eeca 100644 (file)
 (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)
index 9549ebfab35c7a62306ec9711dcb12bbbc9459ea..54de6e055debdc48b2aed8c95035b4cac063ed3e 100644 (file)
 (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)
index 65b11c998068dfb2f161d487ecfb4769bb1c865f..45e68c6aed9588ccc8ad0ef3053f987a5b410a02 100644 (file)
 (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)
index a7e747e6e70f5c36c942d5fce9b12118fd6050de..d9e614f61a2832abd9d8b558f7cc3135953cfd8b 100644 (file)
 (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)
index 50fdf29b04fa87b68c95815987fc2214334b3f0e..098e19c8a82642d2fab9dae369949c96d49d4553 100644 (file)
 (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)
index f5e78ec2944a9721f55aa77dbdd7dd3420aacc7c..70f4f0d616f75ae701bb18a9afe41e64bfc5bdf5 100644 (file)
 (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)
index a668b610930ec3e601b323dbb0a98d2380646023..6ef8c7b5b9a63a0ffa5d22048a4c32744b755858 100644 (file)
 // (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?
index 61ac734224c15198d5a8a22d7b211d386b082d2f..960d68845f1c32c8e9922dcfd643bf8c67ccfb3c 100644 (file)
 (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
index 272b260cb7dcc83396d7443c6ece1d55c52b14d9..dc1581362c6d5629b6634f292a6c2a6aa0c0cfc6 100644 (file)
 (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)
index 7931aa7f06d2f3bbea449724ae94fa80788ac431..0b68db7f0465df7ff30f3702a49f8711dd0bcd01 100644 (file)
 (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)])
 (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)
 (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))))
index 07d93ac07350cab8c890165a042df26096a17ba3..a5b80770bb13ef069bc4f09d5790d2f5775bd969 100644 (file)
@@ -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)
index 6810f5f797f78c99e580caea6de93b2251fc6f53..8f72930bcea0f72fb4fb6faf8fa80ee4f805b0da 100644 (file)
@@ -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),
index 2e4ad064a9a04bc27844bd497ac6a04940892a7b..0359e25c9873526bd4e64b5568f07a1b2a10dfef 100644 (file)
@@ -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
                        }
                }
index 3ca033797d7db451299fd87fca3baf5c7badb6a9..815c4a5047289f9701a59558a49b11297ccc2959 100644 (file)
@@ -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",
index 997b05c3a2c6c4ea7e513593db8e134e3289325c..662f58e4b576690b24218bdab12ff09cfaba476f 100644 (file)
@@ -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
index 1942ab148aaa685f14c9cad05611fca58661e86d..b479bca7ff470a028a159e5c1689270f62e8c15f 100644 (file)
@@ -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,
index d581160b5fda3fc881b8465c5dc36008868e3f24..5e151b5213d29b656c1dffd719b9dd3e9cfec2ad 100644 (file)
@@ -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
 }
index 7d9810b4a652cd454a99141db92be9c81b4f1684..a204d48d073bb90fcb5c1ea28e4511ed982e91b4 100644 (file)
@@ -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
index be4873caa013ce38b8d10f3c5dbf365cd7c31179..47d3f431ab22ef98f623ef29f65a89b6b794ad87 100644 (file)
@@ -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
index 1eb32285cd1f81d291d3b39a04a18aaebdad4b6c..5e9ce5c96c11b4678b3eb15f43e51948196ca120 100644 (file)
@@ -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
index d039c731d379e56d395cc7090de59b65069bd410..cea9d03a9d51678e71473a44a507227bfe137a1d 100644 (file)
@@ -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
index c101e91636fdde510dfa83bcb94e5dc697827408..231949644ee8dcbe565983705216e41a81495c33 100644 (file)
@@ -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
index 084463a10fba14a75065a1e486a68201ef19ae08..9cd0050e26d1a2c5e4c974130f02a7c731a9f07f 100644 (file)
@@ -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
index 8dc3d008b098c6e3046dcc701f01ba28b2595a8c..ba6a862989ff64c8125f603d142567ee0103a3d9 100644 (file)
@@ -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
index d5d392b94a590c04d2ba472d988a673a5683aa54..7125b888bdbfdc5d57b9490fc7a5e87eae1cd9f5 100644 (file)
@@ -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
index 26dd254952f3951e2bfd09b243e2417ef83bd462..c07651ef0ecb38d28c95d9e4bb9c53373fa22a7d 100644 (file)
@@ -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
index 357be7693712a2b7b3d8860c48778aaf36befedb..a1c83ea37834ef7aa6fee21d3549e5019093144b 100644 (file)
@@ -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)
index 92b8b006b7ec44ddda7dbc3aa7e59ccd68c1ed2a..2366e0bfbf358c2757891bb64abfa9925cdf39cd 100644 (file)
@@ -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
diff --git a/test/fixedbugs/issue26105.go b/test/fixedbugs/issue26105.go
new file mode 100644 (file)
index 0000000..88a5f16
--- /dev/null
@@ -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])
+}