Re-commit r223330: Rewrite InputGraph's Group
llvm-svn: 223867
diff --git a/lld/lib/Core/InputGraph.cpp b/lld/lib/Core/InputGraph.cpp
index 27cbcbb..cde4127 100644
--- a/lld/lib/Core/InputGraph.cpp
+++ b/lld/lib/Core/InputGraph.cpp
@@ -36,8 +36,6 @@
}
}
-void InputGraph::notifyProgress() { _currentInputElement->notifyProgress(); }
-
void InputGraph::registerObserver(std::function<void(File *)> fn) {
_observers.push_back(fn);
}
@@ -61,12 +59,13 @@
ErrorOr<InputElement *> InputGraph::getNextInputElement() {
if (_nextElementIndex >= _inputArgs.size())
return make_error_code(InputGraphError::no_more_elements);
- return _inputArgs[_nextElementIndex++].get();
+ InputElement *elem = _inputArgs[_nextElementIndex++].get();
+ if (isa<GroupEnd>(elem))
+ return getNextInputElement();
+ return elem;
}
void InputGraph::normalize() {
- for (std::unique_ptr<InputElement> &elt : _inputArgs)
- elt->expand();
std::vector<std::unique_ptr<InputElement>> vec;
for (std::unique_ptr<InputElement> &elt : _inputArgs) {
if (elt->getReplacements(vec))
@@ -76,6 +75,25 @@
_inputArgs = std::move(vec);
}
+// If we are at the end of a group, return its size (which indicates
+// how many files we need to go back in the command line).
+// Returns 0 if we are not at the end of a group.
+int InputGraph::getGroupSize() {
+ if (_nextElementIndex >= _inputArgs.size())
+ return 0;
+ InputElement *elem = _inputArgs[_nextElementIndex].get();
+ if (const GroupEnd *group = dyn_cast<GroupEnd>(elem))
+ return group->getSize();
+ return 0;
+}
+
+void InputGraph::skipGroup() {
+ if (_nextElementIndex >= _inputArgs.size())
+ return;
+ if (isa<GroupEnd>(_inputArgs[_nextElementIndex].get()))
+ _nextElementIndex++;
+}
+
/// \brief Read the file into _buffer.
std::error_code FileNode::getBuffer(StringRef filePath) {
// Create a memory buffer
@@ -87,32 +105,10 @@
return std::error_code();
}
-/// \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, and have made no progress on
- // linking, we cannot resolve any symbol from this group. Continue to the
- // next one by returning no_more_files.
- if (_nextElementIndex == _elements.size()) {
- if (!_madeProgress)
- 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;
- }
+bool FileNode::getReplacements(InputGraph::InputElementVectorT &result) {
+ if (_files.size() < 2)
+ return false;
+ for (std::unique_ptr<File> &file : _files)
+ result.push_back(llvm::make_unique<SimpleFileNode>(_path, std::move(file)));
+ return true;
}
diff --git a/lld/lib/Core/Resolver.cpp b/lld/lib/Core/Resolver.cpp
index e4a1b53..c991b8c 100644
--- a/lld/lib/Core/Resolver.cpp
+++ b/lld/lib/Core/Resolver.cpp
@@ -27,7 +27,7 @@
namespace lld {
-void Resolver::handleFile(const File &file) {
+bool Resolver::handleFile(const File &file) {
bool undefAdded = false;
for (const DefinedAtom *atom : file.defined())
doDefinedAtom(*atom);
@@ -38,13 +38,7 @@
doSharedLibraryAtom(*atom);
for (const AbsoluteAtom *atom : file.absolute())
doAbsoluteAtom(*atom);
-
- // Notify the input file manager of the fact that we have made some progress
- // on linking using the current input file. It may want to know the fact for
- // --start-group/--end-group.
- if (undefAdded) {
- _context.getInputGraph().notifyProgress();
- }
+ return undefAdded;
}
void Resolver::forEachUndefines(bool searchForOverrides,
@@ -76,17 +70,19 @@
} while (undefineGenCount != _symbolTable.size());
}
-void Resolver::handleArchiveFile(const File &file) {
+bool Resolver::handleArchiveFile(const File &file) {
const ArchiveLibraryFile *archiveFile = cast<ArchiveLibraryFile>(&file);
bool searchForOverrides =
_context.searchArchivesToOverrideTentativeDefinitions();
+ bool undefAdded = false;
forEachUndefines(searchForOverrides,
[&](StringRef undefName, bool dataSymbolOnly) {
if (const File *member = archiveFile->find(undefName, dataSymbolOnly)) {
member->setOrdinal(_context.getNextOrdinalAndIncrement());
- handleFile(*member);
+ undefAdded = handleFile(*member) || undefAdded;
}
});
+ return undefAdded;
}
void Resolver::handleSharedLibrary(const File &file) {
@@ -233,31 +229,66 @@
doDefinedAtom(*newAtom);
}
+// Returns true if at least one of N previous files has created an
+// undefined symbol.
+bool Resolver::undefinesAdded(int n) {
+ for (size_t i = _fileIndex - n; i < _fileIndex; ++i)
+ if (_newUndefinesAdded[_files[i]])
+ return true;
+ return false;
+}
+
+ErrorOr<File &> Resolver::nextFile(bool &inGroup) {
+ if (size_t groupSize = _context.getInputGraph().getGroupSize()) {
+ // We are at the end of the current group. If one or more new
+ // undefined atom has been added in the last groupSize files, we
+ // reiterate over the files.
+ if (undefinesAdded(groupSize))
+ _fileIndex -= groupSize;
+ _context.getInputGraph().skipGroup();
+ return nextFile(inGroup);
+ }
+ if (_fileIndex < _files.size()) {
+ // We are still in the current group.
+ inGroup = true;
+ return *_files[_fileIndex++];
+ }
+ // We are not in a group. Get a new file.
+ ErrorOr<File &> file = _context.getInputGraph().getNextFile();
+ if (std::error_code ec = file.getError()) {
+ if (ec != InputGraphError::no_more_files)
+ llvm::errs() << "Error occurred in getNextFile: " << ec.message() << "\n";
+ return ec;
+ }
+ _files.push_back(&*file);
+ ++_fileIndex;
+ inGroup = false;
+ return *file;
+}
+
// Keep adding atoms until _context.getNextFile() returns an error. This
// function is where undefined atoms are resolved.
bool Resolver::resolveUndefines() {
ScopedTask task(getDefaultDomain(), "resolveUndefines");
for (;;) {
- ErrorOr<File &> file = _context.getInputGraph().getNextFile();
- std::error_code ec = file.getError();
- if (ec == InputGraphError::no_more_files)
- return true;
- if (!file) {
- llvm::errs() << "Error occurred in getNextFile: " << ec.message() << "\n";
- return false;
- }
-
+ bool inGroup = false;
+ bool undefAdded = false;
+ ErrorOr<File &> file = nextFile(inGroup);
+ if (std::error_code ec = file.getError())
+ return ec == InputGraphError::no_more_files;
switch (file->kind()) {
case File::kindObject:
+ if (inGroup)
+ break;
assert(!file->hasOrdinal());
file->setOrdinal(_context.getNextOrdinalAndIncrement());
- handleFile(*file);
+ undefAdded = handleFile(*file);
break;
case File::kindArchiveLibrary:
if (!file->hasOrdinal())
file->setOrdinal(_context.getNextOrdinalAndIncrement());
- handleArchiveFile(*file);
+ undefAdded = handleArchiveFile(*file);
break;
case File::kindSharedLibrary:
if (!file->hasOrdinal())
@@ -265,6 +296,7 @@
handleSharedLibrary(*file);
break;
}
+ _newUndefinesAdded[&*file] = undefAdded;
}
}