Index: llvm/lib/Target/RISCV/RISCVISelLowering.h =================================================================== --- llvm/lib/Target/RISCV/RISCVISelLowering.h +++ llvm/lib/Target/RISCV/RISCVISelLowering.h @@ -51,7 +51,14 @@ FMV_X_ANYEXTW_RV64, // READ_CYCLE_WIDE - A read of the 64-bit cycle CSR on a 32-bit target // (returns (Lo, Hi)). It takes a chain operand. - READ_CYCLE_WIDE + READ_CYCLE_WIDE, + // Generalized Reverse and Generalized Or-Combine - directly matching the + // semantics of the named RISC-V instructions. Lowered as custom nodes as + // TableGen chokes when faced with commutative permutations in deeply-nested + // DAGs. Each node takes an input operand and a TargetConstant immediate + // shift amount, and outputs a bit-manipulated version of input. All operands + // are of type XLenVT. + GREVIW, }; } Index: llvm/lib/Target/RISCV/RISCVISelLowering.cpp =================================================================== --- llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -156,8 +156,16 @@ setOperationAction(ISD::ROTR, XLenVT, Expand); } - if (!Subtarget.hasStdExtZbp()) + if (Subtarget.hasStdExtZbp()) { + setOperationAction(ISD::BITREVERSE, XLenVT, Legal); + + if (Subtarget.is64Bit()) { + setOperationAction(ISD::BITREVERSE, MVT::i32, Custom); + setOperationAction(ISD::BSWAP, MVT::i32, Custom); + } + } else { setOperationAction(ISD::BSWAP, XLenVT, Expand); + } if (!Subtarget.hasStdExtZbb()) { setOperationAction(ISD::CTTZ, XLenVT, Expand); @@ -165,9 +173,6 @@ setOperationAction(ISD::CTPOP, XLenVT, Expand); } - if (Subtarget.hasStdExtZbp()) - setOperationAction(ISD::BITREVERSE, XLenVT, Legal); - if (Subtarget.hasStdExtZbt()) { setOperationAction(ISD::FSHL, XLenVT, Legal); setOperationAction(ISD::FSHR, XLenVT, Legal); @@ -1026,6 +1031,21 @@ Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, FPConv)); break; } + case ISD::BSWAP: + case ISD::BITREVERSE: { + assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() && + Subtarget.hasStdExtZbp() && "Unexpected custom legalisation"); + SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, + N->getOperand(0)); + unsigned Imm = N->getOpcode() == ISD::BITREVERSE ? 31 : 24; + SDValue GREVIW = DAG.getNode(RISCVISD::GREVIW, DL, MVT::i64, NewOp0, + DAG.getTargetConstant(Imm, DL, + Subtarget.getXLenVT())); + // ReplaceNodeResults requires we maintain the same type for the return + // value. + Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, GREVIW)); + break; + } } } @@ -1094,6 +1114,17 @@ } break; } + case RISCVISD::GREVIW: { + // Only the lower 32 bits of the first operand are read. + SDValue Op0 = N->getOperand(0); + APInt Mask = APInt::getLowBitsSet(Op0.getValueSizeInBits(), 32); + if (SimplifyDemandedBits(Op0, Mask, DCI)) { + if (N->getOpcode() != ISD::DELETED_NODE) + DCI.AddToWorklist(N); + return SDValue(N, 0); + } + break; + } case RISCVISD::FMV_X_ANYEXTW_RV64: { SDLoc DL(N); SDValue Op0 = N->getOperand(0); @@ -1187,6 +1218,7 @@ case RISCVISD::DIVW: case RISCVISD::DIVUW: case RISCVISD::REMUW: + case RISCVISD::GREVIW: // TODO: As the result is sign-extended, this is conservatively correct. A // more precise answer could be calculated for SRAW depending on known // bits in the shift amount. @@ -2639,6 +2671,8 @@ return "RISCVISD::FMV_X_ANYEXTW_RV64"; case RISCVISD::READ_CYCLE_WIDE: return "RISCVISD::READ_CYCLE_WIDE"; + case RISCVISD::GREVIW: + return "RISCVISD::GREVIW"; } return nullptr; } Index: llvm/lib/Target/RISCV/RISCVInstrInfoB.td =================================================================== --- llvm/lib/Target/RISCV/RISCVInstrInfoB.td +++ llvm/lib/Target/RISCV/RISCVInstrInfoB.td @@ -17,6 +17,11 @@ // Operand and SDNode transformation definitions. //===----------------------------------------------------------------------===// +def SDT_RISCVGREVGORC : SDTypeProfile<1, 2, [SDTCisVT<0, XLenVT>, + SDTCisSameAs<0, 1>, + SDTCisSameAs<1, 2>]>; +def riscv_greviw : SDNode<"RISCVISD::GREVIW", SDT_RISCVGREVGORC, []>; + def UImmLog2XLenHalfAsmOperand : AsmOperandClass { let Name = "UImmLog2XLenHalf"; let RenderMethod = "addImmOperands"; @@ -1009,6 +1014,7 @@ (shl GPR:$rs1, (i64 16))), i32), (GORCIW GPR:$rs1, (i64 16))>; +def : Pat<(riscv_greviw GPR:$rs1, timm:$shamt), (GREVIW GPR:$rs1, timm:$shamt)>; def : Pat<(sext_inreg (or (and (shl GPR:$rs1, (i64 1)), (i64 0xAAAAAAAA)), (and (srl GPR:$rs1, (i64 1)), (i64 0x55555555))), i32), @@ -1028,8 +1034,6 @@ def : Pat<(sext_inreg (or (shl GPR:$rs1, (i64 16)), (srl (and GPR:$rs1, 0xFFFF0000), (i64 16))), i32), (GREVIW GPR:$rs1, (i64 16))>; -def : Pat<(sra (bswap GPR:$rs1), (i64 32)), (GREVIW GPR:$rs1, (i64 24))>; -def : Pat<(sra (bitreverse GPR:$rs1), (i64 32)), (GREVIW GPR:$rs1, (i64 31))>; } // Predicates = [HasStdExtZbp, IsRV64] let Predicates = [HasStdExtZbt, IsRV64] in { Index: llvm/test/CodeGen/RISCV/rv64Zbp.ll =================================================================== --- llvm/test/CodeGen/RISCV/rv64Zbp.ll +++ llvm/test/CodeGen/RISCV/rv64Zbp.ll @@ -958,15 +958,13 @@ ; ; RV64IB-LABEL: bswap_i32_nosext: ; RV64IB: # %bb.0: -; RV64IB-NEXT: rev8 a0, a0 -; RV64IB-NEXT: srli a0, a0, 32 +; RV64IB-NEXT: greviw a0, a0, 24 ; RV64IB-NEXT: sw a0, 0(a1) ; RV64IB-NEXT: ret ; ; RV64IBP-LABEL: bswap_i32_nosext: ; RV64IBP: # %bb.0: -; RV64IBP-NEXT: rev8 a0, a0 -; RV64IBP-NEXT: srli a0, a0, 32 +; RV64IBP-NEXT: greviw a0, a0, 24 ; RV64IBP-NEXT: sw a0, 0(a1) ; RV64IBP-NEXT: ret %1 = tail call i32 @llvm.bswap.i32(i32 %a) @@ -1219,15 +1217,13 @@ ; ; RV64IB-LABEL: bitreverse_i32_nosext: ; RV64IB: # %bb.0: -; RV64IB-NEXT: rev a0, a0 -; RV64IB-NEXT: srli a0, a0, 32 +; RV64IB-NEXT: greviw a0, a0, 31 ; RV64IB-NEXT: sw a0, 0(a1) ; RV64IB-NEXT: ret ; ; RV64IBP-LABEL: bitreverse_i32_nosext: ; RV64IBP: # %bb.0: -; RV64IBP-NEXT: rev a0, a0 -; RV64IBP-NEXT: srli a0, a0, 32 +; RV64IBP-NEXT: greviw a0, a0, 31 ; RV64IBP-NEXT: sw a0, 0(a1) ; RV64IBP-NEXT: ret %1 = tail call i32 @llvm.bitreverse.i32(i32 %a)