https://github.com/4vtomat created 
https://github.com/llvm/llvm-project/pull/187197

Normally intrinsic support is decoupled from assembler support which
means we cant simply use arch string to check if intrinsics are
supported. This patch defines macros "__riscv_v_intrinsic_{EXTENSION}}
to check whether the intrinsics of EXTENSION is supported by this compiler.


>From abec7a4d68cd56445c7e5221288394bc4d587e77 Mon Sep 17 00:00:00 2001
From: Brandon Wu <[email protected]>
Date: Mon, 16 Mar 2026 23:48:35 -0700
Subject: [PATCH] [clang][RISCV] Use macro to check if intrinsics are supported

Normally intrinsic support is decoupled from assembler support which
means we cant simply use arch string to check if intrinsics are
supported. This patch defines macros "__riscv_v_intrinsic_{EXTENSION}}
to check whether the intrinsics of EXTENSION is supported by this compiler.
---
 clang/lib/Basic/Targets/RISCV.cpp             | 46 ++++++++++++++
 .../riscv-vector-intrinsic-exts.c             | 63 +++++++++++++++++++
 clang/utils/TableGen/RISCVVEmitter.cpp        | 19 +++++-
 llvm/docs/RISCVUsage.rst                      | 23 +++++++
 4 files changed, 148 insertions(+), 3 deletions(-)
 create mode 100644 clang/test/Preprocessor/riscv-vector-intrinsic-exts.c

diff --git a/clang/lib/Basic/Targets/RISCV.cpp 
b/clang/lib/Basic/Targets/RISCV.cpp
index 685925b0773dc..a46eb87d88b94 100644
--- a/clang/lib/Basic/Targets/RISCV.cpp
+++ b/clang/lib/Basic/Targets/RISCV.cpp
@@ -22,6 +22,16 @@
 using namespace clang;
 using namespace clang::targets;
 
