void utoa(unsigned long n, char *s) {
  if (n == 0) {
    *s++ = '0';
    *s = 0;
    return;
  }
  char buffer[128] = {0};
  char *digit;
  for (digit = buffer; n; digit++, n /= 10) {
    *digit = '0' + (n % 10);
  }
  digit--;
  while (digit >= buffer) {
    *s++ = *digit--;
  }
  *s = 0;
}


x86 assembly (clang, -O0):
<utoa>:
push   %rbp
mov    %rsp,%rbp
sub    $0xa0,%rsp
mov    %rdi,-0x8(%rbp)
mov    %rsi,-0x10(%rbp)
cmpq   $0x0,-0x8(%rbp)
jne    114c <utoa+0x3c>
mov    -0x10(%rbp),%rax
mov    %rax,%rcx
add    $0x1,%rcx
mov    %rcx,-0x10(%rbp)
movb   $0x30,(%rax)
mov    -0x10(%rbp),%rax
movb   $0x0,(%rax)
jmp    121b <utoa+0x10b>
lea    -0x90(%rbp),%rdi
xor    %esi,%esi
mov    $0x80,%edx
call   1030 <memset@plt>
lea    -0x90(%rbp),%rax
mov    %rax,-0x98(%rbp)
cmpq   $0x0,-0x8(%rbp)
je     11be <utoa+0xae>
mov    -0x8(%rbp),%rax
mov    $0xa,%ecx
xor    %edx,%edx
div    %rcx
add    $0x30,%rdx
mov    %dl,%cl
mov    -0x98(%rbp),%rax
mov    %cl,(%rax)
mov    -0x98(%rbp),%rax
add    $0x1,%rax
mov    %rax,-0x98(%rbp)
mov    -0x8(%rbp),%rax
mov    $0xa,%ecx
xor    %edx,%edx
div    %rcx
mov    %rax,-0x8(%rbp)
jmp    116d <utoa+0x5d>
mov    -0x98(%rbp),%rax
add    $0xffffffffffffffff,%rax
mov    %rax,-0x98(%rbp)
mov    -0x98(%rbp),%rax
lea    -0x90(%rbp),%rcx
cmp    %rcx,%rax
jb     1214 <utoa+0x104>
mov    -0x98(%rbp),%rax
mov    %rax,%rcx
add    $0xffffffffffffffff,%rcx
mov    %rcx,-0x98(%rbp)
mov    (%rax),%cl
mov    -0x10(%rbp),%rax
mov    %rax,%rdx
add    $0x1,%rdx
mov    %rdx,-0x10(%rbp)
mov    %cl,(%rax)
jmp    11d0 <utoa+0xc0>
mov    -0x10(%rbp),%rax
movb   $0x0,(%rax)
add    $0xa0,%rsp
pop    %rbp
ret

