Skip to content

Commit 43f3996

Browse files
committed
AArch64: Relax x16/x17 constraint on AUT in certain cases.
On most operating systems, the x16 and x17 registers are not special, so there is no benefit, and only a code size cost, to constraining AUT to only using them. Therefore, adjust the backend to only use the AUT pseudo (renamed AUTx16x17 for clarity) on Darwin platforms, or if traps are requested. All other platforms use the unconstrained variant of the instruction for selection. Pull Request: llvm#132857
1 parent 64046e9 commit 43f3996

10 files changed

+306
-211
lines changed

llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp

+1-10
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,6 @@
6969

7070
using namespace llvm;
7171

72-
enum PtrauthCheckMode { Default, Unchecked, Poison, Trap };
73-
static cl::opt<PtrauthCheckMode> PtrauthAuthChecks(
74-
"aarch64-ptrauth-auth-checks", cl::Hidden,
75-
cl::values(clEnumValN(Unchecked, "none", "don't test for failure"),
76-
clEnumValN(Poison, "poison", "poison on failure"),
77-
clEnumValN(Trap, "trap", "trap on failure")),
78-
cl::desc("Check pointer authentication auth/resign failures"),
79-
cl::init(Default));
80-
8172
#define DEBUG_TYPE "asm-printer"
8273

8374
namespace {
@@ -2866,7 +2857,7 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) {
28662857
return;
28672858
}
28682859

2869-
case AArch64::AUT:
2860+
case AArch64::AUTx16x17:
28702861
case AArch64::AUTPAC:
28712862
emitPtrauthAuthResign(MI);
28722863
return;

llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp

+6-4
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ class AArch64DAGToDAGISel : public SelectionDAGISel {
361361

362362
bool tryIndexedLoad(SDNode *N);
363363

364-
void SelectPtrauthAuth(SDNode *N);
364+
void SelectPtrauthAuthX16X17(SDNode *N);
365365
void SelectPtrauthResign(SDNode *N);
366366

367367
bool trySelectStackSlotTagP(SDNode *N);
@@ -1521,7 +1521,7 @@ extractPtrauthBlendDiscriminators(SDValue Disc, SelectionDAG *DAG) {
15211521
AddrDisc);
15221522
}
15231523

