Merge pull request #15013 from davidungar/PR-18-11-fileMap

[Batch mode] Write supplementary output file map. rdar://problem/38157859
This commit is contained in:
David Ungar
2018-03-16 17:38:53 -07:00
committed by GitHub
38 changed files with 696 additions and 358 deletions

View File

@@ -5,12 +5,10 @@ set(swiftDriver_sources
Driver.cpp
FrontendUtil.cpp
Job.cpp
OutputFileMap.cpp
ParseableOutput.cpp
PrettyStackTrace.cpp
ToolChain.cpp
ToolChains.cpp
Types.cpp
)
set(swiftDriver_targetDefines)

View File

@@ -26,6 +26,8 @@
#include "swift/Driver/Job.h"
#include "swift/Driver/ParseableOutput.h"
#include "swift/Driver/ToolChain.h"
#include "swift/Frontend/OutputFileMap.h"
#include "swift/Option/Options.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SetVector.h"
@@ -37,12 +39,14 @@
#include "llvm/Support/Compiler.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/YAMLParser.h"
#include "llvm/Support/raw_ostream.h"
#include "CompilationRecord.h"
#define DEBUG_TYPE "batch-mode"
// Batch-mode has a sub-mode for testing that randomizes batch partitions,
// by user-provided seed. That is the only thing randomized here.
#include <random>
@@ -103,6 +107,7 @@ Compilation::Compilation(DiagnosticEngine &Diags,
bool EnableIncrementalBuild,
bool EnableBatchMode,
unsigned BatchSeed,
bool ForceOneBatchRepartition,
bool SkipTaskExecution,
bool SaveTemps,
bool ShowDriverTimeCompilation,
@@ -119,12 +124,14 @@ Compilation::Compilation(DiagnosticEngine &Diags,
EnableIncrementalBuild(EnableIncrementalBuild),
EnableBatchMode(EnableBatchMode),
BatchSeed(BatchSeed),
ForceOneBatchRepartition(ForceOneBatchRepartition),
SaveTemps(SaveTemps),
ShowDriverTimeCompilation(ShowDriverTimeCompilation),
Stats(std::move(StatsReporter)) {
};
static bool writeFilelistIfNecessary(const Job *job, DiagnosticEngine &diags);
static bool writeFilelistIfNecessary(const Job *job, const ArgList &args,
DiagnosticEngine &diags);
using CommandSet = llvm::SmallPtrSet<const Job *, 16>;
using CommandSetVector = llvm::SetVector<const Job*>;
@@ -254,7 +261,8 @@ namespace driver {
void addPendingJobToTaskQueue(const Job *Cmd) {
// FIXME: Failing here should not take down the whole process.
bool success = writeFilelistIfNecessary(Cmd, Comp.Diags);
bool success =
writeFilelistIfNecessary(Cmd, *Comp.TranslatedArgs.get(), Comp.Diags);
assert(success && "failed to write filelist");
(void)success;
@@ -787,12 +795,20 @@ namespace driver {
});
}
// FIXME: at the moment we're not passing OutputFileMaps to frontends, so
// due to the multiplication of the number of additional files and the
// Due to the multiplication of the number of additional files and the
// number of files in a batch, it's pretty easy to construct too-long
// command lines here, which will then fail to exec. We address this crudely
// by re-forming batches with a finer partition when we overflow.
//
// Now that we're passing OutputFileMaps to frontends, this should never
// happen, but keep this as insurance, because the decision to pass output
// file maps cannot know the exact length of the command line, so may
// possibly fail to use the OutputFileMap.
//
// In order to be able to exercise as much of the code paths as possible,
// take a flag to force a retry, but only once.
bool shouldRetryWithMorePartitions(std::vector<const Job *> const &Batches,
bool &PretendTheCommandLineIsTooLongOnce,
size_t &NumPartitions) {
// Stop rebatching if we can't subdivide batches any further.
@@ -801,10 +817,14 @@ namespace driver {
for (auto const *B : Batches) {
if (!llvm::sys::commandLineFitsWithinSystemLimits(B->getExecutable(),
B->getArguments())) {
B->getArguments()) ||
PretendTheCommandLineIsTooLongOnce) {
PretendTheCommandLineIsTooLongOnce = false;
// To avoid redoing the batch loop too many times, repartition pretty
// aggressively by doubling partition count / halving size.
NumPartitions *= 2;
DEBUG(llvm::dbgs()
<< "Should have used a supplementary output file map.\n");
return true;
}
}
@@ -827,6 +847,8 @@ namespace driver {
size_t NumPartitions = Comp.NumberOfParallelCommands;
CommandSetVector Batchable, NonBatchable;
std::vector<const Job *> Batches;
bool PretendTheCommandLineIsTooLongOnce =
Comp.getForceOneBatchRepartition();
do {
// We might be restarting loop; clear these before proceeding.
Batchable.clear();
@@ -845,7 +867,8 @@ namespace driver {
formBatchJobFromPartitionBatch(Batches, Batch);
}
} while (shouldRetryWithMorePartitions(Batches, NumPartitions));
} while (shouldRetryWithMorePartitions(
Batches, PretendTheCommandLineIsTooLongOnce, NumPartitions));
PendingExecution.clear();
// Save batches so we can locate and decompose them on task-exit.
@@ -1089,7 +1112,8 @@ static void writeCompilationRecord(StringRef path, StringRef argsHash,
}
}
static bool writeFilelistIfNecessary(const Job *job, DiagnosticEngine &diags) {
static bool writeFilelistIfNecessary(const Job *job, const ArgList &args,
DiagnosticEngine &diags) {
bool ok = true;
for (const FilelistInfo &filelistInfo : job->getFilelistInfos()) {
if (filelistInfo.path.empty())
@@ -1121,18 +1145,29 @@ static bool writeFilelistIfNecessary(const Job *job, DiagnosticEngine &diags) {
}
break;
case FilelistInfo::WhichFiles::PrimaryInputs:
for (const Action *A : job->getSource().getInputs()) {
const auto *IA = cast<InputAction>(A);
out << IA->getInputArg().getValue() << "\n";
// Ensure that -index-file-path works in conjunction with
// -driver-use-filelists. It needs to be the only primary.
if (Arg *A = args.getLastArg(options::OPT_index_file_path))
out << A->getValue() << "\n";
else {
// The normal case for non-single-compile jobs.
for (const Action *A : job->getSource().getInputs()) {
const auto *IA = cast<InputAction>(A);
out << IA->getInputArg().getValue() << "\n";
}
}
break;
case FilelistInfo::WhichFiles::Output:
case FilelistInfo::WhichFiles::Output: {
const CommandOutput &outputInfo = job->getOutput();
assert(outputInfo.getPrimaryOutputType() == filelistInfo.type);
for (auto &output : outputInfo.getPrimaryOutputFilenames())
out << output << "\n";
break;
}
case FilelistInfo::WhichFiles::SupplementaryOutput:
job->getOutput().writeOutputFileMap(out);
break;
}
}
return ok;
}
@@ -1171,7 +1206,7 @@ int Compilation::performSingleCommand(const Job *Cmd) {
break;
}
if (!writeFilelistIfNecessary(Cmd, Diags))
if (!writeFilelistIfNecessary(Cmd, *TranslatedArgs.get(), Diags))
return 1;
switch (Level) {

View File

@@ -17,25 +17,25 @@
#include "swift/Driver/Driver.h"
#include "ToolChains.h"
#include "swift/Strings.h"
#include "swift/AST/DiagnosticEngine.h"
#include "swift/AST/DiagnosticsDriver.h"
#include "swift/AST/DiagnosticsFrontend.h"
#include "swift/Basic/LLVM.h"
#include "swift/Basic/TaskQueue.h"
#include "swift/Basic/Version.h"
#include "swift/Basic/Range.h"
#include "swift/Basic/Statistic.h"
#include "swift/Basic/TaskQueue.h"
#include "swift/Basic/Version.h"
#include "swift/Config.h"
#include "swift/Driver/Action.h"
#include "swift/Driver/Compilation.h"
#include "swift/Driver/Job.h"
#include "swift/Driver/OutputFileMap.h"
#include "swift/Driver/PrettyStackTrace.h"
#include "swift/Driver/ToolChain.h"
#include "swift/Frontend/OutputFileMap.h"
#include "swift/Option/Options.h"
#include "swift/Option/SanitizerOptions.h"
#include "swift/Parse/Lexer.h"
#include "swift/Config.h"
#include "swift/Strings.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/STLExtras.h"
@@ -531,6 +531,8 @@ Driver::buildCompilation(const ToolChain &TC,
A->getAsString(*ArgList), A->getValue());
}
}
DriverForceOneBatchRepartition =
ArgList->hasArg(options::OPT_driver_force_one_batch_repartition);
bool Incremental = ArgList->hasArg(options::OPT_incremental);
if (ArgList->hasArg(options::OPT_whole_module_optimization)) {
@@ -621,7 +623,7 @@ Driver::buildCompilation(const ToolChain &TC,
// REPL mode expects no input files, so suppress the error.
SuppressNoInputFilesError = true;
std::unique_ptr<OutputFileMap> OFM =
Optional<OutputFileMap> OFM =
buildOutputFileMap(*TranslatedArgList, workingDirectory);
if (Diags.hadAnyError())
@@ -704,13 +706,14 @@ Driver::buildCompilation(const ToolChain &TC,
Incremental,
BatchMode,
DriverBatchSeed,
DriverForceOneBatchRepartition,
DriverSkipExecution,
SaveTemps,
ShowDriverTimeCompilation,
std::move(StatsReporter)));
// Construct the graph of Actions.
SmallVector<const Action *, 8> TopLevelActions;
buildActions(TopLevelActions, TC, OI, OFM.get(),
buildActions(TopLevelActions, TC, OI, OFM ? OFM.getPointer() : nullptr,
rebuildEverything ? nullptr : &outOfDateMap, *C);
if (Diags.hadAnyError())
@@ -721,7 +724,8 @@ Driver::buildCompilation(const ToolChain &TC,
return nullptr;
}
buildJobs(TopLevelActions, OI, OFM.get(), workingDirectory, TC, *C);
buildJobs(TopLevelActions, OI, OFM ? OFM.getPointer() : nullptr,
workingDirectory, TC, *C);
if (DriverPrintDerivedOutputFileMap) {
C->getDerivedOutputFileMap().dump(llvm::outs(), true);
@@ -1102,7 +1106,8 @@ void Driver::buildOutputInfo(const ToolChain &TC, const DerivedArgList &Args,
} else { // DriverKind::Batch
OI.CompilerMode = OutputInfo::Mode::StandardCompile;
if (Args.hasArg(options::OPT_whole_module_optimization))
if (Args.hasArg(options::OPT_whole_module_optimization,
options::OPT_index_file))
OI.CompilerMode = OutputInfo::Mode::SingleCompile;
OI.CompilerOutputType = types::TY_Object;
}
@@ -1697,20 +1702,21 @@ bool Driver::handleImmediateArgs(const ArgList &Args, const ToolChain &TC) {
return true;
}
std::unique_ptr<OutputFileMap>
Optional<OutputFileMap>
Driver::buildOutputFileMap(const llvm::opt::DerivedArgList &Args,
StringRef workingDirectory) const {
const Arg *A = Args.getLastArg(options::OPT_output_file_map);
if (!A)
return nullptr;
return None;
// TODO: perform some preflight checks to ensure the file exists.
auto OFM = OutputFileMap::loadFromPath(A->getValue(), workingDirectory);
if (!OFM) {
// TODO: emit diagnostic with error string
Diags.diagnose(SourceLoc(), diag::error_unable_to_load_output_file_map);
llvm::Expected<OutputFileMap> OFM =
OutputFileMap::loadFromPath(A->getValue(), workingDirectory);
if (auto Err = OFM.takeError()) {
Diags.diagnose(SourceLoc(), diag::error_unable_to_load_output_file_map,
llvm::toString(std::move(Err)));
}
return OFM;
return *OFM;
}
void Driver::buildJobs(ArrayRef<const Action *> TopLevelActions,
@@ -2650,3 +2656,17 @@ void Driver::printHelp(bool ShowHidden) const {
getOpts().PrintHelp(llvm::outs(), Name.c_str(), "Swift compiler",
IncludedFlagsBitmask, ExcludedFlagsBitmask);
}
bool OutputInfo::mightHaveExplicitPrimaryInputs(
const CommandOutput &Output) const {
switch (CompilerMode) {
case Mode::StandardCompile:
case Mode::BatchModeCompile:
return true;
case Mode::SingleCompile:
return false;
case Mode::Immediate:
case Mode::REPL:
llvm_unreachable("REPL and immediate modes handled elsewhere");
}
}

View File

@@ -240,6 +240,10 @@ StringRef CommandOutput::getAnyOutputForType(types::ID Type) const {
return getAdditionalOutputForType(Type);
}
const OutputFileMap &CommandOutput::getDerivedOutputMap() const {
return DerivedOutputMap;
}
StringRef CommandOutput::getBaseInput(size_t Index) const {
assert(Index < Inputs.size());
return Inputs[Index].Base;
@@ -310,6 +314,16 @@ CommandOutput::dump() const {
llvm::errs() << '\n';
}
void CommandOutput::writeOutputFileMap(llvm::raw_ostream &out) const {
SmallVector<StringRef, 4> inputs;
for (const CommandInputPair IP : Inputs) {
assert(IP.Base == IP.Primary && !IP.Base.empty() &&
"output file maps won't work if these differ");
inputs.push_back(IP.Primary);
}
getDerivedOutputMap().write(out, inputs);
}
Job::~Job() = default;
void Job::printArguments(raw_ostream &os,

View File

@@ -1,200 +0,0 @@
//===--- OutputFileMap.cpp - Driver output file map -----------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "swift/Driver/OutputFileMap.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include <system_error>
using namespace swift;
using namespace swift::driver;
std::unique_ptr<OutputFileMap>
OutputFileMap::loadFromPath(StringRef Path, StringRef workingDirectory) {
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileBufOrErr =
llvm::MemoryBuffer::getFile(Path);
if (!FileBufOrErr)
return nullptr;
return loadFromBuffer(std::move(FileBufOrErr.get()), workingDirectory);
}
std::unique_ptr<OutputFileMap>
OutputFileMap::loadFromBuffer(StringRef Data, StringRef workingDirectory) {
std::unique_ptr<llvm::MemoryBuffer> Buffer{
llvm::MemoryBuffer::getMemBuffer(Data)
};
return loadFromBuffer(std::move(Buffer), workingDirectory);
}
std::unique_ptr<OutputFileMap>
OutputFileMap::loadFromBuffer(std::unique_ptr<llvm::MemoryBuffer> Buffer,
StringRef workingDirectory) {
std::unique_ptr<OutputFileMap> OFM(new OutputFileMap());
if (OFM->parse(std::move(Buffer), workingDirectory))
return nullptr;
return OFM;
}
const TypeToPathMap *OutputFileMap::getOutputMapForInput(StringRef Input) const{
auto iter = InputToOutputsMap.find(Input);
if (iter == InputToOutputsMap.end())
return nullptr;
else
return &iter->second;
}
TypeToPathMap &
OutputFileMap::getOrCreateOutputMapForInput(StringRef Input) {
return InputToOutputsMap[Input];
}
const TypeToPathMap *OutputFileMap::getOutputMapForSingleOutput() const {
return getOutputMapForInput(StringRef());
}
TypeToPathMap &
OutputFileMap::getOrCreateOutputMapForSingleOutput() {
return InputToOutputsMap[StringRef()];
}
void OutputFileMap::dump(llvm::raw_ostream &os, bool Sort) const {
typedef std::pair<types::ID, std::string> TypePathPair;
auto printOutputPair = [&os] (StringRef InputPath,
const TypePathPair &OutputPair) -> void {
os << InputPath << " -> " << types::getTypeName(OutputPair.first) << ": \""
<< OutputPair.second << "\"\n";
};
if (Sort) {
typedef std::pair<StringRef, TypeToPathMap> PathMapPair;
std::vector<PathMapPair> Maps;
for (auto &InputPair : InputToOutputsMap) {
Maps.emplace_back(InputPair.first(), InputPair.second);
}
std::sort(Maps.begin(), Maps.end(), [] (const PathMapPair &LHS,
const PathMapPair &RHS) -> bool {
return LHS.first < RHS.first;
});
for (auto &InputPair : Maps) {
const TypeToPathMap &Map = InputPair.second;
std::vector<TypePathPair> Pairs;
Pairs.insert(Pairs.end(), Map.begin(), Map.end());
std::sort(Pairs.begin(), Pairs.end());
for (auto &OutputPair : Pairs) {
printOutputPair(InputPair.first, OutputPair);
}
}
} else {
for (auto &InputPair : InputToOutputsMap) {
const TypeToPathMap &Map = InputPair.second;
for (const TypePathPair &OutputPair : Map) {
printOutputPair(InputPair.first(), OutputPair);
}
}
}
}
bool OutputFileMap::parse(std::unique_ptr<llvm::MemoryBuffer> Buffer,
StringRef workingDirectory) {
llvm::SourceMgr SM;
llvm::yaml::Stream YAMLStream(Buffer->getMemBufferRef(), SM);
auto I = YAMLStream.begin();
if (I == YAMLStream.end())
return true;
auto Root = I->getRoot();
if (!Root)
return true;
auto *Map = dyn_cast<llvm::yaml::MappingNode>(Root);
if (!Map)
return true;
auto resolvePath =
[workingDirectory](
llvm::yaml::ScalarNode *Path,
llvm::SmallVectorImpl<char> &PathStorage) -> StringRef {
StringRef PathStr = Path->getValue(PathStorage);
if (workingDirectory.empty() || PathStr.empty() || PathStr == "-" ||
llvm::sys::path::is_absolute(PathStr)) {
return PathStr;
}
// Copy the path to avoid making assumptions about how getValue deals with
// Storage.
SmallString<128> PathStrCopy(PathStr);
PathStorage.clear();
PathStorage.reserve(PathStrCopy.size() + workingDirectory.size() + 1);
PathStorage.insert(PathStorage.begin(), workingDirectory.begin(),
workingDirectory.end());
llvm::sys::path::append(PathStorage, PathStrCopy);
return StringRef(PathStorage.data(), PathStorage.size());
};
for (auto &Pair : *Map) {
llvm::yaml::Node *Key = Pair.getKey();
llvm::yaml::Node *Value = Pair.getValue();
if (!Key)
return true;
if (!Value)
return true;
auto *InputPath = dyn_cast<llvm::yaml::ScalarNode>(Key);
if (!InputPath)
return true;
llvm::yaml::MappingNode *OutputMapNode =
dyn_cast<llvm::yaml::MappingNode>(Value);
if (!OutputMapNode)
return true;
TypeToPathMap OutputMap;
for (auto &OutputPair : *OutputMapNode) {
llvm::yaml::Node *Key = OutputPair.getKey();
llvm::yaml::Node *Value = OutputPair.getValue();
auto *KindNode = dyn_cast<llvm::yaml::ScalarNode>(Key);
if (!KindNode)
return true;
auto *Path = dyn_cast<llvm::yaml::ScalarNode>(Value);
if (!Path)
return true;
llvm::SmallString<16> KindStorage;
types::ID Kind =
types::lookupTypeForName(KindNode->getValue(KindStorage));
// Ignore unknown types, so that an older swiftc can be used with a newer
// build system.
if (Kind == types::TY_INVALID)
continue;
llvm::SmallString<128> PathStorage;
OutputMap.insert(std::pair<types::ID, std::string>(
Kind, resolvePath(Path, PathStorage)));
}
llvm::SmallString<128> InputStorage;
InputToOutputsMap[resolvePath(InputPath, InputStorage)] =
std::move(OutputMap);
}
return false;
}

View File

@@ -15,7 +15,7 @@
#include "swift/Basic/JSONSerialization.h"
#include "swift/Driver/Action.h"
#include "swift/Driver/Job.h"
#include "swift/Driver/Types.h"
#include "swift/Frontend/Types.h"
#include "llvm/Option/Arg.h"
#include "llvm/Support/raw_ostream.h"

View File

@@ -13,7 +13,7 @@
#include "swift/Driver/PrettyStackTrace.h"
#include "swift/Driver/Action.h"
#include "swift/Driver/Job.h"
#include "swift/Driver/Types.h"
#include "swift/Frontend/Types.h"
#include "llvm/Option/Arg.h"
#include "llvm/Support/raw_ostream.h"

View File

@@ -21,24 +21,23 @@
#include "swift/Driver/Compilation.h"
#include "swift/Driver/Driver.h"
#include "swift/Driver/Job.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
#include "llvm/ADT/STLExtras.h"
using namespace swift;
using namespace swift::driver;
using namespace llvm::opt;
ToolChain::JobContext::JobContext(Compilation &C,
ArrayRef<const Job *> Inputs,
ToolChain::JobContext::JobContext(Compilation &C, ArrayRef<const Job *> Inputs,
ArrayRef<const Action *> InputActions,
const CommandOutput &Output,
const OutputInfo &OI)
: C(C), Inputs(Inputs), InputActions(InputActions), Output(Output),
OI(OI), Args(C.getArgs()) {}
: C(C), Inputs(Inputs), InputActions(InputActions), Output(Output), OI(OI),
Args(C.getArgs()) {}
ArrayRef<InputPair> ToolChain::JobContext::getTopLevelInputFiles() const {
return C.getInputFiles();

View File

@@ -17,6 +17,7 @@
#include "swift/Basic/Platform.h"
#include "swift/Basic/Range.h"
#include "swift/Basic/TaskQueue.h"
#include "swift/Driver/Compilation.h"
#include "swift/Driver/Driver.h"
#include "swift/Driver/Job.h"
#include "swift/Frontend/Frontend.h"
@@ -37,8 +38,41 @@ using namespace swift;
using namespace swift::driver;
using namespace llvm::opt;
/// The limit for passing a list of files on the command line.
static const size_t TOO_MANY_FILES = 128;
bool ToolChain::JobContext::shouldUseInputFileList() const {
if (Args.hasArg(options::OPT_driver_use_filelists))
return true;
return getTopLevelInputFiles().size() > TOO_MANY_FILES;
}
bool ToolChain::JobContext::shouldUsePrimaryInputFileListInFrontendInvocation()
const {
if (Args.hasArg(options::OPT_driver_use_filelists))
return true;
return InputActions.size() > TOO_MANY_FILES;
}
bool ToolChain::JobContext::shouldUseMainOutputFileListInFrontendInvocation()
const {
if (Args.hasArg(options::OPT_driver_use_filelists))
return true;
return Output.getPrimaryOutputFilenames().size() > TOO_MANY_FILES;
}
bool ToolChain::JobContext::
shouldUseSupplementaryOutputFileMapInFrontendInvocation() const {
if (Args.hasArg(options::OPT_driver_use_filelists))
return true;
static const unsigned UpperBoundOnSupplementaryOutputFileTypes =
types::TY_INVALID;
return InputActions.size() * UpperBoundOnSupplementaryOutputFileTypes >
TOO_MANY_FILES;
}
bool ToolChain::JobContext::shouldFilterFrontendInputsByType() const {
// FIXME: SingleCompile has not filtered its inputs in the past and now people
// rely upon that. But we would like the compilation modes to be consistent.
return OI.CompilerMode != OutputInfo::Mode::SingleCompile;
}
static void addInputsOfType(ArgStringList &Arguments,
ArrayRef<const Action *> Inputs,
@@ -214,19 +248,10 @@ static void addCommonFrontendArgs(const ToolChain &TC,
inputArgs.AddAllArgs(arguments, options::OPT_Xllvm);
inputArgs.AddAllArgs(arguments, options::OPT_Xcc);
addOutputsOfType(arguments, output, inputArgs,
types::TY_SwiftModuleDocFile,
"-emit-module-doc-path");
if (llvm::sys::Process::StandardErrHasColors())
arguments.push_back("-color-diagnostics");
addOutputsOfType(arguments, output, inputArgs,
types::TY_SerializedDiagnostics,
"-serialize-diagnostics-path");
}
ToolChain::InvocationInfo
ToolChain::constructInvocation(const CompileJobAction &job,
const JobContext &context) const {
@@ -235,164 +260,15 @@ ToolChain::constructInvocation(const CompileJobAction &job,
Arguments.push_back("-frontend");
// Determine the frontend mode option.
const char *FrontendModeOption = nullptr;
switch (context.OI.CompilerMode) {
case OutputInfo::Mode::StandardCompile:
case OutputInfo::Mode::SingleCompile:
case OutputInfo::Mode::BatchModeCompile: {
switch (context.Output.getPrimaryOutputType()) {
case types::TY_Object:
FrontendModeOption = "-c";
break;
case types::TY_PCH:
FrontendModeOption = "-emit-pch";
break;
case types::TY_RawSIL:
FrontendModeOption = "-emit-silgen";
break;
case types::TY_SIL:
FrontendModeOption = "-emit-sil";
break;
case types::TY_RawSIB:
FrontendModeOption = "-emit-sibgen";
break;
case types::TY_SIB:
FrontendModeOption = "-emit-sib";
break;
case types::TY_LLVM_IR:
FrontendModeOption = "-emit-ir";
break;
case types::TY_LLVM_BC:
FrontendModeOption = "-emit-bc";
break;
case types::TY_Assembly:
FrontendModeOption = "-S";
break;
case types::TY_SwiftModuleFile:
// Since this is our primary output, we need to specify the option here.
FrontendModeOption = "-emit-module";
break;
case types::TY_ImportedModules:
FrontendModeOption = "-emit-imported-modules";
break;
case types::TY_IndexData:
FrontendModeOption = "-typecheck";
break;
case types::TY_Remapping:
FrontendModeOption = "-update-code";
break;
case types::TY_Nothing:
// We were told to output nothing, so get the last mode option and use that.
if (const Arg *A = context.Args.getLastArg(options::OPT_modes_Group))
FrontendModeOption = A->getSpelling().data();
else
llvm_unreachable("We were told to perform a standard compile, "
"but no mode option was passed to the driver.");
break;
case types::TY_Swift:
case types::TY_dSYM:
case types::TY_AutolinkFile:
case types::TY_Dependencies:
case types::TY_SwiftModuleDocFile:
case types::TY_ClangModuleFile:
case types::TY_SerializedDiagnostics:
case types::TY_ObjCHeader:
case types::TY_Image:
case types::TY_SwiftDeps:
case types::TY_ModuleTrace:
case types::TY_TBD:
case types::TY_OptRecord:
llvm_unreachable("Output type can never be primary output.");
case types::TY_INVALID:
llvm_unreachable("Invalid type ID");
}
break;
}
case OutputInfo::Mode::Immediate:
case OutputInfo::Mode::REPL:
llvm_unreachable("REPL and immediate modes handled elsewhere");
{
// Determine the frontend mode option.
const char *FrontendModeOption = context.computeFrontendModeForCompile();
assert(FrontendModeOption != nullptr &&
"No frontend mode option specified!");
Arguments.push_back(FrontendModeOption);
}
assert(FrontendModeOption != nullptr && "No frontend mode option specified!");
Arguments.push_back(FrontendModeOption);
// Add input arguments.
switch (context.OI.CompilerMode) {
case OutputInfo::Mode::StandardCompile:
assert(context.InputActions.size() == 1 &&
"Standard-compile mode takes exactly one input (the primary file)");
LLVM_FALLTHROUGH;
case OutputInfo::Mode::BatchModeCompile: {
bool UseFileList =
(context.Args.hasArg(options::OPT_driver_use_filelists) ||
context.getTopLevelInputFiles().size() > TOO_MANY_FILES);
bool UsePrimaryFileList =
((context.OI.CompilerMode == OutputInfo::Mode::BatchModeCompile) &&
(context.Args.hasArg(options::OPT_driver_use_filelists) ||
context.InputActions.size() > TOO_MANY_FILES));
if (UseFileList) {
Arguments.push_back("-filelist");
Arguments.push_back(context.getAllSourcesPath());
}
if (UsePrimaryFileList) {
Arguments.push_back("-primary-filelist");
Arguments.push_back(context.getTemporaryFilePath("primaryInputs", ""));
II.FilelistInfos.push_back({Arguments.back(), types::TY_Swift,
FilelistInfo::WhichFiles::PrimaryInputs});
}
if (!UseFileList || !UsePrimaryFileList) {
llvm::StringSet<> primaries;
for (const Action *A : context.InputActions) {
const auto *IA = cast<InputAction>(A);
primaries.insert(IA->getInputArg().getValue());
}
for (auto inputPair : context.getTopLevelInputFiles()) {
if (!types::isPartOfSwiftCompilation(inputPair.first))
continue;
const char *inputName = inputPair.second->getValue();
if (primaries.count(inputName)) {
if (!UsePrimaryFileList) {
Arguments.push_back("-primary-file");
Arguments.push_back(inputName);
}
} else {
if (!UseFileList) {
Arguments.push_back(inputName);
}
}
}
}
break;
}
case OutputInfo::Mode::SingleCompile: {
StringRef PrimaryFileWrittenToCommandLine;
if (context.Output.getPrimaryOutputType() == types::TY_IndexData) {
if (Arg *A = context.Args.getLastArg(options::OPT_index_file_path)) {
Arguments.push_back("-primary-file");
Arguments.push_back(A->getValue());
PrimaryFileWrittenToCommandLine = A->getValue();
}
}
if (context.Args.hasArg(options::OPT_driver_use_filelists) ||
context.InputActions.size() > TOO_MANY_FILES) {
Arguments.push_back("-filelist");
Arguments.push_back(context.getAllSourcesPath());
} else {
for (const Action *A : context.InputActions) {
const Arg &InputArg = cast<InputAction>(A)->getInputArg();
// Frontend no longer tolerates redundant input files on command line.
if (InputArg.getValue() != PrimaryFileWrittenToCommandLine)
InputArg.render(context.Args, Arguments);
}
}
break;
}
case OutputInfo::Mode::Immediate:
case OutputInfo::Mode::REPL:
llvm_unreachable("REPL and immediate modes handled elsewhere");
}
context.addFrontendInputAndOutputArguments(Arguments, II.FilelistInfos);
// Forward migrator flags.
if (auto DataPath = context.Args.getLastArg(options::
@@ -453,33 +329,6 @@ ToolChain::constructInvocation(const CompileJobAction &job,
Arguments.push_back("-module-name");
Arguments.push_back(context.Args.MakeArgString(context.OI.ModuleName));
addOutputsOfType(Arguments, context.Output, context.Args,
types::ID::TY_SwiftModuleFile,
"-emit-module-path");
if (addOutputsOfType(Arguments, context.Output, context.Args,
types::ID::TY_ObjCHeader, "-emit-objc-header-path")) {
assert(context.OI.CompilerMode == OutputInfo::Mode::SingleCompile &&
"The Swift tool should only emit an Obj-C header in single compile"
"mode!");
}
addOutputsOfType(Arguments, context.Output, context.Args,
types::TY_Dependencies,
"-emit-dependencies-path");
addOutputsOfType(Arguments, context.Output, context.Args,
types::TY_SwiftDeps,
"-emit-reference-dependencies-path");
addOutputsOfType(Arguments, context.Output, context.Args,
types::TY_ModuleTrace,
"-emit-loaded-module-trace-path");
addOutputsOfType(Arguments, context.Output, context.Args,
types::TY_TBD,
"-emit-tbd-path");
addOutputsOfType(Arguments, context.Output, context.Args,
types::TY_OptRecord,
"-save-optimization-record-path");
@@ -500,8 +349,7 @@ ToolChain::constructInvocation(const CompileJobAction &job,
// Add the output file argument if necessary.
if (context.Output.getPrimaryOutputType() != types::TY_Nothing) {
if (context.Args.hasArg(options::OPT_driver_use_filelists) ||
context.Output.getPrimaryOutputFilenames().size() > TOO_MANY_FILES) {
if (context.shouldUseMainOutputFileListInFrontendInvocation()) {
Arguments.push_back("-output-filelist");
Arguments.push_back(context.getTemporaryFilePath("outputs", ""));
II.FilelistInfos.push_back({Arguments.back(),
@@ -526,6 +374,185 @@ ToolChain::constructInvocation(const CompileJobAction &job,
return II;
}
const char *ToolChain::JobContext::computeFrontendModeForCompile() const {
switch (OI.CompilerMode) {
case OutputInfo::Mode::StandardCompile:
case OutputInfo::Mode::SingleCompile:
case OutputInfo::Mode::BatchModeCompile:
break;
case OutputInfo::Mode::Immediate:
case OutputInfo::Mode::REPL:
llvm_unreachable("REPL and immediate modes handled elsewhere");
}
switch (Output.getPrimaryOutputType()) {
case types::TY_Object:
return "-c";
case types::TY_PCH:
return "-emit-pch";
case types::TY_RawSIL:
return "-emit-silgen";
case types::TY_SIL:
return "-emit-sil";
case types::TY_RawSIB:
return "-emit-sibgen";
case types::TY_SIB:
return "-emit-sib";
case types::TY_LLVM_IR:
return "-emit-ir";
case types::TY_LLVM_BC:
return "-emit-bc";
case types::TY_Assembly:
return "-S";
case types::TY_SwiftModuleFile:
// Since this is our primary output, we need to specify the option here.
return "-emit-module";
case types::TY_ImportedModules:
return "-emit-imported-modules";
case types::TY_IndexData:
return "-typecheck";
case types::TY_Remapping:
return "-update-code";
case types::TY_Nothing:
// We were told to output nothing, so get the last mode option and use that.
if (const Arg *A = Args.getLastArg(options::OPT_modes_Group))
return A->getSpelling().data();
else
llvm_unreachable("We were told to perform a standard compile, "
"but no mode option was passed to the driver.");
case types::TY_Swift:
case types::TY_dSYM:
case types::TY_AutolinkFile:
case types::TY_Dependencies:
case types::TY_SwiftModuleDocFile:
case types::TY_ClangModuleFile:
case types::TY_SerializedDiagnostics:
case types::TY_ObjCHeader:
case types::TY_Image:
case types::TY_SwiftDeps:
case types::TY_ModuleTrace:
case types::TY_TBD:
case types::TY_OptRecord:
llvm_unreachable("Output type can never be primary output.");
case types::TY_INVALID:
llvm_unreachable("Invalid type ID");
}
}
void ToolChain::JobContext::addFrontendInputAndOutputArguments(
ArgStringList &Arguments, std::vector<FilelistInfo> &FilelistInfos) const {
switch (OI.CompilerMode) {
case OutputInfo::Mode::StandardCompile:
assert(InputActions.size() == 1 &&
"Standard-compile mode takes exactly one input (the primary file)");
break;
case OutputInfo::Mode::BatchModeCompile:
case OutputInfo::Mode::SingleCompile:
break;
case OutputInfo::Mode::Immediate:
case OutputInfo::Mode::REPL:
llvm_unreachable("REPL and immediate modes handled elsewhere");
}
const bool UseFileList = shouldUseInputFileList();
const bool MayHavePrimaryInputs = OI.mightHaveExplicitPrimaryInputs(Output);
const bool UsePrimaryFileList =
MayHavePrimaryInputs &&
shouldUsePrimaryInputFileListInFrontendInvocation();
const bool FilterInputsByType = shouldFilterFrontendInputsByType();
const bool UseSupplementaryOutputFileList =
shouldUseSupplementaryOutputFileMapInFrontendInvocation();
if (UseFileList) {
Arguments.push_back("-filelist");
Arguments.push_back(getAllSourcesPath());
}
if (UsePrimaryFileList) {
Arguments.push_back("-primary-filelist");
Arguments.push_back(getTemporaryFilePath("primaryInputs", ""));
FilelistInfos.push_back({Arguments.back(), types::TY_Swift,
FilelistInfo::WhichFiles::PrimaryInputs});
}
if (!UseFileList || !UsePrimaryFileList) {
addFrontendCommandLineInputArguments(MayHavePrimaryInputs, UseFileList,
UsePrimaryFileList, FilterInputsByType,
Arguments);
}
if (UseSupplementaryOutputFileList) {
Arguments.push_back("-supplementary-output-file-map");
Arguments.push_back(getTemporaryFilePath("supplementaryOutputs", ""));
FilelistInfos.push_back({Arguments.back(), types::TY_INVALID,
FilelistInfo::WhichFiles::SupplementaryOutput});
} else {
addFrontendSupplementaryOutputArguments(Arguments);
}
}
void ToolChain::JobContext::addFrontendCommandLineInputArguments(
const bool mayHavePrimaryInputs, const bool useFileList,
const bool usePrimaryFileList, const bool filterByType,
ArgStringList &arguments) const {
llvm::StringSet<> primaries;
if (mayHavePrimaryInputs) {
for (const Action *A : InputActions) {
const auto *IA = cast<InputAction>(A);
const llvm::opt::Arg &InArg = IA->getInputArg();
primaries.insert(InArg.getValue());
}
}
// -index-file compilations are weird. They are processed as SingleCompiles
// (WMO), but must indicate that there is one primary file, designated by
// -index-file-path.
if (Arg *A = Args.getLastArg(options::OPT_index_file_path)) {
assert(primaries.empty() &&
"index file jobs should be treated as single (WMO) compiles");
primaries.insert(A->getValue());
}
for (auto inputPair : getTopLevelInputFiles()) {
if (filterByType && !types::isPartOfSwiftCompilation(inputPair.first))
continue;
const char *inputName = inputPair.second->getValue();
const bool isPrimary = primaries.count(inputName);
if (isPrimary && !usePrimaryFileList) {
arguments.push_back("-primary-file");
arguments.push_back(inputName);
}
if ((!isPrimary || usePrimaryFileList) && !useFileList)
arguments.push_back(inputName);
}
}
void ToolChain::JobContext::addFrontendSupplementaryOutputArguments(
ArgStringList &arguments) const {
// FIXME: Get these and other argument strings from the same place for both
// driver and frontend.
addOutputsOfType(arguments, Output, Args, types::ID::TY_SwiftModuleFile,
"-emit-module-path");
addOutputsOfType(arguments, Output, Args, types::TY_SwiftModuleDocFile,
"-emit-module-doc-path");
addOutputsOfType(arguments, Output, Args, types::TY_SerializedDiagnostics,
"-serialize-diagnostics-path");
if (addOutputsOfType(arguments, Output, Args, types::ID::TY_ObjCHeader,
"-emit-objc-header-path")) {
assert(OI.CompilerMode == OutputInfo::Mode::SingleCompile &&
"The Swift tool should only emit an Obj-C header in single compile"
"mode!");
}
addOutputsOfType(arguments, Output, Args, types::TY_Dependencies,
"-emit-dependencies-path");
addOutputsOfType(arguments, Output, Args, types::TY_SwiftDeps,
"-emit-reference-dependencies-path");
addOutputsOfType(arguments, Output, Args, types::TY_ModuleTrace,
"-emit-loaded-module-trace-path");
addOutputsOfType(arguments, Output, Args, types::TY_TBD, "-emit-tbd-path");
}
ToolChain::InvocationInfo
ToolChain::constructInvocation(const InterpretJobAction &job,
const JobContext &context) const {
@@ -711,8 +738,7 @@ ToolChain::constructInvocation(const MergeModuleJobAction &job,
Arguments.push_back("-merge-modules");
Arguments.push_back("-emit-module");
if (context.Args.hasArg(options::OPT_driver_use_filelists) ||
context.Inputs.size() > TOO_MANY_FILES) {
if (context.shouldUseInputFileList()) {
Arguments.push_back("-filelist");
Arguments.push_back(context.getTemporaryFilePath("inputs", ""));
II.FilelistInfos.push_back({Arguments.back(), types::TY_SwiftModuleFile,
@@ -747,6 +773,14 @@ ToolChain::constructInvocation(const MergeModuleJobAction &job,
addCommonFrontendArgs(*this, context.OI, context.Output, context.Args,
Arguments);
addOutputsOfType(Arguments, context.Output, context.Args,
types::TY_SwiftModuleDocFile, "-emit-module-doc-path");
addOutputsOfType(Arguments, context.Output, context.Args,
types::TY_SerializedDiagnostics,
"-serialize-diagnostics-path");
addOutputsOfType(Arguments, context.Output, context.Args,
types::TY_ObjCHeader, "-emit-objc-header-path");
context.Args.AddLastArg(Arguments, options::OPT_import_objc_header);
Arguments.push_back("-module-name");
@@ -755,13 +789,6 @@ ToolChain::constructInvocation(const MergeModuleJobAction &job,
assert(context.Output.getPrimaryOutputType() == types::TY_SwiftModuleFile &&
"The MergeModule tool only produces swiftmodule files!");
auto ObjCHeaderOutputPath =
context.Output.getAdditionalOutputForType(types::TY_ObjCHeader);
if (!ObjCHeaderOutputPath.empty()) {
Arguments.push_back("-emit-objc-header-path");
Arguments.push_back(
context.Args.MakeArgString(ObjCHeaderOutputPath));
}
Arguments.push_back("-o");
Arguments.push_back(context.Args.MakeArgString(
@@ -899,6 +926,9 @@ ToolChain::constructInvocation(const GeneratePCHJobAction &job,
addCommonFrontendArgs(*this, context.OI, context.Output, context.Args,
Arguments);
addOutputsOfType(Arguments, context.Output, context.Args,
types::TY_SerializedDiagnostics,
"-serialize-diagnostics-path");
addInputsOfType(Arguments, context.InputActions, types::TY_ObjCHeader);
context.Args.AddLastArg(Arguments, options::OPT_index_store_path);
@@ -1267,8 +1297,7 @@ toolchains::Darwin::constructInvocation(const LinkJobAction &job,
InvocationInfo II = {LD};
ArgStringList &Arguments = II.Arguments;
if (context.Args.hasArg(options::OPT_driver_use_filelists) ||
context.Inputs.size() > TOO_MANY_FILES) {
if (context.shouldUseInputFileList()) {
Arguments.push_back("-filelist");
Arguments.push_back(context.getTemporaryFilePath("inputs", "LinkFileList"));
II.FilelistInfos.push_back(

View File

@@ -1,182 +0,0 @@
//===--- Types.cpp - Driver input & temporary type information ------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "swift/Driver/Types.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
using namespace swift;
using namespace swift::driver;
using namespace swift::driver::types;
struct TypeInfo {
const char *Name;
const char *Flags;
const char *TempSuffix;
};
static const TypeInfo TypeInfos[] = {
#define TYPE(NAME, ID, TEMP_SUFFIX, FLAGS) \
{ NAME, FLAGS, TEMP_SUFFIX },
#include "swift/Driver/Types.def"
};
static const TypeInfo &getInfo(unsigned Id) {
assert(Id >= 0 && Id < TY_INVALID && "Invalid Type ID.");
return TypeInfos[Id];
}
StringRef types::getTypeName(ID Id) {
return getInfo(Id).Name;
}
StringRef types::getTypeTempSuffix(ID Id) {
return getInfo(Id).TempSuffix;
}
ID types::lookupTypeForExtension(StringRef Ext) {
if (Ext.empty())
return TY_INVALID;
assert(Ext.front() == '.' && "not a file extension");
return llvm::StringSwitch<types::ID>(Ext.drop_front())
#define TYPE(NAME, ID, SUFFIX, FLAGS) \
.Case(SUFFIX, TY_##ID)
#include "swift/Driver/Types.def"
.Default(TY_INVALID);
}
ID types::lookupTypeForName(StringRef Name) {
return llvm::StringSwitch<types::ID>(Name)
#define TYPE(NAME, ID, SUFFIX, FLAGS) \
.Case(NAME, TY_##ID)
#include "swift/Driver/Types.def"
.Default(TY_INVALID);
}
bool types::isTextual(ID Id) {
switch (Id) {
case types::TY_Swift:
case types::TY_SIL:
case types::TY_Dependencies:
case types::TY_Assembly:
case types::TY_RawSIL:
case types::TY_LLVM_IR:
case types::TY_ObjCHeader:
case types::TY_AutolinkFile:
case types::TY_ImportedModules:
case types::TY_TBD:
case types::TY_ModuleTrace:
case types::TY_OptRecord:
return true;
case types::TY_Image:
case types::TY_Object:
case types::TY_dSYM:
case types::TY_PCH:
case types::TY_SIB:
case types::TY_RawSIB:
case types::TY_SwiftModuleFile:
case types::TY_SwiftModuleDocFile:
case types::TY_LLVM_BC:
case types::TY_SerializedDiagnostics:
case types::TY_ClangModuleFile:
case types::TY_SwiftDeps:
case types::TY_Nothing:
case types::TY_Remapping:
case types::TY_IndexData:
return false;
case types::TY_INVALID:
llvm_unreachable("Invalid type ID.");
}
// Work around MSVC warning: not all control paths return a value
llvm_unreachable("All switch cases are covered");
}
bool types::isAfterLLVM(ID Id) {
switch (Id) {
case types::TY_Assembly:
case types::TY_LLVM_IR:
case types::TY_LLVM_BC:
case types::TY_Object:
return true;
case types::TY_Swift:
case types::TY_PCH:
case types::TY_ImportedModules:
case types::TY_TBD:
case types::TY_SIL:
case types::TY_Dependencies:
case types::TY_RawSIL:
case types::TY_ObjCHeader:
case types::TY_AutolinkFile:
case types::TY_Image:
case types::TY_dSYM:
case types::TY_SIB:
case types::TY_RawSIB:
case types::TY_SwiftModuleFile:
case types::TY_SwiftModuleDocFile:
case types::TY_SerializedDiagnostics:
case types::TY_ClangModuleFile:
case types::TY_SwiftDeps:
case types::TY_Nothing:
case types::TY_Remapping:
case types::TY_IndexData:
case types::TY_ModuleTrace:
case types::TY_OptRecord:
return false;
case types::TY_INVALID:
llvm_unreachable("Invalid type ID.");
}
// Work around MSVC warning: not all control paths return a value
llvm_unreachable("All switch cases are covered");
}
bool types::isPartOfSwiftCompilation(ID Id) {
switch (Id) {
case types::TY_Swift:
case types::TY_SIL:
case types::TY_RawSIL:
case types::TY_SIB:
case types::TY_RawSIB:
return true;
case types::TY_Assembly:
case types::TY_LLVM_IR:
case types::TY_LLVM_BC:
case types::TY_Object:
case types::TY_Dependencies:
case types::TY_ObjCHeader:
case types::TY_AutolinkFile:
case types::TY_PCH:
case types::TY_ImportedModules:
case types::TY_TBD:
case types::TY_Image:
case types::TY_dSYM:
case types::TY_SwiftModuleFile:
case types::TY_SwiftModuleDocFile:
case types::TY_SerializedDiagnostics:
case types::TY_ClangModuleFile:
case types::TY_SwiftDeps:
case types::TY_Nothing:
case types::TY_Remapping:
case types::TY_IndexData:
case types::TY_ModuleTrace:
case types::TY_OptRecord:
return false;
case types::TY_INVALID:
llvm_unreachable("Invalid type ID.");
}
// Work around MSVC warning: not all control paths return a value
llvm_unreachable("All switch cases are covered");
}