Skip to content

Commit 1177b54

Browse files
authored
Merge pull request #50315 from JuliaLang/pc/fix-mssa-preserve
Fix MemorySSA preservation in julia-licm
2 parents 5c070f4 + f5faa08 commit 1177b54

File tree

3 files changed

+245
-6
lines changed

3 files changed

+245
-6
lines changed

src/llvm-julia-licm.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ struct JuliaLICM : public JuliaPassContext {
176176
// Lazy initialization of exit blocks insertion points.
177177
bool exit_pts_init = false;
178178
SmallVector<Instruction*, 8> _exit_pts;
179-
auto get_exit_pts = [&] () -> ArrayRef<Instruction*> {
179+
auto get_exit_pts = [&] () -> MutableArrayRef<Instruction*> {
180180
if (!exit_pts_init) {
181181
exit_pts_init = true;
182182
SmallVector<BasicBlock*, 8> exit_bbs;
@@ -242,6 +242,7 @@ struct JuliaLICM : public JuliaPassContext {
242242
}
243243
++SunkPreserveEnd;
244244
moveInstructionBefore(*call, *exit_pts[0], MSSAU, SE, MemorySSA::Beginning);
245+
exit_pts[0] = call;
245246
LLVM_DEBUG(dbgs() << "Sunk gc_preserve_end: " << *call << "\n");
246247
REMARK([&](){
247248
return OptimizationRemark(DEBUG_TYPE, "Sunk", call)
@@ -250,6 +251,7 @@ struct JuliaLICM : public JuliaPassContext {
250251
for (unsigned i = 1; i < exit_pts.size(); i++) {
251252
// Clone exit
252253
auto CI = CallInst::Create(call, {}, exit_pts[i]);
254+
exit_pts[i] = CI;
253255
createNewInstruction(CI, call, MSSAU);
254256
LLVM_DEBUG(dbgs() << "Cloned and sunk gc_preserve_end: " << *CI << "\n");
255257
REMARK([&](){
@@ -345,11 +347,8 @@ struct JuliaLICM : public JuliaPassContext {
345347
auto align = Align(DL.getPointerSize(0));
346348
auto clear_obj = builder.CreateMemSet(obj_i8, ConstantInt::get(Type::getInt8Ty(call->getContext()), 0), call->getArgOperand(1), align);
347349
if (MSSAU.getMemorySSA()) {
348-
auto alloc_mdef = MSSAU.getMemorySSA()->getMemoryAccess(call);
349-
assert(isa<MemoryDef>(alloc_mdef) && "Expected alloc to be associated with a memory def!");
350-
auto clear_mdef = MSSAU.createMemoryAccessAfter(clear_obj, nullptr, alloc_mdef);
351-
assert(isa<MemoryDef>(clear_mdef) && "Expected memset to be associated with a memory def!");
352-
(void) clear_mdef;
350+
auto clear_mdef = MSSAU.createMemoryAccessInBB(clear_obj, nullptr, clear_obj->getParent(), MemorySSA::BeforeTerminator);
351+
MSSAU.insertDef(cast<MemoryDef>(clear_mdef), true);
353352
}
354353
changed = true;
355354
}
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
; COM: NewPM-only test, tests that memoryssa is preserved correctly
2+
3+
; RUN: opt -enable-new-pm=1 --opaque-pointers=0 --load-pass-plugin=libjulia-codegen%shlibext -passes='function(loop-mssa(JuliaLICM),print<memoryssa>)' -S -o /dev/null %s 2>&1 | FileCheck %s --check-prefixes=CHECK,TYPED
4+
5+
; RUN: opt -enable-new-pm=1 --opaque-pointers=1 --load-pass-plugin=libjulia-codegen%shlibext -passes='function(loop-mssa(JuliaLICM),print<memoryssa>)' -S -o /dev/null %s 2>&1 | FileCheck %s --check-prefixes=CHECK,OPAQUE
6+
7+
@tag = external addrspace(10) global {}, align 16
8+
9+
declare void @julia.write_barrier({} addrspace(10)*, ...)
10+
11+
declare {}*** @julia.get_pgcstack()
12+
13+
declare token @llvm.julia.gc_preserve_begin(...)
14+
15+
declare void @llvm.julia.gc_preserve_end(token)
16+
17+
declare void @mssa_use({} addrspace(10)*)
18+
19+
declare noalias nonnull {} addrspace(10)* @julia.gc_alloc_obj({}**, i64, {} addrspace(10)*)
20+
21+
; COM: check basic preserve hoist/sink functionality
22+
; CHECK-LABEL: MemorySSA for function: hoist_sink_preserves
23+
; CHECK-LABEL: @hoist_sink_preserves
24+
define void @hoist_sink_preserves({} addrspace(10)* %obj, i1 %ret) {
25+
; CHECK: top:
26+
top:
27+
; CHECK-NEXT: [[PGCSTACK:[0-9]+]] = MemoryDef(liveOnEntry)
28+
%pgcstack = call {}*** @julia.get_pgcstack()
29+
%current_task = bitcast {}*** %pgcstack to {}**
30+
; CHECK: br label %preheader
31+
br label %preheader
32+
; CHECK: preheader:
33+
preheader:
34+
; CHECK-NEXT: [[PRESERVE_TOKEN:[0-9]+]] = MemoryDef([[PGCSTACK]])
35+
; CHECK-NEXT: %preserve_token = call token (...) @llvm.julia.gc_preserve_begin
36+
; CHECK-NEXT: br label %loop
37+
br label %loop
38+
; CHECK: loop:
39+
loop:
40+
; CHECK-NOT: call token (...) @llvm.julia.gc_preserve_begin
41+
%preserve_token = call token (...) @llvm.julia.gc_preserve_begin({} addrspace(10)* %obj)
42+
; CHECK-NOT: call void @llvm.julia.gc_preserve_end
43+
call void @llvm.julia.gc_preserve_end(token %preserve_token)
44+
; CHECK-NEXT: [[MPHI:[0-9]+]] = MemoryPhi({preheader,[[PRESERVE_TOKEN]]},{loop,[[MPHI]]})
45+
; CHECK-NEXT: br i1 %ret
46+
br i1 %ret, label %return, label %loop
47+
; CHECK: return:
48+
return:
49+
; CHECK-NEXT: [[PRESERVE_END:[0-9]+]] = MemoryDef([[MPHI]])
50+
; CHECK-NEXT: call void @llvm.julia.gc_preserve_end(token %preserve_token)
51+
; CHECK-NEXT: [[MSSA_USE:[0-9]+]] = MemoryDef([[PRESERVE_END]])
52+
; CHECK-NEXT: call void @mssa_use
53+
call void @mssa_use({} addrspace(10)* %obj)
54+
; CHECK-NEXT: ret void
55+
ret void
56+
}
57+
58+
; COM: check sink functionality when there are multiple loop exit blocks
59+
; CHECK-LABEL: MemorySSA for function: hoist_multisink_preserves
60+
; CHECK-LABEL: @hoist_multisink_preserves
61+
define void @hoist_multisink_preserves({} addrspace(10)* %obj, i1 %ret) {
62+
; CHECK: top:
63+
top:
64+
; CHECK-NEXT: [[PGCSTACK:[0-9]+]] = MemoryDef(liveOnEntry)
65+
%pgcstack = call {}*** @julia.get_pgcstack()
66+
%current_task = bitcast {}*** %pgcstack to {}**
67+
; CHECK: br label %preheader
68+
br label %preheader
69+
; CHECK: preheader:
70+
preheader:
71+
; CHECK-NEXT: [[PRESERVE_TOKEN:[0-9]+]] = MemoryDef([[PGCSTACK]])
72+
; CHECK-NEXT: %preserve_token = call token (...) @llvm.julia.gc_preserve_begin
73+
; CHECK-NEXT: br label %loop
74+
br label %loop
75+
; CHECK: loop:
76+
loop:
77+
; CHECK-NOT: call token (...) @llvm.julia.gc_preserve_begin
78+
%preserve_token = call token (...) @llvm.julia.gc_preserve_begin({} addrspace(10)* %obj)
79+
; CHECK-NOT: call void @llvm.julia.gc_preserve_end
80+
call void @llvm.julia.gc_preserve_end(token %preserve_token)
81+
; CHECK-NEXT: [[MPHI:[0-9]+]] = MemoryPhi({preheader,[[PRESERVE_TOKEN]]},{loop2,[[MPHI]]})
82+
; CHECK-NEXT: br i1 %ret
83+
br i1 %ret, label %return, label %loop2
84+
; CHECK: loop2:
85+
loop2:
86+
; CHECK-NEXT: br i1 %ret
87+
br i1 %ret, label %return2, label %loop
88+
; CHECK: return:
89+
return:
90+
; CHECK-NEXT: [[PRESERVE_END_1:[0-9]+]] = MemoryDef([[MPHI]])
91+
; CHECK-NEXT: call void @llvm.julia.gc_preserve_end(token %preserve_token)
92+
; CHECK-NEXT: [[MSSA_USE:[0-9]+]] = MemoryDef([[PRESERVE_END_1]])
93+
; CHECK-NEXT: call void @mssa_use
94+
call void @mssa_use({} addrspace(10)* %obj)
95+
; CHECK-NEXT: ret void
96+
ret void
97+
; CHECK: return2:
98+
return2:
99+
; CHECK-NEXT: [[PRESERVE_END_2:[0-9]+]] = MemoryDef([[MPHI]])
100+
; CHECK-NEXT: call void @llvm.julia.gc_preserve_end(token %preserve_token)
101+
; CHECK-NEXT: [[MSSA_USE:[0-9]+]] = MemoryDef([[PRESERVE_END_2]])
102+
; CHECK-NEXT: call void @mssa_use
103+
call void @mssa_use({} addrspace(10)* %obj)
104+
; CHECK-NEXT: ret void
105+
ret void
106+
}
107+
108+
define void @hoist_allocation({} addrspace(10)* %obj, i1 %ret) {
109+
; CHECK: top:
110+
top:
111+
; CHECK-NEXT: [[PGCSTACK:[0-9]+]] = MemoryDef(liveOnEntry)
112+
%pgcstack = call {}*** @julia.get_pgcstack()
113+
%current_task = bitcast {}*** %pgcstack to {}**
114+
br label %preheader
115+
; CHECK: preheader:
116+
preheader:
117+
; CHECK-NEXT: [[ALLOC:[0-9]+]] = MemoryDef([[PGCSTACK]])
118+
119+
; TYPED-NEXT: %alloc = call {} addrspace(10)* @julia.gc_alloc_obj({}** %current_task, i64 0, {} addrspace(10)* @tag)
120+
; TYPED-NEXT: %[[BCAST:.*]] = bitcast {} addrspace(10)* %alloc to i8 addrspace(10)*
121+
122+
; OPAQUE-NEXT: %alloc = call ptr addrspace(10) @julia.gc_alloc_obj(ptr %current_task, i64 0, ptr addrspace(10) @tag)
123+
124+
; CHECK-NEXT: [[MSET:[0-9]+]] = MemoryDef([[ALLOC]])
125+
; CHECK-NEXT: call void @llvm.memset
126+
; CHECK-NEXT: br label %loop
127+
br label %loop
128+
; CHECK: loop:
129+
loop:
130+
; CHECK-NOT: %alloc
131+
; CHECK-NOT: @julia.gc_alloc_obj
132+
%alloc = call {} addrspace(10)* @julia.gc_alloc_obj({}** %current_task, i64 0, {} addrspace(10)* @tag)
133+
; CHECK-NEXT: [[MPHI:[0-9]+]] = MemoryPhi({preheader,[[MSET]]},{loop,[[MPHI]]})
134+
br i1 %ret, label %return, label %loop
135+
; CHECK: return:
136+
return:
137+
; CHECK-NEXT: [[MSSA_USE:[0-9]+]] = MemoryDef([[MPHI]])
138+
; CHECK-NEXT: call void @mssa_use
139+
call void @mssa_use({} addrspace(10)* %obj)
140+
; CHECK-NEXT: ret void
141+
ret void
142+
}
143+
144+
define void @hoist_write_barrier({} addrspace(10)* %obj, i1 %ret) {
145+
; CHECK: top:
146+
top:
147+
; CHECK-NEXT: [[PGCSTACK:[0-9]+]] = MemoryDef(liveOnEntry)
148+
%pgcstack = call {}*** @julia.get_pgcstack()
149+
%current_task = bitcast {}*** %pgcstack to {}**
150+
br label %preheader
151+
; CHECK: preheader:
152+
preheader:
153+
; CHECK-NEXT: [[WB:[0-9]+]] = MemoryDef([[PGCSTACK]])
154+
; CHECK-NEXT: call void
155+
; CHECK-SAME: @julia.write_barrier
156+
; CHECK-NEXT: br label %loop
157+
br label %loop
158+
; CHECK: loop:
159+
loop:
160+
; CHECK-NOT: @julia.write_barrier
161+
call void ({} addrspace(10)*, ...) @julia.write_barrier({} addrspace(10)* %obj)
162+
; CHECK-NEXT: [[MPHI:[0-9]+]] = MemoryPhi({preheader,[[WB]]},{loop,[[MPHI]]})
163+
br i1 %ret, label %return, label %loop
164+
; CHECK: return:
165+
return:
166+
; CHECK-NEXT: [[MSSA_USE:[0-9]+]] = MemoryDef([[MPHI]])
167+
; CHECK-NEXT: call void @mssa_use
168+
call void @mssa_use({} addrspace(10)* %obj)
169+
; CHECK-NEXT: ret void
170+
ret void
171+
}

test/llvmpasses/julia-licm.ll

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,75 @@ declare void @julia.write_barrier({}*, ...)
1212

1313
declare {}*** @julia.get_pgcstack()
1414

15+
declare token @llvm.julia.gc_preserve_begin(...)
16+
17+
declare void @llvm.julia.gc_preserve_end(token)
18+
19+
; COM: check basic preserve hoist/sink functionality
20+
; CHECK-LABEL: @hoist_sink_preserves
21+
define void @hoist_sink_preserves({} addrspace(10)* %obj, i1 %ret) {
22+
top:
23+
%pgcstack = call {}*** @julia.get_pgcstack()
24+
%current_task = bitcast {}*** %pgcstack to {}**
25+
; CHECK: br label %preheader
26+
br label %preheader
27+
; CHECK: preheader:
28+
preheader:
29+
; CHECK-NEXT: %preserve_token = call token (...) @llvm.julia.gc_preserve_begin
30+
; CHECK-NEXT: br label %loop
31+
br label %loop
32+
; CHECK: loop:
33+
loop:
34+
; CHECK-NOT: call token (...) @llvm.julia.gc_preserve_begin
35+
%preserve_token = call token (...) @llvm.julia.gc_preserve_begin({} addrspace(10)* %obj)
36+
; CHECK-NOT: call void @llvm.julia.gc_preserve_end
37+
call void @llvm.julia.gc_preserve_end(token %preserve_token)
38+
; CHECK-NEXT: br i1 %ret
39+
br i1 %ret, label %return, label %loop
40+
; CHECK: return:
41+
return:
42+
; CHECK-NEXT: call void @llvm.julia.gc_preserve_end(token %preserve_token)
43+
; CHECK-NEXT: ret void
44+
ret void
45+
}
46+
47+
; COM: check sink functionality when there are multiple loop exit blocks
48+
; CHECK-LABEL: @hoist_multisink_preserves
49+
define void @hoist_multisink_preserves({} addrspace(10)* %obj, i1 %ret) {
50+
top:
51+
%pgcstack = call {}*** @julia.get_pgcstack()
52+
%current_task = bitcast {}*** %pgcstack to {}**
53+
; CHECK: br label %preheader
54+
br label %preheader
55+
; CHECK: preheader:
56+
preheader:
57+
; CHECK-NEXT: %preserve_token = call token (...) @llvm.julia.gc_preserve_begin
58+
; CHECK-NEXT: br label %loop
59+
br label %loop
60+
; CHECK: loop:
61+
loop:
62+
; CHECK-NOT: call token (...) @llvm.julia.gc_preserve_begin
63+
%preserve_token = call token (...) @llvm.julia.gc_preserve_begin({} addrspace(10)* %obj)
64+
; CHECK-NOT: call void @llvm.julia.gc_preserve_end
65+
call void @llvm.julia.gc_preserve_end(token %preserve_token)
66+
; CHECK-NEXT: br i1 %ret
67+
br i1 %ret, label %return, label %loop2
68+
; CHECK: loop2:
69+
loop2:
70+
; CHECK-NEXT: br i1 %ret
71+
br i1 %ret, label %return2, label %loop
72+
; CHECK: return:
73+
return:
74+
; CHECK-NEXT: call void @llvm.julia.gc_preserve_end(token %preserve_token)
75+
; CHECK-NEXT: ret void
76+
ret void
77+
; CHECK: return2:
78+
return2:
79+
; CHECK-NEXT: call void @llvm.julia.gc_preserve_end(token %preserve_token)
80+
; CHECK-NEXT: ret void
81+
ret void
82+
}
83+
1584
; COM: check basic allocation hoisting functionality
1685
; CHECK-LABEL: @julia_allocation_hoist
1786
define nonnull {} addrspace(10)* @julia_allocation_hoist(i64 signext %0) #0 {

0 commit comments

Comments
 (0)