llvm-project/lld/lib/Driver/Driver.cpp
Shankar Easwaran 2895527ec2 [Core] Add flag to check if RoundTripPasses need to be run.
This would allow other flavor specific contexts to override the default value,
if they want to optionally run the round trip passes.

There is some information lost like the original file owner of the atom with
RoundTripPasses. The Gnu flavor needs this information inorder to implement
LinkerScript matching and for other diagnostic outputs such as Map files.

The flag also can be used to record information in the Atom if the information
to the Writer needs to be conveyed through References too.

llvm-svn: 222983
2014-12-01 01:04:11 +00:00

137 lines
4.1 KiB
C++

//===- lib/Driver/Driver.cpp - Linker Driver Emulator ---------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lld/Driver/Driver.h"
#include "lld/Core/Instrumentation.h"
#include "lld/Core/LLVM.h"
#include "lld/Core/Parallel.h"
#include "lld/Core/PassManager.h"
#include "lld/Core/Resolver.h"
#include "lld/Passes/RoundTripNativePass.h"
#include "lld/Passes/RoundTripYAMLPass.h"
#include "lld/ReaderWriter/Reader.h"
#include "lld/ReaderWriter/Writer.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Option/Arg.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include <mutex>
namespace lld {
/// This is where the link is actually performed.
bool Driver::link(LinkingContext &context, raw_ostream &diagnostics) {
// Honor -mllvm
if (!context.llvmOptions().empty()) {
unsigned numArgs = context.llvmOptions().size();
const char **args = new const char *[numArgs + 2];
args[0] = "lld (LLVM option parsing)";
for (unsigned i = 0; i != numArgs; ++i)
args[i + 1] = context.llvmOptions()[i];
args[numArgs + 1] = 0;
llvm::cl::ParseCommandLineOptions(numArgs + 1, args);
}
InputGraph &inputGraph = context.getInputGraph();
if (!inputGraph.size())
return false;
inputGraph.normalize();
bool fail = false;
// Read inputs
ScopedTask readTask(getDefaultDomain(), "Read Args");
TaskGroup tg;
std::mutex diagnosticsMutex;
for (std::unique_ptr<InputElement> &ie : inputGraph.inputElements()) {
tg.spawn([&] {
// Writes to the same output stream is not guaranteed to be thread-safe.
// We buffer the diagnostics output to a separate string-backed output
// stream, acquire the lock, and then print it out.
std::string buf;
llvm::raw_string_ostream stream(buf);
if (std::error_code ec = ie->parse(context, stream)) {
if (FileNode *fileNode = dyn_cast<FileNode>(ie.get()))
stream << fileNode->errStr(ec) << "\n";
else if (dyn_cast<Group>(ie.get()))
// FIXME: We need a better diagnostics here
stream << "Cannot parse group input element\n";
else
llvm_unreachable("Unknown type of input element");
fail = true;
}
stream.flush();
if (!buf.empty()) {
std::lock_guard<std::mutex> lock(diagnosticsMutex);
diagnostics << buf;
}
});
}
tg.sync();
readTask.end();
if (fail)
return false;
std::unique_ptr<SimpleFileNode> fileNode(
new SimpleFileNode("Internal Files"));
InputGraph::FileVectorT internalFiles;
context.createInternalFiles(internalFiles);
if (internalFiles.size())
fileNode->addFiles(std::move(internalFiles));
// Give target a chance to add files.
InputGraph::FileVectorT implicitFiles;
context.createImplicitFiles(implicitFiles);
if (implicitFiles.size())
fileNode->addFiles(std::move(implicitFiles));
context.getInputGraph().addInputElementFront(std::move(fileNode));
// Do core linking.
ScopedTask resolveTask(getDefaultDomain(), "Resolve");
Resolver resolver(context);
if (!resolver.resolve())
return false;
std::unique_ptr<MutableFile> merged = resolver.resultFile();
resolveTask.end();
// Run passes on linked atoms.
ScopedTask passTask(getDefaultDomain(), "Passes");
PassManager pm;
context.addPasses(pm);
#ifndef NDEBUG
if (context.runRoundTripPass()) {
pm.add(std::unique_ptr<Pass>(new RoundTripYAMLPass(context)));
pm.add(std::unique_ptr<Pass>(new RoundTripNativePass(context)));
}
#endif
pm.runOnFile(merged);
passTask.end();
// Give linked atoms to Writer to generate output file.
ScopedTask writeTask(getDefaultDomain(), "Write");
if (std::error_code ec = context.writeFile(*merged)) {
diagnostics << "Failed to write file '" << context.outputPath()
<< "': " << ec.message() << "\n";
return false;
}
return true;
}
} // namespace