diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp index d298965595b47..4539efd591c8b 100644 --- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp @@ -683,6 +683,59 @@ bool RISCVDAGToDAGISel::trySignedBitfieldExtract(SDNode *Node) { return false; } +bool RISCVDAGToDAGISel::trySignedBitfieldInsertInSign(SDNode *Node) { + // Only supported with XAndesPerf at the moment. + if (!Subtarget->hasVendorXAndesPerf()) + return false; + + auto *N1C = dyn_cast(Node->getOperand(1)); + if (!N1C) + return false; + + SDValue N0 = Node->getOperand(0); + if (!N0.hasOneUse()) + return false; + + auto BitfieldInsert = [&](SDValue N0, unsigned Msb, unsigned Lsb, + const SDLoc &DL, MVT VT) { + unsigned Opc = RISCV::NDS_BFOS; + // If the Lsb is equal to the Msb, then the Lsb should be 0. + if (Lsb == Msb) + Lsb = 0; + return CurDAG->getMachineNode(Opc, DL, VT, N0.getOperand(0), + CurDAG->getTargetConstant(Lsb, DL, VT), + CurDAG->getTargetConstant(Msb, DL, VT)); + }; + + SDLoc DL(Node); + MVT VT = Node->getSimpleValueType(0); + const unsigned RightShAmt = N1C->getZExtValue(); + + // Transform (sra (shl X, C1) C2) with C1 > C2 + // -> (NDS.BFOS X, lsb, msb) + if (N0.getOpcode() == ISD::SHL) { + auto *N01C = dyn_cast(N0->getOperand(1)); + if (!N01C) + return false; + + const unsigned LeftShAmt = N01C->getZExtValue(); + // Make sure that this is a bitfield insertion (i.e., the shift-right + // amount should be less than the left-shift). + if (LeftShAmt <= RightShAmt) + return false; + + const unsigned MsbPlusOne = VT.getSizeInBits() - RightShAmt; + const unsigned Msb = MsbPlusOne - 1; + const unsigned Lsb = LeftShAmt - RightShAmt; + + SDNode *Sbi = BitfieldInsert(N0, Msb, Lsb, DL, VT); + ReplaceNode(Node, Sbi); + return true; + } + + return false; +} + bool RISCVDAGToDAGISel::tryUnsignedBitfieldExtract(SDNode *Node, const SDLoc &DL, MVT VT, SDValue X, unsigned Msb, @@ -1214,6 +1267,9 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) { if (trySignedBitfieldExtract(Node)) return; + if (trySignedBitfieldInsertInSign(Node)) + return; + // Optimize (sra (sext_inreg X, i16), C) -> // (srai (slli X, (XLen-16), (XLen-16) + C) // And (sra (sext_inreg X, i8), C) -> diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h index abc0372d15c4f..cb63c21fd8fc9 100644 --- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h +++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h @@ -77,6 +77,7 @@ class RISCVDAGToDAGISel : public SelectionDAGISel { bool tryShrinkShlLogicImm(SDNode *Node); bool trySignedBitfieldExtract(SDNode *Node); + bool trySignedBitfieldInsertInSign(SDNode *Node); bool tryUnsignedBitfieldExtract(SDNode *Node, const SDLoc &DL, MVT VT, SDValue X, unsigned Msb, unsigned Lsb); bool tryUnsignedBitfieldInsertInZero(SDNode *Node, const SDLoc &DL, MVT VT, diff --git a/llvm/test/CodeGen/RISCV/rv32xandesperf.ll b/llvm/test/CodeGen/RISCV/rv32xandesperf.ll index 3996420d477b2..3e7f09f3d6c22 100644 --- a/llvm/test/CodeGen/RISCV/rv32xandesperf.ll +++ b/llvm/test/CodeGen/RISCV/rv32xandesperf.ll @@ -154,6 +154,32 @@ define i32 @bfos_from_ashr_sexti16_i32(i16 %x) { ret i32 %ashr } +; MSB = 0 + +define i32 @bfos_from_ashr_shl_with_msb_zero_insert_i32(i32 %x) { +; CHECK-LABEL: bfos_from_ashr_shl_with_msb_zero_insert_i32: +; CHECK: # %bb.0: +; CHECK-NEXT: nds.bfos a0, a0, 0, 14 +; CHECK-NEXT: ret + %shl = shl i32 %x, 31 + %lshr = ashr i32 %shl, 17 + ret i32 %lshr +} + +; MSB < LSB + +define i32 @bfos_from_ashr_shl_insert_i32(i32 %x) { +; CHECK-LABEL: bfos_from_ashr_shl_insert_i32: +; CHECK: # %bb.0: +; CHECK-NEXT: nds.bfos a0, a0, 18, 20 +; CHECK-NEXT: ret + %shl = shl i32 %x, 29 + %lshr = ashr i32 %shl, 11 + ret i32 %lshr +} + +; sext + define i32 @sexti1_i32(i32 %a) { ; CHECK-LABEL: sexti1_i32: ; CHECK: # %bb.0: diff --git a/llvm/test/CodeGen/RISCV/rv64xandesperf.ll b/llvm/test/CodeGen/RISCV/rv64xandesperf.ll index af7c300a92d1f..98cda42665169 100644 --- a/llvm/test/CodeGen/RISCV/rv64xandesperf.ll +++ b/llvm/test/CodeGen/RISCV/rv64xandesperf.ll @@ -212,6 +212,52 @@ define i64 @bfos_from_ashr_sexti16_i64(i16 %x) { ret i64 %ashr } +; MSB = 0 + +define i32 @bfos_from_ashr_shl_with_msb_zero_insert_i32(i32 %x) { +; CHECK-LABEL: bfos_from_ashr_shl_with_msb_zero_insert_i32: +; CHECK: # %bb.0: +; CHECK-NEXT: nds.bfos a0, a0, 0, 14 +; CHECK-NEXT: ret + %shl = shl i32 %x, 31 + %lshr = ashr i32 %shl, 17 + ret i32 %lshr +} + +define i64 @bfos_from_ashr_shl_with_msb_zero_insert_i64(i64 %x) { +; CHECK-LABEL: bfos_from_ashr_shl_with_msb_zero_insert_i64: +; CHECK: # %bb.0: +; CHECK-NEXT: nds.bfos a0, a0, 0, 46 +; CHECK-NEXT: ret + %shl = shl i64 %x, 63 + %lshr = ashr i64 %shl, 17 + ret i64 %lshr +} + +; MSB < LSB + +define i32 @bfos_from_ashr_shl_insert_i32(i32 %x) { +; CHECK-LABEL: bfos_from_ashr_shl_insert_i32: +; CHECK: # %bb.0: +; CHECK-NEXT: nds.bfos a0, a0, 18, 20 +; CHECK-NEXT: ret + %shl = shl i32 %x, 29 + %lshr = ashr i32 %shl, 11 + ret i32 %lshr +} + +define i64 @bfos_from_ashr_shl_insert_i64(i64 %x) { +; CHECK-LABEL: bfos_from_ashr_shl_insert_i64: +; CHECK: # %bb.0: +; CHECK-NEXT: nds.bfos a0, a0, 18, 52 +; CHECK-NEXT: ret + %shl = shl i64 %x, 29 + %lshr = ashr i64 %shl, 11 + ret i64 %lshr +} + +; sext + define signext i32 @sexti1_i32(i32 signext %a) { ; CHECK-LABEL: sexti1_i32: ; CHECK: # %bb.0: