]> granicus.if.org Git - llvm/commitdiff
AArch64: Add a tagged-globals backend feature.
authorPeter Collingbourne <peter@pcc.me.uk>
Wed, 31 Jul 2019 20:14:19 +0000 (20:14 +0000)
committerPeter Collingbourne <peter@pcc.me.uk>
Wed, 31 Jul 2019 20:14:19 +0000 (20:14 +0000)
This feature instructs the backend to allow locally defined global variable
addresses to contain a pointer tag in bits 56-63 that will be ignored by
the hardware (i.e. TBI), but may be used by an instrumentation pass such
as HWASAN. It works by adding a MOVK instruction to the regular ADRP/ADD
sequence that sets bits 48-63 to the corresponding bits of the global, with
the linker bounds check disabled on the ADRP instruction to prevent the tag
from causing a link failure.

This implementation of the feature omits the MOVK when loading from or storing
to a global, which is sufficient for TBI. If the same approach is extended
to MTE, assuming that 0 is not configured as a catch-all tag, we will most
likely also need the MOVK in this case in order to avoid a tag mismatch.

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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@367475 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/AArch64/AArch64.td
lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp
lib/Target/AArch64/AArch64InstrInfo.cpp
lib/Target/AArch64/AArch64MCInstLower.cpp
lib/Target/AArch64/AArch64Subtarget.cpp
lib/Target/AArch64/AArch64Subtarget.h
lib/Target/AArch64/Utils/AArch64BaseInfo.h
test/CodeGen/AArch64/tagged-globals.ll [new file with mode: 0644]

index 57e4b329ded29e96b3e4fb9f2eb74ec72a18b7cd..c55fc24105f727746e6b8361748d53e28492c525 100644 (file)
@@ -355,6 +355,11 @@ def FeatureETE : SubtargetFeature<"ete", "HasETE",
 def FeatureTME : SubtargetFeature<"tme", "HasTME",
     "true", "Enable Transactional Memory Extension" >;
 
+def FeatureTaggedGlobals : SubtargetFeature<"tagged-globals",
+    "AllowTaggedGlobals",
+    "true", "Use an instruction sequence for taking the address of a global "
+    "that allows a memory tag in the upper address bits">;
+
 //===----------------------------------------------------------------------===//
 // Architectures.
 //
index 210c10eb18421d8dc756d482869e020c1911256b..ea90cb8236d024ce26e42d1811dfa5bda52b75c2 100644 (file)
@@ -539,6 +539,23 @@ bool AArch64ExpandPseudo::expandMI(MachineBasicBlock &MBB,
         BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::ADRP), DstReg)
             .add(MI.getOperand(1));
 
+    if (MI.getOperand(1).getTargetFlags() & AArch64II::MO_TAGGED) {
+      // MO_TAGGED on the page indicates a tagged address. Set the tag now.
+      // We do so by creating a MOVK that sets bits 48-63 of the register to
+      // (global address + 0x100000000 - PC) >> 48. This assumes that we're in
+      // the small code model so we can assume a binary size of <= 4GB, which
+      // makes the untagged PC relative offset positive. The binary must also be
+      // loaded into address range [0, 2^48). Both of these properties need to
+      // be ensured at runtime when using tagged addresses.
+      auto Tag = MI.getOperand(1);
+      Tag.setTargetFlags(AArch64II::MO_PREL | AArch64II::MO_G3);
+      Tag.setOffset(0x100000000);
+      BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::MOVKXi), DstReg)
+          .addReg(DstReg)
+          .add(Tag)
+          .addImm(48);
+    }
+
     MachineInstrBuilder MIB2 =
         BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::ADDXri))
             .add(MI.getOperand(0))
index 4edd25b46c3ee73fb6c341801ec19aa0a0dd7772..5d7385c4e70145c9eb6d3fd892729275e1146f92 100644 (file)
@@ -4739,7 +4739,8 @@ AArch64InstrInfo::getSerializableBitmaskMachineOperandTargetFlags() const {
       {MO_COFFSTUB, "aarch64-coffstub"},
       {MO_GOT, "aarch64-got"},   {MO_NC, "aarch64-nc"},
       {MO_S, "aarch64-s"},       {MO_TLS, "aarch64-tls"},
-      {MO_DLLIMPORT, "aarch64-dllimport"}};
+      {MO_DLLIMPORT, "aarch64-dllimport"},
+      {MO_PREL, "aarch64-prel"}};
   return makeArrayRef(TargetFlags);
 }
 
