diff --git a/src/coreclr/jit/codegenriscv64.cpp b/src/coreclr/jit/codegenriscv64.cpp index 6deaa25f599831..021343e95173b3 100644 --- a/src/coreclr/jit/codegenriscv64.cpp +++ b/src/coreclr/jit/codegenriscv64.cpp @@ -3188,7 +3188,6 @@ void CodeGen::genCodeForCompare(GenTreeOp* tree) regOp1 = tmpRegOp1; } } - if (tree->OperIs(GT_EQ, GT_NE)) { if ((imm != 0) || (cmpSize == EA_4BYTE)) @@ -3353,8 +3352,14 @@ void CodeGen::genCodeForJumpCompare(GenTreeOpCC* tree) regNumber tmpRegOp1 = rsGetRsvdReg(); assert(regOp1 != tmpRegOp1); imm = static_cast(imm); - emit->emitIns_R_R(INS_sext_w, EA_8BYTE, tmpRegOp1, regOp1); - regOp1 = tmpRegOp1; + + // It might be possible to watch the type of op1 to decide the redundancy. + // But due to the safety reason, only a peephole optimization is done now. + if (!(emit->isRedundantSignExtend(INS_sext_w, EA_8BYTE, tmpRegOp1, regOp1))) + { + emit->emitIns_R_R(INS_sext_w, EA_8BYTE, tmpRegOp1, regOp1); + regOp1 = tmpRegOp1; + } break; } case EA_8BYTE: @@ -3389,8 +3394,14 @@ void CodeGen::genCodeForJumpCompare(GenTreeOpCC* tree) { regNumber tmpRegOp1 = rsGetRsvdReg(); assert(regOp1 != tmpRegOp1); - emit->emitIns_R_R(INS_sext_w, EA_8BYTE, tmpRegOp1, regOp1); - regOp1 = tmpRegOp1; + + // It might be possible to watch the type of op1 to decide the redundancy. + // But due to the safety reason, only a peephole optimization is done now. + if (!(emit->isRedundantSignExtend(INS_sext_w, EA_8BYTE, tmpRegOp1, regOp1))) + { + emit->emitIns_R_R(INS_sext_w, EA_8BYTE, tmpRegOp1, regOp1); + regOp1 = tmpRegOp1; + } } } @@ -3438,10 +3449,23 @@ void CodeGen::genCodeForJumpCompare(GenTreeOpCC* tree) regNumber tmpRegOp2 = rsGetRsvdReg(); assert(regOp1 != tmpRegOp2); assert(regOp2 != tmpRegOp2); - emit->emitIns_R_R(INS_sext_w, EA_8BYTE, tmpRegOp1, regOp1); - emit->emitIns_R_R(INS_sext_w, EA_8BYTE, tmpRegOp2, regOp2); - regOp1 = tmpRegOp1; - regOp2 = tmpRegOp2; + + // It might be possible to watch the type of op1 to decide the redundancy. + // But due to the safety reason, only a peephole optimization is done now. + bool signExtOp1 = !(emit->isRedundantSignExtend(INS_sext_w, EA_8BYTE, tmpRegOp1, regOp1)); + bool signExtOp2 = !(emit->isRedundantSignExtend(INS_sext_w, EA_8BYTE, tmpRegOp2, regOp2)); + + if (signExtOp1) + { + emit->emitIns_R_R(INS_sext_w, EA_8BYTE, tmpRegOp1, regOp1); + regOp1 = tmpRegOp1; + } + + if (signExtOp2) + { + emit->emitIns_R_R(INS_sext_w, EA_8BYTE, tmpRegOp2, regOp2); + regOp2 = tmpRegOp2; + } } switch (cond.GetCode()) diff --git a/src/coreclr/jit/emitriscv64.cpp b/src/coreclr/jit/emitriscv64.cpp index bf11222800d09b..6f78573fb18635 100644 --- a/src/coreclr/jit/emitriscv64.cpp +++ b/src/coreclr/jit/emitriscv64.cpp @@ -640,6 +640,101 @@ void emitter::emitIns_Mov(emitAttr attr, regNumber dstReg, regNumber srcReg, boo } } +//------------------------------------------------------------------------ +// emitInsIsSignExtend: Determines whether a given instruction sign extends +// +// Arguments: +// ins -- The instruction being checked +// +bool emitter::emitInsIsSignExtend(instruction ins) +{ + switch (ins) + { + case INS_sext_w: // R_R + case INS_lui: // R_I + + // R_R_I + case INS_lb: + case INS_lh: + case INS_lw: + + // R_R_I + case INS_addiw: + case INS_slliw: + case INS_srliw: + case INS_sraiw: + + // R_R_R + case INS_addw: + case INS_subw: + case INS_sllw: + case INS_srlw: + case INS_sraw: + + // R_R_R + case INS_mulw: + case INS_divw: + case INS_divuw: + case INS_remw: + case INS_remuw: + { + return true; + } + // TODO: Add more sign-extension instructions + default: + { + return false; + } + } +} + +//------------------------------------------------------------------------ +// isRedundantSignExtend: +// Check if the current 'sext.w' instruction is redundant and can be omitted. +// +// A 'sext.w' instruction is redundant if the previous instruction sign extends +// the source register of current instruction. +// +// Arguments: +// ins -- The instruction being emitted +// attr -- The emit attribute +// dst -- The destination register +// src -- The source register +// +bool emitter::isRedundantSignExtend(instruction ins, emitAttr size, regNumber dst, regNumber src) +{ + assert(ins == INS_sext_w); + + if (!emitComp->opts.OptimizationEnabled()) + { + return false; + } + + const bool canOptimize = emitCanPeepholeLastIns(); + + if (!canOptimize) + { + return false; + } + + regNumber prevDst = emitLastIns->idReg1(); + regNumber prevSrc = emitLastIns->idReg2(); + emitAttr prevSize = emitLastIns->idOpSize(); + + bool isPrevInsSignExtend = emitInsIsSignExtend(emitLastIns->idIns()); + + if (isPrevInsSignExtend && (prevDst == src)) + { + JITDUMP("\n -- suppressing 'sext.w reg%u, reg%u' as previous instruction already sign-extended " + "the register reg%u.\n", + dst, src, prevDst); + + return true; + } + + return false; +} + /***************************************************************************** * * Add an instruction referencing two registers diff --git a/src/coreclr/jit/emitriscv64.h b/src/coreclr/jit/emitriscv64.h index 57f7472c245934..b75feeed8b9fe1 100644 --- a/src/coreclr/jit/emitriscv64.h +++ b/src/coreclr/jit/emitriscv64.h @@ -19,6 +19,8 @@ struct CnsVal bool cnsReloc; }; +bool isRedundantSignExtend(instruction ins, emitAttr size, regNumber dst, regNumber src); + #ifdef DEBUG /************************************************************************/ @@ -61,6 +63,7 @@ instrDesc* emitNewInstrCallInd(int argCnt, bool emitInsIsLoad(instruction ins); bool emitInsIsStore(instruction ins); bool emitInsIsLoadOrStore(instruction ins); +bool emitInsIsSignExtend(instruction ins); void emitDispInsName( code_t code, const BYTE* addr, bool doffs, unsigned insOffset, const instrDesc* id, const insGroup* ig);