[clang] da34aff - [Clang][LoongArch] Implement __builtin_loongarch_crc_w_d_w builtin and add diagnostics

via cfe-commits cfe-commits at lists.llvm.org
Thu Nov 10 17:24:00 PST 2022


Author: gonglingqin
Date: 2022-11-11T09:16:57+08:00
New Revision: da34aff90d2b08f8172dd4942e398fc0c012399c

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

LOG: [Clang][LoongArch] Implement __builtin_loongarch_crc_w_d_w builtin and add diagnostics

This patch adds support to prevent __builtin_loongarch_crc_w_d_w from compiling
on loongarch32 in the front end and adds diagnostics accordingly.

Reference: https://github.com/gcc-mirror/gcc/blob/master/gcc/config/loongarch/larchintrin.h#L175-L184

Depends on D136906

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

Added: 
    clang/test/CodeGen/LoongArch/intrinsic-error.c
    clang/test/CodeGen/LoongArch/intrinsic-la64.c
    llvm/test/CodeGen/LoongArch/intrinsic-la32-error.ll
    llvm/test/CodeGen/LoongArch/intrinsic-la64.ll

Modified: 
    clang/include/clang/Basic/BuiltinsLoongArch.def
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/include/clang/Sema/Sema.h
    clang/lib/Basic/Targets/LoongArch.cpp
    clang/lib/Basic/Targets/LoongArch.h
    clang/lib/CodeGen/CGBuiltin.cpp
    clang/lib/Headers/larchintrin.h
    clang/lib/Sema/SemaChecking.cpp
    llvm/include/llvm/IR/IntrinsicsLoongArch.td
    llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
    llvm/lib/Target/LoongArch/LoongArchISelLowering.h
    llvm/lib/Target/LoongArch/LoongArchInstrInfo.td

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/BuiltinsLoongArch.def b/clang/include/clang/Basic/BuiltinsLoongArch.def
index 109592ca4324d..a896ccfa18fa8 100644
--- a/clang/include/clang/Basic/BuiltinsLoongArch.def
+++ b/clang/include/clang/Basic/BuiltinsLoongArch.def
@@ -19,5 +19,7 @@
 // TODO: Added feature constraints.
 TARGET_BUILTIN(__builtin_loongarch_dbar, "vIUi", "nc", "")
 
+TARGET_BUILTIN(__builtin_loongarch_crc_w_d_w, "iLii", "nc", "64bit")
+
 #undef BUILTIN
 #undef TARGET_BUILTIN

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index eea38a4cab8a3..03fa742d038aa 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11729,4 +11729,8 @@ def err_non_designated_init_used : Error<
   "a randomized struct can only be initialized with a designated initializer">;
 def err_cast_from_randomized_struct : Error<
   "casting from randomized structure pointer type %0 to %1">;
+
+// LoongArch-specific Diagnostics
+def err_loongarch_builtin_requires_la64 : Error<
+  "this builtin requires target: loongarch64">;
 } // end of sema component.

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 59e99bc050cec..206f1fe88e5bf 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13342,6 +13342,8 @@ class Sema final {
   bool CheckRISCVLMUL(CallExpr *TheCall, unsigned ArgNum);
   bool CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
                                      CallExpr *TheCall);
+  bool CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI,
+                                         unsigned BuiltinID, CallExpr *TheCall);
 
   bool SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall);
   bool SemaBuiltinVAStartARMMicrosoft(CallExpr *Call);

diff  --git a/clang/lib/Basic/Targets/LoongArch.cpp b/clang/lib/Basic/Targets/LoongArch.cpp
index f79afe5eb7c49..d8e1865217c1d 100644
--- a/clang/lib/Basic/Targets/LoongArch.cpp
+++ b/clang/lib/Basic/Targets/LoongArch.cpp
@@ -168,6 +168,27 @@ const Builtin::Info LoongArchTargetInfo::BuiltinInfo[] = {
 #include "clang/Basic/BuiltinsLoongArch.def"
 };
 
