[llvm] 63d4686 - [LoongArch] Add intrinsics for MOVFCSR2GR and MOVGR2FCSR instructions

Xiaodong Liu via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 3 22:12:42 PST 2023


Author: Xiaodong Liu
Date: 2023-01-04T14:11:30+08:00
New Revision: 63d46869ea5769693f7895be066f042929512e06

URL: https://github.com/llvm/llvm-project/commit/63d46869ea5769693f7895be066f042929512e06
DIFF: https://github.com/llvm/llvm-project/commit/63d46869ea5769693f7895be066f042929512e06.diff

LOG: [LoongArch] Add intrinsics for MOVFCSR2GR and MOVGR2FCSR instructions

Instruction formats:
`movgr2fcsr fcsr, rj`
`movfcsr2gr rd, fcsr`
MOVGR2FCSR modifies the value of the software writable field
corresponding to the FCSR (floating-point control and status
register) `fcsr` according to the value of the lower 32 bits of
the GR (general purpose register) `rj`.
MOVFCSR2GR sign extends the 32-bit value of the FCSR `fcsr`
and writes it into the GR `rd`.

Add "i32 @llvm.loongarch.movfcsr2gr(i32)" intrinsic for MOVFCSR2GR
instruction. The argument is FCSR register number. The return value
is the value in the FCSR.
Add "void @llvm.loongarch.movgr2fcsr(i32, i32)" intrinsic for MOVGR2FCSR
instruction. The first argument is the FCSR number, the second argument
is the value in GR.

Reviewed By: SixWeining, xen0n

Differential Revision: https://reviews.llvm.org/D140685

Added: 
    

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-la32-error.c
    clang/test/CodeGen/LoongArch/intrinsic-la32.c
    clang/test/CodeGen/LoongArch/intrinsic-la64-error.c
    clang/test/CodeGen/LoongArch/intrinsic-la64.c
    llvm/include/llvm/IR/IntrinsicsLoongArch.td
    llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.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-not-constant-error.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 98b1738b7223..cc466cf2703c 100644
--- a/clang/include/clang/Basic/BuiltinsLoongArch.def
+++ b/clang/include/clang/Basic/BuiltinsLoongArch.def
@@ -19,6 +19,8 @@
 // TODO: Added feature constraints.
 TARGET_BUILTIN(__builtin_loongarch_dbar, "vIUi", "nc", "")
 TARGET_BUILTIN(__builtin_loongarch_ibar, "vIUi", "nc", "")
+TARGET_BUILTIN(__builtin_loongarch_movfcsr2gr, "UiIUi", "nc", "f")
+TARGET_BUILTIN(__builtin_loongarch_movgr2fcsr, "vIUiUi", "nc", "f")
 TARGET_BUILTIN(__builtin_loongarch_break, "vIUi", "nc", "")
 TARGET_BUILTIN(__builtin_loongarch_syscall, "vIUi", "nc", "")
 TARGET_BUILTIN(__builtin_loongarch_cpucfg, "UiUi", "nc", "")

diff  --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index cb2dd54e0f73..b1e8517460ce 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -19703,6 +19703,12 @@ Value *CodeGenFunction::EmitLoongArchBuiltinExpr(unsigned BuiltinID,
   case LoongArch::BI__builtin_loongarch_ibar:
     ID = Intrinsic::loongarch_ibar;
     break;
+  case LoongArch::BI__builtin_loongarch_movfcsr2gr:
+    ID = Intrinsic::loongarch_movfcsr2gr;
+    break;
+  case LoongArch::BI__builtin_loongarch_movgr2fcsr:
+    ID = Intrinsic::loongarch_movgr2fcsr;
+    break;
   case LoongArch::BI__builtin_loongarch_syscall:
     ID = Intrinsic::loongarch_syscall;
     break;

diff  --git a/clang/lib/Headers/larchintrin.h b/clang/lib/Headers/larchintrin.h
index 524c13489db1..5edcf4c02a44 100644
--- a/clang/lib/Headers/larchintrin.h
+++ b/clang/lib/Headers/larchintrin.h
@@ -110,6 +110,11 @@ extern __inline int
 
 #define __ibar(/*ui15*/ _1) __builtin_loongarch_ibar((_1))
 
+#define __movfcsr2gr(/*ui5*/ _1) __builtin_loongarch_movfcsr2gr((_1));
+
+#define __movgr2fcsr(/*ui5*/ _1, _2)                                           \
+  __builtin_loongarch_movgr2fcsr((_1), (unsigned int)_2);
+
 #define __syscall(/*ui15*/ _1) __builtin_loongarch_syscall((_1))
 
 #define __csrrd_w(/*ui14*/ _1) ((unsigned int)__builtin_loongarch_csrrd_w((_1)))

diff  --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 75296306c98e..05bf498737ec 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -3759,6 +3759,9 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI,
                   diag::err_loongarch_builtin_requires_la64)
              << TheCall->getSourceRange();
     return SemaBuiltinConstantArgRange(TheCall, 1, 0, 31);
