@@ -13387,6 +13387,56 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac)
1338713387
1338813388 /* No match - exit */
1338913389 }
13390+
13391+ // Skip optimization if non-NEG operand is constant.
13392+ // Both op1 and op2 are not constant because it was already checked above.
13393+ if (opts.OptimizationEnabled() && fgGlobalMorph &&
13394+ (((op1->gtFlags & GTF_EXCEPT) == 0) || ((op2->gtFlags & GTF_EXCEPT) == 0)))
13395+ {
13396+ // a - -b = > a + b
13397+ // SUB(a, (NEG(b)) => ADD(a, b)
13398+
13399+ if (!op1->OperIs(GT_NEG) && op2->OperIs(GT_NEG))
13400+ {
13401+ // tree: SUB
13402+ // op1: a
13403+ // op2: NEG
13404+ // op2Child: b
13405+
13406+ GenTree* op2Child = op2->AsOp()->gtOp1; // b
13407+ oper = GT_ADD;
13408+ tree->SetOper(oper, GenTree::PRESERVE_VN);
13409+ tree->AsOp()->gtOp2 = op2Child;
13410+
13411+ DEBUG_DESTROY_NODE(op2);
13412+
13413+ op2 = op2Child;
13414+ }
13415+
13416+ // -a - -b = > b - a
13417+ // SUB(NEG(a), (NEG(b)) => SUB(b, a)
13418+
13419+ if (op1->OperIs(GT_NEG) && op2->OperIs(GT_NEG))
13420+ {
13421+ // tree: SUB
13422+ // op1: NEG
13423+ // op1Child: a
13424+ // op2: NEG
13425+ // op2Child: b
13426+
13427+ GenTree* op1Child = op1->AsOp()->gtOp1; // a
13428+ GenTree* op2Child = op2->AsOp()->gtOp1; // b
13429+ tree->AsOp()->gtOp1 = op2Child;
13430+ tree->AsOp()->gtOp2 = op1Child;
13431+
13432+ DEBUG_DESTROY_NODE(op1);
13433+ DEBUG_DESTROY_NODE(op2);
13434+
13435+ op1 = op2Child;
13436+ op2 = op1Child;
13437+ }
13438+ }
13439+
1339013440 break;
1339113441
1339213442#ifdef TARGET_ARM64
@@ -13555,6 +13605,57 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac)
1355513605 }
1355613606 }
1355713607 }
13608+
13609+ if (opts.OptimizationEnabled() && fgGlobalMorph &&
13610+ (((op1->gtFlags & GTF_EXCEPT) == 0) || ((op2->gtFlags & GTF_EXCEPT) == 0)))
13611+ {
13612+ // - a + b = > b - a
13613+ // ADD((NEG(a), b) => SUB(b, a)
13614+
13615+ // Skip optimization if non-NEG operand is constant.
13616+ if (op1->OperIs(GT_NEG) && !op2->OperIs(GT_NEG) &&
13617+ !(op2->IsCnsIntOrI() && varTypeIsIntegralOrI(typ)))
13618+ {
13619+ // tree: ADD
13620+ // op1: NEG
13621+ // op2: b
13622+ // op1Child: a
13623+
13624+ GenTree* op1Child = op1->AsOp()->gtOp1; // a
13625+ oper = GT_SUB;
13626+ tree->SetOper(oper, GenTree::PRESERVE_VN);
13627+ tree->AsOp()->gtOp1 = op2;
13628+ tree->AsOp()->gtOp2 = op1Child;
13629+
13630+ DEBUG_DESTROY_NODE(op1);
13631+
13632+ op1 = op2;
13633+ op2 = op1Child;
13634+ }
13635+
13636+ // a + -b = > a - b
13637+ // ADD(a, (NEG(b)) => SUB(a, b)
13638+
13639+ if (!op1->OperIs(GT_NEG) && op2->OperIs(GT_NEG))
13640+ {
13641+ // a is non cosntant because it was already canonicalized to have
13642+ // variable on the left and constant on the right.
13643+
13644+ // tree: ADD
13645+ // op1: a
13646+ // op2: NEG
13647+ // op2Child: b
13648+
13649+ GenTree* op2Child = op2->AsOp()->gtOp1; // a
13650+ oper = GT_SUB;
13651+ tree->SetOper(oper, GenTree::PRESERVE_VN);
13652+ tree->AsOp()->gtOp2 = op2Child;
13653+
13654+ DEBUG_DESTROY_NODE(op2);
13655+
13656+ op2 = op2Child;
13657+ }
13658+ }
1355813659 }
1355913660 /* See if we can fold GT_MUL by const nodes */
1356013661 else if (oper == GT_MUL && op2->IsCnsIntOrI() && !optValnumCSE_phase)
0 commit comments