From: Duncan P. N. Exon Smith Date: Thu, 8 Jan 2015 22:38:29 +0000 (+0000) Subject: IR: Add 'distinct' MDNodes to bitcode and assembly X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=f416d72973fe5a7d2b0acf81a83d52e2e1a85b2c;p=oota-llvm.git IR: Add 'distinct' MDNodes to bitcode and assembly Propagate whether `MDNode`s are 'distinct' through the other types of IR (assembly and bitcode). This adds the `distinct` keyword to assembly. Currently, no one actually calls `MDNode::getDistinct()`, so these nodes only get created for: - self-references, which are never uniqued, and - nodes whose operands are replaced that hit a uniquing collision. The concept of distinct nodes is still not quite first-class, since distinct-ness doesn't yet survive across `MapMetadata()`. Part of PR22111. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@225474 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/docs/LangRef.rst b/docs/LangRef.rst index 5238fe90d30..0a1c7768d5a 100644 --- a/docs/LangRef.rst +++ b/docs/LangRef.rst @@ -2848,6 +2848,12 @@ their operand. For example: !{ !"test\00", i32 10} +Metadata nodes that aren't uniqued use the ``distinct`` keyword. For example: + +.. code-block:: llvm + + !0 = distinct !{!"test\00", i32 10} + A :ref:`named metadata ` is a collection of metadata nodes, which can be looked up in the module symbol table. For example: diff --git a/include/llvm/Bitcode/LLVMBitCodes.h b/include/llvm/Bitcode/LLVMBitCodes.h index a717cdde9ee..81544ea32d2 100644 --- a/include/llvm/Bitcode/LLVMBitCodes.h +++ b/include/llvm/Bitcode/LLVMBitCodes.h @@ -140,7 +140,7 @@ namespace bitc { METADATA_VALUE = 2, // VALUE: [type num, value num] METADATA_NODE = 3, // NODE: [n x md num] METADATA_NAME = 4, // STRING: [values] - // 5 is unused. + METADATA_DISTINCT_NODE = 5, // DISTINCT_NODE: [n x md num] METADATA_KIND = 6, // [n x [id, name]] // 7 is unused. METADATA_OLD_NODE = 8, // OLD_NODE: [n x (type num, value num)] diff --git a/lib/AsmParser/LLLexer.cpp b/lib/AsmParser/LLLexer.cpp index ca3c9e8b6f8..de5db1a4093 100644 --- a/lib/AsmParser/LLLexer.cpp +++ b/lib/AsmParser/LLLexer.cpp @@ -655,6 +655,9 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(x); KEYWORD(blockaddress); + // Metadata types. + KEYWORD(distinct); + // Use-list order directives. KEYWORD(uselistorder); KEYWORD(uselistorder_bb); diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp index 232c580b88f..bcb314dfbd7 100644 --- a/lib/AsmParser/LLParser.cpp +++ b/lib/AsmParser/LLParser.cpp @@ -618,8 +618,9 @@ bool LLParser::ParseStandaloneMetadata() { if (Lex.getKind() == lltok::Type) return TokError("unexpected type in metadata definition"); + bool IsDistinct = EatIfPresent(lltok::kw_distinct); if (ParseToken(lltok::exclaim, "Expected '!' here") || - ParseMDNode(Init)) + ParseMDNode(Init, IsDistinct)) return true; // See if this was forward referenced, if so, handle it. @@ -2945,12 +2946,15 @@ bool LLParser::ParseGlobalValueVector(SmallVectorImpl &Elts) { return false; } -bool LLParser::ParseMDNode(MDNode *&MD) { +bool LLParser::ParseMDNode(MDNode *&MD, bool IsDistinct) { SmallVector Elts; if (ParseMDNodeVector(Elts)) return true; - MD = MDNode::get(Context, Elts); + if (IsDistinct) + MD = MDNode::getDistinct(Context, Elts); + else + MD = MDNode::get(Context, Elts); return false; } diff --git a/lib/AsmParser/LLParser.h b/lib/AsmParser/LLParser.h index d8d272b500d..f1df5b8e54b 100644 --- a/lib/AsmParser/LLParser.h +++ b/lib/AsmParser/LLParser.h @@ -389,7 +389,7 @@ namespace llvm { bool ParseMetadataAsValue(Value *&V, PerFunctionState &PFS); bool ParseValueAsMetadata(Metadata *&MD, PerFunctionState *PFS); bool ParseMetadata(Metadata *&MD, PerFunctionState *PFS); - bool ParseMDNode(MDNode *&MD); + bool ParseMDNode(MDNode *&MD, bool IsDistinct = false); bool ParseMDNodeVector(SmallVectorImpl &MDs); bool ParseInstructionMetadata(Instruction *Inst, PerFunctionState *PFS); diff --git a/lib/AsmParser/LLToken.h b/lib/AsmParser/LLToken.h index a2111ca96e9..4fb01824d9b 100644 --- a/lib/AsmParser/LLToken.h +++ b/lib/AsmParser/LLToken.h @@ -182,6 +182,9 @@ namespace lltok { kw_extractelement, kw_insertelement, kw_shufflevector, kw_extractvalue, kw_insertvalue, kw_blockaddress, + // Metadata types. + kw_distinct, + // Use-list order directives. kw_uselistorder, kw_uselistorder_bb, diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp index 7c7eebde1df..1792f8b8dd4 100644 --- a/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/lib/Bitcode/Reader/BitcodeReader.cpp @@ -1106,6 +1106,7 @@ std::error_code BitcodeReader::ParseMetadata() { // Read a record. Record.clear(); unsigned Code = Stream.readRecord(Entry.ID, Record); + bool IsDistinct = false; switch (Code) { default: // Default behavior: ignore. break; @@ -1196,12 +1197,17 @@ std::error_code BitcodeReader::ParseMetadata() { NextMDValueNo++); break; } + case bitc::METADATA_DISTINCT_NODE: + IsDistinct = true; + // fallthrough... case bitc::METADATA_NODE: { SmallVector Elts; Elts.reserve(Record.size()); for (unsigned ID : Record) Elts.push_back(ID ? MDValueList.getValueFwdRef(ID - 1) : nullptr); - MDValueList.AssignValue(MDNode::get(Context, Elts), NextMDValueNo++); + MDValueList.AssignValue(IsDistinct ? MDNode::getDistinct(Context, Elts) + : MDNode::get(Context, Elts), + NextMDValueNo++); break; } case bitc::METADATA_STRING: { diff --git a/lib/Bitcode/Writer/BitcodeWriter.cpp b/lib/Bitcode/Writer/BitcodeWriter.cpp index 2eb67219c8a..8152799bbce 100644 --- a/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -773,7 +773,9 @@ static void WriteMDNode(const MDNode *N, assert(!isa(MD) && "Unexpected function-local metadata"); Record.push_back(VE.getMetadataID(MD) + 1); } - Stream.EmitRecord(bitc::METADATA_NODE, Record); + Stream.EmitRecord(N->isDistinct() ? bitc::METADATA_DISTINCT_NODE + : bitc::METADATA_NODE, + Record); Record.clear(); } diff --git a/lib/IR/AsmWriter.cpp b/lib/IR/AsmWriter.cpp index 175e20f9794..dc2c5934c2a 100644 --- a/lib/IR/AsmWriter.cpp +++ b/lib/IR/AsmWriter.cpp @@ -1253,6 +1253,8 @@ static void WriteMDNodeBodyInternal(raw_ostream &Out, const MDNode *Node, TypePrinting *TypePrinter, SlotTracker *Machine, const Module *Context) { + if (Node->isDistinct()) + Out << "distinct "; Out << "!{"; for (unsigned mi = 0, me = Node->getNumOperands(); mi != me; ++mi) { const Metadata *MD = Node->getOperand(mi); diff --git a/test/Assembler/distinct-mdnode.ll b/test/Assembler/distinct-mdnode.ll new file mode 100644 index 00000000000..abd7aeacbfc --- /dev/null +++ b/test/Assembler/distinct-mdnode.ll @@ -0,0 +1,28 @@ +; RUN: llvm-as < %s | llvm-dis | FileCheck %s +; RUN: verify-uselistorder %s + +!named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} + +!0 = !{} +!1 = !{} ; This should merge with !0. +!2 = !{!0} +!3 = !{!0} ; This should merge with !2. +!4 = distinct !{} +!5 = distinct !{} +!6 = distinct !{!0} +!7 = distinct !{!0} +!8 = distinct !{!8} +!9 = distinct !{!9} +!10 = !{!10} ; This should become distinct. + +; CHECK: !named = !{!0, !0, !1, !1, !2, !3, !4, !5, !6, !7, !8} +; CHECK: !0 = !{} +; CHECK-NEXT: !1 = !{!0} +; CHECK-NEXT: !2 = distinct !{} +; CHECK-NEXT: !3 = distinct !{} +; CHECK-NEXT: !4 = distinct !{!0} +; CHECK-NEXT: !5 = distinct !{!0} +; CHECK-NEXT: !6 = distinct !{!6} +; CHECK-NEXT: !7 = distinct !{!7} +; CHECK-NEXT: !8 = distinct !{!8} +; CHECK-NOT: ! diff --git a/test/Transforms/Inline/noalias-calls.ll b/test/Transforms/Inline/noalias-calls.ll index 85870f144d9..c09d2a67329 100644 --- a/test/Transforms/Inline/noalias-calls.ll +++ b/test/Transforms/Inline/noalias-calls.ll @@ -36,9 +36,9 @@ attributes #0 = { nounwind } attributes #1 = { nounwind uwtable } ; CHECK: !0 = !{!1} -; CHECK: !1 = !{!1, !2, !"hello: %c"} -; CHECK: !2 = !{!2, !"hello"} +; CHECK: !1 = distinct !{!1, !2, !"hello: %c"} +; CHECK: !2 = distinct !{!2, !"hello"} ; CHECK: !3 = !{!4} -; CHECK: !4 = !{!4, !2, !"hello: %a"} +; CHECK: !4 = distinct !{!4, !2, !"hello: %a"} ; CHECK: !5 = !{!4, !1} diff --git a/test/Transforms/Inline/noalias-cs.ll b/test/Transforms/Inline/noalias-cs.ll index 44bce57b744..da5ddd64ed0 100644 --- a/test/Transforms/Inline/noalias-cs.ll +++ b/test/Transforms/Inline/noalias-cs.ll @@ -47,36 +47,36 @@ entry: attributes #0 = { nounwind uwtable } !0 = !{!1} -!1 = !{!1, !2, !"hello: %a"} -!2 = !{!2, !"hello"} +!1 = distinct !{!1, !2, !"hello: %a"} +!2 = distinct !{!2, !"hello"} !3 = !{!4, !6} -!4 = !{!4, !5, !"hello2: %a"} -!5 = !{!5, !"hello2"} -!6 = !{!6, !5, !"hello2: %b"} +!4 = distinct !{!4, !5, !"hello2: %a"} +!5 = distinct !{!5, !"hello2"} +!6 = distinct !{!6, !5, !"hello2: %b"} !7 = !{!4} !8 = !{!6} ; CHECK: !0 = !{!1, !3} -; CHECK: !1 = !{!1, !2, !"hello2: %a"} -; CHECK: !2 = !{!2, !"hello2"} -; CHECK: !3 = !{!3, !2, !"hello2: %b"} +; CHECK: !1 = distinct !{!1, !2, !"hello2: %a"} +; CHECK: !2 = distinct !{!2, !"hello2"} +; CHECK: !3 = distinct !{!3, !2, !"hello2: %b"} ; CHECK: !4 = !{!1} ; CHECK: !5 = !{!3} ; CHECK: !6 = !{!7, !9, !10} -; CHECK: !7 = !{!7, !8, !"hello2: %a"} -; CHECK: !8 = !{!8, !"hello2"} -; CHECK: !9 = !{!9, !8, !"hello2: %b"} -; CHECK: !10 = !{!10, !11, !"hello: %a"} -; CHECK: !11 = !{!11, !"hello"} +; CHECK: !7 = distinct !{!7, !8, !"hello2: %a"} +; CHECK: !8 = distinct !{!8, !"hello2"} +; CHECK: !9 = distinct !{!9, !8, !"hello2: %b"} +; CHECK: !10 = distinct !{!10, !11, !"hello: %a"} +; CHECK: !11 = distinct !{!11, !"hello"} ; CHECK: !12 = !{!7} ; CHECK: !13 = !{!9, !10} ; CHECK: !14 = !{!9} ; CHECK: !15 = !{!7, !10} ; CHECK: !16 = !{!10} ; CHECK: !17 = !{!18, !20} -; CHECK: !18 = !{!18, !19, !"hello2: %a"} -; CHECK: !19 = !{!19, !"hello2"} -; CHECK: !20 = !{!20, !19, !"hello2: %b"} +; CHECK: !18 = distinct !{!18, !19, !"hello2: %a"} +; CHECK: !19 = distinct !{!19, !"hello2"} +; CHECK: !20 = distinct !{!20, !19, !"hello2: %b"} ; CHECK: !21 = !{!18, !10} ; CHECK: !22 = !{!20} ; CHECK: !23 = !{!20, !10} diff --git a/test/Transforms/Inline/noalias.ll b/test/Transforms/Inline/noalias.ll index 76e4508417e..674da1e2efb 100644 --- a/test/Transforms/Inline/noalias.ll +++ b/test/Transforms/Inline/noalias.ll @@ -65,12 +65,12 @@ entry: attributes #0 = { nounwind uwtable } ; CHECK: !0 = !{!1} -; CHECK: !1 = !{!1, !2, !"hello: %a"} -; CHECK: !2 = !{!2, !"hello"} +; CHECK: !1 = distinct !{!1, !2, !"hello: %a"} +; CHECK: !2 = distinct !{!2, !"hello"} ; CHECK: !3 = !{!4, !6} -; CHECK: !4 = !{!4, !5, !"hello2: %a"} -; CHECK: !5 = !{!5, !"hello2"} -; CHECK: !6 = !{!6, !5, !"hello2: %b"} +; CHECK: !4 = distinct !{!4, !5, !"hello2: %a"} +; CHECK: !5 = distinct !{!5, !"hello2"} +; CHECK: !6 = distinct !{!6, !5, !"hello2: %b"} ; CHECK: !7 = !{!4} ; CHECK: !8 = !{!6} diff --git a/test/Transforms/Inline/noalias2.ll b/test/Transforms/Inline/noalias2.ll index b2734b24019..9c8f8e22d38 100644 --- a/test/Transforms/Inline/noalias2.ll +++ b/test/Transforms/Inline/noalias2.ll @@ -72,24 +72,24 @@ entry: ; CHECK: } ; CHECK: !0 = !{!1} -; CHECK: !1 = !{!1, !2, !"hello: %c"} -; CHECK: !2 = !{!2, !"hello"} +; CHECK: !1 = distinct !{!1, !2, !"hello: %c"} +; CHECK: !2 = distinct !{!2, !"hello"} ; CHECK: !3 = !{!4} -; CHECK: !4 = !{!4, !2, !"hello: %a"} +; CHECK: !4 = distinct !{!4, !2, !"hello: %a"} ; CHECK: !5 = !{!6, !8} -; CHECK: !6 = !{!6, !7, !"hello: %c"} -; CHECK: !7 = !{!7, !"hello"} -; CHECK: !8 = !{!8, !9, !"foo: %c"} -; CHECK: !9 = !{!9, !"foo"} +; CHECK: !6 = distinct !{!6, !7, !"hello: %c"} +; CHECK: !7 = distinct !{!7, !"hello"} +; CHECK: !8 = distinct !{!8, !9, !"foo: %c"} +; CHECK: !9 = distinct !{!9, !"foo"} ; CHECK: !10 = !{!11, !12} -; CHECK: !11 = !{!11, !7, !"hello: %a"} -; CHECK: !12 = !{!12, !9, !"foo: %a"} +; CHECK: !11 = distinct !{!11, !7, !"hello: %a"} +; CHECK: !12 = distinct !{!12, !9, !"foo: %a"} ; CHECK: !13 = !{!8} ; CHECK: !14 = !{!12} ; CHECK: !15 = !{!16, !18} -; CHECK: !16 = !{!16, !17, !"hello2: %a"} -; CHECK: !17 = !{!17, !"hello2"} -; CHECK: !18 = !{!18, !17, !"hello2: %b"} +; CHECK: !16 = distinct !{!16, !17, !"hello2: %a"} +; CHECK: !17 = distinct !{!17, !"hello2"} +; CHECK: !18 = distinct !{!18, !17, !"hello2: %b"} ; CHECK: !19 = !{!16} ; CHECK: !20 = !{!18} diff --git a/test/Transforms/LoopUnroll/runtime-loop.ll b/test/Transforms/LoopUnroll/runtime-loop.ll index 925c3e2a360..3a8777bb147 100644 --- a/test/Transforms/LoopUnroll/runtime-loop.ll +++ b/test/Transforms/LoopUnroll/runtime-loop.ll @@ -115,6 +115,6 @@ for.end: ; preds = %for.cond.for.end_cr ret i16 %res.0.lcssa } -; CHECK: !0 = !{!0, !1} +; CHECK: !0 = distinct !{!0, !1} ; CHECK: !1 = !{!"llvm.loop.unroll.disable"} diff --git a/test/Transforms/LoopUnroll/unroll-pragmas-disabled.ll b/test/Transforms/LoopUnroll/unroll-pragmas-disabled.ll index 748a49e8ff4..4f934a688be 100644 --- a/test/Transforms/LoopUnroll/unroll-pragmas-disabled.ll +++ b/test/Transforms/LoopUnroll/unroll-pragmas-disabled.ll @@ -138,12 +138,12 @@ for.inc5.1: ; preds = %for.body3.1 !10 = !{!"llvm.loop.unroll.count", i32 2} -; CHECK: ![[LOOP_1]] = !{![[LOOP_1]], ![[VEC_ENABLE:.*]], ![[WIDTH_8:.*]], ![[UNROLL_DISABLE:.*]]} +; CHECK: ![[LOOP_1]] = distinct !{![[LOOP_1]], ![[VEC_ENABLE:.*]], ![[WIDTH_8:.*]], ![[UNROLL_DISABLE:.*]]} ; CHECK: ![[VEC_ENABLE]] = !{!"llvm.loop.vectorize.enable", i1 true} ; CHECK: ![[WIDTH_8]] = !{!"llvm.loop.vectorize.width", i32 8} ; CHECK: ![[UNROLL_DISABLE]] = !{!"llvm.loop.unroll.disable"} -; CHECK: ![[LOOP_2]] = !{![[LOOP_2]], ![[UNROLL_FULL:.*]]} +; CHECK: ![[LOOP_2]] = distinct !{![[LOOP_2]], ![[UNROLL_FULL:.*]]} ; CHECK: ![[UNROLL_FULL]] = !{!"llvm.loop.unroll.full"} -; CHECK: ![[LOOP_3]] = !{![[LOOP_3]], ![[UNROLL_DISABLE:.*]]} -; CHECK: ![[LOOP_4]] = !{![[LOOP_4]], ![[UNROLL_DISABLE:.*]]} -; CHECK: ![[LOOP_5]] = !{![[LOOP_5]], ![[UNROLL_DISABLE:.*]]} +; CHECK: ![[LOOP_3]] = distinct !{![[LOOP_3]], ![[UNROLL_DISABLE:.*]]} +; CHECK: ![[LOOP_4]] = distinct !{![[LOOP_4]], ![[UNROLL_DISABLE:.*]]} +; CHECK: ![[LOOP_5]] = distinct !{![[LOOP_5]], ![[UNROLL_DISABLE:.*]]} diff --git a/test/Transforms/LoopVectorize/X86/already-vectorized.ll b/test/Transforms/LoopVectorize/X86/already-vectorized.ll index f3191c86f4a..29d74a0645e 100644 --- a/test/Transforms/LoopVectorize/X86/already-vectorized.ll +++ b/test/Transforms/LoopVectorize/X86/already-vectorized.ll @@ -39,8 +39,8 @@ for.end: ; preds = %for.body } ; Now, we check for the Hint metadata -; CHECK: [[vect]] = !{[[vect]], [[width:![0-9]+]], [[unroll:![0-9]+]]} +; CHECK: [[vect]] = distinct !{[[vect]], [[width:![0-9]+]], [[unroll:![0-9]+]]} ; CHECK: [[width]] = !{!"llvm.loop.vectorize.width", i32 1} ; CHECK: [[unroll]] = !{!"llvm.loop.interleave.count", i32 1} -; CHECK: [[scalar]] = !{[[scalar]], [[width]], [[unroll]]} +; CHECK: [[scalar]] = distinct !{[[scalar]], [[width]], [[unroll]]} diff --git a/test/Transforms/LoopVectorize/vectorize-once.ll b/test/Transforms/LoopVectorize/vectorize-once.ll index 30fdd8f3158..a9b2a53f74b 100644 --- a/test/Transforms/LoopVectorize/vectorize-once.ll +++ b/test/Transforms/LoopVectorize/vectorize-once.ll @@ -68,10 +68,10 @@ _ZSt10accumulateIPiiET0_T_S2_S1_.exit: ; preds = %for.body.i, %entry attributes #0 = { nounwind readonly ssp uwtable "fp-contract-model"="standard" "no-frame-pointer-elim" "no-frame-pointer-elim-non-leaf" "realign-stack" "relocation-model"="pic" "ssp-buffers-size"="8" } -; CHECK: !0 = !{!0, !1, !2} +; CHECK: !0 = distinct !{!0, !1, !2} ; CHECK: !1 = !{!"llvm.loop.vectorize.width", i32 1} ; CHECK: !2 = !{!"llvm.loop.interleave.count", i32 1} -; CHECK: !3 = !{!3, !1, !2} +; CHECK: !3 = distinct !{!3, !1, !2} !0 = !{!0, !1} !1 = !{!"llvm.loop.vectorize.width", i32 1} diff --git a/utils/emacs/llvm-mode.el b/utils/emacs/llvm-mode.el index 6758bdfe870..6d8395cc111 100644 --- a/utils/emacs/llvm-mode.el +++ b/utils/emacs/llvm-mode.el @@ -53,6 +53,8 @@ `(,(regexp-opt '("extractelement" "insertelement" "shufflevector") 'words) . font-lock-keyword-face) ;; Aggregate ops `(,(regexp-opt '("extractvalue" "insertvalue") 'words) . font-lock-keyword-face) + ;; Metadata types + `(,(regexp-opt '("distinct") 'words) . font-lock-keyword-face) ;; Use-list order directives `(,(regexp-opt '("uselistorder" "uselistorder_bb") 'words) . font-lock-keyword-face) diff --git a/utils/vim/llvm.vim b/utils/vim/llvm.vim index 7d413dd2ec4..23a34b51336 100644 --- a/utils/vim/llvm.vim +++ b/utils/vim/llvm.vim @@ -41,7 +41,7 @@ syn keyword llvmKeyword alignstack alwaysinline appending arm_aapcs_vfpcc syn keyword llvmKeyword arm_aapcscc arm_apcscc asm atomic available_externally syn keyword llvmKeyword blockaddress byval c catch cc ccc cleanup coldcc common syn keyword llvmKeyword constant datalayout declare default define deplibs -syn keyword llvmKeyword dllexport dllimport except extern_weak external +syn keyword llvmKeyword distinct dllexport dllimport except extern_weak external syn keyword llvmKeyword externally_initialized fastcc filter gc global hidden syn keyword llvmKeyword initialexec inlinehint inreg intel_ocl_bicc inteldialect syn keyword llvmKeyword internal linkonce linkonce_odr localdynamic localexec