Index: lib/CodeGen/SelectionDAG/DAGCombiner.cpp =================================================================== --- lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -4259,14 +4259,43 @@ } 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) { - SDValue NewOp1 = distributeTruncateThroughAnd(N->getOperand(1).getNode()); + if (N1.getOpcode() == ISD::TRUNCATE && + N1.getOperand(0).getOpcode() == ISD::AND) { + SDValue NewOp1 = distributeTruncateThroughAnd(N1.getNode()); if (NewOp1.getNode()) - return DAG.getNode(N->getOpcode(), SDLoc(N), N->getValueType(0), - N->getOperand(0), NewOp1); + 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(); } Index: test/CodeGen/ARM/ror.ll =================================================================== --- test/CodeGen/ARM/ror.ll +++ test/CodeGen/ARM/ror.ll @@ -0,0 +1,17 @@ +; RUN: llc -mtriple=arm-eabi -mattr=+v6 %s -o - | FileCheck %s + +; rotr (rotr x, 4), 6 -> rotr x, 10 -> ror r0, r0, #10 +define i32 @test1(i32 %x) nounwind readnone { +; CHECK-LABEL: test1: +; CHECK: ror r0, r0, #10 +; CHECK: bx lr +entry: + %high_part.i = shl i32 %x, 28 + %low_part.i = lshr i32 %x, 4 + %result.i = or i32 %high_part.i, %low_part.i + %high_part.i.1 = shl i32 %result.i, 26 + %low_part.i.2 = lshr i32 %result.i, 6 + %result.i.3 = or i32 %low_part.i.2, %high_part.i.1 + ret i32 %result.i.3 +} +