aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/utils/TableGen
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/utils/TableGen')
-rw-r--r--contrib/llvm-project/clang/utils/TableGen/ASTTableGen.cpp7
-rw-r--r--contrib/llvm-project/clang/utils/TableGen/ASTTableGen.h1
-rw-r--r--contrib/llvm-project/clang/utils/TableGen/ClangASTNodesEmitter.cpp107
-rw-r--r--contrib/llvm-project/clang/utils/TableGen/ClangASTPropertiesEmitter.cpp39
-rw-r--r--contrib/llvm-project/clang/utils/TableGen/ClangAttrEmitter.cpp1280
-rw-r--r--contrib/llvm-project/clang/utils/TableGen/ClangCommentCommandInfoEmitter.cpp20
-rw-r--r--contrib/llvm-project/clang/utils/TableGen/ClangCommentHTMLNamedCharacterReferenceEmitter.cpp6
-rw-r--r--contrib/llvm-project/clang/utils/TableGen/ClangCommentHTMLTagsEmitter.cpp5
-rw-r--r--contrib/llvm-project/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp83
-rw-r--r--contrib/llvm-project/clang/utils/TableGen/ClangOpcodesEmitter.cpp198
-rw-r--r--contrib/llvm-project/clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp355
-rw-r--r--contrib/llvm-project/clang/utils/TableGen/ClangOptionDocEmitter.cpp89
-rw-r--r--contrib/llvm-project/clang/utils/TableGen/ClangSACheckersEmitter.cpp45
-rw-r--r--contrib/llvm-project/clang/utils/TableGen/ClangSyntaxEmitter.cpp4
-rw-r--r--contrib/llvm-project/clang/utils/TableGen/ClangTypeNodesEmitter.cpp2
-rw-r--r--contrib/llvm-project/clang/utils/TableGen/MveEmitter.cpp49
-rw-r--r--contrib/llvm-project/clang/utils/TableGen/NeonEmitter.cpp261
-rw-r--r--contrib/llvm-project/clang/utils/TableGen/RISCVVEmitter.cpp1538
-rw-r--r--contrib/llvm-project/clang/utils/TableGen/SveEmitter.cpp710
-rw-r--r--contrib/llvm-project/clang/utils/TableGen/TableGen.cpp116
-rw-r--r--contrib/llvm-project/clang/utils/TableGen/TableGenBackends.h27
21 files changed, 3038 insertions, 1904 deletions
diff --git a/contrib/llvm-project/clang/utils/TableGen/ASTTableGen.cpp b/contrib/llvm-project/clang/utils/TableGen/ASTTableGen.cpp
index 3f6da40964e0..54288ff6a03b 100644
--- a/contrib/llvm-project/clang/utils/TableGen/ASTTableGen.cpp
+++ b/contrib/llvm-project/clang/utils/TableGen/ASTTableGen.cpp
@@ -15,6 +15,7 @@
#include "ASTTableGen.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/Error.h"
+#include <optional>
using namespace llvm;
using namespace clang;
@@ -32,7 +33,7 @@ llvm::StringRef clang::tblgen::HasProperties::getName() const {
static StringRef removeExpectedNodeNameSuffix(Record *node, StringRef suffix) {
StringRef nodeName = node->getName();
- if (!nodeName.endswith(suffix)) {
+ if (!nodeName.ends_with(suffix)) {
PrintFatalError(node->getLoc(),
Twine("name of node doesn't end in ") + suffix);
}
@@ -81,7 +82,7 @@ void PropertyType::emitCXXValueTypeName(bool forRead, raw_ostream &out) const {
elementType.emitCXXValueTypeName(forRead, out);
out << ">";
} else if (auto valueType = getOptionalElementType()) {
- out << "llvm::Optional<";
+ out << "std::optional<";
valueType.emitCXXValueTypeName(forRead, out);
out << ">";
} else {
@@ -107,7 +108,7 @@ static void visitASTNodeRecursive(ASTNode node, ASTNode base,
static void visitHierarchy(RecordKeeper &records,
StringRef nodeClassName,
ASTNodeHierarchyVisitor<ASTNode> visit) {
- // Check for the node class, just as a sanity check.
+ // Check for the node class, just as a basic correctness check.
if (!records.getClass(nodeClassName)) {
PrintFatalError(Twine("cannot find definition for node class ")
+ nodeClassName);
diff --git a/contrib/llvm-project/clang/utils/TableGen/ASTTableGen.h b/contrib/llvm-project/clang/utils/TableGen/ASTTableGen.h
index ab9429f3feee..41f78a6a3bbc 100644
--- a/contrib/llvm-project/clang/utils/TableGen/ASTTableGen.h
+++ b/contrib/llvm-project/clang/utils/TableGen/ASTTableGen.h
@@ -11,6 +11,7 @@
#include "llvm/TableGen/Record.h"
#include "llvm/ADT/STLExtras.h"
+#include <optional>
// These are spellings in the tblgen files.
diff --git a/contrib/llvm-project/clang/utils/TableGen/ClangASTNodesEmitter.cpp b/contrib/llvm-project/clang/utils/TableGen/ClangASTNodesEmitter.cpp
index 2b8d7a9efdf1..07ddafce3291 100644
--- a/contrib/llvm-project/clang/utils/TableGen/ClangASTNodesEmitter.cpp
+++ b/contrib/llvm-project/clang/utils/TableGen/ClangASTNodesEmitter.cpp
@@ -33,6 +33,7 @@ class ClangASTNodesEmitter {
typedef std::multimap<ASTNode, ASTNode> ChildMap;
typedef ChildMap::const_iterator ChildIterator;
+ std::set<ASTNode> PrioritizedClasses;
RecordKeeper &Records;
ASTNode Root;
const std::string &NodeClassName;
@@ -70,8 +71,16 @@ class ClangASTNodesEmitter {
std::pair<ASTNode, ASTNode> EmitNode(raw_ostream& OS, ASTNode Base);
public:
explicit ClangASTNodesEmitter(RecordKeeper &R, const std::string &N,
- const std::string &S)
- : Records(R), NodeClassName(N), BaseSuffix(S) {}
+ const std::string &S,
+ std::string_view PriorizeIfSubclassOf)
+ : Records(R), NodeClassName(N), BaseSuffix(S) {
+ auto vecPrioritized =
+ PriorizeIfSubclassOf.empty()
+ ? std::vector<Record *>{}
+ : R.getAllDerivedDefinitions(PriorizeIfSubclassOf);
+ PrioritizedClasses =
+ std::set<ASTNode>(vecPrioritized.begin(), vecPrioritized.end());
+ }
// run - Output the .inc file contents
void run(raw_ostream &OS);
@@ -95,8 +104,23 @@ std::pair<ASTNode, ASTNode> ClangASTNodesEmitter::EmitNode(raw_ostream &OS,
if (!Base.isAbstract())
First = Last = Base;
+ auto comp = [this](ASTNode LHS, ASTNode RHS) {
+ auto LHSPrioritized = PrioritizedClasses.count(LHS) > 0;
+ auto RHSPrioritized = PrioritizedClasses.count(RHS) > 0;
+ if (LHSPrioritized && !RHSPrioritized)
+ return true;
+ if (!LHSPrioritized && RHSPrioritized)
+ return false;
+
+ return LHS.getName() > RHS.getName();
+ };
+ auto SortedChildren = std::set<ASTNode, decltype(comp)>(comp);
+
for (; i != e; ++i) {
- ASTNode Child = i->second;
+ SortedChildren.insert(i->second);
+ }
+
+ for (const auto &Child : SortedChildren) {
bool Abstract = Child.isAbstract();
std::string NodeName = macroName(std::string(Child.getName()));
@@ -148,9 +172,7 @@ void ClangASTNodesEmitter::deriveChildTree() {
const std::vector<Record*> Stmts
= Records.getAllDerivedDefinitions(NodeClassName);
- for (unsigned i = 0, e = Stmts.size(); i != e; ++i) {
- Record *R = Stmts[i];
-
+ for (auto *R : Stmts) {
if (auto B = R->getValueAsOptionalDef(BaseFieldName))
Tree.insert(std::make_pair(B, R));
else if (Root)
@@ -169,7 +191,7 @@ void ClangASTNodesEmitter::deriveChildTree() {
void ClangASTNodesEmitter::run(raw_ostream &OS) {
deriveChildTree();
- emitSourceFileHeader("List of AST nodes of a particular kind", OS);
+ emitSourceFileHeader("List of AST nodes of a particular kind", OS, Records);
// Write the preamble
OS << "#ifndef ABSTRACT_" << macroHierarchyName() << "\n";
@@ -182,9 +204,9 @@ void ClangASTNodesEmitter::run(raw_ostream &OS) {
OS << "#endif\n\n";
OS << "#ifndef LAST_" << macroHierarchyName() << "_RANGE\n";
- OS << "# define LAST_"
- << macroHierarchyName() << "_RANGE(Base, First, Last) "
- << macroHierarchyName() << "_RANGE(Base, First, Last)\n";
+ OS << "# define LAST_" << macroHierarchyName()
+ << "_RANGE(Base, First, Last) " << macroHierarchyName()
+ << "_RANGE(Base, First, Last)\n";
OS << "#endif\n\n";
EmitNode(OS, Root);
@@ -196,8 +218,20 @@ void ClangASTNodesEmitter::run(raw_ostream &OS) {
}
void clang::EmitClangASTNodes(RecordKeeper &RK, raw_ostream &OS,
- const std::string &N, const std::string &S) {
- ClangASTNodesEmitter(RK, N, S).run(OS);
+ const std::string &N, const std::string &S,
+ std::string_view PriorizeIfSubclassOf) {
+ ClangASTNodesEmitter(RK, N, S, PriorizeIfSubclassOf).run(OS);
+}
+
+void printDeclContext(const std::multimap<Record *, Record *> &Tree,
+ Record *DeclContext, raw_ostream &OS) {
+ if (!DeclContext->getValueAsBit(AbstractFieldName))
+ OS << "DECL_CONTEXT(" << DeclContext->getName() << ")\n";
+ auto i = Tree.lower_bound(DeclContext);
+ auto end = Tree.upper_bound(DeclContext);
+ for (; i != end; ++i) {
+ printDeclContext(Tree, i->second, OS);
+ }
}
// Emits and addendum to a .inc file to enumerate the clang declaration
@@ -205,43 +239,30 @@ void clang::EmitClangASTNodes(RecordKeeper &RK, raw_ostream &OS,
void clang::EmitClangDeclContext(RecordKeeper &Records, raw_ostream &OS) {
// FIXME: Find a .td file format to allow for this to be represented better.
- emitSourceFileHeader("List of AST Decl nodes", OS);
+ emitSourceFileHeader("List of AST Decl nodes", OS, Records);
OS << "#ifndef DECL_CONTEXT\n";
OS << "# define DECL_CONTEXT(DECL)\n";
OS << "#endif\n";
-
- OS << "#ifndef DECL_CONTEXT_BASE\n";
- OS << "# define DECL_CONTEXT_BASE(DECL) DECL_CONTEXT(DECL)\n";
- OS << "#endif\n";
-
- typedef std::set<Record*> RecordSet;
- typedef std::vector<Record*> RecordVector;
-
- RecordVector DeclContextsVector
- = Records.getAllDerivedDefinitions(DeclContextNodeClassName);
- RecordVector Decls = Records.getAllDerivedDefinitions(DeclNodeClassName);
- RecordSet DeclContexts (DeclContextsVector.begin(), DeclContextsVector.end());
-
- for (RecordVector::iterator i = Decls.begin(), e = Decls.end(); i != e; ++i) {
- Record *R = *i;
-
- if (Record *B = R->getValueAsOptionalDef(BaseFieldName)) {
- if (DeclContexts.find(B) != DeclContexts.end()) {
- OS << "DECL_CONTEXT_BASE(" << B->getName() << ")\n";
- DeclContexts.erase(B);
- }
- }
+
+ std::vector<Record *> DeclContextsVector =
+ Records.getAllDerivedDefinitions(DeclContextNodeClassName);
+ std::vector<Record *> Decls =
+ Records.getAllDerivedDefinitions(DeclNodeClassName);
+
+ std::multimap<Record *, Record *> Tree;
+
+ const std::vector<Record *> Stmts =
+ Records.getAllDerivedDefinitions(DeclNodeClassName);
+
+ for (auto *R : Stmts) {
+ if (auto *B = R->getValueAsOptionalDef(BaseFieldName))
+ Tree.insert(std::make_pair(B, R));
}
- // To keep identical order, RecordVector may be used
- // instead of RecordSet.
- for (RecordVector::iterator
- i = DeclContextsVector.begin(), e = DeclContextsVector.end();
- i != e; ++i)
- if (DeclContexts.find(*i) != DeclContexts.end())
- OS << "DECL_CONTEXT(" << (*i)->getName() << ")\n";
+ for (auto *DeclContext : DeclContextsVector) {
+ printDeclContext(Tree, DeclContext, OS);
+ }
OS << "#undef DECL_CONTEXT\n";
- OS << "#undef DECL_CONTEXT_BASE\n";
}
diff --git a/contrib/llvm-project/clang/utils/TableGen/ClangASTPropertiesEmitter.cpp b/contrib/llvm-project/clang/utils/TableGen/ClangASTPropertiesEmitter.cpp
index caced02e1e11..de8dda60681f 100644
--- a/contrib/llvm-project/clang/utils/TableGen/ClangASTPropertiesEmitter.cpp
+++ b/contrib/llvm-project/clang/utils/TableGen/ClangASTPropertiesEmitter.cpp
@@ -20,6 +20,7 @@
#include "llvm/TableGen/TableGenBackend.h"
#include <cctype>
#include <map>
+#include <optional>
#include <set>
#include <string>
using namespace llvm;
@@ -455,7 +456,7 @@ void ASTPropsEmitter::emitPropertiedReaderWriterBody(HasProperties node,
// Emit code to read all the properties.
visitAllProperties(node, nodeInfo, [&](Property prop) {
// Verify that the creation code refers to this property.
- if (info.IsReader && creationCode.find(prop.getName()) == StringRef::npos)
+ if (info.IsReader && !creationCode.contains(prop.getName()))
PrintFatalError(nodeInfo.Creator.getLoc(),
"creation code for " + node.getName()
+ " doesn't refer to property \""
@@ -525,7 +526,8 @@ void ASTPropsEmitter::emitReadOfProperty(StringRef readerName,
// get a pr-value back from read(), and we should be able to forward
// that in the creation rule.
Out << " ";
- if (!condition.empty()) Out << "llvm::Optional<";
+ if (!condition.empty())
+ Out << "std::optional<";
type.emitCXXValueTypeName(true, Out);
if (!condition.empty()) Out << ">";
Out << " " << name;
@@ -591,7 +593,7 @@ void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName,
template <class NodeClass>
static void emitASTReader(RecordKeeper &records, raw_ostream &out,
StringRef description) {
- emitSourceFileHeader(description, out);
+ emitSourceFileHeader(description, out, records);
ASTPropsEmitter(records, out).emitNodeReaderClass<NodeClass>();
}
@@ -605,7 +607,7 @@ void clang::EmitClangTypeReader(RecordKeeper &records, raw_ostream &out) {
template <class NodeClass>
static void emitASTWriter(RecordKeeper &records, raw_ostream &out,
StringRef description) {
- emitSourceFileHeader(description, out);
+ emitSourceFileHeader(description, out, records);
ASTPropsEmitter(records, out).emitNodeWriterClass<NodeClass>();
}
@@ -662,9 +664,7 @@ ASTPropsEmitter::emitDispatcherTemplate(const ReaderWriterInfo &info) {
declareSpecialization("<class T>",
"llvm::ArrayRef<T>",
"Array");
- declareSpecialization("<class T>",
- "llvm::Optional<T>",
- "Optional");
+ declareSpecialization("<class T>", "std::optional<T>", "Optional");
Out << "\n";
}
@@ -677,15 +677,20 @@ ASTPropsEmitter::emitPackUnpackOptionalTemplate(const ReaderWriterInfo &info) {
Out << "template <class ValueType>\n"
"struct " << classPrefix << "OptionalValue;\n";
- auto declareSpecialization = [&](const Twine &typeName,
- StringRef code) {
+ auto declareSpecialization = [&](const Twine &typeName, StringRef code) {
Out << "template <>\n"
- "struct " << classPrefix << "OptionalValue<" << typeName << "> {\n"
- " static " << (info.IsReader ? "Optional<" : "") << typeName
- << (info.IsReader ? "> " : " ") << methodName << "("
- << (info.IsReader ? "" : "Optional<") << typeName
- << (info.IsReader ? "" : ">") << " value) {\n"
- " return " << code << ";\n"
+ "struct "
+ << classPrefix << "OptionalValue<" << typeName
+ << "> {\n"
+ " static "
+ << (info.IsReader ? "std::optional<" : "") << typeName
+ << (info.IsReader ? "> " : " ") << methodName << "("
+ << (info.IsReader ? "" : "std::optional<") << typeName
+ << (info.IsReader ? "" : ">")
+ << " value) {\n"
+ " return "
+ << code
+ << ";\n"
" }\n"
"};\n";
};
@@ -847,7 +852,7 @@ void ASTPropsEmitter::emitBasicReaderWriterFile(const ReaderWriterInfo &info) {
/// Emit an .inc file that defines some helper classes for reading
/// basic values.
void clang::EmitClangBasicReader(RecordKeeper &records, raw_ostream &out) {
- emitSourceFileHeader("Helper classes for BasicReaders", out);
+ emitSourceFileHeader("Helper classes for BasicReaders", out, records);
// Use any property, we won't be using those properties.
auto info = ReaderWriterInfo::forReader<TypeNode>();
@@ -857,7 +862,7 @@ void clang::EmitClangBasicReader(RecordKeeper &records, raw_ostream &out) {
/// Emit an .inc file that defines some helper classes for writing
/// basic values.
void clang::EmitClangBasicWriter(RecordKeeper &records, raw_ostream &out) {
- emitSourceFileHeader("Helper classes for BasicWriters", out);
+ emitSourceFileHeader("Helper classes for BasicWriters", out, records);
// Use any property, we won't be using those properties.
auto info = ReaderWriterInfo::forWriter<TypeNode>();
diff --git a/contrib/llvm-project/clang/utils/TableGen/ClangAttrEmitter.cpp b/contrib/llvm-project/clang/utils/TableGen/ClangAttrEmitter.cpp
index d679d58aaef1..89b88e386f25 100644
--- a/contrib/llvm-project/clang/utils/TableGen/ClangAttrEmitter.cpp
+++ b/contrib/llvm-project/clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -16,6 +16,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
@@ -36,6 +37,7 @@
#include <cstdint>
#include <map>
#include <memory>
+#include <optional>
#include <set>
#include <sstream>
#include <string>
@@ -49,17 +51,21 @@ namespace {
class FlattenedSpelling {
std::string V, N, NS;
bool K = false;
+ const Record &OriginalSpelling;
public:
FlattenedSpelling(const std::string &Variety, const std::string &Name,
- const std::string &Namespace, bool KnownToGCC) :
- V(Variety), N(Name), NS(Namespace), K(KnownToGCC) {}
+ const std::string &Namespace, bool KnownToGCC,
+ const Record &OriginalSpelling)
+ : V(Variety), N(Name), NS(Namespace), K(KnownToGCC),
+ OriginalSpelling(OriginalSpelling) {}
explicit FlattenedSpelling(const Record &Spelling)
: V(std::string(Spelling.getValueAsString("Variety"))),
- N(std::string(Spelling.getValueAsString("Name"))) {
+ N(std::string(Spelling.getValueAsString("Name"))),
+ OriginalSpelling(Spelling) {
assert(V != "GCC" && V != "Clang" &&
"Given a GCC spelling, which means this hasn't been flattened!");
- if (V == "CXX11" || V == "C2x" || V == "Pragma")
+ if (V == "CXX11" || V == "C23" || V == "Pragma")
NS = std::string(Spelling.getValueAsString("Namespace"));
}
@@ -67,6 +73,7 @@ public:
const std::string &name() const { return N; }
const std::string &nameSpace() const { return NS; }
bool knownToGCC() const { return K; }
+ const Record &getSpellingRecord() const { return OriginalSpelling; }
};
} // end anonymous namespace
@@ -80,15 +87,15 @@ GetFlattenedSpellings(const Record &Attr) {
StringRef Variety = Spelling->getValueAsString("Variety");
StringRef Name = Spelling->getValueAsString("Name");
if (Variety == "GCC") {
- Ret.emplace_back("GNU", std::string(Name), "", true);
- Ret.emplace_back("CXX11", std::string(Name), "gnu", true);
+ Ret.emplace_back("GNU", std::string(Name), "", true, *Spelling);
+ Ret.emplace_back("CXX11", std::string(Name), "gnu", true, *Spelling);
if (Spelling->getValueAsBit("AllowInC"))
- Ret.emplace_back("C2x", std::string(Name), "gnu", true);
+ Ret.emplace_back("C23", std::string(Name), "gnu", true, *Spelling);
} else if (Variety == "Clang") {
- Ret.emplace_back("GNU", std::string(Name), "", false);
- Ret.emplace_back("CXX11", std::string(Name), "clang", false);
+ Ret.emplace_back("GNU", std::string(Name), "", false, *Spelling);
+ Ret.emplace_back("CXX11", std::string(Name), "clang", false, *Spelling);
if (Spelling->getValueAsBit("AllowInC"))
- Ret.emplace_back("C2x", std::string(Name), "clang", false);
+ Ret.emplace_back("C23", std::string(Name), "clang", false, *Spelling);
} else
Ret.push_back(FlattenedSpelling(*Spelling));
}
@@ -154,7 +161,7 @@ static StringRef NormalizeNameForSpellingComparison(StringRef Name) {
// Normalize the spelling of a GNU attribute (i.e. "x" in "__attribute__((x))"),
// removing "__" if it appears at the beginning and end of the attribute's name.
static StringRef NormalizeGNUAttrSpelling(StringRef AttrSpelling) {
- if (AttrSpelling.startswith("__") && AttrSpelling.endswith("__")) {
+ if (AttrSpelling.starts_with("__") && AttrSpelling.ends_with("__")) {
AttrSpelling = AttrSpelling.substr(2, AttrSpelling.size() - 4);
}
@@ -201,9 +208,9 @@ namespace {
bool Fake;
public:
- Argument(const Record &Arg, StringRef Attr)
- : lowerName(std::string(Arg.getValueAsString("Name"))),
- upperName(lowerName), attrName(Attr), isOpt(false), Fake(false) {
+ Argument(StringRef Arg, StringRef Attr)
+ : lowerName(std::string(Arg)), upperName(lowerName), attrName(Attr),
+ isOpt(false), Fake(false) {
if (!lowerName.empty()) {
lowerName[0] = std::tolower(lowerName[0]);
upperName[0] = std::toupper(upperName[0]);
@@ -214,6 +221,8 @@ namespace {
if (lowerName == "interface")
lowerName = "interface_";
}
+ Argument(const Record &Arg, StringRef Attr)
+ : Argument(Arg.getValueAsString("Name"), Attr) {}
virtual ~Argument() = default;
StringRef getLowerName() const { return lowerName; }
@@ -311,12 +320,19 @@ namespace {
}
std::string getIsOmitted() const override {
- if (type == "IdentifierInfo *")
+ auto IsOneOf = [](StringRef subject, auto... list) {
+ return ((subject == list) || ...);
+ };
+
+ if (IsOneOf(type, "IdentifierInfo *", "Expr *"))
return "!get" + getUpperName().str() + "()";
- if (type == "TypeSourceInfo *")
+ if (IsOneOf(type, "TypeSourceInfo *"))
return "!get" + getUpperName().str() + "Loc()";
- if (type == "ParamIdx")
+ if (IsOneOf(type, "ParamIdx"))
return "!get" + getUpperName().str() + "().isValid()";
+
+ assert(IsOneOf(type, "unsigned", "int", "bool", "FunctionDecl *",
+ "VarDecl *"));
return "false";
}
@@ -340,7 +356,7 @@ namespace {
}
void writeDump(raw_ostream &OS) const override {
- if (StringRef(type).endswith("Decl *")) {
+ if (StringRef(type).ends_with("Decl *")) {
OS << " OS << \" \";\n";
OS << " dumpBareDeclRef(SA->get" << getUpperName() << "());\n";
} else if (type == "IdentifierInfo *") {
@@ -499,6 +515,16 @@ namespace {
OS << " assert(!is" << getLowerName() << "Expr);\n";
OS << " return " << getLowerName() << "Type;\n";
OS << " }";
+
+ OS << " std::optional<unsigned> getCached" << getUpperName()
+ << "Value() const {\n";
+ OS << " return " << getLowerName() << "Cache;\n";
+ OS << " }";
+
+ OS << " void setCached" << getUpperName()
+ << "Value(unsigned AlignVal) {\n";
+ OS << " " << getLowerName() << "Cache = AlignVal;\n";
+ OS << " }";
}
void writeAccessorDefinitions(raw_ostream &OS) const override {
@@ -521,21 +547,6 @@ namespace {
OS << " return " << getLowerName()
<< "Type->getType()->containsErrors();\n";
OS << "}\n";
-
- // FIXME: Do not do the calculation here
- // FIXME: Handle types correctly
- // A null pointer means maximum alignment
- OS << "unsigned " << getAttrName() << "Attr::get" << getUpperName()
- << "(ASTContext &Ctx) const {\n";
- OS << " assert(!is" << getUpperName() << "Dependent());\n";
- OS << " if (is" << getLowerName() << "Expr)\n";
- OS << " return " << getLowerName() << "Expr ? " << getLowerName()
- << "Expr->EvaluateKnownConstInt(Ctx).getZExtValue()"
- << " * Ctx.getCharWidth() : "
- << "Ctx.getTargetDefaultAlignForAttributeAligned();\n";
- OS << " else\n";
- OS << " return 0; // FIXME\n";
- OS << "}\n";
}
void writeASTVisitorTraversal(raw_ostream &OS) const override {
@@ -592,7 +603,8 @@ namespace {
OS << "union {\n";
OS << "Expr *" << getLowerName() << "Expr;\n";
OS << "TypeSourceInfo *" << getLowerName() << "Type;\n";
- OS << "};";
+ OS << "};\n";
+ OS << "std::optional<unsigned> " << getLowerName() << "Cache;\n";
}
void writePCHReadArgs(raw_ostream &OS) const override {
@@ -619,14 +631,21 @@ namespace {
}
std::string getIsOmitted() const override {
- return "!is" + getLowerName().str() + "Expr || !" + getLowerName().str()
- + "Expr";
+ return "!((is" + getLowerName().str() + "Expr && " +
+ getLowerName().str() + "Expr) || (!is" + getLowerName().str() +
+ "Expr && " + getLowerName().str() + "Type))";
}
void writeValue(raw_ostream &OS) const override {
OS << "\";\n";
- OS << " " << getLowerName()
+ OS << " if (is" << getLowerName() << "Expr && " << getLowerName()
+ << "Expr)";
+ OS << " " << getLowerName()
<< "Expr->printPretty(OS, nullptr, Policy);\n";
+ OS << " if (!is" << getLowerName() << "Expr && " << getLowerName()
+ << "Type)";
+ OS << " " << getLowerName()
+ << "Type->getType().print(OS, Policy);\n";
OS << " OS << \"";
}
@@ -665,6 +684,11 @@ namespace {
ArgName(getLowerName().str() + "_"), ArgSizeName(ArgName + "Size"),
RangeName(std::string(getLowerName())) {}
+ VariadicArgument(StringRef Arg, StringRef Attr, std::string T)
+ : Argument(Arg, Attr), Type(std::move(T)),
+ ArgName(getLowerName().str() + "_"), ArgSizeName(ArgName + "Size"),
+ RangeName(std::string(getLowerName())) {}
+
const std::string &getType() const { return Type; }
const std::string &getArgName() const { return ArgName; }
const std::string &getArgSizeName() const { return ArgSizeName; }
@@ -687,6 +711,18 @@ namespace {
<< "); }\n";
}
+ void writeSetter(raw_ostream &OS) const {
+ OS << " void set" << getUpperName() << "(ASTContext &Ctx, ";
+ writeCtorParameters(OS);
+ OS << ") {\n";
+ OS << " " << ArgSizeName << " = " << getUpperName() << "Size;\n";
+ OS << " " << ArgName << " = new (Ctx, 16) " << getType() << "["
+ << ArgSizeName << "];\n";
+ OS << " ";
+ writeCtorBody(OS);
+ OS << " }\n";
+ }
+
void writeCloneArgs(raw_ostream &OS) const override {
OS << ArgName << ", " << ArgSizeName;
}
@@ -786,6 +822,49 @@ namespace {
}
};
+ class VariadicOMPInteropInfoArgument : public VariadicArgument {
+ public:
+ VariadicOMPInteropInfoArgument(const Record &Arg, StringRef Attr)
+ : VariadicArgument(Arg, Attr, "OMPInteropInfo") {}
+
+ void writeDump(raw_ostream &OS) const override {
+ OS << " for (" << getAttrName() << "Attr::" << getLowerName()
+ << "_iterator I = SA->" << getLowerName() << "_begin(), E = SA->"
+ << getLowerName() << "_end(); I != E; ++I) {\n";
+ OS << " if (I->IsTarget && I->IsTargetSync)\n";
+ OS << " OS << \" Target_TargetSync\";\n";
+ OS << " else if (I->IsTarget)\n";
+ OS << " OS << \" Target\";\n";
+ OS << " else\n";
+ OS << " OS << \" TargetSync\";\n";
+ OS << " }\n";
+ }
+
+ void writePCHReadDecls(raw_ostream &OS) const override {
+ OS << " unsigned " << getLowerName() << "Size = Record.readInt();\n";
+ OS << " SmallVector<OMPInteropInfo, 4> " << getLowerName() << ";\n";
+ OS << " " << getLowerName() << ".reserve(" << getLowerName()
+ << "Size);\n";
+ OS << " for (unsigned I = 0, E = " << getLowerName() << "Size; ";
+ OS << "I != E; ++I) {\n";
+ OS << " bool IsTarget = Record.readBool();\n";
+ OS << " bool IsTargetSync = Record.readBool();\n";
+ OS << " " << getLowerName()
+ << ".emplace_back(IsTarget, IsTargetSync);\n";
+ OS << " }\n";
+ }
+
+ void writePCHWrite(raw_ostream &OS) const override {
+ OS << " Record.push_back(SA->" << getLowerName() << "_size());\n";
+ OS << " for (" << getAttrName() << "Attr::" << getLowerName()
+ << "_iterator I = SA->" << getLowerName() << "_begin(), E = SA->"
+ << getLowerName() << "_end(); I != E; ++I) {\n";
+ OS << " Record.writeBool(I->IsTarget);\n";
+ OS << " Record.writeBool(I->IsTargetSync);\n";
+ OS << " }\n";
+ }
+ };
+
class VariadicParamIdxArgument : public VariadicArgument {
public:
VariadicParamIdxArgument(const Record &Arg, StringRef Attr)
@@ -819,15 +898,25 @@ namespace {
}
class EnumArgument : public Argument {
- std::string type;
+ std::string fullType;
+ StringRef shortType;
std::vector<StringRef> values, enums, uniques;
+ bool isExternal;
public:
EnumArgument(const Record &Arg, StringRef Attr)
- : Argument(Arg, Attr), type(std::string(Arg.getValueAsString("Type"))),
- values(Arg.getValueAsListOfStrings("Values")),
+ : Argument(Arg, Attr), values(Arg.getValueAsListOfStrings("Values")),
enums(Arg.getValueAsListOfStrings("Enums")),
- uniques(uniqueEnumsInOrder(enums)) {
+ uniques(uniqueEnumsInOrder(enums)),
+ isExternal(Arg.getValueAsBit("IsExternalType")) {
+ StringRef Type = Arg.getValueAsString("Type");
+ shortType = isExternal ? Type.rsplit("::").second : Type;
+ // If shortType didn't contain :: at all rsplit will give us an empty
+ // string.
+ if (shortType.empty())
+ shortType = Type;
+ fullType = isExternal ? Type : (getAttrName() + "Attr::" + Type).str();
+
// FIXME: Emit a proper error
assert(!uniques.empty());
}
@@ -835,7 +924,7 @@ namespace {
bool isEnumArg() const override { return true; }
void writeAccessors(raw_ostream &OS) const override {
- OS << " " << type << " get" << getUpperName() << "() const {\n";
+ OS << " " << fullType << " get" << getUpperName() << "() const {\n";
OS << " return " << getLowerName() << ";\n";
OS << " }";
}
@@ -851,30 +940,32 @@ namespace {
OS << getLowerName() << "(" << getUpperName() << ")";
}
void writeCtorDefaultInitializers(raw_ostream &OS) const override {
- OS << getLowerName() << "(" << type << "(0))";
+ OS << getLowerName() << "(" << fullType << "(0))";
}
void writeCtorParameters(raw_ostream &OS) const override {
- OS << type << " " << getUpperName();
+ OS << fullType << " " << getUpperName();
}
void writeDeclarations(raw_ostream &OS) const override {
- auto i = uniques.cbegin(), e = uniques.cend();
- // The last one needs to not have a comma.
- --e;
+ if (!isExternal) {
+ auto i = uniques.cbegin(), e = uniques.cend();
+ // The last one needs to not have a comma.
+ --e;
+
+ OS << "public:\n";
+ OS << " enum " << shortType << " {\n";
+ for (; i != e; ++i)
+ OS << " " << *i << ",\n";
+ OS << " " << *e << "\n";
+ OS << " };\n";
+ }
- OS << "public:\n";
- OS << " enum " << type << " {\n";
- for (; i != e; ++i)
- OS << " " << *i << ",\n";
- OS << " " << *e << "\n";
- OS << " };\n";
OS << "private:\n";
- OS << " " << type << " " << getLowerName() << ";";
+ OS << " " << fullType << " " << getLowerName() << ";";
}
void writePCHReadDecls(raw_ostream &OS) const override {
- OS << " " << getAttrName() << "Attr::" << type << " " << getLowerName()
- << "(static_cast<" << getAttrName() << "Attr::" << type
- << ">(Record.readInt()));\n";
+ OS << " " << fullType << " " << getLowerName() << "(static_cast<"
+ << fullType << ">(Record.readInt()));\n";
}
void writePCHReadArgs(raw_ostream &OS) const override {
@@ -882,45 +973,50 @@ namespace {
}
void writePCHWrite(raw_ostream &OS) const override {
- OS << "Record.push_back(SA->get" << getUpperName() << "());\n";
+ OS << "Record.push_back(static_cast<uint64_t>(SA->get" << getUpperName()
+ << "()));\n";
}
void writeValue(raw_ostream &OS) const override {
// FIXME: this isn't 100% correct -- some enum arguments require printing
// as a string literal, while others require printing as an identifier.
// Tablegen currently does not distinguish between the two forms.
- OS << "\\\"\" << " << getAttrName() << "Attr::Convert" << type << "ToStr(get"
- << getUpperName() << "()) << \"\\\"";
+ OS << "\\\"\" << " << getAttrName() << "Attr::Convert" << shortType
+ << "ToStr(get" << getUpperName() << "()) << \"\\\"";
}
void writeDump(raw_ostream &OS) const override {
OS << " switch(SA->get" << getUpperName() << "()) {\n";
for (const auto &I : uniques) {
- OS << " case " << getAttrName() << "Attr::" << I << ":\n";
+ OS << " case " << fullType << "::" << I << ":\n";
OS << " OS << \" " << I << "\";\n";
OS << " break;\n";
}
+ if (isExternal) {
+ OS << " default:\n";
+ OS << " llvm_unreachable(\"Invalid attribute value\");\n";
+ }
OS << " }\n";
}
void writeConversion(raw_ostream &OS, bool Header) const {
if (Header) {
- OS << " static bool ConvertStrTo" << type << "(StringRef Val, " << type
- << " &Out);\n";
- OS << " static const char *Convert" << type << "ToStr(" << type
- << " Val);\n";
+ OS << " static bool ConvertStrTo" << shortType << "(StringRef Val, "
+ << fullType << " &Out);\n";
+ OS << " static const char *Convert" << shortType << "ToStr("
+ << fullType << " Val);\n";
return;
}
- OS << "bool " << getAttrName() << "Attr::ConvertStrTo" << type
- << "(StringRef Val, " << type << " &Out) {\n";
- OS << " Optional<" << type << "> R = llvm::StringSwitch<Optional<";
- OS << type << ">>(Val)\n";
+ OS << "bool " << getAttrName() << "Attr::ConvertStrTo" << shortType
+ << "(StringRef Val, " << fullType << " &Out) {\n";
+ OS << " std::optional<" << fullType << "> "
+ << "R = llvm::StringSwitch<std::optional<" << fullType << ">>(Val)\n";
for (size_t I = 0; I < enums.size(); ++I) {
OS << " .Case(\"" << values[I] << "\", ";
- OS << getAttrName() << "Attr::" << enums[I] << ")\n";
+ OS << fullType << "::" << enums[I] << ")\n";
}
- OS << " .Default(Optional<" << type << ">());\n";
+ OS << " .Default(std::optional<" << fullType << ">());\n";
OS << " if (R) {\n";
OS << " Out = *R;\n return true;\n }\n";
OS << " return false;\n";
@@ -930,14 +1026,17 @@ namespace {
// trivial because some enumeration values have multiple named
// enumerators, such as type_visibility(internal) and
// type_visibility(hidden) both mapping to TypeVisibilityAttr::Hidden.
- OS << "const char *" << getAttrName() << "Attr::Convert" << type
- << "ToStr(" << type << " Val) {\n"
+ OS << "const char *" << getAttrName() << "Attr::Convert" << shortType
+ << "ToStr(" << fullType << " Val) {\n"
<< " switch(Val) {\n";
SmallDenseSet<StringRef, 8> Uniques;
for (size_t I = 0; I < enums.size(); ++I) {
if (Uniques.insert(enums[I]).second)
- OS << " case " << getAttrName() << "Attr::" << enums[I]
- << ": return \"" << values[I] << "\";\n";
+ OS << " case " << fullType << "::" << enums[I] << ": return \""
+ << values[I] << "\";\n";
+ }
+ if (isExternal) {
+ OS << " default: llvm_unreachable(\"Invalid attribute value\");\n";
}
OS << " }\n"
<< " llvm_unreachable(\"No enumerator with that value\");\n"
@@ -946,27 +1045,36 @@ namespace {
};
class VariadicEnumArgument: public VariadicArgument {
- std::string type, QualifiedTypeName;
+ std::string fullType;
+ StringRef shortType;
std::vector<StringRef> values, enums, uniques;
+ bool isExternal;
protected:
void writeValueImpl(raw_ostream &OS) const override {
// FIXME: this isn't 100% correct -- some enum arguments require printing
// as a string literal, while others require printing as an identifier.
// Tablegen currently does not distinguish between the two forms.
- OS << " OS << \"\\\"\" << " << getAttrName() << "Attr::Convert" << type
- << "ToStr(Val)" << "<< \"\\\"\";\n";
+ OS << " OS << \"\\\"\" << " << getAttrName() << "Attr::Convert"
+ << shortType << "ToStr(Val)"
+ << "<< \"\\\"\";\n";
}
public:
VariadicEnumArgument(const Record &Arg, StringRef Attr)
: VariadicArgument(Arg, Attr,
std::string(Arg.getValueAsString("Type"))),
- type(std::string(Arg.getValueAsString("Type"))),
values(Arg.getValueAsListOfStrings("Values")),
enums(Arg.getValueAsListOfStrings("Enums")),
- uniques(uniqueEnumsInOrder(enums)) {
- QualifiedTypeName = getAttrName().str() + "Attr::" + type;
+ uniques(uniqueEnumsInOrder(enums)),
+ isExternal(Arg.getValueAsBit("IsExternalType")) {
+ StringRef Type = Arg.getValueAsString("Type");
+ shortType = isExternal ? Type.rsplit("::").second : Type;
+ // If shortType didn't contain :: at all rsplit will give us an empty
+ // string.
+ if (shortType.empty())
+ shortType = Type;
+ fullType = isExternal ? Type : (getAttrName() + "Attr::" + Type).str();
// FIXME: Emit a proper error
assert(!uniques.empty());
@@ -975,16 +1083,18 @@ namespace {
bool isVariadicEnumArg() const override { return true; }
void writeDeclarations(raw_ostream &OS) const override {
- auto i = uniques.cbegin(), e = uniques.cend();
- // The last one needs to not have a comma.
- --e;
-
- OS << "public:\n";
- OS << " enum " << type << " {\n";
- for (; i != e; ++i)
- OS << " " << *i << ",\n";
- OS << " " << *e << "\n";
- OS << " };\n";
+ if (!isExternal) {
+ auto i = uniques.cbegin(), e = uniques.cend();
+ // The last one needs to not have a comma.
+ --e;
+
+ OS << "public:\n";
+ OS << " enum " << shortType << " {\n";
+ for (; i != e; ++i)
+ OS << " " << *i << ",\n";
+ OS << " " << *e << "\n";
+ OS << " };\n";
+ }
OS << "private:\n";
VariadicArgument::writeDeclarations(OS);
@@ -996,7 +1106,7 @@ namespace {
<< getLowerName() << "_end(); I != E; ++I) {\n";
OS << " switch(*I) {\n";
for (const auto &UI : uniques) {
- OS << " case " << getAttrName() << "Attr::" << UI << ":\n";
+ OS << " case " << fullType << "::" << UI << ":\n";
OS << " OS << \" " << UI << "\";\n";
OS << " break;\n";
}
@@ -1006,13 +1116,13 @@ namespace {
void writePCHReadDecls(raw_ostream &OS) const override {
OS << " unsigned " << getLowerName() << "Size = Record.readInt();\n";
- OS << " SmallVector<" << QualifiedTypeName << ", 4> " << getLowerName()
+ OS << " SmallVector<" << fullType << ", 4> " << getLowerName()
<< ";\n";
OS << " " << getLowerName() << ".reserve(" << getLowerName()
<< "Size);\n";
OS << " for (unsigned i = " << getLowerName() << "Size; i; --i)\n";
- OS << " " << getLowerName() << ".push_back(" << "static_cast<"
- << QualifiedTypeName << ">(Record.readInt()));\n";
+ OS << " " << getLowerName() << ".push_back("
+ << "static_cast<" << fullType << ">(Record.readInt()));\n";
}
void writePCHWrite(raw_ostream &OS) const override {
@@ -1020,41 +1130,42 @@ namespace {
OS << " for (" << getAttrName() << "Attr::" << getLowerName()
<< "_iterator i = SA->" << getLowerName() << "_begin(), e = SA->"
<< getLowerName() << "_end(); i != e; ++i)\n";
- OS << " " << WritePCHRecord(QualifiedTypeName, "(*i)");
+ OS << " " << WritePCHRecord(fullType, "(*i)");
}
void writeConversion(raw_ostream &OS, bool Header) const {
if (Header) {
- OS << " static bool ConvertStrTo" << type << "(StringRef Val, " << type
- << " &Out);\n";
- OS << " static const char *Convert" << type << "ToStr(" << type
- << " Val);\n";
+ OS << " static bool ConvertStrTo" << shortType << "(StringRef Val, "
+ << fullType << " &Out);\n";
+ OS << " static const char *Convert" << shortType << "ToStr("
+ << fullType << " Val);\n";
return;
}
- OS << "bool " << getAttrName() << "Attr::ConvertStrTo" << type
+ OS << "bool " << getAttrName() << "Attr::ConvertStrTo" << shortType
<< "(StringRef Val, ";
- OS << type << " &Out) {\n";
- OS << " Optional<" << type << "> R = llvm::StringSwitch<Optional<";
- OS << type << ">>(Val)\n";
+ OS << fullType << " &Out) {\n";
+ OS << " std::optional<" << fullType
+ << "> R = llvm::StringSwitch<std::optional<";
+ OS << fullType << ">>(Val)\n";
for (size_t I = 0; I < enums.size(); ++I) {
OS << " .Case(\"" << values[I] << "\", ";
- OS << getAttrName() << "Attr::" << enums[I] << ")\n";
+ OS << fullType << "::" << enums[I] << ")\n";
}
- OS << " .Default(Optional<" << type << ">());\n";
+ OS << " .Default(std::optional<" << fullType << ">());\n";
OS << " if (R) {\n";
OS << " Out = *R;\n return true;\n }\n";
OS << " return false;\n";
OS << "}\n\n";
- OS << "const char *" << getAttrName() << "Attr::Convert" << type
- << "ToStr(" << type << " Val) {\n"
+ OS << "const char *" << getAttrName() << "Attr::Convert" << shortType
+ << "ToStr(" << fullType << " Val) {\n"
<< " switch(Val) {\n";
SmallDenseSet<StringRef, 8> Uniques;
for (size_t I = 0; I < enums.size(); ++I) {
if (Uniques.insert(enums[I]).second)
- OS << " case " << getAttrName() << "Attr::" << enums[I]
- << ": return \"" << values[I] << "\";\n";
+ OS << " case " << fullType << "::" << enums[I] << ": return \""
+ << values[I] << "\";\n";
}
OS << " }\n"
<< " llvm_unreachable(\"No enumerator with that value\");\n"
@@ -1153,6 +1264,13 @@ namespace {
OS << " }\n";
}
+ void writeValue(raw_ostream &OS) const override {
+ OS << "\";\n";
+ OS << " get" << getUpperName()
+ << "()->printPretty(OS, nullptr, Policy);\n";
+ OS << " OS << \"";
+ }
+
void writeDump(raw_ostream &OS) const override {}
void writeDumpChildren(raw_ostream &OS) const override {
@@ -1168,6 +1286,9 @@ namespace {
: VariadicArgument(Arg, Attr, "Expr *")
{}
+ VariadicExprArgument(StringRef ArgName, StringRef Attr)
+ : VariadicArgument(ArgName, Attr, "Expr *") {}
+
void writeASTVisitorTraversal(raw_ostream &OS) const override {
OS << " {\n";
OS << " " << getType() << " *I = A->" << getLowerName()
@@ -1293,7 +1414,29 @@ namespace {
}
};
-} // end anonymous namespace
+ class WrappedAttr : public SimpleArgument {
+ public:
+ WrappedAttr(const Record &Arg, StringRef Attr)
+ : SimpleArgument(Arg, Attr, "Attr *") {}
+
+ void writePCHReadDecls(raw_ostream &OS) const override {
+ OS << " Attr *" << getLowerName() << " = Record.readAttr();";
+ }
+
+ void writePCHWrite(raw_ostream &OS) const override {
+ OS << " AddAttr(SA->get" << getUpperName() << "());";
+ }
+
+ void writeDump(raw_ostream &OS) const override {}
+
+ void writeDumpChildren(raw_ostream &OS) const override {
+ OS << " Visit(SA->get" << getUpperName() << "());\n";
+ }
+
+ void writeHasChildren(raw_ostream &OS) const override { OS << "true"; }
+ };
+
+ } // end anonymous namespace
static std::unique_ptr<Argument>
createArgument(const Record &Arg, StringRef Attr,
@@ -1349,8 +1492,12 @@ createArgument(const Record &Arg, StringRef Attr,
Ptr = std::make_unique<VariadicIdentifierArgument>(Arg, Attr);
else if (ArgName == "VersionArgument")
Ptr = std::make_unique<VersionArgument>(Arg, Attr);
+ else if (ArgName == "WrappedAttr")
+ Ptr = std::make_unique<WrappedAttr>(Arg, Attr);
else if (ArgName == "OMPTraitInfoArgument")
Ptr = std::make_unique<SimpleArgument>(Arg, Attr, "OMPTraitInfo *");
+ else if (ArgName == "VariadicOMPInteropInfoArgument")
+ Ptr = std::make_unique<VariadicOMPInteropInfoArgument>(Arg, Attr);
if (!Ptr) {
// Search in reverse order so that the most-derived type is handled first.
@@ -1445,7 +1592,7 @@ writePrettyPrintFunction(const Record &R,
if (Variety == "GNU") {
Prefix = " __attribute__((";
Suffix = "))";
- } else if (Variety == "CXX11" || Variety == "C2x") {
+ } else if (Variety == "CXX11" || Variety == "C23") {
Prefix = " [[";
Suffix = "]]";
std::string Namespace = Spellings[I].nameSpace();
@@ -1470,6 +1617,9 @@ writePrettyPrintFunction(const Record &R,
Spelling += Namespace;
Spelling += " ";
}
+ } else if (Variety == "HLSLSemantic") {
+ Prefix = ":";
+ Suffix = "";
} else {
llvm_unreachable("Unknown attribute syntax variety!");
}
@@ -1499,12 +1649,10 @@ writePrettyPrintFunction(const Record &R,
// To avoid printing parentheses around an empty argument list or
// printing spurious commas at the end of an argument list, we need to
// determine where the last provided non-fake argument is.
- unsigned NonFakeArgs = 0;
bool FoundNonOptArg = false;
for (const auto &arg : llvm::reverse(Args)) {
if (arg->isFake())
continue;
- ++NonFakeArgs;
if (FoundNonOptArg)
continue;
// FIXME: arg->getIsOmitted() == "false" means we haven't implemented
@@ -1598,8 +1746,7 @@ SpellingNamesAreCommon(const std::vector<FlattenedSpelling>& Spellings) {
assert(!Spellings.empty() && "An empty list of spellings was provided");
std::string FirstName =
std::string(NormalizeNameForSpellingComparison(Spellings.front().name()));
- for (const auto &Spelling :
- llvm::make_range(std::next(Spellings.begin()), Spellings.end())) {
+ for (const auto &Spelling : llvm::drop_begin(Spellings)) {
std::string Name =
std::string(NormalizeNameForSpellingComparison(Spelling.name()));
if (Name != FirstName)
@@ -1772,7 +1919,7 @@ struct AttributeSubjectMatchRule {
}
if (isAbstractRule())
Result += "_abstract";
- return std::string(Result.str());
+ return std::string(Result);
}
std::string getEnumValue() const { return "attr::" + getEnumValueName(); }
@@ -1969,7 +2116,7 @@ bool PragmaClangAttributeSupport::isAttributedSupported(
for (const auto *Subject : Subjects) {
if (!isSupportedPragmaClangAttributeSubject(*Subject))
continue;
- if (SubjectsToRules.find(Subject) == SubjectsToRules.end())
+ if (!SubjectsToRules.contains(Subject))
return false;
HasAtLeastOneValidSubject = true;
}
@@ -2038,12 +2185,12 @@ PragmaClangAttributeSupport::generateStrictConformsTo(const Record &Attr,
void PragmaClangAttributeSupport::generateParsingHelpers(raw_ostream &OS) {
// Generate routines that check the names of sub-rules.
- OS << "Optional<attr::SubjectMatchRule> "
+ OS << "std::optional<attr::SubjectMatchRule> "
"defaultIsAttributeSubjectMatchSubRuleFor(StringRef, bool) {\n";
- OS << " return None;\n";
+ OS << " return std::nullopt;\n";
OS << "}\n\n";
- std::map<const Record *, std::vector<AttributeSubjectMatchRule>>
+ llvm::MapVector<const Record *, std::vector<AttributeSubjectMatchRule>>
SubMatchRules;
for (const auto &Rule : Rules) {
if (!Rule.isSubRule())
@@ -2052,36 +2199,37 @@ void PragmaClangAttributeSupport::generateParsingHelpers(raw_ostream &OS) {
}
for (const auto &SubMatchRule : SubMatchRules) {
- OS << "Optional<attr::SubjectMatchRule> isAttributeSubjectMatchSubRuleFor_"
+ OS << "std::optional<attr::SubjectMatchRule> "
+ "isAttributeSubjectMatchSubRuleFor_"
<< SubMatchRule.first->getValueAsString("Name")
<< "(StringRef Name, bool IsUnless) {\n";
OS << " if (IsUnless)\n";
OS << " return "
- "llvm::StringSwitch<Optional<attr::SubjectMatchRule>>(Name).\n";
+ "llvm::StringSwitch<std::optional<attr::SubjectMatchRule>>(Name).\n";
for (const auto &Rule : SubMatchRule.second) {
if (Rule.isNegatedSubRule())
OS << " Case(\"" << Rule.getName() << "\", " << Rule.getEnumValue()
<< ").\n";
}
- OS << " Default(None);\n";
+ OS << " Default(std::nullopt);\n";
OS << " return "
- "llvm::StringSwitch<Optional<attr::SubjectMatchRule>>(Name).\n";
+ "llvm::StringSwitch<std::optional<attr::SubjectMatchRule>>(Name).\n";
for (const auto &Rule : SubMatchRule.second) {
if (!Rule.isNegatedSubRule())
OS << " Case(\"" << Rule.getName() << "\", " << Rule.getEnumValue()
<< ").\n";
}
- OS << " Default(None);\n";
+ OS << " Default(std::nullopt);\n";
OS << "}\n\n";
}
// Generate the function that checks for the top-level rules.
- OS << "std::pair<Optional<attr::SubjectMatchRule>, "
- "Optional<attr::SubjectMatchRule> (*)(StringRef, "
+ OS << "std::pair<std::optional<attr::SubjectMatchRule>, "
+ "std::optional<attr::SubjectMatchRule> (*)(StringRef, "
"bool)> isAttributeSubjectMatchRule(StringRef Name) {\n";
OS << " return "
- "llvm::StringSwitch<std::pair<Optional<attr::SubjectMatchRule>, "
- "Optional<attr::SubjectMatchRule> (*) (StringRef, "
+ "llvm::StringSwitch<std::pair<std::optional<attr::SubjectMatchRule>, "
+ "std::optional<attr::SubjectMatchRule> (*) (StringRef, "
"bool)>>(Name).\n";
for (const auto &Rule : Rules) {
if (Rule.isSubRule())
@@ -2095,7 +2243,7 @@ void PragmaClangAttributeSupport::generateParsingHelpers(raw_ostream &OS) {
OS << " Case(\"" << Rule.getName() << "\", std::make_pair("
<< Rule.getEnumValue() << ", " << SubRuleFunction << ")).\n";
}
- OS << " Default(std::make_pair(None, "
+ OS << " Default(std::make_pair(std::nullopt, "
"defaultIsAttributeSubjectMatchSubRuleFor));\n";
OS << "}\n\n";
@@ -2137,6 +2285,11 @@ static void forEachUniqueSpelling(const Record &Attr, Fn &&F) {
}
}
+static bool isTypeArgument(const Record *Arg) {
+ return !Arg->getSuperClasses().empty() &&
+ Arg->getSuperClasses().back().first->getName() == "TypeArgument";
+}
+
/// Emits the first-argument-is-type property for attributes.
static void emitClangAttrTypeArgList(RecordKeeper &Records, raw_ostream &OS) {
OS << "#if defined(CLANG_ATTR_TYPE_ARG_LIST)\n";
@@ -2148,7 +2301,7 @@ static void emitClangAttrTypeArgList(RecordKeeper &Records, raw_ostream &OS) {
if (Args.empty())
continue;
- if (Args[0]->getSuperClasses().back().first->getName() != "TypeArgument")
+ if (!isTypeArgument(Args[0]))
continue;
// All these spellings take a single type argument.
@@ -2178,7 +2331,7 @@ static void emitClangAttrArgContextList(RecordKeeper &Records, raw_ostream &OS)
OS << "#endif // CLANG_ATTR_ARG_CONTEXT_LIST\n\n";
}
-static bool isIdentifierArgument(Record *Arg) {
+static bool isIdentifierArgument(const Record *Arg) {
return !Arg->getSuperClasses().empty() &&
llvm::StringSwitch<bool>(Arg->getSuperClasses().back().first->getName())
.Case("IdentifierArgument", true)
@@ -2187,7 +2340,7 @@ static bool isIdentifierArgument(Record *Arg) {
.Default(false);
}
-static bool isVariadicIdentifierArgument(Record *Arg) {
+static bool isVariadicIdentifierArgument(const Record *Arg) {
return !Arg->getSuperClasses().empty() &&
llvm::StringSwitch<bool>(
Arg->getSuperClasses().back().first->getName())
@@ -2196,6 +2349,30 @@ static bool isVariadicIdentifierArgument(Record *Arg) {
.Default(false);
}
+static bool isVariadicExprArgument(const Record *Arg) {
+ return !Arg->getSuperClasses().empty() &&
+ llvm::StringSwitch<bool>(
+ Arg->getSuperClasses().back().first->getName())
+ .Case("VariadicExprArgument", true)
+ .Default(false);
+}
+
+static bool isStringLiteralArgument(const Record *Arg) {
+ return !Arg->getSuperClasses().empty() &&
+ llvm::StringSwitch<bool>(
+ Arg->getSuperClasses().back().first->getName())
+ .Case("StringArgument", true)
+ .Default(false);
+}
+
+static bool isVariadicStringLiteralArgument(const Record *Arg) {
+ return !Arg->getSuperClasses().empty() &&
+ llvm::StringSwitch<bool>(
+ Arg->getSuperClasses().back().first->getName())
+ .Case("VariadicStringArgument", true)
+ .Default(false);
+}
+
static void emitClangAttrVariadicIdentifierArgList(RecordKeeper &Records,
raw_ostream &OS) {
OS << "#if defined(CLANG_ATTR_VARIADIC_IDENTIFIER_ARG_LIST)\n";
@@ -2216,6 +2393,34 @@ static void emitClangAttrVariadicIdentifierArgList(RecordKeeper &Records,
OS << "#endif // CLANG_ATTR_VARIADIC_IDENTIFIER_ARG_LIST\n\n";
}
+// Emits the list of arguments that should be parsed as unevaluated string
+// literals for each attribute.
+static void emitClangAttrUnevaluatedStringLiteralList(RecordKeeper &Records,
+ raw_ostream &OS) {
+ OS << "#if defined(CLANG_ATTR_STRING_LITERAL_ARG_LIST)\n";
+ std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
+ for (const auto *Attr : Attrs) {
+ std::vector<Record *> Args = Attr->getValueAsListOfDefs("Args");
+ uint32_t Bits = 0;
+ assert(Args.size() <= 32 && "unsupported number of arguments in attribute");
+ for (uint32_t N = 0; N < Args.size(); ++N) {
+ Bits |= (isStringLiteralArgument(Args[N]) << N);
+ // If we have a variadic string argument, set all the remaining bits to 1
+ if (isVariadicStringLiteralArgument(Args[N])) {
+ Bits |= maskTrailingZeros<decltype(Bits)>(N);
+ break;
+ }
+ }
+ if (!Bits)
+ continue;
+ // All these spellings have at least one string literal has argument.
+ forEachUniqueSpelling(*Attr, [&](const FlattenedSpelling &S) {
+ OS << ".Case(\"" << S.name() << "\", " << Bits << ")\n";
+ });
+ }
+ OS << "#endif // CLANG_ATTR_STRING_LITERAL_ARG_LIST\n\n";
+}
+
// Emits the first-argument-is-identifier property for attributes.
static void emitClangAttrIdentifierArgList(RecordKeeper &Records, raw_ostream &OS) {
OS << "#if defined(CLANG_ATTR_IDENTIFIER_ARG_LIST)\n";
@@ -2263,6 +2468,40 @@ static void emitClangAttrThisIsaIdentifierArgList(RecordKeeper &Records,
OS << "#endif // CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST\n\n";
}
+static void emitClangAttrAcceptsExprPack(RecordKeeper &Records,
+ raw_ostream &OS) {
+ OS << "#if defined(CLANG_ATTR_ACCEPTS_EXPR_PACK)\n";
+ ParsedAttrMap Attrs = getParsedAttrList(Records);
+ for (const auto &I : Attrs) {
+ const Record &Attr = *I.second;
+
+ if (!Attr.getValueAsBit("AcceptsExprPack"))
+ continue;
+
+ forEachUniqueSpelling(Attr, [&](const FlattenedSpelling &S) {
+ OS << ".Case(\"" << S.name() << "\", true)\n";
+ });
+ }
+ OS << "#endif // CLANG_ATTR_ACCEPTS_EXPR_PACK\n\n";
+}
+
+static bool isRegularKeywordAttribute(const FlattenedSpelling &S) {
+ return (S.variety() == "Keyword" &&
+ !S.getSpellingRecord().getValueAsBit("HasOwnParseRules"));
+}
+
+static void emitFormInitializer(raw_ostream &OS,
+ const FlattenedSpelling &Spelling,
+ StringRef SpellingIndex) {
+ bool IsAlignas =
+ (Spelling.variety() == "Keyword" && Spelling.name() == "alignas");
+ OS << "{AttributeCommonInfo::AS_" << Spelling.variety() << ", "
+ << SpellingIndex << ", " << (IsAlignas ? "true" : "false")
+ << " /*IsAlignas*/, "
+ << (isRegularKeywordAttribute(Spelling) ? "true" : "false")
+ << " /*IsRegularKeywordAttribute*/}";
+}
+
static void emitAttributes(RecordKeeper &Records, raw_ostream &OS,
bool Header) {
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
@@ -2319,6 +2558,25 @@ static void emitAttributes(RecordKeeper &Records, raw_ostream &OS,
std::vector<std::unique_ptr<Argument>> Args;
Args.reserve(ArgRecords.size());
+ bool AttrAcceptsExprPack = Attr->getValueAsBit("AcceptsExprPack");
+ if (AttrAcceptsExprPack) {
+ for (size_t I = 0; I < ArgRecords.size(); ++I) {
+ const Record *ArgR = ArgRecords[I];
+ if (isIdentifierArgument(ArgR) || isVariadicIdentifierArgument(ArgR) ||
+ isTypeArgument(ArgR))
+ PrintFatalError(Attr->getLoc(),
+ "Attributes accepting packs cannot also "
+ "have identifier or type arguments.");
+ // When trying to determine if value-dependent expressions can populate
+ // the attribute without prior instantiation, the decision is made based
+ // on the assumption that only the last argument is ever variadic.
+ if (I < (ArgRecords.size() - 1) && isVariadicExprArgument(ArgR))
+ PrintFatalError(Attr->getLoc(),
+ "Attributes accepting packs can only have the last "
+ "argument be variadic.");
+ }
+ }
+
bool HasOptArg = false;
bool HasFakeArg = false;
for (const auto *ArgRecord : ArgRecords) {
@@ -2336,6 +2594,16 @@ static void emitAttributes(RecordKeeper &Records, raw_ostream &OS,
}
}
+ std::unique_ptr<VariadicExprArgument> DelayedArgs = nullptr;
+ if (AttrAcceptsExprPack) {
+ DelayedArgs =
+ std::make_unique<VariadicExprArgument>("DelayedArgs", R.getName());
+ if (Header) {
+ DelayedArgs->writeDeclarations(OS);
+ OS << "\n\n";
+ }
+ }
+
if (Header)
OS << "public:\n";
@@ -2362,7 +2630,7 @@ static void emitAttributes(RecordKeeper &Records, raw_ostream &OS,
});
// Emit CreateImplicit factory methods.
- auto emitCreate = [&](bool Implicit, bool emitFake) {
+ auto emitCreate = [&](bool Implicit, bool DelayedArgsOnly, bool emitFake) {
if (Header)
OS << " static ";
OS << R.getName() << "Attr *";
@@ -2371,16 +2639,22 @@ static void emitAttributes(RecordKeeper &Records, raw_ostream &OS,
OS << "Create";
if (Implicit)
OS << "Implicit";
+ if (DelayedArgsOnly)
+ OS << "WithDelayedArgs";
OS << "(";
OS << "ASTContext &Ctx";
- for (auto const &ai : Args) {
- if (ai->isFake() && !emitFake) continue;
+ if (!DelayedArgsOnly) {
+ for (auto const &ai : Args) {
+ if (ai->isFake() && !emitFake)
+ continue;
+ OS << ", ";
+ ai->writeCtorParameters(OS);
+ }
+ } else {
OS << ", ";
- ai->writeCtorParameters(OS);
+ DelayedArgs->writeCtorParameters(OS);
}
OS << ", const AttributeCommonInfo &CommonInfo";
- if (Header && Implicit)
- OS << " = {SourceRange{}}";
OS << ")";
if (Header) {
OS << ";\n";
@@ -2390,10 +2664,14 @@ static void emitAttributes(RecordKeeper &Records, raw_ostream &OS,
OS << " {\n";
OS << " auto *A = new (Ctx) " << R.getName();
OS << "Attr(Ctx, CommonInfo";
- for (auto const &ai : Args) {
- if (ai->isFake() && !emitFake) continue;
- OS << ", ";
- ai->writeImplicitCtorArgs(OS);
+
+ if (!DelayedArgsOnly) {
+ for (auto const &ai : Args) {
+ if (ai->isFake() && !emitFake)
+ continue;
+ OS << ", ";
+ ai->writeImplicitCtorArgs(OS);
+ }
}
OS << ");\n";
if (Implicit) {
@@ -2404,10 +2682,16 @@ static void emitAttributes(RecordKeeper &Records, raw_ostream &OS,
"!A->getAttrName())\n";
OS << " A->setAttributeSpellingListIndex(0);\n";
}
+ if (DelayedArgsOnly) {
+ OS << " A->setDelayedArgs(Ctx, ";
+ DelayedArgs->writeImplicitCtorArgs(OS);
+ OS << ");\n";
+ }
OS << " return A;\n}\n\n";
};
- auto emitCreateNoCI = [&](bool Implicit, bool emitFake) {
+ auto emitCreateNoCI = [&](bool Implicit, bool DelayedArgsOnly,
+ bool emitFake) {
if (Header)
OS << " static ";
OS << R.getName() << "Attr *";
@@ -2416,18 +2700,28 @@ static void emitAttributes(RecordKeeper &Records, raw_ostream &OS,
OS << "Create";
if (Implicit)
OS << "Implicit";
+ if (DelayedArgsOnly)
+ OS << "WithDelayedArgs";
OS << "(";
OS << "ASTContext &Ctx";
- for (auto const &ai : Args) {
- if (ai->isFake() && !emitFake) continue;
+ if (!DelayedArgsOnly) {
+ for (auto const &ai : Args) {
+ if (ai->isFake() && !emitFake)
+ continue;
+ OS << ", ";
+ ai->writeCtorParameters(OS);
+ }
+ } else {
OS << ", ";
- ai->writeCtorParameters(OS);
+ DelayedArgs->writeCtorParameters(OS);
}
- OS << ", SourceRange Range, AttributeCommonInfo::Syntax Syntax";
- if (!ElideSpelling) {
- OS << ", " << R.getName() << "Attr::Spelling S";
+ OS << ", SourceRange Range";
+ if (Header)
+ OS << " = {}";
+ if (Spellings.size() > 1) {
+ OS << ", Spelling S";
if (Header)
- OS << " = static_cast<Spelling>(SpellingNotCalculated)";
+ OS << " = " << SemanticToSyntacticMap[0];
}
OS << ")";
if (Header) {
@@ -2443,45 +2737,89 @@ static void emitAttributes(RecordKeeper &Records, raw_ostream &OS,
else
OS << "NoSemaHandlerAttribute";
- OS << ", Syntax";
- if (!ElideSpelling)
- OS << ", S";
+ if (Spellings.size() == 0) {
+ OS << ", AttributeCommonInfo::Form::Implicit()";
+ } else if (Spellings.size() == 1) {
+ OS << ", ";
+ emitFormInitializer(OS, Spellings[0], "0");
+ } else {
+ OS << ", [&]() {\n";
+ OS << " switch (S) {\n";
+ std::set<std::string> Uniques;
+ unsigned Idx = 0;
+ for (auto I = Spellings.begin(), E = Spellings.end(); I != E;
+ ++I, ++Idx) {
+ const FlattenedSpelling &S = *I;
+ const auto &Name = SemanticToSyntacticMap[Idx];
+ if (Uniques.insert(Name).second) {
+ OS << " case " << Name << ":\n";
+ OS << " return AttributeCommonInfo::Form";
+ emitFormInitializer(OS, S, Name);
+ OS << ";\n";
+ }
+ }
+ OS << " default:\n";
+ OS << " llvm_unreachable(\"Unknown attribute spelling!\");\n"
+ << " return AttributeCommonInfo::Form";
+ emitFormInitializer(OS, Spellings[0], "0");
+ OS << ";\n"
+ << " }\n"
+ << " }()";
+ }
+
OS << ");\n";
OS << " return Create";
if (Implicit)
OS << "Implicit";
+ if (DelayedArgsOnly)
+ OS << "WithDelayedArgs";
OS << "(Ctx";
- for (auto const &ai : Args) {
- if (ai->isFake() && !emitFake) continue;
+ if (!DelayedArgsOnly) {
+ for (auto const &ai : Args) {
+ if (ai->isFake() && !emitFake)
+ continue;
+ OS << ", ";
+ ai->writeImplicitCtorArgs(OS);
+ }
+ } else {
OS << ", ";
- ai->writeImplicitCtorArgs(OS);
+ DelayedArgs->writeImplicitCtorArgs(OS);
}
OS << ", I);\n";
OS << "}\n\n";
};
- auto emitCreates = [&](bool emitFake) {
- emitCreate(true, emitFake);
- emitCreate(false, emitFake);
- emitCreateNoCI(true, emitFake);
- emitCreateNoCI(false, emitFake);
+ auto emitCreates = [&](bool DelayedArgsOnly, bool emitFake) {
+ emitCreate(true, DelayedArgsOnly, emitFake);
+ emitCreate(false, DelayedArgsOnly, emitFake);
+ emitCreateNoCI(true, DelayedArgsOnly, emitFake);
+ emitCreateNoCI(false, DelayedArgsOnly, emitFake);
};
if (Header)
OS << " // Factory methods\n";
// Emit a CreateImplicit that takes all the arguments.
- emitCreates(true);
+ emitCreates(false, true);
// Emit a CreateImplicit that takes all the non-fake arguments.
if (HasFakeArg)
- emitCreates(false);
+ emitCreates(false, false);
+
+ // Emit a CreateWithDelayedArgs that takes only the dependent argument
+ // expressions.
+ if (DelayedArgs)
+ emitCreates(true, false);
// Emit constructors.
- auto emitCtor = [&](bool emitOpt, bool emitFake) {
+ auto emitCtor = [&](bool emitOpt, bool emitFake, bool emitNoArgs) {
auto shouldEmitArg = [=](const std::unique_ptr<Argument> &arg) {
- if (arg->isFake()) return emitFake;
- if (arg->isOptional()) return emitOpt;
+ if (emitNoArgs)
+ return false;
+ if (arg->isFake())
+ return emitFake;
+ if (arg->isOptional())
+ return emitOpt;
return true;
};
if (Header)
@@ -2492,7 +2830,8 @@ static void emitAttributes(RecordKeeper &Records, raw_ostream &OS,
<< "Attr(ASTContext &Ctx, const AttributeCommonInfo &CommonInfo";
OS << '\n';
for (auto const &ai : Args) {
- if (!shouldEmitArg(ai)) continue;
+ if (!shouldEmitArg(ai))
+ continue;
OS << " , ";
ai->writeCtorParameters(OS);
OS << "\n";
@@ -2522,11 +2861,17 @@ static void emitAttributes(RecordKeeper &Records, raw_ostream &OS,
}
OS << "\n";
}
+ if (DelayedArgs) {
+ OS << " , ";
+ DelayedArgs->writeCtorDefaultInitializers(OS);
+ OS << "\n";
+ }
OS << " {\n";
for (auto const &ai : Args) {
- if (!shouldEmitArg(ai)) continue;
+ if (!shouldEmitArg(ai))
+ continue;
ai->writeCtorBody(OS);
}
OS << "}\n\n";
@@ -2537,15 +2882,24 @@ static void emitAttributes(RecordKeeper &Records, raw_ostream &OS,
// Emit a constructor that includes all the arguments.
// This is necessary for cloning.
- emitCtor(true, true);
+ emitCtor(true, true, false);
// Emit a constructor that takes all the non-fake arguments.
if (HasFakeArg)
- emitCtor(true, false);
+ emitCtor(true, false, false);
// Emit a constructor that takes all the non-fake, non-optional arguments.
if (HasOptArg)
- emitCtor(false, false);
+ emitCtor(false, false, false);
+
+ // Emit constructors that takes no arguments if none already exists.
+ // This is used for delaying arguments.
+ bool HasRequiredArgs =
+ llvm::count_if(Args, [=](const std::unique_ptr<Argument> &arg) {
+ return !arg->isFake() && !arg->isOptional();
+ });
+ if (DelayedArgs && HasRequiredArgs)
+ emitCtor(false, false, true);
if (Header) {
OS << '\n';
@@ -2591,6 +2945,11 @@ static void emitAttributes(RecordKeeper &Records, raw_ostream &OS,
}
if (Header) {
+ if (DelayedArgs) {
+ DelayedArgs->writeAccessors(OS);
+ DelayedArgs->writeSetter(OS);
+ }
+
OS << R.getValueAsString("AdditionalMembers");
OS << "\n\n";
@@ -2599,6 +2958,9 @@ static void emitAttributes(RecordKeeper &Records, raw_ostream &OS,
OS << "};\n\n";
} else {
+ if (DelayedArgs)
+ DelayedArgs->writeAccessorDefinitions(OS);
+
OS << R.getName() << "Attr *" << R.getName()
<< "Attr::clone(ASTContext &C) const {\n";
OS << " auto *A = new (C) " << R.getName() << "Attr(C, *this";
@@ -2610,6 +2972,11 @@ static void emitAttributes(RecordKeeper &Records, raw_ostream &OS,
OS << " A->Inherited = Inherited;\n";
OS << " A->IsPackExpansion = IsPackExpansion;\n";
OS << " A->setImplicit(Implicit);\n";
+ if (DelayedArgs) {
+ OS << " A->setDelayedArgs(C, ";
+ DelayedArgs->writeCloneArgs(OS);
+ OS << ");\n";
+ }
OS << " return A;\n}\n\n";
writePrettyPrintFunction(R, Args, OS);
@@ -2619,7 +2986,7 @@ static void emitAttributes(RecordKeeper &Records, raw_ostream &OS,
}
// Emits the class definitions for attributes.
void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
- emitSourceFileHeader("Attribute classes' definitions", OS);
+ emitSourceFileHeader("Attribute classes' definitions", OS, Records);
OS << "#ifndef LLVM_CLANG_ATTR_CLASSES_INC\n";
OS << "#define LLVM_CLANG_ATTR_CLASSES_INC\n\n";
@@ -2631,7 +2998,8 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
// Emits the class method definitions for attributes.
void clang::EmitClangAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
- emitSourceFileHeader("Attribute classes' member function definitions", OS);
+ emitSourceFileHeader("Attribute classes' member function definitions", OS,
+ Records);
emitAttributes(Records, OS, false);
@@ -2676,9 +3044,9 @@ static void emitAttrList(raw_ostream &OS, StringRef Class,
// Determines if an attribute has a Pragma spelling.
static bool AttrHasPragmaSpelling(const Record *R) {
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*R);
- return llvm::find_if(Spellings, [](const FlattenedSpelling &S) {
- return S.variety() == "Pragma";
- }) != Spellings.end();
+ return llvm::any_of(Spellings, [](const FlattenedSpelling &S) {
+ return S.variety() == "Pragma";
+ });
}
namespace {
@@ -2698,7 +3066,8 @@ static const AttrClassDescriptor AttrClassDescriptors[] = {
{ "INHERITABLE_ATTR", "InheritableAttr" },
{ "DECL_OR_TYPE_ATTR", "DeclOrTypeAttr" },
{ "INHERITABLE_PARAM_ATTR", "InheritableParamAttr" },
- { "PARAMETER_ABI_ATTR", "ParameterABIAttr" }
+ { "PARAMETER_ABI_ATTR", "ParameterABIAttr" },
+ { "HLSL_ANNOTATION_ATTR", "HLSLAnnotationAttr"}
};
static void emitDefaultDefine(raw_ostream &OS, StringRef name,
@@ -2866,7 +3235,8 @@ namespace clang {
// Emits the enumeration list for attributes.
void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) {
- emitSourceFileHeader("List of all attributes that Clang recognizes", OS);
+ emitSourceFileHeader("List of all attributes that Clang recognizes", OS,
+ Records);
AttrClassHierarchy Hierarchy(Records);
@@ -2905,9 +3275,41 @@ void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) {
}
// Emits the enumeration list for attributes.
+void EmitClangAttrPrintList(const std::string &FieldName, RecordKeeper &Records,
+ raw_ostream &OS) {
+ emitSourceFileHeader(
+ "List of attributes that can be print on the left side of a decl", OS,
+ Records);
+
+ AttrClassHierarchy Hierarchy(Records);
+
+ std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
+ std::vector<Record *> PragmaAttrs;
+ bool first = false;
+
+ for (auto *Attr : Attrs) {
+ if (!Attr->getValueAsBit("ASTNode"))
+ continue;
+
+ if (!Attr->getValueAsBit(FieldName))
+ continue;
+
+ if (!first) {
+ first = true;
+ OS << "#define CLANG_ATTR_LIST_" << FieldName;
+ }
+
+ OS << " \\\n case attr::" << Attr->getName() << ":";
+ }
+
+ OS << '\n';
+}
+
+// Emits the enumeration list for attributes.
void EmitClangAttrSubjectMatchRuleList(RecordKeeper &Records, raw_ostream &OS) {
emitSourceFileHeader(
- "List of all attribute subject matching rules that Clang recognizes", OS);
+ "List of all attribute subject matching rules that Clang recognizes", OS,
+ Records);
PragmaClangAttributeSupport &PragmaAttributeSupport =
getPragmaAttributeSupport(Records);
emitDefaultDefine(OS, "ATTR_MATCH_RULE", nullptr);
@@ -2917,12 +3319,13 @@ void EmitClangAttrSubjectMatchRuleList(RecordKeeper &Records, raw_ostream &OS) {
// Emits the code to read an attribute from a precompiled header.
void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS) {
- emitSourceFileHeader("Attribute deserialization code", OS);
+ emitSourceFileHeader("Attribute deserialization code", OS, Records);
Record *InhClass = Records.getClass("InheritableAttr");
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"),
ArgRecords;
std::vector<std::unique_ptr<Argument>> Args;
+ std::unique_ptr<VariadicExprArgument> DelayedArgs;
OS << " switch (Kind) {\n";
for (const auto *Attr : Attrs) {
@@ -2935,6 +3338,12 @@ void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS) {
OS << " bool isInherited = Record.readInt();\n";
OS << " bool isImplicit = Record.readInt();\n";
OS << " bool isPackExpansion = Record.readInt();\n";
+ DelayedArgs = nullptr;
+ if (Attr->getValueAsBit("AcceptsExprPack")) {
+ DelayedArgs =
+ std::make_unique<VariadicExprArgument>("DelayedArgs", R.getName());
+ DelayedArgs->writePCHReadDecls(OS);
+ }
ArgRecords = R.getValueAsListOfDefs("Args");
Args.clear();
for (const auto *Arg : ArgRecords) {
@@ -2951,6 +3360,12 @@ void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS) {
OS << " cast<InheritableAttr>(New)->setInherited(isInherited);\n";
OS << " New->setImplicit(isImplicit);\n";
OS << " New->setPackExpansion(isPackExpansion);\n";
+ if (DelayedArgs) {
+ OS << " cast<" << R.getName()
+ << "Attr>(New)->setDelayedArgs(Context, ";
+ DelayedArgs->writePCHReadArgs(OS);
+ OS << ");\n";
+ }
OS << " break;\n";
OS << " }\n";
}
@@ -2959,7 +3374,7 @@ void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS) {
// Emits the code to write an attribute to a precompiled header.
void EmitClangAttrPCHWrite(RecordKeeper &Records, raw_ostream &OS) {
- emitSourceFileHeader("Attribute serialization code", OS);
+ emitSourceFileHeader("Attribute serialization code", OS, Records);
Record *InhClass = Records.getClass("InheritableAttr");
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"), Args;
@@ -2978,6 +3393,8 @@ void EmitClangAttrPCHWrite(RecordKeeper &Records, raw_ostream &OS) {
OS << " Record.push_back(SA->isInherited());\n";
OS << " Record.push_back(A->isImplicit());\n";
OS << " Record.push_back(A->isPackExpansion());\n";
+ if (Attr->getValueAsBit("AcceptsExprPack"))
+ VariadicExprArgument("DelayedArgs", R.getName()).writePCHWrite(OS);
for (const auto *Arg : Args)
createArgument(*Arg, R.getName())->writePCHWrite(OS);
@@ -3070,9 +3487,10 @@ static bool GenerateTargetSpecificAttrChecks(const Record *R,
}
static void GenerateHasAttrSpellingStringSwitch(
- const std::vector<Record *> &Attrs, raw_ostream &OS,
- const std::string &Variety = "", const std::string &Scope = "") {
- for (const auto *Attr : Attrs) {
+ const std::vector<std::pair<const Record *, FlattenedSpelling>> &Attrs,
+ raw_ostream &OS, const std::string &Variety,
+ const std::string &Scope = "") {
+ for (const auto &[Attr, Spelling] : Attrs) {
// C++11-style attributes have specific version information associated with
// them. If the attribute has no scope, the version information must not
// have the default value (1), as that's incorrect. Instead, the unscoped
@@ -3080,22 +3498,33 @@ static void GenerateHasAttrSpellingStringSwitch(
// document, which can be found at:
// https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations
//
- // C2x-style attributes have the same kind of version information
+ // C23-style attributes have the same kind of version information
// associated with them. The unscoped attribute version information should
// be taken from the specification of the attribute in the C Standard.
+ //
+ // Clang-specific attributes have the same kind of version information
+ // associated with them. This version is typically the default value (1).
+ // These version values are clang-specific and should typically be
+ // incremented once the attribute changes its syntax and/or semantics in a
+ // a way that is impactful to the end user.
int Version = 1;
- if (Variety == "CXX11" || Variety == "C2x") {
- std::vector<Record *> Spellings = Attr->getValueAsListOfDefs("Spellings");
- for (const auto &Spelling : Spellings) {
- if (Spelling->getValueAsString("Variety") == Variety) {
- Version = static_cast<int>(Spelling->getValueAsInt("Version"));
- if (Scope.empty() && Version == 1)
- PrintError(Spelling->getLoc(), "Standard attributes must have "
- "valid version information.");
- break;
- }
- }
+ assert(Spelling.variety() == Variety);
+ std::string Name = "";
+ if (Spelling.nameSpace().empty() || Scope == Spelling.nameSpace()) {
+ Name = Spelling.name();
+ Version = static_cast<int>(
+ Spelling.getSpellingRecord().getValueAsInt("Version"));
+ // Verify that explicitly specified CXX11 and C23 spellings (i.e.
+ // not inferred from Clang/GCC spellings) have a version that's
+ // different from the default (1).
+ bool RequiresValidVersion =
+ (Variety == "CXX11" || Variety == "C23") &&
+ Spelling.getSpellingRecord().getValueAsString("Variety") == Variety;
+ if (RequiresValidVersion && Scope.empty() && Version == 1)
+ PrintError(Spelling.getSpellingRecord().getLoc(),
+ "Standard attributes must have "
+ "valid version information.");
}
std::string Test;
@@ -3107,35 +3536,77 @@ static void GenerateHasAttrSpellingStringSwitch(
// If this is the C++11 variety, also add in the LangOpts test.
if (Variety == "CXX11")
Test += " && LangOpts.CPlusPlus11";
- else if (Variety == "C2x")
- Test += " && LangOpts.DoubleSquareBracketAttributes";
+ } else if (!Attr->getValueAsListOfDefs("TargetSpecificSpellings").empty()) {
+ // Add target checks if this spelling is target-specific.
+ const std::vector<Record *> TargetSpellings =
+ Attr->getValueAsListOfDefs("TargetSpecificSpellings");
+ for (const auto &TargetSpelling : TargetSpellings) {
+ // Find spelling that matches current scope and name.
+ for (const auto &Spelling : GetFlattenedSpellings(*TargetSpelling)) {
+ if (Scope == Spelling.nameSpace() && Name == Spelling.name()) {
+ const Record *Target = TargetSpelling->getValueAsDef("Target");
+ std::vector<StringRef> Arches =
+ Target->getValueAsListOfStrings("Arches");
+ GenerateTargetSpecificAttrChecks(Target, Arches, Test,
+ /*FnName=*/nullptr);
+ break;
+ }
+ }
+ }
+
+ if (Variety == "CXX11")
+ Test += " && LangOpts.CPlusPlus11";
} else if (Variety == "CXX11")
// C++11 mode should be checked against LangOpts, which is presumed to be
// present in the caller.
Test = "LangOpts.CPlusPlus11";
- else if (Variety == "C2x")
- Test = "LangOpts.DoubleSquareBracketAttributes";
-
- std::string TestStr =
- !Test.empty() ? Test + " ? " + llvm::itostr(Version) + " : 0" : "1";
- std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*Attr);
- for (const auto &S : Spellings)
- if (Variety.empty() || (Variety == S.variety() &&
- (Scope.empty() || Scope == S.nameSpace())))
- OS << " .Case(\"" << S.name() << "\", " << TestStr << ")\n";
+
+ std::string TestStr = !Test.empty()
+ ? Test + " ? " + llvm::itostr(Version) + " : 0"
+ : llvm::itostr(Version);
+ if (Scope.empty() || Scope == Spelling.nameSpace())
+ OS << " .Case(\"" << Spelling.name() << "\", " << TestStr << ")\n";
}
OS << " .Default(0);\n";
}
+// Emits list of regular keyword attributes with info about their arguments.
+void EmitClangRegularKeywordAttributeInfo(RecordKeeper &Records,
+ raw_ostream &OS) {
+ emitSourceFileHeader(
+ "A list of regular keyword attributes generated from the attribute"
+ " definitions",
+ OS);
+ // Assume for now that the same token is not used in multiple regular
+ // keyword attributes.
+ for (auto *R : Records.getAllDerivedDefinitions("Attr"))
+ for (const auto &S : GetFlattenedSpellings(*R)) {
+ if (!isRegularKeywordAttribute(S))
+ continue;
+ std::vector<Record *> Args = R->getValueAsListOfDefs("Args");
+ bool HasArgs = llvm::any_of(
+ Args, [](const Record *Arg) { return !Arg->getValueAsBit("Fake"); });
+
+ OS << "KEYWORD_ATTRIBUTE("
+ << S.getSpellingRecord().getValueAsString("Name") << ", "
+ << (HasArgs ? "true" : "false") << ", )\n";
+ }
+ OS << "#undef KEYWORD_ATTRIBUTE\n";
+}
+
// Emits the list of spellings for attributes.
void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
- emitSourceFileHeader("Code to implement the __has_attribute logic", OS);
+ emitSourceFileHeader("Code to implement the __has_attribute logic", OS,
+ Records);
// Separate all of the attributes out into four group: generic, C++11, GNU,
// and declspecs. Then generate a big switch statement for each of them.
std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
- std::vector<Record *> Declspec, Microsoft, GNU, Pragma;
- std::map<std::string, std::vector<Record *>> CXX, C2x;
+ std::vector<std::pair<const Record *, FlattenedSpelling>> Declspec, Microsoft,
+ GNU, Pragma, HLSLSemantic;
+ std::map<std::string,
+ std::vector<std::pair<const Record *, FlattenedSpelling>>>
+ CXX, C23;
// Walk over the list of all attributes, and split them out based on the
// spelling variety.
@@ -3144,37 +3615,45 @@ void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
for (const auto &SI : Spellings) {
const std::string &Variety = SI.variety();
if (Variety == "GNU")
- GNU.push_back(R);
+ GNU.emplace_back(R, SI);
else if (Variety == "Declspec")
- Declspec.push_back(R);
+ Declspec.emplace_back(R, SI);
else if (Variety == "Microsoft")
- Microsoft.push_back(R);
+ Microsoft.emplace_back(R, SI);
else if (Variety == "CXX11")
- CXX[SI.nameSpace()].push_back(R);
- else if (Variety == "C2x")
- C2x[SI.nameSpace()].push_back(R);
+ CXX[SI.nameSpace()].emplace_back(R, SI);
+ else if (Variety == "C23")
+ C23[SI.nameSpace()].emplace_back(R, SI);
else if (Variety == "Pragma")
- Pragma.push_back(R);
+ Pragma.emplace_back(R, SI);
+ else if (Variety == "HLSLSemantic")
+ HLSLSemantic.emplace_back(R, SI);
}
}
OS << "const llvm::Triple &T = Target.getTriple();\n";
OS << "switch (Syntax) {\n";
- OS << "case AttrSyntax::GNU:\n";
+ OS << "case AttributeCommonInfo::Syntax::AS_GNU:\n";
OS << " return llvm::StringSwitch<int>(Name)\n";
GenerateHasAttrSpellingStringSwitch(GNU, OS, "GNU");
- OS << "case AttrSyntax::Declspec:\n";
+ OS << "case AttributeCommonInfo::Syntax::AS_Declspec:\n";
OS << " return llvm::StringSwitch<int>(Name)\n";
GenerateHasAttrSpellingStringSwitch(Declspec, OS, "Declspec");
- OS << "case AttrSyntax::Microsoft:\n";
+ OS << "case AttributeCommonInfo::Syntax::AS_Microsoft:\n";
OS << " return llvm::StringSwitch<int>(Name)\n";
GenerateHasAttrSpellingStringSwitch(Microsoft, OS, "Microsoft");
- OS << "case AttrSyntax::Pragma:\n";
+ OS << "case AttributeCommonInfo::Syntax::AS_Pragma:\n";
OS << " return llvm::StringSwitch<int>(Name)\n";
GenerateHasAttrSpellingStringSwitch(Pragma, OS, "Pragma");
- auto fn = [&OS](const char *Spelling, const char *Variety,
- const std::map<std::string, std::vector<Record *>> &List) {
- OS << "case AttrSyntax::" << Variety << ": {\n";
+ OS << "case AttributeCommonInfo::Syntax::AS_HLSLSemantic:\n";
+ OS << " return llvm::StringSwitch<int>(Name)\n";
+ GenerateHasAttrSpellingStringSwitch(HLSLSemantic, OS, "HLSLSemantic");
+ auto fn = [&OS](const char *Spelling,
+ const std::map<
+ std::string,
+ std::vector<std::pair<const Record *, FlattenedSpelling>>>
+ &List) {
+ OS << "case AttributeCommonInfo::Syntax::AS_" << Spelling << ": {\n";
// C++11-style attributes are further split out based on the Scope.
for (auto I = List.cbegin(), E = List.cend(); I != E; ++I) {
if (I != List.cbegin())
@@ -3189,14 +3668,24 @@ void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
}
OS << "\n} break;\n";
};
- fn("CXX11", "CXX", CXX);
- fn("C2x", "C", C2x);
+ fn("CXX11", CXX);
+ fn("C23", C23);
+ OS << "case AttributeCommonInfo::Syntax::AS_Keyword:\n";
+ OS << "case AttributeCommonInfo::Syntax::AS_ContextSensitiveKeyword:\n";
+ OS << " llvm_unreachable(\"hasAttribute not supported for keyword\");\n";
+ OS << " return 0;\n";
+ OS << "case AttributeCommonInfo::Syntax::AS_Implicit:\n";
+ OS << " llvm_unreachable (\"hasAttribute not supported for "
+ "AS_Implicit\");\n";
+ OS << " return 0;\n";
+
OS << "}\n";
}
void EmitClangAttrSpellingListIndex(RecordKeeper &Records, raw_ostream &OS) {
- emitSourceFileHeader("Code to translate different attribute spellings "
- "into internal identifiers", OS);
+ emitSourceFileHeader("Code to translate different attribute spellings into "
+ "internal identifiers",
+ OS, Records);
OS << " switch (getParsedKind()) {\n";
OS << " case IgnoredAttribute:\n";
@@ -3226,7 +3715,8 @@ void EmitClangAttrSpellingListIndex(RecordKeeper &Records, raw_ostream &OS) {
// Emits code used by RecursiveASTVisitor to visit attributes
void EmitClangAttrASTVisitor(RecordKeeper &Records, raw_ostream &OS) {
- emitSourceFileHeader("Used by RecursiveASTVisitor to visit attributes.", OS);
+ emitSourceFileHeader("Used by RecursiveASTVisitor to visit attributes.", OS,
+ Records);
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
@@ -3265,6 +3755,10 @@ void EmitClangAttrASTVisitor(RecordKeeper &Records, raw_ostream &OS) {
for (const auto *Arg : ArgRecords)
createArgument(*Arg, R.getName())->writeASTVisitorTraversal(OS);
+ if (Attr->getValueAsBit("AcceptsExprPack"))
+ VariadicExprArgument("DelayedArgs", R.getName())
+ .writeASTVisitorTraversal(OS);
+
OS << " return true;\n";
OS << "}\n\n";
}
@@ -3347,7 +3841,8 @@ void EmitClangAttrTemplateInstantiateHelper(const std::vector<Record *> &Attrs,
// Emits code to instantiate dependent attributes on templates.
void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS) {
- emitSourceFileHeader("Template instantiation code for attributes", OS);
+ emitSourceFileHeader("Template instantiation code for attributes", OS,
+ Records);
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
@@ -3369,7 +3864,8 @@ void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS) {
// Emits the list of parsed attributes.
void EmitClangAttrParsedAttrList(RecordKeeper &Records, raw_ostream &OS) {
- emitSourceFileHeader("List of all attributes that Clang recognizes", OS);
+ emitSourceFileHeader("List of all attributes that Clang recognizes", OS,
+ Records);
OS << "#ifndef PARSED_ATTR\n";
OS << "#define PARSED_ATTR(NAME) NAME\n";
@@ -3390,7 +3886,7 @@ static void emitArgInfo(const Record &R, raw_ostream &OS) {
// attribute and emit the number of required arguments followed by the
// number of optional arguments.
std::vector<Record *> Args = R.getValueAsListOfDefs("Args");
- unsigned ArgCount = 0, OptCount = 0;
+ unsigned ArgCount = 0, OptCount = 0, ArgMemberCount = 0;
bool HasVariadic = false;
for (const auto *Arg : Args) {
// If the arg is fake, it's the user's job to supply it: general parsing
@@ -3398,14 +3894,16 @@ static void emitArgInfo(const Record &R, raw_ostream &OS) {
if (Arg->getValueAsBit("Fake"))
continue;
Arg->getValueAsBit("Optional") ? ++OptCount : ++ArgCount;
+ ++ArgMemberCount;
if (!HasVariadic && isArgVariadic(*Arg, R.getName()))
HasVariadic = true;
}
// If there is a variadic argument, we will set the optional argument count
// to its largest value. Since it's currently a 4-bit number, we set it to 15.
- OS << " NumArgs = " << ArgCount << ";\n";
- OS << " OptArgs = " << (HasVariadic ? 15 : OptCount) << ";\n";
+ OS << " /*NumArgs=*/" << ArgCount << ",\n";
+ OS << " /*OptArgs=*/" << (HasVariadic ? 15 : OptCount) << ",\n";
+ OS << " /*NumArgMembers=*/" << ArgMemberCount << ",\n";
}
static std::string GetDiagnosticSpelling(const Record &R) {
@@ -3554,8 +4052,9 @@ static void GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) {
if (!StmtSubjects.empty()) {
OS << "bool diagAppertainsToDecl(Sema &S, const ParsedAttr &AL, ";
OS << "const Decl *D) const override {\n";
- OS << " S.Diag(AL.getLoc(), diag::err_stmt_attribute_invalid_on_decl)\n";
- OS << " << AL << D->getLocation();\n";
+ OS << " S.Diag(AL.getLoc(), diag::err_attribute_invalid_on_decl)\n";
+ OS << " << AL << AL.isRegularKeywordAttribute() << "
+ "D->getLocation();\n";
OS << " return false;\n";
OS << "}\n\n";
}
@@ -3584,7 +4083,7 @@ static void GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) {
OS << (Warn ? "warn_attribute_wrong_decl_type_str"
: "err_attribute_wrong_decl_type_str");
OS << ")\n";
- OS << " << Attr << ";
+ OS << " << Attr << Attr.isRegularKeywordAttribute() << ";
OS << CalculateDiagnostic(*SubjectObj) << ";\n";
OS << " return false;\n";
OS << " }\n";
@@ -3599,7 +4098,8 @@ static void GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) {
OS << "bool diagAppertainsToStmt(Sema &S, const ParsedAttr &AL, ";
OS << "const Stmt *St) const override {\n";
OS << " S.Diag(AL.getLoc(), diag::err_decl_attribute_invalid_on_stmt)\n";
- OS << " << AL << St->getBeginLoc();\n";
+ OS << " << AL << AL.isRegularKeywordAttribute() << "
+ "St->getBeginLoc();\n";
OS << " return false;\n";
OS << "}\n\n";
}
@@ -3618,7 +4118,7 @@ static void GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) {
OS << (Warn ? "warn_attribute_wrong_decl_type_str"
: "err_attribute_wrong_decl_type_str");
OS << ")\n";
- OS << " << Attr << ";
+ OS << " << Attr << Attr.isRegularKeywordAttribute() << ";
OS << CalculateDiagnostic(*SubjectObj) << ";\n";
OS << " return false;\n";
OS << " }\n";
@@ -3689,7 +4189,8 @@ static void GenerateMutualExclusionsChecks(const Record &Attr,
for (const std::string &A : DeclAttrs) {
OS << " if (const auto *A = D->getAttr<" << A << ">()) {\n";
OS << " S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)"
- << " << AL << A;\n";
+ << " << AL << A << (AL.isRegularKeywordAttribute() ||"
+ << " A->isRegularKeywordAttribute());\n";
OS << " S.Diag(A->getLocation(), diag::note_conflicting_attribute);";
OS << " \nreturn false;\n";
OS << " }\n";
@@ -3710,7 +4211,8 @@ static void GenerateMutualExclusionsChecks(const Record &Attr,
<< ">()) {\n";
MergeDeclOS << " S.Diag(First->getLocation(), "
<< "diag::err_attributes_are_not_compatible) << First << "
- << "Second;\n";
+ << "Second << (First->isRegularKeywordAttribute() || "
+ << "Second->isRegularKeywordAttribute());\n";
MergeDeclOS << " S.Diag(Second->getLocation(), "
<< "diag::note_conflicting_attribute);\n";
MergeDeclOS << " return false;\n";
@@ -3750,7 +4252,8 @@ static void GenerateMutualExclusionsChecks(const Record &Attr,
MergeStmtOS << " if (Iter != C.end()) {\n";
MergeStmtOS << " S.Diag((*Iter)->getLocation(), "
<< "diag::err_attributes_are_not_compatible) << *Iter << "
- << "Second;\n";
+ << "Second << ((*Iter)->isRegularKeywordAttribute() || "
+ << "Second->isRegularKeywordAttribute());\n";
MergeStmtOS << " S.Diag(Second->getLocation(), "
<< "diag::note_conflicting_attribute);\n";
MergeStmtOS << " return false;\n";
@@ -3803,14 +4306,8 @@ static void GenerateLangOptRequirements(const Record &R,
if (LangOpts.empty())
return;
- OS << "bool diagLangOpts(Sema &S, const ParsedAttr &Attr) ";
- OS << "const override {\n";
- OS << " auto &LangOpts = S.LangOpts;\n";
- OS << " if (" << GenerateTestExpression(LangOpts) << ")\n";
- OS << " return true;\n\n";
- OS << " S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) ";
- OS << "<< Attr;\n";
- OS << " return false;\n";
+ OS << "bool acceptsLangOpts(const LangOptions &LangOpts) const override {\n";
+ OS << " return " << GenerateTestExpression(LangOpts) << ";\n";
OS << "}\n\n";
}
@@ -3855,6 +4352,51 @@ static void GenerateTargetRequirements(const Record &Attr,
OS << "}\n\n";
}
+static void
+GenerateSpellingTargetRequirements(const Record &Attr,
+ const std::vector<Record *> &TargetSpellings,
+ raw_ostream &OS) {
+ // If there are no target specific spellings, use the default target handler.
+ if (TargetSpellings.empty())
+ return;
+
+ std::string Test;
+ bool UsesT = false;
+ const std::vector<FlattenedSpelling> SpellingList =
+ GetFlattenedSpellings(Attr);
+ for (unsigned TargetIndex = 0; TargetIndex < TargetSpellings.size();
+ ++TargetIndex) {
+ const auto &TargetSpelling = TargetSpellings[TargetIndex];
+ std::vector<FlattenedSpelling> Spellings =
+ GetFlattenedSpellings(*TargetSpelling);
+
+ Test += "((SpellingListIndex == ";
+ for (unsigned Index = 0; Index < Spellings.size(); ++Index) {
+ Test +=
+ llvm::itostr(getSpellingListIndex(SpellingList, Spellings[Index]));
+ if (Index != Spellings.size() - 1)
+ Test += " ||\n SpellingListIndex == ";
+ else
+ Test += ") && ";
+ }
+
+ const Record *Target = TargetSpelling->getValueAsDef("Target");
+ std::vector<StringRef> Arches = Target->getValueAsListOfStrings("Arches");
+ std::string FnName = "isTargetSpelling";
+ UsesT |= GenerateTargetSpecificAttrChecks(Target, Arches, Test, &FnName);
+ Test += ")";
+ if (TargetIndex != TargetSpellings.size() - 1)
+ Test += " || ";
+ }
+
+ OS << "bool spellingExistsInTarget(const TargetInfo &Target,\n";
+ OS << " const unsigned SpellingListIndex) const "
+ "override {\n";
+ if (UsesT)
+ OS << " const llvm::Triple &T = Target.getTriple(); (void)T;\n";
+ OS << " return " << Test << ";\n", OS << "}\n\n";
+}
+
static void GenerateSpellingIndexToSemanticSpelling(const Record &Attr,
raw_ostream &OS) {
// If the attribute does not have a semantic form, we can bail out early.
@@ -3895,6 +4437,55 @@ static void GenerateHandleDeclAttribute(const Record &Attr, raw_ostream &OS) {
OS << "}\n\n";
}
+static bool isParamExpr(const Record *Arg) {
+ return !Arg->getSuperClasses().empty() &&
+ llvm::StringSwitch<bool>(
+ Arg->getSuperClasses().back().first->getName())
+ .Case("ExprArgument", true)
+ .Case("VariadicExprArgument", true)
+ .Default(false);
+}
+
+void GenerateIsParamExpr(const Record &Attr, raw_ostream &OS) {
+ OS << "bool isParamExpr(size_t N) const override {\n";
+ OS << " return ";
+ auto Args = Attr.getValueAsListOfDefs("Args");
+ for (size_t I = 0; I < Args.size(); ++I)
+ if (isParamExpr(Args[I]))
+ OS << "(N == " << I << ") || ";
+ OS << "false;\n";
+ OS << "}\n\n";
+}
+
+void GenerateHandleAttrWithDelayedArgs(RecordKeeper &Records, raw_ostream &OS) {
+ OS << "static void handleAttrWithDelayedArgs(Sema &S, Decl *D, ";
+ OS << "const ParsedAttr &Attr) {\n";
+ OS << " SmallVector<Expr *, 4> ArgExprs;\n";
+ OS << " ArgExprs.reserve(Attr.getNumArgs());\n";
+ OS << " for (unsigned I = 0; I < Attr.getNumArgs(); ++I) {\n";
+ OS << " assert(!Attr.isArgIdent(I));\n";
+ OS << " ArgExprs.push_back(Attr.getArgAsExpr(I));\n";
+ OS << " }\n";
+ OS << " clang::Attr *CreatedAttr = nullptr;\n";
+ OS << " switch (Attr.getKind()) {\n";
+ OS << " default:\n";
+ OS << " llvm_unreachable(\"Attribute cannot hold delayed arguments.\");\n";
+ ParsedAttrMap Attrs = getParsedAttrList(Records);
+ for (const auto &I : Attrs) {
+ const Record &R = *I.second;
+ if (!R.getValueAsBit("AcceptsExprPack"))
+ continue;
+ OS << " case ParsedAttr::AT_" << I.first << ": {\n";
+ OS << " CreatedAttr = " << R.getName() << "Attr::CreateWithDelayedArgs";
+ OS << "(S.Context, ArgExprs.data(), ArgExprs.size(), Attr);\n";
+ OS << " break;\n";
+ OS << " }\n";
+ }
+ OS << " }\n";
+ OS << " D->addAttr(CreatedAttr);\n";
+ OS << "}\n\n";
+}
+
static bool IsKnownToGCC(const Record &Attr) {
// Look at the spellings for this subject; if there are any spellings which
// claim to be known to GCC, the attribute is known to GCC.
@@ -3905,7 +4496,7 @@ static bool IsKnownToGCC(const Record &Attr) {
/// Emits the parsed attribute helpers
void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
- emitSourceFileHeader("Parsed attribute helpers", OS);
+ emitSourceFileHeader("Parsed attribute helpers", OS, Records);
OS << "#if !defined(WANT_DECL_MERGE_LOGIC) && "
<< "!defined(WANT_STMT_MERGE_LOGIC)\n";
@@ -3919,7 +4510,7 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
// Generate all of the custom appertainsTo functions that the attributes
// will be using.
- for (auto I : Attrs) {
+ for (const auto &I : Attrs) {
const Record &Attr = *I.second;
if (Attr.isValueUnset("Subjects"))
continue;
@@ -3965,35 +4556,67 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
}
OS << "};\n";
}
+
+ std::vector<std::string> ArgNames;
+ for (const auto &Arg : Attr.getValueAsListOfDefs("Args")) {
+ bool UnusedUnset;
+ if (Arg->getValueAsBitOrUnset("Fake", UnusedUnset))
+ continue;
+ ArgNames.push_back(Arg->getValueAsString("Name").str());
+ for (const auto &Class : Arg->getSuperClasses()) {
+ if (Class.first->getName().starts_with("Variadic")) {
+ ArgNames.back().append("...");
+ break;
+ }
+ }
+ }
+ if (!ArgNames.empty()) {
+ OS << "static constexpr const char *" << I->first << "ArgNames[] = {\n";
+ for (const auto &N : ArgNames)
+ OS << '"' << N << "\",";
+ OS << "};\n";
+ }
+
OS << "struct ParsedAttrInfo" << I->first
<< " final : public ParsedAttrInfo {\n";
- OS << " ParsedAttrInfo" << I->first << "() {\n";
- OS << " AttrKind = ParsedAttr::AT_" << AttrName << ";\n";
+ OS << " constexpr ParsedAttrInfo" << I->first << "() : ParsedAttrInfo(\n";
+ OS << " /*AttrKind=*/ParsedAttr::AT_" << AttrName << ",\n";
emitArgInfo(Attr, OS);
- OS << " HasCustomParsing = ";
- OS << Attr.getValueAsBit("HasCustomParsing") << ";\n";
- OS << " IsTargetSpecific = ";
- OS << Attr.isSubClassOf("TargetSpecificAttr") << ";\n";
- OS << " IsType = ";
- OS << (Attr.isSubClassOf("TypeAttr") ||
- Attr.isSubClassOf("DeclOrTypeAttr")) << ";\n";
- OS << " IsStmt = ";
+ OS << " /*HasCustomParsing=*/";
+ OS << Attr.getValueAsBit("HasCustomParsing") << ",\n";
+ OS << " /*AcceptsExprPack=*/";
+ OS << Attr.getValueAsBit("AcceptsExprPack") << ",\n";
+ OS << " /*IsTargetSpecific=*/";
+ OS << Attr.isSubClassOf("TargetSpecificAttr") << ",\n";
+ OS << " /*IsType=*/";
+ OS << (Attr.isSubClassOf("TypeAttr") || Attr.isSubClassOf("DeclOrTypeAttr"))
+ << ",\n";
+ OS << " /*IsStmt=*/";
OS << (Attr.isSubClassOf("StmtAttr") || Attr.isSubClassOf("DeclOrStmtAttr"))
- << ";\n";
- OS << " IsKnownToGCC = ";
- OS << IsKnownToGCC(Attr) << ";\n";
- OS << " IsSupportedByPragmaAttribute = ";
- OS << PragmaAttributeSupport.isAttributedSupported(*I->second) << ";\n";
+ << ",\n";
+ OS << " /*IsKnownToGCC=*/";
+ OS << IsKnownToGCC(Attr) << ",\n";
+ OS << " /*IsSupportedByPragmaAttribute=*/";
+ OS << PragmaAttributeSupport.isAttributedSupported(*I->second) << ",\n";
if (!Spellings.empty())
- OS << " Spellings = " << I->first << "Spellings;\n";
- OS << " }\n";
+ OS << " /*Spellings=*/" << I->first << "Spellings,\n";
+ else
+ OS << " /*Spellings=*/{},\n";
+ if (!ArgNames.empty())
+ OS << " /*ArgNames=*/" << I->first << "ArgNames";
+ else
+ OS << " /*ArgNames=*/{}";
+ OS << ") {}\n";
GenerateAppertainsTo(Attr, OS);
GenerateMutualExclusionsChecks(Attr, Records, OS, MergeDeclOS, MergeStmtOS);
GenerateLangOptRequirements(Attr, OS);
GenerateTargetRequirements(Attr, Dupes, OS);
+ GenerateSpellingTargetRequirements(
+ Attr, Attr.getValueAsListOfDefs("TargetSpecificSpellings"), OS);
GenerateSpellingIndexToSemanticSpelling(Attr, OS);
PragmaAttributeSupport.generateStrictConformsTo(*I->second, OS);
GenerateHandleDeclAttribute(Attr, OS);
+ GenerateIsParamExpr(Attr, OS);
OS << "static const ParsedAttrInfo" << I->first << " Instance;\n";
OS << "};\n";
OS << "const ParsedAttrInfo" << I->first << " ParsedAttrInfo" << I->first
@@ -4006,6 +4629,9 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
}
OS << "};\n\n";
+ // Generate function for handling attributes with delayed arguments
+ GenerateHandleAttrWithDelayedArgs(Records, OS);
+
// Generate the attribute match rules.
emitAttributeMatchRules(PragmaAttributeSupport, OS);
@@ -4034,11 +4660,11 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
// Emits the kind list of parsed attributes
void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) {
- emitSourceFileHeader("Attribute name matcher", OS);
+ emitSourceFileHeader("Attribute name matcher", OS, Records);
std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
std::vector<StringMatcher::StringPair> GNU, Declspec, Microsoft, CXX11,
- Keywords, Pragma, C2x;
+ Keywords, Pragma, C23, HLSLSemantic;
std::set<std::string> Seen;
for (const auto *A : Attrs) {
const Record &Attr = *A;
@@ -4060,9 +4686,8 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) {
if (Attr.isSubClassOf("TargetSpecificAttr") &&
!Attr.isValueUnset("ParseKind")) {
AttrName = std::string(Attr.getValueAsString("ParseKind"));
- if (Seen.find(AttrName) != Seen.end())
+ if (!Seen.insert(AttrName).second)
continue;
- Seen.insert(AttrName);
} else
AttrName = NormalizeAttrName(StringRef(Attr.getName())).str();
@@ -4076,8 +4701,8 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) {
Matches = &CXX11;
if (!S.nameSpace().empty())
Spelling += S.nameSpace() + "::";
- } else if (Variety == "C2x") {
- Matches = &C2x;
+ } else if (Variety == "C23") {
+ Matches = &C23;
if (!S.nameSpace().empty())
Spelling += S.nameSpace() + "::";
} else if (Variety == "GNU")
@@ -4090,6 +4715,8 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) {
Matches = &Keywords;
else if (Variety == "Pragma")
Matches = &Pragma;
+ else if (Variety == "HLSLSemantic")
+ Matches = &HLSLSemantic;
assert(Matches && "Unsupported spelling variety found");
@@ -4118,13 +4745,15 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) {
StringMatcher("Name", Microsoft, OS).Emit();
OS << " } else if (AttributeCommonInfo::AS_CXX11 == Syntax) {\n";
StringMatcher("Name", CXX11, OS).Emit();
- OS << " } else if (AttributeCommonInfo::AS_C2x == Syntax) {\n";
- StringMatcher("Name", C2x, OS).Emit();
+ OS << " } else if (AttributeCommonInfo::AS_C23 == Syntax) {\n";
+ StringMatcher("Name", C23, OS).Emit();
OS << " } else if (AttributeCommonInfo::AS_Keyword == Syntax || ";
OS << "AttributeCommonInfo::AS_ContextSensitiveKeyword == Syntax) {\n";
StringMatcher("Name", Keywords, OS).Emit();
OS << " } else if (AttributeCommonInfo::AS_Pragma == Syntax) {\n";
StringMatcher("Name", Pragma, OS).Emit();
+ OS << " } else if (AttributeCommonInfo::AS_HLSLSemantic == Syntax) {\n";
+ StringMatcher("Name", HLSLSemantic, OS).Emit();
OS << " }\n";
OS << " return AttributeCommonInfo::UnknownAttribute;\n"
<< "}\n";
@@ -4132,7 +4761,7 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) {
// Emits the code to dump an attribute.
void EmitClangAttrTextNodeDump(RecordKeeper &Records, raw_ostream &OS) {
- emitSourceFileHeader("Attribute text node dumper", OS);
+ emitSourceFileHeader("Attribute text node dumper", OS, Records);
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"), Args;
for (const auto *Attr : Attrs) {
@@ -4155,6 +4784,9 @@ void EmitClangAttrTextNodeDump(RecordKeeper &Records, raw_ostream &OS) {
for (const auto *Arg : Args)
createArgument(*Arg, R.getName())->writeDump(SS);
+ if (Attr->getValueAsBit("AcceptsExprPack"))
+ VariadicExprArgument("DelayedArgs", R.getName()).writeDump(OS);
+
if (SS.tell()) {
OS << " void Visit" << R.getName() << "Attr(const " << R.getName()
<< "Attr *A) {\n";
@@ -4168,7 +4800,7 @@ void EmitClangAttrTextNodeDump(RecordKeeper &Records, raw_ostream &OS) {
}
void EmitClangAttrNodeTraverse(RecordKeeper &Records, raw_ostream &OS) {
- emitSourceFileHeader("Attribute text node traverser", OS);
+ emitSourceFileHeader("Attribute text node traverser", OS, Records);
std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr"), Args;
for (const auto *Attr : Attrs) {
@@ -4182,6 +4814,8 @@ void EmitClangAttrNodeTraverse(RecordKeeper &Records, raw_ostream &OS) {
Args = R.getValueAsListOfDefs("Args");
for (const auto *Arg : Args)
createArgument(*Arg, R.getName())->writeDumpChildren(SS);
+ if (Attr->getValueAsBit("AcceptsExprPack"))
+ VariadicExprArgument("DelayedArgs", R.getName()).writeDumpChildren(SS);
if (SS.tell()) {
OS << " void Visit" << R.getName() << "Attr(const " << R.getName()
<< "Attr *A) {\n";
@@ -4194,13 +4828,14 @@ void EmitClangAttrNodeTraverse(RecordKeeper &Records, raw_ostream &OS) {
}
}
-void EmitClangAttrParserStringSwitches(RecordKeeper &Records,
- raw_ostream &OS) {
- emitSourceFileHeader("Parser-related llvm::StringSwitch cases", OS);
+void EmitClangAttrParserStringSwitches(RecordKeeper &Records, raw_ostream &OS) {
+ emitSourceFileHeader("Parser-related llvm::StringSwitch cases", OS, Records);
emitClangAttrArgContextList(Records, OS);
emitClangAttrIdentifierArgList(Records, OS);
+ emitClangAttrUnevaluatedStringLiteralList(Records, OS);
emitClangAttrVariadicIdentifierArgList(Records, OS);
emitClangAttrThisIsaIdentifierArgList(Records, OS);
+ emitClangAttrAcceptsExprPack(Records, OS);
emitClangAttrTypeArgList(Records, OS);
emitClangAttrLateParsedList(Records, OS);
}
@@ -4210,16 +4845,36 @@ void EmitClangAttrSubjectMatchRulesParserStringSwitches(RecordKeeper &Records,
getPragmaAttributeSupport(Records).generateParsingHelpers(OS);
}
-enum class SpellingKind {
+void EmitClangAttrDocTable(RecordKeeper &Records, raw_ostream &OS) {
+ emitSourceFileHeader("Clang attribute documentation", OS, Records);
+
+ std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
+ for (const auto *A : Attrs) {
+ if (!A->getValueAsBit("ASTNode"))
+ continue;
+ std::vector<Record *> Docs = A->getValueAsListOfDefs("Documentation");
+ assert(!Docs.empty());
+ // Only look at the first documentation if there are several.
+ // (Currently there's only one such attr, revisit if this becomes common).
+ StringRef Text =
+ Docs.front()->getValueAsOptionalString("Content").value_or("");
+ OS << "\nstatic const char AttrDoc_" << A->getName() << "[] = "
+ << "R\"reST(" << Text.trim() << ")reST\";\n";
+ }
+}
+
+enum class SpellingKind : size_t {
GNU,
CXX11,
- C2x,
+ C23,
Declspec,
Microsoft,
Keyword,
Pragma,
+ HLSLSemantic,
+ NumSpellingKinds
};
-static const size_t NumSpellingKinds = (size_t)SpellingKind::Pragma + 1;
+static const size_t NumSpellingKinds = (size_t)SpellingKind::NumSpellingKinds;
class SpellingList {
std::vector<std::string> Spellings[NumSpellingKinds];
@@ -4233,16 +4888,17 @@ public:
SpellingKind Kind = StringSwitch<SpellingKind>(Spelling.variety())
.Case("GNU", SpellingKind::GNU)
.Case("CXX11", SpellingKind::CXX11)
- .Case("C2x", SpellingKind::C2x)
+ .Case("C23", SpellingKind::C23)
.Case("Declspec", SpellingKind::Declspec)
.Case("Microsoft", SpellingKind::Microsoft)
.Case("Keyword", SpellingKind::Keyword)
- .Case("Pragma", SpellingKind::Pragma);
+ .Case("Pragma", SpellingKind::Pragma)
+ .Case("HLSLSemantic", SpellingKind::HLSLSemantic);
std::string Name;
if (!Spelling.nameSpace().empty()) {
switch (Kind) {
case SpellingKind::CXX11:
- case SpellingKind::C2x:
+ case SpellingKind::C23:
Name = Spelling.nameSpace() + "::";
break;
case SpellingKind::Pragma:
@@ -4287,7 +4943,8 @@ static void WriteCategoryHeader(const Record *DocCategory,
static std::pair<std::string, SpellingList>
GetAttributeHeadingAndSpellings(const Record &Documentation,
- const Record &Attribute) {
+ const Record &Attribute,
+ StringRef Cat) {
// FIXME: there is no way to have a per-spelling category for the attribute
// documentation. This may not be a limiting factor since the spellings
// should generally be consistently applied across the category.
@@ -4307,7 +4964,7 @@ GetAttributeHeadingAndSpellings(const Record &Documentation,
else {
std::set<std::string> Uniques;
for (auto I = Spellings.begin(), E = Spellings.end();
- I != E && Uniques.size() <= 1; ++I) {
+ I != E; ++I) {
std::string Spelling =
std::string(NormalizeNameForSpellingComparison(I->name()));
Uniques.insert(Spelling);
@@ -4316,6 +4973,11 @@ GetAttributeHeadingAndSpellings(const Record &Documentation,
// needs.
if (Uniques.size() == 1)
Heading = *Uniques.begin();
+ // If it's in the undocumented category, just construct a header by
+ // concatenating all the spellings. Might not be great, but better than
+ // nothing.
+ else if (Cat == "Undocumented")
+ Heading = llvm::join(Uniques.begin(), Uniques.end(), ", ");
}
}
@@ -4336,10 +4998,12 @@ static void WriteDocumentation(RecordKeeper &Records,
OS << Doc.Heading << "\n" << std::string(Doc.Heading.length(), '-') << "\n";
// List what spelling syntaxes the attribute supports.
+ // Note: "#pragma clang attribute" is handled outside the spelling kinds loop
+ // so it must be last.
OS << ".. csv-table:: Supported Syntaxes\n";
- OS << " :header: \"GNU\", \"C++11\", \"C2x\", \"``__declspec``\",";
- OS << " \"Keyword\", \"``#pragma``\", \"``#pragma clang attribute``\"\n\n";
- OS << " \"";
+ OS << " :header: \"GNU\", \"C++11\", \"C23\", \"``__declspec``\",";
+ OS << " \"Keyword\", \"``#pragma``\", \"HLSL Semantic\", \"``#pragma clang ";
+ OS << "attribute``\"\n\n \"";
for (size_t Kind = 0; Kind != NumSpellingKinds; ++Kind) {
SpellingKind K = (SpellingKind)Kind;
// TODO: List Microsoft (IDL-style attribute) spellings once we fully
@@ -4397,26 +5061,32 @@ void EmitClangAttrDocs(RecordKeeper &Records, raw_ostream &OS) {
// Gather the Documentation lists from each of the attributes, based on the
// category provided.
std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
- std::map<const Record *, std::vector<DocumentationData>> SplitDocs;
+ struct CategoryLess {
+ bool operator()(const Record *L, const Record *R) const {
+ return L->getValueAsString("Name") < R->getValueAsString("Name");
+ }
+ };
+ std::map<const Record *, std::vector<DocumentationData>, CategoryLess>
+ SplitDocs;
for (const auto *A : Attrs) {
const Record &Attr = *A;
std::vector<Record *> Docs = Attr.getValueAsListOfDefs("Documentation");
for (const auto *D : Docs) {
const Record &Doc = *D;
const Record *Category = Doc.getValueAsDef("Category");
- // If the category is "undocumented", then there cannot be any other
- // documentation categories (otherwise, the attribute would become
- // documented).
+ // If the category is "InternalOnly", then there cannot be any other
+ // documentation categories (otherwise, the attribute would be
+ // emitted into the docs).
const StringRef Cat = Category->getValueAsString("Name");
- bool Undocumented = Cat == "Undocumented";
- if (Undocumented && Docs.size() > 1)
+ bool InternalOnly = Cat == "InternalOnly";
+ if (InternalOnly && Docs.size() > 1)
PrintFatalError(Doc.getLoc(),
- "Attribute is \"Undocumented\", but has multiple "
+ "Attribute is \"InternalOnly\", but has multiple "
"documentation categories");
- if (!Undocumented)
+ if (!InternalOnly)
SplitDocs[Category].push_back(DocumentationData(
- Doc, Attr, GetAttributeHeadingAndSpellings(Doc, Attr)));
+ Doc, Attr, GetAttributeHeadingAndSpellings(Doc, Attr, Cat)));
}
}
diff --git a/contrib/llvm-project/clang/utils/TableGen/ClangCommentCommandInfoEmitter.cpp b/contrib/llvm-project/clang/utils/TableGen/ClangCommentCommandInfoEmitter.cpp
index eb2f23191c55..a113b02e1999 100644
--- a/contrib/llvm-project/clang/utils/TableGen/ClangCommentCommandInfoEmitter.cpp
+++ b/contrib/llvm-project/clang/utils/TableGen/ClangCommentCommandInfoEmitter.cpp
@@ -20,9 +20,10 @@
using namespace llvm;
-void clang::EmitClangCommentCommandInfo(RecordKeeper &Records, raw_ostream &OS) {
- emitSourceFileHeader("A list of commands useable in documentation "
- "comments", OS);
+void clang::EmitClangCommentCommandInfo(RecordKeeper &Records,
+ raw_ostream &OS) {
+ emitSourceFileHeader("A list of commands useable in documentation comments",
+ OS, Records);
OS << "namespace {\n"
"const CommandInfo Commands[] = {\n";
@@ -83,6 +84,12 @@ static std::string MangleName(StringRef Str) {
default:
Mangled += Str[i];
break;
+ case '(':
+ Mangled += "lparen";
+ break;
+ case ')':
+ Mangled += "rparen";
+ break;
case '[':
Mangled += "lsquare";
break;
@@ -106,9 +113,10 @@ static std::string MangleName(StringRef Str) {
return Mangled;
}
-void clang::EmitClangCommentCommandList(RecordKeeper &Records, raw_ostream &OS) {
- emitSourceFileHeader("A list of commands useable in documentation "
- "comments", OS);
+void clang::EmitClangCommentCommandList(RecordKeeper &Records,
+ raw_ostream &OS) {
+ emitSourceFileHeader("A list of commands useable in documentation comments",
+ OS, Records);
OS << "#ifndef COMMENT_COMMAND\n"
<< "# define COMMENT_COMMAND(NAME)\n"
diff --git a/contrib/llvm-project/clang/utils/TableGen/ClangCommentHTMLNamedCharacterReferenceEmitter.cpp b/contrib/llvm-project/clang/utils/TableGen/ClangCommentHTMLNamedCharacterReferenceEmitter.cpp
index 15671a99a3fc..f1cd9af0519d 100644
--- a/contrib/llvm-project/clang/utils/TableGen/ClangCommentHTMLNamedCharacterReferenceEmitter.cpp
+++ b/contrib/llvm-project/clang/utils/TableGen/ClangCommentHTMLNamedCharacterReferenceEmitter.cpp
@@ -66,12 +66,12 @@ void clang::EmitClangCommentHTMLNamedCharacterReferences(RecordKeeper &Records,
}
CLiteral.append(";");
- StringMatcher::StringPair Match(Spelling, std::string(CLiteral.str()));
+ StringMatcher::StringPair Match(Spelling, std::string(CLiteral));
NameToUTF8.push_back(Match);
}
- emitSourceFileHeader("HTML named character reference to UTF-8 "
- "translation", OS);
+ emitSourceFileHeader("HTML named character reference to UTF-8 translation",
+ OS, Records);
OS << "StringRef translateHTMLNamedCharacterReferenceToUTF8(\n"
" StringRef Name) {\n";
diff --git a/contrib/llvm-project/clang/utils/TableGen/ClangCommentHTMLTagsEmitter.cpp b/contrib/llvm-project/clang/utils/TableGen/ClangCommentHTMLTagsEmitter.cpp
index 78bbbd1cba57..3dc1098753e0 100644
--- a/contrib/llvm-project/clang/utils/TableGen/ClangCommentHTMLTagsEmitter.cpp
+++ b/contrib/llvm-project/clang/utils/TableGen/ClangCommentHTMLTagsEmitter.cpp
@@ -27,7 +27,7 @@ void clang::EmitClangCommentHTMLTags(RecordKeeper &Records, raw_ostream &OS) {
"return true;");
}
- emitSourceFileHeader("HTML tag name matcher", OS);
+ emitSourceFileHeader("HTML tag name matcher", OS, Records);
OS << "bool isHTMLTagName(StringRef Name) {\n";
StringMatcher("Name", Matches, OS).Emit();
@@ -49,7 +49,7 @@ void clang::EmitClangCommentHTMLTagsProperties(RecordKeeper &Records,
MatchesEndTagForbidden.push_back(Match);
}
- emitSourceFileHeader("HTML tag properties", OS);
+ emitSourceFileHeader("HTML tag properties", OS, Records);
OS << "bool isHTMLEndTagOptional(StringRef Name) {\n";
StringMatcher("Name", MatchesEndTagOptional, OS).Emit();
@@ -61,4 +61,3 @@ void clang::EmitClangCommentHTMLTagsProperties(RecordKeeper &Records,
OS << " return false;\n"
<< "}\n\n";
}
-
diff --git a/contrib/llvm-project/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp b/contrib/llvm-project/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp
index 014c1adcd809..480c7c83f5f8 100644
--- a/contrib/llvm-project/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp
+++ b/contrib/llvm-project/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp
@@ -12,7 +12,6 @@
#include "TableGenBackends.h"
#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -30,6 +29,7 @@
#include <cctype>
#include <functional>
#include <map>
+#include <optional>
#include <set>
using namespace llvm;
@@ -129,13 +129,14 @@ namespace {
};
struct GroupInfo {
+ llvm::StringRef GroupName;
std::vector<const Record*> DiagsInGroup;
std::vector<std::string> SubGroups;
- unsigned IDNo;
+ unsigned IDNo = 0;
llvm::SmallVector<const Record *, 1> Defs;
- GroupInfo() : IDNo(0) {}
+ GroupInfo() = default;
};
} // end anonymous namespace.
@@ -174,6 +175,7 @@ static void groupDiagnostics(const std::vector<Record*> &Diags,
Record *Group = DiagGroups[i];
GroupInfo &GI =
DiagsInGroup[std::string(Group->getValueAsString("GroupName"))];
+ GI.GroupName = Group->getName();
GI.Defs.push_back(Group);
std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups");
@@ -248,8 +250,9 @@ typedef llvm::PointerUnion<RecordVec*, RecordSet*> VecOrSet;
namespace {
class InferPedantic {
- typedef llvm::DenseMap<const Record*,
- std::pair<unsigned, Optional<unsigned> > > GMap;
+ typedef llvm::DenseMap<const Record *,
+ std::pair<unsigned, std::optional<unsigned>>>
+ GMap;
DiagGroupParentMap &DiagGroupParents;
const std::vector<Record*> &Diags;
@@ -323,7 +326,7 @@ bool InferPedantic::isOffByDefault(const Record *Diag) {
bool InferPedantic::groupInPedantic(const Record *Group, bool increment) {
GMap::mapped_type &V = GroupCount[Group];
// Lazily compute the threshold value for the group count.
- if (!V.second.hasValue()) {
+ if (!V.second) {
const GroupInfo &GI =
DiagsInGroup[std::string(Group->getValueAsString("GroupName"))];
V.second = GI.SubGroups.size() + GI.DiagsInGroup.size();
@@ -335,7 +338,7 @@ bool InferPedantic::groupInPedantic(const Record *Group, bool increment) {
// Consider a group in -Wpendatic IFF if has at least one diagnostic
// or subgroup AND all of those diagnostics and subgroups are covered
// by -Wpedantic via our computation.
- return V.first != 0 && V.first == V.second.getValue();
+ return V.first != 0 && V.first == *V.second;
}
void InferPedantic::markGroup(const Record *Group) {
@@ -402,17 +405,14 @@ void InferPedantic::compute(VecOrSet DiagsInPedantic,
if (!groupInPedantic(Group))
continue;
- unsigned ParentsInPedantic = 0;
const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
- for (unsigned j = 0, ej = Parents.size(); j != ej; ++j) {
- if (groupInPedantic(Parents[j]))
- ++ParentsInPedantic;
- }
+ bool AllParentsInPedantic =
+ llvm::all_of(Parents, [&](Record *R) { return groupInPedantic(R); });
// If all the parents are in -Wpedantic, this means that this diagnostic
// group will be indirectly included by -Wpedantic already. In that
// case, do not add it directly to -Wpedantic. If the group has no
// parents, obviously it should go into -Wpedantic.
- if (Parents.size() > 0 && ParentsInPedantic == Parents.size())
+ if (Parents.size() > 0 && AllParentsInPedantic)
continue;
if (RecordVec *V = GroupsInPedantic.dyn_cast<RecordVec*>())
@@ -614,7 +614,7 @@ struct DiagnosticTextBuilder {
return It->second.Root;
}
- LLVM_ATTRIBUTE_NORETURN void PrintFatalError(llvm::Twine const &Msg) const {
+ [[noreturn]] void PrintFatalError(llvm::Twine const &Msg) const {
assert(EvaluatingRecord && "not evaluating a record?");
llvm::PrintFatalError(EvaluatingRecord->getLoc(), Msg);
}
@@ -653,6 +653,14 @@ private:
Root(O.Root) {
O.Root = nullptr;
}
+ // The move assignment operator is defined as deleted pending further
+ // motivation.
+ DiagText &operator=(DiagText &&) = delete;
+
+ // The copy constrcutor and copy assignment operator is defined as deleted
+ // pending further motivation.
+ DiagText(const DiagText &) = delete;
+ DiagText &operator=(const DiagText &) = delete;
~DiagText() {
for (Piece *P : AllocatedPieces)
@@ -676,7 +684,7 @@ private:
};
template <class Derived> struct DiagTextVisitor {
- using ModifierMappingsType = Optional<std::vector<int>>;
+ using ModifierMappingsType = std::optional<std::vector<int>>;
private:
Derived &getDerived() { return static_cast<Derived &>(*this); }
@@ -707,7 +715,7 @@ public:
private:
DiagTextVisitor &Visitor;
- Optional<std::vector<int>> OldMappings;
+ std::optional<std::vector<int>> OldMappings;
public:
Piece *Substitution;
@@ -1166,7 +1174,7 @@ std::vector<std::string>
DiagnosticTextBuilder::buildForDocumentation(StringRef Severity,
const Record *R) {
EvaluatingRecordGuard Guard(&EvaluatingRecord, R);
- StringRef Text = R->getValueAsString("Text");
+ StringRef Text = R->getValueAsString("Summary");
DiagText D(*this, Text);
TextPiece *Prefix = D.New<TextPiece>(Severity, Severity);
@@ -1185,7 +1193,7 @@ DiagnosticTextBuilder::buildForDocumentation(StringRef Severity,
std::string DiagnosticTextBuilder::buildForDefinition(const Record *R) {
EvaluatingRecordGuard Guard(&EvaluatingRecord, R);
- StringRef Text = R->getValueAsString("Text");
+ StringRef Text = R->getValueAsString("Summary");
DiagText D(*this, Text);
std::string Result;
DiagTextPrinter{*this, Result}.Visit(D.Root);
@@ -1279,8 +1287,8 @@ void clang::EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS,
OS << ", \"";
OS.write_escaped(DiagTextBuilder.buildForDefinition(&R)) << '"';
- // Warning associated with the diagnostic. This is stored as an index into
- // the alphabetically sorted warning table.
+ // Warning group associated with the diagnostic. This is stored as an index
+ // into the alphabetically sorted warning group table.
if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) {
std::map<std::string, GroupInfo>::iterator I = DiagsInGroup.find(
std::string(DI->getDef()->getValueAsString("GroupName")));
@@ -1309,6 +1317,11 @@ void clang::EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS,
else
OS << ", false";
+ if (R.getValueAsBit("ShowInSystemMacro"))
+ OS << ", true";
+ else
+ OS << ", false";
+
if (R.getValueAsBit("Deferrable"))
OS << ", true";
else
@@ -1330,7 +1343,7 @@ static std::string getDiagCategoryEnum(llvm::StringRef name) {
SmallString<256> enumName = llvm::StringRef("DiagCat_");
for (llvm::StringRef::iterator I = name.begin(), E = name.end(); I != E; ++I)
enumName += isalnum(*I) ? *I : '_';
- return std::string(enumName.str());
+ return std::string(enumName);
}
/// Emit the array of diagnostic subgroups.
@@ -1487,18 +1500,20 @@ static void emitDiagTable(std::map<std::string, GroupInfo> &DiagsInGroup,
for (auto const &I: DiagsInGroup)
MaxLen = std::max(MaxLen, (unsigned)I.first.size());
- OS << "\n#ifdef GET_DIAG_TABLE\n";
+ OS << "\n#ifdef DIAG_ENTRY\n";
unsigned SubGroupIndex = 1, DiagArrayIndex = 1;
for (auto const &I: DiagsInGroup) {
// Group option string.
- OS << " { /* ";
+ OS << "DIAG_ENTRY(";
+ OS << I.second.GroupName << " /* ";
+
if (I.first.find_first_not_of("abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789!@#$%^*-+=:?") !=
std::string::npos)
PrintFatalError("Invalid character in diagnostic group '" + I.first +
"'");
- OS << I.first << " */ " << std::string(MaxLen - I.first.size(), ' ');
+ OS << I.first << " */, ";
// Store a pascal-style length byte at the beginning of the string.
std::string Name = char(I.first.size()) + I.first;
OS << GroupNames.GetOrAddStringOffset(Name, false) << ", ";
@@ -1517,7 +1532,7 @@ static void emitDiagTable(std::map<std::string, GroupInfo> &DiagsInGroup,
DiagArrayIndex += DiagsInPedantic.size();
DiagArrayIndex += V.size() + 1;
} else {
- OS << "/* Empty */ 0, ";
+ OS << "0, ";
}
// Subgroups.
@@ -1525,17 +1540,25 @@ static void emitDiagTable(std::map<std::string, GroupInfo> &DiagsInGroup,
const bool hasSubGroups =
!SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty());
if (hasSubGroups) {
- OS << "/* DiagSubGroup" << I.second.IDNo << " */ " << SubGroupIndex;
+ OS << "/* DiagSubGroup" << I.second.IDNo << " */ " << SubGroupIndex
+ << ", ";
if (IsPedantic)
SubGroupIndex += GroupsInPedantic.size();
SubGroupIndex += SubGroups.size() + 1;
} else {
- OS << "/* Empty */ 0";
+ OS << "0, ";
}
- OS << " },\n";
+ std::string Documentation = I.second.Defs.back()
+ ->getValue("Documentation")
+ ->getValue()
+ ->getAsUnquotedString();
+
+ OS << "R\"(" << StringRef(Documentation).trim() << ")\"";
+
+ OS << ")\n";
}
- OS << "#endif // GET_DIAG_TABLE\n\n";
+ OS << "#endif // DIAG_ENTRY\n\n";
}
/// Emit the table of diagnostic categories.
@@ -1688,7 +1711,7 @@ void writeHeader(StringRef Str, raw_ostream &OS, char Kind = '-') {
void writeDiagnosticText(DiagnosticTextBuilder &Builder, const Record *R,
StringRef Role, raw_ostream &OS) {
- StringRef Text = R->getValueAsString("Text");
+ StringRef Text = R->getValueAsString("Summary");
if (Text == "%0")
OS << "The text of this diagnostic is not controlled by Clang.\n\n";
else {
diff --git a/contrib/llvm-project/clang/utils/TableGen/ClangOpcodesEmitter.cpp b/contrib/llvm-project/clang/utils/TableGen/ClangOpcodesEmitter.cpp
index ffeedcdf0ee2..db88c990d5f9 100644
--- a/contrib/llvm-project/clang/utils/TableGen/ClangOpcodesEmitter.cpp
+++ b/contrib/llvm-project/clang/utils/TableGen/ClangOpcodesEmitter.cpp
@@ -21,7 +21,7 @@ using namespace llvm;
namespace {
class ClangOpcodesEmitter {
RecordKeeper &Records;
- Record Root;
+ const Record Root;
unsigned NumTypes;
public:
@@ -34,33 +34,32 @@ public:
private:
/// Emits the opcode name for the opcode enum.
/// The name is obtained by concatenating the name with the list of types.
- void EmitEnum(raw_ostream &OS, StringRef N, Record *R);
+ void EmitEnum(raw_ostream &OS, StringRef N, const Record *R);
/// Emits the switch case and the invocation in the interpreter.
- void EmitInterp(raw_ostream &OS, StringRef N, Record *R);
+ void EmitInterp(raw_ostream &OS, StringRef N, const Record *R);
/// Emits the disassembler.
- void EmitDisasm(raw_ostream &OS, StringRef N, Record *R);
+ void EmitDisasm(raw_ostream &OS, StringRef N, const Record *R);
/// Emits the byte code emitter method.
- void EmitEmitter(raw_ostream &OS, StringRef N, Record *R);
+ void EmitEmitter(raw_ostream &OS, StringRef N, const Record *R);
/// Emits the prototype.
- void EmitProto(raw_ostream &OS, StringRef N, Record *R);
+ void EmitProto(raw_ostream &OS, StringRef N, const Record *R);
/// Emits the prototype to dispatch from a type.
- void EmitGroup(raw_ostream &OS, StringRef N, Record *R);
+ void EmitGroup(raw_ostream &OS, StringRef N, const Record *R);
/// Emits the evaluator method.
- void EmitEval(raw_ostream &OS, StringRef N, Record *R);
+ void EmitEval(raw_ostream &OS, StringRef N, const Record *R);
- void PrintTypes(raw_ostream &OS, ArrayRef<Record *> Types);
+ void PrintTypes(raw_ostream &OS, ArrayRef<const Record *> Types);
};
-void Enumerate(const Record *R,
- StringRef N,
- std::function<void(ArrayRef<Record *>, Twine)> &&F) {
- llvm::SmallVector<Record *, 2> TypePath;
+void Enumerate(const Record *R, StringRef N,
+ std::function<void(ArrayRef<const Record *>, Twine)> &&F) {
+ llvm::SmallVector<const Record *, 2> TypePath;
auto *Types = R->getValueAsListInit("Types");
std::function<void(size_t, const Twine &)> Rec;
@@ -102,67 +101,80 @@ void ClangOpcodesEmitter::run(raw_ostream &OS) {
}
}
-void ClangOpcodesEmitter::EmitEnum(raw_ostream &OS, StringRef N, Record *R) {
+void ClangOpcodesEmitter::EmitEnum(raw_ostream &OS, StringRef N,
+ const Record *R) {
OS << "#ifdef GET_OPCODE_NAMES\n";
- Enumerate(R, N, [&OS](ArrayRef<Record *>, const Twine &ID) {
+ Enumerate(R, N, [&OS](ArrayRef<const Record *>, const Twine &ID) {
OS << "OP_" << ID << ",\n";
});
OS << "#endif\n";
}
-void ClangOpcodesEmitter::EmitInterp(raw_ostream &OS, StringRef N, Record *R) {
+void ClangOpcodesEmitter::EmitInterp(raw_ostream &OS, StringRef N,
+ const Record *R) {
OS << "#ifdef GET_INTERP\n";
- Enumerate(R, N, [this, R, &OS, &N](ArrayRef<Record *> TS, const Twine &ID) {
- bool CanReturn = R->getValueAsBit("CanReturn");
- bool ChangesPC = R->getValueAsBit("ChangesPC");
- auto Args = R->getValueAsListOfDefs("Args");
-
- OS << "case OP_" << ID << ": {\n";
-
- // Emit calls to read arguments.
- for (size_t I = 0, N = Args.size(); I < N; ++I) {
- OS << " auto V" << I;
- OS << " = ";
- OS << "PC.read<" << Args[I]->getValueAsString("Name") << ">();\n";
- }
-
- // Emit a call to the template method and pass arguments.
- OS << " if (!" << N;
- PrintTypes(OS, TS);
- OS << "(S";
- if (ChangesPC)
- OS << ", PC";
- else
- OS << ", OpPC";
- if (CanReturn)
- OS << ", Result";
- for (size_t I = 0, N = Args.size(); I < N; ++I)
- OS << ", V" << I;
- OS << "))\n";
- OS << " return false;\n";
-
- // Bail out if interpreter returned.
- if (CanReturn) {
- OS << " if (!S.Current || S.Current->isRoot())\n";
- OS << " return true;\n";
- }
-
- OS << " continue;\n";
- OS << "}\n";
- });
+ Enumerate(R, N,
+ [this, R, &OS, &N](ArrayRef<const Record *> TS, const Twine &ID) {
+ bool CanReturn = R->getValueAsBit("CanReturn");
+ bool ChangesPC = R->getValueAsBit("ChangesPC");
+ auto Args = R->getValueAsListOfDefs("Args");
+
+ OS << "case OP_" << ID << ": {\n";
+
+ if (CanReturn)
+ OS << " bool DoReturn = (S.Current == StartFrame);\n";
+
+ // Emit calls to read arguments.
+ for (size_t I = 0, N = Args.size(); I < N; ++I) {
+ OS << " auto V" << I;
+ OS << " = ";
+ OS << "ReadArg<" << Args[I]->getValueAsString("Name")
+ << ">(S, PC);\n";
+ }
+
+ // Emit a call to the template method and pass arguments.
+ OS << " if (!" << N;
+ PrintTypes(OS, TS);
+ OS << "(S";
+ if (ChangesPC)
+ OS << ", PC";
+ else
+ OS << ", OpPC";
+ if (CanReturn)
+ OS << ", Result";
+ for (size_t I = 0, N = Args.size(); I < N; ++I)
+ OS << ", V" << I;
+ OS << "))\n";
+ OS << " return false;\n";
+
+ // Bail out if interpreter returned.
+ if (CanReturn) {
+ OS << " if (!S.Current || S.Current->isRoot())\n";
+ OS << " return true;\n";
+
+ OS << " if (DoReturn)\n";
+ OS << " return true;\n";
+ }
+
+ OS << " continue;\n";
+ OS << "}\n";
+ });
OS << "#endif\n";
}
-void ClangOpcodesEmitter::EmitDisasm(raw_ostream &OS, StringRef N, Record *R) {
+void ClangOpcodesEmitter::EmitDisasm(raw_ostream &OS, StringRef N,
+ const Record *R) {
OS << "#ifdef GET_DISASM\n";
- Enumerate(R, N, [R, &OS](ArrayRef<Record *>, const Twine &ID) {
+ Enumerate(R, N, [R, &OS](ArrayRef<const Record *>, const Twine &ID) {
OS << "case OP_" << ID << ":\n";
OS << " PrintName(\"" << ID << "\");\n";
OS << " OS << \"\\t\"";
- for (auto *Arg : R->getValueAsListOfDefs("Args"))
- OS << " << PC.read<" << Arg->getValueAsString("Name") << ">() << \" \"";
+ for (auto *Arg : R->getValueAsListOfDefs("Args")) {
+ OS << " << ReadArg<" << Arg->getValueAsString("Name") << ">(P, PC)";
+ OS << " << \" \"";
+ }
OS << " << \"\\n\";\n";
OS << " continue;\n";
@@ -170,12 +182,13 @@ void ClangOpcodesEmitter::EmitDisasm(raw_ostream &OS, StringRef N, Record *R) {
OS << "#endif\n";
}
-void ClangOpcodesEmitter::EmitEmitter(raw_ostream &OS, StringRef N, Record *R) {
+void ClangOpcodesEmitter::EmitEmitter(raw_ostream &OS, StringRef N,
+ const Record *R) {
if (R->getValueAsBit("HasCustomLink"))
return;
OS << "#ifdef GET_LINK_IMPL\n";
- Enumerate(R, N, [R, &OS](ArrayRef<Record *>, const Twine &ID) {
+ Enumerate(R, N, [R, &OS](ArrayRef<const Record *>, const Twine &ID) {
auto Args = R->getValueAsListOfDefs("Args");
// Emit the list of arguments.
@@ -200,10 +213,11 @@ void ClangOpcodesEmitter::EmitEmitter(raw_ostream &OS, StringRef N, Record *R) {
OS << "#endif\n";
}
-void ClangOpcodesEmitter::EmitProto(raw_ostream &OS, StringRef N, Record *R) {
+void ClangOpcodesEmitter::EmitProto(raw_ostream &OS, StringRef N,
+ const Record *R) {
OS << "#if defined(GET_EVAL_PROTO) || defined(GET_LINK_PROTO)\n";
auto Args = R->getValueAsListOfDefs("Args");
- Enumerate(R, N, [&OS, &Args](ArrayRef<Record *> TS, const Twine &ID) {
+ Enumerate(R, N, [&OS, &Args](ArrayRef<const Record *> TS, const Twine &ID) {
OS << "bool emit" << ID << "(";
for (auto *Arg : Args)
OS << Arg->getValueAsString("Name") << ", ";
@@ -231,16 +245,19 @@ void ClangOpcodesEmitter::EmitProto(raw_ostream &OS, StringRef N, Record *R) {
OS << "#endif\n";
}
-void ClangOpcodesEmitter::EmitGroup(raw_ostream &OS, StringRef N, Record *R) {
+void ClangOpcodesEmitter::EmitGroup(raw_ostream &OS, StringRef N,
+ const Record *R) {
if (!R->getValueAsBit("HasGroup"))
return;
auto *Types = R->getValueAsListInit("Types");
auto Args = R->getValueAsListOfDefs("Args");
+ Twine EmitFuncName = "emit" + N;
+
// Emit the prototype of the group emitter in the header.
OS << "#if defined(GET_EVAL_PROTO) || defined(GET_LINK_PROTO)\n";
- OS << "bool emit" << N << "(";
+ OS << "bool " << EmitFuncName << "(";
for (size_t I = 0, N = Types->size(); I < N; ++I)
OS << "PrimType, ";
for (auto *Arg : Args)
@@ -256,7 +273,7 @@ void ClangOpcodesEmitter::EmitGroup(raw_ostream &OS, StringRef N, Record *R) {
OS << "#else\n";
OS << "ByteCodeEmitter\n";
OS << "#endif\n";
- OS << "::emit" << N << "(";
+ OS << "::" << EmitFuncName << "(";
for (size_t I = 0, N = Types->size(); I < N; ++I)
OS << "PrimType T" << I << ", ";
for (size_t I = 0, N = Args.size(); I < N; ++I)
@@ -264,8 +281,9 @@ void ClangOpcodesEmitter::EmitGroup(raw_ostream &OS, StringRef N, Record *R) {
OS << "const SourceInfo &I) {\n";
std::function<void(size_t, const Twine &)> Rec;
- llvm::SmallVector<Record *, 2> TS;
- Rec = [this, &Rec, &OS, Types, &Args, R, &TS, N](size_t I, const Twine &ID) {
+ llvm::SmallVector<const Record *, 2> TS;
+ Rec = [this, &Rec, &OS, Types, &Args, R, &TS, N,
+ EmitFuncName](size_t I, const Twine &ID) {
if (I >= Types->size()) {
// Print a call to the emitter method.
// Custom evaluator methods dispatch to template methods.
@@ -301,7 +319,8 @@ void ClangOpcodesEmitter::EmitGroup(raw_ostream &OS, StringRef N, Record *R) {
}
// Emit a default case if not all types are present.
if (Cases.size() < NumTypes)
- OS << " default: llvm_unreachable(\"invalid type\");\n";
+ OS << " default: llvm_unreachable(\"invalid type: " << EmitFuncName
+ << "\");\n";
OS << " }\n";
OS << " llvm_unreachable(\"invalid enum value\");\n";
} else {
@@ -314,34 +333,37 @@ void ClangOpcodesEmitter::EmitGroup(raw_ostream &OS, StringRef N, Record *R) {
OS << "#endif\n";
}
-void ClangOpcodesEmitter::EmitEval(raw_ostream &OS, StringRef N, Record *R) {
+void ClangOpcodesEmitter::EmitEval(raw_ostream &OS, StringRef N,
+ const Record *R) {
if (R->getValueAsBit("HasCustomEval"))
return;
OS << "#ifdef GET_EVAL_IMPL\n";
- Enumerate(R, N, [this, R, &N, &OS](ArrayRef<Record *> TS, const Twine &ID) {
- auto Args = R->getValueAsListOfDefs("Args");
-
- OS << "bool EvalEmitter::emit" << ID << "(";
- for (size_t I = 0, N = Args.size(); I < N; ++I)
- OS << Args[I]->getValueAsString("Name") << " A" << I << ", ";
- OS << "const SourceInfo &L) {\n";
- OS << " if (!isActive()) return true;\n";
- OS << " CurrentSource = L;\n";
-
- OS << " return " << N;
- PrintTypes(OS, TS);
- OS << "(S, OpPC";
- for (size_t I = 0, N = Args.size(); I < N; ++I)
- OS << ", A" << I;
- OS << ");\n";
- OS << "}\n";
- });
+ Enumerate(R, N,
+ [this, R, &N, &OS](ArrayRef<const Record *> TS, const Twine &ID) {
+ auto Args = R->getValueAsListOfDefs("Args");
+
+ OS << "bool EvalEmitter::emit" << ID << "(";
+ for (size_t I = 0, N = Args.size(); I < N; ++I)
+ OS << Args[I]->getValueAsString("Name") << " A" << I << ", ";
+ OS << "const SourceInfo &L) {\n";
+ OS << " if (!isActive()) return true;\n";
+ OS << " CurrentSource = L;\n";
+
+ OS << " return " << N;
+ PrintTypes(OS, TS);
+ OS << "(S, OpPC";
+ for (size_t I = 0, N = Args.size(); I < N; ++I)
+ OS << ", A" << I;
+ OS << ");\n";
+ OS << "}\n";
+ });
OS << "#endif\n";
}
-void ClangOpcodesEmitter::PrintTypes(raw_ostream &OS, ArrayRef<Record *> Types) {
+void ClangOpcodesEmitter::PrintTypes(raw_ostream &OS,
+ ArrayRef<const Record *> Types) {
if (Types.empty())
return;
OS << "<";
diff --git a/contrib/llvm-project/clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp b/contrib/llvm-project/clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp
index a4cb5b7cacd9..968b3e0661a8 100644
--- a/contrib/llvm-project/clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp
+++ b/contrib/llvm-project/clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp
@@ -17,6 +17,7 @@
#include "TableGenBackends.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringMap.h"
@@ -233,19 +234,18 @@ private:
MapVector<BuiltinIndexListTy *, BuiltinTableEntries> SignatureListMap;
};
-// OpenCL builtin test generator. This class processes the same TableGen input
-// as BuiltinNameEmitter, but generates a .cl file that contains a call to each
-// builtin function described in the .td input.
-class OpenCLBuiltinTestEmitter {
+/// Base class for emitting a file (e.g. header or test) from OpenCLBuiltins.td
+class OpenCLBuiltinFileEmitterBase {
public:
- OpenCLBuiltinTestEmitter(RecordKeeper &Records, raw_ostream &OS)
+ OpenCLBuiltinFileEmitterBase(RecordKeeper &Records, raw_ostream &OS)
: Records(Records), OS(OS) {}
+ virtual ~OpenCLBuiltinFileEmitterBase() = default;
// Entrypoint to generate the functions for testing all OpenCL builtin
// functions.
- void emit();
+ virtual void emit() = 0;
-private:
+protected:
struct TypeFlags {
TypeFlags() : IsConst(false), IsVolatile(false), IsPointer(false) {}
bool IsConst : 1;
@@ -282,6 +282,27 @@ private:
expandTypesInSignature(const std::vector<Record *> &Signature,
SmallVectorImpl<SmallVector<std::string, 2>> &Types);
+ // Emit extension enabling pragmas.
+ void emitExtensionSetup();
+
+ // Emit an #if guard for a Builtin's extension. Return the corresponding
+ // closing #endif, or an empty string if no extension #if guard was emitted.
+ std::string emitExtensionGuard(const Record *Builtin);
+
+ // Emit an #if guard for a Builtin's language version. Return the
+ // corresponding closing #endif, or an empty string if no version #if guard
+ // was emitted.
+ std::string emitVersionGuard(const Record *Builtin);
+
+ // Emit an #if guard for all type extensions required for the given type
+ // strings. Return the corresponding closing #endif, or an empty string
+ // if no extension #if guard was emitted.
+ StringRef
+ emitTypeExtensionGuards(const SmallVectorImpl<std::string> &Signature);
+
+ // Map type strings to type extensions (e.g. "half2" -> "cl_khr_fp16").
+ StringMap<StringRef> TypeExtMap;
+
// Contains OpenCL builtin functions and related information, stored as
// Record instances. They are coming from the associated TableGen file.
RecordKeeper &Records;
@@ -290,10 +311,35 @@ private:
raw_ostream &OS;
};
+// OpenCL builtin test generator. This class processes the same TableGen input
+// as BuiltinNameEmitter, but generates a .cl file that contains a call to each
+// builtin function described in the .td input.
+class OpenCLBuiltinTestEmitter : public OpenCLBuiltinFileEmitterBase {
+public:
+ OpenCLBuiltinTestEmitter(RecordKeeper &Records, raw_ostream &OS)
+ : OpenCLBuiltinFileEmitterBase(Records, OS) {}
+
+ // Entrypoint to generate the functions for testing all OpenCL builtin
+ // functions.
+ void emit() override;
+};
+
+// OpenCL builtin header generator. This class processes the same TableGen
+// input as BuiltinNameEmitter, but generates a .h file that contains a
+// prototype for each builtin function described in the .td input.
+class OpenCLBuiltinHeaderEmitter : public OpenCLBuiltinFileEmitterBase {
+public:
+ OpenCLBuiltinHeaderEmitter(RecordKeeper &Records, raw_ostream &OS)
+ : OpenCLBuiltinFileEmitterBase(Records, OS) {}
+
+ // Entrypoint to generate the header.
+ void emit() override;
+};
+
} // namespace
void BuiltinNameEmitter::Emit() {
- emitSourceFileHeader("OpenCL Builtin handling", OS);
+ emitSourceFileHeader("OpenCL Builtin handling", OS, Records);
OS << "#include \"llvm/ADT/StringRef.h\"\n";
OS << "using namespace clang;\n\n";
@@ -323,7 +369,7 @@ void BuiltinNameEmitter::ExtractEnumTypes(std::vector<Record *> &Types,
raw_string_ostream SS(Output);
for (const auto *T : Types) {
- if (TypesSeen.find(T->getValueAsString("Name")) == TypesSeen.end()) {
+ if (!TypesSeen.contains(T->getValueAsString("Name"))) {
SS << " OCLT_" + T->getValueAsString("Name") << ",\n";
// Save the type names in the same order as their enum value. Note that
// the Record can be a VectorType or something else, only the name is
@@ -464,7 +510,7 @@ void BuiltinNameEmitter::GetOverloads() {
std::vector<Record *> Builtins = Records.getAllDerivedDefinitions("Builtin");
for (const auto *B : Builtins) {
StringRef BName = B->getValueAsString("Name");
- if (FctOverloadMap.find(BName) == FctOverloadMap.end()) {
+ if (!FctOverloadMap.contains(BName)) {
FctOverloadMap.insert(std::make_pair(
BName, std::vector<std::pair<const Record *, unsigned>>{}));
}
@@ -472,10 +518,10 @@ void BuiltinNameEmitter::GetOverloads() {
auto Signature = B->getValueAsListOfDefs("Signature");
// Reuse signatures to avoid unnecessary duplicates.
auto it =
- std::find_if(SignaturesList.begin(), SignaturesList.end(),
- [&](const std::pair<std::vector<Record *>, unsigned> &a) {
- return a.first == Signature;
- });
+ llvm::find_if(SignaturesList,
+ [&](const std::pair<std::vector<Record *>, unsigned> &a) {
+ return a.first == Signature;
+ });
unsigned SignIndex;
if (it == SignaturesList.end()) {
VerifySignature(Signature, B);
@@ -564,7 +610,7 @@ static unsigned short EncodeVersions(unsigned int MinVersion,
}
unsigned VersionIDs[] = {100, 110, 120, 200, 300};
- for (unsigned I = 0; I < sizeof(VersionIDs) / sizeof(VersionIDs[0]); I++) {
+ for (unsigned I = 0; I < std::size(VersionIDs); I++) {
if (VersionIDs[I] >= MinVersion && VersionIDs[I] < MaxVersion) {
Encoded |= 1 << I;
}
@@ -709,6 +755,20 @@ static std::pair<unsigned, unsigned> isOpenCLBuiltin(llvm::StringRef Name) {
OS << "} // isOpenCLBuiltin\n";
}
+// Emit an if-statement with an isMacroDefined call for each extension in
+// the space-separated list of extensions.
+static void EmitMacroChecks(raw_ostream &OS, StringRef Extensions) {
+ SmallVector<StringRef, 2> ExtVec;
+ Extensions.split(ExtVec, " ");
+ OS << " if (";
+ for (StringRef Ext : ExtVec) {
+ if (Ext != ExtVec.front())
+ OS << " && ";
+ OS << "S.getPreprocessor().isMacroDefined(\"" << Ext << "\")";
+ }
+ OS << ") {\n ";
+}
+
void BuiltinNameEmitter::EmitQualTypeFinder() {
OS << R"(
@@ -774,15 +834,24 @@ static void OCL2Qual(Sema &S, const OpenCLTypeStruct &Ty,
<< " case OCLAQ_None:\n"
<< " llvm_unreachable(\"Image without access qualifier\");\n";
for (const auto &Image : ITE.getValue()) {
+ StringRef Exts =
+ Image->getValueAsDef("Extension")->getValueAsString("ExtName");
OS << StringSwitch<const char *>(
Image->getValueAsString("AccessQualifier"))
.Case("RO", " case OCLAQ_ReadOnly:\n")
.Case("WO", " case OCLAQ_WriteOnly:\n")
- .Case("RW", " case OCLAQ_ReadWrite:\n")
- << " QT.push_back("
+ .Case("RW", " case OCLAQ_ReadWrite:\n");
+ if (!Exts.empty()) {
+ OS << " ";
+ EmitMacroChecks(OS, Exts);
+ }
+ OS << " QT.push_back("
<< Image->getValueAsDef("QTExpr")->getValueAsString("TypeExpr")
- << ");\n"
- << " break;\n";
+ << ");\n";
+ if (!Exts.empty()) {
+ OS << " }\n";
+ }
+ OS << " break;\n";
}
OS << " }\n"
<< " break;\n";
@@ -801,15 +870,14 @@ static void OCL2Qual(Sema &S, const OpenCLTypeStruct &Ty,
// Collect all QualTypes for a single vector size into TypeList.
OS << " SmallVector<QualType, " << BaseTypes.size() << "> TypeList;\n";
for (const auto *T : BaseTypes) {
- StringRef Ext =
+ StringRef Exts =
T->getValueAsDef("Extension")->getValueAsString("ExtName");
- if (!Ext.empty()) {
- OS << " if (S.getPreprocessor().isMacroDefined(\"" << Ext
- << "\")) {\n ";
+ if (!Exts.empty()) {
+ EmitMacroChecks(OS, Exts);
}
OS << " TypeList.push_back("
<< T->getValueAsDef("QTExpr")->getValueAsString("TypeExpr") << ");\n";
- if (!Ext.empty()) {
+ if (!Exts.empty()) {
OS << " }\n";
}
}
@@ -839,10 +907,10 @@ static void OCL2Qual(Sema &S, const OpenCLTypeStruct &Ty,
for (const auto *T : Types) {
// Check this is not an image type
- if (ImageTypesMap.find(T->getValueAsString("Name")) != ImageTypesMap.end())
+ if (ImageTypesMap.contains(T->getValueAsString("Name")))
continue;
// Check we have not seen this Type
- if (TypesSeen.find(T->getValueAsString("Name")) != TypesSeen.end())
+ if (TypesSeen.contains(T->getValueAsString("Name")))
continue;
TypesSeen.insert(std::make_pair(T->getValueAsString("Name"), true));
@@ -853,15 +921,14 @@ static void OCL2Qual(Sema &S, const OpenCLTypeStruct &Ty,
// Emit the cases for non generic, non image types.
OS << " case OCLT_" << T->getValueAsString("Name") << ":\n";
- StringRef Ext = T->getValueAsDef("Extension")->getValueAsString("ExtName");
- // If this type depends on an extension, ensure the extension macro is
+ StringRef Exts = T->getValueAsDef("Extension")->getValueAsString("ExtName");
+ // If this type depends on an extension, ensure the extension macros are
// defined.
- if (!Ext.empty()) {
- OS << " if (S.getPreprocessor().isMacroDefined(\"" << Ext
- << "\")) {\n ";
+ if (!Exts.empty()) {
+ EmitMacroChecks(OS, Exts);
}
OS << " QT.push_back(" << QT->getValueAsString("TypeExpr") << ");\n";
- if (!Ext.empty()) {
+ if (!Exts.empty()) {
OS << " }\n";
}
OS << " break;\n";
@@ -923,9 +990,9 @@ static void OCL2Qual(Sema &S, const OpenCLTypeStruct &Ty,
OS << "\n} // OCL2Qual\n";
}
-std::string OpenCLBuiltinTestEmitter::getTypeString(const Record *Type,
- TypeFlags Flags,
- int VectorSize) const {
+std::string OpenCLBuiltinFileEmitterBase::getTypeString(const Record *Type,
+ TypeFlags Flags,
+ int VectorSize) const {
std::string S;
if (Type->getValueAsBit("IsConst") || Flags.IsConst) {
S += "const ";
@@ -970,7 +1037,7 @@ std::string OpenCLBuiltinTestEmitter::getTypeString(const Record *Type,
return S;
}
-void OpenCLBuiltinTestEmitter::getTypeLists(
+void OpenCLBuiltinFileEmitterBase::getTypeLists(
Record *Type, TypeFlags &Flags, std::vector<Record *> &TypeList,
std::vector<int64_t> &VectorList) const {
bool isGenType = Type->isSubClassOf("GenericType");
@@ -1003,7 +1070,7 @@ void OpenCLBuiltinTestEmitter::getTypeLists(
VectorList.push_back(Type->getValueAsInt("VecWidth"));
}
-void OpenCLBuiltinTestEmitter::expandTypesInSignature(
+void OpenCLBuiltinFileEmitterBase::expandTypesInSignature(
const std::vector<Record *> &Signature,
SmallVectorImpl<SmallVector<std::string, 2>> &Types) {
// Find out if there are any GenTypes in this signature, and if so, calculate
@@ -1021,7 +1088,16 @@ void OpenCLBuiltinTestEmitter::expandTypesInSignature(
// Insert the Cartesian product of the types and vector sizes.
for (const auto &Vector : VectorList) {
for (const auto &Type : TypeList) {
- ExpandedArg.push_back(getTypeString(Type, Flags, Vector));
+ std::string FullType = getTypeString(Type, Flags, Vector);
+ ExpandedArg.push_back(FullType);
+
+ // If the type requires an extension, add a TypeExtMap entry mapping
+ // the full type name to the extension.
+ StringRef Ext =
+ Type->getValueAsDef("Extension")->getValueAsString("ExtName");
+ if (!Ext.empty() && !TypeExtMap.contains(FullType)) {
+ TypeExtMap.insert({FullType, Ext});
+ }
}
}
NumSignatures = std::max<unsigned>(NumSignatures, ExpandedArg.size());
@@ -1044,10 +1120,7 @@ void OpenCLBuiltinTestEmitter::expandTypesInSignature(
}
}
-void OpenCLBuiltinTestEmitter::emit() {
- emitSourceFileHeader("OpenCL Builtin exhaustive testing", OS);
-
- // Enable some extensions for testing.
+void OpenCLBuiltinFileEmitterBase::emitExtensionSetup() {
OS << R"(
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
#pragma OPENCL EXTENSION cl_khr_fp64 : enable
@@ -1058,6 +1131,93 @@ void OpenCLBuiltinTestEmitter::emit() {
#pragma OPENCL EXTENSION cl_khr_3d_image_writes : enable
)";
+}
+
+std::string
+OpenCLBuiltinFileEmitterBase::emitExtensionGuard(const Record *Builtin) {
+ StringRef Extensions =
+ Builtin->getValueAsDef("Extension")->getValueAsString("ExtName");
+ if (Extensions.empty())
+ return "";
+
+ OS << "#if";
+
+ SmallVector<StringRef, 2> ExtVec;
+ Extensions.split(ExtVec, " ");
+ bool isFirst = true;
+ for (StringRef Ext : ExtVec) {
+ if (!isFirst) {
+ OS << " &&";
+ }
+ OS << " defined(" << Ext << ")";
+ isFirst = false;
+ }
+ OS << "\n";
+
+ return "#endif // Extension\n";
+}
+
+std::string
+OpenCLBuiltinFileEmitterBase::emitVersionGuard(const Record *Builtin) {
+ std::string OptionalEndif;
+ auto PrintOpenCLVersion = [this](int Version) {
+ OS << "CL_VERSION_" << (Version / 100) << "_" << ((Version % 100) / 10);
+ };
+ int MinVersion = Builtin->getValueAsDef("MinVersion")->getValueAsInt("ID");
+ if (MinVersion != 100) {
+ // OpenCL 1.0 is the default minimum version.
+ OS << "#if __OPENCL_C_VERSION__ >= ";
+ PrintOpenCLVersion(MinVersion);
+ OS << "\n";
+ OptionalEndif = "#endif // MinVersion\n" + OptionalEndif;
+ }
+ int MaxVersion = Builtin->getValueAsDef("MaxVersion")->getValueAsInt("ID");
+ if (MaxVersion) {
+ OS << "#if __OPENCL_C_VERSION__ < ";
+ PrintOpenCLVersion(MaxVersion);
+ OS << "\n";
+ OptionalEndif = "#endif // MaxVersion\n" + OptionalEndif;
+ }
+ return OptionalEndif;
+}
+
+StringRef OpenCLBuiltinFileEmitterBase::emitTypeExtensionGuards(
+ const SmallVectorImpl<std::string> &Signature) {
+ SmallSet<StringRef, 2> ExtSet;
+
+ // Iterate over all types to gather the set of required TypeExtensions.
+ for (const auto &Ty : Signature) {
+ StringRef TypeExt = TypeExtMap.lookup(Ty);
+ if (!TypeExt.empty()) {
+ // The TypeExtensions are space-separated in the .td file.
+ SmallVector<StringRef, 2> ExtVec;
+ TypeExt.split(ExtVec, " ");
+ for (const auto Ext : ExtVec) {
+ ExtSet.insert(Ext);
+ }
+ }
+ }
+
+ // Emit the #if only when at least one extension is required.
+ if (ExtSet.empty())
+ return "";
+
+ OS << "#if ";
+ bool isFirst = true;
+ for (const auto Ext : ExtSet) {
+ if (!isFirst)
+ OS << " && ";
+ OS << "defined(" << Ext << ")";
+ isFirst = false;
+ }
+ OS << "\n";
+ return "#endif // TypeExtension\n";
+}
+
+void OpenCLBuiltinTestEmitter::emit() {
+ emitSourceFileHeader("OpenCL Builtin exhaustive testing", OS, Records);
+
+ emitExtensionSetup();
// Ensure each test has a unique name by numbering them.
unsigned TestID = 0;
@@ -1071,44 +1231,13 @@ void OpenCLBuiltinTestEmitter::emit() {
expandTypesInSignature(B->getValueAsListOfDefs("Signature"), FTypes);
OS << "// Test " << Name << "\n";
- std::string OptionalEndif;
- StringRef Extensions =
- B->getValueAsDef("Extension")->getValueAsString("ExtName");
- if (!Extensions.empty()) {
- OS << "#if";
- OptionalEndif = "#endif // Extension\n";
- SmallVector<StringRef, 2> ExtVec;
- Extensions.split(ExtVec, " ");
- bool isFirst = true;
- for (StringRef Ext : ExtVec) {
- if (!isFirst) {
- OS << " &&";
- }
- OS << " defined(" << Ext << ")";
- isFirst = false;
- }
- OS << "\n";
- }
- auto PrintOpenCLVersion = [this](int Version) {
- OS << "CL_VERSION_" << (Version / 100) << "_" << ((Version % 100) / 10);
- };
- int MinVersion = B->getValueAsDef("MinVersion")->getValueAsInt("ID");
- if (MinVersion != 100) {
- // OpenCL 1.0 is the default minimum version.
- OS << "#if __OPENCL_C_VERSION__ >= ";
- PrintOpenCLVersion(MinVersion);
- OS << "\n";
- OptionalEndif = "#endif // MinVersion\n" + OptionalEndif;
- }
- int MaxVersion = B->getValueAsDef("MaxVersion")->getValueAsInt("ID");
- if (MaxVersion) {
- OS << "#if __OPENCL_C_VERSION__ < ";
- PrintOpenCLVersion(MaxVersion);
- OS << "\n";
- OptionalEndif = "#endif // MaxVersion\n" + OptionalEndif;
- }
+ std::string OptionalExtensionEndif = emitExtensionGuard(B);
+ std::string OptionalVersionEndif = emitVersionGuard(B);
+
for (const auto &Signature : FTypes) {
+ StringRef OptionalTypeExtEndif = emitTypeExtensionGuards(Signature);
+
// Emit function declaration.
OS << Signature[0] << " test" << TestID++ << "_" << Name << "(";
if (Signature.size() > 1) {
@@ -1135,16 +1264,84 @@ void OpenCLBuiltinTestEmitter::emit() {
// End of function body.
OS << "}\n";
+ OS << OptionalTypeExtEndif;
}
- OS << OptionalEndif << "\n";
+
+ OS << OptionalVersionEndif;
+ OS << OptionalExtensionEndif;
}
}
+void OpenCLBuiltinHeaderEmitter::emit() {
+ emitSourceFileHeader("OpenCL Builtin declarations", OS, Records);
+
+ emitExtensionSetup();
+
+ OS << R"(
+#define __ovld __attribute__((overloadable))
+#define __conv __attribute__((convergent))
+#define __purefn __attribute__((pure))
+#define __cnfn __attribute__((const))
+
+)";
+
+ // Iterate over all builtins; sort to follow order of definition in .td file.
+ std::vector<Record *> Builtins = Records.getAllDerivedDefinitions("Builtin");
+ llvm::sort(Builtins, LessRecord());
+
+ for (const auto *B : Builtins) {
+ StringRef Name = B->getValueAsString("Name");
+
+ std::string OptionalExtensionEndif = emitExtensionGuard(B);
+ std::string OptionalVersionEndif = emitVersionGuard(B);
+
+ SmallVector<SmallVector<std::string, 2>, 4> FTypes;
+ expandTypesInSignature(B->getValueAsListOfDefs("Signature"), FTypes);
+
+ for (const auto &Signature : FTypes) {
+ StringRef OptionalTypeExtEndif = emitTypeExtensionGuards(Signature);
+
+ // Emit function declaration.
+ OS << Signature[0] << " __ovld ";
+ if (B->getValueAsBit("IsConst"))
+ OS << "__cnfn ";
+ if (B->getValueAsBit("IsPure"))
+ OS << "__purefn ";
+ if (B->getValueAsBit("IsConv"))
+ OS << "__conv ";
+
+ OS << Name << "(";
+ if (Signature.size() > 1) {
+ for (unsigned I = 1; I < Signature.size(); I++) {
+ if (I != 1)
+ OS << ", ";
+ OS << Signature[I];
+ }
+ }
+ OS << ");\n";
+
+ OS << OptionalTypeExtEndif;
+ }
+
+ OS << OptionalVersionEndif;
+ OS << OptionalExtensionEndif;
+ }
+
+ OS << "\n// Disable any extensions we may have enabled previously.\n"
+ "#pragma OPENCL EXTENSION all : disable\n";
+}
+
void clang::EmitClangOpenCLBuiltins(RecordKeeper &Records, raw_ostream &OS) {
BuiltinNameEmitter NameChecker(Records, OS);
NameChecker.Emit();
}
+void clang::EmitClangOpenCLBuiltinHeader(RecordKeeper &Records,
+ raw_ostream &OS) {
+ OpenCLBuiltinHeaderEmitter HeaderFileGenerator(Records, OS);
+ HeaderFileGenerator.emit();
+}
+
void clang::EmitClangOpenCLBuiltinTests(RecordKeeper &Records,
raw_ostream &OS) {
OpenCLBuiltinTestEmitter TestFileGenerator(Records, OS);
diff --git a/contrib/llvm-project/clang/utils/TableGen/ClangOptionDocEmitter.cpp b/contrib/llvm-project/clang/utils/TableGen/ClangOptionDocEmitter.cpp
index 0e079b6b505a..a4095950ca97 100644
--- a/contrib/llvm-project/clang/utils/TableGen/ClangOptionDocEmitter.cpp
+++ b/contrib/llvm-project/clang/utils/TableGen/ClangOptionDocEmitter.cpp
@@ -31,13 +31,40 @@ struct DocumentedGroup;
struct Documentation {
std::vector<DocumentedGroup> Groups;
std::vector<DocumentedOption> Options;
+
+ bool empty() {
+ return Groups.empty() && Options.empty();
+ }
};
struct DocumentedGroup : Documentation {
Record *Group;
};
+static bool hasFlag(const Record *Option, StringRef OptionFlag,
+ StringRef FlagsField) {
+ for (const Record *Flag : Option->getValueAsListOfDefs(FlagsField))
+ if (Flag->getName() == OptionFlag)
+ return true;
+ if (const DefInit *DI = dyn_cast<DefInit>(Option->getValueInit("Group")))
+ for (const Record *Flag : DI->getDef()->getValueAsListOfDefs(FlagsField))
+ if (Flag->getName() == OptionFlag)
+ return true;
+ return false;
+}
+
+static bool isOptionVisible(const Record *Option, const Record *DocInfo) {
+ for (StringRef IgnoredFlag : DocInfo->getValueAsListOfStrings("IgnoreFlags"))
+ if (hasFlag(Option, IgnoredFlag, "Flags"))
+ return false;
+ for (StringRef Mask : DocInfo->getValueAsListOfStrings("VisibilityMask"))
+ if (hasFlag(Option, Mask, "Visibility"))
+ return true;
+ return false;
+}
+
// Reorganize the records into a suitable form for emitting documentation.
-Documentation extractDocumentation(RecordKeeper &Records) {
+Documentation extractDocumentation(RecordKeeper &Records,
+ const Record *DocInfo) {
Documentation Result;
// Build the tree of groups. The root in the tree is the fake option group
@@ -124,12 +151,15 @@ Documentation extractDocumentation(RecordKeeper &Records) {
D.Groups.back().Group = G;
Documentation &Base = D.Groups.back();
Base = DocumentationForGroup(G);
+ if (Base.empty())
+ D.Groups.pop_back();
}
auto &Options = OptionsInGroup[R];
llvm::sort(Options, CompareByName);
for (Record *O : Options)
- D.Options.push_back(DocumentationForOption(O));
+ if (isOptionVisible(O, DocInfo))
+ D.Options.push_back(DocumentationForOption(O));
return D;
};
@@ -161,25 +191,10 @@ unsigned getNumArgsForKind(Record *OptionKind, const Record *Option) {
.Default(0);
}
-bool hasFlag(const Record *OptionOrGroup, StringRef OptionFlag) {
- for (const Record *Flag : OptionOrGroup->getValueAsListOfDefs("Flags"))
- if (Flag->getName() == OptionFlag)
- return true;
- return false;
-}
-
-bool isExcluded(const Record *OptionOrGroup, const Record *DocInfo) {
- // FIXME: Provide a flag to specify the set of exclusions.
- for (StringRef Exclusion : DocInfo->getValueAsListOfStrings("ExcludedFlags"))
- if (hasFlag(OptionOrGroup, Exclusion))
- return true;
- return false;
-}
-
std::string escapeRST(StringRef Str) {
std::string Out;
for (auto K : Str) {
- if (StringRef("`*|_[]\\").count(K))
+ if (StringRef("`*|[]\\").count(K))
Out.push_back('\\');
Out.push_back(K);
}
@@ -238,6 +253,8 @@ void emitOptionWithArgs(StringRef Prefix, const Record *Option,
}
}
+constexpr StringLiteral DefaultMetaVarName = "<arg>";
+
void emitOptionName(StringRef Prefix, const Record *Option, raw_ostream &OS) {
// Find the arguments to list after the option.
unsigned NumArgs = getNumArgsForKind(Option->getValueAsDef("Kind"), Option);
@@ -247,7 +264,7 @@ void emitOptionName(StringRef Prefix, const Record *Option, raw_ostream &OS) {
if (HasMetaVarName)
Args.push_back(std::string(Option->getValueAsString("MetaVarName")));
else if (NumArgs == 1)
- Args.push_back("<arg>");
+ Args.push_back(DefaultMetaVarName.str());
// Fill up arguments if this option didn't provide a meta var name or it
// supports an unlimited number of arguments. We can't see how many arguments
@@ -294,14 +311,13 @@ void forEachOptionName(const DocumentedOption &Option, const Record *DocInfo,
F(Option.Option);
for (auto *Alias : Option.Aliases)
- if (!isExcluded(Alias, DocInfo) && canSphinxCopeWithOption(Option.Option))
+ if (isOptionVisible(Alias, DocInfo) &&
+ canSphinxCopeWithOption(Option.Option))
F(Alias);
}
void emitOption(const DocumentedOption &Option, const Record *DocInfo,
raw_ostream &OS) {
- if (isExcluded(Option.Option, DocInfo))
- return;
if (Option.Option->getValueAsDef("Kind")->getName() == "KIND_UNKNOWN" ||
Option.Option->getValueAsDef("Kind")->getName() == "KIND_INPUT")
return;
@@ -341,8 +357,30 @@ void emitOption(const DocumentedOption &Option, const Record *DocInfo,
OS << "\n\n";
// Emit the description, if we have one.
+ const Record *R = Option.Option;
std::string Description =
- getRSTStringWithTextFallback(Option.Option, "DocBrief", "HelpText");
+ getRSTStringWithTextFallback(R, "DocBrief", "HelpText");
+
+ if (!isa<UnsetInit>(R->getValueInit("Values"))) {
+ if (!Description.empty() && Description.back() != '.')
+ Description.push_back('.');
+
+ StringRef MetaVarName;
+ if (!isa<UnsetInit>(R->getValueInit("MetaVarName")))
+ MetaVarName = R->getValueAsString("MetaVarName");
+ else
+ MetaVarName = DefaultMetaVarName;
+
+ SmallVector<StringRef> Values;
+ SplitString(R->getValueAsString("Values"), Values, ",");
+ Description += (" " + MetaVarName + " must be '").str();
+ if (Values.size() > 1) {
+ Description += join(Values.begin(), Values.end() - 1, "', '");
+ Description += "' or '";
+ }
+ Description += (Values.back() + "'.").str();
+ }
+
if (!Description.empty())
OS << Description << "\n\n";
}
@@ -352,9 +390,6 @@ void emitDocumentation(int Depth, const Documentation &Doc,
void emitGroup(int Depth, const DocumentedGroup &Group, const Record *DocInfo,
raw_ostream &OS) {
- if (isExcluded(Group.Group, DocInfo))
- return;
-
emitHeading(Depth,
getRSTStringWithTextFallback(Group.Group, "DocName", "Name"), OS);
@@ -388,5 +423,5 @@ void clang::EmitClangOptDocs(RecordKeeper &Records, raw_ostream &OS) {
OS << DocInfo->getValueAsString("Intro") << "\n";
OS << ".. program:: " << DocInfo->getValueAsString("Program") << "\n";
- emitDocumentation(0, extractDocumentation(Records), DocInfo, OS);
+ emitDocumentation(0, extractDocumentation(Records, DocInfo), DocInfo, OS);
}
diff --git a/contrib/llvm-project/clang/utils/TableGen/ClangSACheckersEmitter.cpp b/contrib/llvm-project/clang/utils/TableGen/ClangSACheckersEmitter.cpp
index 00d88274fc38..2a2e466ae197 100644
--- a/contrib/llvm-project/clang/utils/TableGen/ClangSACheckersEmitter.cpp
+++ b/contrib/llvm-project/clang/utils/TableGen/ClangSACheckersEmitter.cpp
@@ -24,28 +24,29 @@ using namespace llvm;
// Static Analyzer Checkers Tables generation
//===----------------------------------------------------------------------===//
-static std::string getPackageFullName(const Record *R);
+static std::string getPackageFullName(const Record *R, StringRef Sep = ".");
-static std::string getParentPackageFullName(const Record *R) {
+static std::string getParentPackageFullName(const Record *R,
+ StringRef Sep = ".") {
std::string name;
if (DefInit *DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage")))
- name = getPackageFullName(DI->getDef());
+ name = getPackageFullName(DI->getDef(), Sep);
return name;
}
-static std::string getPackageFullName(const Record *R) {
- std::string name = getParentPackageFullName(R);
+static std::string getPackageFullName(const Record *R, StringRef Sep) {
+ std::string name = getParentPackageFullName(R, Sep);
if (!name.empty())
- name += ".";
+ name += Sep;
assert(!R->getValueAsString("PackageName").empty());
name += R->getValueAsString("PackageName");
return name;
}
-static std::string getCheckerFullName(const Record *R) {
- std::string name = getParentPackageFullName(R);
+static std::string getCheckerFullName(const Record *R, StringRef Sep = ".") {
+ std::string name = getParentPackageFullName(R, Sep);
if (!name.empty())
- name += ".";
+ name += Sep;
assert(!R->getValueAsString("CheckerName").empty());
name += R->getValueAsString("CheckerName");
return name;
@@ -74,20 +75,18 @@ static inline uint64_t getValueFromBitsInit(const BitsInit *B, const Record &R)
}
static std::string getCheckerDocs(const Record &R) {
- StringRef LandingPage;
- if (BitsInit *BI = R.getValueAsBitsInit("Documentation")) {
- uint64_t V = getValueFromBitsInit(BI, R);
- if (V == 1)
- LandingPage = "available_checks.html";
- else if (V == 2)
- LandingPage = "alpha_checks.html";
- }
-
- if (LandingPage.empty())
+ const BitsInit *BI = R.getValueAsBitsInit("Documentation");
+ if (!BI)
+ PrintFatalError(R.getLoc(), "missing Documentation<...> member for " +
+ getCheckerFullName(&R));
+
+ // Ignore 'Documentation<NotDocumented>' checkers.
+ if (getValueFromBitsInit(BI, R) == 0)
return "";
- return (llvm::Twine("https://clang-analyzer.llvm.org/") + LandingPage + "#" +
- getCheckerFullName(&R))
+ std::string CheckerFullName = StringRef(getCheckerFullName(&R, "-")).lower();
+ return (llvm::Twine("https://clang.llvm.org/docs/analyzer/checkers.html#") +
+ CheckerFullName)
.str();
}
@@ -220,7 +219,7 @@ void clang::EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) {
// - DESCRIPTION
// - DEFAULT: The default value for this option.
//
- // The full option can be specified in the command like like this:
+ // The full option can be specified in the command like this:
// -analyzer-config PACKAGENAME:OPTIONNAME=VALUE
OS << "\n"
"#ifdef GET_PACKAGE_OPTIONS\n";
@@ -320,7 +319,7 @@ void clang::EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) {
// - DESCRIPTION
// - DEFAULT: The default value for this option.
//
- // The full option can be specified in the command like like this:
+ // The full option can be specified in the command like this:
// -analyzer-config CHECKERNAME:OPTIONNAME=VALUE
OS << "\n"
"#ifdef GET_CHECKER_OPTIONS\n";
diff --git a/contrib/llvm-project/clang/utils/TableGen/ClangSyntaxEmitter.cpp b/contrib/llvm-project/clang/utils/TableGen/ClangSyntaxEmitter.cpp
index a940edbb1d24..9720d5873184 100644
--- a/contrib/llvm-project/clang/utils/TableGen/ClangSyntaxEmitter.cpp
+++ b/contrib/llvm-project/clang/utils/TableGen/ClangSyntaxEmitter.cpp
@@ -129,7 +129,7 @@ struct SyntaxConstraint {
void clang::EmitClangSyntaxNodeList(llvm::RecordKeeper &Records,
llvm::raw_ostream &OS) {
- llvm::emitSourceFileHeader("Syntax tree node list", OS);
+ llvm::emitSourceFileHeader("Syntax tree node list", OS, Records);
Hierarchy H(Records);
OS << R"cpp(
#ifndef NODE
@@ -188,7 +188,7 @@ static void printDoc(llvm::StringRef Doc, llvm::raw_ostream &OS) {
void clang::EmitClangSyntaxNodeClasses(llvm::RecordKeeper &Records,
llvm::raw_ostream &OS) {
- llvm::emitSourceFileHeader("Syntax tree node list", OS);
+ llvm::emitSourceFileHeader("Syntax tree node list", OS, Records);
Hierarchy H(Records);
OS << "\n// Forward-declare node types so we don't have to carefully "
diff --git a/contrib/llvm-project/clang/utils/TableGen/ClangTypeNodesEmitter.cpp b/contrib/llvm-project/clang/utils/TableGen/ClangTypeNodesEmitter.cpp
index 690042f3200e..66bdf5e67602 100644
--- a/contrib/llvm-project/clang/utils/TableGen/ClangTypeNodesEmitter.cpp
+++ b/contrib/llvm-project/clang/utils/TableGen/ClangTypeNodesEmitter.cpp
@@ -104,7 +104,7 @@ void TypeNodeEmitter::emit() {
if (Types.empty())
PrintFatalError("no Type records in input!");
- emitSourceFileHeader("An x-macro database of Clang type nodes", Out);
+ emitSourceFileHeader("An x-macro database of Clang type nodes", Out, Records);
// Preamble
addMacroToUndef(TypeMacroName);
diff --git a/contrib/llvm-project/clang/utils/TableGen/MveEmitter.cpp b/contrib/llvm-project/clang/utils/TableGen/MveEmitter.cpp
index 091af2dc52a1..496cb10d14f2 100644
--- a/contrib/llvm-project/clang/utils/TableGen/MveEmitter.cpp
+++ b/contrib/llvm-project/clang/utils/TableGen/MveEmitter.cpp
@@ -212,6 +212,7 @@ public:
std::string llvmName() const override {
return "llvm::PointerType::getUnqual(" + Pointee->llvmName() + ")";
}
+ const Type *getPointeeType() const { return Pointee; }
static bool classof(const Type *T) {
return T->typeKind() == TypeKind::Pointer;
@@ -349,13 +350,8 @@ public:
bool requiresFloat() const override { return false; };
bool requiresMVE() const override { return true; }
std::string llvmName() const override {
- // Use <4 x i1> instead of <2 x i1> for two-lane vector types. See
- // the comment in llvm/lib/Target/ARM/ARMInstrMVE.td for further
- // explanation.
- unsigned ModifiedLanes = (Lanes == 2 ? 4 : Lanes);
-
- return "llvm::FixedVectorType::get(Builder.getInt1Ty(), " +
- utostr(ModifiedLanes) + ")";
+ return "llvm::FixedVectorType::get(Builder.getInt1Ty(), " + utostr(Lanes) +
+ ")";
}
static bool classof(const Type *T) {
@@ -707,12 +703,14 @@ public:
class AddressResult : public Result {
public:
Ptr Arg;
+ const Type *Ty;
unsigned Align;
- AddressResult(Ptr Arg, unsigned Align) : Arg(Arg), Align(Align) {}
+ AddressResult(Ptr Arg, const Type *Ty, unsigned Align)
+ : Arg(Arg), Ty(Ty), Align(Align) {}
void genCode(raw_ostream &OS,
CodeGenParamAllocator &ParamAlloc) const override {
- OS << "Address(" << Arg->varname() << ", CharUnits::fromQuantity("
- << Align << "))";
+ OS << "Address(" << Arg->varname() << ", " << Ty->llvmName()
+ << ", CharUnits::fromQuantity(" << Align << "))";
}
std::string typeName() const override {
return "Address";
@@ -884,7 +882,7 @@ public:
} else if (V->varnameUsed()) {
std::string Type = V->typeName();
OS << V->typeName();
- if (!StringRef(Type).endswith("*"))
+ if (!StringRef(Type).ends_with("*"))
OS << " ";
OS << V->varname() << " = ";
}
@@ -898,7 +896,7 @@ public:
llvm::APInt i = iOrig.trunc(64);
SmallString<40> s;
i.toString(s, 16, true, true);
- return std::string(s.str());
+ return std::string(s);
}
std::string genSema() const {
@@ -1194,13 +1192,21 @@ Result::Ptr EmitterBase::getCodeForDag(DagInit *D, const Result::Scope &Scope,
if (D->getNumArgs() != 2)
PrintFatalError("'address' should have two arguments");
Result::Ptr Arg = getCodeForDagArg(D, 0, Scope, Param);
+
+ const Type *Ty = nullptr;
+ if (auto *DI = dyn_cast<DagInit>(D->getArg(0)))
+ if (auto *PTy = dyn_cast<PointerType>(getType(DI->getOperator(), Param)))
+ Ty = PTy->getPointeeType();
+ if (!Ty)
+ PrintFatalError("'address' pointer argument should be a pointer");
+
unsigned Alignment;
if (auto *II = dyn_cast<IntInit>(D->getArg(1))) {
Alignment = II->getValue();
} else {
PrintFatalError("'address' alignment argument should be an integer");
}
- return std::make_shared<AddressResult>(Arg, Alignment);
+ return std::make_shared<AddressResult>(Arg, Ty, Alignment);
} else if (Op->getName() == "unsignedflag") {
if (D->getNumArgs() != 1)
PrintFatalError("unsignedflag should have exactly one argument");
@@ -1494,8 +1500,7 @@ protected:
class raw_self_contained_string_ostream : private string_holder,
public raw_string_ostream {
public:
- raw_self_contained_string_ostream()
- : string_holder(), raw_string_ostream(S) {}
+ raw_self_contained_string_ostream() : raw_string_ostream(S) {}
};
const char LLVMLicenseHeader[] =
@@ -1675,7 +1680,7 @@ void EmitterBase::EmitBuiltinCG(raw_ostream &OS) {
for (size_t i = 0, e = MG.ParamTypes.size(); i < e; ++i) {
StringRef Type = MG.ParamTypes[i];
OS << " " << Type;
- if (!Type.endswith("*"))
+ if (!Type.ends_with("*"))
OS << " ";
OS << " Param" << utostr(i) << ";\n";
}
@@ -1828,7 +1833,7 @@ void MveEmitter::EmitHeader(raw_ostream &OS) {
// prototype.
std::string RetTypeName = Int.returnType()->cName();
- if (!StringRef(RetTypeName).endswith("*"))
+ if (!StringRef(RetTypeName).ends_with("*"))
RetTypeName += " ";
std::vector<std::string> ArgTypeNames;
@@ -1941,8 +1946,8 @@ void MveEmitter::EmitHeader(raw_ostream &OS) {
void MveEmitter::EmitBuiltinDef(raw_ostream &OS) {
for (const auto &kv : ACLEIntrinsics) {
const ACLEIntrinsic &Int = *kv.second;
- OS << "TARGET_HEADER_BUILTIN(__builtin_arm_mve_" << Int.fullName()
- << ", \"\", \"n\", \"arm_mve.h\", ALL_LANGUAGES, \"\")\n";
+ OS << "BUILTIN(__builtin_arm_mve_" << Int.fullName()
+ << ", \"\", \"n\")\n";
}
std::set<std::string> ShortNamesSeen;
@@ -2073,7 +2078,7 @@ void CdeEmitter::EmitHeader(raw_ostream &OS) {
// Make strings for the types involved in the function's
// prototype.
std::string RetTypeName = Int.returnType()->cName();
- if (!StringRef(RetTypeName).endswith("*"))
+ if (!StringRef(RetTypeName).ends_with("*"))
RetTypeName += " ";
std::vector<std::string> ArgTypeNames;
@@ -2151,8 +2156,8 @@ void CdeEmitter::EmitBuiltinDef(raw_ostream &OS) {
if (kv.second->headerOnly())
continue;
const ACLEIntrinsic &Int = *kv.second;
- OS << "TARGET_HEADER_BUILTIN(__builtin_arm_cde_" << Int.fullName()
- << ", \"\", \"ncU\", \"arm_cde.h\", ALL_LANGUAGES, \"\")\n";
+ OS << "BUILTIN(__builtin_arm_cde_" << Int.fullName()
+ << ", \"\", \"ncU\")\n";
}
}
diff --git a/contrib/llvm-project/clang/utils/TableGen/NeonEmitter.cpp b/contrib/llvm-project/clang/utils/TableGen/NeonEmitter.cpp
index f0da1a7d2f4e..53334016c180 100644
--- a/contrib/llvm-project/clang/utils/TableGen/NeonEmitter.cpp
+++ b/contrib/llvm-project/clang/utils/TableGen/NeonEmitter.cpp
@@ -26,8 +26,6 @@
#include "TableGenBackends.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/None.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
@@ -45,6 +43,7 @@
#include <cstdint>
#include <deque>
#include <map>
+#include <optional>
#include <set>
#include <sstream>
#include <string>
@@ -292,7 +291,7 @@ class Variable {
std::string N;
public:
- Variable() : T(Type::getVoid()), N("") {}
+ Variable() : T(Type::getVoid()) {}
Variable(Type T, std::string N) : T(std::move(T)), N(std::move(N)) {}
Type getType() const { return T; }
@@ -321,8 +320,10 @@ class Intrinsic {
/// The list of DAGs for the body. May be empty, in which case we should
/// emit a builtin call.
ListInit *Body;
- /// The architectural #ifdef guard.
- std::string Guard;
+ /// The architectural ifdef guard.
+ std::string ArchGuard;
+ /// The architectural target() guard.
+ std::string TargetGuard;
/// Set if the Unavailable bit is 1. This means we don't generate a body,
/// just an "unavailable" attribute on a declaration.
bool IsUnavailable;
@@ -368,9 +369,9 @@ class Intrinsic {
public:
Intrinsic(Record *R, StringRef Name, StringRef Proto, TypeSpec OutTS,
TypeSpec InTS, ClassKind CK, ListInit *Body, NeonEmitter &Emitter,
- StringRef Guard, bool IsUnavailable, bool BigEndianSafe)
+ StringRef ArchGuard, StringRef TargetGuard, bool IsUnavailable, bool BigEndianSafe)
: R(R), Name(Name.str()), OutTS(OutTS), InTS(InTS), CK(CK), Body(Body),
- Guard(Guard.str()), IsUnavailable(IsUnavailable),
+ ArchGuard(ArchGuard.str()), TargetGuard(TargetGuard.str()), IsUnavailable(IsUnavailable),
BigEndianSafe(BigEndianSafe), PolymorphicKeyType(0), NeededEarly(false),
UseMacro(false), BaseType(OutTS, "."), InBaseType(InTS, "."),
Emitter(Emitter) {
@@ -382,13 +383,13 @@ public:
StringRef Mods = getNextModifiers(Proto, Pos);
while (!Mods.empty()) {
Types.emplace_back(InTS, Mods);
- if (Mods.find('!') != StringRef::npos)
+ if (Mods.contains('!'))
PolymorphicKeyType = Types.size() - 1;
Mods = getNextModifiers(Proto, Pos);
}
- for (auto Type : Types) {
+ for (const auto &Type : Types) {
// If this builtin takes an immediate argument, we need to #define it rather
// than use a standard declaration, so that SemaChecking can range check
// the immediate passed by the user.
@@ -411,14 +412,14 @@ public:
/// transitive closure.
const std::set<Intrinsic *> &getDependencies() const { return Dependencies; }
/// Get the architectural guard string (#ifdef).
- std::string getGuard() const { return Guard; }
+ std::string getArchGuard() const { return ArchGuard; }
+ std::string getTargetGuard() const { return TargetGuard; }
/// Get the non-mangled name.
std::string getName() const { return Name; }
/// Return true if the intrinsic takes an immediate operand.
bool hasImmediate() const {
- return std::any_of(Types.begin(), Types.end(),
- [](const Type &T) { return T.isImmediate(); });
+ return llvm::any_of(Types, [](const Type &T) { return T.isImmediate(); });
}
/// Return the parameter index of the immediate operand.
@@ -442,7 +443,7 @@ public:
/// Return the index that parameter PIndex will sit at
/// in a generated function call. This is often just PIndex,
/// but may not be as things such as multiple-vector operands
- /// and sret parameters need to be taken into accont.
+ /// and sret parameters need to be taken into account.
unsigned getGeneratedParamIdx(unsigned PIndex) {
unsigned Idx = 0;
if (getReturnType().getNumVectors() > 1)
@@ -460,9 +461,11 @@ public:
void setNeededEarly() { NeededEarly = true; }
bool operator<(const Intrinsic &Other) const {
- // Sort lexicographically on a two-tuple (Guard, Name)
- if (Guard != Other.Guard)
- return Guard < Other.Guard;
+ // Sort lexicographically on a three-tuple (ArchGuard, TargetGuard, Name)
+ if (ArchGuard != Other.ArchGuard)
+ return ArchGuard < Other.ArchGuard;
+ if (TargetGuard != Other.TargetGuard)
+ return TargetGuard < Other.TargetGuard;
return Name < Other.Name;
}
@@ -503,6 +506,7 @@ private:
void emitBody(StringRef CallPrefix);
void emitShadowedArgs();
void emitArgumentReversal();
+ void emitReturnVarDecl();
void emitReturnReversal();
void emitReverseVariable(Variable &Dest, Variable &Src);
void emitNewLine();
@@ -546,6 +550,8 @@ class NeonEmitter {
void createIntrinsic(Record *R, SmallVectorImpl<Intrinsic *> &Out);
void genBuiltinsDef(raw_ostream &OS, SmallVectorImpl<Intrinsic *> &Defs);
+ void genStreamingSVECompatibleList(raw_ostream &OS,
+ SmallVectorImpl<Intrinsic *> &Defs);
void genOverloadTypeCheckCode(raw_ostream &OS,
SmallVectorImpl<Intrinsic *> &Defs);
void genIntrinsicRangeCheckCode(raw_ostream &OS,
@@ -555,7 +561,7 @@ public:
/// Called by Intrinsic - this attempts to get an intrinsic that takes
/// the given types as arguments.
Intrinsic &getIntrinsic(StringRef Name, ArrayRef<Type> Types,
- Optional<std::string> MangledName);
+ std::optional<std::string> MangledName);
/// Called by Intrinsic - returns a globally-unique number.
unsigned getUniqueNumber() { return UniqueNumber++; }
@@ -589,6 +595,8 @@ public:
// Emit arm_bf16.h.inc
void runBF16(raw_ostream &o);
+ void runVectorTypes(raw_ostream &o);
+
// Emit all the __builtin prototypes used in arm_neon.h, arm_fp16.h and
// arm_bf16.h
void runHeader(raw_ostream &o);
@@ -732,17 +740,17 @@ Type Type::fromTypedefName(StringRef Name) {
Name = Name.drop_front();
}
- if (Name.startswith("float")) {
+ if (Name.starts_with("float")) {
T.Kind = Float;
Name = Name.drop_front(5);
- } else if (Name.startswith("poly")) {
+ } else if (Name.starts_with("poly")) {
T.Kind = Poly;
Name = Name.drop_front(4);
- } else if (Name.startswith("bfloat")) {
+ } else if (Name.starts_with("bfloat")) {
T.Kind = BFloat16;
Name = Name.drop_front(6);
} else {
- assert(Name.startswith("int"));
+ assert(Name.starts_with("int"));
Name = Name.drop_front(3);
}
@@ -783,7 +791,7 @@ Type Type::fromTypedefName(StringRef Name) {
Name = Name.drop_front(I);
}
- assert(Name.startswith("_t") && "Malformed typedef!");
+ assert(Name.starts_with("_t") && "Malformed typedef!");
return T;
}
@@ -817,19 +825,19 @@ void Type::applyTypespec(bool &Quad) {
break;
case 'h':
Kind = Float;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case 's':
ElementBitwidth = 16;
break;
case 'f':
Kind = Float;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case 'i':
ElementBitwidth = 32;
break;
case 'd':
Kind = Float;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case 'l':
ElementBitwidth = 64;
break;
@@ -951,7 +959,7 @@ std::string Intrinsic::getInstTypeCode(Type T, ClassKind CK) const {
char typeCode = '\0';
bool printNumber = true;
- if (CK == ClassB)
+ if (CK == ClassB && TargetGuard == "")
return "";
if (T.isBFloat16())
@@ -975,7 +983,7 @@ std::string Intrinsic::getInstTypeCode(Type T, ClassKind CK) const {
break;
}
}
- if (CK == ClassB) {
+ if (CK == ClassB && TargetGuard == "") {
typeCode = '\0';
}
@@ -1077,7 +1085,7 @@ std::string Intrinsic::mangleName(std::string Name, ClassKind LocalCK) const {
S += "_" + getInstTypeCode(InBaseType, LocalCK);
}
- if (LocalCK == ClassB)
+ if (LocalCK == ClassB && TargetGuard == "")
S += "_v";
// Insert a 'q' before the first '_' character so that it ends up before
@@ -1137,10 +1145,14 @@ void Intrinsic::initVariables() {
}
void Intrinsic::emitPrototype(StringRef NamePrefix) {
- if (UseMacro)
+ if (UseMacro) {
OS << "#define ";
- else
- OS << "__ai " << Types[0].str() << " ";
+ } else {
+ OS << "__ai ";
+ if (TargetGuard != "")
+ OS << "__attribute__((target(\"" << TargetGuard << "\"))) ";
+ OS << Types[0].str() << " ";
+ }
OS << NamePrefix.str() << mangleName(Name, ClassS) << "(";
@@ -1229,6 +1241,15 @@ void Intrinsic::emitArgumentReversal() {
}
}
+void Intrinsic::emitReturnVarDecl() {
+ assert(RetVar.getType() == Types[0]);
+ // Create a return variable, if we're not void.
+ if (!RetVar.getType().isVoid()) {
+ OS << " " << RetVar.getType().str() << " " << RetVar.getName() << ";";
+ emitNewLine();
+ }
+}
+
void Intrinsic::emitReturnReversal() {
if (isBigEndianSafe())
return;
@@ -1271,9 +1292,8 @@ void Intrinsic::emitShadowedArgs() {
}
bool Intrinsic::protoHasScalar() const {
- return std::any_of(Types.begin(), Types.end(), [](const Type &T) {
- return T.isScalar() && !T.isImmediate();
- });
+ return llvm::any_of(
+ Types, [](const Type &T) { return T.isScalar() && !T.isImmediate(); });
}
void Intrinsic::emitBodyAsBuiltinCall() {
@@ -1308,7 +1328,7 @@ void Intrinsic::emitBodyAsBuiltinCall() {
if (LocalCK == ClassB) {
Type T2 = T;
T2.makeOneVector();
- T2.makeInteger(8, /*Signed=*/true);
+ T2.makeInteger(8, /*Sign=*/true);
Cast = "(" + T2.str() + ")";
}
@@ -1355,13 +1375,6 @@ void Intrinsic::emitBodyAsBuiltinCall() {
void Intrinsic::emitBody(StringRef CallPrefix) {
std::vector<std::string> Lines;
- assert(RetVar.getType() == Types[0]);
- // Create a return variable, if we're not void.
- if (!RetVar.getType().isVoid()) {
- OS << " " << RetVar.getType().str() << " " << RetVar.getName() << ";";
- emitNewLine();
- }
-
if (!Body || Body->getValues().empty()) {
// Nothing specific to output - must output a builtin.
emitBodyAsBuiltinCall();
@@ -1462,7 +1475,7 @@ Intrinsic::DagEmitter::emitDagCall(DagInit *DI, bool MatchMangledName) {
N = SI->getAsUnquotedString();
else
N = emitDagArg(DI->getArg(0), "").second;
- Optional<std::string> MangledName;
+ std::optional<std::string> MangledName;
if (MatchMangledName) {
if (Intr.getRecord()->getValueAsBit("isLaneQ"))
N += "q";
@@ -1475,7 +1488,7 @@ Intrinsic::DagEmitter::emitDagCall(DagInit *DI, bool MatchMangledName) {
Intr.Dependencies.insert(&Callee);
// Now create the call itself.
- std::string S = "";
+ std::string S;
if (!Callee.isBigEndianSafe())
S += CallPrefix.str();
S += Callee.getMangledName(true) + "(";
@@ -1641,12 +1654,12 @@ std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagShuffle(DagInit *DI){
std::make_unique<Rev>(Arg1.first.getElementSizeInBits()));
ST.addExpander("MaskExpand",
std::make_unique<MaskExpander>(Arg1.first.getNumElements()));
- ST.evaluate(DI->getArg(2), Elts, None);
+ ST.evaluate(DI->getArg(2), Elts, std::nullopt);
std::string S = "__builtin_shufflevector(" + Arg1.second + ", " + Arg2.second;
for (auto &E : Elts) {
StringRef Name = E->getName();
- assert_with_loc(Name.startswith("sv"),
+ assert_with_loc(Name.starts_with("sv"),
"Incorrect element kind in shuffle mask!");
S += ", " + Name.drop_front(2).str();
}
@@ -1851,6 +1864,9 @@ void Intrinsic::generateImpl(bool ReverseArguments,
OS << " __attribute__((unavailable));";
} else {
emitOpeningBrace();
+ // Emit return variable declaration first as to not trigger
+ // -Wdeclaration-after-statement.
+ emitReturnVarDecl();
emitShadowedArgs();
if (ReverseArguments)
emitArgumentReversal();
@@ -1869,6 +1885,9 @@ void Intrinsic::indexBody() {
CurrentRecord = R;
initVariables();
+ // Emit return variable declaration first as to not trigger
+ // -Wdeclaration-after-statement.
+ emitReturnVarDecl();
emitBody("");
OS.str("");
@@ -1880,7 +1899,7 @@ void Intrinsic::indexBody() {
//===----------------------------------------------------------------------===//
Intrinsic &NeonEmitter::getIntrinsic(StringRef Name, ArrayRef<Type> Types,
- Optional<std::string> MangledName) {
+ std::optional<std::string> MangledName) {
// First, look up the name in the intrinsic map.
assert_with_loc(IntrinsicMap.find(Name.str()) != IntrinsicMap.end(),
("Intrinsic '" + Name + "' not found!").str());
@@ -1916,10 +1935,9 @@ Intrinsic &NeonEmitter::getIntrinsic(StringRef Name, ArrayRef<Type> Types,
continue;
unsigned ArgNum = 0;
- bool MatchingArgumentTypes =
- std::all_of(Types.begin(), Types.end(), [&](const auto &Type) {
- return Type == I.getParamType(ArgNum++);
- });
+ bool MatchingArgumentTypes = llvm::all_of(Types, [&](const auto &Type) {
+ return Type == I.getParamType(ArgNum++);
+ });
if (MatchingArgumentTypes)
GoodVec.push_back(&I);
@@ -1939,7 +1957,8 @@ void NeonEmitter::createIntrinsic(Record *R,
std::string Types = std::string(R->getValueAsString("Types"));
Record *OperationRec = R->getValueAsDef("Operation");
bool BigEndianSafe = R->getValueAsBit("BigEndianSafe");
- std::string Guard = std::string(R->getValueAsString("ArchGuard"));
+ std::string ArchGuard = std::string(R->getValueAsString("ArchGuard"));
+ std::string TargetGuard = std::string(R->getValueAsString("TargetGuard"));
bool IsUnavailable = OperationRec->getValueAsBit("Unavailable");
std::string CartesianProductWith = std::string(R->getValueAsString("CartesianProductWith"));
@@ -1981,7 +2000,7 @@ void NeonEmitter::createIntrinsic(Record *R,
for (auto &I : NewTypeSpecs) {
Entry.emplace_back(R, Name, Proto, I.first, I.second, CK, Body, *this,
- Guard, IsUnavailable, BigEndianSafe);
+ ArchGuard, TargetGuard, IsUnavailable, BigEndianSafe);
Out.push_back(&Entry.back());
}
@@ -1996,22 +2015,55 @@ void NeonEmitter::genBuiltinsDef(raw_ostream &OS,
// We only want to emit a builtin once, and we want to emit them in
// alphabetical order, so use a std::set.
- std::set<std::string> Builtins;
+ std::set<std::pair<std::string, std::string>> Builtins;
for (auto *Def : Defs) {
if (Def->hasBody())
continue;
- std::string S = "BUILTIN(__builtin_neon_" + Def->getMangledName() + ", \"";
-
+ std::string S = "__builtin_neon_" + Def->getMangledName() + ", \"";
S += Def->getBuiltinTypeStr();
- S += "\", \"n\")";
+ S += "\", \"n\"";
- Builtins.insert(S);
+ Builtins.emplace(S, Def->getTargetGuard());
+ }
+
+ for (auto &S : Builtins) {
+ if (S.second == "")
+ OS << "BUILTIN(";
+ else
+ OS << "TARGET_BUILTIN(";
+ OS << S.first;
+ if (S.second == "")
+ OS << ")\n";
+ else
+ OS << ", \"" << S.second << "\")\n";
}
- for (auto &S : Builtins)
- OS << S << "\n";
+ OS << "#endif\n\n";
+}
+
+void NeonEmitter::genStreamingSVECompatibleList(
+ raw_ostream &OS, SmallVectorImpl<Intrinsic *> &Defs) {
+ OS << "#ifdef GET_NEON_STREAMING_COMPAT_FLAG\n";
+
+ std::set<std::string> Emitted;
+ for (auto *Def : Defs) {
+ // If the def has a body (that is, it has Operation DAGs), it won't call
+ // __builtin_neon_* so we don't need to generate a definition for it.
+ if (Def->hasBody())
+ continue;
+
+ std::string Name = Def->getMangledName();
+ if (Emitted.find(Name) != Emitted.end())
+ continue;
+
+ // FIXME: We should make exceptions here for some NEON builtins that are
+ // permitted in streaming mode.
+ OS << "case NEON::BI__builtin_neon_" << Name
+ << ": BuiltinType = ArmNonStreaming; break;\n";
+ Emitted.insert(Name);
+ }
OS << "#endif\n\n";
}
@@ -2025,10 +2077,10 @@ void NeonEmitter::genOverloadTypeCheckCode(raw_ostream &OS,
// definitions may extend the number of permitted types (i.e. augment the
// Mask). Use std::map to avoid sorting the table by hash number.
struct OverloadInfo {
- uint64_t Mask;
- int PtrArgNum;
- bool HasConstPtr;
- OverloadInfo() : Mask(0ULL), PtrArgNum(0), HasConstPtr(false) {}
+ uint64_t Mask = 0ULL;
+ int PtrArgNum = 0;
+ bool HasConstPtr = false;
+ OverloadInfo() = default;
};
std::map<std::string, OverloadInfo> OverloadMap;
@@ -2062,12 +2114,13 @@ void NeonEmitter::genOverloadTypeCheckCode(raw_ostream &OS,
std::string Name = Def->getName();
// Omit type checking for the pointer arguments of vld1_lane, vld1_dup,
- // and vst1_lane intrinsics. Using a pointer to the vector element
- // type with one of those operations causes codegen to select an aligned
- // load/store instruction. If you want an unaligned operation,
- // the pointer argument needs to have less alignment than element type,
- // so just accept any pointer type.
- if (Name == "vld1_lane" || Name == "vld1_dup" || Name == "vst1_lane") {
+ // vst1_lane, vldap1_lane, and vstl1_lane intrinsics. Using a pointer to
+ // the vector element type with one of those operations causes codegen to
+ // select an aligned load/store instruction. If you want an unaligned
+ // operation, the pointer argument needs to have less alignment than element
+ // type, so just accept any pointer type.
+ if (Name == "vld1_lane" || Name == "vld1_dup" || Name == "vst1_lane" ||
+ Name == "vldap1_lane" || Name == "vstl1_lane") {
PtrArgNum = -1;
HasConstPtr = false;
}
@@ -2197,6 +2250,8 @@ void NeonEmitter::runHeader(raw_ostream &OS) {
// Generate ARM overloaded type checking code for SemaChecking.cpp
genOverloadTypeCheckCode(OS, Defs);
+ genStreamingSVECompatibleList(OS, Defs);
+
// Generate ARM range checking code for shift/lane immediates.
genIntrinsicRangeCheckCode(OS, Defs);
}
@@ -2328,18 +2383,9 @@ void NeonEmitter::run(raw_ostream &OS) {
OS << "#include <stdint.h>\n\n";
- OS << "#ifdef __ARM_FEATURE_BF16\n";
OS << "#include <arm_bf16.h>\n";
- OS << "typedef __bf16 bfloat16_t;\n";
- OS << "#endif\n\n";
- // Emit NEON-specific scalar typedefs.
- OS << "typedef float float32_t;\n";
- OS << "typedef __fp16 float16_t;\n";
-
- OS << "#ifdef __aarch64__\n";
- OS << "typedef double float64_t;\n";
- OS << "#endif\n\n";
+ OS << "#include <arm_vector_types.h>\n";
// For now, signedness of polynomial types depends on target
OS << "#ifdef __aarch64__\n";
@@ -2352,12 +2398,7 @@ void NeonEmitter::run(raw_ostream &OS) {
OS << "typedef int16_t poly16_t;\n";
OS << "typedef int64_t poly64_t;\n";
OS << "#endif\n";
-
- emitNeonTypeDefs("cQcsQsiQilQlUcQUcUsQUsUiQUiUlQUlhQhfQfdQdPcQPcPsQPsPlQPl", OS);
-
- OS << "#ifdef __ARM_FEATURE_BF16\n";
- emitNeonTypeDefs("bQb", OS);
- OS << "#endif\n\n";
+ emitNeonTypeDefs("PcQPcPsQPsPlQPl", OS);
OS << "#define __ai static __inline__ __attribute__((__always_inline__, "
"__nodebug__))\n\n";
@@ -2393,10 +2434,10 @@ void NeonEmitter::run(raw_ostream &OS) {
}
// Emit #endif/#if pair if needed.
- if ((*I)->getGuard() != InGuard) {
+ if ((*I)->getArchGuard() != InGuard) {
if (!InGuard.empty())
OS << "#endif\n";
- InGuard = (*I)->getGuard();
+ InGuard = (*I)->getArchGuard();
if (!InGuard.empty())
OS << "#if " << InGuard << "\n";
}
@@ -2502,10 +2543,10 @@ void NeonEmitter::runFP16(raw_ostream &OS) {
}
// Emit #endif/#if pair if needed.
- if ((*I)->getGuard() != InGuard) {
+ if ((*I)->getArchGuard() != InGuard) {
if (!InGuard.empty())
OS << "#endif\n";
- InGuard = (*I)->getGuard();
+ InGuard = (*I)->getArchGuard();
if (!InGuard.empty())
OS << "#if " << InGuard << "\n";
}
@@ -2526,6 +2567,38 @@ void NeonEmitter::runFP16(raw_ostream &OS) {
OS << "#endif /* __ARM_FP16_H */\n";
}
+void NeonEmitter::runVectorTypes(raw_ostream &OS) {
+ OS << "/*===---- arm_vector_types - ARM vector type "
+ "------===\n"
+ " *\n"
+ " *\n"
+ " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
+ "Exceptions.\n"
+ " * See https://llvm.org/LICENSE.txt for license information.\n"
+ " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
+ " *\n"
+ " *===-----------------------------------------------------------------"
+ "------===\n"
+ " */\n\n";
+ OS << "#if !defined(__ARM_NEON_H) && !defined(__ARM_SVE_H)\n";
+ OS << "#error \"This file should not be used standalone. Please include"
+ " arm_neon.h or arm_sve.h instead\"\n\n";
+ OS << "#endif\n";
+ OS << "#ifndef __ARM_NEON_TYPES_H\n";
+ OS << "#define __ARM_NEON_TYPES_H\n";
+ OS << "typedef float float32_t;\n";
+ OS << "typedef __fp16 float16_t;\n";
+
+ OS << "#ifdef __aarch64__\n";
+ OS << "typedef double float64_t;\n";
+ OS << "#endif\n\n";
+
+ emitNeonTypeDefs("cQcsQsiQilQlUcQUcUsQUsUiQUiUlQUlhQhfQfdQd", OS);
+
+ emitNeonTypeDefs("bQb", OS);
+ OS << "#endif // __ARM_NEON_TYPES_H\n";
+}
+
void NeonEmitter::runBF16(raw_ostream &OS) {
OS << "/*===---- arm_bf16.h - ARM BF16 intrinsics "
"-----------------------------------===\n"
@@ -2579,10 +2652,10 @@ void NeonEmitter::runBF16(raw_ostream &OS) {
}
// Emit #endif/#if pair if needed.
- if ((*I)->getGuard() != InGuard) {
+ if ((*I)->getArchGuard() != InGuard) {
if (!InGuard.empty())
OS << "#endif\n";
- InGuard = (*I)->getGuard();
+ InGuard = (*I)->getArchGuard();
if (!InGuard.empty())
OS << "#if " << InGuard << "\n";
}
@@ -2620,6 +2693,10 @@ void clang::EmitNeonSema(RecordKeeper &Records, raw_ostream &OS) {
NeonEmitter(Records).runHeader(OS);
}
+void clang::EmitVectorTypes(RecordKeeper &Records, raw_ostream &OS) {
+ NeonEmitter(Records).runVectorTypes(OS);
+}
+
void clang::EmitNeonTest(RecordKeeper &Records, raw_ostream &OS) {
llvm_unreachable("Neon test generation no longer implemented!");
}
diff --git a/contrib/llvm-project/clang/utils/TableGen/RISCVVEmitter.cpp b/contrib/llvm-project/clang/utils/TableGen/RISCVVEmitter.cpp
index 24f2250c9ae0..2ca47f1ba59f 100644
--- a/contrib/llvm-project/clang/utils/TableGen/RISCVVEmitter.cpp
+++ b/contrib/llvm-project/clang/utils/TableGen/RISCVVEmitter.cpp
@@ -14,205 +14,87 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Support/RISCVVIntrinsicUtils.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSet.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include <numeric>
+#include <optional>
using namespace llvm;
-using BasicType = char;
-using VScaleVal = Optional<unsigned>;
+using namespace clang::RISCV;
namespace {
+struct SemaRecord {
+ // Intrinsic name, e.g. vadd_vv
+ std::string Name;
-// Exponential LMUL
-struct LMULType {
- int Log2LMUL;
- LMULType(int Log2LMUL);
- // Return the C/C++ string representation of LMUL
- std::string str() const;
- Optional<unsigned> getScale(unsigned ElementBitwidth) const;
- void MulLog2LMUL(int Log2LMUL);
- LMULType &operator*=(uint32_t RHS);
-};
+ // Overloaded intrinsic name, could be empty if can be computed from Name
+ // e.g. vadd
+ std::string OverloadedName;
-// This class is compact representation of a valid and invalid RVVType.
-class RVVType {
- enum ScalarTypeKind : uint32_t {
- Void,
- Size_t,
- Ptrdiff_t,
- UnsignedLong,
- SignedLong,
- Boolean,
- SignedInteger,
- UnsignedInteger,
- Float,
- Invalid,
- };
- BasicType BT;
- ScalarTypeKind ScalarType = Invalid;
- LMULType LMUL;
- bool IsPointer = false;
- // IsConstant indices are "int", but have the constant expression.
- bool IsImmediate = false;
- // Const qualifier for pointer to const object or object of const type.
- bool IsConstant = false;
- unsigned ElementBitwidth = 0;
- VScaleVal Scale = 0;
- bool Valid;
-
- std::string BuiltinStr;
- std::string ClangBuiltinStr;
- std::string Str;
- std::string ShortStr;
+ // Supported type, mask of BasicType.
+ unsigned TypeRangeMask;
-public:
- RVVType() : RVVType(BasicType(), 0, StringRef()) {}
- RVVType(BasicType BT, int Log2LMUL, StringRef prototype);
-
- // Return the string representation of a type, which is an encoded string for
- // passing to the BUILTIN() macro in Builtins.def.
- const std::string &getBuiltinStr() const { return BuiltinStr; }
-
- // Return the clang buitlin type for RVV vector type which are used in the
- // riscv_vector.h header file.
- const std::string &getClangBuiltinStr() const { return ClangBuiltinStr; }
-
- // Return the C/C++ string representation of a type for use in the
- // riscv_vector.h header file.
- const std::string &getTypeStr() const { return Str; }
-
- // Return the short name of a type for C/C++ name suffix.
- const std::string &getShortStr() {
- // Not all types are used in short name, so compute the short name by
- // demanded.
- if (ShortStr.empty())
- initShortStr();
- return ShortStr;
- }
+ // Supported LMUL.
+ unsigned Log2LMULMask;
- bool isValid() const { return Valid; }
- bool isScalar() const { return Scale.hasValue() && Scale.getValue() == 0; }
- bool isVector() const { return Scale.hasValue() && Scale.getValue() != 0; }
- bool isFloat() const { return ScalarType == ScalarTypeKind::Float; }
- bool isSignedInteger() const {
- return ScalarType == ScalarTypeKind::SignedInteger;
- }
- bool isFloatVector(unsigned Width) const {
- return isVector() && isFloat() && ElementBitwidth == Width;
- }
- bool isFloat(unsigned Width) const {
- return isFloat() && ElementBitwidth == Width;
- }
+ // Required extensions for this intrinsic.
+ uint32_t RequiredExtensions;
-private:
- // Verify RVV vector type and set Valid.
- bool verifyType() const;
-
- // Creates a type based on basic types of TypeRange
- void applyBasicType();
-
- // Applies a prototype modifier to the current type. The result maybe an
- // invalid type.
- void applyModifier(StringRef prototype);
-
- // Compute and record a string for legal type.
- void initBuiltinStr();
- // Compute and record a builtin RVV vector type string.
- void initClangBuiltinStr();
- // Compute and record a type string for used in the header.
- void initTypeStr();
- // Compute and record a short name of a type for C/C++ name suffix.
- void initShortStr();
-};
+ // Prototype for this intrinsic.
+ SmallVector<PrototypeDescriptor> Prototype;
-using RVVTypePtr = RVVType *;
-using RVVTypes = std::vector<RVVTypePtr>;
+ // Suffix of intrinsic name.
+ SmallVector<PrototypeDescriptor> Suffix;
-enum RISCVExtension : uint8_t {
- Basic = 0,
- F = 1 << 1,
- D = 1 << 2,
- Zfh = 1 << 3,
- Zvamo = 1 << 4,
- Zvlsseg = 1 << 5,
-};
+ // Suffix of overloaded intrinsic name.
+ SmallVector<PrototypeDescriptor> OverloadedSuffix;
-// TODO refactor RVVIntrinsic class design after support all intrinsic
-// combination. This represents an instantiation of an intrinsic with a
-// particular type and prototype
-class RVVIntrinsic {
+ // Number of field, large than 1 if it's segment load/store.
+ unsigned NF;
+ bool HasMasked :1;
+ bool HasVL :1;
+ bool HasMaskedOffOperand :1;
+ bool HasTailPolicy : 1;
+ bool HasMaskPolicy : 1;
+ bool HasFRMRoundModeOp : 1;
+ bool IsTuple : 1;
+ uint8_t UnMaskedPolicyScheme : 2;
+ uint8_t MaskedPolicyScheme : 2;
+};
+
+// Compressed function signature table.
+class SemaSignatureTable {
private:
- std::string Name; // Builtin name
- std::string MangledName;
- std::string IRName;
- bool HasSideEffects;
- bool IsMask;
- bool HasMaskedOffOperand;
- bool HasVL;
- bool HasNoMaskedOverloaded;
- bool HasAutoDef; // There is automiatic definition in header
- std::string ManualCodegen;
- RVVTypePtr OutputType; // Builtin output type
- RVVTypes InputTypes; // Builtin input types
- // The types we use to obtain the specific LLVM intrinsic. They are index of
- // InputTypes. -1 means the return type.
- std::vector<int64_t> IntrinsicTypes;
- uint8_t RISCVExtensions = 0;
- unsigned NF = 1;
+ std::vector<PrototypeDescriptor> SignatureTable;
+
+ void insert(ArrayRef<PrototypeDescriptor> Signature);
public:
- RVVIntrinsic(StringRef Name, StringRef Suffix, StringRef MangledName,
- StringRef MangledSuffix, StringRef IRName, bool HasSideEffects,
- bool IsMask, bool HasMaskedOffOperand, bool HasVL,
- bool HasNoMaskedOverloaded, bool HasAutoDef,
- StringRef ManualCodegen, const RVVTypes &Types,
- const std::vector<int64_t> &IntrinsicTypes,
- StringRef RequiredExtension, unsigned NF);
- ~RVVIntrinsic() = default;
-
- StringRef getName() const { return Name; }
- StringRef getMangledName() const { return MangledName; }
- bool hasSideEffects() const { return HasSideEffects; }
- bool hasMaskedOffOperand() const { return HasMaskedOffOperand; }
- bool hasVL() const { return HasVL; }
- bool hasNoMaskedOverloaded() const { return HasNoMaskedOverloaded; }
- bool hasManualCodegen() const { return !ManualCodegen.empty(); }
- bool hasAutoDef() const { return HasAutoDef; }
- bool isMask() const { return IsMask; }
- StringRef getIRName() const { return IRName; }
- StringRef getManualCodegen() const { return ManualCodegen; }
- uint8_t getRISCVExtensions() const { return RISCVExtensions; }
- unsigned getNF() const { return NF; }
-
- // Return the type string for a BUILTIN() macro in Builtins.def.
- std::string getBuiltinTypeStr() const;
-
- // Emit the code block for switch body in EmitRISCVBuiltinExpr, it should
- // init the RVVIntrinsic ID and IntrinsicTypes.
- void emitCodeGenSwitchBody(raw_ostream &o) const;
-
- // Emit the macros for mapping C/C++ intrinsic function to builtin functions.
- void emitIntrinsicMacro(raw_ostream &o) const;
-
- // Emit the mangled function definition.
- void emitMangledFuncDef(raw_ostream &o) const;
+ static constexpr unsigned INVALID_INDEX = ~0U;
+
+ // Create compressed signature table from SemaRecords.
+ void init(ArrayRef<SemaRecord> SemaRecords);
+
+ // Query the Signature, return INVALID_INDEX if not found.
+ unsigned getIndex(ArrayRef<PrototypeDescriptor> Signature);
+
+ /// Print signature table in RVVHeader Record to \p OS
+ void print(raw_ostream &OS);
};
class RVVEmitter {
private:
RecordKeeper &Records;
- std::string HeaderCode;
- // Concat BasicType, LMUL and Proto as key
- StringMap<RVVType> LegalTypes;
- StringSet<> IllegalTypes;
+ RVVTypeCache TypeCache;
public:
RVVEmitter(RecordKeeper &R) : Records(R) {}
@@ -226,619 +108,113 @@ public:
/// Emit all the information needed to map builtin -> LLVM IR intrinsic.
void createCodeGen(raw_ostream &o);
- std::string getSuffixStr(char Type, int Log2LMUL, StringRef Prototypes);
+ /// Emit all the information needed by SemaRISCVVectorLookup.cpp.
+ /// We've large number of intrinsic function for RVV, creating a customized
+ /// could speed up the compilation time.
+ void createSema(raw_ostream &o);
private:
- /// Create all intrinsics and add them to \p Out
- void createRVVIntrinsics(std::vector<std::unique_ptr<RVVIntrinsic>> &Out);
- /// Compute output and input types by applying different config (basic type
- /// and LMUL with type transformers). It also record result of type in legal
- /// or illegal set to avoid compute the same config again. The result maybe
- /// have illegal RVVType.
- Optional<RVVTypes> computeTypes(BasicType BT, int Log2LMUL, unsigned NF,
- ArrayRef<std::string> PrototypeSeq);
- Optional<RVVTypePtr> computeType(BasicType BT, int Log2LMUL, StringRef Proto);
-
- /// Emit Acrh predecessor definitions and body, assume the element of Defs are
- /// sorted by extension.
- void emitArchMacroAndBody(
- std::vector<std::unique_ptr<RVVIntrinsic>> &Defs, raw_ostream &o,
- std::function<void(raw_ostream &, const RVVIntrinsic &)>);
-
- // Emit the architecture preprocessor definitions. Return true when emits
- // non-empty string.
- bool emitExtDefStr(uint8_t Extensions, raw_ostream &o);
- // Slice Prototypes string into sub prototype string and process each sub
- // prototype string individually in the Handler.
- void parsePrototypes(StringRef Prototypes,
- std::function<void(StringRef)> Handler);
+ /// Create all intrinsics and add them to \p Out and SemaRecords.
+ void createRVVIntrinsics(std::vector<std::unique_ptr<RVVIntrinsic>> &Out,
+ std::vector<SemaRecord> *SemaRecords = nullptr);
+ /// Create all intrinsic records and SemaSignatureTable from SemaRecords.
+ void createRVVIntrinsicRecords(std::vector<RVVIntrinsicRecord> &Out,
+ SemaSignatureTable &SST,
+ ArrayRef<SemaRecord> SemaRecords);
+
+ /// Print HeaderCode in RVVHeader Record to \p Out
+ void printHeaderCode(raw_ostream &OS);
};
} // namespace
-//===----------------------------------------------------------------------===//
-// Type implementation
-//===----------------------------------------------------------------------===//
-
-LMULType::LMULType(int NewLog2LMUL) {
- // Check Log2LMUL is -3, -2, -1, 0, 1, 2, 3
- assert(NewLog2LMUL <= 3 && NewLog2LMUL >= -3 && "Bad LMUL number!");
- Log2LMUL = NewLog2LMUL;
-}
-
-std::string LMULType::str() const {
- if (Log2LMUL < 0)
- return "mf" + utostr(1ULL << (-Log2LMUL));
- return "m" + utostr(1ULL << Log2LMUL);
-}
-
-VScaleVal LMULType::getScale(unsigned ElementBitwidth) const {
- int Log2ScaleResult = 0;
- switch (ElementBitwidth) {
- default:
- break;
- case 8:
- Log2ScaleResult = Log2LMUL + 3;
- break;
- case 16:
- Log2ScaleResult = Log2LMUL + 2;
- break;
- case 32:
- Log2ScaleResult = Log2LMUL + 1;
- break;
- case 64:
- Log2ScaleResult = Log2LMUL;
- break;
- }
- // Illegal vscale result would be less than 1
- if (Log2ScaleResult < 0)
- return None;
- return 1 << Log2ScaleResult;
-}
-
-void LMULType::MulLog2LMUL(int log2LMUL) { Log2LMUL += log2LMUL; }
-
-LMULType &LMULType::operator*=(uint32_t RHS) {
- assert(isPowerOf2_32(RHS));
- this->Log2LMUL = this->Log2LMUL + Log2_32(RHS);
- return *this;
-}
-
-RVVType::RVVType(BasicType BT, int Log2LMUL, StringRef prototype)
- : BT(BT), LMUL(LMULType(Log2LMUL)) {
- applyBasicType();
- applyModifier(prototype);
- Valid = verifyType();
- if (Valid) {
- initBuiltinStr();
- initTypeStr();
- if (isVector()) {
- initClangBuiltinStr();
- }
- }
-}
-
-// clang-format off
-// boolean type are encoded the ratio of n (SEW/LMUL)
-// SEW/LMUL | 1 | 2 | 4 | 8 | 16 | 32 | 64
-// c type | vbool64_t | vbool32_t | vbool16_t | vbool8_t | vbool4_t | vbool2_t | vbool1_t
-// IR type | nxv1i1 | nxv2i1 | nxv4i1 | nxv8i1 | nxv16i1 | nxv32i1 | nxv64i1
-
-// type\lmul | 1/8 | 1/4 | 1/2 | 1 | 2 | 4 | 8
-// -------- |------ | -------- | ------- | ------- | -------- | -------- | --------
-// i64 | N/A | N/A | N/A | nxv1i64 | nxv2i64 | nxv4i64 | nxv8i64
-// i32 | N/A | N/A | nxv1i32 | nxv2i32 | nxv4i32 | nxv8i32 | nxv16i32
-// i16 | N/A | nxv1i16 | nxv2i16 | nxv4i16 | nxv8i16 | nxv16i16 | nxv32i16
-// i8 | nxv1i8 | nxv2i8 | nxv4i8 | nxv8i8 | nxv16i8 | nxv32i8 | nxv64i8
-// double | N/A | N/A | N/A | nxv1f64 | nxv2f64 | nxv4f64 | nxv8f64
-// float | N/A | N/A | nxv1f32 | nxv2f32 | nxv4f32 | nxv8f32 | nxv16f32
-// half | N/A | nxv1f16 | nxv2f16 | nxv4f16 | nxv8f16 | nxv16f16 | nxv32f16
-// clang-format on
-
-bool RVVType::verifyType() const {
- if (ScalarType == Invalid)
- return false;
- if (isScalar())
- return true;
- if (!Scale.hasValue())
- return false;
- if (isFloat() && ElementBitwidth == 8)
- return false;
- unsigned V = Scale.getValue();
- switch (ElementBitwidth) {
- case 1:
- case 8:
- // Check Scale is 1,2,4,8,16,32,64
- return (V <= 64 && isPowerOf2_32(V));
- case 16:
- // Check Scale is 1,2,4,8,16,32
- return (V <= 32 && isPowerOf2_32(V));
- case 32:
- // Check Scale is 1,2,4,8,16
- return (V <= 16 && isPowerOf2_32(V));
- case 64:
- // Check Scale is 1,2,4,8
- return (V <= 8 && isPowerOf2_32(V));
- }
- return false;
-}
-
-void RVVType::initBuiltinStr() {
- assert(isValid() && "RVVType is invalid");
- switch (ScalarType) {
- case ScalarTypeKind::Void:
- BuiltinStr = "v";
- return;
- case ScalarTypeKind::Size_t:
- BuiltinStr = "z";
- if (IsImmediate)
- BuiltinStr = "I" + BuiltinStr;
- if (IsPointer)
- BuiltinStr += "*";
- return;
- case ScalarTypeKind::Ptrdiff_t:
- BuiltinStr = "Y";
- return;
- case ScalarTypeKind::UnsignedLong:
- BuiltinStr = "ULi";
- return;
- case ScalarTypeKind::SignedLong:
- BuiltinStr = "Li";
- return;
- case ScalarTypeKind::Boolean:
- assert(ElementBitwidth == 1);
- BuiltinStr += "b";
- break;
- case ScalarTypeKind::SignedInteger:
- case ScalarTypeKind::UnsignedInteger:
- switch (ElementBitwidth) {
- case 8:
- BuiltinStr += "c";
- break;
- case 16:
- BuiltinStr += "s";
- break;
- case 32:
- BuiltinStr += "i";
- break;
- case 64:
- BuiltinStr += "Wi";
- break;
- default:
- llvm_unreachable("Unhandled ElementBitwidth!");
- }
- if (isSignedInteger())
- BuiltinStr = "S" + BuiltinStr;
- else
- BuiltinStr = "U" + BuiltinStr;
- break;
- case ScalarTypeKind::Float:
- switch (ElementBitwidth) {
- case 16:
- BuiltinStr += "x";
- break;
- case 32:
- BuiltinStr += "f";
- break;
- case 64:
- BuiltinStr += "d";
- break;
- default:
- llvm_unreachable("Unhandled ElementBitwidth!");
- }
- break;
- default:
- llvm_unreachable("ScalarType is invalid!");
- }
- if (IsImmediate)
- BuiltinStr = "I" + BuiltinStr;
- if (isScalar()) {
- if (IsConstant)
- BuiltinStr += "C";
- if (IsPointer)
- BuiltinStr += "*";
- return;
- }
- BuiltinStr = "q" + utostr(Scale.getValue()) + BuiltinStr;
- // Pointer to vector types. Defined for Zvlsseg load intrinsics.
- // Zvlsseg load intrinsics have pointer type arguments to store the loaded
- // vector values.
- if (IsPointer)
- BuiltinStr += "*";
-}
-
-void RVVType::initClangBuiltinStr() {
- assert(isValid() && "RVVType is invalid");
- assert(isVector() && "Handle Vector type only");
-
- ClangBuiltinStr = "__rvv_";
- switch (ScalarType) {
- case ScalarTypeKind::Boolean:
- ClangBuiltinStr += "bool" + utostr(64 / Scale.getValue()) + "_t";
- return;
- case ScalarTypeKind::Float:
- ClangBuiltinStr += "float";
- break;
- case ScalarTypeKind::SignedInteger:
- ClangBuiltinStr += "int";
- break;
- case ScalarTypeKind::UnsignedInteger:
- ClangBuiltinStr += "uint";
- break;
- default:
- llvm_unreachable("ScalarTypeKind is invalid");
- }
- ClangBuiltinStr += utostr(ElementBitwidth) + LMUL.str() + "_t";
-}
-
-void RVVType::initTypeStr() {
- assert(isValid() && "RVVType is invalid");
-
- if (IsConstant)
- Str += "const ";
-
- auto getTypeString = [&](StringRef TypeStr) {
- if (isScalar())
- return Twine(TypeStr + Twine(ElementBitwidth) + "_t").str();
- return Twine("v" + TypeStr + Twine(ElementBitwidth) + LMUL.str() + "_t")
- .str();
- };
-
- switch (ScalarType) {
- case ScalarTypeKind::Void:
- Str = "void";
- return;
- case ScalarTypeKind::Size_t:
- Str = "size_t";
- if (IsPointer)
- Str += " *";
- return;
- case ScalarTypeKind::Ptrdiff_t:
- Str = "ptrdiff_t";
- return;
- case ScalarTypeKind::UnsignedLong:
- Str = "unsigned long";
- return;
- case ScalarTypeKind::SignedLong:
- Str = "long";
- return;
- case ScalarTypeKind::Boolean:
- if (isScalar())
- Str += "bool";
- else
- // Vector bool is special case, the formulate is
- // `vbool<N>_t = MVT::nxv<64/N>i1` ex. vbool16_t = MVT::4i1
- Str += "vbool" + utostr(64 / Scale.getValue()) + "_t";
- break;
- case ScalarTypeKind::Float:
- if (isScalar()) {
- if (ElementBitwidth == 64)
- Str += "double";
- else if (ElementBitwidth == 32)
- Str += "float";
- else if (ElementBitwidth == 16)
- Str += "_Float16";
- else
- llvm_unreachable("Unhandled floating type.");
- } else
- Str += getTypeString("float");
- break;
- case ScalarTypeKind::SignedInteger:
- Str += getTypeString("int");
- break;
- case ScalarTypeKind::UnsignedInteger:
- Str += getTypeString("uint");
- break;
- default:
- llvm_unreachable("ScalarType is invalid!");
- }
- if (IsPointer)
- Str += " *";
-}
-
-void RVVType::initShortStr() {
- switch (ScalarType) {
- case ScalarTypeKind::Boolean:
- assert(isVector());
- ShortStr = "b" + utostr(64 / Scale.getValue());
- return;
- case ScalarTypeKind::Float:
- ShortStr = "f" + utostr(ElementBitwidth);
- break;
- case ScalarTypeKind::SignedInteger:
- ShortStr = "i" + utostr(ElementBitwidth);
- break;
- case ScalarTypeKind::UnsignedInteger:
- ShortStr = "u" + utostr(ElementBitwidth);
- break;
- default:
- PrintFatalError("Unhandled case!");
- }
- if (isVector())
- ShortStr += LMUL.str();
-}
-
-void RVVType::applyBasicType() {
- switch (BT) {
+static BasicType ParseBasicType(char c) {
+ switch (c) {
case 'c':
- ElementBitwidth = 8;
- ScalarType = ScalarTypeKind::SignedInteger;
+ return BasicType::Int8;
break;
case 's':
- ElementBitwidth = 16;
- ScalarType = ScalarTypeKind::SignedInteger;
+ return BasicType::Int16;
break;
case 'i':
- ElementBitwidth = 32;
- ScalarType = ScalarTypeKind::SignedInteger;
+ return BasicType::Int32;
break;
case 'l':
- ElementBitwidth = 64;
- ScalarType = ScalarTypeKind::SignedInteger;
+ return BasicType::Int64;
break;
case 'x':
- ElementBitwidth = 16;
- ScalarType = ScalarTypeKind::Float;
+ return BasicType::Float16;
break;
case 'f':
- ElementBitwidth = 32;
- ScalarType = ScalarTypeKind::Float;
+ return BasicType::Float32;
break;
case 'd':
- ElementBitwidth = 64;
- ScalarType = ScalarTypeKind::Float;
- break;
- default:
- PrintFatalError("Unhandled type code!");
- }
- assert(ElementBitwidth != 0 && "Bad element bitwidth!");
-}
-
-void RVVType::applyModifier(StringRef Transformer) {
- if (Transformer.empty())
- return;
- // Handle primitive type transformer
- auto PType = Transformer.back();
- switch (PType) {
- case 'e':
- Scale = 0;
- break;
- case 'v':
- Scale = LMUL.getScale(ElementBitwidth);
- break;
- case 'w':
- ElementBitwidth *= 2;
- LMUL *= 2;
- Scale = LMUL.getScale(ElementBitwidth);
- break;
- case 'q':
- ElementBitwidth *= 4;
- LMUL *= 4;
- Scale = LMUL.getScale(ElementBitwidth);
- break;
- case 'o':
- ElementBitwidth *= 8;
- LMUL *= 8;
- Scale = LMUL.getScale(ElementBitwidth);
- break;
- case 'm':
- ScalarType = ScalarTypeKind::Boolean;
- Scale = LMUL.getScale(ElementBitwidth);
- ElementBitwidth = 1;
- break;
- case '0':
- ScalarType = ScalarTypeKind::Void;
- break;
- case 'z':
- ScalarType = ScalarTypeKind::Size_t;
- break;
- case 't':
- ScalarType = ScalarTypeKind::Ptrdiff_t;
+ return BasicType::Float64;
break;
- case 'u':
- ScalarType = ScalarTypeKind::UnsignedLong;
- break;
- case 'l':
- ScalarType = ScalarTypeKind::SignedLong;
+ case 'y':
+ return BasicType::BFloat16;
break;
default:
- PrintFatalError("Illegal primitive type transformers!");
- }
- Transformer = Transformer.drop_back();
-
- // Extract and compute complex type transformer. It can only appear one time.
- if (Transformer.startswith("(")) {
- size_t Idx = Transformer.find(')');
- assert(Idx != StringRef::npos);
- StringRef ComplexType = Transformer.slice(1, Idx);
- Transformer = Transformer.drop_front(Idx + 1);
- assert(Transformer.find('(') == StringRef::npos &&
- "Only allow one complex type transformer");
-
- auto UpdateAndCheckComplexProto = [&]() {
- Scale = LMUL.getScale(ElementBitwidth);
- const StringRef VectorPrototypes("vwqom");
- if (!VectorPrototypes.contains(PType))
- PrintFatalError("Complex type transformer only supports vector type!");
- if (Transformer.find_first_of("PCKWS") != StringRef::npos)
- PrintFatalError(
- "Illegal type transformer for Complex type transformer");
- };
- auto ComputeFixedLog2LMUL =
- [&](StringRef Value,
- std::function<bool(const int32_t &, const int32_t &)> Compare) {
- int32_t Log2LMUL;
- Value.getAsInteger(10, Log2LMUL);
- if (!Compare(Log2LMUL, LMUL.Log2LMUL)) {
- ScalarType = Invalid;
- return false;
- }
- // Update new LMUL
- LMUL = LMULType(Log2LMUL);
- UpdateAndCheckComplexProto();
- return true;
- };
- auto ComplexTT = ComplexType.split(":");
- if (ComplexTT.first == "Log2EEW") {
- uint32_t Log2EEW;
- ComplexTT.second.getAsInteger(10, Log2EEW);
- // update new elmul = (eew/sew) * lmul
- LMUL.MulLog2LMUL(Log2EEW - Log2_32(ElementBitwidth));
- // update new eew
- ElementBitwidth = 1 << Log2EEW;
- ScalarType = ScalarTypeKind::SignedInteger;
- UpdateAndCheckComplexProto();
- } else if (ComplexTT.first == "FixedSEW") {
- uint32_t NewSEW;
- ComplexTT.second.getAsInteger(10, NewSEW);
- // Set invalid type if src and dst SEW are same.
- if (ElementBitwidth == NewSEW) {
- ScalarType = Invalid;
- return;
- }
- // Update new SEW
- ElementBitwidth = NewSEW;
- UpdateAndCheckComplexProto();
- } else if (ComplexTT.first == "LFixedLog2LMUL") {
- // New LMUL should be larger than old
- if (!ComputeFixedLog2LMUL(ComplexTT.second, std::greater<int32_t>()))
- return;
- } else if (ComplexTT.first == "SFixedLog2LMUL") {
- // New LMUL should be smaller than old
- if (!ComputeFixedLog2LMUL(ComplexTT.second, std::less<int32_t>()))
- return;
- } else {
- PrintFatalError("Illegal complex type transformers!");
- }
- }
-
- // Compute the remain type transformers
- for (char I : Transformer) {
- switch (I) {
- case 'P':
- if (IsConstant)
- PrintFatalError("'P' transformer cannot be used after 'C'");
- if (IsPointer)
- PrintFatalError("'P' transformer cannot be used twice");
- IsPointer = true;
- break;
- case 'C':
- if (IsConstant)
- PrintFatalError("'C' transformer cannot be used twice");
- IsConstant = true;
- break;
- case 'K':
- IsImmediate = true;
- break;
- case 'U':
- ScalarType = ScalarTypeKind::UnsignedInteger;
- break;
- case 'I':
- ScalarType = ScalarTypeKind::SignedInteger;
- break;
- case 'F':
- ScalarType = ScalarTypeKind::Float;
- break;
- case 'S':
- LMUL = LMULType(0);
- // Update ElementBitwidth need to update Scale too.
- Scale = LMUL.getScale(ElementBitwidth);
- break;
- default:
- PrintFatalError("Illegal non-primitive type transformer!");
- }
+ return BasicType::Unknown;
}
}
-//===----------------------------------------------------------------------===//
-// RVVIntrinsic implementation
-//===----------------------------------------------------------------------===//
-RVVIntrinsic::RVVIntrinsic(StringRef NewName, StringRef Suffix,
- StringRef NewMangledName, StringRef MangledSuffix,
- StringRef IRName, bool HasSideEffects, bool IsMask,
- bool HasMaskedOffOperand, bool HasVL,
- bool HasNoMaskedOverloaded, bool HasAutoDef,
- StringRef ManualCodegen, const RVVTypes &OutInTypes,
- const std::vector<int64_t> &NewIntrinsicTypes,
- StringRef RequiredExtension, unsigned NF)
- : IRName(IRName), HasSideEffects(HasSideEffects), IsMask(IsMask),
- HasMaskedOffOperand(HasMaskedOffOperand), HasVL(HasVL),
- HasNoMaskedOverloaded(HasNoMaskedOverloaded), HasAutoDef(HasAutoDef),
- ManualCodegen(ManualCodegen.str()), NF(NF) {
-
- // Init Name and MangledName
- Name = NewName.str();
- if (NewMangledName.empty())
- MangledName = NewName.split("_").first.str();
- else
- MangledName = NewMangledName.str();
- if (!Suffix.empty())
- Name += "_" + Suffix.str();
- if (!MangledSuffix.empty())
- MangledName += "_" + MangledSuffix.str();
- if (IsMask) {
- Name += "_m";
- }
- // Init RISC-V extensions
- for (const auto &T : OutInTypes) {
- if (T->isFloatVector(16) || T->isFloat(16))
- RISCVExtensions |= RISCVExtension::Zfh;
- else if (T->isFloatVector(32) || T->isFloat(32))
- RISCVExtensions |= RISCVExtension::F;
- else if (T->isFloatVector(64) || T->isFloat(64))
- RISCVExtensions |= RISCVExtension::D;
- }
- if (RequiredExtension == "Zvamo")
- RISCVExtensions |= RISCVExtension::Zvamo;
- if (RequiredExtension == "Zvlsseg")
- RISCVExtensions |= RISCVExtension::Zvlsseg;
-
- // Init OutputType and InputTypes
- OutputType = OutInTypes[0];
- InputTypes.assign(OutInTypes.begin() + 1, OutInTypes.end());
-
- // IntrinsicTypes is nonmasked version index. Need to update it
- // if there is maskedoff operand (It is always in first operand).
- IntrinsicTypes = NewIntrinsicTypes;
- if (IsMask && HasMaskedOffOperand) {
- for (auto &I : IntrinsicTypes) {
- if (I >= 0)
- I += NF;
- }
- }
+static VectorTypeModifier getTupleVTM(unsigned NF) {
+ assert(2 <= NF && NF <= 8 && "2 <= NF <= 8");
+ return static_cast<VectorTypeModifier>(
+ static_cast<uint8_t>(VectorTypeModifier::Tuple2) + (NF - 2));
}
-std::string RVVIntrinsic::getBuiltinTypeStr() const {
- std::string S;
- S += OutputType->getBuiltinStr();
- for (const auto &T : InputTypes) {
- S += T->getBuiltinStr();
- }
- return S;
-}
+void emitCodeGenSwitchBody(const RVVIntrinsic *RVVI, raw_ostream &OS) {
+ if (!RVVI->getIRName().empty())
+ OS << " ID = Intrinsic::riscv_" + RVVI->getIRName() + ";\n";
+ if (RVVI->getNF() >= 2)
+ OS << " NF = " + utostr(RVVI->getNF()) + ";\n";
-void RVVIntrinsic::emitCodeGenSwitchBody(raw_ostream &OS) const {
- if (!getIRName().empty())
- OS << " ID = Intrinsic::riscv_" + getIRName() + ";\n";
- if (NF >= 2)
- OS << " NF = " + utostr(getNF()) + ";\n";
- if (hasManualCodegen()) {
- OS << ManualCodegen;
+ OS << " PolicyAttrs = " << RVVI->getPolicyAttrsBits() << ";\n";
+
+ if (RVVI->hasManualCodegen()) {
+ OS << "IsMasked = " << (RVVI->isMasked() ? "true" : "false") << ";\n";
+ OS << RVVI->getManualCodegen();
OS << "break;\n";
return;
}
- if (isMask()) {
- if (hasVL()) {
+ for (const auto &I : enumerate(RVVI->getInputTypes())) {
+ if (I.value()->isPointer()) {
+ assert(RVVI->getIntrinsicTypes().front() == -1 &&
+ "RVVI should be vector load intrinsic.");
+ }
+ }
+
+ if (RVVI->isMasked()) {
+ if (RVVI->hasVL()) {
OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);\n";
+ if (RVVI->hasPolicyOperand())
+ OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType(),"
+ " PolicyAttrs));\n";
+ if (RVVI->hasMaskedOffOperand() && RVVI->getPolicyAttrs().isTAMAPolicy())
+ OS << " Ops.insert(Ops.begin(), "
+ "llvm::PoisonValue::get(ResultType));\n";
+ // Masked reduction cases.
+ if (!RVVI->hasMaskedOffOperand() && RVVI->hasPassthruOperand() &&
+ RVVI->getPolicyAttrs().isTAMAPolicy())
+ OS << " Ops.insert(Ops.begin(), "
+ "llvm::PoisonValue::get(ResultType));\n";
} else {
OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end());\n";
}
+ } else {
+ if (RVVI->hasPolicyOperand())
+ OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType(), "
+ "PolicyAttrs));\n";
+ else if (RVVI->hasPassthruOperand() && RVVI->getPolicyAttrs().isTAPolicy())
+ OS << " Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));\n";
}
OS << " IntrinsicTypes = {";
ListSeparator LS;
- for (const auto &Idx : IntrinsicTypes) {
+ for (const auto &Idx : RVVI->getIntrinsicTypes()) {
if (Idx == -1)
OS << LS << "ResultType";
else
@@ -847,40 +223,89 @@ void RVVIntrinsic::emitCodeGenSwitchBody(raw_ostream &OS) const {
// VL could be i64 or i32, need to encode it in IntrinsicTypes. VL is
// always last operand.
- if (hasVL())
+ if (RVVI->hasVL())
OS << ", Ops.back()->getType()";
OS << "};\n";
OS << " break;\n";
}
-void RVVIntrinsic::emitIntrinsicMacro(raw_ostream &OS) const {
- OS << "#define " << getName() << "(";
- if (!InputTypes.empty()) {
- ListSeparator LS;
- for (unsigned i = 0, e = InputTypes.size(); i != e; ++i)
- OS << LS << "op" << i;
- }
- OS << ") \\\n";
- OS << "__builtin_rvv_" << getName() << "(";
- if (!InputTypes.empty()) {
- ListSeparator LS;
- for (unsigned i = 0, e = InputTypes.size(); i != e; ++i)
- OS << LS << "(" << InputTypes[i]->getTypeStr() << ")(op" << i << ")";
+//===----------------------------------------------------------------------===//
+// SemaSignatureTable implementation
+//===----------------------------------------------------------------------===//
+void SemaSignatureTable::init(ArrayRef<SemaRecord> SemaRecords) {
+ // Sort signature entries by length, let longer signature insert first, to
+ // make it more possible to reuse table entries, that can reduce ~10% table
+ // size.
+ struct Compare {
+ bool operator()(const SmallVector<PrototypeDescriptor> &A,
+ const SmallVector<PrototypeDescriptor> &B) const {
+ if (A.size() != B.size())
+ return A.size() > B.size();
+
+ size_t Len = A.size();
+ for (size_t i = 0; i < Len; ++i) {
+ if (A[i] != B[i])
+ return A[i] < B[i];
+ }
+
+ return false;
+ }
+ };
+
+ std::set<SmallVector<PrototypeDescriptor>, Compare> Signatures;
+ auto InsertToSignatureSet =
+ [&](const SmallVector<PrototypeDescriptor> &Signature) {
+ if (Signature.empty())
+ return;
+
+ Signatures.insert(Signature);
+ };
+
+ assert(!SemaRecords.empty());
+
+ for (const SemaRecord &SR : SemaRecords) {
+ InsertToSignatureSet(SR.Prototype);
+ InsertToSignatureSet(SR.Suffix);
+ InsertToSignatureSet(SR.OverloadedSuffix);
}
- OS << ")\n";
+
+ for (auto &Sig : Signatures)
+ insert(Sig);
}
-void RVVIntrinsic::emitMangledFuncDef(raw_ostream &OS) const {
- OS << "__attribute__((clang_builtin_alias(";
- OS << "__builtin_rvv_" << getName() << ")))\n";
- OS << OutputType->getTypeStr() << " " << getMangledName() << "(";
- // Emit function arguments
- if (!InputTypes.empty()) {
- ListSeparator LS;
- for (unsigned i = 0; i < InputTypes.size(); ++i)
- OS << LS << InputTypes[i]->getTypeStr() << " op" << i;
+void SemaSignatureTable::insert(ArrayRef<PrototypeDescriptor> Signature) {
+ if (getIndex(Signature) != INVALID_INDEX)
+ return;
+
+ // Insert Signature into SignatureTable if not found in the table.
+ SignatureTable.insert(SignatureTable.begin(), Signature.begin(),
+ Signature.end());
+}
+
+unsigned SemaSignatureTable::getIndex(ArrayRef<PrototypeDescriptor> Signature) {
+ // Empty signature could be point into any index since there is length
+ // field when we use, so just always point it to 0.
+ if (Signature.empty())
+ return 0;
+
+ // Checking Signature already in table or not.
+ if (Signature.size() <= SignatureTable.size()) {
+ size_t Bound = SignatureTable.size() - Signature.size() + 1;
+ for (size_t Index = 0; Index < Bound; ++Index) {
+ if (equal(Signature.begin(), Signature.end(),
+ SignatureTable.begin() + Index))
+ return Index;
+ }
}
- OS << ");\n\n";
+
+ return INVALID_INDEX;
+}
+
+void SemaSignatureTable::print(raw_ostream &OS) {
+ for (const auto &Sig : SignatureTable)
+ OS << "PrototypeDescriptor(" << static_cast<int>(Sig.PT) << ", "
+ << static_cast<int>(Sig.VTM) << ", " << static_cast<int>(Sig.TM)
+ << "),\n";
}
//===----------------------------------------------------------------------===//
@@ -915,13 +340,9 @@ void RVVEmitter::createHeader(raw_ostream &OS) {
OS << "extern \"C\" {\n";
OS << "#endif\n\n";
- std::vector<std::unique_ptr<RVVIntrinsic>> Defs;
- createRVVIntrinsics(Defs);
+ OS << "#pragma clang riscv intrinsic vector\n\n";
- // Print header code
- if (!HeaderCode.empty()) {
- OS << HeaderCode;
- }
+ printHeaderCode(OS);
auto printType = [&](auto T) {
OS << "typedef " << T->getClangBuiltinStr() << " " << T->getTypeStr()
@@ -931,73 +352,66 @@ void RVVEmitter::createHeader(raw_ostream &OS) {
constexpr int Log2LMULs[] = {-3, -2, -1, 0, 1, 2, 3};
// Print RVV boolean types.
for (int Log2LMUL : Log2LMULs) {
- auto T = computeType('c', Log2LMUL, "m");
- if (T.hasValue())
- printType(T.getValue());
+ auto T = TypeCache.computeType(BasicType::Int8, Log2LMUL,
+ PrototypeDescriptor::Mask);
+ if (T)
+ printType(*T);
}
// Print RVV int/float types.
for (char I : StringRef("csil")) {
+ BasicType BT = ParseBasicType(I);
for (int Log2LMUL : Log2LMULs) {
- auto T = computeType(I, Log2LMUL, "v");
- if (T.hasValue()) {
- printType(T.getValue());
- auto UT = computeType(I, Log2LMUL, "Uv");
- printType(UT.getValue());
+ auto T = TypeCache.computeType(BT, Log2LMUL, PrototypeDescriptor::Vector);
+ if (T) {
+ printType(*T);
+ auto UT = TypeCache.computeType(
+ BT, Log2LMUL,
+ PrototypeDescriptor(BaseTypeModifier::Vector,
+ VectorTypeModifier::NoModifier,
+ TypeModifier::UnsignedInteger));
+ printType(*UT);
+ }
+ for (int NF = 2; NF <= 8; ++NF) {
+ auto TupleT = TypeCache.computeType(
+ BT, Log2LMUL,
+ PrototypeDescriptor(BaseTypeModifier::Vector, getTupleVTM(NF),
+ TypeModifier::SignedInteger));
+ auto TupleUT = TypeCache.computeType(
+ BT, Log2LMUL,
+ PrototypeDescriptor(BaseTypeModifier::Vector, getTupleVTM(NF),
+ TypeModifier::UnsignedInteger));
+ if (TupleT)
+ printType(*TupleT);
+ if (TupleUT)
+ printType(*TupleUT);
}
}
}
- OS << "#if defined(__riscv_zfh)\n";
- for (int Log2LMUL : Log2LMULs) {
- auto T = computeType('x', Log2LMUL, "v");
- if (T.hasValue())
- printType(T.getValue());
- }
- OS << "#endif\n";
-
- OS << "#if defined(__riscv_f)\n";
- for (int Log2LMUL : Log2LMULs) {
- auto T = computeType('f', Log2LMUL, "v");
- if (T.hasValue())
- printType(T.getValue());
- }
- OS << "#endif\n";
- OS << "#if defined(__riscv_d)\n";
- for (int Log2LMUL : Log2LMULs) {
- auto T = computeType('d', Log2LMUL, "v");
- if (T.hasValue())
- printType(T.getValue());
+ for (BasicType BT : {BasicType::Float16, BasicType::Float32,
+ BasicType::Float64, BasicType::BFloat16}) {
+ for (int Log2LMUL : Log2LMULs) {
+ auto T = TypeCache.computeType(BT, Log2LMUL, PrototypeDescriptor::Vector);
+ if (T)
+ printType(*T);
+ for (int NF = 2; NF <= 8; ++NF) {
+ auto TupleT = TypeCache.computeType(
+ BT, Log2LMUL,
+ PrototypeDescriptor(BaseTypeModifier::Vector, getTupleVTM(NF),
+ (BT == BasicType::BFloat16
+ ? TypeModifier::BFloat
+ : TypeModifier::Float)));
+ if (TupleT)
+ printType(*TupleT);
+ }
+ }
}
- OS << "#endif\n\n";
-
- // The same extension include in the same arch guard marco.
- std::stable_sort(Defs.begin(), Defs.end(),
- [](const std::unique_ptr<RVVIntrinsic> &A,
- const std::unique_ptr<RVVIntrinsic> &B) {
- return A->getRISCVExtensions() < B->getRISCVExtensions();
- });
-
- // Print intrinsic functions with macro
- emitArchMacroAndBody(Defs, OS, [](raw_ostream &OS, const RVVIntrinsic &Inst) {
- Inst.emitIntrinsicMacro(OS);
- });
OS << "#define __riscv_v_intrinsic_overloading 1\n";
- // Print Overloaded APIs
- OS << "#define __rvv_overloaded static inline "
- "__attribute__((__always_inline__, __nodebug__, __overloadable__))\n";
-
- emitArchMacroAndBody(Defs, OS, [](raw_ostream &OS, const RVVIntrinsic &Inst) {
- if (!Inst.isMask() && !Inst.hasNoMaskedOverloaded())
- return;
- OS << "__rvv_overloaded ";
- Inst.emitMangledFuncDef(OS);
- });
-
OS << "\n#ifdef __cplusplus\n";
OS << "}\n";
- OS << "#endif // __riscv_vector\n";
+ OS << "#endif // __cplusplus\n";
OS << "#endif // __RISCV_VECTOR_H\n";
}
@@ -1005,17 +419,29 @@ void RVVEmitter::createBuiltins(raw_ostream &OS) {
std::vector<std::unique_ptr<RVVIntrinsic>> Defs;
createRVVIntrinsics(Defs);
+ // Map to keep track of which builtin names have already been emitted.
+ StringMap<RVVIntrinsic *> BuiltinMap;
+
OS << "#if defined(TARGET_BUILTIN) && !defined(RISCVV_BUILTIN)\n";
OS << "#define RISCVV_BUILTIN(ID, TYPE, ATTRS) TARGET_BUILTIN(ID, TYPE, "
- "ATTRS, \"experimental-v\")\n";
+ "ATTRS, \"zve32x\")\n";
OS << "#endif\n";
for (auto &Def : Defs) {
- OS << "RISCVV_BUILTIN(__builtin_rvv_" << Def->getName() << ",\""
- << Def->getBuiltinTypeStr() << "\", ";
- if (!Def->hasSideEffects())
- OS << "\"n\")\n";
- else
- OS << "\"\")\n";
+ auto P =
+ BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get()));
+ if (!P.second) {
+ // Verf that this would have produced the same builtin definition.
+ if (P.first->second->hasBuiltinAlias() != Def->hasBuiltinAlias())
+ PrintFatalError("Builtin with same name has different hasAutoDef");
+ else if (!Def->hasBuiltinAlias() &&
+ P.first->second->getBuiltinTypeStr() != Def->getBuiltinTypeStr())
+ PrintFatalError("Builtin with same name has different type string");
+ continue;
+ }
+ OS << "RISCVV_BUILTIN(__builtin_rvv_" << Def->getBuiltinName() << ",\"";
+ if (!Def->hasBuiltinAlias())
+ OS << Def->getBuiltinTypeStr();
+ OS << "\", \"n\")\n";
}
OS << "#undef RISCVV_BUILTIN\n";
}
@@ -1024,233 +450,319 @@ void RVVEmitter::createCodeGen(raw_ostream &OS) {
std::vector<std::unique_ptr<RVVIntrinsic>> Defs;
createRVVIntrinsics(Defs);
// IR name could be empty, use the stable sort preserves the relative order.
- std::stable_sort(Defs.begin(), Defs.end(),
- [](const std::unique_ptr<RVVIntrinsic> &A,
- const std::unique_ptr<RVVIntrinsic> &B) {
- return A->getIRName() < B->getIRName();
- });
- // Print switch body when the ir name or ManualCodegen changes from previous
- // iteration.
+ llvm::stable_sort(Defs, [](const std::unique_ptr<RVVIntrinsic> &A,
+ const std::unique_ptr<RVVIntrinsic> &B) {
+ if (A->getIRName() == B->getIRName())
+ return (A->getPolicyAttrs() < B->getPolicyAttrs());
+ return (A->getIRName() < B->getIRName());
+ });
+
+ // Map to keep track of which builtin names have already been emitted.
+ StringMap<RVVIntrinsic *> BuiltinMap;
+
+ // Print switch body when the ir name, ManualCodegen or policy changes from
+ // previous iteration.
RVVIntrinsic *PrevDef = Defs.begin()->get();
for (auto &Def : Defs) {
StringRef CurIRName = Def->getIRName();
if (CurIRName != PrevDef->getIRName() ||
- (Def->getManualCodegen() != PrevDef->getManualCodegen())) {
- PrevDef->emitCodeGenSwitchBody(OS);
+ (Def->getManualCodegen() != PrevDef->getManualCodegen()) ||
+ (Def->getPolicyAttrs() != PrevDef->getPolicyAttrs())) {
+ emitCodeGenSwitchBody(PrevDef, OS);
}
PrevDef = Def.get();
- OS << "case RISCV::BI__builtin_rvv_" << Def->getName() << ":\n";
- }
- Defs.back()->emitCodeGenSwitchBody(OS);
- OS << "\n";
-}
-void RVVEmitter::parsePrototypes(StringRef Prototypes,
- std::function<void(StringRef)> Handler) {
- const StringRef Primaries("evwqom0ztul");
- while (!Prototypes.empty()) {
- size_t Idx = 0;
- // Skip over complex prototype because it could contain primitive type
- // character.
- if (Prototypes[0] == '(')
- Idx = Prototypes.find_first_of(')');
- Idx = Prototypes.find_first_of(Primaries, Idx);
- assert(Idx != StringRef::npos);
- Handler(Prototypes.slice(0, Idx + 1));
- Prototypes = Prototypes.drop_front(Idx + 1);
- }
-}
+ auto P =
+ BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get()));
+ if (P.second) {
+ OS << "case RISCVVector::BI__builtin_rvv_" << Def->getBuiltinName()
+ << ":\n";
+ continue;
+ }
-std::string RVVEmitter::getSuffixStr(char Type, int Log2LMUL,
- StringRef Prototypes) {
- SmallVector<std::string> SuffixStrs;
- parsePrototypes(Prototypes, [&](StringRef Proto) {
- auto T = computeType(Type, Log2LMUL, Proto);
- SuffixStrs.push_back(T.getValue()->getShortStr());
- });
- return join(SuffixStrs, "_");
+ if (P.first->second->getIRName() != Def->getIRName())
+ PrintFatalError("Builtin with same name has different IRName");
+ else if (P.first->second->getManualCodegen() != Def->getManualCodegen())
+ PrintFatalError("Builtin with same name has different ManualCodegen");
+ else if (P.first->second->isMasked() != Def->isMasked())
+ PrintFatalError("Builtin with same name has different isMasked");
+ else if (P.first->second->hasVL() != Def->hasVL())
+ PrintFatalError("Builtin with same name has different hasVL");
+ else if (P.first->second->getPolicyScheme() != Def->getPolicyScheme())
+ PrintFatalError("Builtin with same name has different getPolicyScheme");
+ else if (P.first->second->getIntrinsicTypes() != Def->getIntrinsicTypes())
+ PrintFatalError("Builtin with same name has different IntrinsicTypes");
+ }
+ emitCodeGenSwitchBody(Defs.back().get(), OS);
+ OS << "\n";
}
void RVVEmitter::createRVVIntrinsics(
- std::vector<std::unique_ptr<RVVIntrinsic>> &Out) {
+ std::vector<std::unique_ptr<RVVIntrinsic>> &Out,
+ std::vector<SemaRecord> *SemaRecords) {
std::vector<Record *> RV = Records.getAllDerivedDefinitions("RVVBuiltin");
for (auto *R : RV) {
StringRef Name = R->getValueAsString("Name");
StringRef SuffixProto = R->getValueAsString("Suffix");
- StringRef MangledName = R->getValueAsString("MangledName");
- StringRef MangledSuffixProto = R->getValueAsString("MangledSuffix");
+ StringRef OverloadedName = R->getValueAsString("OverloadedName");
+ StringRef OverloadedSuffixProto = R->getValueAsString("OverloadedSuffix");
StringRef Prototypes = R->getValueAsString("Prototype");
StringRef TypeRange = R->getValueAsString("TypeRange");
- bool HasMask = R->getValueAsBit("HasMask");
+ bool HasMasked = R->getValueAsBit("HasMasked");
bool HasMaskedOffOperand = R->getValueAsBit("HasMaskedOffOperand");
bool HasVL = R->getValueAsBit("HasVL");
- bool HasNoMaskedOverloaded = R->getValueAsBit("HasNoMaskedOverloaded");
- bool HasSideEffects = R->getValueAsBit("HasSideEffects");
+ Record *MPSRecord = R->getValueAsDef("MaskedPolicyScheme");
+ auto MaskedPolicyScheme =
+ static_cast<PolicyScheme>(MPSRecord->getValueAsInt("Value"));
+ Record *UMPSRecord = R->getValueAsDef("UnMaskedPolicyScheme");
+ auto UnMaskedPolicyScheme =
+ static_cast<PolicyScheme>(UMPSRecord->getValueAsInt("Value"));
std::vector<int64_t> Log2LMULList = R->getValueAsListOfInts("Log2LMUL");
+ bool HasTailPolicy = R->getValueAsBit("HasTailPolicy");
+ bool HasMaskPolicy = R->getValueAsBit("HasMaskPolicy");
+ bool SupportOverloading = R->getValueAsBit("SupportOverloading");
+ bool HasBuiltinAlias = R->getValueAsBit("HasBuiltinAlias");
StringRef ManualCodegen = R->getValueAsString("ManualCodegen");
- StringRef ManualCodegenMask = R->getValueAsString("ManualCodegenMask");
std::vector<int64_t> IntrinsicTypes =
R->getValueAsListOfInts("IntrinsicTypes");
- StringRef RequiredExtension = R->getValueAsString("RequiredExtension");
+ std::vector<StringRef> RequiredFeatures =
+ R->getValueAsListOfStrings("RequiredFeatures");
StringRef IRName = R->getValueAsString("IRName");
- StringRef IRNameMask = R->getValueAsString("IRNameMask");
+ StringRef MaskedIRName = R->getValueAsString("MaskedIRName");
unsigned NF = R->getValueAsInt("NF");
+ bool IsTuple = R->getValueAsBit("IsTuple");
+ bool HasFRMRoundModeOp = R->getValueAsBit("HasFRMRoundModeOp");
+
+ const Policy DefaultPolicy;
+ SmallVector<Policy> SupportedUnMaskedPolicies =
+ RVVIntrinsic::getSupportedUnMaskedPolicies();
+ SmallVector<Policy> SupportedMaskedPolicies =
+ RVVIntrinsic::getSupportedMaskedPolicies(HasTailPolicy, HasMaskPolicy);
- StringRef HeaderCodeStr = R->getValueAsString("HeaderCode");
- bool HasAutoDef = HeaderCodeStr.empty();
- if (!HeaderCodeStr.empty()) {
- HeaderCode += HeaderCodeStr.str();
- }
// Parse prototype and create a list of primitive type with transformers
- // (operand) in ProtoSeq. ProtoSeq[0] is output operand.
- SmallVector<std::string> ProtoSeq;
- parsePrototypes(Prototypes, [&ProtoSeq](StringRef Proto) {
- ProtoSeq.push_back(Proto.str());
- });
+ // (operand) in Prototype. Prototype[0] is output operand.
+ SmallVector<PrototypeDescriptor> BasicPrototype =
+ parsePrototypes(Prototypes);
+
+ SmallVector<PrototypeDescriptor> SuffixDesc = parsePrototypes(SuffixProto);
+ SmallVector<PrototypeDescriptor> OverloadedSuffixDesc =
+ parsePrototypes(OverloadedSuffixProto);
// Compute Builtin types
- SmallVector<std::string> ProtoMaskSeq = ProtoSeq;
- if (HasMask) {
- // If HasMaskedOffOperand, insert result type as first input operand.
- if (HasMaskedOffOperand) {
- if (NF == 1) {
- ProtoMaskSeq.insert(ProtoMaskSeq.begin() + 1, ProtoSeq[0]);
- } else {
- // Convert
- // (void, op0 address, op1 address, ...)
- // to
- // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...)
- for (unsigned I = 0; I < NF; ++I)
- ProtoMaskSeq.insert(
- ProtoMaskSeq.begin() + NF + 1,
- ProtoSeq[1].substr(1)); // Use substr(1) to skip '*'
- }
- }
- if (HasMaskedOffOperand && NF > 1) {
- // Convert
- // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...)
- // to
- // (void, op0 address, op1 address, ..., mask, maskedoff0, maskedoff1,
- // ...)
- ProtoMaskSeq.insert(ProtoMaskSeq.begin() + NF + 1, "m");
- } else {
- // If HasMask, insert 'm' as first input operand.
- ProtoMaskSeq.insert(ProtoMaskSeq.begin() + 1, "m");
- }
- }
- // If HasVL, append 'z' to last operand
- if (HasVL) {
- ProtoSeq.push_back("z");
- ProtoMaskSeq.push_back("z");
- }
+ auto Prototype = RVVIntrinsic::computeBuiltinTypes(
+ BasicPrototype, /*IsMasked=*/false,
+ /*HasMaskedOffOperand=*/false, HasVL, NF, UnMaskedPolicyScheme,
+ DefaultPolicy, IsTuple);
+ llvm::SmallVector<PrototypeDescriptor> MaskedPrototype;
+ if (HasMasked)
+ MaskedPrototype = RVVIntrinsic::computeBuiltinTypes(
+ BasicPrototype, /*IsMasked=*/true, HasMaskedOffOperand, HasVL, NF,
+ MaskedPolicyScheme, DefaultPolicy, IsTuple);
// Create Intrinsics for each type and LMUL.
for (char I : TypeRange) {
for (int Log2LMUL : Log2LMULList) {
- Optional<RVVTypes> Types = computeTypes(I, Log2LMUL, NF, ProtoSeq);
+ BasicType BT = ParseBasicType(I);
+ std::optional<RVVTypes> Types =
+ TypeCache.computeTypes(BT, Log2LMUL, NF, Prototype);
// Ignored to create new intrinsic if there are any illegal types.
- if (!Types.hasValue())
+ if (!Types)
continue;
- auto SuffixStr = getSuffixStr(I, Log2LMUL, SuffixProto);
- auto MangledSuffixStr = getSuffixStr(I, Log2LMUL, MangledSuffixProto);
- // Create a non-mask intrinsic
+ auto SuffixStr =
+ RVVIntrinsic::getSuffixStr(TypeCache, BT, Log2LMUL, SuffixDesc);
+ auto OverloadedSuffixStr = RVVIntrinsic::getSuffixStr(
+ TypeCache, BT, Log2LMUL, OverloadedSuffixDesc);
+ // Create a unmasked intrinsic
Out.push_back(std::make_unique<RVVIntrinsic>(
- Name, SuffixStr, MangledName, MangledSuffixStr, IRName,
- HasSideEffects, /*IsMask=*/false, /*HasMaskedOffOperand=*/false,
- HasVL, HasNoMaskedOverloaded, HasAutoDef, ManualCodegen,
- Types.getValue(), IntrinsicTypes, RequiredExtension, NF));
- if (HasMask) {
- // Create a mask intrinsic
- Optional<RVVTypes> MaskTypes =
- computeTypes(I, Log2LMUL, NF, ProtoMaskSeq);
+ Name, SuffixStr, OverloadedName, OverloadedSuffixStr, IRName,
+ /*IsMasked=*/false, /*HasMaskedOffOperand=*/false, HasVL,
+ UnMaskedPolicyScheme, SupportOverloading, HasBuiltinAlias,
+ ManualCodegen, *Types, IntrinsicTypes, RequiredFeatures, NF,
+ DefaultPolicy, HasFRMRoundModeOp));
+ if (UnMaskedPolicyScheme != PolicyScheme::SchemeNone)
+ for (auto P : SupportedUnMaskedPolicies) {
+ SmallVector<PrototypeDescriptor> PolicyPrototype =
+ RVVIntrinsic::computeBuiltinTypes(
+ BasicPrototype, /*IsMasked=*/false,
+ /*HasMaskedOffOperand=*/false, HasVL, NF,
+ UnMaskedPolicyScheme, P, IsTuple);
+ std::optional<RVVTypes> PolicyTypes =
+ TypeCache.computeTypes(BT, Log2LMUL, NF, PolicyPrototype);
+ Out.push_back(std::make_unique<RVVIntrinsic>(
+ Name, SuffixStr, OverloadedName, OverloadedSuffixStr, IRName,
+ /*IsMask=*/false, /*HasMaskedOffOperand=*/false, HasVL,
+ UnMaskedPolicyScheme, SupportOverloading, HasBuiltinAlias,
+ ManualCodegen, *PolicyTypes, IntrinsicTypes, RequiredFeatures,
+ NF, P, HasFRMRoundModeOp));
+ }
+ if (!HasMasked)
+ continue;
+ // Create a masked intrinsic
+ std::optional<RVVTypes> MaskTypes =
+ TypeCache.computeTypes(BT, Log2LMUL, NF, MaskedPrototype);
+ Out.push_back(std::make_unique<RVVIntrinsic>(
+ Name, SuffixStr, OverloadedName, OverloadedSuffixStr, MaskedIRName,
+ /*IsMasked=*/true, HasMaskedOffOperand, HasVL, MaskedPolicyScheme,
+ SupportOverloading, HasBuiltinAlias, ManualCodegen, *MaskTypes,
+ IntrinsicTypes, RequiredFeatures, NF, DefaultPolicy,
+ HasFRMRoundModeOp));
+ if (MaskedPolicyScheme == PolicyScheme::SchemeNone)
+ continue;
+ for (auto P : SupportedMaskedPolicies) {
+ SmallVector<PrototypeDescriptor> PolicyPrototype =
+ RVVIntrinsic::computeBuiltinTypes(
+ BasicPrototype, /*IsMasked=*/true, HasMaskedOffOperand, HasVL,
+ NF, MaskedPolicyScheme, P, IsTuple);
+ std::optional<RVVTypes> PolicyTypes =
+ TypeCache.computeTypes(BT, Log2LMUL, NF, PolicyPrototype);
Out.push_back(std::make_unique<RVVIntrinsic>(
- Name, SuffixStr, MangledName, MangledSuffixStr, IRNameMask,
- HasSideEffects, /*IsMask=*/true, HasMaskedOffOperand, HasVL,
- HasNoMaskedOverloaded, HasAutoDef, ManualCodegenMask,
- MaskTypes.getValue(), IntrinsicTypes, RequiredExtension, NF));
+ Name, SuffixStr, OverloadedName, OverloadedSuffixStr,
+ MaskedIRName, /*IsMasked=*/true, HasMaskedOffOperand, HasVL,
+ MaskedPolicyScheme, SupportOverloading, HasBuiltinAlias,
+ ManualCodegen, *PolicyTypes, IntrinsicTypes, RequiredFeatures, NF,
+ P, HasFRMRoundModeOp));
}
- } // end for Log2LMULList
- } // end for TypeRange
- }
-}
+ } // End for Log2LMULList
+ } // End for TypeRange
+
+ // We don't emit vsetvli and vsetvlimax for SemaRecord.
+ // They are written in riscv_vector.td and will emit those marco define in
+ // riscv_vector.h
+ if (Name == "vsetvli" || Name == "vsetvlimax")
+ continue;
+
+ if (!SemaRecords)
+ continue;
+
+ // Create SemaRecord
+ SemaRecord SR;
+ SR.Name = Name.str();
+ SR.OverloadedName = OverloadedName.str();
+ BasicType TypeRangeMask = BasicType::Unknown;
+ for (char I : TypeRange)
+ TypeRangeMask |= ParseBasicType(I);
+
+ SR.TypeRangeMask = static_cast<unsigned>(TypeRangeMask);
+
+ unsigned Log2LMULMask = 0;
+ for (int Log2LMUL : Log2LMULList)
+ Log2LMULMask |= 1 << (Log2LMUL + 3);
+
+ SR.Log2LMULMask = Log2LMULMask;
+
+ SR.RequiredExtensions = 0;
+ for (auto RequiredFeature : RequiredFeatures) {
+ RVVRequire RequireExt =
+ StringSwitch<RVVRequire>(RequiredFeature)
+ .Case("RV64", RVV_REQ_RV64)
+ .Case("Zvfhmin", RVV_REQ_Zvfhmin)
+ .Case("Xsfvcp", RVV_REQ_Xsfvcp)
+ .Case("Xsfvfnrclipxfqf", RVV_REQ_Xsfvfnrclipxfqf)
+ .Case("Xsfvfwmaccqqq", RVV_REQ_Xsfvfwmaccqqq)
+ .Case("Xsfvqmaccdod", RVV_REQ_Xsfvqmaccdod)
+ .Case("Xsfvqmaccqoq", RVV_REQ_Xsfvqmaccqoq)
+ .Case("Zvbb", RVV_REQ_Zvbb)
+ .Case("Zvbc", RVV_REQ_Zvbc)
+ .Case("Zvkb", RVV_REQ_Zvkb)
+ .Case("Zvkg", RVV_REQ_Zvkg)
+ .Case("Zvkned", RVV_REQ_Zvkned)
+ .Case("Zvknha", RVV_REQ_Zvknha)
+ .Case("Zvknhb", RVV_REQ_Zvknhb)
+ .Case("Zvksed", RVV_REQ_Zvksed)
+ .Case("Zvksh", RVV_REQ_Zvksh)
+ .Case("Experimental", RVV_REQ_Experimental)
+ .Default(RVV_REQ_None);
+ assert(RequireExt != RVV_REQ_None && "Unrecognized required feature?");
+ SR.RequiredExtensions |= RequireExt;
+ }
-Optional<RVVTypes>
-RVVEmitter::computeTypes(BasicType BT, int Log2LMUL, unsigned NF,
- ArrayRef<std::string> PrototypeSeq) {
- // LMUL x NF must be less than or equal to 8.
- if ((Log2LMUL >= 1) && (1 << Log2LMUL) * NF > 8)
- return llvm::None;
-
- RVVTypes Types;
- for (const std::string &Proto : PrototypeSeq) {
- auto T = computeType(BT, Log2LMUL, Proto);
- if (!T.hasValue())
- return llvm::None;
- // Record legal type index
- Types.push_back(T.getValue());
+ SR.NF = NF;
+ SR.HasMasked = HasMasked;
+ SR.HasVL = HasVL;
+ SR.HasMaskedOffOperand = HasMaskedOffOperand;
+ SR.HasTailPolicy = HasTailPolicy;
+ SR.HasMaskPolicy = HasMaskPolicy;
+ SR.UnMaskedPolicyScheme = static_cast<uint8_t>(UnMaskedPolicyScheme);
+ SR.MaskedPolicyScheme = static_cast<uint8_t>(MaskedPolicyScheme);
+ SR.Prototype = std::move(BasicPrototype);
+ SR.Suffix = parsePrototypes(SuffixProto);
+ SR.OverloadedSuffix = parsePrototypes(OverloadedSuffixProto);
+ SR.IsTuple = IsTuple;
+ SR.HasFRMRoundModeOp = HasFRMRoundModeOp;
+
+ SemaRecords->push_back(SR);
}
- return Types;
}
-Optional<RVVTypePtr> RVVEmitter::computeType(BasicType BT, int Log2LMUL,
- StringRef Proto) {
- std::string Idx = Twine(Twine(BT) + Twine(Log2LMUL) + Proto).str();
- // Search first
- auto It = LegalTypes.find(Idx);
- if (It != LegalTypes.end())
- return &(It->second);
- if (IllegalTypes.count(Idx))
- return llvm::None;
- // Compute type and record the result.
- RVVType T(BT, Log2LMUL, Proto);
- if (T.isValid()) {
- // Record legal type index and value.
- LegalTypes.insert({Idx, T});
- return &(LegalTypes[Idx]);
+void RVVEmitter::printHeaderCode(raw_ostream &OS) {
+ std::vector<Record *> RVVHeaders =
+ Records.getAllDerivedDefinitions("RVVHeader");
+ for (auto *R : RVVHeaders) {
+ StringRef HeaderCodeStr = R->getValueAsString("HeaderCode");
+ OS << HeaderCodeStr.str();
}
- // Record illegal type index.
- IllegalTypes.insert(Idx);
- return llvm::None;
}
-void RVVEmitter::emitArchMacroAndBody(
- std::vector<std::unique_ptr<RVVIntrinsic>> &Defs, raw_ostream &OS,
- std::function<void(raw_ostream &, const RVVIntrinsic &)> PrintBody) {
- uint8_t PrevExt = (*Defs.begin())->getRISCVExtensions();
- bool NeedEndif = emitExtDefStr(PrevExt, OS);
- for (auto &Def : Defs) {
- uint8_t CurExt = Def->getRISCVExtensions();
- if (CurExt != PrevExt) {
- if (NeedEndif)
- OS << "#endif\n\n";
- NeedEndif = emitExtDefStr(CurExt, OS);
- PrevExt = CurExt;
- }
- if (Def->hasAutoDef())
- PrintBody(OS, *Def);
+void RVVEmitter::createRVVIntrinsicRecords(std::vector<RVVIntrinsicRecord> &Out,
+ SemaSignatureTable &SST,
+ ArrayRef<SemaRecord> SemaRecords) {
+ SST.init(SemaRecords);
+
+ for (const auto &SR : SemaRecords) {
+ Out.emplace_back(RVVIntrinsicRecord());
+ RVVIntrinsicRecord &R = Out.back();
+ R.Name = SR.Name.c_str();
+ R.OverloadedName = SR.OverloadedName.c_str();
+ R.PrototypeIndex = SST.getIndex(SR.Prototype);
+ R.SuffixIndex = SST.getIndex(SR.Suffix);
+ R.OverloadedSuffixIndex = SST.getIndex(SR.OverloadedSuffix);
+ R.PrototypeLength = SR.Prototype.size();
+ R.SuffixLength = SR.Suffix.size();
+ R.OverloadedSuffixSize = SR.OverloadedSuffix.size();
+ R.RequiredExtensions = SR.RequiredExtensions;
+ R.TypeRangeMask = SR.TypeRangeMask;
+ R.Log2LMULMask = SR.Log2LMULMask;
+ R.NF = SR.NF;
+ R.HasMasked = SR.HasMasked;
+ R.HasVL = SR.HasVL;
+ R.HasMaskedOffOperand = SR.HasMaskedOffOperand;
+ R.HasTailPolicy = SR.HasTailPolicy;
+ R.HasMaskPolicy = SR.HasMaskPolicy;
+ R.UnMaskedPolicyScheme = SR.UnMaskedPolicyScheme;
+ R.MaskedPolicyScheme = SR.MaskedPolicyScheme;
+ R.IsTuple = SR.IsTuple;
+ R.HasFRMRoundModeOp = SR.HasFRMRoundModeOp;
+
+ assert(R.PrototypeIndex !=
+ static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX));
+ assert(R.SuffixIndex !=
+ static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX));
+ assert(R.OverloadedSuffixIndex !=
+ static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX));
}
- if (NeedEndif)
- OS << "#endif\n\n";
}
-bool RVVEmitter::emitExtDefStr(uint8_t Extents, raw_ostream &OS) {
- if (Extents == RISCVExtension::Basic)
- return false;
- OS << "#if ";
- ListSeparator LS(" && ");
- if (Extents & RISCVExtension::F)
- OS << LS << "defined(__riscv_f)";
- if (Extents & RISCVExtension::D)
- OS << LS << "defined(__riscv_d)";
- if (Extents & RISCVExtension::Zfh)
- OS << LS << "defined(__riscv_zfh)";
- if (Extents & RISCVExtension::Zvamo)
- OS << LS << "defined(__riscv_zvamo)";
- if (Extents & RISCVExtension::Zvlsseg)
- OS << LS << "defined(__riscv_zvlsseg)";
- OS << "\n";
- return true;
+void RVVEmitter::createSema(raw_ostream &OS) {
+ std::vector<std::unique_ptr<RVVIntrinsic>> Defs;
+ std::vector<RVVIntrinsicRecord> RVVIntrinsicRecords;
+ SemaSignatureTable SST;
+ std::vector<SemaRecord> SemaRecords;
+
+ createRVVIntrinsics(Defs, &SemaRecords);
+
+ createRVVIntrinsicRecords(RVVIntrinsicRecords, SST, SemaRecords);
+
+ // Emit signature table for SemaRISCVVectorLookup.cpp.
+ OS << "#ifdef DECL_SIGNATURE_TABLE\n";
+ SST.print(OS);
+ OS << "#endif\n";
+
+ // Emit RVVIntrinsicRecords for SemaRISCVVectorLookup.cpp.
+ OS << "#ifdef DECL_INTRINSIC_RECORDS\n";
+ for (const RVVIntrinsicRecord &Record : RVVIntrinsicRecords)
+ OS << Record;
+ OS << "#endif\n";
}
namespace clang {
@@ -1266,4 +778,8 @@ void EmitRVVBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {
RVVEmitter(Records).createCodeGen(OS);
}
+void EmitRVVBuiltinSema(RecordKeeper &Records, raw_ostream &OS) {
+ RVVEmitter(Records).createSema(OS);
+}
+
} // End namespace clang
diff --git a/contrib/llvm-project/clang/utils/TableGen/SveEmitter.cpp b/contrib/llvm-project/clang/utils/TableGen/SveEmitter.cpp
index b2f6ede56522..174304f09007 100644
--- a/contrib/llvm-project/clang/utils/TableGen/SveEmitter.cpp
+++ b/contrib/llvm-project/clang/utils/TableGen/SveEmitter.cpp
@@ -23,16 +23,17 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/TableGen/Record.h"
+#include "llvm/ADT/StringMap.h"
#include "llvm/TableGen/Error.h"
-#include <string>
-#include <sstream>
-#include <set>
+#include "llvm/TableGen/Record.h"
+#include <array>
#include <cctype>
+#include <set>
+#include <sstream>
+#include <string>
#include <tuple>
using namespace llvm;
@@ -43,6 +44,8 @@ enum ClassKind {
ClassG, // Overloaded name without type suffix
};
+enum class ACLEKind { SVE, SME };
+
using TypeSpec = std::string;
namespace {
@@ -64,24 +67,29 @@ public:
};
class SVEType {
- TypeSpec TS;
bool Float, Signed, Immediate, Void, Constant, Pointer, BFloat;
- bool DefaultType, IsScalable, Predicate, PredicatePattern, PrefetchOp;
+ bool DefaultType, IsScalable, Predicate, PredicatePattern, PrefetchOp,
+ Svcount;
unsigned Bitwidth, ElementBitwidth, NumVectors;
public:
- SVEType() : SVEType(TypeSpec(), 'v') {}
+ SVEType() : SVEType("", 'v') {}
- SVEType(TypeSpec TS, char CharMod)
- : TS(TS), Float(false), Signed(true), Immediate(false), Void(false),
+ SVEType(StringRef TS, char CharMod, unsigned NumVectors = 1)
+ : Float(false), Signed(true), Immediate(false), Void(false),
Constant(false), Pointer(false), BFloat(false), DefaultType(false),
IsScalable(true), Predicate(false), PredicatePattern(false),
- PrefetchOp(false), Bitwidth(128), ElementBitwidth(~0U), NumVectors(1) {
+ PrefetchOp(false), Svcount(false), Bitwidth(128), ElementBitwidth(~0U),
+ NumVectors(NumVectors) {
if (!TS.empty())
- applyTypespec();
+ applyTypespec(TS);
applyModifier(CharMod);
}
+ SVEType(const SVEType &Base, unsigned NumV) : SVEType(Base) {
+ NumVectors = NumV;
+ }
+
bool isPointer() const { return Pointer; }
bool isVoidPointer() const { return Pointer && Void; }
bool isSigned() const { return Signed; }
@@ -89,19 +97,23 @@ public:
bool isScalar() const { return NumVectors == 0; }
bool isVector() const { return NumVectors > 0; }
bool isScalableVector() const { return isVector() && IsScalable; }
+ bool isFixedLengthVector() const { return isVector() && !IsScalable; }
bool isChar() const { return ElementBitwidth == 8; }
bool isVoid() const { return Void & !Pointer; }
bool isDefault() const { return DefaultType; }
bool isFloat() const { return Float && !BFloat; }
bool isBFloat() const { return BFloat && !Float; }
bool isFloatingPoint() const { return Float || BFloat; }
- bool isInteger() const { return !isFloatingPoint() && !Predicate; }
+ bool isInteger() const {
+ return !isFloatingPoint() && !Predicate && !Svcount;
+ }
bool isScalarPredicate() const {
return !isFloatingPoint() && Predicate && NumVectors == 0;
}
bool isPredicateVector() const { return Predicate; }
bool isPredicatePattern() const { return PredicatePattern; }
bool isPrefetchOp() const { return PrefetchOp; }
+ bool isSvcount() const { return Svcount; }
bool isConstant() const { return Constant; }
unsigned getElementSizeInBits() const { return ElementBitwidth; }
unsigned getNumVectors() const { return NumVectors; }
@@ -124,13 +136,12 @@ public:
private:
/// Creates the type based on the typespec string in TS.
- void applyTypespec();
+ void applyTypespec(StringRef TS);
/// Applies a prototype modifier to the type.
void applyModifier(char Mod);
};
-
class SVEEmitter;
/// The main grunt class. This represents an instantiation of an intrinsic with
@@ -189,7 +200,9 @@ public:
SVEType getReturnType() const { return Types[0]; }
ArrayRef<SVEType> getTypes() const { return Types; }
SVEType getParamType(unsigned I) const { return Types[I + 1]; }
- unsigned getNumParams() const { return Proto.size() - 1; }
+ unsigned getNumParams() const {
+ return Proto.size() - (2 * llvm::count(Proto, '.')) - 1;
+ }
uint64_t getFlags() const { return Flags; }
bool isFlagSet(uint64_t Flag) const { return Flags & Flag;}
@@ -203,6 +216,9 @@ public:
/// ClassS, so will add type suffixes such as _u32/_s32.
std::string getMangledName() const { return mangleName(ClassS); }
+ /// As above, but mangles the LLVM name instead.
+ std::string getMangledLLVMName() const { return mangleLLVMName(); }
+
/// Returns true if the intrinsic is overloaded, in that it should also generate
/// a short form without the type-specifiers, e.g. 'svld1(..)' instead of
/// 'svld1_u32(..)'.
@@ -220,19 +236,28 @@ public:
/// Return the parameter index of the splat operand.
unsigned getSplatIdx() const {
- // These prototype modifiers are described in arm_sve.td.
- auto Idx = Proto.find_first_of("ajfrKLR@");
- assert(Idx != std::string::npos && Idx > 0 &&
- "Prototype has no splat operand");
- return Idx - 1;
+ unsigned I = 1, Param = 0;
+ for (; I < Proto.size(); ++I, ++Param) {
+ if (Proto[I] == 'a' || Proto[I] == 'j' || Proto[I] == 'f' ||
+ Proto[I] == 'r' || Proto[I] == 'K' || Proto[I] == 'L' ||
+ Proto[I] == 'R' || Proto[I] == '@')
+ break;
+
+ // Multivector modifier can be skipped
+ if (Proto[I] == '.')
+ I += 2;
+ }
+ assert(I != Proto.size() && "Prototype has no splat operand");
+ return Param;
}
/// Emits the intrinsic declaration to the ostream.
- void emitIntrinsic(raw_ostream &OS) const;
+ void emitIntrinsic(raw_ostream &OS, SVEEmitter &Emitter, ACLEKind Kind) const;
private:
std::string getMergeSuffix() const { return MergeSuffix; }
std::string mangleName(ClassKind LocalCK) const;
+ std::string mangleLLVMName() const;
std::string replaceTemplatedArgs(std::string Name, TypeSpec TS,
std::string Proto) const;
};
@@ -244,17 +269,11 @@ private:
// which is inconvenient to specify in the arm_sve.td file or
// generate in CGBuiltin.cpp.
struct ReinterpretTypeInfo {
+ SVEType BaseType;
const char *Suffix;
- const char *Type;
- const char *BuiltinType;
};
- SmallVector<ReinterpretTypeInfo, 12> Reinterprets = {
- {"s8", "svint8_t", "q16Sc"}, {"s16", "svint16_t", "q8Ss"},
- {"s32", "svint32_t", "q4Si"}, {"s64", "svint64_t", "q2SWi"},
- {"u8", "svuint8_t", "q16Uc"}, {"u16", "svuint16_t", "q8Us"},
- {"u32", "svuint32_t", "q4Ui"}, {"u64", "svuint64_t", "q2UWi"},
- {"f16", "svfloat16_t", "q8h"}, {"bf16", "svbfloat16_t", "q8y"},
- {"f32", "svfloat32_t", "q4f"}, {"f64", "svfloat64_t", "q2d"}};
+
+ static const std::array<ReinterpretTypeInfo, 12> Reinterprets;
RecordKeeper &Records;
llvm::StringMap<uint64_t> EltTypes;
@@ -298,7 +317,8 @@ public:
auto It = FlagTypes.find(MaskName);
if (It != FlagTypes.end()) {
uint64_t Mask = It->getValue();
- unsigned Shift = llvm::countTrailingZeros(Mask);
+ unsigned Shift = llvm::countr_zero(Mask);
+ assert(Shift < 64 && "Mask value produced an invalid shift value");
return (V << Shift) & Mask;
}
llvm_unreachable("Unsupported flag");
@@ -334,6 +354,10 @@ public:
/// Emit arm_sve.h.
void createHeader(raw_ostream &o);
+ // Emits core intrinsics in both arm_sme.h and arm_sve.h
+ void createCoreHeaderIntrinsics(raw_ostream &o, SVEEmitter &Emitter,
+ ACLEKind Kind);
+
/// Emit all the __builtin prototypes and code needed by Sema.
void createBuiltins(raw_ostream &o);
@@ -346,10 +370,43 @@ public:
/// Create the SVETypeFlags used in CGBuiltins
void createTypeFlags(raw_ostream &o);
+ /// Emit arm_sme.h.
+ void createSMEHeader(raw_ostream &o);
+
+ /// Emit all the SME __builtin prototypes and code needed by Sema.
+ void createSMEBuiltins(raw_ostream &o);
+
+ /// Emit all the information needed to map builtin -> LLVM IR intrinsic.
+ void createSMECodeGenMap(raw_ostream &o);
+
+ /// Create a table for a builtin's requirement for PSTATE.SM.
+ void createStreamingAttrs(raw_ostream &o, ACLEKind Kind);
+
+ /// Emit all the range checks for the immediates.
+ void createSMERangeChecks(raw_ostream &o);
+
+ /// Create a table for a builtin's requirement for PSTATE.ZA.
+ void createBuiltinZAState(raw_ostream &OS);
+
/// Create intrinsic and add it to \p Out
- void createIntrinsic(Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out);
+ void createIntrinsic(Record *R,
+ SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out);
};
+const std::array<SVEEmitter::ReinterpretTypeInfo, 12> SVEEmitter::Reinterprets =
+ {{{SVEType("c", 'd'), "s8"},
+ {SVEType("Uc", 'd'), "u8"},
+ {SVEType("s", 'd'), "s16"},
+ {SVEType("Us", 'd'), "u16"},
+ {SVEType("i", 'd'), "s32"},
+ {SVEType("Ui", 'd'), "u32"},
+ {SVEType("l", 'd'), "s64"},
+ {SVEType("Ul", 'd'), "u64"},
+ {SVEType("h", 'd'), "f16"},
+ {SVEType("b", 'd'), "bf16"},
+ {SVEType("f", 'd'), "f32"},
+ {SVEType("d", 'd'), "f64"}}};
+
} // end anonymous namespace
@@ -365,6 +422,9 @@ std::string SVEType::builtin_str() const {
if (isScalarPredicate())
return "b";
+ if (isSvcount())
+ return "Qa";
+
if (isVoidPointer())
S += "v";
else if (!isFloatingPoint())
@@ -413,7 +473,8 @@ std::string SVEType::builtin_str() const {
return S;
}
- assert(isScalableVector() && "Unsupported type");
+ if (isFixedLengthVector())
+ return "V" + utostr(getNumElements() * NumVectors) + S;
return "q" + utostr(getNumElements() * NumVectors) + S;
}
@@ -428,13 +489,15 @@ std::string SVEType::str() const {
if (Void)
S += "void";
else {
- if (isScalableVector())
+ if (isScalableVector() || isSvcount())
S += "sv";
if (!Signed && !isFloatingPoint())
S += "u";
if (Float)
S += "float";
+ else if (isSvcount())
+ S += "count";
else if (isScalarPredicate() || isPredicateVector())
S += "bool";
else if (isBFloat())
@@ -442,9 +505,9 @@ std::string SVEType::str() const {
else
S += "int";
- if (!isScalarPredicate() && !isPredicateVector())
+ if (!isScalarPredicate() && !isPredicateVector() && !isSvcount())
S += utostr(ElementBitwidth);
- if (!isScalableVector() && isVector())
+ if (isFixedLengthVector())
S += "x" + utostr(getNumElements());
if (NumVectors > 1)
S += "x" + utostr(NumVectors);
@@ -459,9 +522,13 @@ std::string SVEType::str() const {
return S;
}
-void SVEType::applyTypespec() {
+
+void SVEType::applyTypespec(StringRef TS) {
for (char I : TS) {
switch (I) {
+ case 'Q':
+ Svcount = true;
+ break;
case 'P':
Predicate = true;
break;
@@ -480,6 +547,9 @@ void SVEType::applyTypespec() {
case 'l':
ElementBitwidth = 64;
break;
+ case 'q':
+ ElementBitwidth = 128;
+ break;
case 'h':
Float = true;
ElementBitwidth = 16;
@@ -506,15 +576,6 @@ void SVEType::applyTypespec() {
void SVEType::applyModifier(char Mod) {
switch (Mod) {
- case '2':
- NumVectors = 2;
- break;
- case '3':
- NumVectors = 3;
- break;
- case '4':
- NumVectors = 4;
- break;
case 'v':
Void = true;
break;
@@ -523,7 +584,7 @@ void SVEType::applyModifier(char Mod) {
break;
case 'c':
Constant = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case 'p':
Pointer = true;
Bitwidth = ElementBitwidth;
@@ -553,9 +614,15 @@ void SVEType::applyModifier(char Mod) {
Float = false;
BFloat = false;
Predicate = true;
+ Svcount = false;
Bitwidth = 16;
ElementBitwidth = 1;
break;
+ case '{':
+ IsScalable = false;
+ Bitwidth = 128;
+ NumVectors = 1;
+ break;
case 's':
case 'a':
Bitwidth = ElementBitwidth;
@@ -592,18 +659,21 @@ void SVEType::applyModifier(char Mod) {
break;
case 'u':
Predicate = false;
+ Svcount = false;
Signed = false;
Float = false;
BFloat = false;
break;
case 'x':
Predicate = false;
+ Svcount = false;
Signed = true;
Float = false;
BFloat = false;
break;
case 'i':
Predicate = false;
+ Svcount = false;
Float = false;
BFloat = false;
ElementBitwidth = Bitwidth = 64;
@@ -613,6 +683,7 @@ void SVEType::applyModifier(char Mod) {
break;
case 'I':
Predicate = false;
+ Svcount = false;
Float = false;
BFloat = false;
ElementBitwidth = Bitwidth = 32;
@@ -623,6 +694,7 @@ void SVEType::applyModifier(char Mod) {
break;
case 'J':
Predicate = false;
+ Svcount = false;
Float = false;
BFloat = false;
ElementBitwidth = Bitwidth = 32;
@@ -633,6 +705,7 @@ void SVEType::applyModifier(char Mod) {
break;
case 'k':
Predicate = false;
+ Svcount = false;
Signed = true;
Float = false;
BFloat = false;
@@ -641,6 +714,7 @@ void SVEType::applyModifier(char Mod) {
break;
case 'l':
Predicate = false;
+ Svcount = false;
Signed = true;
Float = false;
BFloat = false;
@@ -649,6 +723,7 @@ void SVEType::applyModifier(char Mod) {
break;
case 'm':
Predicate = false;
+ Svcount = false;
Signed = false;
Float = false;
BFloat = false;
@@ -657,6 +732,7 @@ void SVEType::applyModifier(char Mod) {
break;
case 'n':
Predicate = false;
+ Svcount = false;
Signed = false;
Float = false;
BFloat = false;
@@ -681,6 +757,12 @@ void SVEType::applyModifier(char Mod) {
BFloat = false;
ElementBitwidth = 64;
break;
+ case '[':
+ Signed = false;
+ Float = false;
+ BFloat = false;
+ ElementBitwidth = 8;
+ break;
case 't':
Signed = true;
Float = false;
@@ -695,17 +777,20 @@ void SVEType::applyModifier(char Mod) {
break;
case 'O':
Predicate = false;
+ Svcount = false;
Float = true;
ElementBitwidth = 16;
break;
case 'M':
Predicate = false;
+ Svcount = false;
Float = true;
BFloat = false;
ElementBitwidth = 32;
break;
case 'N':
Predicate = false;
+ Svcount = false;
Float = true;
ElementBitwidth = 64;
break;
@@ -757,6 +842,11 @@ void SVEType::applyModifier(char Mod) {
NumVectors = 0;
Signed = true;
break;
+ case '%':
+ Pointer = true;
+ Void = true;
+ NumVectors = 0;
+ break;
case 'A':
Pointer = true;
ElementBitwidth = Bitwidth = 8;
@@ -799,11 +889,51 @@ void SVEType::applyModifier(char Mod) {
NumVectors = 0;
Signed = false;
break;
+ case '$':
+ Predicate = false;
+ Svcount = false;
+ Float = false;
+ BFloat = true;
+ ElementBitwidth = 16;
+ break;
+ case '}':
+ Predicate = false;
+ Signed = true;
+ Svcount = true;
+ NumVectors = 0;
+ Float = false;
+ BFloat = false;
+ break;
+ case '.':
+ llvm_unreachable(". is never a type in itself");
+ break;
default:
llvm_unreachable("Unhandled character!");
}
}
+/// Returns the modifier and number of vectors for the given operand \p Op.
+std::pair<char, unsigned> getProtoModifier(StringRef Proto, unsigned Op) {
+ for (unsigned P = 0; !Proto.empty(); ++P) {
+ unsigned NumVectors = 1;
+ unsigned CharsToSkip = 1;
+ char Mod = Proto[0];
+ if (Mod == '2' || Mod == '3' || Mod == '4') {
+ NumVectors = Mod - '0';
+ Mod = 'd';
+ if (Proto.size() > 1 && Proto[1] == '.') {
+ Mod = Proto[2];
+ CharsToSkip = 3;
+ }
+ }
+
+ if (P == Op)
+ return {Mod, NumVectors};
+
+ Proto = Proto.drop_front(CharsToSkip);
+ }
+ llvm_unreachable("Unexpected Op");
+}
//===----------------------------------------------------------------------===//
// Intrinsic implementation
@@ -819,8 +949,11 @@ Intrinsic::Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy,
MergeSuffix(MergeSuffix.str()), BaseType(BT, 'd'), Flags(Flags),
ImmChecks(Checks.begin(), Checks.end()) {
// Types[0] is the return value.
- for (unsigned I = 0; I < Proto.size(); ++I) {
- SVEType T(BaseTypeSpec, Proto[I]);
+ for (unsigned I = 0; I < (getNumParams() + 1); ++I) {
+ char Mod;
+ unsigned NumVectors;
+ std::tie(Mod, NumVectors) = getProtoModifier(Proto, I);
+ SVEType T(BaseTypeSpec, Mod, NumVectors);
Types.push_back(T);
// Add range checks for immediates
@@ -879,6 +1012,8 @@ std::string Intrinsic::replaceTemplatedArgs(std::string Name, TypeSpec TS,
std::string TypeCode;
if (T.isInteger())
TypeCode = T.isSigned() ? 's' : 'u';
+ else if (T.isSvcount())
+ TypeCode = 'c';
else if (T.isPredicateVector())
TypeCode = 'b';
else if (T.isBFloat())
@@ -891,6 +1026,13 @@ std::string Intrinsic::replaceTemplatedArgs(std::string Name, TypeSpec TS,
return Ret;
}
+std::string Intrinsic::mangleLLVMName() const {
+ std::string S = getLLVMName();
+
+ // Replace all {d} like expressions with e.g. 'u32'
+ return replaceTemplatedArgs(S, getBaseTypeSpec(), getProto());
+}
+
std::string Intrinsic::mangleName(ClassKind LocalCK) const {
std::string S = getName();
@@ -918,15 +1060,25 @@ std::string Intrinsic::mangleName(ClassKind LocalCK) const {
getMergeSuffix();
}
-void Intrinsic::emitIntrinsic(raw_ostream &OS) const {
+void Intrinsic::emitIntrinsic(raw_ostream &OS, SVEEmitter &Emitter,
+ ACLEKind Kind) const {
bool IsOverloaded = getClassKind() == ClassG && getProto().size() > 1;
std::string FullName = mangleName(ClassS);
std::string ProtoName = mangleName(getClassKind());
-
OS << (IsOverloaded ? "__aio " : "__ai ")
- << "__attribute__((__clang_arm_builtin_alias("
- << "__builtin_sve_" << FullName << ")))\n";
+ << "__attribute__((__clang_arm_builtin_alias(";
+
+ switch (Kind) {
+ case ACLEKind::SME:
+ OS << "__builtin_sme_" << FullName << ")";
+ break;
+ case ACLEKind::SVE:
+ OS << "__builtin_sve_" << FullName << ")";
+ break;
+ }
+
+ OS << "))\n";
OS << getTypes()[0].str() << " " << ProtoName << "(";
for (unsigned I = 0; I < getTypes().size() - 1; ++I) {
@@ -959,7 +1111,7 @@ uint64_t SVEEmitter::encodeTypeFlags(const SVEType &T) {
return encodeEltType("EltTyBFloat16");
}
- if (T.isPredicateVector()) {
+ if (T.isPredicateVector() || T.isSvcount()) {
switch (T.getElementSizeInBits()) {
case 8:
return encodeEltType("EltTyBool8");
@@ -983,6 +1135,8 @@ uint64_t SVEEmitter::encodeTypeFlags(const SVEType &T) {
return encodeEltType("EltTyInt32");
case 64:
return encodeEltType("EltTyInt64");
+ case 128:
+ return encodeEltType("EltTyInt128");
default:
llvm_unreachable("Unhandled integer element bitwidth!");
}
@@ -993,7 +1147,7 @@ void SVEEmitter::createIntrinsic(
StringRef Name = R->getValueAsString("Name");
StringRef Proto = R->getValueAsString("Prototype");
StringRef Types = R->getValueAsString("Types");
- StringRef Guard = R->getValueAsString("ArchGuard");
+ StringRef Guard = R->getValueAsString("TargetGuard");
StringRef LLVMName = R->getValueAsString("LLVMIntrinsic");
uint64_t Merge = R->getValueAsInt("Merge");
StringRef MergeSuffix = R->getValueAsString("MergeSuffix");
@@ -1039,10 +1193,11 @@ void SVEEmitter::createIntrinsic(
assert(Arg >= 0 && Kind >= 0 && "Arg and Kind must be nonnegative");
unsigned ElementSizeInBits = 0;
+ char Mod;
+ unsigned NumVectors;
+ std::tie(Mod, NumVectors) = getProtoModifier(Proto, EltSizeArg + 1);
if (EltSizeArg >= 0)
- ElementSizeInBits =
- SVEType(TS, Proto[EltSizeArg + /* offset by return arg */ 1])
- .getElementSizeInBits();
+ ElementSizeInBits = SVEType(TS, Mod, NumVectors).getElementSizeInBits();
ImmChecks.push_back(ImmCheck(Arg, Kind, ElementSizeInBits));
}
@@ -1058,6 +1213,34 @@ void SVEEmitter::createIntrinsic(
}
}
+void SVEEmitter::createCoreHeaderIntrinsics(raw_ostream &OS,
+ SVEEmitter &Emitter,
+ ACLEKind Kind) {
+ SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
+ std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
+ for (auto *R : RV)
+ createIntrinsic(R, Defs);
+
+ // Sort intrinsics in header file by following order/priority:
+ // - Architectural guard (i.e. does it require SVE2 or SVE2_AES)
+ // - Class (is intrinsic overloaded or not)
+ // - Intrinsic name
+ std::stable_sort(Defs.begin(), Defs.end(),
+ [](const std::unique_ptr<Intrinsic> &A,
+ const std::unique_ptr<Intrinsic> &B) {
+ auto ToTuple = [](const std::unique_ptr<Intrinsic> &I) {
+ return std::make_tuple(I->getGuard(),
+ (unsigned)I->getClassKind(),
+ I->getName());
+ };
+ return ToTuple(A) < ToTuple(B);
+ });
+
+ // Actually emit the intrinsic declarations.
+ for (auto &I : Defs)
+ I->emitIntrinsic(OS, Emitter, Kind);
+}
+
void SVEEmitter::createHeader(raw_ostream &OS) {
OS << "/*===---- arm_sve.h - ARM SVE intrinsics "
"-----------------------------------===\n"
@@ -1075,10 +1258,6 @@ void SVEEmitter::createHeader(raw_ostream &OS) {
OS << "#ifndef __ARM_SVE_H\n";
OS << "#define __ARM_SVE_H\n\n";
- OS << "#if !defined(__ARM_FEATURE_SVE)\n";
- OS << "#error \"SVE support not enabled\"\n";
- OS << "#else\n\n";
-
OS << "#if !defined(__LITTLE_ENDIAN__)\n";
OS << "#error \"Big endian is currently not supported for arm_sve.h\"\n";
OS << "#endif\n";
@@ -1104,20 +1283,10 @@ void SVEEmitter::createHeader(raw_ostream &OS) {
OS << "typedef __SVUint64_t svuint64_t;\n";
OS << "typedef __SVFloat16_t svfloat16_t;\n\n";
- OS << "#if defined(__ARM_FEATURE_SVE_BF16) && "
- "!defined(__ARM_FEATURE_BF16_SCALAR_ARITHMETIC)\n";
- OS << "#error \"__ARM_FEATURE_BF16_SCALAR_ARITHMETIC must be defined when "
- "__ARM_FEATURE_SVE_BF16 is defined\"\n";
- OS << "#endif\n\n";
-
- OS << "#if defined(__ARM_FEATURE_SVE_BF16)\n";
- OS << "typedef __SVBFloat16_t svbfloat16_t;\n";
- OS << "#endif\n\n";
+ OS << "typedef __SVBfloat16_t svbfloat16_t;\n";
- OS << "#if defined(__ARM_FEATURE_BF16_SCALAR_ARITHMETIC)\n";
OS << "#include <arm_bf16.h>\n";
- OS << "typedef __bf16 bfloat16_t;\n";
- OS << "#endif\n\n";
+ OS << "#include <arm_vector_types.h>\n";
OS << "typedef __SVFloat32_t svfloat32_t;\n";
OS << "typedef __SVFloat64_t svfloat64_t;\n";
@@ -1154,13 +1323,15 @@ void SVEEmitter::createHeader(raw_ostream &OS) {
OS << "typedef __clang_svfloat16x4_t svfloat16x4_t;\n";
OS << "typedef __clang_svfloat32x4_t svfloat32x4_t;\n";
OS << "typedef __clang_svfloat64x4_t svfloat64x4_t;\n";
- OS << "typedef __SVBool_t svbool_t;\n\n";
+ OS << "typedef __SVBool_t svbool_t;\n";
+ OS << "typedef __clang_svboolx2_t svboolx2_t;\n";
+ OS << "typedef __clang_svboolx4_t svboolx4_t;\n\n";
- OS << "#ifdef __ARM_FEATURE_SVE_BF16\n";
OS << "typedef __clang_svbfloat16x2_t svbfloat16x2_t;\n";
OS << "typedef __clang_svbfloat16x3_t svbfloat16x3_t;\n";
OS << "typedef __clang_svbfloat16x4_t svbfloat16x4_t;\n";
- OS << "#endif\n";
+
+ OS << "typedef __SVCount_t svcount_t;\n\n";
OS << "enum svpattern\n";
OS << "{\n";
@@ -1206,69 +1377,34 @@ void SVEEmitter::createHeader(raw_ostream &OS) {
"__nodebug__, __overloadable__))\n\n";
// Add reinterpret functions.
- for (auto ShortForm : { false, true } )
- for (const ReinterpretTypeInfo &From : Reinterprets)
+ for (auto [N, Suffix] :
+ std::initializer_list<std::pair<unsigned, const char *>>{
+ {1, ""}, {2, "_x2"}, {3, "_x3"}, {4, "_x4"}}) {
+ for (auto ShortForm : {false, true})
for (const ReinterpretTypeInfo &To : Reinterprets) {
- const bool IsBFloat = StringRef(From.Suffix).equals("bf16") ||
- StringRef(To.Suffix).equals("bf16");
- if (IsBFloat)
- OS << "#if defined(__ARM_FEATURE_SVE_BF16)\n";
- if (ShortForm) {
- OS << "__aio " << From.Type << " svreinterpret_" << From.Suffix;
- OS << "(" << To.Type << " op) {\n";
- OS << " return __builtin_sve_reinterpret_" << From.Suffix << "_"
- << To.Suffix << "(op);\n";
- OS << "}\n\n";
- } else
- OS << "#define svreinterpret_" << From.Suffix << "_" << To.Suffix
- << "(...) __builtin_sve_reinterpret_" << From.Suffix << "_"
- << To.Suffix << "(__VA_ARGS__)\n";
- if (IsBFloat)
- OS << "#endif /* #if defined(__ARM_FEATURE_SVE_BF16) */\n";
+ SVEType ToV(To.BaseType, N);
+ for (const ReinterpretTypeInfo &From : Reinterprets) {
+ SVEType FromV(From.BaseType, N);
+ if (ShortForm) {
+ OS << "__aio __attribute__((target(\"sve\"))) " << ToV.str()
+ << " svreinterpret_" << To.Suffix;
+ OS << "(" << FromV.str() << " op) __arm_streaming_compatible {\n";
+ OS << " return __builtin_sve_reinterpret_" << To.Suffix << "_"
+ << From.Suffix << Suffix << "(op);\n";
+ OS << "}\n\n";
+ } else
+ OS << "#define svreinterpret_" << To.Suffix << "_" << From.Suffix
+ << Suffix << "(...) __builtin_sve_reinterpret_" << To.Suffix
+ << "_" << From.Suffix << Suffix << "(__VA_ARGS__)\n";
+ }
}
-
- SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
- std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
- for (auto *R : RV)
- createIntrinsic(R, Defs);
-
- // Sort intrinsics in header file by following order/priority:
- // - Architectural guard (i.e. does it require SVE2 or SVE2_AES)
- // - Class (is intrinsic overloaded or not)
- // - Intrinsic name
- std::stable_sort(
- Defs.begin(), Defs.end(), [](const std::unique_ptr<Intrinsic> &A,
- const std::unique_ptr<Intrinsic> &B) {
- auto ToTuple = [](const std::unique_ptr<Intrinsic> &I) {
- return std::make_tuple(I->getGuard(), (unsigned)I->getClassKind(), I->getName());
- };
- return ToTuple(A) < ToTuple(B);
- });
-
- StringRef InGuard = "";
- for (auto &I : Defs) {
- // Emit #endif/#if pair if needed.
- if (I->getGuard() != InGuard) {
- if (!InGuard.empty())
- OS << "#endif //" << InGuard << "\n";
- InGuard = I->getGuard();
- if (!InGuard.empty())
- OS << "\n#if " << InGuard << "\n";
- }
-
- // Actually emit the intrinsic declaration.
- I->emitIntrinsic(OS);
}
- if (!InGuard.empty())
- OS << "#endif //" << InGuard << "\n";
+ createCoreHeaderIntrinsics(OS, *this, ACLEKind::SVE);
- OS << "#if defined(__ARM_FEATURE_SVE_BF16)\n";
OS << "#define svcvtnt_bf16_x svcvtnt_bf16_m\n";
OS << "#define svcvtnt_bf16_f32_x svcvtnt_bf16_f32_m\n";
- OS << "#endif /*__ARM_FEATURE_SVE_BF16 */\n\n";
- OS << "#if defined(__ARM_FEATURE_SVE2)\n";
OS << "#define svcvtnt_f16_x svcvtnt_f16_m\n";
OS << "#define svcvtnt_f16_f32_x svcvtnt_f16_f32_m\n";
OS << "#define svcvtnt_f32_x svcvtnt_f32_m\n";
@@ -1277,12 +1413,11 @@ void SVEEmitter::createHeader(raw_ostream &OS) {
OS << "#define svcvtxnt_f32_x svcvtxnt_f32_m\n";
OS << "#define svcvtxnt_f32_f64_x svcvtxnt_f32_f64_m\n\n";
- OS << "#endif /*__ARM_FEATURE_SVE2 */\n\n";
-
OS << "#ifdef __cplusplus\n";
OS << "} // extern \"C\"\n";
OS << "#endif\n\n";
- OS << "#endif /*__ARM_FEATURE_SVE */\n\n";
+ OS << "#undef __ai\n\n";
+ OS << "#undef __aio\n\n";
OS << "#endif /* __ARM_SVE_H */\n";
}
@@ -1303,19 +1438,28 @@ void SVEEmitter::createBuiltins(raw_ostream &OS) {
// Only create BUILTINs for non-overloaded intrinsics, as overloaded
// declarations only live in the header file.
if (Def->getClassKind() != ClassG)
- OS << "BUILTIN(__builtin_sve_" << Def->getMangledName() << ", \""
- << Def->getBuiltinTypeStr() << "\", \"n\")\n";
+ OS << "TARGET_BUILTIN(__builtin_sve_" << Def->getMangledName() << ", \""
+ << Def->getBuiltinTypeStr() << "\", \"n\", \"" << Def->getGuard()
+ << "\")\n";
}
- // Add reinterpret builtins
- for (const ReinterpretTypeInfo &From : Reinterprets)
- for (const ReinterpretTypeInfo &To : Reinterprets)
- OS << "BUILTIN(__builtin_sve_reinterpret_" << From.Suffix << "_"
- << To.Suffix << +", \"" << From.BuiltinType << To.BuiltinType
- << "\", \"n\")\n";
+ // Add reinterpret functions.
+ for (auto [N, Suffix] :
+ std::initializer_list<std::pair<unsigned, const char *>>{
+ {1, ""}, {2, "_x2"}, {3, "_x3"}, {4, "_x4"}}) {
+ for (const ReinterpretTypeInfo &To : Reinterprets) {
+ SVEType ToV(To.BaseType, N);
+ for (const ReinterpretTypeInfo &From : Reinterprets) {
+ SVEType FromV(From.BaseType, N);
+ OS << "TARGET_BUILTIN(__builtin_sve_reinterpret_" << To.Suffix << "_"
+ << From.Suffix << Suffix << +", \"" << ToV.builtin_str()
+ << FromV.builtin_str() << "\", \"n\", \"sve\")\n";
+ }
+ }
+ }
OS << "#endif\n\n";
- }
+}
void SVEEmitter::createCodeGenMap(raw_ostream &OS) {
std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
@@ -1339,7 +1483,7 @@ void SVEEmitter::createCodeGenMap(raw_ostream &OS) {
uint64_t Flags = Def->getFlags();
auto FlagString = std::to_string(Flags);
- std::string LLVMName = Def->getLLVMName();
+ std::string LLVMName = Def->getMangledLLVMName();
std::string Builtin = Def->getMangledName();
if (!LLVMName.empty())
OS << "SVEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString
@@ -1413,6 +1557,251 @@ void SVEEmitter::createTypeFlags(raw_ostream &OS) {
OS << "#endif\n\n";
}
+void SVEEmitter::createSMEHeader(raw_ostream &OS) {
+ OS << "/*===---- arm_sme.h - ARM SME intrinsics "
+ "------===\n"
+ " *\n"
+ " *\n"
+ " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
+ "Exceptions.\n"
+ " * See https://llvm.org/LICENSE.txt for license information.\n"
+ " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
+ " *\n"
+ " *===-----------------------------------------------------------------"
+ "------===\n"
+ " */\n\n";
+
+ OS << "#ifndef __ARM_SME_H\n";
+ OS << "#define __ARM_SME_H\n\n";
+
+ OS << "#if !defined(__LITTLE_ENDIAN__)\n";
+ OS << "#error \"Big endian is currently not supported for arm_sme.h\"\n";
+ OS << "#endif\n";
+
+ OS << "#include <arm_sve.h>\n\n";
+
+ OS << "/* Function attributes */\n";
+ OS << "#define __ai static __inline__ __attribute__((__always_inline__, "
+ "__nodebug__))\n\n";
+ OS << "#define __aio static __inline__ __attribute__((__always_inline__, "
+ "__nodebug__, __overloadable__))\n\n";
+
+ OS << "#ifdef __cplusplus\n";
+ OS << "extern \"C\" {\n";
+ OS << "#endif\n\n";
+
+ OS << "void __arm_za_disable(void) __arm_streaming_compatible;\n\n";
+
+ OS << "__ai bool __arm_has_sme(void) __arm_streaming_compatible {\n";
+ OS << " uint64_t x0, x1;\n";
+ OS << " __builtin_arm_get_sme_state(&x0, &x1);\n";
+ OS << " return x0 & (1ULL << 63);\n";
+ OS << "}\n\n";
+
+ OS << "__ai bool __arm_in_streaming_mode(void) __arm_streaming_compatible "
+ "{\n";
+ OS << " uint64_t x0, x1;\n";
+ OS << " __builtin_arm_get_sme_state(&x0, &x1);\n";
+ OS << " return x0 & 1;\n";
+ OS << "}\n\n";
+
+ OS << "__ai __attribute__((target(\"sme\"))) void svundef_za(void) "
+ "__arm_streaming_compatible __arm_out(\"za\") "
+ "{ }\n\n";
+
+ createCoreHeaderIntrinsics(OS, *this, ACLEKind::SME);
+
+ OS << "#ifdef __cplusplus\n";
+ OS << "} // extern \"C\"\n";
+ OS << "#endif\n\n";
+ OS << "#undef __ai\n\n";
+ OS << "#endif /* __ARM_SME_H */\n";
+}
+
+void SVEEmitter::createSMEBuiltins(raw_ostream &OS) {
+ std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
+ SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
+ for (auto *R : RV) {
+ createIntrinsic(R, Defs);
+ }
+
+ // The mappings must be sorted based on BuiltinID.
+ llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
+ const std::unique_ptr<Intrinsic> &B) {
+ return A->getMangledName() < B->getMangledName();
+ });
+
+ OS << "#ifdef GET_SME_BUILTINS\n";
+ for (auto &Def : Defs) {
+ // Only create BUILTINs for non-overloaded intrinsics, as overloaded
+ // declarations only live in the header file.
+ if (Def->getClassKind() != ClassG)
+ OS << "TARGET_BUILTIN(__builtin_sme_" << Def->getMangledName() << ", \""
+ << Def->getBuiltinTypeStr() << "\", \"n\", \"" << Def->getGuard()
+ << "\")\n";
+ }
+
+ OS << "#endif\n\n";
+}
+
+void SVEEmitter::createSMECodeGenMap(raw_ostream &OS) {
+ std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
+ SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
+ for (auto *R : RV) {
+ createIntrinsic(R, Defs);
+ }
+
+ // The mappings must be sorted based on BuiltinID.
+ llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
+ const std::unique_ptr<Intrinsic> &B) {
+ return A->getMangledName() < B->getMangledName();
+ });
+
+ OS << "#ifdef GET_SME_LLVM_INTRINSIC_MAP\n";
+ for (auto &Def : Defs) {
+ // Builtins only exist for non-overloaded intrinsics, overloaded
+ // declarations only live in the header file.
+ if (Def->getClassKind() == ClassG)
+ continue;
+
+ uint64_t Flags = Def->getFlags();
+ auto FlagString = std::to_string(Flags);
+
+ std::string LLVMName = Def->getLLVMName();
+ std::string Builtin = Def->getMangledName();
+ if (!LLVMName.empty())
+ OS << "SMEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString
+ << "),\n";
+ else
+ OS << "SMEMAP2(" << Builtin << ", " << FlagString << "),\n";
+ }
+ OS << "#endif\n\n";
+}
+
+void SVEEmitter::createSMERangeChecks(raw_ostream &OS) {
+ std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
+ SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
+ for (auto *R : RV) {
+ createIntrinsic(R, Defs);
+ }
+
+ // The mappings must be sorted based on BuiltinID.
+ llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
+ const std::unique_ptr<Intrinsic> &B) {
+ return A->getMangledName() < B->getMangledName();
+ });
+
+
+ OS << "#ifdef GET_SME_IMMEDIATE_CHECK\n";
+
+ // Ensure these are only emitted once.
+ std::set<std::string> Emitted;
+
+ for (auto &Def : Defs) {
+ if (Emitted.find(Def->getMangledName()) != Emitted.end() ||
+ Def->getImmChecks().empty())
+ continue;
+
+ OS << "case SME::BI__builtin_sme_" << Def->getMangledName() << ":\n";
+ for (auto &Check : Def->getImmChecks())
+ OS << "ImmChecks.push_back(std::make_tuple(" << Check.getArg() << ", "
+ << Check.getKind() << ", " << Check.getElementSizeInBits() << "));\n";
+ OS << " break;\n";
+
+ Emitted.insert(Def->getMangledName());
+ }
+
+ OS << "#endif\n\n";
+}
+
+void SVEEmitter::createBuiltinZAState(raw_ostream &OS) {
+ std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
+ SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
+ for (auto *R : RV)
+ createIntrinsic(R, Defs);
+
+ std::map<std::string, std::set<std::string>> IntrinsicsPerState;
+ for (auto &Def : Defs) {
+ std::string Key;
+ auto AddToKey = [&Key](const std::string &S) -> void {
+ Key = Key.empty() ? S : (Key + " | " + S);
+ };
+
+ if (Def->isFlagSet(getEnumValueForFlag("IsInZA")))
+ AddToKey("ArmInZA");
+ else if (Def->isFlagSet(getEnumValueForFlag("IsOutZA")))
+ AddToKey("ArmOutZA");
+ else if (Def->isFlagSet(getEnumValueForFlag("IsInOutZA")))
+ AddToKey("ArmInOutZA");
+
+ if (Def->isFlagSet(getEnumValueForFlag("IsInZT0")))
+ AddToKey("ArmInZT0");
+ else if (Def->isFlagSet(getEnumValueForFlag("IsOutZT0")))
+ AddToKey("ArmOutZT0");
+ else if (Def->isFlagSet(getEnumValueForFlag("IsInOutZT0")))
+ AddToKey("ArmInOutZT0");
+
+ if (!Key.empty())
+ IntrinsicsPerState[Key].insert(Def->getMangledName());
+ }
+
+ OS << "#ifdef GET_SME_BUILTIN_GET_STATE\n";
+ for (auto &KV : IntrinsicsPerState) {
+ for (StringRef Name : KV.second)
+ OS << "case SME::BI__builtin_sme_" << Name << ":\n";
+ OS << " return " << KV.first << ";\n";
+ }
+ OS << "#endif\n\n";
+}
+
+void SVEEmitter::createStreamingAttrs(raw_ostream &OS, ACLEKind Kind) {
+ std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
+ SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
+ for (auto *R : RV)
+ createIntrinsic(R, Defs);
+
+ StringRef ExtensionKind;
+ switch (Kind) {
+ case ACLEKind::SME:
+ ExtensionKind = "SME";
+ break;
+ case ACLEKind::SVE:
+ ExtensionKind = "SVE";
+ break;
+ }
+
+ OS << "#ifdef GET_" << ExtensionKind << "_STREAMING_ATTRS\n";
+
+ llvm::StringMap<std::set<std::string>> StreamingMap;
+
+ uint64_t IsStreamingFlag = getEnumValueForFlag("IsStreaming");
+ uint64_t IsStreamingOrSVE2p1Flag = getEnumValueForFlag("IsStreamingOrSVE2p1");
+ uint64_t IsStreamingCompatibleFlag =
+ getEnumValueForFlag("IsStreamingCompatible");
+ for (auto &Def : Defs) {
+ if (Def->isFlagSet(IsStreamingFlag))
+ StreamingMap["ArmStreaming"].insert(Def->getMangledName());
+ else if (Def->isFlagSet(IsStreamingOrSVE2p1Flag))
+ StreamingMap["ArmStreamingOrSVE2p1"].insert(Def->getMangledName());
+ else if (Def->isFlagSet(IsStreamingCompatibleFlag))
+ StreamingMap["ArmStreamingCompatible"].insert(Def->getMangledName());
+ else
+ StreamingMap["ArmNonStreaming"].insert(Def->getMangledName());
+ }
+
+ for (auto BuiltinType : StreamingMap.keys()) {
+ for (auto Name : StreamingMap[BuiltinType]) {
+ OS << "case " << ExtensionKind << "::BI__builtin_"
+ << ExtensionKind.lower() << "_";
+ OS << Name << ":\n";
+ }
+ OS << " BuiltinType = " << BuiltinType << ";\n";
+ OS << " break;\n";
+ }
+
+ OS << "#endif\n\n";
+}
+
namespace clang {
void EmitSveHeader(RecordKeeper &Records, raw_ostream &OS) {
SVEEmitter(Records).createHeader(OS);
@@ -1434,4 +1823,31 @@ void EmitSveTypeFlags(RecordKeeper &Records, raw_ostream &OS) {
SVEEmitter(Records).createTypeFlags(OS);
}
+void EmitSveStreamingAttrs(RecordKeeper &Records, raw_ostream &OS) {
+ SVEEmitter(Records).createStreamingAttrs(OS, ACLEKind::SVE);
+}
+
+void EmitSmeHeader(RecordKeeper &Records, raw_ostream &OS) {
+ SVEEmitter(Records).createSMEHeader(OS);
+}
+
+void EmitSmeBuiltins(RecordKeeper &Records, raw_ostream &OS) {
+ SVEEmitter(Records).createSMEBuiltins(OS);
+}
+
+void EmitSmeBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {
+ SVEEmitter(Records).createSMECodeGenMap(OS);
+}
+
+void EmitSmeRangeChecks(RecordKeeper &Records, raw_ostream &OS) {
+ SVEEmitter(Records).createSMERangeChecks(OS);
+}
+
+void EmitSmeStreamingAttrs(RecordKeeper &Records, raw_ostream &OS) {
+ SVEEmitter(Records).createStreamingAttrs(OS, ACLEKind::SME);
+}
+
+void EmitSmeBuiltinZAState(RecordKeeper &Records, raw_ostream &OS) {
+ SVEEmitter(Records).createBuiltinZAState(OS);
+}
} // End namespace clang
diff --git a/contrib/llvm-project/clang/utils/TableGen/TableGen.cpp b/contrib/llvm-project/clang/utils/TableGen/TableGen.cpp
index 7fb5d0acc6f3..158d10e2b3d6 100644
--- a/contrib/llvm-project/clang/utils/TableGen/TableGen.cpp
+++ b/contrib/llvm-project/clang/utils/TableGen/TableGen.cpp
@@ -13,6 +13,7 @@
#include "TableGenBackends.h" // Declares all backends.
#include "ASTTableGen.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
#include "llvm/TableGen/Error.h"
@@ -30,9 +31,13 @@ enum ActionType {
GenClangAttrSubjectMatchRulesParserStringSwitches,
GenClangAttrImpl,
GenClangAttrList,
+ GenClangAttrCanPrintLeftList,
+ GenClangAttrMustPrintLeftList,
+ GenClangAttrDocTable,
GenClangAttrSubjectMatchRuleList,
GenClangAttrPCHRead,
GenClangAttrPCHWrite,
+ GenClangRegularKeywordAttributeInfo,
GenClangAttrHasAttributeImpl,
GenClangAttrSpellingListIndex,
GenClangAttrASTVisitor,
@@ -63,10 +68,12 @@ enum ActionType {
GenClangCommentCommandInfo,
GenClangCommentCommandList,
GenClangOpenCLBuiltins,
+ GenClangOpenCLBuiltinHeader,
GenClangOpenCLBuiltinTests,
GenArmNeon,
GenArmFP16,
GenArmBF16,
+ GenArmVectorType,
GenArmNeonSema,
GenArmNeonTest,
GenArmMveHeader,
@@ -79,6 +86,13 @@ enum ActionType {
GenArmSveBuiltinCG,
GenArmSveTypeFlags,
GenArmSveRangeChecks,
+ GenArmSveStreamingAttrs,
+ GenArmSmeHeader,
+ GenArmSmeBuiltins,
+ GenArmSmeBuiltinCG,
+ GenArmSmeRangeChecks,
+ GenArmSmeStreamingAttrs,
+ GenArmSmeBuiltinZAState,
GenArmCdeHeader,
GenArmCdeBuiltinDef,
GenArmCdeBuiltinSema,
@@ -87,6 +101,10 @@ enum ActionType {
GenRISCVVectorHeader,
GenRISCVVectorBuiltins,
GenRISCVVectorBuiltinCG,
+ GenRISCVVectorBuiltinSema,
+ GenRISCVSiFiveVectorBuiltins,
+ GenRISCVSiFiveVectorBuiltinCG,
+ GenRISCVSiFiveVectorBuiltinSema,
GenAttrDocs,
GenDiagDocs,
GenOptDocs,
@@ -115,6 +133,16 @@ cl::opt<ActionType> Action(
"Generate clang attribute implementations"),
clEnumValN(GenClangAttrList, "gen-clang-attr-list",
"Generate a clang attribute list"),
+ clEnumValN(GenClangAttrCanPrintLeftList,
+ "gen-clang-attr-can-print-left-list",
+ "Generate list of attributes that can be printed on left "
+ "side of a decl"),
+ clEnumValN(GenClangAttrMustPrintLeftList,
+ "gen-clang-attr-must-print-left-list",
+ "Generate list of attributes that must be printed on left "
+ "side of a decl"),
+ clEnumValN(GenClangAttrDocTable, "gen-clang-attr-doc-table",
+ "Generate a table of attribute documentation"),
clEnumValN(GenClangAttrSubjectMatchRuleList,
"gen-clang-attr-subject-match-rule-list",
"Generate a clang attribute subject match rule list"),
@@ -122,6 +150,10 @@ cl::opt<ActionType> Action(
"Generate clang PCH attribute reader"),
clEnumValN(GenClangAttrPCHWrite, "gen-clang-attr-pch-write",
"Generate clang PCH attribute writer"),
+ clEnumValN(GenClangRegularKeywordAttributeInfo,
+ "gen-clang-regular-keyword-attr-info",
+ "Generate a list of regular keyword attributes with info "
+ "about their arguments"),
clEnumValN(GenClangAttrHasAttributeImpl,
"gen-clang-attr-has-attribute-impl",
"Generate a clang attribute spelling list"),
@@ -195,11 +227,16 @@ cl::opt<ActionType> Action(
"documentation comments"),
clEnumValN(GenClangOpenCLBuiltins, "gen-clang-opencl-builtins",
"Generate OpenCL builtin declaration handlers"),
+ clEnumValN(GenClangOpenCLBuiltinHeader,
+ "gen-clang-opencl-builtin-header",
+ "Generate OpenCL builtin header"),
clEnumValN(GenClangOpenCLBuiltinTests, "gen-clang-opencl-builtin-tests",
"Generate OpenCL builtin declaration tests"),
clEnumValN(GenArmNeon, "gen-arm-neon", "Generate arm_neon.h for clang"),
clEnumValN(GenArmFP16, "gen-arm-fp16", "Generate arm_fp16.h for clang"),
clEnumValN(GenArmBF16, "gen-arm-bf16", "Generate arm_bf16.h for clang"),
+ clEnumValN(GenArmVectorType, "gen-arm-vector-type",
+ "Generate arm_vector_types.h for clang"),
clEnumValN(GenArmNeonSema, "gen-arm-neon-sema",
"Generate ARM NEON sema support for clang"),
clEnumValN(GenArmNeonTest, "gen-arm-neon-test",
@@ -214,6 +251,20 @@ cl::opt<ActionType> Action(
"Generate arm_sve_typeflags.inc for clang"),
clEnumValN(GenArmSveRangeChecks, "gen-arm-sve-sema-rangechecks",
"Generate arm_sve_sema_rangechecks.inc for clang"),
+ clEnumValN(GenArmSveStreamingAttrs, "gen-arm-sve-streaming-attrs",
+ "Generate arm_sve_streaming_attrs.inc for clang"),
+ clEnumValN(GenArmSmeHeader, "gen-arm-sme-header",
+ "Generate arm_sme.h for clang"),
+ clEnumValN(GenArmSmeBuiltins, "gen-arm-sme-builtins",
+ "Generate arm_sme_builtins.inc for clang"),
+ clEnumValN(GenArmSmeBuiltinCG, "gen-arm-sme-builtin-codegen",
+ "Generate arm_sme_builtin_cg_map.inc for clang"),
+ clEnumValN(GenArmSmeRangeChecks, "gen-arm-sme-sema-rangechecks",
+ "Generate arm_sme_sema_rangechecks.inc for clang"),
+ clEnumValN(GenArmSmeStreamingAttrs, "gen-arm-sme-streaming-attrs",
+ "Generate arm_sme_streaming_attrs.inc for clang"),
+ clEnumValN(GenArmSmeBuiltinZAState, "gen-arm-sme-builtin-za-state",
+ "Generate arm_sme_builtins_za_state.inc for clang"),
clEnumValN(GenArmMveHeader, "gen-arm-mve-header",
"Generate arm_mve.h for clang"),
clEnumValN(GenArmMveBuiltinDef, "gen-arm-mve-builtin-def",
@@ -240,6 +291,17 @@ cl::opt<ActionType> Action(
"Generate riscv_vector_builtins.inc for clang"),
clEnumValN(GenRISCVVectorBuiltinCG, "gen-riscv-vector-builtin-codegen",
"Generate riscv_vector_builtin_cg.inc for clang"),
+ clEnumValN(GenRISCVVectorBuiltinSema, "gen-riscv-vector-builtin-sema",
+ "Generate riscv_vector_builtin_sema.inc for clang"),
+ clEnumValN(GenRISCVSiFiveVectorBuiltins,
+ "gen-riscv-sifive-vector-builtins",
+ "Generate riscv_sifive_vector_builtins.inc for clang"),
+ clEnumValN(GenRISCVSiFiveVectorBuiltinCG,
+ "gen-riscv-sifive-vector-builtin-codegen",
+ "Generate riscv_sifive_vector_builtin_cg.inc for clang"),
+ clEnumValN(GenRISCVSiFiveVectorBuiltinSema,
+ "gen-riscv-sifive-vector-builtin-sema",
+ "Generate riscv_sifive_vector_builtin_sema.inc for clang"),
clEnumValN(GenAttrDocs, "gen-attr-docs",
"Generate attribute documentation"),
clEnumValN(GenDiagDocs, "gen-diag-docs",
@@ -280,6 +342,15 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenClangAttrList:
EmitClangAttrList(Records, OS);
break;
+ case GenClangAttrCanPrintLeftList:
+ EmitClangAttrPrintList("CanPrintOnLeft", Records, OS);
+ break;
+ case GenClangAttrMustPrintLeftList:
+ EmitClangAttrPrintList("PrintOnLeft", Records, OS);
+ break;
+ case GenClangAttrDocTable:
+ EmitClangAttrDocTable(Records, OS);
+ break;
case GenClangAttrSubjectMatchRuleList:
EmitClangAttrSubjectMatchRuleList(Records, OS);
break;
@@ -289,6 +360,9 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenClangAttrPCHWrite:
EmitClangAttrPCHWrite(Records, OS);
break;
+ case GenClangRegularKeywordAttributeInfo:
+ EmitClangRegularKeywordAttributeInfo(Records, OS);
+ break;
case GenClangAttrHasAttributeImpl:
EmitClangAttrHasAttrImpl(Records, OS);
break;
@@ -329,7 +403,8 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
EmitClangASTNodes(Records, OS, CommentNodeClassName, "");
break;
case GenClangDeclNodes:
- EmitClangASTNodes(Records, OS, DeclNodeClassName, "Decl");
+ EmitClangASTNodes(Records, OS, DeclNodeClassName, "Decl",
+ DeclContextNodeClassName);
EmitClangDeclContext(Records, OS);
break;
case GenClangStmtNodes:
@@ -374,6 +449,9 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenClangOpenCLBuiltins:
EmitClangOpenCLBuiltins(Records, OS);
break;
+ case GenClangOpenCLBuiltinHeader:
+ EmitClangOpenCLBuiltinHeader(Records, OS);
+ break;
case GenClangOpenCLBuiltinTests:
EmitClangOpenCLBuiltinTests(Records, OS);
break;
@@ -389,6 +467,9 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenArmFP16:
EmitFP16(Records, OS);
break;
+ case GenArmVectorType:
+ EmitVectorTypes(Records, OS);
+ break;
case GenArmBF16:
EmitBF16(Records, OS);
break;
@@ -428,6 +509,27 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenArmSveRangeChecks:
EmitSveRangeChecks(Records, OS);
break;
+ case GenArmSveStreamingAttrs:
+ EmitSveStreamingAttrs(Records, OS);
+ break;
+ case GenArmSmeHeader:
+ EmitSmeHeader(Records, OS);
+ break;
+ case GenArmSmeBuiltins:
+ EmitSmeBuiltins(Records, OS);
+ break;
+ case GenArmSmeBuiltinCG:
+ EmitSmeBuiltinCG(Records, OS);
+ break;
+ case GenArmSmeRangeChecks:
+ EmitSmeRangeChecks(Records, OS);
+ break;
+ case GenArmSmeStreamingAttrs:
+ EmitSmeStreamingAttrs(Records, OS);
+ break;
+ case GenArmSmeBuiltinZAState:
+ EmitSmeBuiltinZAState(Records, OS);
+ break;
case GenArmCdeHeader:
EmitCdeHeader(Records, OS);
break;
@@ -452,6 +554,18 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenRISCVVectorBuiltinCG:
EmitRVVBuiltinCG(Records, OS);
break;
+ case GenRISCVVectorBuiltinSema:
+ EmitRVVBuiltinSema(Records, OS);
+ break;
+ case GenRISCVSiFiveVectorBuiltins:
+ EmitRVVBuiltins(Records, OS);
+ break;
+ case GenRISCVSiFiveVectorBuiltinCG:
+ EmitRVVBuiltinCG(Records, OS);
+ break;
+ case GenRISCVSiFiveVectorBuiltinSema:
+ EmitRVVBuiltinSema(Records, OS);
+ break;
case GenAttrDocs:
EmitClangAttrDocs(Records, OS);
break;
diff --git a/contrib/llvm-project/clang/utils/TableGen/TableGenBackends.h b/contrib/llvm-project/clang/utils/TableGen/TableGenBackends.h
index bf40c7b1d18f..58a4af3c23a6 100644
--- a/contrib/llvm-project/clang/utils/TableGen/TableGenBackends.h
+++ b/contrib/llvm-project/clang/utils/TableGen/TableGenBackends.h
@@ -25,8 +25,16 @@ class RecordKeeper;
namespace clang {
void EmitClangDeclContext(llvm::RecordKeeper &RK, llvm::raw_ostream &OS);
+/**
+ @param PriorizeIfSubclassOf These classes should be prioritized in the output.
+ This is useful to force enum generation/jump tables/lookup tables to be more
+ compact in both size and surrounding code in hot functions. An example use is
+ in Decl for classes that inherit from DeclContext, for functions like
+ castFromDeclContext.
+ */
void EmitClangASTNodes(llvm::RecordKeeper &RK, llvm::raw_ostream &OS,
- const std::string &N, const std::string &S);
+ const std::string &N, const std::string &S,
+ std::string_view PriorizeIfSubclassOf = "");
void EmitClangBasicReader(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitClangBasicWriter(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitClangTypeNodes(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
@@ -39,10 +47,14 @@ void EmitClangAttrSubjectMatchRulesParserStringSwitches(
void EmitClangAttrClass(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitClangAttrImpl(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitClangAttrList(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
+void EmitClangAttrPrintList(const std::string &FieldName,
+ llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitClangAttrSubjectMatchRuleList(llvm::RecordKeeper &Records,
llvm::raw_ostream &OS);
void EmitClangAttrPCHRead(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitClangAttrPCHWrite(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
+void EmitClangRegularKeywordAttributeInfo(llvm::RecordKeeper &Records,
+ llvm::raw_ostream &OS);
void EmitClangAttrHasAttrImpl(llvm::RecordKeeper &Records,
llvm::raw_ostream &OS);
void EmitClangAttrSpellingListIndex(llvm::RecordKeeper &Records,
@@ -61,6 +73,7 @@ void EmitClangAttrTextNodeDump(llvm::RecordKeeper &Records,
llvm::raw_ostream &OS);
void EmitClangAttrNodeTraverse(llvm::RecordKeeper &Records,
llvm::raw_ostream &OS);
+void EmitClangAttrDocTable(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitClangDiagsDefs(llvm::RecordKeeper &Records, llvm::raw_ostream &OS,
const std::string &Component);
@@ -92,6 +105,7 @@ void EmitNeon(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitFP16(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitBF16(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitNeonSema(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
+void EmitVectorTypes(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitNeonTest(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitSveHeader(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
@@ -99,6 +113,14 @@ void EmitSveBuiltins(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitSveBuiltinCG(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitSveTypeFlags(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitSveRangeChecks(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
+void EmitSveStreamingAttrs(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
+
+void EmitSmeHeader(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
+void EmitSmeBuiltins(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
+void EmitSmeBuiltinCG(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
+void EmitSmeRangeChecks(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
+void EmitSmeStreamingAttrs(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
+void EmitSmeBuiltinZAState(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitMveHeader(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitMveBuiltinDef(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
@@ -109,6 +131,7 @@ void EmitMveBuiltinAliases(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitRVVHeader(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitRVVBuiltins(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitRVVBuiltinCG(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
+void EmitRVVBuiltinSema(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitCdeHeader(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitCdeBuiltinDef(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
@@ -122,6 +145,8 @@ void EmitClangOptDocs(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitClangOpenCLBuiltins(llvm::RecordKeeper &Records,
llvm::raw_ostream &OS);
+void EmitClangOpenCLBuiltinHeader(llvm::RecordKeeper &Records,
+ llvm::raw_ostream &OS);
void EmitClangOpenCLBuiltinTests(llvm::RecordKeeper &Records,
llvm::raw_ostream &OS);