Skip to content

[RISCV] Implement Clang Builtins for XAndesPerf Extension #147018

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

tclin914
Copy link
Contributor

@tclin914 tclin914 commented Jul 4, 2025

This patch adds the Clang builtins for byte comparision instructions in XAndesPerf Extension. These instructions are hardly generated by compiler. So we provide the Clang builtins for the user.

This patch adds the Clang builtins for byte comparision instructions in
XAndesPerf Extension. These instructions are hardly generated by
compiler. So we provide the Clang builtins for the user.
@tclin914 tclin914 requested review from lenary, topperc and wangpc-pp July 4, 2025 08:43
@llvmbot llvmbot added clang Clang issues not falling into any other category backend:RISC-V backend:X86 clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:headers Headers provided by Clang, e.g. for intrinsics clang:codegen IR generation bugs: mangling, exceptions, etc. llvm:ir labels Jul 4, 2025
@llvmbot
Copy link
Member

llvmbot commented Jul 4, 2025

@llvm/pr-subscribers-clang

@llvm/pr-subscribers-backend-risc-v

Author: Jim Lin (tclin914)

Changes

This patch adds the Clang builtins for byte comparision instructions in XAndesPerf Extension. These instructions are hardly generated by compiler. So we provide the Clang builtins for the user.


Patch is 25.93 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/147018.diff

11 Files Affected:

  • (modified) clang/include/clang/Basic/BuiltinsRISCV.td (+5)
  • (added) clang/include/clang/Basic/BuiltinsRISCVXAndes.td (+29)
  • (modified) clang/lib/CodeGen/TargetBuiltins/RISCV.cpp (+18)
  • (modified) clang/lib/Headers/CMakeLists.txt (+1)
  • (added) clang/lib/Headers/riscv_nds.h (+47)
  • (added) clang/test/CodeGen/RISCV/riscv-xandesperf-c-api.c (+159)
  • (added) clang/test/CodeGen/RISCV/riscv-xandesperf.c (+109)
  • (modified) llvm/include/llvm/IR/IntrinsicsRISCVXAndes.td (+14)
  • (modified) llvm/lib/Target/RISCV/RISCVInstrInfoXAndes.td (+11)
  • (modified) llvm/test/CodeGen/RISCV/rv32xandesperf.ll (+47)
  • (modified) llvm/test/CodeGen/RISCV/rv64xandesperf.ll (+47)
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..8ebcc18889d6c
--- /dev/null
+++ b/clang/include/clang/Basic/BuiltinsRISCVXAndes.td
@@ -0,0 +1,29 @@
+//==- 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 {
+//===----------------------------------------------------------------------===//
+// XAndesPerf extension.
+//===----------------------------------------------------------------------===//
+
+def ffb     : RISCVXAndesBuiltin<"long int(unsigned long int, unsigned long int)", "xandesperf">;
+def ffzmism : RISCVXAndesBuiltin<"long int(unsigned long int, unsigned long int)", "xandesperf">;
+def ffmism  : RISCVXAndesBuiltin<"long int(unsigned long int, unsigned long int)", "xandesperf">;
+def flmism  : RISCVXAndesBuiltin<"long int(unsigned long int, unsigned long int)", "xandesperf">;
+} // Attributes = [NoThrow, Const]
diff --git a/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp b/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
index 89e3f6f203df3..48a497b32a4a6 100644
--- a/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
@@ -413,6 +413,24 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
     ID = Intrinsic::riscv_cv_alu_subuRN;
     break;
 
