commit 788e98601909e0a9e7a3b175b2ed419fc1d948a1
Author: Duncan P. N. Exon Smith <dexonsmith@apple.com>
Date:   Fri Mar 14 16:30:37 2014 -0700

    PGO: Statically generate data structures
    
    In instrumentation-based profiling, we need a set of data structures to
    represent the counters.  Previously, these were built up during static
    initialization.  Now, they're shoved into a specially-named section so
    that they show up as an array.
    
    As a consequence of the reorganizing symbols, instrumentation data
    structures for linkonce functions are now correctly coalesced.
    
    This is the first step in a larger project to minimize runtime overhead
    and dependencies in instrumentation-based profilng.  The larger picture
    includes removing all initialization overhead and making the dependency
    on libc optional.
    
    <rdar://problem/15943240>

diff --git a/lib/profile/PGOProfiling.c b/lib/profile/PGOProfiling.c
index 986fd84..6ed4d7a 100644
--- a/lib/profile/PGOProfiling.c
+++ b/lib/profile/PGOProfiling.c
@@ -32,68 +32,100 @@ typedef unsigned int uint32_t;
 typedef unsigned long long uint64_t;
 #endif
 
-static FILE *OutputFile = NULL;
-
-/*
- * A list of functions to write out the data.
+typedef struct __llvm_pgo_data {
+  const uint32_t NameSize;
+  const uint32_t NumCounters;
+  const char *const Name;
+  const uint64_t *const Counters;
+} DataType;
+
+/* TODO: Calculate these with linker magic. */
+static DataType *First = NULL;
+static DataType *Final = NULL;
+/*!
+ * \brief Register an instrumented function.
+ *
+ * Calls to this are emitted by clang with -fprofile-instr-generate.  Such
+ * calls are only required (and only emitted) on targets where we haven't
+ * implemented linker magic to find the bounds of the section.
+ *
+ * For now, that's all targets.
  */
-typedef void (*writeout_fn)();
-
-struct writeout_fn_node {
-  writeout_fn fn;
-  struct writeout_fn_node *next;
-};
-
-static struct writeout_fn_node *writeout_fn_head = NULL;
-static struct writeout_fn_node *writeout_fn_tail = NULL;
-
-void llvm_pgo_emit(const char *MangledName, uint32_t NumCounters,
-                   uint64_t *Counters) {
-  uint32_t i;
-  fprintf(OutputFile, "%s %u\n", MangledName, NumCounters);
-  for (i = 0; i < NumCounters; ++i)
-    fprintf(OutputFile, "%" PRIu64 "\n", Counters[i]);
-  fprintf(OutputFile, "\n");
+void __llvm_pgo_register_function(void *Data_) {
+  /* TODO: Only emit this function if we can't use linker magic. */
+  DataType *Data = (DataType*)Data_;
+  if (!First || Data < First)
+    First = Data;
+  if (!Final || Data > Final)
+    Final = Data;
 }
 
-void llvm_pgo_register_writeout_function(writeout_fn fn) {
-  struct writeout_fn_node *new_node = malloc(sizeof(struct writeout_fn_node));
-  new_node->fn = fn;
-  new_node->next = NULL;
+/*! \brief Get the first instrumentation record. */
+static DataType *getFirst() {
+  /* TODO: Use extern + linker magic instead of a static variable. */
+  return First;
+}
 
-  if (!writeout_fn_head) {
-    writeout_fn_head = writeout_fn_tail = new_node;
-  } else {
-    writeout_fn_tail->next = new_node;
-    writeout_fn_tail = new_node;
-  }
+/*! \brief Get the last instrumentation record. */
+static DataType *getLast() {
+  /* TODO: Use extern + linker magic instead of a static variable. */
+  return Final + 1;
 }
 
-void llvm_pgo_writeout_files() {
-  const char *OutputName = getenv("LLVM_PROFILE_FILE");
-  if (OutputName == NULL || OutputName[0] == '\0')
-    OutputName = "default.profdata";
+/* TODO: void __llvm_pgo_get_size_for_buffer(void);  */
+/* TODO: void __llvm_pgo_write_buffer(char *Buffer); */
+
+static void writeFunction(FILE *OutputFile, const DataType *Data) {
+  /* TODO: Requires libc: break requirement by writing directly to a buffer
+   * instead of a FILE stream.
+   */
+  uint32_t I;
+  for (I = 0; I < Data->NameSize; ++I)
+    fputc(Data->Name[I], OutputFile);
+  fprintf(OutputFile, " %u\n", Data->NumCounters);
+  for (I = 0; I < Data->NumCounters; ++I)
+    fprintf(OutputFile, "%" PRIu64 "\n", Data->Counters[I]);
+  fprintf(OutputFile, "\n");
+}
+
+/*! \brief Write instrumentation data to the given file. */
+void __llvm_pgo_write_file(const char *OutputName) {
+  /* TODO: Requires libc: move to separate translation unit. */
+  DataType *I, *E;
+  FILE *OutputFile;
+  if (!OutputName || !OutputName[0])
+    return;
   OutputFile = fopen(OutputName, "w");
   if (!OutputFile) return;
 
-  while (writeout_fn_head) {
-    struct writeout_fn_node *node = writeout_fn_head;
-    writeout_fn_head = writeout_fn_head->next;
-    node->fn();
-    free(node);
-  }
+  /* TODO: mmap file to buffer of size __llvm_pgo_get_size_for_buffer() and
+   * call __llvm_pgo_write_buffer().
+   */
+  for (I = getFirst(), E = getLast(); I != E; ++I)
+    writeFunction(OutputFile, I);
 
   fclose(OutputFile);
 }
 
-void llvm_pgo_init(writeout_fn wfn) {
-  static int atexit_ran = 0;
+/*! \brief Write instrumentation data to the default file. */
+void __llvm_pgo_write_default_file() {
+  /* TODO: Requires libc: move to separate translation unit. */
+  const char *OutputName = getenv("LLVM_PROFILE_FILE");
+  if (OutputName == NULL || OutputName[0] == '\0')
+    OutputName = "default.profdata";
+  __llvm_pgo_write_file(OutputName);
+}
 
-  if (wfn)
-    llvm_pgo_register_writeout_function(wfn);
+/*!
+ * \brief Register to write instrumentation data to the default file at exit.
+ */
+void __llvm_pgo_register_write_atexit() {
+  /* TODO: Requires libc: move to separate translation unit. */
+  static int HasBeenRegistered = 0;
 
-  if (atexit_ran == 0) {
-    atexit_ran = 1;
-    atexit(llvm_pgo_writeout_files);
+  if (!HasBeenRegistered) {
+    HasBeenRegistered = 1;
+    atexit(__llvm_pgo_write_default_file);
   }
 }
+
