void putstr(const char *s) {
  unsigned long serial_port;
  do {
    serial_port = 0x206000;
    if ((*(volatile unsigned long *)(serial_port + (0x80))) & 1)
      break;
    serial_port = 0x207000;
    if ((*(volatile unsigned long *)(serial_port + (0x80))) & 1)
      break;
    return;
  } while (0);
  while (*s) {
    while (!((*(volatile unsigned long *)(serial_port + (0x98))) & (1 << 14)))
      barrier();
    (*(volatile unsigned long *)(serial_port + (0x40))) = *s;
    if (*s == '\n') {
      while (!((*(volatile unsigned long *)(serial_port + (0x98))) & (1 << 14)))
        barrier();
      (*(volatile unsigned long *)(serial_port + (0x40))) = '\r';
    }
    s++;
  }
}


x86 assembly (clang, -O0):
<putstr>:
push   %rbp
mov    %rsp,%rbp
sub    $0x10,%rsp
mov    %rdi,-0x8(%rbp)
movq   $0x206000,-0x10(%rbp)
mov    -0x10(%rbp),%rax
mov    0x80(%rax),%rax
and    $0x1,%rax
cmp    $0x0,%rax
je     1142 <putstr+0x32>
jmp    116d <putstr+0x5d>
movq   $0x207000,-0x10(%rbp)
mov    -0x10(%rbp),%rax
mov    0x80(%rax),%rax
and    $0x1,%rax
cmp    $0x0,%rax
je     1168 <putstr+0x58>
jmp    116d <putstr+0x5d>
jmp    122c <putstr+0x11c>
jmp    1172 <putstr+0x62>
mov    -0x8(%rbp),%rax
cmpb   $0x0,(%rax)
je     122c <putstr+0x11c>
jmp    1184 <putstr+0x74>
mov    -0x10(%rbp),%rax
mov    0x98(%rax),%rax
and    $0x4000,%rax
cmp    $0x0,%rax
setne  %al
xor    $0xff,%al
test   $0x1,%al
jne    11ab <putstr+0x9b>
jmp    11b7 <putstr+0xa7>
mov    $0x0,%al
call   1030 <barrier@plt>
jmp    1184 <putstr+0x74>
mov    -0x8(%rbp),%rax
movsbq (%rax),%rcx
mov    -0x10(%rbp),%rax
mov    %rcx,0x40(%rax)
mov    -0x8(%rbp),%rax
movsbl (%rax),%eax
cmp    $0xa,%eax
jne    121b <putstr+0x10b>
jmp    11dc <putstr+0xcc>
mov    -0x10(%rbp),%rax
mov    0x98(%rax),%rax
and    $0x4000,%rax
cmp    $0x0,%rax
setne  %al
xor    $0xff,%al
test   $0x1,%al
jne    1203 <putstr+0xf3>
jmp    120f <putstr+0xff>
mov    $0x0,%al
call   1030 <barrier@plt>
jmp    11dc <putstr+0xcc>
mov    -0x10(%rbp),%rax
movq   $0xd,0x40(%rax)
mov    -0x8(%rbp),%rax
add    $0x1,%rax
mov    %rax,-0x8(%rbp)
jmp    1172 <putstr+0x62>
add    $0x10,%rsp
pop    %rbp
ret

x86 assembly (clang, -O2):
<putstr>:
push   %r15
push   %r14
push   %rbx
mov    %rdi,%r15
mov    0x206080,%rax
mov    $0x206000,%r14d
test   $0x1,%al
jne    113e <putstr+0x2e>
mov    $0x207000,%r14d
testq  $0x1,0x207080
je     11bb <putstr+0xab>
mov    (%r15),%al
test   %al,%al
je     11bb <putstr+0xab>
mov    %r14,%rbx
or     $0x98,%rbx
or     $0x40,%r14
jmp    1173 <putstr+0x63>
cs nopw 0x0(%rax,%rax,1)
nop
movq   $0xd,(%r14)
mov    0x1(%r15),%al
add    $0x1,%r15
test   %al,%al
je     11bb <putstr+0xab>
testq  $0x4000,(%rbx)
jne    1193 <putstr+0x83>
nopl   0x0(%rax)
xor    %eax,%eax
call   1030 <barrier@plt>
testq  $0x4000,(%rbx)
je     1180 <putstr+0x70>
mov    (%r15),%al
movsbq %al,%rax
mov    %rax,(%r14)
cmpb   $0xa,(%r15)
jne    1167 <putstr+0x57>
testq  $0x4000,(%rbx)
jne    1160 <putstr+0x50>
xor    %eax,%eax
call   1030 <barrier@plt>
testq  $0x4000,(%rbx)
je     11a9 <putstr+0x99>
jmp    1160 <putstr+0x50>
pop    %rbx
pop    %r14
pop    %r15
ret

