long mp_mul(unsigned short *rop, unsigned short *op1, unsigned short *op2,
            unsigned long len1, unsigned long len2) {
  if (len1 < len2) {
    unsigned short *top = op1;
    unsigned long tlen = len1;
    op1 = op2;
    len1 = len2;
    op2 = top;
    len2 = tlen;
  };
  if (len1 < 32 || len2 < 32)
    return (mp_base_mul(rop, op1, op2, len1, len2));
  else if (len1 < 128 && len2 < 128 && len2 > ((len1 + 1) >> 1))
    return (mp_karatsuba_mul(rop, op1, op2, len1, len2));
  else if (len1 >= 128 && len2 >= 128 && (len2 + 2) / 3 == (len1 + 2) / 3)
    return (mp_toom_mul(rop, op1, op2, len1, len2));
  else {
    long xsize, psize, isize;
    unsigned short *ptr;
    isize = 0;
    xsize = len1 + len2;
    mp_mul(rop, op1, op2, len2, len2);
    len1 -= len2;
    op1 += len2;
    if (len1 > len2)
      ptr = mp_calloc(1, sizeof(unsigned short) * (len2 + len2));
    else
      ptr = mp_calloc(1, sizeof(unsigned short) * (len1 + len2));
    while (len1 >= len2) {
      isize += len2;
      psize = mp_mul(ptr, op1, op2, len2, len2);
      mp_add(rop + isize, rop + isize, ptr, xsize - isize, psize);
      len1 -= len2;
      op1 += len2;
      memset(ptr, '\0',
             sizeof(unsigned short) *
                 (((len1) < (len2) ? (len1) : (len2)) + len2));
    }
    if (len1) {
      isize += len2;
      psize = mp_mul(ptr, op2, op1, len2, len1);
      mp_add(rop + isize, rop + isize, ptr, xsize, psize);
    }
    if (rop[xsize - 1] == 0)
      --xsize;
    mp_free(ptr);
    return (xsize);
  }
}


