Skip to content

Commit a0e1810

Browse files
authored
[IRGen] Generate layout strings for subset of enums (swiftlang#63930)
rdar://105959425
1 parent 3dae89e commit a0e1810

File tree

4 files changed

+140
-48
lines changed

4 files changed

+140
-48
lines changed

lib/IRGen/GenMeta.cpp

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1591,14 +1591,16 @@ namespace {
15911591

15921592
Size PayloadSizeOffset;
15931593
const EnumImplStrategy &Strategy;
1594-
1594+
bool hasLayoutString;
1595+
15951596
public:
15961597
EnumContextDescriptorBuilder(IRGenModule &IGM, EnumDecl *Type,
1597-
RequireMetadata_t requireMetadata)
1598-
: super(IGM, Type, requireMetadata),
1599-
Strategy(getEnumImplStrategy(IGM,
1600-
getType()->getDeclaredTypeInContext()->getCanonicalType()))
1601-
{
1598+
RequireMetadata_t requireMetadata,
1599+
bool hasLayoutString)
1600+
: super(IGM, Type, requireMetadata),
1601+
Strategy(getEnumImplStrategy(
1602+
IGM, getType()->getDeclaredTypeInContext()->getCanonicalType())),
1603+
hasLayoutString(hasLayoutString) {
16021604
auto &layout = IGM.getMetadataLayout(getType());
16031605
if (layout.hasPayloadSizeOffset())
16041606
PayloadSizeOffset = layout.getPayloadSizeOffset().getStatic();
@@ -1635,6 +1637,8 @@ namespace {
16351637
TypeContextDescriptorFlags flags;
16361638

16371639
setCommonFlags(flags);
1640+
flags.setHasLayoutString(hasLayoutString);
1641+
16381642
return flags.getOpaqueValue();
16391643
}
16401644

@@ -2567,7 +2571,9 @@ void irgen::emitLazyTypeContextDescriptor(IRGenModule &IGM,
25672571
StructContextDescriptorBuilder(IGM, sd, requireMetadata,
25682572
/*hasLayoutString*/ false).emit();
25692573
} else if (auto ed = dyn_cast<EnumDecl>(type)) {
2570-
EnumContextDescriptorBuilder(IGM, ed, requireMetadata).emit();
2574+
EnumContextDescriptorBuilder(IGM, ed, requireMetadata,
2575+
/*hasLayoutString*/ false)
2576+
.emit();
25712577
} else if (auto cd = dyn_cast<ClassDecl>(type)) {
25722578
ClassContextDescriptorBuilder(IGM, cd, requireMetadata).emit();
25732579
} else {
@@ -5277,8 +5283,9 @@ namespace {
52775283
}
52785284

52795285
llvm::Constant *emitNominalTypeDescriptor() {
5280-
auto descriptor =
5281-
EnumContextDescriptorBuilder(IGM, Target, RequireMetadata).emit();
5286+
auto descriptor = EnumContextDescriptorBuilder(
5287+
IGM, Target, RequireMetadata, !!getLayoutString())
5288+
.emit();
52825289
return descriptor;
52835290
}
52845291

@@ -5471,7 +5478,9 @@ namespace {
54715478
}
54725479

54735480
llvm::Constant *emitNominalTypeDescriptor() {
5474-
return EnumContextDescriptorBuilder(IGM, Target, RequireMetadata).emit();
5481+
return EnumContextDescriptorBuilder(IGM, Target, RequireMetadata,
5482+
/*hasLayoutString*/ false)
5483+
.emit();
54755484
}
54765485

54775486
GenericMetadataPatternFlags getPatternFlags() {

lib/IRGen/TypeLayout.cpp

Lines changed: 45 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2181,51 +2181,63 @@ llvm::Value *EnumTypeLayoutEntry::isBitwiseTakable(IRGenFunction &IGF) const {
21812181
llvm::Constant *
21822182
EnumTypeLayoutEntry::layoutString(IRGenModule &IGM,
21832183
GenericSignature genericSig) const {
2184-
return nullptr;
2185-
// LayoutStringBuilder B{};
2184+
switch (copyDestroyKind(IGM)) {
2185+
case CopyDestroyStrategy::POD:
2186+
case CopyDestroyStrategy::Normal: {
2187+
return nullptr;
2188+
}
2189+
case CopyDestroyStrategy::ForwardToPayload:
2190+
case CopyDestroyStrategy::NullableRefcounted: {
2191+
LayoutStringBuilder B{};
21862192

2187-
// if (containsArchetypeField() ||
2188-
// containsResilientField() ||
2189-
// isMultiPayloadEnum() ||
2190-
// !refCountString(IGM, B)) {
2191-
// return nullptr;
2192-
// }
2193+
if (containsArchetypeField() || containsResilientField() ||
2194+
isMultiPayloadEnum() || !refCountString(IGM, B, genericSig)) {
2195+
return nullptr;
2196+
}
21932197

2194-
// ConstantInitBuilder IB(IGM);
2195-
// auto SB = IB.beginStruct();
2196-
// SB.setPacked(true);
2198+
ConstantInitBuilder IB(IGM);
2199+
auto SB = IB.beginStruct();
2200+
SB.setPacked(true);
21972201

2198-
// B.result(IGM, SB);
2202+
B.result(IGM, SB);
2203+
2204+
IRGenMangler mangler;
2205+
std::string symbolName =
2206+
mangler.mangleSymbolNameForMangledMetadataAccessorString(
2207+
"type_layout_string", genericSig.getCanonicalSignature(),
2208+
ty.getASTType()->mapTypeOutOfContext()->getCanonicalType());
21992209

2200-
// return SB.finishAndCreateGlobal("", IGM.getPointerAlignment(),
2201-
// /*constant*/ true);
2210+
return SB.finishAndCreateGlobal(symbolName, IGM.getPointerAlignment(),
2211+
/*constant*/ true);
2212+
}
2213+
}
22022214
}
22032215

22042216
bool EnumTypeLayoutEntry::refCountString(IRGenModule &IGM,
22052217
LayoutStringBuilder &B,
22062218
GenericSignature genericSig) const {
2207-
// switch (copyDestroyKind(IGM)) {
2208-
// case CopyDestroyStrategy::POD: {
2209-
// auto size = fixedSize(IGM);
2210-
// assert(size && "POD should not have dynamic size");
2211-
// B.addSkip(size->getValue());
2212-
// return true;
2213-
// }
2214-
// case CopyDestroyStrategy::NullableRefcounted:
2215-
// case CopyDestroyStrategy::ForwardToPayload:
2216-
// return cases[0]->refCountString(IGM, B, genericSig);
2217-
// case CopyDestroyStrategy::Normal:
2218-
auto *accessor = createMetatypeAccessorFunction(IGM, ty, genericSig);
2219+
switch (copyDestroyKind(IGM)) {
2220+
case CopyDestroyStrategy::POD: {
2221+
auto size = fixedSize(IGM);
2222+
assert(size && "POD should not have dynamic size");
2223+
B.addSkip(size->getValue());
2224+
return true;
2225+
}
2226+
case CopyDestroyStrategy::NullableRefcounted:
2227+
case CopyDestroyStrategy::ForwardToPayload:
2228+
return cases[0]->refCountString(IGM, B, genericSig);
2229+
case CopyDestroyStrategy::Normal: {
22192230
if (genericSig || !isFixedSize(IGM)) {
2220-
B.addResilientRefCount(accessor);
2231+
// B.addResilientRefCount(accessor);
22212232
return false;
2222-
} else {
2223-
B.addFixedEnumRefCount(accessor);
2224-
B.addSkip(fixedSize(IGM)->getValue());
22252233
}
22262234

2235+
auto *accessor = createMetatypeAccessorFunction(IGM, ty, genericSig);
2236+
B.addFixedEnumRefCount(accessor);
2237+
B.addSkip(fixedSize(IGM)->getValue());
22272238
return true;
2228-
// }
2239+
}
2240+
}
22292241
}
22302242

22312243
void EnumTypeLayoutEntry::computeProperties() {
@@ -2245,7 +2257,8 @@ EnumTypeLayoutEntry::copyDestroyKind(IRGenModule &IGM) const {
22452257
return NullableRefcounted;
22462258
} else {
22472259
unsigned numTags = numEmptyCases;
2248-
if (cases[0]->canValueWitnessExtraInhabitantsUpTo(IGM, numTags - 1)) {
2260+
if (cases.size() == 1 &&
2261+
cases[0]->canValueWitnessExtraInhabitantsUpTo(IGM, numTags - 1)) {
22492262
return ForwardToPayload;
22502263
}
22512264
return Normal;

test/Interpreter/Inputs/layout_string_witnesses_types.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import Swift
2+
13
public class SimpleClass {
24
public let x: Int
35

@@ -134,6 +136,16 @@ public struct ExistentialRefWrapper {
134136
}
135137
}
136138

139+
public enum NullableRefEnum {
140+
case nonEmpty(SimpleClass)
141+
case empty
142+
}
143+
144+
public enum ForwardToPayloadEnum {
145+
case nonEmpty(SimpleClass, Int)
146+
case empty
147+
}
148+
137149
#if os(macOS)
138150
import Foundation
139151

test/Interpreter/layout_string_witnesses_static.swift

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
// RUN: %empty-directory(%t)
2-
// RUN: %target-swift-frontend -enable-experimental-feature LayoutStringValueWitnesses -enable-type-layout -emit-module -emit-module-path=%t/layout_string_witnesses_types.swiftmodule %S/Inputs/layout_string_witnesses_types.swift
3-
// RUN: %target-build-swift -Xfrontend -enable-experimental-feature -Xfrontend LayoutStringValueWitnesses -Xfrontend -enable-type-layout -c -parse-as-library -o %t/layout_string_witnesses_types.o %S/Inputs/layout_string_witnesses_types.swift
2+
// RUN: %target-swift-frontend -enable-experimental-feature LayoutStringValueWitnesses -enable-type-layout -parse-stdlib -emit-module -emit-module-path=%t/layout_string_witnesses_types.swiftmodule %S/Inputs/layout_string_witnesses_types.swift
3+
// RUN: %target-build-swift -Xfrontend -enable-experimental-feature -Xfrontend LayoutStringValueWitnesses -Xfrontend -enable-type-layout -Xfrontend -parse-stdlib -c -parse-as-library -o %t/layout_string_witnesses_types.o %S/Inputs/layout_string_witnesses_types.swift
44
// RUN: %target-swift-frontend -enable-experimental-feature LayoutStringValueWitnesses -enable-library-evolution -emit-module -emit-module-path=%t/layout_string_witnesses_types_resilient.swiftmodule %S/Inputs/layout_string_witnesses_types_resilient.swift
55
// RUN: %target-build-swift -g -Xfrontend -enable-experimental-feature -Xfrontend LayoutStringValueWitnesses -Xfrontend -enable-library-evolution -c -parse-as-library -o %t/layout_string_witnesses_types_resilient.o %S/Inputs/layout_string_witnesses_types_resilient.swift
6-
// RUN: %target-build-swift -g -Xfrontend -enable-experimental-feature -Xfrontend LayoutStringValueWitnesses -Xfrontend -enable-type-layout -module-name layout_string_witnesses_static %t/layout_string_witnesses_types.o %t/layout_string_witnesses_types_resilient.o -I %t -o %t/main %s
6+
// RUN: %target-build-swift -g -Xfrontend -enable-experimental-feature -Xfrontend LayoutStringValueWitnesses -Xfrontend -enable-type-layout -Xfrontend -parse-stdlib -module-name layout_string_witnesses_static %t/layout_string_witnesses_types.o %t/layout_string_witnesses_types_resilient.o -I %t -o %t/main %s
77
// RUN: %target-codesign %t/main
88
// RUN: %target-run %t/main | %FileCheck %s --check-prefix=CHECK -check-prefix=CHECK-%target-os
99

1010
// REQUIRES: executable_test
1111

12+
import Swift
1213
import layout_string_witnesses_types
1314
import layout_string_witnesses_types_resilient
1415

@@ -189,7 +190,7 @@ class ClassWithSomeProtocol: SomeProtocol {
189190

190191
func testExistential() {
191192
let ptr = UnsafeMutablePointer<ExistentialWrapper>.allocate(capacity: 1)
192-
193+
193194
do {
194195
let x = ClassWithSomeProtocol()
195196
testInit(ptr, to: ExistentialWrapper(x: x))
@@ -271,16 +272,73 @@ func testMultiPayloadEnum() {
271272

272273
// CHECK-NEXT: Before deinit
273274
print("Before deinit")
274-
275275

276276
// CHECK-NEXT: SimpleClass deinitialized!
277277
testDestroy(ptr)
278-
278+
279279
ptr.deallocate()
280280
}
281281

282282
testMultiPayloadEnum()
283283

284+
func testNullableRefEnum() {
285+
let ptr = UnsafeMutablePointer<NullableRefEnum>.allocate(capacity: 1)
286+
287+
do {
288+
let x = NullableRefEnum.nonEmpty(SimpleClass(x: 23))
289+
testInit(ptr, to: x)
290+
}
291+
292+
do {
293+
let y = NullableRefEnum.nonEmpty(SimpleClass(x: 28))
294+
295+
// CHECK: Before deinit
296+
print("Before deinit")
297+
298+
// CHECK-NEXT: SimpleClass deinitialized!
299+
testAssign(ptr, from: y)
300+
}
301+
302+
// CHECK-NEXT: Before deinit
303+
print("Before deinit")
304+
305+
// CHECK-NEXT: SimpleClass deinitialized!
306+
testDestroy(ptr)
307+
308+
ptr.deallocate()
309+
}
310+
311+
testNullableRefEnum()
312+
313+
func testForwardToPayloadEnum() {
314+
let ptr = UnsafeMutablePointer<ForwardToPayloadEnum>.allocate(capacity: 1)
315+
316+
do {
317+
let x = ForwardToPayloadEnum.nonEmpty(SimpleClass(x: 23), 43)
318+
testInit(ptr, to: x)
319+
}
320+
321+
do {
322+
let y = ForwardToPayloadEnum.nonEmpty(SimpleClass(x: 28), 65)
323+
324+
// CHECK: Before deinit
325+
print("Before deinit")
326+
327+
// CHECK-NEXT: SimpleClass deinitialized!
328+
testAssign(ptr, from: y)
329+
}
330+
331+
// CHECK-NEXT: Before deinit
332+
print("Before deinit")
333+
334+
// CHECK-NEXT: SimpleClass deinitialized!
335+
testDestroy(ptr)
336+
337+
ptr.deallocate()
338+
}
339+
340+
testForwardToPayloadEnum()
341+
284342
#if os(macOS)
285343
func testObjc() {
286344
let ptr = UnsafeMutablePointer<ObjcWrapper>.allocate(capacity: 1)

0 commit comments

Comments
 (0)