add floating support to tstresult() (#20884)

This commit is contained in:
Walter Bright 2025-02-17 03:07:45 -08:00 committed by GitHub
parent c0c1b0ab12
commit ef47ecf0a2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 26 additions and 117 deletions

View file

@ -1162,40 +1162,28 @@ void getlvalue(ref CodeBuilder cdb,ref code pcs,elem* e,regm_t keepmsk,RM rm = R
// fltregs
/*****************************
* Given a result in registers, test it for true or false.
* Will fail if TYfptr and the reg is ES!
* If saveflag is true, preserve the contents of the
* registers.
* Given a result in registers regm, test it for true or false.
* Params:
* cdb = generated code sink
* regm = result register(s) and mPSW
* tym = type of result
* saveflag = true means preserve the contents of the registers
*/
@trusted
void tstresult(ref CodeBuilder cdb, regm_t regm, tym_t tym, bool saveflag)
{
reg_t scrreg; // scratch register
regm_t scrregm;
//if (!(regm & (mBP | ALLREGS)))
//printf("tstresult(regm = %s, tym = x%x, saveflag = %d)\n",
//regm_str(regm),tym,saveflag);
//printf("tstresult(regm = %s, tym = x%x, saveflag = %d)\n",regm_str(regm),tym,saveflag);
tym = tybasic(tym);
reg_t reg = findreg(regm);
uint sz = _tysize[tym];
assert(regm & cgstate.allregs);
static if (0)
{
assert(regm & (XMMREGS | mBP | ALLREGS));
if (sz == 1)
{
assert(regm & BYTEREGS);
genregs(cdb, 0x84, reg, reg); // TEST regL,regL
if (I64 && reg >= 4)
code_orrex(cdb.last(), REX);
return;
}
assert(regm & (cgstate.allregs | INSTR.FLOATREGS));
static if (0)
if (regm & XMMREGS)
{
regm_t xregs = XMMREGS & ~regm;
const xreg = allocreg(cdb,xregs, TYdouble);
const xreg = allocreg(cdb,xregs,TYdouble);
opcode_t op = 0;
if (tym == TYdouble || tym == TYidouble || tym == TYcdouble)
op = 0x660000;
@ -1211,104 +1199,16 @@ static if (0)
}
return;
}
}
if (sz <= REGSIZE)
if (tyfloating(tym))
{
if (tym == TYfloat)
{
if (saveflag)
{
scrregm = cgstate.allregs & ~regm; // possible scratch regs
scrreg = allocreg(cdb, scrregm, TYoffset); // allocate scratch reg
genmovreg(cdb, scrreg, reg); // MOV scrreg,msreg
reg = scrreg;
}
getregs(cdb, mask(reg));
cdb.gen2(0xD1, modregrmx(3, 4, reg)); // SHL reg,1
return;
}
}
gentstreg(cdb,reg,sz == 8); // CMP reg,#0
static if (0)
{
if (saveflag || tyfv(tym))
{
L1:
scrregm = ALLREGS & ~regm; // possible scratch regs
scrreg = allocreg(cdb, scrregm, TYoffset); // allocate scratch reg
if (I32 || sz == REGSIZE * 2)
{
assert(regm & mMSW && regm & mLSW);
reg = findregmsw(regm);
if (I32)
{
if (tyfv(tym))
genregs(cdb, MOVZXw, scrreg, reg); // MOVZX scrreg,msreg
else
{
genmovreg(cdb, scrreg, reg); // MOV scrreg,msreg
if (tym == TYdouble || tym == TYdouble_alias)
cdb.gen2(0xD1, modregrm(3, 4, scrreg)); // SHL scrreg,1
}
}
else
{
genmovreg(cdb, scrreg, reg); // MOV scrreg,msreg
if (tym == TYfloat)
cdb.gen2(0xD1, modregrm(3, 4, scrreg)); // SHL scrreg,1
}
reg = findreglsw(regm);
genorreg(cdb, scrreg, reg); // OR scrreg,lsreg
}
else if (sz == 8)
{
// !I32
genmovreg(cdb, scrreg, AX); // MOV scrreg,AX
if (tym == TYdouble || tym == TYdouble_alias)
cdb.gen2(0xD1 ,modregrm(3, 4, scrreg)); // SHL scrreg,1
genorreg(cdb, scrreg, BX); // OR scrreg,BX
genorreg(cdb, scrreg, CX); // OR scrreg,CX
genorreg(cdb, scrreg, DX); // OR scrreg,DX
}
else
assert(0);
const ftype = INSTR.szToFtype(sz);
cdb.gen1(INSTR.fcmp_float(ftype,0,reg)); // FCMP Vn,#0.0
}
else
{
if (I32 || sz == REGSIZE * 2)
{
// can't test ES:LSW for 0
assert(regm & mMSW & ALLREGS && regm & (mLSW | mBP));
reg = findregmsw(regm);
if (cgstate.regcon.mvar & mask(reg)) // if register variable
goto L1; // don't trash it
getregs(cdb, mask(reg)); // we're going to trash reg
if (tyfloating(tym) && sz == 2 * _tysize[TYint])
cdb.gen2(0xD1, modregrm(3 ,4, reg)); // SHL reg,1
genorreg(cdb, reg, findreglsw(regm)); // OR reg,reg+1
if (I64)
code_orrex(cdb.last(), REX_W);
}
else if (sz == 8)
{ assert(regm == DOUBLEREGS_16);
getregs(cdb,mAX); // allocate AX
if (tym == TYdouble || tym == TYdouble_alias)
cdb.gen2(0xD1, modregrm(3, 4, AX)); // SHL AX,1
genorreg(cdb, AX, BX); // OR AX,BX
genorreg(cdb, AX, CX); // OR AX,CX
genorreg(cdb, AX, DX); // OR AX,DX
}
else
assert(0);
}
gentstreg(cdb,reg,sz == 8); // CMP reg,#0
code_orflag(cdb.last(),CFpsw);
}
}
/******************************

View file

@ -2048,7 +2048,7 @@ void disassemble(uint c) @trusted
{
p1 = opcode2 & 0x10 ? "fcmpe" : "fcmp";
p2 = fregString(rbuf[0..4],"sd h"[ftype],Rn);
p3 = (Rm == 0 && (opcode2 & 0x18) == 0x18) ? "#0.0" : fregString(rbuf[4..8],"sd h"[ftype],Rm);
p3 = (Rm == 0 && (opcode2 & 8)) ? "#0.0" : fregString(rbuf[4..8],"sd h"[ftype],Rm);
}
}

View file

@ -761,6 +761,15 @@ struct INSTR
return floatcmp(0, 0, ftype, Vm & 31, 0, Vn & 31, opcode2);
}
/* FCMP Vn,Vm https://www.scs.stanford.edu/~zyedidia/arm64/fcmp_float.html
* FCMP Vn,#0.0
*/
static uint fcmp_float(uint ftype, reg_t Vm, reg_t Vn)
{
uint opcode2 = Vm == 0 ? 8 : 0; // Vm is 0 for FCMP Vn,#0.0
return floatcmp(0, 0, ftype, Vm & 31, 0, Vn & 31, opcode2);
}
/* Floating-point immediate
* FMOV (scalar, immediate)
* FMOV <Vd>,#<imm> https://www.scs.stanford.edu/~zyedidia/arm64/fmov_float_imm.html