XiaodongLoong created this revision.
Herald added a subscriber: hiraditya.
Herald added a project: All.
XiaodongLoong requested review of this revision.
Herald added projects: clang, LLVM.
Herald added subscribers: llvm-commits, cfe-commits.

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.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D140685

Files:
  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

Index: llvm/test/CodeGen/LoongArch/intrinsic.ll
===================================================================
--- llvm/test/CodeGen/LoongArch/intrinsic.ll
+++ 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 @@
   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
Index: llvm/test/CodeGen/LoongArch/intrinsic-not-constant-error.ll
===================================================================
--- llvm/test/CodeGen/LoongArch/intrinsic-not-constant-error.ll
+++ 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 @@
   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:
Index: llvm/test/CodeGen/LoongArch/intrinsic-error.ll
===================================================================
--- llvm/test/CodeGen/LoongArch/intrinsic-error.ll
+++ 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" }
Index: llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
===================================================================
--- llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
+++ llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
@@ -48,6 +48,10 @@
                                                 SDTCisVT<3, GRLenVT>]>;
 def SDT_LoongArchIocsrwr : SDTypeProfile<0, 2, [SDTCisInt<0>,
                                                 SDTCisSameAs<0, 1>]>;
+def SDT_LoongArchGR2FCSR : SDTypeProfile<0, 2, [SDTCisVT<0, i32>,
+    SDTCisVT<1, GRLenVT>]>;
+def SDT_LoongArchFCSR2GR : 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 @@
                              [SDNPHasChain, SDNPSideEffect]>;
 def loongarch_break : SDNode<"LoongArchISD::BREAK", SDT_LoongArchVI,
                               [SDNPHasChain, SDNPSideEffect]>;
+def loongarch_movfcsr2gr : SDNode<"LoongArchISD::MOVFCSR2GR", SDT_LoongArchFCSR2GR>;
+def loongarch_movgr2fcsr : SDNode<"LoongArchISD::MOVGR2FCSR", SDT_LoongArchGR2FCSR,
+                                   [SDNPHasChain, SDNPSideEffect]>;
 def loongarch_syscall : SDNode<"LoongArchISD::SYSCALL", SDT_LoongArchVI,
                                 [SDNPHasChain, SDNPSideEffect]>;
 def loongarch_csrrd : SDNode<"LoongArchISD::CSRRD", SDT_LoongArchCsrrd,
@@ -1632,6 +1639,13 @@
 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
 //===----------------------------------------------------------------------===//
Index: llvm/lib/Target/LoongArch/LoongArchISelLowering.h
===================================================================
--- llvm/lib/Target/LoongArch/LoongArchISelLowering.h
+++ llvm/lib/Target/LoongArch/LoongArchISelLowering.h
@@ -43,6 +43,8 @@
   // FPR<->GPR transfer operations
   MOVGR2FR_W_LA64,
   MOVFR2GR_S_LA64,
+  MOVFCSR2GR,
+  MOVGR2FCSR,
 
   FTINT,
 
Index: llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
===================================================================
--- llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -708,6 +708,26 @@
 
     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 @@
     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 @@
   }
   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 @@
     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;
Index: llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td
===================================================================
--- llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td
+++ llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td
@@ -98,7 +98,8 @@
 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>;
Index: llvm/include/llvm/IR/IntrinsicsLoongArch.td
===================================================================
--- llvm/include/llvm/IR/IntrinsicsLoongArch.td
+++ llvm/include/llvm/IR/IntrinsicsLoongArch.td
@@ -54,6 +54,10 @@
 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],
Index: clang/test/CodeGen/LoongArch/intrinsic-la64.c
===================================================================
--- clang/test/CodeGen/LoongArch/intrinsic-la64.c
+++ 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 @@
   __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);
+}
Index: clang/test/CodeGen/LoongArch/intrinsic-la64-error.c
===================================================================
--- clang/test/CodeGen/LoongArch/intrinsic-la64-error.c
+++ clang/test/CodeGen/LoongArch/intrinsic-la64-error.c
@@ -32,3 +32,16 @@
   __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}}
+}
Index: clang/test/CodeGen/LoongArch/intrinsic-la32.c
===================================================================
--- clang/test/CodeGen/LoongArch/intrinsic-la32.c
+++ 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 @@
   __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);
+}
Index: clang/test/CodeGen/LoongArch/intrinsic-la32-error.c
===================================================================
--- clang/test/CodeGen/LoongArch/intrinsic-la32-error.c
+++ clang/test/CodeGen/LoongArch/intrinsic-la32-error.c
@@ -21,6 +21,19 @@
   __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]}}
Index: clang/lib/Sema/SemaChecking.cpp
===================================================================
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -3759,6 +3759,9 @@
                   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;
Index: clang/lib/Headers/larchintrin.h
===================================================================
--- clang/lib/Headers/larchintrin.h
+++ clang/lib/Headers/larchintrin.h
@@ -110,6 +110,11 @@
 
 #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)))
Index: clang/lib/CodeGen/CGBuiltin.cpp
===================================================================
--- clang/lib/CodeGen/CGBuiltin.cpp
+++ clang/lib/CodeGen/CGBuiltin.cpp
@@ -19659,6 +19659,12 @@
   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;
Index: clang/include/clang/Basic/BuiltinsLoongArch.def
===================================================================
--- clang/include/clang/Basic/BuiltinsLoongArch.def
+++ 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", "")
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to