[llvm] [RISCV] Implement Intrinsics and CodeGen Support for XCValu Extension… (PR #78138)

via llvm-commits llvm-commits at lists.llvm.org
Mon Jan 15 01:55:30 PST 2024


https://github.com/realqhc created https://github.com/llvm/llvm-project/pull/78138

… in CV32E40P

Implement XCValu intrinsics and CodeGen for CV32E40P according to the specification.

This commit is part of a patch-set to upstream the vendor specific extensions of CV32E40P that need LLVM intrinsics to implement Clang builtins.

Contributors: @CharKeaney, @ChunyuLiao, @jeremybennett, @lewis-revill, @NandniJamnadas, @PaoloS02, @serkm, @simonpcook, @xingmingjie.

>From 0c00753fbc8771c5fa3ac6bb060c26a90d6460de Mon Sep 17 00:00:00 2001
From: Qihan Cai <qcai8733 at uni.sydney.edu.au>
Date: Fri, 12 Jan 2024 12:40:29 +0800
Subject: [PATCH] [RISCV] Implement Intrinsics and CodeGen Support for XCValu
 Extension in CV32E40P

Implement XCValu intrinsics for CV32E40P according to the
specification.

This commit is part of a patch-set to upstream the vendor specific
extensions of CV32E40P that need LLVM intrinsics to implement Clang
builtins.

Contributors: @CharKeaney, @ChunyuLiao, @jeremybennett, @lewis-revill,
@NandniJamnadas, @PaoloS02, @serkm, @simonpcook, @xingmingjie.
---
 llvm/include/llvm/IR/IntrinsicsRISCVXCV.td    |  28 +
 .../Target/RISCV/RISCVExpandPseudoInsts.cpp   |  83 +++
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp   |  16 +-
 llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td    | 162 ++++-
 llvm/test/CodeGen/RISCV/xcvalu.ll             | 583 ++++++++++++++++++
 5 files changed, 866 insertions(+), 6 deletions(-)
 create mode 100644 llvm/test/CodeGen/RISCV/xcvalu.ll

diff --git a/llvm/include/llvm/IR/IntrinsicsRISCVXCV.td b/llvm/include/llvm/IR/IntrinsicsRISCVXCV.td
index f1590ad66e362b..f0c6faadf6aabf 100644
--- a/llvm/include/llvm/IR/IntrinsicsRISCVXCV.td
+++ b/llvm/include/llvm/IR/IntrinsicsRISCVXCV.td
@@ -18,6 +18,18 @@ class ScalarCoreVBitManipGprIntrinsic
     : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty],
                             [IntrNoMem, IntrSpeculatable]>;
 
+class ScalarCoreVAluGprIntrinsic
+  : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty],
+                          [IntrNoMem, IntrSpeculatable]>;
+
+class ScalarCoreVAluGprGprIntrinsic
+  : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty],
+                          [IntrNoMem, IntrSpeculatable]>;
+
+class ScalarCoreVAluGprGprGprIntrinsic
+  : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty],
+                          [IntrNoMem, IntrSpeculatable]>;
+
 let TargetPrefix = "riscv" in {
   def int_riscv_cv_bitmanip_extract : ScalarCoreVBitManipGprGprIntrinsic;
   def int_riscv_cv_bitmanip_extractu : ScalarCoreVBitManipGprGprIntrinsic;
@@ -34,4 +46,20 @@ let TargetPrefix = "riscv" in {
     : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty],
                             [IntrNoMem, IntrWillReturn, IntrSpeculatable,
                             ImmArg<ArgIndex<1>>, ImmArg<ArgIndex<2>>]>;
+
+  def int_riscv_cv_alu_exths : ScalarCoreVAluGprIntrinsic;
+  def int_riscv_cv_alu_exthz : ScalarCoreVAluGprIntrinsic;
+  def int_riscv_cv_alu_extbs : ScalarCoreVAluGprIntrinsic;
+  def int_riscv_cv_alu_extbz : ScalarCoreVAluGprIntrinsic;
+
+  def int_riscv_cv_alu_clip   : ScalarCoreVAluGprGprIntrinsic;
+  def int_riscv_cv_alu_clipu  : ScalarCoreVAluGprGprIntrinsic;
+  def int_riscv_cv_alu_addn   : ScalarCoreVAluGprGprGprIntrinsic;
+  def int_riscv_cv_alu_addun  : ScalarCoreVAluGprGprGprIntrinsic;
+  def int_riscv_cv_alu_addrn  : ScalarCoreVAluGprGprGprIntrinsic;
+  def int_riscv_cv_alu_addurn : ScalarCoreVAluGprGprGprIntrinsic;
+  def int_riscv_cv_alu_subn   : ScalarCoreVAluGprGprGprIntrinsic;
+  def int_riscv_cv_alu_subun  : ScalarCoreVAluGprGprGprIntrinsic;
+  def int_riscv_cv_alu_subrn  : ScalarCoreVAluGprGprGprIntrinsic;
+  def int_riscv_cv_alu_suburn : ScalarCoreVAluGprGprGprIntrinsic;
 } // TargetPrefix = "riscv"
diff --git a/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp b/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp
index ed2b1ceb7d6f0d..aaac5ce834dd4b 100644
--- a/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp
+++ b/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp
@@ -53,6 +53,8 @@ class RISCVExpandPseudo : public MachineFunctionPass {
                             MachineBasicBlock::iterator MBBI);
   bool expandRV32ZdinxLoad(MachineBasicBlock &MBB,
                            MachineBasicBlock::iterator MBBI);
