summaryrefslogtreecommitdiff
path: root/runtime
diff options
context:
space:
mode:
authortstellar <tstellar@91177308-0d34-0410-b5e6-96231b3b80d8>2012-09-18 19:40:39 +0000
committertstellar <tstellar@91177308-0d34-0410-b5e6-96231b3b80d8>2012-09-18 19:40:39 +0000
commit15d14cb83df480dd4aab6435873ca50254891a2d (patch)
treee5ef7d77a1e7703b625d5de82d50c26e4944cdc7 /runtime
Create R600 Branch
git-svn-id: https://llvm.org/svn/llvm-project/llvm/branches/R600/@164161 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'runtime')
-rw-r--r--runtime/CMakeLists.txt5
-rw-r--r--runtime/LLVMBuild.txt21
-rw-r--r--runtime/Makefile31
-rw-r--r--runtime/README.txt4
-rw-r--r--runtime/libprofile/BasicBlockTracing.c67
-rw-r--r--runtime/libprofile/CMakeLists.txt20
-rw-r--r--runtime/libprofile/CommonProfiling.c151
-rw-r--r--runtime/libprofile/EdgeProfiling.c45
-rw-r--r--runtime/libprofile/GCDAProfiling.c205
-rw-r--r--runtime/libprofile/Makefile51
-rw-r--r--runtime/libprofile/OptimalEdgeProfiling.c45
-rw-r--r--runtime/libprofile/PathProfiling.c270
-rw-r--r--runtime/libprofile/Profiling.h36
-rw-r--r--runtime/libprofile/libprofile.exports12
14 files changed, 963 insertions, 0 deletions
diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt
new file mode 100644
index 0000000000..502b91dc58
--- /dev/null
+++ b/runtime/CMakeLists.txt
@@ -0,0 +1,5 @@
+if( NOT LLVM_BUILD_RUNTIME )
+ set(EXCLUDE_FROM_ALL ON)
+endif()
+
+add_subdirectory(libprofile)
diff --git a/runtime/LLVMBuild.txt b/runtime/LLVMBuild.txt
new file mode 100644
index 0000000000..05334fda50
--- /dev/null
+++ b/runtime/LLVMBuild.txt
@@ -0,0 +1,21 @@
+;===- ./runtime/LLVMBuild.txt ----------------------------------*- Conf -*--===;
+;
+; The LLVM Compiler Infrastructure
+;
+; This file is distributed under the University of Illinois Open Source
+; License. See LICENSE.TXT for details.
+;
+;===------------------------------------------------------------------------===;
+;
+; This is an LLVMBuild description file for the components in this subdirectory.
+;
+; For more information on the LLVMBuild system, please see:
+;
+; http://llvm.org/docs/LLVMBuild.html
+;
+;===------------------------------------------------------------------------===;
+
+[component_0]
+type = Group
+name = Runtime
+parent = $ROOT
diff --git a/runtime/Makefile b/runtime/Makefile
new file mode 100644
index 0000000000..d0e85d5826
--- /dev/null
+++ b/runtime/Makefile
@@ -0,0 +1,31 @@
+##===- runtime/Makefile ------------------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ..
+include $(LEVEL)/Makefile.config
+
+ifndef NO_RUNTIME_LIBS
+
+PARALLEL_DIRS := libprofile
+
+# Disable libprofile: a faulty libtool is generated by autoconf which breaks the
+# build on Sparc
+ifeq ($(ARCH), Sparc)
+PARALLEL_DIRS := $(filter-out libprofile, $(PARALLEL_DIRS))
+endif
+
+ifeq ($(TARGET_OS), $(filter $(TARGET_OS), Cygwin MingW Minix))
+PARALLEL_DIRS := $(filter-out libprofile, $(PARALLEL_DIRS))
+endif
+
+endif
+
+include $(LEVEL)/Makefile.common
+
+install::
diff --git a/runtime/README.txt b/runtime/README.txt
new file mode 100644
index 0000000000..2e2e547de3
--- /dev/null
+++ b/runtime/README.txt
@@ -0,0 +1,4 @@
+This directory contains the various runtime libraries used by components of
+the LLVM compiler. For example, the automatic pool allocation transformation
+inserts calls to an external pool allocator library. This runtime library is
+an example of the type of library that lives in these directories.
diff --git a/runtime/libprofile/BasicBlockTracing.c b/runtime/libprofile/BasicBlockTracing.c
new file mode 100644
index 0000000000..0815e2e516
--- /dev/null
+++ b/runtime/libprofile/BasicBlockTracing.c
@@ -0,0 +1,67 @@
+/*===-- BasicBlockTracing.c - Support library for basic block tracing -----===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+|*===----------------------------------------------------------------------===*|
+|*
+|* This file implements the call back routines for the basic block tracing
+|* instrumentation pass. This should be used with the -trace-basic-blocks
+|* LLVM pass.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#include "Profiling.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+static unsigned *ArrayStart, *ArrayEnd, *ArrayCursor;
+
+/* WriteAndFlushBBTraceData - write out the currently accumulated trace data
+ * and reset the cursor to point to the beginning of the buffer.
+ */
+static void WriteAndFlushBBTraceData () {
+ write_profiling_data(BBTraceInfo, ArrayStart, (ArrayCursor - ArrayStart));
+ ArrayCursor = ArrayStart;
+}
+
+/* BBTraceAtExitHandler - When the program exits, just write out any remaining
+ * data and free the trace buffer.
+ */
+static void BBTraceAtExitHandler(void) {
+ WriteAndFlushBBTraceData ();
+ free (ArrayStart);
+}
+
+/* llvm_trace_basic_block - called upon hitting a new basic block. */
+void llvm_trace_basic_block (unsigned BBNum) {
+ *ArrayCursor++ = BBNum;
+ if (ArrayCursor == ArrayEnd)
+ WriteAndFlushBBTraceData ();
+}
+
+/* llvm_start_basic_block_tracing - This is the main entry point of the basic
+ * block tracing library. It is responsible for setting up the atexit
+ * handler and allocating the trace buffer.
+ */
+int llvm_start_basic_block_tracing(int argc, const char **argv,
+ unsigned *arrayStart, unsigned numElements) {
+ int Ret;
+ const unsigned BufferSize = 128 * 1024;
+ unsigned ArraySize;
+
+ Ret = save_arguments(argc, argv);
+
+ /* Allocate a buffer to contain BB tracing data */
+ ArraySize = BufferSize / sizeof (unsigned);
+ ArrayStart = malloc (ArraySize * sizeof (unsigned));
+ ArrayEnd = ArrayStart + ArraySize;
+ ArrayCursor = ArrayStart;
+
+ /* Set up the atexit handler. */
+ atexit (BBTraceAtExitHandler);
+
+ return Ret;
+}
diff --git a/runtime/libprofile/CMakeLists.txt b/runtime/libprofile/CMakeLists.txt
new file mode 100644
index 0000000000..8609715b33
--- /dev/null
+++ b/runtime/libprofile/CMakeLists.txt
@@ -0,0 +1,20 @@
+set(SOURCES
+ BasicBlockTracing.c
+ CommonProfiling.c
+ GCDAProfiling.c
+ PathProfiling.c
+ EdgeProfiling.c
+ OptimalEdgeProfiling.c
+ Profiling.h
+ )
+
+add_llvm_library( profile_rt-static ${SOURCES} )
+set_target_properties( profile_rt-static
+ PROPERTIES
+ OUTPUT_NAME "profile_rt" )
+
+set(BUILD_SHARED_LIBS ON)
+add_llvm_library( profile_rt-shared ${SOURCES} )
+set_target_properties( profile_rt-shared
+ PROPERTIES
+ OUTPUT_NAME "profile_rt" )
diff --git a/runtime/libprofile/CommonProfiling.c b/runtime/libprofile/CommonProfiling.c
new file mode 100644
index 0000000000..acc17ce11e
--- /dev/null
+++ b/runtime/libprofile/CommonProfiling.c
@@ -0,0 +1,151 @@
+/*===-- CommonProfiling.c - Profiling support library support -------------===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+|*===----------------------------------------------------------------------===*|
+|*
+|* This file implements functions used by the various different types of
+|* profiling implementations.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#include "Profiling.h"
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#if !defined(_MSC_VER) && !defined(__MINGW32__)
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+#include <stdlib.h>
+
+static char *SavedArgs = 0;
+static unsigned SavedArgsLength = 0;
+
+static const char *OutputFilename = "llvmprof.out";
+
+/* save_arguments - Save argc and argv as passed into the program for the file
+ * we output.
+ */
+int save_arguments(int argc, const char **argv) {
+ unsigned Length, i;
+ if (SavedArgs || !argv) return argc; /* This can be called multiple times */
+
+ /* Check to see if there are any arguments passed into the program for the
+ * profiler. If there are, strip them off and remember their settings.
+ */
+ while (argc > 1 && !strncmp(argv[1], "-llvmprof-", 10)) {
+ /* Ok, we have an llvmprof argument. Remove it from the arg list and decide
+ * what to do with it.
+ */
+ const char *Arg = argv[1];
+ memmove((char**)&argv[1], &argv[2], (argc-1)*sizeof(char*));
+ --argc;
+
+ if (!strcmp(Arg, "-llvmprof-output")) {
+ if (argc == 1)
+ puts("-llvmprof-output requires a filename argument!");
+ else {
+ OutputFilename = strdup(argv[1]);
+ memmove((char**)&argv[1], &argv[2], (argc-1)*sizeof(char*));
+ --argc;
+ }
+ } else {
+ printf("Unknown option to the profiler runtime: '%s' - ignored.\n", Arg);
+ }
+ }
+
+ for (Length = 0, i = 0; i != (unsigned)argc; ++i)
+ Length += strlen(argv[i])+1;
+
+ /* Defensively check for a zero length, even though this is unlikely
+ * to happen in practice. This avoids calling malloc() below with a
+ * size of 0.
+ */
+ if (Length == 0) {
+ SavedArgs = 0;
+ SavedArgsLength = 0;
+ return argc;
+ }
+
+ SavedArgs = (char*)malloc(Length);
+ for (Length = 0, i = 0; i != (unsigned)argc; ++i) {
+ unsigned Len = strlen(argv[i]);
+ memcpy(SavedArgs+Length, argv[i], Len);
+ Length += Len;
+ SavedArgs[Length++] = ' ';
+ }
+
+ SavedArgsLength = Length;
+
+ return argc;
+}
+
+
+/*
+ * Retrieves the file descriptor for the profile file.
+ */
+int getOutFile() {
+ static int OutFile = -1;
+
+ /* If this is the first time this function is called, open the output file
+ * for appending, creating it if it does not already exist.
+ */
+ if (OutFile == -1) {
+ OutFile = open(OutputFilename, O_CREAT | O_WRONLY, 0666);
+ lseek(OutFile, 0, SEEK_END); /* O_APPEND prevents seeking */
+ if (OutFile == -1) {
+ fprintf(stderr, "LLVM profiling runtime: while opening '%s': ",
+ OutputFilename);
+ perror("");
+ return(OutFile);
+ }
+
+ /* Output the command line arguments to the file. */
+ {
+ int PTy = ArgumentInfo;
+ int Zeros = 0;
+ if (write(OutFile, &PTy, sizeof(int)) < 0 ||
+ write(OutFile, &SavedArgsLength, sizeof(unsigned)) < 0 ||
+ write(OutFile, SavedArgs, SavedArgsLength) < 0 ) {
+ fprintf(stderr,"error: unable to write to output file.");
+ exit(0);
+ }
+ /* Pad out to a multiple of four bytes */
+ if (SavedArgsLength & 3) {
+ if (write(OutFile, &Zeros, 4-(SavedArgsLength&3)) < 0) {
+ fprintf(stderr,"error: unable to write to output file.");
+ exit(0);
+ }
+ }
+ }
+ }
+ return(OutFile);
+}
+
+/* write_profiling_data - Write a raw block of profiling counters out to the
+ * llvmprof.out file. Note that we allow programs to be instrumented with
+ * multiple different kinds of instrumentation. For this reason, this function
+ * may be called more than once.
+ */
+void write_profiling_data(enum ProfilingType PT, unsigned *Start,
+ unsigned NumElements) {
+ int PTy;
+ int outFile = getOutFile();
+
+ /* Write out this record! */
+ PTy = PT;
+ if( write(outFile, &PTy, sizeof(int)) < 0 ||
+ write(outFile, &NumElements, sizeof(unsigned)) < 0 ||
+ write(outFile, Start, NumElements*sizeof(unsigned)) < 0 ) {
+ fprintf(stderr,"error: unable to write to output file.");
+ exit(0);
+ }
+}
diff --git a/runtime/libprofile/EdgeProfiling.c b/runtime/libprofile/EdgeProfiling.c
new file mode 100644
index 0000000000..f19e188f0d
--- /dev/null
+++ b/runtime/libprofile/EdgeProfiling.c
@@ -0,0 +1,45 @@
+/*===-- EdgeProfiling.c - Support library for edge profiling --------------===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+|*===----------------------------------------------------------------------===*|
+|*
+|* This file implements the call back routines for the edge profiling
+|* instrumentation pass. This should be used with the -insert-edge-profiling
+|* LLVM pass.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#include "Profiling.h"
+#include <stdlib.h>
+
+static unsigned *ArrayStart;
+static unsigned NumElements;
+
+/* EdgeProfAtExitHandler - When the program exits, just write out the profiling
+ * data.
+ */
+static void EdgeProfAtExitHandler(void) {
+ /* Note that if this were doing something more intelligent with the
+ * instrumentation, we could do some computation here to expand what we
+ * collected into simple edge profiles. Since we directly count each edge, we
+ * just write out all of the counters directly.
+ */
+ write_profiling_data(EdgeInfo, ArrayStart, NumElements);
+}
+
+
+/* llvm_start_edge_profiling - This is the main entry point of the edge
+ * profiling library. It is responsible for setting up the atexit handler.
+ */
+int llvm_start_edge_profiling(int argc, const char **argv,
+ unsigned *arrayStart, unsigned numElements) {
+ int Ret = save_arguments(argc, argv);
+ ArrayStart = arrayStart;
+ NumElements = numElements;
+ atexit(EdgeProfAtExitHandler);
+ return Ret;
+}
diff --git a/runtime/libprofile/GCDAProfiling.c b/runtime/libprofile/GCDAProfiling.c
new file mode 100644
index 0000000000..f2dc4f7988
--- /dev/null
+++ b/runtime/libprofile/GCDAProfiling.c
@@ -0,0 +1,205 @@
+/*===- GCDAProfiling.c - Support library for GCDA file emission -----------===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+|*===----------------------------------------------------------------------===*|
+|*
+|* This file implements the call back routines for the gcov profiling
+|* instrumentation pass. Link against this library when running code through
+|* the -insert-gcov-profiling LLVM pass.
+|*
+|* We emit files in a corrupt version of GCOV's "gcda" file format. These files
+|* are only close enough that LCOV will happily parse them. Anything that lcov
+|* ignores is missing.
+|*
+|* TODO: gcov is multi-process safe by having each exit open the existing file
+|* and append to it. We'd like to achieve that and be thread-safe too.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#include "llvm/Support/DataTypes.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#ifdef _WIN32
+#include <direct.h>
+#endif
+
+/* #define DEBUG_GCDAPROFILING */
+
+/*
+ * --- GCOV file format I/O primitives ---
+ */
+
+static FILE *output_file = NULL;
+
+static void write_int32(uint32_t i) {
+ fwrite(&i, 4, 1, output_file);
+}
+
+static void write_int64(uint64_t i) {
+ uint32_t lo = i >> 0;
+ uint32_t hi = i >> 32;
+ write_int32(lo);
+ write_int32(hi);
+}
+
+static uint32_t length_of_string(const char *s) {
+ return (strlen(s) / 4) + 1;
+}
+
+static void write_string(const char *s) {
+ uint32_t len = length_of_string(s);
+ write_int32(len);
+ fwrite(s, strlen(s), 1, output_file);
+ fwrite("\0\0\0\0", 4 - (strlen(s) % 4), 1, output_file);
+}
+
+static char *mangle_filename(const char *orig_filename) {
+ /* TODO: handle GCOV_PREFIX_STRIP */
+ const char *prefix;
+ char *filename = 0;
+
+ prefix = getenv("GCOV_PREFIX");
+
+ if (!prefix)
+ return strdup(orig_filename);
+
+ filename = malloc(strlen(prefix) + 1 + strlen(orig_filename) + 1);
+ strcpy(filename, prefix);
+ strcat(filename, "/");
+ strcat(filename, orig_filename);
+ return filename;
+}
+
+static void recursive_mkdir(const char *filename) {
+ char *pathname;
+ int i, e;
+
+ for (i = 1, e = strlen(filename); i != e; ++i) {
+ if (filename[i] != '/') continue;
+ pathname = malloc(i + 1);
+ strncpy(pathname, filename, i);
+ pathname[i] = '\0';
+#ifdef _WIN32
+ _mkdir(pathname);
+#else
+ mkdir(pathname, 0750); /* some of these will fail, ignore it. */
+#endif
+ free(pathname);
+ }
+}
+
+/*
+ * --- LLVM line counter API ---
+ */
+
+/* A file in this case is a translation unit. Each .o file built with line
+ * profiling enabled will emit to a different file. Only one file may be
+ * started at a time.
+ */
+void llvm_gcda_start_file(const char *orig_filename) {
+ char *filename;
+ filename = mangle_filename(orig_filename);
+ recursive_mkdir(filename);
+ output_file = fopen(filename, "w+b");
+
+ if (!output_file) {
+ const char *cptr = strrchr(orig_filename, '/');
+ output_file = fopen(cptr ? cptr + 1 : orig_filename, "w+b");
+
+ if (!output_file) {
+ fprintf(stderr, "LLVM profiling runtime: cannot open '%s': ",
+ cptr ? cptr + 1 : orig_filename);
+ perror("");
+ free(filename);
+ return;
+ }
+ }
+
+ /* gcda file, version 404*, stamp LLVM. */
+#ifdef __APPLE__
+ fwrite("adcg*204MVLL", 12, 1, output_file);
+#else
+ fwrite("adcg*404MVLL", 12, 1, output_file);
+#endif
+
+#ifdef DEBUG_GCDAPROFILING
+ printf("llvmgcda: [%s]\n", orig_filename);
+#endif
+
+ free(filename);
+}
+
+/* Given an array of pointers to counters (counters), increment the n-th one,
+ * where we're also given a pointer to n (predecessor).
+ */
+void llvm_gcda_increment_indirect_counter(uint32_t *predecessor,
+ uint64_t **counters) {
+ uint64_t *counter;
+ uint32_t pred;
+
+ pred = *predecessor;
+ if (pred == 0xffffffff)
+ return;
+ counter = counters[pred];
+
+ /* Don't crash if the pred# is out of sync. This can happen due to threads,
+ or because of a TODO in GCOVProfiling.cpp buildEdgeLookupTable(). */
+ if (counter)
+ ++*counter;
+#ifdef DEBUG_GCDAPROFILING
+ else
+ printf("llvmgcda: increment_indirect_counter counters=%x, pred=%u\n",
+ state_table_row, *predecessor);
+#endif
+}
+
+void llvm_gcda_emit_function(uint32_t ident, const char *function_name) {
+#ifdef DEBUG_GCDAPROFILING
+ printf("llvmgcda: function id=%x\n", ident);
+#endif
+ if (!output_file) return;
+
+ /* function tag */
+ fwrite("\0\0\0\1", 4, 1, output_file);
+ write_int32(3 + 1 + length_of_string(function_name));
+ write_int32(ident);
+ write_int32(0);
+ write_int32(0);
+ write_string(function_name);
+}
+
+void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) {
+ uint32_t i;
+
+ /* Counter #1 (arcs) tag */
+ if (!output_file) return;
+ fwrite("\0\0\xa1\1", 4, 1, output_file);
+ write_int32(num_counters * 2);
+ for (i = 0; i < num_counters; ++i)
+ write_int64(counters[i]);
+
+#ifdef DEBUG_GCDAPROFILING
+ printf("llvmgcda: %u arcs\n", num_counters);
+ for (i = 0; i < num_counters; ++i)
+ printf("llvmgcda: %llu\n", (unsigned long long)counters[i]);
+#endif
+}
+
+void llvm_gcda_end_file() {
+ /* Write out EOF record. */
+ if (!output_file) return;
+ fwrite("\0\0\0\0\0\0\0\0", 8, 1, output_file);
+ fclose(output_file);
+ output_file = NULL;
+
+#ifdef DEBUG_GCDAPROFILING
+ printf("llvmgcda: -----\n");
+#endif
+}
diff --git a/runtime/libprofile/Makefile b/runtime/libprofile/Makefile
new file mode 100644
index 0000000000..d8511495ce
--- /dev/null
+++ b/runtime/libprofile/Makefile
@@ -0,0 +1,51 @@
+##===- runtime/libprofile/Makefile -------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../..
+include $(LEVEL)/Makefile.config
+
+ifneq ($(strip $(LLVMCC)),)
+BYTECODE_LIBRARY = 1
+endif
+LIBRARYNAME = profile_rt
+LINK_LIBS_IN_SHARED = 1
+SHARED_LIBRARY = 1
+EXTRA_DIST = libprofile.exports
+EXPORTED_SYMBOL_FILE = $(PROJ_SRC_DIR)/libprofile.exports
+
+# Build and install this archive.
+BUILD_ARCHIVE = 1
+override NO_INSTALL_ARCHIVES =
+
+include $(LEVEL)/Makefile.common
+
+ifeq ($(HOST_OS),Darwin)
+ # Special hack to allow libprofile_rt to have an offset version number.
+ PROFILE_RT_LIBRARY_VERSION := $(LLVM_SUBMIT_VERSION)
+
+ # Set dylib internal version number to llvmCore submission number.
+ ifdef LLVM_SUBMIT_VERSION
+ LLVMLibsOptions := $(LLVMLibsOptions) -Wl,-current_version \
+ -Wl,$(PROFILE_RT_LIBRARY_VERSION).$(LLVM_SUBMIT_SUBVERSION) \
+ -Wl,-compatibility_version -Wl,1
+ endif
+ # Extra options to override libtool defaults.
+ LLVMLibsOptions := $(LLVMLibsOptions) \
+ -Wl,-dead_strip \
+ -Wl,-seg1addr -Wl,0xE0000000
+
+ # Mac OS X 10.4 and earlier tools do not allow a second -install_name on
+ # command line.
+ DARWIN_VERS := $(shell echo $(TARGET_TRIPLE) | sed 's/.*darwin\([0-9]*\).*/\1/')
+ ifneq ($(DARWIN_VERS),8)
+ LLVMLibsOptions := $(LLVMLibsOptions) \
+ -Wl,-install_name \
+ -Wl,"@executable_path/../lib/lib$(LIBRARYNAME)$(SHLIBEXT)"
+ endif
+endif
diff --git a/runtime/libprofile/OptimalEdgeProfiling.c b/runtime/libprofile/OptimalEdgeProfiling.c
new file mode 100644
index 0000000000..3a7631b6e8
--- /dev/null
+++ b/runtime/libprofile/OptimalEdgeProfiling.c
@@ -0,0 +1,45 @@
+/*===-- OptimalEdgeProfiling.c - Support library for opt. edge profiling --===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+|*===----------------------------------------------------------------------===*|
+|*
+|* This file implements the call back routines for the edge profiling
+|* instrumentation pass. This should be used with the
+|* -insert-opt-edge-profiling LLVM pass.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#include "Profiling.h"
+#include <stdlib.h>
+
+static unsigned *ArrayStart;
+static unsigned NumElements;
+
+/* OptEdgeProfAtExitHandler - When the program exits, just write out the
+ * profiling data.
+ */
+static void OptEdgeProfAtExitHandler(void) {
+ /* Note that, although the array has a counter for each edge, not all
+ * counters are updated, the ones that are not used are initialised with -1.
+ * When loading this information the counters with value -1 have to be
+ * recalculated, it is guaranteed that this is possible.
+ */
+ write_profiling_data(OptEdgeInfo, ArrayStart, NumElements);
+}
+
+
+/* llvm_start_opt_edge_profiling - This is the main entry point of the edge
+ * profiling library. It is responsible for setting up the atexit handler.
+ */
+int llvm_start_opt_edge_profiling(int argc, const char **argv,
+ unsigned *arrayStart, unsigned numElements) {
+ int Ret = save_arguments(argc, argv);
+ ArrayStart = arrayStart;
+ NumElements = numElements;
+ atexit(OptEdgeProfAtExitHandler);
+ return Ret;
+}
diff --git a/runtime/libprofile/PathProfiling.c b/runtime/libprofile/PathProfiling.c
new file mode 100644
index 0000000000..71ee944fc5
--- /dev/null
+++ b/runtime/libprofile/PathProfiling.c
@@ -0,0 +1,270 @@
+/*===-- PathProfiling.c - Support library for path profiling --------------===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+|*===----------------------------------------------------------------------===*|
+|*
+|* This file implements the call back routines for the path profiling
+|* instrumentation pass. This should be used with the -insert-path-profiling
+|* LLVM pass.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#include "Profiling.h"
+#include "llvm/Analysis/ProfileInfoTypes.h"
+#include "llvm/Support/DataTypes.h"
+#include <sys/types.h>
+#if !defined(_MSC_VER) && !defined(__MINGW32__)
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+/* note that this is used for functions with large path counts,
+ but it is unlikely those paths will ALL be executed */
+#define ARBITRARY_HASH_BIN_COUNT 100
+
+typedef struct pathHashEntry_s {
+ uint32_t pathNumber;
+ uint32_t pathCount;
+ struct pathHashEntry_s* next;
+} pathHashEntry_t;
+
+typedef struct pathHashTable_s {
+ pathHashEntry_t* hashBins[ARBITRARY_HASH_BIN_COUNT];
+ uint32_t pathCounts;
+} pathHashTable_t;
+
+typedef struct {
+ enum ProfilingStorageType type;
+ uint32_t size;
+ void* array;
+} ftEntry_t;
+
+/* pointer to the function table allocated in the instrumented program */
+ftEntry_t* ft;
+uint32_t ftSize;
+
+/* write an array table to file */
+void writeArrayTable(uint32_t fNumber, ftEntry_t* ft, uint32_t* funcCount) {
+ int outFile = getOutFile();
+ uint32_t arrayHeaderLocation = 0;
+ uint32_t arrayCurrentLocation = 0;
+ uint32_t arrayIterator = 0;
+ uint32_t functionUsed = 0;
+ uint32_t pathCounts = 0;
+
+ /* look through each entry in the array to determine whether the function
+ was executed at all */
+ for( arrayIterator = 0; arrayIterator < ft->size; arrayIterator++ ) {
+ uint32_t pc = ((uint32_t*)ft->array)[arrayIterator];
+
+ /* was this path executed? */
+ if( pc ) {
+ PathProfileTableEntry pte;
+ pte.pathNumber = arrayIterator;
+ pte.pathCounter = pc;
+ pathCounts++;
+
+ /* one-time initialization stuff */
+ if(!functionUsed) {
+ arrayHeaderLocation = lseek(outFile, 0, SEEK_CUR);
+ lseek(outFile, sizeof(PathProfileHeader), SEEK_CUR);
+ functionUsed = 1;
+ (*funcCount)++;
+ }
+
+ /* write path data */
+ if (write(outFile, &pte, sizeof(PathProfileTableEntry)) < 0) {
+ fprintf(stderr, "error: unable to write path entry to output file.\n");
+ return;
+ }
+ }
+ }
+
+ /* If this function was executed, write the header */
+ if( functionUsed ) {
+ PathProfileHeader fHeader;
+ fHeader.fnNumber = fNumber;
+ fHeader.numEntries = pathCounts;
+
+ arrayCurrentLocation = lseek(outFile, 0, SEEK_CUR);
+ lseek(outFile, arrayHeaderLocation, SEEK_SET);
+
+ if (write(outFile, &fHeader, sizeof(PathProfileHeader)) < 0) {
+ fprintf(stderr,
+ "error: unable to write function header to output file.\n");
+ return;
+ }
+
+ lseek(outFile, arrayCurrentLocation, SEEK_SET);
+ }
+}
+
+static uint32_t hash (uint32_t key) {
+ /* this may benefit from a proper hash function */
+ return key%ARBITRARY_HASH_BIN_COUNT;
+}
+
+/* output a specific function's hash table to the profile file */
+void writeHashTable(uint32_t functionNumber, pathHashTable_t* hashTable) {
+ int outFile = getOutFile();
+ PathProfileHeader header;
+ uint32_t i;
+
+ header.fnNumber = functionNumber;
+ header.numEntries = hashTable->pathCounts;
+
+ if (write(outFile, &header, sizeof(PathProfileHeader)) < 0) {
+ fprintf(stderr, "error: unable to write function header to output file.\n");
+ return;
+ }
+
+ for (i = 0; i < ARBITRARY_HASH_BIN_COUNT; i++) {
+ pathHashEntry_t* hashEntry = hashTable->hashBins[i];
+
+ while (hashEntry) {
+ pathHashEntry_t* temp;
+
+ PathProfileTableEntry pte;
+ pte.pathNumber = hashEntry->pathNumber;
+ pte.pathCounter = hashEntry->pathCount;
+
+ if (write(outFile, &pte, sizeof(PathProfileTableEntry)) < 0) {
+ fprintf(stderr, "error: unable to write path entry to output file.\n");
+ return;
+ }
+
+ temp = hashEntry;
+ hashEntry = hashEntry->next;
+ free (temp);
+
+ }
+ }
+}
+
+/* Return a pointer to this path's specific path counter */
+static uint32_t* getPathCounter(uint32_t functionNumber,
+ uint32_t pathNumber) {
+ pathHashTable_t* hashTable;
+ pathHashEntry_t* hashEntry;
+ uint32_t index = hash(pathNumber);
+
+ if( ft[functionNumber-1].array == 0)
+ ft[functionNumber-1].array = calloc(sizeof(pathHashTable_t), 1);
+
+ hashTable = (pathHashTable_t*)((ftEntry_t*)ft)[functionNumber-1].array;
+ hashEntry = hashTable->hashBins[index];
+
+ while (hashEntry) {
+ if (hashEntry->pathNumber == pathNumber) {
+ return &hashEntry->pathCount;
+ }
+
+ hashEntry = hashEntry->next;
+ }
+
+ hashEntry = malloc(sizeof(pathHashEntry_t));
+ hashEntry->pathNumber = pathNumber;
+ hashEntry->pathCount = 0;
+ hashEntry->next = hashTable->hashBins[index];
+ hashTable->hashBins[index] = hashEntry;
+ hashTable->pathCounts++;
+ return &hashEntry->pathCount;
+}
+
+/* Increment a specific path's count */
+void llvm_increment_path_count (uint32_t functionNumber, uint32_t pathNumber) {
+ uint32_t* pathCounter = getPathCounter(functionNumber, pathNumber);
+ if( *pathCounter < 0xffffffff )
+ (*pathCounter)++;
+}
+
+/* Increment a specific path's count */
+void llvm_decrement_path_count (uint32_t functionNumber, uint32_t pathNumber) {
+ uint32_t* pathCounter = getPathCounter(functionNumber, pathNumber);
+ (*pathCounter)--;
+}
+
+/*
+ * Writes out a path profile given a function table, in the following format.
+ *
+ *
+ * | <-- 32 bits --> |
+ * +-----------------+-----------------+
+ * 0x00 | profileType | functionCount |
+ * +-----------------+-----------------+
+ * 0x08 | functionNum | profileEntries | // function 1
+ * +-----------------+-----------------+
+ * 0x10 | pathNumber | pathCounter | // entry 1.1
+ * +-----------------+-----------------+
+ * 0x18 | pathNumber | pathCounter | // entry 1.2
+ * +-----------------+-----------------+
+ * ... | ... | ... | // entry 1.n
+ * +-----------------+-----------------+
+ * ... | functionNum | profileEntries | // function 2
+ * +-----------------+-----------------+
+ * ... | pathNumber | pathCounter | // entry 2.1
+ * +-----------------+-----------------+
+ * ... | pathNumber | pathCounter | // entry 2.2
+ * +-----------------+-----------------+
+ * ... | ... | ... | // entry 2.n
+ * +-----------------+-----------------+
+ *
+ */
+static void pathProfAtExitHandler(void) {
+ int outFile = getOutFile();
+ uint32_t i;
+ uint32_t header[2] = { PathInfo, 0 };
+ uint32_t headerLocation;
+ uint32_t currentLocation;
+
+ /* skip over the header for now */
+ headerLocation = lseek(outFile, 0, SEEK_CUR);
+ lseek(outFile, 2*sizeof(uint32_t), SEEK_CUR);
+
+ /* Iterate through each function */
+ for( i = 0; i < ftSize; i++ ) {
+ if( ft[i].type == ProfilingArray ) {
+ writeArrayTable(i+1,&ft[i],header + 1);
+
+ } else if( ft[i].type == ProfilingHash ) {
+ /* If the hash exists, write it to file */
+ if( ft[i].array ) {
+ writeHashTable(i+1,ft[i].array);
+ header[1]++;
+ free(ft[i].array);
+ }
+ }
+ }
+
+ /* Setup and write the path profile header */
+ currentLocation = lseek(outFile, 0, SEEK_CUR);
+ lseek(outFile, headerLocation, SEEK_SET);
+
+ if (write(outFile, header, sizeof(header)) < 0) {
+ fprintf(stderr,
+ "error: unable to write path profile header to output file.\n");
+ return;
+ }
+
+ lseek(outFile, currentLocation, SEEK_SET);
+}
+/* llvm_start_path_profiling - This is the main entry point of the path
+ * profiling library. It is responsible for setting up the atexit handler.
+ */
+int llvm_start_path_profiling(int argc, const char** argv,
+ void* functionTable, uint32_t numElements) {
+ int Ret = save_arguments(argc, argv);
+ ft = functionTable;
+ ftSize = numElements;
+ atexit(pathProfAtExitHandler);
+
+ return Ret;
+}
diff --git a/runtime/libprofile/Profiling.h b/runtime/libprofile/Profiling.h
new file mode 100644
index 0000000000..acc6399a18
--- /dev/null
+++ b/runtime/libprofile/Profiling.h
@@ -0,0 +1,36 @@
+/*===-- Profiling.h - Profiling support library support routines ----------===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+|*===----------------------------------------------------------------------===*|
+|*
+|* This file defines functions shared by the various different profiling
+|* implementations.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#ifndef PROFILING_H
+#define PROFILING_H
+
+#include "llvm/Analysis/ProfileDataTypes.h" /* for enum ProfilingType */
+
+/* save_arguments - Save argc and argv as passed into the program for the file
+ * we output.
+ */
+int save_arguments(int argc, const char **argv);
+
+/*
+ * Retrieves the file descriptor for the profile file.
+ */
+int getOutFile();
+
+/* write_profiling_data - Write out a typed packet of profiling data to the
+ * current output file.
+ */
+void write_profiling_data(enum ProfilingType PT, unsigned *Start,
+ unsigned NumElements);
+
+#endif
diff --git a/runtime/libprofile/libprofile.exports b/runtime/libprofile/libprofile.exports
new file mode 100644
index 0000000000..2f25be6920
--- /dev/null
+++ b/runtime/libprofile/libprofile.exports
@@ -0,0 +1,12 @@
+llvm_start_edge_profiling
+llvm_start_opt_edge_profiling
+llvm_start_path_profiling
+llvm_start_basic_block_tracing
+llvm_trace_basic_block
+llvm_increment_path_count
+llvm_decrement_path_count
+llvm_gcda_start_file
+llvm_gcda_increment_indirect_counter
+llvm_gcda_emit_function
+llvm_gcda_emit_arcs
+llvm_gcda_end_file