// #target: mingw-x64

module test;
import test2;
import std::collections::list;
import std::collections::linkedlist;
import hello_world;


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

fn void helloWorld()
{
    printf("helloWorld!\n");
}
fn int test_static()
{
    static int x = 1;
    x++;
    printf("Test static %d\n", x);
    return x;
}

struct Bobo { short b; float c; short d; short e; float f; short g; }


struct Blob { int z; int f; }

union Foor
{
    long a;
    char[12] b;
}


fn int helo(double d, Bobo b)
{
    int[3] de = { 1, 2, 3 };
    Bobo c = b;
    helo(1.0, c);
    return 1;
}


fn int test1(int a, int b)
{
    a = a >> b;
    if (b > 128) return -1;
    return a;
}

struct Foo2
{
    int x;
}

fn void Foo2.printme(Foo2 *foo)
{
    printf("Foo is: %d\n", foo.x);
}

fn int Foo2.mutate(Foo2 *foo)
{
    printf("Mutating");
    return ++foo.x;
}



alias oopsInt = test2::argh{int};
alias oopsDouble = test2::argh{int};
alias Argh = fn int(double, Bobo);
alias Argh2 = fn int(double, Bobo);



fn int sum_us(int... x)
{
    int sum = 0;
    if (x.len == 0) return 0;
    sum += x[0] + sum_us(...x[1..^1]);
    return sum;
}

alias Frob = long;

fn int sumd(int[] x)
{
    int sum = 0;
    for (int i = 0; i < x.len; i++) sum += x[i];
    return sum;
}

struct Foo
{
    int a;
    int b;
}

alias getValueInt = test2::getValue{int};
alias getValueDouble = test2::getValue{double};
alias IntBlob = test2::Blob{int};
alias DoubleBlob = test2::Blob{double};
alias getMultInt = test2::getMult{int};
alias getMultDouble = test2::getMult{double};

alias IntArray = List{int};
alias IntList = LinkedList{int};

enum MyEnum : int
{
    HELO,
    WORLD,
    BYE
}


fn void main()
{
    test_static();
    test_static();
    test_static();
    hello_world::hello();
    IntList list;
    list.push(10);
    list.push(15);
    list.push(30);
    for (int i = 0; i < (int)(list.len()); i++)
    {
        printf("Element[%d]: %d\n", i, list.get(i));
    }
    list.free();

    printf("Elements: %d\n", (int)(MyEnum.values.len));

    int elements = MyEnum.values.len;
    printf("Hello\n");
    IntArray array;
    array.push(100);
    array.push(200);
    array.push(400);
    array.push(600);
    array.insert_at(2, 300);
    for (int i = 0; i < (int)(array.len()); i++)
    {
        printf("Element[%d]: %d\n", i, array.get(i));
    }
    array.free();
    IntBlob a = { 42 };
    DoubleBlob b = { 33.3 };
    printf("a was %d\n", getValueInt(a));
    printf("b was %f\n", getValueDouble(b));
    printf("Mult int was %d\n", getMultInt(25));
    printf("Mult double was %f\n", getMultDouble(3.3));


    helloWorld();
    Foo ddx;
    int fro = 3;
    int[4] x = { 1, 2, 3, 3 };
    fro += printf("1Vararg4splatA: %d\n", sum_us(...x));
    printf("%d\n", fro);
    int[] z = &x;
    int[3] de = { 1, 2, 3 };
    printf("Vararg4splatB: %d\n", sum_us(...&x));
    printf("Vararg4splatC: %d\n", sum_us(...z));
    printf("Vararg4: %d\n", sum_us(1, 2, 4, 5));
    printf("Vararg1: %d\n", sum_us(1));
    printf("Vararg0: %d\n", sum_us());
    Argh a1;
    Argh2 b2;
}

module hello_world;
import foo;

extern fn int printf(char *, ...);
alias doubleMult = foo::check{double};

