From: Kristof Beyls Date: Thu, 11 Jun 2020 06:42:16 +0000 (+0100) Subject: [AArch64] Introduce AArch64SLSHardeningPass, implementing hardening of RET and BR... X-Git-Tag: llvmorg-12-init~3402 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=0ee176edc8b4a6f20527e907bfd026b07a27e7ef;p=platform%2Fupstream%2Fllvm.git [AArch64] Introduce AArch64SLSHardeningPass, implementing hardening of RET and BR instructions. Some processors may speculatively execute the instructions immediately following RET (returns) and BR (indirect jumps), even though control flow should change unconditionally at these instructions. To avoid a potential miss-speculatively executed gadget after these instructions leaking secrets through side channels, this pass places a speculation barrier immediately after every RET and BR instruction. Since these barriers are never on the correct, architectural execution path, performance overhead of this is expected to be low. On targets that implement that Armv8.0-SB Speculation Barrier extension, a single SB instruction is emitted that acts as a speculation barrier. On other targets, a DSB SYS followed by a ISB is emitted to act as a speculation barrier. These speculation barriers are implemented as pseudo instructions to avoid later passes to analyze them and potentially remove them. Even though currently LLVM does not produce BRAA/BRAB/BRAAZ/BRABZ instructions, these are also mitigated by the pass and tested through a MIR test. The mitigation is off by default and can be enabled by the harden-sls-retbr subtarget feature. Differential Revision: https://reviews.llvm.org/D81400 --- diff --git a/llvm/lib/Target/AArch64/AArch64.h b/llvm/lib/Target/AArch64/AArch64.h index c182536..e62a405 100644 --- a/llvm/lib/Target/AArch64/AArch64.h +++ b/llvm/lib/Target/AArch64/AArch64.h @@ -38,6 +38,7 @@ FunctionPass *createAArch64ISelDag(AArch64TargetMachine &TM, CodeGenOpt::Level OptLevel); FunctionPass *createAArch64StorePairSuppressPass(); FunctionPass *createAArch64ExpandPseudoPass(); +FunctionPass *createAArch64SLSHardeningPass(); FunctionPass *createAArch64SpeculationHardeningPass(); FunctionPass *createAArch64LoadStoreOptimizationPass(); FunctionPass *createAArch64SIMDInstrOptPass(); @@ -72,6 +73,7 @@ void initializeAArch64ConditionalComparesPass(PassRegistry&); void initializeAArch64ConditionOptimizerPass(PassRegistry&); void initializeAArch64DeadRegisterDefinitionsPass(PassRegistry&); void initializeAArch64ExpandPseudoPass(PassRegistry&); +void initializeAArch64SLSHardeningPass(PassRegistry&); void initializeAArch64SpeculationHardeningPass(PassRegistry&); void initializeAArch64LoadStoreOptPass(PassRegistry&); void initializeAArch64SIMDInstrOptPass(PassRegistry&); diff --git a/llvm/lib/Target/AArch64/AArch64.td b/llvm/lib/Target/AArch64/AArch64.td index 88a89cf..4dac0fa 100644 --- a/llvm/lib/Target/AArch64/AArch64.td +++ b/llvm/lib/Target/AArch64/AArch64.td @@ -458,6 +458,14 @@ def FeatureUseEL#i#ForTP : SubtargetFeature<"tpidr-el"#i, "UseEL"#i#"ForTP", "true", "Permit use of TPIDR_EL"#i#" for the TLS base">; //===----------------------------------------------------------------------===// +// Control codegen mitigation against Straight Line Speculation vulnerability. +//===----------------------------------------------------------------------===// + +def FeatureHardenSlsRetBr : SubtargetFeature<"harden-sls-retbr", + "HardenSlsRetBr", "true", + "Harden against straight line speculation across RET and BR instructions">; + +//===----------------------------------------------------------------------===// // AArch64 Processors supported. // diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp index c450558..f4ccf65 100644 --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -1115,6 +1115,25 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) { EmitToStreamer(*OutStreamer, TmpInst); return; } + case AArch64::SpeculationBarrierISBDSBEndBB: { + // Print DSB SYS + ISB + MCInst TmpInstDSB; + TmpInstDSB.setOpcode(AArch64::DSB); + TmpInstDSB.addOperand(MCOperand::createImm(0xf)); + EmitToStreamer(*OutStreamer, TmpInstDSB); + MCInst TmpInstISB; + TmpInstISB.setOpcode(AArch64::ISB); + TmpInstISB.addOperand(MCOperand::createImm(0xf)); + EmitToStreamer(*OutStreamer, TmpInstISB); + return; + } + case AArch64::SpeculationBarrierSBEndBB: { + // Print SB + MCInst TmpInstSB; + TmpInstSB.setOpcode(AArch64::SB); + EmitToStreamer(*OutStreamer, TmpInstSB); + return; + } case AArch64::TLSDESC_CALLSEQ: { /// lower this to: /// adrp x0, :tlsdesc:var diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp index ed8c5f6..ab588c9 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp @@ -111,6 +111,14 @@ unsigned AArch64InstrInfo::getInstSizeInBytes(const MachineInstr &MI) const { // This gets lowered to an instruction sequence which takes 16 bytes NumBytes = 16; break; + case AArch64::SpeculationBarrierISBDSBEndBB: + // This gets lowered to 2 4-byte instructions. + NumBytes = 8; + break; + case AArch64::SpeculationBarrierSBEndBB: + // This gets lowered to 1 4-byte instructions. + NumBytes = 4; + break; case AArch64::JumpTableDest32: case AArch64::JumpTableDest16: case AArch64::JumpTableDest8: @@ -230,6 +238,12 @@ bool AArch64InstrInfo::analyzeBranch(MachineBasicBlock &MBB, if (I == MBB.end()) return false; + // Skip over SpeculationBarrierEndBB terminators + if (I->getOpcode() == AArch64::SpeculationBarrierISBDSBEndBB || + I->getOpcode() == AArch64::SpeculationBarrierSBEndBB) { + --I; + } + if (!isUnpredicatedTerminator(*I)) return false; diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.h b/llvm/lib/Target/AArch64/AArch64InstrInfo.h index e05b183..70b6513 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.h +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.h @@ -386,7 +386,15 @@ static inline bool isCondBranchOpcode(int Opc) { } static inline bool isIndirectBranchOpcode(int Opc) { - return Opc == AArch64::BR; + switch (Opc) { + case AArch64::BR: + case AArch64::BRAA: + case AArch64::BRAB: + case AArch64::BRAAZ: + case AArch64::BRABZ: + return true; + } + return false; } // struct TSFlags { diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td index 5aa7376..6a03270 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -711,6 +711,14 @@ let hasSideEffects = 1, isCodeGenOnly = 1 in { : Pseudo<(outs GPR32:$dst), (ins GPR32:$src), []>, Sched<[]>; } +// SpeculationBarrierEndBB must only be used after an unconditional control +// flow, i.e. after a terminator for which isBarrier is True. +let hasSideEffects = 1, isCodeGenOnly = 1, isTerminator = 1, isBarrier = 1 in { + def SpeculationBarrierISBDSBEndBB + : Pseudo<(outs), (ins), []>, Sched<[]>; + def SpeculationBarrierSBEndBB + : Pseudo<(outs), (ins), []>, Sched<[]>; +} //===----------------------------------------------------------------------===// // System instructions. diff --git a/llvm/lib/Target/AArch64/AArch64SLSHardening.cpp b/llvm/lib/Target/AArch64/AArch64SLSHardening.cpp new file mode 100644 index 0000000..c37b5b7 --- /dev/null +++ b/llvm/lib/Target/AArch64/AArch64SLSHardening.cpp @@ -0,0 +1,120 @@ +//===- AArch64SLSHardening.cpp - Harden Straight Line Missspeculation -----===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains a pass to insert code to mitigate against side channel +// vulnerabilities that may happen under straight line miss-speculation. +// +//===----------------------------------------------------------------------===// + +#include "AArch64InstrInfo.h" +#include "AArch64Subtarget.h" +#include "Utils/AArch64BaseInfo.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineOperand.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/RegisterScavenging.h" +#include "llvm/IR/DebugLoc.h" +#include "llvm/Pass.h" +#include "llvm/Support/CodeGen.h" +#include "llvm/Support/Debug.h" +#include "llvm/Target/TargetMachine.h" +#include + +using namespace llvm; + +#define DEBUG_TYPE "aarch64-sls-hardening" + +#define AARCH64_SLS_HARDENING_NAME "AArch64 sls hardening pass" + +namespace { + +class AArch64SLSHardening : public MachineFunctionPass { +public: + const TargetInstrInfo *TII; + const TargetRegisterInfo *TRI; + const AArch64Subtarget *ST; + + static char ID; + + AArch64SLSHardening() : MachineFunctionPass(ID) { + initializeAArch64SLSHardeningPass(*PassRegistry::getPassRegistry()); + } + + bool runOnMachineFunction(MachineFunction &Fn) override; + + StringRef getPassName() const override { return AARCH64_SLS_HARDENING_NAME; } + +private: + bool hardenReturnsAndBRs(MachineBasicBlock &MBB) const; + void insertSpeculationBarrier(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + DebugLoc DL) const; +}; + +} // end anonymous namespace + +char AArch64SLSHardening::ID = 0; + +INITIALIZE_PASS(AArch64SLSHardening, "aarch64-sls-hardening", + AARCH64_SLS_HARDENING_NAME, false, false) + +void AArch64SLSHardening::insertSpeculationBarrier( + MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, + DebugLoc DL) const { + assert(MBBI != MBB.begin() && + "Must not insert SpeculationBarrierEndBB as only instruction in MBB."); + assert(std::prev(MBBI)->isBarrier() && + "SpeculationBarrierEndBB must only follow unconditional control flow " + "instructions."); + assert(std::prev(MBBI)->isTerminator() && + "SpeculatoinBarrierEndBB must only follow terminators."); + if (ST->hasSB()) + BuildMI(MBB, MBBI, DL, TII->get(AArch64::SpeculationBarrierSBEndBB)); + else + BuildMI(MBB, MBBI, DL, TII->get(AArch64::SpeculationBarrierISBDSBEndBB)); +} + +bool AArch64SLSHardening::runOnMachineFunction(MachineFunction &MF) { + ST = &MF.getSubtarget(); + TII = MF.getSubtarget().getInstrInfo(); + TRI = MF.getSubtarget().getRegisterInfo(); + + bool Modified = false; + for (auto &MBB : MF) + Modified |= hardenReturnsAndBRs(MBB); + + return Modified; +} + +bool AArch64SLSHardening::hardenReturnsAndBRs(MachineBasicBlock &MBB) const { + if (!ST->hardenSlsRetBr()) + return false; + bool Modified = false; + MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator(), E = MBB.end(); + MachineBasicBlock::iterator NextMBBI; + for (; MBBI != E; MBBI = NextMBBI) { + MachineInstr &MI = *MBBI; + NextMBBI = std::next(MBBI); + if (MI.isReturn() || isIndirectBranchOpcode(MI.getOpcode())) { + assert(MI.isTerminator()); + insertSpeculationBarrier(MBB, std::next(MBBI), MI.getDebugLoc()); + Modified = true; + } + } + return Modified; +} + +FunctionPass *llvm::createAArch64SLSHardeningPass() { + return new AArch64SLSHardening(); +} diff --git a/llvm/lib/Target/AArch64/AArch64Subtarget.h b/llvm/lib/Target/AArch64/AArch64Subtarget.h index 09a8cf5..6d21831 100644 --- a/llvm/lib/Target/AArch64/AArch64Subtarget.h +++ b/llvm/lib/Target/AArch64/AArch64Subtarget.h @@ -210,6 +210,7 @@ protected: bool UseEL2ForTP = false; bool UseEL3ForTP = false; bool AllowTaggedGlobals = false; + bool HardenSlsRetBr = false; uint8_t MaxInterleaveFactor = 2; uint8_t VectorInsertExtractBaseCost = 3; uint16_t CacheLineSize = 0; @@ -363,6 +364,8 @@ public: hasFuseCCSelect() || hasFuseLiterals(); } + bool hardenSlsRetBr() const { return HardenSlsRetBr; } + bool useEL1ForTP() const { return UseEL1ForTP; } bool useEL2ForTP() const { return UseEL2ForTP; } bool useEL3ForTP() const { return UseEL3ForTP; } diff --git a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp index 75fbd1c9..8c3e38c 100644 --- a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp +++ b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp @@ -192,6 +192,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeAArch64Target() { initializeLDTLSCleanupPass(*PR); initializeSVEIntrinsicOptsPass(*PR); initializeAArch64SpeculationHardeningPass(*PR); + initializeAArch64SLSHardeningPass(*PR); initializeAArch64StackTaggingPass(*PR); initializeAArch64StackTaggingPreRAPass(*PR); } @@ -635,6 +636,8 @@ void AArch64PassConfig::addPreSched2() { // info. addPass(createAArch64SpeculationHardeningPass()); + addPass(createAArch64SLSHardeningPass()); + if (TM->getOptLevel() != CodeGenOpt::None) { if (EnableFalkorHWPFFix) addPass(createFalkorHWPFFixPass()); diff --git a/llvm/lib/Target/AArch64/CMakeLists.txt b/llvm/lib/Target/AArch64/CMakeLists.txt index 823b9df..5dda8ef 100644 --- a/llvm/lib/Target/AArch64/CMakeLists.txt +++ b/llvm/lib/Target/AArch64/CMakeLists.txt @@ -59,6 +59,7 @@ add_llvm_target(AArch64CodeGen AArch64PromoteConstant.cpp AArch64PBQPRegAlloc.cpp AArch64RegisterInfo.cpp + AArch64SLSHardening.cpp AArch64SelectionDAGInfo.cpp AArch64SpeculationHardening.cpp AArch64StackTagging.cpp diff --git a/llvm/test/CodeGen/AArch64/O0-pipeline.ll b/llvm/test/CodeGen/AArch64/O0-pipeline.ll index a1141e2..504bdfa 100644 --- a/llvm/test/CodeGen/AArch64/O0-pipeline.ll +++ b/llvm/test/CodeGen/AArch64/O0-pipeline.ll @@ -55,6 +55,7 @@ ; CHECK-NEXT: Post-RA pseudo instruction expansion pass ; CHECK-NEXT: AArch64 pseudo instruction expansion pass ; CHECK-NEXT: AArch64 speculation hardening pass +; CHECK-NEXT: AArch64 sls hardening pass ; CHECK-NEXT: Analyze Machine Code For Garbage Collection ; CHECK-NEXT: Insert fentry calls ; CHECK-NEXT: Insert XRay ops diff --git a/llvm/test/CodeGen/AArch64/O3-pipeline.ll b/llvm/test/CodeGen/AArch64/O3-pipeline.ll index 55e0c7b..869ee9c 100644 --- a/llvm/test/CodeGen/AArch64/O3-pipeline.ll +++ b/llvm/test/CodeGen/AArch64/O3-pipeline.ll @@ -178,6 +178,7 @@ ; CHECK-NEXT: AArch64 pseudo instruction expansion pass ; CHECK-NEXT: AArch64 load / store optimization pass ; CHECK-NEXT: AArch64 speculation hardening pass +; CHECK-NEXT: AArch64 sls hardening pass ; CHECK-NEXT: MachineDominator Tree Construction ; CHECK-NEXT: Machine Natural Loop Construction ; CHECK-NEXT: Falkor HW Prefetch Fix Late Phase diff --git a/llvm/test/CodeGen/AArch64/speculation-hardening-sls.ll b/llvm/test/CodeGen/AArch64/speculation-hardening-sls.ll new file mode 100644 index 0000000..9d2741b --- /dev/null +++ b/llvm/test/CodeGen/AArch64/speculation-hardening-sls.ll @@ -0,0 +1,104 @@ +; RUN: llc -mattr=harden-sls-retbr -verify-machineinstrs -mtriple=aarch64-none-linux-gnu < %s | FileCheck %s --check-prefixes=CHECK,ISBDSB +; RUN: llc -mattr=harden-sls-retbr -mattr=+sb -verify-machineinstrs -mtriple=aarch64-none-linux-gnu < %s | FileCheck %s --check-prefixes=CHECK,SB + + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @double_return(i32 %a, i32 %b) local_unnamed_addr { +entry: + %cmp = icmp sgt i32 %a, 0 + br i1 %cmp, label %if.then, label %if.else + +if.then: ; preds = %entry + %div = sdiv i32 %a, %b + ret i32 %div + +if.else: ; preds = %entry + %div1 = sdiv i32 %b, %a + ret i32 %div1 +; CHECK-LABEL: double_return: +; CHECK: {{ret$}} +; ISBDSB-NEXT: dsb sy +; ISBDSB-NEXT: isb +; SB-NEXT: {{ sb$}} +; CHECK: {{ret$}} +; ISBDSB-NEXT: dsb sy +; ISBDSB-NEXT: isb +; SB-NEXT: {{ sb$}} +} + +@__const.indirect_branch.ptr = private unnamed_addr constant [2 x i8*] [i8* blockaddress(@indirect_branch, %return), i8* blockaddress(@indirect_branch, %l2)], align 8 + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @indirect_branch(i32 %a, i32 %b, i32 %i) { +entry: + %idxprom = sext i32 %i to i64 + %arrayidx = getelementptr inbounds [2 x i8*], [2 x i8*]* @__const.indirect_branch.ptr, i64 0, i64 %idxprom + %0 = load i8*, i8** %arrayidx, align 8 + indirectbr i8* %0, [label %return, label %l2] + +l2: ; preds = %entry + br label %return + +return: ; preds = %entry, %l2 + %retval.0 = phi i32 [ 1, %l2 ], [ 0, %entry ] + ret i32 %retval.0 +; CHECK-LABEL: indirect_branch: +; CHECK: br x +; ISBDSB-NEXT: dsb sy +; ISBDSB-NEXT: isb +; SB-NEXT: {{ sb$}} +; CHECK: {{ret$}} +; ISBDSB-NEXT: dsb sy +; ISBDSB-NEXT: isb +; SB-NEXT: {{ sb$}} +} + +; Check that RETAA and RETAB instructions are also protected as expected. +define dso_local i32 @ret_aa(i32 returned %a) local_unnamed_addr "target-features"="+neon,+v8.3a" "sign-return-address"="all" "sign-return-address-key"="a_key" { +entry: +; CHECK-LABEL: ret_aa: +; CHECK: {{ retaa$}} +; ISBDSB-NEXT: dsb sy +; ISBDSB-NEXT: isb +; SB-NEXT: {{ sb$}} + ret i32 %a +} + +define dso_local i32 @ret_ab(i32 returned %a) local_unnamed_addr "target-features"="+neon,+v8.3a" "sign-return-address"="all" "sign-return-address-key"="b_key" { +entry: +; CHECK-LABEL: ret_ab: +; CHECK: {{ retab$}} +; ISBDSB-NEXT: dsb sy +; ISBDSB-NEXT: isb +; SB-NEXT: {{ sb$}} + ret i32 %a +} + +define i32 @asmgoto() { +entry: +; CHECK-LABEL: asmgoto: + callbr void asm sideeffect "B $0", "X"(i8* blockaddress(@asmgoto, %d)) + to label %asm.fallthrough [label %d] + ; The asm goto above produces a direct branch: +; CHECK: //APP +; CHECK-NEXT: {{^[ \t]+b }} +; CHECK-NEXT: //NO_APP + ; For direct branches, no mitigation is needed. +; ISDDSB-NOT: dsb sy +; SB-NOT: {{ sb$}} + +asm.fallthrough: ; preds = %entry + ret i32 0 +; CHECK: {{ret$}} +; ISBDSB-NEXT: dsb sy +; ISBDSB-NEXT: isb +; SB-NEXT: {{ sb$}} + +d: ; preds = %asm.fallthrough, %entry + ret i32 1 +; CHECK: {{ret$}} +; ISBDSB-NEXT: dsb sy +; ISBDSB-NEXT: isb +; SB-NEXT: {{ sb$}} +; CHECK-NEXT: .Lfunc_end +} diff --git a/llvm/test/CodeGen/AArch64/speculation-hardening-sls.mir b/llvm/test/CodeGen/AArch64/speculation-hardening-sls.mir new file mode 100644 index 0000000..600c0f5 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/speculation-hardening-sls.mir @@ -0,0 +1,150 @@ +# RUN: llc -verify-machineinstrs -mtriple=aarch64-none-linux-gnu \ +# RUN: -start-before aarch64-sls-hardening -o - %s \ +# RUN: -mattr=harden-sls-retbr \ +# RUN: | FileCheck %s --check-prefixes=CHECK,ISBDSB +# RUN: llc -verify-machineinstrs -mtriple=aarch64-none-linux-gnu \ +# RUN: -start-before aarch64-sls-hardening -o - %s \ +# RUN: -mattr=harden-sls-retbr -mattr=+sb \ +# RUN: | FileCheck %s --check-prefixes=CHECK,SB + +# Check that the SLS hardening pass also protects BRA* indirect branches that +# llvm currently does not generate. +--- | + @ptr_aa = private unnamed_addr constant [2 x i8*] [i8* blockaddress(@br_aa, %return), i8* blockaddress(@br_aa, %l2)], align 8 + @ptr_aaz = private unnamed_addr constant [2 x i8*] [i8* blockaddress(@br_aaz, %return), i8* blockaddress(@br_aaz, %l2)], align 8 + @ptr_ab = private unnamed_addr constant [2 x i8*] [i8* blockaddress(@br_ab, %return), i8* blockaddress(@br_ab, %l2)], align 8 + @ptr_abz = private unnamed_addr constant [2 x i8*] [i8* blockaddress(@br_abz, %return), i8* blockaddress(@br_abz, %l2)], align 8 + + define dso_local i32 @br_aa(i32 %a, i32 %b, i32 %i) { + entry: + br label %l2 + l2: + br label %return + return: + ret i32 undef + } + define dso_local i32 @br_aaz(i32 %a, i32 %b, i32 %i) { + entry: + br label %l2 + l2: + br label %return + return: + ret i32 undef + } + define dso_local i32 @br_ab(i32 %a, i32 %b, i32 %i) { + entry: + br label %l2 + l2: + br label %return + return: + ret i32 undef + } + define dso_local i32 @br_abz(i32 %a, i32 %b, i32 %i) { + entry: + br label %l2 + l2: + br label %return + return: + ret i32 undef + } +... +--- +name: br_aa +tracksRegLiveness: true +body: | + ; CHECK-LABEL: br_aa: + bb.0.entry: + successors: %bb.2, %bb.1 + liveins: $w2 + $x8 = ADRP target-flags(aarch64-page) @ptr_aa + renamable $x8 = ADDXri $x8, target-flags(aarch64-pageoff, aarch64-nc) @ptr_aa, 0 + renamable $x8 = LDRXroW killed renamable $x8, killed renamable $w2, 1, 1 + BRAA killed renamable $x8, $sp + ; CHECK: braa x8, sp + ; ISBDSB-NEXT: dsb sy + ; ISBDSB-NEXT: isb + ; SB-NEXT: {{ sb$}} + + bb.1.l2 (address-taken): + renamable $w0 = MOVZWi 1, 0 + RET undef $lr, implicit $w0 + + bb.2.return (address-taken): + $w0 = ORRWrs $wzr, $wzr, 0 + RET undef $lr, implicit $w0 +... +--- +name: br_aaz +tracksRegLiveness: true +body: | + ; CHECK-LABEL: br_aaz: + bb.0.entry: + successors: %bb.2, %bb.1 + liveins: $w2 + $x8 = ADRP target-flags(aarch64-page) @ptr_aaz + renamable $x8 = ADDXri $x8, target-flags(aarch64-pageoff, aarch64-nc) @ptr_aaz, 0 + renamable $x8 = LDRXroW killed renamable $x8, killed renamable $w2, 1, 1 + BRAAZ killed renamable $x8 + ; CHECK: braaz x8 + ; ISBDSB-NEXT: dsb sy + ; ISBDSB-NEXT: isb + ; SB-NEXT: {{ sb$}} + + bb.1.l2 (address-taken): + renamable $w0 = MOVZWi 1, 0 + RET undef $lr, implicit $w0 + + bb.2.return (address-taken): + $w0 = ORRWrs $wzr, $wzr, 0 + RET undef $lr, implicit $w0 +... +--- +name: br_ab +tracksRegLiveness: true +body: | + ; CHECK-LABEL: br_ab: + bb.0.entry: + successors: %bb.2, %bb.1 + liveins: $w2 + $x8 = ADRP target-flags(aarch64-page) @ptr_ab + renamable $x8 = ADDXri $x8, target-flags(aarch64-pageoff, aarch64-nc) @ptr_ab, 0 + renamable $x8 = LDRXroW killed renamable $x8, killed renamable $w2, 1, 1 + BRAA killed renamable $x8, $sp + ; CHECK: braa x8, sp + ; ISBDSB-NEXT: dsb sy + ; ISBDSB-NEXT: isb + ; SB-NEXT: {{ sb$}} + + bb.1.l2 (address-taken): + renamable $w0 = MOVZWi 1, 0 + RET undef $lr, implicit $w0 + + bb.2.return (address-taken): + $w0 = ORRWrs $wzr, $wzr, 0 + RET undef $lr, implicit $w0 +... +--- +name: br_abz +tracksRegLiveness: true +body: | + ; CHECK-LABEL: br_abz: + bb.0.entry: + successors: %bb.2, %bb.1 + liveins: $w2 + $x8 = ADRP target-flags(aarch64-page) @ptr_abz + renamable $x8 = ADDXri $x8, target-flags(aarch64-pageoff, aarch64-nc) @ptr_abz, 0 + renamable $x8 = LDRXroW killed renamable $x8, killed renamable $w2, 1, 1 + BRAAZ killed renamable $x8 + ; CHECK: braaz x8 + ; ISBDSB-NEXT: dsb sy + ; ISBDSB-NEXT: isb + ; SB-NEXT: {{ sb$}} + + bb.1.l2 (address-taken): + renamable $w0 = MOVZWi 1, 0 + RET undef $lr, implicit $w0 + + bb.2.return (address-taken): + $w0 = ORRWrs $wzr, $wzr, 0 + RET undef $lr, implicit $w0 +...