Skip to content

Commit 73d68a3

Browse files
committed
[IRGen] Pack metadata may be alloc'd for layouts.
Previously, mayRequirePackMetadata only considered whether a type involved a pack. That failed to account for the case of outlined value functions that require pack metadata when the type involves a pack in its layout. Here, mayRequirePackMetadata now considers also whether the layout corresponding to a type involves a pack. rdar://119829826
1 parent 75b2707 commit 73d68a3

File tree

5 files changed

+122
-13
lines changed

5 files changed

+122
-13
lines changed

include/swift/SIL/SILInstruction.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -853,7 +853,7 @@ class SILInstruction : public llvm::ilist_node<SILInstruction> {
853853

854854
/// Whether IRGen lowering of this instruction may result in emitting packs of
855855
/// metadata or witness tables.
856-
bool mayRequirePackMetadata() const;
856+
bool mayRequirePackMetadata(SILFunction const &F) const;
857857

858858
/// Create a new copy of this instruction, which retains all of the operands
859859
/// and other information of this one. If an insertion point is specified,

lib/IRGen/PackMetadataMarkerInserter.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,9 @@ Inserter::shouldInsertMarkersForInstruction(SILInstruction *inst) {
9494
LLVM_FALLTHROUGH;
9595
}
9696
default:
97-
return inst->mayRequirePackMetadata() ? FindResult::Some : FindResult::None;
97+
return inst->mayRequirePackMetadata(*inst->getFunction())
98+
? FindResult::Some
99+
: FindResult::None;
98100
}
99101
}
100102

lib/SIL/IR/SILInstruction.cpp

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1301,7 +1301,11 @@ bool SILInstruction::isDeallocatingStack() const {
13011301
return false;
13021302
}
13031303

