// #target: macos-x64
// #opt: --fp-math=relaxed
module test;
extern fn int printf(char* format, ...);

fn void main() {
    float radians = 3.1415 / 4;
    float[<3>] axis = {0.0, 0.0, 1.0};

    float cosr = (float) $$cos(radians);
    float sinr = (float) $$sin(radians);
    float x = axis[0];
    float y = axis[1];
    float z = axis[2];

    float[<4>][4] a = {};
    a[0] = {
        cosr + (x * x) * (float) (1.0 - cosr),
        (x * y) * (float) (1.0 - cosr) - (z * sinr),
        (x * z) * (float) (1.0 - cosr) + (y * sinr),
        0.0
    };

    a[1] = {
        (y * x) * (float) (1.0 - cosr) + (z * sinr),
        cosr + (y * y) * (float) (1.0 - cosr),
        (y * z) * (float) (1.0 - cosr) - (x * sinr),
        0.0
    };

    a[2] = {
        (z * x) * (float) (1.0 - cosr) - (y * sinr),
        (z * y) * (float) (1.0 - cosr) + (x * sinr),
        cosr + (z * z) * (float) (1.0 - cosr),
        0.0
    };

    a[3] = {
        0.0,
        0.0,
        0.0,
        1.0
    };

    float[<4>][4] b = {
        {
            cosr + (x * x) * (float) (1.0 - cosr),
            (x * y) * (float) (1.0 - cosr) - (z * sinr),
            (x * z) * (float) (1.0 - cosr) + (y * sinr),
            0.0
        },
        {
            (y * x) * (float) (1.0 - cosr) + (z * sinr),
            cosr + (y * y) * (float) (1.0 - cosr),
            (y * z) * (float) (1.0 - cosr) - (x * sinr),
            0.0
        },
        {
            (z * x) * (float) (1.0 - cosr) - (y * sinr),
            (z * y) * (float) (1.0 - cosr) + (x * sinr),
            cosr + (z * z) * (float) (1.0 - cosr),
            0.0
        },
        {
            0.0,
            0.0,
            0.0,
            1.0
        }
    };

    foreach(v : a) {
        printf("A: %f %f %f %f\n", v[0], v[1], v[2], v[3]);
    }

    printf("\n");

    foreach(v : b) {
        printf("B: %f %f %f %f\n", v[0], v[1], v[2], v[3]);
    }
}

