char and (char a, char b) {
  assert(is_binary(a) && is_binary(b));
  if (a == '0' || b == '0')
    return '0';
  else
    return '1';
}


x86 assembly (clang, -O0):
<and>:
push   %rbp
mov    %rsp,%rbp
sub    $0x10,%rsp
mov    %sil,%al
mov    %dil,%cl
mov    %cl,-0x2(%rbp)
mov    %al,-0x3(%rbp)
movsbl -0x2(%rbp),%edi
mov    $0x0,%al
call   1040 <is_binary@plt>
mov    %eax,%ecx
xor    %eax,%eax
cmp    $0x0,%ecx
mov    %al,-0x4(%rbp)
je     1163 <and+0x43>
movsbl -0x3(%rbp),%edi
mov    $0x0,%al
call   1040 <is_binary@plt>
cmp    $0x0,%eax
setne  %al
mov    %al,-0x4(%rbp)
mov    -0x4(%rbp),%al
and    $0x1,%al
movzbl %al,%edi
mov    $0x0,%al
call   1030 <assert@plt>
movsbl -0x2(%rbp),%eax
cmp    $0x30,%eax
je     118c <and+0x6c>
movsbl -0x3(%rbp),%eax
cmp    $0x30,%eax
jne    1195 <and+0x75>
movb   $0x30,-0x1(%rbp)
jmp    1199 <and+0x79>
movb   $0x31,-0x1(%rbp)
movsbl -0x1(%rbp),%eax
add    $0x10,%rsp
pop    %rbp
ret

x86 assembly (clang, -O2):
<and>:
push   %rbp
push   %r14
push   %rbx
mov    %esi,%r14d
mov    %edi,%ebp
xor    %ebx,%ebx
xor    %eax,%eax
call   1040 <is_binary@plt>
test   %eax,%eax
je     1148 <and+0x28>
movsbl %r14b,%edi
xor    %eax,%eax
call   1040 <is_binary@plt>
xor    %ebx,%ebx
test   %eax,%eax
setne  %bl
mov    %ebx,%edi
xor    %eax,%eax
call   1030 <assert@plt>
cmp    $0x30,%bpl
sete   %cl
cmp    $0x30,%r14b
sete   %al
or     %cl,%al
xor    $0x31,%al
pop    %rbx
pop    %r14
pop    %rbp
ret

LLVM IR (-O0):
define signext i8 @and(i8 signext %0, i8 signext %1) {
%3 = alloca i8
%4 = alloca i8
%5 = alloca i8
store i8 %0, i8* %4
store i8 %1, i8* %5
%6 = load i8, i8* %4
%7 = sext i8 %6 to i32
%8 = call i32 (i32, ...) bitcast (i32 (...)* @is_binary to i32 (i32, ...)*)(i32 %7)
%9 = icmp ne i32 %8, 0
br i1 %9, label %10, label %15
10: ; preds = %2
%11 = load i8, i8* %5
%12 = sext i8 %11 to i32
%13 = call i32 (i32, ...) bitcast (i32 (...)* @is_binary to i32 (i32, ...)*)(i32 %12)
%14 = icmp ne i32 %13, 0
br label %15
15: ; preds = %10, %2
%16 = phi i1 [ false, %2 ], [ %14, %10 ]
%17 = zext i1 %16 to i32
%18 = call i32 (i32, ...) bitcast (i32 (...)* @assert to i32 (i32, ...)*)(i32 %17)
%19 = load i8, i8* %4
%20 = sext i8 %19 to i32
%21 = icmp eq i32 %20, 48
br i1 %21, label %26, label %22
22: ; preds = %15
%23 = load i8, i8* %5
%24 = sext i8 %23 to i32
%25 = icmp eq i32 %24, 48
br i1 %25, label %26, label %27
26: ; preds = %22, %15
store i8 48, i8* %3
br label %28
27: ; preds = %22
store i8 49, i8* %3
br label %28
28: ; preds = %27, %26
%29 = load i8, i8* %3
ret i8 %29
}

LLVM IR (-O2):
define signext i8 @and(i8 signext %0, i8 signext %1) {
%3 = sext i8 %0 to i32
%4 = tail call i32 (i32, ...) bitcast (i32 (...)* @is_binary to i32 (i32, ...)*)(i32 %3)
%5 = icmp eq i32 %4, 0
br i1 %5, label %11, label %6
6: ; preds = %2
%7 = sext i8 %1 to i32
%8 = tail call i32 (i32, ...) bitcast (i32 (...)* @is_binary to i32 (i32, ...)*)(i32 %7)
%9 = icmp ne i32 %8, 0
%10 = zext i1 %9 to i32
br label %11
11: ; preds = %6, %2
%12 = phi i32 [ 0, %2 ], [ %10, %6 ]
%13 = tail call i32 (i32, ...) bitcast (i32 (...)* @assert to i32 (i32, ...)*)(i32 %12)
%14 = icmp eq i8 %0, 48
%15 = icmp eq i8 %1, 48
%16 = or i1 %14, %15
%17 = select i1 %16, i8 48, i8 49
ret i8 %17
}