I have what appears to be a bug in LLVM... I'm deeply hesitant to
label it a bug, given my lack of experience with LLVM, but the
behaviour of this fragment strongly suggests a bug.
In particular, compiling and running this fragment using a fresh SVN
build yields this stderr:
uccello:/tmp clements$ lli a.out.bc
0 lli 0x005e72b6 char const* std::find<char const*,
char>(char const*, char const*, char const&) + 98
1 lli 0x005e77eb
llvm::sys::PrintStackTraceOnErrorSignal() + 593
2 libSystem.B.dylib 0x9623509b _sigtramp + 43
3 libSystem.B.dylib 0xffffffff _sigtramp + 1776070543
4 lli 0x001f421b
llvm::ExecutionEngine::runFunctionAsMain(llvm::Function*,
std::vector<std::string, std::allocator<std::string> > const&,
char
const* const*) + 1101
5 lli 0x00002e03 main + 1633
6 lli 0x00002736 start + 54
Segmentation fault
However, running it with the interpreter allows it to finish
successfully:
uccello:/tmp clements$ lli -force-interpreter=true a.out.bc
0
Also, the code is insanely sensitive to small changes. In the text
below, there's a conditional branch to the %WrongNumberArgs label that
leads to the crash. Replacing the test variable with its value (0)
causes the error to go away, though this could be due to aggressive
dead-code optimization.
Basically, I'm looking for answers to these questions:
1) does this stack trace suggest a compiler bug?
2) does the fact that the behavior is different in the interpreter
than with the JIT suggest that this is a compiler bug?
3) are there known issues with 'unwind' in the code in the SVN head?
Perhaps the easiest thing would just be to give up on 'unwind,' but if
this is in fact an LLVM bug I figured I'd let someone have a crack at
it.
The attached code is large (~200 lines), but most of my attempts to
slim it down make the bug go away, unfortunately.
Hey, at least it's reproducible...
My system: Mac OS X 10.5.5, Intel Core Duo (*not* Core 2 duo), LLVM
from SVN head.
I also tried running it on an older version of LLVM on a Fedora 9
machine with similar results, so it's not exclusively a mac problem.
Thanks in advance for any advice,
John Clements
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-
i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-
f80:128:128"
target triple = "i386-apple-darwin9.5"
@error_code = global i32 0
@error_val = global i32 0
%eframe = type {%eframe*, i32, [0 x i32]}
%closure = type {i32, %eframe*}
%packed_args = type {i32, [0 x i32]}
@empty_env = global i32 0
define i32 @scheme_entry () {
%init_env = bitcast i32* @empty_env to %eframe*
%main = invoke i32 @main_1(%eframe* %init_env) to label %Done unwind
label %Exn
Done:
%fixed = bitcast i32 %main to i32
ret i32 %fixed
Exn:
ret i32 0
}
define i32 @dispatch(%eframe* %env, i32 %fun_val, %packed_args* %args) {
%reg_1 = and i32 %fun_val, 3
%reg_2 = icmp eq i32 %reg_1, 1
br i1 %reg_2, label %L_79, label %L_80
L_80:
store i32 %fun_val, i32* @error_val
store i32 5, i32* @error_code
unwind
L_79:
%reg_3 = and i32 %fun_val, 4294967292
%reg_4 = inttoptr i32 %reg_3 to i32*
%reg_5 = load i32* %reg_4
%reg_6 = and i32 %reg_5, 3
%reg_7 = icmp eq i32 %reg_6, 0
br i1 %reg_7, label %Dispatch, label %Fail
Fail:
store i32 2, i32* @error_code
unwind
Dispatch:
switch i32 %reg_5, label %NoMatch [
i32 4, label %Jump_to_main_1
i32 0, label %Jump_to_f_0]
NoMatch:
store i32 %reg_5, i32* @error_val
store i32 3, i32* @error_code
unwind
Jump_to_main_1:
%reg_8 = getelementptr %packed_args* %args, i32 0, i32 0
%reg_9 = load i32* %reg_8
%reg_10 = icmp eq i32 %reg_9, 0
br i1 %reg_10, label %L_81, label %WrongNumArgs
L_81:
%reg_11 = call i32 @main_1(%eframe* %env)
ret i32 %reg_11
Jump_to_f_0:
%reg_12 = getelementptr %packed_args* %args, i32 0, i32 0
%reg_13 = load i32* %reg_12
%reg_14 = icmp eq i32 %reg_13, 3
br i1 %reg_14, label %L_82, label %WrongNumArgs
;;; br i1 0, label %L_82, label %WrongNumArgs
L_82:
ret i32 3
WrongNumArgs:
unwind
}
define i32 @main_1(%eframe* %env) {
%reg_22 = malloc {%eframe*, i32, [1 x i32]}
%reg_23 = bitcast {%eframe*, i32, [1 x i32]}* %reg_22 to %eframe*
%reg_24 = getelementptr %eframe* %reg_23, i32 0, i32 0
store %eframe* %env, %eframe** %reg_24
%reg_25 = getelementptr %eframe* %reg_23, i32 0, i32 1
store i32 1, i32* %reg_25
%reg_26 = malloc %closure
%reg_27 = getelementptr %closure* %reg_26, i32 0, i32 0
store i32 0, i32* %reg_27
%reg_28 = getelementptr %closure* %reg_26, i32 0, i32 1
store %eframe* %reg_23, %eframe** %reg_28
%reg_29 = ptrtoint %closure* %reg_26 to i32
%reg_30 = or i32 %reg_29, 1
%reg_34 = malloc {i32, [2 x i32]}
%reg_35 = getelementptr {i32, [2 x i32]}* %reg_34, i32 0, i32 0
store i32 2, i32* %reg_35
%reg_36 = getelementptr {i32, [2 x i32]}* %reg_34, i32 0, i32 1, i32 0
store i32 12, i32* %reg_36
%reg_37 = getelementptr {i32, [2 x i32]}* %reg_34, i32 0, i32 1, i32 1
store i32 16, i32* %reg_37
%reg_38 = bitcast {i32, [2 x i32]}* %reg_34 to %packed_args*
%reg_39 = call i32 @dispatch(%eframe* %reg_23,i32
%reg_30,%packed_args* %reg_38)
ret i32 %reg_39
}
@"\01LC" = internal constant [3 x i8] c"%d\00" ; <[3 x
i8]*> [#uses=1]
@"\01LC1" = internal constant [6 x i8] c"false\00" ; <[6
x i8]*>
[#uses=1]
@"\01LC2" = internal constant [5 x i8] c"true\00" ; <[5
x i8]*>
[#uses=1]
@"\01LC3" = internal constant [5 x i8] c"#\5C%c\00" ;
<[5 x i8]*>
[#uses=1]
@"\01LC4" = internal constant [16 x i8] c"unknown
pointer\00" ; <[16
x i8]*> [#uses=1]
@"\01LC5" = internal constant [5 x i8] c"void\00" ; <[5
x i8]*>
[#uses=1]
@"\01LC6" = internal constant [18 x i8] c"#<unknown
0x%08x>\00" ;
<[18 x i8]*> [#uses=1]
@"\01LC7" = internal constant [45 x i8] c"evaluation halted with
error: %d and value: \00" ; <[45 x i8]*> [#uses=1]
define void @print_val(i32 %x) nounwind {
entry:
%x_addr = alloca i32 ; <i32*> [#uses=10]
%"alloca point" = bitcast i32 0 to i32 ; <i32> [#uses=0]
store i32 %x, i32* %x_addr
%0 = load i32* %x_addr, align 4 ; <i32> [#uses=1]
%1 = and i32 %0, 3 ; <i32> [#uses=1]
%2 = icmp eq i32 %1, 0 ; <i1> [#uses=1]
br i1 %2, label %bb, label %bb1
bb: ; preds = %entry
%3 = load i32* %x_addr, align 4 ; <i32> [#uses=1]
%4 = ashr i32 %3, 2 ; <i32> [#uses=1]
%5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([3 x i8]*
@"\01LC", i32 0, i32 0), i32 %4) nounwind ; <i32> [#uses=0]
br label %bb12
bb1: ; preds = %entry
%6 = load i32* %x_addr, align 4 ; <i32> [#uses=1]
%7 = icmp eq i32 %6, 47 ; <i1> [#uses=1]
br i1 %7, label %bb2, label %bb3
bb2: ; preds = %bb1
%8 = call i32 (i8*, ...)* @printf(i8* getelementptr ([6 x i8]*
@"\01LC1", i32 0, i32 0)) nounwind ; <i32> [#uses=0]
br label %bb12
bb3: ; preds = %bb1
%9 = load i32* %x_addr, align 4 ; <i32> [#uses=1]
%10 = icmp eq i32 %9, 111 ; <i1> [#uses=1]
br i1 %10, label %bb4, label %bb5
bb4: ; preds = %bb3
%11 = call i32 (i8*, ...)* @printf(i8* getelementptr ([5 x i8]*
@"\01LC2", i32 0, i32 0)) nounwind ; <i32> [#uses=0]
br label %bb12
bb5: ; preds = %bb3
%12 = load i32* %x_addr, align 4 ; <i32> [#uses=1]
%13 = and i32 %12, 255 ; <i32> [#uses=1]
%14 = icmp eq i32 %13, 15 ; <i1> [#uses=1]
br i1 %14, label %bb6, label %bb7
bb6: ; preds = %bb5
%15 = load i32* %x_addr, align 4 ; <i32> [#uses=1]
%16 = ashr i32 %15, 8 ; <i32> [#uses=1]
%17 = call i32 (i8*, ...)* @printf(i8* getelementptr ([5 x i8]*
@"\01LC3", i32 0, i32 0), i32 %16) nounwind ; <i32> [#uses=0]
br label %bb12
bb7: ; preds = %bb5
%18 = load i32* %x_addr, align 4 ; <i32> [#uses=1]
%19 = and i32 %18, 3 ; <i32> [#uses=1]
%20 = icmp eq i32 %19, 1 ; <i1> [#uses=1]
br i1 %20, label %bb8, label %bb9
bb8: ; preds = %bb7
%21 = call i32 (i8*, ...)* @printf(i8* getelementptr ([16 x i8]*
@"\01LC4", i32 0, i32 0)) nounwind ; <i32> [#uses=0]
br label %bb12
bb9: ; preds = %bb7
%22 = load i32* %x_addr, align 4 ; <i32> [#uses=1]
%23 = icmp eq i32 %22, 63 ; <i1> [#uses=1]
br i1 %23, label %bb10, label %bb11
bb10: ; preds = %bb9
%24 = call i32 (i8*, ...)* @printf(i8* getelementptr ([5 x i8]*
@"\01LC5", i32 0, i32 0)) nounwind ; <i32> [#uses=0]
br label %bb12
bb11: ; preds = %bb9
%25 = load i32* %x_addr, align 4 ; <i32> [#uses=1]
%26 = call i32 (i8*, ...)* @printf(i8* getelementptr ([18 x i8]*
@"\01LC6", i32 0, i32 0), i32 %25) nounwind ; <i32> [#uses=0]
br label %bb12
bb12: ; preds = %bb11, %bb10, %bb8, %bb6, %bb4, %bb2, %bb
%27 = call i32 @putchar(i32 10) nounwind ; <i32> [#uses=0]
br label %return
return: ; preds = %bb12
ret void
}
declare i32 @printf(i8*, ...) nounwind
declare i32 @putchar(i32)
define i32 @main(i32 %argc, i8** %argv) nounwind {
entry:
%argc_addr = alloca i32 ; <i32*> [#uses=1]
%argv_addr = alloca i8** ; <i8***> [#uses=1]
%retval = alloca i32 ; <i32*> [#uses=2]
%result = alloca i32 ; <i32*> [#uses=2]
%0 = alloca i32 ; <i32*> [#uses=2]
%"alloca point" = bitcast i32 0 to i32 ; <i32> [#uses=0]
store i32 %argc, i32* %argc_addr
store i8** %argv, i8*** %argv_addr
%1 = call i32 @scheme_entry() nounwind ; <i32> [#uses=1]
store i32 %1, i32* %result, align 4
%2 = load i32* @error_code, align 4 ; <i32> [#uses=1]
%3 = icmp ne i32 %2, 0 ; <i1> [#uses=1]
br i1 %3, label %bb, label %bb1
bb: ; preds = %entry
%4 = load i32* @error_code, align 4 ; <i32> [#uses=1]
%5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([45 x i8]*
@"\01LC7", i32 0, i32 0), i32 %4) nounwind ; <i32> [#uses=0]
%6 = load i32* @error_val, align 4 ; <i32> [#uses=1]
call void @print_val(i32 %6) nounwind
call void @exit(i32 0) noreturn nounwind
unreachable
bb1: ; preds = %entry
%7 = load i32* %result, align 4 ; <i32> [#uses=1]
call void @print_val(i32 %7) nounwind
store i32 0, i32* %0, align 4
%8 = load i32* %0, align 4 ; <i32> [#uses=1]
store i32 %8, i32* %retval, align 4
br label %return
return: ; preds = %bb1
%retval2 = load i32* %retval ; <i32> [#uses=1]
ret i32 %retval2
}
declare void @exit(i32) noreturn nounwind