@@ -5644,7 +5644,9 @@ void Compiler::lvaFixVirtualFrameOffsets()
5644
5644
#endif
5645
5645
5646
5646
// The delta to be added to virtual offset to adjust it relative to frame pointer or SP
5647
- int delta = 0 ;
5647
+ int delta = 0 ;
5648
+ int frameLocalsDelta = 0 ;
5649
+ int frameBoundary = 0 ;
5648
5650
5649
5651
#ifdef TARGET_XARCH
5650
5652
delta += REGSIZE_BYTES; // pushed PC (return address) for x86/x64
@@ -5669,7 +5671,25 @@ void Compiler::lvaFixVirtualFrameOffsets()
5669
5671
// We set FP to be after LR, FP
5670
5672
delta += 2 * REGSIZE_BYTES;
5671
5673
}
5672
- #elif defined(TARGET_AMD64) || defined(TARGET_ARM64)
5674
+ #elif defined(TARGET_ARM64)
5675
+ else
5676
+ {
5677
+ // FP is used.
5678
+ delta += codeGen->genTotalFrameSize () - codeGen->genSPtoFPdelta ();
5679
+
5680
+ // If we placed FP/LR at the bottom of the frame we need to shift all the variables
5681
+ // on the new frame to account for it. See lvaAssignVirtualFrameOffsetsToLocals.
5682
+ if (!codeGen->IsSaveFpLrWithAllCalleeSavedRegisters ())
5683
+ {
5684
+ // We set FP to be after LR, FP
5685
+ frameLocalsDelta = 2 * REGSIZE_BYTES;
5686
+ frameBoundary = opts.IsOSR () ? -info.compPatchpointInfo ->TotalFrameSize () : 0 ;
5687
+ if (info.compIsVarArgs )
5688
+ frameBoundary -= MAX_REG_ARG * REGSIZE_BYTES;
5689
+ }
5690
+ JITDUMP (" --- delta bump %d for FP frame, %d inside frame for FP/LR relocation\n " , delta, frameLocalsDelta);
5691
+ }
5692
+ #elif defined(TARGET_AMD64)
5673
5693
else
5674
5694
{
5675
5695
// FP is used.
@@ -5737,7 +5757,7 @@ void Compiler::lvaFixVirtualFrameOffsets()
5737
5757
5738
5758
#if defined(TARGET_X86)
5739
5759
// On x86, we set the stack offset for a promoted field
5740
- // to match a struct parameter in lvAssignFrameOffsetsToPromotedStructs .
5760
+ // to match a struct parameter in lvaAssignFrameOffsetsToPromotedStructs .
5741
5761
if ((!varDsc->lvIsParam || parentvarDsc->lvIsParam ) && promotionType == PROMOTION_TYPE_DEPENDENT)
5742
5762
#else
5743
5763
if (!varDsc->lvIsParam && promotionType == PROMOTION_TYPE_DEPENDENT)
@@ -5757,15 +5777,23 @@ void Compiler::lvaFixVirtualFrameOffsets()
5757
5777
5758
5778
if (doAssignStkOffs)
5759
5779
{
5760
- JITDUMP (" -- V%02u was %d, now %d\n " , lclNum, varDsc->GetStackOffset (), varDsc->GetStackOffset () + delta);
5761
- varDsc->SetStackOffset (varDsc->GetStackOffset () + delta);
5780
+ int localDelta = delta;
5781
+
5782
+ if (frameLocalsDelta != 0 && varDsc->GetStackOffset () < frameBoundary)
5783
+ {
5784
+ localDelta += frameLocalsDelta;
5785
+ }
5786
+
5787
+ JITDUMP (" -- V%02u was %d, now %d\n " , lclNum, varDsc->GetStackOffset (),
5788
+ varDsc->GetStackOffset () + localDelta);
5789
+ varDsc->SetStackOffset (varDsc->GetStackOffset () + localDelta);
5762
5790
5763
5791
#if DOUBLE_ALIGN
5764
5792
if (genDoubleAlign () && !codeGen->isFramePointerUsed ())
5765
5793
{
5766
5794
if (varDsc->lvFramePointerBased )
5767
5795
{
5768
- varDsc->SetStackOffset (varDsc->GetStackOffset () - delta );
5796
+ varDsc->SetStackOffset (varDsc->GetStackOffset () - localDelta );
5769
5797
5770
5798
// We need to re-adjust the offsets of the parameters so they are EBP
5771
5799
// relative rather than stack/frame pointer relative
@@ -5787,9 +5815,13 @@ void Compiler::lvaFixVirtualFrameOffsets()
5787
5815
assert (codeGen->regSet .tmpAllFree ());
5788
5816
for (TempDsc* temp = codeGen->regSet .tmpListBeg (); temp != nullptr ; temp = codeGen->regSet .tmpListNxt (temp))
5789
5817
{
5790
- temp->tdAdjustTempOffs (delta);
5818
+ temp->tdAdjustTempOffs (delta + frameLocalsDelta );
5791
5819
}
5792
5820
5821
+ if (lvaCachedGenericContextArgOffs < frameBoundary)
5822
+ {
5823
+ lvaCachedGenericContextArgOffs += frameLocalsDelta;
5824
+ }
5793
5825
lvaCachedGenericContextArgOffs += delta;
5794
5826
5795
5827
#if FEATURE_FIXED_OUT_ARGS
@@ -6045,30 +6077,6 @@ void Compiler::lvaAssignVirtualFrameOffsetsToLocals()
6045
6077
codeGen->setFramePointerUsed (codeGen->isFramePointerRequired ());
6046
6078
}
6047
6079
6048
- #ifdef TARGET_ARM64
6049
- // Decide where to save FP and LR registers. We store FP/LR registers at the bottom of the frame if there is
6050
- // a frame pointer used (so we get positive offsets from the frame pointer to access locals), but not if we
6051
- // need a GS cookie AND localloc is used, since we need the GS cookie to protect the saved return value,
6052
- // and also the saved frame pointer. See CodeGen::genPushCalleeSavedRegisters() for more details about the
6053
- // frame types. Since saving FP/LR at high addresses is a relatively rare case, force using it during stress.
6054
- // (It should be legal to use these frame types for every frame).
6055
-
6056
- if (opts.compJitSaveFpLrWithCalleeSavedRegisters == 0 )
6057
- {
6058
- // Default configuration
6059
- codeGen->SetSaveFpLrWithAllCalleeSavedRegisters ((getNeedsGSSecurityCookie () && compLocallocUsed) ||
6060
- opts.compDbgEnC || compStressCompile (STRESS_GENERIC_VARN, 20 ));
6061
- }
6062
- else if (opts.compJitSaveFpLrWithCalleeSavedRegisters == 1 )
6063
- {
6064
- codeGen->SetSaveFpLrWithAllCalleeSavedRegisters (false ); // Disable using new frames
6065
- }
6066
- else if ((opts.compJitSaveFpLrWithCalleeSavedRegisters == 2 ) || (opts.compJitSaveFpLrWithCalleeSavedRegisters == 3 ))
6067
- {
6068
- codeGen->SetSaveFpLrWithAllCalleeSavedRegisters (true ); // Force using new frames
6069
- }
6070
- #endif // TARGET_ARM64
6071
-
6072
6080
#ifdef TARGET_XARCH
6073
6081
// On x86/amd64, the return address has already been pushed by the call instruction in the caller.
6074
6082
stkOffs -= TARGET_POINTER_SIZE; // return address;
@@ -6117,9 +6125,13 @@ void Compiler::lvaAssignVirtualFrameOffsetsToLocals()
6117
6125
#endif // !TARGET_ARM
6118
6126
6119
6127
#ifdef TARGET_ARM64
6120
- // If the frame pointer is used, then we'll save FP/LR at the bottom of the stack.
6121
- // Otherwise, we won't store FP, and we'll store LR at the top, with the other callee-save
6122
- // registers (if any).
6128
+ // If the frame pointer is used, then we'll save FP/LR either at the bottom of the stack
6129
+ // or at the top of the stack depending on frame type. We make the decision after assigning
6130
+ // the variables on the frame and then fix up the offsets in lvaFixVirtualFrameOffsets.
6131
+ // For now, we proceed as if FP/LR were saved with the callee registers. If we later
6132
+ // decide to move the FP/LR to the bottom of the frame it shifts all the assigned
6133
+ // variables and temporaries by 16 bytes. The largest alignment we currently make is 16
6134
+ // bytes for SIMD.
6123
6135
6124
6136
int initialStkOffs = 0 ;
6125
6137
if (info.compIsVarArgs )
@@ -6130,17 +6142,7 @@ void Compiler::lvaAssignVirtualFrameOffsetsToLocals()
6130
6142
stkOffs -= initialStkOffs;
6131
6143
}
6132
6144
6133
- if (codeGen->IsSaveFpLrWithAllCalleeSavedRegisters () || !isFramePointerUsed ()) // Note that currently we always have
6134
- // a frame pointer
6135
- {
6136
- stkOffs -= compCalleeRegsPushed * REGSIZE_BYTES;
6137
- }
6138
- else
6139
- {
6140
- // Subtract off FP and LR.
6141
- assert (compCalleeRegsPushed >= 2 );
6142
- stkOffs -= (compCalleeRegsPushed - 2 ) * REGSIZE_BYTES;
6143
- }
6145
+ stkOffs -= compCalleeRegsPushed * REGSIZE_BYTES;
6144
6146
6145
6147
#elif defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
6146
6148
@@ -6810,15 +6812,6 @@ void Compiler::lvaAssignVirtualFrameOffsetsToLocals()
6810
6812
}
6811
6813
#endif // TARGET_AMD64
6812
6814
6813
- #ifdef TARGET_ARM64
6814
- if (!codeGen->IsSaveFpLrWithAllCalleeSavedRegisters () && isFramePointerUsed ()) // Note that currently we always have
6815
- // a frame pointer
6816
- {
6817
- // Create space for saving FP and LR.
6818
- stkOffs -= 2 * REGSIZE_BYTES;
6819
- }
6820
- #endif // TARGET_ARM64
6821
-
6822
6815
#if FEATURE_FIXED_OUT_ARGS
6823
6816
if (lvaOutgoingArgSpaceSize > 0 )
6824
6817
{
@@ -6856,6 +6849,44 @@ void Compiler::lvaAssignVirtualFrameOffsetsToLocals()
6856
6849
6857
6850
noway_assert (compLclFrameSize + originalFrameSize ==
6858
6851
(unsigned )-(stkOffs + (pushedCount * (int )TARGET_POINTER_SIZE)));
6852
+
6853
+ #ifdef TARGET_ARM64
6854
+ // Decide where to save FP and LR registers. We store FP/LR registers at the bottom of the frame if there is
6855
+ // a frame pointer used (so we get positive offsets from the frame pointer to access locals), but not if we
6856
+ // need a GS cookie AND localloc is used, since we need the GS cookie to protect the saved return value,
6857
+ // and also the saved frame pointer. See CodeGen::genPushCalleeSavedRegisters() for more details about the
6858
+ // frame types. Since saving FP/LR at high addresses is a relatively rare case, force using it during stress.
6859
+ // (It should be legal to use these frame types for every frame).
6860
+ //
6861
+ // For Apple NativeAOT ABI we try to save the FP/LR registers on top to get canonical frame layout that can
6862
+ // be represented with compact unwinding information. In order to maintain code quality we only do it when
6863
+ // we can use SP-based addressing (!isFramePointerRequired) through lvaFrameAddress optimization, or if the
6864
+ // whole frame is small enough that the negative FP-based addressing can address the whole frame.
6865
+
6866
+ if (opts.compJitSaveFpLrWithCalleeSavedRegisters == 0 )
6867
+ {
6868
+ if (IsTargetAbi (CORINFO_NATIVEAOT_ABI) && TargetOS::IsApplePlatform &&
6869
+ (!codeGen->isFramePointerRequired () || codeGen->genTotalFrameSize () < 0x100 ))
6870
+ {
6871
+ codeGen->SetSaveFpLrWithAllCalleeSavedRegisters (true );
6872
+ }
6873
+ else
6874
+ {
6875
+ // Default configuration
6876
+ codeGen->SetSaveFpLrWithAllCalleeSavedRegisters ((getNeedsGSSecurityCookie () && compLocallocUsed) ||
6877
+ opts.compDbgEnC ||
6878
+ compStressCompile (Compiler::STRESS_GENERIC_VARN, 20 ));
6879
+ }
6880
+ }
6881
+ else if (opts.compJitSaveFpLrWithCalleeSavedRegisters == 1 )
6882
+ {
6883
+ codeGen->SetSaveFpLrWithAllCalleeSavedRegisters (false ); // Disable using new frames
6884
+ }
6885
+ else if ((opts.compJitSaveFpLrWithCalleeSavedRegisters == 2 ) || (opts.compJitSaveFpLrWithCalleeSavedRegisters == 3 ))
6886
+ {
6887
+ codeGen->SetSaveFpLrWithAllCalleeSavedRegisters (true ); // Force using new frames
6888
+ }
6889
+ #endif // TARGET_ARM64
6859
6890
}
6860
6891
6861
6892
// ------------------------------------------------------------------------
0 commit comments