long factorial(int n) {
  static const long factorials[] = {1,
                                    1,
                                    2,
                                    6,
                                    24,
                                    120,
                                    720,
                                    5040,
                                    40320,
                                    362880,
                                    3628800,
                                    39916800L,
                                    479001600L,
                                    6227020800L,
                                    87178291200L,
                                    1307674368000L,
                                    20922789888000L,
                                    355687428096000L,
                                    6402373705728000L,
                                    121645100408832000L,
                                    2432902008176640000L};
  if (n <= 20)
    return factorials[n];
  long f = 1;
  while (n >= 2)
    f *= n--;
  return f;
}


x86 assembly (clang, -O0):
<factorial>:
push   %rbp
mov    %rsp,%rbp
mov    %edi,-0xc(%rbp)
cmpl   $0x14,-0xc(%rbp)
jg     1129 <factorial+0x29>
movslq -0xc(%rbp),%rcx
lea    0xee4(%rip),%rax
mov    (%rax,%rcx,8),%rax
mov    %rax,-0x8(%rbp)
jmp    115e <factorial+0x5e>
movq   $0x1,-0x18(%rbp)
cmpl   $0x2,-0xc(%rbp)
jl     1156 <factorial+0x56>
mov    -0xc(%rbp),%eax
mov    %eax,%ecx
add    $0xffffffff,%ecx
mov    %ecx,-0xc(%rbp)
cltq
imul   -0x18(%rbp),%rax
mov    %rax,-0x18(%rbp)
jmp    1131 <factorial+0x31>
mov    -0x18(%rbp),%rax
mov    %rax,-0x8(%rbp)
mov    -0x8(%rbp),%rax
pop    %rbp
ret

x86 assembly (clang, -O2):
<factorial>:
cmp    $0x15,%edi
jge    1114 <factorial+0x14>
movslq %edi,%rax
lea    0xef1(%rip),%rcx
mov    (%rcx,%rax,8),%rax
ret
mov    %edi,%ecx
mov    $0x1,%eax
nopl   0x0(%rax,%rax,1)
imul   %rcx,%rax
lea    -0x1(%rcx),%rdx
cmp    $0x2,%rcx
mov    %rdx,%rcx
ja     1120 <factorial+0x20>
ret

LLVM IR (-O0):
@factorial.factorials = internal constant [21 x i64] [i64 1, i64 1, i64 2, i64 6, i64 24, i64 120, i64 720, i64 5040, i64 40320, i64 362880, i64 3628800, i64 39916800, i64 479001600, i64 6227020800, i64 87178291200, i64 1307674368000, i64 20922789888000, i64 355687428096000, i64 6402373705728000, i64 121645100408832000, i64 2432902008176640000]
define i64 @factorial(i32 %0) {
%2 = alloca i64
%3 = alloca i32
%4 = alloca i64
store i32 %0, i32* %3
%5 = load i32, i32* %3
%6 = icmp sle i32 %5, 20
br i1 %6, label %7, label %12
7: ; preds = %1
%8 = load i32, i32* %3
%9 = sext i32 %8 to i64
%10 = getelementptr inbounds [21 x i64], [21 x i64]* @factorial.factorials, i64 0, i64 %9
%11 = load i64, i64* %10
store i64 %11, i64* %2
br label %24
12: ; preds = %1
store i64 1, i64* %4
br label %13
13: ; preds = %16, %12
%14 = load i32, i32* %3
%15 = icmp sge i32 %14, 2
br i1 %15, label %16, label %22
16: ; preds = %13
%17 = load i32, i32* %3
%18 = add nsw i32 %17, -1
store i32 %18, i32* %3
%19 = sext i32 %17 to i64
%20 = load i64, i64* %4
%21 = mul nsw i64 %20, %19
store i64 %21, i64* %4
br label %13
22: ; preds = %13
%23 = load i64, i64* %4
store i64 %23, i64* %2
br label %24
24: ; preds = %22, %7
%25 = load i64, i64* %2
ret i64 %25
}

LLVM IR (-O2):
@factorial.factorials = internal unnamed_addr constant [21 x i64] [i64 1, i64 1, i64 2, i64 6, i64 24, i64 120, i64 720, i64 5040, i64 40320, i64 362880, i64 3628800, i64 39916800, i64 479001600, i64 6227020800, i64 87178291200, i64 1307674368000, i64 20922789888000, i64 355687428096000, i64 6402373705728000, i64 121645100408832000, i64 2432902008176640000]
define i64 @factorial(i32 %0) {
%2 = icmp slt i32 %0, 21
br i1 %2, label %5, label %3
3: ; preds = %1
%4 = zext i32 %0 to i64
br label %9
5: ; preds = %1
%6 = sext i32 %0 to i64
%7 = getelementptr inbounds [21 x i64], [21 x i64]* @factorial.factorials, i64 0, i64 %6
%8 = load i64, i64* %7
br label %15
9: ; preds = %3, %9
%10 = phi i64 [ %4, %3 ], [ %12, %9 ]
%11 = phi i64 [ 1, %3 ], [ %13, %9 ]
%12 = add nsw i64 %10, -1
%13 = mul nsw i64 %11, %10
%14 = icmp ugt i64 %10, 2
br i1 %14, label %9, label %15
15: ; preds = %9, %5
%16 = phi i64 [ %8, %5 ], [ %13, %9 ]
ret i64 %16
}