Пример #1
0
static bool verifySILSelfParameterType(SILDeclRef DeclRef,
                                       SILFunction *F, CanSILFunctionType FTy) {
  SILModule &M = F->getModule();
  SILParameterInfo PInfo = FTy->getSelfParameter();
  CanType CTy = PInfo.getType();
  SILType Ty = SILType::getPrimitiveObjectType(CTy);

  // We do not care about trivial parameters (for now). There seem to be
  // cases where we lower them as unowned.
  //
  // *NOTE* We do not run this check when we have a generic type since
  // *generic types do not have type lowering and are always treated as
  // *non-trivial since we do not know the type.
  if (CTy->hasArchetype() || CTy->hasTypeParameter() ||
      M.getTypeLowering(Ty).isTrivial())
    return true;

  // If this function is a constructor or destructor, bail. These have @owned
  // parameters.
  if (DeclRef.isConstructor() || DeclRef.isDestructor())
    return true;

  // Otherwise, if this function type has a guaranteed self parameter type,
  // make sure that we have a +0 self param.
  return !FTy->getExtInfo().hasGuaranteedSelfParam() ||
          PInfo.isGuaranteed() || PInfo.isIndirectMutating();
}
Пример #2
0
void SILCombiner::eraseApply(FullApplySite FAS, const UserListTy &Users) {
    // Make sure to release and destroy any owned or in-arguments.
    auto FuncType = FAS.getOrigCalleeType();
    assert(FuncType->getParameters().size() == FAS.getNumArguments() &&
           "mismatching number of arguments");
    for (int i = 0, e = FAS.getNumArguments(); i < e; ++i) {
        SILParameterInfo PI = FuncType->getParameters()[i];
        auto Arg = FAS.getArgument(i);
        switch (PI.getConvention()) {
        case ParameterConvention::Indirect_In:
            Builder.createDestroyAddr(FAS.getLoc(), Arg);
            break;
        case ParameterConvention::Direct_Owned:
            Builder.createReleaseValue(FAS.getLoc(), Arg, Atomicity::Atomic);
            break;
        case ParameterConvention::Indirect_In_Guaranteed:
        case ParameterConvention::Indirect_Inout:
        case ParameterConvention::Indirect_InoutAliasable:
        case ParameterConvention::Direct_Unowned:
        case ParameterConvention::Direct_Deallocating:
        case ParameterConvention::Direct_Guaranteed:
            break;
        }
    }

    // Erase all of the reference counting instructions (in reverse order to have
    // no dangling uses).
    for (auto rit = Users.rbegin(), re = Users.rend(); rit != re; ++rit)
        eraseInstFromFunction(**rit);

    // And the Apply itself.
    eraseInstFromFunction(*FAS.getInstruction());
}
Пример #3
0
clang::CanQualType IRGenModule::getClangType(SILParameterInfo params) {
    auto clangType = getClangType(params.getSILType());
    // @block_storage types must be @inout_aliasable and have
    // special lowering
    if (!params.getSILType().is<SILBlockStorageType>()) {
        if (params.isIndirectMutating()) {
            return getClangASTContext().getPointerType(clangType);
        }
        if (params.isIndirect()) {
            auto constTy =
                getClangASTContext().getCanonicalType(clangType.withConst());
            return getClangASTContext().getPointerType(constTy);
        }
    }
    return clangType;
}
Пример #4
0
/// Returns true on success.
bool PartialApplyCombiner::allocateTemporaries() {
    // Copy the original arguments of the partial_apply into
    // newly created temporaries and use these temporaries instead of
    // the original arguments afterwards.
    // This is done to "extend" the life-time of original partial_apply
    // arguments, as they may be destroyed/deallocated before the last
    // use by one of the apply instructions.
    // TODO:
    // Copy arguments of the partial_apply into new temporaries
    // only if the lifetime of arguments ends before their uses
    // by apply instructions.
    bool needsReleases = false;
    CanSILFunctionType PAITy =
        dyn_cast<SILFunctionType>(PAI->getCallee()->getType().getSwiftType());

    // Emit a destroy value for each captured closure argument.
    ArrayRef<SILParameterInfo> Params = PAITy->getParameters();
    auto Args = PAI->getArguments();
    unsigned Delta = Params.size() - Args.size();

    llvm::SmallVector<std::pair<SILValue, unsigned>, 8> ArgsToHandle;
    for (unsigned AI = 0, AE = Args.size(); AI != AE; ++AI) {
        SILValue Arg = Args[AI];
        SILParameterInfo Param = Params[AI + Delta];
        if (Param.isIndirectMutating())
            continue;
        // Create a temporary and copy the argument into it, if:
        // - the argument stems from an alloc_stack
        // - the argument is consumed by the callee and is indirect
        //   (e.g. it is an @in argument)
        if (isa<AllocStackInst>(Arg) ||
                (Param.isConsumed() && Param.isIndirect())) {
            // If the temporary is non-trivial, we need to release it later.
            if (!Arg->getType().isTrivial(PAI->getModule()))
                needsReleases = true;
            ArgsToHandle.push_back(std::make_pair(Arg, AI));
        }
    }

    if (needsReleases) {
        // Compute the set of endpoints, which will be used to insert releases of
        // temporaries. This may fail if the frontier is located on a critical edge
        // which we may not split (no CFG changes in SILCombine).
        ValueLifetimeAnalysis VLA(PAI);
        if (!VLA.computeFrontier(PAFrontier, ValueLifetimeAnalysis::DontModifyCFG))
            return false;
    }

    for (auto ArgWithIdx : ArgsToHandle) {
        SILValue Arg = ArgWithIdx.first;
        Builder.setInsertionPoint(PAI->getFunction()->begin()->begin());
        // Create a new temporary at the beginning of a function.
        auto *Tmp = Builder.createAllocStack(PAI->getLoc(), Arg->getType(),
        {/*Constant*/ true, ArgWithIdx.second});
        Builder.setInsertionPoint(PAI);
        // Copy argument into this temporary.
        Builder.createCopyAddr(PAI->getLoc(), Arg, Tmp,
                               IsTake_t::IsNotTake,
                               IsInitialization_t::IsInitialization);

        Tmps.push_back(Tmp);
        ArgToTmp.insert(std::make_pair(Arg, Tmp));
    }
    return true;
}
Пример #5
0
void ClosureSpecializer::gatherCallSites(
    SILFunction *Caller,
    llvm::SmallVectorImpl<ClosureInfo*> &ClosureCandidates,
    llvm::DenseSet<FullApplySite> &MultipleClosureAI) {

  // A set of apply inst that we have associated with a closure. We use this to
  // make sure that we do not handle call sites with multiple closure arguments.
  llvm::DenseSet<FullApplySite> VisitedAI;

  // For each basic block BB in Caller...
  for (auto &BB : *Caller) {

    // For each instruction II in BB...
    for (auto &II : BB) {
      // If II is not a closure that we support specializing, skip it...
      if (!isSupportedClosure(&II))
        continue;

      ClosureInfo *CInfo = nullptr;

      // Go through all uses of our closure.
      for (auto *Use : II.getUses()) {
        // If this use is not an apply inst or an apply inst with
        // substitutions, there is nothing interesting for us to do, so
        // continue...
        auto AI = FullApplySite::isa(Use->getUser());
        if (!AI || AI.hasSubstitutions())
          continue;

        // Check if we have already associated this apply inst with a closure to
        // be specialized. We do not handle applies that take in multiple
        // closures at this time.
        if (!VisitedAI.insert(AI).second) {
          MultipleClosureAI.insert(AI);
          continue;
        }

        // If AI does not have a function_ref definition as its callee, we can
        // not do anything here... so continue...
        SILFunction *ApplyCallee = AI.getReferencedFunction();
        if (!ApplyCallee || ApplyCallee->isExternalDeclaration())
          continue;

        // Ok, we know that we can perform the optimization but not whether or
        // not the optimization is profitable. Find the index of the argument
        // corresponding to our partial apply.
        Optional<unsigned> ClosureIndex;
        for (unsigned i = 0, e = AI.getNumArguments(); i != e; ++i) {
          if (AI.getArgument(i) != SILValue(&II))
            continue;
          ClosureIndex = i;
          DEBUG(llvm::dbgs() << "    Found callsite with closure argument at "
                << i << ": " << *AI.getInstruction());
          break;
        }

        // If we did not find an index, there is nothing further to do,
        // continue.
        if (!ClosureIndex.hasValue())
          continue;

        // Make sure that the Closure is invoked in the Apply's callee. We only
        // want to perform closure specialization if we know that we will be
        // able to change a partial_apply into an apply.
        //
        // TODO: Maybe just call the function directly instead of moving the
        // partial apply?
        SILValue Arg = ApplyCallee->getArgument(ClosureIndex.getValue());
        if (std::none_of(Arg->use_begin(), Arg->use_end(),
                         [&Arg](Operand *Op) -> bool {
                           auto UserAI = FullApplySite::isa(Op->getUser());
                           return UserAI && UserAI.getCallee() == Arg;
                         })) {
          continue;
        }

        auto NumIndirectResults =
          AI.getSubstCalleeType()->getNumIndirectResults();
        assert(ClosureIndex.getValue() >= NumIndirectResults);
        auto ClosureParamIndex = ClosureIndex.getValue() - NumIndirectResults;

        auto ParamInfo = AI.getSubstCalleeType()->getParameters();
        SILParameterInfo ClosureParamInfo = ParamInfo[ClosureParamIndex];

        // Get all non-failure exit BBs in the Apply Callee if our partial apply
        // is guaranteed. If we do not understand one of the exit BBs, bail.
        //
        // We need this to make sure that we insert a release in the appropriate
        // locations to balance the +1 from the creation of the partial apply.
        llvm::TinyPtrVector<SILBasicBlock *> NonFailureExitBBs;
        if (ClosureParamInfo.isGuaranteed() &&
            !findAllNonFailureExitBBs(ApplyCallee, NonFailureExitBBs)) {
          continue;
        }

        // Compute the final release points of the closure. We will insert
        // release of the captured arguments here.
        if (!CInfo) {
          CInfo = new ClosureInfo(&II);
          ValueLifetimeAnalysis VLA(CInfo->Closure);
          VLA.computeFrontier(CInfo->LifetimeFrontier,
                              ValueLifetimeAnalysis::AllowToModifyCFG);
        }

        // Now we know that CSDesc is profitable to specialize. Add it to our
        // call site list.
        CInfo->CallSites.push_back(
          CallSiteDescriptor(CInfo, AI, ClosureIndex.getValue(),
                             ClosureParamInfo, std::move(NonFailureExitBBs)));
      }
      if (CInfo)
        ClosureCandidates.push_back(CInfo);
    }
  }
}