dang created this revision. Herald added subscribers: llvm-commits, cfe-commits, dexonsmith, mgorny. Herald added projects: clang, LLVM. dang added reviewers: Bigcheese, dexonsmith. dang edited the summary of this revision.
This is an add-on to the RFC at http://lists.llvm.org/pipermail/cfe-dev/2020-May/065421.html <http://lists.llvm.org/pipermail/cfe-dev/2020-May/065421.html> This only works for -fmodules-strict-context-hash at the moment. This introduces optional additional information in Option records that can specify a mapping between an option and a field of a class (used here for CompilerInvocation). Also it adds a GenerateCC1CommandLine method to Compiler invocation that uses the TableGen definitions to generate command line argument strings. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D79796 Files: clang/include/clang/Driver/CC1Options.td clang/include/clang/Frontend/CompilerInvocation.h clang/lib/Frontend/CompilerInvocation.cpp clang/unittests/Frontend/CMakeLists.txt clang/unittests/Frontend/CompilerInvocationTest.cpp llvm/include/llvm/Option/OptParser.td llvm/utils/TableGen/OptParserEmitter.cpp
Index: llvm/utils/TableGen/OptParserEmitter.cpp =================================================================== --- llvm/utils/TableGen/OptParserEmitter.cpp +++ llvm/utils/TableGen/OptParserEmitter.cpp @@ -33,6 +33,20 @@ return OS; } +static void EmitMarshallingInfo(raw_ostream &OS, const Record &R) { + OS << R.getValueAsString("KeyPath"); + OS << ", "; + if (!isa<UnsetInit>(R.getValueInit("IsPositive"))) + OS << R.getValueAsBit("IsPositive"); + else + OS << "INVALID"; + OS << ", "; + if (!isa<UnsetInit>(R.getValueInit("DefaultValue"))) + OS << R.getValueAsString("DefaultValue"); + else + OS << "INVALID"; +} + /// OptParserEmitter - This tablegen backend takes an input .td file /// describing a list of options and emits a data structure for parsing and /// working with those options when given an input command line. @@ -135,12 +149,8 @@ OS << "//////////\n"; OS << "// Options\n\n"; - for (unsigned i = 0, e = Opts.size(); i != e; ++i) { - const Record &R = *Opts[i]; - - // Start a single option entry. - OS << "OPTION("; + auto WriteOptRecordFields = [&](raw_ostream &OS, const Record &R) { // The option prefix; std::vector<StringRef> prf = R.getValueAsListOfStrings("Prefixes"); OS << Prefixes[PrefixKeyT(prf.begin(), prf.end())] << ", "; @@ -149,7 +159,7 @@ write_cstring(OS, R.getValueAsString("Name")); // The option identifier name. - OS << ", "<< getOptionName(R); + OS << ", " << getOptionName(R); // The option kind. OS << ", " << R.getValueAsDef("Kind")->getValueAsString("Name"); @@ -190,8 +200,7 @@ int NumFlags = 0; const ListInit *LI = R.getValueAsListInit("Flags"); for (Init *I : *LI) - OS << (NumFlags++ ? " | " : "") - << cast<DefInit>(I)->getDef()->getName(); + OS << (NumFlags++ ? " | " : "") << cast<DefInit>(I)->getDef()->getName(); if (GroupFlags) { for (Init *I : *GroupFlags) OS << (NumFlags++ ? " | " : "") @@ -224,11 +233,33 @@ write_cstring(OS, R.getValueAsString("Values")); else OS << "nullptr"; + }; + + for (unsigned i = 0, e = Opts.size(); i != e; ++i) { + const Record &R = *Opts[i]; + // Start a single option entry. + OS << "OPTION("; + WriteOptRecordFields(OS, R); OS << ")\n"; } OS << "#endif // OPTION\n"; + OS << "#ifdef OPTION_WITH_MARSHALLING\n"; + for (unsigned i = 0, e = Opts.size(); i != e; ++i) { + const Record &R = *Opts[i]; + + if (!isa<UnsetInit>(R.getValueInit("MarshallingInfo"))) { + OS << "OPTION_WITH_MARSHALLING("; + WriteOptRecordFields(OS, R); + OS << ", "; + EmitMarshallingInfo( + OS, *cast<DefInit>(R.getValueInit("MarshallingInfo"))->getDef()); + OS << ")\n"; + } + } + OS << "#endif // OPTION_WITH_MARSHALLING\n"; + OS << "\n"; OS << "#ifdef OPTTABLE_ARG_INIT\n"; OS << "//////////\n"; @@ -252,8 +283,8 @@ "OptTable!\");\n"; } OS << "}\n"; + } + OS << "\n"; + OS << "#endif // OPTTABLE_ARG_INIT\n"; } - OS << "\n"; - OS << "#endif // OPTTABLE_ARG_INIT\n"; -} } // end namespace llvm Index: llvm/include/llvm/Option/OptParser.td =================================================================== --- llvm/include/llvm/Option/OptParser.td +++ llvm/include/llvm/Option/OptParser.td @@ -80,6 +80,16 @@ list<OptionFlag> Flags = []; } +// Add support for generating marshalling code + +class OptionMarshallingInfo<code keypath> { + code KeyPath = keypath; + // Used by the Flag option kind. + bit IsPositive = ?; + code DefaultValue = ?; + list<code> EnumValues = ?; +} + // Define the option class. class Option<list<string> prefixes, string name, OptionKind kind> { @@ -97,6 +107,7 @@ OptionGroup Group = ?; Option Alias = ?; list<string> AliasArgs = []; + OptionMarshallingInfo MarshallingInfo = ?; } // Helpers for defining options. @@ -130,6 +141,22 @@ class Values<string value> { string Values = value; } class ValuesCode<code valuecode> { code ValuesCode = valuecode; } +class MarshallingInfo<OptionMarshallingInfo info> { OptionMarshallingInfo MarshallingInfo = info; } +class MarshallingFlag<code keypath, bit ispositive, code defaultvalue> + : OptionMarshallingInfo<keypath> { + bit IsPositive = ispositive; + code DefaultValue = defaultvalue; +} +class MarshallingString<code keypath, code defaultvalue> + : OptionMarshallingInfo<keypath> { + code DefaultValue = defaultvalue; +} +class MarshallingEnum<code keypath, code defaultvalue, list<code> enumvalues> + : OptionMarshallingInfo<keypath> { + code DefaultValue = defaultvalue; + list<code>EnumValues = enumvalues; +} + // Predefined options. // FIXME: Have generator validate that these appear in correct position (and Index: clang/unittests/Frontend/CompilerInvocationTest.cpp =================================================================== --- /dev/null +++ clang/unittests/Frontend/CompilerInvocationTest.cpp @@ -0,0 +1,38 @@ +//===- unittests/Frontend/CompilerInvocationTest.cpp - CI tests //---------===// +// +// 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 "clang/Frontend/CompilerInvocation.h" +#include "clang/Frontend/CompilerInstance.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace clang; + +namespace { + +TEST(CompilerInvocation, CanGenerateCC1CommandLine) { + const char *Args[] = {"clang", "-xc++", "-fmodules-strict-context-hash", "-"}; + + IntrusiveRefCntPtr<DiagnosticsEngine> Diags = + CompilerInstance::createDiagnostics(new DiagnosticOptions()); + + CompilerInvocation CInvok; + CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); + + SmallVector<const char *, 32> GeneratedArgs; + SmallVector<std::string, 32> GeneratedArgsStorage; + auto StringAlloc = [&GeneratedArgsStorage](const Twine &Arg) { + return GeneratedArgsStorage.emplace_back(Arg.str()).c_str(); + }; + + CInvok.generateCC1CommandLine(GeneratedArgs, StringAlloc); + + ASSERT_STREQ(GeneratedArgs[0], "-fmodules-strict-context-hash"); +} + +} // anonymous namespace Index: clang/unittests/Frontend/CMakeLists.txt =================================================================== --- clang/unittests/Frontend/CMakeLists.txt +++ clang/unittests/Frontend/CMakeLists.txt @@ -4,6 +4,7 @@ add_clang_unittest(FrontendTests ASTUnitTest.cpp + CompilerInvocationTest.cpp CompilerInstanceTest.cpp FixedPointString.cpp FrontendActionTest.cpp Index: clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- clang/lib/Frontend/CompilerInvocation.cpp +++ clang/lib/Frontend/CompilerInvocation.cpp @@ -51,6 +51,7 @@ #include "llvm/ADT/Hashing.h" #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" @@ -2212,7 +2213,6 @@ Opts.AddPrebuiltModulePath(A->getValue()); Opts.DisableModuleHash = Args.hasArg(OPT_fdisable_module_hash); Opts.ModulesHashContent = Args.hasArg(OPT_fmodules_hash_content); - Opts.ModulesStrictContextHash = Args.hasArg(OPT_fmodules_strict_context_hash); Opts.ModulesValidateDiagnosticOptions = !Args.hasArg(OPT_fmodules_disable_diagnostic_validation); Opts.ImplicitModuleMaps = Args.hasFlag(OPT_fimplicit_module_maps, @@ -3743,7 +3743,15 @@ MissingArgCount, IncludedFlagsBitmask); removeExplicitModuleBuildIncompatibleOptions(Args); - + +#define OPTION_WITH_MARSHALLING(PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, \ + ALIASARGS, FLAGS, PARAM, HELPTEXT, METAVAR, \ + VALUES, KEYPATH, IS_POSITIVE, DEFAULT_VALUE) \ + if (Option::KIND##Class == Option::FlagClass) \ + Res.KEYPATH = Args.hasArg(OPT_##ID) && IS_POSITIVE; +#include "clang/Driver/Options.inc" +#undef OPTION_WITH_MARSHALLING + LangOptions &LangOpts = *Res.getLangOpts(); // Check for missing argument error. @@ -4016,6 +4024,22 @@ return llvm::APInt(64, code).toString(36, /*Signed=*/false); } +void CompilerInvocation::generateCC1CommandLine( + SmallVectorImpl<const char *> &Args, + llvm::function_ref<const char *(const Twine &)> StringAllocator) const { +#define PREFIX(PREFIX_TYPE, BRACED_INIT) \ + const char *PREFIX_TYPE[4] = BRACED_INIT; +#define OPTION_WITH_MARSHALLING(PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, \ + ALIASARGS, FLAGS, PARAM, HELPTEXT, METAVAR, \ + VALUES, KEYPATH, IS_POSITIVE, DEFAULT_VALUE) \ + if (Option::KIND##Class == Option::FlagClass && \ + IS_POSITIVE != DEFAULT_VALUE && this->KEYPATH != DEFAULT_VALUE) \ + Args.push_back(StringAllocator(Twine(PREFIX_TYPE[0]) + NAME)); +#include "clang/Driver/Options.inc" +#undef OPTION_WITH_MARSHALLING +#undef PREFIX +} + namespace clang { IntrusiveRefCntPtr<llvm::vfs::FileSystem> Index: clang/include/clang/Frontend/CompilerInvocation.h =================================================================== --- clang/include/clang/Frontend/CompilerInvocation.h +++ clang/include/clang/Frontend/CompilerInvocation.h @@ -157,6 +157,8 @@ /// one of the vaild-to-access (albeit arbitrary) states. /// /// \param [out] Res - The resulting invocation. + /// \param [in] CommandLineArgs - Array of argument strings, this should not + /// contain "-cc1". static bool CreateFromArgs(CompilerInvocation &Res, ArrayRef<const char *> CommandLineArgs, DiagnosticsEngine &Diags); @@ -187,6 +189,20 @@ /// identifying the conditions under which the module was built. std::string getModuleHash(DiagnosticsEngine &Diags) const; + /// Generate a cc1-compatible command line arguments from this instance. + /// + /// \param [out] Args - The generated arguments. Note that the caller is + /// responsible for insersting the path to the clang executable and "-cc1" if + /// desired. + /// \param StringAllocator - A function that given a Twine can allocate + /// storage for a given command line argument and return a pointer to the + /// newly allocated string. The returned pointer is what gets appended to + /// Args. + void + generateCC1CommandLine(llvm::SmallVectorImpl<const char *> &Args, + llvm::function_ref<const char *(const llvm::Twine &)> + StringAllocator) const; + /// @} /// @name Option Subgroups /// @{ Index: clang/include/clang/Driver/CC1Options.td =================================================================== --- clang/include/clang/Driver/CC1Options.td +++ clang/include/clang/Driver/CC1Options.td @@ -854,7 +854,8 @@ HelpText<"Enable hashing the content of a module file">; def fmodules_strict_context_hash : Flag<["-"], "fmodules-strict-context-hash">, HelpText<"Enable hashing of all compiler options that could impact the " - "semantics of a module in an implicit build">; + "semantics of a module in an implicit build">, + MarshallingInfo<MarshallingFlag<"HeaderSearchOpts->ModulesStrictContextHash", 1, "false">>; def c_isystem : JoinedOrSeparate<["-"], "c-isystem">, MetaVarName<"<directory>">, HelpText<"Add directory to the C SYSTEM include search path">; def objc_isystem : JoinedOrSeparate<["-"], "objc-isystem">,
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits