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 @trusted
void prolog_saveregs(ref CGstate cg, ref CodeBuilder cdb, regm_t topush, int cfa_offset) 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(!(topush & ~fregsaved));
assert(cg.pushoffuse || !topush); 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 xmmtopush = 0;
int gptopush = popcnt(topush); // general purpose registers to save int gptopush = popcnt(topush); // general purpose registers to save
targ_size_t gpoffset = cg.pushoff + cg.BPoff; targ_size_t gpoffset = cg.pushoff + cg.BPoff;
gpoffset += localsize;
reg_t fp; // frame pointer reg_t fp; // frame pointer
if (!cg.hasframe || cg.enforcealign) if (!cg.hasframe || cg.enforcealign)
{ {
@ -391,6 +393,7 @@ void prolog_saveregs(ref CGstate cg, ref CodeBuilder cdb, regm_t topush, int cfa
@trusted @trusted
private void epilog_restoreregs(ref CGstate cg, ref CodeBuilder cdb, regm_t topop) 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.AArch64);
assert(cg.pushoffuse || !topop); 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 xmmtopop = popcnt(topop & XMMREGS); // XMM regs take 16 bytes
int gptopop = popcnt(topop); // general purpose registers to save int gptopop = popcnt(topop); // general purpose registers to save
targ_size_t gpoffset = cg.pushoff + cg.BPoff; targ_size_t gpoffset = cg.pushoff + cg.BPoff;
gpoffset += localsize;
reg_t fp; reg_t fp;
if (!cg.hasframe || cg.enforcealign) 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) const ins = (mask(reg) & INSTR.FLOATREGS)
// https://www.scs.stanford.edu/~zyedidia/arm64/ldr_imm_fpsimd.html // 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] : INSTR.ldr_imm_gen(1, reg, fp, gpoffset); // LDR reg,[fp,#offset]
cdb.gen1(ins); cdb.gen1(ins);
gpoffset += REGSIZE; gpoffset += REGSIZE;
@ -705,7 +709,7 @@ void epilog(block* b)
* order they were pushed. * order they were pushed.
*/ */
topop = fregsaved & ~cgstate.mfuncreg; topop = fregsaved & ~cgstate.mfuncreg;
// epilog_restoreregs(cdbx, topop); // implement epilog_restoreregs(cgstate, cdbx, topop);
if (cgstate.usednteh & NTEHjmonitor) if (cgstate.usednteh & NTEHjmonitor)
{ {

View file

@ -795,13 +795,27 @@ else
/* Instead of pushing the registers onto the stack one by one, /* Instead of pushing the registers onto the stack one by one,
* allocate space in the stack frame and copy/restore them there. * allocate space in the stack frame and copy/restore them there.
*/ */
int xmmtopush = popcnt(topush & XMMREGS); // XMM regs take 16 bytes if (cg.AArch64)
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), //printf("topush: %s\n", regm_str(topush));
xmmtopush ? STACKALIGN : REGSIZE, bias); int numtopush = popcnt(topush);
cg.pushoffuse = true; // tell others we're using this strategy 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; localsize = -cg.funcarg.offset;
static if (0) static if (0)
printf("Alloca.offset = x%llx, cstop = x%llx, CSoff = x%llx, NDPoff = x%llx, localsize = x%llx\n", 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)localsize); 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); assert(cast(targ_ptrdiff_t)localsize >= 0);
// Keep the stack aligned by 8 for any subsequent function calls // Keep the stack aligned by 8 for any subsequent function calls
@ -855,8 +869,8 @@ else
cg.funcarg.offset = -localsize; cg.funcarg.offset = -localsize;
static if (0) 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", 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)localsize); 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 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 else if (cg.needframe) // if variables or parameters
{ {
// xlocalsize can be adjusted for NTEXCEPTIONS==2
prolog_frame(cg, cdbx, farfunc, xlocalsize, enter, cfa_offset); prolog_frame(cg, cdbx, farfunc, xlocalsize, enter, cfa_offset);
cg.hasframe = true; cg.hasframe = true;
} }