[llvm] [M68k] implement large code model (PR #106381)

Janis Heims via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 29 03:44:32 PDT 2024


https://github.com/TechnoElf updated https://github.com/llvm/llvm-project/pull/106381

>From b724ce53a799c1563d13cb466a0e5783d8098c57 Mon Sep 17 00:00:00 2001
From: TechnoElf <technoelf at undertheprinter.com>
Date: Wed, 28 Aug 2024 14:13:27 +0200
Subject: [PATCH] [M68k] implement large code model

---
 llvm/lib/Target/M68k/M68kSubtarget.cpp        |  54 ++++-
 llvm/lib/Target/M68k/M68kTargetMachine.cpp    |   2 -
 llvm/test/CodeGen/M68k/CodeModel/large-pic.ll | 205 ++++++++++++++++++
 .../M68k/CodeModel/large-pie-global-access.ll | 139 ++++++++++++
 llvm/test/CodeGen/M68k/CodeModel/large-pie.ll |  66 ++++++
 .../CodeGen/M68k/CodeModel/large-static.ll    | 180 +++++++++++++++
 6 files changed, 640 insertions(+), 6 deletions(-)
 create mode 100644 llvm/test/CodeGen/M68k/CodeModel/large-pic.ll
 create mode 100644 llvm/test/CodeGen/M68k/CodeModel/large-pie-global-access.ll
 create mode 100644 llvm/test/CodeGen/M68k/CodeModel/large-pie.ll
 create mode 100644 llvm/test/CodeGen/M68k/CodeModel/large-static.ll

diff --git a/llvm/lib/Target/M68k/M68kSubtarget.cpp b/llvm/lib/Target/M68k/M68kSubtarget.cpp
index cacdbf559faa2d..53ec574ae5596c 100644
--- a/llvm/lib/Target/M68k/M68kSubtarget.cpp
+++ b/llvm/lib/Target/M68k/M68kSubtarget.cpp
@@ -115,7 +115,7 @@ M68kSubtarget &M68kSubtarget::initializeSubtargetDependencies(
 //  ---------------------+------------+------------+------------+-------------
 //                branch |   pc-rel   |   pc-rel   |   pc-rel   |   pc-rel
 //  ---------------------+------------+------------+------------+-------------
-//           call global |    @PLT    |    @PLT    |    @PLT    |    @PLT
+//           call global |  absolute  |    @PLT    |  absolute  |    @PLT
 //  ---------------------+------------+------------+------------+-------------
 //         call internal |   pc-rel   |   pc-rel   |   pc-rel   |   pc-rel
 //  ---------------------+------------+------------+------------+-------------
@@ -127,6 +127,24 @@ M68kSubtarget &M68kSubtarget::initializeSubtargetDependencies(
 //  ---------------------+------------+------------+------------+-------------
 //      data global big* |   pc-rel   |  @GOTPCREL |  absolute  |  @GOTPCREL
 //  ---------------------+------------+------------+------------+-------------
+//                       |          Large          |
+//                       +-------------------------+
+//                       |   Static   |    PIC     |
+//  ---------------------+------------+------------+
+//                branch |  absolute  |   pc-rel   |
+//  ---------------------+------------+------------+
+//           call global |  absolute  |    @PLT    |
+//  ---------------------+------------+------------+
+//         call internal |  absolute  |   pc-rel   |
+//  ---------------------+------------+------------+
+//            data local |  absolute  |  @GOTOFF   |
+//  ---------------------+------------+------------+
+//       data local big* |  absolute  |  @GOTOFF   |
+//  ---------------------+------------+------------+
+//           data global |  absolute  |  @GOTOFF   |
+//  ---------------------+------------+------------+
+//      data global big* |  absolute  |  @GOTOFF   |
+//  ---------------------+------------+------------+
 //
 // * Big data potentially cannot be reached within 16 bit offset and requires
 //   special handling for old(x00 and x10) CPUs. Normally these symbols go into
@@ -142,8 +160,22 @@ M68kSubtarget &M68kSubtarget::initializeSubtargetDependencies(
 /// Classify a blockaddress reference for the current subtarget according to how
 /// we should reference it in a non-pcrel context.
 unsigned char M68kSubtarget::classifyBlockAddressReference() const {
-  // Unless we start to support Large Code Model branching is always pc-rel
-  return M68kII::MO_PC_RELATIVE_ADDRESS;
+  switch (TM.getCodeModel()) {
+  default:
+    llvm_unreachable("Unsupported code model");
+  case CodeModel::Small:
+  case CodeModel::Kernel:
+  case CodeModel::Medium: {
+    return M68kII::MO_PC_RELATIVE_ADDRESS;
+  }
+  case CodeModel::Large: {
+    if (isPositionIndependent()) {
+      return M68kII::MO_PC_RELATIVE_ADDRESS;
+    } else {
+      return M68kII::MO_ABSOLUTE_ADDRESS;
+    }
+  }
+  }
 }
 
 unsigned char
@@ -171,6 +203,13 @@ M68kSubtarget::classifyLocalReference(const GlobalValue *GV) const {
       return M68kII::MO_ABSOLUTE_ADDRESS;
     }
   }
+  case CodeModel::Large: {
+    if (isPositionIndependent()) {
+      return M68kII::MO_GOTOFF;
+    } else {
+      return M68kII::MO_ABSOLUTE_ADDRESS;
+    }
+  }
   }
 }
 
@@ -212,6 +251,12 @@ unsigned char M68kSubtarget::classifyGlobalReference(const GlobalValue *GV,
 
     return M68kII::MO_ABSOLUTE_ADDRESS;
   }
+  case CodeModel::Large: {
+    if (isPositionIndependent())
+      return M68kII::MO_GOTOFF;
+
+    return M68kII::MO_ABSOLUTE_ADDRESS;
+  }
   }
 }
 
