Esempio n. 1
0
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;
      }
   }
Esempio n. 2
0
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;
   }
Esempio n. 3
0
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);
      }
   }
Esempio n. 4
0
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);
      }
   }
Esempio n. 5
0
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);
      }
   }
Esempio n. 6
0
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());
	     }
      }
   }
Esempio n. 7
0
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");
      }
   }
Esempio n. 8
0
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
   }
Esempio n. 9
0
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;
   }
Esempio n. 10
0
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);
   }
Esempio n. 11
0
// 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;
}
Esempio n. 12
0
TR_ExpressionsSimplification::LoopInfo*
TR_ExpressionsSimplification::findLoopInfo(TR_RegionStructure* region)
   {
   ListIterator<TR::CFGEdge> exitEdges(&region->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;
   }
Esempio n. 13
0
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");
      }
   }
Esempio n. 14
0
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);
   }
Esempio n. 15
0
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;
         }
      }
   }