void _ultoa(unsigned long value, char *string, unsigned char radix) {
  char buffer[32];
  unsigned char index = 32;
  do {
    unsigned char c = '0' + (value % radix);
    if (c > (unsigned char)'9')
      c += 'A' - '9' - 1;
    buffer[--index] = c;
    value /= radix;
  } while (value);
  do {
    *string++ = buffer[index];
  } while (++index != 32);
  *string = 0;
}


x86 assembly (clang, -O0):
<_ultoa>:
push   %rbp
mov    %rsp,%rbp
mov    %dl,%al
mov    %rdi,-0x8(%rbp)
mov    %rsi,-0x10(%rbp)
mov    %al,-0x11(%rbp)
movb   $0x20,-0x41(%rbp)
mov    -0x8(%rbp),%rax
movzbl -0x11(%rbp),%ecx
xor    %edx,%edx
div    %rcx
add    $0x30,%rdx
mov    %dl,%al
mov    %al,-0x42(%rbp)
movzbl -0x42(%rbp),%eax
cmp    $0x39,%eax
jle    1142 <_ultoa+0x42>
movzbl -0x42(%rbp),%eax
add    $0x7,%eax
mov    %al,-0x42(%rbp)
mov    -0x42(%rbp),%cl
mov    -0x41(%rbp),%al
add    $0xff,%al
mov    %al,-0x41(%rbp)
movzbl %al,%eax
mov    %cl,-0x40(%rbp,%rax,1)
movzbl -0x11(%rbp),%eax
mov    %eax,%ecx
mov    -0x8(%rbp),%rax
xor    %edx,%edx
div    %rcx
mov    %rax,-0x8(%rbp)
cmpq   $0x0,-0x8(%rbp)
jne    1115 <_ultoa+0x15>
jmp    1177 <_ultoa+0x77>
movzbl -0x41(%rbp),%eax
mov    -0x40(%rbp,%rax,1),%cl
mov    -0x10(%rbp),%rax
mov    %rax,%rdx
add    $0x1,%rdx
mov    %rdx,-0x10(%rbp)
mov    %cl,(%rax)
mov    -0x41(%rbp),%al
add    $0x1,%al
mov    %al,-0x41(%rbp)
movzbl %al,%eax
cmp    $0x20,%eax
jne    1177 <_ultoa+0x77>
mov    -0x10(%rbp),%rax
movb   $0x0,(%rax)
pop    %rbp
ret

