Reduces memory usage compiling backend sources, most notably for AMDGPU by ~98 MB per source on average. AMDGPUGenRegisterInfo.inc is tens of megabytes in size now, and is even larger downstream. At the same time, it is included in nearly all backend sources, typically just for a small portion of its content, resulting in compilation being unnecessarily memory-hungry, which in turn stresses buildbots and wastes their resources. Splitting .inc files also helps avoiding extra ccache misses where changes in .td files don't cause changes in all parts of what previously was a single .inc file. It is thought that rather than building on top of the current single-output-file design of TableGen, e.g., using `split-file`, it would be more preferable to recognise the need for multi-file outputs and give it a proper first-class support directly in TableGen.
120 lines
3.9 KiB
C++
120 lines
3.9 KiB
C++
//===- TableGenBackend.cpp - Utilities for TableGen Backends ----*- 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file provides useful services for TableGen backends...
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/TableGen/TableGenBackend.h"
|
|
#include "llvm/ADT/Twine.h"
|
|
#include "llvm/Support/CommandLine.h"
|
|
#include "llvm/Support/ManagedStatic.h"
|
|
#include "llvm/Support/Path.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
#include <cstddef>
|
|
|
|
using namespace llvm;
|
|
using namespace TableGen::Emitter;
|
|
|
|
const size_t MAX_LINE_LEN = 80U;
|
|
|
|
// CommandLine options of class type are not directly supported with some
|
|
// specific exceptions like std::string which are safe to copy. In our case,
|
|
// the `FnT` function_ref object is also safe to copy. So provide a
|
|
// specialization of `OptionValue` for `FnT` type that stores it as a copy.
|
|
// This is essentially similar to OptionValue<std::string> specialization for
|
|
// strings.
|
|
template <> struct cl::OptionValue<FnT> final : cl::OptionValueCopy<FnT> {
|
|
OptionValue() = default;
|
|
|
|
OptionValue(const FnT &V) { this->setValue(V); }
|
|
|
|
OptionValue<FnT> &operator=(const FnT &V) {
|
|
setValue(V);
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
namespace {
|
|
struct OptCreatorT {
|
|
static void *call() {
|
|
return new cl::opt<FnT>(cl::desc("Action to perform:"));
|
|
}
|
|
};
|
|
} // namespace
|
|
|
|
static ManagedStatic<cl::opt<FnT>, OptCreatorT> CallbackFunction;
|
|
|
|
Opt::Opt(StringRef Name, FnT CB, StringRef Desc, bool ByDefault) {
|
|
if (ByDefault)
|
|
CallbackFunction->setInitialValue(CB);
|
|
CallbackFunction->getParser().addLiteralOption(Name, CB, Desc);
|
|
}
|
|
|
|
/// Apply callback specified on the command line. Returns true if no callback
|
|
/// was applied.
|
|
bool llvm::TableGen::Emitter::ApplyCallback(const RecordKeeper &Records,
|
|
TableGenOutputFiles &OutFiles,
|
|
StringRef FilenamePrefix) {
|
|
FnT Fn = CallbackFunction->getValue();
|
|
if (Fn.SingleFileGenerator) {
|
|
std::string S;
|
|
raw_string_ostream OS(S);
|
|
Fn.SingleFileGenerator(Records, OS);
|
|
OutFiles = {S, {}};
|
|
return false;
|
|
}
|
|
if (Fn.MultiFileGenerator) {
|
|
OutFiles = Fn.MultiFileGenerator(FilenamePrefix, Records);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static void printLine(raw_ostream &OS, const Twine &Prefix, char Fill,
|
|
StringRef Suffix) {
|
|
size_t Pos = (size_t)OS.tell();
|
|
assert((Prefix.str().size() + Suffix.size() <= MAX_LINE_LEN) &&
|
|
"header line exceeds max limit");
|
|
OS << Prefix;
|
|
for (size_t i = (size_t)OS.tell() - Pos, e = MAX_LINE_LEN - Suffix.size();
|
|
i < e; ++i)
|
|
OS << Fill;
|
|
OS << Suffix << '\n';
|
|
}
|
|
|
|
void llvm::emitSourceFileHeader(StringRef Desc, raw_ostream &OS,
|
|
const RecordKeeper &Record) {
|
|
printLine(OS, "/*===- TableGen'erated file ", '-', "*- C++ -*-===*\\");
|
|
StringRef Prefix("|* ");
|
|
StringRef Suffix(" *|");
|
|
printLine(OS, Prefix, ' ', Suffix);
|
|
size_t PSLen = Prefix.size() + Suffix.size();
|
|
assert(PSLen < MAX_LINE_LEN);
|
|
size_t Pos = 0U;
|
|
do {
|
|
size_t Length = std::min(Desc.size() - Pos, MAX_LINE_LEN - PSLen);
|
|
printLine(OS, Prefix + Desc.substr(Pos, Length), ' ', Suffix);
|
|
Pos += Length;
|
|
} while (Pos < Desc.size());
|
|
printLine(OS, Prefix, ' ', Suffix);
|
|
printLine(OS, Prefix + "Automatically generated file, do not edit!", ' ',
|
|
Suffix);
|
|
|
|
// Print the filename of source file.
|
|
if (!Record.getInputFilename().empty())
|
|
printLine(
|
|
OS, Prefix + "From: " + sys::path::filename(Record.getInputFilename()),
|
|
' ', Suffix);
|
|
printLine(OS, Prefix, ' ', Suffix);
|
|
printLine(OS, "\\*===", '-', "===*/");
|
|
OS << '\n';
|
|
}
|