Skip to content

Commit de45866

Browse files
LevyHsumemfrob
authored andcommitted
[RISCV] Add IR intrinsic for Zbr extension
Implementation for RISC-V Zbr extension intrinsic. Header files are included in separate patch in case the name needs to be changed RV32 / 64: crc32b crc32h crc32w crc32cb crc32ch crc32cw RV64 Only: crc32d crc32cd Reviewed By: craig.topper Differential Revision: https://reviews.llvm.org/D99009
1 parent 1c852eb commit de45866

File tree

11 files changed

+442
-8
lines changed

11 files changed

+442
-8
lines changed

clang/include/clang/Basic/BuiltinsRISCV.def

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,15 @@
1717

1818
#include "clang/Basic/riscv_vector_builtins.inc"
1919

20+
// Zbr extension
21+
TARGET_BUILTIN(__builtin_riscv_crc32_b, "LiLi", "nc", "experimental-zbr")
22+
TARGET_BUILTIN(__builtin_riscv_crc32_h, "LiLi", "nc", "experimental-zbr")
23+
TARGET_BUILTIN(__builtin_riscv_crc32_w, "LiLi", "nc", "experimental-zbr")
24+
TARGET_BUILTIN(__builtin_riscv_crc32c_b, "LiLi", "nc", "experimental-zbr")
25+
TARGET_BUILTIN(__builtin_riscv_crc32c_h, "LiLi", "nc", "experimental-zbr")
26+
TARGET_BUILTIN(__builtin_riscv_crc32c_w, "LiLi", "nc", "experimental-zbr")
27+
TARGET_BUILTIN(__builtin_riscv_crc32_d, "LiLi", "nc", "experimental-zbr")
28+
TARGET_BUILTIN(__builtin_riscv_crc32c_d, "LiLi", "nc", "experimental-zbr")
29+
2030
#undef BUILTIN
2131
#undef TARGET_BUILTIN

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11185,7 +11185,7 @@ def warn_tcb_enforcement_violation : Warning<
1118511185
"calling %0 is a violation of trusted computing base '%1'">,
1118611186
InGroup<DiagGroup<"tcb-enforcement">>;
1118711187

11188-
// RISC-V V-extension
11189-
def err_riscvv_builtin_requires_v : Error<
11190-
"builtin requires 'V' extension support to be enabled">;
11188+
// RISC-V builtin required extension warning
11189+
def err_riscv_builtin_requires_extension : Error<
11190+
"builtin requires %0 extension support to be enabled">;
1119111191
} // end of sema component.

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17876,6 +17876,44 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
1787617876
llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes;
1787717877
switch (BuiltinID) {
1787817878
#include "clang/Basic/riscv_vector_builtin_cg.inc"
17879+
17880+
// Zbr
17881+
case RISCV::BI__builtin_riscv_crc32_b:
17882+
ID = Intrinsic::riscv_crc32_b;
17883+
IntrinsicTypes = {ResultType};
17884+
break;
17885+
case RISCV::BI__builtin_riscv_crc32_h:
17886+
ID = Intrinsic::riscv_crc32_h;
17887+
IntrinsicTypes = {ResultType};
17888+
break;
17889+
case RISCV::BI__builtin_riscv_crc32_w:
17890+
ID = Intrinsic::riscv_crc32_w;
17891+
IntrinsicTypes = {ResultType};
17892+
break;
17893+
case RISCV::BI__builtin_riscv_crc32_d:
17894+
ID = Intrinsic::riscv_crc32_d;
17895+
IntrinsicTypes = {ResultType};
17896+
break;
17897+
case RISCV::BI__builtin_riscv_crc32c_b:
17898+
ID = Intrinsic::riscv_crc32c_b;
17899+
IntrinsicTypes = {ResultType};
17900+
break;
17901+
case RISCV::BI__builtin_riscv_crc32c_h:
17902+
ID = Intrinsic::riscv_crc32c_h;
17903+
IntrinsicTypes = {ResultType};
17904+
break;
17905+
case RISCV::BI__builtin_riscv_crc32c_w:
17906+
ID = Intrinsic::riscv_crc32c_w;
17907+
IntrinsicTypes = {ResultType};
17908+
break;
17909+
case RISCV::BI__builtin_riscv_crc32c_d:
17910+
ID = Intrinsic::riscv_crc32c_d;
17911+
IntrinsicTypes = {ResultType};
17912+
break;
17913+
default: {
17914+
llvm_unreachable("unexpected builtin ID");
17915+
return nullptr;
17916+
} // default
1787917917
}
1788017918

