diff --git a/llvm/lib/Target/M68k/M68kSubtarget.cpp b/llvm/lib/Target/M68k/M68kSubtarget.cpp index cacdbf559faa2..53ec574ae5596 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 b65de5e177b53..2248837e6ca61 100644 --- a/llvm/lib/Target/M68k/M68kTargetMachine.cpp +++ b/llvm/lib/Target/M68k/M68kTargetMachine.cpp @@ -87,8 +87,6 @@ CodeModel::Model getEffectiveCodeModel(std::optional 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 0000000000000..c937efa60b72b --- /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 + +@ptr = external global ptr +@dst = external global i32 +@src = external global i32 + +define void @test0() nounwind { +; CHECK-LABEL: test0: +; CHECK: ; %bb.0: ; %entry +; CHECK-NEXT: lea (_GLOBAL_OFFSET_TABLE_@GOTPCREL,%pc), %a0 +; CHECK-NEXT: move.l %a0, %a1 +; CHECK-NEXT: adda.l #dst@GOTOFF, %a1 +; CHECK-NEXT: move.l #ptr@GOTOFF, %d0 +; CHECK-NEXT: move.l %a1, (0,%a0,%d0) +; CHECK-NEXT: move.l #src@GOTOFF, %d0 +; CHECK-NEXT: move.l #dst@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 +} + +@ptr2 = global ptr null +@dst2 = global i32 0 +@src2 = global i32 0 + +define void @test1() nounwind { +; CHECK-LABEL: test1: +; CHECK: ; %bb.0: ; %entry +; CHECK-NEXT: lea (_GLOBAL_OFFSET_TABLE_@GOTPCREL,%pc), %a0 +; CHECK-NEXT: move.l %a0, %a1 +; CHECK-NEXT: adda.l #dst2@GOTOFF, %a1 +; CHECK-NEXT: move.l #ptr2@GOTOFF, %d0 +; CHECK-NEXT: move.l %a1, (0,%a0,%d0) +; CHECK-NEXT: move.l #src2@GOTOFF, %d0 +; CHECK-NEXT: move.l #dst2@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@PLT,%pc) +; CHECK-NEXT: adda.l #4, %sp +; CHECK-NEXT: rts +entry: + %ptr = call ptr @malloc(i32 40) + ret void +} + +@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_@GOTPCREL,%pc), %a2 +; CHECK-NEXT: jsr (afoo@PLT,%pc) +; CHECK-NEXT: move.l #pfoo@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@PLT,%pc) +; CHECK-NEXT: adda.l #4, %sp +; CHECK-NEXT: rts +entry: + call void(...) @foo() + ret void +} + +@ptr6 = internal global ptr null +@dst6 = internal global i32 0 +@src6 = internal global i32 0 + +define void @test5() nounwind { +; CHECK-LABEL: test5: +; CHECK: ; %bb.0: ; %entry +; CHECK-NEXT: lea (_GLOBAL_OFFSET_TABLE_@GOTPCREL,%pc), %a0 +; CHECK-NEXT: move.l %a0, %a1 +; CHECK-NEXT: adda.l #dst6@GOTOFF, %a1 +; CHECK-NEXT: move.l #ptr6@GOTOFF, %d0 +; CHECK-NEXT: move.l %a1, (0,%a0,%d0) +; CHECK-NEXT: move.l #src6@GOTOFF, %d0 +; CHECK-NEXT: move.l #dst6@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_@GOTPCREL,%pc), %a0 +; CHECK-NEXT: lsl.l #2, %d0 +; CHECK-NEXT: move.l %a0, %a1 +; CHECK-NEXT: adda.l #.LJTI6_0@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@PLT ; TAILCALL +; CHECK-NEXT: .LBB6_3: ; %bb5 +; CHECK-NEXT: bra foo5@PLT ; TAILCALL +; CHECK-NEXT: .LBB6_5: ; %bb1 +; CHECK-NEXT: bra foo2@PLT ; TAILCALL +; CHECK-NEXT: .LBB6_2: ; %bb +; CHECK-NEXT: bra foo1@PLT ; TAILCALL +; CHECK-NEXT: .LBB6_9: ; %bb4 +; CHECK-NEXT: bra foo4@PLT ; TAILCALL +; CHECK-NEXT: .LBB6_8: ; %bb3 +; CHECK-NEXT: bra foo3@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 0000000000000..f82b961382fbf --- /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 +@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_@GOTPCREL,%pc), %a0 +; CHECK-NEXT: move.l #a@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 +@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_@GOTPCREL,%pc), %a0 +; CHECK-NEXT: move.l #b@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 +@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_@GOTPCREL,%pc), %a0 +; CHECK-NEXT: move.l #c@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. +@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_@GOTPCREL,%pc), %a0 +; CHECK-NEXT: move.l #d@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_@GOTPCREL,%pc), %a0 +; CHECK-NEXT: move.l #d@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_@GOTPCREL,%pc), %a0 +; CHECK-NEXT: adda.l #foo@GOTOFF, %a0 +; CHECK-NEXT: move.l %a0, (%sp) +; CHECK-NEXT: jsr (access_fp@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_@GOTPCREL,%pc), %a0 +; CHECK-NEXT: adda.l #bar@GOTOFF, %a0 +; CHECK-NEXT: move.l %a0, (%sp) +; CHECK-NEXT: jsr (access_fp@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 0000000000000..ad902528d1dd3 --- /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@PLT,%pc) +; CHECK-NEXT: jsr (weak_odr_foo@PLT,%pc) +; CHECK-NEXT: jsr (weak_foo@PLT,%pc) +; CHECK-NEXT: jsr (internal_foo,%pc) +; CHECK-NEXT: jsr (ext_baz@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 0000000000000..fb38cd9582bd1 --- /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 + +@ptr = external global ptr +@dst = external global i32 +@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 +} + +@ptr2 = global ptr null +@dst2 = global i32 0 +@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 +} + +@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 +} + +@ptr6 = internal global ptr null +@dst6 = internal global i32 0 +@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(...)