HsiangKai created this revision.
HsiangKai added reviewers: kito-cheng, craig.topper, frasercrmck, rogfer01.
Herald added subscribers: achieveartificialintelligence, StephenFan, vkmr,
evandro, luismarques, apazos, sameer.abuasal, s.egerton, Jim, benna, psnobl,
jocewei, PkmX, the_o, brucehoult, MartinMosbeck, edward-jones, zzheng, jrtc27,
shiva0217, niosHD, sabuasal, simoncook, johnrusso, rbar, asb.
Herald added a reviewer: aaron.ballman.
HsiangKai requested review of this revision.
Herald added subscribers: cfe-commits, MaskRay.
Herald added a project: clang.
This patch provides a proof-of-concept implementation of the proposal.
https://github.com/riscv-non-isa/rvv-intrinsic-doc/issues/120
In this patch, we create a new attribute rvv_policy to annotate C
intrinsics with its tail/inactive elements policy. The syntax is
__attribute__((rvv_policy(tama)))
vint32m1_t vadd_tama(...);
The possible policy is tama, tamu, tuma, tumu.
ta: tail agnostic
tu: tail undisturbed
ma: inactive masked-off agnostic
mu: inactive masked-off undisturbed
This attribute is used in riscv_vector.h.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D112534
Files:
clang/include/clang/Basic/Attr.td
clang/include/clang/Basic/AttrDocs.td
clang/lib/CodeGen/CGBuiltin.cpp
clang/lib/Sema/SemaDeclAttr.cpp
clang/test/CodeGen/RISCV/rvv-intrinsics/vadd-policy.c
clang/test/CodeGen/RISCV/rvv-intrinsics/vadd-tu.c
clang/utils/TableGen/RISCVVEmitter.cpp
Index: clang/utils/TableGen/RISCVVEmitter.cpp
===================================================================
--- clang/utils/TableGen/RISCVVEmitter.cpp
+++ clang/utils/TableGen/RISCVVEmitter.cpp
@@ -204,6 +204,10 @@
// Emit the macros for mapping C/C++ intrinsic function to builtin functions.
void emitIntrinsicFuncDef(raw_ostream &o) const;
+ // Emit the declarations for mapping C/C++ intrinsic function to builtin
+ // functions.
+ void emitIntrinsicWithPolicyFuncDef(raw_ostream &o) const;
+
// Emit the mangled function definition.
void emitMangledFuncDef(raw_ostream &o) const;
};
@@ -835,9 +839,28 @@
if (isMask()) {
if (hasVL()) {
OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);\n";
- if (hasPolicy())
- OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType(),"
- " TAIL_UNDISTURBED));\n";
+ if (hasPolicy()) {
+ OS << " if (PolicyAttr) {\n";
+ OS << " switch (PolicyAttr->getPolicy()) {\n";
+ OS << " default:\n";
+ OS << " PolicyValue = 0;\n";
+ OS << " break;\n";
+ OS << " case RISCVVPolicyAttr::TAMU:\n";
+ OS << " PolicyValue = TAIL_AGNOSTIC;\n";
+ OS << " break;\n";
+ OS << " case RISCVVPolicyAttr::TUMA:\n";
+ OS << " PolicyValue = MASK_AGNOSTIC;\n";
+ OS << " break;\n";
+ OS << " case RISCVVPolicyAttr::TAMA:\n";
+ OS << " PolicyValue = MASK_AGNOSTIC | TAIL_AGNOSTIC;\n";
+ OS << " break;\n";
+ OS << " }\n";
+ OS << " } else {\n";
+ OS << " PolicyValue = 0;\n";
+ OS << " }\n";
+ OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType(), "
+ "PolicyValue));\n";
+ }
} else {
OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end());\n";
}
@@ -873,6 +896,30 @@
OS << ");\n";
}
+void RVVIntrinsic::emitIntrinsicWithPolicyFuncDef(raw_ostream &OS) const {
+ if (!isMask())
+ return;
+
+ const char *policySuffix[] = {"tumu", "tamu", "tuma", "tama"};
+
+ for (unsigned i = 0; i < 4; ++i) {
+ OS << "__rvv_ai ";
+ OS << "__attribute__((__clang_builtin_alias__(";
+ OS << "__builtin_rvv_" << getBuiltinName() << ")))\n";
+ OS << "__attribute__((rvv_policy(" << policySuffix[i] << ")))\n";
+ StringRef IntrinsicName = getName().substr(0, getName().size() - 2);
+ OS << OutputType->getTypeStr() << " " << IntrinsicName << "_"
+ << policySuffix[i] << "(";
+ // Emit function arguments
+ if (!InputTypes.empty()) {
+ ListSeparator LS;
+ for (unsigned i = 0; i < InputTypes.size(); ++i)
+ OS << LS << InputTypes[i]->getTypeStr();
+ }
+ OS << ");\n";
+ }
+}
+
void RVVIntrinsic::emitMangledFuncDef(raw_ostream &OS) const {
OS << "__attribute__((__clang_builtin_alias__(";
OS << "__builtin_rvv_" << getBuiltinName() << ")))\n";
@@ -989,6 +1036,10 @@
Inst.emitIntrinsicFuncDef(OS);
});
+ emitArchMacroAndBody(Defs, OS, [](raw_ostream &OS, const RVVIntrinsic &Inst) {
+ Inst.emitIntrinsicWithPolicyFuncDef(OS);
+ });
+
OS << "#undef __rvv_ai\n\n";
OS << "#define __riscv_v_intrinsic_overloading 1\n";
Index: clang/test/CodeGen/RISCV/rvv-intrinsics/vadd-tu.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/RISCV/rvv-intrinsics/vadd-tu.c
@@ -0,0 +1,24 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
+// REQUIRES: riscv-registered-target
+// RUN: %clang_cc1 -triple riscv64 -target-feature +f -target-feature +d -target-feature +experimental-v \
+// RUN: -target-feature +experimental-zfh -disable-O0-optnone -emit-llvm %s -o - | opt -S -mem2reg | FileCheck --check-prefix=CHECK-RV64 %s
+
+#include <riscv_vector.h>
+
+// CHECK-RV64-LABEL: @test_vadd_vv_i8m1_tu(
+// CHECK-RV64-NEXT: entry:
+// CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 8 x i8> @llvm.riscv.vadd.tu.nxv8i8.nxv8i8.i64(<vscale x 8 x i8> [[DEST:%.*]], <vscale x 8 x i8> [[OP1:%.*]], <vscale x 8 x i8> [[OP2:%.*]], i64 [[VL:%.*]])
+// CHECK-RV64-NEXT: ret <vscale x 8 x i8> [[TMP0]]
+//
+vint8m1_t test_vadd_vv_i8m1_tu(vint8m1_t dest, vint8m1_t op1, vint8m1_t op2, size_t vl) {
+ return vadd_vv_i8m1_tu(dest, op1, op2, vl);
+}
+
+// CHECK-RV64-LABEL: @test_vadd_vx_i8m1_tu(
+// CHECK-RV64-NEXT: entry:
+// CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 8 x i8> @llvm.riscv.vadd.tu.nxv8i8.i8.i64(<vscale x 8 x i8> [[DEST:%.*]], <vscale x 8 x i8> [[OP1:%.*]], i8 [[OP2:%.*]], i64 [[VL:%.*]])
+// CHECK-RV64-NEXT: ret <vscale x 8 x i8> [[TMP0]]
+//
+vint8m1_t test_vadd_vx_i8m1_tu(vint8m1_t dest, vint8m1_t op1, int8_t op2, size_t vl) {
+ return vadd_vx_i8m1_tu(dest, op1, op2, vl);
+}
Index: clang/test/CodeGen/RISCV/rvv-intrinsics/vadd-policy.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/RISCV/rvv-intrinsics/vadd-policy.c
@@ -0,0 +1,42 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
+// REQUIRES: riscv-registered-target
+// RUN: %clang_cc1 -triple riscv64 -target-feature +f -target-feature +d -target-feature +experimental-v \
+// RUN: -target-feature +experimental-zfh -disable-O0-optnone -emit-llvm %s -o - | opt -S -mem2reg | FileCheck --check-prefix=CHECK-RV64 %s
+
+#include <riscv_vector.h>
+
+// CHECK-RV64-LABEL: @test_vadd_vv_i8m1_tama(
+// CHECK-RV64-NEXT: entry:
+// CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 8 x i8> @llvm.riscv.vadd.mask.nxv8i8.nxv8i8.i64(<vscale x 8 x i8> [[MASKEDOFF:%.*]], <vscale x 8 x i8> [[OP1:%.*]], <vscale x 8 x i8> [[OP2:%.*]], <vscale x 8 x i1> [[MASK:%.*]], i64 [[VL:%.*]], i64 3)
+// CHECK-RV64-NEXT: ret <vscale x 8 x i8> [[TMP0]]
+//
+vint8m1_t test_vadd_vv_i8m1_tama(vbool8_t mask, vint8m1_t maskedoff, vint8m1_t op1, vint8m1_t op2, size_t vl) {
+ return vadd_vv_i8m1_tama(mask, maskedoff, op1, op2, vl);
+}
+
+// CHECK-RV64-LABEL: @test_vadd_vv_i8m1_tamu(
+// CHECK-RV64-NEXT: entry:
+// CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 8 x i8> @llvm.riscv.vadd.mask.nxv8i8.nxv8i8.i64(<vscale x 8 x i8> [[MASKEDOFF:%.*]], <vscale x 8 x i8> [[OP1:%.*]], <vscale x 8 x i8> [[OP2:%.*]], <vscale x 8 x i1> [[MASK:%.*]], i64 [[VL:%.*]], i64 1)
+// CHECK-RV64-NEXT: ret <vscale x 8 x i8> [[TMP0]]
+//
+vint8m1_t test_vadd_vv_i8m1_tamu(vbool8_t mask, vint8m1_t maskedoff, vint8m1_t op1, vint8m1_t op2, size_t vl) {
+ return vadd_vv_i8m1_tamu(mask, maskedoff, op1, op2, vl);
+}
+
+// CHECK-RV64-LABEL: @test_vadd_vv_i8m1_tuma(
+// CHECK-RV64-NEXT: entry:
+// CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 8 x i8> @llvm.riscv.vadd.mask.nxv8i8.nxv8i8.i64(<vscale x 8 x i8> [[MASKEDOFF:%.*]], <vscale x 8 x i8> [[OP1:%.*]], <vscale x 8 x i8> [[OP2:%.*]], <vscale x 8 x i1> [[MASK:%.*]], i64 [[VL:%.*]], i64 2)
+// CHECK-RV64-NEXT: ret <vscale x 8 x i8> [[TMP0]]
+//
+vint8m1_t test_vadd_vv_i8m1_tuma(vbool8_t mask, vint8m1_t maskedoff, vint8m1_t op1, vint8m1_t op2, size_t vl) {
+ return vadd_vv_i8m1_tuma(mask, maskedoff, op1, op2, vl);
+}
+
+// CHECK-RV64-LABEL: @test_vadd_vv_i8m1_tumu(
+// CHECK-RV64-NEXT: entry:
+// CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 8 x i8> @llvm.riscv.vadd.mask.nxv8i8.nxv8i8.i64(<vscale x 8 x i8> [[MASKEDOFF:%.*]], <vscale x 8 x i8> [[OP1:%.*]], <vscale x 8 x i8> [[OP2:%.*]], <vscale x 8 x i1> [[MASK:%.*]], i64 [[VL:%.*]], i64 0)
+// CHECK-RV64-NEXT: ret <vscale x 8 x i8> [[TMP0]]
+//
+vint8m1_t test_vadd_vv_i8m1_tumu(vbool8_t mask, vint8m1_t maskedoff, vint8m1_t op1, vint8m1_t op2, size_t vl) {
+ return vadd_vv_i8m1_tumu(mask, maskedoff, op1, op2, vl);
+}
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -5369,6 +5369,23 @@
D->addAttr(::new (S.Context) BuiltinAliasAttr(S.Context, AL, Ident));
}
+static void handleRISCVVPolicyAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ if (!AL.isArgIdent(0)) {
+ S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
+ << AL << 0 << AANT_ArgumentIdentifier;
+ return;
+ }
+
+ RISCVVPolicyAttr::PolicyType Policy;
+ IdentifierInfo *II = AL.getArgAsIdent(0)->Ident;
+ if (!RISCVVPolicyAttr::ConvertStrToPolicyType(II->getName(), Policy)) {
+ S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << II;
+ return;
+ }
+
+ D->addAttr(::new (S.Context) RISCVVPolicyAttr(S.Context, AL, Policy));
+}
+
//===----------------------------------------------------------------------===//
// Checker-specific attribute handlers.
//===----------------------------------------------------------------------===//
@@ -8520,6 +8537,10 @@
case ParsedAttr::AT_UsingIfExists:
handleSimpleAttribute<UsingIfExistsAttr>(S, D, AL);
break;
+
+ case ParsedAttr::AT_RISCVVPolicy:
+ handleRISCVVPolicyAttr(S, D, AL);
+ break;
}
}
Index: clang/lib/CodeGen/CGBuiltin.cpp
===================================================================
--- clang/lib/CodeGen/CGBuiltin.cpp
+++ clang/lib/CodeGen/CGBuiltin.cpp
@@ -18608,6 +18608,10 @@
Intrinsic::ID ID = Intrinsic::not_intrinsic;
unsigned NF = 1;
constexpr unsigned TAIL_UNDISTURBED = 0;
+ constexpr unsigned TAIL_AGNOSTIC = 0b01;
+ constexpr unsigned MASK_AGNOSTIC = 0b10;
+ auto *PolicyAttr = E->getCalleeDecl()->getAttr<RISCVVPolicyAttr>();
+ size_t PolicyValue;
// Required for overloaded intrinsics.
llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes;
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -2143,6 +2143,19 @@
}];
}
+def RISCVVPolicyDocs : Documentation {
+ let Category = DocCatFunction;
+ let Heading = "RISC-V vector tail/mask policy";
+ let Content = [{
+Users could use the attribute to specify the policy of destination tail and
+destination inactive masked-off elements in the vector operations. There are
+two kinds of policies described in the vector specification. One is undisturbed.
+It will retain the value they previously held. Another is agnostic. It will
+retain the value they previously held or are overwritten with 1s. It is intended
+for use only inside ``riscv_*.h``.
+ }];
+}
+
def AVRInterruptDocs : Documentation {
let Category = DocCatFunction;
let Heading = "interrupt (AVR)";
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -1783,6 +1783,15 @@
let Documentation = [RISCVInterruptDocs];
}
+def RISCVVPolicy : InheritableAttr, TargetSpecificAttr<TargetRISCV> {
+ let Spellings = [Clang<"rvv_policy">];
+ let Subjects = SubjectList<[Function]>;
+ let Args = [EnumArgument<"Policy", "PolicyType",
+ ["tumu", "tamu", "tuma", "tama"],
+ ["TUMU", "TAMU", "TUMA", "TAMA"]>];
+ let Documentation = [RISCVVPolicyDocs];
+}
+
// This is not a TargetSpecificAttr so that is silently accepted and
// ignored on other targets as encouraged by the OpenCL spec.
//
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits