Skip to content

Commit 097e0e1

Browse files
authored
llvm-reduce: Add pass to sink defs to uses (#170317)
The intent is to reduce live ranges and reduce the impact on later scheduling on the testcase.
1 parent 2a10e91 commit 097e0e1

File tree

7 files changed

+347
-0
lines changed

7 files changed

+347
-0
lines changed
Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
; Test that llvm-reduce can move def instructions down to uses.
2+
;
3+
; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=sink-defs-to-uses --test FileCheck --test-arg --check-prefixes=CHECK,INTERESTING --test-arg %s --test-arg --input-file %s -o %t
4+
; RUN: FileCheck --check-prefixes=CHECK,RESULT %s < %t
5+
6+
declare i32 @leaf()
7+
declare void @func()
8+
declare void @use(i32)
9+
declare void @use0(i32)
10+
declare void @use1(i32)
11+
declare void @use2(i32)
12+
declare i32 @leaf_with_arg(i32)
13+
14+
; CHECK-LABEL: define i32 @sink_leaf_to_ret() {
15+
; INTERESTING: call i32 @leaf()
16+
17+
; RESULT-NEXT: call void @func()
18+
; RESULT-NEXT: %ret = call i32 @leaf()
19+
; RESULT-NEXT: ret i32 %ret
20+
define i32 @sink_leaf_to_ret() {
21+
%ret = call i32 @leaf()
22+
call void @func()
23+
ret i32 %ret
24+
}
25+
26+
; CHECK-LABEL: define i32 @no_sink_leaf_to_ret() {
27+
; INTERESTING: call i32 @leaf()
28+
; INTERESTING: call void @func()
29+
30+
; RESULT: %ret = call i32 @leaf()
31+
; RESULT-NEXT: call void @func()
32+
; RESULT-NEXT: ret i32 %ret
33+
define i32 @no_sink_leaf_to_ret() {
34+
%ret = call i32 @leaf()
35+
call void @func()
36+
ret i32 %ret
37+
}
38+
39+
; CHECK-LABEL: define i32 @sink_across_trivial_block() {
40+
; RESULT: {{^}}entry:
41+
; RESULT-NEXT: br label %ret
42+
; RESULT: {{^}}ret:
43+
; RESULT-NEXT: call void @func
44+
; RESULT-NEXT: %val = call i32 @leaf()
45+
; RESULT-NEXT: ret i32 %val
46+
define i32 @sink_across_trivial_block() {
47+
entry:
48+
%val = call i32 @leaf()
49+
br label %ret
50+
51+
ret:
52+
call void @func()
53+
ret i32 %val
54+
}
55+
56+
; CHECK-LABEL: define i32 @cannot_sink_phi_def(
57+
; INTERESTING: phi i32
58+
59+
; RESULT: {{^}}b:
60+
; RESULT-NEXT: %phi = phi i32
61+
; RESULT-NEXT: call void @func(
62+
; RESULT-NEXT: ret i32 %phi
63+
define i32 @cannot_sink_phi_def(i1 %cond) {
64+
entry:
65+
br i1 %cond, label %a, label %b
66+
67+
a:
68+
br label %b
69+
70+
b:
71+
%phi = phi i32 [ 0, %entry ], [ 1, %a ]
72+
call void @func()
73+
ret i32 %phi
74+
}
75+
76+
; CHECK-LABEL: define i32 @cannot_sink_phi_use(
77+
; INTERESTING: phi i32
78+
define i32 @cannot_sink_phi_use(ptr %arg) {
79+
entry:
80+
call void @func()
81+
br label %loop
82+
83+
loop:
84+
%phi = phi i32 [ 0, %entry ], [ %add, %loop ]
85+
call void @func()
86+
%def0 = call i32 @leaf()
87+
call void @func()
88+
%add = add i32 %phi, 1
89+
%loop.cond = load volatile i1, ptr %arg
90+
br i1 %loop.cond, label %loop, label %exit
91+
92+
exit:
93+
ret i32 %phi
94+
}
95+
96+
; CHECK-LABEL: define i32 @cannot_sink_past_other_use(
97+
; INTERESTING: call i32 @leaf
98+
99+
; RESULT-NEXT: %val = call i32
100+
; RESULT-NEXT: call void @use(i32 %val)
101+
; RESULT-NEXT: ret i32 %val
102+
define i32 @cannot_sink_past_other_use() {
103+
%val = call i32 @leaf()
104+
call void @use(i32 %val)
105+
ret i32 %val
106+
}
107+
108+
; CHECK-LABEL: define void @no_sink_alloca(
109+
; CHECK-NEXT: alloca
110+
; RESULT-NEXT: call void @func
111+
; RESULT-NEXT: store i32
112+
; RESULT-NEXT: ret
113+
define void @no_sink_alloca() {
114+
%alloca = alloca i32
115+
call void @func()
116+
store i32 0, ptr %alloca
117+
ret void
118+
}
119+
120+
; CHECK-LABEL: define i32 @cannot_sink_callbr(
121+
; CHECK: callbr i32
122+
123+
; RESULT: store i32 1
124+
; RESULT-NEXT: ret i32 %load0
125+
126+
; RESULT: store i32 2
127+
; RESULT-NEXT: ret i32 2
128+
129+
; RESULT: store i32 3
130+
; RESULT-NEXT: ret i32 3
131+
define i32 @cannot_sink_callbr(ptr %arg0, ptr %ptr1) {
132+
entry:
133+
%load0 = load i32, ptr %arg0
134+
%callbr = callbr i32 asm "", "=r,r,!i,!i"(i32 %load0)
135+
to label %one [label %two, label %three]
136+
one:
137+
store i32 1, ptr %ptr1
138+
ret i32 %load0
139+
140+
two:
141+
store i32 2, ptr %ptr1
142+
ret i32 2
143+
144+
three:
145+
store i32 3, ptr %ptr1
146+
ret i32 3
147+
}
148+
149+
declare i32 @__gxx_personality_v0(...)
150+
declare i32 @maybe_throwing_callee(i32)
151+
declare void @did_not_throw(i32)
152+
153+
; landingpad must be first in the block, so it cannot be sunk.
154+
; CHECK-LABEL: @cannot_sink_landingpad(
155+
; INTERESTING: landingpad
156+
157+
; RESULT: %landing = landingpad { ptr, i32 }
158+
; RESULT-NEXT: catch ptr
159+
; RESULT-NEXT: call void @func(
160+
; RESULT-NEXT: call void @func(
161+
; RESULT-NEXT: extractvalue { ptr, i32 } %landing, 1
162+
define void @cannot_sink_landingpad(i32 %arg) personality ptr @__gxx_personality_v0 {
163+
bb:
164+
%i0 = invoke i32 @maybe_throwing_callee(i32 %arg)
165+
to label %bb3 unwind label %bb1
166+
167+
bb1: ; preds = %bb
168+
%landing = landingpad { ptr, i32 }
169+
catch ptr null
170+
call void @func()
171+
call void @func()
172+
%extract0 = extractvalue { ptr, i32 } %landing, 1
173+
call void @use(i32 %extract0)
174+
br label %bb4
175+
176+
bb3: ; preds = %bb
177+
call void @did_not_throw(i32 %i0)
178+
br label %bb4
179+
180+
bb4: ; preds = %bb3, %bb1
181+
ret void
182+
}
183+
184+
; CHECK-LABEL: define void @sink_multiple_uses() {
185+
; INTERESTING: call i32 @leaf(
186+
; INTERESTING: call void @use0(
187+
188+
; RESULT-NEXT: call void @func(
189+
; RESULT-NEXT: %ret = call i32 @leaf()
190+
; RESULT-NEXT: call void @use0(i32 %ret)
191+
define void @sink_multiple_uses() {
192+
%ret = call i32 @leaf()
193+
call void @func()
194+
call void @use0(i32 %ret)
195+
call void @func()
196+
call void @use1(i32 %ret)
197+
call void @func()
198+
call void @use2(i32 %ret)
199+
ret void
200+
}
201+
202+
; CHECK-LABEL: define i32 @can_sink_end_diamond(
203+
; RESULT: entry:
204+
; RESULT-NEXT: br i1
205+
206+
; RESULT: endif:
207+
; RESULT-NEXT: %val = call i32 @leaf()
208+
; RESULT-NEXT: call void @use(i32 %val)
209+
; RESULT-NEXT: ret i32 %val
210+
define i32 @can_sink_end_diamond(i1 %cond) {
211+
entry:
212+
%val = call i32 @leaf()
213+
br i1 %cond, label %a, label %b
214+
215+
a:
216+
br label %endif
217+
218+
b:
219+
br label %endif
220+
221+
endif:
222+
call void @use(i32 %val)
223+
ret i32 %val
224+
}
225+
226+
; CHECK-LABEL: define i32 @cannot_sink_diamond_end_0(
227+
; RESULT: entry:
228+
; RESULT-NEXT: %val = call i32 @leaf()
229+
define i32 @cannot_sink_diamond_end_0(i1 %cond) {
230+
entry:
231+
%val = call i32 @leaf()
232+
br i1 %cond, label %a, label %b
233+
234+
a:
235+
call void @use0(i32 %val)
236+
br label %endif
237+
238+
b:
239+
call void @use1(i32 %val)
240+
br label %endif
241+
242+
endif:
243+
ret i32 %val
244+
}
245+
246+
; CHECK-LABEL: define void @cannot_sink_diamond_end_1(
247+
; RESULT: entry:
248+
; RESULT-NEXT: %val = call i32 @leaf()
249+
define void @cannot_sink_diamond_end_1(i1 %cond) {
250+
entry:
251+
%val = call i32 @leaf()
252+
br i1 %cond, label %a, label %b
253+
254+
a:
255+
call void @use0(i32 %val)
256+
br label %endif
257+
258+
b:
259+
call void @use1(i32 %val)
260+
br label %endif
261+
262+
endif:
263+
ret void
264+
}

llvm/tools/llvm-reduce/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ add_llvm_tool(llvm-reduce
6060
deltas/ReduceRegisterMasks.cpp
6161
deltas/ReduceRegisterDefs.cpp
6262
deltas/ReduceRegisterUses.cpp
63+
deltas/ReduceSinkDefsToUses.cpp
6364
deltas/ReduceTargetFeaturesAttr.cpp
6465
deltas/ReduceUsingSimplifyCFG.cpp
6566
deltas/RunIRPasses.cpp

llvm/tools/llvm-reduce/DeltaManager.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include "deltas/ReduceRegisterDefs.h"
4646
#include "deltas/ReduceRegisterMasks.h"
4747
#include "deltas/ReduceRegisterUses.h"
48+
#include "deltas/ReduceSinkDefsToUses.h"
4849
#include "deltas/ReduceSpecialGlobals.h"
4950
#include "deltas/ReduceTargetFeaturesAttr.h"
5051
#include "deltas/ReduceUsingSimplifyCFG.h"

llvm/tools/llvm-reduce/DeltaPasses.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ DELTA_PASS_IR("atomic-ordering", reduceAtomicOrderingDeltaPass, "Reducing Atomic
5959
DELTA_PASS_IR("syncscopes", reduceAtomicSyncScopesDeltaPass, "Reducing Atomic Sync Scopes")
6060
DELTA_PASS_IR("instruction-flags", reduceInstructionFlagsDeltaPass, "Reducing Instruction Flags")
6161
DELTA_PASS_IR("inline-call-sites", reduceInlineCallSitesDeltaPass, "Inlining callsites")
62+
DELTA_PASS_IR("sink-defs-to-uses", reduceSinkDefsToUsesDeltaPass, "Sinking defs to uses")
6263

6364
#ifndef DELTA_PASS_MIR
6465
#define DELTA_PASS_MIR(NAME, FUNC, DESC)
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//===- ReduceSinkDefsToUses.cpp - Specialized Delta Pass ------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Try to move defs to be next to their uses
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "ReduceSinkDefsToUses.h"
14+
#include "Utils.h"
15+
#include "llvm/IR/Dominators.h"
16+
#include "llvm/IR/Instructions.h"
17+
18+
using namespace llvm;
19+
20+
static bool shouldPreserveUsePosition(const Instruction &I) {
21+
return isa<AllocaInst>(I) || isa<PHINode>(I) || I.isEHPad();
22+
}
23+
24+
static bool shouldPreserveDefPosition(const Instruction &I) {
25+
return shouldPreserveUsePosition(I) || I.isTerminator();
26+
}
27+
28+
static void sinkDefsToUsesInFunction(Oracle &O, Function &F) {
29+
DominatorTree DT(F);
30+
31+
for (BasicBlock &BB : F) {
32+
for (Instruction &UseInst : make_early_inc_range(reverse(BB))) {
33+
if (shouldPreserveUsePosition(UseInst))
34+
continue;
35+
36+
for (Value *UseOp : UseInst.operands()) {
37+
Instruction *DefInst = dyn_cast<Instruction>(UseOp);
38+
if (!DefInst || shouldPreserveDefPosition(*DefInst))
39+
continue;
40+
41+
if (!all_of(DefInst->users(), [&](const User *DefUser) {
42+
return DefUser == &UseInst ||
43+
DT.dominates(&UseInst, cast<Instruction>(DefUser));
44+
})) {
45+
continue;
46+
}
47+
48+
if (!O.shouldKeep())
49+
DefInst->moveBeforePreserving(UseInst.getIterator());
50+
}
51+
}
52+
}
53+
}
54+
55+
void llvm::reduceSinkDefsToUsesDeltaPass(Oracle &O, ReducerWorkItem &WorkItem) {
56+
Module &M = WorkItem.getModule();
57+
for (Function &F : M) {
58+
if (!F.isDeclaration())
59+
sinkDefsToUsesInFunction(O, F);
60+
}
61+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//===- ReduceSinkDefsToUses.h - Specialized Delta Pass ----------*- C++- *-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_TOOLS_LLVM_REDUCE_DELTAS_SINKDEFSTOUSES_H
10+
#define LLVM_TOOLS_LLVM_REDUCE_DELTAS_SINKDEFSTOUSES_H
11+
12+
#include "Delta.h"
13+
14+
namespace llvm {
15+
void reduceSinkDefsToUsesDeltaPass(Oracle &O, ReducerWorkItem &WorkItem);
16+
} // namespace llvm
17+
18+
#endif

llvm/utils/gn/secondary/llvm/tools/llvm-reduce/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ executable("llvm-reduce") {
4848
"deltas/ReduceRegisterDefs.cpp",
4949
"deltas/ReduceRegisterMasks.cpp",
5050
"deltas/ReduceRegisterUses.cpp",
51+
"deltas/ReduceSinkDefsToUses.cpp",
5152
"deltas/ReduceSpecialGlobals.cpp",
5253
"deltas/ReduceTargetFeaturesAttr.cpp",
5354
"deltas/ReduceUsingSimplifyCFG.cpp",

0 commit comments

Comments
 (0)