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

faultdef ABC, DEF;

fn void main()
{
	io::printfn("1:%d", get_a(1) ?? get_b(4) ?? -1);
	io::printfn("2:%d", get_a(2) ?? get_b(4) ?? -1);
	io::printfn("3:%d", get_a(1) ?? get_b(5) ?? -1);
	io::printfn("4:%s", @catch(ABC? ?? DEF?));
	io::printfn("5:%s", ABC? ?? 3);
	io::printfn("6:%s", @catch((3 > 2 ? ABC? : 4) ?? DEF?));
	io::printfn("7:%s", @catch((3 < 2 ? ABC? : 4) ?? DEF?));
	long x = DEF? ?? 3;
	io::printfn("8:%s", x);
	int? xy = ABC? ?? DEF?;
}

fn int? get_a(int x)
{
	if (x % 2) return ABC?;
	return x * 2;
}

fn int? get_b(int x)
{
	if (x % 2 == 0) return ABC?;
	return x * 2;
}

/* #expect: test.ll

define void @test.main() #0 {
entry:
  %varargslots = alloca [1 x %any], align 16
  %retparam = alloca i32, align 4
  %retparam1 = alloca i32, align 4
  %taddr = alloca i32, align 4
  %retparam7 = alloca i64, align 8
  %varargslots10 = alloca [1 x %any], align 16
  %retparam11 = alloca i32, align 4
  %retparam15 = alloca i32, align 4
  %taddr23 = alloca i32, align 4
  %retparam24 = alloca i64, align 8
  %varargslots27 = alloca [1 x %any], align 16
  %retparam28 = alloca i32, align 4
  %retparam32 = alloca i32, align 4
  %taddr40 = alloca i32, align 4
  %retparam41 = alloca i64, align 8
  %varargslots44 = alloca [1 x %any], align 16
  %blockret = alloca i64, align 8
  %f = alloca i64, align 8
  %retparam45 = alloca i64, align 8
  %varargslots48 = alloca [1 x %any], align 16
  %taddr49 = alloca i32, align 4
  %retparam50 = alloca i64, align 8
  %varargslots53 = alloca [1 x %any], align 16
  %blockret54 = alloca i64, align 8
  %f55 = alloca i64, align 8
  %retparam62 = alloca i64, align 8
  %varargslots65 = alloca [1 x %any], align 16
  %blockret66 = alloca i64, align 8
  %f67 = alloca i64, align 8
  %retparam76 = alloca i64, align 8
  %x = alloca i64, align 8
  %varargslots79 = alloca [1 x %any], align 16
  %retparam80 = alloca i64, align 8
  %xy = alloca i32, align 4
  %xy.f = alloca i64, align 8
  %0 = call i64 @test.get_a(ptr %retparam, i32 1)
  %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 %else_block

after_check:                                      ; preds = %entry
  %2 = load i32, ptr %retparam, align 4
  br label %phi_block5

else_block:                                       ; preds = %entry
  %3 = call i64 @test.get_b(ptr %retparam1, i32 4)
  %not_err2 = icmp eq i64 %3, 0
  %4 = call i1 @llvm.expect.i1(i1 %not_err2, i1 true)
  br i1 %4, label %after_check3, label %else_block4

after_check3:                                     ; preds = %else_block
  %5 = load i32, ptr %retparam1, align 4
  br label %phi_block

else_block4:                                      ; preds = %else_block
  br label %phi_block

phi_block:                                        ; preds = %else_block4, %after_check3
  %val = phi i32 [ %5, %after_check3 ], [ -1, %else_block4 ]
  br label %phi_block5

phi_block5:                                       ; preds = %phi_block, %after_check
  %val6 = phi i32 [ %2, %after_check ], [ %val, %phi_block ]
  store i32 %val6, ptr %taddr, align 4
  %6 = insertvalue %any undef, ptr %taddr, 0
  %7 = insertvalue %any %6, i64 ptrtoint (ptr @"$ct.int" to i64), 1
  store %any %7, ptr %varargslots, align 16
  %8 = call i64 @std.io.printfn(ptr %retparam7, ptr @.str, i64 4, ptr %varargslots, i64 1)
  %9 = call i64 @test.get_a(ptr %retparam11, i32 2)
  %not_err12 = icmp eq i64 %9, 0
  %10 = call i1 @llvm.expect.i1(i1 %not_err12, i1 true)
  br i1 %10, label %after_check13, label %else_block14

after_check13:                                    ; preds = %phi_block5
  %11 = load i32, ptr %retparam11, align 4
  br label %phi_block21

else_block14:                                     ; preds = %phi_block5
  %12 = call i64 @test.get_b(ptr %retparam15, i32 4)
  %not_err16 = icmp eq i64 %12, 0
  %13 = call i1 @llvm.expect.i1(i1 %not_err16, i1 true)
  br i1 %13, label %after_check17, label %else_block18

after_check17:                                    ; preds = %else_block14
  %14 = load i32, ptr %retparam15, align 4
  br label %phi_block19

else_block18:                                     ; preds = %else_block14
  br label %phi_block19

phi_block19:                                      ; preds = %else_block18, %after_check17
  %val20 = phi i32 [ %14, %after_check17 ], [ -1, %else_block18 ]
  br label %phi_block21

phi_block21:                                      ; preds = %phi_block19, %after_check13
  %val22 = phi i32 [ %11, %after_check13 ], [ %val20, %phi_block19 ]
  store i32 %val22, ptr %taddr23, align 4
  %15 = insertvalue %any undef, ptr %taddr23, 0
  %16 = insertvalue %any %15, i64 ptrtoint (ptr @"$ct.int" to i64), 1
  store %any %16, ptr %varargslots10, align 16
  %17 = call i64 @std.io.printfn(ptr %retparam24, ptr @.str.1, i64 4, ptr %varargslots10, i64 1)
  %18 = call i64 @test.get_a(ptr %retparam28, i32 1)
  %not_err29 = icmp eq i64 %18, 0
  %19 = call i1 @llvm.expect.i1(i1 %not_err29, i1 true)
  br i1 %19, label %after_check30, label %else_block31

after_check30:                                    ; preds = %phi_block21
  %20 = load i32, ptr %retparam28, align 4
  br label %phi_block38

else_block31:                                     ; preds = %phi_block21
  %21 = call i64 @test.get_b(ptr %retparam32, i32 5)
  %not_err33 = icmp eq i64 %21, 0
  %22 = call i1 @llvm.expect.i1(i1 %not_err33, i1 true)
  br i1 %22, label %after_check34, label %else_block35

after_check34:                                    ; preds = %else_block31
  %23 = load i32, ptr %retparam32, align 4
  br label %phi_block36

else_block35:                                     ; preds = %else_block31
  br label %phi_block36

phi_block36:                                      ; preds = %else_block35, %after_check34
  %val37 = phi i32 [ %23, %after_check34 ], [ -1, %else_block35 ]
  br label %phi_block38

phi_block38:                                      ; preds = %phi_block36, %after_check30
  %val39 = phi i32 [ %20, %after_check30 ], [ %val37, %phi_block36 ]
  store i32 %val39, ptr %taddr40, align 4
  %24 = insertvalue %any undef, ptr %taddr40, 0
  %25 = insertvalue %any %24, i64 ptrtoint (ptr @"$ct.int" to i64), 1
  store %any %25, ptr %varargslots27, align 16
  %26 = call i64 @std.io.printfn(ptr %retparam41, ptr @.str.2, i64 4, ptr %varargslots27, i64 1)
  br label %testblock

testblock:                                        ; preds = %phi_block38
  store i64 ptrtoint (ptr @test.DEF to i64), ptr %f, align 8
  br label %end_block

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

if.then:                                          ; preds = %end_block
  %28 = load i64, ptr %f, align 8
  store i64 %28, 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
  %29 = insertvalue %any undef, ptr %blockret, 0
  %30 = insertvalue %any %29, i64 ptrtoint (ptr @"$ct.fault" to i64), 1
  store %any %30, ptr %varargslots44, align 16
  %31 = call i64 @std.io.printfn(ptr %retparam45, ptr @.str.3, i64 4, ptr %varargslots44, i64 1)
  store i32 3, ptr %taddr49, align 4
  %32 = insertvalue %any undef, ptr %taddr49, 0
  %33 = insertvalue %any %32, i64 ptrtoint (ptr @"$ct.int" to i64), 1
  store %any %33, ptr %varargslots48, align 16
  %34 = call i64 @std.io.printfn(ptr %retparam50, ptr @.str.4, i64 4, ptr %varargslots48, i64 1)
  br label %testblock56

testblock56:                                      ; preds = %expr_block.exit
  store i64 ptrtoint (ptr @test.DEF to i64), ptr %f55, align 8
  br label %end_block57

end_block57:                                      ; preds = %testblock56
  %35 = load i64, ptr %f55, align 8
  %i2b58 = icmp ne i64 %35, 0
  br i1 %i2b58, label %if.then59, label %if.exit60

if.then59:                                        ; preds = %end_block57
  %36 = load i64, ptr %f55, align 8
  store i64 %36, ptr %blockret54, align 8
  br label %expr_block.exit61

if.exit60:                                        ; preds = %end_block57
  store i64 0, ptr %blockret54, align 8
  br label %expr_block.exit61

expr_block.exit61:                                ; preds = %if.exit60, %if.then59
  %37 = insertvalue %any undef, ptr %blockret54, 0
  %38 = insertvalue %any %37, i64 ptrtoint (ptr @"$ct.fault" to i64), 1
  store %any %38, ptr %varargslots53, align 16
  %39 = call i64 @std.io.printfn(ptr %retparam62, ptr @.str.5, i64 4, ptr %varargslots53, i64 1)
  br label %testblock68

testblock68:                                      ; preds = %expr_block.exit61
  br label %phi_block70

phi_block70:                                      ; preds = %testblock68
  store i64 0, ptr %f67, align 8
  br label %end_block71

end_block71:                                      ; preds = %phi_block70
  %40 = load i64, ptr %f67, align 8
  %i2b72 = icmp ne i64 %40, 0
  br i1 %i2b72, label %if.then73, label %if.exit74

if.then73:                                        ; preds = %end_block71
  %41 = load i64, ptr %f67, align 8
  store i64 %41, ptr %blockret66, align 8
  br label %expr_block.exit75

if.exit74:                                        ; preds = %end_block71
  store i64 0, ptr %blockret66, align 8
  br label %expr_block.exit75

expr_block.exit75:                                ; preds = %if.exit74, %if.then73
  %42 = insertvalue %any undef, ptr %blockret66, 0
  %43 = insertvalue %any %42, i64 ptrtoint (ptr @"$ct.fault" to i64), 1
  store %any %43, ptr %varargslots65, align 16
  %44 = call i64 @std.io.printfn(ptr %retparam76, ptr @.str.6, i64 4, ptr %varargslots65, i64 1)
  store i64 3, ptr %x, align 8
  %45 = insertvalue %any undef, ptr %x, 0
  %46 = insertvalue %any %45, i64 ptrtoint (ptr @"$ct.long" to i64), 1
  store %any %46, ptr %varargslots79, align 16
  %47 = call i64 @std.io.printfn(ptr %retparam80, ptr @.str.7, i64 4, ptr %varargslots79, i64 1)
  store i64 ptrtoint (ptr @test.DEF to i64), ptr %xy.f, align 8
  ret void
}

; Function Attrs:
define i64 @test.get_a(ptr %0, i32 %1) #0 {
entry:
  %reterr = alloca i64, align 8
  %smod = srem i32 %1, 2
  %i2b = icmp ne i32 %smod, 0
  br i1 %i2b, label %if.then, label %if.exit

if.then:                                          ; preds = %entry
  ret i64 ptrtoint (ptr @test.ABC to i64)

if.exit:                                          ; preds = %entry
  %mul = mul i32 %1, 2
  store i32 %mul, ptr %0, align 4
  ret i64 0
}

; Function Attrs:
define i64 @test.get_b(ptr %0, i32 %1) #0 {
entry:
  %reterr = alloca i64, align 8
  %smod = srem i32 %1, 2
  %eq = icmp eq i32 %smod, 0
  br i1 %eq, label %if.then, label %if.exit

if.then:                                          ; preds = %entry
  ret i64 ptrtoint (ptr @test.ABC to i64)

if.exit:                                          ; preds = %entry
  %mul = mul i32 %1, 2
  store i32 %mul, ptr %0, align 4
  ret i64 0
}