diff --git a/compiler/src/dmd/backend/arm/cod4.d b/compiler/src/dmd/backend/arm/cod4.d index e8d8f01dba3..43e62f4f58c 100644 --- a/compiler/src/dmd/backend/arm/cod4.d +++ b/compiler/src/dmd/backend/arm/cod4.d @@ -55,8 +55,8 @@ nothrow: @trusted void cdeq(ref CGstate cg, ref CodeBuilder cdb,elem* e,ref regm_t pretregs) { - //printf("cdeq(e = %p, pretregs = %s)\n",e,regm_str(pretregs)); - //elem_print(e); + printf("cdeq(e = %p, pretregs = %s)\n",e,regm_str(pretregs)); + elem_print(e); reg_t reg; code cs; @@ -255,8 +255,8 @@ void cdaddass(ref CGstate cg, ref CodeBuilder cdb,elem* e,ref regm_t pretregs) if (tyfloating(tyml)) { - floatOpAss(cdb,e,pretregs); - return; + floatOpAss(cdb,e,pretregs); + return; } regm_t forccs = pretregs & mPSW; // return result in flags regm_t forregs = pretregs & ~mPSW; // return result in regs @@ -430,17 +430,64 @@ void cdaddass(ref CGstate cg, ref CodeBuilder cdb,elem* e,ref regm_t pretregs) } /******************************** - * Generate code for op= + * Generate code for op=, OPnegass */ @trusted void floatOpAss(ref CodeBuilder cdb,elem* e,ref regm_t pretregs) { - printf("floatOpass(e=%p, pretregs = %s)\n",e,regm_str(pretregs)); - elem_print(e); + //printf("floatOpass(e=%p, pretregs = %s)\n",e,regm_str(pretregs)); + //elem_print(e); elem* e1 = e.E1; - elem* e2 = e.E2; tym_t ty1 = tybasic(e1.Ety); const sz1 = _tysize[ty1]; + code cs; + regm_t retregs; + reg_t reg; + + if (e.Eoper == OPnegass) + { + bool regvar; + getlvalue(cdb,cs,e1,0); + if (cs.reg == NOREG) + { + retregs = INSTR.FLOATREGS; + reg = allocreg(cdb,retregs,ty1); + } + else + { + regvar = true; + retregs = mask(cs.reg); + getregs(cdb,retregs); + reg = cs.reg; + } + uint szw = sz1 == 8 ? 8 : 4; + loadFromEA(cs, reg, szw, sz1); + cdb.gen(&cs); + assert(reg & 32); + uint ftype = sz1 == 2 ? 3 : + sz1 == 4 ? 0 : 1; + cdb.gen1(INSTR.fneg_float(ftype, reg, reg)); // fneg reg,reg + storeToEA(cs, reg, szw); + cdb.gen(&cs); + + retregs = mask(reg); + pretregs &= ~mPSW; + + 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,retregs,pretregs); + freenode(e1); + return; + } + + elem* e2 = e.E2; regm_t rretregs = INSTR.FLOATREGS & ~pretregs; if (!rretregs) rretregs = INSTR.FLOATREGS; @@ -449,11 +496,8 @@ rretregs = 1L << 34; // until loaddata() works codelem(cgstate,cdb,e2,rretregs,false); // eval right leaf reg_t rreg = findreg(rretregs); - code cs; - regm_t retregs; - reg_t reg; bool regvar = false; - if (config.flags4 & CFG4optimized) + if (0 && config.flags4 & CFG4optimized) { // Be careful of cases like (x = x+x+x). We cannot evaluate in // x if x is in a register. @@ -476,35 +520,35 @@ rretregs = 1L << 34; // until loaddata() works if (!retregs) retregs = INSTR.FLOATREGS & ~rretregs; reg = allocreg(cdb,retregs,ty1); - loadFromEA(cs,reg,sz1,sz1); - cdb.gen(&cs); + loadFromEA(cs,reg,sz1,sz1); + cdb.gen(&cs); } reg_t Rd = reg, Rn = rreg, Rm = reg; uint ftype = sz1 == 2 ? 3 : - sz1 == 4 ? 0 : 1; + sz1 == 4 ? 0 : 1; switch (e.Eoper) { - // FADD/FSUB (extended register) - // http://www.scs.stanford.edu/~zyedidia/arm64/encodingindex.html#addsub_ext - case OPaddass: - cdb.gen1(INSTR.fadd_float(ftype,Rm,Rn,Rd)); // FADD Rd,Rn,Rm - break; - - case OPminass: - cdb.gen1(INSTR.fsub_float(ftype,Rm,Rn,Rd)); // FSUB Rd,Rn,Rm - break; - - case OPmulass: - cdb.gen1(INSTR.fmul_float(ftype,Rm,Rn,Rd)); // FMUL Rd,Rn,Rm - break; - - case OPdivass: - cdb.gen1(INSTR.fdiv_float(ftype,Rm,Rn,Rd)); // FDIV Rd,Rn,Rm - break; - - default: - assert(0); + // FADD/FSUB (extended register) + // http://www.scs.stanford.edu/~zyedidia/arm64/encodingindex.html#addsub_ext + case OPaddass: + cdb.gen1(INSTR.fadd_float(ftype,Rm,Rn,Rd)); // FADD Rd,Rn,Rm + break; + + case OPminass: + cdb.gen1(INSTR.fsub_float(ftype,Rm,Rn,Rd)); // FSUB Rd,Rn,Rm + break; + + case OPmulass: + cdb.gen1(INSTR.fmul_float(ftype,Rm,Rn,Rd)); // FMUL Rd,Rn,Rm + break; + + case OPdivass: + cdb.gen1(INSTR.fdiv_float(ftype,Rm,Rn,Rd)); // FDIV Rd,Rn,Rm + break; + + default: + assert(0); } if (!regvar) @@ -551,8 +595,8 @@ void cdmulass(ref CGstate cg, ref CodeBuilder cdb,elem* e,ref regm_t pretregs) if (tyfloating(tyml)) { - floatOpAss(cdb,e,pretregs); - return; + floatOpAss(cdb,e,pretregs); + return; } assert(sz <= REGSIZE); @@ -618,8 +662,8 @@ void cddivass(ref CGstate cg, ref CodeBuilder cdb,elem* e,ref regm_t pretregs) if (tyfloating(tyml)) { - floatOpAss(cdb,e,pretregs); - return; + floatOpAss(cdb,e,pretregs); + return; } code cs; diff --git a/compiler/src/dmd/backend/arm/instr.d b/compiler/src/dmd/backend/arm/instr.d index 2163dc3b875..2c10680c6c4 100644 --- a/compiler/src/dmd/backend/arm/instr.d +++ b/compiler/src/dmd/backend/arm/instr.d @@ -734,6 +734,10 @@ struct INSTR */ static uint fcvt_float(uint ftype, uint opcode, reg_t Vn, reg_t Vd) { return floatdp1(0,0,ftype,opcode,Vn & 31,Vd & 31); } + /* FNEG fpreg,fpreg https://www.scs.stanford.edu/~zyedidia/arm64/fneg_float.html + */ + static uint fneg_float(uint ftype, reg_t Vn, reg_t Vd) { return floatdp1(0,0,ftype,2,Vn & 31,Vd & 31); } + /* Floating-point compare */ /* Floating-point immediate