/* 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
}
}
}
+
+ 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)