From c2ec455f183d88a63d3cffe23ca6ff1acf0d7d07 Mon Sep 17 00:00:00 2001 From: gonglingqin Date: Mon, 21 Nov 2022 09:12:18 +0800 Subject: [PATCH] [LoongArch] Add intrinsics for ibar, break and syscall Diagnostics for intrinsic input parameters have also been added. Differential Revision: https://reviews.llvm.org/D138094 --- .../include/clang/Basic/BuiltinsLoongArch.def | 3 + clang/lib/CodeGen/CGBuiltin.cpp | 9 +++ clang/lib/Headers/larchintrin.h | 6 ++ clang/lib/Sema/SemaChecking.cpp | 3 + .../test/CodeGen/LoongArch/intrinsic-error.c | 24 ++++++-- clang/test/CodeGen/LoongArch/intrinsic.c | 41 +++++++++++++ llvm/include/llvm/IR/IntrinsicsLoongArch.td | 6 +- .../LoongArch/LoongArchISelLowering.cpp | 60 ++++++++++++++----- .../Target/LoongArch/LoongArchISelLowering.h | 3 + .../Target/LoongArch/LoongArchInstrInfo.td | 20 ++++--- .../test/CodeGen/LoongArch/intrinsic-error.ll | 56 ++++++++++++++--- .../LoongArch/intrinsic-not-constant-error.ll | 35 +++++++++++ llvm/test/CodeGen/LoongArch/intrinsic.ll | 33 ++++++++++ 13 files changed, 264 insertions(+), 35 deletions(-) create mode 100644 llvm/test/CodeGen/LoongArch/intrinsic-not-constant-error.ll diff --git a/clang/include/clang/Basic/BuiltinsLoongArch.def b/clang/include/clang/Basic/BuiltinsLoongArch.def index a896ccfa18fa..fe2900497a50 100644 --- a/clang/include/clang/Basic/BuiltinsLoongArch.def +++ b/clang/include/clang/Basic/BuiltinsLoongArch.def @@ -18,6 +18,9 @@ // TODO: Support more builtins. // TODO: Added feature constraints. TARGET_BUILTIN(__builtin_loongarch_dbar, "vIUi", "nc", "") +TARGET_BUILTIN(__builtin_loongarch_ibar, "vIUi", "nc", "") +TARGET_BUILTIN(__builtin_loongarch_break, "vIUi", "nc", "") +TARGET_BUILTIN(__builtin_loongarch_syscall, "vIUi", "nc", "") TARGET_BUILTIN(__builtin_loongarch_crc_w_d_w, "iLii", "nc", "64bit") diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 6000478bf545..e45f1187e231 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -19663,6 +19663,15 @@ Value *CodeGenFunction::EmitLoongArchBuiltinExpr(unsigned BuiltinID, case LoongArch::BI__builtin_loongarch_crc_w_d_w: ID = Intrinsic::loongarch_crc_w_d_w; break; + case LoongArch::BI__builtin_loongarch_break: + ID = Intrinsic::loongarch_break; + break; + case LoongArch::BI__builtin_loongarch_ibar: + ID = Intrinsic::loongarch_ibar; + break; + case LoongArch::BI__builtin_loongarch_syscall: + ID = Intrinsic::loongarch_syscall; + break; // TODO: Support more Intrinsics. } diff --git a/clang/lib/Headers/larchintrin.h b/clang/lib/Headers/larchintrin.h index 7080bda8f3dc..ad284f62d815 100644 --- a/clang/lib/Headers/larchintrin.h +++ b/clang/lib/Headers/larchintrin.h @@ -22,8 +22,14 @@ extern __inline int } #endif +#define __break(/*ui15*/ _1) __builtin_loongarch_break((_1)) + #define __dbar(/*ui15*/ _1) __builtin_loongarch_dbar((_1)) +#define __ibar(/*ui15*/ _1) __builtin_loongarch_ibar((_1)) + +#define __syscall(/*ui15*/ _1) __builtin_loongarch_syscall((_1)) + #ifdef __cplusplus } #endif diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index e3b1d5f7f9e4..75bd0ef57bcc 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -3710,7 +3710,10 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, diag::err_loongarch_builtin_requires_la64) << TheCall->getSourceRange(); break; + case LoongArch::BI__builtin_loongarch_break: case LoongArch::BI__builtin_loongarch_dbar: + case LoongArch::BI__builtin_loongarch_ibar: + case LoongArch::BI__builtin_loongarch_syscall: // Check if immediate is in [0, 32767]. return SemaBuiltinConstantArgRange(TheCall, 0, 0, 32767); } diff --git a/clang/test/CodeGen/LoongArch/intrinsic-error.c b/clang/test/CodeGen/LoongArch/intrinsic-error.c index 6f2b2ea3409e..8deed3693b25 100644 --- a/clang/test/CodeGen/LoongArch/intrinsic-error.c +++ b/clang/test/CodeGen/LoongArch/intrinsic-error.c @@ -7,10 +7,26 @@ int crc_w_d_w(long int a, int b) { return __builtin_loongarch_crc_w_d_w(a, b); // expected-error {{this builtin requires target: loongarch64}} } -void dbar_out_of_hi_range() { - return __builtin_loongarch_dbar(32768); // expected-error {{argument value 32768 is outside the valid range [0, 32767]}} +void dbar(int a) { + __builtin_loongarch_dbar(32768); // expected-error {{argument value 32768 is outside the valid range [0, 32767]}} + __builtin_loongarch_dbar(-1); // expected-error {{argument value 4294967295 is outside the valid range [0, 32767]}} + __builtin_loongarch_dbar(a); // expected-error {{argument to '__builtin_loongarch_dbar' must be a constant integer}} } -void dbar_out_of_lo_range() { - return __builtin_loongarch_dbar(-1); // expected-error {{argument value 4294967295 is outside the valid range [0, 32767]}} +void ibar(int a) { + __builtin_loongarch_ibar(32769); // expected-error {{argument value 32769 is outside the valid range [0, 32767]}} + __builtin_loongarch_ibar(-1); // expected-error {{argument value 4294967295 is outside the valid range [0, 32767]}} + __builtin_loongarch_ibar(a); // expected-error {{argument to '__builtin_loongarch_ibar' must be a constant integer}} +} + +void loongarch_break(int a) { + __builtin_loongarch_break(32769); // expected-error {{argument value 32769 is outside the valid range [0, 32767]}} + __builtin_loongarch_break(-1); // expected-error {{argument value 4294967295 is outside the valid range [0, 32767]}} + __builtin_loongarch_break(a); // expected-error {{argument to '__builtin_loongarch_break' 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]}} + __builtin_loongarch_syscall(a); // expected-error {{argument to '__builtin_loongarch_syscall' must be a constant integer}} } diff --git a/clang/test/CodeGen/LoongArch/intrinsic.c b/clang/test/CodeGen/LoongArch/intrinsic.c index 0f59131cbfb9..98ad203e9a6f 100644 --- a/clang/test/CodeGen/LoongArch/intrinsic.c +++ b/clang/test/CodeGen/LoongArch/intrinsic.c @@ -20,3 +20,44 @@ void dbar() { return __builtin_loongarch_dbar(0); } +// LA32-LABEL: @ibar( +// LA32-NEXT: entry: +// LA32-NEXT: call void @llvm.loongarch.ibar(i32 0) +// LA32-NEXT: ret void +// +// LA64-LABEL: @ibar( +// LA64-NEXT: entry: +// LA64-NEXT: call void @llvm.loongarch.ibar(i32 0) +// LA64-NEXT: ret void +// +void ibar() { + return __builtin_loongarch_ibar(0); +} + +// LA32-LABEL: @loongarch_break( +// LA32-NEXT: entry: +// LA32-NEXT: call void @llvm.loongarch.break(i32 1) +// LA32-NEXT: ret void +// +// LA64-LABEL: @loongarch_break( +// LA64-NEXT: entry: +// LA64-NEXT: call void @llvm.loongarch.break(i32 1) +// LA64-NEXT: ret void +// +void loongarch_break() { + __builtin_loongarch_break(1); +} + +// LA32-LABEL: @syscall( +// LA32-NEXT: entry: +// LA32-NEXT: call void @llvm.loongarch.syscall(i32 1) +// LA32-NEXT: ret void +// +// LA64-LABEL: @syscall( +// LA64-NEXT: entry: +// LA64-NEXT: call void @llvm.loongarch.syscall(i32 1) +// LA64-NEXT: ret void +// +void syscall() { + __builtin_loongarch_syscall(1); +} diff --git a/llvm/include/llvm/IR/IntrinsicsLoongArch.td b/llvm/include/llvm/IR/IntrinsicsLoongArch.td index 7898d4205e94..e00edad46136 100644 --- a/llvm/include/llvm/IR/IntrinsicsLoongArch.td +++ b/llvm/include/llvm/IR/IntrinsicsLoongArch.td @@ -49,7 +49,11 @@ defm int_loongarch_masked_cmpxchg : MaskedAtomicRMWFiveOpIntrinsics; //===----------------------------------------------------------------------===// // LoongArch BASE -def int_loongarch_dbar : Intrinsic<[], [llvm_i32_ty]>; +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_syscall : Intrinsic<[], [llvm_i32_ty], [ImmArg>]>; + def int_loongarch_crc_w_d_w : Intrinsic<[llvm_i32_ty], [llvm_i64_ty, llvm_i32_ty]>; } // TargetPrefix = "loongarch" diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp index eec32fd49054..5d170a0f3eaf 100644 --- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp +++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp @@ -578,35 +578,64 @@ LoongArchTargetLowering::lowerINTRINSIC_W_CHAIN(SDValue Op, } } +// Helper function that emits error message for intrinsics with void return +// value. +static SDValue emitIntrinsicErrorMessage(SDValue Op, StringRef Name, + StringRef ErrorMsg, + SelectionDAG &DAG) { + + DAG.getContext()->emitError("argument to '" + Name + "' " + ErrorMsg); + return Op.getOperand(0); +} + SDValue LoongArchTargetLowering::lowerINTRINSIC_VOID(SDValue Op, SelectionDAG &DAG) const { SDLoc DL(Op); MVT GRLenVT = Subtarget.getGRLenVT(); + SDValue Op0 = Op.getOperand(0); + SDValue Op2 = Op.getOperand(2); + const StringRef ErrorMsgOOR = "out of range"; switch (Op.getConstantOperandVal(1)) { default: // TODO: Add more Intrinsics. return SDValue(); case Intrinsic::loongarch_dbar: { - SDValue Op0 = Op.getOperand(0); - SDValue Op2 = Op.getOperand(2); - if (!isa(Op2)) { - DAG.getContext()->emitError("argument to '__builtin_loongarch_dbar' must " - "be a constant integer"); - return Op.getOperand(0); - } unsigned Imm = cast(Op2)->getZExtValue(); - if (!isUInt<15>(Imm)) { - DAG.getContext()->emitError( - "argument to '__builtin_loongarch_dbar' out of range"); - return Op0; - } + if (!isUInt<15>(Imm)) + return emitIntrinsicErrorMessage(Op, "__builtin_loongarch_dbar", + ErrorMsgOOR, DAG); - if (GRLenVT == MVT::i32) - return Op; return DAG.getNode(LoongArchISD::DBAR, DL, MVT::Other, Op0, DAG.getConstant(Imm, DL, GRLenVT)); } + case Intrinsic::loongarch_ibar: { + unsigned Imm = cast(Op2)->getZExtValue(); + if (!isUInt<15>(Imm)) + return emitIntrinsicErrorMessage(Op, "__builtin_loongarch_ibar", + ErrorMsgOOR, DAG); + + return DAG.getNode(LoongArchISD::IBAR, DL, MVT::Other, Op0, + DAG.getConstant(Imm, DL, GRLenVT)); + } + case Intrinsic::loongarch_break: { + unsigned Imm = cast(Op2)->getZExtValue(); + if (!isUInt<15>(Imm)) + return emitIntrinsicErrorMessage(Op, "__builtin_loongarch_break", + ErrorMsgOOR, DAG); + + return DAG.getNode(LoongArchISD::BREAK, DL, MVT::Other, Op0, + DAG.getConstant(Imm, DL, GRLenVT)); + } + case Intrinsic::loongarch_syscall: { + unsigned Imm = cast(Op2)->getZExtValue(); + if (!isUInt<15>(Imm)) + return emitIntrinsicErrorMessage(Op, "__builtin_loongarch_syscall", + ErrorMsgOOR, DAG); + + return DAG.getNode(LoongArchISD::SYSCALL, DL, MVT::Other, Op0, + DAG.getConstant(Imm, DL, GRLenVT)); + } } } @@ -1354,6 +1383,9 @@ const char *LoongArchTargetLowering::getTargetNodeName(unsigned Opcode) const { NODE_NAME_CASE(CLZ_W) NODE_NAME_CASE(CTZ_W) NODE_NAME_CASE(DBAR) + NODE_NAME_CASE(IBAR) + NODE_NAME_CASE(BREAK) + NODE_NAME_CASE(SYSCALL) NODE_NAME_CASE(CRC_W_D_W) } #undef NODE_NAME_CASE diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h index e181c104b1e1..6f98e40c41d3 100644 --- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h +++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h @@ -60,7 +60,10 @@ enum NodeType : unsigned { BITREV_W, // Intrinsic operations + BREAK, DBAR, + IBAR, + SYSCALL, // CRC check operations CRC_W_D_W diff --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td index 84b9f2c29e5a..79b2b482824c 100644 --- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td +++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td @@ -35,7 +35,8 @@ def SDT_LoongArchBStrPick: SDTypeProfile<1, 3, [ SDTCisInt<0>, SDTCisSameAs<0, 1>, SDTCisInt<2>, SDTCisSameAs<2, 3> ]>; -def SDT_LoongArchDBAR : SDTypeProfile<0, 1, [SDTCisVT<0, GRLenVT>]>; +// "VI" means no output and an integer input. +def SDT_LoongArchVI : SDTypeProfile<0, 1, [SDTCisVT<0, GRLenVT>]>; // TODO: Add LoongArch specific DAG Nodes // Target-independent nodes, but with target-specific formats. @@ -70,8 +71,14 @@ def loongarch_bitrev_4b : SDNode<"LoongArchISD::BITREV_4B", SDTUnaryOp>; def loongarch_bitrev_w : SDNode<"LoongArchISD::BITREV_W", SDTUnaryOp>; def loongarch_clzw : SDNode<"LoongArchISD::CLZ_W", SDTIntBitCountUnaryOp>; def loongarch_ctzw : SDNode<"LoongArchISD::CTZ_W", SDTIntBitCountUnaryOp>; -def loongarch_dbar : SDNode<"LoongArchISD::DBAR", SDT_LoongArchDBAR, +def loongarch_dbar : SDNode<"LoongArchISD::DBAR", SDT_LoongArchVI, [SDNPHasChain, SDNPSideEffect]>; +def loongarch_ibar : SDNode<"LoongArchISD::IBAR", SDT_LoongArchVI, + [SDNPHasChain, SDNPSideEffect]>; +def loongarch_break : SDNode<"LoongArchISD::BREAK", SDT_LoongArchVI, + [SDNPHasChain, SDNPSideEffect]>; +def loongarch_syscall : SDNode<"LoongArchISD::SYSCALL", SDT_LoongArchVI, + [SDNPHasChain, SDNPSideEffect]>; //===----------------------------------------------------------------------===// // Operand and SDNode transformation definitions. @@ -1341,13 +1348,12 @@ def : Pat<(atomic_load_xor_32 GPR:$addr, GPR:$incr), /// Intrinsics -let Predicates = [IsLA32] in { -def : Pat<(int_loongarch_dbar uimm15:$imm15), (DBAR uimm15:$imm15)>; -} // Predicates = [IsLA32] +def : Pat<(loongarch_dbar uimm15:$imm15), (DBAR uimm15:$imm15)>; +def : Pat<(loongarch_ibar uimm15:$imm15), (IBAR uimm15:$imm15)>; +def : Pat<(loongarch_break uimm15:$imm15), (BREAK uimm15:$imm15)>; +def : Pat<(loongarch_syscall uimm15:$imm15), (SYSCALL uimm15:$imm15)>; let Predicates = [IsLA64] in { -def : Pat<(loongarch_dbar uimm15:$imm15), (DBAR uimm15:$imm15)>; - // CRC Check Instructions def : PatGprGpr; } // Predicates = [IsLA64] diff --git a/llvm/test/CodeGen/LoongArch/intrinsic-error.ll b/llvm/test/CodeGen/LoongArch/intrinsic-error.ll index a00cd8c5e6ac..76773040a3ff 100644 --- a/llvm/test/CodeGen/LoongArch/intrinsic-error.ll +++ b/llvm/test/CodeGen/LoongArch/intrinsic-error.ll @@ -1,12 +1,10 @@ -; RUN: not llc --mtriple=loongarch32 --disable-verify < %s 2>&1 | FileCheck %s -; RUN: not llc --mtriple=loongarch64 --disable-verify < %s 2>&1 | FileCheck %s +; RUN: not llc --mtriple=loongarch32 < %s 2>&1 | FileCheck %s +; RUN: not llc --mtriple=loongarch64 < %s 2>&1 | FileCheck %s -define void @dbar_not_constant(i32 %x) nounwind { -; CHECK: argument to '__builtin_loongarch_dbar' must be a constant integer -entry: - call void @llvm.loongarch.dbar(i32 %x) - ret void -} +declare void @llvm.loongarch.dbar(i32) +declare void @llvm.loongarch.ibar(i32) +declare void @llvm.loongarch.break(i32) +declare void @llvm.loongarch.syscall(i32) define void @dbar_imm_out_of_hi_range() nounwind { ; CHECK: argument to '__builtin_loongarch_dbar' out of range @@ -22,4 +20,44 @@ entry: ret void } -declare void @llvm.loongarch.dbar(i32) +define void @ibar_imm_out_of_hi_range() nounwind { +; CHECK: argument to '__builtin_loongarch_ibar' out of range +entry: + call void @llvm.loongarch.ibar(i32 32769) + ret void +} + +define void @ibar_imm_out_of_lo_range() nounwind { +; CHECK: argument to '__builtin_loongarch_ibar' out of range +entry: + call void @llvm.loongarch.ibar(i32 -1) + ret void +} + +define void @break_imm_out_of_hi_range() nounwind { +; CHECK: argument to '__builtin_loongarch_break' out of range +entry: + call void @llvm.loongarch.break(i32 32769) + ret void +} + +define void @break_imm_out_of_lo_range() nounwind { +; CHECK: argument to '__builtin_loongarch_break' out of range +entry: + call void @llvm.loongarch.break(i32 -1) + ret void +} + +define void @syscall_imm_out_of_hi_range() nounwind { +; CHECK: argument to '__builtin_loongarch_syscall' out of range +entry: + call void @llvm.loongarch.syscall(i32 32769) + ret void +} + +define void @syscall_imm_out_of_lo_range() nounwind { +; CHECK: argument to '__builtin_loongarch_syscall' out of range +entry: + call void @llvm.loongarch.syscall(i32 -1) + ret void +} diff --git a/llvm/test/CodeGen/LoongArch/intrinsic-not-constant-error.ll b/llvm/test/CodeGen/LoongArch/intrinsic-not-constant-error.ll new file mode 100644 index 000000000000..9ba25d7d1b5a --- /dev/null +++ b/llvm/test/CodeGen/LoongArch/intrinsic-not-constant-error.ll @@ -0,0 +1,35 @@ +; RUN: not llc --mtriple=loongarch32 < %s 2>&1 | FileCheck %s +; RUN: not llc --mtriple=loongarch64 < %s 2>&1 | FileCheck %s + +declare void @llvm.loongarch.dbar(i32) +declare void @llvm.loongarch.ibar(i32) +declare void @llvm.loongarch.break(i32) +declare void @llvm.loongarch.syscall(i32) + +define void @dbar_not_constant(i32 %x) nounwind { +; CHECK: immarg operand has non-immediate parameter +entry: + call void @llvm.loongarch.dbar(i32 %x) + ret void +} + +define void @ibar(i32 %x) nounwind { +; CHECK: immarg operand has non-immediate parameter +entry: + call void @llvm.loongarch.ibar(i32 %x) + ret void +} + +define void @break(i32 %x) nounwind { +; CHECK: immarg operand has non-immediate parameter +entry: + call void @llvm.loongarch.break(i32 %x) + ret void +} + +define void @syscall(i32 %x) nounwind { +; CHECK: immarg operand has non-immediate parameter +entry: + call void @llvm.loongarch.syscall(i32 %x) + ret void +} diff --git a/llvm/test/CodeGen/LoongArch/intrinsic.ll b/llvm/test/CodeGen/LoongArch/intrinsic.ll index 088c4b68cd74..ea5c07e28f16 100644 --- a/llvm/test/CodeGen/LoongArch/intrinsic.ll +++ b/llvm/test/CodeGen/LoongArch/intrinsic.ll @@ -3,6 +3,9 @@ ; RUN: llc --mtriple=loongarch64 < %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.syscall(i32) define void @foo() nounwind { ; CHECK-LABEL: foo: @@ -13,3 +16,33 @@ entry: call void @llvm.loongarch.dbar(i32 0) ret void } + +define void @ibar() nounwind { +; CHECK-LABEL: ibar: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: ibar 0 +; CHECK-NEXT: ret +entry: + call void @llvm.loongarch.ibar(i32 0) + ret void +} + +define void @break() nounwind { +; CHECK-LABEL: break: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: break 1 +; CHECK-NEXT: ret +entry: + call void @llvm.loongarch.break(i32 1) + ret void +} + +define void @syscall() nounwind { +; CHECK-LABEL: syscall: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: syscall 1 +; CHECK-NEXT: ret +entry: + call void @llvm.loongarch.syscall(i32 1) + ret void +}