gonglingqin created this revision.
gonglingqin added reviewers: xen0n, xry111, SixWeining, wangleiat, MaskRay,
XiaodongLoong.
Herald added subscribers: StephenFan, hiraditya.
Herald added a project: All.
gonglingqin requested review of this revision.
Herald added projects: clang, LLVM.
Herald added subscribers: llvm-commits, cfe-commits.
These intrinsics are required by Linux [1].
[1]:
https://github.com/loongson/linux/blob/master/arch/loongarch/include/asm/loongarch.h
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D139288
Files:
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-error-la64.c
clang/test/CodeGen/LoongArch/intrinsic-error.c
clang/test/CodeGen/LoongArch/intrinsic-la64.c
clang/test/CodeGen/LoongArch/intrinsic.c
llvm/include/llvm/IR/IntrinsicsLoongArch.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-la32-error.ll
llvm/test/CodeGen/LoongArch/intrinsic-la64-error.ll
llvm/test/CodeGen/LoongArch/intrinsic-la64.ll
llvm/test/CodeGen/LoongArch/intrinsic.ll
Index: llvm/test/CodeGen/LoongArch/intrinsic.ll
===================================================================
--- llvm/test/CodeGen/LoongArch/intrinsic.ll
+++ llvm/test/CodeGen/LoongArch/intrinsic.ll
@@ -6,6 +6,9 @@
declare void @llvm.loongarch.ibar(i32)
declare void @llvm.loongarch.break(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 @foo() nounwind {
; CHECK-LABEL: foo:
@@ -46,3 +49,33 @@
call void @llvm.loongarch.syscall(i32 1)
ret void
}
+
+define i32 @csrrd_w() {
+; CHECK-LABEL: csrrd_w:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: csrrd $a0, 1
+; CHECK-NEXT: ret
+entry:
+ %0 = tail call i32 @llvm.loongarch.csrrd.w(i32 1)
+ ret i32 %0
+}
+
+define i32 @csrwr_w(i32 signext %a) {
+; CHECK-LABEL: csrwr_w:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: csrwr $a0, 1
+; CHECK-NEXT: ret
+entry:
+ %0 = tail call i32 @llvm.loongarch.csrwr.w(i32 %a, i32 1)
+ ret i32 %0
+}
+
+define i32 @csrxchg_w(i32 signext %a, i32 signext %b) {
+; CHECK-LABEL: csrxchg_w:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: csrxchg $a0, $a1, 1
+; CHECK-NEXT: ret
+entry:
+ %0 = tail call i32 @llvm.loongarch.csrxchg.w(i32 %a, i32 %b, i32 1)
+ ret i32 %0
+}
Index: llvm/test/CodeGen/LoongArch/intrinsic-la64.ll
===================================================================
--- llvm/test/CodeGen/LoongArch/intrinsic-la64.ll
+++ llvm/test/CodeGen/LoongArch/intrinsic-la64.ll
@@ -9,6 +9,9 @@
declare i32 @llvm.loongarch.crcc.w.h.w(i32, i32)
declare i32 @llvm.loongarch.crcc.w.w.w(i32, i32)
declare i32 @llvm.loongarch.crcc.w.d.w(i64, i32)
+declare i64 @llvm.loongarch.csrrd.d(i32 immarg)
+declare i64 @llvm.loongarch.csrwr.d(i64, i32 immarg)
+declare i64 @llvm.loongarch.csrxchg.d(i64, i64, i32 immarg)
define i32 @crc_w_b_w(i32 %a, i32 %b) nounwind {
; CHECK-LABEL: crc_w_b_w:
@@ -81,3 +84,33 @@
%res = call i32 @llvm.loongarch.crcc.w.d.w(i64 %a, i32 %b)
ret i32 %res
}
+
+define i64 @csrrd_d() {
+; CHECK-LABEL: csrrd_d:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: csrrd $a0, 1
+; CHECK-NEXT: ret
+entry:
+ %0 = tail call i64 @llvm.loongarch.csrrd.d(i32 1)
+ ret i64 %0
+}
+
+define i64 @csrwr_d(i64 %a) {
+; CHECK-LABEL: csrwr_d:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: csrwr $a0, 1
+; CHECK-NEXT: ret
+entry:
+ %0 = tail call i64 @llvm.loongarch.csrwr.d(i64 %a, i32 1)
+ ret i64 %0
+}
+
+define i64 @csrxchg_d(i64 %a, i64 %b) {
+; CHECK-LABEL: csrxchg_d:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: csrxchg $a0, $a1, 1
+; CHECK-NEXT: ret
+entry:
+ %0 = tail call i64 @llvm.loongarch.csrxchg.d(i64 %a, i64 %b, i32 1)
+ ret i64 %0
+}
Index: llvm/test/CodeGen/LoongArch/intrinsic-la64-error.ll
===================================================================
--- /dev/null
+++ llvm/test/CodeGen/LoongArch/intrinsic-la64-error.ll
@@ -0,0 +1,48 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: not llc --mtriple=loongarch64 < %s 2>&1 | FileCheck %s
+
+declare i64 @llvm.loongarch.csrrd.d(i32 immarg)
+declare i64 @llvm.loongarch.csrwr.d(i64, i32 immarg)
+declare i64 @llvm.loongarch.csrxchg.d(i64, i64, i32 immarg)
+
+define i64 @csrrd_d_imm_out_of_hi_range() nounwind {
+; CHECK: argument to 'llvm.loongarch.csrrd.d' out of range
+entry:
+ %0 = call i64 @llvm.loongarch.csrrd.d(i32 16384)
+ ret i64 %0
+}
+
+define i64 @csrrd_d_imm_out_of_lo_range() nounwind {
+; CHECK: argument to 'llvm.loongarch.csrrd.d' out of range
+entry:
+ %0 = call i64 @llvm.loongarch.csrrd.d(i32 -1)
+ ret i64 %0
+}
+
+define i64 @csrwr_d_imm_out_of_hi_range(i64 %a) nounwind {
+; CHECK: argument to 'llvm.loongarch.csrwr.d' out of range
+entry:
+ %0 = call i64 @llvm.loongarch.csrwr.d(i64 %a, i32 16384)
+ ret i64 %0
+}
+
+define i64 @csrwr_d_imm_out_of_lo_range(i64 %a) nounwind {
+; CHECK: argument to 'llvm.loongarch.csrwr.d' out of range
+entry:
+ %0 = call i64 @llvm.loongarch.csrwr.d(i64 %a, i32 -1)
+ ret i64 %0
+}
+
+define i64 @csrxchg_d_imm_out_of_hi_range(i64 %a, i64 %b) nounwind {
+; CHECK: argument to 'llvm.loongarch.csrxchg.d' out of range
+entry:
+ %0 = call i64 @llvm.loongarch.csrxchg.d(i64 %a, i64 %b, i32 16384)
+ ret i64 %0
+}
+
+define i64 @csrxchg_d_imm_out_of_lo_range(i64 %a, i64 %b) nounwind {
+; CHECK: argument to 'llvm.loongarch.csrxchg.d' out of range
+entry:
+ %0 = call i64 @llvm.loongarch.csrxchg.d(i64 %a, i64 %b, i32 -1)
+ ret i64 %0
+}
Index: llvm/test/CodeGen/LoongArch/intrinsic-la32-error.ll
===================================================================
--- llvm/test/CodeGen/LoongArch/intrinsic-la32-error.ll
+++ llvm/test/CodeGen/LoongArch/intrinsic-la32-error.ll
@@ -8,6 +8,9 @@
declare i32 @llvm.loongarch.crcc.w.h.w(i32, i32)
declare i32 @llvm.loongarch.crcc.w.w.w(i32, i32)
declare i32 @llvm.loongarch.crcc.w.d.w(i64, i32)
+declare i64 @llvm.loongarch.csrrd.d(i32 immarg)
+declare i64 @llvm.loongarch.csrwr.d(i64, i32 immarg)
+declare i64 @llvm.loongarch.csrxchg.d(i64, i64, i32 immarg)
define i32 @crc_w_b_w(i32 %a, i32 %b) nounwind {
; CHECK: llvm.loongarch.crc.w.b.w requires target: loongarch64
@@ -64,3 +67,24 @@
%res = call i32 @llvm.loongarch.crcc.w.d.w(i64 %a, i32 %b)
ret i32 %res
}
+
+define i64 @csrrd_d() {
+; CHECK: llvm.loongarch.csrrd.d requires target: loongarch64
+entry:
+ %0 = tail call i64 @llvm.loongarch.csrrd.d(i32 1)
+ ret i64 %0
+}
+
+define i64 @csrwr_d(i64 %a) {
+; CHECK: llvm.loongarch.csrwr.d requires target: loongarch64
+entry:
+ %0 = tail call i64 @llvm.loongarch.csrwr.d(i64 %a, i32 1)
+ ret i64 %0
+}
+
+define i64 @csrxchg_d(i64 %a, i64 %b) {
+; CHECK: llvm.loongarch.csrxchg.d requires target: loongarch64
+entry:
+ %0 = tail call i64 @llvm.loongarch.csrxchg.d(i64 %a, i64 %b, i32 1)
+ ret i64 %0
+}
Index: llvm/test/CodeGen/LoongArch/intrinsic-error.ll
===================================================================
--- llvm/test/CodeGen/LoongArch/intrinsic-error.ll
+++ llvm/test/CodeGen/LoongArch/intrinsic-error.ll
@@ -6,6 +6,9 @@
declare void @llvm.loongarch.ibar(i32)
declare void @llvm.loongarch.break(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 {
; CHECK: argument to 'llvm.loongarch.dbar' out of range
@@ -62,3 +65,45 @@
call void @llvm.loongarch.syscall(i32 -1)
ret void
}
+
+define i32 @csrrd_w_imm_out_of_hi_range() nounwind {
+; 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 {
+; 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 {
+; 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 {
+; 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 {
+; 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 {
+; 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
+}
Index: llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
===================================================================
--- llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
+++ llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
@@ -38,6 +38,15 @@
// "VI" means no output and an integer input.
def SDT_LoongArchVI : SDTypeProfile<0, 1, [SDTCisVT<0, GRLenVT>]>;
+def SDT_LoongArchCsrrd : SDTypeProfile<1, 1, [SDTCisInt<0>,
+ SDTCisVT<1, GRLenVT>]>;
+def SDT_LoongArchCsrwr : SDTypeProfile<1, 2, [SDTCisInt<0>, SDTCisSameAs<0, 1>,
+ SDTCisVT<2, GRLenVT>]>;
+def SDT_LoongArchCsrxchg : SDTypeProfile<1, 3, [SDTCisInt<0>,
+ SDTCisSameAs<0, 1>,
+ SDTCisSameAs<0, 2>,
+ SDTCisVT<3, GRLenVT>]>;
+
// TODO: Add LoongArch specific DAG Nodes
// Target-independent nodes, but with target-specific formats.
def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_CallSeqStart,
@@ -93,6 +102,13 @@
[SDNPHasChain, SDNPSideEffect]>;
def loongarch_syscall : SDNode<"LoongArchISD::SYSCALL", SDT_LoongArchVI,
[SDNPHasChain, SDNPSideEffect]>;
+def loongarch_csrrd : SDNode<"LoongArchISD::CSRRD", SDT_LoongArchCsrrd,
+ [SDNPHasChain, SDNPSideEffect]>;
+def loongarch_csrwr : SDNode<"LoongArchISD::CSRWR", SDT_LoongArchCsrwr,
+ [SDNPHasChain, SDNPSideEffect]>;
+def loongarch_csrxchg : SDNode<"LoongArchISD::CSRXCHG",
+ SDT_LoongArchCsrxchg,
+ [SDNPHasChain, SDNPSideEffect]>;
//===----------------------------------------------------------------------===//
// Operand and SDNode transformation definitions.
@@ -159,7 +175,8 @@
let ParserMatchClass = UImmAsmOperand<12, "ori">;
}
-def uimm14 : Operand<GRLenVT> {
+def uimm14 : Operand<GRLenVT>,
+ ImmLeaf <GRLenVT, [{return isUInt<14>(Imm);}]> {
let ParserMatchClass = UImmAsmOperand<14>;
}
@@ -1621,3 +1638,13 @@
def ERTN : FmtI32<0b00000110010010000011100000000000, "ertn">;
def DBCL : MISC_I15<0b00000000001010101, "dbcl">;
def IDLE : MISC_I15<0b00000110010010001, "idle">;
+
+//===----------------------------------------------------------------------===//
+// Privilege Intrinsics
+//===----------------------------------------------------------------------===//
+
+def : Pat<(loongarch_csrrd uimm14:$imm14), (CSRRD uimm14:$imm14)>;
+def : Pat<(loongarch_csrwr GPR:$rd, uimm14:$imm14),
+ (CSRWR GPR:$rd, uimm14:$imm14)>;
+def : Pat<(loongarch_csrxchg GPR:$rd, GPR:$rj, uimm14:$imm14),
+ (CSRXCHG GPR:$rd, GPR:$rj, uimm14:$imm14)>;
Index: llvm/lib/Target/LoongArch/LoongArchISelLowering.h
===================================================================
--- llvm/lib/Target/LoongArch/LoongArchISelLowering.h
+++ llvm/lib/Target/LoongArch/LoongArchISelLowering.h
@@ -73,7 +73,11 @@
CRCC_W_B_W,
CRCC_W_H_W,
CRCC_W_W_W,
- CRCC_W_D_W
+ CRCC_W_D_W,
+
+ CSRRD,
+ CSRWR,
+ CSRXCHG,
};
} // end namespace LoongArchISD
Index: llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
===================================================================
--- llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -63,6 +63,7 @@
setOperationAction(ISD::DEBUGTRAP, MVT::Other, Legal);
setOperationAction(ISD::TRAP, MVT::Other, Legal);
setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom);
+ setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom);
setOperationAction({ISD::GlobalAddress, ISD::BlockAddress, ISD::ConstantPool,
ISD::JumpTable},
@@ -591,9 +592,25 @@
}
}
+// Helper function that emits error message for intrinsics with chain.
+static SDValue emitIntrinsicWithChainErrorMessage(SDValue Op,
+ StringRef ErrorMsg,
+ SelectionDAG &DAG) {
+
+ DAG.getContext()->emitError("argument to '" + Op->getOperationName(0) + "' " +
+ ErrorMsg);
+ return DAG.getMergeValues({DAG.getUNDEF(Op.getValueType()), Op.getOperand(0)},
+ SDLoc(Op));
+}
+
SDValue
LoongArchTargetLowering::lowerINTRINSIC_W_CHAIN(SDValue Op,
SelectionDAG &DAG) const {
+ SDLoc DL(Op);
+ MVT GRLenVT = Subtarget.getGRLenVT();
+ SDValue Op0 = Op.getOperand(0);
+ std::string Name = Op->getOperationName(0);
+ const StringRef ErrorMsgOOR = "out of range";
switch (Op.getConstantOperandVal(1)) {
default:
@@ -608,8 +625,40 @@
case Intrinsic::loongarch_crcc_w_d_w: {
std::string Name = Op->getOperationName(0);
DAG.getContext()->emitError(Name + " requires target: loongarch64");
+ return DAG.getMergeValues({DAG.getUNDEF(Op.getValueType()), Op0}, DL);
+ }
+ case Intrinsic::loongarch_csrrd_w:
+ case Intrinsic::loongarch_csrrd_d: {
+ unsigned Imm = cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue();
+ if (!isUInt<14>(Imm))
+ return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG);
+ return DAG.getMergeValues(
+ {DAG.getNode(LoongArchISD::CSRRD, DL, GRLenVT, Op0,
+ DAG.getConstant(Imm, DL, GRLenVT)),
+ Op0},
+ DL);
+ }
+ case Intrinsic::loongarch_csrwr_w:
+ case Intrinsic::loongarch_csrwr_d: {
+ unsigned Imm = cast<ConstantSDNode>(Op.getOperand(3))->getZExtValue();
+ if (!isUInt<14>(Imm))
+ return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG);
return DAG.getMergeValues(
- {DAG.getUNDEF(Op.getValueType()), Op.getOperand(0)}, SDLoc(Op));
+ {DAG.getNode(LoongArchISD::CSRWR, DL, GRLenVT, Op0, Op.getOperand(2),
+ DAG.getConstant(Imm, DL, GRLenVT)),
+ Op0},
+ DL);
+ }
+ case Intrinsic::loongarch_csrxchg_w:
+ case Intrinsic::loongarch_csrxchg_d: {
+ unsigned Imm = cast<ConstantSDNode>(Op.getOperand(4))->getZExtValue();
+ if (!isUInt<14>(Imm))
+ return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG);
+ return DAG.getMergeValues(
+ {DAG.getNode(LoongArchISD::CSRXCHG, DL, GRLenVT, Op0, Op.getOperand(2),
+ Op.getOperand(3), DAG.getConstant(Imm, DL, GRLenVT)),
+ Op0},
+ DL);
}
}
}
@@ -939,10 +988,10 @@
break;
}
case ISD::INTRINSIC_W_CHAIN: {
- assert(VT == MVT::i32 && Subtarget.is64Bit() &&
- "Unexpected custom legalisation");
+ SDValue Op0 = N->getOperand(0);
SDValue Op2 = N->getOperand(2);
- SDValue Op3 = N->getOperand(3);
+ MVT GRLenVT = Subtarget.getGRLenVT();
+ std::string Name = N->getOperationName(0);
switch (N->getConstantOperandVal(1)) {
default:
@@ -951,9 +1000,10 @@
case Intrinsic::loongarch_##NAME: { \
Results.push_back(DAG.getNode( \
ISD::TRUNCATE, DL, VT, \
- DAG.getNode(LoongArchISD::NODE, DL, MVT::i64, \
- DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2), \
- DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op3)))); \
+ DAG.getNode( \
+ LoongArchISD::NODE, DL, MVT::i64, \
+ DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2), \
+ DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3))))); \
Results.push_back(N->getOperand(0)); \
break; \
}
@@ -966,15 +1016,80 @@
#define CRC_CASE_EXT_UNARYOP(NAME, NODE) \
case Intrinsic::loongarch_##NAME: { \
- Results.push_back(DAG.getNode( \
- ISD::TRUNCATE, DL, VT, \
- DAG.getNode(LoongArchISD::NODE, DL, MVT::i64, Op2, \
- DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op3)))); \
+ Results.push_back( \
+ DAG.getNode(ISD::TRUNCATE, DL, VT, \
+ DAG.getNode(LoongArchISD::NODE, DL, MVT::i64, Op2, \
+ DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, \
+ N->getOperand(3))))); \
Results.push_back(N->getOperand(0)); \
break; \
}
CRC_CASE_EXT_UNARYOP(crc_w_d_w, CRC_W_D_W)
CRC_CASE_EXT_UNARYOP(crcc_w_d_w, CRCC_W_D_W)
+#define CSR_CASE(ID) \
+ case Intrinsic::loongarch_##ID: { \
+ if (!Subtarget.is64Bit()) { \
+ DAG.getContext()->emitError(Name + " requires target: loongarch64"); \
+ Results.push_back(DAG.getUNDEF(VT)); \
+ Results.push_back(N->getOperand(0)); \
+ } \
+ break; \
+ }
+ CSR_CASE(csrrd_d);
+ CSR_CASE(csrwr_d);
+ CSR_CASE(csrxchg_d);
+ case Intrinsic::loongarch_csrrd_w: {
+ unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
+ if (!isUInt<14>(Imm)) {
+ DAG.getContext()->emitError("argument to '" + Name + "' out of range");
+ Results.push_back(DAG.getUNDEF(VT));
+ Results.push_back(N->getOperand(0));
+ break;
+ }
+
+ Results.push_back(
+ DAG.getNode(ISD::TRUNCATE, DL, VT,
+ DAG.getNode(LoongArchISD::CSRRD, DL, GRLenVT, Op0,
+ DAG.getConstant(Imm, DL, GRLenVT))));
+ Results.push_back(N->getOperand(0));
+ break;
+ }
+ case Intrinsic::loongarch_csrwr_w: {
+ unsigned Imm = cast<ConstantSDNode>(N->getOperand(3))->getZExtValue();
+ if (!isUInt<14>(Imm)) {
+ DAG.getContext()->emitError("argument to '" + Name + "' out of range");
+ Results.push_back(DAG.getUNDEF(VT));
+ Results.push_back(N->getOperand(0));
+ break;
+ }
+
+ Results.push_back(DAG.getNode(
+ ISD::TRUNCATE, DL, VT,
+ DAG.getNode(LoongArchISD::CSRWR, DL, GRLenVT, Op0,
+ DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),
+ DAG.getConstant(Imm, DL, GRLenVT))));
+ Results.push_back(N->getOperand(0));
+ break;
+ }
+ case Intrinsic::loongarch_csrxchg_w: {
+ unsigned Imm = cast<ConstantSDNode>(N->getOperand(4))->getZExtValue();
+ if (!isUInt<14>(Imm)) {
+ DAG.getContext()->emitError("argument to '" + Name + "' out of range");
+ Results.push_back(DAG.getUNDEF(VT));
+ Results.push_back(N->getOperand(0));
+ break;
+ }
+
+ Results.push_back(DAG.getNode(
+ ISD::TRUNCATE, DL, VT,
+ DAG.getNode(
+ LoongArchISD::CSRXCHG, DL, GRLenVT, Op0,
+ DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),
+ DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3)),
+ DAG.getConstant(Imm, DL, GRLenVT))));
+ Results.push_back(N->getOperand(0));
+ break;
+ }
}
break;
}
@@ -1456,6 +1571,9 @@
NODE_NAME_CASE(CRCC_W_H_W)
NODE_NAME_CASE(CRCC_W_W_W)
NODE_NAME_CASE(CRCC_W_D_W)
+ NODE_NAME_CASE(CSRRD)
+ NODE_NAME_CASE(CSRWR)
+ NODE_NAME_CASE(CSRXCHG)
}
#undef NODE_NAME_CASE
return nullptr;
Index: llvm/include/llvm/IR/IntrinsicsLoongArch.td
===================================================================
--- llvm/include/llvm/IR/IntrinsicsLoongArch.td
+++ llvm/include/llvm/IR/IntrinsicsLoongArch.td
@@ -73,4 +73,23 @@
[llvm_i32_ty, llvm_i32_ty]>;
def int_loongarch_crcc_w_d_w : Intrinsic<[llvm_i32_ty],
[llvm_i64_ty, llvm_i32_ty]>;
+
+def int_loongarch_csrrd_w : Intrinsic<[llvm_i32_ty], [llvm_i32_ty],
+ [ImmArg<ArgIndex<0>>]>;
+def int_loongarch_csrrd_d : Intrinsic<[llvm_i64_ty], [llvm_i32_ty],
+ [ImmArg<ArgIndex<0>>]>;
+def int_loongarch_csrwr_w : Intrinsic<[llvm_i32_ty],
+ [llvm_i32_ty, llvm_i32_ty],
+ [ImmArg<ArgIndex<1>>]>;
+def int_loongarch_csrwr_d : Intrinsic<[llvm_i64_ty],
+ [llvm_i64_ty, llvm_i32_ty],
+ [ImmArg<ArgIndex<1>>]>;
+def int_loongarch_csrxchg_w : Intrinsic<[llvm_i32_ty],
+ [llvm_i32_ty, llvm_i32_ty,
+ llvm_i32_ty],
+ [ImmArg<ArgIndex<2>>]>;
+def int_loongarch_csrxchg_d : Intrinsic<[llvm_i64_ty],
+ [llvm_i64_ty, llvm_i64_ty,
+ llvm_i32_ty],
+ [ImmArg<ArgIndex<2>>]>;
} // TargetPrefix = "loongarch"
Index: clang/test/CodeGen/LoongArch/intrinsic.c
===================================================================
--- clang/test/CodeGen/LoongArch/intrinsic.c
+++ clang/test/CodeGen/LoongArch/intrinsic.c
@@ -61,3 +61,63 @@
void syscall() {
__builtin_loongarch_syscall(1);
}
+
+// LA32-LABEL: @csrrd_w(
+// LA32-NEXT: entry:
+// LA32-NEXT: [[TMP0:%.*]] = call i32 @llvm.loongarch.csrrd.w(i32 1)
+// LA32-NEXT: ret i32 [[TMP0]]
+//
+// LA64-LABEL: @csrrd_w(
+// LA64-NEXT: entry:
+// LA64-NEXT: [[TMP0:%.*]] = call i32 @llvm.loongarch.csrrd.w(i32 1)
+// LA64-NEXT: ret i32 [[TMP0]]
+//
+unsigned int csrrd_w() {
+ return __builtin_loongarch_csrrd_w(1);
+}
+
+// LA32-LABEL: @csrwr_w(
+// LA32-NEXT: entry:
+// LA32-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
+// LA32-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// LA32-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// LA32-NEXT: [[TMP1:%.*]] = call i32 @llvm.loongarch.csrwr.w(i32 [[TMP0]], i32 1)
+// LA32-NEXT: ret i32 [[TMP1]]
+//
+// LA64-LABEL: @csrwr_w(
+// LA64-NEXT: entry:
+// LA64-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
+// LA64-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// LA64-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// LA64-NEXT: [[TMP1:%.*]] = call i32 @llvm.loongarch.csrwr.w(i32 [[TMP0]], i32 1)
+// LA64-NEXT: ret i32 [[TMP1]]
+//
+unsigned int csrwr_w(unsigned int a) {
+ return __builtin_loongarch_csrwr_w(a, 1);
+}
+
+// LA32-LABEL: @csrxchg_w(
+// LA32-NEXT: entry:
+// LA32-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
+// LA32-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4
+// LA32-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// LA32-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// LA32-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// LA32-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// LA32-NEXT: [[TMP2:%.*]] = call i32 @llvm.loongarch.csrxchg.w(i32 [[TMP0]], i32 [[TMP1]], i32 1)
+// LA32-NEXT: ret i32 [[TMP2]]
+//
+// LA64-LABEL: @csrxchg_w(
+// LA64-NEXT: entry:
+// LA64-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
+// LA64-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4
+// LA64-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// LA64-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// LA64-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// LA64-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// LA64-NEXT: [[TMP2:%.*]] = call i32 @llvm.loongarch.csrxchg.w(i32 [[TMP0]], i32 [[TMP1]], i32 1)
+// LA64-NEXT: ret i32 [[TMP2]]
+//
+unsigned int csrxchg_w(unsigned int a, unsigned int b) {
+ return __builtin_loongarch_csrxchg_w(a, b, 1);
+}
Index: clang/test/CodeGen/LoongArch/intrinsic-la64.c
===================================================================
--- clang/test/CodeGen/LoongArch/intrinsic-la64.c
+++ clang/test/CodeGen/LoongArch/intrinsic-la64.c
@@ -74,3 +74,30 @@
int crcc_w_d_w(long int a, int b) {
return __builtin_loongarch_crcc_w_d_w(a, b);
}
+
+// CHECK-LABEL: @csrrd_d(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.loongarch.csrrd.d(i32 1)
+// CHECK-NEXT: ret i64 [[TMP0]]
+//
+unsigned long int csrrd_d() {
+ return __builtin_loongarch_csrrd_d(1);
+}
+
+// CHECK-LABEL: @csrwr_d(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.loongarch.csrwr.d(i64 [[A:%.*]], i32 1)
+// CHECK-NEXT: ret i64 [[TMP0]]
+//
+unsigned long int csrwr_d(unsigned long int a) {
+ return __builtin_loongarch_csrwr_d(a, 1);
+}
+
+// CHECK-LABEL: @csrxchg_d(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.loongarch.csrxchg.d(i64 [[A:%.*]], i64 [[B:%.*]], i32 1)
+// CHECK-NEXT: ret i64 [[TMP0]]
+//
+unsigned long int csrxchg_d(unsigned long int a, unsigned long int b) {
+ return __builtin_loongarch_csrxchg_d(a, b, 1);
+}
Index: clang/test/CodeGen/LoongArch/intrinsic-error.c
===================================================================
--- clang/test/CodeGen/LoongArch/intrinsic-error.c
+++ clang/test/CodeGen/LoongArch/intrinsic-error.c
@@ -57,3 +57,33 @@
int crcc_w_d_w(long int a, int b) {
return __builtin_loongarch_crcc_w_d_w(a, b); // expected-error {{this builtin requires target: loongarch64}}
}
+
+unsigned long int csrrd_d() {
+ return __builtin_loongarch_csrrd_d(1); // expected-error {{this builtin requires target: loongarch64}}
+}
+
+unsigned long int csrwr_d(unsigned long int a) {
+ return __builtin_loongarch_csrwr_d(a, 1); // expected-error {{this builtin requires target: loongarch64}}
+}
+
+unsigned long int csrxchg_d(unsigned long int a, unsigned long int b) {
+ return __builtin_loongarch_csrxchg_d(a, b, 1); // expected-error {{this builtin requires target: loongarch64}}
+}
+
+void csrrd_w(int a) {
+ __builtin_loongarch_csrrd_w(16384); // expected-error {{argument value 16384 is outside the valid range [0, 16383]}}
+ __builtin_loongarch_csrrd_w(-1); // expected-error {{argument value 4294967295 is outside the valid range [0, 16383]}}
+ __builtin_loongarch_csrrd_w(a); // expected-error {{argument to '__builtin_loongarch_csrrd_w' must be a constant integer}}
+}
+
+void csrwr_w(unsigned int a) {
+ __builtin_loongarch_csrwr_w(a, 16384); // expected-error {{argument value 16384 is outside the valid range [0, 16383]}}
+ __builtin_loongarch_csrwr_w(a, -1); // expected-error {{argument value 4294967295 is outside the valid range [0, 16383]}}
+ __builtin_loongarch_csrwr_w(a, a); // expected-error {{argument to '__builtin_loongarch_csrwr_w' must be a constant integer}}
+}
+
+void csrxchg_w(unsigned int a, unsigned int b) {
+ __builtin_loongarch_csrxchg_w(a, b, 16384); // expected-error {{argument value 16384 is outside the valid range [0, 16383]}}
+ __builtin_loongarch_csrxchg_w(a, b, -1); // expected-error {{argument value 4294967295 is outside the valid range [0, 16383]}}
+ __builtin_loongarch_csrxchg_w(a, b, b); // expected-error {{argument to '__builtin_loongarch_csrxchg_w' must be a constant integer}}
+}
Index: clang/test/CodeGen/LoongArch/intrinsic-error-la64.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/LoongArch/intrinsic-error-la64.c
@@ -0,0 +1,22 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
+// RUN: %clang_cc1 -triple loongarch64 -emit-llvm -S -verify %s -o /dev/null
+
+#include <larchintrin.h>
+
+void csrrd_d(int a) {
+ __builtin_loongarch_csrrd_d(16384); // expected-error {{argument value 16384 is outside the valid range [0, 16383]}}
+ __builtin_loongarch_csrrd_d(-1); // expected-error {{argument value 4294967295 is outside the valid range [0, 16383]}}
+ __builtin_loongarch_csrrd_d(a); // expected-error {{argument to '__builtin_loongarch_csrrd_d' must be a constant integer}}
+}
+
+void csrwr_d(unsigned long int a) {
+ __builtin_loongarch_csrwr_d(a, 16384); // expected-error {{argument value 16384 is outside the valid range [0, 16383]}}
+ __builtin_loongarch_csrwr_d(a, -1); // expected-error {{argument value 4294967295 is outside the valid range [0, 16383]}}
+ __builtin_loongarch_csrwr_d(a, a); // expected-error {{argument to '__builtin_loongarch_csrwr_d' must be a constant integer}}
+}
+
+void csrxchg_d(unsigned long int a, unsigned long int b) {
+ __builtin_loongarch_csrxchg_d(a, b, 16384); // expected-error {{argument value 16384 is outside the valid range [0, 16383]}}
+ __builtin_loongarch_csrxchg_d(a, b, -1); // expected-error {{argument value 4294967295 is outside the valid range [0, 16383]}}
+ __builtin_loongarch_csrxchg_d(a, b, b); // expected-error {{argument to '__builtin_loongarch_csrxchg_d' must be a constant integer}}
+}
Index: clang/lib/Sema/SemaChecking.cpp
===================================================================
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -3723,6 +3723,30 @@
case LoongArch::BI__builtin_loongarch_syscall:
// Check if immediate is in [0, 32767].
return SemaBuiltinConstantArgRange(TheCall, 0, 0, 32767);
+ case LoongArch::BI__builtin_loongarch_csrrd_w:
+ return SemaBuiltinConstantArgRange(TheCall, 0, 0, 16383);
+ case LoongArch::BI__builtin_loongarch_csrwr_w:
+ return SemaBuiltinConstantArgRange(TheCall, 1, 0, 16383);
+ case LoongArch::BI__builtin_loongarch_csrxchg_w:
+ return SemaBuiltinConstantArgRange(TheCall, 2, 0, 16383);
+ case LoongArch::BI__builtin_loongarch_csrrd_d:
+ if (!TI.hasFeature("64bit"))
+ return Diag(TheCall->getBeginLoc(),
+ diag::err_loongarch_builtin_requires_la64)
+ << TheCall->getSourceRange();
+ return SemaBuiltinConstantArgRange(TheCall, 0, 0, 16383);
+ case LoongArch::BI__builtin_loongarch_csrwr_d:
+ if (!TI.hasFeature("64bit"))
+ return Diag(TheCall->getBeginLoc(),
+ diag::err_loongarch_builtin_requires_la64)
+ << TheCall->getSourceRange();
+ return SemaBuiltinConstantArgRange(TheCall, 1, 0, 16383);
+ case LoongArch::BI__builtin_loongarch_csrxchg_d:
+ if (!TI.hasFeature("64bit"))
+ return Diag(TheCall->getBeginLoc(),
+ diag::err_loongarch_builtin_requires_la64)
+ << TheCall->getSourceRange();
+ return SemaBuiltinConstantArgRange(TheCall, 2, 0, 16383);
}
return false;
Index: clang/lib/Headers/larchintrin.h
===================================================================
--- clang/lib/Headers/larchintrin.h
+++ clang/lib/Headers/larchintrin.h
@@ -72,6 +72,29 @@
#define __syscall(/*ui15*/ _1) __builtin_loongarch_syscall((_1))
+#define __csrrd_w(/*ui14*/ _1) ((unsigned int)__builtin_loongarch_csrrd_w((_1)))
+
+#define __csrwr_w(/*unsigned int*/ _1, /*ui14*/ _2) \
+ ((unsigned int)__builtin_loongarch_csrwr_w((unsigned int)(_1), (_2)))
+
+#define __csrxchg_w(/*unsigned int*/ _1, /*unsigned int*/ _2, /*ui14*/ _3) \
+ ((unsigned int)__builtin_loongarch_csrxchg_w((unsigned int)(_1), \
+ (unsigned int)(_2), (_3)))
+
+#ifdef __loongarch_grlen == 64
+#define __csrrd_d(/*ui14*/ _1) \
+ ((unsigned long int)__builtin_loongarch_csrrd_d((_1)))
+
+#define __csrwr_d(/*unsigned long int*/ _1, /*ui14*/ _2) \
+ ((unsigned long int)__builtin_loongarch_csrwr_d((unsigned long int)(_1), \
+ (_2)))
+
+#define __csrxchg_d(/*unsigned long int*/ _1, /*unsigned long int*/ _2, \
+ /*ui14*/ _3) \
+ ((unsigned long int)__builtin_loongarch_csrxchg_d( \
+ (unsigned long int)(_1), (unsigned long int)(_2), (_3)))
+#endif
+
#ifdef __cplusplus
}
#endif
Index: clang/lib/CodeGen/CGBuiltin.cpp
===================================================================
--- clang/lib/CodeGen/CGBuiltin.cpp
+++ clang/lib/CodeGen/CGBuiltin.cpp
@@ -19694,6 +19694,24 @@
case LoongArch::BI__builtin_loongarch_crcc_w_d_w:
ID = Intrinsic::loongarch_crcc_w_d_w;
break;
+ case LoongArch::BI__builtin_loongarch_csrrd_w:
+ ID = Intrinsic::loongarch_csrrd_w;
+ break;
+ case LoongArch::BI__builtin_loongarch_csrwr_w:
+ ID = Intrinsic::loongarch_csrwr_w;
+ break;
+ case LoongArch::BI__builtin_loongarch_csrxchg_w:
+ ID = Intrinsic::loongarch_csrxchg_w;
+ break;
+ case LoongArch::BI__builtin_loongarch_csrrd_d:
+ ID = Intrinsic::loongarch_csrrd_d;
+ break;
+ case LoongArch::BI__builtin_loongarch_csrwr_d:
+ ID = Intrinsic::loongarch_csrwr_d;
+ break;
+ case LoongArch::BI__builtin_loongarch_csrxchg_d:
+ ID = Intrinsic::loongarch_csrxchg_d;
+ break;
// TODO: Support more Intrinsics.
}
Index: clang/include/clang/Basic/BuiltinsLoongArch.def
===================================================================
--- clang/include/clang/Basic/BuiltinsLoongArch.def
+++ clang/include/clang/Basic/BuiltinsLoongArch.def
@@ -31,5 +31,12 @@
TARGET_BUILTIN(__builtin_loongarch_crcc_w_w_w, "iii", "nc", "64bit")
TARGET_BUILTIN(__builtin_loongarch_crcc_w_d_w, "iLii", "nc", "64bit")
+TARGET_BUILTIN(__builtin_loongarch_csrrd_w, "UiIUi", "nc", "")
+TARGET_BUILTIN(__builtin_loongarch_csrrd_d, "ULiIUi", "nc", "64bit")
+TARGET_BUILTIN(__builtin_loongarch_csrwr_w, "UiUiIUi", "nc", "")
+TARGET_BUILTIN(__builtin_loongarch_csrwr_d, "ULiULiIUi", "nc", "64bit")
+TARGET_BUILTIN(__builtin_loongarch_csrxchg_w, "UiUiUiIUi", "nc", "")
+TARGET_BUILTIN(__builtin_loongarch_csrxchg_d, "ULiULiULiIUi", "nc", "64bit")
+
#undef BUILTIN
#undef TARGET_BUILTIN
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits