void fb_image_convert_32to16(const unsigned char *src, unsigned char *dest,
                             int w) {
  unsigned short *d = (unsigned short *)dest;
  unsigned int c;
  for (; w; w--) {
    c = *(unsigned int *)src & 0x00FFFFFF;
    *d++ = (unsigned short)((c >> (16 + 3)) | ((c >> 5) & 0x07E0) |
                            ((c << 8) & 0xF800));
    src += sizeof(unsigned int);
  }
}


x86 assembly (clang, -O0):
<fb_image_convert_32to16>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x8(%rbp)
mov    %rsi,-0x10(%rbp)
mov    %edx,-0x14(%rbp)
mov    -0x10(%rbp),%rax
mov    %rax,-0x20(%rbp)
cmpl   $0x0,-0x14(%rbp)
je     1180 <fb_image_convert_32to16+0x80>
mov    -0x8(%rbp),%rax
mov    (%rax),%eax
and    $0xffffff,%eax
mov    %eax,-0x24(%rbp)
mov    -0x24(%rbp),%eax
shr    $0x13,%eax
mov    -0x24(%rbp),%ecx
shr    $0x5,%ecx
and    $0x7e0,%ecx
or     %ecx,%eax
mov    -0x24(%rbp),%ecx
shl    $0x8,%ecx
and    $0xf800,%ecx
or     %ecx,%eax
mov    %ax,%cx
mov    -0x20(%rbp),%rax
mov    %rax,%rdx
add    $0x2,%rdx
mov    %rdx,-0x20(%rbp)
mov    %cx,(%rax)
mov    -0x8(%rbp),%rax
add    $0x4,%rax
mov    %rax,-0x8(%rbp)
mov    -0x14(%rbp),%eax
add    $0xffffffff,%eax
mov    %eax,-0x14(%rbp)
jmp    1117 <fb_image_convert_32to16+0x17>
pop    %rbp
ret

x86 assembly (clang, -O2):
<fb_image_convert_32to16>:
test   %edx,%edx
je     1221 <fb_image_convert_32to16+0x121>
lea    -0x1(%rdx),%r8d
cmp    $0x7,%r8d
jae    111d <fb_image_convert_32to16+0x1d>
mov    %rdi,%r9
mov    %rsi,%r10
jmp    11ec <fb_image_convert_32to16+0xec>
add    $0x1,%r8
mov    %r8,%rax
and    $0xfffffffffffffff8,%rax
lea    (%rdi,%rax,4),%r9
lea    (%rsi,%rax,2),%r10
sub    %eax,%edx
xor    %ecx,%ecx
movdqa 0xec3(%rip),%xmm8
movdqa 0xecb(%rip),%xmm1
movdqa 0xed3(%rip),%xmm2
nopl   (%rax)
movdqu (%rdi,%rcx,4),%xmm4
movdqu 0x10(%rdi,%rcx,4),%xmm6
movdqa %xmm4,%xmm5
psrld  $0x13,%xmm5
movdqa %xmm6,%xmm0
psrld  $0x13,%xmm0
pand   %xmm8,%xmm5
pand   %xmm8,%xmm0
movdqa %xmm4,%xmm7
psrld  $0x5,%xmm7
movdqa %xmm6,%xmm3
psrld  $0x5,%xmm3
pand   %xmm1,%xmm7
por    %xmm5,%xmm7
pand   %xmm1,%xmm3
por    %xmm0,%xmm3
pslld  $0x8,%xmm4
pslld  $0x8,%xmm6
pand   %xmm2,%xmm4
por    %xmm7,%xmm4
pand   %xmm2,%xmm6
por    %xmm3,%xmm6
pshuflw $0xe8,%xmm4,%xmm0
pshufhw $0xe8,%xmm0,%xmm0
pshufd $0xe8,%xmm0,%xmm0
pshuflw $0xe8,%xmm6,%xmm3
pshufhw $0xe8,%xmm3,%xmm3
pshufd $0xe8,%xmm3,%xmm3
punpcklqdq %xmm3,%xmm0
movdqu %xmm0,(%rsi,%rcx,2)
add    $0x8,%rcx
cmp    %rcx,%rax
jne    1150 <fb_image_convert_32to16+0x50>
cmp    %rax,%r8
je     1221 <fb_image_convert_32to16+0x121>
mov    %edx,%eax
xor    %ecx,%ecx
mov    (%r9,%rcx,4),%edx
mov    %edx,%esi
shr    $0x13,%esi
and    $0x1f,%esi
mov    %edx,%edi
shr    $0x5,%edi
and    $0x7e0,%edi
or     %esi,%edi
shl    $0x8,%edx
and    $0xf800,%edx
or     %edi,%edx
mov    %dx,(%r10,%rcx,2)
add    $0x1,%rcx
cmp    %ecx,%eax
jne    11f0 <fb_image_convert_32to16+0xf0>
ret

