diff --git a/include/llvm/Module.h b/include/llvm/Module.h index 8ce5ec4f1d1..046798845be 100644 --- a/include/llvm/Module.h +++ b/include/llvm/Module.h @@ -154,6 +154,31 @@ public: /// An enumeration for describing the size of a pointer on the target machine. enum PointerSize { AnyPointerSize, Pointer32, Pointer64 }; + /// An enumeration for the supported behaviors of module flags. The following + /// module flags behavior values are supported: + /// + /// Value Behavior + /// ----- -------- + /// 1 Error + /// Emits an error if two values disagree. + /// + /// 2 Warning + /// Emits a warning if two values disagree. + /// + /// 3 Require + /// Emits an error when the specified value is not present + /// or doesn't have the specified value. It is an error for + /// two (or more) llvm.module.flags with the same ID to have + /// the Require behavior but different values. There may be + /// multiple Require flags per ID. + /// + /// 4 Override + /// Uses the specified value if the two values disagree. It + /// is an error for two (or more) llvm.module.flags with the + /// same ID to have the Override behavior but different + /// values. + enum ModAttrBehavior { Error = 1, Warning = 2, Require = 3, Override = 4 }; + /// @} /// @name Member Variables /// @{ @@ -372,6 +397,27 @@ public: /// and delete it. void eraseNamedMetadata(NamedMDNode *NMD); +/// @} +/// @name Module Flags Accessors +/// @{ + + /// getModuleFlagsMetadata - Returns the NamedMDNode in the module that + /// represents module-level flags. This method returns null if there are no + /// module-level flags. + NamedMDNode *getModuleFlagsMetadata() const; + + /// getOrInsertModuleFlagsMetadata - Returns the NamedMDNode in the module + /// that represents module-level flags. If module-level flags aren't found, + /// it creates the named metadata that contains them. + NamedMDNode *getOrInsertModuleFlagsMetadata(); + + /// addModuleFlag - Add a module-level flag to the module-level flags + /// metadata. It will create the module-level flags named metadata if it + /// doesn't already exist. + void addModuleFlag(ModAttrBehavior Behavior, StringRef Key, Value *Val); + void addModuleFlag(ModAttrBehavior Behavior, StringRef Key, uint32_t Val); + void addModuleFlag(MDNode *Node); + /// @} /// @name Materialization /// @{ diff --git a/lib/Linker/LinkModules.cpp b/lib/Linker/LinkModules.cpp index 73ae6ad8c2d..8e2fc4fe3fd 100644 --- a/lib/Linker/LinkModules.cpp +++ b/lib/Linker/LinkModules.cpp @@ -16,8 +16,10 @@ #include "llvm/DerivedTypes.h" #include "llvm/Instructions.h" #include "llvm/Module.h" -#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Path.h" #include "llvm/Transforms/Utils/Cloning.h" @@ -406,11 +408,19 @@ namespace { } void computeTypeMapping(); + bool categorizeModuleFlagNodes(const NamedMDNode *ModFlags, + DenseMap &ErrorNode, + DenseMap &WarningNode, + DenseMap &OverrideNode, + DenseMap > &RequireNodes, + SmallSetVector &SeenIDs); bool linkAppendingVarProto(GlobalVariable *DstGV, GlobalVariable *SrcGV); bool linkGlobalProto(GlobalVariable *SrcGV); bool linkFunctionProto(Function *SrcF); bool linkAliasProto(GlobalAlias *SrcA); + bool linkModuleFlagsMetadata(); void linkAppendingVarInit(const AppendingVarInfo &AVI); void linkGlobalInits(); @@ -938,8 +948,11 @@ void ModuleLinker::linkAliasBodies() { /// linkNamedMDNodes - Insert all of the named mdnodes in Src into the Dest /// module. void ModuleLinker::linkNamedMDNodes() { + const NamedMDNode *SrcModFlags = SrcM->getModuleFlagsMetadata(); for (Module::const_named_metadata_iterator I = SrcM->named_metadata_begin(), E = SrcM->named_metadata_end(); I != E; ++I) { + // Don't link module flags here. Do them separately. + if (&*I == SrcModFlags) continue; NamedMDNode *DestNMD = DstM->getOrInsertNamedMetadata(I->getName()); // Add Src elements into Dest node. for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i) @@ -947,10 +960,175 @@ void ModuleLinker::linkNamedMDNodes() { RF_None, &TypeMap)); } } + +/// categorizeModuleFlagNodes - +bool ModuleLinker:: +categorizeModuleFlagNodes(const NamedMDNode *ModFlags, + DenseMap &ErrorNode, + DenseMap &WarningNode, + DenseMap &OverrideNode, + DenseMap > &RequireNodes, + SmallSetVector &SeenIDs) { + bool HasErr = false; + + for (unsigned I = 0, E = ModFlags->getNumOperands(); I != E; ++I) { + MDNode *Op = ModFlags->getOperand(I); + assert(Op->getNumOperands() == 3 && "Invalid module flag metadata!"); + assert(isa(Op->getOperand(0)) && + "Module flag's first operand must be an integer!"); + assert(isa(Op->getOperand(1)) && + "Module flag's second operand must be an MDString!"); + + ConstantInt *Behavior = cast(Op->getOperand(0)); + MDString *ID = cast(Op->getOperand(1)); + Value *Val = Op->getOperand(2); + switch (Behavior->getZExtValue()) { + default: + assert(false && "Invalid behavior in module flag metadata!"); + break; + case Module::Error: { + MDNode *&ErrNode = ErrorNode[ID]; + if (!ErrNode) ErrNode = Op; + if (ErrNode->getOperand(2) != Val) + HasErr = emitError("Linking module flags '" + ID->getString() + + "': IDs have conflicting values!"); + break; + } + case Module::Warning: { + MDNode *&WarnNode = WarningNode[ID]; + if (!WarnNode) WarnNode = Op; + if (WarnNode->getOperand(2) != Val) + errs() << "WARNING: Linking module flags '" << ID->getString() + << "': IDs have conflicting values!"; + break; + } + case Module::Require: RequireNodes[ID].insert(Op); break; + case Module::Override: { + MDNode *&OvrNode = OverrideNode[ID]; + if (!OvrNode) OvrNode = Op; + if (OvrNode->getOperand(2) != Val) + HasErr = emitError("Linking module flags '" + ID->getString() + + "': IDs have conflicting override values!"); + break; + } + } + + SeenIDs.insert(ID); + } + + return HasErr; +} + +/// linkModuleFlagsMetadata - Merge the linker flags in Src into the Dest +/// module. +bool ModuleLinker::linkModuleFlagsMetadata() { + const NamedMDNode *SrcModFlags = SrcM->getModuleFlagsMetadata(); + if (!SrcModFlags) return false; + + NamedMDNode *DstModFlags = DstM->getOrInsertModuleFlagsMetadata(); + + // If the destination module doesn't have module flags yet, then just copy + // over the source module's flags. + if (DstModFlags->getNumOperands() == 0) { + for (unsigned I = 0, E = SrcModFlags->getNumOperands(); I != E; ++I) + DstModFlags->addOperand(SrcModFlags->getOperand(I)); + + return false; + } + + bool HasErr = false; + + // Otherwise, we have to merge them based on their behaviors. First, + // categorize all of the nodes in the modules' module flags. If an error or + // warning occurs, then emit the appropriate message(s). + DenseMap ErrorNode; + DenseMap WarningNode; + DenseMap OverrideNode; + DenseMap > RequireNodes; + SmallSetVector SeenIDs; + + HasErr |= categorizeModuleFlagNodes(SrcModFlags, ErrorNode, WarningNode, + OverrideNode, RequireNodes, SeenIDs); + HasErr |= categorizeModuleFlagNodes(DstModFlags, ErrorNode, WarningNode, + OverrideNode, RequireNodes, SeenIDs); + + // Check that there isn't both an error and warning node for a flag. + for (SmallSetVector::iterator + I = SeenIDs.begin(), E = SeenIDs.end(); I != E; ++I) { + MDString *ID = *I; + if (ErrorNode[ID] && WarningNode[ID]) + HasErr = emitError("Linking module flags '" + ID->getString() + + "': IDs have conflicting behaviors"); + } + + // Early exit if we had an error. + if (HasErr) return true; + + // Get the destination's module flags ready for new operands. + DstModFlags->dropAllReferences(); + + // Add all of the module flags to the destination module. + DenseMap > AddedNodes; + for (SmallSetVector::iterator + I = SeenIDs.begin(), E = SeenIDs.end(); I != E; ++I) { + MDString *ID = *I; + if (OverrideNode[ID]) { + DstModFlags->addOperand(OverrideNode[ID]); + AddedNodes[ID].push_back(OverrideNode[ID]); + } else if (ErrorNode[ID]) { + DstModFlags->addOperand(ErrorNode[ID]); + AddedNodes[ID].push_back(ErrorNode[ID]); + } else if (WarningNode[ID]) { + DstModFlags->addOperand(WarningNode[ID]); + AddedNodes[ID].push_back(WarningNode[ID]); + } + + for (SmallSetVector::iterator + II = RequireNodes[ID].begin(), IE = RequireNodes[ID].end(); + II != IE; ++II) + DstModFlags->addOperand(*II); + } + + // Now check that all of the requirements have been satisfied. + for (SmallSetVector::iterator + I = SeenIDs.begin(), E = SeenIDs.end(); I != E; ++I) { + MDString *ID = *I; + SmallSetVector &Set = RequireNodes[ID]; + + for (SmallSetVector::iterator + II = Set.begin(), IE = Set.end(); II != IE; ++II) { + MDNode *Node = *II; + assert(isa(Node->getOperand(2)) && + "Module flag's third operand must be an MDNode!"); + MDNode *Val = cast(Node->getOperand(2)); + + MDString *ReqID = cast(Val->getOperand(0)); + Value *ReqVal = Val->getOperand(1); + + bool HasValue = false; + for (SmallVectorImpl::iterator + RI = AddedNodes[ReqID].begin(), RE = AddedNodes[ReqID].end(); + RI != RE; ++RI) { + MDNode *ReqNode = *RI; + if (ReqNode->getOperand(2) == ReqVal) { + HasValue = true; + break; + } + } + + if (!HasValue) + HasErr = emitError("Linking module flags '" + ReqID->getString() + + "': does not have the required value!"); + } + } + + return HasErr; +} bool ModuleLinker::run() { - assert(DstM && "Null Destination module"); - assert(SrcM && "Null Source Module"); + assert(DstM && "Null destination module"); + assert(SrcM && "Null source module"); // Inherit the target data from the source module if the destination module // doesn't have one already. @@ -1030,7 +1208,6 @@ bool ModuleLinker::run() { // Link in the function bodies that are defined in the source module into // DstM. for (Module::iterator SF = SrcM->begin(), E = SrcM->end(); SF != E; ++SF) { - // Skip if not linking from source. if (DoNotLinkFromSource.count(SF)) continue; @@ -1048,11 +1225,15 @@ bool ModuleLinker::run() { // Resolve all uses of aliases with aliasees. linkAliasBodies(); - // Remap all of the named mdnoes in Src into the DstM module. We do this + // Remap all of the named MDNodes in Src into the DstM module. We do this // after linking GlobalValues so that MDNodes that reference GlobalValues // are properly remapped. linkNamedMDNodes(); + // Merge the module flags into the DstM module. + if (linkModuleFlagsMetadata()) + return true; + // Process vector of lazily linked in functions. bool LinkedInAnyFunctions; do { diff --git a/lib/VMCore/Module.cpp b/lib/VMCore/Module.cpp index c29029bf6c0..09468184cc1 100644 --- a/lib/VMCore/Module.cpp +++ b/lib/VMCore/Module.cpp @@ -321,11 +321,51 @@ NamedMDNode *Module::getOrInsertNamedMetadata(StringRef Name) { return NMD; } +/// eraseNamedMetadata - Remove the given NamedMDNode from this module and +/// delete it. void Module::eraseNamedMetadata(NamedMDNode *NMD) { static_cast *>(NamedMDSymTab)->erase(NMD->getName()); NamedMDList.erase(NMD); } +/// getModuleFlagsMetadata - Returns the NamedMDNode in the module that +/// represents module-level flags. This method returns null if there are no +/// module-level flags. +NamedMDNode *Module::getModuleFlagsMetadata() const { + return getNamedMetadata("llvm.module.flags"); +} + +/// getOrInsertModuleFlagsMetadata - Returns the NamedMDNode in the module that +/// represents module-level flags. If module-level flags aren't found, it +/// creates the named metadata that contains them. +NamedMDNode *Module::getOrInsertModuleFlagsMetadata() { + return getOrInsertNamedMetadata("llvm.module.flags"); +} + +/// addModuleFlag - Add a module-level flag to the module-level flags +/// metadata. It will create the module-level flags named metadata if it doesn't +/// already exist. +void Module::addModuleFlag(ModAttrBehavior Behavior, StringRef Key, + Value *Val) { + Type *Int32Ty = Type::getInt32Ty(Context); + Value *Ops[3] = { + ConstantInt::get(Int32Ty, Behavior), MDString::get(Context, Key), Val + }; + getOrInsertModuleFlagsMetadata()->addOperand(MDNode::get(Context, Ops)); +} +void Module::addModuleFlag(ModAttrBehavior Behavior, StringRef Key, + uint32_t Val) { + Type *Int32Ty = Type::getInt32Ty(Context); + addModuleFlag(Behavior, Key, ConstantInt::get(Int32Ty, Val)); +} +void Module::addModuleFlag(MDNode *Node) { + assert(Node->getNumOperands() == 3 && + "Invalid number of operands for module flag!"); + assert(isa(Node->getOperand(0)) && + isa(Node->getOperand(1)) && + "Invalid operand types for module flag!"); + getOrInsertModuleFlagsMetadata()->addOperand(Node); +} //===----------------------------------------------------------------------===// // Methods to control the materialization of GlobalValues in the Module. diff --git a/test/Linker/module-flags-1-a.ll b/test/Linker/module-flags-1-a.ll new file mode 100644 index 00000000000..973aa80822c --- /dev/null +++ b/test/Linker/module-flags-1-a.ll @@ -0,0 +1,16 @@ +; RUN: llvm-link %s %p/module-flags-1-b.ll -S -o - | sort | FileCheck %s + +; Test basic functionality of module flags. + +; CHECK: !0 = metadata !{i32 1, metadata !"foo", i32 37} +; CHECK: !1 = metadata !{i32 1, metadata !"qux", i32 42} +; CHECK: !2 = metadata !{i32 1, metadata !"mux", metadata !3} +; CHECK: !3 = metadata !{metadata !"hello world", i32 927} +; CHECK: !4 = metadata !{i32 2, metadata !"bar", i32 42} +; CHECK: !llvm.module.flags = !{!0, !1, !2, !4} + +!0 = metadata !{ i32 1, metadata !"foo", i32 37 } +!1 = metadata !{ i32 2, metadata !"bar", i32 42 } +!2 = metadata !{ i32 1, metadata !"mux", metadata !{ metadata !"hello world", i32 927 } } + +!llvm.module.flags = !{ !0, !1, !2 } diff --git a/test/Linker/module-flags-1-b.ll b/test/Linker/module-flags-1-b.ll new file mode 100644 index 00000000000..bf3f5e55550 --- /dev/null +++ b/test/Linker/module-flags-1-b.ll @@ -0,0 +1,8 @@ +; This file is used with module-flags-1-a.ll +; RUN: true + +!0 = metadata !{ i32 1, metadata !"foo", i32 37 } +!1 = metadata !{ i32 1, metadata !"qux", i32 42 } +!2 = metadata !{ i32 1, metadata !"mux", metadata !{ metadata !"hello world", i32 927 } } + +!llvm.module.flags = !{ !0, !1, !2 } diff --git a/test/Linker/module-flags-2-a.ll b/test/Linker/module-flags-2-a.ll new file mode 100644 index 00000000000..3ae02889d16 --- /dev/null +++ b/test/Linker/module-flags-2-a.ll @@ -0,0 +1,10 @@ +; RUN: llvm-link %s %p/module-flags-2-b.ll -S -o - | sort | FileCheck %s + +; Test the 'override' behavior. + +; CHECK: !0 = metadata !{i32 4, metadata !"foo", i32 37} +; CHECK: !llvm.module.flags = !{!0} + +!0 = metadata !{ i32 1, metadata !"foo", i32 927 } + +!llvm.module.flags = !{ !0 } diff --git a/test/Linker/module-flags-2-b.ll b/test/Linker/module-flags-2-b.ll new file mode 100644 index 00000000000..ab55e4b997c --- /dev/null +++ b/test/Linker/module-flags-2-b.ll @@ -0,0 +1,6 @@ +; This file is used with module-flags-2-a.ll +; RUN: true + +!0 = metadata !{ i32 4, metadata !"foo", i32 37 } ; Override the "foo" value. + +!llvm.module.flags = !{ !0 } diff --git a/test/Linker/module-flags-3-a.ll b/test/Linker/module-flags-3-a.ll new file mode 100644 index 00000000000..4233a0a7a5b --- /dev/null +++ b/test/Linker/module-flags-3-a.ll @@ -0,0 +1,14 @@ +; RUN: llvm-link %s %p/module-flags-3-b.ll -S -o - | sort | FileCheck %s + +; Test 'require' behavior. + +; CHECK: !0 = metadata !{i32 1, metadata !"foo", i32 37} +; CHECK: !1 = metadata !{i32 3, metadata !"foo", metadata !2} +; CHECK: !2 = metadata !{metadata !"bar", i32 42} +; CHECK: !3 = metadata !{i32 1, metadata !"bar", i32 42} +; CHECK: !llvm.module.flags = !{!0, !1, !3} + +!0 = metadata !{ i32 1, metadata !"foo", i32 37 } +!1 = metadata !{ i32 1, metadata !"bar", i32 42 } + +!llvm.module.flags = !{ !0, !1 } diff --git a/test/Linker/module-flags-3-b.ll b/test/Linker/module-flags-3-b.ll new file mode 100644 index 00000000000..76be8026337 --- /dev/null +++ b/test/Linker/module-flags-3-b.ll @@ -0,0 +1,8 @@ +; This file is used with module-flags-3-a.ll +; RUN: true + +!0 = metadata !{ i32 3, metadata !"foo", + metadata !{ metadata !"bar", i32 42 } +} + +!llvm.module.flags = !{ !0 } diff --git a/test/Linker/module-flags-4-a.ll b/test/Linker/module-flags-4-a.ll new file mode 100644 index 00000000000..0199ef486cc --- /dev/null +++ b/test/Linker/module-flags-4-a.ll @@ -0,0 +1,10 @@ +; RUN: not llvm-link %s %p/module-flags-4-b.ll -S -o - |& FileCheck %s + +; Test 'require' error. + +; CHECK: Linking module flags 'bar': does not have the required value + +!0 = metadata !{ i32 1, metadata !"foo", i32 37 } +!1 = metadata !{ i32 1, metadata !"bar", i32 927 } + +!llvm.module.flags = !{ !0, !1 } diff --git a/test/Linker/module-flags-4-b.ll b/test/Linker/module-flags-4-b.ll new file mode 100644 index 00000000000..3a460bbeb0b --- /dev/null +++ b/test/Linker/module-flags-4-b.ll @@ -0,0 +1,8 @@ +; This file is used with module-flags-4-a.ll +; RUN: true + +!0 = metadata !{ i32 3, metadata !"foo", + metadata !{ metadata !"bar", i32 42 } +} + +!llvm.module.flags = !{ !0 } diff --git a/test/Linker/module-flags-5-a.ll b/test/Linker/module-flags-5-a.ll new file mode 100644 index 00000000000..21b20a31efd --- /dev/null +++ b/test/Linker/module-flags-5-a.ll @@ -0,0 +1,9 @@ +; RUN: not llvm-link %s %p/module-flags-5-b.ll -S -o - |& FileCheck %s + +; Test the 'override' error. + +; CHECK: Linking module flags 'foo': IDs have conflicting override values + +!0 = metadata !{ i32 4, metadata !"foo", i32 927 } + +!llvm.module.flags = !{ !0 } diff --git a/test/Linker/module-flags-5-b.ll b/test/Linker/module-flags-5-b.ll new file mode 100644 index 00000000000..1e99b207544 --- /dev/null +++ b/test/Linker/module-flags-5-b.ll @@ -0,0 +1,6 @@ +; This file is used with module-flags-5-a.ll +; RUN: true + +!0 = metadata !{ i32 4, metadata !"foo", i32 37 } ; Override the "foo" value. + +!llvm.module.flags = !{ !0 } diff --git a/test/Linker/module-flags-6-a.ll b/test/Linker/module-flags-6-a.ll new file mode 100644 index 00000000000..aeade470ca1 --- /dev/null +++ b/test/Linker/module-flags-6-a.ll @@ -0,0 +1,9 @@ +; RUN: not llvm-link %s %p/module-flags-6-b.ll -S -o - |& FileCheck %s + +; Test module flags error messages. + +; CHECK: Linking module flags 'foo': IDs have conflicting values + +!0 = metadata !{ i32 1, metadata !"foo", i32 37 } + +!llvm.module.flags = !{ !0 } diff --git a/test/Linker/module-flags-6-b.ll b/test/Linker/module-flags-6-b.ll new file mode 100644 index 00000000000..2bc5a96045b --- /dev/null +++ b/test/Linker/module-flags-6-b.ll @@ -0,0 +1,6 @@ +; This file is used with module-flags-6-a.ll +; RUN: true + +!0 = metadata !{ i32 1, metadata !"foo", i32 38 } + +!llvm.module.flags = !{ !0 }