fn void hello()
{
    printf("Hello baby\n");
    printf("Mult %f\n", doubleMult(11.1));
}

module foo <Type>;

fn Type check(Type i)
{
    return i * i;
}

module test2 <Type>;

struct Blob
{
    Type a;
}

fn Type getMult(Type a)
{
    return a * a;
}
Type argh = 234;

enum Hello : int
{
    FOO,
    BAR,
}

macro Hello wut()
{
    return Hello.FOO;
}

alias Bye = Hello;
alias wat = wut;
alias byebye = hello;

fn int hello()
{
    return 1;
}

fn Type getValue(Blob blob)
{
    return blob.a;
}

/* #expect: test.ll

%"Blob{int}" = type { i32 }
%"Blob{double}" = type { double }
%Bobo = type { i16, float, i16, i16, float, i16 }
%"int[]" = type { ptr, i64 }
%"LinkedList{int}" = type { %any, i64, ptr, ptr }
%any = type { ptr, i64 }
%"List{int}" = type { i64, i64, %any, ptr }
%Foo = type { i32, i32 }

$"$ct.test.Bobo" = comdat any

$"$ct.test.Blob" = comdat any

$"$ct.test.Foor" = comdat any

$"$ct.test.Foo2" = comdat any

$"$ct.test.Foo" = comdat any

$"$ct.int" = comdat any

$"$ct.test.MyEnum" = comdat any

@"$ct.test.Bobo" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 20, i64 0, i64 6, [0 x i64] zeroinitializer }, comdat, align 8
@"$ct.test.Blob" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, comdat, align 8
@"$ct.test.Foor" = linkonce global %.introspect { i8 11, i64 0, ptr null, i64 16, i64 0, i64 2, [0 x i64] zeroinitializer }, comdat, align 8
@"$ct.test.Foo2" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, comdat, align 8
@"$ct.test.Foo" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, comdat, align 8
@.enum.HELO = internal constant [5 x i8] c"HELO\00", align 1
@.enum.WORLD = internal constant [6 x i8] c"WORLD\00", align 1
@.enum.BYE = internal constant [4 x i8] c"BYE\00", align 1
@"$ct.int" = linkonce global %.introspect { i8 2, i64 0, ptr null, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, comdat, align 8
@"$ct.test.MyEnum" = linkonce global { i8, i64, ptr, i64, i64, i64, [3 x %"char[]"] } { i8 8, i64 0, ptr null, i64 4, i64 ptrtoint (ptr @"$ct.int" to i64), i64 3, [3 x %"char[]"] [%"char[]" { ptr @.enum.HELO, i64 4 }, %"char[]" { ptr @.enum.WORLD, i64 5 }, %"char[]" { ptr @.enum.BYE, i64 3 }] }, comdat, align 8
@.str = private unnamed_addr constant [13 x i8] c"helloWorld!\0A\00", align 1
@test_static.x = internal unnamed_addr global i32 1, align 4
@.str.1 = private unnamed_addr constant [16 x i8] c"Test static %d\0A\00", align 1
@.__const = private unnamed_addr constant [3 x i32] [i32 1, i32 2, i32 3], align 4
@.str.2 = private unnamed_addr constant [17 x i8] c"Element[%d]: %d\0A\00", align 1
@.str.3 = private unnamed_addr constant [14 x i8] c"Elements: %d\0A\00", align 1
@.str.4 = private unnamed_addr constant [7 x i8] c"Hello\0A\00", align 1
@.str.5 = private unnamed_addr constant [17 x i8] c"Element[%d]: %d\0A\00", align 1
@.__const.6 = private unnamed_addr constant %"Blob{int}" { i32 42 }, align 4
@.__const.7 = private unnamed_addr constant %"Blob{double}" { double 3.330000e+01 }, align 8
@.str.8 = private unnamed_addr constant [10 x i8] c"a was %d\0A\00", align 1
@.str.9 = private unnamed_addr constant [10 x i8] c"b was %f\0A\00", align 1
@.str.10 = private unnamed_addr constant [17 x i8] c"Mult int was %d\0A\00", align 1
@.str.11 = private unnamed_addr constant [20 x i8] c"Mult double was %f\0A\00", align 1
@.__const.12 = private unnamed_addr constant [4 x i32] [i32 1, i32 2, i32 3, i32 3], align 16
@.str.13 = private unnamed_addr constant [20 x i8] c"1Vararg4splatA: %d\0A\00", align 1
@.str.14 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
@.__const.15 = private unnamed_addr constant [3 x i32] [i32 1, i32 2, i32 3], align 4
@.str.16 = private unnamed_addr constant [19 x i8] c"Vararg4splatB: %d\0A\00", align 1
@.str.17 = private unnamed_addr constant [19 x i8] c"Vararg4splatC: %d\0A\00", align 1
@.str.18 = private unnamed_addr constant [13 x i8] c"Vararg4: %d\0A\00", align 1
@.str.19 = private unnamed_addr constant [13 x i8] c"Vararg1: %d\0A\00", align 1
@.str.20 = private unnamed_addr constant [13 x i8] c"Vararg0: %d\0A\00", align 1
@.str.21 = private unnamed_addr constant [12 x i8] c"Foo is: %d\0A\00", align 1
@.str.22 = private unnamed_addr constant [9 x i8] c"Mutating\00", align 1

; Function Attrs:
define void @test.Foo2.printme(ptr %0) #0 {
entry:
  %1 = load i32, ptr %0, align 4
  %2 = call i32 (ptr, ...) @printf(ptr @.str.21, i32 %1)
  ret void
}

; Function Attrs:
define i32 @test.Foo2.mutate(ptr %0) #0 {
entry:
  %1 = call i32 (ptr, ...) @printf(ptr @.str.22)
  %2 = load i32, ptr %0, align 4
  %add = add i32 %2, 1
  store i32 %add, ptr %0, align 4
  ret i32 %add
}

declare i32 @printf(ptr, ...) #0

define void @test.helloWorld() #0 {
entry:
  %0 = call i32 (ptr, ...) @printf(ptr @.str)
  ret void
}

define i32 @test.test_static() #0 {
entry:
  %0 = load i32, ptr @test_static.x, align 4
  %add = add i32 %0, 1
  store i32 %add, ptr @test_static.x, align 4
  %1 = load i32, ptr @test_static.x, align 4
  %2 = call i32 (ptr, ...) @printf(ptr @.str.1, i32 %1)
  %3 = load i32, ptr @test_static.x, align 4
  ret i32 %3
}

define i32 @test.helo(double %0, ptr align 4 %1) #0 {
entry:
  %de = alloca [3 x i32], align 4
  %c = alloca %Bobo, align 4
  %indirectarg = alloca %Bobo, align 4
  call void @llvm.memcpy.p0.p0.i32(ptr align 4 %de, ptr align 4 @.__const, i32 12, i1 false)
  call void @llvm.memcpy.p0.p0.i32(ptr align 4 %c, ptr align 4 %1, i32 20, i1 false)
  call void @llvm.memcpy.p0.p0.i32(ptr align 4 %indirectarg, ptr align 4 %c, i32 20, i1 false)
  %2 = call i32 @test.helo(double 1.000000e+00, ptr align 4 %indirectarg)
  ret i32 1
}

define i32 @test.test1(i32 %0, i32 %1) #0 {
entry:
  %a = alloca i32, align 4
  store i32 %0, ptr %a, align 4
  %2 = load i32, ptr %a, align 4
  %ashr = ashr i32 %2, %1
  %3 = freeze i32 %ashr
  store i32 %3, ptr %a, align 4
  %gt = icmp sgt i32 %1, 128
  br i1 %gt, label %if.then, label %if.exit

if.then:                                          ; preds = %entry
  ret i32 -1

if.exit:                                          ; preds = %entry
  %4 = load i32, ptr %a, align 4
  ret i32 %4
}

define i32 @test.sum_us(ptr align 8 %0) #0 {
entry:
  %sum = alloca i32, align 4
  %indirectarg = alloca %"int[]", align 8
  store i32 0, ptr %sum, align 4
  %ptradd = getelementptr inbounds i8, ptr %0, i64 8
  %1 = load i64, ptr %ptradd, align 8
  %eq = icmp eq i64 0, %1
  br i1 %eq, label %if.then, label %if.exit

if.then:                                          ; preds = %entry
  ret i32 0

if.exit:                                          ; preds = %entry
  %2 = load i32, ptr %sum, align 4
  %3 = load ptr, ptr %0, align 8
  %4 = load i32, ptr %3, align 4
  %5 = load %"int[]", ptr %0, align 8
  %6 = extractvalue %"int[]" %5, 0
  %7 = extractvalue %"int[]" %5, 1
  %sub = sub i64 %7, 1
  %8 = add i64 %sub, 1
  %size = sub i64 %8, 1
  %ptradd1 = getelementptr inbounds i8, ptr %6, i64 4
  %9 = insertvalue %"int[]" undef, ptr %ptradd1, 0
  %10 = insertvalue %"int[]" %9, i64 %size, 1
  store %"int[]" %10, ptr %indirectarg, align 8
  %11 = call i32 @test.sum_us(ptr align 8 %indirectarg)
  %add = add i32 %4, %11
  %add2 = add i32 %2, %add
  store i32 %add2, ptr %sum, align 4
  %12 = load i32, ptr %sum, align 4
  ret i32 %12
}

define i32 @test.sumd(ptr align 8 %0) #0 {
entry:
  %sum = alloca i32, align 4
  %i = alloca i32, align 4
  store i32 0, ptr %sum, align 4
  store i32 0, ptr %i, align 4
  br label %loop.cond

loop.cond:                                        ; preds = %loop.body, %entry
  %1 = load i32, ptr %i, align 4
  %sext = sext i32 %1 to i64
  %ptradd = getelementptr inbounds i8, ptr %0, i64 8
  %2 = load i64, ptr %ptradd, align 8
  %lt = icmp slt i64 %sext, %2
  %check = icmp slt i64 %2, 0
  %siui-lt = or i1 %check, %lt
  br i1 %siui-lt, label %loop.body, label %loop.exit

loop.body:                                        ; preds = %loop.cond
  %3 = load i32, ptr %sum, align 4
  %4 = load ptr, ptr %0, align 8
  %5 = load i32, ptr %i, align 4
  %sext1 = sext i32 %5 to i64
  %ptroffset = getelementptr inbounds [4 x i8], ptr %4, i64 %sext1
  %6 = load i32, ptr %ptroffset, align 4
  %add = add i32 %3, %6
  store i32 %add, ptr %sum, align 4
  %7 = load i32, ptr %i, align 4
  %add2 = add i32 %7, 1
  store i32 %add2, ptr %i, align 4
  br label %loop.cond

loop.exit:                                        ; preds = %loop.cond
  %8 = load i32, ptr %sum, align 4
  ret i32 %8
}

define void @test.main() #0 {
entry:
  %list = alloca %"LinkedList{int}", align 8
  %i = alloca i32, align 4
  %elements = alloca i32, align 4
  %array = alloca %"List{int}", align 8
  %i1 = alloca i32, align 4
  %a = alloca %"Blob{int}", align 4
  %b = alloca %"Blob{double}", align 8
  %ddx = alloca %Foo, align 4
  %fro = alloca i32, align 4
  %x = alloca [4 x i32], align 16
  %indirectarg = alloca %"int[]", align 8
  %z = alloca %"int[]", align 8
  %de = alloca [3 x i32], align 4
  %indirectarg10 = alloca %"int[]", align 8
  %indirectarg11 = alloca %"int[]", align 8
  %varargslots = alloca [4 x i32], align 16
  %indirectarg15 = alloca %"int[]", align 8
  %varargslots16 = alloca [1 x i32], align 4
  %indirectarg18 = alloca %"int[]", align 8
  %indirectarg19 = alloca %"int[]", align 8
  %a1 = alloca ptr, align 8
  %b2 = alloca ptr, align 8
  %0 = call i32 @test.test_static()
  %1 = call i32 @test.test_static()
  %2 = call i32 @test.test_static()
  call void @hello_world.hello()
  call void @llvm.memset.p0.i64(ptr align 8 %list, i8 0, i64 40, i1 false)
  call void @"std.collections.linkedlist.LinkedList$int$.push"(ptr %list, i32 10)
  call void @"std.collections.linkedlist.LinkedList$int$.push"(ptr %list, i32 15)
  call void @"std.collections.linkedlist.LinkedList$int$.push"(ptr %list, i32 30)
  store i32 0, ptr %i, align 4
  br label %loop.cond

loop.cond:                                        ; preds = %loop.body, %entry
  %3 = load i32, ptr %i, align 4
  %4 = call i64 @"std.collections.linkedlist.LinkedList$int$.len"(ptr %list) #3
  %trunc = trunc i64 %4 to i32
  %lt = icmp slt i32 %3, %trunc
  br i1 %lt, label %loop.body, label %loop.exit

loop.body:                                        ; preds = %loop.cond
  %5 = load i32, ptr %i, align 4
  %sext = sext i32 %5 to i64
  %6 = call i32 @"std.collections.linkedlist.LinkedList$int$.get"(ptr %list, i64 %sext)
  %7 = load i32, ptr %i, align 4
  %8 = call i32 (ptr, ...) @printf(ptr @.str.2, i32 %7, i32 %6)
  %9 = load i32, ptr %i, align 4
  %add = add i32 %9, 1
  store i32 %add, ptr %i, align 4
  br label %loop.cond

loop.exit:                                        ; preds = %loop.cond
  call void @"std.collections.linkedlist.LinkedList$int$.free"(ptr %list)
  %10 = call i32 (ptr, ...) @printf(ptr @.str.3, i32 3)
  store i32 3, ptr %elements, align 4
  %11 = call i32 (ptr, ...) @printf(ptr @.str.4)
  call void @llvm.memset.p0.i64(ptr align 8 %array, i8 0, i64 40, i1 false)
  call void @"std.collections.list.List$int$.push"(ptr %array, i32 100) #3
  call void @"std.collections.list.List$int$.push"(ptr %array, i32 200) #3
  call void @"std.collections.list.List$int$.push"(ptr %array, i32 400) #3
  call void @"std.collections.list.List$int$.push"(ptr %array, i32 600) #3
  call void @"std.collections.list.List$int$.insert_at"(ptr %array, i64 2, i32 300)
  store i32 0, ptr %i1, align 4
  br label %loop.cond2

loop.cond2:                                       ; preds = %loop.body5, %loop.exit
  %12 = load i32, ptr %i1, align 4
  %13 = call i64 @"std.collections.list.List$int$.len"(ptr %array) #3
  %trunc3 = trunc i64 %13 to i32
  %lt4 = icmp slt i32 %12, %trunc3
  br i1 %lt4, label %loop.body5, label %loop.exit8

loop.body5:                                       ; preds = %loop.cond2
  %14 = load i32, ptr %i1, align 4
  %sext6 = sext i32 %14 to i64
  %15 = call i32 @"std.collections.list.List$int$.get"(ptr %array, i64 %sext6) #3
  %16 = load i32, ptr %i1, align 4
  %17 = call i32 (ptr, ...) @printf(ptr @.str.5, i32 %16, i32 %15)
  %18 = load i32, ptr %i1, align 4
  %add7 = add i32 %18, 1
  store i32 %add7, ptr %i1, align 4
  br label %loop.cond2

loop.exit8:                                       ; preds = %loop.cond2
  call void @"std.collections.list.List$int$.free"(ptr %array)
  call void @llvm.memcpy.p0.p0.i32(ptr align 4 %a, ptr align 4 @.__const.6, i32 4, i1 false)
  call void @llvm.memcpy.p0.p0.i32(ptr align 8 %b, ptr align 8 @.__const.7, i32 8, i1 false)
  %19 = load i32, ptr %a, align 4
  %20 = call i32 @"test2.getValue$int$"(i32 %19)
  %21 = call i32 (ptr, ...) @printf(ptr @.str.8, i32 %20)
  %22 = load i64, ptr %b, align 8
  %23 = call double @"test2.getValue$double$"(i64 %22)
  %24 = call i32 (ptr, ...) @printf(ptr @.str.9, double %23)
  %25 = call i32 @"test2.getMult$int$"(i32 25)
  %26 = call i32 (ptr, ...) @printf(ptr @.str.10, i32 %25)
  %27 = call double @"test2.getMult$double$"(double 3.300000e+00)
  %28 = call i32 (ptr, ...) @printf(ptr @.str.11, double %27)
  call void @test.helloWorld()
  store i32 0, ptr %ddx, align 4
  %ptradd = getelementptr inbounds i8, ptr %ddx, i64 4
  store i32 0, ptr %ptradd, align 4
  store i32 3, ptr %fro, align 4
  call void @llvm.memcpy.p0.p0.i32(ptr align 16 %x, ptr align 16 @.__const.12, i32 16, i1 false)
  %29 = load i32, ptr %fro, align 4
  %30 = insertvalue %"int[]" undef, ptr %x, 0
  %31 = insertvalue %"int[]" %30, i64 4, 1
  store %"int[]" %31, ptr %indirectarg, align 8
  %32 = call i32 @test.sum_us(ptr align 8 %indirectarg)
  %33 = call i32 (ptr, ...) @printf(ptr @.str.13, i32 %32)
  %add9 = add i32 %29, %33
  store i32 %add9, ptr %fro, align 4
  %34 = load i32, ptr %fro, align 4
  %35 = call i32 (ptr, ...) @printf(ptr @.str.14, i32 %34)
  %36 = insertvalue %"int[]" undef, ptr %x, 0
  %37 = insertvalue %"int[]" %36, i64 4, 1
  store %"int[]" %37, ptr %z, align 8
  call void @llvm.memcpy.p0.p0.i32(ptr align 4 %de, ptr align 4 @.__const.15, i32 12, i1 false)
  %38 = insertvalue %"int[]" undef, ptr %x, 0
  %39 = insertvalue %"int[]" %38, i64 4, 1
  store %"int[]" %39, ptr %indirectarg10, align 8
  %40 = call i32 @test.sum_us(ptr align 8 %indirectarg10)
  %41 = call i32 (ptr, ...) @printf(ptr @.str.16, i32 %40)
  call void @llvm.memcpy.p0.p0.i32(ptr align 8 %indirectarg11, ptr align 8 %z, i32 16, i1 false)
  %42 = call i32 @test.sum_us(ptr align 8 %indirectarg11)
  %43 = call i32 (ptr, ...) @printf(ptr @.str.17, i32 %42)
  store i32 1, ptr %varargslots, align 16
  %ptradd12 = getelementptr inbounds i8, ptr %varargslots, i64 4
  store i32 2, ptr %ptradd12, align 4
  %ptradd13 = getelementptr inbounds i8, ptr %varargslots, i64 8
  store i32 4, ptr %ptradd13, align 4
  %ptradd14 = getelementptr inbounds i8, ptr %varargslots, i64 12
  store i32 5, ptr %ptradd14, align 4
  %44 = insertvalue %"int[]" undef, ptr %varargslots, 0
  %"$$temp" = insertvalue %"int[]" %44, i64 4, 1
  store %"int[]" %"$$temp", ptr %indirectarg15, align 8
  %45 = call i32 @test.sum_us(ptr align 8 %indirectarg15)
  %46 = call i32 (ptr, ...) @printf(ptr @.str.18, i32 %45)
  store i32 1, ptr %varargslots16, align 4
  %47 = insertvalue %"int[]" undef, ptr %varargslots16, 0
  %"$$temp17" = insertvalue %"int[]" %47, i64 1, 1
  store %"int[]" %"$$temp17", ptr %indirectarg18, align 8
  %48 = call i32 @test.sum_us(ptr align 8 %indirectarg18)
  %49 = call i32 (ptr, ...) @printf(ptr @.str.19, i32 %48)
  store %"int[]" zeroinitializer, ptr %indirectarg19, align 8
  %50 = call i32 @test.sum_us(ptr align 8 %indirectarg19)
  %51 = call i32 (ptr, ...) @printf(ptr @.str.20, i32 %50)
  store ptr null, ptr %a1, align 8
  store ptr null, ptr %b2, align 8
  ret void
}

declare void @llvm.memcpy.p0.p0.i32(ptr noalias
declare void @hello_world.hello() #0
declare void @llvm.memset.p0.i64(ptr
declare void @"std.collections.linkedlist.LinkedList$int$.push"(ptr, i32) #0
declare i64 @"std.collections.linkedlist.LinkedList$int$.len"(ptr) #0
declare i32 @"std.collections.linkedlist.LinkedList$int$.get"(ptr, i64) #0
declare void @"std.collections.linkedlist.LinkedList$int$.free"(ptr) #0
declare void @"std.collections.list.List$int$.push"(ptr, i32) #0
declare void @"std.collections.list.List$int$.insert_at"(ptr, i64, i32) #0
declare i64 @"std.collections.list.List$int$.len"(ptr) #0
declare i32 @"std.collections.list.List$int$.get"(ptr, i64) #0
declare void @"std.collections.list.List$int$.free"(ptr) #0
declare i32 @"test2.getValue$int$"(i32) #0
declare double @"test2.getValue$double$"(i64) #0
declare i32 @"test2.getMult$int$"(i32) #0
declare double @"test2.getMult$double$"(double) #0

// #expect: foo.ll


define weak_odr double @"foo.check$double$"(double %0) #0 comdat {
entry:
  %fmul = fmul double %0, %0
  ret double %fmul
}


// #expect: test2.ll

define weak_odr i32 @"test2.getValue$int$"(i32 %0) #0 comdat {
entry:
  %blob = alloca %"Blob{int}", align 4
  store i32 %0, ptr %blob, align 4
  %1 = load i32, ptr %blob, align 4
  ret i32 %1
}

define weak_odr double @"test2.getMult$double$"(double %0)
entry:
  %fmul = fmul double %0, %0
  ret double %fmul
}

define weak_odr i32 @"test2.hello$double$"() #0
entry:
  ret i32 1
}

define weak_odr double @"test2.getValue$double$"(i64 %0) #0 comdat {
entry:
  %blob = alloca %"Blob{double}", align 8
  store i64 %0, ptr %blob, align 8
  %1 = load double, ptr %blob, align 8
  ret double %1
}

!llvm.module.flags = !{!0, !1, !2, !3, !4, !5}

!0 = !{i32 2, !"Dwarf Version", i32 4}
!1 = !{i32 2, !"Debug Info Version", i32 3}
!2 = !{i32 2, !"wchar_size", i32 4}
!3 = !{i32 4, !"PIC Level", i32 2}
!4 = !{i32 1, !"uwtable", i32 2}
!5 = !{i32 2, !"frame-pointer", i32 2}
