int FASTO_cpy(char *dest, char *p, char *end) {
  while (1) {
    *((int *)dest) = *((int *)p);
    p += sizeof(int);
    if (p >= end)
      break;
    dest += sizeof(int);
  }
}


x86 assembly (clang, -O0):
<FASTO_cpy>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x10(%rbp)
mov    %rsi,-0x18(%rbp)
mov    %rdx,-0x20(%rbp)
mov    -0x18(%rbp),%rax
mov    (%rax),%ecx
mov    -0x10(%rbp),%rax
mov    %ecx,(%rax)
mov    -0x18(%rbp),%rax
add    $0x4,%rax
mov    %rax,-0x18(%rbp)
mov    -0x18(%rbp),%rax
cmp    -0x20(%rbp),%rax
jb     113b <FASTO_cpy+0x3b>
jmp    114c <FASTO_cpy+0x4c>
mov    -0x10(%rbp),%rax
add    $0x4,%rax
mov    %rax,-0x10(%rbp)
jmp    1110 <FASTO_cpy+0x10>
mov    -0x4(%rbp),%eax
pop    %rbp
ret

x86 assembly (clang, -O2):
<FASTO_cpy>:
lea    0x4(%rsi),%rax
cmp    %rax,%rdx
mov    %rax,%r10
cmova  %rdx,%r10
mov    %rsi,%rcx
not    %rcx
add    %rcx,%r10
cmp    $0x1c,%r10
jb     11e0 <FASTO_cpy+0xe0>
cmp    %rax,%rdx
cmova  %rdx,%rax
add    %rcx,%rax
add    $0x4,%rax
and    $0xfffffffffffffffc,%rax
lea    (%rsi,%rax,1),%rcx
cmp    %rdi,%rcx
jbe    1148 <FASTO_cpy+0x48>
add    %rdi,%rax
cmp    %rsi,%rax
ja     11e0 <FASTO_cpy+0xe0>
shr    $0x2,%r10
add    $0x1,%r10
mov    %r10,%r8
and    $0xfffffffffffffff8,%r8
lea    -0x8(%r8),%rax
mov    %rax,%r9
shr    $0x3,%r9
add    $0x1,%r9
test   %rax,%rax
je     11f2 <FASTO_cpy+0xf2>
mov    %r9,%rax
and    $0xfffffffffffffffe,%rax
xor    %ecx,%ecx
nopl   0x0(%rax,%rax,1)
movups (%rsi,%rcx,1),%xmm0
movups 0x10(%rsi,%rcx,1),%xmm1
movups %xmm0,(%rdi,%rcx,1)
movups %xmm1,0x10(%rdi,%rcx,1)
movups 0x20(%rsi,%rcx,1),%xmm0
movups 0x30(%rsi,%rcx,1),%xmm1
movups %xmm0,0x20(%rdi,%rcx,1)
movups %xmm1,0x30(%rdi,%rcx,1)
add    $0x40,%rcx
add    $0xfffffffffffffffe,%rax
jne    1180 <FASTO_cpy+0x80>
test   $0x1,%r9b
je     11c8 <FASTO_cpy+0xc8>
movups (%rsi,%rcx,1),%xmm0
movups 0x10(%rsi,%rcx,1),%xmm1
movups %xmm0,(%rdi,%rcx,1)
movups %xmm1,0x10(%rdi,%rcx,1)
cmp    %r8,%r10
je     11f1 <FASTO_cpy+0xf1>
lea    (%rsi,%r8,4),%rsi
lea    (%rdi,%r8,4),%rdi
cs nopw 0x0(%rax,%rax,1)
nop
mov    (%rsi),%eax
mov    %eax,(%rdi)
add    $0x4,%rsi
add    $0x4,%rdi
cmp    %rdx,%rsi
jb     11e0 <FASTO_cpy+0xe0>
ret
xor    %ecx,%ecx
test   $0x1,%r9b
jne    11b6 <FASTO_cpy+0xb6>
jmp    11c8 <FASTO_cpy+0xc8>

LLVM IR (-O0):
define i32 @FASTO_cpy(i8* %0, i8* %1, i8* %2) {
%4 = alloca i32
%5 = alloca i8*
%6 = alloca i8*
%7 = alloca i8*
store i8* %0, i8** %5
store i8* %1, i8** %6
store i8* %2, i8** %7
br label %8
8: ; preds = %3, %20
%9 = load i8*, i8** %6
%10 = bitcast i8* %9 to i32*
%11 = load i32, i32* %10
%12 = load i8*, i8** %5
%13 = bitcast i8* %12 to i32*
store i32 %11, i32* %13
%14 = load i8*, i8** %6
%15 = getelementptr inbounds i8, i8* %14, i64 4
store i8* %15, i8** %6
%16 = load i8*, i8** %6
%17 = load i8*, i8** %7
%18 = icmp uge i8* %16, %17
br i1 %18, label %19, label %20
19: ; preds = %8
br label %23
20: ; preds = %8
%21 = load i8*, i8** %5
%22 = getelementptr inbounds i8, i8* %21, i64 4
store i8* %22, i8** %5
br label %8
23: ; preds = %19
%24 = load i32, i32* %4
ret i32 %24
}

