[PATCH] D59174: [DAGCombine] Fold (x & ~y) | y patterns

Roman Lebedev via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Sun Mar 17 06:47:15 PDT 2019


lebedev.ri accepted this revision.
lebedev.ri added inline comments.


================
Comment at: llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp:5429
 
+  // fold (or (and X, (xor Y, -1)), Y) -> (or X, Y)
+  if (N0.getOpcode() == ISD::AND && isBitwiseNot(N0.getOperand(1)) &&
----------------
nikic wrote:
> lebedev.ri wrote:
> > lebedev.ri wrote:
> > > nikic wrote:
> > > > lebedev.ri wrote:
> > > > > There are 4 variations of this pattern, both `or` and `and` are commutative.
> > > > Right you are. I've added these now, which resulted in a few more changes to the variablemask tests. I was under the mistaken impression that `(and X, (xor Y, -1))` is a canonicalized and-not pattern.
> > > That is indeed a very subtle (and costly!) thing.
> > > `(and X, (xor Y, -1))` will be in that order (well, some deterministic order).
> > > But what if `X` and `Y` aren't arguments, but some values (instructions)?
> > > Then they will also affect the weights and thus ordering.
> > > 
> > Hmm, nobody likes that there is no pattern matching in back end :/
> > But this duplication isn't too nice too.
> > Can you try this instead:
> > ```
> > // Fold all 4 commutative variations of    or (and (xor Y, -1), X), Y
> > // to                                      or X, Y
> > static SDValue foldDegradedBitselect(SDNode *N, SelectionDAG &DAG) {
> >   assert(N->getOpcode() == ISD::OR && "outermost node should be 'or'.");
> > 
> >   SDValue X, Y;
> >   auto outerMatcher = [N, &X, &Y](bool swap) {
> >     SDValue And = N->getOperand(0);
> >     Y = N->getOperand(1);
> > 
> >     if (And.getOpcode() != ISD::AND || swap)
> >       std::swap(And, Y);
> >     if (And.getOpcode() != ISD::AND)
> >       return false;
> > 
> >     auto innerMatcher = [And, Y, &X](bool swap) {
> >       assert(And.getOpcode() == ISD::AND);
> > 
> >       SDValue NotY = And.getOperand(0);
> >       X = And.getOperand(1);
> > 
> >       if (!isBitwiseNot(NotY) || swap)
> >         std::swap(NotY, X);
> >       if (!isBitwiseNot(NotY))
> >         return false;
> > 
> >       SDValue Y2 = NotY.getOperand(0);
> > 
> >       return Y == Y2;
> >     };
> > 
> >     return innerMatcher(/*swap=*/false) || innerMatcher(/*swap=*/true);
> >   };
> > 
> >   if (!(outerMatcher(/*swap=*/false) || outerMatcher(/*swap=*/true)))
> >     return SDValue();
> > 
> >   return DAG.getNode(ISD::OR, SDLoc(Y), Y.getValueType(), X, Y);
> > }
> > ```
> > ?
> > 
> > If that doesn't work, at least factor out these 4 duplicate if's into a function.
> I've extracted a function that will be called with N0, N1 and N1, N0 to avoid repeating the outer pattern, and because this seems useful for potential future transforms as well.
> 
> This still repeats the and commutation, but I think the explicit repetition here is more obvious than the operand swapping variant.
Ok, in this case i guess that works too.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D59174/new/

https://reviews.llvm.org/D59174





More information about the llvm-commits mailing list