Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -560,6 +560,8 @@ LLVM allows an explicit section to be specified for globals. If the target supports it, it will emit globals to the section specified. +Additionally, the global can placed in a comdat if the target has the necessary +support. By default, global initializers are optimized by assuming that global variables defined within the module are not modified from their @@ -590,7 +592,8 @@ [@ =] [Linkage] [Visibility] [DLLStorageClass] [ThreadLocal] [unnamed_addr] [AddrSpace] [ExternallyInitialized] - [, section "name"] [, align ] + [, section "name"] [, comdat $] + [, align ] For example, the following defines a global in a numbered address space with an initializer, section, and alignment: @@ -625,8 +628,9 @@ :ref:`parameter attribute ` for the return type, a function name, a (possibly empty) argument list (each with optional :ref:`parameter attributes `), optional :ref:`function attributes `, -an optional section, an optional alignment, an optional :ref:`garbage -collector name `, an optional :ref:`prefix `, an opening +an optional section, an optional alignment, +an optional :ref:`comdat `, +an optional :ref:`garbage collector name `, an optional :ref:`prefix `, an opening curly brace, a list of basic blocks, and a closing curly brace. LLVM function declarations consist of the "``declare``" keyword, an @@ -656,6 +660,8 @@ LLVM allows an explicit section to be specified for functions. If the target supports it, it will emit functions to the section specified. +Additionally, the function can placed in a comdat if the target has the +necessary support. An explicit alignment may be specified for a function. If not present, or if the alignment is set to zero, the alignment of the function is set @@ -671,8 +677,8 @@ define [linkage] [visibility] [DLLStorageClass] [cconv] [ret attrs] @ ([argument list]) - [unnamed_addr] [fn Attrs] [section "name"] [align N] - [gc] [prefix Constant] { ... } + [unnamed_addr] [fn Attrs] [section "name"] [comdat $] + [align N] [gc] [prefix Constant] { ... } .. _langref_aliases: @@ -714,6 +720,55 @@ * No global value in the expression can be a declaration, since that would require a relocation, which is not possible. +.. _langref_comdats: + +Comdats +------- + +Comdat IR provides access to COFF and ELF object file COMDAT functionality. + +Comdats have a name which represents the COMDAT key. All global objects which +specify this key will only end up in the final object file if the linker chooses that key over some other key. + +Comdats provide a selection kind to provide input on how the linker should +choose between keys in two different object files. + +Syntax:: + + $ = comdat SelectionKind + +The selection kind must be one of the following: + +``any`` + The linker may choose any COMDAT key, the choice is arbitrary. +``exactmatch`` + The linker may choose any COMDAT key but the sections must contain the + same data. +``largest`` + The linker will choose the section containing the largest COMDAT key. +``newest`` + The linker will choose the section containing the newest COMDAT key. +``noduplicates`` + The linker requires that only section with this COMDAT key exist. +``samesize`` + The linker may choose any COMDAT key but the sections must contain the + same amount of data. + +Note that not all targets support COMDATs and some may only support ``any`` as a +selection kind. + +Here is an example of a COMDAT group where a function will only be selected if +the COMDAT key's section is the largest: + +.. code-block:: llvm + + $foo = comdat largest + @foo = global i32 2, comdat $foo + + define void @bar() comdat $foo { + ret void + } + .. _namedmetadatastructure: Named Metadata Index: include/llvm-c/Core.h =================================================================== --- include/llvm-c/Core.h +++ include/llvm-c/Core.h @@ -266,7 +266,8 @@ LLVMPointerTypeKind, /**< Pointers */ LLVMVectorTypeKind, /**< SIMD 'packed' format, or other vector type */ LLVMMetadataTypeKind, /**< Metadata */ - LLVMX86_MMXTypeKind /**< X86 MMX */ + LLVMX86_MMXTypeKind, /**< X86 MMX */ + LLVMComdatTypeKind, /**< COMDATs */ } LLVMTypeKind; typedef enum { @@ -1733,6 +1734,8 @@ void LLVMSetLinkage(LLVMValueRef Global, LLVMLinkage Linkage); const char *LLVMGetSection(LLVMValueRef Global); void LLVMSetSection(LLVMValueRef Global, const char *Section); +LLVMValueRef LLVMGetComdat(LLVMValueRef Global); +void LLVMSetComdat(LLVMValueRef Global, LLVMValueRef ComdatRef); LLVMVisibility LLVMGetVisibility(LLVMValueRef Global); void LLVMSetVisibility(LLVMValueRef Global, LLVMVisibility Viz); LLVMDLLStorageClass LLVMGetDLLStorageClass(LLVMValueRef Global); Index: include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- include/llvm/Bitcode/LLVMBitCodes.h +++ include/llvm/Bitcode/LLVMBitCodes.h @@ -71,7 +71,8 @@ // MODULE_CODE_PURGEVALS: [numvals] MODULE_CODE_PURGEVALS = 10, - MODULE_CODE_GCNAME = 11 // GCNAME: [strchr x N] + MODULE_CODE_GCNAME = 11, // GCNAME: [strchr x N] + MODULE_CODE_COMDAT = 12 // COMDAT: [selection_kind, name] }; /// PARAMATTR blocks have code for defining a parameter attribute set. @@ -120,7 +121,8 @@ TYPE_CODE_STRUCT_NAME = 19, // STRUCT_NAME: [strchr x N] TYPE_CODE_STRUCT_NAMED = 20,// STRUCT_NAMED: [ispacked, eltty x N] - TYPE_CODE_FUNCTION = 21 // FUNCTION: [vararg, retty, paramty x N] + TYPE_CODE_FUNCTION = 21, // FUNCTION: [vararg, retty, paramty x N] + TYPE_CODE_COMDAT = 22, // COMDAT: [selection_kind, name] }; // The type symbol table only has one code (TST_ENTRY_CODE). @@ -376,6 +378,15 @@ ATTR_KIND_JUMP_TABLE = 40 }; + enum ComdatSelectionKindCodes { + COMDAT_SELECTION_KIND_ANY = 1, + COMDAT_SELECTION_KIND_EXACT_MATCH = 2, + COMDAT_SELECTION_KIND_LARGEST = 3, + COMDAT_SELECTION_KIND_NEWEST = 4, + COMDAT_SELECTION_KIND_NO_DUPLICATES = 5, + COMDAT_SELECTION_KIND_SAME_SIZE = 6, + }; + } // End bitc namespace } // End llvm namespace Index: include/llvm/IR/Comdat.h =================================================================== --- /dev/null +++ include/llvm/IR/Comdat.h @@ -0,0 +1,84 @@ +//===-- llvm/IR/Comdat.h - Comdat definitions -------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// @file +/// This file contains the declaration of the Comdat class, which represents a +/// single COMDAT in LLVM. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_IR_COMDAT_H +#define LLVM_IR_COMDAT_H + +#include "llvm/ADT/ilist_node.h" +#include "llvm/ADT/Twine.h" +#include "llvm/ADT/VariadicFunction.h" +#include "llvm/IR/LeakDetector.h" +#include "llvm/IR/Value.h" + +namespace llvm { +class LLVMContext; +class Module; +template +class SymbolTableListTraits; +class Twine; + +class Comdat : public Value, public ilist_node { +public: + enum SelectionKind : uint8_t { + Any, + ExactMatch, + Largest, + Newest, + NoDuplicates, + SameSize, + }; + + /// \brief Destroy Comdat. + ~Comdat(); + + /// \brief Get the module that holds this section. + Module *getParent() { return Parent; } + const Module *getParent() const { return Parent; } + + /// Methods for support type inquiry through isa, cast, and dyn_cast: + static inline bool classof(const Value *V) { + return V->getValueID() == Value::ComdatVal; + } + + Comdat(SelectionKind SK, const Twine &Name, Comdat *InsertBefore); + Comdat(SelectionKind SK, const Twine &Name, Module *M); + + SelectionKind getSelectionKind() const { return SK; } + void setSelectionKind(SelectionKind NewSK) { SK = NewSK; } + +private: + friend class SymbolTableListTraits; + Comdat(const Comdat &) LLVM_DELETED_FUNCTION; + + void setParent(Module *M) { + if (getParent()) + LeakDetector::addGarbageObject(this); + Parent = M; + if (getParent()) + LeakDetector::removeGarbageObject(this); + } + + // Shadow Value::setValueSubclassData with a private forwarding method so that + // subclasses cannot accidentally use it. + void setValueSubclassData(unsigned short D) { + Value::setValueSubclassData(D); + } + + Module *Parent; + SelectionKind SK; +}; +} // end llvm namespace + +#endif Index: include/llvm/IR/Function.h =================================================================== --- include/llvm/IR/Function.h +++ include/llvm/IR/Function.h @@ -23,7 +23,9 @@ #include "llvm/IR/Attributes.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/CallingConv.h" +#include "llvm/IR/Comdat.h" #include "llvm/IR/GlobalObject.h" +#include "llvm/IR/OperandTraits.h" #include "llvm/Support/Compiler.h" namespace llvm { @@ -125,13 +127,21 @@ const Twine &N = "", Module *M = nullptr); public: + // allocate space for one operand + void *operator new(size_t s) { + return User::operator new(s, 1); + } + static Function *Create(FunctionType *Ty, LinkageTypes Linkage, const Twine &N = "", Module *M = nullptr) { - return new(0) Function(Ty, Linkage, N, M); + return new Function(Ty, Linkage, N, M); } ~Function(); + /// Provide fast operand accessors + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Comdat); + Type *getReturnType() const; // Return the type of the ret val FunctionType *getFunctionType() const; // Return the FunctionType for me @@ -513,6 +523,11 @@ return F ? &F->getValueSymbolTable() : nullptr; } +template <> +struct OperandTraits : public OptionalOperandTraits {}; + +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(Function, Comdat) + } // End llvm namespace #endif Index: include/llvm/IR/GlobalAlias.h =================================================================== --- include/llvm/IR/GlobalAlias.h +++ include/llvm/IR/GlobalAlias.h @@ -37,9 +37,13 @@ const Twine &Name, Constant *Aliasee, Module *Parent); public: - // allocate space for exactly one operand + // allocate space for exactly two operands void *operator new(size_t s) { - return User::operator new(s, 1); + return User::operator new(s, 2); + } + + ~GlobalAlias() { + NumOperands = 2; // FIXME: needed by operator delete } /// If a parent module is specified, the alias is automatically inserted into @@ -66,7 +70,7 @@ static GlobalAlias *create(const Twine &Name, GlobalValue *Aliasee); /// Provide fast operand accessors - DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Constant); + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); /// removeFromParent - This method unlinks 'this' from the containing module, /// but does not delete it. @@ -84,7 +88,7 @@ return const_cast(this)->getAliasee(); } Constant *getAliasee() { - return getOperand(0); + return cast(getOperand(0)); } static bool isValidLinkage(LinkageTypes L) { @@ -100,10 +104,10 @@ template <> struct OperandTraits : - public FixedNumOperandTraits { + public OptionalOperandTraits { }; -DEFINE_TRANSPARENT_OPERAND_ACCESSORS(GlobalAlias, Constant) +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(GlobalAlias, Value) } // End llvm namespace Index: include/llvm/IR/GlobalValue.h =================================================================== --- include/llvm/IR/GlobalValue.h +++ include/llvm/IR/GlobalValue.h @@ -23,6 +23,7 @@ namespace llvm { +class Comdat; class PointerType; class Module; @@ -110,6 +111,10 @@ bool hasUnnamedAddr() const { return UnnamedAddr; } void setUnnamedAddr(bool Val) { UnnamedAddr = Val; } + bool hasComdat() const { return getComdat() != nullptr; } + const Comdat *getComdat() const; + void setComdat(Comdat *C); + VisibilityTypes getVisibility() const { return VisibilityTypes(Visibility); } bool hasDefaultVisibility() const { return Visibility == DefaultVisibility; } bool hasHiddenVisibility() const { return Visibility == HiddenVisibility; } Index: include/llvm/IR/GlobalVariable.h =================================================================== --- include/llvm/IR/GlobalVariable.h +++ include/llvm/IR/GlobalVariable.h @@ -47,9 +47,9 @@ // initializers are run? public: - // allocate space for exactly one operand + // allocate space for exactly two operands void *operator new(size_t s) { - return User::operator new(s, 1); + return User::operator new(s, 2); } /// GlobalVariable ctor - If a parent module is specified, the global is @@ -67,7 +67,7 @@ bool isExternallyInitialized = false); ~GlobalVariable() { - NumOperands = 1; // FIXME: needed by operator delete + NumOperands = 2; // FIXME: needed by operator delete } /// Provide fast operand accessors @@ -177,7 +177,7 @@ template <> struct OperandTraits : - public OptionalOperandTraits { + public OptionalOperandTraits { }; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(GlobalVariable, Value) Index: include/llvm/IR/Module.h =================================================================== --- include/llvm/IR/Module.h +++ include/llvm/IR/Module.h @@ -16,6 +16,7 @@ #define LLVM_IR_MODULE_H #include "llvm/ADT/iterator_range.h" +#include "llvm/IR/Comdat.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalAlias.h" @@ -82,6 +83,23 @@ mutable ilist_node Sentinel; }; +template <> +struct ilist_traits : public SymbolTableListTraits { + // createSentinel is used to get hold of a node that marks the end of the + // list. + Comdat *createSentinel() const { return static_cast(&Sentinel); } + static void destroySentinel(Comdat *) {} + + Comdat *provideInitialHead() const { return createSentinel(); } + Comdat *ensureHead(Comdat *) const { return createSentinel(); } + static void noteHead(Comdat *, Comdat *) {} + + static ValueSymbolTable *getSymTab(Module *Par); + +private: + mutable ilist_node Sentinel; +}; + template<> struct ilist_traits : public ilist_default_traits { // createSentinel is used to get hold of a node that marks the end of @@ -121,6 +139,8 @@ typedef iplist FunctionListType; /// The type for the list of aliases. typedef iplist AliasListType; + /// The type for the list of COMDATs. + typedef iplist ComdatListType; /// The type for the list of named metadata. typedef ilist NamedMDListType; @@ -139,6 +159,11 @@ /// The Global Alias constant iterator typedef AliasListType::const_iterator const_alias_iterator; + /// The COMDAT iterators. + typedef ComdatListType::iterator comdat_iterator; + /// The COMDAT constant iterator + typedef ComdatListType::const_iterator const_comdat_iterator; + /// The named metadata iterators. typedef NamedMDListType::iterator named_metadata_iterator; /// The named metadata constant interators. @@ -194,9 +219,11 @@ GlobalListType GlobalList; ///< The Global Variables in the module FunctionListType FunctionList; ///< The Functions in the module AliasListType AliasList; ///< The Aliases in the module + ComdatListType ComdatList; ///< The COMDATs in the module NamedMDListType NamedMDList; ///< The named metadata in the module std::string GlobalScopeAsm; ///< Inline Asm at global scope. ValueSymbolTable *ValSymTab; ///< Symbol table for values + ValueSymbolTable *ComdatSymTab; ///< Symbol table for COMDATs std::unique_ptr Materializer; ///< Used to materialize GlobalValues std::string ModuleID; ///< Human readable identifier for the module @@ -397,6 +424,15 @@ void eraseNamedMetadata(NamedMDNode *NMD); /// @} +/// @name Comdat Accessors +/// @{ + + /// Return the Comdat in the module with the specified name. This method + /// returns a new Comdat if a Comdat with the specified name is not + /// found. + Comdat *getOrInsertComdat(StringRef Name, Comdat::SelectionKind SK); + +/// @} /// @name Module Flags Accessors /// @{ @@ -486,6 +522,13 @@ static iplist Module::*getSublistAccess(GlobalAlias*) { return &Module::AliasList; } + /// Get the Module's list of COMDATs (constant). + const ComdatListType &getComdatList() const { return ComdatList; } + /// Get the Module's list of COMDATs. + ComdatListType &getComdatList() { return ComdatList; } + static iplist Module::*getSublistAccess(Comdat *) { + return &Module::ComdatList; + } /// Get the Module's list of named metadata (constant). const NamedMDListType &getNamedMDList() const { return NamedMDList; } /// Get the Module's list of named metadata. @@ -497,6 +540,10 @@ const ValueSymbolTable &getValueSymbolTable() const { return *ValSymTab; } /// Get the Module's symbol table of global variable and function identifiers. ValueSymbolTable &getValueSymbolTable() { return *ValSymTab; } + /// Get the Module's symbol table for COMDATs (constant). + const ValueSymbolTable &getComdatSymbolTable() const { return *ComdatSymTab; } + /// Get the Module's symbol table for COMDATs. + ValueSymbolTable &getComdatSymbolTable() { return *ComdatSymTab; } /// @} /// @name Global Variable Iteration @@ -545,6 +592,24 @@ } /// @} +/// @name Comdat Iteration +/// @{ + + comdat_iterator comdat_begin() { return ComdatList.begin(); } + const_comdat_iterator comdat_begin() const { return ComdatList.begin(); } + comdat_iterator comdat_end () { return ComdatList.end(); } + const_comdat_iterator comdat_end () const { return ComdatList.end(); } + size_t comdat_size () const { return ComdatList.size(); } + bool comdat_empty() const { return ComdatList.empty(); } + + iterator_range comdats() { + return iterator_range(comdat_begin(), comdat_end()); + } + iterator_range comdats() const { + return iterator_range(comdat_begin(), comdat_end()); + } + +/// @} /// @name Named Metadata Iteration /// @{ Index: include/llvm/IR/Type.h =================================================================== --- include/llvm/IR/Type.h +++ include/llvm/IR/Type.h @@ -71,7 +71,8 @@ StructTyID, ///< 12: Structures ArrayTyID, ///< 13: Arrays PointerTyID, ///< 14: Pointers - VectorTyID ///< 15: SIMD 'packed' format, or other vector type + VectorTyID, ///< 15: SIMD 'packed' format, or other vector type + ComdatTyID, ///< 16: COMDATs }; private: @@ -188,6 +189,9 @@ /// isMetadataTy - Return true if this is 'metadata'. bool isMetadataTy() const { return getTypeID() == MetadataTyID; } + /// \brief Return true if this is 'comdat'. + bool isComdatTy() const { return getTypeID() == ComdatTyID; } + /// isIntegerTy - True if this is an instance of IntegerType. /// bool isIntegerTy() const { return getTypeID() == IntegerTyID; } @@ -382,6 +386,7 @@ static Type *getFloatTy(LLVMContext &C); static Type *getDoubleTy(LLVMContext &C); static Type *getMetadataTy(LLVMContext &C); + static Type *getComdatTy(LLVMContext &C); static Type *getX86_FP80Ty(LLVMContext &C); static Type *getFP128Ty(LLVMContext &C); static Type *getPPC_FP128Ty(LLVMContext &C); Index: include/llvm/IR/Value.h =================================================================== --- include/llvm/IR/Value.h +++ include/llvm/IR/Value.h @@ -324,6 +324,7 @@ ConstantPointerNullVal, // This is an instance of ConstantPointerNull MDNodeVal, // This is an instance of MDNode MDStringVal, // This is an instance of MDString + ComdatVal, // This is an instance of Comdat InlineAsmVal, // This is an instance of InlineAsm InstructionVal, // This is an instance of Instruction // Enum values starting at InstructionVal are used for Instructions; Index: include/llvm/IR/ValueSymbolTable.h =================================================================== --- include/llvm/IR/ValueSymbolTable.h +++ include/llvm/IR/ValueSymbolTable.h @@ -22,6 +22,7 @@ template class SymbolTableListTraits; class BasicBlock; + class Comdat; class Function; class NamedMDNode; class Module; @@ -36,6 +37,7 @@ friend class SymbolTableListTraits; friend class SymbolTableListTraits; friend class SymbolTableListTraits; + friend class SymbolTableListTraits; friend class SymbolTableListTraits; friend class SymbolTableListTraits; friend class SymbolTableListTraits; Index: lib/AsmParser/LLLexer.h =================================================================== --- lib/AsmParser/LLLexer.h +++ lib/AsmParser/LLLexer.h @@ -81,6 +81,7 @@ lltok::Kind LexDigitOrNegative(); lltok::Kind LexPositive(); lltok::Kind LexAt(); + lltok::Kind LexDollar(); lltok::Kind LexExclaim(); lltok::Kind LexPercent(); lltok::Kind LexQuote(); Index: lib/AsmParser/LLLexer.cpp =================================================================== --- lib/AsmParser/LLLexer.cpp +++ lib/AsmParser/LLLexer.cpp @@ -209,6 +209,7 @@ return LexToken(); case '+': return LexPositive(); case '@': return LexAt(); + case '$': return LexDollar(); case '%': return LexPercent(); case '"': return LexQuote(); case '.': @@ -222,13 +223,6 @@ return lltok::dotdotdot; } return lltok::Error; - case '$': - if (const char *Ptr = isLabelTail(CurPtr)) { - CurPtr = Ptr; - StrVal.assign(TokStart, CurPtr-1); - return lltok::LabelStr; - } - return lltok::Error; case ';': SkipLineComment(); return LexToken(); @@ -307,6 +301,43 @@ return lltok::Error; } +lltok::Kind LLLexer::LexDollar() { + if (const char *Ptr = isLabelTail(TokStart)) { + CurPtr = Ptr; + StrVal.assign(TokStart, CurPtr - 1); + return lltok::LabelStr; + } + + // Handle DollarStringConstant: $\"[^\"]*\" + if (CurPtr[0] == '"') { + ++CurPtr; + + while (1) { + int CurChar = getNextChar(); + + if (CurChar == EOF) { + Error("end of file in COMDAT variable name"); + return lltok::Error; + } + if (CurChar == '"') { + StrVal.assign(TokStart + 2, CurPtr - 1); + UnEscapeLexed(StrVal); + if (StringRef(StrVal).find_first_of(0) != StringRef::npos) { + Error("Null bytes are not allowed in names"); + return lltok::Error; + } + return lltok::ComdatVar; + } + } + } + + // Handle ComdatVarName: $[-a-zA-Z$._][-a-zA-Z$._0-9]* + if (ReadVarName()) + return lltok::ComdatVar; + + return lltok::Error; +} + /// ReadString - Read a string until the closing quote. lltok::Kind LLLexer::ReadString(lltok::Kind kind) { const char *Start = CurPtr; @@ -618,6 +649,16 @@ KEYWORD(type); KEYWORD(opaque); + KEYWORD(comdat); + + // Comdat types + KEYWORD(any); + KEYWORD(exactmatch); + KEYWORD(largest); + KEYWORD(newest); + KEYWORD(noduplicates); + KEYWORD(samesize); + KEYWORD(eq); KEYWORD(ne); KEYWORD(slt); KEYWORD(sgt); KEYWORD(sle); KEYWORD(sge); KEYWORD(ult); KEYWORD(ugt); KEYWORD(ule); KEYWORD(uge); KEYWORD(oeq); KEYWORD(one); KEYWORD(olt); KEYWORD(ogt); KEYWORD(ole); Index: lib/AsmParser/LLParser.h =================================================================== --- lib/AsmParser/LLParser.h +++ lib/AsmParser/LLParser.h @@ -34,6 +34,7 @@ class Instruction; class Constant; class GlobalValue; + class Comdat; class MDString; class MDNode; class StructType; @@ -46,6 +47,7 @@ enum { t_LocalID, t_GlobalID, // ID in UIntVal. t_LocalName, t_GlobalName, // Name in StrVal. + t_ComdatName, // Name in StrVal. t_APSInt, t_APFloat, // Value in APSIntVal/APFloatVal. t_Null, t_Undef, t_Zero, // No value. t_EmptyArray, // No value: [] @@ -122,6 +124,9 @@ std::map > ForwardRefValIDs; std::vector NumberedVals; + // Comdat reference information. + std::map> ForwardRefComdats; + // References to blockaddress. The key is the function ValID, the value is // a list of references to blocks in that function. std::map > > @@ -154,6 +159,10 @@ GlobalValue *GetGlobalVal(const std::string &N, Type *Ty, LocTy Loc); GlobalValue *GetGlobalVal(unsigned ID, Type *Ty, LocTy Loc); + /// GetComdatVal - Get a Comdat with the specified name, creating a forward + /// reference record if needed. + Comdat *GetComdat(const std::string &N, LocTy Loc); + // Helper Routines. bool ParseToken(lltok::Kind T, const char *ErrMsg); bool EatIfPresent(lltok::Kind T) { @@ -247,6 +256,7 @@ bool ParseAlias(const std::string &Name, LocTy Loc, unsigned Visibility, unsigned DLLStorageClass, GlobalVariable::ThreadLocalMode TLM, bool UnnamedAddr); + bool ParseComdat(); bool ParseStandaloneMetadata(); bool ParseNamedMetadata(); bool ParseMDString(MDString *&Result); @@ -358,6 +368,7 @@ bool ParseGlobalValue(Type *Ty, Constant *&V); bool ParseGlobalTypeAndValue(Constant *&V); bool ParseGlobalValueVector(SmallVectorImpl &Elts); + bool ParseOptionalComdat(Comdat *&C); bool ParseMetadataListValue(ValID &ID, PerFunctionState *PFS); bool ParseMetadataValue(ValID &ID, PerFunctionState *PFS); bool ParseMDNodeVector(SmallVectorImpl &, PerFunctionState *PFS); Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -163,6 +163,11 @@ return Error(I->second.second, "use of undefined type named '" + I->getKey() + "'"); + if (!ForwardRefComdats.empty()) + return Error(ForwardRefComdats.begin()->second.second, + "use of undefined comdat '$" + + ForwardRefComdats.begin()->first + "'"); + if (!ForwardRefVals.empty()) return Error(ForwardRefVals.begin()->second.second, "use of undefined value '@" + ForwardRefVals.begin()->first + @@ -238,6 +243,7 @@ case lltok::LocalVar: if (ParseNamedType()) return true; break; case lltok::GlobalID: if (ParseUnnamedGlobal()) return true; break; case lltok::GlobalVar: if (ParseNamedGlobal()) return true; break; + case lltok::ComdatVar: if (ParseComdat()) return true; break; case lltok::exclaim: if (ParseStandaloneMetadata()) return true; break; case lltok::MetadataVar:if (ParseNamedMetadata()) return true; break; @@ -513,6 +519,46 @@ UnnamedAddr); } +bool LLParser::ParseComdat() { + assert(Lex.getKind() == lltok::ComdatVar); + std::string Name = Lex.getStrVal(); + LocTy NameLoc = Lex.getLoc(); + Lex.Lex(); + + if (ParseToken(lltok::equal, "expected '=' here")) + return true; + + if (ParseToken(lltok::kw_comdat, "expected comdat keyword")) + return TokError("expected comdat type"); + + Comdat::SelectionKind SK; + switch (Lex.getKind()) { + default: return TokError("unknown selection kind"); + case lltok::kw_any: SK = Comdat::Any; break; + case lltok::kw_exactmatch: SK = Comdat::ExactMatch; break; + case lltok::kw_largest: SK = Comdat::Largest; break; + case lltok::kw_newest: SK = Comdat::Newest; break; + case lltok::kw_noduplicates: SK = Comdat::NoDuplicates; break; + case lltok::kw_samesize: SK = Comdat::SameSize; break; + } + Lex.Lex(); + + // See if the comdat was forward referenced, if so, use the comdat. + Comdat *C = cast_or_null(M->getComdatSymbolTable().lookup(Name)); + if (C && !ForwardRefComdats.erase(Name)) + return Error(NameLoc, "redefinition of comdat '$" + Name + "'"); + + if (!C) { + C = new Comdat(SK, Name, M); + } else { + C->setSelectionKind(SK); + // Move the forward-reference to the correct spot in the module. + M->getComdatList().splice(M->comdat_end(), M->getComdatList(), C); + } + + return false; +} + // MDString: // ::= '!' STRINGCONSTANT bool LLParser::ParseMDString(MDString *&Result) { @@ -682,6 +728,13 @@ return Error(AliaseeLoc, "invalid aliasee"); Aliasee = ID.ConstantVal; } + Comdat *C = nullptr; + if (EatIfPresent(lltok::comma)) { + if (ParseOptionalComdat(C)) + return true; + else if (!C) + return TokError("unknown global variable property!"); + } Type *AliaseeType = Aliasee->getType(); auto *PTy = dyn_cast(AliaseeType); @@ -698,6 +751,7 @@ GA->setVisibility((GlobalValue::VisibilityTypes)Visibility); GA->setDLLStorageClass((GlobalValue::DLLStorageClassTypes)DLLStorageClass); GA->setUnnamedAddr(UnnamedAddr); + GA->setComdat(C); // See if this value already exists in the symbol table. If so, it is either // a redefinition or a definition of a forward reference. @@ -837,7 +891,12 @@ if (ParseOptionalAlignment(Alignment)) return true; GV->setAlignment(Alignment); } else { - TokError("unknown global variable property!"); + Comdat *C; + if (ParseOptionalComdat(C)) return true; + if (C) + GV->setComdat(C); + else + return TokError("unknown global variable property!"); } } @@ -1096,6 +1155,37 @@ //===----------------------------------------------------------------------===// +// Comdat Reference/Resolution Routines. +//===----------------------------------------------------------------------===// + +/// GetComdatVal - Get a Comdat with the specified name, creating a forward +/// reference record if needed. +Comdat *LLParser::GetComdat(const std::string &Name, LocTy Loc) { + // Look this name up in the normal function symbol table. + Comdat *C = cast_or_null(M->getComdatSymbolTable().lookup(Name)); + + // If this is a forward reference for the value, see if we already created a + // forward ref record. + if (!C) { + std::map>::iterator I = + ForwardRefComdats.find(Name); + if (I != ForwardRefComdats.end()) + C = I->second.first; + } + + // If we have the value in the symbol table or fwd-ref table, return it. + if (C) + return C; + + // Otherwise, create a new forward reference for this value and remember it. + Comdat *FwdVal = new Comdat(Comdat::Any, Name, M); + + ForwardRefComdats[Name] = std::make_pair(FwdVal, Loc); + return FwdVal; +} + + +//===----------------------------------------------------------------------===// // Helper Routines. //===----------------------------------------------------------------------===// @@ -2320,6 +2410,10 @@ ID.StrVal = Lex.getStrVal(); ID.Kind = ValID::t_GlobalName; break; + case lltok::ComdatVar: // $foo + ID.StrVal = Lex.getStrVal(); + ID.Kind = ValID::t_ComdatName; + break; case lltok::LocalVarID: // %42 ID.UIntVal = Lex.getUIntVal(); ID.Kind = ValID::t_LocalID; @@ -2789,6 +2883,22 @@ ParseGlobalValue(Ty, V); } +bool LLParser::ParseOptionalComdat(Comdat *&C) { + C = nullptr; + if (!EatIfPresent(lltok::kw_comdat)) + return false; + if (Lex.getKind() != lltok::ComdatVar) + return TokError("expected comdat variable"); + + ValID ID; + Value *V = nullptr; + bool Parsed = ParseValID(ID) || + ConvertValIDToValue(Type::getComdatTy(Context), ID, V, nullptr); + if (V && !(C = dyn_cast(V))) + return Error(ID.Loc, "expected comdat"); + return Parsed; +} + /// ParseGlobalValueVector /// ::= /*empty*/ /// ::= TypeAndValue (',' TypeAndValue)* @@ -2893,6 +3003,11 @@ return Error(ID.Loc, "metadata value must have metadata type"); V = ID.MDStringVal; return false; + case ValID::t_ComdatName: + if (!Ty->isComdatTy()) + return Error(ID.Loc, "comdat value must have comdat type"); + V = GetComdat(ID.StrVal, ID.Loc); + return V == nullptr; case ValID::t_GlobalName: V = GetGlobalVal(ID.StrVal, Ty, ID.Loc); return V == nullptr; @@ -3089,6 +3204,7 @@ bool UnnamedAddr; LocTy UnnamedAddrLoc; Constant *Prefix = nullptr; + Comdat *C; if (ParseArgumentList(ArgList, isVarArg) || ParseOptionalToken(lltok::kw_unnamed_addr, UnnamedAddr, @@ -3097,6 +3213,7 @@ BuiltinLoc) || (EatIfPresent(lltok::kw_section) && ParseStringConstant(Section)) || + ParseOptionalComdat(C) || ParseOptionalAlignment(Alignment) || (EatIfPresent(lltok::kw_gc) && ParseStringConstant(GC)) || @@ -3199,6 +3316,7 @@ Fn->setUnnamedAddr(UnnamedAddr); Fn->setAlignment(Alignment); Fn->setSection(Section); + Fn->setComdat(C); if (!GC.empty()) Fn->setGC(GC.c_str()); Fn->setPrefixData(Prefix); ForwardRefAttrGroups[Fn] = FwdRefAttrGrps; Index: lib/AsmParser/LLToken.h =================================================================== --- lib/AsmParser/LLToken.h +++ lib/AsmParser/LLToken.h @@ -141,6 +141,16 @@ kw_type, kw_opaque, + kw_comdat, + + // Comdat types + kw_any, + kw_exactmatch, + kw_largest, + kw_newest, + kw_noduplicates, + kw_samesize, + kw_eq, kw_ne, kw_slt, kw_sgt, kw_sle, kw_sge, kw_ult, kw_ugt, kw_ule, kw_uge, kw_oeq, kw_one, kw_olt, kw_ogt, kw_ole, kw_oge, kw_ord, kw_uno, kw_ueq, kw_une, @@ -179,6 +189,7 @@ // String valued tokens (StrVal). LabelStr, // foo: GlobalVar, // @foo @"foo" + ComdatVar, // $foo LocalVar, // %foo %"foo" MetadataVar, // !foo StringConstant, // "foo" Index: lib/Bitcode/Reader/BitcodeReader.h =================================================================== --- lib/Bitcode/Reader/BitcodeReader.h +++ lib/Bitcode/Reader/BitcodeReader.h @@ -26,6 +26,7 @@ #include namespace llvm { + class Comdat; class MemoryBuffer; class LLVMContext; @@ -136,12 +137,14 @@ std::vector TypeList; BitcodeReaderValueList ValueList; BitcodeReaderMDValueList MDValueList; + std::vector ComdatList; SmallVector InstructionList; SmallVector, 64> UseListRecords; std::vector > GlobalInits; std::vector > AliasInits; std::vector > FunctionPrefixes; + std::vector> Comdats; SmallVector InstsWithTBAATag; @@ -358,6 +361,7 @@ error_code RememberAndSkipFunctionBody(); error_code ParseFunctionBody(Function *F); error_code GlobalCleanup(); + error_code ResolveComdats(); error_code ResolveGlobalAndAliasInits(); error_code ParseMetadata(); error_code ParseMetadataAttachment(); Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -45,6 +45,7 @@ std::vector().swap(TypeList); ValueList.clear(); MDValueList.clear(); + std::vector().swap(ComdatList); std::vector().swap(MAttributes); std::vector().swap(FunctionBBs); @@ -205,6 +206,19 @@ } } +static Comdat::SelectionKind getDecodedComdatSelectionKind(unsigned Val) { + switch (Val) { + default: // Map unknown selection kinds to any. + case bitc::COMDAT_SELECTION_KIND_ANY: return Comdat::Any; + case bitc::COMDAT_SELECTION_KIND_EXACT_MATCH: return Comdat::ExactMatch; + case bitc::COMDAT_SELECTION_KIND_LARGEST: return Comdat::Largest; + case bitc::COMDAT_SELECTION_KIND_NEWEST: return Comdat::Newest; + case bitc::COMDAT_SELECTION_KIND_NO_DUPLICATES: return Comdat::NoDuplicates; + case bitc::COMDAT_SELECTION_KIND_SAME_SIZE: return Comdat::SameSize; + + } +} + static void UpgradeDLLImportExportLinkage(llvm::GlobalValue *GV, unsigned Val) { switch (Val) { case 5: GV->setDLLStorageClass(GlobalValue::DLLImportStorageClass); break; @@ -1096,6 +1110,26 @@ return 1ULL << 63; } +error_code BitcodeReader::ResolveComdats() { + std::vector> ComdatWorklist; + ComdatWorklist.swap(Comdats); + + while (!ComdatWorklist.empty()) { + unsigned ComdatID = ComdatWorklist.back().second; + if (ComdatID >= ComdatList.size()) { + Comdats.push_back(ComdatWorklist.back()); + } else { + if (Comdat *C = ComdatList[ComdatID]) + ComdatWorklist.back().first->setComdat(C); + else + return Error(InvalidValue); + } + ComdatWorklist.pop_back(); + } + + return error_code(); +} + /// ResolveGlobalAndAliasInits - Resolve all of the initializers for global /// values and aliases that we can. error_code BitcodeReader::ResolveGlobalAndAliasInits() { @@ -1147,6 +1181,9 @@ FunctionPrefixWorklist.pop_back(); } + if (error_code EC = ResolveComdats()) + return EC; + return error_code(); } @@ -1839,6 +1876,17 @@ GCTable.push_back(S); break; } + case bitc::MODULE_CODE_COMDAT: { // COMDAT: [selection_kind, name] + if (Record.size() < 2) + return Error(InvalidRecord); + Comdat::SelectionKind SK = getDecodedComdatSelectionKind(Record[0]); + std::string ComdatName; + if (ConvertToString(Record, 1, ComdatName)) + return Error(InvalidRecord); + Comdat *C = new Comdat(SK, ComdatName, TheModule); + ComdatList.push_back(C); + break; + } // GLOBALVAR: [pointer type, isconst, initid, // linkage, alignment, section, visibility, threadlocal, // unnamed_addr, dllstorageclass] @@ -1899,6 +1947,11 @@ // Remember which value to use for the global initializer. if (unsigned InitID = Record[2]) GlobalInits.push_back(std::make_pair(NewGV, InitID-1)); + + // Remember which value to use for the comdat. + if (Record.size() > 11) + if (unsigned ComdatID = Record[11]) + Comdats.push_back(std::make_pair(NewGV, ComdatID - 1)); break; } // FUNCTION: [type, callingconv, isproto, linkage, paramattr, @@ -1952,6 +2005,10 @@ else UpgradeDLLImportExportLinkage(Func, Record[3]); + if (Record.size() > 12) + if (unsigned ComdatID = Record[12]) + Func->setComdat(ComdatList[ComdatID - 1]); + ValueList.push_back(Func); // If this is a function with a body, remember the prototype we are @@ -1992,6 +2049,10 @@ NewGA->setUnnamedAddr(Record[6]); ValueList.push_back(NewGA); AliasInits.push_back(std::make_pair(NewGA, Record[1])); + // Remember which value to use for the comdat. + if (Record.size() > 7) + if (unsigned ComdatID = Record[7]) + Comdats.push_back(std::make_pair(NewGA, ComdatID - 1)); break; } /// MODULE_CODE_PURGEVALS: [numvals] Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -398,6 +398,7 @@ case Type::LabelTyID: Code = bitc::TYPE_CODE_LABEL; break; case Type::MetadataTyID: Code = bitc::TYPE_CODE_METADATA; break; case Type::X86_MMXTyID: Code = bitc::TYPE_CODE_X86_MMX; break; + case Type::ComdatTyID: Code = bitc::TYPE_CODE_COMDAT; break; case Type::IntegerTyID: // INTEGER: [width] Code = bitc::TYPE_CODE_INTEGER; @@ -524,6 +525,18 @@ llvm_unreachable("Invalid TLS model"); } +static unsigned getEncodedComdatSelectionKind(const Comdat &C) { + switch (C.getSelectionKind()) { + case Comdat::Any: return bitc::COMDAT_SELECTION_KIND_ANY; + case Comdat::ExactMatch: return bitc::COMDAT_SELECTION_KIND_EXACT_MATCH; + case Comdat::Largest: return bitc::COMDAT_SELECTION_KIND_LARGEST; + case Comdat::Newest: return bitc::COMDAT_SELECTION_KIND_NEWEST; + case Comdat::NoDuplicates: return bitc::COMDAT_SELECTION_KIND_NO_DUPLICATES; + case Comdat::SameSize: return bitc::COMDAT_SELECTION_KIND_SAME_SIZE; + } + llvm_unreachable("Invalid selection kind"); +} + // Emit top-level description of module, including target triple, inline asm, // descriptors for global variables, and function prototype info. static void WriteModuleInfo(const Module *M, const ValueEnumerator &VE, @@ -607,8 +620,19 @@ SimpleGVarAbbrev = Stream.EmitAbbrev(Abbv); } - // Emit the global variable information. + // Emit the comdat information. SmallVector Vals; + for (const Comdat &C : M->comdats()) { + // COMDAT: [selection_kind, name] + unsigned AbbrevToUse = 0; + Vals.push_back(getEncodedComdatSelectionKind(C)); + for (char C : C.getName()) + Vals.push_back((unsigned char)C); + Stream.EmitRecord(bitc::MODULE_CODE_COMDAT, Vals, AbbrevToUse); + Vals.clear(); + } + + // Emit the global variable information. for (const GlobalVariable &GV : M->globals()) { unsigned AbbrevToUse = 0; @@ -625,12 +649,14 @@ if (GV.isThreadLocal() || GV.getVisibility() != GlobalValue::DefaultVisibility || GV.hasUnnamedAddr() || GV.isExternallyInitialized() || - GV.getDLLStorageClass() != GlobalValue::DefaultStorageClass) { + GV.getDLLStorageClass() != GlobalValue::DefaultStorageClass || + GV.hasComdat()) { Vals.push_back(getEncodedVisibility(GV)); Vals.push_back(getEncodedThreadLocalMode(GV)); Vals.push_back(GV.hasUnnamedAddr()); Vals.push_back(GV.isExternallyInitialized()); Vals.push_back(getEncodedDLLStorageClass(GV)); + Vals.push_back(GV.hasComdat() ? (VE.getValueID(GV.getComdat()) + 1) : 0); } else { AbbrevToUse = SimpleGVarAbbrev; } @@ -656,6 +682,7 @@ Vals.push_back(F.hasPrefixData() ? (VE.getValueID(F.getPrefixData()) + 1) : 0); Vals.push_back(getEncodedDLLStorageClass(F)); + Vals.push_back(F.hasComdat() ? (VE.getValueID(F.getComdat()) + 1) : 0); unsigned AbbrevToUse = 0; Stream.EmitRecord(bitc::MODULE_CODE_FUNCTION, Vals, AbbrevToUse); @@ -672,6 +699,7 @@ Vals.push_back(getEncodedDLLStorageClass(A)); Vals.push_back(getEncodedThreadLocalMode(A)); Vals.push_back(A.hasUnnamedAddr()); + Vals.push_back(A.hasComdat() ? (VE.getValueID(A.getComdat()) + 1) : 0); unsigned AbbrevToUse = 0; Stream.EmitRecord(bitc::MODULE_CODE_ALIAS, Vals, AbbrevToUse); Vals.clear(); Index: lib/Bitcode/Writer/ValueEnumerator.h =================================================================== --- lib/Bitcode/Writer/ValueEnumerator.h +++ lib/Bitcode/Writer/ValueEnumerator.h @@ -25,6 +25,7 @@ class Value; class Instruction; class BasicBlock; +class Comdat; class Function; class Module; class MDNode; @@ -48,6 +49,8 @@ typedef DenseMap ValueMapType; ValueMapType ValueMap; ValueList Values; + ValueMapType ComdatMap; + ValueList Comdats; ValueList MDValues; SmallVector FunctionLocalMDs; ValueMapType MDValueMap; @@ -158,11 +161,13 @@ void EnumerateFunctionLocalMetadata(const MDNode *N); void EnumerateNamedMDNode(const NamedMDNode *NMD); void EnumerateValue(const Value *V); + void EnumerateComdat(const Comdat *C); void EnumerateType(Type *T); void EnumerateOperandType(const Value *V); void EnumerateAttributes(AttributeSet PAL); void EnumerateValueSymbolTable(const ValueSymbolTable &ST); + void EnumerateComdats(const Module *M); void EnumerateNamedMetadata(const Module *M); }; Index: lib/Bitcode/Writer/ValueEnumerator.cpp =================================================================== --- lib/Bitcode/Writer/ValueEnumerator.cpp +++ lib/Bitcode/Writer/ValueEnumerator.cpp @@ -68,6 +68,7 @@ // Insert constants and metadata that are named at module level into the slot // pool so that the module symbol table can refer to them... EnumerateValueSymbolTable(M->getValueSymbolTable()); + EnumerateComdats(M); EnumerateNamedMetadata(M); SmallVector, 8> MDs; @@ -130,6 +131,11 @@ assert(I != MDValueMap.end() && "Value not in slotcalculator!"); return I->second-1; } + if (isa(V)) { + ValueMapType::const_iterator I = ComdatMap.find(V); + assert(I != ComdatMap.end() && "Value not in slotcalculator!"); + return I->second - 1; + } ValueMapType::const_iterator I = ValueMap.find(V); assert(I != ValueMap.end() && "Value not in slotcalculator!"); @@ -139,6 +145,8 @@ void ValueEnumerator::dump() const { print(dbgs(), ValueMap, "Default"); dbgs() << '\n'; + print(dbgs(), ComdatMap, "Comdat"); + dbgs() << '\n'; print(dbgs(), MDValueMap, "MetaData"); dbgs() << '\n'; } @@ -206,6 +214,13 @@ EnumerateValue(VI->getValue()); } +/// EnumerateComdats - Insert all of the values in the specified symbol +/// table into the values table. +void ValueEnumerator::EnumerateComdats(const Module *M) { + for (const Comdat &C : M->comdats()) + EnumerateComdat(&C); +} + /// EnumerateNamedMetadata - Insert all of the values referenced by /// named metadata in the specified module. void ValueEnumerator::EnumerateNamedMetadata(const Module *M) { @@ -343,6 +358,17 @@ ValueID = Values.size(); } +void ValueEnumerator::EnumerateComdat(const Comdat *C) { + // Check to see if it's already in! + unsigned &ComdatID = ComdatMap[C]; + if (ComdatID) { + // Increment use count. + Comdats[ComdatID - 1].second++; + return; + } + Comdats.push_back(std::make_pair(C, 1U)); + ComdatID = Comdats.size(); +} void ValueEnumerator::EnumerateType(Type *Ty) { unsigned *TypeID = &TypeMap[Ty]; Index: lib/CodeGen/TargetLoweringObjectFileImpl.cpp =================================================================== --- lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -200,14 +200,23 @@ // Infer section flags from the section name if we can. Kind = getELFKindForNamedSection(SectionName, Kind); + StringRef Group = ""; + unsigned Flags = getELFSectionFlags(Kind); + if (const Comdat *C = GV->getComdat()) { + if (C->getSelectionKind() != Comdat::Any) + report_fatal_error("ELF COMDATs only support SelectionKind::Any, '" + + C->getName() + "' cannot be lowered."); + Group = C->getName(); + Flags |= ELF::SHF_GROUP; + } return getContext().getELFSection(SectionName, - getELFSectionType(SectionName, Kind), - getELFSectionFlags(Kind), Kind); + getELFSectionType(SectionName, Kind), Flags, + Kind, /*EntrySize=*/0, Group); } /// getSectionPrefixForGlobal - Return the section prefix name used by options /// FunctionsSections and DataSections. -static const char *getSectionPrefixForGlobal(SectionKind Kind) { +static StringRef getSectionPrefixForGlobal(SectionKind Kind) { if (Kind.isText()) return ".text."; if (Kind.isReadOnly()) return ".rodata."; if (Kind.isBSS()) return ".bss."; @@ -238,18 +247,24 @@ // If this global is linkonce/weak and the target handles this by emitting it // into a 'uniqued' section name, create and return the section now. - if ((GV->isWeakForLinker() || EmitUniquedSection) && + if ((GV->isWeakForLinker() || EmitUniquedSection || GV->hasComdat()) && !Kind.isCommon()) { - const char *Prefix; - Prefix = getSectionPrefixForGlobal(Kind); + StringRef Prefix = getSectionPrefixForGlobal(Kind); - SmallString<128> Name(Prefix, Prefix+strlen(Prefix)); + SmallString<128> Name(Prefix); TM.getNameWithPrefix(Name, GV, Mang, true); StringRef Group = ""; unsigned Flags = getELFSectionFlags(Kind); - if (GV->isWeakForLinker()) { - Group = Name.substr(strlen(Prefix)); + if (GV->isWeakForLinker() || GV->hasComdat()) { + if (const Comdat *C = GV->getComdat()) { + if (C->getSelectionKind() != Comdat::Any) + report_fatal_error("ELF COMDATs only support SelectionKind::Any, '" + + C->getName() + "' cannot be lowered."); + Group = C->getName(); + } else { + Group = Name.substr(Prefix.size()); + } Flags |= ELF::SHF_GROUP; } @@ -490,6 +505,10 @@ StringRef Segment, Section; unsigned TAA = 0, StubSize = 0; bool TAAParsed; + + if (const Comdat *C = GV->getComdat()) + report_fatal_error("MachO doesn't support COMDATs, '" + C->getName() + + "' cannot be lowered."); std::string ErrorCode = MCSectionMachO::ParseSectionSpecifier(GV->getSection(), Segment, Section, TAA, TAAParsed, StubSize); @@ -561,6 +580,10 @@ SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind, Mangler &Mang, const TargetMachine &TM) const { + if (const Comdat *C = GV->getComdat()) + report_fatal_error("MachO doesn't support COMDATs, '" + C->getName() + + "' cannot be lowered."); + // Handle thread local data. if (Kind.isThreadBSS()) return TLSBSSSection; if (Kind.isThreadData()) return TLSDataSection; @@ -728,6 +751,32 @@ return Flags; } +static int getSelectionForCOFF(const GlobalValue *GV) { + if (const Comdat *C = GV->getComdat()) { + if (C->getName() == GV->getName()) { + switch (C->getSelectionKind()) { + case Comdat::Any: + return COFF::IMAGE_COMDAT_SELECT_ANY; + case Comdat::ExactMatch: + return COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH; + case Comdat::Largest: + return COFF::IMAGE_COMDAT_SELECT_LARGEST; + case Comdat::Newest: + return COFF::IMAGE_COMDAT_SELECT_NEWEST; + case Comdat::NoDuplicates: + return COFF::IMAGE_COMDAT_SELECT_NODUPLICATES; + case Comdat::SameSize: + return COFF::IMAGE_COMDAT_SELECT_SAME_SIZE; + } + } else { + return COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE; + } + } else if (GV->isWeakForLinker()) { + return COFF::IMAGE_COMDAT_SELECT_ANY; + } + return 0; +} + const MCSection *TargetLoweringObjectFileCOFF::getExplicitSectionGlobal( const GlobalValue *GV, SectionKind Kind, Mangler &Mang, const TargetMachine &TM) const { @@ -735,11 +784,26 @@ unsigned Characteristics = getCOFFSectionFlags(Kind); StringRef Name = GV->getSection(); StringRef COMDATSymName = ""; - if (GV->isWeakForLinker()) { - Selection = COFF::IMAGE_COMDAT_SELECT_ANY; - Characteristics |= COFF::IMAGE_SCN_LNK_COMDAT; - MCSymbol *Sym = TM.getSymbol(GV, Mang); - COMDATSymName = Sym->getName(); + if ((GV->isWeakForLinker() || GV->hasComdat()) && !Kind.isCommon()) { + Selection = getSelectionForCOFF(GV); + if (Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE || + !GV->hasPrivateLinkage()) { + const GlobalValue *ComdatGV; + if (Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) { + StringRef ComdatGVName = GV->getComdat()->getName(); + ComdatGV = GV->getParent()->getNamedValue(ComdatGVName); + if (!ComdatGV) + report_fatal_error("Associative COMDAT symbol '" + ComdatGVName + + "' does not exist."); + } else { + ComdatGV = GV; + } + MCSymbol *Sym = TM.getSymbol(ComdatGV, Mang); + COMDATSymName = Sym->getName(); + Characteristics |= COFF::IMAGE_SCN_LNK_COMDAT; + } else { + Selection = 0; + } } return getContext().getCOFFSection(Name, Characteristics, @@ -776,17 +840,32 @@ // into a 'uniqued' section name, create and return the section now. // Section names depend on the name of the symbol which is not feasible if the // symbol has private linkage. - if ((GV->isWeakForLinker() || EmitUniquedSection) && - !GV->hasPrivateLinkage() && !Kind.isCommon()) { + if ((GV->isWeakForLinker() || EmitUniquedSection || GV->hasComdat()) && + !Kind.isCommon()) { const char *Name = getCOFFSectionNameForUniqueGlobal(Kind); unsigned Characteristics = getCOFFSectionFlags(Kind); Characteristics |= COFF::IMAGE_SCN_LNK_COMDAT; - MCSymbol *Sym = TM.getSymbol(GV, Mang); - return getContext().getCOFFSection( - Name, Characteristics, Kind, Sym->getName(), - GV->isWeakForLinker() ? COFF::IMAGE_COMDAT_SELECT_ANY - : COFF::IMAGE_COMDAT_SELECT_NODUPLICATES); + int Selection = getSelectionForCOFF(GV); + if (!Selection) + Selection = COFF::IMAGE_COMDAT_SELECT_NODUPLICATES; + if (Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE || + !GV->hasPrivateLinkage()) { + const GlobalValue *ComdatGV; + if (Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) { + StringRef ComdatGVName = GV->getComdat()->getName(); + ComdatGV = GV->getParent()->getNamedValue(ComdatGVName); + if (!ComdatGV) + report_fatal_error("Associative COMDAT symbol '" + ComdatGVName + + "' does not exist."); + } else { + ComdatGV = GV; + } + MCSymbol *Sym = TM.getSymbol(ComdatGV, Mang); + StringRef COMDATSymName = Sym->getName(); + return getContext().getCOFFSection(Name, Characteristics, Kind, + COMDATSymName, Selection); + } } if (Kind.isText()) Index: lib/IR/AsmWriter.h =================================================================== --- lib/IR/AsmWriter.h +++ lib/IR/AsmWriter.h @@ -26,6 +26,7 @@ class BasicBlock; class Function; class GlobalValue; +class Comdat; class Module; class NamedMDNode; class Value; @@ -101,6 +102,7 @@ void printTypeIdentities(); void printGlobal(const GlobalVariable *GV); void printAlias(const GlobalAlias *GV); + void printComdat(const Comdat *C); void printFunction(const Function *F); void printArgument(const Argument *FA, AttributeSet Attrs, unsigned Idx); void printBasicBlock(const BasicBlock *BB); Index: lib/IR/AsmWriter.cpp =================================================================== --- lib/IR/AsmWriter.cpp +++ lib/IR/AsmWriter.cpp @@ -106,6 +106,7 @@ enum PrefixType { GlobalPrefix, + ComdatPrefix, LabelPrefix, LocalPrefix, NoPrefix @@ -119,6 +120,7 @@ switch (Prefix) { case NoPrefix: break; case GlobalPrefix: OS << '@'; break; + case ComdatPrefix: OS << '$'; break; case LabelPrefix: break; case LocalPrefix: OS << '%'; break; } @@ -202,6 +204,8 @@ case Type::PPC_FP128TyID: OS << "ppc_fp128"; return; case Type::LabelTyID: OS << "label"; return; case Type::MetadataTyID: OS << "metadata"; return; + case Type::ComdatTyID: OS << "comdat"; return; + case Type::X86_MMXTyID: OS << "x86_mmx"; return; case Type::IntegerTyID: OS << 'i' << cast(Ty)->getBitWidth(); @@ -1308,6 +1312,12 @@ printTypeIdentities(); + // Output all comdats. + if (!M->comdat_empty()) Out << '\n'; + for (const Comdat &S : M->comdats()) { + printComdat(&S); Out << '\n'; + } + // Output all globals. if (!M->global_empty()) Out << '\n'; for (Module::const_global_iterator I = M->global_begin(), E = M->global_end(); @@ -1470,6 +1480,10 @@ PrintEscapedString(GV->getSection(), Out); Out << '"'; } + if (GV->hasComdat()) { + Out << ", comdat "; + PrintLLVMName(Out, GV->getComdat()->getName(), ComdatPrefix); + } if (GV->getAlignment()) Out << ", align " << GV->getAlignment(); @@ -1506,10 +1520,32 @@ writeOperand(Aliasee, !isa(Aliasee)); } + if (GA->hasComdat()) { + Out << ", comdat "; + PrintLLVMName(Out, GA->getComdat()->getName(), ComdatPrefix); + } + printInfoComment(*GA); Out << '\n'; } +void AssemblyWriter::printComdat(const Comdat *C) { + PrintLLVMName(Out, C->getName(), ComdatPrefix); + Out << " = comdat "; + + switch (C->getSelectionKind()) { + case Comdat::Any: Out << "any"; break; + case Comdat::ExactMatch: Out << "exactmatch"; break; + case Comdat::Largest: Out << "largest"; break; + case Comdat::Newest: Out << "newest"; break; + case Comdat::NoDuplicates: Out << "noduplicates"; break; + case Comdat::SameSize: Out << "samesize"; break; + } + + printInfoComment(*C); + Out << '\n'; +} + void AssemblyWriter::printTypeIdentities() { if (TypePrinter.NumberedTypes.empty() && TypePrinter.NamedTypes.empty()) @@ -1647,6 +1683,10 @@ PrintEscapedString(F->getSection(), Out); Out << '"'; } + if (F->hasComdat()) { + Out << " comdat "; + PrintLLVMName(Out, F->getComdat()->getName(), ComdatPrefix); + } if (F->getAlignment()) Out << " align " << F->getAlignment(); if (F->hasGC()) @@ -2187,6 +2227,10 @@ W.printFunction(F); else W.printAlias(cast(GV)); + } else if (const auto *C = dyn_cast(this)) { + SlotTracker SlotTable(C->getParent()); + AssemblyWriter W(OS, SlotTable, C->getParent(), nullptr); + W.printComdat(C); } else if (const MDNode *N = dyn_cast(this)) { const Function *F = N->getFunction(); SlotTracker SlotTable(F); Index: lib/IR/CMakeLists.txt =================================================================== --- lib/IR/CMakeLists.txt +++ lib/IR/CMakeLists.txt @@ -3,6 +3,7 @@ Attributes.cpp AutoUpgrade.cpp BasicBlock.cpp + Comdat.cpp ConstantFold.cpp ConstantRange.cpp Constants.cpp Index: lib/IR/Comdat.cpp =================================================================== --- /dev/null +++ lib/IR/Comdat.cpp @@ -0,0 +1,39 @@ +//===-- Comdat.cpp - Implement Metadata classes --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Comdat class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/Comdat.h" +#include "SymbolTableListTraitsImpl.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +using namespace llvm; + +// Explicit instantiations of SymbolTableListTraits since some of the methods +// are not in the public header file. +template class llvm::SymbolTableListTraits; + +Comdat::Comdat(SelectionKind SK, const Twine &Name, Module *M) + : Value(Type::getComdatTy(M->getContext()), Value::ComdatVal), + Parent(nullptr), SK(SK) { + setName(Name); + M->getComdatList().push_back(this); +} + +Comdat::Comdat(SelectionKind SK, const Twine &Name, Comdat *InsertBefore) + : Value(Type::getComdatTy(InsertBefore->getParent()->getContext()), + Value::ComdatVal), + Parent(nullptr), SK(SK) { + setName(Name); + InsertBefore->getParent()->getComdatList().insert(InsertBefore, this); +} + +Comdat::~Comdat() {} Index: lib/IR/Core.cpp =================================================================== --- lib/IR/Core.cpp +++ lib/IR/Core.cpp @@ -260,6 +260,8 @@ return LLVMVectorTypeKind; case Type::X86_MMXTyID: return LLVMX86_MMXTypeKind; + case Type::ComdatTyID: + return LLVMComdatTypeKind; } llvm_unreachable("Unhandled TypeID."); } Index: lib/IR/Function.cpp =================================================================== --- lib/IR/Function.cpp +++ lib/IR/Function.cpp @@ -217,8 +217,8 @@ Function::Function(FunctionType *Ty, LinkageTypes Linkage, const Twine &name, Module *ParentModule) - : GlobalObject(PointerType::getUnqual(Ty), - Value::FunctionVal, nullptr, 0, Linkage, name) { + : GlobalObject(PointerType::getUnqual(Ty), Value::FunctionVal, + OperandTraits::op_begin(this), 0, Linkage, name) { assert(FunctionType::isValidReturnType(getReturnType()) && "invalid return type"); SymTab = new ValueSymbolTable(); @@ -252,6 +252,8 @@ // Remove the intrinsicID from the Cache. if (getValueName() && isIntrinsic()) getContext().pImpl->IntrinsicIDCache.erase(this); + + NumOperands = 1; // FIXME: needed by operator delete } void Function::BuildLazyArguments() const { Index: lib/IR/Globals.cpp =================================================================== --- lib/IR/Globals.cpp +++ lib/IR/Globals.cpp @@ -105,6 +105,32 @@ void GlobalObject::setSection(StringRef S) { Section = S; } +const Comdat *GlobalValue::getComdat() const { + if (isa(this) || isa(this)) + return NumOperands > 1 ? cast(getOperand(1)) : nullptr; + return NumOperands > 0 ? cast(this)->getOperand(0) : nullptr; +} +void GlobalValue::setComdat(Comdat *C) { + if (isa(this) || isa(this)) { + // Comdats on declarations are semantically meaningless, ignore them. + if (isDeclaration()) + return; + if (C) { + NumOperands = 2; + setOperand(1, C); + } else { + NumOperands = 1; + } + } else { + if (C) { + NumOperands = 1; + cast(this)->setOperand(0, C); + } else { + NumOperands = 0; + } + } +} + bool GlobalValue::isDeclaration() const { // Globals are definitions if they have an initializer. if (const GlobalVariable *GV = dyn_cast(this)) @@ -205,6 +231,8 @@ void GlobalVariable::setInitializer(Constant *InitVal) { if (!InitVal) { + if (hasComdat()) + Op<1>().set(nullptr); if (hasInitializer()) { Op<0>().set(nullptr); NumOperands = 0; @@ -213,7 +241,7 @@ assert(InitVal->getType() == getType()->getElementType() && "Initializer type must match GlobalVariable type"); if (!hasInitializer()) - NumOperands = 1; + NumOperands = hasComdat() ? 2 : 1; Op<0>().set(InitVal); } } @@ -236,7 +264,7 @@ const Twine &Name, Constant *Aliasee, Module *ParentModule) : GlobalValue(PointerType::get(Ty, AddressSpace), Value::GlobalAliasVal, - &Op<0>(), 1, Link, Name) { + OperandTraits::op_begin(this), 1, Link, Name) { LeakDetector::addGarbageObject(this); Op<0>() = Aliasee; Index: lib/IR/LLVMContextImpl.h =================================================================== --- lib/IR/LLVMContextImpl.h +++ lib/IR/LLVMContextImpl.h @@ -301,7 +301,7 @@ LeakDetectorImpl LLVMObjects; // Basic type instances. - Type VoidTy, LabelTy, HalfTy, FloatTy, DoubleTy, MetadataTy; + Type VoidTy, LabelTy, HalfTy, FloatTy, DoubleTy, MetadataTy, ComdatTy; Type X86_FP80Ty, FP128Ty, PPC_FP128Ty, X86_MMXTy; IntegerType Int1Ty, Int8Ty, Int16Ty, Int32Ty, Int64Ty; Index: lib/IR/LLVMContextImpl.cpp =================================================================== --- lib/IR/LLVMContextImpl.cpp +++ lib/IR/LLVMContextImpl.cpp @@ -27,6 +27,7 @@ FloatTy(C, Type::FloatTyID), DoubleTy(C, Type::DoubleTyID), MetadataTy(C, Type::MetadataTyID), + ComdatTy(C, Type::ComdatTyID), X86_FP80Ty(C, Type::X86_FP80TyID), FP128Ty(C, Type::FP128TyID), PPC_FP128Ty(C, Type::PPC_FP128TyID), Index: lib/IR/Module.cpp =================================================================== --- lib/IR/Module.cpp +++ lib/IR/Module.cpp @@ -46,6 +46,7 @@ Module::Module(StringRef MID, LLVMContext &C) : Context(C), Materializer(), ModuleID(MID), DL("") { ValSymTab = new ValueSymbolTable(); + ComdatSymTab = new ValueSymbolTable(); NamedMDSymTab = new StringMap(); Context.addModule(this); } @@ -56,8 +57,10 @@ GlobalList.clear(); FunctionList.clear(); AliasList.clear(); + ComdatList.clear(); NamedMDList.clear(); delete ValSymTab; + delete ComdatSymTab; delete static_cast *>(NamedMDSymTab); } @@ -437,3 +440,7 @@ return dwarf::DWARF_VERSION; return cast(Val)->getZExtValue(); } + +ValueSymbolTable *ilist_traits::getSymTab(Module *M) { + return M ? &M->getComdatSymbolTable() : nullptr; +} Index: lib/IR/Type.cpp =================================================================== --- lib/IR/Type.cpp +++ lib/IR/Type.cpp @@ -34,6 +34,7 @@ case PPC_FP128TyID : return getPPC_FP128Ty(C); case LabelTyID : return getLabelTy(C); case MetadataTyID : return getMetadataTy(C); + case ComdatTyID : return getComdatTy(C); case X86_MMXTyID : return getX86_MMXTy(C); default: return nullptr; @@ -224,6 +225,7 @@ Type *Type::getFloatTy(LLVMContext &C) { return &C.pImpl->FloatTy; } Type *Type::getDoubleTy(LLVMContext &C) { return &C.pImpl->DoubleTy; } Type *Type::getMetadataTy(LLVMContext &C) { return &C.pImpl->MetadataTy; } +Type *Type::getComdatTy(LLVMContext &C) { return &C.pImpl->ComdatTy; } Type *Type::getX86_FP80Ty(LLVMContext &C) { return &C.pImpl->X86_FP80Ty; } Type *Type::getFP128Ty(LLVMContext &C) { return &C.pImpl->FP128Ty; } Type *Type::getPPC_FP128Ty(LLVMContext &C) { return &C.pImpl->PPC_FP128Ty; } @@ -381,7 +383,7 @@ /// type. bool FunctionType::isValidReturnType(Type *RetTy) { return !RetTy->isFunctionTy() && !RetTy->isLabelTy() && - !RetTy->isMetadataTy(); + !RetTy->isMetadataTy() && !RetTy->isComdatTy(); } /// isValidArgumentType - Return true if the specified type is valid as an @@ -595,7 +597,8 @@ bool StructType::isValidElementType(Type *ElemTy) { return !ElemTy->isVoidTy() && !ElemTy->isLabelTy() && - !ElemTy->isMetadataTy() && !ElemTy->isFunctionTy(); + !ElemTy->isMetadataTy() && !ElemTy->isFunctionTy() && + !ElemTy->isComdatTy(); } /// isLayoutIdentical - Return true if this is layout identical to the @@ -688,7 +691,8 @@ bool ArrayType::isValidElementType(Type *ElemTy) { return !ElemTy->isVoidTy() && !ElemTy->isLabelTy() && - !ElemTy->isMetadataTy() && !ElemTy->isFunctionTy(); + !ElemTy->isMetadataTy() && !ElemTy->isFunctionTy() && + !ElemTy->isComdatTy(); } //===----------------------------------------------------------------------===// Index: lib/IR/Value.cpp =================================================================== --- lib/IR/Value.cpp +++ lib/IR/Value.cpp @@ -154,6 +154,9 @@ } else if (Argument *A = dyn_cast(V)) { if (Function *P = A->getParent()) ST = &P->getValueSymbolTable(); + } else if (Comdat *C = dyn_cast(V)) { + if (Module *P = C->getParent()) + ST = &P->getComdatSymbolTable(); } else if (isa(V)) return true; else { Index: test/Feature/comdat.ll =================================================================== --- /dev/null +++ test/Feature/comdat.ll @@ -0,0 +1,14 @@ +; RUN: llvm-as < %s | llvm-dis | FileCheck %s + +$f = comdat any +; CHECK: $f = comdat any + +@v = global i32 0, comdat $f +; CHECK: @v = global i32 0, comdat $f +@a = alias i32* @v, comdat $f +; CHECK: @a = alias i32* @v, comdat $f + +define void @f() comdat $f { + ret void +} +; CHECK: define void @f() comdat $f Index: test/Instrumentation/AddressSanitizer/do-not-instrument-llvm-metadata.ll =================================================================== --- test/Instrumentation/AddressSanitizer/do-not-instrument-llvm-metadata.ll +++ test/Instrumentation/AddressSanitizer/do-not-instrument-llvm-metadata.ll @@ -5,7 +5,7 @@ target triple = "x86_64-unknown-linux-gnu" @.str_noinst = private unnamed_addr constant [4 x i8] c"aaa\00", section "llvm.metadata" -@.str_inst = private unnamed_addr constant [4 x i8] c"aaa\00", +@.str_inst = private unnamed_addr constant [4 x i8] c"aaa\00" ; CHECK-NOT: {{asan_gen.*str_noinst}} ; CHECK: {{asan_gen.*str_inst}} Index: test/MC/COFF/comdat.ll =================================================================== --- /dev/null +++ test/MC/COFF/comdat.ll @@ -0,0 +1,62 @@ +; RUN: llc -mtriple i386-pc-win32 < %s | FileCheck %s + +$f1 = comdat any +@v1 = global i32 0, comdat $f1 +define void @f1() comdat $f1 { + ret void +} + +$f2 = comdat exactmatch +@v2 = global i32 0, comdat $f2 +define void @f2() comdat $f2 { + ret void +} + +$f3 = comdat largest +@v3 = global i32 0, comdat $f3 +define void @f3() comdat $f3 { + ret void +} + +$f4 = comdat newest +@v4 = global i32 0, comdat $f4 +define void @f4() comdat $f4 { + ret void +} + +$f5 = comdat noduplicates +@v5 = global i32 0, comdat $f5 +define void @f5() comdat $f5 { + ret void +} + +$f6 = comdat samesize +@v6 = global i32 0, comdat $f6 +define void @f6() comdat $f6 { + ret void +} + +; CHECK: .section .text,"xr",discard,_f1 +; CHECK: .globl _f1 +; CHECK: .section .text,"xr",same_contents,_f2 +; CHECK: .globl _f2 +; CHECK: .section .text,"xr",largest,_f3 +; CHECK: .globl _f3 +; CHECK: .section .text,"xr",newest,_f4 +; CHECK: .globl _f4 +; CHECK: .section .text,"xr",one_only,_f5 +; CHECK: .globl _f5 +; CHECK: .section .text,"xr",same_size,_f6 +; CHECK: .globl _f6 +; CHECK: .section .bss,"bw",associative,_f1 +; CHECK: .globl _v1 +; CHECK: .section .bss,"bw",associative,_f2 +; CHECK: .globl _v2 +; CHECK: .section .bss,"bw",associative,_f3 +; CHECK: .globl _v3 +; CHECK: .section .bss,"bw",associative,_f4 +; CHECK: .globl _v4 +; CHECK: .section .bss,"bw",associative,_f5 +; CHECK: .globl _v5 +; CHECK: .section .bss,"bw",associative,_f6 +; CHECK: .globl _v6 Index: test/MC/ELF/comdat.ll =================================================================== --- /dev/null +++ test/MC/ELF/comdat.ll @@ -0,0 +1,11 @@ +; RUN: llc -mtriple x86_64-pc-linux-gnu < %s | FileCheck %s + +$f = comdat any +@v = global i32 0, comdat $f +define void @f() comdat $f { + ret void +} +; CHECK: .section .text.f,"axG",@progbits,f,comdat +; CHECK: .globl f +; CHECK: .section .bss.v,"aGw",@nobits,f,comdat +; CHECK: .globl v Index: test/MC/MachO/comdat.ll =================================================================== --- /dev/null +++ test/MC/MachO/comdat.ll @@ -0,0 +1,6 @@ +; RUN: not llc -mtriple x86_64-apple-darwin < %s 2> %t +; RUN: FileCheck < %t %s + +$f = comdat any +@v = global i32 0, comdat $f +; CHECK: LLVM ERROR: MachO doesn't support COMDATs, 'f' cannot be lowered.