Skip to content

Commit 840ded4

Browse files
committed
[IRGen] Accessor returns prespecializations.
For every prespecialization of generic metadata that exists in the module where the generic type is defined, the metadata accessor gains code with the following effect switch arguments { case prespecialization1.genericArguments: return prespecialization1 case prespecialization2.genericArguments: return prespecialization2 ... default: return swift_getGenericMetadata(...) } rdar://problem/56961700
1 parent c2d5d60 commit 840ded4

File tree

1 file changed

+96
-2
lines changed

1 file changed

+96
-2
lines changed

lib/IRGen/MetadataRequest.cpp

Lines changed: 96 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,29 @@
1919
#include "ConstantBuilder.h"
2020
#include "Explosion.h"
2121
#include "FixedTypeInfo.h"
22-
#include "GenericRequirement.h"
2322
#include "GenArchetype.h"
2423
#include "GenClass.h"
2524
#include "GenMeta.h"
2625
#include "GenProto.h"
2726
#include "GenType.h"
27+
#include "GenericRequirement.h"
2828
#include "IRGenDebugInfo.h"
2929
#include "IRGenFunction.h"
3030
#include "IRGenMangler.h"
3131
#include "IRGenModule.h"
3232
#include "swift/AST/ASTContext.h"
3333
#include "swift/AST/ExistentialLayout.h"
34+
#include "swift/AST/GenericEnvironment.h"
3435
#include "swift/AST/IRGenOptions.h"
3536
#include "swift/AST/SubstitutionMap.h"
3637
#include "swift/ClangImporter/ClangModule.h"
3738
#include "swift/IRGen/Linking.h"
3839
#include "swift/SIL/FormalLinkage.h"
3940
#include "swift/SIL/TypeLowering.h"
41+
#include "llvm/ADT/STLExtras.h"
42+
#include "llvm/IR/Constant.h"
43+
#include "llvm/Support/FormatVariadic.h"
44+
#include <algorithm>
4045

4146
using namespace swift;
4247
using namespace irgen;
@@ -1765,6 +1770,74 @@ IRGenFunction::emitGenericTypeMetadataAccessFunctionCall(
17651770
return MetadataResponse::handle(*this, request, call);
17661771
}
17671772