+  // XAndesPerf
+  case RISCV::BI__builtin_riscv_nds_ffb:
+    IntrinsicTypes = {ResultType};
+    ID = Intrinsic::riscv_nds_ffb;
+    break;
+  case RISCV::BI__builtin_riscv_nds_ffzmism:
+    IntrinsicTypes = {ResultType};
+    ID = Intrinsic::riscv_nds_ffzmism;
+    break;
+  case RISCV::BI__builtin_riscv_nds_ffmism:
+    IntrinsicTypes = {ResultType};
+    ID = Intrinsic::riscv_nds_ffmism;
+    break;
+  case RISCV::BI__builtin_riscv_nds_flmism:
+    IntrinsicTypes = {ResultType};
+    ID = Intrinsic::riscv_nds_flmism;
+    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..44e2d4b1174c0 100644
--- a/clang/lib/Headers/CMakeLists.txt
+++ b/clang/lib/Headers/CMakeLists.txt
@@ -126,6 +126,7 @@ set(ppc_htm_files
 set(riscv_files
   riscv_bitmanip.h
   riscv_corev_alu.h
+  riscv_nds.h
   riscv_crypto.h
   riscv_ntlh.h
   sifive_vector.h
diff --git a/clang/lib/Headers/riscv_nds.h b/clang/lib/Headers/riscv_nds.h
new file mode 100644
index 0000000000000..dcce943f59b71
--- /dev/null
+++ b/clang/lib/Headers/riscv_nds.h
@@ -0,0 +1,47 @@
+/*===---- 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_xandesperf)
+
+#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__))
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_nds_ffb(unsigned long a,
+                                                          unsigned long b) {
+  return __builtin_riscv_nds_ffb(a, b);
+}
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_nds_ffzmism(unsigned long a,
+                                                              unsigned long b) {
+  return __builtin_riscv_nds_ffzmism(a, b);
+}
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_nds_ffmism(unsigned long a,
+                                                             unsigned long b) {
+  return __builtin_riscv_nds_ffmism(a, b);
+}
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_nds_flmism(unsigned long a,
+                                                             unsigned long b) {
+  return __builtin_riscv_nds_flmism(a, b);
+}
+
+#endif // defined(__riscv_nds)
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif // define __RISCV_NDS_H
diff --git a/clang/test/CodeGen/RISCV/riscv-xandesperf-c-api.c b/clang/test/CodeGen/RISCV/riscv-xandesperf-c-api.c
new file mode 100644
index 0000000000000..ab872d13cc1ea
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/riscv-xandesperf-c-api.c
@@ -0,0 +1,159 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
+// RUN: %clang_cc1 -triple riscv32 -target-feature +xandesperf -emit-llvm %s -o - \
+// RUN:     | FileCheck %s --check-prefix=CHECK-RV32
+// RUN: %clang_cc1 -triple riscv64 -target-feature +xandesperf -emit-llvm %s -o - \
+// RUN:     | FileCheck %s --check-prefix=CHECK-RV64
+
+#include <riscv_nds.h>
+
+// CHECK-RV32-LABEL: @test_ffb(
+// CHECK-RV32-NEXT:  entry:
+// CHECK-RV32-NEXT:    [[A_ADDR_I:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR_I:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[TMP0]], ptr [[A_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    store i32 [[TMP1]], ptr [[B_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP2:%.*]] = load i32, ptr [[A_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP3:%.*]] = load i32, ptr [[B_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP4:%.*]] = call i32 @llvm.riscv.nds.ffb.i32(i32 [[TMP2]], i32 [[TMP3]])
+// CHECK-RV32-NEXT:    ret i32 [[TMP4]]
+//
+// CHECK-RV64-LABEL: @test_ffb(
+// CHECK-RV64-NEXT:  entry:
+// CHECK-RV64-NEXT:    [[A_ADDR_I:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR_I:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[A_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    store i64 [[A:%.*]], ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[B:%.*]], ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP0:%.*]] = load i64, ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP1:%.*]] = load i64, ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[TMP0]], ptr [[A_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    store i64 [[TMP1]], ptr [[B_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP2:%.*]] = load i64, ptr [[A_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP3:%.*]] = load i64, ptr [[B_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP4:%.*]] = call i64 @llvm.riscv.nds.ffb.i64(i64 [[TMP2]], i64 [[TMP3]])
+// CHECK-RV64-NEXT:    ret i64 [[TMP4]]
+//
+long test_ffb(unsigned long a, unsigned long b) {
+  return __riscv_nds_ffb(a, b);
+}
+
+// CHECK-RV32-LABEL: @test_ffzmism(
+// CHECK-RV32-NEXT:  entry:
+// CHECK-RV32-NEXT:    [[A_ADDR_I:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR_I:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[TMP0]], ptr [[A_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    store i32 [[TMP1]], ptr [[B_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP2:%.*]] = load i32, ptr [[A_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP3:%.*]] = load i32, ptr [[B_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP4:%.*]] = call i32 @llvm.riscv.nds.ffzmism.i32(i32 [[TMP2]], i32 [[TMP3]])
+// CHECK-RV32-NEXT:    ret i32 [[TMP4]]
+//
+// CHECK-RV64-LABEL: @test_ffzmism(
+// CHECK-RV64-NEXT:  entry:
+// CHECK-RV64-NEXT:    [[A_ADDR_I:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR_I:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[A_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    store i64 [[A:%.*]], ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[B:%.*]], ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP0:%.*]] = load i64, ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP1:%.*]] = load i64, ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[TMP0]], ptr [[A_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    store i64 [[TMP1]], ptr [[B_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP2:%.*]] = load i64, ptr [[A_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP3:%.*]] = load i64, ptr [[B_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP4:%.*]] = call i64 @llvm.riscv.nds.ffzmism.i64(i64 [[TMP2]], i64 [[TMP3]])
+// CHECK-RV64-NEXT:    ret i64 [[TMP4]]
+//
+long test_ffzmism(unsigned long a, unsigned long b) {
+  return __riscv_nds_ffzmism(a, b);
+}
+
+// CHECK-RV32-LABEL: @test_ffmism(
+// CHECK-RV32-NEXT:  entry:
+// CHECK-RV32-NEXT:    [[A_ADDR_I:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR_I:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[TMP0]], ptr [[A_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    store i32 [[TMP1]], ptr [[B_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP2:%.*]] = load i32, ptr [[A_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP3:%.*]] = load i32, ptr [[B_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP4:%.*]] = call i32 @llvm.riscv.nds.ffmism.i32(i32 [[TMP2]], i32 [[TMP3]])
+// CHECK-RV32-NEXT:    ret i32 [[TMP4]]
+//
+// CHECK-RV64-LABEL: @test_ffmism(
+// CHECK-RV64-NEXT:  entry:
+// CHECK-RV64-NEXT:    [[A_ADDR_I:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR_I:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[A_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    store i64 [[A:%.*]], ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[B:%.*]], ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP0:%.*]] = load i64, ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP1:%.*]] = load i64, ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[TMP0]], ptr [[A_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    store i64 [[TMP1]], ptr [[B_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP2:%.*]] = load i64, ptr [[A_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP3:%.*]] = load i64, ptr [[B_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP4:%.*]] = call i64 @llvm.riscv.nds.ffmism.i64(i64 [[TMP2]], i64 [[TMP3]])
+// CHECK-RV64-NEXT:    ret i64 [[TMP4]]
+//
+long test_ffmism(unsigned long a, unsigned long b) {
+  return __riscv_nds_ffmism(a, b);
+}
+
+// CHECK-RV32-LABEL: @test_flmism(
+// CHECK-RV32-NEXT:  entry:
+// CHECK-RV32-NEXT:    [[A_ADDR_I:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR_I:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[TMP0]], ptr [[A_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    store i32 [[TMP1]], ptr [[B_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP2:%.*]] = load i32, ptr [[A_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP3:%.*]] = load i32, ptr [[B_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP4:%.*]] = call i32 @llvm.riscv.nds.flmism.i32(i32 [[TMP2]], i32 [[TMP3]])
+// CHECK-RV32-NEXT:    ret i32 [[TMP4]]
+//
+// CHECK-RV64-LABEL: @test_flmism(
+// CHECK-RV64-NEXT:  entry:
+// CHECK-RV64-NEXT:    [[A_ADDR_I:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR_I:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[A_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    store i64 [[A:%.*]], ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[B:%.*]], ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP0:%.*]] = load i64, ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP1:%.*]] = load i64, ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[TMP0]], ptr [[A_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    store i64 [[TMP1]], ptr [[B_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP2:%.*]] = load i64, ptr [[A_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP3:%.*]] = load i64, ptr [[B_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP4:%.*]] = call i64 @llvm.riscv.nds.flmism.i64(i64 [[TMP2]], i64 [[TMP3]])
+// CHECK-RV64-NEXT:    ret i64 [[TMP4]]
+//
+long test_flmism(unsigned long a, unsigned long b) {
+  return __riscv_nds_flmism(a, b);
+}
diff --git a/clang/test/CodeGen/RISCV/riscv-xandesperf.c b/clang/test/CodeGen/RISCV/riscv-xandesperf.c
new file mode 100644
index 0000000000000..d4273b295ed46
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/riscv-xandesperf.c
@@ -0,0 +1,109 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
+// RUN: %clang_cc1 -triple riscv32 -target-feature +xandesperf -emit-llvm %s -o - \
+// RUN:     | FileCheck %s --check-prefix=CHECK-RV32
+// RUN: %clang_cc1 -triple riscv64 -target-feature +xandesperf -emit-llvm %s -o - \
+// RUN:     | FileCheck %s --check-prefix=CHECK-RV64
+
+// CHECK-RV32-LABEL: @test_ffb(
+// CHECK-RV32-NEXT:  entry:
+// CHECK-RV32-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.nds.ffb.i32(i32 [[TMP0]], i32 [[TMP1]])
+// CHECK-RV32-NEXT:    ret i32 [[TMP2]]
+//
+// CHECK-RV64-LABEL: @test_ffb(
+// CHECK-RV64-NEXT:  entry:
+// CHECK-RV64-NEXT:    [[A_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    store i64 [[A:%.*]], ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[B:%.*]], ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP0:%.*]] = load i64, ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP1:%.*]] = load i64, ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP2:%.*]] = call i64 @llvm.riscv.nds.ffb.i64(i64 [[TMP0]], i64 [[TMP1]])
+// CHECK-RV64-NEXT:    ret i64 [[TMP2]]
+//
+long test_ffb(unsigned long a, unsigned long b) {
+  return __builtin_riscv_nds_ffb(a, b);
+}
+
+// CHECK-RV32-LABEL: @test_ffzmism(
+// CHECK-RV32-NEXT:  entry:
+// CHECK-RV32-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.nds.ffzmism.i32(i32 [[TMP0]], i32 [[TMP1]])
+// CHECK-RV32-NEXT:    ret i32 [[TMP2]]
+//
+// CHECK-RV64-LABEL: @test_ffzmism(
+// CHECK-RV64-NEXT:  entry:
+// CHECK-RV64-NEXT:    [[A_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    store i64 [[A:%.*]], ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[B:%.*]], ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP0:%.*]] = load i64, ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP1:%.*]] = load i64, ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP2:%.*]] = call i64 @llvm.riscv.nds.ffzmism.i64(i64 [[TMP0]], i64 [[TMP1]])
+// CHECK-RV64-NEXT:    ret i64 [[TMP2]]
+//
+long test_ffzmism(unsigned long a, unsigned long b) {
+  return __builtin_riscv_nds_ffzmism(a, b);
+}
+
+// CHECK-RV32-LABEL: @test_ffmism(
+// CHECK-RV32-NEXT:  entry:
+// CHECK-RV32-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.nds.ffmism.i32(i32 [[TMP0]], i32 [[TMP1]])
+// CHECK-RV32-NEXT:    ret i32 [[TMP2]]
+//
+// CHECK-RV64-LABEL: @test_ffmism(
+// CHECK-RV64-NEXT:  entry:
+// CHECK-RV64-NEXT:    [[A_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    store i64 [[A:%.*]], ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[B:%.*]], ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP0:%.*]] = load i64, ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP1:%.*]] = load i64, ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP2:%.*]] = call i64 @llvm.riscv.nds.ffmism.i64(i64 [[TMP0]], i64 [[TMP1]])
+// CHECK-RV64-NEXT:    ret i64 [[TMP2]]
+//
+long test_ffmism(unsigned long a, unsigned long b) {
+  return __builtin_riscv_nds_ffmism(a, b);
+}
+
+// CHECK-RV32-LABEL: @test_flmism(
+// CHECK-RV32-NEXT:  entry:
+// CHECK-RV32-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.nds.flmism.i32(i32 [[TMP0]], i32 [[TMP1]])
+// CHECK-RV32-NEXT:    ret i32 [[TMP2]]
+//
+// CHECK-RV64-LABEL: @test_flmism(
+// CHECK-RV64-NEXT:  entry:
+// CHECK-RV64-NEXT:    [[A_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    store i64 [[A:%.*]], ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[B:%.*]], ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP0:%.*]] = load i64, ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[T...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Jul 4, 2025

@llvm/pr-subscribers-llvm-ir

Author: Jim Lin (tclin914)

Changes

This patch adds the Clang builtins for byte comparision instructions in XAndesPerf Extension. These instructions are hardly generated by compiler. So we provide the Clang builtins for the user.


Patch is 25.93 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/147018.diff

11 Files Affected:

  • (modified) clang/include/clang/Basic/BuiltinsRISCV.td (+5)
  • (added) clang/include/clang/Basic/BuiltinsRISCVXAndes.td (+29)
  • (modified) clang/lib/CodeGen/TargetBuiltins/RISCV.cpp (+18)
  • (modified) clang/lib/Headers/CMakeLists.txt (+1)
  • (added) clang/lib/Headers/riscv_nds.h (+47)
  • (added) clang/test/CodeGen/RISCV/riscv-xandesperf-c-api.c (+159)
  • (added) clang/test/CodeGen/RISCV/riscv-xandesperf.c (+109)
  • (modified) llvm/include/llvm/IR/IntrinsicsRISCVXAndes.td (+14)
  • (modified) llvm/lib/Target/RISCV/RISCVInstrInfoXAndes.td (+11)
  • (modified) llvm/test/CodeGen/RISCV/rv32xandesperf.ll (+47)
  • (modified) llvm/test/CodeGen/RISCV/rv64xandesperf.ll (+47)
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..8ebcc18889d6c
--- /dev/null
+++ b/clang/include/clang/Basic/BuiltinsRISCVXAndes.td
@@ -0,0 +1,29 @@
+//==- 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 {
+//===----------------------------------------------------------------------===//
+// XAndesPerf extension.
+//===----------------------------------------------------------------------===//
+
+def ffb     : RISCVXAndesBuiltin<"long int(unsigned long int, unsigned long int)", "xandesperf">;
+def ffzmism : RISCVXAndesBuiltin<"long int(unsigned long int, unsigned long int)", "xandesperf">;
+def ffmism  : RISCVXAndesBuiltin<"long int(unsigned long int, unsigned long int)", "xandesperf">;
+def flmism  : RISCVXAndesBuiltin<"long int(unsigned long int, unsigned long int)", "xandesperf">;
+} // Attributes = [NoThrow, Const]
diff --git a/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp b/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
index 89e3f6f203df3..48a497b32a4a6 100644
--- a/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
@@ -413,6 +413,24 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
     ID = Intrinsic::riscv_cv_alu_subuRN;
     break;
 
+  // XAndesPerf
+  case RISCV::BI__builtin_riscv_nds_ffb:
+    IntrinsicTypes = {ResultType};
+    ID = Intrinsic::riscv_nds_ffb;
+    break;
+  case RISCV::BI__builtin_riscv_nds_ffzmism:
+    IntrinsicTypes = {ResultType};
+    ID = Intrinsic::riscv_nds_ffzmism;
+    break;
+  case RISCV::BI__builtin_riscv_nds_ffmism:
+    IntrinsicTypes = {ResultType};
+    ID = Intrinsic::riscv_nds_ffmism;
+    break;
+  case RISCV::BI__builtin_riscv_nds_flmism:
+    IntrinsicTypes = {ResultType};
+    ID = Intrinsic::riscv_nds_flmism;
+    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..44e2d4b1174c0 100644
--- a/clang/lib/Headers/CMakeLists.txt
+++ b/clang/lib/Headers/CMakeLists.txt
@@ -126,6 +126,7 @@ set(ppc_htm_files
 set(riscv_files
   riscv_bitmanip.h
   riscv_corev_alu.h
+  riscv_nds.h
   riscv_crypto.h
   riscv_ntlh.h
   sifive_vector.h
diff --git a/clang/lib/Headers/riscv_nds.h b/clang/lib/Headers/riscv_nds.h
new file mode 100644
index 0000000000000..dcce943f59b71
--- /dev/null
+++ b/clang/lib/Headers/riscv_nds.h
@@ -0,0 +1,47 @@
+/*===---- 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_xandesperf)
+
+#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__))
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_nds_ffb(unsigned long a,
+                                                          unsigned long b) {
+  return __builtin_riscv_nds_ffb(a, b);
+}
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_nds_ffzmism(unsigned long a,
+                                                              unsigned long b) {
+  return __builtin_riscv_nds_ffzmism(a, b);
+}
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_nds_ffmism(unsigned long a,
+                                                             unsigned long b) {
+  return __builtin_riscv_nds_ffmism(a, b);
+}
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_nds_flmism(unsigned long a,
+                                                             unsigned long b) {
+  return __builtin_riscv_nds_flmism(a, b);
+}
+
+#endif // defined(__riscv_nds)
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif // define __RISCV_NDS_H
diff --git a/clang/test/CodeGen/RISCV/riscv-xandesperf-c-api.c b/clang/test/CodeGen/RISCV/riscv-xandesperf-c-api.c
new file mode 100644
index 0000000000000..ab872d13cc1ea
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/riscv-xandesperf-c-api.c
@@ -0,0 +1,159 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
+// RUN: %clang_cc1 -triple riscv32 -target-feature +xandesperf -emit-llvm %s -o - \
+// RUN:     | FileCheck %s --check-prefix=CHECK-RV32
+// RUN: %clang_cc1 -triple riscv64 -target-feature +xandesperf -emit-llvm %s -o - \
+// RUN:     | FileCheck %s --check-prefix=CHECK-RV64
+
+#include <riscv_nds.h>
+
+// CHECK-RV32-LABEL: @test_ffb(
+// CHECK-RV32-NEXT:  entry:
+// CHECK-RV32-NEXT:    [[A_ADDR_I:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR_I:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[TMP0]], ptr [[A_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    store i32 [[TMP1]], ptr [[B_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP2:%.*]] = load i32, ptr [[A_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP3:%.*]] = load i32, ptr [[B_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP4:%.*]] = call i32 @llvm.riscv.nds.ffb.i32(i32 [[TMP2]], i32 [[TMP3]])
+// CHECK-RV32-NEXT:    ret i32 [[TMP4]]
+//
+// CHECK-RV64-LABEL: @test_ffb(
+// CHECK-RV64-NEXT:  entry:
+// CHECK-RV64-NEXT:    [[A_ADDR_I:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR_I:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[A_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    store i64 [[A:%.*]], ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[B:%.*]], ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP0:%.*]] = load i64, ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP1:%.*]] = load i64, ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[TMP0]], ptr [[A_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    store i64 [[TMP1]], ptr [[B_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP2:%.*]] = load i64, ptr [[A_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP3:%.*]] = load i64, ptr [[B_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP4:%.*]] = call i64 @llvm.riscv.nds.ffb.i64(i64 [[TMP2]], i64 [[TMP3]])
+// CHECK-RV64-NEXT:    ret i64 [[TMP4]]
+//
+long test_ffb(unsigned long a, unsigned long b) {
+  return __riscv_nds_ffb(a, b);
+}
+
+// CHECK-RV32-LABEL: @test_ffzmism(
+// CHECK-RV32-NEXT:  entry:
+// CHECK-RV32-NEXT:    [[A_ADDR_I:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR_I:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[TMP0]], ptr [[A_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    store i32 [[TMP1]], ptr [[B_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP2:%.*]] = load i32, ptr [[A_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP3:%.*]] = load i32, ptr [[B_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP4:%.*]] = call i32 @llvm.riscv.nds.ffzmism.i32(i32 [[TMP2]], i32 [[TMP3]])
+// CHECK-RV32-NEXT:    ret i32 [[TMP4]]
+//
+// CHECK-RV64-LABEL: @test_ffzmism(
+// CHECK-RV64-NEXT:  entry:
+// CHECK-RV64-NEXT:    [[A_ADDR_I:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR_I:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[A_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    store i64 [[A:%.*]], ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[B:%.*]], ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP0:%.*]] = load i64, ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP1:%.*]] = load i64, ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[TMP0]], ptr [[A_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    store i64 [[TMP1]], ptr [[B_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP2:%.*]] = load i64, ptr [[A_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP3:%.*]] = load i64, ptr [[B_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP4:%.*]] = call i64 @llvm.riscv.nds.ffzmism.i64(i64 [[TMP2]], i64 [[TMP3]])
+// CHECK-RV64-NEXT:    ret i64 [[TMP4]]
+//
+long test_ffzmism(unsigned long a, unsigned long b) {
+  return __riscv_nds_ffzmism(a, b);
+}
+
+// CHECK-RV32-LABEL: @test_ffmism(
+// CHECK-RV32-NEXT:  entry:
+// CHECK-RV32-NEXT:    [[A_ADDR_I:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR_I:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[TMP0]], ptr [[A_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    store i32 [[TMP1]], ptr [[B_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP2:%.*]] = load i32, ptr [[A_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP3:%.*]] = load i32, ptr [[B_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP4:%.*]] = call i32 @llvm.riscv.nds.ffmism.i32(i32 [[TMP2]], i32 [[TMP3]])
+// CHECK-RV32-NEXT:    ret i32 [[TMP4]]
+//
+// CHECK-RV64-LABEL: @test_ffmism(
+// CHECK-RV64-NEXT:  entry:
+// CHECK-RV64-NEXT:    [[A_ADDR_I:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR_I:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[A_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    store i64 [[A:%.*]], ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[B:%.*]], ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP0:%.*]] = load i64, ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP1:%.*]] = load i64, ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[TMP0]], ptr [[A_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    store i64 [[TMP1]], ptr [[B_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP2:%.*]] = load i64, ptr [[A_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP3:%.*]] = load i64, ptr [[B_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP4:%.*]] = call i64 @llvm.riscv.nds.ffmism.i64(i64 [[TMP2]], i64 [[TMP3]])
+// CHECK-RV64-NEXT:    ret i64 [[TMP4]]
+//
+long test_ffmism(unsigned long a, unsigned long b) {
+  return __riscv_nds_ffmism(a, b);
+}
+
+// CHECK-RV32-LABEL: @test_flmism(
+// CHECK-RV32-NEXT:  entry:
+// CHECK-RV32-NEXT:    [[A_ADDR_I:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR_I:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[TMP0]], ptr [[A_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    store i32 [[TMP1]], ptr [[B_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP2:%.*]] = load i32, ptr [[A_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP3:%.*]] = load i32, ptr [[B_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP4:%.*]] = call i32 @llvm.riscv.nds.flmism.i32(i32 [[TMP2]], i32 [[TMP3]])
+// CHECK-RV32-NEXT:    ret i32 [[TMP4]]
+//
+// CHECK-RV64-LABEL: @test_flmism(
+// CHECK-RV64-NEXT:  entry:
+// CHECK-RV64-NEXT:    [[A_ADDR_I:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR_I:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[A_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    store i64 [[A:%.*]], ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[B:%.*]], ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP0:%.*]] = load i64, ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP1:%.*]] = load i64, ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[TMP0]], ptr [[A_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    store i64 [[TMP1]], ptr [[B_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP2:%.*]] = load i64, ptr [[A_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP3:%.*]] = load i64, ptr [[B_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP4:%.*]] = call i64 @llvm.riscv.nds.flmism.i64(i64 [[TMP2]], i64 [[TMP3]])
+// CHECK-RV64-NEXT:    ret i64 [[TMP4]]
+//
+long test_flmism(unsigned long a, unsigned long b) {
+  return __riscv_nds_flmism(a, b);
+}
diff --git a/clang/test/CodeGen/RISCV/riscv-xandesperf.c b/clang/test/CodeGen/RISCV/riscv-xandesperf.c
new file mode 100644
index 0000000000000..d4273b295ed46
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/riscv-xandesperf.c
@@ -0,0 +1,109 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
+// RUN: %clang_cc1 -triple riscv32 -target-feature +xandesperf -emit-llvm %s -o - \
+// RUN:     | FileCheck %s --check-prefix=CHECK-RV32
+// RUN: %clang_cc1 -triple riscv64 -target-feature +xandesperf -emit-llvm %s -o - \
+// RUN:     | FileCheck %s --check-prefix=CHECK-RV64
+
+// CHECK-RV32-LABEL: @test_ffb(
+// CHECK-RV32-NEXT:  entry:
+// CHECK-RV32-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.nds.ffb.i32(i32 [[TMP0]], i32 [[TMP1]])
+// CHECK-RV32-NEXT:    ret i32 [[TMP2]]
+//
+// CHECK-RV64-LABEL: @test_ffb(
+// CHECK-RV64-NEXT:  entry:
+// CHECK-RV64-NEXT:    [[A_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    store i64 [[A:%.*]], ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[B:%.*]], ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP0:%.*]] = load i64, ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP1:%.*]] = load i64, ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP2:%.*]] = call i64 @llvm.riscv.nds.ffb.i64(i64 [[TMP0]], i64 [[TMP1]])
+// CHECK-RV64-NEXT:    ret i64 [[TMP2]]
+//
+long test_ffb(unsigned long a, unsigned long b) {
+  return __builtin_riscv_nds_ffb(a, b);
+}
+
+// CHECK-RV32-LABEL: @test_ffzmism(
+// CHECK-RV32-NEXT:  entry:
+// CHECK-RV32-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.nds.ffzmism.i32(i32 [[TMP0]], i32 [[TMP1]])
+// CHECK-RV32-NEXT:    ret i32 [[TMP2]]
+//
+// CHECK-RV64-LABEL: @test_ffzmism(
+// CHECK-RV64-NEXT:  entry:
+// CHECK-RV64-NEXT:    [[A_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    store i64 [[A:%.*]], ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[B:%.*]], ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP0:%.*]] = load i64, ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP1:%.*]] = load i64, ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP2:%.*]] = call i64 @llvm.riscv.nds.ffzmism.i64(i64 [[TMP0]], i64 [[TMP1]])
+// CHECK-RV64-NEXT:    ret i64 [[TMP2]]
+//
+long test_ffzmism(unsigned long a, unsigned long b) {
+  return __builtin_riscv_nds_ffzmism(a, b);
+}
+
+// CHECK-RV32-LABEL: @test_ffmism(
+// CHECK-RV32-NEXT:  entry:
+// CHECK-RV32-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.nds.ffmism.i32(i32 [[TMP0]], i32 [[TMP1]])
+// CHECK-RV32-NEXT:    ret i32 [[TMP2]]
+//
+// CHECK-RV64-LABEL: @test_ffmism(
+// CHECK-RV64-NEXT:  entry:
+// CHECK-RV64-NEXT:    [[A_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    store i64 [[A:%.*]], ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[B:%.*]], ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP0:%.*]] = load i64, ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP1:%.*]] = load i64, ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP2:%.*]] = call i64 @llvm.riscv.nds.ffmism.i64(i64 [[TMP0]], i64 [[TMP1]])
+// CHECK-RV64-NEXT:    ret i64 [[TMP2]]
+//
+long test_ffmism(unsigned long a, unsigned long b) {
+  return __builtin_riscv_nds_ffmism(a, b);
+}
+
+// CHECK-RV32-LABEL: @test_flmism(
+// CHECK-RV32-NEXT:  entry:
+// CHECK-RV32-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.nds.flmism.i32(i32 [[TMP0]], i32 [[TMP1]])
+// CHECK-RV32-NEXT:    ret i32 [[TMP2]]
+//
+// CHECK-RV64-LABEL: @test_flmism(
+// CHECK-RV64-NEXT:  entry:
+// CHECK-RV64-NEXT:    [[A_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    store i64 [[A:%.*]], ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[B:%.*]], ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP0:%.*]] = load i64, ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[T...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Jul 4, 2025

@llvm/pr-subscribers-backend-x86

Author: Jim Lin (tclin914)

Changes

This patch adds the Clang builtins for byte comparision instructions in XAndesPerf Extension. These instructions are hardly generated by compiler. So we provide the Clang builtins for the user.


Patch is 25.93 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/147018.diff

11 Files Affected:

  • (modified) clang/include/clang/Basic/BuiltinsRISCV.td (+5)
  • (added) clang/include/clang/Basic/BuiltinsRISCVXAndes.td (+29)
  • (modified) clang/lib/CodeGen/TargetBuiltins/RISCV.cpp (+18)
  • (modified) clang/lib/Headers/CMakeLists.txt (+1)
  • (added) clang/lib/Headers/riscv_nds.h (+47)
  • (added) clang/test/CodeGen/RISCV/riscv-xandesperf-c-api.c (+159)
  • (added) clang/test/CodeGen/RISCV/riscv-xandesperf.c (+109)
  • (modified) llvm/include/llvm/IR/IntrinsicsRISCVXAndes.td (+14)
  • (modified) llvm/lib/Target/RISCV/RISCVInstrInfoXAndes.td (+11)
  • (modified) llvm/test/CodeGen/RISCV/rv32xandesperf.ll (+47)
  • (modified) llvm/test/CodeGen/RISCV/rv64xandesperf.ll (+47)
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..8ebcc18889d6c
--- /dev/null
+++ b/clang/include/clang/Basic/BuiltinsRISCVXAndes.td
@@ -0,0 +1,29 @@
+//==- 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 {
+//===----------------------------------------------------------------------===//
+// XAndesPerf extension.
+//===----------------------------------------------------------------------===//
+
+def ffb     : RISCVXAndesBuiltin<"long int(unsigned long int, unsigned long int)", "xandesperf">;
+def ffzmism : RISCVXAndesBuiltin<"long int(unsigned long int, unsigned long int)", "xandesperf">;
+def ffmism  : RISCVXAndesBuiltin<"long int(unsigned long int, unsigned long int)", "xandesperf">;
+def flmism  : RISCVXAndesBuiltin<"long int(unsigned long int, unsigned long int)", "xandesperf">;
+} // Attributes = [NoThrow, Const]
diff --git a/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp b/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
index 89e3f6f203df3..48a497b32a4a6 100644
--- a/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
@@ -413,6 +413,24 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
     ID = Intrinsic::riscv_cv_alu_subuRN;
     break;
 
+  // XAndesPerf
+  case RISCV::BI__builtin_riscv_nds_ffb:
+    IntrinsicTypes = {ResultType};
+    ID = Intrinsic::riscv_nds_ffb;
+    break;
+  case RISCV::BI__builtin_riscv_nds_ffzmism:
+    IntrinsicTypes = {ResultType};
+    ID = Intrinsic::riscv_nds_ffzmism;
+    break;
+  case RISCV::BI__builtin_riscv_nds_ffmism:
+    IntrinsicTypes = {ResultType};
+    ID = Intrinsic::riscv_nds_ffmism;
+    break;
+  case RISCV::BI__builtin_riscv_nds_flmism:
+    IntrinsicTypes = {ResultType};
+    ID = Intrinsic::riscv_nds_flmism;
+    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..44e2d4b1174c0 100644
--- a/clang/lib/Headers/CMakeLists.txt
+++ b/clang/lib/Headers/CMakeLists.txt
@@ -126,6 +126,7 @@ set(ppc_htm_files
 set(riscv_files
   riscv_bitmanip.h
   riscv_corev_alu.h
+  riscv_nds.h
   riscv_crypto.h
   riscv_ntlh.h
   sifive_vector.h
diff --git a/clang/lib/Headers/riscv_nds.h b/clang/lib/Headers/riscv_nds.h
new file mode 100644
index 0000000000000..dcce943f59b71
--- /dev/null
+++ b/clang/lib/Headers/riscv_nds.h
@@ -0,0 +1,47 @@
+/*===---- 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_xandesperf)
+
+#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__))
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_nds_ffb(unsigned long a,
+                                                          unsigned long b) {
+  return __builtin_riscv_nds_ffb(a, b);
+}
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_nds_ffzmism(unsigned long a,
+                                                              unsigned long b) {
+  return __builtin_riscv_nds_ffzmism(a, b);
+}
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_nds_ffmism(unsigned long a,
+                                                             unsigned long b) {
+  return __builtin_riscv_nds_ffmism(a, b);
+}
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_nds_flmism(unsigned long a,
+                                                             unsigned long b) {
+  return __builtin_riscv_nds_flmism(a, b);
+}
+
+#endif // defined(__riscv_nds)
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif // define __RISCV_NDS_H
diff --git a/clang/test/CodeGen/RISCV/riscv-xandesperf-c-api.c b/clang/test/CodeGen/RISCV/riscv-xandesperf-c-api.c
new file mode 100644
index 0000000000000..ab872d13cc1ea
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/riscv-xandesperf-c-api.c
@@ -0,0 +1,159 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
+// RUN: %clang_cc1 -triple riscv32 -target-feature +xandesperf -emit-llvm %s -o - \
+// RUN:     | FileCheck %s --check-prefix=CHECK-RV32
+// RUN: %clang_cc1 -triple riscv64 -target-feature +xandesperf -emit-llvm %s -o - \
+// RUN:     | FileCheck %s --check-prefix=CHECK-RV64
+
+#include <riscv_nds.h>
+
+// CHECK-RV32-LABEL: @test_ffb(
+// CHECK-RV32-NEXT:  entry:
+// CHECK-RV32-NEXT:    [[A_ADDR_I:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR_I:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[TMP0]], ptr [[A_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    store i32 [[TMP1]], ptr [[B_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP2:%.*]] = load i32, ptr [[A_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP3:%.*]] = load i32, ptr [[B_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP4:%.*]] = call i32 @llvm.riscv.nds.ffb.i32(i32 [[TMP2]], i32 [[TMP3]])
+// CHECK-RV32-NEXT:    ret i32 [[TMP4]]
+//
+// CHECK-RV64-LABEL: @test_ffb(
+// CHECK-RV64-NEXT:  entry:
+// CHECK-RV64-NEXT:    [[A_ADDR_I:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR_I:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[A_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    store i64 [[A:%.*]], ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[B:%.*]], ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP0:%.*]] = load i64, ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP1:%.*]] = load i64, ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[TMP0]], ptr [[A_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    store i64 [[TMP1]], ptr [[B_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP2:%.*]] = load i64, ptr [[A_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP3:%.*]] = load i64, ptr [[B_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP4:%.*]] = call i64 @llvm.riscv.nds.ffb.i64(i64 [[TMP2]], i64 [[TMP3]])
+// CHECK-RV64-NEXT:    ret i64 [[TMP4]]
+//
+long test_ffb(unsigned long a, unsigned long b) {
+  return __riscv_nds_ffb(a, b);
+}
+
+// CHECK-RV32-LABEL: @test_ffzmism(
+// CHECK-RV32-NEXT:  entry:
+// CHECK-RV32-NEXT:    [[A_ADDR_I:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR_I:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[TMP0]], ptr [[A_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    store i32 [[TMP1]], ptr [[B_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP2:%.*]] = load i32, ptr [[A_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP3:%.*]] = load i32, ptr [[B_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP4:%.*]] = call i32 @llvm.riscv.nds.ffzmism.i32(i32 [[TMP2]], i32 [[TMP3]])
+// CHECK-RV32-NEXT:    ret i32 [[TMP4]]
+//
+// CHECK-RV64-LABEL: @test_ffzmism(
+// CHECK-RV64-NEXT:  entry:
+// CHECK-RV64-NEXT:    [[A_ADDR_I:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR_I:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[A_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    store i64 [[A:%.*]], ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[B:%.*]], ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP0:%.*]] = load i64, ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP1:%.*]] = load i64, ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[TMP0]], ptr [[A_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    store i64 [[TMP1]], ptr [[B_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP2:%.*]] = load i64, ptr [[A_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP3:%.*]] = load i64, ptr [[B_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP4:%.*]] = call i64 @llvm.riscv.nds.ffzmism.i64(i64 [[TMP2]], i64 [[TMP3]])
+// CHECK-RV64-NEXT:    ret i64 [[TMP4]]
+//
+long test_ffzmism(unsigned long a, unsigned long b) {
+  return __riscv_nds_ffzmism(a, b);
+}
+
+// CHECK-RV32-LABEL: @test_ffmism(
+// CHECK-RV32-NEXT:  entry:
+// CHECK-RV32-NEXT:    [[A_ADDR_I:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR_I:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[TMP0]], ptr [[A_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    store i32 [[TMP1]], ptr [[B_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP2:%.*]] = load i32, ptr [[A_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP3:%.*]] = load i32, ptr [[B_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP4:%.*]] = call i32 @llvm.riscv.nds.ffmism.i32(i32 [[TMP2]], i32 [[TMP3]])
+// CHECK-RV32-NEXT:    ret i32 [[TMP4]]
+//
+// CHECK-RV64-LABEL: @test_ffmism(
+// CHECK-RV64-NEXT:  entry:
+// CHECK-RV64-NEXT:    [[A_ADDR_I:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR_I:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[A_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    store i64 [[A:%.*]], ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[B:%.*]], ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP0:%.*]] = load i64, ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP1:%.*]] = load i64, ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[TMP0]], ptr [[A_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    store i64 [[TMP1]], ptr [[B_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP2:%.*]] = load i64, ptr [[A_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP3:%.*]] = load i64, ptr [[B_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP4:%.*]] = call i64 @llvm.riscv.nds.ffmism.i64(i64 [[TMP2]], i64 [[TMP3]])
+// CHECK-RV64-NEXT:    ret i64 [[TMP4]]
+//
+long test_ffmism(unsigned long a, unsigned long b) {
+  return __riscv_nds_ffmism(a, b);
+}
+
+// CHECK-RV32-LABEL: @test_flmism(
+// CHECK-RV32-NEXT:  entry:
+// CHECK-RV32-NEXT:    [[A_ADDR_I:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR_I:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[TMP0]], ptr [[A_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    store i32 [[TMP1]], ptr [[B_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP2:%.*]] = load i32, ptr [[A_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP3:%.*]] = load i32, ptr [[B_ADDR_I]], align 4
+// CHECK-RV32-NEXT:    [[TMP4:%.*]] = call i32 @llvm.riscv.nds.flmism.i32(i32 [[TMP2]], i32 [[TMP3]])
+// CHECK-RV32-NEXT:    ret i32 [[TMP4]]
+//
+// CHECK-RV64-LABEL: @test_flmism(
+// CHECK-RV64-NEXT:  entry:
+// CHECK-RV64-NEXT:    [[A_ADDR_I:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR_I:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[A_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    store i64 [[A:%.*]], ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[B:%.*]], ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP0:%.*]] = load i64, ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP1:%.*]] = load i64, ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[TMP0]], ptr [[A_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    store i64 [[TMP1]], ptr [[B_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP2:%.*]] = load i64, ptr [[A_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP3:%.*]] = load i64, ptr [[B_ADDR_I]], align 8
+// CHECK-RV64-NEXT:    [[TMP4:%.*]] = call i64 @llvm.riscv.nds.flmism.i64(i64 [[TMP2]], i64 [[TMP3]])
+// CHECK-RV64-NEXT:    ret i64 [[TMP4]]
+//
+long test_flmism(unsigned long a, unsigned long b) {
+  return __riscv_nds_flmism(a, b);
+}
diff --git a/clang/test/CodeGen/RISCV/riscv-xandesperf.c b/clang/test/CodeGen/RISCV/riscv-xandesperf.c
new file mode 100644
index 0000000000000..d4273b295ed46
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/riscv-xandesperf.c
@@ -0,0 +1,109 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
+// RUN: %clang_cc1 -triple riscv32 -target-feature +xandesperf -emit-llvm %s -o - \
+// RUN:     | FileCheck %s --check-prefix=CHECK-RV32
+// RUN: %clang_cc1 -triple riscv64 -target-feature +xandesperf -emit-llvm %s -o - \
+// RUN:     | FileCheck %s --check-prefix=CHECK-RV64
+
+// CHECK-RV32-LABEL: @test_ffb(
+// CHECK-RV32-NEXT:  entry:
+// CHECK-RV32-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.nds.ffb.i32(i32 [[TMP0]], i32 [[TMP1]])
+// CHECK-RV32-NEXT:    ret i32 [[TMP2]]
+//
+// CHECK-RV64-LABEL: @test_ffb(
+// CHECK-RV64-NEXT:  entry:
+// CHECK-RV64-NEXT:    [[A_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    store i64 [[A:%.*]], ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[B:%.*]], ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP0:%.*]] = load i64, ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP1:%.*]] = load i64, ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP2:%.*]] = call i64 @llvm.riscv.nds.ffb.i64(i64 [[TMP0]], i64 [[TMP1]])
+// CHECK-RV64-NEXT:    ret i64 [[TMP2]]
+//
+long test_ffb(unsigned long a, unsigned long b) {
+  return __builtin_riscv_nds_ffb(a, b);
+}
+
+// CHECK-RV32-LABEL: @test_ffzmism(
+// CHECK-RV32-NEXT:  entry:
+// CHECK-RV32-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.nds.ffzmism.i32(i32 [[TMP0]], i32 [[TMP1]])
+// CHECK-RV32-NEXT:    ret i32 [[TMP2]]
+//
+// CHECK-RV64-LABEL: @test_ffzmism(
+// CHECK-RV64-NEXT:  entry:
+// CHECK-RV64-NEXT:    [[A_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    store i64 [[A:%.*]], ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[B:%.*]], ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP0:%.*]] = load i64, ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP1:%.*]] = load i64, ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP2:%.*]] = call i64 @llvm.riscv.nds.ffzmism.i64(i64 [[TMP0]], i64 [[TMP1]])
+// CHECK-RV64-NEXT:    ret i64 [[TMP2]]
+//
+long test_ffzmism(unsigned long a, unsigned long b) {
+  return __builtin_riscv_nds_ffzmism(a, b);
+}
+
+// CHECK-RV32-LABEL: @test_ffmism(
+// CHECK-RV32-NEXT:  entry:
+// CHECK-RV32-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.nds.ffmism.i32(i32 [[TMP0]], i32 [[TMP1]])
+// CHECK-RV32-NEXT:    ret i32 [[TMP2]]
+//
+// CHECK-RV64-LABEL: @test_ffmism(
+// CHECK-RV64-NEXT:  entry:
+// CHECK-RV64-NEXT:    [[A_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    store i64 [[A:%.*]], ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[B:%.*]], ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP0:%.*]] = load i64, ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP1:%.*]] = load i64, ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP2:%.*]] = call i64 @llvm.riscv.nds.ffmism.i64(i64 [[TMP0]], i64 [[TMP1]])
+// CHECK-RV64-NEXT:    ret i64 [[TMP2]]
+//
+long test_ffmism(unsigned long a, unsigned long b) {
+  return __builtin_riscv_nds_ffmism(a, b);
+}
+
+// CHECK-RV32-LABEL: @test_flmism(
+// CHECK-RV32-NEXT:  entry:
+// CHECK-RV32-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-RV32-NEXT:    store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-RV32-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.nds.flmism.i32(i32 [[TMP0]], i32 [[TMP1]])
+// CHECK-RV32-NEXT:    ret i32 [[TMP2]]
+//
+// CHECK-RV64-LABEL: @test_flmism(
+// CHECK-RV64-NEXT:  entry:
+// CHECK-RV64-NEXT:    [[A_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    [[B_ADDR:%.*]] = alloca i64, align 8
+// CHECK-RV64-NEXT:    store i64 [[A:%.*]], ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    store i64 [[B:%.*]], ptr [[B_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[TMP0:%.*]] = load i64, ptr [[A_ADDR]], align 8
+// CHECK-RV64-NEXT:    [[T...
[truncated]

// XAndesPerf extension.
//===----------------------------------------------------------------------===//

def ffb : RISCVXAndesBuiltin<"long int(unsigned long int, unsigned long int)", "xandesperf">;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have 32/64 versions just like clz, orc.b?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, we did not plan to provide both 32-bit and 64-bit versions for RV64. The 32-bit version would be only for RV32, and the 64-bit version is for RV64.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:RISC-V backend:X86 clang:codegen IR generation bugs: mangling, exceptions, etc. clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:headers Headers provided by Clang, e.g. for intrinsics clang Clang issues not falling into any other category llvm:ir
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants