[llvm] 55929cd - [JITLink][AArch32] Implement Armv5 ldr-pc stubs and use them for all pre-v7 targets (#79082)

via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 23 09:02:21 PST 2024


Author: Stefan Gränitz
Date: 2024-01-23T18:02:17+01:00
New Revision: 55929cd679375d6ee5111edcb881103f57588d0e

URL: https://github.com/llvm/llvm-project/commit/55929cd679375d6ee5111edcb881103f57588d0e
DIFF: https://github.com/llvm/llvm-project/commit/55929cd679375d6ee5111edcb881103f57588d0e.diff

LOG: [JITLink][AArch32] Implement Armv5 ldr-pc stubs and use them for all pre-v7 targets (#79082)

This stub type loads an absolute address directly into the PC register.
It's the simplest and most compatible way to implement a branch
indirection across the entire address space (and probably the slowest as
well). It's the ideal fallback for all targets for which we did not
(yet) implement a more performant solution.

Added: 
    llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_armv7plus.s
    llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_thumbv6m.s
    llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_thumbv7a.s
    llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_thumbv7m.s

Modified: 
    llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
    llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp
    llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
    llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_arm.s
    llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_data.s
    llvm/test/ExecutionEngine/JITLink/AArch32/ELF_stubs_arm.s
    llvm/test/ExecutionEngine/JITLink/AArch32/ELF_stubs_thumb.s

Removed: 
    llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_thumb.s


################################################################################
diff  --git a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
index ef28ba88431e4c6..eda6feb441e6726 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h
@@ -134,14 +134,15 @@ const char *getEdgeKindName(Edge::Kind K);
 /// Stubs are often called "veneers" in the official docs and online.
 ///
 enum class StubsFlavor {
-  Unsupported = 0,
+  Undefined = 0,
+  pre_v7,
   v7,
 };
 
 /// JITLink sub-arch configuration for Arm CPU models
 struct ArmConfig {
   bool J1J2BranchEncoding = false;
-  StubsFlavor Stubs = StubsFlavor::Unsupported;
+  StubsFlavor Stubs = StubsFlavor::Undefined;
   // In the long term, we might want a linker switch like --target1-rel
   bool Target1Rel = false;
 };
@@ -149,18 +150,12 @@ struct ArmConfig {
 /// Obtain the sub-arch configuration for a given Arm CPU model.
 inline ArmConfig getArmConfigForCPUArch(ARMBuildAttrs::CPUArch CPUArch) {
   ArmConfig ArmCfg;
-  switch (CPUArch) {
-  case ARMBuildAttrs::v7:
-  case ARMBuildAttrs::v8_A:
+  if (CPUArch == ARMBuildAttrs::v7 || CPUArch >= ARMBuildAttrs::v7E_M) {
     ArmCfg.J1J2BranchEncoding = true;
     ArmCfg.Stubs = StubsFlavor::v7;
-    break;
-  default:
-    DEBUG_WITH_TYPE("jitlink", {
-      dbgs() << "  Warning: ARM config not defined for CPU architecture "
-             << getCPUArchName(CPUArch) << " (" << CPUArch << ")\n";
-    });
-    break;
+  } else {
+    ArmCfg.J1J2BranchEncoding = false;
+    ArmCfg.Stubs = StubsFlavor::pre_v7;
   }
   return ArmCfg;
 }
@@ -344,6 +339,43 @@ class GOTBuilder : public TableManager<GOTBuilder> {
   Section *GOTSection = nullptr;
 };
 
+/// Stubs builder emits non-position-independent Arm stubs for pre-v7 CPUs.
+/// These architectures have no MovT/MovW instructions and don't support Thumb2.
+/// BL is the only Thumb instruction that can generate stubs and they can always
+/// be transformed into BLX.
+class StubsManager_prev7 {
+public:
+  StubsManager_prev7() = default;
+
+  /// Name of the object file section that will contain all our stubs.
+  static StringRef getSectionName() {
+    return "__llvm_jitlink_aarch32_STUBS_prev7";
+  }
+
+  /// Implements link-graph traversal via visitExistingEdges()
+  bool visitEdge(LinkGraph &G, Block *B, Edge &E);
+
+private:
+  // Each stub uses a single block that can have 2 entryponts, one for Arm and
+  // one for Thumb
+  struct StubMapEntry {
+    Block *B = nullptr;
+    Symbol *ArmEntry = nullptr;
+    Symbol *ThumbEntry = nullptr;
+  };
+
+  std::pair<StubMapEntry *, bool> getStubMapSlot(StringRef Name) {
+    auto &&[Stubs, NewStub] = StubMap.try_emplace(Name);
+    return std::make_pair(&Stubs->second, NewStub);
+  }
+
+  Symbol *getOrCreateSlotEntrypoint(LinkGraph &G, StubMapEntry &Slot,
+                                    bool Thumb);
+
+  DenseMap<StringRef, StubMapEntry> StubMap;
+  Section *StubsSection = nullptr;
+};
+
 /// Stubs builder for v7 emits non-position-independent Arm and Thumb stubs.
 class StubsManager_v7 {
 public:

diff  --git a/llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp
index dfe6ab14adc2797..908b88fef1b3143 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp
@@ -259,21 +259,8 @@ createLinkGraphFromELFObject_aarch32(MemoryBufferRef ObjectBuffer) {
   // Resolve our internal configuration for the target. If at some point the
   // CPUArch alone becomes too unprecise, we can find more details in the
   // Tag_CPU_arch_profile.
-  aarch32::ArmConfig ArmCfg;
-  using namespace ARMBuildAttrs;
-  auto Arch = static_cast<CPUArch>(ARM::getArchAttr(AK));
-  switch (Arch) {
-  case v7:
-  case v8_A:
-    ArmCfg = aarch32::getArmConfigForCPUArch(Arch);
-    assert(ArmCfg.Stubs != aarch32::StubsFlavor::Unsupported &&
-           "Provide a config for each supported CPU");
-    break;
-  default:
-    return make_error<JITLinkError>(
-        "Failed to build ELF link graph: Unsupported CPU arch " +
-        StringRef(aarch32::getCPUArchName(Arch)));
-  }
+  auto Arch = static_cast<ARMBuildAttrs::CPUArch>(ARM::getArchAttr(AK));
+  aarch32::ArmConfig ArmCfg = aarch32::getArmConfigForCPUArch(Arch);
 
   // Populate the link-graph.
   switch (TT.getArch()) {
@@ -318,11 +305,15 @@ void link_ELF_aarch32(std::unique_ptr<LinkGraph> G,
       PassCfg.PrePrunePasses.push_back(markAllSymbolsLive);
 
     switch (ArmCfg.Stubs) {
+    case aarch32::StubsFlavor::pre_v7:
+      PassCfg.PostPrunePasses.push_back(
+          buildTables_ELF_aarch32<aarch32::StubsManager_prev7>);
+      break;
     case aarch32::StubsFlavor::v7:
       PassCfg.PostPrunePasses.push_back(
           buildTables_ELF_aarch32<aarch32::StubsManager_v7>);
       break;
-    case aarch32::StubsFlavor::Unsupported:
+    case aarch32::StubsFlavor::Undefined:
       llvm_unreachable("Check before building graph");
     }
   }

diff  --git a/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp b/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
index 96dff7656f17d63..00be2f57d066402 100644
--- a/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/aarch32.cpp
@@ -739,6 +739,13 @@ bool GOTBuilder::visitEdge(LinkGraph &G, Block *B, Edge &E) {
   return true;
 }
 
+const uint8_t ArmThumbv5LdrPc[] = {
+    0x78, 0x47,             // bx pc
+    0xfd, 0xe7,             // b #-6 ; Arm recommended sequence to follow bx pc
+    0x04, 0xf0, 0x1f, 0xe5, // ldr pc, [pc,#-4] ; L1
+    0x00, 0x00, 0x00, 0x00, // L1: .word S
+};
+
 const uint8_t Armv7ABS[] = {
     0x00, 0xc0, 0x00, 0xe3, // movw r12, #0x0000     ; lower 16-bit
     0x00, 0xc0, 0x40, 0xe3, // movt r12, #0x0000     ; upper 16-bit
@@ -759,6 +766,12 @@ static Block &allocStub(LinkGraph &G, Section &S, const uint8_t (&Code)[Size]) {
   return G.createContentBlock(S, Template, orc::ExecutorAddr(), Alignment, 0);
 }
 
+static Block &createStubPrev7(LinkGraph &G, Section &S, Symbol &Target) {
+  Block &B = allocStub(G, S, ArmThumbv5LdrPc);
+  B.addEdge(Data_Pointer32, 8, Target, 0);
+  return B;
+}
+
 static Block &createStubThumbv7(LinkGraph &G, Section &S, Symbol &Target) {
   Block &B = allocStub(G, S, Thumbv7ABS);
   B.addEdge(Thumb_MovwAbsNC, 0, Target, 0);
@@ -816,6 +829,60 @@ static bool needsStub(const Edge &E) {
   return false;
 }
 
+// The ArmThumbv5LdrPc stub has 2 entrypoints: Thumb at offset 0 is taken only
+// for Thumb B instructions. Thumb BL is rewritten to BLX and takes the Arm
+// entrypoint at offset 4. Arm branches always use that one.
+Symbol *StubsManager_prev7::getOrCreateSlotEntrypoint(LinkGraph &G,
+                                                      StubMapEntry &Slot,
+                                                      bool Thumb) {
+  constexpr orc::ExecutorAddrDiff ThumbEntrypointOffset = 0;
+  constexpr orc::ExecutorAddrDiff ArmEntrypointOffset = 4;
+  if (Thumb && !Slot.ThumbEntry) {
+    Slot.ThumbEntry =
+        &G.addAnonymousSymbol(*Slot.B, ThumbEntrypointOffset, 4, true, false);
+    Slot.ThumbEntry->setTargetFlags(ThumbSymbol);
+  }
+  if (!Thumb && !Slot.ArmEntry)
+    Slot.ArmEntry =
+        &G.addAnonymousSymbol(*Slot.B, ArmEntrypointOffset, 8, true, false);
+  return Thumb ? Slot.ThumbEntry : Slot.ArmEntry;
+}
+
+bool StubsManager_prev7::visitEdge(LinkGraph &G, Block *B, Edge &E) {
+  if (!needsStub(E))
+    return false;
+
+  Symbol &Target = E.getTarget();
+  assert(Target.hasName() && "Edge cannot point to anonymous target");
+  auto [Slot, NewStub] = getStubMapSlot(Target.getName());
+
+  if (NewStub) {
+    if (!StubsSection)
+      StubsSection = &G.createSection(getSectionName(),
+                                      orc::MemProt::Read | orc::MemProt::Exec);
+    LLVM_DEBUG({
+      dbgs() << "    Created stub entry for " << Target.getName() << " in "
+             << StubsSection->getName() << "\n";
+    });
+    Slot->B = &createStubPrev7(G, *StubsSection, Target);
+  }
+
+  // The ArmThumbv5LdrPc stub has 2 entrypoints: Thumb at offset 0 is taken only
+  // for Thumb B instructions. Thumb BL is rewritten to BLX and takes the Arm
+  // entrypoint at offset 4. Arm branches always use that one.
+  bool UseThumb = E.getKind() == Thumb_Jump24;
+  Symbol *StubEntrypoint = getOrCreateSlotEntrypoint(G, *Slot, UseThumb);
+
+  LLVM_DEBUG({
+    dbgs() << "    Using " << (UseThumb ? "Thumb" : "Arm") << " entrypoint "
+           << *StubEntrypoint << " in "
+           << StubEntrypoint->getBlock().getSection().getName() << "\n";
+  });
+
+  E.setTarget(*StubEntrypoint);
+  return true;
+}
+
 bool StubsManager_v7::visitEdge(LinkGraph &G, Block *B, Edge &E) {
   if (!needsStub(E))
     return false;

diff  --git a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_arm.s b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_arm.s
index 6fd383e2cce5c9f..3dec8c96f5cd575 100644
--- a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_arm.s
+++ b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_arm.s
@@ -1,8 +1,22 @@
-# RUN: llvm-mc -triple=armv7-linux-gnueabi -arm-add-build-attributes -filetype=obj -o %t.o %s
-# RUN: llvm-objdump -r %t.o | FileCheck --check-prefix=CHECK-TYPE %s
-# RUN: llvm-objdump --disassemble %t.o | FileCheck --check-prefix=CHECK-INSTR %s
+# Test pre-v7 Arm features
+#
+# RUN: llvm-mc -triple=armv4t-linux-gnueabi -arm-add-build-attributes -filetype=obj -o %t_armv4t.o %s
+# RUN: llvm-objdump -r %t_armv4t.o | FileCheck --check-prefix=CHECK-TYPE %s
+# RUN: llvm-objdump --disassemble %t_armv4t.o | FileCheck --check-prefix=CHECK-INSTR %s
 # RUN: llvm-jitlink -noexec -slab-address 0x76ff0000 -slab-allocate 10Kb \
-# RUN:              -slab-page-size 4096 -show-entry-es -check %s %t.o
+# RUN:              -slab-page-size 4096 -check %s %t_armv4t.o
+#
+# RUN: llvm-mc -triple=armv7-linux-gnueabi -arm-add-build-attributes -filetype=obj -o %t_armv7.o %s
+# RUN: llvm-objdump -r %t_armv7.o | FileCheck --check-prefix=CHECK-TYPE %s
+# RUN: llvm-objdump --disassemble %t_armv7.o | FileCheck --check-prefix=CHECK-INSTR %s
+# RUN: llvm-jitlink -noexec -slab-address 0x76ff0000 -slab-allocate 10Kb \
+# RUN:              -slab-page-size 4096 -check %s %t_armv7.o
+#
+# RUN: llvm-mc -triple=armv9-linux-gnueabi -arm-add-build-attributes -filetype=obj -o %t_armv9.o %s
+# RUN: llvm-objdump -r %t_armv9.o | FileCheck --check-prefix=CHECK-TYPE %s
+# RUN: llvm-objdump --disassemble %t_armv9.o | FileCheck --check-prefix=CHECK-INSTR %s
+# RUN: llvm-jitlink -noexec -slab-address 0x76ff0000 -slab-allocate 10Kb \
+# RUN:              -slab-page-size 4096 -check %s %t_armv9.o
 
 
 	.text
@@ -63,38 +77,6 @@ jump24_target:
 	bx	lr
 	.size	jump24_target,	.-jump24_target
 
-
-# CHECK-TYPE: {{[0-9a-f]+}} R_ARM_MOVW_ABS_NC data_symbol
-# CHECK-INSTR: 	0000001c <movw>:
-# CHECK-INSTR: 	      1c: e3000000     movw      r0, #0x0
-# jitlink-check: decode_operand(movw, 1) = (data_symbol&0x0000ffff)
-	.globl	movw
-	.type	movw,%function
-	.p2align	2
-movw:
-	movw r0, :lower16:data_symbol
-	.size	movw,	.-movw
-
-# CHECK-TYPE: {{[0-9a-f]+}} R_ARM_MOVT_ABS data_symbol
-# CHECK-INSTR: 	00000020 <movt>:
-# CHECK-INSTR: 	      20: e3400000     movt      r0, #0x0
-# We decode the operand with index 2, because movt generates one leading implicit
-# predicate operand that we have to skip in order to decode the data_symbol operand
-# jitlink-check: decode_operand(movt, 2) = (data_symbol&0xffff0000>>16)
-	.globl	movt
-	.type	movt,%function
-	.p2align	2
-movt:
-	movt r0, :upper16:data_symbol
-	.size	movt,	.-movt
-
-	.data
-	.global data_symbol
-data_symbol:
-	.long 1073741822
-
-	.text
-
 # Empty main function for jitlink to be happy
 	.globl	main
 	.type	main,%function

diff  --git a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_armv7plus.s b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_armv7plus.s
new file mode 100644
index 000000000000000..890b2136959ef12
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_armv7plus.s
@@ -0,0 +1,49 @@
+# Test v7 Arm features
+#
+# RUN: llvm-mc -triple=armv7-linux-gnueabi -arm-add-build-attributes -filetype=obj -o %t_armv7.o %s
+# RUN: llvm-objdump -r %t_armv7.o | FileCheck --check-prefix=CHECK-TYPE %s
+# RUN: llvm-objdump --disassemble %t_armv7.o | FileCheck --check-prefix=CHECK-INSTR %s
+# RUN: llvm-jitlink -noexec -slab-address 0x76ff0000 -slab-allocate 10Kb \
+# RUN:              -slab-page-size 4096 -abs data_symbol=0x00001234 -check %s %t_armv7.o
+#
+# RUN: llvm-mc -triple=armv9-linux-gnueabi -arm-add-build-attributes -filetype=obj -o %t_armv9.o %s
+# RUN: llvm-objdump -r %t_armv9.o | FileCheck --check-prefix=CHECK-TYPE %s
+# RUN: llvm-objdump --disassemble %t_armv9.o | FileCheck --check-prefix=CHECK-INSTR %s
+# RUN: llvm-jitlink -noexec -slab-address 0x76ff0000 -slab-allocate 10Kb \
+# RUN:              -slab-page-size 4096 -abs data_symbol=0x00001234 -check %s %t_armv9.o
+
+
+	.text
+	.syntax unified
+
+# CHECK-TYPE: {{[0-9a-f]+}} R_ARM_MOVW_ABS_NC data_symbol
+# CHECK-INSTR: <movw>:
+# CHECK-INSTR: e3000000 movw r0, #0x0
+# jitlink-check: decode_operand(movw, 1) = data_symbol[15:0]
+	.globl	movw
+	.type	movw,%function
+	.p2align	2
+movw:
+	movw r0, :lower16:data_symbol
+	.size	movw,	.-movw
+
+# CHECK-TYPE: {{[0-9a-f]+}} R_ARM_MOVT_ABS data_symbol
+# CHECK-INSTR: <movt>:
+# CHECK-INSTR: e3400000 movt r0, #0x0
+# We decode the operand with index 2, because movt generates one leading implicit
+# predicate operand that we have to skip in order to decode the data_symbol operand
+# jitlink-check: decode_operand(movt, 2) = data_symbol[31:16]
+	.globl	movt
+	.type	movt,%function
+	.p2align	2
+movt:
+	movt r0, :upper16:data_symbol
+	.size	movt,	.-movt
+
+# Empty main function for jitlink to be happy
+	.globl	main
+	.type	main,%function
+	.p2align	2
+main:
+	bx	lr
+	.size	main,	.-main

diff  --git a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_data.s b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_data.s
index 544e8c259d28687..4a2b281816d2bdb 100644
--- a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_data.s
+++ b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_data.s
@@ -1,4 +1,9 @@
-# RUN: rm -rf %t && mkdir -p %t/armv7 && mkdir -p %t/thumbv7
+# RUN: rm -rf %t && mkdir -p %t/armv6 && mkdir -p %t/armv7 && mkdir -p %t/thumbv7
+# RUN: llvm-mc -triple=armv6-none-linux-gnueabi -arm-add-build-attributes -filetype=obj -o %t/armv6/out.o %s
+# RUN: llvm-objdump -r %t/armv6/out.o | FileCheck --check-prefix=CHECK-TYPE %s
+# RUN: llvm-jitlink -noexec -slab-address 0x76ff0000 -slab-allocate 10Kb -slab-page-size 4096 \
+# RUN:              -abs target=0x76bbe88f -check %s %t/armv6/out.o
+
 # RUN: llvm-mc -triple=armv7-none-linux-gnueabi -arm-add-build-attributes -filetype=obj -o %t/armv7/out.o %s
 # RUN: llvm-objdump -r %t/armv7/out.o | FileCheck --check-prefix=CHECK-TYPE %s
 # RUN: llvm-jitlink -noexec -slab-address 0x76ff0000 -slab-allocate 10Kb -slab-page-size 4096 \

diff  --git a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_thumb.s b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_thumb.s
deleted file mode 100644
index 86f011834baae9f..000000000000000
--- a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_thumb.s
+++ /dev/null
@@ -1,145 +0,0 @@
-# RUN: llvm-mc -triple=thumbv7-linux-gnueabi -arm-add-build-attributes -filetype=obj -o %t.o %s
-# RUN: llvm-objdump -r %t.o | FileCheck --check-prefix=CHECK-TYPE %s
-# RUN: llvm-objdump --disassemble %t.o | FileCheck --check-prefix=CHECK-INSTR %s
-# RUN: llvm-jitlink -noexec -slab-address 0x76ff0000 -slab-allocate 10Kb \
-# RUN:              -slab-page-size 4096 -abs external_func=0x76bbe880 \
-# RUN:              -check %s %t.o
-
-
-	.text
-	.syntax unified
-
-# CHECK-TYPE: {{[0-9a-f]+}} R_ARM_THM_CALL call_target_thumb
-# CHECK-INSTR: 	00000000 <call_site>:
-# CHECK-INSTR: 	       0: f7ff fffe     bl
-# CHECK-INSTR: 	       4: f7ff fffe     bl
-# CHECK-INSTR: 	00000008 <call_target_thumb>
-# CHECK-INSTR: 	0000000c <call_target_arm>
-# We decode the operand with index 2, because bl generates two leading implicit
-# predicate operands that we have to skip in order to decode the call_target operand
-# jitlink-check: decode_operand(call_site + 0, 2) = call_target_thumb - (call_site + 4)
-# jitlink-check: decode_operand(call_site + 4, 2) = call_target_arm   - (call_site + 8)
-	.globl	call_site
-	.type	call_site,%function
-	.p2align	1
-	.code	16
-	.thumb_func
-call_site:
-	bl	call_target_thumb
-	bl	call_target_arm
-	.size	call_site, .-call_site
-
-	.globl	call_target_thumb
-	.type	call_target_thumb,%function
-	.p2align	1
-	.code	16
-	.thumb_func
-call_target_thumb:
-	bx	lr
-	.size	call_target_thumb, .-call_target_thumb
-
-	.globl	call_target_arm
-	.type	call_target_arm,%function
-	.p2align	2
-	.code	32
-call_target_arm:
-	bx	lr
-	.size	call_target_arm, .-call_target_arm
-
-# CHECK-TYPE: {{[0-9a-f]+}} R_ARM_THM_JUMP24 jump24_target
-# CHECK-INSTR: 	00000010 <jump24_site>:
-# CHECK-INSTR: 	      10: f7ff bffe     b.w
-# CHECK-INSTR: 	00000014 <jump24_target>
-# b.w generates two implicit predicate operands as well, but they are trailing
-# operands, so there is no need to adjust the operand index.
-# jitlink-check: decode_operand(jump24_site, 0) = jump24_target - next_pc(jump24_site)
-	.globl	jump24_site
-	.type	jump24_site,%function
-	.p2align	1
-	.code	16
-	.thumb_func
-jump24_site:
-	b.w	jump24_target
-	.size	jump24_site,	.-jump24_site
-
-	.globl	jump24_target
-	.type	jump24_target,%function
-	.p2align	1
-	.code	16
-	.thumb_func
-jump24_target:
-	bx	lr
-	.size	jump24_target,	.-jump24_target
-
-# CHECK-TYPE: {{[0-9a-f]+}} R_ARM_THM_MOVW_ABS_NC data_symbol
-# CHECK-INSTR: 	00000016 <movw>:
-# CHECK-INSTR: 	      16: f240 0000     movw    r0, #0x0
-# jitlink-check: decode_operand(movw, 1) = (data_symbol&0x0000ffff)
-	.globl	movw
-	.type	movw,%function
-	.p2align	1
-	.code	16
-	.thumb_func
-movw:
-	movw r0, :lower16:data_symbol
-	.size	movw,	.-movw
-
-# CHECK-TYPE: {{[0-9a-f]+}} R_ARM_THM_MOVT_ABS data_symbol
-# CHECK-INSTR: 	0000001a <movt>:
-# CHECK-INSTR: 	      1a: f2c0 0000     movt    r0, #0x0
-# We decode the operand with index 2, because movt generates one leading implicit
-# predicate operand that we have to skip in order to decode the data_symbol operand
-# jitlink-check: decode_operand(movt, 2) = (data_symbol&0xffff0000>>16)
-	.globl	movt
-	.type	movt,%function
-	.p2align	1
-	.code	16
-	.thumb_func
-movt:
-	movt r0, :upper16:data_symbol
-	.size	movt,	.-movt
-
-	.data
-	.global data_symbol
-data_symbol:
-	.long 1073741822
-
-	.text
-
-# CHECK-TYPE: {{[0-9a-f]+}} R_ARM_THM_MOVW_PREL_NC external_func
-# CHECK-INSTR: 	0000001e <movw_prel>:
-# CHECK-INSTR: 	      1e: f240 0000     movw    r0, #0x0
-# jitlink-check: decode_operand(movw_prel, 1) = \
-# jitlink-check:              ((external_func - movw_prel)&0x0000ffff)
-.globl	movw_prel
-.type	movw_prel,%function
-.p2align	1
-.code	16
-.thumb_func
-movw_prel:
-	movw r0, :lower16:external_func - .
-	.size	movw_prel,	.-movw_prel
-
-# CHECK-TYPE: {{[0-9a-f]+}} R_ARM_THM_MOVT_PREL external_func 
-# CHECK-INSTR: 	00000022 <movt_prel>:
-# CHECK-INSTR: 	      22: f2c0 0000    movt    r0, #0x0
-# jitlink-check: decode_operand(movt_prel, 2) = \
-# jitlink-check:               ((external_func - movt_prel)&0xffff0000>>16)
-.globl	movt_prel
-.type	movt_prel,%function
-.p2align	1
-.code	16
-.thumb_func
-movt_prel:
-	movt r0, :upper16:external_func - .
-	.size	movt_prel,	.-movt_prel
-
-# Empty main function for jitlink to be happy
-	.globl	main
-	.type	main,%function
-	.p2align	1
-	.code	16
-	.thumb_func
-main:
-	bx	lr
-	.size	main,	.-main

diff  --git a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_thumbv6m.s b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_thumbv6m.s
new file mode 100644
index 000000000000000..e0a224d9c710664
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_thumbv6m.s
@@ -0,0 +1,60 @@
+# Test pre-v7 Thumb features for Thumb-only targets
+#
+# RUN: llvm-mc -triple=thumbv6m-linux-gnueabi -arm-add-build-attributes -filetype=obj -o %t_thumbv6m.o %s
+# RUN: llvm-objdump -r %t_thumbv6m.o | FileCheck --check-prefix=CHECK-TYPE %s
+# RUN: llvm-objdump --disassemble %t_thumbv6m.o | FileCheck --check-prefix=CHECK-INSTR %s
+# RUN: llvm-jitlink -noexec -slab-address 0x76ff0000 -slab-allocate 10Kb \
+# RUN:              -slab-page-size 4096 -abs external_func=0x76bbe880 \
+# RUN:              -check %s %t_thumbv6m.o
+#
+# RUN: llvm-mc -triple=thumbv7m-linux-gnueabi -arm-add-build-attributes -filetype=obj -o %t_thumbv7m.o %s
+# RUN: llvm-objdump -r %t_thumbv7m.o | FileCheck --check-prefix=CHECK-TYPE %s
+# RUN: llvm-objdump --disassemble %t_thumbv7m.o | FileCheck --check-prefix=CHECK-INSTR %s
+# RUN: llvm-jitlink -noexec -slab-address 0x76ff0000 -slab-allocate 10Kb \
+# RUN:              -slab-page-size 4096 -abs external_func=0x76bbe880 \
+# RUN:              -check %s %t_thumbv7m.o
+#
+# RUN: llvm-mc -triple=thumbv7-linux-gnueabi -arm-add-build-attributes -filetype=obj -o %t_thumbv7.o %s
+# RUN: llvm-objdump -r %t_thumbv7.o | FileCheck --check-prefix=CHECK-TYPE %s
+# RUN: llvm-objdump --disassemble %t_thumbv7.o | FileCheck --check-prefix=CHECK-INSTR %s
+# RUN: llvm-jitlink -noexec -slab-address 0x76ff0000 -slab-allocate 10Kb \
+# RUN:              -slab-page-size 4096 -abs external_func=0x76bbe880 \
+# RUN:              -check %s %t_thumbv7.o
+
+
+	.text
+	.syntax unified
+
+# CHECK-TYPE: {{[0-9a-f]+}} R_ARM_THM_CALL call_target_thumb
+# CHECK-INSTR: <call_site>:
+# CHECK-INSTR: f7ff fffe     bl
+# We decode the operand with index 2, because bl generates two leading implicit
+# predicate operands that we have to skip in order to decode the call_target operand
+# jitlink-check: decode_operand(call_site, 2) = call_target_thumb - (call_site + 4)
+	.globl	call_site
+	.type	call_site,%function
+	.p2align	1
+	.code	16
+	.thumb_func
+call_site:
+	bl	call_target_thumb
+	.size	call_site, .-call_site
+
+	.globl	call_target_thumb
+	.type	call_target_thumb,%function
+	.p2align	1
+	.code	16
+	.thumb_func
+call_target_thumb:
+	bx	lr
+	.size	call_target_thumb, .-call_target_thumb
+
+# Empty main function for jitlink to be happy
+	.globl	main
+	.type	main,%function
+	.p2align	1
+	.code	16
+	.thumb_func
+main:
+	bx	lr
+	.size	main,	.-main

diff  --git a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_thumbv7a.s b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_thumbv7a.s
new file mode 100644
index 000000000000000..0e4a2cfb2c34965
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_thumbv7a.s
@@ -0,0 +1,45 @@
+# Test v7 Thumb features for mixed Arm/Thumb targets
+#
+# RUN: llvm-mc -triple=thumbv7-linux-gnueabi -arm-add-build-attributes -filetype=obj -o %t_thumbv7.o %s
+# RUN: llvm-objdump -r %t_thumbv7.o | FileCheck --check-prefix=CHECK-TYPE %s
+# RUN: llvm-objdump --disassemble %t_thumbv7.o | FileCheck --check-prefix=CHECK-INSTR %s
+# RUN: llvm-jitlink -noexec -slab-address 0x76ff0000 -slab-allocate 10Kb \
+# RUN:              -slab-page-size 4096 -abs external_func=0x76bbe880 \
+# RUN:              -check %s %t_thumbv7.o
+
+
+	.text
+	.syntax unified
+
+# CHECK-TYPE: {{[0-9a-f]+}} R_ARM_THM_CALL call_target_arm
+# CHECK-INSTR: <call_site>:
+# CHECK-INSTR: f7ff fffe     bl
+# We decode the operand with index 2, because bl generates two leading implicit
+# predicate operands that we have to skip in order to decode the call_target operand
+# jitlink-check: decode_operand(call_site, 2) = call_target_arm - next_pc(call_site)
+	.globl	call_site
+	.type	call_site,%function
+	.p2align	1
+	.code	16
+	.thumb_func
+call_site:
+	bl	call_target_arm
+	.size	call_site, .-call_site
+
+	.globl	call_target_arm
+	.type	call_target_arm,%function
+	.p2align	2
+	.code	32
+call_target_arm:
+	bx	lr
+	.size	call_target_arm, .-call_target_arm
+
+# Empty main function for jitlink to be happy
+	.globl	main
+	.type	main,%function
+	.p2align	1
+	.code	16
+	.thumb_func
+main:
+	bx	lr
+	.size	main,	.-main

diff  --git a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_thumbv7m.s b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_thumbv7m.s
new file mode 100644
index 000000000000000..4997fb3cf8ab1d4
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_relocations_thumbv7m.s
@@ -0,0 +1,107 @@
+# Test v7 Thumb features for Thumb-only targets
+#
+# RUN: llvm-mc -triple=thumbv7m-linux-gnueabi -arm-add-build-attributes -filetype=obj -o %t_thumbv7m.o %s
+# RUN: llvm-objdump -r %t_thumbv7m.o | FileCheck --check-prefix=CHECK-TYPE %s
+# RUN: llvm-objdump --disassemble %t_thumbv7m.o | FileCheck --check-prefix=CHECK-INSTR %s
+# RUN: llvm-jitlink -noexec -slab-address 0x76ff0000 -slab-allocate 10Kb \
+# RUN:              -slab-page-size 4096 -abs ext_func=0x76bbe880 -abs ext_data=0x00001234 \
+# RUN:              -check %s %t_thumbv7m.o
+#
+# RUN: llvm-mc -triple=thumbv7-linux-gnueabi -arm-add-build-attributes -filetype=obj -o %t_thumbv7.o %s
+# RUN: llvm-objdump -r %t_thumbv7.o | FileCheck --check-prefix=CHECK-TYPE %s
+# RUN: llvm-objdump --disassemble %t_thumbv7.o | FileCheck --check-prefix=CHECK-INSTR %s
+# RUN: llvm-jitlink -noexec -slab-address 0x76ff0000 -slab-allocate 10Kb \
+# RUN:              -slab-page-size 4096 -abs ext_func=0x76bbe880 -abs ext_data=0x00001234 \
+# RUN:              -check %s %t_thumbv7.o
+
+	.text
+	.syntax unified
+
+
+# CHECK-TYPE: {{[0-9a-f]+}} R_ARM_THM_JUMP24 jump24_target
+# CHECK-INSTR: <jump24_site>:
+# CHECK-INSTR: f7ff bffe     b.w
+# b.w generates two implicit predicate operands as well, but they are trailing
+# operands, so there is no need to adjust the operand index.
+# jitlink-check: decode_operand(jump24_site, 0) = jump24_target - next_pc(jump24_site)
+	.globl	jump24_site
+	.type	jump24_site,%function
+	.p2align	1
+	.code	16
+	.thumb_func
+jump24_site:
+	b.w	jump24_target
+	.size	jump24_site, .-jump24_site
+
+	.globl	jump24_target
+	.type	jump24_target,%function
+	.p2align	1
+	.code	16
+	.thumb_func
+jump24_target:
+	bx	lr
+	.size	jump24_target, .-jump24_target
+
+# CHECK-TYPE: {{[0-9a-f]+}} R_ARM_THM_MOVW_ABS_NC ext_data
+# CHECK-INSTR: <movw>:
+# CHECK-INSTR: f240 0000     movw    r0, #0x0
+# jitlink-check: decode_operand(movw, 1) = ext_data[15:0]
+	.globl	movw
+	.type	movw,%function
+	.p2align	1
+	.code	16
+	.thumb_func
+movw:
+	movw r0, :lower16:ext_data
+	.size	movw,	.-movw
+
+# CHECK-TYPE: {{[0-9a-f]+}} R_ARM_THM_MOVT_ABS ext_data
+# CHECK-INSTR: <movt>:
+# CHECK-INSTR: f2c0 0000     movt    r0, #0x0
+# We decode the operand with index 2, because movt generates one leading implicit
+# predicate operand that we have to skip in order to decode the ext_data operand
+# jitlink-check: decode_operand(movt, 2) = ext_data[31:16]
+	.globl	movt
+	.type	movt,%function
+	.p2align	1
+	.code	16
+	.thumb_func
+movt:
+	movt r0, :upper16:ext_data
+	.size	movt,	.-movt
+
+# CHECK-TYPE: {{[0-9a-f]+}} R_ARM_THM_MOVW_PREL_NC ext_func
+# CHECK-INSTR: <movw_prel>:
+# CHECK-INSTR: f240 0000     movw    r0, #0x0
+# jitlink-check: decode_operand(movw_prel, 1) = (ext_func - movw_prel)[15:0]
+  .globl	movw_prel
+  .type	movw_prel,%function
+  .p2align	1
+  .code	16
+  .thumb_func
+movw_prel:
+	movw r0, :lower16:ext_func - .
+	.size	movw_prel, .-movw_prel
+
+# CHECK-TYPE: {{[0-9a-f]+}} R_ARM_THM_MOVT_PREL ext_func
+# CHECK-INSTR: <movt_prel>:
+# CHECK-INSTR: f2c0 0000    movt    r0, #0x0
+# jitlink-check: decode_operand(movt_prel, 2) = (ext_func - movt_prel)[31:16]
+  .globl	movt_prel
+  .type	movt_prel,%function
+  .p2align	1
+  .code	16
+  .thumb_func
+movt_prel:
+	movt r0, :upper16:ext_func - .
+	.size	movt_prel, .-movt_prel
+
+# Empty main function for jitlink to be happy
+	.globl	main
+	.type	main,%function
+	.p2align	1
+	.code	16
+	.thumb_func
+main:
+	bx	lr
+	.size	main,	.-main

diff  --git a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_stubs_arm.s b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_stubs_arm.s
index fb2e0eb2c0bf249..d3a596c811ec4e3 100644
--- a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_stubs_arm.s
+++ b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_stubs_arm.s
@@ -1,10 +1,22 @@
-# RUN: rm -rf %t && mkdir -p %t
+# RUN: rm -rf %t && mkdir -p %t/armv4t && mkdir -p %t/armv6 && mkdir -p %t/armv7
+#
+# RUN: llvm-mc -triple=armv4t-linux-gnueabi -arm-add-build-attributes \
+# RUN:         -filetype=obj -o %t/armv4t/out.o %s
+# RUN: llvm-jitlink -noexec -slab-address 0x76ff0000 \
+# RUN:              -slab-allocate 10Kb -slab-page-size 4096 \
+# RUN:              -abs ext=0x76bbe880 -check %s %t/armv4t/out.o
+#
+# RUN: llvm-mc -triple=armv6-linux-gnueabi -arm-add-build-attributes \
+# RUN:         -filetype=obj -o %t/armv6/out.o %s
+# RUN: llvm-jitlink -noexec -slab-address 0x76ff0000 \
+# RUN:              -slab-allocate 10Kb -slab-page-size 4096 \
+# RUN:              -abs ext=0x76bbe880 -check %s %t/armv6/out.o
+#
 # RUN: llvm-mc -triple=armv7-linux-gnueabi -arm-add-build-attributes \
-# RUN:         -filetype=obj -o %t/out.o %s
+# RUN:         -filetype=obj -o %t/armv7/out.o %s
 # RUN: llvm-jitlink -noexec -slab-address 0x76ff0000 \
 # RUN:              -slab-allocate 10Kb -slab-page-size 4096 \
-# RUN:              -abs ext=0x76bbe880 \
-# RUN:              -check %s %t/out.o
+# RUN:              -abs ext=0x76bbe880 -check %s %t/armv7/out.o
 
 	.text
 	.syntax unified
@@ -36,10 +48,10 @@ test_arm_call:
 	pop	{pc}
 	.size	test_arm_call, .-test_arm_call
 
-# This test is executable with both, Arm and Thumb `ext` functions. It only has
-# to return with `bx lr`. For example:
-#   > echo "void ext() {}" | clang -target armv7-linux-gnueabihf -o ext-arm.o -c -xc -
-#   > llvm-jitlink ext-arm.o out.o
+# This test is executable with any Arm (and for v7+ also Thumb) `ext` functions.
+# It only has to return with `bx lr`. For example:
+#   > echo "void ext() {}" | clang -target armv7-linux-gnueabihf -o ext.o -c -xc -
+#   > llvm-jitlink ext.o out.o
 #
 	.globl	main
 	.type	main,%function
@@ -48,6 +60,6 @@ main:
 	push	{lr}
 	bl	test_arm_call
 	bl	test_arm_jump
-	movw	r0, #0
+	mov	r0, #0
 	pop	{pc}
 	.size	main, .-main

diff  --git a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_stubs_thumb.s b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_stubs_thumb.s
index f6156628ce2a9fe..aa8c917a08809f0 100644
--- a/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_stubs_thumb.s
+++ b/llvm/test/ExecutionEngine/JITLink/AArch32/ELF_stubs_thumb.s
@@ -1,10 +1,17 @@
-# RUN: rm -rf %t && mkdir -p %t
+# RUN: rm -rf %t && mkdir -p %t/thumbv7m && mkdir -p %t/thumbv7
+#
+# RUN: llvm-mc -triple=thumbv7m-linux-gnueabi -arm-add-build-attributes \
+# RUN:         -filetype=obj -o %t/thumbv7m/out.o %s
+# RUN: llvm-jitlink -noexec -slab-address 0x76ff0000 \
+# RUN:              -slab-allocate 10Kb -slab-page-size 4096 \
+# RUN:              -abs ext=0x76bbe880 -check %s %t/thumbv7m/out.o
+#
 # RUN: llvm-mc -triple=thumbv7-linux-gnueabi -arm-add-build-attributes \
-# RUN:         -filetype=obj -o %t/elf_stubs.o %s
+# RUN:         -filetype=obj -o %t/thumbv7/out.o %s
 # RUN: llvm-jitlink -noexec -slab-address 0x76ff0000 \
 # RUN:              -slab-allocate 10Kb -slab-page-size 4096 \
-# RUN:              -abs external_func=0x76bbe880 \
-# RUN:              -check %s %t/elf_stubs.o
+# RUN:              -abs ext=0x76bbe880 -check %s %t/thumbv7/out.o
+
 
 	.text
 	.syntax unified
@@ -14,15 +21,15 @@
 # where the branch-target address is loaded from a GOT entry. Instead, they
 # hard-code it in the immediate field.
 #
-# jitlink-check: decode_operand(test_external_call, 2) = stub_addr(elf_stubs.o, external_func) - next_pc(test_external_call)
-# jitlink-check: decode_operand(test_external_jump, 0) = stub_addr(elf_stubs.o, external_func) - next_pc(test_external_jump)
+# jitlink-check: decode_operand(test_external_call, 2) = stub_addr(out.o, ext) - next_pc(test_external_call)
+# jitlink-check: decode_operand(test_external_jump, 0) = stub_addr(out.o, ext) - next_pc(test_external_jump)
 	.globl  test_external_call
 	.type	test_external_call,%function
 	.p2align	1
 	.code	16
 	.thumb_func
 test_external_call:
-	bl	external_func
+	bl	ext
 	.size test_external_call, .-test_external_call
 
 	.globl  test_external_jump
@@ -31,7 +38,7 @@ test_external_call:
 	.code	16
 	.thumb_func
 test_external_jump:
-	b	external_func
+	b	ext
 	.size test_external_jump, .-test_external_jump
 
 # Empty main function for jitlink to be happy


        


More information about the llvm-commits mailing list