Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright 2011 Advanced Micro Devices, Inc.
  3.  *
  4.  * Permission is hereby granted, free of charge, to any person obtaining a
  5.  * copy of this software and associated documentation files (the "Software"),
  6.  * to deal in the Software without restriction, including without limitation
  7.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8.  * and/or sell copies of the Software, and to permit persons to whom the
  9.  * Software is furnished to do so, subject to the following conditions:
  10.  *
  11.  * The above copyright notice and this permission notice (including the next
  12.  * paragraph) shall be included in all copies or substantial portions of the
  13.  * Software.
  14.  *
  15.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  18.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20.  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  21.  * SOFTWARE.
  22.  *
  23.  * Authors: Tom Stellard <thomas.stellard@amd.com>
  24.  *
  25.  */
  26. #include "radeon_llvm_emit.h"
  27. #include "util/u_memory.h"
  28.  
  29. #include <llvm-c/Target.h>
  30. #include <llvm-c/TargetMachine.h>
  31.  
  32. #include <stdlib.h>
  33. #include <stdio.h>
  34. #include <string.h>
  35. #include <libelf.h>
  36. #include <gelf.h>
  37.  
  38. #define CPU_STRING_LEN 30
  39. #define FS_STRING_LEN 30
  40. #define TRIPLE_STRING_LEN 7
  41.  
  42. /**
  43.  * Set the shader type we want to compile
  44.  *
  45.  * @param type shader type to set
  46.  */
  47. void radeon_llvm_shader_type(LLVMValueRef F, unsigned type)
  48. {
  49.   char Str[2];
  50.   sprintf(Str, "%1d", type);
  51.  
  52.   LLVMAddTargetDependentFunctionAttr(F, "ShaderType", Str);
  53. }
  54.  
  55. static void init_r600_target() {
  56.         static unsigned initialized = 0;
  57.         if (!initialized) {
  58.                 LLVMInitializeR600TargetInfo();
  59.                 LLVMInitializeR600Target();
  60.                 LLVMInitializeR600TargetMC();
  61.                 LLVMInitializeR600AsmPrinter();
  62.                 initialized = 1;
  63.         }
  64. }
  65.  
  66. static LLVMTargetRef get_r600_target() {
  67.         LLVMTargetRef target = NULL;
  68.  
  69.         for (target = LLVMGetFirstTarget(); target;
  70.                                         target = LLVMGetNextTarget(target)) {
  71.                 if (!strncmp(LLVMGetTargetName(target), "r600", 4)) {
  72.                         break;
  73.                 }
  74.         }
  75.  
  76.         if (!target) {
  77.                 fprintf(stderr, "Can't find target r600\n");
  78.                 return NULL;
  79.         }
  80.         return target;
  81. }
  82.  
  83. /**
  84.  * Compile an LLVM module to machine code.
  85.  *
  86.  * @returns 0 for success, 1 for failure
  87.  */
  88. unsigned radeon_llvm_compile(LLVMModuleRef M, struct radeon_llvm_binary *binary,
  89.                                           const char * gpu_family, unsigned dump) {
  90.  
  91.         LLVMTargetRef target;
  92.         LLVMTargetMachineRef tm;
  93.         char cpu[CPU_STRING_LEN];
  94.         char fs[FS_STRING_LEN];
  95.         char *err;
  96.         LLVMMemoryBufferRef out_buffer;
  97.         unsigned buffer_size;
  98.         const char *buffer_data;
  99.         char triple[TRIPLE_STRING_LEN];
  100.         char *elf_buffer;
  101.         Elf *elf;
  102.         Elf_Scn *section = NULL;
  103.         size_t section_str_index;
  104.         LLVMBool r;
  105.  
  106.         init_r600_target();
  107.  
  108.         target = get_r600_target();
  109.         if (!target) {
  110.                 return 1;
  111.         }
  112.  
  113.         strncpy(cpu, gpu_family, CPU_STRING_LEN);
  114.         memset(fs, 0, sizeof(fs));
  115.         if (dump) {
  116.                 LLVMDumpModule(M);
  117.                 strncpy(fs, "+DumpCode", FS_STRING_LEN);
  118.         }
  119.         strncpy(triple, "r600--", TRIPLE_STRING_LEN);
  120.         tm = LLVMCreateTargetMachine(target, triple, cpu, fs,
  121.                                   LLVMCodeGenLevelDefault, LLVMRelocDefault,
  122.                                                   LLVMCodeModelDefault);
  123.  
  124.         r = LLVMTargetMachineEmitToMemoryBuffer(tm, M, LLVMObjectFile, &err,
  125.                                                                  &out_buffer);
  126.         if (r) {
  127.                 fprintf(stderr, "%s", err);
  128.                 FREE(err);
  129.                 return 1;
  130.         }
  131.  
  132.         buffer_size = LLVMGetBufferSize(out_buffer);
  133.         buffer_data = LLVMGetBufferStart(out_buffer);
  134.  
  135.         /* One of the libelf implementations
  136.          * (http://www.mr511.de/software/english.htm) requires calling
  137.          * elf_version() before elf_memory().
  138.          */
  139.         elf_version(EV_CURRENT);
  140.         elf_buffer = MALLOC(buffer_size);
  141.         memcpy(elf_buffer, buffer_data, buffer_size);
  142.  
  143.         elf = elf_memory(elf_buffer, buffer_size);
  144.  
  145.         elf_getshdrstrndx(elf, &section_str_index);
  146.  
  147.         while ((section = elf_nextscn(elf, section))) {
  148.                 const char *name;
  149.                 Elf_Data *section_data = NULL;
  150.                 GElf_Shdr section_header;
  151.                 if (gelf_getshdr(section, &section_header) != &section_header) {
  152.                         fprintf(stderr, "Failed to read ELF section header\n");
  153.                         return 1;
  154.                 }
  155.                 name = elf_strptr(elf, section_str_index, section_header.sh_name);
  156.                 if (!strcmp(name, ".text")) {
  157.                         section_data = elf_getdata(section, section_data);
  158.                         binary->code_size = section_data->d_size;
  159.                         binary->code = MALLOC(binary->code_size * sizeof(unsigned char));
  160.                         memcpy(binary->code, section_data->d_buf, binary->code_size);
  161.                 } else if (!strcmp(name, ".AMDGPU.config")) {
  162.                         section_data = elf_getdata(section, section_data);
  163.                         binary->config_size = section_data->d_size;
  164.                         binary->config = MALLOC(binary->config_size * sizeof(unsigned char));
  165.                         memcpy(binary->config, section_data->d_buf, binary->config_size);
  166.                 }
  167.         }
  168.  
  169.         LLVMDisposeMemoryBuffer(out_buffer);
  170.         LLVMDisposeTargetMachine(tm);
  171.         return 0;
  172. }
  173.