Skip to content

[AArch64][PAC] Introduce AArch64::PAC pseudo instruction #146488

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: users/atrosinenko/machine-licm-implicit-defs
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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;
Expand Down
75 changes: 75 additions & 0 deletions llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3073,6 +3073,76 @@ 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::NoRegister;
IntDisc = MaybeBlend->getOperand(1).getImm();
}
}

// For uniformity, always use NoRegister, as XZR is not necessarily contained
// in the requested register class.
if (AddrDisc == AArch64::XZR)
AddrDisc = AArch64::NoRegister;

// Make sure AddrDisc operand respects the register class imposed by MI.
if (AddrDisc && 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 {

Expand Down Expand Up @@ -3171,6 +3241,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;
}
}

Expand Down
7 changes: 7 additions & 0 deletions llvm/lib/Target/AArch64/AArch64ISelLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would probably suggest to use a bit more specific naming. As blend also could refer to vector blend operation.

MachineOperand &IntDiscOp,
MachineOperand &AddrDiscOp,
const TargetRegisterClass *AddrDiscRC) const;

MachineBasicBlock *
EmitInstrWithCustomInserter(MachineInstr &MI,
MachineBasicBlock *MBB) const override;
Expand Down
21 changes: 20 additions & 1 deletion llvm/lib/Target/AArch64/AArch64InstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -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">;
Expand Down Expand Up @@ -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.
Expand Down
205 changes: 205 additions & 0 deletions llvm/test/CodeGen/AArch64/ptrauth-isel.ll
Original file line number Diff line number Diff line change
@@ -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 $noreg, 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, $noreg, 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
}
Loading