+  bool expandCoreVClip(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI);
+  bool expandCoreVAddSub(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI);
 #ifndef NDEBUG
   unsigned getInstSizeInBytes(const MachineFunction &MF) const {
     unsigned Size = 0;
@@ -161,6 +163,16 @@ bool RISCVExpandPseudo::expandMI(MachineBasicBlock &MBB,
   case RISCV::PseudoVMSET_M_B64:
     // vmset.m vd => vmxnor.mm vd, vd, vd
     return expandVMSET_VMCLR(MBB, MBBI, RISCV::VMXNOR_MM);
+  case RISCV::CV_CLIP_PSEUDO:
+  case RISCV::CV_CLIPU_PSEUDO:return expandCoreVClip(MBB, MBBI);
+  case RISCV::CV_ADDN_PSEUDO:
+  case RISCV::CV_ADDUN_PSEUDO:
+  case RISCV::CV_ADDRN_PSEUDO:
+  case RISCV::CV_ADDURN_PSEUDO:
+  case RISCV::CV_SUBN_PSEUDO:
+  case RISCV::CV_SUBUN_PSEUDO:
+  case RISCV::CV_SUBRN_PSEUDO:
+  case RISCV::CV_SUBURN_PSEUDO:return expandCoreVAddSub(MBB, MBBI);
   }
 
   return false;
@@ -547,6 +559,77 @@ bool RISCVPreRAExpandPseudo::expandLoadTLSGDAddress(
                              RISCV::ADDI);
 }
 
+bool RISCVExpandPseudo::expandCoreVClip(llvm::MachineBasicBlock &MBB,
+                                        MachineBasicBlock::iterator MBBI) {
+  DebugLoc DL = MBBI->getDebugLoc();
+  Register DstReg = MBBI->getOperand(0).getReg();
+  Register I = MBBI->getOperand(1).getReg();
+  uint64_t J = MBBI->getOperand(2).getImm();
+
+  unsigned Opcode = MBBI->getOpcode() == RISCV::CV_CLIPU_PSEUDO ?
+                    RISCV::CV_CLIPU : RISCV::CV_CLIP;
+  const MCInstrDesc &Desc = TII->get(Opcode);
+  BuildMI(MBB, MBBI, DL, Desc, DstReg)
+      .addReg(I)
+      .addImm(Log2_32_Ceil(J + 1) + 1);
+  MBBI->eraseFromParent();
+  return true;
+}
+
+bool RISCVExpandPseudo::expandCoreVAddSub(llvm::MachineBasicBlock &MBB,
+                                          MachineBasicBlock::iterator MBBI) {
+  auto *MRI = &MBB.getParent()->getRegInfo();
+  DebugLoc DL = MBBI->getDebugLoc();
+  Register DstReg = MBBI->getOperand(0).getReg();
+  Register X = MBBI->getOperand(1).getReg();
+  Register Y = MBBI->getOperand(2).getReg();
+  uint8_t Shift = MBBI->getOperand(3).getImm();
+
+  bool IsImm = 0 <= Shift && Shift <= 31;
+  unsigned Opcode;
+  switch (MBBI->getOpcode()) {
+  case RISCV::CV_ADDN_PSEUDO:
+    Opcode = IsImm ? RISCV::CV_ADDN : RISCV::CV_ADDNR;
+    break;
+  case RISCV::CV_ADDUN_PSEUDO:
+    Opcode = IsImm ? RISCV::CV_ADDUN : RISCV::CV_ADDUNR;
+    break;
+  case RISCV::CV_ADDRN_PSEUDO:
+    Opcode = IsImm ? RISCV::CV_ADDRN : RISCV::CV_ADDRNR;
+    break;
+  case RISCV::CV_ADDURN_PSEUDO:
+    Opcode = IsImm ? RISCV::CV_ADDURN : RISCV::CV_ADDURNR;
+    break;
+  case RISCV::CV_SUBN_PSEUDO:
+    Opcode = IsImm ? RISCV::CV_SUBN : RISCV::CV_SUBNR;
+    break;
+  case RISCV::CV_SUBUN_PSEUDO:
+    Opcode = IsImm ? RISCV::CV_SUBUN : RISCV::CV_SUBUNR;
+    break;
+  case RISCV::CV_SUBRN_PSEUDO:
+    Opcode = IsImm ? RISCV::CV_SUBRN : RISCV::CV_SUBRNR;
+    break;
+  case RISCV::CV_SUBURN_PSEUDO:
+    Opcode = IsImm ? RISCV::CV_SUBURN : RISCV::CV_SUBURNR;
+    break;
+  default:llvm_unreachable("unknown instruction");
+  }
+  const MCInstrDesc &Desc = TII->get(Opcode);
+  if (IsImm) {
+    BuildMI(MBB, MBBI, DL, Desc, DstReg).
+        addReg(X).
+        addReg(Y).
+        addImm(Shift);
+  } else {
+    MRI->replaceRegWith(DstReg, X);
+    BuildMI(MBB, MBBI, DL, Desc, DstReg).
+        addReg(Y).
+        addReg(DstReg);
+  }
+  MBBI->eraseFromParent();
+  return true;
+}
+
 } // end of anonymous namespace
 
 INITIALIZE_PASS(RISCVExpandPseudo, "riscv-expand-pseudo",
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index cb9ffabc41236e..0979b40af768ed 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -250,10 +250,12 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
   if (RV64LegalI32 && Subtarget.is64Bit())
     setOperationAction(ISD::SELECT_CC, MVT::i32, Expand);
 
-  setCondCodeAction(ISD::SETLE, XLenVT, Expand);
+  if (!Subtarget.hasVendorXCValu())
+    setCondCodeAction(ISD::SETLE, XLenVT, Expand);
   setCondCodeAction(ISD::SETGT, XLenVT, Custom);
   setCondCodeAction(ISD::SETGE, XLenVT, Expand);
-  setCondCodeAction(ISD::SETULE, XLenVT, Expand);
+  if (!Subtarget.hasVendorXCValu())
+    setCondCodeAction(ISD::SETULE, XLenVT, Expand);
   setCondCodeAction(ISD::SETUGT, XLenVT, Custom);
   setCondCodeAction(ISD::SETUGE, XLenVT, Expand);
 
@@ -1366,6 +1368,16 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
     }
   }
 
