@@ -163,8 +163,15 @@ class AArch64AsmPrinter : public AsmPrinter {
163163 // Emit the sequence for AUT or AUTPAC.
164164 void emitPtrauthAuthResign (const MachineInstr *MI);
165165
166- // Emit the sequence to compute a discriminator into x17, or reuse AddrDisc.
167- unsigned emitPtrauthDiscriminator (uint16_t Disc, unsigned AddrDisc);
166+ // Emit the sequence to compute the discriminator.
167+ // ScratchReg should be x16/x17.
168+ // The returned register is either unmodified AddrDisc or x16/x17.
169+ // If the expanded pseudo is allowed to clobber AddrDisc register, setting
170+ // MayUseAddrAsScratch may save one MOV instruction, provided the address
171+ // is already in x16/x17.
172+ Register emitPtrauthDiscriminator (uint16_t Disc, Register AddrDisc,
173+ Register ScratchReg,
174+ bool MayUseAddrAsScratch = false );
168175
169176 // Emit the sequence for LOADauthptrstatic
170177 void LowerLOADauthptrstatic (const MachineInstr &MI);
@@ -1727,8 +1734,10 @@ void AArch64AsmPrinter::emitFMov0(const MachineInstr &MI) {
17271734 }
17281735}
17291736
1730- unsigned AArch64AsmPrinter::emitPtrauthDiscriminator (uint16_t Disc,
1731- unsigned AddrDisc) {
1737+ Register AArch64AsmPrinter::emitPtrauthDiscriminator (uint16_t Disc,
1738+ Register AddrDisc,
1739+ Register ScratchReg,
1740+ bool MayUseAddrAsScratch) {
17321741 // So far we've used NoRegister in pseudos. Now we need real encodings.
17331742 if (AddrDisc == AArch64::NoRegister)
17341743 AddrDisc = AArch64::XZR;
@@ -1738,16 +1747,24 @@ unsigned AArch64AsmPrinter::emitPtrauthDiscriminator(uint16_t Disc,
17381747 if (!Disc)
17391748 return AddrDisc;
17401749
1741- // If there's only a constant discriminator, MOV it into x17 .
1750+ // If there's only a constant discriminator, MOV it into the scratch register .
17421751 if (AddrDisc == AArch64::XZR) {
1743- emitMOVZ (AArch64::X17 , Disc, 0 );
1744- return AArch64::X17 ;
1752+ emitMOVZ (ScratchReg , Disc, 0 );
1753+ return ScratchReg ;
17451754 }
17461755
1747- // If there are both, emit a blend into x17.
1748- emitMovXReg (AArch64::X17, AddrDisc);
1749- emitMOVK (AArch64::X17, Disc, 48 );
1750- return AArch64::X17;
1756+ // If there are both, emit a blend into the scratch register.
1757+
1758+ // Check if we can save one MOV instruction.
1759+ assert (MayUseAddrAsScratch || ScratchReg != AddrDisc);
1760+ bool AddrDiscIsSafe = AddrDisc == AArch64::X16 || AddrDisc == AArch64::X17;
1761+ if (MayUseAddrAsScratch && AddrDiscIsSafe)
1762+ ScratchReg = AddrDisc;
1763+ else
1764+ emitMovXReg (ScratchReg, AddrDisc);
1765+
1766+ emitMOVK (ScratchReg, Disc, 48 );
1767+ return ScratchReg;
17511768}
17521769
17531770// / Emits a code sequence to check an authenticated pointer value.
@@ -1964,7 +1981,8 @@ void AArch64AsmPrinter::emitPtrauthAuthResign(const MachineInstr *MI) {
19641981
19651982 // Compute aut discriminator into x17
19661983 assert (isUInt<16 >(AUTDisc));
1967- unsigned AUTDiscReg = emitPtrauthDiscriminator (AUTDisc, AUTAddrDisc);
1984+ Register AUTDiscReg =
1985+ emitPtrauthDiscriminator (AUTDisc, AUTAddrDisc, AArch64::X17);
19681986 bool AUTZero = AUTDiscReg == AArch64::XZR;
19691987 unsigned AUTOpc = getAUTOpcodeForKey (AUTKey, AUTZero);
19701988
@@ -2005,7 +2023,8 @@ void AArch64AsmPrinter::emitPtrauthAuthResign(const MachineInstr *MI) {
20052023
20062024 // Compute pac discriminator into x17
20072025 assert (isUInt<16 >(PACDisc));
2008- unsigned PACDiscReg = emitPtrauthDiscriminator (PACDisc, PACAddrDisc);
2026+ Register PACDiscReg =
2027+ emitPtrauthDiscriminator (PACDisc, PACAddrDisc, AArch64::X17);
20092028 bool PACZero = PACDiscReg == AArch64::XZR;
20102029 unsigned PACOpc = getPACOpcodeForKey (PACKey, PACZero);
20112030
@@ -2037,8 +2056,17 @@ void AArch64AsmPrinter::emitPtrauthBranch(const MachineInstr *MI) {
20372056
20382057 unsigned AddrDisc = MI->getOperand (3 ).getReg ();
20392058
2040- // Compute discriminator into x17
2041- unsigned DiscReg = emitPtrauthDiscriminator (Disc, AddrDisc);
2059+ // Make sure AddrDisc is solely used to compute the discriminator.
2060+ // While hardly meaningful, it is still possible to describe an authentication
2061+ // of a pointer against its own value (instead of storage address) with
2062+ // intrinsics, so use report_fatal_error instead of assert.
2063+ if (BrTarget == AddrDisc)
2064+ report_fatal_error (" Branch target is signed with its own value" );
2065+
2066+ // x16 and x17 are implicit-def'ed by MI, and AddrDisc is not used as any
2067+ // other input, so try to save one MOV by setting MayUseAddrAsScratch.
2068+ Register DiscReg = emitPtrauthDiscriminator (Disc, AddrDisc, AArch64::X17,
2069+ /* MayUseAddrAsScratch=*/ true );
20422070 bool IsZeroDisc = DiscReg == AArch64::XZR;
20432071
20442072 unsigned Opc;
@@ -2332,16 +2360,7 @@ void AArch64AsmPrinter::LowerMOVaddrPAC(const MachineInstr &MI) {
23322360 }
23332361 }
23342362
2335- unsigned DiscReg = AddrDisc;
2336- if (Disc != 0 ) {
2337- if (AddrDisc != AArch64::XZR) {
2338- emitMovXReg (AArch64::X17, AddrDisc);
2339- emitMOVK (AArch64::X17, Disc, 48 );
2340- } else {
2341- emitMOVZ (AArch64::X17, Disc, 0 );
2342- }
2343- DiscReg = AArch64::X17;
2344- }
2363+ Register DiscReg = emitPtrauthDiscriminator (Disc, AddrDisc, AArch64::X17);
23452364
23462365 auto MIB = MCInstBuilder (getPACOpcodeForKey (Key, DiscReg == AArch64::XZR))
23472366 .addReg (AArch64::X16)
@@ -2609,6 +2628,7 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) {
26092628 // instruction here.
26102629 case AArch64::AUTH_TCRETURN:
26112630 case AArch64::AUTH_TCRETURN_BTI: {
2631+ Register Callee = MI->getOperand (0 ).getReg ();
26122632 const uint64_t Key = MI->getOperand (2 ).getImm ();
26132633 assert ((Key == AArch64PACKey::IA || Key == AArch64PACKey::IB) &&
26142634 " Invalid auth key for tail-call return" );
@@ -2618,31 +2638,23 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) {
26182638
26192639 Register AddrDisc = MI->getOperand (4 ).getReg ();
26202640
2621- Register ScratchReg = MI->getOperand (0 ).getReg () == AArch64::X16
2622- ? AArch64::X17
2623- : AArch64::X16;
2641+ Register ScratchReg = Callee == AArch64::X16 ? AArch64::X17 : AArch64::X16;
26242642
26252643 emitPtrauthTailCallHardening (MI);
26262644
2627- unsigned DiscReg = AddrDisc;
2628- if (Disc) {
2629- if (AddrDisc != AArch64::NoRegister) {
2630- if (ScratchReg != AddrDisc)
2631- emitMovXReg (ScratchReg, AddrDisc);
2632- emitMOVK (ScratchReg, Disc, 48 );
2633- } else {
2634- emitMOVZ (ScratchReg, Disc, 0 );
2635- }
2636- DiscReg = ScratchReg;
2637- }
2645+ // See the comments in emitPtrauthBranch.
2646+ if (Callee == AddrDisc)
2647+ report_fatal_error (" Call target is signed with its own value" );
2648+ Register DiscReg = emitPtrauthDiscriminator (Disc, AddrDisc, ScratchReg,
2649+ /* MayUseAddrAsScratch=*/ true );
26382650
2639- const bool IsZero = DiscReg == AArch64::NoRegister ;
2651+ const bool IsZero = DiscReg == AArch64::XZR ;
26402652 const unsigned Opcodes[2 ][2 ] = {{AArch64::BRAA, AArch64::BRAAZ},
26412653 {AArch64::BRAB, AArch64::BRABZ}};
26422654
26432655 MCInst TmpInst;
26442656 TmpInst.setOpcode (Opcodes[Key][IsZero]);
2645- TmpInst.addOperand (MCOperand::createReg (MI-> getOperand ( 0 ). getReg () ));
2657+ TmpInst.addOperand (MCOperand::createReg (Callee ));
26462658 if (!IsZero)
26472659 TmpInst.addOperand (MCOperand::createReg (DiscReg));
26482660 EmitToStreamer (*OutStreamer, TmpInst);
0 commit comments