+bool LoongArchTargetInfo::initFeatureMap(
+    llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
+    const std::vector<std::string> &FeaturesVec) const {
+  if (getTriple().getArch() == llvm::Triple::loongarch64)
+    Features["64bit"] = true;
+
+  return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
+}
+
+/// Return true if has this feature.
+bool LoongArchTargetInfo::hasFeature(StringRef Feature) const {
+  bool Is64Bit = getTriple().getArch() == llvm::Triple::loongarch64;
+  // TODO: Handle more features.
+  return llvm::StringSwitch<bool>(Feature)
+      .Case("loongarch32", !Is64Bit)
+      .Case("loongarch64", Is64Bit)
+      .Case("32bit", !Is64Bit)
+      .Case("64bit", Is64Bit)
+      .Default(false);
+}
+
 ArrayRef<Builtin::Info> LoongArchTargetInfo::getTargetBuiltins() const {
   return llvm::makeArrayRef(BuiltinInfo, clang::LoongArch::LastTSBuiltin -
                                              Builtin::FirstTSBuiltin);

diff  --git a/clang/lib/Basic/Targets/LoongArch.h b/clang/lib/Basic/Targets/LoongArch.h
index 4128dfd8aa7de..69dc2e9d0471e 100644
--- a/clang/lib/Basic/Targets/LoongArch.h
+++ b/clang/lib/Basic/Targets/LoongArch.h
@@ -66,6 +66,13 @@ class LLVM_LIBRARY_VISIBILITY LoongArchTargetInfo : public TargetInfo {
 
   bool handleTargetFeatures(std::vector<std::string> &Features,
                             DiagnosticsEngine &Diags) override;
+
+  bool
+  initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
+                 StringRef CPU,
+                 const std::vector<std::string> &FeaturesVec) const override;
+
+  bool hasFeature(StringRef Feature) const override;
 };
 
 class LLVM_LIBRARY_VISIBILITY LoongArch32TargetInfo

diff  --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index e16094bca3762..a008d01383b0c 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -19638,6 +19638,9 @@ Value *CodeGenFunction::EmitLoongArchBuiltinExpr(unsigned BuiltinID,
   case LoongArch::BI__builtin_loongarch_dbar:
     ID = Intrinsic::loongarch_dbar;
     break;
+  case LoongArch::BI__builtin_loongarch_crc_w_d_w:
+    ID = Intrinsic::loongarch_crc_w_d_w;
+    break;
     // TODO: Support more Intrinsics.
   }
 

diff  --git a/clang/lib/Headers/larchintrin.h b/clang/lib/Headers/larchintrin.h
index c1e634cd6e590..7080bda8f3dca 100644
--- a/clang/lib/Headers/larchintrin.h
+++ b/clang/lib/Headers/larchintrin.h
@@ -14,6 +14,14 @@
 extern "C" {
 #endif
 
+#if __loongarch_grlen == 64
+extern __inline int
+    __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+    __crc_w_d_w(long int _1, int _2) {
+  return (int)__builtin_loongarch_crc_w_d_w((long int)_1, (int)_2);
+}
+#endif
+
 #define __dbar(/*ui15*/ _1) __builtin_loongarch_dbar((_1))
 
 #ifdef __cplusplus

diff  --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 25d746e62e3e1..003f74e292153 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2020,6 +2020,9 @@ bool Sema::CheckTSBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
   case llvm::Triple::riscv32:
   case llvm::Triple::riscv64:
     return CheckRISCVBuiltinFunctionCall(TI, BuiltinID, TheCall);
+  case llvm::Triple::loongarch32:
+  case llvm::Triple::loongarch64:
+    return CheckLoongArchBuiltinFunctionCall(TI, BuiltinID, TheCall);
   }
 }
 
@@ -3668,6 +3671,23 @@ bool Sema::CheckHexagonBuiltinFunctionCall(unsigned BuiltinID,
   return CheckHexagonBuiltinArgument(BuiltinID, TheCall);
 }
 
+bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI,
+                                             unsigned BuiltinID,
+                                             CallExpr *TheCall) {
+  switch (BuiltinID) {
+  default:
+    break;
+  case LoongArch::BI__builtin_loongarch_crc_w_d_w:
+    if (!TI.hasFeature("64bit"))
+      return Diag(TheCall->getBeginLoc(),
+                  diag::err_loongarch_builtin_requires_la64)
+             << TheCall->getSourceRange();
+    break;
+  }
+
+  return false;
+}
+
 bool Sema::CheckMipsBuiltinFunctionCall(const TargetInfo &TI,
                                         unsigned BuiltinID, CallExpr *TheCall) {
   return CheckMipsBuiltinCpu(TI, BuiltinID, TheCall) ||

diff  --git a/clang/test/CodeGen/LoongArch/intrinsic-error.c b/clang/test/CodeGen/LoongArch/intrinsic-error.c
new file mode 100644
index 0000000000000..5dc0cadd686ef
--- /dev/null
+++ b/clang/test/CodeGen/LoongArch/intrinsic-error.c
@@ -0,0 +1,8 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
+// RUN: %clang_cc1 -triple loongarch32 -emit-llvm -S -verify %s -o /dev/null
+
+#include <larchintrin.h>
+
+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}}
+}

