@@ -11611,6 +11611,68 @@ GenTree* Compiler::fgMorphFieldAssignToSIMDIntrinsicSet(GenTree* tree)
1161111611
1161211612#endif // FEATURE_SIMD
1161311613
11614+ //------------------------------------------------------------------------------
11615+ // fgMorphCommutative : Try to simplify "(X op C1) op C2" to "X op C3"
11616+ // for commutative operators.
11617+ //
11618+ // Arguments:
11619+ // tree - node to fold
11620+ //
11621+ // return value:
11622+ // A folded GenTree* instance or nullptr if something prevents folding.
11623+ //
11624+
11625+ GenTree* Compiler::fgMorphCommutative(GenTreeOp* tree)
11626+ {
11627+ assert(varTypeIsIntegralOrI(tree->TypeGet()));
11628+ assert(tree->OperIs(GT_ADD, GT_MUL, GT_OR, GT_AND, GT_XOR));
11629+
11630+ // op1 can be GT_COMMA, in this case we're going to fold
11631+ // "(op (COMMA(... (op X C1))) C2)" to "(COMMA(... (op X C3)))"
11632+ GenTree* op1 = tree->gtGetOp1()->gtEffectiveVal(true);
11633+ genTreeOps oper = tree->OperGet();
11634+
11635+ if (!op1->OperIs(oper) || !tree->gtGetOp2()->IsCnsIntOrI() || !op1->gtGetOp2()->IsCnsIntOrI() ||
11636+ op1->gtGetOp1()->IsCnsIntOrI() || gtIsActiveCSE_Candidate(op1))
11637+ {
11638+ return nullptr;
11639+ }
11640+
11641+ if (tree->OperMayOverflow() && (tree->gtOverflow() || op1->gtOverflow()))
11642+ {
11643+ return nullptr;
11644+ }
11645+
11646+ GenTreeIntCon* cns1 = op1->gtGetOp2()->AsIntCon();
11647+ GenTreeIntCon* cns2 = tree->gtGetOp2()->AsIntCon();
11648+
11649+ if (!varTypeIsIntegralOrI(tree->TypeGet()) || cns1->TypeIs(TYP_REF) || !cns1->TypeIs(cns2->TypeGet()))
11650+ {
11651+ return nullptr;
11652+ }
11653+
11654+ GenTree* foldedCns = gtFoldExprConst(gtNewOperNode(oper, cns1->TypeGet(), cns1, cns2));
11655+ if (!foldedCns->IsCnsIntOrI())
11656+ {
11657+ // Give up if we can't fold "C1 op C2"
11658+ return nullptr;
11659+ }
11660+
11661+ cns1->gtIconVal = foldedCns->AsIntCon()->IconValue();
11662+ if ((oper == GT_ADD) && foldedCns->IsCnsIntOrI())
11663+ {
11664+ cns1->AsIntCon()->gtFieldSeq =
11665+ GetFieldSeqStore()->Append(cns1->AsIntCon()->gtFieldSeq, cns2->AsIntCon()->gtFieldSeq);
11666+ }
11667+
11668+ GenTreeOp* newTree = tree->gtGetOp1()->AsOp();
11669+ DEBUG_DESTROY_NODE(tree);
11670+ DEBUG_DESTROY_NODE(cns2);
11671+ DEBUG_DESTROY_NODE(foldedCns);
11672+ INDEBUG(newTree->gtOp2->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED);
11673+ return newTree;
11674+ }
11675+
1161411676/*****************************************************************************
1161511677 *
1161611678 * Transform the given GTK_SMPOP tree for code generation.
@@ -13451,49 +13513,8 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac)
1345113513
1345213514 if (op2->IsCnsIntOrI() && varTypeIsIntegralOrI(typ))
1345313515 {
13454- // Fold "((x+icon1)+icon2) to (x+(icon1+icon2))"
13455- // Fold "((comma(y, x+icon1)+icon2) to comma(y, x+(icon1+icon2))"
1345613516 CLANG_FORMAT_COMMENT_ANCHOR;
1345713517
13458- const bool commasOnly = true;
13459- GenTree* op1EffectiveValue = op1->gtEffectiveVal(commasOnly);
13460-
13461- if (op1EffectiveValue->gtOper == GT_ADD && !gtIsActiveCSE_Candidate(op1EffectiveValue) &&
13462- !op1EffectiveValue->gtOverflow() && op1EffectiveValue->AsOp()->gtOp2->IsCnsIntOrI() &&
13463- (op1EffectiveValue->AsOp()->gtOp2->OperGet() == op2->OperGet()) &&
13464- (op1EffectiveValue->AsOp()->gtOp2->TypeGet() != TYP_REF) && (op2->TypeGet() != TYP_REF))
13465- {
13466- cns1 = op1EffectiveValue->AsOp()->gtOp2;
13467-
13468- cns1->AsIntConCommon()->SetIconValue(cns1->AsIntConCommon()->IconValue() +
13469- op2->AsIntConCommon()->IconValue());
13470- #ifdef TARGET_64BIT
13471- if (cns1->TypeGet() == TYP_INT)
13472- {
13473- // we need to properly re-sign-extend or truncate after adding two int constants above
13474- cns1->AsIntCon()->TruncateOrSignExtend32();
13475- }
13476- #endif // TARGET_64BIT
13477-
13478- if (cns1->OperGet() == GT_CNS_INT)
13479- {
13480- cns1->AsIntCon()->gtFieldSeq =
13481- GetFieldSeqStore()->Append(cns1->AsIntCon()->gtFieldSeq, op2->AsIntCon()->gtFieldSeq);
13482- }
13483- DEBUG_DESTROY_NODE(op2);
13484-
13485- GenTree* oldTree = tree;
13486- tree = tree->AsOp()->gtOp1;
13487- op1 = tree->AsOp()->gtOp1;
13488- op2 = tree->AsOp()->gtOp2;
13489- DEBUG_DESTROY_NODE(oldTree);
13490-
13491- if (tree->OperGet() != GT_ADD)
13492- {
13493- return tree;
13494- }
13495- }
13496-
1349713518 // Fold (x + 0).
1349813519
1349913520 if ((op2->AsIntConCommon()->IconValue() == 0) && !gtIsActiveCSE_Candidate(tree))
@@ -13669,6 +13690,21 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac)
1366913690 op2 = tree->AsOp()->gtOp2;
1367013691 }
1367113692
13693+ if (varTypeIsIntegralOrI(tree->TypeGet()) && tree->OperIs(GT_ADD, GT_MUL, GT_AND, GT_OR, GT_XOR))
13694+ {
13695+ GenTree* foldedTree = fgMorphCommutative(tree->AsOp());
13696+ if (foldedTree != nullptr)
13697+ {
13698+ tree = foldedTree;
13699+ op1 = tree->gtGetOp1();
13700+ op2 = tree->gtGetOp2();
13701+ if (!tree->OperIs(oper))
13702+ {
13703+ return tree;
13704+ }
13705+ }
13706+ }
13707+
1367213708 break;
1367313709
1367413710 case GT_NOT:
0 commit comments