https://github.com/atrosinenko updated https://github.com/llvm/llvm-project/pull/146488
>From ba9d8965de86e63cce18fc9c2d0fe9484f172e1f Mon Sep 17 00:00:00 2001 From: Anatoly Trosinenko <atrosine...@accesssoftek.com> Date: Sat, 28 Jun 2025 10:50:46 +0300 Subject: [PATCH] [AArch64][PAC] Introduce AArch64::PAC pseudo instruction Introduce a pseudo instruction to be selected instead of a pair of `MOVKXi` and `PAC[DI][AB]` carrying address and immediate modifiers as separate operands. The new pseudo instruction is expanded in AsmPrinter, so that MOVKXi is emitted immediately before `PAC[DI][AB]`. This way, an attacker cannot control the immediate modifier used to sign the value, even if address modifier can be substituted. To simplify the instruction selection, select AArch64::PAC pseudo using TableGen pattern and post-process its $AddrDisc operand by custom inserter hook - this eliminates duplication of the logic for DAGISel and GlobalISel. Furthermore, this improves cross-BB analysis in case of DAGISel. --- llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 32 +++ .../Target/AArch64/AArch64ISelLowering.cpp | 74 +++++++ llvm/lib/Target/AArch64/AArch64ISelLowering.h | 7 + llvm/lib/Target/AArch64/AArch64InstrInfo.td | 21 +- llvm/test/CodeGen/AArch64/ptrauth-isel.ll | 205 ++++++++++++++++++ 5 files changed, 338 insertions(+), 1 deletion(-) create mode 100644 llvm/test/CodeGen/AArch64/ptrauth-isel.ll diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp index dd10050592190..f34217a3a8133 100644 --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -171,6 +171,9 @@ class AArch64AsmPrinter : public AsmPrinter { // Emit the sequence for AUT or AUTPAC. void emitPtrauthAuthResign(const MachineInstr *MI); + // Emit the sequence for PAC. + void emitPtrauthSign(const MachineInstr *MI); + // Emit the sequence to compute the discriminator. // // ScratchReg should be x16/x17. @@ -2173,6 +2176,31 @@ void AArch64AsmPrinter::emitPtrauthAuthResign(const MachineInstr *MI) { OutStreamer->emitLabel(EndSym); } +void AArch64AsmPrinter::emitPtrauthSign(const MachineInstr *MI) { + Register Val = MI->getOperand(1).getReg(); + auto Key = (AArch64PACKey::ID)MI->getOperand(2).getImm(); + uint64_t Disc = MI->getOperand(3).getImm(); + Register AddrDisc = MI->getOperand(4).getReg(); + bool AddrDiscKilled = MI->getOperand(4).isKill(); + + // Compute aut discriminator into x17 + assert(isUInt<16>(Disc)); + Register DiscReg = emitPtrauthDiscriminator( + Disc, AddrDisc, AArch64::X17, /*MayUseAddrAsScratch=*/AddrDiscKilled); + bool IsZeroDisc = DiscReg == AArch64::XZR; + unsigned Opc = getPACOpcodeForKey(Key, IsZeroDisc); + + // paciza x16 ; if IsZeroDisc + // pacia x16, x17 ; if !IsZeroDisc + MCInst PACInst; + PACInst.setOpcode(Opc); + PACInst.addOperand(MCOperand::createReg(Val)); + PACInst.addOperand(MCOperand::createReg(Val)); + if (!IsZeroDisc) + PACInst.addOperand(MCOperand::createReg(DiscReg)); + EmitToStreamer(*OutStreamer, PACInst); +} + void AArch64AsmPrinter::emitPtrauthBranch(const MachineInstr *MI) { bool IsCall = MI->getOpcode() == AArch64::BLRA; unsigned BrTarget = MI->getOperand(0).getReg(); @@ -2867,6 +2895,10 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) { emitPtrauthAuthResign(MI); return; + case AArch64::PAC: + emitPtrauthSign(MI); + return; + case AArch64::LOADauthptrstatic: LowerLOADauthptrstatic(*MI); return; diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp index fb8bd81c033af..c8eb9f3dd01ad 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -3073,6 +3073,75 @@ AArch64TargetLowering::EmitGetSMESaveSize(MachineInstr &MI, return BB; } +// Helper function to find the instruction that defined a virtual register. +// If unable to find such instruction, returns nullptr. +static MachineInstr *stripVRegCopies(const MachineRegisterInfo &MRI, + Register Reg) { + while (Reg.isVirtual()) { + MachineInstr *DefMI = MRI.getVRegDef(Reg); + assert(DefMI && "Virtual register definition not found"); + unsigned Opcode = DefMI->getOpcode(); + + if (Opcode == AArch64::COPY) { + Reg = DefMI->getOperand(1).getReg(); + // Vreg is defined by copying from physreg. + if (Reg.isPhysical()) + return DefMI; + continue; + } + if (Opcode == AArch64::SUBREG_TO_REG) { + Reg = DefMI->getOperand(2).getReg(); + continue; + } + + return DefMI; + } + return nullptr; +} + +void AArch64TargetLowering::fixupBlendComponents( + MachineInstr &MI, MachineBasicBlock *BB, MachineOperand &IntDiscOp, + MachineOperand &AddrDiscOp, const TargetRegisterClass *AddrDiscRC) const { + const TargetInstrInfo *TII = Subtarget->getInstrInfo(); + MachineRegisterInfo &MRI = MI.getMF()->getRegInfo(); + const DebugLoc &DL = MI.getDebugLoc(); + + Register AddrDisc = AddrDiscOp.getReg(); + int64_t IntDisc = IntDiscOp.getImm(); + + assert(IntDisc == 0 && "Blend components are already expanded"); + + MachineInstr *MaybeBlend = stripVRegCopies(MRI, AddrDisc); + + if (MaybeBlend) { + // Detect blend(addr, imm) which is lowered as "MOVK addr, #imm, #48". + // Alternatively, recognize small immediate modifier passed via VReg. + if (MaybeBlend->getOpcode() == AArch64::MOVKXi && + MaybeBlend->getOperand(3).getImm() == 48) { + AddrDisc = MaybeBlend->getOperand(1).getReg(); + IntDisc = MaybeBlend->getOperand(2).getImm(); + } else if (MaybeBlend->getOpcode() == AArch64::MOVi32imm && + isUInt<16>(MaybeBlend->getOperand(1).getImm())) { + AddrDisc = AArch64::XZR; + IntDisc = MaybeBlend->getOperand(1).getImm(); + } + } + + // Normalize NoRegister operands emitted by GlobalISel. + if (AddrDisc == AArch64::NoRegister) + AddrDisc = AArch64::XZR; + + // Make sure AddrDisc operand respects the register class imposed by MI. + if (AddrDisc != AArch64::XZR && MRI.getRegClass(AddrDisc) != AddrDiscRC) { + Register TmpReg = MRI.createVirtualRegister(AddrDiscRC); + BuildMI(*BB, MI, DL, TII->get(AArch64::COPY), TmpReg).addReg(AddrDisc); + AddrDisc = TmpReg; + } + + AddrDiscOp.setReg(AddrDisc); + IntDiscOp.setImm(IntDisc); +} + MachineBasicBlock *AArch64TargetLowering::EmitInstrWithCustomInserter( MachineInstr &MI, MachineBasicBlock *BB) const { @@ -3171,6 +3240,11 @@ MachineBasicBlock *AArch64TargetLowering::EmitInstrWithCustomInserter( return EmitZTInstr(MI, BB, AArch64::ZERO_T, /*Op0IsDef=*/true); case AArch64::MOVT_TIZ_PSEUDO: return EmitZTInstr(MI, BB, AArch64::MOVT_TIZ, /*Op0IsDef=*/true); + + case AArch64::PAC: + fixupBlendComponents(MI, BB, MI.getOperand(3), MI.getOperand(4), + &AArch64::GPR64noipRegClass); + return BB; } } diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.h b/llvm/lib/Target/AArch64/AArch64ISelLowering.h index 89f90ee2b7707..3f71daa4daa91 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.h +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.h @@ -182,6 +182,13 @@ class AArch64TargetLowering : public TargetLowering { MachineBasicBlock *EmitGetSMESaveSize(MachineInstr &MI, MachineBasicBlock *BB) const; + /// Replace (0, vreg) discriminator components with the operands of blend + /// or with (immediate, XZR) when possible. + void fixupBlendComponents(MachineInstr &MI, MachineBasicBlock *BB, + MachineOperand &IntDiscOp, + MachineOperand &AddrDiscOp, + const TargetRegisterClass *AddrDiscRC) const; + MachineBasicBlock * EmitInstrWithCustomInserter(MachineInstr &MI, MachineBasicBlock *MBB) const override; diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td index f01b634f44ba6..c509b431927c1 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -2030,7 +2030,7 @@ let Predicates = [HasPAuth] in { def DZB : SignAuthZero<prefix_z, 0b11, !strconcat(asm, "dzb"), op>; } - defm PAC : SignAuth<0b000, 0b010, "pac", int_ptrauth_sign>; + defm PAC : SignAuth<0b000, 0b010, "pac", null_frag>; defm AUT : SignAuth<0b001, 0b011, "aut", null_frag>; def XPACI : ClearAuth<0, "xpaci">; @@ -2136,6 +2136,25 @@ let Predicates = [HasPAuth] in { let Uses = [X16]; } + // PAC pseudo instruction. Is AsmPrinter, it is expanded into an actual PAC* + // instruction immediately preceded by the discriminator computation. + // This enforces the expected immediate modifier is used for signing, even + // if an attacker is able to substitute AddrDisc. + def PAC : Pseudo<(outs GPR64:$SignedVal), + (ins GPR64:$Val, i32imm:$Key, i64imm:$Disc, GPR64noip:$AddrDisc), + [], "$SignedVal = $Val">, Sched<[WriteI, ReadI]> { + let isCodeGenOnly = 1; + let hasSideEffects = 0; + let mayStore = 0; + let mayLoad = 0; + let Size = 12; + let Defs = [X17]; + let usesCustomInserter = 1; + } + + def : Pat<(int_ptrauth_sign GPR64:$Val, timm:$Key, GPR64noip:$AddrDisc), + (PAC GPR64:$Val, $Key, 0, GPR64noip:$AddrDisc)>; + // AUT and re-PAC a value, using different keys/data. // This directly manipulates x16/x17, which are the only registers the OS // guarantees are safe to use for sensitive operations. diff --git a/llvm/test/CodeGen/AArch64/ptrauth-isel.ll b/llvm/test/CodeGen/AArch64/ptrauth-isel.ll new file mode 100644 index 0000000000000..89ce439f5b47b --- /dev/null +++ b/llvm/test/CodeGen/AArch64/ptrauth-isel.ll @@ -0,0 +1,205 @@ +; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5 +; RUN: llc < %s -mtriple arm64e-apple-darwin -verify-machineinstrs -stop-after=finalize-isel -global-isel=0 \ +; RUN: | FileCheck %s --check-prefixes=DAGISEL +; RUN: llc < %s -mtriple arm64e-apple-darwin -verify-machineinstrs -stop-after=finalize-isel -global-isel=1 -global-isel-abort=1 \ +; RUN: | FileCheck %s --check-prefixes=GISEL +; RUN: llc < %s -mtriple aarch64-linux-gnu -mattr=+pauth -verify-machineinstrs -stop-after=finalize-isel -global-isel=0 \ +; RUN: | FileCheck %s --check-prefixes=DAGISEL +; RUN: llc < %s -mtriple aarch64-linux-gnu -mattr=+pauth -verify-machineinstrs -stop-after=finalize-isel -global-isel=1 -global-isel-abort=1 \ +; RUN: | FileCheck %s --check-prefixes=GISEL + +; Check MIR produced by the instruction selector to validate properties that +; cannot be reliably tested by only inspecting the final asm output. + +@discvar = dso_local global i64 0 + +; Make sure the components of blend(addr, imm) are recognized and passed to +; PAC pseudo via separate operands to prevent substitution of the immediate +; modifier. +; +; MIR output of the instruction selector is inspected, as it is hard to reliably +; distinguish MOVKXi immediately followed by a pseudo from a standalone pseudo +; instruction carrying address and immediate modifiers in its separate operands +; by only observing the final asm output. + +define i64 @small_imm_disc(i64 %addr) { + ; DAGISEL-LABEL: name: small_imm_disc + ; DAGISEL: bb.0.entry: + ; DAGISEL-NEXT: liveins: $x0 + ; DAGISEL-NEXT: {{ $}} + ; DAGISEL-NEXT: [[COPY:%[0-9]+]]:gpr64 = COPY $x0 + ; DAGISEL-NEXT: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 42 + ; DAGISEL-NEXT: [[SUBREG_TO_REG:%[0-9]+]]:gpr64noip = SUBREG_TO_REG 0, killed [[MOVi32imm]], %subreg.sub_32 + ; DAGISEL-NEXT: [[PAC:%[0-9]+]]:gpr64 = PAC [[COPY]], 2, 42, killed $xzr, implicit-def dead $x17 + ; DAGISEL-NEXT: $x0 = COPY [[PAC]] + ; DAGISEL-NEXT: RET_ReallyLR implicit $x0 + ; + ; GISEL-LABEL: name: small_imm_disc + ; GISEL: bb.1.entry: + ; GISEL-NEXT: liveins: $x0 + ; GISEL-NEXT: {{ $}} + ; GISEL-NEXT: [[COPY:%[0-9]+]]:gpr64 = COPY $x0 + ; GISEL-NEXT: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 42 + ; GISEL-NEXT: [[SUBREG_TO_REG:%[0-9]+]]:gpr64noip = SUBREG_TO_REG 0, [[MOVi32imm]], %subreg.sub_32 + ; GISEL-NEXT: [[PAC:%[0-9]+]]:gpr64 = PAC [[COPY]], 2, 42, $xzr, implicit-def dead $x17 + ; GISEL-NEXT: $x0 = COPY [[PAC]] + ; GISEL-NEXT: RET_ReallyLR implicit $x0 +entry: + %signed = call i64 @llvm.ptrauth.sign(i64 %addr, i32 2, i64 42) + ret i64 %signed +} + +define i64 @large_imm_disc_wreg(i64 %addr) { + ; DAGISEL-LABEL: name: large_imm_disc_wreg + ; DAGISEL: bb.0.entry: + ; DAGISEL-NEXT: liveins: $x0 + ; DAGISEL-NEXT: {{ $}} + ; DAGISEL-NEXT: [[COPY:%[0-9]+]]:gpr64 = COPY $x0 + ; DAGISEL-NEXT: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 12345678 + ; DAGISEL-NEXT: [[SUBREG_TO_REG:%[0-9]+]]:gpr64noip = SUBREG_TO_REG 0, killed [[MOVi32imm]], %subreg.sub_32 + ; DAGISEL-NEXT: [[PAC:%[0-9]+]]:gpr64 = PAC [[COPY]], 2, 0, killed [[SUBREG_TO_REG]], implicit-def dead $x17 + ; DAGISEL-NEXT: $x0 = COPY [[PAC]] + ; DAGISEL-NEXT: RET_ReallyLR implicit $x0 + ; + ; GISEL-LABEL: name: large_imm_disc_wreg + ; GISEL: bb.1.entry: + ; GISEL-NEXT: liveins: $x0 + ; GISEL-NEXT: {{ $}} + ; GISEL-NEXT: [[COPY:%[0-9]+]]:gpr64 = COPY $x0 + ; GISEL-NEXT: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 12345678 + ; GISEL-NEXT: [[SUBREG_TO_REG:%[0-9]+]]:gpr64noip = SUBREG_TO_REG 0, [[MOVi32imm]], %subreg.sub_32 + ; GISEL-NEXT: [[PAC:%[0-9]+]]:gpr64 = PAC [[COPY]], 2, 0, [[SUBREG_TO_REG]], implicit-def dead $x17 + ; GISEL-NEXT: $x0 = COPY [[PAC]] + ; GISEL-NEXT: RET_ReallyLR implicit $x0 +entry: + %signed = call i64 @llvm.ptrauth.sign(i64 %addr, i32 2, i64 12345678) + ret i64 %signed +} + +define i64 @large_imm_disc_xreg(i64 %addr) { + ; DAGISEL-LABEL: name: large_imm_disc_xreg + ; DAGISEL: bb.0.entry: + ; DAGISEL-NEXT: liveins: $x0 + ; DAGISEL-NEXT: {{ $}} + ; DAGISEL-NEXT: [[COPY:%[0-9]+]]:gpr64 = COPY $x0 + ; DAGISEL-NEXT: [[MOVi64imm:%[0-9]+]]:gpr64noip = MOVi64imm 123456789012345 + ; DAGISEL-NEXT: [[PAC:%[0-9]+]]:gpr64 = PAC [[COPY]], 2, 0, killed [[MOVi64imm]], implicit-def dead $x17 + ; DAGISEL-NEXT: $x0 = COPY [[PAC]] + ; DAGISEL-NEXT: RET_ReallyLR implicit $x0 + ; + ; GISEL-LABEL: name: large_imm_disc_xreg + ; GISEL: bb.1.entry: + ; GISEL-NEXT: liveins: $x0 + ; GISEL-NEXT: {{ $}} + ; GISEL-NEXT: [[COPY:%[0-9]+]]:gpr64 = COPY $x0 + ; GISEL-NEXT: [[MOVi64imm:%[0-9]+]]:gpr64noip = MOVi64imm 123456789012345 + ; GISEL-NEXT: [[PAC:%[0-9]+]]:gpr64 = PAC [[COPY]], 2, 0, [[MOVi64imm]], implicit-def dead $x17 + ; GISEL-NEXT: $x0 = COPY [[PAC]] + ; GISEL-NEXT: RET_ReallyLR implicit $x0 +entry: + %signed = call i64 @llvm.ptrauth.sign(i64 %addr, i32 2, i64 123456789012345) + ret i64 %signed +} + +define i64 @blend_and_sign_same_bb(i64 %addr) { + ; DAGISEL-LABEL: name: blend_and_sign_same_bb + ; DAGISEL: bb.0.entry: + ; DAGISEL-NEXT: liveins: $x0 + ; DAGISEL-NEXT: {{ $}} + ; DAGISEL-NEXT: [[COPY:%[0-9]+]]:gpr64 = COPY $x0 + ; DAGISEL-NEXT: [[ADRP:%[0-9]+]]:gpr64common = ADRP target-flags(aarch64-page) @discvar + ; DAGISEL-NEXT: [[LDRXui:%[0-9]+]]:gpr64 = LDRXui killed [[ADRP]], target-flags(aarch64-pageoff, aarch64-nc) @discvar :: (dereferenceable load (s64) from @discvar) + ; DAGISEL-NEXT: [[MOVKXi:%[0-9]+]]:gpr64noip = MOVKXi [[LDRXui]], 42, 48 + ; DAGISEL-NEXT: [[COPY1:%[0-9]+]]:gpr64noip = COPY [[LDRXui]] + ; DAGISEL-NEXT: [[PAC:%[0-9]+]]:gpr64 = PAC [[COPY]], 2, 42, killed [[COPY1]], implicit-def dead $x17 + ; DAGISEL-NEXT: $x0 = COPY [[PAC]] + ; DAGISEL-NEXT: RET_ReallyLR implicit $x0 + ; + ; GISEL-LABEL: name: blend_and_sign_same_bb + ; GISEL: bb.1.entry: + ; GISEL-NEXT: liveins: $x0 + ; GISEL-NEXT: {{ $}} + ; GISEL-NEXT: [[COPY:%[0-9]+]]:gpr64 = COPY $x0 + ; GISEL-NEXT: [[ADRP:%[0-9]+]]:gpr64common = ADRP target-flags(aarch64-page) @discvar + ; GISEL-NEXT: [[LDRXui:%[0-9]+]]:gpr64 = LDRXui [[ADRP]], target-flags(aarch64-pageoff, aarch64-nc) @discvar :: (dereferenceable load (s64) from @discvar) + ; GISEL-NEXT: [[MOVKXi:%[0-9]+]]:gpr64noip = MOVKXi [[LDRXui]], 42, 48 + ; GISEL-NEXT: [[COPY1:%[0-9]+]]:gpr64noip = COPY [[LDRXui]] + ; GISEL-NEXT: [[PAC:%[0-9]+]]:gpr64 = PAC [[COPY]], 2, 42, [[COPY1]], implicit-def dead $x17 + ; GISEL-NEXT: $x0 = COPY [[PAC]] + ; GISEL-NEXT: RET_ReallyLR implicit $x0 +entry: + %addrdisc = load i64, ptr @discvar + %disc = call i64 @llvm.ptrauth.blend(i64 %addrdisc, i64 42) + %signed = call i64 @llvm.ptrauth.sign(i64 %addr, i32 2, i64 %disc) + ret i64 %signed +} + +; In the below test cases both %addrdisc and %disc are computed (i.e. they are +; neither global addresses, nor function arguments) in a different basic block, +; making them harder to express via ISD::PtrAuthGlobalAddress. + +define i64 @blend_and_sign_different_bbs(i64 %addr, i64 %cond) { + ; DAGISEL-LABEL: name: blend_and_sign_different_bbs + ; DAGISEL: bb.0.entry: + ; DAGISEL-NEXT: successors: %bb.1(0x50000000), %bb.2(0x30000000) + ; DAGISEL-NEXT: liveins: $x0, $x1 + ; DAGISEL-NEXT: {{ $}} + ; DAGISEL-NEXT: [[COPY:%[0-9]+]]:gpr64 = COPY $x1 + ; DAGISEL-NEXT: [[COPY1:%[0-9]+]]:gpr64 = COPY $x0 + ; DAGISEL-NEXT: [[ADRP:%[0-9]+]]:gpr64common = ADRP target-flags(aarch64-page) @discvar + ; DAGISEL-NEXT: [[LDRXui:%[0-9]+]]:gpr64 = LDRXui killed [[ADRP]], target-flags(aarch64-pageoff, aarch64-nc) @discvar :: (dereferenceable load (s64) from @discvar) + ; DAGISEL-NEXT: [[MOVKXi:%[0-9]+]]:gpr64 = MOVKXi [[LDRXui]], 42, 48 + ; DAGISEL-NEXT: [[COPY2:%[0-9]+]]:gpr64noip = COPY [[MOVKXi]] + ; DAGISEL-NEXT: CBZX [[COPY]], %bb.2 + ; DAGISEL-NEXT: B %bb.1 + ; DAGISEL-NEXT: {{ $}} + ; DAGISEL-NEXT: bb.1.next: + ; DAGISEL-NEXT: successors: %bb.2(0x80000000) + ; DAGISEL-NEXT: {{ $}} + ; DAGISEL-NEXT: [[COPY3:%[0-9]+]]:gpr64common = COPY [[COPY2]] + ; DAGISEL-NEXT: INLINEASM &nop, 1 /* sideeffect attdialect */, 3866633 /* reguse:GPR64common */, [[COPY3]] + ; DAGISEL-NEXT: {{ $}} + ; DAGISEL-NEXT: bb.2.exit: + ; DAGISEL-NEXT: [[COPY4:%[0-9]+]]:gpr64noip = COPY [[LDRXui]] + ; DAGISEL-NEXT: [[PAC:%[0-9]+]]:gpr64 = PAC [[COPY1]], 2, 42, [[COPY4]], implicit-def dead $x17 + ; DAGISEL-NEXT: $x0 = COPY [[PAC]] + ; DAGISEL-NEXT: RET_ReallyLR implicit $x0 + ; + ; GISEL-LABEL: name: blend_and_sign_different_bbs + ; GISEL: bb.1.entry: + ; GISEL-NEXT: successors: %bb.2(0x50000000), %bb.3(0x30000000) + ; GISEL-NEXT: liveins: $x0, $x1 + ; GISEL-NEXT: {{ $}} + ; GISEL-NEXT: [[COPY:%[0-9]+]]:gpr64 = COPY $x0 + ; GISEL-NEXT: [[COPY1:%[0-9]+]]:gpr64 = COPY $x1 + ; GISEL-NEXT: [[ADRP:%[0-9]+]]:gpr64common = ADRP target-flags(aarch64-page) @discvar + ; GISEL-NEXT: [[LDRXui:%[0-9]+]]:gpr64 = LDRXui [[ADRP]], target-flags(aarch64-pageoff, aarch64-nc) @discvar :: (dereferenceable load (s64) from @discvar) + ; GISEL-NEXT: [[MOVKXi:%[0-9]+]]:gpr64noip = MOVKXi [[LDRXui]], 42, 48 + ; GISEL-NEXT: CBZX [[COPY1]], %bb.3 + ; GISEL-NEXT: B %bb.2 + ; GISEL-NEXT: {{ $}} + ; GISEL-NEXT: bb.2.next: + ; GISEL-NEXT: successors: %bb.3(0x80000000) + ; GISEL-NEXT: {{ $}} + ; GISEL-NEXT: [[COPY2:%[0-9]+]]:gpr64common = COPY [[MOVKXi]] + ; GISEL-NEXT: INLINEASM &nop, 1 /* sideeffect attdialect */, 3866633 /* reguse:GPR64common */, [[COPY2]] + ; GISEL-NEXT: {{ $}} + ; GISEL-NEXT: bb.3.exit: + ; GISEL-NEXT: [[COPY3:%[0-9]+]]:gpr64noip = COPY [[LDRXui]] + ; GISEL-NEXT: [[PAC:%[0-9]+]]:gpr64 = PAC [[COPY]], 2, 42, [[COPY3]], implicit-def dead $x17 + ; GISEL-NEXT: $x0 = COPY [[PAC]] + ; GISEL-NEXT: RET_ReallyLR implicit $x0 +entry: + %addrdisc = load i64, ptr @discvar + %disc = call i64 @llvm.ptrauth.blend(i64 %addrdisc, i64 42) + %cond.b = icmp ne i64 %cond, 0 + br i1 %cond.b, label %next, label %exit + +next: + call void asm sideeffect "nop", "r"(i64 %disc) + br label %exit + +exit: + %signed = call i64 @llvm.ptrauth.sign(i64 %addr, i32 2, i64 %disc) + ret i64 %signed +} _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits