Skip to content

Commit 2d27ec5

Browse files
authored
Merge pull request swiftlang#72267 from meg-gupta/enablesilcombineempty
Enable SILCombine of inject_enum_addr for empty types
2 parents a312225 + 50f0fd2 commit 2d27ec5

File tree

6 files changed

+122
-53
lines changed

6 files changed

+122
-53
lines changed

include/swift/SILOptimizer/Utils/InstOptUtils.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,12 @@ bool specializeClassMethodInst(ClassMethodInst *cm);
598598
bool specializeAppliesInFunction(SILFunction &F,
599599
SILTransform *transform,
600600
bool isMandatory);
601+
602+
/// Instantiate the specified type by recursively tupling and structing the
603+
/// unique instances of the empty types and undef "instances" of the non-empty
604+
/// types aggregated together at each level.
605+
SILValue createEmptyAndUndefValue(SILType ty, SILInstruction *insertionPoint,
606+
SILBuilderContext &ctx, bool noUndef = false);
601607
} // end namespace swift
602608

603609
#endif // SWIFT_SILOPTIMIZER_UTILS_INSTOPTUTILS_H

lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -953,16 +953,6 @@ SILCombiner::visitInjectEnumAddrInst(InjectEnumAddrInst *IEAI) {
953953
// can't handle the payload case here due to the flow problems caused by the
954954
// dependency in between the enum and its data.
955955

956-
// Disable this for empty typle type because empty tuple stack locations maybe
957-
// uninitialized. And converting to value form loses tag information.
958-
if (IEAI->getElement()->hasAssociatedValues()) {
959-
SILType elemType = IEAI->getOperand()->getType().getEnumElementType(
960-
IEAI->getElement(), IEAI->getFunction());
961-
if (elemType.isEmpty(*IEAI->getFunction())) {
962-
return nullptr;
963-
}
964-
}
965-
966956
assert(IEAI->getOperand()->getType().isAddress() && "Must be an address");
967957
Builder.setCurrentDebugScope(IEAI->getDebugScope());
968958

@@ -1231,6 +1221,7 @@ SILCombiner::visitInjectEnumAddrInst(InjectEnumAddrInst *IEAI) {
12311221
auto *AI = dyn_cast_or_null<ApplyInst>(getSingleNonDebugUser(DataAddrInst));
12321222
if (!AI)
12331223
return nullptr;
1224+
12341225
unsigned ArgIdx = 0;
12351226
Operand *EnumInitOperand = nullptr;
12361227
for (auto &Opd : AI->getArgumentOperands()) {
@@ -1255,10 +1246,22 @@ SILCombiner::visitInjectEnumAddrInst(InjectEnumAddrInst *IEAI) {
12551246
EnumInitOperand->get()->getType());
12561247
EnumInitOperand->set(AllocStack);
12571248
Builder.setInsertionPoint(std::next(SILBasicBlock::iterator(AI)));
1258-
SILValue Load(Builder.createLoad(DataAddrInst->getLoc(), AllocStack,
1259-
LoadOwnershipQualifier::Unqualified));
1249+
SILValue enumValue;
1250+
1251+
// If it is an empty type, apply may not initialize it.
1252+
// Create an empty value of the empty type and store it to a new local.
1253+
SILType elemType = IEAI->getOperand()->getType().getEnumElementType(
1254+
IEAI->getElement(), IEAI->getFunction());
1255+
if (elemType.isEmpty(*IEAI->getFunction())) {
1256+
enumValue = createEmptyAndUndefValue(
1257+
elemType.getObjectType(), &*Builder.getInsertionPoint(),
1258+
Builder.getBuilderContext(), /*noUndef*/ true);
1259+
} else {
1260+
enumValue = Builder.createLoad(DataAddrInst->getLoc(), AllocStack,
1261+
LoadOwnershipQualifier::Unqualified);
1262+
}
12601263
EnumInst *E = Builder.createEnum(
1261-
DataAddrInst->getLoc(), Load, DataAddrInst->getElement(),
1264+
DataAddrInst->getLoc(), enumValue, DataAddrInst->getElement(),
12621265
DataAddrInst->getOperand()->getType().getObjectType());
12631266
Builder.createStore(DataAddrInst->getLoc(), E, DataAddrInst->getOperand(),
12641267
StoreOwnershipQualifier::Unqualified);

lib/SILOptimizer/Transforms/SILMem2Reg.cpp

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -679,43 +679,6 @@ replaceLoad(SILInstruction *inst, SILValue newValue, AllocStackInst *asi,
679679
}
680680
}
681681

682-
/// Instantiate the specified type by recursively tupling and structing the
683-
/// unique instances of the empty types and undef "instances" of the non-empty
684-
/// types aggregated together at each level.
685-
static SILValue createEmptyAndUndefValue(SILType ty,
686-
SILInstruction *insertionPoint,
687-
SILBuilderContext &ctx) {
688-
auto *function = insertionPoint->getFunction();
689-
if (auto tupleTy = ty.getAs<TupleType>()) {
690-
SmallVector<SILValue, 4> elements;
691-
for (unsigned idx : range(tupleTy->getNumElements())) {
692-
SILType elementTy = ty.getTupleElementType(idx);
693-
auto element = createEmptyAndUndefValue(elementTy, insertionPoint, ctx);
694-
elements.push_back(element);
695-
}
696-
SILBuilderWithScope builder(insertionPoint, ctx);
697-
return builder.createTuple(insertionPoint->getLoc(), ty, elements);
698-
} else if (auto *decl = ty.getStructOrBoundGenericStruct()) {
699-
TypeExpansionContext tec = *function;
700-
auto &module = function->getModule();
701-
if (decl->isResilient(tec.getContext()->getParentModule(),
702-
tec.getResilienceExpansion())) {
703-
llvm::errs() << "Attempting to create value for illegal empty type:\n";
704-
ty.print(llvm::errs());
705-
llvm::report_fatal_error("illegal empty type: resilient struct");
706-
}
707-
SmallVector<SILValue, 4> elements;
708-
for (auto *field : decl->getStoredProperties()) {
709-
auto elementTy = ty.getFieldType(field, module, tec);
710-
auto element = createEmptyAndUndefValue(elementTy, insertionPoint, ctx);
711-
elements.push_back(element);
712-
}
713-
SILBuilderWithScope builder(insertionPoint, ctx);
714-
return builder.createStruct(insertionPoint->getLoc(), ty, elements);
715-
} else {
716-
return SILUndef::get(insertionPoint->getFunction(), ty);
717-
}
718-
}
719682

720683
/// Whether lexical lifetimes should be added for the values stored into the
721684
/// alloc_stack.

lib/SILOptimizer/Utils/InstOptUtils.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1972,3 +1972,40 @@ IntegerLiteralInst *swift::optimizeBuiltinCanBeObjCClass(BuiltinInst *bi,
19721972
}
19731973
llvm_unreachable("Unhandled TypeTraitResult in switch.");
19741974
}
1975+
1976+
SILValue swift::createEmptyAndUndefValue(SILType ty,
1977+
SILInstruction *insertionPoint,
1978+
SILBuilderContext &ctx,
1979+
bool noUndef) {
1980+
auto *function = insertionPoint->getFunction();
1981+
if (auto tupleTy = ty.getAs<TupleType>()) {
1982+
SmallVector<SILValue, 4> elements;
1983+
for (unsigned idx : range(tupleTy->getNumElements())) {
1984+
SILType elementTy = ty.getTupleElementType(idx);
1985+
auto element = createEmptyAndUndefValue(elementTy, insertionPoint, ctx);
1986+
elements.push_back(element);
1987+
}
1988+
SILBuilderWithScope builder(insertionPoint, ctx);
1989+
return builder.createTuple(insertionPoint->getLoc(), ty, elements);
1990+
}
1991+
if (auto *decl = ty.getStructOrBoundGenericStruct()) {
1992+
TypeExpansionContext tec = *function;
1993+
auto &module = function->getModule();
1994+
if (decl->isResilient(tec.getContext()->getParentModule(),
1995+
tec.getResilienceExpansion())) {
1996+
llvm::errs() << "Attempting to create value for illegal empty type:\n";
1997+
ty.print(llvm::errs());
1998+
llvm::report_fatal_error("illegal empty type: resilient struct");
1999+
}
2000+
SmallVector<SILValue, 4> elements;
2001+
for (auto *field : decl->getStoredProperties()) {
2002+
auto elementTy = ty.getFieldType(field, module, tec);
2003+
auto element = createEmptyAndUndefValue(elementTy, insertionPoint, ctx);
2004+
elements.push_back(element);
2005+
}
2006+
SILBuilderWithScope builder(insertionPoint, ctx);
2007+
return builder.createStruct(insertionPoint->getLoc(), ty, elements);
2008+
}
2009+
assert(!noUndef);
2010+
return SILUndef::get(insertionPoint->getFunction(), ty);
2011+
}

test/Inputs/resilient_struct.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,3 +119,5 @@ public struct UnavailableResilientInt {
119119
self.i = i
120120
}
121121
}
122+
123+
public struct ResilientEmptyStruct {}

