[PGO] Implement a more robust/readable Writer callback interface

(patch suggested by silvas)

With this patch, the IO information is wrapped in struct
ProfDataIOVec, and interface of writerCallback takes a vector
of IOVec and a pointer to writer context pointer.

Differential Revision: http://reviews.llvm.org/D14859

llvm-svn: 253764
diff --git a/compiler-rt/lib/profile/InstrProfilingBuffer.c b/compiler-rt/lib/profile/InstrProfilingBuffer.c
index dc5958e..130b30e 100644
--- a/compiler-rt/lib/profile/InstrProfilingBuffer.c
+++ b/compiler-rt/lib/profile/InstrProfilingBuffer.c
@@ -41,24 +41,31 @@
          PROFILE_RANGE_SIZE(Counters) * sizeof(uint64_t) + NamesSize + Padding;
 }
 
-static size_t bufferWriter(const void *Data, size_t ElmSize, size_t NumElm,
-                           void **Buffer) {
-  size_t Length = ElmSize * NumElm;
-  memcpy(*Buffer, Data, Length);
-  *(char **)Buffer += Length;
-  return NumElm;
+/* The buffer writer is reponsponsible in keeping writer state
+ * across the call.
+ */
+static uint32_t bufferWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs,
+                             void **WriterCtx) {
+  uint32_t I;
+  char **Buffer = (char **)WriterCtx;
+  for (I = 0; I < NumIOVecs; I++) {
+    size_t Length = IOVecs[I].ElmSize * IOVecs[I].NumElm;
+    memcpy(*Buffer, IOVecs[I].Data, Length);
+    *Buffer += Length;
+  }
+  return 0;
 }
 
 __attribute__((visibility("hidden"))) int
 __llvm_profile_write_buffer(char *Buffer) {
-  return llvmWriteProfData(Buffer, bufferWriter, 0, 0);
+  return llvmWriteProfData(bufferWriter, Buffer, 0, 0);
 }
 
 __attribute__((visibility("hidden"))) int __llvm_profile_write_buffer_internal(
     char *Buffer, const __llvm_profile_data *DataBegin,
     const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin,
     const uint64_t *CountersEnd, const char *NamesBegin, const char *NamesEnd) {
-  return llvmWriteProfDataImpl(Buffer, bufferWriter, DataBegin, DataEnd,
+  return llvmWriteProfDataImpl(bufferWriter, Buffer, DataBegin, DataEnd,
                                CountersBegin, CountersEnd, 0, 0, NamesBegin,
                                NamesEnd);
 }
diff --git a/compiler-rt/lib/profile/InstrProfilingFile.c b/compiler-rt/lib/profile/InstrProfilingFile.c
index 37d3729..742df21 100644
--- a/compiler-rt/lib/profile/InstrProfilingFile.c
+++ b/compiler-rt/lib/profile/InstrProfilingFile.c
@@ -17,17 +17,24 @@
 
 #define UNCONST(ptr) ((void *)(uintptr_t)(ptr))
 
-static size_t fileWriter(const void *Data, size_t ElmSize, size_t NumElm,
-                         void **File) {
-  return fwrite(Data, ElmSize, NumElm, (FILE *)*File);
+/* Return 1 if there is an error, otherwise return  0.  */
+static uint32_t fileWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs,
+                           void **WriterCtx) {
+  uint32_t I;
+  FILE *File = (FILE *)*WriterCtx;
+  for (I = 0; I < NumIOVecs; I++) {
+    if (fwrite(IOVecs[I].Data, IOVecs[I].ElmSize, IOVecs[I].NumElm, File) !=
+        IOVecs[I].NumElm)
+      return 1;
+  }
+  return 0;
 }
-uint8_t *ValueDataBegin = NULL;
 
 static int writeFile(FILE *File) {
   uint8_t *ValueDataBegin = NULL;
   const uint64_t ValueDataSize =
       __llvm_profile_gather_value_data(&ValueDataBegin);
-  int r = llvmWriteProfData(File, fileWriter, ValueDataBegin, ValueDataSize);
+  int r = llvmWriteProfData(fileWriter, File, ValueDataBegin, ValueDataSize);
   free(ValueDataBegin);
   return r;
 }
diff --git a/compiler-rt/lib/profile/InstrProfilingInternal.h b/compiler-rt/lib/profile/InstrProfilingInternal.h
index 518e6a3..e912ce8 100644
--- a/compiler-rt/lib/profile/InstrProfilingInternal.h
+++ b/compiler-rt/lib/profile/InstrProfilingInternal.h
@@ -41,12 +41,18 @@
 /*!
  * This is an internal function not intended to be used externally.
  */
-typedef size_t (*WriterCallback)(const void *Data, size_t ElmS, size_t NumElm,
-                                 void **BufferOrFile);
-int llvmWriteProfData(void *WriterCtx, WriterCallback Writer,
+typedef struct ProfDataIOVec {
+  const char *Data;
+  size_t ElmSize;
+  size_t NumElm;
+} ProfDataIOVec;
+
+typedef uint32_t (*WriterCallback)(ProfDataIOVec *, uint32_t NumIOVecs,
+                                   void **WriterCtx);
+int llvmWriteProfData(WriterCallback Writer, void *WriterCtx,
                       const uint8_t *ValueDataBegin,
                       const uint64_t ValueDataSize);
-int llvmWriteProfDataImpl(void *WriterCtx, WriterCallback Writer,
+int llvmWriteProfDataImpl(WriterCallback Writer, void *WriterCtx,
                           const __llvm_profile_data *DataBegin,
                           const __llvm_profile_data *DataEnd,
                           const uint64_t *CountersBegin,
diff --git a/compiler-rt/lib/profile/InstrProfilingWriter.c b/compiler-rt/lib/profile/InstrProfilingWriter.c
index 31d72bf..af0afc8 100644
--- a/compiler-rt/lib/profile/InstrProfilingWriter.c
+++ b/compiler-rt/lib/profile/InstrProfilingWriter.c
@@ -11,7 +11,7 @@
 #include "InstrProfilingInternal.h"
 
 __attribute__((visibility("hidden"))) int
-llvmWriteProfData(void *WriterCtx, WriterCallback Writer,
+llvmWriteProfData(WriterCallback Writer, void *WriterCtx,
                   const uint8_t *ValueDataBegin, const uint64_t ValueDataSize) {
   /* Match logic in __llvm_profile_write_buffer(). */
   const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
@@ -20,13 +20,13 @@
   const uint64_t *CountersEnd = __llvm_profile_end_counters();
   const char *NamesBegin = __llvm_profile_begin_names();
   const char *NamesEnd = __llvm_profile_end_names();
-  return llvmWriteProfDataImpl(WriterCtx, Writer, DataBegin, DataEnd,
+  return llvmWriteProfDataImpl(Writer, WriterCtx, DataBegin, DataEnd,
                                CountersBegin, CountersEnd, ValueDataBegin,
                                ValueDataSize, NamesBegin, NamesEnd);
 }
 
 __attribute__((visibility("hidden"))) int llvmWriteProfDataImpl(
-    void *WriterCtx, WriterCallback Writer,
+    WriterCallback Writer, void *WriterCtx,
     const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd,
     const uint64_t *CountersBegin, const uint64_t *CountersEnd,
     const uint8_t *ValueDataBegin, const uint64_t ValueDataSize,
@@ -58,19 +58,19 @@
   Header.ValueDataSize = ValueDataSize;
   Header.ValueDataDelta = (uintptr_t)ValueDataBegin;
 
-/* Write the data. */
-#define CHECK_write(Data, Size, Length, BuffOrFile)                            \
-  do {                                                                         \
-    if (Writer(Data, Size, Length, &BuffOrFile) != Length)                     \
-      return -1;                                                               \
-  } while (0)
-  CHECK_write(&Header, sizeof(__llvm_profile_header), 1, WriterCtx);
-  CHECK_write(DataBegin, sizeof(__llvm_profile_data), DataSize, WriterCtx);
-  CHECK_write(CountersBegin, sizeof(uint64_t), CountersSize, WriterCtx);
-  CHECK_write(NamesBegin, sizeof(char), NamesSize, WriterCtx);
-  CHECK_write(Zeroes, sizeof(char), Padding, WriterCtx);
-  if (ValueDataBegin)
-    CHECK_write(ValueDataBegin, sizeof(char), ValueDataSize, WriterCtx);
-#undef CHECK_write
+  /* Write the data. */
+  ProfDataIOVec IOVec[] = {
+      {(const char *)&Header, sizeof(__llvm_profile_header), 1},
+      {(const char *)DataBegin, sizeof(__llvm_profile_data), DataSize},
+      {(const char *)CountersBegin, sizeof(uint64_t), CountersSize},
+      {(const char *)NamesBegin, sizeof(char), NamesSize},
+      {(const char *)Zeroes, sizeof(char), Padding}};
+  if (Writer(IOVec, sizeof(IOVec) / sizeof(ProfDataIOVec), &WriterCtx))
+    return -1;
+  if (ValueDataBegin) {
+    ProfDataIOVec IOVec[1] = {{ValueDataBegin, sizeof(char), ValueDataSize}};
+    if (Writer(IOVec, 1, &WriterCtx))
+      return -1;
+  }
   return 0;
 }