[clang] 9e06d18 - [LoongArch] Add intrinsics for CACOP instruction

Xiaodong Liu via cfe-commits cfe-commits at lists.llvm.org
Thu Jan 5 19:44:46 PST 2023


Author: Xiaodong Liu
Date: 2023-01-06T11:41:35+08:00
New Revision: 9e06d18c80e77383f0ecdda428e74fbc1df3dd99

URL: https://github.com/llvm/llvm-project/commit/9e06d18c80e77383f0ecdda428e74fbc1df3dd99
DIFF: https://github.com/llvm/llvm-project/commit/9e06d18c80e77383f0ecdda428e74fbc1df3dd99.diff

LOG: [LoongArch] Add intrinsics for CACOP instruction

The CACOP instruction is mainly used for cache initialization
and cache-consistency maintenance.

Depends on D140872

Reviewed By: SixWeining

Differential Revision: https://reviews.llvm.org/D140527

Added: 
    llvm/test/CodeGen/LoongArch/intrinsic-la32.ll

Modified: 
    clang/include/clang/Basic/BuiltinsLoongArch.def
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/lib/Basic/Targets/LoongArch.cpp
    clang/lib/CodeGen/CGBuiltin.cpp
    clang/lib/Headers/larchintrin.h
    clang/lib/Sema/SemaChecking.cpp
    clang/test/CodeGen/LoongArch/intrinsic-la32-error.c
    clang/test/CodeGen/LoongArch/intrinsic-la32.c
    clang/test/CodeGen/LoongArch/intrinsic-la64.c
    clang/test/Driver/loongarch-default-features.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-la32-error.ll
    llvm/test/CodeGen/LoongArch/intrinsic-la64-error.ll
    llvm/test/CodeGen/LoongArch/intrinsic-la64.ll

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/BuiltinsLoongArch.def b/clang/include/clang/Basic/BuiltinsLoongArch.def
index cc466cf2703ca..7f2c8403410dd 100644
--- a/clang/include/clang/Basic/BuiltinsLoongArch.def
+++ b/clang/include/clang/Basic/BuiltinsLoongArch.def
@@ -17,6 +17,8 @@
 
 // TODO: Support more builtins.
 // TODO: Added feature constraints.
+TARGET_BUILTIN(__builtin_loongarch_cacop_d, "vLiULiLi", "nc", "64bit")
+TARGET_BUILTIN(__builtin_loongarch_cacop_w, "viUii", "nc", "32bit")
 TARGET_BUILTIN(__builtin_loongarch_dbar, "vIUi", "nc", "")
 TARGET_BUILTIN(__builtin_loongarch_ibar, "vIUi", "nc", "")
 TARGET_BUILTIN(__builtin_loongarch_movfcsr2gr, "UiIUi", "nc", "f")

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 16ab35fcb7a67..c684d3b4a7810 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11764,4 +11764,6 @@ def warn_unsafe_buffer_expression : Warning<
 def warn_unsafe_buffer_variable : Warning<
   "variable %0 participates in unchecked buffer operations">,
   InGroup<UnsafeBufferUsage>, DefaultIgnore;
+def err_loongarch_builtin_requires_la32 : Error<
+  "this builtin requires target: loongarch32">;
 } // end of sema component.

diff  --git a/clang/lib/Basic/Targets/LoongArch.cpp b/clang/lib/Basic/Targets/LoongArch.cpp
index 5ac94864cebb2..4ce2be8c80742 100644
--- a/clang/lib/Basic/Targets/LoongArch.cpp
+++ b/clang/lib/Basic/Targets/LoongArch.cpp
@@ -179,6 +179,8 @@ bool LoongArchTargetInfo::initFeatureMap(
     const std::vector<std::string> &FeaturesVec) const {
   if (getTriple().getArch() == llvm::Triple::loongarch64)
     Features["64bit"] = true;
+  if (getTriple().getArch() == llvm::Triple::loongarch32)
+    Features["32bit"] = true;
 
   return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
 }

