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

enum Bar : const String
{
	XABC = "foekf",
	XDEF = "foekfokef"
}

enum Foo : const int
{
	ABC = 4,
	DEF,
	EGH = Foo.ABC + 10,
	GHH,
	HELLO = DEF
}


enum Bde2 : const int
{
	FOO = 2,
	BAR = 100
}

typedef Bde3 = int;
const BDE3_FOO = 2;
const BDE3_BAR = 100;



enum Abc2 : const int
{
	UP,
	DOWN,
}


typedef Abc4 = int;
const Abc4 ABC4_UP = 0b10;
const Abc4 ABC4_DOWN = 0b01;

bitstruct Abc3 : int
{
	bool down : 0;
	bool up : 1;
}

fn void print_bde2(Bde2 v)
{
	if (v == Bde2.FOO) io::printn("FOO!!");
}

fn void print_bde3(Bde3 v)
{
	if (v == BDE3_FOO) io::printn("FOO!!");
}


fn void print_direction2(Abc2 a)
{
	if (a & Abc2.UP) io::printn("Up");
	if (a & Abc2.DOWN) io::printn("Down");
}

fn void print_direction4(Abc4 a)
{
	if (a & ABC4_UP) io::printn("Up");
	if (a & ABC4_DOWN) io::printn("Down");
}

fn void print_direction3(Abc3 a)
{
	if (a.up) io::printn("Up");
	if (a.down) io::printn("Down");
}

fn void main()
{
	print_direction2(Abc2.UP | Abc2.DOWN);
	print_direction4(ABC4_UP | ABC4_DOWN);
	print_direction3({ .up, .down });
	print_bde2(FOO);
	print_bde3(BDE3_FOO);

}

fn int test()
{
	Bar bar = XDEF;
	Foo f = ABC;
	Foo b = Foo.ABC * Foo.ABC;
	int x = (int)Foo.ABC;
	Foo e = (Foo)4;
	return 0;
}

