void user_bcopy(char *src, char *dest, int bytes) {
  char *s_ptr, *d_ptr;
  s_ptr = src + bytes - 1;
  d_ptr = dest + bytes - 1;
  for (; d_ptr >= dest; --s_ptr, --d_ptr)
    *d_ptr = *s_ptr;
}


x86 assembly (clang, -O0):
<user_bcopy>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x8(%rbp)
mov    %rsi,-0x10(%rbp)
mov    %edx,-0x14(%rbp)
mov    -0x8(%rbp),%rax
movslq -0x14(%rbp),%rcx
add    %rcx,%rax
add    $0xffffffffffffffff,%rax
mov    %rax,-0x20(%rbp)
mov    -0x10(%rbp),%rax
movslq -0x14(%rbp),%rcx
add    %rcx,%rax
add    $0xffffffffffffffff,%rax
mov    %rax,-0x28(%rbp)
mov    -0x28(%rbp),%rax
cmp    -0x10(%rbp),%rax
jb     116c <user_bcopy+0x6c>
mov    -0x20(%rbp),%rax
mov    (%rax),%cl
mov    -0x28(%rbp),%rax
mov    %cl,(%rax)
mov    -0x20(%rbp),%rax
add    $0xffffffffffffffff,%rax
mov    %rax,-0x20(%rbp)
mov    -0x28(%rbp),%rax
add    $0xffffffffffffffff,%rax
mov    %rax,-0x28(%rbp)
jmp    1135 <user_bcopy+0x35>
pop    %rbp
ret

