From: David Chase Date: Tue, 3 Jul 2018 15:34:38 +0000 (-0400) Subject: cmd/compile: add LocalAddr that takes SP,mem operands X-Git-Tag: go1.11beta2~127 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=0029cd479e344e0fa6930331cf86e6f985508163;p=gostls13.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 Reviewed-by: Keith Randall --- diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index ff2b93d3d4..553713a1e9 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -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 diff --git a/src/cmd/compile/internal/ssa/check.go b/src/cmd/compile/internal/ssa/check.go index a0ef5fbced..556e7fb7f7 100644 --- a/src/cmd/compile/internal/ssa/check.go +++ b/src/cmd/compile/internal/ssa/check.go @@ -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()) } diff --git a/src/cmd/compile/internal/ssa/cse_test.go b/src/cmd/compile/internal/ssa/cse_test.go index adb8664945..b139701990 100644 --- a/src/cmd/compile/internal/ssa/cse_test.go +++ b/src/cmd/compile/internal/ssa/cse_test.go @@ -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")), diff --git a/src/cmd/compile/internal/ssa/deadstore.go b/src/cmd/compile/internal/ssa/deadstore.go index e92521a79c..6359588129 100644 --- a/src/cmd/compile/internal/ssa/deadstore.go +++ b/src/cmd/compile/internal/ssa/deadstore.go @@ -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 { diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go index 85d41d124b..eb5775efcb 100644 --- a/src/cmd/compile/internal/ssa/func.go +++ b/src/cmd/compile/internal/ssa/func.go @@ -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) diff --git a/src/cmd/compile/internal/ssa/gen/386.rules b/src/cmd/compile/internal/ssa/gen/386.rules index 570685436a..65ac532689 100644 --- a/src/cmd/compile/internal/ssa/gen/386.rules +++ b/src/cmd/compile/internal/ssa/gen/386.rules @@ -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) diff --git a/src/cmd/compile/internal/ssa/gen/AMD64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules index 9549ebfab3..54de6e055d 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64.rules +++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules @@ -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) diff --git a/src/cmd/compile/internal/ssa/gen/ARM.rules b/src/cmd/compile/internal/ssa/gen/ARM.rules index 65b11c9980..45e68c6aed 100644 --- a/src/cmd/compile/internal/ssa/gen/ARM.rules +++ b/src/cmd/compile/internal/ssa/gen/ARM.rules @@ -253,6 +253,7 @@ (OffPtr [off] ptr) -> (ADDconst [off] ptr) (Addr {sym} base) -> (MOVWaddr {sym} base) +(LocalAddr {sym} base _) -> (MOVWaddr {sym} base) // loads (Load ptr mem) && t.IsBoolean() -> (MOVBUload ptr mem) diff --git a/src/cmd/compile/internal/ssa/gen/ARM64.rules b/src/cmd/compile/internal/ssa/gen/ARM64.rules index a7e747e6e7..d9e614f61a 100644 --- a/src/cmd/compile/internal/ssa/gen/ARM64.rules +++ b/src/cmd/compile/internal/ssa/gen/ARM64.rules @@ -317,6 +317,7 @@ (OffPtr [off] ptr) -> (ADDconst [off] ptr) (Addr {sym} base) -> (MOVDaddr {sym} base) +(LocalAddr {sym} base _) -> (MOVDaddr {sym} base) // loads (Load ptr mem) && t.IsBoolean() -> (MOVBUload ptr mem) diff --git a/src/cmd/compile/internal/ssa/gen/MIPS.rules b/src/cmd/compile/internal/ssa/gen/MIPS.rules index 50fdf29b04..098e19c8a8 100644 --- a/src/cmd/compile/internal/ssa/gen/MIPS.rules +++ b/src/cmd/compile/internal/ssa/gen/MIPS.rules @@ -219,6 +219,7 @@ (OffPtr [off] ptr) -> (ADDconst [off] ptr) (Addr {sym} base) -> (MOVWaddr {sym} base) +(LocalAddr {sym} base _) -> (MOVWaddr {sym} base) // loads (Load ptr mem) && t.IsBoolean() -> (MOVBUload ptr mem) diff --git a/src/cmd/compile/internal/ssa/gen/MIPS64.rules b/src/cmd/compile/internal/ssa/gen/MIPS64.rules index f5e78ec294..70f4f0d616 100644 --- a/src/cmd/compile/internal/ssa/gen/MIPS64.rules +++ b/src/cmd/compile/internal/ssa/gen/MIPS64.rules @@ -229,6 +229,7 @@ (OffPtr [off] ptr) -> (ADDVconst [off] ptr) (Addr {sym} base) -> (MOVVaddr {sym} base) +(LocalAddr {sym} base _) -> (MOVVaddr {sym} base) // loads (Load ptr mem) && t.IsBoolean() -> (MOVBUload ptr mem) diff --git a/src/cmd/compile/internal/ssa/gen/PPC64.rules b/src/cmd/compile/internal/ssa/gen/PPC64.rules index a668b61093..6ef8c7b5b9 100644 --- a/src/cmd/compile/internal/ssa/gen/PPC64.rules +++ b/src/cmd/compile/internal/ssa/gen/PPC64.rules @@ -273,6 +273,7 @@ // (MaskIfNotCarry CarrySet) -> -1 (Addr {sym} base) -> (MOVDaddr {sym} base) +(LocalAddr {sym} base _) -> (MOVDaddr {sym} base) (OffPtr [off] ptr) -> (ADD (MOVDconst [off]) ptr) // TODO: optimize these cases? diff --git a/src/cmd/compile/internal/ssa/gen/S390X.rules b/src/cmd/compile/internal/ssa/gen/S390X.rules index 61ac734224..960d68845f 100644 --- a/src/cmd/compile/internal/ssa/gen/S390X.rules +++ b/src/cmd/compile/internal/ssa/gen/S390X.rules @@ -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 diff --git a/src/cmd/compile/internal/ssa/gen/Wasm.rules b/src/cmd/compile/internal/ssa/gen/Wasm.rules index 272b260cb7..dc1581362c 100644 --- a/src/cmd/compile/internal/ssa/gen/Wasm.rules +++ b/src/cmd/compile/internal/ssa/gen/Wasm.rules @@ -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) diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules index 7931aa7f06..0b68db7f04 100644 --- a/src/cmd/compile/internal/ssa/gen/generic.rules +++ b/src/cmd/compile/internal/ssa/gen/generic.rules @@ -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)))) diff --git a/src/cmd/compile/internal/ssa/gen/genericOps.go b/src/cmd/compile/internal/ssa/gen/genericOps.go index 07d93ac073..a5b80770bb 100644 --- a/src/cmd/compile/internal/ssa/gen/genericOps.go +++ b/src/cmd/compile/internal/ssa/gen/genericOps.go @@ -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) diff --git a/src/cmd/compile/internal/ssa/loop_test.go b/src/cmd/compile/internal/ssa/loop_test.go index 6810f5f797..8f72930bce 100644 --- a/src/cmd/compile/internal/ssa/loop_test.go +++ b/src/cmd/compile/internal/ssa/loop_test.go @@ -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), diff --git a/src/cmd/compile/internal/ssa/nilcheck.go b/src/cmd/compile/internal/ssa/nilcheck.go index 2e4ad064a9..0359e25c98 100644 --- a/src/cmd/compile/internal/ssa/nilcheck.go +++ b/src/cmd/compile/internal/ssa/nilcheck.go @@ -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 } } diff --git a/src/cmd/compile/internal/ssa/nilcheck_test.go b/src/cmd/compile/internal/ssa/nilcheck_test.go index 3ca033797d..815c4a5047 100644 --- a/src/cmd/compile/internal/ssa/nilcheck_test.go +++ b/src/cmd/compile/internal/ssa/nilcheck_test.go @@ -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", diff --git a/src/cmd/compile/internal/ssa/numberlines.go b/src/cmd/compile/internal/ssa/numberlines.go index 997b05c3a2..662f58e4b5 100644 --- a/src/cmd/compile/internal/ssa/numberlines.go +++ b/src/cmd/compile/internal/ssa/numberlines.go @@ -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 diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index 1942ab148a..b479bca7ff 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -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, diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go index d581160b5f..5e151b5213 100644 --- a/src/cmd/compile/internal/ssa/rewrite.go +++ b/src/cmd/compile/internal/ssa/rewrite.go @@ -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 } diff --git a/src/cmd/compile/internal/ssa/rewrite386.go b/src/cmd/compile/internal/ssa/rewrite386.go index 7d9810b4a6..a204d48d07 100644 --- a/src/cmd/compile/internal/ssa/rewrite386.go +++ b/src/cmd/compile/internal/ssa/rewrite386.go @@ -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 diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go index be4873caa0..47d3f431ab 100644 --- a/src/cmd/compile/internal/ssa/rewriteAMD64.go +++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go @@ -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 diff --git a/src/cmd/compile/internal/ssa/rewriteARM.go b/src/cmd/compile/internal/ssa/rewriteARM.go index 1eb32285cd..5e9ce5c96c 100644 --- a/src/cmd/compile/internal/ssa/rewriteARM.go +++ b/src/cmd/compile/internal/ssa/rewriteARM.go @@ -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 diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go index d039c731d3..cea9d03a9d 100644 --- a/src/cmd/compile/internal/ssa/rewriteARM64.go +++ b/src/cmd/compile/internal/ssa/rewriteARM64.go @@ -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 diff --git a/src/cmd/compile/internal/ssa/rewriteMIPS.go b/src/cmd/compile/internal/ssa/rewriteMIPS.go index c101e91636..231949644e 100644 --- a/src/cmd/compile/internal/ssa/rewriteMIPS.go +++ b/src/cmd/compile/internal/ssa/rewriteMIPS.go @@ -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 diff --git a/src/cmd/compile/internal/ssa/rewriteMIPS64.go b/src/cmd/compile/internal/ssa/rewriteMIPS64.go index 084463a10f..9cd0050e26 100644 --- a/src/cmd/compile/internal/ssa/rewriteMIPS64.go +++ b/src/cmd/compile/internal/ssa/rewriteMIPS64.go @@ -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 diff --git a/src/cmd/compile/internal/ssa/rewritePPC64.go b/src/cmd/compile/internal/ssa/rewritePPC64.go index 8dc3d008b0..ba6a862989 100644 --- a/src/cmd/compile/internal/ssa/rewritePPC64.go +++ b/src/cmd/compile/internal/ssa/rewritePPC64.go @@ -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 diff --git a/src/cmd/compile/internal/ssa/rewriteS390X.go b/src/cmd/compile/internal/ssa/rewriteS390X.go index d5d392b94a..7125b888bd 100644 --- a/src/cmd/compile/internal/ssa/rewriteS390X.go +++ b/src/cmd/compile/internal/ssa/rewriteS390X.go @@ -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 diff --git a/src/cmd/compile/internal/ssa/rewriteWasm.go b/src/cmd/compile/internal/ssa/rewriteWasm.go index 26dd254952..c07651ef0e 100644 --- a/src/cmd/compile/internal/ssa/rewriteWasm.go +++ b/src/cmd/compile/internal/ssa/rewriteWasm.go @@ -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 diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go index 357be76937..a1c83ea378 100644 --- a/src/cmd/compile/internal/ssa/rewritegeneric.go +++ b/src/cmd/compile/internal/ssa/rewritegeneric.go @@ -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) diff --git a/src/cmd/compile/internal/ssa/writebarrier.go b/src/cmd/compile/internal/ssa/writebarrier.go index 92b8b006b7..2366e0bfbf 100644 --- a/src/cmd/compile/internal/ssa/writebarrier.go +++ b/src/cmd/compile/internal/ssa/writebarrier.go @@ -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 index 0000000000..88a5f162f3 --- /dev/null +++ b/test/fixedbugs/issue26105.go @@ -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]) +}