Skip to content

Commit b447d87

Browse files
committed
Fix lower handlers pass to handle merging branches into leave_funcs. Also add tests and fix llvmpasses
1 parent bafd135 commit b447d87

File tree

5 files changed

+128
-32
lines changed

5 files changed

+128
-32
lines changed

src/llvm-lower-handlers.cpp

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,16 @@ static bool lowerExcHandlers(Function &F) {
150150
EnterDepth[CI] = Depth++;
151151
else if (Callee == leave_func || Callee == leave_noexcept_func) {
152152
LeaveDepth[CI] = Depth;
153-
Depth -= cast<ConstantInt>(CI->getArgOperand(1))->getLimitedValue();
153+
if (auto change = dyn_cast<ConstantInt>(CI->getArgOperand(1)))
154+
Depth -= change->getLimitedValue();
155+
else if (auto Phi = dyn_cast<PHINode>(CI->getArgOperand(1))) {
156+
//This should really do a dataflow analysis but assuming worst case means that we will always have enough space
157+
uint64_t MinPhiDepth = std::numeric_limits<uint64_t>::max();
158+
for (Value *Incoming : Phi->incoming_values()) {
159+
MinPhiDepth = std::min(MinPhiDepth, cast<ConstantInt>(Incoming)->getLimitedValue());
160+
}
161+
Depth -= MinPhiDepth;
162+
}
154163
}
155164
assert(Depth >= 0);
156165
if (Depth > MaxDepth)
@@ -175,7 +184,7 @@ static bool lowerExcHandlers(Function &F) {
175184
unsigned allocaAddressSpace = F.getParent()->getDataLayout().getAllocaAddrSpace();
176185
for (int i = 0; i < MaxDepth; ++i) {
177186
auto *buff = new AllocaInst(Type::getInt8Ty(F.getContext()), allocaAddressSpace,
178-
handler_sz, Align(16), "", firstInst);
187+
handler_sz, Align(16), "depth" + std::to_string(i), firstInst);
179188
if (allocaAddressSpace) {
180189
AddrSpaceCastInst *buff_casted = new AddrSpaceCastInst(buff, PointerType::get(F.getContext(), AddressSpace::Generic));
181190
buff_casted->insertAfter(buff);
@@ -232,7 +241,18 @@ static bool lowerExcHandlers(Function &F) {
232241
// Insert lifetime end intrinsics after every leave.
233242
for (auto it : LeaveDepth) {
234243
int StartDepth = it.second - 1;
235-
int npops = cast<ConstantInt>(it.first->getArgOperand(1))->getLimitedValue();
244+
uint64_t minPops = std::numeric_limits<uint64_t>::max();
245+
if (auto change = dyn_cast<ConstantInt>(it.first->getArgOperand(1)))
246+
minPops = change->getLimitedValue();
247+
else if (auto Phi = dyn_cast<PHINode>(it.first->getArgOperand(1))) {
248+
//This should really do a dataflow analysis but assuming worst case means that we will always have enough space
249+
uint64_t MinPhiDepth = std::numeric_limits<uint64_t>::max();
250+
for (Value *Incoming : Phi->incoming_values()) {
251+
MinPhiDepth = std::min(MinPhiDepth, cast<ConstantInt>(Incoming)->getLimitedValue());
252+
}
253+
minPops = MinPhiDepth;
254+
}
255+
int npops = minPops;
236256
for (int i = 0; i < npops; ++i) {
237257
assert(StartDepth-i >= 0);
238258
Value *lifetime_args[] = {

test/exceptions.jl

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,3 +400,28 @@ end
400400
catch
401401
current_exceptions()
402402
end) == 2
403+
404+
# Trigger merging of branches in LLVM so we have a dynamic pop_handler
405+
a1234123::Int = 3
406+
function poll_fd2()
407+
local timer
408+
try
409+
try
410+
try
411+
global a1234123 = 1
412+
finally
413+
global a1234123 = 2
414+
end
415+
return events
416+
catch ex
417+
return FDEvent()
418+
end
419+
finally
420+
if @isdefined(timer)
421+
global a1234123 = 2
422+
else
423+
global a1234123 = 4
424+
end
425+
end
426+
end
427+
@test_throws UndefVarError poll_fd2() #shouldn't crash

test/llvmpasses/image-codegen.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
# CHECK-NOT: private global
1515
# CHECK: jl_global
1616
# COM: we emit both declarations and definitions, so we may see either style in the IR
17-
# CHECK-SAME: = {{(external )?}}global
17+
# CHECK-SAME: = {{(external )?}}
1818
# CHECK: julia_f_
1919
# CHECK-NOT: internal global
2020
# CHECK-NOT: private global

test/llvmpasses/lower-handlers.ll

Lines changed: 76 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,88 @@
11
; This file is a part of Julia. License is MIT: https://julialang.org/license
22

33
; RUN: opt --load-pass-plugin=libjulia-codegen%shlibext -passes='function(LowerExcHandlers)' -S %s | FileCheck %s
4+
; ModuleID = 'lower-handlers.ll'
5+
; ModuleID = 'lower-handlers2.ll'
6+
source_filename = "lower-handlers.ll"
47

5-
attributes #1 = { returns_twice }
6-
declare {i32, i8*} @julia.except_enter({}*) #1
7-
declare void @ijl_pop_handler({}*, i32)
8-
declare i8**** @julia.ptls_states()
9-
declare i8**** @julia.get_pgcstack()
8+
declare ptr @julia.get_pgcstack()
9+
10+
declare i64 @ijl_excstack_state(ptr)
11+
12+
declare { i32, ptr } @julia.except_enter(ptr)
13+
14+
declare void @ijl_pop_handler(ptr, i32)
15+
16+
declare void @ijl_pop_handler_noexcept(ptr, i32)
17+
18+
declare void @ijl_restore_excstack(ptr, i64)
19+
20+
declare ptr @julia.ptls_states()
1021

1122
define void @simple() {
1223
top:
13-
%pgcstack = call i8**** @julia.get_pgcstack()
24+
%pgcstack = call ptr @julia.get_pgcstack()
1425
; CHECK: call void @llvm.lifetime.start
1526
; CHECK: call void @ijl_enter_handler
1627
; CHECK: setjmp
17-
%rb = call {i32, i8*} @julia.except_enter({}* null)
18-
%r = extractvalue {i32, i8*} %rb, 0
19-
%b = extractvalue {i32, i8*} %rb, 1
20-
%cmp = icmp eq i32 %r, 0
21-
br i1 %cmp, label %try, label %catch
22-
try:
23-
%lcssa = phi {i32, i8*} [ %rb, %top ]
24-
br label %after
25-
catch:
26-
br label %after
27-
after:
28-
call void @ijl_pop_handler({}* null, i32 1)
28+
%rb = call { i32, ptr } @julia.except_enter(ptr null)
29+
%r = extractvalue { i32, ptr } %rb, 0
30+
%b = extractvalue { i32, ptr } %rb, 1
31+
%cmp = icmp eq i32 %r, 0
32+
br i1 %cmp, label %try, label %catch
33+
34+
try: ; preds = %top
35+
%lcssa = phi { i32, ptr } [ %rb, %top ]
36+
br label %after
37+
38+
catch: ; preds = %top
39+
br label %after
40+
41+
after: ; preds = %catch, %try
42+
call void @ijl_pop_handler(ptr null, i32 1)
43+
; CHECK: llvm.lifetime.end
44+
ret void
45+
}
46+
47+
define ptr addrspace(10) @julia_poll_fd2_1135(){
48+
top:
49+
; CHECK: %depth0 = alloca i8, i32 256, align 16
50+
; CHECK: %depth1 = alloca i8, i32 256, align 16
51+
%pgcstack = call ptr @julia.get_pgcstack()
52+
%current_task7 = getelementptr inbounds i8, ptr %pgcstack, i64 -112
53+
%0 = call i64 @ijl_excstack_state(ptr nonnull %current_task7)
54+
; CHECK: call void @llvm.lifetime.start
55+
; CHECK: call void @ijl_enter_handler
56+
; CHECK: setjmp
57+
%1 = call { i32, ptr } @julia.except_enter(ptr nonnull %current_task7)
58+
%2 = extractvalue { i32, ptr } %1, 0
59+
%.not2 = icmp eq i32 %2, 0
60+
br i1 %.not2, label %try, label %L50
61+
62+
L50: ; preds = %top
63+
call void @ijl_pop_handler(ptr nonnull %current_task7, i32 1)
64+
; CHECK: llvm.lifetime.end
65+
unreachable
66+
67+
try: ; preds = %top
68+
%3 = call i64 @ijl_excstack_state(ptr nonnull %current_task7)
69+
; CHECK: call void @llvm.lifetime.start
70+
; CHECK: call void @ijl_enter_handler
71+
; CHECK: setjmp
72+
%4 = call { i32, ptr } @julia.except_enter(ptr nonnull %current_task7)
73+
%5 = extractvalue { i32, ptr } %4, 0
74+
%6 = icmp eq i32 %5, 0
75+
br i1 %6, label %common.ret, label %catch_pop14
76+
77+
catch_pop14: ; preds = %try
78+
call void @ijl_pop_handler(ptr nonnull %current_task7, i32 1)
79+
; CHECK: llvm.lifetime.end
80+
call void @ijl_restore_excstack(ptr nonnull %current_task7, i64 %3)
81+
br label %common.ret
82+
83+
common.ret: ; preds = %catch_pop14, %try
84+
%.sink = phi i32 [ 1, %catch_pop14 ], [ 2, %try ]
85+
call void @ijl_pop_handler_noexcept(ptr nonnull %current_task7, i32 %.sink)
2986
; CHECK: llvm.lifetime.end
30-
ret void
87+
ret ptr addrspace(10) null
3188
}

test/llvmpasses/pipeline-prints.ll

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -285,25 +285,19 @@ attributes #2 = { inaccessiblemem_or_argmemonly }
285285

286286
; COM: InstSimplify/InstCombine should kill this zext-trunc pair
287287
; AFTEREARLYSIMPLIFICATION: [[ZEXT:%.*]] = zext i1 {{%.*}} to i8
288-
; AFTEREARLYSIMPLIFICATION-NEXT: trunc i8 [[ZEXT]] to i1
289288

290-
; BEFOREEARLYOPTIMIZATION: [[ZEXT:%.*]] = zext i1 {{%.*}} to i8
291-
; BEFOREEARLYOPTIMIZATION-NEXT: trunc i8 [[ZEXT]] to i1
292289

293290
; AFTEREARLYOPTIMIZATION-NOT: zext i1 {{%.*}} to i8
294-
; AFTEREARLYOPTIMIZATION-NOT: trunc i8 {{%.*}} to i1
295291

296292
; BEFORELOOPOPTIMIZATION-NOT: zext i1 {{%.*}} to i8
297-
; BEFORELOOPOPTIMIZATION-NOT: trunc i8 {{%.*}} to i1
298293

299294
; COM: Loop simplification makes the exit condition obvious
300295
; AFTERLOOPSIMPLIFICATION: L35.lr.ph:
301296
; AFTERLOOPSIMPLIFICATION: add nuw nsw
302297

303-
; COM: Scalar optimization removes the previous add from the preheader
304-
; AFTERSCALAROPTIMIZATION: L35.lr.ph:
305-
; AFTERSCALAROPTIMIZATION-NOT: add nuw nsw
306-
; AFTERSCALAROPTIMIZATION: br label %L35
298+
; COM: Scalar optimization removes the preheader
299+
; AFTERSCALAROPTIMIZATION: L17:
300+
; AFTERSCALAROPTIMIZATION: icmp eq i64 {{%.*}}, 1,
307301

308302
; COM: Vectorization does stuff
309303
; AFTERVECTORIZATION: vector.body

0 commit comments

Comments
 (0)