void hex_to_byte(const char *str, unsigned char *bin, int len) {
  for (; len >= 2; len -= 2, str += 2)
    *(bin++) = (((str[0]) <= '9' ? (str[0]) & 0xF : ((str[0]) - 'a' + 10) & 0xF)
                << 4) |
               ((str[1]) <= '9' ? (str[1]) & 0xF : ((str[1]) - 'a' + 10) & 0xF);
}


x86 assembly (clang, -O0):
<hex_to_byte>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x8(%rbp)
mov    %rsi,-0x10(%rbp)
mov    %edx,-0x14(%rbp)
cmpl   $0x2,-0x14(%rbp)
jl     11c4 <hex_to_byte+0xc4>
mov    -0x8(%rbp),%rax
movsbl (%rax),%eax
cmp    $0x39,%eax
jg     113b <hex_to_byte+0x3b>
mov    -0x8(%rbp),%rax
movsbl (%rax),%eax
and    $0xf,%eax
mov    %eax,-0x18(%rbp)
jmp    114e <hex_to_byte+0x4e>
mov    -0x8(%rbp),%rax
movsbl (%rax),%eax
sub    $0x61,%eax
add    $0xa,%eax
and    $0xf,%eax
mov    %eax,-0x18(%rbp)
mov    -0x18(%rbp),%eax
shl    $0x4,%eax
mov    %eax,-0x1c(%rbp)
mov    -0x8(%rbp),%rax
movsbl 0x1(%rax),%eax
cmp    $0x39,%eax
jg     117b <hex_to_byte+0x7b>
mov    -0x8(%rbp),%rax
movsbl 0x1(%rax),%eax
and    $0xf,%eax
mov    %eax,-0x20(%rbp)
jmp    118f <hex_to_byte+0x8f>
mov    -0x8(%rbp),%rax
movsbl 0x1(%rax),%eax
sub    $0x61,%eax
add    $0xa,%eax
and    $0xf,%eax
mov    %eax,-0x20(%rbp)
mov    -0x1c(%rbp),%eax
mov    -0x20(%rbp),%ecx
or     %ecx,%eax
mov    %al,%cl
mov    -0x10(%rbp),%rax
mov    %rax,%rdx
add    $0x1,%rdx
mov    %rdx,-0x10(%rbp)
mov    %cl,(%rax)
mov    -0x14(%rbp),%eax
sub    $0x2,%eax
mov    %eax,-0x14(%rbp)
mov    -0x8(%rbp),%rax
add    $0x2,%rax
mov    %rax,-0x8(%rbp)
jmp    110f <hex_to_byte+0xf>
pop    %rbp
ret