LLVM IR (-O2):
define i32 @FASTO_cpy(i8* nocapture writeonly %0, i8* %1, i8* readnone %2) {
%4 = ptrtoint i8* %1 to i64
%5 = ptrtoint i8* %2 to i64
%6 = ptrtoint i8* %1 to i64
%7 = add i64 %4, 4
%8 = call i64 @llvm.umax.i64(i64 %5, i64 %7)
%9 = xor i64 %4, -1
%10 = add i64 %8, %9
%11 = lshr i64 %10, 2
%12 = add nuw nsw i64 %11, 1
%13 = icmp ult i64 %10, 28
br i1 %13, label %89, label %14
14: ; preds = %3
%15 = ptrtoint i8* %2 to i64
%16 = add i64 %6, 4
%17 = call i64 @llvm.umax.i64(i64 %15, i64 %16)
%18 = xor i64 %6, -1
%19 = add i64 %17, %18
%20 = add i64 %19, 4
%21 = and i64 %20, -4
%22 = getelementptr i8, i8* %0, i64 %21
%23 = getelementptr i8, i8* %1, i64 %21
%24 = icmp ugt i8* %23, %0
%25 = icmp ugt i8* %22, %1
%26 = and i1 %24, %25
br i1 %26, label %89, label %27
27: ; preds = %14
%28 = and i64 %12, 9223372036854775800
%29 = shl i64 %28, 2
%30 = getelementptr i8, i8* %1, i64 %29
%31 = shl i64 %28, 2
%32 = getelementptr i8, i8* %0, i64 %31
%33 = add nsw i64 %28, -8
%34 = lshr exact i64 %33, 3
%35 = add nuw nsw i64 %34, 1
%36 = and i64 %35, 1
%37 = icmp eq i64 %33, 0
br i1 %37, label %73, label %38
38: ; preds = %27
%39 = and i64 %35, 4611686018427387902
br label %40
40: ; preds = %40, %38
%41 = phi i64 [ 0, %38 ], [ %68, %40 ]
%42 = phi i64 [ 0, %38 ], [ %69, %40 ]
%43 = shl i64 %41, 2
%44 = getelementptr i8, i8* %1, i64 %43
%45 = shl i64 %41, 2
%46 = getelementptr i8, i8* %0, i64 %45
%47 = bitcast i8* %44 to <4 x i32>*
%48 = load <4 x i32>, <4 x i32>* %47
%49 = getelementptr i8, i8* %44, i64 16
%50 = bitcast i8* %49 to <4 x i32>*
%51 = load <4 x i32>, <4 x i32>* %50
%52 = bitcast i8* %46 to <4 x i32>*
store <4 x i32> %48, <4 x i32>* %52
%53 = getelementptr i8, i8* %46, i64 16
%54 = bitcast i8* %53 to <4 x i32>*
store <4 x i32> %51, <4 x i32>* %54
%55 = or i64 %41, 8
%56 = shl i64 %55, 2
%57 = getelementptr i8, i8* %1, i64 %56
%58 = shl i64 %55, 2
%59 = getelementptr i8, i8* %0, i64 %58
%60 = bitcast i8* %57 to <4 x i32>*
%61 = load <4 x i32>, <4 x i32>* %60
%62 = getelementptr i8, i8* %57, i64 16
%63 = bitcast i8* %62 to <4 x i32>*
%64 = load <4 x i32>, <4 x i32>* %63
%65 = bitcast i8* %59 to <4 x i32>*
store <4 x i32> %61, <4 x i32>* %65
%66 = getelementptr i8, i8* %59, i64 16
%67 = bitcast i8* %66 to <4 x i32>*
store <4 x i32> %64, <4 x i32>* %67
%68 = add nuw i64 %41, 16
%69 = add i64 %42, 2
%70 = icmp eq i64 %69, %39
br i1 %70, label %71, label %40
71: ; preds = %40
%72 = shl i64 %68, 2
br label %73
73: ; preds = %71, %27
%74 = phi i64 [ 0, %27 ], [ %72, %71 ]
%75 = icmp eq i64 %36, 0
br i1 %75, label %87, label %76
76: ; preds = %73
%77 = getelementptr i8, i8* %1, i64 %74
%78 = getelementptr i8, i8* %0, i64 %74
%79 = bitcast i8* %77 to <4 x i32>*
%80 = load <4 x i32>, <4 x i32>* %79
%81 = getelementptr i8, i8* %77, i64 16
%82 = bitcast i8* %81 to <4 x i32>*
%83 = load <4 x i32>, <4 x i32>* %82
%84 = bitcast i8* %78 to <4 x i32>*
store <4 x i32> %80, <4 x i32>* %84
%85 = getelementptr i8, i8* %78, i64 16
%86 = bitcast i8* %85 to <4 x i32>*
store <4 x i32> %83, <4 x i32>* %86
br label %87
87: ; preds = %73, %76
%88 = icmp eq i64 %12, %28
br i1 %88, label %101, label %89
89: ; preds = %14, %3, %87
%90 = phi i8* [ %1, %14 ], [ %1, %3 ], [ %30, %87 ]
%91 = phi i8* [ %0, %14 ], [ %0, %3 ], [ %32, %87 ]
br label %92
92: ; preds = %89, %92
%93 = phi i8* [ %98, %92 ], [ %90, %89 ]
%94 = phi i8* [ %100, %92 ], [ %91, %89 ]
%95 = bitcast i8* %93 to i32*
%96 = load i32, i32* %95
%97 = bitcast i8* %94 to i32*
store i32 %96, i32* %97
%98 = getelementptr inbounds i8, i8* %93, i64 4
%99 = icmp ult i8* %98, %2
%100 = getelementptr inbounds i8, i8* %94, i64 4
br i1 %99, label %92, label %101
101: ; preds = %92, %87
ret i32 undef
}