
All the sources of `llvm-min-tblgen` are also used for `llvm-tblgen`, with identical compilation flags. Reuse the object files of `llvm-min-tblgen` for `llvm-tblgen` by applying the usual source structure of an executable: One file per executable which named after the executable name containing the (in this case trivial) main function, which just calls the tblgen_main in TableGen.cpp. This should also clear up any confusion (including mine) of where each executable's main function is. While this slightly reduces build time, the main motivation is ccache. Using the hard_link option, building the object files for `llvm-tblgen` will result in a hard link to the same object file already used for `llvm-min-tblgen`. To signal the build system that the file is new, ccache will update the file's time stamp. Unfortunately, time stamps are shared between all hard-linked files s.t. this will indirectly also update the time stamps for the object files used for `llvm-tblgen`. At the next run, Ninja will recognize this time stamp discrepancy to the expected stamp recorded in `.ninja_log` and rebuild those object files for `llvm-min-tblgen`, which again will also update the stamp for the `llvm-tblgen`... . This is especially annoying for tablegen because it means Ninja will re-run all tablegenning in every build. I am using the hard_link option because it reduces the cost of having multiple build-trees of the LLVM sources and reduces the wear to the SSD they are stored on.
149 lines
5.0 KiB
C++
149 lines
5.0 KiB
C++
//===- Attributes.cpp - Generate attributes -------------------------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/TableGen/Error.h"
|
|
#include "llvm/TableGen/Record.h"
|
|
#include "llvm/TableGen/TableGenBackend.h"
|
|
using namespace llvm;
|
|
|
|
#define DEBUG_TYPE "attr-enum"
|
|
|
|
namespace {
|
|
|
|
class Attributes {
|
|
public:
|
|
Attributes(const RecordKeeper &R) : Records(R) {}
|
|
void run(raw_ostream &OS);
|
|
|
|
private:
|
|
void emitTargetIndependentNames(raw_ostream &OS);
|
|
void emitFnAttrCompatCheck(raw_ostream &OS, bool IsStringAttr);
|
|
void emitAttributeProperties(raw_ostream &OF);
|
|
|
|
const RecordKeeper &Records;
|
|
};
|
|
|
|
} // End anonymous namespace.
|
|
|
|
void Attributes::emitTargetIndependentNames(raw_ostream &OS) {
|
|
OS << "#ifdef GET_ATTR_NAMES\n";
|
|
OS << "#undef GET_ATTR_NAMES\n";
|
|
|
|
OS << "#ifndef ATTRIBUTE_ALL\n";
|
|
OS << "#define ATTRIBUTE_ALL(FIRST, SECOND)\n";
|
|
OS << "#endif\n\n";
|
|
|
|
auto Emit = [&](ArrayRef<StringRef> KindNames, StringRef MacroName) {
|
|
OS << "#ifndef " << MacroName << "\n";
|
|
OS << "#define " << MacroName
|
|
<< "(FIRST, SECOND) ATTRIBUTE_ALL(FIRST, SECOND)\n";
|
|
OS << "#endif\n\n";
|
|
for (StringRef KindName : KindNames) {
|
|
for (auto *A : Records.getAllDerivedDefinitions(KindName)) {
|
|
OS << MacroName << "(" << A->getName() << ","
|
|
<< A->getValueAsString("AttrString") << ")\n";
|
|
}
|
|
}
|
|
OS << "#undef " << MacroName << "\n\n";
|
|
};
|
|
|
|
// Emit attribute enums in the same order llvm::Attribute::operator< expects.
|
|
Emit({"EnumAttr", "TypeAttr", "IntAttr", "ConstantRangeAttr",
|
|
"ConstantRangeListAttr"},
|
|
"ATTRIBUTE_ENUM");
|
|
Emit({"StrBoolAttr"}, "ATTRIBUTE_STRBOOL");
|
|
Emit({"ComplexStrAttr"}, "ATTRIBUTE_COMPLEXSTR");
|
|
|
|
OS << "#undef ATTRIBUTE_ALL\n";
|
|
OS << "#endif\n\n";
|
|
|
|
OS << "#ifdef GET_ATTR_ENUM\n";
|
|
OS << "#undef GET_ATTR_ENUM\n";
|
|
unsigned Value = 1; // Leave zero for AttrKind::None.
|
|
for (StringRef KindName : {"EnumAttr", "TypeAttr", "IntAttr",
|
|
"ConstantRangeAttr", "ConstantRangeListAttr"}) {
|
|
OS << "First" << KindName << " = " << Value << ",\n";
|
|
for (auto *A : Records.getAllDerivedDefinitions(KindName)) {
|
|
OS << A->getName() << " = " << Value << ",\n";
|
|
Value++;
|
|
}
|
|
OS << "Last" << KindName << " = " << (Value - 1) << ",\n";
|
|
}
|
|
OS << "#endif\n\n";
|
|
}
|
|
|
|
void Attributes::emitFnAttrCompatCheck(raw_ostream &OS, bool IsStringAttr) {
|
|
OS << "#ifdef GET_ATTR_COMPAT_FUNC\n";
|
|
OS << "#undef GET_ATTR_COMPAT_FUNC\n";
|
|
|
|
OS << "static inline bool hasCompatibleFnAttrs(const Function &Caller,\n"
|
|
<< " const Function &Callee) {\n";
|
|
OS << " bool Ret = true;\n\n";
|
|
|
|
for (const Record *Rule : Records.getAllDerivedDefinitions("CompatRule")) {
|
|
StringRef FuncName = Rule->getValueAsString("CompatFunc");
|
|
OS << " Ret &= " << FuncName << "(Caller, Callee";
|
|
StringRef AttrName = Rule->getValueAsString("AttrName");
|
|
if (!AttrName.empty())
|
|
OS << ", \"" << AttrName << "\"";
|
|
OS << ");\n";
|
|
}
|
|
|
|
OS << "\n";
|
|
OS << " return Ret;\n";
|
|
OS << "}\n\n";
|
|
|
|
OS << "static inline void mergeFnAttrs(Function &Caller,\n"
|
|
<< " const Function &Callee) {\n";
|
|
|
|
for (const Record *Rule : Records.getAllDerivedDefinitions("MergeRule")) {
|
|
StringRef FuncName = Rule->getValueAsString("MergeFunc");
|
|
OS << " " << FuncName << "(Caller, Callee);\n";
|
|
}
|
|
|
|
OS << "}\n\n";
|
|
|
|
OS << "#endif\n";
|
|
}
|
|
|
|
void Attributes::emitAttributeProperties(raw_ostream &OS) {
|
|
OS << "#ifdef GET_ATTR_PROP_TABLE\n";
|
|
OS << "#undef GET_ATTR_PROP_TABLE\n";
|
|
OS << "static const uint8_t AttrPropTable[] = {\n";
|
|
for (StringRef KindName : {"EnumAttr", "TypeAttr", "IntAttr",
|
|
"ConstantRangeAttr", "ConstantRangeListAttr"}) {
|
|
bool AllowIntersectAnd = KindName == "EnumAttr";
|
|
bool AllowIntersectMin = KindName == "IntAttr";
|
|
for (auto *A : Records.getAllDerivedDefinitions(KindName)) {
|
|
OS << "0";
|
|
for (const Init *P : *A->getValueAsListInit("Properties")) {
|
|
if (!AllowIntersectAnd &&
|
|
cast<DefInit>(P)->getDef()->getName() == "IntersectAnd")
|
|
PrintFatalError("'IntersectAnd' only compatible with 'EnumAttr'");
|
|
if (!AllowIntersectMin &&
|
|
cast<DefInit>(P)->getDef()->getName() == "IntersectMin")
|
|
PrintFatalError("'IntersectMin' only compatible with 'IntAttr'");
|
|
|
|
OS << " | AttributeProperty::" << cast<DefInit>(P)->getDef()->getName();
|
|
}
|
|
OS << ",\n";
|
|
}
|
|
}
|
|
OS << "};\n";
|
|
OS << "#endif\n";
|
|
}
|
|
|
|
void Attributes::run(raw_ostream &OS) {
|
|
emitTargetIndependentNames(OS);
|
|
emitFnAttrCompatCheck(OS, false);
|
|
emitAttributeProperties(OS);
|
|
}
|
|
|
|
static TableGen::Emitter::OptClass<Attributes> X("gen-attrs",
|
|
"Generate attributes");
|