void _compute_viterbi(int *path, const double *A, const double *pobs,
                      const double *pi, int N, int T) {
  int i, j, t, maxi;
  double sum, maxprod, p;
  double *v = (double *)malloc(N * sizeof(double));
  double *vnext = (double *)malloc(N * sizeof(double));
  double *h = (double *)malloc(N * sizeof(double));
  double *vh;
  int *ptr = (int *)malloc(T * N * sizeof(int));
  sum = 0.0;
  for (i = 0; i < N; i++) {
    v[i] = pobs[i] * pi[i];
    sum += v[i];
  }
  for (i = 0; i < N; i++) {
    v[i] /= sum;
  }
  for (t = 1; t < T; t++) {
    sum = 0.0;
    for (j = 0; j < N; j++) {
      for (i = 0; i < N; i++) {
        h[i] = v[i] * A[i * N + j];
      }
      maxi = argmax(h, N);
      ptr[t * N + j] = maxi;
      vnext[j] = pobs[t * N + j] * v[maxi] * A[maxi * N + j];
      sum += vnext[j];
    }
    for (i = 0; i < N; i++) {
      vnext[i] /= sum;
    }
    vh = v;
    v = vnext;
    vnext = vh;
  }
  path[T - 1] = argmax(v, N);
  for (t = T - 2; t >= 0; t--) {
    path[t] = ptr[(t + 1) * N + path[t + 1]];
  }
  free(v);
  free(vnext);
  free(h);
  free(ptr);
}


