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


x86 assembly (clang, -O0):
<f>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x8(%rbp)
mov    %rsi,-0x10(%rbp)
mov    %rdx,-0x18(%rbp)
movl   $0x0,-0x1c(%rbp)
cmpl   $0x32,-0x1c(%rbp)
jge    115e <f+0x5e>
mov    -0x10(%rbp),%rax
movslq -0x1c(%rbp),%rcx
movzbl (%rax,%rcx,1),%eax
mov    -0x18(%rbp),%rcx
movslq -0x1c(%rbp),%rdx
movzbl (%rcx,%rdx,1),%ecx
add    %ecx,%eax
mov    $0x2,%ecx
cltd
idiv   %ecx
mov    %al,%dl
mov    -0x8(%rbp),%rax
movslq -0x1c(%rbp),%rcx
mov    %dl,(%rax,%rcx,1)
mov    -0x1c(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x1c(%rbp)
jmp    1117 <f+0x17>
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 i32
store i8* %0, i8** %4
store i8* %1, i8** %5
store i8* %2, i8** %6
store i32 0, i32* %7
br label %8
8: ; preds = %31, %3
%9 = load i32, i32* %7
%10 = icmp slt i32 %9, 50
br i1 %10, label %11, label %34
11: ; preds = %8
%12 = load i8*, i8** %5
%13 = load i32, i32* %7
%14 = sext i32 %13 to i64
%15 = getelementptr inbounds i8, i8* %12, i64 %14
%16 = load i8, i8* %15
%17 = zext i8 %16 to i32
%18 = load i8*, i8** %6
%19 = load i32, i32* %7
%20 = sext i32 %19 to i64
%21 = getelementptr inbounds i8, i8* %18, i64 %20
%22 = load i8, i8* %21
%23 = zext i8 %22 to i32
%24 = add nsw i32 %17, %23
%25 = sdiv i32 %24, 2
%26 = trunc i32 %25 to i8
%27 = load i8*, i8** %4
%28 = load i32, i32* %7
%29 = sext i32 %28 to i64
%30 = getelementptr inbounds i8, i8* %27, i64 %29
store i8 %26, i8* %30
br label %31
31: ; preds = %11
%32 = load i32, i32* %7
%33 = add nsw i32 %32, 1
store i32 %33, i32* %7
br label %8
34: ; 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
}