Skip to content

Commit cecbbfb

Browse files
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 <jeonlee@microsoft.com>
1 parent d547916 commit cecbbfb

File tree

1 file changed

+101
-0
lines changed

1 file changed

+101
-0
lines changed

src/coreclr/src/jit/morph.cpp

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)