x86 assembly (clang, -O2):
<hex_to_byte>:
cmp    $0x2,%edx
jl     11a6 <hex_to_byte+0xa6>
xor    %ecx,%ecx
mov    %edx,%r9d
sub    $0x3,%r9d
cmovb  %ecx,%r9d
add    $0x1,%r9d
cmp    $0xe,%r9d
jb     1146 <hex_to_byte+0x46>
mov    %edx,%eax
sub    $0x3,%eax
cmovb  %ecx,%eax
add    $0x1,%eax
shr    %eax
lea    (%rdi,%rax,2),%rcx
add    $0x2,%rcx
cmp    %rsi,%rcx
jbe    11a7 <hex_to_byte+0xa7>
add    %rsi,%rax
add    $0x1,%rax
cmp    %rdi,%rax
jbe    11a7 <hex_to_byte+0xa7>
mov    %rsi,%r8
mov    %rdi,%r11
add    $0x2,%edx
xor    %eax,%eax
cs nopw 0x0(%rax,%rax,1)
nopl   0x0(%rax,%rax,1)
movzbl (%r11,%rax,2),%ecx
mov    %ecx,%esi
shl    $0x4,%sil
lea    -0x70(%rsi),%edi
cmp    $0x3a,%cl
movzbl %sil,%ecx
movzbl %dil,%esi
cmovl  %ecx,%esi
movzbl 0x1(%r11,%rax,2),%ecx
lea    0x9(%rcx),%edi
cmp    $0x3a,%cl
movzbl %dil,%edi
cmovl  %ecx,%edi
and    $0xf,%dil
or     %sil,%dil
mov    %dil,(%r8,%rax,1)
add    $0xfffffffe,%edx
add    $0x1,%rax
cmp    $0x3,%edx
ja     1160 <hex_to_byte+0x60>
ret
xor    %r8d,%r8d
cmp    $0x1e,%r9d
jae    11b7 <hex_to_byte+0xb7>
xor    %eax,%eax
jmp    12ac <hex_to_byte+0x1ac>
shr    %r9d
add    $0x1,%r9d
mov    %r9d,%eax
and    $0xfffffff0,%eax
xor    %ecx,%ecx
movdqa 0xe32(%rip),%xmm0
movdqa 0xe3a(%rip),%xmm1
movdqa 0xe41(%rip),%xmm8
movdqa 0xe48(%rip),%xmm9
movdqa 0xe50(%rip),%xmm4
movdqa 0xe58(%rip),%xmm5
nopl   0x0(%rax,%rax,1)
movdqu (%rdi,%rcx,2),%xmm3
movdqu 0x10(%rdi,%rcx,2),%xmm7
movdqa %xmm7,%xmm2
pand   %xmm0,%xmm2
movdqa %xmm3,%xmm6
pand   %xmm0,%xmm6
packuswb %xmm2,%xmm6
psrlw  $0x8,%xmm7
psrlw  $0x8,%xmm3
packuswb %xmm7,%xmm3
movdqa %xmm1,%xmm2
pcmpgtb %xmm6,%xmm2
psllw  $0x4,%xmm6
pand   %xmm8,%xmm6
movdqa %xmm6,%xmm7
paddb  %xmm9,%xmm7
pand   %xmm2,%xmm6
pandn  %xmm7,%xmm2
por    %xmm6,%xmm2
movdqa %xmm1,%xmm6
pcmpgtb %xmm3,%xmm6
movdqa %xmm3,%xmm7
paddb  %xmm4,%xmm7
pand   %xmm6,%xmm3
pandn  %xmm7,%xmm6
por    %xmm3,%xmm6
pand   %xmm5,%xmm6
por    %xmm2,%xmm6
movdqu %xmm6,(%rsi,%rcx,1)
add    $0x10,%rcx
cmp    %rcx,%rax
jne    1200 <hex_to_byte+0x100>
cmp    %r9,%rax
je     11a6 <hex_to_byte+0xa6>
test   $0x8,%r9b
jne    12ac <hex_to_byte+0x1ac>
lea    (%rdi,%rax,2),%r11
add    %rax,%rsi
add    %eax,%eax
sub    %eax,%edx
mov    %rsi,%r8
jmp    114c <hex_to_byte+0x4c>
mov    %edx,%r9d
sub    $0x3,%r9d
cmovb  %r8d,%r9d
add    $0x1,%r9d
shr    %r9d
add    $0x1,%r9d
mov    %r9d,%r10d
and    $0xfffffff8,%r10d
sub    %r10d,%edx
sub    %r10d,%edx
lea    (%rsi,%r10,1),%r8
lea    (%rdi,%r10,2),%r11
movdqa 0xd20(%rip),%xmm8
movdqa 0xd78(%rip),%xmm0
movdqa 0xd2f(%rip),%xmm9
movdqa 0xd77(%rip),%xmm3
movdqa 0xd7f(%rip),%xmm4
movdqa 0xd87(%rip),%xmm5
nopl   0x0(%rax)
movdqu (%rdi,%rax,2),%xmm6
movdqa %xmm6,%xmm7
pand   %xmm8,%xmm7
packuswb %xmm7,%xmm7
psrlw  $0x8,%xmm6
packuswb %xmm6,%xmm6
movdqa %xmm0,%xmm1
pcmpgtb %xmm7,%xmm1
psllw  $0x4,%xmm7
pand   %xmm9,%xmm7
movdqa %xmm7,%xmm2
paddb  %xmm3,%xmm2
pand   %xmm1,%xmm7
pandn  %xmm2,%xmm1
por    %xmm7,%xmm1
movdqa %xmm0,%xmm2
pcmpgtb %xmm6,%xmm2
movdqa %xmm6,%xmm7
paddb  %xmm4,%xmm7
pand   %xmm2,%xmm6
pandn  %xmm7,%xmm2
por    %xmm6,%xmm2
pand   %xmm5,%xmm2
por    %xmm1,%xmm2
movq   %xmm2,(%rsi,%rax,1)
add    $0x8,%rax
cmp    %rax,%r10
jne    1310 <hex_to_byte+0x210>
cmp    %r9,%r10
jne    114c <hex_to_byte+0x4c>
jmp    11a6 <hex_to_byte+0xa6>

