-
Notifications
You must be signed in to change notification settings - Fork 12k
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
[RISCV] Add riscv_atomic.h and Zawrs/Zalrsc builtins #94578
[RISCV] Add riscv_atomic.h and Zawrs/Zalrsc builtins #94578
Conversation
Created using spr 1.3.6-beta.1
@llvm/pr-subscribers-clang @llvm/pr-subscribers-backend-risc-v Author: Pengcheng Wang (wangpc-pp) Changes
Patch is 26.60 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/94578.diff 14 Files Affected:
diff --git a/clang/include/clang/Basic/BuiltinsRISCV.td b/clang/include/clang/Basic/BuiltinsRISCV.td
index 4cc89a8a9d8af..458c755179417 100644
--- a/clang/include/clang/Basic/BuiltinsRISCV.td
+++ b/clang/include/clang/Basic/BuiltinsRISCV.td
@@ -146,3 +146,21 @@ let Features = "zihintntl", Attributes = [CustomTypeChecking] in {
def ntl_load : RISCVBuiltin<"void(...)">;
def ntl_store : RISCVBuiltin<"void(...)">;
} // Features = "zihintntl", Attributes = [CustomTypeChecking]
+
+//===----------------------------------------------------------------------===//
+// Zawrs extension.
+//===----------------------------------------------------------------------===//
+let Features = "zawrs" in {
+def wrs_nto : RISCVBuiltin<"void()">;
+def wrs_sto : RISCVBuiltin<"void()">;
+} // Features = "zawrs"
+
+//===----------------------------------------------------------------------===//
+// Zalrsc extension.
+//===----------------------------------------------------------------------===//
+let Features = "zalrsc" in {
+def lr_w : RISCVBuiltin<"int(int *, _Constant unsigned int)">;
+def lr_d : RISCVBuiltin<"int64_t(int64_t *, _Constant unsigned int)">;
+def sc_w : RISCVBuiltin<"int(int, int *, _Constant unsigned int)">;
+def sc_d : RISCVBuiltin<"int64_t(int64_t, int64_t *, _Constant unsigned int)">;
+} // Features = "zalrsc"
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 37d0c478e0330..db48c69e10c86 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -21769,6 +21769,28 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
ID = Intrinsic::riscv_sm3p1;
break;
+ // Zawrs
+ case RISCV::BI__builtin_riscv_wrs_nto:
+ ID = Intrinsic::riscv_wrs_nto;
+ break;
+ case RISCV::BI__builtin_riscv_wrs_sto:
+ ID = Intrinsic::riscv_wrs_sto;
+ break;
+
+ // Zalrsc
+ case RISCV::BI__builtin_riscv_lr_w:
+ ID = Intrinsic::riscv_lr_w;
+ break;
+ case RISCV::BI__builtin_riscv_lr_d:
+ ID = Intrinsic::riscv_lr_d;
+ break;
+ case RISCV::BI__builtin_riscv_sc_w:
+ ID = Intrinsic::riscv_sc_w;
+ break;
+ case RISCV::BI__builtin_riscv_sc_d:
+ ID = Intrinsic::riscv_sc_d;
+ break;
+
// Zihintntl
case RISCV::BI__builtin_riscv_ntl_load: {
llvm::Type *ResTy = ConvertType(E->getType());
diff --git a/clang/lib/Headers/CMakeLists.txt b/clang/lib/Headers/CMakeLists.txt
index d3090e488306f..cf2fbf1893772 100644
--- a/clang/lib/Headers/CMakeLists.txt
+++ b/clang/lib/Headers/CMakeLists.txt
@@ -118,6 +118,7 @@ set(ppc_htm_files
)
set(riscv_files
+ riscv_atomics.h
riscv_bitmanip.h
riscv_crypto.h
riscv_ntlh.h
diff --git a/clang/lib/Headers/riscv_atomics.h b/clang/lib/Headers/riscv_atomics.h
new file mode 100644
index 0000000000000..35db57fe36131
--- /dev/null
+++ b/clang/lib/Headers/riscv_atomics.h
@@ -0,0 +1,36 @@
+/*===---- riscv_atomics.h - RISC-V atomics 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_ATOMICS_H
+#define __RISCV_ATOMICS_H
+
+#ifdef __riscv_zalrsc
+enum {
+ __RISCV_ORDER_NONE = 0,
+ __RISCV_ORDER_AQ = 1,
+ __RISCV_ORDER_RL = 2,
+ __RISCV_ORDER_AQ_RL = 3
+};
+
+#define __riscv_lr_w __builtin_riscv_lr_w
+#define __riscv_sc_w __builtin_riscv_sc_w
+
+#if __riscv_xlen == 64
+#define __riscv_lr_d __builtin_riscv_lr_d
+#define __riscv_sc_d __builtin_riscv_sc_d
+#endif
+
+#endif
+
+#ifdef __riscv_zawrs
+#define __riscv_wrs_nto __builtin_riscv_wrs_nto
+#define __riscv_wrs_sto __builtin_riscv_wrs_sto
+#endif
+
+#endif
diff --git a/clang/lib/Sema/SemaRISCV.cpp b/clang/lib/Sema/SemaRISCV.cpp
index fd4fc15c1fd79..0b69b72cea8bb 100644
--- a/clang/lib/Sema/SemaRISCV.cpp
+++ b/clang/lib/Sema/SemaRISCV.cpp
@@ -1303,7 +1303,7 @@ bool SemaRISCV::CheckBuiltinFunctionCall(const TargetInfo &TI,
case RISCVVector::BI__builtin_rvv_vfwnmsac_vf_rm_mu:
return SemaRef.BuiltinConstantArgRange(TheCall, 4, 0, 4);
case RISCV::BI__builtin_riscv_ntl_load:
- case RISCV::BI__builtin_riscv_ntl_store:
+ case RISCV::BI__builtin_riscv_ntl_store: {
DeclRefExpr *DRE =
cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
assert((BuiltinID == RISCV::BI__builtin_riscv_ntl_store ||
@@ -1368,6 +1368,14 @@ bool SemaRISCV::CheckBuiltinFunctionCall(const TargetInfo &TI,
return false;
}
+ case RISCV::BI__builtin_riscv_lr_w:
+ case RISCV::BI__builtin_riscv_lr_d:
+ return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 3);
+ case RISCV::BI__builtin_riscv_sc_w:
+ case RISCV::BI__builtin_riscv_sc_d:
+ return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 3);
+ }
+
return false;
}
diff --git a/clang/test/CodeGen/RISCV/atomics-intrinsics/zalrsc-error.c b/clang/test/CodeGen/RISCV/atomics-intrinsics/zalrsc-error.c
new file mode 100644
index 0000000000000..d274077c9acfd
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/atomics-intrinsics/zalrsc-error.c
@@ -0,0 +1,13 @@
+// REQUIRES: riscv-registered-target
+// RUN: %clang_cc1 -triple riscv64 -target-feature +zalrsc -S -verify %s -o -
+// RUN: %clang_cc1 -triple riscv64 -target-feature +zalrsc -S -verify %s -o -
+
+#include <riscv_atomics.h>
+
+int zalrsc_lr_w(int* ptr) {
+ return __riscv_lr_w(ptr, 4); // expected-error {{argument value 4 is outside the valid range [0, 3]}}
+}
+
+int zalrsc_sc_w(int v, int* ptr) {
+ return __riscv_sc_w(v, ptr, 4); // expected-error {{argument value 4 is outside the valid range [0, 3]}}
+}
diff --git a/clang/test/CodeGen/RISCV/atomics-intrinsics/zalrsc.c b/clang/test/CodeGen/RISCV/atomics-intrinsics/zalrsc.c
new file mode 100644
index 0000000000000..662ac53ee1e57
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/atomics-intrinsics/zalrsc.c
@@ -0,0 +1,222 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 2
+// REQUIRES: riscv-registered-target
+// RUN: %clang_cc1 -triple riscv32 -target-feature +zalrsc -disable-O0-optnone \
+// RUN: -emit-llvm %s -o - | opt -S -passes=mem2reg | \
+// RUN: FileCheck --check-prefixes=CHECK-RV32 %s
+// RUN: %clang_cc1 -triple riscv64 -target-feature +zalrsc -disable-O0-optnone \
+// RUN: -emit-llvm %s -o - | opt -S -passes=mem2reg | \
+// RUN: FileCheck --check-prefix=CHECK-RV64 %s
+
+#include <stdint.h>
+#include <riscv_atomics.h>
+
+// CHECK-RV32-LABEL: define dso_local i32 @zalrsc_lr_w_none
+// CHECK-RV32-SAME: (ptr noundef [[PTR:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-RV32-NEXT: entry:
+// CHECK-RV32-NEXT: [[TMP0:%.*]] = call i32 @llvm.riscv.lr.w(ptr [[PTR]], i32 0)
+// CHECK-RV32-NEXT: ret i32 [[TMP0]]
+//
+// CHECK-RV64-LABEL: define dso_local signext i32 @zalrsc_lr_w_none
+// CHECK-RV64-SAME: (ptr noundef [[PTR:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-RV64-NEXT: entry:
+// CHECK-RV64-NEXT: [[TMP0:%.*]] = call i32 @llvm.riscv.lr.w(ptr [[PTR]], i32 0)
+// CHECK-RV64-NEXT: ret i32 [[TMP0]]
+//
+int zalrsc_lr_w_none(int* ptr) {
+ return __riscv_lr_w(ptr, __RISCV_ORDER_NONE);
+}
+
+// CHECK-RV32-LABEL: define dso_local i32 @zalrsc_lr_w_aq
+// CHECK-RV32-SAME: (ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
+// CHECK-RV32-NEXT: entry:
+// CHECK-RV32-NEXT: [[TMP0:%.*]] = call i32 @llvm.riscv.lr.w(ptr [[PTR]], i32 1)
+// CHECK-RV32-NEXT: ret i32 [[TMP0]]
+//
+// CHECK-RV64-LABEL: define dso_local signext i32 @zalrsc_lr_w_aq
+// CHECK-RV64-SAME: (ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
+// CHECK-RV64-NEXT: entry:
+// CHECK-RV64-NEXT: [[TMP0:%.*]] = call i32 @llvm.riscv.lr.w(ptr [[PTR]], i32 1)
+// CHECK-RV64-NEXT: ret i32 [[TMP0]]
+//
+int zalrsc_lr_w_aq(int* ptr) {
+ return __riscv_lr_w(ptr, __RISCV_ORDER_AQ);
+}
+
+// CHECK-RV32-LABEL: define dso_local i32 @zalrsc_lr_w_rl
+// CHECK-RV32-SAME: (ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
+// CHECK-RV32-NEXT: entry:
+// CHECK-RV32-NEXT: [[TMP0:%.*]] = call i32 @llvm.riscv.lr.w(ptr [[PTR]], i32 2)
+// CHECK-RV32-NEXT: ret i32 [[TMP0]]
+//
+// CHECK-RV64-LABEL: define dso_local signext i32 @zalrsc_lr_w_rl
+// CHECK-RV64-SAME: (ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
+// CHECK-RV64-NEXT: entry:
+// CHECK-RV64-NEXT: [[TMP0:%.*]] = call i32 @llvm.riscv.lr.w(ptr [[PTR]], i32 2)
+// CHECK-RV64-NEXT: ret i32 [[TMP0]]
+//
+int zalrsc_lr_w_rl(int* ptr) {
+ return __riscv_lr_w(ptr, __RISCV_ORDER_RL);
+}
+
+// CHECK-RV32-LABEL: define dso_local i32 @zalrsc_lr_w_aqrl
+// CHECK-RV32-SAME: (ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
+// CHECK-RV32-NEXT: entry:
+// CHECK-RV32-NEXT: [[TMP0:%.*]] = call i32 @llvm.riscv.lr.w(ptr [[PTR]], i32 3)
+// CHECK-RV32-NEXT: ret i32 [[TMP0]]
+//
+// CHECK-RV64-LABEL: define dso_local signext i32 @zalrsc_lr_w_aqrl
+// CHECK-RV64-SAME: (ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
+// CHECK-RV64-NEXT: entry:
+// CHECK-RV64-NEXT: [[TMP0:%.*]] = call i32 @llvm.riscv.lr.w(ptr [[PTR]], i32 3)
+// CHECK-RV64-NEXT: ret i32 [[TMP0]]
+//
+int zalrsc_lr_w_aqrl(int* ptr) {
+ return __riscv_lr_w(ptr, __RISCV_ORDER_AQ_RL);
+}
+
+// CHECK-RV32-LABEL: define dso_local i32 @zalrsc_sc_w_none
+// CHECK-RV32-SAME: (i32 noundef [[V:%.*]], ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
+// CHECK-RV32-NEXT: entry:
+// CHECK-RV32-NEXT: [[TMP0:%.*]] = call i32 @llvm.riscv.sc.w(i32 [[V]], ptr [[PTR]], i32 0)
+// CHECK-RV32-NEXT: ret i32 [[TMP0]]
+//
+// CHECK-RV64-LABEL: define dso_local signext i32 @zalrsc_sc_w_none
+// CHECK-RV64-SAME: (i32 noundef signext [[V:%.*]], ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
+// CHECK-RV64-NEXT: entry:
+// CHECK-RV64-NEXT: [[TMP0:%.*]] = call i32 @llvm.riscv.sc.w(i32 [[V]], ptr [[PTR]], i32 0)
+// CHECK-RV64-NEXT: ret i32 [[TMP0]]
+//
+int zalrsc_sc_w_none(int v, int* ptr) {
+ return __riscv_sc_w(v, ptr, __RISCV_ORDER_NONE);
+}
+
+// CHECK-RV32-LABEL: define dso_local i32 @zalrsc_sc_w_aq
+// CHECK-RV32-SAME: (i32 noundef [[V:%.*]], ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
+// CHECK-RV32-NEXT: entry:
+// CHECK-RV32-NEXT: [[TMP0:%.*]] = call i32 @llvm.riscv.sc.w(i32 [[V]], ptr [[PTR]], i32 1)
+// CHECK-RV32-NEXT: ret i32 [[TMP0]]
+//
+// CHECK-RV64-LABEL: define dso_local signext i32 @zalrsc_sc_w_aq
+// CHECK-RV64-SAME: (i32 noundef signext [[V:%.*]], ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
+// CHECK-RV64-NEXT: entry:
+// CHECK-RV64-NEXT: [[TMP0:%.*]] = call i32 @llvm.riscv.sc.w(i32 [[V]], ptr [[PTR]], i32 1)
+// CHECK-RV64-NEXT: ret i32 [[TMP0]]
+//
+int zalrsc_sc_w_aq(int v, int* ptr) {
+ return __riscv_sc_w(v, ptr, __RISCV_ORDER_AQ);
+}
+
+// CHECK-RV32-LABEL: define dso_local i32 @zalrsc_sc_w_rl
+// CHECK-RV32-SAME: (i32 noundef [[V:%.*]], ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
+// CHECK-RV32-NEXT: entry:
+// CHECK-RV32-NEXT: [[TMP0:%.*]] = call i32 @llvm.riscv.sc.w(i32 [[V]], ptr [[PTR]], i32 2)
+// CHECK-RV32-NEXT: ret i32 [[TMP0]]
+//
+// CHECK-RV64-LABEL: define dso_local signext i32 @zalrsc_sc_w_rl
+// CHECK-RV64-SAME: (i32 noundef signext [[V:%.*]], ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
+// CHECK-RV64-NEXT: entry:
+// CHECK-RV64-NEXT: [[TMP0:%.*]] = call i32 @llvm.riscv.sc.w(i32 [[V]], ptr [[PTR]], i32 2)
+// CHECK-RV64-NEXT: ret i32 [[TMP0]]
+//
+int zalrsc_sc_w_rl(int v, int* ptr) {
+ return __riscv_sc_w(v, ptr, __RISCV_ORDER_RL);
+}
+
+// CHECK-RV32-LABEL: define dso_local i32 @zalrsc_sc_w_aqrl
+// CHECK-RV32-SAME: (i32 noundef [[V:%.*]], ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
+// CHECK-RV32-NEXT: entry:
+// CHECK-RV32-NEXT: [[TMP0:%.*]] = call i32 @llvm.riscv.sc.w(i32 [[V]], ptr [[PTR]], i32 3)
+// CHECK-RV32-NEXT: ret i32 [[TMP0]]
+//
+// CHECK-RV64-LABEL: define dso_local signext i32 @zalrsc_sc_w_aqrl
+// CHECK-RV64-SAME: (i32 noundef signext [[V:%.*]], ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
+// CHECK-RV64-NEXT: entry:
+// CHECK-RV64-NEXT: [[TMP0:%.*]] = call i32 @llvm.riscv.sc.w(i32 [[V]], ptr [[PTR]], i32 3)
+// CHECK-RV64-NEXT: ret i32 [[TMP0]]
+//
+int zalrsc_sc_w_aqrl(int v, int* ptr) {
+ return __riscv_sc_w(v, ptr, __RISCV_ORDER_AQ_RL);
+}
+
+#if __riscv_xlen == 64
+// CHECK-RV64-LABEL: define dso_local i64 @zalrsc_lr_d_none
+// CHECK-RV64-SAME: (ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
+// CHECK-RV64-NEXT: entry:
+// CHECK-RV64-NEXT: [[TMP0:%.*]] = call i64 @llvm.riscv.lr.d(ptr [[PTR]], i32 0)
+// CHECK-RV64-NEXT: ret i64 [[TMP0]]
+//
+int64_t zalrsc_lr_d_none(int64_t* ptr) {
+ return __riscv_lr_d(ptr, __RISCV_ORDER_NONE);
+}
+
+// CHECK-RV64-LABEL: define dso_local i64 @zalrsc_lr_d_aq
+// CHECK-RV64-SAME: (ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
+// CHECK-RV64-NEXT: entry:
+// CHECK-RV64-NEXT: [[TMP0:%.*]] = call i64 @llvm.riscv.lr.d(ptr [[PTR]], i32 1)
+// CHECK-RV64-NEXT: ret i64 [[TMP0]]
+//
+int64_t zalrsc_lr_d_aq(int64_t* ptr) {
+ return __riscv_lr_d(ptr, __RISCV_ORDER_AQ);
+}
+
+// CHECK-RV64-LABEL: define dso_local i64 @zalrsc_lr_d_rl
+// CHECK-RV64-SAME: (ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
+// CHECK-RV64-NEXT: entry:
+// CHECK-RV64-NEXT: [[TMP0:%.*]] = call i64 @llvm.riscv.lr.d(ptr [[PTR]], i32 2)
+// CHECK-RV64-NEXT: ret i64 [[TMP0]]
+//
+int64_t zalrsc_lr_d_rl(int64_t* ptr) {
+ return __riscv_lr_d(ptr, __RISCV_ORDER_RL);
+}
+
+// CHECK-RV64-LABEL: define dso_local i64 @zalrsc_lr_d_aqrl
+// CHECK-RV64-SAME: (ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
+// CHECK-RV64-NEXT: entry:
+// CHECK-RV64-NEXT: [[TMP0:%.*]] = call i64 @llvm.riscv.lr.d(ptr [[PTR]], i32 3)
+// CHECK-RV64-NEXT: ret i64 [[TMP0]]
+//
+int64_t zalrsc_lr_d_aqrl(int64_t* ptr) {
+ return __riscv_lr_d(ptr, __RISCV_ORDER_AQ_RL);
+}
+
+// CHECK-RV64-LABEL: define dso_local i64 @zalrsc_sc_d_none
+// CHECK-RV64-SAME: (i64 noundef [[V:%.*]], ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
+// CHECK-RV64-NEXT: entry:
+// CHECK-RV64-NEXT: [[TMP0:%.*]] = call i64 @llvm.riscv.sc.d(i64 [[V]], ptr [[PTR]], i32 0)
+// CHECK-RV64-NEXT: ret i64 [[TMP0]]
+//
+int64_t zalrsc_sc_d_none(int64_t v, int64_t* ptr) {
+ return __riscv_sc_d(v, ptr, __RISCV_ORDER_NONE);
+}
+
+// CHECK-RV64-LABEL: define dso_local i64 @zalrsc_sc_d_aq
+// CHECK-RV64-SAME: (i64 noundef [[V:%.*]], ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
+// CHECK-RV64-NEXT: entry:
+// CHECK-RV64-NEXT: [[TMP0:%.*]] = call i64 @llvm.riscv.sc.d(i64 [[V]], ptr [[PTR]], i32 1)
+// CHECK-RV64-NEXT: ret i64 [[TMP0]]
+//
+int64_t zalrsc_sc_d_aq(int64_t v, int64_t* ptr) {
+ return __riscv_sc_d(v, ptr, __RISCV_ORDER_AQ);
+}
+
+// CHECK-RV64-LABEL: define dso_local i64 @zalrsc_sc_d_rl
+// CHECK-RV64-SAME: (i64 noundef [[V:%.*]], ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
+// CHECK-RV64-NEXT: entry:
+// CHECK-RV64-NEXT: [[TMP0:%.*]] = call i64 @llvm.riscv.sc.d(i64 [[V]], ptr [[PTR]], i32 2)
+// CHECK-RV64-NEXT: ret i64 [[TMP0]]
+//
+int64_t zalrsc_sc_d_rl(int64_t v, int64_t* ptr) {
+ return __riscv_sc_d(v, ptr, __RISCV_ORDER_RL);
+}
+
+// CHECK-RV64-LABEL: define dso_local i64 @zalrsc_sc_d_aqrl
+// CHECK-RV64-SAME: (i64 noundef [[V:%.*]], ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
+// CHECK-RV64-NEXT: entry:
+// CHECK-RV64-NEXT: [[TMP0:%.*]] = call i64 @llvm.riscv.sc.d(i64 [[V]], ptr [[PTR]], i32 3)
+// CHECK-RV64-NEXT: ret i64 [[TMP0]]
+//
+int64_t zalrsc_sc_d_aqrl(int64_t v, int64_t* ptr) {
+ return __riscv_sc_d(v, ptr, __RISCV_ORDER_AQ_RL);
+}
+
+#endif
diff --git a/clang/test/CodeGen/RISCV/atomics-intrinsics/zawrs.c b/clang/test/CodeGen/RISCV/atomics-intrinsics/zawrs.c
new file mode 100644
index 0000000000000..998655e67a160
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/atomics-intrinsics/zawrs.c
@@ -0,0 +1,42 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 2
+// REQUIRES: riscv-registered-target
+// RUN: %clang_cc1 -triple riscv32 -target-feature +zawrs -disable-O0-optnone \
+// RUN: -emit-llvm %s -o - | opt -S -passes=mem2reg | \
+// RUN: FileCheck --check-prefixes=CHECK-RV32 %s
+// RUN: %clang_cc1 -triple riscv64 -target-feature +zawrs -disable-O0-optnone \
+// RUN: -emit-llvm %s -o - | opt -S -passes=mem2reg | \
+// RUN: FileCheck --check-prefix=CHECK-RV64 %s
+
+#include <riscv_atomics.h>
+
+// CHECK-RV32-LABEL: define dso_local void @zawrs_nto
+// CHECK-RV32-SAME: () #[[ATTR0:[0-9]+]] {
+// CHECK-RV32-NEXT: entry:
+// CHECK-RV32-NEXT: call void @llvm.riscv.wrs.nto()
+// CHECK-RV32-NEXT: ret void
+//
+// CHECK-RV64-LABEL: define dso_local void @zawrs_nto
+// CHECK-RV64-SAME: () #[[ATTR0:[0-9]+]] {
+// CHECK-RV64-NEXT: entry:
+// CHECK-RV64-NEXT: call void @llvm.riscv.wrs.nto()
+// CHECK-RV64-NEXT: ret void
+//
+void zawrs_nto(){
+ __riscv_wrs_nto();
+}
+
+// CHECK-RV32-LABEL: define dso_local void @zawrs_sto
+// CHECK-RV32-SAME: () #[[ATTR0]] {
+// CHECK-RV32-NEXT: entry:
+// CHECK-RV32-NEXT: call void @llvm.riscv.wrs.sto()
+// CHECK-RV32-NEXT: ret void
+//
+// CHECK-RV64-LABEL: define dso_local void @zawrs_sto
+// CHECK-RV64-SAME: () #[[ATTR0]] {
+// CHECK-RV64-NEXT: entry:
+// CHECK-RV64-NEXT: call void @llvm.riscv.wrs.sto()
+// CHECK-RV64-NEXT: ret void
+//
+void zawrs_sto(){
+ __riscv_wrs_sto();
+}
diff --git a/llvm/include/llvm/IR/IntrinsicsRISCV.td b/llvm/include/llvm/IR/IntrinsicsRISCV.td
index 4c4e7351212f8..c9a0e75645694 100644
--- a/llvm/include/llvm/IR/IntrinsicsRISCV.td
+++ b/llvm/include/llvm/IR/IntrinsicsRISCV.td
@@ -124,6 +124,38 @@ let TargetPrefix = "riscv" in {
[IntrNoMem, IntrSpeculatable, ImmArg<ArgIndex<2>>]>;
} // TargetPrefix = "riscv"
+//===----------------------------------------------------------------------===//
+// 'Zawrs' (Wait on Reservation Set)
+
+let TargetPrefix = "riscv" in {
+ def int_riscv_wrs_nto
+ : DefaultAttrsIntrinsic<[], [], [IntrHasSideEffects]>;
+ def int_riscv_wrs_sto
+ : DefaultAttrsIntrinsic<[], [], [IntrHasSideEffects]>;
+} // TargetPrefix = "riscv"
+
+//===----------------------------------------------------------------------===//
+// 'Zalrsc' (Load-Reserved/Store-Conditional)
+
+let TargetPrefix = "riscv" in {
+ def int_riscv_lr_w
+ : DefaultAttrsIntrinsic<[llvm_i32_ty],
+ [llvm_ptr_ty, llvm_i32_ty],
+ [IntrReadMem, ImmArg<ArgIndex<1>>]>;
+ def int_riscv_lr_d
+ : DefaultAttrsIntrinsic<[llvm_i64_ty],
+ [llvm_ptr_ty, llvm_i32_ty],
+ [IntrReadMem, ImmArg<ArgIndex<1>>]>;
+ def int_riscv_sc_w
+ : DefaultAttrsIntrinsic<[llvm_i32_ty],
+ [llvm_i32_ty, llvm_ptr_ty, llvm_i32_ty],
+ [IntrWriteMem, ImmArg<ArgIndex<2>>]>;
+ def int_riscv_sc_d
+ : DefaultAttrsIntrinsic<[llvm_i64_ty],
+ [llvm_i64_ty, llvm_ptr_ty, llvm_i32_ty],
+ [IntrWriteMem, ImmArg<ArgIndex<2>>]>;
+} // TargetPrefix = "riscv"
+
//===----------------------------------------------------------------------===//
// Vectors
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoA.td b/llvm/lib/Target/RISCV/RISCVInstrInfoA.td
index 814e0ddf111e6..5dbf954995bed 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoA.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoA.td
@@ -136,6 +136,31 @@ let Predicates = [HasAtomicLdSt, IsRV64] in {
def : StPat<atomic_store_64, SD, GPR, i64>;
}
+/// LR/SC intrinsics patterns
+multiclass LRPat<Intrinsic intrinsic, string inst> {
+ def : Pat<(intrinsic GPR:$src, 0), (!cast<Instruction>(inst) GPR:$src)>;
+ def : Pat<(intrinsic GPR:$src, 1), (!cast<Instruction>(inst # "_AQ") GPR:$src)>;
+ def : Pat<(intrinsic GPR:$src, 2), (!cast<Instruction>(inst # "_RL") GPR:$src)>;
+ def : Pat<(intrinsic GPR:$src, 3), (!cast<Instruction>(inst # "_AQ_RL") GPR:$src)>;
+}
+
+multiclass SCPat<Intrinsic intrinsic, string inst> {
+ def : Pat<(intrinsic GPR:$src, GPR:$dst, 0), (!cast<Instruction>(inst) GPR:$src, GPR:$dst)>;
+ def : Pat<(intrinsic GPR:$src, GPR:$dst, 1), (!cast<Instruction>(inst # "_AQ") GPR:$src, GPR:$dst)>;
+ def : Pat<(intrinsic GPR:$src, GPR:$dst, 2), (!cast<Instruction>(inst # "_RL") GPR:$src, GPR:$dst)>;
+ def : Pat<(intrinsic GPR:$src, GPR:$dst, 3), (!cast<Instruction>(inst # "_AQ_RL") GPR:$src, GPR:$dst)>;
+}
+
+let Predicates = [HasStdExtAOrZalrsc] in {
+ defm : LRPat<int_riscv_lr_w, "LR_W">;
+ defm : SCPat<int_riscv_sc_w, "SC_W">;
+} // Predicates = [HasStdExtAOrZalrsc]
+
+let Predicates = [HasStdExtAOrZalrsc, IsRV64] in {
+ defm : LRPat<int_riscv_lr_d, "LR_D">;
+ defm :...
[truncated]
|
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
lr/sc builtins are extremely fragile: there's no reasonable way for the compiler to guarantee that the sc is placed in such a way that it will eventually succeed. (The equivalent intrinsics do exist on ARM, but ARM has significantly stronger guarantees here. Even then, it's not completely reliable.) |
I think the user should have enough knowledges about lr/sc to make the logic reasonable. If we don't provide these intrinsics, the user who wants to implement custom locks will use inline assemly instead.
I don't know much about there intrinsics on ARM, what are the |
It's not about knowledge, it's that they are basically impossible for the compiler to actually guarantee they'll work at all.
Good, because other than using C11-style atomics (or Itanium-style __sync builtins), that's the right thing to do. |
If we are talking about the necessariness of adding these intrinsics, please refer to the ARM implementations in DPDK (https://github.com/DPDK/dpdk/blob/76cef1af8bdaeaf67a5c4ca5df3f221df994dc46/lib/eal/arm/include/rte_pause_64.h). We want to use Zawrs&Zalrsc instructions to implement these on RISCV. |
Then write the loops in assembly. Really, it's not hard to do, and it's the only real way to guarantee it'll actually work the way you think it does. Compilers are free to insert whatever stack spills and reloads they want in between your inline assembly blocks or intrinsic calls, which can wreak havoc with load reservations if you're expecting them to be untouched in between. C is just not the right language to be modelling that kind of thing in, assembly is. |
Especially with -O0. |
Arm specifies that there's a memory reservation, and you can write whatever operations you want as long as you don't break that reservation. And the reservation is usually only a few bytes. RISC-V specifically only guarantees behavior for sequences of integer instructions. |
Created using spr 1.3.6-beta.1
My understanding from the sync-up call just now is you're planning to drop lr/sc intrinsics due to the concerns listed in this thread (which I share), but will keep pushing the zawrs intrinsics. |
riscv_atomic.h
contains all builtins for atomics.Doc: riscv-non-isa/riscv-c-api-doc#79