Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions llvm/include/llvm/TableGen/CodeGenHelpers.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//===----------------------------------------------------------------------===//
//
// 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 defines common utilities for generating C++ code.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_TABLEGEN_CODEGENHELPERS_H
#define LLVM_TABLEGEN_CODEGENHELPERS_H

#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/raw_ostream.h"
#include <string>

namespace llvm {
// Simple RAII helper for emitting ifdef-undef-endif scope.
class IfDefEmitter {
public:
IfDefEmitter(raw_ostream &OS, StringRef Name) : Name(Name.str()), OS(OS) {
OS << "#ifdef " << Name << "\n"
<< "#undef " << Name << "\n\n";
}
~IfDefEmitter() { OS << "\n#endif // " << Name << "\n\n"; }

private:
std::string Name;
raw_ostream &OS;
};

// Simple RAII helper for emitting namespace scope. Name can be a single
// namespace (empty for anonymous namespace) or nested namespace.
class NamespaceEmitter {
public:
NamespaceEmitter(raw_ostream &OS, StringRef Name) : OS(OS) {
emitNamespaceStarts(Name);
}

~NamespaceEmitter() { close(); }

// Explicit function to close the namespace scopes.
void close() {
for (StringRef NS : llvm::reverse(Namespaces))
OS << "} // namespace " << NS << "\n";
Namespaces.clear();
}

private:
void emitNamespaceStarts(StringRef Name) {
llvm::SplitString(Name, Namespaces, "::");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A follow-on improvement would be to get rid of this namespace parsing and emit this directly using C++17 nested namespace definition.

for (StringRef NS : Namespaces)
OS << "namespace " << NS << " {\n";
}

SmallVector<StringRef, 2> Namespaces;
raw_ostream &OS;
};

} // end namespace llvm

#endif // LLVM_TABLEGEN_CODEGENHELPERS_H
73 changes: 18 additions & 55 deletions llvm/utils/TableGen/Basic/DirectiveEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/TableGen/CodeGenHelpers.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
Expand All @@ -29,27 +30,11 @@

using namespace llvm;

namespace {
// Simple RAII helper for defining ifdef-undef-endif scopes.
class IfDefScope {
public:
IfDefScope(StringRef Name, raw_ostream &OS) : Name(Name), OS(OS) {
OS << "#ifdef " << Name << "\n"
<< "#undef " << Name << "\n";
}

~IfDefScope() { OS << "\n#endif // " << Name << "\n\n"; }

private:
StringRef Name;
raw_ostream &OS;
};
} // namespace

namespace {
enum class Frontend { LLVM, Flang, Clang };
} // namespace

StringRef getFESpelling(Frontend FE) {
static StringRef getFESpelling(Frontend FE) {
switch (FE) {
case Frontend::LLVM:
return "llvm";
Expand All @@ -60,7 +45,6 @@ StringRef getFESpelling(Frontend FE) {
}
llvm_unreachable("unknown FE kind");
}
} // namespace

// Get the full namespace qualifier for the directive language.
static std::string getQualifier(const DirectiveLanguage &DirLang,
Expand Down Expand Up @@ -297,13 +281,8 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) {
OS << "#include <cstddef>\n"; // for size_t
OS << "#include <utility>\n"; // for std::pair
OS << "\n";
OS << "namespace llvm {\n";

// Open namespaces defined in the directive language
SmallVector<StringRef, 2> Namespaces;
SplitString(DirLang.getCppNamespace(), Namespaces, "::");
for (auto Ns : Namespaces)
OS << "namespace " << Ns << " {\n";
NamespaceEmitter LlvmNS(OS, "llvm");
NamespaceEmitter DirLangNS(OS, DirLang.getCppNamespace());

if (DirLang.hasEnableBitmaskEnumInNamespace())
OS << "\nLLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();\n";
Expand Down Expand Up @@ -380,9 +359,7 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) {
OS << "\n";
}

// Closing namespaces
for (auto Ns : reverse(Namespaces))
OS << "} // namespace " << Ns << "\n";
DirLangNS.close();

// These specializations need to be in ::llvm.
for (StringRef Enum : {"Association", "Category", "Directive", "Clause"}) {
Expand All @@ -392,9 +369,7 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) {
OS << " static constexpr bool is_iterable = true;\n";
OS << "};\n";
}

OS << "} // namespace llvm\n";

LlvmNS.close();
OS << "#endif // LLVM_" << Lang << "_INC\n";
}

