Skip to content
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

[LoongArch64] fix the errors for mod/div after #82924. #85140

Merged
merged 1 commit into from
Apr 24, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
251 changes: 118 additions & 133 deletions src/coreclr/jit/codegenloongarch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2580,183 +2580,168 @@ void CodeGen::genCodeForDivMod(GenTreeOp* tree)
assert(varTypeIsFloating(tree->gtOp1));
assert(varTypeIsFloating(tree->gtOp2));
assert(tree->gtOper == GT_DIV);
// genCodeForBinary(tree);

instruction ins = genGetInsForOper(tree);
emit->emitIns_R_R_R(ins, emitActualTypeSize(targetType), tree->GetRegNum(), tree->gtOp1->GetRegNum(),
tree->gtOp2->GetRegNum());
}
else // an integer divide operation
else // an integer divide operation.
{
GenTree* divisorOp = tree->gtGetOp2();
GenTree* divisorOp = tree->gtGetOp2();
regNumber divisorReg = divisorOp->GetRegNum();

// divisorOp can be immed or reg
assert(!tree->gtOp1->isContained() && !tree->gtOp1->isContainedIntOrIImmed());
assert(!divisorOp->isContained() || divisorOp->isContainedIntOrIImmed());

if (divisorOp->IsIntegralConst(0) || divisorOp->GetRegNum() == REG_R0)
{
// We unconditionally throw a divide by zero exception
genJumpToThrowHlpBlk(EJ_jmp, SCK_DIV_BY_ZERO);
}
else // the divisor is not the constant zero
{
GenTree* src1 = tree->gtOp1;
unsigned TypeSize = genTypeSize(genActualType(tree->TypeGet()));
emitAttr size = EA_ATTR(TypeSize);

assert(TypeSize >= genTypeSize(genActualType(src1->TypeGet())) &&
TypeSize >= genTypeSize(genActualType(divisorOp->TypeGet())));
ExceptionSetFlags exSetFlags = tree->OperExceptions(compiler);

// ssize_t intConstValue = divisorOp->AsIntCon()->gtIconVal;
regNumber Reg1 = src1->GetRegNum();
regNumber divisorReg = divisorOp->GetRegNum();
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 = REG_R21;
emit->emitIns_I_la(EA_PTRSIZE, REG_R21, intConst);
}
// Only for commutative operations do we check src1 and allow it to be a contained immediate
else if (tree->OperIsCommutative())
if ((exSetFlags & ExceptionSetFlags::DivideByZeroException) != ExceptionSetFlags::None)
{
if (divisorOp->IsIntegralConst(0) || (divisorReg == REG_R0))
{
// src1 can be immed or reg
assert(!src1->isContained() || src1->isContainedIntOrIImmed());
// We unconditionally throw a divide by zero exception
genJumpToThrowHlpBlk(EJ_jmp, SCK_DIV_BY_ZERO);

// Check src1 and allow it to be a contained immediate
if (src1->isContainedIntOrIImmed())
{
assert(!divisorOp->isContainedIntOrIImmed());
ssize_t intConst = (int)(src1->AsIntCon()->gtIconVal);
Reg1 = REG_R21;
emit->emitIns_I_la(EA_PTRSIZE, REG_R21, intConst);
}
// We still need to call genProduceReg
genProduceReg(tree);

return;
}
else
{
// src1 can only be a reg
assert(!src1->isContained());
assert(emitter::isGeneralRegister(divisorReg));

// Check if the divisor is zero throw a DivideByZeroException
genJumpToThrowHlpBlk_la(SCK_DIV_BY_ZERO, INS_beq, divisorReg);
}
}

GenTree* src1 = tree->gtOp1;
emitAttr size = EA_ATTR(genTypeSize(genActualType(tree->TypeGet())));

assert(!divisorOp->IsIntegralConst(0));

regNumber Reg1 = src1->GetRegNum();
instruction ins;

// Generate the require runtime checks for GT_DIV or GT_UDIV
if (tree->gtOper == GT_DIV || tree->gtOper == GT_MOD)
// 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 = emitter::isGeneralRegister(divisorReg) ? divisorReg : REG_R21;
emit->emitIns_I_la(EA_PTRSIZE, divisorReg, intConst);
}
else
{
// src1 can only be a reg
assert(!src1->isContained());
assert(emitter::isGeneralRegister(Reg1));
assert(emitter::isGeneralRegister(divisorReg));
}

