https://github.com/Scheremo created 
https://github.com/llvm/llvm-project/pull/202564

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

>From 3aef9f7f2a208155851b6152ad6bddd4855efbe5 Mon Sep 17 00:00:00 2001
From: Moritz Scherer <[email protected]>
Date: Tue, 9 Jun 2026 10:13:07 +0200
Subject: [PATCH] [RISCV] Add Clang builtins for XCVbitmanip

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
---
 clang/include/clang/Basic/BuiltinsRISCVXCV.td |  15 +++
 clang/lib/CIR/CodeGen/CIRGenBuiltinRISCV.cpp  |  12 +++
 clang/lib/CodeGen/TargetBuiltins/RISCV.cpp    |  51 +++++++++
 clang/lib/Sema/SemaRISCV.cpp                  |  26 +++++
 clang/test/CodeGen/RISCV/riscv-xcvbitmanip.c  | 100 ++++++++++++++++++
 clang/test/Sema/riscv-xcvbitmanip-builtins.c  |  33 ++++++
 llvm/include/llvm/IR/IntrinsicsRISCVXCV.td    |   1 +
 llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td    |   2 +-
 llvm/test/CodeGen/RISCV/xcvbitmanip.ll        |   2 +-
 9 files changed, 240 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/CodeGen/RISCV/riscv-xcvbitmanip.c
 create mode 100644 clang/test/Sema/riscv-xcvbitmanip-builtins.c

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
 }
 

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to