/* #expect: test.ll

define void @test.print_bde2(i32 %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
  %eq = icmp eq i32 %0, 2
  br i1 %eq, label %if.then, label %if.exit

if.then:                                          ; preds = %entry
  %1 = call ptr @std.io.stdout()
  %2 = call i64 @std.io.File.write(ptr %retparam, ptr %1, ptr @.str, i64 5)
  %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 = %if.then
  store i64 %2, ptr %error_var, align 8
  br label %guard_block

after_check:                                      ; preds = %if.then
  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
  br label %if.exit

if.exit:                                          ; preds = %voiderr, %entry
  ret void
}

define void @test.print_bde3(i32 %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
  %eq = icmp eq i32 %0, 2
  br i1 %eq, label %if.then, label %if.exit

if.then:                                          ; preds = %entry
  %1 = call ptr @std.io.stdout()
  %2 = call i64 @std.io.File.write(ptr %retparam, ptr %1, ptr @.str.4, i64 5)
  %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 = %if.then
  store i64 %2, ptr %error_var, align 8
  br label %guard_block

after_check:                                      ; preds = %if.then
  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
  br label %if.exit

if.exit:                                          ; preds = %voiderr, %entry
  ret void
}

define void @test.print_direction2(i32 %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
  %len17 = alloca i64, align 8
  %error_var18 = alloca i64, align 8
  %retparam20 = alloca i64, align 8
  %error_var26 = alloca i64, align 8
  %error_var32 = alloca i64, align 8
  %and = and i32 %0, 0
  %i2b = icmp ne i32 %and, 0
  br i1 %i2b, label %if.then, label %if.exit

if.then:                                          ; preds = %entry
  %1 = call ptr @std.io.stdout()
  %2 = call i64 @std.io.File.write(ptr %retparam, ptr %1, ptr @.str.5, i64 2)
  %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 = %if.then
  store i64 %2, ptr %error_var, align 8
  br label %guard_block

after_check:                                      ; preds = %if.then
  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
  br label %if.exit

if.exit:                                          ; preds = %voiderr, %entry
  %and14 = and i32 %0, 1
  %i2b15 = icmp ne i32 %and14, 0
  br i1 %i2b15, label %if.then16, label %if.exit40

if.then16:                                        ; preds = %if.exit
  %10 = call ptr @std.io.stdout()
  %11 = call i64 @std.io.File.write(ptr %retparam20, ptr %10, ptr @.str.6, i64 4)
  %not_err21 = icmp eq i64 %11, 0
  %12 = call i1 @llvm.expect.i1(i1 %not_err21, i1 true)
  br i1 %12, label %after_check23, label %assign_optional22

assign_optional22:                                ; preds = %if.then16
  store i64 %11, ptr %error_var18, align 8
  br label %guard_block24

after_check23:                                    ; preds = %if.then16
  br label %noerr_block25

guard_block24:                                    ; preds = %assign_optional22
  br label %voiderr39

noerr_block25:                                    ; preds = %after_check23
  %13 = load i64, ptr %retparam20, align 8
  store i64 %13, ptr %len17, align 8
  %14 = call i64 @std.io.File.write_byte(ptr %10, i8 zeroext 10)
  %not_err27 = icmp eq i64 %14, 0
  %15 = call i1 @llvm.expect.i1(i1 %not_err27, i1 true)
  br i1 %15, label %after_check29, label %assign_optional28

assign_optional28:                                ; preds = %noerr_block25
  store i64 %14, ptr %error_var26, align 8
  br label %guard_block30

after_check29:                                    ; preds = %noerr_block25
  br label %noerr_block31

guard_block30:                                    ; preds = %assign_optional28
  br label %voiderr39

noerr_block31:                                    ; preds = %after_check29
  %16 = call i64 @std.io.File.flush(ptr %10)
  %not_err33 = icmp eq i64 %16, 0
  %17 = call i1 @llvm.expect.i1(i1 %not_err33, i1 true)
  br i1 %17, label %after_check35, label %assign_optional34

assign_optional34:                                ; preds = %noerr_block31
  store i64 %16, ptr %error_var32, align 8
  br label %guard_block36

after_check35:                                    ; preds = %noerr_block31
  br label %noerr_block37

guard_block36:                                    ; preds = %assign_optional34
  br label %voiderr39

noerr_block37:                                    ; preds = %after_check35
  %18 = load i64, ptr %len17, align 8
  %add38 = add i64 %18, 1
  br label %voiderr39

voiderr39:                                        ; preds = %noerr_block37, %guard_block36, %guard_block30, %guard_block24
  br label %if.exit40

if.exit40:                                        ; preds = %voiderr39, %if.exit
  ret void
}

define void @test.print_direction4(i32 %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
  %len17 = alloca i64, align 8
  %error_var18 = alloca i64, align 8
  %retparam20 = alloca i64, align 8
  %error_var26 = alloca i64, align 8
  %error_var32 = alloca i64, align 8
  %and = and i32 %0, 2
  %i2b = icmp ne i32 %and, 0
  br i1 %i2b, label %if.then, label %if.exit

if.then:                                          ; preds = %entry
  %1 = call ptr @std.io.stdout()
  %2 = call i64 @std.io.File.write(ptr %retparam, ptr %1, ptr @.str.7, i64 2)
  %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 = %if.then
  store i64 %2, ptr %error_var, align 8
  br label %guard_block

after_check:                                      ; preds = %if.then
  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
  br label %if.exit

if.exit:                                          ; preds = %voiderr, %entry
  %and14 = and i32 %0, 1
  %i2b15 = icmp ne i32 %and14, 0
  br i1 %i2b15, label %if.then16, label %if.exit40

if.then16:                                        ; preds = %if.exit
  %10 = call ptr @std.io.stdout()
  %11 = call i64 @std.io.File.write(ptr %retparam20, ptr %10, ptr @.str.8, i64 4)
  %not_err21 = icmp eq i64 %11, 0
  %12 = call i1 @llvm.expect.i1(i1 %not_err21, i1 true)
  br i1 %12, label %after_check23, label %assign_optional22

assign_optional22:                                ; preds = %if.then16
  store i64 %11, ptr %error_var18, align 8
  br label %guard_block24

after_check23:                                    ; preds = %if.then16
  br label %noerr_block25

guard_block24:                                    ; preds = %assign_optional22
  br label %voiderr39

noerr_block25:                                    ; preds = %after_check23
  %13 = load i64, ptr %retparam20, align 8
  store i64 %13, ptr %len17, align 8
  %14 = call i64 @std.io.File.write_byte(ptr %10, i8 zeroext 10)
  %not_err27 = icmp eq i64 %14, 0
  %15 = call i1 @llvm.expect.i1(i1 %not_err27, i1 true)
  br i1 %15, label %after_check29, label %assign_optional28

assign_optional28:                                ; preds = %noerr_block25
  store i64 %14, ptr %error_var26, align 8
  br label %guard_block30

after_check29:                                    ; preds = %noerr_block25
  br label %noerr_block31

guard_block30:                                    ; preds = %assign_optional28
  br label %voiderr39

noerr_block31:                                    ; preds = %after_check29
  %16 = call i64 @std.io.File.flush(ptr %10)
  %not_err33 = icmp eq i64 %16, 0
  %17 = call i1 @llvm.expect.i1(i1 %not_err33, i1 true)
  br i1 %17, label %after_check35, label %assign_optional34

assign_optional34:                                ; preds = %noerr_block31
  store i64 %16, ptr %error_var32, align 8
  br label %guard_block36

after_check35:                                    ; preds = %noerr_block31
  br label %noerr_block37

guard_block36:                                    ; preds = %assign_optional34
  br label %voiderr39

noerr_block37:                                    ; preds = %after_check35
  %18 = load i64, ptr %len17, align 8
  %add38 = add i64 %18, 1
  br label %voiderr39

voiderr39:                                        ; preds = %noerr_block37, %guard_block36, %guard_block30, %guard_block24
  br label %if.exit40

if.exit40:                                        ; preds = %voiderr39, %if.exit
  ret void
}

define void @test.print_direction3(i32 %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
  %len16 = alloca i64, align 8
  %error_var17 = alloca i64, align 8
  %retparam19 = alloca i64, align 8
  %error_var25 = alloca i64, align 8
  %error_var31 = alloca i64, align 8
  %lshrl = lshr i32 %0, 1
  %1 = and i32 1, %lshrl
  %trunc = trunc i32 %1 to i8
  %2 = trunc i8 %trunc to i1
  br i1 %2, label %if.then, label %if.exit

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

assign_optional:                                  ; preds = %if.then
  store i64 %4, ptr %error_var, align 8
  br label %guard_block

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

guard_block:                                      ; preds = %assign_optional
  br label %voiderr

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

assign_optional4:                                 ; preds = %noerr_block
  store i64 %7, 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
  %9 = call i64 @std.io.File.flush(ptr %3)
  %not_err9 = icmp eq i64 %9, 0
  %10 = call i1 @llvm.expect.i1(i1 %not_err9, i1 true)
  br i1 %10, label %after_check11, label %assign_optional10

assign_optional10:                                ; preds = %noerr_block7
  store i64 %9, 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
  %11 = load i64, ptr %len, align 8
  %add = add i64 %11, 1
  br label %voiderr

voiderr:                                          ; preds = %noerr_block13, %guard_block12, %guard_block6, %guard_block
  br label %if.exit

if.exit:                                          ; preds = %voiderr, %entry
  %12 = and i32 1, %0
  %trunc14 = trunc i32 %12 to i8
  %13 = trunc i8 %trunc14 to i1
  br i1 %13, label %if.then15, label %if.exit39

if.then15:                                        ; preds = %if.exit
  %14 = call ptr @std.io.stdout()
  %15 = call i64 @std.io.File.write(ptr %retparam19, ptr %14, ptr @.str.10, i64 4)
  %not_err20 = icmp eq i64 %15, 0
  %16 = call i1 @llvm.expect.i1(i1 %not_err20, i1 true)
  br i1 %16, label %after_check22, label %assign_optional21

assign_optional21:                                ; preds = %if.then15
  store i64 %15, ptr %error_var17, align 8
  br label %guard_block23

after_check22:                                    ; preds = %if.then15
  br label %noerr_block24

guard_block23:                                    ; preds = %assign_optional21
  br label %voiderr38

noerr_block24:                                    ; preds = %after_check22
  %17 = load i64, ptr %retparam19, align 8
  store i64 %17, ptr %len16, align 8
  %18 = call i64 @std.io.File.write_byte(ptr %14, i8 zeroext 10)
  %not_err26 = icmp eq i64 %18, 0
  %19 = call i1 @llvm.expect.i1(i1 %not_err26, i1 true)
  br i1 %19, label %after_check28, label %assign_optional27

assign_optional27:                                ; preds = %noerr_block24
  store i64 %18, ptr %error_var25, align 8
  br label %guard_block29

after_check28:                                    ; preds = %noerr_block24
  br label %noerr_block30

guard_block29:                                    ; preds = %assign_optional27
  br label %voiderr38

noerr_block30:                                    ; preds = %after_check28
  %20 = call i64 @std.io.File.flush(ptr %14)
  %not_err32 = icmp eq i64 %20, 0
  %21 = call i1 @llvm.expect.i1(i1 %not_err32, i1 true)
  br i1 %21, label %after_check34, label %assign_optional33

assign_optional33:                                ; preds = %noerr_block30
  store i64 %20, ptr %error_var31, align 8
  br label %guard_block35

after_check34:                                    ; preds = %noerr_block30
  br label %noerr_block36

guard_block35:                                    ; preds = %assign_optional33
  br label %voiderr38

noerr_block36:                                    ; preds = %after_check34
  %22 = load i64, ptr %len16, align 8
  %add37 = add i64 %22, 1
  br label %voiderr38

voiderr38:                                        ; preds = %noerr_block36, %guard_block35, %guard_block29, %guard_block23
  br label %if.exit39

if.exit39:                                        ; preds = %voiderr38, %if.exit
  ret void
}
define void @test.main() #0 {
entry:
  call void @test.print_direction2(i32 1)
  call void @test.print_direction4(i32 3)
  call void @test.print_direction3(i32 3)
  call void @test.print_bde2(i32 2)
  call void @test.print_bde3(i32 2)
  ret void
}

define i32 @test.test() #0 {
entry:
  %bar = alloca %"char[]", align 8
  %f = alloca i32, align 4
  %b = alloca i32, align 4
  %x = alloca i32, align 4
  %e = alloca i32, align 4
  store %"char[]" { ptr @.str.11, i64 9 }, ptr %bar, align 8
  store i32 4, ptr %f, align 4
  store i32 16, ptr %b, align 4
  store i32 4, ptr %x, align 4
  store i32 4, ptr %e, align 4
  ret i32 0
}
