Skip to content

Commit 747cbfc

Browse files
authored
[IRGen] Mask extra tag bits in getEnumTag function for CVW (swiftlang#71421)
rdar://121868127 In compact value witnesses we need to mask the extra tag bits in case they are used to store tag bits of outer enums, so we only read the ones we are interested in.
1 parent 802aab8 commit 747cbfc

File tree

5 files changed

+77
-31
lines changed

5 files changed

+77
-31
lines changed

lib/IRGen/GenEnum.cpp

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -300,9 +300,10 @@ EnumImplStrategy::emitResilientTagIndices(IRGenModule &IGM) const {
300300

301301
llvm::Value *
302302
EnumImplStrategy::emitFixedGetEnumTag(IRGenFunction &IGF, SILType T,
303-
Address enumAddr) const {
303+
Address enumAddr,
304+
bool maskExtraTagBits) const {
304305
assert(TIK >= Fixed);
305-
return emitGetEnumTag(IGF, T, enumAddr);
306+
return emitGetEnumTag(IGF, T, enumAddr, maskExtraTagBits);
306307
}
307308

308309
llvm::Value *
@@ -418,9 +419,8 @@ namespace {
418419
T, getTypeInfo());
419420
}
420421

421-
llvm::Value *
422-
emitGetEnumTag(IRGenFunction &IGF, SILType T, Address enumAddr)
423-
const override {
422+
llvm::Value *emitGetEnumTag(IRGenFunction &IGF, SILType T, Address enumAddr,
423+
bool maskExtraTagBits) const override {
424424
return llvm::ConstantInt::get(IGF.IGM.Int32Ty, 0);
425425
}
426426

@@ -943,9 +943,8 @@ namespace {
943943
return Size((getDiscriminatorType()->getBitWidth() + 7) / 8);
944944
}
945945

946-
llvm::Value *
947-
emitGetEnumTag(IRGenFunction &IGF, SILType T, Address enumAddr)
948-
const override {
946+
llvm::Value *emitGetEnumTag(IRGenFunction &IGF, SILType T, Address enumAddr,
947+
bool maskExtraTagBits) const override {
949948
Explosion value;
950949
loadAsTake(IGF, enumAddr, value);
951950

@@ -1654,16 +1653,23 @@ namespace {
16541653
return {payload, extraTag};
16551654
}
16561655

1657-
std::pair<EnumPayload, llvm::Value*>
1658-
emitPrimitiveLoadPayloadAndExtraTag(IRGenFunction &IGF, Address addr) const{
1656+
std::pair<EnumPayload, llvm::Value *>
1657+
emitPrimitiveLoadPayloadAndExtraTag(IRGenFunction &IGF, Address addr,
1658+
bool maskExtraTagBits = false) const {
16591659
llvm::Value *extraTag = nullptr;
16601660
auto payload = EnumPayload::load(IGF, projectPayload(IGF, addr),
16611661
PayloadSchema);
1662-
if (ExtraTagBitCount > 0)
1662+
if (ExtraTagBitCount > 0) {
16631663
extraTag = IGF.Builder.CreateLoad(projectExtraTagBits(IGF, addr));
1664+
if (maskExtraTagBits) {
1665+
auto maskBits = llvm::NextPowerOf2(NumExtraTagValues) - 1;
1666+
auto mask = llvm::ConstantInt::get(extraTag->getType(), maskBits);
1667+
extraTag = IGF.Builder.CreateAnd(extraTag, mask);
1668+
}
1669+
}
16641670
return {std::move(payload), extraTag};
16651671
}
1666-
1672+
16671673
void packIntoEnumPayload(IRGenModule &IGM,
16681674
IRBuilder &builder,
16691675
EnumPayload &outerPayload,
@@ -1968,8 +1974,8 @@ namespace {
19681974

19691975
/// Emit a call into the runtime to get the current enum payload tag.
19701976
/// This returns a tag index in the range [0..NumElements-1].
1971-
llvm::Value *emitGetEnumTag(IRGenFunction &IGF, SILType T,
1972-
Address enumAddr) const override {
1977+
llvm::Value *emitGetEnumTag(IRGenFunction &IGF, SILType T, Address enumAddr,
1978+
bool maskExtraTagBits = false) const override {
19731979
auto numEmptyCases =
19741980
llvm::ConstantInt::get(IGF.IGM.Int32Ty, ElementsWithNoPayload.size());
19751981

@@ -1983,9 +1989,9 @@ namespace {
19831989
opaqueAddr);
19841990
}
19851991

1986-
19871992
llvm::Value *emitFixedGetEnumTag(IRGenFunction &IGF, SILType T,
1988-
Address enumAddr) const override {
1993+
Address enumAddr,
1994+
bool maskExtraTagBits) const override {
19891995
assert(TIK >= Fixed);
19901996
auto numEmptyCases =
19911997
llvm::ConstantInt::get(IGF.IGM.Int32Ty, ElementsWithNoPayload.size());
@@ -4067,9 +4073,8 @@ namespace {
40674073
public:
40684074

40694075
/// Returns a tag index in the range [0..NumElements-1].
4070-
llvm::Value *
4071-
emitGetEnumTag(IRGenFunction &IGF, SILType T, Address addr)
4072-
const override {
4076+
llvm::Value *emitGetEnumTag(IRGenFunction &IGF, SILType T, Address addr,
4077+
bool maskExtraTagBits) const override {
40734078
unsigned numPayloadCases = ElementsWithPayload.size();
40744079
llvm::Constant *payloadCases =
40754080
llvm::ConstantInt::get(IGM.Int32Ty, numPayloadCases);
@@ -4087,8 +4092,8 @@ namespace {
40874092

40884093
// Load the fixed-size representation and derive the tags.
40894094
EnumPayload payload; llvm::Value *extraTagBits;
4090-
std::tie(payload, extraTagBits)
4091-
= emitPrimitiveLoadPayloadAndExtraTag(IGF, addr);
4095+
std::tie(payload, extraTagBits) =
4096+
emitPrimitiveLoadPayloadAndExtraTag(IGF, addr, maskExtraTagBits);
40924097

40934098
// Load the payload tag.
40944099
llvm::Value *tagValue = extractPayloadTag(IGF, payload, extraTagBits);
@@ -6150,9 +6155,8 @@ namespace {
61506155

61516156
/// \group Operations for emitting type metadata
61526157

6153-
llvm::Value *
6154-
emitGetEnumTag(IRGenFunction &IGF, SILType T, Address addr)
6155-
const override {
6158+
llvm::Value *emitGetEnumTag(IRGenFunction &IGF, SILType T, Address addr,
6159+
bool maskExtraTagBits) const override {
61566160
llvm_unreachable("resilient enums cannot be defined");
61576161
}
61586162

lib/IRGen/GenEnum.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -259,17 +259,17 @@ class EnumImplStrategy {
259259

260260
/// Return the enum case tag for the given value. Payload cases come first,
261261
/// followed by non-payload cases. Used for the getEnumTag value witness.
262-
virtual llvm::Value *emitGetEnumTag(IRGenFunction &IGF,
263-
SILType T,
264-
Address enumAddr) const = 0;
262+
virtual llvm::Value *emitGetEnumTag(IRGenFunction &IGF, SILType T,
263+
Address enumAddr,
264+
bool maskExtraTagBits = false) const = 0;
265265

266266
/// Return the enum case tag for the given value. Payload cases come first,
267267
/// followed by non-payload cases. Used for the getEnumTag value witness.
268268
///
269269
/// Only ever called for fixed types.
270-
virtual llvm::Value *emitFixedGetEnumTag(IRGenFunction &IGF,
271-
SILType T,
272-
Address enumAddr) const;
270+
virtual llvm::Value *emitFixedGetEnumTag(IRGenFunction &IGF, SILType T,
271+
Address enumAddr,
272+
bool maskExtraTagBits = false) const;
273273
llvm::Value *emitOutlinedGetEnumTag(IRGenFunction &IGF, SILType T,
274274
Address enumAddr) const;
275275

lib/IRGen/TypeLayout.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,8 @@ llvm::Function *createFixedEnumLoadTag(IRGenModule &IGM,
517517
auto enumAddr = typeInfo->getAddressForPointer(castEnumPtr);
518518

519519
auto &strategy = getEnumImplStrategy(IGM, entry.ty);
520-
auto tag = strategy.emitFixedGetEnumTag(IGF, entry.ty, enumAddr);
520+
auto tag = strategy.emitFixedGetEnumTag(IGF, entry.ty, enumAddr,
521+
/*maskExtraTagBits*/ true);
521522
IGF.Builder.CreateRet(tag);
522523
});
523524

test/Interpreter/Inputs/layout_string_witnesses_types.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,18 @@ public struct TupleLargeAlignment<T> {
576576
}
577577
}
578578

579+
public enum NestedMultiPayloadInner {
580+
case a(UInt)
581+
case b(AnyObject)
582+
case c(AnyObject)
583+
}
584+
585+
public enum NestedMultiPayloadOuter {
586+
case a(NestedMultiPayloadInner)
587+
case b(NestedMultiPayloadInner)
588+
case c(NestedMultiPayloadInner)
589+
}
590+
579591
@inline(never)
580592
public func consume<T>(_ x: T.Type) {
581593
withExtendedLifetime(x) {}

test/Interpreter/layout_string_witnesses_static.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,6 +1103,35 @@ func testNotBitwiseTakableBridge() {
11031103

11041104
testNotBitwiseTakableBridge()
11051105

1106+
// Regression test for rdar://121868127
1107+
func testMultiPayloadEnumNested() {
1108+
let ptr = UnsafeMutablePointer<NestedMultiPayloadOuter>.allocate(capacity: 1)
1109+
1110+
do {
1111+
testInit(ptr, to: .b(.b(SimpleClass(x: 23))))
1112+
}
1113+
1114+
do {
1115+
let y = NestedMultiPayloadOuter.b(.b(SimpleClass(x: 23)))
1116+
1117+
// CHECK: Before deinit
1118+
print("Before deinit")
1119+
1120+
// CHECK-NEXT: SimpleClass deinitialized!
1121+
testAssign(ptr, from: y)
1122+
}
1123+
1124+
// CHECK-NEXT: Before deinit
1125+
print("Before deinit")
1126+
1127+
// CHECK-NEXT: SimpleClass deinitialized!
1128+
testDestroy(ptr)
1129+
1130+
ptr.deallocate()
1131+
}
1132+
1133+
testMultiPayloadEnumNested()
1134+
11061135
#if os(macOS)
11071136
func testObjc() {
11081137
let ptr = UnsafeMutablePointer<ObjcWrapper>.allocate(capacity: 1)

0 commit comments

Comments
 (0)