Skip to content

[4.1] SIL : Use the enum 's generic signature and the payloads type f… #14234

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/swift/SIL/TypeLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -863,6 +863,9 @@ class TypeConverter {
GenericEnvironment *env,
bool isMutable);

CanSILBoxType getBoxTypeForEnumElement(SILType enumType,
EnumElementDecl *elt);

private:
CanType getLoweredRValueType(AbstractionPattern origType, CanType substType);

Expand Down
12 changes: 7 additions & 5 deletions lib/SIL/SILType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -328,17 +328,19 @@ SILType SILType::getEnumElementType(EnumElementDecl *elt, SILModule &M) const {
return SILType(objectType, getCategory());
}

// If the case is indirect, then the payload is boxed.
if (elt->isIndirect() || elt->getParentEnum()->isIndirect()) {
auto box = M.Types.getBoxTypeForEnumElement(*this, elt);
return SILType(SILType::getPrimitiveObjectType(box).getSwiftRValueType(),
getCategory());
}

auto substEltTy =
getSwiftRValueType()->getTypeOfMember(M.getSwiftModule(), elt,
elt->getArgumentInterfaceType());
auto loweredTy =
M.Types.getLoweredType(M.Types.getAbstractionPattern(elt), substEltTy);

// If the case is indirect, then the payload is boxed.
if (elt->isIndirect() || elt->getParentEnum()->isIndirect())
loweredTy = SILType::getPrimitiveObjectType(
SILBoxType::get(loweredTy.getSwiftRValueType()));

return SILType(loweredTy.getSwiftRValueType(), getCategory());
}

Expand Down
39 changes: 39 additions & 0 deletions lib/SIL/TypeLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2527,6 +2527,45 @@ TypeConverter::getContextBoxTypeForCapture(ValueDecl *captured,
return boxType;
}

CanSILBoxType TypeConverter::getBoxTypeForEnumElement(SILType enumType,
EnumElementDecl *elt) {

auto *enumDecl = enumType.getEnumOrBoundGenericEnum();

assert(elt->getDeclContext() == enumDecl);
assert(elt->isIndirect() || elt->getParentEnum()->isIndirect());

auto &C = M.getASTContext();

auto boxSignature = getEffectiveGenericSignature(enumDecl);

if (boxSignature == CanGenericSignature()) {
auto eltIntfTy = elt->getArgumentInterfaceType();
auto boxVarTy = getLoweredType(eltIntfTy).getSwiftRValueType();
auto layout = SILLayout::get(C, nullptr, SILField(boxVarTy, true));
return SILBoxType::get(C, layout, {});
}

// Use the enum's signature for the box type.
auto boundEnum = enumType.getSwiftRValueType();

// Lower the enum element's argument in the box's context.
auto eltIntfTy = elt->getArgumentInterfaceType();
GenericContextScope scope(*this, boxSignature);
auto boxVarTy = getLoweredType(getAbstractionPattern(elt), eltIntfTy)
.getSwiftRValueType();
auto layout = SILLayout::get(C, boxSignature, SILField(boxVarTy, true));

// Instantiate the layout with enum's substitution list.
auto subMap = boundEnum->getContextSubstitutionMap(
M.getSwiftModule(), enumDecl, enumDecl->getGenericEnvironment());
SmallVector<Substitution, 4> genericArgs;
boxSignature->getSubstitutions(subMap, genericArgs);

auto boxTy = SILBoxType::get(C, layout, genericArgs);
return boxTy;
}