diff  --git a/clang/test/CodeGen/LoongArch/intrinsic-la64.c b/clang/test/CodeGen/LoongArch/intrinsic-la64.c
new file mode 100644
index 0000000000000..9fc37460a5efc
--- /dev/null
+++ b/clang/test/CodeGen/LoongArch/intrinsic-la64.c
@@ -0,0 +1,13 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
+// RUN: %clang_cc1 -triple loongarch64 -O2 -emit-llvm %s -o - | FileCheck %s
+
+#include <larchintrin.h>
+
+// 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:%.*]])
+// CHECK-NEXT:    ret i32 [[TMP0]]
+//
+int crc_w_d_w(long int a, int b) {
+  return __builtin_loongarch_crc_w_d_w(a, b);
+}

diff  --git a/llvm/include/llvm/IR/IntrinsicsLoongArch.td b/llvm/include/llvm/IR/IntrinsicsLoongArch.td
index 116bdfba7ff55..7898d4205e94f 100644
--- a/llvm/include/llvm/IR/IntrinsicsLoongArch.td
+++ b/llvm/include/llvm/IR/IntrinsicsLoongArch.td
@@ -46,5 +46,10 @@ defm int_loongarch_masked_atomicrmw_umin : MaskedAtomicRMWIntrinsics;
 //   ptr addr, grlen cmpval, grlen newval, grlen mask, grlenimm ordering)
 defm int_loongarch_masked_cmpxchg : MaskedAtomicRMWFiveOpIntrinsics;
 
+//===----------------------------------------------------------------------===//
+// LoongArch BASE
+
 def int_loongarch_dbar : Intrinsic<[], [llvm_i32_ty]>;
+def int_loongarch_crc_w_d_w : Intrinsic<[llvm_i32_ty],
+                                        [llvm_i64_ty, llvm_i32_ty]>;
 } // TargetPrefix = "loongarch"

diff  --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
index 651b03a084c54..7bd0047a00b6d 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -90,6 +90,7 @@ LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM,
     setOperationAction(ISD::CTTZ, MVT::i32, Custom);
     setOperationAction(ISD::CTLZ, MVT::i32, Custom);
     setOperationAction(ISD::INTRINSIC_VOID, MVT::i32, Custom);
+    setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::i32, Custom);
     if (Subtarget.hasBasicF() && !Subtarget.hasBasicD())
       setOperationAction(ISD::FP_TO_UINT, MVT::i32, Custom);
     if (Subtarget.hasBasicF())
@@ -114,6 +115,7 @@ LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM,
     setOperationAction(ISD::BITREVERSE, MVT::i64, Legal);
   } else {
     setOperationAction(ISD::BITREVERSE, MVT::i32, Legal);
+    setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::i64, Custom);
   }
 
   static const ISD::CondCode FPCCToExpand[] = {
@@ -210,6 +212,8 @@ SDValue LoongArchTargetLowering::LowerOperation(SDValue Op,
     return lowerGlobalTLSAddress(Op, DAG);
   case ISD::INTRINSIC_WO_CHAIN:
     return lowerINTRINSIC_WO_CHAIN(Op, DAG);
+  case ISD::INTRINSIC_W_CHAIN:
+    return lowerINTRINSIC_W_CHAIN(Op, DAG);
   case ISD::INTRINSIC_VOID:
     return lowerINTRINSIC_VOID(Op, DAG);
   case ISD::BlockAddress:
@@ -556,6 +560,22 @@ LoongArchTargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op,
   }
 }
 
+SDValue
+LoongArchTargetLowering::lowerINTRINSIC_W_CHAIN(SDValue Op,
+                                                SelectionDAG &DAG) const {
+
+  switch (Op.getConstantOperandVal(1)) {
+  default:
+    return Op;
+  case Intrinsic::loongarch_crc_w_d_w: {
+    DAG.getContext()->emitError(
+        "llvm.loongarch.crc.w.d.w requires target: loongarch64");
+    return DAG.getMergeValues(
+        {DAG.getUNDEF(Op.getValueType()), Op.getOperand(0)}, SDLoc(Op));
+  }
+  }
+}
+
 SDValue LoongArchTargetLowering::lowerINTRINSIC_VOID(SDValue Op,
                                                      SelectionDAG &DAG) const {
   SDLoc DL(Op);
@@ -857,6 +877,25 @@ void LoongArchTargetLowering::ReplaceNodeResults(
     Results.push_back(customLegalizeToWOp(N, DAG, 1));
     break;
   }
+  case ISD::INTRINSIC_W_CHAIN: {
+    assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() &&
+           "Unexpected custom legalisation");
+
+    switch (N->getConstantOperandVal(1)) {
+    default:
+      llvm_unreachable("Unexpected Intrinsic.");
+    case Intrinsic::loongarch_crc_w_d_w: {
+      Results.push_back(DAG.getNode(
+          ISD::TRUNCATE, DL, N->getValueType(0),
+          DAG.getNode(
+              LoongArchISD::CRC_W_D_W, DL, MVT::i64, N->getOperand(2),
+              DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3)))));
+      Results.push_back(N->getOperand(0));
+      break;
+    }
+    }
+    break;
+  }
   }
 }
 
