Skip to content

Commit

Permalink
Improve registerExchange API on Z
Browse files Browse the repository at this point in the history
When assigning virtual register to target real register while assigning
registers for instruction, register exchange API which would take care
of care of making exchange between the target real register and current
assigned register bails out when faced with different sized register and
falls back to the path where we would need spare register to satisfy the
requirement. This would cause an issue where we run out of all the
registers.
In order to make exchange between target real register and current
assigned register, if either one is 64-bit, we can simply use 8 byte
spill slot to do that. This commit upgrades the register exchange API to
do that.

Fixes: eclipse-openj9/openj9#12789

Signed-off-by: Rahil Shah <rahil@ca.ibm.com>
  • Loading branch information
r30shah committed Jul 12, 2021
1 parent bdee22f commit 8d35797
Showing 1 changed file with 17 additions and 26 deletions.
43 changes: 17 additions & 26 deletions compiler/z/codegen/OMRMachine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,13 +263,11 @@ OMR::Z::Machine::registerExchange(TR::CodeGenerator* cg,
}
else
{
TR_ASSERT_FATAL(targetReg->getAssignedRegister()->is64BitReg() == sourceReg->getAssignedRegister()->is64BitReg(), "Attempting register exchange with one 64-bit register (%s) and one 32-bit register (%s)", getRegisterName(sourceReg, cg), getRegisterName(targetReg, cg));

TR::InstOpCode::Mnemonic opLoadReg = TR::InstOpCode::bad;
TR::InstOpCode::Mnemonic opLoad = TR::InstOpCode::bad;
TR::InstOpCode::Mnemonic opStore = TR::InstOpCode::bad;

if (targetReg->getAssignedRegister()->is64BitReg())
if (targetReg->getAssignedRegister()->is64BitReg() || sourceReg->getAssignedRegister()->is64BitReg())
{
opLoadReg = TR::InstOpCode::LGR;
opLoad = TR::InstOpCode::LG;
Expand All @@ -292,7 +290,7 @@ OMR::Z::Machine::registerExchange(TR::CodeGenerator* cg,
TR::Instruction * currentInstruction = precedingInstruction;
TR_BackingStore * location;

if (targetReg->getAssignedRegister()->is64BitReg())
if (targetReg->getAssignedRegister()->is64BitReg() || sourceReg->getAssignedRegister()->is64BitReg())
{
location = cg->allocateSpill(8, false, NULL);
}
Expand Down Expand Up @@ -2920,27 +2918,8 @@ OMR::Z::Machine::reverseSpillState(TR::Instruction *currentInstruction,
bool
OMR::Z::Machine::isAssignable(TR::Register * virtReg, TR::RealRegister * realReg)
{
if (virtReg->isUsedInMemRef() && realReg == _registerFile[TR::RealRegister::GPR0])
{
return false;
}
else
{
// TODO: This is needlessly restrictive. The registerExchange API cannot handle register exchanges with one
// 32-bit and one 64-bit register and the code below effectively guards against calling the registerExchange
// API in such situations. This can definitely be relaxed and the registerExchange API taught how to handle
// those cases. If you look at the places this API (isAssignable) is used you will see we effectively handle
// it there already. That code needs to be cleaned up and consolidated into the registerExchange API.
if (virtReg->getKind() != TR_FPR && virtReg->getKind() != TR_VRF)
{
if (realReg->getAssignedRegister() != NULL)
{
return virtReg->is64BitReg() == realReg->getAssignedRegister()->is64BitReg();
}
}

return true;
}
// virtReg used in memory reference can not be assigned to GPR0.
return !(virtReg->isUsedInMemRef() && realReg == _registerFile[TR::RealRegister::GPR0]);
}

/**
Expand Down Expand Up @@ -3058,7 +3037,19 @@ OMR::Z::Machine::coerceRegisterAssignment(TR::Instruction
if (!self()->isAssignable(currentTargetVirtual, currentAssignedRegister))
{
{
TR_ASSERT(spareReg!=NULL, "coerce reg - blocked, sparereg cannot be NULL.");
/**
* Register exchange API takes care of exchanging between registers.
* In rare case, where virtual register to which real target register
* is assigned to is used in memory reference and currentAssignedRegister
* is GPR0, we can not do register exchange and in that case we would need
* spareReg.
* Currently we do not have any solution when we hit this scenario so
* instead of failing the JVM with Assert, fail the compilation.
*/
if (spareReg == NULL)
{
comp->failCompilation<TR::CompilationException>("Abort compilation as we can not find a spareReg for blocked target real register");
}
self()->cg()->traceRegAssigned(currentTargetVirtual, spareReg);

cursor = self()->registerCopy(self()->cg(), rk, targetRegister, spareReg, currentInstruction);
Expand Down

0 comments on commit 8d35797

Please sign in to comment.