[Mesa-dev] [PATCH 2/3] radeon/llvm: Use LLVM C API for compiling LLVM IR to ISA v2

Tom Stellard tom at stellard.net
Thu May 2 08:01:19 PDT 2013


From: Tom Stellard <thomas.stellard at amd.com>

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
---
 src/gallium/drivers/radeon/Makefile.am          |   2 -
 src/gallium/drivers/radeon/Makefile.sources     |   4 +-
 src/gallium/drivers/radeon/radeon_llvm_emit.c   | 172 ++++++++++++++++++++++
 src/gallium/drivers/radeon/radeon_llvm_emit.cpp | 184 ------------------------
 src/gallium/drivers/radeon/radeon_llvm_emit.h   |  14 --
 5 files changed, 173 insertions(+), 203 deletions(-)
 create mode 100644 src/gallium/drivers/radeon/radeon_llvm_emit.c
 delete mode 100644 src/gallium/drivers/radeon/radeon_llvm_emit.cpp

diff --git a/src/gallium/drivers/radeon/Makefile.am b/src/gallium/drivers/radeon/Makefile.am
index 6522598..9b4255e 100644
--- a/src/gallium/drivers/radeon/Makefile.am
+++ b/src/gallium/drivers/radeon/Makefile.am
@@ -27,7 +27,6 @@ endif
 
 libllvmradeon at VERSION@_la_CXXFLAGS = \
 	$(GALLIUM_CFLAGS) \
-	$(filter-out -DDEBUG, $(LLVM_CXXFLAGS)) \
 	$(DEFINES)
 
 libllvmradeon at VERSION@_la_CFLAGS = \
@@ -35,7 +34,6 @@ libllvmradeon at VERSION@_la_CFLAGS = \
 	$(LLVM_CFLAGS)
 
 libllvmradeon at VERSION@_la_SOURCES = \
-	$(LLVM_CPP_FILES) \
 	$(LLVM_C_FILES)
 
 libllvmradeon at VERSION@_la_LIBADD = \
diff --git a/src/gallium/drivers/radeon/Makefile.sources b/src/gallium/drivers/radeon/Makefile.sources
index a23d5c4..d33c81b 100644
--- a/src/gallium/drivers/radeon/Makefile.sources
+++ b/src/gallium/drivers/radeon/Makefile.sources
@@ -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
index 0000000..1a4d4fd
--- /dev/null
+++ b/src/gallium/drivers/radeon/radeon_llvm_emit.c
@@ -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 at 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
index 03eb5f2..0000000
--- a/src/gallium/drivers/radeon/radeon_llvm_emit.cpp
+++ /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 at 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/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/Wrap.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;
-}
diff --git a/src/gallium/drivers/radeon/radeon_llvm_emit.h b/src/gallium/drivers/radeon/radeon_llvm_emit.h
index f78fc19..72c24c6 100644
--- a/src/gallium/drivers/radeon/radeon_llvm_emit.h
+++ b/src/gallium/drivers/radeon/radeon_llvm_emit.h
@@ -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 */
-- 
1.7.11.4



More information about the mesa-dev mailing list