double atof(const char *string) {
  float sign;
  float value;
  int c;
  while (*string <= ' ') {
    if (!*string) {
      return 0;
    }
    string++;
  }
  switch (*string) {
  case '+':
    string++;
    sign = 1;
    break;
  case '-':
    string++;
    sign = -1;
    break;
  default:
    sign = 1;
    break;
  }
  value = 0;
  c = string[0];
  if (c != '.') {
    do {
      c = *string++;
      if ((c < '0') || (c > '9')) {
        break;
      }
      c -= '0';
      value = value * 10 + c;
    } while (1);
  } else {
    string++;
  }
  if (c == '.') {
    double fraction;
    fraction = 0.1;
    do {
      c = *string++;
      if ((c < '0') || (c > '9')) {
        break;
      }
      c -= '0';
      value += c * fraction;
      fraction *= 0.1;
    } while (1);
  }
  return (value * sign);
}


x86 assembly (clang, -O0):
<atof>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x10(%rbp)
mov    -0x10(%rbp),%rax
movsbl (%rax),%eax
cmp    $0x20,%eax
jg     1143 <atof+0x43>
mov    -0x10(%rbp),%rax
cmpb   $0x0,(%rax)
jne    1132 <atof+0x32>
xorps  %xmm0,%xmm0
movsd  %xmm0,-0x8(%rbp)
jmp    12f7 <atof+0x1f7>
mov    -0x10(%rbp),%rax
add    $0x1,%rax
mov    %rax,-0x10(%rbp)
jmp    1108 <atof+0x8>
mov    -0x10(%rbp),%rax
movsbl (%rax),%eax
mov    %eax,-0x2c(%rbp)
sub    $0x2b,%eax
je     116c <atof+0x6c>
jmp    115b <atof+0x5b>
mov    -0x2c(%rbp),%eax
sub    $0x2d,%eax
je     118a <atof+0x8a>
jmp    11a8 <atof+0xa8>
mov    -0x10(%rbp),%rax
add    $0x1,%rax
mov    %rax,-0x10(%rbp)
movss  0xe84(%rip),%xmm0
movss  %xmm0,-0x14(%rbp)
jmp    11b5 <atof+0xb5>
mov    -0x10(%rbp),%rax
add    $0x1,%rax
mov    %rax,-0x10(%rbp)
movss  0xe62(%rip),%xmm0
movss  %xmm0,-0x14(%rbp)
jmp    11b5 <atof+0xb5>
movss  0xe54(%rip),%xmm0
movss  %xmm0,-0x14(%rbp)
xorps  %xmm0,%xmm0
movss  %xmm0,-0x18(%rbp)
mov    -0x10(%rbp),%rax
movsbl (%rax),%eax
mov    %eax,-0x1c(%rbp)
cmpl   $0x2e,-0x1c(%rbp)
je     1240 <atof+0x140>
jmp    11d6 <atof+0xd6>
mov    -0x10(%rbp),%rax
mov    %rax,%rcx
add    $0x1,%rcx
mov    %rcx,-0x10(%rbp)
movsbl (%rax),%eax
mov    %eax,-0x1c(%rbp)
cmpl   $0x30,-0x1c(%rbp)
jl     11ff <atof+0xff>
cmpl   $0x39,-0x1c(%rbp)
jle    1204 <atof+0x104>
jmp    123b <atof+0x13b>
mov    -0x1c(%rbp),%eax
sub    $0x30,%eax
mov    %eax,-0x1c(%rbp)
movss  -0x18(%rbp),%xmm0
cvtsi2ssl -0x1c(%rbp),%xmm1
movss  0xde9(%rip),%xmm2
mulss  %xmm2,%xmm0
addss  %xmm1,%xmm0
movss  %xmm0,-0x18(%rbp)
mov    $0x1,%al
test   $0x1,%al
jne    11d6 <atof+0xd6>
jmp    123b <atof+0x13b>
jmp    124c <atof+0x14c>
mov    -0x10(%rbp),%rax
add    $0x1,%rax
mov    %rax,-0x10(%rbp)
cmpl   $0x2e,-0x1c(%rbp)
jne    12e4 <atof+0x1e4>
movsd  0xdb2(%rip),%xmm0
movsd  %xmm0,-0x28(%rbp)
mov    -0x10(%rbp),%rax
mov    %rax,%rcx
add    $0x1,%rcx
mov    %rcx,-0x10(%rbp)
movsbl (%rax),%eax
mov    %eax,-0x1c(%rbp)
cmpl   $0x30,-0x1c(%rbp)
jl     128c <atof+0x18c>
cmpl   $0x39,-0x1c(%rbp)
jle    1291 <atof+0x191>
jmp    12df <atof+0x1df>
mov    -0x1c(%rbp),%eax
sub    $0x30,%eax
mov    %eax,-0x1c(%rbp)
cvtsi2sdl -0x1c(%rbp),%xmm0
movsd  -0x28(%rbp),%xmm2
movss  -0x18(%rbp),%xmm1
cvtss2sd %xmm1,%xmm1
mulsd  %xmm2,%xmm0
addsd  %xmm1,%xmm0
cvtsd2ss %xmm0,%xmm0
movss  %xmm0,-0x18(%rbp)
movsd  0xd4a(%rip),%xmm0
mulsd  -0x28(%rbp),%xmm0
movsd  %xmm0,-0x28(%rbp)
mov    $0x1,%al
test   $0x1,%al
jne    1263 <atof+0x163>
jmp    12df <atof+0x1df>
jmp    12e4 <atof+0x1e4>
movss  -0x18(%rbp),%xmm0
mulss  -0x14(%rbp),%xmm0
cvtss2sd %xmm0,%xmm0
movsd  %xmm0,-0x8(%rbp)
movsd  -0x8(%rbp),%xmm0
pop    %rbp
ret

