// #target: macos-x64
module foo;
import std::io;

faultdef ABC;

fn void blurb() { io::printn("Blurb");}

macro int? tester()
{
	defer blurb();
	return ABC~;
}
fn void? test(int x)
{
	io::printfn("test(%d)", x);
	if (x || (tester()!)) io::printn("Ok1");
	io::printn("Test next");
	if (tester()! || x) io::printn("Ok?");
	io::printn("Test ok");
}

fn void? test2(int x)
{
	io::printfn("test2(%d)", x);
	if (x && (tester()!)) io::printn("Ok1");
	io::printn("Test next");
	if ((tester()!) && x) io::printn("Ok?");
	io::printn("Test ok");
}

fn void main()
{
	fault a = @catch(test(0));
	fault b = @catch(test(1));
	fault c = @catch(test2(0));
	fault d = @catch(test2(1));
}

/* #expect: foo.ll

define i64 @foo.test(i32 %0) #0 {
entry:
  %varargslots = alloca [1 x %any], align 16
  %taddr = alloca i32, align 4
  %retparam = alloca i64, align 8
  %error_var = alloca i64, align 8
  %blockret = alloca i32, align 4
  %len = alloca i64, align 8
  %error_var2 = alloca i64, align 8
  %retparam4 = alloca i64, align 8
  %error_var6 = alloca i64, align 8
  %error_var12 = alloca i64, align 8
  %len19 = alloca i64, align 8
  %error_var20 = alloca i64, align 8
  %retparam22 = alloca i64, align 8
  %error_var28 = alloca i64, align 8
  %error_var34 = alloca i64, align 8
  %error_var42 = alloca i64, align 8
  %blockret43 = alloca i32, align 4
  store i32 %0, ptr %taddr, align 4
  %1 = insertvalue %any undef, ptr %taddr, 0
  %2 = insertvalue %any %1, i64 ptrtoint (ptr @"$ct.int" to i64), 1
  store %any %2, ptr %varargslots, align 16
  %3 = call i64 @std.io.printfn(ptr %retparam, ptr @.str.1, i64 8, ptr %varargslots, i64 1)
  %i2b = icmp ne i32 %0, 0
  br i1 %i2b, label %or.phi, label %or.rhs

or.rhs:                                           ; preds = %entry
  store i64 ptrtoint (ptr @foo.ABC to i64), ptr %error_var, align 8
  br label %opt_block_cleanup

opt_block_cleanup:                                ; preds = %or.rhs
  call void @foo.blurb()
  br label %guard_block

guard_block:                                      ; preds = %opt_block_cleanup
  %4 = load i64, ptr %error_var, align 8
  ret i64 %4

or.phi:                                           ; preds = %entry
  br label %if.then

if.then:                                          ; preds = %or.phi
  %5 = call ptr @std.io.stdout()
  %6 = call i64 @std.io.File.write(ptr %retparam4, ptr %5, ptr @.str.2, i64 3)
  %not_err = icmp eq i64 %6, 0
  %7 = call i1 @llvm.expect.i1(i1 %not_err, i1 true)
  br i1 %7, label %after_check, label %assign_optional

assign_optional:                                  ; preds = %if.then
  store i64 %6, ptr %error_var2, align 8
  br label %guard_block5

after_check:                                      ; preds = %if.then
  br label %noerr_block

guard_block5:                                     ; preds = %assign_optional
  br label %voiderr

noerr_block:                                      ; preds = %after_check
  %8 = load i64, ptr %retparam4, align 8
  store i64 %8, ptr %len, align 8
  %9 = call i64 @std.io.File.write_byte(ptr %5, i8 zeroext 10)
  %not_err7 = icmp eq i64 %9, 0
  %10 = call i1 @llvm.expect.i1(i1 %not_err7, i1 true)
  br i1 %10, label %after_check9, label %assign_optional8

assign_optional8:                                 ; preds = %noerr_block
  store i64 %9, ptr %error_var6, align 8
  br label %guard_block10

after_check9:                                     ; preds = %noerr_block
  br label %noerr_block11

guard_block10:                                    ; preds = %assign_optional8
  br label %voiderr

noerr_block11:                                    ; preds = %after_check9
  %11 = call i64 @std.io.File.flush(ptr %5)
  %not_err13 = icmp eq i64 %11, 0
  %12 = call i1 @llvm.expect.i1(i1 %not_err13, i1 true)
  br i1 %12, label %after_check15, label %assign_optional14

assign_optional14:                                ; preds = %noerr_block11
  store i64 %11, ptr %error_var12, align 8
  br label %guard_block16

after_check15:                                    ; preds = %noerr_block11
  br label %noerr_block17

guard_block16:                                    ; preds = %assign_optional14
  br label %voiderr

noerr_block17:                                    ; preds = %after_check15
  %13 = load i64, ptr %len, align 8
  %add = add i64 %13, 1
  br label %voiderr

voiderr:                                          ; preds = %noerr_block17, %guard_block16, %guard_block10, %guard_block5
  br label %if.exit

if.exit:                                          ; preds = %voiderr
  %14 = call ptr @std.io.stdout()
  %15 = call i64 @std.io.File.write(ptr %retparam22, ptr %14, ptr @.str.3, i64 9)
  %not_err23 = icmp eq i64 %15, 0
  %16 = call i1 @llvm.expect.i1(i1 %not_err23, i1 true)
  br i1 %16, label %after_check25, label %assign_optional24

assign_optional24:                                ; preds = %if.exit
  store i64 %15, ptr %error_var20, align 8
  br label %guard_block26

after_check25:                                    ; preds = %if.exit
  br label %noerr_block27

guard_block26:                                    ; preds = %assign_optional24
  br label %voiderr41

noerr_block27:                                    ; preds = %after_check25
  %17 = load i64, ptr %retparam22, align 8
  store i64 %17, ptr %len19, align 8
  %18 = call i64 @std.io.File.write_byte(ptr %14, i8 zeroext 10)
  %not_err29 = icmp eq i64 %18, 0
  %19 = call i1 @llvm.expect.i1(i1 %not_err29, i1 true)
  br i1 %19, label %after_check31, label %assign_optional30

assign_optional30:                                ; preds = %noerr_block27
  store i64 %18, ptr %error_var28, align 8
  br label %guard_block32

after_check31:                                    ; preds = %noerr_block27
  br label %noerr_block33

guard_block32:                                    ; preds = %assign_optional30
  br label %voiderr41

noerr_block33:                                    ; preds = %after_check31
  %20 = call i64 @std.io.File.flush(ptr %14)
  %not_err35 = icmp eq i64 %20, 0
  %21 = call i1 @llvm.expect.i1(i1 %not_err35, i1 true)
  br i1 %21, label %after_check37, label %assign_optional36

assign_optional36:                                ; preds = %noerr_block33
  store i64 %20, ptr %error_var34, align 8
  br label %guard_block38

after_check37:                                    ; preds = %noerr_block33
  br label %noerr_block39

guard_block38:                                    ; preds = %assign_optional36
  br label %voiderr41

noerr_block39:                                    ; preds = %after_check37
  %22 = load i64, ptr %len19, align 8
  %add40 = add i64 %22, 1
  br label %voiderr41

voiderr41:                                        ; preds = %noerr_block39, %guard_block38, %guard_block32, %guard_block26
  store i64 ptrtoint (ptr @foo.ABC to i64), ptr %error_var42, align 8
  br label %opt_block_cleanup44

opt_block_cleanup44:                              ; preds = %voiderr41
  call void @foo.blurb()
  br label %guard_block45

guard_block45:                                    ; preds = %opt_block_cleanup44
  %23 = load i64, ptr %error_var42, align 8
  ret i64 %23
}

; Function Attrs:
define i64 @foo.test2(i32 %0) #0 {
entry:
  %varargslots = alloca [1 x %any], align 16
  %taddr = alloca i32, align 4
  %retparam = alloca i64, align 8
  %error_var = alloca i64, align 8
  %blockret = alloca i32, align 4
  %len = alloca i64, align 8
  %error_var2 = alloca i64, align 8
  %retparam4 = alloca i64, align 8
  %error_var6 = alloca i64, align 8
  %error_var12 = alloca i64, align 8
  %error_var18 = alloca i64, align 8
  %blockret19 = alloca i32, align 4
  store i32 %0, ptr %taddr, align 4
  %1 = insertvalue %any undef, ptr %taddr, 0
  %2 = insertvalue %any %1, i64 ptrtoint (ptr @"$ct.int" to i64), 1
  store %any %2, ptr %varargslots, align 16
  %3 = call i64 @std.io.printfn(ptr %retparam, ptr @.str.4, i64 9, ptr %varargslots, i64 1)
  %i2b = icmp ne i32 %0, 0
  br i1 %i2b, label %and.rhs, label %and.phi

and.rhs:                                          ; preds = %entry
  store i64 ptrtoint (ptr @foo.ABC to i64), ptr %error_var, align 8
  br label %opt_block_cleanup

opt_block_cleanup:                                ; preds = %and.rhs
  call void @foo.blurb()
  br label %guard_block

guard_block:                                      ; preds = %opt_block_cleanup
  %4 = load i64, ptr %error_var, align 8
  ret i64 %4

and.phi:                                          ; preds = %entry
  br label %if.exit

if.exit:                                          ; preds = %and.phi
  %5 = call ptr @std.io.stdout()
  %6 = call i64 @std.io.File.write(ptr %retparam4, ptr %5, ptr @.str.5, i64 9)
  %not_err = icmp eq i64 %6, 0
  %7 = call i1 @llvm.expect.i1(i1 %not_err, i1 true)
  br i1 %7, label %after_check, label %assign_optional

assign_optional:                                  ; preds = %if.exit
  store i64 %6, ptr %error_var2, align 8
  br label %guard_block5

after_check:                                      ; preds = %if.exit
  br label %noerr_block

guard_block5:                                     ; preds = %assign_optional
  br label %voiderr

noerr_block:                                      ; preds = %after_check
  %8 = load i64, ptr %retparam4, align 8
  store i64 %8, ptr %len, align 8
  %9 = call i64 @std.io.File.write_byte(ptr %5, i8 zeroext 10)
  %not_err7 = icmp eq i64 %9, 0
  %10 = call i1 @llvm.expect.i1(i1 %not_err7, i1 true)
  br i1 %10, label %after_check9, label %assign_optional8

assign_optional8:                                 ; preds = %noerr_block
  store i64 %9, ptr %error_var6, align 8
  br label %guard_block10

after_check9:                                     ; preds = %noerr_block
  br label %noerr_block11

guard_block10:                                    ; preds = %assign_optional8
  br label %voiderr

noerr_block11:                                    ; preds = %after_check9
  %11 = call i64 @std.io.File.flush(ptr %5)
  %not_err13 = icmp eq i64 %11, 0
  %12 = call i1 @llvm.expect.i1(i1 %not_err13, i1 true)
  br i1 %12, label %after_check15, label %assign_optional14

assign_optional14:                                ; preds = %noerr_block11
  store i64 %11, ptr %error_var12, align 8
  br label %guard_block16

after_check15:                                    ; preds = %noerr_block11
  br label %noerr_block17

guard_block16:                                    ; preds = %assign_optional14
  br label %voiderr

noerr_block17:                                    ; preds = %after_check15
  %13 = load i64, ptr %len, align 8
  %add = add i64 %13, 1
  br label %voiderr

voiderr:                                          ; preds = %noerr_block17, %guard_block16, %guard_block10, %guard_block5
  store i64 ptrtoint (ptr @foo.ABC to i64), ptr %error_var18, align 8
  br label %opt_block_cleanup20

opt_block_cleanup20:                              ; preds = %voiderr
  call void @foo.blurb()
  br label %guard_block21

guard_block21:                                    ; preds = %opt_block_cleanup20
  %14 = load i64, ptr %error_var18, align 8
  ret i64 %14
}

; Function Attrs:
define void @foo.main() #0 {
entry:
  %a = alloca i64, align 8
  %blockret = alloca i64, align 8
  %f = alloca i64, align 8
  %b = alloca i64, align 8
  %blockret1 = alloca i64, align 8
  %f2 = alloca i64, align 8
  %c = alloca i64, align 8
  %blockret12 = alloca i64, align 8
  %f13 = alloca i64, align 8
  %d = alloca i64, align 8
  %blockret23 = alloca i64, align 8
  %f24 = alloca i64, align 8
  br label %testblock

testblock:                                        ; preds = %entry
  %0 = call i64 @foo.test(i32 0)
  %not_err = icmp eq i64 %0, 0
  %1 = call i1 @llvm.expect.i1(i1 %not_err, i1 true)
  br i1 %1, label %after_check, label %assign_optional

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

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

end_block:                                        ; preds = %after_check, %assign_optional
  %2 = load i64, ptr %f, align 8
  %i2b = icmp ne i64 %2, 0
  br i1 %i2b, label %if.then, label %if.exit

if.then:                                          ; preds = %end_block
  %3 = load i64, ptr %f, align 8
  store i64 %3, ptr %blockret, align 8
  br label %expr_block.exit

if.exit:                                          ; preds = %end_block
  store i64 0, ptr %blockret, align 8
  br label %expr_block.exit

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

testblock3:                                       ; preds = %expr_block.exit
  %5 = call i64 @foo.test(i32 1)
  %not_err4 = icmp eq i64 %5, 0
  %6 = call i1 @llvm.expect.i1(i1 %not_err4, i1 true)
  br i1 %6, label %after_check6, label %assign_optional5

assign_optional5:                                 ; preds = %testblock3
  store i64 %5, ptr %f2, align 8
  br label %end_block7

after_check6:                                     ; preds = %testblock3
  store i64 0, ptr %f2, align 8
  br label %end_block7

end_block7:                                       ; preds = %after_check6, %assign_optional5
  %7 = load i64, ptr %f2, align 8
  %i2b8 = icmp ne i64 %7, 0
  br i1 %i2b8, label %if.then9, label %if.exit10

if.then9:                                         ; preds = %end_block7
  %8 = load i64, ptr %f2, align 8
  store i64 %8, ptr %blockret1, align 8
  br label %expr_block.exit11

if.exit10:                                        ; preds = %end_block7
  store i64 0, ptr %blockret1, align 8
  br label %expr_block.exit11

expr_block.exit11:                                ; preds = %if.exit10, %if.then9
  %9 = load i64, ptr %blockret1, align 8
  store i64 %9, ptr %b, align 8
  br label %testblock14

testblock14:                                      ; preds = %expr_block.exit11
  %10 = call i64 @foo.test2(i32 0)
  %not_err15 = icmp eq i64 %10, 0
  %11 = call i1 @llvm.expect.i1(i1 %not_err15, i1 true)
  br i1 %11, label %after_check17, label %assign_optional16

assign_optional16:                                ; preds = %testblock14
  store i64 %10, ptr %f13, align 8
  br label %end_block18

after_check17:                                    ; preds = %testblock14
  store i64 0, ptr %f13, align 8
  br label %end_block18

end_block18:                                      ; preds = %after_check17, %assign_optional16
  %12 = load i64, ptr %f13, align 8
  %i2b19 = icmp ne i64 %12, 0
  br i1 %i2b19, label %if.then20, label %if.exit21

if.then20:                                        ; preds = %end_block18
  %13 = load i64, ptr %f13, align 8
  store i64 %13, ptr %blockret12, align 8
  br label %expr_block.exit22

if.exit21:                                        ; preds = %end_block18
  store i64 0, ptr %blockret12, align 8
  br label %expr_block.exit22

expr_block.exit22:                                ; preds = %if.exit21, %if.then20
  %14 = load i64, ptr %blockret12, align 8
  store i64 %14, ptr %c, align 8
  br label %testblock25

testblock25:                                      ; preds = %expr_block.exit22
  %15 = call i64 @foo.test2(i32 1)
  %not_err26 = icmp eq i64 %15, 0
  %16 = call i1 @llvm.expect.i1(i1 %not_err26, i1 true)
  br i1 %16, label %after_check28, label %assign_optional27

assign_optional27:                                ; preds = %testblock25
  store i64 %15, ptr %f24, align 8
  br label %end_block29

after_check28:                                    ; preds = %testblock25
  store i64 0, ptr %f24, align 8
  br label %end_block29

end_block29:                                      ; preds = %after_check28, %assign_optional27
  %17 = load i64, ptr %f24, align 8
  %i2b30 = icmp ne i64 %17, 0
  br i1 %i2b30, label %if.then31, label %if.exit32

if.then31:                                        ; preds = %end_block29
  %18 = load i64, ptr %f24, align 8
  store i64 %18, ptr %blockret23, align 8
  br label %expr_block.exit33

if.exit32:                                        ; preds = %end_block29
  store i64 0, ptr %blockret23, align 8
  br label %expr_block.exit33

expr_block.exit33:                                ; preds = %if.exit32, %if.then31
  %19 = load i64, ptr %blockret23, align 8
  store i64 %19, ptr %d, align 8
  ret void
}

; Function Attrs:
define i32 @main(i32 %0, ptr %1) #0 {
entry:
  call void @foo.main()
  ret i32 0
}
