[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