neerajksingh created this revision. neerajksingh added reviewers: rnk, hans.
The clang-cl driver disables access to command line options outside of the "Core" and "CLOption" sets of command line arguments. This filtering makes it impossible to pass arguments that are interpreted by the clang driver and not by either 'cc1' (the frontend) or the LLVM backend. An example driver-level flag is the '-fno-slp-vectorize' flag, which is processed by the driver in Clang::ConstructJob and used to set the cc1 flag "-vectorize-slp". There is no negative cc1 flag or -mllvm flag, so it is not currently possible to disable the SLP vectorizer from the clang-cl driver. This change introduces the "/Xdriver:" argument that is available when the driver mode is set to CL compatibility. This option works similarly to the "-Xclang" option, except that the option values are processed by the clang driver rather than by 'cc1'. An example usage is: clang-cl /Xdriver:-fno-slp-vectorize /O2 test.c Another example shows how "/Xdriver:" can be used to pass a flag where there is a conflict between a clang-cl compat option and an overlapping clang driver option: clang-cl /MD /Xdriver:-MD /Xdriver:-MF /Xdriver:test_dep_file.dep test.c In the previous example, the unprefixed /MD selects the DLL version of the msvc CRT, while the prefixed -MD flag and the -MF flags are used to create a make dependency file for included headers. One note about flag ordering: the /Xdriver: flags are concatenated to the end of the argument list, so in cases where the last flag wins, the /Xdriver: flags will be chosen regardless of their order relative to other flags on the driver command line. Repository: rC Clang https://reviews.llvm.org/D53457 Files: include/clang/Driver/CLCompatOptions.td include/clang/Driver/Driver.h lib/Driver/Driver.cpp test/Driver/cl-options.c
Index: test/Driver/cl-options.c =================================================================== --- test/Driver/cl-options.c +++ test/Driver/cl-options.c @@ -614,5 +614,17 @@ // RUN: --version \ // RUN: -Werror /Zs -- %s 2>&1 +// Accept clang options under the /Xdriver: flag. + +// RUN: %clang_cl -O2 -### -- %s 2>&1 | FileCheck -check-prefix=NOXDRIVER %s +// NOXDRIVER: "--dependent-lib=libcmt" +// NOXDRIVER-SAME: "-vectorize-slp" +// NOXDRIVER-NOT: "--dependent-lib=msvcrt" + +// RUN: %clang_cl -O2 -MD /Xdriver:-fno-slp-vectorize /Xdriver:-MD /Xdriver:-MF /Xdriver:my_dependency_file.dep -### -- %s 2>&1 | FileCheck -check-prefix=XDRIVER %s +// XDRIVER: "--dependent-lib=msvcrt" +// XDRIVER-SAME: "-dependency-file" "my_dependency_file.dep" +// XDRIVER-NOT: "--dependent-lib=libcmt" +// XDRIVER-NOT: "-vectorize-slp" void f() { } Index: lib/Driver/Driver.cpp =================================================================== --- lib/Driver/Driver.cpp +++ lib/Driver/Driver.cpp @@ -166,14 +166,15 @@ } InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings, + bool ForceNonCLMode, bool &ContainsError) { llvm::PrettyStackTraceString CrashInfo("Command line argument parsing"); ContainsError = false; unsigned IncludedFlagsBitmask; unsigned ExcludedFlagsBitmask; std::tie(IncludedFlagsBitmask, ExcludedFlagsBitmask) = - getIncludeExcludeOptionFlagMasks(); + getIncludeExcludeOptionFlagMasks(ForceNonCLMode); unsigned MissingArgIndex, MissingArgCount; InputArgList Args = @@ -730,7 +731,7 @@ ConfigFile = CfgFileName.str(); bool ContainErrors; CfgOptions = llvm::make_unique<InputArgList>( - ParseArgStrings(NewCfgArgs, ContainErrors)); + ParseArgStrings(NewCfgArgs, false, ContainErrors)); if (ContainErrors) { CfgOptions.reset(); return true; @@ -924,7 +925,7 @@ // Arguments specified in command line. bool ContainsError; CLOptions = llvm::make_unique<InputArgList>( - ParseArgStrings(ArgList.slice(1), ContainsError)); + ParseArgStrings(ArgList.slice(1), false, ContainsError)); // Try parsing configuration file. if (!ContainsError) @@ -934,21 +935,45 @@ // All arguments, from both config file and command line. InputArgList Args = std::move(HasConfigFile ? std::move(*CfgOptions) : std::move(*CLOptions)); - if (HasConfigFile) - for (auto *Opt : *CLOptions) { - if (Opt->getOption().matches(options::OPT_config)) - continue; + + auto appendOneArg = [&Args](const Arg *Opt, const Arg *BaseArg) { unsigned Index = Args.MakeIndex(Opt->getSpelling()); - const Arg *BaseArg = &Opt->getBaseArg(); - if (BaseArg == Opt) - BaseArg = nullptr; Arg *Copy = new llvm::opt::Arg(Opt->getOption(), Opt->getSpelling(), Index, BaseArg); Copy->getValues() = Opt->getValues(); if (Opt->isClaimed()) Copy->claim(); Args.append(Copy); + }; + + if (HasConfigFile) + for (auto *Opt : *CLOptions) { + if (Opt->getOption().matches(options::OPT_config)) + continue; + const Arg *BaseArg = &Opt->getBaseArg(); + if (BaseArg == Opt) + BaseArg = nullptr; + appendOneArg(Opt, BaseArg); + } + + // In CL mode, look for any pass-through arguments + if (IsCLMode() && !ContainsError) { + SmallVector<const char *, 16> CLModePassThroughArgList; + for (const auto *A : Args.filtered(options::OPT__SLASH_Xdriver)) { + A->claim(); + CLModePassThroughArgList.push_back(A->getValue()); + } + + if (!CLModePassThroughArgList.empty()) { + auto CLModePassThroughOptions = llvm::make_unique<InputArgList>( + ParseArgStrings(CLModePassThroughArgList, true, ContainsError)); + + if (!ContainsError) + for (auto *Opt : *CLModePassThroughOptions) { + appendOneArg(Opt, nullptr); + } } + } // FIXME: This stuff needs to go into the Compilation, not the driver. bool CCCPrintPhases; @@ -1452,7 +1477,7 @@ unsigned IncludedFlagsBitmask; unsigned ExcludedFlagsBitmask; std::tie(IncludedFlagsBitmask, ExcludedFlagsBitmask) = - getIncludeExcludeOptionFlagMasks(); + getIncludeExcludeOptionFlagMasks(false); ExcludedFlagsBitmask |= options::NoDriverOption; if (!ShowHidden) @@ -4661,11 +4686,11 @@ return false; } -std::pair<unsigned, unsigned> Driver::getIncludeExcludeOptionFlagMasks() const { +std::pair<unsigned, unsigned> Driver::getIncludeExcludeOptionFlagMasks(bool ForceNonCLMode) const { unsigned IncludedFlagsBitmask = 0; unsigned ExcludedFlagsBitmask = options::NoDriverOption; - if (Mode == CLMode) { + if (Mode == CLMode && !ForceNonCLMode) { // Include CL and Core options. IncludedFlagsBitmask |= options::CLOption; IncludedFlagsBitmask |= options::CoreOption; Index: include/clang/Driver/Driver.h =================================================================== --- include/clang/Driver/Driver.h +++ include/clang/Driver/Driver.h @@ -362,6 +362,7 @@ /// ParseArgStrings - Parse the given list of strings into an /// ArgList. llvm::opt::InputArgList ParseArgStrings(ArrayRef<const char *> Args, + bool ForceNonCLMode, bool &ContainsError); /// BuildInputs - Construct the list of inputs and their types from @@ -552,7 +553,7 @@ /// Get bitmasks for which option flags to include and exclude based on /// the driver mode. - std::pair<unsigned, unsigned> getIncludeExcludeOptionFlagMasks() const; + std::pair<unsigned, unsigned> getIncludeExcludeOptionFlagMasks(bool ForceNonCLMode) const; /// Helper used in BuildJobsForAction. Doesn't use the cache when building /// jobs specifically for the given action, but will use the cache when Index: include/clang/Driver/CLCompatOptions.td =================================================================== --- include/clang/Driver/CLCompatOptions.td +++ include/clang/Driver/CLCompatOptions.td @@ -321,6 +321,8 @@ def _SLASH_volatile_ms : Option<["/", "-"], "volatile:ms", KIND_FLAG>, Group<_SLASH_volatile_Group>, Flags<[CLOption, DriverOption]>, HelpText<"Volatile loads and stores have acquire and release semantics">; +def _SLASH_Xdriver : CLJoinedOrSeparate<"Xdriver:">, + HelpText<"Pass <arg> to the clang driver">, MetaVarName<"<arg>">; def _SLASH_Zl : CLFlag<"Zl">, HelpText<"Don't mention any default libraries in the object file">;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits