Skip to content

Commit c55753b

Browse files
Merge pull request #83590 from aschwaighofer/largetypes_reg2mem_single_user_peephole
LargeTypesReg2Mem: Peephole load followed by single user to reuse the load's address
2 parents 5755fb2 + 1e8e3b8 commit c55753b

File tree

3 files changed

+83
-36
lines changed

3 files changed

+83
-36
lines changed

lib/IRGen/LoadableByAddress.cpp

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3927,6 +3927,13 @@ void AddressAssignment::finish(DominanceInfo *dominance,
39273927
StackNesting::fixNesting(&currFn);
39283928
}
39293929

3930+
static bool isSoleUserOf(LoadInst *load, SILInstruction *next) {
3931+
if (!load->hasOneUse())
3932+
return false;
3933+
if(load->getSingleUse()->getUser() != next)
3934+
return false;
3935+
return true;
3936+
}
39303937
namespace {
39313938
class AssignAddressToDef : SILInstructionVisitor<AssignAddressToDef> {
39323939
friend SILVisitorBase<AssignAddressToDef>;
@@ -4036,6 +4043,14 @@ class AssignAddressToDef : SILInstructionVisitor<AssignAddressToDef> {
40364043
}
40374044

40384045
void visitLoadInst(LoadInst *load) {
4046+
// Forward the address of the load if its sole user immediately follows the
4047+
// load instructions.
4048+
if (isSoleUserOf(load, &*++load->getIterator())) {
4049+
assignment.markForDeletion(load);
4050+
assignment.mapValueToAddress(origValue, load->getOperand());
4051+
return;
4052+
}
4053+
40394054
auto builder = assignment.getBuilder(load->getIterator());
40404055
auto addr = assignment.createAllocStack(load->getType());
40414056

@@ -4464,22 +4479,35 @@ class RewriteUser : SILInstructionVisitor<RewriteUser> {
44644479

44654480
void visitSwitchEnumInst(SwitchEnumInst *sw) {
44664481
auto opdAddr = assignment.getAddressForValue(sw->getOperand());
4467-
{
4482+
// UncheckedTakeEnumDataAddr is destructive. If we have a used switch target
4483+
// block argument we need to provide for a destructible location for the
4484+
// UncheckedTakeEnumDataAddr.
4485+
SILValue destructibleAddress;
4486+
auto initDestructibleAddress = [&] () -> void{
4487+
if (destructibleAddress)
4488+
return;
44684489
auto addr = assignment.createAllocStack(sw->getOperand()->getType());
44694490
// UncheckedTakeEnumDataAddr is destructive.
44704491
// So we need to copy to keep the original address location valid.
44714492
auto builder = assignment.getBuilder(sw->getIterator());
44724493
builder.createCopyAddr(sw->getLoc(), opdAddr, addr, IsTake,
44734494
IsInitialization);
4474-
opdAddr = addr;
4475-
}
4495+
destructibleAddress = addr;
4496+
};
44764497

44774498
auto loc = sw->getLoc();
44784499

44794500
auto rewriteCase = [&](EnumElementDecl *caseDecl, SILBasicBlock *caseBB) {
44804501
// Nothing to do for unused case payloads.
4481-
if (caseBB->getArguments().size() == 0)
4502+
if (caseBB->getArguments().size() == 0 ||
4503+
caseBB->getArguments()[0]->use_empty()) {
4504+
if (caseBB->getArguments().size()) {
4505+
assignment.markBlockArgumentForDeletion(caseBB);
4506+
}
44824507
return;
4508+
}
4509+
4510+
initDestructibleAddress();
44834511

44844512
assert(caseBB->getArguments().size() == 1);
44854513
SILArgument *caseArg = caseBB->getArgument(0);
@@ -4488,8 +4516,10 @@ class RewriteUser : SILInstructionVisitor<RewriteUser> {
44884516

44894517
SILBuilder caseBuilder = assignment.getBuilder(caseBB->begin());
44904518
auto *caseAddr =
4491-
caseBuilder.createUncheckedTakeEnumDataAddr(loc, opdAddr, caseDecl,
4492-
caseArg->getType().getAddressType());
4519+
caseBuilder.createUncheckedTakeEnumDataAddr(loc, destructibleAddress,
4520+
caseDecl,
4521+
caseArg->getType().getAddressType());
4522+
44934523
if (assignment.isLargeLoadableType(caseArg->getType())) {
44944524
assignment.mapValueToAddress(caseArg, caseAddr);
44954525
assignment.markBlockArgumentForDeletion(caseBB);

test/IRGen/big_types.sil

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,17 +80,14 @@ unwind:
8080
// CHECK-LABEL: sil @use_yield_big : $@convention(thin) () -> () {
8181
// CHECK: bb0:
8282
// CHECK-NEXT: [[TEMP:%.*]] = alloc_stack $BigStruct
83-
// CHECK-NEXT: [[TEMP2:%.*]] = alloc_stack $BigStruct
8483
// CHECK-NEXT: // function_ref
8584
// CHECK-NEXT: [[CORO:%.*]] = function_ref @test_yield_big : $@yield_once @convention(thin) () -> @yields @in_guaranteed BigStruct
8685
// CHECK-NEXT: ([[ADDR:%.*]], [[TOKEN:%.*]]) = begin_apply [[CORO]]()
8786
// CHECK-NEXT: copy_addr [take] [[ADDR]] to [init] [[TEMP]] : $*BigStruct
88-
// CHECK-NEXT: copy_addr [take] [[TEMP]] to [init] [[TEMP2]] : $*BigStruct
8987
// CHECK-NEXT: // function_ref
9088
// CHECK-NEXT: [[USE:%.*]] = function_ref @use_big_struct : $@convention(thin) (@in_guaranteed BigStruct) -> ()
91-
// CHECK-NEXT: apply [[USE]]([[TEMP2]])
89+
// CHECK-NEXT: apply [[USE]]([[TEMP]])
9290
// CHECK-NEXT: [[RET:%.*]] = end_apply [[TOKEN]] as $()
93-
// CHECK-NEXT: dealloc_stack [[TEMP2]] : $*BigStruct
9491
// CHECK-NEXT: dealloc_stack [[TEMP]] : $*BigStruct
9592
// CHECK-NEXT: return [[RET]] : $()
9693
sil @use_yield_big : $@convention(thin) () -> () {

test/IRGen/loadable_by_address_reg2mem.sil

Lines changed: 46 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,12 @@ struct Small {
6666
// CHECK: bb0:
6767
// CHECK: %0 = alloc_stack $Optional<X>
6868
// CHECK: %1 = alloc_stack $X
69-
// CHECK: %2 = alloc_stack $X
70-
// CHECK: %3 = alloc_stack $Optional<X>
71-
// CHECK: copy_addr [take] %2 to [init] %1 : $*X
72-
// CHECK: %5 = init_enum_data_addr %0 : $*Optional<X>, #Optional.some!enumelt
73-
// CHECK: copy_addr [take] %1 to [init] %5 : $*X
69+
// CHECK: %2 = alloc_stack $Optional<X>
70+
// CHECK: %3 = init_enum_data_addr %0 : $*Optional<X>, #Optional.some!enumelt
71+
// CHECK: copy_addr [take] %1 to [init] %3 : $*X
7472
// CHECK: inject_enum_addr %0 : $*Optional<X>, #Optional.some!enumelt
75-
// CHECK: copy_addr [take] %0 to [init] %3 : $*Optional<X>
76-
// CHECK: dealloc_stack %3 : $*Optional<X>
77-
// CHECK: dealloc_stack %2 : $*X
73+
// CHECK: copy_addr [take] %0 to [init] %2 : $*Optional<X>
74+
// CHECK: dealloc_stack %2 : $*Optional<X>
7875
// CHECK: dealloc_stack %1 : $*X
7976
// CHECK: dealloc_stack %0 : $*Optional<X>
8077
// CHECK: } // end sil function 'test1'
@@ -92,25 +89,29 @@ bb0:
9289
return %t : $()
9390
}
9491

92+
sil @useX : $@convention(thin) (X) -> ()
93+
9594
// CHECK: sil @test2 : $@convention(thin) () -> () {
9695
// CHECK: bb0:
9796
// CHECK: %0 = alloc_stack $Optional<X>
98-
// CHECK: %1 = alloc_stack $Optional<X>
97+
// CHECK: %1 = alloc_stack $X
9998
// CHECK: %2 = alloc_stack $Optional<X>
100-
// CHECK: copy_addr [take] %2 to [init] %1 : $*Optional<X>
101-
// CHECK: copy_addr [take] %1 to [init] %0 : $*Optional<X>
102-
// CHECK: switch_enum_addr %0 : $*Optional<X>, case #Optional.some!enumelt: bb1, case #Optional.none!enumelt: bb2
99+
// CHECK: copy_addr [take] %2 to [init] %0 : $*Optional<X>
100+
// CHECK: switch_enum_addr %2 : $*Optional<X>, case #Optional.some!enumelt: bb1, case #Optional.none!enumelt: bb2
103101

104102
// CHECK: bb1:
105-
// CHECK: %6 = unchecked_take_enum_data_addr %0 : $*Optional<X>, #Optional.some!enumelt
103+
// CHECK: %5 = unchecked_take_enum_data_addr %0 : $*Optional<X>, #Optional.some!enumelt
104+
// CHECK: copy_addr [take] %5 to [init] %1 : $*X
105+
// CHECK: %7 = function_ref @useX : $@convention(thin) (@in_guaranteed X) -> ()
106+
// CHECK: %8 = apply %7(%1) : $@convention(thin) (@in_guaranteed X) -> ()
106107
// CHECK: br bb3
107108

108109
// CHECK: bb2:
109110
// CHECK: br bb3
110111

111112
// CHECK: bb3:
112113
// CHECK: dealloc_stack %2 : $*Optional<X>
113-
// CHECK: dealloc_stack %1 : $*Optional<X>
114+
// CHECK: dealloc_stack %1 : $*X
114115
// CHECK: dealloc_stack %0 : $*Optional<X>
115116
// CHECK: } // end sil function 'test2'
116117

@@ -121,6 +122,8 @@ bb0:
121122
switch_enum %2 : $Optional<X>, case #Optional.some!enumelt: bb1, case #Optional.none!enumelt: bb2
122123

123124
bb1(%3: $X):
125+
%f = function_ref @useX : $@convention(thin) (X) -> ()
126+
apply %f(%3) : $@convention(thin) (X) -> ()
124127
br bb3
125128

126129
bb2:
@@ -184,11 +187,9 @@ bb0:
184187

185188
// CHECK: sil @test5 : $@convention(thin) (@in (X, X)) -> () {
186189
// CHECK: bb0(%0 : $*(X, X)):
187-
// CHECK: %1 = alloc_stack $(X, X)
188-
// CHECK: %2 = alloc_stack $X
189-
// CHECK: copy_addr [take] %0 to [init] %1 : $*(X, X)
190-
// CHECK: %4 = tuple_element_addr %1 : $*(X, X), 1
191-
// CHECK: copy_addr [take] %4 to [init] %2 : $*X
190+
// CHECK: %1 = alloc_stack $X
191+
// CHECK: %2 = tuple_element_addr %0 : $*(X, X), 1
192+
// CHECK: copy_addr [take] %2 to [init] %1 : $*X
192193
// CHECK: } // end sil function 'test5'
193194

194195
sil @test5 : $@convention(thin) (@in (X, X)) -> () {
@@ -231,11 +232,9 @@ bb0:
231232

232233
// CHECK: sil @test7 : $@convention(thin) (@in Y) -> () {
233234
// CHECK: bb0(%0 : $*Y):
234-
// CHECK: %1 = alloc_stack $Y
235-
// CHECK: %2 = alloc_stack $X
236-
// CHECK: copy_addr [take] %0 to [init] %1 : $*Y
237-
// CHECK: %4 = struct_element_addr %1 : $*Y, #Y.y1
238-
// CHECK: copy_addr [take] %4 to [init] %2 : $*X
235+
// CHECK: %1 = alloc_stack $X
236+
// CHECK: %2 = struct_element_addr %0 : $*Y, #Y.y1
237+
// CHECK: copy_addr [take] %2 to [init] %1 : $*X
239238
// CHECK: } // end sil function 'test7'
240239

241240
sil @test7 : $@convention(thin) (@in Y) -> () {
@@ -339,8 +338,8 @@ bb0:
339338
}
340339

341340
// CHECK: sil @test13
342-
// CHECK: [[ADDR:%.*]] = unchecked_addr_cast %1 : $*X to $*Y
343-
// CHECK: copy_addr [take] [[ADDR]] to [init] %2 : $*Y
341+
// CHECK: [[ADDR:%.*]] = unchecked_addr_cast %2 : $*X to $*Y
342+
// CHECK: copy_addr [take] [[ADDR]] to [init] %1 : $*Y
344343
// CHECK: } // end sil function 'test13'
345344
sil @test13 : $@convention(thin) (@in X) -> () {
346345
bb0(%0 : $*X):
@@ -443,3 +442,24 @@ bb0(%0 : $String):
443442
%13 = tuple ()
444443
return %13 : $()
445444
}
445+
446+
sil_global private @global : $Optional<X>
447+
448+
sil @test18: $@convention(thin) () -> () {
449+
bb0:
450+
%0 = global_addr @global : $*Optional<X>
451+
%1 = begin_access [modify] [static] [no_nested_conflict] %0
452+
%2 = load %1
453+
switch_enum %2, case #Optional.some!enumelt: bb2, case #Optional.none!enumelt: bb1
454+
455+
bb1:
456+
%4 = integer_literal $Builtin.Int1, -1
457+
cond_fail %4, "Unexpectedly found nil while unwrapping an Optional value"
458+
unreachable
459+
460+
bb2(%7 : $X):
461+
%8 = unchecked_take_enum_data_addr %1, #Optional.some!enumelt
462+
end_access %1
463+
%13 = tuple ()
464+
return %13 : $()
465+
}

0 commit comments

Comments
 (0)