[LoongArch] Add intrinsics for ibar, break and syscall

Diagnostics for intrinsic input parameters have also been added.

Differential Revision: https://reviews.llvm.org/D138094
This commit is contained in:
gonglingqin 2022-11-21 09:12:18 +08:00
parent fd6d660917
commit c2ec455f18
13 changed files with 264 additions and 35 deletions

View File

@ -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")

View File

@ -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.
}

View File

@ -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

View File

@ -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);
}

View File

@ -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}}
}

View File

@ -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);
}

View File

@ -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<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_syscall : Intrinsic<[], [llvm_i32_ty], [ImmArg<ArgIndex<0>>]>;
def int_loongarch_crc_w_d_w : Intrinsic<[llvm_i32_ty],
[llvm_i64_ty, llvm_i32_ty]>;
} // TargetPrefix = "loongarch"

View File

@ -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<ConstantSDNode>(Op2)) {
DAG.getContext()->emitError("argument to '__builtin_loongarch_dbar' must "
"be a constant integer");
return Op.getOperand(0);
}
unsigned Imm = cast<ConstantSDNode>(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<ConstantSDNode>(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<ConstantSDNode>(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<ConstantSDNode>(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

View File

@ -60,7 +60,10 @@ enum NodeType : unsigned {
BITREV_W,
// Intrinsic operations
BREAK,
DBAR,
IBAR,
SYSCALL,
// CRC check operations
CRC_W_D_W

View File

@ -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<loongarch_crc_w_d_w, CRC_W_D_W>;
} // Predicates = [IsLA64]

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}