Skip to content

Commit 3d0abaa

Browse files
committed
Recognize x*z + y*z pattern and simplify to z*(x+y)
1 parent f47bb30 commit 3d0abaa

File tree

2 files changed

+91
-12
lines changed

2 files changed

+91
-12
lines changed

src/jit/compiler.h

+1
Original file line numberDiff line numberDiff line change
@@ -5206,6 +5206,7 @@ class Compiler
52065206
private:
52075207
// Recognize a bitwise rotation pattern and convert into a GT_ROL or a GT_ROR node.
52085208
GenTree* fgRecognizeAndMorphBitwiseRotation(GenTree* tree);
5209+
GenTree* fgRecognizeAndMorphMyPattern(GenTree* tree);
52095210
bool fgOperIsBitwiseRotationRoot(genTreeOps oper);
52105211

52115212
//-------- Determine the order in which the trees will be evaluated -------

src/jit/morph.cpp

+90-12
Original file line numberDiff line numberDiff line change
@@ -13072,6 +13072,18 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac)
1307213072
}
1307313073
}
1307413074
}
13075+
13076+
13077+
tree = fgRecognizeAndMorphMyPattern(tree);
13078+
if (tree->OperGet() != GT_ADD)
13079+
{
13080+
// fgRecognizeAndMorphMyPattern returned a new tree
13081+
oper = tree->OperGet();
13082+
typ = tree->TypeGet();
13083+
op1 = tree->gtOp.gtOp1;
13084+
op2 = tree->gtOp.gtOp2;
13085+
break;
13086+
}
1307513087
}
1307613088
/* See if we can fold GT_MUL by const nodes */
1307713089
else if (oper == GT_MUL && op2->IsCnsIntOrI() && !optValnumCSE_phase)
@@ -14361,18 +14373,84 @@ bool Compiler::fgOperIsBitwiseRotationRoot(genTreeOps oper)
1436114373
return (oper == GT_OR) || (oper == GT_XOR);
1436214374
}
1436314375

14364-
//------------------------------------------------------------------------------
14365-
// fgRecognizeAndMorphBitwiseRotation : Check if the tree represents a left or right rotation. If so, return
14366-
// an equivalent GT_ROL or GT_ROR tree; otherwise, return the original tree.
14367-
//
14368-
// Arguments:
14369-
// tree - tree to check for a rotation pattern
14370-
//
14371-
// Return Value:
14372-
// An equivalent GT_ROL or GT_ROR tree if a pattern is found; original tree otherwise.
14373-
//
14374-
// Assumption:
14375-
// The input is a GT_OR or a GT_XOR tree.
14376+
GenTree* Compiler::fgRecognizeAndMorphMyPattern(GenTree* tree)
14377+
{
14378+
//
14379+
// Check for my blog pattern :-) e.g.,
14380+
//
14381+
// ADD MUL
14382+
// / \ / \.
14383+
// MUL MUL -> z ADD
14384+
// / \ / \. / \
14385+
// x z y z x y
14386+
//
14387+
// The patterns recognized:
14388+
// x * z + y * z (only this one is implemented for now)
14389+
// x * z + z * y
14390+
// z * x + y * z
14391+
// z * x + z * y
14392+
// x * z - y * z
14393+
// x * z - z * y
14394+
// z * x - y * z
14395+
// z * x - z * y
14396+
// DSL to declare them all sounds like a good idea ;-)
14397+
14398+
// make sure the root node is ADD
14399+
if (tree->OperGet() != GT_ADD)
14400+
return tree;
14401+
14402+
GenTree* leftMul = tree->gtGetOp1();
14403+
GenTree* rightMul = tree->gtGetOp2();
14404+
14405+
// we need both ops to be MUL (see graph ^)
14406+
if ((leftMul->OperGet() != GT_MUL) || (rightMul->OperGet() != GT_MUL))
14407+
return tree;
14408+
14409+
// optimize only if there are no side effects
14410+
if (((tree->gtFlags & GTF_PERSISTENT_SIDE_EFFECTS) != 0) || ((tree->gtFlags & GTF_ORDER_SIDEEFF) != 0))
14411+
{
14412+
// We can't do anything if the tree has assignments, calls, or volatile
14413+
// reads. Note that we allow GTF_EXCEPT side effect since any exceptions
14414+
// thrown by the original tree will be thrown by the transformed tree as well.
14415+
14416+
// TODO: do I have to check sub-nodes?
14417+
return tree;
14418+
}
14419+
14420+
GenTree* x;
14421+
GenTree* z;
14422+
GenTree* y;
14423+
14424+
// test for "x * z + y * z"
14425+
if (GenTree::Compare(leftMul->gtGetOp2(), rightMul->gtGetOp2()))
14426+
{
14427+
x = leftMul->gtGetOp1();
14428+
y = rightMul->gtGetOp1();
14429+
z = rightMul->gtGetOp2();
14430+
}
14431+
else
14432+
{
14433+
// TODO: other patterns from the comment above ^
14434+
return tree;
14435+
}
14436+
14437+
var_types type = genActualType(tree->gtType);
14438+
// TODO: check types - e.g. we can't do it for floats (there is no "fast-math" mode yet)
14439+
14440+
// We can use the same tree only during global morph; reusing the tree in a later morph
14441+
// may invalidate value numbers.
14442+
if (fgGlobalMorph)
14443+
{
14444+
tree->gtOp.gtOp1 = z;
14445+
tree->gtOp.gtOp2 = gtNewOperNode(GT_ADD, type, x, y);
14446+
tree->ChangeOper(GT_MUL);
14447+
return tree;
14448+
}
14449+
else
14450+
{
14451+
return gtNewOperNode(GT_MUL, type, z, gtNewOperNode(GT_ADD, type, x, y));
14452+
}
14453+
}
1437614454

1437714455
GenTree* Compiler::fgRecognizeAndMorphBitwiseRotation(GenTree* tree)
1437814456
{

0 commit comments

Comments
 (0)