Skip to content

Commit 69aaeb6

Browse files
committed
[AddressLowering] Move into secondary use.
If a value's storage is a use projection out of some use, AddressLowering correctly does not move into that storage when initializing the composing use of the operand for the user into whose storage it projects. Previously, however, it was only checked that the value's storage was a use projection at all. When initializing the composing use of the operand of some _other_ user of the value (i.e. a user into whose storage it does _not_ project), the result was a missing move. Here, this is fixed by only skipping the move when the value's storage is a projection _and_ it projects into the storage of the user of the operand at hand.
1 parent 09511a7 commit 69aaeb6

File tree

2 files changed

+52
-2
lines changed

2 files changed

+52
-2
lines changed

lib/SILOptimizer/Mandatory/AddressLowering.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1747,8 +1747,16 @@ void AddressMaterialization::initializeComposingUse(Operand *operand) {
17471747
ValueStorage &storage = pass.valueStorageMap.getStorage(def);
17481748
assert(storage.isRewritten && "Source value should be rewritten");
17491749

1750-
if (storage.isUseProjection)
1751-
return;
1750+
// If the operand projects into one of its users and this user is that one
1751+
// into which it projects, then the memory was already initialized. If it's
1752+
// another user, however, that memory is _not_initialized.
1753+
if (storage.isUseProjection) {
1754+
auto *aggregate = dyn_cast<SingleValueInstruction>(operand->getUser());
1755+
if (aggregate && (storage.projectedStorageID ==
1756+
pass.valueStorageMap.getOrdinal(aggregate))) {
1757+
return;
1758+
}
1759+
}
17521760

17531761
auto destAddr =
17541762
materializeProjectionIntoUse(operand, /*intoPhiOperand*/ false);

test/SILOptimizer/address_lowering.sil

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ struct Pair<T> {
6060
var y : T
6161
}
6262

63+
struct Box<T> {
64+
var t: T
65+
}
66+
6367
struct Box2<T, U> {
6468
var v1: T
6569
var v2: U
@@ -2712,6 +2716,44 @@ entry:
27122716
return %retval : $()
27132717
}
27142718

2719+
// CHECK-LABEL: sil [ossa] @test_struct_1_two_use_projections : {{.*}} {
2720+
// CHECK: [[S_ADDR:%[^,]+]] = alloc_stack $Box<T>
2721+
// CHECK: [[S2_ADDR:%[^,]+]] = alloc_stack $Box<T>
2722+
// CHECK: [[S_FIELD_ADDR:%[^,]+]] = struct_element_addr [[S_ADDR]] : $*Box<T>, #Box.t
2723+
// CHECK: apply undef<T>([[S_FIELD_ADDR]])
2724+
// CHECK: cond_br undef, [[LEFT:bb[0-9]+]], [[RIGHT:bb[0-9]+]]
2725+
// CHECK: [[RIGHT]]:
2726+
// CHECK: destroy_addr [[S_ADDR]] : $*Box<T>
2727+
// CHECK: br [[EXIT:bb[0-9]+]]
2728+
// CHECK: [[LEFT]]:
2729+
// CHECK: [[S2_FIELD_ADDR:%[^,]+]] = struct_element_addr [[S2_ADDR]] : $*Box<T>, #Box.t
2730+
// CHECK: copy_addr [take] [[S_FIELD_ADDR]] to [init] [[S2_FIELD_ADDR]]
2731+
// CHECK: destroy_addr [[S2_ADDR]] : $*Box<T>
2732+
// CHECK: br [[EXIT]]
2733+
// CHECK: [[EXIT]]:
2734+
// CHECK: dealloc_stack [[S2_ADDR]] : $*Box<T>
2735+
// CHECK: dealloc_stack [[S_ADDR]] : $*Box<T>
2736+
// CHECK-LABEL: } // end sil function 'test_struct_1_two_use_projections'
2737+
sil [ossa] @test_struct_1_two_use_projections : $@convention(thin) <T> () -> () {
2738+
entry:
2739+
%box = apply undef<T>() : $@convention(thin) <T> () -> (@out T)
2740+
cond_br undef, left, right
2741+
2742+
left:
2743+
%s2 = struct $Box<T>(%box : $T)
2744+
destroy_value %s2 : $Box<T>
2745+
br exit
2746+
2747+
right:
2748+
%s = struct $Box<T>(%box : $T)
2749+
destroy_value %s : $Box<T>
2750+
br exit
2751+
2752+
exit:
2753+
%retval = tuple ()
2754+
return %retval : $()
2755+
}
2756+
27152757
// CHECK-LABEL: sil [ossa] @test_tuple_pack_extract : {{.*}} {
27162758
// CHECK: bb0([[TUPLE_PACK_ADDR:%[^,]+]] :
27172759
// CHECK: [[INDEX:%[^,]+]] = dynamic_pack_index

0 commit comments

Comments
 (0)