Skip to content

[AArch64][PAC] Rework discriminator analysis for calls and tail calls #147136

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/pauth-imm-modifier-auth-resign
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
63 changes: 22 additions & 41 deletions llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -347,40 +347,6 @@ static bool isZeroingInactiveLanes(SDValue Op) {
}
}

static std::tuple<SDValue, SDValue>
extractPtrauthBlendDiscriminators(SDValue Disc, SelectionDAG *DAG) {
SDLoc DL(Disc);
SDValue AddrDisc;
SDValue ConstDisc;

// If this is a blend, remember the constant and address discriminators.
// Otherwise, it's either a constant discriminator, or a non-blended
// address discriminator.
if (Disc->getOpcode() == ISD::INTRINSIC_WO_CHAIN &&
Disc->getConstantOperandVal(0) == Intrinsic::ptrauth_blend) {
AddrDisc = Disc->getOperand(1);
ConstDisc = Disc->getOperand(2);
} else {
ConstDisc = Disc;
}

// If the constant discriminator (either the blend RHS, or the entire
// discriminator value) isn't a 16-bit constant, bail out, and let the
// discriminator be computed separately.
const auto *ConstDiscN = dyn_cast<ConstantSDNode>(ConstDisc);
if (!ConstDiscN || !isUInt<16>(ConstDiscN->getZExtValue()))
return std::make_tuple(DAG->getTargetConstant(0, DL, MVT::i64), Disc);

// If there's no address discriminator, use NoRegister, which we'll later
// replace with XZR, or directly use a Z variant of the inst. when available.
if (!AddrDisc)
AddrDisc = DAG->getRegister(AArch64::NoRegister, MVT::i64);

return std::make_tuple(
DAG->getTargetConstant(ConstDiscN->getZExtValue(), DL, MVT::i64),
AddrDisc);
}

AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
const AArch64Subtarget &STI)
: TargetLowering(TM), Subtarget(&STI) {
Expand Down Expand Up @@ -3124,6 +3090,10 @@ void AArch64TargetLowering::fixupBlendComponents(
isUInt<16>(MaybeBlend->getOperand(1).getImm())) {
AddrDisc = AArch64::NoRegister;
IntDisc = MaybeBlend->getOperand(1).getImm();
} else if (MaybeBlend->getOpcode() == AArch64::COPY &&
MaybeBlend->getOperand(1).getReg() == AArch64::XZR) {
AddrDisc = AArch64::NoRegister;
IntDisc = 0;
}
}

Expand Down Expand Up @@ -3256,6 +3226,22 @@ MachineBasicBlock *AArch64TargetLowering::EmitInstrWithCustomInserter(
fixupBlendComponents(MI, BB, MI.getOperand(4), MI.getOperand(5),
&AArch64::GPR64noipRegClass);
return BB;
case AArch64::AUTH_TCRETURN:
fixupBlendComponents(MI, BB, MI.getOperand(3), MI.getOperand(4),
&AArch64::tcGPR64RegClass);
return BB;
case AArch64::AUTH_TCRETURN_BTI:
fixupBlendComponents(MI, BB, MI.getOperand(3), MI.getOperand(4),
&AArch64::tcGPRnotx16x17RegClass);
return BB;
case AArch64::BLRA:
fixupBlendComponents(MI, BB, MI.getOperand(2), MI.getOperand(3),
&AArch64::GPR64noipRegClass);
return BB;
case AArch64::BLRA_RVMARKER:
fixupBlendComponents(MI, BB, MI.getOperand(4), MI.getOperand(5),
&AArch64::GPR64noipRegClass);
return BB;
}
}

Expand Down Expand Up @@ -9508,18 +9494,13 @@ AArch64TargetLowering::LowerCall(CallLoweringInfo &CLI,
assert((Key == AArch64PACKey::IA || Key == AArch64PACKey::IB) &&
"Invalid auth call key");

// Split the discriminator into address/integer components.
SDValue AddrDisc, IntDisc;
std::tie(IntDisc, AddrDisc) =
extractPtrauthBlendDiscriminators(CLI.PAI->Discriminator, &DAG);

if (Opc == AArch64ISD::CALL_RVMARKER)
Opc = AArch64ISD::AUTH_CALL_RVMARKER;
else
Opc = IsTailCall ? AArch64ISD::AUTH_TC_RETURN : AArch64ISD::AUTH_CALL;
Ops.push_back(DAG.getTargetConstant(Key, DL, MVT::i32));
Ops.push_back(IntDisc);
Ops.push_back(AddrDisc);
Ops.push_back(DAG.getTargetConstant(/*IntDisc=*/0, DL, MVT::i64));
Ops.push_back(CLI.PAI->Discriminator);
}