1304-
bool SILInstruction::mayRequirePackMetadata() const {
1304+
static bool typeOrLayoutInvolvesPack(SILType ty, SILFunction const &F) {
1305+
return ty.hasAnyPack() || ty.isOrContainsPack(F);
1306+
}
1307+
1308+
bool SILInstruction::mayRequirePackMetadata(SILFunction const &F) const {
13051309
switch (getKind()) {
13061310
case SILInstructionKind::AllocPackInst:
13071311
case SILInstructionKind::TuplePackElementAddrInst:
@@ -1313,11 +1317,11 @@ bool SILInstruction::mayRequirePackMetadata() const {
13131317
case SILInstructionKind::TryApplyInst: {
13141318
// Check the function type for packs.
13151319
auto apply = ApplySite::isa(const_cast<SILInstruction *>(this));
1316-
if (apply.getCallee()->getType().hasAnyPack())
1320+
if (typeOrLayoutInvolvesPack(apply.getCallee()->getType(), F))
13171321
return true;
13181322
// Check the substituted types for packs.
13191323
for (auto ty : apply.getSubstitutionMap().getReplacementTypes()) {
1320-
if (ty->hasAnyPack())
1324+
if (typeOrLayoutInvolvesPack(F.getTypeLowering(ty).getLoweredType(), F))
13211325
return true;
13221326
}
13231327
return false;
@@ -1328,20 +1332,20 @@ bool SILInstruction::mayRequirePackMetadata() const {
13281332
case SILInstructionKind::DestroyValueInst:
13291333
// Unary instructions.
13301334
{
1331-
return getOperand(0)->getType().hasAnyPack();
1335+
return typeOrLayoutInvolvesPack(getOperand(0)->getType(), F);
13321336
}
13331337
case SILInstructionKind::AllocStackInst: {
13341338
auto *asi = cast<AllocStackInst>(this);
1335-
return asi->getType().hasAnyPack();
1339+
return typeOrLayoutInvolvesPack(asi->getType(), F);
13361340
}
13371341
case SILInstructionKind::MetatypeInst: {
13381342
auto *mi = cast<MetatypeInst>(this);
1339-
return mi->getType().hasAnyPack();
1343+
return typeOrLayoutInvolvesPack(mi->getType(), F);
13401344
}
13411345
case SILInstructionKind::WitnessMethodInst: {
13421346
auto *wmi = cast<WitnessMethodInst>(this);
13431347
auto ty = wmi->getLookupType();
1344-
return ty->hasAnyPack();
1348+
return typeOrLayoutInvolvesPack(F.getTypeLowering(ty).getLoweredType(), F);
13451349
}
13461350
default:
13471351
// Instructions that deallocate stack must not result in pack metadata
@@ -1359,15 +1363,15 @@ bool SILInstruction::mayRequirePackMetadata() const {
13591363
// Check results and operands for packs. If a pack appears, lowering the
13601364
// instruction might result in pack metadata emission.
13611365
for (auto result : getResults()) {
1362-
if (result->getType().hasAnyPack())
1366+
if (typeOrLayoutInvolvesPack(result->getType(), F))
13631367
return true;
13641368
}
13651369
for (auto operandTy : getOperandTypes()) {
1366-
if (operandTy.hasAnyPack())
1370+
if (typeOrLayoutInvolvesPack(operandTy, F))
13671371
return true;
13681372
}
13691373
for (auto &tdo : getTypeDependentOperands()) {
1370-
if (tdo.get()->getType().hasAnyPack())
1374+
if (typeOrLayoutInvolvesPack(tdo.get()->getType(), F))
13711375
return true;
13721376
}
13731377

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6270,7 +6270,7 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
62706270
}
62716271

62726272
void checkAllocPackMetadataInst(AllocPackMetadataInst *apmi) {
6273-
require(apmi->getIntroducer()->mayRequirePackMetadata(),
6273+
require(apmi->getIntroducer()->mayRequirePackMetadata(*apmi->getFunction()),
62746274
"Introduces instruction of kind which cannot emit on-stack pack "
62756275
"metadata");
62766276
require(F.getModule().getStage() == SILStage::Lowered,
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// RUN: %target-swift-frontend -Onone -disable-availability-checking -emit-ir -primary-file %s -enable-pack-metadata-stack-promotion=false -enable-pack-metadata-stack-promotion=true -Xllvm -sil-print-after=pack-metadata-marker-inserter 2>&1 | %FileCheck %s --check-prefixes CHECK-SIL
2+
// RUN: %target-swift-frontend -Onone -disable-availability-checking -emit-ir -primary-file %s -enable-pack-metadata-stack-promotion=false -enable-pack-metadata-stack-promotion=true | %IRGenFileCheck %s --check-prefixes CHECK-LLVM
3+
4+
public struct G<each T> {
5+
var pack: (repeat each T)
6+
}
7+
8+
public struct S<T> {
9+
let g: G<T>
10+
}
11+
12+
// CHECK-SIL-LABEL: sil @consumeS : {{.*}} {
13+
// CHECK-SIL: bb0([[INSTANCE:%[^,]+]] :
14+
// CHECK-SIL: alloc_pack_metadata
15+
// CHECK-SIL: [[METADATA:%[^,]+]] = alloc_pack_metadata
16+
// CHECK-SIL: destroy_addr [[INSTANCE]]
17+
// CHECK-SIL: dealloc_pack_metadata [[METADATA]]
18+
// CHECK-SIL-LABEL: } // end sil function 'consumeS'
19+
// CHECK-LLVM-LABEL: define{{.*}} swiftcc void @consumeS(
20+
// CHECK-LLVM-SAME: ptr noalias [[INSTANCE:%[^,]+]],
21+
// CHECK-LLVM-SAME: ptr [[T_METADATA:%[^)]+]]
22+
// CHECK-LLVM-SAME: ) {{.*}} {
23+
// CHECK-LLVM: [[G_METADATA_PACK:%[^,]+]] = alloca [1 x ptr]
24+
// CHECK-LLVM: call void @llvm.lifetime.start.p0(
25+
// CHECK-LLVM-SAME: ptr [[G_METADATA_PACK]])
26+
// CHECK-LLVM: [[G_METADATA_PACK_T_SLOT:%[^,]+]] = getelementptr inbounds [1 x ptr], ptr [[G_METADATA_PACK]]
27+
// CHECK-LLVM: store ptr [[T_METADATA]], ptr [[G_METADATA_PACK_T_SLOT]]
28+
// CHECK-LLVM: [[G_METADATA_RESPONSE:%[^,]+]] = call swiftcc %swift.metadata_response @"$s35pack_metadata_marker_inserter_onone1GVMa"(
29+
// CHECK-LLVM-SAME: ptr [[G_METADATA_PACK]])
30+
// CHECK-LLVM: [[G_METADATA:%[^,]+]] = extractvalue %swift.metadata_response [[G_METADATA_RESPONSE]]
31+
// CHECK-LLVM: [[S_METADATA_RESPONSE:%[^,]+]] = call swiftcc %swift.metadata_response @"$s35pack_metadata_marker_inserter_onone1SVMa"(
32+
// CHECK-LLVM-SAME: ptr [[T_METADATA]])
33+
// CHECK-LLVM: [[S_METADATA:%[^,]+]] = extractvalue %swift.metadata_response [[S_METADATA_RESPONSE]]
34+
// The metadata for G<T> is passed to the outlined destroy for S.
35+
// CHECK-LLVM: @"$s35pack_metadata_marker_inserter_onone1SVyxGlWOh"(ptr [[INSTANCE]], ptr [[T_METADATA]], ptr [[G_METADATA]], ptr [[S_METADATA]])
36+
// CHECK-LLVM: call void @llvm.lifetime.end.p0(
37+
// CHECK-LLVM-SAME: ptr [[G_METADATA_PACK]])
38+
// CHECK-LLVM: }
39+
@_silgen_name("consumeS")
40+
public func consumeS<T>(_: consuming S<T>) {}
41+
42+
public func callConsumeS<T>(_ s: consuming S<T>) {
43+
consumeS(s)
44+
}
45+
46+
@_silgen_name("consume2S")
47+
public func consume2S<T>(_: consuming S<T>, _: consuming S<T>) {}
48+
49+
// CHECK-SIL-LABEL: sil @callConsume2S : {{.*}} {
50+
// CHECK-SIL: bb0([[INSTANCE:%[^,]+]] :
51+
// CHECK-SIL: alloc_pack_metadata
52+
// CHECK-SIL: [[COPY2:%[^,]+]] = alloc_stack
53+
// CHECK-SIL: alloc_pack_metadata
54+
// CHECK-SIL: [[COPY1:%[^,]+]] = alloc_stack
55+
// CHECK-SIL: alloc_pack_metadata
56+
// CHECK-SIL: [[COPY_ADDR_1_METADATA:%[^,]+]] = alloc_pack_metadata
57+
// CHECK-SIL: copy_addr [[INSTANCE]] to [init] [[COPY1]]
58+
// CHECK-SIL: [[COPY_ADDR_2_METADATA:%[^,]+]] = alloc_pack_metadata
59+
// CHECK-SIL: copy_addr [[INSTANCE]] to [init] [[COPY2]]
60+
// CHECK-SIL: [[CONSUME_2_S:%[^,]+]] = function_ref @consume2S
61+
// CHECK-SIL: apply [[CONSUME_2_S]]<T>([[COPY1]], [[COPY2]])
62+
// CHECK-SIL: dealloc_pack_metadata [[COPY_ADDR_2_METADATA]]
63+
// CHECK-SIL: dealloc_pack_metadata [[COPY_ADDR_1_METADATA]]
64+
// CHECK-SIL-LABEL: } // end sil function 'callConsume2S'
65+
// CHECK-LLVM-LABEL: define{{.*}} swiftcc void @callConsume2S(
66+
// CHECK-LLVM-SAME: ptr noalias [[INSTANCE:%[^,]+]],
67+
// CHECK-LLVM-SAME: ptr [[T_METADATA:%[^)]+]]
68+
// CHECK-LLVM-SAME: ) {{.*}} {
69+
// CHECK-LLVM: [[G_METADATA_PACK:%[^,]+]] = alloca [1 x ptr]
70+
// CHECK-LLVM: [[S_METADATA_RESPONSE:%[^,]+]] = call swiftcc %swift.metadata_response @"$s35pack_metadata_marker_inserter_onone1SVMa"(
71+
// CHECK-LLVM-SAME: ptr [[T_METADATA]])
72+
// CHECK-LLVM: [[S_METADATA:%[^,]+]] = extractvalue %swift.metadata_response [[S_METADATA_RESPONSE]]
73+
// CHECK-LLVM: [[S_VWT_ADDR:%[^,]+]] = getelementptr inbounds ptr, ptr [[S_METADATA]], [[INT]] -1
74+
// CHECK-LLVM: [[S_VWT:%[^,]+]] = load ptr, ptr [[S_VWT_ADDR]]
75+
// CHECK-LLVM: [[S_SIZE_ADDR:%[^,]+]] = getelementptr inbounds %swift.vwtable, ptr [[S_VWT]]
76+
// CHECK-LLVM: [[S_SIZE:%[^,]+]] = load [[INT]], ptr [[S_SIZE_ADDR]]
77+
// CHECK-LLVM: [[COPY_1_ADDR:%[^,]+]] = alloca i8, [[INT]] [[S_SIZE]]
78+
// CHECK-LLVM: call void @llvm.lifetime.start.p0(
79+
// CHECK-LLVM-SAME: ptr [[COPY_1_ADDR]])
80+
// CHECK-LLVM: [[COPY_2_ADDR:%[^,]+]] = alloca i8, [[INT]] [[S_SIZE]]
81+
// CHECK-LLVM: call void @llvm.lifetime.start.p0(
82+
// CHECK-LLVM-SAME: ptr [[COPY_2_ADDR]])
83+
// CHECK-LLVM: call void @llvm.lifetime.start.p0(
84+
// CHECK-LLVM-SAME: ptr [[G_METADATA_PACK]])
85+
// CHECK-LLVM: [[G_METADATA_PACK_T_SLOT:%[^,]+]] = getelementptr inbounds [1 x ptr], ptr [[G_METADATA_PACK]]
86+
// CHECK-LLVM: store ptr [[T_METADATA]], ptr [[G_METADATA_PACK_T_SLOT]]
87+
// CHECK-LLVM: [[G_METADATA_RESPONSE:%[^,]+]] = call swiftcc %swift.metadata_response @"$s35pack_metadata_marker_inserter_onone1GVMa"(
88+
// CHECK-LLVM-SAME: ptr [[G_METADATA_PACK]])
89+
// CHECK-LLVM: [[G_METADATA:%[^,]+]] = extractvalue %swift.metadata_response [[G_METADATA_RESPONSE]], 0
90+
// CHECK-LLVM: call ptr @"$s35pack_metadata_marker_inserter_onone1SVyxGlWOc"(ptr [[INSTANCE]], ptr [[COPY_2_ADDR]], ptr [[T_METADATA]], ptr [[G_METADATA]], ptr [[S_METADATA]])
91+
// CHECK-LLVM: call ptr @"$s35pack_metadata_marker_inserter_onone1SVyxGlWOc"(ptr [[INSTANCE]], ptr [[COPY_1_ADDR]], ptr [[T_METADATA]], ptr [[G_METADATA]], ptr [[S_METADATA]])
92+
// CHECK-LLVM: call swiftcc void @consume2S(ptr noalias [[COPY_2_ADDR]], ptr noalias [[COPY_1_ADDR]], ptr [[T_METADATA]])
93+
// CHECK-LLVM: call void @llvm.lifetime.end.p0(
94+
// CHECK-LLVM-SAME: ptr [[G_METADATA_PACK]])
95+
// CHECK-LLVM: call void @llvm.lifetime.end.p0(
96+
// CHECK-LLVM-SAME: ptr [[COPY_2_ADDR]])
97+
// CHECK-LLVM: call void @llvm.lifetime.end.p0(
98+
// CHECK-LLVM-SAME: ptr [[COPY_1_ADDR]])
99+
// CHECK-LLVM-LABEL: }
100+
@_silgen_name("callConsume2S")
101+
public func callConsume2S<T>(_ s: S<T>) {
102+
consume2S(s, s)
103+
}

0 commit comments

Comments
 (0)