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
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to