Skip to content

Commit

Permalink
Changes in RegDepCopyRemoval for splitPostGRA block splitter
Browse files Browse the repository at this point in the history
RegDepCopyRemoval is the last ran optimization which intends to
reduce register shuffling due to global register dependencies.
It was generating tree where we have a PassThrough Child under PassThrough
to copy node to new virtual register. This tree was not working well with
the post GRA block splitter. Issue was that PassThrough child encountered in
GlRegDeps was anchored to tree top. In postGRA block splitter, it records the
regStores encountered before the GlRegDeps in extended basic block to guide
decision on which register to chose for the node after split point.In this commit,
adding changes to both splitPostGRA block splitter and RegDepCopyRemoval optimization
so that we can split the blocks after later has run.

Signed-off-by: Rahil Shah <[email protected]>
  • Loading branch information
r30shah committed May 26, 2020
1 parent 6367999 commit efa37c8
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 11 deletions.
10 changes: 7 additions & 3 deletions compiler/il/OMRBlock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1018,6 +1018,9 @@ static void gatherUnavailableRegisters(TR::Compilation *comp, TR::Node *regDeps,
if (dep->getOpCodeValue() == TR::PassThrough)
{
TR::Node *value = dep->getFirstChild();
TR::Node *originalNode = value;
while (originalNode->getOpCodeValue() == TR::PassThrough)
originalNode = originalNode->getFirstChild();
auto nodeInfoEntry = nodeInfo->find(value);
// If a node referenced under the PassThrough node post split point requires uncommoning
// We need to check if the we can use the information to allocate the register for the node or not.
Expand All @@ -1043,7 +1046,7 @@ static void gatherUnavailableRegisters(TR::Compilation *comp, TR::Node *regDeps,
if (checkIfRegisterIsAvailable(comp, storeNode, unavailableRegisters))
{
// Whether the PassThrough uses same register or not, use the last recorded regStore to assign register to the node.
TR::Node *regLoad = TR::Node::create(value, comp->il.opCodeForRegisterLoad(value->getDataType()));
TR::Node *regLoad = TR::Node::create(value, comp->il.opCodeForRegisterLoad(originalNode->getDataType()));
regLoad->setRegLoadStoreSymbolReference(storeNode->getRegLoadStoreSymbolReference());
regLoad->setGlobalRegisterNumber(storeNode->getGlobalRegisterNumber());
unavailableRegisters.set(storeNode->getGlobalRegisterNumber());
Expand All @@ -1066,15 +1069,16 @@ static void gatherUnavailableRegisters(TR::Compilation *comp, TR::Node *regDeps,
dep->getLowGlobalRegisterNumber() == nodeInfoEntry->second.second->getLowGlobalRegisterNumber() &&
dep->getHighGlobalRegisterNumber() == nodeInfoEntry->second.second->getHighGlobalRegisterNumber())
{
// Passthrough uses same register as the replacement, do not need to do anything
regDeps->setAndIncChild(i, nodeInfoEntry->second.second);
dep->recursivelyDecReferenceCount();
}
else if (needToCreateRegStore && (!needToCheckStoreRegPostSplitPoint || !checkStoreRegNodeListForNode(dep, storeRegNodePostSplitPoint)))
{
// We have either used different register for replacement to value node after split point or Passthrough has corresponding regStore before spilt point, but registers were unavailable.
// In these cases we need to create a regStore for the PassThrough.
// If we have replacement then need to store the replacement to register, else, value needs to be stored.
TR::Node *nodeToBeStored = nodeInfoEntry->second.second != NULL ? nodeInfoEntry->second.second : value;
TR::Node *regStore = TR::Node::create(value, comp->il.opCodeForRegisterStore(value->getDataType()), 1, nodeToBeStored);
TR::Node *regStore = TR::Node::create(value, comp->il.opCodeForRegisterStore(originalNode->getDataType()), 1, nodeToBeStored);
currentTT->insertBefore(TR::TreeTop::create(comp, regStore));
regStore->setGlobalRegisterNumber(dep->getGlobalRegisterNumber());
if (nodeToBeStored->requiresRegisterPair(comp))
Expand Down
39 changes: 32 additions & 7 deletions compiler/optimizer/RegDepCopyRemoval.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,14 @@ TR::RegDepCopyRemoval::perform()
processRegDeps(lastChild, tt);
}
}
else if (node->getOpCode().isStoreReg()
&& node->getHighGlobalRegisterNumber() == static_cast<TR_GlobalRegisterNumber>(-1)
&& (node->getType().isIntegral() || node->getType().isAddress()))
{
TR_GlobalRegisterNumber lowReg = node->getLowGlobalRegisterNumber();
NodeChoice &choice = getNodeChoice(lowReg);
choice.regStoreNode = node;
}
break;
}
}
Expand Down Expand Up @@ -136,15 +144,17 @@ void
TR::RegDepCopyRemoval::discardAllNodeChoices()
{
for (TR_GlobalRegisterNumber reg = _regBegin; reg < _regEnd; reg++)
discardNodeChoice(reg);
discardNodeChoice(reg , true);
}

void
TR::RegDepCopyRemoval::discardNodeChoice(TR_GlobalRegisterNumber reg)
TR::RegDepCopyRemoval::discardNodeChoice(TR_GlobalRegisterNumber reg, bool clearRegStore)
{
NodeChoice &choice = getNodeChoice(reg);
choice.original = NULL;
choice.selected = NULL;
if (clearRegStore)
choice.regStoreNode = NULL;
}

void
Expand Down Expand Up @@ -218,10 +228,13 @@ TR::RegDepCopyRemoval::readRegDeps()
continue;
}

