[llvm] [RISCV][XCV] Add LLVM intrinsics for non-representable XCVsimd ops (PR #204880)
Luke Lau via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 25 08:51:11 PDT 2026
================
@@ -0,0 +1,486 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -mattr=+m,+xcvsimd -verify-machineinstrs < %s \
+; RUN: | FileCheck %s
+
+; This file tests that all XCVsimd LLVM IR intrinsics are correctly lowered
+; to their corresponding CV32E40P machine instructions.
+
+;===----------------------------------------------------------------------===;
+; ADD / SUB
+;===----------------------------------------------------------------------===;
+
+;===----------------------------------------------------------------------===;
+; AVG / AVGU
+;===----------------------------------------------------------------------===;
+
+;===----------------------------------------------------------------------===;
+; MIN / MINU / MAX / MAXU (representative: _h and _sc_b for each)
+;===----------------------------------------------------------------------===;
+
+;===----------------------------------------------------------------------===;
+; SRL / SRA / SLL
+;===----------------------------------------------------------------------===;
+
+;===----------------------------------------------------------------------===;
+; OR / XOR / AND
+;===----------------------------------------------------------------------===;
+
+;===----------------------------------------------------------------------===;
+; ABS
+;===----------------------------------------------------------------------===;
+
+;===----------------------------------------------------------------------===;
+; DOT PRODUCTS (non-accumulating)
+;===----------------------------------------------------------------------===;
+
+define i32 @test_cv_simd_dotup_h(i32 %a, i32 %b) {
+; CHECK-LABEL: test_cv_simd_dotup_h:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.dotup.h a0, a0, a1
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.dotup.h(i32 %a, i32 %b)
+ ret i32 %res
+}
+
+define i32 @test_cv_simd_dotup_b(i32 %a, i32 %b) {
+; CHECK-LABEL: test_cv_simd_dotup_b:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.dotup.b a0, a0, a1
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.dotup.b(i32 %a, i32 %b)
+ ret i32 %res
+}
+
+define i32 @test_cv_simd_dotup_sc_h(i32 %a, i32 %b) {
+; CHECK-LABEL: test_cv_simd_dotup_sc_h:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.dotup.sc.h a0, a0, a1
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.dotup.sc.h(i32 %a, i32 %b)
+ ret i32 %res
+}
+
+define i32 @test_cv_simd_dotup_sc_b(i32 %a, i32 %b) {
+; CHECK-LABEL: test_cv_simd_dotup_sc_b:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.dotup.sc.b a0, a0, a1
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.dotup.sc.b(i32 %a, i32 %b)
+ ret i32 %res
+}
+
+define i32 @test_cv_simd_dotusp_h(i32 %a, i32 %b) {
+; CHECK-LABEL: test_cv_simd_dotusp_h:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.dotusp.h a0, a0, a1
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.dotusp.h(i32 %a, i32 %b)
+ ret i32 %res
+}
+
+define i32 @test_cv_simd_dotsp_h(i32 %a, i32 %b) {
+; CHECK-LABEL: test_cv_simd_dotsp_h:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.dotsp.h a0, a0, a1
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.dotsp.h(i32 %a, i32 %b)
+ ret i32 %res
+}
+
+;===----------------------------------------------------------------------===;
+; SDOT (accumulating dot products)
+;===----------------------------------------------------------------------===;
+
+define i32 @test_cv_simd_sdotup_h(i32 %a, i32 %b, i32 %acc) {
+; CHECK-LABEL: test_cv_simd_sdotup_h:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.sdotup.h a2, a0, a1
+; CHECK-NEXT: mv a0, a2
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.sdotup.h(i32 %a, i32 %b, i32 %acc)
+ ret i32 %res
+}
+
+define i32 @test_cv_simd_sdotup_b(i32 %a, i32 %b, i32 %acc) {
+; CHECK-LABEL: test_cv_simd_sdotup_b:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.sdotup.b a2, a0, a1
+; CHECK-NEXT: mv a0, a2
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.sdotup.b(i32 %a, i32 %b, i32 %acc)
+ ret i32 %res
+}
+
+define i32 @test_cv_simd_sdotusp_h(i32 %a, i32 %b, i32 %acc) {
+; CHECK-LABEL: test_cv_simd_sdotusp_h:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.sdotusp.h a2, a0, a1
+; CHECK-NEXT: mv a0, a2
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.sdotusp.h(i32 %a, i32 %b, i32 %acc)
+ ret i32 %res
+}
+
+define i32 @test_cv_simd_sdotsp_h(i32 %a, i32 %b, i32 %acc) {
+; CHECK-LABEL: test_cv_simd_sdotsp_h:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.sdotsp.h a2, a0, a1
+; CHECK-NEXT: mv a0, a2
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.sdotsp.h(i32 %a, i32 %b, i32 %acc)
+ ret i32 %res
+}
+
+;===----------------------------------------------------------------------===;
+; EXTRACT / EXTRACTU / INSERT
+;===----------------------------------------------------------------------===;
+
+define i32 @test_cv_simd_extract_h(i32 %a) {
+; CHECK-LABEL: test_cv_simd_extract_h:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.extract.h a0, a0, 1
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.extract.h(i32 %a, i32 1)
+ ret i32 %res
+}
+
+define i32 @test_cv_simd_extract_b(i32 %a) {
+; CHECK-LABEL: test_cv_simd_extract_b:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.extract.b a0, a0, 3
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.extract.b(i32 %a, i32 3)
+ ret i32 %res
+}
+
+define i32 @test_cv_simd_extractu_h(i32 %a) {
+; CHECK-LABEL: test_cv_simd_extractu_h:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.extractu.h a0, a0, 0
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.extractu.h(i32 %a, i32 0)
+ ret i32 %res
+}
+
+define i32 @test_cv_simd_extractu_b(i32 %a) {
+; CHECK-LABEL: test_cv_simd_extractu_b:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.extractu.b a0, a0, 2
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.extractu.b(i32 %a, i32 2)
+ ret i32 %res
+}
+
+define i32 @test_cv_simd_insert_h(i32 %rd, i32 %rs1) {
+; CHECK-LABEL: test_cv_simd_insert_h:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.insert.h a0, a1, 1
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.insert.h(i32 %rd, i32 %rs1, i32 1)
+ ret i32 %res
+}
+
+define i32 @test_cv_simd_insert_b(i32 %rd, i32 %rs1) {
+; CHECK-LABEL: test_cv_simd_insert_b:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.insert.b a0, a1, 2
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.insert.b(i32 %rd, i32 %rs1, i32 2)
+ ret i32 %res
+}
+
+;===----------------------------------------------------------------------===;
+; SHUFFLE / SHUFFLE2
+;===----------------------------------------------------------------------===;
+
+define i32 @test_cv_simd_shuffle_h(i32 %a, i32 %b) {
+; CHECK-LABEL: test_cv_simd_shuffle_h:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.shuffle.h a0, a0, a1
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.shuffle.h(i32 %a, i32 %b)
+ ret i32 %res
+}
+
+define i32 @test_cv_simd_shuffle_b(i32 %a, i32 %b) {
+; CHECK-LABEL: test_cv_simd_shuffle_b:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.shuffle.b a0, a0, a1
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.shuffle.b(i32 %a, i32 %b)
+ ret i32 %res
+}
+
+define i32 @test_cv_simd_shuffle_sci_h(i32 %a) {
+; CHECK-LABEL: test_cv_simd_shuffle_sci_h:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.shuffle.sci.h a0, a0, 2
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.shuffle.sci.h(i32 %a, i32 2)
+ ret i32 %res
+}
+
+; Test shuffle_sci_b pseudo expansion: imm=0x45 → bits[7:6]=1 → shufflei1
+define i32 @test_cv_simd_shuffle_sci_b_i1(i32 %a) {
+; CHECK-LABEL: test_cv_simd_shuffle_sci_b_i1:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.shufflei1.sci.b a0, a0, 5
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.shuffle.sci.b(i32 %a, i32 69)
+ ret i32 %res
+}
+
+; Test shuffle_sci_b pseudo expansion: imm=0x03 → bits[7:6]=0 → shufflei0
+define i32 @test_cv_simd_shuffle_sci_b_i0(i32 %a) {
+; CHECK-LABEL: test_cv_simd_shuffle_sci_b_i0:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.shufflei0.sci.b a0, a0, 3
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.shuffle.sci.b(i32 %a, i32 3)
+ ret i32 %res
+}
+
+; Test shuffle_sci_b pseudo expansion: imm=0x83 → bits[7:6]=2 → shufflei2
+define i32 @test_cv_simd_shuffle_sci_b_i2(i32 %a) {
+; CHECK-LABEL: test_cv_simd_shuffle_sci_b_i2:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.shufflei2.sci.b a0, a0, 3
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.shuffle.sci.b(i32 %a, i32 131)
+ ret i32 %res
+}
+
+; Test shuffle_sci_b pseudo expansion: imm=0xC0 → bits[7:6]=3 → shufflei3
+define i32 @test_cv_simd_shuffle_sci_b_i3(i32 %a) {
+; CHECK-LABEL: test_cv_simd_shuffle_sci_b_i3:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.shufflei3.sci.b a0, a0, 0
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.shuffle.sci.b(i32 %a, i32 192)
+ ret i32 %res
+}
+
+define i32 @test_cv_simd_shuffle2_h(i32 %rd, i32 %rs1, i32 %rs2) {
+; CHECK-LABEL: test_cv_simd_shuffle2_h:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.shuffle2.h a0, a1, a2
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.shuffle2.h(i32 %rs1, i32 %rs2, i32 %rd)
+ ret i32 %res
+}
+
+define i32 @test_cv_simd_shuffle2_b(i32 %rd, i32 %rs1, i32 %rs2) {
+; CHECK-LABEL: test_cv_simd_shuffle2_b:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.shuffle2.b a0, a1, a2
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.shuffle2.b(i32 %rs1, i32 %rs2, i32 %rd)
+ ret i32 %res
+}
+
+;===----------------------------------------------------------------------===;
+; PACK
+;===----------------------------------------------------------------------===;
+
+define i32 @test_cv_simd_packlo_h(i32 %a, i32 %b) {
+; CHECK-LABEL: test_cv_simd_packlo_h:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.pack a0, a0, a1
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.packlo.h(i32 %a, i32 %b)
+ ret i32 %res
+}
+
+define i32 @test_cv_simd_packhi_h(i32 %a, i32 %b) {
+; CHECK-LABEL: test_cv_simd_packhi_h:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.pack.h a0, a0, a1
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.packhi.h(i32 %a, i32 %b)
+ ret i32 %res
+}
+
+define i32 @test_cv_simd_packhi_b(i32 %rd, i32 %rs1, i32 %rs2) {
+; CHECK-LABEL: test_cv_simd_packhi_b:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.packhi.b a0, a1, a2
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.packhi.b(i32 %rd, i32 %rs1, i32 %rs2)
+ ret i32 %res
+}
+
+define i32 @test_cv_simd_packlo_b(i32 %rd, i32 %rs1, i32 %rs2) {
+; CHECK-LABEL: test_cv_simd_packlo_b:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.packlo.b a0, a1, a2
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.packlo.b(i32 %rd, i32 %rs1, i32 %rs2)
+ ret i32 %res
+}
+
+;===----------------------------------------------------------------------===;
+; COMPARE (representative subset)
+;===----------------------------------------------------------------------===;
+
+;===----------------------------------------------------------------------===;
+; COMPLEX: cplxmul / cplxconj / subrotmj
+;===----------------------------------------------------------------------===;
+
+define i32 @test_cv_simd_cplxmul_r(i32 %rs1, i32 %rs2, i32 %rd) {
+; CHECK-LABEL: test_cv_simd_cplxmul_r:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.cplxmul.r a2, a0, a1
+; CHECK-NEXT: mv a0, a2
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.cplxmul.r(i32 %rs1, i32 %rs2, i32 %rd, i32 0)
+ ret i32 %res
+}
+
+define i32 @test_cv_simd_cplxmul_r_div2(i32 %rs1, i32 %rs2, i32 %rd) {
+; CHECK-LABEL: test_cv_simd_cplxmul_r_div2:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.cplxmul.r.div2 a2, a0, a1
+; CHECK-NEXT: mv a0, a2
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.cplxmul.r(i32 %rs1, i32 %rs2, i32 %rd, i32 1)
+ ret i32 %res
+}
+
+define i32 @test_cv_simd_cplxmul_i(i32 %rs1, i32 %rs2, i32 %rd) {
+; CHECK-LABEL: test_cv_simd_cplxmul_i:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.cplxmul.i a2, a0, a1
+; CHECK-NEXT: mv a0, a2
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.cplxmul.i(i32 %rs1, i32 %rs2, i32 %rd, i32 0)
+ ret i32 %res
+}
+
+define i32 @test_cv_simd_cplxmul_i_div4(i32 %rs1, i32 %rs2, i32 %rd) {
+; CHECK-LABEL: test_cv_simd_cplxmul_i_div4:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.cplxmul.i.div4 a2, a0, a1
+; CHECK-NEXT: mv a0, a2
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.cplxmul.i(i32 %rs1, i32 %rs2, i32 %rd, i32 2)
+ ret i32 %res
+}
+
+define i32 @test_cv_simd_cplxconj(i32 %a) {
+; CHECK-LABEL: test_cv_simd_cplxconj:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.cplxconj a0, a0
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.cplxconj(i32 %a)
+ ret i32 %res
+}
+
+define i32 @test_cv_simd_subrotmj(i32 %a, i32 %b) {
+; CHECK-LABEL: test_cv_simd_subrotmj:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.subrotmj a0, a0, a1
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.subrotmj(i32 %a, i32 %b, i32 0)
+ ret i32 %res
+}
+
+define i32 @test_cv_simd_subrotmj_div2(i32 %a, i32 %b) {
+; CHECK-LABEL: test_cv_simd_subrotmj_div2:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.subrotmj.div2 a0, a0, a1
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.subrotmj(i32 %a, i32 %b, i32 1)
+ ret i32 %res
+}
+
+define i32 @test_cv_simd_subrotmj_div4(i32 %a, i32 %b) {
+; CHECK-LABEL: test_cv_simd_subrotmj_div4:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.subrotmj.div4 a0, a0, a1
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.subrotmj(i32 %a, i32 %b, i32 2)
+ ret i32 %res
+}
+
+define i32 @test_cv_simd_subrotmj_div8(i32 %a, i32 %b) {
+; CHECK-LABEL: test_cv_simd_subrotmj_div8:
+; CHECK: # %bb.0:
+; CHECK-NEXT: cv.subrotmj.div8 a0, a0, a1
+; CHECK-NEXT: ret
+ %res = call i32 @llvm.riscv.cv.simd.subrotmj(i32 %a, i32 %b, i32 3)
+ ret i32 %res
+}
+
+;===----------------------------------------------------------------------===;
+; Intrinsic declarations
+;===----------------------------------------------------------------------===;
+
+; ADD/SUB
+
+; AVG/AVGU
+
+; MIN/MINU/MAX/MAXU
+
+; SRL/SRA/SLL
+
+; OR/XOR/AND
+
+; ABS
+
+; DOT (non-accumulating)
+declare i32 @llvm.riscv.cv.simd.dotup.h(i32, i32)
----------------
lukel97 wrote:
You don't need to declare intriniscs anymore these days so you can remove these lines
https://github.com/llvm/llvm-project/pull/204880
More information about the llvm-commits
mailing list