//===- 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 using namespace lld; static bool sortInputElements(const std::unique_ptr &a, const std::unique_ptr &b) { return a->getOrdinal() < b->getOrdinal(); } bool InputGraph::addInputElement(std::unique_ptr 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::insertElementAt(std::unique_ptr element, Position position) { if (position == InputGraph::Position::BEGIN) { _inputArgs.insert(_inputArgs.begin(), std::move(element)); return; } assert(position == InputGraph::Position::END); _inputArgs.push_back(std::move(element)); } /// \brief Helper functions for the resolver ErrorOr 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 > _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 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 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; } }