@@ -13072,6 +13072,18 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac)
13072
13072
}
13073
13073
}
13074
13074
}
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
+ }
13075
13087
}
13076
13088
/* See if we can fold GT_MUL by const nodes */
13077
13089
else if (oper == GT_MUL && op2->IsCnsIntOrI() && !optValnumCSE_phase)
@@ -14361,18 +14373,84 @@ bool Compiler::fgOperIsBitwiseRotationRoot(genTreeOps oper)
14361
14373
return (oper == GT_OR) || (oper == GT_XOR);
14362
14374
}
14363
14375
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
+ }
14376
14454
14377
14455
GenTree* Compiler::fgRecognizeAndMorphBitwiseRotation(GenTree* tree)
14378
14456
{
0 commit comments