x86 assembly (clang, -O0):
<mp_mul>:
push   %rbp
mov    %rsp,%rbp
sub    $0x80,%rsp
mov    %rdi,-0x10(%rbp)
mov    %rsi,-0x18(%rbp)
mov    %rdx,-0x20(%rbp)
mov    %rcx,-0x28(%rbp)
mov    %r8,-0x30(%rbp)
mov    -0x28(%rbp),%rax
cmp    -0x30(%rbp),%rax
jae    11dd <mp_mul+0x5d>
mov    -0x18(%rbp),%rax
mov    %rax,-0x38(%rbp)
mov    -0x28(%rbp),%rax
mov    %rax,-0x40(%rbp)
mov    -0x20(%rbp),%rax
mov    %rax,-0x18(%rbp)
mov    -0x30(%rbp),%rax
mov    %rax,-0x28(%rbp)
mov    -0x38(%rbp),%rax
mov    %rax,-0x20(%rbp)
mov    -0x40(%rbp),%rax
mov    %rax,-0x30(%rbp)
cmpq   $0x20,-0x28(%rbp)
jb     11f3 <mp_mul+0x73>
cmpq   $0x20,-0x30(%rbp)
jae    1219 <mp_mul+0x99>
mov    -0x10(%rbp),%rdi
mov    -0x18(%rbp),%rsi
mov    -0x20(%rbp),%rdx
mov    -0x28(%rbp),%rcx
mov    -0x30(%rbp),%r8
mov    $0x0,%al
call   1090 <mp_base_mul@plt>
cltq
mov    %rax,-0x8(%rbp)
jmp    14fd <mp_mul+0x37d>
cmpq   $0x80,-0x28(%rbp)
jae    1274 <mp_mul+0xf4>
cmpq   $0x80,-0x30(%rbp)
jae    1274 <mp_mul+0xf4>
mov    -0x30(%rbp),%rax
mov    -0x28(%rbp),%rcx
add    $0x1,%rcx
shr    $0x1,%rcx
cmp    %rcx,%rax
jbe    1274 <mp_mul+0xf4>
mov    -0x10(%rbp),%rdi
mov    -0x18(%rbp),%rsi
mov    -0x20(%rbp),%rdx
mov    -0x28(%rbp),%rcx
mov    -0x30(%rbp),%r8
mov    $0x0,%al
call   1070 <mp_karatsuba_mul@plt>
cltq
mov    %rax,-0x8(%rbp)
jmp    14fd <mp_mul+0x37d>
cmpq   $0x80,-0x28(%rbp)
jb     12ee <mp_mul+0x16e>
cmpq   $0x80,-0x30(%rbp)
jb     12ee <mp_mul+0x16e>
mov    -0x30(%rbp),%rax
add    $0x2,%rax
mov    $0x3,%ecx
xor    %edx,%edx
div    %rcx
mov    %rax,-0x68(%rbp)
mov    -0x28(%rbp),%rax
add    $0x2,%rax
mov    $0x3,%ecx
xor    %edx,%edx
div    %rcx
mov    %rax,%rcx
mov    -0x68(%rbp),%rax
cmp    %rcx,%rax
jne    12ee <mp_mul+0x16e>
mov    -0x10(%rbp),%rdi
mov    -0x18(%rbp),%rsi
mov    -0x20(%rbp),%rdx
mov    -0x28(%rbp),%rcx
mov    -0x30(%rbp),%r8
mov    $0x0,%al
call   1050 <mp_toom_mul@plt>
cltq
mov    %rax,-0x8(%rbp)
jmp    14fd <mp_mul+0x37d>
movq   $0x0,-0x58(%rbp)
mov    -0x28(%rbp),%rax
add    -0x30(%rbp),%rax
mov    %rax,-0x48(%rbp)
mov    -0x10(%rbp),%rdi
mov    -0x18(%rbp),%rsi
mov    -0x20(%rbp),%rdx
mov    -0x30(%rbp),%rcx
mov    -0x30(%rbp),%r8
call   10a0 <mp_mul@plt>
mov    -0x30(%rbp),%rcx
mov    -0x28(%rbp),%rax
sub    %rcx,%rax
mov    %rax,-0x28(%rbp)
mov    -0x30(%rbp),%rax
shl    $0x1,%rax
add    -0x18(%rbp),%rax
mov    %rax,-0x18(%rbp)
mov    -0x28(%rbp),%rax
cmp    -0x30(%rbp),%rax
jbe    136b <mp_mul+0x1eb>
mov    -0x30(%rbp),%rsi
add    -0x30(%rbp),%rsi
shl    $0x1,%rsi
mov    $0x1,%edi
mov    $0x0,%al
call   1030 <mp_calloc@plt>
cltq
mov    %rax,-0x60(%rbp)
jmp    1389 <mp_mul+0x209>
mov    -0x28(%rbp),%rsi
add    -0x30(%rbp),%rsi
shl    $0x1,%rsi
mov    $0x1,%edi
mov    $0x0,%al
call   1030 <mp_calloc@plt>
cltq
mov    %rax,-0x60(%rbp)
jmp    138e <mp_mul+0x20e>
mov    -0x28(%rbp),%rax
cmp    -0x30(%rbp),%rax
jb     1460 <mp_mul+0x2e0>
mov    -0x30(%rbp),%rax
add    -0x58(%rbp),%rax
mov    %rax,-0x58(%rbp)
mov    -0x60(%rbp),%rdi
mov    -0x18(%rbp),%rsi
mov    -0x20(%rbp),%rdx
mov    -0x30(%rbp),%rcx
mov    -0x30(%rbp),%r8
call   10a0 <mp_mul@plt>
mov    %rax,-0x50(%rbp)
mov    -0x10(%rbp),%rdi
mov    -0x58(%rbp),%rax
shl    $0x1,%rax
add    %rax,%rdi
mov    -0x10(%rbp),%rsi
mov    -0x58(%rbp),%rax
shl    $0x1,%rax
add    %rax,%rsi
mov    -0x60(%rbp),%rdx
mov    -0x48(%rbp),%rcx
sub    -0x58(%rbp),%rcx
mov    -0x50(%rbp),%r8
mov    $0x0,%al
call   1040 <mp_add@plt>
mov    -0x30(%rbp),%rcx
mov    -0x28(%rbp),%rax
sub    %rcx,%rax
mov    %rax,-0x28(%rbp)
mov    -0x30(%rbp),%rax
shl    $0x1,%rax
add    -0x18(%rbp),%rax
mov    %rax,-0x18(%rbp)
mov    -0x60(%rbp),%rax
mov    %rax,-0x70(%rbp)
mov    -0x28(%rbp),%rax
cmp    -0x30(%rbp),%rax
jae    143c <mp_mul+0x2bc>
mov    -0x28(%rbp),%rax
mov    %rax,-0x78(%rbp)
jmp    1444 <mp_mul+0x2c4>
mov    -0x30(%rbp),%rax
mov    %rax,-0x78(%rbp)
mov    -0x70(%rbp),%rdi
mov    -0x78(%rbp),%rdx
add    -0x30(%rbp),%rdx
shl    $0x1,%rdx
xor    %esi,%esi
call   1060 <memset@plt>
jmp    138e <mp_mul+0x20e>
cmpq   $0x0,-0x28(%rbp)
je     14c5 <mp_mul+0x345>
mov    -0x30(%rbp),%rax
add    -0x58(%rbp),%rax
mov    %rax,-0x58(%rbp)
mov    -0x60(%rbp),%rdi
mov    -0x20(%rbp),%rsi
mov    -0x18(%rbp),%rdx
mov    -0x30(%rbp),%rcx
mov    -0x28(%rbp),%r8
call   10a0 <mp_mul@plt>
mov    %rax,-0x50(%rbp)
mov    -0x10(%rbp),%rdi
mov    -0x58(%rbp),%rax
shl    $0x1,%rax
add    %rax,%rdi
mov    -0x10(%rbp),%rsi
mov    -0x58(%rbp),%rax
shl    $0x1,%rax
add    %rax,%rsi
mov    -0x60(%rbp),%rdx
mov    -0x48(%rbp),%rcx
mov    -0x50(%rbp),%r8
mov    $0x0,%al
call   1040 <mp_add@plt>
mov    -0x10(%rbp),%rax
mov    -0x48(%rbp),%rcx
sub    $0x1,%rcx
movzwl (%rax,%rcx,2),%eax
cmp    $0x0,%eax
jne    14ea <mp_mul+0x36a>
mov    -0x48(%rbp),%rax
add    $0xffffffffffffffff,%rax
mov    %rax,-0x48(%rbp)
mov    -0x60(%rbp),%rdi
mov    $0x0,%al
call   1080 <mp_free@plt>
mov    -0x48(%rbp),%rax
mov    %rax,-0x8(%rbp)
mov    -0x8(%rbp),%rax
add    $0x80,%rsp
pop    %rbp
ret

