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


x86 assembly (clang, -O0):
<cvt_hex>:
push   %rbp
mov    %rsp,%rbp
mov    %dx,%ax
mov    %rdi,-0x8(%rbp)
mov    %rsi,-0x10(%rbp)
mov    %ax,-0x12(%rbp)
movw   $0x0,-0x14(%rbp)
movzwl -0x14(%rbp),%eax
movzwl -0x12(%rbp),%ecx
cmp    %ecx,%eax
jge    11fe <cvt_hex+0xfe>
mov    -0x8(%rbp),%rax
movzwl -0x14(%rbp),%ecx
movzbl (%rax,%rcx,1),%eax
sar    $0x4,%eax
and    $0xf,%eax
mov    %al,-0x15(%rbp)
movzbl -0x15(%rbp),%eax
cmp    $0x9,%eax
jg     116a <cvt_hex+0x6a>
movzbl -0x15(%rbp),%eax
add    $0x30,%eax
mov    %al,%dl
mov    -0x10(%rbp),%rax
movzwl -0x14(%rbp),%ecx
shl    $0x1,%ecx
movslq %ecx,%rcx
mov    %dl,(%rax,%rcx,1)
jmp    1187 <cvt_hex+0x87>
movzbl -0x15(%rbp),%eax
add    $0x61,%eax
sub    $0xa,%eax
mov    %al,%dl
mov    -0x10(%rbp),%rax
movzwl -0x14(%rbp),%ecx
shl    $0x1,%ecx
movslq %ecx,%rcx
mov    %dl,(%rax,%rcx,1)
mov    -0x8(%rbp),%rax
movzwl -0x14(%rbp),%ecx
movzbl (%rax,%rcx,1),%eax
and    $0xf,%eax
mov    %al,-0x15(%rbp)
movzbl -0x15(%rbp),%eax
cmp    $0x9,%eax
jg     11c8 <cvt_hex+0xc8>
movzbl -0x15(%rbp),%eax
add    $0x30,%eax
mov    %al,%dl
mov    -0x10(%rbp),%rax
movzwl -0x14(%rbp),%ecx
shl    $0x1,%ecx
add    $0x1,%ecx
movslq %ecx,%rcx
mov    %dl,(%rax,%rcx,1)
jmp    11e8 <cvt_hex+0xe8>
movzbl -0x15(%rbp),%eax
add    $0x61,%eax
sub    $0xa,%eax
mov    %al,%dl
mov    -0x10(%rbp),%rax
movzwl -0x14(%rbp),%ecx
shl    $0x1,%ecx
add    $0x1,%ecx
movslq %ecx,%rcx
mov    %dl,(%rax,%rcx,1)
jmp    11ed <cvt_hex+0xed>
mov    -0x14(%rbp),%ax
add    $0x1,%ax
mov    %ax,-0x14(%rbp)
jmp    1119 <cvt_hex+0x19>
mov    -0x10(%rbp),%rax
movzwl -0x12(%rbp),%ecx
shl    $0x1,%ecx
movslq %ecx,%rcx
movb   $0x0,(%rax,%rcx,1)
pop    %rbp
ret

x86 assembly (clang, -O2):
<cvt_hex>:
test   %edx,%edx
je     1116 <cvt_hex+0x16>
movzwl %dx,%r8d
cmp    $0x8,%r8w
jae    111d <cvt_hex+0x1d>
xor    %ecx,%ecx
jmp    11f0 <cvt_hex+0xf0>
xor    %eax,%eax
movb   $0x0,(%rsi,%rax,1)
ret
lea    (%rdi,%r8,1),%rcx
cmp    %rsi,%rcx
jbe    1136 <cvt_hex+0x36>
lea    (%rsi,%r8,2),%rcx
cmp    %rdi,%rcx
jbe    1136 <cvt_hex+0x36>
xor    %ecx,%ecx
jmp    11f0 <cvt_hex+0xf0>
mov    %r8d,%ecx
and    $0xfffffff8,%ecx
xor    %edx,%edx
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,%rdx,1),%xmm0
movdqa %xmm0,%xmm7
psrlw  $0x4,%xmm7
pand   %xmm8,%xmm7
movdqa %xmm0,%xmm6
pmaxub %xmm9,%xmm6
pcmpeqb %xmm0,%xmm6
movdqa %xmm7,%xmm1
paddb  %xmm2,%xmm1
por    %xmm3,%xmm7
pand   %xmm6,%xmm1
pandn  %xmm7,%xmm6
por    %xmm1,%xmm6
pand   %xmm4,%xmm0
movdqa %xmm0,%xmm1
pmaxub %xmm5,%xmm1
pcmpeqb %xmm0,%xmm1
movdqa %xmm0,%xmm7
paddb  %xmm2,%xmm7
por    %xmm3,%xmm0
pand   %xmm1,%xmm7
pandn  %xmm0,%xmm1
por    %xmm7,%xmm1
punpcklbw %xmm1,%xmm6
movdqu %xmm6,(%rsi,%rdx,2)
add    $0x8,%rdx
cmp    %rdx,%rcx
jne    1170 <cvt_hex+0x70>
cmp    %r8,%rcx
je     1235 <cvt_hex+0x135>
nopw   0x0(%rax,%rax,1)
movzbl (%rdi,%rcx,1),%edx
mov    %edx,%eax
shr    $0x4,%al
lea    0x57(%rax),%r9d
or     $0x30,%al
cmp    $0xa0,%dl
movzbl %al,%eax
movzbl %r9b,%edx
cmovb  %eax,%edx
mov    %dl,(%rsi,%rcx,2)
movzbl (%rdi,%rcx,1),%eax
and    $0xf,%al
lea    0x57(%rax),%r9d
lea    0x30(%rax),%edx
cmp    $0xa,%al
movzbl %dl,%eax
movzbl %r9b,%edx
cmovb  %eax,%edx
mov    %dl,0x1(%rsi,%rcx,2)
add    $0x1,%rcx
cmp    %rcx,%r8
jne    11f0 <cvt_hex+0xf0>
lea    (%r8,%r8,1),%rax
movb   $0x0,(%rsi,%rax,1)
ret

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

LLVM IR (-O2):
define void @cvt_hex(i8* nocapture %0, i8* nocapture writeonly %1, i16 zeroext %2) {
%4 = icmp eq i16 %2, 0
br i1 %4, label %70, label %5
5: ; preds = %3
%6 = zext i16 %2 to i64
%7 = icmp ult i16 %2, 8
br i1 %7, label %44, label %8
8: ; preds = %5
%9 = shl nuw nsw i64 %6, 1
%10 = getelementptr i8, i8* %1, i64 %9
%11 = getelementptr i8, i8* %0, i64 %6
%12 = icmp ugt i8* %11, %1
%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, 65528
%17 = getelementptr inbounds i8, i8* %1, 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 87, i8 87, i8 87, i8 87, i8 87, i8 87, i8 87, i8 87>
%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 = add nuw nsw <8 x i8> %30, <i8 87, i8 87, i8 87, i8 87, i8 87, i8 87, i8 87, i8 87>
%33 = or <8 x i8> %30, <i8 48, i8 48, i8 48, i8 48, i8 48, i8 48, i8 48, i8 48>
%34 = select <8 x i1> %31, <8 x i8> %33, <8 x i8> %32
%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, 87
%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* %1, i64 %55
store i8 %54, i8* %56
%57 = load i8, i8* %48
%58 = and i8 %57, 15
%59 = icmp ult i8 %58, 10
%60 = add nuw nsw i8 %58, 87
%61 = or i8 %58, 48
%62 = select i1 %59, i8 %61, i8 %60
%63 = shl nuw nsw i64 %47, 1
%64 = or i64 %63, 1
%65 = getelementptr inbounds i8, i8* %1, 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 nuw nsw i64 %6, 1
br label %70
70: ; preds = %68, %3
%71 = phi i64 [ 0, %3 ], [ %69, %68 ]
%72 = getelementptr inbounds i8, i8* %1, i64 %71
store i8 0, i8* %72
ret void
}