// Add argument registers to the end of the list so that they are known live
Expand Down
4 changes: 3 additions & 1 deletion llvm/lib/Target/AArch64/AArch64InstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -2080,6 +2080,7 @@ let Predicates = [HasPAuth] in {
let Size = 12; // 4 fixed + 8 variable, to compute discriminator.
let Defs = [X16,X17,LR];
let Uses = [SP];
let usesCustomInserter = 1;
}

def BLRA_RVMARKER : Pseudo<
Expand All @@ -2092,6 +2093,7 @@ let Predicates = [HasPAuth] in {
let isCall = 1;
let Defs = [X16,X17,LR];
let Uses = [SP];
let usesCustomInserter = 1;
}

// BRA pseudo, generalized version of BRAA/BRAB/Z.
Expand Down Expand Up @@ -2221,7 +2223,7 @@ let Predicates = [HasPAuth] in {
// make sure at least one register is usable as a scratch one - for that
// purpose, use tcGPRnotx16x17 register class for one of the operands.
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Size = 16,
Defs = [X16,X17], Uses = [SP] in {
usesCustomInserter = 1, Defs = [X16,X17], Uses = [SP] in {
def AUTH_TCRETURN
: Pseudo<(outs), (ins tcGPRnotx16x17:$dst, i32imm:$FPDiff, i32imm:$Key,
i64imm:$Disc, tcGPR64:$AddrDisc),
Expand Down
24 changes: 6 additions & 18 deletions llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1169,15 +1169,9 @@ bool AArch64CallLowering::lowerTailCall(
Info.PAI->Key == AArch64PACKey::IB) &&
"Invalid auth call key");
MIB.addImm(Info.PAI->Key);

Register AddrDisc = 0;
uint16_t IntDisc = 0;
std::tie(IntDisc, AddrDisc) =
extractPtrauthBlendDiscriminators(Info.PAI->Discriminator, MRI);

MIB.addImm(IntDisc);
MIB.addUse(AddrDisc);
if (AddrDisc != AArch64::NoRegister) {
MIB.addImm(/*IntDisc=*/0);
MIB.addUse(Info.PAI->Discriminator);
if (Info.PAI->Discriminator != AArch64::NoRegister) {
MIB->getOperand(4).setReg(constrainOperandRegClass(
MF, *TRI, MRI, *MF.getSubtarget().getInstrInfo(),
*MF.getSubtarget().getRegBankInfo(), *MIB, MIB->getDesc(),
Expand Down Expand Up @@ -1443,15 +1437,9 @@ bool AArch64CallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
Info.PAI->Key == AArch64PACKey::IB) &&
"Invalid auth call key");
MIB.addImm(Info.PAI->Key);

Register AddrDisc = 0;
uint16_t IntDisc = 0;
std::tie(IntDisc, AddrDisc) =
extractPtrauthBlendDiscriminators(Info.PAI->Discriminator, MRI);

MIB.addImm(IntDisc);
MIB.addUse(AddrDisc);
if (AddrDisc != AArch64::NoRegister) {
MIB.addImm(/*IntDisc=*/0);
MIB.addUse(Info.PAI->Discriminator);
if (Info.PAI->Discriminator != AArch64::NoRegister) {
constrainOperandRegClass(MF, *TRI, MRI, *MF.getSubtarget().getInstrInfo(),
*MF.getSubtarget().getRegBankInfo(), *MIB,
MIB->getDesc(), MIB->getOperand(CalleeOpNo + 3),
Expand Down
4 changes: 2 additions & 2 deletions llvm/test/CodeGen/AArch64/ptrauth-call.ll
Original file line number Diff line number Diff line change
Expand Up @@ -196,9 +196,9 @@ define i32 @test_call_omit_extra_moves(ptr %objptr) #0 {
; CHECK-NEXT: mov x17, x0
; CHECK-NEXT: movk x17, #6503, lsl #48
; CHECK-NEXT: autda x16, x17
; CHECK-NEXT: ldr x8, [x16]
; CHECK-NEXT: ldr x9, [x16]
; CHECK-NEXT: movk x16, #34646, lsl #48
; CHECK-NEXT: blraa x8, x16
; CHECK-NEXT: blraa x9, x16
; CHECK-NEXT: mov w0, #42
; DARWIN-NEXT: ldp x29, x30, [sp], #16
; ELF-NEXT: ldr x30, [sp], #16
Expand Down
216 changes: 216 additions & 0 deletions llvm/test/CodeGen/AArch64/ptrauth-isel.ll
Original file line number Diff line number Diff line change
Expand Up @@ -434,3 +434,219 @@ exit:
%resigned = call i64 @llvm.ptrauth.resign(i64 %addr, i32 2, i64 %auth.disc, i32 3, i64 %sign.disc)
ret i64 %resigned
}

; Test other pseudo instructions accepting discriminator components as separate
; operands: AUTH_TCRETURN, AUTH_TCRETURN_BTI and BLRA.
; FIXME: Test BLRA_RVMARKER.
;
; A few other PAuth-related pseudo instructions exist that accept address and
; integer discriminator components, but the way they are currently selected both
; by DAGISel and GlobalISel is not susceptible to this issue:
; * MOVaddrPAC and LOADgotPAC are only emitted when lowering `ptrauth` constants
; in LLVM IR, so their discriminators are never expressed via blend.
; * BRA is only emitted for indirect branch, and its address discriminator is
; always XZR.
;
; Furthermore, a few more pseudo instructions have HasPAuth in their predicates,
; but only have constant discriminator or no discriminator operands at all:
; LOADgotAUTH and LOADauthptrstatic.
;
; The below test cases specify non-default preserve_nonecc calling convention -
; this is to prevent meaningless divergence between Darwin and ELF targets due
; to difference in callee-saved register masks specified in call instructions.

define preserve_nonecc i64 @auth_tcreturn_blend_components(ptr %callee, i1 %cond.b) {
; DAGISEL-LABEL: name: auth_tcreturn_blend_components
; DAGISEL: bb.0.entry:
; DAGISEL-NEXT: successors: %bb.1(0x40000000), %bb.2(0x40000000)
; DAGISEL-NEXT: liveins: $x20, $w0
; DAGISEL-NEXT: {{ $}}
; DAGISEL-NEXT: [[COPY:%[0-9]+]]:gpr32 = COPY $w0
; DAGISEL-NEXT: [[COPY1:%[0-9]+]]:tcgprnotx16x17 = COPY $x20
; 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]+]]:tcgpr64 = COPY [[MOVKXi]]
; DAGISEL-NEXT: TBZW [[COPY]], 0, %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]+]]:tcgpr64 = COPY [[LDRXui]]
; DAGISEL-NEXT: AUTH_TCRETURN [[COPY1]], 0, 1, 42, [[COPY4]], csr_aarch64_noneregs, implicit-def dead $x16, implicit-def dead $x17, implicit $sp
;
; GISEL-LABEL: name: auth_tcreturn_blend_components
; GISEL: bb.1.entry:
; GISEL-NEXT: successors: %bb.2(0x40000000), %bb.3(0x40000000)
; GISEL-NEXT: liveins: $w0, $x20
; GISEL-NEXT: {{ $}}
; GISEL-NEXT: [[COPY:%[0-9]+]]:tcgprnotx16x17 = COPY $x20
; GISEL-NEXT: [[COPY1:%[0-9]+]]:gpr32 = COPY $w0
; 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]+]]:tcgpr64 = MOVKXi [[LDRXui]], 42, 48
; GISEL-NEXT: TBZW [[COPY1]], 0, %bb.3
; GISEL-NEXT: B %bb.2
; GISEL-NEXT: {{ $}}
; GISEL-NEXT: bb.2.next:
; GISEL-NEXT: successors: %bb.3(0x80000000)
; GISEL-NEXT: {{ $}}
; GISEL-NEXT: INLINEASM &nop, 1 /* sideeffect attdialect */, 3866633 /* reguse:GPR64common */, [[MOVKXi]]
; GISEL-NEXT: {{ $}}
; GISEL-NEXT: bb.3.exit:
; GISEL-NEXT: [[COPY2:%[0-9]+]]:tcgpr64 = COPY [[LDRXui]]
; GISEL-NEXT: AUTH_TCRETURN [[COPY]], 0, 1, 42, [[COPY2]], csr_aarch64_noneregs, implicit-def $x16, implicit-def $x17, implicit $sp
entry:
%addrdisc = load i64, ptr @discvar
%disc = call i64 @llvm.ptrauth.blend(i64 %addrdisc, i64 42)
br i1 %cond.b, label %next, label %exit

