diff --git a/clang/include/clang/Basic/BuiltinsLoongArch.def b/clang/include/clang/Basic/BuiltinsLoongArch.def --- 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 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -19703,6 +19703,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; diff --git a/clang/lib/Headers/larchintrin.h b/clang/lib/Headers/larchintrin.h --- a/clang/lib/Headers/larchintrin.h +++ b/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))) diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp --- a/clang/lib/Sema/SemaChecking.cpp +++ b/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; diff --git a/clang/test/CodeGen/LoongArch/intrinsic-la32-error.c b/clang/test/CodeGen/LoongArch/intrinsic-la32-error.c --- a/clang/test/CodeGen/LoongArch/intrinsic-la32-error.c +++ b/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]}} diff --git a/clang/test/CodeGen/LoongArch/intrinsic-la32.c b/clang/test/CodeGen/LoongArch/intrinsic-la32.c --- 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 @@ -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); +} diff --git a/clang/test/CodeGen/LoongArch/intrinsic-la64-error.c b/clang/test/CodeGen/LoongArch/intrinsic-la64-error.c --- a/clang/test/CodeGen/LoongArch/intrinsic-la64-error.c +++ b/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}} +} diff --git a/clang/test/CodeGen/LoongArch/intrinsic-la64.c b/clang/test/CodeGen/LoongArch/intrinsic-la64.c --- 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 @@ -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); +} diff --git a/llvm/include/llvm/IR/IntrinsicsLoongArch.td b/llvm/include/llvm/IR/IntrinsicsLoongArch.td --- a/llvm/include/llvm/IR/IntrinsicsLoongArch.td +++ b/llvm/include/llvm/IR/IntrinsicsLoongArch.td @@ -54,6 +54,10 @@ def int_loongarch_break : Intrinsic<[], [llvm_i32_ty], [ImmArg>]>; def int_loongarch_dbar : Intrinsic<[], [llvm_i32_ty], [ImmArg>]>; def int_loongarch_ibar : Intrinsic<[], [llvm_i32_ty], [ImmArg>]>; +def int_loongarch_movfcsr2gr : Intrinsic<[llvm_i32_ty], [llvm_i32_ty], + [ImmArg>]>; +def int_loongarch_movgr2fcsr : Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], + [ImmArg>]>; def int_loongarch_syscall : Intrinsic<[], [llvm_i32_ty], [ImmArg>]>; 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 --- a/llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td +++ b/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>; diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h --- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h +++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h @@ -43,6 +43,8 @@ // FPR<->GPR transfer operations MOVGR2FR_W_LA64, MOVFR2GR_S_LA64, + MOVFCSR2GR, + MOVGR2FCSR, FTINT, diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp --- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp +++ b/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(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(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(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(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; diff --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td --- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td +++ b/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_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 @@ [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 @@ 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 --- 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 --- 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 @@ 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 --- 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 @@ 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