diff  --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 0afa25da7aee3..fa6128b2a6441 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -19694,6 +19694,12 @@ Value *CodeGenFunction::EmitLoongArchBuiltinExpr(unsigned BuiltinID,
   switch (BuiltinID) {
   default:
     llvm_unreachable("unexpected builtin ID.");
+  case LoongArch::BI__builtin_loongarch_cacop_d:
+    ID = Intrinsic::loongarch_cacop_d;
+    break;
+  case LoongArch::BI__builtin_loongarch_cacop_w:
+    ID = Intrinsic::loongarch_cacop_w;
+    break;
   case LoongArch::BI__builtin_loongarch_dbar:
     ID = Intrinsic::loongarch_dbar;
     break;

diff  --git a/clang/lib/Headers/larchintrin.h b/clang/lib/Headers/larchintrin.h
index 5edcf4c02a441..c5c533ee0b8c1 100644
--- a/clang/lib/Headers/larchintrin.h
+++ b/clang/lib/Headers/larchintrin.h
@@ -106,6 +106,16 @@ extern __inline int
 
 #define __break(/*ui15*/ _1) __builtin_loongarch_break((_1))
 
+#if __loongarch_grlen == 32
+#define __cacop_w(/*uimm5*/ _1, /*unsigned int*/ _2, /*simm12*/ _3)            \
+  ((void)__builtin_loongarch_cacop_w((_1), (unsigned int)(_2), (_3)))
+#endif
+
+#if __loongarch_grlen == 64
+#define __cacop_d(/*uimm5*/ _1, /*unsigned long int*/ _2, /*simm12*/ _3)       \
+  ((void)__builtin_loongarch_cacop_d((_1), (unsigned long int)(_2), (_3)))
+#endif
+
 #define __dbar(/*ui15*/ _1) __builtin_loongarch_dbar((_1))
 
 #define __ibar(/*ui15*/ _1) __builtin_loongarch_ibar((_1))

diff  --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 05bf498737ec4..f787d6c2255f5 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -3705,6 +3705,23 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI,
   switch (BuiltinID) {
   default:
     break;
+  case LoongArch::BI__builtin_loongarch_cacop_d:
+    if (!TI.hasFeature("64bit"))
+      return Diag(TheCall->getBeginLoc(),
+                  diag::err_loongarch_builtin_requires_la64)
+             << TheCall->getSourceRange();
+    LLVM_FALLTHROUGH;
+  case LoongArch::BI__builtin_loongarch_cacop_w: {
+    if (BuiltinID == LoongArch::BI__builtin_loongarch_cacop_w &&
+        !TI.hasFeature("32bit"))
+      return Diag(TheCall->getBeginLoc(),
+                  diag::err_loongarch_builtin_requires_la32)
+             << TheCall->getSourceRange();
+    SemaBuiltinConstantArgRange(TheCall, 0, 0, llvm::maxUIntN(5));
+    SemaBuiltinConstantArgRange(TheCall, 2, llvm::minIntN(12),
+                                llvm::maxIntN(12));
+    break;
+  }
   case LoongArch::BI__builtin_loongarch_crc_w_b_w:
   case LoongArch::BI__builtin_loongarch_crc_w_h_w:
   case LoongArch::BI__builtin_loongarch_crc_w_w_w:

diff  --git a/clang/test/CodeGen/LoongArch/intrinsic-la32-error.c b/clang/test/CodeGen/LoongArch/intrinsic-la32-error.c
index 9941a6f874cba..2c3c249c54b13 100644
--- a/clang/test/CodeGen/LoongArch/intrinsic-la32-error.c
+++ b/clang/test/CodeGen/LoongArch/intrinsic-la32-error.c
@@ -3,6 +3,14 @@
 
 #include <larchintrin.h>
 
+void cacop_d(unsigned long int a) {
+  __builtin_loongarch_cacop_d(1, a, 1024); // expected-error {{this builtin requires target: loongarch64}}
+  __builtin_loongarch_cacop_w(-1, a, 1024); // expected-error {{argument value -1 is outside the valid range [0, 31]}}
+  __builtin_loongarch_cacop_w(32, a, 1024); // expected-error {{argument value 32 is outside the valid range [0, 31]}}
+  __builtin_loongarch_cacop_w(1, a, -4096); // expected-error {{argument value -4096 is outside the valid range [-2048, 2047]}}
+  __builtin_loongarch_cacop_w(1, a, 4096); // expected-error {{argument value 4096 is outside the valid range [-2048, 2047]}}
+}
+
 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]}}

