diff --git a/docs/LangRef.rst b/docs/LangRef.rst index 7d9fe417445..23ebad64a31 100644 --- a/docs/LangRef.rst +++ b/docs/LangRef.rst @@ -2508,6 +2508,16 @@ The following behaviors are supported: other module. If both modules specify **Override**, but the values differ, an error will be emitted. + * - 5 + - **Append** + Appends the two values, which are required to be metadata nodes. + + * - 6 + - **AppendUnique** + Appends the two values, which are required to be metadata + nodes. However, duplicate entries in the second list are dropped + during the append operation. + It is an error for a particular unique flag ID to have multiple behaviors, except in the case of **Require** (which adds restrictions on another metadata value) or **Override**. diff --git a/include/llvm/IR/Module.h b/include/llvm/IR/Module.h index f1290a7a28f..4460aa435b9 100644 --- a/include/llvm/IR/Module.h +++ b/include/llvm/IR/Module.h @@ -147,30 +147,38 @@ 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 ModFlagBehavior { Error = 1, Warning = 2, Require = 3, Override = 4 }; + /// This enumeration defines the supported behaviors of module flags. + enum ModFlagBehavior { + /// Emits an error if two values disagree, otherwise the resulting value is + /// that of the operands. + Error = 1, + + /// Emits a warning if two values disagree. The result value will be the + /// operand for the flag from the first module being linked. + Warning = 2, + + /// Adds a requirement that another module flag be present and have a + /// specified value after linking is performed. The value must be a metadata + /// pair, where the first element of the pair is the ID of the module flag + /// to be restricted, and the second element of the pair is the value the + /// module flag should be restricted to. This behavior can be used to + /// restrict the allowable results (via triggering of an error) of linking + /// IDs with the **Override** behavior. + Require = 3, + + /// Uses the specified value, regardless of the behavior or value of the + /// other module. If both modules specify **Override**, but the values + /// differ, an error will be emitted. + Override = 4, + + /// Appends the two values, which are required to be metadata nodes. + Append = 5, + + /// Appends the two values, which are required to be metadata + /// nodes. However, duplicate entries in the second list are dropped + /// during the append operation. + AppendUnique = 6 + }; struct ModuleFlagEntry { ModFlagBehavior Behavior; diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp index 2488a7de169..49821f24f23 100644 --- a/lib/IR/Verifier.cpp +++ b/lib/IR/Verifier.cpp @@ -571,24 +571,25 @@ void Verifier::visitModuleFlag(MDNode *Op, DenseMap&SeenIDs, "invalid behavior operand in module flag (expected constant integer)", Op->getOperand(0)); unsigned BehaviorValue = Behavior->getZExtValue(); - Assert1((Module::Error <= BehaviorValue && - BehaviorValue <= Module::Override), - "invalid behavior operand in module flag (unexpected constant)", - Op->getOperand(0)); Assert1(ID, "invalid ID operand in module flag (expected metadata string)", Op->getOperand(1)); - // Unless this is a "requires" flag, check the ID is unique. - if (BehaviorValue != Module::Require) { - bool Inserted = SeenIDs.insert(std::make_pair(ID, Op)).second; - Assert1(Inserted, - "module flag identifiers must be unique (or of 'require' type)", - ID); - } + // Sanity check the values for behaviors with additional requirements. + switch (BehaviorValue) { + default: + Assert1(false, + "invalid behavior operand in module flag (unexpected constant)", + Op->getOperand(0)); + break; - // If this is a "requires" flag, sanity check the value. - if (BehaviorValue == Module::Require) { + case Module::Error: + case Module::Warning: + case Module::Override: + // These behavior types accept any value. + break; + + case Module::Require: { // The value should itself be an MDNode with two operands, a flag ID (an // MDString), and a value. MDNode *Value = dyn_cast(Op->getOperand(2)); @@ -603,6 +604,25 @@ void Verifier::visitModuleFlag(MDNode *Op, DenseMap&SeenIDs, // Append it to the list of requirements, to check once all module flags are // scanned. Requirements.push_back(Value); + break; + } + + case Module::Append: + case Module::AppendUnique: { + // These behavior types require the operand be an MDNode. + Assert1(isa(Op->getOperand(2)), + "invalid value for 'append'-type module flag " + "(expected a metadata node)", Op->getOperand(2)); + break; + } + } + + // Unless this is a "requires" flag, check the ID is unique. + if (BehaviorValue != Module::Require) { + bool Inserted = SeenIDs.insert(std::make_pair(ID, Op)).second; + Assert1(Inserted, + "module flag identifiers must be unique (or of 'require' type)", + ID); } } diff --git a/lib/Linker/LinkModules.cpp b/lib/Linker/LinkModules.cpp index 1b4ef324d72..3b8928a3245 100644 --- a/lib/Linker/LinkModules.cpp +++ b/lib/Linker/LinkModules.cpp @@ -1086,6 +1086,34 @@ bool ModuleLinker::linkModuleFlagsMetadata() { } continue; } + case Module::Append: { + MDNode *DstValue = cast(DstOp->getOperand(2)); + MDNode *SrcValue = cast(SrcOp->getOperand(2)); + unsigned NumOps = DstValue->getNumOperands() + SrcValue->getNumOperands(); + Value **VP, **Values = VP = new Value*[NumOps]; + for (unsigned i = 0, e = DstValue->getNumOperands(); i != e; ++i, ++VP) + *VP = DstValue->getOperand(i); + for (unsigned i = 0, e = SrcValue->getNumOperands(); i != e; ++i, ++VP) + *VP = SrcValue->getOperand(i); + DstOp->replaceOperandWith(2, MDNode::get(DstM->getContext(), + ArrayRef(Values, + NumOps))); + delete[] Values; + break; + } + case Module::AppendUnique: { + SmallSetVector Elts; + MDNode *DstValue = cast(DstOp->getOperand(2)); + MDNode *SrcValue = cast(SrcOp->getOperand(2)); + for (unsigned i = 0, e = DstValue->getNumOperands(); i != e; ++i) + Elts.insert(DstValue->getOperand(i)); + for (unsigned i = 0, e = SrcValue->getNumOperands(); i != e; ++i) + Elts.insert(SrcValue->getOperand(i)); + DstOp->replaceOperandWith(2, MDNode::get(DstM->getContext(), + ArrayRef(Elts.begin(), + Elts.end()))); + break; + } } } diff --git a/test/Linker/module-flags-8-a.ll b/test/Linker/module-flags-8-a.ll new file mode 100644 index 00000000000..146cae763d6 --- /dev/null +++ b/test/Linker/module-flags-8-a.ll @@ -0,0 +1,14 @@ +; RUN: llvm-link %s %p/module-flags-8-b.ll -S -o - | sort | FileCheck %s + +; Test append-type module flags. + +; CHECK: !0 = metadata !{i32 5, metadata !"flag-0", metadata !1} +; CHECK: !1 = metadata !{i32 0, i32 0, i32 1} +; CHECK: !2 = metadata !{i32 6, metadata !"flag-1", metadata !3} +; CHECK: !3 = metadata !{i32 0, i32 1, i32 2} +; CHECK: !llvm.module.flags = !{!0, !2} + +!0 = metadata !{ i32 5, metadata !"flag-0", metadata !{ i32 0 } } +!1 = metadata !{ i32 6, metadata !"flag-1", metadata !{ i32 0, i32 1 } } + +!llvm.module.flags = !{ !0, !1 } diff --git a/test/Linker/module-flags-8-b.ll b/test/Linker/module-flags-8-b.ll new file mode 100644 index 00000000000..08f9bc49ee5 --- /dev/null +++ b/test/Linker/module-flags-8-b.ll @@ -0,0 +1,7 @@ +; This file is used with module-flags-6-a.ll +; RUN: true + +!0 = metadata !{ i32 5, metadata !"flag-0", metadata !{ i32 0, i32 1 } } +!1 = metadata !{ i32 6, metadata !"flag-1", metadata !{ i32 1, i32 2 } } + +!llvm.module.flags = !{ !0, !1 } diff --git a/test/Verifier/module-flags-1.ll b/test/Verifier/module-flags-1.ll index 94e98171153..e5feaf3a580 100644 --- a/test/Verifier/module-flags-1.ll +++ b/test/Verifier/module-flags-1.ll @@ -33,6 +33,14 @@ !9 = metadata !{ i32 2, metadata !"bar", i32 51 } !10 = metadata !{ i32 3, metadata !"bar", metadata !{ metadata !"bar", i32 51 } } +; Check that any 'append'-type module flags are valid. +; CHECK: invalid value for 'append'-type module flag (expected a metadata node) +!16 = metadata !{ i32 5, metadata !"flag-2", i32 56 } +; CHECK: invalid value for 'append'-type module flag (expected a metadata node) +!17 = metadata !{ i32 5, metadata !"flag-3", i32 57 } +; CHECK-NOT: invalid value for 'append'-type module flag (expected a metadata node) +!18 = metadata !{ i32 5, metadata !"flag-4", metadata !{ i32 57 } } + ; Check that any 'require' module flags are valid. ; CHECK: invalid requirement on flag, flag is not present in module !11 = metadata !{ i32 3, metadata !"bar", @@ -48,4 +56,5 @@ metadata !{ metadata !"flag-1", i32 55 } } !llvm.module.flags = !{ - !0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10, !11, !12, !13, !14, !15 } + !0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10, !11, !12, !13, !14, !15, + !16, !17, !18 }