Skip to content

Commit afceb4e

Browse files
committed
IRGen: Factor out calling convention shuffling in metadata accessors.
Metadata accessors that take <=3 arguments have to put the arguments in a temporary buffer and move the registers around in order to call swift_getGenericMetadata. We can factor this into a common shim function.
1 parent 1533a84 commit afceb4e

File tree

3 files changed

+114
-73
lines changed

3 files changed

+114
-73
lines changed

lib/IRGen/MetadataRequest.cpp

Lines changed: 103 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1637,59 +1637,118 @@ emitGenericTypeMetadataAccessFunction(IRGenFunction &IGF,
16371637
Explosion &params,
16381638
NominalTypeDecl *nominal,
16391639
GenericArguments &genericArgs) {
1640-
llvm::Value *descriptor =
1641-
IGF.IGM.getAddrOfTypeContextDescriptor(nominal, RequireMetadata);
1640+
auto &IGM = IGF.IGM;
1641+
1642+
llvm::Constant *descriptor =
1643+
IGM.getAddrOfTypeContextDescriptor(nominal, RequireMetadata);
16421644

16431645
auto request = params.claimNext();
16441646

16451647
auto numArguments = genericArgs.Types.size();
16461648

1647-
bool allocatedBuffer = false;
1648-
Address argsBuffer;
1649+
llvm::Value *result;
16491650
if (numArguments > NumDirectGenericTypeMetadataAccessFunctionArgs) {
1650-
// The caller provided a buffer with enough space for all of the arguments;
1651-
// use that.
1652-
argsBuffer = Address(params.claimNext(), IGF.IGM.getPointerAlignment());
1651+
// swift_getGenericMetadata's calling convention is already cleverly
1652+
// laid out to minimize the assembly language size of the thunk.
1653+
// The caller passed us an appropriate buffer with the arguments.
1654+
auto argsBuffer = Address(params.claimNext(), IGM.getPointerAlignment());
1655+
llvm::Value *arguments =
1656+
IGF.Builder.CreateBitCast(argsBuffer.getAddress(), IGM.Int8PtrTy);
1657+
1658+
// Make the call.
1659+
auto call = IGF.Builder.CreateCall(IGM.getGetGenericMetadataFn(),
1660+
{request, arguments, descriptor});
1661+
call->setDoesNotThrow();
1662+
call->setCallingConv(IGM.SwiftCC);
1663+
call->addAttribute(llvm::AttributeList::FunctionIndex,
1664+
llvm::Attribute::ReadOnly);
1665+
result = call;
16531666
} else {
1654-
// Allocate a buffer with enough storage for the arguments.
1655-
auto argsBufferTy =
1656-
llvm::StructType::get(IGF.IGM.LLVMContext, genericArgs.Types);
1657-
argsBuffer = IGF.createAlloca(argsBufferTy,
1658-
IGF.IGM.getPointerAlignment(),
1659-
"generic.arguments");
1660-
IGF.Builder.CreateLifetimeStart(argsBuffer,
1661-
IGF.IGM.getPointerSize() * genericArgs.Values.size());
1662-
allocatedBuffer = true;
1663-
1664-
// Store direct arguments into the buffer.
1665-
for (auto i : range(numArguments)) {
1666-
Address elt = IGF.Builder.CreateStructGEP(argsBuffer, i,
1667-
IGF.IGM.getPointerSize() * i);
1668-
1669-
auto *arg =
1670-
IGF.Builder.CreateBitCast(params.claimNext(),
1671-
elt.getType()->getPointerElementType());
1672-
IGF.Builder.CreateStore(arg, elt);
1667+
static_assert(NumDirectGenericTypeMetadataAccessFunctionArgs == 3,
1668+
"adjust this if you change "
1669+
"NumDirectGenericTypeMetadataAccessFunctionArgs");
1670+
// Factor out the buffer shuffling for metadata accessors that take their
1671+
// arguments directly, so that the accessor function itself only needs to
1672+
// materialize the nominal type descriptor and call this thunk.
1673+
auto thunkFn = cast<llvm::Function>(
1674+
IGM.getModule()
1675+
->getOrInsertFunction("__swift_instantiateGenericMetadata",
1676+
IGM.TypeMetadataResponseTy,
1677+
IGM.SizeTy, // request
1678+
IGM.Int8PtrTy, // arg 0
1679+
IGM.Int8PtrTy, // arg 1
1680+
IGM.Int8PtrTy, // arg 2
1681+
IGM.TypeContextDescriptorPtrTy) // type context descriptor
1682+
->stripPointerCasts());
1683+
1684+
if (thunkFn->empty()) {
1685+
ApplyIRLinkage(IRLinkage::InternalLinkOnceODR)
1686+
.to(thunkFn);
1687+
thunkFn->setDoesNotAccessMemory();
1688+
thunkFn->setDoesNotThrow();
1689+
thunkFn->setCallingConv(IGM.SwiftCC);
1690+
thunkFn->addAttribute(llvm::AttributeList::FunctionIndex,
1691+
llvm::Attribute::NoInline);
1692+
1693+
[&IGM, thunkFn]{
1694+
IRGenFunction subIGF(IGM, thunkFn);
1695+
1696+
auto params = subIGF.collectParameters();
1697+
auto request = params.claimNext();
1698+
auto arg0 = params.claimNext();
1699+
auto arg1 = params.claimNext();
1700+
auto arg2 = params.claimNext();
1701+
auto descriptor = params.claimNext();
1702+
1703+
// Allocate a buffer with enough storage for the arguments.
1704+
auto argsBufferTy =
1705+
llvm::ArrayType::get(IGM.Int8PtrTy,
1706+
NumDirectGenericTypeMetadataAccessFunctionArgs);
1707+
auto argsBuffer = subIGF.createAlloca(argsBufferTy,
1708+
IGM.getPointerAlignment(),
1709+
"generic.arguments");
1710+
subIGF.Builder.CreateLifetimeStart(argsBuffer,
1711+
IGM.getPointerSize() * NumDirectGenericTypeMetadataAccessFunctionArgs);
1712+
1713+
auto arg0Buf = subIGF.Builder.CreateConstInBoundsGEP2_32(argsBufferTy,
1714+
argsBuffer.getAddress(), 0, 0);
1715+
subIGF.Builder.CreateStore(arg0, arg0Buf, IGM.getPointerAlignment());
1716+
auto arg1Buf = subIGF.Builder.CreateConstInBoundsGEP2_32(argsBufferTy,
1717+
argsBuffer.getAddress(), 0, 1);
1718+
subIGF.Builder.CreateStore(arg1, arg1Buf, IGM.getPointerAlignment());
1719+
auto arg2Buf = subIGF.Builder.CreateConstInBoundsGEP2_32(argsBufferTy,
1720+
argsBuffer.getAddress(), 0, 2);
1721+
subIGF.Builder.CreateStore(arg2, arg2Buf, IGM.getPointerAlignment());
1722+
1723+
// Make the call.
1724+
auto argsAddr = subIGF.Builder.CreateBitCast(argsBuffer.getAddress(),
1725+
IGM.Int8PtrTy);
1726+
auto result = subIGF.Builder.CreateCall(IGM.getGetGenericMetadataFn(),
1727+
{request, argsAddr, descriptor});
1728+
subIGF.Builder.CreateRet(result);
1729+
}();
16731730
}
1731+
1732+
// Call out to the helper.
1733+
auto arg0 = numArguments >= 1
1734+
? IGF.Builder.CreateBitCast(params.claimNext(), IGM.Int8PtrTy)
1735+
: llvm::UndefValue::get(IGM.Int8PtrTy);
1736+
auto arg1 = numArguments >= 2
1737+
? IGF.Builder.CreateBitCast(params.claimNext(), IGM.Int8PtrTy)
1738+
: llvm::UndefValue::get(IGM.Int8PtrTy);
1739+
auto arg2 = numArguments >= 3
1740+
? IGF.Builder.CreateBitCast(params.claimNext(), IGM.Int8PtrTy)
1741+
: llvm::UndefValue::get(IGM.Int8PtrTy);
1742+
1743+
auto call = IGF.Builder.CreateCall(thunkFn,
1744+
{request, arg0, arg1, arg2, descriptor});
1745+
call->setDoesNotAccessMemory();
1746+
call->setDoesNotThrow();
1747+
call->setCallingConv(IGM.SwiftCC);
1748+
1749+
result = call;
16741750
}
1675-
1676-
llvm::Value *arguments =
1677-
IGF.Builder.CreateBitCast(argsBuffer.getAddress(), IGF.IGM.Int8PtrTy);
1678-
1679-
// Make the call.
1680-
auto result = IGF.Builder.CreateCall(IGF.IGM.getGetGenericMetadataFn(),
1681-
{request, arguments, descriptor});
1682-
result->setDoesNotThrow();
1683-
result->setCallingConv(IGF.IGM.SwiftCC);
1684-
result->addAttribute(llvm::AttributeList::FunctionIndex,
1685-
llvm::Attribute::ReadOnly);
1686-
1687-
// If we allocated the array ourselves, end its lifetime.
1688-
if (allocatedBuffer) {
1689-
IGF.Builder.CreateLifetimeEnd(argsBuffer,
1690-
IGF.IGM.getPointerSize() * genericArgs.Values.size());
1691-
}
1692-
1751+
16931752
return MetadataResponse::handle(IGF, DynamicMetadataRequest(request), result);
16941753
}
16951754

test/IRGen/generic_classes.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,5 +400,5 @@ entry(%c : $RootGeneric<Int32>):
400400
// CHECK: ret %swift.metadata_response [[T1]]
401401
// CHECK: }
402402

403-
// OSIZE: define hidden swiftcc %swift.metadata_response @"$s15generic_classes11RootGenericCMa"(i64, %swift.type*) [[ATTRS:#[0-9]+]] {
403+
// OSIZE: define hidden swiftcc %swift.metadata_response @"$s15generic_classes11RootGenericCMa"(i64, %swift.type* {{.*}}) [[ATTRS:#[0-9]+]] {
404404
// OSIZE: [[ATTRS]] = {{{.*}}noinline

test/IRGen/generic_metatypes.swift

Lines changed: 10 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -119,41 +119,23 @@ func makeGenericMetatypes() {
119119

120120
// CHECK-LABEL: define hidden swiftcc %swift.metadata_response @"$s17generic_metatypes6OneArgVMa"
121121
// CHECK-SAME: ([[INT]], %swift.type*)
122-
// CHECK: [[BUFFER:%.*]] = alloca { %swift.type* }
123-
// CHECK: [[BUFFER_PTR:%.*]] = bitcast { %swift.type* }* [[BUFFER]] to i8*
124-
// CHECK: call void @llvm.lifetime.start
125-
// CHECK: [[BUFFER_ELT:%.*]] = getelementptr inbounds { %swift.type* }, { %swift.type* }* [[BUFFER]], i32 0, i32 0
126-
// CHECK: store %swift.type* %1, %swift.type** [[BUFFER_ELT]]
127-
// CHECK: [[BUFFER_PTR:%.*]] = bitcast { %swift.type* }* [[BUFFER]] to i8*
128-
// CHECK: [[T0:%.*]] = call swiftcc %swift.metadata_response @swift_getGenericMetadata([[INT]] %0, i8* [[BUFFER_PTR]], %swift.type_descriptor* {{.*}} @"$s17generic_metatypes6OneArgVMn" {{.*}})
122+
// CHECK: [[BITCAST_1:%.*]] = bitcast {{.*}} %1
123+
// CHECK: [[T0:%.*]] = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[BITCAST_1]], i8* undef, i8* undef, %swift.type_descriptor* {{.*}} @"$s17generic_metatypes6OneArgVMn" {{.*}})
129124
// CHECK: [[METADATA:%.*]] = extractvalue %swift.metadata_response [[T0]], 0
130125

131126
// CHECK-LABEL: define hidden swiftcc %swift.metadata_response @"$s17generic_metatypes7TwoArgsVMa"
132127
// CHECK-SAME: ([[INT]], %swift.type*, %swift.type*)
133-
// CHECK: [[BUFFER:%.*]] = alloca { %swift.type*, %swift.type* }
134-
// CHECK: [[BUFFER_PTR:%.*]] = bitcast { %swift.type*, %swift.type* }* [[BUFFER]] to i8*
135-
// CHECK: call void @llvm.lifetime.start
136-
// CHECK: [[BUFFER_ELT:%.*]] = getelementptr inbounds { %swift.type*, %swift.type* }, { %swift.type*, %swift.type* }* [[BUFFER]], i32 0, i32 0
137-
// CHECK: store %swift.type* %1, %swift.type** [[BUFFER_ELT]]
138-
// CHECK: [[BUFFER_ELT:%.*]] = getelementptr inbounds { %swift.type*, %swift.type* }, { %swift.type*, %swift.type* }* [[BUFFER]], i32 0, i32 1
139-
// CHECK: store %swift.type* %2, %swift.type** [[BUFFER_ELT]]
140-
// CHECK: [[BUFFER_PTR:%.*]] = bitcast { %swift.type*, %swift.type* }* [[BUFFER]] to i8*
141-
// CHECK: [[T0:%.*]] = call swiftcc %swift.metadata_response @swift_getGenericMetadata([[INT]] %0, i8* [[BUFFER_PTR]], %swift.type_descriptor* {{.*}} @"$s17generic_metatypes7TwoArgsVMn" {{.*}})
128+
// CHECK: [[BITCAST_1:%.*]] = bitcast {{.*}} %1
129+
// CHECK: [[BITCAST_2:%.*]] = bitcast {{.*}} %2
130+
// CHECK: [[T0:%.*]] = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[BITCAST_1]], i8* [[BITCAST_2]], i8* undef, %swift.type_descriptor* {{.*}} @"$s17generic_metatypes7TwoArgsVMn" {{.*}})
142131
// CHECK: [[METADATA:%.*]] = extractvalue %swift.metadata_response [[T0]], 0
143132

144133
// CHECK-LABEL: define hidden swiftcc %swift.metadata_response @"$s17generic_metatypes9ThreeArgsVMa"
145134
// CHECK-SAME: ({{i[0-9]+}}, %swift.type*, %swift.type*, %swift.type*)
146-
// CHECK: [[BUFFER:%.*]] = alloca { %swift.type*, %swift.type*, %swift.type* }
147-
// CHECK: [[BUFFER_PTR:%.*]] = bitcast { %swift.type*, %swift.type*, %swift.type* }* [[BUFFER]] to i8*
148-
// CHECK: call void @llvm.lifetime.start
149-
// CHECK: [[BUFFER_ELT:%.*]] = getelementptr inbounds { %swift.type*, %swift.type*, %swift.type* }, { %swift.type*, %swift.type*, %swift.type* }* [[BUFFER]], i32 0, i32 0
150-
// CHECK: store %swift.type* %1, %swift.type** [[BUFFER_ELT]]
151-
// CHECK: [[BUFFER_ELT:%.*]] = getelementptr inbounds { %swift.type*, %swift.type*, %swift.type* }, { %swift.type*, %swift.type*, %swift.type* }* [[BUFFER]], i32 0, i32 1
152-
// CHECK: store %swift.type* %2, %swift.type** [[BUFFER_ELT]]
153-
// CHECK: [[BUFFER_ELT:%.*]] = getelementptr inbounds { %swift.type*, %swift.type*, %swift.type* }, { %swift.type*, %swift.type*, %swift.type* }* [[BUFFER]], i32 0, i32 2
154-
// CHECK: store %swift.type* %3, %swift.type** [[BUFFER_ELT]]
155-
// CHECK: [[BUFFER_PTR:%.*]] = bitcast { %swift.type*, %swift.type*, %swift.type* }* [[BUFFER]] to i8*
156-
// CHECK: [[T0:%.*]] = call swiftcc %swift.metadata_response @swift_getGenericMetadata([[INT]] %0, i8* [[BUFFER_PTR]], %swift.type_descriptor* {{.*}} @"$s17generic_metatypes9ThreeArgsVMn" {{.*}})
135+
// CHECK: [[BITCAST_1:%.*]] = bitcast {{.*}} %1
136+
// CHECK: [[BITCAST_2:%.*]] = bitcast {{.*}} %2
137+
// CHECK: [[BITCAST_3:%.*]] = bitcast {{.*}} %3
138+
// CHECK: [[T0:%.*]] = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata([[INT]] %0, i8* [[BITCAST_1]], i8* [[BITCAST_2]], i8* [[BITCAST_3]], %swift.type_descriptor* {{.*}} @"$s17generic_metatypes9ThreeArgsVMn" {{.*}})
157139
// CHECK: [[METADATA:%.*]] = extractvalue %swift.metadata_response [[T0]], 0
158140

159141
// CHECK-LABEL: define hidden swiftcc %swift.metadata_response @"$s17generic_metatypes8FiveArgsVMa"
@@ -164,4 +146,4 @@ func makeGenericMetatypes() {
164146
// CHECK: ret %swift.metadata_response
165147

166148
// CHECK: attributes [[NOUNWIND_READNONE]] = { nounwind readnone }
167-
// CHECK: attributes [[NOUNWIND_OPT]] = { noinline nounwind "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "target-cpu"
149+
// CHECK: attributes [[NOUNWIND_OPT]] = { noinline nounwind "no-frame-pointer-elim"="false" {{.*}} "target-cpu"

0 commit comments

Comments
 (0)