Skip to content

Commit 1331ac5

Browse files
authored
Merge pull request swiftlang#30718 from eeckstein/loop-rotate
LoopRotate: limit the size of the block to be duplicated.
2 parents 26357ee + 2876194 commit 1331ac5

File tree

2 files changed

+104
-24
lines changed

2 files changed

+104
-24
lines changed

lib/SILOptimizer/LoopTransforms/LoopRotate.cpp

+12-8
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,20 @@
2525
#include "swift/SILOptimizer/Utils/CFGOptUtils.h"
2626
#include "swift/SILOptimizer/Utils/LoopUtils.h"
2727
#include "swift/SILOptimizer/Utils/SILSSAUpdater.h"
28+
#include "swift/SILOptimizer/Utils/SILInliner.h"
2829

2930
#include "llvm/Support/Debug.h"
3031
#include "llvm/Support/CommandLine.h"
3132

3233
using namespace swift;
3334

34-
static llvm::cl::opt<bool> ShouldRotate("sil-looprotate",
35-
llvm::cl::init(true));
35+
/// The size limit for the loop block to duplicate.
36+
///
37+
/// Larger blocks will not be duplicated to avoid too much code size increase.
38+
/// It's very seldom that the default value of 20 is exceeded (< 0.3% of all
39+
/// loops in the swift benchmarks).
40+
static llvm::cl::opt<int> LoopRotateSizeLimit("looprotate-size-limit",
41+
llvm::cl::init(20));
3642

