LclVarDsc* varDsc = compiler->lvaGetDesc(lclNode);
if (lclNode->IsMultiReg())
{
+ // This is the case of storing to a multi-reg local, currently supported
+ // only in ARM64 CodeGen. It may require HFA and SIMD features enabled.
NYI_RISCV64("genCodeForStoreLclVar-----unimplemented on RISCV64 yet----");
- regNumber operandReg = genConsumeReg(data);
- unsigned int regCount = varDsc->lvFieldCnt;
- for (unsigned i = 0; i < regCount; ++i)
- {
- regNumber varReg = lclNode->GetRegByIndex(i);
- assert(varReg != REG_NA);
- unsigned fieldLclNum = varDsc->lvFieldLclStart + i;
- LclVarDsc* fieldVarDsc = compiler->lvaGetDesc(fieldLclNum);
- assert(fieldVarDsc->TypeGet() == TYP_FLOAT);
- GetEmitter()->emitIns_R_R_I(INS_sd, emitTypeSize(TYP_FLOAT), varReg, operandReg, i);
- }
- genProduceReg(lclNode);
}
else
{
ins = INS_fdiv_d;
}
break;
- case GT_NEG:
- NYI_RISCV64("GT_NEG-----unimplemented/unused on RISCV64 yet----");
- break;
default:
- NYI_RISCV64("Unhandled oper in genGetInsForOper() - float");
- unreached();
+ NO_WAY("Unhandled oper in genGetInsForOper() - float");
break;
}
}
}
break;
- case GT_NEG:
- NYI_RISCV64("GT_NEG-----unimplemented/unused on RISCV64 yet----");
- break;
-
- case GT_NOT:
- NYI_RISCV64("GT_NEG-----unimplemented/unused on RISCV64 yet----");
- break;
-
case GT_AND:
isImm = isImmed(treeNode);
if (isImm)
break;
default:
- NYI_RISCV64("Unhandled oper in genGetInsForOper() - integer");
- unreached();
+ NO_WAY("Unhandled oper in genGetInsForOper() - integer");
break;
}
}
// Arguments:
// tree - the GT_SWAP node
//
-void CodeGen::genCodeForSwap(GenTreeOp* tree)
+void CodeGen::genCodeForSwap(GenTreeOp*)
{
+ // For now GT_SWAP handling is only (partially) supported in ARM64 and XARCH CodeGens.
NYI_RISCV64("genCodeForSwap-----unimplemented/unused on RISCV64 yet----");
}
return callerSPtoSPdelta;
}
+// Produce generic and unoptimized code for loading constant to register and dereferencing it
+// at the end
+static void emitLoadConstAtAddr(emitter* emit, regNumber dstRegister, ssize_t imm)
+{
+ ssize_t high = (imm >> 32) & 0xffffffff;
+ emit->emitIns_R_I(INS_lui, EA_PTRSIZE, dstRegister, (((high + 0x800) >> 12) & 0xfffff));
+ emit->emitIns_R_R_I(INS_addi, EA_PTRSIZE, dstRegister, dstRegister, (high & 0xfff));
+
+ ssize_t low = imm & 0xffffffff;
+ emit->emitIns_R_R_I(INS_slli, EA_PTRSIZE, dstRegister, dstRegister, 11);
+ emit->emitIns_R_R_I(INS_addi, EA_PTRSIZE, dstRegister, dstRegister, ((low >> 21) & 0x7ff));
+
+ emit->emitIns_R_R_I(INS_slli, EA_PTRSIZE, dstRegister, dstRegister, 11);
+ emit->emitIns_R_R_I(INS_addi, EA_PTRSIZE, dstRegister, dstRegister, ((low >> 10) & 0x7ff));
+ emit->emitIns_R_R_I(INS_ld, EA_PTRSIZE, dstRegister, dstRegister, (low & 0x3ff));
+}
+
/*****************************************************************************
* Emit a call to a helper function.
*/
}
else
{
- ssize_t high = (((ssize_t)pAddr) >> 32) & 0xffffffff;
- GetEmitter()->emitIns_R_I(INS_lui, EA_PTRSIZE, callTarget, (((high + 0x800) >> 12) & 0xfffff));
- GetEmitter()->emitIns_R_R_I(INS_addi, EA_PTRSIZE, callTarget, callTarget, (high & 0xfff));
-
- ssize_t low = ((ssize_t)pAddr) & 0xffffffff;
- GetEmitter()->emitIns_R_R_I(INS_slli, EA_PTRSIZE, callTarget, callTarget, 11);
- GetEmitter()->emitIns_R_R_I(INS_addi, EA_PTRSIZE, callTarget, callTarget, ((low >> 21) & 0x7ff));
-
- GetEmitter()->emitIns_R_R_I(INS_slli, EA_PTRSIZE, callTarget, callTarget, 11);
- GetEmitter()->emitIns_R_R_I(INS_addi, EA_PTRSIZE, callTarget, callTarget, ((low >> 10) & 0x7ff));
- GetEmitter()->emitIns_R_R_I(INS_ld, EA_PTRSIZE, callTarget, callTarget, (low & 0x3ff));
+ emitLoadConstAtAddr(GetEmitter(), callTarget, (ssize_t)pAddr);
}
regSet.verifyRegUsed(callTarget);
genEmitHelperCall(CORINFO_HELP_MEMSET, 0, EA_UNKNOWN);
}
-// Generate code for a load from some address + offset
-// base: tree node which can be either a local address or arbitrary node
-// offset: distance from the base from which to load
-void CodeGen::genCodeForLoadOffset(instruction ins, emitAttr size, regNumber dst, GenTree* base, unsigned offset)
-{
- NYI_RISCV64("genCodeForLoadOffset-----unimplemented on RISCV64 yet----");
-}
-
//------------------------------------------------------------------------
// genCall: Produce code for a GT_CALL node
//
if (addr == nullptr)
{
- NYI_RISCV64("part of genJumpToThrowHlpBlk_la-----unimplemented on RISCV64 yet----");
callType = emitter::EC_INDIR_R;
callTarget = REG_DEFAULT_HELPER_CALL_TARGET;
+ if (compiler->opts.compReloc)
+ {
+ ssize_t imm = (3 + 1) << 2;
+ emit->emitIns_R_R_I(ins, EA_PTRSIZE, reg1, reg2, imm);
+ emit->emitIns_R_AI(INS_jal, EA_PTR_DSP_RELOC, callTarget, (ssize_t)pAddr);
+ }
+ else
+ {
+ ssize_t imm = 9 << 2;
+ emit->emitIns_R_R_I(ins, EA_PTRSIZE, reg1, reg2, imm);
+ // TODO-RISCV64-CQ: In the future we may consider using emitter::emitLoadImmediate instead,
+ // which is less straightforward but offers slightly better codegen.
+ emitLoadConstAtAddr(GetEmitter(), callTarget, (ssize_t)pAddr);
+ }
+ regSet.verifyRegUsed(callTarget);
}
else
{ // INS_OPTS_C
return emitJumpKindInstructions[jumpKind];
}
-/*****************************************************************************
-* Look up the jump kind for an instruction. It better be a conditional
-* branch instruction with a jump kind!
-*/
-
-/*static*/ emitJumpKind emitter::emitInsToJumpKind(instruction ins)
-{
- NYI_RISCV64("emitInsToJumpKind-----unimplemented on RISCV64 yet----");
- return EJ_NONE;
-}
-
/*****************************************************************************
* Reverse the conditional jump
*/
code |= ((imm >> 20) & 0x1) << 31;
break;
default:
- NYI_RISCV64("illegal ins within emitIns_I!");
+ NO_WAY("illegal ins within emitIns_I!");
}
instrDesc* id = emitNewInstr(attr);
code |= ((imm >> 20) & 0x1) << 31;
break;
default:
- NYI_RISCV64("illegal ins within emitIns_R_I!");
+ NO_WAY("illegal ins within emitIns_R_I!");
break;
} // end switch (ins)
return;
}
default:
- NYI_RISCV64("illegal ins within emitDisInsName!");
+ NO_WAY("illegal ins within emitDisInsName!");
}
- NYI_RISCV64("illegal ins within emitDisInsName!");
+ NO_WAY("illegal ins within emitDisInsName!");
}
/*****************************************************************************
ins = INS_sd;
break;
default:
- NYI_RISCV64("illegal ins within emitInsLoadStoreOp!");
+ NO_WAY("illegal ins within emitInsLoadStoreOp!");
}
if (lsl > 0)
GenTreeIntConCommon* intConst = nullptr;
GenTree* nonIntReg = nullptr;
- bool needCheckOv = dst->gtOverflowEx();
+ const bool needCheckOv = dst->gtOverflowEx();
if (varTypeIsFloating(dst))
{
if (needCheckOv)
{
- if (ins == INS_addi || ins == INS_addiw)
+ // At this point andi/ori/xori are excluded by previous checks
+ assert(ins == INS_addi || ins == INS_addiw);
+
+ // AS11 = B + C
+ if ((dst->gtFlags & GTF_UNSIGNED) != 0)
{
- // AS11 = B + C
- if ((dst->gtFlags & GTF_UNSIGNED) != 0)
- {
- codeGen->genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_bltu, dst->GetRegNum(), nullptr,
- codeGen->rsGetRsvdReg());
- }
- else
+ codeGen->genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_bltu, dst->GetRegNum(), nullptr,
+ codeGen->rsGetRsvdReg());
+ }
+ else
+ {
+ if (imm > 0)
{
- if (imm > 0)
- {
- // B > 0 and C > 0, if A < B, goto overflow
- BasicBlock* tmpLabel = codeGen->genCreateTempLabel();
- emitIns_J_cond_la(INS_bge, tmpLabel, REG_R0, codeGen->rsGetRsvdReg());
- emitIns_R_R_I(INS_slti, EA_PTRSIZE, codeGen->rsGetRsvdReg(), dst->GetRegNum(), imm);
+ // B > 0 and C > 0, if A < B, goto overflow
+ BasicBlock* tmpLabel = codeGen->genCreateTempLabel();
+ emitIns_J_cond_la(INS_bge, tmpLabel, REG_R0, codeGen->rsGetRsvdReg());
+ emitIns_R_R_I(INS_slti, EA_PTRSIZE, codeGen->rsGetRsvdReg(), dst->GetRegNum(), imm);
- codeGen->genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_bne, codeGen->rsGetRsvdReg());
+ codeGen->genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_bne, codeGen->rsGetRsvdReg());
- codeGen->genDefineTempLabel(tmpLabel);
- }
- else if (imm < 0)
- {
- // B < 0 and C < 0, if A > B, goto overflow
- BasicBlock* tmpLabel = codeGen->genCreateTempLabel();
- emitIns_J_cond_la(INS_bge, tmpLabel, codeGen->rsGetRsvdReg(), REG_R0);
- emitIns_R_R_I(INS_addi, attr, codeGen->rsGetRsvdReg(), REG_R0, imm);
+ codeGen->genDefineTempLabel(tmpLabel);
+ }
+ else if (imm < 0)
+ {
+ // B < 0 and C < 0, if A > B, goto overflow
+ BasicBlock* tmpLabel = codeGen->genCreateTempLabel();
+ emitIns_J_cond_la(INS_bge, tmpLabel, codeGen->rsGetRsvdReg(), REG_R0);
+ emitIns_R_R_I(INS_addi, attr, codeGen->rsGetRsvdReg(), REG_R0, imm);
- codeGen->genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_blt, codeGen->rsGetRsvdReg(), nullptr,
- dst->GetRegNum());
+ codeGen->genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_blt, codeGen->rsGetRsvdReg(), nullptr,
+ dst->GetRegNum());
- codeGen->genDefineTempLabel(tmpLabel);
- }
+ codeGen->genDefineTempLabel(tmpLabel);
}
}
- else
- {
- NYI_RISCV64("-----unimplemented on RISCV64 yet----");
- }
}
}
else if (varTypeIsFloating(dst))
{
emitIns_R_R_R(ins, attr, dst->GetRegNum(), src1->GetRegNum(), src2->GetRegNum());
}
- else if (dst->OperGet() == GT_MUL)
+ else
{
- if (!needCheckOv && !(dst->gtFlags & GTF_UNSIGNED))
+ switch (dst->OperGet())
{
- emitIns_R_R_R(ins, attr, dst->GetRegNum(), src1->GetRegNum(), src2->GetRegNum());
- }
- else
- {
- if (needCheckOv)
+ case GT_MUL:
{
- assert(codeGen->rsGetRsvdReg() != dst->GetRegNum());
- assert(codeGen->rsGetRsvdReg() != src1->GetRegNum());
- assert(codeGen->rsGetRsvdReg() != src2->GetRegNum());
-
- assert(REG_RA != dst->GetRegNum());
- assert(REG_RA != src1->GetRegNum());
- assert(REG_RA != src2->GetRegNum());
-
- if ((dst->gtFlags & GTF_UNSIGNED) != 0)
+ if (!needCheckOv && !(dst->gtFlags & GTF_UNSIGNED))
{
- if (attr == EA_4BYTE)
- {
- emitIns_R_R_I(INS_slli, EA_8BYTE, codeGen->rsGetRsvdReg(), src1->GetRegNum(), 32);
- emitIns_R_R_I(INS_slli, EA_8BYTE, REG_RA, src2->GetRegNum(), 32);
- emitIns_R_R_R(INS_mulhu, EA_8BYTE, codeGen->rsGetRsvdReg(), codeGen->rsGetRsvdReg(), REG_RA);
- emitIns_R_R_I(INS_srai, attr, codeGen->rsGetRsvdReg(), codeGen->rsGetRsvdReg(), 32);
- }
- else
- {
- emitIns_R_R_R(INS_mulhu, attr, codeGen->rsGetRsvdReg(), src1->GetRegNum(), src2->GetRegNum());
- }
+ emitIns_R_R_R(ins, attr, dst->GetRegNum(), src1->GetRegNum(), src2->GetRegNum());
}
else
{
- if (attr == EA_4BYTE)
+ if (needCheckOv)
{
- emitIns_R_R_R(INS_mul, EA_8BYTE, codeGen->rsGetRsvdReg(), src1->GetRegNum(), src2->GetRegNum());
- emitIns_R_R_I(INS_srai, attr, codeGen->rsGetRsvdReg(), codeGen->rsGetRsvdReg(), 32);
+ assert(codeGen->rsGetRsvdReg() != dst->GetRegNum());
+ assert(codeGen->rsGetRsvdReg() != src1->GetRegNum());
+ assert(codeGen->rsGetRsvdReg() != src2->GetRegNum());
+
+ assert(REG_RA != dst->GetRegNum());
+ assert(REG_RA != src1->GetRegNum());
+ assert(REG_RA != src2->GetRegNum());
+
+ if ((dst->gtFlags & GTF_UNSIGNED) != 0)
+ {
+ if (attr == EA_4BYTE)
+ {
+ emitIns_R_R_I(INS_slli, EA_8BYTE, codeGen->rsGetRsvdReg(), src1->GetRegNum(), 32);
+ emitIns_R_R_I(INS_slli, EA_8BYTE, REG_RA, src2->GetRegNum(), 32);
+ emitIns_R_R_R(INS_mulhu, EA_8BYTE, codeGen->rsGetRsvdReg(), codeGen->rsGetRsvdReg(),
+ REG_RA);
+ emitIns_R_R_I(INS_srai, attr, codeGen->rsGetRsvdReg(), codeGen->rsGetRsvdReg(), 32);
+ }
+ else
+ {
+ emitIns_R_R_R(INS_mulhu, attr, codeGen->rsGetRsvdReg(), src1->GetRegNum(),
+ src2->GetRegNum());
+ }
+ }
+ else
+ {
+ if (attr == EA_4BYTE)
+ {
+ emitIns_R_R_R(INS_mul, EA_8BYTE, codeGen->rsGetRsvdReg(), src1->GetRegNum(),
+ src2->GetRegNum());
+ emitIns_R_R_I(INS_srai, attr, codeGen->rsGetRsvdReg(), codeGen->rsGetRsvdReg(), 32);
+ }
+ else
+ {
+ emitIns_R_R_R(INS_mulh, attr, codeGen->rsGetRsvdReg(), src1->GetRegNum(),
+ src2->GetRegNum());
+ }
+ }
}
- else
+
+ // n * n bytes will store n bytes result
+ emitIns_R_R_R(ins, attr, dst->GetRegNum(), src1->GetRegNum(), src2->GetRegNum());
+
+ if ((dst->gtFlags & GTF_UNSIGNED) != 0)
{
- emitIns_R_R_R(INS_mulh, attr, codeGen->rsGetRsvdReg(), src1->GetRegNum(), src2->GetRegNum());
+ if (attr == EA_4BYTE)
+ {
+ emitIns_R_R_I(INS_slli, EA_8BYTE, dst->GetRegNum(), dst->GetRegNum(), 32);
+ emitIns_R_R_I(INS_srli, EA_8BYTE, dst->GetRegNum(), dst->GetRegNum(), 32);
+ }
}
- }
- }
- // n * n bytes will store n bytes result
- emitIns_R_R_R(ins, attr, dst->GetRegNum(), src1->GetRegNum(), src2->GetRegNum());
+ if (needCheckOv)
+ {
+ assert(codeGen->rsGetRsvdReg() != dst->GetRegNum());
+ assert(codeGen->rsGetRsvdReg() != src1->GetRegNum());
+ assert(codeGen->rsGetRsvdReg() != src2->GetRegNum());
- if ((dst->gtFlags & GTF_UNSIGNED) != 0)
- {
- if (attr == EA_4BYTE)
- {
- emitIns_R_R_I(INS_slli, EA_8BYTE, dst->GetRegNum(), dst->GetRegNum(), 32);
- emitIns_R_R_I(INS_srli, EA_8BYTE, dst->GetRegNum(), dst->GetRegNum(), 32);
+ if ((dst->gtFlags & GTF_UNSIGNED) != 0)
+ {
+ codeGen->genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_bne, codeGen->rsGetRsvdReg());
+ }
+ else
+ {
+ regNumber tmpReg = dst->GetSingleTempReg();
+ assert(tmpReg != dst->GetRegNum());
+ assert(tmpReg != src1->GetRegNum());
+ assert(tmpReg != src2->GetRegNum());
+ size_t imm = (EA_SIZE(attr) == EA_8BYTE) ? 63 : 31;
+ emitIns_R_R_I(EA_SIZE(attr) == EA_8BYTE ? INS_srai : INS_sraiw, attr, tmpReg,
+ dst->GetRegNum(), imm);
+ codeGen->genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_bne, codeGen->rsGetRsvdReg(), nullptr,
+ tmpReg);
+ }
+ }
}
}
+ break;
- if (needCheckOv)
+ case GT_AND:
+ case GT_AND_NOT:
+ case GT_OR:
+ case GT_XOR:
{
- assert(codeGen->rsGetRsvdReg() != dst->GetRegNum());
- assert(codeGen->rsGetRsvdReg() != src1->GetRegNum());
- assert(codeGen->rsGetRsvdReg() != src2->GetRegNum());
+ emitIns_R_R_R(ins, attr, dst->GetRegNum(), src1->GetRegNum(), src2->GetRegNum());
- if ((dst->gtFlags & GTF_UNSIGNED) != 0)
- {
- codeGen->genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_bne, codeGen->rsGetRsvdReg());
- }
- else
- {
- regNumber tmpReg = dst->GetSingleTempReg();
- assert(tmpReg != dst->GetRegNum());
- assert(tmpReg != src1->GetRegNum());
- assert(tmpReg != src2->GetRegNum());
- size_t imm = (EA_SIZE(attr) == EA_8BYTE) ? 63 : 31;
- emitIns_R_R_I(EA_SIZE(attr) == EA_8BYTE ? INS_srai : INS_sraiw, attr, tmpReg, dst->GetRegNum(),
- imm);
- codeGen->genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_bne, codeGen->rsGetRsvdReg(), nullptr, tmpReg);
- }
+ // TODO-RISCV64-CQ: here sign-extend dst when deal with 32bit data is too conservative.
+ if (EA_SIZE(attr) == EA_4BYTE)
+ emitIns_R_R_I(INS_slliw, attr, dst->GetRegNum(), dst->GetRegNum(), 0);
}
- }
- }
- else if (dst->OperIs(GT_AND, GT_AND_NOT, GT_OR, GT_XOR))
- {
- emitIns_R_R_R(ins, attr, dst->GetRegNum(), src1->GetRegNum(), src2->GetRegNum());
-
- // TODO-RISCV64-CQ: here sign-extend dst when deal with 32bit data is too conservative.
- if (EA_SIZE(attr) == EA_4BYTE)
- emitIns_R_R_I(INS_slliw, attr, dst->GetRegNum(), dst->GetRegNum(), 0);
- }
- else
- {
- regNumber regOp1 = src1->GetRegNum();
- regNumber regOp2 = src2->GetRegNum();
- regNumber saveOperReg1 = REG_NA;
- regNumber saveOperReg2 = REG_NA;
+ break;
- if ((dst->gtFlags & GTF_UNSIGNED) && (attr == EA_8BYTE))
- {
- if (src1->gtType == TYP_INT)
+ case GT_ADD:
+ case GT_SUB:
{
- emitIns_R_R_I(INS_slli, EA_8BYTE, regOp1, regOp1, 32);
- emitIns_R_R_I(INS_srli, EA_8BYTE, regOp1, regOp1, 32);
- }
- if (src2->gtType == TYP_INT)
- {
- emitIns_R_R_I(INS_slli, EA_8BYTE, regOp2, regOp2, 32);
- emitIns_R_R_I(INS_srli, EA_8BYTE, regOp2, regOp2, 32);
- }
- }
-
- if (needCheckOv)
- {
- assert(!varTypeIsFloating(dst));
+ regNumber regOp1 = src1->GetRegNum();
+ regNumber regOp2 = src2->GetRegNum();
+ regNumber saveOperReg1 = REG_NA;
+ regNumber saveOperReg2 = REG_NA;
- assert(codeGen->rsGetRsvdReg() != dst->GetRegNum());
+ if ((dst->gtFlags & GTF_UNSIGNED) && (attr == EA_8BYTE))
+ {
+ if (src1->gtType == TYP_INT)
+ {
+ emitIns_R_R_I(INS_slli, EA_8BYTE, regOp1, regOp1, 32);
+ emitIns_R_R_I(INS_srli, EA_8BYTE, regOp1, regOp1, 32);
+ }
+ if (src2->gtType == TYP_INT)
+ {
+ emitIns_R_R_I(INS_slli, EA_8BYTE, regOp2, regOp2, 32);
+ emitIns_R_R_I(INS_srli, EA_8BYTE, regOp2, regOp2, 32);
+ }
+ }
- if (dst->GetRegNum() == regOp1)
- {
- assert(codeGen->rsGetRsvdReg() != regOp1);
- assert(REG_RA != regOp1);
- saveOperReg1 = codeGen->rsGetRsvdReg();
- saveOperReg2 = regOp2;
- emitIns_R_R_I(INS_addi, attr, codeGen->rsGetRsvdReg(), regOp1, 0);
- }
- else if (dst->GetRegNum() == regOp2)
- {
- assert(codeGen->rsGetRsvdReg() != regOp2);
- assert(REG_RA != regOp2);
- saveOperReg1 = regOp1;
- saveOperReg2 = codeGen->rsGetRsvdReg();
- emitIns_R_R_I(INS_addi, attr, codeGen->rsGetRsvdReg(), regOp2, 0);
- }
- else
- {
- saveOperReg1 = regOp1;
- saveOperReg2 = regOp2;
- }
- }
+ if (needCheckOv)
+ {
+ assert(!varTypeIsFloating(dst));
- emitIns_R_R_R(ins, attr, dst->GetRegNum(), regOp1, regOp2);
+ assert(codeGen->rsGetRsvdReg() != dst->GetRegNum());
- if (needCheckOv)
- {
- if (dst->OperGet() == GT_ADD || dst->OperGet() == GT_SUB)
- {
- ssize_t imm;
- regNumber tempReg1;
- regNumber tempReg2;
- // ADD : A = B + C
- // SUB : C = A - B
- if ((dst->gtFlags & GTF_UNSIGNED) != 0)
- {
- // if A < B, goto overflow
- if (dst->OperGet() == GT_ADD)
+ if (dst->GetRegNum() == regOp1)
+ {
+ assert(codeGen->rsGetRsvdReg() != regOp1);
+ assert(REG_RA != regOp1);
+ saveOperReg1 = codeGen->rsGetRsvdReg();
+ saveOperReg2 = regOp2;
+ emitIns_R_R_I(INS_addi, attr, codeGen->rsGetRsvdReg(), regOp1, 0);
+ }
+ else if (dst->GetRegNum() == regOp2)
{
- tempReg1 = dst->GetRegNum();
- tempReg2 = saveOperReg1;
+ assert(codeGen->rsGetRsvdReg() != regOp2);
+ assert(REG_RA != regOp2);
+ saveOperReg1 = regOp1;
+ saveOperReg2 = codeGen->rsGetRsvdReg();
+ emitIns_R_R_I(INS_addi, attr, codeGen->rsGetRsvdReg(), regOp2, 0);
}
else
{
- tempReg1 = saveOperReg1;
- tempReg2 = saveOperReg2;
+ saveOperReg1 = regOp1;
+ saveOperReg2 = regOp2;
}
- codeGen->genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_bltu, tempReg1, nullptr, tempReg2);
}
- else
- {
- tempReg1 = REG_RA;
- tempReg2 = dst->GetSingleTempReg();
- assert(tempReg1 != tempReg2);
- assert(tempReg1 != saveOperReg1);
- assert(tempReg2 != saveOperReg2);
-
- ssize_t ui6 = (attr == EA_4BYTE) ? 31 : 63;
- if (dst->OperGet() == GT_ADD)
- emitIns_R_R_I(INS_srli, attr, tempReg1, saveOperReg1, ui6);
- else
- emitIns_R_R_I(INS_srli, attr, tempReg1, dst->GetRegNum(), ui6);
- emitIns_R_R_I(INS_srli, attr, tempReg2, saveOperReg2, ui6);
- emitIns_R_R_R(INS_xor, attr, tempReg1, tempReg1, tempReg2);
- if (attr == EA_4BYTE)
+ emitIns_R_R_R(ins, attr, dst->GetRegNum(), regOp1, regOp2);
+
+ if (needCheckOv)
+ {
+ ssize_t imm;
+ regNumber tempReg1;
+ regNumber tempReg2;
+ // ADD : A = B + C
+ // SUB : C = A - B
+ if ((dst->gtFlags & GTF_UNSIGNED) != 0)
{
- imm = 1;
- emitIns_R_R_I(INS_andi, attr, tempReg1, tempReg1, imm);
- emitIns_R_R_I(INS_andi, attr, tempReg2, tempReg2, imm);
+ // if A < B, goto overflow
+ if (dst->OperGet() == GT_ADD)
+ {
+ tempReg1 = dst->GetRegNum();
+ tempReg2 = saveOperReg1;
+ }
+ else
+ {
+ tempReg1 = saveOperReg1;
+ tempReg2 = saveOperReg2;
+ }
+ codeGen->genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_bltu, tempReg1, nullptr, tempReg2);
}
- // if (B > 0 && C < 0) || (B < 0 && C > 0), skip overflow
- BasicBlock* tmpLabel = codeGen->genCreateTempLabel();
- BasicBlock* tmpLabel2 = codeGen->genCreateTempLabel();
- BasicBlock* tmpLabel3 = codeGen->genCreateTempLabel();
+ else
+ {
+ tempReg1 = REG_RA;
+ tempReg2 = dst->GetSingleTempReg();
+ assert(tempReg1 != tempReg2);
+ assert(tempReg1 != saveOperReg1);
+ assert(tempReg2 != saveOperReg2);
+
+ ssize_t ui6 = (attr == EA_4BYTE) ? 31 : 63;
+ if (dst->OperGet() == GT_ADD)
+ emitIns_R_R_I(INS_srli, attr, tempReg1, saveOperReg1, ui6);
+ else
+ emitIns_R_R_I(INS_srli, attr, tempReg1, dst->GetRegNum(), ui6);
+ emitIns_R_R_I(INS_srli, attr, tempReg2, saveOperReg2, ui6);
- emitIns_J_cond_la(INS_bne, tmpLabel, tempReg1, REG_R0);
+ emitIns_R_R_R(INS_xor, attr, tempReg1, tempReg1, tempReg2);
+ if (attr == EA_4BYTE)
+ {
+ imm = 1;
+ emitIns_R_R_I(INS_andi, attr, tempReg1, tempReg1, imm);
+ emitIns_R_R_I(INS_andi, attr, tempReg2, tempReg2, imm);
+ }
+ // if (B > 0 && C < 0) || (B < 0 && C > 0), skip overflow
+ BasicBlock* tmpLabel = codeGen->genCreateTempLabel();
+ BasicBlock* tmpLabel2 = codeGen->genCreateTempLabel();
+ BasicBlock* tmpLabel3 = codeGen->genCreateTempLabel();
- emitIns_J_cond_la(INS_bne, tmpLabel3, tempReg2, REG_R0);
+ emitIns_J_cond_la(INS_bne, tmpLabel, tempReg1, REG_R0);
- // B > 0 and C > 0, if A < B, goto overflow
- emitIns_J_cond_la(INS_bge, tmpLabel, dst->OperGet() == GT_ADD ? dst->GetRegNum() : saveOperReg1,
- dst->OperGet() == GT_ADD ? saveOperReg1 : saveOperReg2);
+ emitIns_J_cond_la(INS_bne, tmpLabel3, tempReg2, REG_R0);
- codeGen->genDefineTempLabel(tmpLabel2);
+ // B > 0 and C > 0, if A < B, goto overflow
+ emitIns_J_cond_la(INS_bge, tmpLabel, dst->OperGet() == GT_ADD ? dst->GetRegNum() : saveOperReg1,
+ dst->OperGet() == GT_ADD ? saveOperReg1 : saveOperReg2);
- codeGen->genJumpToThrowHlpBlk(EJ_jmp, SCK_OVERFLOW);
+ codeGen->genDefineTempLabel(tmpLabel2);
- codeGen->genDefineTempLabel(tmpLabel3);
+ codeGen->genJumpToThrowHlpBlk(EJ_jmp, SCK_OVERFLOW);
- // B < 0 and C < 0, if A > B, goto overflow
- emitIns_J_cond_la(INS_blt, tmpLabel2, dst->OperGet() == GT_ADD ? saveOperReg1 : saveOperReg2,
- dst->OperGet() == GT_ADD ? dst->GetRegNum() : saveOperReg1);
+ codeGen->genDefineTempLabel(tmpLabel3);
- codeGen->genDefineTempLabel(tmpLabel);
+ // B < 0 and C < 0, if A > B, goto overflow
+ emitIns_J_cond_la(INS_blt, tmpLabel2, dst->OperGet() == GT_ADD ? saveOperReg1 : saveOperReg2,
+ dst->OperGet() == GT_ADD ? dst->GetRegNum() : saveOperReg1);
+
+ codeGen->genDefineTempLabel(tmpLabel);
+ }
}
}
- else
- {
-#ifdef DEBUG
- printf("---------[RISCV64]-NOTE: UnsignedOverflow instruction %d\n", ins);
-#endif
- NYI_RISCV64("unimplemented on RISCV64 yet");
- }
+ break;
+
+ default:
+ NO_WAY("unexpected instruction within emitInsTernary!");
}
}