summaryrefslogtreecommitdiffstats
path: root/llvm
diff options
context:
space:
mode:
authorOliver Stannard <oliver.stannard@arm.com>2018-10-08 14:04:24 +0000
committerOliver Stannard <oliver.stannard@arm.com>2018-10-08 14:04:24 +0000
commit250e5a5b655f67d58470533a7b21ce38d7946d50 (patch)
treeadff3250f0798fad85f09d5d2c0b8e6ff4df469b /llvm
parent1aedf203dd17e58be86c61a6fd674b3f8d41b296 (diff)
downloadbcm5719-llvm-250e5a5b655f67d58470533a7b21ce38d7946d50.tar.gz
bcm5719-llvm-250e5a5b655f67d58470533a7b21ce38d7946d50.zip
[AArch64][v8.5A] Branch Target Identification code-generation pass
The Branch Target Identification extension, introduced to AArch64 in Armv8.5-A, adds the BTI instruction, which is used to mark valid targets of indirect branches. When enabled, the processor will trap if an instruction in a protected page tries to perform an indirect branch to any instruction other than a BTI. The BTI instruction uses encodings which were NOPs in earlier versions of the architecture, so BTI-enabled code will still run on earlier hardware, just without the extra protection. There are 3 variants of the BTI instruction, which are valid targets for different kinds or branches: - BTI C can be targeted by call instructions, and is inteneded to be used at function entry points. These are the BLR instruction, as well as BR with x16 or x17. These BR instructions are allowed for use in PLT entries, and we can also use them to allow indirect tail-calls. - BTI J can be targeted by BR only, and is intended to be used by jump tables. - BTI JC acts ab both a BTI C and a BTI J instruction, and can be targeted by any BLR or BR instruction. Note that RET instructions are not restricted by branch target identification, the reason for this is that return addresses can be protected more effectively using return address signing. Direct branches and calls are also unaffected, as it is assumed that an attacker cannot modify executable pages (if they could, they wouldn't need to do a ROP/JOP attack). This patch adds a MachineFunctionPass which: - Adds a BTI C at the start of every function which could be indirectly called (either because it is address-taken, or externally visible so could be address-taken in another translation unit). - Adds a BTI J at the start of every basic block which could be indirectly branched to. This could be either done by a jump table, or by taking the address of the block (e.g. the using GCC label values extension). We only need to use BTI JC when a function is indirectly-callable, and takes the address of the entry block. I've not been able to trigger this from C or IR, but I've included a MIR test just in case. Using BTI C at function entries relies on the fact that no other code in BTI-protected pages uses indirect tail-calls, unless they use x16 or x17 to hold the address. I'll add that code-generation restriction as a separate patch. Differential revision: https://reviews.llvm.org/D52867 llvm-svn: 343967
Diffstat (limited to 'llvm')
-rw-r--r--llvm/lib/Target/AArch64/AArch64.h2
-rw-r--r--llvm/lib/Target/AArch64/AArch64BranchTargets.cpp130
-rw-r--r--llvm/lib/Target/AArch64/AArch64TargetMachine.cpp9
-rw-r--r--llvm/lib/Target/AArch64/CMakeLists.txt1
-rw-r--r--llvm/test/CodeGen/AArch64/O0-pipeline.ll1
-rw-r--r--llvm/test/CodeGen/AArch64/O3-pipeline.ll1
-rw-r--r--llvm/test/CodeGen/AArch64/branch-target-enforcment.mir325
7 files changed, 469 insertions, 0 deletions
diff --git a/llvm/lib/Target/AArch64/AArch64.h b/llvm/lib/Target/AArch64/AArch64.h
index 74f22e287f8..6472dcd5157 100644
--- a/llvm/lib/Target/AArch64/AArch64.h
+++ b/llvm/lib/Target/AArch64/AArch64.h
@@ -46,6 +46,7 @@ FunctionPass *createAArch64A57FPLoadBalancing();
FunctionPass *createAArch64A53Fix835769();
FunctionPass *createFalkorHWPFFixPass();
FunctionPass *createFalkorMarkStridedAccessesPass();
+FunctionPass *createAArch64BranchTargetsPass();
FunctionPass *createAArch64CleanupLocalDynamicTLSPass();
@@ -58,6 +59,7 @@ FunctionPass *createAArch64PreLegalizeCombiner();
void initializeAArch64A53Fix835769Pass(PassRegistry&);
void initializeAArch64A57FPLoadBalancingPass(PassRegistry&);
void initializeAArch64AdvSIMDScalarPass(PassRegistry&);
+void initializeAArch64BranchTargetsPass(PassRegistry&);
void initializeAArch64CollectLOHPass(PassRegistry&);
void initializeAArch64CondBrTuningPass(PassRegistry &);
void initializeAArch64ConditionalComparesPass(PassRegistry&);
diff --git a/llvm/lib/Target/AArch64/AArch64BranchTargets.cpp b/llvm/lib/Target/AArch64/AArch64BranchTargets.cpp
new file mode 100644
index 00000000000..da70a624c5b
--- /dev/null
+++ b/llvm/lib/Target/AArch64/AArch64BranchTargets.cpp
@@ -0,0 +1,130 @@
+//===-- AArch64BranchTargets.cpp -- Harden code using v8.5-A BTI extension -==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass inserts BTI instructions at the start of every function and basic
+// block which could be indirectly called. The hardware will (when enabled)
+// trap when an indirect branch or call instruction targets an instruction
+// which is not a valid BTI instruction. This is intended to guard against
+// control-flow hijacking attacks. Note that this does not do anything for RET
+// instructions, as they can be more precisely protected by return address
+// signing.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AArch64Subtarget.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineJumpTableInfo.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/Support/Debug.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "aarch64-branch-targets"
+#define AARCH64_BRANCH_TARGETS_NAME "AArch64 Branch Targets"
+
+namespace {
+class AArch64BranchTargets : public MachineFunctionPass {
+public:
+ static char ID;
+ AArch64BranchTargets() : MachineFunctionPass(ID) {}
+ void getAnalysisUsage(AnalysisUsage &AU) const override;
+ bool runOnMachineFunction(MachineFunction &MF) override;
+ StringRef getPassName() const override { return AARCH64_BRANCH_TARGETS_NAME; }
+
+private:
+ void addBTI(MachineBasicBlock &MBB, bool CouldCall, bool CouldJump);
+};
+} // end anonymous namespace
+
+char AArch64BranchTargets::ID = 0;
+
+INITIALIZE_PASS(AArch64BranchTargets, "aarch64-branch-targets",
+ AARCH64_BRANCH_TARGETS_NAME, false, false)
+
+void AArch64BranchTargets::getAnalysisUsage(AnalysisUsage &AU) const {
+ AU.setPreservesCFG();
+ MachineFunctionPass::getAnalysisUsage(AU);
+}
+
+FunctionPass *llvm::createAArch64BranchTargetsPass() {
+ return new AArch64BranchTargets();
+}
+
+bool AArch64BranchTargets::runOnMachineFunction(MachineFunction &MF) {
+ const Function &F = MF.getFunction();
+ if (!F.hasFnAttribute("branch-target-enforcement"))
+ return false;
+
+ LLVM_DEBUG(
+ dbgs() << "********** AArch64 Branch Targets **********\n"
+ << "********** Function: " << MF.getName() << '\n');
+
+ // LLVM does not consider basic blocks which are the targets of jump tables
+ // to be address-taken (the address can't escape anywhere else), but they are
+ // used for indirect branches, so need BTI instructions.
+ SmallPtrSet<MachineBasicBlock *, 8> JumpTableTargets;
+ if (auto *JTI = MF.getJumpTableInfo())
+ for (auto &JTE : JTI->getJumpTables())
+ for (auto *MBB : JTE.MBBs)
+ JumpTableTargets.insert(MBB);
+
+ bool MadeChange = false;
+ for (MachineBasicBlock &MBB : MF) {
+ bool CouldCall = false, CouldJump = false;
+ // If the function is address-taken or externally-visible, it could be
+ // indirectly called. PLT entries and tail-calls use BR, but when they are
+ // are in guarded pages should all use x16 or x17 to hold the called
+ // address, so we don't need to set CouldJump here. BR instructions in
+ // non-guarded pages (which might be non-BTI-aware code) are allowed to
+ // branch to a "BTI c" using any register.
+ if (&MBB == &*MF.begin() && (F.hasAddressTaken() || !F.hasLocalLinkage()))
+ CouldCall = true;
+
+ // If the block itself is address-taken, it could be indirectly branched
+ // to, but not called.
+ if (MBB.hasAddressTaken() || JumpTableTargets.count(&MBB))
+ CouldJump = true;
+
+ if (CouldCall || CouldJump) {
+ addBTI(MBB, CouldCall, CouldJump);
+ MadeChange = true;
+ }
+ }
+
+ return MadeChange;
+}
+
+void AArch64BranchTargets::addBTI(MachineBasicBlock &MBB, bool CouldCall,
+ bool CouldJump) {
+ LLVM_DEBUG(dbgs() << "Adding BTI " << (CouldJump ? "j" : "")
+ << (CouldCall ? "c" : "") << " to " << MBB.getName()
+ << "\n");
+
+ const AArch64InstrInfo *TII = static_cast<const AArch64InstrInfo *>(
+ MBB.getParent()->getSubtarget().getInstrInfo());
+
+ unsigned HintNum = 32;
+ if (CouldCall)
+ HintNum |= 2;
+ if (CouldJump)
+ HintNum |= 4;
+ assert(HintNum != 32 && "No target kinds!");
+
+ auto MBBI = MBB.begin();
+
+ // PACI[AB]SP are implicitly BTI JC, so no BTI instruction needed there.
+ if (MBBI != MBB.end() && (MBBI->getOpcode() == AArch64::PACIASP ||
+ MBBI->getOpcode() == AArch64::PACIBSP))
+ return;
+
+ BuildMI(MBB, MBB.begin(), MBB.findDebugLoc(MBB.begin()),
+ TII->get(AArch64::HINT))
+ .addImm(HintNum);
+}
diff --git a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
index a66f5277f24..e183288d8df 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
@@ -141,6 +141,11 @@ static cl::opt<int> EnableGlobalISelAtO(
static cl::opt<bool> EnableFalkorHWPFFix("aarch64-enable-falkor-hwpf-fix",
cl::init(true), cl::Hidden);
+static cl::opt<bool>
+ EnableBranchTargets("aarch64-enable-branch-targets", cl::Hidden,
+ cl::desc("Enable the AAcrh64 branch target pass"),
+ cl::init(true));
+
extern "C" void LLVMInitializeAArch64Target() {
// Register the target.
RegisterTargetMachine<AArch64leTargetMachine> X(getTheAArch64leTarget());
@@ -151,6 +156,7 @@ extern "C" void LLVMInitializeAArch64Target() {
initializeAArch64A53Fix835769Pass(*PR);
initializeAArch64A57FPLoadBalancingPass(*PR);
initializeAArch64AdvSIMDScalarPass(*PR);
+ initializeAArch64BranchTargetsPass(*PR);
initializeAArch64CollectLOHPass(*PR);
initializeAArch64ConditionalComparesPass(*PR);
initializeAArch64ConditionOptimizerPass(*PR);
@@ -537,6 +543,9 @@ void AArch64PassConfig::addPreEmitPass() {
if (BranchRelaxation)
addPass(&BranchRelaxationPassID);
+ if (EnableBranchTargets)
+ addPass(createAArch64BranchTargetsPass());
+
if (TM->getOptLevel() != CodeGenOpt::None && EnableCollectLOH &&
TM->getTargetTriple().isOSBinFormatMachO())
addPass(createAArch64CollectLOHPass());
diff --git a/llvm/lib/Target/AArch64/CMakeLists.txt b/llvm/lib/Target/AArch64/CMakeLists.txt
index e6ca69c1971..c57ebeb854c 100644
--- a/llvm/lib/Target/AArch64/CMakeLists.txt
+++ b/llvm/lib/Target/AArch64/CMakeLists.txt
@@ -22,6 +22,7 @@ add_llvm_target(AArch64CodeGen
AArch64A57FPLoadBalancing.cpp
AArch64AdvSIMDScalarPass.cpp
AArch64AsmPrinter.cpp
+ AArch64BranchTargets.cpp
AArch64CallLowering.cpp
AArch64CleanupLocalDynamicTLSPass.cpp
AArch64CollectLOH.cpp
diff --git a/llvm/test/CodeGen/AArch64/O0-pipeline.ll b/llvm/test/CodeGen/AArch64/O0-pipeline.ll
index 5121cf76ac4..d85d126883c 100644
--- a/llvm/test/CodeGen/AArch64/O0-pipeline.ll
+++ b/llvm/test/CodeGen/AArch64/O0-pipeline.ll
@@ -52,6 +52,7 @@
; CHECK-NEXT: AArch64 pseudo instruction expansion pass
; CHECK-NEXT: Analyze Machine Code For Garbage Collection
; CHECK-NEXT: Branch relaxation pass
+; CHECK-NEXT: AArch64 Branch Targets
; CHECK-NEXT: Contiguously Lay Out Funclets
; CHECK-NEXT: StackMap Liveness Analysis
; CHECK-NEXT: Live DEBUG_VALUE analysis
diff --git a/llvm/test/CodeGen/AArch64/O3-pipeline.ll b/llvm/test/CodeGen/AArch64/O3-pipeline.ll
index aa5a5578d24..33bc05f91d5 100644
--- a/llvm/test/CodeGen/AArch64/O3-pipeline.ll
+++ b/llvm/test/CodeGen/AArch64/O3-pipeline.ll
@@ -150,6 +150,7 @@
; CHECK-NEXT: MachinePostDominator Tree Construction
; CHECK-NEXT: Branch Probability Basic Block Placement
; CHECK-NEXT: Branch relaxation pass
+; CHECK-NEXT: AArch64 Branch Targets
; CHECK-NEXT: Contiguously Lay Out Funclets
; CHECK-NEXT: StackMap Liveness Analysis
; CHECK-NEXT: Live DEBUG_VALUE analysis
diff --git a/llvm/test/CodeGen/AArch64/branch-target-enforcment.mir b/llvm/test/CodeGen/AArch64/branch-target-enforcment.mir
new file mode 100644
index 00000000000..2cc6354d5db
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/branch-target-enforcment.mir
@@ -0,0 +1,325 @@
+# RUN: llc -run-pass=aarch64-branch-targets %s -o - | FileCheck %s
+--- |
+ target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
+ target triple = "aarch64-arm-none-eabi"
+
+ define hidden i32 @simple_external() "branch-target-enforcement" {
+ entry:
+ ret i32 0
+ }
+
+ define internal i32 @simple_internal() "branch-target-enforcement" {
+ entry:
+ ret i32 0
+ }
+
+ define hidden i32 @ptr_auth() "branch-target-enforcement" {
+ entry:
+ tail call void asm sideeffect "", "~{lr}"()
+ ret i32 0
+ }
+
+ define hidden i32 @ptr_auth_b() "branch-target-enforcement" {
+ entry:
+ tail call void asm sideeffect "", "~{lr}"()
+ ret i32 0
+ }
+
+ define hidden i32 @jump_table(i32 %a) "branch-target-enforcement" {
+ entry:
+ switch i32 %a, label %sw.epilog [
+ i32 1, label %sw.bb
+ i32 2, label %sw.bb1
+ i32 3, label %sw.bb2
+ i32 4, label %sw.bb3
+ i32 5, label %sw.bb4
+ ]
+
+ sw.bb: ; preds = %entry
+ tail call void asm sideeffect "", ""()
+ br label %sw.epilog
+
+ sw.bb1: ; preds = %entry
+ tail call void asm sideeffect "", ""()
+ br label %sw.epilog
+
+ sw.bb2: ; preds = %entry
+ tail call void asm sideeffect "", ""()
+ br label %sw.epilog
+
+ sw.bb3: ; preds = %entry
+ tail call void asm sideeffect "", ""()
+ br label %sw.epilog
+
+ sw.bb4: ; preds = %entry
+ tail call void asm sideeffect "", ""()
+ br label %sw.epilog
+
+ sw.epilog: ; preds = %entry, %sw.bb4, %sw.bb3, %sw.bb2, %sw.bb1, %sw.bb
+ ret i32 0
+ }
+
+ @label_address.addr = internal unnamed_addr global i8* blockaddress(@label_address, %return), align 8
+
+ define hidden i32 @label_address() "branch-target-enforcement" {
+ entry:
+ %0 = load i8*, i8** @label_address.addr, align 8
+ indirectbr i8* %0, [label %return, label %lab2]
+
+ lab2: ; preds = %entry
+ br label %.split
+
+ return: ; preds = %entry
+ br label %.split
+
+ .split: ; preds = %lab2, %return
+ %merge = phi i8* [ blockaddress(@label_address, %lab2), %return ], [ blockaddress(@label_address, %return), %lab2 ]
+ %merge2 = phi i32 [ 1, %return ], [ 2, %lab2 ]
+ store i8* %merge, i8** @label_address.addr, align 8
+ ret i32 %merge2
+ }
+
+ define hidden i32 @label_address_entry() "branch-target-enforcement" {
+ entry:
+ %0 = load i8*, i8** @label_address.addr, align 8
+ indirectbr i8* %0, [label %return, label %lab2]
+
+ lab2: ; preds = %entry
+ br label %.split
+
+ return: ; preds = %entry
+ br label %.split
+
+ .split: ; preds = %lab2, %return
+ %merge = phi i8* [ blockaddress(@label_address, %lab2), %return ], [ blockaddress(@label_address, %return), %lab2 ]
+ %merge2 = phi i32 [ 1, %return ], [ 2, %lab2 ]
+ store i8* %merge, i8** @label_address.addr, align 8
+ ret i32 %merge2
+ }
+
+...
+---
+# External function, could be addres-taken elsewhere so needs BTI JC.
+name: simple_external
+body: |
+ bb.0.entry:
+ ; CHECK-LABEL: name: simple_external
+ ; CHECK: HINT 34
+ ; CHECK: RET
+ $w0 = ORRWrs $wzr, $wzr, 0
+ RET undef $lr, implicit killed $w0
+
+---
+# Internal function, not address-taken in this module, so no BTI needed.
+name: simple_internal
+body: |
+ bb.0.entry:
+ ; CHECK-LABEL: name: simple_internal
+ ; CHECK-NOT: HINT
+ ; CHECK: RET
+ $w0 = ORRWrs $wzr, $wzr, 0
+ RET undef $lr, implicit killed $w0
+
+---
+# Function starts with PACIASP, which implicitly acts as BTI JC, so no change
+# needed.
+name: ptr_auth
+stack:
+ - { id: 0, name: '', type: spill-slot, offset: -16, size: 8, alignment: 16,
+ stack-id: 0, callee-saved-register: '$lr', callee-saved-restored: true,
+ debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+body: |
+ bb.0.entry:
+ liveins: $lr
+
+ ; CHECK-LABEL: name: ptr_auth
+ ; CHECK-NOT: HINT
+ ; CHECK: frame-setup PACIASP
+ ; CHECK-NOT: HINT
+ ; CHECK: RETAA
+ frame-setup PACIASP implicit-def $lr, implicit killed $lr, implicit $sp
+ early-clobber $sp = frame-setup STRXpre killed $lr, $sp, -16 :: (store 8 into %stack.0)
+ INLINEASM &"", 1, 12, implicit-def dead early-clobber $lr
+ $w0 = ORRWrs $wzr, $wzr, 0
+ early-clobber $sp, $lr = frame-destroy LDRXpost $sp, 16 :: (load 8 from %stack.0)
+ RETAA implicit killed $w0
+
+---
+# Function starts with PACIBSP, which implicitly acts as BTI JC, so no change
+# needed.
+name: ptr_auth_b
+stack:
+ - { id: 0, name: '', type: spill-slot, offset: -16, size: 8, alignment: 16,
+ stack-id: 0, callee-saved-register: '$lr', callee-saved-restored: true,
+ debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+body: |
+ bb.0.entry:
+ liveins: $lr
+
+ ; CHECK-LABEL: name: ptr_auth_b
+ ; CHECK-NOT: HINT
+ ; CHECK: frame-setup PACIBSP
+ ; CHECK-NOT: HINT
+ ; CHECK: RETAB
+ frame-setup PACIBSP implicit-def $lr, implicit killed $lr, implicit $sp
+ early-clobber $sp = frame-setup STRXpre killed $lr, $sp, -16 :: (store 8 into %stack.0)
+ INLINEASM &"", 1, 12, implicit-def dead early-clobber $lr
+ $w0 = ORRWrs $wzr, $wzr, 0
+ early-clobber $sp, $lr = frame-destroy LDRXpost $sp, 16 :: (load 8 from %stack.0)
+ RETAB implicit killed $w0
+
+---
+# Function contains a jump table, so every target of the jump table must start
+# with BTI J.
+name: jump_table
+jumpTable:
+ kind: block-address
+ entries:
+ - id: 0
+ blocks: [ '%bb.2', '%bb.3', '%bb.4', '%bb.5', '%bb.6' ]
+body: |
+ bb.0.entry:
+ ; CHECK-LABEL: name: jump_table
+ ; CHECK: HINT 34
+ successors: %bb.7(0x15555555), %bb.1(0x6aaaaaab)
+ liveins: $w0
+
+ renamable $w8 = SUBWri killed renamable $w0, 1, 0, implicit-def $x8
+ dead $wzr = SUBSWri renamable $w8, 4, 0, implicit-def $nzcv
+ Bcc 8, %bb.7, implicit $nzcv
+
+ bb.1.entry:
+ ; CHECK: bb.1.entry:
+ ; CHECK-NOT: HINT
+ ; CHECK: BR killed renamable $x8
+ successors: %bb.2(0x1999999a), %bb.3(0x1999999a), %bb.4(0x1999999a), %bb.5(0x1999999a), %bb.6(0x1999999a)
+ liveins: $x8
+
+ $x9 = ADRP target-flags(aarch64-page) %jump-table.0
+ renamable $x9 = ADDXri killed $x9, target-flags(aarch64-pageoff, aarch64-nc) %jump-table.0, 0
+ renamable $x8 = LDRXroX killed renamable $x9, killed renamable $x8, 0, 1 :: (load 8 from jump-table)
+ BR killed renamable $x8
+
+ bb.2.sw.bb:
+ ; CHECK: bb.2.sw.bb
+ ; CHECK-NEXT: HINT 36
+ $w0 = ORRWrs $wzr, $wzr, 0
+ INLINEASM &"", 1
+ RET undef $lr, implicit killed $w0
+
+ bb.3.sw.bb1:
+ ; CHECK: bb.3.sw.bb1
+ ; CHECK-NEXT: HINT 36
+ $w0 = ORRWrs $wzr, $wzr, 0
+ INLINEASM &"", 1
+ RET undef $lr, implicit killed $w0
+
+ bb.4.sw.bb2:
+ ; CHECK: bb.4.sw.bb2
+ ; CHECK-NEXT: HINT 36
+ $w0 = ORRWrs $wzr, $wzr, 0
+ INLINEASM &"", 1
+ RET undef $lr, implicit killed $w0
+
+ bb.5.sw.bb3:
+ ; CHECK: bb.5.sw.bb3
+ ; CHECK-NEXT: HINT 36
+ $w0 = ORRWrs $wzr, $wzr, 0
+ INLINEASM &"", 1
+ RET undef $lr, implicit killed $w0
+
+ bb.6.sw.bb4:
+ ; CHECK: bb.6.sw.bb4
+ ; CHECK-NEXT: successors: %bb.7(0x80000000)
+ ; CHECK-NEXT: {{ }}
+ ; CHECK-NEXT: HINT 36
+ successors: %bb.7(0x80000000)
+
+ INLINEASM &"", 1
+
+ bb.7.sw.epilog:
+ ; CHECK: bb.7.sw.epilog:
+ ; CHECK-NOT: HINT
+ ; CHECK: RET
+ $w0 = ORRWrs $wzr, $wzr, 0
+ RET undef $lr, implicit killed $w0
+
+---
+# Function takes address of basic blocks, so they must start with BTI J.
+name: label_address
+body: |
+ bb.0.entry:
+ ; CHECK-LABEL: label_address
+ ; CHECK: bb.0.entry:
+ ; CHECK-NEXT: successors: %bb.1(0x40000000), %bb.2(0x40000000)
+ ; CHECK-NEXT: {{ }}
+ ; CHECK-NEXT: HINT 34
+ ; CHECK: BR killed renamable $x9
+ successors: %bb.1(0x40000000), %bb.2(0x40000000)
+
+ renamable $x8 = ADRP target-flags(aarch64-page) @label_address.addr
+ renamable $x9 = LDRXui renamable $x8, target-flags(aarch64-pageoff, aarch64-nc) @label_address.addr :: (dereferenceable load 8 from @label_address.addr)
+ BR killed renamable $x9
+
+ bb.1.return (address-taken):
+ ; CHECK: bb.1.return (address-taken):
+ ; CHECK-NEXT: HINT 36
+ liveins: $x8
+
+ $x9 = ADRP target-flags(aarch64-page) blockaddress(@label_address, %ir-block.lab2)
+ renamable $w0 = ORRWri $wzr, 0
+ renamable $x9 = ADDXri killed $x9, target-flags(aarch64-pageoff, aarch64-nc) blockaddress(@label_address, %ir-block.lab2), 0
+ STRXui killed renamable $x9, killed renamable $x8, target-flags(aarch64-pageoff, aarch64-nc) @label_address.addr :: (store 8 into @label_address.addr)
+ RET undef $lr, implicit killed $w0
+
+ bb.2.lab2 (address-taken):
+ ; CHECK: bb.2.lab2 (address-taken):
+ ; CHECK-NEXT: HINT 36
+ liveins: $x8
+
+ $x9 = ADRP target-flags(aarch64-page) blockaddress(@label_address, %ir-block.return)
+ renamable $w0 = ORRWri $wzr, 1984
+ renamable $x9 = ADDXri killed $x9, target-flags(aarch64-pageoff, aarch64-nc) blockaddress(@label_address, %ir-block.return), 0
+ STRXui killed renamable $x9, killed renamable $x8, target-flags(aarch64-pageoff, aarch64-nc) @label_address.addr :: (store 8 into @label_address.addr)
+ RET undef $lr, implicit killed $w0
+
+---
+# Function takes address of the entry block, so the entry block needs a BTI JC.
+name: label_address_entry
+body: |
+ bb.0.entry (address-taken):
+ ; CHECK-LABEL: label_address_entry
+ ; CHECK: bb.0.entry (address-taken):
+ ; CHECK-NEXT: successors: %bb.1(0x40000000), %bb.2(0x40000000)
+ ; CHECK-NEXT: {{ }}
+ ; CHECK-NEXT: HINT 38
+ ; CHECK: BR killed renamable $x9
+ successors: %bb.1(0x40000000), %bb.2(0x40000000)
+
+ renamable $x8 = ADRP target-flags(aarch64-page) @label_address.addr
+ renamable $x9 = LDRXui renamable $x8, target-flags(aarch64-pageoff, aarch64-nc) @label_address.addr :: (dereferenceable load 8 from @label_address.addr)
+ BR killed renamable $x9
+
+ bb.1.return (address-taken):
+ ; CHECK: bb.1.return (address-taken):
+ ; CHECK-NEXT: HINT 36
+ liveins: $x8
+
+ $x9 = ADRP target-flags(aarch64-page) blockaddress(@label_address, %ir-block.entry)
+ renamable $w0 = ORRWri $wzr, 0
+ renamable $x9 = ADDXri killed $x9, target-flags(aarch64-pageoff, aarch64-nc) blockaddress(@label_address, %ir-block.entry), 0
+ STRXui killed renamable $x9, killed renamable $x8, target-flags(aarch64-pageoff, aarch64-nc) @label_address.addr :: (store 8 into @label_address.addr)
+ RET undef $lr, implicit killed $w0
+
+ bb.2.lab2:
+ ; CHECK: bb.2.lab2:
+ ; CHECK-NOT: HINT
+ liveins: $x8
+
+ $x9 = ADRP target-flags(aarch64-page) blockaddress(@label_address, %ir-block.return)
+ renamable $w0 = ORRWri $wzr, 1984
+ renamable $x9 = ADDXri killed $x9, target-flags(aarch64-pageoff, aarch64-nc) blockaddress(@label_address, %ir-block.return), 0
+ STRXui killed renamable $x9, killed renamable $x8, target-flags(aarch64-pageoff, aarch64-nc) @label_address.addr :: (store 8 into @label_address.addr)
+ RET undef $lr, implicit killed $w0
+
+...
OpenPOWER on IntegriCloud