Skip to content

Commit 4065cdd

Browse files
authored
Merge pull request #10586 from eeckstein/fix-arccm-4.0
ARCCodeMotion: fix two problems in release hoisting:
2 parents 1c34375 + 821bd3a commit 4065cdd

File tree

2 files changed

+126
-7
lines changed

2 files changed

+126
-7
lines changed

lib/SILOptimizer/Transforms/ARCCodeMotion.cpp

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -618,13 +618,16 @@ class ReleaseBlockState : public BlockState {
618618
}
619619

620620
/// constructor.
621-
ReleaseBlockState(bool IsExit, unsigned size, bool MultiIteration) {
621+
///
622+
/// If \p InitOptimistic is true, the block in-bits are initialized to 1
623+
/// which enables optimistic data flow evaluation.
624+
ReleaseBlockState(bool InitOptimistic, unsigned size) {
622625
// backward data flow.
623626
// Initialize to true if we are running optimistic data flow, i.e.
624627
// MultiIteration is true.
625-
BBSetIn.resize(size, MultiIteration);
628+
BBSetIn.resize(size, InitOptimistic);
626629
BBSetOut.resize(size, false);
627-
BBMaxSet.resize(size, !IsExit && MultiIteration);
630+
BBMaxSet.resize(size, InitOptimistic);
628631

629632
// Genset and Killset are initially empty.
630633
BBGenSet.resize(size, false);
@@ -735,6 +738,17 @@ bool ReleaseCodeMotionContext::requireIteration() {
735738
}
736739

737740
void ReleaseCodeMotionContext::initializeCodeMotionDataFlow() {
741+
// All blocks which are initialized with 1-bits. These are all blocks which
742+
// eventually reach the function exit (return, throw), excluding the
743+
// function exit blocks themselves.
744+
// Optimistic initialization enables moving releases across loops. On the
745+
// other hand, blocks, which never reach the function exit, e.g. infinite
746+
// loop blocks, must be excluded. Otherwise we would end up inserting
747+
// completely unrelated release instructions in such blocks.
748+
llvm::SmallPtrSet<SILBasicBlock *, 32> BlocksInitOptimistically;
749+
750+
llvm::SmallVector<SILBasicBlock *, 32> Worklist;
751+
738752
// Find all the RC roots in the function.
739753
for (auto &BB : *F) {
740754
for (auto &II : BB) {
@@ -750,13 +764,25 @@ void ReleaseCodeMotionContext::initializeCodeMotionDataFlow() {
750764
RCRootIndex[Root] = RCRootVault.size();
751765
RCRootVault.insert(Root);
752766
}
767+
if (MultiIteration && BB.getTerminator()->isFunctionExiting())
768+
Worklist.push_back(&BB);
769+
}
770+
771+
// Find all blocks from which there is a path to the function exit.
772+
// Note: the Worklist is empty if we are not in MultiIteration mode.
773+
while (!Worklist.empty()) {
774+
SILBasicBlock *BB = Worklist.pop_back_val();
775+
for (SILBasicBlock *Pred : BB->getPredecessorBlocks()) {
776+
if (BlocksInitOptimistically.insert(Pred).second)
777+
Worklist.push_back(Pred);
778+
}
753779
}
754780

755781
// Initialize all the data flow bit vector for all basic blocks.
756782
for (auto &BB : *F) {
757783
BlockStates[&BB] = new (BPA.Allocate())
758-
ReleaseBlockState(BB.getTerminator()->isFunctionExiting(),
759-
RCRootVault.size(), MultiIteration);
784+
ReleaseBlockState(BlocksInitOptimistically.count(&BB) != 0,
785+
RCRootVault.size());
760786
}
761787
}
762788

@@ -1038,17 +1064,22 @@ class ARCCodeMotion : public SILFunctionTransform {
10381064
return;
10391065

10401066
DEBUG(llvm::dbgs() << "*** ARCCM on function: " << F->getName() << " ***\n");
1067+
1068+
PostOrderAnalysis *POA = PM->getAnalysis<PostOrderAnalysis>();
1069+
10411070
// Split all critical edges.
10421071
//
10431072
// TODO: maybe we can do this lazily or maybe we should disallow SIL passes
10441073
// to create critical edges.
10451074
bool EdgeChanged = splitAllCriticalEdges(*F, false, nullptr, nullptr);
1075+
if (EdgeChanged)
1076+
POA->invalidateFunction(F);
10461077

1047-
llvm::SpecificBumpPtrAllocator<BlockState> BPA;
1048-
auto *PO = PM->getAnalysis<PostOrderAnalysis>()->get(F);
1078+
auto *PO = POA->get(F);
10491079
auto *AA = PM->getAnalysis<AliasAnalysis>();
10501080
auto *RCFI = PM->getAnalysis<RCIdentityAnalysis>()->get(F);
10511081

1082+
llvm::SpecificBumpPtrAllocator<BlockState> BPA;
10521083
bool InstChanged = false;
10531084
if (Kind == Release) {
10541085
// TODO: we should consider Throw block as well, or better we should

test/SILOptimizer/retain_release_code_motion.sil

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,3 +443,91 @@ bb3:
443443
%5 = tuple()
444444
return %5 : $()
445445
}
446+
447+
// CHECK-LABEL: sil @move_retain_over_loop
448+
// CHECK: bb0({{.*}}):
449+
// CHECK-NEXT: br bb1
450+
// CHECK: bb1:
451+
// CHECK-NEXT: cond_br
452+
// CHECK: bb2:
453+
// CHECK: strong_retain
454+
// CHECK: apply
455+
// CHECK: strong_release
456+
// CHECK: return
457+
sil @move_retain_over_loop : $@convention(thin) (Builtin.NativeObject) -> () {
458+
bb0(%0 : $Builtin.NativeObject):
459+
strong_retain %0 : $Builtin.NativeObject
460+
br bb1
461+
462+
bb1:
463+
cond_br undef, bb1, bb2
464+
465+
bb2:
466+
%2 = function_ref @blocker : $@convention(thin) () -> ()
467+
apply %2() : $@convention(thin) () -> ()
468+
strong_release %0 : $Builtin.NativeObject
469+
%1 = tuple()
470+
return %1 : $()
471+
}
472+
473+
// CHECK-LABEL: sil @move_release_over_loop
474+
// CHECK: bb0{{.*}}:
475+
// CHECK: strong_retain
476+
// CHECK: apply
477+
// CHECK: strong_release
478+
// CHECK: br bb1
479+
// CHECK: bb1:
480+
// CHECK-NEXT: cond_br
481+
// CHECK: bb2:
482+
// CHECK-NEXT: br bb1
483+
// CHECK: bb3:
484+
// CHECK-NEXT: tuple
485+
// CHECK-NEXT: return
486+
sil @move_release_over_loop : $@convention(thin) (Builtin.NativeObject) -> () {
487+
bb0(%0 : $Builtin.NativeObject):
488+
strong_retain %0 : $Builtin.NativeObject
489+
%2 = function_ref @blocker : $@convention(thin) () -> ()
490+
apply %2() : $@convention(thin) () -> ()
491+
br bb1
492+
493+
bb1:
494+
cond_br undef, bb1, bb2
495+
496+
bb2:
497+
strong_release %0 : $Builtin.NativeObject
498+
%1 = tuple()
499+
return %1 : $()
500+
}
501+
502+
// CHECK-LABEL: sil @handle_infinite_loop
503+
// CHECK: bb0{{.*}}:
504+
// CHECK-NEXT: cond_br
505+
// CHECK: bb1:
506+
// CHECK-NOT: {{(retain|release)}}
507+
// CHECK: apply
508+
// CHECK-NEXT: br bb2
509+
// CHECK: bb2:
510+
// CHECK-NEXT: br bb2
511+
// CHECK: bb3:
512+
// CHECK: strong_retain
513+
// CHECK: strong_release
514+
// CHECK: return
515+
sil @handle_infinite_loop : $@convention(thin) (@inout Builtin.NativeObject) -> () {
516+
bb0(%a : $*Builtin.NativeObject):
517+
cond_br undef, bb1, bb3
518+
519+
bb1:
520+
%2 = function_ref @blocker : $@convention(thin) () -> ()
521+
apply %2() : $@convention(thin) () -> ()
522+
br bb2
523+
524+
bb2:
525+
br bb2
526+
527+
bb3:
528+
%0 = load %a : $*Builtin.NativeObject
529+
strong_retain %0 : $Builtin.NativeObject
530+
strong_release %0 : $Builtin.NativeObject
531+
%1 = tuple()
532+
return %1 : $()
533+
}

0 commit comments

Comments
 (0)