unsigned char AlphaComp(unsigned char fg, unsigned char alpha,
                        unsigned char bg) {
  unsigned char out;
  unsigned short temp;
  switch (alpha) {
  case 0:
    out = bg;
    break;
  case 255:
    out = fg;
    break;
  default:
    temp = ((unsigned short)(fg) * (unsigned short)(alpha) +
            (unsigned short)(bg) *
                (unsigned short)(255 - (unsigned short)(alpha)) +
            (unsigned short)128);
    out = (unsigned char)((temp + (temp >> 8)) >> 8);
    break;
  }
  return out;
}


x86 assembly (clang, -O0):
<AlphaComp>:
push   %rbp
mov    %rsp,%rbp
mov    %dl,%al
mov    %sil,%cl
mov    %dil,%dl
mov    %dl,-0x1(%rbp)
mov    %cl,-0x2(%rbp)
mov    %al,-0x3(%rbp)
movzbl -0x2(%rbp),%eax
mov    %eax,-0xc(%rbp)
test   %eax,%eax
je     113c <AlphaComp+0x3c>
jmp    1129 <AlphaComp+0x29>
mov    -0xc(%rbp),%eax
sub    $0xff,%eax
je     1147 <AlphaComp+0x47>
jmp    1152 <AlphaComp+0x52>
mov    -0x3(%rbp),%al
mov    %al,-0x4(%rbp)
jmp    119c <AlphaComp+0x9c>
mov    -0x1(%rbp),%al
mov    %al,-0x4(%rbp)
jmp    119c <AlphaComp+0x9c>
movzbl -0x1(%rbp),%eax
movzwl %ax,%eax
movzbl -0x2(%rbp),%ecx
movzwl %cx,%ecx
imul   %ecx,%eax
movzbl -0x3(%rbp),%ecx
movzwl %cx,%ecx
movzbl -0x2(%rbp),%edx
movzwl %dx,%esi
mov    $0xff,%edx
sub    %esi,%edx
movzwl %dx,%edx
imul   %edx,%ecx
add    %ecx,%eax
add    $0x80,%eax
mov    %ax,-0x6(%rbp)
movzwl -0x6(%rbp),%eax
movzwl -0x6(%rbp),%ecx
sar    $0x8,%ecx
add    %ecx,%eax
sar    $0x8,%eax
mov    %al,-0x4(%rbp)
movzbl -0x4(%rbp),%eax
pop    %rbp
ret

x86 assembly (clang, -O2):
<AlphaComp>:
mov    %edx,%eax
test   %esi,%esi
je     113e <AlphaComp+0x3e>
cmp    $0xff,%sil
jne    110f <AlphaComp+0xf>
mov    %edi,%eax
ret
movzbl %dil,%ecx
movzbl %sil,%edx
imul   %ecx,%edx
movzbl %al,%eax
not    %sil
movzbl %sil,%ecx
imul   %eax,%ecx
lea    (%rdx,%rcx,1),%eax
add    $0x80,%eax
add    %ecx,%edx
movzbl %ah,%eax
add    %edx,%eax
add    $0x80,%eax
shr    $0x8,%eax
ret

LLVM IR (-O0):
define zeroext i8 @AlphaComp(i8 zeroext %0, i8 zeroext %1, i8 zeroext %2) {
%4 = alloca i8
%5 = alloca i8
%6 = alloca i8
%7 = alloca i8
%8 = alloca i16
store i8 %0, i8* %4
store i8 %1, i8* %5
store i8 %2, i8* %6
%9 = load i8, i8* %5
%10 = zext i8 %9 to i32
switch i32 %10, label %15 [
i32 0, label %11
i32 255, label %13
]
11: ; preds = %3
%12 = load i8, i8* %6
store i8 %12, i8* %7
br label %44
13: ; preds = %3
%14 = load i8, i8* %4
store i8 %14, i8* %7
br label %44
15: ; preds = %3
%16 = load i8, i8* %4
%17 = zext i8 %16 to i16
%18 = zext i16 %17 to i32
%19 = load i8, i8* %5
%20 = zext i8 %19 to i16
%21 = zext i16 %20 to i32
%22 = mul nsw i32 %18, %21
%23 = load i8, i8* %6
%24 = zext i8 %23 to i16
%25 = zext i16 %24 to i32
%26 = load i8, i8* %5
%27 = zext i8 %26 to i16
%28 = zext i16 %27 to i32
%29 = sub nsw i32 255, %28
%30 = trunc i32 %29 to i16
%31 = zext i16 %30 to i32
%32 = mul nsw i32 %25, %31
%33 = add nsw i32 %22, %32
%34 = add nsw i32 %33, 128
%35 = trunc i32 %34 to i16
store i16 %35, i16* %8
%36 = load i16, i16* %8
%37 = zext i16 %36 to i32
%38 = load i16, i16* %8
%39 = zext i16 %38 to i32
%40 = ashr i32 %39, 8
%41 = add nsw i32 %37, %40
%42 = ashr i32 %41, 8
%43 = trunc i32 %42 to i8
store i8 %43, i8* %7
br label %44
44: ; preds = %15, %13, %11
%45 = load i8, i8* %7
ret i8 %45
}

LLVM IR (-O2):
define zeroext i8 @AlphaComp(i8 zeroext %0, i8 zeroext %1, i8 zeroext %2) {
switch i8 %1, label %5 [
i8 0, label %20
i8 -1, label %4
]
4: ; preds = %3
br label %20
5: ; preds = %3
%6 = zext i8 %0 to i32
%7 = zext i8 %1 to i32
%8 = mul nuw nsw i32 %7, %6
%9 = zext i8 %2 to i32
%10 = xor i8 %1, -1
%11 = zext i8 %10 to i32
%12 = mul nuw nsw i32 %9, %11
%13 = add nuw nsw i32 %8, 128
%14 = add nuw nsw i32 %13, %12
%15 = lshr i32 %14, 8
%16 = and i32 %15, 255
%17 = add nuw nsw i32 %16, %14
%18 = lshr i32 %17, 8
%19 = trunc i32 %18 to i8
br label %20
20: ; preds = %3, %5, %4
%21 = phi i8 [ %19, %5 ], [ %0, %4 ], [ %2, %3 ]
ret i8 %21
}