1/* 2 * Copyright © 2018 Red Hat. 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 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23#include "radv_llvm_helper.h" 24#include "ac_llvm_util.h" 25 26#include <list> 27class radv_llvm_per_thread_info { 28 public: 29 radv_llvm_per_thread_info(enum radeon_family arg_family, 30 enum ac_target_machine_options arg_tm_options, unsigned arg_wave_size) 31 : family(arg_family), tm_options(arg_tm_options), wave_size(arg_wave_size), passes(NULL) 32 { 33 } 34 35 ~radv_llvm_per_thread_info() 36 { 37 ac_destroy_llvm_compiler(&llvm_info); 38 } 39 40 bool init(void) 41 { 42 if (!ac_init_llvm_compiler(&llvm_info, family, tm_options)) 43 return false; 44 45 passes = ac_create_llvm_passes(llvm_info.tm); 46 if (!passes) 47 return false; 48 49 return true; 50 } 51 52 bool compile_to_memory_buffer(LLVMModuleRef module, char **pelf_buffer, size_t *pelf_size) 53 { 54 return ac_compile_module_to_elf(passes, module, pelf_buffer, pelf_size); 55 } 56 57 bool is_same(enum radeon_family arg_family, enum ac_target_machine_options arg_tm_options, 58 unsigned arg_wave_size) 59 { 60 if (arg_family == family && arg_tm_options == tm_options && arg_wave_size == wave_size) 61 return true; 62 return false; 63 } 64 struct ac_llvm_compiler llvm_info; 65 66 private: 67 enum radeon_family family; 68 enum ac_target_machine_options tm_options; 69 unsigned wave_size; 70 struct ac_compiler_passes *passes; 71}; 72 73/* we have to store a linked list per thread due to the possiblity of multiple gpus being required */ 74static thread_local std::list<radv_llvm_per_thread_info> radv_llvm_per_thread_list; 75 76bool 77radv_compile_to_elf(struct ac_llvm_compiler *info, LLVMModuleRef module, char **pelf_buffer, 78 size_t *pelf_size) 79{ 80 radv_llvm_per_thread_info *thread_info = nullptr; 81 82 for (auto &I : radv_llvm_per_thread_list) { 83 if (I.llvm_info.tm == info->tm) { 84 thread_info = &I; 85 break; 86 } 87 } 88 89 if (!thread_info) { 90 struct ac_compiler_passes *passes = ac_create_llvm_passes(info->tm); 91 bool ret = ac_compile_module_to_elf(passes, module, pelf_buffer, pelf_size); 92 ac_destroy_llvm_passes(passes); 93 return ret; 94 } 95 96 return thread_info->compile_to_memory_buffer(module, pelf_buffer, pelf_size); 97} 98 99bool 100radv_init_llvm_compiler(struct ac_llvm_compiler *info, enum radeon_family family, 101 enum ac_target_machine_options tm_options, unsigned wave_size) 102{ 103 for (auto &I : radv_llvm_per_thread_list) { 104 if (I.is_same(family, tm_options, wave_size)) { 105 *info = I.llvm_info; 106 return true; 107 } 108 } 109 110 radv_llvm_per_thread_list.emplace_back(family, tm_options, wave_size); 111 radv_llvm_per_thread_info &tinfo = radv_llvm_per_thread_list.back(); 112 113 if (!tinfo.init()) { 114 radv_llvm_per_thread_list.pop_back(); 115 return false; 116 } 117 118 *info = tinfo.llvm_info; 119 return true; 120} 121