// #target: macos-x64
module test;
import std::io;
struct Foo
{
	int a; int b;
}
typedef Int2V = int[<2>] @simd;
fn void test(int[2] a, int[] b, Int2V c)
{
	io::printfn("%s %s %s", a, b, c);
}
fn void main()
{
	var $x = { { 1, 2 } };
	Foo[1] abc = (Foo[1])$x;
	Foo defg = (Foo)$x[0];
	int[2][1] y = (int[2][1])$x;
	double[2][1] y2 = $x;
	io::printfn("%s %s {%s, %s}", y, y2, defg.a, defg.b);
	test({ 1, 2 }, { 3, 4}, { 5, 6 });
	var $a = { 2, 7 };
	test($a, $a, $a);
}

/* #expect: test.ll

%.introspect = type { i8, i64, ptr, i64, i64, i64, [0 x i64] }
%Foo = type { i32, i32 }
%"int[]" = type { ptr, i64 }
%any = type { ptr, i64 }

@"$ct.test.Foo" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.test.Int2V" = linkonce global %.introspect { i8 18, i64 0, ptr null, i64 8, i64 ptrtoint (ptr @"$ct.siv2$int" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.siv2$int" = linkonce global %.introspect { i8 17, i64 0, ptr null, i64 8, i64 ptrtoint (ptr @"$ct.int" to i64), i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.int" = linkonce global %.introspect { i8 2, i64 0, ptr null, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@.str = private unnamed_addr constant [9 x i8] c"%s %s %s\00", align 1
@"$ct.a2$int" = linkonce global %.introspect { i8 15, i64 0, ptr null, i64 8, i64 ptrtoint (ptr @"$ct.int" to i64), i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.sa$int" = linkonce global %.introspect { i8 16, i64 0, ptr null, i64 16, i64 ptrtoint (ptr @"$ct.int" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
@.__const = private unnamed_addr constant [1 x %Foo] [%Foo { i32 1, i32 2 }], align 4
@.__const.1 = private unnamed_addr constant %Foo { i32 1, i32 2 }, align 4
@.__const.2 = private unnamed_addr constant [1 x [2 x i32]] [[2 x i32] [i32 1, i32 2]], align 4
@.__const.3 = private unnamed_addr constant [1 x [2 x double]] [[2 x double] [double 1.000000e+00, double 2.000000e+00]], align 16
@.str.4 = private unnamed_addr constant [15 x i8] c"%s %s {%s, %s}\00", align 1
@"$ct.a1$a2$int" = linkonce global %.introspect { i8 15, i64 0, ptr null, i64 8, i64 ptrtoint (ptr @"$ct.a2$int" to i64), i64 1, [0 x i64] zeroinitializer }, align 8
@"$ct.a1$a2$double" = linkonce global %.introspect { i8 15, i64 0, ptr null, i64 16, i64 ptrtoint (ptr @"$ct.a2$double" to i64), i64 1, [0 x i64] zeroinitializer }, align 8
@"$ct.a2$double" = linkonce global %.introspect { i8 15, i64 0, ptr null, i64 16, i64 ptrtoint (ptr @"$ct.double" to i64), i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.double" = linkonce global %.introspect { i8 4, i64 0, ptr null, i64 8, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@.__const.5 = private unnamed_addr constant [2 x i32] [i32 1, i32 2], align 4
@.__const.6 = private unnamed_addr constant [2 x i32] [i32 3, i32 4], align 4
@.__const.7 = private unnamed_addr constant [2 x i32] [i32 2, i32 7], align 4
@.__const.8 = private unnamed_addr constant [2 x i32] [i32 2, i32 7], align 4

; Function Attrs:
define void @test.test(i64 %0, ptr %1, i64 %2, double %3) #0 {
entry:
  %a = alloca [2 x i32], align 4
  %b = alloca %"int[]", align 8
  %c = alloca <2 x i32>, align 8
  %varargslots = alloca [3 x %any], align 16
  %retparam = alloca i64, align 8
  store i64 %0, ptr %a, align 4
  store ptr %1, ptr %b, align 8
  %ptradd = getelementptr inbounds i8, ptr %b, i64 8
  store i64 %2, ptr %ptradd, align 8
  store double %3, ptr %c, align 8
  %4 = insertvalue %any undef, ptr %a, 0
  %5 = insertvalue %any %4, i64 ptrtoint (ptr @"$ct.a2$int" to i64), 1
  store %any %5, ptr %varargslots, align 16
  %6 = insertvalue %any undef, ptr %b, 0
  %7 = insertvalue %any %6, i64 ptrtoint (ptr @"$ct.sa$int" to i64), 1
  %ptradd1 = getelementptr inbounds i8, ptr %varargslots, i64 16
  store %any %7, ptr %ptradd1, align 16
  %8 = insertvalue %any undef, ptr %c, 0
  %9 = insertvalue %any %8, i64 ptrtoint (ptr @"$ct.test.Int2V" to i64), 1
  %ptradd2 = getelementptr inbounds i8, ptr %varargslots, i64 32
  store %any %9, ptr %ptradd2, align 16
  %10 = call i64 @std.io.printfn(ptr %retparam, ptr @.str, i64 8, ptr %varargslots, i64 3)
  ret void
}

; Function Attrs:
define void @test.main() #0 {
entry:
  %abc = alloca [1 x %Foo], align 4
  %defg = alloca %Foo, align 4
  %y = alloca [1 x [2 x i32]], align 4
  %y2 = alloca [1 x [2 x double]], align 16
  %varargslots = alloca [4 x %any], align 16
  %retparam = alloca i64, align 8
  %literal = alloca [2 x i32], align 4
  %literal4 = alloca [2 x i32], align 4
  %taddr = alloca <2 x i32>, align 8
  %literal5 = alloca [2 x i32], align 4
  %literal6 = alloca [2 x i32], align 4
  %taddr7 = alloca <2 x i32>, align 8
  call void @llvm.memcpy.p0.p0.i32(ptr align 4 %abc, ptr align 4 @.__const, i32 8, i1 false)
  call void @llvm.memcpy.p0.p0.i32(ptr align 4 %defg, ptr align 4 @.__const.1, i32 8, i1 false)
  call void @llvm.memcpy.p0.p0.i32(ptr align 4 %y, ptr align 4 @.__const.2, i32 8, i1 false)
  call void @llvm.memcpy.p0.p0.i32(ptr align 16 %y2, ptr align 16 @.__const.3, i32 16, i1 false)
  %0 = insertvalue %any undef, ptr %y, 0
  %1 = insertvalue %any %0, i64 ptrtoint (ptr @"$ct.a1$a2$int" to i64), 1
  store %any %1, ptr %varargslots, align 16
  %2 = insertvalue %any undef, ptr %y2, 0
  %3 = insertvalue %any %2, i64 ptrtoint (ptr @"$ct.a1$a2$double" to i64), 1
  %ptradd = getelementptr inbounds i8, ptr %varargslots, i64 16
  store %any %3, ptr %ptradd, align 16
  %4 = insertvalue %any undef, ptr %defg, 0
  %5 = insertvalue %any %4, i64 ptrtoint (ptr @"$ct.int" to i64), 1
  %ptradd1 = getelementptr inbounds i8, ptr %varargslots, i64 32
  store %any %5, ptr %ptradd1, align 16
  %ptradd2 = getelementptr inbounds i8, ptr %defg, i64 4
  %6 = insertvalue %any undef, ptr %ptradd2, 0
  %7 = insertvalue %any %6, i64 ptrtoint (ptr @"$ct.int" to i64), 1
  %ptradd3 = getelementptr inbounds i8, ptr %varargslots, i64 48
  store %any %7, ptr %ptradd3, align 16
  %8 = call i64 @std.io.printfn(ptr %retparam, ptr @.str.4, i64 14, ptr %varargslots, i64 4)
  call void @llvm.memcpy.p0.p0.i32(ptr align 4 %literal, ptr align 4 @.__const.5, i32 8, i1 false)
  call void @llvm.memcpy.p0.p0.i32(ptr align 4 %literal4, ptr align 4 @.__const.6, i32 8, i1 false)
  %9 = insertvalue %"int[]" undef, ptr %literal4, 0
  %10 = insertvalue %"int[]" %9, i64 2, 1
  %11 = load i64, ptr %literal, align 4
  store <2 x i32> <i32 5, i32 6>, ptr %taddr, align 8
  %12 = load double, ptr %taddr, align 8
  call void @test.test(i64 %11, ptr %literal4, i64 2, double %12)
  call void @llvm.memcpy.p0.p0.i32(ptr align 4 %literal5, ptr align 4 @.__const.7, i32 8, i1 false)
  call void @llvm.memcpy.p0.p0.i32(ptr align 4 %literal6, ptr align 4 @.__const.8, i32 8, i1 false)
  %13 = insertvalue %"int[]" undef, ptr %literal6, 0
  %14 = insertvalue %"int[]" %13, i64 2, 1
  %15 = load i64, ptr %literal5, align 4
  store <2 x i32> <i32 2, i32 7>, ptr %taddr7, align 8
  %16 = load double, ptr %taddr7, align 8
  call void @test.test(i64 %15, ptr %literal6, i64 2, double %16)
  ret void
}
