void unhexify(char *src, int len, unsigned char *dest) {
  while (len--) {
    if (*src <= '9')
      *dest = (*src - '0');
    else
      *dest = 10 + ((*src - 'A') & 15);
    *dest = (*dest << 4);
    src++;
    if (*src <= '9')
      *dest += (*src - '0');
    else
      *dest += 10 + ((*src - 'A') & 15);
    src++;
    dest++;
  }
}


x86 assembly (clang, -O0):
<unhexify>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x8(%rbp)
mov    %esi,-0xc(%rbp)
mov    %rdx,-0x18(%rbp)
mov    -0xc(%rbp),%eax
mov    %eax,%ecx
add    $0xffffffff,%ecx
mov    %ecx,-0xc(%rbp)
cmp    $0x0,%eax
je     11e2 <unhexify+0xe2>
mov    -0x8(%rbp),%rax
movsbl (%rax),%eax
cmp    $0x39,%eax
jg     114a <unhexify+0x4a>
mov    -0x8(%rbp),%rax
movsbl (%rax),%eax
sub    $0x30,%eax
mov    %al,%cl
mov    -0x18(%rbp),%rax
mov    %cl,(%rax)
jmp    1162 <unhexify+0x62>
mov    -0x8(%rbp),%rax
movsbl (%rax),%eax
sub    $0x41,%eax
and    $0xf,%eax
add    $0xa,%eax
mov    %al,%cl
mov    -0x18(%rbp),%rax
mov    %cl,(%rax)
mov    -0x18(%rbp),%rax
movzbl (%rax),%eax
shl    $0x4,%eax
mov    %al,%cl
mov    -0x18(%rbp),%rax
mov    %cl,(%rax)
mov    -0x8(%rbp),%rax
add    $0x1,%rax
mov    %rax,-0x8(%rbp)
mov    -0x8(%rbp),%rax
movsbl (%rax),%eax
cmp    $0x39,%eax
jg     11aa <unhexify+0xaa>
mov    -0x8(%rbp),%rax
movsbl (%rax),%edx
sub    $0x30,%edx
mov    -0x18(%rbp),%rax
movzbl (%rax),%ecx
add    %edx,%ecx
mov    %cl,(%rax)
jmp    11c5 <unhexify+0xc5>
mov    -0x8(%rbp),%rax
movsbl (%rax),%edx
sub    $0x41,%edx
and    $0xf,%edx
add    $0xa,%edx
mov    -0x18(%rbp),%rax
movzbl (%rax),%ecx
add    %edx,%ecx
mov    %cl,(%rax)
mov    -0x8(%rbp),%rax
add    $0x1,%rax
mov    %rax,-0x8(%rbp)
mov    -0x18(%rbp),%rax
add    $0x1,%rax
mov    %rax,-0x18(%rbp)
jmp    110f <unhexify+0xf>
pop    %rbp
ret

