[clang] 63d4686 - [LoongArch] Add intrinsics for MOVFCSR2GR and MOVGR2FCSR instructions
Xiaodong Liu via cfe-commits
cfe-commits at lists.llvm.org
Tue Jan 3 22:12:40 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 cfe-commits
mailing list