diff  --git a/clang/test/CodeGen/LoongArch/intrinsic-la32.c b/clang/test/CodeGen/LoongArch/intrinsic-la32.c
index 060692a79ef4b..93d54f511a9cd 100644
--- a/clang/test/CodeGen/LoongArch/intrinsic-la32.c
+++ b/clang/test/CodeGen/LoongArch/intrinsic-la32.c
@@ -200,3 +200,14 @@ void loongarch_movgr2fcsr(int a) {
   __movgr2fcsr(1, a);
   __builtin_loongarch_movgr2fcsr(1, a);
 }
+
+// CHECK-LABEL: @cacop_w(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    tail call void @llvm.loongarch.cacop.w(i32 1, i32 [[A:%.*]], i32 1024)
+// CHECK-NEXT:    tail call void @llvm.loongarch.cacop.w(i32 1, i32 [[A]], i32 1024)
+// CHECK-NEXT:    ret void
+//
+void cacop_w(unsigned long int a) {
+  __cacop_w(1, a, 1024);
+  __builtin_loongarch_cacop_w(1, a, 1024);
+}

diff  --git a/clang/test/CodeGen/LoongArch/intrinsic-la64.c b/clang/test/CodeGen/LoongArch/intrinsic-la64.c
index a8e8f7dddade0..a740882eef541 100644
--- a/clang/test/CodeGen/LoongArch/intrinsic-la64.c
+++ b/clang/test/CodeGen/LoongArch/intrinsic-la64.c
@@ -123,6 +123,17 @@ int crc_w_w_w(int a, int b) {
   return 0;
 }
 
+// CHECK-LABEL: @cacop_d(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    tail call void @llvm.loongarch.cacop.d(i64 1, i64 [[A:%.*]], i64 1024)
+// CHECK-NEXT:    tail call void @llvm.loongarch.cacop.d(i64 1, i64 [[A]], i64 1024)
+// CHECK-NEXT:    ret void
+//
+void cacop_d(unsigned long int a) {
+  __cacop_d(1, a, 1024);
+  __builtin_loongarch_cacop_d(1, a, 1024);
+}
+
 // CHECK-LABEL: @crc_w_d_w(
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[TMP0:%.*]] = tail call i32 @llvm.loongarch.crc.w.d.w(i64 [[A:%.*]], i32 [[B:%.*]])

diff  --git a/clang/test/Driver/loongarch-default-features.c b/clang/test/Driver/loongarch-default-features.c
index 8abc68b9ee744..027d8cdb70cf4 100644
--- a/clang/test/Driver/loongarch-default-features.c
+++ b/clang/test/Driver/loongarch-default-features.c
@@ -1,7 +1,7 @@
 // RUN: %clang --target=loongarch32 -S -emit-llvm %s -o - | FileCheck %s --check-prefix=LA32
 // RUN: %clang --target=loongarch64 -S -emit-llvm %s -o - | FileCheck %s --check-prefix=LA64
 
-// LA32-NOT: "target-features"=
+// LA32: "target-features"="+32bit"
 // LA64: "target-features"="+64bit,+d,+f"
 
 int foo(void) {

diff  --git a/llvm/include/llvm/IR/IntrinsicsLoongArch.td b/llvm/include/llvm/IR/IntrinsicsLoongArch.td
index 995e357d3186f..5edce3c529e12 100644
--- a/llvm/include/llvm/IR/IntrinsicsLoongArch.td
+++ b/llvm/include/llvm/IR/IntrinsicsLoongArch.td
@@ -52,6 +52,10 @@ defm int_loongarch_masked_cmpxchg : MaskedAtomicRMWFiveOpIntrinsics;
 // LoongArch BASE
 
 def int_loongarch_break : Intrinsic<[], [llvm_i32_ty], [ImmArg<ArgIndex<0>>]>;
+def int_loongarch_cacop_d : Intrinsic<[], [llvm_i64_ty, llvm_i64_ty, llvm_i64_ty],
+    [ImmArg<ArgIndex<0>>, ImmArg<ArgIndex<2>>]>;
+def int_loongarch_cacop_w : Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty],
+    [ImmArg<ArgIndex<0>>, ImmArg<ArgIndex<2>>]>;
 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_movfcsr2gr : Intrinsic<[llvm_i32_ty], [llvm_i32_ty],

