From cecbbfb87c1bcf661d64d799df1cb7bad325f447 Mon Sep 17 00:00:00 2001 From: Julie Lee <63486087+JulieLeeMSFT@users.noreply.github.com> Date: Fri, 6 Nov 2020 07:04:07 -0800 Subject: [PATCH] Simple GT_NEG optimization for #13837 (#43921) * Simple arithmetic optimization with GT_NEG * Skip GT_NEG optimization when an operand is constant. Revert bitwise rotation pattern * Fixed Value Numbering assert * Cleaned up code and comments for simple GT_NEG optimization * Formatting Co-authored-by: Julie Lee --- src/coreclr/src/jit/morph.cpp | 101 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/src/coreclr/src/jit/morph.cpp b/src/coreclr/src/jit/morph.cpp index e26fc7d..e172a9c 100644 --- a/src/coreclr/src/jit/morph.cpp +++ b/src/coreclr/src/jit/morph.cpp @@ -13387,6 +13387,56 @@ DONE_MORPHING_CHILDREN: /* No match - exit */ } + + // Skip optimization if non-NEG operand is constant. + // Both op1 and op2 are not constant because it was already checked above. + if (opts.OptimizationEnabled() && fgGlobalMorph && + (((op1->gtFlags & GTF_EXCEPT) == 0) || ((op2->gtFlags & GTF_EXCEPT) == 0))) + { + // a - -b = > a + b + // SUB(a, (NEG(b)) => ADD(a, b) + + if (!op1->OperIs(GT_NEG) && op2->OperIs(GT_NEG)) + { + // tree: SUB + // op1: a + // op2: NEG + // op2Child: b + + GenTree* op2Child = op2->AsOp()->gtOp1; // b + oper = GT_ADD; + tree->SetOper(oper, GenTree::PRESERVE_VN); + tree->AsOp()->gtOp2 = op2Child; + + DEBUG_DESTROY_NODE(op2); + + op2 = op2Child; + } + + // -a - -b = > b - a + // SUB(NEG(a), (NEG(b)) => SUB(b, a) + + if (op1->OperIs(GT_NEG) && op2->OperIs(GT_NEG)) + { + // tree: SUB + // op1: NEG + // op1Child: a + // op2: NEG + // op2Child: b + + GenTree* op1Child = op1->AsOp()->gtOp1; // a + GenTree* op2Child = op2->AsOp()->gtOp1; // b + tree->AsOp()->gtOp1 = op2Child; + tree->AsOp()->gtOp2 = op1Child; + + DEBUG_DESTROY_NODE(op1); + DEBUG_DESTROY_NODE(op2); + + op1 = op2Child; + op2 = op1Child; + } + } + break; #ifdef TARGET_ARM64 @@ -13555,6 +13605,57 @@ DONE_MORPHING_CHILDREN: } } } + + if (opts.OptimizationEnabled() && fgGlobalMorph && + (((op1->gtFlags & GTF_EXCEPT) == 0) || ((op2->gtFlags & GTF_EXCEPT) == 0))) + { + // - a + b = > b - a + // ADD((NEG(a), b) => SUB(b, a) + + // Skip optimization if non-NEG operand is constant. + if (op1->OperIs(GT_NEG) && !op2->OperIs(GT_NEG) && + !(op2->IsCnsIntOrI() && varTypeIsIntegralOrI(typ))) + { + // tree: ADD + // op1: NEG + // op2: b + // op1Child: a + + GenTree* op1Child = op1->AsOp()->gtOp1; // a + oper = GT_SUB; + tree->SetOper(oper, GenTree::PRESERVE_VN); + tree->AsOp()->gtOp1 = op2; + tree->AsOp()->gtOp2 = op1Child; + + DEBUG_DESTROY_NODE(op1); + + op1 = op2; + op2 = op1Child; + } + + // a + -b = > a - b + // ADD(a, (NEG(b)) => SUB(a, b) + + if (!op1->OperIs(GT_NEG) && op2->OperIs(GT_NEG)) + { + // a is non cosntant because it was already canonicalized to have + // variable on the left and constant on the right. + + // tree: ADD + // op1: a + // op2: NEG + // op2Child: b + + GenTree* op2Child = op2->AsOp()->gtOp1; // a + oper = GT_SUB; + tree->SetOper(oper, GenTree::PRESERVE_VN); + tree->AsOp()->gtOp2 = op2Child; + + DEBUG_DESTROY_NODE(op2); + + op2 = op2Child; + } + } } /* See if we can fold GT_MUL by const nodes */ else if (oper == GT_MUL && op2->IsCnsIntOrI() && !optValnumCSE_phase) -- 2.7.4