double vcos(double *vertex, int v1, int v2, int v3) {
  double e1[3], e2[3];
  e1[0] = vertex[3 * v1 + 0] - vertex[3 * v2 + 0];
  e1[1] = vertex[3 * v1 + 1] - vertex[3 * v2 + 1];
  e1[2] = vertex[3 * v1 + 2] - vertex[3 * v2 + 2];
  e2[0] = vertex[3 * v3 + 0] - vertex[3 * v2 + 0];
  e2[1] = vertex[3 * v3 + 1] - vertex[3 * v2 + 1];
  e2[2] = vertex[3 * v3 + 2] - vertex[3 * v2 + 2];
  vnorm(e1), vnorm(e2);
  return dot(e1, e2);
}


x86 assembly (clang, -O0):
<vcos>:
push   %rbp
mov    %rsp,%rbp
sub    $0x50,%rsp
mov    %rdi,-0x8(%rbp)
mov    %esi,-0xc(%rbp)
mov    %edx,-0x10(%rbp)
mov    %ecx,-0x14(%rbp)
mov    -0x8(%rbp),%rax
imul   $0x3,-0xc(%rbp),%ecx
add    $0x0,%ecx
movslq %ecx,%rcx
movsd  (%rax,%rcx,8),%xmm0
mov    -0x8(%rbp),%rax
imul   $0x3,-0x10(%rbp),%ecx
add    $0x0,%ecx
movslq %ecx,%rcx
subsd  (%rax,%rcx,8),%xmm0
movsd  %xmm0,-0x30(%rbp)
mov    -0x8(%rbp),%rax
imul   $0x3,-0xc(%rbp),%ecx
add    $0x1,%ecx
movslq %ecx,%rcx
movsd  (%rax,%rcx,8),%xmm0
mov    -0x8(%rbp),%rax
imul   $0x3,-0x10(%rbp),%ecx
add    $0x1,%ecx
movslq %ecx,%rcx
subsd  (%rax,%rcx,8),%xmm0
movsd  %xmm0,-0x28(%rbp)
mov    -0x8(%rbp),%rax
imul   $0x3,-0xc(%rbp),%ecx
add    $0x2,%ecx
movslq %ecx,%rcx
movsd  (%rax,%rcx,8),%xmm0
mov    -0x8(%rbp),%rax
imul   $0x3,-0x10(%rbp),%ecx
add    $0x2,%ecx
movslq %ecx,%rcx
subsd  (%rax,%rcx,8),%xmm0
movsd  %xmm0,-0x20(%rbp)
mov    -0x8(%rbp),%rax
imul   $0x3,-0x14(%rbp),%ecx
add    $0x0,%ecx
movslq %ecx,%rcx
movsd  (%rax,%rcx,8),%xmm0
mov    -0x8(%rbp),%rax
imul   $0x3,-0x10(%rbp),%ecx
add    $0x0,%ecx
movslq %ecx,%rcx
subsd  (%rax,%rcx,8),%xmm0
movsd  %xmm0,-0x50(%rbp)
mov    -0x8(%rbp),%rax
imul   $0x3,-0x14(%rbp),%ecx
add    $0x1,%ecx
movslq %ecx,%rcx
movsd  (%rax,%rcx,8),%xmm0
mov    -0x8(%rbp),%rax
imul   $0x3,-0x10(%rbp),%ecx
add    $0x1,%ecx
movslq %ecx,%rcx
subsd  (%rax,%rcx,8),%xmm0
movsd  %xmm0,-0x48(%rbp)
mov    -0x8(%rbp),%rax
imul   $0x3,-0x14(%rbp),%ecx
add    $0x2,%ecx
movslq %ecx,%rcx
movsd  (%rax,%rcx,8),%xmm0
mov    -0x8(%rbp),%rax
imul   $0x3,-0x10(%rbp),%ecx
add    $0x2,%ecx
movslq %ecx,%rcx
subsd  (%rax,%rcx,8),%xmm0
movsd  %xmm0,-0x40(%rbp)
lea    -0x30(%rbp),%rdi
mov    $0x0,%al
call   1040 <vnorm@plt>
lea    -0x50(%rbp),%rdi
mov    $0x0,%al
call   1040 <vnorm@plt>
lea    -0x30(%rbp),%rdi
lea    -0x50(%rbp),%rsi
mov    $0x0,%al
call   1030 <dot@plt>
cvtsi2sd %eax,%xmm0
add    $0x50,%rsp
pop    %rbp
ret

