void hex_encode(char _b[16], char *_h) {
  unsigned short i;
  unsigned char j;
  for (i = 0; i < 16; i++) {
    j = (_b[i] >> 4) & 0xf;
    if (j <= 9) {
      _h[i * 2] = (j + '0');
    } else {
      _h[i * 2] = (j + 'a' - 10);
    }
    j = _b[i] & 0xf;
    if (j <= 9) {
      _h[i * 2 + 1] = (j + '0');
    } else {
      _h[i * 2 + 1] = (j + 'a' - 10);
    }
  };
  _h[32] = '\0';
}


x86 assembly (clang, -O0):
<hex_encode>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x8(%rbp)
mov    %rsi,-0x10(%rbp)
movw   $0x0,-0x12(%rbp)
movzwl -0x12(%rbp),%eax
cmp    $0x10,%eax
jge    11f4 <hex_encode+0xf4>
mov    -0x8(%rbp),%rax
movzwl -0x12(%rbp),%ecx
movsbl (%rax,%rcx,1),%eax
sar    $0x4,%eax
and    $0xf,%eax
mov    %al,-0x13(%rbp)
movzbl -0x13(%rbp),%eax
cmp    $0x9,%eax
jg     1160 <hex_encode+0x60>
movzbl -0x13(%rbp),%eax
add    $0x30,%eax
mov    %al,%dl
mov    -0x10(%rbp),%rax
movzwl -0x12(%rbp),%ecx
shl    $0x1,%ecx
movslq %ecx,%rcx
mov    %dl,(%rax,%rcx,1)
jmp    117d <hex_encode+0x7d>
movzbl -0x13(%rbp),%eax
add    $0x61,%eax
sub    $0xa,%eax
mov    %al,%dl
mov    -0x10(%rbp),%rax
movzwl -0x12(%rbp),%ecx
shl    $0x1,%ecx
movslq %ecx,%rcx
mov    %dl,(%rax,%rcx,1)
mov    -0x8(%rbp),%rax
movzwl -0x12(%rbp),%ecx
movsbl (%rax,%rcx,1),%eax
and    $0xf,%eax
mov    %al,-0x13(%rbp)
movzbl -0x13(%rbp),%eax
cmp    $0x9,%eax
jg     11be <hex_encode+0xbe>
movzbl -0x13(%rbp),%eax
add    $0x30,%eax
mov    %al,%dl
mov    -0x10(%rbp),%rax
movzwl -0x12(%rbp),%ecx
shl    $0x1,%ecx
add    $0x1,%ecx
movslq %ecx,%rcx
mov    %dl,(%rax,%rcx,1)
jmp    11de <hex_encode+0xde>
movzbl -0x13(%rbp),%eax
add    $0x61,%eax
sub    $0xa,%eax
mov    %al,%dl
mov    -0x10(%rbp),%rax
movzwl -0x12(%rbp),%ecx
shl    $0x1,%ecx
add    $0x1,%ecx
movslq %ecx,%rcx
mov    %dl,(%rax,%rcx,1)
jmp    11e3 <hex_encode+0xe3>
mov    -0x12(%rbp),%ax
add    $0x1,%ax
mov    %ax,-0x12(%rbp)
jmp    1112 <hex_encode+0x12>
mov    -0x10(%rbp),%rax
movb   $0x0,0x20(%rax)
pop    %rbp
ret

x86 assembly (clang, -O2):
<hex_encode>:
lea    0x10(%rdi),%rax
cmp    %rsi,%rax
jbe    116e <hex_encode+0x6e>
lea    0x20(%rsi),%rax
cmp    %rdi,%rax
jbe    116e <hex_encode+0x6e>
xor    %eax,%eax
cs nopw 0x0(%rax,%rax,1)
xchg   %ax,%ax
movzbl (%rdi,%rax,1),%ecx
mov    %ecx,%edx
shr    $0x4,%dl
lea    0x57(%rdx),%r8d
or     $0x30,%dl
cmp    $0xa0,%cl
movzbl %dl,%ecx
movzbl %r8b,%edx
cmovb  %ecx,%edx
mov    %dl,(%rsi,%rax,2)
movzbl (%rdi,%rax,1),%ecx
and    $0xf,%cl
lea    0x30(%rcx),%r8d
lea    0x57(%rcx),%edx
cmp    $0xa,%cl
movzbl %r8b,%ecx
movzbl %dl,%edx
cmovb  %ecx,%edx
mov    %dl,0x1(%rsi,%rax,2)
add    $0x1,%rax
cmp    $0x10,%rax
jne    1120 <hex_encode+0x20>
movb   $0x0,0x20(%rsi)
ret
movq   (%rdi),%xmm3
movdqa %xmm3,%xmm6
psrlw  $0x4,%xmm6
movdqa 0xe7c(%rip),%xmm8
pand   %xmm8,%xmm6
movdqa 0xe7f(%rip),%xmm0
movdqa %xmm3,%xmm7
pmaxub %xmm0,%xmm7
pcmpeqb %xmm3,%xmm7
movdqa 0xe7b(%rip),%xmm2
movdqa %xmm6,%xmm5
paddb  %xmm2,%xmm5
movdqa 0xe7b(%rip),%xmm1
por    %xmm1,%xmm6
pand   %xmm7,%xmm5
pandn  %xmm6,%xmm7
por    %xmm5,%xmm7
movdqa 0xe72(%rip),%xmm9
pand   %xmm9,%xmm3
movdqa 0xe75(%rip),%xmm4
movdqa %xmm3,%xmm6
pmaxub %xmm4,%xmm6
pcmpeqb %xmm3,%xmm6
movdqa %xmm3,%xmm5
por    %xmm1,%xmm5
paddb  %xmm2,%xmm3
pand   %xmm6,%xmm3
pandn  %xmm5,%xmm6
por    %xmm3,%xmm6
punpcklbw %xmm6,%xmm7
movdqu %xmm7,(%rsi)
movq   0x8(%rdi),%xmm6
movdqa %xmm6,%xmm3
psrlw  $0x4,%xmm3
pand   %xmm8,%xmm3
pmaxub %xmm6,%xmm0
pcmpeqb %xmm6,%xmm0
movdqa %xmm3,%xmm5
paddb  %xmm2,%xmm5
por    %xmm1,%xmm3
pand   %xmm0,%xmm5
pandn  %xmm3,%xmm0
por    %xmm5,%xmm0
pand   %xmm9,%xmm6
pmaxub %xmm6,%xmm4
pcmpeqb %xmm6,%xmm4
por    %xmm6,%xmm1
paddb  %xmm2,%xmm6
pand   %xmm4,%xmm6
pandn  %xmm1,%xmm4
por    %xmm6,%xmm4
punpcklbw %xmm4,%xmm0
movdqu %xmm0,0x10(%rsi)
movb   $0x0,0x20(%rsi)
ret

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

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