void urldecode(char *p) {
  int i = 0;
  while (*(p + i)) {
    if ((*p = *(p + i)) == '%') {
      *p = *(p + i + 1) >= 'A' ? ((*(p + i + 1) & 0XDF) - 'A') + 10
                               : (*(p + i + 1) - '0');
      *p = (*p) * 16;
      *p += *(p + i + 2) >= 'A' ? ((*(p + i + 2) & 0XDF) - 'A') + 10
                                : (*(p + i + 2) - '0');
      i += 2;
    } else if (*(p + i) == '+') {
      *p = ' ';
    }
    p++;
  }
  *p = '\0';
}


x86 assembly (clang, -O0):
<urldecode>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x8(%rbp)
movl   $0x0,-0xc(%rbp)
mov    -0x8(%rbp),%rax
movslq -0xc(%rbp),%rcx
cmpb   $0x0,(%rax,%rcx,1)
je     123b <urldecode+0x13b>
mov    -0x8(%rbp),%rax
movslq -0xc(%rbp),%rcx
mov    (%rax,%rcx,1),%al
mov    -0x8(%rbp),%rcx
mov    %al,(%rcx)
movsbl %al,%eax
cmp    $0x25,%eax
jne    1209 <urldecode+0x109>
mov    -0x8(%rbp),%rax
movslq -0xc(%rbp),%rcx
movsbl 0x1(%rax,%rcx,1),%eax
cmp    $0x41,%eax
jl     1174 <urldecode+0x74>
mov    -0x8(%rbp),%rax
movslq -0xc(%rbp),%rcx
movsbl 0x1(%rax,%rcx,1),%eax
and    $0xdf,%eax
sub    $0x41,%eax
add    $0xa,%eax
mov    %eax,-0x10(%rbp)
jmp    1187 <urldecode+0x87>
mov    -0x8(%rbp),%rax
movslq -0xc(%rbp),%rcx
movsbl 0x1(%rax,%rcx,1),%eax
sub    $0x30,%eax
mov    %eax,-0x10(%rbp)
mov    -0x10(%rbp),%eax
mov    %al,%cl
mov    -0x8(%rbp),%rax
mov    %cl,(%rax)
mov    -0x8(%rbp),%rax
movsbl (%rax),%eax
shl    $0x4,%eax
mov    %al,%cl
mov    -0x8(%rbp),%rax
mov    %cl,(%rax)
mov    -0x8(%rbp),%rax
movslq -0xc(%rbp),%rcx
movsbl 0x2(%rax,%rcx,1),%eax
cmp    $0x41,%eax
jl     11da <urldecode+0xda>
mov    -0x8(%rbp),%rax
movslq -0xc(%rbp),%rcx
movsbl 0x2(%rax,%rcx,1),%eax
and    $0xdf,%eax
sub    $0x41,%eax
add    $0xa,%eax
mov    %eax,-0x14(%rbp)
jmp    11ed <urldecode+0xed>
mov    -0x8(%rbp),%rax
movslq -0xc(%rbp),%rcx
movsbl 0x2(%rax,%rcx,1),%eax
sub    $0x30,%eax
mov    %eax,-0x14(%rbp)
mov    -0x14(%rbp),%edx
mov    -0x8(%rbp),%rax
movsbl (%rax),%ecx
add    %edx,%ecx
mov    %cl,(%rax)
mov    -0xc(%rbp),%eax
add    $0x2,%eax
mov    %eax,-0xc(%rbp)
jmp    122a <urldecode+0x12a>
mov    -0x8(%rbp),%rax
movslq -0xc(%rbp),%rcx
movsbl (%rax,%rcx,1),%eax
cmp    $0x2b,%eax
jne    1225 <urldecode+0x125>
mov    -0x8(%rbp),%rax
movb   $0x20,(%rax)
jmp    122a <urldecode+0x12a>
mov    -0x8(%rbp),%rax
add    $0x1,%rax
mov    %rax,-0x8(%rbp)
jmp    110f <urldecode+0xf>
mov    -0x8(%rbp),%rax
movb   $0x0,(%rax)
pop    %rbp
ret

