int digit_from_char(char c, long base, char *digit) {
  if (c >= '0' && c <= '9') {
    *digit = c - '0';
    return (*digit < base);
  }
  if (base <= 10) {
    return 0;
  }
  char p;
  if (c >= 'A' && c <= 'Z') {
    p = c - 'A';
  } else if (c >= 'a' && c <= 'z') {
    p = c - 'a';
  } else {
    return 0;
  }
  *digit = p + 10;
  return (p < base);
}


x86 assembly (clang, -O0):
<digit_from_char>:
push   %rbp
mov    %rsp,%rbp
mov    %dil,%al
mov    %al,-0x5(%rbp)
mov    %rsi,-0x10(%rbp)
mov    %rdx,-0x18(%rbp)
movsbl -0x5(%rbp),%eax
cmp    $0x30,%eax
jl     1157 <digit_from_char+0x57>
movsbl -0x5(%rbp),%eax
cmp    $0x39,%eax
jg     1157 <digit_from_char+0x57>
movsbl -0x5(%rbp),%eax
sub    $0x30,%eax
mov    %al,%cl
mov    -0x18(%rbp),%rax
mov    %cl,(%rax)
mov    -0x18(%rbp),%rax
movsbq (%rax),%rax
cmp    -0x10(%rbp),%rax
setl   %al
and    $0x1,%al
movzbl %al,%eax
mov    %eax,-0x4(%rbp)
jmp    11f4 <digit_from_char+0xf4>
cmpq   $0xa,-0x10(%rbp)
jg     116e <digit_from_char+0x6e>
movl   $0x0,-0x4(%rbp)
jmp    11f4 <digit_from_char+0xf4>
movsbl -0x5(%rbp),%eax
cmp    $0x41,%eax
jl     1197 <digit_from_char+0x97>
movsbl -0x5(%rbp),%eax
cmp    $0x5a,%eax
jg     1197 <digit_from_char+0x97>
movsbl -0x5(%rbp),%eax
sub    $0x41,%eax
mov    %al,-0x19(%rbp)
jmp    11d1 <digit_from_char+0xd1>
movsbl -0x5(%rbp),%eax
cmp    $0x61,%eax
jl     11c0 <digit_from_char+0xc0>
movsbl -0x5(%rbp),%eax
cmp    $0x7a,%eax
jg     11c0 <digit_from_char+0xc0>
movsbl -0x5(%rbp),%eax
sub    $0x61,%eax
mov    %al,-0x19(%rbp)
jmp    11cc <digit_from_char+0xcc>
movl   $0x0,-0x4(%rbp)
jmp    11f4 <digit_from_char+0xf4>
jmp    11d1 <digit_from_char+0xd1>
movsbl -0x19(%rbp),%eax
add    $0xa,%eax
mov    %al,%cl
mov    -0x18(%rbp),%rax
mov    %cl,(%rax)
movsbq -0x19(%rbp),%rax
cmp    -0x10(%rbp),%rax
setl   %al
and    $0x1,%al
movzbl %al,%eax
mov    %eax,-0x4(%rbp)
mov    -0x4(%rbp),%eax
pop    %rbp
ret

x86 assembly (clang, -O2):
<digit_from_char>:
lea    -0x30(%rdi),%eax
cmp    $0x9,%al
ja     1116 <digit_from_char+0x16>
mov    %al,(%rdx)
movzbl %al,%eax
cmp    %rsi,%rax
setl   %al
movzbl %al,%eax
ret
cmp    $0xb,%rsi
jl     1141 <digit_from_char+0x41>
lea    -0x41(%rdi),%eax
cmp    $0x1a,%al
jb     112f <digit_from_char+0x2f>
add    $0x9f,%dil
mov    %edi,%eax
cmp    $0x19,%dil
ja     1141 <digit_from_char+0x41>
lea    0xa(%rax),%ecx
mov    %cl,(%rdx)
movzbl %al,%eax
cmp    %rsi,%rax
setb   %al
movzbl %al,%eax
ret
xor    %eax,%eax
movzbl %al,%eax
ret

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

LLVM IR (-O2):
define i32 @digit_from_char(i8 signext %0, i64 %1, i8* nocapture writeonly %2) {
%4 = add i8 %0, -48
%5 = icmp ult i8 %4, 10
br i1 %5, label %6, label %9
6: ; preds = %3
store i8 %4, i8* %2
%7 = zext i8 %4 to i64
%8 = icmp slt i64 %7, %1
br label %22
9: ; preds = %3
%10 = icmp slt i64 %1, 11
br i1 %10, label %22, label %11
11: ; preds = %9
%12 = add i8 %0, -65
%13 = icmp ult i8 %12, 26
br i1 %13, label %17, label %14
14: ; preds = %11
%15 = add i8 %0, -97
%16 = icmp ult i8 %15, 26
br i1 %16, label %17, label %22
17: ; preds = %14, %11
%18 = phi i8 [ %12, %11 ], [ %15, %14 ]
%19 = add nuw nsw i8 %18, 10
store i8 %19, i8* %2
%20 = zext i8 %18 to i64
%21 = icmp ult i64 %20, %1
br label %22
22: ; preds = %17, %14, %9, %6
%23 = phi i1 [ %8, %6 ], [ false, %9 ], [ %21, %17 ], [ false, %14 ]
%24 = zext i1 %23 to i32
ret i32 %24
}