unsigned char hex_ascii_to_bin(unsigned char c) {
  switch (c) {
  case '0' ... '9':
    return c - '0';
  case 'a' ... 'f':
    return c - 'a' + 10;
  case 'A' ... 'F':
    return c - 'A' + 10;
  }
  return '\0';
}


x86 assembly (clang, -O0):
<hex_ascii_to_bin>:
push   %rbp
mov    %rsp,%rbp
mov    %dil,%al
mov    %al,-0x2(%rbp)
movzbl -0x2(%rbp),%eax
mov    %eax,-0x8(%rbp)
add    $0xffffffd0,%eax
sub    $0xa,%eax
jb     114a <hex_ascii_to_bin+0x4a>
jmp    1122 <hex_ascii_to_bin+0x22>
mov    -0x8(%rbp),%eax
add    $0xffffffbf,%eax
sub    $0x6,%eax
jb     116b <hex_ascii_to_bin+0x6b>
jmp    1136 <hex_ascii_to_bin+0x36>
mov    -0x8(%rbp),%eax
add    $0xffffff9f,%eax
sub    $0x6,%eax
jb     1159 <hex_ascii_to_bin+0x59>
jmp    117d <hex_ascii_to_bin+0x7d>
movzbl -0x2(%rbp),%eax
sub    $0x30,%eax
mov    %al,-0x1(%rbp)
jmp    1181 <hex_ascii_to_bin+0x81>
movzbl -0x2(%rbp),%eax
sub    $0x61,%eax
add    $0xa,%eax
mov    %al,-0x1(%rbp)
jmp    1181 <hex_ascii_to_bin+0x81>
movzbl -0x2(%rbp),%eax
sub    $0x41,%eax
add    $0xa,%eax
mov    %al,-0x1(%rbp)
jmp    1181 <hex_ascii_to_bin+0x81>
movb   $0x0,-0x1(%rbp)
movzbl -0x1(%rbp),%eax
pop    %rbp
ret

x86 assembly (clang, -O2):
<hex_ascii_to_bin>:
add    $0xd0,%dil
cmp    $0x36,%dil
ja     1119 <hex_ascii_to_bin+0x19>
movsbq %dil,%rax
lea    0xeeb(%rip),%rcx
mov    (%rax,%rcx,1),%al
ret
xor    %eax,%eax
ret

LLVM IR (-O0):
define zeroext i8 @hex_ascii_to_bin(i8 zeroext %0) {
%2 = alloca i8
%3 = alloca i8
store i8 %0, i8* %3
%4 = load i8, i8* %3
%5 = zext i8 %4 to i32
switch i32 %5, label %23 [
i32 48, label %6
i32 49, label %6
i32 50, label %6
i32 51, label %6
i32 52, label %6
i32 53, label %6
i32 54, label %6
i32 55, label %6
i32 56, label %6
i32 57, label %6
i32 97, label %11
i32 98, label %11
i32 99, label %11
i32 100, label %11
i32 101, label %11
i32 102, label %11
i32 65, label %17
i32 66, label %17
i32 67, label %17
i32 68, label %17
i32 69, label %17
i32 70, label %17
]
6: ; preds = %1, %1, %1, %1, %1, %1, %1, %1, %1, %1
%7 = load i8, i8* %3
%8 = zext i8 %7 to i32
%9 = sub nsw i32 %8, 48
%10 = trunc i32 %9 to i8
store i8 %10, i8* %2
br label %24
11: ; preds = %1, %1, %1, %1, %1, %1
%12 = load i8, i8* %3
%13 = zext i8 %12 to i32
%14 = sub nsw i32 %13, 97
%15 = add nsw i32 %14, 10
%16 = trunc i32 %15 to i8
store i8 %16, i8* %2
br label %24
17: ; preds = %1, %1, %1, %1, %1, %1
%18 = load i8, i8* %3
%19 = zext i8 %18 to i32
%20 = sub nsw i32 %19, 65
%21 = add nsw i32 %20, 10
%22 = trunc i32 %21 to i8
store i8 %22, i8* %2
br label %24
23: ; preds = %1
store i8 0, i8* %2
br label %24
24: ; preds = %23, %17, %11, %6
%25 = load i8, i8* %2
ret i8 %25
}

LLVM IR (-O2):
@switch.table.hex_ascii_to_bin = [55 x i8] c"\00\01\02\03\04\05\06\07\08\09\00\00\00\00\00\00\00\0A\0B\0C\0D\0E\0F\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\0A\0B\0C\0D\0E\0F"
define zeroext i8 @hex_ascii_to_bin(i8 zeroext %0) {
%2 = add i8 %0, -48
%3 = icmp ult i8 %2, 55
br i1 %3, label %4, label %8
4: ; preds = %1
%5 = sext i8 %2 to i64
%6 = getelementptr inbounds [55 x i8], [55 x i8]* @switch.table.hex_ascii_to_bin, i64 0, i64 %5
%7 = load i8, i8* %6
br label %8
8: ; preds = %4, %1
%9 = phi i8 [ 0, %1 ], [ %7, %4 ]
ret i8 %9
}