@@ -221,7 +266,8 @@ unsigned M68kSubtarget::getJumpTableEncoding() const {
     // the potential delta between the jump target and table base can be larger
     // than displacement field, which is True for older CPUs(16 bit disp)
     // in Medium model(can have large data way beyond 16 bit).
-    if (TM.getCodeModel() == CodeModel::Medium && !atLeastM68020())
+    if ((TM.getCodeModel() == CodeModel::Medium && !atLeastM68020()) ||
+        TM.getCodeModel() == CodeModel::Large)
       return MachineJumpTableInfo::EK_Custom32;
 
     return MachineJumpTableInfo::EK_LabelDifference32;
diff --git a/llvm/lib/Target/M68k/M68kTargetMachine.cpp b/llvm/lib/Target/M68k/M68kTargetMachine.cpp
index b65de5e177b53e..2248837e6ca61b 100644
--- a/llvm/lib/Target/M68k/M68kTargetMachine.cpp
+++ b/llvm/lib/Target/M68k/M68kTargetMachine.cpp
@@ -87,8 +87,6 @@ CodeModel::Model getEffectiveCodeModel(std::optional<CodeModel::Model> CM,
                                        bool JIT) {
   if (!CM) {
     return CodeModel::Small;
-  } else if (CM == CodeModel::Large) {
-    llvm_unreachable("Large code model is not supported");
   } else if (CM == CodeModel::Kernel) {
     llvm_unreachable("Kernel code model is not implemented yet");
   }
diff --git a/llvm/test/CodeGen/M68k/CodeModel/large-pic.ll b/llvm/test/CodeGen/M68k/CodeModel/large-pic.ll
new file mode 100644
index 00000000000000..c937efa60b72b2
--- /dev/null
+++ b/llvm/test/CodeGen/M68k/CodeModel/large-pic.ll
@@ -0,0 +1,205 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc < %s -O2 -mtriple=m68k -verify-machineinstrs \
+; RUN:              -code-model=large -relocation-model=pic \
+; RUN:   | FileCheck %s
+
+ at ptr = external global ptr
+ at dst = external global i32
+ at src = external global i32
+
+define void @test0() nounwind {
+; CHECK-LABEL: test0:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    lea (_GLOBAL_OFFSET_TABLE_ at GOTPCREL,%pc), %a0
+; CHECK-NEXT:    move.l %a0, %a1
+; CHECK-NEXT:    adda.l #dst at GOTOFF, %a1
+; CHECK-NEXT:    move.l #ptr at GOTOFF, %d0
+; CHECK-NEXT:    move.l %a1, (0,%a0,%d0)
+; CHECK-NEXT:    move.l #src at GOTOFF, %d0
+; CHECK-NEXT:    move.l #dst at GOTOFF, %d1
+; CHECK-NEXT:    move.l (0,%a0,%d0), (0,%a0,%d1)
+; CHECK-NEXT:    rts
+entry:
+    store ptr @dst, ptr @ptr
+    %tmp.s = load i32, ptr @src
+    store i32 %tmp.s, ptr @dst
+    ret void
+}
+
+ at ptr2 = global ptr null
+ at dst2 = global i32 0
+ at src2 = global i32 0
+
+define void @test1() nounwind {
+; CHECK-LABEL: test1:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    lea (_GLOBAL_OFFSET_TABLE_ at GOTPCREL,%pc), %a0
+; CHECK-NEXT:    move.l %a0, %a1
+; CHECK-NEXT:    adda.l #dst2 at GOTOFF, %a1
+; CHECK-NEXT:    move.l #ptr2 at GOTOFF, %d0
+; CHECK-NEXT:    move.l %a1, (0,%a0,%d0)
+; CHECK-NEXT:    move.l #src2 at GOTOFF, %d0
+; CHECK-NEXT:    move.l #dst2 at GOTOFF, %d1
+; CHECK-NEXT:    move.l (0,%a0,%d0), (0,%a0,%d1)
+; CHECK-NEXT:    rts
+entry:
+    store ptr @dst2, ptr @ptr2
+    %tmp.s = load i32, ptr @src2
+    store i32 %tmp.s, ptr @dst2
+    ret void
+}
+
+declare ptr @malloc(i32)
+
+define void @test2() nounwind {
+; CHECK-LABEL: test2:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    suba.l #4, %sp
+; CHECK-NEXT:    move.l #40, (%sp)
+; CHECK-NEXT:    jsr (malloc at PLT,%pc)
+; CHECK-NEXT:    adda.l #4, %sp
+; CHECK-NEXT:    rts
+entry:
+    %ptr = call ptr @malloc(i32 40)
+    ret void
+}
+
+ at pfoo = external global ptr
+declare ptr @afoo(...)
+
+define void @test3() nounwind {
+; CHECK-LABEL: test3:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    suba.l #4, %sp
+; CHECK-NEXT:    movem.l %a2, (0,%sp) ; 8-byte Folded Spill
+; CHECK-NEXT:    lea (_GLOBAL_OFFSET_TABLE_ at GOTPCREL,%pc), %a2
+; CHECK-NEXT:    jsr (afoo at PLT,%pc)
+; CHECK-NEXT:    move.l #pfoo at GOTOFF, %d0
+; CHECK-NEXT:    move.l %a0, (0,%a2,%d0)
+; CHECK-NEXT:    jsr (%a0)
+; CHECK-NEXT:    movem.l (0,%sp), %a2 ; 8-byte Folded Reload
+; CHECK-NEXT:    adda.l #4, %sp
+; CHECK-NEXT:    rts
+entry:
+    %tmp = call ptr(...) @afoo()
+    store ptr %tmp, ptr @pfoo
+    %tmp1 = load ptr, ptr @pfoo
+    call void(...) %tmp1()
+    ret void
+}
+
+declare void @foo(...)
+
+define void @test4() nounwind {
+; CHECK-LABEL: test4:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    suba.l #4, %sp
+; CHECK-NEXT:    jsr (foo at PLT,%pc)
+; CHECK-NEXT:    adda.l #4, %sp
+; CHECK-NEXT:    rts
+entry:
+    call void(...) @foo()
+    ret void
+}
+
+ at ptr6 = internal global ptr null
+ at dst6 = internal global i32 0
+ at src6 = internal global i32 0
+
+define void @test5() nounwind {
+; CHECK-LABEL: test5:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    lea (_GLOBAL_OFFSET_TABLE_ at GOTPCREL,%pc), %a0
+; CHECK-NEXT:    move.l %a0, %a1
+; CHECK-NEXT:    adda.l #dst6 at GOTOFF, %a1
+; CHECK-NEXT:    move.l #ptr6 at GOTOFF, %d0
+; CHECK-NEXT:    move.l %a1, (0,%a0,%d0)
+; CHECK-NEXT:    move.l #src6 at GOTOFF, %d0
+; CHECK-NEXT:    move.l #dst6 at GOTOFF, %d1
+; CHECK-NEXT:    move.l (0,%a0,%d0), (0,%a0,%d1)
+; CHECK-NEXT:    rts
+entry:
+    store ptr @dst6, ptr @ptr6
+    %tmp.s = load i32, ptr @src6
+    store i32 %tmp.s, ptr @dst6
+    ret void
+}
+
+define void @test7(i32 %n.u) nounwind {
+; CHECK-LABEL: test7:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    move.l (4,%sp), %d0
+; CHECK-NEXT:    add.l #-1, %d0
+; CHECK-NEXT:    move.l %d0, %d1
+; CHECK-NEXT:    sub.l #12, %d1
+; CHECK-NEXT:    bhi .LBB6_12
+; CHECK-NEXT:  ; %bb.1: ; %entry
+; CHECK-NEXT:    lea (_GLOBAL_OFFSET_TABLE_ at GOTPCREL,%pc), %a0
+; CHECK-NEXT:    lsl.l #2, %d0
+; CHECK-NEXT:    move.l %a0, %a1
+; CHECK-NEXT:    adda.l #.LJTI6_0 at GOTOFF, %a1
+; CHECK-NEXT:    move.l %a0, %d1
+; CHECK-NEXT:    add.l (0,%a1,%d0), %d1
+; CHECK-NEXT:    move.l %d1, %a0
+; CHECK-NEXT:    jmp (%a0)
+; CHECK-NEXT:  .LBB6_12: ; %bb2
+; CHECK-NEXT:    bra foo6 at PLT ; TAILCALL
+; CHECK-NEXT:  .LBB6_3: ; %bb5
+; CHECK-NEXT:    bra foo5 at PLT ; TAILCALL
+; CHECK-NEXT:  .LBB6_5: ; %bb1
+; CHECK-NEXT:    bra foo2 at PLT ; TAILCALL
+; CHECK-NEXT:  .LBB6_2: ; %bb
+; CHECK-NEXT:    bra foo1 at PLT ; TAILCALL
+; CHECK-NEXT:  .LBB6_9: ; %bb4
+; CHECK-NEXT:    bra foo4 at PLT ; TAILCALL
+; CHECK-NEXT:  .LBB6_8: ; %bb3
+; CHECK-NEXT:    bra foo3 at PLT ; TAILCALL
+entry:
+    switch i32 %n.u, label %bb12 [i32 1, label %bb i32 2, label %bb6 i32 4, label %bb7 i32 5, label %bb8 i32 6, label %bb10 i32 7, label %bb1 i32 8, label %bb3 i32 9, label %bb4 i32 10, label %bb9 i32 11, label %bb2 i32 12, label %bb5 i32 13, label %bb11 ]
+bb:
+    tail call void(...) @foo1()
+    ret void
+bb1:
+    tail call void(...) @foo2()
+    ret void
+bb2:
+    tail call void(...) @foo6()
+    ret void
+bb3:
+    tail call void(...) @foo3()
+    ret void
+bb4:
+    tail call void(...) @foo4()
+    ret void
+bb5:
+    tail call void(...) @foo5()
+    ret void
+bb6:
+    tail call void(...) @foo1()
+    ret void
+bb7:
+    tail call void(...) @foo2()
+    ret void
+bb8:
+    tail call void(...) @foo6()
+    ret void
+bb9:
+    tail call void(...) @foo3()
+    ret void
+bb10:
+    tail call void(...) @foo4()
+    ret void
+bb11:
+    tail call void(...) @foo5()
+    ret void
+bb12:
+    tail call void(...) @foo6()
+    ret void
+}
+
+declare void @foo1(...)
+declare void @foo2(...)
+declare void @foo6(...)
+declare void @foo3(...)
+declare void @foo4(...)
+declare void @foo5(...)
diff --git a/llvm/test/CodeGen/M68k/CodeModel/large-pie-global-access.ll b/llvm/test/CodeGen/M68k/CodeModel/large-pie-global-access.ll
new file mode 100644
index 00000000000000..f82b961382fbf0
--- /dev/null
+++ b/llvm/test/CodeGen/M68k/CodeModel/large-pie-global-access.ll
@@ -0,0 +1,139 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -O2 -mtriple=m68k -verify-machineinstrs \
+; RUN:              -code-model=large -relocation-model=pic \
+; RUN:   | FileCheck %s
+
+; External Linkage
+ at a = global i32 0, align 4
+
+define i32 @my_access_global_a() #0 {
+; CHECK-LABEL: my_access_global_a:
+; CHECK:         .cfi_startproc
+; CHECK-NEXT:  ; %bb.0: ; %entry
+; CHECK-NEXT:    lea (_GLOBAL_OFFSET_TABLE_ at GOTPCREL,%pc), %a0
+; CHECK-NEXT:    move.l #a at GOTOFF, %d0
+; CHECK-NEXT:    move.l (0,%a0,%d0), %d0
+; CHECK-NEXT:    rts
+entry:
+  %0 = load i32, ptr @a, align 4
+  ret i32 %0
+}
+
+; WeakAny Linkage
+ at b = weak global i32 0, align 4
+
+define i32 @my_access_global_b() #0 {
+; CHECK-LABEL: my_access_global_b:
+; CHECK:         .cfi_startproc
+; CHECK-NEXT:  ; %bb.0: ; %entry
+; CHECK-NEXT:    lea (_GLOBAL_OFFSET_TABLE_ at GOTPCREL,%pc), %a0
+; CHECK-NEXT:    move.l #b at GOTOFF, %d0
+; CHECK-NEXT:    move.l (0,%a0,%d0), %d0
+; CHECK-NEXT:    rts
+entry:
+ %0 = load i32, ptr @b, align 4
+ ret i32 %0
+}
+
+; Internal Linkage
+ at c = internal global i32 0, align 4
+
+define i32 @my_access_global_c() #0 {
+; CHECK-LABEL: my_access_global_c:
+; CHECK:         .cfi_startproc
+; CHECK-NEXT:  ; %bb.0: ; %entry
+; CHECK-NEXT:    lea (_GLOBAL_OFFSET_TABLE_ at GOTPCREL,%pc), %a0
+; CHECK-NEXT:    move.l #c at GOTOFF, %d0
+; CHECK-NEXT:    move.l (0,%a0,%d0), %d0
+; CHECK-NEXT:    rts
+entry:
+ %0 = load i32, ptr @c, align 4
+ ret i32 %0
+}
+
+; External Linkage, only declaration.
+ at d = external global i32, align 4
+
+define i32 @my_access_global_load_d() #0 {
+; CHECK-LABEL: my_access_global_load_d:
+; CHECK:         .cfi_startproc
+; CHECK-NEXT:  ; %bb.0: ; %entry
+; CHECK-NEXT:    lea (_GLOBAL_OFFSET_TABLE_ at GOTPCREL,%pc), %a0
+; CHECK-NEXT:    move.l #d at GOTOFF, %d0
+; CHECK-NEXT:    move.l (0,%a0,%d0), %d0
+; CHECK-NEXT:    rts
+entry:
+ %0 = load i32, ptr @d, align 4
+ ret i32 %0
+}
+
+; External Linkage, only declaration, store a value.
+define i32 @my_access_global_store_d() #0 {
+; CHECK-LABEL: my_access_global_store_d:
+; CHECK:         .cfi_startproc
+; CHECK-NEXT:  ; %bb.0: ; %entry
+; CHECK-NEXT:    lea (_GLOBAL_OFFSET_TABLE_ at GOTPCREL,%pc), %a0
+; CHECK-NEXT:    move.l #d at GOTOFF, %d0
+; CHECK-NEXT:    move.l #2, (0,%a0,%d0)
+; CHECK-NEXT:    moveq #0, %d0
+; CHECK-NEXT:    rts
+entry:
+ store i32 2, ptr @d, align 4
+ ret i32 0
+}
+
+; External Linkage, function pointer access.
+declare i32 @access_fp(ptr)
+declare i32 @foo()
+
+define i32 @my_access_fp_foo() #0 {
+; CHECK-LABEL: my_access_fp_foo:
+; CHECK:         .cfi_startproc
+; CHECK-NEXT:  ; %bb.0: ; %entry
+; CHECK-NEXT:    suba.l #4, %sp
+; CHECK-NEXT:    .cfi_def_cfa_offset -8
+; CHECK-NEXT:    lea (_GLOBAL_OFFSET_TABLE_ at GOTPCREL,%pc), %a0
+; CHECK-NEXT:    adda.l #foo at GOTOFF, %a0
+; CHECK-NEXT:    move.l %a0, (%sp)
+; CHECK-NEXT:    jsr (access_fp at PLT,%pc)
+; CHECK-NEXT:    adda.l #4, %sp
+; CHECK-NEXT:    rts
+entry:
+ %call = call i32 @access_fp(ptr @foo)
+ ret i32 %call
+}
+
+; LinkOnceODR Linkage, function pointer access.
+
+$bar = comdat any
+
+define linkonce_odr i32 @bar() comdat {
+; CHECK-LABEL: bar:
+; CHECK:         .cfi_startproc
+; CHECK-NEXT:  ; %bb.0: ; %entry
+; CHECK-NEXT:    moveq #0, %d0
+; CHECK-NEXT:    rts
+entry:
+ ret i32 0
+}
+
+define i32 @my_access_fp_bar() #0 {
+; CHECK-LABEL: my_access_fp_bar:
+; CHECK:         .cfi_startproc
+; CHECK-NEXT:  ; %bb.0: ; %entry
+; CHECK-NEXT:    suba.l #4, %sp
+; CHECK-NEXT:    .cfi_def_cfa_offset -8
+; CHECK-NEXT:    lea (_GLOBAL_OFFSET_TABLE_ at GOTPCREL,%pc), %a0
+; CHECK-NEXT:    adda.l #bar at GOTOFF, %a0
+; CHECK-NEXT:    move.l %a0, (%sp)
+; CHECK-NEXT:    jsr (access_fp at PLT,%pc)
+; CHECK-NEXT:    adda.l #4, %sp
+; CHECK-NEXT:    rts
+entry:
+ %call = call i32 @access_fp(ptr @bar)
+ ret i32 %call
+}
+
+!llvm.module.flags = !{!0, !1}
+!0 = !{i32 1, !"PIC Level", i32 1}
+!1 = !{i32 1, !"PIE Level", i32 1}
diff --git a/llvm/test/CodeGen/M68k/CodeModel/large-pie.ll b/llvm/test/CodeGen/M68k/CodeModel/large-pie.ll
new file mode 100644
index 00000000000000..ad902528d1dd3f
--- /dev/null
+++ b/llvm/test/CodeGen/M68k/CodeModel/large-pie.ll
@@ -0,0 +1,66 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc < %s -O0 -mtriple=m68k -verify-machineinstrs \
+; RUN:              -code-model=large -relocation-model=pic \
+; RUN:   | FileCheck %s
+
+define weak void @weak_foo() {
+; CHECK-LABEL: weak_foo:
+; CHECK:         .cfi_startproc
+; CHECK-NEXT:  ; %bb.0:
+; CHECK-NEXT:    rts
+  ret void
+}
+
+define weak_odr void @weak_odr_foo() {
+; CHECK-LABEL: weak_odr_foo:
+; CHECK:         .cfi_startproc
+; CHECK-NEXT:  ; %bb.0:
+; CHECK-NEXT:    rts
+  ret void
+}
+
+define internal void @internal_foo() {
+; CHECK-LABEL: internal_foo:
+; CHECK:         .cfi_startproc
+; CHECK-NEXT:  ; %bb.0:
+; CHECK-NEXT:    rts
+  ret void
+}
+
+declare i32 @ext_baz()
+
+define void @foo() {
+; CHECK-LABEL: foo:
+; CHECK:         .cfi_startproc
+; CHECK-NEXT:  ; %bb.0:
+; CHECK-NEXT:    rts
+  ret void
+}
+
+define void @bar() {
+; CHECK-LABEL: bar:
+; CHECK:         .cfi_startproc
+; CHECK-NEXT:  ; %bb.0: ; %entry
+; CHECK-NEXT:    suba.l #4, %sp
+; CHECK-NEXT:    .cfi_def_cfa_offset -8
+; CHECK-NEXT:    jsr (foo at PLT,%pc)
+; CHECK-NEXT:    jsr (weak_odr_foo at PLT,%pc)
+; CHECK-NEXT:    jsr (weak_foo at PLT,%pc)
+; CHECK-NEXT:    jsr (internal_foo,%pc)
+; CHECK-NEXT:    jsr (ext_baz at PLT,%pc)
+; CHECK-NEXT:    adda.l #4, %sp
+; CHECK-NEXT:    rts
+entry:
+  call void @foo()
+  call void @weak_odr_foo()
+  call void @weak_foo()
+  call void @internal_foo()
+  call i32 @ext_baz()
+  ret void
+}
+
+; -fpie for local global data tests should be added here
+
+!llvm.module.flags = !{!0, !1}
+!0 = !{i32 1, !"PIC Level", i32 1}
+!1 = !{i32 1, !"PIE Level", i32 1}
diff --git a/llvm/test/CodeGen/M68k/CodeModel/large-static.ll b/llvm/test/CodeGen/M68k/CodeModel/large-static.ll
new file mode 100644
index 00000000000000..fb38cd9582bd13
--- /dev/null
+++ b/llvm/test/CodeGen/M68k/CodeModel/large-static.ll
@@ -0,0 +1,180 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc < %s -O2 -mtriple=m68k -verify-machineinstrs \
+; RUN:              -code-model=large -relocation-model=static \
+; RUN:   | FileCheck %s
+
+ at ptr = external global ptr
+ at dst = external global i32
+ at src = external global i32
+
+define void @test0() nounwind {
+; CHECK-LABEL: test0:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    move.l #dst, ptr
+; CHECK-NEXT:    move.l src, dst
+; CHECK-NEXT:    rts
+entry:
+    store ptr @dst, ptr @ptr
+    %tmp.s = load i32, ptr @src
+    store i32 %tmp.s, ptr @dst
+    ret void
+}
+
+ at ptr2 = global ptr null
+ at dst2 = global i32 0
+ at src2 = global i32 0
+
+define void @test1() nounwind {
+; CHECK-LABEL: test1:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    move.l #dst2, ptr2
+; CHECK-NEXT:    move.l src2, dst2
+; CHECK-NEXT:    rts
+entry:
+    store ptr @dst2, ptr @ptr2
+    %tmp.s = load i32, ptr @src2
+    store i32 %tmp.s, ptr @dst2
+    ret void
+}
+
+declare ptr @malloc(i32)
+
+define void @test2() nounwind {
+; CHECK-LABEL: test2:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    suba.l #4, %sp
+; CHECK-NEXT:    move.l #40, (%sp)
+; CHECK-NEXT:    jsr malloc
+; CHECK-NEXT:    adda.l #4, %sp
+; CHECK-NEXT:    rts
+entry:
+    %ptr = call ptr @malloc(i32 40)
+    ret void
+}
+
+ at pfoo = external global ptr
+declare ptr @afoo(...)
+
+
+define void @test3() nounwind {
+; CHECK-LABEL: test3:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    suba.l #4, %sp
+; CHECK-NEXT:    jsr afoo
+; CHECK-NEXT:    move.l %a0, pfoo
+; CHECK-NEXT:    jsr (%a0)
+; CHECK-NEXT:    adda.l #4, %sp
+; CHECK-NEXT:    rts
+entry:
+    %tmp = call ptr(...) @afoo()
+    store ptr %tmp, ptr @pfoo
+    %tmp1 = load ptr, ptr @pfoo
+    call void(...) %tmp1()
+    ret void
+}
+
+declare void @foo(...)
+
+define void @test4() nounwind {
+; CHECK-LABEL: test4:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    suba.l #4, %sp
+; CHECK-NEXT:    jsr foo
+; CHECK-NEXT:    adda.l #4, %sp
+; CHECK-NEXT:    rts
+entry:
+    call void(...) @foo()
+    ret void
+}
+
+ at ptr6 = internal global ptr null
+ at dst6 = internal global i32 0
+ at src6 = internal global i32 0
+
+define void @test5() nounwind {
+; CHECK-LABEL: test5:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    move.l #dst6, ptr6
+; CHECK-NEXT:    move.l src6, dst6
+; CHECK-NEXT:    rts
+entry:
+    store ptr @dst6, ptr @ptr6
+    %tmp.s = load i32, ptr @src6
+    store i32 %tmp.s, ptr @dst6
+    ret void
+}
+
+define void @test7(i32 %n.u) nounwind {
+; CHECK-LABEL: test7:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    move.l (4,%sp), %d0
+; CHECK-NEXT:    add.l #-1, %d0
+; CHECK-NEXT:    move.l %d0, %d1
+; CHECK-NEXT:    sub.l #12, %d1
+; CHECK-NEXT:    bhi .LBB6_12
+; CHECK-NEXT:  ; %bb.1: ; %entry
+; CHECK-NEXT:    lsl.l #2, %d0
+; CHECK-NEXT:    move.l #.LJTI6_0, %a0
+; CHECK-NEXT:    move.l (0,%a0,%d0), %a0
+; CHECK-NEXT:    jmp (%a0)
+; CHECK-NEXT:  .LBB6_12: ; %bb2
+; CHECK-NEXT:    bra foo6 ; TAILCALL
+; CHECK-NEXT:  .LBB6_3: ; %bb5
+; CHECK-NEXT:    bra foo5 ; TAILCALL
+; CHECK-NEXT:  .LBB6_5: ; %bb1
+; CHECK-NEXT:    bra foo2 ; TAILCALL
+; CHECK-NEXT:  .LBB6_2: ; %bb
+; CHECK-NEXT:    bra foo1 ; TAILCALL
+; CHECK-NEXT:  .LBB6_9: ; %bb4
+; CHECK-NEXT:    bra foo4 ; TAILCALL
+; CHECK-NEXT:  .LBB6_8: ; %bb3
+; CHECK-NEXT:    bra foo3 ; TAILCALL
+entry:
+    switch i32 %n.u, label %bb12 [i32 1, label %bb i32 2, label %bb6 i32 4, label %bb7 i32 5, label %bb8 i32 6, label %bb10 i32 7, label %bb1 i32 8, label %bb3 i32 9, label %bb4 i32 10, label %bb9 i32 11, label %bb2 i32 12, label %bb5 i32 13, label %bb11 ]
+bb:
+    tail call void(...) @foo1()
+    ret void
+bb1:
+    tail call void(...) @foo2()
+    ret void
+bb2:
+    tail call void(...) @foo6()
+    ret void
+bb3:
+    tail call void(...) @foo3()
+    ret void
+bb4:
+    tail call void(...) @foo4()
+    ret void
+bb5:
+    tail call void(...) @foo5()
+    ret void
+bb6:
+    tail call void(...) @foo1()
+    ret void
+bb7:
+    tail call void(...) @foo2()
+    ret void
+bb8:
+    tail call void(...) @foo6()
+    ret void
+bb9:
+    tail call void(...) @foo3()
+    ret void
+bb10:
+    tail call void(...) @foo4()
+    ret void
+bb11:
+    tail call void(...) @foo5()
+    ret void
+bb12:
+    tail call void(...) @foo6()
+    ret void
+}
+
+declare void @foo1(...)
+declare void @foo2(...)
+declare void @foo6(...)
+declare void @foo3(...)
+declare void @foo4(...)
+declare void @foo5(...)



More information about the llvm-commits mailing list