Skip to content

Commit da34aff

Browse files
committed
[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
1 parent ffb109b commit da34aff

File tree

16 files changed

+165
-0
lines changed

16 files changed

+165
-0
lines changed

clang/include/clang/Basic/BuiltinsLoongArch.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,7 @@
1919
// TODO: Added feature constraints.
2020
TARGET_BUILTIN(__builtin_loongarch_dbar, "vIUi", "nc", "")
2121

22+
TARGET_BUILTIN(__builtin_loongarch_crc_w_d_w, "iLii", "nc", "64bit")
23+
2224
#undef BUILTIN
2325
#undef TARGET_BUILTIN

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11729,4 +11729,8 @@ def err_non_designated_init_used : Error<
1172911729
"a randomized struct can only be initialized with a designated initializer">;
1173011730
def err_cast_from_randomized_struct : Error<
1173111731
"casting from randomized structure pointer type %0 to %1">;
11732+
11733+
// LoongArch-specific Diagnostics
11734+
def err_loongarch_builtin_requires_la64 : Error<
11735+
"this builtin requires target: loongarch64">;
1173211736
} // end of sema component.

clang/include/clang/Sema/Sema.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13342,6 +13342,8 @@ class Sema final {
1334213342
bool CheckRISCVLMUL(CallExpr *TheCall, unsigned ArgNum);
1334313343
bool CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
1334413344
CallExpr *TheCall);
13345+
bool CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI,
13346+
unsigned BuiltinID, CallExpr *TheCall);
1334513347

1334613348
bool SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall);
1334713349
bool SemaBuiltinVAStartARMMicrosoft(CallExpr *Call);

clang/lib/Basic/Targets/LoongArch.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,27 @@ const Builtin::Info LoongArchTargetInfo::BuiltinInfo[] = {
168168
#include "clang/Basic/BuiltinsLoongArch.def"
169169
};
170170

171+
bool LoongArchTargetInfo::initFeatureMap(
172+
llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
173+
const std::vector<std::string> &FeaturesVec) const {
174+
if (getTriple().getArch() == llvm::Triple::loongarch64)
175+
Features["64bit"] = true;
176+
177+
return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
178+
}
179+
180+
/// Return true if has this feature.
181+
bool LoongArchTargetInfo::hasFeature(StringRef Feature) const {
182+
bool Is64Bit = getTriple().getArch() == llvm::Triple::loongarch64;
183+
// TODO: Handle more features.
184+
return llvm::StringSwitch<bool>(Feature)
185+
.Case("loongarch32", !Is64Bit)
186+
.Case("loongarch64", Is64Bit)
187+
.Case("32bit", !Is64Bit)
188+
.Case("64bit", Is64Bit)
189+
.Default(false);
190+
}
191+
171192
ArrayRef<Builtin::Info> LoongArchTargetInfo::getTargetBuiltins() const {
172193
return llvm::makeArrayRef(BuiltinInfo, clang::LoongArch::LastTSBuiltin -
173194
Builtin::FirstTSBuiltin);

clang/lib/Basic/Targets/LoongArch.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,13 @@ class LLVM_LIBRARY_VISIBILITY LoongArchTargetInfo : public TargetInfo {
6666

6767
bool handleTargetFeatures(std::vector<std::string> &Features,
6868
DiagnosticsEngine &Diags) override;
69+
70+
bool
71+
initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
72+
StringRef CPU,
73+
const std::vector<std::string> &FeaturesVec) const override;
74+
75+
bool hasFeature(StringRef Feature) const override;
6976
};
7077

7178
class LLVM_LIBRARY_VISIBILITY LoongArch32TargetInfo

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19638,6 +19638,9 @@ Value *CodeGenFunction::EmitLoongArchBuiltinExpr(unsigned BuiltinID,
1963819638
case LoongArch::BI__builtin_loongarch_dbar:
1963919639
ID = Intrinsic::loongarch_dbar;
1964019640
break;
19641+
case LoongArch::BI__builtin_loongarch_crc_w_d_w:
19642+
ID = Intrinsic::loongarch_crc_w_d_w;
19643+
break;
1964119644
// TODO: Support more Intrinsics.
1964219645
}
1964319646

