[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, &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);
> +		}
> +	}
> +
> +	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, &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 */



More information about the mesa-dev mailing list