fix offsets in prolog_saveregs/restoreregs (#21251)

This commit is contained in:
Walter Bright 2025-04-17 01:35:25 -07:00 committed by GitHub
parent d6602a6b0f
commit 93d2e53e94
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 32 additions and 13 deletions

View file

@ -341,7 +341,8 @@ void genBranch(ref CodeBuilder cdb, COND cond, FL fltarg, block* targ)
@trusted
void prolog_saveregs(ref CGstate cg, ref CodeBuilder cdb, regm_t topush, int cfa_offset)
{
printf("prolog_saveregs() topush: %s pushoffuse: %d\n", regm_str(topush), cg.pushoffuse);
//printf("prolog_saveregs() topush: %s pushoffuse: %d\n", regm_str(topush), cg.pushoffuse);
//printf("function: %s\n", funcsym_p.Sident.ptr);
assert(!(topush & ~fregsaved));
assert(cg.pushoffuse || !topush);
@ -349,6 +350,7 @@ void prolog_saveregs(ref CGstate cg, ref CodeBuilder cdb, regm_t topush, int cfa
int xmmtopush = 0;
int gptopush = popcnt(topush); // general purpose registers to save
targ_size_t gpoffset = cg.pushoff + cg.BPoff;
gpoffset += localsize;
reg_t fp; // frame pointer
if (!cg.hasframe || cg.enforcealign)
{
@ -391,6 +393,7 @@ void prolog_saveregs(ref CGstate cg, ref CodeBuilder cdb, regm_t topush, int cfa
@trusted
private void epilog_restoreregs(ref CGstate cg, ref CodeBuilder cdb, regm_t topop)
{
//printf("prolog_restoreregs() topop: %s\n", regm_str(topop));
assert(cg.AArch64);
assert(cg.pushoffuse || !topop);
@ -399,6 +402,7 @@ private void epilog_restoreregs(ref CGstate cg, ref CodeBuilder cdb, regm_t topo
int xmmtopop = popcnt(topop & XMMREGS); // XMM regs take 16 bytes
int gptopop = popcnt(topop); // general purpose registers to save
targ_size_t gpoffset = cg.pushoff + cg.BPoff;
gpoffset += localsize;
reg_t fp;
if (!cg.hasframe || cg.enforcealign)
@ -416,7 +420,7 @@ private void epilog_restoreregs(ref CGstate cg, ref CodeBuilder cdb, regm_t topo
const ins = (mask(reg) & INSTR.FLOATREGS)
// https://www.scs.stanford.edu/~zyedidia/arm64/ldr_imm_fpsimd.html
? INSTR.ldr_imm_fpsimd(3,0,cast(uint)gpoffset >> 3,fp,reg) // LDR reg,[fp,#offset]
? INSTR.ldr_imm_fpsimd(3,1,cast(uint)gpoffset >> 3,fp,reg) // LDR reg,[fp,#offset]
: INSTR.ldr_imm_gen(1, reg, fp, gpoffset); // LDR reg,[fp,#offset]
cdb.gen1(ins);
gpoffset += REGSIZE;
@ -705,7 +709,7 @@ void epilog(block* b)
* order they were pushed.
*/
topop = fregsaved & ~cgstate.mfuncreg;
// epilog_restoreregs(cdbx, topop); // implement
epilog_restoreregs(cgstate, cdbx, topop);
if (cgstate.usednteh & NTEHjmonitor)
{

View file

@ -795,13 +795,27 @@ else
/* Instead of pushing the registers onto the stack one by one,
* allocate space in the stack frame and copy/restore them there.
*/
int xmmtopush = popcnt(topush & XMMREGS); // XMM regs take 16 bytes
int gptopush = popcnt(topush) - xmmtopush; // general purpose registers to save
if (cg.NDPoff || xmmtopush || cg.funcarg.size)
if (cg.AArch64)
{
cg.pushoff = alignsection(cg.pushoff - (gptopush * REGSIZE + xmmtopush * 16),
xmmtopush ? STACKALIGN : REGSIZE, bias);
cg.pushoffuse = true; // tell others we're using this strategy
//printf("topush: %s\n", regm_str(topush));
int numtopush = popcnt(topush);
if (numtopush || cg.funcarg.size)
{
cg.pushoff = alignsection(cg.pushoff - numtopush * REGSIZE,
REGSIZE, bias);
cg.pushoffuse = true; // tell others we're using this strategy
}
}
else
{
int xmmtopush = popcnt(topush & XMMREGS); // XMM regs take 16 bytes
int gptopush = popcnt(topush) - xmmtopush; // general purpose registers to save
if (cg.NDPoff || xmmtopush || cg.funcarg.size)
{
cg.pushoff = alignsection(cg.pushoff - (gptopush * REGSIZE + xmmtopush * 16),
xmmtopush ? STACKALIGN : REGSIZE, bias);
cg.pushoffuse = true; // tell others we're using this strategy
}
}
}
@ -823,8 +837,8 @@ else
localsize = -cg.funcarg.offset;
static if (0)
printf("Alloca.offset = x%llx, cstop = x%llx, CSoff = x%llx, NDPoff = x%llx, localsize = x%llx\n",
cast(long)cg.Alloca.offset, cast(long)CSE.size(), cast(long)cg.CSoff, cast(long)cg.NDPoff, cast(long)localsize);
printf("Alloca.offset: x%llx cstop: x%llx CSoff: x%llx NDPoff: x%llx pushoff: x%llx localsize: x%llx\n",
cast(long)cg.Alloca.offset, cast(long)CSE.size(), cast(long)cg.CSoff, cast(long)cg.NDPoff, cast(long)cg.pushoff, cast(long)localsize);
assert(cast(targ_ptrdiff_t)localsize >= 0);
// Keep the stack aligned by 8 for any subsequent function calls
@ -855,8 +869,8 @@ else
cg.funcarg.offset = -localsize;
static if (0)
printf("Foff x%02x Auto.size x%02x NDPoff x%02x CSoff x%02x Para.size x%02x localsize x%02x\n",
cast(int)cg.Foff,cast(int)cg.Auto.size,cast(int)cg.NDPoff,cast(int)cg.CSoff,cast(int)cg.Para.size,cast(int)localsize);
printf("Foff x%02x Auto.size x%02x NDPoff x%02x CSoff x%02x Para.size x%02x pushoff x%02x localsize x%02x\n",
cast(int)cg.Foff,cast(int)cg.Auto.size,cast(int)cg.NDPoff,cast(int)cg.CSoff,cast(int)cg.Para.size,cast(int)cg.pushoff,cast(int)localsize);
uint xlocalsize = cast(uint)localsize; // amount to subtract from ESP to make room for locals
@ -924,6 +938,7 @@ else
}
else if (cg.needframe) // if variables or parameters
{
// xlocalsize can be adjusted for NTEXCEPTIONS==2
prolog_frame(cg, cdbx, farfunc, xlocalsize, enter, cfa_offset);
cg.hasframe = true;
}