x86 assembly (clang, -O2):
<atof>:
mov    (%rdi),%al
cmp    $0x20,%al
jg     1124 <atof+0x24>
cs nopw 0x0(%rax,%rax,1)
test   %al,%al
je     11fc <atof+0xfc>
movzbl 0x1(%rdi),%eax
add    $0x1,%rdi
cmp    $0x21,%al
jl     1110 <atof+0x10>
movss  0xed4(%rip),%xmm0
cmp    $0x2b,%al
je     113c <atof+0x3c>
cmp    $0x2d,%al
jne    1143 <atof+0x43>
movss  0xec8(%rip),%xmm0
mov    0x1(%rdi),%al
add    $0x1,%rdi
add    $0x1,%rdi
xorps  %xmm1,%xmm1
cmp    $0x2e,%al
je     1198 <atof+0x98>
lea    -0x3a(%rax),%ecx
xorps  %xmm1,%xmm1
cmp    $0xf6,%cl
jb     1194 <atof+0x94>
xorps  %xmm1,%xmm1
movss  0xea4(%rip),%xmm2
cs nopw 0x0(%rax,%rax,1)
xchg   %ax,%ax
movzbl %al,%eax
add    $0xffffffd0,%eax
xorps  %xmm3,%xmm3
cvtsi2ss %eax,%xmm3
mulss  %xmm2,%xmm1
addss  %xmm3,%xmm1
movzbl (%rdi),%eax
add    $0x1,%rdi
lea    -0x3a(%rax),%ecx
cmp    $0xf5,%cl
ja     1170 <atof+0x70>
cmp    $0x2e,%al
jne    11f3 <atof+0xf3>
mov    (%rdi),%al
lea    -0x3a(%rax),%ecx
cmp    $0xf6,%cl
jb     11f3 <atof+0xf3>
add    $0x1,%rdi
movsd  0xe62(%rip),%xmm2
movapd %xmm2,%xmm3
cs nopw 0x0(%rax,%rax,1)
nopl   0x0(%rax)
movzbl %al,%eax
add    $0xffffffd0,%eax
xorps  %xmm4,%xmm4
cvtsi2sd %eax,%xmm4
cvtss2sd %xmm1,%xmm1
mulsd  %xmm3,%xmm4
addsd  %xmm1,%xmm4
xorps  %xmm1,%xmm1
cvtsd2ss %xmm4,%xmm1
mulsd  %xmm2,%xmm3
movzbl (%rdi),%eax
lea    -0x3a(%rax),%ecx
add    $0x1,%rdi
cmp    $0xf5,%cl
ja     11c0 <atof+0xc0>
mulss  %xmm1,%xmm0
cvtss2sd %xmm0,%xmm0
ret
xorps  %xmm0,%xmm0
ret

