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; }
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; }
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; }
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 }