From 1cea8098e27cc040afd158020d4412b6abb1fc1d Mon Sep 17 00:00:00 2001 From: Mikhail Skvortcov Date: Mon, 24 Apr 2017 14:10:20 +0300 Subject: [PATCH] RyuJIT/ARM32: Enable arithmetic overflow checks. --- src/jit/codegenarm.cpp | 35 ++--------------- src/jit/emitarm.cpp | 101 ++++++++++++++++++------------------------------- 2 files changed, 40 insertions(+), 96 deletions(-) diff --git a/src/jit/codegenarm.cpp b/src/jit/codegenarm.cpp index bac24d5..81ba35e 100644 --- a/src/jit/codegenarm.cpp +++ b/src/jit/codegenarm.cpp @@ -216,14 +216,8 @@ void CodeGen::genCodeForBinary(GenTree* treeNode) var_types targetType = treeNode->TypeGet(); emitter* emit = getEmitter(); - assert(oper == GT_ADD || oper == GT_SUB || oper == GT_ADD_LO || oper == GT_ADD_HI || oper == GT_SUB_LO || - oper == GT_SUB_HI || oper == GT_OR || oper == GT_XOR || oper == GT_AND); - - if ((oper == GT_ADD || oper == GT_SUB || oper == GT_ADD_HI || oper == GT_SUB_HI) && treeNode->gtOverflow()) - { - // This is also checked in the importer. - NYI("Overflow not yet implemented"); - } + assert(oper == GT_ADD || oper == GT_SUB || oper == GT_MUL || oper == GT_ADD_LO || oper == GT_ADD_HI || + oper == GT_SUB_LO || oper == GT_SUB_HI || oper == GT_OR || oper == GT_XOR || oper == GT_AND); GenTreePtr op1 = treeNode->gtGetOp1(); GenTreePtr op2 = treeNode->gtGetOp2(); @@ -403,32 +397,9 @@ void CodeGen::genCodeForTreeNode(GenTreePtr treeNode) case GT_SUB_HI: case GT_ADD: case GT_SUB: - genConsumeOperands(treeNode->AsOp()); - genCodeForBinary(treeNode); - break; - case GT_MUL: - { genConsumeOperands(treeNode->AsOp()); - - const genTreeOps oper = treeNode->OperGet(); - if (treeNode->gtOverflow()) - { - // This is also checked in the importer. - NYI("Overflow not yet implemented"); - } - - GenTreePtr op1 = treeNode->gtGetOp1(); - GenTreePtr op2 = treeNode->gtGetOp2(); - instruction ins = genGetInsForOper(treeNode->OperGet(), targetType); - - // The arithmetic node must be sitting in a register (since it's not contained) - noway_assert(targetReg != REG_NA); - - regNumber r = emit->emitInsTernary(ins, emitTypeSize(treeNode), treeNode, op1, op2); - assert(r == targetReg); - } - genProduceReg(treeNode); + genCodeForBinary(treeNode); break; case GT_LSH: diff --git a/src/jit/emitarm.cpp b/src/jit/emitarm.cpp index 30eaca9..2b8eb25 100644 --- a/src/jit/emitarm.cpp +++ b/src/jit/emitarm.cpp @@ -7680,8 +7680,6 @@ regNumber emitter::emitInsBinary(instruction ins, emitAttr attr, GenTree* dst, G regNumber emitter::emitInsTernary(instruction ins, emitAttr attr, GenTree* dst, GenTree* src1, GenTree* src2) { - regNumber result = REG_NA; - // dst can only be a reg assert(!dst->isContained()); @@ -7728,18 +7726,14 @@ regNumber emitter::emitInsTernary(instruction ins, emitAttr attr, GenTree* dst, assert(!src1->isContained()); } } - bool isMulOverflow = false; + + insFlags flags = INS_FLAGS_DONT_CARE; + bool isMulOverflow = false; if (dst->gtOverflowEx()) { - NYI_ARM("emitInsTernary overflow"); -#if 0 - if (ins == INS_add) - { - ins = INS_adds; - } - else if (ins == INS_sub) + if ((ins == INS_add) || (ins == INS_adc) || (ins == INS_sub) || (ins == INS_sbc)) { - ins = INS_subs; + flags = INS_FLAGS_SET; } else if (ins == INS_mul) { @@ -7750,88 +7744,67 @@ regNumber emitter::emitInsTernary(instruction ins, emitAttr attr, GenTree* dst, { assert(!"Invalid ins for overflow check"); } -#endif } if (intConst != nullptr) { - emitIns_R_R_I(ins, attr, dst->gtRegNum, nonIntReg->gtRegNum, intConst->IconValue()); + emitIns_R_R_I(ins, attr, dst->gtRegNum, nonIntReg->gtRegNum, intConst->IconValue(), flags); } else { if (isMulOverflow) { - NYI_ARM("emitInsTernary overflow"); -#if 0 regNumber extraReg = dst->GetSingleTempReg(); assert(extraReg != dst->gtRegNum); if ((dst->gtFlags & GTF_UNSIGNED) != 0) { - if (attr == EA_4BYTE) - { - // Compute 8 byte results from 4 byte by 4 byte multiplication. - emitIns_R_R_R(INS_umull, EA_8BYTE, dst->gtRegNum, src1->gtRegNum, src2->gtRegNum); - - // Get the high result by shifting dst. - emitIns_R_R_I(INS_lsr, EA_8BYTE, extraReg, dst->gtRegNum, 32); - } - else - { - assert(attr == EA_8BYTE); - // Compute the high result. - emitIns_R_R_R(INS_umulh, attr, extraReg, src1->gtRegNum, src2->gtRegNum); - - // Now multiply without skewing the high result. - emitIns_R_R_R(ins, attr, dst->gtRegNum, src1->gtRegNum, src2->gtRegNum); - } + // Compute 8 byte result from 4 byte by 4 byte multiplication. + emitIns_R_R_R_R(INS_umull, EA_4BYTE, dst->gtRegNum, extraReg, src1->gtRegNum, src2->gtRegNum); - // zero-sign bit comparison to detect overflow. + // Overflow exists if the result's high word is non-zero. emitIns_R_I(INS_cmp, attr, extraReg, 0); } else { - int bitShift = 0; - if (attr == EA_4BYTE) - { - // Compute 8 byte results from 4 byte by 4 byte multiplication. - emitIns_R_R_R(INS_smull, EA_8BYTE, dst->gtRegNum, src1->gtRegNum, src2->gtRegNum); - - // Get the high result by shifting dst. - emitIns_R_R_I(INS_lsr, EA_8BYTE, extraReg, dst->gtRegNum, 32); + // Compute 8 byte result from 4 byte by 4 byte multiplication. + emitIns_R_R_R_R(INS_smull, EA_4BYTE, dst->gtRegNum, extraReg, src1->gtRegNum, src2->gtRegNum); - bitShift = 31; - } - else - { - assert(attr == EA_8BYTE); - // Save the high result in a temporary register. - emitIns_R_R_R(INS_smulh, attr, extraReg, src1->gtRegNum, src2->gtRegNum); - - // Now multiply without skewing the high result. - emitIns_R_R_R(ins, attr, dst->gtRegNum, src1->gtRegNum, src2->gtRegNum); - - bitShift = 63; - } - - // Sign bit comparison to detect overflow. - emitIns_R_R_I(INS_cmp, attr, extraReg, dst->gtRegNum, bitShift, INS_OPTS_ASR); + // Overflow exists if the result's high word is not merely a sign bit. + emitIns_R_R_I(INS_cmp, attr, extraReg, dst->gtRegNum, 31, INS_FLAGS_DONT_CARE, INS_OPTS_ASR); } -#endif } else { - // We can just multiply. - emitIns_R_R_R(ins, attr, dst->gtRegNum, src1->gtRegNum, src2->gtRegNum); + // We can just do the arithmetic, setting the flags if needed. + emitIns_R_R_R(ins, attr, dst->gtRegNum, src1->gtRegNum, src2->gtRegNum, flags); } } if (dst->gtOverflowEx()) { - NYI_ARM("emitInsTernary overflow"); -#if 0 assert(!varTypeIsFloating(dst)); - codeGen->genCheckOverflow(dst); -#endif + + emitJumpKind jumpKind; + + if (dst->OperGet() == GT_MUL) + { + jumpKind = EJ_ne; + } + else + { + bool isUnsignedOverflow = ((dst->gtFlags & GTF_UNSIGNED) != 0); + jumpKind = isUnsignedOverflow ? EJ_lo : EJ_vs; + if (jumpKind == EJ_lo) + { + if ((dst->OperGet() != GT_SUB) && (dst->OperGet() != GT_ASG_SUB) && (dst->OperGet() != GT_SUB_HI)) + { + jumpKind = EJ_hs; + } + } + } + + // Jump to the block which will throw the exception. + codeGen->genJumpToThrowHlpBlk(jumpKind, SCK_OVERFLOW); } return dst->gtRegNum; -- 2.7.4