Skip to content

Commit

Permalink
WIP: Generate compact unwinding friendly frames on Apple platforms
Browse files Browse the repository at this point in the history
  • Loading branch information
filipnavara committed Sep 1, 2024
1 parent d837fac commit 3f208ce
Show file tree
Hide file tree
Showing 8 changed files with 243 additions and 40 deletions.
2 changes: 2 additions & 0 deletions src/coreclr/jit/codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -654,8 +654,10 @@ class CodeGen final : public CodeGenInterface
#ifdef TARGET_ARM64
virtual void SetSaveFpLrWithAllCalleeSavedRegisters(bool value);
virtual bool IsSaveFpLrWithAllCalleeSavedRegisters() const;
virtual void SetReverseAndPairCalleeSavedRegisters(bool value);
bool genSaveFpLrWithAllCalleeSavedRegisters;
bool genForceFuncletFrameType5;
bool genReverseAndPairCalleeSavedRegisters;
#endif // TARGET_ARM64

//-------------------------------------------------------------------------
Expand Down
60 changes: 52 additions & 8 deletions src/coreclr/jit/codegenarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -852,12 +852,20 @@ void CodeGen::genSaveCalleeSavedRegisterGroup(regMaskTP regsMask, int spDelta, i

for (int i = 0; i < regStack.Height(); ++i)
{
RegPair regPair = regStack.Bottom(i);
RegPair regPair = genReverseAndPairCalleeSavedRegisters ? regStack.Top(i) : regStack.Bottom(i);
if (regPair.reg2 != REG_NA)
{
// We can use a STP instruction.
genPrologSaveRegPair(regPair.reg1, regPair.reg2, spOffset, spDelta, regPair.useSaveNextPair, REG_IP0,
nullptr);
if (genReverseAndPairCalleeSavedRegisters)
{
genPrologSaveRegPair(regPair.reg2, regPair.reg1, spOffset, spDelta, false,
REG_IP0, nullptr);
}
else
{
genPrologSaveRegPair(regPair.reg1, regPair.reg2, spOffset, spDelta, regPair.useSaveNextPair,
REG_IP0, nullptr);
}

spOffset += 2 * slotSize;
}
Expand Down Expand Up @@ -932,8 +940,9 @@ void CodeGen::genSaveCalleeSavedRegistersHelp(regMaskTP regsToSaveMask, int lowe

// Save integer registers at higher addresses than floating-point registers.

regMaskTP maskSaveRegsFrame = regsToSaveMask & (RBM_FP | RBM_LR);
regMaskTP maskSaveRegsFloat = regsToSaveMask & RBM_ALLFLOAT;
regMaskTP maskSaveRegsInt = regsToSaveMask & ~maskSaveRegsFloat;
regMaskTP maskSaveRegsInt = regsToSaveMask & ~maskSaveRegsFloat & ~maskSaveRegsFrame;

if (maskSaveRegsFloat != RBM_NONE)
{
Expand All @@ -945,6 +954,14 @@ void CodeGen::genSaveCalleeSavedRegistersHelp(regMaskTP regsToSaveMask, int lowe
if (maskSaveRegsInt != RBM_NONE)
{
genSaveCalleeSavedRegisterGroup(maskSaveRegsInt, spDelta, lowestCalleeSavedOffset);
spDelta = 0;
lowestCalleeSavedOffset += genCountBits(maskSaveRegsInt) * FPSAVE_REGSIZE_BYTES;
}

if (maskSaveRegsFrame != RBM_NONE)
{
genPrologSaveRegPair(REG_FP, REG_LR, lowestCalleeSavedOffset, spDelta, false, REG_IP0,
nullptr);
// No need to update spDelta, lowestCalleeSavedOffset since they're not used after this.
}
}
Expand Down Expand Up @@ -976,13 +993,21 @@ void CodeGen::genRestoreCalleeSavedRegisterGroup(regMaskTP regsMask, int spDelta
stackDelta = spDelta;
}

RegPair regPair = regStack.Top(i);
RegPair regPair = genReverseAndPairCalleeSavedRegisters ? regStack.Bottom(i) : regStack.Top(i);
if (regPair.reg2 != REG_NA)
{
spOffset -= 2 * slotSize;

genEpilogRestoreRegPair(regPair.reg1, regPair.reg2, spOffset, stackDelta, regPair.useSaveNextPair, REG_IP1,
nullptr);
if (genReverseAndPairCalleeSavedRegisters)
{
genEpilogRestoreRegPair(regPair.reg2, regPair.reg1, spOffset, stackDelta, false,
REG_IP1, nullptr);
}
else
{
genEpilogRestoreRegPair(regPair.reg1, regPair.reg2, spOffset, stackDelta, regPair.useSaveNextPair,
REG_IP1, nullptr);
}
}
else
{
Expand Down Expand Up @@ -1049,11 +1074,19 @@ void CodeGen::genRestoreCalleeSavedRegistersHelp(regMaskTP regsToRestoreMask, in

// Save integer registers at higher addresses than floating-point registers.

regMaskTP maskRestoreRegsFrame = regsToRestoreMask & (RBM_FP | RBM_LR);
regMaskTP maskRestoreRegsFloat = regsToRestoreMask & RBM_ALLFLOAT;
regMaskTP maskRestoreRegsInt = regsToRestoreMask & ~maskRestoreRegsFloat;
regMaskTP maskRestoreRegsInt = regsToRestoreMask & ~maskRestoreRegsFloat & ~maskRestoreRegsFrame;

// Restore in the opposite order of saving.

if (maskRestoreRegsFrame != RBM_NONE)
{
int spFrameDelta = (maskRestoreRegsFloat != RBM_NONE || maskRestoreRegsInt != RBM_NONE) ? 0 : spDelta;
spOffset -= 2 * REGSIZE_BYTES;
genEpilogRestoreRegPair(REG_FP, REG_LR, spOffset, spFrameDelta, false, REG_IP1, nullptr);
}

if (maskRestoreRegsInt != RBM_NONE)
{
int spIntDelta = (maskRestoreRegsFloat != RBM_NONE) ? 0 : spDelta; // should we delay the SP adjustment?
Expand Down Expand Up @@ -5148,6 +5181,17 @@ bool CodeGen::IsSaveFpLrWithAllCalleeSavedRegisters() const
return genSaveFpLrWithAllCalleeSavedRegisters;
}

//---------------------------------------------------------------------
// SetReverseAndPairCalleeSavedRegisters - Set the variable that indicates if X19-X28 registers
// callee-saved registers are stored in reverse order and we always store them as pairs even if
// one register in the pair is unused.
//
void CodeGen::SetReverseAndPairCalleeSavedRegisters(bool value)
{
JITDUMP("Setting genReverseAndPairCalleeSavedRegisters to %s\n", dspBool(value));
genReverseAndPairCalleeSavedRegisters = value;
}

/*****************************************************************************
* Emit a call to a helper function.
*
Expand Down
21 changes: 21 additions & 0 deletions src/coreclr/jit/codegencommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ CodeGen::CodeGen(Compiler* theCompiler)
#ifdef TARGET_ARM64
genSaveFpLrWithAllCalleeSavedRegisters = false;
genForceFuncletFrameType5 = false;
genReverseAndPairCalleeSavedRegisters = false;
#endif // TARGET_ARM64
}

Expand Down Expand Up @@ -4846,6 +4847,26 @@ void CodeGen::genFinalizeFrame()
}
#endif // TARGET_ARM

#ifdef TARGET_ARM64
if (genReverseAndPairCalleeSavedRegisters)
{
// Make sure we push the registers in pairs if possible. If we only allocate a contiguous
// block of registers this should add at most one integer and at most one floating point
// register to the list. The stack has to be 16-byte aligned, so in worst case it results
// in allocating 16 bytes more space on stack if odd number of integer and odd number of
// FP registers were occupied. Same number of instructions will be generated, just the
// STR instructions are replaced with STP (store pair).
regMaskTP maskModifiedRegs = regSet.rsGetModifiedRegsMask();
regMaskTP maskPairRegs =
((maskModifiedRegs & (RBM_V8 | RBM_V10 | RBM_V12 | RBM_V14)).getLow() << 1) |
((maskModifiedRegs & (RBM_R19 | RBM_R21 | RBM_R23 | RBM_R25 | RBM_R27)).getLow() << 1);
if (maskPairRegs != RBM_NONE)
{
regSet.rsSetRegsModified(maskPairRegs);
}
}
#endif

#ifdef DEBUG
if (verbose)
{
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/codegeninterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ class CodeGenInterface
#ifdef TARGET_ARM64
virtual void SetSaveFpLrWithAllCalleeSavedRegisters(bool value) = 0;
virtual bool IsSaveFpLrWithAllCalleeSavedRegisters() const = 0;
virtual void SetReverseAndPairCalleeSavedRegisters(bool value) = 0;
#endif // TARGET_ARM64

regNumber genGetThisArgReg(GenTreeCall* call) const;
Expand Down
14 changes: 11 additions & 3 deletions src/coreclr/jit/lclvars.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6129,9 +6129,17 @@ void Compiler::lvaAssignVirtualFrameOffsetsToLocals()

if (opts.compJitSaveFpLrWithCalleeSavedRegisters == 0)
{
// Default configuration
codeGen->SetSaveFpLrWithAllCalleeSavedRegisters((getNeedsGSSecurityCookie() && compLocallocUsed) ||
opts.compDbgEnC || compStressCompile(STRESS_GENERIC_VARN, 20));
if (IsTargetAbi(CORINFO_NATIVEAOT_ABI) && TargetOS::IsApplePlatform)
{
codeGen->SetSaveFpLrWithAllCalleeSavedRegisters(true);
codeGen->SetReverseAndPairCalleeSavedRegisters(true);
}
else
{
// Default configuration
codeGen->SetSaveFpLrWithAllCalleeSavedRegisters((getNeedsGSSecurityCookie() && compLocallocUsed) ||
opts.compDbgEnC || compStressCompile(STRESS_GENERIC_VARN, 20));
}
}
else if (opts.compJitSaveFpLrWithCalleeSavedRegisters == 1)
{
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/optcse.h
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ class CSE_Heuristic : public CSE_HeuristicCommon
bool PromotionCheck(CSE_Candidate* candidate);
void AdjustHeuristic(CSE_Candidate* candidate);
bool ConsiderTree(GenTree* tree, bool isReturn);
bool IsLargeFrame() { return largeFrame; }

const char* Name() const
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,5 +120,18 @@ internal static class MachNative
public const uint PLATFORM_TVOSSIMULATOR = 8;
public const uint PLATFORM_WATCHOSSIMULATOR = 9;
public const uint PLATFORM_DRIVERKIT = 10;

public const uint UNWIND_ARM64_MODE_FRAMELESS = 0x02000000;
public const uint UNWIND_ARM64_MODE_DWARF = 0x03000000;
public const uint UNWIND_ARM64_MODE_FRAME = 0x04000000;
public const uint UNWIND_ARM64_FRAME_X19_X20_PAIR = 0x00000001;
public const uint UNWIND_ARM64_FRAME_X21_X22_PAIR = 0x00000002;
public const uint UNWIND_ARM64_FRAME_X23_X24_PAIR = 0x00000004;
public const uint UNWIND_ARM64_FRAME_X25_X26_PAIR = 0x00000008;
public const uint UNWIND_ARM64_FRAME_X27_X28_PAIR = 0x00000010;
public const uint UNWIND_ARM64_FRAME_D8_D9_PAIR = 0x00000100;
public const uint UNWIND_ARM64_FRAME_D10_D11_PAIR = 0x00000200;
public const uint UNWIND_ARM64_FRAME_D12_D13_PAIR = 0x00000400;
public const uint UNWIND_ARM64_FRAME_D14_D15_PAIR = 0x00000800;
}
}
Loading

0 comments on commit 3f208ce

Please sign in to comment.