1788117919
assert(ID != Intrinsic::not_intrinsic);

clang/lib/Sema/SemaChecking.cpp

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3415,13 +3415,27 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI,
34153415
CallExpr *TheCall) {
34163416
// CodeGenFunction can also detect this, but this gives a better error
34173417
// message.
3418+
bool FeatureMissing = false;
3419+
SmallVector<StringRef> ReqFeatures;
34183420
StringRef Features = Context.BuiltinInfo.getRequiredFeatures(BuiltinID);
3419-
if (Features.find("experimental-v") != StringRef::npos &&
3420-
!TI.hasFeature("experimental-v"))
3421-
return Diag(TheCall->getBeginLoc(), diag::err_riscvv_builtin_requires_v)
3422-
<< TheCall->getSourceRange();
3421+
Features.split(ReqFeatures, ',');
34233422

3424-
return false;
3423+
// Check if each required feature is included
3424+
for (auto &I : ReqFeatures) {
3425+
if (TI.hasFeature(I))
3426+
continue;
3427+
// Make message like "experimental-zbr" to "Zbr"
3428+
I.consume_front("experimental-");
3429+
std::string FeatureStr = I.str();
3430+
FeatureStr[0] = std::toupper(FeatureStr[0]);
3431+
3432+
// Error message
3433+
FeatureMissing = true;
3434+
Diag(TheCall->getBeginLoc(), diag::err_riscv_builtin_requires_extension)
3435+
<< TheCall->getSourceRange() << StringRef(FeatureStr);
3436+
}
3437+
3438+
return FeatureMissing;
34253439
}
34263440

