@@ -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
1437714455GenTree* Compiler::fgRecognizeAndMorphBitwiseRotation(GenTree* tree)
1437814456{
0 commit comments