[Driver] Replace Target with TargetInfo. Simplify LinkerInput.

This removes Target and moves the functionality it had over to TargetInfo.

This also simplifies LinkerInput by removing the InputKind. This will be handled elsewhere.

llvm-svn: 174589
This commit is contained in:
Michael J. Spencer 2013-02-07 06:46:48 +00:00
parent 589baf98b4
commit cfe59fd0d3
12 changed files with 88 additions and 225 deletions

View File

@ -29,38 +29,31 @@
#include <vector>
namespace lld {
enum class InputKind {
Unknown,
YAML,
Native,
Object,
LLVM,
Script
};
/// \brief An input to the linker.
///
/// This class represents an input to the linker. It create the MemoryBuffer
/// lazily when needed based on the file path. It can also take a MemoryBuffer
/// directly.
///
/// The intent is that we only open each file once. And have strong ownership
/// semantics.
class LinkerInput {
LinkerInput(const LinkerInput &) LLVM_DELETED_FUNCTION;
public:
LinkerInput(StringRef file, InputKind kind = InputKind::Unknown)
: _file(file)
, _kind(kind) {}
LinkerInput(StringRef file) : _file(file) {}
LinkerInput(std::unique_ptr<llvm::MemoryBuffer> buffer,
InputKind kind = InputKind::Unknown)
: _buffer(std::move(buffer))
, _file(_buffer->getBufferIdentifier())
, _kind(kind) {}
LinkerInput(std::unique_ptr<llvm::MemoryBuffer> buffer)
: _buffer(std::move(buffer)), _file(_buffer->getBufferIdentifier()) {
}
LinkerInput(LinkerInput &&other)
: _buffer(std::move(other._buffer))
, _file(std::move(other._file))
, _kind(other._kind) {}
LinkerInput(LinkerInput && other)
: _buffer(std::move(other._buffer)), _file(std::move(other._file)) {
}
LinkerInput &operator=(LinkerInput &&rhs) {
_buffer = std::move(rhs._buffer);
_file = std::move(rhs._file);
_kind = rhs._kind;
return *this;
}
@ -75,33 +68,6 @@ public:
return *_buffer;
}
ErrorOr<InputKind> getKind() const {
if (_kind == InputKind::Unknown) {
_kind = llvm::StringSwitch<InputKind>(getPath())
.EndsWith(".objtxt", InputKind::YAML)
.EndsWith(".yaml", InputKind::YAML)
.Default(InputKind::Unknown);
if (_kind != InputKind::Unknown)
return _kind;
auto buf = getBuffer();
if (!buf)
return error_code(buf);
llvm::sys::fs::file_magic magic =
llvm::sys::fs::identify_magic(buf->getBuffer());
switch (magic) {
case llvm::sys::fs::file_magic::elf_relocatable:
_kind = InputKind::Object;
break;
}
}
return _kind;
}
StringRef getPath() const {
return _file;
}
@ -114,7 +80,6 @@ public:
private:
mutable std::unique_ptr<llvm::MemoryBuffer> _buffer;
std::string _file;
mutable InputKind _kind;
};
enum OutputKind {

View File

@ -31,8 +31,11 @@ namespace llvm {
}
namespace lld {
class LinkerInput;
struct LinkerOptions;
class PassManager;
class Reader;
class Writer;
class TargetInfo {
protected:
@ -53,6 +56,14 @@ public:
virtual void addPasses(PassManager &pm) const {}
/// \brief Get a reference to a Reader for the given input.
///
/// Will always return the same object for the same input.
virtual ErrorOr<Reader &> getReader(const LinkerInput &input) const = 0;
/// \brief Get the writer.
virtual ErrorOr<Writer &> getWriter() const = 0;
// TODO: Split out to TargetRelocationInfo.
virtual ErrorOr<int32_t> relocKindFromString(StringRef str) const {
int32_t val;

View File

@ -1,58 +0,0 @@
//===- lld/Driver/Target.h - Linker Target Abstraction --------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
///
/// Interface and factory for creating a specific Target. A Target is used to
/// encapsulate all of the target specific configurations for the linker.
///
//===----------------------------------------------------------------------===//
#ifndef LLD_DRIVER_TARGET_H
#define LLD_DRIVER_TARGET_H
#include "lld/Core/TargetInfo.h"
#include "llvm/Support/ErrorOr.h"
#include <memory>
namespace lld {
class LinkerInput;
struct LinkerOptions;
class Reader;
class TargetInfo;
class Writer;
/// \brief Represents a specific target.
class Target {
protected:
Target(std::unique_ptr<TargetInfo> ti) : _targetInfo(std::move(ti)) {}
public:
virtual ~Target();
const TargetInfo &getTargetInfo() const { return *_targetInfo; };
/// \brief Get a reference to a Reader for the given input.
///
/// Will always return the same object for the same input.
virtual ErrorOr<lld::Reader&> getReader(const LinkerInput &input) = 0;
/// \brief Get the writer.
virtual ErrorOr<lld::Writer&> getWriter() = 0;
static std::unique_ptr<Target> create(const LinkerOptions&);
protected:
std::unique_ptr<TargetInfo> _targetInfo;
};
}
#endif

View File

@ -12,6 +12,9 @@
#include "lld/Core/LinkerOptions.h"
#include "lld/Core/TargetInfo.h"
#include "lld/ReaderWriter/Reader.h"
#include "lld/ReaderWriter/Writer.h"
#include "llvm/Object/ELF.h"
#include "llvm/Support/ELF.h"
@ -30,7 +33,7 @@ public:
class ELFTargetInfo : public TargetInfo {
protected:
ELFTargetInfo(const LinkerOptions &lo) : TargetInfo(lo) {}
ELFTargetInfo(const LinkerOptions &lo);
public:
uint16_t getOutputType() const;
@ -44,6 +47,10 @@ public:
return false;
}
virtual ErrorOr<Reader &> getReader(const LinkerInput &input) const;
virtual ErrorOr<Writer &> getWriter() const;
static std::unique_ptr<ELFTargetInfo> create(const LinkerOptions &lo);
template <typename ELFT>
@ -54,6 +61,8 @@ public:
protected:
std::unique_ptr<TargetHandlerBase> _targetHandler;
mutable std::unique_ptr<Reader> _reader;
mutable std::unique_ptr<Writer> _writer;
};
} // end namespace lld

View File

@ -12,6 +12,8 @@
#include "lld/Core/TargetInfo.h"
#include "llvm/Support/ErrorHandling.h"
#include <memory>
namespace lld {
@ -28,6 +30,14 @@ public:
virtual uint64_t getPageZeroSize() const = 0;
virtual ErrorOr<Reader &> getReader(const LinkerInput &input) const {
llvm_unreachable("Unimplemented!");
}
virtual ErrorOr<Writer &> getWriter() const {
llvm_unreachable("Unimplemented!");
}
static std::unique_ptr<MachOTargetInfo> create(const LinkerOptions &lo);
};
} // end namespace lld

View File

@ -8,8 +8,6 @@ add_lld_library(lldDriver
Driver.cpp
Drivers.cpp
LinkerInvocation.cpp
Target.cpp
Targets.cpp
)
add_dependencies(lldDriver DriverOptionsTableGen)

View File

@ -218,7 +218,7 @@ LinkerOptions lld::generateOptions(const llvm::opt::ArgList &args) {
for (llvm::opt::arg_iterator it = args.filtered_begin(ld::OPT_INPUT),
ie = args.filtered_end();
it != ie; ++it) {
ret._input.push_back(LinkerInput((*it)->getValue(), InputKind::Object));
ret._input.push_back(LinkerInput((*it)->getValue()));
}
ret._llvmArgs = args.getAllArgValues(core::OPT_mllvm);

View File

@ -12,7 +12,7 @@
#include "lld/Core/InputFiles.h"
#include "lld/Core/PassManager.h"
#include "lld/Core/Resolver.h"
#include "lld/Driver/Target.h"
#include "lld/ReaderWriter/ELFTargetInfo.h"
#include "lld/ReaderWriter/Reader.h"
#include "lld/ReaderWriter/Writer.h"
@ -21,6 +21,12 @@
using namespace lld;
namespace {
std::unique_ptr<TargetInfo> createTargetInfo(const LinkerOptions &lo) {
return ELFTargetInfo::create(lo);
}
}
void LinkerInvocation::operator()() {
// Honor -mllvm
if (!_options._llvmArgs.empty()) {
@ -34,9 +40,9 @@ void LinkerInvocation::operator()() {
}
// Create target.
std::unique_ptr<Target> target(Target::create(_options));
std::unique_ptr<TargetInfo> targetInfo(createTargetInfo(_options));
if (!target) {
if (!targetInfo) {
llvm::errs() << "Failed to create target for " << _options._target
<< "\n";
return;
@ -45,7 +51,7 @@ void LinkerInvocation::operator()() {
// Read inputs
InputFiles inputs;
for (const auto &input : _options._input) {
auto reader = target->getReader(input);
auto reader = targetInfo->getReader(input);
if (error_code ec = reader) {
llvm::errs() << "Failed to get reader for: " << input.getPath() << ": "
<< ec.message() << "\n";
@ -69,17 +75,17 @@ void LinkerInvocation::operator()() {
inputs.appendFiles(files);
}
auto writer = target->getWriter();
auto writer = targetInfo->getWriter();
// Give writer a chance to add files
writer->addFiles(inputs);
Resolver resolver(target->getTargetInfo(), inputs);
Resolver resolver(*targetInfo, inputs);
resolver.resolve();
MutableFile &merged = resolver.resultFile();
PassManager pm;
target->getTargetInfo().addPasses(pm);
targetInfo->addPasses(pm);
pm.runOnFile(merged);
if (error_code ec = writer) {

View File

@ -1,14 +0,0 @@
//===- lib/Driver/Target.cpp - Linker Target Abstraction ------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lld/Driver/Target.h"
using namespace lld;
Target::~Target() {}

View File

@ -1,92 +0,0 @@
//===- lib/Driver/Targets.cpp - Linker Targets ----------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
///
/// Concrete instances of the Target interface.
///
//===----------------------------------------------------------------------===//
#include "lld/Driver/Target.h"
#include "lld/Core/LinkerOptions.h"
#include "lld/Core/TargetInfo.h"
#include "lld/ReaderWriter/Reader.h"
#include "lld/ReaderWriter/Writer.h"
#include "lld/ReaderWriter/ELFTargetInfo.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/raw_ostream.h"
#include <set>
using namespace lld;
using namespace std::placeholders;
class ELFTarget : public Target {
public:
ELFTarget(std::unique_ptr<ELFTargetInfo> ti)
: Target(std::unique_ptr<TargetInfo>(ti.get())),
_elfTargetInfo(*ti.release()), _readerELF(createReaderELF(
_elfTargetInfo, std::bind(&ELFTarget::getReader, this, _1))),
_readerYAML(createReaderYAML(*_targetInfo)),
_writer(createWriterELF(_elfTargetInfo)),
_writerYAML(createWriterYAML(*_targetInfo)) {
}
virtual ErrorOr<lld::Reader&> getReader(const LinkerInput &input) {
auto kind = input.getKind();
if (!kind)
return error_code(kind);
if (*kind == InputKind::YAML)
return *_readerYAML;
if (*kind == InputKind::Object)
return *_readerELF;
return llvm::make_error_code(llvm::errc::invalid_argument);
}
virtual ErrorOr<lld::Writer&> getWriter() {
return _targetInfo->getLinkerOptions()._outputYAML ? *_writerYAML
: *_writer;
}
protected:
const ELFTargetInfo &_elfTargetInfo;
std::unique_ptr<lld::Reader> _readerELF, _readerYAML;
std::unique_ptr<lld::Writer> _writer, _writerYAML;
};
class X86LinuxTarget LLVM_FINAL : public ELFTarget {
public:
X86LinuxTarget(std::unique_ptr<ELFTargetInfo> ti)
: ELFTarget(std::move(ti)) {}
};
class HexagonTarget LLVM_FINAL : public ELFTarget {
public:
HexagonTarget(std::unique_ptr<ELFTargetInfo> ti)
: ELFTarget(std::move(ti)) {}
};
std::unique_ptr<Target> Target::create(const LinkerOptions &lo) {
llvm::Triple t(lo._target);
// Create a TargetInfo.
std::unique_ptr<ELFTargetInfo> ti(ELFTargetInfo::create(lo));
// Create the Target
if (t.getOS() == llvm::Triple::Linux && (t.getArch() == llvm::Triple::x86 ||
t.getArch() == llvm::Triple::x86_64))
return std::unique_ptr<Target>(new X86LinuxTarget(std::move(ti)));
else if (t.getArch() == llvm::Triple::hexagon)
return std::unique_ptr<Target>(new HexagonTarget(std::move(ti)));
return std::unique_ptr<Target>();
}

View File

@ -18,6 +18,8 @@
#include "llvm/Support/ELF.h"
namespace lld {
ELFTargetInfo::ELFTargetInfo(const LinkerOptions &lo) : TargetInfo(lo) {}
uint16_t ELFTargetInfo::getOutputType() const {
switch (_options._outputKind) {
case OutputKind::Executable:
@ -52,6 +54,23 @@ uint16_t ELFTargetInfo::getOutputMachine() const {
}
}
ErrorOr<Reader &> ELFTargetInfo::getReader(const LinkerInput &input) const {
if (!_reader)
_reader = createReaderELF(*this, std::bind(&ELFTargetInfo::getReader, this,
std::placeholders::_1));
return *_reader;
}
ErrorOr<Writer &> ELFTargetInfo::getWriter() const {
if (!_writer) {
if (_options._outputYAML)
_writer = createWriterYAML(*this);
else
_writer = createWriterELF(*this);
}
return *_writer;
}
std::unique_ptr<ELFTargetInfo> ELFTargetInfo::create(const LinkerOptions &lo) {
switch (llvm::Triple(llvm::Triple::normalize(lo._target)).getArch()) {
case llvm::Triple::x86:

View File

@ -195,6 +195,15 @@ public:
}
return llvm::make_error_code(llvm::errc::invalid_argument);
}
virtual ErrorOr<Reader &> getReader(const LinkerInput &input) const {
llvm_unreachable("Unimplemented!");
}
virtual ErrorOr<Writer &> getWriter() const {
llvm_unreachable("Unimplemented!");
}
private:
bool _doStubs;
bool _doGOT;