+  case LoongArch::BI__builtin_loongarch_movfcsr2gr:
+  case LoongArch::BI__builtin_loongarch_movgr2fcsr:
+    return SemaBuiltinConstantArgRange(TheCall, 0, 0, llvm::maxUIntN(2));
   }
 
   return false;

diff  --git a/clang/test/CodeGen/LoongArch/intrinsic-la32-error.c b/clang/test/CodeGen/LoongArch/intrinsic-la32-error.c
index cca7f14c94c4..9941a6f874cb 100644
--- a/clang/test/CodeGen/LoongArch/intrinsic-la32-error.c
+++ b/clang/test/CodeGen/LoongArch/intrinsic-la32-error.c
@@ -21,6 +21,19 @@ void loongarch_break(int a) {
   __builtin_loongarch_break(a); // expected-error {{argument to '__builtin_loongarch_break' must be a constant integer}}
 }
 
+int movfcsr2gr_out_of_lo_range(int a) {
+  int b =  __builtin_loongarch_movfcsr2gr(-1); // expected-error {{argument value 4294967295 is outside the valid range [0, 3]}}
+  int c = __builtin_loongarch_movfcsr2gr(32); // expected-error {{argument value 32 is outside the valid range [0, 3]}}
+  int d = __builtin_loongarch_movfcsr2gr(a); // expected-error {{argument to '__builtin_loongarch_movfcsr2gr' must be a constant integer}}
+  return 0;
+}
+
+void movgr2fcsr(int a, int b) {
+  __builtin_loongarch_movgr2fcsr(-1, b); // expected-error {{argument value 4294967295 is outside the valid range [0, 3]}}
+  __builtin_loongarch_movgr2fcsr(32, b); // expected-error {{argument value 32 is outside the valid range [0, 3]}}
+  __builtin_loongarch_movgr2fcsr(a, b); // expected-error {{argument to '__builtin_loongarch_movgr2fcsr' must be a constant integer}}
+}
+
 void syscall(int a) {
   __builtin_loongarch_syscall(32769); // expected-error {{argument value 32769 is outside the valid range [0, 32767]}}
   __builtin_loongarch_syscall(-1); // expected-error {{argument value 4294967295 is outside the valid range [0, 32767]}}

diff  --git a/clang/test/CodeGen/LoongArch/intrinsic-la32.c b/clang/test/CodeGen/LoongArch/intrinsic-la32.c
index dbfa554acb4f..060692a79ef4 100644
--- a/clang/test/CodeGen/LoongArch/intrinsic-la32.c
+++ b/clang/test/CodeGen/LoongArch/intrinsic-la32.c
@@ -1,5 +1,5 @@
 // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
-// RUN: %clang_cc1 -triple loongarch32 -O2 -emit-llvm %s -o - \
+// RUN: %clang_cc1 -triple loongarch32 -target-feature +f -O2 -emit-llvm %s -o - \
 // RUN:     | FileCheck %s -check-prefix=LA32
 
 #include <larchintrin.h>
@@ -177,3 +177,26 @@ void rdtime() {
   __rdtimeh_w();
   __rdtimel_w();
 }
+
+// LA32-LABEL: @loongarch_movfcsr2gr(
+// LA32-NEXT:  entry:
+// LA32-NEXT:    [[TMP0:%.*]] = tail call i32 @llvm.loongarch.movfcsr2gr(i32 1)
+// LA32-NEXT:    [[TMP1:%.*]] = tail call i32 @llvm.loongarch.movfcsr2gr(i32 1)
+// LA32-NEXT:    ret i32 0
+//
+int loongarch_movfcsr2gr() {
+  int a =  __movfcsr2gr(1);
+  int b = __builtin_loongarch_movfcsr2gr(1);
+  return 0;
+}
+
+// LA32-LABEL: @loongarch_movgr2fcsr(
+// LA32-NEXT:  entry:
+// LA32-NEXT:    tail call void @llvm.loongarch.movgr2fcsr(i32 1, i32 [[A:%.*]])
+// LA32-NEXT:    tail call void @llvm.loongarch.movgr2fcsr(i32 1, i32 [[A]])
+// LA32-NEXT:    ret void
+//
+void loongarch_movgr2fcsr(int a) {
+  __movgr2fcsr(1, a);
+  __builtin_loongarch_movgr2fcsr(1, a);
+}

diff  --git a/clang/test/CodeGen/LoongArch/intrinsic-la64-error.c b/clang/test/CodeGen/LoongArch/intrinsic-la64-error.c
index 93294af03af2..60dfece74be6 100644
--- a/clang/test/CodeGen/LoongArch/intrinsic-la64-error.c
+++ b/clang/test/CodeGen/LoongArch/intrinsic-la64-error.c
@@ -32,3 +32,16 @@ void ldpte_d(long int a, int b) {
   __builtin_loongarch_ldpte_d(a, -1); // expected-error {{argument value 18446744073709551615 is outside the valid range [0, 31]}}
   __builtin_loongarch_ldpte_d(a, b); // expected-error {{argument to '__builtin_loongarch_ldpte_d' must be a constant integer}}
 }
+
+int movfcsr2gr_out_of_lo_range(int a) {
+  int b = __builtin_loongarch_movfcsr2gr(-1); // expected-error {{argument value 4294967295 is outside the valid range [0, 3]}}
+  int c = __builtin_loongarch_movfcsr2gr(32); // expected-error {{argument value 32 is outside the valid range [0, 3]}}
+  int d = __builtin_loongarch_movfcsr2gr(a); // expected-error {{argument to '__builtin_loongarch_movfcsr2gr' must be a constant integer}}
+  return 0;
+}
+
+void movgr2fcsr(int a, int b) {
+  __builtin_loongarch_movgr2fcsr(-1, b); // expected-error {{argument value 4294967295 is outside the valid range [0, 3]}}
+  __builtin_loongarch_movgr2fcsr(32, b); // expected-error {{argument value 32 is outside the valid range [0, 3]}}
+  __builtin_loongarch_movgr2fcsr(a, b); // expected-error {{argument to '__builtin_loongarch_movgr2fcsr' must be a constant integer}}
+}

diff  --git a/clang/test/CodeGen/LoongArch/intrinsic-la64.c b/clang/test/CodeGen/LoongArch/intrinsic-la64.c
index da39d45b8667..a8e8f7dddade 100644
--- a/clang/test/CodeGen/LoongArch/intrinsic-la64.c
+++ b/clang/test/CodeGen/LoongArch/intrinsic-la64.c
@@ -1,5 +1,5 @@
 // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
-// RUN: %clang_cc1 -triple loongarch64 -O2 -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple loongarch64 -target-feature +f -O2 -emit-llvm %s -o - | FileCheck %s
 
 #include <larchintrin.h>
 
@@ -393,3 +393,26 @@ void rdtime() {
   __rdtimeh_w();
   __rdtimel_w();
 }
+
+// CHECK-LABEL: @loongarch_movfcsr2gr(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = tail call i32 @llvm.loongarch.movfcsr2gr(i32 1)
+// CHECK-NEXT:    [[TMP1:%.*]] = tail call i32 @llvm.loongarch.movfcsr2gr(i32 1)
+// CHECK-NEXT:    ret i32 0
+//
+int loongarch_movfcsr2gr() {
+  int a =  __movfcsr2gr(1);
+  int b = __builtin_loongarch_movfcsr2gr(1);
+  return 0;
+}
+
+// CHECK-LABEL: @loongarch_movgr2fcsr(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    tail call void @llvm.loongarch.movgr2fcsr(i32 1, i32 [[A:%.*]])
+// CHECK-NEXT:    tail call void @llvm.loongarch.movgr2fcsr(i32 1, i32 [[A]])
+// CHECK-NEXT:    ret void
+//
+void loongarch_movgr2fcsr(int a) {
+  __movgr2fcsr(1, a);
+  __builtin_loongarch_movgr2fcsr(1, a);
+}

diff  --git a/llvm/include/llvm/IR/IntrinsicsLoongArch.td b/llvm/include/llvm/IR/IntrinsicsLoongArch.td
index ec3c2402849d..995e357d3186 100644
--- a/llvm/include/llvm/IR/IntrinsicsLoongArch.td
+++ b/llvm/include/llvm/IR/IntrinsicsLoongArch.td
@@ -54,6 +54,10 @@ defm int_loongarch_masked_cmpxchg : MaskedAtomicRMWFiveOpIntrinsics;
 def int_loongarch_break : Intrinsic<[], [llvm_i32_ty], [ImmArg<ArgIndex<0>>]>;
 def int_loongarch_dbar : Intrinsic<[], [llvm_i32_ty], [ImmArg<ArgIndex<0>>]>;
 def int_loongarch_ibar : Intrinsic<[], [llvm_i32_ty], [ImmArg<ArgIndex<0>>]>;
+def int_loongarch_movfcsr2gr : Intrinsic<[llvm_i32_ty], [llvm_i32_ty],
+                               [ImmArg<ArgIndex<0>>]>;
+def int_loongarch_movgr2fcsr : Intrinsic<[], [llvm_i32_ty, llvm_i32_ty],
+                               [ImmArg<ArgIndex<0>>]>;
 def int_loongarch_syscall : Intrinsic<[], [llvm_i32_ty], [ImmArg<ArgIndex<0>>]>;
 
 def int_loongarch_crc_w_b_w : Intrinsic<[llvm_i32_ty],

diff  --git a/llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td
index 40e7665fb1f7..f6981a0b2d9a 100644
--- a/llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td
+++ b/llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td
@@ -98,7 +98,8 @@ def FSEL_S : FP_SEL<0b00001101000000, "fsel", FPR32>;
 def FMOV_S     : FP_MOV<0b0000000100010100100101, "fmov.s", FPR32, FPR32>;
 def MOVGR2FR_W : FP_MOV<0b0000000100010100101001, "movgr2fr.w", FPR32, GPR>;
 def MOVFR2GR_S : FP_MOV<0b0000000100010100101101, "movfr2gr.s", GPR, FPR32>;
-def MOVGR2FCSR : FP_MOV<0b0000000100010100110000, "movgr2fcsr", FCSR, GPR>;
+def MOVGR2FCSR : FPFmtMOV<0b0000000100010100110000, (outs), (ins FCSR:$dst, GPR:$src),
+    "movgr2fcsr", "$dst, $src">;
 def MOVFCSR2GR : FP_MOV<0b0000000100010100110010, "movfcsr2gr", GPR, FCSR>;
 def MOVFR2CF_S : FP_MOV<0b0000000100010100110100, "movfr2cf", CFR, FPR32>;
 def MOVCF2FR_S : FP_MOV<0b0000000100010100110101, "movcf2fr", FPR32, CFR>;

diff  --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
index fc06fc9226de..dc98eac76ac2 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -708,6 +708,26 @@ LoongArchTargetLowering::lowerINTRINSIC_W_CHAIN(SDValue Op,
 
     return Op;
   }
+  case Intrinsic::loongarch_movfcsr2gr: {
+    if (!Subtarget.hasBasicF()) {
+      DAG.getContext()->emitError(
+          "llvm.loongarch.movfcsr2gr expects basic f target feature");
+      return DAG.getMergeValues(
+          {DAG.getUNDEF(Op.getValueType()), Op.getOperand(0)}, SDLoc(Op));
+    }
+    unsigned Imm = cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue();
+    if (!isUInt<2>(Imm)) {
+      DAG.getContext()->emitError("argument to '" + Op->getOperationName(0) +
+                                  "' " + ErrorMsgOOR);
+      return DAG.getMergeValues(
+          {DAG.getUNDEF(Op.getValueType()), Op.getOperand(0)}, SDLoc(Op));
+    }
+    return DAG.getMergeValues(
+        {DAG.getNode(LoongArchISD::MOVFCSR2GR, DL, Op.getValueType(),
+                     DAG.getRegister(LoongArch::FCSR0 + Imm, MVT::i32)),
+         Op.getOperand(0)},
+        DL);
+  }
   }
 }
 
