[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:
parent
fd6d660917
commit
c2ec455f18
|
@ -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")
|
||||
|
||||
|
|
|
@ -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.
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -60,7 +60,10 @@ enum NodeType : unsigned {
|
|||
BITREV_W,
|
||||
|
||||
// Intrinsic operations
|
||||
BREAK,
|
||||
DBAR,
|
||||
IBAR,
|
||||
SYSCALL,
|
||||
|
||||
// CRC check operations
|
||||
CRC_W_D_W
|
||||
|
|
|
@ -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,7 +71,13 @@ 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]>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue