Skip to content

Commit c718e10

Browse files
committed
[IRGen] Always load extra tag bits as full bytes in CVW to avoid elemination of masking
rdar://129627898 LLVM expects integer types of fractional byte sizes to have been written as those types as well, so it expects all unused bytes to be 0. Since we are using the unused extra tag bits to store tags of outer enums, that assumption does not hold here. In regular witnesses, the outer enum would mask out those bytes before checking the tag of the inner enum. In CVW we can't do that, so we have to apply the mask ourselves. To guarantee the mask does not get optimized out, we have to use full bytes instead of fractionals.
1 parent 5682a1f commit c718e10

File tree

3 files changed

+57
-7
lines changed

3 files changed

+57
-7
lines changed

lib/IRGen/GenEnum.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1685,11 +1685,22 @@ namespace {
16851685
auto payload = EnumPayload::load(IGF, projectPayload(IGF, addr),
16861686
PayloadSchema);
16871687
if (ExtraTagBitCount > 0) {
1688-
extraTag = IGF.Builder.CreateLoad(projectExtraTagBits(IGF, addr));
16891688
if (maskExtraTagBits) {
1690-
auto maskBits = llvm::NextPowerOf2(NumExtraTagValues) - 1;
1689+
auto projectedBits = projectExtraTagBits(IGF, addr);
1690+
// LLVM assumes that loads of fractional byte sizes have been stored
1691+
// with the same type, so all unused bits would be 0. Since we are
1692+
// re-using spare bits for tag storage, that assumption is wrong here.
1693+
// In CVW we have to mask the extra bits, which requires us to make
1694+
// this cast here, otherwise LLVM would optimize away the bit mask.
1695+
if (projectedBits.getElementType()->getIntegerBitWidth() < 8) {
1696+
projectedBits = IGF.Builder.CreateElementBitCast(addr, IGM.Int8Ty);
1697+
}
1698+
extraTag = IGF.Builder.CreateLoad(projectedBits);
1699+
auto maskBits = llvm::PowerOf2Ceil(NumExtraTagValues) - 1;
16911700
auto mask = llvm::ConstantInt::get(extraTag->getType(), maskBits);
16921701
extraTag = IGF.Builder.CreateAnd(extraTag, mask);
1702+
} else {
1703+
extraTag = IGF.Builder.CreateLoad(projectExtraTagBits(IGF, addr));
16931704
}
16941705
}
16951706
return {std::move(payload), extraTag};

test/Interpreter/Inputs/layout_string_witnesses_types.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,16 @@ public enum MultiPayloadError {
619619
case error2(Int, Error)
620620
}
621621

622+
public enum TwoPayloadInner {
623+
case x(AnyObject)
624+
case y(Int)
625+
}
626+
627+
public enum TwoPayloadOuter {
628+
case x(Int)
629+
case y(TwoPayloadInner)
630+
}
631+
622632
@inline(never)
623633
public func consume<T>(_ x: T.Type) {
624634
withExtendedLifetime(x) {}

test/Interpreter/layout_string_witnesses_static.swift

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
// RUN: %empty-directory(%t)
2-
// RUN: %target-swift-frontend -I %S/Inputs/CTypes -enable-experimental-feature LayoutStringValueWitnesses -enable-layout-string-value-witnesses -parse-stdlib -emit-module -emit-module-path=%t/layout_string_witnesses_types.swiftmodule %S/Inputs/layout_string_witnesses_types.swift
2+
// RUN: %target-swift-frontend -O -I %S/Inputs/CTypes -enable-experimental-feature LayoutStringValueWitnesses -enable-layout-string-value-witnesses -parse-stdlib -emit-module -emit-module-path=%t/layout_string_witnesses_types.swiftmodule %S/Inputs/layout_string_witnesses_types.swift
33

44
// NOTE: We have to build this as dylib to turn private external symbols into local symbols, so we can observe potential issues with linkage
5-
// RUN: %target-build-swift-dylib(%t/%target-library-name(layout_string_witnesses_types)) -I %S/Inputs/CTypes -Xfrontend -enable-experimental-feature -Xfrontend LayoutStringValueWitnesses -Xfrontend -enable-layout-string-value-witnesses -Xfrontend -parse-stdlib -parse-as-library %S/Inputs/layout_string_witnesses_types.swift
5+
// RUN: %target-build-swift-dylib(%t/%target-library-name(layout_string_witnesses_types)) -O -I %S/Inputs/CTypes -Xfrontend -enable-experimental-feature -Xfrontend LayoutStringValueWitnesses -Xfrontend -enable-layout-string-value-witnesses -Xfrontend -parse-stdlib -parse-as-library %S/Inputs/layout_string_witnesses_types.swift
66
// RUN: %target-codesign %t/%target-library-name(layout_string_witnesses_types)
7-
// RUN: %target-swift-frontend -enable-experimental-feature LayoutStringValueWitnesses -enable-layout-string-value-witnesses -enable-library-evolution -emit-module -emit-module-path=%t/layout_string_witnesses_types_resilient.swiftmodule %S/Inputs/layout_string_witnesses_types_resilient.swift
8-
// RUN: %target-build-swift -g -Xfrontend -enable-experimental-feature -Xfrontend LayoutStringValueWitnesses -Xfrontend -enable-layout-string-value-witnesses -Xfrontend -enable-library-evolution -c -parse-as-library -o %t/layout_string_witnesses_types_resilient.o %S/Inputs/layout_string_witnesses_types_resilient.swift
9-
// RUN: %target-build-swift -g -Xfrontend -enable-experimental-feature -Xfrontend LayoutStringValueWitnesses -Xfrontend -enable-layout-string-value-witnesses -Xfrontend -enable-type-layout -Xfrontend -parse-stdlib -module-name layout_string_witnesses_static -llayout_string_witnesses_types -L%t %t/layout_string_witnesses_types_resilient.o -I %t -o %t/main %s %target-rpath(%t)
7+
// RUN: %target-swift-frontend -O -enable-experimental-feature LayoutStringValueWitnesses -enable-layout-string-value-witnesses -enable-library-evolution -emit-module -emit-module-path=%t/layout_string_witnesses_types_resilient.swiftmodule %S/Inputs/layout_string_witnesses_types_resilient.swift
8+
// RUN: %target-build-swift -O -g -Xfrontend -enable-experimental-feature -Xfrontend LayoutStringValueWitnesses -Xfrontend -enable-layout-string-value-witnesses -Xfrontend -enable-library-evolution -c -parse-as-library -o %t/layout_string_witnesses_types_resilient.o %S/Inputs/layout_string_witnesses_types_resilient.swift
9+
// RUN: %target-build-swift -O -g -Xfrontend -enable-experimental-feature -Xfrontend LayoutStringValueWitnesses -Xfrontend -enable-layout-string-value-witnesses -Xfrontend -enable-type-layout -Xfrontend -parse-stdlib -module-name layout_string_witnesses_static -llayout_string_witnesses_types -L%t %t/layout_string_witnesses_types_resilient.o -I %t -o %t/main %s %target-rpath(%t)
1010
// RUN: %target-codesign %t/main
1111
// RUN: %target-run %t/main %t/%target-library-name(layout_string_witnesses_types) | %FileCheck %s --check-prefix=CHECK -check-prefix=CHECK-%target-os
1212

@@ -1290,6 +1290,35 @@ func testCTypeUnderAligned() {
12901290

12911291
testCTypeUnderAligned()
12921292

1293+
func testNestedTwoPayload() {
1294+
let ptr = UnsafeMutablePointer<TwoPayloadOuter>.allocate(capacity: 1)
1295+
1296+
do {
1297+
let x = TwoPayloadOuter.y(TwoPayloadInner.x(SimpleClass(x: 23)))
1298+
testInit(ptr, to: x)
1299+
}
1300+
1301+
do {
1302+
let y = TwoPayloadOuter.y(TwoPayloadInner.x(SimpleClass(x: 1)))
1303+
1304+
// CHECK: Before deinit
1305+
print("Before deinit")
1306+
1307+
// CHECK-NEXT: SimpleClass deinitialized!
1308+
testAssign(ptr, from: y)
1309+
}
1310+
1311+
// CHECK-NEXT: Before deinit
1312+
print("Before deinit")
1313+
1314+
// CHECK-NEXT: SimpleClass deinitialized!
1315+
testDestroy(ptr)
1316+
1317+
ptr.deallocate()
1318+
}
1319+
1320+
testNestedTwoPayload()
1321+
12931322
#if os(macOS)
12941323
func testObjc() {
12951324
let ptr = UnsafeMutablePointer<ObjcWrapper>.allocate(capacity: 1)

0 commit comments

Comments
 (0)