x86 assembly (clang, -O2):
<_ultoa>:
push   %r14
push   %rbx
mov    %edx,%r9d
mov    $0xfe,%r8b
xor    %r14d,%r14d
jmp    1145 <_ultoa+0x45>
xchg   %ax,%ax
mov    %rdi,%rax
xor    %edx,%edx
div    %r9
lea    0x30(%rdx),%ebx
add    $0x37,%dl
cmp    $0x3a,%bl
movzbl %dl,%ecx
movzbl %bl,%edx
cmovae %ecx,%edx
lea    0x1f(%r14),%ecx
movzbl %cl,%ecx
mov    %dl,-0x28(%rsp,%rcx,1)
add    $0xff,%r14b
add    $0x1,%r8b
cmp    %r9,%rdi
mov    %rax,%rdi
jb     1157 <_ultoa+0x57>
mov    %rdi,%rax
shr    $0x20,%rax
jne    1110 <_ultoa+0x10>
mov    %edi,%eax
xor    %edx,%edx
div    %r9d
jmp    1118 <_ultoa+0x18>
lea    0x1(%rsi),%rax
mov    %dl,(%rsi)
cmp    $0xff,%r14b
je     12e0 <_ultoa+0x1e0>
mov    $0xfe,%bl
sub    %r14b,%bl
lea    0x21(%r14),%edi
cmp    $0x1f,%bl
jb     124f <_ultoa+0x14f>
cmp    $0x1f,%dil
ja     124f <_ultoa+0x14f>
movzbl %bl,%edi
lea    0x1(%rdi),%r9
mov    %r9d,%r10d
and    $0xffffffe0,%r10d
lea    -0x20(%r10),%rcx
mov    %rcx,%r11
shr    $0x5,%r11
add    $0x1,%r11
test   %rcx,%rcx
je     12e7 <_ultoa+0x1e7>
lea    0x41(%r14),%ebx
add    $0x1,%edi
and    $0xffffffe0,%edi
add    $0xffffffffffffffe0,%rdi
shr    $0x5,%rdi
add    $0x1,%rdi
and    $0xfffffffffffffffe,%rdi
xor    %edx,%edx
cs nopw 0x0(%rax,%rax,1)
nop
lea    -0x20(%rbx),%ecx
movzbl %cl,%ecx
movups -0x28(%rsp,%rcx,1),%xmm0
movups -0x18(%rsp,%rcx,1),%xmm1
movups %xmm0,0x1(%rsi,%rdx,1)
movups %xmm1,0x11(%rsi,%rdx,1)
movzbl %bl,%ebx
movups -0x28(%rsp,%rbx,1),%xmm0
movups -0x18(%rsp,%rbx,1),%xmm1
movups %xmm0,0x21(%rsi,%rdx,1)
movups %xmm1,0x31(%rsi,%rdx,1)
add    $0x40,%rdx
add    $0x40,%bl
add    $0xfffffffffffffffe,%rdi
jne    11d0 <_ultoa+0xd0>
test   $0x1,%r11b
je     1231 <_ultoa+0x131>
lea    (%rdx,%r14,1),%ecx
add    $0x21,%cl
movzbl %cl,%ecx
movups -0x28(%rsp,%rcx,1),%xmm0
movups -0x18(%rsp,%rcx,1),%xmm1
movups %xmm0,(%rax,%rdx,1)
movups %xmm1,0x10(%rax,%rdx,1)
add    %r10,%rax
cmp    %r10,%r9
je     12e0 <_ultoa+0x1e0>
add    $0x1,%r8b
and    $0xe0,%r8b
add    %r14b,%r8b
add    $0x21,%r8b
mov    %r8d,%edi
mov    %edi,%ebx
neg    %bl
mov    %edi,%ecx
and    $0x3,%bl
je     1276 <_ultoa+0x176>
nopw   0x0(%rax,%rax,1)
movzbl %cl,%ecx
movzbl -0x28(%rsp,%rcx,1),%edx
mov    %dl,(%rax)
add    $0x1,%rax
add    $0x1,%cl
add    $0xff,%bl
jne    1260 <_ultoa+0x160>
add    $0xe3,%dil
cmp    $0x3,%dil
jb     12e0 <_ultoa+0x1e0>
movzbl %cl,%edx
xor    %ecx,%ecx
cs nopw 0x0(%rax,%rax,1)
nop
lea    (%rdx,%rcx,1),%rsi
movzbl %sil,%edi
movzbl -0x28(%rsp,%rdi,1),%ebx
mov    %bl,(%rax,%rcx,1)
lea    0x1(%rsi),%edi
movzbl %dil,%edi
movzbl -0x28(%rsp,%rdi,1),%ebx
mov    %bl,0x1(%rax,%rcx,1)
lea    0x2(%rsi),%edi
movzbl %dil,%edi
movzbl -0x28(%rsp,%rdi,1),%ebx
mov    %bl,0x2(%rax,%rcx,1)
add    $0x3,%esi
movzbl %sil,%esi
movzbl -0x28(%rsp,%rsi,1),%ebx
mov    %bl,0x3(%rax,%rcx,1)
add    $0x4,%rcx
lea    (%rcx,%rdx,1),%esi
cmp    $0x20,%sil
jne    1290 <_ultoa+0x190>
add    %rcx,%rax
movb   $0x0,(%rax)
pop    %rbx
pop    %r14
ret
xor    %edx,%edx
test   $0x1,%r11b
jne    1214 <_ultoa+0x114>
jmp    1231 <_ultoa+0x131>

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

LLVM IR (-O2):
define void @_ultoa(i64 %0, i8* nocapture writeonly %1, i8 zeroext %2) {
%4 = alloca [32 x i8]
%5 = getelementptr inbounds [32 x i8], [32 x i8]* %4, i64 0, i64 0
%6 = zext i8 %2 to i64
br label %7
7: ; preds = %7, %3
%8 = phi i64 [ %0, %3 ], [ %19, %7 ]
%9 = phi i8 [ 32, %3 ], [ %16, %7 ]
%10 = urem i64 %8, %6
%11 = trunc i64 %10 to i8
%12 = add i8 %11, 48
%13 = icmp ugt i8 %12, 57
%14 = add i8 %11, 55
%15 = select i1 %13, i8 %14, i8 %12
%16 = add i8 %9, -1
%17 = zext i8 %16 to i64
%18 = getelementptr inbounds [32 x i8], [32 x i8]* %4, i64 0, i64 %17
store i8 %15, i8* %18
%19 = udiv i64 %8, %6
%20 = icmp ult i64 %8, %6
br i1 %20, label %21, label %7
21: ; preds = %7
%22 = getelementptr inbounds i8, i8* %1, i64 1
store i8 %15, i8* %1
%23 = icmp eq i8 %9, 32
br i1 %23, label %142, label %24
24: ; preds = %21
%25 = sub i8 31, %9
%26 = zext i8 %25 to i64
%27 = add nuw nsw i64 %26, 1
%28 = icmp ult i8 %25, 31
%29 = icmp ugt i8 %9, 31
%30 = or i1 %28, %29
br i1 %30, label %95, label %31
31: ; preds = %24
%32 = and i64 %27, 480
%33 = trunc i64 %32 to i8
%34 = add i8 %9, %33
%35 = getelementptr i8, i8* %22, i64 %32
%36 = add nsw i64 %32, -32
%37 = lshr exact i64 %36, 5
%38 = add nuw nsw i64 %37, 1
%39 = and i64 %38, 1
%40 = icmp eq i64 %36, 0
br i1 %40, label %76, label %41
41: ; preds = %31
%42 = and i64 %38, 1152921504606846974
br label %43
43: ; preds = %43, %41
%44 = phi i64 [ 0, %41 ], [ %73, %43 ]
%45 = phi i64 [ 0, %41 ], [ %74, %43 ]
%46 = trunc i64 %44 to i8
%47 = add i8 %9, %46
%48 = getelementptr i8, i8* %22, i64 %44
%49 = zext i8 %47 to i64
%50 = getelementptr inbounds [32 x i8], [32 x i8]* %4, i64 0, i64 %49
%51 = bitcast i8* %50 to <16 x i8>*
%52 = load <16 x i8>, <16 x i8>* %51
%53 = getelementptr inbounds i8, i8* %50, i64 16
%54 = bitcast i8* %53 to <16 x i8>*
%55 = load <16 x i8>, <16 x i8>* %54
%56 = bitcast i8* %48 to <16 x i8>*
store <16 x i8> %52, <16 x i8>* %56
%57 = getelementptr i8, i8* %48, i64 16
%58 = bitcast i8* %57 to <16 x i8>*
store <16 x i8> %55, <16 x i8>* %58
%59 = or i64 %44, 32
%60 = trunc i64 %59 to i8
%61 = add i8 %9, %60
%62 = getelementptr i8, i8* %22, i64 %59
%63 = zext i8 %61 to i64
%64 = getelementptr inbounds [32 x i8], [32 x i8]* %4, i64 0, i64 %63
%65 = bitcast i8* %64 to <16 x i8>*
%66 = load <16 x i8>, <16 x i8>* %65
%67 = getelementptr inbounds i8, i8* %64, i64 16
%68 = bitcast i8* %67 to <16 x i8>*
%69 = load <16 x i8>, <16 x i8>* %68
%70 = bitcast i8* %62 to <16 x i8>*
store <16 x i8> %66, <16 x i8>* %70
%71 = getelementptr i8, i8* %62, i64 16
%72 = bitcast i8* %71 to <16 x i8>*
store <16 x i8> %69, <16 x i8>* %72
%73 = add nuw i64 %44, 64
%74 = add i64 %45, 2
%75 = icmp eq i64 %74, %42
br i1 %75, label %76, label %43
76: ; preds = %43, %31
%77 = phi i64 [ 0, %31 ], [ %73, %43 ]
%78 = icmp eq i64 %39, 0
br i1 %78, label %93, label %79
79: ; preds = %76
%80 = trunc i64 %77 to i8
%81 = add i8 %9, %80
%82 = getelementptr i8, i8* %22, i64 %77
%83 = zext i8 %81 to i64
%84 = getelementptr inbounds [32 x i8], [32 x i8]* %4, i64 0, i64 %83
%85 = bitcast i8* %84 to <16 x i8>*
%86 = load <16 x i8>, <16 x i8>* %85
%87 = getelementptr inbounds i8, i8* %84, i64 16
%88 = bitcast i8* %87 to <16 x i8>*
%89 = load <16 x i8>, <16 x i8>* %88
%90 = bitcast i8* %82 to <16 x i8>*
store <16 x i8> %86, <16 x i8>* %90
%91 = getelementptr i8, i8* %82, i64 16
%92 = bitcast i8* %91 to <16 x i8>*
store <16 x i8> %89, <16 x i8>* %92
br label %93
93: ; preds = %76, %79
%94 = icmp eq i64 %27, %32
br i1 %94, label %142, label %95
95: ; preds = %24, %93
%96 = phi i8 [ %9, %24 ], [ %34, %93 ]
%97 = phi i8* [ %22, %24 ], [ %35, %93 ]
%98 = sub i8 0, %96
%99 = and i8 %98, 3
%100 = icmp eq i8 %99, 0
br i1 %100, label %112, label %101
101: ; preds = %95, %101
%102 = phi i8 [ %109, %101 ], [ %96, %95 ]
%103 = phi i8* [ %108, %101 ], [ %97, %95 ]
%104 = phi i8 [ %110, %101 ], [ 0, %95 ]
%105 = zext i8 %102 to i64
%106 = getelementptr inbounds [32 x i8], [32 x i8]* %4, i64 0, i64 %105
%107 = load i8, i8* %106
%108 = getelementptr inbounds i8, i8* %103, i64 1
store i8 %107, i8* %103
%109 = add i8 %102, 1
%110 = add i8 %104, 1
%111 = icmp eq i8 %110, %99
br i1 %111, label %112, label %101
112: ; preds = %101, %95
%113 = phi i8* [ undef, %95 ], [ %108, %101 ]
%114 = phi i8 [ %96, %95 ], [ %109, %101 ]
%115 = phi i8* [ %97, %95 ], [ %108, %101 ]
%116 = add i8 %96, -29
%117 = icmp ult i8 %116, 3
br i1 %117, label %142, label %118
118: ; preds = %112, %118
%119 = phi i8 [ %140, %118 ], [ %114, %112 ]
%120 = phi i8* [ %139, %118 ], [ %115, %112 ]
%121 = zext i8 %119 to i64
%122 = getelementptr inbounds [32 x i8], [32 x i8]* %4, i64 0, i64 %121
%123 = load i8, i8* %122
%124 = getelementptr inbounds i8, i8* %120, i64 1
store i8 %123, i8* %120
%125 = add i8 %119, 1
%126 = zext i8 %125 to i64
%127 = getelementptr inbounds [32 x i8], [32 x i8]* %4, i64 0, i64 %126
%128 = load i8, i8* %127
%129 = getelementptr inbounds i8, i8* %120, i64 2
store i8 %128, i8* %124
%130 = add i8 %119, 2
%131 = zext i8 %130 to i64
%132 = getelementptr inbounds [32 x i8], [32 x i8]* %4, i64 0, i64 %131
%133 = load i8, i8* %132
%134 = getelementptr inbounds i8, i8* %120, i64 3
store i8 %133, i8* %129
%135 = add i8 %119, 3
%136 = zext i8 %135 to i64
%137 = getelementptr inbounds [32 x i8], [32 x i8]* %4, i64 0, i64 %136
%138 = load i8, i8* %137
%139 = getelementptr inbounds i8, i8* %120, i64 4
store i8 %138, i8* %134
%140 = add i8 %119, 4
%141 = icmp eq i8 %140, 32
br i1 %141, label %142, label %118
142: ; preds = %112, %118, %93, %21
%143 = phi i8* [ %22, %21 ], [ %35, %93 ], [ %113, %112 ], [ %139, %118 ]
store i8 0, i8* %143
ret void
}