diff options
author | Tom Stellard <[email protected]> | 2013-04-02 10:42:50 -0700 |
---|---|---|
committer | Tom Stellard <[email protected]> | 2013-05-06 09:06:06 -0700 |
commit | 024fe6852a76f33d7e2afc5621340e387c381bb0 (patch) | |
tree | 7f51eaef023680967b689e743e00ba086f2b1152 /src/gallium | |
parent | 55eb8eaaa8bf8696d56effce6ed87f03bea779e0 (diff) |
radeon/llvm: Use LLVM C API for compiling LLVM IR to ISA v2
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: [email protected]
Diffstat (limited to 'src/gallium')
-rw-r--r-- | src/gallium/drivers/radeon/Makefile.am | 2 | ||||
-rw-r--r-- | src/gallium/drivers/radeon/Makefile.sources | 4 | ||||
-rw-r--r-- | src/gallium/drivers/radeon/radeon_llvm_emit.c | 172 | ||||
-rw-r--r-- | src/gallium/drivers/radeon/radeon_llvm_emit.cpp | 184 | ||||
-rw-r--r-- | src/gallium/drivers/radeon/radeon_llvm_emit.h | 14 |
5 files changed, 173 insertions, 203 deletions
diff --git a/src/gallium/drivers/radeon/Makefile.am b/src/gallium/drivers/radeon/Makefile.am index f1f8ced78dc..32ad32932b0 100644 --- a/src/gallium/drivers/radeon/Makefile.am +++ b/src/gallium/drivers/radeon/Makefile.am @@ -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 = \ diff --git a/src/gallium/drivers/radeon/Makefile.sources b/src/gallium/drivers/radeon/Makefile.sources index a23d5c4ad2c..d33c81b0fc0 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 00000000000..1a4d4fdd22b --- /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 <[email protected]> + * + */ +#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 10127151b10..00000000000 --- 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 <[email protected]> - * - */ -#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, §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 f78fc19faf7..72c24c65593 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 */ |