diff --git a/clang/test/CodeGen/PowerPC/aix-init-ref-null.cpp b/clang/test/CodeGen/PowerPC/aix-init-ref-null.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/PowerPC/aix-init-ref-null.cpp @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -emit-llvm -O3 -x c++ < %s | FileCheck %s +// XFAIL: * +// This function should fail until .ref is support on AIX. + +// Global Ctors present at -O0, removed by -O3 +typedef enum { + A, B +} E; + +class base { +protected: + base(E v): m(v) { } +private: + E m; +}; + +struct ext: base { + ext():base(A){} +}; + +ext base_rview; + +// CHECK: @base_rview = local_unnamed_addr global %struct.ext zeroinitializer, align [[ALIGN:[0-9]+]], !associated ![[ASSOC0:[0-9]+]] +// CHECK: @llvm.global_ctors = appending global [0 x { i32, ptr, ptr }] zeroinitializer +// CHECK: ![[ASSOC0]] = distinct !{null} diff --git a/clang/test/CodeGen/PowerPC/aix-ref-static-var.cpp b/clang/test/CodeGen/PowerPC/aix-ref-static-var.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/PowerPC/aix-ref-static-var.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -emit-llvm -x c++ < %s | FileCheck %s +// XFAIL: * +// This function should fail until .ref is support on AIX. + +struct S { + ~S(); +}; +void f() { + static S s; +} + +// CHECK: @_ZZ1fvE1s = internal global %struct.S zeroinitializer, align [[ALIGN:[0-9]+]], !associated ![[ASSOC0:[0-9]+]] +// CHECK: define internal void @__dtor__ZZ1fvE1s() [[ATTR:#[0-9]+]] !associated ![[ASSOC0:[0-9]+]] { +// CHECK: ![[ASSOC0]] = !{ptr @_GLOBAL__D_a} diff --git a/clang/test/CodeGenCXX/aix-static-init-debug-info.cpp b/clang/test/CodeGenCXX/aix-static-init-debug-info.cpp --- a/clang/test/CodeGenCXX/aix-static-init-debug-info.cpp +++ b/clang/test/CodeGenCXX/aix-static-init-debug-info.cpp @@ -13,6 +13,8 @@ X v; +// XFAIL-CHECK: @v = global %struct.X zeroinitializer, align {{[0-9]+}}, !dbg !{{[0-9]+}}, !associated ![[ASSOC1:[0-9]+]] + // CHECK: define internal void @__cxx_global_var_init() [[ATTR:#[0-9]+]] !dbg ![[DBGVAR16:[0-9]+]] { // CHECK: entry: // CHECK: call void @_ZN1XC1Ev(ptr {{[^,]*}} @v), !dbg ![[DBGVAR19:[0-9]+]] @@ -21,6 +23,7 @@ // CHECK: } // CHECK: define internal void @__dtor_v() [[ATTR:#[0-9]+]] !dbg ![[DBGVAR20:[0-9]+]] { +// XFAIL-CHECK: define internal void @__dtor_v() [[ATTR:#[0-9]+]] !dbg ![[DBGVAR20:[0-9]+]] !associated ![[ASSOC2:[0-9]+]] { // CHECK: entry: // CHECK: call void @_ZN1XD1Ev(ptr @v), !dbg ![[DBGVAR21b:[0-9]+]] // CHECK: ret void, !dbg ![[DBGVAR21:[0-9]+]] @@ -52,10 +55,12 @@ // CHECK: ret void // CHECK: } +// XFAIL-CHECK: ![[ASSOC1]] = !{ptr @{{_GLOBAL__sub_I__|_GLOBAL__D_a}}, ptr @{{_GLOBAL__sub_I__|_GLOBAL__D_a}}} // CHECK: ![[DBGVAR16]] = distinct !DISubprogram(name: "__cxx_global_var_init", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, type: !{{[0-9]+}}, flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !{{[0-9]+}}, retainedNodes: !{{[0-9]+}}) // CHECK: ![[DBGVAR19]] = !DILocation(line: 14, column: 3, scope: ![[DBGVAR16]]) // CHECK: ![[DBGVAR19b]] = !DILocation(line: 0, scope: ![[DBGVAR16]]) // CHECK: ![[DBGVAR20]] = distinct !DISubprogram(name: "__dtor_v", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: 14, type: !{{[0-9]+}}, scopeLine: 14, flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !{{[0-9]+}}, retainedNodes: !{{[0-9]+}}) +// XFAIL-CHECK: ![[ASSOC2]] = !{ptr @_GLOBAL__D_a} // CHECK: ![[DBGVAR21b]] = !DILocation(line: 0, scope: ![[DBGVAR20]]) // CHECK: ![[DBGVAR21]] = !DILocation(line: 14, column: 3, scope: ![[DBGVAR20]]) // CHECK: ![[DBGVAR22]] = distinct !DISubprogram(linkageName: "__finalize_v", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: 14, type: !{{[0-9]+}}, scopeLine: 14, flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !{{[0-9]+}}, retainedNodes: !{{[0-9]+}}) diff --git a/clang/test/CodeGenCXX/aix-static-init-temp-spec-and-inline-var.cpp b/clang/test/CodeGenCXX/aix-static-init-temp-spec-and-inline-var.cpp --- a/clang/test/CodeGenCXX/aix-static-init-temp-spec-and-inline-var.cpp +++ b/clang/test/CodeGenCXX/aix-static-init-temp-spec-and-inline-var.cpp @@ -44,8 +44,13 @@ A A::instance = bar(); } // namespace test2 +// XFAIL-CHECK: @_ZN5test12t0E = global %"struct.test1::Test1" zeroinitializer, align {{[0-9]+}}, !associated ![[ASSOC0:[0-9]+]] +// XFAIL-CHECK: @_ZN5test12t2E = linkonce_odr global %"struct.test1::Test1" zeroinitializer, align {{[0-9]+}}, !associated ![[ASSOC1:[0-9]+]] // CHECK: @_ZGVN5test12t2E = linkonce_odr global i64 0, align 8 +// XFAIL-CHECK: @_ZN5test12t1IiEE = linkonce_odr global %"struct.test1::Test1" zeroinitializer, align {{[0-9]+}}, !associated ![[ASSOC2:[0-9]+]] +// XFAIL-CHECK: @_ZN5test21AIvE8instanceE = weak_odr global %"struct.test2::A" zeroinitializer, align {{[0-9]+}}, !associated ![[ASSOC3:[0-9]+]] // CHECK: @_ZGVN5test21AIvE8instanceE = weak_odr global i64 0, align 8 +// XFAIL-CHECK: @_ZN5test21AIiE8instanceE = global %"struct.test2::A.0" zeroinitializer, align {{[0-9]+}}, !associated ![[ASSOC0:[0-9]+]] // CHECK: @_ZGVN5test12t1IiEE = linkonce_odr global i64 0, align 8 // CHECK: @llvm.global_ctors = appending global [4 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @__cxx_global_var_init.1, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @__cxx_global_var_init.2, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @__cxx_global_var_init.4, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__sub_I__, ptr null }] // CHECK: @llvm.global_dtors = appending global [4 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @__finalize__ZN5test12t2E, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @__finalize__ZN5test21AIvE8instanceE, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @__finalize__ZN5test12t1IiEE, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__D_a, ptr null }] @@ -59,6 +64,7 @@ // CHECK: } // CHECK: define internal void @__dtor__ZN5test12t0E() [[ATTR:#[0-9]+]] { +// XFAIL-CHECK: define internal void @__dtor__ZN5test12t0E() [[ATTR:#[0-9]+]] !associated ![[ASSOC4:[0-9]+]] { // CHECK: entry: // CHECK: call void @_ZN5test15Test1D1Ev(ptr @_ZN5test12t0E) // CHECK: ret void @@ -101,6 +107,7 @@ // CHECK: } // CHECK: define internal void @__dtor__ZN5test12t2E() [[ATTR:#[0-9]+]] { +// XFAIL-CHECK: define internal void @__dtor__ZN5test12t2E() [[ATTR:#[0-9]+]] !associated ![[ASSOC5:[0-9]+]] { // CHECK: entry: // CHECK: call void @_ZN5test15Test1D1Ev(ptr @_ZN5test12t2E) // CHECK: ret void @@ -137,6 +144,7 @@ // CHECK: } // CHECK: define internal void @__dtor__ZN5test21AIvE8instanceE() [[ATTR:#[0-9]+]] { +// XFAIL-CHECK: define internal void @__dtor__ZN5test21AIvE8instanceE() [[ATTR:#[0-9]+]] !associated ![[ASSOC6:[0-9]+]] { // CHECK: entry: // CHECK: call void @_ZN5test21AIvED1Ev(ptr @_ZN5test21AIvE8instanceE) // CHECK: ret void @@ -164,6 +172,7 @@ // CHECK: } // CHECK: define internal void @__dtor__ZN5test21AIiE8instanceE() [[ATTR:#[0-9]+]] { +// XFAIL-CHECK: define internal void @__dtor__ZN5test21AIiE8instanceE() [[ATTR:#[0-9]+]] !associated ![[ASSOC4:[0-9]+]] { // CHECK: entry: // CHECK: call void @_ZN5test21AIiED1Ev(ptr @_ZN5test21AIiE8instanceE) // CHECK: ret void @@ -201,6 +210,7 @@ // CHECK: } // CHECK: define internal void @__dtor__ZN5test12t1IiEE() [[ATTR:#[0-9]+]] { +// XFAIL-CHECK: define internal void @__dtor__ZN5test12t1IiEE() [[ATTR:#[0-9]+]] !associated ![[ASSOC7:[0-9]+]] { // CHECK: entry: // CHECK: call void @_ZN5test15Test1D1Ev(ptr @_ZN5test12t1IiEE) // CHECK: ret void @@ -233,3 +243,12 @@ // CHECK: call void @__finalize__ZN5test12t0E() // CHECK: ret void // CHECK: } + +// XFAIL-CHECK: ![[ASSOC0]] = !{ptr @{{_GLOBAL__sub_I__|_GLOBAL__D_a}}, ptr @{{_GLOBAL__sub_I__|_GLOBAL__D_a}}} +// XFAIL-CHECK: ![[ASSOC1]] = !{ptr @{{__cxx_global_var_init.1|__finalize__ZN5test12t2E}}, ptr @{{__cxx_global_var_init.1|__finalize__ZN5test12t2E}}} +// XFAIL-CHECK: ![[ASSOC2]] = !{ptr @{{__cxx_global_var_init.4|__finalize__ZN5test12t1IiEE}}, ptr @{{__cxx_global_var_init.4|__finalize__ZN5test12t1IiEE}}} +// XFAIL-CHECK: ![[ASSOC3]] = !{ptr @{{__finalize__ZN5test21AIvE8instanceE|__cxx_global_var_init.2}}, ptr @{{__finalize__ZN5test21AIvE8instanceE|__cxx_global_var_init.2}}} +// XFAIL-CHECK: ![[ASSOC4]] = !{ptr @_GLOBAL__D_a} +// XFAIL-CHECK: ![[ASSOC5]] = !{ptr @__finalize__ZN5test12t2E} +// XFAIL-CHECK: ![[ASSOC6]] = !{ptr @__finalize__ZN5test21AIvE8instanceE} +// XFAIL-CHECK: ![[ASSOC7]] = !{ptr @__finalize__ZN5test12t1IiEE} diff --git a/clang/test/CodeGenCXX/aix-static-init.cpp b/clang/test/CodeGenCXX/aix-static-init.cpp --- a/clang/test/CodeGenCXX/aix-static-init.cpp +++ b/clang/test/CodeGenCXX/aix-static-init.cpp @@ -38,6 +38,10 @@ } } // namespace test4 +// XFAIL-CHECK: @_ZN5test12t1E = global %"struct.test1::Test1" zeroinitializer, align {{[0-9]+}}, !associated ![[ASSOC0:[0-9]+]] +// XFAIL-CHECK: @_ZN5test12t2E = global %"struct.test1::Test1" zeroinitializer, align {{[0-9]+}}, !associated ![[ASSOC0:[0-9]+]] +// XFAIL-CHECK: @_ZN5test21xE = global i32 0, align {{[0-9]+}}, !associated ![[ASSOC1:[0-9]+]] +// XFAIL-CHECK: @_ZN5test31tE = global %"struct.test3::Test3" undef, align {{[0-9]+}}, !associated ![[ASSOC0:[0-9]+]] // CHECK: @_ZGVZN5test41fEvE11staticLocal = internal global i64 0, align 8 // CHECK: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__sub_I__, ptr null }] // CHECK: @llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__D_a, ptr null }] @@ -50,6 +54,7 @@ // CHECK: } // CHECK: define internal void @__dtor__ZN5test12t1E() [[ATTR:#[0-9]+]] { +// XFAIL-CHECK: define internal void @__dtor__ZN5test12t1E() [[ATTR:#[0-9]+]] !associated ![[ASSOC2:[0-9]+]] { // CHECK: entry: // CHECK: call void @_ZN5test15Test1D1Ev(ptr @_ZN5test12t1E) // CHECK: ret void @@ -81,6 +86,7 @@ // CHECK: } // CHECK: define internal void @__dtor__ZN5test12t2E() [[ATTR:#[0-9]+]] { +// XFAIL-CHECK: define internal void @__dtor__ZN5test12t2E() [[ATTR:#[0-9]+]] !associated ![[ASSOC2:[0-9]+]] { // CHECK: entry: // CHECK: call void @_ZN5test15Test1D1Ev(ptr @_ZN5test12t2E) // CHECK: ret void @@ -115,6 +121,7 @@ // CHECK: } // CHECK: define internal void @__dtor__ZN5test31tE() [[ATTR:#[0-9]+]] { +// XFAIL-CHECK: define internal void @__dtor__ZN5test31tE() [[ATTR:#[0-9]+]] !associated ![[ASSOC2:[0-9]+]] { // CHECK: entry: // CHECK: call void @_ZN5test35Test3D1Ev(ptr @_ZN5test31tE) // CHECK: ret void @@ -156,6 +163,7 @@ // CHECK: } // CHECK: define internal void @__dtor__ZZN5test41fEvE11staticLocal() [[ATTR:#[0-9]+]] { +// XFAIL-CHECK: define internal void @__dtor__ZZN5test41fEvE11staticLocal() [[ATTR:#[0-9]+]] !associated ![[ASSOC2:[0-9]+]] { // CHECK: entry: // CHECK: call void @_ZN5test45Test4D1Ev(ptr @_ZZN5test41fEvE11staticLocal) // CHECK: ret void @@ -192,3 +200,7 @@ // CHECK: call void @__finalize__ZN5test12t1E() // CHECK: ret void // CHECK: } + +// XFAIL-CHECK: ![[ASSOC0]] = !{ptr @{{_GLOBAL__sub_I__|_GLOBAL__D_a}}, ptr @{{_GLOBAL__sub_I__|_GLOBAL__D_a}}} +// XFAIL-CHECK: ![[ASSOC1]] = !{ptr @_GLOBAL__sub_I__} +// XFAIL-CHECK: ![[ASSOC2]] = !{ptr @_GLOBAL__D_a} diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -7318,8 +7318,6 @@ linker-defined encapsulation symbols ``__start_`` and ``__stop_``. -It does not have any effect on non-ELF targets. - Example: .. code-block:: text @@ -7329,6 +7327,11 @@ @b = internal global i32 2, comdat $a, section "abc", !associated !0 !0 = !{ptr @a} +It does not have any effect on non-ELF targets. Non-ELF target may use +``associated`` metadata for its own purpose. For example, on AIX XCOFF target, +the ``associated`` metadata may indicate connection among static variables +(static global variable, static class member etc.) and static init/term +functions. This kind of association can be one-to-many. '``prof``' Metadata ^^^^^^^^^^^^^^^^^^^ diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -663,22 +663,29 @@ 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, + auto CheckAssocOperand = [this, &GV, GO, Associated](const Metadata *Op) { + 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); + } + }; + + for (unsigned i = 0, e = Associated->getNumOperands(); i != e; ++i) + CheckAssocOperand(Associated->getOperand(i).get()); } } Check(!GV.hasAppendingLinkage() || isa(GV),