// Only process integral and address-type nodes; they'll go into GPRs

TR_GlobalRegisterNumber reg = depNode->getGlobalRegisterNumber();
TR::DataType depType = depValue->getType();
if (!depType.isIntegral() && !depType.isAddress())
NodeChoice &choice = getNodeChoice(reg);
// Only process integral and address-type nodes; they'll go into GPRs
// For the PassThrough Node, if the recorded regStore node does not have same child as depValue, we skip it.
if ((!depType.isIntegral() && !depType.isAddress()) || (choice.regStoreNode != NULL && choice.regStoreNode->getFirstChild() != depValue))
{
ignoreRegister(reg);
continue;
Expand Down Expand Up @@ -408,9 +421,21 @@ TR::RegDepCopyRemoval::makeFreshCopy(TR_GlobalRegisterNumber reg)
copyNode = TR::Node::create(TR::PassThrough, 1, dep.value);
copyNode->setCopyToNewVirtualRegister();
}

TR::Node *copyTreetopNode = TR::Node::create(TR::treetop, 1, copyNode);
_treetop->insertBefore(TR::TreeTop::create(comp(), copyTreetopNode));
NodeChoice &choice = getNodeChoice(reg);
if (choice.regStoreNode == NULL)
{
// As we walk down in Extended Basic Block, for each register, if exists, we record a regStore node, if we do not have one found for given register, node should be regLoad.
TR_ASSERT_FATAL(dep.node->getOpCode().isLoadReg(), "Only PassThrough (with a corresponding regStore appeared before) or regLoad is expected as children of GlRegDeps, Unexpected Node is n%dn OpCode %s",dep.node->getGlobalIndex(), dep.node->getOpCode().getName());
choice.regStoreNode = TR::Node::create(dep.node, comp()->il.opCodeForRegisterStore(dep.node->getDataType()), 1, copyNode);
_treetop->insertBefore(TR::TreeTop::create(comp(), choice.regStoreNode));
choice.regStoreNode->setGlobalRegisterNumber(dep.node->getGlobalRegisterNumber());
choice.regStoreNode->setRegLoadStoreSymbolReference(dep.node->getRegLoadStoreSymbolReference());
}
else
{
choice.regStoreNode->setAndIncChild(0, copyNode);
dep.value->recursivelyDecReferenceCount();
}
if (trace())
traceMsg(comp(), "\tcopy is n%un\n", copyNode->getGlobalIndex());

Expand Down
3 changes: 2 additions & 1 deletion compiler/optimizer/RegDepCopyRemoval.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ class RegDepCopyRemoval : public TR::Optimization
{
TR::Node *original;
TR::Node *selected;
TR::Node *regStoreNode;
};

const char *registerName(TR_GlobalRegisterNumber reg);
Expand All @@ -105,7 +106,7 @@ class RegDepCopyRemoval : public TR::Optimization
NodeChoice &getNodeChoice(TR_GlobalRegisterNumber reg);

void discardAllNodeChoices();
void discardNodeChoice(TR_GlobalRegisterNumber reg);
void discardNodeChoice(TR_GlobalRegisterNumber reg, bool clearRegStore = false);
void rememberNodeChoice(TR_GlobalRegisterNumber reg, TR::Node *selected);

void processRegDeps(TR::Node *deps, TR::TreeTop *depTT);
Expand Down

0 comments on commit efa37c8

Please sign in to comment.