[clang] [llvm] [RISCV] Implement Builtins for XAndesBFHCvt extension. (PR #148804)

via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 15 01:55:11 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-x86

Author: Jim Lin (tclin914)

<details>
<summary>Changes</summary>

XAndesBFHCvt provides two builtins functions for converting between float and bf16. Users can use them to convert bf16 values loaded from memory to float, perform arithmetic operations, then convert them back to bf16 and store them to memory.

The load/store and move operations for bf16 will be handled in a later patch.

---
Full diff: https://github.com/llvm/llvm-project/pull/148804.diff


11 Files Affected:

- (modified) clang/include/clang/Basic/BuiltinsRISCV.td (+5) 
- (added) clang/include/clang/Basic/BuiltinsRISCVXAndes.td (+27) 
- (modified) clang/lib/CodeGen/TargetBuiltins/RISCV.cpp (+8) 
- (modified) clang/lib/Headers/CMakeLists.txt (+1) 
- (added) clang/lib/Headers/riscv_nds.h (+35) 
- (added) clang/test/CodeGen/RISCV/riscv-xandesbfhcvt-c-api.c (+25) 
- (added) clang/test/CodeGen/RISCV/riscv-xandesbfhcvt.c (+23) 
- (modified) llvm/include/llvm/IR/IntrinsicsRISCVXAndes.td (+9) 
- (modified) llvm/lib/Target/RISCV/RISCVISelLowering.cpp (+1-1) 
- (modified) llvm/lib/Target/RISCV/RISCVInstrInfoXAndes.td (+7) 
- (added) llvm/test/CodeGen/RISCV/xandesbfhcvt.ll (+27) 


``````````diff
diff --git a/clang/include/clang/Basic/BuiltinsRISCV.td b/clang/include/clang/Basic/BuiltinsRISCV.td
index b2cd5648e008f..5927eaf80d57a 100644
--- a/clang/include/clang/Basic/BuiltinsRISCV.td
+++ b/clang/include/clang/Basic/BuiltinsRISCV.td
@@ -157,3 +157,8 @@ def pause : RISCVBuiltin<"void()">;
 // XCV extensions.
 //===----------------------------------------------------------------------===//
 include "clang/Basic/BuiltinsRISCVXCV.td"
+
+//===----------------------------------------------------------------------===//
+// XAndes extensions.
+//===----------------------------------------------------------------------===//
+include "clang/Basic/BuiltinsRISCVXAndes.td"
diff --git a/clang/include/clang/Basic/BuiltinsRISCVXAndes.td b/clang/include/clang/Basic/BuiltinsRISCVXAndes.td
new file mode 100644
index 0000000000000..ea9a7166bc6e8
--- /dev/null
+++ b/clang/include/clang/Basic/BuiltinsRISCVXAndes.td
@@ -0,0 +1,27 @@
+//==- BuiltinsRISCVXAndes.td - RISC-V Andes Builtin database -----*- C++ -*-==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the Andes-specific builtin function database.  Users of
+// this file must define the BUILTIN macro to make use of this information.
+//
+//===----------------------------------------------------------------------===//
+
+class RISCVXAndesBuiltin<string prototype, string features = ""> : TargetBuiltin {
+  let Spellings = ["__builtin_riscv_nds_" # NAME];
+  let Prototype = prototype;
+  let Features = features;
+}
+
+let Attributes = [NoThrow, Const] in {
+//===----------------------------------------------------------------------===//
+// XAndesBFHCvt extension.
+//===----------------------------------------------------------------------===//
+
+def fcvt_s_bf16 : RISCVXAndesBuiltin<"float(__bf16)", "xandesbfhcvt">;
+def fcvt_bf16_s : RISCVXAndesBuiltin<"__bf16(float)", "xandesbfhcvt">;
+} // Attributes = [NoThrow, Const]
diff --git a/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp b/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
index 89e3f6f203df3..63092139af4fa 100644
--- a/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
@@ -413,6 +413,14 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
     ID = Intrinsic::riscv_cv_alu_subuRN;
     break;
 
+  // XAndesBFHCvt
+  case RISCV::BI__builtin_riscv_nds_fcvt_s_bf16:
+    ID = Intrinsic::riscv_nds_fcvt_s_bf16;
+    break;
+  case RISCV::BI__builtin_riscv_nds_fcvt_bf16_s:
+    ID = Intrinsic::riscv_nds_fcvt_bf16_s;
+    break;
+
     // Vector builtins are handled from here.
 #include "clang/Basic/riscv_vector_builtin_cg.inc"
 
diff --git a/clang/lib/Headers/CMakeLists.txt b/clang/lib/Headers/CMakeLists.txt
index c96d209c1fc0c..76ac8409e568f 100644
--- a/clang/lib/Headers/CMakeLists.txt
+++ b/clang/lib/Headers/CMakeLists.txt
@@ -127,6 +127,7 @@ set(riscv_files
   riscv_bitmanip.h
   riscv_corev_alu.h
   riscv_crypto.h
+  riscv_nds.h
   riscv_ntlh.h
   sifive_vector.h
   andes_vector.h
diff --git a/clang/lib/Headers/riscv_nds.h b/clang/lib/Headers/riscv_nds.h
new file mode 100644
index 0000000000000..5ccef00e332ed
--- /dev/null
+++ b/clang/lib/Headers/riscv_nds.h
@@ -0,0 +1,35 @@
+/*===---- riscv_nds.h - Andes intrinsics -----------------------------------===
+ *
+ * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+ * See https://llvm.org/LICENSE.txt for license information.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#ifndef __RISCV_NDS_H
+#define __RISCV_NDS_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#if defined(__riscv_xandesbfhcvt)
+
+#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__))
+
+static __inline__ float __DEFAULT_FN_ATTRS __riscv_nds_fcvt_s_bf16(__bf16 bf) {
+  return __builtin_riscv_nds_fcvt_s_bf16(bf);
+}
+
+static __inline__ __bf16 __DEFAULT_FN_ATTRS __riscv_nds_fcvt_bf16_s(float sf) {
+  return __builtin_riscv_nds_fcvt_bf16_s(sf);
+}
+
+#endif // defined(__riscv_xandesbfhcvt)
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif // define __RISCV_NDS_H
diff --git a/clang/test/CodeGen/RISCV/riscv-xandesbfhcvt-c-api.c b/clang/test/CodeGen/RISCV/riscv-xandesbfhcvt-c-api.c
new file mode 100644
index 0000000000000..49935217080e5
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/riscv-xandesbfhcvt-c-api.c
@@ -0,0 +1,25 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
+// RUN: %clang_cc1 -triple riscv32 -target-feature +xandesbfhcvt -emit-llvm %s -o - \
+// RUN:   -disable-O0-optnone | opt -S -passes=mem2reg | FileCheck %s
+// RUN: %clang_cc1 -triple riscv64 -target-feature +xandesbfhcvt -emit-llvm %s -o - \
+// RUN:   -disable-O0-optnone | opt -S -passes=mem2reg | FileCheck %s
+
+#include <riscv_nds.h>
+
+// CHECK-LABEL: @test_fcvt_s_bf16(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = call float @llvm.riscv.nds.fcvt.s.bf16(bfloat [[BF:%.*]])
+// CHECK-NEXT:    ret float [[TMP0]]
+//
+float test_fcvt_s_bf16(__bf16 bf) {
+  return __riscv_nds_fcvt_s_bf16(bf);
+}
+
+// CHECK-LABEL: @test_fcvt_bf16_s(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = call bfloat @llvm.riscv.nds.fcvt.bf16.s(float [[SF:%.*]])
+// CHECK-NEXT:    ret bfloat [[TMP0]]
+//
+__bf16 test_fcvt_bf16_s(float sf) {
+  return __riscv_nds_fcvt_bf16_s(sf);
+}
diff --git a/clang/test/CodeGen/RISCV/riscv-xandesbfhcvt.c b/clang/test/CodeGen/RISCV/riscv-xandesbfhcvt.c
new file mode 100644
index 0000000000000..ecb809f43b56a
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/riscv-xandesbfhcvt.c
@@ -0,0 +1,23 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
+// RUN: %clang_cc1 -triple riscv32 -target-feature +xandesbfhcvt -emit-llvm %s -o - \
+// RUN:   -disable-O0-optnone | opt -S -passes=mem2reg | FileCheck %s
+// RUN: %clang_cc1 -triple riscv64 -target-feature +xandesbfhcvt -emit-llvm %s -o - \
+// RUN:   -disable-O0-optnone | opt -S -passes=mem2reg | FileCheck %s
+
+// CHECK-LABEL: @test_fcvt_s_bf16(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = call float @llvm.riscv.nds.fcvt.s.bf16(bfloat [[BF:%.*]])
+// CHECK-NEXT:    ret float [[TMP0]]
+//
+float test_fcvt_s_bf16(__bf16 bf) {
+  return __builtin_riscv_nds_fcvt_s_bf16(bf);
+}
+
+// CHECK-LABEL: @test_fcvt_bf16_s(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = call bfloat @llvm.riscv.nds.fcvt.bf16.s(float [[SF:%.*]])
+// CHECK-NEXT:    ret bfloat [[TMP0]]
+//
+__bf16 test_fcvt_bf16_s(float sf) {
+  return __builtin_riscv_nds_fcvt_bf16_s(sf);
+}
diff --git a/llvm/include/llvm/IR/IntrinsicsRISCVXAndes.td b/llvm/include/llvm/IR/IntrinsicsRISCVXAndes.td
index 43f7f7e22fe94..9bb7855a709f3 100644
--- a/llvm/include/llvm/IR/IntrinsicsRISCVXAndes.td
+++ b/llvm/include/llvm/IR/IntrinsicsRISCVXAndes.td
@@ -11,6 +11,15 @@
 //===----------------------------------------------------------------------===//
 
 let TargetPrefix = "riscv" in {
+  // Andes Scalar BFloat16 Conversion Extension
+  def int_riscv_nds_fcvt_s_bf16
+      : DefaultAttrsIntrinsic<[llvm_float_ty], [llvm_bfloat_ty],
+                              [IntrNoMem, IntrSpeculatable]>;
+
+  def int_riscv_nds_fcvt_bf16_s
+      : DefaultAttrsIntrinsic<[llvm_bfloat_ty], [llvm_float_ty],
+                              [IntrNoMem, IntrSpeculatable]>;
+
   // Andes Vector BFloat16 Conversion Extension
   def int_riscv_nds_vfwcvt_s_bf16 : RISCVConversionUnMasked;
   def int_riscv_nds_vfncvt_bf16_s : RISCVConversionUnMaskedRoundingMode;
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 359e529df46f3..45fcb27e2f88e 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -129,7 +129,7 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
 
   if (Subtarget.hasStdExtZfhmin())
     addRegisterClass(MVT::f16, &RISCV::FPR16RegClass);
-  if (Subtarget.hasStdExtZfbfmin())
+  if (Subtarget.hasStdExtZfbfmin() || Subtarget.hasVendorXAndesBFHCvt())
     addRegisterClass(MVT::bf16, &RISCV::FPR16RegClass);
   if (Subtarget.hasStdExtF())
     addRegisterClass(MVT::f32, &RISCV::FPR32RegClass);
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXAndes.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXAndes.td
index 38992b6c05d08..06b35163e9cf4 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoXAndes.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXAndes.td
@@ -767,6 +767,13 @@ def : Sh2AddPat<NDS_LEA_W_ZE>;
 def : Sh3AddPat<NDS_LEA_D_ZE>;
 } // Predicates = [HasVendorXAndesPerf, IsRV64]
 
+let Predicates = [HasVendorXAndesBFHCvt] in {
+def : Pat<(int_riscv_nds_fcvt_s_bf16 (bf16 FPR16:$rs)),
+          (NDS_FCVT_S_BF16 (bf16 FPR16:$rs))>;
+def : Pat<(bf16 (int_riscv_nds_fcvt_bf16_s FPR32:$rs)),
+          (NDS_FCVT_BF16_S FPR32:$rs)>;
+} // Predicates = [HasVendorXAndesBFHCvt]
+
 let Predicates = [HasVendorXAndesVBFHCvt] in {
 defm PseudoNDS_VFWCVT_S_BF16 : VPseudoVWCVT_S_BF16;
 defm PseudoNDS_VFNCVT_BF16_S : VPseudoVNCVT_BF16_S;
diff --git a/llvm/test/CodeGen/RISCV/xandesbfhcvt.ll b/llvm/test/CodeGen/RISCV/xandesbfhcvt.ll
new file mode 100644
index 0000000000000..5b8c6c11a0750
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/xandesbfhcvt.ll
@@ -0,0 +1,27 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -mattr=+xandesbfhcvt -target-abi ilp32f \
+; RUN:   -verify-machineinstrs < %s | FileCheck %s
+; RUN: llc -mtriple=riscv64 -mattr=+xandesbfhcvt -target-abi lp64f \
+; RUN:   -verify-machineinstrs < %s | FileCheck %s
+
+declare bfloat @llvm.riscv.nds.fcvt.bf16.s(float)
+
+define float @fcvt_s_bf16(bfloat %a) nounwind {
+; CHECK-LABEL: fcvt_s_bf16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    nds.fcvt.s.bf16 fa0, fa0
+; CHECK-NEXT:    ret
+  %1 = call float @llvm.riscv.nds.fcvt.s.bf16(bfloat %a)
+  ret float %1
+}
+
+declare float @llvm.riscv.nds.fcvt.s.bf16(bfloat)
+
+define bfloat @fcvt_bf16_s(float %a) nounwind {
+; CHECK-LABEL: fcvt_bf16_s:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    nds.fcvt.bf16.s fa0, fa0
+; CHECK-NEXT:    ret
+  %1 = call bfloat @llvm.riscv.nds.fcvt.bf16.s(float %a)
+  ret bfloat %1
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/148804


More information about the llvm-commits mailing list