diff  --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
index 55d5af82587c1..b5e5374a5e76b 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -746,13 +746,38 @@ SDValue LoongArchTargetLowering::lowerINTRINSIC_VOID(SDValue Op,
   SDLoc DL(Op);
   MVT GRLenVT = Subtarget.getGRLenVT();
   SDValue Op0 = Op.getOperand(0);
+  uint64_t IntrinsicEnum = Op.getConstantOperandVal(1);
   SDValue Op2 = Op.getOperand(2);
   const StringRef ErrorMsgOOR = "out of range";
 
-  switch (Op.getConstantOperandVal(1)) {
+  switch (IntrinsicEnum) {
   default:
     // TODO: Add more Intrinsics.
     return SDValue();
+  case Intrinsic::loongarch_cacop_d:
+  case Intrinsic::loongarch_cacop_w: {
+    if (IntrinsicEnum == Intrinsic::loongarch_cacop_d && !Subtarget.is64Bit()) {
+      DAG.getContext()->emitError(
+          "llvm.loongarch.cacop.d requires target: loongarch64");
+      return Op.getOperand(0);
+    }
+    if (IntrinsicEnum == Intrinsic::loongarch_cacop_w && Subtarget.is64Bit()) {
+      DAG.getContext()->emitError(
+          "llvm.loongarch.cacop.w requires target: loongarch32");
+      return Op.getOperand(0);
+    }
+    // call void @llvm.loongarch.cacop.[d/w](uimm5, rj, simm12)
+    unsigned Imm1 = cast<ConstantSDNode>(Op2)->getZExtValue();
+    if (!isUInt<5>(Imm1))
+      return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
+    SDValue Op4 = Op.getOperand(4);
+    int Imm2 = cast<ConstantSDNode>(Op4)->getSExtValue();
+    if (!isInt<12>(Imm2))
+      return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
+
+    return Op;
+  }
+
   case Intrinsic::loongarch_dbar: {
     unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
     if (!isUInt<15>(Imm))
@@ -1778,6 +1803,8 @@ const char *LoongArchTargetLowering::getTargetNodeName(unsigned Opcode) const {
     NODE_NAME_CASE(CPUCFG)
     NODE_NAME_CASE(MOVGR2FCSR)
     NODE_NAME_CASE(MOVFCSR2GR)
+    NODE_NAME_CASE(CACOP_D)
+    NODE_NAME_CASE(CACOP_W)
   }
 #undef NODE_NAME_CASE
   return nullptr;

diff  --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
index 9227131461d39..976aae3bb6cee 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
@@ -61,8 +61,10 @@ enum NodeType : unsigned {
   BITREV_4B,
   BITREV_W,
 
-  // Intrinsic operations
+  // Intrinsic operations start ============================================
   BREAK,
+  CACOP_D,
+  CACOP_W,
   DBAR,
   IBAR,
   SYSCALL,
@@ -93,6 +95,7 @@ enum NodeType : unsigned {
 
   // Read CPU configuration information operation
   CPUCFG,
+  // Intrinsic operations end =============================================
 };
 } // end namespace LoongArchISD
 

diff  --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
index b4a8ad8991757..8e552b23b65d7 100644
--- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
+++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
@@ -589,6 +589,10 @@ def RDTIMEL_W : RDTIME_2R<0b0000000000000000011000, "rdtimel.w">;
 def RDTIMEH_W : RDTIME_2R<0b0000000000000000011001, "rdtimeh.w">;
 def CPUCFG : ALU_2R<0b0000000000000000011011, "cpucfg">;
 
+// Cache Maintenance Instructions
+def CACOP : FmtCACOP<(outs), (ins uimm5:$op, GPR:$rj, simm12:$imm12), "cacop",
+                     "$op, $rj, $imm12">;
+
 /// LA64 instructions
 
 let Predicates = [IsLA64] in {
@@ -1563,6 +1567,10 @@ defm : PseudoBinPat<"atomic_load_xor_32", PseudoAtomicLoadXor32>;
 
 /// Intrinsics
 
+def : Pat<(int_loongarch_cacop_d timm:$op, i64:$rj, timm:$imm12),
+          (CACOP uimm5:$op, GPR:$rj, simm12:$imm12)>;
+def : Pat<(int_loongarch_cacop_w i32:$op, i32:$rj, i32:$imm12),
+          (CACOP uimm5:$op, GPR:$rj, simm12:$imm12)>;
 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)>;
@@ -1673,10 +1681,6 @@ def IOCSRRD_D : IOCSRRD<0b0000011001001000000011, "iocsrrd.d">;
 def IOCSRWR_D : IOCSRWR<0b0000011001001000000111, "iocsrwr.d">;
 } // Predicates = [IsLA64]
 
-// Cache Maintenance Instructions
-def CACOP : FmtCACOP<(outs), (ins uimm5:$op, GPR:$rj, simm12:$imm12), "cacop",
-                     "$op, $rj, $imm12">;
-
 // TLB Maintenance Instructions
 def TLBSRCH  : FmtI32<0b00000110010010000010100000000000, "tlbsrch">;
 def TLBRD    : FmtI32<0b00000110010010000010110000000000, "tlbrd">;

diff  --git a/llvm/test/CodeGen/LoongArch/intrinsic-la32-error.ll b/llvm/test/CodeGen/LoongArch/intrinsic-la32-error.ll
index c4910ccad4d56..4b38e6ca10906 100644
--- a/llvm/test/CodeGen/LoongArch/intrinsic-la32-error.ll
+++ b/llvm/test/CodeGen/LoongArch/intrinsic-la32-error.ll
@@ -1,5 +1,6 @@
 ; RUN: not llc --mtriple=loongarch32 --disable-verify < %s 2>&1 | FileCheck %s
 
+declare void @llvm.loongarch.cacop.w(i32, i32, i32)
 declare i32 @llvm.loongarch.crc.w.b.w(i32, i32)
 declare i32 @llvm.loongarch.crc.w.h.w(i32, i32)
 declare i32 @llvm.loongarch.crc.w.w.w(i32, i32)
@@ -18,6 +19,34 @@ declare void @llvm.loongarch.asrtgt.d(i64, i64)
 declare i64 @llvm.loongarch.lddir.d(i64, i32)
 declare void @llvm.loongarch.ldpte.d(i64, i32)
 
+define void @cacop_arg0_out_of_hi_range(i32 %a) nounwind {
+; CHECK: argument to 'llvm.loongarch.cacop.w' out of range
+entry:
+  call void @llvm.loongarch.cacop.w(i32 32, i32 %a, i32 1024)
+  ret void
+}
+
+define void @cacop_arg0_out_of_lo_range(i32 %a) nounwind {
+; CHECK: argument to 'llvm.loongarch.cacop.w' out of range
+entry:
+  call void @llvm.loongarch.cacop.w(i32 -1, i32 %a, i32 1024)
+  ret void
+}
+
+define void @cacop_arg2_out_of_hi_range(i32 %a) nounwind {
+; CHECK: argument to 'llvm.loongarch.cacop.w' out of range
+entry:
+  call void @llvm.loongarch.cacop.w(i32 1, i32 %a, i32 4096)
+  ret void
+}
+
+define void @cacop_arg2_out_of_lo_range(i32 %a) nounwind {
+; CHECK: argument to 'llvm.loongarch.cacop.w' out of range
+entry:
+  call void @llvm.loongarch.cacop.w(i32 1, i32 %a, i32 -4096)
+  ret void
+}
+
 define i32 @crc_w_b_w(i32 %a, i32 %b) nounwind {
 ; CHECK: llvm.loongarch.crc.w.b.w requires target: loongarch64
 entry:

diff  --git a/llvm/test/CodeGen/LoongArch/intrinsic-la32.ll b/llvm/test/CodeGen/LoongArch/intrinsic-la32.ll
new file mode 100644
index 0000000000000..37e0902625a2c
--- /dev/null
+++ b/llvm/test/CodeGen/LoongArch/intrinsic-la32.ll
@@ -0,0 +1,13 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc --mtriple=loongarch32 < %s | FileCheck %s
+
+declare void @llvm.loongarch.cacop.w(i32, i32, i32)
+
+define void @cacop_w(i32 %a) nounwind {
+; CHECK-LABEL: cacop_w:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cacop 1, $a0, 4
+; CHECK-NEXT:    ret
+  call void @llvm.loongarch.cacop.w(i32 1, i32 %a, i32 4)
+  ret void
+}

diff  --git a/llvm/test/CodeGen/LoongArch/intrinsic-la64-error.ll b/llvm/test/CodeGen/LoongArch/intrinsic-la64-error.ll
index 05eb9f313e24f..51f6c445309ab 100644
--- a/llvm/test/CodeGen/LoongArch/intrinsic-la64-error.ll
+++ b/llvm/test/CodeGen/LoongArch/intrinsic-la64-error.ll
@@ -1,6 +1,8 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
 ; RUN: not llc --mtriple=loongarch64 < %s 2>&1 | FileCheck %s
 
+declare void @llvm.loongarch.cacop.w(i32, i32, i32)
+declare void @llvm.loongarch.cacop.d(i64, i64, i64)
 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)
@@ -46,3 +48,37 @@ entry:
   %0 = call i64 @llvm.loongarch.csrxchg.d(i64 %a, i64 %b, i32 -1)
   ret i64 %0
 }
+
+define void @cacop_w(i32 %a) nounwind {
+; CHECK: llvm.loongarch.cacop.w requires target: loongarch32
+  call void @llvm.loongarch.cacop.w(i32 1, i32 %a, i32 4)
+  ret void
+}
+
+define void @cacop_arg0_out_of_hi_range(i64 %a) nounwind {
+; CHECK: argument to 'llvm.loongarch.cacop.d' out of range
+entry:
+  call void @llvm.loongarch.cacop.d(i64 32, i64 %a, i64 1024)
+  ret void
+}
+
+define void @cacop_arg0_out_of_lo_range(i64 %a) nounwind {
+; CHECK: argument to 'llvm.loongarch.cacop.d' out of range
+entry:
+  call void @llvm.loongarch.cacop.d(i64 -1, i64 %a, i64 1024)
+  ret void
+}
+
+define void @cacop_arg2_out_of_hi_range(i64 %a) nounwind {
+; CHECK: argument to 'llvm.loongarch.cacop.d' out of range
+entry:
+  call void @llvm.loongarch.cacop.d(i64 1, i64 %a, i64 4096)
+  ret void
+}
+
+define void @cacop_arg2_out_of_lo_range(i64 %a) nounwind {
+; CHECK: argument to 'llvm.loongarch.cacop.d' out of range
+entry:
+  call void @llvm.loongarch.cacop.d(i64 1, i64 %a, i64 -4096)
+  ret void
+}

diff  --git a/llvm/test/CodeGen/LoongArch/intrinsic-la64.ll b/llvm/test/CodeGen/LoongArch/intrinsic-la64.ll
index 1ec55f341629b..7b28682b5aa97 100644
--- a/llvm/test/CodeGen/LoongArch/intrinsic-la64.ll
+++ b/llvm/test/CodeGen/LoongArch/intrinsic-la64.ll
@@ -1,6 +1,7 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
 ; RUN: llc --mtriple=loongarch64 < %s | FileCheck %s
 
+declare void @llvm.loongarch.cacop.d(i64, i64, i64)
 declare i32 @llvm.loongarch.crc.w.b.w(i32, i32)
 declare i32 @llvm.loongarch.crc.w.h.w(i32, i32)
 declare i32 @llvm.loongarch.crc.w.w.w(i32, i32)
@@ -46,6 +47,15 @@ define i32 @crc_w_w_w(i32 %a, i32 %b) nounwind {
   ret i32 %res
 }
 
+define void @cacop_d(i64 %a) nounwind {
+; CHECK-LABEL: cacop_d:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cacop 1, $a0, 4
+; CHECK-NEXT:    ret
+  call void @llvm.loongarch.cacop.d(i64 1, i64 %a, i64 4)
+  ret void
+}
+
 define i32 @crc_w_d_w(i64 %a, i32 %b) nounwind {
 ; CHECK-LABEL: crc_w_d_w:
 ; CHECK:       # %bb.0:


        


More information about the cfe-commits mailing list