1 /*
2 * Copyright © 2018 Red Hat.
3 *
4 * SPDX-License-Identifier: MIT
5 */
6 #include "radv_llvm_helper.h"
7 #include "ac_llvm_util.h"
8
9 #include <list>
10 class radv_llvm_per_thread_info {
11 public:
radv_llvm_per_thread_info(enum radeon_family arg_family,enum ac_target_machine_options arg_tm_options,unsigned arg_wave_size)12 radv_llvm_per_thread_info(enum radeon_family arg_family, enum ac_target_machine_options arg_tm_options,
13 unsigned arg_wave_size)
14 : family(arg_family), tm_options(arg_tm_options), wave_size(arg_wave_size), passes(NULL)
15 {
16 }
17
~radv_llvm_per_thread_info()18 ~radv_llvm_per_thread_info()
19 {
20 ac_destroy_llvm_compiler(&llvm_info);
21 }
22
init(void)23 bool init(void)
24 {
25 if (!ac_init_llvm_compiler(&llvm_info, family, tm_options))
26 return false;
27
28 passes = ac_create_llvm_passes(llvm_info.tm);
29 if (!passes)
30 return false;
31
32 return true;
33 }
34
compile_to_memory_buffer(LLVMModuleRef module,char ** pelf_buffer,size_t * pelf_size)35 bool compile_to_memory_buffer(LLVMModuleRef module, char **pelf_buffer, size_t *pelf_size)
36 {
37 return ac_compile_module_to_elf(passes, module, pelf_buffer, pelf_size);
38 }
39
is_same(enum radeon_family arg_family,enum ac_target_machine_options arg_tm_options,unsigned arg_wave_size)40 bool is_same(enum radeon_family arg_family, enum ac_target_machine_options arg_tm_options, unsigned arg_wave_size)
41 {
42 if (arg_family == family && arg_tm_options == tm_options && arg_wave_size == wave_size)
43 return true;
44 return false;
45 }
46 struct ac_llvm_compiler llvm_info;
47
48 private:
49 enum radeon_family family;
50 enum ac_target_machine_options tm_options;
51 unsigned wave_size;
52 struct ac_compiler_passes *passes;
53 };
54
55 /* we have to store a linked list per thread due to the possibility of multiple gpus being required */
56 static thread_local std::list<radv_llvm_per_thread_info> radv_llvm_per_thread_list;
57
58 bool
radv_compile_to_elf(struct ac_llvm_compiler * info,LLVMModuleRef module,char ** pelf_buffer,size_t * pelf_size)59 radv_compile_to_elf(struct ac_llvm_compiler *info, LLVMModuleRef module, char **pelf_buffer, size_t *pelf_size)
60 {
61 radv_llvm_per_thread_info *thread_info = nullptr;
62
63 for (auto &I : radv_llvm_per_thread_list) {
64 if (I.llvm_info.tm == info->tm) {
65 thread_info = &I;
66 break;
67 }
68 }
69
70 if (!thread_info) {
71 struct ac_compiler_passes *passes = ac_create_llvm_passes(info->tm);
72 bool ret = ac_compile_module_to_elf(passes, module, pelf_buffer, pelf_size);
73 ac_destroy_llvm_passes(passes);
74 return ret;
75 }
76
77 return thread_info->compile_to_memory_buffer(module, pelf_buffer, pelf_size);
78 }
79
80 bool
radv_init_llvm_compiler(struct ac_llvm_compiler * info,enum radeon_family family,enum ac_target_machine_options tm_options,unsigned wave_size)81 radv_init_llvm_compiler(struct ac_llvm_compiler *info, enum radeon_family family,
82 enum ac_target_machine_options tm_options, unsigned wave_size)
83 {
84 for (auto &I : radv_llvm_per_thread_list) {
85 if (I.is_same(family, tm_options, wave_size)) {
86 *info = I.llvm_info;
87 return true;
88 }
89 }
90
91 radv_llvm_per_thread_list.emplace_back(family, tm_options, wave_size);
92 radv_llvm_per_thread_info &tinfo = radv_llvm_per_thread_list.back();
93
94 if (!tinfo.init()) {
95 radv_llvm_per_thread_list.pop_back();
96 return false;
97 }
98
99 *info = tinfo.llvm_info;
100 return true;
101 }
102