next:
call void asm sideeffect "nop", "r"(i64 %disc)
br label %exit

exit:
%result = tail call preserve_nonecc i64 %callee() [ "ptrauth"(i32 1, i64 %disc) ]
ret i64 %result
}

define preserve_nonecc i64 @auth_tcreturn_bti_blend_components(ptr %callee, i1 %cond.b) "branch-target-enforcement"="true" {
; DAGISEL-LABEL: name: auth_tcreturn_bti_blend_components
; DAGISEL: bb.0.entry:
; DAGISEL-NEXT: successors: %bb.1(0x40000000), %bb.2(0x40000000)
; DAGISEL-NEXT: liveins: $x20, $w0
; DAGISEL-NEXT: {{ $}}
; DAGISEL-NEXT: [[COPY:%[0-9]+]]:gpr32 = COPY $w0
; DAGISEL-NEXT: [[COPY1:%[0-9]+]]:gpr64 = COPY $x20
; 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]+]]:tcgprnotx16x17 = COPY [[MOVKXi]]
; DAGISEL-NEXT: TBZW [[COPY]], 0, %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]+]]:tcgprx16x17 = COPY [[COPY1]]
; DAGISEL-NEXT: [[COPY5:%[0-9]+]]:tcgprnotx16x17 = COPY [[LDRXui]]
; DAGISEL-NEXT: AUTH_TCRETURN_BTI [[COPY4]], 0, 1, 42, [[COPY5]], csr_aarch64_noneregs, implicit-def dead $x16, implicit-def dead $x17, implicit $sp
;
; GISEL-LABEL: name: auth_tcreturn_bti_blend_components
; GISEL: bb.1.entry:
; GISEL-NEXT: successors: %bb.2(0x40000000), %bb.3(0x40000000)
; GISEL-NEXT: liveins: $w0, $x20
; GISEL-NEXT: {{ $}}
; GISEL-NEXT: [[COPY:%[0-9]+]]:tcgprx16x17 = COPY $x20
; GISEL-NEXT: [[COPY1:%[0-9]+]]:gpr32 = COPY $w0
; 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]+]]:tcgprnotx16x17 = MOVKXi [[LDRXui]], 42, 48
; GISEL-NEXT: TBZW [[COPY1]], 0, %bb.3
; GISEL-NEXT: B %bb.2
; GISEL-NEXT: {{ $}}
; GISEL-NEXT: bb.2.next:
; GISEL-NEXT: successors: %bb.3(0x80000000)
; GISEL-NEXT: {{ $}}
; GISEL-NEXT: INLINEASM &nop, 1 /* sideeffect attdialect */, 3866633 /* reguse:GPR64common */, [[MOVKXi]]
; GISEL-NEXT: {{ $}}
; GISEL-NEXT: bb.3.exit:
; GISEL-NEXT: [[COPY2:%[0-9]+]]:tcgprnotx16x17 = COPY [[LDRXui]]
; GISEL-NEXT: AUTH_TCRETURN_BTI [[COPY]], 0, 1, 42, [[COPY2]], csr_aarch64_noneregs, implicit-def $x16, implicit-def $x17, implicit $sp
entry:
%addrdisc = load i64, ptr @discvar
%disc = call i64 @llvm.ptrauth.blend(i64 %addrdisc, i64 42)
br i1 %cond.b, label %next, label %exit

