The attached patch contains: - Cleanups in the DAGCombiner.cpp ROTL/ROTR combine code, primarily helping me to fix 80col violations (benefiting the code as a whole). - Detect sign/zext/any-extended versions of ROTL/ROTR patterns. - Allow custom lowering for ROTL/ROTR (needed in the CellSPU's case for 8-bit rotates, when only 16-bit and 32-bit rotates are actually implemented in the instruction set.) -scooter -------------- next part -------------- Index: lib/CodeGen/SelectionDAG/LegalizeDAG.cpp ==================================================================--- lib/CodeGen/SelectionDAG/LegalizeDAG.cpp (.../trunk) (revision 2118) +++ lib/CodeGen/SelectionDAG/LegalizeDAG.cpp (.../branches/llvm-spu) (revision 2118) @@ -2683,10 +2683,24 @@ case ISD::ROTR: Tmp1 = LegalizeOp(Node->getOperand(0)); // LHS Tmp2 = LegalizeOp(Node->getOperand(1)); // RHS - - assert(TLI.isOperationLegal(Node->getOpcode(), Node->getValueType(0)) && - "Cannot handle this yet!"); Result = DAG.UpdateNodeOperands(Result, Tmp1, Tmp2); + switch (TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0))) { + default: + assert(0 && "ROTL/ROTR legalize operation not supported"); + break; + case TargetLowering::Legal: + break; + case TargetLowering::Custom: + Tmp1 = TLI.LowerOperation(Result, DAG); + if (Tmp1.Val) Result = Tmp1; + break; + case TargetLowering::Promote: + assert(0 && "Do not know how to promote ROTL/ROTR"); + break; + case TargetLowering::Expand: + assert(0 && "Do not know how to expand ROTL/ROTR"); + break; + } break; case ISD::BSWAP: Index: lib/CodeGen/SelectionDAG/DAGCombiner.cpp ==================================================================--- lib/CodeGen/SelectionDAG/DAGCombiner.cpp (.../trunk) (revision 2118) +++ lib/CodeGen/SelectionDAG/DAGCombiner.cpp (.../branches/llvm-spu) (revision 2118) @@ -1488,23 +1488,24 @@ } unsigned OpSizeInBits = MVT::getSizeInBits(VT); + SDOperand LHSShiftArg = LHSShift.getOperand(0); + SDOperand LHSShiftAmt = LHSShift.getOperand(1); + SDOperand RHSShiftAmt = RHSShift.getOperand(1); // fold (or (shl x, C1), (srl x, C2)) -> (rotl x, C1) // fold (or (shl x, C1), (srl x, C2)) -> (rotr x, C2) - if (LHSShift.getOperand(1).getOpcode() == ISD::Constant && - RHSShift.getOperand(1).getOpcode() == ISD::Constant) { - uint64_t LShVal = cast<ConstantSDNode>(LHSShift.getOperand(1))->getValue(); - uint64_t RShVal = cast<ConstantSDNode>(RHSShift.getOperand(1))->getValue(); + if (LHSShiftAmt.getOpcode() == ISD::Constant && + RHSShiftAmt.getOpcode() == ISD::Constant) { + uint64_t LShVal = cast<ConstantSDNode>(LHSShiftAmt)->getValue(); + uint64_t RShVal = cast<ConstantSDNode>(RHSShiftAmt)->getValue(); if ((LShVal + RShVal) != OpSizeInBits) return 0; SDOperand Rot; if (HasROTL) - Rot = DAG.getNode(ISD::ROTL, VT, LHSShift.getOperand(0), - LHSShift.getOperand(1)); + Rot = DAG.getNode(ISD::ROTL, VT, LHSShiftArg, LHSShiftAmt); else - Rot = DAG.getNode(ISD::ROTR, VT, LHSShift.getOperand(0), - RHSShift.getOperand(1)); + Rot = DAG.getNode(ISD::ROTR, VT, LHSShiftArg, RHSShiftAmt); // If there is an AND of either shifted operand, apply it to the result. if (LHSMask.Val || RHSMask.Val) { @@ -1532,35 +1533,71 @@ // fold (or (shl x, y), (srl x, (sub 32, y))) -> (rotl x, y) // fold (or (shl x, y), (srl x, (sub 32, y))) -> (rotr x, (sub 32, y)) - if (RHSShift.getOperand(1).getOpcode() == ISD::SUB && - LHSShift.getOperand(1) == RHSShift.getOperand(1).getOperand(1)) { + if (RHSShiftAmt.getOpcode() == ISD::SUB && + LHSShiftAmt == RHSShiftAmt.getOperand(1)) { if (ConstantSDNode *SUBC = - dyn_cast<ConstantSDNode>(RHSShift.getOperand(1).getOperand(0))) { + dyn_cast<ConstantSDNode>(RHSShiftAmt.getOperand(0))) { if (SUBC->getValue() == OpSizeInBits) if (HasROTL) - return DAG.getNode(ISD::ROTL, VT, LHSShift.getOperand(0), - LHSShift.getOperand(1)).Val; + return DAG.getNode(ISD::ROTL, VT, LHSShiftArg, LHSShiftAmt).Val; else - return DAG.getNode(ISD::ROTR, VT, LHSShift.getOperand(0), - LHSShift.getOperand(1)).Val; + return DAG.getNode(ISD::ROTR, VT, LHSShiftArg, LHSShiftAmt).Val; } } // fold (or (shl x, (sub 32, y)), (srl x, r)) -> (rotr x, y) // fold (or (shl x, (sub 32, y)), (srl x, r)) -> (rotl x, (sub 32, y)) - if (LHSShift.getOperand(1).getOpcode() == ISD::SUB && - RHSShift.getOperand(1) == LHSShift.getOperand(1).getOperand(1)) { + if (LHSShiftAmt.getOpcode() == ISD::SUB && + RHSShiftAmt == LHSShiftAmt.getOperand(1)) { if (ConstantSDNode *SUBC = - dyn_cast<ConstantSDNode>(LHSShift.getOperand(1).getOperand(0))) { + dyn_cast<ConstantSDNode>(LHSShiftAmt.getOperand(0))) { if (SUBC->getValue() == OpSizeInBits) if (HasROTL) - return DAG.getNode(ISD::ROTL, VT, LHSShift.getOperand(0), - LHSShift.getOperand(1)).Val; + return DAG.getNode(ISD::ROTL, VT, LHSShiftArg, LHSShiftAmt).Val; else - return DAG.getNode(ISD::ROTR, VT, LHSShift.getOperand(0), - RHSShift.getOperand(1)).Val; + return DAG.getNode(ISD::ROTR, VT, LHSShiftArg, RHSShiftAmt).Val; } } + + // Look for sign/zext/any-extended cases: + if ((LHSShiftAmt.getOpcode() == ISD::SIGN_EXTEND + || LHSShiftAmt.getOpcode() == ISD::ZERO_EXTEND + || LHSShiftAmt.getOpcode() == ISD::ANY_EXTEND) && + (RHSShiftAmt.getOpcode() == ISD::SIGN_EXTEND + || RHSShiftAmt.getOpcode() == ISD::ZERO_EXTEND + || RHSShiftAmt.getOpcode() == ISD::ANY_EXTEND)) { + SDOperand LHSOp0 = LHSShiftAmt.getOperand(0); + SDOperand RHSOp0 = RHSShiftAmt.getOperand(0); + if (RHSOp0.getOpcode() == ISD::SUB && + RHSOp0.getOperand(1) == LHSOp0) { + // fold (or (shl x, (*ext y)), (srl x, (*ext (sub 32, y)))) -> + // (rotr x, y) + // fold (or (shl x, (*ext y)), (srl x, (*ext (sub 32, y)))) -> + // (rotl x, (sub 32, y)) + if (ConstantSDNode *SUBC = cast<ConstantSDNode>(RHSOp0.getOperand(0))) { + if (SUBC->getValue() == OpSizeInBits) { + if (HasROTL) + return DAG.getNode(ISD::ROTL, VT, LHSShiftArg, LHSShiftAmt).Val; + else + return DAG.getNode(ISD::ROTR, VT, LHSShiftArg, RHSShiftAmt).Val; + } + } + } else if (LHSOp0.getOpcode() == ISD::SUB && + RHSOp0 == LHSOp0.getOperand(1)) { + // fold (or (shl x, (*ext (sub 32, y))), (srl x, (*ext r))) -> + // (rotl x, y) + // fold (or (shl x, (*ext (sub 32, y))), (srl x, (*ext r))) -> + // (rotr x, (sub 32, y)) + if (ConstantSDNode *SUBC = cast<ConstantSDNode>(LHSOp0.getOperand(0))) { + if (SUBC->getValue() == OpSizeInBits) { + if (HasROTL) + return DAG.getNode(ISD::ROTL, VT, LHSShiftArg, RHSShiftAmt).Val; + else + return DAG.getNode(ISD::ROTL, VT, LHSShiftArg, LHSShiftAmt).Val; + } + } + } + } return 0; }