Skip to content

regalloc: removes the last use of map for faster allocation #2226

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

Merged
merged 2 commits into from
Jun 4, 2024
Merged
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
112 changes: 52 additions & 60 deletions internal/engine/wazevo/backend/regalloc/regalloc.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,8 @@ type (
phiDefInstListPool wazevoapi.Pool[phiDefInstList]

// Followings are re-used during various places.
blks []Block
reals []RealReg
currentOccupants regInUseSet
blks []Block
reals []RealReg

// Following two fields are updated while iterating the blocks in the reverse postorder.
state state
Expand Down Expand Up @@ -979,27 +978,15 @@ func (a *Allocator) fixMergeState(f Function, blk Block) {
}

s.currentBlockID = bID
a.updateLiveInVRState(a.getOrAllocateBlockState(bID))
a.updateLiveInVRState(blkSt)

currentOccupants := &a.currentOccupants
for i := 0; i < preds; i++ {
currentOccupants.reset()
if i == blkSt.startFromPredIndex {
continue
}

currentOccupantsRev := make(map[VReg]RealReg)
pred := blk.Pred(i)
predSt := a.getOrAllocateBlockState(pred.ID())
for r := RealReg(0); r < 64; r++ {
if v := predSt.endRegs.get(r); v.Valid() {
if _v := blkSt.startRegs.get(r); !_v.Valid() {
continue
}
currentOccupants.add(r, v)
currentOccupantsRev[v] = r
}
}

s.resetAt(predSt)

Expand All @@ -1016,17 +1003,13 @@ func (a *Allocator) fixMergeState(f Function, blk Block) {
floatTmp = FromRealReg(floatFree, RegTypeFloat)
}

if wazevoapi.RegAllocLoggingEnabled {
fmt.Println("\t", pred.ID(), ":", currentOccupants.format(a.regInfo))
}

for r := RealReg(0); r < 64; r++ {
desiredVReg := desiredOccupants.get(r)
if !desiredVReg.Valid() {
continue
}

currentVReg := currentOccupants.get(r)
currentVReg := s.regsInUse.get(r)
if desiredVReg.ID() == currentVReg.ID() {
continue
}
Expand All @@ -1038,86 +1021,95 @@ func (a *Allocator) fixMergeState(f Function, blk Block) {
} else {
tmpRealReg = floatTmp
}
a.reconcileEdge(f, r, pred, currentOccupants, currentOccupantsRev, currentVReg, desiredVReg, tmpRealReg, typ)
a.reconcileEdge(f, r, pred, currentVReg, desiredVReg, tmpRealReg, typ)
}
}
}