static void countNumberOfInnerFields(unsigned &fieldsCount, SILModule &Module,
SILType Ty) {
if (auto *structDecl = Ty.getStructOrBoundGenericStruct()) {
Expand Down
2 changes: 1 addition & 1 deletion lib/SILGen/SILGenApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3532,7 +3532,7 @@ ManagedValue SILGenFunction::emitInjectEnum(SILLocation loc,
// throws, we know to deallocate the uninitialized box.
if (element->isIndirect() ||
element->getParentEnum()->isIndirect()) {
auto boxTy = SILBoxType::get(payloadTL.getLoweredType().getSwiftRValueType());
auto boxTy = SGM.M.Types.getBoxTypeForEnumElement(enumTy, element);
auto *box = B.createAllocBox(loc, boxTy);
auto *addr = B.createProjectBox(loc, box, 0);

Expand Down
16 changes: 16 additions & 0 deletions test/Interpreter/enum.swift
Original file line number Diff line number Diff line change
Expand Up @@ -651,3 +651,19 @@ func run() {
}

run()

public enum Indirect<T> {
indirect case payload((T, other: T))
case none
}

public func testIndirectEnum<T>(_ payload: T) -> Indirect<T> {
return Indirect.payload((payload, other: payload))
}

public func testCase(_ closure: @escaping (Int) -> ()) -> Indirect<(Int) -> ()> {
return testIndirectEnum(closure)
}

// CHECK: payload((Function), other: (Function))
print(testCase({ _ in }))
6 changes: 3 additions & 3 deletions test/SIL/Parser/indirect_enum.sil
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ entry(%e : $TreeA<T>):
%b = project_box %a : $<τ_0_0> { var τ_0_0 } <T>, 0

%c = unchecked_enum_data %e : $TreeA<T>, #TreeA.Branch!enumelt.1
%d = project_box %c : $<τ_0_0> { var τ_0_0 } <(left: TreeA<T>, right: TreeA<T>)>, 0
%d = project_box %c : $<τ_0_0> { var (left: TreeA<τ_0_0>, right: TreeA<τ_0_0>) } <T>, 0

return undef : $()
}
Expand All @@ -38,7 +38,7 @@ entry(%e : $*TreeB<T>):
destroy_addr %a : $*T

%c = unchecked_take_enum_data_addr %e : $*TreeB<T>, #TreeB.Branch!enumelt.1
%d = load [take] %c : $*<τ_0_0> { var τ_0_0 } <(left: TreeB<T>, right: TreeB<T>)>
%d = load [take] %c : $*<τ_0_0> { var (left: TreeB<τ_0_0>, right: TreeB<τ_0_0>) } <T>

return undef : $()
}
Expand All @@ -49,7 +49,7 @@ entry(%e : $TreeInt):
store %a to [trivial] undef : $*Int

%c = unchecked_enum_data %e : $TreeInt, #TreeInt.Branch!enumelt.1
%d = project_box %c : $<τ_0_0> { var τ_0_0 } <(left: TreeInt, right: TreeInt)>, 0
%d = project_box %c : ${ var (left: TreeInt, right: TreeInt) }, 0

return undef : $()
}
11 changes: 11 additions & 0 deletions test/SILGen/enum.swift
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,14 @@ enum Foo { case A(P, String) }
func Foo_cases() {
_ = Foo.A
}

enum Indirect<T> {
indirect case payload((T, other: T))
case none
}
// CHECK-LABEL: sil{{.*}} @{{.*}}makeIndirectEnum{{.*}} : $@convention(thin) <T> (@in T) -> @owned Indirect<T>
// CHECK: [[BOX:%.*]] = alloc_box $<τ_0_0> { var (τ_0_0, other: τ_0_0) } <T>
// CHECK: enum $Indirect<T>, #Indirect.payload!enumelt.1, [[BOX]] : $<τ_0_0> { var (τ_0_0, other: τ_0_0) } <T>
func makeIndirectEnum<T>(_ payload: T) -> Indirect<T> {
return Indirect.payload((payload, other: payload))
}
18 changes: 9 additions & 9 deletions test/SILGen/indirect_enum.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func TreeA_cases<T>(_ t: T, l: TreeA<T>, r: TreeA<T>) {
let _ = TreeA<T>.Leaf(t)

// CHECK-NEXT: [[METATYPE:%.*]] = metatype $@thin TreeA<T>.Type
// CHECK-NEXT: [[BOX:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <(left: TreeA<T>, right: TreeA<T>)>
// CHECK-NEXT: [[BOX:%.*]] = alloc_box $<τ_0_0> { var (left: TreeA<τ_0_0>, right: TreeA<τ_0_0>) } <T>
// CHECK-NEXT: [[PB:%.*]] = project_box [[BOX]]
// CHECK-NEXT: [[LEFT:%.*]] = tuple_element_addr [[PB]] : $*(left: TreeA<T>, right: TreeA<T>), 0
// CHECK-NEXT: [[RIGHT:%.*]] = tuple_element_addr [[PB]] : $*(left: TreeA<T>, right: TreeA<T>), 1
Expand All @@ -50,7 +50,7 @@ func TreeA_cases<T>(_ t: T, l: TreeA<T>, r: TreeA<T>) {
func TreeA_reabstract(_ f: @escaping (Int) -> Int) {
// CHECK: bb0([[ARG:%.*]] : $@callee_guaranteed (Int) -> Int):
// CHECK: [[METATYPE:%.*]] = metatype $@thin TreeA<(Int) -> Int>.Type
// CHECK-NEXT: [[BOX:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <@callee_guaranteed (@in Int) -> @out Int>
// CHECK-NEXT: [[BOX:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <(Int) -> Int>
// CHECK-NEXT: [[PB:%.*]] = project_box [[BOX]]
// CHECK-NEXT: [[BORROWED_ARG:%.*]] = begin_borrow [[ARG]]
// CHECK-NEXT: [[ARG_COPY:%.*]] = copy_value [[BORROWED_ARG]]
Expand Down Expand Up @@ -92,7 +92,7 @@ func TreeB_cases<T>(_ t: T, l: TreeB<T>, r: TreeB<T>) {
let _ = TreeB<T>.Leaf(t)

// CHECK-NEXT: [[METATYPE:%.*]] = metatype $@thin TreeB<T>.Type
// CHECK-NEXT: [[BOX:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <(left: TreeB<T>, right: TreeB<T>)>
// CHECK-NEXT: [[BOX:%.*]] = alloc_box $<τ_0_0> { var (left: TreeB<τ_0_0>, right: TreeB<τ_0_0>) } <T>
// CHECK-NEXT: [[PB:%.*]] = project_box [[BOX]]
// CHECK-NEXT: [[LEFT:%.*]] = tuple_element_addr [[PB]]
// CHECK-NEXT: [[RIGHT:%.*]] = tuple_element_addr [[PB]]
Expand Down Expand Up @@ -127,7 +127,7 @@ func TreeInt_cases(_ t: Int, l: TreeInt, r: TreeInt) {
let _ = TreeInt.Leaf(t)

// CHECK-NEXT: [[METATYPE:%.*]] = metatype $@thin TreeInt.Type
// CHECK-NEXT: [[BOX:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <(left: TreeInt, right: TreeInt)>
// CHECK-NEXT: [[BOX:%.*]] = alloc_box ${ var (left: TreeInt, right: TreeInt) }
// CHECK-NEXT: [[PB:%.*]] = project_box [[BOX]]
// CHECK-NEXT: [[LEFT:%.*]] = tuple_element_addr [[PB]]
// CHECK-NEXT: [[RIGHT:%.*]] = tuple_element_addr [[PB]]
Expand Down Expand Up @@ -194,7 +194,7 @@ func switchTreeA<T>(_ x: TreeA<T>) {
case .Leaf(let x):
b(x)

// CHECK: [[BRANCH_CASE]]([[NODE_BOX:%.*]] : $<τ_0_0> { var τ_0_0 } <(left: TreeA<T>, right: TreeA<T>)>):
// CHECK: [[BRANCH_CASE]]([[NODE_BOX:%.*]] : $<τ_0_0> { var (left: TreeA<τ_0_0>, right: TreeA<τ_0_0>) } <T>):
// CHECK: [[TUPLE_ADDR:%.*]] = project_box [[NODE_BOX]]
// CHECK: [[TUPLE:%.*]] = load_borrow [[TUPLE_ADDR]]
// CHECK: [[LEFT:%.*]] = tuple_extract [[TUPLE]] {{.*}}, 0
Expand Down Expand Up @@ -370,7 +370,7 @@ func guardTreeA<T>(_ tree: TreeA<T>) {
// CHECK: [[NO]]([[ORIGINAL_VALUE:%.*]] : $TreeA<T>):
// CHECK: destroy_value [[ORIGINAL_VALUE]]
// CHECK: end_borrow [[BORROWED_ARG_3]] from [[ARG]]
// CHECK: [[YES]]([[BOX:%.*]] : $<τ_0_0> { var τ_0_0 } <(left: TreeA<T>, right: TreeA<T>)>):
// CHECK: [[YES]]([[BOX:%.*]] : $<τ_0_0> { var (left: TreeA<τ_0_0>, right: TreeA<τ_0_0>) } <T>):
// CHECK: [[VALUE_ADDR:%.*]] = project_box [[BOX]]
// CHECK: [[TUPLE:%.*]] = load [take] [[VALUE_ADDR]]
// CHECK: [[TUPLE_COPY:%.*]] = copy_value [[TUPLE]]
Expand Down Expand Up @@ -425,7 +425,7 @@ func guardTreeA<T>(_ tree: TreeA<T>) {
// CHECK: [[NO]]([[ORIGINAL_VALUE:%.*]] : $TreeA<T>):
// CHECK: destroy_value [[ORIGINAL_VALUE]]
// CHECK: end_borrow [[BORROWED_ARG]] from [[ARG]]
// CHECK: [[YES]]([[BOX:%.*]] : $<τ_0_0> { var τ_0_0 } <(left: TreeA<T>, right: TreeA<T>)>):
// CHECK: [[YES]]([[BOX:%.*]] : $<τ_0_0> { var (left: TreeA<τ_0_0>, right: TreeA<τ_0_0>) } <T>):
// CHECK: [[VALUE_ADDR:%.*]] = project_box [[BOX]]
// CHECK: [[TUPLE:%.*]] = load [take] [[VALUE_ADDR]]
// CHECK: [[TUPLE_COPY:%.*]] = copy_value [[TUPLE]]
Expand Down Expand Up @@ -540,7 +540,7 @@ func dontDisableCleanupOfIndirectPayload(_ x: TrivialButIndirect) {
// CHECK: [[ARG_COPY:%.*]] = copy_value [[BORROWED_ARG]]
// CHECK: switch_enum [[ARG_COPY]] : $TrivialButIndirect, case #TrivialButIndirect.Direct!enumelt.1: [[YES:bb[0-9]+]], case #TrivialButIndirect.Indirect!enumelt.1: [[NO:bb[0-9]+]]
//
// CHECK: [[NO]]([[PAYLOAD:%.*]] : $<τ_0_0> { var τ_0_0 } <Int>):
// CHECK: [[NO]]([[PAYLOAD:%.*]] : ${ var Int }):
// CHECK: destroy_value [[PAYLOAD]]
// CHECK: end_borrow [[BORROWED_ARG]] from [[ARG]]
guard case .Direct(let foo) = x else { return }
Expand All @@ -555,7 +555,7 @@ func dontDisableCleanupOfIndirectPayload(_ x: TrivialButIndirect) {
// CHECK-NOT: destroy_value
// CHECK: end_borrow [[BORROWED_ARG]] from [[ARG]]

// CHECK: [[YES]]([[BOX:%.*]] : $<τ_0_0> { var τ_0_0 } <Int>):
// CHECK: [[YES]]([[BOX:%.*]] : ${ var Int }):
// CHECK: destroy_value [[BOX]]

guard case .Indirect(let bar) = x else { return }
Expand Down
12 changes: 6 additions & 6 deletions test/SILOptimizer/predictable_memopt.sil
Original file line number Diff line number Diff line change
Expand Up @@ -436,14 +436,14 @@ enum IndirectCase {
sil @indirect_enum_box : $@convention(thin) (Int) -> IndirectCase {
// CHECK: bb0([[X:%.*]] : $Int):
entry(%x : $Int):
// CHECK: [[BOX:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <Int>
%b = alloc_box $<τ_0_0> { var τ_0_0 } <Int>
// CHECK: [[BOX:%.*]] = alloc_box ${ var Int }
%b = alloc_box ${ var Int }
// CHECK: [[PB:%.*]] = project_box [[BOX]]
%ba = project_box %b : $<τ_0_0> { var τ_0_0 } <Int>, 0
%ba = project_box %b : ${ var Int }, 0
// CHECK: store [[X]] to [[PB]]
store %x to %ba : $*Int
// CHECK: [[E:%.*]] = enum $IndirectCase, #IndirectCase.X!enumelt.1, [[BOX]] : $<τ_0_0> { var τ_0_0 } <Int>
%e = enum $IndirectCase, #IndirectCase.X!enumelt.1, %b : $<τ_0_0> { var τ_0_0 } <Int>
// CHECK: [[E:%.*]] = enum $IndirectCase, #IndirectCase.X!enumelt.1, [[BOX]] : ${ var Int }
%e = enum $IndirectCase, #IndirectCase.X!enumelt.1, %b : ${ var Int }
// CHECK: return [[E]]
return %e : $IndirectCase
}
Expand Down Expand Up @@ -837,4 +837,4 @@ bb1:
bb2:
destroy_addr %1 : $*Builtin.NativeObject
unreachable
}
}