1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2018 Red Hat.
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21bf215546Sopenharmony_ci * IN THE SOFTWARE.
22bf215546Sopenharmony_ci */
23bf215546Sopenharmony_ci#include "radv_llvm_helper.h"
24bf215546Sopenharmony_ci#include "ac_llvm_util.h"
25bf215546Sopenharmony_ci
26bf215546Sopenharmony_ci#include <list>
27bf215546Sopenharmony_ciclass radv_llvm_per_thread_info {
28bf215546Sopenharmony_ci public:
29bf215546Sopenharmony_ci   radv_llvm_per_thread_info(enum radeon_family arg_family,
30bf215546Sopenharmony_ci                             enum ac_target_machine_options arg_tm_options, unsigned arg_wave_size)
31bf215546Sopenharmony_ci       : family(arg_family), tm_options(arg_tm_options), wave_size(arg_wave_size), passes(NULL)
32bf215546Sopenharmony_ci   {
33bf215546Sopenharmony_ci   }
34bf215546Sopenharmony_ci
35bf215546Sopenharmony_ci   ~radv_llvm_per_thread_info()
36bf215546Sopenharmony_ci   {
37bf215546Sopenharmony_ci      ac_destroy_llvm_compiler(&llvm_info);
38bf215546Sopenharmony_ci   }
39bf215546Sopenharmony_ci
40bf215546Sopenharmony_ci   bool init(void)
41bf215546Sopenharmony_ci   {
42bf215546Sopenharmony_ci      if (!ac_init_llvm_compiler(&llvm_info, family, tm_options))
43bf215546Sopenharmony_ci         return false;
44bf215546Sopenharmony_ci
45bf215546Sopenharmony_ci      passes = ac_create_llvm_passes(llvm_info.tm);
46bf215546Sopenharmony_ci      if (!passes)
47bf215546Sopenharmony_ci         return false;
48bf215546Sopenharmony_ci
49bf215546Sopenharmony_ci      return true;
50bf215546Sopenharmony_ci   }
51bf215546Sopenharmony_ci
52bf215546Sopenharmony_ci   bool compile_to_memory_buffer(LLVMModuleRef module, char **pelf_buffer, size_t *pelf_size)
53bf215546Sopenharmony_ci   {
54bf215546Sopenharmony_ci      return ac_compile_module_to_elf(passes, module, pelf_buffer, pelf_size);
55bf215546Sopenharmony_ci   }
56bf215546Sopenharmony_ci
57bf215546Sopenharmony_ci   bool is_same(enum radeon_family arg_family, enum ac_target_machine_options arg_tm_options,
58bf215546Sopenharmony_ci                unsigned arg_wave_size)
59bf215546Sopenharmony_ci   {
60bf215546Sopenharmony_ci      if (arg_family == family && arg_tm_options == tm_options && arg_wave_size == wave_size)
61bf215546Sopenharmony_ci         return true;
62bf215546Sopenharmony_ci      return false;
63bf215546Sopenharmony_ci   }
64bf215546Sopenharmony_ci   struct ac_llvm_compiler llvm_info;
65bf215546Sopenharmony_ci
66bf215546Sopenharmony_ci private:
67bf215546Sopenharmony_ci   enum radeon_family family;
68bf215546Sopenharmony_ci   enum ac_target_machine_options tm_options;
69bf215546Sopenharmony_ci   unsigned wave_size;
70bf215546Sopenharmony_ci   struct ac_compiler_passes *passes;
71bf215546Sopenharmony_ci};
72bf215546Sopenharmony_ci
73bf215546Sopenharmony_ci/* we have to store a linked list per thread due to the possiblity of multiple gpus being required */
74bf215546Sopenharmony_cistatic thread_local std::list<radv_llvm_per_thread_info> radv_llvm_per_thread_list;
75bf215546Sopenharmony_ci
76bf215546Sopenharmony_cibool
77bf215546Sopenharmony_ciradv_compile_to_elf(struct ac_llvm_compiler *info, LLVMModuleRef module, char **pelf_buffer,
78bf215546Sopenharmony_ci                    size_t *pelf_size)
79bf215546Sopenharmony_ci{
80bf215546Sopenharmony_ci   radv_llvm_per_thread_info *thread_info = nullptr;
81bf215546Sopenharmony_ci
82bf215546Sopenharmony_ci   for (auto &I : radv_llvm_per_thread_list) {
83bf215546Sopenharmony_ci      if (I.llvm_info.tm == info->tm) {
84bf215546Sopenharmony_ci         thread_info = &I;
85bf215546Sopenharmony_ci         break;
86bf215546Sopenharmony_ci      }
87bf215546Sopenharmony_ci   }
88bf215546Sopenharmony_ci
89bf215546Sopenharmony_ci   if (!thread_info) {
90bf215546Sopenharmony_ci      struct ac_compiler_passes *passes = ac_create_llvm_passes(info->tm);
91bf215546Sopenharmony_ci      bool ret = ac_compile_module_to_elf(passes, module, pelf_buffer, pelf_size);
92bf215546Sopenharmony_ci      ac_destroy_llvm_passes(passes);
93bf215546Sopenharmony_ci      return ret;
94bf215546Sopenharmony_ci   }
95bf215546Sopenharmony_ci
96bf215546Sopenharmony_ci   return thread_info->compile_to_memory_buffer(module, pelf_buffer, pelf_size);
97bf215546Sopenharmony_ci}
98bf215546Sopenharmony_ci
99bf215546Sopenharmony_cibool
100bf215546Sopenharmony_ciradv_init_llvm_compiler(struct ac_llvm_compiler *info, enum radeon_family family,
101bf215546Sopenharmony_ci                        enum ac_target_machine_options tm_options, unsigned wave_size)
102bf215546Sopenharmony_ci{
103bf215546Sopenharmony_ci   for (auto &I : radv_llvm_per_thread_list) {
104bf215546Sopenharmony_ci      if (I.is_same(family, tm_options, wave_size)) {
105bf215546Sopenharmony_ci         *info = I.llvm_info;
106bf215546Sopenharmony_ci         return true;
107bf215546Sopenharmony_ci      }
108bf215546Sopenharmony_ci   }
109bf215546Sopenharmony_ci
110bf215546Sopenharmony_ci   radv_llvm_per_thread_list.emplace_back(family, tm_options, wave_size);
111bf215546Sopenharmony_ci   radv_llvm_per_thread_info &tinfo = radv_llvm_per_thread_list.back();
112bf215546Sopenharmony_ci
113bf215546Sopenharmony_ci   if (!tinfo.init()) {
114bf215546Sopenharmony_ci      radv_llvm_per_thread_list.pop_back();
115bf215546Sopenharmony_ci      return false;
116bf215546Sopenharmony_ci   }
117bf215546Sopenharmony_ci
118bf215546Sopenharmony_ci   *info = tinfo.llvm_info;
119bf215546Sopenharmony_ci   return true;
120bf215546Sopenharmony_ci}
121