clover: Add environment variables for dumping kernel code v2
authorTom Stellard <thomas.stellard@amd.com>
Tue, 30 Sep 2014 14:32:33 +0000 (10:32 -0400)
committerTom Stellard <thomas.stellard@amd.com>
Thu, 16 Oct 2014 23:42:52 +0000 (19:42 -0400)
There are two debug variables:

CLOVER_DEBUG which you can set to any combination of llvm,clc,asm
(separated by commas) to dump llvm IR, OpenCL C, and native assembly.

CLOVER_DEBUG_FILE which you can set to a file name for dumping output
instead of stderr.  If you set this variable, the output will be split
into three separate files with different suffixes: .cl for OpenCL C,
.ll for LLVM IR, and .asm for native assembly.  Note that when data
is written, it is always appended to the files.

v2:
  - Code cleanups
  - Add CLOVER_DEBUG_FILE environment variable for dumping to a file.

Reviewed-by: Francisco Jerez <currojerez@riseup.net>
src/gallium/state_trackers/clover/llvm/invocation.cpp

index 56607615343a38696dd2dceda3188a8e07a3065d..3cdf883e403432abb9410bca20a127a853740179 100644 (file)
@@ -61,6 +61,8 @@
 #include <llvm/Support/TargetRegistry.h>
 #include <llvm/Transforms/IPO.h>
 #include <llvm/Transforms/IPO/PassManagerBuilder.h>
+#include <llvm/Transforms/Utils/Cloning.h>
+
 
 #if HAVE_LLVM < 0x0302
 #include <llvm/Target/TargetData.h>
@@ -132,6 +134,15 @@ namespace {
       return module::deserialize(cs);
    }
 #endif
+   void debug_log(const std::string &msg, const std::string &suffix) {
+      const char *dbg_file = debug_get_option("CLOVER_DEBUG_FILE", "stderr");
+      if (!strcmp("stderr", dbg_file)) {
+         std::cerr << msg;
+       } else {
+        std::ofstream file(dbg_file + suffix, std::ios::app);
+        file << msg;
+       }
+   }
 
    llvm::Module *
    compile_llvm(llvm::LLVMContext &llvm_ctx, const std::string &source,
@@ -456,9 +467,32 @@ namespace {
       return m;
    }
 
+   void
+   emit_code(LLVMTargetMachineRef tm, LLVMModuleRef mod,
+             LLVMCodeGenFileType file_type,
+             LLVMMemoryBufferRef *out_buffer,
+             compat::string &r_log) {
+      LLVMBool err;
+      char *err_message = NULL;
+
+      err = LLVMTargetMachineEmitToMemoryBuffer(tm, mod, file_type,
+                                                &err_message, out_buffer);
+
+      if (err) {
+         r_log = std::string(err_message);
+      }
+
+      LLVMDisposeMessage(err_message);
+
+      if (err) {
+         throw build_error();
+      }
+   }
+
    std::vector<char>
    compile_native(const llvm::Module *mod, const std::string &triple,
-                  const std::string &processor, compat::string &r_log) {
+                  const std::string &processor, unsigned dump_asm,
+                  compat::string &r_log) {
 
       std::string log;
       LLVMTargetRef target;
@@ -466,7 +500,6 @@ namespace {
       LLVMMemoryBufferRef out_buffer;
       unsigned buffer_size;
       const char *buffer_data;
-      LLVMBool err;
       LLVMModuleRef mod_ref = wrap(mod);
 
       if (LLVMGetTargetFromTriple(triple.c_str(), &target, &error_message)) {
@@ -484,16 +517,21 @@ namespace {
          throw build_error();
       }
 
-      err = LLVMTargetMachineEmitToMemoryBuffer(tm, mod_ref, LLVMObjectFile,
-                                                &error_message, &out_buffer);
-
-      if (err) {
-         LLVMDisposeTargetMachine(tm);
-         r_log = std::string(error_message);
-         LLVMDisposeMessage(error_message);
-         throw build_error();
+      if (dump_asm) {
+         LLVMSetTargetMachineAsmVerbosity(tm, true);
+         LLVMModuleRef debug_mod = wrap(llvm::CloneModule(mod));
+         emit_code(tm, debug_mod, LLVMAssemblyFile, &out_buffer, r_log);
+         buffer_size = LLVMGetBufferSize(out_buffer);
+         buffer_data = LLVMGetBufferStart(out_buffer);
+         debug_log(std::string(buffer_data, buffer_size), ".asm");
+
+         LLVMSetTargetMachineAsmVerbosity(tm, false);
+         LLVMDisposeMemoryBuffer(out_buffer);
+         LLVMDisposeModule(debug_mod);
       }
 
+      emit_code(tm, mod_ref, LLVMObjectFile, &out_buffer, r_log);
+
       buffer_size = LLVMGetBufferSize(out_buffer);
       buffer_data = LLVMGetBufferStart(out_buffer);
 
@@ -632,6 +670,18 @@ namespace {
    }
 } // End anonymous namespace
 
+#define DBG_CLC  (1 << 0)
+#define DBG_LLVM (1 << 1)
+#define DBG_ASM  (1 << 2)
+
+static const struct debug_named_value debug_options[] = {
+   {"clc", DBG_CLC, "Dump the OpenCL C code for all kernels."},
+   {"llvm", DBG_LLVM, "Dump the generated LLVM IR for all kernels."},
+   {"asm", DBG_ASM, "Dump kernel assembly code for targets specifying "
+                    "PIPE_SHADER_IR_NATIVE"},
+       DEBUG_NAMED_VALUE_END // must be last
+};
+
 module
 clover::compile_program_llvm(const compat::string &source,
                              enum pipe_shader_ir ir,
@@ -640,6 +690,8 @@ clover::compile_program_llvm(const compat::string &source,
                              compat::string &r_log) {
 
    init_targets();
+   static unsigned debug_flags = debug_get_flags_option("CLOVER_DEBUG",
+                                                         debug_options, 0);
 
    std::vector<llvm::Function *> kernels;
    size_t processor_str_len = std::string(target.begin()).find_first_of("-");
@@ -664,6 +716,17 @@ clover::compile_program_llvm(const compat::string &source,
 
    optimize(mod, optimization_level, kernels);
 
+   if (debug_flags & DBG_CLC)
+      debug_log(source, ".cl");
+
+   if (debug_flags & DBG_LLVM) {
+      std::string log;
+      llvm::raw_string_ostream s_log(log);
+      mod->print(s_log, NULL);
+      s_log.flush();
+      debug_log(log, ".ll");
+    }
+
    module m;
    // Build the clover::module
    switch (ir) {
@@ -676,7 +739,8 @@ clover::compile_program_llvm(const compat::string &source,
          m = build_module_llvm(mod, kernels, address_spaces);
          break;
       case PIPE_SHADER_IR_NATIVE: {
-         std::vector<char> code = compile_native(mod, triple, processor, r_log);
+         std::vector<char> code = compile_native(mod, triple, processor,
+                                                debug_flags & DBG_ASM, r_log);
          m = build_module_native(code, mod, kernels, address_spaces, r_log);
          break;
       }