From 80698d58e1b3bfa2c5eae11b589436a7b35327c3 Mon Sep 17 00:00:00 2001 From: Anatoly Trosinenko Date: Sat, 6 Jul 2024 13:51:00 +0300 Subject: [PATCH] Revert "[AArch64][PAC] Support BLRA* instructions in SLS Hardening pass (#97605)" This reverts commit 88b26293a24bdd85fce2b2f7191cc0a5bc0cecfe. --- .../Target/AArch64/AArch64SLSHardening.cpp | 377 ++++++------------ .../speculation-hardening-sls-blra.mir | 210 ---------- 2 files changed, 118 insertions(+), 469 deletions(-) delete mode 100644 llvm/test/CodeGen/AArch64/speculation-hardening-sls-blra.mir diff --git a/llvm/lib/Target/AArch64/AArch64SLSHardening.cpp b/llvm/lib/Target/AArch64/AArch64SLSHardening.cpp index 5e83015d72f422..00ba31b3e500dc 100644 --- a/llvm/lib/Target/AArch64/AArch64SLSHardening.cpp +++ b/llvm/lib/Target/AArch64/AArch64SLSHardening.cpp @@ -13,7 +13,6 @@ #include "AArch64InstrInfo.h" #include "AArch64Subtarget.h" -#include "llvm/ADT/StringSwitch.h" #include "llvm/CodeGen/IndirectThunks.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFunction.h" @@ -24,11 +23,8 @@ #include "llvm/IR/DebugLoc.h" #include "llvm/Pass.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/FormatVariadic.h" #include "llvm/Target/TargetMachine.h" #include -#include -#include using namespace llvm; @@ -36,107 +32,17 @@ using namespace llvm; #define AARCH64_SLS_HARDENING_NAME "AArch64 sls hardening pass" -// Common name prefix of all thunks generated by this pass. -// -// The generic form is -// __llvm_slsblr_thunk_xN for BLR thunks -// __llvm_slsblr_thunk_(aaz|abz)_xN for BLRAAZ and BLRABZ thunks -// __llvm_slsblr_thunk_(aa|ab)_xN_xM for BLRAA and BLRAB thunks -static constexpr StringRef CommonNamePrefix = "__llvm_slsblr_thunk_"; +static const char SLSBLRNamePrefix[] = "__llvm_slsblr_thunk_"; namespace { -struct ThunkKind { - enum ThunkKindId { - ThunkBR, - ThunkBRAA, - ThunkBRAB, - ThunkBRAAZ, - ThunkBRABZ, - }; - - ThunkKindId Id; - StringRef NameInfix; - bool HasXmOperand; - bool NeedsPAuth; - - // Opcode to perform indirect jump from inside the thunk. - unsigned BROpcode; - - static const ThunkKind BR; - static const ThunkKind BRAA; - static const ThunkKind BRAB; - static const ThunkKind BRAAZ; - static const ThunkKind BRABZ; -}; - -// Set of inserted thunks. -class ThunksSet { -public: - static constexpr unsigned NumXRegisters = 32; - - // Given Xn register, returns n. - static unsigned indexOfXReg(Register Xn); - // Given n, returns Xn register. - static Register xRegByIndex(unsigned N); - - ThunksSet &operator|=(const ThunksSet &Other) { - BLRThunks |= Other.BLRThunks; - BLRAAZThunks |= Other.BLRAAZThunks; - BLRABZThunks |= Other.BLRABZThunks; - for (unsigned I = 0; I < NumXRegisters; ++I) - BLRAAThunks[I] |= Other.BLRAAThunks[I]; - for (unsigned I = 0; I < NumXRegisters; ++I) - BLRABThunks[I] |= Other.BLRABThunks[I]; - - return *this; - } - - bool get(ThunkKind::ThunkKindId Kind, Register Xn, Register Xm) { - reg_bitmask_t XnBit = reg_bitmask_t(1) << indexOfXReg(Xn); - return getBitmask(Kind, Xm) & XnBit; - } - - void set(ThunkKind::ThunkKindId Kind, Register Xn, Register Xm) { - reg_bitmask_t XnBit = reg_bitmask_t(1) << indexOfXReg(Xn); - getBitmask(Kind, Xm) |= XnBit; - } - -private: - typedef uint32_t reg_bitmask_t; - static_assert(NumXRegisters <= sizeof(reg_bitmask_t) * CHAR_BIT, - "Bitmask is not wide enough to hold all Xn registers"); - - // Bitmasks representing operands used, with n-th bit corresponding to Xn - // register operand. If the instruction has a second operand (Xm), an array - // of bitmasks is used, indexed by m. - // Indexes corresponding to the forbidden x16, x17 and x30 registers are - // always unset, for simplicity there are no holes. - reg_bitmask_t BLRThunks = 0; - reg_bitmask_t BLRAAZThunks = 0; - reg_bitmask_t BLRABZThunks = 0; - reg_bitmask_t BLRAAThunks[NumXRegisters] = {}; - reg_bitmask_t BLRABThunks[NumXRegisters] = {}; - - reg_bitmask_t &getBitmask(ThunkKind::ThunkKindId Kind, Register Xm) { - switch (Kind) { - case ThunkKind::ThunkBR: - return BLRThunks; - case ThunkKind::ThunkBRAAZ: - return BLRAAZThunks; - case ThunkKind::ThunkBRABZ: - return BLRABZThunks; - case ThunkKind::ThunkBRAA: - return BLRAAThunks[indexOfXReg(Xm)]; - case ThunkKind::ThunkBRAB: - return BLRABThunks[indexOfXReg(Xm)]; - } - } -}; +// Set of inserted thunks: bitmask with bits corresponding to +// indexes in SLSBLRThunks array. +typedef uint32_t ThunksSet; struct SLSHardeningInserter : ThunkInserter { public: - const char *getThunkPrefix() { return CommonNamePrefix.data(); } + const char *getThunkPrefix() { return SLSBLRNamePrefix; } bool mayUseThunk(const MachineFunction &MF) { ComdatThunks &= !MF.getSubtarget().hardenSlsNoComdat(); // We are inserting barriers aside from thunk calls, so @@ -162,61 +68,6 @@ struct SLSHardeningInserter : ThunkInserter { } // end anonymous namespace -const ThunkKind ThunkKind::BR = {ThunkBR, "", /*HasXmOperand=*/false, - /*NeedsPAuth=*/false, AArch64::BR}; -const ThunkKind ThunkKind::BRAA = {ThunkBRAA, "aa_", /*HasXmOperand=*/true, - /*NeedsPAuth=*/true, AArch64::BRAA}; -const ThunkKind ThunkKind::BRAB = {ThunkBRAB, "ab_", /*HasXmOperand=*/true, - /*NeedsPAuth=*/true, AArch64::BRAB}; -const ThunkKind ThunkKind::BRAAZ = {ThunkBRAAZ, "aaz_", /*HasXmOperand=*/false, - /*NeedsPAuth=*/true, AArch64::BRAAZ}; -const ThunkKind ThunkKind::BRABZ = {ThunkBRABZ, "abz_", /*HasXmOperand=*/false, - /*NeedsPAuth=*/true, AArch64::BRABZ}; - -// Returns thunk kind to emit, or nullptr if not a BLR* instruction. -static const ThunkKind *getThunkKind(unsigned OriginalOpcode) { - switch (OriginalOpcode) { - case AArch64::BLR: - case AArch64::BLRNoIP: - return &ThunkKind::BR; - case AArch64::BLRAA: - return &ThunkKind::BRAA; - case AArch64::BLRAB: - return &ThunkKind::BRAB; - case AArch64::BLRAAZ: - return &ThunkKind::BRAAZ; - case AArch64::BLRABZ: - return &ThunkKind::BRABZ; - } - return nullptr; -} - -static bool isBLR(const MachineInstr &MI) { - return getThunkKind(MI.getOpcode()) != nullptr; -} - -unsigned ThunksSet::indexOfXReg(Register Reg) { - assert(AArch64::GPR64RegClass.contains(Reg)); - assert(Reg != AArch64::X16 && Reg != AArch64::X17 && Reg != AArch64::LR); - - // Most Xn registers have consecutive ids, except for FP and XZR. - unsigned Result = (unsigned)Reg - (unsigned)AArch64::X0; - if (Reg == AArch64::FP) - Result = 29; - else if (Reg == AArch64::XZR) - Result = 31; - - assert(Result < NumXRegisters && "Internal register numbering changed"); - assert(AArch64::GPR64RegClass.getRegister(Result).id() == Reg && - "Internal register numbering changed"); - - return Result; -} - -Register ThunksSet::xRegByIndex(unsigned N) { - return AArch64::GPR64RegClass.getRegister(N); -} - static void insertSpeculationBarrier(const AArch64Subtarget *ST, MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, @@ -253,6 +104,22 @@ ThunksSet SLSHardeningInserter::insertThunks(MachineModuleInfo &MMI, return ExistingThunks; } +static bool isBLR(const MachineInstr &MI) { + switch (MI.getOpcode()) { + case AArch64::BLR: + case AArch64::BLRNoIP: + return true; + case AArch64::BLRAA: + case AArch64::BLRAB: + case AArch64::BLRAAZ: + case AArch64::BLRABZ: + llvm_unreachable("Currently, LLVM's code generator does not support " + "producing BLRA* instructions. Therefore, there's no " + "support in this pass for those instructions."); + } + return false; +} + bool SLSHardeningInserter::hardenReturnsAndBRs(MachineModuleInfo &MMI, MachineBasicBlock &MBB) { const AArch64Subtarget *ST = @@ -272,64 +139,64 @@ bool SLSHardeningInserter::hardenReturnsAndBRs(MachineModuleInfo &MMI, return Modified; } -// Currently, the longest possible thunk name is -// __llvm_slsblr_thunk_aa_xNN_xMM -// which is 31 characters (without the '\0' character). -static SmallString<32> createThunkName(const ThunkKind &Kind, Register Xn, - Register Xm) { - unsigned N = ThunksSet::indexOfXReg(Xn); - if (!Kind.HasXmOperand) - return formatv("{0}{1}x{2}", CommonNamePrefix, Kind.NameInfix, N); - - unsigned M = ThunksSet::indexOfXReg(Xm); - return formatv("{0}{1}x{2}_x{3}", CommonNamePrefix, Kind.NameInfix, N, M); -} +static const unsigned NumPermittedRegs = 29; +static const struct ThunkNameAndReg { + const char* Name; + Register Reg; +} SLSBLRThunks[NumPermittedRegs] = { + {"__llvm_slsblr_thunk_x0", AArch64::X0}, + {"__llvm_slsblr_thunk_x1", AArch64::X1}, + {"__llvm_slsblr_thunk_x2", AArch64::X2}, + {"__llvm_slsblr_thunk_x3", AArch64::X3}, + {"__llvm_slsblr_thunk_x4", AArch64::X4}, + {"__llvm_slsblr_thunk_x5", AArch64::X5}, + {"__llvm_slsblr_thunk_x6", AArch64::X6}, + {"__llvm_slsblr_thunk_x7", AArch64::X7}, + {"__llvm_slsblr_thunk_x8", AArch64::X8}, + {"__llvm_slsblr_thunk_x9", AArch64::X9}, + {"__llvm_slsblr_thunk_x10", AArch64::X10}, + {"__llvm_slsblr_thunk_x11", AArch64::X11}, + {"__llvm_slsblr_thunk_x12", AArch64::X12}, + {"__llvm_slsblr_thunk_x13", AArch64::X13}, + {"__llvm_slsblr_thunk_x14", AArch64::X14}, + {"__llvm_slsblr_thunk_x15", AArch64::X15}, + // X16 and X17 are deliberately missing, as the mitigation requires those + // register to not be used in BLR. See comment in ConvertBLRToBL for more + // details. + {"__llvm_slsblr_thunk_x18", AArch64::X18}, + {"__llvm_slsblr_thunk_x19", AArch64::X19}, + {"__llvm_slsblr_thunk_x20", AArch64::X20}, + {"__llvm_slsblr_thunk_x21", AArch64::X21}, + {"__llvm_slsblr_thunk_x22", AArch64::X22}, + {"__llvm_slsblr_thunk_x23", AArch64::X23}, + {"__llvm_slsblr_thunk_x24", AArch64::X24}, + {"__llvm_slsblr_thunk_x25", AArch64::X25}, + {"__llvm_slsblr_thunk_x26", AArch64::X26}, + {"__llvm_slsblr_thunk_x27", AArch64::X27}, + {"__llvm_slsblr_thunk_x28", AArch64::X28}, + {"__llvm_slsblr_thunk_x29", AArch64::FP}, + // X30 is deliberately missing, for similar reasons as X16 and X17 are + // missing. + {"__llvm_slsblr_thunk_x31", AArch64::XZR}, +}; -static std::tuple -parseThunkName(StringRef ThunkName) { - assert(ThunkName.starts_with(CommonNamePrefix) && - "Should be filtered out by ThunkInserter"); - // Thunk name suffix, such as "x1" or "aa_x2_x3". - StringRef NameSuffix = ThunkName.drop_front(CommonNamePrefix.size()); - - // Parse thunk kind based on thunk name infix. - const ThunkKind &Kind = *StringSwitch(NameSuffix) - .StartsWith("aa_", &ThunkKind::BRAA) - .StartsWith("ab_", &ThunkKind::BRAB) - .StartsWith("aaz_", &ThunkKind::BRAAZ) - .StartsWith("abz_", &ThunkKind::BRABZ) - .Default(&ThunkKind::BR); - - auto ParseRegName = [](StringRef Name) { - unsigned N; - - assert(Name.starts_with("x") && "xN register name expected"); - bool Fail = Name.drop_front(1).getAsInteger(/*Radix=*/10, N); - assert(!Fail && N < ThunksSet::NumXRegisters && "Unexpected register"); - (void)Fail; - - return ThunksSet::xRegByIndex(N); - }; - - // For example, "x1" or "x2_x3". - StringRef RegsStr = NameSuffix.drop_front(Kind.NameInfix.size()); - StringRef XnStr, XmStr; - std::tie(XnStr, XmStr) = RegsStr.split('_'); - - // Parse register operands. - Register Xn = ParseRegName(XnStr); - Register Xm = Kind.HasXmOperand ? ParseRegName(XmStr) : AArch64::NoRegister; - - return std::make_tuple(std::ref(Kind), Xn, Xm); +unsigned getThunkIndex(Register Reg) { + for (unsigned I = 0; I < NumPermittedRegs; ++I) + if (SLSBLRThunks[I].Reg == Reg) + return I; + llvm_unreachable("Unexpected register"); } void SLSHardeningInserter::populateThunk(MachineFunction &MF) { assert(MF.getFunction().hasComdat() == ComdatThunks && "ComdatThunks value changed since MF creation"); - Register Xn, Xm; - auto KindAndRegs = parseThunkName(MF.getName()); - const ThunkKind &Kind = std::get<0>(KindAndRegs); - std::tie(std::ignore, Xn, Xm) = KindAndRegs; + // FIXME: How to better communicate Register number, rather than through + // name and lookup table? + assert(MF.getName().starts_with(getThunkPrefix())); + auto ThunkIt = llvm::find_if( + SLSBLRThunks, [&MF](auto T) { return T.Name == MF.getName(); }); + assert(ThunkIt != std::end(SLSBLRThunks)); + Register ThunkReg = ThunkIt->Reg; const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); @@ -351,26 +218,16 @@ void SLSHardeningInserter::populateThunk(MachineFunction &MF) { Entry->clear(); // These thunks need to consist of the following instructions: - // __llvm_slsblr_thunk_...: - // MOV x16, xN ; BR* instructions are not compatible with "BTI c" - // ; branch target unless xN is x16 or x17. - // BR* ... ; One of: BR x16 - // ; BRA(A|B) x16, xM - // ; BRA(A|B)Z x16 + // __llvm_slsblr_thunk_xN: + // BR xN // barrierInsts - Entry->addLiveIn(Xn); - // MOV X16, Reg == ORR X16, XZR, Reg, LSL #0 + Entry->addLiveIn(ThunkReg); + // MOV X16, ThunkReg == ORR X16, XZR, ThunkReg, LSL #0 BuildMI(Entry, DebugLoc(), TII->get(AArch64::ORRXrs), AArch64::X16) .addReg(AArch64::XZR) - .addReg(Xn) + .addReg(ThunkReg) .addImm(0); - auto &Builder = - BuildMI(Entry, DebugLoc(), TII->get(Kind.BROpcode)).addReg(AArch64::X16); - if (Xm != AArch64::NoRegister) { - Entry->addLiveIn(Xm); - Builder.addReg(Xm); - } - + BuildMI(Entry, DebugLoc(), TII->get(AArch64::BR)).addReg(AArch64::X16); // Make sure the thunks do not make use of the SB extension in case there is // a function somewhere that will call to it that for some reason disabled // the SB extension locally on that function, even though it's enabled for @@ -382,14 +239,12 @@ void SLSHardeningInserter::populateThunk(MachineFunction &MF) { void SLSHardeningInserter::convertBLRToBL( MachineModuleInfo &MMI, MachineBasicBlock &MBB, MachineBasicBlock::instr_iterator MBBI, ThunksSet &Thunks) { - // Transform a BLR* instruction (one of BLR, BLRAA/BLRAB or BLRAAZ/BLRABZ) to - // a BL to the thunk containing BR, BRAA/BRAB or BRAAZ/BRABZ, respectively. - // + // Transform a BLR to a BL as follows: // Before: // |-----------------------------| // | ... | // | instI | - // | BLR* xN or BLR* xN, xM | + // | BLR xN | // | instJ | // | ... | // |-----------------------------| @@ -398,53 +253,61 @@ void SLSHardeningInserter::convertBLRToBL( // |-----------------------------| // | ... | // | instI | - // | BL __llvm_slsblr_thunk_... | + // | BL __llvm_slsblr_thunk_xN | // | instJ | // | ... | // |-----------------------------| // - // __llvm_slsblr_thunk_...: + // __llvm_slsblr_thunk_xN: // |-----------------------------| - // | MOV x16, xN | - // | BR* x16 or BR* x16, xM | + // | BR xN | // | barrierInsts | // |-----------------------------| // - // This function needs to transform BLR* instruction into BL with the correct - // thunk name and lazily create the thunk if it does not exist yet. + // This function merely needs to transform BLR xN into BL + // __llvm_slsblr_thunk_xN. // // Since linkers are allowed to clobber X16 and X17 on function calls, the - // above mitigation only works if the original BLR* instruction had neither - // X16 nor X17 as one of its operands. Code generation before must make sure - // that no such BLR* instruction was produced if the mitigation is enabled. + // above mitigation only works if the original BLR instruction was not + // BLR X16 nor BLR X17. Code generation before must make sure that no BLR + // X16|X17 was produced if the mitigation is enabled. MachineInstr &BLR = *MBBI; assert(isBLR(BLR)); - const ThunkKind &Kind = *getThunkKind(BLR.getOpcode()); - - unsigned NumRegOperands = Kind.HasXmOperand ? 2 : 1; - assert(BLR.getNumExplicitOperands() == NumRegOperands && - "Expected one or two register inputs"); - Register Xn = BLR.getOperand(0).getReg(); - Register Xm = - Kind.HasXmOperand ? BLR.getOperand(1).getReg() : AArch64::NoRegister; - + unsigned BLOpcode; + Register Reg; + bool RegIsKilled; + switch (BLR.getOpcode()) { + case AArch64::BLR: + case AArch64::BLRNoIP: + BLOpcode = AArch64::BL; + Reg = BLR.getOperand(0).getReg(); + assert(Reg != AArch64::X16 && Reg != AArch64::X17 && Reg != AArch64::LR); + RegIsKilled = BLR.getOperand(0).isKill(); + break; + case AArch64::BLRAA: + case AArch64::BLRAB: + case AArch64::BLRAAZ: + case AArch64::BLRABZ: + llvm_unreachable("BLRA instructions cannot yet be produced by LLVM, " + "therefore there is no need to support them for now."); + default: + llvm_unreachable("unhandled BLR"); + } DebugLoc DL = BLR.getDebugLoc(); MachineFunction &MF = *MBBI->getMF(); MCContext &Context = MBB.getParent()->getContext(); const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); - - auto ThunkName = createThunkName(Kind, Xn, Xm); + unsigned ThunkIndex = getThunkIndex(Reg); + StringRef ThunkName = SLSBLRThunks[ThunkIndex].Name; MCSymbol *Sym = Context.getOrCreateSymbol(ThunkName); - - if (!Thunks.get(Kind.Id, Xn, Xm)) { - StringRef TargetAttrs = Kind.NeedsPAuth ? "+pauth" : ""; - Thunks.set(Kind.Id, Xn, Xm); - createThunkFunction(MMI, ThunkName, ComdatThunks, TargetAttrs); + if (!(Thunks & (1u << ThunkIndex))) { + Thunks |= 1u << ThunkIndex; + createThunkFunction(MMI, ThunkName, ComdatThunks); } - MachineInstr *BL = BuildMI(MBB, MBBI, DL, TII->get(AArch64::BL)).addSym(Sym); + MachineInstr *BL = BuildMI(MBB, MBBI, DL, TII->get(BLOpcode)).addSym(Sym); // Now copy the implicit operands from BLR to BL and copy other necessary // info. @@ -475,13 +338,9 @@ void SLSHardeningInserter::convertBLRToBL( // Now copy over the implicit operands from the original BLR BL->copyImplicitOps(MF, BLR); MF.moveCallSiteInfo(&BLR, BL); - // Also add the register operands of the original BLR* instruction - // as being used in the called thunk. - for (unsigned OpIdx = 0; OpIdx < NumRegOperands; ++OpIdx) { - MachineOperand &Op = BLR.getOperand(OpIdx); - BL->addOperand(MachineOperand::CreateReg(Op.getReg(), /*isDef=*/false, - /*isImp=*/true, Op.isKill())); - } + // Also add the register called in the BLR as being used in the called thunk. + BL->addOperand(MachineOperand::CreateReg(Reg, false /*isDef*/, true /*isImp*/, + RegIsKilled /*isKill*/)); // Remove BLR instruction MBB.erase(MBBI); } diff --git a/llvm/test/CodeGen/AArch64/speculation-hardening-sls-blra.mir b/llvm/test/CodeGen/AArch64/speculation-hardening-sls-blra.mir deleted file mode 100644 index 06669a6d6aae25..00000000000000 --- a/llvm/test/CodeGen/AArch64/speculation-hardening-sls-blra.mir +++ /dev/null @@ -1,210 +0,0 @@ -# RUN: llc -verify-machineinstrs -mtriple=aarch64-none-linux-gnu \ -# RUN: -start-before aarch64-sls-hardening -o - %s \ -# RUN: -asm-verbose=0 \ -# RUN: | FileCheck %s \ -# RUN: --implicit-check-not=__llvm_slsblr_thunk_aa_x5_x8 \ -# RUN: --implicit-check-not=__llvm_slsblr_thunk_ab_x5_x8 \ -# RUN: --implicit-check-not=__llvm_slsblr_thunk_aaz_x5 \ -# RUN: --implicit-check-not=__llvm_slsblr_thunk_abz_x5 - -# Pointer Authentication extension introduces more branch-with-link-to-register -# instructions for the BLR SLS hardening to handle, namely BLRAA, BLRAB, BLRAAZ -# and BLRABZ. Unlike the non-authenticating BLR instruction, BLRAA and BLRAB -# accept two register operands (almost 900 combinations for each instruction). -# For that reason, it is not practical to create all possible thunks. - -# Check that the BLR SLS hardening transforms BLRA* instructions into -# unconditional BL calls to the correct thunk functions. -# Check that only relevant thunk functions are generated. ---- | - define void @test_instructions() #0 { - entry: - ret void - } - - define void @test_no_redef() #0 { - entry: - ret void - } - - define void @test_regs() #0 { - entry: - ret void - } - - attributes #0 = { "target-features"="+pauth,+harden-sls-blr" } -... - -# Test that all BLRA* instructions are handled. ---- -name: test_instructions -tracksRegLiveness: true -body: | - bb.0.entry: - liveins: $lr, $x0, $x1, $x2, $x3 - - BLRAA $x0, $x1, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 - BLRAB $x1, $x2, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 - BLRAAZ $x2, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 - BLRABZ $x3, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 - RET undef $lr -... - -# Test that the same thunk function is not created twice. ---- -name: test_no_redef -tracksRegLiveness: true -body: | - bb.0.entry: - liveins: $lr, $x0, $x1, $x2, $x3, $x4 - - ; thunk used by @test_instructions - BLRAB $x1, $x2, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 - - ; thunk used by this function twice - BLRAB $x3, $x4, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 - BLRAB $x3, $x4, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 - - RET undef $lr -... - -# Test that all xN registers (except x16, x17, x30 and xzr) are handled. ---- -name: test_regs -tracksRegLiveness: true -body: | - bb.0.entry: - liveins: $lr, $x0, $x1, $x2, $x3, $x4, $x5, $x6, $x7, $x8, $x9, $x10, $x11, $x12, $x13, $x14, $x15, $x16, $x17, $x18, $x19, $x20, $x21, $x22, $x23, $x24, $x25, $x26, $x27, $x28, $fp - - BLRAA $x0, $x1, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 - BLRAA $x2, $x3, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 - BLRAA $x4, $x5, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 - BLRAA $x6, $x7, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 - BLRAA $x8, $x9, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 - BLRAA $x10, $x11, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 - BLRAA $x12, $x13, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 - BLRAA $x14, $x15, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 - ; skipping x16 and x17 - BLRAA $x18, $x19, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 - BLRAA $x20, $x21, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 - BLRAA $x22, $x23, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 - BLRAA $x24, $x25, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 - BLRAA $x26, $x27, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 - BLRAA $x28, $fp, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $w0 - RET undef $lr -... - -# CHECK-LABEL: test_instructions: -# CHECK-NEXT: .cfi_startproc -# CHECK-NEXT: bl __llvm_slsblr_thunk_aa_x0_x1 -# CHECK-NEXT: bl __llvm_slsblr_thunk_ab_x1_x2 -# CHECK-NEXT: bl __llvm_slsblr_thunk_aaz_x2 -# CHECK-NEXT: bl __llvm_slsblr_thunk_abz_x3 -# CHECK-NEXT: ret - -# CHECK-LABEL: test_no_redef: -# CHECK-NEXT: .cfi_startproc -# CHECK-NEXT: bl __llvm_slsblr_thunk_ab_x1_x2 -# CHECK-NEXT: bl __llvm_slsblr_thunk_ab_x3_x4 -# CHECK-NEXT: bl __llvm_slsblr_thunk_ab_x3_x4 -# CHECK-NEXT: ret - -# CHECK-LABEL: test_regs: -# CHECK-NEXT: .cfi_startproc -# CHECK-NEXT: bl __llvm_slsblr_thunk_aa_x0_x1 -# CHECK-NEXT: bl __llvm_slsblr_thunk_aa_x2_x3 -# CHECK-NEXT: bl __llvm_slsblr_thunk_aa_x4_x5 -# CHECK-NEXT: bl __llvm_slsblr_thunk_aa_x6_x7 -# CHECK-NEXT: bl __llvm_slsblr_thunk_aa_x8_x9 -# CHECK-NEXT: bl __llvm_slsblr_thunk_aa_x10_x11 -# CHECK-NEXT: bl __llvm_slsblr_thunk_aa_x12_x13 -# CHECK-NEXT: bl __llvm_slsblr_thunk_aa_x14_x15 -# skipping x16 and x17 -# CHECK-NEXT: bl __llvm_slsblr_thunk_aa_x18_x19 -# CHECK-NEXT: bl __llvm_slsblr_thunk_aa_x20_x21 -# CHECK-NEXT: bl __llvm_slsblr_thunk_aa_x22_x23 -# CHECK-NEXT: bl __llvm_slsblr_thunk_aa_x24_x25 -# CHECK-NEXT: bl __llvm_slsblr_thunk_aa_x26_x27 -# CHECK-NEXT: bl __llvm_slsblr_thunk_aa_x28_x29 -# CHECK-NEXT: ret - -# CHECK-LABEL: __llvm_slsblr_thunk_aa_x0_x1: -# CHECK-NEXT: mov x16, x0 -# CHECK-NEXT: braa x16, x1 -# CHECK-NEXT: dsb sy -# CHECK-NEXT: isb - -# CHECK-LABEL: __llvm_slsblr_thunk_ab_x1_x2: -# CHECK-NEXT: mov x16, x1 -# CHECK-NEXT: brab x16, x2 -# CHECK-NEXT: dsb sy -# CHECK-NEXT: isb - -# CHECK-LABEL: __llvm_slsblr_thunk_aaz_x2: -# CHECK-NEXT: mov x16, x2 -# CHECK-NEXT: braaz x16 -# CHECK-NEXT: dsb sy -# CHECK-NEXT: isb - -# CHECK-LABEL: __llvm_slsblr_thunk_abz_x3: -# CHECK-NEXT: mov x16, x3 -# CHECK-NEXT: brabz x16 -# CHECK-NEXT: dsb sy -# CHECK-NEXT: isb - -# The instruction *operands* should correspond to the thunk function *name* -# (check that the name is parsed correctly when populating the thunk). - -# CHECK-LABEL: __llvm_slsblr_thunk_aa_x2_x3: -# CHECK-NEXT: mov x16, x2 -# CHECK: braa x16, x3 - -# CHECK-LABEL: __llvm_slsblr_thunk_aa_x4_x5: -# CHECK-NEXT: mov x16, x4 -# CHECK: braa x16, x5 - -# CHECK-LABEL: __llvm_slsblr_thunk_aa_x6_x7: -# CHECK-NEXT: mov x16, x6 -# CHECK: braa x16, x7 - -# CHECK-LABEL: __llvm_slsblr_thunk_aa_x8_x9: -# CHECK-NEXT: mov x16, x8 -# CHECK: braa x16, x9 - -# CHECK-LABEL: __llvm_slsblr_thunk_aa_x10_x11: -# CHECK-NEXT: mov x16, x10 -# CHECK: braa x16, x11 - -# CHECK-LABEL: __llvm_slsblr_thunk_aa_x12_x13: -# CHECK-NEXT: mov x16, x12 -# CHECK: braa x16, x13 - -# CHECK-LABEL: __llvm_slsblr_thunk_aa_x14_x15: -# CHECK-NEXT: mov x16, x14 -# CHECK: braa x16, x15 - -# skipping x16 and x17 - -# CHECK-LABEL: __llvm_slsblr_thunk_aa_x18_x19: -# CHECK-NEXT: mov x16, x18 -# CHECK: braa x16, x19 - -# CHECK-LABEL: __llvm_slsblr_thunk_aa_x20_x21: -# CHECK-NEXT: mov x16, x20 -# CHECK: braa x16, x21 - -# CHECK-LABEL: __llvm_slsblr_thunk_aa_x22_x23: -# CHECK-NEXT: mov x16, x22 -# CHECK: braa x16, x23 - -# CHECK-LABEL: __llvm_slsblr_thunk_aa_x24_x25: -# CHECK-NEXT: mov x16, x24 -# CHECK: braa x16, x25 - -# CHECK-LABEL: __llvm_slsblr_thunk_aa_x26_x27: -# CHECK-NEXT: mov x16, x26 -# CHECK: braa x16, x27 - -# CHECK-LABEL: __llvm_slsblr_thunk_aa_x28_x29: -# CHECK-NEXT: mov x16, x28 -# CHECK: braa x16, x29