Files
swift-mirror/lib/IRGen/Outlining.cpp
2025-10-23 15:36:54 -04:00

687 lines
24 KiB
C++

//===--- Outlining.cpp - Outlining value operations -----------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements IR generation for outlined value operations in Swift.
//
//===----------------------------------------------------------------------===//
#include "Outlining.h"
#include "Explosion.h"
#include "GenOpaque.h"
#include "GenProto.h"
#include "GenericRequirement.h"
#include "IRGenFunction.h"
#include "IRGenMangler.h"
#include "IRGenModule.h"
#include "LoadableTypeInfo.h"
#include "LocalTypeDataKind.h"
#include "MetadataRequest.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/IRGenOptions.h"
#include "swift/Basic/Assertions.h"
#include "swift/IRGen/GenericRequirement.h"
#include "swift/IRGen/Linking.h"
#include "swift/SIL/SILModule.h"
using namespace swift;
using namespace irgen;
static GenericEnvironment *digOutGenericEnvironment(CanType loweredType) {
// Find a non-local, non-opaque archetype in the type and pull out
// its generic environment.
// TODO: we ought to be able to usefully minimize this
GenericEnvironment *env = nullptr;
loweredType.findIf([&env](CanType t) -> bool {
if (auto arch = dyn_cast<ArchetypeType>(t)) {
if (!isa<PrimaryArchetypeType>(arch) && !isa<PackArchetypeType>(arch))
return false;
env = arch->getGenericEnvironment();
return true;
}
return false;
});
return env;
}
OutliningMetadataCollector::OutliningMetadataCollector(
SILType T, IRGenFunction &IGF, LayoutIsNeeded_t needsLayout,
DeinitIsNeeded_t needsDeinitTypes)
: T(T), IGF(IGF), needsLayout(needsLayout), needsDeinit(needsDeinitTypes) {}
void OutliningMetadataCollector::collectTypeMetadata(SILType ty) {
assert(state != OutliningMetadataCollector::State::Kind::Collected);
// If the type has no archetypes, we can emit it from scratch in the callee.
if (!ty.hasArchetype()) {
return;
}
// Substitute opaque types if allowed.
ty = IGF.IGM.substOpaqueTypesWithUnderlyingTypes(ty);
collectTypeMetadataForLayout(ty);
collectTypeMetadataForDeinit(ty);
}
void OutliningMetadataCollector::collectTypeMetadataForLayout(SILType ty) {
if (!needsLayout)
return;
auto astType = ty.getASTType();
auto &ti = IGF.IGM.getTypeInfoForLowered(astType);
// We don't need the metadata for fixed size types or types that are not ABI
// accessible. Outlining will call the value witness of the enclosing type of
// non ABI accessible field/element types.
if (isa<FixedTypeInfo>(ti) || !ti.isABIAccessible()) {
return;
}
// If the type is a legal formal type, add it as a formal type.
// FIXME: does this force us to emit a more expensive metadata than we need
// to?
if (astType->isLegalFormalType()) {
return state.getCollecting().addFormalTypeMetadata(astType);
}
state.getCollecting().addRepresentationTypeMetadata(ty);
}
void OutliningMetadataCollector::collectTypeMetadataForDeinit(SILType ty) {
if (!needsDeinit)
return;
auto *nominal = ty.getASTType()->getAnyNominal();
if (!nominal)
return;
if (!nominal->getValueTypeDestructor())
return;
assert(ty.isMoveOnly());
state.getCollecting().addValueTypeWithDeinit(ty);
}
void OutliningMetadataCollector::materializeFormalTypeMetadata(
CanType ty, State::Collected::Elements &into) {
// If the type has no archetypes, we can emit it from scratch in the callee.
assert(ty->hasArchetype());
auto key = LocalTypeDataKey(ty, LocalTypeDataKind::forFormalTypeMetadata());
if (into.Values.count(key))
return;
auto metadata = IGF.emitTypeMetadataRef(ty);
into.Values.insert({key, metadata});
assert(into.Values.count(key));
}
void OutliningMetadataCollector::materializeRepresentationTypeMetadata(
SILType ty, State::Collected::Elements &into) {
auto key = LocalTypeDataKey(
ty.getASTType(), LocalTypeDataKind::forRepresentationTypeMetadata());
if (into.Values.count(key))
return;
auto metadata = IGF.emitTypeMetadataRefForLayout(ty);
into.Values.insert({key, metadata});
}
void OutliningMetadataCollector::materialize() {
if (state == State::Kind::Collected)
return;
auto collection = std::move(state.getCollecting());
switch (collection) {
case State::CollectionKind::Elements: {
auto &elements = collection.getElements();
auto &collected = state.setCollectedElements();
for (auto &element : elements.elements) {
switch (element) {
case State::ElementKind::MetadataForFormal: {
auto ty = element.getFormalType();
materializeFormalTypeMetadata(ty, /*into=*/collected);
break;
}
case State::ElementKind::MetadataForRepresentation: {
auto ty = element.getRepresentationType();
materializeRepresentationTypeMetadata(ty, /*into=*/collected);
break;
}
}
}
return;
}
case State::CollectionKind::Environment: {
auto pair = getTypeAndGenericSignatureForManglingOutlineFunction(T);
auto sig = pair.second;
auto subs = digOutGenericEnvironment(T.getASTType())
->getForwardingSubstitutionMap();
auto &collected = state.setCollectedEnvironment(subs);
GenericTypeRequirements requirements(IGF.IGM, sig);
for (auto requirement : requirements.getRequirements()) {
auto *value = emitGenericRequirementFromSubstitutions(
IGF, requirement, MetadataState::Complete, subs);
collected.Requirements.insert({requirement, value});
}
return;
}
}
}
void OutliningMetadataCollector::addPolymorphicArguments(
SmallVectorImpl<llvm::Value *> &args) const {
assert(hasFinished());
if (state == State::Kind::Empty)
return;
auto &collected = state.getCollected();
switch (collected) {
case State::CollectionKind::Elements: {
for (auto &pair : collected.getElements().Values) {
auto metadata = pair.second;
assert(metadata->getType() == IGF.IGM.TypeMetadataPtrTy);
args.push_back(metadata);
}
return;
}
case State::CollectionKind::Environment: {
for (auto &pair : collected.getEnvironment().Requirements) {
auto *value = pair.second;
args.push_back(value);
}
return;
}
}
}
void OutliningMetadataCollector::addPolymorphicParameterTypes(
SmallVectorImpl<llvm::Type *> &paramTys) const {
assert(hasFinished());
if (state == State::Kind::Empty)
return;
auto &collected = state.getCollected();
switch (collected) {
case State::CollectionKind::Elements: {
for (auto &pair : collected.getElements().Values) {
auto *metadata = pair.second;
paramTys.push_back(metadata->getType());
}
return;
}
case State::CollectionKind::Environment: {
for (auto &pair : collected.getEnvironment().Requirements) {
auto *value = pair.second;
paramTys.push_back(value->getType());
}
return;
}
}
}
void OutliningMetadataCollector::bindPolymorphicParameters(
IRGenFunction &IGF, Explosion &params) const {
assert(hasFinished());
if (state == State::Kind::Empty)
return;
auto &collected = state.getCollected();
switch (collected) {
case State::CollectionKind::Elements: {
// Note that our parameter IGF intentionally shadows the IGF that this
// collector was built with.
for (auto &pair : collected.getElements().Values) {
llvm::Value *arg = params.claimNext();
auto key = pair.first;
assert(key.Kind.isAnyTypeMetadata());
setTypeMetadataName(IGF.IGM, arg, key.Type);
if (key.Kind == LocalTypeDataKind::forRepresentationTypeMetadata()) {
IGF.setUnscopedLocalTypeData(key, MetadataResponse::forComplete(arg));
} else {
IGF.bindLocalTypeDataFromTypeMetadata(key.Type,
IsExact,
arg,
MetadataState::Complete);
}
}
return;
}
case State::CollectionKind::Environment: {
auto &environment = collected.getEnvironment();
for (auto &pair : environment.Requirements) {
bindGenericRequirement(IGF, pair.first, params.claimNext(),
MetadataState::Complete, environment.Subs);
}
return;
}
}
}
std::pair<CanType, CanGenericSignature>
irgen::getTypeAndGenericSignatureForManglingOutlineFunction(SILType type) {
auto loweredType = type.getASTType();
if (!loweredType->hasArchetype()) return {loweredType, nullptr};
GenericEnvironment *env = digOutGenericEnvironment(loweredType);
assert(env && "has archetype but no archetype?!");
return {loweredType->mapTypeOutOfContext()->getCanonicalType(),
env->getGenericSignature().getCanonicalSignature()};
}
bool TypeInfo::withWitnessableMetadataCollector(
IRGenFunction &IGF, SILType T, LayoutIsNeeded_t mayNeedLayout,
DeinitIsNeeded_t needsDeinit,
llvm::function_ref<void(OutliningMetadataCollector &)> invocation) const {
bool needsCollector = false;
LayoutIsNeeded_t needsLayout = LayoutIsNotNeeded;
if (!T.hasLocalArchetype() &&
!IGF.outliningCanCallValueWitnesses()) {
needsCollector = true;
if (T.hasArchetype()) {
needsLayout = LayoutIsNeeded;
}
} else if (!T.hasArchetype()) {
needsCollector = true;
// The implementation will call vwt in this case.
needsLayout = LayoutIsNotNeeded;
}
if (needsCollector) {
OutliningMetadataCollector collector(T, IGF, needsLayout, needsDeinit);
if (needsDeinit || needsLayout) {
// Only collect if anything would be collected.
collectMetadataForOutlining(collector, T);
}
collector.materialize();
invocation(collector);
return true;
}
return false;
}
void TypeInfo::callOutlinedCopy(IRGenFunction &IGF, Address dest, Address src,
SILType T, IsInitialization_t isInit,
IsTake_t isTake) const {
if (withWitnessableMetadataCollector(
IGF, T, LayoutIsNeeded, DeinitIsNotNeeded, [&](auto collector) {
collector.emitCallToOutlinedCopy(dest, src, T, *this, isInit,
isTake);
})) {
return;
}
if (isInit == IsInitialization && isTake == IsTake) {
return emitInitializeWithTakeCall(IGF, T, dest, src);
} else if (isInit == IsInitialization && isTake == IsNotTake) {
return emitInitializeWithCopyCall(IGF, T, dest, src);
} else if (isInit == IsNotInitialization && isTake == IsTake) {
return emitAssignWithTakeCall(IGF, T, dest, src);
} else if (isInit == IsNotInitialization && isTake == IsNotTake) {
return emitAssignWithCopyCall(IGF, T, dest, src);
}
llvm_unreachable("unknown case");
}
void OutliningMetadataCollector::emitCallToOutlinedCopy(
Address dest, Address src, SILType T, const TypeInfo &ti,
IsInitialization_t isInit, IsTake_t isTake) const {
assert(hasFinished());
assert(!needsDeinit);
llvm::SmallVector<llvm::Value *, 4> args;
args.push_back(IGF.Builder.CreateElementBitCast(src, ti.getStorageType())
.getAddress());
args.push_back(IGF.Builder.CreateElementBitCast(dest, ti.getStorageType())
.getAddress());
addPolymorphicArguments(args);
llvm::Constant *outlinedFn;
if (isInit && isTake) {
outlinedFn =
IGF.IGM.getOrCreateOutlinedInitializeWithTakeFunction(T, ti, *this);
} else if (isInit) {
outlinedFn =
IGF.IGM.getOrCreateOutlinedInitializeWithCopyFunction(T, ti, *this);
} else if (isTake) {
outlinedFn =
IGF.IGM.getOrCreateOutlinedAssignWithTakeFunction(T, ti, *this);
} else {
outlinedFn =
IGF.IGM.getOrCreateOutlinedAssignWithCopyFunction(T, ti, *this);
}
llvm::CallInst *call = IGF.Builder.CreateCall(
cast<llvm::Function>(outlinedFn)->getFunctionType(), outlinedFn, args);
call->setCallingConv(IGF.IGM.DefaultCC);
}
static bool needsSpecialOwnershipHandling(SILType t) {
auto astType = t.getASTType();
auto ref = dyn_cast<ReferenceStorageType>(astType);
if (!ref) {
return false;
}
return ref->getOwnership() != ReferenceOwnership::Strong;
}
static bool canUseValueWitnessForValueOp(IRGenModule &IGM, SILType T) {
if (!IGM.getSILModule().isTypeMetadataForLayoutAccessible(T))
return false;
// No value witness tables in embedded Swift.
if (IGM.Context.LangOpts.hasFeature(Feature::Embedded))
return false;
// It is not a good code size trade-off to instantiate a metatype for
// existentials, and also does not back-deploy gracefully in the case of
// constrained protocols.
if (T.getASTType()->isExistentialType())
return false;
if (needsSpecialOwnershipHandling(T))
return false;
if (T.getASTType()->hasDynamicSelfType())
return false;
return true;
}
llvm::Constant *IRGenModule::getOrCreateOutlinedInitializeWithTakeFunction(
SILType T, const TypeInfo &ti,
const OutliningMetadataCollector &collector) {
auto manglingBits = getTypeAndGenericSignatureForManglingOutlineFunction(T);
auto funcName =
IRGenMangler(T.getASTContext()).mangleOutlinedInitializeWithTakeFunction(manglingBits.first,
manglingBits.second, collector.IGF.isPerformanceConstraint);
return getOrCreateOutlinedCopyAddrHelperFunction(
T, ti, collector, funcName,
[this](IRGenFunction &IGF, Address dest, Address src, SILType T,
const TypeInfo &ti) {
if (!IGF.outliningCanCallValueWitnesses() ||
T.hasArchetype() || !canUseValueWitnessForValueOp(*this, T)) {
ti.initializeWithTake(IGF, dest, src, T, true, /*zeroizeIfSensitive=*/ true);
} else {
emitInitializeWithTakeCall(IGF, T, dest, src);
}
});
}
llvm::Constant *IRGenModule::getOrCreateOutlinedInitializeWithCopyFunction(
SILType T, const TypeInfo &ti,
const OutliningMetadataCollector &collector) {
auto manglingBits = getTypeAndGenericSignatureForManglingOutlineFunction(T);
auto funcName =
IRGenMangler(T.getASTContext()).mangleOutlinedInitializeWithCopyFunction(manglingBits.first,
manglingBits.second, collector.IGF.isPerformanceConstraint);
return getOrCreateOutlinedCopyAddrHelperFunction(
T, ti, collector, funcName,
[this](IRGenFunction &IGF, Address dest, Address src, SILType T,
const TypeInfo &ti) {
if (!IGF.outliningCanCallValueWitnesses() ||
T.hasArchetype() || !canUseValueWitnessForValueOp(*this, T)) {
ti.initializeWithCopy(IGF, dest, src, T, true);
} else {
emitInitializeWithCopyCall(IGF, T, dest, src);
}
});
}
llvm::Constant *IRGenModule::getOrCreateOutlinedAssignWithTakeFunction(
SILType T, const TypeInfo &ti,
const OutliningMetadataCollector &collector) {
auto manglingBits = getTypeAndGenericSignatureForManglingOutlineFunction(T);
auto funcName =
IRGenMangler(T.getASTContext()).mangleOutlinedAssignWithTakeFunction(manglingBits.first,
manglingBits.second, collector.IGF.isPerformanceConstraint);
return getOrCreateOutlinedCopyAddrHelperFunction(
T, ti, collector, funcName,
[this](IRGenFunction &IGF, Address dest, Address src, SILType T,
const TypeInfo &ti) {
if (!IGF.outliningCanCallValueWitnesses() ||
T.hasArchetype() || !canUseValueWitnessForValueOp(*this, T)) {
ti.assignWithTake(IGF, dest, src, T, true);
} else {
emitAssignWithTakeCall(IGF, T, dest, src);
}
});
}
llvm::Constant *IRGenModule::getOrCreateOutlinedAssignWithCopyFunction(
SILType T, const TypeInfo &ti,
const OutliningMetadataCollector &collector) {
auto manglingBits = getTypeAndGenericSignatureForManglingOutlineFunction(T);
auto funcName =
IRGenMangler(T.getASTContext()).mangleOutlinedAssignWithCopyFunction(manglingBits.first,
manglingBits.second, collector.IGF.isPerformanceConstraint);
return getOrCreateOutlinedCopyAddrHelperFunction(
T, ti, collector, funcName,
[this](IRGenFunction &IGF, Address dest, Address src, SILType T,
const TypeInfo &ti) {
if (!IGF.outliningCanCallValueWitnesses() ||
T.hasArchetype() || !canUseValueWitnessForValueOp(*this, T)) {
ti.assignWithCopy(IGF, dest, src, T, true);
} else {
emitAssignWithCopyCall(IGF, T, dest, src);
}
});
}
llvm::Constant *IRGenModule::getOrCreateOutlinedCopyAddrHelperFunction(
SILType T, const TypeInfo &ti,
const OutliningMetadataCollector &collector,
StringRef funcName,
CopyAddrHelperGenerator generator) {
assert(collector.hasFinished());
llvm::SmallVector<llvm::Type *, 4> paramTys;
paramTys.push_back(PtrTy);
paramTys.push_back(PtrTy);
collector.addPolymorphicParameterTypes(paramTys);
IRLinkage *linkage = nullptr;
IRLinkage privateLinkage = {
llvm::GlobalValue::PrivateLinkage,
llvm::GlobalValue::DefaultVisibility,
llvm::GlobalValue::DefaultStorageClass,
};
// Opaque result types might lead to different expansions in different files.
// The default hidden linkonce_odr might lead to linking an implementation
// from another file that head a different expansion/different
// signature/different implementation.
if (getTypeProperties(T, TypeExpansionContext::minimal())
.isTypeExpansionSensitive()) {
linkage = &privateLinkage;
}
return getOrCreateHelperFunction(
funcName, PtrTy, paramTys,
[&](IRGenFunction &IGF) {
auto params = IGF.collectParameters();
Address src = ti.getAddressForPointer(params.claimNext());
Address dest = ti.getAddressForPointer(params.claimNext());
collector.bindPolymorphicParameters(IGF, params);
generator(IGF, dest, src, T, ti);
IGF.Builder.CreateRet(dest.getAddress());
},
true /*setIsNoInline*/,
false /*forPrologue*/,
collector.IGF.isPerformanceConstraint,
linkage);
}
void TypeInfo::callOutlinedDestroy(IRGenFunction &IGF,
Address addr, SILType T) const {
// Short-cut destruction of trivial values.
if (IGF.IGM.getTypeProperties(T).isTrivial())
return;
if (withWitnessableMetadataCollector(
IGF, T, LayoutIsNeeded, DeinitIsNeeded, [&](auto collector) {
collector.emitCallToOutlinedDestroy(addr, T, *this);
})) {
return;
}
return emitDestroyCall(IGF, T, addr);
}
void OutliningMetadataCollector::emitCallToOutlinedDestroy(
Address addr, SILType T, const TypeInfo &ti) const {
assert(hasFinished());
assert(needsDeinit);
llvm::SmallVector<llvm::Value *, 4> args;
args.push_back(IGF.Builder.CreateElementBitCast(addr, ti.getStorageType())
.getAddress());
addPolymorphicArguments(args);
auto outlinedFn =
IGF.IGM.getOrCreateOutlinedDestroyFunction(T, ti, *this);
llvm::CallInst *call = IGF.Builder.CreateCall(
cast<llvm::Function>(outlinedFn)->getFunctionType(), outlinedFn, args);
call->setCallingConv(IGF.IGM.DefaultCC);
}
llvm::Constant *IRGenModule::getOrCreateOutlinedDestroyFunction(
SILType T, const TypeInfo &ti,
const OutliningMetadataCollector &collector) {
IRGenMangler mangler(T.getASTContext());
auto manglingBits = getTypeAndGenericSignatureForManglingOutlineFunction(T);
auto funcName = mangler.mangleOutlinedDestroyFunction(manglingBits.first,
manglingBits.second, collector.IGF.isPerformanceConstraint);
IRLinkage *linkage = nullptr;
IRLinkage privateLinkage = {
llvm::GlobalValue::PrivateLinkage,
llvm::GlobalValue::DefaultVisibility,
llvm::GlobalValue::DefaultStorageClass,
};
// Opaque result types might lead to different expansions in different files.
// The default hidden linkonce_odr might lead to linking an implementation
// from another file that head a different expansion/different
// signature/different implementation.
if (getTypeProperties(T, TypeExpansionContext::minimal())
.isTypeExpansionSensitive()) {
linkage = &privateLinkage;
}
llvm::SmallVector<llvm::Type *, 4> paramTys;
paramTys.push_back(PtrTy);
collector.addPolymorphicParameterTypes(paramTys);
return getOrCreateHelperFunction(
funcName, PtrTy, paramTys,
[&](IRGenFunction &IGF) {
Explosion params = IGF.collectParameters();
Address addr = ti.getAddressForPointer(params.claimNext());
collector.bindPolymorphicParameters(IGF, params);
if (!IGF.outliningCanCallValueWitnesses() ||
T.hasArchetype() || !canUseValueWitnessForValueOp(*this, T)) {
ti.destroy(IGF, addr, T, true);
} else {
emitDestroyCall(IGF, T, addr);
}
IGF.Builder.CreateRet(addr.getAddress());
},
true /*setIsNoInline*/,
false /*forPrologue*/,
collector.IGF.isPerformanceConstraint,
linkage);
}
llvm::Constant *IRGenModule::getOrCreateRetainFunction(const TypeInfo &ti,
SILType t,
llvm::Type *llvmType,
Atomicity atomicity) {
auto *loadableTI = cast<LoadableTypeInfo>(&ti);
IRGenMangler mangler(t.getASTContext());
auto manglingBits =
getTypeAndGenericSignatureForManglingOutlineFunction(t);
auto funcName = mangler.mangleOutlinedRetainFunction(manglingBits.first,
manglingBits.second);
llvm::Type *argTys[] = {llvmType};
return getOrCreateHelperFunction(
funcName, llvmType, argTys,
[&](IRGenFunction &IGF) {
auto it = IGF.CurFn->arg_begin();
Address addr(&*it++, loadableTI->getStorageType(),
loadableTI->getFixedAlignment());
Explosion loaded;
loadableTI->loadAsTake(IGF, addr, loaded);
Explosion out;
loadableTI->copy(IGF, loaded, out, atomicity);
(void)out.claimAll();
IGF.Builder.CreateRet(addr.getAddress());
},
true /*setIsNoInline*/);
}
void TypeInfo::callOutlinedRelease(IRGenFunction &IGF, Address addr, SILType T,
Atomicity atomicity) const {
OutliningMetadataCollector collector(T, IGF, LayoutIsNotNeeded,
DeinitIsNeeded);
collectMetadataForOutlining(collector, T);
collector.materialize();
collector.emitCallToOutlinedRelease(addr, T, *this, atomicity);
}
void OutliningMetadataCollector::emitCallToOutlinedRelease(
Address addr, SILType T, const TypeInfo &ti, Atomicity atomicity) const {
assert(hasFinished());
assert(!needsLayout);
assert(needsDeinit);
llvm::SmallVector<llvm::Value *, 4> args;
args.push_back(addr.getAddress());
addPolymorphicArguments(args);
auto *outlinedF = cast<llvm::Function>(IGF.IGM.getOrCreateReleaseFunction(
ti, T, addr.getAddress()->getType(), atomicity, *this));
llvm::CallInst *call =
IGF.Builder.CreateCall(outlinedF->getFunctionType(), outlinedF, args);
call->setCallingConv(IGF.IGM.DefaultCC);
}
llvm::Constant *IRGenModule::getOrCreateReleaseFunction(
const TypeInfo &ti, SILType t, llvm::Type *ptrTy, Atomicity atomicity,
const OutliningMetadataCollector &collector) {
auto *loadableTI = cast<LoadableTypeInfo>(&ti);
IRGenMangler mangler(t.getASTContext());
auto manglingBits =
getTypeAndGenericSignatureForManglingOutlineFunction(t);
auto funcName = mangler.mangleOutlinedReleaseFunction(manglingBits.first,
manglingBits.second);
llvm::SmallVector<llvm::Type *, 4> argTys;
argTys.push_back(ptrTy);
collector.addPolymorphicParameterTypes(argTys);
return getOrCreateHelperFunction(
funcName, ptrTy, argTys,
[&](IRGenFunction &IGF) {
Explosion params = IGF.collectParameters();
Address addr(params.claimNext(), loadableTI->getStorageType(),
loadableTI->getFixedAlignment());
collector.bindPolymorphicParameters(IGF, params);
Explosion loaded;
loadableTI->loadAsTake(IGF, addr, loaded);
loadableTI->consume(IGF, loaded, atomicity, t);
IGF.Builder.CreateRet(addr.getAddress());
},
true /*setIsNoInline*/);
}