Expand Down Expand Up @@ -971,11 +946,10 @@ static void generateDirectiveClauseSets(const DirectiveLanguage &DirLang,
std::string IfDefName{"GEN_"};
IfDefName += getFESpelling(FE).upper();
IfDefName += "_DIRECTIVE_CLAUSE_SETS";
IfDefScope Scope(IfDefName, OS);
IfDefEmitter Scope(OS, IfDefName);

StringRef Namespace =
getFESpelling(FE == Frontend::Flang ? Frontend::LLVM : FE);
OS << "\n";
// The namespace has to be different for clang vs flang, as 2 structs with the
// same name but different layout is UB. So just put the 'clang' on in the
// clang namespace.
Expand Down Expand Up @@ -1016,9 +990,8 @@ static void generateDirectiveClauseMap(const DirectiveLanguage &DirLang,
std::string IfDefName{"GEN_"};
IfDefName += getFESpelling(FE).upper();
IfDefName += "_DIRECTIVE_CLAUSE_MAP";
IfDefScope Scope(IfDefName, OS);
IfDefEmitter Scope(OS, IfDefName);

OS << "\n";
OS << "{\n";

// The namespace has to be different for clang vs flang, as 2 structs with the
Expand Down Expand Up @@ -1062,9 +1035,7 @@ static void generateDirectiveClauseMap(const DirectiveLanguage &DirLang,
static void generateFlangClauseParserClass(const DirectiveLanguage &DirLang,
raw_ostream &OS) {

IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES", OS);

OS << "\n";
IfDefEmitter Scope(OS, "GEN_FLANG_CLAUSE_PARSER_CLASSES");

for (const Clause Clause : DirLang.getClauses()) {
if (!Clause.getFlangClass().empty()) {
Expand All @@ -1089,9 +1060,8 @@ static void generateFlangClauseParserClass(const DirectiveLanguage &DirLang,
static void generateFlangClauseParserClassList(const DirectiveLanguage &DirLang,
raw_ostream &OS) {

IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES_LIST", OS);
IfDefEmitter Scope(OS, "GEN_FLANG_CLAUSE_PARSER_CLASSES_LIST");

OS << "\n";
interleaveComma(DirLang.getClauses(), OS, [&](const Record *C) {
Clause Clause(C);
OS << Clause.getFormattedParserClassName() << "\n";
Expand All @@ -1102,9 +1072,8 @@ static void generateFlangClauseParserClassList(const DirectiveLanguage &DirLang,
static void generateFlangClauseDump(const DirectiveLanguage &DirLang,
raw_ostream &OS) {

IfDefScope Scope("GEN_FLANG_DUMP_PARSE_TREE_CLAUSES", OS);
IfDefEmitter Scope(OS, "GEN_FLANG_DUMP_PARSE_TREE_CLAUSES");

OS << "\n";
for (const Clause Clause : DirLang.getClauses()) {
OS << "NODE(" << DirLang.getFlangClauseBaseClass() << ", "
<< Clause.getFormattedParserClassName() << ")\n";
Expand All @@ -1116,10 +1085,9 @@ static void generateFlangClauseDump(const DirectiveLanguage &DirLang,
static void generateFlangClauseUnparse(const DirectiveLanguage &DirLang,
raw_ostream &OS) {

IfDefScope Scope("GEN_FLANG_CLAUSE_UNPARSE", OS);
IfDefEmitter Scope(OS, "GEN_FLANG_CLAUSE_UNPARSE");

StringRef Base = DirLang.getFlangClauseBaseClass();
OS << "\n";

for (const Clause Clause : DirLang.getClauses()) {
if (Clause.skipFlangUnparser())
Expand Down Expand Up @@ -1172,9 +1140,8 @@ static void generateFlangClauseUnparse(const DirectiveLanguage &DirLang,
static void generateFlangClauseCheckPrototypes(const DirectiveLanguage &DirLang,
raw_ostream &OS) {

IfDefScope Scope("GEN_FLANG_CLAUSE_CHECK_ENTER", OS);
IfDefEmitter Scope(OS, "GEN_FLANG_CLAUSE_CHECK_ENTER");

OS << "\n";
for (const Clause Clause : DirLang.getClauses()) {
OS << "void Enter(const parser::" << DirLang.getFlangClauseBaseClass()
<< "::" << Clause.getFormattedParserClassName() << " &);\n";
Expand All @@ -1186,12 +1153,11 @@ static void generateFlangClauseCheckPrototypes(const DirectiveLanguage &DirLang,
static void generateFlangClauseParserKindMap(const DirectiveLanguage &DirLang,
raw_ostream &OS) {

IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_KIND_MAP", OS);
IfDefEmitter Scope(OS, "GEN_FLANG_CLAUSE_PARSER_KIND_MAP");

StringRef Prefix = DirLang.getClausePrefix();
std::string Qual = getQualifier(DirLang);

OS << "\n";
for (const Record *R : DirLang.getClauses()) {
Clause C(R);
OS << "if constexpr (std::is_same_v<A, parser::"
Expand All @@ -1216,11 +1182,10 @@ static void generateFlangClausesParser(const DirectiveLanguage &DirLang,
llvm::sort(Names, [](const auto &A, const auto &B) {
return A.second.Name > B.second.Name;
});
IfDefScope Scope("GEN_FLANG_CLAUSES_PARSER", OS);
IfDefEmitter Scope(OS, "GEN_FLANG_CLAUSES_PARSER");
StringRef Base = DirLang.getFlangClauseBaseClass();

unsigned LastIndex = Names.size() - 1;
OS << "\n";
OS << "TYPE_PARSER(\n";
for (auto [Index, RecSp] : llvm::enumerate(Names)) {
auto [R, S] = RecSp;
Expand Down Expand Up @@ -1313,10 +1278,9 @@ static void emitDirectivesFlangImpl(const DirectiveLanguage &DirLang,
static void generateClauseClassMacro(const DirectiveLanguage &DirLang,
raw_ostream &OS) {
// Generate macros style information for legacy code in clang
IfDefScope Scope("GEN_CLANG_CLAUSE_CLASS", OS);
IfDefEmitter Scope(OS, "GEN_CLANG_CLAUSE_CLASS");

StringRef Prefix = DirLang.getClausePrefix();
OS << "\n";

OS << "#ifndef CLAUSE\n";
OS << "#define CLAUSE(Enum, Str, Implicit)\n";
Expand Down Expand Up @@ -1375,12 +1339,11 @@ static void generateClauseClassMacro(const DirectiveLanguage &DirLang,
// language. This code can be included in library.
void emitDirectivesBasicImpl(const DirectiveLanguage &DirLang,
raw_ostream &OS) {
IfDefScope Scope("GEN_DIRECTIVES_IMPL", OS);
IfDefEmitter Scope(OS, "GEN_DIRECTIVES_IMPL");

StringRef DPrefix = DirLang.getDirectivePrefix();
StringRef CPrefix = DirLang.getClausePrefix();

OS << "\n";
OS << "#include \"llvm/Frontend/Directive/Spelling.h\"\n";
OS << "#include \"llvm/Support/ErrorHandling.h\"\n";
OS << "#include <utility>\n";
Expand Down
36 changes: 17 additions & 19 deletions llvm/utils/TableGen/Basic/TargetFeaturesEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//

#include "TargetFeaturesEmitter.h"
#include "llvm/TableGen/CodeGenHelpers.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/TableGenBackend.h"
#include "llvm/TargetParser/SubtargetFeature.h"
Expand Down Expand Up @@ -43,7 +44,7 @@ FeatureMapTy TargetFeaturesEmitter::enumeration(raw_ostream &OS) {
PrintFatalError(
"Too many subtarget features! Bump MAX_SUBTARGET_FEATURES.");

OS << "namespace " << Target << " {\n";
NamespaceEmitter NS(OS, Target);

OS << "enum {\n";

Expand All @@ -58,9 +59,8 @@ FeatureMapTy TargetFeaturesEmitter::enumeration(raw_ostream &OS) {

OS << " " << "NumSubtargetFeatures = " << N << "\n";

// Close enumeration and namespace
// Close enumeration.
OS << "};\n";
OS << "} // end namespace " << Target << "\n";
return FeatureMap;
}

Expand Down Expand Up @@ -149,25 +149,23 @@ void TargetFeaturesEmitter::printCPUKeyValues(raw_ostream &OS,
void TargetFeaturesEmitter::run(raw_ostream &OS) {
OS << "// Autogenerated by TargetFeatureEmitter.cpp\n\n";

OS << "\n#ifdef GET_SUBTARGETFEATURES_ENUM\n";
OS << "#undef GET_SUBTARGETFEATURES_ENUM\n\n";

OS << "namespace llvm {\n";
auto FeatureMap = enumeration(OS);
OS << "} // end namespace llvm\n\n";
OS << "#endif // GET_SUBTARGETFEATURES_ENUM\n\n";
FeatureMapTy FeatureMap;
{
IfDefEmitter IfDef(OS, "GET_SUBTARGETFEATURES_ENUM");
NamespaceEmitter NS(OS, "llvm");
FeatureMap = enumeration(OS);
}

OS << "\n#ifdef GET_SUBTARGETFEATURES_KV\n";
OS << "#undef GET_SUBTARGETFEATURES_KV\n\n";
{
IfDefEmitter IfDef(OS, "GET_SUBTARGETFEATURES_KV");
NamespaceEmitter NS(OS, "llvm");

OS << "namespace llvm {\n";
printFeatureKeyValues(OS, FeatureMap);
OS << "\n";
printFeatureKeyValues(OS, FeatureMap);
OS << "\n";

printCPUKeyValues(OS, FeatureMap);
OS << "\n";
OS << "} // end namespace llvm\n\n";
OS << "#endif // GET_SUBTARGETFEATURES_KV\n\n";
printCPUKeyValues(OS, FeatureMap);
OS << "\n";
}
}

static TableGen::Emitter::OptClass<TargetFeaturesEmitter>
Expand Down
Loading