summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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