@@ -757,6 +777,21 @@ SDValue LoongArchTargetLowering::lowerINTRINSIC_VOID(SDValue Op,
     return DAG.getNode(LoongArchISD::BREAK, DL, MVT::Other, Op0,
                        DAG.getConstant(Imm, DL, GRLenVT));
   }
+  case Intrinsic::loongarch_movgr2fcsr: {
+    if (!Subtarget.hasBasicF()) {
+      DAG.getContext()->emitError(
+          "llvm.loongarch.movgr2fcsr expects basic f target feature");
+      return Op0;
+    }
+    unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
+    if (!isUInt<2>(Imm))
+      return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
+
+    return DAG.getNode(
+        LoongArchISD::MOVGR2FCSR, DL, MVT::Other, Op0,
+        DAG.getRegister(LoongArch::FCSR0 + Imm, MVT::i32),
+        DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Op.getOperand(3)));
+  }
   case Intrinsic::loongarch_syscall: {
     unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
     if (!isUInt<15>(Imm))
@@ -1085,11 +1120,38 @@ void LoongArchTargetLowering::ReplaceNodeResults(
   }
   case ISD::INTRINSIC_W_CHAIN: {
     SDValue Op0 = N->getOperand(0);
+    EVT VT = N->getValueType(0);
+    uint64_t Op1 = N->getConstantOperandVal(1);
+    if (Op1 == Intrinsic::loongarch_movfcsr2gr) {
+      if (!Subtarget.hasBasicF()) {
+        DAG.getContext()->emitError(
+            "llvm.loongarch.movfcsr2gr expects basic f target feature");
+        Results.push_back(DAG.getMergeValues(
+            {DAG.getUNDEF(N->getValueType(0)), N->getOperand(0)}, SDLoc(N)));
+        Results.push_back(N->getOperand(0));
+        return;
+      }
+      unsigned Imm = cast<ConstantSDNode>(N->getOperand(2))->getZExtValue();
+      if (!isUInt<2>(Imm)) {
+        DAG.getContext()->emitError("argument to '" + N->getOperationName(0) +
+                                    "' " + "out of range");
+        Results.push_back(DAG.getMergeValues(
+            {DAG.getUNDEF(N->getValueType(0)), N->getOperand(0)}, SDLoc(N)));
+        Results.push_back(N->getOperand(0));
+        return;
+      }
+      Results.push_back(DAG.getNode(
+          ISD::TRUNCATE, DL, VT,
+          DAG.getNode(LoongArchISD::MOVFCSR2GR, SDLoc(N), MVT::i64,
+                      DAG.getRegister(LoongArch::FCSR0 + Imm, MVT::i32))));
+      Results.push_back(N->getOperand(0));
+      return;
+    }
     SDValue Op2 = N->getOperand(2);
     MVT GRLenVT = Subtarget.getGRLenVT();
     std::string Name = N->getOperationName(0);
 
-    switch (N->getConstantOperandVal(1)) {
+    switch (Op1) {
     default:
       llvm_unreachable("Unexpected Intrinsic.");
 #define CRC_CASE_EXT_BINARYOP(NAME, NODE)                                      \
@@ -1714,6 +1776,8 @@ const char *LoongArchTargetLowering::getTargetNodeName(unsigned Opcode) const {
     NODE_NAME_CASE(IOCSRWR_W)
     NODE_NAME_CASE(IOCSRWR_D)
     NODE_NAME_CASE(CPUCFG)
+    NODE_NAME_CASE(MOVGR2FCSR)
+    NODE_NAME_CASE(MOVFCSR2GR)
   }
 #undef NODE_NAME_CASE
   return nullptr;

diff  --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
index 858cd05ba931..9227131461d3 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
@@ -43,6 +43,8 @@ enum NodeType : unsigned {
   // FPR<->GPR transfer operations
   MOVGR2FR_W_LA64,
   MOVFR2GR_S_LA64,
+  MOVFCSR2GR,
+  MOVGR2FCSR,
 
   FTINT,
 

diff  --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
index e15579276378..b4a8ad899175 100644
--- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
+++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
@@ -48,6 +48,10 @@ def SDT_LoongArchCsrxchg : SDTypeProfile<1, 3, [SDTCisInt<0>,
                                                 SDTCisVT<3, GRLenVT>]>;
 def SDT_LoongArchIocsrwr : SDTypeProfile<0, 2, [SDTCisInt<0>,
                                                 SDTCisSameAs<0, 1>]>;
+def SDT_LoongArchMovgr2fcsr : SDTypeProfile<0, 2, [SDTCisVT<0, i32>,
+    SDTCisVT<1, GRLenVT>]>;
+def SDT_LoongArchMovfcsr2gr : SDTypeProfile<1, 1, [SDTCisVT<0, GRLenVT>,
+    SDTCisVT<1, i32>]>;
 
 // TODO: Add LoongArch specific DAG Nodes
 // Target-independent nodes, but with target-specific formats.
@@ -102,6 +106,9 @@ def loongarch_ibar : SDNode<"LoongArchISD::IBAR", SDT_LoongArchVI,
                              [SDNPHasChain, SDNPSideEffect]>;
 def loongarch_break : SDNode<"LoongArchISD::BREAK", SDT_LoongArchVI,
                               [SDNPHasChain, SDNPSideEffect]>;
+def loongarch_movfcsr2gr : SDNode<"LoongArchISD::MOVFCSR2GR", SDT_LoongArchMovfcsr2gr>;
+def loongarch_movgr2fcsr : SDNode<"LoongArchISD::MOVGR2FCSR", SDT_LoongArchMovgr2fcsr,
+                                   [SDNPHasChain, SDNPSideEffect]>;
 def loongarch_syscall : SDNode<"LoongArchISD::SYSCALL", SDT_LoongArchVI,
                                 [SDNPHasChain, SDNPSideEffect]>;
 def loongarch_csrrd : SDNode<"LoongArchISD::CSRRD", SDT_LoongArchCsrrd,
@@ -1632,6 +1639,13 @@ def PseudoLI_D : Pseudo<(outs GPR:$rd), (ins grlenimm:$imm), [],
 include "LoongArchFloat32InstrInfo.td"
 include "LoongArchFloat64InstrInfo.td"
 
+let Predicates = [HasBasicF] in {
+def : Pat<(loongarch_movfcsr2gr i32:$fcsr),
+          (MOVFCSR2GR FCSR:$fcsr)>;
+def : Pat<(loongarch_movgr2fcsr i32:$fcsr, GRLenVT:$rj),
+          (MOVGR2FCSR FCSR:$fcsr, GPR:$rj)>;
+}
+
 //===----------------------------------------------------------------------===//
 // Privilege Instructions
 //===----------------------------------------------------------------------===//

diff  --git a/llvm/test/CodeGen/LoongArch/intrinsic-error.ll b/llvm/test/CodeGen/LoongArch/intrinsic-error.ll
index 213aa2adf6a5..882e7f693d0a 100644
--- a/llvm/test/CodeGen/LoongArch/intrinsic-error.ll
+++ b/llvm/test/CodeGen/LoongArch/intrinsic-error.ll
@@ -5,105 +5,151 @@
 declare void @llvm.loongarch.dbar(i32)
 declare void @llvm.loongarch.ibar(i32)
 declare void @llvm.loongarch.break(i32)
+declare void @llvm.loongarch.movgr2fcsr(i32, i32)
+declare i32 @llvm.loongarch.movfcsr2gr(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 {
+define void @dbar_imm_out_of_hi_range() #0 {
 ; CHECK: argument to 'llvm.loongarch.dbar' out of range
 entry:
   call void @llvm.loongarch.dbar(i32 32769)
   ret void
 }
 
-define void @dbar_imm_out_of_lo_range() nounwind {
+define void @dbar_imm_out_of_lo_range() #0 {
 ; CHECK: argument to 'llvm.loongarch.dbar' out of range
 entry:
   call void @llvm.loongarch.dbar(i32 -1)
   ret void
 }
 
-define void @ibar_imm_out_of_hi_range() nounwind {
+define void @ibar_imm_out_of_hi_range() #0 {
 ; CHECK: argument to 'llvm.loongarch.ibar' out of range
 entry:
   call void @llvm.loongarch.ibar(i32 32769)
   ret void
 }
 
-define void @ibar_imm_out_of_lo_range() nounwind {
+define void @ibar_imm_out_of_lo_range() #0 {
 ; CHECK: argument to 'llvm.loongarch.ibar' out of range
 entry:
   call void @llvm.loongarch.ibar(i32 -1)
   ret void
 }
 
-define void @break_imm_out_of_hi_range() nounwind {
+define void @break_imm_out_of_hi_range() #0 {
 ; CHECK: argument to 'llvm.loongarch.break' out of range
 entry:
   call void @llvm.loongarch.break(i32 32769)
   ret void
 }
 
-define void @break_imm_out_of_lo_range() nounwind {
+define void @break_imm_out_of_lo_range() #0 {
 ; CHECK: argument to 'llvm.loongarch.break' out of range
 entry:
   call void @llvm.loongarch.break(i32 -1)
   ret void
 }
 
-define void @syscall_imm_out_of_hi_range() nounwind {
+define void @movgr2fcsr(i32 %a) nounwind {
+; CHECK: llvm.loongarch.movgr2fcsr expects basic f target feature
+entry:
+  call void @llvm.loongarch.movgr2fcsr(i32 1, i32 %a)
+  ret void
+}
+
+define void @movgr2fcsr_imm_out_of_hi_range(i32 %a) #0 {
+; CHECK: argument to 'llvm.loongarch.movgr2fcsr' out of range
+entry:
+  call void @llvm.loongarch.movgr2fcsr(i32 32, i32 %a)
+  ret void
+}
+
+define void @movgr2fcsr_imm_out_of_lo_range(i32 %a) #0 {
+; CHECK: argument to 'llvm.loongarch.movgr2fcsr' out of range
+entry:
+  call void @llvm.loongarch.movgr2fcsr(i32 -1, i32 %a)
+  ret void
+}
+
+define i32 @movfcsr2gr() nounwind {
+; CHECK: llvm.loongarch.movfcsr2gr expects basic f target feature
+entry:
+  %res = call i32 @llvm.loongarch.movfcsr2gr(i32 1)
+  ret i32 %res
+}
+
+define i32 @movfcsr2gr_imm_out_of_hi_range() #0 {
+; CHECK: argument to 'llvm.loongarch.movfcsr2gr' out of range
+entry:
+  %res = call i32 @llvm.loongarch.movfcsr2gr(i32 32)
+  ret i32 %res
+}
+
+define i32 @movfcsr2gr_imm_out_of_lo_range() #0 {
+; CHECK: argument to 'llvm.loongarch.movfcsr2gr' out of range
+entry:
+  %res = call i32 @llvm.loongarch.movfcsr2gr(i32 -1)
+  ret i32 %res
+}
+
+define void @syscall_imm_out_of_hi_range() #0 {
 ; CHECK: argument to 'llvm.loongarch.syscall' out of range
 entry:
   call void @llvm.loongarch.syscall(i32 32769)
   ret void
 }
 
-define void @syscall_imm_out_of_lo_range() nounwind {
+define void @syscall_imm_out_of_lo_range() #0 {
 ; CHECK: argument to 'llvm.loongarch.syscall' out of range
 entry:
   call void @llvm.loongarch.syscall(i32 -1)
   ret void
 }
 
-define i32 @csrrd_w_imm_out_of_hi_range() nounwind {
+define i32 @csrrd_w_imm_out_of_hi_range() #0 {
 ; 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 {
+define i32 @csrrd_w_imm_out_of_lo_range() #0 {
 ; 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 {
+define i32 @csrwr_w_imm_out_of_hi_range(i32 %a) #0 {
 ; 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 {
+define i32 @csrwr_w_imm_out_of_lo_range(i32 %a) #0 {
 ; 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 {
+define i32 @csrxchg_w_imm_out_of_hi_range(i32 %a, i32 %b) #0 {
 ; 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 {
+define i32 @csrxchg_w_imm_out_of_lo_range(i32 %a, i32 %b) #0 {
 ; 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
 }
+
+attributes #0 = { nounwind "target-features"="+f" }

diff  --git a/llvm/test/CodeGen/LoongArch/intrinsic-not-constant-error.ll b/llvm/test/CodeGen/LoongArch/intrinsic-not-constant-error.ll
index 9ba25d7d1b5a..9cb89670c293 100644
--- a/llvm/test/CodeGen/LoongArch/intrinsic-not-constant-error.ll
+++ b/llvm/test/CodeGen/LoongArch/intrinsic-not-constant-error.ll
@@ -4,6 +4,8 @@
 declare void @llvm.loongarch.dbar(i32)
 declare void @llvm.loongarch.ibar(i32)
 declare void @llvm.loongarch.break(i32)
+declare void @llvm.loongarch.movgr2fcsr(i32, i32)
+declare i32 @llvm.loongarch.movfcsr2gr(i32)
 declare void @llvm.loongarch.syscall(i32)
 
 define void @dbar_not_constant(i32 %x) nounwind {
@@ -27,6 +29,20 @@ entry:
   ret void
 }
 
+define void @movgr2fcsr(i32 %a) nounwind {
+; CHECK: immarg operand has non-immediate parameter
+entry:
+  call void @llvm.loongarch.movgr2fcsr(i32 %a, i32 %a)
+  ret void
+}
+
+define i32 @movfcsr2gr(i32 %a) nounwind {
+; CHECK: immarg operand has non-immediate parameter
+entry:
+  %res = call i32 @llvm.loongarch.movfcsr2gr(i32 %a)
+  ret i32 %res
+}
+
 define void @syscall(i32 %x) nounwind {
 ; CHECK: immarg operand has non-immediate parameter
 entry:

diff  --git a/llvm/test/CodeGen/LoongArch/intrinsic.ll b/llvm/test/CodeGen/LoongArch/intrinsic.ll
index 4f5887a9936d..401e07fdefdf 100644
--- a/llvm/test/CodeGen/LoongArch/intrinsic.ll
+++ b/llvm/test/CodeGen/LoongArch/intrinsic.ll
@@ -1,10 +1,12 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc --mtriple=loongarch32 < %s | FileCheck %s
-; RUN: llc --mtriple=loongarch64 < %s | FileCheck %s
+; RUN: llc --mtriple=loongarch32 --mattr=+f < %s | FileCheck %s
+; RUN: llc --mtriple=loongarch64 --mattr=+f < %s | FileCheck %s
 
 declare void @llvm.loongarch.dbar(i32)
 declare void @llvm.loongarch.ibar(i32)
 declare void @llvm.loongarch.break(i32)
+declare void @llvm.loongarch.movgr2fcsr(i32, i32)
+declare i32 @llvm.loongarch.movfcsr2gr(i32)
 declare void @llvm.loongarch.syscall(i32)
 declare i32 @llvm.loongarch.csrrd.w(i32 immarg)
 declare i32 @llvm.loongarch.csrwr.w(i32, i32 immarg)
@@ -47,6 +49,26 @@ entry:
   ret void
 }
 
+define void @movgr2fcsr(i32 %a) nounwind {
+; CHECK-LABEL: movgr2fcsr:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    movgr2fcsr $fcsr1, $a0
+; CHECK-NEXT:    ret
+entry:
+  call void @llvm.loongarch.movgr2fcsr(i32 1, i32 %a)
+  ret void
+}
+
+define i32 @movfcsr2gr() nounwind {
+; CHECK-LABEL: movfcsr2gr:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    movfcsr2gr $a0, $fcsr1
+; CHECK-NEXT:    ret
+entry:
+  %res = call i32 @llvm.loongarch.movfcsr2gr(i32 1)
+  ret i32 %res
+}
+
 define void @syscall() nounwind {
 ; CHECK-LABEL: syscall:
 ; CHECK:       # %bb.0: # %entry


        


More information about the llvm-commits mailing list