@@ -199,6 +199,11 @@ SpillArea getSpillArea(Register Reg,
199
199
// push {r0-r10, r12} GPRCS1
200
200
// vpush {r8-d15} DPRCS1
201
201
// push {r11, lr} GPRCS2
202
+ //
203
+ // SplitR11AAPCSSignRA:
204
+ // push {r0-r10, r12} GPRSC1
205
+ // push {r11, lr} GPRCS2
206
+ // vpush {r8-d15} DPRCS1
202
207
203
208
// If FPCXTNS is spilled (for CMSE secure entryfunctions), it is always at
204
209
// the top of the stack frame.
@@ -246,7 +251,8 @@ SpillArea getSpillArea(Register Reg,
246
251
return SpillArea::GPRCS1;
247
252
248
253
case ARM::LR:
249
- if (Variation == ARMSubtarget::SplitR11WindowsSEH)
254
+ if (Variation == ARMSubtarget::SplitR11WindowsSEH ||
255
+ Variation == ARMSubtarget::SplitR11AAPCSSignRA)
250
256
return SpillArea::GPRCS2;
251
257
else
252
258
return SpillArea::GPRCS1;
@@ -859,6 +865,9 @@ static int getMaxFPOffset(const ARMSubtarget &STI, const ARMFunctionInfo &AFI,
859
865
// This is a conservative estimation: Assume the frame pointer being r7 and
860
866
// pc("r15") up to r8 getting spilled before (= 8 registers).
861
867
int MaxRegBytes = 8 * 4 ;
868
+ if (PushPopSplit == ARMSubtarget::SplitR11AAPCSSignRA)
869
+ // Here, r11 can be stored below all of r4-r15.
870
+ MaxRegBytes = 11 * 4 ;
862
871
if (PushPopSplit == ARMSubtarget::SplitR11WindowsSEH) {
863
872
// Here, r11 can be stored below all of r4-r15 plus d8-d15.
864
873
MaxRegBytes = 11 * 4 + 8 * 8 ;
@@ -931,17 +940,23 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
931
940
}
932
941
933
942
// Determine spill area sizes, and some important frame indices.
943
+ SpillArea FramePtrSpillArea;
944
+ bool BeforeFPPush = true ;
934
945
for (const CalleeSavedInfo &I : CSI) {
935
946
Register Reg = I.getReg ();
936
947
int FI = I.getFrameIdx ();
937
948
938
- if (Reg == FramePtr)
949
+ SpillArea Area = getSpillArea (Reg, PushPopSplit,
950
+ AFI->getNumAlignedDPRCS2Regs (), RegInfo);
951
+
952
+ if (Reg == FramePtr) {
939
953
FramePtrSpillFI = FI;
954
+ FramePtrSpillArea = Area;
955
+ }
940
956
if (Reg == ARM::D8)
941
957
D8SpillFI = FI;
942
958
943
- switch (getSpillArea (Reg, PushPopSplit, AFI->getNumAlignedDPRCS2Regs (),
944
- RegInfo)) {
959
+ switch (Area) {
945
960
case SpillArea::FPCXT:
946
961
FPCXTSaveSize += 4 ;
947
962
break ;
@@ -968,21 +983,23 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
968
983
// Move past FPCXT area.
969
984
if (FPCXTSaveSize > 0 ) {
970
985
LastPush = MBBI++;
971
- DefCFAOffsetCandidates.addInst (LastPush, FPCXTSaveSize, true );
986
+ DefCFAOffsetCandidates.addInst (LastPush, FPCXTSaveSize, BeforeFPPush );
972
987
}
973
988
974
989
// Allocate the vararg register save area.
975
990
if (ArgRegsSaveSize) {
976
991
emitSPUpdate (isARM, MBB, MBBI, dl, TII, -ArgRegsSaveSize,
977
992
MachineInstr::FrameSetup);
978
993
LastPush = std::prev (MBBI);
979
- DefCFAOffsetCandidates.addInst (LastPush, ArgRegsSaveSize, true );
994
+ DefCFAOffsetCandidates.addInst (LastPush, ArgRegsSaveSize, BeforeFPPush );
980
995
}
981
996
982
997
// Move past area 1.
983
998
if (GPRCS1Size > 0 ) {
984
999
GPRCS1Push = LastPush = MBBI++;
985
- DefCFAOffsetCandidates.addInst (LastPush, GPRCS1Size, true );
1000
+ DefCFAOffsetCandidates.addInst (LastPush, GPRCS1Size, BeforeFPPush);
1001
+ if (FramePtrSpillArea == SpillArea::GPRCS1)
1002
+ BeforeFPPush = false ;
986
1003
}
987
1004
988
1005
// Determine starting offsets of spill areas. These offsets are all positive
@@ -1006,21 +1023,13 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
1006
1023
} else {
1007
1024
DPRCSOffset = GPRCS2Offset - DPRGapSize - DPRCSSize;
1008
1025
}
1009
- int FramePtrOffsetInPush = 0 ;
1010
1026
if (HasFP) {
1011
1027
// Offset from the CFA to the saved frame pointer, will be negative.
1012
1028
int FPOffset = MFI.getObjectOffset (FramePtrSpillFI);
1013
1029
LLVM_DEBUG (dbgs () << " FramePtrSpillFI: " << FramePtrSpillFI
1014
1030
<< " , FPOffset: " << FPOffset << " \n " );
1015
1031
assert (getMaxFPOffset (STI, *AFI, MF) <= FPOffset &&
1016
1032
" Max FP estimation is wrong" );
1017
- // Offset from the top of the GPRCS1 area to the saved frame pointer, will
1018
- // be negative.
1019
- FramePtrOffsetInPush = FPOffset + ArgRegsSaveSize + FPCXTSaveSize;
1020
- LLVM_DEBUG (dbgs () << " FramePtrOffsetInPush=" << FramePtrOffsetInPush
1021
- << " , FramePtrSpillOffset="
1022
- << (MFI.getObjectOffset (FramePtrSpillFI) + NumBytes)
1023
- << " \n " );
1024
1033
AFI->setFramePtrSpillOffset (MFI.getObjectOffset (FramePtrSpillFI) +
1025
1034
NumBytes);
1026
1035
}
@@ -1032,7 +1041,9 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
1032
1041
// after DPRCS1.
1033
1042
if (GPRCS2Size > 0 && PushPopSplit != ARMSubtarget::SplitR11WindowsSEH) {
1034
1043
GPRCS2Push = LastPush = MBBI++;
1035
- DefCFAOffsetCandidates.addInst (LastPush, GPRCS2Size);
1044
+ DefCFAOffsetCandidates.addInst (LastPush, GPRCS2Size, BeforeFPPush);
1045
+ if (FramePtrSpillArea == SpillArea::GPRCS2)
1046
+ BeforeFPPush = false ;
1036
1047
}
1037
1048
1038
1049
// Prolog/epilog inserter assumes we correctly align DPRs on the stack, so our
@@ -1045,7 +1056,7 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
1045
1056
else {
1046
1057
emitSPUpdate (isARM, MBB, MBBI, dl, TII, -DPRGapSize,
1047
1058
MachineInstr::FrameSetup);
1048
- DefCFAOffsetCandidates.addInst (std::prev (MBBI), DPRGapSize);
1059
+ DefCFAOffsetCandidates.addInst (std::prev (MBBI), DPRGapSize, BeforeFPPush );
1049
1060
}
1050
1061
}
1051
1062
@@ -1054,7 +1065,8 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
1054
1065
// Since vpush register list cannot have gaps, there may be multiple vpush
1055
1066
// instructions in the prologue.
1056
1067
while (MBBI != MBB.end () && MBBI->getOpcode () == ARM::VSTMDDB_UPD) {
1057
- DefCFAOffsetCandidates.addInst (MBBI, sizeOfSPAdjustment (*MBBI));
1068
+ DefCFAOffsetCandidates.addInst (MBBI, sizeOfSPAdjustment (*MBBI),
1069
+ BeforeFPPush);
1058
1070
LastPush = MBBI++;
1059
1071
}
1060
1072
}
@@ -1073,7 +1085,9 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
1073
1085
// Move GPRCS2, if using using SplitR11WindowsSEH.
1074
1086
if (GPRCS2Size > 0 && PushPopSplit == ARMSubtarget::SplitR11WindowsSEH) {
1075
1087
GPRCS2Push = LastPush = MBBI++;
1076
- DefCFAOffsetCandidates.addInst (LastPush, GPRCS2Size);
1088
+ DefCFAOffsetCandidates.addInst (LastPush, GPRCS2Size, BeforeFPPush);
1089
+ if (FramePtrSpillArea == SpillArea::GPRCS2)
1090
+ BeforeFPPush = false ;
1077
1091
}
1078
1092
1079
1093
bool NeedsWinCFIStackAlloc = NeedsWinCFI;
@@ -1174,28 +1188,51 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
1174
1188
// into spill area 1, including the FP in R11. In either case, it
1175
1189
// is in area one and the adjustment needs to take place just after
1176
1190
// that push.
1177
- // FIXME: The above is not necessary true when PACBTI is enabled.
1178
- // AAPCS requires use of R11, and PACBTI gets in the way of regular pushes,
1179
- // so FP ends up on area two.
1180
1191
MachineBasicBlock::iterator AfterPush;
1181
1192
if (HasFP) {
1182
- AfterPush = std::next (GPRCS1Push);
1183
- unsigned PushSize = sizeOfSPAdjustment (*GPRCS1Push);
1184
- int FPOffset = PushSize + FramePtrOffsetInPush;
1185
- if (PushPopSplit == ARMSubtarget::SplitR11WindowsSEH) {
1186
- AfterPush = std::next (GPRCS2Push);
1187
- emitRegPlusImmediate (!AFI->isThumbFunction (), MBB, AfterPush, dl, TII,
1188
- FramePtr, ARM::SP, 0 , MachineInstr::FrameSetup);
1189
- } else {
1190
- emitRegPlusImmediate (!AFI->isThumbFunction (), MBB, AfterPush, dl, TII,
1191
- FramePtr, ARM::SP, FPOffset,
1192
- MachineInstr::FrameSetup);
1193
+ MachineBasicBlock::iterator FPPushInst;
1194
+ // Offset from SP immediately after the push which saved the FP to the FP
1195
+ // save slot.
1196
+ int64_t FPOffsetAfterPush;
1197
+ switch (FramePtrSpillArea) {
1198
+ case SpillArea::GPRCS1:
1199
+ FPPushInst = GPRCS1Push;
1200
+ FPOffsetAfterPush = MFI.getObjectOffset (FramePtrSpillFI) +
1201
+ ArgRegsSaveSize + FPCXTSaveSize +
1202
+ sizeOfSPAdjustment (*FPPushInst);
1203
+ LLVM_DEBUG (dbgs () << " Frame pointer in GPRCS1, offset "
1204
+ << FPOffsetAfterPush << " after that push\n " );
1205
+ break ;
1206
+ case SpillArea::GPRCS2:
1207
+ FPPushInst = GPRCS2Push;
1208
+ FPOffsetAfterPush = MFI.getObjectOffset (FramePtrSpillFI) +
1209
+ ArgRegsSaveSize + FPCXTSaveSize + GPRCS1Size +
1210
+ sizeOfSPAdjustment (*FPPushInst);
1211
+ if (PushPopSplit == ARMSubtarget::SplitR11WindowsSEH)
1212
+ FPOffsetAfterPush += DPRCSSize + DPRGapSize;
1213
+ LLVM_DEBUG (dbgs () << " Frame pointer in GPRCS2, offset "
1214
+ << FPOffsetAfterPush << " after that push\n " );
1215
+ break ;
1216
+ default :
1217
+ llvm_unreachable (" frame pointer in unknown spill area" );
1218
+ break ;
1193
1219
}
1220
+ AfterPush = std::next (FPPushInst);
1221
+ if (PushPopSplit == ARMSubtarget::SplitR11WindowsSEH)
1222
+ assert (FPOffsetAfterPush == 0 );
1223
+
1224
+ // Emit the MOV or ADD to set up the frame pointer register.
1225
+ emitRegPlusImmediate (!AFI->isThumbFunction (), MBB, AfterPush, dl, TII,
1226
+ FramePtr, ARM::SP, FPOffsetAfterPush,
1227
+ MachineInstr::FrameSetup);
1228
+
1194
1229
if (!NeedsWinCFI) {
1195
- if (FramePtrOffsetInPush + PushSize != 0 ) {
1230
+ // Emit DWARF info to find the CFA using the frame pointer from this
1231
+ // point onward.
1232
+ if (FPOffsetAfterPush != 0 ) {
1196
1233
unsigned CFIIndex = MF.addFrameInst (MCCFIInstruction::cfiDefCfa (
1197
1234
nullptr , MRI->getDwarfRegNum (FramePtr, true ),
1198
- FPCXTSaveSize + ArgRegsSaveSize - FramePtrOffsetInPush ));
1235
+ -MFI. getObjectOffset (FramePtrSpillFI) ));
1199
1236
BuildMI (MBB, AfterPush, dl, TII.get (TargetOpcode::CFI_INSTRUCTION))
1200
1237
.addCFIIndex (CFIIndex)
1201
1238
.setMIFlags (MachineInstr::FrameSetup);
@@ -1708,7 +1745,8 @@ void ARMFrameLowering::emitPopInst(MachineBasicBlock &MBB,
1708
1745
if (Reg == ARM::LR && !isTailCall && !isVarArg && !isInterrupt &&
1709
1746
!isCmseEntry && !isTrap && AFI->getArgumentStackToRestore () == 0 &&
1710
1747
STI.hasV5TOps () && MBB.succ_empty () && !hasPAC &&
1711
- PushPopSplit != ARMSubtarget::SplitR11WindowsSEH) {
1748
+ (PushPopSplit != ARMSubtarget::SplitR11WindowsSEH &&
1749
+ PushPopSplit != ARMSubtarget::SplitR11AAPCSSignRA)) {
1712
1750
Reg = ARM::PC;
1713
1751
// Fold the return instruction into the LDM.
1714
1752
DeleteRet = true ;
@@ -2940,18 +2978,29 @@ bool ARMFrameLowering::assignCalleeSavedSpillSlots(
2940
2978
const auto &AFI = *MF.getInfo <ARMFunctionInfo>();
2941
2979
if (AFI.shouldSignReturnAddress ()) {
2942
2980
// The order of register must match the order we push them, because the
2943
- // PEI assigns frame indices in that order. When compiling for return
2944
- // address sign and authenication, we use split push, therefore the orders
2945
- // we want are:
2946
- // LR, R7, R6, R5, R4, <R12>, R11, R10, R9, R8, D15-D8
2947
- CSI.insert (find_if (CSI,
2948
- [=](const auto &CS) {
2949
- Register Reg = CS.getReg ();
2950
- return Reg == ARM::R10 || Reg == ARM::R11 ||
2951
- Reg == ARM::R8 || Reg == ARM::R9 ||
2952
- ARM::DPRRegClass.contains (Reg);
2953
- }),
2954
- CalleeSavedInfo (ARM::R12));
2981
+ // PEI assigns frame indices in that order. That order depends on the
2982
+ // PushPopSplitVariation, there are only two cases which we use with return
2983
+ // address signing:
2984
+ switch (STI.getPushPopSplitVariation (MF)) {
2985
+ case ARMSubtarget::SplitR7:
2986
+ // LR, R7, R6, R5, R4, <R12>, R11, R10, R9, R8, D15-D8
2987
+ CSI.insert (find_if (CSI,
2988
+ [=](const auto &CS) {
2989
+ Register Reg = CS.getReg ();
2990
+ return Reg == ARM::R10 || Reg == ARM::R11 ||
2991
+ Reg == ARM::R8 || Reg == ARM::R9 ||
2992
+ ARM::DPRRegClass.contains (Reg);
2993
+ }),
2994
+ CalleeSavedInfo (ARM::R12));
2995
+ break ;
2996
+ case ARMSubtarget::SplitR11AAPCSSignRA:
2997
+ // With SplitR11AAPCSSignRA, R12 will always be the highest-addressed CSR
2998
+ // on the stack.
2999
+ CSI.insert (CSI.begin (), CalleeSavedInfo (ARM::R12));
3000
+ break ;
3001
+ default :
3002
+ llvm_unreachable (" Unexpected CSR split with return address signing" );
3003
+ }
2955
3004
}
2956
3005
2957
3006
return false ;
0 commit comments