x86 assembly (clang, -O2):
<user_bcopy>:
push   %r15
push   %r14
push   %r13
push   %r12
push   %rbx
movslq %edx,%r15
lea    (%rsi,%r15,1),%r11
add    $0xffffffffffffffff,%r11
cmp    %rsi,%r11
jb     1192 <user_bcopy+0x92>
lea    (%rsi,%r15,1),%r8
mov    $0x1,%r12d
sub    %r8,%r12
mov    %rsi,%r9
neg    %r9
cmp    %r9,%r12
cmovbe %r9,%r12
lea    (%rdi,%r15,1),%r10
add    %r8,%r12
cmp    $0x4,%r12
jb     1167 <user_bcopy+0x67>
lea    (%rsi,%r15,1),%rcx
add    $0xfffffffffffffffe,%rcx
lea    -0x1(%rsi),%rax
cmp    %rax,%rcx
cmovb  %rcx,%rax
add    $0x1,%rax
cmp    %r10,%rax
jae    119c <user_bcopy+0x9c>
sub    %rsi,%rax
add    %rdi,%rax
cmp    %r8,%rax
jae    119c <user_bcopy+0x9c>
mov    %r10,%rax
mov    %r11,%rdi
add    $0xffffffffffffffff,%rax
cs nopw 0x0(%rax,%rax,1)
nopl   0x0(%rax,%rax,1)
movzbl (%rax),%ecx
mov    %cl,(%rdi)
add    $0xffffffffffffffff,%rdi
add    $0xffffffffffffffff,%rax
cmp    %rsi,%rdi
jae    1180 <user_bcopy+0x80>
pop    %rbx
pop    %r12
pop    %r13
pop    %r14
pop    %r15
ret
cmp    $0x10,%r12
jae    11a9 <user_bcopy+0xa9>
xor    %ecx,%ecx
jmp    1263 <user_bcopy+0x163>
mov    %r12,%rcx
and    $0xfffffffffffffff0,%rcx
lea    -0x10(%rcx),%rax
mov    %rax,%rbx
shr    $0x4,%rbx
add    $0x1,%rbx
mov    %ebx,%r14d
and    $0x3,%r14d
cmp    $0x30,%rax
jae    11d0 <user_bcopy+0xd0>
xor    %eax,%eax
jmp    1218 <user_bcopy+0x118>
and    $0xfffffffffffffffc,%rbx
lea    -0xf(%r11),%r13
lea    -0x10(%r10),%rdx
xor    %eax,%eax
xchg   %ax,%ax
movups (%rdx,%rax,1),%xmm0
movups %xmm0,0x0(%r13,%rax,1)
movups -0x10(%rdx,%rax,1),%xmm0
movups %xmm0,-0x10(%r13,%rax,1)
movups -0x20(%rdx,%rax,1),%xmm0
movups %xmm0,-0x20(%r13,%rax,1)
movups -0x30(%rdx,%rax,1),%xmm0
movups %xmm0,-0x30(%r13,%rax,1)
add    $0xffffffffffffffc0,%rax
add    $0xfffffffffffffffc,%rbx
jne    11e0 <user_bcopy+0xe0>
neg    %rax
test   %r14,%r14
je     1254 <user_bcopy+0x154>
sub    %rax,%r15
lea    (%rsi,%r15,1),%rax
add    $0xfffffffffffffff0,%rax
lea    (%rdi,%r15,1),%rdx
add    $0xfffffffffffffff0,%rdx
shl    $0x4,%r14
xor    %edi,%edi
cs nopw 0x0(%rax,%rax,1)
movups (%rdx,%rdi,1),%xmm0
movups %xmm0,(%rax,%rdi,1)
add    $0xfffffffffffffff0,%rdi
mov    %r14,%rbx
add    %rdi,%rbx
jne    1240 <user_bcopy+0x140>
cmp    %rcx,%r12
je     1192 <user_bcopy+0x92>
test   $0xc,%r12b
je     12c1 <user_bcopy+0x1c1>
mov    $0x1,%ebx
sub    %r8,%rbx
cmp    %r9,%rbx
cmovbe %r9,%rbx
add    %r8,%rbx
mov    %rbx,%r8
and    $0xfffffffffffffffc,%r8
mov    %r10,%rax
sub    %r8,%rax
mov    %r11,%rdi
sub    %r8,%rdi
neg    %rcx
and    $0xfffffffffffffffc,%r12
neg    %r12
cs nopw 0x0(%rax,%rax,1)
nopl   0x0(%rax)
mov    -0x4(%r10,%rcx,1),%edx
mov    %edx,-0x3(%r11,%rcx,1)
add    $0xfffffffffffffffc,%rcx
cmp    %rcx,%r12
jne    12a0 <user_bcopy+0x1a0>
cmp    %r8,%rbx
jne    116d <user_bcopy+0x6d>
jmp    1192 <user_bcopy+0x92>
sub    %rcx,%r11
sub    %rcx,%r10
jmp    1167 <user_bcopy+0x67>

LLVM IR (-O0):
define void @user_bcopy(i8* %0, i8* %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
%9 = load i8*, i8** %4
%10 = load i32, i32* %6
%11 = sext i32 %10 to i64
%12 = getelementptr inbounds i8, i8* %9, i64 %11
%13 = getelementptr inbounds i8, i8* %12, i64 -1
store i8* %13, i8** %7
%14 = load i8*, i8** %5
%15 = load i32, i32* %6
%16 = sext i32 %15 to i64
%17 = getelementptr inbounds i8, i8* %14, i64 %16
%18 = getelementptr inbounds i8, i8* %17, i64 -1
store i8* %18, i8** %8
br label %19
19: ; preds = %27, %3
%20 = load i8*, i8** %8
%21 = load i8*, i8** %5
%22 = icmp uge i8* %20, %21
br i1 %22, label %23, label %32
23: ; preds = %19
%24 = load i8*, i8** %7
%25 = load i8, i8* %24
%26 = load i8*, i8** %8
store i8 %25, i8* %26
br label %27
27: ; preds = %23
%28 = load i8*, i8** %7
%29 = getelementptr inbounds i8, i8* %28, i32 -1
store i8* %29, i8** %7
%30 = load i8*, i8** %8
%31 = getelementptr inbounds i8, i8* %30, i32 -1
store i8* %31, i8** %8
br label %19
32: ; preds = %19
ret void
}

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