int serial_getc(void) {
  unsigned char ch;
  while (((*((volatile unsigned *)((0xc8100000 | (0x01 << 10) | (0x30 << 2)) +
                                   (3 << 2)))) &
          (0x7f << 0)) == 0)
    ;
  if ((*((volatile unsigned *)((0xc8100000 | (0x01 << 10) | (0x30 << 2)) +
                               (3 << 2)))) &
      ((1 << 16) | (1 << 17))) {
    (*((volatile unsigned *)((0xc8100000 | (0x01 << 10) | (0x30 << 2)) +
                             (2 << 2))) =
         (*((volatile unsigned *)((0xc8100000 | (0x01 << 10) | (0x30 << 2)) +
                                  (2 << 2)))) |
         ((1 << 24)));
    (*((volatile unsigned *)((0xc8100000 | (0x01 << 10) | (0x30 << 2)) +
                             (2 << 2))) =
         (*((volatile unsigned *)((0xc8100000 | (0x01 << 10) | (0x30 << 2)) +
                                  (2 << 2)))) &
         (~((1 << 24))));
  }
  ch = (*((volatile unsigned *)((0xc8100000 | (0x01 << 10) | (0x30 << 2)) +
                                (1 << 2)))) &
       0x00ff;
  return ((int)ch);
}


x86 assembly (clang, -O0):
<serial_getc>:
push   %rbp
mov    %rsp,%rbp
mov    $0xc81004cc,%eax
mov    (%rax),%eax
and    $0x7f,%eax
cmp    $0x0,%eax
jne    111c <serial_getc+0x1c>
jmp    1104 <serial_getc+0x4>
mov    $0xc81004cc,%eax
mov    (%rax),%eax
and    $0x30000,%eax
cmp    $0x0,%eax
je     1159 <serial_getc+0x59>
mov    $0xc81004c8,%eax
mov    (%rax),%ecx
or     $0x1000000,%ecx
mov    $0xc81004c8,%eax
mov    %ecx,(%rax)
mov    $0xc81004c8,%eax
mov    (%rax),%ecx
and    $0xfeffffff,%ecx
mov    $0xc81004c8,%eax
mov    %ecx,(%rax)
mov    $0xc81004c4,%eax
mov    (%rax),%eax
and    $0xff,%eax
mov    %al,-0x1(%rbp)
movzbl -0x1(%rbp),%eax
pop    %rbp
ret

x86 assembly (clang, -O2):
<serial_getc>:
mov    $0xc81004c8,%eax
cs nopw 0x0(%rax,%rax,1)
nop
testl  $0x7f,0x4(%rax)
je     1110 <serial_getc+0x10>
testl  $0x30000,0x4(%rax)
je     112e <serial_getc+0x2e>
orl    $0x1000000,(%rax)
andl   $0xfeffffff,(%rax)
mov    -0x4(%rax),%eax
movzbl %al,%eax
ret

LLVM IR (-O0):
define i32 @serial_getc() {
%1 = alloca i8
br label %2
2: ; preds = %6, %0
%3 = load volatile i32, i32* inttoptr (i64 3356493004 to i32*)
%4 = and i32 %3, 127
%5 = icmp eq i32 %4, 0
br i1 %5, label %6, label %7
6: ; preds = %2
br label %2
7: ; preds = %2
%8 = load volatile i32, i32* inttoptr (i64 3356493004 to i32*)
%9 = and i32 %8, 196608
%10 = icmp ne i32 %9, 0
br i1 %10, label %11, label %16
11: ; preds = %7
%12 = load volatile i32, i32* inttoptr (i64 3356493000 to i32*)
%13 = or i32 %12, 16777216
store volatile i32 %13, i32* inttoptr (i64 3356493000 to i32*)
%14 = load volatile i32, i32* inttoptr (i64 3356493000 to i32*)
%15 = and i32 %14, -16777217
store volatile i32 %15, i32* inttoptr (i64 3356493000 to i32*)
br label %16
16: ; preds = %11, %7
%17 = load volatile i32, i32* inttoptr (i64 3356492996 to i32*)
%18 = and i32 %17, 255
%19 = trunc i32 %18 to i8
store i8 %19, i8* %1
%20 = load i8, i8* %1
%21 = zext i8 %20 to i32
ret i32 %21
}

LLVM IR (-O2):
define i32 @serial_getc() {
br label %1
1: ; preds = %1, %0
%2 = load volatile i32, i32* inttoptr (i64 3356493004 to i32*)
%3 = and i32 %2, 127
%4 = icmp eq i32 %3, 0
br i1 %4, label %1, label %5
5: ; preds = %1
%6 = load volatile i32, i32* inttoptr (i64 3356493004 to i32*)
%7 = and i32 %6, 196608
%8 = icmp eq i32 %7, 0
br i1 %8, label %14, label %9
9: ; preds = %5
%10 = load volatile i32, i32* inttoptr (i64 3356493000 to i32*)
%11 = or i32 %10, 16777216
store volatile i32 %11, i32* inttoptr (i64 3356493000 to i32*)
%12 = load volatile i32, i32* inttoptr (i64 3356493000 to i32*)
%13 = and i32 %12, -16777217
store volatile i32 %13, i32* inttoptr (i64 3356493000 to i32*)
br label %14
14: ; preds = %9, %5
%15 = load volatile i32, i32* inttoptr (i64 3356492996 to i32*)
%16 = and i32 %15, 255
ret i32 %16
}