163 lines
5.1 KiB
C++
163 lines
5.1 KiB
C++
//===- lib/Core/InputGraph.cpp --------------------------------------------===//
|
|
//
|
|
// The LLVM Linker
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "lld/Core/InputGraph.h"
|
|
|
|
#include "lld/Core/Resolver.h"
|
|
|
|
#include <memory>
|
|
|
|
using namespace lld;
|
|
|
|
static bool sortInputElements(const std::unique_ptr<InputElement> &a,
|
|
const std::unique_ptr<InputElement> &b) {
|
|
return a->getOrdinal() < b->getOrdinal();
|
|
}
|
|
|
|
bool InputGraph::addInputElement(std::unique_ptr<InputElement> ie) {
|
|
_inputArgs.push_back(std::move(ie));
|
|
return true;
|
|
}
|
|
|
|
bool InputGraph::assignOrdinals() {
|
|
for (auto &ie : _inputArgs)
|
|
ie->setOrdinal(++_ordinal);
|
|
return true;
|
|
}
|
|
|
|
void InputGraph::doPostProcess() {
|
|
std::stable_sort(_inputArgs.begin(), _inputArgs.end(), sortInputElements);
|
|
}
|
|
|
|
bool InputGraph::dump(raw_ostream &diagnostics) {
|
|
for (auto &ie : _inputArgs)
|
|
if (!ie->dump(diagnostics))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
/// \brief Insert element at position
|
|
void InputGraph::insertOneElementAt(std::unique_ptr<InputElement> element,
|
|
Position position, size_t pos) {
|
|
if (position == InputGraph::Position::BEGIN)
|
|
pos = 0;
|
|
else if (position == InputGraph::Position::END)
|
|
pos = _inputArgs.size();
|
|
_inputArgs.insert(_inputArgs.begin() + pos, std::move(element));
|
|
}
|
|
|
|
/// \brief Helper functions for the resolver
|
|
ErrorOr<InputElement *> InputGraph::getNextInputElement() {
|
|
if (_nextElementIndex >= _inputArgs.size())
|
|
return make_error_code(InputGraphError::no_more_elements);
|
|
return _inputArgs[_nextElementIndex++].get();
|
|
}
|
|
|
|
void InputGraph::normalize() {
|
|
auto iterb = _inputArgs.begin();
|
|
auto itere = _inputArgs.end();
|
|
auto currentIter = _inputArgs.begin();
|
|
|
|
std::vector<std::unique_ptr<InputElement> > _workInputArgs;
|
|
while (iterb != itere) {
|
|
bool expand = (*iterb)->shouldExpand();
|
|
currentIter = iterb++;
|
|
if (expand) {
|
|
_workInputArgs.insert(
|
|
_workInputArgs.end(),
|
|
std::make_move_iterator((*currentIter)->expandElements().begin()),
|
|
std::make_move_iterator((*currentIter)->expandElements().end()));
|
|
} else {
|
|
_workInputArgs.push_back(std::move(*currentIter));
|
|
}
|
|
}
|
|
_inputArgs = std::move(_workInputArgs);
|
|
}
|
|
|
|
/// InputElement
|
|
|
|
/// \brief Initialize the Input Element, The ordinal value of an input Element
|
|
/// is initially set to -1, if the user wants to override its ordinal,
|
|
/// let the user do it
|
|
InputElement::InputElement(Kind type, int64_t ordinal)
|
|
: _kind(type), _ordinal(ordinal) {}
|
|
|
|
/// FileNode
|
|
FileNode::FileNode(StringRef path, int64_t ordinal)
|
|
: InputElement(InputElement::Kind::File, ordinal), _path(path),
|
|
_resolveState(Resolver::StateNoChange), _nextFileIndex(0) {}
|
|
|
|
/// \brief Read the file into _buffer.
|
|
error_code FileNode::getBuffer(StringRef filePath) {
|
|
// Create a memory buffer
|
|
std::unique_ptr<MemoryBuffer> mb;
|
|
if (error_code ec = MemoryBuffer::getFileOrSTDIN(filePath, mb))
|
|
return ec;
|
|
_buffer = std::move(mb);
|
|
return error_code::success();
|
|
}
|
|
|
|
// Reset the next file that would be be processed by the resolver.
|
|
// Reset the resolve state too.
|
|
void FileNode::resetNextIndex() {
|
|
_nextFileIndex = 0;
|
|
setResolveState(Resolver::StateNoChange);
|
|
}
|
|
|
|
/// ControlNode
|
|
|
|
/// \brief Get the resolver State. The return value of the resolve
|
|
/// state for a control node is the or'ed value of the resolve states
|
|
/// contained in it.
|
|
uint32_t Group::getResolveState() const {
|
|
uint32_t resolveState = Resolver::StateNoChange;
|
|
for (auto &elem : _elements)
|
|
resolveState |= elem->getResolveState();
|
|
return resolveState;
|
|
}
|
|
|
|
/// \brief Set the resolve state for the current element
|
|
/// thats processed by the resolver.
|
|
void Group::setResolveState(uint32_t resolveState) {
|
|
if (_elements.empty())
|
|
return;
|
|
_elements[_currentElementIndex]->setResolveState(resolveState);
|
|
}
|
|
|
|
/// Group
|
|
|
|
/// \brief Return the next file that need to be processed by the resolver.
|
|
/// This also processes input elements depending on the resolve status
|
|
/// of the input elements contained in the group.
|
|
ErrorOr<File &> Group::getNextFile() {
|
|
// If there are no elements, move on to the next input element
|
|
if (_elements.empty())
|
|
return make_error_code(InputGraphError::no_more_files);
|
|
|
|
for (;;) {
|
|
// If we have processed all the elements as part of this node
|
|
// check the resolver status for each input element and if the status
|
|
// has not changed, move onto the next file.
|
|
if (_nextElementIndex == _elements.size()) {
|
|
if (getResolveState() == Resolver::StateNoChange)
|
|
return make_error_code(InputGraphError::no_more_files);
|
|
resetNextIndex();
|
|
}
|
|
_currentElementIndex = _nextElementIndex;
|
|
auto file = _elements[_nextElementIndex]->getNextFile();
|
|
// Move on to the next element if we have finished processing all
|
|
// the files in the input element
|
|
if (file.getError() == InputGraphError::no_more_files) {
|
|
_nextElementIndex++;
|
|
continue;
|
|
}
|
|
return *file;
|
|
}
|
|
}
|