Skip to content

Commit ec68c72

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 707a36c commit ec68c72

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
@@ -171,6 +171,9 @@ class AArch64AsmPrinter : public AsmPrinter {
171171
// Emit the sequence for AUT or AUTPAC.
172172
void emitPtrauthAuthResign(const MachineInstr *MI);
173173

174+
// Emit the sequence for PAC.
175+
void emitPtrauthSign(const MachineInstr *MI);
176+
174177
// Emit the sequence to compute the discriminator.
175178
//
176179
// ScratchReg should be x16/x17.
@@ -2173,6 +2176,31 @@ void AArch64AsmPrinter::emitPtrauthAuthResign(const MachineInstr *MI) {
21732176
OutStreamer->emitLabel(EndSym);
21742177
}
21752178

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

2898+
case AArch64::PAC:
2899+
emitPtrauthSign(MI);
2900+
return;
2901+
28702902
case AArch64::LOADauthptrstatic:
28712903
LowerLOADauthptrstatic(*MI);
28722904
return;

llvm/lib/Target/AArch64/AArch64ISelLowering.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3073,6 +3073,75 @@ AArch64TargetLowering::EmitGetSMESaveSize(MachineInstr &MI,
30733073
return BB;
30743074
}
30753075

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

@@ -3171,6 +3240,11 @@ MachineBasicBlock *AArch64TargetLowering::EmitInstrWithCustomInserter(
31713240
return EmitZTInstr(MI, BB, AArch64::ZERO_T, /*Op0IsDef=*/true);
31723241
case AArch64::MOVT_TIZ_PSEUDO:
31733242
return EmitZTInstr(MI, BB, AArch64::MOVT_TIZ, /*Op0IsDef=*/true);
3243+
3244+
case AArch64::PAC:
3245+
fixupBlendComponents(MI, BB, MI.getOperand(3), MI.getOperand(4),
3246+
&AArch64::GPR64noipRegClass);
3247+
return BB;
31743248
}
31753249
}
31763250

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
@@ -2030,7 +2030,7 @@ let Predicates = [HasPAuth] in {
20302030
def DZB : SignAuthZero<prefix_z, 0b11, !strconcat(asm, "dzb"), op>;
20312031
}
20322032

2033-
defm PAC : SignAuth<0b000, 0b010, "pac", int_ptrauth_sign>;
2033+
defm PAC : SignAuth<0b000, 0b010, "pac", null_frag>;
20342034
defm AUT : SignAuth<0b001, 0b011, "aut", null_frag>;
20352035

20362036
def XPACI : ClearAuth<0, "xpaci">;
@@ -2136,6 +2136,25 @@ let Predicates = [HasPAuth] in {
21362136
let Uses = [X16];
21372137
}
21382138

2139+
// PAC pseudo instruction. Is AsmPrinter, it is expanded into an actual PAC*
2140+
// instruction immediately preceded by the discriminator computation.
2141+
// This enforces the expected immediate modifier is used for signing, even
2142+
// if an attacker is able to substitute AddrDisc.
2143+
def PAC : Pseudo<(outs GPR64:$SignedVal),
2144+
(ins GPR64:$Val, i32imm:$Key, i64imm:$Disc, GPR64noip:$AddrDisc),
2145+
[], "$SignedVal = $Val">, Sched<[WriteI, ReadI]> {
2146+
let isCodeGenOnly = 1;
2147+
let hasSideEffects = 0;
2148+
let mayStore = 0;
2149+
let mayLoad = 0;
2150+
let Size = 12;
2151+
let Defs = [X17];
2152+
let usesCustomInserter = 1;
2153+
}
2154+
2155+
def : Pat<(int_ptrauth_sign GPR64:$Val, timm:$Key, GPR64noip:$AddrDisc),
2156+
(PAC GPR64:$Val, $Key, 0, GPR64noip:$AddrDisc)>;
2157+
21392158
// AUT and re-PAC a value, using different keys/data.
21402159
// This directly manipulates x16/x17, which are the only registers the OS
21412160
// guarantees 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)