From b69f79c2b6cd69a4979146774329260870b35dcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Sowi=C5=84ski?= Date: Mon, 4 Dec 2023 11:31:47 +0100 Subject: [PATCH] [RISC-V] Replace rsGetRsvdReg with ordinary temp registers (#95317) * [RISC-V] Replace rsGetRsvdReg calls in emitInsTernary with ordinary temps * [RISC-V] Give emitInsTernary a haircut * [RISC-V] Add missing newline when printf is exceeds MAX_LEN * [RISC-V] Replace rsGetRsvdReg with a normal constant in genLcLHeap. Plus a small optimization, fuse addi+and into andi to avoid using a temp reg. * [RISC-V] Replace rsGetRsvdReg with ordinary temp regs in GT_(MOD|DIV|MULHI) * [RISC-V] Replace rsGetRsvdReg with ordinary temp reg in switch tables * [RISC-V] Replace rsGetRsvdReg with ordinary temps in genCodeForCompare * [RISC-V] Replace rsGetRsvdReg with ordinary temps in genCodeForShift * [RISC-V] Replace rsGetRsvdReg with ordinary temp reg in genCodeForIndexAddr and genLeaInstruction * [RISC-V] Replace rsGetRsvdReg with ordinary temp reg in genIntCastOverflowCheck * [RISC-V] Code review: remove an always true if and don't enter divisor checking when we know we need a temp * [RISC-V] Small refactorings after review --- src/coreclr/jit/codegen.h | 8 +- src/coreclr/jit/codegenriscv64.cpp | 208 +++++++++++++++-------------- src/coreclr/jit/emitriscv64.cpp | 156 +++++++++++----------- src/coreclr/jit/lsrariscv64.cpp | 124 ++++++++++++++++- 4 files changed, 314 insertions(+), 182 deletions(-) diff --git a/src/coreclr/jit/codegen.h b/src/coreclr/jit/codegen.h index 762245840f930..b855f65b95163 100644 --- a/src/coreclr/jit/codegen.h +++ b/src/coreclr/jit/codegen.h @@ -800,7 +800,11 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX void genSetRegToCond(regNumber dstReg, GenTree* tree); #if defined(TARGET_ARMARCH) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) - void genScaledAdd(emitAttr attr, regNumber targetReg, regNumber baseReg, regNumber indexReg, int scale); + void genScaledAdd(emitAttr attr, + regNumber targetReg, + regNumber baseReg, + regNumber indexReg, + int scale RISCV64_ARG(regNumber scaleTempReg)); #endif // TARGET_ARMARCH || TARGET_LOONGARCH64 || TARGET_RISCV64 #if defined(TARGET_ARMARCH) @@ -817,6 +821,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX // Generate the instruction to move a value between register files void genBitCast(var_types targetType, regNumber targetReg, var_types srcType, regNumber srcReg); +public: struct GenIntCastDesc { enum CheckKind @@ -894,6 +899,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX } }; +protected: void genIntCastOverflowCheck(GenTreeCast* cast, const GenIntCastDesc& desc, regNumber reg); void genIntToIntCast(GenTreeCast* cast); void genFloatToFloatCast(GenTree* treeNode); diff --git a/src/coreclr/jit/codegenriscv64.cpp b/src/coreclr/jit/codegenriscv64.cpp index c2dafce1fb0a6..87235374c4095 100644 --- a/src/coreclr/jit/codegenriscv64.cpp +++ b/src/coreclr/jit/codegenriscv64.cpp @@ -1370,9 +1370,10 @@ void CodeGen::genCodeForMulHi(GenTreeOp* treeNode) assert(EA_SIZE(attr) == EA_4BYTE); if (isUnsigned) { - emit->emitIns_R_R_I(INS_slli, EA_8BYTE, rsGetRsvdReg(), op1->GetRegNum(), 32); + regNumber tempReg = treeNode->GetSingleTempReg(); + emit->emitIns_R_R_I(INS_slli, EA_8BYTE, tempReg, op1->GetRegNum(), 32); emit->emitIns_R_R_I(INS_slli, EA_8BYTE, targetReg, op2->GetRegNum(), 32); - emit->emitIns_R_R_R(INS_mulhu, EA_8BYTE, targetReg, rsGetRsvdReg(), targetReg); + emit->emitIns_R_R_R(INS_mulhu, EA_8BYTE, targetReg, tempReg, targetReg); emit->emitIns_R_R_I(INS_srai, attr, targetReg, targetReg, 32); } else @@ -1682,6 +1683,7 @@ void CodeGen::genLclHeap(GenTree* tree) regNumber targetReg = tree->GetRegNum(); regNumber regCnt = REG_NA; + regNumber tempReg = REG_NA; regNumber pspSymReg = REG_NA; var_types type = genActualType(size->gtType); emitAttr easz = emitTypeSize(type); @@ -1724,7 +1726,6 @@ void CodeGen::genLclHeap(GenTree* tree) // since we don't need any internal registers. if (compiler->info.compInitMem) { - assert(tree->AvailableTempRegCount() == 0); regCnt = targetReg; } else @@ -1740,10 +1741,7 @@ void CodeGen::genLclHeap(GenTree* tree) // regCnt will be the total number of bytes to localloc inst_RV_IV(INS_addi, regCnt, (STACK_ALIGN - 1), emitActualTypeSize(type)); - assert(regCnt != rsGetRsvdReg()); - ssize_t imm2 = ~(STACK_ALIGN - 1); - emit->emitIns_R_R_I(INS_addi, EA_PTRSIZE, rsGetRsvdReg(), REG_R0, imm2); - emit->emitIns_R_R_R(INS_and, emitActualTypeSize(type), regCnt, regCnt, rsGetRsvdReg()); + emit->emitIns_R_R_I(INS_andi, emitActualTypeSize(type), regCnt, regCnt, ~(STACK_ALIGN - 1)); } // If we have an outgoing arg area then we must adjust the SP by popping off the @@ -1762,7 +1760,8 @@ void CodeGen::genLclHeap(GenTree* tree) unsigned outgoingArgSpaceAligned = roundUp(compiler->lvaOutgoingArgSpaceSize, STACK_ALIGN); // assert((compiler->lvaOutgoingArgSpaceSize % STACK_ALIGN) == 0); // This must be true for the stack to remain // // aligned - genInstrWithConstant(INS_addi, EA_PTRSIZE, REG_SPBASE, REG_SPBASE, outgoingArgSpaceAligned, rsGetRsvdReg()); + tempReg = tree->ExtractTempReg(); + genInstrWithConstant(INS_addi, EA_PTRSIZE, REG_SPBASE, REG_SPBASE, outgoingArgSpaceAligned, tempReg); stackAdjustment += outgoingArgSpaceAligned; } @@ -1815,8 +1814,10 @@ void CodeGen::genLclHeap(GenTree* tree) } else { - emit->emitLoadImmediate(EA_PTRSIZE, rsGetRsvdReg(), amount); - emit->emitIns_R_R_R(INS_sub, EA_PTRSIZE, REG_SPBASE, REG_SPBASE, rsGetRsvdReg()); + if (tempReg == REG_NA) + tempReg = tree->ExtractTempReg(); + emit->emitLoadImmediate(EA_PTRSIZE, tempReg, amount); + emit->emitIns_R_R_R(INS_sub, EA_PTRSIZE, REG_SPBASE, REG_SPBASE, tempReg); } goto ALLOC_DONE; @@ -1828,7 +1829,6 @@ void CodeGen::genLclHeap(GenTree* tree) assert(regCnt == REG_NA); if (compiler->info.compInitMem) { - assert(tree->AvailableTempRegCount() == 0); regCnt = targetReg; } else @@ -1901,17 +1901,19 @@ void CodeGen::genLclHeap(GenTree* tree) // mov SP, regCnt // - // Setup the regTmp + if (tempReg == REG_NA) + tempReg = tree->ExtractTempReg(); + regNumber regTmp = tree->GetSingleTempReg(); - assert(regCnt != rsGetRsvdReg()); - emit->emitIns_R_R_R(INS_sltu, EA_PTRSIZE, rsGetRsvdReg(), REG_SPBASE, regCnt); + assert(regCnt != tempReg); + emit->emitIns_R_R_R(INS_sltu, EA_PTRSIZE, tempReg, REG_SPBASE, regCnt); //// subu regCnt, SP, regCnt // regCnt now holds ultimate SP emit->emitIns_R_R_R(INS_sub, EA_PTRSIZE, regCnt, REG_SPBASE, regCnt); // Overflow, set regCnt to lowest possible value - emit->emitIns_R_R_I(INS_beq, EA_PTRSIZE, rsGetRsvdReg(), REG_R0, 2 << 2); + emit->emitIns_R_R_I(INS_beq, EA_PTRSIZE, tempReg, REG_R0, 2 << 2); emit->emitIns_R_R_I(INS_addi, EA_PTRSIZE, regCnt, REG_R0, 0); assert(compiler->eeGetPageSize() == ((compiler->eeGetPageSize() >> 12) << 12)); @@ -1923,12 +1925,12 @@ void CodeGen::genLclHeap(GenTree* tree) emit->emitIns_R_R_I(INS_lw, EA_4BYTE, REG_R0, REG_SPBASE, 0); // decrement SP by eeGetPageSize() - emit->emitIns_R_R_R(INS_sub, EA_PTRSIZE, rsGetRsvdReg(), REG_SPBASE, regTmp); + emit->emitIns_R_R_R(INS_sub, EA_PTRSIZE, tempReg, REG_SPBASE, regTmp); - assert(regTmp != rsGetRsvdReg()); + assert(regTmp != tempReg); ssize_t imm = 3 << 2; // goto done. - emit->emitIns_R_R_I(INS_bltu, EA_PTRSIZE, rsGetRsvdReg(), regCnt, imm); + emit->emitIns_R_R_I(INS_bltu, EA_PTRSIZE, tempReg, regCnt, imm); emit->emitIns_R_R_R(INS_sub, EA_PTRSIZE, REG_SPBASE, REG_SPBASE, regTmp); @@ -1953,23 +1955,21 @@ void CodeGen::genLclHeap(GenTree* tree) assert((stackAdjustment % STACK_ALIGN) == 0); // This must be true for the stack to remain aligned assert((lastTouchDelta == ILLEGAL_LAST_TOUCH_DELTA) || (lastTouchDelta >= 0)); - const regNumber tmpReg = rsGetRsvdReg(); - if ((lastTouchDelta == ILLEGAL_LAST_TOUCH_DELTA) || (stackAdjustment + (unsigned)lastTouchDelta + STACK_PROBE_BOUNDARY_THRESHOLD_BYTES > compiler->eeGetPageSize())) { - genStackPointerConstantAdjustmentLoopWithProbe(-(ssize_t)stackAdjustment, tmpReg); + genStackPointerConstantAdjustmentLoopWithProbe(-(ssize_t)stackAdjustment, tempReg); } else { - genStackPointerConstantAdjustment(-(ssize_t)stackAdjustment, tmpReg); + genStackPointerConstantAdjustment(-(ssize_t)stackAdjustment, tempReg); } // Return the stackalloc'ed address in result register. // TargetReg = SP + stackAdjustment. // - genInstrWithConstant(INS_addi, EA_PTRSIZE, targetReg, REG_SPBASE, (ssize_t)stackAdjustment, tmpReg); + genInstrWithConstant(INS_addi, EA_PTRSIZE, targetReg, REG_SPBASE, (ssize_t)stackAdjustment, tempReg); } else // stackAdjustment == 0 { @@ -2093,13 +2093,15 @@ void CodeGen::genCodeForDivMod(GenTreeOp* tree) // ssize_t intConstValue = divisorOp->AsIntCon()->gtIconVal; regNumber reg1 = src1->GetRegNum(); regNumber divisorReg = divisorOp->GetRegNum(); + regNumber tempReg = REG_NA; instruction ins; // Check divisorOp first as we can always allow it to be a contained immediate if (divisorOp->isContainedIntOrIImmed()) { ssize_t intConst = (int)(divisorOp->AsIntCon()->gtIconVal); - divisorReg = rsGetRsvdReg(); + tempReg = tree->GetSingleTempReg(); + divisorReg = tempReg; emit->emitLoadImmediate(EA_PTRSIZE, divisorReg, intConst); } // Only for commutative operations do we check src1 and allow it to be a contained immediate @@ -2113,7 +2115,8 @@ void CodeGen::genCodeForDivMod(GenTreeOp* tree) { assert(!divisorOp->isContainedIntOrIImmed()); ssize_t intConst = (int)(src1->AsIntCon()->gtIconVal); - reg1 = rsGetRsvdReg(); + tempReg = tree->GetSingleTempReg(); + reg1 = tempReg; emit->emitLoadImmediate(EA_PTRSIZE, reg1, intConst); } } @@ -2153,10 +2156,13 @@ void CodeGen::genCodeForDivMod(GenTreeOp* tree) ExceptionSetFlags exSetFlags = tree->OperExceptions(compiler); if (checkDividend && ((exSetFlags & ExceptionSetFlags::ArithmeticException) != ExceptionSetFlags::None)) { + if (tempReg == REG_NA) + tempReg = tree->GetSingleTempReg(); + // Check if the divisor is not -1 branch to 'sdivLabel' - emit->emitIns_R_R_I(INS_addi, EA_PTRSIZE, rsGetRsvdReg(), REG_R0, -1); + emit->emitIns_R_R_I(INS_addi, EA_PTRSIZE, tempReg, REG_R0, -1); BasicBlock* sdivLabel = genCreateTempLabel(); // can optimize for riscv64. - emit->emitIns_J_cond_la(INS_bne, sdivLabel, rsGetRsvdReg(), divisorReg); + emit->emitIns_J_cond_la(INS_bne, sdivLabel, tempReg, divisorReg); // If control flow continues past here the 'divisorReg' is known to be -1 regNumber dividendReg = tree->gtGetOp1()->GetRegNum(); @@ -2167,9 +2173,8 @@ void CodeGen::genCodeForDivMod(GenTreeOp* tree) emit->emitIns_J_cond_la(INS_beq, sdivLabel, dividendReg, REG_R0); - emit->emitIns_R_R_R(size == EA_4BYTE ? INS_addw : INS_add, size, rsGetRsvdReg(), dividendReg, - dividendReg); - genJumpToThrowHlpBlk_la(SCK_ARITH_EXCPN, INS_beq, rsGetRsvdReg()); + emit->emitIns_R_R_R(size == EA_4BYTE ? INS_addw : INS_add, size, tempReg, dividendReg, dividendReg); + genJumpToThrowHlpBlk_la(SCK_ARITH_EXCPN, INS_beq, tempReg); genDefineTempLabel(sdivLabel); } @@ -2554,8 +2559,8 @@ void CodeGen::genTableBasedSwitch(GenTree* treeNode) regNumber tmpReg = treeNode->GetSingleTempReg(); // load the ip-relative offset (which is relative to start of fgFirstBB) - GetEmitter()->emitIns_R_R_I(INS_slli, EA_8BYTE, rsGetRsvdReg(), idxReg, 2); - GetEmitter()->emitIns_R_R_R(INS_add, EA_8BYTE, baseReg, baseReg, rsGetRsvdReg()); + GetEmitter()->emitIns_R_R_I(INS_slli, EA_8BYTE, tmpReg, idxReg, 2); + GetEmitter()->emitIns_R_R_R(INS_add, EA_8BYTE, baseReg, baseReg, tmpReg); GetEmitter()->emitIns_R_R_I(INS_lw, EA_4BYTE, baseReg, baseReg, 0); // add it to the absolute address of fgFirstBB @@ -3470,13 +3475,14 @@ void CodeGen::genCodeForCompare(GenTreeOp* tree) } else if (tree->OperIs(GT_EQ)) { - skipLabel = genCreateTempLabel(); + regNumber tempReg = tree->GetSingleTempReg(); + skipLabel = genCreateTempLabel(); emit->emitIns_R_R(cmpSize == EA_4BYTE ? INS_fclass_s : INS_fclass_d, cmpSize, targetReg, regOp1); - emit->emitIns_R_R(cmpSize == EA_4BYTE ? INS_fclass_s : INS_fclass_d, cmpSize, rsGetRsvdReg(), regOp2); - emit->emitIns_R_R_R(INS_or, EA_8BYTE, rsGetRsvdReg(), targetReg, rsGetRsvdReg()); - emit->emitIns_R_R_I(INS_andi, EA_8BYTE, rsGetRsvdReg(), rsGetRsvdReg(), 0x300); + emit->emitIns_R_R(cmpSize == EA_4BYTE ? INS_fclass_s : INS_fclass_d, cmpSize, tempReg, regOp2); + emit->emitIns_R_R_R(INS_or, EA_8BYTE, tempReg, targetReg, tempReg); + emit->emitIns_R_R_I(INS_andi, EA_8BYTE, tempReg, tempReg, 0x300); emit->emitIns_R_R_I(INS_addi, EA_8BYTE, targetReg, REG_R0, 1); - emit->emitIns_J(INS_bnez, skipLabel, rsGetRsvdReg()); + emit->emitIns_J(INS_bnez, skipLabel, tempReg); emit->emitIns_R_R_R(cmpSize == EA_4BYTE ? INS_feq_s : INS_feq_d, cmpSize, targetReg, regOp1, regOp2); genDefineTempLabel(skipLabel); } @@ -3514,13 +3520,14 @@ void CodeGen::genCodeForCompare(GenTreeOp* tree) } else if (tree->OperIs(GT_NE)) { + regNumber tempReg = tree->GetSingleTempReg(); emit->emitIns_R_R(cmpSize == EA_4BYTE ? INS_fclass_s : INS_fclass_d, cmpSize, targetReg, regOp1); - emit->emitIns_R_R(cmpSize == EA_4BYTE ? INS_fclass_s : INS_fclass_d, cmpSize, rsGetRsvdReg(), regOp2); - emit->emitIns_R_R_R(INS_or, EA_8BYTE, rsGetRsvdReg(), targetReg, rsGetRsvdReg()); - emit->emitIns_R_R_I(INS_andi, EA_8BYTE, rsGetRsvdReg(), rsGetRsvdReg(), 0x300); + emit->emitIns_R_R(cmpSize == EA_4BYTE ? INS_fclass_s : INS_fclass_d, cmpSize, tempReg, regOp2); + emit->emitIns_R_R_R(INS_or, EA_8BYTE, tempReg, targetReg, tempReg); + emit->emitIns_R_R_I(INS_andi, EA_8BYTE, tempReg, tempReg, 0x300); emit->emitIns_R_R_I(INS_addi, EA_8BYTE, targetReg, REG_R0, 0); BasicBlock* skipLabel = genCreateTempLabel(); - emit->emitIns_J(INS_bnez, skipLabel, rsGetRsvdReg()); + emit->emitIns_J(INS_bnez, skipLabel, tempReg); emit->emitIns_R_R_R(cmpSize == EA_4BYTE ? INS_feq_s : INS_feq_d, cmpSize, targetReg, regOp1, regOp2); emit->emitIns_R_R_R(INS_sub, EA_8BYTE, targetReg, REG_R0, targetReg); emit->emitIns_R_R_I(INS_addi, EA_8BYTE, targetReg, targetReg, 1); @@ -3579,7 +3586,7 @@ void CodeGen::genCodeForCompare(GenTreeOp* tree) { imm = static_cast(imm); - regNumber tmpRegOp1 = rsGetRsvdReg(); + regNumber tmpRegOp1 = tree->GetSingleTempReg(); assert(regOp1 != tmpRegOp1); emit->emitIns_R_R_I(INS_slli, EA_8BYTE, tmpRegOp1, regOp1, 32); @@ -3708,7 +3715,7 @@ void CodeGen::genCodeForCompare(GenTreeOp* tree) if (cmpSize == EA_4BYTE) { regNumber tmpRegOp1 = REG_RA; - regNumber tmpRegOp2 = rsGetRsvdReg(); + regNumber tmpRegOp2 = tree->GetSingleTempReg(); assert(regOp1 != tmpRegOp2); assert(regOp2 != tmpRegOp2); @@ -5539,22 +5546,23 @@ void CodeGen::genCodeForShift(GenTree* tree) if (tree->OperIs(GT_ROR, GT_ROL)) { - unsigned immWidth = emitter::getBitWidth(size); // For RISCV64, immWidth will be set to 32 or 64 + regNumber tempReg = tree->GetSingleTempReg(); + unsigned immWidth = emitter::getBitWidth(size); // For RISCV64, immWidth will be set to 32 or 64 if (!shiftBy->IsCnsIntOrI()) { - regNumber shiftRight = tree->OperIs(GT_ROR) ? shiftBy->GetRegNum() : rsGetRsvdReg(); - regNumber shiftLeft = tree->OperIs(GT_ROR) ? rsGetRsvdReg() : shiftBy->GetRegNum(); - GetEmitter()->emitIns_R_R_I(INS_addi, size, rsGetRsvdReg(), REG_R0, immWidth); - GetEmitter()->emitIns_R_R_R(INS_sub, size, rsGetRsvdReg(), rsGetRsvdReg(), shiftBy->GetRegNum()); + regNumber shiftRight = tree->OperIs(GT_ROR) ? shiftBy->GetRegNum() : tempReg; + regNumber shiftLeft = tree->OperIs(GT_ROR) ? tempReg : shiftBy->GetRegNum(); + GetEmitter()->emitIns_R_R_I(INS_addi, size, tempReg, REG_R0, immWidth); + GetEmitter()->emitIns_R_R_R(INS_sub, size, tempReg, tempReg, shiftBy->GetRegNum()); if (size == EA_8BYTE) { GetEmitter()->emitIns_R_R_R(INS_srl, size, REG_RA, operand->GetRegNum(), shiftRight); - GetEmitter()->emitIns_R_R_R(INS_sll, size, rsGetRsvdReg(), operand->GetRegNum(), shiftLeft); + GetEmitter()->emitIns_R_R_R(INS_sll, size, tempReg, operand->GetRegNum(), shiftLeft); } else { GetEmitter()->emitIns_R_R_R(INS_srlw, size, REG_RA, operand->GetRegNum(), shiftRight); - GetEmitter()->emitIns_R_R_R(INS_sllw, size, rsGetRsvdReg(), operand->GetRegNum(), shiftLeft); + GetEmitter()->emitIns_R_R_R(INS_sllw, size, tempReg, operand->GetRegNum(), shiftLeft); } } else @@ -5569,15 +5577,15 @@ void CodeGen::genCodeForShift(GenTree* tree) if ((shiftByImm >= 32 && shiftByImm < 64) || size == EA_8BYTE) { GetEmitter()->emitIns_R_R_I(INS_srli, size, REG_RA, operand->GetRegNum(), shiftRight); - GetEmitter()->emitIns_R_R_I(INS_slli, size, rsGetRsvdReg(), operand->GetRegNum(), shiftLeft); + GetEmitter()->emitIns_R_R_I(INS_slli, size, tempReg, operand->GetRegNum(), shiftLeft); } else { GetEmitter()->emitIns_R_R_I(INS_srliw, size, REG_RA, operand->GetRegNum(), shiftRight); - GetEmitter()->emitIns_R_R_I(INS_slliw, size, rsGetRsvdReg(), operand->GetRegNum(), shiftLeft); + GetEmitter()->emitIns_R_R_I(INS_slliw, size, tempReg, operand->GetRegNum(), shiftLeft); } } - GetEmitter()->emitIns_R_R_R(INS_or, size, tree->GetRegNum(), REG_RA, rsGetRsvdReg()); + GetEmitter()->emitIns_R_R_R(INS_or, size, tree->GetRegNum(), REG_RA, tempReg); } else { @@ -5671,7 +5679,8 @@ void CodeGen::genCodeForLclFld(GenTreeLclFld* tree) // genScaledAdd: A helper for `dest = base + (index << scale)` // and maybe optimize the instruction(s) for this operation. // -void CodeGen::genScaledAdd(emitAttr attr, regNumber targetReg, regNumber baseReg, regNumber indexReg, int scale) +void CodeGen::genScaledAdd( + emitAttr attr, regNumber targetReg, regNumber baseReg, regNumber indexReg, int scale, regNumber scaleTempReg) { assert((scale >> 5) == 0); emitter* emit = GetEmitter(); @@ -5695,10 +5704,10 @@ void CodeGen::genScaledAdd(emitAttr attr, regNumber targetReg, regNumber baseReg ins = INS_slli; ins2 = INS_add; } - + assert(scaleTempReg != REG_NA); // target = base + index << scale - emit->emitIns_R_R_I(ins, attr, rsGetRsvdReg(), indexReg, scale); - emit->emitIns_R_R_R(ins2, attr, targetReg, baseReg, rsGetRsvdReg()); + emit->emitIns_R_R_I(ins, attr, scaleTempReg, indexReg, scale); + emit->emitIns_R_R_R(ins2, attr, targetReg, baseReg, scaleTempReg); } } @@ -5727,21 +5736,23 @@ void CodeGen::genCodeForIndexAddr(GenTreeIndexAddr* node) // The index is never contained, even if it is a constant. assert(index->isUsedFromReg()); + regNumber tempReg = node->GetSingleTempReg(); + // Generate the bounds check if necessary. if (node->IsBoundsChecked()) { - GetEmitter()->emitIns_R_R_I(INS_lw, EA_4BYTE, rsGetRsvdReg(), base->GetRegNum(), node->gtLenOffset); - // if (index >= rsGetRsvdReg()) + GetEmitter()->emitIns_R_R_I(INS_lw, EA_4BYTE, tempReg, base->GetRegNum(), node->gtLenOffset); + // if (index >= tempReg) // { // JumpToThrowHlpBlk; // } // - // sltu rsGetRsvdReg(), index, rsGetRsvdReg() - // bne rsGetRsvdReg(), zero, RngChkExit + // sltu tempReg, index, tempReg + // bne tempReg, zero, RngChkExit // IndRngFail: // ... // RngChkExit: - genJumpToThrowHlpBlk_la(SCK_RNGCHK_FAIL, INS_bgeu, index->GetRegNum(), node->gtIndRngFailBB, rsGetRsvdReg()); + genJumpToThrowHlpBlk_la(SCK_RNGCHK_FAIL, INS_bgeu, index->GetRegNum(), node->gtIndRngFailBB, tempReg); } emitAttr attr = emitActualTypeSize(node); @@ -5755,11 +5766,11 @@ void CodeGen::genCodeForIndexAddr(GenTreeIndexAddr* node) // dest = base + (index << scale) if (node->gtElemSize <= 64) { - genScaledAdd(attr, node->GetRegNum(), base->GetRegNum(), index->GetRegNum(), scale); + genScaledAdd(attr, node->GetRegNum(), base->GetRegNum(), index->GetRegNum(), scale, tempReg); } else { - GetEmitter()->emitLoadImmediate(EA_PTRSIZE, rsGetRsvdReg(), scale); + GetEmitter()->emitLoadImmediate(EA_PTRSIZE, tempReg, scale); instruction ins; instruction ins2; @@ -5773,16 +5784,16 @@ void CodeGen::genCodeForIndexAddr(GenTreeIndexAddr* node) ins = INS_sll; ins2 = INS_add; } - GetEmitter()->emitIns_R_R_R(ins, attr, rsGetRsvdReg(), index->GetRegNum(), rsGetRsvdReg()); - GetEmitter()->emitIns_R_R_R(ins2, attr, node->GetRegNum(), rsGetRsvdReg(), base->GetRegNum()); + GetEmitter()->emitIns_R_R_R(ins, attr, tempReg, index->GetRegNum(), tempReg); + GetEmitter()->emitIns_R_R_R(ins2, attr, node->GetRegNum(), tempReg, base->GetRegNum()); } } else // we have to load the element size and use a MADD (multiply-add) instruction { - // rsGetRsvdReg() = element size - instGen_Set_Reg_To_Imm(EA_4BYTE, rsGetRsvdReg(), (ssize_t)node->gtElemSize); + // tempReg = element size + instGen_Set_Reg_To_Imm(EA_4BYTE, tempReg, (ssize_t)node->gtElemSize); - // dest = index * rsGetRsvdReg() + base + // dest = index * tempReg + base instruction ins; instruction ins2; if (attr == EA_4BYTE) @@ -5795,8 +5806,8 @@ void CodeGen::genCodeForIndexAddr(GenTreeIndexAddr* node) ins = INS_mul; ins2 = INS_add; } - GetEmitter()->emitIns_R_R_R(ins, EA_PTRSIZE, rsGetRsvdReg(), index->GetRegNum(), rsGetRsvdReg()); - GetEmitter()->emitIns_R_R_R(ins2, attr, node->GetRegNum(), rsGetRsvdReg(), base->GetRegNum()); + GetEmitter()->emitIns_R_R_R(ins, EA_PTRSIZE, tempReg, index->GetRegNum(), tempReg); + GetEmitter()->emitIns_R_R_R(ins2, attr, node->GetRegNum(), tempReg, base->GetRegNum()); } // dest = dest + elemOffs @@ -6662,35 +6673,37 @@ void CodeGen::genIntCastOverflowCheck(GenTreeCast* cast, const GenIntCastDesc& d case GenIntCastDesc::CHECK_UINT_RANGE: { + regNumber tempReg = cast->GetSingleTempReg(); // We need to check if the value is not greater than 0xFFFFFFFF // if the upper 32 bits are zero. ssize_t imm = -1; - GetEmitter()->emitIns_R_R_I(INS_addi, EA_8BYTE, rsGetRsvdReg(), REG_R0, imm); + GetEmitter()->emitIns_R_R_I(INS_addi, EA_8BYTE, tempReg, REG_R0, imm); - GetEmitter()->emitIns_R_R_I(INS_slli, EA_8BYTE, rsGetRsvdReg(), rsGetRsvdReg(), 32); - GetEmitter()->emitIns_R_R_R(INS_and, EA_8BYTE, rsGetRsvdReg(), reg, rsGetRsvdReg()); - genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_bne, rsGetRsvdReg()); + GetEmitter()->emitIns_R_R_I(INS_slli, EA_8BYTE, tempReg, tempReg, 32); + GetEmitter()->emitIns_R_R_R(INS_and, EA_8BYTE, tempReg, reg, tempReg); + genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_bne, tempReg); } break; case GenIntCastDesc::CHECK_POSITIVE_INT_RANGE: { + regNumber tempReg = cast->GetSingleTempReg(); // We need to check if the value is not greater than 0x7FFFFFFF // if the upper 33 bits are zero. - // instGen_Set_Reg_To_Imm(EA_8BYTE, rsGetRsvdReg(), 0xFFFFFFFF80000000LL); + // instGen_Set_Reg_To_Imm(EA_8BYTE, tempReg, 0xFFFFFFFF80000000LL); ssize_t imm = -1; - GetEmitter()->emitIns_R_R_I(INS_addi, EA_8BYTE, rsGetRsvdReg(), REG_R0, imm); + GetEmitter()->emitIns_R_R_I(INS_addi, EA_8BYTE, tempReg, REG_R0, imm); - GetEmitter()->emitIns_R_R_I(INS_slli, EA_8BYTE, rsGetRsvdReg(), rsGetRsvdReg(), 31); + GetEmitter()->emitIns_R_R_I(INS_slli, EA_8BYTE, tempReg, tempReg, 31); - GetEmitter()->emitIns_R_R_R(INS_and, EA_8BYTE, rsGetRsvdReg(), reg, rsGetRsvdReg()); - genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_bne, rsGetRsvdReg()); + GetEmitter()->emitIns_R_R_R(INS_and, EA_8BYTE, tempReg, reg, tempReg); + genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_bne, tempReg); } break; case GenIntCastDesc::CHECK_INT_RANGE: { - const regNumber tempReg = rsGetRsvdReg(); + const regNumber tempReg = cast->GetSingleTempReg(); assert(tempReg != reg); GetEmitter()->emitLoadImmediate(EA_8BYTE, tempReg, INT32_MAX); genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_blt, tempReg, nullptr, reg); @@ -6703,39 +6716,37 @@ void CodeGen::genIntCastOverflowCheck(GenTreeCast* cast, const GenIntCastDesc& d default: { assert(desc.CheckKind() == GenIntCastDesc::CHECK_SMALL_INT_RANGE); - const int castMaxValue = desc.CheckSmallIntMax(); - const int castMinValue = desc.CheckSmallIntMin(); - instruction ins; + const int castMaxValue = desc.CheckSmallIntMax(); + const int castMinValue = desc.CheckSmallIntMin(); + const regNumber tempReg = cast->GetSingleTempReg(); + instruction ins; if (castMaxValue > 2047) { assert((castMaxValue == 32767) || (castMaxValue == 65535)); - GetEmitter()->emitLoadImmediate(EA_ATTR(desc.CheckSrcSize()), rsGetRsvdReg(), castMaxValue + 1); + GetEmitter()->emitLoadImmediate(EA_ATTR(desc.CheckSrcSize()), tempReg, castMaxValue + 1); ins = castMinValue == 0 ? INS_bgeu : INS_bge; - genJumpToThrowHlpBlk_la(SCK_OVERFLOW, ins, reg, nullptr, rsGetRsvdReg()); + genJumpToThrowHlpBlk_la(SCK_OVERFLOW, ins, reg, nullptr, tempReg); } else { - GetEmitter()->emitIns_R_R_I(INS_addiw, EA_ATTR(desc.CheckSrcSize()), rsGetRsvdReg(), REG_R0, - castMaxValue); + GetEmitter()->emitIns_R_R_I(INS_addiw, EA_ATTR(desc.CheckSrcSize()), tempReg, REG_R0, castMaxValue); ins = castMinValue == 0 ? INS_bltu : INS_blt; - genJumpToThrowHlpBlk_la(SCK_OVERFLOW, ins, rsGetRsvdReg(), nullptr, reg); + genJumpToThrowHlpBlk_la(SCK_OVERFLOW, ins, tempReg, nullptr, reg); } if (castMinValue != 0) { if (emitter::isValidSimm12(castMinValue)) { - GetEmitter()->emitIns_R_R_I(INS_slti, EA_ATTR(desc.CheckSrcSize()), rsGetRsvdReg(), reg, - castMinValue); + GetEmitter()->emitIns_R_R_I(INS_slti, EA_ATTR(desc.CheckSrcSize()), tempReg, reg, castMinValue); } else { - GetEmitter()->emitLoadImmediate(EA_8BYTE, rsGetRsvdReg(), castMinValue); - GetEmitter()->emitIns_R_R_R(INS_slt, EA_ATTR(desc.CheckSrcSize()), rsGetRsvdReg(), reg, - rsGetRsvdReg()); + GetEmitter()->emitLoadImmediate(EA_8BYTE, tempReg, castMinValue); + GetEmitter()->emitIns_R_R_R(INS_slt, EA_ATTR(desc.CheckSrcSize()), tempReg, reg, tempReg); } - genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_bne, rsGetRsvdReg()); + genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_bne, tempReg); } } break; @@ -7012,11 +7023,12 @@ void CodeGen::genLeaInstruction(GenTreeAddrMode* lea) assert(isPow2(lea->gtScale)); BitScanForward(&scale, lea->gtScale); assert(scale <= 4); + regNumber scaleTempReg = scale ? lea->ExtractTempReg() : REG_NA; if (offset == 0) { // Then compute target reg from [base + index*scale] - genScaledAdd(size, lea->GetRegNum(), memBase->GetRegNum(), index->GetRegNum(), scale); + genScaledAdd(size, lea->GetRegNum(), memBase->GetRegNum(), index->GetRegNum(), scale, scaleTempReg); } else { @@ -7026,7 +7038,7 @@ void CodeGen::genLeaInstruction(GenTreeAddrMode* lea) if (!useLargeOffsetSeq && emitter::isValidSimm12(offset)) { - genScaledAdd(size, lea->GetRegNum(), memBase->GetRegNum(), index->GetRegNum(), scale); + genScaledAdd(size, lea->GetRegNum(), memBase->GetRegNum(), index->GetRegNum(), scale, scaleTempReg); instruction ins = size == EA_4BYTE ? INS_addiw : INS_addi; emit->emitIns_R_R_I(ins, size, lea->GetRegNum(), lea->GetRegNum(), offset); } @@ -7040,7 +7052,7 @@ void CodeGen::genLeaInstruction(GenTreeAddrMode* lea) // compute the large offset. instGen_Set_Reg_To_Imm(EA_PTRSIZE, tmpReg, offset); - genScaledAdd(EA_PTRSIZE, tmpReg, tmpReg, index->GetRegNum(), scale); + genScaledAdd(EA_PTRSIZE, tmpReg, tmpReg, index->GetRegNum(), scale, scaleTempReg); instruction ins = size == EA_4BYTE ? INS_addw : INS_add; emit->emitIns_R_R_R(ins, size, lea->GetRegNum(), tmpReg, memBase->GetRegNum()); diff --git a/src/coreclr/jit/emitriscv64.cpp b/src/coreclr/jit/emitriscv64.cpp index 2af73d74bba2d..487f380d3d49a 100644 --- a/src/coreclr/jit/emitriscv64.cpp +++ b/src/coreclr/jit/emitriscv64.cpp @@ -3251,8 +3251,10 @@ void emitter::emitDisInsName(code_t code, const BYTE* addr, instrDesc* id) int len = printf(" %s, %s, %d", rs1, rs2, offset); if (len <= 0 || len > MAX_LEN) + { + printf("\n"); return; - + } if (!emitComp->opts.disDiffable) printf("%*s;; offset=0x%04X", MAX_LEN - len, "", emitCurCodeOffs(insAdr) + offset); printf("\n"); @@ -4162,17 +4164,14 @@ regNumber emitter::emitInsTernary(instruction ins, emitAttr attr, GenTree* dst, } } + regNumber dstReg = dst->GetRegNum(); + regNumber src1Reg = src1->GetRegNum(); + regNumber src2Reg = src2->GetRegNum(); + if (intConst != nullptr) { ssize_t imm = intConst->IconValue(); - if (ins == INS_andi || ins == INS_ori || ins == INS_xori) - { - assert(isValidSimm12(imm)); - } - else - { - assert(isValidSimm12(imm)); - } + assert(isValidSimm12(imm)); if (ins == INS_sub) { @@ -4191,12 +4190,14 @@ regNumber emitter::emitInsTernary(instruction ins, emitAttr attr, GenTree* dst, assert(ins == INS_addi || ins == INS_addiw || ins == INS_andi || ins == INS_ori || ins == INS_xori); + regNumber tempReg = needCheckOv ? dst->ExtractTempReg() : REG_NA; + if (needCheckOv) { - emitIns_R_R_R(INS_or, attr, codeGen->rsGetRsvdReg(), nonIntReg->GetRegNum(), REG_R0); + emitIns_R_R(INS_mov, attr, tempReg, nonIntReg->GetRegNum()); } - emitIns_R_R_I(ins, attr, dst->GetRegNum(), nonIntReg->GetRegNum(), imm); + emitIns_R_R_I(ins, attr, dstReg, nonIntReg->GetRegNum(), imm); if (needCheckOv) { @@ -4206,8 +4207,7 @@ regNumber emitter::emitInsTernary(instruction ins, emitAttr attr, GenTree* dst, // AS11 = B + C if ((dst->gtFlags & GTF_UNSIGNED) != 0) { - codeGen->genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_bltu, dst->GetRegNum(), nullptr, - codeGen->rsGetRsvdReg()); + codeGen->genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_bltu, dstReg, nullptr, tempReg); } else { @@ -4215,10 +4215,10 @@ regNumber emitter::emitInsTernary(instruction ins, emitAttr attr, GenTree* dst, { // 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); + emitIns_J_cond_la(INS_bge, tmpLabel, REG_R0, tempReg); + emitIns_R_R_I(INS_slti, EA_PTRSIZE, tempReg, dstReg, imm); - codeGen->genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_bne, codeGen->rsGetRsvdReg()); + codeGen->genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_bne, tempReg); codeGen->genDefineTempLabel(tmpLabel); } @@ -4226,11 +4226,10 @@ regNumber emitter::emitInsTernary(instruction ins, emitAttr attr, GenTree* dst, { // 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); + emitIns_J_cond_la(INS_bge, tmpLabel, tempReg, REG_R0); + emitIns_R_R_I(INS_addi, attr, tempReg, REG_R0, imm); - codeGen->genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_blt, codeGen->rsGetRsvdReg(), nullptr, - dst->GetRegNum()); + codeGen->genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_blt, tempReg, nullptr, dstReg); codeGen->genDefineTempLabel(tmpLabel); } @@ -4239,95 +4238,92 @@ regNumber emitter::emitInsTernary(instruction ins, emitAttr attr, GenTree* dst, } else if (varTypeIsFloating(dst)) { - emitIns_R_R_R(ins, attr, dst->GetRegNum(), src1->GetRegNum(), src2->GetRegNum()); + emitIns_R_R_R(ins, attr, dstReg, src1Reg, src2Reg); } else { + regNumber tempReg = needCheckOv ? dst->ExtractTempReg() : REG_NA; + switch (dst->OperGet()) { case GT_MUL: { if (!needCheckOv && !(dst->gtFlags & GTF_UNSIGNED)) { - emitIns_R_R_R(ins, attr, dst->GetRegNum(), src1->GetRegNum(), src2->GetRegNum()); + emitIns_R_R_R(ins, attr, dstReg, src1Reg, src2Reg); } else { if (needCheckOv) { - assert(codeGen->rsGetRsvdReg() != dst->GetRegNum()); - assert(codeGen->rsGetRsvdReg() != src1->GetRegNum()); - assert(codeGen->rsGetRsvdReg() != src2->GetRegNum()); + assert(tempReg != dstReg); + assert(tempReg != src1Reg); + assert(tempReg != src2Reg); - assert(REG_RA != dst->GetRegNum()); - assert(REG_RA != src1->GetRegNum()); - assert(REG_RA != src2->GetRegNum()); + assert(REG_RA != dstReg); + assert(REG_RA != src1Reg); + assert(REG_RA != src2Reg); 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); + emitIns_R_R_I(INS_slli, EA_8BYTE, tempReg, src1Reg, 32); + emitIns_R_R_I(INS_slli, EA_8BYTE, REG_RA, src2Reg, 32); + emitIns_R_R_R(INS_mulhu, EA_8BYTE, tempReg, tempReg, REG_RA); + emitIns_R_R_I(INS_srai, attr, tempReg, tempReg, 32); } else { - emitIns_R_R_R(INS_mulhu, attr, codeGen->rsGetRsvdReg(), src1->GetRegNum(), - src2->GetRegNum()); + emitIns_R_R_R(INS_mulhu, attr, tempReg, src1Reg, src2Reg); } } 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); + emitIns_R_R_R(INS_mul, EA_8BYTE, tempReg, src1Reg, src2Reg); + emitIns_R_R_I(INS_srai, attr, tempReg, tempReg, 32); } else { - emitIns_R_R_R(INS_mulh, attr, codeGen->rsGetRsvdReg(), src1->GetRegNum(), - src2->GetRegNum()); + emitIns_R_R_R(INS_mulh, attr, tempReg, src1Reg, src2Reg); } } } // n * n bytes will store n bytes result - emitIns_R_R_R(ins, attr, dst->GetRegNum(), src1->GetRegNum(), src2->GetRegNum()); + emitIns_R_R_R(ins, attr, dstReg, src1Reg, src2Reg); 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); + emitIns_R_R_I(INS_slli, EA_8BYTE, dstReg, dstReg, 32); + emitIns_R_R_I(INS_srli, EA_8BYTE, dstReg, dstReg, 32); } } if (needCheckOv) { - assert(codeGen->rsGetRsvdReg() != dst->GetRegNum()); - assert(codeGen->rsGetRsvdReg() != src1->GetRegNum()); - assert(codeGen->rsGetRsvdReg() != src2->GetRegNum()); + assert(tempReg != dstReg); + assert(tempReg != src1Reg); + assert(tempReg != src2Reg); if ((dst->gtFlags & GTF_UNSIGNED) != 0) { - codeGen->genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_bne, codeGen->rsGetRsvdReg()); + codeGen->genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_bne, tempReg); } else { - regNumber tmpReg = dst->GetSingleTempReg(); - assert(tmpReg != dst->GetRegNum()); - assert(tmpReg != src1->GetRegNum()); - assert(tmpReg != src2->GetRegNum()); + regNumber tempReg2 = dst->ExtractTempReg(); + assert(tempReg2 != dstReg); + assert(tempReg2 != src1Reg); + assert(tempReg2 != src2Reg); 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); + emitIns_R_R_I(EA_SIZE(attr) == EA_8BYTE ? INS_srai : INS_sraiw, attr, tempReg2, dstReg, + imm); + codeGen->genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_bne, tempReg, nullptr, tempReg2); } } } @@ -4339,19 +4335,19 @@ regNumber emitter::emitInsTernary(instruction ins, emitAttr attr, GenTree* dst, case GT_OR: case GT_XOR: { - emitIns_R_R_R(ins, attr, dst->GetRegNum(), src1->GetRegNum(), src2->GetRegNum()); + emitIns_R_R_R(ins, attr, dstReg, src1Reg, src2Reg); // 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); + emitIns_R_R_I(INS_slliw, attr, dstReg, dstReg, 0); } break; case GT_ADD: case GT_SUB: { - regNumber regOp1 = src1->GetRegNum(); - regNumber regOp2 = src2->GetRegNum(); + regNumber regOp1 = src1Reg; + regNumber regOp2 = src2Reg; regNumber saveOperReg1 = REG_NA; regNumber saveOperReg2 = REG_NA; @@ -4373,23 +4369,23 @@ regNumber emitter::emitInsTernary(instruction ins, emitAttr attr, GenTree* dst, { assert(!varTypeIsFloating(dst)); - assert(codeGen->rsGetRsvdReg() != dst->GetRegNum()); + assert(tempReg != dstReg); - if (dst->GetRegNum() == regOp1) + if (dstReg == regOp1) { - assert(codeGen->rsGetRsvdReg() != regOp1); + assert(tempReg != regOp1); assert(REG_RA != regOp1); - saveOperReg1 = codeGen->rsGetRsvdReg(); + saveOperReg1 = tempReg; saveOperReg2 = regOp2; - emitIns_R_R_I(INS_addi, attr, codeGen->rsGetRsvdReg(), regOp1, 0); + emitIns_R_R_I(INS_addi, attr, tempReg, regOp1, 0); } - else if (dst->GetRegNum() == regOp2) + else if (dstReg == regOp2) { - assert(codeGen->rsGetRsvdReg() != regOp2); + assert(tempReg != regOp2); assert(REG_RA != regOp2); saveOperReg1 = regOp1; - saveOperReg2 = codeGen->rsGetRsvdReg(); - emitIns_R_R_I(INS_addi, attr, codeGen->rsGetRsvdReg(), regOp2, 0); + saveOperReg2 = tempReg; + emitIns_R_R_I(INS_addi, attr, tempReg, regOp2, 0); } else { @@ -4398,7 +4394,7 @@ regNumber emitter::emitInsTernary(instruction ins, emitAttr attr, GenTree* dst, } } - emitIns_R_R_R(ins, attr, dst->GetRegNum(), regOp1, regOp2); + emitIns_R_R_R(ins, attr, dstReg, regOp1, regOp2); if (needCheckOv) { @@ -4407,12 +4403,13 @@ regNumber emitter::emitInsTernary(instruction ins, emitAttr attr, GenTree* dst, regNumber tempReg2; // ADD : A = B + C // SUB : C = A - B + bool isAdd = (dst->OperGet() == GT_ADD); if ((dst->gtFlags & GTF_UNSIGNED) != 0) { // if A < B, goto overflow - if (dst->OperGet() == GT_ADD) + if (isAdd) { - tempReg1 = dst->GetRegNum(); + tempReg1 = dstReg; tempReg2 = saveOperReg1; } else @@ -4425,16 +4422,13 @@ regNumber emitter::emitInsTernary(instruction ins, emitAttr attr, GenTree* dst, else { tempReg1 = REG_RA; - tempReg2 = dst->GetSingleTempReg(); + tempReg2 = dst->ExtractTempReg(); 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, tempReg1, isAdd ? saveOperReg1 : dstReg, ui6); emitIns_R_R_I(INS_srli, attr, tempReg2, saveOperReg2, ui6); emitIns_R_R_R(INS_xor, attr, tempReg1, tempReg1, tempReg2); @@ -4454,8 +4448,8 @@ regNumber emitter::emitInsTernary(instruction ins, emitAttr attr, GenTree* dst, emitIns_J_cond_la(INS_bne, tmpLabel3, tempReg2, 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_bge, tmpLabel, isAdd ? dstReg : saveOperReg1, + isAdd ? saveOperReg1 : saveOperReg2); codeGen->genDefineTempLabel(tmpLabel2); @@ -4464,8 +4458,8 @@ regNumber emitter::emitInsTernary(instruction ins, emitAttr attr, GenTree* dst, codeGen->genDefineTempLabel(tmpLabel3); // 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); + emitIns_J_cond_la(INS_blt, tmpLabel2, isAdd ? saveOperReg1 : saveOperReg2, + isAdd ? dstReg : saveOperReg1); codeGen->genDefineTempLabel(tmpLabel); } @@ -4478,7 +4472,7 @@ regNumber emitter::emitInsTernary(instruction ins, emitAttr attr, GenTree* dst, } } - return dst->GetRegNum(); + return dstReg; } unsigned emitter::get_curTotalCodeSize() diff --git a/src/coreclr/jit/lsrariscv64.cpp b/src/coreclr/jit/lsrariscv64.cpp index 2cf4511622772..fad675e26a6b0 100644 --- a/src/coreclr/jit/lsrariscv64.cpp +++ b/src/coreclr/jit/lsrariscv64.cpp @@ -24,6 +24,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #include "jit.h" #include "sideeffects.h" #include "lower.h" +#include "codegen.h" //------------------------------------------------------------------------ // BuildNode: Build the RefPositions for a node @@ -242,6 +243,8 @@ int LinearScan::BuildNode(GenTree* tree) { // Need a register different from target reg to check for overflow. buildInternalIntRegisterDefForNode(tree); + if ((tree->gtFlags & GTF_UNSIGNED) == 0) + buildInternalIntRegisterDefForNode(tree); setInternalRegsDelayFree = true; } FALLTHROUGH; @@ -254,6 +257,9 @@ int LinearScan::BuildNode(GenTree* tree) case GT_RSH: case GT_RSZ: case GT_ROR: + case GT_ROL: + if (tree->OperIs(GT_ROR, GT_ROL)) + buildInternalIntRegisterDefForNode(tree); srcCount = BuildBinaryUses(tree->AsOp()); buildInternalRegisterUses(); assert(dstCount == 1); @@ -275,6 +281,8 @@ int LinearScan::BuildNode(GenTree* tree) { // Need a register different from target reg to check for overflow. buildInternalIntRegisterDefForNode(tree); + if ((tree->gtFlags & GTF_UNSIGNED) == 0) + buildInternalIntRegisterDefForNode(tree); setInternalRegsDelayFree = true; } FALLTHROUGH; @@ -282,10 +290,65 @@ int LinearScan::BuildNode(GenTree* tree) case GT_MOD: case GT_UMOD: case GT_DIV: - case GT_MULHI: case GT_UDIV: { srcCount = BuildBinaryUses(tree->AsOp()); + + GenTree* divisorOp = tree->gtGetOp2(); + if (!varTypeIsFloating(tree->TypeGet()) && + !(divisorOp->IsIntegralConst(0) || divisorOp->GetRegNum() == REG_R0)) + { + bool needTemp = false; + if (divisorOp->isContainedIntOrIImmed()) + { + needTemp = true; // divisorReg + } + else if (tree->OperIsCommutative()) + { + if (tree->gtGetOp1()->isContainedIntOrIImmed()) + needTemp = true; // reg1 + } + + if (!needTemp && (tree->gtOper == GT_DIV || tree->gtOper == GT_MOD)) + { + bool checkDividend = true; + // Do we have an immediate for the 'divisorOp'? + if (divisorOp->IsCnsIntOrI()) + { + ssize_t intConstValue = divisorOp->AsIntCon()->gtIconVal; + if (intConstValue != -1) + { + checkDividend = false; // We statically know that the dividend is not -1 + } + } + ExceptionSetFlags exSetFlags = tree->OperExceptions(compiler); + if (checkDividend && + ((exSetFlags & ExceptionSetFlags::ArithmeticException) != ExceptionSetFlags::None)) + { + needTemp = true; + } + } + + if (needTemp) + buildInternalIntRegisterDefForNode(tree); + } + buildInternalRegisterUses(); + assert(dstCount == 1); + BuildDef(tree); + } + break; + + case GT_MULHI: + { + srcCount = BuildBinaryUses(tree->AsOp()); + + emitAttr attr = emitActualTypeSize(tree->AsOp()); + if (EA_SIZE(attr) != EA_8BYTE) + { + if ((tree->AsOp()->gtFlags & GTF_UNSIGNED) != 0) + buildInternalIntRegisterDefForNode(tree); + } + buildInternalRegisterUses(); assert(dstCount == 1); BuildDef(tree); @@ -343,6 +406,41 @@ int LinearScan::BuildNode(GenTree* tree) case GT_LE: case GT_GE: case GT_GT: + { + var_types op1Type = genActualType(tree->gtGetOp1()->TypeGet()); + if (varTypeIsFloating(op1Type)) + { + bool isUnordered = (tree->gtFlags & GTF_RELOP_NAN_UN) != 0; + if (isUnordered) + { + if (tree->OperIs(GT_EQ)) + buildInternalIntRegisterDefForNode(tree); + } + else + { + if (tree->OperIs(GT_NE)) + buildInternalIntRegisterDefForNode(tree); + } + } + else + { + emitAttr cmpSize = EA_ATTR(genTypeSize(op1Type)); + if (tree->gtGetOp2()->isContainedIntOrIImmed()) + { + bool isUnsigned = (tree->gtFlags & GTF_UNSIGNED) != 0; + if (cmpSize == EA_4BYTE && isUnsigned) + buildInternalIntRegisterDefForNode(tree); + } + else + { + if (cmpSize == EA_4BYTE) + buildInternalIntRegisterDefForNode(tree); + } + } + buildInternalRegisterUses(); + } + FALLTHROUGH; + case GT_JCMP: srcCount = BuildCmp(tree); break; @@ -454,6 +552,8 @@ int LinearScan::BuildNode(GenTree* tree) // Non-const No 2 // + bool needExtraTemp = (compiler->lvaOutgoingArgSpaceSize > 0); + GenTree* size = tree->gtGetOp1(); if (size->IsCnsIntOrI()) { @@ -480,13 +580,15 @@ int LinearScan::BuildNode(GenTree* tree) // No need to initialize allocated stack space. if (sizeVal < compiler->eeGetPageSize()) { - // Need no internal registers + ssize_t imm = -(ssize_t)sizeVal; + needExtraTemp |= !emitter::isValidSimm12(imm); } else { // We need two registers: regCnt and RegTmp buildInternalIntRegisterDefForNode(tree); buildInternalIntRegisterDefForNode(tree); + needExtraTemp = true; } } } @@ -498,9 +600,13 @@ int LinearScan::BuildNode(GenTree* tree) { buildInternalIntRegisterDefForNode(tree); buildInternalIntRegisterDefForNode(tree); + needExtraTemp = true; } } + if (needExtraTemp) + buildInternalIntRegisterDefForNode(tree); // tempReg + if (!size->isContained()) { BuildUse(size); @@ -549,6 +655,14 @@ int LinearScan::BuildNode(GenTree* tree) } assert(dstCount == 1); + if ((base != nullptr) && (index != nullptr)) + { + DWORD scale; + BitScanForward(&scale, lea->gtScale); + if (scale > 0) + buildInternalIntRegisterDefForNode(tree); // scaleTempReg + } + // On RISCV64 we may need a single internal register // (when both conditions are true then we still only need a single internal register) if ((index != nullptr) && (cns != 0)) @@ -1266,6 +1380,12 @@ int LinearScan::BuildBlockStore(GenTreeBlk* blkNode) // int LinearScan::BuildCast(GenTreeCast* cast) { + enum CodeGen::GenIntCastDesc::CheckKind kind = CodeGen::GenIntCastDesc(cast).CheckKind(); + if ((kind != CodeGen::GenIntCastDesc::CHECK_NONE) && (kind != CodeGen::GenIntCastDesc::CHECK_POSITIVE)) + { + buildInternalIntRegisterDefForNode(cast); + } + buildInternalRegisterUses(); int srcCount = BuildOperandUses(cast->CastOp()); BuildDef(cast);