void uart_putc(char c) {
  unsigned char lsr;
  do {
    lsr = *((volatile unsigned char *)(0x90000000 + 5));
  } while ((lsr & 0x20) != 0x20);
  *((volatile unsigned char *)(0x90000000 + 0)) = c;
  if (c == '\n') {
    do {
      lsr = *((volatile unsigned char *)(0x90000000 + 5));
    } while ((lsr & 0x20) != 0x20);
    *((volatile unsigned char *)(0x90000000 + 0)) = '\r';
  }
  do {
    lsr = *((volatile unsigned char *)(0x90000000 + 5));
  } while ((lsr & (0x40 | 0x20)) != (0x40 | 0x20));
}


x86 assembly (clang, -O0):
<uart_putc>:
push   %rbp
mov    %rsp,%rbp
mov    %dil,%al
mov    %al,-0x1(%rbp)
mov    $0x90000005,%eax
mov    (%rax),%al
mov    %al,-0x2(%rbp)
movzbl -0x2(%rbp),%eax
and    $0x20,%eax
cmp    $0x20,%eax
jne    110a <uart_putc+0xa>
mov    -0x1(%rbp),%cl
mov    $0x90000000,%eax
mov    %cl,(%rax)
movsbl -0x1(%rbp),%eax
cmp    $0xa,%eax
jne    1162 <uart_putc+0x62>
jmp    1140 <uart_putc+0x40>
mov    $0x90000005,%eax
mov    (%rax),%al
mov    %al,-0x2(%rbp)
movzbl -0x2(%rbp),%eax
and    $0x20,%eax
cmp    $0x20,%eax
jne    1140 <uart_putc+0x40>
mov    $0x90000000,%eax
movb   $0xd,(%rax)
jmp    1167 <uart_putc+0x67>
mov    $0x90000005,%eax
mov    (%rax),%al
mov    %al,-0x2(%rbp)
movzbl -0x2(%rbp),%eax
and    $0x60,%eax
cmp    $0x60,%eax
jne    1167 <uart_putc+0x67>
pop    %rbp
ret

x86 assembly (clang, -O2):
<uart_putc>:
mov    $0x90000005,%eax
cs nopw 0x0(%rax,%rax,1)
nop
testb  $0x20,(%rax)
je     1110 <uart_putc+0x10>
mov    %dil,-0x5(%rax)
cmp    $0xa,%dil
jne    1130 <uart_putc+0x30>
nop
testb  $0x20,(%rax)
je     1120 <uart_putc+0x20>
movb   $0xd,-0x5(%rax)
nopl   0x0(%rax)
movzbl (%rax),%ecx
not    %cl
test   $0x60,%cl
jne    1130 <uart_putc+0x30>
ret

LLVM IR (-O0):
define void @uart_putc(i8 signext %0) {
%2 = alloca i8
%3 = alloca i8
store i8 %0, i8* %2
br label %4
4: ; preds = %6, %1
%5 = load volatile i8, i8* inttoptr (i64 2415919109 to i8*)
store i8 %5, i8* %3
br label %6
6: ; preds = %4
%7 = load i8, i8* %3
%8 = zext i8 %7 to i32
%9 = and i32 %8, 32
%10 = icmp ne i32 %9, 32
br i1 %10, label %4, label %11
11: ; preds = %6
%12 = load i8, i8* %2
store volatile i8 %12, i8* inttoptr (i64 2415919104 to i8*)
%13 = load i8, i8* %2
%14 = sext i8 %13 to i32
%15 = icmp eq i32 %14, 10
br i1 %15, label %16, label %25
16: ; preds = %11
br label %17
17: ; preds = %19, %16
%18 = load volatile i8, i8* inttoptr (i64 2415919109 to i8*)
store i8 %18, i8* %3
br label %19
19: ; preds = %17
%20 = load i8, i8* %3
%21 = zext i8 %20 to i32
%22 = and i32 %21, 32
%23 = icmp ne i32 %22, 32
br i1 %23, label %17, label %24
24: ; preds = %19
store volatile i8 13, i8* inttoptr (i64 2415919104 to i8*)
br label %25
25: ; preds = %24, %11
br label %26
26: ; preds = %28, %25
%27 = load volatile i8, i8* inttoptr (i64 2415919109 to i8*)
store i8 %27, i8* %3
br label %28
28: ; preds = %26
%29 = load i8, i8* %3
%30 = zext i8 %29 to i32
%31 = and i32 %30, 96
%32 = icmp ne i32 %31, 96
br i1 %32, label %26, label %33
33: ; preds = %28
ret void
}

LLVM IR (-O2):
define void @uart_putc(i8 signext %0) {
br label %2
2: ; preds = %2, %1
%3 = load volatile i8, i8* inttoptr (i64 2415919109 to i8*)
%4 = and i8 %3, 32
%5 = icmp eq i8 %4, 0
br i1 %5, label %2, label %6
6: ; preds = %2
store volatile i8 %0, i8* inttoptr (i64 2415919104 to i8*)
%7 = icmp eq i8 %0, 10
br i1 %7, label %8, label %13
8: ; preds = %6, %8
%9 = load volatile i8, i8* inttoptr (i64 2415919109 to i8*)
%10 = and i8 %9, 32
%11 = icmp eq i8 %10, 0
br i1 %11, label %8, label %12
12: ; preds = %8
store volatile i8 13, i8* inttoptr (i64 2415919104 to i8*)
br label %13
13: ; preds = %12, %6
br label %14
14: ; preds = %13, %14
%15 = load volatile i8, i8* inttoptr (i64 2415919109 to i8*)
%16 = and i8 %15, 96
%17 = icmp eq i8 %16, 96
br i1 %17, label %18, label %14
18: ; preds = %14
ret void
}