clang/lib/Headers/larchintrin.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@
1414
extern "C" {
1515
#endif
1616

17+
#if __loongarch_grlen == 64
18+
extern __inline int
19+
__attribute__((__gnu_inline__, __always_inline__, __artificial__))
20+
__crc_w_d_w(long int _1, int _2) {
21+
return (int)__builtin_loongarch_crc_w_d_w((long int)_1, (int)_2);
22+
}
23+
#endif
24+
1725
#define __dbar(/*ui15*/ _1) __builtin_loongarch_dbar((_1))
1826

1927
#ifdef __cplusplus

clang/lib/Sema/SemaChecking.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2020,6 +2020,9 @@ bool Sema::CheckTSBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
20202020
case llvm::Triple::riscv32:
20212021
case llvm::Triple::riscv64:
20222022
return CheckRISCVBuiltinFunctionCall(TI, BuiltinID, TheCall);
2023+
case llvm::Triple::loongarch32:
2024+
case llvm::Triple::loongarch64:
2025+
return CheckLoongArchBuiltinFunctionCall(TI, BuiltinID, TheCall);
20232026
}
20242027
}
20252028

@@ -3668,6 +3671,23 @@ bool Sema::CheckHexagonBuiltinFunctionCall(unsigned BuiltinID,
36683671
return CheckHexagonBuiltinArgument(BuiltinID, TheCall);
36693672
}
36703673

3674+
bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI,
3675+
unsigned BuiltinID,
3676+
CallExpr *TheCall) {
3677+
switch (BuiltinID) {
3678+
default:
3679+
break;
3680+
case LoongArch::BI__builtin_loongarch_crc_w_d_w:
3681+
if (!TI.hasFeature("64bit"))
3682+
return Diag(TheCall->getBeginLoc(),
3683+
diag::err_loongarch_builtin_requires_la64)
3684+
<< TheCall->getSourceRange();
3685+
break;
3686+
}
3687+
3688+
return false;
3689+
}
3690+
36713691
bool Sema::CheckMipsBuiltinFunctionCall(const TargetInfo &TI,
36723692
unsigned BuiltinID, CallExpr *TheCall) {
36733693
return CheckMipsBuiltinCpu(TI, BuiltinID, TheCall) ||
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
2+
// RUN: %clang_cc1 -triple loongarch32 -emit-llvm -S -verify %s -o /dev/null
3+
4+
#include <larchintrin.h>
5+
6+
int crc_w_d_w(long int a, int b) {
7+
return __builtin_loongarch_crc_w_d_w(a, b); // expected-error {{this builtin requires target: loongarch64}}
8+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
2+
// RUN: %clang_cc1 -triple loongarch64 -O2 -emit-llvm %s -o - | FileCheck %s
3+
4+
#include <larchintrin.h>
5+
6+
// CHECK-LABEL: @crc_w_d_w(
7+
// CHECK-NEXT: entry:
8+
// CHECK-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.loongarch.crc.w.d.w(i64 [[A:%.*]], i32 [[B:%.*]])
9+
// CHECK-NEXT: ret i32 [[TMP0]]
10+
//
11+
int crc_w_d_w(long int a, int b) {
12+
return __builtin_loongarch_crc_w_d_w(a, b);
13+
}

llvm/include/llvm/IR/IntrinsicsLoongArch.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,10 @@ defm int_loongarch_masked_atomicrmw_umin : MaskedAtomicRMWIntrinsics;
4646
// ptr addr, grlen cmpval, grlen newval, grlen mask, grlenimm ordering)
4747
defm int_loongarch_masked_cmpxchg : MaskedAtomicRMWFiveOpIntrinsics;
4848

49+
//===----------------------------------------------------------------------===//
50+
// LoongArch BASE
51+
4952
def int_loongarch_dbar : Intrinsic<[], [llvm_i32_ty]>;
53+
def int_loongarch_crc_w_d_w : Intrinsic<[llvm_i32_ty],
54+
[llvm_i64_ty, llvm_i32_ty]>;
5055
} // TargetPrefix = "loongarch"

llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM,
9090
setOperationAction(ISD::CTTZ, MVT::i32, Custom);
9191
setOperationAction(ISD::CTLZ, MVT::i32, Custom);
9292
setOperationAction(ISD::INTRINSIC_VOID, MVT::i32, Custom);
93+
setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::i32, Custom);
9394
if (Subtarget.hasBasicF() && !Subtarget.hasBasicD())
9495
setOperationAction(ISD::FP_TO_UINT, MVT::i32, Custom);
9596
if (Subtarget.hasBasicF())
@@ -114,6 +115,7 @@ LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM,
114115
setOperationAction(ISD::BITREVERSE, MVT::i64, Legal);
115116
} else {
116117
setOperationAction(ISD::BITREVERSE, MVT::i32, Legal);
118+
setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::i64, Custom);
117119
}
118120

119121
static const ISD::CondCode FPCCToExpand[] = {
@@ -210,6 +212,8 @@ SDValue LoongArchTargetLowering::LowerOperation(SDValue Op,
210212
return lowerGlobalTLSAddress(Op, DAG);
211213
case ISD::INTRINSIC_WO_CHAIN:
212214
return lowerINTRINSIC_WO_CHAIN(Op, DAG);
215+
case ISD::INTRINSIC_W_CHAIN:
216+
return lowerINTRINSIC_W_CHAIN(Op, DAG);
213217
case ISD::INTRINSIC_VOID:
214218
return lowerINTRINSIC_VOID(Op, DAG);
215219
case ISD::BlockAddress:
@@ -556,6 +560,22 @@ LoongArchTargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op,
556560
}
557561
}
558562

563+
SDValue
564+
LoongArchTargetLowering::lowerINTRINSIC_W_CHAIN(SDValue Op,
565+
SelectionDAG &DAG) const {
566+
567+
switch (Op.getConstantOperandVal(1)) {
568+
default:
569+
return Op;
570+
case Intrinsic::loongarch_crc_w_d_w: {
571+
DAG.getContext()->emitError(
572+
"llvm.loongarch.crc.w.d.w requires target: loongarch64");
573+
return DAG.getMergeValues(
574+
{DAG.getUNDEF(Op.getValueType()), Op.getOperand(0)}, SDLoc(Op));
575+
}
576+
}
577+
}
578+
559579
SDValue LoongArchTargetLowering::lowerINTRINSIC_VOID(SDValue Op,
560580
SelectionDAG &DAG) const {
561581
SDLoc DL(Op);
@@ -857,6 +877,25 @@ void LoongArchTargetLowering::ReplaceNodeResults(
857877
Results.push_back(customLegalizeToWOp(N, DAG, 1));
858878
break;
859879
}
880+
case ISD::INTRINSIC_W_CHAIN: {
881+
assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() &&
882+
"Unexpected custom legalisation");
883+
884+
switch (N->getConstantOperandVal(1)) {
885+
default:
886+
llvm_unreachable("Unexpected Intrinsic.");
887+
case Intrinsic::loongarch_crc_w_d_w: {
888+
Results.push_back(DAG.getNode(
889+
ISD::TRUNCATE, DL, N->getValueType(0),
890+
DAG.getNode(
891+
LoongArchISD::CRC_W_D_W, DL, MVT::i64, N->getOperand(2),
892+
DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3)))));
893+
Results.push_back(N->getOperand(0));
894+
break;
895+
}
896+
}
897+
break;
898+
}
860899
}
861900
}
862901