/* #expect: test.ll

define void @test.main() #0 {
entry:
  %radians = alloca float, align 4
  %axis = alloca <3 x float>, align 16
  %cosr = alloca float, align 4
  %sinr = alloca float, align 4
  %x = alloca float, align 4
  %y = alloca float, align 4
  %z = alloca float, align 4
  %a = alloca [4 x <4 x float>], align 16
  %b = alloca [4 x <4 x float>], align 16
  %.anon = alloca i64, align 8
  %v = alloca <4 x float>, align 16
  %.anon92 = alloca i64, align 8
  %v96 = alloca <4 x float>, align 16
  store float 0x3FE921CAC0000000, ptr %radians, align 4
  store <4 x float> <float 0.000000e+00, float 0.000000e+00, float 1.000000e+00, float undef>, ptr %axis, align 16
  %0 = load float, ptr %radians, align 4
  %1 = call reassoc arcp contract float @llvm.cos.f32(float %0)
  store float %1, ptr %cosr, align 4
  %2 = load float, ptr %radians, align 4
  %3 = call reassoc arcp contract float @llvm.sin.f32(float %2)
  store float %3, ptr %sinr, align 4
  %4 = load <4 x float>, ptr %axis, align 16
  %extractvec = shufflevector <4 x float> %4, <4 x float> poison, <3 x i32> <i32 0, i32 1, i32 2>
  %5 = extractelement <3 x float> %extractvec, i64 0
  store float %5, ptr %x, align 4
  %6 = load <4 x float>, ptr %axis, align 16
  %extractvec1 = shufflevector <4 x float> %6, <4 x float> poison, <3 x i32> <i32 0, i32 1, i32 2>
  %7 = extractelement <3 x float> %extractvec1, i64 1
  store float %7, ptr %y, align 4
  %8 = load <4 x float>, ptr %axis, align 16
  %extractvec2 = shufflevector <4 x float> %8, <4 x float> poison, <3 x i32> <i32 0, i32 1, i32 2>
  %9 = extractelement <3 x float> %extractvec2, i64 2
  store float %9, ptr %z, align 4
  call void @llvm.memset.p0.i64(ptr align 16 %a, i8 0, i64 64, i1 false)
  %10 = load float, ptr %cosr, align 4
  %11 = load float, ptr %x, align 4
  %12 = load float, ptr %x, align 4
  %fmul = fmul reassoc arcp contract float %11, %12
  %13 = load float, ptr %cosr, align 4
  %fpfpext = fpext
  %fsub = fsub reassoc arcp contract double 1.000000e+00, %fpfpext
  %fpfptrunc = fptrunc
  %14 = call reassoc arcp contract float @llvm.fmuladd.f32(float %fmul, float %fpfptrunc, float %10)
  %15 = insertelement <4 x float> undef, float %14, i64 0
  %16 = load float, ptr %x, align 4
  %17 = load float, ptr %y, align 4
  %fmul3 = fmul reassoc arcp contract float %16, %17
  %18 = load float, ptr %cosr, align 4
  %fpfpext4 = fpext
  %fsub5 = fsub reassoc arcp contract double 1.000000e+00, %fpfpext4
  %fpfptrunc6 = fptrunc
  %19 = load float, ptr %z, align 4
  %20 = load float, ptr %sinr, align 4
  %fmul7 = fmul reassoc arcp contract float %19, %20
  %21 = fneg reassoc arcp contract float %fmul7
  %22 = call reassoc arcp contract float @llvm.fmuladd.f32(float %fmul3, float %fpfptrunc6, float %21)
  %23 = insertelement <4 x float> %15, float %22, i64 1
  %24 = load float, ptr %x, align 4
  %25 = load float, ptr %z, align 4
  %fmul8 = fmul reassoc arcp contract float %24, %25
  %26 = load float, ptr %cosr, align 4
  %fpfpext9 = fpext
  %fsub10 = fsub reassoc arcp contract double 1.000000e+00, %fpfpext9
  %fpfptrunc11 = fptrunc
  %27 = load float, ptr %y, align 4
  %28 = load float, ptr %sinr, align 4
  %fmul12 = fmul reassoc arcp contract float %27, %28
  %29 = call reassoc arcp contract float @llvm.fmuladd.f32(float %fmul8, float %fpfptrunc11, float %fmul12)
  %30 = insertelement <4 x float> %23, float %29, i64 2
  %31 = insertelement <4 x float> %30, float 0.000000e+00, i64 3
  store <4 x float> %31, ptr %a, align 16
  %32 = load float, ptr %y, align 4
  %33 = load float, ptr %x, align 4
  %fmul13 = fmul reassoc arcp contract float %32, %33
  %34 = load float, ptr %cosr, align 4
  %fpfpext14 = fpext
  %fsub15 = fsub reassoc arcp contract double 1.000000e+00, %fpfpext14
  %fpfptrunc16 = fptrunc
  %35 = load float, ptr %z, align 4
  %36 = load float, ptr %sinr, align 4
  %fmul17 = fmul reassoc arcp contract float %35, %36
  %37 = call reassoc arcp contract float @llvm.fmuladd.f32(float %fmul13, float %fpfptrunc16, float %fmul17)
  %38 = insertelement <4 x float> undef, float %37, i64 0
  %39 = load float, ptr %cosr, align 4
  %40 = load float, ptr %y, align 4
  %41 = load float, ptr %y, align 4
  %fmul18 = fmul reassoc arcp contract float %40, %41
  %42 = load float, ptr %cosr, align 4
  %fpfpext19 = fpext
  %fsub20 = fsub reassoc arcp contract double 1.000000e+00, %fpfpext19
  %fpfptrunc21 = fptrunc
  %43 = call reassoc arcp contract float @llvm.fmuladd.f32(float %fmul18, float %fpfptrunc21, float %39)
  %44 = insertelement <4 x float> %38, float %43, i64 1
  %45 = load float, ptr %y, align 4
  %46 = load float, ptr %z, align 4
  %fmul22 = fmul reassoc arcp contract float %45, %46
  %47 = load float, ptr %cosr, align 4
  %fpfpext23 = fpext
  %fsub24 = fsub reassoc arcp contract double 1.000000e+00, %fpfpext23
  %fpfptrunc25 = fptrunc
  %48 = load float, ptr %x, align 4
  %49 = load float, ptr %sinr, align 4
  %fmul26 = fmul reassoc arcp contract float %48, %49
  %50 = fneg reassoc arcp contract float %fmul26
  %51 = call reassoc arcp contract float @llvm.fmuladd.f32(float %fmul22, float %fpfptrunc25, float %50)
  %52 = insertelement <4 x float> %44, float %51, i64 2
  %53 = insertelement <4 x float> %52, float 0.000000e+00, i64 3
  %ptradd = getelementptr inbounds i8, ptr %a, i64 16
  store <4 x float> %53, ptr %ptradd, align 16
  %54 = load float, ptr %z, align 4
  %55 = load float, ptr %x, align 4
  %fmul27 = fmul reassoc arcp contract float %54, %55
  %56 = load float, ptr %cosr, align 4
  %fpfpext28 = fpext
  %fsub29 = fsub reassoc arcp contract double 1.000000e+00, %fpfpext28
  %fpfptrunc30 = fptrunc
  %57 = load float, ptr %y, align 4
  %58 = load float, ptr %sinr, align 4
  %fmul31 = fmul reassoc arcp contract float %57, %58
  %59 = fneg reassoc arcp contract float %fmul31
  %60 = call reassoc arcp contract float @llvm.fmuladd.f32(float %fmul27, float %fpfptrunc30, float %59)
  %61 = insertelement <4 x float> undef, float %60, i64 0
  %62 = load float, ptr %z, align 4
  %63 = load float, ptr %y, align 4
  %fmul32 = fmul reassoc arcp contract float %62, %63
  %64 = load float, ptr %cosr, align 4
  %fpfpext33 = fpext
  %fsub34 = fsub reassoc arcp contract double 1.000000e+00, %fpfpext33
  %fpfptrunc35 = fptrunc
  %65 = load float, ptr %x, align 4
  %66 = load float, ptr %sinr, align 4
  %fmul36 = fmul reassoc arcp contract float %65, %66
  %67 = call reassoc arcp contract float @llvm.fmuladd.f32(float %fmul32, float %fpfptrunc35, float %fmul36)
  %68 = insertelement <4 x float> %61, float %67, i64 1
  %69 = load float, ptr %cosr, align 4
  %70 = load float, ptr %z, align 4
  %71 = load float, ptr %z, align 4
  %fmul37 = fmul reassoc arcp contract float %70, %71
  %72 = load float, ptr %cosr, align 4
  %fpfpext38 = fpext
  %fsub39 = fsub reassoc arcp contract double 1.000000e+00, %fpfpext38
  %fpfptrunc40 = fptrunc
  %73 = call reassoc arcp contract float @llvm.fmuladd.f32(float %fmul37, float %fpfptrunc40, float %69)
  %74 = insertelement <4 x float> %68, float %73, i64 2
  %75 = insertelement <4 x float> %74, float 0.000000e+00, i64 3
  %ptradd41 = getelementptr inbounds i8, ptr %a, i64 32
  store <4 x float> %75, ptr %ptradd41, align 16
  %ptradd42 = getelementptr inbounds i8, ptr %a, i64 48
  store <4 x float> <float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float 1.000000e+00>, ptr %ptradd42, align 16
  %76 = load float, ptr %cosr, align 4
  %77 = load float, ptr %x, align 4
  %78 = load float, ptr %x, align 4
  %fmul43 = fmul reassoc arcp contract float %77, %78
  %79 = load float, ptr %cosr, align 4
  %fpfpext44 = fpext
  %fsub45 = fsub reassoc arcp contract double 1.000000e+00, %fpfpext44
  %fpfptrunc46 = fptrunc
  %80 = call reassoc arcp contract float @llvm.fmuladd.f32(float %fmul43, float %fpfptrunc46, float %76)
  %81 = insertelement <4 x float> undef, float %80, i64 0
  %82 = load float, ptr %x, align 4
  %83 = load float, ptr %y, align 4
  %fmul47 = fmul reassoc arcp contract float %82, %83
  %84 = load float, ptr %cosr, align 4
  %fpfpext48 = fpext
  %fsub49 = fsub reassoc arcp contract double 1.000000e+00, %fpfpext48
  %fpfptrunc50 = fptrunc
  %85 = load float, ptr %z, align 4
  %86 = load float, ptr %sinr, align 4
  %fmul51 = fmul reassoc arcp contract float %85, %86
  %87 = fneg reassoc arcp contract float %fmul51
  %88 = call reassoc arcp contract float @llvm.fmuladd.f32(float %fmul47, float %fpfptrunc50, float %87)
  %89 = insertelement <4 x float> %81, float %88, i64 1
  %90 = load float, ptr %x, align 4
  %91 = load float, ptr %z, align 4
  %fmul52 = fmul reassoc arcp contract float %90, %91
  %92 = load float, ptr %cosr, align 4
  %fpfpext53 = fpext
  %fsub54 = fsub reassoc arcp contract double 1.000000e+00, %fpfpext53
  %fpfptrunc55 = fptrunc
  %93 = load float, ptr %y, align 4
  %94 = load float, ptr %sinr, align 4
  %fmul56 = fmul reassoc arcp contract float %93, %94
  %95 = call reassoc arcp contract float @llvm.fmuladd.f32(float %fmul52, float %fpfptrunc55, float %fmul56)
  %96 = insertelement <4 x float> %89, float %95, i64 2
  %97 = insertelement <4 x float> %96, float 0.000000e+00, i64 3
  store <4 x float> %97, ptr %b, align 16
  %ptradd57 = getelementptr inbounds i8, ptr %b, i64 16
  %98 = load float, ptr %y, align 4
  %99 = load float, ptr %x, align 4
  %fmul58 = fmul reassoc arcp contract float %98, %99
  %100 = load float, ptr %cosr, align 4
  %fpfpext59 = fpext
  %fsub60 = fsub reassoc arcp contract double 1.000000e+00, %fpfpext59
  %fpfptrunc61 = fptrunc
  %101 = load float, ptr %z, align 4
  %102 = load float, ptr %sinr, align 4
  %fmul62 = fmul reassoc arcp contract float %101, %102
  %103 = call reassoc arcp contract float @llvm.fmuladd.f32(float %fmul58, float %fpfptrunc61, float %fmul62)
  %104 = insertelement <4 x float> undef, float %103, i64 0
  %105 = load float, ptr %cosr, align 4
  %106 = load float, ptr %y, align 4
  %107 = load float, ptr %y, align 4
  %fmul63 = fmul reassoc arcp contract float %106, %107
  %108 = load float, ptr %cosr, align 4
  %fpfpext64 = fpext
  %fsub65 = fsub reassoc arcp contract double 1.000000e+00, %fpfpext64
  %fpfptrunc66 = fptrunc
  %109 = call reassoc arcp contract float @llvm.fmuladd.f32(float %fmul63, float %fpfptrunc66, float %105)
  %110 = insertelement <4 x float> %104, float %109, i64 1
  %111 = load float, ptr %y, align 4
  %112 = load float, ptr %z, align 4
  %fmul67 = fmul reassoc arcp contract float %111, %112
  %113 = load float, ptr %cosr, align 4
  %fpfpext68 = fpext
  %fsub69 = fsub reassoc arcp contract double 1.000000e+00, %fpfpext68
  %fpfptrunc70 = fptrunc
  %114 = load float, ptr %x, align 4
  %115 = load float, ptr %sinr, align 4
  %fmul71 = fmul reassoc arcp contract float %114, %115
  %116 = fneg reassoc arcp contract float %fmul71
  %117 = call reassoc arcp contract float @llvm.fmuladd.f32(float %fmul67, float %fpfptrunc70, float %116)
  %118 = insertelement <4 x float> %110, float %117, i64 2
  %119 = insertelement <4 x float> %118, float 0.000000e+00, i64 3
  store <4 x float> %119, ptr %ptradd57, align 16
  %ptradd72 = getelementptr inbounds i8, ptr %b, i64 32
  %120 = load float, ptr %z, align 4
  %121 = load float, ptr %x, align 4
  %fmul73 = fmul reassoc arcp contract float %120, %121
  %122 = load float, ptr %cosr, align 4
  %fpfpext74 = fpext
  %fsub75 = fsub reassoc arcp contract double 1.000000e+00, %fpfpext74
  %fpfptrunc76 = fptrunc
  %123 = load float, ptr %y, align 4
  %124 = load float, ptr %sinr, align 4
  %fmul77 = fmul reassoc arcp contract float %123, %124
  %125 = fneg reassoc arcp contract float %fmul77
  %126 = call reassoc arcp contract float @llvm.fmuladd.f32(float %fmul73, float %fpfptrunc76, float %125)
  %127 = insertelement <4 x float> undef, float %126, i64 0
  %128 = load float, ptr %z, align 4
  %129 = load float, ptr %y, align 4
  %fmul78 = fmul reassoc arcp contract float %128, %129
  %130 = load float, ptr %cosr, align 4
  %fpfpext79 = fpext
  %fsub80 = fsub reassoc arcp contract double 1.000000e+00, %fpfpext79
  %fpfptrunc81 = fptrunc
  %131 = load float, ptr %x, align 4
  %132 = load float, ptr %sinr, align 4
  %fmul82 = fmul reassoc arcp contract float %131, %132
  %133 = call reassoc arcp contract float @llvm.fmuladd.f32(float %fmul78, float %fpfptrunc81, float %fmul82)
  %134 = insertelement <4 x float> %127, float %133, i64 1
  %135 = load float, ptr %cosr, align 4
  %136 = load float, ptr %z, align 4
  %137 = load float, ptr %z, align 4
  %fmul83 = fmul reassoc arcp contract float %136, %137
  %138 = load float, ptr %cosr, align 4
  %fpfpext84 = fpext
  %fsub85 = fsub reassoc arcp contract double 1.000000e+00, %fpfpext84
  %fpfptrunc86 = fptrunc
  %139 = call reassoc arcp contract float @llvm.fmuladd.f32(float %fmul83, float %fpfptrunc86, float %135)
  %140 = insertelement <4 x float> %134, float %139, i64 2
  %141 = insertelement <4 x float> %140, float 0.000000e+00, i64 3
  store <4 x float> %141, ptr %ptradd72, align 16
  %ptradd87 = getelementptr inbounds i8, ptr %b, i64 48
  store <4 x float> <float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float 1.000000e+00>, ptr %ptradd87, align 16
  store i64 0, ptr %.anon, align 8
  br label %loop.cond

loop.cond:                                        ; preds = %loop.body, %entry
  %142 = load i64, ptr %.anon, align 8
  %gt = icmp ugt i64 4, %142
  br i1 %gt, label %loop.body, label %loop.exit

loop.body:                                        ; preds = %loop.cond
  %143 = load i64, ptr %.anon, align 8
  %ptroffset = getelementptr inbounds [16 x i8], ptr %a, i64 %143
  %144 = load <4 x float>, ptr %ptroffset, align 16
  store <4 x float> %144, ptr %v, align 16
  %145 = load <4 x float>, ptr %v, align 16
  %146 = extractelement <4 x float> %145, i64 0
  %fpfpext88 = fpext
  %147 = load <4 x float>, ptr %v, align 16
  %148 = extractelement <4 x float> %147, i64 1
  %fpfpext89 = fpext
  %149 = load <4 x float>, ptr %v, align 16
  %150 = extractelement <4 x float> %149, i64 2
  %fpfpext90 = fpext
  %151 = load <4 x float>, ptr %v, align 16
  %152 = extractelement <4 x float> %151, i64 3
  %fpfpext91 = fpext
  %153 = call i32 (ptr, ...) @printf(ptr @.str, double %fpfpext88, double %fpfpext89, double %fpfpext90, double %fpfpext91)
  %154 = load i64, ptr %.anon, align 8
  %addnuw = add nuw i64 %154, 1
  store i64 %addnuw, ptr %.anon, align 8
  br label %loop.cond

loop.exit:                                        ; preds = %loop.cond
  %155 = call i32 (ptr, ...) @printf(ptr @.str.1)
  store i64 0, ptr %.anon92, align 8
  br label %loop.cond93

loop.cond93:                                      ; preds = %loop.body95, %loop.exit
  %156 = load i64, ptr %.anon92, align 8
  %gt94 = icmp ugt i64 4, %156
  br i1 %gt94, label %loop.body95, label %loop.exit103

loop.body95:                                      ; preds = %loop.cond93
  %157 = load i64, ptr %.anon92, align 8
  %ptroffset97 = getelementptr inbounds [16 x i8], ptr %b, i64 %157
  %158 = load <4 x float>, ptr %ptroffset97, align 16
  store <4 x float> %158, ptr %v96, align 16
  %159 = load <4 x float>, ptr %v96, align 16
  %160 = extractelement <4 x float> %159, i64 0
  %fpfpext98 = fpext
  %161 = load <4 x float>, ptr %v96, align 16
  %162 = extractelement <4 x float> %161, i64 1
  %fpfpext99 = fpext
  %163 = load <4 x float>, ptr %v96, align 16
  %164 = extractelement <4 x float> %163, i64 2
  %fpfpext100 = fpext
  %165 = load <4 x float>, ptr %v96, align 16
  %166 = extractelement <4 x float> %165, i64 3
  %fpfpext101 = fpext
  %167 = call i32 (ptr, ...) @printf(ptr @.str.2, double %fpfpext98, double %fpfpext99, double %fpfpext100, double %fpfpext101)
  %168 = load i64, ptr %.anon92, align 8
  %addnuw102 = add nuw i64 %168, 1
  store i64 %addnuw102, ptr %.anon92, align 8
  br label %loop.cond93

loop.exit103:                                     ; preds = %loop.cond93
  ret void
}