Skip to content

Commit 1208d32

Browse files
Merge pull request #64356 from nate-chandler/rdar106224845
[Mem2Reg] Instantiate arbitrary empty types.
2 parents ed9e2d6 + e089e95 commit 1208d32

File tree

2 files changed

+65
-15
lines changed

2 files changed

+65
-15
lines changed

lib/SILOptimizer/Transforms/SILMem2Reg.cpp

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -470,19 +470,43 @@ replaceLoad(SILInstruction *inst, SILValue newValue, AllocStackInst *asi,
470470
}
471471
}
472472

473-
/// Create a tuple value for an empty tuple or a tuple of empty tuples.
474-
static SILValue createValueForEmptyTuple(SILType ty,
475-
SILInstruction *insertionPoint,
476-
SILBuilderContext &ctx) {
477-
auto tupleTy = ty.castTo<TupleType>();
478-
SmallVector<SILValue, 4> elements;
479-
for (unsigned idx : range(tupleTy->getNumElements())) {
480-
SILType elementTy = ty.getTupleElementType(idx);
481-
elements.push_back(
482-
createValueForEmptyTuple(elementTy, insertionPoint, ctx));
473+
/// Instantiate the specified empty type by recursively tupling and structing
474+
/// the empty types aggregated together at each level.
475+
static SILValue createValueForEmptyType(SILType ty,
476+
SILInstruction *insertionPoint,
477+
SILBuilderContext &ctx) {
478+
auto *function = insertionPoint->getFunction();
479+
assert(ty.isEmpty(*function));
480+
if (auto tupleTy = ty.getAs<TupleType>()) {
481+
SmallVector<SILValue, 4> elements;
482+
for (unsigned idx : range(tupleTy->getNumElements())) {
483+
SILType elementTy = ty.getTupleElementType(idx);
484+
auto element = createValueForEmptyType(elementTy, insertionPoint, ctx);
485+
elements.push_back(element);
486+
}
487+
SILBuilderWithScope builder(insertionPoint, ctx);
488+
return builder.createTuple(insertionPoint->getLoc(), ty, elements);
489+
} else if (auto *decl = ty.getStructOrBoundGenericStruct()) {
490+
TypeExpansionContext tec = *function;
491+
auto &module = function->getModule();
492+
if (decl->isResilient(tec.getContext()->getParentModule(),
493+
tec.getResilienceExpansion())) {
494+
llvm::errs() << "Attempting to create value for illegal empty type:\n";
495+
ty.print(llvm::errs());
496+
llvm::report_fatal_error("illegal empty type: resilient struct");
497+
}
498+
SmallVector<SILValue, 4> elements;
499+
for (auto *field : decl->getStoredProperties()) {
500+
auto elementTy = ty.getFieldType(field, module, tec);
501+
auto element = createValueForEmptyType(elementTy, insertionPoint, ctx);
502+
elements.push_back(element);
503+
}
504+
SILBuilderWithScope builder(insertionPoint, ctx);
505+
return builder.createStruct(insertionPoint->getLoc(), ty, elements);
483506
}
484-
SILBuilderWithScope builder(insertionPoint, ctx);
485-
return builder.createTuple(insertionPoint->getLoc(), ty, elements);
507+
llvm::errs() << "Attempting to create value for illegal empty type:\n";
508+
ty.print(llvm::errs());
509+
llvm::report_fatal_error("illegal empty type: neither tuple nor struct.");
486510
}
487511

488512
/// Whether lexical lifetimes should be added for the values stored into the
@@ -1859,11 +1883,11 @@ void MemoryToRegisters::removeSingleBlockAllocation(AllocStackInst *asi) {
18591883
// with our running value.
18601884
if (isLoadFromStack(inst, asi)) {
18611885
if (!runningVals) {
1862-
// Loading without a previous store is only acceptable if the type is
1863-
// Void (= empty tuple) or a tuple of Voids.
1886+
// Loading from uninitialized memory is only acceptable if the type is
1887+
// empty--an aggregate of types without storage.
18641888
runningVals = {
18651889
LiveValues::toReplace(asi,
1866-
/*replacement=*/createValueForEmptyTuple(
1890+
/*replacement=*/createValueForEmptyType(
18671891
asi->getElementType(), inst, ctx)),
18681892
/*isStorageValid=*/true};
18691893
}

test/SILOptimizer/mem2reg.sil

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ struct LargeCodesizeStruct {
2222
var s5: SmallCodesizeStruct
2323
}
2424

25+
struct EmptyStruct {}
26+
struct Pair<T, U> {
27+
var t: T
28+
var u: U
29+
}
30+
2531
///////////
2632
// Tests //
2733
///////////
@@ -492,3 +498,23 @@ bb3:
492498
%11 = tuple ()
493499
return %11 : $()
494500
}
501+
502+
// CHECK-LABEL: sil @load_from_uninitialized_empty : {{.*}} {
503+
// CHECK: [[V_3_0:%[^,]+]] = struct $EmptyStruct
504+
// CHECK: [[V_3_1:%[^,]+]] = struct $EmptyStruct
505+
// CHECK: [[V_2_0:%[^,]+]] = struct $Pair{{.*}} ([[V_3_0]]{{.*}}, [[V_3_1]]
506+
// CHECK: [[V_2_1:%[^,]+]] = struct $EmptyStruct ()
507+
// CHECK: [[V_1_0:%[^,]+]] = struct $Pair{{.*}} ([[V_2_0]]{{.*}}, [[V_2_1]]
508+
// CHECK: [[V_2_2:%[^,]+]] = struct $EmptyStruct
509+
// CHECK: [[V_2_3:%[^,]+]] = struct $EmptyStruct
510+
// CHECK: [[V_1_1:%[^,]+]] = tuple ([[V_2_2]]{{.*}}, [[V_2_3]]
511+
// CHECK: [[V_1_2:%[^,]+]] = struct $EmptyStruct
512+
// CHECK: [[V_0:%[^,]+]] = tuple ([[V_1_0]]{{.*}}, [[V_1_1]]{{.*}}, [[V_1_2]]{{.*}})
513+
// CHECK: return [[V_0]]
514+
// CHECK-LABEL: } // end sil function 'load_from_uninitialized_empty'
515+
sil @load_from_uninitialized_empty : $@convention(thin) () -> (Pair<Pair<EmptyStruct, EmptyStruct>, EmptyStruct>, (EmptyStruct, EmptyStruct), EmptyStruct) {
516+
%addr = alloc_stack $(Pair<Pair<EmptyStruct, EmptyStruct>, EmptyStruct>, (EmptyStruct, EmptyStruct), EmptyStruct)
517+
%value = load %addr : $*(Pair<Pair<EmptyStruct, EmptyStruct>, EmptyStruct>, (EmptyStruct, EmptyStruct), EmptyStruct)
518+
dealloc_stack %addr : $*(Pair<Pair<EmptyStruct, EmptyStruct>, EmptyStruct>, (EmptyStruct, EmptyStruct), EmptyStruct)
519+
return %value : $(Pair<Pair<EmptyStruct, EmptyStruct>, EmptyStruct>, (EmptyStruct, EmptyStruct), EmptyStruct)
520+
}

0 commit comments

Comments
 (0)