next:
call void asm sideeffect "nop", "r"(i64 %disc)
br label %exit

exit:
%result = tail call preserve_nonecc i64 %callee() [ "ptrauth"(i32 1, i64 %disc) ]
ret i64 %result
}

define preserve_nonecc i64 @blra_blend_components(ptr %callee, i1 %cond.b) {
; DAGISEL-LABEL: name: blra_blend_components
; DAGISEL: bb.0.entry:
; DAGISEL-NEXT: successors: %bb.1(0x40000000), %bb.2(0x40000000)
; DAGISEL-NEXT: liveins: $x20, $w0
; DAGISEL-NEXT: {{ $}}
; DAGISEL-NEXT: [[COPY:%[0-9]+]]:gpr32 = COPY $w0
; DAGISEL-NEXT: [[COPY1:%[0-9]+]]:gpr64noip = COPY $x20
; 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]+]]:gpr64 = COPY [[MOVKXi]]
; DAGISEL-NEXT: TBZW [[COPY]], 0, %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: ADJCALLSTACKDOWN 0, 0, implicit-def dead $sp, implicit $sp
; DAGISEL-NEXT: [[COPY4:%[0-9]+]]:gpr64noip = COPY [[LDRXui]]
; DAGISEL-NEXT: BLRA [[COPY1]], 1, 42, [[COPY4]], csr_aarch64_noneregs, implicit-def dead $x16, implicit-def dead $x17, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def $x0
; DAGISEL-NEXT: ADJCALLSTACKUP 0, 0, implicit-def dead $sp, implicit $sp
; DAGISEL-NEXT: [[COPY5:%[0-9]+]]:gpr64sp = COPY $x0
; DAGISEL-NEXT: [[ADDXri:%[0-9]+]]:gpr64sp = ADDXri [[COPY5]], 123, 0
; DAGISEL-NEXT: $x0 = COPY [[ADDXri]]
; DAGISEL-NEXT: RET_ReallyLR implicit $x0
;
; GISEL-LABEL: name: blra_blend_components
; GISEL: bb.1.entry:
; GISEL-NEXT: successors: %bb.2(0x40000000), %bb.3(0x40000000)
; GISEL-NEXT: liveins: $w0, $x20
; GISEL-NEXT: {{ $}}
; GISEL-NEXT: [[COPY:%[0-9]+]]:gpr64noip = COPY $x20
; GISEL-NEXT: [[COPY1:%[0-9]+]]:gpr32 = COPY $w0
; 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]+]]:gpr64 = MOVKXi [[LDRXui]], 42, 48
; GISEL-NEXT: TBZW [[COPY1]], 0, %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: ADJCALLSTACKDOWN 0, 0, implicit-def $sp, implicit $sp
; GISEL-NEXT: [[COPY3:%[0-9]+]]:gpr64noip = COPY [[LDRXui]]
; GISEL-NEXT: BLRA [[COPY]], 1, 42, [[COPY3]], csr_aarch64_noneregs, implicit-def $x16, implicit-def $x17, implicit-def $lr, implicit $sp, implicit-def $x0
; GISEL-NEXT: ADJCALLSTACKUP 0, 0, implicit-def $sp, implicit $sp
; GISEL-NEXT: [[COPY4:%[0-9]+]]:gpr64sp = COPY $x0
; GISEL-NEXT: [[ADDXri:%[0-9]+]]:gpr64sp = ADDXri [[COPY4]], 123, 0
; GISEL-NEXT: $x0 = COPY [[ADDXri]]
; GISEL-NEXT: RET_ReallyLR implicit $x0
entry:
%addrdisc = load i64, ptr @discvar
%disc = call i64 @llvm.ptrauth.blend(i64 %addrdisc, i64 42)
br i1 %cond.b, label %next, label %exit

next:
call void asm sideeffect "nop", "r"(i64 %disc)
br label %exit

exit:
%tmp = call preserve_nonecc i64 %callee() [ "ptrauth"(i32 1, i64 %disc) ]
; Prevent tail call.
%result = add i64 %tmp, 123
ret i64 %result
}
Loading