Skip to content

Commit 4128050

Browse files
committed
[IRGen] Lowered open_pack_element.
1 parent ffbe85f commit 4128050

File tree

5 files changed

+302
-3
lines changed

5 files changed

+302
-3
lines changed

lib/IRGen/GenPack.cpp

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,188 @@ irgen::emitTypeMetadataPackRef(IRGenFunction &IGF, CanPackType packType,
368368
return response;
369369
}
370370

371+
llvm::Value *
372+
irgen::emitTypeMetadataPackElementRef(IRGenFunction &IGF, CanPackType packType,
373+
llvm::Value *index,
374+
DynamicMetadataRequest request) {
375+
// If the pack has already been materialized, just gep into it.
376+
if (auto pack = tryGetLocalPackTypeMetadata(IGF, packType, request)) {
377+
auto *gep = IGF.Builder.CreateInBoundsGEP(IGF.IGM.TypeMetadataPtrTy,
378+
pack.getMetadata(), index);
379+
auto addr =
380+
Address(gep, IGF.IGM.TypeMetadataPtrTy, IGF.IGM.getPointerAlignment());
381+
auto *metadata = IGF.Builder.CreateLoad(addr);
382+
return metadata;
383+
}
384+
385+
// Otherwise, in general, there's no already available array of metadata
386+
// which can be indexed into.
387+
auto *shape = IGF.emitPackShapeExpression(packType);
388+
389+
// If the shape and the index are both constant, the type for which metadata
390+
// will be emitted is statically available.
391+
auto *constantShape = dyn_cast<llvm::ConstantInt>(shape);
392+
auto *constantIndex = dyn_cast<llvm::ConstantInt>(index);
393+
if (constantShape && constantIndex) {
394+
assert(packType->getNumElements() == constantShape->getValue());
395+
auto index = constantIndex->getValue().getZExtValue();
396+
assert(packType->getNumElements() > index);
397+
auto ty = packType.getElementType(index);
398+
auto response = IGF.emitTypeMetadataRef(ty, request);
399+
auto *metadata = response.getMetadata();
400+
return metadata;
401+
}
402+
403+
// A pack consists of types and pack expansion types. An example:
404+
// {repeat each T, Int, repeat each T, repeat each U, String},
405+
// The above type has length 5. The type "repeat each U" is at index 3.
406+
//
407+
// A pack _explosion_ is notionally obtained by flat-mapping the pack by the
408+
// the operation of "listing elements" in pack expansion types.
409+
//
410+
// The explosion of the example pack looks like
411+
// {T_0, T_1, ..., Int, T_0, T_1, ..., U_0, U_1, ..., String}
412+
// ^^^^^^^^^^^^^
413+
// the runtime components of "each T"
414+
//
415+
// We have an index into the explosion,
416+
//
417+
// {T_0, T_1, ..., Int, T_0, T_1, ..., U_0, U_1, ... String}
418+
// ------------%index------------>
419+
//
420+
// and we need to obtain the element in the explosion corresponding to it.
421+
//
422+
// {T_0, T_1, ..., Int, T_0, T_1, ..., T_k, ..., U_0, U_1, ... String}
423+
// ------------%index---------------> ^^^
424+
//
425+
// Unfortunately, the explosion has not (the first check in this function)
426+
// been materialized--and doing so is likely wasteful--so we can't simply
427+
// index into some array.
428+
//
429+
// Instead, we will compute
430+
// (1) the index into the _pack_ and
431+
// {repeat each T, Int, repeat each T, repeat each U, String}
432+
// ------%outer------> ^^^^^^^^^^^^^
433+
// (2) the index within the elements of the pack expansion type
434+
// {T_0, T_2, ..., T_k, ...}
435+
// ----%inner---> ^^^
436+
//
437+
// The first index will be switched over. The second index will be used in
438+
// the destination blocks.
439+
auto *current = IGF.Builder.GetInsertBlock();
440+
441+
// Terminate the block that branches to candidate or exit.
442+
auto emitBranchTo = [&IGF](llvm::Value *condition, llvm::BasicBlock *exit,
443+
llvm::BasicBlock *candidate) {
444+
if (condition) {
445+
IGF.Builder.CreateCondBr(condition, exit, candidate);
446+
} else {
447+
IGF.Builder.CreateBr(candidate);
448+
}
449+
};
450+
451+
auto *indexBlock = IGF.createBasicBlock("pack-index-element-outer-index");
452+
IGF.Builder.emitBlock(indexBlock);
453+
// The index into the pack:
454+
// {repeat each T, Int, repeat each T, repeat each U, String}
455+
// -------%outer------> ^^^^^^^^^^^^^
456+
auto *outerIndexPhi =
457+
IGF.Builder.CreatePHI(IGF.IGM.SizeTy, packType.getElementTypes().size());
458+
// The lower bound of the pack expansion:
459+
// {T_0, T_1, ..., Int, T_0, T_1, ..., T_k, ..., U_0, U_1, ... String}
460+
// ------%lower------> ^^^
461+
// By subtracting it from the index
462+
// {T_0, T_1, ..., Int, T_0, T_1, ..., T_k, ..., U_0, U_1, ... String}
463+
// ------------%index---------------> ^^^
464+
// the index within the elements of the pack expansion is obtained:
465+
// {T_0, T_2, ..., T_k, ...}
466+
// ----%inner---> ^^^
467+
// := %index - %lower
468+
auto *lowerBoundPhi =
469+
IGF.Builder.CreatePHI(IGF.IGM.SizeTy, packType.getElementTypes().size());
470+
IGF.Builder.SetInsertPoint(current);
471+
llvm::Value *condition = nullptr;
472+
auto packIndex = 0;
473+
llvm::Value *lowerBound = llvm::ConstantInt::get(IGF.IGM.SizeTy, 0);
474+
llvm::SmallVector<std::pair<llvm::BasicBlock *, unsigned>, 4> incomingOuters;
475+
for (auto elementTy : packType.getElementTypes()) {
476+
auto *candidate = IGF.createBasicBlock("pack-index-element-candidate");
477+
emitBranchTo(condition, indexBlock, candidate);
478+
IGF.Builder.emitBlock(candidate);
479+
480+
llvm::Value *upperBound = nullptr;
481+
if (auto expansionTy = dyn_cast<PackExpansionType>(elementTy)) {
482+
auto reducedShape = expansionTy.getCountType();
483+
auto *length = IGF.emitPackShapeExpression(reducedShape);
484+
upperBound = IGF.Builder.CreateAdd(lowerBound, length);
485+
// %index < %upperBound
486+
//
487+
// It's not necessary to check that %index >= %lowerBound. Either
488+
// elementTy is the first element type in packType or we branched here
489+
// from some series of candidate blocks in each of which it was determined
490+
// that %index is greater than the indices of the corresponding element
491+
// type.
492+
condition = IGF.Builder.CreateICmpULT(index, upperBound);
493+
} else {
494+
upperBound = IGF.Builder.CreateAdd(
495+
lowerBound, llvm::ConstantInt::get(IGF.IGM.SizeTy, 1));
496+
// %index == %lowerBound
497+
condition = IGF.Builder.CreateICmpEQ(lowerBound, index);
498+
}
499+
outerIndexPhi->addIncoming(
500+
llvm::ConstantInt::get(IGF.IGM.SizeTy, packIndex), candidate);
501+
lowerBoundPhi->addIncoming(lowerBound, candidate);
502+
503+
lowerBound = upperBound;
504+
++packIndex;
505+
}
506+
auto *trap = IGF.createBasicBlock("pack-index-element-trap");
507+
emitBranchTo(condition, indexBlock, trap);
508+
509+
IGF.Builder.emitBlock(trap);
510+
IGF.emitTrap("Variadic generic index out of bounds",
511+
/*EmitUnreachable=*/true);
512+
513+
// At this point, both the outer and inner indices (%outer and %inner
514+
// respectively) are available.
515+
// %outer := outerIndexPhi
516+
// %inner := sub index, innerIndexPhi
517+
//
518+
// Now construct blocks for each element of the pack and switch on the outer
519+
// index to decide which to jump to. Each block will use the inner index to
520+
// materialize the metadata for the inner index.
521+
IGF.Builder.SetInsertPoint(indexBlock);
522+
auto *switchInst = IGF.Builder.CreateSwitch(
523+
outerIndexPhi, trap, packType.getElementTypes().size());
524+
525+
auto *exit = IGF.createBasicBlock("pack-index-element-exit");
526+
IGF.Builder.emitBlock(exit);
527+
auto *metadataPhi = IGF.Builder.CreatePHI(IGF.IGM.TypeMetadataPtrTy,
528+
packType.getElementTypes().size());
529+
530+
packIndex = 0;
531+
for (auto elementTy : packType.getElementTypes()) {
532+
auto *block = IGF.createBasicBlock("pack-index-element-selection");
533+
switchInst->addCase(llvm::ConstantInt::get(IGF.IGM.SizeTy, packIndex),
534+
block);
535+
IGF.Builder.emitBlock(block);
536+
537+
llvm::Value *metadata = nullptr;
538+
if (auto expansionTy = dyn_cast<PackExpansionType>(elementTy)) {
539+
auto *relativeIndex = IGF.Builder.CreateSub(index, lowerBoundPhi);
540+
metadata = emitPackExpansionElementMetadata(IGF, expansionTy,
541+
relativeIndex, request);
542+
} else {
543+
metadata = IGF.emitTypeMetadataRef(elementTy, request).getMetadata();
544+
}
545+
metadataPhi->addIncoming(metadata, block);
546+
IGF.Builder.CreateBr(exit);
547+
++packIndex;
548+
}
549+
IGF.Builder.SetInsertPoint(exit);
550+
return metadataPhi;
551+
}
552+
371553
void irgen::cleanupTypeMetadataPack(IRGenFunction &IGF,
372554
StackAddress pack,
373555
Optional<unsigned> elementCount) {

lib/IRGen/GenPack.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ emitTypeMetadataPackRef(IRGenFunction &IGF,
5050
CanPackType packType,
5151
DynamicMetadataRequest request);
5252

53+
llvm::Value *emitTypeMetadataPackElementRef(IRGenFunction &IGF,
54+
CanPackType packType,
55+
llvm::Value *index,
56+
DynamicMetadataRequest request);
57+
5358
void cleanupTypeMetadataPack(IRGenFunction &IGF,
5459
StackAddress pack,
5560
Optional<unsigned> elementCount);

lib/IRGen/IRGenSIL.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include "swift/AST/ASTContext.h"
1919
#include "swift/AST/DiagnosticsIRGen.h"
20+
#include "swift/AST/GenericEnvironment.h"
2021
#include "swift/AST/IRGenOptions.h"
2122
#include "swift/AST/ParameterList.h"
2223
#include "swift/AST/Pattern.h"
@@ -49,8 +50,8 @@
4950
#include "llvm/ADT/TinyPtrVector.h"
5051
#include "llvm/IR/Constant.h"
5152
#include "llvm/IR/Constants.h"
52-
#include "llvm/IR/DebugInfo.h"
5353
#include "llvm/IR/DIBuilder.h"
54+
#include "llvm/IR/DebugInfo.h"
5455
#include "llvm/IR/Function.h"
5556
#include "llvm/IR/InlineAsm.h"
5657
#include "llvm/IR/Instructions.h"
@@ -6863,8 +6864,17 @@ void IRGenSILFunction::visitScalarPackIndexInst(ScalarPackIndexInst *i) {
68636864
void IRGenSILFunction::visitOpenPackElementInst(swift::OpenPackElementInst *i) {
68646865
llvm::Value *index = getLoweredSingletonExplosion(i->getIndexOperand());
68656866

6866-
// FIXME: bind the archetypes
6867-
(void) index;
6867+
llvm::SmallVector<CanPackType, 2> packs;
6868+
i->getOpenedGenericEnvironment()->forEachPackElementBinding(
6869+
[&](auto *archetype, auto *pack) { packs.push_back(CanPackType(pack)); });
6870+
auto packIndex = 0;
6871+
i->forEachDefinedLocalArchetype([&](auto archetype, auto value) {
6872+
auto pack = packs[packIndex];
6873+
auto *metadata = emitTypeMetadataPackElementRef(*this, pack, index,
6874+
MetadataState::Complete);
6875+
this->bindArchetype(archetype, metadata, MetadataState::Complete, {});
6876+
++packIndex;
6877+
});
68686878

68696879
// The result is just used for type dependencies.
68706880
}

test/IRGen/run_variadic_generics.sil

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift-dylib(%t/%target-library-name(PrintShims)) %S/../Inputs/print-shims.swift -module-name PrintShims -emit-module -emit-module-path %t/PrintShims.swiftmodule
3+
// RUN: %target-codesign %t/%target-library-name(PrintShims)
4+
// RUN: %target-build-swift -enable-experimental-feature VariadicGenerics -g -parse-sil %s -module-name main -o %t/main -I %t -L %t -lPrintShims %target-rpath(%t)
5+
// RUN: %target-codesign %t/main
6+
// RUN: %target-run %t/main %t/%target-library-name(PrintShims) | %FileCheck %s
7+
8+
// REQUIRES: executable_test
9+
10+
// Because of -enable-experimental-feature VariadicGenerics
11+
// REQUIRES: asserts
12+
13+
import Builtin
14+
import Swift
15+
import PrintShims
16+
17+
sil public_external @printGenericType : $@convention(thin) <T> (@thick T.Type) -> ()
18+
19+
struct A {}
20+
struct B {}
21+
struct C {}
22+
struct D {}
23+
struct E {}
24+
struct F {}
25+
26+
sil [ossa] @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
27+
bb0(%argc : $Int32, %argv : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
28+
%f = function_ref @f : $@convention(thin) <T_1..., T_2... where (repeat (each T_1, each T_2)): Any> (Builtin.Word) -> ()
29+
%0 = integer_literal $Builtin.Word, 0
30+
// U_1 -> {A, B, C, D, E, F}
31+
// ---0--> ^
32+
// CHECK: A
33+
// U_2 -> {D, E, F, A, B, C}
34+
// ---0--> ^
35+
// CHECK: D
36+
apply %f<Pack{A, B, C}, Pack{D, E, F}>(%0) : $@convention(thin) <T_1..., T_2... where (repeat (each T_1, each T_2)): Any> (Builtin.Word) -> ()
37+
%1 = integer_literal $Builtin.Word, 1
38+
// U_1 -> {A, B, C, D, E, F}
39+
// ----1----> ^
40+
// CHECK: B
41+
// U_2 -> {D, E, F, A, B, C}
42+
// ----1----> ^
43+
// CHECK: E
44+
apply %f<Pack{A, B, C}, Pack{D, E, F}>(%1) : $@convention(thin) <T_1..., T_2... where (repeat (each T_1, each T_2)): Any> (Builtin.Word) -> ()
45+
%2 = integer_literal $Builtin.Word, 2
46+
// U_1 -> {A, B, C, D, E, F}
47+
// ------2-----> ^
48+
// CHECK: C
49+
// U_2 -> {D, E, F, A, B, C}
50+
// ------2-----> ^
51+
// CHECK: F
52+
apply %f<Pack{A, B, C}, Pack{D, E, F}>(%2) : $@convention(thin) <T_1..., T_2... where (repeat (each T_1, each T_2)): Any> (Builtin.Word) -> ()
53+
%3 = integer_literal $Builtin.Word, 3
54+
// U_1 -> {A, B, C, D, E, F}
55+
// -------3-------> ^
56+
// CHECK: D
57+
// U_2 -> {D, E, F, A, B, C}
58+
// -------3-------> ^
59+
// CHECK: A
60+
apply %f<Pack{A, B, C}, Pack{D, E, F}>(%3) : $@convention(thin) <T_1..., T_2... where (repeat (each T_1, each T_2)): Any> (Builtin.Word) -> ()
61+
%4 = integer_literal $Builtin.Word, 4
62+
// U_1 -> {A, B, C, D, E, F}
63+
// ---------4--------> ^
64+
// CHECK: E
65+
// U_2 -> {D, E, F, A, B, C}
66+
// ---------4--------> ^
67+
// CHECK: B
68+
apply %f<Pack{A, B, C}, Pack{D, E, F}>(%4) : $@convention(thin) <T_1..., T_2... where (repeat (each T_1, each T_2)): Any> (Builtin.Word) -> ()
69+
%5 = integer_literal $Builtin.Word, 5
70+
// U_1 -> {A, B, C, D, E, F}
71+
// -----------5---------> ^
72+
// CHECK: F
73+
// U_2 -> {D, E, F, A, B, C}
74+
// -----------5---------> ^
75+
// CHECK: C
76+
apply %f<Pack{A, B, C}, Pack{D, E, F}>(%5) : $@convention(thin) <T_1..., T_2... where (repeat (each T_1, each T_2)): Any> (Builtin.Word) -> ()
77+
78+
%outb = integer_literal $Builtin.Int32, 0
79+
%out = struct $Int32 (%outb : $Builtin.Int32)
80+
return %out : $Int32
81+
}
82+
83+
sil @f : $<T_1..., T_2... where (repeat (each T_1, each T_2)): Any> (Builtin.Word) -> () {
84+
entry(%intIndex : $Builtin.Word):
85+
%innerIndex = dynamic_pack_index %intIndex of $Pack{repeat each T_1, repeat each T_2}
86+
%token = open_pack_element %innerIndex of <U_1..., U_2... where (repeat (each U_1, each U_2)): Any> at <Pack{repeat each T_1, repeat each T_2}, Pack{repeat each T_2, repeat each T_1}>, shape $U_2, uuid "01234567-89AB-CDEF-0123-000000000000"
87+
%metatype_1 = metatype $@thick (@pack_element("01234567-89AB-CDEF-0123-000000000000") U_1).Type
88+
%metatype_2 = metatype $@thick (@pack_element("01234567-89AB-CDEF-0123-000000000000") U_2).Type
89+
%printGenericType = function_ref @printGenericType : $@convention(thin) <T> (@thick T.Type) -> ()
90+
// Print the first archetype that is bound.
91+
apply %printGenericType<(@pack_element("01234567-89AB-CDEF-0123-000000000000") U_1)>(%metatype_1) : $@convention(thin) <T> (@thick T.Type) -> ()
92+
// Print the second archetype that is bound.
93+
apply %printGenericType<(@pack_element("01234567-89AB-CDEF-0123-000000000000") U_2)>(%metatype_2) : $@convention(thin) <T> (@thick T.Type) -> ()
94+
%retval = tuple ()
95+
return %retval : $()
96+
}

test/Inputs/print-shims.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,9 @@ public func printBool(_ bool: Bool) {
2222
public func printAny(_ any: Any) {
2323
print(any)
2424
}
25+
26+
@_silgen_name("printGenericType")
27+
public func printGenericType<T>(_ t: T.Type) {
28+
print(T.self)
29+
}
30+

0 commit comments

Comments
 (0)