LLVM IR (-O0):
define double @atof(i8* %0) {
%2 = alloca double
%3 = alloca i8*
%4 = alloca float
%5 = alloca float
%6 = alloca i32
%7 = alloca double
store i8* %0, i8** %3
br label %8
8: ; preds = %18, %1
%9 = load i8*, i8** %3
%10 = load i8, i8* %9
%11 = sext i8 %10 to i32
%12 = icmp sle i32 %11, 32
br i1 %12, label %13, label %21
13: ; preds = %8
%14 = load i8*, i8** %3
%15 = load i8, i8* %14
%16 = icmp ne i8 %15, 0
br i1 %16, label %18, label %17
17: ; preds = %13
store double 0.000000e+00, double* %2
br label %97
18: ; preds = %13
%19 = load i8*, i8** %3
%20 = getelementptr inbounds i8, i8* %19, i32 1
store i8* %20, i8** %3
br label %8
21: ; preds = %8
%22 = load i8*, i8** %3
%23 = load i8, i8* %22
%24 = sext i8 %23 to i32
switch i32 %24, label %31 [
i32 43, label %25
i32 45, label %28
]
25: ; preds = %21
%26 = load i8*, i8** %3
%27 = getelementptr inbounds i8, i8* %26, i32 1
store i8* %27, i8** %3
store float 1.000000e+00, float* %4
br label %32
28: ; preds = %21
%29 = load i8*, i8** %3
%30 = getelementptr inbounds i8, i8* %29, i32 1
store i8* %30, i8** %3
store float -1.000000e+00, float* %4
br label %32
31: ; preds = %21
store float 1.000000e+00, float* %4
br label %32
32: ; preds = %31, %28, %25
store float 0.000000e+00, float* %5
%33 = load i8*, i8** %3
%34 = getelementptr inbounds i8, i8* %33, i64 0
%35 = load i8, i8* %34
%36 = sext i8 %35 to i32
store i32 %36, i32* %6
%37 = load i32, i32* %6
%38 = icmp ne i32 %37, 46
br i1 %38, label %39, label %60
39: ; preds = %32
br label %40
40: ; preds = %58, %39
%41 = load i8*, i8** %3
%42 = getelementptr inbounds i8, i8* %41, i32 1
store i8* %42, i8** %3
%43 = load i8, i8* %41
%44 = sext i8 %43 to i32
store i32 %44, i32* %6
%45 = load i32, i32* %6
%46 = icmp slt i32 %45, 48
br i1 %46, label %50, label %47
47: ; preds = %40
%48 = load i32, i32* %6
%49 = icmp sgt i32 %48, 57
br i1 %49, label %50, label %51
50: ; preds = %47, %40
br label %59
51: ; preds = %47
%52 = load i32, i32* %6
%53 = sub nsw i32 %52, 48
store i32 %53, i32* %6
%54 = load float, float* %5
%55 = load i32, i32* %6
%56 = sitofp i32 %55 to float
%57 = call float @llvm.fmuladd.f32(float %54, float 1.000000e+01, float %56)
store float %57, float* %5
br label %58
58: ; preds = %51
br i1 true, label %40, label %59
59: ; preds = %58, %50
br label %63
60: ; preds = %32
%61 = load i8*, i8** %3
%62 = getelementptr inbounds i8, i8* %61, i32 1
store i8* %62, i8** %3
br label %63
63: ; preds = %60, %59
%64 = load i32, i32* %6
%65 = icmp eq i32 %64, 46
br i1 %65, label %66, label %92
66: ; preds = %63
store double 1.000000e-01, double* %7
br label %67
67: ; preds = %90, %66
%68 = load i8*, i8** %3
%69 = getelementptr inbounds i8, i8* %68, i32 1
store i8* %69, i8** %3
%70 = load i8, i8* %68
%71 = sext i8 %70 to i32
store i32 %71, i32* %6
%72 = load i32, i32* %6
%73 = icmp slt i32 %72, 48
br i1 %73, label %77, label %74
74: ; preds = %67
%75 = load i32, i32* %6
%76 = icmp sgt i32 %75, 57
br i1 %76, label %77, label %78
77: ; preds = %74, %67
br label %91
78: ; preds = %74
%79 = load i32, i32* %6
%80 = sub nsw i32 %79, 48
store i32 %80, i32* %6
%81 = load i32, i32* %6
%82 = sitofp i32 %81 to double
%83 = load double, double* %7
%84 = load float, float* %5
%85 = fpext float %84 to double
%86 = call double @llvm.fmuladd.f64(double %82, double %83, double %85)
%87 = fptrunc double %86 to float
store float %87, float* %5
%88 = load double, double* %7
%89 = fmul double %88, 1.000000e-01
store double %89, double* %7
br label %90
90: ; preds = %78
br i1 true, label %67, label %91
91: ; preds = %90, %77
br label %92
92: ; preds = %91, %63
%93 = load float, float* %5
%94 = load float, float* %4
%95 = fmul float %93, %94
%96 = fpext float %95 to double
store double %96, double* %2
br label %97
97: ; preds = %92, %17
%98 = load double, double* %2
ret double %98
}

