Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wazevo(regalloc): removes map usage in real reg tracking #1801

Merged
merged 1 commit into from
Oct 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions internal/engine/wazevo/backend/isa/arm64/abi.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ var regInfo = &regalloc.RegisterInfo{
v0: v0VReg, v1: v1VReg, v2: v2VReg, v3: v3VReg, v4: v4VReg, v5: v5VReg, v6: v6VReg, v7: v7VReg, v8: v8VReg, v9: v9VReg, v10: v10VReg, v11: v11VReg, v12: v12VReg, v13: v13VReg, v14: v14VReg, v15: v15VReg, v16: v16VReg, v17: v17VReg, v18: v18VReg, v19: v19VReg, v20: v20VReg, v21: v21VReg, v22: v22VReg, v23: v23VReg, v24: v24VReg, v25: v25VReg, v26: v26VReg, v27: v27VReg, v28: v28VReg, v29: v29VReg, v30: v30VReg, v31: v31VReg,
},
RealRegName: func(r regalloc.RealReg) string { return regNames[r] },
RealRegType: func(r regalloc.RealReg) regalloc.RegType {
if r < v0 {
return regalloc.RegTypeInt
}
return regalloc.RegTypeFloat
},
}

// abiImpl implements backend.FunctionABI.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ func (m *machine) RegisterInfo(debug bool) *regalloc.RegisterInfo {
regInfoDebug.CallerSavedRegisters = regInfo.CallerSavedRegisters
regInfoDebug.RealRegToVReg = regInfo.RealRegToVReg
regInfoDebug.RealRegName = regInfo.RealRegName
regInfoDebug.RealRegType = regInfo.RealRegType
regInfoDebug.AllocatableRegisters[regalloc.RegTypeFloat] = []regalloc.RealReg{
v18, // One callee saved.
v7, v6, v5, v4, v3, v2, v1, v0, // Allocatable sets == Argument registers.
Expand Down
61 changes: 28 additions & 33 deletions internal/engine/wazevo/backend/regalloc/regalloc.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ type (
RealRegToVReg []VReg
// RealRegName returns the name of the given RealReg for debugging.
RealRegName func(r RealReg) string
RealRegType func(r RealReg) RegType
}

// Allocator is a register allocator.
Expand Down Expand Up @@ -80,8 +81,8 @@ type (
lastUses map[VReg]programCounter
kills map[VReg]programCounter
// Pre-colored real registers can have multiple live ranges in one block.
realRegUses map[VReg][]programCounter
realRegDefs map[VReg][]programCounter
realRegUses [vRegIDReservedForRealNum][]programCounter
realRegDefs [vRegIDReservedForRealNum][]programCounter
intervalMng *intervalManager
}

Expand Down Expand Up @@ -185,9 +186,10 @@ func (a *Allocator) livenessAnalysis(f Function) {
}
for _, def := range instr.Defs() {
dstVR = def
defID := def.ID()
pos := pc + pcDefOffset
if def.IsRealReg() {
info.realRegDefs[def] = append(info.realRegDefs[def], pos)
info.realRegDefs[defID] = append(info.realRegDefs[defID], pos)
} else {
if _, ok := info.defs[def]; !ok {
// This means that this VReg is defined multiple times in a series of instructions
Expand Down Expand Up @@ -407,37 +409,30 @@ func (a *Allocator) buildLiveRangesForNonReals(info *blockInfo) {
func (a *Allocator) buildLiveRangesForReals(info *blockInfo) {
ds, us := info.realRegDefs, info.realRegUses

// In order to do the deterministic compilation, we need to sort the registers.
a.vs = a.vs[:0]
for v := range us {
for i := 0; i < RealRegsNumMax; i++ {
r := RealReg(i)
// Non allocation target registers are not needed here.
if !a.allocatableSet[v.RealReg()] {
if !a.allocatableSet[r] {
continue
}
a.vs = append(a.vs, v)
}
sort.SliceStable(a.vs, func(i, j int) bool {
return a.vs[i].RealReg() < a.vs[j].RealReg()
})

for _, v := range a.vs {
uses := us[v]
defs, ok := ds[v]
if !ok || len(defs) != len(uses) {
uses := us[r]
defs := ds[r]
if len(defs) != len(uses) {
// This is likely a bug of the Instr interface implementation and/or ABI around call instructions.
// E.g. call or ret instructions should specify that they use all the real registers (calling convention).
panic(
fmt.Sprintf(
"BUG: real register (%s) is defined and used, but the number of defs and uses are different: %d (defs) != %d (uses)",
a.regInfo.RealRegName(v.RealReg()), len(defs), len(uses),
a.regInfo.RealRegName(r), len(defs), len(uses),
),
)
}

for i := range uses {
n := a.allocateNode()
n.r = v.RealReg()
n.v = v
n.r = r
n.v = FromRealReg(r, a.regInfo.RealRegType(r))
defined, used := defs[i], uses[i]
intervalNode := info.intervalMng.insert(n, defined, used)
n.ranges = append(n.ranges, intervalNode)
Expand Down Expand Up @@ -558,26 +553,22 @@ func (a *Allocator) initBlockInfo(i *blockInfo) {
} else {
resetMap(a, i.kills)
}
if i.realRegUses == nil {
i.realRegUses = make(map[VReg][]programCounter)
} else {
resetMap(a, i.realRegUses)
}
if i.realRegDefs == nil {
i.realRegDefs = make(map[VReg][]programCounter)
} else {
resetMap(a, i.realRegDefs)

for index := range i.realRegUses {
i.realRegUses[index] = i.realRegUses[index][:0]
i.realRegDefs[index] = i.realRegDefs[index][:0]
}
}

func (i *blockInfo) addRealRegUsage(v VReg, pc programCounter) {
defs := i.realRegDefs[v]
id := v.ID()
defs := i.realRegDefs[id]
if len(defs) == 0 {
// If the definition not found yet but used, this must be a function preamble,
// so we let's assume it is defined at the beginning.
i.realRegDefs[v] = append(i.realRegDefs[v], 0)
i.realRegDefs[id] = append(i.realRegDefs[id], 0)
}
i.realRegUses[v] = append(i.realRegUses[v], pc)
i.realRegUses[id] = append(i.realRegUses[id], pc)
}

// Format is for debugging.
Expand Down Expand Up @@ -605,11 +596,15 @@ func (i *blockInfo) Format(ri *RegisterInfo) string {
}
buf.WriteString("\n\trealRegUses: ")
for v, pos := range i.realRegUses {
buf.WriteString(fmt.Sprintf("%s@%v ", ri.RealRegName(v.RealReg()), pos))
if len(pos) > 0 {
buf.WriteString(fmt.Sprintf("%s@%v ", ri.RealRegName(RealReg(v)), pos))
}
}
buf.WriteString("\n\trealRegDefs: ")
for v, pos := range i.realRegDefs {
buf.WriteString(fmt.Sprintf("%s@%v ", ri.RealRegName(v.RealReg()), pos))
if len(pos) > 0 {
buf.WriteString(fmt.Sprintf("%s@%v ", ri.RealRegName(RealReg(v)), pos))
}
}
return buf.String()
}
Expand Down
33 changes: 14 additions & 19 deletions internal/engine/wazevo/backend/regalloc/regalloc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import (
)

func TestAllocator_livenessAnalysis(t *testing.T) {
realReg, realReg2 := FromRealReg(50, RegTypeInt), FromRealReg(100, RegTypeInt)
const realRegID, realRegID2 = 50, 100
realReg, realReg2 := FromRealReg(realRegID, RegTypeInt), FromRealReg(realRegID2, RegTypeInt)
const phiVReg = 12345
for _, tc := range []struct {
name string
Expand Down Expand Up @@ -83,11 +84,11 @@ func TestAllocator_livenessAnalysis(t *testing.T) {
4: pcStride + pcDefOffset,
5: pcStride + pcDefOffset,
},
realRegUses: map[VReg][]programCounter{
realReg: {pcStride*2 + pcUseOffset},
realRegUses: [vRegIDReservedForRealNum][]programCounter{
realRegID: {pcStride*2 + pcUseOffset},
},
realRegDefs: map[VReg][]programCounter{
realReg: {pcDefOffset},
realRegDefs: [vRegIDReservedForRealNum][]programCounter{
realRegID: {pcDefOffset},
},
},
2: {
Expand Down Expand Up @@ -144,22 +145,22 @@ func TestAllocator_livenessAnalysis(t *testing.T) {
liveOuts: map[VReg]struct{}{1000: {}},
lastUses: map[VReg]programCounter{1: pcUseOffset},
kills: map[VReg]programCounter{1: pcUseOffset},
realRegDefs: map[VReg][]programCounter{
realReg: {pcDefOffset, pcStride*4 + pcDefOffset},
realReg2: {pcStride*2 + pcDefOffset},
realRegDefs: [vRegIDReservedForRealNum][]programCounter{
realRegID: {pcDefOffset, pcStride*4 + pcDefOffset},
realRegID2: {pcStride*2 + pcDefOffset},
},
realRegUses: map[VReg][]programCounter{
realReg: {pcStride + pcUseOffset, pcStride*5 + pcUseOffset},
realReg2: {pcStride*3 + pcUseOffset},
realRegUses: [vRegIDReservedForRealNum][]programCounter{
realRegID: {pcStride + pcUseOffset, pcStride*5 + pcUseOffset},
realRegID2: {pcStride*3 + pcUseOffset},
},
},
2: {
liveIns: map[VReg]struct{}{1000: {}, 2: {}},
liveOuts: map[VReg]struct{}{1000: {}},
lastUses: map[VReg]programCounter{2: pcUseOffset},
kills: map[VReg]programCounter{2: pcUseOffset},
realRegUses: map[VReg][]programCounter{realReg2: {pcUseOffset}},
realRegDefs: map[VReg][]programCounter{realReg2: {0}},
realRegUses: [vRegIDReservedForRealNum][]programCounter{realRegID2: {pcUseOffset}},
realRegDefs: [vRegIDReservedForRealNum][]programCounter{realRegID2: {0}},
},
3: {
liveIns: map[VReg]struct{}{1000: {}},
Expand Down Expand Up @@ -535,12 +536,6 @@ func initMapInInfo(info *blockInfo) {
if info.lastUses == nil {
info.lastUses = make(map[VReg]programCounter)
}
if info.realRegUses == nil {
info.realRegUses = make(map[VReg][]programCounter)
}
if info.realRegDefs == nil {
info.realRegDefs = make(map[VReg][]programCounter)
}
}

func TestNode_assignedRealReg(t *testing.T) {
Expand Down
Loading