void TR_Latestness::analyzeTreeTopsInBlockStructure(TR_BlockStructure *blockStructure) { TR::Block *block = blockStructure->getBlock(); TR::TreeTop *currentTree = block->getExit(); TR::TreeTop *entryTree = block->getEntry(); /////copyFromInto(_regularInfo, _outSetInfo[blockStructure->getNumber()]); bool notSeenTreeWithChecks = true; _containsExceptionTreeTop = false; while (!(currentTree == entryTree)) { if (notSeenTreeWithChecks) { bool currentTreeHasChecks = treeHasChecks(currentTree); if (currentTreeHasChecks) { notSeenTreeWithChecks = false; _containsExceptionTreeTop = true; /////compose(_regularInfo, _exceptionInfo); /////compose(_outSetInfo[blockStructure->getNumber()], _exceptionInfo); } } else break; if (!(currentTree == entryTree)) currentTree = currentTree->getPrevTreeTop(); } }
void TR_ReachingDefinitions::initializeGenAndKillSetInfo() { // For each block in the CFG build the gen and kill set for this analysis. // Go in treetop order, which guarantees that we see the correct (i.e. first) // evaluation point for each node. // TR::Block *block; int32_t blockNum = 0; bool seenException = false; TR_BitVector defsKilled(getNumberOfBits(), trMemory()->currentStackRegion()); comp()->incVisitCount(); for (TR::TreeTop *treeTop = comp()->getStartTree(); treeTop; treeTop = treeTop->getNextTreeTop()) { TR::Node *node = treeTop->getNode(); if (node->getOpCodeValue() == TR::BBStart) { block = node->getBlock(); blockNum = block->getNumber(); seenException = false; if (traceRD()) traceMsg(comp(), "\nNow generating gen and kill information for block_%d\n", blockNum); continue; } #if DEBUG if (node->getOpCodeValue() == TR::BBEnd && traceRD()) { traceMsg(comp(), " Block %d:\n", blockNum); traceMsg(comp(), " Gen set "); if (_regularGenSetInfo[blockNum]) _regularGenSetInfo[blockNum]->print(comp()); else traceMsg(comp(), "{}"); traceMsg(comp(), "\n Kill set "); if (_regularKillSetInfo[blockNum]) _regularKillSetInfo[blockNum]->print(comp()); else traceMsg(comp(), "{}"); traceMsg(comp(), "\n Exception Gen set "); if (_exceptionGenSetInfo[blockNum]) _exceptionGenSetInfo[blockNum]->print(comp()); else traceMsg(comp(), "{}"); traceMsg(comp(), "\n Exception Kill set "); if (_exceptionKillSetInfo[blockNum]) _exceptionKillSetInfo[blockNum]->print(comp()); else traceMsg(comp(), "{}"); continue; } #endif initializeGenAndKillSetInfoForNode(node, defsKilled, seenException, blockNum, NULL); if (!seenException && treeHasChecks(treeTop)) seenException = true; } }
int32_t TR_AsyncCheckInsertion::insertReturnAsyncChecks(TR::Optimization *opt, const char *counterPrefix) { TR::Compilation * const comp = opt->comp(); if (opt->trace()) traceMsg(comp, "Inserting return asyncchecks (%s)\n", counterPrefix); int numAsyncChecksInserted = 0; for (TR::TreeTop *treeTop = comp->getStartTree(); treeTop; /* nothing */ ) { TR::Block *block = treeTop->getNode()->getBlock(); if (block->getLastRealTreeTop()->getNode()->getOpCode().isReturn() && performTransformation(comp, "%sInserting return asynccheck (%s) in block_%d\n", opt->optDetailString(), counterPrefix, block->getNumber())) { insertAsyncCheck(block, comp, counterPrefix); numAsyncChecksInserted++; } treeTop = block->getExit()->getNextRealTreeTop(); } return numAsyncChecksInserted; }
static void resetBlockVisitFlags(TR::Compilation *comp) { for (TR::Block *block = comp->getStartBlock(); block != NULL; block = block->getNextBlock()) { block->setHasBeenVisited(false); } }
// Process the structure recursively // int32_t TR_ExpressionsSimplification::perform(TR_Structure * str) { if (trace()) traceMsg(comp(), "Analyzing root Structure : %p\n", str); TR_RegionStructure *region; // Only regions can be simplified // if (!(region = str->asRegion())) return 0; TR_RegionStructure::Cursor it(*region); for (TR_StructureSubGraphNode *node = it.getCurrent(); node != 0; node = it.getNext()) { // Too strict /* if ((node->getPredecessors().size() == 1)) { TR::CFGEdge *edge = node->getPredecessors().front(); TR_StructureSubGraphNode *pred = toStructureSubGraphNode(edge->getFrom()); TR_BlockStructure *b = pred->getStructure()->asBlock(); if (b && pred->getSuccessors().size() == 1)) perform(node->getStructure()); } */ perform(node->getStructure()); } // debug only // /* if (region->isNaturalLoop() && (region->getParent() && !region->getParent()->asRegion()->isCanonicalizedLoop())) { traceMsg(comp(), "Loop not canonicalized %x\n", region); } */ TR::Block *entryBlock = region->getEntryBlock(); if (region->isNaturalLoop() && !entryBlock->isCold() && (region->getParent() /* && region->getParent()->asRegion()->isCanonicalizedLoop() */)) { if (trace()) traceMsg(comp(), "Found candidate non cold loop %p for expression elimination\n", region); findAndSimplifyInvariantLoopExpressions(region); } return 1; // Need to specify the cost }
TR::TreeTop * OMR::TreeTop::getExtendedBlockExitTreeTop() { TR_ASSERT(self()->getNode()->getOpCodeValue() == TR::BBStart, "getExitTreeTop, is only valid for a bbStart"); TR::Block * b; TR::TreeTop * exitTT = self()->getNode()->getBlock()->getExit(), * nextTT; while ((nextTT = exitTT->getNextTreeTop()) && (b = nextTT->getNode()->getBlock(), b->isExtensionOfPreviousBlock())) exitTT = b->getExit(); return exitTT; }
void TR_ForwardReachabilityWithoutExceptionEdges::propagateInputs(blocknum_t blockNum, int32_t depth, blocknum_t *stack, blocknum_t *depth_map, TR_BitVector *closure) { TR::Block *block = getBlock(blockNum); for (auto edge = block->getPredecessors().begin(); edge != block->getPredecessors().end(); ++edge) { TR::Block *inputBlock = toBlock((*edge)->getFrom()); propagateOneInput(inputBlock->getNumber(), blockNum, depth, stack, depth_map, closure); } }
void TR_BackwardReachability::propagateInputs(blocknum_t blockNum, int32_t depth, blocknum_t *stack, blocknum_t *depth_map, TR_BitVector *closure) { TR::Block *block = getBlock(blockNum); TR_SuccessorIterator bi(block); for (TR::CFGEdge *edge = bi.getFirst(); edge != NULL; edge = bi.getNext()) { TR::Block *inputBlock = toBlock(edge->getTo()); propagateOneInput(inputBlock->getNumber(), blockNum, depth, stack, depth_map, closure); } }
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::removeUncertainBlocks(TR_RegionStructure* region, List<TR::Block> *candidateBlocksList) { // Examine the top region block first // TR::Block *entryBlock = _currentRegion->getEntryBlock(); ListIterator<TR::Block> blocks; blocks.set(candidateBlocksList); if (trace()) traceMsg(comp(), "Number of blocks %d, entry block number %d\n", candidateBlocksList->getSize(), entryBlock->getNumber()); for (TR::Block *block = blocks.getFirst(); block; block = blocks.getNext()) { TR::CFGNode *cfgNode = block; if (!(cfgNode->getExceptionSuccessors().empty()) || blockHasCalls(block, comp())) { if (trace()) traceMsg(comp(), "An exception can be thrown from block_%d. Removing all the blocks, since we cannot know the number of iterations.\n", block->getNumber()); candidateBlocksList->deleteAll(); break; } } TR_PostDominators postDominators(comp()); if (postDominators.isValid()) { postDominators.findControlDependents(); for (TR::Block *block = blocks.getFirst(); block; block = blocks.getNext()) { if (postDominators.dominates(block, entryBlock) == 0) { candidateBlocksList->remove(block); if (trace()) traceMsg(comp(), "Block_%d is not guaranteed to be executed at least once. Removing it from the list.\n", block->getNumber()); } } } else { if (trace()) traceMsg(comp(), "There is no post dominators information. Removing all the blocks.\n"); for (TR::Block *block = blocks.getFirst(); block; block = blocks.getNext()) { candidateBlocksList->remove(block); if (trace()) traceMsg(comp(), "Block_%d is removed from the list\n", block->getNumber()); } } }
void TR_LocalAnalysis::initializeBlocks(TR::Block *block, TR::BitVector &blocksSeen) { _info[block->getNumber()]._block = block; blocksSeen[block->getNumber()] = true; TR::Block *next; for (auto nextEdge = block->getSuccessors().begin(); nextEdge != block->getSuccessors().end(); ++nextEdge) { next = toBlock((*nextEdge)->getTo()); if (!blocksSeen.ValueAt(next->getNumber())) initializeBlocks(next, blocksSeen); } for (auto nextEdge = block->getExceptionSuccessors().begin(); nextEdge != block->getExceptionSuccessors().end(); ++nextEdge) { next = toBlock((*nextEdge)->getTo()); if (!blocksSeen.ValueAt(next->getNumber())) initializeBlocks(next, blocksSeen); } }
int32_t TR_LocalLiveRangeReduction::perform() { if (TR::Compiler->target.cpu.isZ()) return false; TR::TreeTop * exitTT, * nextTT; TR::Block *b; TR::TreeTop * tt; //calculate number of TreeTops in each bb (or extended bb) for (tt = comp()->getStartTree(); tt; tt = nextTT) { TR::StackMemoryRegion stackMemoryRegion(*trMemory()); TR::Node *node = tt->getNode(); b = node->getBlock(); exitTT = b->getExit(); _numTreeTops = b->getNumberOfRealTreeTops()+2; //include both BBStart/BBend //support for extended blocks while ((nextTT = exitTT->getNextTreeTop()) && (b = nextTT->getNode()->getBlock(), b->isExtensionOfPreviousBlock())) { _numTreeTops += b->getNumberOfRealTreeTops()+2; exitTT = b->getExit(); } _treesRefInfoArray = (TR_TreeRefInfo**)trMemory()->allocateStackMemory(_numTreeTops*sizeof(TR_TreeRefInfo*)); memset(_treesRefInfoArray, 0, _numTreeTops*sizeof(TR_TreeRefInfo*)); _movedTreesList.deleteAll(); _depPairList.deleteAll(); transformExtendedBlock(tt,exitTT->getNextTreeTop()); } if (trace()) traceMsg(comp(), "\nEnding LocalLiveRangeReducer\n"); return 2; }
void TR_ExpressionsSimplification::invalidateCandidates() { _visitCount = comp()->incVisitCount(); if (trace()) { traceMsg(comp(), "Checking which candidates may be invalidated\n"); ListIterator<TR::TreeTop> treeTops(_candidateTTs); for (TR::TreeTop *treeTop = treeTops.getFirst(); treeTop; treeTop = treeTops.getNext()) { traceMsg(comp(), " Candidate treetop: %p node: %p\n", treeTop, treeTop->getNode()); } } TR_ScratchList<TR::Block> blocksInLoop(trMemory()); _currentRegion->getBlocks(&blocksInLoop); ListIterator<TR::Block> blocks(&blocksInLoop); for (TR::Block *currentBlock = blocks.getFirst(); currentBlock; currentBlock = blocks.getNext()) { TR::TreeTop *tt = currentBlock->getEntry(); TR::TreeTop *exitTreeTop = currentBlock->getExit(); while (tt != exitTreeTop) { TR::Node *currentNode = tt->getNode(); if (trace()) traceMsg(comp(), "Looking at treeTop [%p]\n", currentNode); removeCandidate(currentNode, tt); tt = tt->getNextTreeTop(); } } removeUnsupportedCandidates(); }
TR::Block * TR_ExpressionsSimplification::findPredecessorBlock(TR::CFGNode *entryNode) { if (!(entryNode->getPredecessors().size() == 2)) return 0; TR::Block *block = 0; for (auto edge = entryNode->getPredecessors().begin(); edge != entryNode->getPredecessors().end(); ++edge) { if ((*edge)->getFrom()->getSuccessors().size() == 1) { block = toBlock((*edge)->getFrom()); if (block->getStructureOf()->isLoopInvariantBlock()) break; else block = 0; } } //traceMsg(comp(), "Commoned code will be put in block_%d\n", block->getNumber()); return block; }
void TR_ReachabilityAnalysis::perform(TR_BitVector *result) { TR::CFG *cfg = comp()->getFlowGraph(); int32_t numBlockIndexes = cfg->getNextNodeNumber(); int32_t numBlocks = cfg->getNumberOfNodes(); _blocks = cfg->createArrayOfBlocks(); blocknum_t *stack = (blocknum_t*)comp()->trMemory()->allocateStackMemory(numBlockIndexes * sizeof(stack[0])); blocknum_t *depthMap = (blocknum_t*)comp()->trMemory()->allocateStackMemory(numBlockIndexes * sizeof(depthMap[0])); memset(depthMap, 0, numBlockIndexes * sizeof(depthMap[0])); bool trace = comp()->getOption(TR_TraceReachability); if (trace) traceMsg(comp(), "BEGIN REACHABILITY: %d blocks\n", numBlocks); for (TR::Block *block = comp()->getStartBlock(); block; block = block->getNextBlock()) { blocknum_t blockNum = block->getNumber(); if (trace) traceMsg(comp(), "Visit block_%d\n", blockNum); if (depthMap[blockNum] == 0) traverse(blockNum, 0, stack, depthMap, result); else traceMsg(comp(), " depth is already %d; skip\n", depthMap[blockNum]); } if (comp()->getOption(TR_TraceReachability)) { traceMsg(comp(), "END REACHABILITY. Result:\n"); result->print(comp(), comp()->getOutFile()); traceMsg(comp(), "\n"); } }
void TR_ExpressionsSimplification::tranformStoreMotionCandidate(TR::TreeTop *treeTop, bool *isPreheaderBlockInvalid) { TR::Node *node = treeTop->getNode(); TR_ASSERT(node->getOpCode().isStore() && !node->getSymbol()->isStatic() && !node->getSymbol()->holdsMonitoredObject(), "node %p was expected to be a non-static non-monitored object store and was not.", node); // this candidate should be valid, either direct or indirect if (trace()) comp()->getDebug()->print(comp()->getOutFile(), node, 0, true); TR::Block *entryBlock = _currentRegion->getEntryBlock(); TR::Block *preheaderBlock = findPredecessorBlock(entryBlock); if (!preheaderBlock) { if (trace()) traceMsg(comp(), "Fail to find a place to put the hoist code in\n"); *isPreheaderBlockInvalid = true; return; } // Earlier post-dominance test ensures that the loop is executed as least once, or is canonicalized. // but to be safe we still perform on canonicalized loops only. if (_currentRegion->isCanonicalizedLoop()) // make sure that the loop is canonicalized, in which case the preheader is { // executed in its first iteration and is protected. if (performTransformation(comp(), "%sMove out loop-invariant store [%p] to block_%d\n", OPT_DETAILS, node, preheaderBlock->getNumber())) { TR::Node *newNode = node->duplicateTree(); transformNode(newNode, preheaderBlock); TR::TransformUtil::removeTree(comp(), treeTop); } } else { if (trace()) traceMsg(comp(), "No canonicalized loop for this candidate\n"); } }
static void moveBlockAfterDest(TR::CFG *cfg, TR::Block *toMove, TR::Block *dest) { TR::Compilation *comp = TR::comp(); // Step1 splice out toMove TR::Block *toMovePrev = toMove->getPrevBlock(); TR::Block *toMoveSucc = toMove->getNextBlock(); toMovePrev->getExit()->join(toMoveSucc->getEntry()); // Step 2 splice toMove in after dest TR::Block *destNext = dest->getNextBlock(); dest->getExit()->join(toMove->getEntry()); toMove->getExit()->join(destNext->getEntry()); cfg->addEdge(toMove, destNext); cfg->addEdge(dest, toMove); cfg->removeEdge(dest, destNext); cfg->addEdge(toMovePrev, toMoveSucc); cfg->removeEdge(toMovePrev, toMove); cfg->removeEdge(toMove, toMoveSucc); }
/** * Search for direct loads in the taken side of a guard * * @param firstBlock The guard's branch destination * @param coldPathLoads BitVector of symbol reference numbers for any direct loads seen until the merge back to mainline */ static void collectColdPathLoads(TR::Block* firstBlock, TR_BitVector &coldPathLoads) { TR_Stack<TR::Block*> blocksToCheck(TR::comp()->trMemory(), 8, false, stackAlloc); blocksToCheck.push(firstBlock); TR::NodeChecklist checklist(TR::comp()); coldPathLoads.empty(); while (!blocksToCheck.isEmpty()) { TR::Block *block = blocksToCheck.pop(); for (TR::TreeTop *tt = block->getFirstRealTreeTop(); tt->getNode()->getOpCodeValue() != TR::BBEnd; tt = tt->getNextTreeTop()) collectDirectLoads(tt->getNode(), coldPathLoads, checklist); // Search for any successors that have not merged with the mainline for (auto itr = block->getSuccessors().begin(), end = block->getSuccessors().end(); itr != end; ++itr) { TR::Block *dest = (*itr)->getTo()->asBlock(); if (dest != TR::comp()->getFlowGraph()->getEnd() && dest->getPredecessors().size() == 1) blocksToCheck.push(dest); } } }
int32_t TR_CatchBlockRemover::perform() { TR::CFG *cfg = comp()->getFlowGraph(); if (cfg == NULL) { if (trace()) traceMsg(comp(), "Can't do Catch Block Removal, no CFG\n"); return 0; } if (trace()) traceMsg(comp(), "Starting Catch Block Removal\n"); bool thereMayBeRemovableCatchBlocks = false; { TR::StackMemoryRegion stackMemoryRegion(*trMemory()); TR::Block *block; ListIterator<TR::CFGEdge> edgeIterator; // Go through all blocks that have exception successors and see if any of them // are not reached. Mark each of these edges with a visit count so they can // be identified later. // vcount_t visitCount = comp()->incOrResetVisitCount(); TR::CFGNode *cfgNode; for (cfgNode = cfg->getFirstNode(); cfgNode; cfgNode = cfgNode->getNext()) { if (cfgNode->getExceptionSuccessors().empty()) continue; block = toBlock(cfgNode); uint32_t reachedExceptions = 0; TR::TreeTop *treeTop; for (treeTop = block->getEntry(); treeTop != block->getExit(); treeTop = treeTop->getNextTreeTop()) { reachedExceptions |= treeTop->getNode()->exceptionsRaised(); if (treeTop->getNode()->getOpCodeValue() == TR::monexitfence) // for live monitor metadata reachedExceptions |= TR::Block::CanCatchMonitorExit; } if (reachedExceptions & TR::Block::CanCatchUserThrows) continue; for (auto edge = block->getExceptionSuccessors().begin(); edge != block->getExceptionSuccessors().end();) { TR::CFGEdge * current = *(edge++); TR::Block *catchBlock = toBlock(current->getTo()); if (catchBlock->isOSRCodeBlock() || catchBlock->isOSRCatchBlock()) continue; if (!reachedExceptions && performTransformation(comp(), "%sRemove redundant exception edge from block_%d at [%p] to catch block_%d at [%p]\n", optDetailString(), block->getNumber(), block, catchBlock->getNumber(), catchBlock)) { cfg->removeEdge(block, catchBlock); thereMayBeRemovableCatchBlocks = true; } else { if (!catchBlock->canCatchExceptions(reachedExceptions)) { current->setVisitCount(visitCount); thereMayBeRemovableCatchBlocks = true; } } } } bool edgesRemoved = false; // Now look to see if there are any catch blocks for which all exception // predecessors have the visit count set. If so, the block is unreachable and // can be removed. // If only some of the exception predecessors are marked, these edges are // left in place to identify the try/catch structure properly. // while (thereMayBeRemovableCatchBlocks) { thereMayBeRemovableCatchBlocks = false; for (cfgNode = cfg->getFirstNode(); cfgNode; cfgNode = cfgNode->getNext()) { if (cfgNode->getExceptionPredecessors().empty()) continue; auto edgeIt = cfgNode->getExceptionPredecessors().begin(); for (; edgeIt != cfgNode->getExceptionPredecessors().end(); ++edgeIt) { if ((*edgeIt)->getVisitCount() != visitCount) break; } if (edgeIt == cfgNode->getExceptionPredecessors().end() && performTransformation(comp(), "%sRemove redundant catch block_%d at [%p]\n", optDetailString(), cfgNode->getNumber(), cfgNode)) { while (!cfgNode->getExceptionPredecessors().empty()) { cfg->removeEdge(cfgNode->getExceptionPredecessors().front()); } edgesRemoved = true; thereMayBeRemovableCatchBlocks = true; } } } // Any transformations invalidate use/def and value number information // if (edgesRemoved) { optimizer()->setUseDefInfo(NULL); optimizer()->setValueNumberInfo(NULL); requestOpt(OMR::treeSimplification, true); } } // scope of the stack memory region if (trace()) traceMsg(comp(), "\nEnding Catch Block Removal\n"); return 1; // actual cost }
TR_GlobalRegisterNumber OMR::X86::I386::CodeGenerator::pickRegister( TR_RegisterCandidate *rc, TR::Block **allBlocks, TR_BitVector &availableRegisters, TR_GlobalRegisterNumber &highRegisterNumber, TR_LinkHead<TR_RegisterCandidate> *candidates) { if (!self()->comp()->getOption(TR_DisableRegisterPressureSimulation)) { if (self()->comp()->getOption(TR_AssignEveryGlobalRegister)) { // This is not really necessary except for testing purposes. // Conceptually, the common pickRegister code should be free to make // its choices based only on performance considerations, and shouldn't // need to worry about correctness. When SupportsVMThreadGRA is not set, // it is incorrect to choose the VMThread register. Therefore we mask // it out here. // // Having said that, the common code *does* already mask out the // VMThread register for convenience, so under normal circumstances, // this code is redundant. It is only necessary when // TR_AssignEveryGlobalRegister is set. // availableRegisters -= *self()->getGlobalRegisters(TR_vmThreadSpill, self()->comp()->getMethodSymbol()->getLinkageConvention()); } return OMR::CodeGenerator::pickRegister(rc, allBlocks, availableRegisters, highRegisterNumber, candidates); } if ((rc->getSymbol()->getDataType() == TR::Float) || (rc->getSymbol()->getDataType() == TR::Double)) { if (availableRegisters.get(7)) return 7; if (availableRegisters.get(8)) return 8; if (availableRegisters.get(9)) return 9; if (availableRegisters.get(10)) return 10; if (availableRegisters.get(11)) return 11; if (availableRegisters.get(12)) return 12; return -1; } if (!_assignedGlobalRegisters) _assignedGlobalRegisters = new (self()->trStackMemory()) TR_BitVector(self()->comp()->getSymRefCount(), self()->trMemory(), stackAlloc, growable); if (availableRegisters.get(5)) return 5; // esi if (availableRegisters.get(2)) return 2; // ecx static char *dontUseEBXasGPR = feGetEnv("dontUseEBXasGPR"); if (!dontUseEBXasGPR && availableRegisters.get(1)) return 1; #ifdef J9_PROJECT_SPECIFIC TR::RecognizedMethod rm = self()->comp()->getMethodSymbol()->getRecognizedMethod(); if (rm == TR::java_util_HashtableHashEnumerator_hasMoreElements) { if (availableRegisters.get(4)) return 4; // edi if (availableRegisters.get(3)) return 3; // edx } else #endif { int32_t numExtraRegs = 0; int32_t maxRegisterPressure = 0; vcount_t visitCount = self()->comp()->incVisitCount(); TR_BitVectorIterator bvi(rc->getBlocksLiveOnEntry()); int32_t maxFrequency = 0; while (bvi.hasMoreElements()) { int32_t liveBlockNum = bvi.getNextElement(); TR::Block *block = allBlocks[liveBlockNum]; if (block->getFrequency() > maxFrequency) maxFrequency = block->getFrequency(); } int32_t maxStaticFrequency = 0; if (maxFrequency == 0) { bvi.setBitVector(rc->getBlocksLiveOnEntry()); while (bvi.hasMoreElements()) { int32_t liveBlockNum = bvi.getNextElement(); TR::Block *block = allBlocks[liveBlockNum]; TR_BlockStructure *blockStructure = block->getStructureOf(); int32_t blockWeight = 1; if (blockStructure && !block->isCold()) { blockStructure->calculateFrequencyOfExecution(&blockWeight); if (blockWeight > maxStaticFrequency) maxStaticFrequency = blockWeight; } } } bool assigningEDX = false; if (!availableRegisters.get(4) && availableRegisters.get(3)) assigningEDX = true; bool vmThreadUsed = false; bvi.setBitVector(rc->getBlocksLiveOnEntry()); while (bvi.hasMoreElements()) { int32_t liveBlockNum = bvi.getNextElement(); TR::Block *block = allBlocks[liveBlockNum]; _assignedGlobalRegisters->empty(); int32_t numAssignedGlobalRegs = 0; TR_RegisterCandidate *prev; for (prev = candidates->getFirst(); prev; prev = prev->getNext()) { bool gprCandidate = true; if ((prev->getSymbol()->getDataType() == TR::Float) || (prev->getSymbol()->getDataType() == TR::Double)) gprCandidate = false; if (gprCandidate && prev->getBlocksLiveOnEntry().get(liveBlockNum)) { numAssignedGlobalRegs++; if (prev->getDataType() == TR::Int64) numAssignedGlobalRegs++; _assignedGlobalRegisters->set(prev->getSymbolReference()->getReferenceNumber()); } } maxRegisterPressure = self()->estimateRegisterPressure(block, visitCount, maxStaticFrequency, maxFrequency, vmThreadUsed, numAssignedGlobalRegs, _assignedGlobalRegisters, rc->getSymbolReference(), assigningEDX); if (maxRegisterPressure >= self()->getMaximumNumbersOfAssignableGPRs()) break; } // Determine if we can spare any extra registers for this candidate without spilling // in any hot (critical) blocks // if (maxRegisterPressure < self()->getMaximumNumbersOfAssignableGPRs()) numExtraRegs = self()->getMaximumNumbersOfAssignableGPRs() - maxRegisterPressure; //dumpOptDetails("For global register candidate %d reg pressure is %d maxRegs %d numExtraRegs %d\n", rc->getSymbolReference()->getReferenceNumber(), maxRegisterPressure, comp()->cg()->getMaximumNumbersOfAssignableGPRs(), numExtraRegs); if (numExtraRegs > 0) { if (availableRegisters.get(4)) return 4; // edi if (availableRegisters.get(3)) return 3; // edx } } return -1; // -1 ==> don't use a global register }
int32_t TR::DeadTreesElimination::process(TR::TreeTop *startTree, TR::TreeTop *endTree) { TR::StackMemoryRegion stackRegion(*comp()->trMemory()); LongestPathMap longestPaths(std::less<TR::Node*>(), stackRegion); typedef TR::typed_allocator<CRAnchor, TR::Region&> CRAnchorAlloc; typedef TR::forward_list<CRAnchor, CRAnchorAlloc> CRAnchorList; CRAnchorList anchors(stackRegion); vcount_t visitCount = comp()->incOrResetVisitCount(); TR::TreeTop *treeTop; for (treeTop = startTree; (treeTop != endTree); treeTop = treeTop->getNextTreeTop()) treeTop->getNode()->initializeFutureUseCounts(visitCount); TR::Block *block = NULL; bool delayedRegStoresBeforeThisPass = _delayedRegStores; // Update visitCount as they are used in this optimization and need to be visitCount = comp()->incOrResetVisitCount(); for (TR::TreeTopIterator iter(startTree, comp()); iter != endTree; ++iter) { TR::Node *node = iter.currentTree()->getNode(); if (node->getOpCodeValue() == TR::BBStart) { block = node->getBlock(); if (!block->isExtensionOfPreviousBlock()) longestPaths.clear(); } int vcountLimit = MAX_VCOUNT - 3; if (comp()->getVisitCount() > vcountLimit) { dumpOptDetails(comp(), "%sVisit count %d exceeds limit %d; stopping\n", optDetailString(), comp()->getVisitCount(), vcountLimit); return 0; } // correct at all intermediate stages // if ((node->getOpCodeValue() != TR::treetop) && (!node->getOpCode().isAnchor() || (node->getFirstChild()->getReferenceCount() != 1)) && (!node->getOpCode().isStoreReg() || (node->getFirstChild()->getReferenceCount() != 1)) && (delayedRegStoresBeforeThisPass || (iter.currentTree() == block->getLastRealTreeTop()) || !node->getOpCode().isStoreReg() || (node->getVisitCount() == visitCount))) { if (node->getOpCode().isAnchor() && node->getFirstChild()->getOpCode().isLoadIndirect()) anchors.push_front(CRAnchor(iter.currentTree(), block)); TR::TransformUtil::recursivelySetNodeVisitCount(node, visitCount); continue; } if (node->getOpCode().isStoreReg()) _delayedRegStores = true; TR::Node *child = node->getFirstChild(); if (child->getOpCodeValue() == TR::PassThrough) { TR::Node *newChild = child->getFirstChild(); node->setAndIncChild(0, newChild); newChild->incFutureUseCount(); if (child->getReferenceCount() <= 1) optimizer()->prepareForNodeRemoval(child); child->recursivelyDecReferenceCount(); recursivelyDecFutureUseCount(child); child = newChild; } bool treeTopCanBeEliminated = false; // If the treetop child has been seen before then it must be anchored // somewhere above already; so we don't need the treetop to be anchoring // this node (as the computation is already done at the first reference to // the node). // if (visitCount == child->getVisitCount()) { treeTopCanBeEliminated = true; } else { TR::ILOpCode &childOpCode = child->getOpCode(); TR::ILOpCodes opCodeValue = childOpCode.getOpCodeValue(); bool seenConditionalBranch = false; bool callWithNoSideEffects = child->getOpCode().isCall() && child->getSymbolReference()->getSymbol()->isResolvedMethod() && child->getSymbolReference()->getSymbol()->castToResolvedMethodSymbol()->isSideEffectFree(); if (callWithNoSideEffects) { treeTopCanBeEliminated = true; } else if (!((childOpCode.isCall() && !callWithNoSideEffects) || childOpCode.isStore() || ((opCodeValue == TR::New || opCodeValue == TR::anewarray || opCodeValue == TR::newarray) && child->getReferenceCount() > 1) || opCodeValue == TR::multianewarray || opCodeValue == TR::MergeNew || opCodeValue == TR::checkcast || opCodeValue == TR::Prefetch || opCodeValue == TR::iu2l || ((childOpCode.isDiv() || childOpCode.isRem()) && child->getNumChildren() == 3))) { // Perform the rather complex check to see whether its safe // to disconnect the child node from the treetop // bool safeToReplaceNode = false; if (child->getReferenceCount() == 1) { safeToReplaceNode = true; #ifdef J9_PROJECT_SPECIFIC if (child->getOpCode().isPackedExponentiation()) { // pdexp has a possible message side effect in truncating or no significant digits left cases safeToReplaceNode = false; } #endif if (opCodeValue == TR::loadaddr) treeTopCanBeEliminated = true; } else if (!_cannotBeEliminated) { safeToReplaceNode = isSafeToReplaceNode( child, iter.currentTree(), &seenConditionalBranch, visitCount, comp(), &_targetTrees, _cannotBeEliminated, longestPaths); } if (safeToReplaceNode) { if (childOpCode.hasSymbolReference()) { TR::SymbolReference *symRef = child->getSymbolReference(); if (symRef->getSymbol()->isAuto() || symRef->getSymbol()->isParm()) treeTopCanBeEliminated = true; else { if (childOpCode.isLoad() || (opCodeValue == TR::loadaddr) || (opCodeValue == TR::instanceof) || (((opCodeValue == TR::New) || (opCodeValue == TR::anewarray || opCodeValue == TR::newarray)) && ///child->getFirstChild()->isNonNegative())) child->markedAllocationCanBeRemoved())) // opCodeValue == TR::multianewarray || // opCodeValue == TR::MergeNew) treeTopCanBeEliminated = true; } } else treeTopCanBeEliminated = true; } } // Fix for the case when a float to non-float conversion node swings // down past a branch on IA32; this would cause a FP value to be commoned // across a branch where there was none originally; this causes pblms // as a value is left on the stack. // if (treeTopCanBeEliminated && seenConditionalBranch) { if (!cg()->getSupportsJavaFloatSemantics()) { if (child->getOpCode().isConversion() || child->getOpCode().isBooleanCompare()) { if (child->getFirstChild()->getOpCode().isFloatingPoint() && !child->getOpCode().isFloatingPoint()) treeTopCanBeEliminated = false; } } } if (treeTopCanBeEliminated) { TR::NodeChecklist visited(comp()); bool containsFloatingPoint = false; for (int32_t i = 0; i < child->getNumChildren(); ++i) { // Anchor nodes with reference count > 1 // bool highGlobalIndex = false; if (fixUpTree(child->getChild(i), iter.currentTree(), visited, highGlobalIndex, self(), visitCount)) containsFloatingPoint = true; if (highGlobalIndex) { dumpOptDetails(comp(), "%sGlobal index limit exceeded; stopping\n", optDetailString()); return 0; } } if (seenConditionalBranch && containsFloatingPoint) { if (!cg()->getSupportsJavaFloatSemantics()) treeTopCanBeEliminated = false; } } } // Update visitCount as they are used in this optimization and need to be // correct at all intermediate stages // if (!treeTopCanBeEliminated) TR::TransformUtil::recursivelySetNodeVisitCount(node, visitCount); if (treeTopCanBeEliminated) { TR::TreeTop *prevTree = iter.currentTree()->getPrevTreeTop(); TR::TreeTop *nextTree = iter.currentTree()->getNextTreeTop(); if (!node->getOpCode().isStoreReg() || (node->getFirstChild()->getReferenceCount() == 1)) { // Actually going to remove the treetop now // if (performTransformation(comp(), "%sRemove tree : [" POINTER_PRINTF_FORMAT "] ([" POINTER_PRINTF_FORMAT "] = %s)\n", optDetailString(), node, node->getFirstChild(), node->getFirstChild()->getOpCode().getName())) { prevTree->join(nextTree); optimizer()->prepareForNodeRemoval(node); ///child->recursivelyDecReferenceCount(); node->recursivelyDecReferenceCount(); recursivelyDecFutureUseCount(child); iter.jumpTo(prevTree); if (child->getReferenceCount() == 1) requestOpt(OMR::treeSimplification, true, block); if (nextTree->getNode()->getOpCodeValue() == TR::Goto && prevTree->getNode()->getOpCodeValue() == TR::BBStart && !prevTree->getNode()->getBlock()->isExtensionOfPreviousBlock()) { requestOpt( OMR::redundantGotoElimination, prevTree->getNode()->getBlock()); } } } else { if (performTransformation(comp(), "%sMove tree : [" POINTER_PRINTF_FORMAT "]([" POINTER_PRINTF_FORMAT "] = %s) to end of block\n", optDetailString(), node, node->getFirstChild(), node->getFirstChild()->getOpCode().getName())) { prevTree->join(nextTree); node->setVisitCount(visitCount); TR::TreeTop *lastTree = findLastTreetop(block, prevTree); TR::TreeTop *prevLastTree = lastTree->getPrevTreeTop(); TR::TreeTop *cursorTreeTop = nextTree; while (cursorTreeTop != lastTree) { if (cursorTreeTop->getNode()->getOpCode().isStoreReg() && (cursorTreeTop->getNode()->getGlobalRegisterNumber() == iter.currentTree()->getNode()->getGlobalRegisterNumber())) { lastTree = cursorTreeTop; prevLastTree = lastTree->getPrevTreeTop(); break; } cursorTreeTop = cursorTreeTop->getNextTreeTop(); } if (lastTree->getNode()->getOpCodeValue() == TR::BBStart) { prevLastTree = lastTree; lastTree = block->getExit(); } TR::Node *lastNode = lastTree->getNode(); TR::Node *prevLastNode = prevLastTree->getNode(); if (lastNode->getOpCode().isIf() && !lastNode->getOpCode().isCompBranchOnly() && prevLastNode->getOpCode().isStoreReg() && ((prevLastNode->getFirstChild() == lastNode->getFirstChild()) || (prevLastNode->getFirstChild() == lastNode->getSecondChild()))) { lastTree = prevLastTree; prevLastTree = lastTree->getPrevTreeTop(); } prevLastTree->join(iter.currentTree()); iter.currentTree()->join(lastTree); iter.jumpTo(prevTree); requestOpt(OMR::treeSimplification, true, block); } } } } for (auto it = anchors.begin(); it != anchors.end(); ++it) { TR::Node *anchor = it->tree->getNode(); TR::Node *load = anchor->getChild(0); if (load->getReferenceCount() > 1) continue; // We can eliminate the indirect load immediately, but for the moment the // subtree providing the base object has to be anchored. TR::Node *heapBase = anchor->getChild(1); TR::Node::recreate(anchor, TR::treetop); anchor->setAndIncChild(0, load->getChild(0)); anchor->setChild(1, NULL); anchor->setNumChildren(1); if (!heapBase->getOpCode().isLoadConst()) { it->tree->insertAfter( TR::TreeTop::create( comp(), TR::Node::create(heapBase, TR::treetop, 1, heapBase))); } load->recursivelyDecReferenceCount(); heapBase->recursivelyDecReferenceCount(); // A later pass of dead trees can likely move (or even remove) the base // object expression. requestOpt(OMR::deadTreesElimination, true, it->block); } return 1; // actual cost }
void TR::DeadTreesElimination::prePerformOnBlocks() { _cannotBeEliminated = false; _delayedRegStores = false; _targetTrees.deleteAll(); // Walk through all the blocks to remove trivial dead trees of the form // treetop // => node // The problem with these trees is in the scenario where the earlier use // of 'node' is also dead. However, our analysis won't find that because // the reference count is > 1. vcount_t visitCount = comp()->incOrResetVisitCount(); for (TR::TreeTop *tt = comp()->getStartTree(); tt != 0; tt = tt->getNextTreeTop()) { bool removed = false; TR::Node *node = tt->getNode(); if (node->getOpCodeValue() == TR::treetop && node->getFirstChild()->getVisitCount() == visitCount && performTransformation(comp(), "%sRemove trivial dead tree: %p\n", optDetailString(), node)) { TR::TransformUtil::removeTree(comp(), tt); removed = true; } else { if (node->getOpCode().isCheck() && node->getFirstChild()->getOpCode().isCall() && node->getFirstChild()->getReferenceCount() == 1 && node->getFirstChild()->getSymbolReference()->getSymbol()->isResolvedMethod() && node->getFirstChild()->getSymbolReference()->getSymbol()->castToResolvedMethodSymbol()->isSideEffectFree() && performTransformation(comp(), "%sRemove dead check of side-effect free call: %p\n", optDetailString(), node)) { TR::TransformUtil::removeTree(comp(), tt); removed = true; } } if (removed && tt->getNextTreeTop()->getNode()->getOpCodeValue() == TR::Goto && tt->getPrevTreeTop()->getNode()->getOpCodeValue() == TR::BBStart && !tt->getPrevTreeTop()->getNode()->getBlock()->isExtensionOfPreviousBlock()) { requestOpt(OMR::redundantGotoElimination, tt->getEnclosingBlock()); } if (node->getVisitCount() >= visitCount) continue; TR::TransformUtil::recursivelySetNodeVisitCount(tt->getNode(), visitCount); } // If the last use of an iRegLoad has been removed, then remove the node from // the BBStart and remove the corresponding dependency node from each of the block's // predecessors. // while (1) { bool glRegDepRemoved = false; for (TR::Block * b = comp()->getStartBlock(); b; b = b->getNextBlock()) { TR::TreeTop * startTT = b->getEntry(); TR::Node * startNode = startTT->getNode(); if (startNode->getNumChildren() > 0 && !debug("disableEliminationOfGlRegDeps")) { TR::Node * glRegDeps = startNode->getFirstChild(); TR_ASSERT(glRegDeps->getOpCodeValue() == TR::GlRegDeps, "expected TR::GlRegDeps"); for (int32_t i = glRegDeps->getNumChildren() - 1; i >= 0; --i) { TR::Node * dep = glRegDeps->getChild(i); if (dep->getReferenceCount() == 1 && (!dep->getOpCode().isFloatingPoint() || cg()->getSupportsJavaFloatSemantics()) && performTransformation(comp(), "%sRemove GlRegDep : %p\n", optDetailString(), glRegDeps->getChild(i))) { glRegDeps->removeChild(i); glRegDepRemoved = true; TR_GlobalRegisterNumber registerNum = dep->getGlobalRegisterNumber(); for (auto e = b->getPredecessors().begin(); e != b->getPredecessors().end(); ++e) { TR::Block * pred = toBlock((*e)->getFrom()); if (pred == comp()->getFlowGraph()->getStart()) continue; TR::Node * parent = pred->getLastRealTreeTop()->getNode(); if ( parent->getOpCode().isJumpWithMultipleTargets() && parent->getOpCode().hasBranchChildren()) { for (int32_t j = parent->getCaseIndexUpperBound() - 1; j > 0; --j) { TR::Node * caseNode = parent->getChild(j); TR_ASSERT(caseNode->getOpCode().isCase() || caseNode->getOpCodeValue() == TR::branch, "having problems navigating a switch"); if (caseNode->getBranchDestination() == startTT && caseNode->getNumChildren() > 0 && 0) // can't do this now that all glRegDeps are hung off the default branch removeGlRegDep(caseNode, registerNum, pred, this); } } else if (!parent->getOpCode().isReturn() && parent->getOpCodeValue() != TR::igoto && !( parent->getOpCode().isJumpWithMultipleTargets() && parent->getOpCode().hasBranchChildren()) && !(parent->getOpCodeValue()==TR::treetop && parent->getFirstChild()->getOpCode().isCall() && parent->getFirstChild()->getOpCode().isIndirect())) { if (pred->getNextBlock() == b) parent = pred->getExit()->getNode(); removeGlRegDep(parent, registerNum, pred, this); } } } } if (glRegDeps->getNumChildren() == 0) startNode->removeChild(0); } } if (!glRegDepRemoved) break; } }
bool TR_ExpressionsSimplification::tranformSummationReductionCandidate(TR::TreeTop *treeTop, LoopInfo *loopInfo, bool *isPreheaderBlockInvalid) { TR::Node *node = treeTop->getNode(); TR::Node *opNode = node->getFirstChild(); TR::Node *expNode = NULL; int32_t expChildNumber = 0; bool removeOnly = false; bool replaceWithNewNode = false; if (opNode->getOpCodeValue() == TR::iadd || opNode->getOpCodeValue() == TR::isub) { if (opNode->getSecondChild()->getOpCode().hasSymbolReference() && node->getSymbolReference() == opNode->getSecondChild()->getSymbolReference()) { expChildNumber = 0; expNode = opNode->getFirstChild(); } else { expChildNumber = 1; expNode = opNode->getSecondChild(); } expNode = iaddisubSimplifier(expNode, loopInfo); replaceWithNewNode = true; } else if (opNode->getOpCodeValue() == TR::ixor || opNode->getOpCodeValue() == TR::ineg) { expNode = ixorinegSimplifier(opNode, loopInfo, &removeOnly); } if (expNode) { if (trace()) comp()->getDebug()->print(comp()->getOutFile(), expNode, 0, true); TR::Block *entryBlock = _currentRegion->getEntryBlock(); TR::Block *preheaderBlock = findPredecessorBlock(entryBlock); if (!preheaderBlock) { if (trace()) traceMsg(comp(), "Fail to find a place to put the hoist code in\n"); *isPreheaderBlockInvalid = true; return true; } if (loopInfo->getNumIterations() > 0 || // make sure that the loop is going to be executed at least once _currentRegion->isCanonicalizedLoop()) // or that the loop is canonicalized, in which case the preheader is { // executed in its first iteration and is protected. if (performTransformation(comp(), "%sMove out loop-invariant node [%p] to block_%d\n", OPT_DETAILS, node, preheaderBlock->getNumber())) { if (!(removeOnly)) { TR::Node *newNode = node->duplicateTree(); if (replaceWithNewNode) newNode->getFirstChild()->setAndIncChild(expChildNumber, expNode); transformNode(newNode, preheaderBlock); } TR::TransformUtil::removeTree(comp(), treeTop); } } } return (expNode != NULL); }
void TR_ExpressionsSimplification::simplifyInvariantLoopExpressions(ListIterator<TR::Block> &blocks) { // Need to locate the induction variable of the loop // LoopInfo *loopInfo = findLoopInfo(_currentRegion); if (trace()) { if (!loopInfo) { traceMsg(comp(), "Accurate loop info is not found, cannot carry out summation reduction\n"); } else { traceMsg(comp(), "Accurate loop info has been found, will try to carry out summation reduction\n"); if (loopInfo->getBoundaryNode()) { traceMsg(comp(), "Variable iterations from node %p has not been handled\n",loopInfo->getBoundaryNode()); } else { traceMsg(comp(), "Natural Loop %p will run %d times\n", _currentRegion, loopInfo->getNumIterations()); } } } // Initialize the list of candidates // _candidateTTs = new (trStackMemory()) TR_ScratchList<TR::TreeTop>(trMemory()); for (TR::Block *currentBlock = blocks.getFirst(); currentBlock; currentBlock = blocks.getNext()) { if (trace()) traceMsg(comp(), "Analyzing block #%d, which must be executed once per iteration\n", currentBlock->getNumber()); // Scan through each node in the block // TR::TreeTop *tt = currentBlock->getEntry(); TR::TreeTop *exitTreeTop = currentBlock->getExit(); while (tt != exitTreeTop) { TR::Node *currentNode = tt->getNode(); if (trace()) traceMsg(comp(), "Analyzing tree top node %p\n", currentNode); if (loopInfo) { // requires loop info for the number of iterations setSummationReductionCandidates(currentNode, tt); } setStoreMotionCandidates(currentNode, tt); tt = tt->getNextTreeTop(); } } // New code: without using any UDI // walk through the trees in the loop // to invalidate the candidates // if (!_supportedExpressions) { _supportedExpressions = new (trStackMemory()) TR_BitVector(comp()->getNodeCount(), trMemory(), stackAlloc, growable); } invalidateCandidates(); ListIterator<TR::TreeTop> treeTops(_candidateTTs); for (TR::TreeTop *treeTop = treeTops.getFirst(); treeTop; treeTop = treeTops.getNext()) { if (trace()) traceMsg(comp(), "Candidate TreeTop: %p, Node:%p\n", treeTop, treeTop->getNode()); bool usedCandidate = false; bool isPreheaderBlockInvalid = false; if (loopInfo) { usedCandidate = tranformSummationReductionCandidate(treeTop, loopInfo, &isPreheaderBlockInvalid); } if (isPreheaderBlockInvalid) { break; } if (!usedCandidate) { tranformStoreMotionCandidate(treeTop, &isPreheaderBlockInvalid); } if (isPreheaderBlockInvalid) { break; } } }
TR_ExpressionsSimplification::LoopInfo* TR_ExpressionsSimplification::findLoopInfo(TR_RegionStructure* region) { ListIterator<TR::CFGEdge> exitEdges(®ion->getExitEdges()); if (region->getExitEdges().getSize() != 1) { if (trace()) traceMsg(comp(), "Region with more than 1 exit edges can't be handled\n"); return 0; } TR_StructureSubGraphNode* exitNode = toStructureSubGraphNode(exitEdges.getFirst()->getFrom()); if (!exitNode->getStructure()->asBlock()) { if (trace()) traceMsg(comp(), "The exit block can't be found\n"); return 0; } TR::Block *exitBlock = exitNode->getStructure()->asBlock()->getBlock(); TR::Node *lastTreeInExitBlock = exitBlock->getLastRealTreeTop()->getNode(); if (trace()) { traceMsg(comp(), "The exit block is %d\n", exitBlock->getNumber()); traceMsg(comp(), "The branch node is %p\n", lastTreeInExitBlock); } if (!lastTreeInExitBlock->getOpCode().isBranch()) { if (trace()) traceMsg(comp(), "The branch node couldn't be found\n"); return 0; } if (lastTreeInExitBlock->getNumChildren() < 2) { if (trace()) traceMsg(comp(), "The branch node has less than 2 children\n"); return 0; } TR::Node *firstChildOfLastTree = lastTreeInExitBlock->getFirstChild(); TR::Node *secondChildOfLastTree = lastTreeInExitBlock->getSecondChild(); if (!firstChildOfLastTree->getOpCode().hasSymbolReference()) { if (trace()) traceMsg(comp(), "The branch node's first child node %p - its opcode does not have a symbol reference\n", firstChildOfLastTree); return 0; } TR::SymbolReference *firstChildSymRef = firstChildOfLastTree->getSymbolReference(); if (trace()) traceMsg(comp(), "Symbol Reference: %p Symbol: %p\n", firstChildSymRef, firstChildSymRef->getSymbol()); // Locate the induction variable that matches with the exit node symbol // TR_InductionVariable *indVar = region->findMatchingIV(firstChildSymRef); if (!indVar) return 0; if (!indVar->getIncr()->asIntConst()) { if (trace()) traceMsg(comp(), "Increment is not a constant\n"); return 0; } int32_t increment = indVar->getIncr()->getLowInt(); _visitCount = comp()->incVisitCount(); bool indVarWrittenAndUsedUnexpectedly = false; if (firstChildOfLastTree->getReferenceCount() > 1) { TR::TreeTop *cursorTreeTopInExitBlock = exitBlock->getEntry(); TR::TreeTop *exitTreeTopInExitBlock = exitBlock->getExit(); bool loadSeen = false; while (cursorTreeTopInExitBlock != exitTreeTopInExitBlock) { TR::Node *cursorNode = cursorTreeTopInExitBlock->getNode(); if (checkForLoad(cursorNode, firstChildOfLastTree)) loadSeen = true; if (!cursorNode->getOpCode().isStore() && (cursorNode->getNumChildren() > 0)) cursorNode = cursorNode->getFirstChild(); if (cursorNode->getOpCode().isStore() && (cursorNode->getSymbolReference() == firstChildSymRef)) { indVarWrittenAndUsedUnexpectedly = true; if ((cursorNode->getFirstChild() == firstChildOfLastTree) || !loadSeen) indVarWrittenAndUsedUnexpectedly = false; else break; } cursorTreeTopInExitBlock = cursorTreeTopInExitBlock->getNextTreeTop(); } } if (indVarWrittenAndUsedUnexpectedly) { return 0; } int32_t lowerBound; int32_t upperBound = 0; TR::Node *bound = 0; bool equals = false; switch(lastTreeInExitBlock->getOpCodeValue()) { case TR::ificmplt: case TR::ificmpgt: equals = true; case TR::ificmple: case TR::ificmpge: if (!(indVar->getEntry() && indVar->getEntry()->asIntConst())) { if (trace()) traceMsg(comp(), "Entry value is not a constant\n"); return 0; } lowerBound = indVar->getEntry()->getLowInt(); if (secondChildOfLastTree->getOpCode().isLoadConst()) { upperBound = secondChildOfLastTree->getInt(); } else if (secondChildOfLastTree->getOpCode().isLoadVar()) { bound = secondChildOfLastTree; } else { if (trace()) traceMsg(comp(), "Second child is not a const or a load\n"); return 0; } return new (trStackMemory()) LoopInfo(bound, lowerBound, upperBound, increment, equals); default: if (trace()) traceMsg(comp(), "The condition has not been implemeted\n"); return 0; } return 0; }
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(); }
// This opt tries to reduce merge backs from cold code that are the result of inliner // gnerated nopable virtual guards // It looks for one basic pattern // // guard1 -> cold1 // BBEND // BBSTART // guard2 -> cold2 // if guard1 is the guard for a method which calls the method guard2 protects or cold1 is // a predecessor of cold2 (a situation commonly greated by virtual guard tail splitter) we // can transform the guards as follows when guard1 and guard2 a // guard1 -> cold1 // BBEND // BBSTART // guard2 -> cold1 // This is safe because there are no trees between the guards and calling the caller will // result in the call to the callee if we need to patch guard2. cold2 and its mergebacks // can then be eliminated // // In addition this opt will try to move guard2 up from the end of a block to the // start of the block. We can do this if guard2 is an HCR guard and there is no GC point // between BBSTART and guard2 since HCR is a stop-the-world event. // // Finally, there is a simple tail splitting step run before the analysis of a guard if we // detect that the taken side of the guard merges back in the next block - this happens // for some empty methods and is common for Object.<init> at the top of constructors. int32_t TR_VirtualGuardHeadMerger::perform() { static char *disableVGHeadMergerTailSplitting = feGetEnv("TR_DisableVGHeadMergerTailSplitting"); TR::CFG *cfg = comp()->getFlowGraph(); // Cache the loads for the outer guard's cold path TR_BitVector coldPathLoads(comp()->trMemory()->currentStackRegion()); TR_BitVector privArgSymRefs(comp()->trMemory()->currentStackRegion()); bool evaluatedColdPathLoads = false; for (TR::Block *block = optimizer()->getMethodSymbol()->getFirstTreeTop()->getNode()->getBlock(); block; block = block->getNextBlock()) { TR::Node *guard1 = block->getLastRealTreeTop()->getNode(); if (isMergeableGuard(guard1)) { if (trace()) traceMsg(comp(), "Found mergeable guard in block_%d\n", block->getNumber()); TR::Block *cold1 = guard1->getBranchDestination()->getEnclosingBlock(); // check for an immediate merge back from the cold block and // tail split one block if we can - we only handle splitting a block // ending in a fallthrough, a branch or a goto for now for simplicity if (!disableVGHeadMergerTailSplitting && (cold1->getSuccessors().size() == 1) && cold1->hasSuccessor(block->getNextBlock()) && cold1->getLastRealTreeTop()->getNode()->getOpCode().isGoto()) { // TODO handle moving code earlier in the block down below the guard // tail split if ((block->getNextBlock()->getSuccessors().size() == 1) || ((block->getNextBlock()->getSuccessors().size() == 2) && block->getNextBlock()->getLastRealTreeTop()->getNode()->getOpCode().isBranch()) && performTransformation(comp(), "%sCloning block_%d and placing clone after block_%d to reduce HCR guard nops\n", OPT_DETAILS, block->getNextBlock()->getNumber(), cold1->getNumber())) tailSplitBlock(block, cold1); } // guard motion is fairly complex but what we want to achieve around guard1 is a sequence // of relocated privarg blocks, followed by a sequence of runtime patchable guards going to // guard1's cold block, followed by a sequence of stop-the-world guards going to guard1's // cold block // // The following code is to setup the various insert points based on the following diagrams // of basic blocks: // // start: setup: end result after moving runtime guard' // | | +-------+ <-- privargIns // | | <-- privargIns | // +-------+ <-- runtimeIns +-------+ // | | | | Guard'| // | | V +-------+ <-- runtimeIns // +-------+ +-------+ | // | Guard | | Guard | V // +-------+ +-------+ <-- HCRIns +-------+ // | ===> | ===> | Guard | // V V +-------+ <-- HCRIns // +-------+ +-------+ | // | | | | V // | | | | +-------+ // // Note we always split the block - this may create an empty block but preserves the incoming // control flow we leave the rest to block extension to fix later block = block->split(block->getLastRealTreeTop(), cfg, true, false); TR::Block *privargIns = block->getPrevBlock(); TR::Block *runtimeIns = block->getPrevBlock(); TR::Block *HCRIns = block; // New outer guard so cold paths must be evaluated evaluatedColdPathLoads = false; // scan for candidate guards to merge with guard1 identified above for (TR::Block *nextBlock = block->getNextBlock(); nextBlock; nextBlock = nextBlock->getNextBlock()) { if (!(nextBlock->getPredecessors().size() == 1) || !nextBlock->hasPredecessor(block)) { break; } TR::TreeTop *guard2Tree = NULL; if (isMergeableGuard(nextBlock->getFirstRealTreeTop()->getNode())) { guard2Tree = nextBlock->getFirstRealTreeTop(); } else if (isMergeableGuard(nextBlock->getLastRealTreeTop()->getNode())) { guard2Tree = nextBlock->getLastRealTreeTop(); } else break; TR::Node *guard2 = guard2Tree->getNode(); TR::Block *guard2Block = nextBlock; // It is not possible to shift an OSR guard unless the destination is already an OSR point // as the necessary OSR state will not be available if (guard2->isOSRGuard() && !guard1->isOSRGuard()) break; TR::Block *insertPoint = isStopTheWorldGuard(guard2) ? HCRIns : runtimeIns; if (!safeToMoveGuard(insertPoint, guard2Tree, guard1->getBranchDestination(), privArgSymRefs)) break; // now we figure out if we can redirect guard2 to guard1's cold block // ie can we do the head merge TR::Block *cold2 = guard2->getBranchDestination()->getEnclosingBlock(); if (guard1->getInlinedSiteIndex() == guard2->getInlinedSiteIndex()) { if (trace()) traceMsg(comp(), " Guard1 [%p] is guarding the same call as Guard2 [%p] - proceeding with guard merging\n", guard1, guard2); } else if (guard2->getInlinedSiteIndex() > -1 && guard1->getInlinedSiteIndex() == TR::comp()->getInlinedCallSite(guard2->getInlinedSiteIndex())._byteCodeInfo.getCallerIndex()) { if (trace()) traceMsg(comp(), " Guard1 [%p] is the caller of Guard2 [%p] - proceeding with guard merging\n", guard1, guard2); } else if ((cold1->getSuccessors().size() == 1) && cold1->hasSuccessor(cold2)) { if (trace()) traceMsg(comp(), " Guard1 cold destination block_%d has guard2 cold destination block_%d as its only successor - proceeding with guard merging\n", cold1->getNumber(), cold2->getNumber()); } else { if (trace()) traceMsg(comp(), " Cold1 block_%d and cold2 block_%d of guard2 [%p] in unknown relationship - abandon the merge attempt\n", cold1->getNumber(), cold2->getNumber(), guard2); break; } // Runtime guards will shift their privargs, so it is necessary to check such a move is safe // This is possible if a privarg temp was recycled for the inner call site, with a prior use as an // argument for the outer call site. As the privargs for the inner call site must be evaluated before // both guards, this would result in the recycled temp holding the incorrect value if the guard is ever // taken. if (!isStopTheWorldGuard(guard2)) { if (!evaluatedColdPathLoads) { collectColdPathLoads(cold1, coldPathLoads); evaluatedColdPathLoads = true; } if (coldPathLoads.intersects(privArgSymRefs)) { if (trace()) traceMsg(comp(), " Recycled temp live in cold1 block_%d and used as privarg before guard2 [%p] - stop guard merging", cold1->getNumber(), guard2); break; } } if (!performTransformation(comp(), "%sRedirecting %s guard [%p] in block_%d to parent guard cold block_%d\n", OPT_DETAILS, isStopTheWorldGuard(guard2) ? "stop the world" : "runtime", guard2, guard2Block->getNumber(), cold1->getNumber())) continue; if (guard2->getBranchDestination() != guard1->getBranchDestination()) guard2Block->changeBranchDestination(guard1->getBranchDestination(), cfg); if (guard2Tree != guard2Block->getFirstRealTreeTop()) { cfg->setStructure(NULL); // We should leave code ahead of an HCR guard in place because: // 1, it might have side effect to runtime guards after it, moving it up might cause us to falsely merge // the subsequent runtime guards // 2, it might contain live monitor, moving it up above a guard can affect the monitor's live range if (!isStopTheWorldGuard(guard2)) { // the block created above guard2 contains only privarg treetops or monitor stores if // guard2 is a runtime-patchable guard and is safe to merge. We need to move the priv // args up to the runtime insert point and leave the monitor stores in place // It's safe to do so because there is no data dependency between the monitor store and // the priv arg store, because the priv arg store does not load the value from the temp // holding the monitored object // Split priv arg stores from monitor stores // Monitor store is generated for the caller of the method guard2 protects, so should appear before // priv arg stores for the method guard2 protects TR::Block *privargBlock = guard2Block; guard2Block = splitRuntimeGuardBlock(comp(), guard2Block, cfg); if (privargBlock != guard2Block) { if (trace()) traceMsg(comp(), " Moving privarg block_%d after block_%d\n", privargBlock->getNumber(), privargIns->getNumber()); moveBlockAfterDest(cfg, privargBlock, privargIns); if (HCRIns == privargIns) HCRIns = privargBlock; if (runtimeIns == privargIns) runtimeIns = privargBlock; privargIns = privargBlock; // refresh the insertPoint since it could be stale after the above updates insertPoint = runtimeIns; } } guard2Block = guard2Block->split(guard2Tree, cfg, true, false); if (trace()) traceMsg(comp(), " Created new block_%d to hold guard [%p] from block_%d\n", guard2Block->getNumber(), guard2, guard2Block->getNumber()); } if (insertPoint != guard2Block->getPrevBlock()) { TR::DebugCounter::incStaticDebugCounter(comp(), TR::DebugCounter::debugCounterName(comp(), "headMerger/%s_%s/(%s)", isStopTheWorldGuard(guard1) ? "stop the world" : "runtime", isStopTheWorldGuard(guard2) ? "stop the world" : "runtime", comp()->signature())); cfg->setStructure(NULL); block = nextBlock = guard2Block->getPrevBlock(); if (trace()) traceMsg(comp(), " Moving guard2 block block_%d after block_%d\n", guard2Block->getNumber(), insertPoint->getNumber()); moveBlockAfterDest(cfg, guard2Block, insertPoint); if (HCRIns == insertPoint) HCRIns = guard2Block; if (runtimeIns == insertPoint) runtimeIns = guard2Block; } else { block = guard2Block; } guard1 = guard2; } } } return 1; }
TR::TreeTop * OMR::Simplifier::simplifyExtendedBlock(TR::TreeTop * treeTop) { TR::Block * block = 0; _containingStructure = NULL; _blockRemoved = false; for (; treeTop; treeTop = treeTop->getNextTreeTop()) { TR::Node * node = treeTop->getNode(); TR_ASSERT(node->getOpCodeValue() == TR::BBStart, "Simplification, expected BBStart treetop"); TR::Block * b = node->getBlock(); if (block && !b->isExtensionOfPreviousBlock()) break; if (b->isOSRCodeBlock() || b->isOSRCatchBlock()) { b->setHasBeenVisited(); treeTop = b->getExit(); continue; } #ifdef DEBUG if (block != b) b->setHasBeenVisited(); #endif if (!block && _reassociate && comp()->getFlowGraph()->getStructure() != NULL // [99391] getStructureOf() only valid if structure isn't invalidated ) { // b is first block in the extended block TR_BlockStructure *blockStructure = b->getStructureOf(); if(blockStructure) { TR_Structure *parent = blockStructure->getParent(); while (parent) { TR_RegionStructure *region = parent->asRegion(); if (region->isNaturalLoop() /* || region->containsInternalCycles() */) { _containingStructure = region; break; } parent = parent->getParent(); } } } block = b; if (trace()) traceMsg(comp(), "simplifying block_%d\n", block->getNumber()); _performLowerTreeSimplifier=NULL; _performLowerTreeNode=NULL; simplify(block); if(_performLowerTreeSimplifier) { _performLowerTreeNode = postWalkLowerTreeSimplifier(_performLowerTreeSimplifier, _performLowerTreeNode, block, (TR::Simplifier *) this); _performLowerTreeSimplifier->setNode(_performLowerTreeNode); } // If the block itself was removed from the CFG during simplification, find // the next 'legitimate' block to be simplified // //if (comp()->getFlowGraph()->getRemovedNodes().find(block)) if(block->nodeIsRemoved()) { TR::TreeTop * tt = findNextLegalTreeTop(comp(), block); // in certain cases the removed block might be the last one we haven't // visited and therefore we won't be able to find a treetop to continue // in such cases we exit the loop // treeTop = tt ? tt->getPrevTreeTop() : 0; if (!treeTop) break; } else { treeTop = block->getExit(); } } // now remove any unreachable blocks // if (_blockRemoved) { // if the next block to be processed has been removed, // find the next valid block to process // if (treeTop) { TR::Block *b = treeTop->getNode()->getBlock(); //if (comp()->getFlowGraph()->getRemovedNodes().find(b)) if(b->nodeIsRemoved()) treeTop = findNextLegalTreeTop(comp(), b); } } return treeTop; }
// This function splits a single succeesor block following an guard and is used to // do the following transform // block - cold1 block - cold1 // \ / => | | // nextBlock nextBlock nextBlock' (called tailSplitBlock below) // | \ / // ... ... void TR_VirtualGuardHeadMerger::tailSplitBlock(TR::Block * block, TR::Block * cold1) { TR::CFG *cfg = comp()->getFlowGraph(); cfg->setStructure(NULL); TR_BlockCloner cloner(cfg); TR::Block *tailSplitBlock = cloner.cloneBlocks(block->getNextBlock(), block->getNextBlock()); tailSplitBlock->setFrequency(cold1->getFrequency()); if (cold1->isCold()) tailSplitBlock->setIsCold(); // physically put the block after cold1 since we want cold1 to fall through tailSplitBlock->getExit()->join(cold1->getExit()->getNextTreeTop()); cold1->getExit()->join(tailSplitBlock->getEntry()); // remove cold1's goto TR::TransformUtil::removeTree(comp(), cold1->getExit()->getPrevRealTreeTop()); // copy the exception edges for (auto e = block->getNextBlock()->getExceptionSuccessors().begin(); e != block->getNextBlock()->getExceptionSuccessors().end(); ++e) cfg->addExceptionEdge(tailSplitBlock, (*e)->getTo()); cfg->addEdge(cold1, tailSplitBlock); // lastly fix up the exit of tailSplitBlock TR::Node *tailSplitEnd = tailSplitBlock->getExit()->getPrevRealTreeTop()->getNode(); if (tailSplitEnd->getOpCode().isGoto()) { tailSplitEnd->setBranchDestination(block->getNextBlock()->getLastRealTreeTop()->getNode()->getBranchDestination()); cfg->addEdge(tailSplitBlock, block->getNextBlock()->getSuccessors().front()->getTo()); } else if (tailSplitEnd->getOpCode().isBranch()) { TR::Block *gotoBlock = TR::Block::createEmptyBlock(tailSplitEnd, comp(), cold1->getFrequency()); if (cold1->isCold()) gotoBlock->setIsCold(true); gotoBlock->getExit()->join(tailSplitBlock->getExit()->getNextTreeTop()); tailSplitBlock->getExit()->join(gotoBlock->getEntry()); cfg->addNode(gotoBlock); gotoBlock->append(TR::TreeTop::create(comp(), TR::Node::create(tailSplitEnd, TR::Goto, 0, block->getNextBlock()->getExit()->getNextTreeTop()))); cfg->addEdge(tailSplitBlock, gotoBlock); cfg->addEdge(tailSplitBlock, tailSplitBlock->getLastRealTreeTop()->getNode()->getBranchDestination()->getEnclosingBlock()); cfg->addEdge(gotoBlock, block->getNextBlock()->getNextBlock()); } else if ( !tailSplitEnd->getOpCode().isReturn() && !tailSplitEnd->getOpCode().isJumpWithMultipleTargets() && tailSplitEnd->getOpCodeValue() != TR::athrow && !(tailSplitEnd->getNumChildren() >= 1 && tailSplitEnd->getFirstChild()->getOpCodeValue() == TR::athrow) ) { tailSplitBlock->append(TR::TreeTop::create(comp(), TR::Node::create(tailSplitEnd, TR::Goto, 0, block->getNextBlock()->getExit()->getNextTreeTop()))); cfg->addEdge(tailSplitBlock, block->getNextBlock()->getNextBlock()); } else { for (auto e = block->getNextBlock()->getSuccessors().begin(); e != block->getNextBlock()->getSuccessors().end(); ++e) cfg->addEdge(tailSplitBlock, (*e)->getTo()); } cfg->removeEdge(cold1, block->getNextBlock()); optimizer()->setUseDefInfo(NULL); optimizer()->setValueNumberInfo(NULL); }