1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-02-01 05:01:59 +01:00
llvm-mirror/utils/TableGen/DirectiveEmitter.cpp
Valentin Clement 869d544267 [openmp] Base of tablegen generated OpenMP common declaration
Summary:
As discussed previously when landing patch for OpenMP in Flang, the idea is
to share common part of the OpenMP declaration between the different Frontend.
While doing this it was thought that moving to tablegen instead of Macros will also
give a cleaner and more powerful way of generating these declaration.
This first part of a future series of patches is setting up the base .td file for
DirectiveLanguage as well as the OpenMP version of it. The base file is meant to
be used by other directive language such as OpenACC.
In this first patch, the Directive and Clause enums are generated with tablegen
instead of the macros on OMPConstants.h. The next pacth will extend this
to other enum and move the Flang frontend to use it.

Reviewers: jdoerfert, DavidTruby, fghanim, ABataev, jdenny, hfinkel, jhuber6, kiranchandramohan, kiranktp

Reviewed By: jdoerfert, jdenny

Subscribers: arphaman, martong, cfe-commits, mgorny, yaxunl, hiraditya, guansong, jfb, sstefan1, aaron.ballman, llvm-commits

Tags: #llvm, #openmp, #clang

Differential Revision: https://reviews.llvm.org/D81736
2020-06-23 10:32:32 -04:00

116 lines
4.1 KiB
C++

//===- DirectiveEmitter.cpp - Directive Language Emitter ------------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
namespace llvm {
void EmitDirectivesEnums(RecordKeeper &Records, raw_ostream &OS) {
const auto &DirectiveLanguages =
Records.getAllDerivedDefinitions("DirectiveLanguage");
if (DirectiveLanguages.size() != 1) {
PrintError("A single definition of DirectiveLanguage is needed.");
return;
}
const auto &DirectiveLanguage = DirectiveLanguages[0];
StringRef languageName = DirectiveLanguage->getValueAsString("name");
StringRef DirectivePrefix =
DirectiveLanguage->getValueAsString("directivePrefix");
StringRef ClausePrefix = DirectiveLanguage->getValueAsString("clausePrefix");
StringRef CppNamespace = DirectiveLanguage->getValueAsString("cppNamespace");
bool MakeEnumAvailableInNamespace =
DirectiveLanguage->getValueAsBit("makeEnumAvailableInNamespace");
bool EnableBitmaskEnumInNamespace =
DirectiveLanguage->getValueAsBit("enableBitmaskEnumInNamespace");
OS << "#ifndef LLVM_" << languageName << "_INC\n";
OS << "#define LLVM_" << languageName << "_INC\n";
if (EnableBitmaskEnumInNamespace)
OS << "#include \"llvm/ADT/BitmaskEnum.h\"\n";
OS << "namespace llvm {\n";
// Open namespaces defined in the directive language
llvm::SmallVector<StringRef, 2> Namespaces;
llvm::SplitString(CppNamespace, Namespaces, "::");
for (auto Ns : Namespaces)
OS << "namespace " << Ns << " {\n";
if (EnableBitmaskEnumInNamespace)
OS << "LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();\n";
// Emit Directive enumeration
OS << "enum class Directive {\n";
const auto &Directives = Records.getAllDerivedDefinitions("Directive");
for (const auto &D : Directives) {
const auto Name = D->getValueAsString("name");
std::string N = Name.str();
std::replace(N.begin(), N.end(), ' ', '_');
OS << DirectivePrefix << N << ",\n";
}
OS << "};\n";
OS << "static constexpr std::size_t Directive_enumSize = "
<< Directives.size() << ";\n";
// Emit Clause enumeration
OS << "enum class Clause {\n";
const auto &Clauses = Records.getAllDerivedDefinitions("Clause");
for (const auto &C : Clauses) {
const auto Name = C->getValueAsString("name");
OS << ClausePrefix << Name << ",\n";
}
OS << "};\n";
OS << "static constexpr std::size_t Clause_enumSize = " << Clauses.size()
<< ";\n";
// Make the enum values available in the defined namespace. This allows us to
// write something like Enum_X if we have a `using namespace <CppNamespace>`.
// At the same time we do not loose the strong type guarantees of the enum
// class, that is we cannot pass an unsigned as Directive without an explicit
// cast.
if (MakeEnumAvailableInNamespace) {
for (const auto &D : Directives) {
const auto Name = D->getValueAsString("name");
std::string N = Name.str();
std::replace(N.begin(), N.end(), ' ', '_');
OS << "constexpr auto " << DirectivePrefix << N << " = " << CppNamespace
<< "::Directive::" << DirectivePrefix << N << ";\n";
}
for (const auto &C : Clauses) {
const auto Name = C->getValueAsString("name");
OS << "constexpr auto " << ClausePrefix << Name << " = " << CppNamespace
<< "::Clause::" << ClausePrefix << Name << ";\n";
}
}
// Closing namespaces
for (auto Ns : llvm::reverse(Namespaces))
OS << "} // namespace " << Ns << "\n";
OS << "} // namespace llvm\n";
OS << "#endif";
}
} // namespace llvm