// check (MinInt / -1) => ArithmeticException
if (tree->gtOper == GT_DIV || tree->gtOper == GT_MOD)
{
if ((exSetFlags & ExceptionSetFlags::ArithmeticException) != ExceptionSetFlags::None)
{
// Two possible exceptions:
// (AnyVal / 0) => DivideByZeroException
// (MinInt / -1) => ArithmeticException
//
bool checkDividend = true;
// Check if the divisor is not -1 branch to 'sdivLabel'
emit->emitIns_R_R_I(INS_addi_d, EA_PTRSIZE, REG_SCRATCH, REG_R0, -1);
BasicBlock* sdivLabel = genCreateTempLabel(); // can optimize for loongarch64.
emit->emitIns_J_cond_la(INS_bne, sdivLabel, REG_SCRATCH, divisorReg);

// Do we have an immediate for the 'divisorOp'?
// If control flow continues past here the 'divisorReg' is known to be -1
regNumber dividendReg = tree->gtGetOp1()->GetRegNum();

// At this point the divisor is known to be -1
//
// Whether dividendReg is MinInt or not
//
if (divisorOp->IsCnsIntOrI())
if (size == EA_4BYTE)
{
ssize_t intConstValue = divisorOp->AsIntCon()->gtIconVal;
// assert(intConstValue != 0); // already checked above by IsIntegralConst(0)
if (intConstValue != -1)
{
checkDividend = false; // We statically know that the dividend is not -1
}
// MinInt=0x80000000
emit->emitIns_R_R_I(INS_slli_w, EA_4BYTE, REG_SCRATCH, REG_SCRATCH, 31);
}
else // insert check for division by zero
else
{
// Check if the divisor is zero throw a DivideByZeroException
genJumpToThrowHlpBlk_la(SCK_DIV_BY_ZERO, INS_beq, divisorReg);
assert(size == EA_8BYTE);
// MinInt=0x8000000000000000
emit->emitIns_R_R_I(INS_slli_d, EA_8BYTE, REG_SCRATCH, REG_SCRATCH, 63);
}
genJumpToThrowHlpBlk_la(SCK_ARITH_EXCPN, INS_beq, REG_SCRATCH, nullptr, dividendReg);
genDefineTempLabel(sdivLabel);
}

if (checkDividend)
// Generate the sdiv instruction
if (size == EA_4BYTE)
{
if (tree->OperGet() == GT_DIV)
{
// Check if the divisor is not -1 branch to 'sdivLabel'
emit->emitIns_R_R_I(INS_addi_d, EA_PTRSIZE, REG_R21, REG_R0, -1);
BasicBlock* sdivLabel = genCreateTempLabel(); // can optimize for loongarch64.
emit->emitIns_J_cond_la(INS_bne, sdivLabel, REG_R21, divisorReg);

// If control flow continues past here the 'divisorReg' is known to be -1
regNumber dividendReg = tree->gtGetOp1()->GetRegNum();
// At this point the divisor is known to be -1
//
// Whether dividendReg is MinInt or not
//

emit->emitIns_J_cond_la(INS_beq, sdivLabel, dividendReg, REG_R0);

emit->emitIns_R_R_R(size == EA_4BYTE ? INS_add_w : INS_add_d, size, REG_R21, dividendReg,
dividendReg);
genJumpToThrowHlpBlk_la(SCK_ARITH_EXCPN, INS_beq, REG_R21);
genDefineTempLabel(sdivLabel);
ins = INS_div_w;
}

// Generate the sdiv instruction
if (size == EA_4BYTE)
else
{
if (tree->OperGet() == GT_DIV)
{
ins = INS_div_w;
}
else
{
ins = INS_mod_w;
}
ins = INS_mod_w;
}
}
else
{
if (tree->OperGet() == GT_DIV)
{
ins = INS_div_d;
}
else
{
if (tree->OperGet() == GT_DIV)
{
ins = INS_div_d;
}
else
{
ins = INS_mod_d;
}
ins = INS_mod_d;
}

emit->emitIns_R_R_R(ins, size, tree->GetRegNum(), Reg1, divisorReg);
}
else // if (tree->gtOper == GT_UDIV) GT_UMOD

emit->emitIns_R_R_R(ins, size, tree->GetRegNum(), Reg1, divisorReg);
}
else // if (tree->gtOper == GT_UDIV) GT_UMOD
{
// Only one possible exception
// (AnyVal / 0) => DivideByZeroException
//
// Note that division by the constant 0 was already checked for above by the
// op2->IsIntegralConst(0) check
//

if (!divisorOp->IsCnsIntOrI())
{
// Only one possible exception
// (AnyVal / 0) => DivideByZeroException
//
// Note that division by the constant 0 was already checked for above by the
// op2->IsIntegralConst(0) check
// divisorOp is not a constant, so it could be zero
//
genJumpToThrowHlpBlk_la(SCK_DIV_BY_ZERO, INS_beq, divisorReg);
}

if (!divisorOp->IsCnsIntOrI())
if (size == EA_4BYTE)
{
if (tree->OperGet() == GT_UDIV)
{
// divisorOp is not a constant, so it could be zero
//
genJumpToThrowHlpBlk_la(SCK_DIV_BY_ZERO, INS_beq, divisorReg);
ins = INS_div_wu;
}

if (size == EA_4BYTE)
else
{
if (tree->OperGet() == GT_UDIV)
{
ins = INS_div_wu;
}
else
{
ins = INS_mod_wu;
}
ins = INS_mod_wu;
}

// TODO-LOONGARCH64: here is just for signed-extension ?
emit->emitIns_R_R_I(INS_slli_w, EA_4BYTE, Reg1, Reg1, 0);
emit->emitIns_R_R_I(INS_slli_w, EA_4BYTE, divisorReg, divisorReg, 0);
// TODO-LOONGARCH64: here is just for signed-extension ?
emit->emitIns_R_R_I(INS_slli_w, EA_4BYTE, Reg1, Reg1, 0);
emit->emitIns_R_R_I(INS_slli_w, EA_4BYTE, divisorReg, divisorReg, 0);
}
else
{
if (tree->OperGet() == GT_UDIV)
{
ins = INS_div_du;
}
else
{
if (tree->OperGet() == GT_UDIV)
{
ins = INS_div_du;
}
else
{
ins = INS_mod_du;
}
ins = INS_mod_du;
}

emit->emitIns_R_R_R(ins, size, tree->GetRegNum(), Reg1, divisorReg);
}

emit->emitIns_R_R_R(ins, size, tree->GetRegNum(), Reg1, divisorReg);
}
}
genProduceReg(tree);
Expand Down