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

Reduce TP for targets with more than 64 Registers Part 1 #112704

Merged
merged 5 commits into from
Mar 20, 2025
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
25 changes: 25 additions & 0 deletions src/coreclr/jit/compiler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1110,6 +1110,31 @@ inline regNumber genFirstRegNumFromMaskAndToggle(SingleTypeRegSet& mask, var_typ
return regNum;
}

//------------------------------------------------------------------------------
// genFirstRegNumFromMaskAndToggle : Maps first bit set in the register mask to a
// register number and also toggle the bit in the `mask`.
// Arguments:
// mask - the register mask
// type - type of the register mask
//
// Return Value:
// The number of the first register contained in the mask and updates the `mask` to toggle
// the bit.
//

inline regNumber genFirstRegNumFromMaskAndToggle(SingleTypeRegSet& mask)
{
assert(mask != RBM_NONE); // Must have one bit set, so can't have a mask of zero

/* Convert the mask to a register number */

regNumber regNum = (regNumber)BitOperations::BitScanForward(mask);

mask ^= genSingleTypeRegMask(regNum);

return regNum;
}

/*****************************************************************************
*
* Return the size in bytes of the given type.
Expand Down
86 changes: 75 additions & 11 deletions src/coreclr/jit/lsra.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3856,9 +3856,36 @@ void LinearScan::processKills(RefPosition* killRefPosition)
RefPosition* nextKill = killRefPosition->nextRefPosition;

regMaskTP killedRegs = killRefPosition->getKilledRegisters();
while (killedRegs.IsNonEmpty())

freeKilledRegs(killRefPosition, killedRegs.getLow(), nextKill, REG_LOW_BASE);

#ifdef HAS_MORE_THAN_64_REGISTERS
freeKilledRegs(killRefPosition, killedRegs.getHigh(), nextKill, REG_HIGH_BASE);
#endif

regsBusyUntilKill &= ~killRefPosition->getKilledRegisters();
INDEBUG(dumpLsraAllocationEvent(LSRA_EVENT_KILL_REGS, nullptr, REG_NA, nullptr, NONE,
killRefPosition->getKilledRegisters()));
}

//------------------------------------------------------------------------
// freeKilledRegs: Handle registers that are being killed.
//
// Arguments:
// killRefPosition - The RefPosition for the kill
// killedRegs - Registers to kill
// nextKill - The RefPosition for next kill
// regBase - `0` or `64` based on the `killedRegs` being processed
//
void LinearScan::freeKilledRegs(RefPosition* killRefPosition,
SingleTypeRegSet killedRegs,
RefPosition* nextKill,
int regBase)
{

while (killedRegs != RBM_NONE)
{
regNumber killedReg = genFirstRegNumFromMaskAndToggle(killedRegs);
regNumber killedReg = (regNumber)(genFirstRegNumFromMaskAndToggle(killedRegs) + regBase);
RegRecord* regRecord = getRegisterRecord(killedReg);
Interval* assignedInterval = regRecord->assignedInterval;
if (assignedInterval != nullptr)
Expand All @@ -3874,10 +3901,6 @@ void LinearScan::processKills(RefPosition* killRefPosition)
: regRecord->recentRefPosition->nextRefPosition;
updateNextFixedRef(regRecord, regNextRefPos, nextKill);
}

regsBusyUntilKill &= ~killRefPosition->getKilledRegisters();
INDEBUG(dumpLsraAllocationEvent(LSRA_EVENT_KILL_REGS, nullptr, REG_NA, nullptr, NONE,
killRefPosition->getKilledRegisters()));
}

//------------------------------------------------------------------------
Expand Down Expand Up @@ -4555,14 +4578,34 @@ void LinearScan::processBlockStartLocations(BasicBlock* currentBlock)
}
}
#else

regMaskTP deadCandidates = ~liveRegs;

// Only focus on actual registers present
deadCandidates &= actualRegistersMask;
handleDeadCandidates(deadCandidates.getLow(), REG_LOW_BASE, inVarToRegMap);
#ifdef HAS_MORE_THAN_64_REGISTERS
handleDeadCandidates(deadCandidates.getHigh(), REG_HIGH_BASE, inVarToRegMap);
#endif // HAS_MORE_THAN_64_REGISTERS
#endif // TARGET_ARM
}

while (deadCandidates.IsNonEmpty())
//------------------------------------------------------------------------
// handleDeadCandidates: Handle registers that are assigned to local variables.
//
// Arguments:
// deadCandidates - mask of registers.
// regBase - base register number.
// inVarToRegMap - variable to register map.
//
// Return Value:
// None
//
void LinearScan::handleDeadCandidates(SingleTypeRegSet deadCandidates, int regBase, VarToRegMap inVarToRegMap)
{
while (deadCandidates != RBM_NONE)
{
regNumber reg = genFirstRegNumFromMaskAndToggle(deadCandidates);
regNumber reg = (regNumber)(genFirstRegNumFromMaskAndToggle(deadCandidates) + regBase);
RegRecord* physRegRecord = getRegisterRecord(reg);

makeRegAvailable(reg, physRegRecord->registerType);
Expand Down Expand Up @@ -4592,7 +4635,6 @@ void LinearScan::processBlockStartLocations(BasicBlock* currentBlock)
}
}
}
#endif // TARGET_ARM
}

//------------------------------------------------------------------------
Expand Down Expand Up @@ -4741,6 +4783,22 @@ void LinearScan::freeRegister(RegRecord* physRegRecord)
}
}

//------------------------------------------------------------------------
// LinearScan::freeRegisters: Free the registers in 'regsToFree'
//
// Arguments:
// regsToFree - the mask of registers to free, separated into low and high parts.
// regBase - `0` or `64` depending on if the registers to be freed are in the lower or higher bank.
//
void LinearScan::freeRegistersSingleType(SingleTypeRegSet regsToFree, int regBase)
{
while (regsToFree != RBM_NONE)
{
regNumber nextReg = (regNumber)(genFirstRegNumFromMaskAndToggle(regsToFree) + regBase);
RegRecord* regRecord = getRegisterRecord(nextReg);
freeRegister(regRecord);
}
}
//------------------------------------------------------------------------
// LinearScan::freeRegisters: Free the registers in 'regsToFree'
//
Expand All @@ -4756,20 +4814,26 @@ void LinearScan::freeRegisters(regMaskTP regsToFree)

INDEBUG(dumpLsraAllocationEvent(LSRA_EVENT_FREE_REGS));
makeRegsAvailable(regsToFree);
#ifdef TARGET_ARM
while (regsToFree.IsNonEmpty())
{
regNumber nextReg = genFirstRegNumFromMaskAndToggle(regsToFree);

RegRecord* regRecord = getRegisterRecord(nextReg);
#ifdef TARGET_ARM
if (regRecord->assignedInterval != nullptr && (regRecord->assignedInterval->registerType == TYP_DOUBLE))
{
assert(genIsValidDoubleReg(nextReg));
regsToFree.RemoveRegNumFromMask(regNumber(nextReg + 1));
}
#endif
freeRegister(regRecord);
}
#else
freeRegistersSingleType(regsToFree.getLow(), REG_LOW_BASE);
#ifdef HAS_MORE_THAN_64_REGISTERS
freeRegistersSingleType(regsToFree.getHigh(), REG_HIGH_BASE);
#endif

#endif
}

//------------------------------------------------------------------------
Expand Down
21 changes: 14 additions & 7 deletions src/coreclr/jit/lsra.h
Original file line number Diff line number Diff line change
Expand Up @@ -1005,8 +1005,10 @@ class LinearScan : public LinearScanInterface

// Record variable locations at start/end of block
void processBlockStartLocations(BasicBlock* current);
void processBlockEndLocations(BasicBlock* current);
void resetAllRegistersState();

FORCEINLINE void handleDeadCandidates(SingleTypeRegSet deadCandidates, int regBase, VarToRegMap inVarToRegMap);
void processBlockEndLocations(BasicBlock* current);
void resetAllRegistersState();

#ifdef TARGET_ARM
bool isSecondHalfReg(RegRecord* regRec, Interval* interval);
Expand Down Expand Up @@ -1079,9 +1081,10 @@ class LinearScan : public LinearScanInterface
SingleTypeRegSet lowSIMDRegs();
SingleTypeRegSet internalFloatRegCandidates();

void makeRegisterInactive(RegRecord* physRegRecord);
void freeRegister(RegRecord* physRegRecord);
void freeRegisters(regMaskTP regsToFree);
void makeRegisterInactive(RegRecord* physRegRecord);
void freeRegister(RegRecord* physRegRecord);
void freeRegisters(regMaskTP regsToFree);
FORCEINLINE void freeRegistersSingleType(SingleTypeRegSet regsToFree, int regBase);

// Get the type that this tree defines.
var_types getDefType(GenTree* tree)
Expand Down Expand Up @@ -1192,8 +1195,12 @@ class LinearScan : public LinearScanInterface
void setIntervalAsSplit(Interval* interval);
void spillInterval(Interval* interval, RefPosition* fromRefPosition DEBUGARG(RefPosition* toRefPosition));

void processKills(RefPosition* killRefPosition);
void spillGCRefs(RefPosition* killRefPosition);
void processKills(RefPosition* killRefPosition);
FORCEINLINE void freeKilledRegs(RefPosition* killRefPosition,
SingleTypeRegSet killedRegs,
RefPosition* nextKill,
int regBase);
void spillGCRefs(RefPosition* killRefPosition);

/*****************************************************************************
* Register selection
Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/jit/target.h
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,10 @@ typedef uint64_t regMaskSmall;
#define HAS_MORE_THAN_64_REGISTERS 1
#endif // TARGET_ARM64

#define REG_LOW_BASE 0
#ifdef HAS_MORE_THAN_64_REGISTERS
#define REG_HIGH_BASE 64
#endif
// TODO: Rename regMaskSmall as RegSet64 (at least for 64-bit)
typedef regMaskSmall SingleTypeRegSet;
inline SingleTypeRegSet genSingleTypeRegMask(regNumber reg);
Expand Down
Loading