x86 assembly (clang, -O2):
<urldecode>:
mov    (%rdi),%dl
test   %dl,%dl
je     1180 <urldecode+0x80>
xor    %r8d,%r8d
mov    %rdi,%rcx
jmp    116b <urldecode+0x6b>
xchg   %ax,%ax
movzbl 0x1(%rdi),%edx
mov    %edx,%esi
shl    $0x4,%sil
lea    -0x70(%rsi),%eax
cmp    $0x41,%dl
movzbl %sil,%edx
movzbl %al,%esi
cmovl  %edx,%esi
mov    %sil,(%rcx)
movzbl 0x2(%rdi),%edx
mov    %edx,%eax
and    $0xdf,%al
add    $0xc9,%al
lea    -0x30(%rdx),%edi
cmp    $0x41,%dl
movzbl %dil,%edx
movzbl %al,%eax
cmovl  %edx,%eax
add    %sil,%al
mov    %al,(%rcx)
add    $0x2,%r8d
lea    0x1(%rcx),%rsi
movslq %r8d,%rax
lea    (%rcx,%rax,1),%rdi
add    $0x1,%rdi
movzbl 0x1(%rcx,%rax,1),%edx
mov    %rsi,%rcx
test   %dl,%dl
je     117c <urldecode+0x7c>
mov    %dl,(%rcx)
cmp    $0x25,%dl
je     1110 <urldecode+0x10>
cmpb   $0x2b,(%rdi)
jne    1150 <urldecode+0x50>
movb   $0x20,(%rcx)
jmp    1150 <urldecode+0x50>
movb   $0x0,(%rsi)
ret
movb   $0x0,(%rdi)
ret

LLVM IR (-O0):
define void @urldecode(i8* %0) {
%2 = alloca i8*
%3 = alloca i32
store i8* %0, i8** %2
store i32 0, i32* %3
br label %4
4: ; preds = %107, %1
%5 = load i8*, i8** %2
%6 = load i32, i32* %3
%7 = sext i32 %6 to i64
%8 = getelementptr inbounds i8, i8* %5, i64 %7
%9 = load i8, i8* %8
%10 = icmp ne i8 %9, 0
br i1 %10, label %11, label %110
11: ; preds = %4
%12 = load i8*, i8** %2
%13 = load i32, i32* %3
%14 = sext i32 %13 to i64
%15 = getelementptr inbounds i8, i8* %12, i64 %14
%16 = load i8, i8* %15
%17 = load i8*, i8** %2
store i8 %16, i8* %17
%18 = sext i8 %16 to i32
%19 = icmp eq i32 %18, 37
br i1 %19, label %20, label %96
20: ; preds = %11
%21 = load i8*, i8** %2
%22 = load i32, i32* %3
%23 = sext i32 %22 to i64
%24 = getelementptr inbounds i8, i8* %21, i64 %23
%25 = getelementptr inbounds i8, i8* %24, i64 1
%26 = load i8, i8* %25
%27 = sext i8 %26 to i32
%28 = icmp sge i32 %27, 65
br i1 %28, label %29, label %40
29: ; preds = %20
%30 = load i8*, i8** %2
%31 = load i32, i32* %3
%32 = sext i32 %31 to i64
%33 = getelementptr inbounds i8, i8* %30, i64 %32
%34 = getelementptr inbounds i8, i8* %33, i64 1
%35 = load i8, i8* %34
%36 = sext i8 %35 to i32
%37 = and i32 %36, 223
%38 = sub nsw i32 %37, 65
%39 = add nsw i32 %38, 10
br label %49
40: ; preds = %20
%41 = load i8*, i8** %2
%42 = load i32, i32* %3
%43 = sext i32 %42 to i64
%44 = getelementptr inbounds i8, i8* %41, i64 %43
%45 = getelementptr inbounds i8, i8* %44, i64 1
%46 = load i8, i8* %45
%47 = sext i8 %46 to i32
%48 = sub nsw i32 %47, 48
br label %49
49: ; preds = %40, %29
%50 = phi i32 [ %39, %29 ], [ %48, %40 ]
%51 = trunc i32 %50 to i8
%52 = load i8*, i8** %2
store i8 %51, i8* %52
%53 = load i8*, i8** %2
%54 = load i8, i8* %53
%55 = sext i8 %54 to i32
%56 = mul nsw i32 %55, 16
%57 = trunc i32 %56 to i8
%58 = load i8*, i8** %2
store i8 %57, i8* %58
%59 = load i8*, i8** %2
%60 = load i32, i32* %3
%61 = sext i32 %60 to i64
%62 = getelementptr inbounds i8, i8* %59, i64 %61
%63 = getelementptr inbounds i8, i8* %62, i64 2
%64 = load i8, i8* %63
%65 = sext i8 %64 to i32
%66 = icmp sge i32 %65, 65
br i1 %66, label %67, label %78
67: ; preds = %49
%68 = load i8*, i8** %2
%69 = load i32, i32* %3
%70 = sext i32 %69 to i64
%71 = getelementptr inbounds i8, i8* %68, i64 %70
%72 = getelementptr inbounds i8, i8* %71, i64 2
%73 = load i8, i8* %72
%74 = sext i8 %73 to i32
%75 = and i32 %74, 223
%76 = sub nsw i32 %75, 65
%77 = add nsw i32 %76, 10
br label %87
78: ; preds = %49
%79 = load i8*, i8** %2
%80 = load i32, i32* %3
%81 = sext i32 %80 to i64
%82 = getelementptr inbounds i8, i8* %79, i64 %81
%83 = getelementptr inbounds i8, i8* %82, i64 2
%84 = load i8, i8* %83
%85 = sext i8 %84 to i32
%86 = sub nsw i32 %85, 48
br label %87
87: ; preds = %78, %67
%88 = phi i32 [ %77, %67 ], [ %86, %78 ]
%89 = load i8*, i8** %2
%90 = load i8, i8* %89
%91 = sext i8 %90 to i32
%92 = add nsw i32 %91, %88
%93 = trunc i32 %92 to i8
store i8 %93, i8* %89
%94 = load i32, i32* %3
%95 = add nsw i32 %94, 2
store i32 %95, i32* %3
br label %107
96: ; preds = %11
%97 = load i8*, i8** %2
%98 = load i32, i32* %3
%99 = sext i32 %98 to i64
%100 = getelementptr inbounds i8, i8* %97, i64 %99
%101 = load i8, i8* %100
%102 = sext i8 %101 to i32
%103 = icmp eq i32 %102, 43
br i1 %103, label %104, label %106
104: ; preds = %96
%105 = load i8*, i8** %2
store i8 32, i8* %105
br label %106
106: ; preds = %104, %96
br label %107
107: ; preds = %106, %87
%108 = load i8*, i8** %2
%109 = getelementptr inbounds i8, i8* %108, i32 1
store i8* %109, i8** %2
br label %4
110: ; preds = %4
%111 = load i8*, i8** %2
store i8 0, i8* %111
ret void
}

