[llvm] 685bbe6 - [Clang][LoongArch] Add intrinsic for csrrd, csrwr and csrxchg
via llvm-commits
llvm-commits at lists.llvm.org
Wed Dec 7 22:25:40 PST 2022
Author: gonglingqin
Date: 2022-12-08T14:11:50+08:00
New Revision: 685bbe65f5c3617e79f52a5af827cee2ee0b6f45
URL: https://github.com/llvm/llvm-project/commit/685bbe65f5c3617e79f52a5af827cee2ee0b6f45
DIFF: https://github.com/llvm/llvm-project/commit/685bbe65f5c3617e79f52a5af827cee2ee0b6f45.diff
LOG: [Clang][LoongArch] Add intrinsic for csrrd, csrwr and csrxchg
These intrinsics are required by Linux [1].
[1]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/loongarch/include/asm/loongarch.h?h=v6.0&id=4fe89d07dcc2804c8b562f6c7896a45643d34b2f#n232
Differential Revision: https://reviews.llvm.org/D139288
Added:
clang/test/CodeGen/LoongArch/intrinsic-error-la64.c
llvm/test/CodeGen/LoongArch/intrinsic-la64-error.ll
Modified:
clang/include/clang/Basic/BuiltinsLoongArch.def
clang/lib/CodeGen/CGBuiltin.cpp
clang/lib/Headers/larchintrin.h
clang/lib/Sema/SemaChecking.cpp
clang/test/CodeGen/LoongArch/intrinsic-error.c
clang/test/CodeGen/LoongArch/intrinsic-la64.c
clang/test/CodeGen/LoongArch/intrinsic.c
llvm/include/llvm/IR/IntrinsicsLoongArch.td
llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
llvm/lib/Target/LoongArch/LoongArchISelLowering.h
llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
llvm/test/CodeGen/LoongArch/intrinsic-error.ll
llvm/test/CodeGen/LoongArch/intrinsic-la32-error.ll
llvm/test/CodeGen/LoongArch/intrinsic-la64.ll
llvm/test/CodeGen/LoongArch/intrinsic.ll
Removed:
################################################################################
diff --git a/clang/include/clang/Basic/BuiltinsLoongArch.def b/clang/include/clang/Basic/BuiltinsLoongArch.def
index 85635b0b12424..fa4aaffa5ff71 100644
--- a/clang/include/clang/Basic/BuiltinsLoongArch.def
+++ b/clang/include/clang/Basic/BuiltinsLoongArch.def
@@ -31,5 +31,12 @@ TARGET_BUILTIN(__builtin_loongarch_crcc_w_h_w, "iii", "nc", "64bit")
TARGET_BUILTIN(__builtin_loongarch_crcc_w_w_w, "iii", "nc", "64bit")
TARGET_BUILTIN(__builtin_loongarch_crcc_w_d_w, "iLii", "nc", "64bit")
+TARGET_BUILTIN(__builtin_loongarch_csrrd_w, "UiIUi", "nc", "")
+TARGET_BUILTIN(__builtin_loongarch_csrrd_d, "ULiIUi", "nc", "64bit")
+TARGET_BUILTIN(__builtin_loongarch_csrwr_w, "UiUiIUi", "nc", "")
+TARGET_BUILTIN(__builtin_loongarch_csrwr_d, "ULiULiIUi", "nc", "64bit")
+TARGET_BUILTIN(__builtin_loongarch_csrxchg_w, "UiUiUiIUi", "nc", "")
+TARGET_BUILTIN(__builtin_loongarch_csrxchg_d, "ULiULiULiIUi", "nc", "64bit")
+
#undef BUILTIN
#undef TARGET_BUILTIN
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 88ffe7552b907..9650b9ce978f7 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -19700,6 +19700,24 @@ Value *CodeGenFunction::EmitLoongArchBuiltinExpr(unsigned BuiltinID,
case LoongArch::BI__builtin_loongarch_crcc_w_d_w:
ID = Intrinsic::loongarch_crcc_w_d_w;
break;
+ case LoongArch::BI__builtin_loongarch_csrrd_w:
+ ID = Intrinsic::loongarch_csrrd_w;
+ break;
+ case LoongArch::BI__builtin_loongarch_csrwr_w:
+ ID = Intrinsic::loongarch_csrwr_w;
+ break;
+ case LoongArch::BI__builtin_loongarch_csrxchg_w:
+ ID = Intrinsic::loongarch_csrxchg_w;
+ break;
+ case LoongArch::BI__builtin_loongarch_csrrd_d:
+ ID = Intrinsic::loongarch_csrrd_d;
+ break;
+ case LoongArch::BI__builtin_loongarch_csrwr_d:
+ ID = Intrinsic::loongarch_csrwr_d;
+ break;
+ case LoongArch::BI__builtin_loongarch_csrxchg_d:
+ ID = Intrinsic::loongarch_csrxchg_d;
+ break;
// TODO: Support more Intrinsics.
}
diff --git a/clang/lib/Headers/larchintrin.h b/clang/lib/Headers/larchintrin.h
index b16161b7cabc6..02c31657a2bc9 100644
--- a/clang/lib/Headers/larchintrin.h
+++ b/clang/lib/Headers/larchintrin.h
@@ -72,6 +72,29 @@ extern __inline int
#define __syscall(/*ui15*/ _1) __builtin_loongarch_syscall((_1))
+#define __csrrd_w(/*ui14*/ _1) ((unsigned int)__builtin_loongarch_csrrd_w((_1)))
+
+#define __csrwr_w(/*unsigned int*/ _1, /*ui14*/ _2) \
+ ((unsigned int)__builtin_loongarch_csrwr_w((unsigned int)(_1), (_2)))
+
+#define __csrxchg_w(/*unsigned int*/ _1, /*unsigned int*/ _2, /*ui14*/ _3) \
+ ((unsigned int)__builtin_loongarch_csrxchg_w((unsigned int)(_1), \
+ (unsigned int)(_2), (_3)))
+
+#if __loongarch_grlen == 64
+#define __csrrd_d(/*ui14*/ _1) \
+ ((unsigned long int)__builtin_loongarch_csrrd_d((_1)))
+
+#define __csrwr_d(/*unsigned long int*/ _1, /*ui14*/ _2) \
+ ((unsigned long int)__builtin_loongarch_csrwr_d((unsigned long int)(_1), \
+ (_2)))
+
+#define __csrxchg_d(/*unsigned long int*/ _1, /*unsigned long int*/ _2, \
+ /*ui14*/ _3) \
+ ((unsigned long int)__builtin_loongarch_csrxchg_d( \
+ (unsigned long int)(_1), (unsigned long int)(_2), (_3)))
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 4e5b721a597e2..c89d55b58f5c2 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -3723,6 +3723,30 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI,
case LoongArch::BI__builtin_loongarch_syscall:
// Check if immediate is in [0, 32767].
return SemaBuiltinConstantArgRange(TheCall, 0, 0, 32767);
+ case LoongArch::BI__builtin_loongarch_csrrd_w:
+ return SemaBuiltinConstantArgRange(TheCall, 0, 0, 16383);
+ case LoongArch::BI__builtin_loongarch_csrwr_w:
+ return SemaBuiltinConstantArgRange(TheCall, 1, 0, 16383);
+ case LoongArch::BI__builtin_loongarch_csrxchg_w:
+ return SemaBuiltinConstantArgRange(TheCall, 2, 0, 16383);
+ case LoongArch::BI__builtin_loongarch_csrrd_d:
+ if (!TI.hasFeature("64bit"))
+ return Diag(TheCall->getBeginLoc(),
+ diag::err_loongarch_builtin_requires_la64)
+ << TheCall->getSourceRange();
+ return SemaBuiltinConstantArgRange(TheCall, 0, 0, 16383);
+ case LoongArch::BI__builtin_loongarch_csrwr_d:
+ if (!TI.hasFeature("64bit"))
+ return Diag(TheCall->getBeginLoc(),
+ diag::err_loongarch_builtin_requires_la64)
+ << TheCall->getSourceRange();
+ return SemaBuiltinConstantArgRange(TheCall, 1, 0, 16383);
+ case LoongArch::BI__builtin_loongarch_csrxchg_d:
+ if (!TI.hasFeature("64bit"))
+ return Diag(TheCall->getBeginLoc(),
+ diag::err_loongarch_builtin_requires_la64)
+ << TheCall->getSourceRange();
+ return SemaBuiltinConstantArgRange(TheCall, 2, 0, 16383);
}
return false;
diff --git a/clang/test/CodeGen/LoongArch/intrinsic-error-la64.c b/clang/test/CodeGen/LoongArch/intrinsic-error-la64.c
new file mode 100644
index 0000000000000..b6e40446b14ba
--- /dev/null
+++ b/clang/test/CodeGen/LoongArch/intrinsic-error-la64.c
@@ -0,0 +1,22 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
+// RUN: %clang_cc1 -triple loongarch64 -emit-llvm -S -verify %s -o /dev/null
+
+#include <larchintrin.h>
+
+void csrrd_d(int a) {
+ __builtin_loongarch_csrrd_d(16384); // expected-error {{argument value 16384 is outside the valid range [0, 16383]}}
+ __builtin_loongarch_csrrd_d(-1); // expected-error {{argument value 4294967295 is outside the valid range [0, 16383]}}
+ __builtin_loongarch_csrrd_d(a); // expected-error {{argument to '__builtin_loongarch_csrrd_d' must be a constant integer}}
+}
+
+void csrwr_d(unsigned long int a) {
+ __builtin_loongarch_csrwr_d(a, 16384); // expected-error {{argument value 16384 is outside the valid range [0, 16383]}}
+ __builtin_loongarch_csrwr_d(a, -1); // expected-error {{argument value 4294967295 is outside the valid range [0, 16383]}}
+ __builtin_loongarch_csrwr_d(a, a); // expected-error {{argument to '__builtin_loongarch_csrwr_d' must be a constant integer}}
+}
+
+void csrxchg_d(unsigned long int a, unsigned long int b) {
+ __builtin_loongarch_csrxchg_d(a, b, 16384); // expected-error {{argument value 16384 is outside the valid range [0, 16383]}}
+ __builtin_loongarch_csrxchg_d(a, b, -1); // expected-error {{argument value 4294967295 is outside the valid range [0, 16383]}}
+ __builtin_loongarch_csrxchg_d(a, b, b); // expected-error {{argument to '__builtin_loongarch_csrxchg_d' must be a constant integer}}
+}
diff --git a/clang/test/CodeGen/LoongArch/intrinsic-error.c b/clang/test/CodeGen/LoongArch/intrinsic-error.c
index 8c2bddc362bfe..633a32fc919da 100644
--- a/clang/test/CodeGen/LoongArch/intrinsic-error.c
+++ b/clang/test/CodeGen/LoongArch/intrinsic-error.c
@@ -57,3 +57,33 @@ int crcc_w_w_w(int a, int b) {
int crcc_w_d_w(long int a, int b) {
return __builtin_loongarch_crcc_w_d_w(a, b); // expected-error {{this builtin requires target: loongarch64}}
}
+
+unsigned long int csrrd_d() {
+ return __builtin_loongarch_csrrd_d(1); // expected-error {{this builtin requires target: loongarch64}}
+}
+
+unsigned long int csrwr_d(unsigned long int a) {
+ return __builtin_loongarch_csrwr_d(a, 1); // expected-error {{this builtin requires target: loongarch64}}
+}
+
+unsigned long int csrxchg_d(unsigned long int a, unsigned long int b) {
+ return __builtin_loongarch_csrxchg_d(a, b, 1); // expected-error {{this builtin requires target: loongarch64}}
+}
+
+void csrrd_w(int a) {
+ __builtin_loongarch_csrrd_w(16384); // expected-error {{argument value 16384 is outside the valid range [0, 16383]}}
+ __builtin_loongarch_csrrd_w(-1); // expected-error {{argument value 4294967295 is outside the valid range [0, 16383]}}
+ __builtin_loongarch_csrrd_w(a); // expected-error {{argument to '__builtin_loongarch_csrrd_w' must be a constant integer}}
+}
+
+void csrwr_w(unsigned int a) {
+ __builtin_loongarch_csrwr_w(a, 16384); // expected-error {{argument value 16384 is outside the valid range [0, 16383]}}
+ __builtin_loongarch_csrwr_w(a, -1); // expected-error {{argument value 4294967295 is outside the valid range [0, 16383]}}
+ __builtin_loongarch_csrwr_w(a, a); // expected-error {{argument to '__builtin_loongarch_csrwr_w' must be a constant integer}}
+}
+
+void csrxchg_w(unsigned int a, unsigned int b) {
+ __builtin_loongarch_csrxchg_w(a, b, 16384); // expected-error {{argument value 16384 is outside the valid range [0, 16383]}}
+ __builtin_loongarch_csrxchg_w(a, b, -1); // expected-error {{argument value 4294967295 is outside the valid range [0, 16383]}}
+ __builtin_loongarch_csrxchg_w(a, b, b); // expected-error {{argument to '__builtin_loongarch_csrxchg_w' must be a constant integer}}
+}
diff --git a/clang/test/CodeGen/LoongArch/intrinsic-la64.c b/clang/test/CodeGen/LoongArch/intrinsic-la64.c
index 702686f5e6d3e..e5ac673dd376b 100644
--- a/clang/test/CodeGen/LoongArch/intrinsic-la64.c
+++ b/clang/test/CodeGen/LoongArch/intrinsic-la64.c
@@ -74,3 +74,39 @@ int crcc_w_w_w(int a, int b) {
int crcc_w_d_w(long int a, int b) {
return __builtin_loongarch_crcc_w_d_w(a, b);
}
+
+// CHECK-LABEL: @csrrd_d(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.loongarch.csrrd.d(i32 1)
+// CHECK-NEXT: [[TMP1:%.*]] = tail call i64 @llvm.loongarch.csrrd.d(i32 1)
+// CHECK-NEXT: ret i64 0
+//
+unsigned long int csrrd_d() {
+ unsigned long int a = __csrrd_d(1);
+ unsigned long int b = __builtin_loongarch_csrrd_d(1);
+ return 0;
+}
+
+// CHECK-LABEL: @csrwr_d(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.loongarch.csrwr.d(i64 [[A:%.*]], i32 1)
+// CHECK-NEXT: [[TMP1:%.*]] = tail call i64 @llvm.loongarch.csrwr.d(i64 [[A]], i32 1)
+// CHECK-NEXT: ret i64 0
+//
+unsigned long int csrwr_d(unsigned long int a) {
+ unsigned long int b = __csrwr_d(a, 1);
+ unsigned long int c = __builtin_loongarch_csrwr_d(a, 1);
+ return 0;
+}
+
+// CHECK-LABEL: @csrxchg_d(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.loongarch.csrxchg.d(i64 [[A:%.*]], i64 [[B:%.*]], i32 1)
+// CHECK-NEXT: [[TMP1:%.*]] = tail call i64 @llvm.loongarch.csrxchg.d(i64 [[A]], i64 [[B]], i32 1)
+// CHECK-NEXT: ret i64 0
+//
+unsigned long int csrxchg_d(unsigned long int a, unsigned long int b) {
+ unsigned long int c = __csrxchg_d(a, b, 1);
+ unsigned long int d = __builtin_loongarch_csrxchg_d(a, b, 1);
+ return 0;
+}
diff --git a/clang/test/CodeGen/LoongArch/intrinsic.c b/clang/test/CodeGen/LoongArch/intrinsic.c
index 98ad203e9a6f2..5dc788abdbb0e 100644
--- a/clang/test/CodeGen/LoongArch/intrinsic.c
+++ b/clang/test/CodeGen/LoongArch/intrinsic.c
@@ -61,3 +61,105 @@ void loongarch_break() {
void syscall() {
__builtin_loongarch_syscall(1);
}
+
+// LA32-LABEL: @csrrd_w(
+// LA32-NEXT: entry:
+// LA32-NEXT: [[A:%.*]] = alloca i32, align 4
+// LA32-NEXT: [[B:%.*]] = alloca i32, align 4
+// LA32-NEXT: [[TMP0:%.*]] = call i32 @llvm.loongarch.csrrd.w(i32 1)
+// LA32-NEXT: store i32 [[TMP0]], ptr [[A]], align 4
+// LA32-NEXT: [[TMP1:%.*]] = call i32 @llvm.loongarch.csrrd.w(i32 1)
+// LA32-NEXT: store i32 [[TMP1]], ptr [[B]], align 4
+// LA32-NEXT: ret i32 0
+//
+// LA64-LABEL: @csrrd_w(
+// LA64-NEXT: entry:
+// LA64-NEXT: [[A:%.*]] = alloca i32, align 4
+// LA64-NEXT: [[B:%.*]] = alloca i32, align 4
+// LA64-NEXT: [[TMP0:%.*]] = call i32 @llvm.loongarch.csrrd.w(i32 1)
+// LA64-NEXT: store i32 [[TMP0]], ptr [[A]], align 4
+// LA64-NEXT: [[TMP1:%.*]] = call i32 @llvm.loongarch.csrrd.w(i32 1)
+// LA64-NEXT: store i32 [[TMP1]], ptr [[B]], align 4
+// LA64-NEXT: ret i32 0
+//
+unsigned int csrrd_w() {
+ unsigned int a = __csrrd_w(1);
+ unsigned int b = __builtin_loongarch_csrrd_w(1);
+ return 0;
+}
+
+// LA32-LABEL: @csrwr_w(
+// LA32-NEXT: entry:
+// LA32-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
+// LA32-NEXT: [[B:%.*]] = alloca i32, align 4
+// LA32-NEXT: [[C:%.*]] = alloca i32, align 4
+// LA32-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// LA32-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// LA32-NEXT: [[TMP1:%.*]] = call i32 @llvm.loongarch.csrwr.w(i32 [[TMP0]], i32 1)
+// LA32-NEXT: store i32 [[TMP1]], ptr [[B]], align 4
+// LA32-NEXT: [[TMP2:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// LA32-NEXT: [[TMP3:%.*]] = call i32 @llvm.loongarch.csrwr.w(i32 [[TMP2]], i32 1)
+// LA32-NEXT: store i32 [[TMP3]], ptr [[C]], align 4
+// LA32-NEXT: ret i32 0
+//
+// LA64-LABEL: @csrwr_w(
+// LA64-NEXT: entry:
+// LA64-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
+// LA64-NEXT: [[B:%.*]] = alloca i32, align 4
+// LA64-NEXT: [[C:%.*]] = alloca i32, align 4
+// LA64-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// LA64-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// LA64-NEXT: [[TMP1:%.*]] = call i32 @llvm.loongarch.csrwr.w(i32 [[TMP0]], i32 1)
+// LA64-NEXT: store i32 [[TMP1]], ptr [[B]], align 4
+// LA64-NEXT: [[TMP2:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// LA64-NEXT: [[TMP3:%.*]] = call i32 @llvm.loongarch.csrwr.w(i32 [[TMP2]], i32 1)
+// LA64-NEXT: store i32 [[TMP3]], ptr [[C]], align 4
+// LA64-NEXT: ret i32 0
+//
+unsigned int csrwr_w(unsigned int a) {
+ unsigned int b = __csrwr_w(a, 1);
+ unsigned int c = __builtin_loongarch_csrwr_w(a, 1);
+ return 0;
+}
+
+// LA32-LABEL: @csrxchg_w(
+// LA32-NEXT: entry:
+// LA32-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
+// LA32-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4
+// LA32-NEXT: [[C:%.*]] = alloca i32, align 4
+// LA32-NEXT: [[D:%.*]] = alloca i32, align 4
+// LA32-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// LA32-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// LA32-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// LA32-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// LA32-NEXT: [[TMP2:%.*]] = call i32 @llvm.loongarch.csrxchg.w(i32 [[TMP0]], i32 [[TMP1]], i32 1)
+// LA32-NEXT: store i32 [[TMP2]], ptr [[C]], align 4
+// LA32-NEXT: [[TMP3:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// LA32-NEXT: [[TMP4:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// LA32-NEXT: [[TMP5:%.*]] = call i32 @llvm.loongarch.csrxchg.w(i32 [[TMP3]], i32 [[TMP4]], i32 1)
+// LA32-NEXT: store i32 [[TMP5]], ptr [[D]], align 4
+// LA32-NEXT: ret i32 0
+//
+// LA64-LABEL: @csrxchg_w(
+// LA64-NEXT: entry:
+// LA64-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
+// LA64-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4
+// LA64-NEXT: [[C:%.*]] = alloca i32, align 4
+// LA64-NEXT: [[D:%.*]] = alloca i32, align 4
+// LA64-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// LA64-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// LA64-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// LA64-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// LA64-NEXT: [[TMP2:%.*]] = call i32 @llvm.loongarch.csrxchg.w(i32 [[TMP0]], i32 [[TMP1]], i32 1)
+// LA64-NEXT: store i32 [[TMP2]], ptr [[C]], align 4
+// LA64-NEXT: [[TMP3:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// LA64-NEXT: [[TMP4:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// LA64-NEXT: [[TMP5:%.*]] = call i32 @llvm.loongarch.csrxchg.w(i32 [[TMP3]], i32 [[TMP4]], i32 1)
+// LA64-NEXT: store i32 [[TMP5]], ptr [[D]], align 4
+// LA64-NEXT: ret i32 0
+//
+unsigned int csrxchg_w(unsigned int a, unsigned int b) {
+ unsigned int c = __csrxchg_w(a, b, 1);
+ unsigned int d = __builtin_loongarch_csrxchg_w(a, b, 1);
+ return 0;
+}
diff --git a/llvm/include/llvm/IR/IntrinsicsLoongArch.td b/llvm/include/llvm/IR/IntrinsicsLoongArch.td
index 8da6599bf9eb5..599ed83609212 100644
--- a/llvm/include/llvm/IR/IntrinsicsLoongArch.td
+++ b/llvm/include/llvm/IR/IntrinsicsLoongArch.td
@@ -73,4 +73,23 @@ def int_loongarch_crcc_w_w_w : Intrinsic<[llvm_i32_ty],
[llvm_i32_ty, llvm_i32_ty]>;
def int_loongarch_crcc_w_d_w : Intrinsic<[llvm_i32_ty],
[llvm_i64_ty, llvm_i32_ty]>;
+
+def int_loongarch_csrrd_w : Intrinsic<[llvm_i32_ty], [llvm_i32_ty],
+ [ImmArg<ArgIndex<0>>]>;
+def int_loongarch_csrrd_d : Intrinsic<[llvm_i64_ty], [llvm_i32_ty],
+ [ImmArg<ArgIndex<0>>]>;
+def int_loongarch_csrwr_w : Intrinsic<[llvm_i32_ty],
+ [llvm_i32_ty, llvm_i32_ty],
+ [ImmArg<ArgIndex<1>>]>;
+def int_loongarch_csrwr_d : Intrinsic<[llvm_i64_ty],
+ [llvm_i64_ty, llvm_i32_ty],
+ [ImmArg<ArgIndex<1>>]>;
+def int_loongarch_csrxchg_w : Intrinsic<[llvm_i32_ty],
+ [llvm_i32_ty, llvm_i32_ty,
+ llvm_i32_ty],
+ [ImmArg<ArgIndex<2>>]>;
+def int_loongarch_csrxchg_d : Intrinsic<[llvm_i64_ty],
+ [llvm_i64_ty, llvm_i64_ty,
+ llvm_i32_ty],
+ [ImmArg<ArgIndex<2>>]>;
} // TargetPrefix = "loongarch"
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
index 166e3b30236a7..fd23aadcdb755 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -63,6 +63,7 @@ LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::DEBUGTRAP, MVT::Other, Legal);
setOperationAction(ISD::TRAP, MVT::Other, Legal);
setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom);
+ setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom);
setOperationAction({ISD::GlobalAddress, ISD::BlockAddress, ISD::ConstantPool,
ISD::JumpTable},
@@ -591,9 +592,25 @@ LoongArchTargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op,
}
}
+// Helper function that emits error message for intrinsics with chain.
+static SDValue emitIntrinsicWithChainErrorMessage(SDValue Op,
+ StringRef ErrorMsg,
+ SelectionDAG &DAG) {
+
+ DAG.getContext()->emitError("argument to '" + Op->getOperationName(0) + "' " +
+ ErrorMsg);
+ return DAG.getMergeValues({DAG.getUNDEF(Op.getValueType()), Op.getOperand(0)},
+ SDLoc(Op));
+}
+
SDValue
LoongArchTargetLowering::lowerINTRINSIC_W_CHAIN(SDValue Op,
SelectionDAG &DAG) const {
+ SDLoc DL(Op);
+ MVT GRLenVT = Subtarget.getGRLenVT();
+ SDValue Op0 = Op.getOperand(0);
+ std::string Name = Op->getOperationName(0);
+ const StringRef ErrorMsgOOR = "out of range";
switch (Op.getConstantOperandVal(1)) {
default:
@@ -608,8 +625,40 @@ LoongArchTargetLowering::lowerINTRINSIC_W_CHAIN(SDValue Op,
case Intrinsic::loongarch_crcc_w_d_w: {
std::string Name = Op->getOperationName(0);
DAG.getContext()->emitError(Name + " requires target: loongarch64");
+ return DAG.getMergeValues({DAG.getUNDEF(Op.getValueType()), Op0}, DL);
+ }
+ case Intrinsic::loongarch_csrrd_w:
+ case Intrinsic::loongarch_csrrd_d: {
+ unsigned Imm = cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue();
+ if (!isUInt<14>(Imm))
+ return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG);
+ return DAG.getMergeValues(
+ {DAG.getNode(LoongArchISD::CSRRD, DL, GRLenVT, Op0,
+ DAG.getConstant(Imm, DL, GRLenVT)),
+ Op0},
+ DL);
+ }
+ case Intrinsic::loongarch_csrwr_w:
+ case Intrinsic::loongarch_csrwr_d: {
+ unsigned Imm = cast<ConstantSDNode>(Op.getOperand(3))->getZExtValue();
+ if (!isUInt<14>(Imm))
+ return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG);
return DAG.getMergeValues(
- {DAG.getUNDEF(Op.getValueType()), Op.getOperand(0)}, SDLoc(Op));
+ {DAG.getNode(LoongArchISD::CSRWR, DL, GRLenVT, Op0, Op.getOperand(2),
+ DAG.getConstant(Imm, DL, GRLenVT)),
+ Op0},
+ DL);
+ }
+ case Intrinsic::loongarch_csrxchg_w:
+ case Intrinsic::loongarch_csrxchg_d: {
+ unsigned Imm = cast<ConstantSDNode>(Op.getOperand(4))->getZExtValue();
+ if (!isUInt<14>(Imm))
+ return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG);
+ return DAG.getMergeValues(
+ {DAG.getNode(LoongArchISD::CSRXCHG, DL, GRLenVT, Op0, Op.getOperand(2),
+ Op.getOperand(3), DAG.getConstant(Imm, DL, GRLenVT)),
+ Op0},
+ DL);
}
}
}
@@ -939,10 +988,10 @@ void LoongArchTargetLowering::ReplaceNodeResults(
break;
}
case ISD::INTRINSIC_W_CHAIN: {
- assert(VT == MVT::i32 && Subtarget.is64Bit() &&
- "Unexpected custom legalisation");
+ SDValue Op0 = N->getOperand(0);
SDValue Op2 = N->getOperand(2);
- SDValue Op3 = N->getOperand(3);
+ MVT GRLenVT = Subtarget.getGRLenVT();
+ std::string Name = N->getOperationName(0);
switch (N->getConstantOperandVal(1)) {
default:
@@ -951,9 +1000,10 @@ void LoongArchTargetLowering::ReplaceNodeResults(
case Intrinsic::loongarch_##NAME: { \
Results.push_back(DAG.getNode( \
ISD::TRUNCATE, DL, VT, \
- DAG.getNode(LoongArchISD::NODE, DL, MVT::i64, \
- DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2), \
- DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op3)))); \
+ DAG.getNode( \
+ LoongArchISD::NODE, DL, MVT::i64, \
+ DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2), \
+ DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3))))); \
Results.push_back(N->getOperand(0)); \
break; \
}
@@ -966,15 +1016,80 @@ void LoongArchTargetLowering::ReplaceNodeResults(
#define CRC_CASE_EXT_UNARYOP(NAME, NODE) \
case Intrinsic::loongarch_##NAME: { \
- Results.push_back(DAG.getNode( \
- ISD::TRUNCATE, DL, VT, \
- DAG.getNode(LoongArchISD::NODE, DL, MVT::i64, Op2, \
- DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op3)))); \
+ Results.push_back( \
+ DAG.getNode(ISD::TRUNCATE, DL, VT, \
+ DAG.getNode(LoongArchISD::NODE, DL, MVT::i64, Op2, \
+ DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, \
+ N->getOperand(3))))); \
Results.push_back(N->getOperand(0)); \
break; \
}
CRC_CASE_EXT_UNARYOP(crc_w_d_w, CRC_W_D_W)
CRC_CASE_EXT_UNARYOP(crcc_w_d_w, CRCC_W_D_W)
+#define CSR_CASE(ID) \
+ case Intrinsic::loongarch_##ID: { \
+ if (!Subtarget.is64Bit()) { \
+ DAG.getContext()->emitError(Name + " requires target: loongarch64"); \
+ Results.push_back(DAG.getUNDEF(VT)); \
+ Results.push_back(N->getOperand(0)); \
+ } \
+ break; \
+ }
+ CSR_CASE(csrrd_d);
+ CSR_CASE(csrwr_d);
+ CSR_CASE(csrxchg_d);
+ case Intrinsic::loongarch_csrrd_w: {
+ unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
+ if (!isUInt<14>(Imm)) {
+ DAG.getContext()->emitError("argument to '" + Name + "' out of range");
+ Results.push_back(DAG.getUNDEF(VT));
+ Results.push_back(N->getOperand(0));
+ break;
+ }
+
+ Results.push_back(
+ DAG.getNode(ISD::TRUNCATE, DL, VT,
+ DAG.getNode(LoongArchISD::CSRRD, DL, GRLenVT, Op0,
+ DAG.getConstant(Imm, DL, GRLenVT))));
+ Results.push_back(N->getOperand(0));
+ break;
+ }
+ case Intrinsic::loongarch_csrwr_w: {
+ unsigned Imm = cast<ConstantSDNode>(N->getOperand(3))->getZExtValue();
+ if (!isUInt<14>(Imm)) {
+ DAG.getContext()->emitError("argument to '" + Name + "' out of range");
+ Results.push_back(DAG.getUNDEF(VT));
+ Results.push_back(N->getOperand(0));
+ break;
+ }
+
+ Results.push_back(DAG.getNode(
+ ISD::TRUNCATE, DL, VT,
+ DAG.getNode(LoongArchISD::CSRWR, DL, GRLenVT, Op0,
+ DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),
+ DAG.getConstant(Imm, DL, GRLenVT))));
+ Results.push_back(N->getOperand(0));
+ break;
+ }
+ case Intrinsic::loongarch_csrxchg_w: {
+ unsigned Imm = cast<ConstantSDNode>(N->getOperand(4))->getZExtValue();
+ if (!isUInt<14>(Imm)) {
+ DAG.getContext()->emitError("argument to '" + Name + "' out of range");
+ Results.push_back(DAG.getUNDEF(VT));
+ Results.push_back(N->getOperand(0));
+ break;
+ }
+
+ Results.push_back(DAG.getNode(
+ ISD::TRUNCATE, DL, VT,
+ DAG.getNode(
+ LoongArchISD::CSRXCHG, DL, GRLenVT, Op0,
+ DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),
+ DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3)),
+ DAG.getConstant(Imm, DL, GRLenVT))));
+ Results.push_back(N->getOperand(0));
+ break;
+ }
}
break;
}
@@ -1456,6 +1571,9 @@ const char *LoongArchTargetLowering::getTargetNodeName(unsigned Opcode) const {
NODE_NAME_CASE(CRCC_W_H_W)
NODE_NAME_CASE(CRCC_W_W_W)
NODE_NAME_CASE(CRCC_W_D_W)
+ NODE_NAME_CASE(CSRRD)
+ NODE_NAME_CASE(CSRWR)
+ NODE_NAME_CASE(CSRXCHG)
}
#undef NODE_NAME_CASE
return nullptr;
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
index 6f34284ccec53..9dcc5bce0fa57 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
@@ -73,7 +73,11 @@ enum NodeType : unsigned {
CRCC_W_B_W,
CRCC_W_H_W,
CRCC_W_W_W,
- CRCC_W_D_W
+ CRCC_W_D_W,
+
+ CSRRD,
+ CSRWR,
+ CSRXCHG,
};
} // end namespace LoongArchISD
diff --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
index dea15f7e3c66a..83ca6a395b8e6 100644
--- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
+++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
@@ -38,6 +38,15 @@ def SDT_LoongArchBStrPick: SDTypeProfile<1, 3, [
// "VI" means no output and an integer input.
def SDT_LoongArchVI : SDTypeProfile<0, 1, [SDTCisVT<0, GRLenVT>]>;
+def SDT_LoongArchCsrrd : SDTypeProfile<1, 1, [SDTCisInt<0>,
+ SDTCisVT<1, GRLenVT>]>;
+def SDT_LoongArchCsrwr : SDTypeProfile<1, 2, [SDTCisInt<0>, SDTCisSameAs<0, 1>,
+ SDTCisVT<2, GRLenVT>]>;
+def SDT_LoongArchCsrxchg : SDTypeProfile<1, 3, [SDTCisInt<0>,
+ SDTCisSameAs<0, 1>,
+ SDTCisSameAs<0, 2>,
+ SDTCisVT<3, GRLenVT>]>;
+
// TODO: Add LoongArch specific DAG Nodes
// Target-independent nodes, but with target-specific formats.
def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_CallSeqStart,
@@ -93,6 +102,13 @@ def loongarch_break : SDNode<"LoongArchISD::BREAK", SDT_LoongArchVI,
[SDNPHasChain, SDNPSideEffect]>;
def loongarch_syscall : SDNode<"LoongArchISD::SYSCALL", SDT_LoongArchVI,
[SDNPHasChain, SDNPSideEffect]>;
+def loongarch_csrrd : SDNode<"LoongArchISD::CSRRD", SDT_LoongArchCsrrd,
+ [SDNPHasChain, SDNPSideEffect]>;
+def loongarch_csrwr : SDNode<"LoongArchISD::CSRWR", SDT_LoongArchCsrwr,
+ [SDNPHasChain, SDNPSideEffect]>;
+def loongarch_csrxchg : SDNode<"LoongArchISD::CSRXCHG",
+ SDT_LoongArchCsrxchg,
+ [SDNPHasChain, SDNPSideEffect]>;
//===----------------------------------------------------------------------===//
// Operand and SDNode transformation definitions.
@@ -159,7 +175,8 @@ def uimm12_ori : UImm12Operand {
let ParserMatchClass = UImmAsmOperand<12, "ori">;
}
-def uimm14 : Operand<GRLenVT> {
+def uimm14 : Operand<GRLenVT>,
+ ImmLeaf <GRLenVT, [{return isUInt<14>(Imm);}]> {
let ParserMatchClass = UImmAsmOperand<14>;
}
@@ -1627,3 +1644,13 @@ def LDPTE : FmtLDPTE<(outs), (ins GPR:$rj, uimm8:$seq), "ldpte", "$rj, $seq">;
def ERTN : FmtI32<0b00000110010010000011100000000000, "ertn">;
def DBCL : MISC_I15<0b00000000001010101, "dbcl">;
def IDLE : MISC_I15<0b00000110010010001, "idle">;
+
+//===----------------------------------------------------------------------===//
+// Privilege Intrinsics
+//===----------------------------------------------------------------------===//
+
+def : Pat<(loongarch_csrrd uimm14:$imm14), (CSRRD uimm14:$imm14)>;
+def : Pat<(loongarch_csrwr GPR:$rd, uimm14:$imm14),
+ (CSRWR GPR:$rd, uimm14:$imm14)>;
+def : Pat<(loongarch_csrxchg GPR:$rd, GPR:$rj, uimm14:$imm14),
+ (CSRXCHG GPR:$rd, GPR:$rj, uimm14:$imm14)>;
diff --git a/llvm/test/CodeGen/LoongArch/intrinsic-error.ll b/llvm/test/CodeGen/LoongArch/intrinsic-error.ll
index 053df872da909..213aa2adf6a58 100644
--- a/llvm/test/CodeGen/LoongArch/intrinsic-error.ll
+++ b/llvm/test/CodeGen/LoongArch/intrinsic-error.ll
@@ -6,6 +6,9 @@ declare void @llvm.loongarch.dbar(i32)
declare void @llvm.loongarch.ibar(i32)
declare void @llvm.loongarch.break(i32)
declare void @llvm.loongarch.syscall(i32)
+declare i32 @llvm.loongarch.csrrd.w(i32 immarg)
+declare i32 @llvm.loongarch.csrwr.w(i32, i32 immarg)
+declare i32 @llvm.loongarch.csrxchg.w(i32, i32, i32 immarg)
define void @dbar_imm_out_of_hi_range() nounwind {
; CHECK: argument to 'llvm.loongarch.dbar' out of range
@@ -62,3 +65,45 @@ entry:
call void @llvm.loongarch.syscall(i32 -1)
ret void
}
+
+define i32 @csrrd_w_imm_out_of_hi_range() nounwind {
+; CHECK: argument to 'llvm.loongarch.csrrd.w' out of range
+entry:
+ %0 = call i32 @llvm.loongarch.csrrd.w(i32 16384)
+ ret i32 %0
+}
+
+define i32 @csrrd_w_imm_out_of_lo_range() nounwind {
+; CHECK: argument to 'llvm.loongarch.csrrd.w' out of range
+entry:
+ %0 = call i32 @llvm.loongarch.csrrd.w(i32 -1)
+ ret i32 %0
+}
+
+define i32 @csrwr_w_imm_out_of_hi_range(i32 %a) nounwind {
+; CHECK: argument to 'llvm.loongarch.csrwr.w' out of range
+entry:
+ %0 = call i32 @llvm.loongarch.csrwr.w(i32 %a, i32 16384)
+ ret i32 %0
+}
+
+define i32 @csrwr_w_imm_out_of_lo_range(i32 %a) nounwind {
+; CHECK: argument to 'llvm.loongarch.csrwr.w' out of range
+entry:
+ %0 = call i32 @llvm.loongarch.csrwr.w(i32 %a, i32 -1)
+ ret i32 %0
+}
+
+define i32 @csrxchg_w_imm_out_of_hi_range(i32 %a, i32 %b) nounwind {
+; CHECK: argument to 'llvm.loongarch.csrxchg.w' out of range
+entry:
+ %0 = call i32 @llvm.loongarch.csrxchg.w(i32 %a, i32 %b, i32 16384)
+ ret i32 %0
+}
+
+define i32 @csrxchg_w_imm_out_of_lo_range(i32 %a, i32 %b) nounwind {
+; CHECK: argument to 'llvm.loongarch.csrxchg.w' out of range
+entry:
+ %0 = call i32 @llvm.loongarch.csrxchg.w(i32 %a, i32 %b, i32 -1)
+ ret i32 %0
+}
diff --git a/llvm/test/CodeGen/LoongArch/intrinsic-la32-error.ll b/llvm/test/CodeGen/LoongArch/intrinsic-la32-error.ll
index 9aeff0f57ffd6..19930886a79f9 100644
--- a/llvm/test/CodeGen/LoongArch/intrinsic-la32-error.ll
+++ b/llvm/test/CodeGen/LoongArch/intrinsic-la32-error.ll
@@ -8,6 +8,9 @@ declare i32 @llvm.loongarch.crcc.w.b.w(i32, i32)
declare i32 @llvm.loongarch.crcc.w.h.w(i32, i32)
declare i32 @llvm.loongarch.crcc.w.w.w(i32, i32)
declare i32 @llvm.loongarch.crcc.w.d.w(i64, i32)
+declare i64 @llvm.loongarch.csrrd.d(i32 immarg)
+declare i64 @llvm.loongarch.csrwr.d(i64, i32 immarg)
+declare i64 @llvm.loongarch.csrxchg.d(i64, i64, i32 immarg)
define i32 @crc_w_b_w(i32 %a, i32 %b) nounwind {
; CHECK: llvm.loongarch.crc.w.b.w requires target: loongarch64
@@ -64,3 +67,24 @@ entry:
%res = call i32 @llvm.loongarch.crcc.w.d.w(i64 %a, i32 %b)
ret i32 %res
}
+
+define i64 @csrrd_d() {
+; CHECK: llvm.loongarch.csrrd.d requires target: loongarch64
+entry:
+ %0 = tail call i64 @llvm.loongarch.csrrd.d(i32 1)
+ ret i64 %0
+}
+
+define i64 @csrwr_d(i64 %a) {
+; CHECK: llvm.loongarch.csrwr.d requires target: loongarch64
+entry:
+ %0 = tail call i64 @llvm.loongarch.csrwr.d(i64 %a, i32 1)
+ ret i64 %0
+}
+
+define i64 @csrxchg_d(i64 %a, i64 %b) {
+; CHECK: llvm.loongarch.csrxchg.d requires target: loongarch64
+entry:
+ %0 = tail call i64 @llvm.loongarch.csrxchg.d(i64 %a, i64 %b, i32 1)
+ ret i64 %0
+}
diff --git a/llvm/test/CodeGen/LoongArch/intrinsic-la64-error.ll b/llvm/test/CodeGen/LoongArch/intrinsic-la64-error.ll
new file mode 100644
index 0000000000000..05eb9f313e24f
--- /dev/null
+++ b/llvm/test/CodeGen/LoongArch/intrinsic-la64-error.ll
@@ -0,0 +1,48 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: not llc --mtriple=loongarch64 < %s 2>&1 | FileCheck %s
+
+declare i64 @llvm.loongarch.csrrd.d(i32 immarg)
+declare i64 @llvm.loongarch.csrwr.d(i64, i32 immarg)
+declare i64 @llvm.loongarch.csrxchg.d(i64, i64, i32 immarg)
+
+define i64 @csrrd_d_imm_out_of_hi_range() nounwind {
+; CHECK: argument to 'llvm.loongarch.csrrd.d' out of range
+entry:
+ %0 = call i64 @llvm.loongarch.csrrd.d(i32 16384)
+ ret i64 %0
+}
+
+define i64 @csrrd_d_imm_out_of_lo_range() nounwind {
+; CHECK: argument to 'llvm.loongarch.csrrd.d' out of range
+entry:
+ %0 = call i64 @llvm.loongarch.csrrd.d(i32 -1)
+ ret i64 %0
+}
+
+define i64 @csrwr_d_imm_out_of_hi_range(i64 %a) nounwind {
+; CHECK: argument to 'llvm.loongarch.csrwr.d' out of range
+entry:
+ %0 = call i64 @llvm.loongarch.csrwr.d(i64 %a, i32 16384)
+ ret i64 %0
+}
+
+define i64 @csrwr_d_imm_out_of_lo_range(i64 %a) nounwind {
+; CHECK: argument to 'llvm.loongarch.csrwr.d' out of range
+entry:
+ %0 = call i64 @llvm.loongarch.csrwr.d(i64 %a, i32 -1)
+ ret i64 %0
+}
+
+define i64 @csrxchg_d_imm_out_of_hi_range(i64 %a, i64 %b) nounwind {
+; CHECK: argument to 'llvm.loongarch.csrxchg.d' out of range
+entry:
+ %0 = call i64 @llvm.loongarch.csrxchg.d(i64 %a, i64 %b, i32 16384)
+ ret i64 %0
+}
+
+define i64 @csrxchg_d_imm_out_of_lo_range(i64 %a, i64 %b) nounwind {
+; CHECK: argument to 'llvm.loongarch.csrxchg.d' out of range
+entry:
+ %0 = call i64 @llvm.loongarch.csrxchg.d(i64 %a, i64 %b, i32 -1)
+ ret i64 %0
+}
diff --git a/llvm/test/CodeGen/LoongArch/intrinsic-la64.ll b/llvm/test/CodeGen/LoongArch/intrinsic-la64.ll
index fd06313a37c4a..8b439b8b6cfe8 100644
--- a/llvm/test/CodeGen/LoongArch/intrinsic-la64.ll
+++ b/llvm/test/CodeGen/LoongArch/intrinsic-la64.ll
@@ -9,6 +9,9 @@ declare i32 @llvm.loongarch.crcc.w.b.w(i32, i32)
declare i32 @llvm.loongarch.crcc.w.h.w(i32, i32)
declare i32 @llvm.loongarch.crcc.w.w.w(i32, i32)
declare i32 @llvm.loongarch.crcc.w.d.w(i64, i32)
+declare i64 @llvm.loongarch.csrrd.d(i32 immarg)
+declare i64 @llvm.loongarch.csrwr.d(i64, i32 immarg)
+declare i64 @llvm.loongarch.csrxchg.d(i64, i64, i32 immarg)
define i32 @crc_w_b_w(i32 %a, i32 %b) nounwind {
; CHECK-LABEL: crc_w_b_w:
@@ -81,3 +84,33 @@ define i32 @crcc_w_d_w(i64 %a, i32 %b) nounwind {
%res = call i32 @llvm.loongarch.crcc.w.d.w(i64 %a, i32 %b)
ret i32 %res
}
+
+define i64 @csrrd_d() {
+; CHECK-LABEL: csrrd_d:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: csrrd $a0, 1
+; CHECK-NEXT: ret
+entry:
+ %0 = tail call i64 @llvm.loongarch.csrrd.d(i32 1)
+ ret i64 %0
+}
+
+define i64 @csrwr_d(i64 %a) {
+; CHECK-LABEL: csrwr_d:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: csrwr $a0, 1
+; CHECK-NEXT: ret
+entry:
+ %0 = tail call i64 @llvm.loongarch.csrwr.d(i64 %a, i32 1)
+ ret i64 %0
+}
+
+define i64 @csrxchg_d(i64 %a, i64 %b) {
+; CHECK-LABEL: csrxchg_d:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: csrxchg $a0, $a1, 1
+; CHECK-NEXT: ret
+entry:
+ %0 = tail call i64 @llvm.loongarch.csrxchg.d(i64 %a, i64 %b, i32 1)
+ ret i64 %0
+}
diff --git a/llvm/test/CodeGen/LoongArch/intrinsic.ll b/llvm/test/CodeGen/LoongArch/intrinsic.ll
index ea5c07e28f164..297e4d34cfee6 100644
--- a/llvm/test/CodeGen/LoongArch/intrinsic.ll
+++ b/llvm/test/CodeGen/LoongArch/intrinsic.ll
@@ -6,6 +6,9 @@ declare void @llvm.loongarch.dbar(i32)
declare void @llvm.loongarch.ibar(i32)
declare void @llvm.loongarch.break(i32)
declare void @llvm.loongarch.syscall(i32)
+declare i32 @llvm.loongarch.csrrd.w(i32 immarg)
+declare i32 @llvm.loongarch.csrwr.w(i32, i32 immarg)
+declare i32 @llvm.loongarch.csrxchg.w(i32, i32, i32 immarg)
define void @foo() nounwind {
; CHECK-LABEL: foo:
@@ -46,3 +49,33 @@ entry:
call void @llvm.loongarch.syscall(i32 1)
ret void
}
+
+define i32 @csrrd_w() {
+; CHECK-LABEL: csrrd_w:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: csrrd $a0, 1
+; CHECK-NEXT: ret
+entry:
+ %0 = tail call i32 @llvm.loongarch.csrrd.w(i32 1)
+ ret i32 %0
+}
+
+define i32 @csrwr_w(i32 signext %a) {
+; CHECK-LABEL: csrwr_w:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: csrwr $a0, 1
+; CHECK-NEXT: ret
+entry:
+ %0 = tail call i32 @llvm.loongarch.csrwr.w(i32 %a, i32 1)
+ ret i32 %0
+}
+
+define i32 @csrxchg_w(i32 signext %a, i32 signext %b) {
+; CHECK-LABEL: csrxchg_w:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: csrxchg $a0, $a1, 1
+; CHECK-NEXT: ret
+entry:
+ %0 = tail call i32 @llvm.loongarch.csrxchg.w(i32 %a, i32 %b, i32 1)
+ ret i32 %0
+}
More information about the llvm-commits
mailing list