[clang] [llvm] [RISCV] Add Clang builtins for XCVbitmanip (PR #202564)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Jun 9 03:10:17 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-codegen
@llvm/pr-subscribers-backend-risc-v
Author: Moritz Scherer (Scheremo)
<details>
<summary>Changes</summary>
First time adding ISA extension support in the frontend; please let me know if I made any mistakes or there is anything to improve.
Clang did not expose builtins for the CORE-V XCVbitmanip extension, so C code could not directly use the existing backend support for cv.extract, cv.extractu, cv.insert, cv.bclr, cv.bset, cv.ff1, cv.fl1, cv.clb, cv.cnt, cv.ror, and cv.bitrev. [An overview of the ISA extension can be found here](https://docs.openhwgroup.org/projects/cv32e40p-user-manual/en/latest/instruction_set_extensions.html#bit-manipulation-operations).
Add the XCVbitmanip builtin definitions and lower them in Clang CodeGen. The operations that match generic LLVM bit operations are lowered to those forms: ff1 to cttz, cnt to ctpop, and ror to fshr. The remaining operations lower to llvm.riscv.cv.bitmanip intrinsics. Add a dedicated llvm.riscv.cv.bitmanip.fl1 intrinsic because cv.fl1 returns the index of the most significant set bit, not the leading-zero count returned by llvm.ctlz.
Add Sema checking for:
- requiring the xcvbitmanip extension for all XCVbitmanip builtins
- cv.bitrev's constant immediate operands
- cv.bitrev's valid immediate ranges
CIR codegen now recognizes the new builtins and keeps them on the existing NYI path for unsupported RISC-V target builtins.
Add coverage for:
- LLVM IR lowering of all XCVbitmanip builtins
- immediate and register operand forms for extract/extractu/insert/bclr/bset
- generic intrinsic lowering for ff1/cnt/ror
- dedicated target intrinsic lowering for fl1
- cv.bitrev immediate range diagnostics
- cv.bitrev constant-operand diagnostics
- missing-extension diagnostics for every XCVbitmanip builtin
- LLVM CodeGen lowering of llvm.riscv.cv.bitmanip.fl1 to cv.fl1
Tested with:
llvm-lit -sv \
clang/test/CodeGen/RISCV/riscv-xcvbitmanip.c \
clang/test/Sema/riscv-xcvbitmanip-builtins.c \
llvm/test/CodeGen/RISCV/xcvbitmanip.ll
---
Full diff: https://github.com/llvm/llvm-project/pull/202564.diff
9 Files Affected:
- (modified) clang/include/clang/Basic/BuiltinsRISCVXCV.td (+15)
- (modified) clang/lib/CIR/CodeGen/CIRGenBuiltinRISCV.cpp (+12)
- (modified) clang/lib/CodeGen/TargetBuiltins/RISCV.cpp (+51)
- (modified) clang/lib/Sema/SemaRISCV.cpp (+26)
- (added) clang/test/CodeGen/RISCV/riscv-xcvbitmanip.c (+100)
- (added) clang/test/Sema/riscv-xcvbitmanip-builtins.c (+33)
- (modified) llvm/include/llvm/IR/IntrinsicsRISCVXCV.td (+1)
- (modified) llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td (+1-1)
- (modified) llvm/test/CodeGen/RISCV/xcvbitmanip.ll (+1-1)
``````````diff
diff --git a/clang/include/clang/Basic/BuiltinsRISCVXCV.td b/clang/include/clang/Basic/BuiltinsRISCVXCV.td
index 65eb52b198775..763c48f363fb0 100644
--- a/clang/include/clang/Basic/BuiltinsRISCVXCV.td
+++ b/clang/include/clang/Basic/BuiltinsRISCVXCV.td
@@ -18,6 +18,21 @@ class RISCVXCVBuiltin<string prototype, string features = ""> : TargetBuiltin {
}
let Attributes = [NoThrow, Const] in {
+//===----------------------------------------------------------------------===//
+// XCVbitmanip extension.
+//===----------------------------------------------------------------------===//
+def bitmanip_extract : RISCVXCVBuiltin<"int(unsigned int, unsigned short)", "xcvbitmanip">;
+def bitmanip_extractu : RISCVXCVBuiltin<"unsigned int(unsigned int, unsigned short)", "xcvbitmanip">;
+def bitmanip_insert : RISCVXCVBuiltin<"unsigned int(unsigned int, unsigned short, unsigned int)", "xcvbitmanip">;
+def bitmanip_bclr : RISCVXCVBuiltin<"unsigned int(unsigned int, unsigned short)", "xcvbitmanip">;
+def bitmanip_bset : RISCVXCVBuiltin<"unsigned int(unsigned int, unsigned short)", "xcvbitmanip">;
+def bitmanip_ff1 : RISCVXCVBuiltin<"unsigned char(unsigned int)", "xcvbitmanip">;
+def bitmanip_fl1 : RISCVXCVBuiltin<"unsigned char(unsigned int)", "xcvbitmanip">;
+def bitmanip_clb : RISCVXCVBuiltin<"unsigned char(unsigned int)", "xcvbitmanip">;
+def bitmanip_cnt : RISCVXCVBuiltin<"unsigned char(unsigned int)", "xcvbitmanip">;
+def bitmanip_ror : RISCVXCVBuiltin<"unsigned int(unsigned int, unsigned int)", "xcvbitmanip">;
+def bitmanip_bitrev : RISCVXCVBuiltin<"unsigned int(unsigned int, _Constant unsigned char, _Constant unsigned char)", "xcvbitmanip">;
+
//===----------------------------------------------------------------------===//
// XCValu extension.
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinRISCV.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinRISCV.cpp
index ec262922be942..9438a533672b1 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltinRISCV.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinRISCV.cpp
@@ -167,6 +167,18 @@ CIRGenFunction::emitRISCVBuiltinExpr(unsigned builtinID, const CallExpr *e) {
break;
}
+ // XCVbitmanip
+ case RISCV::BI__builtin_riscv_cv_bitmanip_extract:
+ case RISCV::BI__builtin_riscv_cv_bitmanip_extractu:
+ case RISCV::BI__builtin_riscv_cv_bitmanip_insert:
+ case RISCV::BI__builtin_riscv_cv_bitmanip_bclr:
+ case RISCV::BI__builtin_riscv_cv_bitmanip_bset:
+ case RISCV::BI__builtin_riscv_cv_bitmanip_ff1:
+ case RISCV::BI__builtin_riscv_cv_bitmanip_fl1:
+ case RISCV::BI__builtin_riscv_cv_bitmanip_clb:
+ case RISCV::BI__builtin_riscv_cv_bitmanip_cnt:
+ case RISCV::BI__builtin_riscv_cv_bitmanip_ror:
+ case RISCV::BI__builtin_riscv_cv_bitmanip_bitrev:
// XCValu
case RISCV::BI__builtin_riscv_cv_alu_addN:
case RISCV::BI__builtin_riscv_cv_alu_addRN:
diff --git a/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp b/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
index 3bf7dd07d54d3..2215f45998175 100644
--- a/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
@@ -1304,6 +1304,57 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
return Builder.CreateCall(Fn, {});
}
+ // XCVbitmanip
+ case RISCV::BI__builtin_riscv_cv_bitmanip_extract:
+ Ops[1] = Builder.CreateIntCast(Ops[1], Int32Ty, /*isSigned*/ false);
+ ID = Intrinsic::riscv_cv_bitmanip_extract;
+ break;
+ case RISCV::BI__builtin_riscv_cv_bitmanip_extractu:
+ Ops[1] = Builder.CreateIntCast(Ops[1], Int32Ty, /*isSigned*/ false);
+ ID = Intrinsic::riscv_cv_bitmanip_extractu;
+ break;
+ case RISCV::BI__builtin_riscv_cv_bitmanip_insert:
+ Ops[1] = Builder.CreateIntCast(Ops[1], Int32Ty, /*isSigned*/ false);
+ ID = Intrinsic::riscv_cv_bitmanip_insert;
+ break;
+ case RISCV::BI__builtin_riscv_cv_bitmanip_bclr:
+ Ops[1] = Builder.CreateIntCast(Ops[1], Int32Ty, /*isSigned*/ false);
+ ID = Intrinsic::riscv_cv_bitmanip_bclr;
+ break;
+ case RISCV::BI__builtin_riscv_cv_bitmanip_bset:
+ Ops[1] = Builder.CreateIntCast(Ops[1], Int32Ty, /*isSigned*/ false);
+ ID = Intrinsic::riscv_cv_bitmanip_bset;
+ break;
+ case RISCV::BI__builtin_riscv_cv_bitmanip_ff1: {
+ Function *F = CGM.getIntrinsic(Intrinsic::cttz, Int32Ty);
+ Value *Result = Builder.CreateCall(F, {Ops[0], Builder.getInt1(false)});
+ return Builder.CreateIntCast(Result, ResultType, /*isSigned*/ false);
+ }
+ case RISCV::BI__builtin_riscv_cv_bitmanip_fl1: {
+ Function *F = CGM.getIntrinsic(Intrinsic::riscv_cv_bitmanip_fl1);
+ Value *Result = Builder.CreateCall(F, {Ops[0]});
+ return Builder.CreateIntCast(Result, ResultType, /*isSigned*/ false);
+ }
+ case RISCV::BI__builtin_riscv_cv_bitmanip_clb: {
+ Function *F = CGM.getIntrinsic(Intrinsic::riscv_cv_bitmanip_clb);
+ Value *Result = Builder.CreateCall(F, {Ops[0]});
+ return Builder.CreateIntCast(Result, ResultType, /*isSigned*/ false);
+ }
+ case RISCV::BI__builtin_riscv_cv_bitmanip_cnt: {
+ Function *F = CGM.getIntrinsic(Intrinsic::ctpop, Int32Ty);
+ Value *Result = Builder.CreateCall(F, {Ops[0]});
+ return Builder.CreateIntCast(Result, ResultType, /*isSigned*/ false);
+ }
+ case RISCV::BI__builtin_riscv_cv_bitmanip_ror: {
+ Function *F = CGM.getIntrinsic(Intrinsic::fshr, Int32Ty);
+ return Builder.CreateCall(F, {Ops[0], Ops[0], Ops[1]});
+ }
+ case RISCV::BI__builtin_riscv_cv_bitmanip_bitrev:
+ Ops[1] = Builder.CreateIntCast(Ops[1], Int32Ty, /*isSigned*/ false);
+ Ops[2] = Builder.CreateIntCast(Ops[2], Int32Ty, /*isSigned*/ false);
+ ID = Intrinsic::riscv_cv_bitmanip_bitrev;
+ break;
+
// XCValu
case RISCV::BI__builtin_riscv_cv_alu_addN:
ID = Intrinsic::riscv_cv_alu_addN;
diff --git a/clang/lib/Sema/SemaRISCV.cpp b/clang/lib/Sema/SemaRISCV.cpp
index 56555b931b8d5..a256bd91b665c 100644
--- a/clang/lib/Sema/SemaRISCV.cpp
+++ b/clang/lib/Sema/SemaRISCV.cpp
@@ -588,11 +588,34 @@ bool SemaRISCV::CheckBuiltinFunctionCall(const TargetInfo &TI,
<< /* IsExtension */ true << TheCall->getSourceRange() << RF;
}
+ auto CheckRequiredExtension = [&](StringRef RequiredExt) -> bool {
+ if (TI.hasFeature(RequiredExt) || FunctionFeatureMap.lookup(RequiredExt))
+ return false;
+ return Diag(TheCall->getBeginLoc(),
+ diag::err_riscv_builtin_requires_extension)
+ << /* IsExtension */ true << TheCall->getSourceRange()
+ << RequiredExt;
+ };
+
// vmulh.vv, vmulh.vx, vmulhu.vv, vmulhu.vx, vmulhsu.vv, vmulhsu.vx,
// vsmul.vv, vsmul.vx are not included for EEW=64 in Zve64*.
switch (BuiltinID) {
default:
break;
+ case RISCV::BI__builtin_riscv_cv_bitmanip_extract:
+ case RISCV::BI__builtin_riscv_cv_bitmanip_extractu:
+ case RISCV::BI__builtin_riscv_cv_bitmanip_insert:
+ case RISCV::BI__builtin_riscv_cv_bitmanip_bclr:
+ case RISCV::BI__builtin_riscv_cv_bitmanip_bset:
+ case RISCV::BI__builtin_riscv_cv_bitmanip_ff1:
+ case RISCV::BI__builtin_riscv_cv_bitmanip_fl1:
+ case RISCV::BI__builtin_riscv_cv_bitmanip_clb:
+ case RISCV::BI__builtin_riscv_cv_bitmanip_cnt:
+ case RISCV::BI__builtin_riscv_cv_bitmanip_ror:
+ case RISCV::BI__builtin_riscv_cv_bitmanip_bitrev:
+ if (CheckRequiredExtension("xcvbitmanip"))
+ return true;
+ break;
case RISCVVector::BI__builtin_rvv_vmulhsu_vv:
case RISCVVector::BI__builtin_rvv_vmulhsu_vx:
case RISCVVector::BI__builtin_rvv_vmulhsu_vv_tu:
@@ -688,6 +711,9 @@ bool SemaRISCV::CheckBuiltinFunctionCall(const TargetInfo &TI,
case RISCVVector::BI__builtin_rvv_sf_vsettk:
return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 3) ||
SemaRef.BuiltinConstantArgRange(TheCall, 2, 1, 3);
+ case RISCV::BI__builtin_riscv_cv_bitmanip_bitrev:
+ return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 31) ||
+ SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 3);
case RISCVVector::BI__builtin_rvv_sf_mm_f_f_w1:
case RISCVVector::BI__builtin_rvv_sf_mm_f_f_w2:
case RISCVVector::BI__builtin_rvv_sf_mm_e5m2_e4m3_w4:
diff --git a/clang/test/CodeGen/RISCV/riscv-xcvbitmanip.c b/clang/test/CodeGen/RISCV/riscv-xcvbitmanip.c
new file mode 100644
index 0000000000000..efdafb708044b
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/riscv-xcvbitmanip.c
@@ -0,0 +1,100 @@
+// RUN: %clang_cc1 -triple riscv32 -target-feature +xcvbitmanip -emit-llvm %s -o - \
+// RUN: -disable-O0-optnone | opt -S -passes=mem2reg | FileCheck %s
+
+#include <stdint.h>
+
+// CHECK-LABEL: @test_bitmanip_extract(
+// CHECK: call i32 @llvm.riscv.cv.bitmanip.extract(i32 {{.*}}, i32 31)
+int32_t test_bitmanip_extract(uint32_t a) {
+ return __builtin_riscv_cv_bitmanip_extract(a, 31);
+}
+
+// CHECK-LABEL: @test_bitmanip_extractr(
+// CHECK: call i32 @llvm.riscv.cv.bitmanip.extract(i32 {{.*}}, i32 {{.*}})
+int32_t test_bitmanip_extractr(uint32_t a, uint16_t b) {
+ return __builtin_riscv_cv_bitmanip_extract(a, b);
+}
+
+// CHECK-LABEL: @test_bitmanip_extractu(
+// CHECK: call i32 @llvm.riscv.cv.bitmanip.extractu(i32 {{.*}}, i32 31)
+uint32_t test_bitmanip_extractu(uint32_t a) {
+ return __builtin_riscv_cv_bitmanip_extractu(a, 31);
+}
+
+// CHECK-LABEL: @test_bitmanip_extractur(
+// CHECK: call i32 @llvm.riscv.cv.bitmanip.extractu(i32 {{.*}}, i32 {{.*}})
+uint32_t test_bitmanip_extractur(uint32_t a, uint16_t b) {
+ return __builtin_riscv_cv_bitmanip_extractu(a, b);
+}
+
+// CHECK-LABEL: @test_bitmanip_insert(
+// CHECK: call i32 @llvm.riscv.cv.bitmanip.insert(i32 {{.*}}, i32 31, i32 {{.*}})
+uint32_t test_bitmanip_insert(uint32_t a, uint32_t k) {
+ return __builtin_riscv_cv_bitmanip_insert(a, 31, k);
+}
+
+// CHECK-LABEL: @test_bitmanip_insertr(
+// CHECK: call i32 @llvm.riscv.cv.bitmanip.insert(i32 {{.*}}, i32 {{.*}}, i32 {{.*}})
+uint32_t test_bitmanip_insertr(uint32_t a, uint16_t b, uint32_t k) {
+ return __builtin_riscv_cv_bitmanip_insert(a, b, k);
+}
+
+// CHECK-LABEL: @test_bitmanip_bclr(
+// CHECK: call i32 @llvm.riscv.cv.bitmanip.bclr(i32 {{.*}}, i32 31)
+uint32_t test_bitmanip_bclr(uint32_t a) {
+ return __builtin_riscv_cv_bitmanip_bclr(a, 31);
+}
+
+// CHECK-LABEL: @test_bitmanip_bclrr(
+// CHECK: call i32 @llvm.riscv.cv.bitmanip.bclr(i32 {{.*}}, i32 {{.*}})
+uint32_t test_bitmanip_bclrr(uint32_t a, uint16_t b) {
+ return __builtin_riscv_cv_bitmanip_bclr(a, b);
+}
+
+// CHECK-LABEL: @test_bitmanip_bset(
+// CHECK: call i32 @llvm.riscv.cv.bitmanip.bset(i32 {{.*}}, i32 31)
+uint32_t test_bitmanip_bset(uint32_t a) {
+ return __builtin_riscv_cv_bitmanip_bset(a, 31);
+}
+
+// CHECK-LABEL: @test_bitmanip_bsetr(
+// CHECK: call i32 @llvm.riscv.cv.bitmanip.bset(i32 {{.*}}, i32 {{.*}})
+uint32_t test_bitmanip_bsetr(uint32_t a, uint16_t b) {
+ return __builtin_riscv_cv_bitmanip_bset(a, b);
+}
+
+// CHECK-LABEL: @test_bitmanip_ff1(
+// CHECK: call i32 @llvm.cttz.i32(i32 {{.*}}, i1 false)
+uint8_t test_bitmanip_ff1(uint32_t a) {
+ return __builtin_riscv_cv_bitmanip_ff1(a);
+}
+
+// CHECK-LABEL: @test_bitmanip_fl1(
+// CHECK: call i32 @llvm.riscv.cv.bitmanip.fl1(i32 {{.*}})
+uint8_t test_bitmanip_fl1(uint32_t a) {
+ return __builtin_riscv_cv_bitmanip_fl1(a);
+}
+
+// CHECK-LABEL: @test_bitmanip_clb(
+// CHECK: call i32 @llvm.riscv.cv.bitmanip.clb(i32 {{.*}})
+uint8_t test_bitmanip_clb(uint32_t a) {
+ return __builtin_riscv_cv_bitmanip_clb(a);
+}
+
+// CHECK-LABEL: @test_bitmanip_cnt(
+// CHECK: call i32 @llvm.ctpop.i32(i32 {{.*}})
+uint8_t test_bitmanip_cnt(uint32_t a) {
+ return __builtin_riscv_cv_bitmanip_cnt(a);
+}
+
+// CHECK-LABEL: @test_bitmanip_ror(
+// CHECK: call i32 @llvm.fshr.i32(i32 {{.*}}, i32 {{.*}}, i32 {{.*}})
+uint32_t test_bitmanip_ror(uint32_t a, uint32_t b) {
+ return __builtin_riscv_cv_bitmanip_ror(a, b);
+}
+
+// CHECK-LABEL: @test_bitmanip_bitrev(
+// CHECK: call i32 @llvm.riscv.cv.bitmanip.bitrev(i32 {{.*}}, i32 31, i32 3)
+uint32_t test_bitmanip_bitrev(uint32_t a) {
+ return __builtin_riscv_cv_bitmanip_bitrev(a, 31, 3);
+}
diff --git a/clang/test/Sema/riscv-xcvbitmanip-builtins.c b/clang/test/Sema/riscv-xcvbitmanip-builtins.c
new file mode 100644
index 0000000000000..12c6b1c05904b
--- /dev/null
+++ b/clang/test/Sema/riscv-xcvbitmanip-builtins.c
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -triple riscv32 -target-feature +xcvbitmanip -fsyntax-only -verify=xcv %s
+// RUN: %clang_cc1 -triple riscv32 -DNO_XCVBITMANIP -fsyntax-only -verify=noxcv %s
+
+#include <stdint.h>
+
+#ifndef NO_XCVBITMANIP
+void test_bitmanip_bitrev_range(uint32_t a) {
+ (void)__builtin_riscv_cv_bitmanip_bitrev(a, 31, 3);
+ (void)__builtin_riscv_cv_bitmanip_bitrev(a, -1, 0); // xcv-error {{argument value 255 is outside the valid range [0, 31]}}
+ (void)__builtin_riscv_cv_bitmanip_bitrev(a, 32, 0); // xcv-error {{argument value 32 is outside the valid range [0, 31]}}
+ (void)__builtin_riscv_cv_bitmanip_bitrev(a, 0, -1); // xcv-error {{argument value 255 is outside the valid range [0, 3]}}
+ (void)__builtin_riscv_cv_bitmanip_bitrev(a, 0, 4); // xcv-error {{argument value 4 is outside the valid range [0, 3]}}
+}
+
+void test_bitmanip_bitrev_constant(uint32_t a, uint8_t b) {
+ (void)__builtin_riscv_cv_bitmanip_bitrev(a, b, 0); // xcv-error {{argument to '__builtin_riscv_cv_bitmanip_bitrev' must be a constant integer}}
+ (void)__builtin_riscv_cv_bitmanip_bitrev(a, 0, b); // xcv-error {{argument to '__builtin_riscv_cv_bitmanip_bitrev' must be a constant integer}}
+}
+#else
+void test_bitmanip_requires_xcvbitmanip(uint32_t a, uint16_t b, uint32_t k) {
+ (void)__builtin_riscv_cv_bitmanip_extract(a, b); // noxcv-error {{builtin requires at least one of the following extensions: xcvbitmanip}}
+ (void)__builtin_riscv_cv_bitmanip_extractu(a, b); // noxcv-error {{builtin requires at least one of the following extensions: xcvbitmanip}}
+ (void)__builtin_riscv_cv_bitmanip_insert(a, b, k); // noxcv-error {{builtin requires at least one of the following extensions: xcvbitmanip}}
+ (void)__builtin_riscv_cv_bitmanip_bclr(a, b); // noxcv-error {{builtin requires at least one of the following extensions: xcvbitmanip}}
+ (void)__builtin_riscv_cv_bitmanip_bset(a, b); // noxcv-error {{builtin requires at least one of the following extensions: xcvbitmanip}}
+ (void)__builtin_riscv_cv_bitmanip_ff1(a); // noxcv-error {{builtin requires at least one of the following extensions: xcvbitmanip}}
+ (void)__builtin_riscv_cv_bitmanip_fl1(a); // noxcv-error {{builtin requires at least one of the following extensions: xcvbitmanip}}
+ (void)__builtin_riscv_cv_bitmanip_clb(a); // noxcv-error {{builtin requires at least one of the following extensions: xcvbitmanip}}
+ (void)__builtin_riscv_cv_bitmanip_cnt(a); // noxcv-error {{builtin requires at least one of the following extensions: xcvbitmanip}}
+ (void)__builtin_riscv_cv_bitmanip_ror(a, k); // noxcv-error {{builtin requires at least one of the following extensions: xcvbitmanip}}
+ (void)__builtin_riscv_cv_bitmanip_bitrev(a, 31, 3); // noxcv-error {{builtin requires at least one of the following extensions: xcvbitmanip}}
+}
+#endif
diff --git a/llvm/include/llvm/IR/IntrinsicsRISCVXCV.td b/llvm/include/llvm/IR/IntrinsicsRISCVXCV.td
index 465665c838bae..ae3eb3b2d3dee 100644
--- a/llvm/include/llvm/IR/IntrinsicsRISCVXCV.td
+++ b/llvm/include/llvm/IR/IntrinsicsRISCVXCV.td
@@ -53,6 +53,7 @@ let TargetPrefix = "riscv" in {
[IntrNoMem, IntrSpeculatable]>;
def int_riscv_cv_bitmanip_clb : ScalarCoreVBitManipGprIntrinsic;
+ def int_riscv_cv_bitmanip_fl1 : ScalarCoreVBitManipGprIntrinsic;
def int_riscv_cv_bitmanip_bitrev
: DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty],
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td
index 8b52fc965e601..5cb4c7ba84ea8 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td
@@ -734,7 +734,7 @@ let Predicates = [HasVendorXCVbitmanip, IsRV32] in {
(CV_LO5 cv_uimm10:$imm))>;
def : PatGpr<cttz, CV_FF1, i32>;
- def : PatGpr<ctlz, CV_FL1, i32>;
+ def : PatGpr<int_riscv_cv_bitmanip_fl1, CV_FL1>;
def : PatGpr<int_riscv_cv_bitmanip_clb, CV_CLB>;
def : PatGpr<ctpop, CV_CNT, i32>;
diff --git a/llvm/test/CodeGen/RISCV/xcvbitmanip.ll b/llvm/test/CodeGen/RISCV/xcvbitmanip.ll
index 7e63efac9b62f..cb40bbc10fb9a 100644
--- a/llvm/test/CodeGen/RISCV/xcvbitmanip.ll
+++ b/llvm/test/CodeGen/RISCV/xcvbitmanip.ll
@@ -117,7 +117,7 @@ define i32 @test.cv.fl1(i32 %a) {
; CHECK: # %bb.0:
; CHECK-NEXT: cv.fl1 a0, a0
; CHECK-NEXT: ret
- %1 = call i32 @llvm.ctlz.i32(i32 %a, i1 0)
+ %1 = call i32 @llvm.riscv.cv.bitmanip.fl1(i32 %a)
ret i32 %1
}
``````````
</details>
https://github.com/llvm/llvm-project/pull/202564
More information about the cfe-commits
mailing list