Skip to content

Commit

Permalink
[RISC-V] Flush-to-zero behavior for float-to-int conversion (#94762)
Browse files Browse the repository at this point in the history
* Implemented several RISC-V csr instructions and enabled flush-to-zero behavior for float-to-int conversion instruction

* Apply comments

* Replace branch solution with feq

* Fixed typo

* Fixed typo

* Fixed csr instructions emitter

* Apply comments

* Apply jit-format

* Apply comments

* Temp register fix

* Fixed dstSize

* Wrong temporary register selection fix

* Fixed typo
  • Loading branch information
denis-paranichev committed Dec 7, 2023
1 parent 03c2d25 commit 90dc96e
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 0 deletions.
18 changes: 18 additions & 0 deletions src/coreclr/jit/codegenriscv64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3385,8 +3385,26 @@ void CodeGen::genFloatToIntCast(GenTree* treeNode)

genConsumeOperands(treeNode->AsOp());

regNumber tmpReg = treeNode->GetSingleTempReg();
assert(tmpReg != treeNode->GetRegNum());
assert(tmpReg != op1->GetRegNum());

GetEmitter()->emitIns_R_R(ins, dstSize, treeNode->GetRegNum(), op1->GetRegNum());

// This part emulates the "flush to zero" option because the RISC-V specification does not provide it.
instruction feq_ins = INS_feq_s;
if (srcType == TYP_DOUBLE)
{
feq_ins = INS_feq_d;
}
// Compare op1 with itself to get 0 if op1 is NaN and 1 for any other value
GetEmitter()->emitIns_R_R_R(feq_ins, dstSize, tmpReg, op1->GetRegNum(), op1->GetRegNum());
// Get subtraction result of REG_ZERO (always 0) and feq result
// As a result we get 0 for NaN and -1 (all bits set) for any other value
GetEmitter()->emitIns_R_R_R(INS_sub, dstSize, tmpReg, REG_ZERO, tmpReg);
// and instruction with received mask produces 0 for NaN and preserves any other value
GetEmitter()->emitIns_R_R_R(INS_and, dstSize, treeNode->GetRegNum(), treeNode->GetRegNum(), tmpReg);

genProduceReg(treeNode);
}

Expand Down
87 changes: 87 additions & 0 deletions src/coreclr/jit/emitriscv64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,15 @@ void emitter::emitIns_R_R_I(
code |= ((imm >> 5) & 0x3f) << 25;
code |= ((imm >> 12) & 0x1) << 31;
}
else if (ins == INS_csrrs || ins == INS_csrrw || ins == INS_csrrc)
{
assert(isGeneralRegisterOrR0(reg1));
assert(isGeneralRegisterOrR0(reg2));
assert(isValidUimm12(imm));
code |= reg1 << 7;
code |= reg2 << 15;
code |= imm << 20;
}
else
{
NYI_RISCV64("illegal ins within emitIns_R_R_I!");
Expand All @@ -704,6 +713,39 @@ void emitter::emitIns_R_R_I(
appendToCurIG(id);
}

/*****************************************************************************
*
* Add an instruction referencing register and two constants.
*/

void emitter::emitIns_R_I_I(
instruction ins, emitAttr attr, regNumber reg1, ssize_t imm1, ssize_t imm2, insOpts opt) /* = INS_OPTS_NONE */
{
code_t code = emitInsCode(ins);

if (INS_csrrwi <= ins && ins <= INS_csrrci)
{
assert(isGeneralRegisterOrR0(reg1));
assert(isValidUimm5(imm1));
assert(isValidUimm12(imm2));
code |= reg1 << 7;
code |= imm1 << 15;
code |= imm2 << 20;
}
else
{
NYI_RISCV64("illegal ins within emitIns_R_I_I!");
}
instrDesc* id = emitNewInstr(attr);

id->idIns(ins);
id->idReg1(reg1);
id->idAddr()->iiaSetInstrEncode(code);
id->idCodeSize(4);

appendToCurIG(id);
}

/*****************************************************************************
*
* Add an instruction referencing three registers.
Expand Down Expand Up @@ -3351,6 +3393,51 @@ void emitter::emitDisInsName(code_t code, const BYTE* addr, instrDesc* id)
}
case 0x73:
{
unsigned int opcode2 = (code >> 12) & 0x7;
if (opcode2 != 0)
{
const char* rd = RegNames[(code >> 7) & 0x1f];
int csrtype = (code >> 20);
if (opcode2 <= 0x3)
{
const char* rs1 = RegNames[(code >> 15) & 0x1f];
switch (opcode2)
{
case 0x1: // CSRRW
printf("csrrw %s, %d, %s\n", rd, csrtype, rs1);
return;
case 0x2: // CSRRS
printf("csrrs %s, %d, %s\n", rd, csrtype, rs1);
return;
case 0x3: // CSRRC
printf("csrrc %s, %d, %s\n", rd, csrtype, rs1);
return;
default:
printf("RISCV64 illegal instruction: 0x%08X\n", code);
break;
}
}
else
{
unsigned imm5 = ((code >> 15) & 0x1f);
switch (opcode2)
{
case 0x5: // CSRRWI
printf("csrrwi %s, %d, %d\n", rd, csrtype, imm5);
return;
case 0x6: // CSRRSI
printf("csrrsi %s, %d, %d\n", rd, csrtype, imm5);
return;
case 0x7: // CSRRCI
printf("csrrci %s, %d, %d\n", rd, csrtype, imm5);
return;
default:
printf("RISCV64 illegal instruction: 0x%08X\n", code);
break;
}
}
}

if (code == emitInsCode(INS_ebreak))
{
printf("ebreak\n");
Expand Down
9 changes: 9 additions & 0 deletions src/coreclr/jit/emitriscv64.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,12 @@ static bool isValidUimm11(ssize_t value)
return (0 == (value >> 11));
}

// Returns true if 'value' is a legal unsigned immediate 5 bit encoding.
static bool isValidUimm5(ssize_t value)
{
return (0 == (value >> 5));
}

// Returns true if 'value' is a legal signed immediate 20 bit encoding.
static bool isValidSimm20(ssize_t value)
{
Expand Down Expand Up @@ -189,6 +195,9 @@ void emitIns_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2,
void emitIns_R_R_I(
instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, ssize_t imm, insOpts opt = INS_OPTS_NONE);

void emitIns_R_I_I(
instruction ins, emitAttr attr, regNumber reg1, ssize_t imm1, ssize_t imm2, insOpts opt = INS_OPTS_NONE);

void emitIns_R_R_R(
instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber reg3, insOpts opt = INS_OPTS_NONE);

Expand Down
6 changes: 6 additions & 0 deletions src/coreclr/jit/lsrariscv64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1394,6 +1394,12 @@ int LinearScan::BuildCast(GenTreeCast* cast)
int srcCount = BuildOperandUses(cast->CastOp());
BuildDef(cast);

if (varTypeIsFloating(cast->gtOp1) && !varTypeIsFloating(cast->TypeGet()))
{
buildInternalIntRegisterDefForNode(cast);
buildInternalRegisterUses();
}

return srcCount;
}

Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/registerriscv64.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ REGDEF(T5, 30, 0x40000000, "t5" )
REGDEF(T6, 31, 0x80000000, "t6" )

REGALIAS(R8, FP)
REGALIAS(ZERO, R0)

#define FBASE 32
#define FMASK(x) (1ULL << (FBASE+(x)))
Expand Down

0 comments on commit 90dc96e

Please sign in to comment.