Index: llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp =================================================================== --- llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -591,14 +591,7 @@ if (!MD) return nullptr; - const MDOperand &Op = MD->getOperand(0); - if (!Op.get()) - return nullptr; - - auto *VM = dyn_cast(Op); - if (!VM) - report_fatal_error("MD_associated operand is not ValueAsMetadata"); - + auto *VM = cast(MD->getOperand(0).get()); auto *OtherGV = dyn_cast(VM->getValue()); return OtherGV ? dyn_cast(TM.getSymbol(OtherGV)) : nullptr; } Index: llvm/lib/IR/Verifier.cpp =================================================================== --- llvm/lib/IR/Verifier.cpp +++ llvm/lib/IR/Verifier.cpp @@ -653,6 +653,28 @@ Check(A->value() <= Value::MaximumAlignment, "huge alignment values are unsupported", GO); } + + if (const MDNode *Associated = + GO->getMetadata(LLVMContext::MD_associated)) { + Check(Associated->getNumOperands() == 1, + "associated metadata must have one operand", &GV, Associated); + const Metadata *Op = Associated->getOperand(0).get(); + Check(Op, "associated metadata must have a global value", GO, Associated); + + const auto *VM = dyn_cast_or_null(Op); + Check(VM, "associated metadata must be ValueAsMetadata", GO, Associated); + if (VM) { + Check(isa(VM->getValue()->getType()), + "associated value must be pointer typed", GV, Associated); + + const Value *Stripped = VM->getValue()->stripPointerCastsAndAliases(); + Check(isa(Stripped) || isa(Stripped), + "associated metadata must point to a GlobalObject", GO, Stripped); + Check(Stripped != GO, + "global values should not associate to themselves", GO, + Associated); + } + } } Check(!GV.hasAppendingLinkage() || isa(GV), "Only global variables can have appending linkage!", &GV); Index: llvm/test/Assembler/associated-metadata.ll =================================================================== --- /dev/null +++ llvm/test/Assembler/associated-metadata.ll @@ -0,0 +1,93 @@ +; RUN: llvm-as < %s | llvm-dis | FileCheck %s + +@gv.decl = external constant [8 x i8] +@gv.def = constant [8 x i8] zeroinitializer + +@gv.associated.func.decl = external addrspace(1) constant [8 x i8], !associated !0 +@gv.associated.func.def = external addrspace(1) constant [8 x i8], !associated !1 + +@gv.associated.gv.decl = external addrspace(1) constant [8 x i8], !associated !2 +@gv.associated.gv.def = external addrspace(1) constant [8 x i8], !associated !3 + +@alias = alias i32, ptr @gv.def + +@gv.associated.alias.gv.def = external addrspace(1) constant [8 x i8], !associated !4 + +@gv.associated.alias.addrspacecast = external addrspace(1) constant [8 x i8], !associated !5 +@alias.addrspacecast = alias i32, ptr addrspace(1) addrspacecast (ptr @gv.def to ptr addrspace(1)) + + +@gv.def.associated.addrspacecast = external addrspace(1) constant [8 x i8], !associated !6 + +@ifunc = dso_local ifunc i32 (i32), ptr @ifunc_resolver +@gv.associated.ifunc = external constant [8 x i8], !associated !7 + +@gv.associated.null = external constant [8 x i8], !associated !8 +@gv.associated.inttoptr = external constant [8 x i8], !associated !9 +@gv.associated.poison = external constant [8 x i8], !associated !10 +@gv.associated.undef = external constant [8 x i8], !associated !11 +@associated.addrspacecast.null = external addrspace(1) constant [8 x i8], !associated !12 + + +;. +; CHECK: @[[GV_DECL:[a-zA-Z0-9_$"\\.-]+]] = external constant [8 x i8] +; CHECK: @[[GV_DEF:[a-zA-Z0-9_$"\\.-]+]] = constant [8 x i8] zeroinitializer +; CHECK: @[[GV_ASSOCIATED_FUNC_DECL:[a-zA-Z0-9_$"\\.-]+]] = external addrspace(1) constant [8 x i8], !associated !0 +; CHECK: @[[GV_ASSOCIATED_FUNC_DEF:[a-zA-Z0-9_$"\\.-]+]] = external addrspace(1) constant [8 x i8], !associated !1 +; CHECK: @[[GV_ASSOCIATED_GV_DECL:[a-zA-Z0-9_$"\\.-]+]] = external addrspace(1) constant [8 x i8], !associated !2 +; CHECK: @[[GV_ASSOCIATED_GV_DEF:[a-zA-Z0-9_$"\\.-]+]] = external addrspace(1) constant [8 x i8], !associated !3 +; CHECK: @[[GV_ASSOCIATED_ALIAS_GV_DEF:[a-zA-Z0-9_$"\\.-]+]] = external addrspace(1) constant [8 x i8], !associated !4 +; CHECK: @[[GV_ASSOCIATED_ALIAS_ADDRSPACECAST:[a-zA-Z0-9_$"\\.-]+]] = external addrspace(1) constant [8 x i8], !associated !5 +; CHECK: @[[GV_DEF_ASSOCIATED_ADDRSPACECAST:[a-zA-Z0-9_$"\\.-]+]] = external addrspace(1) constant [8 x i8], !associated !6 +; CHECK: @[[GV_ASSOCIATED_IFUNC:[a-zA-Z0-9_$"\\.-]+]] = external constant [8 x i8], !associated !7 +; CHECK: @[[GV_ASSOCIATED_NULL:[a-zA-Z0-9_$"\\.-]+]] = external constant [8 x i8], !associated !8 +; CHECK: @[[GV_ASSOCIATED_INTTOPTR:[a-zA-Z0-9_$"\\.-]+]] = external constant [8 x i8], !associated !9 +; CHECK: @[[GV_ASSOCIATED_POISON:[a-zA-Z0-9_$"\\.-]+]] = external constant [8 x i8], !associated !10 +; CHECK: @[[GV_ASSOCIATED_UNDEF:[a-zA-Z0-9_$"\\.-]+]] = external constant [8 x i8], !associated !11 +; CHECK: @[[ALIAS:[a-zA-Z0-9_$"\\.-]+]] = alias i32, ptr @gv.def +; CHECK: @[[ALIAS_ADDRSPACECAST:[a-zA-Z0-9_$"\\.-]+]] = alias i32, addrspacecast (ptr @gv.def to ptr addrspace(1)) +; CHECK: @[[IFUNC:[a-zA-Z0-9_$"\\.-]+]] = dso_local ifunc i32 (i32), ptr @ifunc_resolver +;. +define ptr @ifunc_resolver() { +; CHECK-LABEL: @ifunc_resolver( +; CHECK-NEXT: ret ptr null +; + ret ptr null +} + + +declare void @func.decl() +define void @func.def() { +; CHECK-LABEL: @func.def( +; CHECK-NEXT: ret void +; + ret void +} + +!0 = !{ ptr @func.decl } +!1 = !{ ptr @func.def } +!2 = !{ ptr @gv.decl } +!3 = !{ ptr @gv.def } +!4 = !{ ptr @alias } +!5 = !{ ptr addrspace(1) @alias.addrspacecast } +!6 = !{ ptr addrspace(1) addrspacecast (ptr @gv.def to ptr addrspace(1)) } +!7 = !{ ptr @ifunc } +!8 = !{ ptr null } +!9 = !{ ptr inttoptr (i64 12345 to ptr) } +!10 = !{ ptr poison } +!11 = !{ ptr undef } +!12 = !{ptr addrspace(1) addrspacecast (ptr null to ptr addrspace(1))} +;. +; CHECK: [[META0:![0-9]+]] = !{ptr @func.decl} +; CHECK: [[META1:![0-9]+]] = !{ptr @func.def} +; CHECK: [[META2:![0-9]+]] = !{ptr @gv.decl} +; CHECK: [[META3:![0-9]+]] = !{ptr @gv.def} +; CHECK: [[META4:![0-9]+]] = !{ptr @alias} +; CHECK: [[META5:![0-9]+]] = !{ptr addrspace(1) @alias.addrspacecast} +; CHECK: [[META6:![0-9]+]] = !{ptr addrspace(1) addrspacecast (ptr @gv.def to ptr addrspace(1))} +; CHECK: [[META7:![0-9]+]] = !{ptr @ifunc} +; CHECK: [[META8:![0-9]+]] = !{ptr null} +; CHECK: [[META9:![0-9]+]] = !{ptr inttoptr (i64 12345 to ptr)} +; CHECK: [[META10:![0-9]+]] = !{ptr poison} +; CHECK: [[META11:![0-9]+]] = !{ptr undef} +;. Index: llvm/test/CodeGen/X86/elf-associated.ll =================================================================== --- llvm/test/CodeGen/X86/elf-associated.ll +++ llvm/test/CodeGen/X86/elf-associated.ll @@ -38,13 +38,8 @@ !5 = !{ptr null} ; CHECK-DAG: .section ccc,"awo",@progbits,0,unique,3 -; Null metadata. -@m = global i32 1, section "ddd", !associated !6 -!6 = distinct !{null} -; CHECK-DAG: .section ddd,"awo",@progbits,0,unique,4 - ; Aliases are OK. @n = alias i32, ptr inttoptr (i64 add (i64 ptrtoint (ptr @a to i64), i64 1297036692682702848) to ptr) @o = global i32 1, section "eee", !associated !7 !7 = !{ptr @n} -; CHECK-DAG: .section eee,"awo",@progbits,n,unique,5 +; CHECK-DAG: .section eee,"awo",@progbits,n,unique,4 Index: llvm/test/Linker/Inputs/associated-global.ll =================================================================== --- /dev/null +++ llvm/test/Linker/Inputs/associated-global.ll @@ -0,0 +1,9 @@ +@a = global i32 0, !associated !0 +@b = external global i32, !associated !1 +@c = internal global i32 1, !associated !2 +@e = global i32 0, !associated !3 + +!0 = !{ptr @b} +!1 = !{ptr @a} +!2 = !{ptr @e} +!3 = !{ptr @c} Index: llvm/test/Linker/associated-global.ll =================================================================== --- /dev/null +++ llvm/test/Linker/associated-global.ll @@ -0,0 +1,26 @@ +; RUN: llvm-link -S %s %S/Inputs/associated-global.ll | FileCheck %s + +; CHECK: @c = internal global i32 1, !associated !0 +; CHECK: @d = global i32 0, !associated !1 +; CHECK: @a = global i32 0, !associated !2 +; CHECK: @b = global i32 0, !associated !3 +; CHECK: @c.3 = internal global i32 1, !associated !4 +; CHECK: @e = global i32 0, !associated !5 + +; CHECK: !0 = !{ptr @d} +; CHECK: !1 = !{ptr @c} +; CHECK: !2 = !{ptr @b} +; CHECK: !3 = !{ptr @a} +; CHECK: !4 = !{ptr @e} +; CHECK: !5 = !{ptr @c.3} + + +@a = external global i32, !associated !0 +@b = global i32 0, !associated !1 +@c = internal global i32 1, !associated !2 +@d = global i32 0, !associated !3 + +!0 = !{ptr @b} +!1 = !{ptr @a} +!2 = !{ptr @d} +!3 = !{ptr @c} Index: llvm/test/Linker/metadata-global.ll =================================================================== --- llvm/test/Linker/metadata-global.ll +++ llvm/test/Linker/metadata-global.ll @@ -3,9 +3,9 @@ ; CHECK-DAG: @a = global i32 0 ; CHECK-DAG: @b = global i32 0, !associated !0 -; CHECK-DAG: !0 = !{ptr @b} +; CHECK-DAG: !0 = !{ptr @a} @a = global i32 0 @b = global i32 0, !associated !0 -!0 = !{ptr @b} +!0 = !{ptr @a} Index: llvm/test/Verifier/associated-metadata.ll =================================================================== --- /dev/null +++ llvm/test/Verifier/associated-metadata.ll @@ -0,0 +1,47 @@ +; RUN: not llvm-as -disable-output < %s -o /dev/null 2>&1 | FileCheck %s + +; CHECK: associated value must be pointer typed +; CHECK-NEXT: ptr addrspace(1) @associated.int +; CHECK-NEXT: !0 = !{i32 1} +@associated.int = external addrspace(1) constant [8 x i8], !associated !0 + +; CHECK: associated value must be pointer typed +; CHECK-NEXT: ptr addrspace(1) @associated.float +; CHECK-NEXT: !1 = !{float 1.000000e+00} +@associated.float = external addrspace(1) constant [8 x i8], !associated !1 + +; CHECK: associated metadata must have one operand +; CHECK-NEXT: ptr addrspace(1) @associated.too.many.ops +; CHECK-NEXT: !2 = !{ptr @gv.decl0, ptr @gv.decl1} +@associated.too.many.ops = external addrspace(1) constant [8 x i8], !associated !2 + +; CHECK: associated metadata must have one operand +; CHECK-NEXT: ptr addrspace(1) @associated.empty +; CHECK-NEXT: !3 = !{} +@associated.empty = external addrspace(1) constant [8 x i8], !associated !3 + +; CHECK: associated metadata must have a global value +; CHECK-NEXT: ptr addrspace(1) @associated.null.metadata +; CHECK-NEXT: !4 = !{null} +@associated.null.metadata = external addrspace(1) constant [8 x i8], !associated !4 + +; CHECK: global values should not associate to themselves +; CHECK-NEXT: ptr @associated.self +; CHECK-NEXT: !5 = !{ptr @associated.self} +@associated.self = external constant [8 x i8], !associated !5 + +; CHECK: associated metadata must be ValueAsMetadata +; CHECK-NEXT: ptr @associated.string +; CHECK-NEXT: !6 = !{!"string"} +@associated.string = external constant [8 x i8], !associated !6 + +@gv.decl0 = external constant [8 x i8] +@gv.decl1 = external constant [8 x i8] + +!0 = !{i32 1} +!1 = !{float 1.000000e+00} +!2 = !{ptr @gv.decl0, ptr @gv.decl1} +!3 = !{} +!4 = !{null} +!5 = !{ptr @associated.self} +!6 = !{!"string"}