Skip to content

Commit 702f86c

Browse files
authored
Merge pull request swiftlang#75429 from tbkka/tbkka-mpe-improvements-2024-07-23
More MPE improvements
2 parents 608f5fc + 3ffc3e8 commit 702f86c

File tree

6 files changed

+344
-9
lines changed

6 files changed

+344
-9
lines changed

stdlib/public/RemoteInspection/TypeLowering.cpp

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -327,9 +327,7 @@ BitMask BuiltinTypeInfo::getSpareBits(TypeConverter &TC, bool &hasAddrOnly) cons
327327
auto mask = BitMask::oneMask(getSize());
328328
mask.keepOnlyMostSignificantBits(getSize() * 8 - intSize);
329329
return mask;
330-
} else if (
331-
Name == "ypXp" || // Any.Type
332-
Name == "yyXf" // 'yyXf' = @thin () -> Void function
330+
} else if (Name == "ypXp" // Any.Type
333331
) {
334332
// Builtin types that expose pointer spare bits
335333
auto mpePointerSpareBits = TC.getBuilder().getMultiPayloadEnumPointerMask();
@@ -413,28 +411,42 @@ bool RecordTypeInfo::readExtraInhabitantIndex(remote::MemoryReader &reader,
413411
}
414412

415413
BitMask RecordTypeInfo::getSpareBits(TypeConverter &TC, bool &hasAddrOnly) const {
414+
// Start with all spare bits; we'll mask them out as we go...
416415
auto mask = BitMask::oneMask(getSize());
417416
switch (SubKind) {
418417
case RecordKind::Invalid:
419-
return mask; // FIXME: Should invalid have all spare bits? Or none? Does it matter?
418+
// FIXME: Should invalid have all spare bits? Or none? Does it matter?
419+
return mask;
420420
case RecordKind::Tuple:
421421
case RecordKind::Struct:
422+
// Regular aggregates inherit spare bits from their fields
422423
break;
423424
case RecordKind::ThickFunction:
424-
break;
425+
// Thick functions have two fields:
426+
// * Code pointer that might be signed and/or misaligned
427+
// * Context that could be a tagged pointer
428+
mask.makeZero(); // No spare bits
429+
return mask;
425430
case RecordKind::OpaqueExistential: {
426431
// Existential storage isn't recorded as a field,
427432
// so we handle it specially here...
428433
int pointerSize = TC.targetPointerSize();
429434
BitMask submask = BitMask::zeroMask(pointerSize * 3);
430435
mask.andMask(submask, 0);
431436
hasAddrOnly = true;
437+
// Mask the rest of the fields as usual...
432438
break;
433439
}
434440
case RecordKind::ClassExistential:
435-
break;
436-
case RecordKind::ExistentialMetatype:
437-
break; // Field 0 is metadata pointer, a Builtin of type 'yyXf'
441+
// Class existential is a data pointer that does expose spare bits
442+
// ... so we can fall through ...
443+
case RecordKind::ExistentialMetatype: {
444+
// Initial metadata pointer has spare bits
445+
auto mpePointerSpareBits = TC.getBuilder().getMultiPayloadEnumPointerMask();
446+
mask.andMask(mpePointerSpareBits, 0);
447+
mask.keepOnlyLeastSignificantBytes(TC.targetPointerSize());
448+
return mask;
449+
}
438450
case RecordKind::ErrorExistential:
439451
break;
440452
case RecordKind::ClassInstance:
@@ -1071,7 +1083,20 @@ class MultiPayloadEnumTypeInfo: public EnumTypeInfo {
10711083
BitMask getMultiPayloadTagBitsMask() const {
10721084
auto payloadTagValues = NumEffectivePayloadCases - 1;
10731085
if (getNumCases() > NumEffectivePayloadCases) {
1074-
payloadTagValues += 1;
1086+
// How many payload bits are there?
1087+
auto payloadBits = spareBitsMask;
1088+
payloadBits.complement(); // Non-spare bits are payload bits
1089+
auto numPayloadBits = payloadBits.countSetBits();
1090+
1091+
if (numPayloadBits >= 32) {
1092+
// Lots of payload bits!! We only need one extra tag value
1093+
payloadTagValues += 1;
1094+
} else {
1095+
// We may need multiple tag values to cover all the non-payload cases
1096+
auto numNonPayloadCasesPerTag = 1ULL << numPayloadBits;
1097+
auto numNonPayloadCases = getNumCases() - NumEffectivePayloadCases;
1098+
payloadTagValues += (numNonPayloadCases + numNonPayloadCasesPerTag - 1) / numNonPayloadCasesPerTag;
1099+
}
10751100
}
10761101
int payloadTagBits = 0;
10771102
while (payloadTagValues > 0) {
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift -lswiftSwiftReflectionTest %s -o %t/reflect_Enum_values10
3+
// RUN: %target-codesign %t/reflect_Enum_values10
4+
5+
// RUN: %target-run %target-swift-reflection-test %t/reflect_Enum_values10 | tee /dev/stderr | %FileCheck %s --check-prefix=CHECK%target-ptrsize --check-prefix=CHECKALL --dump-input=fail %add_num_extra_inhabitants
6+
7+
// REQUIRES: objc_interop
8+
// REQUIRES: executable_test
9+
// UNSUPPORTED: use_os_stdlib
10+
11+
import SwiftReflectionTest
12+
13+
protocol P : AnyObject {
14+
}
15+
16+
class C : P {
17+
var a: Int
18+
var b: Int
19+
init() { a = 0; b = 0; }
20+
}
21+
22+
// MemoryLayout<B>.size == 8
23+
enum B {
24+
case a(C)
25+
case b(C)
26+
}
27+
28+
reflect(enumValue: B.a(C()))
29+
30+
// CHECKALL: Reflecting an enum value.
31+
// CHECKALL-NEXT: Type reference:
32+
// CHECKALL-NEXT: (enum reflect_Enum_values10.B)
33+
// CHECKALL-NEXT: Value: .a(_)
34+
35+
reflect(enumValue: B.b(C()))
36+
37+
// CHECKALL: Reflecting an enum value.
38+
// CHECKALL-NEXT: Type reference:
39+
// CHECKALL-NEXT: (enum reflect_Enum_values10.B)
40+
// CHECKALL-NEXT: Value: .b(_)
41+
42+
// MemoryLayout<Q>.size == 16
43+
// MemoryLayout<P>.size == 16
44+
enum Q {
45+
case a(P)
46+
case b(P)
47+
}
48+
49+
reflect(enumValue: Q.a(C()))
50+
51+
// CHECKALL: Reflecting an enum value.
52+
// CHECKALL-NEXT: Type reference:
53+
// CHECKALL-NEXT: (enum reflect_Enum_values10.Q)
54+
// CHECKALL-NEXT: Value: .a(_)
55+
56+
reflect(enumValue: Q.b(C()))
57+
58+
// CHECKALL: Reflecting an enum value.
59+
// CHECKALL-NEXT: Type reference:
60+
// CHECKALL-NEXT: (enum reflect_Enum_values10.Q)
61+
// CHECKALL-NEXT: Value: .b(_)
62+
63+
doneReflecting()
64+
65+
// CHECKALL: Done.
66+
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift -lswiftSwiftReflectionTest %s -o %t/reflect_Enum_values11
3+
// RUN: %target-codesign %t/reflect_Enum_values11
4+
5+
// RUN: %target-run %target-swift-reflection-test %t/reflect_Enum_values11 | tee /dev/stderr | %FileCheck %s --check-prefix=CHECK%target-ptrsize --check-prefix=CHECKALL --dump-input=fail %add_num_extra_inhabitants
6+
7+
// REQUIRES: objc_interop
8+
// REQUIRES: executable_test
9+
// UNSUPPORTED: use_os_stdlib
10+
11+
import SwiftReflectionTest
12+
13+
public enum A1 {
14+
case item1
15+
}
16+
public enum A2 {
17+
case item1
18+
}
19+
public enum A3 {
20+
case item1
21+
}
22+
public enum A4 {
23+
case item1
24+
}
25+
public enum A5 {
26+
case item1
27+
}
28+
public enum A6 {
29+
case item1
30+
case item2
31+
}
32+
public enum A7 {
33+
case item1
34+
case item2
35+
}
36+
37+
// MemoryLayout<Request>.size = 1
38+
public enum Request {
39+
case a1(A1)
40+
case a2(A2)
41+
case a3(A3)
42+
case a4(A4)
43+
case a5(A5)
44+
case a6(A6)
45+
case a7(A7)
46+
}
47+
48+
reflect(enumValue: Request.a1(.item1))
49+
50+
// CHECKALL: Reflecting an enum value.
51+
// CHECKALL-NEXT: Type reference:
52+
// CHECKALL-NEXT: (enum reflect_Enum_values11.Request)
53+
// CHECKALL-NEXT: Value: .a1(.item1)
54+
55+
reflect(enumValue: Request.a2(.item1))
56+
57+
// CHECKALL: Reflecting an enum value.
58+
// CHECKALL-NEXT: Type reference:
59+
// CHECKALL-NEXT: (enum reflect_Enum_values11.Request)
60+
// CHECKALL-NEXT: Value: .a2(.item1)
61+
62+
reflect(enumValue: Request.a3(.item1))
63+
64+
// CHECKALL: Reflecting an enum value.
65+
// CHECKALL-NEXT: Type reference:
66+
// CHECKALL-NEXT: (enum reflect_Enum_values11.Request)
67+
// CHECKALL-NEXT: Value: .a3(.item1)
68+
69+
reflect(enumValue: Request.a4(.item1))
70+
71+
// CHECKALL: Reflecting an enum value.
72+
// CHECKALL-NEXT: Type reference:
73+
// CHECKALL-NEXT: (enum reflect_Enum_values11.Request)
74+
// CHECKALL-NEXT: Value: .a4(.item1)
75+
76+
reflect(enumValue: Request.a5(.item1))
77+
78+
// CHECKALL: Reflecting an enum value.
79+
// CHECKALL-NEXT: Type reference:
80+
// CHECKALL-NEXT: (enum reflect_Enum_values11.Request)
81+
// CHECKALL-NEXT: Value: .a5(.item1)
82+
83+
reflect(enumValue: Request.a6(.item1))
84+
85+
// CHECKALL: Reflecting an enum value.
86+
// CHECKALL-NEXT: Type reference:
87+
// CHECKALL-NEXT: (enum reflect_Enum_values11.Request)
88+
// CHECKALL-NEXT: Value: .a6(.item1)
89+
90+
reflect(enumValue: Request.a6(.item2))
91+
92+
// CHECKALL: Reflecting an enum value.
93+
// CHECKALL-NEXT: Type reference:
94+
// CHECKALL-NEXT: (enum reflect_Enum_values11.Request)
95+
// CHECKALL-NEXT: Value: .a6(.item2)
96+
97+
reflect(enumValue: Request.a7(.item1))
98+
99+
// CHECKALL: Reflecting an enum value.
100+
// CHECKALL-NEXT: Type reference:
101+
// CHECKALL-NEXT: (enum reflect_Enum_values11.Request)
102+
// CHECKALL-NEXT: Value: .a7(.item1)
103+
104+
reflect(enumValue: Request.a7(.item2))
105+
106+
// CHECKALL: Reflecting an enum value.
107+
// CHECKALL-NEXT: Type reference:
108+
// CHECKALL-NEXT: (enum reflect_Enum_values11.Request)
109+
// CHECKALL-NEXT: Value: .a7(.item2)
110+
111+
doneReflecting()
112+
113+
// CHECKALL: Done.
114+
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift -lswiftSwiftReflectionTest %s -o %t/reflect_Enum_values7
3+
// RUN: %target-codesign %t/reflect_Enum_values7
4+
5+
// RUN: %target-run %target-swift-reflection-test %t/reflect_Enum_values7 | tee /dev/stderr | %FileCheck %s --dump-input=fail
6+
7+
// REQUIRES: objc_interop
8+
// REQUIRES: executable_test
9+
// UNSUPPORTED: use_os_stdlib
10+
11+
import SwiftReflectionTest
12+
13+
public struct MyError : Error {}
14+
15+
// MemoryLayout<MPEWithClosurePayload>.size == 17
16+
// MemoryLayout<()->Void>.size == 16
17+
enum MPEWithClosurePayload {
18+
case int(()->Void)
19+
case closure(() -> Void)
20+
}
21+
22+
// MemoryLayout<E>.size == 17
23+
// enum E { case a(()->Void); case b(()->Void); }
24+
25+
reflect(enumValue: MPEWithClosurePayload.int({}))
26+
27+
// CHECK: Reflecting an enum value.
28+
// CHECK-NEXT: Type reference:
29+
// CHECK-NEXT: (enum reflect_Enum_values7.MPEWithClosurePayload)
30+
// CHECK-NEXT: Value: .int(_)
31+
32+
reflect(enumValue: MPEWithClosurePayload.closure({}))
33+
34+
// CHECK: Reflecting an enum value.
35+
// CHECK-NEXT: Type reference:
36+
// CHECK-NEXT: (enum reflect_Enum_values7.MPEWithClosurePayload)
37+
// CHECK-NEXT: Value: .closure(_)
38+
39+
doneReflecting()
40+
41+
// CHECK: Done.
42+
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift -lswiftSwiftReflectionTest %s -o %t/reflect_Enum_values8
3+
// RUN: %target-codesign %t/reflect_Enum_values8
4+
5+
// RUN: %target-run %target-swift-reflection-test %t/reflect_Enum_values8 | tee /dev/stderr | %FileCheck %s --check-prefix=CHECK%target-ptrsize --check-prefix=CHECKALL --dump-input=fail %add_num_extra_inhabitants
6+
7+
// REQUIRES: objc_interop
8+
// REQUIRES: executable_test
9+
// UNSUPPORTED: use_os_stdlib
10+
11+
import SwiftReflectionTest
12+
13+
enum B {
14+
case a(Int)
15+
case b(Float)
16+
}
17+
18+
enum A_Opt {
19+
case a(B?)
20+
case other(Int)
21+
}
22+
23+
reflect(enumValue: A_Opt.a(.none))
24+
25+
// CHECKALL: Reflecting an enum value.
26+
// CHECKALL-NEXT: Type reference:
27+
// CHECKALL-NEXT: (enum reflect_Enum_values8.A_Opt)
28+
// CHECKALL-NEXT: Value: .a(.none)
29+
30+
reflect(enumValue: A_Opt.a(.a(0)))
31+
32+
// CHECKALL: Reflecting an enum value.
33+
// CHECKALL-NEXT: Type reference:
34+
// CHECKALL-NEXT: (enum reflect_Enum_values8.A_Opt)
35+
// CHECKALL-NEXT: Value: .a(.some(.a(_)))
36+
37+
reflect(enumValue: A_Opt.a(.b(0.0)))
38+
39+
// CHECKALL: Reflecting an enum value.
40+
// CHECKALL-NEXT: Type reference:
41+
// CHECKALL-NEXT: (enum reflect_Enum_values8.A_Opt)
42+
// CHECKALL-NEXT: Value: .a(.some(.b(_)))
43+
44+
doneReflecting()
45+
46+
// CHECKALL: Done.
47+
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift -lswiftSwiftReflectionTest %s -o %t/reflect_Enum_values9
3+
// RUN: %target-codesign %t/reflect_Enum_values9
4+
5+
// RUN: %target-run %target-swift-reflection-test %t/reflect_Enum_values9 | tee /dev/stderr | %FileCheck %s --check-prefix=CHECK%target-ptrsize --check-prefix=CHECKALL --dump-input=fail %add_num_extra_inhabitants
6+
7+
// REQUIRES: objc_interop
8+
// REQUIRES: executable_test
9+
// UNSUPPORTED: use_os_stdlib
10+
11+
import SwiftReflectionTest
12+
13+
enum E : Error {
14+
case e
15+
}
16+
17+
// MemoryLayout<B>.size == 8
18+
// MemoryLayout<Error>.size == 8
19+
enum B {
20+
case a(Error)
21+
case b(Error)
22+
}
23+
24+
reflect(enumValue: B.a(E.e))
25+
26+
// CHECKALL: Reflecting an enum value.
27+
// CHECKALL-NEXT: Type reference:
28+
// CHECKALL-NEXT: (enum reflect_Enum_values9.B)
29+
// CHECKALL-NEXT: Value: .a(_)
30+
31+
reflect(enumValue: B.b(E.e))
32+
33+
// CHECKALL: Reflecting an enum value.
34+
// CHECKALL-NEXT: Type reference:
35+
// CHECKALL-NEXT: (enum reflect_Enum_values9.B)
36+
// CHECKALL-NEXT: Value: .b(_)
37+
38+
doneReflecting()
39+
40+
// CHECKALL: Done.
41+

0 commit comments

Comments
 (0)