Files
gps/tools/local/circt/include/llvm/TableGen/DirectiveEmitter.h
T
2026-07-12 11:01:51 +03:00

378 lines
11 KiB
C++

//===- DirectiveEmitter.h - Directive Language Emitter ----------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// DirectiveEmitter uses the descriptions of directives and clauses to construct
// common code declarations to be used in Frontends.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TABLEGEN_DIRECTIVEEMITTER_H
#define LLVM_TABLEGEN_DIRECTIVEEMITTER_H
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Frontend/Directive/Spelling.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/TableGen/Record.h"
#include <string>
#include <vector>
namespace llvm {
// Wrapper class that contains DirectiveLanguage's information defined in
// DirectiveBase.td and provides helper methods for accessing it.
class DirectiveLanguage {
public:
explicit DirectiveLanguage(const RecordKeeper &Records) : Records(Records) {
const auto &DirectiveLanguages = getDirectiveLanguages();
Def = DirectiveLanguages[0];
}
StringRef getName() const { return Def->getValueAsString("name"); }
StringRef getCppNamespace() const {
return Def->getValueAsString("cppNamespace");
}
StringRef getDirectivePrefix() const {
return Def->getValueAsString("directivePrefix");
}
StringRef getClausePrefix() const {
return Def->getValueAsString("clausePrefix");
}
StringRef getClauseEnumSetClass() const {
return Def->getValueAsString("clauseEnumSetClass");
}
StringRef getFlangClauseBaseClass() const {
return Def->getValueAsString("flangClauseBaseClass");
}
bool hasMakeEnumAvailableInNamespace() const {
return Def->getValueAsBit("makeEnumAvailableInNamespace");
}
bool hasEnableBitmaskEnumInNamespace() const {
return Def->getValueAsBit("enableBitmaskEnumInNamespace");
}
ArrayRef<const Record *> getAssociations() const {
return Records.getAllDerivedDefinitions("Association");
}
ArrayRef<const Record *> getCategories() const {
return Records.getAllDerivedDefinitions("Category");
}
ArrayRef<const Record *> getSourceLanguages() const {
return Records.getAllDerivedDefinitions("SourceLanguage");
}
ArrayRef<const Record *> getDirectives() const {
return Records.getAllDerivedDefinitions("Directive");
}
ArrayRef<const Record *> getClauses() const {
return Records.getAllDerivedDefinitions("Clause");
}
bool HasValidityErrors() const;
private:
const Record *Def;
const RecordKeeper &Records;
ArrayRef<const Record *> getDirectiveLanguages() const {
return Records.getAllDerivedDefinitions("DirectiveLanguage");
}
};
class Versioned {
public:
int getMinVersion(const Record *R) const {
int64_t Min = R->getValueAsInt("minVersion");
assert(llvm::isInt<IntWidth>(Min) && "Value out of range of 'int'");
return Min;
}
int getMaxVersion(const Record *R) const {
int64_t Max = R->getValueAsInt("maxVersion");
assert(llvm::isInt<IntWidth>(Max) && "Value out of range of 'int'");
return Max;
}
private:
constexpr static int IntWidth = 8 * sizeof(int);
};
class Spelling : public Versioned {
public:
using Value = directive::Spelling;
Spelling(const Record *Def) : Def(Def) {}
StringRef getText() const { return Def->getValueAsString("spelling"); }
llvm::directive::VersionRange getVersions() const {
return llvm::directive::VersionRange{getMinVersion(Def),
getMaxVersion(Def)};
}
Value get() const { return Value{getText(), getVersions()}; }
private:
const Record *Def;
};
// Note: In all the classes below, allow implicit construction from Record *,
// to allow writing code like:
// for (const Directive D : getDirectives()) {
//
// instead of:
//
// for (const Record *R : getDirectives()) {
// Directive D(R);
// Base record class used for Directive and Clause class defined in
// DirectiveBase.td.
class BaseRecord {
public:
BaseRecord(const Record *Def) : Def(Def) {}
std::vector<Spelling::Value> getSpellings() const {
std::vector<Spelling::Value> List;
llvm::transform(Def->getValueAsListOfDefs("spellings"),
std::back_inserter(List),
[](const Record *R) { return Spelling(R).get(); });
return List;
}
StringRef getSpellingForIdentifier() const {
// From all spellings, pick the first one with the minimum version
// (i.e. pick the first from all the oldest ones). This guarantees
// that given several equivalent (in terms of versions) names, the
// first one is used, e.g. given
// Clause<[Spelling<"foo">, Spelling<"bar">]> ...
// "foo" will be the selected spelling.
//
// This is a suitable spelling for generating an identifier name,
// since it will remain unchanged when any potential new spellings
// are added.
Spelling::Value Oldest{"not found", {/*Min=*/INT_MAX, 0}};
for (auto V : getSpellings())
if (V.Versions.Min < Oldest.Versions.Min)
Oldest = V;
return Oldest.Name;
}
// Returns the name of the directive formatted for output. Whitespace are
// replaced with underscores.
static std::string getSnakeName(StringRef Name) {
std::string N = Name.str();
llvm::replace(N, ' ', '_');
return N;
}
// Take a string Name with sub-words separated with characters from Sep,
// and return a string with each of the sub-words capitalized, and the
// separators removed, e.g.
// Name = "some_directive^name", Sep = "_^" -> "SomeDirectiveName".
static std::string getUpperCamelName(StringRef Name, StringRef Sep) {
std::string Camel = Name.str();
// Convert to uppercase
bool Cap = true;
llvm::transform(Camel, Camel.begin(), [&](unsigned char C) {
if (Sep.contains(C)) {
assert(!Cap && "No initial or repeated separators");
Cap = true;
} else if (Cap) {
C = llvm::toUpper(C);
Cap = false;
}
return C;
});
size_t Out = 0;
// Remove separators
for (size_t In = 0, End = Camel.size(); In != End; ++In) {
unsigned char C = Camel[In];
if (!Sep.contains(C))
Camel[Out++] = C;
}
Camel.resize(Out);
return Camel;
}
std::string getFormattedName() const {
if (auto maybeName = Def->getValueAsOptionalString("name"))
return getSnakeName(*maybeName);
return getSnakeName(getSpellingForIdentifier());
}
bool isDefault() const { return Def->getValueAsBit("isDefault"); }
// Returns the record name.
StringRef getRecordName() const { return Def->getName(); }
const Record *getRecord() const { return Def; }
protected:
const Record *Def;
};
// Wrapper class that contains a Directive's information defined in
// DirectiveBase.td and provides helper methods for accessing it.
class Directive : public BaseRecord {
public:
Directive(const Record *Def) : BaseRecord(Def) {}
std::vector<const Record *> getAllowedClauses() const {
return Def->getValueAsListOfDefs("allowedClauses");
}
std::vector<const Record *> getAllowedOnceClauses() const {
return Def->getValueAsListOfDefs("allowedOnceClauses");
}
std::vector<const Record *> getAllowedExclusiveClauses() const {
return Def->getValueAsListOfDefs("allowedExclusiveClauses");
}
std::vector<const Record *> getRequiredClauses() const {
return Def->getValueAsListOfDefs("requiredClauses");
}
std::vector<const Record *> getLeafConstructs() const {
return Def->getValueAsListOfDefs("leafConstructs");
}
const Record *getAssociation() const {
return Def->getValueAsDef("association");
}
const Record *getCategory() const { return Def->getValueAsDef("category"); }
std::vector<const Record *> getSourceLanguages() const {
return Def->getValueAsListOfDefs("languages");
}
// Clang uses a different format for names of its directives enum.
std::string getClangAccSpelling() const {
StringRef Name = getSpellingForIdentifier();
// Clang calls the 'unknown' value 'invalid'.
if (Name == "unknown")
return "Invalid";
return BaseRecord::getUpperCamelName(Name, " _");
}
};
// Wrapper class that contains Clause's information defined in DirectiveBase.td
// and provides helper methods for accessing it.
class Clause : public BaseRecord {
public:
Clause(const Record *Def) : BaseRecord(Def) {}
// Optional field.
StringRef getClangClass() const {
return Def->getValueAsString("clangClass");
}
// Optional field.
StringRef getFlangClass() const {
return Def->getValueAsString("flangClass");
}
// Get the formatted name for Flang parser class. The generic formatted class
// name is constructed from the name were the first letter of each word is
// captitalized and the underscores are removed.
// ex: async -> Async
// num_threads -> NumThreads
std::string getFormattedParserClassName() const {
StringRef Name = getSpellingForIdentifier();
return BaseRecord::getUpperCamelName(Name, "_");
}
// Clang uses a different format for names of its clause enum, which can be
// overwritten with the `clangSpelling` value. So get the proper spelling
// here.
std::string getClangAccSpelling() const {
if (StringRef ClangSpelling = Def->getValueAsString("clangAccSpelling");
!ClangSpelling.empty())
return ClangSpelling.str();
StringRef Name = getSpellingForIdentifier();
return BaseRecord::getUpperCamelName(Name, "_");
}
// Optional field.
StringRef getEnumName() const {
return Def->getValueAsString("enumClauseValue");
}
std::vector<const Record *> getClauseVals() const {
return Def->getValueAsListOfDefs("allowedClauseValues");
}
bool skipFlangUnparser() const {
return Def->getValueAsBit("skipFlangUnparser");
}
bool isValueOptional() const { return Def->getValueAsBit("isValueOptional"); }
bool isValueList() const { return Def->getValueAsBit("isValueList"); }
StringRef getDefaultValue() const {
return Def->getValueAsString("defaultValue");
}
bool isImplicit() const { return Def->getValueAsBit("isImplicit"); }
std::vector<StringRef> getAliases() const {
return Def->getValueAsListOfStrings("aliases");
}
StringRef getPrefix() const { return Def->getValueAsString("prefix"); }
bool isPrefixOptional() const {
return Def->getValueAsBit("isPrefixOptional");
}
};
// Wrapper class that contains VersionedClause's information defined in
// DirectiveBase.td and provides helper methods for accessing it.
class VersionedClause {
public:
VersionedClause(const Record *Def) : Def(Def) {}
// Return the specific clause record wrapped in the Clause class.
Clause getClause() const { return Clause(Def->getValueAsDef("clause")); }
int64_t getMinVersion() const { return Def->getValueAsInt("minVersion"); }
int64_t getMaxVersion() const { return Def->getValueAsInt("maxVersion"); }
private:
const Record *Def;
};
class EnumVal : public BaseRecord {
public:
EnumVal(const Record *Def) : BaseRecord(Def) {}
int getValue() const { return Def->getValueAsInt("value"); }
bool isUserVisible() const { return Def->getValueAsBit("isUserValue"); }
};
} // namespace llvm
#endif // LLVM_TABLEGEN_DIRECTIVEEMITTER_H