[Mesa-dev] [PATCH] radeon/llvm: Use LLVM C API for compiling LLVM IR to ISA.
Christian König
deathsimple at vodafone.de
Wed Apr 17 00:47:30 PDT 2013
Am 17.04.2013 01:13, schrieb Tom Stellard:
> 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.
Looks good on first glance, but I would separate the initialization and
finding the correct target machine into their own functions.
Also I would guess that we need to destroy the target machine after use,
cause in the C++ version that was an autoptr.
Christian.
> ---
> src/gallium/drivers/radeon/Makefile.am | 2 -
> src/gallium/drivers/radeon/Makefile.sources | 4 +-
> src/gallium/drivers/radeon/radeon_llvm_emit.c | 150 ++++++++++++++++++
> src/gallium/drivers/radeon/radeon_llvm_emit.cpp | 193 ------------------------
> src/gallium/drivers/radeon/radeon_llvm_emit.h | 14 --
> 5 files changed, 151 insertions(+), 212 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..d25b962
> --- /dev/null
> +++ b/src/gallium/drivers/radeon/radeon_llvm_emit.c
> @@ -0,0 +1,150 @@
> +/*
> + * 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 <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);
> +}
> +
> +/**
> + * 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.
> + */
> +unsigned radeon_llvm_compile(LLVMModuleRef M, struct radeon_llvm_binary *binary,
> + const char * gpu_family, unsigned dump) {
> +
> + static unsigned initialized = 0;
> + 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;
> + int r;
> +
> + if (!initialized) {
> + LLVMInitializeR600TargetInfo();
> + LLVMInitializeR600Target();
> + LLVMInitializeR600TargetMC();
> + LLVMInitializeR600AsmPrinter();
> + if (!LLVMIsMultithreaded()) {
> + LLVMStartMultithreaded();
> + }
> + initialized = 1;
> + }
> +
> + 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 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);
> +
> + buffer_size = LLVMGetBufferSize(out_buffer);
> + buffer_data = LLVMGetBufferStart(out_buffer);
> +
> + elf_buffer = (char*)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 = (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);
> + }
> + }
> +
> + LLVMDisposeMemoryBuffer(out_buffer);
> + 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 d2dc035..0000000
> --- a/src/gallium/drivers/radeon/radeon_llvm_emit.cpp
> +++ /dev/null
> @@ -1,193 +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-c/Target.h>
> -
> -#include <iostream>
> -#include <stdlib.h>
> -#include <stdio.h>
> -#include <libelf.h>
> -#include <gelf.h>
> -
> -using namespace llvm;
> -
> -namespace {
> -
> -class LLVMEnsureMultithreaded {
> -public:
> - LLVMEnsureMultithreaded()
> - {
> - llvm_start_multithreaded();
> - }
> -};
> -
> -static LLVMEnsureMultithreaded lLVMEnsureMultithreaded;
> -
> -}
> -
> -/**
> - * 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;
> -
> - 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 */
More information about the mesa-dev
mailing list