unsigned char copy_cs(char *restrict p, const char *restrict s, unsigned n) {
  unsigned char cs = 0;
  const char *const end = s + n;
  while (s < end)
    cs += (*p++ = *s++);
  return cs;
}


x86 assembly (clang, -O0):
<copy_cs>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x8(%rbp)
mov    %rsi,-0x10(%rbp)
mov    %edx,-0x14(%rbp)
movb   $0x0,-0x15(%rbp)
mov    -0x10(%rbp),%rax
mov    -0x14(%rbp),%ecx
add    %rcx,%rax
mov    %rax,-0x20(%rbp)
mov    -0x10(%rbp),%rax
cmp    -0x20(%rbp),%rax
jae    1162 <copy_cs+0x62>
mov    -0x10(%rbp),%rax
mov    %rax,%rcx
add    $0x1,%rcx
mov    %rcx,-0x10(%rbp)
mov    (%rax),%al
mov    -0x8(%rbp),%rcx
mov    %rcx,%rdx
add    $0x1,%rdx
mov    %rdx,-0x8(%rbp)
mov    %al,(%rcx)
movsbl %al,%ecx
movzbl -0x15(%rbp),%eax
add    %ecx,%eax
mov    %al,-0x15(%rbp)
jmp    1121 <copy_cs+0x21>
movzbl -0x15(%rbp),%eax
pop    %rbp
ret

x86 assembly (clang, -O2):
<copy_cs>:
push   %r15
push   %r14
push   %r12
push   %rbx
push   %rax
test   %edx,%edx
je     114e <copy_cs+0x3e>
mov    %rsi,%rbx
mov    %edx,%r15d
add    %rsi,%r15
lea    0x1(%rsi),%r12
cmp    %r12,%r15
mov    %r12,%r14
cmova  %r15,%r14
sub    %rsi,%r14
mov    %r14,%rdx
call   1030 <memcpy@plt>
cmp    $0x8,%r14
jae    1155 <copy_cs+0x45>
xor    %eax,%eax
mov    %rbx,%rdx
jmp    12a0 <copy_cs+0x190>
xor    %eax,%eax
jmp    12ab <copy_cs+0x19b>
cmp    $0x20,%r14
jae    1164 <copy_cs+0x54>
xor    %eax,%eax
xor    %ecx,%ecx
jmp    1250 <copy_cs+0x140>
mov    %r14,%rcx
and    $0xffffffffffffffe0,%rcx
lea    -0x20(%rcx),%rdx
mov    %rdx,%rsi
shr    $0x5,%rsi
add    $0x1,%rsi
mov    %esi,%eax
and    $0x3,%eax
cmp    $0x60,%rdx
jae    1191 <copy_cs+0x81>
pxor   %xmm0,%xmm0
xor    %edx,%edx
pxor   %xmm1,%xmm1
jmp    11f9 <copy_cs+0xe9>
and    $0xfffffffffffffffc,%rsi
pxor   %xmm0,%xmm0
xor    %edx,%edx
pxor   %xmm1,%xmm1
nop
movdqu (%rbx,%rdx,1),%xmm2
paddb  %xmm0,%xmm2
movdqu 0x10(%rbx,%rdx,1),%xmm0
paddb  %xmm1,%xmm0
movdqu 0x20(%rbx,%rdx,1),%xmm1
movdqu 0x30(%rbx,%rdx,1),%xmm3
movdqu 0x40(%rbx,%rdx,1),%xmm4
paddb  %xmm1,%xmm4
paddb  %xmm2,%xmm4
movdqu 0x50(%rbx,%rdx,1),%xmm2
paddb  %xmm3,%xmm2
paddb  %xmm0,%xmm2
movdqu 0x60(%rbx,%rdx,1),%xmm0
paddb  %xmm4,%xmm0
movdqu 0x70(%rbx,%rdx,1),%xmm1
paddb  %xmm2,%xmm1
sub    $0xffffffffffffff80,%rdx
add    $0xfffffffffffffffc,%rsi
jne    11a0 <copy_cs+0x90>
test   %rax,%rax
je     122c <copy_cs+0x11c>
add    %rbx,%rdx
add    $0x10,%rdx
shl    $0x5,%rax
xor    %esi,%esi
nopl   0x0(%rax,%rax,1)
movdqu -0x10(%rdx,%rsi,1),%xmm2
paddb  %xmm2,%xmm0
movdqu (%rdx,%rsi,1),%xmm2
paddb  %xmm2,%xmm1
add    $0x20,%rsi
cmp    %rsi,%rax
jne    1210 <copy_cs+0x100>
paddb  %xmm1,%xmm0
pshufd $0xee,%xmm0,%xmm1
paddb  %xmm0,%xmm1
pxor   %xmm0,%xmm0
psadbw %xmm1,%xmm0
movd   %xmm0,%eax
cmp    %rcx,%r14
je     12ab <copy_cs+0x19b>
test   $0x18,%r14b
je     12b7 <copy_cs+0x1a7>
cmp    %r12,%r15
cmova  %r15,%r12
sub    %rbx,%r12
mov    %r12,%rsi
and    $0xfffffffffffffff8,%rsi
lea    (%rbx,%rsi,1),%rdx
movzbl %al,%eax
movd   %eax,%xmm0
nopl   0x0(%rax)
movq   (%rbx,%rcx,1),%xmm1
paddb  %xmm1,%xmm0
add    $0x8,%rcx
cmp    %rcx,%rsi
jne    1270 <copy_cs+0x160>
pxor   %xmm1,%xmm1
psadbw %xmm1,%xmm0
movd   %xmm0,%eax
cmp    %rsi,%r12
je     12ab <copy_cs+0x19b>
cs nopw 0x0(%rax,%rax,1)
nopl   (%rax)
add    (%rdx),%al
add    $0x1,%rdx
cmp    %r15,%rdx
jb     12a0 <copy_cs+0x190>
add    $0x8,%rsp
pop    %rbx
pop    %r12
pop    %r14
pop    %r15
ret
add    %rcx,%rbx
jmp    1146 <copy_cs+0x36>

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

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