LLVM IR (-O2):
define void @urldecode(i8* nocapture %0) {
%2 = load i8, i8* %0
%3 = icmp eq i8 %2, 0
br i1 %3, label %37, label %4
4: ; preds = %1, %30
%5 = phi i8 [ %35, %30 ], [ %2, %1 ]
%6 = phi i8* [ %34, %30 ], [ %0, %1 ]
%7 = phi i32 [ %31, %30 ], [ 0, %1 ]
%8 = phi i8* [ %32, %30 ], [ %0, %1 ]
store i8 %5, i8* %8
%9 = icmp eq i8 %5, 37
br i1 %9, label %10, label %26
10: ; preds = %4
%11 = getelementptr inbounds i8, i8* %6, i64 1
%12 = load i8, i8* %11
%13 = icmp sgt i8 %12, 64
%14 = shl i8 %12, 4
%15 = add i8 %14, -112
%16 = select i1 %13, i8 %15, i8 %14
store i8 %16, i8* %8
%17 = getelementptr inbounds i8, i8* %6, i64 2
%18 = load i8, i8* %17
%19 = icmp sgt i8 %18, 64
%20 = and i8 %18, -33
%21 = add i8 %20, -55
%22 = add i8 %18, -48
%23 = select i1 %19, i8 %21, i8 %22
%24 = add i8 %23, %16
store i8 %24, i8* %8
%25 = add nsw i32 %7, 2
br label %30
26: ; preds = %4
%27 = load i8, i8* %6
%28 = icmp eq i8 %27, 43
br i1 %28, label %29, label %30
29: ; preds = %26
store i8 32, i8* %8
br label %30
30: ; preds = %26, %29, %10
%31 = phi i32 [ %25, %10 ], [ %7, %29 ], [ %7, %26 ]
%32 = getelementptr inbounds i8, i8* %8, i64 1
%33 = sext i32 %31 to i64
%34 = getelementptr inbounds i8, i8* %32, i64 %33
%35 = load i8, i8* %34
%36 = icmp eq i8 %35, 0
br i1 %36, label %37, label %4
37: ; preds = %30, %1
%38 = phi i8* [ %0, %1 ], [ %32, %30 ]
store i8 0, i8* %38
ret void
}