void translit_text(char *s, int len, char from, char to) {
  char *p = s;
  while (--len > 0) {
    if (*p == from)
      *p = to;
    ++p;
  }
}


x86 assembly (clang, -O0):
<translit_text>:
push   %rbp
mov    %rsp,%rbp
mov    %cl,%al
mov    %dl,%cl
mov    %rdi,-0x8(%rbp)
mov    %esi,-0xc(%rbp)
mov    %cl,-0xd(%rbp)
mov    %al,-0xe(%rbp)
mov    -0x8(%rbp),%rax
mov    %rax,-0x18(%rbp)
mov    -0xc(%rbp),%eax
add    $0xffffffff,%eax
mov    %eax,-0xc(%rbp)
cmp    $0x0,%eax
jle    115c <translit_text+0x5c>
mov    -0x18(%rbp),%rax
movsbl (%rax),%eax
movsbl -0xd(%rbp),%ecx
cmp    %ecx,%eax
jne    114b <translit_text+0x4b>
mov    -0xe(%rbp),%cl
mov    -0x18(%rbp),%rax
mov    %cl,(%rax)
mov    -0x18(%rbp),%rax
add    $0x1,%rax
mov    %rax,-0x18(%rbp)
jmp    111d <translit_text+0x1d>
pop    %rbp
ret

x86 assembly (clang, -O2):
<translit_text>:
cmp    $0x2,%esi
jl     12a1 <translit_text+0x1a1>
xor    %eax,%eax
mov    %esi,%r8d
sub    $0x2,%r8d
cmovb  %eax,%r8d
cmp    $0xf,%r8d
jae    1124 <translit_text+0x24>
mov    %rdi,%r10
jmp    12a2 <translit_text+0x1a2>
add    $0x1,%r8
mov    %r8,%r9
and    $0xfffffffffffffff0,%r9
sub    %r9d,%esi
lea    (%rdi,%r9,1),%r10
movzbl %dl,%eax
movd   %eax,%xmm0
punpcklbw %xmm0,%xmm0
pshuflw $0x0,%xmm0,%xmm0
xor    %r11d,%r11d
jmp    115d <translit_text+0x5d>
nopl   0x0(%rax,%rax,1)
add    $0x10,%r11
cmp    %r11,%r9
je     129c <translit_text+0x19c>
movq   (%rdi,%r11,1),%xmm1
pcmpeqb %xmm0,%xmm1
movd   %xmm1,%eax
test   $0x1,%al
je     1173 <translit_text+0x73>
mov    %cl,(%rdi,%r11,1)
movdqa %xmm1,%xmm2
pslld  $0x8,%xmm2
movd   %xmm2,%eax
shr    $0x10,%eax
test   $0x1,%al
je     118c <translit_text+0x8c>
mov    %cl,0x1(%rdi,%r11,1)
pextrw $0x1,%xmm1,%eax
test   $0x1,%al
je     119a <translit_text+0x9a>
mov    %cl,0x2(%rdi,%r11,1)
movdqa %xmm1,%xmm2
psllq  $0x18,%xmm2
pextrw $0x3,%xmm2,%eax
test   $0x1,%al
je     11b1 <translit_text+0xb1>
mov    %cl,0x3(%rdi,%r11,1)
pextrw $0x2,%xmm1,%eax
test   $0x1,%al
je     11bf <translit_text+0xbf>
mov    %cl,0x4(%rdi,%r11,1)
movdqa %xmm1,%xmm2
pslldq $0x5,%xmm2
pextrw $0x5,%xmm2,%eax
test   $0x1,%al
je     11d6 <translit_text+0xd6>
mov    %cl,0x5(%rdi,%r11,1)
pextrw $0x3,%xmm1,%eax
test   $0x1,%al
je     11e4 <translit_text+0xe4>
mov    %cl,0x6(%rdi,%r11,1)
pslldq $0x7,%xmm1
pextrw $0x7,%xmm1,%eax
test   $0x1,%al
je     11f7 <translit_text+0xf7>
mov    %cl,0x7(%rdi,%r11,1)
movq   0x8(%rdi,%r11,1),%xmm1
pcmpeqb %xmm0,%xmm1
movd   %xmm1,%eax
test   $0x1,%al
je     120f <translit_text+0x10f>
mov    %cl,0x8(%rdi,%r11,1)
movdqa %xmm1,%xmm2
pslld  $0x8,%xmm2
movd   %xmm2,%eax
shr    $0x10,%eax
test   $0x1,%al
je     1228 <translit_text+0x128>
mov    %cl,0x9(%rdi,%r11,1)
pextrw $0x1,%xmm1,%eax
test   $0x1,%al
je     1236 <translit_text+0x136>
mov    %cl,0xa(%rdi,%r11,1)
movdqa %xmm1,%xmm2
psllq  $0x18,%xmm2
pextrw $0x3,%xmm2,%eax
test   $0x1,%al
je     124d <translit_text+0x14d>
mov    %cl,0xb(%rdi,%r11,1)
pextrw $0x2,%xmm1,%eax
test   $0x1,%al
je     125b <translit_text+0x15b>
mov    %cl,0xc(%rdi,%r11,1)
movdqa %xmm1,%xmm2
pslldq $0x5,%xmm2
pextrw $0x5,%xmm2,%eax
test   $0x1,%al
je     1272 <translit_text+0x172>
mov    %cl,0xd(%rdi,%r11,1)
pextrw $0x3,%xmm1,%eax
test   $0x1,%al
je     1280 <translit_text+0x180>
mov    %cl,0xe(%rdi,%r11,1)
pslldq $0x7,%xmm1
pextrw $0x7,%xmm1,%eax
test   $0x1,%al
je     1150 <translit_text+0x50>
mov    %cl,0xf(%rdi,%r11,1)
jmp    1150 <translit_text+0x50>
cmp    %r9,%r8
jne    12a2 <translit_text+0x1a2>
ret
add    $0x1,%esi
jmp    12bc <translit_text+0x1bc>
nopw   0x0(%rax,%rax,1)
add    $0x1,%r10
add    $0xffffffff,%esi
cmp    $0x2,%esi
jbe    12a1 <translit_text+0x1a1>
cmp    %dl,(%r10)
jne    12b0 <translit_text+0x1b0>
mov    %cl,(%r10)
jmp    12b0 <translit_text+0x1b0>

