int read_hex(char *str, unsigned long *val) {
  unsigned long local_val = 0, len = 0;
  for (;;) {
    if (*str >= '0' && *str <= '9') {
      local_val = (local_val * 16) + (*str - '0');
      len++;
    } else if (*str >= 'a' && *str <= 'f') {
      local_val = (local_val * 16) + (*str - 'a' + 10);
      len++;
    } else if (*str >= 'A' && *str <= 'F') {
      local_val = (local_val * 16) + (*str - 'A' + 10);
      len++;
    } else {
      *val = local_val;
      return len;
    }
    str++;
  }
}


x86 assembly (clang, -O0):
<read_hex>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x8(%rbp)
mov    %rsi,-0x10(%rbp)
movq   $0x0,-0x18(%rbp)
movq   $0x0,-0x20(%rbp)
mov    -0x8(%rbp),%rax
movsbl (%rax),%eax
cmp    $0x30,%eax
jl     1169 <read_hex+0x69>
mov    -0x8(%rbp),%rax
movsbl (%rax),%eax
cmp    $0x39,%eax
jg     1169 <read_hex+0x69>
mov    -0x18(%rbp),%rax
shl    $0x4,%rax
mov    -0x8(%rbp),%rcx
movsbl (%rcx),%ecx
sub    $0x30,%ecx
movslq %ecx,%rcx
add    %rcx,%rax
mov    %rax,-0x18(%rbp)
mov    -0x20(%rbp),%rax
add    $0x1,%rax
mov    %rax,-0x20(%rbp)
jmp    1224 <read_hex+0x124>
mov    -0x8(%rbp),%rax
movsbl (%rax),%eax
cmp    $0x61,%eax
jl     11b9 <read_hex+0xb9>
mov    -0x8(%rbp),%rax
movsbl (%rax),%eax
cmp    $0x66,%eax
jg     11b9 <read_hex+0xb9>
mov    -0x18(%rbp),%rax
shl    $0x4,%rax
mov    -0x8(%rbp),%rcx
movsbl (%rcx),%ecx
sub    $0x61,%ecx
add    $0xa,%ecx
movslq %ecx,%rcx
add    %rcx,%rax
mov    %rax,-0x18(%rbp)
mov    -0x20(%rbp),%rax
add    $0x1,%rax
mov    %rax,-0x20(%rbp)
jmp    121f <read_hex+0x11f>
mov    -0x8(%rbp),%rax
movsbl (%rax),%eax
cmp    $0x41,%eax
jl     1209 <read_hex+0x109>
mov    -0x8(%rbp),%rax
movsbl (%rax),%eax
cmp    $0x46,%eax
jg     1209 <read_hex+0x109>
mov    -0x18(%rbp),%rax
shl    $0x4,%rax
mov    -0x8(%rbp),%rcx
movsbl (%rcx),%ecx
sub    $0x41,%ecx
add    $0xa,%ecx
movslq %ecx,%rcx
add    %rcx,%rax
mov    %rax,-0x18(%rbp)
mov    -0x20(%rbp),%rax
add    $0x1,%rax
mov    %rax,-0x20(%rbp)
jmp    121a <read_hex+0x11a>
mov    -0x18(%rbp),%rcx
mov    -0x10(%rbp),%rax
mov    %rcx,(%rax)
mov    -0x20(%rbp),%rax
pop    %rbp
ret
jmp    121f <read_hex+0x11f>
jmp    1224 <read_hex+0x124>
mov    -0x8(%rbp),%rax
add    $0x1,%rax
mov    %rax,-0x8(%rbp)
jmp    111c <read_hex+0x1c>

x86 assembly (clang, -O2):
<read_hex>:
mov    $0xffffffa9,%eax
xor    %r10d,%r10d
lea    0x27(%rax),%r9
lea    0x20(%rax),%r8
xor    %eax,%eax
jmp    112e <read_hex+0x2e>
cs nopw 0x0(%rax,%rax,1)
xchg   %ax,%ax
shl    $0x4,%r10
add    %r11d,%ecx
add    %rcx,%r10
add    $0x1,%rax
movsbq (%rdi,%rax,1),%r11
lea    -0x30(%r11),%edx
mov    %r9,%rcx
cmp    $0xa,%dl
jb     1120 <read_hex+0x20>
lea    -0x61(%r11),%edx
mov    $0xffffffa9,%ecx
cmp    $0x6,%dl
jb     1120 <read_hex+0x20>
lea    -0x41(%r11),%edx
mov    %r8,%rcx
cmp    $0x6,%dl
jb     1120 <read_hex+0x20>
mov    %r10,(%rsi)
ret

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

LLVM IR (-O2):
define i32 @read_hex(i8* nocapture %0, i64* nocapture writeonly %1) {
br label %3
3: ; preds = %19, %2
%4 = phi i8* [ %0, %2 ], [ %26, %19 ]
%5 = phi i64 [ 0, %2 ], [ %24, %19 ]
%6 = phi i64 [ 0, %2 ], [ %25, %19 ]
%7 = load i8, i8* %4
%8 = sext i8 %7 to i64
%9 = add i8 %7, -48
%10 = icmp ult i8 %9, 10
br i1 %10, label %19, label %11
11: ; preds = %3
%12 = add i8 %7, -97
%13 = icmp ult i8 %12, 6
br i1 %13, label %19, label %14
14: ; preds = %11
%15 = add i8 %7, -65
%16 = icmp ult i8 %15, 6
br i1 %16, label %19, label %17
17: ; preds = %14
store i64 %5, i64* %1
%18 = trunc i64 %6 to i32
ret i32 %18
19: ; preds = %14, %11, %3
%20 = phi i64 [ 4294967248, %3 ], [ 4294967209, %11 ], [ 4294967241, %14 ]
%21 = shl i64 %5, 4
%22 = add nsw i64 %20, %8
%23 = and i64 %22, 4294967295
%24 = add i64 %23, %21
%25 = add i64 %6, 1
%26 = getelementptr inbounds i8, i8* %4, i64 1
br label %3
}