void byteToString(unsigned char *buffer, int len, unsigned char *string) {
  int i = 0;
  int tmp;
  for (i = 0; i < len; i++) {
    tmp = buffer[i] >> 4;
    if (tmp >= 0 && tmp <= 9)
      string[i * 2] = tmp + '0';
    else if (tmp >= 10 && tmp <= 15)
      string[i * 2] = tmp - 10 + 'A';
    else
      string[i * 2] = 'F';
    tmp = buffer[i] & 0xF;
    if (tmp >= 0 && tmp <= 9)
      string[i * 2 + 1] = tmp + '0';
    else if (tmp >= 10 && tmp <= 15)
      string[i * 2 + 1] = tmp - 10 + 'A';
    else
      string[i * 2 + 1] = 'F';
  }
  string[i * 2] = '\0';
}


x86 assembly (clang, -O0):
<byteToString>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x8(%rbp)
mov    %esi,-0xc(%rbp)
mov    %rdx,-0x18(%rbp)
movl   $0x0,-0x1c(%rbp)
movl   $0x0,-0x1c(%rbp)
mov    -0x1c(%rbp),%eax
cmp    -0xc(%rbp),%eax
jge    125f <byteToString+0x15f>
mov    -0x8(%rbp),%rax
movslq -0x1c(%rbp),%rcx
movzbl (%rax,%rcx,1),%eax
sar    $0x4,%eax
mov    %eax,-0x20(%rbp)
cmpl   $0x0,-0x20(%rbp)
jl     116c <byteToString+0x6c>
cmpl   $0x9,-0x20(%rbp)
jg     116c <byteToString+0x6c>
mov    -0x20(%rbp),%eax
add    $0x30,%eax
mov    %al,%dl
mov    -0x18(%rbp),%rax
mov    -0x1c(%rbp),%ecx
shl    $0x1,%ecx
movslq %ecx,%rcx
mov    %dl,(%rax,%rcx,1)
jmp    11b6 <byteToString+0xb6>
cmpl   $0xa,-0x20(%rbp)
jl     11a0 <byteToString+0xa0>
cmpl   $0xf,-0x20(%rbp)
jg     11a0 <byteToString+0xa0>
mov    -0x20(%rbp),%eax
sub    $0xa,%eax
add    $0x41,%eax
mov    %al,%dl
mov    -0x18(%rbp),%rax
mov    -0x1c(%rbp),%ecx
shl    $0x1,%ecx
movslq %ecx,%rcx
mov    %dl,(%rax,%rcx,1)
jmp    11b1 <byteToString+0xb1>
mov    -0x18(%rbp),%rax
mov    -0x1c(%rbp),%ecx
shl    $0x1,%ecx
movslq %ecx,%rcx
movb   $0x46,(%rax,%rcx,1)
jmp    11b6 <byteToString+0xb6>
mov    -0x8(%rbp),%rax
movslq -0x1c(%rbp),%rcx
movzbl (%rax,%rcx,1),%eax
and    $0xf,%eax
mov    %eax,-0x20(%rbp)
cmpl   $0x0,-0x20(%rbp)
jl     11fc <byteToString+0xfc>
cmpl   $0x9,-0x20(%rbp)
jg     11fc <byteToString+0xfc>
mov    -0x20(%rbp),%eax
add    $0x30,%eax
mov    %al,%dl
mov    -0x18(%rbp),%rax
mov    -0x1c(%rbp),%ecx
shl    $0x1,%ecx
add    $0x1,%ecx
movslq %ecx,%rcx
mov    %dl,(%rax,%rcx,1)
jmp    124c <byteToString+0x14c>
cmpl   $0xa,-0x20(%rbp)
jl     1233 <byteToString+0x133>
cmpl   $0xf,-0x20(%rbp)
jg     1233 <byteToString+0x133>
mov    -0x20(%rbp),%eax
sub    $0xa,%eax
add    $0x41,%eax
mov    %al,%dl
mov    -0x18(%rbp),%rax
mov    -0x1c(%rbp),%ecx
shl    $0x1,%ecx
add    $0x1,%ecx
movslq %ecx,%rcx
mov    %dl,(%rax,%rcx,1)
jmp    1247 <byteToString+0x147>
mov    -0x18(%rbp),%rax
mov    -0x1c(%rbp),%ecx
shl    $0x1,%ecx
add    $0x1,%ecx
movslq %ecx,%rcx
movb   $0x46,(%rax,%rcx,1)
jmp    124c <byteToString+0x14c>
jmp    1251 <byteToString+0x151>
mov    -0x1c(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x1c(%rbp)
jmp    111d <byteToString+0x1d>
mov    -0x18(%rbp),%rax
mov    -0x1c(%rbp),%ecx
shl    $0x1,%ecx
movslq %ecx,%rcx
movb   $0x0,(%rax,%rcx,1)
pop    %rbp
ret

x86 assembly (clang, -O2):
<byteToString>:
test   %esi,%esi
jle    1114 <byteToString+0x14>
mov    %esi,%r8d
cmp    $0x8,%esi
jae    111b <byteToString+0x1b>
xor    %r9d,%r9d
jmp    11f0 <byteToString+0xf0>
xor    %esi,%esi
movb   $0x0,(%rdx,%rsi,1)
ret
lea    (%rdi,%r8,1),%rax
cmp    %rdx,%rax
jbe    1135 <byteToString+0x35>
lea    (%rdx,%r8,2),%rax
cmp    %rdi,%rax
jbe    1135 <byteToString+0x35>
xor    %r9d,%r9d
jmp    11f0 <byteToString+0xf0>
mov    %r8d,%r9d
and    $0xfffffff8,%r9d
xor    %eax,%eax
movdqa 0xeb9(%rip),%xmm8
movdqa 0xec0(%rip),%xmm9
movdqa 0xec8(%rip),%xmm2
movdqa 0xed0(%rip),%xmm3
movdqa 0xed8(%rip),%xmm4
movdqa 0xee0(%rip),%xmm5
movq   (%rdi,%rax,1),%xmm6
movdqa %xmm6,%xmm7
psrlw  $0x4,%xmm7
pand   %xmm8,%xmm7
movdqa %xmm6,%xmm0
pmaxub %xmm9,%xmm0
pcmpeqb %xmm6,%xmm0
movdqa %xmm7,%xmm1
paddb  %xmm2,%xmm1
por    %xmm3,%xmm7
pand   %xmm0,%xmm1
pandn  %xmm7,%xmm0
por    %xmm1,%xmm0
pand   %xmm4,%xmm6
movdqa %xmm6,%xmm1
pmaxub %xmm5,%xmm1
pcmpeqb %xmm6,%xmm1
movdqa %xmm6,%xmm7
por    %xmm3,%xmm7
paddb  %xmm2,%xmm6
pand   %xmm1,%xmm6
pandn  %xmm7,%xmm1
por    %xmm6,%xmm1
punpcklbw %xmm1,%xmm0
movdqu %xmm0,(%rdx,%rax,2)
add    $0x8,%rax
cmp    %rax,%r9
jne    1170 <byteToString+0x70>
cmp    %r8,%r9
je     1239 <byteToString+0x139>
nopw   0x0(%rax,%rax,1)
movzbl (%rdi,%r9,1),%eax
mov    %eax,%ecx
shr    $0x4,%cl
lea    0x37(%rcx),%r10d
or     $0x30,%cl
cmp    $0xa0,%al
movzbl %cl,%eax
movzbl %r10b,%ecx
cmovb  %eax,%ecx
mov    %cl,(%rdx,%r9,2)
movzbl (%rdi,%r9,1),%eax
and    $0xf,%al
lea    0x30(%rax),%r10d
lea    0x37(%rax),%ecx
cmp    $0xa,%al
movzbl %r10b,%eax
movzbl %cl,%ecx
cmovb  %eax,%ecx
mov    %cl,0x1(%rdx,%r9,2)
add    $0x1,%r9
cmp    %r9,%r8
jne    11f0 <byteToString+0xf0>
add    %esi,%esi
movb   $0x0,(%rdx,%rsi,1)
ret

LLVM IR (-O0):
define void @byteToString(i8* %0, i32 %1, i8* %2) {
%4 = alloca i8*
%5 = alloca i32
%6 = alloca i8*
%7 = alloca i32
%8 = alloca i32
store i8* %0, i8** %4
store i32 %1, i32* %5
store i8* %2, i8** %6
store i32 0, i32* %7
store i32 0, i32* %7
br label %9
9: ; preds = %107, %3
%10 = load i32, i32* %7
%11 = load i32, i32* %5
%12 = icmp slt i32 %10, %11
br i1 %12, label %13, label %110
13: ; preds = %9
%14 = load i8*, i8** %4
%15 = load i32, i32* %7
%16 = sext i32 %15 to i64
%17 = getelementptr inbounds i8, i8* %14, i64 %16
%18 = load i8, i8* %17
%19 = zext i8 %18 to i32
%20 = ashr i32 %19, 4
store i32 %20, i32* %8
%21 = load i32, i32* %8
%22 = icmp sge i32 %21, 0
br i1 %22, label %23, label %35
23: ; preds = %13
%24 = load i32, i32* %8
%25 = icmp sle i32 %24, 9
br i1 %25, label %26, label %35
26: ; preds = %23
%27 = load i32, i32* %8
%28 = add nsw i32 %27, 48
%29 = trunc i32 %28 to i8
%30 = load i8*, i8** %6
%31 = load i32, i32* %7
%32 = mul nsw i32 %31, 2
%33 = sext i32 %32 to i64
%34 = getelementptr inbounds i8, i8* %30, i64 %33
store i8 %29, i8* %34
br label %58
35: ; preds = %23, %13
%36 = load i32, i32* %8
%37 = icmp sge i32 %36, 10
br i1 %37, label %38, label %51
38: ; preds = %35
%39 = load i32, i32* %8
%40 = icmp sle i32 %39, 15
br i1 %40, label %41, label %51
41: ; preds = %38
%42 = load i32, i32* %8
%43 = sub nsw i32 %42, 10
%44 = add nsw i32 %43, 65
%45 = trunc i32 %44 to i8
%46 = load i8*, i8** %6
%47 = load i32, i32* %7
%48 = mul nsw i32 %47, 2
%49 = sext i32 %48 to i64
%50 = getelementptr inbounds i8, i8* %46, i64 %49
store i8 %45, i8* %50
br label %57
51: ; preds = %38, %35
%52 = load i8*, i8** %6
%53 = load i32, i32* %7
%54 = mul nsw i32 %53, 2
%55 = sext i32 %54 to i64
%56 = getelementptr inbounds i8, i8* %52, i64 %55
store i8 70, i8* %56
br label %57
57: ; preds = %51, %41
br label %58
58: ; preds = %57, %26
%59 = load i8*, i8** %4
%60 = load i32, i32* %7
%61 = sext i32 %60 to i64
%62 = getelementptr inbounds i8, i8* %59, i64 %61
%63 = load i8, i8* %62
%64 = zext i8 %63 to i32
%65 = and i32 %64, 15
store i32 %65, i32* %8
%66 = load i32, i32* %8
%67 = icmp sge i32 %66, 0
br i1 %67, label %68, label %81
68: ; preds = %58
%69 = load i32, i32* %8
%70 = icmp sle i32 %69, 9
br i1 %70, label %71, label %81
71: ; preds = %68
%72 = load i32, i32* %8
%73 = add nsw i32 %72, 48
%74 = trunc i32 %73 to i8
%75 = load i8*, i8** %6
%76 = load i32, i32* %7
%77 = mul nsw i32 %76, 2
%78 = add nsw i32 %77, 1
%79 = sext i32 %78 to i64
%80 = getelementptr inbounds i8, i8* %75, i64 %79
store i8 %74, i8* %80
br label %106
81: ; preds = %68, %58
%82 = load i32, i32* %8
%83 = icmp sge i32 %82, 10
br i1 %83, label %84, label %98
84: ; preds = %81
%85 = load i32, i32* %8
%86 = icmp sle i32 %85, 15
br i1 %86, label %87, label %98
87: ; preds = %84
%88 = load i32, i32* %8
%89 = sub nsw i32 %88, 10
%90 = add nsw i32 %89, 65
%91 = trunc i32 %90 to i8
%92 = load i8*, i8** %6
%93 = load i32, i32* %7
%94 = mul nsw i32 %93, 2
%95 = add nsw i32 %94, 1
%96 = sext i32 %95 to i64
%97 = getelementptr inbounds i8, i8* %92, i64 %96
store i8 %91, i8* %97
br label %105
98: ; preds = %84, %81
%99 = load i8*, i8** %6
%100 = load i32, i32* %7
%101 = mul nsw i32 %100, 2
%102 = add nsw i32 %101, 1
%103 = sext i32 %102 to i64
%104 = getelementptr inbounds i8, i8* %99, i64 %103
store i8 70, i8* %104
br label %105
105: ; preds = %98, %87
br label %106
106: ; preds = %105, %71
br label %107
107: ; preds = %106
%108 = load i32, i32* %7
%109 = add nsw i32 %108, 1
store i32 %109, i32* %7
br label %9
110: ; preds = %9
%111 = load i8*, i8** %6
%112 = load i32, i32* %7
%113 = mul nsw i32 %112, 2
%114 = sext i32 %113 to i64
%115 = getelementptr inbounds i8, i8* %111, i64 %114
store i8 0, i8* %115
ret void
}

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