Skip to content

Commit b206c76

Browse files
authored
Merge pull request #62566 from slavapestov/irgen-metadata-packs
IRGen: Sketch out metadata pack emission
2 parents 22eeac6 + 0e72564 commit b206c76

9 files changed

+424
-105
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5175,8 +5175,6 @@ namespace {
51755175

51765176
static bool conformsToProtocolInOriginalModule(NominalTypeDecl *nominal,
51775177
const ProtocolDecl *proto) {
5178-
auto &ctx = nominal->getASTContext();
5179-
51805178
if (inheritanceListContainsProtocol(nominal, proto))
51815179
return true;
51825180

lib/IRGen/GenArchetype.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ MetadataResponse
6060
irgen::emitArchetypeTypeMetadataRef(IRGenFunction &IGF,
6161
CanArchetypeType archetype,
6262
DynamicMetadataRequest request) {
63+
assert(!isa<PackArchetypeType>(archetype));
64+
6365
// Check for an existing cache entry.
6466
if (auto response = IGF.tryGetLocalTypeMetadata(archetype, request))
6567
return response;

lib/IRGen/GenDecl.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5493,13 +5493,6 @@ Address IRGenFunction::createAlloca(llvm::Type *type,
54935493
return Address(alloca, type, alignment);
54945494
}
54955495

5496-
/// Allocate a fixed-size buffer on the stack.
5497-
Address IRGenFunction::createFixedSizeBufferAlloca(const llvm::Twine &name) {
5498-
return createAlloca(IGM.getFixedBufferTy(),
5499-
getFixedBufferAlignment(IGM),
5500-
name);
5501-
}
5502-
55035496
/// Get or create a global string constant.
55045497
///
55055498
/// \returns an i8* with a null terminator; note that embedded nulls

lib/IRGen/GenPack.cpp

Lines changed: 280 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2022 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
@@ -14,7 +14,9 @@
1414
//
1515
//===----------------------------------------------------------------------===//
1616

17+
#include "GenPack.h"
1718
#include "swift/AST/Decl.h"
19+
#include "swift/AST/GenericEnvironment.h"
1820
#include "swift/AST/IRGenOptions.h"
1921
#include "swift/AST/Types.h"
2022
#include "swift/SIL/SILModule.h"
@@ -24,49 +26,303 @@
2426
#include "GenType.h"
2527
#include "IRGenFunction.h"
2628
#include "IRGenModule.h"
29+
#include "MetadataRequest.h"
2730

2831
using namespace swift;
2932
using namespace irgen;
3033

31-
llvm::Value *IRGenFunction::emitPackShapeExpression(CanType type) {
34+
static void accumulateSum(IRGenFunction &IGF, llvm::Value *&result,
35+
llvm::Value *value) {
36+
if (result == nullptr) {
37+
result = value;
38+
return;
39+
}
3240

33-
type = type->getReducedShape()->getCanonicalType();
41+
result = IGF.Builder.CreateAdd(result, value);
42+
}
3443

35-
auto kind = LocalTypeDataKind::forPackShapeExpression();
44+
using PackExplosionCallback = void (CanType eltTy,
45+
unsigned scalarIndex,
46+
llvm::Value *dynamicIndex,
47+
llvm::Value *dynamicLength);
3648

37-
llvm::Value *result = tryGetLocalTypeData(type, kind);
38-
if (result != nullptr)
39-
return result;
49+
static std::pair<unsigned, llvm::Value *>
50+
visitPackExplosion(IRGenFunction &IGF, CanPackType type,
51+
llvm::function_ref<PackExplosionCallback> callback) {
52+
llvm::Value *result = nullptr;
4053

4154
// If shape(T) == t and shape(U) == u, the shape expression for a pack
4255
// {T..., Int, T..., U..., String} becomes 't + t + u + 2'.
4356
unsigned scalarElements = 0;
4457

45-
auto accumulate = [&](llvm::Value *value) {
46-
if (result == nullptr) {
47-
result = value;
48-
return;
49-
}
50-
51-
result = Builder.CreateAdd(result, value);
52-
};
53-
54-
auto packType = cast<PackType>(type);
55-
for (auto elt : packType.getElementTypes()) {
58+
for (auto elt : type.getElementTypes()) {
5659
if (auto expansionType = dyn_cast<PackExpansionType>(elt)) {
5760
auto reducedShape = expansionType.getCountType();
58-
accumulate(emitPackShapeExpression(reducedShape));
61+
auto *eltCount = IGF.emitPackShapeExpression(reducedShape);
62+
callback(elt, scalarElements, result, eltCount);
63+
accumulateSum(IGF, result, eltCount);
5964
continue;
6065
}
6166

67+
callback(elt, scalarElements, result, nullptr);
6268
++scalarElements;
6369
}
6470

65-
if (scalarElements > 0) {
66-
auto *constant = llvm::ConstantInt::get(IGM.SizeTy, scalarElements);
67-
accumulate(constant);
71+
return std::make_pair(scalarElements, result);
72+
}
73+
74+
llvm::Value *IRGenFunction::emitPackShapeExpression(CanType type) {
75+
76+
type = type->getReducedShape()->getCanonicalType();
77+
78+
auto kind = LocalTypeDataKind::forPackShapeExpression();
79+
80+
llvm::Value *result = tryGetLocalTypeData(type, kind);
81+
if (result != nullptr)
82+
return result;
83+
84+
auto pair = visitPackExplosion(
85+
*this, cast<PackType>(type),
86+
[&](CanType, unsigned, llvm::Value *, llvm::Value *) {});
87+
88+
if (pair.first > 0) {
89+
auto *constant = llvm::ConstantInt::get(IGM.SizeTy, pair.first);
90+
accumulateSum(*this, pair.second, constant);
91+
}
92+
93+
setScopedLocalTypeData(type, kind, pair.second);
94+
return pair.second;
95+
}
96+
97+
MetadataResponse
98+
irgen::emitPackArchetypeMetadataRef(IRGenFunction &IGF,
99+
CanPackArchetypeType type,
100+
DynamicMetadataRequest request) {
101+
if (auto result = IGF.tryGetLocalTypeMetadata(type, request))
102+
return result;
103+
104+
auto packType = type->getSingletonPackType();
105+
auto response = emitTypeMetadataPackRef(IGF, packType, request);
106+
107+
IGF.setScopedLocalTypeMetadata(type, response);
108+
return response;
109+
}
110+
111+
static Address emitFixedSizeMetadataPackRef(IRGenFunction &IGF,
112+
CanPackType packType,
113+
DynamicMetadataRequest request) {
114+
assert(!packType->containsPackExpansionType());
115+
116+
unsigned elementCount = packType->getNumElements();
117+
auto allocType = llvm::ArrayType::get(
118+
IGF.IGM.TypeMetadataPtrTy, elementCount);
119+
120+
auto pack = IGF.createAlloca(allocType, IGF.IGM.getPointerAlignment());
121+
IGF.Builder.CreateLifetimeStart(pack,
122+
IGF.IGM.getPointerSize() * elementCount);
123+
124+
for (unsigned i : indices(packType->getElementTypes())) {
125+
Address slot = IGF.Builder.CreateStructGEP(
126+
pack, i, IGF.IGM.getPointerSize());
127+
128+
auto metadata = IGF.emitTypeMetadataRef(
129+
packType.getElementType(i), request).getMetadata();
130+
IGF.Builder.CreateStore(metadata, slot);
131+
}
132+
133+
pack = IGF.Builder.CreateConstArrayGEP(
134+
pack, 0, IGF.IGM.getPointerSize());
135+
136+
return pack;
137+
}
138+
139+
static void emitPackExpansionType(IRGenFunction &IGF,
140+
Address pack,
141+
CanPackExpansionType expansionTy,
142+
llvm::Value *dynamicIndex,
143+
llvm::Value *dynamicLength,
144+
DynamicMetadataRequest request) {
145+
auto *prev = IGF.Builder.GetInsertBlock();
146+
auto *check = IGF.createBasicBlock("pack-expansion-check");
147+
auto *loop = IGF.createBasicBlock("pack-expansion-loop");
148+
auto *rest = IGF.createBasicBlock("pack-expansion-rest");
149+
150+
IGF.Builder.CreateBr(check);
151+
IGF.Builder.emitBlock(check);
152+
153+
// An index into the source metadata pack.
154+
auto *phi = IGF.Builder.CreatePHI(IGF.IGM.SizeTy, 2);
155+
phi->addIncoming(llvm::ConstantInt::get(IGF.IGM.SizeTy, 0), prev);
156+
157+
// If we reach the end, jump to the continuation block.
158+
auto *cond = IGF.Builder.CreateICmpULT(phi, dynamicLength);
159+
IGF.Builder.CreateCondBr(cond, loop, rest);
160+
161+
IGF.Builder.emitBlock(loop);
162+
163+
auto patternTy = expansionTy.getPatternType();
164+
165+
// Find all the pack archetypes appearing in the pattern type.
166+
SmallVector<Type, 2> patternPacks;
167+
patternTy->getTypeParameterPacks(patternPacks);
168+
169+
// Get the outer generic signature and environment.
170+
auto *genericEnv = cast<PackArchetypeType>(expansionTy.getCountType())
171+
->getGenericEnvironment();
172+
auto subMap = genericEnv->getForwardingSubstitutionMap();
173+
174+
auto genericSig = genericEnv->getGenericSignature().getCanonicalSignature();
175+
176+
// Create an opened element signature and environment.
177+
auto elementSig = IGF.IGM.Context.getOpenedElementSignature(genericSig);
178+
auto *elementEnv = GenericEnvironment::forOpenedElement(
179+
elementSig, UUID::fromTime(), subMap);
180+
181+
// Open each pack archetype.
182+
for (auto patternPackType : patternPacks) {
183+
// Get the metadata for the pack archetype.
184+
auto patternPackArchetype = cast<PackArchetypeType>(
185+
patternPackType->getCanonicalType());
186+
auto patternPack = IGF.emitTypeMetadataRef(patternPackArchetype, request)
187+
.getMetadata();
188+
189+
patternPack = IGF.Builder.CreatePointerCast(
190+
patternPack, IGF.IGM.TypeMetadataPtrPtrTy);
191+
192+
Address patternPackAddress(patternPack, IGF.IGM.TypeMetadataPtrTy,
193+
IGF.IGM.getPointerAlignment());
194+
195+
// Load the metadata pack element from the current source index.
196+
Address fromPtr(
197+
IGF.Builder.CreateInBoundsGEP(patternPackAddress.getElementType(),
198+
patternPackAddress.getAddress(),
199+
phi),
200+
patternPackAddress.getElementType(),
201+
patternPackAddress.getAlignment());
202+
auto metadata = IGF.Builder.CreateLoad(fromPtr);
203+
204+
// Bind the metadata pack element to the element archetype.
205+
auto elementArchetype =
206+
elementEnv->mapPackTypeIntoElementContext(
207+
patternPackArchetype->getInterfaceType());
208+
209+
IGF.setScopedLocalTypeMetadata(
210+
CanType(elementArchetype),
211+
MetadataResponse::forComplete(metadata));
212+
}
213+
214+
// Replace pack archetypes with element archetypes in the pattern type.
215+
auto instantiatedPatternTy = elementEnv->mapPackTypeIntoElementContext(
216+
patternTy->mapTypeOutOfContext())->getCanonicalType();
217+
218+
// Emit the element metadata.
219+
auto element = IGF.emitTypeMetadataRef(instantiatedPatternTy, request)
220+
.getMetadata();
221+
222+
// Store the element metadata into to the current destination index.
223+
auto *eltIndex = IGF.Builder.CreateAdd(dynamicIndex, phi);
224+
Address eltPtr(
225+
IGF.Builder.CreateInBoundsGEP(pack.getElementType(),
226+
pack.getAddress(),
227+
eltIndex),
228+
pack.getElementType(),
229+
pack.getAlignment());
230+
231+
IGF.Builder.CreateStore(element, eltPtr);
232+
233+
// Increment our counter.
234+
auto *next = IGF.Builder.CreateAdd(phi,
235+
llvm::ConstantInt::get(IGF.IGM.SizeTy, 1));
236+
237+
phi->addIncoming(next, loop);
238+
239+
// Repeat the loop.
240+
IGF.Builder.CreateBr(check);
241+
242+
// Fall through.
243+
IGF.Builder.emitBlock(rest);
244+
}
245+
246+
StackAddress
247+
irgen::emitTypeMetadataPack(IRGenFunction &IGF,
248+
CanPackType packType,
249+
DynamicMetadataRequest request) {
250+
auto *shape = IGF.emitPackShapeExpression(packType);
251+
252+
if (auto *constantInt = dyn_cast<llvm::ConstantInt>(shape)) {
253+
assert(packType->getNumElements() == constantInt->getValue());
254+
return StackAddress(emitFixedSizeMetadataPackRef(IGF, packType, request));
68255
}
69256

70-
setScopedLocalTypeData(type, kind, result);
71-
return result;
257+
assert(packType->containsPackExpansionType());
258+
auto pack = IGF.emitDynamicAlloca(IGF.IGM.TypeMetadataPtrTy, shape,
259+
IGF.IGM.getPointerAlignment(),
260+
/*allowTaskAlloc=*/true);
261+
262+
auto visitFn =
263+
[&](CanType eltTy, unsigned staticIndex,
264+
llvm::Value *dynamicIndex,
265+
llvm::Value *dynamicLength) {
266+
if (staticIndex != 0 || dynamicIndex == nullptr) {
267+
auto *constant = llvm::ConstantInt::get(IGF.IGM.SizeTy, staticIndex);
268+
accumulateSum(IGF, dynamicIndex, constant);
269+
}
270+
271+
if (auto expansionTy = dyn_cast<PackExpansionType>(eltTy)) {
272+
emitPackExpansionType(IGF, pack.getAddress(), expansionTy,
273+
dynamicIndex, dynamicLength, request);
274+
} else {
275+
Address eltPtr(
276+
IGF.Builder.CreateInBoundsGEP(pack.getAddress().getElementType(),
277+
pack.getAddressPointer(),
278+
dynamicIndex),
279+
pack.getAddress().getElementType(),
280+
pack.getAlignment());
281+
282+
auto metadata = IGF.emitTypeMetadataRef(eltTy, request).getMetadata();
283+
IGF.Builder.CreateStore(metadata, eltPtr);
284+
}
285+
};
286+
287+
visitPackExplosion(IGF, packType, visitFn);
288+
289+
return pack;
290+
}
291+
292+
MetadataResponse
293+
irgen::emitTypeMetadataPackRef(IRGenFunction &IGF,
294+
CanPackType packType,
295+
DynamicMetadataRequest request) {
296+
if (auto result = IGF.tryGetLocalTypeMetadata(packType, request))
297+
return result;
298+
299+
if (packType->getNumElements() == 1 &&
300+
isa<PackExpansionType>(packType.getElementType(0))) {
301+
if (auto packArchetypeType = dyn_cast<PackArchetypeType>(
302+
cast<PackExpansionType>(packType.getElementType(0))
303+
.getPatternType())) {
304+
if (auto result = IGF.tryGetLocalTypeMetadata(packArchetypeType, request))
305+
return result;
306+
}
307+
}
308+
309+
auto pack = emitTypeMetadataPack(IGF, packType, request);
310+
auto *metadata = IGF.Builder.CreateConstArrayGEP(
311+
pack.getAddress(), 0, IGF.IGM.getPointerSize()).getAddress();
312+
313+
auto response = MetadataResponse::forComplete(metadata);
314+
IGF.setScopedLocalTypeMetadata(packType, response);
315+
316+
return response;
317+
}
318+
319+
void irgen::cleanupTypeMetadataPack(IRGenFunction &IGF,
320+
StackAddress pack,
321+
Optional<unsigned> elementCount) {
322+
if (pack.getExtraInfo()) {
323+
IGF.emitDeallocateDynamicAlloca(pack);
324+
} else {
325+
IGF.Builder.CreateLifetimeEnd(pack.getAddress(),
326+
IGF.IGM.getPointerSize() * (*elementCount));
327+
}
72328
}

0 commit comments

Comments
 (0)