Esempio n. 1
0
/// Optimize placement of initializer calls given a list of calls to the
/// same initializer. All original initialization points must be dominated by
/// the final initialization calls.
///
/// The current heuristic hoists all initialization points within a function to
/// a single dominating call in the outer loop preheader.
void SILGlobalOpt::placeInitializers(SILFunction *InitF,
                                     ArrayRef<ApplyInst *> Calls) {
  LLVM_DEBUG(llvm::dbgs() << "GlobalOpt: calls to "
             << Demangle::demangleSymbolAsString(InitF->getName())
             << " : " << Calls.size() << "\n");
  // Map each initializer-containing function to its final initializer call.
  llvm::DenseMap<SILFunction *, ApplyInst *> ParentFuncs;
  for (auto *AI : Calls) {
    assert(AI->getNumArguments() == 0 && "ill-formed global init call");
    assert(cast<FunctionRefInst>(AI->getCallee())->getReferencedFunction()
           == InitF && "wrong init call");
    SILFunction *ParentF = AI->getFunction();
    DominanceInfo *DT = DA->get(ParentF);
    ApplyInst *HoistAI =
        getHoistedApplyForInitializer(AI, DT, InitF, ParentF, ParentFuncs);

    // If we were unable to find anything, just go onto the next apply.
    if (!HoistAI) {
      continue;
    }

    // Otherwise, move this call to the outermost loop preheader.
    SILBasicBlock *BB = HoistAI->getParent();
    typedef llvm::DomTreeNodeBase<SILBasicBlock> DomTreeNode;
    DomTreeNode *Node = DT->getNode(BB);
    while (Node) {
      SILBasicBlock *DomParentBB = Node->getBlock();
      if (isAvailabilityCheck(DomParentBB)) {
        LLVM_DEBUG(llvm::dbgs() << "  don't hoist above availability check "
                                   "at bb"
                                << DomParentBB->getDebugID() << "\n");
        break;
      }
      BB = DomParentBB;
      if (!isInLoop(BB))
        break;
      Node = Node->getIDom();
    }

    if (BB == HoistAI->getParent()) {
      // BB is either unreachable or not in a loop.
      LLVM_DEBUG(llvm::dbgs() << "  skipping (not in a loop): " << *HoistAI
                              << "  in " << HoistAI->getFunction()->getName()
                              << "\n");
      continue;
    }

    LLVM_DEBUG(llvm::dbgs() << "  hoisting: " << *HoistAI << "  in "
                       << HoistAI->getFunction()->getName() << "\n");
    HoistAI->moveBefore(&*BB->begin());
    placeFuncRef(HoistAI, DT);
    HasChanged = true;
  }
}
Esempio n. 2
0
ApplyInst *SILGlobalOpt::getHoistedApplyForInitializer(
    ApplyInst *AI, DominanceInfo *DT, SILFunction *InitF, SILFunction *ParentF,
    llvm::DenseMap<SILFunction *, ApplyInst *> &ParentFuncs) {
  auto PFI = ParentFuncs.find(ParentF);
  if (PFI == ParentFuncs.end()) {
    ParentFuncs[ParentF] = AI;

    // It's the first time we found a call to InitF in this function, so we
    // try to hoist it out of any loop.
    return AI;
  }

  // Found a replacement for this init call. Ensure the replacement dominates
  // the original call site.
  ApplyInst *CommonAI = PFI->second;
  assert(
      cast<FunctionRefInst>(CommonAI->getCallee())->getReferencedFunction() ==
          InitF &&
      "ill-formed global init call");
  SILBasicBlock *DomBB =
      DT->findNearestCommonDominator(AI->getParent(), CommonAI->getParent());

  // We must not move initializers around availability-checks.
  if (isAvailabilityCheckOnDomPath(DomBB, CommonAI->getParent(), DT))
    return nullptr;

  ApplyInst *Result = nullptr;
  if (DomBB != CommonAI->getParent()) {
    CommonAI->moveBefore(&*DomBB->begin());
    placeFuncRef(CommonAI, DT);

    // Try to hoist the existing AI again if we move it to another block,
    // e.g. from a loop exit into the loop.
    Result = CommonAI;
  }

  AI->replaceAllUsesWith(CommonAI);
  AI->eraseFromParent();
  HasChanged = true;
  return Result;
}
Esempio n. 3
0
/// Optimize placement of initializer calls given a list of calls to the
/// same initializer. All original initialization points must be dominated by
/// the final initialization calls.
///
/// The current heuristic hoists all initialization points within a function to
/// a single dominating call in the outer loop preheader.
void SILGlobalOpt::placeInitializers(SILFunction *InitF,
                                     ArrayRef<ApplyInst*> Calls) {
  DEBUG(llvm::dbgs() << "GlobalOpt: calls to "
        << demangle_wrappers::demangleSymbolAsString(InitF->getName())
        << " : " << Calls.size() << "\n");
  // Map each initializer-containing function to its final initializer call.
  llvm::DenseMap<SILFunction*, ApplyInst*> ParentFuncs;
  for (auto *AI : Calls) {
    assert(AI->getNumArguments() == 0 && "ill-formed global init call");
    assert(cast<FunctionRefInst>(AI->getCallee())->getReferencedFunction()
           == InitF && "wrong init call");

    SILFunction *ParentF = AI->getFunction();
    DominanceInfo *DT = DA->get(ParentF);
    auto PFI = ParentFuncs.find(ParentF);
    ApplyInst *HoistAI = nullptr;
    if (PFI != ParentFuncs.end()) {
      // Found a replacement for this init call.
      // Ensure the replacement dominates the original call site.
      ApplyInst *CommonAI = PFI->second;
      assert(cast<FunctionRefInst>(CommonAI->getCallee())
             ->getReferencedFunction() == InitF &&
             "ill-formed global init call");
      SILBasicBlock *DomBB =
        DT->findNearestCommonDominator(AI->getParent(), CommonAI->getParent());
      
      // We must not move initializers around availability-checks.
      if (!isAvailabilityCheckOnDomPath(DomBB, CommonAI->getParent(), DT)) {
        if (DomBB != CommonAI->getParent()) {
          CommonAI->moveBefore(&*DomBB->begin());
          placeFuncRef(CommonAI, DT);
          
          // Try to hoist the existing AI again if we move it to another block,
          // e.g. from a loop exit into the loop.
          HoistAI = CommonAI;
        }
        AI->replaceAllUsesWith(CommonAI);
        AI->eraseFromParent();
        HasChanged = true;
      }
    } else {
      ParentFuncs[ParentF] = AI;
      
      // It's the first time we found a call to InitF in this function, so we
      // try to hoist it out of any loop.
      HoistAI = AI;
    }
    if (HoistAI) {
      // Move this call to the outermost loop preheader.
      SILBasicBlock *BB = HoistAI->getParent();
      typedef llvm::DomTreeNodeBase<SILBasicBlock> DomTreeNode;
      DomTreeNode *Node = DT->getNode(BB);
      while (Node) {
        SILBasicBlock *DomParentBB = Node->getBlock();
        if (isAvailabilityCheck(DomParentBB)) {
          DEBUG(llvm::dbgs() << "  don't hoist above availability check at bb" <<
                DomParentBB->getDebugID() << "\n");
          break;
        }
        BB = DomParentBB;
        if (!isInLoop(BB))
          break;
        Node = Node->getIDom();
      }
      if (BB == HoistAI->getParent()) {
        // BB is either unreachable or not in a loop.
        DEBUG(llvm::dbgs() << "  skipping (not in a loop): " << *HoistAI
              << "  in " << HoistAI->getFunction()->getName() << "\n");
      }
      else {
        DEBUG(llvm::dbgs() << "  hoisting: " << *HoistAI
              << "  in " << HoistAI->getFunction()->getName() << "\n");
        HoistAI->moveBefore(&*BB->begin());
        placeFuncRef(HoistAI, DT);
        HasChanged = true;
      }
    }
  }
}