[PGO][AIX] Improve dummy var retention and allow -bcdtors:csect linking.

1) Use a static array of pointer to retain the dummy vars.
2) Associate liveness of the array with that of the runtime hook variable
   __llvm_profile_runtime.
3) Perform the runtime initialization through the runtime hook variable.
4) Preserve the runtime hook variable using the -u linker flag.

Reviewed By: hubert.reinterpretcast

Differential Revision: https://reviews.llvm.org/D136192

GitOrigin-RevId: 461a1836d3d77371bb6271fefd645897997a22b8
diff --git a/lib/profile/InstrProfilingPlatformLinux.c b/lib/profile/InstrProfilingPlatformLinux.c
index 3af61d2..adf4132 100644
--- a/lib/profile/InstrProfilingPlatformLinux.c
+++ b/lib/profile/InstrProfilingPlatformLinux.c
@@ -250,23 +250,21 @@
 // section exists. So for the scenario where the user objects have no such
 // section (i.e. when they are compiled with -fno-profile-generate), we always
 // define these zero length variables in each of the above 4 sections.
-COMPILER_RT_VISIBILITY int dummy_cnts[0] COMPILER_RT_SECTION(
+static int dummy_cnts[0] COMPILER_RT_SECTION(
     COMPILER_RT_SEG INSTR_PROF_CNTS_SECT_NAME);
-COMPILER_RT_VISIBILITY int dummy_data[0] COMPILER_RT_SECTION(
+static int dummy_data[0] COMPILER_RT_SECTION(
     COMPILER_RT_SEG INSTR_PROF_DATA_SECT_NAME);
-COMPILER_RT_VISIBILITY const int dummy_name[0] COMPILER_RT_SECTION(
+static const int dummy_name[0] COMPILER_RT_SECTION(
     COMPILER_RT_SEG INSTR_PROF_NAME_SECT_NAME);
-COMPILER_RT_VISIBILITY int dummy_vnds[0] COMPILER_RT_SECTION(
+static int dummy_vnds[0] COMPILER_RT_SECTION(
     COMPILER_RT_SEG INSTR_PROF_VNODES_SECT_NAME);
 
-// Create a fake reference to avoid GC'ing of the dummy variables by the linker.
-// Ideally, we create a ".ref" of each variable inside the function
-// __llvm_profile_begin_counters(), but there's no source level construct
-// that allows us to generate that.
-__attribute__((destructor)) void keep() {
-  int volatile use = &dummy_cnts < &dummy_data && &dummy_name < &dummy_vnds;
-  (void)use;
-}
+// To avoid GC'ing of the dummy variables by the linker, reference them in an
+// array and reference the array in the runtime registration code
+// (InstrProfilingRuntime.cpp)
+COMPILER_RT_VISIBILITY
+void *__llvm_profile_keep[] = {(void *)&dummy_cnts, (void *)&dummy_data,
+                               (void *)&dummy_name, (void *)&dummy_vnds};
 #endif
 
 #endif
diff --git a/lib/profile/InstrProfilingRuntime.cpp b/lib/profile/InstrProfilingRuntime.cpp
index 4ea2bb2..04f761c 100644
--- a/lib/profile/InstrProfilingRuntime.cpp
+++ b/lib/profile/InstrProfilingRuntime.cpp
@@ -10,19 +10,23 @@
 
 #include "InstrProfiling.h"
 
-/* int __llvm_profile_runtime  */
-COMPILER_RT_VISIBILITY int INSTR_PROF_PROFILE_RUNTIME_VAR;
+static int RegisterRuntime() {
+  __llvm_profile_initialize();
+  return 0;
 }
 
-namespace {
+#ifndef _AIX
+/* int __llvm_profile_runtime  */
+COMPILER_RT_VISIBILITY int INSTR_PROF_PROFILE_RUNTIME_VAR;
 
-class RegisterRuntime {
-public:
-  RegisterRuntime() {
-    __llvm_profile_initialize();
-  }
-};
-
-RegisterRuntime Registration;
-
+static int Registration = RegisterRuntime();
+#else
+extern COMPILER_RT_VISIBILITY void *__llvm_profile_keep[];
+/* On AIX, when linking with -bcdtors:csect, the variable whose constructor does
+ * the registration needs to be explicitly kept, hence we reuse the runtime hook
+ * variable to do the registration since it'll be kept via the -u linker flag.
+ * Create a volatile reference to __llvm_profile_keep to keep the array alive.*/
+COMPILER_RT_VISIBILITY int INSTR_PROF_PROFILE_RUNTIME_VAR =
+    ((void)*(void *volatile *)__llvm_profile_keep, RegisterRuntime());
+#endif
 }
diff --git a/test/profile/AIX/lit.local.cfg.py b/test/profile/AIX/lit.local.cfg.py
new file mode 100644
index 0000000..7ec27bf
--- /dev/null
+++ b/test/profile/AIX/lit.local.cfg.py
@@ -0,0 +1,9 @@
+def getRoot(config):
+  if not config.parent:
+    return config
+  return getRoot(config.parent)
+
+root = getRoot(config)
+
+if root.host_os not in ['AIX']:
+  config.unsupported = True
diff --git a/test/profile/AIX/shared-bexpall-pgo.c b/test/profile/AIX/shared-bexpall-pgo.c
new file mode 100644
index 0000000..b3b865d
--- /dev/null
+++ b/test/profile/AIX/shared-bexpall-pgo.c
@@ -0,0 +1,14 @@
+// RUN: split-file %s %t
+// RUN: cd %t
+//
+// RUN: %clang_pgogen foo.c -c -o foo.o
+// RUN: %clang_pgogen -shared foo.o -o libfoo.so -bexpall
+// RUN: %clang_pgogen -L%t user.c libfoo.so -o user1
+// RUN: ./user1
+
+//--- foo.c
+void foo() {}
+
+//--- user.c
+void foo();
+int main() { foo(); }