// Returns true if there is any constraint to the move bool TR_LocalLiveRangeReduction::isAnySymInDefinedOrUsedBy(TR_TreeRefInfo *currentTreeRefInfo, TR::Node *currentNode, TR_TreeRefInfo *movingTreeRefInfo ) { TR::Node *movingNode = movingTreeRefInfo->getTreeTop()->getNode(); // ignore anchors // if (movingNode->getOpCode().isAnchor()) movingNode = movingNode->getFirstChild(); TR::ILOpCode &opCode = currentNode->getOpCode(); ////if ((opCode.getOpCodeValue() == TR::monent) || (opCode.getOpCodeValue() == TR::monexit)) if (nodeMaybeMonitor(currentNode)) { if (trace()) traceMsg(comp(),"cannot move %p beyond monitor %p\n",movingNode,currentNode); return true; } // Don't move gc points or things across gc points // if (movingNode->canGCandReturn() || currentNode->canGCandReturn()) { if (trace()) traceMsg(comp(), "cannot move gc points %p past %p\n", movingNode, currentNode); return true; } // Don't move checks or calls at all // if (containsCallOrCheck(movingTreeRefInfo,movingNode)) { if (trace()) traceMsg(comp(),"cannot move check or call %s\n", getDebug()->getName(movingNode)); return true; } // Don't move object header store past a GC point // if ((currentNode->getOpCode().isWrtBar() || currentNode->canCauseGC()) && mayBeObjectHeaderStore(movingNode, fe())) { if (trace()) traceMsg(comp(),"cannot move possible object header store %s past GC point %s\n", getDebug()->getName(movingNode), getDebug()->getName(currentNode)); return true; } if (TR::Compiler->target.cpu.isPower() && opCode.getOpCodeValue() == TR::allocationFence) { // Can't move allocations past flushes if (movingNode->getOpCodeValue() == TR::treetop && movingNode->getFirstChild()->getOpCode().isNew() && (currentNode->getAllocation() == NULL || currentNode->getAllocation() == movingNode->getFirstChild())) { if (trace()) { traceMsg(comp(),"cannot move %p beyond flush %p - ", movingNode, currentNode); if (currentNode->getAllocation() == NULL) traceMsg(comp(),"(flush with null allocation)\n"); else traceMsg(comp(),"(flush for allocation %p)\n", currentNode->getAllocation()); } return true; } // Can't move certain stores past flushes // Exclude all indirect stores, they may be for stack allocs, in which case the flush is needed at least as a scheduling barrier // Direct stores to autos and parms are the only safe candidates if (movingNode->getOpCode().isStoreIndirect() || (movingNode->getOpCode().isStoreDirect() && !movingNode->getSymbol()->isParm() && !movingNode->getSymbol()->isAuto())) { if (trace()) traceMsg(comp(),"cannot move %p beyond flush %p - (flush for possible stack alloc)", movingNode, currentNode); return true; } } for (int32_t i = 0; i < currentNode->getNumChildren(); i++) { TR::Node *child = currentNode->getChild(i); //Any node that has side effects (like call and newarrya) cannot be evaluated in the middle of the tree. if (movingTreeRefInfo->getFirstRefNodesList()->find(child)) { //for calls and unresolve symbol that are not under check if (child->exceptionsRaised() || (child->getOpCode().hasSymbolReference() && child->getSymbolReference()->isUnresolved())) { if (trace()) traceMsg(comp(),"cannot move %p beyond %p - cannot change evaluation point of %p\n ",movingNode,currentTreeRefInfo->getTreeTop()->getNode(),child); return true; } else if(movingNode->getOpCode().isStore()) { TR::SymbolReference *stSymRef = movingNode->getSymbolReference(); int32_t stSymRefNum = stSymRef->getReferenceNumber(); //TR::SymbolReference *stSymRef = movingNode->getSymbolReference(); int32_t numHelperSymbols = comp()->getSymRefTab()->getNumHelperSymbols(); if ((comp()->getSymRefTab()->isNonHelper(stSymRefNum, TR::SymbolReferenceTable::vftSymbol))|| (comp()->getSymRefTab()->isNonHelper(stSymRefNum, TR::SymbolReferenceTable::contiguousArraySizeSymbol))|| (comp()->getSymRefTab()->isNonHelper(stSymRefNum, TR::SymbolReferenceTable::discontiguousArraySizeSymbol))|| (stSymRef == comp()->getSymRefTab()->findHeaderFlagsSymbolRef())|| (stSymRef->getSymbol() == comp()->getSymRefTab()->findGenericIntShadowSymbol())) return true; } else if (movingNode->getOpCode().isResolveOrNullCheck()) { if (trace()) traceMsg(comp(),"cannot move %p beyond %p - node %p under ResolveOrNullCheck",movingNode,currentTreeRefInfo->getTreeTop()->getNode(),currentNode); return true; } else if (TR::Compiler->target.is64Bit() && movingNode->getOpCode().isBndCheck() && ((opCode.getOpCodeValue() == TR::i2l) || (opCode.getOpCodeValue() == TR::iu2l)) && !child->isNonNegative()) { if (trace()) traceMsg(comp(),"cannot move %p beyond %p - changing the eval point of %p will casue extra cg instruction ",movingNode,currentTreeRefInfo->getTreeTop()->getNode(),currentNode); return true; } } //don't recurse over nodes each are not the first reference if (child->getReferenceCount()==1 || currentTreeRefInfo->getFirstRefNodesList()->find(child)) { if (isAnySymInDefinedOrUsedBy(currentTreeRefInfo, child, movingTreeRefInfo )) return true; } } return false; }
static bool isSafeToReplaceNode(TR::Node *currentNode, TR::TreeTop *curTreeTop, bool *seenConditionalBranch, vcount_t visitCount, TR::Compilation *comp, List<OMR::TreeInfo> *targetTrees, bool &cannotBeEliminated, LongestPathMap &longestPaths) { LexicalTimer tx("safeToReplace", comp->phaseTimer()); TR::SparseBitVector symbolReferencesInNode(comp->allocator()); // Collect all symbols that could be killed between here and the next reference // comp->incVisitCount(); //////vcount_t visitCount = comp->getVisitCount(); int32_t numDeadSubNodes = 0; bool cantMoveUnderBranch = false; bool seenInternalPointer = false; bool seenArraylet = false; int32_t curMaxHeight = getLongestPathOfDAG(currentNode, longestPaths); collectSymbolReferencesInNode(currentNode, symbolReferencesInNode, &numDeadSubNodes, visitCount, comp, &seenInternalPointer, &seenArraylet, &cantMoveUnderBranch); bool registersScarce = comp->cg()->areAssignableGPRsScarce(); #ifdef J9_PROJECT_SPECIFIC bool isBCD = currentNode->getType().isBCD(); #endif if (numDeadSubNodes > 1 && #ifdef J9_PROJECT_SPECIFIC !isBCD && #endif registersScarce) { return false; } OMR::TreeInfo *curTreeInfo = findOrCreateTreeInfo(curTreeTop, targetTrees, comp); int32_t curHeight = curTreeInfo->getHeight()+curMaxHeight; if (curHeight > MAX_ALLOWED_HEIGHT) { cannotBeEliminated = true; return false; } // TEMPORARY // Don't allow removal of a node containing an unresolved reference if // the gcOnResolve option is set // bool isUnresolvedReference = currentNode->hasUnresolvedSymbolReference(); if (isUnresolvedReference) return false; bool mayBeVolatileReference = currentNode->mightHaveVolatileSymbolReference(); //if (mayBeVolatileReference) // return false; // Now scan forwards through the trees looking for the next use and checking // to see if any symbols in the subtree are getting modified; if so it is not // safe to replace the node at its next use. // comp->incVisitCount(); for (TR::TreeTop *treeTop = curTreeTop->getNextTreeTop(); treeTop; treeTop = treeTop->getNextTreeTop()) { TR::Node *node = treeTop->getNode(); if(node->getOpCodeValue() == TR::treetop) node = node->getFirstChild(); if (node->getOpCodeValue() == TR::BBStart && !node->getBlock()->isExtensionOfPreviousBlock()) return true; if (cantMoveUnderBranch && (node->getOpCode().isBranch() || node->getOpCode().isJumpWithMultipleTargets())) return false; if (node->canGCandReturn() && seenInternalPointer) return false; int32_t tempHeight = 0; int32_t maxHeight = 0; bool canMoveIfVolatile = true; if (containsNode(node, currentNode, visitCount, comp, &tempHeight, &maxHeight, canMoveIfVolatile)) { // TEMPORARY // Disable moving an unresolved reference down to the middle of a // JNI call, until the resolve helper is fixed properly // if (isUnresolvedReference && node->getFirstChild()->getOpCode().isCall() && node->getFirstChild()->getSymbol()->castToMethodSymbol()->isJNI()) return false; if (curTreeInfo) { OMR::TreeInfo *treeInfo = findOrCreateTreeInfo(treeTop, targetTrees, comp); int32_t height = treeInfo->getHeight(); int32_t maxHeightUsed = maxHeight; if (maxHeightUsed < curMaxHeight) maxHeightUsed = curMaxHeight; if (height < curTreeInfo->getHeight()) height = curTreeInfo->getHeight(); height++; if ((height+maxHeightUsed) > MAX_ALLOWED_HEIGHT) { cannotBeEliminated = true; return false; } treeInfo->setHeight(height); } return true; } if (mayBeVolatileReference && !canMoveIfVolatile) return false; if ((node->getOpCode().isBranch() && (node->getOpCodeValue() != TR::Goto)) || (node->getOpCode().isJumpWithMultipleTargets() && node->getOpCode().hasBranchChildren())) *seenConditionalBranch = true; if (node->getOpCodeValue() == TR::treetop || node->getOpCode().isNullCheck() || node->getOpCode().isResolveCheck() || node->getOpCodeValue() == TR::ArrayStoreCHK || node->getOpCode().isSpineCheck()) { node = node->getFirstChild(); } if (node->getOpCode().isStore()) { // For a store, just the single symbol reference is killed. // Resolution of the store symbol is handled by TR::ResolveCHK // if (symbolReferencesInNode.ValueAt(node->getSymbolReference()->getReferenceNumber())) return false; } // Node Aliasing Changes // Check if the definition modifies any symbol in the subtree // if (node->mayKill(true).containsAny(symbolReferencesInNode, comp)) return false; } return true; }