101e04c3fSmrg/*
201e04c3fSmrg * Copyright © 2018 Red Hat.
301e04c3fSmrg *
401e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a
501e04c3fSmrg * copy of this software and associated documentation files (the "Software"),
601e04c3fSmrg * to deal in the Software without restriction, including without limitation
701e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
801e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the
901e04c3fSmrg * Software is furnished to do so, subject to the following conditions:
1001e04c3fSmrg *
1101e04c3fSmrg * The above copyright notice and this permission notice (including the next
1201e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the
1301e04c3fSmrg * Software.
1401e04c3fSmrg *
1501e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1601e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1701e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1801e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1901e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2001e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
2101e04c3fSmrg * IN THE SOFTWARE.
2201e04c3fSmrg */
237ec681f3Smrg#include "radv_llvm_helper.h"
2401e04c3fSmrg#include "ac_llvm_util.h"
2501e04c3fSmrg
2601e04c3fSmrg#include <list>
2701e04c3fSmrgclass radv_llvm_per_thread_info {
287ec681f3Smrg public:
297ec681f3Smrg   radv_llvm_per_thread_info(enum radeon_family arg_family,
307ec681f3Smrg                             enum ac_target_machine_options arg_tm_options, unsigned arg_wave_size)
317ec681f3Smrg       : family(arg_family), tm_options(arg_tm_options), wave_size(arg_wave_size), passes(NULL)
327ec681f3Smrg   {
337ec681f3Smrg   }
347ec681f3Smrg
357ec681f3Smrg   ~radv_llvm_per_thread_info()
367ec681f3Smrg   {
377ec681f3Smrg      ac_destroy_llvm_compiler(&llvm_info);
387ec681f3Smrg   }
397ec681f3Smrg
407ec681f3Smrg   bool init(void)
417ec681f3Smrg   {
427ec681f3Smrg      if (!ac_init_llvm_compiler(&llvm_info, family, tm_options))
437ec681f3Smrg         return false;
447ec681f3Smrg
457ec681f3Smrg      passes = ac_create_llvm_passes(llvm_info.tm);
467ec681f3Smrg      if (!passes)
477ec681f3Smrg         return false;
487ec681f3Smrg
497ec681f3Smrg      return true;
507ec681f3Smrg   }
517ec681f3Smrg
527ec681f3Smrg   bool compile_to_memory_buffer(LLVMModuleRef module, char **pelf_buffer, size_t *pelf_size)
537ec681f3Smrg   {
547ec681f3Smrg      return ac_compile_module_to_elf(passes, module, pelf_buffer, pelf_size);
557ec681f3Smrg   }
567ec681f3Smrg
577ec681f3Smrg   bool is_same(enum radeon_family arg_family, enum ac_target_machine_options arg_tm_options,
587ec681f3Smrg                unsigned arg_wave_size)
597ec681f3Smrg   {
607ec681f3Smrg      if (arg_family == family && arg_tm_options == tm_options && arg_wave_size == wave_size)
617ec681f3Smrg         return true;
627ec681f3Smrg      return false;
637ec681f3Smrg   }
647ec681f3Smrg   struct ac_llvm_compiler llvm_info;
657ec681f3Smrg
667ec681f3Smrg private:
677ec681f3Smrg   enum radeon_family family;
687ec681f3Smrg   enum ac_target_machine_options tm_options;
697ec681f3Smrg   unsigned wave_size;
707ec681f3Smrg   struct ac_compiler_passes *passes;
7101e04c3fSmrg};
7201e04c3fSmrg
7301e04c3fSmrg/* we have to store a linked list per thread due to the possiblity of multiple gpus being required */
7401e04c3fSmrgstatic thread_local std::list<radv_llvm_per_thread_info> radv_llvm_per_thread_list;
7501e04c3fSmrg
767ec681f3Smrgbool
777ec681f3Smrgradv_compile_to_elf(struct ac_llvm_compiler *info, LLVMModuleRef module, char **pelf_buffer,
787ec681f3Smrg                    size_t *pelf_size)
7901e04c3fSmrg{
807ec681f3Smrg   radv_llvm_per_thread_info *thread_info = nullptr;
817ec681f3Smrg
827ec681f3Smrg   for (auto &I : radv_llvm_per_thread_list) {
837ec681f3Smrg      if (I.llvm_info.tm == info->tm) {
847ec681f3Smrg         thread_info = &I;
857ec681f3Smrg         break;
867ec681f3Smrg      }
877ec681f3Smrg   }
887ec681f3Smrg
897ec681f3Smrg   if (!thread_info) {
907ec681f3Smrg      struct ac_compiler_passes *passes = ac_create_llvm_passes(info->tm);
917ec681f3Smrg      bool ret = ac_compile_module_to_elf(passes, module, pelf_buffer, pelf_size);
927ec681f3Smrg      ac_destroy_llvm_passes(passes);
937ec681f3Smrg      return ret;
947ec681f3Smrg   }
957ec681f3Smrg
967ec681f3Smrg   return thread_info->compile_to_memory_buffer(module, pelf_buffer, pelf_size);
9701e04c3fSmrg}
9801e04c3fSmrg
997ec681f3Smrgbool
1007ec681f3Smrgradv_init_llvm_compiler(struct ac_llvm_compiler *info, enum radeon_family family,
1017ec681f3Smrg                        enum ac_target_machine_options tm_options, unsigned wave_size)
10201e04c3fSmrg{
1037ec681f3Smrg   for (auto &I : radv_llvm_per_thread_list) {
1047ec681f3Smrg      if (I.is_same(family, tm_options, wave_size)) {
1057ec681f3Smrg         *info = I.llvm_info;
1067ec681f3Smrg         return true;
1077ec681f3Smrg      }
1087ec681f3Smrg   }
1097ec681f3Smrg
1107ec681f3Smrg   radv_llvm_per_thread_list.emplace_back(family, tm_options, wave_size);
1117ec681f3Smrg   radv_llvm_per_thread_info &tinfo = radv_llvm_per_thread_list.back();
1127ec681f3Smrg
1137ec681f3Smrg   if (!tinfo.init()) {
1147ec681f3Smrg      radv_llvm_per_thread_list.pop_back();
1157ec681f3Smrg      return false;
1167ec681f3Smrg   }
1177ec681f3Smrg
1187ec681f3Smrg   *info = tinfo.llvm_info;
1197ec681f3Smrg   return true;
12001e04c3fSmrg}
121