void fb_image_convert_24to16(const unsigned char *src, unsigned char *dest,
                             int w) {
  unsigned short *d = (unsigned short *)dest;
  for (; w; w--) {
    *d++ = (((unsigned short)src[0] << 8) & 0xF800) |
           (((unsigned short)src[1] << 3) & 0x07E0) |
           ((unsigned short)src[2] >> 3);
    src += 3;
  }
}


x86 assembly (clang, -O0):
<fb_image_convert_24to16>:
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     1188 <fb_image_convert_24to16+0x88>
mov    -0x8(%rbp),%rax
movzbl (%rax),%eax
movzwl %ax,%eax
shl    $0x8,%eax
and    $0xf800,%eax
mov    -0x8(%rbp),%rcx
movzbl 0x1(%rcx),%ecx
movzwl %cx,%ecx
shl    $0x3,%ecx
and    $0x7e0,%ecx
or     %ecx,%eax
mov    -0x8(%rbp),%rcx
movzbl 0x2(%rcx),%ecx
movzwl %cx,%ecx
sar    $0x3,%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    $0x3,%rax
mov    %rax,-0x8(%rbp)
mov    -0x14(%rbp),%eax
add    $0xffffffff,%eax
mov    %eax,-0x14(%rbp)
jmp    1117 <fb_image_convert_24to16+0x17>
pop    %rbp
ret

x86 assembly (clang, -O2):
<fb_image_convert_24to16>:
test   %edx,%edx
je     1392 <fb_image_convert_24to16+0x292>
lea    -0x1(%rdx),%r8d
cmp    $0x7,%r8d
jb     1137 <fb_image_convert_24to16+0x37>
lea    (%r8,%r8,2),%rax
add    %rdi,%rax
add    $0x3,%rax
cmp    %rsi,%rax
jbe    11eb <fb_image_convert_24to16+0xeb>
lea    (%rsi,%r8,2),%rax
add    $0x2,%rax
cmp    %rdi,%rax
jbe    11eb <fb_image_convert_24to16+0xeb>
mov    %rsi,%r10
mov    %rdi,%rcx
test   $0x1,%dl
jne    114e <fb_image_convert_24to16+0x4e>
mov    %edx,%eax
cmp    $0x1,%edx
jne    1185 <fb_image_convert_24to16+0x85>
jmp    1392 <fb_image_convert_24to16+0x292>
movzbl (%rcx),%eax
and    $0xfffffff8,%eax
shl    $0x8,%eax
movzbl 0x1(%rcx),%esi
and    $0xfc,%esi
lea    (%rax,%rsi,8),%eax
movzbl 0x2(%rcx),%esi
shr    $0x3,%esi
or     %eax,%esi
mov    %si,(%r10)
add    $0x2,%r10
add    $0x3,%rcx
lea    -0x1(%rdx),%eax
cmp    $0x1,%edx
je     1392 <fb_image_convert_24to16+0x292>
mov    %eax,%eax
xor    %edx,%edx
nopl   0x0(%rax)
movzbl (%rcx),%esi
and    $0xfffffff8,%esi
shl    $0x8,%esi
movzbl 0x1(%rcx),%edi
and    $0xfc,%edi
lea    (%rsi,%rdi,8),%esi
movzbl 0x2(%rcx),%edi
shr    $0x3,%edi
or     %esi,%edi
mov    %di,(%r10,%rdx,2)
movzbl 0x3(%rcx),%esi
and    $0xfffffff8,%esi
shl    $0x8,%esi
movzbl 0x4(%rcx),%edi
and    $0xfc,%edi
lea    (%rsi,%rdi,8),%esi
movzbl 0x5(%rcx),%edi
shr    $0x3,%edi
or     %esi,%edi
mov    %di,0x2(%r10,%rdx,2)
add    $0x2,%rdx
add    $0x6,%rcx
cmp    %edx,%eax
jne    1190 <fb_image_convert_24to16+0x90>
jmp    1392 <fb_image_convert_24to16+0x292>
add    $0x1,%r8
mov    %r8,%r9
and    $0xfffffffffffffff8,%r9
lea    (%rsi,%r9,2),%r10
sub    %r9d,%edx
lea    (%r9,%r9,2),%rcx
add    %rdi,%rcx
xor    %eax,%eax
movdqa 0xdf1(%rip),%xmm11
pxor   %xmm1,%xmm1
movdqa 0xdf4(%rip),%xmm12
movdqa 0xdfb(%rip),%xmm13
movdqa 0xe02(%rip),%xmm14
movdqa 0xe09(%rip),%xmm15
movdqa 0xe11(%rip),%xmm6
movdqa 0xe18(%rip),%xmm8
movdqa 0xe1f(%rip),%xmm9
movdqa 0xe26(%rip),%xmm10
nopw   0x0(%rax,%rax,1)
movdqu (%rdi),%xmm3
movq   0x10(%rdi),%xmm2
movdqa %xmm11,%xmm0
pandn  %xmm2,%xmm0
movdqa %xmm3,%xmm4
pand   %xmm11,%xmm4
por    %xmm0,%xmm4
punpcklbw %xmm1,%xmm4
pand   %xmm12,%xmm4
movdqa %xmm3,%xmm5
punpckhbw %xmm1,%xmm5
movdqa %xmm12,%xmm0
pandn  %xmm5,%xmm0
por    %xmm4,%xmm0
pshufd $0xd8,%xmm0,%xmm0
pshufhw $0x6c,%xmm0,%xmm0
pshufd $0x6c,%xmm0,%xmm0
pshuflw $0x6c,%xmm0,%xmm0
pshufhw $0xc6,%xmm0,%xmm0
packuswb %xmm0,%xmm0
punpcklbw %xmm0,%xmm0
pand   %xmm8,%xmm0
movdqa %xmm13,%xmm4
pandn  %xmm2,%xmm4
movdqa %xmm3,%xmm7
pand   %xmm13,%xmm7
por    %xmm4,%xmm7
punpcklbw %xmm1,%xmm7
pand   %xmm14,%xmm7
movdqa %xmm14,%xmm4
pandn  %xmm5,%xmm4
por    %xmm7,%xmm4
pshuflw $0xc6,%xmm4,%xmm4
pshufhw $0xc6,%xmm4,%xmm4
pshufd $0x6c,%xmm4,%xmm4
pshuflw $0x39,%xmm4,%xmm4
pshufhw $0x39,%xmm4,%xmm4
packuswb %xmm4,%xmm4
punpcklbw %xmm4,%xmm4
movdqa %xmm15,%xmm7
pandn  %xmm2,%xmm7
pand   %xmm15,%xmm3
por    %xmm7,%xmm3
punpcklbw %xmm1,%xmm3
pand   %xmm6,%xmm3
movdqa %xmm6,%xmm2
pandn  %xmm5,%xmm2
por    %xmm3,%xmm2
pshufd $0x27,%xmm2,%xmm2
pshufhw $0x6c,%xmm2,%xmm2
pshufd $0x27,%xmm2,%xmm2
pshuflw $0xc6,%xmm2,%xmm2
pshufhw $0xc6,%xmm2,%xmm2
packuswb %xmm2,%xmm2
psllw  $0x3,%xmm4
pand   %xmm9,%xmm4
por    %xmm0,%xmm4
psrlw  $0x3,%xmm2
pand   %xmm10,%xmm2
punpcklbw %xmm1,%xmm2
por    %xmm4,%xmm2
movdqu %xmm2,(%rsi,%rax,2)
add    $0x8,%rax
add    $0x18,%rdi
cmp    %rax,%r9
jne    1260 <fb_image_convert_24to16+0x160>
cmp    %r9,%r8
jne    113d <fb_image_convert_24to16+0x3d>
ret

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

