[lld] r223330 - Rewrite InputGraph's Group

Rui Ueyama ruiu at google.com
Sun Dec 7 17:19:57 PST 2014


On Fri, Dec 5, 2014 at 9:13 AM, Shankar Easwaran <shankare at codeaurora.org>
wrote:

> Hi Rui,
>
> They key idea was to flatten the graph but also use tags to know about
> some control flags, that change linker operation(group begins / ends (or)
> what input files are part of as-needed).
>
> The LinkingContext would need to  know about what happens in the resolver
> per input element (that would contain a tag and a file locator).
>
> These two requirements are really needed for the linker Gnu flavor for its
> operation and the infrastructure needs to be scalable as well.
>

Yes, these are obvious needs. I have of course no intention to remove
--as-needed from the linker.

As you might have noticed, notifyProgress is not the only way that we can
use for the core linker to the LinkingContext. It, for example, doesn't
have to be real-time. Instead of telling the progress for each file, we
could accumulate that information and pass it to the next pass.

The breakage caused by the last commit was an accident -- it should have
caught by a test but it wasn't. I'm trying to fix it by self-hosting LLD on
Linux and Mac.

Shankar Easwaran
>
> On 12/4/2014 3:51 PM, Rui Ueyama wrote:
>
>> Shanker,
>>
>> I don't think this patch is that different from what you proposed. The key
>> idea is as I understand to flatten the Graph to make it easy to handle.
>> This patch is in aligned with that. This is an incremental patch towards
>> that direction.
>>
>> On Thu, Dec 4, 2014 at 10:54 AM, Shankar Easwaran <
>> shankare at codeaurora.org>
>> wrote:
>>
>>    Hi Rui,
>>>
>>> I try to build clang with lld by just taking the arguments directly from
>>> the usual clang build, without any change.
>>>
>>> You should be able to reproduce it locally, but anyways here are the
>>> arguments to build clang with lld with the Gnu flavor :-
>>>
>>> *lld -flavor gnu*  -z relro --hash-style=gnu --build-id --eh-frame-hdr -m
>>>
>>> elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o bin/clang-3.6
>>> /usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/../../../x86_64-
>>> linux-gnu/crt1.o
>>> /usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/../../../x86_64-
>>> linux-gnu/crti.o
>>> /usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/crtbegin.o
>>> -L/usr/bin/../lib/gcc/x86_64-linux-gnu/4.9
>>> -L/usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/../../../x86_64-linux-gnu
>>> -L/lib/x86_64-linux-gnu -L/lib/../lib64 -L/usr/lib/x86_64-linux-gnu
>>> -L/usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/../../..
>>> -L/usr/lib/llvm-3.5/bin/../lib -L/lib -L/usr/lib -allow-shlib-undefined
>>> --export-dynamic -O3
>>> tools/clang/tools/driver/CMakeFiles/clang.dir/driver.cpp.o
>>> tools/clang/tools/driver/CMakeFiles/clang.dir/cc1_main.cpp.o
>>> tools/clang/tools/driver/CMakeFiles/clang.dir/cc1as_main.cpp.o
>>> lib/libLLVMAArch64CodeGen.a lib/libLLVMAArch64AsmPrinter.a
>>> lib/libLLVMAArch64AsmParser.a lib/libLLVMAArch64Desc.a
>>> lib/libLLVMAArch64Info.a lib/libLLVMAArch64Disassembler.a
>>> lib/libLLVMARMCodeGen.a lib/libLLVMARMAsmPrinter.a
>>> lib/libLLVMARMAsmParser.a lib/libLLVMARMDesc.a lib/libLLVMARMInfo.a
>>> lib/libLLVMARMDisassembler.a lib/libLLVMCppBackendCodeGen.a
>>> lib/libLLVMCppBackendInfo.a lib/libLLVMHexagonCodeGen.a
>>> lib/libLLVMHexagonDesc.a lib/libLLVMHexagonInfo.a
>>> lib/libLLVMHexagonDisassembler.a lib/libLLVMMipsCodeGen.a
>>> lib/libLLVMMipsAsmPrinter.a lib/libLLVMMipsAsmParser.a
>>> lib/libLLVMMipsDesc.a lib/libLLVMMipsInfo.a lib/libLLVMMipsDisassembler.a
>>> lib/libLLVMMSP430CodeGen.a lib/libLLVMMSP430AsmPrinter.a
>>> lib/libLLVMMSP430Desc.a lib/libLLVMMSP430Info.a lib/libLLVMNVPTXCodeGen.a
>>> lib/libLLVMNVPTXAsmPrinter.a lib/libLLVMNVPTXDesc.a
>>> lib/libLLVMNVPTXInfo.a
>>> lib/libLLVMPowerPCCodeGen.a lib/libLLVMPowerPCAsmPrinter.a
>>> lib/libLLVMPowerPCAsmParser.a lib/libLLVMPowerPCDesc.a
>>> lib/libLLVMPowerPCInfo.a lib/libLLVMPowerPCDisassembler.a
>>> lib/libLLVMR600CodeGen.a lib/libLLVMR600AsmPrinter.a
>>> lib/libLLVMR600AsmParser.a lib/libLLVMR600Desc.a lib/libLLVMR600Info.a
>>> lib/libLLVMSparcCodeGen.a lib/libLLVMSparcAsmPrinter.a
>>> lib/libLLVMSparcAsmParser.a lib/libLLVMSparcDesc.a lib/libLLVMSparcInfo.a
>>> lib/libLLVMSparcDisassembler.a lib/libLLVMSystemZCodeGen.a
>>> lib/libLLVMSystemZAsmPrinter.a lib/libLLVMSystemZAsmParser.a
>>> lib/libLLVMSystemZDesc.a lib/libLLVMSystemZInfo.a
>>> lib/libLLVMSystemZDisassembler.a lib/libLLVMX86CodeGen.a
>>> lib/libLLVMX86AsmPrinter.a lib/libLLVMX86AsmParser.a lib/libLLVMX86Desc.a
>>> lib/libLLVMX86Info.a lib/libLLVMX86Disassembler.a
>>> lib/libLLVMXCoreCodeGen.a
>>> lib/libLLVMXCoreAsmPrinter.a lib/libLLVMXCoreDesc.a
>>> lib/libLLVMXCoreInfo.a
>>> lib/libLLVMXCoreDisassembler.a lib/libLLVMAnalysis.a lib/libLLVMCodeGen.a
>>> lib/libLLVMCore.a lib/libLLVMipa.a lib/libLLVMipo.a
>>> lib/libLLVMInstCombine.a lib/libLLVMInstrumentation.a lib/libLLVMMC.a
>>> lib/libLLVMMCParser.a lib/libLLVMObjCARCOpts.a lib/libLLVMOption.a
>>> lib/libLLVMScalarOpts.a lib/libLLVMSupport.a lib/libLLVMTransformUtils.a
>>> lib/libLLVMVectorize.a lib/libclangBasic.a lib/libclangDriver.a
>>> lib/libclangFrontend.a lib/libclangFrontendTool.a
>>> lib/libLLVMAArch64AsmPrinter.a lib/libLLVMAArch64Info.a
>>> lib/libLLVMAArch64Utils.a lib/libLLVMARMDesc.a lib/libLLVMARMAsmPrinter.a
>>> lib/libLLVMARMInfo.a lib/libLLVMHexagonDesc.a lib/libLLVMHexagonInfo.a
>>> lib/libLLVMMipsAsmPrinter.a lib/libLLVMMipsInfo.a
>>> lib/libLLVMMSP430AsmPrinter.a lib/libLLVMNVPTXAsmPrinter.a
>>> lib/libLLVMPowerPCAsmPrinter.a lib/libLLVMPowerPCInfo.a
>>> lib/libLLVMR600AsmPrinter.a lib/libLLVMSparcAsmPrinter.a
>>> lib/libLLVMSparcInfo.a lib/libLLVMSystemZDesc.a
>>> lib/libLLVMSystemZAsmPrinter.a lib/libLLVMSystemZInfo.a
>>> lib/libLLVMX86CodeGen.a lib/libLLVMX86Desc.a lib/libLLVMX86AsmPrinter.a
>>> lib/libLLVMX86Utils.a lib/libLLVMX86Info.a lib/libLLVMXCoreAsmPrinter.a
>>> lib/libLLVMAsmPrinter.a lib/libLLVMSelectionDAG.a lib/libLLVMCodeGen.a
>>> lib/libLLVMXCoreInfo.a lib/libLLVMMCDisassembler.a lib/libclangCodeGen.a
>>> lib/libLLVMipo.a lib/libLLVMVectorize.a lib/libLLVMInstrumentation.a
>>> lib/libLLVMObjCARCOpts.a lib/libLLVMScalarOpts.a lib/libLLVMInstCombine.a
>>> lib/libLLVMProfileData.a lib/libLLVMObject.a lib/libLLVMBitWriter.a
>>> lib/libLLVMIRReader.a lib/libLLVMAsmParser.a lib/libLLVMLinker.a
>>> lib/libLLVMTransformUtils.a lib/libLLVMipa.a lib/libLLVMAnalysis.a
>>> lib/libLLVMTarget.a lib/libclangRewriteFrontend.a
>>> lib/libclangARCMigrate.a
>>> lib/libclangStaticAnalyzerFrontend.a lib/libclangFrontend.a
>>> lib/libclangDriver.a lib/libLLVMOption.a lib/libclangParse.a
>>> lib/libLLVMMCParser.a lib/libclangSerialization.a lib/libclangSema.a
>>> lib/libclangEdit.a lib/libLLVMBitReader.a
>>> lib/libclangStaticAnalyzerCheckers.a lib/libclangStaticAnalyzerCore.a
>>> lib/libclangAnalysis.a lib/libclangAST.a lib/libclangRewrite.a
>>> lib/libclangLex.a lib/libclangBasic.a lib/libLLVMCore.a lib/libLLVMMC.a
>>> lib/libLLVMSupport.a -lrt -ldl -ltinfo -latomic -lpthread -lz -lm -rpath
>>> "\$ORIGIN/../lib" -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc
>>> /usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/crtend.o
>>> /usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/../../../x86_64-
>>> linux-gnu/crtn.o
>>>
>>> Shankar Easwaran
>>>
>>> On 12/4/2014 12:26 PM, Rui Ueyama wrote:
>>>
>>> Let me roll this back first.
>>>
>>> Jean-Deniel and Shankar, please send me code so that I can reproduce that
>>> issue locally (and I will add the tests).
>>>
>>> On Thu, Dec 4, 2014 at 9:34 AM, Shankar Easwaran <
>>> shankare at codeaurora.org> <shankare at codeaurora.org>
>>>
>>> wrote:
>>>
>>>
>>>    Hi Ruiu,
>>>
>>> Sorry I missed this review completely.
>>>
>>> We have taken a lot of effort to be able to build clang with lld, and
>>> this
>>> change prevents building clang with lld anymore as it fails with
>>> unresolved
>>> symbols.  Please revert this change.
>>>
>>> *There are two things missing for modeling the Gnu flavor with this model
>>> as part of this change as well when I reviewed :-*
>>>
>>> a) The ELF writer needs to dump the way the linker resolved with
>>> start-group/end-group information.
>>>
>>> b) This model is also difficult to model --as-needed, --no-as-needed. The
>>> shared libraries in the list need to be added, only if the shared
>>> libraries
>>> resolved any symbol.
>>> For the above, the resolver has to notify the LinkingContext about how
>>> symbols were resolved for this functionality.
>>>
>>> Finally I would think we thoroughly review the the proposal that
>>> myself/Bigcheese talked about in the developers conference.
>>>
>>> The linkingcontext will be completely responsible for managing the input
>>> graph, which will just be a vector of InputElements that contain a tag in
>>> addition to the FileLocator.
>>>
>>>
>>> http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-
>>> of-Mon-20141027/242287.html
>>>
>>> Shankar Easwaran
>>>
>>>
>>> On 12/3/2014 7:09 PM, Rui Ueyama wrote:
>>>
>>> Author: ruiu
>>> Date: Wed Dec  3 19:09:06 2014
>>> New Revision: 223330
>>>
>>> URL: http://llvm.org/viewvc/llvm-project?rev=223330&view=rev
>>> Log:
>>> Rewrite InputGraph's Group
>>>
>>> The aim of this patch is to reduce the excessive abstraction from
>>> the InputGraph. We found that even a simple thing, such as sorting
>>> input files (Mach-O) or adding a new file to the input file list
>>> (PE/COFF), is nearly impossible with the InputGraph abstraction,
>>> because it hides too much information behind it. As a result,
>>> we invented complex interactions between components (e.g.
>>> notifyProgress() mechanism) and tricky code to work around that
>>> limitation. There were many occasions that we needed to write
>>> awkward code.
>>>
>>> This patch is a first step to make it cleaner. As a first step,
>>> this removes Group class from the InputGraph. The grouping feature
>>> is now directly handled by the Resolver. notifyProgress is removed
>>> since we no longer need that. I could have cleaned it up even more,
>>> but in order to keep the patch minimum, I focused on Group.
>>>
>>> SimpleFileNode class, a container of File objects, is now limited
>>> to have only one File. We shold have done this earlier.
>>> We used to allow putting multiple File objects to FileNode.
>>> Although SimpleFileNode usually has only one file, the Driver class
>>> actually used that capability. I modified the Driver class a bit,
>>> so that one FileNode is created for each input File.
>>>
>>> We should now probably remove SimpleFileNode and directly store
>>> File objects to the InputGraph in some way, because a container
>>> that can contain only one object is useless. This is a TODO.
>>>
>>> Mach-O input files are now sorted before they are passe to the
>>> Resolver. DarwinInputGraph class is no longer needed, so removed.
>>>
>>> PECOFF still has hacky code to add a new file to the input file list.
>>> This will be cleaned up in another patch.
>>>
>>> Modified:
>>>      lld/trunk/include/lld/Core/InputGraph.h
>>>      lld/trunk/include/lld/Core/LinkingContext.h
>>>      lld/trunk/include/lld/Core/Resolver.h
>>>      lld/trunk/include/lld/Driver/DarwinInputGraph.h
>>>      lld/trunk/include/lld/Driver/WinLinkInputGraph.h
>>>      lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h
>>>      lld/trunk/include/lld/ReaderWriter/PECOFFLinkingContext.h
>>>      lld/trunk/lib/Core/InputGraph.cpp
>>>      lld/trunk/lib/Core/Resolver.cpp
>>>      lld/trunk/lib/Driver/DarwinInputGraph.cpp
>>>      lld/trunk/lib/Driver/DarwinLdDriver.cpp
>>>      lld/trunk/lib/Driver/Driver.cpp
>>>      lld/trunk/lib/Driver/GnuLdDriver.cpp
>>>      lld/trunk/lib/Driver/GnuLdInputGraph.cpp
>>>      lld/trunk/lib/Driver/WinLinkDriver.cpp
>>>      lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
>>>      lld/trunk/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp
>>>      lld/trunk/unittests/DriverTests/DriverTest.h
>>>      lld/trunk/unittests/DriverTests/InputGraphTest.cpp
>>>      lld/trunk/unittests/DriverTests/WinLinkDriverTest.cpp
>>>
>>> Modified: lld/trunk/include/lld/Core/InputGraph.h
>>> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/
>>> Core/InputGraph.h?rev=223330&r1=223329&r2=223330&view=diff
>>> ============================================================
>>> ==================
>>> --- lld/trunk/include/lld/Core/InputGraph.h (original)
>>> +++ lld/trunk/include/lld/Core/InputGraph.h Wed Dec  3 19:09:06 2014
>>> @@ -59,12 +59,6 @@ public:
>>>     /// assigned in the way files are resolved.
>>>     virtual ErrorOr<File &> getNextFile();
>>>
>>> -  /// Notifies the current input element of Resolver made some progress
>>> on
>>> -  /// resolving undefined symbols using the current file. Group
>>> (representing
>>> -  /// --start-group and --end-group) uses that notification to make a
>>> decision
>>> -  /// whether it should iterate over again or terminate or not.
>>> -  virtual void notifyProgress();
>>> -
>>>     /// Adds an observer of getNextFile(). Each time a new file is about
>>> to be
>>>     /// returned from getNextFile(), registered observers are called
>>> with the file
>>>     /// being returned.
>>> @@ -76,14 +70,18 @@ public:
>>>     /// \brief Adds a node at the beginning of the InputGraph
>>>     void addInputElementFront(std::unique_ptr<InputElement>);
>>>
>>> -  /// Normalize the InputGraph. It calls expand() on each node and then
>>> replace
>>> -  /// it with getReplacements() results.
>>> +  /// Normalize the InputGraph. It calls getReplacements() on each
>>> element.
>>>     void normalize();
>>>
>>> -  range<InputElementIterT> inputElements() {
>>> -    return make_range(_inputArgs.begin(), _inputArgs.end());
>>> +  InputElementVectorT &inputElements() {
>>> +    return _inputArgs;
>>>     }
>>>
>>> +  // Returns the current group size if we are at an --end-group.
>>> +  // Otherwise returns 0.
>>> +  int getGroupSize();
>>> +  void skipGroup();
>>> +
>>>     // \brief Returns the number of input files.
>>>     size_t size() const { return _inputArgs.size(); }
>>>
>>> @@ -108,8 +106,8 @@ class InputElement {
>>>   public:
>>>     /// Each input element in the graph can be a File or a control
>>>     enum class Kind : uint8_t {
>>> -    Group,      // Represents a type associated with Group
>>> -    File        // Represents a type associated with File Nodes
>>> +    File,       // Represents a type associated with File Nodes
>>> +    GroupEnd,
>>>     };
>>>
>>>     InputElement(Kind type) : _kind(type) {}
>>> @@ -129,16 +127,9 @@ public:
>>>     /// Get the next file to be processed by the resolver
>>>     virtual ErrorOr<File &> getNextFile() = 0;
>>>
>>> -  /// Refer InputGraph::notifyProgress(). By default, it does nothing.
>>> Only
>>> -  /// Group is interested in this message.
>>> -  virtual void notifyProgress() {};
>>> -
>>>     /// \brief Reset the next index
>>>     virtual void resetNextIndex() = 0;
>>>
>>> -  /// Returns true if we want to replace this node with children.
>>> -  virtual void expand() {}
>>> -
>>>     /// Get the elements that we want to expand with.
>>>     virtual bool getReplacements(InputGraph::InputElementVectorT &) {
>>>       return false;
>>> @@ -148,73 +139,31 @@ protected:
>>>     Kind _kind; // The type of the Element
>>>   };
>>>
>>> -/// \brief A Control node which contains a group of InputElements
>>> -/// This affects the resolver so that it resolves undefined symbols
>>> -/// in the group completely before looking at other input files that
>>> -/// follow the group
>>> -class Group : public InputElement {
>>> +// This is a marker for --end-group. getSize() returns the number of
>>> +// files between the corresponding --start-group and this marker.
>>> +class GroupEnd : public InputElement {
>>>   public:
>>> -  Group()
>>> -      : InputElement(InputElement::Kind::Group),
>>> _currentElementIndex(0),
>>> -        _nextElementIndex(0), _madeProgress(false) {}
>>> +  GroupEnd(int size) : InputElement(Kind::GroupEnd), _size(size) {}
>>>
>>> -  static inline bool classof(const InputElement *a) {
>>> -    return a->kind() == InputElement::Kind::Group;
>>> -  }
>>> -
>>> -  /// \brief Process input element and add it to the group
>>> -  bool addFile(std::unique_ptr<InputElement> element) {
>>> -    _elements.push_back(std::move(element));
>>> -    return true;
>>> -  }
>>> +  int getSize() const { return _size; }
>>>
>>> -  range<InputGraph::InputElementIterT> elements() {
>>> -    return make_range(_elements.begin(), _elements.end());
>>> -  }
>>> -
>>> -  void resetNextIndex() override {
>>> -    _madeProgress = false;
>>> -    _currentElementIndex = 0;
>>> -    _nextElementIndex = 0;
>>> -    for (std::unique_ptr<InputElement> &elem : _elements)
>>> -      elem->resetNextIndex();
>>> +  static inline bool classof(const InputElement *a) {
>>> +    return a->kind() == Kind::GroupEnd;
>>>     }
>>>
>>>     /// \brief Parse the group members.
>>>     std::error_code parse(const LinkingContext &ctx, raw_ostream &diag)
>>> override {
>>> -    for (std::unique_ptr<InputElement> &ei : _elements)
>>> -      if (std::error_code ec = ei->parse(ctx, diag))
>>> -        return ec;
>>>       return std::error_code();
>>>     }
>>>
>>> -  /// If Resolver made a progress using the current file, it's ok to
>>> revisit
>>> -  /// files in this group in future.
>>> -  void notifyProgress() override {
>>> -    for (std::unique_ptr<InputElement> &elem : _elements)
>>> -      elem->notifyProgress();
>>> -    _madeProgress = true;
>>> -  }
>>> -
>>> -  ErrorOr<File &> getNextFile() override;
>>> -
>>> -  void expand() override {
>>> -    for (std::unique_ptr<InputElement> &elt : _elements)
>>> -      elt->expand();
>>> -    std::vector<std::unique_ptr<InputElement>> result;
>>> -    for (std::unique_ptr<InputElement> &elt : _elements) {
>>> -      if (elt->getReplacements(result))
>>> -        continue;
>>> -      result.push_back(std::move(elt));
>>> -    }
>>> -    _elements.swap(result);
>>> +  ErrorOr<File &> getNextFile() override {
>>> +    llvm_unreachable("shouldn't be here.");
>>>     }
>>>
>>> -protected:
>>> -  InputGraph::InputElementVectorT _elements;
>>> -  uint32_t _currentElementIndex;
>>> -  uint32_t _nextElementIndex;
>>> -  bool _madeProgress;
>>> +  void resetNextIndex() override {}
>>> +
>>> +private:
>>> +  int _size;
>>>   };
>>>
>>>   /// \brief Represents an Input file in the graph
>>> @@ -252,6 +201,8 @@ public:
>>>
>>>     /// \brief add a file to the list of files
>>>     virtual void addFiles(InputGraph::FileVectorT files) {
>>> +    assert(files.size() == 1);
>>> +    assert(_files.empty());
>>>       for (std::unique_ptr<File> &ai : files)
>>>         _files.push_back(std::move(ai));
>>>     }
>>> @@ -260,6 +211,8 @@ public:
>>>     /// the node again.
>>>     void resetNextIndex() override { _nextFileIndex = 0; }
>>>
>>> +  bool getReplacements(InputGraph::InputElementVectorT &result)
>>> override;
>>> +
>>>   protected:
>>>     /// \brief Read the file into _buffer.
>>>     std::error_code getBuffer(StringRef filePath);
>>> @@ -276,6 +229,10 @@ protected:
>>>   class SimpleFileNode : public FileNode {
>>>   public:
>>>     SimpleFileNode(StringRef path) : FileNode(path) {}
>>> +  SimpleFileNode(StringRef path, std::unique_ptr<File> f)
>>> +      : FileNode(path) {
>>> +    _files.push_back(std::move(f));
>>> +  }
>>>
>>>     virtual ~SimpleFileNode() {}
>>>
>>>
>>> Modified: lld/trunk/include/lld/Core/LinkingContext.h
>>> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/
>>> Core/LinkingContext.h?rev=223330&r1=223329&r2=223330&view=diff
>>> ============================================================
>>> ==================
>>> --- lld/trunk/include/lld/Core/LinkingContext.h (original)
>>> +++ lld/trunk/include/lld/Core/LinkingContext.h Wed Dec  3 19:09:06 2014
>>> @@ -322,6 +322,10 @@ public:
>>>     bool runRoundTripPass() const { return _runRoundTripPasses; }
>>>   #endif
>>>
>>> +  // This function is called just before the Resolver kicks in.
>>> +  // Derived classes may use that chance to rearrange the input files.
>>> +  virtual void maybeSortInputFiles() {}
>>> +
>>>     /// @}
>>>   protected:
>>>     LinkingContext(); // Must be subclassed
>>>
>>> Modified: lld/trunk/include/lld/Core/Resolver.h
>>> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/
>>> Core/Resolver.h?rev=223330&r1=223329&r2=223330&view=diff
>>> ============================================================
>>> ==================
>>> --- lld/trunk/include/lld/Core/Resolver.h (original)
>>> +++ lld/trunk/include/lld/Core/Resolver.h Wed Dec  3 19:09:06 2014
>>> @@ -28,7 +28,8 @@ class LinkingContext;
>>>   class Resolver {
>>>   public:
>>>     Resolver(LinkingContext &context)
>>> -      : _context(context), _symbolTable(context), _result(new
>>> MergedFile()) {}
>>> +      : _context(context), _symbolTable(context), _result(new
>>> MergedFile()),
>>> +        _fileIndex(0) {}
>>>
>>>     // InputFiles::Handler methods
>>>     void doDefinedAtom(const DefinedAtom&);
>>> @@ -38,10 +39,10 @@ public:
>>>
>>>     // Handle files, this adds atoms from the current file thats
>>>     // being processed by the resolver
>>> -  void handleFile(const File &);
>>> +  bool handleFile(const File &);
>>>
>>>     // Handle an archive library file.
>>> -  void handleArchiveFile(const File &);
>>> +  bool handleArchiveFile(const File &);
>>>
>>>     // Handle a shared library file.
>>>     void handleSharedLibrary(const File &);
>>> @@ -54,6 +55,9 @@ public:
>>>   private:
>>>     typedef std::function<void(StringRef, bool)> UndefCallback;
>>>
>>> +  bool undefinesAdded(int count);
>>> +  ErrorOr<File &> nextFile(bool &inGroup);
>>> +
>>>     /// \brief Add section group/.gnu.linkonce if it does not exist
>>> previously.
>>>     void maybeAddSectionGroupOrGnuLinkOnce(const DefinedAtom &atom);
>>>
>>> @@ -110,6 +114,11 @@ private:
>>>     llvm::DenseSet<const Atom *>  _deadAtoms;
>>>     std::unique_ptr<MergedFile>   _result;
>>>     llvm::DenseMap<const Atom *, llvm::DenseSet<const Atom *>>
>>> _reverseRef;
>>> +
>>> +  // --start-group and --end-group
>>> +  std::vector<File *> _files;
>>> +  std::map<File *, bool> _newUndefinesAdded;
>>> +  size_t _fileIndex;
>>>   };
>>>
>>>   } // namespace lld
>>>
>>> Modified: lld/trunk/include/lld/Driver/DarwinInputGraph.h
>>> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/
>>> Driver/DarwinInputGraph.h?rev=223330&r1=223329&r2=223330&view=diff
>>> ============================================================
>>> ==================
>>> --- lld/trunk/include/lld/Driver/DarwinInputGraph.h (original)
>>> +++ lld/trunk/include/lld/Driver/DarwinInputGraph.h Wed Dec  3 19:09:06
>>> 2014
>>> @@ -23,18 +23,6 @@
>>>
>>>   namespace lld {
>>>
>>> -
>>> -class DarwinInputGraph : public InputGraph {
>>> -public:
>>> -  DarwinInputGraph() : _librariesPhase(false), _repeatLibraries(false)
>>> { }
>>> -  ErrorOr<File &> getNextFile() override;
>>> -  void notifyProgress() override;
>>> -private:
>>> -  bool _librariesPhase;
>>> -  bool _repeatLibraries;
>>> -};
>>> -
>>> -
>>>   /// \brief Represents a MachO File
>>>   class MachOFileNode : public FileNode {
>>>   public:
>>>
>>> Modified: lld/trunk/include/lld/Driver/WinLinkInputGraph.h
>>> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/
>>> Driver/WinLinkInputGraph.h?rev=223330&r1=223329&r2=223330&view=diff
>>> ============================================================
>>> ==================
>>> --- lld/trunk/include/lld/Driver/WinLinkInputGraph.h (original)
>>> +++ lld/trunk/include/lld/Driver/WinLinkInputGraph.h Wed Dec  3
>>> 19:09:06 2014
>>> @@ -55,21 +55,6 @@ public:
>>>     ErrorOr<StringRef> getPath(const LinkingContext &ctx) const override;
>>>   };
>>>
>>> -/// \brief Represents a ELF control node
>>> -class PECOFFGroup : public Group {
>>> -public:
>>> -  PECOFFGroup(PECOFFLinkingContext &ctx) : Group(), _ctx(ctx) {}
>>> -
>>> -  /// \brief Parse the group members.
>>> -  std::error_code parse(const LinkingContext &ctx, raw_ostream &diag)
>>> override {
>>> -    std::lock_guard<std::recursive_mutex> lock(_ctx.getMutex());
>>> -    return Group::parse(ctx, diag);
>>> -  }
>>> -
>>> -private:
>>> -  PECOFFLinkingContext &_ctx;
>>> -};
>>> -
>>>   } // namespace lld
>>>
>>>   #endif
>>>
>>> Modified: lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h
>>> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/
>>> ReaderWriter/MachOLinkingContext.h?rev=223330&r1=223329&r2=223330&
>>> view=diff
>>> ============================================================
>>> ==================
>>> --- lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h (original)
>>> +++ lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h Wed Dec  3
>>> 19:09:06 2014
>>> @@ -283,6 +283,8 @@ public:
>>>     /// bits are xxxx.yy.zz.  Largest number is 65535.255.255
>>>     static bool parsePackedVersion(StringRef str, uint32_t &result);
>>>
>>> +  void maybeSortInputFiles() override;
>>> +
>>>   private:
>>>     Writer &writer() const override;
>>>     mach_o::MachODylibFile* loadIndirectDylib(StringRef path);
>>>
>>> Modified: lld/trunk/include/lld/ReaderWriter/PECOFFLinkingContext.h
>>> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/
>>> ReaderWriter/PECOFFLinkingContext.h?rev=223330&r1=223329&r2=223330&
>>> view=diff
>>> ============================================================
>>> ==================
>>> --- lld/trunk/include/lld/ReaderWriter/PECOFFLinkingContext.h (original)
>>> +++ lld/trunk/include/lld/ReaderWriter/PECOFFLinkingContext.h Wed Dec
>>> 3 19:09:06 2014
>>> @@ -29,7 +29,6 @@ using llvm::COFF::WindowsSubsystem;
>>>   static const uint8_t DEFAULT_DOS_STUB[128] = {'M', 'Z'};
>>>
>>>   namespace lld {
>>> -class Group;
>>>
>>>   class PECOFFLinkingContext : public LinkingContext {
>>>   public:
>>> @@ -315,8 +314,7 @@ public:
>>>     void setEntryNode(SimpleFileNode *node) { _entryNode = node; }
>>>     SimpleFileNode *getEntryNode() const { return _entryNode; }
>>>
>>> -  void setLibraryGroup(Group *group) { _libraryGroup = group; }
>>> -  Group *getLibraryGroup() const { return _libraryGroup; }
>>> +  void addLibraryFile(std::unique_ptr<FileNode> file);
>>>
>>>     void setModuleDefinitionFile(const std::string val) {
>>>       _moduleDefinitionFile = val;
>>> @@ -438,9 +436,6 @@ private:
>>>     // The node containing the entry point file.
>>>     SimpleFileNode *_entryNode;
>>>
>>> -  // The PECOFFGroup that contains all the .lib files.
>>> -  Group *_libraryGroup;
>>> -
>>>     // Name of the temporary file for lib.exe subcommand. For debugging
>>>     // only.
>>>     std::string _moduleDefinitionFile;
>>>
>>> Modified: lld/trunk/lib/Core/InputGraph.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Core/
>>> InputGraph.cpp?rev=223330&r1=223329&r2=223330&view=diff
>>> ============================================================
>>> ==================
>>> --- lld/trunk/lib/Core/InputGraph.cpp (original)
>>> +++ lld/trunk/lib/Core/InputGraph.cpp Wed Dec  3 19:09:06 2014
>>> @@ -36,8 +36,6 @@ ErrorOr<File &> InputGraph::getNextFile(
>>>     }
>>>   }
>>>
>>> -void InputGraph::notifyProgress() { _currentInputElement->notifyProgress();
>>> }
>>> -
>>>   void InputGraph::registerObserver(std::function<void(File *)> fn) {
>>>     _observers.push_back(fn);
>>>   }
>>> @@ -61,12 +59,13 @@ bool InputGraph::dump(raw_ostream &diagn
>>>   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 @@ void InputGraph::normalize() {
>>>     _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 @@ std::error_code FileNode::getBuffer(Stri
>>>     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;
>>>   }
>>>
>>> Modified: lld/trunk/lib/Core/Resolver.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Core/
>>> Resolver.cpp?rev=223330&r1=223329&r2=223330&view=diff
>>> ============================================================
>>> ==================
>>> --- lld/trunk/lib/Core/Resolver.cpp (original)
>>> +++ lld/trunk/lib/Core/Resolver.cpp Wed Dec  3 19:09:06 2014
>>> @@ -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 @@ void Resolver::handleFile(const File &fi
>>>       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 @@ void Resolver::forEachUndefines(bool sea
>>>     } 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 = undefAdded || handleFile(*member);
>>>       }
>>>     });
>>> +  return undefAdded;
>>>   }
>>>
>>>   void Resolver::handleSharedLibrary(const File &file) {
>>> @@ -233,31 +229,66 @@ void Resolver::addAtoms(const std::vecto
>>>       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 @@ bool Resolver::resolveUndefines() {
>>>         handleSharedLibrary(*file);
>>>         break;
>>>       }
>>> +    _newUndefinesAdded[&*file] = undefAdded;
>>>     }
>>>   }
>>>
>>>
>>> Modified: lld/trunk/lib/Driver/DarwinInputGraph.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/
>>> DarwinInputGraph.cpp?rev=223330&r1=223329&r2=223330&view=diff
>>> ============================================================
>>> ==================
>>> --- lld/trunk/lib/Driver/DarwinInputGraph.cpp (original)
>>> +++ lld/trunk/lib/Driver/DarwinInputGraph.cpp Wed Dec  3 19:09:06 2014
>>> @@ -18,48 +18,6 @@
>>>   namespace lld {
>>>
>>>
>>> -ErrorOr<File &> DarwinInputGraph::getNextFile() {
>>> -  // The darwin linker processes input files in two phases.  The first
>>> phase
>>> -  // links in all object (.o) files in command line order. The second
>>> phase
>>> -  // links in libraries in command line order. If there are still
>>> UndefinedAtoms
>>> -  // the second phase is repeated until notifyProgress() is not called
>>> by
>>> -  // resolver.
>>> -  for (;;) {
>>> -    if (_currentInputElement) {
>>> -      for(;;) {
>>> -        ErrorOr<File &> next = _currentInputElement->getNextFile();
>>> -        if (next.getError())
>>> -          break;
>>> -        File *file = &next.get();
>>> -        bool fileIsLibrary = isa<SharedLibraryFile>(file) ||
>>> -                             isa<ArchiveLibraryFile>(file);
>>> -        if (fileIsLibrary == _librariesPhase) {
>>> -          // Return library in library phase and object files in
>>> non-lib mode.
>>> -          return *file;
>>> -        }
>>> -      }
>>> -    }
>>> -
>>> -    if (_nextElementIndex >= _inputArgs.size()) {
>>> -      // If no more elements, done unless we need to repeat library
>>> scan.
>>> -      if (_librariesPhase && !_repeatLibraries)
>>> -        return make_error_code(InputGraphError::no_more_files);
>>> -      // Clear iterations and only look for libraries.
>>> -      _librariesPhase = true;
>>> -      _repeatLibraries = false;
>>> -      _nextElementIndex = 0;
>>> -      for (auto &ie : _inputArgs) {
>>> -        ie->resetNextIndex();
>>> -      }
>>> -    }
>>> -    _currentInputElement = _inputArgs[_nextElementIndex++].get();
>>> -  }
>>> -}
>>> -
>>> -void DarwinInputGraph::notifyProgress() {
>>> -  _repeatLibraries = true;
>>> -}
>>> -
>>>   /// \brief Parse the input file to lld::File.
>>>   std::error_code MachOFileNode::parse(const LinkingContext &ctx,
>>>                                        raw_ostream &diagnostics)  {
>>>
>>> Modified: lld/trunk/lib/Driver/DarwinLdDriver.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/
>>> DarwinLdDriver.cpp?rev=223330&r1=223329&r2=223330&view=diff
>>> ============================================================
>>> ==================
>>> --- lld/trunk/lib/Driver/DarwinLdDriver.cpp (original)
>>> +++ lld/trunk/lib/Driver/DarwinLdDriver.cpp Wed Dec  3 19:09:06 2014
>>> @@ -83,7 +83,7 @@ static std::string canonicalizePath(Stri
>>>     }
>>>   }
>>>
>>> -static void addFile(StringRef path, std::unique_ptr<DarwinInputGraph>
>>> &inputGraph,
>>> +static void addFile(StringRef path, std::unique_ptr<InputGraph>
>>> &inputGraph,
>>>                       MachOLinkingContext &ctx, bool loadWholeArchive,
>>>                       bool upwardDylib) {
>>>     auto node = llvm::make_unique<MachOFileNode>(path, ctx);
>>> @@ -185,7 +185,7 @@ static std::error_code parseOrderFile(St
>>>   // per line. The <dir> prefix is prepended to each partial path.
>>>   //
>>>   static std::error_code parseFileList(StringRef fileListPath,
>>> -                                     std::unique_ptr<DarwinInputGraph>
>>> &inputGraph,
>>> +                                     std::unique_ptr<InputGraph>
>>> &inputGraph,
>>>                                        MachOLinkingContext &ctx, bool
>>> forceLoad,
>>>                                        raw_ostream &diagnostics) {
>>>     // If there is a comma, split off <dir>.
>>> @@ -521,7 +521,7 @@ bool DarwinLdDriver::parse(int argc, con
>>>       }
>>>     }
>>>
>>> -  std::unique_ptr<DarwinInputGraph> inputGraph(new DarwinInputGraph());
>>> +  std::unique_ptr<InputGraph> inputGraph(new InputGraph());
>>>
>>>     // Now construct the set of library search directories, following
>>> ld64's
>>>     // baroque set of accumulated hacks. Mostly, the algorithm constructs
>>>
>>> Modified: lld/trunk/lib/Driver/Driver.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/
>>> Driver.cpp?rev=223330&r1=223329&r2=223330&view=diff
>>> ============================================================
>>> ==================
>>> --- lld/trunk/lib/Driver/Driver.cpp (original)
>>> +++ lld/trunk/lib/Driver/Driver.cpp Wed Dec  3 19:09:06 2014
>>> @@ -62,9 +62,6 @@ bool Driver::link(LinkingContext &contex
>>>         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;
>>> @@ -83,21 +80,24 @@ bool Driver::link(LinkingContext &contex
>>>     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));
>>> +  for (auto i = internalFiles.rbegin(), e = internalFiles.rend(); i !=
>>> e; ++i) {
>>> +    context.getInputGraph().addInputElementFront(
>>> +        llvm::make_unique<SimpleFileNode>("internal", std::move(*i)));
>>> +  }
>>>
>>>     // 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));
>>> +  for (auto i = implicitFiles.rbegin(), e = implicitFiles.rend(); i !=
>>> e; ++i) {
>>> +    context.getInputGraph().addInputElementFront(
>>> +        llvm::make_unique<SimpleFileNode>("implicit", std::move(*i)));
>>> +  }
>>> +
>>> +  // Give target a chance to sort the input files.
>>> +  // Mach-O uses this chance to move all object files before library
>>> files.
>>> +  context.maybeSortInputFiles();
>>>
>>>     // Do core linking.
>>>     ScopedTask resolveTask(getDefaultDomain(), "Resolve");
>>>
>>> Modified: lld/trunk/lib/Driver/GnuLdDriver.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/
>>> GnuLdDriver.cpp?rev=223330&r1=223329&r2=223330&view=diff
>>> ============================================================
>>> ==================
>>> --- lld/trunk/lib/Driver/GnuLdDriver.cpp (original)
>>> +++ lld/trunk/lib/Driver/GnuLdDriver.cpp Wed Dec  3 19:09:06 2014
>>> @@ -295,7 +295,8 @@ bool GnuLdDriver::parse(int argc, const
>>>     }
>>>
>>>     std::unique_ptr<InputGraph> inputGraph(new InputGraph());
>>> -  std::stack<Group *> groupStack;
>>> +  std::stack<int> groupStack;
>>> +  int numfiles = 0;
>>>
>>>     ELFFileNode::Attributes attributes;
>>>
>>> @@ -468,16 +469,21 @@ bool GnuLdDriver::parse(int argc, const
>>>         break;
>>>       }
>>>
>>> -    case OPT_start_group: {
>>> -      std::unique_ptr<Group> group(new Group());
>>> -      groupStack.push(group.get());
>>> -      inputGraph->addInputElement(std::move(group));
>>> +    case OPT_start_group:
>>> +      groupStack.push(numfiles);
>>>         break;
>>> -    }
>>>
>>> -    case OPT_end_group:
>>> +    case OPT_end_group: {
>>> +      if (groupStack.empty()) {
>>> +        diagnostics << "stray --end-group\n";
>>> +        return false;
>>> +      }
>>> +      int startGroupPos = groupStack.top();
>>> +      inputGraph->addInputElement(
>>> +          llvm::make_unique<GroupEnd>(numfiles - startGroupPos));
>>>         groupStack.pop();
>>>         break;
>>> +    }
>>>
>>>       case OPT_z: {
>>>         StringRef extOpt = inputArg->getValue();
>>> @@ -552,11 +558,8 @@ bool GnuLdDriver::parse(int argc, const
>>>           }
>>>         }
>>>         std::unique_ptr<InputElement> inputFile(inputNode);
>>> -      if (groupStack.empty()) {
>>> -        inputGraph->addInputElement(std::move(inputFile));
>>> -      } else {
>>> -        groupStack.top()->addFile(std::move(inputFile));
>>> -      }
>>> +      ++numfiles;
>>> +      inputGraph->addInputElement(std::move(inputFile));
>>>         break;
>>>       }
>>>
>>>
>>> Modified: lld/trunk/lib/Driver/GnuLdInputGraph.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/
>>> GnuLdInputGraph.cpp?rev=223330&r1=223329&r2=223330&view=diff
>>> ============================================================
>>> ==================
>>> --- lld/trunk/lib/Driver/GnuLdInputGraph.cpp (original)
>>> +++ lld/trunk/lib/Driver/GnuLdInputGraph.cpp Wed Dec  3 19:09:06 2014
>>> @@ -91,7 +91,7 @@ std::error_code ELFGNULdScript::parse(co
>>>       auto *group = dyn_cast<script::Group>(c);
>>>       if (!group)
>>>         continue;
>>> -    std::unique_ptr<Group> groupStart(new Group());
>>> +    size_t numfiles = 0;
>>>       for (const script::Path &path : group->getPaths()) {
>>>         // TODO : Propagate Set WholeArchive/dashlPrefix
>>>         attributes.setAsNeeded(path._asNeeded);
>>> @@ -100,9 +100,10 @@ std::error_code ELFGNULdScript::parse(co
>>>             _elfLinkingContext, _elfLinkingContext.
>>> allocateString(path._path),
>>>             attributes);
>>>         std::unique_ptr<InputElement> inputFile(inputNode);
>>> -      groupStart.get()->addFile(std::move(inputFile));
>>> +      _expandElements.push_back(std::move(inputFile));
>>> +      ++numfiles;
>>>       }
>>> -    _expandElements.push_back(std::move(groupStart));
>>> +    _expandElements.push_back(llvm::make_unique<GroupEnd>(numfiles));
>>>     }
>>>     return std::error_code();
>>>   }
>>>
>>> Modified: lld/trunk/lib/Driver/WinLinkDriver.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/
>>> WinLinkDriver.cpp?rev=223330&r1=223329&r2=223330&view=diff
>>> ============================================================
>>> ==================
>>> --- lld/trunk/lib/Driver/WinLinkDriver.cpp (original)
>>> +++ lld/trunk/lib/Driver/WinLinkDriver.cpp Wed Dec  3 19:09:06 2014
>>> @@ -781,7 +781,7 @@ static bool hasLibrary(const PECOFFLinki
>>>     ErrorOr<StringRef> path = fileNode->getPath(ctx);
>>>     if (!path)
>>>       return false;
>>> -  for (std::unique_ptr<InputElement> &p : ctx.getLibraryGroup()->
>>> elements())
>>> +  for (std::unique_ptr<InputElement> &p : ctx.getInputGraph().
>>> inputElements())
>>>       if (auto *f = dyn_cast<FileNode>(p.get()))
>>>         if (*path == *f->getPath(ctx))
>>>           return true;
>>> @@ -1397,10 +1397,8 @@ bool WinLinkDriver::parse(int argc, cons
>>>       ctx.setEntryNode(entry.get());
>>>       ctx.getInputGraph().addInputElement(std::move(entry));
>>>
>>> -    // The container for all library files.
>>> -    std::unique_ptr<Group> group(new PECOFFGroup(ctx));
>>> -    ctx.setLibraryGroup(group.get());
>>> -    ctx.getInputGraph().addInputElement(std::move(group));
>>> +    // Add a group-end marker.
>>> +    ctx.getInputGraph().addInputElement(llvm::make_
>>> unique<GroupEnd>(0));
>>>     }
>>>
>>>     // Add the library files to the library group.
>>> @@ -1409,7 +1407,7 @@ bool WinLinkDriver::parse(int argc, cons
>>>         if (isReadingDirectiveSection)
>>>           if (lib->parse(ctx, diag))
>>>             return false;
>>> -      ctx.getLibraryGroup()->addFile(std::move(lib));
>>> +      ctx.addLibraryFile(std::move(lib));
>>>       }
>>>     }
>>>
>>>
>>> Modified: lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/
>>> ReaderWriter/MachO/MachOLinkingContext.cpp?rev=
>>> 223330&r1=223329&r2=223330&view=diff
>>> ============================================================
>>> ==================
>>> --- lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp (original)
>>> +++ lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp Wed Dec  3
>>> 19:09:06 2014
>>> @@ -22,6 +22,7 @@
>>>   #include "llvm/ADT/Triple.h"
>>>   #include "llvm/Config/config.h"
>>>   #include "llvm/Support/Errc.h"
>>> +#include "llvm/Support/Debug.h"
>>>   #include "llvm/Support/Host.h"
>>>   #include "llvm/Support/MachO.h"
>>>   #include "llvm/Support/Path.h"
>>> @@ -923,4 +924,35 @@ bool MachOLinkingContext::customAtomOrde
>>>     return true;
>>>   }
>>>
>>> +static File *getFirstFile(const std::unique_ptr<InputElement> &elem) {
>>> +  FileNode *e = dyn_cast<FileNode>(const_cast<InputElement
>>> *>(elem.get()));
>>> +  if (!e || e->files().empty())
>>> +    return nullptr;
>>> +  return e->files()[0].get();
>>> +}
>>> +
>>> +static bool isLibrary(const std::unique_ptr<InputElement> &elem) {
>>> +  File *f = getFirstFile(elem);
>>> +  return f && (isa<SharedLibraryFile>(f) || isa<ArchiveLibraryFile>(f));
>>> +}
>>> +
>>> +// The darwin linker processes input files in two phases.  The first
>>> phase
>>> +// links in all object (.o) files in command line order. The second
>>> phase
>>> +// links in libraries in command line order.
>>> +// In this function we reorder the input files so that all the object
>>> files
>>> +// comes before any library file. We also make a group for the library
>>> files
>>> +// so that the Resolver will reiterate over the libraries as long as we
>>> find
>>> +// new undefines from libraries.
>>> +void MachOLinkingContext::maybeSortInputFiles() {
>>> +  std::vector<std::unique_ptr<InputElement>> &elements
>>> +      = getInputGraph().inputElements();
>>> +  std::stable_sort(elements.begin(), elements.end(),
>>> +                   [](const std::unique_ptr<InputElement> &a,
>>> +                      const std::unique_ptr<InputElement> &b) {
>>> +                     return !isLibrary(a) && isLibrary(b);
>>> +                   });
>>> +  size_t numLibs = std::count_if(elements.begin(), elements.end(),
>>> isLibrary);
>>> +  elements.push_back(llvm::make_unique<GroupEnd>(numLibs));
>>> +}
>>> +
>>>   } // end namespace lld
>>>
>>> Modified: lld/trunk/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/
>>> ReaderWriter/PECOFF/PECOFFLinkingContext.cpp?rev=
>>> 223330&r1=223329&r2=223330&view=diff
>>> ============================================================
>>> ==================
>>> --- lld/trunk/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp
>>> (original)
>>> +++ lld/trunk/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp Wed Dec
>>> 3 19:09:06 2014
>>> @@ -87,6 +87,23 @@ std::unique_ptr<File> PECOFFLinkingConte
>>>         "<command line option /include>");
>>>   }
>>>
>>> +void PECOFFLinkingContext::addLibraryFile(std::unique_ptr<FileNode>
>>> file) {
>>> +  GroupEnd *currentGroupEnd;
>>> +  int pos = -1;
>>> +  std::vector<std::unique_ptr<InputElement>> &elements
>>> +      = getInputGraph().inputElements();
>>> +  for (int i = 0, e = elements.size(); i < e; ++i) {
>>> +    if ((currentGroupEnd = dyn_cast<GroupEnd>(elements[i].get()))) {
>>> +      pos = i;
>>> +      break;
>>> +    }
>>> +  }
>>> +  assert(pos >= 0);
>>> +  elements.insert(elements.begin() + pos, std::move(file));
>>> +  elements[pos + 1] = llvm::make_unique<GroupEnd>(
>>> +      currentGroupEnd->getSize() + 1);
>>> +}
>>> +
>>>   bool PECOFFLinkingContext::createImplicitFiles(
>>>       std::vector<std::unique_ptr<File>> &) {
>>>     // Create a file for __ImageBase.
>>> @@ -109,7 +126,7 @@ bool PECOFFLinkingContext::createImplici
>>>     auto exportNode = llvm::make_unique<SimpleFileNode>("<export>");
>>>     exportNode->appendInputFile(
>>>         llvm::make_unique<pecoff::ExportedSymbolRenameFile>(*this,
>>> syms));
>>> -  getLibraryGroup()->addFile(std::move(exportNode));
>>> +  addLibraryFile(std::move(exportNode));
>>>
>>>     // Create a file for the entry point function.
>>>     getEntryNode()->appendInputFile(
>>>
>>> Modified: lld/trunk/unittests/DriverTests/DriverTest.h
>>> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/unittests/
>>> DriverTests/DriverTest.h?rev=223330&r1=223329&r2=223330&view=diff
>>> ============================================================
>>> ==================
>>> --- lld/trunk/unittests/DriverTests/DriverTest.h (original)
>>> +++ lld/trunk/unittests/DriverTests/DriverTest.h Wed Dec  3 19:09:06
>>> 2014
>>> @@ -37,18 +37,6 @@ protected:
>>>       llvm_unreachable("not handling other types of input files");
>>>     }
>>>
>>> -  // Convenience method for getting i'th input files name.
>>> -  std::string inputFile(int index1, int index2) {
>>> -    Group *group = dyn_cast<Group>(
>>> -        linkingContext()->getInputGraph().inputElements(
>>> )[index1].get());
>>> -    if (!group)
>>> -      llvm_unreachable("not handling other types of input files");
>>> -    FileNode *file = dyn_cast<FileNode>(group->
>>> elements()[index2].get());
>>> -    if (!file)
>>> -      llvm_unreachable("not handling other types of input files");
>>> -    return *file->getPath(*linkingContext());
>>> -  }
>>> -
>>>     // For unit tests to call driver with various command lines.
>>>     bool parse(const char *args, ...) {
>>>       // Construct command line options from varargs.
>>>
>>> Modified: lld/trunk/unittests/DriverTests/InputGraphTest.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/unittests/
>>> DriverTests/InputGraphTest.cpp?rev=223330&r1=223329&r2=223330&view=diff
>>> ============================================================
>>> ==================
>>> --- lld/trunk/unittests/DriverTests/InputGraphTest.cpp (original)
>>> +++ lld/trunk/unittests/DriverTests/InputGraphTest.cpp Wed Dec  3
>>> 19:09:06 2014
>>> @@ -77,7 +77,7 @@ protected:
>>>
>>>   } // end anonymous namespace
>>>
>>> -static std::unique_ptr<TestFileNode> createFile1(StringRef name) {
>>> +static std::unique_ptr<TestFileNode> createFile(StringRef name) {
>>>     std::vector<std::unique_ptr<File>> files;
>>>     files.push_back(std::unique_ptr<SimpleFile>(new SimpleFile(name)));
>>>     std::unique_ptr<TestFileNode> file(new TestFileNode("filenode"));
>>> @@ -85,109 +85,30 @@ static std::unique_ptr<TestFileNode> cre
>>>     return file;
>>>   }
>>>
>>> -static std::unique_ptr<TestFileNode> createFile2(StringRef name1,
>>> -                                                 StringRef name2) {
>>> -  std::vector<std::unique_ptr<File>> files;
>>> -  files.push_back(std::unique_ptr<SimpleFile>(new SimpleFile(name1)));
>>> -  files.push_back(std::unique_ptr<SimpleFile>(new SimpleFile(name2)));
>>> -  std::unique_ptr<TestFileNode> file(new TestFileNode("filenode"));
>>> -  file->addFiles(std::move(files));
>>> -  return file;
>>> -}
>>> -
>>>   TEST_F(InputGraphTest, Empty) {
>>>     expectEnd();
>>>   }
>>>
>>>   TEST_F(InputGraphTest, File) {
>>> -  _graph->addInputElement(createFile1("file1"));
>>> -  EXPECT_EQ("file1", getNext());
>>> -  expectEnd();
>>> -}
>>> -
>>> -TEST_F(InputGraphTest, Files) {
>>> -  _graph->addInputElement(createFile2("file1", "file2"));
>>> -  EXPECT_EQ("file1", getNext());
>>> -  EXPECT_EQ("file2", getNext());
>>> -  expectEnd();
>>> -}
>>> -
>>> -TEST_F(InputGraphTest, Group) {
>>> -  _graph->addInputElement(createFile2("file1", "file2"));
>>> -
>>> -  std::unique_ptr<Group> group(new Group());
>>> -  group->addFile(createFile2("file3", "file4"));
>>> -  group->addFile(createFile1("file5"));
>>> -  group->addFile(createFile1("file6"));
>>> -  _graph->addInputElement(std::move(group));
>>> -
>>> +  _graph->addInputElement(createFile("file1"));
>>>     EXPECT_EQ("file1", getNext());
>>> -  EXPECT_EQ("file2", getNext());
>>> -  EXPECT_EQ("file3", getNext());
>>> -  EXPECT_EQ("file4", getNext());
>>> -  EXPECT_EQ("file5", getNext());
>>> -  EXPECT_EQ("file6", getNext());
>>> -  expectEnd();
>>> -}
>>> -
>>> -// Iterate through the group
>>> -TEST_F(InputGraphTest, GroupIteration) {
>>> -  _graph->addInputElement(createFile2("file1", "file2"));
>>> -
>>> -  std::unique_ptr<Group> group(new Group());
>>> -  group->addFile(createFile2("file3", "file4"));
>>> -  group->addFile(createFile1("file5"));
>>> -  group->addFile(createFile1("file6"));
>>> -  _graph->addInputElement(std::move(group));
>>> -
>>> -  EXPECT_EQ("file1", getNext());
>>> -  EXPECT_EQ("file2", getNext());
>>> -
>>> -  EXPECT_EQ("file3", getNext());
>>> -  EXPECT_EQ("file4", getNext());
>>> -  EXPECT_EQ("file5", getNext());
>>> -  EXPECT_EQ("file6", getNext());
>>> -  _graph->notifyProgress();
>>> -
>>> -  EXPECT_EQ("file3", getNext());
>>> -  EXPECT_EQ("file4", getNext());
>>> -  _graph->notifyProgress();
>>> -  EXPECT_EQ("file5", getNext());
>>> -  EXPECT_EQ("file6", getNext());
>>> -
>>> -  EXPECT_EQ("file3", getNext());
>>> -  EXPECT_EQ("file4", getNext());
>>> -  EXPECT_EQ("file5", getNext());
>>> -  EXPECT_EQ("file6", getNext());
>>>     expectEnd();
>>>   }
>>>
>>>   // Node expansion tests
>>>   TEST_F(InputGraphTest, Normalize) {
>>> -  _graph->addInputElement(createFile2("file1", "file2"));
>>> +  _graph->addInputElement(createFile("file1"));
>>>
>>>     std::unique_ptr<TestExpandFileNode> expandFile(
>>>         new TestExpandFileNode("node"));
>>> -  expandFile->addElement(createFile1("file3"));
>>> -  expandFile->addElement(createFile1("file4"));
>>> +  expandFile->addElement(createFile("file2"));
>>> +  expandFile->addElement(createFile("file3"));
>>>     _graph->addInputElement(std::move(expandFile));
>>> -
>>> -  std::unique_ptr<Group> group(new Group());
>>> -  std::unique_ptr<TestExpandFileNode> expandFile2(
>>> -      new TestExpandFileNode("node"));
>>> -  expandFile2->addElement(createFile1("file5"));
>>> -  group->addFile(std::move(expandFile2));
>>> -  _graph->addInputElement(std::move(group));
>>> -
>>> -  _graph->addInputElement(createFile1("file6"));
>>>     _graph->normalize();
>>>
>>>     EXPECT_EQ("file1", getNext());
>>>     EXPECT_EQ("file2", getNext());
>>>     EXPECT_EQ("file3", getNext());
>>> -  EXPECT_EQ("file4", getNext());
>>> -  EXPECT_EQ("file5", getNext());
>>> -  EXPECT_EQ("file6", getNext());
>>>     expectEnd();
>>>   }
>>>
>>> @@ -195,8 +116,8 @@ TEST_F(InputGraphTest, Observer) {
>>>     std::vector<std::string> files;
>>>     _graph->registerObserver([&](File *file) {
>>> files.push_back(file->path()); });
>>>
>>> -  _graph->addInputElement(createFile1("file1"));
>>> -  _graph->addInputElement(createFile1("file2"));
>>> +  _graph->addInputElement(createFile("file1"));
>>> +  _graph->addInputElement(createFile("file2"));
>>>     EXPECT_EQ("file1", getNext());
>>>     EXPECT_EQ("file2", getNext());
>>>     expectEnd();
>>>
>>> Modified: lld/trunk/unittests/DriverTests/WinLinkDriverTest.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/unittests/
>>> DriverTests/WinLinkDriverTest.cpp?rev=223330&r1=223329&r2=
>>> 223330&view=diff
>>> ============================================================
>>> ==================
>>> --- lld/trunk/unittests/DriverTests/WinLinkDriverTest.cpp (original)
>>> +++ lld/trunk/unittests/DriverTests/WinLinkDriverTest.cpp Wed Dec  3
>>> 19:09:06 2014
>>> @@ -137,11 +137,11 @@ TEST_F(WinLinkParserTest, Libpath) {
>>>   TEST_F(WinLinkParserTest, InputOrder) {
>>>     EXPECT_TRUE(parse("link.exe", "a.lib", "b.obj", "c.obj", "a.lib",
>>> "d.obj",
>>>                       nullptr));
>>> -  EXPECT_EQ(5, inputFileCount());
>>> +  EXPECT_EQ(6, inputFileCount());
>>>     EXPECT_EQ("b.obj", inputFile(0));
>>>     EXPECT_EQ("c.obj", inputFile(1));
>>>     EXPECT_EQ("d.obj", inputFile(2));
>>> -  EXPECT_EQ("a.lib", inputFile(4, 0));
>>> +  EXPECT_EQ("a.lib", inputFile(4));
>>>   }
>>>
>>>   //
>>> @@ -393,36 +393,36 @@ TEST_F(WinLinkParserTest, SectionMultipl
>>>   TEST_F(WinLinkParserTest, DefaultLib) {
>>>     EXPECT_TRUE(parse("link.exe", "/defaultlib:user32.lib",
>>>                       "/defaultlib:kernel32", "a.obj", nullptr));
>>> -  EXPECT_EQ(3, inputFileCount());
>>> +  EXPECT_EQ(5, inputFileCount());
>>>     EXPECT_EQ("a.obj", inputFile(0));
>>> -  EXPECT_EQ("user32.lib", inputFile(2, 0));
>>> -  EXPECT_EQ("kernel32.lib", inputFile(2, 1));
>>> +  EXPECT_EQ("user32.lib", inputFile(2));
>>> +  EXPECT_EQ("kernel32.lib", inputFile(3));
>>>   }
>>>
>>>   TEST_F(WinLinkParserTest, DefaultLibDuplicates) {
>>>     EXPECT_TRUE(parse("link.exe", "/defaultlib:user32.lib",
>>>                       "/defaultlib:user32.lib", "a.obj", nullptr));
>>> -  EXPECT_EQ(3, inputFileCount());
>>> +  EXPECT_EQ(4, inputFileCount());
>>>     EXPECT_EQ("a.obj", inputFile(0));
>>> -  EXPECT_EQ("user32.lib", inputFile(2, 0));
>>> +  EXPECT_EQ("user32.lib", inputFile(2));
>>>   }
>>>
>>>   TEST_F(WinLinkParserTest, NoDefaultLib) {
>>>     EXPECT_TRUE(parse("link.exe", "/defaultlib:user32.lib",
>>>                       "/defaultlib:kernel32",
>>> "/nodefaultlib:user32.lib", "a.obj",
>>>                       nullptr));
>>> -  EXPECT_EQ(3, inputFileCount());
>>> +  EXPECT_EQ(4, inputFileCount());
>>>     EXPECT_EQ("a.obj", inputFile(0));
>>> -  EXPECT_EQ("kernel32.lib", inputFile(2, 0));
>>> +  EXPECT_EQ("kernel32.lib", inputFile(2));
>>>   }
>>>
>>>   TEST_F(WinLinkParserTest, NoDefaultLibCase) {
>>>     EXPECT_TRUE(parse("link.exe", "/defaultlib:user32",
>>>                       "/defaultlib:kernel32",
>>> "/nodefaultlib:USER32.LIB", "a.obj",
>>>                       nullptr));
>>> -  EXPECT_EQ(3, inputFileCount());
>>> +  EXPECT_EQ(4, inputFileCount());
>>>     EXPECT_EQ("a.obj", inputFile(0));
>>> -  EXPECT_EQ("kernel32.lib", inputFile(2, 0));
>>> +  EXPECT_EQ("kernel32.lib", inputFile(2));
>>>   }
>>>
>>>   TEST_F(WinLinkParserTest, NoDefaultLibAll) {
>>> @@ -436,9 +436,9 @@ TEST_F(WinLinkParserTest, DisallowLib) {
>>>     EXPECT_TRUE(parse("link.exe", "/defaultlib:user32.lib",
>>>                       "/defaultlib:kernel32", "/disallowlib:user32.lib",
>>> "a.obj",
>>>                       nullptr));
>>> -  EXPECT_EQ(3, inputFileCount());
>>> +  EXPECT_EQ(4, inputFileCount());
>>>     EXPECT_EQ("a.obj", inputFile(0));
>>> -  EXPECT_EQ("kernel32.lib", inputFile(2, 0));
>>> +  EXPECT_EQ("kernel32.lib", inputFile(2));
>>>   }
>>>
>>>   //
>>>
>>>
>>> ______________________________
>>> _________________
>>> llvm-commits mailing listllvm-commits at cs.uiuc.eduhttp://
>>> lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>>>
>>>
>>>
>>> --
>>> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
>>> hosted by the Linux Foundation
>>>
>>>
>>>
>>>
>>>
>>> --
>>> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
>>> hosted by the Linux Foundation
>>>
>>>
>>>
>
> --
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted
> by the Linux Foundation
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20141208/82352d95/attachment.html>


More information about the llvm-commits mailing list