1524-
void AArch64DAGToDAGISel::SelectPtrauthAuth(SDNode *N) {
1524+
void AArch64DAGToDAGISel::SelectPtrauthAuthX16X17(SDNode *N) {
15251525
SDLoc DL(N);
15261526
// IntrinsicID is operand #0
15271527
SDValue Val = N->getOperand(1);
@@ -1539,7 +1539,7 @@ void AArch64DAGToDAGISel::SelectPtrauthAuth(SDNode *N) {
15391539
AArch64::X16, Val, SDValue());
15401540
SDValue Ops[] = {AUTKey, AUTConstDisc, AUTAddrDisc, X16Copy.getValue(1)};
15411541

1542-
SDNode *AUT = CurDAG->getMachineNode(AArch64::AUT, DL, MVT::i64, Ops);
1542+
SDNode *AUT = CurDAG->getMachineNode(AArch64::AUTx16x17, DL, MVT::i64, Ops);
15431543
ReplaceNode(N, AUT);
15441544
}
15451545

@@ -5613,7 +5613,9 @@ void AArch64DAGToDAGISel::Select(SDNode *Node) {
56135613
return;
56145614

56155615
case Intrinsic::ptrauth_auth:
5616-
SelectPtrauthAuth(Node);
5616+
if (!Subtarget->isX16X17Safer(CurDAG->getMachineFunction()))
5617+
break;
5618+
SelectPtrauthAuthX16X17(Node);
56175619
return;
56185620

56195621
case Intrinsic::ptrauth_resign:

llvm/lib/Target/AArch64/AArch64InstrInfo.td

+18-7
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,14 @@ def HasLOR : Predicate<"Subtarget->hasLOR()">,
6666
def HasPAuth : Predicate<"Subtarget->hasPAuth()">,
6767
AssemblerPredicateWithAll<(all_of FeaturePAuth), "pauth">;
6868

69+
// On most operating systems, the x16 and x17 registers are not special, so
70+
// there is no benefit, and only a code size cost, to constraining PAC
71+
// instructions to only using them. This predicate may be used to guard patterns
72+
// that allow PAC instructions to be used with any register.
73+
let RecomputePerFunction = 1 in {
74+
def X16X17NotSafer : Predicate<"!Subtarget->isX16X17Safer(*MF)">;
75+
}
76+
6977
def HasPAuthLR : Predicate<"Subtarget->hasPAuthLR()">,
7078
AssemblerPredicateWithAll<(all_of FeaturePAuthLR), "pauth-lr">;
7179

@@ -1820,7 +1828,9 @@ let Predicates = [HasPAuth] in {
18201828
}
18211829

18221830
defm PAC : SignAuth<0b000, 0b010, "pac", int_ptrauth_sign>;
1823-
defm AUT : SignAuth<0b001, 0b011, "aut", null_frag>;
1831+
let Predicates = [HasPAuth, X16X17NotSafer] in {
1832+
defm AUT : SignAuth<0b001, 0b011, "aut", int_ptrauth_auth>;
1833+
}
18241834

18251835
def XPACI : ClearAuth<0, "xpaci">;
18261836
def : Pat<(int_ptrauth_strip GPR64:$Rd, 0), (XPACI GPR64:$Rd)>;
@@ -1912,10 +1922,11 @@ let Predicates = [HasPAuth] in {
19121922
defm LDRAB : AuthLoad<1, "ldrab", simm10Scaled>;
19131923

19141924
// AUT pseudo.
1915-
// This directly manipulates x16/x17, which are the only registers the OS
1916-
// guarantees are safe to use for sensitive operations.
1917-
def AUT : Pseudo<(outs), (ins i32imm:$Key, i64imm:$Disc, GPR64noip:$AddrDisc),
1918-
[]>, Sched<[WriteI, ReadI]> {
1925+
// This directly manipulates x16/x17, which are the only registers that
1926+
// certain OSs guarantee are safe to use for sensitive operations.
1927+
def AUTx16x17 : Pseudo<(outs), (ins i32imm:$Key, i64imm:$Disc,
1928+
GPR64noip:$AddrDisc),
1929+
[]>, Sched<[WriteI, ReadI]> {
19191930
let isCodeGenOnly = 1;
19201931
let hasSideEffects = 1;
19211932
let mayStore = 0;
@@ -1926,8 +1937,8 @@ let Predicates = [HasPAuth] in {
19261937
}
19271938

19281939
// AUT and re-PAC a value, using different keys/data.
1929-
// This directly manipulates x16/x17, which are the only registers the OS
1930-
// guarantees are safe to use for sensitive operations.
1940+
// This directly manipulates x16/x17, which are the only registers that
1941+
// certain OSs guarantee are safe to use for sensitive operations.
19311942
def AUTPAC
19321943
: Pseudo<(outs),
19331944
(ins i32imm:$AUTKey, i64imm:$AUTDisc, GPR64noip:$AUTAddrDisc,

llvm/lib/Target/AArch64/AArch64Subtarget.cpp

+23
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,16 @@ static cl::opt<bool>
102102
UseScalarIncVL("sve-use-scalar-inc-vl", cl::init(false), cl::Hidden,
103103
cl::desc("Prefer add+cnt over addvl/inc/dec"));
104104

105+
cl::opt<PtrauthCheckMode> llvm::PtrauthAuthChecks(
106+
"aarch64-ptrauth-auth-checks", cl::Hidden,
107+
cl::values(clEnumValN(PtrauthCheckMode::Unchecked, "none",
108+
"don't test for failure"),
109+
clEnumValN(PtrauthCheckMode::Poison, "poison",
110+
"poison on failure"),
111+
clEnumValN(PtrauthCheckMode::Trap, "trap", "trap on failure")),
112+
cl::desc("Check pointer authentication auth/resign failures"),
113+
cl::init(PtrauthCheckMode::Default));
114+
105115
unsigned AArch64Subtarget::getVectorInsertExtractBaseCost() const {
106116
if (OverrideVectorInsertExtractBaseCost.getNumOccurrences() > 0)
107117
return OverrideVectorInsertExtractBaseCost;
@@ -663,6 +673,19 @@ AArch64Subtarget::getPtrAuthBlockAddressDiscriminatorIfEnabled(
663673
(Twine(ParentFn.getName()) + " blockaddress").str());
664674
}
665675

676+
bool AArch64Subtarget::isX16X17Safer(const MachineFunction &MF) const {
677+
// The Darwin kernel implements special protections for x16 and x17 so we
678+
// should prefer to use those registers on that platform.
679+
if (isTargetDarwin())
680+
return true;
681+
// Traps are only implemented for the pseudo instructions, but are only
682+
// necessary if FEAT_FPAC is not implemented.
683+
if (hasFPAC())
684+
return false;
685+
return MF.getFunction().hasFnAttribute("ptrauth-auth-traps") ||
686+
PtrauthAuthChecks == PtrauthCheckMode::Trap;
687+
}
688+
666689
bool AArch64Subtarget::enableMachinePipeliner() const {
667690
return getSchedModel().hasInstrSchedModel();
668691
}

llvm/lib/Target/AArch64/AArch64Subtarget.h

+8
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "llvm/CodeGen/RegisterBankInfo.h"
2727
#include "llvm/CodeGen/TargetSubtargetInfo.h"
2828
#include "llvm/IR/DataLayout.h"
29+
#include "llvm/Support/CommandLine.h"
2930

3031
#define GET_SUBTARGETINFO_HEADER
3132
#include "AArch64GenSubtargetInfo.inc"
@@ -35,6 +36,9 @@ class GlobalValue;
3536
class StringRef;
3637
class Triple;
3738

39+
enum class PtrauthCheckMode { Default, Unchecked, Poison, Trap };
40+
extern cl::opt<PtrauthCheckMode> PtrauthAuthChecks;
41+
3842
class AArch64Subtarget final : public AArch64GenSubtargetInfo {
3943
public:
4044
enum ARMProcFamilyEnum : uint8_t {
@@ -318,6 +322,10 @@ class AArch64Subtarget final : public AArch64GenSubtargetInfo {
318322
}
319323
}
320324

325+
/// Returns whether the operating system makes it safer to store sensitive
326+
/// values in x16 and x17 as opposed to other registers.
327+
bool isX16X17Safer(const MachineFunction &MF) const;
328+
321329
/// ParseSubtargetFeatures - Parses features string setting specified
322330
/// subtarget options. Definition of function is auto generated by tblgen.
323331
void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS);

llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -6735,7 +6735,7 @@ bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &I,
67356735

67366736
MIB.buildCopy({AArch64::X16}, {ValReg});
67376737
MIB.buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6738-
MIB.buildInstr(AArch64::AUT)
6738+
MIB.buildInstr(AArch64::AUTx16x17)
67396739
.addImm(AUTKey)
67406740
.addImm(AUTConstDiscC)
67416741
.addUse(AUTAddrDisc)

llvm/test/CodeGen/AArch64/ptrauth-call.ll

+37-16
Original file line numberDiff line numberDiff line change
@@ -169,13 +169,23 @@ define i32 @test_tailcall_ib_var(ptr %arg0, ptr %arg1) #0 {
169169

170170
define void @test_tailcall_omit_mov_x16_x16(ptr %objptr) #0 {
171171
; CHECK-LABEL: test_tailcall_omit_mov_x16_x16:
172-
; CHECK-NEXT: ldr x16, [x0]
173-
; CHECK-NEXT: mov x17, x0
174-
; CHECK-NEXT: movk x17, #6503, lsl #48
175-
; CHECK-NEXT: autda x16, x17
176-
; CHECK-NEXT: ldr x1, [x16]
177-
; CHECK-NEXT: movk x16, #54167, lsl #48
178-
; CHECK-NEXT: braa x1, x16
172+
; DARWIN-NEXT: ldr x16, [x0]
173+
; DARWIN-NEXT: mov x17, x0
174+
; DARWIN-NEXT: movk x17, #6503, lsl #48
175+
; DARWIN-NEXT: autda x16, x17
176+
; DARWIN-NEXT: ldr x1, [x16]
177+
; DARWIN-NEXT: movk x16, #54167, lsl #48
178+
; DARWIN-NEXT: braa x1, x16
179+
; ELF-NEXT: ldr x1, [x0]
180+
; ELF-NEXT: mov x8, x0
181+
; ELF-NEXT: movk x8, #6503, lsl #48
182+
; ELF-NEXT: autda x1, x8
183+
; ELF-NEXT: ldr x2, [x1]
184+
; FIXME: Get rid of the x16/x17 constraint on non-Darwin so we can eliminate
185+
; this mov.
186+
; ELF-NEXT: mov x16, x1
187+
; ELF-NEXT: movk x16, #54167, lsl #48
188+
; ELF-NEXT: braa x2, x16
179189
%vtable.signed = load ptr, ptr %objptr, align 8
180190
%objptr.int = ptrtoint ptr %objptr to i64
181191
%vtable.discr = tail call i64 @llvm.ptrauth.blend(i64 %objptr.int, i64 6503)
@@ -191,16 +201,27 @@ define void @test_tailcall_omit_mov_x16_x16(ptr %objptr) #0 {
191201
define i32 @test_call_omit_extra_moves(ptr %objptr) #0 {
192202
; CHECK-LABEL: test_call_omit_extra_moves:
193203
; DARWIN-NEXT: stp x29, x30, [sp, #-16]!
194-
; ELF-NEXT: str x30, [sp, #-16]!
195-
; CHECK-NEXT: ldr x16, [x0]
196-
; CHECK-NEXT: mov x17, x0
197-
; CHECK-NEXT: movk x17, #6503, lsl #48
198-
; CHECK-NEXT: autda x16, x17
199-
; CHECK-NEXT: ldr x8, [x16]
200-
; CHECK-NEXT: movk x16, #34646, lsl #48
201-
; CHECK-NEXT: blraa x8, x16
202-
; CHECK-NEXT: mov w0, #42
204+
; DARWIN-NEXT: ldr x16, [x0]
205+
; DARWIN-NEXT: mov x17, x0
206+
; DARWIN-NEXT: movk x17, #6503, lsl #48
207+
; DARWIN-NEXT: autda x16, x17
208+
; DARWIN-NEXT: ldr x8, [x16]
209+
; DARWIN-NEXT: movk x16, #34646, lsl #48
210+
; DARWIN-NEXT: blraa x8, x16
211+
; DARWIN-NEXT: mov w0, #42
203212
; DARWIN-NEXT: ldp x29, x30, [sp], #16
213+
; ELF-NEXT: str x30, [sp, #-16]!
214+
; ELF-NEXT: ldr x8, [x0]
215+
; ELF-NEXT: mov x9, x0
216+
; ELF-NEXT: movk x9, #6503, lsl #48
217+
; ELF-NEXT: autda x8, x9
218+
; ELF-NEXT: ldr x9, [x8]
219+
; FIXME: Get rid of the x16/x17 constraint on non-Darwin so we can eliminate
220+
; this mov.
221+
; ELF-NEXT: mov x17, x8
222+
; ELF-NEXT: movk x17, #34646, lsl #48
223+
; ELF-NEXT: blraa x9, x17
224+
; ELF-NEXT: mov w0, #42
204225
; ELF-NEXT: ldr x30, [sp], #16
205226
; CHECK-NEXT: ret
206227
%vtable.signed = load ptr, ptr %objptr

0 commit comments

Comments
 (0)