fix ldr/str floating point registers (#21235)

This commit is contained in:
Walter Bright 2025-04-15 00:30:53 -07:00 committed by GitHub
parent d0cf2c7117
commit c30def82bd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 41 additions and 28 deletions

View file

@ -77,10 +77,10 @@ void loadFromEA(ref code cs, reg_t reg, uint szw, uint szr)
// LDR reg,[cs.base, #offset]
assert(cs.index == NOREG);
uint imm12 = cast(uint)cs.IEV1.Voffset;
if (szw == 4) imm12 >>= 2;
else if (szw == 8) imm12 >>= 3;
else assert(0);
cs.Iop = INSTR.ldr_imm_fpsimd(szw == 8 ? 3 : 2,1,imm12,cs.base,reg);
uint size, opc;
INSTR.szToSizeOpc(szw, size, opc);
imm12 /= szw;
cs.Iop = INSTR.ldr_imm_fpsimd(size,opc,imm12,cs.base,reg);
}
else
assert(0);
@ -150,11 +150,11 @@ void storeToEA(ref code cs, reg_t reg, uint sz)
{
// STR reg,[cs.base, #offset]
assert(cs.index == NOREG);
uint imm12 = cs.Sextend;
if (sz == 4) imm12 >>= 4;
else if (sz == 8) imm12 >>= 8;
else assert(0);
cs.Iop = INSTR.str_imm_fpsimd(sz == 8 ? 3 : 2,0,imm12,cs.base,reg);
uint imm12 = cast(uint)cs.IEV1.Voffset;
uint size, opc;
INSTR.szToSizeOpc(sz, size, opc);
imm12 /= sz;
cs.Iop = INSTR.str_imm_fpsimd(size,opc,imm12,cs.base,reg);
}
else
assert(0);

View file

@ -349,7 +349,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;
reg_t fp;
reg_t fp; // frame pointer
if (!cg.hasframe || cg.enforcealign)
{
gpoffset += cg.EBPtoESP;
@ -365,7 +365,7 @@ void prolog_saveregs(ref CGstate cg, ref CodeBuilder cdb, regm_t topush, int cfa
const ins = (mask(reg) & INSTR.FLOATREGS)
// https://www.scs.stanford.edu/~zyedidia/arm64/str_imm_fpsimd.html
? INSTR.str_imm_fpsimd(3,0,cast(uint)gpoffset,fp,reg) // STR reg,[fp,#offset]
? INSTR.str_imm_fpsimd(3,0,cast(uint)gpoffset >> 3,fp,reg) // STR reg,[fp,#offset]
: INSTR.str_imm_gen(1, reg, fp, gpoffset); // STR reg,[fp,#offset]
cdb.gen1(ins);
@ -416,7 +416,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,1,cast(uint)gpoffset,fp,reg) // LDR reg,[fp,#offset]
? INSTR.ldr_imm_fpsimd(3,0,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;
@ -501,11 +501,10 @@ void prolog_genvarargs(ref CGstate cg, ref CodeBuilder cdb, Symbol* sv)
{
if (!(mask(q) & namedargs)) // unnamed arguments would be the ... ones
{
reg_t fp = (!cg.hasframe || cg.enforcealign) ? 31 : 29; // SP : BP
uint offset = cast(uint)voff + 8 * 8 + (q & 31) * 16;
if (!cg.hasframe || cg.enforcealign)
cdb.gen1(INSTR.str_imm_fpsimd(0,2,offset,31,q)); // STR q,[sp,#offset]
else
cdb.gen1(INSTR.str_imm_fpsimd(0,2,offset,29,q));
offset /= 16; // saving 128 bit Q registers
cdb.gen1(INSTR.str_imm_fpsimd(0,2,offset,fp,q)); // STR q,[sp,#offset]
}
}

View file

@ -56,6 +56,22 @@ struct INSTR
3; // half-precision
}
/* Convert size of floating point type to size,opc
* https://www.scs.stanford.edu/~zyedidia/arm64/str_imm_fpsimd.html
*/
static void szToSizeOpc(uint sz, ref uint size, ref uint opc)
{
switch (sz)
{
case 1: size = 0; opc = 0; break; // Bt byte
case 2: size = 1; opc = 0; break; // Ht half
case 4: size = 2; opc = 0; break; // St single
case 8: size = 3; opc = 0; break; // Dt double
case 16: size = 0; opc = 2; break; // Qt quad
default: assert(0);
}
}
/************************************ Reserved ***********************************************/
/* https://www.scs.stanford.edu/~zyedidia/arm64/encodingindex.html#reserved */
@ -986,24 +1002,22 @@ struct INSTR
/* https://www.scs.stanford.edu/~zyedidia/arm64/str_imm_fpsimd.html
* STR <Vt>,[<Xn|SP>,#<simm>] Unsigned offset
*/
static uint str_imm_fpsimd(uint size, uint opc, uint offset, reg_t Rn, reg_t Vt)
static uint str_imm_fpsimd(uint size, uint opc, uint imm12, reg_t Rn, reg_t Vt)
{
assert(imm12 < 0x1000);
assert(size < 4);
assert(opc < 4);
uint scale = ((opc & 2) << 1) | size;
uint imm12 = (cast(uint)offset >> scale) & 0xFFF;
return ldst_pos(size,1,opc,imm12,Rn,Vt);
}
/* https://www.scs.stanford.edu/~zyedidia/arm64/ldr_imm_fpsimd.html
* LDR <Vt>,[<Xn|SP>,#<simm>] Unsigned offset
*/
static uint ldr_imm_fpsimd(uint size, uint opc, uint offset, reg_t Rn, reg_t Vt)
static uint ldr_imm_fpsimd(uint size, uint opc, uint imm12, reg_t Rn, reg_t Vt)
{
assert(imm12 < 0x1000);
assert(size < 4);
assert(opc < 4);
uint scale = ((opc & 2) << 1) | size;
uint imm12 = (cast(uint)offset >> scale) & 0xFFF;
return ldst_pos(size,1,opc,imm12,Rn,Vt);
}

View file

@ -35,7 +35,7 @@ struct CodeBuilder
code** pTail;
enum BADINS = 0x1234_5678;
// enum BADINS = 0xF900_0FA0;
//enum BADINS = 0xBD00_07A0;
nothrow:
public:

View file

@ -765,6 +765,7 @@ else
if (cg.floatreg)
{
assert(!cg.AArch64);
uint floatregsize = config.fpxmmregs || I32 ? 16 : DOUBLESIZE;
cg.Foff = alignsection(cg.regsave.off - floatregsize, STACKALIGN, bias);
//printf("Foff = x%x, size = x%x\n", cast(int)cg.Foff, cast(int)floatregsize);

View file

@ -4380,11 +4380,10 @@ void prolog_loadparams(ref CodeBuilder cdb, tym_t tyf, bool pushalloc)
if (tyfloating(t.Tty))
{
// STR preg,[bp,#offset]
if (sz == 8)
imm >>= 3;
else if (sz == 4)
imm >>= 2;
cdb.gen1(INSTR.str_imm_fpsimd(2 + (sz == 8),0,imm,29,preg));
uint size, opc;
INSTR.szToSizeOpc(sz, size, opc);
imm /= sz;
cdb.gen1(INSTR.str_imm_fpsimd(size,opc,imm,29,preg)); // https://www.scs.stanford.edu/~zyedidia/arm64/str_imm_fpsimd.html
}
else
// STR preg,bp,#offset