void TR::RegDepCopyRemoval::selectNodesToReuse(TR::NodeChecklist &usedNodes) { for (TR_GlobalRegisterNumber reg = _regBegin; reg < _regEnd; reg++) { RegDepInfo &dep = getRegDepInfo(reg); if (dep.state != REGDEP_UNDECIDED) continue; NodeChoice &prevChoice = getNodeChoice(reg); if (dep.value != prevChoice.original) continue; // can't reuse // Reuse our previous choice! if (trace()) traceMsg(comp(), "\t%s: prefer to reuse previous choice n%un\n", registerName(reg), prevChoice.selected->getGlobalIndex()); TR_ASSERT(!usedNodes.contains(prevChoice.selected), "attempted to reuse the same node more than once\n"); if (prevChoice.selected == dep.value) { dep.state = REGDEP_NODE_ORIGINAL; usedNodes.add(dep.value); } else { dep.state = REGDEP_NODE_REUSE_COPY; } } }
/** * Collect direct loads in a node and its children, adding them to the provided BitVector. * * @param node The node to consider. * @param loadSymRefs BitVector of symbol reference numbers seen. * @param checklist Checklist of visited nodes. */ static void collectDirectLoads(TR::Node *node, TR_BitVector &loadSymRefs, TR::NodeChecklist &checklist) { if (checklist.contains(node)) return; checklist.add(node); if (node->getOpCode().isLoadVarDirect()) loadSymRefs.set(node->getSymbolReference()->getReferenceNumber()); for (int i = 0; i < node->getNumChildren(); i++) collectDirectLoads(node->getChild(i), loadSymRefs, checklist); }
void TR::SoundnessRule::checkNodeSoundness(TR::TreeTop *location, TR::Node *node, TR::NodeChecklist &ancestorNodes, TR::NodeChecklist &visitedNodes) { TR_ASSERT(node != NULL, "checkNodeSoundness requires that node is not NULL"); if (visitedNodes.contains(node)) { return; } visitedNodes.add(node); checkSoundnessCondition(location, !ancestorNodes.contains(node), "n%dn must not be its own ancestor", node->getGlobalIndex()); ancestorNodes.add(node); for (int32_t i = 0; i < node->getNumChildren(); i++) { TR::Node *child = node->getChild(i); checkSoundnessCondition(location, child != NULL, "n%dn child %d must not be NULL", node->getGlobalIndex(), i); checkNodeSoundness(location, child, ancestorNodes, visitedNodes); } ancestorNodes.remove(node); }
/** * Recursive call to anchor nodes with a reference count greater than one prior to a treetop. * * @param comp Compilation object * @param node Node to potentially anchor * @param tt Treetop to anchor nodes before * @param checklist Checklist of visited nodes * @return Whether or not a nodes was anchored. */ static bool anchorCommonNodes(TR::Compilation *comp, TR::Node* node, TR::TreeTop* tt, TR::NodeChecklist &checklist) { if (checklist.contains(node)) return false; checklist.add(node); bool anchored = false; if (node->getReferenceCount() > 1) { tt->insertBefore(TR::TreeTop::create(comp, TR::Node::create(TR::treetop, 1, node))); anchored = true; } else { for (int i = 0; i <node->getNumChildren(); i++) anchored |= anchorCommonNodes(comp, node->getChild(i), tt, checklist); } return anchored; }
void TR::RegDepCopyRemoval::updateRegDeps(TR::NodeChecklist &usedNodes) { for (TR_GlobalRegisterNumber reg = _regBegin; reg < _regEnd; reg++) { RegDepInfo &dep = getRegDepInfo(reg); switch (dep.state) { case REGDEP_NODE_ORIGINAL: rememberNodeChoice(reg, dep.value); break; case REGDEP_NODE_REUSE_COPY: reuseCopy(reg); break; case REGDEP_NODE_FRESH_COPY: makeFreshCopy(reg); break; case REGDEP_IGNORED: discardNodeChoice(reg); break; case REGDEP_ABSENT: { TR::Node *prevSel = getNodeChoice(reg).selected; if (prevSel != NULL && usedNodes.contains(prevSel)) discardNodeChoice(reg); break; } case REGDEP_UNDECIDED: TR_ASSERT(false, "undecided preference for %s survived to updateRegDeps()\n", registerName(reg)); break; default: TR_ASSERT(false, "%s has bad RegDepInfo state %d\n", registerName(reg), (int)dep.state); break; } } }
void TR::RegDepCopyRemoval::selectNodesToCopy(TR::NodeChecklist &usedNodes) { for (TR_GlobalRegisterNumber reg = _regBegin; reg < _regEnd; reg++) { RegDepInfo &dep = getRegDepInfo(reg); if (dep.state != REGDEP_UNDECIDED) continue; if (!usedNodes.contains(dep.value)) { dep.state = REGDEP_NODE_ORIGINAL; usedNodes.add(dep.value); if (trace()) traceMsg(comp(), "\t%s: prefer to keep the original node n%un\n", registerName(reg), dep.value->getGlobalIndex()); } else { dep.state = REGDEP_NODE_FRESH_COPY; if (trace()) traceMsg(comp(), "\t%s: prefer to make a new copy of n%un\n", registerName(reg), dep.value->getGlobalIndex()); } } }
static bool fixUpTree(TR::Node *node, TR::TreeTop *treeTop, TR::NodeChecklist &visited, bool &highGlobalIndex, TR::Optimization *opt, vcount_t evaluatedVisitCount) { if (node->getVisitCount() == evaluatedVisitCount) return false; if (visited.contains(node)) return false; visited.add(node); bool containsFloatingPoint = false; bool anchorLoadaddr = true; bool anchorArrayCmp = true; // for arraycmp node, don't create its tree top anchor // fold it into if statment and save jump instruction if (node->getOpCodeValue() == TR::arraycmp && !node->isArrayCmpLen() && TR::Compiler->target.cpu.isX86()) { anchorArrayCmp = false; } if ((node->getReferenceCount() > 1) && !node->getOpCode().isLoadConst() && anchorLoadaddr && anchorArrayCmp) { if (!opt->comp()->getOption(TR_ProcessHugeMethods)) { int32_t nodeCount = opt->comp()->getNodeCount(); int32_t nodeCountLimit = 3 * USHRT_MAX / 4; if (nodeCount > nodeCountLimit) { dumpOptDetails(opt->comp(), "%snode count %d exceeds limit %d\n", opt->optDetailString(), nodeCount, nodeCountLimit); highGlobalIndex = true; return containsFloatingPoint; } } if (node->getOpCode().isFloatingPoint()) containsFloatingPoint = true; TR::TreeTop *nextTree = treeTop->getNextTreeTop(); node->incFutureUseCount(); TR::TreeTop *anchorTreeTop = TR::TreeTop::create(opt->comp(), TR::Node::create(TR::treetop, 1, node)); anchorTreeTop->getNode()->setFutureUseCount(0); treeTop->join(anchorTreeTop); anchorTreeTop->join(nextTree); } else { for (int32_t i = 0; i < node->getNumChildren(); ++i) { TR::Node *child = node->getChild(i); if (fixUpTree(child, treeTop, visited, highGlobalIndex, opt, evaluatedVisitCount)) containsFloatingPoint = true; } } return containsFloatingPoint; }