Skip to content

Commit 11b8bcf

Browse files
committed
IRGen: Actually construct resilient enums using the new destructiveInjectEnumTag() value witness
This completes the ResilientEnumImplStrategy implementation in IRGen.
1 parent b0c76c6 commit 11b8bcf

File tree

4 files changed

+83
-11
lines changed

4 files changed

+83
-11
lines changed

lib/IRGen/GenEnum.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4281,7 +4281,9 @@ namespace {
42814281
SILType T,
42824282
Address enumAddr,
42834283
EnumElementDecl *Case) const override {
4284-
llvm_unreachable("resilient enums cannot be constructed directly");
4284+
emitDestructiveInjectEnumTagCall(IGF, T,
4285+
getTagIndex(Case),
4286+
enumAddr.getAddress());
42854287
}
42864288

42874289
llvm::Value *

lib/IRGen/GenOpaque.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,23 @@ void irgen::emitDestructiveProjectEnumDataCall(IRGenFunction &IGF,
694694
setHelperAttributes(call);
695695
}
696696

697+
/// Emit a call to the 'destructiveInjectEnumTag' operation.
698+
/// The type must be dynamically known to have enum witnesses.
699+
void irgen::emitDestructiveInjectEnumTagCall(IRGenFunction &IGF,
700+
SILType T,
701+
unsigned tag,
702+
llvm::Value *srcObject) {
703+
auto metadata = IGF.emitTypeMetadataRefForLayout(T);
704+
llvm::Value *fn = IGF.emitValueWitnessForLayout(T,
705+
ValueWitness::DestructiveInjectEnumTag);
706+
llvm::Value *tagValue =
707+
llvm::ConstantInt::get(IGF.IGM.Int32Ty, tag);
708+
llvm::CallInst *call =
709+
IGF.Builder.CreateCall(fn, {srcObject, tagValue, metadata});
710+
call->setCallingConv(IGF.IGM.RuntimeCC);
711+
setHelperAttributes(call);
712+
}
713+
697714
/// Load the 'size' value witness from the given table as a size_t.
698715
llvm::Value *irgen::emitLoadOfSize(IRGenFunction &IGF, SILType T) {
699716
return IGF.emitValueWitnessForLayout(T, ValueWitness::Size);

lib/IRGen/GenOpaque.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,13 @@ namespace irgen {
177177
SILType T,
178178
llvm::Value *srcObject);
179179

180+
/// Emit a call to the 'destructiveInjectEnumTag' operation.
181+
/// The type must be dynamically known to have enum witnesses.
182+
void emitDestructiveInjectEnumTagCall(IRGenFunction &IGF,
183+
SILType T,
184+
unsigned tag,
185+
llvm::Value *srcObject);
186+
180187
/// Emit a load of the 'size' value witness.
181188
llvm::Value *emitLoadOfSize(IRGenFunction &IGF, SILType T);
182189

test/IRGen/enum_resilience.swift

Lines changed: 56 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// RUN: %target-swift-frontend -I %S/../Inputs -enable-source-import -emit-ir -enable-resilience -O %s
33

44
import resilient_enum
5+
import resilient_struct
56

67
// CHECK: %C15enum_resilience5Class = type <{ %swift.refcounted }>
78
// CHECK: %V15enum_resilience9Reference = type <{ %C15enum_resilience5Class* }>
@@ -59,11 +60,11 @@ enum InternalEither {
5960
// CHECK-LABEL: define void @_TF15enum_resilience25functionWithResilientEnumFO14resilient_enum6MediumS1_(%swift.opaque* noalias nocapture sret, %swift.opaque* noalias nocapture)
6061
public func functionWithResilientEnum(m: Medium) -> Medium {
6162

62-
// CHECK: [[METADATA:%.*]] = call %swift.type* @_TMaO14resilient_enum6Medium()
63-
// CHECK-NEXT: [[METADATA_ADDR:%.*]] = bitcast %swift.type* %2 to i8***
64-
// CHECK-NEXT: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** %3, [[INT:i32|i64]] -1
63+
// CHECK: [[METADATA:%.*]] = call %swift.type* @_TMaO14resilient_enum6Medium()
64+
// CHECK-NEXT: [[METADATA_ADDR:%.*]] = bitcast %swift.type* [[METADATA]] to i8***
65+
// CHECK-NEXT: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[METADATA_ADDR]], [[INT:i32|i64]] -1
6566
// CHECK-NEXT: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
66-
// CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** %.valueWitnesses, i32 9
67+
// CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 9
6768
// CHECK-NEXT: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]]
6869
// CHECK-NEXT: [[WITNESS_FN:%.*]] = bitcast i8* [[WITNESS]]
6970
// CHECK-NEXT: call %swift.opaque* [[WITNESS_FN]](%swift.opaque* %0, %swift.opaque* %1, %swift.type* [[METADATA]])
@@ -73,15 +74,13 @@ public func functionWithResilientEnum(m: Medium) -> Medium {
7374
}
7475

7576
// CHECK-LABEL: define void @_TF15enum_resilience33functionWithIndirectResilientEnumFO14resilient_enum16IndirectApproachS1_(%swift.opaque* noalias nocapture sret, %swift.opaque* noalias nocapture)
76-
77-
7877
public func functionWithIndirectResilientEnum(ia: IndirectApproach) -> IndirectApproach {
7978

80-
// CHECK: [[METADATA:%.*]] = call %swift.type* @_TMaO14resilient_enum16IndirectApproach()
81-
// CHECK-NEXT: [[METADATA_ADDR:%.*]] = bitcast %swift.type* %2 to i8***
82-
// CHECK-NEXT: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** %3, [[INT:i32|i64]] -1
79+
// CHECK: [[METADATA:%.*]] = call %swift.type* @_TMaO14resilient_enum16IndirectApproach()
80+
// CHECK-NEXT: [[METADATA_ADDR:%.*]] = bitcast %swift.type* [[METADATA]] to i8***
81+
// CHECK-NEXT: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[METADATA_ADDR]], [[INT:i32|i64]] -1
8382
// CHECK-NEXT: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
84-
// CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** %.valueWitnesses, i32 9
83+
// CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 9
8584
// CHECK-NEXT: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]]
8685
// CHECK-NEXT: [[WITNESS_FN:%.*]] = bitcast i8* [[WITNESS]]
8786
// CHECK-NEXT: call %swift.opaque* [[WITNESS_FN]](%swift.opaque* %0, %swift.opaque* %1, %swift.type* [[METADATA]])
@@ -90,6 +89,53 @@ public func functionWithIndirectResilientEnum(ia: IndirectApproach) -> IndirectA
9089
return ia
9190
}
9291

92+
// CHECK-LABEL: define void @_TF15enum_resilience31constructResilientEnumNoPayloadFT_O14resilient_enum6Medium
93+
public func constructResilientEnumNoPayload() -> Medium {
94+
// CHECK: [[METADATA:%.*]] = call %swift.type* @_TMaO14resilient_enum6Medium()
95+
// CHECK-NEXT: [[METADATA_ADDR:%.*]] = bitcast %swift.type* [[METADATA]] to i8***
96+
// CHECK-NEXT: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[METADATA_ADDR]], [[INT:i32|i64]] -1
97+
// CHECK-NEXT: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
98+
99+
// CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 25
100+
// CHECK-NEXT: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]]
101+
// CHECK-NEXT: [[WITNESS_FN:%.*]] = bitcast i8* [[WITNESS]]
102+
// CHECK-NEXT: call void [[WITNESS_FN]](%swift.opaque* %0, i32 2, %swift.type* [[METADATA]])
103+
104+
// CHECK-NEXT: ret void
105+
return Medium.Paper
106+
}
107+
108+
// CHECK-LABEL: define void @_TF15enum_resilience29constructResilientEnumPayloadFV16resilient_struct4SizeO14resilient_enum6Medium
109+
public func constructResilientEnumPayload(s: Size) -> Medium {
110+
// CHECK: [[METADATA:%.*]] = call %swift.type* @_TMaV16resilient_struct4Size()
111+
// CHECK-NEXT: [[METADATA_ADDR:%.*]] = bitcast %swift.type* [[METADATA]] to i8***
112+
// CHECK-NEXT: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[METADATA_ADDR]], [[INT:i32|i64]] -1
113+
// CHECK-NEXT: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
114+
115+
// CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 6
116+
// CHECK-NEXT: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]]
117+
// CHECK-NEXT: [[WITNESS_FN:%.*]] = bitcast i8* [[WITNESS]]
118+
// CHECK-NEXT: [[COPY:%.*]] = call %swift.opaque* %initializeWithCopy(%swift.opaque* %0, %swift.opaque* %1, %swift.type* [[METADATA]])
119+
120+
// CHECK-NEXT: [[METADATA2:%.*]] = call %swift.type* @_TMaO14resilient_enum6Medium()
121+
// CHECK-NEXT: [[METADATA_ADDR2:%.*]] = bitcast %swift.type* [[METADATA2]] to i8***
122+
// CHECK-NEXT: [[VWT_ADDR2:%.*]] = getelementptr inbounds i8**, i8*** [[METADATA_ADDR2]], [[INT:i32|i64]] -1
123+
// CHECK-NEXT: [[VWT2:%.*]] = load i8**, i8*** [[VWT_ADDR2]]
124+
125+
// CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT2]], i32 25
126+
// CHECK-NEXT: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]]
127+
// CHECK-NEXT: [[WITNESS_FN:%.*]] = bitcast i8* [[WITNESS]]
128+
// CHECK-NEXT: call void [[WITNESS_FN]](%swift.opaque* %0, i32 1, %swift.type* [[METADATA2]])
129+
130+
// CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 4
131+
// CHECK-NEXT: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]]
132+
// CHECK-NEXT: [[WITNESS_FN:%.*]] = bitcast i8* [[WITNESS]]
133+
// CHECK-NEXT: call void [[WITNESS_FN]](%swift.opaque* %1, %swift.type* [[METADATA]]) #2
134+
135+
// CHECK-NEXT: ret void
136+
return Medium.Postcard(s)
137+
}
138+
93139
// CHECK-LABEL: define {{i32|i64}} @_TF15enum_resilience18indirectSwitchTestFO14resilient_enum6MediumSi(%swift.opaque* noalias nocapture)
94140
// CHECK: [[BUFFER:%.*]] = alloca [[BUFFER_TYPE:\[(12|24) x i8\]]]
95141

0 commit comments

Comments
 (0)