-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[RISCV] Implement Clang Builtins for XCValu Extension in CV32E40P #100684
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
Conversation
@llvm/pr-subscribers-clang @llvm/pr-subscribers-backend-risc-v Author: None (realqhc) ChangesThis commit adds the Clang Builtins, C API header and relevant tests for XCValu extension. Spec: https://github.com/openhwgroup/core-v-sw/blob/master/specifications/corev-builtin-spec.md Contributor: @melonedo, @PaoloS02 Patch is 42.99 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/100684.diff 12 Files Affected:
diff --git a/clang/include/clang/Basic/BuiltinsRISCVXCV.def b/clang/include/clang/Basic/BuiltinsRISCVXCV.def
new file mode 100644
index 0000000000000..29c59cdf005d0
--- /dev/null
+++ b/clang/include/clang/Basic/BuiltinsRISCVXCV.def
@@ -0,0 +1,41 @@
+//==- BuiltinsRISCVXCV.def - RISC-V CORE-V 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 CORE-V-specific builtin function database. Users of
+// this file must define the BUILTIN macro to make use of this information.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(BUILTIN) && !defined(TARGET_BUILTIN)
+# define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) BUILTIN(ID, TYPE, ATTRS)
+#endif
+
+TARGET_BUILTIN(alu_slet, "ZiZiZi", "nc", "xcvalu")
+TARGET_BUILTIN(alu_sletu, "ZiUZiUZi", "nc", "xcvalu")
+TARGET_BUILTIN(alu_min, "ZiZiZi", "nc", "xcvalu")
+TARGET_BUILTIN(alu_minu, "UZiUZiUZi", "nc", "xcvalu")
+TARGET_BUILTIN(alu_max, "ZiZiZi", "nc", "xcvalu")
+TARGET_BUILTIN(alu_maxu, "UZiUZiUZi", "nc", "xcvalu")
+TARGET_BUILTIN(alu_exths, "Zis", "nc", "xcvalu")
+TARGET_BUILTIN(alu_exthz, "UZiUs", "nc", "xcvalu")
+TARGET_BUILTIN(alu_extbs, "Zic", "nc", "xcvalu")
+TARGET_BUILTIN(alu_extbz, "UZiUc", "nc", "xcvalu")
+
+TARGET_BUILTIN(alu_clip, "ZiZiUZi", "nc", "xcvalu")
+TARGET_BUILTIN(alu_clipu, "UZiUZiUZi", "nc", "xcvalu")
+TARGET_BUILTIN(alu_addN, "ZiZiUZiUc", "nc", "xcvalu")
+TARGET_BUILTIN(alu_adduN, "UZiUZiUZiUc", "nc", "xcvalu")
+TARGET_BUILTIN(alu_addRN, "ZiZiZiUc", "nc", "xcvalu")
+TARGET_BUILTIN(alu_adduRN, "UZiUZiUZiUc", "nc", "xcvalu")
+TARGET_BUILTIN(alu_subN, "ZiZiUZiUc", "nc", "xcvalu")
+TARGET_BUILTIN(alu_subuN, "UZiUZiUZiUc", "nc", "xcvalu")
+TARGET_BUILTIN(alu_subRN, "ZiZiZiUc", "nc", "xcvalu")
+TARGET_BUILTIN(alu_subuRN, "UZiUZiUZiUc", "nc", "xcvalu")
+
+#undef BUILTIN
+#undef TARGET_BUILTIN
diff --git a/clang/include/clang/Basic/TargetBuiltins.h b/clang/include/clang/Basic/TargetBuiltins.h
index 4333830bf34f2..ea3ab9dd1b59b 100644
--- a/clang/include/clang/Basic/TargetBuiltins.h
+++ b/clang/include/clang/Basic/TargetBuiltins.h
@@ -152,12 +152,22 @@ namespace clang {
};
}
+ namespace RISCVXCV {
+ enum {
+ LastRVVBuiltin = RISCVVector::FirstTSBuiltin - 1,
+#define BUILTIN(ID, TYPE, ATTRS) BI__builtin_riscv_cv_##ID,
+#include "clang/Basic/BuiltinsRISCVXCV.def"
+ FirstTSBuiltin,
+ };
+ }
+
/// RISCV builtins
namespace RISCV {
enum {
LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1,
FirstRVVBuiltin = clang::Builtin::FirstTSBuiltin,
LastRVVBuiltin = RISCVVector::FirstTSBuiltin - 1,
+ LastXCVBuiltin = RISCVXCV::FirstTSBuiltin - 1,
#define BUILTIN(ID, TYPE, ATTRS) BI##ID,
#include "clang/Basic/BuiltinsRISCV.inc"
LastTSBuiltin
diff --git a/clang/include/module.modulemap b/clang/include/module.modulemap
index 00ecd47d35b62..7f8b721f275c6 100644
--- a/clang/include/module.modulemap
+++ b/clang/include/module.modulemap
@@ -55,6 +55,7 @@ module Clang_Basic {
textual header "clang/Basic/BuiltinsNEON.def"
textual header "clang/Basic/BuiltinsNVPTX.def"
textual header "clang/Basic/BuiltinsPPC.def"
+ textual header "Basic/BuiltinsRISCVXCV.def"
textual header "clang/Basic/BuiltinsRISCVVector.def"
textual header "clang/Basic/BuiltinsSME.def"
textual header "clang/Basic/BuiltinsSVE.def"
diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp
index 41d836330b38c..05016095b88aa 100644
--- a/clang/lib/Basic/Targets/RISCV.cpp
+++ b/clang/lib/Basic/Targets/RISCV.cpp
@@ -231,6 +231,11 @@ static constexpr Builtin::Info BuiltinInfo[] = {
{#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#include "clang/Basic/BuiltinsRISCVVector.def"
#define BUILTIN(ID, TYPE, ATTRS) \
+ {"__builtin_riscv_cv_" #ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
+#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
+ {"__builtin_riscv_cv_" #ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
+#include "clang/Basic/BuiltinsRISCVXCV.def"
+#define BUILTIN(ID, TYPE, ATTRS) \ \
{#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
{#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 0c4d0efb70ea5..d37d1d420e860 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -21901,6 +21901,30 @@ Value *CodeGenFunction::EmitHexagonBuiltinExpr(unsigned BuiltinID,
return nullptr;
}
+static Value *EmitXCVIntrinsic(CodeGenFunction &CGF, unsigned BuiltinID,
+ unsigned IntrinsicID,
+ MutableArrayRef<Value *> Ops,
+ const CallExpr *E) {
+ llvm::Type *MachineType =
+ llvm::IntegerType::getInt32Ty(CGF.CGM.getLLVMContext());
+ for (unsigned i = 0, e = E->getNumArgs(); i != e; i++) {
+ if (Ops[i]->getType() != MachineType) {
+ QualType type = E->getArg(i)->getType();
+ assert((type->isSignedIntegerType() || type->isUnsignedIntegerType() ||
+ type->isPointerType()) &&
+ "Argument of Core-V builtin must have signed or unsigned integer "
+ "or Pointer type");
+ if (type->isSignedIntegerType()) {
+ Ops[i] = CGF.Builder.CreateSExt(Ops[i], MachineType);
+ } else if ((type->isUnsignedIntegerType())) {
+ Ops[i] = CGF.Builder.CreateZExt(Ops[i], MachineType);
+ }
+ }
+ }
+ llvm::Function *F = CGF.CGM.getIntrinsic(IntrinsicID);
+ return CGF.Builder.CreateCall(F, Ops);
+}
+
Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
const CallExpr *E,
ReturnValueSlot ReturnValue) {
@@ -22126,6 +22150,13 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
return Store;
}
+// Core-V
+#define BUILTIN(NAME, TYPE, ATTRS) \
+case RISCVXCV::BI__builtin_riscv_cv_##NAME: \
+ ID = Intrinsic::riscv_cv_##NAME; \
+ return EmitXCVIntrinsic(*this, BuiltinID, ID, Ops, E);
+#include "clang/Basic/BuiltinsRISCVXCV.def"
+
// Vector builtins are handled from here.
#include "clang/Basic/riscv_vector_builtin_cg.inc"
// SiFive Vector builtins are handled from here.
diff --git a/clang/lib/Headers/CMakeLists.txt b/clang/lib/Headers/CMakeLists.txt
index 89fa0ecd45eb4..76a82b845fe23 100644
--- a/clang/lib/Headers/CMakeLists.txt
+++ b/clang/lib/Headers/CMakeLists.txt
@@ -122,6 +122,7 @@ set(riscv_files
riscv_crypto.h
riscv_ntlh.h
sifive_vector.h
+ riscv_corev_alu.h
)
set(systemz_files
diff --git a/clang/lib/Headers/riscv_corev_alu.h b/clang/lib/Headers/riscv_corev_alu.h
new file mode 100644
index 0000000000000..fd6e7106c0981
--- /dev/null
+++ b/clang/lib/Headers/riscv_corev_alu.h
@@ -0,0 +1,111 @@
+/*===---- riscv_corev_alu.h - CORE-V ALU 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_COREV_ALU_H
+#define __RISCV_COREV_ALU_H
+
+#include <stdint.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#if defined(__riscv_xcvalu)
+
+#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__))
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_abs(long a) { return __builtin_abs(a); }
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_alu_slet(long a, long b) {
+ return __builtin_riscv_cv_alu_slet(a, b);
+}
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_alu_sletu(unsigned long a, unsigned long b) {
+ return __builtin_riscv_cv_alu_sletu(a, b);
+}
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_alu_min(long a, long b) {
+ return __builtin_riscv_cv_alu_min(a, b);
+}
+
+static __inline__ unsigned long __DEFAULT_FN_ATTRS __riscv_cv_alu_minu(unsigned long a, unsigned long b) {
+ return __builtin_riscv_cv_alu_minu(a, b);
+}
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_alu_max(long a, long b) {
+ return __builtin_riscv_cv_alu_max(a, b);
+}
+
+static __inline__ unsigned long __DEFAULT_FN_ATTRS __riscv_cv_alu_maxu(unsigned long a, unsigned long b) {
+ return __builtin_riscv_cv_alu_maxu(a, b);
+}
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_alu_exths(int16_t a) { return __builtin_riscv_cv_alu_exths(a); }
+
+static __inline__ unsigned long __DEFAULT_FN_ATTRS __riscv_cv_alu_exthz(uint16_t a) {
+ return __builtin_riscv_cv_alu_exthz(a);
+}
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_alu_extbs(int8_t a) { return __builtin_riscv_cv_alu_extbs(a); }
+
+static __inline__ unsigned long __DEFAULT_FN_ATTRS __riscv_cv_alu_extbz(uint8_t a) {
+ return __builtin_riscv_cv_alu_extbz(a);
+}
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_alu_clip(long a, unsigned long b) {
+ return __builtin_riscv_cv_alu_clip(a, b);
+}
+
+static __inline__ unsigned long __DEFAULT_FN_ATTRS __riscv_cv_alu_clipu(unsigned long a, unsigned long b) {
+ return __builtin_riscv_cv_alu_clipu(a, b);
+}
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_alu_addN(long a, long b, uint8_t shft) {
+ return __builtin_riscv_cv_alu_addN(a, b, shft);
+}
+
+static __inline__ unsigned long __DEFAULT_FN_ATTRS __riscv_cv_alu_adduN(unsigned long a, unsigned long b,
+ uint8_t shft) {
+ return __builtin_riscv_cv_alu_adduN(a, b, shft);
+}
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_alu_addRN(long a, long b, uint8_t shft) {
+ return __builtin_riscv_cv_alu_addRN(a, b, shft);
+}
+
+static __inline__ unsigned long __DEFAULT_FN_ATTRS __riscv_cv_alu_adduRN(unsigned long a, unsigned long b,
+ uint8_t shft) {
+ return __builtin_riscv_cv_alu_adduRN(a, b, shft);
+}
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_alu_subN(long a, long b, uint8_t shft) {
+ return __builtin_riscv_cv_alu_subN(a, b, shft);
+}
+
+static __inline__ unsigned long __DEFAULT_FN_ATTRS __riscv_cv_alu_subuN(unsigned long a, unsigned long b,
+ uint8_t shft) {
+ return __builtin_riscv_cv_alu_subuN(a, b, shft);
+}
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_alu_subRN(long a, long b, uint8_t shft) {
+ return __builtin_riscv_cv_alu_subRN(a, b, shft);
+}
+
+static __inline__ unsigned long __DEFAULT_FN_ATTRS __riscv_cv_alu_subuRN(unsigned long a, unsigned long b,
+ uint8_t shft) {
+ return __builtin_riscv_cv_alu_subuRN(a, b, shft);
+}
+
+#endif // defined(__riscv_xcvalu)
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif // define __RISCV_COREV_ALU_H
diff --git a/clang/test/CodeGen/RISCV/riscv-xcvalu-c-api.c b/clang/test/CodeGen/RISCV/riscv-xcvalu-c-api.c
new file mode 100644
index 0000000000000..d5c16fbe3d766
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/riscv-xcvalu-c-api.c
@@ -0,0 +1,126 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
+// RUN: %clang_cc1 -triple riscv32 -target-feature +xcvalu -emit-llvm %s -o - \
+// RUN: | FileCheck %s
+
+#include <stdint.h>
+#include <riscv_corev_alu.h>
+
+// CHECK-LABEL: @test_alu_slet
+// CHECK: @llvm.riscv.cv.alu.slet
+int test_alu_slet(int32_t a, int32_t b) {
+ return __riscv_cv_alu_slet(a, b);
+}
+
+// CHECK-LABEL: @test_alu_sletu
+// CHECK: @llvm.riscv.cv.alu.sletu
+int test_alu_sletu(uint32_t a, uint32_t b) {
+ return __riscv_cv_alu_sletu(a, b);
+}
+
+// CHECK-LABEL: @test_alu_min
+// CHECK: @llvm.riscv.cv.alu.min
+int test_alu_min(int32_t a, int32_t b) {
+ return __riscv_cv_alu_min(a, b);
+}
+
+// CHECK-LABEL: @test_alu_minu
+// CHECK: @llvm.riscv.cv.alu.minu
+int test_alu_minu(uint32_t a, uint32_t b) {
+ return __riscv_cv_alu_minu(a, b);
+}
+
+// CHECK-LABEL: @test_alu_max
+// CHECK: @llvm.riscv.cv.alu.max
+int test_alu_max(int32_t a, int32_t b) {
+ return __riscv_cv_alu_max(a, b);
+}
+
+// CHECK-LABEL: @test_alu_maxu
+// CHECK: @llvm.riscv.cv.alu.maxu
+int test_alu_maxu(uint32_t a, uint32_t b) {
+ return __riscv_cv_alu_maxu(a, b);
+}
+
+// CHECK-LABEL: @test_alu_exths
+// CHECK: @llvm.riscv.cv.alu.exths
+int test_alu_exths(int16_t a) {
+ return __riscv_cv_alu_exths(a);
+}
+
+// CHECK-LABEL: @test_alu_exthz
+// CHECK: @llvm.riscv.cv.alu.exthz
+int test_alu_exthz(uint16_t a) {
+ return __riscv_cv_alu_exthz(a);
+}
+
+// CHECK-LABEL: @test_alu_extbs
+// CHECK: @llvm.riscv.cv.alu.extbs
+int test_alu_extbs(int8_t a) {
+ return __riscv_cv_alu_extbs(a);
+}
+
+// CHECK-LABEL: @test_alu_extbz
+// CHECK: @llvm.riscv.cv.alu.extbz
+int test_alu_extbz(uint8_t a) {
+ return __riscv_cv_alu_extbz(a);
+}
+
+// CHECK-LABEL: @test_alu_clip
+// CHECK: @llvm.riscv.cv.alu.clip
+int test_alu_clip(int32_t a) {
+ return __riscv_cv_alu_clip(a, 0);
+}
+
+// CHECK-LABEL: @test_alu_clipu
+// CHECK: @llvm.riscv.cv.alu.clipu
+int test_alu_clipu(uint32_t a) {
+ return __riscv_cv_alu_clipu(a, 0);
+}
+
+// CHECK-LABEL: @test_alu_addN
+// CHECK: @llvm.riscv.cv.alu.addN
+int test_alu_addN(int32_t a, int32_t b) {
+ return __riscv_cv_alu_addN(a, b, 0);
+}
+
+// CHECK-LABEL: @test_alu_adduN
+// CHECK: @llvm.riscv.cv.alu.adduN
+int test_alu_adduN(uint32_t a, uint32_t b) {
+ return __riscv_cv_alu_adduN(a, b, 0);
+}
+
+// CHECK-LABEL: @test_alu_addRN
+// CHECK: @llvm.riscv.cv.alu.addRN
+int test_alu_addRN(int32_t a, int32_t b) {
+ return __riscv_cv_alu_addRN(a, b, 0);
+}
+
+// CHECK-LABEL: @test_alu_adduRN
+// CHECK: @llvm.riscv.cv.alu.adduRN
+int test_alu_adduRN(uint32_t a, uint32_t b) {
+ return __riscv_cv_alu_adduRN(a, b, 0);
+}
+
+// CHECK-LABEL: @test_alu_subN
+// CHECK: @llvm.riscv.cv.alu.subN
+int test_alu_subN(int32_t a, int32_t b) {
+ return __riscv_cv_alu_subN(a, b, 0);
+}
+
+// CHECK-LABEL: @test_alu_subuN
+// CHECK: @llvm.riscv.cv.alu.subuN
+int test_alu_subuN(uint32_t a, uint32_t b) {
+ return __riscv_cv_alu_subuN(a, b, 0);
+}
+
+// CHECK-LABEL: @test_alu_subRN
+// CHECK: @llvm.riscv.cv.alu.subRN
+int test_alu_subRN(int32_t a, int32_t b) {
+ return __riscv_cv_alu_subRN(a, b, 0);
+}
+
+// CHECK-LABEL: @test_alu_subuRN
+// CHECK: @llvm.riscv.cv.alu.subuRN
+int test_alu_subuRN(uint32_t a, uint32_t b) {
+ return __riscv_cv_alu_subuRN(a, b, 0);
+}
diff --git a/clang/test/CodeGen/RISCV/riscv-xcvalu.c b/clang/test/CodeGen/RISCV/riscv-xcvalu.c
new file mode 100644
index 0000000000000..a3b8c07f22c81
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/riscv-xcvalu.c
@@ -0,0 +1,303 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
+// RUN: %clang_cc1 -triple riscv32 -target-feature +xcvalu -emit-llvm %s -o - \
+// RUN: | FileCheck %s
+
+#include <stdint.h>
+
+// CHECK-LABEL: @test_abs(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.abs.i32(i32 [[TMP0]], i1 true)
+// CHECK-NEXT: ret i32 [[TMP1]]
+//
+int test_abs(int a) {
+ return __builtin_abs(a);
+}
+
+// CHECK-LABEL: @test_alu_slet(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.riscv.cv.alu.slet(i32 [[TMP0]], i32 [[TMP1]])
+// CHECK-NEXT: ret i32 [[TMP2]]
+//
+int test_alu_slet(int32_t a, int32_t b) {
+ return __builtin_riscv_cv_alu_slet(a, b);
+}
+
+// CHECK-LABEL: @test_alu_sletu(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.riscv.cv.alu.sletu(i32 [[TMP0]], i32 [[TMP1]])
+// CHECK-NEXT: ret i32 [[TMP2]]
+//
+int test_alu_sletu(uint32_t a, uint32_t b) {
+ return __builtin_riscv_cv_alu_sletu(a, b);
+}
+
+// CHECK-LABEL: @test_alu_min(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.riscv.cv.alu.min(i32 [[TMP0]], i32 [[TMP1]])
+// CHECK-NEXT: ret i32 [[TMP2]]
+//
+int test_alu_min(int32_t a, int32_t b) {
+ return __builtin_riscv_cv_alu_min(a, b);
+}
+
+// CHECK-LABEL: @test_alu_minu(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.riscv.cv.alu.minu(i32 [[TMP0]], i32 [[TMP1]])
+// CHECK-NEXT: ret i32 [[TMP2]]
+//
+int test_alu_minu(uint32_t a, uint32_t b) {
+ return __builtin_riscv_cv_alu_minu(a, b);
+}
+
+// CHECK-LABEL: @test_alu_max(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.riscv.cv.alu.max(i32 [[TMP0]], i32 [[TMP1]])
+// CHECK-NEXT: ret i32 [[TMP2]]
+//
+int test_alu_max(int32_t a, int32_t b) {
+ return __builtin_riscv_cv_alu_max(a, b);
+}
+
+// CHECK-LABEL: @test_alu_maxu(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.riscv.cv.alu.maxu(i32 [[TMP0]], i32 [[TMP1]])
+// CHECK-NEXT: ret i32 [[TMP2]]
+//
+int test_alu_maxu(uint32_t a, uint32_t b) {
+ return __builtin_riscv_cv_alu_maxu(a, b);
+}
+
+// CHECK-LABEL: @test_alu_exths(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i16, align 2
+// CHECK-NEXT: store i16 [[A:%.*]], ptr [[A_ADDR]], align 2
+// CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[A_ADDR]], align 2
+// CHECK-NEXT: [[TMP1:%.*]] = sext i16 [[TMP0]] to i32
+// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.riscv.cv.alu.exths(i32 [[TMP1]])
+// CHECK-NEXT: ret i32 [[TMP2]]
+//
+int test_alu_exths(int16_t a) {
+ return __builtin_riscv_cv_alu_exths(a);
+}
+
+// CHECK-LABEL: @test_alu_exthz(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i16, align 2
+// CHECK-NEXT: store i16 [[A:%.*]], ptr [[A_ADDR]], ali...
[truncated]
|
@llvm/pr-subscribers-backend-x86 Author: None (realqhc) ChangesThis commit adds the Clang Builtins, C API header and relevant tests for XCValu extension. Spec: https://github.com/openhwgroup/core-v-sw/blob/master/specifications/corev-builtin-spec.md Contributor: @melonedo, @PaoloS02 Patch is 42.99 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/100684.diff 12 Files Affected:
diff --git a/clang/include/clang/Basic/BuiltinsRISCVXCV.def b/clang/include/clang/Basic/BuiltinsRISCVXCV.def
new file mode 100644
index 0000000000000..29c59cdf005d0
--- /dev/null
+++ b/clang/include/clang/Basic/BuiltinsRISCVXCV.def
@@ -0,0 +1,41 @@
+//==- BuiltinsRISCVXCV.def - RISC-V CORE-V 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 CORE-V-specific builtin function database. Users of
+// this file must define the BUILTIN macro to make use of this information.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(BUILTIN) && !defined(TARGET_BUILTIN)
+# define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) BUILTIN(ID, TYPE, ATTRS)
+#endif
+
+TARGET_BUILTIN(alu_slet, "ZiZiZi", "nc", "xcvalu")
+TARGET_BUILTIN(alu_sletu, "ZiUZiUZi", "nc", "xcvalu")
+TARGET_BUILTIN(alu_min, "ZiZiZi", "nc", "xcvalu")
+TARGET_BUILTIN(alu_minu, "UZiUZiUZi", "nc", "xcvalu")
+TARGET_BUILTIN(alu_max, "ZiZiZi", "nc", "xcvalu")
+TARGET_BUILTIN(alu_maxu, "UZiUZiUZi", "nc", "xcvalu")
+TARGET_BUILTIN(alu_exths, "Zis", "nc", "xcvalu")
+TARGET_BUILTIN(alu_exthz, "UZiUs", "nc", "xcvalu")
+TARGET_BUILTIN(alu_extbs, "Zic", "nc", "xcvalu")
+TARGET_BUILTIN(alu_extbz, "UZiUc", "nc", "xcvalu")
+
+TARGET_BUILTIN(alu_clip, "ZiZiUZi", "nc", "xcvalu")
+TARGET_BUILTIN(alu_clipu, "UZiUZiUZi", "nc", "xcvalu")
+TARGET_BUILTIN(alu_addN, "ZiZiUZiUc", "nc", "xcvalu")
+TARGET_BUILTIN(alu_adduN, "UZiUZiUZiUc", "nc", "xcvalu")
+TARGET_BUILTIN(alu_addRN, "ZiZiZiUc", "nc", "xcvalu")
+TARGET_BUILTIN(alu_adduRN, "UZiUZiUZiUc", "nc", "xcvalu")
+TARGET_BUILTIN(alu_subN, "ZiZiUZiUc", "nc", "xcvalu")
+TARGET_BUILTIN(alu_subuN, "UZiUZiUZiUc", "nc", "xcvalu")
+TARGET_BUILTIN(alu_subRN, "ZiZiZiUc", "nc", "xcvalu")
+TARGET_BUILTIN(alu_subuRN, "UZiUZiUZiUc", "nc", "xcvalu")
+
+#undef BUILTIN
+#undef TARGET_BUILTIN
diff --git a/clang/include/clang/Basic/TargetBuiltins.h b/clang/include/clang/Basic/TargetBuiltins.h
index 4333830bf34f2..ea3ab9dd1b59b 100644
--- a/clang/include/clang/Basic/TargetBuiltins.h
+++ b/clang/include/clang/Basic/TargetBuiltins.h
@@ -152,12 +152,22 @@ namespace clang {
};
}
+ namespace RISCVXCV {
+ enum {
+ LastRVVBuiltin = RISCVVector::FirstTSBuiltin - 1,
+#define BUILTIN(ID, TYPE, ATTRS) BI__builtin_riscv_cv_##ID,
+#include "clang/Basic/BuiltinsRISCVXCV.def"
+ FirstTSBuiltin,
+ };
+ }
+
/// RISCV builtins
namespace RISCV {
enum {
LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1,
FirstRVVBuiltin = clang::Builtin::FirstTSBuiltin,
LastRVVBuiltin = RISCVVector::FirstTSBuiltin - 1,
+ LastXCVBuiltin = RISCVXCV::FirstTSBuiltin - 1,
#define BUILTIN(ID, TYPE, ATTRS) BI##ID,
#include "clang/Basic/BuiltinsRISCV.inc"
LastTSBuiltin
diff --git a/clang/include/module.modulemap b/clang/include/module.modulemap
index 00ecd47d35b62..7f8b721f275c6 100644
--- a/clang/include/module.modulemap
+++ b/clang/include/module.modulemap
@@ -55,6 +55,7 @@ module Clang_Basic {
textual header "clang/Basic/BuiltinsNEON.def"
textual header "clang/Basic/BuiltinsNVPTX.def"
textual header "clang/Basic/BuiltinsPPC.def"
+ textual header "Basic/BuiltinsRISCVXCV.def"
textual header "clang/Basic/BuiltinsRISCVVector.def"
textual header "clang/Basic/BuiltinsSME.def"
textual header "clang/Basic/BuiltinsSVE.def"
diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp
index 41d836330b38c..05016095b88aa 100644
--- a/clang/lib/Basic/Targets/RISCV.cpp
+++ b/clang/lib/Basic/Targets/RISCV.cpp
@@ -231,6 +231,11 @@ static constexpr Builtin::Info BuiltinInfo[] = {
{#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#include "clang/Basic/BuiltinsRISCVVector.def"
#define BUILTIN(ID, TYPE, ATTRS) \
+ {"__builtin_riscv_cv_" #ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
+#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
+ {"__builtin_riscv_cv_" #ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
+#include "clang/Basic/BuiltinsRISCVXCV.def"
+#define BUILTIN(ID, TYPE, ATTRS) \ \
{#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
{#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 0c4d0efb70ea5..d37d1d420e860 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -21901,6 +21901,30 @@ Value *CodeGenFunction::EmitHexagonBuiltinExpr(unsigned BuiltinID,
return nullptr;
}
+static Value *EmitXCVIntrinsic(CodeGenFunction &CGF, unsigned BuiltinID,
+ unsigned IntrinsicID,
+ MutableArrayRef<Value *> Ops,
+ const CallExpr *E) {
+ llvm::Type *MachineType =
+ llvm::IntegerType::getInt32Ty(CGF.CGM.getLLVMContext());
+ for (unsigned i = 0, e = E->getNumArgs(); i != e; i++) {
+ if (Ops[i]->getType() != MachineType) {
+ QualType type = E->getArg(i)->getType();
+ assert((type->isSignedIntegerType() || type->isUnsignedIntegerType() ||
+ type->isPointerType()) &&
+ "Argument of Core-V builtin must have signed or unsigned integer "
+ "or Pointer type");
+ if (type->isSignedIntegerType()) {
+ Ops[i] = CGF.Builder.CreateSExt(Ops[i], MachineType);
+ } else if ((type->isUnsignedIntegerType())) {
+ Ops[i] = CGF.Builder.CreateZExt(Ops[i], MachineType);
+ }
+ }
+ }
+ llvm::Function *F = CGF.CGM.getIntrinsic(IntrinsicID);
+ return CGF.Builder.CreateCall(F, Ops);
+}
+
Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
const CallExpr *E,
ReturnValueSlot ReturnValue) {
@@ -22126,6 +22150,13 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
return Store;
}
+// Core-V
+#define BUILTIN(NAME, TYPE, ATTRS) \
+case RISCVXCV::BI__builtin_riscv_cv_##NAME: \
+ ID = Intrinsic::riscv_cv_##NAME; \
+ return EmitXCVIntrinsic(*this, BuiltinID, ID, Ops, E);
+#include "clang/Basic/BuiltinsRISCVXCV.def"
+
// Vector builtins are handled from here.
#include "clang/Basic/riscv_vector_builtin_cg.inc"
// SiFive Vector builtins are handled from here.
diff --git a/clang/lib/Headers/CMakeLists.txt b/clang/lib/Headers/CMakeLists.txt
index 89fa0ecd45eb4..76a82b845fe23 100644
--- a/clang/lib/Headers/CMakeLists.txt
+++ b/clang/lib/Headers/CMakeLists.txt
@@ -122,6 +122,7 @@ set(riscv_files
riscv_crypto.h
riscv_ntlh.h
sifive_vector.h
+ riscv_corev_alu.h
)
set(systemz_files
diff --git a/clang/lib/Headers/riscv_corev_alu.h b/clang/lib/Headers/riscv_corev_alu.h
new file mode 100644
index 0000000000000..fd6e7106c0981
--- /dev/null
+++ b/clang/lib/Headers/riscv_corev_alu.h
@@ -0,0 +1,111 @@
+/*===---- riscv_corev_alu.h - CORE-V ALU 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_COREV_ALU_H
+#define __RISCV_COREV_ALU_H
+
+#include <stdint.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#if defined(__riscv_xcvalu)
+
+#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__))
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_abs(long a) { return __builtin_abs(a); }
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_alu_slet(long a, long b) {
+ return __builtin_riscv_cv_alu_slet(a, b);
+}
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_alu_sletu(unsigned long a, unsigned long b) {
+ return __builtin_riscv_cv_alu_sletu(a, b);
+}
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_alu_min(long a, long b) {
+ return __builtin_riscv_cv_alu_min(a, b);
+}
+
+static __inline__ unsigned long __DEFAULT_FN_ATTRS __riscv_cv_alu_minu(unsigned long a, unsigned long b) {
+ return __builtin_riscv_cv_alu_minu(a, b);
+}
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_alu_max(long a, long b) {
+ return __builtin_riscv_cv_alu_max(a, b);
+}
+
+static __inline__ unsigned long __DEFAULT_FN_ATTRS __riscv_cv_alu_maxu(unsigned long a, unsigned long b) {
+ return __builtin_riscv_cv_alu_maxu(a, b);
+}
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_alu_exths(int16_t a) { return __builtin_riscv_cv_alu_exths(a); }
+
+static __inline__ unsigned long __DEFAULT_FN_ATTRS __riscv_cv_alu_exthz(uint16_t a) {
+ return __builtin_riscv_cv_alu_exthz(a);
+}
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_alu_extbs(int8_t a) { return __builtin_riscv_cv_alu_extbs(a); }
+
+static __inline__ unsigned long __DEFAULT_FN_ATTRS __riscv_cv_alu_extbz(uint8_t a) {
+ return __builtin_riscv_cv_alu_extbz(a);
+}
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_alu_clip(long a, unsigned long b) {
+ return __builtin_riscv_cv_alu_clip(a, b);
+}
+
+static __inline__ unsigned long __DEFAULT_FN_ATTRS __riscv_cv_alu_clipu(unsigned long a, unsigned long b) {
+ return __builtin_riscv_cv_alu_clipu(a, b);
+}
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_alu_addN(long a, long b, uint8_t shft) {
+ return __builtin_riscv_cv_alu_addN(a, b, shft);
+}
+
+static __inline__ unsigned long __DEFAULT_FN_ATTRS __riscv_cv_alu_adduN(unsigned long a, unsigned long b,
+ uint8_t shft) {
+ return __builtin_riscv_cv_alu_adduN(a, b, shft);
+}
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_alu_addRN(long a, long b, uint8_t shft) {
+ return __builtin_riscv_cv_alu_addRN(a, b, shft);
+}
+
+static __inline__ unsigned long __DEFAULT_FN_ATTRS __riscv_cv_alu_adduRN(unsigned long a, unsigned long b,
+ uint8_t shft) {
+ return __builtin_riscv_cv_alu_adduRN(a, b, shft);
+}
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_alu_subN(long a, long b, uint8_t shft) {
+ return __builtin_riscv_cv_alu_subN(a, b, shft);
+}
+
+static __inline__ unsigned long __DEFAULT_FN_ATTRS __riscv_cv_alu_subuN(unsigned long a, unsigned long b,
+ uint8_t shft) {
+ return __builtin_riscv_cv_alu_subuN(a, b, shft);
+}
+
+static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_alu_subRN(long a, long b, uint8_t shft) {
+ return __builtin_riscv_cv_alu_subRN(a, b, shft);
+}
+
+static __inline__ unsigned long __DEFAULT_FN_ATTRS __riscv_cv_alu_subuRN(unsigned long a, unsigned long b,
+ uint8_t shft) {
+ return __builtin_riscv_cv_alu_subuRN(a, b, shft);
+}
+
+#endif // defined(__riscv_xcvalu)
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif // define __RISCV_COREV_ALU_H
diff --git a/clang/test/CodeGen/RISCV/riscv-xcvalu-c-api.c b/clang/test/CodeGen/RISCV/riscv-xcvalu-c-api.c
new file mode 100644
index 0000000000000..d5c16fbe3d766
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/riscv-xcvalu-c-api.c
@@ -0,0 +1,126 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
+// RUN: %clang_cc1 -triple riscv32 -target-feature +xcvalu -emit-llvm %s -o - \
+// RUN: | FileCheck %s
+
+#include <stdint.h>
+#include <riscv_corev_alu.h>
+
+// CHECK-LABEL: @test_alu_slet
+// CHECK: @llvm.riscv.cv.alu.slet
+int test_alu_slet(int32_t a, int32_t b) {
+ return __riscv_cv_alu_slet(a, b);
+}
+
+// CHECK-LABEL: @test_alu_sletu
+// CHECK: @llvm.riscv.cv.alu.sletu
+int test_alu_sletu(uint32_t a, uint32_t b) {
+ return __riscv_cv_alu_sletu(a, b);
+}
+
+// CHECK-LABEL: @test_alu_min
+// CHECK: @llvm.riscv.cv.alu.min
+int test_alu_min(int32_t a, int32_t b) {
+ return __riscv_cv_alu_min(a, b);
+}
+
+// CHECK-LABEL: @test_alu_minu
+// CHECK: @llvm.riscv.cv.alu.minu
+int test_alu_minu(uint32_t a, uint32_t b) {
+ return __riscv_cv_alu_minu(a, b);
+}
+
+// CHECK-LABEL: @test_alu_max
+// CHECK: @llvm.riscv.cv.alu.max
+int test_alu_max(int32_t a, int32_t b) {
+ return __riscv_cv_alu_max(a, b);
+}
+
+// CHECK-LABEL: @test_alu_maxu
+// CHECK: @llvm.riscv.cv.alu.maxu
+int test_alu_maxu(uint32_t a, uint32_t b) {
+ return __riscv_cv_alu_maxu(a, b);
+}
+
+// CHECK-LABEL: @test_alu_exths
+// CHECK: @llvm.riscv.cv.alu.exths
+int test_alu_exths(int16_t a) {
+ return __riscv_cv_alu_exths(a);
+}
+
+// CHECK-LABEL: @test_alu_exthz
+// CHECK: @llvm.riscv.cv.alu.exthz
+int test_alu_exthz(uint16_t a) {
+ return __riscv_cv_alu_exthz(a);
+}
+
+// CHECK-LABEL: @test_alu_extbs
+// CHECK: @llvm.riscv.cv.alu.extbs
+int test_alu_extbs(int8_t a) {
+ return __riscv_cv_alu_extbs(a);
+}
+
+// CHECK-LABEL: @test_alu_extbz
+// CHECK: @llvm.riscv.cv.alu.extbz
+int test_alu_extbz(uint8_t a) {
+ return __riscv_cv_alu_extbz(a);
+}
+
+// CHECK-LABEL: @test_alu_clip
+// CHECK: @llvm.riscv.cv.alu.clip
+int test_alu_clip(int32_t a) {
+ return __riscv_cv_alu_clip(a, 0);
+}
+
+// CHECK-LABEL: @test_alu_clipu
+// CHECK: @llvm.riscv.cv.alu.clipu
+int test_alu_clipu(uint32_t a) {
+ return __riscv_cv_alu_clipu(a, 0);
+}
+
+// CHECK-LABEL: @test_alu_addN
+// CHECK: @llvm.riscv.cv.alu.addN
+int test_alu_addN(int32_t a, int32_t b) {
+ return __riscv_cv_alu_addN(a, b, 0);
+}
+
+// CHECK-LABEL: @test_alu_adduN
+// CHECK: @llvm.riscv.cv.alu.adduN
+int test_alu_adduN(uint32_t a, uint32_t b) {
+ return __riscv_cv_alu_adduN(a, b, 0);
+}
+
+// CHECK-LABEL: @test_alu_addRN
+// CHECK: @llvm.riscv.cv.alu.addRN
+int test_alu_addRN(int32_t a, int32_t b) {
+ return __riscv_cv_alu_addRN(a, b, 0);
+}
+
+// CHECK-LABEL: @test_alu_adduRN
+// CHECK: @llvm.riscv.cv.alu.adduRN
+int test_alu_adduRN(uint32_t a, uint32_t b) {
+ return __riscv_cv_alu_adduRN(a, b, 0);
+}
+
+// CHECK-LABEL: @test_alu_subN
+// CHECK: @llvm.riscv.cv.alu.subN
+int test_alu_subN(int32_t a, int32_t b) {
+ return __riscv_cv_alu_subN(a, b, 0);
+}
+
+// CHECK-LABEL: @test_alu_subuN
+// CHECK: @llvm.riscv.cv.alu.subuN
+int test_alu_subuN(uint32_t a, uint32_t b) {
+ return __riscv_cv_alu_subuN(a, b, 0);
+}
+
+// CHECK-LABEL: @test_alu_subRN
+// CHECK: @llvm.riscv.cv.alu.subRN
+int test_alu_subRN(int32_t a, int32_t b) {
+ return __riscv_cv_alu_subRN(a, b, 0);
+}
+
+// CHECK-LABEL: @test_alu_subuRN
+// CHECK: @llvm.riscv.cv.alu.subuRN
+int test_alu_subuRN(uint32_t a, uint32_t b) {
+ return __riscv_cv_alu_subuRN(a, b, 0);
+}
diff --git a/clang/test/CodeGen/RISCV/riscv-xcvalu.c b/clang/test/CodeGen/RISCV/riscv-xcvalu.c
new file mode 100644
index 0000000000000..a3b8c07f22c81
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/riscv-xcvalu.c
@@ -0,0 +1,303 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
+// RUN: %clang_cc1 -triple riscv32 -target-feature +xcvalu -emit-llvm %s -o - \
+// RUN: | FileCheck %s
+
+#include <stdint.h>
+
+// CHECK-LABEL: @test_abs(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.abs.i32(i32 [[TMP0]], i1 true)
+// CHECK-NEXT: ret i32 [[TMP1]]
+//
+int test_abs(int a) {
+ return __builtin_abs(a);
+}
+
+// CHECK-LABEL: @test_alu_slet(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.riscv.cv.alu.slet(i32 [[TMP0]], i32 [[TMP1]])
+// CHECK-NEXT: ret i32 [[TMP2]]
+//
+int test_alu_slet(int32_t a, int32_t b) {
+ return __builtin_riscv_cv_alu_slet(a, b);
+}
+
+// CHECK-LABEL: @test_alu_sletu(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.riscv.cv.alu.sletu(i32 [[TMP0]], i32 [[TMP1]])
+// CHECK-NEXT: ret i32 [[TMP2]]
+//
+int test_alu_sletu(uint32_t a, uint32_t b) {
+ return __builtin_riscv_cv_alu_sletu(a, b);
+}
+
+// CHECK-LABEL: @test_alu_min(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.riscv.cv.alu.min(i32 [[TMP0]], i32 [[TMP1]])
+// CHECK-NEXT: ret i32 [[TMP2]]
+//
+int test_alu_min(int32_t a, int32_t b) {
+ return __builtin_riscv_cv_alu_min(a, b);
+}
+
+// CHECK-LABEL: @test_alu_minu(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.riscv.cv.alu.minu(i32 [[TMP0]], i32 [[TMP1]])
+// CHECK-NEXT: ret i32 [[TMP2]]
+//
+int test_alu_minu(uint32_t a, uint32_t b) {
+ return __builtin_riscv_cv_alu_minu(a, b);
+}
+
+// CHECK-LABEL: @test_alu_max(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.riscv.cv.alu.max(i32 [[TMP0]], i32 [[TMP1]])
+// CHECK-NEXT: ret i32 [[TMP2]]
+//
+int test_alu_max(int32_t a, int32_t b) {
+ return __builtin_riscv_cv_alu_max(a, b);
+}
+
+// CHECK-LABEL: @test_alu_maxu(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.riscv.cv.alu.maxu(i32 [[TMP0]], i32 [[TMP1]])
+// CHECK-NEXT: ret i32 [[TMP2]]
+//
+int test_alu_maxu(uint32_t a, uint32_t b) {
+ return __builtin_riscv_cv_alu_maxu(a, b);
+}
+
+// CHECK-LABEL: @test_alu_exths(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i16, align 2
+// CHECK-NEXT: store i16 [[A:%.*]], ptr [[A_ADDR]], align 2
+// CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[A_ADDR]], align 2
+// CHECK-NEXT: [[TMP1:%.*]] = sext i16 [[TMP0]] to i32
+// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.riscv.cv.alu.exths(i32 [[TMP1]])
+// CHECK-NEXT: ret i32 [[TMP2]]
+//
+int test_alu_exths(int16_t a) {
+ return __builtin_riscv_cv_alu_exths(a);
+}
+
+// CHECK-LABEL: @test_alu_exthz(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i16, align 2
+// CHECK-NEXT: store i16 [[A:%.*]], ptr [[A_ADDR]], ali...
[truncated]
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
5d0eb64
to
a989acc
Compare
a989acc
to
d2169ca
Compare
@@ -59,16 +59,26 @@ let TargetPrefix = "riscv" in { | |||
[IntrNoMem, IntrWillReturn, IntrSpeculatable, | |||
ImmArg<ArgIndex<1>>, ImmArg<ArgIndex<2>>]>; | |||
|
|||
def int_riscv_cv_alu_slet : ScalarCoreVAluGprGprIntrinsic; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need builtins or intrinsics for slet? We don't have builtins for slt/sltu.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @topperc
There are a few things going on here.
-
The naming of the corresponding instructions in the CORE-V ISA extension was changed from
slet
tosle
, andsletu
tosleu
. The CORE-V standard for builtins has not yet been updated to reflect this change. This needs to be fixed through OpenHW group's standardization processes (@PaoloS02 is leading this inside OpenHW Group). -
These instructions only exist for "less than or equal", there are no equivalents for other comparison predicates, hence just these two builtins mapping to the instructions.
-
LLVM and GCC for CORE-V are intended to be equivalent, and in GCC, having the builtin to generate the instruction is more efficient than using inline assembler. First the dataflow through the instruction is explicit, secondly the pattern for the functionality is exposed to GCC, potentially allowing the instruction to be generated automatically in other circumstances.
So in summary i) it's there because the CORE-V standard for builtins says it should be and ii) it's there to match GCC behavior.
Hope this is helpful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @topperc
There are a few things going on here.
The naming of the corresponding instructions in the CORE-V ISA extension was changed from
slet
tosle
, andsletu
tosleu
. The CORE-V standard for builtins has not yet been updated to reflect this change. This needs to be fixed through OpenHW group's standardization processes (@PaoloS02 is leading this inside OpenHW Group).These instructions only exist for "less than or equal", there are no equivalents for other comparison predicates, hence just these two builtins mapping to the instructions.
I was referring to the stand comparisons. We don't have builtins for writing slt, we expect the programmer to write (a< b) and the backend will figure it out. slte can be automatically selected from (a<=b). Why do we need a builtin too?
- LLVM and GCC for CORE-V are intended to be equivalent, and in GCC, having the builtin to generate the instruction is more efficient than using inline assembler. First the dataflow through the instruction is explicit, secondly the pattern for the functionality is exposed to GCC, potentially allowing the instruction to be generated automatically in other circumstances.
Since gcc already has the builtin, I guess we have to be source compatible. Would it be ok to map the builtin to (zext (icmp sle a,b) in IR and let the middle end and backend treat it like any other compare?
So in summary i) it's there because the CORE-V standard for builtins says it should be and ii) it's there to match GCC behavior.
Hope this is helpful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it too late to remove the builtin? I can't imagine there's much software out there actually using these that would be a pain to change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Especially if they're already being renamed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also note that conversations like this is why standard RISC-V builtins go through a review process seen by developers of both toolchains. I would encourage CORE-V to do the same if they don't want to be surprised by pushback for things that developers of certain toolchains think don't make sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @topperc
There are a few things going on here.
@topperc Thanks for this. Apologies if my original comment was a bit clumsy. I was trying to explain where we were, not where we should go!
- These instructions only exist for "less than or equal", there are no equivalents for other comparison predicates, hence just these two builtins mapping to the instructions.
I was referring to the stand comparisons. We don't have builtins for writing slt, we expect the programmer to write (a< b) and the backend will figure it out. slte can be automatically selected from (a<=b). Why do we need a builtin too?
I understand.
- LLVM and GCC for CORE-V are intended to be equivalent, and in GCC, having the builtin to generate the instruction is more efficient than using inline assembler. First the dataflow through the instruction is explicit, secondly the pattern for the functionality is exposed to GCC, potentially allowing the instruction to be generated automatically in other circumstances.
Since gcc already has the builtin, I guess we have to be source compatible. Would it be ok to map the builtin to (zext (icmp sle a,b) in IR and let the middle end and backend treat it like any other compare?
This is fine. We just want to make sure that any legacy code written for GCC is not too painful to switch to LLVM for the owners.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it too late to remove the builtin? I can't imagine there's much software out there actually using these that would be a pain to change.
@jrtc27 Thanks for the feedback. The problem with an open source core, is that you don't know who has picked it up and adopted it. This core is particularly attractive because of its verification status. I have come across one very large multinational (not an OpenHW member) using the core, without having made any public declaration that this is the core they are using.
We could try dropping it and see if anyone complains.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also note that conversations like this is why standard RISC-V builtins go through a review process seen by developers of both toolchains. I would encourage CORE-V to do the same if they don't want to be surprised by pushback for things that developers of certain toolchains think don't make sense.
@jrtc27 We have to put our hands up on this one. For a long time the CORE-V and its ancestors have only had GCC tool chains, so the engagement was with that community. The LLVM implementation is newer, but we should have reached out early in the project.
How would you suggest we progress given where we are?
@@ -59,16 +59,26 @@ let TargetPrefix = "riscv" in { | |||
[IntrNoMem, IntrWillReturn, IntrSpeculatable, | |||
ImmArg<ArgIndex<1>>, ImmArg<ArgIndex<2>>]>; | |||
|
|||
def int_riscv_cv_alu_slet : ScalarCoreVAluGprGprIntrinsic; | |||
def int_riscv_cv_alu_sletu : ScalarCoreVAluGprGprIntrinsic; | |||
def int_riscv_cv_alu_min : ScalarCoreVAluGprGprIntrinsic; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need builtins for max/min. You can express those directly in C and InstCombine will make llvm.min/max intrinsics.
def int_riscv_cv_alu_minu : ScalarCoreVAluGprGprIntrinsic; | ||
def int_riscv_cv_alu_max : ScalarCoreVAluGprGprIntrinsic; | ||
def int_riscv_cv_alu_maxu : ScalarCoreVAluGprGprIntrinsic; | ||
def int_riscv_cv_alu_exths : ScalarCoreVAluGprIntrinsic; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The extends can be directly expressed in IR with shifts or truncate+extend. I don't think we need intrinsics.
enum { | ||
LastRVVBuiltin = RISCVVector::FirstTSBuiltin - 1, | ||
#define BUILTIN(ID, TYPE, ATTRS) BI__builtin_riscv_cv_##ID, | ||
#include "clang/Basic/BuiltinsRISCVXCV.def" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we include BuiltinsRISCVXCV.def from BuiltinsRISCV.def and not create a new RISCVXCV namespace? RVV it separated because we use FirstRVVBuiltin and LastRVVBuiltin to catch all RVV builtins for some code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no BuiltinsRISCV.def and I can't find a way to make it work like BuiltinRISCVVector.def where rvv and sifive builtins can be in separate files (without modifying BuiltinsRISCV.td).
I have rewrite BuiltinsRISCVXCV.def in the same format as BuiltinsRISCV.td and included it in BuiltinsRISCV.td for now, I'm willing to explore further if there is better solution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I forgot that BuiltinsRISCV.def had been migrated to BuiltinsRISCV.td
//===----------------------------------------------------------------------===// | ||
// XCValu extension. | ||
//===----------------------------------------------------------------------===// | ||
def alu_slet : RISCXCVBuiltin<"int(int, int)", "xcvalu">; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did the intrinsics keep the 't' in their name even though the instruction was renamed here openhwgroup/cv32e40p#833?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will update the intrinsics accordingly after the documentation is renamed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would rather see them deleted. If it's possible to rename them then it's possible to remove them outright and require people to write the trivial standard C equivalent. They serve zero purpose that I can see.
8998dcb
to
9d75e23
Compare
@@ -792,17 +792,18 @@ let Predicates = [HasVendorXCValu, IsRV32], AddedComplexity = 1 in { | |||
def : Pat<(sext_inreg (XLenVT GPR:$rs1), i16), (CV_EXTHS GPR:$rs1)>; | |||
def : Pat<(sext_inreg (XLenVT GPR:$rs1), i8), (CV_EXTBS GPR:$rs1)>; | |||
def : Pat<(and (XLenVT GPR:$rs1), 0xffff), (CV_EXTHZ GPR:$rs1)>; | |||
def : Pat<(and (XLenVT GPR:$rs1), 0xff), (CV_EXTBZ GPR:$rs1)>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is CV_EXTBZ better than ANDI?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm sorry for the late reply. I have raised the question to openhardware group and the answer is, for CV32E40P extension enabled CPUs,cv.extbz
should replace andi
when possible, but the performance comparison is not available right now.
This commit adds the Clang Builtins, C API header and relevant tests for XCValu extension. Spec: https://github.com/openhwgroup/core-v-sw/blob/master/specifications/corev-builtin-spec.md Contributor: @melonedo, @PaoloS02
…ests. Remove exths/exthz intrinsics by replacing them with trunc+extend
7933716
to
7ee760d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/146/builds/1285 Here is the relevant piece of the build log for the reference
|
…vm#100684) This commit adds the Clang Builtins, C API header and relevant tests for XCValu extension. Spec: https://github.com/openhwgroup/core-v-sw/blob/master/specifications/corev-builtin-spec.md Contributor: @melonedo, @PaoloS02
This commit adds the Clang Builtins, C API header and relevant tests for XCValu extension.
Spec: https://github.com/openhwgroup/core-v-sw/blob/master/specifications/corev-builtin-spec.md
Contributor: @melonedo, @PaoloS02