@@ -1312,6 +1351,7 @@ const char *LoongArchTargetLowering::getTargetNodeName(unsigned Opcode) const {
13121351
NODE_NAME_CASE(CLZ_W)
13131352
NODE_NAME_CASE(CTZ_W)
13141353
NODE_NAME_CASE(DBAR)
1354+
NODE_NAME_CASE(CRC_W_D_W)
13151355
}
13161356
#undef NODE_NAME_CASE
13171357
return nullptr;

llvm/lib/Target/LoongArch/LoongArchISelLowering.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ enum NodeType : unsigned {
5959

6060
// Intrinsic operations
6161
DBAR,
62+
63+
// CRC check operations
64+
CRC_W_D_W
6265
};
6366
} // end namespace LoongArchISD
6467

@@ -177,6 +180,7 @@ class LoongArchTargetLowering : public TargetLowering {
177180
SDValue lowerSINT_TO_FP(SDValue Op, SelectionDAG &DAG) const;
178181
SDValue lowerVASTART(SDValue Op, SelectionDAG &DAG) const;
179182
SDValue lowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const;
183+
SDValue lowerINTRINSIC_W_CHAIN(SDValue Op, SelectionDAG &DAG) const;
180184
SDValue lowerINTRINSIC_VOID(SDValue Op, SelectionDAG &DAG) const;
181185
SDValue lowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const;
182186
SDValue lowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const;

llvm/lib/Target/LoongArch/LoongArchInstrInfo.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ def loongarch_sra_w : SDNode<"LoongArchISD::SRA_W", SDT_LoongArchIntBinOpW>;
5555
def loongarch_srl_w : SDNode<"LoongArchISD::SRL_W", SDT_LoongArchIntBinOpW>;
5656
def loongarch_rotr_w : SDNode<"LoongArchISD::ROTR_W", SDT_LoongArchIntBinOpW>;
5757
def loongarch_rotl_w : SDNode<"LoongArchISD::ROTL_W", SDT_LoongArchIntBinOpW>;
58+
def loongarch_crc_w_d_w
59+
: SDNode<"LoongArchISD::CRC_W_D_W", SDT_LoongArchIntBinOpW>;
5860
def loongarch_bstrins
5961
: SDNode<"LoongArchISD::BSTRINS", SDT_LoongArchBStrIns>;
6062
def loongarch_bstrpick
@@ -1317,6 +1319,9 @@ def : Pat<(int_loongarch_dbar uimm15:$imm15), (DBAR uimm15:$imm15)>;
13171319

13181320
let Predicates = [IsLA64] in {
13191321
def : Pat<(loongarch_dbar uimm15:$imm15), (DBAR uimm15:$imm15)>;
1322+
1323+
// CRC Check Instructions
1324+
def : PatGprGpr<loongarch_crc_w_d_w, CRC_W_D_W>;
13201325
} // Predicates = [IsLA64]
13211326

13221327
/// Other pseudo-instructions
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
; RUN: not llc --mtriple=loongarch32 --disable-verify < %s 2>&1 | FileCheck %s
2+
3+
declare i32 @llvm.loongarch.crc.w.d.w(i64, i32)
4+
5+
define i32 @crc_w_d_w(i64 %a, i32 %b) nounwind {
6+
; CHECK: llvm.loongarch.crc.w.d.w requires target: loongarch64
7+
entry:
8+
%res = call i32 @llvm.loongarch.crc.w.d.w(i64 %a, i32 %b)
9+
ret i32 %res
10+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2+
; RUN: llc --mtriple=loongarch64 < %s | FileCheck %s
3+
4+
declare i32 @llvm.loongarch.crc.w.d.w(i64, i32)
5+
6+
define i32 @crc_w_d_w(i64 %a, i32 %b) nounwind {
7+
; CHECK-LABEL: crc_w_d_w:
8+
; CHECK: # %bb.0:
9+
; CHECK-NEXT: crc.w.d.w $a0, $a0, $a1
10+
; CHECK-NEXT: ret
11+
%res = call i32 @llvm.loongarch.crc.w.d.w(i64 %a, i32 %b)
12+
ret i32 %res
13+
}

0 commit comments

Comments
 (0)