test/SILOptimizer/sil_combine_enum_addr.sil

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
1-
// RUN: %target-sil-opt -enable-sil-verify-all %s -sil-combine -jumpthread-simplify-cfg | %FileCheck %s
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-module -enable-library-evolution \
3+
// RUN: -emit-module-path=%t/resilient_struct.swiftmodule \
4+
// RUN: -module-name=resilient_struct %S/../Inputs/resilient_struct.swift
5+
6+
// RUN: %target-sil-opt -enable-sil-verify-all %s -sil-combine -jumpthread-simplify-cfg -I %t | %FileCheck %s
27

38
sil_stage canonical
49

510
import Builtin
611
import Swift
712

13+
import resilient_struct
14+
815
// CHECK-LABEL: sil @convert_inject_enum_addr_select_enum_addr_into_cond_br : $@convention(thin) (@in Int, @inout _Stdout) -> ()
916
// CHECK-NOT: init_existential_addr
1017
// CHECK-NOT: inject_enum_addr
@@ -254,8 +261,7 @@ bb22:
254261
sil @no_init : $@convention(thin) () -> (@out ())
255262

256263
// CHECK-LABEL: sil @test_empty_tuple_uninintialized : $@convention(thin) () -> () {
257-
// CHECK: init_enum_data_addr
258-
// CHECK: inject_enum_addr
264+
// CHECK-NOT: inject_enum_addr
259265
// CHECK-LABEL: } // end sil function 'test_empty_tuple_uninintialized'
260266
sil @test_empty_tuple_uninintialized : $@convention(thin) () -> () {
261267
bb0:
@@ -279,3 +285,55 @@ bb3:
279285
return %8 : $()
280286
}
281287