@@ -1312,6 +1351,7 @@ const char *LoongArchTargetLowering::getTargetNodeName(unsigned Opcode) const {
     NODE_NAME_CASE(CLZ_W)
     NODE_NAME_CASE(CTZ_W)
     NODE_NAME_CASE(DBAR)
+    NODE_NAME_CASE(CRC_W_D_W)
   }
 #undef NODE_NAME_CASE
   return nullptr;

diff  --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
index da0d666d0f704..3cb9999ed982a 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
@@ -59,6 +59,9 @@ enum NodeType : unsigned {
 
   // Intrinsic operations
   DBAR,
+
+  // CRC check operations
+  CRC_W_D_W
 };
 } // end namespace LoongArchISD
 
@@ -177,6 +180,7 @@ class LoongArchTargetLowering : public TargetLowering {
   SDValue lowerSINT_TO_FP(SDValue Op, SelectionDAG &DAG) const;
   SDValue lowerVASTART(SDValue Op, SelectionDAG &DAG) const;
   SDValue lowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const;
+  SDValue lowerINTRINSIC_W_CHAIN(SDValue Op, SelectionDAG &DAG) const;
   SDValue lowerINTRINSIC_VOID(SDValue Op, SelectionDAG &DAG) const;
   SDValue lowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const;
   SDValue lowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const;

diff  --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
index 73d38376bb2e4..8874f7849a90e 100644
--- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
+++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
@@ -55,6 +55,8 @@ def loongarch_sra_w : SDNode<"LoongArchISD::SRA_W", SDT_LoongArchIntBinOpW>;
 def loongarch_srl_w : SDNode<"LoongArchISD::SRL_W", SDT_LoongArchIntBinOpW>;
 def loongarch_rotr_w : SDNode<"LoongArchISD::ROTR_W", SDT_LoongArchIntBinOpW>;
 def loongarch_rotl_w : SDNode<"LoongArchISD::ROTL_W", SDT_LoongArchIntBinOpW>;
+def loongarch_crc_w_d_w
+    : SDNode<"LoongArchISD::CRC_W_D_W", SDT_LoongArchIntBinOpW>;
 def loongarch_bstrins
     : SDNode<"LoongArchISD::BSTRINS", SDT_LoongArchBStrIns>;
 def loongarch_bstrpick
@@ -1317,6 +1319,9 @@ def : Pat<(int_loongarch_dbar uimm15:$imm15), (DBAR 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]
 
 /// Other pseudo-instructions

diff  --git a/llvm/test/CodeGen/LoongArch/intrinsic-la32-error.ll b/llvm/test/CodeGen/LoongArch/intrinsic-la32-error.ll
new file mode 100644
index 0000000000000..15ddc51087657
--- /dev/null
+++ b/llvm/test/CodeGen/LoongArch/intrinsic-la32-error.ll
@@ -0,0 +1,10 @@
+; RUN: not llc --mtriple=loongarch32 --disable-verify < %s 2>&1 | FileCheck %s
+
+declare i32 @llvm.loongarch.crc.w.d.w(i64, i32)
+
+define i32 @crc_w_d_w(i64 %a, i32 %b) nounwind {
+; CHECK: llvm.loongarch.crc.w.d.w requires target: loongarch64
+entry:
+  %res = call i32 @llvm.loongarch.crc.w.d.w(i64 %a, i32 %b)
+  ret i32 %res
+}

diff  --git a/llvm/test/CodeGen/LoongArch/intrinsic-la64.ll b/llvm/test/CodeGen/LoongArch/intrinsic-la64.ll
new file mode 100644
index 0000000000000..a2eaa52982801
--- /dev/null
+++ b/llvm/test/CodeGen/LoongArch/intrinsic-la64.ll
@@ -0,0 +1,13 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc --mtriple=loongarch64 < %s | FileCheck %s
+
+declare i32 @llvm.loongarch.crc.w.d.w(i64, i32)
+
+define i32 @crc_w_d_w(i64 %a, i32 %b) nounwind {
+; CHECK-LABEL: crc_w_d_w:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    crc.w.d.w $a0, $a0, $a1
+; CHECK-NEXT:    ret
+  %res = call i32 @llvm.loongarch.crc.w.d.w(i64 %a, i32 %b)
+  ret i32 %res
+}


        


More information about the cfe-commits mailing list