radeon/llvm: Use LLVM C API for compiling LLVM IR to ISA v2
authorTom Stellard <thomas.stellard@amd.com>
Tue, 2 Apr 2013 17:42:50 +0000 (10:42 -0700)
committerTom Stellard <thomas.stellard@amd.com>
Mon, 6 May 2013 16:06:06 +0000 (09:06 -0700)
The LLVM C API is considered stable and should never change, so it
is much more desirable to use than the LLVM C++ API, which is constantly in
flux.

v2:
  - Split target initialization and lookup into separate functions

Reviewed-by: Mathias.Froehlich@web.de
src/gallium/drivers/radeon/Makefile.am
src/gallium/drivers/radeon/Makefile.sources
src/gallium/drivers/radeon/radeon_llvm_emit.c [new file with mode: 0644]
src/gallium/drivers/radeon/radeon_llvm_emit.cpp [deleted file]
src/gallium/drivers/radeon/radeon_llvm_emit.h

index f1f8ced78dce729c78416b30d54aba37ec3c96aa..32ad32932b00c3ac4938fb30bd772838deabf906 100644 (file)
@@ -27,7 +27,6 @@ endif
 
 libllvmradeon@VERSION@_la_CXXFLAGS = \
        $(GALLIUM_CFLAGS) \
-       $(filter-out -DDEBUG, $(LLVM_CXXFLAGS)) \
        $(DEFINES)
 
 libllvmradeon@VERSION@_la_CFLAGS = \
@@ -35,7 +34,6 @@ libllvmradeon@VERSION@_la_CFLAGS = \
        $(LLVM_CFLAGS)
 
 libllvmradeon@VERSION@_la_SOURCES = \
-       $(LLVM_CPP_FILES) \
        $(LLVM_C_FILES)
 
 libllvmradeon@VERSION@_la_LIBADD = \
index a23d5c4ad2c7b4d179b6c10c4145617fe0f1ab54..d33c81b0fc084755e2f93dfd3d505e0b2ed543b9 100644 (file)
@@ -1,9 +1,7 @@
 C_SOURCES := \
        radeon_uvd.c
 
-LLVM_CPP_FILES := \
-       radeon_llvm_emit.cpp
-
 LLVM_C_FILES := \
        radeon_setup_tgsi_llvm.c \
+       radeon_llvm_emit.c \
        radeon_llvm_util.c
