Index: lib/CodeGen/SelectionDAG/DAGCombiner.cpp =================================================================== --- lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -5267,14 +5267,41 @@ } SDValue DAGCombiner::visitRotate(SDNode *N) { + SDLoc dl(N); + SDValue N0 = N->getOperand(0); + SDValue N1 = N->getOperand(1); + EVT VT = N->getValueType(0); + // fold (rot* x, (trunc (and y, c))) -> (rot* x, (and (trunc y), (trunc c))). - if (N->getOperand(1).getOpcode() == ISD::TRUNCATE && - N->getOperand(1).getOperand(0).getOpcode() == ISD::AND) { - if (SDValue NewOp1 = - distributeTruncateThroughAnd(N->getOperand(1).getNode())) - return DAG.getNode(N->getOpcode(), SDLoc(N), N->getValueType(0), - N->getOperand(0), NewOp1); + if (N1.getOpcode() == ISD::TRUNCATE && + N1.getOperand(0).getOpcode() == ISD::AND) { + if (SDValue NewOp1 = distributeTruncateThroughAnd(N1.getNode())) + return DAG.getNode(N->getOpcode(), dl, VT, N0, NewOp1); } + unsigned NextOp = N0.getOpcode(); + + // fold (rot* (rot* x, c2), c1) -> (rot* x, c1 +- c2 % bitsize) + if (ConstantSDNode *C1 = getAsNonOpaqueConstant(N1)) + if (NextOp == ISD::ROTL || NextOp == ISD::ROTR) + if (ConstantSDNode *C2 = getAsNonOpaqueConstant(N0.getOperand(1))) { + bool MainIsRotr = N->getOpcode() == ISD::ROTR; + bool NextIsRotr = NextOp == ISD::ROTR; + bool SameSide = MainIsRotr == NextIsRotr; + + unsigned Bitsize = VT.getScalarSizeInBits(); + unsigned CombineOp = SameSide ? ISD::ADD : ISD::SUB; + SDValue CombinedShift = + DAG.FoldConstantArithmetic(CombineOp, dl, VT, C1, C2); + ConstantSDNode *CombinedShiftC = getAsNonOpaqueConstant(CombinedShift); + ConstantSDNode *BitsizeC = + getAsNonOpaqueConstant(DAG.getConstant(Bitsize, dl, VT)); + if (CombinedShiftC && BitsizeC) { + SDValue CombinedShiftNorm = DAG.FoldConstantArithmetic( + ISD::SREM, dl, VT, CombinedShiftC, BitsizeC); + return DAG.getNode( + N->getOpcode(), dl, VT, N0->getOperand(0), CombinedShiftNorm); + } + } return SDValue(); }