void lin_fmN(const double *u, double *p, const int *inl, int len, double *A1,
             double *A2) {
  const double *s;
  double a[3], b[3];
  int i, k, l;
  a[2] = 1;
  b[2] = 1;
  s = u;
  for (i = 0; i < len; i++) {
    s = u + 6 * inl[i];
    a[0] = *(s)*A1[0] + A1[1];
    a[1] = *(s + 1) * A1[0] + A1[2];
    b[0] = *(s + 3) * A2[0] + A2[1];
    b[1] = *(s + 4) * A2[0] + A2[2];
    for (k = 0; k < 3; k++)
      for (l = 0; l < 3; l++) {
        *p = a[l] * b[k];
        p++;
      }
  }
}


x86 assembly (clang, -O0):
<lin_fmN>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x8(%rbp)
mov    %rsi,-0x10(%rbp)
mov    %rdx,-0x18(%rbp)
mov    %ecx,-0x1c(%rbp)
mov    %r8,-0x28(%rbp)
mov    %r9,-0x30(%rbp)
movsd  0xedd(%rip),%xmm0
movsd  %xmm0,-0x40(%rbp)
movsd  0xed0(%rip),%xmm0
movsd  %xmm0,-0x60(%rbp)
mov    -0x8(%rbp),%rax
mov    %rax,-0x38(%rbp)
movl   $0x0,-0x74(%rbp)
mov    -0x74(%rbp),%eax
cmp    -0x1c(%rbp),%eax
jge    1287 <lin_fmN+0x187>
mov    -0x8(%rbp),%rax
mov    -0x18(%rbp),%rcx
movslq -0x74(%rbp),%rdx
imul   $0x6,(%rcx,%rdx,4),%ecx
movslq %ecx,%rcx
shl    $0x3,%rcx
add    %rcx,%rax
mov    %rax,-0x38(%rbp)
mov    -0x38(%rbp),%rax
movsd  (%rax),%xmm0
mov    -0x28(%rbp),%rax
movsd  (%rax),%xmm2
mov    -0x28(%rbp),%rax
movsd  0x8(%rax),%xmm1
mulsd  %xmm2,%xmm0
addsd  %xmm1,%xmm0
movsd  %xmm0,-0x50(%rbp)
mov    -0x38(%rbp),%rax
movsd  0x8(%rax),%xmm0
mov    -0x28(%rbp),%rax
movsd  (%rax),%xmm2
mov    -0x28(%rbp),%rax
movsd  0x10(%rax),%xmm1
mulsd  %xmm2,%xmm0
addsd  %xmm1,%xmm0
movsd  %xmm0,-0x48(%rbp)
mov    -0x38(%rbp),%rax
movsd  0x18(%rax),%xmm0
mov    -0x30(%rbp),%rax
movsd  (%rax),%xmm2
mov    -0x30(%rbp),%rax
movsd  0x8(%rax),%xmm1
mulsd  %xmm2,%xmm0
addsd  %xmm1,%xmm0
movsd  %xmm0,-0x70(%rbp)
mov    -0x38(%rbp),%rax
movsd  0x20(%rax),%xmm0
mov    -0x30(%rbp),%rax
movsd  (%rax),%xmm2
mov    -0x30(%rbp),%rax
movsd  0x10(%rax),%xmm1
mulsd  %xmm2,%xmm0
addsd  %xmm1,%xmm0
movsd  %xmm0,-0x68(%rbp)
movl   $0x0,-0x78(%rbp)
cmpl   $0x3,-0x78(%rbp)
jge    1274 <lin_fmN+0x174>
movl   $0x0,-0x7c(%rbp)
cmpl   $0x3,-0x7c(%rbp)
jge    1261 <lin_fmN+0x161>
movslq -0x7c(%rbp),%rax
movsd  -0x50(%rbp,%rax,8),%xmm0
movslq -0x78(%rbp),%rax
mulsd  -0x70(%rbp,%rax,8),%xmm0
mov    -0x10(%rbp),%rax
movsd  %xmm0,(%rax)
mov    -0x10(%rbp),%rax
add    $0x8,%rax
mov    %rax,-0x10(%rbp)
mov    -0x7c(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x7c(%rbp)
jmp    1221 <lin_fmN+0x121>
jmp    1266 <lin_fmN+0x166>
mov    -0x78(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x78(%rbp)
jmp    1210 <lin_fmN+0x110>
jmp    1279 <lin_fmN+0x179>
mov    -0x74(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x74(%rbp)
jmp    1144 <lin_fmN+0x44>
pop    %rbp
ret

x86 assembly (clang, -O2):
<lin_fmN>:
test   %ecx,%ecx
jle    11ae <lin_fmN+0xae>
mov    %ecx,%r11d
xor    %ecx,%ecx
movabs $0x3ff0000000000000,%r10
nopw   0x0(%rax,%rax,1)
movslq (%rdx,%rcx,4),%rax
lea    (%rax,%rax,2),%rax
shl    $0x4,%rax
movupd (%rdi,%rax,1),%xmm0
movupd 0x8(%r8),%xmm1
movsd  (%r8),%xmm2
unpcklpd %xmm2,%xmm2
mulpd  %xmm0,%xmm2
movsd  (%r9),%xmm0
movsd  0x18(%rdi,%rax,1),%xmm3
mulsd  %xmm0,%xmm3
addsd  0x8(%r9),%xmm3
mulsd  0x20(%rdi,%rax,1),%xmm0
addpd  %xmm1,%xmm2
addsd  0x10(%r9),%xmm0
movapd %xmm3,%xmm1
unpcklpd %xmm3,%xmm1
mulpd  %xmm2,%xmm1
movupd %xmm1,(%rsi)
movsd  %xmm3,0x10(%rsi)
movapd %xmm0,%xmm1
unpcklpd %xmm0,%xmm1
mulpd  %xmm2,%xmm1
movupd %xmm1,0x18(%rsi)
movsd  %xmm0,0x28(%rsi)
movupd %xmm2,0x30(%rsi)
mov    %r10,0x40(%rsi)
add    $0x1,%rcx
add    $0x48,%rsi
cmp    %rcx,%r11
jne    1120 <lin_fmN+0x20>
ret

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

LLVM IR (-O2):
define void @lin_fmN(double* nocapture %0, double* nocapture writeonly %1, i32* nocapture %2, i32 %3, double* nocapture %4, double* nocapture %5) {
%7 = icmp sgt i32 %3, 0
br i1 %7, label %8, label %55
8: ; preds = %6
%9 = getelementptr inbounds double, double* %4, i64 1
%10 = getelementptr inbounds double, double* %5, i64 1
%11 = getelementptr inbounds double, double* %5, i64 2
%12 = zext i32 %3 to i64
%13 = bitcast double* %9 to <2 x double>*
br label %14
14: ; preds = %8, %14
%15 = phi i64 [ 0, %8 ], [ %53, %14 ]
%16 = phi double* [ %1, %8 ], [ %52, %14 ]
%17 = getelementptr inbounds i32, i32* %2, i64 %15
%18 = load i32, i32* %17
%19 = mul nsw i32 %18, 6
%20 = sext i32 %19 to i64
%21 = getelementptr inbounds double, double* %0, i64 %20
%22 = load double, double* %4
%23 = bitcast double* %21 to <2 x double>*
%24 = load <2 x double>, <2 x double>* %23
%25 = load <2 x double>, <2 x double>* %13
%26 = insertelement <2 x double> poison, double %22, 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> %24, <2 x double> %27, <2 x double> %25)
%29 = getelementptr inbounds double, double* %21, i64 3
%30 = load double, double* %29
%31 = load double, double* %5
%32 = load double, double* %10
%33 = tail call double @llvm.fmuladd.f64(double %30, double %31, double %32)
%34 = getelementptr inbounds double, double* %21, i64 4
%35 = load double, double* %34
%36 = load double, double* %11
%37 = tail call double @llvm.fmuladd.f64(double %35, double %31, double %36)
%38 = insertelement <2 x double> poison, double %33, i64 0
%39 = shufflevector <2 x double> %38, <2 x double> poison, <2 x i32> zeroinitializer
%40 = fmul <2 x double> %28, %39
%41 = bitcast double* %16 to <2 x double>*
store <2 x double> %40, <2 x double>* %41
%42 = getelementptr inbounds double, double* %16, i64 2
store double %33, double* %42
%43 = getelementptr inbounds double, double* %16, i64 3
%44 = insertelement <2 x double> poison, double %37, i64 0
%45 = shufflevector <2 x double> %44, <2 x double> poison, <2 x i32> zeroinitializer
%46 = fmul <2 x double> %28, %45
%47 = bitcast double* %43 to <2 x double>*
store <2 x double> %46, <2 x double>* %47
%48 = getelementptr inbounds double, double* %16, i64 5
store double %37, double* %48
%49 = getelementptr inbounds double, double* %16, i64 6
%50 = bitcast double* %49 to <2 x double>*
store <2 x double> %28, <2 x double>* %50
%51 = getelementptr inbounds double, double* %16, i64 8
store double 1.000000e+00, double* %51
%52 = getelementptr inbounds double, double* %16, i64 9
%53 = add nuw nsw i64 %15, 1
%54 = icmp eq i64 %53, %12
br i1 %54, label %55, label %14
55: ; preds = %14, %6
ret void
}