aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal
diff options
context:
space:
mode:
authorDavid Chase <drchase@google.com>2021-03-07 14:00:10 -0500
committerDavid Chase <drchase@google.com>2021-03-09 18:45:05 +0000
commit382851c1fd135a99efbe128a3be0ce466d42506f (patch)
tree63e138e97306bfdaffc642677aaffc595d87602f /src/cmd/compile/internal
parent9f5298ca6e7fc9c46c0a82bd7be39450ec48dcb5 (diff)
downloadgo-382851c1fd135a99efbe128a3be0ce466d42506f.tar.gz
go-382851c1fd135a99efbe128a3be0ce466d42506f.zip
cmd/compile: fix failure to communicate between ABIinfo producer&consumer
ABI info producer and consumer had different ideas for register order for parameters. Includes a test, includes improvements to debugging output. Updates #44816. Change-Id: I4812976f7a6c08d6fc02aac1ec0544b1f141cca6 Reviewed-on: https://go-review.googlesource.com/c/go/+/299570 Trust: David Chase <drchase@google.com> Reviewed-by: Than McIntosh <thanm@google.com>
Diffstat (limited to 'src/cmd/compile/internal')
-rw-r--r--src/cmd/compile/internal/abi/abiutils.go77
-rw-r--r--src/cmd/compile/internal/ssa/expand_calls.go83
-rw-r--r--src/cmd/compile/internal/ssa/value.go4
-rw-r--r--src/cmd/compile/internal/test/abiutils_test.go6
4 files changed, 104 insertions, 66 deletions
diff --git a/src/cmd/compile/internal/abi/abiutils.go b/src/cmd/compile/internal/abi/abiutils.go
index 7d5de1d528..ecde34313a 100644
--- a/src/cmd/compile/internal/abi/abiutils.go
+++ b/src/cmd/compile/internal/abi/abiutils.go
@@ -477,9 +477,9 @@ func (c *RegAmounts) regString(r RegIndex) string {
return fmt.Sprintf("<?>%d", r)
}
-// toString method renders an ABIParamAssignment in human-readable
+// ToString method renders an ABIParamAssignment in human-readable
// form, suitable for debugging or unit testing.
-func (ri *ABIParamAssignment) toString(config *ABIConfig) string {
+func (ri *ABIParamAssignment) ToString(config *ABIConfig, extra bool) string {
regs := "R{"
offname := "spilloffset" // offset is for spill for register(s)
if len(ri.Registers) == 0 {
@@ -487,19 +487,25 @@ func (ri *ABIParamAssignment) toString(config *ABIConfig) string {
}
for _, r := range ri.Registers {
regs += " " + config.regAmounts.regString(r)
+ if extra {
+ regs += fmt.Sprintf("(%d)", r)
+ }
+ }
+ if extra {
+ regs += fmt.Sprintf(" | #I=%d, #F=%d", config.regAmounts.intRegs, config.regAmounts.floatRegs)
}
return fmt.Sprintf("%s } %s: %d typ: %v", regs, offname, ri.offset, ri.Type)
}
-// toString method renders an ABIParamResultInfo in human-readable
+// String method renders an ABIParamResultInfo in human-readable
// form, suitable for debugging or unit testing.
func (ri *ABIParamResultInfo) String() string {
res := ""
for k, p := range ri.inparams {
- res += fmt.Sprintf("IN %d: %s\n", k, p.toString(ri.config))
+ res += fmt.Sprintf("IN %d: %s\n", k, p.ToString(ri.config, false))
}
for k, r := range ri.outparams {
- res += fmt.Sprintf("OUT %d: %s\n", k, r.toString(ri.config))
+ res += fmt.Sprintf("OUT %d: %s\n", k, r.ToString(ri.config, false))
}
res += fmt.Sprintf("offsetToSpillArea: %d spillAreaSize: %d",
ri.offsetToSpillArea, ri.spillAreaSize)
@@ -537,25 +543,54 @@ func (state *assignState) stackSlot(t *types.Type) int64 {
return rv
}
-// allocateRegs returns a set of register indices for a parameter or result
+// allocateRegs returns an ordered list of register indices for a parameter or result
// that we've just determined to be register-assignable. The number of registers
// needed is assumed to be stored in state.pUsed.
-func (state *assignState) allocateRegs() []RegIndex {
- regs := []RegIndex{}
-
- // integer
- for r := state.rUsed.intRegs; r < state.rUsed.intRegs+state.pUsed.intRegs; r++ {
- regs = append(regs, RegIndex(r))
+func (state *assignState) allocateRegs(regs []RegIndex, t *types.Type) []RegIndex {
+ if t.Width == 0 {
+ return regs
}
- state.rUsed.intRegs += state.pUsed.intRegs
-
- // floating
- for r := state.rUsed.floatRegs; r < state.rUsed.floatRegs+state.pUsed.floatRegs; r++ {
- regs = append(regs, RegIndex(r+state.rTotal.intRegs))
+ ri := state.rUsed.intRegs
+ rf := state.rUsed.floatRegs
+ if t.IsScalar() || t.IsPtrShaped() {
+ if t.IsComplex() {
+ regs = append(regs, RegIndex(rf+state.rTotal.intRegs), RegIndex(rf+1+state.rTotal.intRegs))
+ rf += 2
+ } else if t.IsFloat() {
+ regs = append(regs, RegIndex(rf+state.rTotal.intRegs))
+ rf += 1
+ } else {
+ n := (int(t.Size()) + types.RegSize - 1) / types.RegSize
+ for i := 0; i < n; i++ { // looking ahead to really big integers
+ regs = append(regs, RegIndex(ri))
+ ri += 1
+ }
+ }
+ state.rUsed.intRegs = ri
+ state.rUsed.floatRegs = rf
+ return regs
+ } else {
+ typ := t.Kind()
+ switch typ {
+ case types.TARRAY:
+ for i := int64(0); i < t.NumElem(); i++ {
+ regs = state.allocateRegs(regs, t.Elem())
+ }
+ return regs
+ case types.TSTRUCT:
+ for _, f := range t.FieldSlice() {
+ regs = state.allocateRegs(regs, f.Type)
+ }
+ return regs
+ case types.TSLICE:
+ return state.allocateRegs(regs, synthSlice)
+ case types.TSTRING:
+ return state.allocateRegs(regs, synthString)
+ case types.TINTER:
+ return state.allocateRegs(regs, synthIface)
+ }
}
- state.rUsed.floatRegs += state.pUsed.floatRegs
-
- return regs
+ panic(fmt.Errorf("Was not expecting type %s", t))
}
// regAllocate creates a register ABIParamAssignment object for a param
@@ -571,7 +606,7 @@ func (state *assignState) regAllocate(t *types.Type, name types.Object, isReturn
return ABIParamAssignment{
Type: t,
Name: name,
- Registers: state.allocateRegs(),
+ Registers: state.allocateRegs([]RegIndex{}, t),
offset: int32(spillLoc),
}
}
diff --git a/src/cmd/compile/internal/ssa/expand_calls.go b/src/cmd/compile/internal/ssa/expand_calls.go
index d7d7d3bc45..6e2004224f 100644
--- a/src/cmd/compile/internal/ssa/expand_calls.go
+++ b/src/cmd/compile/internal/ssa/expand_calls.go
@@ -303,7 +303,7 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64,
if x.debug {
x.indent(3)
defer x.indent(-3)
- x.Printf("rewriteSelect(%s, %s, %d)\n", leaf.LongString(), selector.LongString(), offset)
+ x.Printf("rewriteSelect(%s; %s; memOff=%d; regOff=%d)\n", leaf.LongString(), selector.LongString(), offset, regOffset)
}
var locs []LocalSlot
leafType := leaf.Type
@@ -581,7 +581,13 @@ func (x *expandState) decomposeArg(pos src.XPos, b *Block, source, mem *Value, t
rts, offs := pa.RegisterTypesAndOffsets()
last := loadRegOffset + x.regWidth(t)
if offs[loadRegOffset] != 0 {
- panic(fmt.Errorf("offset %d of requested register %d should be zero", offs[loadRegOffset], loadRegOffset))
+ // Document the problem before panicking.
+ for i := 0; i < len(rts); i++ {
+ rt := rts[i]
+ off := offs[i]
+ fmt.Printf("rt=%s, off=%d, rt.Width=%d, rt.Align=%d\n", rt.String(), off, rt.Width, rt.Align)
+ }
+ panic(fmt.Errorf("offset %d of requested register %d should be zero, source=%s", offs[loadRegOffset], loadRegOffset, source.LongString()))
}
for i := loadRegOffset; i < last; i++ {
rt := rts[i]
@@ -704,7 +710,7 @@ func storeOneArg(x *expandState, pos src.XPos, b *Block, source, mem *Value, t *
if x.debug {
x.indent(3)
defer x.indent(-3)
- fmt.Printf("storeOneArg(%s; %s; %s; aO=%d; sO=%d; lrO=%d; %s)\n", source.LongString(), mem.String(), t.String(), argOffset, storeOffset, loadRegOffset, storeRc.String())
+ x.Printf("storeOneArg(%s; %s; %s; aO=%d; sO=%d; lrO=%d; %s)\n", source.LongString(), mem.String(), t.String(), argOffset, storeOffset, loadRegOffset, storeRc.String())
}
w := x.commonArgs[selKey{source, argOffset, t.Width, t}]
@@ -1388,14 +1394,8 @@ func (x *expandState) rewriteArgToMemOrRegs(v *Value) *Value {
}
case 1:
r := pa.Registers[0]
- i := x.f.ABISelf.FloatIndexFor(r)
- // TODO seems like this has implications for debugging. How does this affect the location?
- if i >= 0 { // float PR
- v.Op = OpArgFloatReg
- } else {
- v.Op = OpArgIntReg
- i = int64(r)
- }
+ var i int64
+ v.Op, i = ArgOpAndRegisterFor(r, x.f.ABISelf)
v.Aux = &AuxNameOffset{v.Aux.(*ir.Name), 0}
v.AuxInt = i
@@ -1409,6 +1409,11 @@ func (x *expandState) rewriteArgToMemOrRegs(v *Value) *Value {
// or rewrites it into a copy of the appropriate OpArgXXX. The actual OpArgXXX is determined by combining baseArg (an OpArg)
// with offset, regOffset, and t to determine which portion of it to reference (either all or a part, in memory or in registers).
func (x *expandState) newArgToMemOrRegs(baseArg, toReplace *Value, offset int64, regOffset Abi1RO, t *types.Type, pos src.XPos) *Value {
+ if x.debug {
+ x.indent(3)
+ defer x.indent(-3)
+ x.Printf("newArgToMemOrRegs(base=%s; toReplace=%s; t=%s; memOff=%d; regOff=%d)\n", baseArg.String(), toReplace.LongString(), t, offset, regOffset)
+ }
key := selKey{baseArg, offset, t.Width, t}
w := x.commonArgs[key]
if w != nil {
@@ -1432,28 +1437,27 @@ func (x *expandState) newArgToMemOrRegs(baseArg, toReplace *Value, offset int64,
toReplace.Aux = aux
toReplace.AuxInt = auxInt
toReplace.Type = t
- x.commonArgs[key] = toReplace
- return toReplace
+ w = toReplace
} else {
- w := baseArg.Block.NewValue0IA(pos, OpArg, t, auxInt, aux)
- x.commonArgs[key] = w
- if x.debug {
- x.Printf("---new %s\n", w.LongString())
- }
- if toReplace != nil {
- toReplace.copyOf(w)
- }
- return w
+ w = baseArg.Block.NewValue0IA(pos, OpArg, t, auxInt, aux)
+ }
+ x.commonArgs[key] = w
+ if toReplace != nil {
+ toReplace.copyOf(w)
}
+ if x.debug {
+ x.Printf("-->%s\n", w.LongString())
+ }
+ return w
}
// Arg is in registers
r := pa.Registers[regOffset]
- auxInt := x.f.ABISelf.FloatIndexFor(r)
- op := OpArgFloatReg
- // TODO seems like this has implications for debugging. How does this affect the location?
- if auxInt < 0 { // int (not float) parameter register
- op = OpArgIntReg
- auxInt = int64(r)
+ op, auxInt := ArgOpAndRegisterFor(r, x.f.ABISelf)
+ if op == OpArgIntReg && t.IsFloat() || op == OpArgFloatReg && t.IsInteger() {
+ fmt.Printf("pa=%v\nx.f.OwnAux.abiInfo=%s\n",
+ pa.ToString(x.f.ABISelf, true),
+ x.f.OwnAux.abiInfo.String())
+ panic(fmt.Errorf("Op/Type mismatch, op=%s, type=%s", op.String(), t.String()))
}
aux := &AuxNameOffset{baseArg.Aux.(*ir.Name), baseArg.AuxInt + offset}
if toReplace != nil && toReplace.Block == baseArg.Block {
@@ -1461,24 +1465,23 @@ func (x *expandState) newArgToMemOrRegs(baseArg, toReplace *Value, offset int64,
toReplace.Aux = aux
toReplace.AuxInt = auxInt
toReplace.Type = t
- x.commonArgs[key] = toReplace
- return toReplace
+ w = toReplace
} else {
- w := baseArg.Block.NewValue0IA(pos, op, t, auxInt, aux)
- if x.debug {
- x.Printf("---new %s\n", w.LongString())
- }
- x.commonArgs[key] = w
- if toReplace != nil {
- toReplace.copyOf(w)
- }
- return w
+ w = baseArg.Block.NewValue0IA(pos, op, t, auxInt, aux)
+ }
+ x.commonArgs[key] = w
+ if toReplace != nil {
+ toReplace.copyOf(w)
}
+ if x.debug {
+ x.Printf("-->%s\n", w.LongString())
+ }
+ return w
+
}
// argOpAndRegisterFor converts an abi register index into an ssa Op and corresponding
// arg register index.
-// TODO could call this in at least two places earlier in this file.
func ArgOpAndRegisterFor(r abi.RegIndex, abiConfig *abi.ABIConfig) (Op, int64) {
i := abiConfig.FloatIndexFor(r)
if i >= 0 { // float PR
diff --git a/src/cmd/compile/internal/ssa/value.go b/src/cmd/compile/internal/ssa/value.go
index 6cc2b2ab8b..5a9779dd1e 100644
--- a/src/cmd/compile/internal/ssa/value.go
+++ b/src/cmd/compile/internal/ssa/value.go
@@ -198,12 +198,12 @@ func (v *Value) auxString() string {
if v.Aux != nil {
return fmt.Sprintf(" {%v}", v.Aux)
}
- case auxSymOff, auxCallOff, auxTypSize:
+ case auxSymOff, auxCallOff, auxTypSize, auxNameOffsetInt8:
s := ""
if v.Aux != nil {
s = fmt.Sprintf(" {%v}", v.Aux)
}
- if v.AuxInt != 0 {
+ if v.AuxInt != 0 || opcodeTable[v.Op].auxType == auxNameOffsetInt8 {
s += fmt.Sprintf(" [%v]", v.AuxInt)
}
return s
diff --git a/src/cmd/compile/internal/test/abiutils_test.go b/src/cmd/compile/internal/test/abiutils_test.go
index 9a7d6d138c..f8d0af8d7a 100644
--- a/src/cmd/compile/internal/test/abiutils_test.go
+++ b/src/cmd/compile/internal/test/abiutils_test.go
@@ -170,9 +170,9 @@ func TestABIUtilsStruct2(t *testing.T) {
exp := makeExpectedDump(`
IN 0: R{ I0 } spilloffset: 0 typ: struct { int64; struct {} }
IN 1: R{ I1 } spilloffset: 16 typ: struct { int64; struct {} }
- IN 2: R{ I2 F0 } spilloffset: 32 typ: struct { float64; struct { int64; struct {} }; struct {} }
- OUT 0: R{ I0 F0 } spilloffset: -1 typ: struct { float64; struct { int64; struct {} }; struct {} }
- OUT 1: R{ I1 F1 } spilloffset: -1 typ: struct { float64; struct { int64; struct {} }; struct {} }
+ IN 2: R{ F0 I2 } spilloffset: 32 typ: struct { float64; struct { int64; struct {} }; struct {} }
+ OUT 0: R{ F0 I0 } spilloffset: -1 typ: struct { float64; struct { int64; struct {} }; struct {} }
+ OUT 1: R{ F1 I1 } spilloffset: -1 typ: struct { float64; struct { int64; struct {} }; struct {} }
offsetToSpillArea: 0 spillAreaSize: 64
`)