x86 assembly (clang, -O2):
<utoa>:
push   %r14
push   %rbx
push   %rax
test   %rdi,%rdi
je     11b8 <utoa+0xb8>
pxor   %xmm0,%xmm0
movdqa %xmm0,-0x10(%rsp)
movdqa %xmm0,-0x20(%rsp)
movdqa %xmm0,-0x30(%rsp)
movdqa %xmm0,-0x40(%rsp)
movdqa %xmm0,-0x50(%rsp)
movdqa %xmm0,-0x60(%rsp)
movdqa %xmm0,-0x70(%rsp)
movdqa %xmm0,-0x80(%rsp)
lea    -0x80(%rsp),%r8
mov    $0x2,%ecx
sub    %r8,%rcx
lea    -0x81(%rsp),%r10
ff
xor    %r9d,%r9d
movabs $0xcccccccccccccccd,%r11
cc cc cc
cs nopw 0x0(%rax,%rax,1)
nopl   (%rax)
mov    %rdi,%rax
mul    %r11
shr    $0x3,%rdx
lea    (%rdx,%rdx,1),%eax
lea    (%rax,%rax,4),%eax
mov    %edi,%ebx
sub    %eax,%ebx
or     $0x30,%bl
mov    %bl,-0x80(%rsp,%r9,1)
add    $0xffffffffffffffff,%rcx
add    $0x1,%r9
add    $0x1,%r10
cmp    $0xa,%rdi
mov    %rdx,%rdi
jae    1170 <utoa+0x70>
lea    (%rsp,%r9,1),%rax
add    $0xffffffffffffff7f,%rax
cmp    %r8,%rax
jae    11c2 <utoa+0xc2>
mov    %rsi,%rax
jmp    1302 <utoa+0x202>
movw   $0x30,(%rsi)
jmp    1305 <utoa+0x205>
lea    0x1(%rsi),%rax
mov    %bl,(%rsi)
lea    (%rsp,%r9,1),%rdx
add    $0xffffffffffffff7e,%rdx
cmp    %r8,%rdx
jb     1302 <utoa+0x202>
mov    %r8,%rbx
neg    %rbx
cmp    %rbx,%rcx
mov    %rbx,%rdi
cmova  %rcx,%rdi
add    %rsp,%rdi
add    $0xffffffffffffff80,%rdi
lea    (%r9,%rdi,1),%r14
add    $0xffffffffffffffff,%r14
cmp    $0x20,%r14
jb     12f0 <utoa+0x1f0>
mov    %r14,%r11
and    $0xffffffffffffffe0,%r11
cmp    %rbx,%rcx
cmova  %rcx,%rbx
add    %rbx,%r10
and    $0xffffffffffffffe0,%r10
neg    %r10
lea    (%rsp,%r10,1),%rcx
add    $0xffffffffffffff80,%rcx
lea    (%r9,%rcx,1),%rdx
add    $0xfffffffffffffffe,%rdx
add    %r11,%rax
add    $0x11,%rsi
lea    (%rsp,%rbx,1),%rcx
add    $0xffffffffffffff80,%rcx
add    %r9,%rcx
add    $0xffffffffffffffff,%rcx
and    $0xffffffffffffffe0,%rcx
neg    %rcx
xor    %edi,%edi
pxor   %xmm0,%xmm0
lea    (%rsp,%rdi,1),%rbx
add    $0xffffffffffffff80,%rbx
movdqu -0x21(%r9,%rbx,1),%xmm1
movdqu -0x11(%r9,%rbx,1),%xmm2
movdqa %xmm2,%xmm3
punpcklbw %xmm0,%xmm3
pshufd $0x4e,%xmm3,%xmm3
pshuflw $0x1b,%xmm3,%xmm3
pshufhw $0x1b,%xmm3,%xmm3
punpckhbw %xmm0,%xmm2
pshufd $0x4e,%xmm2,%xmm2
pshuflw $0x1b,%xmm2,%xmm2
pshufhw $0x1b,%xmm2,%xmm2
packuswb %xmm3,%xmm2
movdqa %xmm1,%xmm3
punpcklbw %xmm0,%xmm3
pshufd $0x4e,%xmm3,%xmm3
pshuflw $0x1b,%xmm3,%xmm3
pshufhw $0x1b,%xmm3,%xmm3
punpckhbw %xmm0,%xmm1
pshufd $0x4e,%xmm1,%xmm1
pshuflw $0x1b,%xmm1,%xmm1
pshufhw $0x1b,%xmm1,%xmm1
packuswb %xmm3,%xmm1
movdqu %xmm2,-0x10(%rsi)
movdqu %xmm1,(%rsi)
add    $0x20,%rsi
add    $0xffffffffffffffe0,%rdi
cmp    %rdi,%rcx
jne    1250 <utoa+0x150>
cmp    %r11,%r14
je     1302 <utoa+0x202>
cs nopw 0x0(%rax,%rax,1)
nopl   0x0(%rax,%rax,1)
movzbl (%rdx),%ecx
mov    %cl,(%rax)
add    $0x1,%rax
add    $0xffffffffffffffff,%rdx
cmp    %r8,%rdx
jae    12f0 <utoa+0x1f0>
movb   $0x0,(%rax)
add    $0x8,%rsp
pop    %rbx
pop    %r14
ret

LLVM IR (-O0):
define void @utoa(i64 %0, i8* %1) {
%3 = alloca i64
%4 = alloca i8*
%5 = alloca [128 x i8]
%6 = alloca i8*
store i64 %0, i64* %3
store i8* %1, i8** %4
%7 = load i64, i64* %3
%8 = icmp eq i64 %7, 0
br i1 %8, label %9, label %13
9: ; preds = %2
%10 = load i8*, i8** %4
%11 = getelementptr inbounds i8, i8* %10, i32 1
store i8* %11, i8** %4
store i8 48, i8* %10
%12 = load i8*, i8** %4
store i8 0, i8* %12
br label %45
13: ; preds = %2
%14 = bitcast [128 x i8]* %5 to i8*
%15 = getelementptr inbounds [128 x i8], [128 x i8]* %5, i64 0, i64 0
store i8* %15, i8** %6
br label %16
16: ; preds = %25, %13
%17 = load i64, i64* %3
%18 = icmp ne i64 %17, 0
br i1 %18, label %19, label %30
19: ; preds = %16
%20 = load i64, i64* %3
%21 = urem i64 %20, 10
%22 = add i64 48, %21
%23 = trunc i64 %22 to i8
%24 = load i8*, i8** %6
store i8 %23, i8* %24
br label %25
25: ; preds = %19
%26 = load i8*, i8** %6
%27 = getelementptr inbounds i8, i8* %26, i32 1
store i8* %27, i8** %6
%28 = load i64, i64* %3
%29 = udiv i64 %28, 10
store i64 %29, i64* %3
br label %16
30: ; preds = %16
%31 = load i8*, i8** %6
%32 = getelementptr inbounds i8, i8* %31, i32 -1
store i8* %32, i8** %6
br label %33
33: ; preds = %37, %30
%34 = load i8*, i8** %6
%35 = getelementptr inbounds [128 x i8], [128 x i8]* %5, i64 0, i64 0
%36 = icmp uge i8* %34, %35
br i1 %36, label %37, label %43
37: ; preds = %33
%38 = load i8*, i8** %6
%39 = getelementptr inbounds i8, i8* %38, i32 -1
store i8* %39, i8** %6
%40 = load i8, i8* %38
%41 = load i8*, i8** %4
%42 = getelementptr inbounds i8, i8* %41, i32 1
store i8* %42, i8** %4
store i8 %40, i8* %41
br label %33
43: ; preds = %33
%44 = load i8*, i8** %4
store i8 0, i8* %44
br label %45
45: ; preds = %43, %9
ret void
}

