Subversion Repositories Kolibri OS

Rev

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 "radeon_elf_util.h"
  28. #include "util/u_memory.h"
  29. #include "pipe/p_shader_tokens.h"
  30.  
  31. #include <llvm-c/Target.h>
  32. #include <llvm-c/TargetMachine.h>
  33. #include <llvm-c/Core.h>
  34.  
  35. #include <stdlib.h>
  36. #include <stdio.h>
  37. #include <string.h>
  38.  
  39. #define CPU_STRING_LEN 30
  40. #define FS_STRING_LEN 30
  41. #define TRIPLE_STRING_LEN 7
  42.  
  43. /**
  44.  * Shader types for the LLVM backend.
  45.  */
  46. enum radeon_llvm_shader_type {
  47.         RADEON_LLVM_SHADER_PS = 0,
  48.         RADEON_LLVM_SHADER_VS = 1,
  49.         RADEON_LLVM_SHADER_GS = 2,
  50.         RADEON_LLVM_SHADER_CS = 3,
  51. };
  52.  
  53. /**
  54.  * Set the shader type we want to compile
  55.  *
  56.  * @param type shader type to set
  57.  */
  58. void radeon_llvm_shader_type(LLVMValueRef F, unsigned type)
  59. {
  60.         char Str[2];
  61.         enum radeon_llvm_shader_type llvm_type;
  62.  
  63.         switch (type) {
  64.         case TGSI_PROCESSOR_VERTEX:
  65.                 llvm_type = RADEON_LLVM_SHADER_VS;
  66.                 break;
  67.         case TGSI_PROCESSOR_GEOMETRY:
  68.                 llvm_type = RADEON_LLVM_SHADER_GS;
  69.                 break;
  70.         case TGSI_PROCESSOR_FRAGMENT:
  71.                 llvm_type = RADEON_LLVM_SHADER_PS;
  72.                 break;
  73.         case TGSI_PROCESSOR_COMPUTE:
  74.                 llvm_type = RADEON_LLVM_SHADER_CS;
  75.                 break;
  76.         default:
  77.                 assert(0);
  78.         }
  79.  
  80.         sprintf(Str, "%1d", llvm_type);
  81.  
  82.         LLVMAddTargetDependentFunctionAttr(F, "ShaderType", Str);
  83. }
  84.  
  85. static void init_r600_target()
  86. {
  87.         static unsigned initialized = 0;
  88.         if (!initialized) {
  89.                 LLVMInitializeR600TargetInfo();
  90.                 LLVMInitializeR600Target();
  91.                 LLVMInitializeR600TargetMC();
  92.                 LLVMInitializeR600AsmPrinter();
  93.                 initialized = 1;
  94.         }
  95. }
  96.  
  97. LLVMTargetRef radeon_llvm_get_r600_target(const char *triple)
  98. {
  99.         LLVMTargetRef target = NULL;
  100.         char *err_message = NULL;
  101.  
  102.         init_r600_target();
  103.  
  104.         if (LLVMGetTargetFromTriple(triple, &target, &err_message)) {
  105.                 fprintf(stderr, "Cannot find target for triple %s ", triple);
  106.                 if (err_message) {
  107.                         fprintf(stderr, "%s\n", err_message);
  108.                 }
  109.                 LLVMDisposeMessage(err_message);
  110.                 return NULL;
  111.         }
  112.         return target;
  113. }
  114.  
  115. #if HAVE_LLVM >= 0x0305
  116.  
  117. static void radeonDiagnosticHandler(LLVMDiagnosticInfoRef di, void *context)
  118. {
  119.         if (LLVMGetDiagInfoSeverity(di) == LLVMDSError) {
  120.                 unsigned int *diagnosticflag = (unsigned int *)context;
  121.                 char *diaginfo_message = LLVMGetDiagInfoDescription(di);
  122.  
  123.                 *diagnosticflag = 1;
  124.                 fprintf(stderr,"LLVM triggered Diagnostic Handler: %s\n", diaginfo_message);
  125.                 LLVMDisposeMessage(diaginfo_message);
  126.         }
  127. }
  128.  
  129. #endif
  130.  
  131. /**
  132.  * Compile an LLVM module to machine code.
  133.  *
  134.  * @returns 0 for success, 1 for failure
  135.  */
  136. unsigned radeon_llvm_compile(LLVMModuleRef M, struct radeon_shader_binary *binary,
  137.                           const char *gpu_family, unsigned dump, LLVMTargetMachineRef tm)
  138. {
  139.  
  140.         char cpu[CPU_STRING_LEN];
  141.         char fs[FS_STRING_LEN];
  142.         char *err;
  143.         bool dispose_tm = false;
  144.         LLVMContextRef llvm_ctx;
  145.         unsigned rval = 0;
  146.         LLVMMemoryBufferRef out_buffer;
  147.         unsigned buffer_size;
  148.         const char *buffer_data;
  149.         char triple[TRIPLE_STRING_LEN];
  150.         LLVMBool mem_err;
  151.  
  152.         if (!tm) {
  153.                 strncpy(triple, "r600--", TRIPLE_STRING_LEN);
  154.                 LLVMTargetRef target = radeon_llvm_get_r600_target(triple);
  155.                 if (!target) {
  156.                         return 1;
  157.                 }
  158.                 strncpy(cpu, gpu_family, CPU_STRING_LEN);
  159.                 memset(fs, 0, sizeof(fs));
  160.                 if (dump) {
  161.                         strncpy(fs, "+DumpCode", FS_STRING_LEN);
  162.                 }
  163.                 tm = LLVMCreateTargetMachine(target, triple, cpu, fs,
  164.                                   LLVMCodeGenLevelDefault, LLVMRelocDefault,
  165.                                                   LLVMCodeModelDefault);
  166.                 dispose_tm = true;
  167.         }
  168.         if (dump) {
  169.                 LLVMDumpModule(M);
  170.         }
  171.         /* Setup Diagnostic Handler*/
  172.         llvm_ctx = LLVMGetModuleContext(M);
  173.  
  174. #if HAVE_LLVM >= 0x0305
  175.         LLVMContextSetDiagnosticHandler(llvm_ctx, radeonDiagnosticHandler, &rval);
  176. #endif
  177.         rval = 0;
  178.  
  179.         /* Compile IR*/
  180.         mem_err = LLVMTargetMachineEmitToMemoryBuffer(tm, M, LLVMObjectFile, &err,
  181.                                                                  &out_buffer);
  182.  
  183.         /* Process Errors/Warnings */
  184.         if (mem_err) {
  185.                 fprintf(stderr, "%s: %s", __FUNCTION__, err);
  186.                 FREE(err);
  187.                 LLVMDisposeTargetMachine(tm);
  188.                 return 1;
  189.         }
  190.  
  191.         if (0 != rval) {
  192.                 fprintf(stderr, "%s: Processing Diag Flag\n", __FUNCTION__);
  193.         }
  194.  
  195.         /* Extract Shader Code*/
  196.         buffer_size = LLVMGetBufferSize(out_buffer);
  197.         buffer_data = LLVMGetBufferStart(out_buffer);
  198.  
  199.         radeon_elf_read(buffer_data, buffer_size, binary, dump);
  200.  
  201.         /* Clean up */
  202.         LLVMDisposeMemoryBuffer(out_buffer);
  203.  
  204.         if (dispose_tm) {
  205.                 LLVMDisposeTargetMachine(tm);
  206.         }
  207.         return rval;
  208. }
  209.