Skip to content

Commit f7d5f4d

Browse files
committed
[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.
1 parent 343e3c6 commit f7d5f4d

File tree

5 files changed

+338
-1
lines changed

5 files changed

+338
-1
lines changed

llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,9 @@ class AArch64AsmPrinter : public AsmPrinter {
176176
std::optional<AArch64PACKey::ID> PACKey,
177177
uint64_t PACDisc, Register PACAddrDisc);
178178

179+
// Emit the sequence for PAC.
180+
void emitPtrauthSign(const MachineInstr *MI);
181+
179182
// Emit the sequence to compute the discriminator.
180183
//
181184
// The returned register is either unmodified AddrDisc or ScratchReg.
@@ -2175,6 +2178,31 @@ void AArch64AsmPrinter::emitPtrauthAuthResign(
21752178
OutStreamer->emitLabel(EndSym);
21762179
}
21772180

2181+
void AArch64AsmPrinter::emitPtrauthSign(const MachineInstr *MI) {
2182+
Register Val = MI->getOperand(1).getReg();
2183+
auto Key = (AArch64PACKey::ID)MI->getOperand(2).getImm();
2184+
uint64_t Disc = MI->getOperand(3).getImm();
2185+
Register AddrDisc = MI->getOperand(4).getReg();
2186+
bool AddrDiscKilled = MI->getOperand(4).isKill();
2187+
2188+
// Compute aut discriminator into x17
2189+
assert(isUInt<16>(Disc));
2190+
Register DiscReg = emitPtrauthDiscriminator(
2191+
Disc, AddrDisc, AArch64::X17, /*MayUseAddrAsScratch=*/AddrDiscKilled);
2192+
bool IsZeroDisc = DiscReg == AArch64::XZR;
2193+
unsigned Opc = getPACOpcodeForKey(Key, IsZeroDisc);
2194+
2195+
// paciza x16 ; if IsZeroDisc
2196+
// pacia x16, x17 ; if !IsZeroDisc
2197+
MCInst PACInst;
2198+
PACInst.setOpcode(Opc);
2199+
PACInst.addOperand(MCOperand::createReg(Val));
2200+
PACInst.addOperand(MCOperand::createReg(Val));
2201+
if (!IsZeroDisc)
2202+
PACInst.addOperand(MCOperand::createReg(DiscReg));
2203+
EmitToStreamer(*OutStreamer, PACInst);
2204+
}
2205+
21782206
void AArch64AsmPrinter::emitPtrauthBranch(const MachineInstr *MI) {
21792207
bool IsCall = MI->getOpcode() == AArch64::BLRA;
21802208
unsigned BrTarget = MI->getOperand(0).getReg();
@@ -2890,6 +2918,10 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) {
28902918
MI->getOperand(4).getImm(), MI->getOperand(5).getReg());
28912919
return;
28922920

2921+
case AArch64::PAC:
2922+
emitPtrauthSign(MI);
2923+
return;
2924+
28932925
case AArch64::LOADauthptrstatic:
28942926
LowerLOADauthptrstatic(*MI);
28952927
return;

llvm/lib/Target/AArch64/AArch64ISelLowering.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3079,6 +3079,75 @@ AArch64TargetLowering::EmitGetSMESaveSize(MachineInstr &MI,
30793079
return BB;
30803080
}
30813081

3082+
// Helper function to find the instruction that defined a virtual register.
3083+
// If unable to find such instruction, returns nullptr.
3084+
static MachineInstr *stripVRegCopies(const MachineRegisterInfo &MRI,
3085+
Register Reg) {
3086+
while (Reg.isVirtual()) {
3087+
MachineInstr *DefMI = MRI.getVRegDef(Reg);
3088+
assert(DefMI && "Virtual register definition not found");
3089+
unsigned Opcode = DefMI->getOpcode();
3090+
3091+
if (Opcode == AArch64::COPY) {
3092+
Reg = DefMI->getOperand(1).getReg();
3093+
// Vreg is defined by copying from physreg.
3094+
if (Reg.isPhysical())
3095+
return DefMI;
3096+
continue;
3097+
}
3098+
if (Opcode == AArch64::SUBREG_TO_REG) {
3099+
Reg = DefMI->getOperand(2).getReg();
3100+
continue;
3101+
}
3102+
3103+
return DefMI;
3104+
}
3105+
return nullptr;
3106+
}
3107+
3108+
void AArch64TargetLowering::fixupBlendComponents(
3109+
MachineInstr &MI, MachineBasicBlock *BB, MachineOperand &IntDiscOp,
3110+
MachineOperand &AddrDiscOp, const TargetRegisterClass *AddrDiscRC) const {
3111+
const TargetInstrInfo *TII = Subtarget->getInstrInfo();
3112+
MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
3113+
const DebugLoc &DL = MI.getDebugLoc();
3114+
3115+
Register AddrDisc = AddrDiscOp.getReg();
3116+
int64_t IntDisc = IntDiscOp.getImm();
3117+
3118+
assert(IntDisc == 0 && "Blend components are already expanded");
3119+
3120+
MachineInstr *MaybeBlend = stripVRegCopies(MRI, AddrDisc);
3121+
3122+
if (MaybeBlend) {
3123+
// Detect blend(addr, imm) which is lowered as "MOVK addr, #imm, #48".
3124+
// Alternatively, recognize small immediate modifier passed via VReg.
3125+
if (MaybeBlend->getOpcode() == AArch64::MOVKXi &&
3126+
MaybeBlend->getOperand(3).getImm() == 48) {
3127+
AddrDisc = MaybeBlend->getOperand(1).getReg();
3128+
IntDisc = MaybeBlend->getOperand(2).getImm();
3129+
} else if (MaybeBlend->getOpcode() == AArch64::MOVi32imm &&
3130+
isUInt<16>(MaybeBlend->getOperand(1).getImm())) {
3131+
AddrDisc = AArch64::XZR;
3132+
IntDisc = MaybeBlend->getOperand(1).getImm();
3133+
}
3134+
}
3135+
3136+
// Normalize NoRegister operands emitted by GlobalISel.
3137+
if (AddrDisc == AArch64::NoRegister)
3138+
AddrDisc = AArch64::XZR;
3139+
3140+
// Make sure AddrDisc operand respects the register class imposed by MI.
3141+
if (AddrDisc != AArch64::XZR && MRI.getRegClass(AddrDisc) != AddrDiscRC) {
3142+
Register TmpReg = MRI.createVirtualRegister(AddrDiscRC);
3143+
BuildMI(*BB, MI, DL, TII->get(AArch64::COPY), TmpReg).addReg(AddrDisc);
3144+
AddrDisc = TmpReg;
3145+
}
3146+
3147+
AddrDiscOp.setReg(AddrDisc);
3148+
IntDiscOp.setImm(IntDisc);
3149+
}
3150+
30823151
MachineBasicBlock *AArch64TargetLowering::EmitInstrWithCustomInserter(
30833152
MachineInstr &MI, MachineBasicBlock *BB) const {
30843153

@@ -3177,6 +3246,11 @@ MachineBasicBlock *AArch64TargetLowering::EmitInstrWithCustomInserter(
31773246
return EmitZTInstr(MI, BB, AArch64::ZERO_T, /*Op0IsDef=*/true);
31783247
case AArch64::MOVT_TIZ_PSEUDO:
31793248
return EmitZTInstr(MI, BB, AArch64::MOVT_TIZ, /*Op0IsDef=*/true);
3249+
3250+
case AArch64::PAC:
3251+
fixupBlendComponents(MI, BB, MI.getOperand(3), MI.getOperand(4),
3252+
&AArch64::GPR64noipRegClass);
3253+
return BB;
31803254
}
31813255
}
31823256

llvm/lib/Target/AArch64/AArch64ISelLowering.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,13 @@ class AArch64TargetLowering : public TargetLowering {
182182
MachineBasicBlock *EmitGetSMESaveSize(MachineInstr &MI,
183183
MachineBasicBlock *BB) const;
184184

185+
/// Replace (0, vreg) discriminator components with the operands of blend
186+
/// or with (immediate, XZR) when possible.
187+
void fixupBlendComponents(MachineInstr &MI, MachineBasicBlock *BB,
188+
MachineOperand &IntDiscOp,
189+
MachineOperand &AddrDiscOp,
190+
const TargetRegisterClass *AddrDiscRC) const;
191+
185192
MachineBasicBlock *
186193
EmitInstrWithCustomInserter(MachineInstr &MI,
187194
MachineBasicBlock *MBB) const override;

llvm/lib/Target/AArch64/AArch64InstrInfo.td

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2036,7 +2036,7 @@ let Predicates = [HasPAuth] in {
20362036
def DZB : SignAuthZero<prefix_z, 0b11, !strconcat(asm, "dzb"), op>;
20372037
}
20382038

2039-
defm PAC : SignAuth<0b000, 0b010, "pac", int_ptrauth_sign>;
2039+
defm PAC : SignAuth<0b000, 0b010, "pac", null_frag>;
20402040
defm AUT : SignAuth<0b001, 0b011, "aut", null_frag>;
20412041

20422042
def XPACI : ClearAuth<0, "xpaci">;
@@ -2156,6 +2156,25 @@ let Predicates = [HasPAuth] in {
21562156
let Uses = [];
21572157
}
21582158

2159+
// PAC pseudo instruction. Is AsmPrinter, it is expanded into an actual PAC*
2160+
// instruction immediately preceded by the discriminator computation.
2161+
// This enforces the expected immediate modifier is used for signing, even
2162+
// if an attacker is able to substitute AddrDisc.
2163+
def PAC : Pseudo<(outs GPR64:$SignedVal),
2164+
(ins GPR64:$Val, i32imm:$Key, i64imm:$Disc, GPR64noip:$AddrDisc),
2165+
[], "$SignedVal = $Val">, Sched<[WriteI, ReadI]> {
2166+
let isCodeGenOnly = 1;
2167+
let hasSideEffects = 0;
2168+
let mayStore = 0;
2169+
let mayLoad = 0;
2170+
let Size = 12;
2171+
let Defs = [X17];
2172+
let usesCustomInserter = 1;
2173+
}
2174+
2175+
def : Pat<(int_ptrauth_sign GPR64:$Val, timm:$Key, GPR64noip:$AddrDisc),
2176+
(PAC GPR64:$Val, $Key, 0, GPR64noip:$AddrDisc)>;
2177+
21592178
// AUT and re-PAC a value, using different keys/data.
21602179
// This directly manipulates x16/x17, which are the only registers that
21612180
// certain OSs guarantee are safe to use for sensitive operations.
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5
2+
; RUN: llc < %s -mtriple arm64e-apple-darwin -verify-machineinstrs -stop-after=finalize-isel -global-isel=0 \
3+
; RUN: | FileCheck %s --check-prefixes=DAGISEL
4+
; RUN: llc < %s -mtriple arm64e-apple-darwin -verify-machineinstrs -stop-after=finalize-isel -global-isel=1 -global-isel-abort=1 \
5+
; RUN: | FileCheck %s --check-prefixes=GISEL
6+
; RUN: llc < %s -mtriple aarch64-linux-gnu -mattr=+pauth -verify-machineinstrs -stop-after=finalize-isel -global-isel=0 \
7+
; RUN: | FileCheck %s --check-prefixes=DAGISEL
8+
; RUN: llc < %s -mtriple aarch64-linux-gnu -mattr=+pauth -verify-machineinstrs -stop-after=finalize-isel -global-isel=1 -global-isel-abort=1 \
9+
; RUN: | FileCheck %s --check-prefixes=GISEL
10+
11+
; Check MIR produced by the instruction selector to validate properties that
12+
; cannot be reliably tested by only inspecting the final asm output.
13+
14+
@discvar = dso_local global i64 0
15+
16+
; Make sure the components of blend(addr, imm) are recognized and passed to
17+
; PAC pseudo via separate operands to prevent substitution of the immediate
18+
; modifier.
19+
;
20+
; MIR output of the instruction selector is inspected, as it is hard to reliably
21+
; distinguish MOVKXi immediately followed by a pseudo from a standalone pseudo
22+
; instruction carrying address and immediate modifiers in its separate operands
23+
; by only observing the final asm output.
24+
25+
define i64 @small_imm_disc(i64 %addr) {
26+
; DAGISEL-LABEL: name: small_imm_disc
27+
; DAGISEL: bb.0.entry:
28+
; DAGISEL-NEXT: liveins: $x0
29+
; DAGISEL-NEXT: {{ $}}
30+
; DAGISEL-NEXT: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
31+
; DAGISEL-NEXT: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 42
32+
; DAGISEL-NEXT: [[SUBREG_TO_REG:%[0-9]+]]:gpr64noip = SUBREG_TO_REG 0, killed [[MOVi32imm]], %subreg.sub_32
33+
; DAGISEL-NEXT: [[PAC:%[0-9]+]]:gpr64 = PAC [[COPY]], 2, 42, killed $xzr, implicit-def dead $x17
34+
; DAGISEL-NEXT: $x0 = COPY [[PAC]]
35+
; DAGISEL-NEXT: RET_ReallyLR implicit $x0
36+
;
37+
; GISEL-LABEL: name: small_imm_disc
38+
; GISEL: bb.1.entry:
39+
; GISEL-NEXT: liveins: $x0
40+
; GISEL-NEXT: {{ $}}
41+
; GISEL-NEXT: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
42+
; GISEL-NEXT: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 42
43+
; GISEL-NEXT: [[SUBREG_TO_REG:%[0-9]+]]:gpr64noip = SUBREG_TO_REG 0, [[MOVi32imm]], %subreg.sub_32
44+
; GISEL-NEXT: [[PAC:%[0-9]+]]:gpr64 = PAC [[COPY]], 2, 42, $xzr, implicit-def dead $x17
45+
; GISEL-NEXT: $x0 = COPY [[PAC]]
46+
; GISEL-NEXT: RET_ReallyLR implicit $x0
47+
entry:
48+
%signed = call i64 @llvm.ptrauth.sign(i64 %addr, i32 2, i64 42)
49+
ret i64 %signed
50+
}
51+
52+
define i64 @large_imm_disc_wreg(i64 %addr) {
53+
; DAGISEL-LABEL: name: large_imm_disc_wreg
54+
; DAGISEL: bb.0.entry:
55+
; DAGISEL-NEXT: liveins: $x0
56+
; DAGISEL-NEXT: {{ $}}
57+
; DAGISEL-NEXT: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
58+
; DAGISEL-NEXT: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 12345678
59+
; DAGISEL-NEXT: [[SUBREG_TO_REG:%[0-9]+]]:gpr64noip = SUBREG_TO_REG 0, killed [[MOVi32imm]], %subreg.sub_32
60+
; DAGISEL-NEXT: [[PAC:%[0-9]+]]:gpr64 = PAC [[COPY]], 2, 0, killed [[SUBREG_TO_REG]], implicit-def dead $x17
61+
; DAGISEL-NEXT: $x0 = COPY [[PAC]]
62+
; DAGISEL-NEXT: RET_ReallyLR implicit $x0
63+
;
64+
; GISEL-LABEL: name: large_imm_disc_wreg
65+
; GISEL: bb.1.entry:
66+
; GISEL-NEXT: liveins: $x0
67+
; GISEL-NEXT: {{ $}}
68+
; GISEL-NEXT: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
69+
; GISEL-NEXT: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 12345678
70+
; GISEL-NEXT: [[SUBREG_TO_REG:%[0-9]+]]:gpr64noip = SUBREG_TO_REG 0, [[MOVi32imm]], %subreg.sub_32
71+
; GISEL-NEXT: [[PAC:%[0-9]+]]:gpr64 = PAC [[COPY]], 2, 0, [[SUBREG_TO_REG]], implicit-def dead $x17
72+
; GISEL-NEXT: $x0 = COPY [[PAC]]
73+
; GISEL-NEXT: RET_ReallyLR implicit $x0
74+
entry:
75+
%signed = call i64 @llvm.ptrauth.sign(i64 %addr, i32 2, i64 12345678)
76+
ret i64 %signed
77+
}
78+
79+
define i64 @large_imm_disc_xreg(i64 %addr) {
80+
; DAGISEL-LABEL: name: large_imm_disc_xreg
81+
; DAGISEL: bb.0.entry:
82+
; DAGISEL-NEXT: liveins: $x0
83+
; DAGISEL-NEXT: {{ $}}
84+
; DAGISEL-NEXT: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
85+
; DAGISEL-NEXT: [[MOVi64imm:%[0-9]+]]:gpr64noip = MOVi64imm 123456789012345
86+
; DAGISEL-NEXT: [[PAC:%[0-9]+]]:gpr64 = PAC [[COPY]], 2, 0, killed [[MOVi64imm]], implicit-def dead $x17
87+
; DAGISEL-NEXT: $x0 = COPY [[PAC]]
88+
; DAGISEL-NEXT: RET_ReallyLR implicit $x0
89+
;
90+
; GISEL-LABEL: name: large_imm_disc_xreg
91+
; GISEL: bb.1.entry:
92+
; GISEL-NEXT: liveins: $x0
93+
; GISEL-NEXT: {{ $}}
94+
; GISEL-NEXT: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
95+
; GISEL-NEXT: [[MOVi64imm:%[0-9]+]]:gpr64noip = MOVi64imm 123456789012345
96+
; GISEL-NEXT: [[PAC:%[0-9]+]]:gpr64 = PAC [[COPY]], 2, 0, [[MOVi64imm]], implicit-def dead $x17
97+
; GISEL-NEXT: $x0 = COPY [[PAC]]
98+
; GISEL-NEXT: RET_ReallyLR implicit $x0
99+
entry:
100+
%signed = call i64 @llvm.ptrauth.sign(i64 %addr, i32 2, i64 123456789012345)
101+
ret i64 %signed
102+
}
103+
104+
define i64 @blend_and_sign_same_bb(i64 %addr) {
105+
; DAGISEL-LABEL: name: blend_and_sign_same_bb
106+
; DAGISEL: bb.0.entry:
107+
; DAGISEL-NEXT: liveins: $x0
108+
; DAGISEL-NEXT: {{ $}}
109+
; DAGISEL-NEXT: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
110+
; DAGISEL-NEXT: [[ADRP:%[0-9]+]]:gpr64common = ADRP target-flags(aarch64-page) @discvar
111+
; DAGISEL-NEXT: [[LDRXui:%[0-9]+]]:gpr64 = LDRXui killed [[ADRP]], target-flags(aarch64-pageoff, aarch64-nc) @discvar :: (dereferenceable load (s64) from @discvar)
112+
; DAGISEL-NEXT: [[MOVKXi:%[0-9]+]]:gpr64noip = MOVKXi [[LDRXui]], 42, 48
113+
; DAGISEL-NEXT: [[COPY1:%[0-9]+]]:gpr64noip = COPY [[LDRXui]]
114+
; DAGISEL-NEXT: [[PAC:%[0-9]+]]:gpr64 = PAC [[COPY]], 2, 42, killed [[COPY1]], implicit-def dead $x17
115+
; DAGISEL-NEXT: $x0 = COPY [[PAC]]
116+
; DAGISEL-NEXT: RET_ReallyLR implicit $x0
117+
;
118+
; GISEL-LABEL: name: blend_and_sign_same_bb
119+
; GISEL: bb.1.entry:
120+
; GISEL-NEXT: liveins: $x0
121+
; GISEL-NEXT: {{ $}}
122+
; GISEL-NEXT: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
123+
; GISEL-NEXT: [[ADRP:%[0-9]+]]:gpr64common = ADRP target-flags(aarch64-page) @discvar
124+
; GISEL-NEXT: [[LDRXui:%[0-9]+]]:gpr64 = LDRXui [[ADRP]], target-flags(aarch64-pageoff, aarch64-nc) @discvar :: (dereferenceable load (s64) from @discvar)
125+
; GISEL-NEXT: [[MOVKXi:%[0-9]+]]:gpr64noip = MOVKXi [[LDRXui]], 42, 48
126+
; GISEL-NEXT: [[COPY1:%[0-9]+]]:gpr64noip = COPY [[LDRXui]]
127+
; GISEL-NEXT: [[PAC:%[0-9]+]]:gpr64 = PAC [[COPY]], 2, 42, [[COPY1]], implicit-def dead $x17
128+
; GISEL-NEXT: $x0 = COPY [[PAC]]
129+
; GISEL-NEXT: RET_ReallyLR implicit $x0
130+
entry:
131+
%addrdisc = load i64, ptr @discvar
132+
%disc = call i64 @llvm.ptrauth.blend(i64 %addrdisc, i64 42)
133+
%signed = call i64 @llvm.ptrauth.sign(i64 %addr, i32 2, i64 %disc)
134+
ret i64 %signed
135+
}
136+
137+
; In the below test cases both %addrdisc and %disc are computed (i.e. they are
138+
; neither global addresses, nor function arguments) in a different basic block,
139+
; making them harder to express via ISD::PtrAuthGlobalAddress.
140+
141+
define i64 @blend_and_sign_different_bbs(i64 %addr, i64 %cond) {
142+
; DAGISEL-LABEL: name: blend_and_sign_different_bbs
143+
; DAGISEL: bb.0.entry:
144+
; DAGISEL-NEXT: successors: %bb.1(0x50000000), %bb.2(0x30000000)
145+
; DAGISEL-NEXT: liveins: $x0, $x1
146+
; DAGISEL-NEXT: {{ $}}
147+
; DAGISEL-NEXT: [[COPY:%[0-9]+]]:gpr64 = COPY $x1
148+
; DAGISEL-NEXT: [[COPY1:%[0-9]+]]:gpr64 = COPY $x0
149+
; DAGISEL-NEXT: [[ADRP:%[0-9]+]]:gpr64common = ADRP target-flags(aarch64-page) @discvar
150+
; DAGISEL-NEXT: [[LDRXui:%[0-9]+]]:gpr64 = LDRXui killed [[ADRP]], target-flags(aarch64-pageoff, aarch64-nc) @discvar :: (dereferenceable load (s64) from @discvar)
151+
; DAGISEL-NEXT: [[MOVKXi:%[0-9]+]]:gpr64 = MOVKXi [[LDRXui]], 42, 48
152+
; DAGISEL-NEXT: [[COPY2:%[0-9]+]]:gpr64noip = COPY [[MOVKXi]]
153+
; DAGISEL-NEXT: CBZX [[COPY]], %bb.2
154+
; DAGISEL-NEXT: B %bb.1
155+
; DAGISEL-NEXT: {{ $}}
156+
; DAGISEL-NEXT: bb.1.next:
157+
; DAGISEL-NEXT: successors: %bb.2(0x80000000)
158+
; DAGISEL-NEXT: {{ $}}
159+
; DAGISEL-NEXT: [[COPY3:%[0-9]+]]:gpr64common = COPY [[COPY2]]
160+
; DAGISEL-NEXT: INLINEASM &nop, 1 /* sideeffect attdialect */, 3866633 /* reguse:GPR64common */, [[COPY3]]
161+
; DAGISEL-NEXT: {{ $}}
162+
; DAGISEL-NEXT: bb.2.exit:
163+
; DAGISEL-NEXT: [[COPY4:%[0-9]+]]:gpr64noip = COPY [[LDRXui]]
164+
; DAGISEL-NEXT: [[PAC:%[0-9]+]]:gpr64 = PAC [[COPY1]], 2, 42, [[COPY4]], implicit-def dead $x17
165+
; DAGISEL-NEXT: $x0 = COPY [[PAC]]
166+
; DAGISEL-NEXT: RET_ReallyLR implicit $x0
167+
;
168+
; GISEL-LABEL: name: blend_and_sign_different_bbs
169+
; GISEL: bb.1.entry:
170+
; GISEL-NEXT: successors: %bb.2(0x50000000), %bb.3(0x30000000)
171+
; GISEL-NEXT: liveins: $x0, $x1
172+
; GISEL-NEXT: {{ $}}
173+
; GISEL-NEXT: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
174+
; GISEL-NEXT: [[COPY1:%[0-9]+]]:gpr64 = COPY $x1
175+
; GISEL-NEXT: [[ADRP:%[0-9]+]]:gpr64common = ADRP target-flags(aarch64-page) @discvar
176+
; GISEL-NEXT: [[LDRXui:%[0-9]+]]:gpr64 = LDRXui [[ADRP]], target-flags(aarch64-pageoff, aarch64-nc) @discvar :: (dereferenceable load (s64) from @discvar)
177+
; GISEL-NEXT: [[MOVKXi:%[0-9]+]]:gpr64noip = MOVKXi [[LDRXui]], 42, 48
178+
; GISEL-NEXT: CBZX [[COPY1]], %bb.3
179+
; GISEL-NEXT: B %bb.2
180+
; GISEL-NEXT: {{ $}}
181+
; GISEL-NEXT: bb.2.next:
182+
; GISEL-NEXT: successors: %bb.3(0x80000000)
183+
; GISEL-NEXT: {{ $}}
184+
; GISEL-NEXT: [[COPY2:%[0-9]+]]:gpr64common = COPY [[MOVKXi]]
185+
; GISEL-NEXT: INLINEASM &nop, 1 /* sideeffect attdialect */, 3866633 /* reguse:GPR64common */, [[COPY2]]
186+
; GISEL-NEXT: {{ $}}
187+
; GISEL-NEXT: bb.3.exit:
188+
; GISEL-NEXT: [[COPY3:%[0-9]+]]:gpr64noip = COPY [[LDRXui]]
189+
; GISEL-NEXT: [[PAC:%[0-9]+]]:gpr64 = PAC [[COPY]], 2, 42, [[COPY3]], implicit-def dead $x17
190+
; GISEL-NEXT: $x0 = COPY [[PAC]]
191+
; GISEL-NEXT: RET_ReallyLR implicit $x0
192+
entry:
193+
%addrdisc = load i64, ptr @discvar
194+
%disc = call i64 @llvm.ptrauth.blend(i64 %addrdisc, i64 42)
195+
%cond.b = icmp ne i64 %cond, 0
196+
br i1 %cond.b, label %next, label %exit
197+
198+
next:
199+
call void asm sideeffect "nop", "r"(i64 %disc)
200+
br label %exit
201+
202+
exit:
203+
%signed = call i64 @llvm.ptrauth.sign(i64 %addr, i32 2, i64 %disc)
204+
ret i64 %signed
205+
}

0 commit comments

Comments
 (0)