Exemplo n.º 1
0
void SideEffectAnalysis::getEffects(FunctionEffects &ApplyEffects, FullApplySite FAS) {
  assert(ApplyEffects.ParamEffects.size() == 0 &&
         "Not using a new ApplyEffects?");
  ApplyEffects.ParamEffects.resize(FAS.getNumArguments());

  // Is this a call to a semantics function?
  ArraySemanticsCall ASC(FAS.getInstruction());
  if (ASC && ASC.hasSelf()) {
    if (getSemanticEffects(ApplyEffects, ASC))
      return;
  }

  if (SILFunction *SingleCallee = FAS.getCalleeFunction()) {
    // Does the function have any @effects?
    if (getDefinedEffects(ApplyEffects, SingleCallee))
      return;
  }

  auto Callees = BCA->getCalleeList(FAS);
  if (!Callees.allCalleesVisible() ||
      // @callee_owned function calls implicitly release the context, which
      // may call deinits of boxed values.
      // TODO: be less conservative about what destructors might be called.
      FAS.getOrigCalleeType()->isCalleeConsumed()) {
    ApplyEffects.setWorstEffects();
    return;
  }

  // We can see all the callees. So we just merge the effects from all of
  // them.
  for (auto *Callee : Callees) {
    const FunctionEffects &CalleeFE = getEffects(Callee);
    ApplyEffects.mergeFrom(CalleeFE);
  }
}
Exemplo n.º 2
0
/// FIXME: Total hack to work around issues exposed while ripping call
///        graph maintenance from the inliner.
static void tryLinkCallee(FullApplySite Apply) {
  auto *F = Apply.getCalleeFunction();
  if (!F || F->isDefinition()) return;

  auto &M = Apply.getFunction()->getModule();
  M.linkFunction(F, SILModule::LinkingMode::LinkAll);
}
Exemplo n.º 3
0
/// Checks whether any of the arguments to the apply are closures and diagnoses
/// if any of the @inout_aliasable captures passed to those closures have
/// in-progress accesses that would conflict with any access the summary
/// says the closure would perform.
//
/// TODO: We currently fail to statically diagnose non-escaping closures pased
/// via @block_storage convention. To enforce this case, we should statically
/// recognize when the apply takes a block argument that has been initialized to
/// a non-escaping closure.
static void checkForViolationsInNoEscapeClosures(
    const StorageMap &Accesses, FullApplySite FAS, AccessSummaryAnalysis *ASA,
    llvm::SmallVectorImpl<ConflictingAccess> &ConflictingAccesses) {

  SILFunction *Callee = FAS.getCalleeFunction();
  if (Callee && !Callee->empty()) {
    // Check for violation with directly called closure
    checkForViolationWithCall(Accesses, Callee, 0, FAS.getArguments(), ASA,
                              ConflictingAccesses);
  }

  // Check for violation with closures passed as arguments
  for (SILValue Argument : FAS.getArguments()) {
    auto *PAI = lookThroughForPartialApply(Argument);
    if (!PAI)
      continue;

    SILFunction *Closure = PAI->getCalleeFunction();
    if (!Closure || Closure->empty())
      continue;

    // Check the closure's captures, which are a suffix of the closure's
    // parameters.
    unsigned StartIndex =
        Closure->getArguments().size() - PAI->getNumCallArguments();
    checkForViolationWithCall(Accesses, Closure, StartIndex,
                              PAI->getArguments(), ASA, ConflictingAccesses);
  }
}
Exemplo n.º 4
0
void SideEffectAnalysis::getEffects(FunctionEffects &ApplyEffects, FullApplySite FAS) {
  assert(ApplyEffects.ParamEffects.size() == 0 &&
         "Not using a new ApplyEffects?");
  ApplyEffects.ParamEffects.resize(FAS.getNumArguments());

  // Is this a call to a semantics function?
  ArraySemanticsCall ASC(FAS.getInstruction());
  if (ASC && ASC.hasSelf()) {
    if (getSemanticEffects(ApplyEffects, ASC))
      return;
  }

  if (SILFunction *SingleCallee = FAS.getCalleeFunction()) {
    // Does the function have any @effects?
    if (getDefinedEffects(ApplyEffects, SingleCallee))
      return;
  }

  auto Callees = BCA->getCalleeList(FAS);
  if (!Callees.allCalleesVisible()) {
    ApplyEffects.setWorstEffects();
    return;
  }

  // We can see all the callees. So we just merge the effects from all of
  // them.
  for (auto *Callee : Callees) {
    const FunctionEffects &CalleeFE = getEffects(Callee);
    ApplyEffects.mergeFrom(CalleeFE);
  }
}
Exemplo n.º 5
0
void AccessSummaryAnalysis::processFullApply(FunctionInfo *callerInfo,
                                             unsigned callerArgumentIndex,
                                             FullApplySite apply,
                                             Operand *argumentOperand,
                                             FunctionOrder &order) {
  unsigned operandNumber = argumentOperand->getOperandNumber();
  assert(operandNumber > 0 && "Summarizing apply for non-argument?");

  unsigned calleeArgumentIndex = operandNumber - 1;
  SILFunction *callee = apply.getCalleeFunction();
  // We can't apply a summary for function whose body we can't see.
  // Since user-provided closures are always in the same module as their callee
  // This likely indicates a missing begin_access before an open-coded
  // call.
  if (!callee || callee->empty())
    return;

  processCall(callerInfo, callerArgumentIndex, callee, calleeArgumentIndex,
              order);
}
Exemplo n.º 6
0
/// Return true if inlining this call site is profitable.
bool SILPerformanceInliner::isProfitableToInline(FullApplySite AI,
                                              unsigned loopDepthOfAI,
                                              DominanceAnalysis *DA,
                                              SILLoopAnalysis *LA,
                                              ConstantTracker &callerTracker,
                                              unsigned &NumCallerBlocks) {
  SILFunction *Callee = AI.getCalleeFunction();
  
  if (Callee->getInlineStrategy() == AlwaysInline)
    return true;
  
  ConstantTracker constTracker(Callee, &callerTracker, AI);
  
  DominanceInfo *DT = DA->get(Callee);
  SILLoopInfo *LI = LA->get(Callee);

  DominanceOrder domOrder(&Callee->front(), DT, Callee->size());
  
  // Calculate the inlining cost of the callee.
  unsigned CalleeCost = 0;
  unsigned Benefit = InlineCostThreshold > 0 ? InlineCostThreshold :
                                               RemovedCallBenefit;
  Benefit += loopDepthOfAI * LoopBenefitFactor;
  int testThreshold = TestThreshold;

  while (SILBasicBlock *block = domOrder.getNext()) {
    constTracker.beginBlock();
    unsigned loopDepth = LI->getLoopDepth(block);
    for (SILInstruction &I : *block) {
      constTracker.trackInst(&I);
      
      auto ICost = instructionInlineCost(I);
      
      if (testThreshold >= 0) {
        // We are in test-mode: use a simplified cost model.
        CalleeCost += testCost(&I);
      } else {
        // Use the regular cost model.
        CalleeCost += unsigned(ICost);
      }
      
      if (ApplyInst *AI = dyn_cast<ApplyInst>(&I)) {
        
        // Check if the callee is passed as an argument. If so, increase the
        // threshold, because inlining will (probably) eliminate the closure.
        SILInstruction *def = constTracker.getDefInCaller(AI->getCallee());
        if (def && (isa<FunctionRefInst>(def) || isa<PartialApplyInst>(def))) {

          DEBUG(llvm::dbgs() << "        Boost: apply const function at"
                             << *AI);
          Benefit += ConstCalleeBenefit + loopDepth * LoopBenefitFactor;
          testThreshold *= 2;
        }
      }
    }
    // Don't count costs in blocks which are dead after inlining.
    SILBasicBlock *takenBlock = getTakenBlock(block->getTerminator(),
                                              constTracker);
    if (takenBlock) {
      Benefit += ConstTerminatorBenefit + TestOpt;
      DEBUG(llvm::dbgs() << "      Take bb" << takenBlock->getDebugID() <<
            " of" << *block->getTerminator());
      domOrder.pushChildrenIf(block, [=] (SILBasicBlock *child) {
        return child->getSinglePredecessor() != block || child == takenBlock;
      });
    } else {
      domOrder.pushChildren(block);
    }
  }

  unsigned Threshold = Benefit; // The default.
  if (testThreshold >= 0) {
    // We are in testing mode.
    Threshold = testThreshold;
  } else if (AI.getFunction()->isThunk()) {
    // Only inline trivial functions into thunks (which will not increase the
    // code size).
    Threshold = TrivialFunctionThreshold;
  } else {
    // The default case.
    // We reduce the benefit if the caller is too large. For this we use a
    // cubic function on the number of caller blocks. This starts to prevent
    // inlining at about 800 - 1000 caller blocks.
    unsigned blockMinus =
      (NumCallerBlocks * NumCallerBlocks) / BlockLimitDenominator *
                          NumCallerBlocks / BlockLimitDenominator;
    if (Threshold > blockMinus + TrivialFunctionThreshold)
      Threshold -= blockMinus;
    else
      Threshold = TrivialFunctionThreshold;
  }

  if (CalleeCost > Threshold) {
    DEBUG(llvm::dbgs() << "        NO: Function too big to inline, "
          "cost: " << CalleeCost << ", threshold: " << Threshold << "\n");
    return false;
  }
  DEBUG(llvm::dbgs() << "        YES: ready to inline, "
        "cost: " << CalleeCost << ", threshold: " << Threshold << "\n");
  NumCallerBlocks += Callee->size();
  return true;
}