index e7d4a2789a28fdf8db75a4c06252ae160c070402..afd5ae6bcbf2cc5dce8c6110c8a1a7e9cbb0aa04 100644 (file)
@@ -148,6 +148,8 @@ MCOperand AArch64MCInstLower::lowerSymbolOperandELF(const MachineOperand &MO,
       RefFlags |= AArch64MCExpr::VK_TLSDESC;
       break;
     }
+  } else if (MO.getTargetFlags() & AArch64II::MO_PREL) {
+    RefFlags |= AArch64MCExpr::VK_PREL;
   } else {
     // No modifier means this is a generic reference, classified as absolute for
     // the cases where it matters (:abs_g0: etc).
index 6a45b4e57d7719e6179aaed6747c4964c3a0c5ac..fb82b264706b66a73102318f14cf2d0e70354c7c 100644 (file)
@@ -229,6 +229,13 @@ AArch64Subtarget::ClassifyGlobalReference(const GlobalValue *GV,
       GV->hasExternalWeakLinkage())
     return AArch64II::MO_GOT;
 
+  // References to tagged globals are marked with MO_NC | MO_TAGGED to indicate
+  // that their nominal addresses are tagged and outside of the code model. In
+  // AArch64ExpandPseudo::expandMI we emit an additional instruction to set the
+  // tag if necessary based on MO_TAGGED.
+  if (AllowTaggedGlobals && !isa<FunctionType>(GV->getValueType()))
+    return AArch64II::MO_NC | AArch64II::MO_TAGGED;
+
   return AArch64II::MO_NO_FLAG;
 }
 
index 3bd1ad0e60f1eb18c3228cd3a538d7acf400c9c9..bf976b0abc28d7399c2a0f093d78243995b4988d 100644 (file)
@@ -191,6 +191,7 @@ protected:
   bool UseEL1ForTP = false;
   bool UseEL2ForTP = false;
   bool UseEL3ForTP = false;
+  bool AllowTaggedGlobals = false;
   uint8_t MaxInterleaveFactor = 2;
   uint8_t VectorInsertExtractBaseCost = 3;
   uint16_t CacheLineSize = 0;
index e5e2fc2cb0df4b9b5b7efb4b50bb17e9f0d0478a..0545329a5836efe496f015b0798177d52fcaa860 100644 (file)
@@ -627,6 +627,14 @@ namespace AArch64II {
     /// MO_S - Indicates that the bits of the symbol operand represented by
     /// MO_G0 etc are signed.
     MO_S = 0x100,
+
+    /// MO_PREL - Indicates that the bits of the symbol operand represented by
+    /// MO_G0 etc are PC relative.
+    MO_PREL = 0x200,
+
+    /// MO_TAGGED - With MO_PAGE, indicates that the page includes a memory tag
+    /// in bits 56-63.
+    MO_TAGGED = 0x400,
   };
 } // end namespace AArch64II
 
diff --git a/test/CodeGen/AArch64/tagged-globals.ll b/test/CodeGen/AArch64/tagged-globals.ll
new file mode 100644 (file)
index 0000000..b0cf882
--- /dev/null
@@ -0,0 +1,32 @@
+; RUN: llc < %s | FileCheck %s
+
+target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
+target triple = "aarch64-unknown-linux-android"
+
+@global = external hidden global i32
+declare void @func()
+
+define i32* @global_addr() #0 {
+  ; CHECK: global_addr:
+  ; CHECK: adrp x0, :pg_hi21_nc:global
+  ; CHECK: movk x0, #:prel_g3:global+4294967296
+  ; CHECK: add x0, x0, :lo12:global
+  ret i32* @global
+}
+
+define i32 @global_load() #0 {
+  ; CHECK: global_load:
+  ; CHECK: adrp x8, :pg_hi21_nc:global
+  ; CHECK: ldr w0, [x8, :lo12:global]
+  %load = load i32, i32* @global
+  ret i32 %load
+}
+
+define void ()* @func_addr() #0 {
+  ; CHECK: func_addr:
+  ; CHECK: adrp x0, func
+  ; CHECK: add x0, x0, :lo12:func
+  ret void ()* @func
+}
+
+attributes #0 = { "target-features"="+tagged-globals" }