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
This commit is contained in:
Duncan P. N. Exon Smith 2015-01-08 22:38:29 +00:00
parent 1cbba214c7
commit f416d72973
20 changed files with 110 additions and 54 deletions

View File

@ -2848,6 +2848,12 @@ their operand. For example:
!{ !"test\00", i32 10} !{ !"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 <namedmetadatastructure>` is a collection of A :ref:`named metadata <namedmetadatastructure>` is a collection of
metadata nodes, which can be looked up in the module symbol table. For metadata nodes, which can be looked up in the module symbol table. For
example: example:

View File

@ -140,7 +140,7 @@ namespace bitc {
METADATA_VALUE = 2, // VALUE: [type num, value num] METADATA_VALUE = 2, // VALUE: [type num, value num]
METADATA_NODE = 3, // NODE: [n x md num] METADATA_NODE = 3, // NODE: [n x md num]
METADATA_NAME = 4, // STRING: [values] 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]] METADATA_KIND = 6, // [n x [id, name]]
// 7 is unused. // 7 is unused.
METADATA_OLD_NODE = 8, // OLD_NODE: [n x (type num, value num)] METADATA_OLD_NODE = 8, // OLD_NODE: [n x (type num, value num)]

View File

@ -655,6 +655,9 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(x); KEYWORD(x);
KEYWORD(blockaddress); KEYWORD(blockaddress);
// Metadata types.
KEYWORD(distinct);
// Use-list order directives. // Use-list order directives.
KEYWORD(uselistorder); KEYWORD(uselistorder);
KEYWORD(uselistorder_bb); KEYWORD(uselistorder_bb);

View File

@ -618,8 +618,9 @@ bool LLParser::ParseStandaloneMetadata() {
if (Lex.getKind() == lltok::Type) if (Lex.getKind() == lltok::Type)
return TokError("unexpected type in metadata definition"); return TokError("unexpected type in metadata definition");
bool IsDistinct = EatIfPresent(lltok::kw_distinct);
if (ParseToken(lltok::exclaim, "Expected '!' here") || if (ParseToken(lltok::exclaim, "Expected '!' here") ||
ParseMDNode(Init)) ParseMDNode(Init, IsDistinct))
return true; return true;
// See if this was forward referenced, if so, handle it. // See if this was forward referenced, if so, handle it.
@ -2945,11 +2946,14 @@ bool LLParser::ParseGlobalValueVector(SmallVectorImpl<Constant *> &Elts) {
return false; return false;
} }
bool LLParser::ParseMDNode(MDNode *&MD) { bool LLParser::ParseMDNode(MDNode *&MD, bool IsDistinct) {
SmallVector<Metadata *, 16> Elts; SmallVector<Metadata *, 16> Elts;
if (ParseMDNodeVector(Elts)) if (ParseMDNodeVector(Elts))
return true; return true;
if (IsDistinct)
MD = MDNode::getDistinct(Context, Elts);
else
MD = MDNode::get(Context, Elts); MD = MDNode::get(Context, Elts);
return false; return false;
} }

View File

@ -389,7 +389,7 @@ namespace llvm {
bool ParseMetadataAsValue(Value *&V, PerFunctionState &PFS); bool ParseMetadataAsValue(Value *&V, PerFunctionState &PFS);
bool ParseValueAsMetadata(Metadata *&MD, PerFunctionState *PFS); bool ParseValueAsMetadata(Metadata *&MD, PerFunctionState *PFS);
bool ParseMetadata(Metadata *&MD, PerFunctionState *PFS); bool ParseMetadata(Metadata *&MD, PerFunctionState *PFS);
bool ParseMDNode(MDNode *&MD); bool ParseMDNode(MDNode *&MD, bool IsDistinct = false);
bool ParseMDNodeVector(SmallVectorImpl<Metadata *> &MDs); bool ParseMDNodeVector(SmallVectorImpl<Metadata *> &MDs);
bool ParseInstructionMetadata(Instruction *Inst, PerFunctionState *PFS); bool ParseInstructionMetadata(Instruction *Inst, PerFunctionState *PFS);

View File

@ -182,6 +182,9 @@ namespace lltok {
kw_extractelement, kw_insertelement, kw_shufflevector, kw_extractelement, kw_insertelement, kw_shufflevector,
kw_extractvalue, kw_insertvalue, kw_blockaddress, kw_extractvalue, kw_insertvalue, kw_blockaddress,
// Metadata types.
kw_distinct,
// Use-list order directives. // Use-list order directives.
kw_uselistorder, kw_uselistorder_bb, kw_uselistorder, kw_uselistorder_bb,

View File

@ -1106,6 +1106,7 @@ std::error_code BitcodeReader::ParseMetadata() {
// Read a record. // Read a record.
Record.clear(); Record.clear();
unsigned Code = Stream.readRecord(Entry.ID, Record); unsigned Code = Stream.readRecord(Entry.ID, Record);
bool IsDistinct = false;
switch (Code) { switch (Code) {
default: // Default behavior: ignore. default: // Default behavior: ignore.
break; break;
@ -1196,12 +1197,17 @@ std::error_code BitcodeReader::ParseMetadata() {
NextMDValueNo++); NextMDValueNo++);
break; break;
} }
case bitc::METADATA_DISTINCT_NODE:
IsDistinct = true;
// fallthrough...
case bitc::METADATA_NODE: { case bitc::METADATA_NODE: {
SmallVector<Metadata *, 8> Elts; SmallVector<Metadata *, 8> Elts;
Elts.reserve(Record.size()); Elts.reserve(Record.size());
for (unsigned ID : Record) for (unsigned ID : Record)
Elts.push_back(ID ? MDValueList.getValueFwdRef(ID - 1) : nullptr); 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; break;
} }
case bitc::METADATA_STRING: { case bitc::METADATA_STRING: {

View File

@ -773,7 +773,9 @@ static void WriteMDNode(const MDNode *N,
assert(!isa<LocalAsMetadata>(MD) && "Unexpected function-local metadata"); assert(!isa<LocalAsMetadata>(MD) && "Unexpected function-local metadata");
Record.push_back(VE.getMetadataID(MD) + 1); 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(); Record.clear();
} }

View File

@ -1253,6 +1253,8 @@ static void WriteMDNodeBodyInternal(raw_ostream &Out, const MDNode *Node,
TypePrinting *TypePrinter, TypePrinting *TypePrinter,
SlotTracker *Machine, SlotTracker *Machine,
const Module *Context) { const Module *Context) {
if (Node->isDistinct())
Out << "distinct ";
Out << "!{"; Out << "!{";
for (unsigned mi = 0, me = Node->getNumOperands(); mi != me; ++mi) { for (unsigned mi = 0, me = Node->getNumOperands(); mi != me; ++mi) {
const Metadata *MD = Node->getOperand(mi); const Metadata *MD = Node->getOperand(mi);

View File

@ -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: !

View File

@ -36,9 +36,9 @@ attributes #0 = { nounwind }
attributes #1 = { nounwind uwtable } attributes #1 = { nounwind uwtable }
; CHECK: !0 = !{!1} ; CHECK: !0 = !{!1}
; CHECK: !1 = !{!1, !2, !"hello: %c"} ; CHECK: !1 = distinct !{!1, !2, !"hello: %c"}
; CHECK: !2 = !{!2, !"hello"} ; CHECK: !2 = distinct !{!2, !"hello"}
; CHECK: !3 = !{!4} ; CHECK: !3 = !{!4}
; CHECK: !4 = !{!4, !2, !"hello: %a"} ; CHECK: !4 = distinct !{!4, !2, !"hello: %a"}
; CHECK: !5 = !{!4, !1} ; CHECK: !5 = !{!4, !1}

View File

@ -47,36 +47,36 @@ entry:
attributes #0 = { nounwind uwtable } attributes #0 = { nounwind uwtable }
!0 = !{!1} !0 = !{!1}
!1 = !{!1, !2, !"hello: %a"} !1 = distinct !{!1, !2, !"hello: %a"}
!2 = !{!2, !"hello"} !2 = distinct !{!2, !"hello"}
!3 = !{!4, !6} !3 = !{!4, !6}
!4 = !{!4, !5, !"hello2: %a"} !4 = distinct !{!4, !5, !"hello2: %a"}
!5 = !{!5, !"hello2"} !5 = distinct !{!5, !"hello2"}
!6 = !{!6, !5, !"hello2: %b"} !6 = distinct !{!6, !5, !"hello2: %b"}
!7 = !{!4} !7 = !{!4}
!8 = !{!6} !8 = !{!6}
; CHECK: !0 = !{!1, !3} ; CHECK: !0 = !{!1, !3}
; CHECK: !1 = !{!1, !2, !"hello2: %a"} ; CHECK: !1 = distinct !{!1, !2, !"hello2: %a"}
; CHECK: !2 = !{!2, !"hello2"} ; CHECK: !2 = distinct !{!2, !"hello2"}
; CHECK: !3 = !{!3, !2, !"hello2: %b"} ; CHECK: !3 = distinct !{!3, !2, !"hello2: %b"}
; CHECK: !4 = !{!1} ; CHECK: !4 = !{!1}
; CHECK: !5 = !{!3} ; CHECK: !5 = !{!3}
; CHECK: !6 = !{!7, !9, !10} ; CHECK: !6 = !{!7, !9, !10}
; CHECK: !7 = !{!7, !8, !"hello2: %a"} ; CHECK: !7 = distinct !{!7, !8, !"hello2: %a"}
; CHECK: !8 = !{!8, !"hello2"} ; CHECK: !8 = distinct !{!8, !"hello2"}
; CHECK: !9 = !{!9, !8, !"hello2: %b"} ; CHECK: !9 = distinct !{!9, !8, !"hello2: %b"}
; CHECK: !10 = !{!10, !11, !"hello: %a"} ; CHECK: !10 = distinct !{!10, !11, !"hello: %a"}
; CHECK: !11 = !{!11, !"hello"} ; CHECK: !11 = distinct !{!11, !"hello"}
; CHECK: !12 = !{!7} ; CHECK: !12 = !{!7}
; CHECK: !13 = !{!9, !10} ; CHECK: !13 = !{!9, !10}
; CHECK: !14 = !{!9} ; CHECK: !14 = !{!9}
; CHECK: !15 = !{!7, !10} ; CHECK: !15 = !{!7, !10}
; CHECK: !16 = !{!10} ; CHECK: !16 = !{!10}
; CHECK: !17 = !{!18, !20} ; CHECK: !17 = !{!18, !20}
; CHECK: !18 = !{!18, !19, !"hello2: %a"} ; CHECK: !18 = distinct !{!18, !19, !"hello2: %a"}
; CHECK: !19 = !{!19, !"hello2"} ; CHECK: !19 = distinct !{!19, !"hello2"}
; CHECK: !20 = !{!20, !19, !"hello2: %b"} ; CHECK: !20 = distinct !{!20, !19, !"hello2: %b"}
; CHECK: !21 = !{!18, !10} ; CHECK: !21 = !{!18, !10}
; CHECK: !22 = !{!20} ; CHECK: !22 = !{!20}
; CHECK: !23 = !{!20, !10} ; CHECK: !23 = !{!20, !10}

View File

@ -65,12 +65,12 @@ entry:
attributes #0 = { nounwind uwtable } attributes #0 = { nounwind uwtable }
; CHECK: !0 = !{!1} ; CHECK: !0 = !{!1}
; CHECK: !1 = !{!1, !2, !"hello: %a"} ; CHECK: !1 = distinct !{!1, !2, !"hello: %a"}
; CHECK: !2 = !{!2, !"hello"} ; CHECK: !2 = distinct !{!2, !"hello"}
; CHECK: !3 = !{!4, !6} ; CHECK: !3 = !{!4, !6}
; CHECK: !4 = !{!4, !5, !"hello2: %a"} ; CHECK: !4 = distinct !{!4, !5, !"hello2: %a"}
; CHECK: !5 = !{!5, !"hello2"} ; CHECK: !5 = distinct !{!5, !"hello2"}
; CHECK: !6 = !{!6, !5, !"hello2: %b"} ; CHECK: !6 = distinct !{!6, !5, !"hello2: %b"}
; CHECK: !7 = !{!4} ; CHECK: !7 = !{!4}
; CHECK: !8 = !{!6} ; CHECK: !8 = !{!6}

View File

@ -72,24 +72,24 @@ entry:
; CHECK: } ; CHECK: }
; CHECK: !0 = !{!1} ; CHECK: !0 = !{!1}
; CHECK: !1 = !{!1, !2, !"hello: %c"} ; CHECK: !1 = distinct !{!1, !2, !"hello: %c"}
; CHECK: !2 = !{!2, !"hello"} ; CHECK: !2 = distinct !{!2, !"hello"}
; CHECK: !3 = !{!4} ; CHECK: !3 = !{!4}
; CHECK: !4 = !{!4, !2, !"hello: %a"} ; CHECK: !4 = distinct !{!4, !2, !"hello: %a"}
; CHECK: !5 = !{!6, !8} ; CHECK: !5 = !{!6, !8}
; CHECK: !6 = !{!6, !7, !"hello: %c"} ; CHECK: !6 = distinct !{!6, !7, !"hello: %c"}
; CHECK: !7 = !{!7, !"hello"} ; CHECK: !7 = distinct !{!7, !"hello"}
; CHECK: !8 = !{!8, !9, !"foo: %c"} ; CHECK: !8 = distinct !{!8, !9, !"foo: %c"}
; CHECK: !9 = !{!9, !"foo"} ; CHECK: !9 = distinct !{!9, !"foo"}
; CHECK: !10 = !{!11, !12} ; CHECK: !10 = !{!11, !12}
; CHECK: !11 = !{!11, !7, !"hello: %a"} ; CHECK: !11 = distinct !{!11, !7, !"hello: %a"}
; CHECK: !12 = !{!12, !9, !"foo: %a"} ; CHECK: !12 = distinct !{!12, !9, !"foo: %a"}
; CHECK: !13 = !{!8} ; CHECK: !13 = !{!8}
; CHECK: !14 = !{!12} ; CHECK: !14 = !{!12}
; CHECK: !15 = !{!16, !18} ; CHECK: !15 = !{!16, !18}
; CHECK: !16 = !{!16, !17, !"hello2: %a"} ; CHECK: !16 = distinct !{!16, !17, !"hello2: %a"}
; CHECK: !17 = !{!17, !"hello2"} ; CHECK: !17 = distinct !{!17, !"hello2"}
; CHECK: !18 = !{!18, !17, !"hello2: %b"} ; CHECK: !18 = distinct !{!18, !17, !"hello2: %b"}
; CHECK: !19 = !{!16} ; CHECK: !19 = !{!16}
; CHECK: !20 = !{!18} ; CHECK: !20 = !{!18}

View File

@ -115,6 +115,6 @@ for.end: ; preds = %for.cond.for.end_cr
ret i16 %res.0.lcssa ret i16 %res.0.lcssa
} }
; CHECK: !0 = !{!0, !1} ; CHECK: !0 = distinct !{!0, !1}
; CHECK: !1 = !{!"llvm.loop.unroll.disable"} ; CHECK: !1 = !{!"llvm.loop.unroll.disable"}

View File

@ -138,12 +138,12 @@ for.inc5.1: ; preds = %for.body3.1
!10 = !{!"llvm.loop.unroll.count", i32 2} !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: ![[VEC_ENABLE]] = !{!"llvm.loop.vectorize.enable", i1 true}
; CHECK: ![[WIDTH_8]] = !{!"llvm.loop.vectorize.width", i32 8} ; CHECK: ![[WIDTH_8]] = !{!"llvm.loop.vectorize.width", i32 8}
; CHECK: ![[UNROLL_DISABLE]] = !{!"llvm.loop.unroll.disable"} ; 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: ![[UNROLL_FULL]] = !{!"llvm.loop.unroll.full"}
; CHECK: ![[LOOP_3]] = !{![[LOOP_3]], ![[UNROLL_DISABLE:.*]]} ; CHECK: ![[LOOP_3]] = distinct !{![[LOOP_3]], ![[UNROLL_DISABLE:.*]]}
; CHECK: ![[LOOP_4]] = !{![[LOOP_4]], ![[UNROLL_DISABLE:.*]]} ; CHECK: ![[LOOP_4]] = distinct !{![[LOOP_4]], ![[UNROLL_DISABLE:.*]]}
; CHECK: ![[LOOP_5]] = !{![[LOOP_5]], ![[UNROLL_DISABLE:.*]]} ; CHECK: ![[LOOP_5]] = distinct !{![[LOOP_5]], ![[UNROLL_DISABLE:.*]]}

View File

@ -39,8 +39,8 @@ for.end: ; preds = %for.body
} }
; Now, we check for the Hint metadata ; 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: [[width]] = !{!"llvm.loop.vectorize.width", i32 1}
; CHECK: [[unroll]] = !{!"llvm.loop.interleave.count", i32 1} ; CHECK: [[unroll]] = !{!"llvm.loop.interleave.count", i32 1}
; CHECK: [[scalar]] = !{[[scalar]], [[width]], [[unroll]]} ; CHECK: [[scalar]] = distinct !{[[scalar]], [[width]], [[unroll]]}

View File

@ -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" } 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: !1 = !{!"llvm.loop.vectorize.width", i32 1}
; CHECK: !2 = !{!"llvm.loop.interleave.count", i32 1} ; CHECK: !2 = !{!"llvm.loop.interleave.count", i32 1}
; CHECK: !3 = !{!3, !1, !2} ; CHECK: !3 = distinct !{!3, !1, !2}
!0 = !{!0, !1} !0 = !{!0, !1}
!1 = !{!"llvm.loop.vectorize.width", i32 1} !1 = !{!"llvm.loop.vectorize.width", i32 1}

View File

@ -53,6 +53,8 @@
`(,(regexp-opt '("extractelement" "insertelement" "shufflevector") 'words) . font-lock-keyword-face) `(,(regexp-opt '("extractelement" "insertelement" "shufflevector") 'words) . font-lock-keyword-face)
;; Aggregate ops ;; Aggregate ops
`(,(regexp-opt '("extractvalue" "insertvalue") 'words) . font-lock-keyword-face) `(,(regexp-opt '("extractvalue" "insertvalue") 'words) . font-lock-keyword-face)
;; Metadata types
`(,(regexp-opt '("distinct") 'words) . font-lock-keyword-face)
;; Use-list order directives ;; Use-list order directives
`(,(regexp-opt '("uselistorder" "uselistorder_bb") 'words) . font-lock-keyword-face) `(,(regexp-opt '("uselistorder" "uselistorder_bb") 'words) . font-lock-keyword-face)

View File

@ -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 arm_aapcscc arm_apcscc asm atomic available_externally
syn keyword llvmKeyword blockaddress byval c catch cc ccc cleanup coldcc common syn keyword llvmKeyword blockaddress byval c catch cc ccc cleanup coldcc common
syn keyword llvmKeyword constant datalayout declare default define deplibs 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 externally_initialized fastcc filter gc global hidden
syn keyword llvmKeyword initialexec inlinehint inreg intel_ocl_bicc inteldialect syn keyword llvmKeyword initialexec inlinehint inreg intel_ocl_bicc inteldialect
syn keyword llvmKeyword internal linkonce linkonce_odr localdynamic localexec syn keyword llvmKeyword internal linkonce linkonce_odr localdynamic localexec