LLVM IR (-O0):
define void @translit_text(i8* %0, i32 %1, i8 signext %2, i8 signext %3) {
%5 = alloca i8*
%6 = alloca i32
%7 = alloca i8
%8 = alloca i8
%9 = alloca i8*
store i8* %0, i8** %5
store i32 %1, i32* %6
store i8 %2, i8* %7
store i8 %3, i8* %8
%10 = load i8*, i8** %5
store i8* %10, i8** %9
br label %11
11: ; preds = %25, %4
%12 = load i32, i32* %6
%13 = add nsw i32 %12, -1
store i32 %13, i32* %6
%14 = icmp sgt i32 %13, 0
br i1 %14, label %15, label %28
15: ; preds = %11
%16 = load i8*, i8** %9
%17 = load i8, i8* %16
%18 = sext i8 %17 to i32
%19 = load i8, i8* %7
%20 = sext i8 %19 to i32
%21 = icmp eq i32 %18, %20
br i1 %21, label %22, label %25
22: ; preds = %15
%23 = load i8, i8* %8
%24 = load i8*, i8** %9
store i8 %23, i8* %24
br label %25
25: ; preds = %22, %15
%26 = load i8*, i8** %9
%27 = getelementptr inbounds i8, i8* %26, i32 1
store i8* %27, i8** %9
br label %11
28: ; preds = %11
ret void
}

