diff --git a/src/cmd/compile/internal/liveness/mergelocals.go b/src/cmd/compile/internal/liveness/mergelocals.go
index 6967ee0..28d034a 100644
--- a/src/cmd/compile/internal/liveness/mergelocals.go
+++ b/src/cmd/compile/internal/liveness/mergelocals.go
@@ -513,8 +513,13 @@
}
}
}
- for _, arg := range v.Args {
+ for idx, arg := range v.Args {
if nc, ok := pendingUses[arg.ID]; ok {
+ if !v.AddrSinkArg(idx) {
+ // If this op may propagate the argument address to its output,
+ // then give up. See issue 80127.
+ continue
+ }
// We found a use of some value that took the
// address of nc.n. Record this inst as a
// potential indirect use.
diff --git a/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go
index 1488201..959aa414 100644
--- a/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go
+++ b/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go
@@ -998,6 +998,7 @@
inputs: []regMask{gp},
},
faultOnNilArg0: true,
+ addrSinkArg0: true,
},
// arg0 = pointer to start of memory to zero
@@ -1014,6 +1015,7 @@
},
clobberFlags: true,
faultOnNilArg0: true,
+ addrSinkArg0: true,
needIntTemp: true,
},
@@ -1030,6 +1032,7 @@
clobbers: buildReg("DI CX"),
},
faultOnNilArg0: true,
+ addrSinkArg0: true,
},
// With a register ABI, the actual register info for these instructions (i.e., what is used in regalloc) is augmented with per-call-site bindings of additional arguments to specific in and out registers.
@@ -1054,6 +1057,8 @@
},
faultOnNilArg0: true,
faultOnNilArg1: true,
+ addrSinkArg0: true,
+ addrSinkArg1: true,
},
// arg0 = destination pointer
// arg1 = source pointer
@@ -1073,6 +1078,8 @@
clobberFlags: true,
faultOnNilArg0: true,
faultOnNilArg1: true,
+ addrSinkArg0: true,
+ addrSinkArg1: true,
needIntTemp: true,
},
@@ -1090,6 +1097,8 @@
},
faultOnNilArg0: true,
faultOnNilArg1: true,
+ addrSinkArg0: true,
+ addrSinkArg1: true,
},
// (InvertFlags (CMPQ a b)) == (CMPQ b a)
diff --git a/src/cmd/compile/internal/ssa/_gen/ARM64Ops.go b/src/cmd/compile/internal/ssa/_gen/ARM64Ops.go
index 04d960f..61c2a26 100644
--- a/src/cmd/compile/internal/ssa/_gen/ARM64Ops.go
+++ b/src/cmd/compile/internal/ssa/_gen/ARM64Ops.go
@@ -424,13 +424,13 @@
{name: "FMOVDloadidx", argLength: 3, reg: fp2load, asm: "FMOVD", typ: "Float64"}, // load 64-bit float from arg0 + arg1, arg2=mem.
// shifted register indexed load
- {name: "MOVHloadidx2", argLength: 3, reg: gp2load, asm: "MOVH", typ: "Int16"}, // load 16-bit half-word from arg0 + arg1*2, sign-extended to 64-bit, arg2=mem.
- {name: "MOVHUloadidx2", argLength: 3, reg: gp2load, asm: "MOVHU", typ: "UInt16"}, // load 16-bit half-word from arg0 + arg1*2, zero-extended to 64-bit, arg2=mem.
- {name: "MOVWloadidx4", argLength: 3, reg: gp2load, asm: "MOVW", typ: "Int32"}, // load 32-bit word from arg0 + arg1*4, sign-extended to 64-bit, arg2=mem.
- {name: "MOVWUloadidx4", argLength: 3, reg: gp2load, asm: "MOVWU", typ: "UInt32"}, // load 32-bit word from arg0 + arg1*4, zero-extended to 64-bit, arg2=mem.
- {name: "MOVDloadidx8", argLength: 3, reg: gp2load, asm: "MOVD", typ: "UInt64"}, // load 64-bit double-word from arg0 + arg1*8, arg2 = mem.
- {name: "FMOVSloadidx4", argLength: 3, reg: fp2load, asm: "FMOVS", typ: "Float32"}, // load 32-bit float from arg0 + arg1*4, arg2 = mem.
- {name: "FMOVDloadidx8", argLength: 3, reg: fp2load, asm: "FMOVD", typ: "Float64"}, // load 64-bit float from arg0 + arg1*8, arg2 = mem.
+ {name: "MOVHloadidx2", argLength: 3, reg: gp2load, asm: "MOVH", typ: "Int16"}, // load 16-bit half-word from arg0 + arg1*2, sign-extended to 64-bit, arg2=mem.
+ {name: "MOVHUloadidx2", argLength: 3, reg: gp2load, asm: "MOVHU", typ: "UInt16"}, // load 16-bit half-word from arg0 + arg1*2, zero-extended to 64-bit, arg2=mem.
+ {name: "MOVWloadidx4", argLength: 3, reg: gp2load, asm: "MOVW", typ: "Int32"}, // load 32-bit word from arg0 + arg1*4, sign-extended to 64-bit, arg2=mem.
+ {name: "MOVWUloadidx4", argLength: 3, reg: gp2load, asm: "MOVWU", typ: "UInt32"}, // load 32-bit word from arg0 + arg1*4, zero-extended to 64-bit, arg2=mem.
+ {name: "MOVDloadidx8", argLength: 3, reg: gp2load, asm: "MOVD", typ: "UInt64", addrSinkArg0: true}, // load 64-bit double-word from arg0 + arg1*8, arg2 = mem.
+ {name: "FMOVSloadidx4", argLength: 3, reg: fp2load, asm: "FMOVS", typ: "Float32"}, // load 32-bit float from arg0 + arg1*4, arg2 = mem.
+ {name: "FMOVDloadidx8", argLength: 3, reg: fp2load, asm: "FMOVD", typ: "Float64"}, // load 64-bit float from arg0 + arg1*8, arg2 = mem.
{name: "MOVBstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 1 byte of arg1 to arg0 + auxInt + aux. arg2=mem.
{name: "MOVHstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 2 bytes of arg1 to arg0 + auxInt + aux. arg2=mem.
@@ -460,11 +460,11 @@
{name: "FMOVDstoreidx", argLength: 4, reg: fpstoreidx, asm: "FMOVD", typ: "Mem"}, // store 64-bit float of arg2 to arg0 + arg1, arg3=mem.
// shifted register indexed store
- {name: "MOVHstoreidx2", argLength: 4, reg: gpstore2, asm: "MOVH", typ: "Mem"}, // store 2 bytes of arg2 to arg0 + arg1*2, arg3 = mem.
- {name: "MOVWstoreidx4", argLength: 4, reg: gpstore2, asm: "MOVW", typ: "Mem"}, // store 4 bytes of arg2 to arg0 + arg1*4, arg3 = mem.
- {name: "MOVDstoreidx8", argLength: 4, reg: gpstore2, asm: "MOVD", typ: "Mem"}, // store 8 bytes of arg2 to arg0 + arg1*8, arg3 = mem.
- {name: "FMOVSstoreidx4", argLength: 4, reg: fpstoreidx, asm: "FMOVS", typ: "Mem"}, // store 32-bit float of arg2 to arg0 + arg1*4, arg3=mem.
- {name: "FMOVDstoreidx8", argLength: 4, reg: fpstoreidx, asm: "FMOVD", typ: "Mem"}, // store 64-bit float of arg2 to arg0 + arg1*8, arg3=mem.
+ {name: "MOVHstoreidx2", argLength: 4, reg: gpstore2, asm: "MOVH", typ: "Mem"}, // store 2 bytes of arg2 to arg0 + arg1*2, arg3 = mem.
+ {name: "MOVWstoreidx4", argLength: 4, reg: gpstore2, asm: "MOVW", typ: "Mem"}, // store 4 bytes of arg2 to arg0 + arg1*4, arg3 = mem.
+ {name: "MOVDstoreidx8", argLength: 4, reg: gpstore2, asm: "MOVD", typ: "Mem", addrSinkArg0: true}, // store 8 bytes of arg2 to arg0 + arg1*8, arg3 = mem.
+ {name: "FMOVSstoreidx4", argLength: 4, reg: fpstoreidx, asm: "FMOVS", typ: "Mem"}, // store 32-bit float of arg2 to arg0 + arg1*4, arg3=mem.
+ {name: "FMOVDstoreidx8", argLength: 4, reg: fpstoreidx, asm: "FMOVD", typ: "Mem"}, // store 64-bit float of arg2 to arg0 + arg1*8, arg3=mem.
{name: "FMOVDgpfp", argLength: 1, reg: gpfp, asm: "FMOVD", earlyOk: true}, // move int64 to float64 (no conversion)
{name: "FMOVDfpgp", argLength: 1, reg: fpgp, asm: "FMOVD", earlyOk: true}, // move float64 to int64 (no conversion)
@@ -584,6 +584,7 @@
inputs: []regMask{gp},
},
faultOnNilArg0: true,
+ addrSinkArg0: true,
},
// large zeroing
@@ -600,6 +601,7 @@
clobbersArg0: true,
},
faultOnNilArg0: true,
+ addrSinkArg0: true,
needIntTemp: true,
},
@@ -619,6 +621,8 @@
},
faultOnNilArg0: true,
faultOnNilArg1: true,
+ addrSinkArg0: true,
+ addrSinkArg1: true,
},
// large copying
@@ -639,6 +643,8 @@
},
faultOnNilArg0: true,
faultOnNilArg1: true,
+ addrSinkArg0: true,
+ addrSinkArg1: true,
},
// Scheduler ensures LoweredGetClosurePtr occurs only in entry block,
diff --git a/src/cmd/compile/internal/ssa/_gen/main.go b/src/cmd/compile/internal/ssa/_gen/main.go
index 1e8de5f..c2c1a04 100644
--- a/src/cmd/compile/internal/ssa/_gen/main.go
+++ b/src/cmd/compile/internal/ssa/_gen/main.go
@@ -73,6 +73,8 @@
unsafePoint bool // this op is an unsafe point, i.e. not safe for async preemption
fixedReg bool // this op will be assigned a fixed register
earlyOk bool // executing this op in an earlier block is ok
+ addrSinkArg0 bool // the address in arg0 does not propagate to the result
+ addrSinkArg1 bool // the address in arg1 does not propagate to the result
symEffect string // effect this op has on symbol in aux
scale uint8 // amd64/386 indexed load scale
}
@@ -397,6 +399,12 @@
if v.earlyOk {
fmt.Fprintln(w, "earlyOk: true,")
}
+ if v.addrSinkArg0 {
+ fmt.Fprintln(w, "addrSinkArg0: true,")
+ }
+ if v.addrSinkArg1 {
+ fmt.Fprintln(w, "addrSinkArg1: true,")
+ }
if v.unsafePoint {
fmt.Fprintln(w, "unsafePoint: true,")
}
diff --git a/src/cmd/compile/internal/ssa/op.go b/src/cmd/compile/internal/ssa/op.go
index 2d2676b..85fdb08 100644
--- a/src/cmd/compile/internal/ssa/op.go
+++ b/src/cmd/compile/internal/ssa/op.go
@@ -47,6 +47,8 @@
unsafePoint bool // this op is an unsafe point, i.e. not safe for async preemption
fixedReg bool // this op will be assigned a fixed register
earlyOk bool // executing this op in an earlier block is ok
+ addrSinkArg0 bool // the address in arg0 does not propagate to the result
+ addrSinkArg1 bool // the address in arg1 does not propagate to the result
symEffect SymEffect // effect this op has on symbol in aux
scale uint8 // amd64/386 indexed load scale
}
diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go
index f79a83c..fe72118 100644
--- a/src/cmd/compile/internal/ssa/opGen.go
+++ b/src/cmd/compile/internal/ssa/opGen.go
@@ -19564,6 +19564,7 @@
auxType: auxInt64,
argLen: 2,
faultOnNilArg0: true,
+ addrSinkArg0: true,
reg: regInfo{
inputs: []inputInfo{
{0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
@@ -19577,6 +19578,7 @@
clobberFlags: true,
needIntTemp: true,
faultOnNilArg0: true,
+ addrSinkArg0: true,
reg: regInfo{
inputs: []inputInfo{
{0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
@@ -19588,6 +19590,7 @@
name: "REPSTOSQ",
argLen: 4,
faultOnNilArg0: true,
+ addrSinkArg0: true,
reg: regInfo{
inputs: []inputInfo{
{0, regMask{v1: 128, v2: 0}}, // DI
@@ -19665,6 +19668,8 @@
argLen: 3,
faultOnNilArg0: true,
faultOnNilArg1: true,
+ addrSinkArg0: true,
+ addrSinkArg1: true,
reg: regInfo{
inputs: []inputInfo{
{0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
@@ -19681,6 +19686,8 @@
needIntTemp: true,
faultOnNilArg0: true,
faultOnNilArg1: true,
+ addrSinkArg0: true,
+ addrSinkArg1: true,
reg: regInfo{
inputs: []inputInfo{
{0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
@@ -19696,6 +19703,8 @@
argLen: 4,
faultOnNilArg0: true,
faultOnNilArg1: true,
+ addrSinkArg0: true,
+ addrSinkArg1: true,
reg: regInfo{
inputs: []inputInfo{
{0, regMask{v1: 128, v2: 0}}, // DI
@@ -77690,9 +77699,10 @@
},
},
{
- name: "MOVDloadidx8",
- argLen: 3,
- asm: arm64.AMOVD,
+ name: "MOVDloadidx8",
+ argLen: 3,
+ addrSinkArg0: true,
+ asm: arm64.AMOVD,
reg: regInfo{
inputs: []inputInfo{
{1, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30
@@ -78001,9 +78011,10 @@
},
},
{
- name: "MOVDstoreidx8",
- argLen: 4,
- asm: arm64.AMOVD,
+ name: "MOVDstoreidx8",
+ argLen: 4,
+ addrSinkArg0: true,
+ asm: arm64.AMOVD,
reg: regInfo{
inputs: []inputInfo{
{1, regMask{v1: 939524095, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 ZERO
@@ -79076,6 +79087,7 @@
auxType: auxInt64,
argLen: 2,
faultOnNilArg0: true,
+ addrSinkArg0: true,
reg: regInfo{
inputs: []inputInfo{
{0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30
@@ -79088,6 +79100,7 @@
argLen: 2,
needIntTemp: true,
faultOnNilArg0: true,
+ addrSinkArg0: true,
reg: regInfo{
inputs: []inputInfo{
{0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30
@@ -79101,6 +79114,8 @@
argLen: 3,
faultOnNilArg0: true,
faultOnNilArg1: true,
+ addrSinkArg0: true,
+ addrSinkArg1: true,
reg: regInfo{
inputs: []inputInfo{
{0, regMask{v1: 318767103, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R26 R30
@@ -79115,6 +79130,8 @@
argLen: 3,
faultOnNilArg0: true,
faultOnNilArg1: true,
+ addrSinkArg0: true,
+ addrSinkArg1: true,
reg: regInfo{
inputs: []inputInfo{
{0, regMask{v1: 310378495, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R26 R30
diff --git a/src/cmd/compile/internal/ssa/value.go b/src/cmd/compile/internal/ssa/value.go
index 95710d9..279099d 100644
--- a/src/cmd/compile/internal/ssa/value.go
+++ b/src/cmd/compile/internal/ssa/value.go
@@ -665,3 +665,15 @@
return true
}
}
+
+// AddrSinkArg reports whether the idx'th argument is known
+// to not propagate to the output value.
+func (v *Value) AddrSinkArg(idx int) bool {
+ if idx == 0 {
+ return opcodeTable[v.Op].addrSinkArg0
+ }
+ if idx == 1 {
+ return opcodeTable[v.Op].addrSinkArg1
+ }
+ return false
+}
diff --git a/test/fixedbugs/issue80127.go b/test/fixedbugs/issue80127.go
new file mode 100644
index 0000000..b76c3d4
--- /dev/null
+++ b/test/fixedbugs/issue80127.go
@@ -0,0 +1,30 @@
+// run
+
+// Copyright 2026 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.
+
+package main
+
+type T [2][2]int64
+
+//go:noinline
+func f(i, j int) int64 {
+ if i < 0 || i > 1 || j < 0 || j > 1 {
+ return 3
+ }
+ var x T
+ x[i][i] = 33
+
+ var y T
+ y[i][i] = 44
+ r := y[j][j]
+
+ return r + x[i][i]
+}
+
+func main() {
+ if x := f(1, 1); x != 77 {
+ println("bad", x)
+ }
+}