Index: llvm/lib/Target/RISCV/RISCVISelLowering.cpp =================================================================== --- llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -283,6 +283,8 @@ if (Subtarget.hasStdExtZbp()) { setTargetDAGCombine(ISD::OR); + setTargetDAGCombine(ISD::ROTL); + setTargetDAGCombine(ISD::ROTR); } } @@ -1303,19 +1305,45 @@ return SDValue(); } +// Helper to enable rotates by bitwidth/2 to be treated as a GREVI/GREVIW. +static bool canCombineWithGREVOrGORC(SDNode *N, unsigned &Opcode, + unsigned &ShAmt, SDValue &Src) { + if (N->getOpcode() == ISD::ROTL || N->getOpcode() == ISD::ROTR) { + Opcode = RISCVISD::GREVI; + ShAmt = N->getValueSizeInBits(0) / 2; + } else if (N->getOpcode() == RISCVISD::ROLW || + N->getOpcode() == RISCVISD::RORW) { + Opcode = RISCVISD::GREVIW; + ShAmt = 16; + } else + return false; + + // We found a rotate, check that it is a constant that matches the required + // value. + Src = N->getOperand(0); + return isa(N->getOperand(1)) && + N->getConstantOperandVal(1) == ShAmt; +} + // Combine (GREVI (GREVI x, C2), C1) -> (GREVI x, C1^C2) when C1^C2 is // non-zero, and to x when it is. Any repeated GREVI stage undoes itself. // Combine (GORCI (GORCI x, C2), C1) -> (GORCI x, C1|C2). Repeated stage does // not undo itself, but they are redundant. static SDValue combineGREVI_GORCI(SDNode *N, SelectionDAG &DAG) { - unsigned ShAmt1 = N->getConstantOperandVal(1); SDValue Src = N->getOperand(0); - if (Src.getOpcode() != N->getOpcode()) + unsigned ShAmt2; + unsigned Opcode; + if (N->getOpcode() == Src.getOpcode()) { + ShAmt2 = Src.getConstantOperandVal(1); + Src = Src.getOperand(0); + } else if (canCombineWithGREVOrGORC(Src.getNode(), Opcode, ShAmt2, Src) && + N->getOpcode() == Opcode) { + // Variables assigned by canCombineWithGREVOrGORC. + } else return SDValue(); - unsigned ShAmt2 = Src.getConstantOperandVal(1); - Src = Src.getOperand(0); + unsigned ShAmt1 = N->getConstantOperandVal(1); unsigned CombinedShAmt; if (N->getOpcode() == RISCVISD::GORCI || N->getOpcode() == RISCVISD::GORCIW) @@ -1332,6 +1360,34 @@ N->getOperand(1).getValueType())); } +// Combine (rotl/rotr (GREVI X, C1), BitWidth/2) into a single GREVI. +static SDValue combineRotate(SDNode *N, SelectionDAG &DAG) { + assert((N->getOpcode() == ISD::ROTL || N->getOpcode() == ISD::ROTR) && + "Unexpected opcode!"); + + SDValue Src = N->getOperand(0); + + // Input must be a GREVI. + if (Src.getOpcode() != RISCVISD::GREVI) + return SDValue(); + + unsigned ShAmt1; + unsigned Opcode; + SDValue Dummy; + if (!canCombineWithGREVOrGORC(N, Opcode, ShAmt1, Dummy) || + Opcode != RISCVISD::GREVI) + return SDValue(); + + unsigned ShAmt2 = Src.getConstantOperandVal(1); + + unsigned CombinedShAmt = ShAmt1 ^ ShAmt2; + + SDLoc DL(N); + return DAG.getNode(RISCVISD::GREVI, DL, N->getValueType(0), Src.getOperand(0), + DAG.getTargetConstant(CombinedShAmt, DL, + Src.getOperand(1).getValueType())); +} + SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const { SelectionDAG &DAG = DCI.DAG; @@ -1397,6 +1453,24 @@ DCI.AddToWorklist(N); return SDValue(N, 0); } + + // Combine (ROLW/RORW (GREVIW X, C1), 16) into a single GREVIW. + SDValue Src = N->getOperand(0); + unsigned ShAmt1; + unsigned Opcode; + SDValue Dummy; + if (Src.getOpcode() == RISCVISD::GREVIW && + canCombineWithGREVOrGORC(N, Opcode, ShAmt1, Dummy) && + Opcode == RISCVISD::GREVIW) { + unsigned ShAmt2 = Src.getConstantOperandVal(1); + unsigned CombinedShAmt = ShAmt1 ^ ShAmt2; + SDLoc DL(N); + return DAG.getNode( + RISCVISD::GREVIW, DL, N->getValueType(0), Src.getOperand(0), + DAG.getTargetConstant(CombinedShAmt, DL, + Src.getOperand(1).getValueType())); + } + break; } case RISCVISD::FSLW: @@ -1469,6 +1543,9 @@ if (auto GORC = combineORToGORC(SDValue(N, 0), DCI.DAG, Subtarget)) return GORC; break; + case ISD::ROTL: + case ISD::ROTR: + return combineRotate(N, DCI.DAG); } return SDValue(); Index: llvm/lib/Target/RISCV/RISCVInstrInfoB.td =================================================================== --- llvm/lib/Target/RISCV/RISCVInstrInfoB.td +++ llvm/lib/Target/RISCV/RISCVInstrInfoB.td @@ -729,11 +729,6 @@ def : Pat<(riscv_gorci GPR:$rs1, timm:$shamt), (GORCI GPR:$rs1, timm:$shamt)>; } // Predicates = [HasStdExtZbp] -let Predicates = [HasStdExtZbp, IsRV32] in { -def : Pat<(rotr (riscv_grevi GPR:$rs1, (i32 24)), (i32 16)), (GREVI GPR:$rs1, 8)>; -def : Pat<(rotl (riscv_grevi GPR:$rs1, (i32 24)), (i32 16)), (GREVI GPR:$rs1, 8)>; -} // Predicates = [HasStdExtZbp, IsRV32] - let Predicates = [HasStdExtZbt] in { def : Pat<(or (and (not GPR:$rs2), GPR:$rs3), (and GPR:$rs2, GPR:$rs1)), (CMIX GPR:$rs1, GPR:$rs2, GPR:$rs3)>; @@ -915,8 +910,6 @@ } // Predicates = [HasStdExtZbb, IsRV64] let Predicates = [HasStdExtZbp, IsRV64] in { -def : Pat<(riscv_rorw (riscv_greviw GPR:$rs1, 24), (i64 16)), (GREVIW GPR:$rs1, 8)>; -def : Pat<(riscv_rolw (riscv_greviw GPR:$rs1, 24), (i64 16)), (GREVIW GPR:$rs1, 8)>; def : Pat<(riscv_greviw GPR:$rs1, timm:$shamt), (GREVIW GPR:$rs1, timm:$shamt)>; def : Pat<(riscv_gorciw GPR:$rs1, timm:$shamt), (GORCIW GPR:$rs1, timm:$shamt)>; } // Predicates = [HasStdExtZbp, IsRV64]