+namespace {
+static constexpr StringRef UniqueExtensions[] = {
+#define DECL_REQUIRED_EXTENSIONS
+#include "clang/Basic/riscv_andes_vector_builtins.inc"
+#include "clang/Basic/riscv_sifive_vector_builtins.inc"
+#include "clang/Basic/riscv_vector_builtins.inc"
+#undef DECL_REQUIRED_EXTENSIONS
+};
+} // namespace
+
 ArrayRef<const char *> RISCVTargetInfo::getGCCRegNames() const {
   // clang-format off
   static const char *const GCCRegNames[] = {
@@ -225,6 +235,42 @@ void RISCVTargetInfo::getTargetDefines(const LangOptions 
&Opts,
   // Currently we support the v1.0 RISC-V V intrinsics.
   Builder.defineMacro("__riscv_v_intrinsic", Twine(getVersionValue(1, 0)));
 
+  // These macros indicate which extensions have intrinsics supported by the
+  // toolchain, regardless of whether they are currently enabled.
+  for (llvm::StringRef Ext : UniqueExtensions) {
+    if (Ext == "64bit")
+      continue;
+    Builder.defineMacro("__riscv_v_intrinsic_" + Twine(Ext));
+  }
+
+  // Define macros for intrinsics that are not explicitly listed in
+  // RequiredFeatures in td files.
+  const char *ImplicitList[] = {"v",      "zve32x", "zve32f",
+                                "zve64x", "zve64f", "zve64d"};
+  for (const auto *Ext : ImplicitList)
+    Builder.defineMacro(Twine("__riscv_v_intrinsic_") + Ext);
+
+  // Define macros for shorthand extensions when all of intrinsics of its
+  // extensions are presented.
+  auto DefineSuperExt = [&](const char *Name, ArrayRef<const char *> Required) 
{
+    assert(Required.size() > 0);
+    std::string Condition =
+        std::string("#if defined(__riscv_v_intrinsic_") + Required[0] + ")";
+    for (size_t i = 1; i < Required.size(); ++i)
+      Condition +=
+          std::string(" && defined(__riscv_v_intrinsic_") + Required[i] + ")";
+    Builder.append(Condition);
+    Builder.defineMacro(Twine("__riscv_v_intrinsic_") + Name);
+    Builder.append("#endif");
+  };
+
+  DefineSuperExt("zvkn", {"zvkned", "zvknhb", "zvkb"});
+  DefineSuperExt("zvknc", {"zvkn", "zvbc"});
+  DefineSuperExt("zvkng", {"zvkn", "zvkg"});
+  DefineSuperExt("zvks", {"zvksed", "zvksh", "zvkb"});
+  DefineSuperExt("zvksc", {"zvks", "zvbc"});
+  DefineSuperExt("zvksg", {"zvks", "zvkg"});
+
   auto VScale = getVScaleRange(Opts, ArmStreamingKind::NotStreaming);
   if (VScale && VScale->first && VScale->first == VScale->second)
     Builder.defineMacro("__riscv_v_fixed_vlen",
diff --git a/clang/test/Preprocessor/riscv-vector-intrinsic-exts.c 
b/clang/test/Preprocessor/riscv-vector-intrinsic-exts.c
new file mode 100644
index 0000000000000..77e9293aec502
--- /dev/null
+++ b/clang/test/Preprocessor/riscv-vector-intrinsic-exts.c
@@ -0,0 +1,63 @@
+// RUN: %clang --target=riscv32-unknown-linux-gnu \
+// RUN:   -march=rv32iv -E -dM %s \
+// RUN:   -o - | FileCheck --check-prefix=CHECK-ALL-INTRINSICS %s
+// RUN: %clang --target=riscv64-unknown-linux-gnu \
+// RUN:   -march=rv64iv -E -dM %s \
+// RUN:   -o - | FileCheck --check-prefix=CHECK-ALL-INTRINSICS %s
+
+// Base vector intrinsics
+// CHECK-ALL-INTRINSICS: __riscv_v_intrinsic_v 1
+
+// Andes vendor extensions
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_xandesvbfhcvt 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_xandesvdot 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_xandesvpackfph 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_xandesvsintload 1
+
+// SiFive vendor extensions
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_xsfmm32a16f 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_xsfmm32a32f 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_xsfmm32a8f 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_xsfmm32a8i 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_xsfmm64a64f 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_xsfmmbase 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_xsfvcp 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_xsfvfbfexp16e 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_xsfvfexp16e 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_xsfvfexp32e 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_xsfvfexpa 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_xsfvfexpa64e 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_xsfvfnrclipxfqf 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_xsfvfwmaccqqq 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_xsfvqmaccdod 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_xsfvqmaccqoq 1
+
+// Standard vector extensions
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_zvabd 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_zvbb 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_zvbc 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_zvdot4a8i 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_zve32f 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_zve32x 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_zve64d 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_zve64f 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_zve64x 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_zvfbfa 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_zvfbfmin 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_zvfbfwma 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_zvfh 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_zvfhmin 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_zvfofp8min 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_zvkb 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_zvkg 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_zvkn 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_zvknc 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_zvkned 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_zvkng 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_zvknha 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_zvknhb 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_zvks 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_zvksc 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_zvksed 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_zvksg 1
+// CHECK-ALL-INTRINSICS-NEXT: __riscv_v_intrinsic_zvksh 1
diff --git a/clang/utils/TableGen/RISCVVEmitter.cpp 
b/clang/utils/TableGen/RISCVVEmitter.cpp
index 970132d85d5b6..4810e9838e6e9 100644
--- a/clang/utils/TableGen/RISCVVEmitter.cpp
+++ b/clang/utils/TableGen/RISCVVEmitter.cpp
@@ -118,7 +118,8 @@ class RVVEmitter {
 private:
   /// Create all intrinsics and add them to \p Out and SemaRecords.
   void createRVVIntrinsics(std::vector<std::unique_ptr<RVVIntrinsic>> &Out,
-                           std::vector<SemaRecord> *SemaRecords = nullptr);
+                           std::vector<SemaRecord> *SemaRecords = nullptr,
+                           std::set<StringRef> *UniqueExtensions = nullptr);
   /// Create all intrinsic records and SemaSignatureTable from SemaRecords.
   void createRVVIntrinsicRecords(std::vector<RVVIntrinsicRecord> &Out,
                                  SemaSignatureTable &SST,
@@ -504,7 +505,8 @@ void RVVEmitter::createHeader(raw_ostream &OS) {
 
 void RVVEmitter::createBuiltins(raw_ostream &OS) {
   std::vector<std::unique_ptr<RVVIntrinsic>> Defs;
-  createRVVIntrinsics(Defs);
+  std::set<StringRef> UniqueExtensions;
+  createRVVIntrinsics(Defs, nullptr, &UniqueExtensions);
 
   llvm::StringToOffsetTable Table;
   // Ensure offset zero is the empty string.
@@ -568,6 +570,12 @@ void RVVEmitter::createBuiltins(raw_ostream &OS) {
     OS << "HeaderDesc::NO_HEADER, ALL_LANGUAGES},\n";
   }
   OS << "#endif // GET_RISCVV_BUILTIN_INFOS\n\n";
+
+  // Collect all unique required extensions for vector intrinsics
+  OS << "#ifdef DECL_REQUIRED_EXTENSIONS\n";
+  for (const auto &UE : UniqueExtensions)
+    OS << "  \"" << UE << "\",\n";
+  OS << "#endif // DECL_REQUIRED_EXTENSIONS\n\n";
 }
 
 void RVVEmitter::createCodeGen(raw_ostream &OS) {
@@ -626,7 +634,8 @@ void RVVEmitter::createCodeGen(raw_ostream &OS) {
 
 void RVVEmitter::createRVVIntrinsics(
     std::vector<std::unique_ptr<RVVIntrinsic>> &Out,
-    std::vector<SemaRecord> *SemaRecords) {
+    std::vector<SemaRecord> *SemaRecords,
+    std::set<StringRef> *UniqueExtensions) {
   for (const Record *R : Records.getAllDerivedDefinitions("RVVBuiltin")) {
     StringRef Name = R->getValueAsString("Name");
     StringRef SuffixProto = R->getValueAsString("Suffix");
@@ -676,6 +685,10 @@ void RVVEmitter::createRVVIntrinsics(
     SmallVector<PrototypeDescriptor> OverloadedSuffixDesc =
         parsePrototypes(OverloadedSuffixProto);
 
+    if (UniqueExtensions)
+      UniqueExtensions->insert(RequiredFeatures.begin(),
+                               RequiredFeatures.end());
+
     // Compute Builtin types
     auto Prototype = RVVIntrinsic::computeBuiltinTypes(
         BasicPrototype, /*IsMasked=*/false,
diff --git a/llvm/docs/RISCVUsage.rst b/llvm/docs/RISCVUsage.rst
index d1befbd645900..165c1f081b39d 100644
--- a/llvm/docs/RISCVUsage.rst
+++ b/llvm/docs/RISCVUsage.rst
@@ -578,6 +578,29 @@ line.  This currently applies to the following extensions:
 
 No extensions have experimental intrinsics.
 
+Vector Intrinsic Detection Macros
+==================================
+
+Clang defines preprocessor macros ``__riscv_v_intrinsic_<extension>`` to 
indicate
+toolchain support for RISC-V vector intrinsics. These macros are defined for 
all
+vector extensions that have intrinsics, allowing code to detect whether the 
compiler
+supports intrinsics for a specific extension.
+
+Note: These macros are defined unconditionally because it's intended to show 
capabilities
+of this compiler instead of showing whether extension is enabled.
+
+Example usage:
+
+.. code-block:: c
+
+    #if defined(__riscv_v_intrinsic_zvbb)
+    // Compiler supports Zvbb intrinsics - can use them
+    #include <riscv_vector.h>
+    void use_zvbb_intrinsics() {
+      // Use Zvbb intrinsics here
+    }
+    #endif
+
 Long (>32-bit) Instruction Support
 ==================================
 

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

Reply via email to