From 9f3c27c2de9cfed18441072afc5af091df161173 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Wed, 29 Apr 2020 18:31:57 +0300 Subject: [PATCH 1/9] Optimize x<0 to x>>31 --- src/coreclr/src/jit/codegenxarch.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/coreclr/src/jit/codegenxarch.cpp b/src/coreclr/src/jit/codegenxarch.cpp index c47c001147c003..4202f3188930cf 100644 --- a/src/coreclr/src/jit/codegenxarch.cpp +++ b/src/coreclr/src/jit/codegenxarch.cpp @@ -6294,6 +6294,21 @@ void CodeGen::genCompareInt(GenTree* treeNode) instruction ins; var_types type = TYP_UNKNOWN; +#ifdef TARGET_64BIT + // Optimize "x<0" to shift if it's saved to a register + if ((targetReg != REG_NA) && tree->OperIs(GT_LT) && op1->isUsedFromReg() && op2->IsIntegralConst(0)) + { + if (targetReg != op1->GetRegNum()) + { + inst_RV_RV(INS_mov, tree->GetRegNum(), op1->GetRegNum(), op1->TypeGet()); + } + const int shift = (genTypeSize(op1Type) * 8) - 1; + inst_RV_IV(INS_shr_N, tree->GetRegNum(), shift, emitActualTypeSize(op1Type)); + genProduceReg(tree); + return; + } +#endif + if (tree->OperIs(GT_TEST_EQ, GT_TEST_NE)) { ins = INS_test; From 4b841a55e47a4f9b502eabfc1fc9add0e02d52df Mon Sep 17 00:00:00 2001 From: EgorBo Date: Thu, 30 Apr 2020 15:29:25 +0300 Subject: [PATCH 2/9] Fix failing tests --- src/coreclr/src/jit/codegenxarch.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/coreclr/src/jit/codegenxarch.cpp b/src/coreclr/src/jit/codegenxarch.cpp index 4202f3188930cf..503539b86c4c06 100644 --- a/src/coreclr/src/jit/codegenxarch.cpp +++ b/src/coreclr/src/jit/codegenxarch.cpp @@ -6298,12 +6298,13 @@ void CodeGen::genCompareInt(GenTree* treeNode) // Optimize "x<0" to shift if it's saved to a register if ((targetReg != REG_NA) && tree->OperIs(GT_LT) && op1->isUsedFromReg() && op2->IsIntegralConst(0)) { + int shift = (genTypeSize(op1) * 8) - 1; if (targetReg != op1->GetRegNum()) { - inst_RV_RV(INS_mov, tree->GetRegNum(), op1->GetRegNum(), op1->TypeGet()); + inst_RV_RV(INS_mov, tree->GetRegNum(), op1->GetRegNum(), TYP_LONG); + shift = 63; } - const int shift = (genTypeSize(op1Type) * 8) - 1; - inst_RV_IV(INS_shr_N, tree->GetRegNum(), shift, emitActualTypeSize(op1Type)); + inst_RV_IV(INS_shr_N, tree->GetRegNum(), shift, emitActualTypeSize(op1)); genProduceReg(tree); return; } From dc1d9fc45a42d5afdb058a6e98e8b746ada839ce Mon Sep 17 00:00:00 2001 From: EgorBo Date: Thu, 30 Apr 2020 15:54:44 +0300 Subject: [PATCH 3/9] clean up --- src/coreclr/src/jit/codegenxarch.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/coreclr/src/jit/codegenxarch.cpp b/src/coreclr/src/jit/codegenxarch.cpp index 503539b86c4c06..ac7931a95d18ca 100644 --- a/src/coreclr/src/jit/codegenxarch.cpp +++ b/src/coreclr/src/jit/codegenxarch.cpp @@ -6298,13 +6298,13 @@ void CodeGen::genCompareInt(GenTree* treeNode) // Optimize "x<0" to shift if it's saved to a register if ((targetReg != REG_NA) && tree->OperIs(GT_LT) && op1->isUsedFromReg() && op2->IsIntegralConst(0)) { - int shift = (genTypeSize(op1) * 8) - 1; + emitAttr targetSize = emitActualTypeSize(op1); if (targetReg != op1->GetRegNum()) { - inst_RV_RV(INS_mov, tree->GetRegNum(), op1->GetRegNum(), TYP_LONG); - shift = 63; + targetSize = op1Type == TYP_LONG ? EA_8BYTE : EA_4BYTE; + inst_RV_RV(INS_mov, tree->GetRegNum(), op1->GetRegNum()); } - inst_RV_IV(INS_shr_N, tree->GetRegNum(), shift, emitActualTypeSize(op1)); + inst_RV_IV(INS_shr_N, tree->GetRegNum(), (int)targetSize * 8 - 1, targetSize); genProduceReg(tree); return; } From 9eb03b05bdeb5981ad8795bf540d83e3399a2a2f Mon Sep 17 00:00:00 2001 From: EgorBo Date: Tue, 22 Sep 2020 01:09:15 +0300 Subject: [PATCH 4/9] enable for x86, handle "x>=0" case --- src/coreclr/src/jit/codegenxarch.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/coreclr/src/jit/codegenxarch.cpp b/src/coreclr/src/jit/codegenxarch.cpp index e69488c1e46b01..38bf02734bbd79 100644 --- a/src/coreclr/src/jit/codegenxarch.cpp +++ b/src/coreclr/src/jit/codegenxarch.cpp @@ -5921,21 +5921,27 @@ void CodeGen::genCompareInt(GenTree* treeNode) instruction ins; var_types type = TYP_UNKNOWN; -#ifdef TARGET_64BIT - // Optimize "x<0" to shift if it's saved to a register - if ((targetReg != REG_NA) && tree->OperIs(GT_LT) && op1->isUsedFromReg() && op2->IsIntegralConst(0)) + // Optimize "x<0" and "x>=0" to "x>>31" if "x" is not a jump condition and in a reg. + // Morph/Lowering are responsible to rotate "00" so we won't handle it here. + if ((targetReg != REG_NA) && tree->OperIs(GT_LT, GT_GE) && op1->isUsedFromReg() && op2->IsIntegralConst(0)) { emitAttr targetSize = emitActualTypeSize(op1); if (targetReg != op1->GetRegNum()) { + // move op1 to the target register. + // in case of byte/short we need save info for shr that it was extended to EA_4BYTE targetSize = op1Type == TYP_LONG ? EA_8BYTE : EA_4BYTE; - inst_RV_RV(INS_mov, tree->GetRegNum(), op1->GetRegNum()); + inst_RV_RV(INS_mov, targetReg, op1->GetRegNum()); + } + if (tree->OperIs(GT_GE)) + { + // emit "neg" for "x>=0" case + inst_RV(INS_neg, targetReg, op1Type, targetSize); } - inst_RV_IV(INS_shr_N, tree->GetRegNum(), (int)targetSize * 8 - 1, targetSize); + inst_RV_IV(INS_shr_N, targetReg, (int)targetSize * 8 - 1, targetSize); genProduceReg(tree); return; } -#endif if (tree->OperIs(GT_TEST_EQ, GT_TEST_NE)) { From 987971159b73dab90659dc0fa0b7292b70a9ff9e Mon Sep 17 00:00:00 2001 From: EgorBo Date: Tue, 22 Sep 2020 02:27:20 +0300 Subject: [PATCH 5/9] Clean up --- src/coreclr/src/jit/codegenxarch.cpp | 44 ++++++++++++++-------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/coreclr/src/jit/codegenxarch.cpp b/src/coreclr/src/jit/codegenxarch.cpp index 38bf02734bbd79..6597f091c4b28e 100644 --- a/src/coreclr/src/jit/codegenxarch.cpp +++ b/src/coreclr/src/jit/codegenxarch.cpp @@ -5921,28 +5921,6 @@ void CodeGen::genCompareInt(GenTree* treeNode) instruction ins; var_types type = TYP_UNKNOWN; - // Optimize "x<0" and "x>=0" to "x>>31" if "x" is not a jump condition and in a reg. - // Morph/Lowering are responsible to rotate "00" so we won't handle it here. - if ((targetReg != REG_NA) && tree->OperIs(GT_LT, GT_GE) && op1->isUsedFromReg() && op2->IsIntegralConst(0)) - { - emitAttr targetSize = emitActualTypeSize(op1); - if (targetReg != op1->GetRegNum()) - { - // move op1 to the target register. - // in case of byte/short we need save info for shr that it was extended to EA_4BYTE - targetSize = op1Type == TYP_LONG ? EA_8BYTE : EA_4BYTE; - inst_RV_RV(INS_mov, targetReg, op1->GetRegNum()); - } - if (tree->OperIs(GT_GE)) - { - // emit "neg" for "x>=0" case - inst_RV(INS_neg, targetReg, op1Type, targetSize); - } - inst_RV_IV(INS_shr_N, targetReg, (int)targetSize * 8 - 1, targetSize); - genProduceReg(tree); - return; - } - if (tree->OperIs(GT_TEST_EQ, GT_TEST_NE)) { ins = INS_test; @@ -5965,6 +5943,28 @@ void CodeGen::genCompareInt(GenTree* treeNode) } else if (op1->isUsedFromReg() && op2->IsIntegralConst(0)) { + // Optimize "x<0" and "x>=0" to "x>>31" if "x" is not a jump condition and in a reg. + // Morph/Lowering are responsible to rotate "00" so we won't handle it here. + if (!varTypeIsByte(tree->TypeGet()) && (targetReg != REG_NA) && tree->OperIs(GT_LT, GT_GE)) + { + emitAttr targetSize = emitActualTypeSize(op1); + if (targetReg != op1->GetRegNum()) + { + // move op1 to the target register. + // in case of byte/short we need to save info for shr that it was extended to EA_4BYTE + targetSize = op1Type == TYP_LONG ? EA_8BYTE : EA_4BYTE; + inst_RV_RV(INS_mov, targetReg, op1->GetRegNum()); + } + if (tree->OperIs(GT_GE)) + { + // emit "neg" for "x>=0" case + inst_RV(INS_neg, targetReg, op1Type, targetSize); + } + inst_RV_IV(INS_shr_N, targetReg, (int)targetSize * 8 - 1, targetSize); + genProduceReg(tree); + return; + } + if (compiler->opts.OptimizationEnabled()) { canReuseFlags = true; From f21b353aef9da0d48b615a75bc629aa5601beeec Mon Sep 17 00:00:00 2001 From: EgorBo Date: Tue, 22 Sep 2020 11:11:53 +0300 Subject: [PATCH 6/9] fix typo (should be not rather than neg) --- src/coreclr/src/jit/codegenxarch.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/coreclr/src/jit/codegenxarch.cpp b/src/coreclr/src/jit/codegenxarch.cpp index 6597f091c4b28e..6c0870a2d58184 100644 --- a/src/coreclr/src/jit/codegenxarch.cpp +++ b/src/coreclr/src/jit/codegenxarch.cpp @@ -5950,15 +5950,14 @@ void CodeGen::genCompareInt(GenTree* treeNode) emitAttr targetSize = emitActualTypeSize(op1); if (targetReg != op1->GetRegNum()) { - // move op1 to the target register. - // in case of byte/short we need to save info for shr that it was extended to EA_4BYTE + // move op1 to the target register and extend to 4BYTE if needed. targetSize = op1Type == TYP_LONG ? EA_8BYTE : EA_4BYTE; inst_RV_RV(INS_mov, targetReg, op1->GetRegNum()); } if (tree->OperIs(GT_GE)) { // emit "neg" for "x>=0" case - inst_RV(INS_neg, targetReg, op1Type, targetSize); + inst_RV(INS_not, targetReg, tree->TypeGet(), targetSize); } inst_RV_IV(INS_shr_N, targetReg, (int)targetSize * 8 - 1, targetSize); genProduceReg(tree); From 061b3a2ee0e3b7bd5c8cc8d18b8ec5557bf4b290 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Tue, 22 Sep 2020 11:13:53 +0300 Subject: [PATCH 7/9] fix typo (should be not rather than neg) --- src/coreclr/src/jit/codegenxarch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/src/jit/codegenxarch.cpp b/src/coreclr/src/jit/codegenxarch.cpp index 6c0870a2d58184..d3d6eade8c9672 100644 --- a/src/coreclr/src/jit/codegenxarch.cpp +++ b/src/coreclr/src/jit/codegenxarch.cpp @@ -5956,7 +5956,7 @@ void CodeGen::genCompareInt(GenTree* treeNode) } if (tree->OperIs(GT_GE)) { - // emit "neg" for "x>=0" case + // emit "not" for "x>=0" case inst_RV(INS_not, targetReg, tree->TypeGet(), targetSize); } inst_RV_IV(INS_shr_N, targetReg, (int)targetSize * 8 - 1, targetSize); From e02d5b6442f8daf22c2bd23a9fb2a2894b1deeab Mon Sep 17 00:00:00 2001 From: EgorBo Date: Tue, 22 Sep 2020 11:25:40 +0300 Subject: [PATCH 8/9] clean up --- src/coreclr/src/jit/codegenxarch.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/coreclr/src/jit/codegenxarch.cpp b/src/coreclr/src/jit/codegenxarch.cpp index d3d6eade8c9672..f90724c8c65c16 100644 --- a/src/coreclr/src/jit/codegenxarch.cpp +++ b/src/coreclr/src/jit/codegenxarch.cpp @@ -5945,14 +5945,12 @@ void CodeGen::genCompareInt(GenTree* treeNode) { // Optimize "x<0" and "x>=0" to "x>>31" if "x" is not a jump condition and in a reg. // Morph/Lowering are responsible to rotate "00" so we won't handle it here. - if (!varTypeIsByte(tree->TypeGet()) && (targetReg != REG_NA) && tree->OperIs(GT_LT, GT_GE)) + if ((genTypeSize(tree->TypeGet()) >= 4) && (targetReg != REG_NA) && tree->OperIs(GT_LT, GT_GE)) { - emitAttr targetSize = emitActualTypeSize(op1); + emitAttr targetSize = emitActualTypeSize(tree->TypeGet()); if (targetReg != op1->GetRegNum()) { - // move op1 to the target register and extend to 4BYTE if needed. - targetSize = op1Type == TYP_LONG ? EA_8BYTE : EA_4BYTE; - inst_RV_RV(INS_mov, targetReg, op1->GetRegNum()); + inst_RV_RV(INS_mov, targetReg, op1->GetRegNum(), tree->TypeGet()); } if (tree->OperIs(GT_GE)) { From 9c76e4c4517a740ed1254cb3db6753fb790016ec Mon Sep 17 00:00:00 2001 From: EgorBo Date: Tue, 22 Sep 2020 17:06:30 +0300 Subject: [PATCH 9/9] clean up --- src/coreclr/src/jit/codegenxarch.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/coreclr/src/jit/codegenxarch.cpp b/src/coreclr/src/jit/codegenxarch.cpp index f90724c8c65c16..6bca839d10514b 100644 --- a/src/coreclr/src/jit/codegenxarch.cpp +++ b/src/coreclr/src/jit/codegenxarch.cpp @@ -5943,21 +5943,23 @@ void CodeGen::genCompareInt(GenTree* treeNode) } else if (op1->isUsedFromReg() && op2->IsIntegralConst(0)) { + emitAttr targetSize = emitActualTypeSize(op1->TypeGet()); + emitAttr op1Size = emitActualTypeSize(op1->TypeGet()); + // Optimize "x<0" and "x>=0" to "x>>31" if "x" is not a jump condition and in a reg. // Morph/Lowering are responsible to rotate "00" so we won't handle it here. - if ((genTypeSize(tree->TypeGet()) >= 4) && (targetReg != REG_NA) && tree->OperIs(GT_LT, GT_GE)) + if ((targetSize >= 4) && (op1Size >= 4) && (targetReg != REG_NA) && tree->OperIs(GT_LT, GT_GE)) { - emitAttr targetSize = emitActualTypeSize(tree->TypeGet()); if (targetReg != op1->GetRegNum()) { - inst_RV_RV(INS_mov, targetReg, op1->GetRegNum(), tree->TypeGet()); + inst_RV_RV(INS_mov, targetReg, op1->GetRegNum(), op1->TypeGet()); } if (tree->OperIs(GT_GE)) { // emit "not" for "x>=0" case - inst_RV(INS_not, targetReg, tree->TypeGet(), targetSize); + inst_RV(INS_not, targetReg, tree->TypeGet(), op1Size); } - inst_RV_IV(INS_shr_N, targetReg, (int)targetSize * 8 - 1, targetSize); + inst_RV_IV(INS_shr_N, targetReg, (int)op1Size * 8 - 1, op1Size); genProduceReg(tree); return; }