34273441
bool Sema::CheckSystemZBuiltinFunctionCall(unsigned BuiltinID,
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
2+
// RUN: %clang_cc1 -triple riscv32 -target-feature +experimental-zbr -emit-llvm %s -o - \
3+
// RUN: | FileCheck %s -check-prefix=RV32ZBR
4+
5+
// RV32ZBR-LABEL: @crc32_b(
6+
// RV32ZBR-NEXT: entry:
7+
// RV32ZBR-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
8+
// RV32ZBR-NEXT: store i32 [[A:%.*]], i32* [[A_ADDR]], align 4
9+
// RV32ZBR-NEXT: [[TMP0:%.*]] = load i32, i32* [[A_ADDR]], align 4
10+
// RV32ZBR-NEXT: [[TMP1:%.*]] = call i32 @llvm.riscv.crc32.b.i32(i32 [[TMP0]])
11+
// RV32ZBR-NEXT: ret i32 [[TMP1]]
12+
//
13+
long crc32_b(long a) {
14+
return __builtin_riscv_crc32_b(a);
15+
}
16+
17+
// RV32ZBR-LABEL: @crc32_h(
18+
// RV32ZBR-NEXT: entry:
19+
// RV32ZBR-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
20+
// RV32ZBR-NEXT: store i32 [[A:%.*]], i32* [[A_ADDR]], align 4
21+
// RV32ZBR-NEXT: [[TMP0:%.*]] = load i32, i32* [[A_ADDR]], align 4
22+
// RV32ZBR-NEXT: [[TMP1:%.*]] = call i32 @llvm.riscv.crc32.h.i32(i32 [[TMP0]])
23+
// RV32ZBR-NEXT: ret i32 [[TMP1]]
24+
//
25+
long crc32_h(long a) {
26+
return __builtin_riscv_crc32_h(a);
27+
}
28+
29+
// RV32ZBR-LABEL: @crc32_w(
30+
// RV32ZBR-NEXT: entry:
31+
// RV32ZBR-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
32+
// RV32ZBR-NEXT: store i32 [[A:%.*]], i32* [[A_ADDR]], align 4
33+
// RV32ZBR-NEXT: [[TMP0:%.*]] = load i32, i32* [[A_ADDR]], align 4
34+
// RV32ZBR-NEXT: [[TMP1:%.*]] = call i32 @llvm.riscv.crc32.w.i32(i32 [[TMP0]])
35+
// RV32ZBR-NEXT: ret i32 [[TMP1]]
36+
//
37+
long crc32_w(long a) {
38+
return __builtin_riscv_crc32_w(a);
39+
}
40+
41+
// RV32ZBR-LABEL: @crc32c_b(
42+
// RV32ZBR-NEXT: entry:
43+
// RV32ZBR-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
44+
// RV32ZBR-NEXT: store i32 [[A:%.*]], i32* [[A_ADDR]], align 4
45+
// RV32ZBR-NEXT: [[TMP0:%.*]] = load i32, i32* [[A_ADDR]], align 4
46+
// RV32ZBR-NEXT: [[TMP1:%.*]] = call i32 @llvm.riscv.crc32c.b.i32(i32 [[TMP0]])
47+
// RV32ZBR-NEXT: ret i32 [[TMP1]]
48+
//
49+
long crc32c_b(long a) {
50+
return __builtin_riscv_crc32c_b(a);
51+
}
52+
53+
// RV32ZBR-LABEL: @crc32c_h(
54+
// RV32ZBR-NEXT: entry:
55+
// RV32ZBR-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
56+
// RV32ZBR-NEXT: store i32 [[A:%.*]], i32* [[A_ADDR]], align 4
57+
// RV32ZBR-NEXT: [[TMP0:%.*]] = load i32, i32* [[A_ADDR]], align 4
58+
// RV32ZBR-NEXT: [[TMP1:%.*]] = call i32 @llvm.riscv.crc32c.h.i32(i32 [[TMP0]])
59+
// RV32ZBR-NEXT: ret i32 [[TMP1]]
60+
//
61+
long crc32c_h(long a) {
62+
return __builtin_riscv_crc32c_h(a);
63+
}
64+
65+
// RV32ZBR-LABEL: @crc32c_w(
66+
// RV32ZBR-NEXT: entry:
67+
// RV32ZBR-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
68+
// RV32ZBR-NEXT: store i32 [[A:%.*]], i32* [[A_ADDR]], align 4
69+
// RV32ZBR-NEXT: [[TMP0:%.*]] = load i32, i32* [[A_ADDR]], align 4
70+
// RV32ZBR-NEXT: [[TMP1:%.*]] = call i32 @llvm.riscv.crc32c.w.i32(i32 [[TMP0]])
71+
// RV32ZBR-NEXT: ret i32 [[TMP1]]
72+
//
73+
long crc32c_w(long a) {
74+
return __builtin_riscv_crc32c_w(a);
75+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
2+
// RUN: %clang_cc1 -triple riscv64 -target-feature +experimental-zbr -emit-llvm %s -o - \
3+
// RUN: | FileCheck %s -check-prefix=RV64ZBR
4+
5+
// RV64ZBR-LABEL: @crc32_b(
6+
// RV64ZBR-NEXT: entry:
7+
// RV64ZBR-NEXT: [[A_ADDR:%.*]] = alloca i64, align 8
8+
// RV64ZBR-NEXT: store i64 [[A:%.*]], i64* [[A_ADDR]], align 8
9+
// RV64ZBR-NEXT: [[TMP0:%.*]] = load i64, i64* [[A_ADDR]], align 8
10+
// RV64ZBR-NEXT: [[TMP1:%.*]] = call i64 @llvm.riscv.crc32.b.i64(i64 [[TMP0]])
11+
// RV64ZBR-NEXT: ret i64 [[TMP1]]
12+
//
13+
long crc32_b(long a) {
14+
return __builtin_riscv_crc32_b(a);
15+
}
16+
17+
// RV64ZBR-LABEL: @crc32_h(
18+
// RV64ZBR-NEXT: entry:
19+
// RV64ZBR-NEXT: [[A_ADDR:%.*]] = alloca i64, align 8
20+
// RV64ZBR-NEXT: store i64 [[A:%.*]], i64* [[A_ADDR]], align 8
21+
// RV64ZBR-NEXT: [[TMP0:%.*]] = load i64, i64* [[A_ADDR]], align 8
22+
// RV64ZBR-NEXT: [[TMP1:%.*]] = call i64 @llvm.riscv.crc32.h.i64(i64 [[TMP0]])
23+
// RV64ZBR-NEXT: ret i64 [[TMP1]]
24+
//
25+
long crc32_h(long a) {
26+
return __builtin_riscv_crc32_h(a);
27+
}
28+
29+
// RV64ZBR-LABEL: @crc32_w(
30+
// RV64ZBR-NEXT: entry:
31+
// RV64ZBR-NEXT: [[A_ADDR:%.*]] = alloca i64, align 8
32+
// RV64ZBR-NEXT: store i64 [[A:%.*]], i64* [[A_ADDR]], align 8
33+
// RV64ZBR-NEXT: [[TMP0:%.*]] = load i64, i64* [[A_ADDR]], align 8
34+
// RV64ZBR-NEXT: [[TMP1:%.*]] = call i64 @llvm.riscv.crc32.w.i64(i64 [[TMP0]])
35+
// RV64ZBR-NEXT: ret i64 [[TMP1]]
36+
//
37+
long crc32_w(long a) {
38+
return __builtin_riscv_crc32_w(a);
39+
}
40+
41+
// RV64ZBR-LABEL: @crc32c_b(
42+
// RV64ZBR-NEXT: entry:
43+
// RV64ZBR-NEXT: [[A_ADDR:%.*]] = alloca i64, align 8
44+
// RV64ZBR-NEXT: store i64 [[A:%.*]], i64* [[A_ADDR]], align 8
45+
// RV64ZBR-NEXT: [[TMP0:%.*]] = load i64, i64* [[A_ADDR]], align 8
46+
// RV64ZBR-NEXT: [[TMP1:%.*]] = call i64 @llvm.riscv.crc32c.b.i64(i64 [[TMP0]])
47+
// RV64ZBR-NEXT: ret i64 [[TMP1]]
48+
//
49+
long crc32c_b(long a) {
50+
return __builtin_riscv_crc32c_b(a);
51+
}
52+
53+
// RV64ZBR-LABEL: @crc32c_h(
54+
// RV64ZBR-NEXT: entry:
55+
// RV64ZBR-NEXT: [[A_ADDR:%.*]] = alloca i64, align 8
56+
// RV64ZBR-NEXT: store i64 [[A:%.*]], i64* [[A_ADDR]], align 8
57+
// RV64ZBR-NEXT: [[TMP0:%.*]] = load i64, i64* [[A_ADDR]], align 8
58+
// RV64ZBR-NEXT: [[TMP1:%.*]] = call i64 @llvm.riscv.crc32c.h.i64(i64 [[TMP0]])
59+
// RV64ZBR-NEXT: ret i64 [[TMP1]]
60+
//
61+
long crc32c_h(long a) {
62+
return __builtin_riscv_crc32c_h(a);
63+
}
64+
65+
// RV64ZBR-LABEL: @crc32c_w(
66+
// RV64ZBR-NEXT: entry:
67+
// RV64ZBR-NEXT: [[A_ADDR:%.*]] = alloca i64, align 8
68+
// RV64ZBR-NEXT: store i64 [[A:%.*]], i64* [[A_ADDR]], align 8
69+
// RV64ZBR-NEXT: [[TMP0:%.*]] = load i64, i64* [[A_ADDR]], align 8
70+
// RV64ZBR-NEXT: [[TMP1:%.*]] = call i64 @llvm.riscv.crc32c.w.i64(i64 [[TMP0]])
71+
// RV64ZBR-NEXT: ret i64 [[TMP1]]
72+
//
73+
long crc32c_w(long a) {
74+
return __builtin_riscv_crc32c_w(a);
75+
}
76+
77+
// RV64ZBR-LABEL: @crc32_d(
78+
// RV64ZBR-NEXT: entry:
79+
// RV64ZBR-NEXT: [[A_ADDR:%.*]] = alloca i64, align 8
80+
// RV64ZBR-NEXT: store i64 [[A:%.*]], i64* [[A_ADDR]], align 8
81+
// RV64ZBR-NEXT: [[TMP0:%.*]] = load i64, i64* [[A_ADDR]], align 8
82+
// RV64ZBR-NEXT: [[TMP1:%.*]] = call i64 @llvm.riscv.crc32.d.i64(i64 [[TMP0]])
83+
// RV64ZBR-NEXT: ret i64 [[TMP1]]
84+
//
85+
long crc32_d(long a) {
86+
return __builtin_riscv_crc32_d(a);
87+
}
88+
89+
// RV64ZBR-LABEL: @crc32c_d(
90+
// RV64ZBR-NEXT: entry:
91+
// RV64ZBR-NEXT: [[A_ADDR:%.*]] = alloca i64, align 8
92+
// RV64ZBR-NEXT: store i64 [[A:%.*]], i64* [[A_ADDR]], align 8
93+
// RV64ZBR-NEXT: [[TMP0:%.*]] = load i64, i64* [[A_ADDR]], align 8
94+
// RV64ZBR-NEXT: [[TMP1:%.*]] = call i64 @llvm.riscv.crc32c.d.i64(i64 [[TMP0]])
95+
// RV64ZBR-NEXT: ret i64 [[TMP1]]
96+
//
97+
long crc32c_d(long a) {
98+
return __builtin_riscv_crc32c_d(a);
99+
}

llvm/include/llvm/IR/IntrinsicsRISCV.td

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,28 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
//===----------------------------------------------------------------------===//
14+
// RISC-V Bitmanip (Bit Manipulation) Extension
15+
// Zbr extension part
16+
17+
let TargetPrefix = "riscv" in {
18+
19+
class BitMan_GPR_Intrinsics
20+
: Intrinsic<[llvm_any_ty],
21+
[LLVMMatchType<0>],
22+
[IntrNoMem, IntrSpeculatable, IntrWillReturn]>;
23+
24+
def int_riscv_crc32_b : BitMan_GPR_Intrinsics;
25+
def int_riscv_crc32_h : BitMan_GPR_Intrinsics;
26+
def int_riscv_crc32_w : BitMan_GPR_Intrinsics;
27+
def int_riscv_crc32_d : BitMan_GPR_Intrinsics;
28+
def int_riscv_crc32c_b : BitMan_GPR_Intrinsics;
29+
def int_riscv_crc32c_h : BitMan_GPR_Intrinsics;
30+
def int_riscv_crc32c_w : BitMan_GPR_Intrinsics;
31+
def int_riscv_crc32c_d : BitMan_GPR_Intrinsics;
32+
33+
} // TargetPrefix = "riscv"
34+
1335
//===----------------------------------------------------------------------===//
1436
// Atomics
1537

llvm/lib/Target/RISCV/RISCVInstrInfo.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,8 @@ def : InstAlias<"zext.b $rd, $rs", (ANDI GPR:$rd, GPR:$rs, 0xFF), 0>;
819819

820820
/// Generic pattern classes
821821

822+
class PatGpr<SDPatternOperator OpNode, RVInst Inst>
823+
: Pat<(OpNode GPR:$rs1), (Inst GPR:$rs1)>;
822824
class PatGprGpr<SDPatternOperator OpNode, RVInst Inst>
823825
: Pat<(OpNode GPR:$rs1, GPR:$rs2), (Inst GPR:$rs1, GPR:$rs2)>;
824826
class PatGprSimm12<SDPatternOperator OpNode, RVInstI Inst>

llvm/lib/Target/RISCV/RISCVInstrInfoB.td

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -893,3 +893,17 @@ def : Pat<(i64 (or (and (assertsexti32 GPR:$rs2), 0xFFFFFFFFFFFF0000),
893893
(srl (and GPR:$rs1, 0xFFFFFFFF), (i64 16)))),
894894
(PACKUW GPR:$rs1, GPR:$rs2)>;
895895
} // Predicates = [HasStdExtZbp, IsRV64]
896+
897+
let Predicates = [HasStdExtZbr] in {
898+
def : PatGpr<int_riscv_crc32_b, CRC32B>;
899+
def : PatGpr<int_riscv_crc32_h, CRC32H>;
900+
def : PatGpr<int_riscv_crc32_w, CRC32W>;
901+
def : PatGpr<int_riscv_crc32c_b, CRC32CB>;
902+
def : PatGpr<int_riscv_crc32c_h, CRC32CH>;
903+
def : PatGpr<int_riscv_crc32c_w, CRC32CW>;
904+
} // Predicates = [HasStdExtZbr]
905+
906+
let Predicates = [HasStdExtZbr, IsRV64] in {
907+
def : PatGpr<int_riscv_crc32_d, CRC32D>;
908+
def : PatGpr<int_riscv_crc32c_d, CRC32CD>;
909+
} // Predicates = [HasStdExtZbr, IsRV64]

0 commit comments

Comments
 (0)