+  if (Subtarget.hasVendorXCValu()) {
+    setOperationAction(ISD::ABS, XLenVT, Legal);
+    setOperationAction(ISD::SMIN, XLenVT, Legal);
+    setOperationAction(ISD::UMIN, XLenVT, Legal);
+    setOperationAction(ISD::SMAX, XLenVT, Legal);
+    setOperationAction(ISD::UMAX, XLenVT, Legal);
+    setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8, Legal);
+    setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16, Legal);
+  }
+
   // Function alignments.
   const Align FunctionAlignment(Subtarget.hasStdExtCOrZca() ? 2 : 4);
   setMinFunctionAlignment(FunctionAlignment);
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td
index 924e91e15c348f..e0aeaf8c5c5f7c 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td
@@ -198,7 +198,7 @@ let DecoderNamespace = "XCValu" in {
 
 } // DecoderNamespace = "XCValu"
 
-let Predicates = [HasVendorXCValu],
+let Predicates = [HasVendorXCValu, IsRV32],
   hasSideEffects = 0, mayLoad = 0, mayStore = 0 in {
   // General ALU Operations
   def CV_ABS    : CVInstAluR<0b0101000, 0b011, "cv.abs">,
@@ -249,10 +249,10 @@ let Predicates = [HasVendorXCValu],
                   Sched<[]>;
   def CV_SUBURN : CVInstAluRRI<0b11, 0b011, "cv.suburn">,
                   Sched<[]>;
-} // Predicates = [HasVendorXCValu],
+} // Predicates = [HasVendorXCValu, IsRV32],
   //   hasSideEffects = 0, mayLoad = 0, mayStore = 0
 
-let Predicates = [HasVendorXCValu],
+let Predicates = [HasVendorXCValu, IsRV32],
   hasSideEffects = 0, mayLoad = 0, mayStore = 0,
   Constraints = "$rd = $rd_wb" in {
   def CV_ADDNR   : CVInstAluRRNR<0b1000000, 0b011, "cv.addnr">,
@@ -272,7 +272,7 @@ let Predicates = [HasVendorXCValu],
   def CV_SUBURNR : CVInstAluRRNR<0b1000111, 0b011, "cv.suburnr">,
                    Sched<[]>;
 
-} // Predicates = [HasVendorXCValu],
+} // Predicates = [HasVendorXCValu, IsRV32],
   //   hasSideEffects = 0, mayLoad = 0, mayStore = 0,
   //   Constraints = "$rd = $rd_wb"
 
@@ -662,6 +662,8 @@ let Predicates = [HasVendorXCVelw, IsRV32], hasSideEffects = 0,
 def cv_tuimm2 : TImmLeaf<XLenVT, [{return isUInt<2>(Imm);}]>;
 def cv_tuimm5 : TImmLeaf<XLenVT, [{return isUInt<5>(Imm);}]>;
 def cv_uimm10 : ImmLeaf<XLenVT, [{return isUInt<10>(Imm);}]>;
