[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, §ion_str_index);
+
+ while ((section = elf_nextscn(elf, section))) {
+ const char *name;
+ Elf_Data *section_data = NULL;
+ GElf_Shdr section_header;
+ if (gelf_getshdr(section, §ion_header) != §ion_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, §ion_str_index);
-
- while ((section = elf_nextscn(elf, section))) {
- const char *name;
- Elf_Data *section_data = NULL;
- GElf_Shdr section_header;
- if (gelf_getshdr(section, §ion_header) != §ion_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