LLVM IR (-O2):
define void @utoa(i64 %0, i8* nocapture writeonly %1) {
%3 = alloca [128 x i8]
%4 = ptrtoint [128 x i8]* %3 to i64
%5 = icmp eq i64 %0, 0
br i1 %5, label %6, label %8
6: ; preds = %2
%7 = getelementptr inbounds i8, i8* %1, i64 1
store i8 48, i8* %1
store i8 0, i8* %7
br label %70
8: ; preds = %2
%9 = getelementptr inbounds [128 x i8], [128 x i8]* %3, i64 0, i64 0
br label %52
10: ; preds = %52
%11 = ptrtoint i8* %53 to i64
%12 = icmp ult i8* %53, %9
br i1 %12, label %68, label %13
13: ; preds = %10
%14 = getelementptr inbounds i8, i8* %1, i64 1
store i8 %57, i8* %1
%15 = getelementptr inbounds i8, i8* %53, i64 -1
%16 = icmp ult i8* %15, %9
br i1 %16, label %68, label %17
17: ; preds = %13
%18 = sub i64 0, %4
%19 = sub i64 1, %11
%20 = call i64 @llvm.umax.i64(i64 %18, i64 %19)
%21 = add i64 %20, %11
%22 = icmp ult i64 %21, 32
br i1 %22, label %49, label %23
23: ; preds = %17
%24 = and i64 %21, -32
%25 = sub i64 0, %24
%26 = getelementptr i8, i8* %15, i64 %25
%27 = getelementptr i8, i8* %14, i64 %24
br label %28
28: ; preds = %28, %23
%29 = phi i64 [ 0, %23 ], [ %45, %28 ]
%30 = sub i64 0, %29
%31 = getelementptr i8, i8* %15, i64 %30
%32 = getelementptr i8, i8* %14, i64 %29
%33 = getelementptr i8, i8* %31, i64 -15
%34 = bitcast i8* %33 to <16 x i8>*
%35 = load <16 x i8>, <16 x i8>* %34
%36 = shufflevector <16 x i8> %35, <16 x i8> poison, <16 x i32> <i32 15, i32 14, i32 13, i32 12, i32 11, i32 10, i32 9, i32 8, i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
%37 = getelementptr i8, i8* %31, i64 -16
%38 = getelementptr i8, i8* %37, i64 -15
%39 = bitcast i8* %38 to <16 x i8>*
%40 = load <16 x i8>, <16 x i8>* %39
%41 = shufflevector <16 x i8> %40, <16 x i8> poison, <16 x i32> <i32 15, i32 14, i32 13, i32 12, i32 11, i32 10, i32 9, i32 8, i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
%42 = bitcast i8* %32 to <16 x i8>*
store <16 x i8> %36, <16 x i8>* %42
%43 = getelementptr i8, i8* %32, i64 16
%44 = bitcast i8* %43 to <16 x i8>*
store <16 x i8> %41, <16 x i8>* %44
%45 = add nuw i64 %29, 32
%46 = icmp eq i64 %45, %24
br i1 %46, label %47, label %28
47: ; preds = %28
%48 = icmp eq i64 %21, %24
br i1 %48, label %68, label %49
49: ; preds = %17, %47
%50 = phi i8* [ %15, %17 ], [ %26, %47 ]
%51 = phi i8* [ %14, %17 ], [ %27, %47 ]
br label %61
52: ; preds = %8, %52
%53 = phi i8* [ %9, %8 ], [ %58, %52 ]
%54 = phi i64 [ %0, %8 ], [ %59, %52 ]
%55 = urem i64 %54, 10
%56 = trunc i64 %55 to i8
%57 = or i8 %56, 48
store i8 %57, i8* %53
%58 = getelementptr inbounds i8, i8* %53, i64 1
%59 = udiv i64 %54, 10
%60 = icmp ult i64 %54, 10
br i1 %60, label %10, label %52
61: ; preds = %49, %61
%62 = phi i8* [ %66, %61 ], [ %50, %49 ]
%63 = phi i8* [ %65, %61 ], [ %51, %49 ]
%64 = load i8, i8* %62
%65 = getelementptr inbounds i8, i8* %63, i64 1
store i8 %64, i8* %63
%66 = getelementptr inbounds i8, i8* %62, i64 -1
%67 = icmp ult i8* %66, %9
br i1 %67, label %68, label %61
68: ; preds = %61, %13, %47, %10
%69 = phi i8* [ %1, %10 ], [ %14, %13 ], [ %27, %47 ], [ %65, %61 ]
store i8 0, i8* %69
br label %70
70: ; preds = %68, %6
ret void
}