x86 assembly (clang, -O2):
<mp_mul>:
push   %rbp
push   %r15
push   %r14
push   %r13
push   %r12
push   %rbx
sub    $0x38,%rsp
mov    %rcx,%r15
mov    %rdx,%rbx
mov    %rdi,%r13
cmp    %r8,%rcx
jae    11aa <mp_mul+0x2a>
mov    %rsi,%rbp
mov    %r8,%r14
cmp    $0x20,%r14
jae    11bc <mp_mul+0x3c>
jmp    11fc <mp_mul+0x7c>
mov    %rbx,%rbp
mov    %r15,%r14
mov    %r8,%r15
mov    %rsi,%rbx
cmp    $0x20,%r14
jb     11fc <mp_mul+0x7c>
cmp    $0x1f,%r15
jbe    11fc <mp_mul+0x7c>
mov    %r15,%rax
or     %r14,%rax
cmp    $0x7f,%rax
ja     121a <mp_mul+0x9a>
lea    0x1(%r14),%rax
shr    %rax
cmp    %rax,%r15
jbe    1270 <mp_mul+0xf0>
mov    %r13,%rdi
mov    %rbx,%rsi
mov    %rbp,%rdx
mov    %r14,%rcx
mov    %r15,%r8
xor    %eax,%eax
call   1070 <mp_karatsuba_mul@plt>
movslq %eax,%rbx
jmp    13d5 <mp_mul+0x255>
mov    %r13,%rdi
mov    %rbx,%rsi
mov    %rbp,%rdx
mov    %r14,%rcx
mov    %r15,%r8
xor    %eax,%eax
call   1090 <mp_base_mul@plt>
movslq %eax,%rbx
jmp    13d5 <mp_mul+0x255>
cmp    $0x80,%r14
jb     1270 <mp_mul+0xf0>
cmp    $0x80,%r15
jb     1270 <mp_mul+0xf0>
lea    0x2(%r15),%rax
movabs $0xaaaaaaaaaaaaaaab,%rsi
aa aa aa
mul    %rsi
mov    %rdx,%rcx
shr    %rcx
lea    0x2(%r14),%rax
mul    %rsi
shr    %rdx
cmp    %rdx,%rcx
jne    1270 <mp_mul+0xf0>
mov    %r13,%rdi
mov    %rbx,%rsi
mov    %rbp,%rdx
mov    %r14,%rcx
mov    %r15,%r8
xor    %eax,%eax
call   1050 <mp_toom_mul@plt>
movslq %eax,%rbx
jmp    13d5 <mp_mul+0x255>
mov    %r13,%rdi
mov    %rbx,%rsi
mov    %rbp,0x10(%rsp)
mov    %rbp,%rdx
mov    %r15,%rcx
mov    %r15,%r8
call   10a0 <mp_mul@plt>
mov    %r14,%rbp
sub    %r15,%rbp
lea    (%r14,%r14,1),%rsi
lea    0x0(,%r15,4),%rax
cmp    %r15,%rbp
cmova  %rax,%rsi
xor    %r12d,%r12d
mov    $0x1,%edi
xor    %eax,%eax
call   1030 <mp_calloc@plt>
movslq %eax,%rdi
lea    (%rbx,%r15,2),%rbx
cmp    %r15,%rbp
mov    %r13,0x8(%rsp)
jb     137a <mp_mul+0x1fa>
lea    (%r15,%r15,1),%rcx
mov    %r14,%rbp
lea    0x0(,%r15,2),%r14
add    %r13,%r14
mov    %r15,%rax
neg    %rax
mov    %rax,0x28(%rsp)
mov    %rcx,0x30(%rsp)
neg    %rcx
mov    %rcx,0x20(%rsp)
mov    %rbp,0x18(%rsp)
xor    %r12d,%r12d
nopl   0x0(%rax,%rax,1)
add    %r15,%r12
mov    %rdi,%r13
mov    %rbx,%rsi
mov    0x10(%rsp),%rdx
mov    %r15,%rcx
mov    %r15,%r8
call   10a0 <mp_mul@plt>
mov    %r14,%rdi
mov    %r14,%rsi
mov    %r13,%rdx
mov    %rbp,%rcx
mov    %rax,%r8
xor    %eax,%eax
call   1040 <mp_add@plt>
mov    0x20(%rsp),%rax
lea    (%rax,%rbp,1),%rdx
cmp    %r15,%rdx
cmovae %r15,%rdx
add    %r15,%rdx
add    %rdx,%rdx
mov    %r13,%rdi
xor    %esi,%esi
call   1060 <memset@plt>
mov    %r13,%rdi
mov    0x30(%rsp),%rax
add    %rax,%rbx
sub    %r15,%rbp
add    %rax,%r14
mov    0x28(%rsp),%rax
add    %rbp,%rax
cmp    %r15,%rax
jae    1300 <mp_mul+0x180>
sub    %r15,%rbp
mov    0x18(%rsp),%r14
mov    0x8(%rsp),%r13
add    %r15,%r14
test   %rbp,%rbp
je     13bf <mp_mul+0x23f>
add    %r15,%r12
mov    %rdi,%r13
mov    0x10(%rsp),%rsi
mov    %rbx,%rdx
mov    %r15,%rcx
mov    %rbp,%r8
call   10a0 <mp_mul@plt>
mov    0x8(%rsp),%rcx
lea    (%rcx,%r12,2),%rdi
mov    %rdi,%rsi
mov    %r13,%rdx
mov    %r14,%rcx
mov    %rax,%r8
xor    %eax,%eax
call   1040 <mp_add@plt>
mov    %r13,%rdi
mov    0x8(%rsp),%r13
lea    -0x1(%r14),%rbx
cmpw   $0x0,-0x2(%r13,%r14,2)
cmovne %r14,%rbx
xor    %eax,%eax
call   1080 <mp_free@plt>
mov    %rbx,%rax
add    $0x38,%rsp
pop    %rbx
pop    %r12
pop    %r13
pop    %r14
pop    %r15
pop    %rbp
ret

