From 5fcca3e15259262b36bd7e4e4bbf4d366f983813 Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Sun, 13 Apr 2025 23:35:36 -0700 Subject: [PATCH] add floatPost() (#21227) --- compiler/src/dmd/backend/arm/cod1.d | 5 +- compiler/src/dmd/backend/arm/cod2.d | 146 +++++++++++++++++++++++++--- 2 files changed, 136 insertions(+), 15 deletions(-) diff --git a/compiler/src/dmd/backend/arm/cod1.d b/compiler/src/dmd/backend/arm/cod1.d index 3b76f6d4da..160f7382b3 100644 --- a/compiler/src/dmd/backend/arm/cod1.d +++ b/compiler/src/dmd/backend/arm/cod1.d @@ -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); diff --git a/compiler/src/dmd/backend/arm/cod2.d b/compiler/src/dmd/backend/arm/cod2.d index 8f6f68f30e..646da582b5 100644 --- a/compiler/src/dmd/backend/arm/cod2.d +++ b/compiler/src/dmd/backend/arm/cod2.d @@ -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