long double factorial(unsigned n) {
  long double f = 1;
  while (n > 0) {
    f *= n--;
  }
  return f;
}


x86 assembly (clang, -O0):
<factorial>:
push   %rbp
mov    %rsp,%rbp
mov    %edi,-0x4(%rbp)
fld1
fstpt  -0x20(%rbp)
cmpl   $0x0,-0x4(%rbp)
jbe    1135 <factorial+0x35>
mov    -0x4(%rbp),%eax
mov    %eax,%ecx
add    $0xffffffff,%ecx
mov    %ecx,-0x4(%rbp)
mov    %rax,-0x28(%rbp)
fildll -0x28(%rbp)
fldt   -0x20(%rbp)
fmulp  %st,%st(1)
fstpt  -0x20(%rbp)
jmp    110c <factorial+0xc>
fldt   -0x20(%rbp)
pop    %rbp
ret

x86 assembly (clang, -O2):
<factorial>:
fld1
test   %edi,%edi
fldz
je     11d8 <factorial+0xd8>
fstp   %st(1)
fstp   %st(0)
lea    -0x1(%rdi),%eax
mov    %edi,%ecx
fld1
fldz
and    $0x7,%ecx
je     114b <factorial+0x4b>
fstp   %st(0)
fstp   %st(0)
fld1
fldz
fxch   %st(1)
nopl   0x0(%rax,%rax,1)
fstp   %st(1)
mov    %edi,%edx
add    $0xffffffff,%edi
mov    %rdx,-0x8(%rsp)
fildll -0x8(%rsp)
fmulp  %st,%st(1)
fld    %st(0)
add    $0xffffffff,%ecx
fxch   %st(1)
jne    1130 <factorial+0x30>
cmp    $0x7,%eax
fxch   %st(1)
jb     11d8 <factorial+0xd8>
fstp   %st(1)
fldz
nopw   0x0(%rax,%rax,1)
fstp   %st(0)
lea    -0x1(%rdi),%eax
mov    %edi,%ecx
mov    %rcx,-0x10(%rsp)
fildll -0x10(%rsp)
fmulp  %st,%st(1)
mov    %rax,-0x48(%rsp)
fildll -0x48(%rsp)
fmulp  %st,%st(1)
lea    -0x2(%rdi),%eax
mov    %rax,-0x18(%rsp)
fildll -0x18(%rsp)
fmulp  %st,%st(1)
lea    -0x3(%rdi),%eax
mov    %rax,-0x20(%rsp)
fildll -0x20(%rsp)
fmulp  %st,%st(1)
lea    -0x4(%rdi),%eax
mov    %rax,-0x28(%rsp)
fildll -0x28(%rsp)
fmulp  %st,%st(1)
lea    -0x5(%rdi),%eax
mov    %rax,-0x30(%rsp)
fildll -0x30(%rsp)
fmulp  %st,%st(1)
lea    -0x6(%rdi),%eax
mov    %rax,-0x38(%rsp)
fildll -0x38(%rsp)
fmulp  %st,%st(1)
lea    -0x7(%rdi),%eax
mov    %rax,-0x40(%rsp)
fildll -0x40(%rsp)
fmulp  %st,%st(1)
add    $0xfffffff8,%edi
fldz
jne    1160 <factorial+0x60>
fstp   %st(0)
ret

LLVM IR (-O0):
define x86_fp80 @factorial(i32 %0) {
%2 = alloca i32
%3 = alloca x86_fp80
store i32 %0, i32* %2
store x86_fp80 0xK3FFF8000000000000000, x86_fp80* %3
br label %4
4: ; preds = %7, %1
%5 = load i32, i32* %2
%6 = icmp ugt i32 %5, 0
br i1 %6, label %7, label %13
7: ; preds = %4
%8 = load i32, i32* %2
%9 = add i32 %8, -1
store i32 %9, i32* %2
%10 = uitofp i32 %8 to x86_fp80
%11 = load x86_fp80, x86_fp80* %3
%12 = fmul x86_fp80 %11, %10
store x86_fp80 %12, x86_fp80* %3
br label %4
13: ; preds = %4
%14 = load x86_fp80, x86_fp80* %3
ret x86_fp80 %14
}

LLVM IR (-O2):
define x86_fp80 @factorial(i32 %0) {
%2 = icmp eq i32 %0, 0
br i1 %2, label %49, label %3
3: ; preds = %1
%4 = add i32 %0, -1
%5 = and i32 %0, 7
%6 = icmp eq i32 %5, 0
br i1 %6, label %16, label %7
7: ; preds = %3, %7
%8 = phi x86_fp80 [ %13, %7 ], [ 0xK3FFF8000000000000000, %3 ]
%9 = phi i32 [ %11, %7 ], [ %0, %3 ]
%10 = phi i32 [ %14, %7 ], [ 0, %3 ]
%11 = add i32 %9, -1
%12 = uitofp i32 %9 to x86_fp80
%13 = fmul x86_fp80 %8, %12
%14 = add i32 %10, 1
%15 = icmp eq i32 %14, %5
br i1 %15, label %16, label %7
16: ; preds = %7, %3
%17 = phi x86_fp80 [ undef, %3 ], [ %13, %7 ]
%18 = phi x86_fp80 [ 0xK3FFF8000000000000000, %3 ], [ %13, %7 ]
%19 = phi i32 [ %0, %3 ], [ %11, %7 ]
%20 = icmp ult i32 %4, 7
br i1 %20, label %49, label %21
21: ; preds = %16, %21
%22 = phi x86_fp80 [ %47, %21 ], [ %18, %16 ]
%23 = phi i32 [ %45, %21 ], [ %19, %16 ]
%24 = add i32 %23, -1
%25 = uitofp i32 %23 to x86_fp80
%26 = fmul x86_fp80 %22, %25
%27 = add i32 %23, -2
%28 = uitofp i32 %24 to x86_fp80
%29 = fmul x86_fp80 %26, %28
%30 = add i32 %23, -3
%31 = uitofp i32 %27 to x86_fp80
%32 = fmul x86_fp80 %29, %31
%33 = add i32 %23, -4
%34 = uitofp i32 %30 to x86_fp80
%35 = fmul x86_fp80 %32, %34
%36 = add i32 %23, -5
%37 = uitofp i32 %33 to x86_fp80
%38 = fmul x86_fp80 %35, %37
%39 = add i32 %23, -6
%40 = uitofp i32 %36 to x86_fp80
%41 = fmul x86_fp80 %38, %40
%42 = add i32 %23, -7
%43 = uitofp i32 %39 to x86_fp80
%44 = fmul x86_fp80 %41, %43
%45 = add i32 %23, -8
%46 = uitofp i32 %42 to x86_fp80
%47 = fmul x86_fp80 %44, %46
%48 = icmp eq i32 %45, 0
br i1 %48, label %49, label %21
49: ; preds = %16, %21, %1
%50 = phi x86_fp80 [ 0xK3FFF8000000000000000, %1 ], [ %17, %16 ], [ %47, %21 ]
ret x86_fp80 %50
}