x86 assembly (clang, -O0):
<_compute_viterbi>:
push   %rbp
mov    %rsp,%rbp
sub    $0x80,%rsp
mov    %rdi,-0x8(%rbp)
mov    %rsi,-0x10(%rbp)
mov    %rdx,-0x18(%rbp)
mov    %rcx,-0x20(%rbp)
mov    %r8d,-0x24(%rbp)
mov    %r9d,-0x28(%rbp)
movslq -0x24(%rbp),%rdi
shl    $0x3,%rdi
call   1050 <malloc@plt>
mov    %rax,-0x58(%rbp)
movslq -0x24(%rbp),%rdi
shl    $0x3,%rdi
call   1050 <malloc@plt>
mov    %rax,-0x60(%rbp)
movslq -0x24(%rbp),%rdi
shl    $0x3,%rdi
call   1050 <malloc@plt>
mov    %rax,-0x68(%rbp)
mov    -0x28(%rbp),%eax
imul   -0x24(%rbp),%eax
movslq %eax,%rdi
shl    $0x2,%rdi
call   1050 <malloc@plt>
mov    %rax,-0x78(%rbp)
xorps  %xmm0,%xmm0
movsd  %xmm0,-0x40(%rbp)
movl   $0x0,-0x2c(%rbp)
mov    -0x2c(%rbp),%eax
cmp    -0x24(%rbp),%eax
jge    1204 <_compute_viterbi+0xd4>
mov    -0x18(%rbp),%rax
movslq -0x2c(%rbp),%rcx
movsd  (%rax,%rcx,8),%xmm0
mov    -0x20(%rbp),%rax
movslq -0x2c(%rbp),%rcx
mulsd  (%rax,%rcx,8),%xmm0
mov    -0x58(%rbp),%rax
movslq -0x2c(%rbp),%rcx
movsd  %xmm0,(%rax,%rcx,8)
mov    -0x58(%rbp),%rax
movslq -0x2c(%rbp),%rcx
movsd  (%rax,%rcx,8),%xmm0
addsd  -0x40(%rbp),%xmm0
movsd  %xmm0,-0x40(%rbp)
mov    -0x2c(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x2c(%rbp)
jmp    11ac <_compute_viterbi+0x7c>
movl   $0x0,-0x2c(%rbp)
mov    -0x2c(%rbp),%eax
cmp    -0x24(%rbp),%eax
jge    1240 <_compute_viterbi+0x110>
movsd  -0x40(%rbp),%xmm1
mov    -0x58(%rbp),%rax
movslq -0x2c(%rbp),%rcx
movsd  (%rax,%rcx,8),%xmm0
divsd  %xmm1,%xmm0
movsd  %xmm0,(%rax,%rcx,8)
mov    -0x2c(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x2c(%rbp)
jmp    120b <_compute_viterbi+0xdb>
movl   $0x1,-0x34(%rbp)
mov    -0x34(%rbp),%eax
cmp    -0x28(%rbp),%eax
jge    13b4 <_compute_viterbi+0x284>
xorps  %xmm0,%xmm0
movsd  %xmm0,-0x40(%rbp)
movl   $0x0,-0x30(%rbp)
mov    -0x30(%rbp),%eax
cmp    -0x24(%rbp),%eax
jge    1352 <_compute_viterbi+0x222>
movl   $0x0,-0x2c(%rbp)
mov    -0x2c(%rbp),%eax
cmp    -0x24(%rbp),%eax
jge    12bf <_compute_viterbi+0x18f>
mov    -0x58(%rbp),%rax
movslq -0x2c(%rbp),%rcx
movsd  (%rax,%rcx,8),%xmm0
mov    -0x10(%rbp),%rax
mov    -0x2c(%rbp),%ecx
imul   -0x24(%rbp),%ecx
add    -0x30(%rbp),%ecx
movslq %ecx,%rcx
mulsd  (%rax,%rcx,8),%xmm0
mov    -0x68(%rbp),%rax
movslq -0x2c(%rbp),%rcx
movsd  %xmm0,(%rax,%rcx,8)
mov    -0x2c(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x2c(%rbp)
jmp    1275 <_compute_viterbi+0x145>
mov    -0x68(%rbp),%rdi
mov    -0x24(%rbp),%esi
mov    $0x0,%al
call   1040 <argmax@plt>
mov    %eax,-0x38(%rbp)
mov    -0x38(%rbp),%edx
mov    -0x78(%rbp),%rax
mov    -0x34(%rbp),%ecx
imul   -0x24(%rbp),%ecx
add    -0x30(%rbp),%ecx
movslq %ecx,%rcx
mov    %edx,(%rax,%rcx,4)
mov    -0x18(%rbp),%rax
mov    -0x34(%rbp),%ecx
imul   -0x24(%rbp),%ecx
add    -0x30(%rbp),%ecx
movslq %ecx,%rcx
movsd  (%rax,%rcx,8),%xmm0
mov    -0x58(%rbp),%rax
movslq -0x38(%rbp),%rcx
mulsd  (%rax,%rcx,8),%xmm0
mov    -0x10(%rbp),%rax
mov    -0x38(%rbp),%ecx
imul   -0x24(%rbp),%ecx
add    -0x30(%rbp),%ecx
movslq %ecx,%rcx
mulsd  (%rax,%rcx,8),%xmm0
mov    -0x60(%rbp),%rax
movslq -0x30(%rbp),%rcx
movsd  %xmm0,(%rax,%rcx,8)
mov    -0x60(%rbp),%rax
movslq -0x30(%rbp),%rcx
movsd  (%rax,%rcx,8),%xmm0
addsd  -0x40(%rbp),%xmm0
movsd  %xmm0,-0x40(%rbp)
mov    -0x30(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x30(%rbp)
jmp    1262 <_compute_viterbi+0x132>
movl   $0x0,-0x2c(%rbp)
mov    -0x2c(%rbp),%eax
cmp    -0x24(%rbp),%eax
jge    138e <_compute_viterbi+0x25e>
movsd  -0x40(%rbp),%xmm1
mov    -0x60(%rbp),%rax
movslq -0x2c(%rbp),%rcx
movsd  (%rax,%rcx,8),%xmm0
divsd  %xmm1,%xmm0
movsd  %xmm0,(%rax,%rcx,8)
mov    -0x2c(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x2c(%rbp)
jmp    1359 <_compute_viterbi+0x229>
mov    -0x58(%rbp),%rax
mov    %rax,-0x70(%rbp)
mov    -0x60(%rbp),%rax
mov    %rax,-0x58(%rbp)
mov    -0x70(%rbp),%rax
mov    %rax,-0x60(%rbp)
mov    -0x34(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x34(%rbp)
jmp    1247 <_compute_viterbi+0x117>
mov    -0x58(%rbp),%rdi
mov    -0x24(%rbp),%esi
mov    $0x0,%al
call   1040 <argmax@plt>
mov    %eax,%edx
mov    -0x8(%rbp),%rax
mov    -0x28(%rbp),%ecx
sub    $0x1,%ecx
movslq %ecx,%rcx
mov    %edx,(%rax,%rcx,4)
mov    -0x28(%rbp),%eax
sub    $0x2,%eax
mov    %eax,-0x34(%rbp)
cmpl   $0x0,-0x34(%rbp)
jl     1424 <_compute_viterbi+0x2f4>
mov    -0x78(%rbp),%rax
mov    -0x34(%rbp),%ecx
add    $0x1,%ecx
imul   -0x24(%rbp),%ecx
mov    -0x8(%rbp),%rdx
mov    -0x34(%rbp),%esi
add    $0x1,%esi
movslq %esi,%rsi
add    (%rdx,%rsi,4),%ecx
movslq %ecx,%rcx
mov    (%rax,%rcx,4),%edx
mov    -0x8(%rbp),%rax
movslq -0x34(%rbp),%rcx
mov    %edx,(%rax,%rcx,4)
mov    -0x34(%rbp),%eax
add    $0xffffffff,%eax
mov    %eax,-0x34(%rbp)
jmp    13dd <_compute_viterbi+0x2ad>
mov    -0x58(%rbp),%rdi
call   1030 <free@plt>
mov    -0x60(%rbp),%rdi
call   1030 <free@plt>
mov    -0x68(%rbp),%rdi
call   1030 <free@plt>
mov    -0x78(%rbp),%rdi
call   1030 <free@plt>
add    $0x80,%rsp
pop    %rbp
ret

x86 assembly (clang, -O2):
<_compute_viterbi>:
push   %rbp
push   %r15
push   %r14
push   %r13
push   %r12
push   %rbx
sub    $0x98,%rsp
mov    %r9d,%r12d
mov    %r8d,%ebp
mov    %rcx,0x30(%rsp)
mov    %rdx,0x8(%rsp)
mov    %rsi,0x10(%rsp)
mov    %rdi,0x48(%rsp)
movslq %r8d,%r14
lea    0x0(,%r14,8),%r13
mov    %r13,%rdi
call   1050 <malloc@plt>
mov    %rax,%r15
mov    %r13,%rdi
call   1050 <malloc@plt>
mov    %rax,%rbx
mov    %r13,%rdi
call   1050 <malloc@plt>
mov    %rax,%r13
mov    %r12,0x18(%rsp)
mov    %r12d,%eax
imul   %ebp,%eax
movslq %eax,%rdi
shl    $0x2,%rdi
call   1050 <malloc@plt>
mov    %r14,%r12
mov    %r15,%rdi
mov    %rbp,%rsi
mov    %esi,%edx
test   %r12d,%r12d
jle    12d7 <_compute_viterbi+0x1a7>
cmp    $0x1,%esi
jne    11c9 <_compute_viterbi+0x99>
xorpd  %xmm0,%xmm0
xor    %ecx,%ecx
mov    0x8(%rsp),%rbp
mov    0x30(%rsp),%r10
jmp    1215 <_compute_viterbi+0xe5>
mov    %edx,%r8d
and    $0xfffffffe,%r8d
xorpd  %xmm0,%xmm0
xor    %ecx,%ecx
mov    0x8(%rsp),%rbp
mov    0x30(%rsp),%r10
movsd  0x0(%rbp,%rcx,8),%xmm1
mulsd  (%r10,%rcx,8),%xmm1
movsd  %xmm1,(%rdi,%rcx,8)
addsd  %xmm0,%xmm1
movsd  0x8(%rbp,%rcx,8),%xmm0
mulsd  0x8(%r10,%rcx,8),%xmm0
movsd  %xmm0,0x8(%rdi,%rcx,8)
addsd  %xmm1,%xmm0
add    $0x2,%rcx
cmp    %rcx,%r8
jne    11e0 <_compute_viterbi+0xb0>
test   $0x1,%dl
je     122f <_compute_viterbi+0xff>
movsd  0x0(%rbp,%rcx,8),%xmm1
mulsd  (%r10,%rcx,8),%xmm1
movsd  %xmm1,(%rdi,%rcx,8)
addsd  %xmm1,%xmm0
test   %esi,%esi
jle    12d7 <_compute_viterbi+0x1a7>
cmp    $0x1,%esi
jne    1243 <_compute_viterbi+0x113>
xor    %ebp,%ebp
jmp    12c0 <_compute_viterbi+0x190>
mov    %edx,%ebp
and    $0xfffffffe,%ebp
movapd %xmm0,%xmm1
unpcklpd %xmm0,%xmm1
lea    -0x2(%rbp),%rcx
mov    %rcx,%r8
shr    %r8
add    $0x1,%r8
test   %rcx,%rcx
je     160c <_compute_viterbi+0x4dc>
mov    %r8,%r10
and    $0xfffffffffffffffe,%r10
xor    %ecx,%ecx
movupd (%rdi,%rcx,8),%xmm2
movupd 0x10(%rdi,%rcx,8),%xmm3
divpd  %xmm1,%xmm2
movupd %xmm2,(%rdi,%rcx,8)
divpd  %xmm1,%xmm3
movupd %xmm3,0x10(%rdi,%rcx,8)
add    $0x4,%rcx
add    $0xfffffffffffffffe,%r10
jne    1270 <_compute_viterbi+0x140>
test   $0x1,%r8b
je     12ac <_compute_viterbi+0x17c>
movupd (%rdi,%rcx,8),%xmm2
divpd  %xmm1,%xmm2
movupd %xmm2,(%rdi,%rcx,8)
cmp    %rdx,%rbp
je     12d7 <_compute_viterbi+0x1a7>
cs nopw 0x0(%rax,%rax,1)
nopl   0x0(%rax,%rax,1)
movsd  (%rdi,%rbp,8),%xmm1
divsd  %xmm0,%xmm1
movsd  %xmm1,(%rdi,%rbp,8)
add    $0x1,%rbp
cmp    %rbp,%rdx
jne    12c0 <_compute_viterbi+0x190>
mov    0x18(%rsp),%rcx
cmp    $0x2,%ecx
mov    %rsi,0x28(%rsp)
mov    %rax,0x20(%rsp)
jl     1547 <_compute_viterbi+0x417>
mov    %ecx,%eax
mov    %rax,0x68(%rsp)
mov    %edx,%ebp
and    $0xfffffffe,%ebp
lea    -0x2(%rbp),%rax
mov    %rax,0x60(%rsp)
mov    %rax,%rcx
shr    %rcx
add    $0x1,%rcx
mov    %rcx,%rax
mov    %rcx,0x58(%rsp)
and    $0xfffffffffffffffe,%rcx
mov    %rcx,0x50(%rsp)
mov    %r12,%r14
shl    $0x4,%r14
mov    $0x1,%r8d
mov    %rbx,%rax
mov    %rdx,0x78(%rsp)
jmp    1352 <_compute_viterbi+0x222>
cs nopw 0x0(%rax,%rax,1)
add    $0x1,%r8
mov    %rbx,%rax
cmp    0x68(%rsp),%r8
je     1547 <_compute_viterbi+0x417>
mov    %rdi,%rbx
mov    %rax,%rdi
test   %esi,%esi
jle    1340 <_compute_viterbi+0x210>
mov    %r8,0x70(%rsp)
imul   %r12,%r8
mov    %r8,0x80(%rsp)
xorpd  %xmm3,%xmm3
mov    0x10(%rsp),%rcx
xor    %r15d,%r15d
mov    %rdi,0x88(%rsp)
jmp    140b <_compute_viterbi+0x2db>
cs nopw 0x0(%rax,%rax,1)
mov    %r13,%rdi
xor    %eax,%eax
call   1040 <argmax@plt>
mov    0x28(%rsp),%rsi
mov    0x80(%rsp),%rcx
add    %r15,%rcx
mov    0x20(%rsp),%rdx
mov    %eax,(%rdx,%rcx,4)
mov    0x8(%rsp),%rdx
movsd  (%rdx,%rcx,8),%xmm0
cltq
mulsd  (%rbx,%rax,8),%xmm0
imul   %esi,%eax
cltq
add    %r15,%rax
mov    0x10(%rsp),%rcx
mulsd  (%rcx,%rax,8),%xmm0
mov    0x88(%rsp),%rdi
movsd  %xmm0,(%rdi,%r15,8)
movapd 0x30(%rsp),%xmm3
addsd  %xmm0,%xmm3
add    $0x1,%r15
mov    0x90(%rsp),%rcx
add    $0x8,%rcx
mov    0x78(%rsp),%rdx
cmp    %rdx,%r15
je     14a0 <_compute_viterbi+0x370>
cmp    $0x1,%esi
mov    %rcx,0x90(%rsp)
jne    1420 <_compute_viterbi+0x2f0>
xor    %eax,%eax
jmp    145f <_compute_viterbi+0x32f>
nopl   0x0(%rax)
xor    %eax,%eax
cs nopw 0x0(%rax,%rax,1)
nopl   0x0(%rax)
movsd  (%rbx,%rax,8),%xmm0
mulsd  (%rcx),%xmm0
movsd  %xmm0,0x0(%r13,%rax,8)
movsd  0x8(%rbx,%rax,8),%xmm0
mulsd  (%rcx,%r12,8),%xmm0
movsd  %xmm0,0x8(%r13,%rax,8)
add    $0x2,%rax
add    %r14,%rcx
cmp    %rax,%rbp
jne    1430 <_compute_viterbi+0x300>
movapd %xmm3,0x30(%rsp)
test   $0x1,%dl
je     1390 <_compute_viterbi+0x260>
movsd  (%rbx,%rax,8),%xmm0
mov    %rax,%rcx
imul   %r12,%rcx
add    %r15,%rcx
mov    0x10(%rsp),%rdx
mulsd  (%rdx,%rcx,8),%xmm0
movsd  %xmm0,0x0(%r13,%rax,8)
jmp    1390 <_compute_viterbi+0x260>
cs nopw 0x0(%rax,%rax,1)
nopl   (%rax)
test   %esi,%esi
mov    0x70(%rsp),%r8
jle    1340 <_compute_viterbi+0x210>
cmp    $0x1,%esi
jne    14b6 <_compute_viterbi+0x386>
xor    %eax,%eax
jmp    1520 <_compute_viterbi+0x3f0>
movapd %xmm3,%xmm0
unpcklpd %xmm3,%xmm0
cmpq   $0x0,0x60(%rsp)
je     153c <_compute_viterbi+0x40c>
mov    0x50(%rsp),%rcx
xor    %eax,%eax
nopl   (%rax)
movupd (%rdi,%rax,8),%xmm1
movupd 0x10(%rdi,%rax,8),%xmm2
divpd  %xmm0,%xmm1
movupd %xmm1,(%rdi,%rax,8)
divpd  %xmm0,%xmm2
movupd %xmm2,0x10(%rdi,%rax,8)
add    $0x4,%rax
add    $0xfffffffffffffffe,%rcx
jne    14d0 <_compute_viterbi+0x3a0>
testb  $0x1,0x58(%rsp)
je     150d <_compute_viterbi+0x3dd>
movupd (%rdi,%rax,8),%xmm1
divpd  %xmm0,%xmm1
movupd %xmm1,(%rdi,%rax,8)
mov    %rbp,%rax
cmp    %rdx,%rbp
je     1340 <_compute_viterbi+0x210>
nopl   0x0(%rax)
movsd  (%rdi,%rax,8),%xmm0
divsd  %xmm3,%xmm0
movsd  %xmm0,(%rdi,%rax,8)
add    $0x1,%rax
cmp    %rax,%rdx
jne    1520 <_compute_viterbi+0x3f0>
jmp    1340 <_compute_viterbi+0x210>
xor    %eax,%eax
testb  $0x1,0x58(%rsp)
jne    14ff <_compute_viterbi+0x3cf>
jmp    150d <_compute_viterbi+0x3dd>
mov    %rdi,%r14
xor    %eax,%eax
call   1040 <argmax@plt>
mov    0x20(%rsp),%r8
mov    0x28(%rsp),%rdi
mov    0x18(%rsp),%rdx
movslq %edx,%rcx
mov    0x48(%rsp),%rbp
mov    %eax,-0x4(%rbp,%rcx,4)
cmp    $0x2,%edx
jl     15d8 <_compute_viterbi+0x4a8>
lea    -0x2(%rdx),%eax
mov    %rax,%rsi
test   $0x1,%al
jne    1598 <_compute_viterbi+0x468>
add    $0xffffffff,%edx
imul   %edi,%edx
movslq 0x4(%rbp,%rax,4),%rcx
movslq %edx,%rdx
add    %rcx,%rdx
mov    (%r8,%rdx,4),%ecx
mov    %ecx,0x0(%rbp,%rax,4)
lea    -0x1(%rax),%rsi
test   %rax,%rax
je     15d8 <_compute_viterbi+0x4a8>
lea    0x1(%rsi),%eax
imul   %edi,%eax
lea    (%rdi,%rdi,1),%ecx
mov    %rsi,%rdx
add    $0x1,%rdx
imul   %esi,%edi
mov    0x0(%rbp,%rdx,4),%esi
add    %eax,%esi
movslq %esi,%rsi
mov    (%r8,%rsi,4),%esi
mov    %esi,-0x4(%rbp,%rdx,4)
add    %edi,%esi
movslq %esi,%rsi
mov    (%r8,%rsi,4),%esi
mov    %esi,-0x8(%rbp,%rdx,4)
sub    %ecx,%eax
sub    %ecx,%edi
add    $0xfffffffffffffffe,%rdx
jne    15b0 <_compute_viterbi+0x480>
mov    %r14,%rdi
mov    %r8,%rbp
call   1030 <free@plt>
mov    %rbx,%rdi
call   1030 <free@plt>
mov    %r13,%rdi
call   1030 <free@plt>
mov    %rbp,%rdi
add    $0x98,%rsp
pop    %rbx
pop    %r12
pop    %r13
pop    %r14
pop    %r15
pop    %rbp
jmp    1030 <free@plt>
xor    %ecx,%ecx
test   $0x1,%r8b
jne    129e <_compute_viterbi+0x16e>
jmp    12ac <_compute_viterbi+0x17c>

LLVM IR (-O0):
define void @_compute_viterbi(i32* %0, double* %1, double* %2, double* %3, i32 %4, i32 %5) {
%7 = alloca i32*
%8 = alloca double*
%9 = alloca double*
%10 = alloca double*
%11 = alloca i32
%12 = alloca i32
%13 = alloca i32
%14 = alloca i32
%15 = alloca i32
%16 = alloca i32
%17 = alloca double
%18 = alloca double
%19 = alloca double
%20 = alloca double*
%21 = alloca double*
%22 = alloca double*
%23 = alloca double*
%24 = alloca i32*
store i32* %0, i32** %7
store double* %1, double** %8
store double* %2, double** %9
store double* %3, double** %10
store i32 %4, i32* %11
store i32 %5, i32* %12
%25 = load i32, i32* %11
%26 = sext i32 %25 to i64
%27 = mul i64 %26, 8
%28 = call i8* @malloc(i64 %27)
%29 = bitcast i8* %28 to double*
store double* %29, double** %20
%30 = load i32, i32* %11
%31 = sext i32 %30 to i64
%32 = mul i64 %31, 8
%33 = call i8* @malloc(i64 %32)
%34 = bitcast i8* %33 to double*
store double* %34, double** %21
%35 = load i32, i32* %11
%36 = sext i32 %35 to i64
%37 = mul i64 %36, 8
%38 = call i8* @malloc(i64 %37)
%39 = bitcast i8* %38 to double*
store double* %39, double** %22
%40 = load i32, i32* %12
%41 = load i32, i32* %11
%42 = mul nsw i32 %40, %41
%43 = sext i32 %42 to i64
%44 = mul i64 %43, 4
%45 = call i8* @malloc(i64 %44)
%46 = bitcast i8* %45 to i32*
store i32* %46, i32** %24
store double 0.000000e+00, double* %17
store i32 0, i32* %13
br label %47
47: ; preds = %74, %6
%48 = load i32, i32* %13
%49 = load i32, i32* %11
%50 = icmp slt i32 %48, %49
br i1 %50, label %51, label %77
51: ; preds = %47
%52 = load double*, double** %9
%53 = load i32, i32* %13
%54 = sext i32 %53 to i64
%55 = getelementptr inbounds double, double* %52, i64 %54
%56 = load double, double* %55
%57 = load double*, double** %10
%58 = load i32, i32* %13
%59 = sext i32 %58 to i64
%60 = getelementptr inbounds double, double* %57, i64 %59
%61 = load double, double* %60
%62 = fmul double %56, %61
%63 = load double*, double** %20
%64 = load i32, i32* %13
%65 = sext i32 %64 to i64
%66 = getelementptr inbounds double, double* %63, i64 %65
store double %62, double* %66
%67 = load double*, double** %20
%68 = load i32, i32* %13
%69 = sext i32 %68 to i64
%70 = getelementptr inbounds double, double* %67, i64 %69
%71 = load double, double* %70
%72 = load double, double* %17
%73 = fadd double %72, %71
store double %73, double* %17
br label %74
74: ; preds = %51
%75 = load i32, i32* %13
%76 = add nsw i32 %75, 1
store i32 %76, i32* %13
br label %47
77: ; preds = %47
store i32 0, i32* %13
br label %78
78: ; preds = %90, %77
%79 = load i32, i32* %13
%80 = load i32, i32* %11
%81 = icmp slt i32 %79, %80
br i1 %81, label %82, label %93
82: ; preds = %78
%83 = load double, double* %17
%84 = load double*, double** %20
%85 = load i32, i32* %13
%86 = sext i32 %85 to i64
%87 = getelementptr inbounds double, double* %84, i64 %86
%88 = load double, double* %87
%89 = fdiv double %88, %83
store double %89, double* %87
br label %90
90: ; preds = %82
%91 = load i32, i32* %13
%92 = add nsw i32 %91, 1
store i32 %92, i32* %13
br label %78
93: ; preds = %78
store i32 1, i32* %15
br label %94
94: ; preds = %203, %93
%95 = load i32, i32* %15
%96 = load i32, i32* %12
%97 = icmp slt i32 %95, %96
br i1 %97, label %98, label %206
98: ; preds = %94
store double 0.000000e+00, double* %17
store i32 0, i32* %14
br label %99
99: ; preds = %180, %98
%100 = load i32, i32* %14
%101 = load i32, i32* %11
%102 = icmp slt i32 %100, %101
br i1 %102, label %103, label %183
103: ; preds = %99
store i32 0, i32* %13
br label %104
104: ; preds = %128, %103
%105 = load i32, i32* %13
%106 = load i32, i32* %11
%107 = icmp slt i32 %105, %106
br i1 %107, label %108, label %131
108: ; preds = %104
%109 = load double*, double** %20
%110 = load i32, i32* %13
%111 = sext i32 %110 to i64
%112 = getelementptr inbounds double, double* %109, i64 %111
%113 = load double, double* %112
%114 = load double*, double** %8
%115 = load i32, i32* %13
%116 = load i32, i32* %11
%117 = mul nsw i32 %115, %116
%118 = load i32, i32* %14
%119 = add nsw i32 %117, %118
%120 = sext i32 %119 to i64
%121 = getelementptr inbounds double, double* %114, i64 %120
%122 = load double, double* %121
%123 = fmul double %113, %122
%124 = load double*, double** %22
%125 = load i32, i32* %13
%126 = sext i32 %125 to i64
%127 = getelementptr inbounds double, double* %124, i64 %126
store double %123, double* %127
br label %128
128: ; preds = %108
%129 = load i32, i32* %13
%130 = add nsw i32 %129, 1
store i32 %130, i32* %13
br label %104
131: ; preds = %104
%132 = load double*, double** %22
%133 = load i32, i32* %11
%134 = call i32 (double*, i32, ...) bitcast (i32 (...)* @argmax to i32 (double*, i32, ...)*)(double* %132, i32 %133)
store i32 %134, i32* %16
%135 = load i32, i32* %16
%136 = load i32*, i32** %24
%137 = load i32, i32* %15
%138 = load i32, i32* %11
%139 = mul nsw i32 %137, %138
%140 = load i32, i32* %14
%141 = add nsw i32 %139, %140
%142 = sext i32 %141 to i64
%143 = getelementptr inbounds i32, i32* %136, i64 %142
store i32 %135, i32* %143
%144 = load double*, double** %9
%145 = load i32, i32* %15
%146 = load i32, i32* %11
%147 = mul nsw i32 %145, %146
%148 = load i32, i32* %14
%149 = add nsw i32 %147, %148
%150 = sext i32 %149 to i64
%151 = getelementptr inbounds double, double* %144, i64 %150
%152 = load double, double* %151
%153 = load double*, double** %20
%154 = load i32, i32* %16
%155 = sext i32 %154 to i64
%156 = getelementptr inbounds double, double* %153, i64 %155
%157 = load double, double* %156
%158 = fmul double %152, %157
%159 = load double*, double** %8
%160 = load i32, i32* %16
%161 = load i32, i32* %11
%162 = mul nsw i32 %160, %161
%163 = load i32, i32* %14
%164 = add nsw i32 %162, %163
%165 = sext i32 %164 to i64
%166 = getelementptr inbounds double, double* %159, i64 %165
%167 = load double, double* %166
%168 = fmul double %158, %167
%169 = load double*, double** %21
%170 = load i32, i32* %14
%171 = sext i32 %170 to i64
%172 = getelementptr inbounds double, double* %169, i64 %171
store double %168, double* %172
%173 = load double*, double** %21
%174 = load i32, i32* %14
%175 = sext i32 %174 to i64
%176 = getelementptr inbounds double, double* %173, i64 %175
%177 = load double, double* %176
%178 = load double, double* %17
%179 = fadd double %178, %177
store double %179, double* %17
br label %180
180: ; preds = %131
%181 = load i32, i32* %14
%182 = add nsw i32 %181, 1
store i32 %182, i32* %14
br label %99
183: ; preds = %99
store i32 0, i32* %13
br label %184
184: ; preds = %196, %183
%185 = load i32, i32* %13
%186 = load i32, i32* %11
%187 = icmp slt i32 %185, %186
br i1 %187, label %188, label %199
188: ; preds = %184
%189 = load double, double* %17
%190 = load double*, double** %21
%191 = load i32, i32* %13
%192 = sext i32 %191 to i64
%193 = getelementptr inbounds double, double* %190, i64 %192
%194 = load double, double* %193
%195 = fdiv double %194, %189
store double %195, double* %193
br label %196
196: ; preds = %188
%197 = load i32, i32* %13
%198 = add nsw i32 %197, 1
store i32 %198, i32* %13
br label %184
199: ; preds = %184
%200 = load double*, double** %20
store double* %200, double** %23
%201 = load double*, double** %21
store double* %201, double** %20
%202 = load double*, double** %23
store double* %202, double** %21
br label %203
203: ; preds = %199
%204 = load i32, i32* %15
%205 = add nsw i32 %204, 1
store i32 %205, i32* %15
br label %94
206: ; preds = %94
%207 = load double*, double** %20
%208 = load i32, i32* %11
%209 = call i32 (double*, i32, ...) bitcast (i32 (...)* @argmax to i32 (double*, i32, ...)*)(double* %207, i32 %208)
%210 = load i32*, i32** %7
%211 = load i32, i32* %12
%212 = sub nsw i32 %211, 1
%213 = sext i32 %212 to i64
%214 = getelementptr inbounds i32, i32* %210, i64 %213
store i32 %209, i32* %214
%215 = load i32, i32* %12
%216 = sub nsw i32 %215, 2
store i32 %216, i32* %15
br label %217
217: ; preds = %240, %206
%218 = load i32, i32* %15
%219 = icmp sge i32 %218, 0
br i1 %219, label %220, label %243
220: ; preds = %217
%221 = load i32*, i32** %24
%222 = load i32, i32* %15
%223 = add nsw i32 %222, 1
%224 = load i32, i32* %11
%225 = mul nsw i32 %223, %224
%226 = load i32*, i32** %7
%227 = load i32, i32* %15
%228 = add nsw i32 %227, 1
%229 = sext i32 %228 to i64
%230 = getelementptr inbounds i32, i32* %226, i64 %229
%231 = load i32, i32* %230
%232 = add nsw i32 %225, %231
%233 = sext i32 %232 to i64
%234 = getelementptr inbounds i32, i32* %221, i64 %233
%235 = load i32, i32* %234
%236 = load i32*, i32** %7
%237 = load i32, i32* %15
%238 = sext i32 %237 to i64
%239 = getelementptr inbounds i32, i32* %236, i64 %238
store i32 %235, i32* %239
br label %240
240: ; preds = %220
%241 = load i32, i32* %15
%242 = add nsw i32 %241, -1
store i32 %242, i32* %15
br label %217
243: ; preds = %217
%244 = load double*, double** %20
%245 = bitcast double* %244 to i8*
%246 = load double*, double** %21
%247 = bitcast double* %246 to i8*
%248 = load double*, double** %22
%249 = bitcast double* %248 to i8*
%250 = load i32*, i32** %24
%251 = bitcast i32* %250 to i8*
ret void
}

LLVM IR (-O2):
define void @_compute_viterbi(i32* nocapture %0, double* nocapture %1, double* nocapture %2, double* nocapture %3, i32 %4, i32 %5) {
%7 = sext i32 %4 to i64
%8 = shl nsw i64 %7, 3
%9 = tail call i8* @malloc(i64 %8)
%10 = bitcast i8* %9 to double*
%11 = tail call i8* @malloc(i64 %8)
%12 = bitcast i8* %11 to double*
%13 = tail call i8* @malloc(i64 %8)
%14 = bitcast i8* %13 to double*
%15 = mul nsw i32 %5, %4
%16 = sext i32 %15 to i64
%17 = shl nsw i64 %16, 2
%18 = tail call i8* @malloc(i64 %17)
%19 = bitcast i8* %18 to i32*
%20 = icmp sgt i32 %4, 0
br i1 %20, label %21, label %108
21: ; preds = %6
%22 = zext i32 %4 to i64
%23 = and i64 %22, 1
%24 = icmp eq i32 %4, 1
br i1 %24, label %27, label %25
25: ; preds = %21
%26 = and i64 %22, 4294967294
br label %86
27: ; preds = %86, %21
%28 = phi double [ undef, %21 ], [ %104, %86 ]
%29 = phi i64 [ 0, %21 ], [ %105, %86 ]
%30 = phi double [ 0.000000e+00, %21 ], [ %104, %86 ]
%31 = icmp eq i64 %23, 0
br i1 %31, label %40, label %32
32: ; preds = %27
%33 = getelementptr inbounds double, double* %2, i64 %29
%34 = load double, double* %33
%35 = getelementptr inbounds double, double* %3, i64 %29
%36 = load double, double* %35
%37 = fmul double %34, %36
%38 = getelementptr inbounds double, double* %10, i64 %29
store double %37, double* %38
%39 = fadd double %30, %37
br label %40
40: ; preds = %27, %32
%41 = phi double [ %28, %27 ], [ %39, %32 ]
br i1 %20, label %42, label %108
42: ; preds = %40
%43 = zext i32 %4 to i64
%44 = icmp eq i32 %4, 1
br i1 %44, label %84, label %45
45: ; preds = %42
%46 = and i64 %22, 4294967294
%47 = insertelement <2 x double> poison, double %41, i64 0
%48 = shufflevector <2 x double> %47, <2 x double> poison, <2 x i32> zeroinitializer
%49 = add nsw i64 %46, -2
%50 = lshr exact i64 %49, 1
%51 = add nuw i64 %50, 1
%52 = and i64 %51, 1
%53 = icmp eq i64 %49, 0
br i1 %53, label %73, label %54
54: ; preds = %45
%55 = and i64 %51, -2
br label %56
56: ; preds = %56, %54
%57 = phi i64 [ 0, %54 ], [ %70, %56 ]
%58 = phi i64 [ 0, %54 ], [ %71, %56 ]
%59 = getelementptr inbounds double, double* %10, i64 %57
%60 = bitcast double* %59 to <2 x double>*
%61 = load <2 x double>, <2 x double>* %60
%62 = fdiv <2 x double> %61, %48
%63 = bitcast double* %59 to <2 x double>*
store <2 x double> %62, <2 x double>* %63
%64 = or i64 %57, 2
%65 = getelementptr inbounds double, double* %10, i64 %64
%66 = bitcast double* %65 to <2 x double>*
%67 = load <2 x double>, <2 x double>* %66
%68 = fdiv <2 x double> %67, %48
%69 = bitcast double* %65 to <2 x double>*
store <2 x double> %68, <2 x double>* %69
%70 = add nuw i64 %57, 4
%71 = add nuw i64 %58, 2
%72 = icmp eq i64 %71, %55
br i1 %72, label %73, label %56
73: ; preds = %56, %45
%74 = phi i64 [ 0, %45 ], [ %70, %56 ]
%75 = icmp eq i64 %52, 0
br i1 %75, label %82, label %76
76: ; preds = %73
%77 = getelementptr inbounds double, double* %10, i64 %74
%78 = bitcast double* %77 to <2 x double>*
%79 = load <2 x double>, <2 x double>* %78
%80 = fdiv <2 x double> %79, %48
%81 = bitcast double* %77 to <2 x double>*
store <2 x double> %80, <2 x double>* %81
br label %82
82: ; preds = %73, %76
%83 = icmp eq i64 %46, %22
br i1 %83, label %108, label %84
84: ; preds = %42, %82
%85 = phi i64 [ 0, %42 ], [ %46, %82 ]
br label %129
86: ; preds = %86, %25
%87 = phi i64 [ 0, %25 ], [ %105, %86 ]
%88 = phi double [ 0.000000e+00, %25 ], [ %104, %86 ]
%89 = phi i64 [ 0, %25 ], [ %106, %86 ]
%90 = getelementptr inbounds double, double* %2, i64 %87
%91 = load double, double* %90
%92 = getelementptr inbounds double, double* %3, i64 %87
%93 = load double, double* %92
%94 = fmul double %91, %93
%95 = getelementptr inbounds double, double* %10, i64 %87
store double %94, double* %95
%96 = fadd double %88, %94
%97 = or i64 %87, 1
%98 = getelementptr inbounds double, double* %2, i64 %97
%99 = load double, double* %98
%100 = getelementptr inbounds double, double* %3, i64 %97
%101 = load double, double* %100
%102 = fmul double %99, %101
%103 = getelementptr inbounds double, double* %10, i64 %97
store double %102, double* %103
%104 = fadd double %96, %102
%105 = add nuw nsw i64 %87, 2
%106 = add i64 %89, 2
%107 = icmp eq i64 %106, %26
br i1 %107, label %27, label %86
108: ; preds = %129, %82, %6, %40
%109 = icmp sgt i32 %5, 1
br i1 %109, label %110, label %242
110: ; preds = %108
%111 = zext i32 %5 to i64
%112 = zext i32 %4 to i64
%113 = zext i32 %4 to i64
%114 = and i64 %112, 4294967294
%115 = add nsw i64 %114, -2
%116 = lshr exact i64 %115, 1
%117 = add nuw i64 %116, 1
%118 = and i64 %112, 1
%119 = icmp eq i32 %4, 1
%120 = and i64 %112, 4294967294
%121 = icmp eq i64 %118, 0
%122 = icmp eq i32 %4, 1
%123 = and i64 %112, 4294967294
%124 = and i64 %117, 1
%125 = icmp eq i64 %115, 0
%126 = and i64 %117, -2
%127 = icmp eq i64 %124, 0
%128 = icmp eq i64 %123, %112
br label %136
129: ; preds = %84, %129
%130 = phi i64 [ %134, %129 ], [ %85, %84 ]
%131 = getelementptr inbounds double, double* %10, i64 %130
%132 = load double, double* %131
%133 = fdiv double %132, %41
store double %133, double* %131
%134 = add nuw nsw i64 %130, 1
%135 = icmp eq i64 %134, %43
br i1 %135, label %108, label %129
136: ; preds = %110, %239
%137 = phi i64 [ 1, %110 ], [ %240, %239 ]
%138 = phi double* [ %12, %110 ], [ %139, %239 ]
%139 = phi double* [ %10, %110 ], [ %138, %239 ]
br i1 %20, label %140, label %239
140: ; preds = %136
%141 = mul nsw i64 %137, %7
br label %175
142: ; preds = %212
br i1 %20, label %143, label %239
143: ; preds = %142
br i1 %122, label %173, label %144
144: ; preds = %143
%145 = insertelement <2 x double> poison, double %229, i64 0
%146 = shufflevector <2 x double> %145, <2 x double> poison, <2 x i32> zeroinitializer
br i1 %125, label %164, label %147
147: ; preds = %144, %147
%148 = phi i64 [ %161, %147 ], [ 0, %144 ]
%149 = phi i64 [ %162, %147 ], [ 0, %144 ]
%150 = getelementptr inbounds double, double* %138, i64 %148
%151 = bitcast double* %150 to <2 x double>*
%152 = load <2 x double>, <2 x double>* %151
%153 = fdiv <2 x double> %152, %146
%154 = bitcast double* %150 to <2 x double>*
store <2 x double> %153, <2 x double>* %154
%155 = or i64 %148, 2
%156 = getelementptr inbounds double, double* %138, i64 %155
%157 = bitcast double* %156 to <2 x double>*
%158 = load <2 x double>, <2 x double>* %157
%159 = fdiv <2 x double> %158, %146
%160 = bitcast double* %156 to <2 x double>*
store <2 x double> %159, <2 x double>* %160
%161 = add nuw i64 %148, 4
%162 = add nuw i64 %149, 2
%163 = icmp eq i64 %162, %126
br i1 %163, label %164, label %147
164: ; preds = %147, %144
%165 = phi i64 [ 0, %144 ], [ %161, %147 ]
br i1 %127, label %172, label %166
166: ; preds = %164
%167 = getelementptr inbounds double, double* %138, i64 %165
%168 = bitcast double* %167 to <2 x double>*
%169 = load <2 x double>, <2 x double>* %168
%170 = fdiv <2 x double> %169, %146
%171 = bitcast double* %167 to <2 x double>*
store <2 x double> %170, <2 x double>* %171
br label %172
172: ; preds = %164, %166
br i1 %128, label %239, label %173
173: ; preds = %143, %172
%174 = phi i64 [ 0, %143 ], [ %123, %172 ]
br label %232
175: ; preds = %212, %140
%176 = phi i64 [ 0, %140 ], [ %230, %212 ]
%177 = phi double [ 0.000000e+00, %140 ], [ %229, %212 ]
br i1 %119, label %201, label %178
178: ; preds = %175, %178
%179 = phi i64 [ %198, %178 ], [ 0, %175 ]
%180 = phi i64 [ %199, %178 ], [ 0, %175 ]
%181 = getelementptr inbounds double, double* %139, i64 %179
%182 = load double, double* %181
%183 = mul nsw i64 %179, %7
%184 = add nsw i64 %183, %176
%185 = getelementptr inbounds double, double* %1, i64 %184
%186 = load double, double* %185
%187 = fmul double %182, %186
%188 = getelementptr inbounds double, double* %14, i64 %179
store double %187, double* %188
%189 = or i64 %179, 1
%190 = getelementptr inbounds double, double* %139, i64 %189
%191 = load double, double* %190
%192 = mul nsw i64 %189, %7
%193 = add nsw i64 %192, %176
%194 = getelementptr inbounds double, double* %1, i64 %193
%195 = load double, double* %194
%196 = fmul double %191, %195
%197 = getelementptr inbounds double, double* %14, i64 %189
store double %196, double* %197
%198 = add nuw nsw i64 %179, 2
%199 = add i64 %180, 2
%200 = icmp eq i64 %199, %120
br i1 %200, label %201, label %178
201: ; preds = %178, %175
%202 = phi i64 [ 0, %175 ], [ %198, %178 ]
br i1 %121, label %212, label %203
203: ; preds = %201
%204 = getelementptr inbounds double, double* %139, i64 %202
%205 = load double, double* %204
%206 = mul nsw i64 %202, %7
%207 = add nsw i64 %206, %176
%208 = getelementptr inbounds double, double* %1, i64 %207
%209 = load double, double* %208
%210 = fmul double %205, %209
%211 = getelementptr inbounds double, double* %14, i64 %202
store double %210, double* %211
br label %212
212: ; preds = %201, %203
%213 = tail call i32 (double*, i32, ...) bitcast (i32 (...)* @argmax to i32 (double*, i32, ...)*)(double* %14, i32 %4)
%214 = add nsw i64 %176, %141
%215 = getelementptr inbounds i32, i32* %19, i64 %214
store i32 %213, i32* %215
%216 = getelementptr inbounds double, double* %2, i64 %214
%217 = load double, double* %216
%218 = sext i32 %213 to i64
%219 = getelementptr inbounds double, double* %139, i64 %218
%220 = load double, double* %219
%221 = fmul double %217, %220
%222 = mul nsw i32 %213, %4
%223 = sext i32 %222 to i64
%224 = add nsw i64 %176, %223
%225 = getelementptr inbounds double, double* %1, i64 %224
%226 = load double, double* %225
%227 = fmul double %221, %226
%228 = getelementptr inbounds double, double* %138, i64 %176
store double %227, double* %228
%229 = fadd double %177, %227
%230 = add nuw nsw i64 %176, 1
%231 = icmp eq i64 %230, %112
br i1 %231, label %142, label %175
232: ; preds = %173, %232
%233 = phi i64 [ %237, %232 ], [ %174, %173 ]
%234 = getelementptr inbounds double, double* %138, i64 %233
%235 = load double, double* %234
%236 = fdiv double %235, %229
store double %236, double* %234
%237 = add nuw nsw i64 %233, 1
%238 = icmp eq i64 %237, %113
br i1 %238, label %239, label %232
239: ; preds = %232, %172, %136, %142
%240 = add nuw nsw i64 %137, 1
%241 = icmp eq i64 %240, %111
br i1 %241, label %242, label %136
242: ; preds = %239, %108
%243 = phi double* [ %10, %108 ], [ %138, %239 ]
%244 = phi double* [ %12, %108 ], [ %139, %239 ]
%245 = tail call i32 (double*, i32, ...) bitcast (i32 (...)* @argmax to i32 (double*, i32, ...)*)(double* %243, i32 %4)
%246 = add nsw i32 %5, -1
%247 = sext i32 %246 to i64
%248 = getelementptr inbounds i32, i32* %0, i64 %247
store i32 %245, i32* %248
br i1 %109, label %249, label %293
249: ; preds = %242
%250 = add nsw i32 %5, -2
%251 = zext i32 %250 to i64
%252 = and i64 %251, 1
%253 = icmp eq i64 %252, 0
br i1 %253, label %254, label %266
254: ; preds = %249
%255 = add nuw nsw i64 %251, 1
%256 = add nsw i32 %5, -1
%257 = mul nsw i32 %256, %4
%258 = getelementptr inbounds i32, i32* %0, i64 %255
%259 = load i32, i32* %258
%260 = add nsw i32 %259, %257
%261 = sext i32 %260 to i64
%262 = getelementptr inbounds i32, i32* %19, i64 %261
%263 = load i32, i32* %262
%264 = getelementptr inbounds i32, i32* %0, i64 %251
store i32 %263, i32* %264
%265 = add nsw i64 %251, -1
br label %266
266: ; preds = %254, %249
%267 = phi i64 [ %251, %249 ], [ %265, %254 ]
%268 = icmp eq i32 %250, 0
br i1 %268, label %293, label %269
269: ; preds = %266, %269
%270 = phi i64 [ %291, %269 ], [ %267, %266 ]
%271 = trunc i64 %270 to i32
%272 = add nuw nsw i64 %270, 1
%273 = add nuw nsw i32 %271, 1
%274 = mul nsw i32 %273, %4
%275 = getelementptr inbounds i32, i32* %0, i64 %272
%276 = load i32, i32* %275
%277 = add nsw i32 %276, %274
%278 = sext i32 %277 to i64
%279 = getelementptr inbounds i32, i32* %19, i64 %278
%280 = load i32, i32* %279
%281 = getelementptr inbounds i32, i32* %0, i64 %270
store i32 %280, i32* %281
%282 = add nsw i64 %270, -1
%283 = trunc i64 %282 to i32
%284 = add nuw nsw i32 %283, 1
%285 = mul nsw i32 %284, %4
%286 = add nsw i32 %280, %285
%287 = sext i32 %286 to i64
%288 = getelementptr inbounds i32, i32* %19, i64 %287
%289 = load i32, i32* %288
%290 = getelementptr inbounds i32, i32* %0, i64 %282
store i32 %289, i32* %290
%291 = add nsw i64 %270, -2
%292 = icmp eq i64 %282, 0
br i1 %292, label %293, label %269
293: ; preds = %266, %269, %242
%294 = bitcast double* %243 to i8*
tail call void @free(i8* %294)
%295 = bitcast double* %244 to i8*
tail call void @free(i8* %295)
tail call void @free(i8* %13)
tail call void @free(i8* %18)
ret void
}