// reconcileEdge reconciles the register state between the current block and the predecessor for the real register `r`.
//
// - currentVReg is the current VReg value that sits on the register `r`. This can be VRegInvalid if the register is not used at the end of the predecessor.
// - desiredVReg is the desired VReg value that should be on the register `r`.
// - freeReg is the temporary register that can be used to swap the values, which may or may not be used.
// - typ is the register type of the `r`.
func (a *Allocator) reconcileEdge(f Function,
r RealReg,
pred Block,
currentOccupants *regInUseSet,
currentOccupantsRev map[VReg]RealReg,
currentVReg, desiredVReg VReg,
freeReg VReg,
typ RegType,
) {
// There are four cases to consider:
// 1. currentVReg is valid, but desiredVReg is on the stack.
// 2. Both currentVReg and desiredVReg are valid.
// 3. Desired is on a different register than `r` and currentReg is not valid.
// 4. Desired is on the stack and currentReg is not valid.

s := &a.state
if currentVReg.Valid() {
// Both are on reg.
er, ok := currentOccupantsRev[desiredVReg]
if !ok {
desiredState := s.getVRegState(desiredVReg.ID())
er := desiredState.r
if er == RealRegInvalid {
// Case 1: currentVReg is valid, but desiredVReg is on the stack.
if wazevoapi.RegAllocLoggingEnabled {
fmt.Printf("\t\tv%d is desired to be on %s, but currently on the stack\n",
desiredVReg.ID(), a.regInfo.RealRegName(r),
)
}
// This case is that the desired value is on the stack, but currentVReg is on the target register.
// We need to move the current value to the stack, and reload the desired value.
// We need to move the current value to the stack, and reload the desired value into the register.
// TODO: we can do better here.
f.StoreRegisterBefore(currentVReg.SetRealReg(r), pred.LastInstrForInsertion())
delete(currentOccupantsRev, currentVReg)
s.releaseRealReg(r)

s.getVRegState(desiredVReg.ID()).recordReload(f, pred)
f.ReloadRegisterBefore(desiredVReg.SetRealReg(r), pred.LastInstrForInsertion())
currentOccupants.add(r, desiredVReg)
currentOccupantsRev[desiredVReg] = r
s.useRealReg(r, desiredVReg)
return
}

if wazevoapi.RegAllocLoggingEnabled {
fmt.Printf("\t\tv%d is desired to be on %s, but currently on %s\n",
desiredVReg.ID(), a.regInfo.RealRegName(r), a.regInfo.RealRegName(er),
} else {
// Case 2: Both currentVReg and desiredVReg are valid.
if wazevoapi.RegAllocLoggingEnabled {
fmt.Printf("\t\tv%d is desired to be on %s, but currently on %s\n",
desiredVReg.ID(), a.regInfo.RealRegName(r), a.regInfo.RealRegName(er),
)
}
// This case, we need to swap the values between the current and desired values.
f.SwapBefore(
currentVReg.SetRealReg(r),
desiredVReg.SetRealReg(er),
freeReg,
pred.LastInstrForInsertion(),
)
}
f.SwapBefore(
currentVReg.SetRealReg(r),
desiredVReg.SetRealReg(er),
freeReg,
pred.LastInstrForInsertion(),
)
s.allocatedRegSet = s.allocatedRegSet.add(freeReg.RealReg())
currentOccupantsRev[desiredVReg] = r
currentOccupantsRev[currentVReg] = er
currentOccupants.add(r, desiredVReg)
currentOccupants.add(er, currentVReg)
if wazevoapi.RegAllocLoggingEnabled {
fmt.Printf("\t\tv%d previously on %s moved to %s\n", currentVReg.ID(), a.regInfo.RealRegName(r), a.regInfo.RealRegName(er))
s.allocatedRegSet = s.allocatedRegSet.add(freeReg.RealReg())
s.releaseRealReg(r)
s.releaseRealReg(er)
s.useRealReg(r, desiredVReg)
s.useRealReg(er, currentVReg)
if wazevoapi.RegAllocLoggingEnabled {
fmt.Printf("\t\tv%d previously on %s moved to %s\n", currentVReg.ID(), a.regInfo.RealRegName(r), a.regInfo.RealRegName(er))
}
}
} else {
// Desired is on reg, but currently the target register is not used.
if wazevoapi.RegAllocLoggingEnabled {
fmt.Printf("\t\tv%d is desired to be on %s, current not used\n",
desiredVReg.ID(), a.regInfo.RealRegName(r),
)
}
if currentReg, ok := currentOccupantsRev[desiredVReg]; ok {
if currentReg := s.getVRegState(desiredVReg.ID()).r; currentReg != RealRegInvalid {
// Case 3: Desired is on a different register than `r` and currentReg is not valid.
// We simply need to move the desired value to the register.
f.InsertMoveBefore(
FromRealReg(r, typ),
desiredVReg.SetRealReg(currentReg),
pred.LastInstrForInsertion(),
)
currentOccupants.remove(currentReg)
s.releaseRealReg(currentReg)
} else {
// Case 4: Both currentVReg and desiredVReg are not valid.
// We simply need to reload the desired value into the register.
s.getVRegState(desiredVReg.ID()).recordReload(f, pred)
f.ReloadRegisterBefore(desiredVReg.SetRealReg(r), pred.LastInstrForInsertion())
}
currentOccupantsRev[desiredVReg] = r
currentOccupants.add(r, desiredVReg)
}

if wazevoapi.RegAllocLoggingEnabled {
fmt.Println("\t", pred.ID(), ":", currentOccupants.format(a.regInfo))
s.useRealReg(r, desiredVReg)
}
}

Expand Down
Loading