[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