LLVM IR (-O2):
define double @atof(i8* nocapture %0) {
%2 = load i8, i8* %0
%3 = icmp slt i8 %2, 33
br i1 %3, label %4, label %12
4: ; preds = %1, %8
%5 = phi i8 [ %10, %8 ], [ %2, %1 ]
%6 = phi i8* [ %9, %8 ], [ %0, %1 ]
%7 = icmp eq i8 %5, 0
br i1 %7, label %72, label %8
8: ; preds = %4
%9 = getelementptr inbounds i8, i8* %6, i64 1
%10 = load i8, i8* %9
%11 = icmp slt i8 %10, 33
br i1 %11, label %4, label %12
12: ; preds = %8, %1
%13 = phi i8* [ %0, %1 ], [ %9, %8 ]
%14 = phi i8 [ %2, %1 ], [ %10, %8 ]
switch i8 %14, label %20 [
i8 43, label %16
i8 45, label %15
]
15: ; preds = %12
br label %16
16: ; preds = %12, %15
%17 = phi float [ -1.000000e+00, %15 ], [ 1.000000e+00, %12 ]
%18 = getelementptr inbounds i8, i8* %13, i64 1
%19 = load i8, i8* %18
br label %20
20: ; preds = %16, %12
%21 = phi i8 [ %19, %16 ], [ %14, %12 ]
%22 = phi i8* [ %18, %16 ], [ %13, %12 ]
%23 = phi float [ %17, %16 ], [ 1.000000e+00, %12 ]
%24 = icmp eq i8 %21, 46
%25 = getelementptr inbounds i8, i8* %22, i64 1
br i1 %24, label %46, label %26
26: ; preds = %20
%27 = add i8 %21, -58
%28 = icmp ult i8 %27, -10
br i1 %28, label %41, label %29
29: ; preds = %26, %29
%30 = phi i8 [ %38, %29 ], [ %21, %26 ]
%31 = phi i8* [ %37, %29 ], [ %25, %26 ]
%32 = phi float [ %36, %29 ], [ 0.000000e+00, %26 ]
%33 = zext i8 %30 to i32
%34 = add nsw i32 %33, -48
%35 = sitofp i32 %34 to float
%36 = tail call float @llvm.fmuladd.f32(float %32, float 1.000000e+01, float %35)
%37 = getelementptr inbounds i8, i8* %31, i64 1
%38 = load i8, i8* %31
%39 = add i8 %38, -58
%40 = icmp ult i8 %39, -10
br i1 %40, label %41, label %29
41: ; preds = %29, %26
%42 = phi i8 [ %21, %26 ], [ %38, %29 ]
%43 = phi float [ 0.000000e+00, %26 ], [ %36, %29 ]
%44 = phi i8* [ %25, %26 ], [ %37, %29 ]
%45 = icmp eq i8 %42, 46
br i1 %45, label %46, label %68
46: ; preds = %20, %41
%47 = phi float [ %43, %41 ], [ 0.000000e+00, %20 ]
%48 = phi i8* [ %44, %41 ], [ %25, %20 ]
%49 = load i8, i8* %48
%50 = add i8 %49, -58
%51 = icmp ult i8 %50, -10
br i1 %51, label %68, label %52
52: ; preds = %46, %52
%53 = phi i8 [ %65, %52 ], [ %49, %46 ]
%54 = phi double [ %64, %52 ], [ 1.000000e-01, %46 ]
%55 = phi float [ %63, %52 ], [ %47, %46 ]
%56 = phi i8* [ %58, %52 ], [ %48, %46 ]
%57 = zext i8 %53 to i32
%58 = getelementptr inbounds i8, i8* %56, i64 1
%59 = add nsw i32 %57, -48
%60 = sitofp i32 %59 to double
%61 = fpext float %55 to double
%62 = tail call double @llvm.fmuladd.f64(double %60, double %54, double %61)
%63 = fptrunc double %62 to float
%64 = fmul double %54, 1.000000e-01
%65 = load i8, i8* %58
%66 = add i8 %65, -58
%67 = icmp ult i8 %66, -10
br i1 %67, label %68, label %52
68: ; preds = %52, %46, %41
%69 = phi float [ %43, %41 ], [ %47, %46 ], [ %63, %52 ]
%70 = fmul float %23, %69
%71 = fpext float %70 to double
br label %72
72: ; preds = %4, %68
%73 = phi double [ %71, %68 ], [ 0.000000e+00, %4 ]
ret double %73
}