LLVM IR (-O2):
define void @fb_image_convert_24to16(i8* nocapture %0, i8* nocapture writeonly %1, i32 %2) {
%4 = icmp eq i32 %2, 0
br i1 %4, label %125, 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 %55, label %11
11: ; preds = %5
%12 = add i32 %2, -1
%13 = zext i32 %12 to i64
%14 = shl nuw nsw i64 %13, 1
%15 = add nuw nsw i64 %14, 2
%16 = getelementptr i8, i8* %1, i64 %15
%17 = mul nuw nsw i64 %13, 3
%18 = add nuw nsw i64 %17, 3
%19 = getelementptr i8, i8* %0, i64 %18
%20 = icmp ugt i8* %19, %1
%21 = icmp ugt i8* %16, %0
%22 = and i1 %20, %21
br i1 %22, label %55, label %23
23: ; preds = %11
%24 = and i64 %9, 8589934584
%25 = getelementptr i16, i16* %6, i64 %24
%26 = trunc i64 %24 to i32
%27 = sub i32 %2, %26
%28 = mul nuw nsw i64 %24, 3
%29 = getelementptr i8, i8* %0, i64 %28
br label %30
30: ; preds = %30, %23
%31 = phi i64 [ 0, %23 ], [ %51, %30 ]
%32 = getelementptr i16, i16* %6, i64 %31
%33 = mul i64 %31, 3
%34 = getelementptr i8, i8* %0, i64 %33
%35 = bitcast i8* %34 to <24 x i8>*
%36 = load <24 x i8>, <24 x i8>* %35
%37 = shufflevector <24 x i8> %36, <24 x i8> poison, <8 x i32> <i32 0, i32 3, i32 6, i32 9, i32 12, i32 15, i32 18, i32 21>
%38 = shufflevector <24 x i8> %36, <24 x i8> poison, <8 x i32> <i32 1, i32 4, i32 7, i32 10, i32 13, i32 16, i32 19, i32 22>
%39 = shufflevector <24 x i8> %36, <24 x i8> poison, <8 x i32> <i32 2, i32 5, i32 8, i32 11, i32 14, i32 17, i32 20, i32 23>
%40 = zext <8 x i8> %37 to <8 x i16>
%41 = shl nuw <8 x i16> %40, <i16 8, i16 8, i16 8, i16 8, i16 8, i16 8, i16 8, i16 8>
%42 = and <8 x i16> %41, <i16 -2048, i16 -2048, i16 -2048, i16 -2048, i16 -2048, i16 -2048, i16 -2048, i16 -2048>
%43 = zext <8 x i8> %38 to <8 x i16>
%44 = shl nuw nsw <8 x i16> %43, <i16 3, i16 3, i16 3, i16 3, i16 3, i16 3, i16 3, i16 3>
%45 = and <8 x i16> %44, <i16 2016, i16 2016, i16 2016, i16 2016, i16 2016, i16 2016, i16 2016, i16 2016>
%46 = or <8 x i16> %45, %42
%47 = lshr <8 x i8> %39, <i8 3, i8 3, i8 3, i8 3, i8 3, i8 3, i8 3, i8 3>
%48 = zext <8 x i8> %47 to <8 x i16>
%49 = or <8 x i16> %46, %48
%50 = bitcast i16* %32 to <8 x i16>*
store <8 x i16> %49, <8 x i16>* %50
%51 = add nuw i64 %31, 8
%52 = icmp eq i64 %51, %24
br i1 %52, label %53, label %30
53: ; preds = %30
%54 = icmp eq i64 %9, %24
br i1 %54, label %125, label %55
55: ; preds = %11, %5, %53
%56 = phi i16* [ %6, %11 ], [ %6, %5 ], [ %25, %53 ]
%57 = phi i32 [ %2, %11 ], [ %2, %5 ], [ %27, %53 ]
%58 = phi i8* [ %0, %11 ], [ %0, %5 ], [ %29, %53 ]
%59 = and i32 %57, 1
%60 = icmp eq i32 %59, 0
br i1 %60, label %80, label %61
61: ; preds = %55
%62 = load i8, i8* %58
%63 = zext i8 %62 to i16
%64 = shl nuw i16 %63, 8
%65 = and i16 %64, -2048
%66 = getelementptr inbounds i8, i8* %58, i64 1
%67 = load i8, i8* %66
%68 = zext i8 %67 to i16
%69 = shl nuw nsw i16 %68, 3
%70 = and i16 %69, 2016
%71 = or i16 %70, %65
%72 = getelementptr inbounds i8, i8* %58, i64 2
%73 = load i8, i8* %72
%74 = lshr i8 %73, 3
%75 = zext i8 %74 to i16
%76 = or i16 %71, %75
%77 = getelementptr inbounds i16, i16* %56, i64 1
store i16 %76, i16* %56
%78 = getelementptr inbounds i8, i8* %58, i64 3
%79 = add nsw i32 %57, -1
br label %80
80: ; preds = %61, %55
%81 = phi i16* [ %56, %55 ], [ %77, %61 ]
%82 = phi i32 [ %57, %55 ], [ %79, %61 ]
%83 = phi i8* [ %58, %55 ], [ %78, %61 ]
%84 = icmp eq i32 %57, 1
br i1 %84, label %125, label %85
85: ; preds = %80, %85
%86 = phi i16* [ %121, %85 ], [ %81, %80 ]
%87 = phi i32 [ %123, %85 ], [ %82, %80 ]
%88 = phi i8* [ %122, %85 ], [ %83, %80 ]
%89 = load i8, i8* %88
%90 = zext i8 %89 to i16
%91 = shl nuw i16 %90, 8
%92 = and i16 %91, -2048
%93 = getelementptr inbounds i8, i8* %88, i64 1
%94 = load i8, i8* %93
%95 = zext i8 %94 to i16
%96 = shl nuw nsw i16 %95, 3
%97 = and i16 %96, 2016
%98 = or i16 %97, %92
%99 = getelementptr inbounds i8, i8* %88, i64 2
%100 = load i8, i8* %99
%101 = lshr i8 %100, 3
%102 = zext i8 %101 to i16
%103 = or i16 %98, %102
%104 = getelementptr inbounds i16, i16* %86, i64 1
store i16 %103, i16* %86
%105 = getelementptr inbounds i8, i8* %88, i64 3
%106 = load i8, i8* %105
%107 = zext i8 %106 to i16
%108 = shl nuw i16 %107, 8
%109 = and i16 %108, -2048
%110 = getelementptr inbounds i8, i8* %88, i64 4
%111 = load i8, i8* %110
%112 = zext i8 %111 to i16
%113 = shl nuw nsw i16 %112, 3
%114 = and i16 %113, 2016
%115 = or i16 %114, %109
%116 = getelementptr inbounds i8, i8* %88, i64 5
%117 = load i8, i8* %116
%118 = lshr i8 %117, 3
%119 = zext i8 %118 to i16
%120 = or i16 %115, %119
%121 = getelementptr inbounds i16, i16* %86, i64 2
store i16 %120, i16* %104
%122 = getelementptr inbounds i8, i8* %88, i64 6
%123 = add nsw i32 %87, -2
%124 = icmp eq i32 %123, 0
br i1 %124, label %125, label %85
125: ; preds = %80, %85, %53, %3
ret void
}