LLVM IR (-O0):
define void @putstr(i8* %0) {
%2 = alloca i8*
%3 = alloca i64
store i8* %0, i8** %2
br label %4
4: ; preds = %1
store i64 2121728, i64* %3
%5 = load i64, i64* %3
%6 = add i64 %5, 128
%7 = inttoptr i64 %6 to i64*
%8 = load volatile i64, i64* %7
%9 = and i64 %8, 1
%10 = icmp ne i64 %9, 0
br i1 %10, label %11, label %12
11: ; preds = %4
br label %21
12: ; preds = %4
store i64 2125824, i64* %3
%13 = load i64, i64* %3
%14 = add i64 %13, 128
%15 = inttoptr i64 %14 to i64*
%16 = load volatile i64, i64* %15
%17 = and i64 %16, 1
%18 = icmp ne i64 %17, 0
br i1 %18, label %19, label %20
19: ; preds = %12
br label %21
20: ; preds = %12
br label %66
21: ; preds = %19, %11
br label %22
22: ; preds = %63, %21
%23 = load i8*, i8** %2
%24 = load i8, i8* %23
%25 = icmp ne i8 %24, 0
br i1 %25, label %26, label %66
26: ; preds = %22
br label %27
27: ; preds = %35, %26
%28 = load i64, i64* %3
%29 = add i64 %28, 152
%30 = inttoptr i64 %29 to i64*
%31 = load volatile i64, i64* %30
%32 = and i64 %31, 16384
%33 = icmp ne i64 %32, 0
%34 = xor i1 %33, true
br i1 %34, label %35, label %37
35: ; preds = %27
%36 = call i32 (...) @barrier()
br label %27
37: ; preds = %27
%38 = load i8*, i8** %2
%39 = load i8, i8* %38
%40 = sext i8 %39 to i64
%41 = load i64, i64* %3
%42 = add i64 %41, 64
%43 = inttoptr i64 %42 to i64*
store volatile i64 %40, i64* %43
%44 = load i8*, i8** %2
%45 = load i8, i8* %44
%46 = sext i8 %45 to i32
%47 = icmp eq i32 %46, 10
br i1 %47, label %48, label %63
48: ; preds = %37
br label %49
49: ; preds = %57, %48
%50 = load i64, i64* %3
%51 = add i64 %50, 152
%52 = inttoptr i64 %51 to i64*
%53 = load volatile i64, i64* %52
%54 = and i64 %53, 16384
%55 = icmp ne i64 %54, 0
%56 = xor i1 %55, true
br i1 %56, label %57, label %59
57: ; preds = %49
%58 = call i32 (...) @barrier()
br label %49
59: ; preds = %49
%60 = load i64, i64* %3
%61 = add i64 %60, 64
%62 = inttoptr i64 %61 to i64*
store volatile i64 13, i64* %62
br label %63
63: ; preds = %59, %37
%64 = load i8*, i8** %2
%65 = getelementptr inbounds i8, i8* %64, i32 1
store i8* %65, i8** %2
br label %22
66: ; preds = %20, %22
ret void
}

LLVM IR (-O2):
define void @putstr(i8* nocapture %0) {
%2 = load volatile i64, i64* inttoptr (i64 2121856 to i64*)
%3 = and i64 %2, 1
%4 = icmp eq i64 %3, 0
br i1 %4, label %5, label %9
5: ; preds = %1
%6 = load volatile i64, i64* inttoptr (i64 2125952 to i64*)
%7 = and i64 %6, 1
%8 = icmp eq i64 %7, 0
br i1 %8, label %50, label %9
9: ; preds = %5, %1
%10 = phi i64 [ 2121728, %1 ], [ 2125824, %5 ]
%11 = load i8, i8* %0
%12 = icmp eq i8 %11, 0
br i1 %12, label %50, label %13
13: ; preds = %9
%14 = or i64 %10, 152
%15 = inttoptr i64 %14 to i64*
%16 = or i64 %10, 64
%17 = inttoptr i64 %16 to i64*
br label %18
18: ; preds = %13, %46
%19 = phi i8 [ %11, %13 ], [ %48, %46 ]
%20 = phi i8* [ %0, %13 ], [ %47, %46 ]
%21 = load volatile i64, i64* %15
%22 = and i64 %21, 16384
%23 = icmp eq i64 %22, 0
br i1 %23, label %24, label %31
24: ; preds = %18, %24
%25 = tail call i32 (...) @barrier()
%26 = load volatile i64, i64* %15
%27 = and i64 %26, 16384
%28 = icmp eq i64 %27, 0
br i1 %28, label %24, label %29
29: ; preds = %24
%30 = load i8, i8* %20
br label %31
31: ; preds = %29, %18
%32 = phi i8 [ %30, %29 ], [ %19, %18 ]
%33 = sext i8 %32 to i64
store volatile i64 %33, i64* %17
%34 = load i8, i8* %20
%35 = icmp eq i8 %34, 10
br i1 %35, label %36, label %46
36: ; preds = %31
%37 = load volatile i64, i64* %15
%38 = and i64 %37, 16384
%39 = icmp eq i64 %38, 0
br i1 %39, label %40, label %45
40: ; preds = %36, %40
%41 = tail call i32 (...) @barrier()
%42 = load volatile i64, i64* %15
%43 = and i64 %42, 16384
%44 = icmp eq i64 %43, 0
br i1 %44, label %40, label %45
45: ; preds = %40, %36
store volatile i64 13, i64* %17
br label %46
46: ; preds = %45, %31
%47 = getelementptr inbounds i8, i8* %20, i64 1
%48 = load i8, i8* %47
%49 = icmp eq i8 %48, 0
br i1 %49, label %50, label %18
50: ; preds = %46, %9, %5
ret void
}