本文整理汇总了C++中SILFunction类的典型用法代码示例。如果您正苦于以下问题:C++ SILFunction类的具体用法?C++ SILFunction怎么用?C++ SILFunction使用的例子?那么, 这里精选的类代码示例或许可以为您提供帮助。
在下文中一共展示了SILFunction类的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: runOnFunctionRecursively
/// \brief Inlines all mandatory inlined functions into the body of a function,
/// first recursively inlining all mandatory apply instructions in those
/// functions into their bodies if necessary.
///
/// \param F the function to be processed
/// \param AI nullptr if this is being called from the top level; the relevant
/// ApplyInst requiring the recursive call when non-null
/// \param FullyInlinedSet the set of all functions already known to be fully
/// processed, to avoid processing them over again
/// \param SetFactory an instance of ImmutableFunctionSet::Factory
/// \param CurrentInliningSet the set of functions currently being inlined in
/// the current call stack of recursive calls
///
/// \returns true if successful, false if failed due to circular inlining.
static bool
runOnFunctionRecursively(SILFunction *F, FullApplySite AI,
SILModule::LinkingMode Mode,
DenseFunctionSet &FullyInlinedSet,
ImmutableFunctionSet::Factory &SetFactory,
ImmutableFunctionSet CurrentInliningSet,
ClassHierarchyAnalysis *CHA) {
// Avoid reprocessing functions needlessly.
if (FullyInlinedSet.count(F))
return true;
// Prevent attempt to circularly inline.
if (CurrentInliningSet.contains(F)) {
// This cannot happen on a top-level call, so AI should be non-null.
assert(AI && "Cannot have circular inline without apply");
SILLocation L = AI.getLoc();
assert(L && "Must have location for transparent inline apply");
diagnose(F->getModule().getASTContext(), L.getStartSourceLoc(),
diag::circular_transparent);
return false;
}
// Add to the current inlining set (immutably, so we only affect the set
// during this call and recursive subcalls).
CurrentInliningSet = SetFactory.add(CurrentInliningSet, F);
SmallVector<SILValue, 16> CaptureArgs;
SmallVector<SILValue, 32> FullArgs;
for (auto FI = F->begin(), FE = F->end(); FI != FE; ++FI) {
for (auto I = FI->begin(), E = FI->end(); I != E; ++I) {
FullApplySite InnerAI = FullApplySite::isa(&*I);
if (!InnerAI)
continue;
auto *ApplyBlock = InnerAI.getParent();
auto NewInstPair = tryDevirtualizeApply(InnerAI, CHA);
if (auto *NewInst = NewInstPair.first) {
replaceDeadApply(InnerAI, NewInst);
if (auto *II = dyn_cast<SILInstruction>(NewInst))
I = II->getIterator();
else
I = NewInst->getParentBlock()->begin();
auto NewAI = FullApplySite::isa(NewInstPair.second.getInstruction());
if (!NewAI)
continue;
InnerAI = NewAI;
}
SILLocation Loc = InnerAI.getLoc();
SILValue CalleeValue = InnerAI.getCallee();
bool IsThick;
PartialApplyInst *PAI;
SILFunction *CalleeFunction = getCalleeFunction(InnerAI, IsThick,
CaptureArgs, FullArgs,
PAI,
Mode);
if (!CalleeFunction ||
CalleeFunction->isTransparent() == IsNotTransparent)
continue;
if (F->isFragile() &&
!CalleeFunction->hasValidLinkageForFragileRef()) {
if (!CalleeFunction->hasValidLinkageForFragileInline()) {
llvm::errs() << "caller: " << F->getName() << "\n";
llvm::errs() << "callee: " << CalleeFunction->getName() << "\n";
llvm_unreachable("Should never be inlining a resilient function into "
"a fragile function");
}
continue;
}
// Then recursively process it first before trying to inline it.
if (!runOnFunctionRecursively(CalleeFunction, InnerAI, Mode,
FullyInlinedSet, SetFactory,
CurrentInliningSet, CHA)) {
// If we failed due to circular inlining, then emit some notes to
// trace back the failure if we have more information.
// FIXME: possibly it could be worth recovering and attempting other
// inlines within this same recursive call rather than simply
// propagating the failure.
if (AI) {
SILLocation L = AI.getLoc();
//.........这里部分代码省略.........
示例2: collectIndicesFromParameters
void MaterializeForSetEmitter::emit(SILGenFunction &gen, ManagedValue self,
SILValue resultBuffer,
SILValue callbackBuffer,
ArrayRef<ManagedValue> indices) {
SILLocation loc = Witness;
loc.markAutoGenerated();
// If there's an abstraction difference, we always need to use the
// get/set pattern.
AccessStrategy strategy;
if (WitnessStorage->getType()->is<ReferenceStorageType>() ||
(Conformance && RequirementStorageType != WitnessStorageType)) {
strategy = AccessStrategy::DispatchToAccessor;
} else {
strategy = WitnessStorage->getAccessStrategy(TheAccessSemantics,
AccessKind::ReadWrite);
}
// Handle the indices.
RValue indicesRV;
if (isa<SubscriptDecl>(WitnessStorage)) {
indicesRV = collectIndicesFromParameters(gen, loc, indices);
} else {
assert(indices.empty() && "indices for a non-subscript?");
}
// As above, assume that we don't need to reabstract 'self'.
// Choose the right implementation.
SILValue address;
SILFunction *callbackFn = nullptr;
switch (strategy) {
case AccessStrategy::Storage:
address = emitUsingStorage(gen, loc, self, std::move(indicesRV));
break;
case AccessStrategy::Addressor:
address = emitUsingAddressor(gen, loc, self, std::move(indicesRV),
callbackBuffer, callbackFn);
break;
case AccessStrategy::DirectToAccessor:
case AccessStrategy::DispatchToAccessor:
address = emitUsingGetterSetter(gen, loc, self, std::move(indicesRV),
resultBuffer, callbackBuffer, callbackFn);
break;
}
// Return the address as a Builtin.RawPointer.
SILType rawPointerTy = SILType::getRawPointerType(gen.getASTContext());
address = gen.B.createAddressToPointer(loc, address, rawPointerTy);
SILType resultTupleTy = gen.F.mapTypeIntoContext(
gen.F.getLoweredFunctionType()->getResult().getSILType());
SILType optCallbackTy = resultTupleTy.getTupleElementType(1);
// Form the callback.
SILValue callback;
if (callbackFn) {
// Make a reference to the function.
callback = gen.B.createFunctionRef(loc, callbackFn);
// If it's polymorphic, cast to RawPointer and then back to the
// right monomorphic type. The safety of this cast relies on some
// assumptions about what exactly IRGen can reconstruct from the
// callback's thick type argument.
if (callbackFn->getLoweredFunctionType()->isPolymorphic()) {
callback = gen.B.createThinFunctionToPointer(loc, callback, rawPointerTy);
OptionalTypeKind optKind;
auto callbackTy = optCallbackTy.getAnyOptionalObjectType(SGM.M, optKind);
callback = gen.B.createPointerToThinFunction(loc, callback, callbackTy);
}
callback = gen.B.createOptionalSome(loc, callback, optCallbackTy);
} else {
callback = gen.B.createOptionalNone(loc, optCallbackTy);
}
// Form the result and return.
auto result = gen.B.createTuple(loc, resultTupleTy, { address, callback });
gen.Cleanups.emitCleanupsForReturn(CleanupLocation::get(loc));
gen.B.createReturn(loc, result);
}
示例3: assert
/// \brief Make sure that all parameters are passed with a reference count
/// neutral parameter convention except for self.
bool swift::ArraySemanticsCall::isValidSignature() {
assert(SemanticsCall && getKind() != ArrayCallKind::kNone &&
"Need an array semantic call");
FunctionRefInst *FRI = cast<FunctionRefInst>(SemanticsCall->getCallee());
SILFunction *F = FRI->getReferencedFunction();
auto FnTy = F->getLoweredFunctionType();
auto &Mod = F->getModule();
// Check whether we have a valid signature for semantic calls that we hoist.
switch (getKind()) {
// All other calls can be consider valid.
default: break;
case ArrayCallKind::kArrayPropsIsNativeTypeChecked: {
// @guaranteed/@owned Self
if (SemanticsCall->getNumArguments() != 1)
return false;
auto SelfConvention = FnTy->getSelfParameter().getConvention();
return SelfConvention == ParameterConvention::Direct_Guaranteed ||
SelfConvention == ParameterConvention::Direct_Owned;
}
case ArrayCallKind::kCheckIndex: {
// Int, @guaranteed/@owned Self
if (SemanticsCall->getNumArguments() != 2 ||
!SemanticsCall->getArgument(0).getType().isTrivial(Mod))
return false;
auto SelfConvention = FnTy->getSelfParameter().getConvention();
return SelfConvention == ParameterConvention::Direct_Guaranteed ||
SelfConvention == ParameterConvention::Direct_Owned;
}
case ArrayCallKind::kCheckSubscript: {
// Int, Bool, Self
if (SemanticsCall->getNumArguments() != 3 ||
!SemanticsCall->getArgument(0).getType().isTrivial(Mod))
return false;
if (!SemanticsCall->getArgument(1).getType().isTrivial(Mod))
return false;
auto SelfConvention = FnTy->getSelfParameter().getConvention();
return SelfConvention == ParameterConvention::Direct_Guaranteed ||
SelfConvention == ParameterConvention::Direct_Owned;
}
case ArrayCallKind::kMakeMutable: {
auto SelfConvention = FnTy->getSelfParameter().getConvention();
return SelfConvention == ParameterConvention::Indirect_Inout;
}
case ArrayCallKind::kArrayUninitialized: {
// Make sure that if we are a _adoptStorage call that our storage is
// uniquely referenced by us.
SILValue Arg0 = SemanticsCall->getArgument(0);
if (Arg0.getType().isExistentialType()) {
auto *AllocBufferAI = dyn_cast<ApplyInst>(Arg0);
if (!AllocBufferAI)
return false;
auto *AllocFn = AllocBufferAI->getCalleeFunction();
if (!AllocFn)
return false;
StringRef AllocFuncName = AllocFn->getName();
if (AllocFuncName != "swift_bufferAllocate" &&
AllocFuncName != "swift_bufferAllocateOnStack")
return false;
if (!hasOneNonDebugUse(*AllocBufferAI))
return false;
}
return true;
}
}
return true;
}
示例4: devirtualizeAppliesInFunction
bool Devirtualizer::devirtualizeAppliesInFunction(SILFunction &F,
ClassHierarchyAnalysis *CHA) {
bool Changed = false;
llvm::SmallVector<SILInstruction *, 8> DeadApplies;
llvm::SmallVector<ApplySite, 8> NewApplies;
for (auto &BB : F) {
for (auto It = BB.begin(), End = BB.end(); It != End;) {
auto &I = *It++;
// Skip non-apply instructions.
auto Apply = FullApplySite::isa(&I);
if (!Apply)
continue;
auto NewInstPair = tryDevirtualizeApply(Apply, CHA);
if (!NewInstPair.second)
continue;
Changed = true;
auto *AI = Apply.getInstruction();
if (!isa<TryApplyInst>(AI))
AI->replaceAllUsesWith(NewInstPair.first);
DeadApplies.push_back(AI);
NewApplies.push_back(NewInstPair.second);
}
}
// Remove all the now-dead applies.
while (!DeadApplies.empty()) {
auto *AI = DeadApplies.pop_back_val();
recursivelyDeleteTriviallyDeadInstructions(AI, true);
}
// For each new apply, attempt to link in function bodies if we do
// not already have them, then notify the pass manager of the new
// functions.
//
// We do this after deleting the old applies because otherwise we
// hit verification errors in the linking code due to having
// non-cond_br critical edges.
while (!NewApplies.empty()) {
auto Apply = NewApplies.pop_back_val();
auto *CalleeFn = Apply.getReferencedFunction();
assert(CalleeFn && "Expected devirtualized callee!");
// FIXME: Until we link everything in up front we need to ensure
// that we link after devirtualizing in order to pull in
// everything we reference from the stdlib. After we do that we
// can move the notification code below back into the main loop
// above.
if (!CalleeFn->isDefinition())
F.getModule().linkFunction(CalleeFn, SILModule::LinkingMode::LinkAll);
// We may not have optimized these functions yet, and it could
// be beneficial to rerun some earlier passes on the current
// function now that we've made these direct references visible.
if (CalleeFn->isDefinition() && CalleeFn->shouldOptimize())
notifyPassManagerOfFunction(CalleeFn, nullptr);
}
return Changed;
}
示例5: assert
SILFunction *SILModule::findFunction(StringRef Name, SILLinkage Linkage) {
assert((Linkage == SILLinkage::Public ||
Linkage == SILLinkage::PublicExternal) &&
"Only a lookup of public functions is supported currently");
SILFunction *F = nullptr;
// First, check if there is a function with a required name in the
// current module.
SILFunction *CurF = lookUpFunction(Name);
// Nothing to do if the current module has a required function
// with a proper linkage already.
if (CurF && CurF->getLinkage() == Linkage) {
F = CurF;
} else {
assert((!CurF || CurF->getLinkage() != Linkage) &&
"hasFunction should be only called for functions that are not "
"contained in the SILModule yet or do not have a required linkage");
}
if (!F) {
SILLinkerVisitor Visitor(*this, getSILLoader(),
SILModule::LinkingMode::LinkNormal);
if (CurF) {
// Perform this lookup only if a function with a given
// name is present in the current module.
// This is done to reduce the amount of IO from the
// swift module file.
if (!Visitor.hasFunction(Name, Linkage))
return nullptr;
// The function in the current module will be changed.
F = CurF;
}
// If function with a given name wasn't seen anywhere yet
// or if it is known to exist, perform a lookup.
if (!F) {
// Try to load the function from other modules.
F = Visitor.lookupFunction(Name, Linkage);
// Bail if nothing was found and we are not sure if
// this function exists elsewhere.
if (!F)
return nullptr;
assert(F && "SILFunction should be present in one of the modules");
assert(F->getLinkage() == Linkage && "SILFunction has a wrong linkage");
}
}
// If a function exists already and it is a non-optimizing
// compilation, simply convert it into an external declaration,
// so that a compiled version from the shared library is used.
if (F->isDefinition() &&
F->getModule().getOptions().Optimization <
SILOptions::SILOptMode::Optimize) {
F->convertToDeclaration();
}
if (F->isExternalDeclaration())
F->setSerialized(IsSerialized_t::IsNotSerialized);
F->setLinkage(Linkage);
return F;
}
示例6: ArgumentExplosionFinalizeOptimizedFunction
void FunctionSignatureTransform::ArgumentExplosionFinalizeOptimizedFunction() {
SILFunction *NewF = TransformDescriptor.OptimizedFunction.get();
SILBasicBlock *BB = &*NewF->begin();
SILBuilder Builder(BB->begin());
Builder.setCurrentDebugScope(BB->getParent()->getDebugScope());
unsigned TotalArgIndex = 0;
for (ArgumentDescriptor &AD : TransformDescriptor.ArgumentDescList) {
// If this argument descriptor was dead and we removed it, just skip it. Do
// not increment the argument index.
if (AD.WasErased) {
continue;
}
// Simply continue if do not explode.
if (!AD.Explode) {
TransformDescriptor.AIM[TotalArgIndex] = AD.Index;
++TotalArgIndex;
continue;
}
assert(!AD.IsEntirelyDead &&
"Should never see completely dead values here");
// OK, we need to explode this argument.
unsigned ArgOffset = ++TotalArgIndex;
unsigned OldArgIndex = ArgOffset - 1;
llvm::SmallVector<SILValue, 8> LeafValues;
// We do this in the same order as leaf types since ProjTree expects that
// the order of leaf values matches the order of leaf types.
llvm::SmallVector<const ProjectionTreeNode *, 8> LeafNodes;
AD.ProjTree.getLiveLeafNodes(LeafNodes);
for (auto *Node : LeafNodes) {
auto OwnershipKind = *AD.getTransformedOwnershipKind(Node->getType());
LeafValues.push_back(
BB->insertFunctionArgument(ArgOffset, Node->getType(), OwnershipKind,
BB->getArgument(OldArgIndex)->getDecl()));
TransformDescriptor.AIM[TotalArgIndex - 1] = AD.Index;
++ArgOffset;
++TotalArgIndex;
}
// Then go through the projection tree constructing aggregates and replacing
// uses.
AD.ProjTree.replaceValueUsesWithLeafUses(
Builder, BB->getParent()->getLocation(), LeafValues);
// We ignored debugvalue uses when we constructed the new arguments, in
// order to preserve as much information as possible, we construct a new
// value for OrigArg from the leaf values and use that in place of the
// OrigArg.
SILValue NewOrigArgValue = AD.ProjTree.computeExplodedArgumentValue(
Builder, BB->getParent()->getLocation(), LeafValues);
// Replace all uses of the original arg with the new value.
SILArgument *OrigArg = BB->getArgument(OldArgIndex);
OrigArg->replaceAllUsesWith(NewOrigArgValue);
// Now erase the old argument since it does not have any uses. We also
// decrement ArgOffset since we have one less argument now.
BB->eraseArgument(OldArgIndex);
--TotalArgIndex;
}
}
示例7: if
// Returns the callee of an apply_inst if it is basically inlineable.
SILFunction *SILPerformanceInliner::getEligibleFunction(FullApplySite AI) {
SILFunction *Callee = AI.getReferencedFunction();
if (!Callee) {
return nullptr;
}
// Don't inline functions that are marked with the @_semantics or @effects
// attribute if the inliner is asked not to inline them.
if (Callee->hasSemanticsAttrs() || Callee->hasEffectsKind()) {
if (WhatToInline == InlineSelection::NoSemanticsAndGlobalInit) {
return nullptr;
}
// The "availability" semantics attribute is treated like global-init.
if (Callee->hasSemanticsAttrs() &&
WhatToInline != InlineSelection::Everything &&
Callee->hasSemanticsAttrThatStartsWith("availability")) {
return nullptr;
}
} else if (Callee->isGlobalInit()) {
if (WhatToInline != InlineSelection::Everything) {
return nullptr;
}
}
// We can't inline external declarations.
if (Callee->empty() || Callee->isExternalDeclaration()) {
return nullptr;
}
// Explicitly disabled inlining.
if (Callee->getInlineStrategy() == NoInline) {
return nullptr;
}
if (!Callee->shouldOptimize()) {
return nullptr;
}
// We don't support this yet.
if (AI.hasSubstitutions()) {
return nullptr;
}
// We don't support inlining a function that binds dynamic self because we
// have no mechanism to preserve the original function's local self metadata.
if (computeMayBindDynamicSelf(Callee)) {
return nullptr;
}
SILFunction *Caller = AI.getFunction();
// Detect self-recursive calls.
if (Caller == Callee) {
return nullptr;
}
// A non-fragile function may not be inlined into a fragile function.
if (Caller->isFragile() && !Callee->isFragile()) {
return nullptr;
}
// Inlining self-recursive functions into other functions can result
// in excessive code duplication since we run the inliner multiple
// times in our pipeline
if (calleeIsSelfRecursive(Callee)) {
return nullptr;
}
return Callee;
}
示例8: removeGuaranteedRetainReleasePairs
/// Remove retain/release pairs around builtin "unsafeGuaranteed" instruction
/// sequences.
static bool removeGuaranteedRetainReleasePairs(SILFunction &F,
RCIdentityFunctionInfo &RCIA) {
DEBUG(llvm::dbgs() << "Running on function " << F.getName() << "\n");
bool Changed = false;
for (auto &BB : F) {
auto It = BB.begin(), End = BB.end();
llvm::DenseMap<SILValue, SILInstruction *> LastRetain;
while (It != End) {
auto *CurInst = &*It;
++It;
// Memorize the last retain.
if (isa<StrongRetainInst>(CurInst) || isa<RetainValueInst>(CurInst)) {
LastRetain[RCIA.getRCIdentityRoot(CurInst->getOperand(0))] = CurInst;
continue;
}
// Look for a builtin "unsafeGuaranteed" instruction.
auto *UnsafeGuaranteedI = dyn_cast<BuiltinInst>(CurInst);
if (!UnsafeGuaranteedI || !UnsafeGuaranteedI->getBuiltinKind() ||
*UnsafeGuaranteedI->getBuiltinKind() !=
BuiltinValueKind::UnsafeGuaranteed)
continue;
auto Opd = UnsafeGuaranteedI->getOperand(0);
auto RCIdOpd = RCIA.getRCIdentityRoot(UnsafeGuaranteedI->getOperand(0));
if (!LastRetain.count(RCIdOpd)) {
DEBUG(llvm::dbgs() << "LastRetain failed\n");
continue;
}
// This code is very conservative. Check that there is a matching retain
// before the unsafeGuaranteed builtin with only retains inbetween.
auto *LastRetainInst = LastRetain[RCIdOpd];
auto NextInstIter = std::next(SILBasicBlock::iterator(LastRetainInst));
while (NextInstIter != BB.end() && &*NextInstIter != CurInst &&
(isa<RetainValueInst>(*NextInstIter) ||
isa<StrongRetainInst>(*NextInstIter) ||
!NextInstIter->mayHaveSideEffects() ||
isa<DebugValueInst>(*NextInstIter) ||
isa<DebugValueAddrInst>(*NextInstIter)))
++NextInstIter;
if (&*NextInstIter != CurInst) {
DEBUG(llvm::dbgs() << "Last retain right before match failed\n");
continue;
}
DEBUG(llvm::dbgs() << "Saw " << *UnsafeGuaranteedI);
DEBUG(llvm::dbgs() << " with operand " << *Opd);
// Match the reference and token result.
// %4 = builtin "unsafeGuaranteed"<Foo>(%0 : $Foo)
// %5 = tuple_extract %4 : $(Foo, Builtin.Int8), 0
// %6 = tuple_extract %4 : $(Foo, Builtin.Int8), 1
SILInstruction *UnsafeGuaranteedValue;
SILInstruction *UnsafeGuaranteedToken;
std::tie(UnsafeGuaranteedValue, UnsafeGuaranteedToken) =
getSingleUnsafeGuaranteedValueResult(UnsafeGuaranteedI);
if (!UnsafeGuaranteedValue) {
DEBUG(llvm::dbgs() << " no single unsafeGuaranteed value use\n");
continue;
}
// Look for a builtin "unsafeGuaranteedEnd" instruction that uses the
// token.
// builtin "unsafeGuaranteedEnd"(%6 : $Builtin.Int8) : $()
BuiltinInst *UnsafeGuaranteedEndI = nullptr;
for (auto *Operand : getNonDebugUses(UnsafeGuaranteedToken)) {
if (UnsafeGuaranteedEndI) {
DEBUG(llvm::dbgs() << " multiple unsafeGuaranteedEnd users\n");
UnsafeGuaranteedEndI = nullptr;
break;
}
auto *BI = dyn_cast<BuiltinInst>(Operand->getUser());
if (!BI || !BI->getBuiltinKind() ||
*BI->getBuiltinKind() != BuiltinValueKind::UnsafeGuaranteedEnd) {
DEBUG(llvm::dbgs() << " wrong unsafeGuaranteed token user "
<< *Operand->getUser());
break;
}
UnsafeGuaranteedEndI = BI;
}
if (!UnsafeGuaranteedEndI) {
DEBUG(llvm::dbgs() << " no single unsafeGuaranteedEnd use found\n");
continue;
}
if (SILBasicBlock::iterator(UnsafeGuaranteedEndI) ==
UnsafeGuaranteedEndI->getParent()->end())
continue;
// Find the release to match with the unsafeGuaranteedValue.
auto &UnsafeGuaranteedEndBB = *UnsafeGuaranteedEndI->getParent();
auto LastRelease = findReleaseToMatchUnsafeGuaranteedValue(
UnsafeGuaranteedEndI, UnsafeGuaranteedI, UnsafeGuaranteedValue,
//.........这里部分代码省略.........
示例9: assert
/// Bridge argument types and adjust retain count conventions for an ObjC thunk.
static SILFunctionType *emitObjCThunkArguments(SILGenFunction &gen,
SILLocation loc,
SILDeclRef thunk,
SmallVectorImpl<SILValue> &args,
SILValue &foreignErrorSlot,
Optional<ForeignErrorConvention> &foreignError) {
SILDeclRef native = thunk.asForeign(false);
auto mod = gen.SGM.M.getSwiftModule();
auto subs = gen.F.getForwardingSubstitutions();
auto objcInfo = gen.SGM.Types.getConstantInfo(thunk);
auto objcFnTy = objcInfo.SILFnType->substGenericArgs(gen.SGM.M, mod, subs);
auto swiftInfo = gen.SGM.Types.getConstantInfo(native);
auto swiftFnTy = swiftInfo.SILFnType->substGenericArgs(gen.SGM.M, mod, subs);
// We must have the same context archetypes as the unthunked function.
assert(objcInfo.ContextGenericParams == swiftInfo.ContextGenericParams);
SmallVector<ManagedValue, 8> bridgedArgs;
bridgedArgs.reserve(objcFnTy->getParameters().size());
SILFunction *orig = gen.SGM.getFunction(native, NotForDefinition);
// Find the foreign error convention if we have one.
if (orig->getLoweredFunctionType()->hasErrorResult()) {
auto func = cast<AbstractFunctionDecl>(thunk.getDecl());
foreignError = func->getForeignErrorConvention();
assert(foreignError && "couldn't find foreign error convention!");
}
// Emit the indirect result arguments, if any.
// FIXME: we're just assuming that these match up exactly?
for (auto indirectResult : objcFnTy->getIndirectResults()) {
SILType argTy = gen.F.mapTypeIntoContext(indirectResult.getSILType());
auto arg = new (gen.F.getModule()) SILArgument(gen.F.begin(), argTy);
args.push_back(arg);
}
// Emit the other arguments, taking ownership of arguments if necessary.
auto inputs = objcFnTy->getParameters();
auto nativeInputs = swiftFnTy->getParameters();
assert(inputs.size() ==
nativeInputs.size() + unsigned(foreignError.hasValue()));
for (unsigned i = 0, e = inputs.size(); i < e; ++i) {
SILType argTy = gen.F.mapTypeIntoContext(inputs[i].getSILType());
SILValue arg = new(gen.F.getModule()) SILArgument(gen.F.begin(), argTy);
// If this parameter is the foreign error slot, pull it out.
// It does not correspond to a native argument.
if (foreignError && i == foreignError->getErrorParameterIndex()) {
foreignErrorSlot = arg;
continue;
}
// If this parameter is deallocating, emit an unmanaged rvalue and
// continue. The object has the deallocating bit set so retain, release is
// irrelevant.
if (inputs[i].isDeallocating()) {
bridgedArgs.push_back(ManagedValue::forUnmanaged(arg));
continue;
}
// If the argument is a block, copy it.
if (argTy.isBlockPointerCompatible()) {
auto copy = gen.B.createCopyBlock(loc, arg);
// If the argument is consumed, we're still responsible for releasing the
// original.
if (inputs[i].isConsumed())
gen.emitManagedRValueWithCleanup(arg);
arg = copy;
}
// Convert the argument to +1 if necessary.
else if (!inputs[i].isConsumed()) {
arg = emitObjCUnconsumedArgument(gen, loc, arg);
}
auto managedArg = gen.emitManagedRValueWithCleanup(arg);
bridgedArgs.push_back(managedArg);
}
assert(bridgedArgs.size() + unsigned(foreignError.hasValue())
== objcFnTy->getParameters().size() &&
"objc inputs don't match number of arguments?!");
assert(bridgedArgs.size() == swiftFnTy->getNumSILArguments() &&
"swift inputs don't match number of arguments?!");
assert((foreignErrorSlot || !foreignError) &&
"didn't find foreign error slot");
// Bridge the input types.
Scope scope(gen.Cleanups, CleanupLocation::get(loc));
assert(bridgedArgs.size() == nativeInputs.size());
for (unsigned i = 0, size = bridgedArgs.size(); i < size; ++i) {
SILType argTy = gen.F.mapTypeIntoContext(
swiftFnTy->getParameters()[i].getSILType());
ManagedValue native =
gen.emitBridgedToNativeValue(loc,
//.........这里部分代码省略.........
示例10: if
// Returns the callee of an apply_inst if it is basically inlineable.
SILFunction *SILPerformanceInliner::getEligibleFunction(FullApplySite AI) {
SILFunction *Callee = AI.getReferencedFunction();
if (!Callee) {
return nullptr;
}
// Don't inline functions that are marked with the @_semantics or @effects
// attribute if the inliner is asked not to inline them.
if (Callee->hasSemanticsAttrs() || Callee->hasEffectsKind()) {
if (WhatToInline == InlineSelection::NoSemanticsAndGlobalInit) {
return nullptr;
}
// The "availability" semantics attribute is treated like global-init.
if (Callee->hasSemanticsAttrs() &&
WhatToInline != InlineSelection::Everything &&
Callee->hasSemanticsAttrThatStartsWith("availability")) {
return nullptr;
}
} else if (Callee->isGlobalInit()) {
if (WhatToInline != InlineSelection::Everything) {
return nullptr;
}
}
// We can't inline external declarations.
if (Callee->empty() || Callee->isExternalDeclaration()) {
return nullptr;
}
// Explicitly disabled inlining.
if (Callee->getInlineStrategy() == NoInline) {
return nullptr;
}
if (!Callee->shouldOptimize()) {
return nullptr;
}
// We don't support this yet.
if (AI.hasSubstitutions())
return nullptr;
SILFunction *Caller = AI.getFunction();
// We don't support inlining a function that binds dynamic self because we
// have no mechanism to preserve the original function's local self metadata.
if (mayBindDynamicSelf(Callee)) {
// Check if passed Self is the same as the Self of the caller.
// In this case, it is safe to inline because both functions
// use the same Self.
if (AI.hasSelfArgument() && Caller->hasSelfParam()) {
auto CalleeSelf = stripCasts(AI.getSelfArgument());
auto CallerSelf = Caller->getSelfArgument();
if (CalleeSelf != SILValue(CallerSelf))
return nullptr;
} else
return nullptr;
}
// Detect self-recursive calls.
if (Caller == Callee) {
return nullptr;
}
// A non-fragile function may not be inlined into a fragile function.
if (Caller->isFragile() &&
!Callee->hasValidLinkageForFragileInline()) {
if (!Callee->hasValidLinkageForFragileRef()) {
llvm::errs() << "caller: " << Caller->getName() << "\n";
llvm::errs() << "callee: " << Callee->getName() << "\n";
llvm_unreachable("Should never be inlining a resilient function into "
"a fragile function");
}
return nullptr;
}
// Inlining self-recursive functions into other functions can result
// in excessive code duplication since we run the inliner multiple
// times in our pipeline
if (calleeIsSelfRecursive(Callee)) {
return nullptr;
}
return Callee;
}
示例11: isProfitableToInline
bool SILPerformanceInliner::isProfitableToInline(FullApplySite AI,
Weight CallerWeight,
ConstantTracker &callerTracker,
int &NumCallerBlocks,
bool IsGeneric) {
SILFunction *Callee = AI.getReferencedFunction();
SILLoopInfo *LI = LA->get(Callee);
ShortestPathAnalysis *SPA = getSPA(Callee, LI);
assert(SPA->isValid());
ConstantTracker constTracker(Callee, &callerTracker, AI);
DominanceInfo *DT = DA->get(Callee);
SILBasicBlock *CalleeEntry = &Callee->front();
DominanceOrder domOrder(CalleeEntry, DT, Callee->size());
// Calculate the inlining cost of the callee.
int CalleeCost = 0;
int Benefit = 0;
// Start with a base benefit.
int BaseBenefit = RemovedCallBenefit;
const SILOptions &Opts = Callee->getModule().getOptions();
// For some reason -Ounchecked can accept a higher base benefit without
// increasing the code size too much.
if (Opts.Optimization == SILOptions::SILOptMode::OptimizeUnchecked)
BaseBenefit *= 2;
CallerWeight.updateBenefit(Benefit, BaseBenefit);
// Go through all blocks of the function, accumulate the cost and find
// benefits.
while (SILBasicBlock *block = domOrder.getNext()) {
constTracker.beginBlock();
Weight BlockW = SPA->getWeight(block, CallerWeight);
for (SILInstruction &I : *block) {
constTracker.trackInst(&I);
CalleeCost += (int)instructionInlineCost(I);
if (FullApplySite AI = FullApplySite::isa(&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)))
BlockW.updateBenefit(Benefit, RemovedClosureBenefit);
} else if (auto *LI = dyn_cast<LoadInst>(&I)) {
// Check if it's a load from a stack location in the caller. Such a load
// might be optimized away if inlined.
if (constTracker.isStackAddrInCaller(LI->getOperand()))
BlockW.updateBenefit(Benefit, RemovedLoadBenefit);
} else if (auto *SI = dyn_cast<StoreInst>(&I)) {
// Check if it's a store to a stack location in the caller. Such a load
// might be optimized away if inlined.
if (constTracker.isStackAddrInCaller(SI->getDest()))
BlockW.updateBenefit(Benefit, RemovedStoreBenefit);
} else if (isa<StrongReleaseInst>(&I) || isa<ReleaseValueInst>(&I)) {
SILValue Op = stripCasts(I.getOperand(0));
if (SILArgument *Arg = dyn_cast<SILArgument>(Op)) {
if (Arg->isFunctionArg() && Arg->getArgumentConvention() ==
SILArgumentConvention::Direct_Guaranteed) {
BlockW.updateBenefit(Benefit, RefCountBenefit);
}
}
} else if (auto *BI = dyn_cast<BuiltinInst>(&I)) {
if (BI->getBuiltinInfo().ID == BuiltinValueKind::OnFastPath)
BlockW.updateBenefit(Benefit, FastPathBuiltinBenefit);
}
}
// Don't count costs in blocks which are dead after inlining.
SILBasicBlock *takenBlock = constTracker.getTakenBlock(block->getTerminator());
if (takenBlock) {
BlockW.updateBenefit(Benefit, RemovedTerminatorBenefit);
domOrder.pushChildrenIf(block, [=] (SILBasicBlock *child) {
return child->getSinglePredecessor() != block || child == takenBlock;
});
} else {
domOrder.pushChildren(block);
}
}
if (AI.getFunction()->isThunk()) {
// Only inline trivial functions into thunks (which will not increase the
// code size).
if (CalleeCost > TrivialFunctionThreshold)
return false;
DEBUG(
dumpCaller(AI.getFunction());
llvm::dbgs() << " decision {" << CalleeCost << " into thunk} " <<
Callee->getName() << '\n';
);
return true;
}
示例12: specializePartialApply
/// Specialize a partial_apply by promoting the parameters indicated by
/// indices. We expect these parameters to be replaced by stack address
/// references.
static PartialApplyInst *
specializePartialApply(PartialApplyInst *PartialApply,
ParamIndexList &PromotedParamIndices,
bool &CFGChanged) {
auto *FRI = cast<FunctionRefInst>(PartialApply->getCallee());
assert(FRI && "Expected a direct partial_apply!");
auto *F = FRI->getReferencedFunction();
assert(F && "Expected a referenced function!");
IsFragile_t Fragile = IsNotFragile;
if (PartialApply->getFunction()->isFragile() && F->isFragile())
Fragile = IsFragile;
std::string ClonedName = getClonedName(F, Fragile, PromotedParamIndices);
auto &M = PartialApply->getModule();
SILFunction *ClonedFn;
if (auto *PrevFn = M.lookUpFunction(ClonedName)) {
assert(PrevFn->isFragile() == Fragile);
ClonedFn = PrevFn;
} else {
// Clone the function the existing partial_apply references.
PromotedParamCloner Cloner(F, Fragile, PromotedParamIndices, ClonedName);
Cloner.populateCloned();
ClonedFn = Cloner.getCloned();
}
// Now create the new partial_apply using the cloned function.
llvm::SmallVector<SILValue, 16> Args;
ValueLifetimeAnalysis::Frontier PAFrontier;
// Promote the arguments that need promotion.
for (auto &O : PartialApply->getArgumentOperands()) {
auto ParamIndex = getParameterIndexForOperand(&O);
if (!count(PromotedParamIndices, ParamIndex)) {
Args.push_back(O.get());
continue;
}
// If this argument is promoted, it is a box that we're
// turning into an address because we've proven we can
// keep this value on the stack. The partial_apply had ownership
// of this box so we must now release it explicitly when the
// partial_apply is released.
auto box = cast<AllocBoxInst>(O.get());
// If the box address has a MUI, route accesses through it so DI still
// works.
SILInstruction *promoted = nullptr;
int numAddrUses = 0;
for (Operand *BoxUse : box->getUses()) {
if (auto *PBI = dyn_cast<ProjectBoxInst>(BoxUse->getUser())) {
for (auto PBIUse : PBI->getUses()) {
numAddrUses++;
if (auto MUI = dyn_cast<MarkUninitializedInst>(PBIUse->getUser()))
promoted = MUI;
}
}
}
assert((!promoted || numAddrUses == 1) &&
"box value used by mark_uninitialized but not exclusively!");
// We only reuse an existing project_box if it directly follows the
// alloc_box. This makes sure that the project_box dominates the
// partial_apply.
if (!promoted)
promoted = getOrCreateProjectBox(box);
Args.push_back(promoted);
if (PAFrontier.empty()) {
ValueLifetimeAnalysis VLA(PartialApply);
CFGChanged |= !VLA.computeFrontier(PAFrontier,
ValueLifetimeAnalysis::AllowToModifyCFG);
assert(!PAFrontier.empty() && "partial_apply must have at least one use "
"to release the returned function");
}
// Insert releases after each point where the partial_apply becomes dead.
for (SILInstruction *FrontierInst : PAFrontier) {
SILBuilderWithScope Builder(FrontierInst);
Builder.emitStrongReleaseAndFold(PartialApply->getLoc(), O.get());
}
}
SILBuilderWithScope Builder(PartialApply);
// Build the function_ref and partial_apply.
SILValue FunctionRef = Builder.createFunctionRef(PartialApply->getLoc(),
ClonedFn);
CanSILFunctionType CanFnTy = ClonedFn->getLoweredFunctionType();
auto const &Subs = PartialApply->getSubstitutions();
CanSILFunctionType SubstCalleeTy = CanFnTy->substGenericArgs(M,
M.getSwiftModule(),
Subs);
//.........这里部分代码省略.........
示例13: doesDestructorHaveSideEffects
/// Analyze the destructor for the class of ARI to see if any instructions in it
/// could have side effects on the program outside the destructor. If it does
/// not, then we can eliminate the destructor.
static bool doesDestructorHaveSideEffects(AllocRefInst *ARI) {
SILFunction *Fn = getDestructor(ARI);
// If we can't find a constructor then assume it has side effects.
if (!Fn)
return true;
// A destructor only has one argument, self.
assert(Fn->begin()->getNumArguments() == 1 &&
"Destructor should have only one argument, self.");
SILArgument *Self = Fn->begin()->getArgument(0);
LLVM_DEBUG(llvm::dbgs() << " Analyzing destructor.\n");
// For each BB in the destructor...
for (auto &BB : *Fn)
// For each instruction I in BB...
for (auto &I : BB) {
LLVM_DEBUG(llvm::dbgs() << " Visiting: " << I);
// If I has no side effects, we can ignore it.
if (!I.mayHaveSideEffects()) {
LLVM_DEBUG(llvm::dbgs() << " SAFE! Instruction has no side "
"effects.\n");
continue;
}
// RefCounting operations on Self are ok since we are already in the
// destructor. RefCountingOperations on other instructions could have side
// effects though.
if (auto *RefInst = dyn_cast<RefCountingInst>(&I)) {
if (stripCasts(RefInst->getOperand(0)) == Self) {
// For now all ref counting insts have 1 operand. Put in an assert
// just in case.
assert(RefInst->getNumOperands() == 1 &&
"Make sure RefInst only has one argument.");
LLVM_DEBUG(llvm::dbgs() << " SAFE! Ref count operation on "
"Self.\n");
continue;
} else {
LLVM_DEBUG(llvm::dbgs() << " UNSAFE! Ref count operation "
"not on self.\n");
return true;
}
}
// dealloc_stack can be ignored.
if (isa<DeallocStackInst>(I)) {
LLVM_DEBUG(llvm::dbgs() << " SAFE! dealloc_stack can be "
"ignored.\n");
continue;
}
// dealloc_ref on self can be ignored, but dealloc_ref on anything else
// cannot be eliminated.
if (auto *DeallocRef = dyn_cast<DeallocRefInst>(&I)) {
if (stripCasts(DeallocRef->getOperand()) == Self) {
LLVM_DEBUG(llvm::dbgs() <<" SAFE! dealloc_ref on self.\n");
continue;
} else {
LLVM_DEBUG(llvm::dbgs() << " UNSAFE! dealloc_ref on value "
"besides self.\n");
return true;
}
}
// Storing into the object can be ignored.
if (auto *SI = dyn_cast<StoreInst>(&I))
if (stripAddressProjections(SI->getDest()) == Self) {
LLVM_DEBUG(llvm::dbgs() << " SAFE! Instruction is a store "
"into self.\n");
continue;
}
LLVM_DEBUG(llvm::dbgs() << " UNSAFE! Unknown instruction.\n");
// Otherwise, we can't remove the deallocation completely.
return true;
}
// We didn't find any side effects.
return false;
}
示例14: specializePartialApply
/// Specialize a partial_apply by promoting the parameters indicated by
/// indices. We expect these parameters to be replaced by stack address
/// references.
static PartialApplyInst *
specializePartialApply(PartialApplyInst *PartialApply,
ParamIndexList &PromotedParamIndices) {
auto *FRI = cast<FunctionRefInst>(PartialApply->getCallee());
assert(FRI && "Expected a direct partial_apply!");
auto *F = FRI->getReferencedFunction();
assert(F && "Expected a referenced function!");
std::string ClonedName = getClonedName(F, PromotedParamIndices);
auto &M = PartialApply->getModule();
SILFunction *ClonedFn;
if (auto *PrevFn = M.lookUpFunction(ClonedName)) {
ClonedFn = PrevFn;
} else {
// Clone the function the existing partial_apply references.
PromotedParamCloner Cloner(F, PromotedParamIndices, ClonedName);
Cloner.populateCloned();
ClonedFn = Cloner.getCloned();
}
// Now create the new partial_apply using the cloned function.
llvm::SmallVector<SILValue, 16> Args;
LifetimeTracker Lifetime(PartialApply);
// Promote the arguments that need promotion.
for (auto &O : PartialApply->getArgumentOperands()) {
auto ParamIndex = getParameterIndexForOperand(&O);
if (!std::count(PromotedParamIndices.begin(), PromotedParamIndices.end(),
ParamIndex)) {
Args.push_back(O.get());
continue;
}
auto Endpoints = Lifetime.getEndpoints();
// If this argument is promoted, it is a box that we're
// turning into an address because we've proven we can
// keep this value on the stack. The partial_apply had ownership
// of this box so we must now release it explicitly when the
// partial_apply is released.
auto box = cast<AllocBoxInst>(O.get());
// If the box address has a MUI, route accesses through it so DI still
// works.
SILInstruction *promoted = nullptr;
int numAddrUses = 0;
for (Operand *BoxUse : box->getUses()) {
if (auto *PBI = dyn_cast<ProjectBoxInst>(BoxUse->getUser())) {
for (auto PBIUse : PBI->getUses()) {
numAddrUses++;
if (auto MUI = dyn_cast<MarkUninitializedInst>(PBIUse->getUser()))
promoted = MUI;
}
}
}
assert((!promoted || numAddrUses == 1) &&
"box value used by mark_uninitialized but not exclusively!");
// We only reuse an existing project_box if it directly follows the
// alloc_box. This makes sure that the project_box dominates the
// partial_apply.
if (!promoted)
promoted = getOrCreateProjectBox(box);
Args.push_back(promoted);
// If the partial_apply is dead, insert a release after it.
if (Endpoints.begin() == Endpoints.end()) {
emitStrongReleaseAfter(O.get(), PartialApply);
continue;
}
// Otherwise insert releases after each point where the
// partial_apply becomes dead.
for (auto *User : Endpoints) {
assert((isa<StrongReleaseInst>(User) || isa<ApplyInst>(User)) &&
"Unexpected end of lifetime for partial_apply!");
emitStrongReleaseAfter(O.get(), User);
}
}
SILBuilderWithScope Builder(PartialApply);
// Build the function_ref and partial_apply.
SILValue FunctionRef = Builder.createFunctionRef(PartialApply->getLoc(),
ClonedFn);
CanSILFunctionType CanFnTy = ClonedFn->getLoweredFunctionType();
auto const &Subs = PartialApply->getSubstitutions();
CanSILFunctionType SubstCalleeTy = CanFnTy->substGenericArgs(M,
M.getSwiftModule(),
Subs);
return Builder.createPartialApply(PartialApply->getLoc(), FunctionRef,
SILType::getPrimitiveObjectType(SubstCalleeTy),
PartialApply->getSubstitutions(), Args,
//.........这里部分代码省略.........
示例15: gatherCallSites
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);
//.........这里部分代码省略.........