diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index ef9ed60c7e3518..b8a72cc0875fb8 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -15097,12 +15097,92 @@ GenTree* Compiler::gtFoldExprBinary(GenTreeOp* tree) return gtFoldExprSpecial(tree); } } - else if (tree->OperIsCompare()) + + genTreeOps oper = tree->OperGet(); + + if (GenTree::OperIsCompare(oper)) { // comparisons of two local variables can sometimes be folded return gtFoldExprCompare(tree); } + if (!opts.OptimizationEnabled()) + { + return tree; + } + + switch (oper) + { + case GT_ADD: + { + if (tree->gtOverflow()) + { + break; + } + + if (op1->OperIs(GT_NEG)) + { + JITDUMP("Folding (-a) + b => b - a\n") + + tree->gtOp1 = op2; + tree->gtOp2 = op1->gtGetOp1(); + + tree->SetOper(GT_SUB, GenTree::PRESERVE_VN); + tree->ToggleReverseOp(); + + return tree; + } + + if (op2->OperIs(GT_NEG)) + { + JITDUMP("Folding a + (-b) => a - b\n") + + tree->gtOp2 = op2->gtGetOp1(); + tree->SetOper(GT_SUB, GenTree::PRESERVE_VN); + + return tree; + } + break; + } + + case GT_SUB: + { + if (tree->gtOverflow()) + { + break; + } + + if (op2->OperIs(GT_NEG)) + { + if (op1->OperIs(GT_NEG)) + { + JITDUMP("Folding (-a) - (-b) => b - a\n") + + tree->gtOp1 = op2->gtGetOp1(); + tree->gtOp2 = op1->gtGetOp1(); + + tree->ToggleReverseOp(); + return tree; + } + else + { + JITDUMP("Folding a - (-b) => a + b\n") + + tree->gtOp2 = op2->gtGetOp1(); + tree->SetOper(GT_ADD, GenTree::PRESERVE_VN); + + return tree; + } + } + break; + } + + default: + { + break; + } + } + return tree; } diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index 1897b43014f17d..bb0c91eb9fe088 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -2265,6 +2265,11 @@ struct GenTree gtFlags &= ~GTF_REVERSE_OPS; } + void ToggleReverseOp() + { + gtFlags ^= GTF_REVERSE_OPS; + } + #if defined(TARGET_XARCH) void SetDontExtend() { diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 2bc2b94e908de9..f68b6243d336b8 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -8003,59 +8003,6 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, bool* optAssertionPropDone) goto CM_ADD_OP; } } - - // Skip optimization if non-NEG operand is constant. - // Both op1 and op2 are not constant because it was already checked above. - if (opts.OptimizationEnabled()) - { - if (!op2->OperIs(GT_NEG)) - { - break; - } - - if (op1->OperIs(GT_NEG) && gtCanSwapOrder(op1, op2)) - { - // -a - -b = > b - a - // SUB(NEG(a), NEG(b)) => SUB(b, a) - - // 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; - } - else - { - // a - -b = > a + b - // SUB(a, NEG(b)) => ADD(a, b) - - // 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; - } - } - break; case GT_DIV: @@ -10618,31 +10565,6 @@ GenTree* Compiler::fgOptimizeAddition(GenTreeOp* add) return fgMorphTree(add); } } - - // - a + b => b - a - // ADD(NEG(a), b) => SUB(b, a) - // Do not do this if "op2" is constant for canonicalization purposes. - if (!op2->IsIntegralConst() && gtCanSwapOrder(op1, op2)) - { - add->SetOper(GT_SUB); - add->gtOp1 = op2; - add->gtOp2 = op1->AsOp()->gtGetOp1(); - - DEBUG_DESTROY_NODE(op1); - return add; - } - } - - // a + -b = > a - b - // ADD(a, NEG(b)) => SUB(a, b) - if (!op1->OperIs(GT_NEG) && op2->OperIs(GT_NEG)) - { - add->SetOper(GT_SUB); - add->gtOp2 = op2->AsOp()->gtGetOp1(); - - DEBUG_DESTROY_NODE(op2); - - return add; } // Fold (~x + 1) to -x.