// #target: macos-x64
module foo;
import std::io;
import libc;
faultdef
    X,
    Y,
    Z,
    W,
    W1;

faultdef X1, Y2;

typedef Bar = int;

enum MyEnum
{
    A,
    B
}

fn void Bar.hello(Bar *b)
{
    io::printn("Hello from Bar");
}

fn void MyEnum.hello(MyEnum *myenum)
{
    io::printn("Hello from MyEnum");
}
fn void main()
{
    fault f = X;
    fault ef = Y;
    fault x = f;
    ulong z = (ulong)(x);
    libc::printf("1: %p\n", z);
    x = ef;
    z = (ulong)(x);
    libc::printf("2: %p\n", z);
    x = W;
    z = (ulong)(x);
    libc::printf("21: %p\n", z);
    x = W1;
    z = (ulong)(x);
    libc::printf("22: %p\n", z);
    x = X1;
    z = (ulong)(x);
    libc::printf("3: %p\n", z);
    x = Y2;
    z = (ulong)(x);
    libc::printf("4: %p\n", z);
    Bar b;
    MyEnum a = MyEnum.A;
    b.hello();
    a.hello();
}

/* #expect: foo.ll

define void @foo.Bar.hello(ptr %0) #0 {
entry:
  %len = alloca i64, align 8
  %error_var = alloca i64, align 8
  %retparam = alloca i64, align 8
  %error_var2 = alloca i64, align 8
  %error_var8 = alloca i64, align 8
  %1 = call ptr @std.io.stdout()
  %2 = call i64 @std.io.File.write(ptr %retparam, ptr %1, ptr @.str.6, i64 14)
  %not_err = icmp eq i64 %2, 0
  %3 = call i1 @llvm.expect.i1(i1 %not_err, i1 true)
  br i1 %3, label %after_check, label %assign_optional

assign_optional:                                  ; preds = %entry
  store i64 %2, ptr %error_var, align 8
  br label %guard_block

after_check:                                      ; preds = %entry
  br label %noerr_block

guard_block:                                      ; preds = %assign_optional
  br label %voiderr

noerr_block:                                      ; preds = %after_check
  %4 = load i64, ptr %retparam, align 8
  store i64 %4, ptr %len, align 8
  %5 = call i64 @std.io.File.write_byte(ptr %1, i8 zeroext 10)
  %not_err3 = icmp eq i64 %5, 0
  %6 = call i1 @llvm.expect.i1(i1 %not_err3, i1 true)
  br i1 %6, label %after_check5, label %assign_optional4

assign_optional4:                                 ; preds = %noerr_block
  store i64 %5, ptr %error_var2, align 8
  br label %guard_block6

after_check5:                                     ; preds = %noerr_block
  br label %noerr_block7

guard_block6:                                     ; preds = %assign_optional4
  br label %voiderr

noerr_block7:                                     ; preds = %after_check5
  %7 = call i64 @std.io.File.flush(ptr %1)
  %not_err9 = icmp eq i64 %7, 0
  %8 = call i1 @llvm.expect.i1(i1 %not_err9, i1 true)
  br i1 %8, label %after_check11, label %assign_optional10

assign_optional10:                                ; preds = %noerr_block7
  store i64 %7, ptr %error_var8, align 8
  br label %guard_block12

after_check11:                                    ; preds = %noerr_block7
  br label %noerr_block13

guard_block12:                                    ; preds = %assign_optional10
  br label %voiderr

noerr_block13:                                    ; preds = %after_check11
  %9 = load i64, ptr %len, align 8
  %add = add i64 %9, 1
  br label %voiderr

voiderr:                                          ; preds = %noerr_block13, %guard_block12, %guard_block6, %guard_block
  ret void
}


define void @foo.MyEnum.hello(ptr %0) #0 {
entry:
  %len = alloca i64, align 8
  %error_var = alloca i64, align 8
  %retparam = alloca i64, align 8
  %error_var2 = alloca i64, align 8
  %error_var8 = alloca i64, align 8
  %1 = call ptr @std.io.stdout()
  %2 = call i64 @std.io.File.write(ptr %retparam, ptr %1, ptr @.str.7, i64 17)
  %not_err = icmp eq i64 %2, 0
  %3 = call i1 @llvm.expect.i1(i1 %not_err, i1 true)
  br i1 %3, label %after_check, label %assign_optional

assign_optional:                                  ; preds = %entry
  store i64 %2, ptr %error_var, align 8
  br label %guard_block

after_check:                                      ; preds = %entry
  br label %noerr_block

guard_block:                                      ; preds = %assign_optional
  br label %voiderr

noerr_block:                                      ; preds = %after_check
  %4 = load i64, ptr %retparam, align 8
  store i64 %4, ptr %len, align 8
  %5 = call i64 @std.io.File.write_byte(ptr %1, i8 zeroext 10)
  %not_err3 = icmp eq i64 %5, 0
  %6 = call i1 @llvm.expect.i1(i1 %not_err3, i1 true)
  br i1 %6, label %after_check5, label %assign_optional4

assign_optional4:                                 ; preds = %noerr_block
  store i64 %5, ptr %error_var2, align 8
  br label %guard_block6

after_check5:                                     ; preds = %noerr_block
  br label %noerr_block7

guard_block6:                                     ; preds = %assign_optional4
  br label %voiderr

noerr_block7:                                     ; preds = %after_check5
  %7 = call i64 @std.io.File.flush(ptr %1)
  %not_err9 = icmp eq i64 %7, 0
  %8 = call i1 @llvm.expect.i1(i1 %not_err9, i1 true)
  br i1 %8, label %after_check11, label %assign_optional10

assign_optional10:                                ; preds = %noerr_block7
  store i64 %7, ptr %error_var8, align 8
  br label %guard_block12

after_check11:                                    ; preds = %noerr_block7
  br label %noerr_block13

guard_block12:                                    ; preds = %assign_optional10
  br label %voiderr

noerr_block13:                                    ; preds = %after_check11
  %9 = load i64, ptr %len, align 8
  %add = add i64 %9, 1
  br label %voiderr

voiderr:                                          ; preds = %noerr_block13, %guard_block12, %guard_block6, %guard_block
  ret void
}


define void @foo.main() #0 {
entry:
  %f = alloca i64, align 8
  %ef = alloca i64, align 8
  %x = alloca i64, align 8
  %z = alloca i64, align 8
  %b = alloca i32, align 4
  %a = alloca i32, align 4
  store i64 ptrtoint (ptr @foo.X to i64), ptr %f, align 8
  store i64 ptrtoint (ptr @foo.Y to i64), ptr %ef, align 8
  %0 = load i64, ptr %f, align 8
  store i64 %0, ptr %x, align 8
  %1 = load i64, ptr %x, align 8
  store i64 %1, ptr %z, align 8
  %2 = load i64, ptr %z, align 8
  %3 = call i32 (ptr, ...) @printf(ptr @.str, i64 %2)
  %4 = load i64, ptr %ef, align 8
  store i64 %4, ptr %x, align 8
  %5 = load i64, ptr %x, align 8
  store i64 %5, ptr %z, align 8
  %6 = load i64, ptr %z, align 8
  %7 = call i32 (ptr, ...) @printf(ptr @.str.1, i64 %6)
  store i64 ptrtoint (ptr @foo.W to i64), ptr %x, align 8
  %8 = load i64, ptr %x, align 8
  store i64 %8, ptr %z, align 8
  %9 = load i64, ptr %z, align 8
  %10 = call i32 (ptr, ...) @printf(ptr @.str.2, i64 %9)
  store i64 ptrtoint (ptr @foo.W1 to i64), ptr %x, align 8
  %11 = load i64, ptr %x, align 8
  store i64 %11, ptr %z, align 8
  %12 = load i64, ptr %z, align 8
  %13 = call i32 (ptr, ...) @printf(ptr @.str.3, i64 %12)
  store i64 ptrtoint (ptr @foo.X1 to i64), ptr %x, align 8
  %14 = load i64, ptr %x, align 8
  store i64 %14, ptr %z, align 8
  %15 = load i64, ptr %z, align 8
  %16 = call i32 (ptr, ...) @printf(ptr @.str.4, i64 %15)
  store i64 ptrtoint (ptr @foo.Y2 to i64), ptr %x, align 8
  %17 = load i64, ptr %x, align 8
  store i64 %17, ptr %z, align 8
  %18 = load i64, ptr %z, align 8
  %19 = call i32 (ptr, ...) @printf(ptr @.str.5, i64 %18)
  store i32 0, ptr %b, align 4
  store i32 0, ptr %a, align 4
  call void @foo.Bar.hello(ptr %b)
  call void @foo.MyEnum.hello(ptr %a)
  ret void
}