diff --git a/src/cmd/compile/internal/dwarfgen/dwarf.go b/src/cmd/compile/internal/dwarfgen/dwarf.go index 422c7e66c47..5d7dc320aa8 100644 --- a/src/cmd/compile/internal/dwarfgen/dwarf.go +++ b/src/cmd/compile/internal/dwarfgen/dwarf.go @@ -222,9 +222,64 @@ func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *ir.Func, apDecls []*ir fnsym.Func().RecordAutoType(reflectdata.TypeLinksym(n.Type())) } + // Sort decls and vars. + sortDeclsAndVars(fn, decls, vars) + return decls, vars } +// 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. +// Prior to the advent of the register ABI, sorting by frame offset +// would achieve this; with the register we now need to go back to the +// original function signature. +func sortDeclsAndVars(fn *ir.Func, decls []*ir.Name, vars []*dwarf.Var) { + paramOrder := make(map[*ir.Name]int) + idx := 1 + for _, selfn := range types.RecvsParamsResults { + fsl := selfn(fn.Type()).FieldSlice() + for _, f := range fsl { + if n, ok := f.Nname.(*ir.Name); ok { + paramOrder[n] = idx + idx++ + } + } + } + sort.Stable(varsAndDecls{decls, vars, paramOrder}) +} + +type varsAndDecls struct { + decls []*ir.Name + vars []*dwarf.Var + paramOrder map[*ir.Name]int +} + +func (v varsAndDecls) Len() int { + return len(v.decls) +} + +func (v varsAndDecls) Less(i, j int) bool { + nameLT := func(ni, nj *ir.Name) bool { + oi, foundi := v.paramOrder[ni] + oj, foundj := v.paramOrder[nj] + if foundi { + if foundj { + return oi < oj + } else { + return true + } + } + return false + } + return nameLT(v.decls[i], v.decls[j]) +} + +func (v varsAndDecls) Swap(i, j int) { + v.vars[i], v.vars[j] = v.vars[j], v.vars[i] + v.decls[i], v.decls[j] = v.decls[j], v.decls[i] +} + // Given a function that was inlined at some point during the // compilation, return a sorted list of nodes corresponding to the // autos/locals in that function prior to inlining. If this is a diff --git a/src/cmd/link/internal/ld/dwarf_test.go b/src/cmd/link/internal/ld/dwarf_test.go index 5cc4800e2a3..2f59c2fe0aa 100644 --- a/src/cmd/link/internal/ld/dwarf_test.go +++ b/src/cmd/link/internal/ld/dwarf_test.go @@ -1660,16 +1660,16 @@ func TestOutputParamAbbrevAndAttr(t *testing.T) { package main //go:noinline -func ABC(p1, p2, p3 int, f1, f2, f3 float32, b1 [1024]int) (r1 int, r2 int, r3 [1024]int, r4 byte) { - b1[0] = 6 - r1, r2, r3, r4 = p3, p2, b1, 'a' +func ABC(c1, c2, c3 int, d1, d2, d3, d4 string, f1, f2, f3 float32, g1 [1024]int) (r1 int, r2 int, r3 [1024]int, r4 byte, r5 string, r6 float32) { + g1[0] = 6 + r1, r2, r3, r4, r5, r6 = c3, c2+c1, g1, 'a', d1+d2+d3+d4, f1+f2+f3 return } func main() { a := [1024]int{} - v1, v2, v3, v4 := ABC(1, 2, 3, 1.0, 2.0, 1.0, a) - println(v1, v2, v3[0], v4) + v1, v2, v3, v4, v5, v6 := ABC(1, 2, 3, "a", "b", "c", "d", 1.0, 2.0, 1.0, a) + println(v1, v2, v3[0], v4, v5, v6) } ` dir := t.TempDir() @@ -1708,18 +1708,20 @@ func main() { // OK to have it missing for input parameters, but for the moment // we verify that the attr is present but set to false. - // Values in this map: + // Values in this map are of the form : + // where order is the order within the child DIE list of the param, + // and is an integer: // - // 0: // -1: varparm attr not found // 1: varparm found with value false // 2: varparm found with value true // - foundParams := make(map[string]int) + foundParams := make(map[string]string) // Walk ABCs's children looking for params. abcIdx := ex.idxFromOffset(abcdie.Offset) childDies := ex.Children(abcIdx) + idx := 0 for _, child := range childDies { if child.Tag == dwarf.TagFormalParameter { st := -1 @@ -1731,7 +1733,8 @@ func main() { } } if name, ok := child.Val(dwarf.AttrName).(string); ok { - foundParams[name] = st + foundParams[name] = fmt.Sprintf("%d:%d", idx, st) + idx++ } } } @@ -1739,13 +1742,14 @@ func main() { // Digest the result. found := make([]string, 0, len(foundParams)) for k, v := range foundParams { - found = append(found, fmt.Sprintf("%s:%d", k, v)) + found = append(found, fmt.Sprintf("%s:%s", k, v)) } sort.Strings(found) - // Make sure we see all of the expected params, that they have - // the varparam attr, and the varparm is set for the returns. - expected := "[b1:1 f1:1 f2:1 f3:1 p1:1 p2:1 p3:1 r1:2 r2:2 r3:2 r4:2]" + // Make sure we see all of the expected params in the proper + // order, that they have the varparam attr, and the varparm is set + // for the returns. + expected := "[c1:0:1 c2:1:1 c3:2:1 d1:3:1 d2:4:1 d3:5:1 d4:6:1 f1:7:1 f2:8:1 f3:9:1 g1:10:1 r1:11:2 r2:12:2 r3:13:2 r4:14:2 r5:15:2 r6:16:2]" if fmt.Sprintf("%+v", found) != expected { t.Errorf("param check failed, wanted %s got %s\n", expected, found)