// #target: macos-x64

faultdef TEST;

macro foo(int x)
{
    if (x) return x;
    return TEST~;
}

extern fn void printf(char*, ...);

fn int main()
{
    int? a = foo(1);

    int? b = foo((a + 3) ?? 2);
    int? c = foo(0);
    (void)printf("a = %d\n", a);
    (void)printf("b = %d\n", b);
    (void)printf("c = %d\n", c);
    if (@catch(c)) printf("c had error\n");
    c = 3;
    (void)printf("c = %d\n", c);
    return 0;
}

/* #expect: failable_catch.ll

define i32 @main() #0 {
entry:
  %a = alloca i32, align 4
  %a.f = alloca i64, align 8
  %blockret = alloca i32, align 4
  %b = alloca i32, align 4
  %b.f = alloca i64, align 8
  %blockret1 = alloca i32, align 4
  %c = alloca i32, align 4
  %c.f = alloca i64, align 8
  %blockret19 = alloca i64, align 8
  %f = alloca i64, align 8
  br label %if.then

if.then:                                          ; preds = %entry
  store i32 1, ptr %blockret, align 4
  br label %expr_block.exit

expr_block.exit:                                  ; preds = %if.then
  %0 = load i32, ptr %blockret, align 4
  store i32 %0, ptr %a, align 4
  store i64 0, ptr %a.f, align 8
  br label %after_assign

after_assign:                                     ; preds = %expr_block.exit
  %optval = load i64, ptr %a.f, align 8
  %not_err = icmp eq i64 %optval, 0
  %1 = call i1 @llvm.expect.i1(i1 %not_err, i1 true)
  br i1 %1, label %after_check, label %else_block

after_check:                                      ; preds = %after_assign
  %2 = load i32, ptr %a, align 4
  %add = add i32 %2, 3
  br label %phi_block

else_block:                                       ; preds = %after_assign
  br label %phi_block

phi_block:                                        ; preds = %else_block, %after_check
  %val = phi i32 [ %add, %after_check ], [ 2, %else_block ]
  %i2b = icmp ne i32 %val, 0
  br i1 %i2b, label %if.then2, label %if.exit

if.then2:                                         ; preds = %phi_block
  store i32 %val, ptr %blockret1, align 4
  br label %expr_block.exit3

if.exit:                                          ; preds = %phi_block
  store i64 ptrtoint (ptr @failable_catch.TEST to i64), ptr %b.f, align 8
  br label %after_assign4

expr_block.exit3:                                 ; preds = %if.then2
  %3 = load i32, ptr %blockret1, align 4
  store i32 %3, ptr %b, align 4
  store i64 0, ptr %b.f, align 8
  br label %after_assign4

after_assign4:                                    ; preds = %expr_block.exit3, %if.exit
  br label %if.exit6

if.exit6:                                         ; preds = %after_assign4
  store i64 ptrtoint (ptr @failable_catch.TEST to i64), ptr %c.f, align 8
  br label %after_assign7

after_assign7:                                    ; preds = %if.exit6
  %optval8 = load i64, ptr %a.f, align 8
  %not_err9 = icmp eq i64 %optval8, 0
  %4 = call i1 @llvm.expect.i1(i1 %not_err9, i1 true)
  br i1 %4, label %after_check10, label %voiderr

after_check10:                                    ; preds = %after_assign7
  %5 = load i32, ptr %a, align 4
  call void (ptr, ...) @printf(ptr @.str, i32 %5)
  br label %voiderr

voiderr:                                          ; preds = %after_check10, %after_assign7
  %optval11 = load i64, ptr %b.f, align 8
  %not_err12 = icmp eq i64 %optval11, 0
  %6 = call i1 @llvm.expect.i1(i1 %not_err12, i1 true)
  br i1 %6, label %after_check13, label %voiderr14

after_check13:                                    ; preds = %voiderr
  %7 = load i32, ptr %b, align 4
  call void (ptr, ...) @printf(ptr @.str.1, i32 %7)
  br label %voiderr14

voiderr14:                                        ; preds = %after_check13, %voiderr
  %optval15 = load i64, ptr %c.f, align 8
  %not_err16 = icmp eq i64 %optval15, 0
  %8 = call i1 @llvm.expect.i1(i1 %not_err16, i1 true)
  br i1 %8, label %after_check17, label %voiderr18

after_check17:                                    ; preds = %voiderr14
  %9 = load i32, ptr %c, align 4
  call void (ptr, ...) @printf(ptr @.str.2, i32 %9)
  br label %voiderr18

voiderr18:                                        ; preds = %after_check17, %voiderr14
  br label %testblock

testblock:                                        ; preds = %voiderr18
  %optval20 = load i64, ptr %c.f, align 8
  %not_err21 = icmp eq i64 %optval20, 0
  %10 = call i1 @llvm.expect.i1(i1 %not_err21, i1 true)
  br i1 %10, label %after_check22, label %assign_optional

assign_optional:                                  ; preds = %testblock
  store i64 %optval20, ptr %f, align 8
  br label %end_block

after_check22:                                    ; preds = %testblock
  store i64 0, ptr %f, align 8
  br label %end_block

end_block:                                        ; preds = %after_check22, %assign_optional
  %11 = load i64, ptr %f, align 8
  %i2b23 = icmp ne i64 %11, 0
  br i1 %i2b23, label %if.then24, label %if.exit25

if.then24:                                        ; preds = %end_block
  %12 = load i64, ptr %f, align 8
  store i64 %12, ptr %blockret19, align 8
  br label %expr_block.exit26

if.exit25:                                        ; preds = %end_block
  store i64 0, ptr %blockret19, align 8
  br label %expr_block.exit26

expr_block.exit26:                                ; preds = %if.exit25, %if.then24
  %13 = load i64, ptr %blockret19, align 8
  %i2b27 = icmp ne i64 %13, 0
  br i1 %i2b27, label %if.then28, label %if.exit29

if.then28:                                        ; preds = %expr_block.exit26
  call void (ptr, ...) @printf(ptr @.str.3)
  br label %if.exit29

if.exit29:                                        ; preds = %if.then28, %expr_block.exit26
  store i32 3, ptr %c, align 4
  store i64 0, ptr %c.f, align 8
  %optval30 = load i64, ptr %c.f, align 8
  %not_err31 = icmp eq i64 %optval30, 0
  %14 = call i1 @llvm.expect.i1(i1 %not_err31, i1 true)
  br i1 %14, label %after_check32, label %voiderr33

after_check32:                                    ; preds = %if.exit29
  %15 = load i32, ptr %c, align 4
  call void (ptr, ...) @printf(ptr @.str.4, i32 %15)
  br label %voiderr33

voiderr33:                                        ; preds = %after_check32, %if.exit29
  ret i32 0
}
