@@ -162,8 +162,27 @@ class AArch64AsmPrinter : public AsmPrinter {
162
162
// Emit the sequence for AUT or AUTPAC.
163
163
void emitPtrauthAuthResign (const MachineInstr *MI);
164
164
165
- // Emit the sequence to compute a discriminator into x17, or reuse AddrDisc.
166
- unsigned emitPtrauthDiscriminator (uint16_t Disc, unsigned AddrDisc);
165
+ // Emit the sequence to compute the discriminator.
166
+ //
167
+ // ScratchReg should be x16/x17.
168
+ //
169
+ // The returned register is either unmodified AddrDisc or x16/x17.
170
+ //
171
+ // If the expanded pseudo is allowed to clobber AddrDisc register, setting
172
+ // MayUseAddrAsScratch may save one MOV instruction, provided the address
173
+ // is already in x16/x17 (i.e. return x16/x17 which is the *modified* AddrDisc
174
+ // register at the same time):
175
+ //
176
+ // mov x17, x16
177
+ // movk x17, #1234, lsl #48
178
+ // ; x16 is not used anymore
179
+ //
180
+ // can be replaced by
181
+ //
182
+ // movk x16, #1234, lsl #48
183
+ Register emitPtrauthDiscriminator (uint16_t Disc, Register AddrDisc,
184
+ Register ScratchReg,
185
+ bool MayUseAddrAsScratch = false );
167
186
168
187
// Emit the sequence for LOADauthptrstatic
169
188
void LowerLOADauthptrstatic (const MachineInstr &MI);
@@ -1726,8 +1745,11 @@ void AArch64AsmPrinter::emitFMov0(const MachineInstr &MI) {
1726
1745
}
1727
1746
}
1728
1747
1729
- unsigned AArch64AsmPrinter::emitPtrauthDiscriminator (uint16_t Disc,
1730
- unsigned AddrDisc) {
1748
+ Register AArch64AsmPrinter::emitPtrauthDiscriminator (uint16_t Disc,
1749
+ Register AddrDisc,
1750
+ Register ScratchReg,
1751
+ bool MayUseAddrAsScratch) {
1752
+ assert (ScratchReg == AArch64::X16 || ScratchReg == AArch64::X17);
1731
1753
// So far we've used NoRegister in pseudos. Now we need real encodings.
1732
1754
if (AddrDisc == AArch64::NoRegister)
1733
1755
AddrDisc = AArch64::XZR;
@@ -1737,16 +1759,24 @@ unsigned AArch64AsmPrinter::emitPtrauthDiscriminator(uint16_t Disc,
1737
1759
if (!Disc)
1738
1760
return AddrDisc;
1739
1761
1740
- // If there's only a constant discriminator, MOV it into x17 .
1762
+ // If there's only a constant discriminator, MOV it into the scratch register .
1741
1763
if (AddrDisc == AArch64::XZR) {
1742
- emitMOVZ (AArch64::X17 , Disc, 0 );
1743
- return AArch64::X17 ;
1764
+ emitMOVZ (ScratchReg , Disc, 0 );
1765
+ return ScratchReg ;
1744
1766
}
1745
1767
1746
- // If there are both, emit a blend into x17.
1747
- emitMovXReg (AArch64::X17, AddrDisc);
1748
- emitMOVK (AArch64::X17, Disc, 48 );
1749
- return AArch64::X17;
1768
+ // If there are both, emit a blend into the scratch register.
1769
+
1770
+ // Check if we can save one MOV instruction.
1771
+ assert (MayUseAddrAsScratch || ScratchReg != AddrDisc);
1772
+ bool AddrDiscIsSafe = AddrDisc == AArch64::X16 || AddrDisc == AArch64::X17;
1773
+ if (MayUseAddrAsScratch && AddrDiscIsSafe)
1774
+ ScratchReg = AddrDisc;
1775
+ else
1776
+ emitMovXReg (ScratchReg, AddrDisc);
1777
+
1778
+ emitMOVK (ScratchReg, Disc, 48 );
1779
+ return ScratchReg;
1750
1780
}
1751
1781
1752
1782
// / Emits a code sequence to check an authenticated pointer value.
@@ -1963,7 +1993,8 @@ void AArch64AsmPrinter::emitPtrauthAuthResign(const MachineInstr *MI) {
1963
1993
1964
1994
// Compute aut discriminator into x17
1965
1995
assert (isUInt<16 >(AUTDisc));
1966
- unsigned AUTDiscReg = emitPtrauthDiscriminator (AUTDisc, AUTAddrDisc);
1996
+ Register AUTDiscReg =
1997
+ emitPtrauthDiscriminator (AUTDisc, AUTAddrDisc, AArch64::X17);
1967
1998
bool AUTZero = AUTDiscReg == AArch64::XZR;
1968
1999
unsigned AUTOpc = getAUTOpcodeForKey (AUTKey, AUTZero);
1969
2000
@@ -2004,7 +2035,8 @@ void AArch64AsmPrinter::emitPtrauthAuthResign(const MachineInstr *MI) {
2004
2035
2005
2036
// Compute pac discriminator into x17
2006
2037
assert (isUInt<16 >(PACDisc));
2007
- unsigned PACDiscReg = emitPtrauthDiscriminator (PACDisc, PACAddrDisc);
2038
+ Register PACDiscReg =
2039
+ emitPtrauthDiscriminator (PACDisc, PACAddrDisc, AArch64::X17);
2008
2040
bool PACZero = PACDiscReg == AArch64::XZR;
2009
2041
unsigned PACOpc = getPACOpcodeForKey (PACKey, PACZero);
2010
2042
@@ -2036,8 +2068,20 @@ void AArch64AsmPrinter::emitPtrauthBranch(const MachineInstr *MI) {
2036
2068
2037
2069
unsigned AddrDisc = MI->getOperand (3 ).getReg ();
2038
2070
2039
- // Compute discriminator into x17
2040
- unsigned DiscReg = emitPtrauthDiscriminator (Disc, AddrDisc);
2071
+ // Make sure AddrDisc is solely used to compute the discriminator.
2072
+ // While hardly meaningful, it is still possible to describe an authentication
2073
+ // of a pointer against its own value (instead of storage address) with
2074
+ // intrinsics, so use report_fatal_error instead of assert.
2075
+ if (BrTarget == AddrDisc)
2076
+ report_fatal_error (" Branch target is signed with its own value" );
2077
+
2078
+ // If we are printing BLRA pseudo instruction, then x16 and x17 are
2079
+ // implicit-def'ed by the MI and AddrDisc is not used as any other input, so
2080
+ // try to save one MOV by setting MayUseAddrAsScratch.
2081
+ // Unlike BLRA, BRA pseudo is used to perform computed goto, and thus not
2082
+ // declared as clobbering x16/x17.
2083
+ Register DiscReg = emitPtrauthDiscriminator (Disc, AddrDisc, AArch64::X17,
2084
+ /* MayUseAddrAsScratch=*/ IsCall);
2041
2085
bool IsZeroDisc = DiscReg == AArch64::XZR;
2042
2086
2043
2087
unsigned Opc;
@@ -2331,16 +2375,7 @@ void AArch64AsmPrinter::LowerMOVaddrPAC(const MachineInstr &MI) {
2331
2375
}
2332
2376
}
2333
2377
2334
- unsigned DiscReg = AddrDisc;
2335
- if (Disc != 0 ) {
2336
- if (AddrDisc != AArch64::XZR) {
2337
- emitMovXReg (AArch64::X17, AddrDisc);
2338
- emitMOVK (AArch64::X17, Disc, 48 );
2339
- } else {
2340
- emitMOVZ (AArch64::X17, Disc, 0 );
2341
- }
2342
- DiscReg = AArch64::X17;
2343
- }
2378
+ Register DiscReg = emitPtrauthDiscriminator (Disc, AddrDisc, AArch64::X17);
2344
2379
2345
2380
auto MIB = MCInstBuilder (getPACOpcodeForKey (Key, DiscReg == AArch64::XZR))
2346
2381
.addReg (AArch64::X16)
@@ -2608,6 +2643,7 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) {
2608
2643
// instruction here.
2609
2644
case AArch64::AUTH_TCRETURN:
2610
2645
case AArch64::AUTH_TCRETURN_BTI: {
2646
+ Register Callee = MI->getOperand (0 ).getReg ();
2611
2647
const uint64_t Key = MI->getOperand (2 ).getImm ();
2612
2648
assert ((Key == AArch64PACKey::IA || Key == AArch64PACKey::IB) &&
2613
2649
" Invalid auth key for tail-call return" );
@@ -2617,31 +2653,23 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) {
2617
2653
2618
2654
Register AddrDisc = MI->getOperand (4 ).getReg ();
2619
2655
2620
- Register ScratchReg = MI->getOperand (0 ).getReg () == AArch64::X16
2621
- ? AArch64::X17
2622
- : AArch64::X16;
2656
+ Register ScratchReg = Callee == AArch64::X16 ? AArch64::X17 : AArch64::X16;
2623
2657
2624
2658
emitPtrauthTailCallHardening (MI);
2625
2659
2626
- unsigned DiscReg = AddrDisc;
2627
- if (Disc) {
2628
- if (AddrDisc != AArch64::NoRegister) {
2629
- if (ScratchReg != AddrDisc)
2630
- emitMovXReg (ScratchReg, AddrDisc);
2631
- emitMOVK (ScratchReg, Disc, 48 );
2632
- } else {
2633
- emitMOVZ (ScratchReg, Disc, 0 );
2634
- }
2635
- DiscReg = ScratchReg;
2636
- }
2660
+ // See the comments in emitPtrauthBranch.
2661
+ if (Callee == AddrDisc)
2662
+ report_fatal_error (" Call target is signed with its own value" );
2663
+ Register DiscReg = emitPtrauthDiscriminator (Disc, AddrDisc, ScratchReg,
2664
+ /* MayUseAddrAsScratch=*/ true );
2637
2665
2638
- const bool IsZero = DiscReg == AArch64::NoRegister ;
2666
+ const bool IsZero = DiscReg == AArch64::XZR ;
2639
2667
const unsigned Opcodes[2 ][2 ] = {{AArch64::BRAA, AArch64::BRAAZ},
2640
2668
{AArch64::BRAB, AArch64::BRABZ}};
2641
2669
2642
2670
MCInst TmpInst;
2643
2671
TmpInst.setOpcode (Opcodes[Key][IsZero]);
2644
- TmpInst.addOperand (MCOperand::createReg (MI-> getOperand ( 0 ). getReg () ));
2672
+ TmpInst.addOperand (MCOperand::createReg (Callee ));
2645
2673
if (!IsZero)
2646
2674
TmpInst.addOperand (MCOperand::createReg (DiscReg));
2647
2675
EmitToStreamer (*OutStreamer, TmpInst);
0 commit comments