x86 assembly (clang, -O2):
<vcos>:
push   %r14
push   %rbx
sub    $0x38,%rsp
lea    (%rsi,%rsi,2),%eax
cltq
lea    (%rdx,%rdx,2),%edx
movslq %edx,%rdx
movupd (%rdi,%rax,8),%xmm0
movupd (%rdi,%rdx,8),%xmm1
subpd  %xmm1,%xmm0
movapd %xmm0,0x20(%rsp)
movsd  0x10(%rdi,%rax,8),%xmm0
movsd  0x10(%rdi,%rdx,8),%xmm2
subsd  %xmm2,%xmm0
movsd  %xmm0,0x30(%rsp)
lea    (%rcx,%rcx,2),%eax
cltq
movupd (%rdi,%rax,8),%xmm0
subpd  %xmm1,%xmm0
movapd %xmm0,(%rsp)
movsd  0x10(%rdi,%rax,8),%xmm0
subsd  %xmm2,%xmm0
movsd  %xmm0,0x10(%rsp)
lea    0x20(%rsp),%r14
mov    %r14,%rdi
xor    %eax,%eax
call   1040 <vnorm@plt>
mov    %rsp,%rbx
mov    %rbx,%rdi
xor    %eax,%eax
call   1040 <vnorm@plt>
mov    %r14,%rdi
mov    %rbx,%rsi
xor    %eax,%eax
call   1030 <dot@plt>
xorps  %xmm0,%xmm0
cvtsi2sd %eax,%xmm0
add    $0x38,%rsp
pop    %rbx
pop    %r14
ret

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

LLVM IR (-O2):
define double @vcos(double* nocapture %0, i32 %1, i32 %2, i32 %3) {
%5 = alloca [3 x double]
%6 = alloca [3 x double]
%7 = bitcast [3 x double]* %5 to i8*
%8 = bitcast [3 x double]* %6 to i8*
%9 = mul nsw i32 %1, 3
%10 = sext i32 %9 to i64
%11 = getelementptr inbounds double, double* %0, i64 %10
%12 = mul nsw i32 %2, 3
%13 = sext i32 %12 to i64
%14 = getelementptr inbounds double, double* %0, i64 %13
%15 = getelementptr inbounds [3 x double], [3 x double]* %5, i64 0, i64 0
%16 = bitcast double* %11 to <2 x double>*
%17 = load <2 x double>, <2 x double>* %16
%18 = bitcast double* %14 to <2 x double>*
%19 = load <2 x double>, <2 x double>* %18
%20 = fsub <2 x double> %17, %19
%21 = bitcast [3 x double]* %5 to <2 x double>*
store <2 x double> %20, <2 x double>* %21
%22 = add nsw i32 %9, 2
%23 = sext i32 %22 to i64
%24 = getelementptr inbounds double, double* %0, i64 %23
%25 = load double, double* %24
%26 = add nsw i32 %12, 2
%27 = sext i32 %26 to i64
%28 = getelementptr inbounds double, double* %0, i64 %27
%29 = load double, double* %28
%30 = fsub double %25, %29
%31 = getelementptr inbounds [3 x double], [3 x double]* %5, i64 0, i64 2
store double %30, double* %31
%32 = mul nsw i32 %3, 3
%33 = sext i32 %32 to i64
%34 = getelementptr inbounds double, double* %0, i64 %33
%35 = load double, double* %34
%36 = getelementptr inbounds [3 x double], [3 x double]* %6, i64 0, i64 0
%37 = add nsw i32 %32, 1
%38 = sext i32 %37 to i64
%39 = getelementptr inbounds double, double* %0, i64 %38
%40 = load double, double* %39
%41 = insertelement <2 x double> poison, double %35, i64 0
%42 = insertelement <2 x double> %41, double %40, i64 1
%43 = fsub <2 x double> %42, %19
%44 = bitcast [3 x double]* %6 to <2 x double>*
store <2 x double> %43, <2 x double>* %44
%45 = add nsw i32 %32, 2
%46 = sext i32 %45 to i64
%47 = getelementptr inbounds double, double* %0, i64 %46
%48 = load double, double* %47
%49 = fsub double %48, %29
%50 = getelementptr inbounds [3 x double], [3 x double]* %6, i64 0, i64 2
store double %49, double* %50
%51 = call i32 (double*, ...) bitcast (i32 (...)* @vnorm to i32 (double*, ...)*)(double* %15)
%52 = call i32 (double*, ...) bitcast (i32 (...)* @vnorm to i32 (double*, ...)*)(double* %36)
%53 = call i32 (double*, double*, ...) bitcast (i32 (...)* @dot to i32 (double*, double*, ...)*)(double* %15, double* %36)
%54 = sitofp i32 %53 to double
ret double %54
}