+def cv_uimm32: Operand<XLenVT>,
+               ImmLeaf<XLenVT, [{return isPowerOf2_32(Imm + 1);}]>;
 
 def CV_LO5: SDNodeXForm<imm, [{
   return CurDAG->getTargetConstant(N->getZExtValue() & 0x1f, SDLoc(N),
@@ -673,6 +675,49 @@ def CV_HI5: SDNodeXForm<imm, [{
                                    N->getValueType(0));
 }]>;
 
+def between : PatFrags<(ops node:$lowerBound, node:$upperBound, node:$value),
+                       [(smin (smax node:$value, node:$lowerBound), node:$upperBound),
+                        (smax (smin node:$value, node:$upperBound), node:$lowerBound)]>;
+
+def betweenu : PatFrags<(ops node:$upperBound, node:$value),
+                        [(smin (smax node:$value, 0), node:$upperBound),
+                         (smax (smin node:$value, node:$upperBound), 0)]>;
+def powerOf2 : ImmLeaf<XLenVT, [{ return isPowerOf2_32(Imm); }]>;
+def powerOf2Minus1 : ImmLeaf<XLenVT, [{ return isPowerOf2_32(Imm+1); }]>;
+def negativePowerOf2 : ImmLeaf<XLenVT, [{ return isPowerOf2_32(-Imm); }]>;
+def roundBit : PatFrag<(ops node:$shiftAmount),
+                       (srl (shl 1, node:$shiftAmount), (XLenVT 1))>;
+def trailing1sPlus1 : SDNodeXForm<imm, [{
+  return CurDAG->getTargetConstant(
+                          llvm::countr_one(N->getZExtValue()) + 1,
+                          SDLoc(N), N->getValueType(0));
+}]>;
+
+def shiftRound : PatFrag<(ops node:$value, node:$shiftAmount),
+                         (sra (add node:$value, powerOf2), node:$shiftAmount), [{
+  if (auto powerOf2 = dyn_cast<ConstantSDNode>(N->getOperand(0)->getOperand(1)))
+    return (powerOf2->getZExtValue() << 1) == (1U << N->getConstantOperandVal(1));
+  return false;
+}]>;
+
+def ushiftRound : PatFrag<(ops node:$value, node:$shiftAmount),
+                          (srl (add node:$value, powerOf2), node:$shiftAmount), [{
+  if (auto powerOf2 = dyn_cast<ConstantSDNode>(N->getOperand(0)->getOperand(1)))
+    return (powerOf2->getZExtValue() << 1) == (1U << N->getConstantOperandVal(1));
+  return false;
+}]>;
+
+def clip : PatFrag<(ops node:$upperBound, node:$value),
+                   (between negativePowerOf2, node:$upperBound, node:$value), [{
+  // Checking lower & upper bound for the clip instruction
+  if (auto bound1 = dyn_cast<ConstantSDNode>(N->getOperand(0)->getOperand(1))) {
+    if (auto bound2 = dyn_cast<ConstantSDNode>(N->getOperand(1))) {
+      return (bound1->getSExtValue() == ~bound2->getSExtValue());
+    }
+  }
+  return false;
+}]>;
+
 multiclass PatCoreVBitManip<Intrinsic intr> {
   def : PatGprGpr<intr, !cast<RVInst>("CV_" # NAME # "R")>;
   def : Pat<(intr GPR:$rs1, cv_uimm10:$imm),
@@ -704,3 +749,112 @@ let Predicates = [HasVendorXCVbitmanip, IsRV32] in {
             (CV_BITREV GPR:$rs1, cv_tuimm2:$radix, cv_tuimm5:$pts)>;
   def : Pat<(bitreverse (XLenVT GPR:$rs)), (CV_BITREV GPR:$rs, 0, 0)>;
 }
+
+class PatCoreVAluGpr <string intr, string asm> :
+  PatGpr<!cast<Intrinsic>("int_riscv_cv_alu_" # intr),
+            !cast<RVInst>("CV_" # asm)>;
+class PatCoreVAluGprGpr <string intr, string asm> :
+  PatGprGpr<!cast<Intrinsic>("int_riscv_cv_alu_" # intr),
+               !cast<RVInst>("CV_" # asm)>;
+
+multiclass PatCoreVAluGprImm <Intrinsic intr> {
+  def "CV_" # NAME # "_PSEUDO" :
+    Pseudo<(outs GPR:$rd), (ins GPR:$rs, cv_uimm32:$imm), []>;
+  def : PatGprGpr<intr, !cast<RVInst>("CV_" # NAME # "R")>;
+  def : PatGprImm<intr, !cast<RVInst>("CV_" # NAME # "_PSEUDO"), cv_uimm32>;
+}
+
+multiclass PatCoreVAluGprGprImm <Intrinsic intr> {
+  def "CV_" # NAME # "_PSEUDO" :
+    Pseudo<(outs GPR:$rd), (ins GPR:$rs1, GPR:$rs2, uimm5:$imm), []>;
+  def : Pat<(intr GPR:$rs1, GPR:$rs2, GPR:$rs3),
+            (!cast<RVInst>("CV_" # NAME # "R") GPR:$rs1, GPR:$rs2, GPR:$rs3)>;
+  def : Pat<(intr GPR:$rs1, GPR:$rs2, uimm5:$imm),
+            (!cast<RVInst>("CV_" # NAME # "_PSEUDO") GPR:$rs1, GPR:$rs2,
+            uimm5:$imm)>;
+}
+
+let Predicates = [HasVendorXCValu, IsRV32], AddedComplexity = 1 in {
+  def : PatGpr<abs, CV_ABS>;
+  def : PatGprGpr<setle, CV_SLET>;
+  def : PatGprGpr<setule, CV_SLETU>;
+  def : PatGprGpr<smin, CV_MIN>;
+  def : PatGprGpr<umin, CV_MINU>;
+  def : PatGprGpr<smax, CV_MAX>;
+  def : PatGprGpr<umax, CV_MAXU>;
+
+  def : Pat<(sext_inreg (XLenVT GPR:$rs1), i16), (CV_EXTHS GPR:$rs1)>;
+  def : Pat<(sext_inreg (XLenVT GPR:$rs1), i8), (CV_EXTBS GPR:$rs1)>;
+
+  def : Pat<(and (XLenVT GPR:$rs1), 0xffff), (CV_EXTHZ GPR:$rs1)>;
+  def : Pat<(and (XLenVT GPR:$rs1), 0xff),   (CV_EXTBZ GPR:$rs1)>;
+
+  def : Pat<(clip powerOf2Minus1:$upperBound, (XLenVT GPR:$rs1)),
+            (CV_CLIP GPR:$rs1, (trailing1sPlus1 imm:$upperBound))>;
+  def : Pat<(between (not GPR:$rs2), GPR:$rs2, (XLenVT GPR:$rs1)),
+            (CV_CLIPR GPR:$rs1, GPR:$rs2)>;
+  def : Pat<(betweenu powerOf2Minus1:$upperBound, (XLenVT GPR:$rs1)),
+            (CV_CLIPU GPR:$rs1, (trailing1sPlus1 imm:$upperBound))>;
+  def : Pat<(betweenu GPR:$rs2, (XLenVT GPR:$rs1)),
+            (CV_CLIPUR GPR:$rs1, GPR:$rs2)>;
+
+  def : Pat<(sra (add (XLenVT GPR:$rs1), (XLenVT GPR:$rs2)), uimm5:$imm5),
+            (CV_ADDN GPR:$rs1, GPR:$rs2, uimm5:$imm5)>;
+  def : Pat<(srl (add (XLenVT GPR:$rs1), (XLenVT GPR:$rs2)), uimm5:$imm5),
+            (CV_ADDUN GPR:$rs1, GPR:$rs2, uimm5:$imm5)>;
+  def : Pat<(shiftRound (add (XLenVT GPR:$rs1), (XLenVT GPR:$rs2)),
+             uimm5:$imm5),
+            (CV_ADDRN GPR:$rs1, GPR:$rs2, uimm5:$imm5)>;
+  def : Pat<(ushiftRound (add (XLenVT GPR:$rs1), (XLenVT GPR:$rs2)),
+             uimm5:$imm5),
+            (CV_ADDURN GPR:$rs1, GPR:$rs2, uimm5:$imm5)>;
+
+  def : Pat<(sra (sub (XLenVT GPR:$rs1), (XLenVT GPR:$rs2)), uimm5:$imm5),
+            (CV_SUBN GPR:$rs1, GPR:$rs2, uimm5:$imm5)>;
+  def : Pat<(srl (sub (XLenVT GPR:$rs1), (XLenVT GPR:$rs2)), uimm5:$imm5),
+            (CV_SUBUN GPR:$rs1, GPR:$rs2, uimm5:$imm5)>;
+  def : Pat<(shiftRound (sub (XLenVT GPR:$rs1), (XLenVT GPR:$rs2)),
+             uimm5:$imm5),
+            (CV_SUBRN GPR:$rs1, GPR:$rs2, uimm5:$imm5)>;
+  def : Pat<(ushiftRound (sub (XLenVT GPR:$rs1), (XLenVT GPR:$rs2)),
+             uimm5:$imm5),
+            (CV_SUBURN GPR:$rs1, GPR:$rs2, uimm5:$imm5)>;
+
+  def : Pat<(sra (add (XLenVT GPR:$rd), (XLenVT GPR:$rs1)), (XLenVT GPR:$rs2)),
+            (CV_ADDNR GPR:$rd, GPR:$rs1, GPR:$rs2)>;
+  def : Pat<(srl (add (XLenVT GPR:$rd), (XLenVT GPR:$rs1)), (XLenVT GPR:$rs2)),
+            (CV_ADDUNR GPR:$rd, GPR:$rs1, GPR:$rs2)>;
+  def : Pat<(sra (add (add (XLenVT GPR:$rd), (XLenVT GPR:$rs1)),
+            (roundBit (XLenVT GPR:$rs2))), (XLenVT GPR:$rs2)),
+            (CV_ADDRNR  GPR:$rd, GPR:$rs1, GPR:$rs2)>;
+  def : Pat<(srl (add (add (XLenVT GPR:$rd), (XLenVT GPR:$rs1)),
+            (roundBit (XLenVT GPR:$rs2))), (XLenVT GPR:$rs2)),
+            (CV_ADDURNR GPR:$rd, GPR:$rs1, GPR:$rs2)>;
+
+  def : Pat<(sra (sub (XLenVT GPR:$rd), (XLenVT GPR:$rs1)), (XLenVT GPR:$rs2)),
+            (CV_SUBNR GPR:$rd, GPR:$rs1, GPR:$rs2)>;
+  def : Pat<(srl (sub (XLenVT GPR:$rd), (XLenVT GPR:$rs1)), (XLenVT GPR:$rs2)),
+            (CV_SUBUNR GPR:$rd, GPR:$rs1, GPR:$rs2)>;
+  def : Pat<(sra (add (sub (XLenVT GPR:$rd), (XLenVT GPR:$rs1)),
+            (roundBit (XLenVT GPR:$rs2))), (XLenVT GPR:$rs2)),
+            (CV_SUBRNR  GPR:$rd, GPR:$rs1, GPR:$rs2)>;
+  def : Pat<(srl (add (sub (XLenVT GPR:$rd), (XLenVT GPR:$rs1)),
+            (roundBit (XLenVT GPR:$rs2))), (XLenVT GPR:$rs2)),
+            (CV_SUBURNR GPR:$rd, GPR:$rs1, GPR:$rs2)>;
+
+  def : PatCoreVAluGpr<"exths", "EXTHS">;
+  def : PatCoreVAluGpr<"exthz", "EXTHZ">;
+  def : PatCoreVAluGpr<"extbs", "EXTBS">;
+  def : PatCoreVAluGpr<"extbz", "EXTBZ">;
+
+  defm CLIP   : PatCoreVAluGprImm<int_riscv_cv_alu_clip>;
+  defm CLIPU  : PatCoreVAluGprImm<int_riscv_cv_alu_clipu>;
+  defm ADDN   : PatCoreVAluGprGprImm<int_riscv_cv_alu_addn>;
+  defm ADDUN  : PatCoreVAluGprGprImm<int_riscv_cv_alu_addun>;
+  defm ADDRN  : PatCoreVAluGprGprImm<int_riscv_cv_alu_addrn>;
+  defm ADDURN : PatCoreVAluGprGprImm<int_riscv_cv_alu_addurn>;
+  defm SUBN   : PatCoreVAluGprGprImm<int_riscv_cv_alu_subn>;
+  defm SUBUN  : PatCoreVAluGprGprImm<int_riscv_cv_alu_subun>;
+  defm SUBRN  : PatCoreVAluGprGprImm<int_riscv_cv_alu_subrn>;
+  defm SUBURN : PatCoreVAluGprGprImm<int_riscv_cv_alu_suburn>;
+} // Predicates = [HasVendorXCValu, IsRV32]
diff --git a/llvm/test/CodeGen/RISCV/xcvalu.ll b/llvm/test/CodeGen/RISCV/xcvalu.ll
new file mode 100644
index 00000000000000..3b83b32a672c09
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/xcvalu.ll
@@ -0,0 +1,583 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -O0 -mtriple=riscv32 -mattr=+m -mattr=+xcvalu -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s
+
+declare i32 @llvm.abs.i32(i32, i1)
+declare i32 @llvm.smin.i32(i32, i32)
+declare i32 @llvm.smax.i32(i32, i32)
+declare i32 @llvm.umin.i32(i32, i32)
+declare i32 @llvm.umax.i32(i32, i32)
+
+define i32 @abs(i32 %a) {
+; CHECK-LABEL: abs:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.abs a0, a0
+; CHECK-NEXT:    ret
+  %1 = call i32 @llvm.abs.i32(i32 %a, i1 false)
+  ret i32 %1
+}
+
+define i1 @slet(i32 %a, i32 %b) {
+; CHECK-LABEL: slet:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.slet a0, a0, a1
+; CHECK-NEXT:    ret
+  %1 = icmp sle i32 %a, %b
+  ret i1 %1
+}
+
+define i1 @sletu(i32 %a, i32 %b) {
+; CHECK-LABEL: sletu:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.sletu a0, a0, a1
+; CHECK-NEXT:    ret
+  %1 = icmp ule i32 %a, %b
+  ret i1 %1
+}
+
+define i32 @smin(i32 %a, i32 %b) {
+; CHECK-LABEL: smin:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.min a0, a0, a1
+; CHECK-NEXT:    ret
+  %1 = call i32 @llvm.smin.i32(i32 %a, i32 %b)
+  ret i32 %1
+}
+
+define i32 @umin(i32 %a, i32 %b) {
+; CHECK-LABEL: umin:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.minu a0, a0, a1
+; CHECK-NEXT:    ret
+  %1 = call i32 @llvm.umin.i32(i32 %a, i32 %b)
+  ret i32 %1
+}
+
+define i32 @smax(i32 %a, i32 %b) {
+; CHECK-LABEL: smax:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.max a0, a0, a1
+; CHECK-NEXT:    ret
+  %1 = call i32 @llvm.smax.i32(i32 %a, i32 %b)
+  ret i32 %1
+}
+
+define i32 @umax(i32 %a, i32 %b) {
+; CHECK-LABEL: umax:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.maxu a0, a0, a1
+; CHECK-NEXT:    ret
+  %1 = call i32 @llvm.umax.i32(i32 %a, i32 %b)
+  ret i32 %1
+}
+
+define i32 @exths(i16 %a) {
+; CHECK-LABEL: exths:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    # kill: def $x11 killed $x10
+; CHECK-NEXT:    cv.exths a0, a0
+; CHECK-NEXT:    ret
+  %1 = sext i16 %a to i32
+  ret i32 %1
+}
+
+define i32 @exthz(i16 %a) {
+; CHECK-LABEL: exthz:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    # kill: def $x11 killed $x10
+; CHECK-NEXT:    cv.exthz a0, a0
+; CHECK-NEXT:    ret
+  %1 = zext i16 %a to i32
+  ret i32 %1
+}
+
+define i32 @extbs(i8 %a) {
+; CHECK-LABEL: extbs:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    # kill: def $x11 killed $x10
+; CHECK-NEXT:    cv.extbs a0, a0
+; CHECK-NEXT:    ret
+  %1 = sext i8 %a to i32
+  ret i32 %1
+}
+
+define i32 @extbz(i8 %a) {
+; CHECK-LABEL: extbz:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    # kill: def $x11 killed $x10
+; CHECK-NEXT:    cv.extbz a0, a0
+; CHECK-NEXT:    ret
+  %1 = zext i8 %a to i32
+  ret i32 %1
+}
+
+define i32 @clip(i32 %a) {
+; CHECK-LABEL: clip:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.clip a0, a0, 7
+; CHECK-NEXT:    ret
+  %1 = call i32 @llvm.smax.i32(i32 %a, i32 -64)
+  %2 = call i32 @llvm.smin.i32(i32 %1, i32 63)
+  ret i32 %2
+}
+
+define i32 @clipr(i32 %a, i32 %b) {
+; CHECK-LABEL: clipr:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.clipr a0, a0, a1
+; CHECK-NEXT:    ret
+  %1 = xor i32 %b, -1
+  %2 = call i32 @llvm.smax.i32(i32 %a, i32 %1)
+  %3 = call i32 @llvm.smin.i32(i32 %2, i32 %b)
+  ret i32 %3
+}
+
+define i32 @clipu(i32 %a) {
+; CHECK-LABEL: clipu:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.clipu a0, a0, 5
+; CHECK-NEXT:    ret
+  %1 = call i32 @llvm.smax.i32(i32 %a, i32 0)
+  %2 = call i32 @llvm.smin.i32(i32 %1, i32 15)
+  ret i32 %2
+}
+
+define i32 @clipur(i32 %a, i32 %b) {
+; CHECK-LABEL: clipur:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.clipur a0, a0, a1
+; CHECK-NEXT:    ret
+  %1 = call i32 @llvm.smax.i32(i32 %a, i32 0)
+  %2 = call i32 @llvm.smin.i32(i32 %1, i32 %b)
+  ret i32 %2
+}
+
+define i32 @addN(i32 %a, i32 %b) {
+; CHECK-LABEL: addN:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.addn a0, a0, a1, 5
+; CHECK-NEXT:    ret
+  %1 = add i32 %a, %b
+  %2 = ashr i32 %1, 5
+  ret i32 %2
+}
+
+define i32 @adduN(i32 %a, i32 %b) {
+; CHECK-LABEL: adduN:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.addun a0, a0, a1, 5
+; CHECK-NEXT:    ret
+  %1 = add i32 %a, %b
+  %2 = lshr i32 %1, 5
+  ret i32 %2
+}
+
+define i32 @addRN(i32 %a, i32 %b) {
+; CHECK-LABEL: addRN:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.addrn a0, a0, a1, 5
+; CHECK-NEXT:    ret
+  %1 = add i32 %a, %b
+  %2 = add i32 %1, 16
+  %3 = ashr i32 %2, 5
+  ret i32 %3
+}
+
+define i32 @adduRN(i32 %a, i32 %b) {
+; CHECK-LABEL: adduRN:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.addurn a0, a0, a1, 5
+; CHECK-NEXT:    ret
+  %1 = add i32 %a, %b
+  %2 = add i32 %1, 16
+  %3 = lshr i32 %2, 5
+  ret i32 %3
+}
+
+define i32 @addNr(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: addNr:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.addnr a0, a1, a2
+; CHECK-NEXT:    ret
+  %1 = add i32 %a, %b
+  %2 = ashr i32 %1, %c
+  ret i32 %2
+}
+
+define i32 @adduNr(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: adduNr:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.addunr a0, a1, a2
+; CHECK-NEXT:    ret
+  %1 = add i32 %a, %b
+  %2 = lshr i32 %1, %c
+  ret i32 %2
+}
+
+define i32 @addRNr(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: addRNr:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.addrnr a0, a1, a2
+; CHECK-NEXT:    ret
+  %1 = add i32 %a, %b
+  %2 = shl i32 1, %c
+  %3 = lshr i32 %2, 1
+  %4 = add i32 %1, %3
+  %5 = ashr i32 %4, %c
+  ret i32 %5
+}
+
+define i32 @adduRNr(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: adduRNr:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.addurnr a0, a1, a2
+; CHECK-NEXT:    ret
+  %1 = add i32 %a, %b
+  %2 = shl i32 1, %c
+  %3 = lshr i32 %2, 1
+  %4 = add i32 %1, %3
+  %5 = lshr i32 %4, %c
+  ret i32 %5
+}
+
+define i32 @subN(i32 %a, i32 %b) {
+; CHECK-LABEL: subN:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.subn a0, a0, a1, 5
+; CHECK-NEXT:    ret
+  %1 = sub i32 %a, %b
+  %2 = ashr i32 %1, 5
+  ret i32 %2
+}
+
+define i32 @subuN(i32 %a, i32 %b) {
+; CHECK-LABEL: subuN:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.subun a0, a0, a1, 5
+; CHECK-NEXT:    ret
+  %1 = sub i32 %a, %b
+  %2 = lshr i32 %1, 5
+  ret i32 %2
+}
+
+define i32 @subRN(i32 %a, i32 %b) {
+; CHECK-LABEL: subRN:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.subrn a0, a0, a1, 5
+; CHECK-NEXT:    ret
+  %1 = sub i32 %a, %b
+  %2 = add i32 %1, 16
+  %3 = ashr i32 %2, 5
+  ret i32 %3
+}
+
+define i32 @subuRN(i32 %a, i32 %b) {
+; CHECK-LABEL: subuRN:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.suburn a0, a0, a1, 5
+; CHECK-NEXT:    ret
+  %1 = sub i32 %a, %b
+  %2 = add i32 %1, 16
+  %3 = lshr i32 %2, 5
+  ret i32 %3
+}
+
+define i32 @subNr(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: subNr:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.subnr a0, a1, a2
+; CHECK-NEXT:    ret
+  %1 = sub i32 %a, %b
+  %2 = ashr i32 %1, %c
+  ret i32 %2
+}
+
+define i32 @subuNr(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: subuNr:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.subunr a0, a1, a2
+; CHECK-NEXT:    ret
+  %1 = sub i32 %a, %b
+  %2 = lshr i32 %1, %c
+  ret i32 %2
+}
+
+define i32 @subRNr(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: subRNr:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.subrnr a0, a1, a2
+; CHECK-NEXT:    ret
+  %1 = sub i32 %a, %b
+  %2 = shl i32 1, %c
+  %3 = lshr i32 %2, 1
+  %4 = add i32 %1, %3
+  %5 = ashr i32 %4, %c
+  ret i32 %5
+}
+
+define i32 @subuRNr(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: subuRNr:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.suburnr a0, a1, a2
+; CHECK-NEXT:    ret
+  %1 = sub i32 %a, %b
+  %2 = shl i32 1, %c
+  %3 = lshr i32 %2, 1
+  %4 = add i32 %1, %3
+  %5 = lshr i32 %4, %c
+  ret i32 %5
+}
+
+declare i32 @llvm.riscv.cv.alu.exths(i32)
+
+define i32 @test.cv.alu.exths(i32 %a) {
+; CHECK-LABEL: test.cv.alu.exths:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.exths a0, a0
+; CHECK-NEXT:    ret
+  %1 = call i32 @llvm.riscv.cv.alu.exths(i32 %a)
+  ret i32 %1
+}
+
+declare i32 @llvm.riscv.cv.alu.exthz(i32)
+
+define i32 @test.cv.alu.exthz(i32 %a) {
+; CHECK-LABEL: test.cv.alu.exthz:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.exthz a0, a0
+; CHECK-NEXT:    ret
+  %1 = call i32 @llvm.riscv.cv.alu.exthz(i32 %a)
+  ret i32 %1
+}
+
+declare i32 @llvm.riscv.cv.alu.extbs(i32)
+
+define i32 @test.cv.alu.extbs(i32 %a) {
+; CHECK-LABEL: test.cv.alu.extbs:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.extbs a0, a0
+; CHECK-NEXT:    ret
+  %1 = call i32 @llvm.riscv.cv.alu.extbs(i32 %a)
+  ret i32 %1
+}
+
+declare i32 @llvm.riscv.cv.alu.extbz(i32)
+
+define i32 @test.cv.alu.extbz(i32 %a) {
+; CHECK-LABEL: test.cv.alu.extbz:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.extbz a0, a0
+; CHECK-NEXT:    ret
+  %1 = call i32 @llvm.riscv.cv.alu.extbz(i32 %a)
+  ret i32 %1
+}
+
+declare i32 @llvm.riscv.cv.alu.clip(i32, i32)
+
+define i32 @test.cv.alu.clip.case.a(i32 %a) {
+; CHECK-LABEL: test.cv.alu.clip.case.a:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.clip a0, a0, 5
+; CHECK-NEXT:    ret
+  %1 = call i32 @llvm.riscv.cv.alu.clip(i32 %a, i32 15)
+  ret i32 %1
+}
+
+define i32 @test.cv.alu.clip.case.b(i32 %a) {
+; CHECK-LABEL: test.cv.alu.clip.case.b:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a1, 10
+; CHECK-NEXT:    cv.clipr a0, a0, a1
+; CHECK-NEXT:    ret
+  %1 = call i32 @llvm.riscv.cv.alu.clip(i32 %a, i32 10)
+  ret i32 %1
+}
+
+declare i32 @llvm.riscv.cv.alu.clipu(i32, i32)
+
+define i32 @test.cv.alu.clipu.case.a(i32 %a) {
+; CHECK-LABEL: test.cv.alu.clipu.case.a:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.clipu a0, a0, 9
+; CHECK-NEXT:    ret
+  %1 = call i32 @llvm.riscv.cv.alu.clipu(i32 %a, i32 255)
+  ret i32 %1
+}
+
+define i32 @test.cv.alu.clipu.case.b(i32 %a) {
+; CHECK-LABEL: test.cv.alu.clipu.case.b:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a1, 200
+; CHECK-NEXT:    cv.clipur a0, a0, a1
+; CHECK-NEXT:    ret
+  %1 = call i32 @llvm.riscv.cv.alu.clipu(i32 %a, i32 200)
+  ret i32 %1
+}
+
+declare i32 @llvm.riscv.cv.alu.addn(i32, i32, i32)
+
+define i32 @test.cv.alu.addn.case.a(i32 %a, i32 %b) {
+; CHECK-LABEL: test.cv.alu.addn.case.a:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.addn a0, a0, a1, 15
+; CHECK-NEXT:    ret
+  %1 = call i32 @llvm.riscv.cv.alu.addn(i32 %a, i32 %b, i32 15)
+  ret i32 %1
+}
+
+define i32 @test.cv.alu.addn.case.b(i32 %a, i32 %b) {
+; CHECK-LABEL: test.cv.alu.addn.case.b:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a2, 32
+; CHECK-NEXT:    cv.addnr a0, a1, a2
+; CHECK-NEXT:    ret
+  %1 = call i32 @llvm.riscv.cv.alu.addn(i32 %a, i32 %b, i32 32)
+  ret i32 %1
+}
+
+declare i32 @llvm.riscv.cv.alu.addun(i32, i32, i32)
+
+define i32 @test.cv.alu.addun.case.a(i32 %a, i32 %b) {
+; CHECK-LABEL: test.cv.alu.addun.case.a:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.addun a0, a0, a1, 15
+; CHECK-NEXT:    ret
+  %1 = call i32 @llvm.riscv.cv.alu.addun(i32 %a, i32 %b, i32 15)
+  ret i32 %1
+}
+
+define i32 @test.cv.alu.addun.case.b(i32 %a, i32 %b) {
+; CHECK-LABEL: test.cv.alu.addun.case.b:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a2, 32
+; CHECK-NEXT:    cv.addunr a0, a1, a2
+; CHECK-NEXT:    ret
+  %1 = call i32 @llvm.riscv.cv.alu.addun(i32 %a, i32 %b, i32 32)
+  ret i32 %1
+}
+
+declare i32 @llvm.riscv.cv.alu.addrn(i32, i32, i32)
+
+define i32 @test.cv.alu.addrn.case.a(i32 %a, i32 %b) {
+; CHECK-LABEL: test.cv.alu.addrn.case.a:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.addrn a0, a0, a1, 15
+; CHECK-NEXT:    ret
+  %1 = call i32 @llvm.riscv.cv.alu.addrn(i32 %a, i32 %b, i32 15)
+  ret i32 %1
+}
+
+define i32 @test.cv.alu.addrn.case.b(i32 %a, i32 %b) {
+; CHECK-LABEL: test.cv.alu.addrn.case.b:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a2, 32
+; CHECK-NEXT:    cv.addrnr a0, a1, a2
+; CHECK-NEXT:    ret
+  %1 = call i32 @llvm.riscv.cv.alu.addrn(i32 %a, i32 %b, i32 32)
+  ret i32 %1
+}
+
+declare i32 @llvm.riscv.cv.alu.addurn(i32, i32, i32)
+
+define i32 @test.cv.alu.addurn.case.a(i32 %a, i32 %b) {
+; CHECK-LABEL: test.cv.alu.addurn.case.a:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.addurn a0, a0, a1, 15
+; CHECK-NEXT:    ret
+  %1 = call i32 @llvm.riscv.cv.alu.addurn(i32 %a, i32 %b, i32 15)
+  ret i32 %1
+}
+
+define i32 @test.cv.alu.addurn.case.b(i32 %a, i32 %b) {
+; CHECK-LABEL: test.cv.alu.addurn.case.b:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a2, 32
+; CHECK-NEXT:    cv.addurnr a0, a1, a2
+; CHECK-NEXT:    ret
+  %1 = call i32 @llvm.riscv.cv.alu.addurn(i32 %a, i32 %b, i32 32)
+  ret i32 %1
+}
+
+declare i32 @llvm.riscv.cv.alu.subn(i32, i32, i32)
+
+define i32 @test.cv.alu.subn.case.a(i32 %a, i32 %b) {
+; CHECK-LABEL: test.cv.alu.subn.case.a:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.subn a0, a0, a1, 15
+; CHECK-NEXT:    ret
+  %1 = call i32 @llvm.riscv.cv.alu.subn(i32 %a, i32 %b, i32 15)
+  ret i32 %1
+}
+
+define i32 @test.cv.alu.subn.case.b(i32 %a, i32 %b) {
+; CHECK-LABEL: test.cv.alu.subn.case.b:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a2, 32
+; CHECK-NEXT:    cv.subnr a0, a1, a2
+; CHECK-NEXT:    ret
+  %1 = call i32 @llvm.riscv.cv.alu.subn(i32 %a, i32 %b, i32 32)
+  ret i32 %1
+}
+
+declare i32 @llvm.riscv.cv.alu.subun(i32, i32, i32)
+
+define i32 @test.cv.alu.subun.case.a(i32 %a, i32 %b) {
+; CHECK-LABEL: test.cv.alu.subun.case.a:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.subun a0, a0, a1, 15
+; CHECK-NEXT:    ret
+  %1 = call i32 @llvm.riscv.cv.alu.subun(i32 %a, i32 %b, i32 15)
+  ret i32 %1
+}
+
+define i32 @test.cv.alu.subun.case.b(i32 %a, i32 %b) {
+; CHECK-LABEL: test.cv.alu.subun.case.b:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a2, 32
+; CHECK-NEXT:    cv.subunr a0, a1, a2
+; CHECK-NEXT:    ret
+  %1 = call i32 @llvm.riscv.cv.alu.subun(i32 %a, i32 %b, i32 32)
+  ret i32 %1
+}
+
+declare i32 @llvm.riscv.cv.alu.subrn(i32, i32, i32)
+
+define i32 @test.cv.alu.subrn.case.a(i32 %a, i32 %b) {
+; CHECK-LABEL: test.cv.alu.subrn.case.a:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.subrn a0, a0, a1, 15
+; CHECK-NEXT:    ret
+  %1 = call i32 @llvm.riscv.cv.alu.subrn(i32 %a, i32 %b, i32 15)
+  ret i32 %1
+}
+
+define i32 @test.cv.alu.subrn.case.b(i32 %a, i32 %b) {
+; CHECK-LABEL: test.cv.alu.subrn.case.b:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a2, 32
+; CHECK-NEXT:    cv.subrnr a0, a1, a2
+; CHECK-NEXT:    ret
+  %1 = call i32 @llvm.riscv.cv.alu.subrn(i32 %a, i32 %b, i32 32)
+  ret i32 %1
+}
+
+declare i32 @llvm.riscv.cv.alu.suburn(i32, i32, i32)
+
+define i32 @test.cv.alu.suburn.case.a(i32 %a, i32 %b) {
+; CHECK-LABEL: test.cv.alu.suburn.case.a:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cv.suburn a0, a0, a1, 15
+; CHECK-NEXT:    ret
+  %1 = call i32 @llvm.riscv.cv.alu.suburn(i32 %a, i32 %b, i32 15)
+  ret i32 %1
+}
+
+define i32 @test.cv.alu.suburn.case.b(i32 %a, i32 %b) {
+; CHECK-LABEL: test.cv.alu.suburn.case.b:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a2, 32
+; CHECK-NEXT:    cv.suburnr a0, a1, a2
+; CHECK-NEXT:    ret
+  %1 = call i32 @llvm.riscv.cv.alu.suburn(i32 %a, i32 %b, i32 32)
+  ret i32 %1
+}



More information about the llvm-commits mailing list