void TR::RegDepCopyRemoval::makeFreshCopy(TR_GlobalRegisterNumber reg) { RegDepInfo &dep = getRegDepInfo(reg); if (!performTransformation(comp(), "%schange %s in GlRegDeps n%un to an explicit copy of n%un\n", optDetailString(), registerName(reg), _regDeps->getGlobalIndex(), dep.value->getGlobalIndex())) return; // Split the block at fallthrough if necessary to avoid putting copies // between branches and BBEnd. TR::Node *curNode = _treetop->getNode(); if (curNode->getOpCodeValue() == TR::BBEnd) { TR::Block *curBlock = curNode->getBlock(); if (curBlock->getLastRealTreeTop() != curBlock->getLastNonControlFlowTreeTop()) { TR::Block *fallthrough = curBlock->getNextBlock(); fallthrough = curBlock->splitEdge(curBlock, fallthrough, comp()); TR_ASSERT(curBlock->getNextBlock() == fallthrough, "bad block placement from splitEdge\n"); fallthrough->setIsExtensionOfPreviousBlock(); _treetop = fallthrough->getExit(); TR::Node *newNode = _treetop->getNode(); newNode->setChild(0, _regDeps); newNode->setNumChildren(1); curNode->setNumChildren(0); if (trace()) traceMsg(comp(), "\tsplit fallthrough edge to insert copy, created block_%d\n", fallthrough->getNumber()); } } // Make and insert the copy TR::Node *copyNode = NULL; if (dep.value->getOpCode().isLoadConst()) { // No need to depend on the other register. // TODO heuristic for whether this is really better than a reg-reg move? generateRegcopyDebugCounter("const-remat"); copyNode = TR::Node::create(dep.value->getOpCodeValue(), 0); copyNode->setConstValue(dep.value->getConstValue()); } else { generateRegcopyDebugCounter("fresh-copy"); 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)); if (trace()) traceMsg(comp(), "\tcopy is n%un\n", copyNode->getGlobalIndex()); updateSingleRegDep(reg, copyNode); }
void TR_ExpressionsSimplification::removeUnsupportedCandidates() { ListIterator<TR::TreeTop> candidateTTs(_candidateTTs); for (TR::TreeTop *candidateTT = candidateTTs.getFirst(); candidateTT; candidateTT = candidateTTs.getNext()) { TR::Node *candidate = candidateTT->getNode(); if (!_supportedExpressions->get(candidate->getGlobalIndex())) { if (trace()) traceMsg(comp(), "Removing candidate %p which is unsupported or has unsupported subexpressions\n", candidate); _candidateTTs->remove(candidateTT); } } }
/** * In pass_1(validateRefCountPass1), the Local Index (which is set to the Ref * Count) for each child is decremented for each visit. The second pass is to * make sure that the Local Index is zero by the end of the block. A non-zero * Local Index would indicate that the Ref count was wrong at the start * of the Validation Process. */ void TR::ValidateNodeRefCountWithinBlock::validateRefCountPass1(TR::Node *node) { /* If this is the first time through this node, verify the children. */ if (!_nodeChecklist.isSet(node->getGlobalIndex())) { _nodeChecklist.set(node->getGlobalIndex()); for (int32_t i = node->getNumChildren() - 1; i >= 0; --i) { TR::Node *child = node->getChild(i); if (_nodeChecklist.isSet(child->getGlobalIndex())) { /* If the child has already been visited, decrement its verifyRefCount. */ child->decLocalIndex(); } else { /* If the child has not yet been visited, set its localIndex and visit it. */ child->setLocalIndex(child->getReferenceCount() - 1); validateRefCountPass1(child); } } } }
void TR::ILValidator::validityRule(Location &location, bool condition, const char *formatStr, ...) { if (!condition) { _isValidSoFar = false; TR::Node *node = location.currentNode(); printDiagnostic("*** VALIDATION ERROR ***\nNode: %s n%dn\nMethod: %s\n", node->getOpCode().getName(), node->getGlobalIndex(), comp()->signature()); va_list args; va_start(args, formatStr); vprintDiagnostic(formatStr, args); va_end(args); printDiagnostic("\n"); FAIL(); } }
void TR::RegDepCopyRemoval::readRegDeps() { for (int i = 0; i < _regDeps->getNumChildren(); i++) { TR::Node *depNode = _regDeps->getChild(i); TR::Node *depValue = depNode; if (depValue->getOpCodeValue() == TR::PassThrough) { do depValue = depValue->getFirstChild(); while (depValue->getOpCodeValue() == TR::PassThrough); } else { TR_ASSERT(depNode->getOpCode().isLoadReg(), "invalid GlRegDeps child opcode n%un %s\n", depNode->getGlobalIndex(), depNode->getOpCode().getName()); } // Avoid register pairs for simplicity, at least for now bool isRegPairDep = depNode->getHighGlobalRegisterNumber() != (TR_GlobalRegisterNumber)-1; bool valueNeedsRegPair = comp()->nodeNeeds2Regs(depValue); TR_ASSERT(isRegPairDep == valueNeedsRegPair, "mismatch on number of registers required for n%un\n", depNode->getGlobalIndex()); if (isRegPairDep) { ignoreRegister(depNode->getLowGlobalRegisterNumber()); ignoreRegister(depNode->getHighGlobalRegisterNumber()); 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()) { ignoreRegister(reg); continue; } RegDepInfo &dep = getRegDepInfo(reg); TR_ASSERT(dep.state == REGDEP_ABSENT, "register %s is multiply-specified\n", registerName(reg)); dep.node = depNode; dep.value = depValue; dep.state = REGDEP_UNDECIDED; dep.childIndex = i; } }
void OMR::CodeGenPhase::performSetupForInstructionSelectionPhase(TR::CodeGenerator * cg, TR::CodeGenPhase * phase) { TR::Compilation *comp = cg->comp(); if (TR::Compiler->target.cpu.isZ() && TR::Compiler->om.shouldGenerateReadBarriersForFieldLoads()) { // TODO (GuardedStorage): We need to come up with a better solution than anchoring aloadi's // to enforce certain evaluation order traceMsg(comp, "GuardedStorage: in performSetupForInstructionSelectionPhase\n"); auto mapAllocator = getTypedAllocator<std::pair<TR::TreeTop*, TR::TreeTop*> >(comp->allocator()); std::map<TR::TreeTop*, TR::TreeTop*, std::less<TR::TreeTop*>, TR::typed_allocator<std::pair<TR::TreeTop* const, TR::TreeTop*>, TR::Allocator> > currentTreeTopToappendTreeTop(std::less<TR::TreeTop*> (), mapAllocator); TR_BitVector *unAnchorableAloadiNodes = comp->getBitVectorPool().get(); for (TR::PreorderNodeIterator iter(comp->getStartTree(), comp); iter != NULL; ++iter) { TR::Node *node = iter.currentNode(); traceMsg(comp, "GuardedStorage: Examining node = %p\n", node); // isNullCheck handles both TR::NULLCHK and TR::ResolveAndNULLCHK // both of which do not operate on their child but their // grandchild (or greatgrandchild). if (node->getOpCode().isNullCheck()) { // An aloadi cannot be anchored if there is a Null Check on // its child. There are two situations where this occurs. // The first is when doing an aloadi off some node that is // being NULLCHK'd (see Ex1). The second is when doing an // icalli in which case the aloadi loads the VFT of an // object that must be NULLCHK'd (see Ex2). // // Ex1: // n1n NULLCHK on n3n // n2n aloadi f <-- First Child And Parent of Null Chk'd Node // n3n aload O // // Ex2: // n1n NULLCHK on n4n // n2n icall foo <-- First Child // n3n aloadi <vft> <-- Parent of Null Chk'd Node // n4n aload O // n4n ==> aload O TR::Node *nodeBeingNullChkd = node->getNullCheckReference(); if (nodeBeingNullChkd) { TR::Node *firstChild = node->getFirstChild(); TR::Node *parentOfNullChkdNode = NULL; if (firstChild->getOpCode().isCall() && firstChild->getOpCode().isIndirect()) { parentOfNullChkdNode = firstChild->getFirstChild(); } else { parentOfNullChkdNode = firstChild; } if (parentOfNullChkdNode && parentOfNullChkdNode->getOpCodeValue() == TR::aloadi && parentOfNullChkdNode->getNumChildren() > 0 && parentOfNullChkdNode->getFirstChild() == nodeBeingNullChkd) { unAnchorableAloadiNodes->set(parentOfNullChkdNode->getGlobalIndex()); traceMsg(comp, "GuardedStorage: Cannot anchor %p\n", firstChild); } } } else { bool shouldAnchorNode = false; if (node->getOpCodeValue() == TR::aloadi && !unAnchorableAloadiNodes->isSet(node->getGlobalIndex())) { shouldAnchorNode = true; } else if (node->getOpCodeValue() == TR::aload && node->getSymbol()->isStatic() && node->getSymbol()->isCollectedReference()) { shouldAnchorNode = true; } if (shouldAnchorNode) { TR::TreeTop* anchorTreeTop = TR::TreeTop::create(comp, TR::Node::create(TR::treetop, 1, node)); TR::TreeTop* appendTreeTop = iter.currentTree(); if (currentTreeTopToappendTreeTop.count(appendTreeTop) > 0) { appendTreeTop = currentTreeTopToappendTreeTop[appendTreeTop]; } // Anchor the aload/aloadi before the current treetop appendTreeTop->insertBefore(anchorTreeTop); currentTreeTopToappendTreeTop[iter.currentTree()] = anchorTreeTop; traceMsg(comp, "GuardedStorage: Anchored %p to treetop = %p\n", node, anchorTreeTop); } } } comp->getBitVectorPool().release(unAnchorableAloadiNodes); } if (cg->shouldBuildStructure() && (comp->getFlowGraph()->getStructure() != NULL)) { TR_Structure *rootStructure = TR_RegionAnalysis::getRegions(comp); comp->getFlowGraph()->setStructure(rootStructure); } phase->reportPhase(SetupForInstructionSelectionPhase); // Dump preIR if (comp->getOption(TR_TraceRegisterPressureDetails) && !comp->getOption(TR_DisableRegisterPressureSimulation)) { traceMsg(comp, " { Post optimization register pressure simulation\n"); TR_BitVector emptyBitVector; vcount_t vc = comp->incVisitCount(); cg->initializeRegisterPressureSimulator(); for (TR::Block *block = comp->getStartBlock(); block; block = block->getNextExtendedBlock()) { TR_LinkHead<TR_RegisterCandidate> emptyCandidateList; TR::CodeGenerator::TR_RegisterPressureState state(NULL, 0, emptyBitVector, emptyBitVector, &emptyCandidateList, cg->getNumberOfGlobalGPRs(), cg->getNumberOfGlobalFPRs(), cg->getNumberOfGlobalVRFs(), vc); TR::CodeGenerator::TR_RegisterPressureSummary summary(state._gprPressure, state._fprPressure, state._vrfPressure); cg->simulateBlockEvaluation(block, &state, &summary); } traceMsg(comp, " }\n"); } TR::LexicalMemProfiler mp(phase->getName(), comp->phaseMemProfiler()); LexicalTimer pt(phase->getName(), comp->phaseTimer()); cg->setUpForInstructionSelection(); }