add floatPost() (#21227)

This commit is contained in:
Walter Bright 2025-04-13 23:35:36 -07:00 committed by GitHub
parent 8a8746f318
commit 5fcca3e152
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 136 additions and 15 deletions

View file

@ -1241,7 +1241,8 @@ void tstresult(ref CodeBuilder cdb, regm_t regm, tym_t tym, bool saveflag)
void fixresult(ref CodeBuilder cdb, elem* e, regm_t retregs, ref regm_t outretregs)
{
//printf("arm.fixresult(e = %p, retregs = %s, outretregs = %s)\n",e,regm_str(retregs),regm_str(outretregs));
if (outretregs == 0) return; // if don't want result
//elem_print(e);
if (outretregs == 0) return; // if don't want result
assert(e && retregs); // need something to work with
regm_t forccs = outretregs & mPSW;
regm_t forregs = outretregs & (cgstate.allregs | INSTR.FLOATREGS);
@ -2068,7 +2069,7 @@ void loaddata(ref CodeBuilder cdb, elem* e, ref regm_t outretregs)
if (tyfloating(tym))
{
const vreg = allocreg(cdb, forregs, tym); // allocate floating point register
float value = e.Vfloat;
double value = e.Vfloat;
if (sz == 8)
value = e.Vdouble;
loadFloatRegConst(cdb,vreg,value,sz);

View file

@ -38,7 +38,7 @@ import dmd.backend.ty;
import dmd.backend.type;
import dmd.backend.x86.xmm;
import dmd.backend.arm.cod1 : loadFromEA, storeToEA, getlvalue;
import dmd.backend.arm.cod3 : conditionCode, genBranch, gentstreg, movregconst, COND;
import dmd.backend.arm.cod3 : conditionCode, genBranch, gentstreg, movregconst, COND, loadFloatRegConst;
import dmd.backend.arm.instr;
nothrow:
@ -1786,24 +1786,17 @@ void cdpost(ref CGstate cg, ref CodeBuilder cdb,elem* e,ref regm_t pretregs)
//printf("cdpost(pretregs = %s)\n", regm_str(pretregs));
//elem_print(e);
const op = e.Eoper; // OPxxxx
if (pretregs == 0) // if nothing to return
if (pretregs == 0) // if nothing to return
{
cdaddass(cgstate,cdb,e,pretregs);
return;
}
const tym_t tyml = tybasic(e.E1.Ety);
const sz = _tysize[tyml];
elem* e2 = e.E2;
if (0 && tyfloating(tyml)) // TODO AArch64
const tym_t tyml = tybasic(e.E1.Ety);
if (tyfloating(tyml))
{
if (config.fpxmmregs && tyxmmreg(tyml) &&
!tycomplex(tyml) // SIMD code is not set up to deal with complex
)
{
xmmpost(cdb,e,pretregs);
return;
}
floatPost(cg, cdb, e, pretregs);
return;
}
if (0 && tyxmmreg(tyml)) // TODO AArch64
{
@ -1811,7 +1804,10 @@ void cdpost(ref CGstate cg, ref CodeBuilder cdb,elem* e,ref regm_t pretregs)
return;
}
const sz = _tysize[tyml];
elem* e2 = e.E2;
assert(e2.Eoper == OPconst);
regm_t possregs = cg.allregs;
code cs;
getlvalue(cdb,cs,e.E1,0);
@ -1915,6 +1911,130 @@ void cdpost(ref CGstate cg, ref CodeBuilder cdb,elem* e,ref regm_t pretregs)
}
}
/******************************
* Do OPpostinc and OPpostdec on floating point lvalue
*/
@trusted
void floatPost(ref CGstate cg, ref CodeBuilder cdb,elem* e,ref regm_t pretregs)
{
//printf("floatPost(pretregs = %s)\n", regm_str(pretregs));
//elem_print(e);
// Much similarity to xmmpost()
elem* e1 = e.E1;
elem* e2 = e.E2;
const tym_t ty1 = tybasic(e.E1.Ety);
const sz = _tysize[ty1];
const ftype = INSTR.szToFtype(sz);
regm_t retregs;
reg_t reg;
bool regvar = false;
if (config.flags4 & CFG4optimized)
{
// Be careful of cases like (x = x+x+x). We cannot evaluate in
// x if x is in a register.
reg_t varreg;
regm_t varregm;
if (isregvar(e1,varregm,varreg) && // if lvalue is register variable
doinreg(e1.Vsym,e2) // and we can compute directly into it
)
{
regvar = true;
retregs = varregm;
reg = varreg; // evaluate directly in target register
getregs(cdb,retregs); // destroy these regs
}
}
code cs;
if (!regvar)
{
getlvalue(cdb,cs,e1,0,RM.rw); // get EA
retregs = INSTR.FLOATREGS & ~pretregs;
if (!retregs)
retregs = INSTR.FLOATREGS;
reg = allocreg(cdb,retregs,ty1);
loadFromEA(cs,reg,sz == 8 ? 8 : 4,sz);
}
if (regvar && pretregs == mPSW)
{
tstresult(cdb, mask(reg),ty1,false);
// If lvalue is a register variable, mark it as modified
getregs(cdb,reg);
regm_t vretregs = INSTR.FLOATREGS & ~mask(cs.reg);
reg_t vreg = allocreg(cdb,vretregs,ty1);
double value = sz == 8 ? e2.Vdouble : e2.Vfloat;
loadFloatRegConst(cdb,vreg,value,sz); // FMOV vreg,value
switch (e.Eoper)
{
case OPpostinc:
cdb.gen1(INSTR.fadd_float(ftype,reg,vreg,reg)); // FADD Rd,Rn,Rm
break;
case OPpostdec:
cdb.gen1(INSTR.fsub_float(ftype,reg,vreg,reg)); // FSUB Rd,Rn,Rm
break;
default:
assert(0);
}
freenode(e2);
return;
}
// Result register
regm_t resultregs = INSTR.FLOATREGS & pretregs & ~retregs;
if (!resultregs)
resultregs = INSTR.FLOATREGS & ~retregs;
const resultreg = allocreg(cdb,resultregs, ty1);
cdb.gen1(INSTR.fmov(ftype,reg,resultreg)); // FMOV resultreg,reg
regm_t vretregs = INSTR.FLOATREGS & ~mask(reg) & ~mask(resultreg);
reg_t vreg = allocreg(cdb,vretregs,ty1);
double value = sz == 8 ? e2.Vdouble : e2.Vfloat;
loadFloatRegConst(cdb,vreg,value,sz); // FMOV vreg,value
switch (e.Eoper)
{
case OPpostinc:
cdb.gen1(INSTR.fadd_float(ftype,reg,vreg,reg)); // FADD Rd,Rn,Rm
break;
case OPpostdec:
cdb.gen1(INSTR.fsub_float(ftype,reg,vreg,reg)); // FSUB Rd,Rn,Rm
break;
default:
assert(0);
}
if (!regvar)
{
storeToEA(cs,reg,sz);
cdb.gen(&cs); // STR reg,EA
}
if (e1.Ecount || // if lvalue is a CSE or
regvar) // rvalue can't be a CSE
{
getregs_imm(cdb,retregs); // necessary if both lvalue and
// rvalue are CSEs (since a reg
// can hold only one e at a time)
cssave(e1,retregs,!OTleaf(e1.Eoper)); // if lvalue is a CSE
}
fixresult(cdb,e,resultregs,pretregs);
freenode(e1);
}
// cddctor
// cdddtor