void __attribute__((noipa))
f(unsigned char *restrict a, unsigned char *restrict b,
  unsigned char *restrict c) {
  for (long int i = 0; i < 50; ++i)
    a[i] = (b[i] + c[i] + 0) >> 1;
}


x86 assembly (clang, -O0):
<f>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x8(%rbp)
mov    %rsi,-0x10(%rbp)
mov    %rdx,-0x18(%rbp)
movq   $0x0,-0x20(%rbp)
cmpq   $0x32,-0x20(%rbp)
jge    1161 <f+0x61>
mov    -0x10(%rbp),%rax
mov    -0x20(%rbp),%rcx
movzbl (%rax,%rcx,1),%eax
mov    -0x18(%rbp),%rcx
mov    -0x20(%rbp),%rdx
movzbl (%rcx,%rdx,1),%ecx
add    %ecx,%eax
add    $0x0,%eax
sar    $0x1,%eax
mov    %al,%dl
mov    -0x8(%rbp),%rax
mov    -0x20(%rbp),%rcx
mov    %dl,(%rax,%rcx,1)
mov    -0x20(%rbp),%rax
add    $0x1,%rax
mov    %rax,-0x20(%rbp)
jmp    1118 <f+0x18>
pop    %rbp
ret

x86 assembly (clang, -O2):
<f>:
movdqu (%rsi),%xmm1
pxor   %xmm0,%xmm0
movdqa %xmm1,%xmm2
punpckhbw %xmm0,%xmm2
punpcklbw %xmm0,%xmm1
movdqu (%rdx),%xmm3
movdqa %xmm3,%xmm4
punpckhbw %xmm0,%xmm4
paddw  %xmm2,%xmm4
punpcklbw %xmm0,%xmm3
paddw  %xmm1,%xmm3
psrlw  $0x1,%xmm4
psrlw  $0x1,%xmm3
packuswb %xmm4,%xmm3
movdqu %xmm3,(%rdi)
movdqu 0x10(%rsi),%xmm1
movdqa %xmm1,%xmm2
punpckhbw %xmm0,%xmm2
punpcklbw %xmm0,%xmm1
movdqu 0x10(%rdx),%xmm3
movdqa %xmm3,%xmm4
punpckhbw %xmm0,%xmm4
paddw  %xmm2,%xmm4
punpcklbw %xmm0,%xmm3
paddw  %xmm1,%xmm3
psrlw  $0x1,%xmm4
psrlw  $0x1,%xmm3
packuswb %xmm4,%xmm3
movdqu %xmm3,0x10(%rdi)
movdqu 0x20(%rsi),%xmm1
movdqa %xmm1,%xmm2
punpckhbw %xmm0,%xmm2
punpcklbw %xmm0,%xmm1
movdqu 0x20(%rdx),%xmm3
movdqa %xmm3,%xmm4
punpckhbw %xmm0,%xmm4
paddw  %xmm2,%xmm4
punpcklbw %xmm0,%xmm3
paddw  %xmm1,%xmm3
psrlw  $0x1,%xmm4
psrlw  $0x1,%xmm3
packuswb %xmm4,%xmm3
movdqu %xmm3,0x20(%rdi)
movzbl 0x30(%rsi),%eax
movzbl 0x30(%rdx),%ecx
add    %eax,%ecx
shr    %ecx
mov    %cl,0x30(%rdi)
movzbl 0x31(%rsi),%eax
movzbl 0x31(%rdx),%ecx
add    %eax,%ecx
shr    %ecx
mov    %cl,0x31(%rdi)
ret

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

LLVM IR (-O2):
define void @f(i8* noalias nocapture writeonly %0, i8* noalias nocapture %1, i8* noalias nocapture %2) {
%4 = bitcast i8* %1 to <16 x i8>*
%5 = load <16 x i8>, <16 x i8>* %4
%6 = zext <16 x i8> %5 to <16 x i16>
%7 = bitcast i8* %2 to <16 x i8>*
%8 = load <16 x i8>, <16 x i8>* %7
%9 = zext <16 x i8> %8 to <16 x i16>
%10 = add nuw nsw <16 x i16> %9, %6
%11 = lshr <16 x i16> %10, <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>
%12 = trunc <16 x i16> %11 to <16 x i8>
%13 = bitcast i8* %0 to <16 x i8>*
store <16 x i8> %12, <16 x i8>* %13
%14 = getelementptr inbounds i8, i8* %1, i64 16
%15 = bitcast i8* %14 to <16 x i8>*
%16 = load <16 x i8>, <16 x i8>* %15
%17 = zext <16 x i8> %16 to <16 x i16>
%18 = getelementptr inbounds i8, i8* %2, i64 16
%19 = bitcast i8* %18 to <16 x i8>*
%20 = load <16 x i8>, <16 x i8>* %19
%21 = zext <16 x i8> %20 to <16 x i16>
%22 = add nuw nsw <16 x i16> %21, %17
%23 = lshr <16 x i16> %22, <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>
%24 = trunc <16 x i16> %23 to <16 x i8>
%25 = getelementptr inbounds i8, i8* %0, i64 16
%26 = bitcast i8* %25 to <16 x i8>*
store <16 x i8> %24, <16 x i8>* %26
%27 = getelementptr inbounds i8, i8* %1, i64 32
%28 = bitcast i8* %27 to <16 x i8>*
%29 = load <16 x i8>, <16 x i8>* %28
%30 = zext <16 x i8> %29 to <16 x i16>
%31 = getelementptr inbounds i8, i8* %2, i64 32
%32 = bitcast i8* %31 to <16 x i8>*
%33 = load <16 x i8>, <16 x i8>* %32
%34 = zext <16 x i8> %33 to <16 x i16>
%35 = add nuw nsw <16 x i16> %34, %30
%36 = lshr <16 x i16> %35, <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>
%37 = trunc <16 x i16> %36 to <16 x i8>
%38 = getelementptr inbounds i8, i8* %0, i64 32
%39 = bitcast i8* %38 to <16 x i8>*
store <16 x i8> %37, <16 x i8>* %39
%40 = getelementptr inbounds i8, i8* %1, i64 48
%41 = load i8, i8* %40
%42 = zext i8 %41 to i16
%43 = getelementptr inbounds i8, i8* %2, i64 48
%44 = load i8, i8* %43
%45 = zext i8 %44 to i16
%46 = add nuw nsw i16 %45, %42
%47 = lshr i16 %46, 1
%48 = trunc i16 %47 to i8
%49 = getelementptr inbounds i8, i8* %0, i64 48
store i8 %48, i8* %49
%50 = getelementptr inbounds i8, i8* %1, i64 49
%51 = load i8, i8* %50
%52 = zext i8 %51 to i16
%53 = getelementptr inbounds i8, i8* %2, i64 49
%54 = load i8, i8* %53
%55 = zext i8 %54 to i16
%56 = add nuw nsw i16 %55, %52
%57 = lshr i16 %56, 1
%58 = trunc i16 %57 to i8
%59 = getelementptr inbounds i8, i8* %0, i64 49
store i8 %58, i8* %59
ret void
}