x86 assembly (clang, -O2):
<unhexify>:
push   %r14
push   %rbx
test   %esi,%esi
je     1187 <unhexify+0x87>
lea    -0x1(%rsi),%r8d
cmp    $0x7,%r8d
jb     112f <unhexify+0x2f>
lea    (%rdi,%r8,2),%rax
add    $0x2,%rax
cmp    %rdx,%rax
jbe    118b <unhexify+0x8b>
lea    (%r8,%rdx,1),%rax
add    $0x1,%rax
cmp    %rdi,%rax
jbe    118b <unhexify+0x8b>
mov    %rdx,%r11
mov    %rdi,%r14
mov    %esi,%edx
xor    %esi,%esi
nopl   0x0(%rax)
movzbl (%r14,%rsi,2),%ecx
xor    %edi,%edi
cmp    $0x3a,%cl
setge  %dil
lea    (%rdi,%rdi,8),%edi
add    %cl,%dil
shl    $0x4,%dil
mov    %dil,(%r11,%rsi,1)
movzbl 0x1(%r14,%rsi,2),%ecx
lea    -0x1(%rcx),%eax
and    $0xf,%al
add    $0xa,%al
lea    -0x30(%rcx),%ebx
cmp    $0x3a,%cl
movzbl %bl,%ecx
movzbl %al,%eax
cmovl  %ecx,%eax
add    %dil,%al
mov    %al,(%r11,%rsi,1)
add    $0x1,%rsi
cmp    %esi,%edx
jne    1140 <unhexify+0x40>
pop    %rbx
pop    %r14
ret
movabs $0x1fffffff0,%r9
cmp    $0xf,%r8d
jae    11a3 <unhexify+0xa3>
xor    %r10d,%r10d
jmp    1297 <unhexify+0x197>
lea    0x1(%r8),%rax
mov    %rax,%r10
and    %r9,%r10
xor    %ecx,%ecx
movdqa 0xe49(%rip),%xmm0
movdqa 0xe51(%rip),%xmm1
movdqa 0xe58(%rip),%xmm8
movdqa 0xe5f(%rip),%xmm9
pcmpeqd %xmm10,%xmm10
movdqa 0xe61(%rip),%xmm11
movdqa 0xe69(%rip),%xmm6
movdqa 0xe71(%rip),%xmm7
nop
movdqu (%rdi,%rcx,2),%xmm2
movdqu 0x10(%rdi,%rcx,2),%xmm3
movdqa %xmm3,%xmm4
pand   %xmm0,%xmm4
movdqa %xmm2,%xmm5
pand   %xmm0,%xmm5
packuswb %xmm4,%xmm5
psrlw  $0x8,%xmm3
psrlw  $0x8,%xmm2
packuswb %xmm3,%xmm2
movdqa %xmm1,%xmm3
pcmpgtb %xmm5,%xmm3
pandn  %xmm8,%xmm3
paddb  %xmm5,%xmm3
psllw  $0x4,%xmm3
pand   %xmm9,%xmm3
movdqa %xmm1,%xmm4
pcmpgtb %xmm2,%xmm4
movdqa %xmm2,%xmm5
paddb  %xmm10,%xmm5
pand   %xmm11,%xmm5
paddb  %xmm6,%xmm5
paddb  %xmm7,%xmm2
pand   %xmm4,%xmm2
pandn  %xmm5,%xmm4
por    %xmm2,%xmm4
paddb  %xmm3,%xmm4
movdqu %xmm4,(%rdx,%rcx,1)
add    $0x10,%rcx
cmp    %rcx,%r10
jne    11f0 <unhexify+0xf0>
cmp    %r10,%rax
je     1187 <unhexify+0x87>
test   $0x8,%al
jne    1297 <unhexify+0x197>
lea    (%rdi,%r10,2),%r14
sub    %r10d,%esi
add    %r10,%rdx
mov    %rdx,%r11
jmp    1135 <unhexify+0x35>
add    $0x1,%r8
add    $0x8,%r9
and    %r8,%r9
lea    (%rdx,%r9,1),%r11
sub    %r9d,%esi
lea    (%rdi,%r9,2),%r14
movdqa 0xd4a(%rip),%xmm8
movdqa 0xdb2(%rip),%xmm3
movdqa 0xdb9(%rip),%xmm9
movdqa 0xd60(%rip),%xmm10
pcmpeqd %xmm11,%xmm11
movdqa 0xdb3(%rip),%xmm5
movdqa 0xdbb(%rip),%xmm6
movdqa 0xdc3(%rip),%xmm7
nopl   (%rax)
movdqu (%rdi,%r10,2),%xmm4
movdqa %xmm4,%xmm2
pand   %xmm8,%xmm2
packuswb %xmm2,%xmm2
psrlw  $0x8,%xmm4
packuswb %xmm4,%xmm4
movdqa %xmm3,%xmm1
pcmpgtb %xmm2,%xmm1
pandn  %xmm9,%xmm1
paddb  %xmm2,%xmm1
psllw  $0x4,%xmm1
pand   %xmm10,%xmm1
movdqa %xmm3,%xmm2
pcmpgtb %xmm4,%xmm2
movdqa %xmm4,%xmm0
paddb  %xmm11,%xmm0
pand   %xmm5,%xmm0
paddb  %xmm6,%xmm0
paddb  %xmm7,%xmm4
pand   %xmm2,%xmm4
pandn  %xmm0,%xmm2
por    %xmm4,%xmm2
paddb  %xmm1,%xmm2
movq   %xmm2,(%rdx,%r10,1)
add    $0x8,%r10
cmp    %r10,%r9
jne    12f0 <unhexify+0x1f0>
cmp    %r9,%r8
jne    1135 <unhexify+0x35>
jmp    1187 <unhexify+0x87>

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

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