[AArch64] Add Tiny Code Model for AArch64

This adds the plumbing for the Tiny code model for the AArch64 backend. This,
instead of loading addresses through the normal ADRP;ADD pair used in the Small
model, uses a single ADR. The 21 bit range of an ADR means that the code and
its statically defined symbols need to be within 1MB of each other.

This makes it mostly interesting for embedded applications where we want to fit
as much as we can in as small a space as possible.

Differential Revision: https://reviews.llvm.org/D49673

llvm-svn: 340397
diff --git a/llvm/test/CodeGen/AArch64/tiny_model.ll b/llvm/test/CodeGen/AArch64/tiny_model.ll
new file mode 100644
index 0000000..ecf0d76
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/tiny_model.ll
@@ -0,0 +1,421 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -verify-machineinstrs -o - -mtriple=aarch64-none-linux-gnu -code-model=tiny < %s | FileCheck %s
+; RUN: llc -verify-machineinstrs -o - -mtriple=aarch64-none-linux-gnu -code-model=tiny -fast-isel < %s | FileCheck %s
+; RUN: llc -verify-machineinstrs -o - -mtriple=aarch64-none-linux-gnu -code-model=tiny -global-isel < %s | FileCheck %s --check-prefix=CHECK-GLOBISEL
+; RUN: llc -verify-machineinstrs -o - -mtriple=aarch64-none-linux-gnu -code-model=tiny -relocation-model=pic < %s | FileCheck %s --check-prefix=CHECK-PIC
+; RUN: llc -verify-machineinstrs -o - -mtriple=aarch64-none-linux-gnu -code-model=tiny -relocation-model=pic -fast-isel < %s | FileCheck %s --check-prefix=CHECK-PIC
+; RUN: llc -verify-machineinstrs -o - -mtriple=aarch64-none-linux-gnu -code-model=tiny -relocation-model=pic -global-isel < %s | FileCheck %s --check-prefix=CHECK-PIC-GLOBISEL
+
+; Note fast-isel tests here will fall back to isel
+
+@src = external local_unnamed_addr global [65536 x i8], align 1
+@dst = external global [65536 x i8], align 1
+@ptr = external local_unnamed_addr global i8*, align 8
+
+define void @foo1() {
+; CHECK-LABEL: foo1:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    adr x8, src
+; CHECK-NEXT:    ldrb w8, [x8]
+; CHECK-NEXT:    adr x9, dst
+; CHECK-NEXT:    strb w8, [x9]
+; CHECK-NEXT:    ret
+;
+; CHECK-GLOBISEL-LABEL: foo1:
+; CHECK-GLOBISEL:       // %bb.0: // %entry
+; CHECK-GLOBISEL-NEXT:    adr x8, src
+; CHECK-GLOBISEL-NEXT:    ldrb w8, [x8]
+; CHECK-GLOBISEL-NEXT:    adr x9, dst
+; CHECK-GLOBISEL-NEXT:    strb w8, [x9]
+; CHECK-GLOBISEL-NEXT:    ret
+;
+; CHECK-PIC-LABEL: foo1:
+; CHECK-PIC:       // %bb.0: // %entry
+; CHECK-PIC-NEXT:    ldr x8, :got:src
+; CHECK-PIC-NEXT:    ldrb w8, [x8]
+; CHECK-PIC-NEXT:    ldr x9, :got:dst
+; CHECK-PIC-NEXT:    strb w8, [x9]
+; CHECK-PIC-NEXT:    ret
+;
+; CHECK-PIC-GLOBISEL-LABEL: foo1:
+; CHECK-PIC-GLOBISEL:       // %bb.0: // %entry
+; CHECK-PIC-GLOBISEL-NEXT:    ldr x8, :got:src
+; CHECK-PIC-GLOBISEL-NEXT:    ldrb w8, [x8]
+; CHECK-PIC-GLOBISEL-NEXT:    ldr x9, :got:dst
+; CHECK-PIC-GLOBISEL-NEXT:    strb w8, [x9]
+; CHECK-PIC-GLOBISEL-NEXT:    ret
+entry:
+  %0 = load i8, i8* getelementptr inbounds ([65536 x i8], [65536 x i8]* @src, i64 0, i64 0), align 1
+  store i8 %0, i8* getelementptr inbounds ([65536 x i8], [65536 x i8]* @dst, i64 0, i64 0), align 1
+  ret void
+}
+
+define void @foo2() {
+; CHECK-LABEL: foo2:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    adr x8, ptr
+; CHECK-NEXT:    adr x9, dst
+; CHECK-NEXT:    str x9, [x8]
+; CHECK-NEXT:    ret
+;
+; CHECK-GLOBISEL-LABEL: foo2:
+; CHECK-GLOBISEL:       // %bb.0: // %entry
+; CHECK-GLOBISEL-NEXT:    adr x8, dst
+; CHECK-GLOBISEL-NEXT:    adr x9, ptr
+; CHECK-GLOBISEL-NEXT:    str x8, [x9]
+; CHECK-GLOBISEL-NEXT:    ret
+;
+; CHECK-PIC-LABEL: foo2:
+; CHECK-PIC:       // %bb.0: // %entry
+; CHECK-PIC-NEXT:    ldr x8, :got:ptr
+; CHECK-PIC-NEXT:    ldr x9, :got:dst
+; CHECK-PIC-NEXT:    str x9, [x8]
+; CHECK-PIC-NEXT:    ret
+;
+; CHECK-PIC-GLOBISEL-LABEL: foo2:
+; CHECK-PIC-GLOBISEL:       // %bb.0: // %entry
+; CHECK-PIC-GLOBISEL-NEXT:    ldr x8, :got:dst
+; CHECK-PIC-GLOBISEL-NEXT:    ldr x9, :got:ptr
+; CHECK-PIC-GLOBISEL-NEXT:    str x8, [x9]
+; CHECK-PIC-GLOBISEL-NEXT:    ret
+entry:
+  store i8* getelementptr inbounds ([65536 x i8], [65536 x i8]* @dst, i64 0, i64 0), i8** @ptr, align 8
+  ret void
+}
+
+define void @foo3() {
+; FIXME: Needn't adr ptr
+;
+; CHECK-LABEL: foo3:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    adr x8, src
+; CHECK-NEXT:    adr x9, ptr
+; CHECK-NEXT:    ldrb w8, [x8]
+; CHECK-NEXT:    ldr x9, [x9]
+; CHECK-NEXT:    strb w8, [x9]
+; CHECK-NEXT:    ret
+;
+; CHECK-GLOBISEL-LABEL: foo3:
+; CHECK-GLOBISEL:       // %bb.0: // %entry
+; CHECK-GLOBISEL-NEXT:    adr x8, src
+; CHECK-GLOBISEL-NEXT:    adr x9, ptr
+; CHECK-GLOBISEL-NEXT:    ldrb w8, [x8]
+; CHECK-GLOBISEL-NEXT:    ldr x9, [x9]
+; CHECK-GLOBISEL-NEXT:    strb w8, [x9]
+; CHECK-GLOBISEL-NEXT:    ret
+;
+; CHECK-PIC-LABEL: foo3:
+; CHECK-PIC:       // %bb.0: // %entry
+; CHECK-PIC-NEXT:    ldr x8, :got:src
+; CHECK-PIC-NEXT:    ldr x9, :got:ptr
+; CHECK-PIC-NEXT:    ldrb w8, [x8]
+; CHECK-PIC-NEXT:    ldr x9, [x9]
+; CHECK-PIC-NEXT:    strb w8, [x9]
+; CHECK-PIC-NEXT:    ret
+;
+; CHECK-PIC-GLOBISEL-LABEL: foo3:
+; CHECK-PIC-GLOBISEL:       // %bb.0: // %entry
+; CHECK-PIC-GLOBISEL-NEXT:    ldr x8, :got:src
+; CHECK-PIC-GLOBISEL-NEXT:    ldr x9, :got:ptr
+; CHECK-PIC-GLOBISEL-NEXT:    ldrb w8, [x8]
+; CHECK-PIC-GLOBISEL-NEXT:    ldr x9, [x9]
+; CHECK-PIC-GLOBISEL-NEXT:    strb w8, [x9]
+; CHECK-PIC-GLOBISEL-NEXT:    ret
+entry:
+  %0 = load i8, i8* getelementptr inbounds ([65536 x i8], [65536 x i8]* @src, i64 0, i64 0), align 1
+  %1 = load i8*, i8** @ptr, align 8
+  store i8 %0, i8* %1, align 1
+  ret void
+}
+
+@lsrc = internal global i8 0, align 4
+@ldst = internal global i8 0, align 4
+@lptr = internal global i8* null, align 8
+
+define void @bar1() {
+; CHECK-LABEL: bar1:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    adr x8, lsrc
+; CHECK-NEXT:    ldrb w8, [x8]
+; CHECK-NEXT:    adr x9, ldst
+; CHECK-NEXT:    strb w8, [x9]
+; CHECK-NEXT:    ret
+;
+; CHECK-GLOBISEL-LABEL: bar1:
+; CHECK-GLOBISEL:       // %bb.0: // %entry
+; CHECK-GLOBISEL-NEXT:    adr x8, lsrc
+; CHECK-GLOBISEL-NEXT:    ldrb w8, [x8]
+; CHECK-GLOBISEL-NEXT:    adr x9, ldst
+; CHECK-GLOBISEL-NEXT:    strb w8, [x9]
+; CHECK-GLOBISEL-NEXT:    ret
+;
+; CHECK-PIC-LABEL: bar1:
+; CHECK-PIC:       // %bb.0: // %entry
+; CHECK-PIC-NEXT:    adr x8, lsrc
+; CHECK-PIC-NEXT:    ldrb w8, [x8]
+; CHECK-PIC-NEXT:    adr x9, ldst
+; CHECK-PIC-NEXT:    strb w8, [x9]
+; CHECK-PIC-NEXT:    ret
+;
+; CHECK-PIC-GLOBISEL-LABEL: bar1:
+; CHECK-PIC-GLOBISEL:       // %bb.0: // %entry
+; CHECK-PIC-GLOBISEL-NEXT:    adr x8, lsrc
+; CHECK-PIC-GLOBISEL-NEXT:    ldrb w8, [x8]
+; CHECK-PIC-GLOBISEL-NEXT:    adr x9, ldst
+; CHECK-PIC-GLOBISEL-NEXT:    strb w8, [x9]
+; CHECK-PIC-GLOBISEL-NEXT:    ret
+entry:
+  %0 = load i8, i8* @lsrc, align 4
+  store i8 %0, i8* @ldst, align 4
+  ret void
+}
+
+define void @bar2() {
+; CHECK-LABEL: bar2:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    adr x8, lptr
+; CHECK-NEXT:    adr x9, ldst
+; CHECK-NEXT:    str x9, [x8]
+; CHECK-NEXT:    ret
+;
+; CHECK-GLOBISEL-LABEL: bar2:
+; CHECK-GLOBISEL:       // %bb.0: // %entry
+; CHECK-GLOBISEL-NEXT:    adr x8, ldst
+; CHECK-GLOBISEL-NEXT:    adr x9, lptr
+; CHECK-GLOBISEL-NEXT:    str x8, [x9]
+; CHECK-GLOBISEL-NEXT:    ret
+;
+; CHECK-PIC-LABEL: bar2:
+; CHECK-PIC:       // %bb.0: // %entry
+; CHECK-PIC-NEXT:    adr x8, lptr
+; CHECK-PIC-NEXT:    adr x9, ldst
+; CHECK-PIC-NEXT:    str x9, [x8]
+; CHECK-PIC-NEXT:    ret
+;
+; CHECK-PIC-GLOBISEL-LABEL: bar2:
+; CHECK-PIC-GLOBISEL:       // %bb.0: // %entry
+; CHECK-PIC-GLOBISEL-NEXT:    adr x8, ldst
+; CHECK-PIC-GLOBISEL-NEXT:    adr x9, lptr
+; CHECK-PIC-GLOBISEL-NEXT:    str x8, [x9]
+; CHECK-PIC-GLOBISEL-NEXT:    ret
+entry:
+  store i8* @ldst, i8** @lptr, align 8
+  ret void
+}
+
+define void @bar3() {
+; FIXME: Needn't adr lptr
+;
+; CHECK-LABEL: bar3:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    adr x8, lsrc
+; CHECK-NEXT:    adr x9, lptr
+; CHECK-NEXT:    ldrb w8, [x8]
+; CHECK-NEXT:    ldr x9, [x9]
+; CHECK-NEXT:    strb w8, [x9]
+; CHECK-NEXT:    ret
+;
+; CHECK-GLOBISEL-LABEL: bar3:
+; CHECK-GLOBISEL:       // %bb.0: // %entry
+; CHECK-GLOBISEL-NEXT:    adr x8, lsrc
+; CHECK-GLOBISEL-NEXT:    adr x9, lptr
+; CHECK-GLOBISEL-NEXT:    ldrb w8, [x8]
+; CHECK-GLOBISEL-NEXT:    ldr x9, [x9]
+; CHECK-GLOBISEL-NEXT:    strb w8, [x9]
+; CHECK-GLOBISEL-NEXT:    ret
+;
+; CHECK-PIC-LABEL: bar3:
+; CHECK-PIC:       // %bb.0: // %entry
+; CHECK-PIC-NEXT:    adr x8, lsrc
+; CHECK-PIC-NEXT:    adr x9, lptr
+; CHECK-PIC-NEXT:    ldrb w8, [x8]
+; CHECK-PIC-NEXT:    ldr x9, [x9]
+; CHECK-PIC-NEXT:    strb w8, [x9]
+; CHECK-PIC-NEXT:    ret
+;
+; CHECK-PIC-GLOBISEL-LABEL: bar3:
+; CHECK-PIC-GLOBISEL:       // %bb.0: // %entry
+; CHECK-PIC-GLOBISEL-NEXT:    adr x8, lsrc
+; CHECK-PIC-GLOBISEL-NEXT:    adr x9, lptr
+; CHECK-PIC-GLOBISEL-NEXT:    ldrb w8, [x8]
+; CHECK-PIC-GLOBISEL-NEXT:    ldr x9, [x9]
+; CHECK-PIC-GLOBISEL-NEXT:    strb w8, [x9]
+; CHECK-PIC-GLOBISEL-NEXT:    ret
+entry:
+  %0 = load i8, i8* @lsrc, align 4
+  %1 = load i8*, i8** @lptr, align 8
+  store i8 %0, i8* %1, align 1
+  ret void
+}
+
+
+@lbsrc = internal global [65536 x i8] zeroinitializer, align 4
+@lbdst = internal global [65536 x i8] zeroinitializer, align 4
+
+define void @baz1() {
+; CHECK-LABEL: baz1:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    adr x8, lbsrc
+; CHECK-NEXT:    ldrb w8, [x8]
+; CHECK-NEXT:    adr x9, lbdst
+; CHECK-NEXT:    strb w8, [x9]
+; CHECK-NEXT:    ret
+;
+; CHECK-GLOBISEL-LABEL: baz1:
+; CHECK-GLOBISEL:       // %bb.0: // %entry
+; CHECK-GLOBISEL-NEXT:    adr x8, lbsrc
+; CHECK-GLOBISEL-NEXT:    ldrb w8, [x8]
+; CHECK-GLOBISEL-NEXT:    adr x9, lbdst
+; CHECK-GLOBISEL-NEXT:    strb w8, [x9]
+; CHECK-GLOBISEL-NEXT:    ret
+;
+; CHECK-PIC-LABEL: baz1:
+; CHECK-PIC:       // %bb.0: // %entry
+; CHECK-PIC-NEXT:    adr x8, lbsrc
+; CHECK-PIC-NEXT:    ldrb w8, [x8]
+; CHECK-PIC-NEXT:    adr x9, lbdst
+; CHECK-PIC-NEXT:    strb w8, [x9]
+; CHECK-PIC-NEXT:    ret
+;
+; CHECK-PIC-GLOBISEL-LABEL: baz1:
+; CHECK-PIC-GLOBISEL:       // %bb.0: // %entry
+; CHECK-PIC-GLOBISEL-NEXT:    adr x8, lbsrc
+; CHECK-PIC-GLOBISEL-NEXT:    ldrb w8, [x8]
+; CHECK-PIC-GLOBISEL-NEXT:    adr x9, lbdst
+; CHECK-PIC-GLOBISEL-NEXT:    strb w8, [x9]
+; CHECK-PIC-GLOBISEL-NEXT:    ret
+entry:
+  %0 = load i8, i8* getelementptr inbounds ([65536 x i8], [65536 x i8]* @lbsrc, i64 0, i64 0), align 4
+  store i8 %0, i8* getelementptr inbounds ([65536 x i8], [65536 x i8]* @lbdst, i64 0, i64 0), align 4
+  ret void
+}
+
+define void @baz2() {
+; CHECK-LABEL: baz2:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    adr x8, lptr
+; CHECK-NEXT:    adr x9, lbdst
+; CHECK-NEXT:    str x9, [x8]
+; CHECK-NEXT:    ret
+;
+; CHECK-GLOBISEL-LABEL: baz2:
+; CHECK-GLOBISEL:       // %bb.0: // %entry
+; CHECK-GLOBISEL-NEXT:    adr x8, lbdst
+; CHECK-GLOBISEL-NEXT:    adr x9, lptr
+; CHECK-GLOBISEL-NEXT:    str x8, [x9]
+; CHECK-GLOBISEL-NEXT:    ret
+;
+; CHECK-PIC-LABEL: baz2:
+; CHECK-PIC:       // %bb.0: // %entry
+; CHECK-PIC-NEXT:    adr x8, lptr
+; CHECK-PIC-NEXT:    adr x9, lbdst
+; CHECK-PIC-NEXT:    str x9, [x8]
+; CHECK-PIC-NEXT:    ret
+;
+; CHECK-PIC-GLOBISEL-LABEL: baz2:
+; CHECK-PIC-GLOBISEL:       // %bb.0: // %entry
+; CHECK-PIC-GLOBISEL-NEXT:    adr x8, lbdst
+; CHECK-PIC-GLOBISEL-NEXT:    adr x9, lptr
+; CHECK-PIC-GLOBISEL-NEXT:    str x8, [x9]
+; CHECK-PIC-GLOBISEL-NEXT:    ret
+entry:
+  store i8* getelementptr inbounds ([65536 x i8], [65536 x i8]* @lbdst, i64 0, i64 0), i8** @lptr, align 8
+  ret void
+}
+
+define void @baz3() {
+; FIXME: Needn't adr lptr
+;
+; CHECK-LABEL: baz3:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    adr x8, lbsrc
+; CHECK-NEXT:    adr x9, lptr
+; CHECK-NEXT:    ldrb w8, [x8]
+; CHECK-NEXT:    ldr x9, [x9]
+; CHECK-NEXT:    strb w8, [x9]
+; CHECK-NEXT:    ret
+;
+; CHECK-GLOBISEL-LABEL: baz3:
+; CHECK-GLOBISEL:       // %bb.0: // %entry
+; CHECK-GLOBISEL-NEXT:    adr x8, lbsrc
+; CHECK-GLOBISEL-NEXT:    adr x9, lptr
+; CHECK-GLOBISEL-NEXT:    ldrb w8, [x8]
+; CHECK-GLOBISEL-NEXT:    ldr x9, [x9]
+; CHECK-GLOBISEL-NEXT:    strb w8, [x9]
+; CHECK-GLOBISEL-NEXT:    ret
+;
+; CHECK-PIC-LABEL: baz3:
+; CHECK-PIC:       // %bb.0: // %entry
+; CHECK-PIC-NEXT:    adr x8, lbsrc
+; CHECK-PIC-NEXT:    adr x9, lptr
+; CHECK-PIC-NEXT:    ldrb w8, [x8]
+; CHECK-PIC-NEXT:    ldr x9, [x9]
+; CHECK-PIC-NEXT:    strb w8, [x9]
+; CHECK-PIC-NEXT:    ret
+;
+; CHECK-PIC-GLOBISEL-LABEL: baz3:
+; CHECK-PIC-GLOBISEL:       // %bb.0: // %entry
+; CHECK-PIC-GLOBISEL-NEXT:    adr x8, lbsrc
+; CHECK-PIC-GLOBISEL-NEXT:    adr x9, lptr
+; CHECK-PIC-GLOBISEL-NEXT:    ldrb w8, [x8]
+; CHECK-PIC-GLOBISEL-NEXT:    ldr x9, [x9]
+; CHECK-PIC-GLOBISEL-NEXT:    strb w8, [x9]
+; CHECK-PIC-GLOBISEL-NEXT:    ret
+entry:
+  %0 = load i8, i8* getelementptr inbounds ([65536 x i8], [65536 x i8]* @lbsrc, i64 0, i64 0), align 4
+  %1 = load i8*, i8** @lptr, align 8
+  store i8 %0, i8* %1, align 1
+  ret void
+}
+
+
+declare void @func(...)
+
+define i8* @externfuncaddr() {
+; CHECK-LABEL: externfuncaddr:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    adr x0, func
+; CHECK-NEXT:    ret
+;
+; CHECK-GLOBISEL-LABEL: externfuncaddr:
+; CHECK-GLOBISEL:       // %bb.0: // %entry
+; CHECK-GLOBISEL-NEXT:    adr x0, func
+; CHECK-GLOBISEL-NEXT:    ret
+;
+; CHECK-PIC-LABEL: externfuncaddr:
+; CHECK-PIC:       // %bb.0: // %entry
+; CHECK-PIC-NEXT:    ldr x0, :got:func
+; CHECK-PIC-NEXT:    ret
+;
+; CHECK-PIC-GLOBISEL-LABEL: externfuncaddr:
+; CHECK-PIC-GLOBISEL:       // %bb.0: // %entry
+; CHECK-PIC-GLOBISEL-NEXT:    ldr x0, :got:func
+; CHECK-PIC-GLOBISEL-NEXT:    ret
+entry:
+      ret i8* bitcast (void (...)* @func to i8*)
+}
+
+define i8* @localfuncaddr() {
+; CHECK-LABEL: localfuncaddr:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    adr x0, externfuncaddr
+; CHECK-NEXT:    ret
+;
+; CHECK-GLOBISEL-LABEL: localfuncaddr:
+; CHECK-GLOBISEL:       // %bb.0: // %entry
+; CHECK-GLOBISEL-NEXT:    adr x0, externfuncaddr
+; CHECK-GLOBISEL-NEXT:    ret
+;
+; CHECK-PIC-LABEL: localfuncaddr:
+; CHECK-PIC:       // %bb.0: // %entry
+; CHECK-PIC-NEXT:    ldr x0, :got:externfuncaddr
+; CHECK-PIC-NEXT:    ret
+;
+; CHECK-PIC-GLOBISEL-LABEL: localfuncaddr:
+; CHECK-PIC-GLOBISEL:       // %bb.0: // %entry
+; CHECK-PIC-GLOBISEL-NEXT:    ldr x0, :got:externfuncaddr
+; CHECK-PIC-GLOBISEL-NEXT:    ret
+entry:
+      ret i8* bitcast (i8* ()* @externfuncaddr to i8*)
+}
+