LLVM IR (-O0):
define void @hex_to_byte(i8* %0, i8* %1, i32 %2) {
%4 = alloca i8*
%5 = alloca i8*
%6 = alloca i32
store i8* %0, i8** %4
store i8* %1, i8** %5
store i32 %2, i32* %6
br label %7
7: ; preds = %58, %3
%8 = load i32, i32* %6
%9 = icmp sge i32 %8, 2
br i1 %9, label %10, label %63
10: ; preds = %7
%11 = load i8*, i8** %4
%12 = getelementptr inbounds i8, i8* %11, i64 0
%13 = load i8, i8* %12
%14 = sext i8 %13 to i32
%15 = icmp sle i32 %14, 57
br i1 %15, label %16, label %22
16: ; preds = %10
%17 = load i8*, i8** %4
%18 = getelementptr inbounds i8, i8* %17, i64 0
%19 = load i8, i8* %18
%20 = sext i8 %19 to i32
%21 = and i32 %20, 15
br label %30
22: ; preds = %10
%23 = load i8*, i8** %4
%24 = getelementptr inbounds i8, i8* %23, i64 0
%25 = load i8, i8* %24
%26 = sext i8 %25 to i32
%27 = sub nsw i32 %26, 97
%28 = add nsw i32 %27, 10
%29 = and i32 %28, 15
br label %30
30: ; preds = %22, %16
%31 = phi i32 [ %21, %16 ], [ %29, %22 ]
%32 = shl i32 %31, 4
%33 = load i8*, i8** %4
%34 = getelementptr inbounds i8, i8* %33, i64 1
%35 = load i8, i8* %34
%36 = sext i8 %35 to i32
%37 = icmp sle i32 %36, 57
br i1 %37, label %38, label %44
38: ; preds = %30
%39 = load i8*, i8** %4
%40 = getelementptr inbounds i8, i8* %39, i64 1
%41 = load i8, i8* %40
%42 = sext i8 %41 to i32
%43 = and i32 %42, 15
br label %52
44: ; preds = %30
%45 = load i8*, i8** %4
%46 = getelementptr inbounds i8, i8* %45, i64 1
%47 = load i8, i8* %46
%48 = sext i8 %47 to i32
%49 = sub nsw i32 %48, 97
%50 = add nsw i32 %49, 10
%51 = and i32 %50, 15
br label %52
52: ; preds = %44, %38
%53 = phi i32 [ %43, %38 ], [ %51, %44 ]
%54 = or i32 %32, %53
%55 = trunc i32 %54 to i8
%56 = load i8*, i8** %5
%57 = getelementptr inbounds i8, i8* %56, i32 1
store i8* %57, i8** %5
store i8 %55, i8* %56
br label %58
58: ; preds = %52
%59 = load i32, i32* %6
%60 = sub nsw i32 %59, 2
store i32 %60, i32* %6
%61 = load i8*, i8** %4
%62 = getelementptr inbounds i8, i8* %61, i64 2
store i8* %62, i8** %4
br label %7
63: ; preds = %7
ret void
}

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