LLVM IR (-O0):
define i64 @mp_mul(i16* %0, i16* %1, i16* %2, i64 %3, i64 %4) {
%6 = alloca i64
%7 = alloca i16*
%8 = alloca i16*
%9 = alloca i16*
%10 = alloca i64
%11 = alloca i64
%12 = alloca i16*
%13 = alloca i64
%14 = alloca i64
%15 = alloca i64
%16 = alloca i64
%17 = alloca i16*
store i16* %0, i16** %7
store i16* %1, i16** %8
store i16* %2, i16** %9
store i64 %3, i64* %10
store i64 %4, i64* %11
%18 = load i64, i64* %10
%19 = load i64, i64* %11
%20 = icmp ult i64 %18, %19
br i1 %20, label %21, label %28
21: ; preds = %5
%22 = load i16*, i16** %8
store i16* %22, i16** %12
%23 = load i64, i64* %10
store i64 %23, i64* %13
%24 = load i16*, i16** %9
store i16* %24, i16** %8
%25 = load i64, i64* %11
store i64 %25, i64* %10
%26 = load i16*, i16** %12
store i16* %26, i16** %9
%27 = load i64, i64* %13
store i64 %27, i64* %11
br label %28
28: ; preds = %21, %5
%29 = load i64, i64* %10
%30 = icmp ult i64 %29, 32
br i1 %30, label %34, label %31
31: ; preds = %28
%32 = load i64, i64* %11
%33 = icmp ult i64 %32, 32
br i1 %33, label %34, label %42
34: ; preds = %31, %28
%35 = load i16*, i16** %7
%36 = load i16*, i16** %8
%37 = load i16*, i16** %9
%38 = load i64, i64* %10
%39 = load i64, i64* %11
%40 = call i32 (i16*, i16*, i16*, i64, i64, ...) bitcast (i32 (...)* @mp_base_mul to i32 (i16*, i16*, i16*, i64, i64, ...)*)(i16* %35, i16* %36, i16* %37, i64 %38, i64 %39)
%41 = sext i32 %40 to i64
store i64 %41, i64* %6
br label %204
42: ; preds = %31
%43 = load i64, i64* %10
%44 = icmp ult i64 %43, 128
br i1 %44, label %45, label %62
45: ; preds = %42
%46 = load i64, i64* %11
%47 = icmp ult i64 %46, 128
br i1 %47, label %48, label %62
48: ; preds = %45
%49 = load i64, i64* %11
%50 = load i64, i64* %10
%51 = add i64 %50, 1
%52 = lshr i64 %51, 1
%53 = icmp ugt i64 %49, %52
br i1 %53, label %54, label %62
54: ; preds = %48
%55 = load i16*, i16** %7
%56 = load i16*, i16** %8
%57 = load i16*, i16** %9
%58 = load i64, i64* %10
%59 = load i64, i64* %11
%60 = call i32 (i16*, i16*, i16*, i64, i64, ...) bitcast (i32 (...)* @mp_karatsuba_mul to i32 (i16*, i16*, i16*, i64, i64, ...)*)(i16* %55, i16* %56, i16* %57, i64 %58, i64 %59)
%61 = sext i32 %60 to i64
store i64 %61, i64* %6
br label %204
62: ; preds = %48, %45, %42
%63 = load i64, i64* %10
%64 = icmp uge i64 %63, 128
br i1 %64, label %65, label %84
65: ; preds = %62
%66 = load i64, i64* %11
%67 = icmp uge i64 %66, 128
br i1 %67, label %68, label %84
68: ; preds = %65
%69 = load i64, i64* %11
%70 = add i64 %69, 2
%71 = udiv i64 %70, 3
%72 = load i64, i64* %10
%73 = add i64 %72, 2
%74 = udiv i64 %73, 3
%75 = icmp eq i64 %71, %74
br i1 %75, label %76, label %84
76: ; preds = %68
%77 = load i16*, i16** %7
%78 = load i16*, i16** %8
%79 = load i16*, i16** %9
%80 = load i64, i64* %10
%81 = load i64, i64* %11
%82 = call i32 (i16*, i16*, i16*, i64, i64, ...) bitcast (i32 (...)* @mp_toom_mul to i32 (i16*, i16*, i16*, i64, i64, ...)*)(i16* %77, i16* %78, i16* %79, i64 %80, i64 %81)
%83 = sext i32 %82 to i64
store i64 %83, i64* %6
br label %204
84: ; preds = %68, %65, %62
store i64 0, i64* %16
%85 = load i64, i64* %10
%86 = load i64, i64* %11
%87 = add i64 %85, %86
store i64 %87, i64* %14
%88 = load i16*, i16** %7
%89 = load i16*, i16** %8
%90 = load i16*, i16** %9
%91 = load i64, i64* %11
%92 = load i64, i64* %11
%93 = call i64 @mp_mul(i16* %88, i16* %89, i16* %90, i64 %91, i64 %92)
%94 = load i64, i64* %11
%95 = load i64, i64* %10
%96 = sub i64 %95, %94
store i64 %96, i64* %10
%97 = load i64, i64* %11
%98 = load i16*, i16** %8
%99 = getelementptr inbounds i16, i16* %98, i64 %97
store i16* %99, i16** %8
%100 = load i64, i64* %10
%101 = load i64, i64* %11
%102 = icmp ugt i64 %100, %101
br i1 %102, label %103, label %111
103: ; preds = %84
%104 = load i64, i64* %11
%105 = load i64, i64* %11
%106 = add i64 %104, %105
%107 = mul i64 2, %106
%108 = call i32 (i32, i64, ...) bitcast (i32 (...)* @mp_calloc to i32 (i32, i64, ...)*)(i32 1, i64 %107)
%109 = sext i32 %108 to i64
%110 = inttoptr i64 %109 to i16*
store i16* %110, i16** %17
br label %119
111: ; preds = %84
%112 = load i64, i64* %10
%113 = load i64, i64* %11
%114 = add i64 %112, %113
%115 = mul i64 2, %114
%116 = call i32 (i32, i64, ...) bitcast (i32 (...)* @mp_calloc to i32 (i32, i64, ...)*)(i32 1, i64 %115)
%117 = sext i32 %116 to i64
%118 = inttoptr i64 %117 to i16*
store i16* %118, i16** %17
br label %119
119: ; preds = %111, %103
br label %120
120: ; preds = %161, %119
%121 = load i64, i64* %10
%122 = load i64, i64* %11
%123 = icmp uge i64 %121, %122
br i1 %123, label %124, label %166
124: ; preds = %120
%125 = load i64, i64* %11
%126 = load i64, i64* %16
%127 = add i64 %126, %125
store i64 %127, i64* %16
%128 = load i16*, i16** %17
%129 = load i16*, i16** %8
%130 = load i16*, i16** %9
%131 = load i64, i64* %11
%132 = load i64, i64* %11
%133 = call i64 @mp_mul(i16* %128, i16* %129, i16* %130, i64 %131, i64 %132)
store i64 %133, i64* %15
%134 = load i16*, i16** %7
%135 = load i64, i64* %16
%136 = getelementptr inbounds i16, i16* %134, i64 %135
%137 = load i16*, i16** %7
%138 = load i64, i64* %16
%139 = getelementptr inbounds i16, i16* %137, i64 %138
%140 = load i16*, i16** %17
%141 = load i64, i64* %14
%142 = load i64, i64* %16
%143 = sub nsw i64 %141, %142
%144 = load i64, i64* %15
%145 = call i32 (i16*, i16*, i16*, i64, i64, ...) bitcast (i32 (...)* @mp_add to i32 (i16*, i16*, i16*, i64, i64, ...)*)(i16* %136, i16* %139, i16* %140, i64 %143, i64 %144)
%146 = load i64, i64* %11
%147 = load i64, i64* %10
%148 = sub i64 %147, %146
store i64 %148, i64* %10
%149 = load i64, i64* %11
%150 = load i16*, i16** %8
%151 = getelementptr inbounds i16, i16* %150, i64 %149
store i16* %151, i16** %8
%152 = load i16*, i16** %17
%153 = bitcast i16* %152 to i8*
%154 = load i64, i64* %10
%155 = load i64, i64* %11
%156 = icmp ult i64 %154, %155
br i1 %156, label %157, label %159
157: ; preds = %124
%158 = load i64, i64* %10
br label %161
159: ; preds = %124
%160 = load i64, i64* %11
br label %161
161: ; preds = %159, %157
%162 = phi i64 [ %158, %157 ], [ %160, %159 ]
%163 = load i64, i64* %11
%164 = add i64 %162, %163
%165 = mul i64 2, %164
br label %120
166: ; preds = %120
%167 = load i64, i64* %10
%168 = icmp ne i64 %167, 0
br i1 %168, label %169, label %189
169: ; preds = %166
%170 = load i64, i64* %11
%171 = load i64, i64* %16
%172 = add i64 %171, %170
store i64 %172, i64* %16
%173 = load i16*, i16** %17
%174 = load i16*, i16** %9
%175 = load i16*, i16** %8
%176 = load i64, i64* %11
%177 = load i64, i64* %10
%178 = call i64 @mp_mul(i16* %173, i16* %174, i16* %175, i64 %176, i64 %177)
store i64 %178, i64* %15
%179 = load i16*, i16** %7
%180 = load i64, i64* %16
%181 = getelementptr inbounds i16, i16* %179, i64 %180
%182 = load i16*, i16** %7
%183 = load i64, i64* %16
%184 = getelementptr inbounds i16, i16* %182, i64 %183
%185 = load i16*, i16** %17
%186 = load i64, i64* %14
%187 = load i64, i64* %15
%188 = call i32 (i16*, i16*, i16*, i64, i64, ...) bitcast (i32 (...)* @mp_add to i32 (i16*, i16*, i16*, i64, i64, ...)*)(i16* %181, i16* %184, i16* %185, i64 %186, i64 %187)
br label %189
189: ; preds = %169, %166
%190 = load i16*, i16** %7
%191 = load i64, i64* %14
%192 = sub nsw i64 %191, 1
%193 = getelementptr inbounds i16, i16* %190, i64 %192
%194 = load i16, i16* %193
%195 = zext i16 %194 to i32
%196 = icmp eq i32 %195, 0
br i1 %196, label %197, label %200
197: ; preds = %189
%198 = load i64, i64* %14
%199 = add nsw i64 %198, -1
store i64 %199, i64* %14
br label %200
200: ; preds = %197, %189
%201 = load i16*, i16** %17
%202 = call i32 (i16*, ...) bitcast (i32 (...)* @mp_free to i32 (i16*, ...)*)(i16* %201)
%203 = load i64, i64* %14
store i64 %203, i64* %6
br label %204
204: ; preds = %200, %76, %54, %34
%205 = load i64, i64* %6
ret i64 %205
}

