-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[RISC-V] Fix invalid operand register in the emitted addition/subtraction code #102074
Changes from all commits
f2d7eb1
cf7afe4
e962811
836f439
bcdb4a4
3e3b72f
685f72e
37ed8d2
71f9c49
a5d29d8
c6614fa
971b36f
4e0264b
3d0ba8e
807acfc
4316263
b841e3c
f82a853
1f5dfa9
965be5a
b34f37d
4371f04
ad89ff5
a2cdb16
a5c582f
9078647
7b24b88
6a6dc82
06dbd79
e464442
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -588,7 +588,7 @@ void emitter::emitIns_R_R( | |
{ | ||
code_t code = emitInsCode(ins); | ||
|
||
if (INS_mov == ins) | ||
if (INS_mov == ins || INS_sext_w == ins) | ||
{ | ||
assert(isGeneralRegisterOrR0(reg1)); | ||
assert(isGeneralRegisterOrR0(reg2)); | ||
|
@@ -3561,8 +3561,15 @@ void emitter::emitDispInsName( | |
//} | ||
switch (opcode2) | ||
{ | ||
case 0x0: // ADDIW | ||
printf("addiw %s, %s, %d\n", rd, rs1, imm12); | ||
case 0x0: // ADDIW & SEXT.W | ||
if (imm12 == 0) | ||
{ | ||
printf("sext.w %s, %s\n", rd, rs1); | ||
} | ||
else | ||
{ | ||
printf("addiw %s, %s, %d\n", rd, rs1, imm12); | ||
} | ||
return; | ||
case 0x1: // SLLIW | ||
printf("slliw %s, %s, %d\n", rd, rs1, imm12 & 0x3f); // 6 BITS for SHAMT in RISCV64 | ||
|
@@ -4980,18 +4987,16 @@ regNumber emitter::emitInsTernary(instruction ins, emitAttr attr, GenTree* dst, | |
if (dstReg == regOp1) | ||
{ | ||
assert(tempReg != regOp1); | ||
assert(REG_RA != regOp1); | ||
saveOperReg1 = tempReg; | ||
saveOperReg2 = regOp2; | ||
emitIns_R_R_I(INS_addi, attr, tempReg, regOp1, 0); | ||
saveOperReg2 = (regOp1 == regOp2) ? tempReg : regOp2; | ||
emitIns_R_R(INS_mov, attr, tempReg, regOp1); | ||
} | ||
else if (dstReg == regOp2) | ||
{ | ||
assert(tempReg != regOp2); | ||
assert(REG_RA != regOp2); | ||
saveOperReg1 = regOp1; | ||
saveOperReg2 = tempReg; | ||
emitIns_R_R_I(INS_addi, attr, tempReg, regOp2, 0); | ||
emitIns_R_R(INS_mov, attr, tempReg, regOp2); | ||
} | ||
else | ||
{ | ||
|
@@ -5002,73 +5007,84 @@ regNumber emitter::emitInsTernary(instruction ins, emitAttr attr, GenTree* dst, | |
|
||
emitIns_R_R_R(ins, attr, dstReg, regOp1, regOp2); | ||
|
||
/* | ||
Check if A = B + C | ||
ADD : A = B + C | ||
SUB : B = A - C | ||
In case of addition: | ||
dst = src1 + src2 | ||
A = dst | ||
B = src1 | ||
C = src2 | ||
In case of subtraction: | ||
dst = src1 - src2 | ||
src1 = dst + src2 | ||
A = src1 | ||
B = dst | ||
C = src2 | ||
*/ | ||
if (needCheckOv) | ||
{ | ||
ssize_t imm; | ||
regNumber tempReg1; | ||
regNumber tempReg2; | ||
// ADD : A = B + C | ||
// SUB : C = A - B | ||
bool isAdd = (dst->OperGet() == GT_ADD); | ||
regNumber resultReg = REG_NA; | ||
|
||
if (dst->OperGet() == GT_ADD) | ||
{ | ||
resultReg = dstReg; | ||
regOp1 = saveOperReg1; | ||
regOp2 = saveOperReg2; | ||
} | ||
else | ||
{ | ||
resultReg = saveOperReg1; | ||
regOp1 = dstReg; | ||
regOp2 = saveOperReg2; | ||
Bajtazar marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
instruction branchIns = INS_none; | ||
regNumber branchReg1 = REG_NA; | ||
regNumber branchReg2 = REG_NA; | ||
|
||
if ((dst->gtFlags & GTF_UNSIGNED) != 0) | ||
{ | ||
// if A < B, goto overflow | ||
if (isAdd) | ||
{ | ||
tempReg1 = dstReg; | ||
tempReg2 = saveOperReg1; | ||
} | ||
else | ||
{ | ||
tempReg1 = saveOperReg1; | ||
tempReg2 = saveOperReg2; | ||
} | ||
codeGen->genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_bltu, tempReg1, nullptr, tempReg2); | ||
// if A < B then overflow | ||
branchIns = INS_bltu; | ||
branchReg1 = resultReg; | ||
branchReg2 = regOp1; | ||
} | ||
else | ||
{ | ||
tempReg1 = REG_RA; | ||
tempReg2 = codeGen->internalRegisters.Extract(dst); | ||
assert(tempReg1 != tempReg2); | ||
assert(tempReg1 != saveOperReg1); | ||
assert(tempReg2 != saveOperReg2); | ||
regNumber tempReg1 = codeGen->internalRegisters.GetSingle(dst); | ||
|
||
ssize_t ui6 = (attr == EA_4BYTE) ? 31 : 63; | ||
emitIns_R_R_I(INS_srli, attr, tempReg1, isAdd ? saveOperReg1 : dstReg, ui6); | ||
emitIns_R_R_I(INS_srli, attr, tempReg2, saveOperReg2, ui6); | ||
branchIns = INS_bne; | ||
|
||
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, tmpLabel, tempReg1, REG_R0); | ||
|
||
emitIns_J_cond_la(INS_bne, tmpLabel3, tempReg2, REG_R0); | ||
assert(src1->gtType != TYP_LONG); | ||
assert(src2->gtType != TYP_LONG); | ||
|
||
// B > 0 and C > 0, if A < B, goto overflow | ||
emitIns_J_cond_la(INS_bge, tmpLabel, isAdd ? dstReg : saveOperReg1, | ||
isAdd ? saveOperReg1 : saveOperReg2); | ||
emitIns_R_R_R(INS_add, attr, tempReg1, regOp1, regOp2); | ||
|
||
codeGen->genDefineTempLabel(tmpLabel2); | ||
|
||
codeGen->genJumpToThrowHlpBlk(EJ_jmp, SCK_OVERFLOW); | ||
|
||
codeGen->genDefineTempLabel(tmpLabel3); | ||
// if 64-bit addition is not equal to 32-bit addition for 32-bit operands then overflow | ||
branchReg1 = resultReg; | ||
branchReg2 = tempReg1; | ||
} | ||
else | ||
{ | ||
assert(attr == EA_8BYTE); | ||
assert(tempReg != tempReg1); | ||
// When the tempReg2 is being used then the tempReg has to be already dead | ||
regNumber tempReg2 = tempReg; | ||
|
||
// B < 0 and C < 0, if A > B, goto overflow | ||
emitIns_J_cond_la(INS_blt, tmpLabel2, isAdd ? saveOperReg1 : saveOperReg2, | ||
isAdd ? dstReg : saveOperReg1); | ||
emitIns_R_R_R(INS_slt, attr, tempReg1, resultReg, regOp1); | ||
emitIns_R_R_I(INS_slti, attr, tempReg2, regOp2, 0); | ||
|
||
codeGen->genDefineTempLabel(tmpLabel); | ||
// if ((A < B) != (C < 0)) then overflow | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For subtraction, is it correct comment? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMO it is Ok, I've used the property of the overflows in RISCV64 that operations ignore overflow and wraps around 2^64. Due to this if A = B - C overflows then B = A + C does too. I've shuffled registers at the beginning according to the type of the operation so that at the end I just checks whether there is an addition overflow There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was confused. Thank you for your explanation. |
||
branchReg1 = tempReg1; | ||
branchReg2 = tempReg2; | ||
} | ||
} | ||
|
||
codeGen->genJumpToThrowHlpBlk_la(SCK_OVERFLOW, branchIns, branchReg1, nullptr, branchReg2); | ||
} | ||
} | ||
break; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you discussed in your team to use pseudo code actively in JIT?
Actually, I want to remove all pseudo codes like
mov
in JITC because some pseudo codes (contains multiple normal instructions) cannot be used in JIT.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO simple "renaming" pseudos like sext.w, bnez, mov, etc, are fine. We're already using them, they convey the intention a bit more clearly, and they make the assembly look closer to print-outs from native compilers.
I agree about multi-instruction pseudos, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay. Actually, we used few pesudos in few code locations, however AFAIK it is not printed properly in dump. I just let those instruction because I hope removing later. If you want to use pseudos. Could you add such instructions like 'mov' and 'nop' in
emitDispInsName
too?Thank you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can add pseudos to the disassm but I would prefer to do it in other PR. Would you mind?