1773+
static void emitCanonicalSpecializationsForGenericTypeMetadataAccessFunction(
1774+
IRGenFunction &IGF, Explosion &params, NominalTypeDecl *nominal,
1775+
GenericArguments &genericArgs,
1776+
std::function<llvm::Value *(int)> valueAtIndex) {
1777+
auto &IGM = IGF.IGM;
1778+
auto specializations = IGF.IGM.IRGen.specializationsForType(nominal);
1779+
if (specializations.size() > 0) {
1780+
SmallVector<llvm::BasicBlock *, 4> conditionBlocks;
1781+
for (size_t index = 0; index < specializations.size(); ++index) {
1782+
conditionBlocks.push_back(llvm::BasicBlock::Create(IGM.getLLVMContext()));
1783+
}
1784+
1785+
IGF.Builder.CreateBr(conditionBlocks[0]);
1786+
1787+
SmallVector<std::pair<llvm::BasicBlock *, llvm::Value *>, 4>
1788+
specializationBlocks;
1789+
auto switchDestination = llvm::BasicBlock::Create(IGM.getLLVMContext());
1790+
unsigned long index = 0;
1791+
for (auto specialization : specializations) {
1792+
auto conditionBlock = conditionBlocks[index];
1793+
IGF.Builder.emitBlock(conditionBlock);
1794+
auto successorBlock = index < conditionBlocks.size() - 1
1795+
? conditionBlocks[index + 1]
1796+
: switchDestination;
1797+
auto specializationBlock = llvm::BasicBlock::Create(IGM.getLLVMContext());
1798+
auto substitutions = specialization->getContextSubstitutionMap(
1799+
IGM.getSwiftModule(), nominal);
1800+
1801+
llvm::Value *condition = llvm::ConstantInt::get(IGM.Int1Ty, 1);
1802+
auto generic = specialization->getAnyGeneric();
1803+
auto parameters = generic->getGenericEnvironment()->getGenericParams();
1804+
for (size_t index = 0; index < parameters.size(); ++index) {
1805+
auto parameter = parameters[index];
1806+
auto argument = ((Type *)parameter)->subst(substitutions);
1807+
llvm::Constant *addr =
1808+
IGM.getAddrOfTypeMetadata(argument->getCanonicalType());
1809+
auto addrInt = IGF.Builder.CreateBitCast(addr, IGM.Int8PtrTy);
1810+
condition = IGF.Builder.CreateAnd(
1811+
condition, IGF.Builder.CreateICmpEQ(addrInt, valueAtIndex(index)));
1812+
}
1813+
IGF.Builder.CreateCondBr(condition, specializationBlock, successorBlock);
1814+
1815+
auto specializedMetadataAddress =
1816+
IGM.getAddrOfTypeMetadata(specialization);
1817+
// Construct a MetadataResponse. It has three fields in the following
1818+
// order:
1819+
// - const Metadata *Metadata;
1820+
// - MetadataState (i32) StaticState;
1821+
llvm::Value *response = llvm::UndefValue::get(IGM.TypeMetadataResponseTy);
1822+
response = IGF.Builder.CreateInsertValue(
1823+
response, specializedMetadataAddress, 0,
1824+
"insert metadata address into response");
1825+
auto state =
1826+
llvm::ConstantInt::get(IGM.SizeTy, (uint32_t)MetadataState::Complete);
1827+
response = IGF.Builder.CreateInsertValue(
1828+
response, state, 1, "insert metadata state into response");
1829+
specializationBlocks.push_back({specializationBlock, response});
1830+
++index;
1831+
}
1832+
1833+
for (auto pair : specializationBlocks) {
1834+
IGF.Builder.emitBlock(pair.first);
1835+
IGF.Builder.CreateRet(pair.second);
1836+
}
1837+
IGF.Builder.emitBlock(switchDestination);
1838+
}
1839+
}
1840+
17681841
static MetadataResponse
17691842
emitGenericTypeMetadataAccessFunction(IRGenFunction &IGF,
17701843
Explosion &params,
@@ -1788,6 +1861,21 @@ emitGenericTypeMetadataAccessFunction(IRGenFunction &IGF,
17881861
llvm::Value *arguments =
17891862
IGF.Builder.CreateBitCast(argsBuffer.getAddress(), IGM.Int8PtrTy);
17901863

1864+
llvm::Value *argumentsBuffer =
1865+
IGF.Builder.CreateBitCast(argsBuffer.getAddress(), IGM.Int8PtrPtrTy);
1866+
1867+
emitCanonicalSpecializationsForGenericTypeMetadataAccessFunction(
1868+
IGF, params, nominal, genericArgs, [&](int index) {
1869+
llvm::Value *indexValue = llvm::ConstantInt::get(IGM.Int64Ty, index);
1870+
llvm::SmallVector<llvm::Value *, 1> indices{indexValue};
1871+
llvm::Value *elementPointer =
1872+
IGF.Builder.CreateGEP(argumentsBuffer, indexValue);
1873+
llvm::LoadInst *retval = IGF.Builder.CreateLoad(
1874+
elementPointer, Alignment(),
1875+
llvm::formatv("load argument at index {0} from buffer", index));
1876+
return retval;
1877+
});
1878+
17911879
// Make the call.
17921880
auto call = IGF.Builder.CreateCall(IGM.getGetGenericMetadataFn(),
17931881
{request, arguments, descriptor});
@@ -1873,7 +1961,13 @@ emitGenericTypeMetadataAccessFunction(IRGenFunction &IGF,
18731961
auto arg2 = numArguments >= 3
18741962
? IGF.Builder.CreateBitCast(params.claimNext(), IGM.Int8PtrTy)
18751963
: llvm::UndefValue::get(IGM.Int8PtrTy);
1876-
1964+
1965+
std::array<llvm::Value *, 3> argValues{arg0, arg1, arg2};
1966+
1967+
emitCanonicalSpecializationsForGenericTypeMetadataAccessFunction(
1968+
IGF, params, nominal, genericArgs,
1969+
[&](int index) { return argValues[index]; });
1970+
18771971
auto call = IGF.Builder.CreateCall(thunkFn,
18781972
{request, arg0, arg1, arg2, descriptor});
18791973
call->setDoesNotAccessMemory();

0 commit comments

Comments
 (0)