LLVM IR (-O2):
define i64 @mp_mul(i16* %0, i16* %1, i16* %2, i64 %3, i64 %4) {
%6 = icmp ult i64 %3, %4
br i1 %6, label %7, label %8
7: ; preds = %5
br label %8
8: ; preds = %7, %5
%9 = phi i16* [ %1, %7 ], [ %2, %5 ]
%10 = phi i64 [ %4, %7 ], [ %3, %5 ]
%11 = phi i64 [ %3, %7 ], [ %4, %5 ]
%12 = phi i16* [ %2, %7 ], [ %1, %5 ]
%13 = icmp ult i64 %10, 32
%14 = icmp ult i64 %11, 32
%15 = or i1 %13, %14
br i1 %15, label %16, label %19
16: ; preds = %8
%17 = tail call i32 (i16*, i16*, i16*, i64, i64, ...) bitcast (i32 (...)* @mp_base_mul to i32 (i16*, i16*, i16*, i64, i64, ...)*)(i16* %0, i16* %12, i16* %9, i64 %10, i64 %11)
%18 = sext i32 %17 to i64
br label %89
19: ; preds = %8
%20 = or i64 %11, %10
%21 = icmp ult i64 %20, 128
br i1 %21, label %22, label %29
22: ; preds = %19
%23 = add nuw nsw i64 %10, 1
%24 = lshr i64 %23, 1
%25 = icmp ugt i64 %11, %24
br i1 %25, label %26, label %42
26: ; preds = %22
%27 = tail call i32 (i16*, i16*, i16*, i64, i64, ...) bitcast (i32 (...)* @mp_karatsuba_mul to i32 (i16*, i16*, i16*, i64, i64, ...)*)(i16* %0, i16* %12, i16* %9, i64 %10, i64 %11)
%28 = sext i32 %27 to i64
br label %89
29: ; preds = %19
%30 = icmp ugt i64 %10, 127
%31 = icmp ugt i64 %11, 127
%32 = and i1 %30, %31
br i1 %32, label %33, label %42
33: ; preds = %29
%34 = add i64 %11, 2
%35 = udiv i64 %34, 3
%36 = add i64 %10, 2
%37 = udiv i64 %36, 3
%38 = icmp eq i64 %35, %37
br i1 %38, label %39, label %42
39: ; preds = %33
%40 = tail call i32 (i16*, i16*, i16*, i64, i64, ...) bitcast (i32 (...)* @mp_toom_mul to i32 (i16*, i16*, i16*, i64, i64, ...)*)(i16* %0, i16* %12, i16* %9, i64 %10, i64 %11)
%41 = sext i32 %40 to i64
br label %89
42: ; preds = %22, %33, %29
%43 = add i64 %11, %10
%44 = tail call i64 @mp_mul(i16* %0, i16* %12, i16* %9, i64 %11, i64 %11)
%45 = sub i64 %10, %11
%46 = icmp ugt i64 %45, %11
%47 = shl i64 %10, 1
%48 = shl i64 %11, 2
%49 = select i1 %46, i64 %48, i64 %47
%50 = tail call i32 (i32, i64, ...) bitcast (i32 (...)* @mp_calloc to i32 (i32, i64, ...)*)(i32 1, i64 %49)
%51 = sext i32 %50 to i64
%52 = inttoptr i64 %51 to i16*
%53 = getelementptr inbounds i16, i16* %12, i64 %11
%54 = icmp ult i64 %45, %11
br i1 %54, label %72, label %55
55: ; preds = %42
%56 = inttoptr i64 %51 to i8*
br label %57
57: ; preds = %55, %57
%58 = phi i16* [ %53, %55 ], [ %71, %57 ]
%59 = phi i64 [ 0, %55 ], [ %61, %57 ]
%60 = phi i64 [ %45, %55 ], [ %66, %57 ]
%61 = add i64 %59, %11
%62 = tail call i64 @mp_mul(i16* %52, i16* %58, i16* %9, i64 %11, i64 %11)
%63 = getelementptr inbounds i16, i16* %0, i64 %61
%64 = sub nsw i64 %43, %61
%65 = tail call i32 (i16*, i16*, i16*, i64, i64, ...) bitcast (i32 (...)* @mp_add to i32 (i16*, i16*, i16*, i64, i64, ...)*)(i16* %63, i16* %63, i16* %52, i64 %64, i64 %62)
%66 = sub i64 %60, %11
%67 = icmp ult i64 %66, %11
%68 = select i1 %67, i64 %66, i64 %11
%69 = add i64 %68, %11
%70 = shl i64 %69, 1
tail call void @llvm.memset.p0i8.i64(i8* align 2 %56, i8 0, i64 %70, i1 false)
%71 = getelementptr inbounds i16, i16* %58, i64 %11
br i1 %67, label %72, label %57
72: ; preds = %57, %42
%73 = phi i64 [ %45, %42 ], [ %66, %57 ]
%74 = phi i64 [ 0, %42 ], [ %61, %57 ]
%75 = phi i16* [ %53, %42 ], [ %71, %57 ]
%76 = icmp eq i64 %73, 0
br i1 %76, label %82, label %77
77: ; preds = %72
%78 = add i64 %74, %11
%79 = tail call i64 @mp_mul(i16* %52, i16* %9, i16* %75, i64 %11, i64 %73)
%80 = getelementptr inbounds i16, i16* %0, i64 %78
%81 = tail call i32 (i16*, i16*, i16*, i64, i64, ...) bitcast (i32 (...)* @mp_add to i32 (i16*, i16*, i16*, i64, i64, ...)*)(i16* %80, i16* %80, i16* %52, i64 %43, i64 %79)
br label %82
82: ; preds = %77, %72
%83 = add nsw i64 %43, -1
%84 = getelementptr inbounds i16, i16* %0, i64 %83
%85 = load i16, i16* %84
%86 = icmp eq i16 %85, 0
%87 = select i1 %86, i64 %83, i64 %43
%88 = tail call i32 (i16*, ...) bitcast (i32 (...)* @mp_free to i32 (i16*, ...)*)(i16* %52)
br label %89
89: ; preds = %82, %39, %26, %16
%90 = phi i64 [ %18, %16 ], [ %28, %26 ], [ %41, %39 ], [ %87, %82 ]
ret i64 %90
}