[llvm] [RISCV] Implement Intrinsics Support for XCValu Extension in CV32E40P (PR #85603)
via llvm-commits
llvm-commits at lists.llvm.org
Thu May 23 23:44:19 PDT 2024
https://github.com/realqhc updated https://github.com/llvm/llvm-project/pull/85603
>From 5f2ee82fc6ac6e78f05562a49077db04afa0fe54 Mon Sep 17 00:00:00 2001
From: Qihan Cai <caiqihan021 at hotmail.com>
Date: Tue, 27 Feb 2024 16:47:58 +0800
Subject: [PATCH 1/3] [RISCV] Implement Intrinsics 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 | 23 +++
llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 16 +-
llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td | 101 +++++++++-
llvm/test/CodeGen/RISCV/xcvalu.ll | 213 ++++++++++++++++++++
4 files changed, 347 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 f1590ad66e362..8b4f4966fbd9a 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,15 @@ 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_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/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 19ef1f2f18ec1..b58891c16abe0 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);
@@ -1400,6 +1402,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 924e91e15c348..f300aedad5b3d 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_uimm_pow2: 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,51 @@ 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 : PatGprGpr<intr, !cast<RVInst>("CV_" # NAME # "R")>;
+ def : Pat<(intr (XLenVT GPR:$rs1), powerOf2Minus1:$upperBound),
+ (!cast<RVInst>("CV_" # NAME) GPR:$rs1,
+ (trailing1sPlus1 imm:$upperBound))>;
+}
+
+multiclass PatCoreVAluGprGprImm <Intrinsic intr> {
+ 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) 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)>;
+
+ 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 0000000000000..b80682a9793a1
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/xcvalu.ll
@@ -0,0 +1,213 @@
+; 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.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
+}
>From 597190a06cda49ee3ba1de598bf344a2001665f4 Mon Sep 17 00:00:00 2001
From: QIHAN CAI <qcai8733 at uni.sydney.edu.au>
Date: Mon, 15 Apr 2024 16:52:00 +0100
Subject: [PATCH 2/3] address comments
---
llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td | 44 ++--------------------
1 file changed, 3 insertions(+), 41 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td
index f300aedad5b3d..5560047201bf3 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td
@@ -675,49 +675,15 @@ 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),
@@ -750,21 +716,21 @@ let Predicates = [HasVendorXCVbitmanip, IsRV32] in {
def : Pat<(bitreverse (XLenVT GPR:$rs)), (CV_BITREV GPR:$rs, 0, 0)>;
}
-class PatCoreVAluGpr <string intr, string asm> :
+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> {
+multiclass PatCoreVAluGprImm<Intrinsic intr> {
def : PatGprGpr<intr, !cast<RVInst>("CV_" # NAME # "R")>;
def : Pat<(intr (XLenVT GPR:$rs1), powerOf2Minus1:$upperBound),
(!cast<RVInst>("CV_" # NAME) GPR:$rs1,
(trailing1sPlus1 imm:$upperBound))>;
}
-multiclass PatCoreVAluGprGprImm <Intrinsic intr> {
+multiclass PatCoreVAluGprGprImm<Intrinsic intr> {
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),
@@ -772,7 +738,6 @@ multiclass PatCoreVAluGprGprImm <Intrinsic intr> {
}
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>;
@@ -783,9 +748,6 @@ let Predicates = [HasVendorXCValu, IsRV32], AddedComplexity = 1 in {
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)>;
-
defm CLIP : PatCoreVAluGprImm<int_riscv_cv_alu_clip>;
defm CLIPU : PatCoreVAluGprImm<int_riscv_cv_alu_clipu>;
defm ADDN : PatCoreVAluGprGprImm<int_riscv_cv_alu_addn>;
>From 37f9c41063f9803d48901259896593cfc0e7f68d Mon Sep 17 00:00:00 2001
From: Qihan Cai <caiqihan021 at hotmail.com>
Date: Fri, 19 Apr 2024 09:25:59 +0800
Subject: [PATCH 3/3] add back incorrectly removed intrinsics and add tests for
them.
---
llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td | 2 +
llvm/test/CodeGen/RISCV/xcvalu.ll | 89 ++++++++++++++++++++++
2 files changed, 91 insertions(+)
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td
index 5560047201bf3..ffbb81c5bb882 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td
@@ -738,6 +738,7 @@ multiclass PatCoreVAluGprGprImm<Intrinsic intr> {
}
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>;
@@ -747,6 +748,7 @@ let Predicates = [HasVendorXCValu, IsRV32], AddedComplexity = 1 in {
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)>;
defm CLIP : PatCoreVAluGprImm<int_riscv_cv_alu_clip>;
defm CLIPU : PatCoreVAluGprImm<int_riscv_cv_alu_clipu>;
diff --git a/llvm/test/CodeGen/RISCV/xcvalu.ll b/llvm/test/CodeGen/RISCV/xcvalu.ll
index b80682a9793a1..b1031731d06fa 100644
--- a/llvm/test/CodeGen/RISCV/xcvalu.ll
+++ b/llvm/test/CodeGen/RISCV/xcvalu.ll
@@ -2,6 +2,95 @@
; 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
+}
+
declare i32 @llvm.riscv.cv.alu.clip(i32, i32)
define i32 @test.cv.alu.clip.case.a(i32 %a) {
More information about the llvm-commits
mailing list