LLVM IR (-O2):
define void @translit_text(i8* nocapture %0, i32 %1, i8 signext %2, i8 signext %3) {
%5 = icmp sgt i32 %1, 1
br i1 %5, label %6, label %126
6: ; preds = %4
%7 = call i32 @llvm.umin.i32(i32 %1, i32 2)
%8 = sub i32 %1, %7
%9 = zext i32 %8 to i64
%10 = add nuw nsw i64 %9, 1
%11 = icmp ult i32 %8, 15
br i1 %11, label %113, label %12
12: ; preds = %6
%13 = and i64 %10, 8589934576
%14 = trunc i64 %13 to i32
%15 = sub i32 %1, %14
%16 = getelementptr i8, i8* %0, i64 %13
%17 = insertelement <8 x i8> poison, i8 %2, i64 0
%18 = shufflevector <8 x i8> %17, <8 x i8> poison, <8 x i32> zeroinitializer
%19 = insertelement <8 x i8> poison, i8 %2, i64 0
%20 = shufflevector <8 x i8> %19, <8 x i8> poison, <8 x i32> zeroinitializer
br label %21
21: ; preds = %108, %12
%22 = phi i64 [ 0, %12 ], [ %109, %108 ]
%23 = getelementptr i8, i8* %0, i64 %22
%24 = bitcast i8* %23 to <8 x i8>*
%25 = load <8 x i8>, <8 x i8>* %24
%26 = getelementptr i8, i8* %23, i64 8
%27 = bitcast i8* %26 to <8 x i8>*
%28 = load <8 x i8>, <8 x i8>* %27
%29 = icmp eq <8 x i8> %25, %18
%30 = icmp eq <8 x i8> %28, %20
%31 = extractelement <8 x i1> %29, i64 0
br i1 %31, label %32, label %33
32: ; preds = %21
store i8 %3, i8* %23
br label %33
33: ; preds = %32, %21
%34 = extractelement <8 x i1> %29, i64 1
br i1 %34, label %35, label %38
35: ; preds = %33
%36 = or i64 %22, 1
%37 = getelementptr i8, i8* %0, i64 %36
store i8 %3, i8* %37
br label %38
38: ; preds = %35, %33
%39 = extractelement <8 x i1> %29, i64 2
br i1 %39, label %40, label %43
40: ; preds = %38
%41 = or i64 %22, 2
%42 = getelementptr i8, i8* %0, i64 %41
store i8 %3, i8* %42
br label %43
43: ; preds = %40, %38
%44 = extractelement <8 x i1> %29, i64 3
br i1 %44, label %45, label %48
45: ; preds = %43
%46 = or i64 %22, 3
%47 = getelementptr i8, i8* %0, i64 %46
store i8 %3, i8* %47
br label %48
48: ; preds = %45, %43
%49 = extractelement <8 x i1> %29, i64 4
br i1 %49, label %50, label %53
50: ; preds = %48
%51 = or i64 %22, 4
%52 = getelementptr i8, i8* %0, i64 %51
store i8 %3, i8* %52
br label %53
53: ; preds = %50, %48
%54 = extractelement <8 x i1> %29, i64 5
br i1 %54, label %55, label %58
55: ; preds = %53
%56 = or i64 %22, 5
%57 = getelementptr i8, i8* %0, i64 %56
store i8 %3, i8* %57
br label %58
58: ; preds = %55, %53
%59 = extractelement <8 x i1> %29, i64 6
br i1 %59, label %60, label %63
60: ; preds = %58
%61 = or i64 %22, 6
%62 = getelementptr i8, i8* %0, i64 %61
store i8 %3, i8* %62
br label %63
63: ; preds = %60, %58
%64 = extractelement <8 x i1> %29, i64 7
br i1 %64, label %65, label %68
65: ; preds = %63
%66 = or i64 %22, 7
%67 = getelementptr i8, i8* %0, i64 %66
store i8 %3, i8* %67
br label %68
68: ; preds = %65, %63
%69 = extractelement <8 x i1> %30, i64 0
br i1 %69, label %70, label %73
70: ; preds = %68
%71 = or i64 %22, 8
%72 = getelementptr i8, i8* %0, i64 %71
store i8 %3, i8* %72
br label %73
73: ; preds = %70, %68
%74 = extractelement <8 x i1> %30, i64 1
br i1 %74, label %75, label %78
75: ; preds = %73
%76 = or i64 %22, 9
%77 = getelementptr i8, i8* %0, i64 %76
store i8 %3, i8* %77
br label %78
78: ; preds = %75, %73
%79 = extractelement <8 x i1> %30, i64 2
br i1 %79, label %80, label %83
80: ; preds = %78
%81 = or i64 %22, 10
%82 = getelementptr i8, i8* %0, i64 %81
store i8 %3, i8* %82
br label %83
83: ; preds = %80, %78
%84 = extractelement <8 x i1> %30, i64 3
br i1 %84, label %85, label %88
85: ; preds = %83
%86 = or i64 %22, 11
%87 = getelementptr i8, i8* %0, i64 %86
store i8 %3, i8* %87
br label %88
88: ; preds = %85, %83
%89 = extractelement <8 x i1> %30, i64 4
br i1 %89, label %90, label %93
90: ; preds = %88
%91 = or i64 %22, 12
%92 = getelementptr i8, i8* %0, i64 %91
store i8 %3, i8* %92
br label %93
93: ; preds = %90, %88
%94 = extractelement <8 x i1> %30, i64 5
br i1 %94, label %95, label %98
95: ; preds = %93
%96 = or i64 %22, 13
%97 = getelementptr i8, i8* %0, i64 %96
store i8 %3, i8* %97
br label %98
98: ; preds = %95, %93
%99 = extractelement <8 x i1> %30, i64 6
br i1 %99, label %100, label %103
100: ; preds = %98
%101 = or i64 %22, 14
%102 = getelementptr i8, i8* %0, i64 %101
store i8 %3, i8* %102
br label %103
103: ; preds = %100, %98
%104 = extractelement <8 x i1> %30, i64 7
br i1 %104, label %105, label %108
105: ; preds = %103
%106 = or i64 %22, 15
%107 = getelementptr i8, i8* %0, i64 %106
store i8 %3, i8* %107
br label %108
108: ; preds = %105, %103
%109 = add nuw i64 %22, 16
%110 = icmp eq i64 %109, %13
br i1 %110, label %111, label %21
111: ; preds = %108
%112 = icmp eq i64 %10, %13
br i1 %112, label %126, label %113
113: ; preds = %6, %111
%114 = phi i32 [ %1, %6 ], [ %15, %111 ]
%115 = phi i8* [ %0, %6 ], [ %16, %111 ]
br label %116
116: ; preds = %113, %123
%117 = phi i32 [ %119, %123 ], [ %114, %113 ]
%118 = phi i8* [ %124, %123 ], [ %115, %113 ]
%119 = add nsw i32 %117, -1
%120 = load i8, i8* %118
%121 = icmp eq i8 %120, %2
br i1 %121, label %122, label %123
122: ; preds = %116
store i8 %3, i8* %118
br label %123
123: ; preds = %122, %116
%124 = getelementptr inbounds i8, i8* %118, i64 1
%125 = icmp ugt i32 %117, 2
br i1 %125, label %116, label %126
126: ; preds = %123, %111, %4
ret void
}