예제 #1
0
void SideEffectAnalysis::analyzeFunction(FunctionInfo *FInfo,
                                         FunctionOrder &BottomUpOrder,
                                         int RecursionDepth) {
  FInfo->NeedUpdateCallers = true;

  if (BottomUpOrder.prepareForVisiting(FInfo))
    return;

  // Handle @effects attributes
  if (getDefinedEffects(FInfo->FE, FInfo->F)) {
    DEBUG(llvm::dbgs() << "  -- has defined effects " <<
          FInfo->F->getName() << '\n');
    return;
  }
  
  if (!FInfo->F->isDefinition()) {
    // We can't assume anything about external functions.
    DEBUG(llvm::dbgs() << "  -- is external " << FInfo->F->getName() << '\n');
    FInfo->FE.setWorstEffects();
    return;
  }
  
  DEBUG(llvm::dbgs() << "  >> analyze " << FInfo->F->getName() << '\n');

  // Check all instructions of the function
  for (auto &BB : *FInfo->F) {
    for (auto &I : BB) {
      analyzeInstruction(FInfo, &I, BottomUpOrder, RecursionDepth);
    }
  }
  DEBUG(llvm::dbgs() << "  << finished " << FInfo->F->getName() << '\n');
}
예제 #2
0
void GenericFunctionEffectAnalysis<FunctionEffects>::analyzeCall(
    FunctionInfo *functionInfo, FullApplySite fullApply,
    FunctionOrder &bottomUpOrder, int recursionDepth) {

  FunctionEffects applyEffects;
  if (applyEffects.summarizeCall(fullApply)) {
    functionInfo->functionEffects.mergeFromApply(applyEffects, fullApply);
    return;
  }

  if (recursionDepth >= MaxRecursionDepth) {
    functionInfo->functionEffects.setWorstEffects();
    return;
  }
  CalleeList callees = BCA->getCalleeList(fullApply);
  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.
      fullApply.getOrigCalleeType()->isCalleeConsumed()) {
    functionInfo->functionEffects.setWorstEffects();
    return;
  }
  // Derive the effects of the apply from the known callees.
  // Defer merging callee effects until the callee is scheduled
  for (SILFunction *callee : callees) {
    FunctionInfo *calleeInfo = getFunctionInfo(callee);
    calleeInfo->addCaller(functionInfo, fullApply);
    if (!calleeInfo->isVisited()) {
      // Recursively visit the called function.
      analyzeFunction(calleeInfo, bottomUpOrder, recursionDepth + 1);
      bottomUpOrder.tryToSchedule(calleeInfo);
    }
  }
}
예제 #3
0
void GenericFunctionEffectAnalysis<FunctionEffects>::analyzeFunction(
    FunctionInfo *functionInfo, FunctionOrder &bottomUpOrder,
    int recursionDepth) {
  functionInfo->needUpdateCallers = true;

  if (bottomUpOrder.prepareForVisiting(functionInfo))
    return;

  auto *F = functionInfo->F;
  if (functionInfo->functionEffects.summarizeFunction(F))
    return;

  DEBUG(llvm::dbgs() << "  >> analyze " << F->getName() << '\n');

  // Check all instructions of the function
  for (auto &BB : *F) {
    for (auto &I : BB) {
      if (auto fullApply = FullApplySite::isa(&I))
        analyzeCall(functionInfo, fullApply, bottomUpOrder, recursionDepth);
      else
        functionInfo->functionEffects.analyzeInstruction(&I);
    }
  }
  DEBUG(llvm::dbgs() << "  << finished " << F->getName() << '\n');
}
예제 #4
0
void AccessSummaryAnalysis::processCall(FunctionInfo *callerInfo,
                                        unsigned callerArgumentIndex,
                                        SILFunction *callee,
                                        unsigned argumentIndex,
                                        FunctionOrder &order) {
  // Record the flow of an argument from  the caller to the callee so that
  // the interprocedural analysis can iterate to a fixpoint.
  FunctionInfo *calleeInfo = getFunctionInfo(callee);
  ArgumentFlow flow = {callerArgumentIndex, argumentIndex, calleeInfo};
  callerInfo->recordFlow(flow);
  if (!calleeInfo->isVisited()) {
    processFunction(calleeInfo, order);
    order.tryToSchedule(calleeInfo);
  }

  propagateFromCalleeToCaller(callerInfo, flow);
}
예제 #5
0
void AccessSummaryAnalysis::processFunction(FunctionInfo *info,
                                            FunctionOrder &order) {
  // Does the summary need to be recomputed?
  if (order.prepareForVisiting(info))
    return;

  // Compute function summary on a per-argument basis.
  unsigned index = 0;
  for (SILArgument *arg : info->getFunction()->getArguments()) {
    FunctionSummary &functionSummary = info->getSummary();
    ArgumentSummary &argSummary =
        functionSummary.getAccessForArgument(index);
    index++;

    auto *functionArg = cast<SILFunctionArgument>(arg);
    // Only summarize @inout_aliasable arguments.
    SILArgumentConvention convention =
        functionArg->getArgumentConvention().Value;
    if (convention != SILArgumentConvention::Indirect_InoutAliasable)
      continue;

    processArgument(info, functionArg, argSummary, order);
  }
}
예제 #6
0
void SideEffectAnalysis::analyzeInstruction(FunctionInfo *FInfo,
                                            SILInstruction *I,
                                            FunctionOrder &BottomUpOrder,
                                            int RecursionDepth) {
  if (FullApplySite FAS = FullApplySite::isa(I)) {
    // Is this a call to a semantics function?
    ArraySemanticsCall ASC(I);
    if (ASC && ASC.hasSelf()) {
      FunctionEffects ApplyEffects(FAS.getNumArguments());
      if (getSemanticEffects(ApplyEffects, ASC)) {
        FInfo->FE.mergeFromApply(ApplyEffects, FAS);
        return;
      }
    }

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

    if (RecursionDepth < MaxRecursionDepth) {
      CalleeList 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()) {
        // Derive the effects of the apply from the known callees.
        for (SILFunction *Callee : Callees) {
          FunctionInfo *CalleeInfo = getFunctionInfo(Callee);
          CalleeInfo->addCaller(FInfo, FAS);
          if (!CalleeInfo->isVisited()) {
            // Recursively visit the called function.
            analyzeFunction(CalleeInfo, BottomUpOrder, RecursionDepth + 1);
            BottomUpOrder.tryToSchedule(CalleeInfo);
          }
        }
        return;
      }
    }
    // Be conservative for everything else.
    FInfo->FE.setWorstEffects();
    return;
  }
  // Handle some kind of instructions specially.
  switch (I->getKind()) {
    case ValueKind::FixLifetimeInst:
      // A fix_lifetime instruction acts like a read on the operand. Retains can move after it
      // but the last release can't move before it.
      FInfo->FE.getEffectsOn(I->getOperand(0))->Reads = true;
      return;
    case ValueKind::AllocStackInst:
    case ValueKind::DeallocStackInst:
      return;
    case ValueKind::StrongRetainInst:
    case ValueKind::StrongRetainUnownedInst:
    case ValueKind::RetainValueInst:
    case ValueKind::UnownedRetainInst:
      FInfo->FE.getEffectsOn(I->getOperand(0))->Retains = true;
      return;
    case ValueKind::StrongReleaseInst:
    case ValueKind::ReleaseValueInst:
    case ValueKind::UnownedReleaseInst:
      FInfo->FE.getEffectsOn(I->getOperand(0))->Releases = true;
      
      // TODO: Check the call graph to be less conservative about what
      // destructors might be called.
      FInfo->FE.setWorstEffects();
      return;
    case ValueKind::LoadInst:
      FInfo->FE.getEffectsOn(cast<LoadInst>(I)->getOperand())->Reads = true;
      return;
    case ValueKind::StoreInst:
      FInfo->FE.getEffectsOn(cast<StoreInst>(I)->getDest())->Writes = true;
      return;
    case ValueKind::CondFailInst:
      FInfo->FE.Traps = true;
      return;
    case ValueKind::PartialApplyInst:
      FInfo->FE.AllocsObjects = true;
      return;
    case ValueKind::BuiltinInst: {
      auto &BI = cast<BuiltinInst>(I)->getBuiltinInfo();
      switch (BI.ID) {
        case BuiltinValueKind::IsUnique:
          // TODO: derive this information in a more general way, e.g. add it
          // to Builtins.def
          FInfo->FE.ReadsRC = true;
          break;
        default:
          break;
      }
      // Detailed memory effects of builtins are handled below by checking the
      // memory behavior of the instruction.
      break;
      }
    default:
      break;
  }

  if (isa<AllocationInst>(I)) {
    // Excluding AllocStackInst (which is handled above).
    FInfo->FE.AllocsObjects = true;
  }
  
  // Check the general memory behavior for instructions we didn't handle above.
  switch (I->getMemoryBehavior()) {
    case MemoryBehavior::None:
      break;
    case MemoryBehavior::MayRead:
      FInfo->FE.GlobalEffects.Reads = true;
      break;
    case MemoryBehavior::MayWrite:
      FInfo->FE.GlobalEffects.Writes = true;
      break;
    case MemoryBehavior::MayReadWrite:
      FInfo->FE.GlobalEffects.Reads = true;
      FInfo->FE.GlobalEffects.Writes = true;
      break;
    case MemoryBehavior::MayHaveSideEffects:
      FInfo->FE.setWorstEffects();
      break;
  }
  if (I->mayTrap())
    FInfo->FE.Traps = true;
}