3743
/// Check whether all operands are loop invariant.
3844
static bool
@@ -59,6 +65,7 @@ canDuplicateOrMoveToPreheader(SILLoop *loop, SILBasicBlock *preheader,
5965
SILBasicBlock *bb,
6066
SmallVectorImpl<SILInstruction *> &moves) {
6167
llvm::DenseSet<SILInstruction *> invariants;
68+
int cost = 0;
6269
for (auto &instRef : *bb) {
6370
auto *inst = &instRef;
6471
if (auto *MI = dyn_cast<MethodInst>(inst)) {
@@ -92,10 +99,12 @@ canDuplicateOrMoveToPreheader(SILLoop *loop, SILBasicBlock *preheader,
9299
hasLoopInvariantOperands(inst, loop, invariants)) {
93100
moves.push_back(inst);
94101
invariants.insert(inst);
102+
} else {
103+
cost += (int)instructionInlineCost(instRef);
95104
}
96105
}
97106

98-
return true;
107+
return cost < LoopRotateSizeLimit;
99108
}
100109

101110
static void mapOperands(SILInstruction *inst,
@@ -440,11 +449,6 @@ class LoopRotation : public SILFunctionTransform {
440449
LLVM_DEBUG(llvm::dbgs() << "No loops in " << f->getName() << "\n");
441450
return;
442451
}
443-
if (!ShouldRotate) {
444-
LLVM_DEBUG(llvm::dbgs()
445-
<< "Skipping loop rotation in " << f->getName() << "\n");
446-
return;
447-
}
448452
LLVM_DEBUG(llvm::dbgs() << "Rotating loops in " << f->getName() << "\n");
449453
bool shouldVerify = getOptions().VerifyAll;
450454

test/SILOptimizer/looprotate.sil

+92-16
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,6 @@ sil_stage canonical
88
import Builtin
99
import Swift
1010

11-
// CHECK-LABEL: looprotate
12-
// CHECK: bb0(%0 : $Int32, %1 : $Bar):
13-
// CHECK: class_method
14-
// CHECK: cond_br {{.*}}, bb3({{.*}} : $Builtin.Int32), bb1
15-
16-
// CHECK: bb1:
17-
// CHECK: br bb2({{.*}} : $Builtin.Int32, {{.*}} : $Builtin.Int32, {{.*}}: $Int32)
18-
19-
// CHECK: bb2({{.*}}: $Builtin.Int32, {{.*}} : $Builtin.Int32, {{.*}} : $Int32):
20-
// CHECK: class_method
21-
// CHECK: cond_br {{%.*}}, bb3({{.*}} : $Builtin.Int32), bb2({{.*}} : $Builtin.Int32, {{.*}} : $Builtin.Int32, {{.*}} : $Int32)
22-
23-
// CHECK: bb3({{.*}} : $Builtin.Int32):
24-
// CHECK: [[STRUCT:%.*]] = struct $Int32 ({{%.*}} : $Builtin.Int32)
25-
// CHECK: return [[STRUCT]] : $Int32
26-
2711
protocol P {
2812
func boo() -> Int64
2913
}
@@ -44,6 +28,24 @@ sil_vtable Bar {
4428
#Bar.foo_objc: @_TFC4main3Bar3foofS0_FT_T_
4529
}
4630

31+
// CHECK-LABEL: looprotate
32+
// CHECK: bb0(%0 : $Int32, %1 : $Bar):
33+
// CHECK: class_method
34+
// CHECK: apply
35+
// CHECK: cond_br {{.*}}, bb3({{.*}} : $Builtin.Int32), bb1
36+
37+
// CHECK: bb1:
38+
// CHECK: br bb2({{.*}} : $Builtin.Int32, {{.*}} : $Builtin.Int32, {{.*}}: $Int32)
39+
40+
// CHECK: bb2({{.*}}: $Builtin.Int32, {{.*}} : $Builtin.Int32, {{.*}} : $Int32):
41+
// CHECK: class_method
42+
// CHECK: apply
43+
// CHECK: cond_br {{%.*}}, bb3({{.*}} : $Builtin.Int32), bb2({{.*}} : $Builtin.Int32, {{.*}} : $Builtin.Int32, {{.*}} : $Int32)
44+
45+
// CHECK: bb3({{.*}} : $Builtin.Int32):
46+
// CHECK: [[STRUCT:%.*]] = struct $Int32 ({{%.*}} : $Builtin.Int32)
47+
// CHECK: return [[STRUCT]] : $Int32
48+
// CHECK: } // end sil function 'looprotate'
4749
sil @looprotate : $@convention(thin) (Int32, @owned Bar) -> Int32 {
4850
bb0(%0 : $Int32, %25: $Bar):
4951
%1 = struct_extract %0 : $Int32, #Int32._value
@@ -77,6 +79,80 @@ bb3:
7779
return %23 : $Int32
7880
}
7981

82+
// CHECK-LABEL: dont_duplicate_large_block
83+
// CHECK: bb0(%0 : $Int32, %1 : $Bar):
84+
// CHECK-NOT: class_method
85+
// CHECK-NOT: apply
86+
// CHECK: br bb1
87+
88+
// CHECK: bb1({{.*}}):
89+
// CHECK: class_method
90+
// CHECK: apply
91+
// CHECK: cond_br
92+
93+
// CHECK: bb2:
94+
// CHECK: br bb1
95+
96+
// CHECK: bb3:
97+
// CHECK: return
98+
// CHECK: } // end sil function 'dont_duplicate_large_block'
99+
sil @dont_duplicate_large_block : $@convention(thin) (Int32, @owned Bar) -> Int32 {
100+
bb0(%0 : $Int32, %25: $Bar):
101+
%1 = struct_extract %0 : $Int32, #Int32._value
102+
%2 = integer_literal $Builtin.Int32, 0
103+
%30 = alloc_box $<τ_0_0> { var τ_0_0 } <Bool>
104+
%30a = project_box %30 : $<τ_0_0> { var τ_0_0 } <Bool>, 0
105+
br bb1(%1 : $Builtin.Int32, %2 : $Builtin.Int32, %25: $Bar, %30 : $<τ_0_0> { var τ_0_0 } <Bool>, %30a : $*Bool)
106+
107+
bb1(%4 : $Builtin.Int32, %5 : $Builtin.Int32, %26: $Bar, %31 : $<τ_0_0> { var τ_0_0 } <Bool>, %32 : $*Bool):
108+
%24 = class_method %26 : $Bar, #Bar.foo : (Bar) -> () -> (), $@convention(method) (@guaranteed Bar) -> () // user: %6
109+
%27 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> ()
110+
%28 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> ()
111+
%29 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> ()
112+
%33 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> ()
113+
%34 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> ()
114+
%35 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> ()
115+
%36 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> ()
116+
%37 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> ()
117+
%38 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> ()
118+
%39 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> ()
119+
%40 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> ()
120+
%41 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> ()
121+
%42 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> ()
122+
%43 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> ()
123+
%44 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> ()
124+
%45 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> ()
125+
%46 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> ()
126+
%47 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> ()
127+
%48 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> ()
128+
%49 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> ()
129+
%50 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> ()
130+
%51 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> ()
131+
%52 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> ()
132+
%53 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> ()
133+
%54 = apply %24(%25) : $@convention(method) (@guaranteed Bar) -> ()
134+
%6 = struct $Int32 (%5 : $Builtin.Int32)
135+
%8 = builtin "cmp_eq_Word"(%5 : $Builtin.Int32, %1 : $Builtin.Int32) : $Builtin.Int1
136+
cond_br %8, bb3, bb2
137+
138+
bb2:
139+
%10 = integer_literal $Builtin.Int32, 1
140+
%12 = integer_literal $Builtin.Int1, -1
141+
%13 = builtin "sadd_with_overflow_Word"(%5 : $Builtin.Int32, %10 : $Builtin.Int32, %12 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1)
142+
%14 = tuple_extract %13 : $(Builtin.Int32, Builtin.Int1), 0
143+
%15 = enum $Optional<Int32>, #Optional.some!enumelt, %6 : $Int32
144+
%16 = unchecked_enum_data %15 : $Optional<Int32>, #Optional.some!enumelt
145+
%17 = struct_extract %16 : $Int32, #Int32._value
146+
%19 = integer_literal $Builtin.Int1, -1
147+
%20 = builtin "sadd_with_overflow_Word"(%4 : $Builtin.Int32, %17 : $Builtin.Int32, %19 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1)
148+
%21 = tuple_extract %20 : $(Builtin.Int32, Builtin.Int1), 0
149+
br bb1(%21 : $Builtin.Int32, %14 : $Builtin.Int32, %26: $Bar, %31 : $<τ_0_0> { var τ_0_0 } <Bool>, %32 : $*Bool)
150+
151+
bb3:
152+
%23 = struct $Int32 (%4 : $Builtin.Int32)
153+
return %23 : $Int32
154+
}
155+
80156
// This example illustrates the problem with using ValueUseIterators.
81157
// As part of updating SSA form we will introduce a phi node argument to the
82158
// branch to bb2. This means we change "cond_br %8, bb3(%4 : $Builtin.Int32),

0 commit comments

Comments
 (0)