288+
sil @no_init_nested_tuple : $@convention(thin) () -> (@out ((), ()))
289+
290+
// CHECK-LABEL: sil @test_empty_nested_tuple_uninintialized : $@convention(thin) () -> () {
291+
// CHECK-NOT: inject_enum_addr
292+
// CHECK-LABEL: } // end sil function 'test_empty_nested_tuple_uninintialized'
293+
sil @test_empty_nested_tuple_uninintialized : $@convention(thin) () -> () {
294+
bb0:
295+
%0 = alloc_stack $Optional<((), ())>
296+
%1 = init_enum_data_addr %0 : $*Optional<((), ())>, #Optional.some!enumelt
297+
%f = function_ref @no_init_nested_tuple : $@convention(thin) () -> (@out ((), ()))
298+
apply %f(%1) : $@convention(thin) () -> (@out ((), ()))
299+
inject_enum_addr %0 : $*Optional<((), ())>, #Optional.some!enumelt
300+
%2 = load %0 : $*Optional<((), ())>
301+
switch_enum %2 : $Optional<((), ())>, case #Optional.some!enumelt: bb1, case #Optional.none!enumelt: bb2
302+
303+
bb1(%4 : $((), ())):
304+
br bb3
305+
306+
bb2:
307+
br bb3
308+
309+
bb3:
310+
dealloc_stack %0 : $*Optional<((), ())>
311+
%8 = tuple ()
312+
return %8 : $()
313+
}
314+
315+
sil @no_init_struct : $@convention(thin) () -> (@out ResilientEmptyStruct)
316+
317+
// CHECK-LABEL: sil @test_empty_struct_uninintialized : $@convention(thin) () -> () {
318+
// CHECK-NOT: switch_enum_addr
319+
// CHECK-LABEL: } // end sil function 'test_empty_struct_uninintialized'
320+
sil @test_empty_struct_uninintialized : $@convention(thin) () -> () {
321+
bb0:
322+
%0 = alloc_stack $Optional<ResilientEmptyStruct>
323+
%1 = init_enum_data_addr %0 : $*Optional<ResilientEmptyStruct>, #Optional.some!enumelt
324+
%f = function_ref @no_init_struct : $@convention(thin) () -> (@out ResilientEmptyStruct)
325+
apply %f(%1) : $@convention(thin) () -> (@out ResilientEmptyStruct)
326+
inject_enum_addr %0 : $*Optional<ResilientEmptyStruct>, #Optional.some!enumelt
327+
switch_enum_addr %0 : $*Optional<ResilientEmptyStruct>, case #Optional.some!enumelt: bb1, case #Optional.none!enumelt: bb2
328+
329+
bb1:
330+
br bb3
331+
332+
bb2:
333+
br bb3
334+
335+
bb3:
336+
dealloc_stack %0 : $*Optional<ResilientEmptyStruct>
337+
%8 = tuple ()
338+
return %8 : $()
339+
}

0 commit comments

Comments
 (0)