diff --git a/src/gallium/drivers/radeon/radeon_llvm_emit.c b/src/gallium/drivers/radeon/radeon_llvm_emit.c
new file mode 100644 (file)
index 0000000..1a4d4fd
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors: Tom Stellard <thomas.stellard@amd.com>
+ *
+ */
+#include "radeon_llvm_emit.h"
+#include "util/u_memory.h"
+
+#include <llvm-c/Target.h>
+#include <llvm-c/TargetMachine.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <libelf.h>
+#include <gelf.h>
+
+#define CPU_STRING_LEN 30
+#define FS_STRING_LEN 30
+#define TRIPLE_STRING_LEN 7
+
+/**
+ * Set the shader type we want to compile
+ *
+ * @param type shader type to set
+ */
+void radeon_llvm_shader_type(LLVMValueRef F, unsigned type)
+{
+  char Str[2];
+  sprintf(Str, "%1d", type);
+
+  LLVMAddTargetDependentFunctionAttr(F, "ShaderType", Str);
+}
+
+static void init_r600_target() {
+       static unsigned initialized = 0;
+       if (!initialized) {
+               LLVMInitializeR600TargetInfo();
+               LLVMInitializeR600Target();
+               LLVMInitializeR600TargetMC();
+               LLVMInitializeR600AsmPrinter();
+               initialized = 1;
+       }
+}
+
+static LLVMTargetRef get_r600_target() {
+       LLVMTargetRef target = NULL;
+
+       for (target = LLVMGetFirstTarget(); target;
+                                       target = LLVMGetNextTarget(target)) {
+               if (!strncmp(LLVMGetTargetName(target), "r600", 4)) {
+                       break;
+               }
+       }
+
+       if (!target) {
+               fprintf(stderr, "Can't find target r600\n");
+               return NULL;
+       }
+       return target;
+}
+
+/**
+ * Compile an LLVM module to machine code.
+ *
+ * @returns 0 for success, 1 for failure
+ */
+unsigned radeon_llvm_compile(LLVMModuleRef M, struct radeon_llvm_binary *binary,
+                                         const char * gpu_family, unsigned dump) {
+
+       LLVMTargetRef target;
+       LLVMTargetMachineRef tm;
+       char cpu[CPU_STRING_LEN];
+       char fs[FS_STRING_LEN];
+       char *err;
+       LLVMMemoryBufferRef out_buffer;
+       unsigned buffer_size;
+       const char *buffer_data;
+       char triple[TRIPLE_STRING_LEN];
+       char *elf_buffer;
+       Elf *elf;
+       Elf_Scn *section = NULL;
+       size_t section_str_index;
+       LLVMBool r;
+
+       init_r600_target();
+
+       target = get_r600_target();
+       if (!target) {
+               return 1;
+       }
+
+       strncpy(cpu, gpu_family, CPU_STRING_LEN);
+       memset(fs, 0, sizeof(fs));
+       if (dump) {
+               LLVMDumpModule(M);
+               strncpy(fs, "+DumpCode", FS_STRING_LEN);
+       }
+       strncpy(triple, "r600--", TRIPLE_STRING_LEN);
+       tm = LLVMCreateTargetMachine(target, triple, cpu, fs,
+                                 LLVMCodeGenLevelDefault, LLVMRelocDefault,
+                                                 LLVMCodeModelDefault);
+
+       r = LLVMTargetMachineEmitToMemoryBuffer(tm, M, LLVMObjectFile, &err,
+                                                                &out_buffer);
+       if (r) {
+               fprintf(stderr, err);
+               FREE(err);
+               return 1;
+       }
+
+       buffer_size = LLVMGetBufferSize(out_buffer);
+       buffer_data = LLVMGetBufferStart(out_buffer);
+
+       /* One of the libelf implementations
+        * (http://www.mr511.de/software/english.htm) requires calling
+        * elf_version() before elf_memory().
+        */
+       elf_version(EV_CURRENT);
+       elf_buffer = MALLOC(buffer_size);
+       memcpy(elf_buffer, buffer_data, buffer_size);
+
+       elf = elf_memory(elf_buffer, buffer_size);
+
+       elf_getshdrstrndx(elf, &section_str_index);
+
+       while ((section = elf_nextscn(elf, section))) {
+               const char *name;
+               Elf_Data *section_data = NULL;
+               GElf_Shdr section_header;
+               if (gelf_getshdr(section, &section_header) != &section_header) {
+                       fprintf(stderr, "Failed to read ELF section header\n");
+                       return 1;
+               }
+               name = elf_strptr(elf, section_str_index, section_header.sh_name);
+               if (!strcmp(name, ".text")) {
+                       section_data = elf_getdata(section, section_data);
+                       binary->code_size = section_data->d_size;
+                       binary->code = MALLOC(binary->code_size * sizeof(unsigned char));
+                       memcpy(binary->code, section_data->d_buf, binary->code_size);
+               } else if (!strcmp(name, ".AMDGPU.config")) {
+                       section_data = elf_getdata(section, section_data);
+                       binary->config_size = section_data->d_size;
+                       binary->config = MALLOC(binary->config_size * sizeof(unsigned char));
+                       memcpy(binary->config, section_data->d_buf, binary->config_size);
+               }
+       }
+
+       LLVMDisposeMemoryBuffer(out_buffer);
+       LLVMDisposeTargetMachine(tm);
+       return 0;
+}
diff --git a/src/gallium/drivers/radeon/radeon_llvm_emit.cpp b/src/gallium/drivers/radeon/radeon_llvm_emit.cpp
deleted file mode 100644 (file)
index 1012715..0000000
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright 2011 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * Authors: Tom Stellard <thomas.stellard@amd.com>
- *
- */
-#include "radeon_llvm_emit.h"
-
-#if HAVE_LLVM < 0x0303
-#include <llvm/LLVMContext.h>
-#include <llvm/Module.h>
-#include <llvm/Function.h>
-#include <llvm/DataLayout.h>
-#else
-#include <llvm/IR/LLVMContext.h>
-#include <llvm/IR/Module.h>
-#include <llvm/IR/Function.h>
-#include <llvm/IR/DataLayout.h>
-#endif
-
-#include <llvm/PassManager.h>
-#include <llvm/ADT/Triple.h>
-#include <llvm/Support/CBindingWrapping.h>
-#include <llvm/Support/FormattedStream.h>
-#include <llvm/Support/Host.h>
-#include <llvm/Support/SourceMgr.h>
-#include <llvm/Support/TargetRegistry.h>
-#include <llvm/Support/TargetSelect.h>
-#include <llvm/Support/Threading.h>
-#include <llvm/Target/TargetMachine.h>
-#include <llvm/Transforms/Scalar.h>
-#include <llvm-c/Target.h>
-
-#include <iostream>
-#include <stdlib.h>
-#include <stdio.h>
-#include <libelf.h>
-#include <gelf.h>
-
-using namespace llvm;
-
-/**
- * Set the shader type we want to compile
- *
- * @param type shader type to set
- */
-extern "C" void
-radeon_llvm_shader_type(LLVMValueRef F, unsigned type)
-{
-  Function *Func = unwrap<Function>(F);
-  int Idx = AttributeSet::FunctionIndex;
-  AttrBuilder B;
-  char Str[2];
-
-  sprintf(Str, "%1d", type);
-  B.addAttribute("ShaderType", Str);
-
-  AttributeSet Set = AttributeSet::get(Func->getContext(), Idx, B);
-  Func->addAttributes(Idx, Set);
-}
-
-/**
- * Compile an LLVM module to machine code.
- *
- * @param bytes This function allocates memory for the byte stream, it is the
- * caller's responsibility to free it.
- */
-extern "C" unsigned
-radeon_llvm_compile(LLVMModuleRef M, struct radeon_llvm_binary *binary,
-                 const char * gpu_family, unsigned dump) {
-
-   Triple AMDGPUTriple(sys::getDefaultTargetTriple());
-
-   LLVMInitializeR600TargetInfo();
-   LLVMInitializeR600Target();
-   LLVMInitializeR600TargetMC();
-   LLVMInitializeR600AsmPrinter();
-
-   std::string err;
-   const Target * AMDGPUTarget = TargetRegistry::lookupTarget("r600", err);
-   if(!AMDGPUTarget) {
-      fprintf(stderr, "Can't find target: %s\n", err.c_str());
-      return 1;
-   }
-   
-   Triple::ArchType Arch = Triple::getArchTypeForLLVMName("r600");
-   if (Arch == Triple::UnknownArch) {
-      fprintf(stderr, "Unknown Arch\n");
-   }
-   AMDGPUTriple.setArch(Arch);
-
-   Module * mod = unwrap(M);
-   std::string FS;
-   TargetOptions TO;
-
-   if (dump) {
-      mod->dump();
-      FS += "+DumpCode";
-   }
-
-   std::auto_ptr<TargetMachine> tm(AMDGPUTarget->createTargetMachine(
-                     AMDGPUTriple.getTriple(), gpu_family, FS,
-                     TO, Reloc::Default, CodeModel::Default,
-                     CodeGenOpt::Default
-                     ));
-   TargetMachine &AMDGPUTargetMachine = *tm.get();
-   PassManager PM;
-   PM.add(new DataLayout(*AMDGPUTargetMachine.getDataLayout()));
-   PM.add(createPromoteMemoryToRegisterPass());
-   AMDGPUTargetMachine.setAsmVerbosityDefault(true);
-
-   std::string CodeString;
-   raw_string_ostream oStream(CodeString);
-   formatted_raw_ostream out(oStream);
-
-   /* Optional extra paramater true / false to disable verify */
-   if (AMDGPUTargetMachine.addPassesToEmitFile(PM, out, TargetMachine::CGFT_ObjectFile,
-                                               true)){
-      fprintf(stderr, "AddingPasses failed.\n");
-      return 1;
-   }
-   PM.run(*mod);
-
-   out.flush();
-   std::string &data = oStream.str();
-
-   char *elf_buffer;
-
-   /* One of the libelf implementations (http://www.mr511.de/software/english.htm)
-    * requires calling elf_version() before elf_memory().
-    */
-   elf_version(EV_CURRENT);
-   elf_buffer = (char*)malloc(data.length());
-   memcpy(elf_buffer, data.c_str(), data.length());
-
-   Elf *elf = elf_memory(elf_buffer, data.length());
-   Elf_Scn *section = NULL;
-   size_t section_str_index;
-
-   elf_getshdrstrndx(elf, &section_str_index);
-
-   while ((section = elf_nextscn(elf, section))) {
-      const char *name;
-      Elf_Data *section_data = NULL;
-      GElf_Shdr section_header;
-      if (gelf_getshdr(section, &section_header) != &section_header) {
-         fprintf(stderr, "Failed to read ELF section header\n");
-         return 1;
-      }
-      name = elf_strptr(elf, section_str_index, section_header.sh_name);
-      if (!strcmp(name, ".text")) {
-         section_data = elf_getdata(section, section_data);
-         binary->code_size = section_data->d_size;
-         binary->code = (unsigned char*)malloc(binary->code_size * sizeof(unsigned char));
-         memcpy(binary->code, section_data->d_buf, binary->code_size);
-      } else if (!strcmp(name, ".AMDGPU.config")) {
-         section_data = elf_getdata(section, section_data);
-         binary->config_size = section_data->d_size;
-         binary->config = (unsigned char*)malloc(binary->config_size * sizeof(unsigned char));
-         memcpy(binary->config, section_data->d_buf, binary->config_size);
-      }
-   }
-
-   return 0;
-}
index f78fc19faf7ce8e45036d9c0a4ad761bd122d0ba..72c24c6559306aedee11ce88f3bf9fdfdc35768c 100644 (file)
@@ -36,26 +36,12 @@ struct radeon_llvm_binary {
        unsigned config_size;
 };
 
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 void radeon_llvm_shader_type(LLVMValueRef F, unsigned type);
 
-unsigned radeon_llvm_bitcode_compile(
-   unsigned char * bitcode, unsigned bitcode_len,
-   unsigned char ** bytes, unsigned * byte_count,
-   const  char * gpu_family, unsigned dump);
-
 unsigned  radeon_llvm_compile(
        LLVMModuleRef M,
        struct radeon_llvm_binary *binary,
        const char * gpu_family,
        unsigned dump);
 
-#ifdef __cplusplus
-} /* Extern "C" */
-#endif
-
 #endif /* RADEON_LLVM_EMIT_H */