@@ -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);
0 commit comments