Skip to content

Commit 78a7d57

Browse files
authored
fix cdneg() for integer, float, and 128 bit floats (dlang#21292)
1 parent 82141da commit 78a7d57

3 files changed

Lines changed: 56 additions & 20 deletions

File tree

compiler/src/dmd/backend/arm/cod2.d

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1658,43 +1658,60 @@ void cdneg(ref CGstate cg, ref CodeBuilder cdb,elem* e,ref regm_t pretregs)
16581658
const sz = _tysize[tyml];
16591659
if (tyfloating(tyml))
16601660
{
1661-
const posregs = INSTR.FLOATREGS;
1662-
regm_t retregs1 = posregs;
1661+
regm_t retregs1 = INSTR.FLOATREGS;
16631662
codelem(cgstate,cdb,e.E1,retregs1,false);
16641663

1665-
regm_t retregs = pretregs & posregs;
1664+
regm_t retregs = pretregs & INSTR.FLOATREGS;
16661665
if (retregs == 0) /* if no return regs speced */
16671666
/* (like if wanted flags only) */
1668-
retregs = FLOATREGS; // give us some
1669-
const Vd = allocreg(cdb, retregs, tyml);
1667+
retregs = INSTR.FLOATREGS; // give us some
1668+
codelem(cgstate,cdb,e.E1,retregs,false);
1669+
getregs(cdb,retregs); // retregs will be destroyed
16701670

1671-
const Vn = findreg(retregs1);
1671+
const Vn = findreg(retregs);
16721672

1673-
const ftype = INSTR.szToFtype(sz);
1674-
cdb.gen1(INSTR.fneg_float(ftype, Vn, Vd));
1673+
if (sz == 16) // 128 bit float
1674+
{
1675+
/* Generate:
1676+
FMOV Xn,Vn.d[1] // upper 64 bits
1677+
EOR Xn,Xn,#0x8000_0000_0000_0000 // toggle sign bit
1678+
FMOV Vn.d[1],Xn // store upper 64 bits
1679+
*/
1680+
// Alloc Xn
1681+
regm_t retregsx = cg.allregs;
1682+
const Xn = allocreg(cdb,retregsx,TYllong); // scratch register Xn
1683+
// https://www.scs.stanford.edu/~zyedidia/arm64/fmov_float_gen.html
1684+
cdb.gen1(INSTR.fmov_float_gen(1,2,1,6,Vn,Xn)); // Top half of 128-bit to 64-bit
1685+
uint N, immr, imms;
1686+
assert(encodeNImmrImms(0x8000_0000_0000_0000,N,immr,imms));
1687+
uint sf = 1, opc = 2;
1688+
cdb.gen1(INSTR.log_imm(sf,opc,N,immr,imms,Xn,Xn)); // https://www.scs.stanford.edu/~zyedidia/arm64/eor_log_imm.html
1689+
cdb.gen1(INSTR.fmov_float_gen(1,2,1,7,Xn,Vn)); // 64-bit to top half of 128-bit
1690+
}
1691+
else
1692+
{
1693+
const ftype = INSTR.szToFtype(sz);
1694+
cdb.gen1(INSTR.fneg_float(ftype, Vn, Vn));
1695+
}
16751696
fixresult(cdb,e,retregs,pretregs);
16761697
return;
16771698
}
16781699

1679-
const posregs = cgstate.allregs;
1680-
regm_t retregs1 = posregs;
1681-
codelem(cgstate,cdb,e.E1,retregs1,false);
16821700

16831701
regm_t retregs = pretregs & cg.allregs;
1684-
if (retregs == 0) /* if no return regs speced */
1685-
/* (like if wanted flags only) */
1686-
retregs = ALLREGS & posregs; // give us some
1687-
reg_t Rd = allocreg(cdb, retregs, tyml);
1688-
1689-
const Rm = findreg(retregs1);
1702+
if (retregs == 0) // if no return regs speced
1703+
retregs = cg.allregs; // give us some
1704+
codelem(cg,cdb,e.E1,retregs,false);
1705+
getregs(cdb,retregs); // retregs will be destroyed
1706+
const Rm = findreg(retregs);
16901707

16911708
/* NEG https://www.scs.stanford.edu/~zyedidia/arm64/neg_sub_addsub_shift.html
16921709
* NEGS https://www.scs.stanford.edu/~zyedidia/arm64/negs_subs_addsub_shift.html
16931710
*/
16941711

16951712
uint sf = sz == 8;
16961713
uint S = (pretregs & mPSW) != 0; // NEG/NEGS
1697-
cdb.gen1(INSTR.addsub_shift(sf,1,S,0,Rm,0,31,Rd)); // NEG/NEGS <Rd>,<Rm>
1714+
cdb.gen1(INSTR.addsub_shift(sf,1,S,0,Rm,0,31,Rm)); // NEG/NEGS <Rm>,<Rm>
16981715

16991716
pretregs &= ~mPSW; // flags already set
17001717
fixresult(cdb,e,retregs,pretregs);

compiler/src/dmd/backend/arm/disasmarm.d

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2073,7 +2073,7 @@ void disassemble(uint c) @trusted
20732073

20742074
if (S == 0)
20752075
{
2076-
p1 = "fmov";
2076+
p1 = "fmov"; // https://www.scs.stanford.edu/~zyedidia/arm64/fmov_float_gen.html
20772077

20782078
if (sf == 0 && ftype == 0 && rmode == 0 && opcode == 7)
20792079
{
@@ -2107,6 +2107,18 @@ void disassemble(uint c) @trusted
21072107
p2 = fregString(rbuf[4 .. 8],"sd h"[ftype],Rd);
21082108
p3 = regString(sf,Rn);
21092109
}
2110+
else if (sf == 1 && ftype == 2 && rmode == 1 && opcode == 6) // top half to 64 bit
2111+
{
2112+
p2 = regString(sf,Rd);
2113+
const n = snprintf(rbuf.ptr, rbuf.length, "v%d.d[1]", Rn);
2114+
p3 = rbuf[0 .. n];
2115+
}
2116+
else if (sf == 1 && ftype == 2 && rmode == 1 && opcode == 7) // 64 bit to top half
2117+
{
2118+
const n = snprintf(rbuf.ptr, rbuf.length, "v%d.d[1]", Rd);
2119+
p2 = rbuf[0 .. n];
2120+
p3 = regString(sf,Rn);
2121+
}
21102122
}
21112123
}
21122124
else
@@ -2981,9 +2993,10 @@ unittest
29812993
unittest
29822994
{
29832995
int line64 = __LINE__;
2984-
string[82] cases64 = // 64 bit code gen
2996+
string[83] cases64 = // 64 bit code gen
29852997
[
29862998
"6F 00 E4 01 movi v1.2d,#0x0",
2999+
"9E AF 00 3E fmov v30.d[1],x1",
29873000
"4E BE 1F C0 mov v0.16b,v30.16b",
29883001
"D4 20 00 20 brk #1",
29893002
"D6 3F 00 00 blr x0",

compiler/src/dmd/backend/arm/instr.d

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -744,9 +744,15 @@ struct INSTR
744744
static uint fmov_float_gen(uint sf, uint ftype, uint rmode, uint opcode, reg_t Rn, reg_t Rd)
745745
{
746746
if (opcode == 7)
747+
{
748+
assert(Rd & 32);
747749
Rd &= 31;
750+
}
748751
else if (opcode == 6)
752+
{
753+
assert(Rn & 32);
749754
Rn &= 31;
755+
}
750756
return float2int(sf, 0, ftype, rmode, opcode, Rn, Rd);
751757
}
752758

0 commit comments

Comments
 (0)