#define NULL ((void *)0)
typedef unsigned long size_t; // Customize by platform.
typedef long intptr_t;
typedef unsigned long uintptr_t;
typedef long scalar_t__; // Either arithmetic or pointer type.
/* By default, we understand bool (as a convenience). */
typedef int bool;
#define false 0
#define true 1

/* Forward declarations */

/* Type definitions */

/* Variables and functions */
int /*<<< orphan*/ memcpy(double **, double **, int);
void homo_op_mul(double O[3][4], double A[3][4], double B[3][4]) {
  double H[3][4];
  int i, j;
  for (j = 0; j < 3; j++)
    for (i = 0; i < 4; i++)
      H[j][i] = A[j][0] * B[0][i] + A[j][1] * B[1][i] + A[j][2] * B[2][i];
  for (i = 0; i < 3; i++)
    H[i][3] += A[i][3];
  memcpy(O, H, sizeof(double) * 3 * 4);
}


x86 assembly (clang, -O0):
<homo_op_mul>:
push   %rbp
mov    %rsp,%rbp
sub    $0x90,%rsp
mov    %rdi,-0x8(%rbp)
mov    %rsi,-0x10(%rbp)
mov    %rdx,-0x18(%rbp)
movl   $0x0,-0x88(%rbp)
cmpl   $0x3,-0x88(%rbp)
jge    1226 <homo_op_mul+0x116>
movl   $0x0,-0x84(%rbp)
cmpl   $0x4,-0x84(%rbp)
jge    120d <homo_op_mul+0xfd>
mov    -0x10(%rbp),%rax
movslq -0x88(%rbp),%rcx
shl    $0x5,%rcx
add    %rcx,%rax
movsd  (%rax),%xmm1
mov    -0x18(%rbp),%rax
movslq -0x84(%rbp),%rcx
movsd  (%rax,%rcx,8),%xmm2
mov    -0x10(%rbp),%rax
movslq -0x88(%rbp),%rcx
shl    $0x5,%rcx
add    %rcx,%rax
movsd  0x8(%rax),%xmm0
mov    -0x18(%rbp),%rax
movslq -0x84(%rbp),%rcx
mulsd  0x20(%rax,%rcx,8),%xmm0
mulsd  %xmm2,%xmm1
addsd  %xmm0,%xmm1
mov    -0x10(%rbp),%rax
movslq -0x88(%rbp),%rcx
shl    $0x5,%rcx
add    %rcx,%rax
movsd  0x10(%rax),%xmm0
mov    -0x18(%rbp),%rax
movslq -0x84(%rbp),%rcx
movsd  0x40(%rax,%rcx,8),%xmm2
mulsd  %xmm2,%xmm0
addsd  %xmm1,%xmm0
movslq -0x88(%rbp),%rcx
lea    -0x80(%rbp),%rax
shl    $0x5,%rcx
add    %rcx,%rax
movslq -0x84(%rbp),%rcx
movsd  %xmm0,(%rax,%rcx,8)
mov    -0x84(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x84(%rbp)
jmp    1148 <homo_op_mul+0x38>
jmp    1212 <homo_op_mul+0x102>
mov    -0x88(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x88(%rbp)
jmp    1131 <homo_op_mul+0x21>
movl   $0x0,-0x84(%rbp)
cmpl   $0x3,-0x84(%rbp)
jge    1284 <homo_op_mul+0x174>
mov    -0x10(%rbp),%rax
movslq -0x84(%rbp),%rcx
shl    $0x5,%rcx
add    %rcx,%rax
movsd  0x18(%rax),%xmm0
movslq -0x84(%rbp),%rcx
lea    -0x80(%rbp),%rax
shl    $0x5,%rcx
add    %rcx,%rax
addsd  0x18(%rax),%xmm0
movsd  %xmm0,0x18(%rax)
mov    -0x84(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x84(%rbp)
jmp    1230 <homo_op_mul+0x120>
mov    -0x8(%rbp),%rdi
lea    -0x80(%rbp),%rsi
mov    $0x60,%edx
call   1030 <memcpy@plt>
add    $0x90,%rsp
pop    %rbp
ret

x86 assembly (clang, -O2):
<homo_op_mul>:
sub    $0x68,%rsp
movsd  (%rsi),%xmm3
movsd  0x8(%rsi),%xmm5
movsd  0x10(%rsi),%xmm15
movapd %xmm5,%xmm1
unpcklpd %xmm5,%xmm1
movupd (%rdx),%xmm9
movupd 0x20(%rdx),%xmm10
movupd 0x40(%rdx),%xmm8
mulpd  %xmm10,%xmm1
movapd %xmm3,%xmm2
unpcklpd %xmm3,%xmm2
mulpd  %xmm9,%xmm2
addpd  %xmm1,%xmm2
movapd %xmm15,%xmm1
unpcklpd %xmm15,%xmm1
mulpd  %xmm8,%xmm1
addpd  %xmm2,%xmm1
movapd %xmm1,(%rsp)
movsd  0x10(%rdx),%xmm2
movsd  0x30(%rdx),%xmm14
movapd %xmm5,%xmm1
mulsd  %xmm14,%xmm1
movapd %xmm3,%xmm7
mulsd  %xmm2,%xmm7
addsd  %xmm1,%xmm7
movsd  0x50(%rdx),%xmm6
movapd %xmm15,%xmm1
mulsd  %xmm6,%xmm1
addsd  %xmm7,%xmm1
movsd  %xmm1,0x10(%rsp)
movsd  0x18(%rdx),%xmm11
movsd  0x38(%rdx),%xmm12
mulsd  %xmm12,%xmm5
mulsd  %xmm11,%xmm3
addsd  %xmm5,%xmm3
movsd  0x58(%rdx),%xmm13
mulsd  %xmm13,%xmm15
addsd  %xmm3,%xmm15
movsd  0x20(%rsi),%xmm4
movsd  0x28(%rsi),%xmm7
movsd  0x30(%rsi),%xmm3
movapd %xmm7,%xmm5
unpcklpd %xmm7,%xmm5
mulpd  %xmm10,%xmm5
movapd %xmm4,%xmm1
unpcklpd %xmm4,%xmm1
mulpd  %xmm9,%xmm1
addpd  %xmm5,%xmm1
movapd %xmm3,%xmm5
unpcklpd %xmm3,%xmm5
mulpd  %xmm8,%xmm5
addpd  %xmm1,%xmm5
movapd %xmm5,0x20(%rsp)
movapd %xmm7,%xmm1
mulsd  %xmm14,%xmm1
movapd %xmm4,%xmm5
mulsd  %xmm2,%xmm5
addsd  %xmm1,%xmm5
movapd %xmm3,%xmm1
mulsd  %xmm6,%xmm1
addsd  %xmm5,%xmm1
movsd  %xmm1,0x30(%rsp)
mulsd  %xmm12,%xmm7
mulsd  %xmm11,%xmm4
addsd  %xmm7,%xmm4
mulsd  %xmm13,%xmm3
addsd  %xmm4,%xmm3
movsd  0x40(%rsi),%xmm0
movsd  0x48(%rsi),%xmm5
movsd  0x50(%rsi),%xmm7
movapd %xmm5,%xmm4
unpcklpd %xmm5,%xmm4
mulpd  %xmm10,%xmm4
movapd %xmm0,%xmm1
unpcklpd %xmm0,%xmm1
mulpd  %xmm9,%xmm1
addpd  %xmm4,%xmm1
movapd %xmm7,%xmm4
unpcklpd %xmm7,%xmm4
mulpd  %xmm8,%xmm4
addpd  %xmm1,%xmm4
movapd %xmm4,0x40(%rsp)
mulsd  %xmm5,%xmm14
mulsd  %xmm0,%xmm2
addsd  %xmm14,%xmm2
mulsd  %xmm7,%xmm6
addsd  %xmm2,%xmm6
movsd  %xmm6,0x50(%rsp)
mulsd  %xmm12,%xmm5
mulsd  %xmm11,%xmm0
addsd  %xmm5,%xmm0
mulsd  %xmm13,%xmm7
addsd  0x18(%rsi),%xmm15
addsd  %xmm0,%xmm7
movsd  %xmm15,0x18(%rsp)
addsd  0x38(%rsi),%xmm3
movsd  %xmm3,0x38(%rsp)
addsd  0x58(%rsi),%xmm7
movsd  %xmm7,0x58(%rsp)
mov    %rsp,%rsi
mov    $0x60,%edx
call   1030 <memcpy@plt>
add    $0x68,%rsp
ret

LLVM IR (-O0):
define void @homo_op_mul([4 x double]* %0, [4 x double]* %1, [4 x double]* %2) {
%4 = alloca [4 x double]*
%5 = alloca [4 x double]*
%6 = alloca [4 x double]*
%7 = alloca [3 x [4 x double]]
%8 = alloca i32
%9 = alloca i32
store [4 x double]* %0, [4 x double]** %4
store [4 x double]* %1, [4 x double]** %5
store [4 x double]* %2, [4 x double]** %6
store i32 0, i32* %9
br label %10
10: ; preds = %67, %3
%11 = load i32, i32* %9
%12 = icmp slt i32 %11, 3
br i1 %12, label %13, label %70
13: ; preds = %10
store i32 0, i32* %8
br label %14
14: ; preds = %63, %13
%15 = load i32, i32* %8
%16 = icmp slt i32 %15, 4
br i1 %16, label %17, label %66
17: ; preds = %14
%18 = load [4 x double]*, [4 x double]** %5
%19 = load i32, i32* %9
%20 = sext i32 %19 to i64
%21 = getelementptr inbounds [4 x double], [4 x double]* %18, i64 %20
%22 = getelementptr inbounds [4 x double], [4 x double]* %21, i64 0, i64 0
%23 = load double, double* %22
%24 = load [4 x double]*, [4 x double]** %6
%25 = getelementptr inbounds [4 x double], [4 x double]* %24, i64 0
%26 = load i32, i32* %8
%27 = sext i32 %26 to i64
%28 = getelementptr inbounds [4 x double], [4 x double]* %25, i64 0, i64 %27
%29 = load double, double* %28
%30 = load [4 x double]*, [4 x double]** %5
%31 = load i32, i32* %9
%32 = sext i32 %31 to i64
%33 = getelementptr inbounds [4 x double], [4 x double]* %30, i64 %32
%34 = getelementptr inbounds [4 x double], [4 x double]* %33, i64 0, i64 1
%35 = load double, double* %34
%36 = load [4 x double]*, [4 x double]** %6
%37 = getelementptr inbounds [4 x double], [4 x double]* %36, i64 1
%38 = load i32, i32* %8
%39 = sext i32 %38 to i64
%40 = getelementptr inbounds [4 x double], [4 x double]* %37, i64 0, i64 %39
%41 = load double, double* %40
%42 = fmul double %35, %41
%43 = call double @llvm.fmuladd.f64(double %23, double %29, double %42)
%44 = load [4 x double]*, [4 x double]** %5
%45 = load i32, i32* %9
%46 = sext i32 %45 to i64
%47 = getelementptr inbounds [4 x double], [4 x double]* %44, i64 %46
%48 = getelementptr inbounds [4 x double], [4 x double]* %47, i64 0, i64 2
%49 = load double, double* %48
%50 = load [4 x double]*, [4 x double]** %6
%51 = getelementptr inbounds [4 x double], [4 x double]* %50, i64 2
%52 = load i32, i32* %8
%53 = sext i32 %52 to i64
%54 = getelementptr inbounds [4 x double], [4 x double]* %51, i64 0, i64 %53
%55 = load double, double* %54
%56 = call double @llvm.fmuladd.f64(double %49, double %55, double %43)
%57 = load i32, i32* %9
%58 = sext i32 %57 to i64
%59 = getelementptr inbounds [3 x [4 x double]], [3 x [4 x double]]* %7, i64 0, i64 %58
%60 = load i32, i32* %8
%61 = sext i32 %60 to i64
%62 = getelementptr inbounds [4 x double], [4 x double]* %59, i64 0, i64 %61
store double %56, double* %62
br label %63
63: ; preds = %17
%64 = load i32, i32* %8
%65 = add nsw i32 %64, 1
store i32 %65, i32* %8
br label %14
66: ; preds = %14
br label %67
67: ; preds = %66
%68 = load i32, i32* %9
%69 = add nsw i32 %68, 1
store i32 %69, i32* %9
br label %10
70: ; preds = %10
store i32 0, i32* %8
br label %71
71: ; preds = %87, %70
%72 = load i32, i32* %8
%73 = icmp slt i32 %72, 3
br i1 %73, label %74, label %90
74: ; preds = %71
%75 = load [4 x double]*, [4 x double]** %5
%76 = load i32, i32* %8
%77 = sext i32 %76 to i64
%78 = getelementptr inbounds [4 x double], [4 x double]* %75, i64 %77
%79 = getelementptr inbounds [4 x double], [4 x double]* %78, i64 0, i64 3
%80 = load double, double* %79
%81 = load i32, i32* %8
%82 = sext i32 %81 to i64
%83 = getelementptr inbounds [3 x [4 x double]], [3 x [4 x double]]* %7, i64 0, i64 %82
%84 = getelementptr inbounds [4 x double], [4 x double]* %83, i64 0, i64 3
%85 = load double, double* %84
%86 = fadd double %85, %80
store double %86, double* %84
br label %87
87: ; preds = %74
%88 = load i32, i32* %8
%89 = add nsw i32 %88, 1
store i32 %89, i32* %8
br label %71
90: ; preds = %71
%91 = load [4 x double]*, [4 x double]** %4
%92 = bitcast [4 x double]* %91 to double**
%93 = getelementptr inbounds [3 x [4 x double]], [3 x [4 x double]]* %7, i64 0, i64 0
%94 = bitcast [4 x double]* %93 to double**
%95 = call i32 @memcpy(double** %92, double** %94, i32 96)
ret void
}

LLVM IR (-O2):
define void @homo_op_mul([4 x double]* %0, [4 x double]* nocapture %1, [4 x double]* nocapture %2) {
%4 = alloca [3 x [4 x double]]
%5 = bitcast [3 x [4 x double]]* %4 to i8*
%6 = getelementptr inbounds [4 x double], [4 x double]* %1, i64 0, i64 0
%7 = load double, double* %6
%8 = getelementptr inbounds [4 x double], [4 x double]* %1, i64 0, i64 1
%9 = load double, double* %8
%10 = getelementptr inbounds [4 x double], [4 x double]* %1, i64 0, i64 2
%11 = load double, double* %10
%12 = getelementptr inbounds [4 x double], [4 x double]* %2, i64 1, i64 0
%13 = getelementptr inbounds [4 x double], [4 x double]* %2, i64 2, i64 0
%14 = bitcast [4 x double]* %2 to <2 x double>*
%15 = load <2 x double>, <2 x double>* %14
%16 = bitcast double* %12 to <2 x double>*
%17 = load <2 x double>, <2 x double>* %16
%18 = insertelement <2 x double> poison, double %9, i64 0
%19 = shufflevector <2 x double> %18, <2 x double> poison, <2 x i32> zeroinitializer
%20 = fmul <2 x double> %19, %17
%21 = insertelement <2 x double> poison, double %7, i64 0
%22 = shufflevector <2 x double> %21, <2 x double> poison, <2 x i32> zeroinitializer
%23 = call <2 x double> @llvm.fmuladd.v2f64(<2 x double> %22, <2 x double> %15, <2 x double> %20)
%24 = bitcast double* %13 to <2 x double>*
%25 = load <2 x double>, <2 x double>* %24
%26 = insertelement <2 x double> poison, double %11, i64 0
%27 = shufflevector <2 x double> %26, <2 x double> poison, <2 x i32> zeroinitializer
%28 = call <2 x double> @llvm.fmuladd.v2f64(<2 x double> %27, <2 x double> %25, <2 x double> %23)
%29 = bitcast [3 x [4 x double]]* %4 to <2 x double>*
store <2 x double> %28, <2 x double>* %29
%30 = getelementptr inbounds [4 x double], [4 x double]* %2, i64 0, i64 2
%31 = load double, double* %30
%32 = getelementptr inbounds [4 x double], [4 x double]* %2, i64 1, i64 2
%33 = load double, double* %32
%34 = fmul double %9, %33
%35 = tail call double @llvm.fmuladd.f64(double %7, double %31, double %34)
%36 = getelementptr inbounds [4 x double], [4 x double]* %2, i64 2, i64 2
%37 = load double, double* %36
%38 = tail call double @llvm.fmuladd.f64(double %11, double %37, double %35)
%39 = getelementptr inbounds [3 x [4 x double]], [3 x [4 x double]]* %4, i64 0, i64 0, i64 2
store double %38, double* %39
%40 = getelementptr inbounds [4 x double], [4 x double]* %2, i64 0, i64 3
%41 = load double, double* %40
%42 = getelementptr inbounds [4 x double], [4 x double]* %2, i64 1, i64 3
%43 = load double, double* %42
%44 = fmul double %9, %43
%45 = tail call double @llvm.fmuladd.f64(double %7, double %41, double %44)
%46 = getelementptr inbounds [4 x double], [4 x double]* %2, i64 2, i64 3
%47 = load double, double* %46
%48 = tail call double @llvm.fmuladd.f64(double %11, double %47, double %45)
%49 = getelementptr inbounds [3 x [4 x double]], [3 x [4 x double]]* %4, i64 0, i64 0, i64 3
%50 = getelementptr inbounds [4 x double], [4 x double]* %1, i64 1, i64 0
%51 = load double, double* %50
%52 = getelementptr inbounds [4 x double], [4 x double]* %1, i64 1, i64 1
%53 = load double, double* %52
%54 = getelementptr inbounds [4 x double], [4 x double]* %1, i64 1, i64 2
%55 = load double, double* %54
%56 = getelementptr inbounds [3 x [4 x double]], [3 x [4 x double]]* %4, i64 0, i64 1, i64 0
%57 = insertelement <2 x double> poison, double %53, i64 0
%58 = shufflevector <2 x double> %57, <2 x double> poison, <2 x i32> zeroinitializer
%59 = fmul <2 x double> %58, %17
%60 = insertelement <2 x double> poison, double %51, i64 0
%61 = shufflevector <2 x double> %60, <2 x double> poison, <2 x i32> zeroinitializer
%62 = call <2 x double> @llvm.fmuladd.v2f64(<2 x double> %61, <2 x double> %15, <2 x double> %59)
%63 = insertelement <2 x double> poison, double %55, i64 0
%64 = shufflevector <2 x double> %63, <2 x double> poison, <2 x i32> zeroinitializer
%65 = call <2 x double> @llvm.fmuladd.v2f64(<2 x double> %64, <2 x double> %25, <2 x double> %62)
%66 = bitcast double* %56 to <2 x double>*
store <2 x double> %65, <2 x double>* %66
%67 = fmul double %53, %33
%68 = tail call double @llvm.fmuladd.f64(double %51, double %31, double %67)
%69 = tail call double @llvm.fmuladd.f64(double %55, double %37, double %68)
%70 = getelementptr inbounds [3 x [4 x double]], [3 x [4 x double]]* %4, i64 0, i64 1, i64 2
store double %69, double* %70
%71 = fmul double %53, %43
%72 = tail call double @llvm.fmuladd.f64(double %51, double %41, double %71)
%73 = tail call double @llvm.fmuladd.f64(double %55, double %47, double %72)
%74 = getelementptr inbounds [3 x [4 x double]], [3 x [4 x double]]* %4, i64 0, i64 1, i64 3
%75 = getelementptr inbounds [4 x double], [4 x double]* %1, i64 2, i64 0
%76 = load double, double* %75
%77 = getelementptr inbounds [4 x double], [4 x double]* %1, i64 2, i64 1
%78 = load double, double* %77
%79 = getelementptr inbounds [4 x double], [4 x double]* %1, i64 2, i64 2
%80 = load double, double* %79
%81 = getelementptr inbounds [3 x [4 x double]], [3 x [4 x double]]* %4, i64 0, i64 2, i64 0
%82 = insertelement <2 x double> poison, double %78, i64 0
%83 = shufflevector <2 x double> %82, <2 x double> poison, <2 x i32> zeroinitializer
%84 = fmul <2 x double> %83, %17
%85 = insertelement <2 x double> poison, double %76, i64 0
%86 = shufflevector <2 x double> %85, <2 x double> poison, <2 x i32> zeroinitializer
%87 = call <2 x double> @llvm.fmuladd.v2f64(<2 x double> %86, <2 x double> %15, <2 x double> %84)
%88 = insertelement <2 x double> poison, double %80, i64 0
%89 = shufflevector <2 x double> %88, <2 x double> poison, <2 x i32> zeroinitializer
%90 = call <2 x double> @llvm.fmuladd.v2f64(<2 x double> %89, <2 x double> %25, <2 x double> %87)
%91 = bitcast double* %81 to <2 x double>*
store <2 x double> %90, <2 x double>* %91
%92 = fmul double %78, %33
%93 = tail call double @llvm.fmuladd.f64(double %76, double %31, double %92)
%94 = tail call double @llvm.fmuladd.f64(double %80, double %37, double %93)
%95 = getelementptr inbounds [3 x [4 x double]], [3 x [4 x double]]* %4, i64 0, i64 2, i64 2
store double %94, double* %95
%96 = fmul double %78, %43
%97 = tail call double @llvm.fmuladd.f64(double %76, double %41, double %96)
%98 = tail call double @llvm.fmuladd.f64(double %80, double %47, double %97)
%99 = getelementptr inbounds [3 x [4 x double]], [3 x [4 x double]]* %4, i64 0, i64 2, i64 3
%100 = getelementptr inbounds [4 x double], [4 x double]* %1, i64 0, i64 3
%101 = load double, double* %100
%102 = fadd double %101, %48
store double %102, double* %49
%103 = getelementptr inbounds [4 x double], [4 x double]* %1, i64 1, i64 3
%104 = load double, double* %103
%105 = fadd double %104, %73
store double %105, double* %74
%106 = getelementptr inbounds [4 x double], [4 x double]* %1, i64 2, i64 3
%107 = load double, double* %106
%108 = fadd double %107, %98
store double %108, double* %99
%109 = bitcast [4 x double]* %0 to double**
%110 = bitcast [3 x [4 x double]]* %4 to double**
%111 = call i32 @memcpy(double** %109, double** %110, i32 96)
ret void
}