aboutsummaryrefslogtreecommitdiff
path: root/src/cmd
diff options
context:
space:
mode:
authorCherry Mui <cherryyz@google.com>2026-02-25 07:26:55 -0800
committerGopher Robot <gobot@golang.org>2026-02-25 07:45:39 -0800
commit5b40e48a2970734e816d2a9f2eac163a3315f3c2 (patch)
tree779bbab9cc5bb5807c9e7b5887321018d365bd17 /src/cmd
parentabf84a51fcec1156712be90f8aa2ae58b461aa65 (diff)
downloadgo-5b40e48a2970734e816d2a9f2eac163a3315f3c2.tar.xz
Revert "cmd/compile: add loclist for removed DCL nodes"
This reverts CL 696575. Reason for revert: break many builders. E.g. https://ci.chromium.org/b/8688888321314872289 Change-Id: I453b50fd0b731a6b3d1870f43fd7ed5937965bc1 Reviewed-on: https://go-review.googlesource.com/c/go/+/749020 Auto-Submit: Cherry Mui <cherryyz@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: David Chase <drchase@google.com>
Diffstat (limited to 'src/cmd')
-rw-r--r--src/cmd/compile/internal/dwarfgen/dwarf.go79
-rw-r--r--src/cmd/compile/internal/ssa/config.go4
-rw-r--r--src/cmd/compile/internal/ssa/debug.go13
-rw-r--r--src/cmd/compile/internal/ssagen/ssa.go61
-rw-r--r--src/cmd/link/dwarf_test.go59
5 files changed, 15 insertions, 201 deletions
diff --git a/src/cmd/compile/internal/dwarfgen/dwarf.go b/src/cmd/compile/internal/dwarfgen/dwarf.go
index 045772378f..9d975e0bc1 100644
--- a/src/cmd/compile/internal/dwarfgen/dwarf.go
+++ b/src/cmd/compile/internal/dwarfgen/dwarf.go
@@ -236,8 +236,6 @@ func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *ir.Func, apDecls []*ir
// reliably report its contents."
// For non-SSA-able arguments, however, the correct information
// is known -- they have a single home on the stack.
- var outidx int
- debug, _ := fn.DebugInfo.(*ssa.FuncDebug)
for _, n := range dcl {
if selected.Has(n) {
continue
@@ -246,11 +244,6 @@ func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *ir.Func, apDecls []*ir
if c == '.' || n.Type().IsUntyped() {
continue
}
-
- // Occasionally the dcl list will contain duplicates. Add here
- // so the `selected.Has` check above filters them out.
- selected.Add(n)
-
if n.Class == ir.PPARAM && !ssa.CanSSA(n.Type()) {
// SSA-able args get location lists, and may move in and
// out of registers, so those are handled elsewhere.
@@ -263,7 +256,6 @@ func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *ir.Func, apDecls []*ir
decls = append(decls, n)
continue
}
-
typename := dwarf.InfoPrefix + types.TypeSymName(n.Type())
decls = append(decls, n)
tag := dwarf.DW_TAG_variable
@@ -296,30 +288,11 @@ func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *ir.Func, apDecls []*ir
DictIndex: n.DictIndex,
ClosureOffset: closureOffset(n, closureVars),
}
- if debug != nil && isReturnValue && n.IsOutputParamInRegisters() {
- // Create register based location list
- // This assumes that the register return params in the dcl list is sorted correctly and
- // params appear in order they are defined in the function signature.
-
- startIDs := debug.RegOutputParamStartIDs
- if !strings.HasPrefix(n.Sym().Name, "~") {
- // If this is not an unnamed return parameter do not pass ranges through and assume
- // this value is live throughout the entirety of the function.
- // TODO(derekparker): there is still work to be done here to better track the movement
- // of these params through the body of the function, e.g. it may move registers at certain address
- // ranges or spill to the stack.
- startIDs = nil
- }
- list := createRegisterReturnParamLocList(debug.RegOutputParamRegList[outidx], debug.EntryID, startIDs)
- outidx++
- dvar.PutLocationList = func(listSym, startPC dwarf.Sym) {
- debug.PutLocationList(list, base.Ctxt, listSym.(*obj.LSym), startPC.(*obj.LSym))
- }
- }
- if debug != nil && n.Esc() == ir.EscHeap {
+ if n.Esc() == ir.EscHeap {
if n.Heapaddr == nil {
base.Fatalf("invalid heap allocated var without Heapaddr")
}
+ debug := fn.DebugInfo.(*ssa.FuncDebug)
list := createHeapDerefLocationList(n, debug.EntryID)
dvar.PutLocationList = func(listSym, startPC dwarf.Sym) {
debug.PutLocationList(list, base.Ctxt, listSym.(*obj.LSym), startPC.(*obj.LSym))
@@ -336,54 +309,6 @@ func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *ir.Func, apDecls []*ir
return decls, vars
}
-// createRegisterReturnParamLocList creates a location list that specifies
-// a value is in a register for the given block ranges.
-// startIDs contains a list of SSA IDs where the value is live, and it is assumed by this function
-// that the value is live until the nearest RET instruction, or the end of the function in the case
-// of the last / only start location.
-func createRegisterReturnParamLocList(regs []int8, entryID ssa.ID, startIDs []ssa.ID) []byte {
- var list []byte
- ctxt := base.Ctxt
-
- if len(startIDs) == 0 {
- // No ranges specified, fall back to full function
- startIDs = []ssa.ID{ssa.BlockStart.ID}
- }
-
- stardIDLenIdx := len(startIDs) - 1
- // Create a location list entry for each range
- for i, start := range startIDs {
- var sizeIdx int
-
- end := ssa.FuncLocalEnd.ID
- if i == stardIDLenIdx {
- // If this is the last entry always extend to end of function.
- end = ssa.FuncEnd.ID
- }
- list, sizeIdx = ssa.SetupLocList(base.Ctxt, entryID, list, start, end)
-
- // The actual location expression
- for _, reg := range regs {
- if reg < 32 {
- list = append(list, dwarf.DW_OP_reg0+byte(reg))
- } else {
- list = append(list, dwarf.DW_OP_regx)
- list = dwarf.AppendUleb128(list, uint64(reg))
- }
- if len(regs) > 1 {
- list = append(list, dwarf.DW_OP_piece)
- list = dwarf.AppendUleb128(list, uint64(ctxt.Arch.RegSize))
- }
- }
-
- // Update the size for this entry
- locSize := len(list) - sizeIdx - 2
- ctxt.Arch.ByteOrder.PutUint16(list[sizeIdx:], uint16(locSize))
- }
-
- return list
-}
-
// sortDeclsAndVars sorts the decl and dwarf var lists according to
// parameter declaration order, so as to insure that when a subprogram
// DIE is emitted, its parameter children appear in declaration order.
diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go
index 6456be5bff..e796071fe8 100644
--- a/src/cmd/compile/internal/ssa/config.go
+++ b/src/cmd/compile/internal/ssa/config.go
@@ -397,10 +397,6 @@ func NewConfig(arch string, types Types, ctxt *obj.Link, optimize, softfloat boo
func (c *Config) Ctxt() *obj.Link { return c.ctxt }
-func (c *Config) Reg(i int8) int16 { return c.registers[i].objNum }
-func (c *Config) IntParamReg(i abi.RegIndex) int8 { return c.intParamRegs[i] }
-func (c *Config) FloatParamReg(i abi.RegIndex) int8 { return c.floatParamRegs[i] }
-
func (c *Config) haveByteSwap(size int64) bool {
switch size {
case 8:
diff --git a/src/cmd/compile/internal/ssa/debug.go b/src/cmd/compile/internal/ssa/debug.go
index 0bbc6b79d1..687abc42cc 100644
--- a/src/cmd/compile/internal/ssa/debug.go
+++ b/src/cmd/compile/internal/ssa/debug.go
@@ -38,12 +38,7 @@ type FuncDebug struct {
LocationLists [][]byte
// Register-resident output parameters for the function. This is filled in at
// SSA generation time.
- RegOutputParams []*ir.Name
- RegOutputParamRegList [][]int8
- // RegOutputParamStartIDs contains a list of SSA IDs which represent a location where
- // the register based return param is known to be live. It is assumed that the value is
- // live from the ID to the closest function return location.
- RegOutputParamStartIDs []ID
+ RegOutputParams []*ir.Name
// Variable declarations that were removed during optimization
OptDcl []*ir.Name
// The ssa.Func.EntryID value, used to build location lists for
@@ -194,12 +189,6 @@ var FuncEnd = &Value{
Aux: StringToAux("FuncEnd"),
}
-var FuncLocalEnd = &Value{
- ID: -40000,
- Op: OpInvalid,
- Aux: StringToAux("FuncLocalEnd"),
-}
-
// RegisterSet is a bitmap of registers, indexed by Register.num.
type RegisterSet uint64
diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go
index fc321ff399..05224601e3 100644
--- a/src/cmd/compile/internal/ssagen/ssa.go
+++ b/src/cmd/compile/internal/ssagen/ssa.go
@@ -461,15 +461,6 @@ func buildssa(fn *ir.Func, worker int, isPgoHot bool) *ssa.Func {
var params *abi.ABIParamResultInfo
params = s.f.ABISelf.ABIAnalyze(fn.Type(), true)
- abiRegIndexToRegister := func(reg abi.RegIndex) int8 {
- i := s.f.ABISelf.FloatIndexFor(reg)
- if i >= 0 { // float PR
- return s.f.Config.FloatParamReg(abi.RegIndex(i))
- } else {
- return s.f.Config.IntParamReg(reg)
- }
- }
-
// The backend's stackframe pass prunes away entries from the fn's
// Dcl list, including PARAMOUT nodes that correspond to output
// params passed in registers. Walk the Dcl list and capture these
@@ -479,16 +470,6 @@ func buildssa(fn *ir.Func, worker int, isPgoHot bool) *ssa.Func {
for _, n := range fn.Dcl {
if n.Class == ir.PPARAMOUT && n.IsOutputParamInRegisters() {
debugInfo.RegOutputParams = append(debugInfo.RegOutputParams, n)
- op := params.OutParam(len(debugInfo.RegOutputParamRegList))
- debugInfo.RegOutputParamRegList = append(debugInfo.RegOutputParamRegList, make([]int8, len(op.Registers)))
- for i, reg := range op.Registers {
- idx := len(debugInfo.RegOutputParamRegList) - 1
- // TODO(deparker) This is a rather large amount of conversions to get from
- // an abi.RegIndex to a Dwarf register number. Can this be simplified?
- abiReg := s.f.Config.Reg(abiRegIndexToRegister(reg))
- dwarfReg := base.Ctxt.Arch.DWARFRegisters[abiReg]
- debugInfo.RegOutputParamRegList[idx][i] = int8(dwarfReg)
- }
}
}
fn.DebugInfo = &debugInfo
@@ -7301,7 +7282,6 @@ func genssa(f *ssa.Func, pp *objw.Progs) {
ssa.BuildFuncDebugNoOptimized(base.Ctxt, f, base.Debug.LocationLists > 1, StackOffset, debugInfo)
} else {
ssa.BuildFuncDebug(base.Ctxt, f, base.Debug.LocationLists, StackOffset, debugInfo)
- populateReturnValueBlockRanges(f, debugInfo)
}
bstart := s.bstart
idToIdx := make([]int, f.NumBlocks())
@@ -7325,20 +7305,6 @@ func genssa(f *ssa.Func, pp *objw.Progs) {
return valueToProgAfter[blk.Values[nv-1].ID].Pc
case ssa.FuncEnd.ID:
return e.curfn.LSym.Size
- case ssa.FuncLocalEnd.ID:
- // Find the closest RET instruction to this block.
- // This ensures that location lists are correct for functions
- // with multiple returns.
- blk := f.Blocks[idToIdx[b]]
- nv := len(blk.Values)
- pa := valueToProgAfter[blk.Values[nv-1].ID]
- for {
- if pa.Link == nil || pa.As == obj.ARET {
- break
- }
- pa = pa.Link
- }
- return pa.Pc + 1
default:
return valueToProgAfter[v].Pc
}
@@ -8118,31 +8084,4 @@ func isStructNotSIMD(t *types.Type) bool {
return t.IsStruct() && !t.IsSIMD()
}
-// populateReturnValueBlockRanges analyzes the SSA to find when return values
-// are assigned and creates precise block ranges for their liveness.
-func populateReturnValueBlockRanges(f *ssa.Func, debugInfo *ssa.FuncDebug) {
- if debugInfo == nil || len(debugInfo.RegOutputParams) == 0 {
- return
- }
-
- // Find assignment points for each return parameter.
- for _, b := range f.Blocks {
- // Check if this is a return block
- if b.Kind != ssa.BlockRet && b.Kind != ssa.BlockRetJmp {
- continue
- }
- val := b.Values[0]
- for i := range b.Values {
- // Not skipping these causes a panic when using the value to lookup within `valueToProgAfter`.
- op := b.Values[i].Op
- if op == ssa.OpArgIntReg || op == ssa.OpArgFloatReg {
- continue
- }
- val = b.Values[i]
- break
- }
- debugInfo.RegOutputParamStartIDs = append(debugInfo.RegOutputParamStartIDs, val.ID)
- }
-}
-
var BoundsCheckFunc [ssa.BoundsKindCount]*obj.LSym
diff --git a/src/cmd/link/dwarf_test.go b/src/cmd/link/dwarf_test.go
index 3b09379800..9d41c55b26 100644
--- a/src/cmd/link/dwarf_test.go
+++ b/src/cmd/link/dwarf_test.go
@@ -16,7 +16,6 @@ import (
"os/exec"
"path"
"path/filepath"
- "regexp"
"runtime"
"strings"
"testing"
@@ -301,13 +300,16 @@ func TestDWARFiOS(t *testing.T) {
// This test ensures that variables promoted to the heap, specifically
// function return parameters, have correct location lists generated.
+//
+// TODO(deparker): This test is intentionally limited to GOOS=="linux"
+// and scoped to net.sendFile, which was the function reported originally in
+// issue #65405. There is relevant discussion in https://go-review.googlesource.com/c/go/+/684377
+// pertaining to these limitations. There are other missing location lists which must be fixed
+// particularly in functions where `linkname` is involved.
func TestDWARFLocationList(t *testing.T) {
- const dwarfGoLanguage = 22
-
- if runtime.GOARCH == "386" {
- t.Skipf("skipping on %s/386: not all unnamed return parameters have lists yet", runtime.GOOS)
+ if runtime.GOOS != "linux" {
+ t.Skip("skipping test on non-linux OS")
}
-
testenv.MustHaveCGO(t)
testenv.MustHaveGoBuild(t)
@@ -342,11 +344,6 @@ func TestDWARFLocationList(t *testing.T) {
// Find the net.sendFile function and check its return parameter location list
reader := d.Reader()
- pattern := `\w+(\.\w+)*\.func\d+`
- re := regexp.MustCompile(pattern)
-
- var cu *dwarf.Entry
- var lr *dwarf.LineReader
for {
entry, err := reader.Next()
if err != nil {
@@ -356,37 +353,14 @@ func TestDWARFLocationList(t *testing.T) {
break
}
- if entry.Tag == dwarf.TagCompileUnit {
- if lang, _ := entry.Val(dwarf.AttrLanguage).(int64); lang != dwarfGoLanguage {
- reader.SkipChildren()
- continue // Skip non-Go compile units.
- }
- cu = entry
- lr, err = d.LineReader(cu)
- if err != nil {
- t.Fatal(err)
- }
- }
-
- if cu != nil && entry.Tag == dwarf.TagSubprogram {
+ // Look for the net.sendFile subprogram
+ if entry.Tag == dwarf.TagSubprogram {
fnName, ok := entry.Val(dwarf.AttrName).(string)
- if !ok || re.MatchString(fnName) {
- continue // Skip if no name or an anonymous function. TODO(deparker): fix loclists for anonymous functions (possible unused param).
- }
-
- if strings.HasPrefix(fnName, "runtime.") {
- // Ignore runtime for now, there are a lot of runtime functions which use
- // certain pragmas that seemingly cause the location lists to be empty such as
- // cgo_unsafe_args and nosplit.
- // TODO(deparker): fix loclists for runtime functions.
+ if !ok || fnName != "net.sendFile" {
+ reader.SkipChildren()
continue
}
- fi, ok := entry.Val(dwarf.AttrDeclFile).(int64)
- if !ok || lr.Files()[fi].Name == "<autogenerated>" {
- continue // Function may be implemented in assembly, skip it.
- }
-
for {
paramEntry, err := reader.Next()
if err != nil {
@@ -399,15 +373,6 @@ func TestDWARFLocationList(t *testing.T) {
if paramEntry.Tag == dwarf.TagFormalParameter {
paramName, _ := paramEntry.Val(dwarf.AttrName).(string)
- if paramName == ".dict" {
- continue
- }
-
- // Skip anonymous / blank (unused) params.
- if strings.HasPrefix(paramName, "~p") {
- continue
- }
-
// Check if this parameter has a location attribute
if loc := paramEntry.Val(dwarf.AttrLocation); loc != nil {
switch locData := loc.(type) {