LLVM IR (-O0):
define void @fb_image_convert_32to16(i8* %0, i8* %1, i32 %2) {
%4 = alloca i8*
%5 = alloca i8*
%6 = alloca i32
%7 = alloca i16*
%8 = alloca i32
store i8* %0, i8** %4
store i8* %1, i8** %5
store i32 %2, i32* %6
%9 = load i8*, i8** %5
%10 = bitcast i8* %9 to i16*
store i16* %10, i16** %7
br label %11
11: ; preds = %34, %3
%12 = load i32, i32* %6
%13 = icmp ne i32 %12, 0
br i1 %13, label %14, label %37
14: ; preds = %11
%15 = load i8*, i8** %4
%16 = bitcast i8* %15 to i32*
%17 = load i32, i32* %16
%18 = and i32 %17, 16777215
store i32 %18, i32* %8
%19 = load i32, i32* %8
%20 = lshr i32 %19, 19
%21 = load i32, i32* %8
%22 = lshr i32 %21, 5
%23 = and i32 %22, 2016
%24 = or i32 %20, %23
%25 = load i32, i32* %8
%26 = shl i32 %25, 8
%27 = and i32 %26, 63488
%28 = or i32 %24, %27
%29 = trunc i32 %28 to i16
%30 = load i16*, i16** %7
%31 = getelementptr inbounds i16, i16* %30, i32 1
store i16* %31, i16** %7
store i16 %29, i16* %30
%32 = load i8*, i8** %4
%33 = getelementptr inbounds i8, i8* %32, i64 4
store i8* %33, i8** %4
br label %34
34: ; preds = %14
%35 = load i32, i32* %6
%36 = add nsw i32 %35, -1
store i32 %36, i32* %6
br label %11
37: ; preds = %11
ret void
}

LLVM IR (-O2):
define void @fb_image_convert_32to16(i8* nocapture %0, i8* nocapture writeonly %1, i32 %2) {
%4 = icmp eq i32 %2, 0
br i1 %4, label %76, label %5
5: ; preds = %3
%6 = bitcast i8* %1 to i16*
%7 = add i32 %2, -1
%8 = zext i32 %7 to i64
%9 = add nuw nsw i64 %8, 1
%10 = icmp ult i32 %7, 7
br i1 %10, label %53, label %11
11: ; preds = %5
%12 = and i64 %9, 8589934584
%13 = shl nuw nsw i64 %12, 2
%14 = getelementptr i8, i8* %0, i64 %13
%15 = getelementptr i16, i16* %6, i64 %12
%16 = trunc i64 %12 to i32
%17 = sub i32 %2, %16
br label %18
18: ; preds = %18, %11
%19 = phi i64 [ 0, %11 ], [ %49, %18 ]
%20 = shl i64 %19, 2
%21 = getelementptr i8, i8* %0, i64 %20
%22 = getelementptr i16, i16* %6, i64 %19
%23 = bitcast i8* %21 to <4 x i32>*
%24 = load <4 x i32>, <4 x i32>* %23
%25 = getelementptr i8, i8* %21, i64 16
%26 = bitcast i8* %25 to <4 x i32>*
%27 = load <4 x i32>, <4 x i32>* %26
%28 = lshr <4 x i32> %24, <i32 19, i32 19, i32 19, i32 19>
%29 = lshr <4 x i32> %27, <i32 19, i32 19, i32 19, i32 19>
%30 = and <4 x i32> %28, <i32 31, i32 31, i32 31, i32 31>
%31 = and <4 x i32> %29, <i32 31, i32 31, i32 31, i32 31>
%32 = lshr <4 x i32> %24, <i32 5, i32 5, i32 5, i32 5>
%33 = lshr <4 x i32> %27, <i32 5, i32 5, i32 5, i32 5>
%34 = and <4 x i32> %32, <i32 2016, i32 2016, i32 2016, i32 2016>
%35 = and <4 x i32> %33, <i32 2016, i32 2016, i32 2016, i32 2016>
%36 = or <4 x i32> %30, %34
%37 = or <4 x i32> %31, %35
%38 = shl <4 x i32> %24, <i32 8, i32 8, i32 8, i32 8>
%39 = shl <4 x i32> %27, <i32 8, i32 8, i32 8, i32 8>
%40 = and <4 x i32> %38, <i32 63488, i32 63488, i32 63488, i32 63488>
%41 = and <4 x i32> %39, <i32 63488, i32 63488, i32 63488, i32 63488>
%42 = or <4 x i32> %36, %40
%43 = or <4 x i32> %37, %41
%44 = trunc <4 x i32> %42 to <4 x i16>
%45 = trunc <4 x i32> %43 to <4 x i16>
%46 = bitcast i16* %22 to <4 x i16>*
store <4 x i16> %44, <4 x i16>* %46
%47 = getelementptr i16, i16* %22, i64 4
%48 = bitcast i16* %47 to <4 x i16>*
store <4 x i16> %45, <4 x i16>* %48
%49 = add nuw i64 %19, 8
%50 = icmp eq i64 %49, %12
br i1 %50, label %51, label %18
51: ; preds = %18
%52 = icmp eq i64 %9, %12
br i1 %52, label %76, label %53
53: ; preds = %5, %51
%54 = phi i8* [ %0, %5 ], [ %14, %51 ]
%55 = phi i16* [ %6, %5 ], [ %15, %51 ]
%56 = phi i32 [ %2, %5 ], [ %17, %51 ]
br label %57
57: ; preds = %53, %57
%58 = phi i8* [ %73, %57 ], [ %54, %53 ]
%59 = phi i16* [ %72, %57 ], [ %55, %53 ]
%60 = phi i32 [ %74, %57 ], [ %56, %53 ]
%61 = bitcast i8* %58 to i32*
%62 = load i32, i32* %61
%63 = lshr i32 %62, 19
%64 = and i32 %63, 31
%65 = lshr i32 %62, 5
%66 = and i32 %65, 2016
%67 = or i32 %64, %66
%68 = shl i32 %62, 8
%69 = and i32 %68, 63488
%70 = or i32 %67, %69
%71 = trunc i32 %70 to i16
%72 = getelementptr inbounds i16, i16* %59, i64 1
store i16 %71, i16* %59
%73 = getelementptr inbounds i8, i8* %58, i64 4
%74 = add nsw i32 %60, -1
%75 = icmp eq i32 %74, 0
br i1 %75, label %76, label %57
76: ; preds = %57, %51, %3
ret void
}