1 // Copyright 2020, 2021 Francesco Biscani (bluescarni@gmail.com), Dario Izzo (dario.izzo@gmail.com)
2 //
3 // This file is part of the heyoka library.
4 //
5 // This Source Code Form is subject to the terms of the Mozilla
6 // Public License v. 2.0. If a copy of the MPL was not distributed
7 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
9 #ifndef HEYOKA_DETAIL_LLVM_HELPERS_HPP
10 #define HEYOKA_DETAIL_LLVM_HELPERS_HPP
11 
12 #include <heyoka/config.hpp>
13 
14 #include <cstddef>
15 #include <cstdint>
16 #include <functional>
17 #include <initializer_list>
18 #include <string>
19 #include <type_traits>
20 #include <typeinfo>
21 #include <utility>
22 #include <vector>
23 
24 #include <heyoka/detail/fwd_decl.hpp>
25 #include <heyoka/detail/llvm_fwd.hpp>
26 #include <heyoka/detail/type_traits.hpp>
27 #include <heyoka/detail/visibility.hpp>
28 
29 namespace heyoka::detail
30 {
31 
32 HEYOKA_DLL_PUBLIC llvm::Type *to_llvm_type_impl(llvm::LLVMContext &, const std::type_info &);
33 
34 // Helper to associate a C++ type to an LLVM type.
35 template <typename T>
to_llvm_type(llvm::LLVMContext & c)36 inline llvm::Type *to_llvm_type(llvm::LLVMContext &c)
37 {
38     return to_llvm_type_impl(c, typeid(T));
39 }
40 
41 HEYOKA_DLL_PUBLIC llvm::Type *make_vector_type(llvm::Type *, std::uint32_t);
42 
43 // Helper to construct an LLVM vector type of size batch_size with elements
44 // of the LLVM type tp corresponding to the C++ type T. If batch_size is 1, tp
45 // will be returned. batch_size cannot be zero.
46 template <typename T>
to_llvm_vector_type(llvm::LLVMContext & c,std::uint32_t batch_size)47 inline llvm::Type *to_llvm_vector_type(llvm::LLVMContext &c, std::uint32_t batch_size)
48 {
49     return make_vector_type(to_llvm_type<T>(c), batch_size);
50 }
51 
52 HEYOKA_DLL_PUBLIC std::string llvm_mangle_type(llvm::Type *);
53 
54 HEYOKA_DLL_PUBLIC llvm::Value *load_vector_from_memory(ir_builder &, llvm::Value *, std::uint32_t);
55 HEYOKA_DLL_PUBLIC void store_vector_to_memory(ir_builder &, llvm::Value *, llvm::Value *);
56 llvm::Value *gather_vector_from_memory(ir_builder &, llvm::Type *, llvm::Value *, std::size_t);
57 
58 HEYOKA_DLL_PUBLIC llvm::Value *vector_splat(ir_builder &, llvm::Value *, std::uint32_t);
59 
60 HEYOKA_DLL_PUBLIC std::vector<llvm::Value *> vector_to_scalars(ir_builder &, llvm::Value *);
61 
62 HEYOKA_DLL_PUBLIC llvm::Value *scalars_to_vector(ir_builder &, const std::vector<llvm::Value *> &);
63 
64 HEYOKA_DLL_PUBLIC llvm::Value *pairwise_reduce(std::vector<llvm::Value *> &,
65                                                const std::function<llvm::Value *(llvm::Value *, llvm::Value *)> &);
66 HEYOKA_DLL_PUBLIC llvm::Value *pairwise_sum(ir_builder &, std::vector<llvm::Value *> &);
67 
68 HEYOKA_DLL_PUBLIC llvm::Value *llvm_invoke_intrinsic(llvm_state &, const std::string &,
69                                                      const std::vector<llvm::Type *> &,
70                                                      const std::vector<llvm::Value *> &);
71 
72 HEYOKA_DLL_PUBLIC llvm::Value *llvm_invoke_external(llvm_state &, const std::string &, llvm::Type *,
73                                                     const std::vector<llvm::Value *> &,
74                                                     // NOTE: this is going to be converted into
75                                                     // a vector of llvm attributes (represented
76                                                     // as an enum) in the implementation.
77                                                     const std::vector<int> & = {});
78 
79 HEYOKA_DLL_PUBLIC llvm::Value *llvm_invoke_internal(llvm_state &, const std::string &,
80                                                     const std::vector<llvm::Value *> &);
81 
82 HEYOKA_DLL_PUBLIC void llvm_loop_u32(llvm_state &, llvm::Value *, llvm::Value *,
83                                      const std::function<void(llvm::Value *)> &,
84                                      const std::function<llvm::Value *(llvm::Value *)> & = {});
85 
86 HEYOKA_DLL_PUBLIC void llvm_while_loop(llvm_state &, const std::function<llvm::Value *()> &,
87                                        const std::function<void()> &);
88 
89 HEYOKA_DLL_PUBLIC void llvm_if_then_else(llvm_state &, llvm::Value *, const std::function<void()> &,
90                                          const std::function<void()> &);
91 
92 HEYOKA_DLL_PUBLIC llvm::Type *pointee_type(llvm::Value *);
93 
94 HEYOKA_DLL_PUBLIC std::string llvm_type_name(llvm::Type *);
95 
96 HEYOKA_DLL_PUBLIC bool compare_function_signature(llvm::Function *, llvm::Type *, const std::vector<llvm::Type *> &);
97 
98 HEYOKA_DLL_PUBLIC llvm::Value *make_global_zero_array(llvm::Module &, llvm::ArrayType *);
99 
100 HEYOKA_DLL_PUBLIC llvm::Value *call_extern_vec(llvm_state &, llvm::Value *, const std::string &);
101 HEYOKA_DLL_PUBLIC llvm::Value *call_extern_vec(llvm_state &, llvm::Value *, llvm::Value *, const std::string &);
102 
103 // Math helpers.
104 HEYOKA_DLL_PUBLIC std::pair<llvm::Value *, llvm::Value *> llvm_sincos(llvm_state &, llvm::Value *);
105 HEYOKA_DLL_PUBLIC llvm::Value *llvm_modulus(llvm_state &, llvm::Value *, llvm::Value *);
106 HEYOKA_DLL_PUBLIC llvm::Value *llvm_abs(llvm_state &, llvm::Value *);
107 HEYOKA_DLL_PUBLIC llvm::Value *llvm_min(llvm_state &, llvm::Value *, llvm::Value *);
108 HEYOKA_DLL_PUBLIC llvm::Value *llvm_max(llvm_state &, llvm::Value *, llvm::Value *);
109 HEYOKA_DLL_PUBLIC llvm::Value *llvm_sgn(llvm_state &, llvm::Value *);
110 HEYOKA_DLL_PUBLIC llvm::Value *llvm_atan2(llvm_state &, llvm::Value *, llvm::Value *);
111 
112 HEYOKA_DLL_PUBLIC llvm::Function *llvm_add_csc_dbl(llvm_state &, std::uint32_t, std::uint32_t);
113 HEYOKA_DLL_PUBLIC llvm::Function *llvm_add_csc_ldbl(llvm_state &, std::uint32_t, std::uint32_t);
114 
115 #if defined(HEYOKA_HAVE_REAL128)
116 
117 HEYOKA_DLL_PUBLIC llvm::Function *llvm_add_csc_f128(llvm_state &, std::uint32_t, std::uint32_t);
118 
119 #endif
120 
121 template <typename T>
llvm_add_csc(llvm_state & s,std::uint32_t n,std::uint32_t batch_size)122 inline llvm::Function *llvm_add_csc(llvm_state &s, std::uint32_t n, std::uint32_t batch_size)
123 {
124     if constexpr (std::is_same_v<T, double>) {
125         return llvm_add_csc_dbl(s, n, batch_size);
126     } else if constexpr (std::is_same_v<T, long double>) {
127         return llvm_add_csc_ldbl(s, n, batch_size);
128 #if defined(HEYOKA_HAVE_REAL128)
129     } else if constexpr (std::is_same_v<T, mppp::real128>) {
130         return llvm_add_csc_f128(s, n, batch_size);
131 #endif
132     } else {
133         static_assert(always_false_v<T>, "Unhandled type.");
134     }
135 }
136 
137 HEYOKA_DLL_PUBLIC llvm::Function *llvm_add_inv_kep_E_dbl(llvm_state &, std::uint32_t);
138 HEYOKA_DLL_PUBLIC llvm::Function *llvm_add_inv_kep_E_ldbl(llvm_state &, std::uint32_t);
139 
140 #if defined(HEYOKA_HAVE_REAL128)
141 
142 HEYOKA_DLL_PUBLIC llvm::Function *llvm_add_inv_kep_E_f128(llvm_state &, std::uint32_t);
143 
144 #endif
145 
146 template <typename T>
llvm_add_inv_kep_E(llvm_state & s,std::uint32_t batch_size)147 inline llvm::Function *llvm_add_inv_kep_E(llvm_state &s, std::uint32_t batch_size)
148 {
149     if constexpr (std::is_same_v<T, double>) {
150         return llvm_add_inv_kep_E_dbl(s, batch_size);
151     } else if constexpr (std::is_same_v<T, long double>) {
152         return llvm_add_inv_kep_E_ldbl(s, batch_size);
153 #if defined(HEYOKA_HAVE_REAL128)
154     } else if constexpr (std::is_same_v<T, mppp::real128>) {
155         return llvm_add_inv_kep_E_f128(s, batch_size);
156 #endif
157     } else {
158         static_assert(always_false_v<T>, "Unhandled type.");
159     }
160 }
161 
162 HEYOKA_DLL_PUBLIC llvm::Value *llvm_add_bc_array_dbl(llvm_state &, std::uint32_t);
163 HEYOKA_DLL_PUBLIC llvm::Value *llvm_add_bc_array_ldbl(llvm_state &, std::uint32_t);
164 
165 #if defined(HEYOKA_HAVE_REAL128)
166 
167 HEYOKA_DLL_PUBLIC llvm::Value *llvm_add_bc_array_f128(llvm_state &, std::uint32_t);
168 
169 #endif
170 
171 template <typename T>
llvm_add_bc_array(llvm_state & s,std::uint32_t n)172 inline llvm::Value *llvm_add_bc_array(llvm_state &s, std::uint32_t n)
173 {
174     if constexpr (std::is_same_v<T, double>) {
175         return llvm_add_bc_array_dbl(s, n);
176     } else if constexpr (std::is_same_v<T, long double>) {
177         return llvm_add_bc_array_ldbl(s, n);
178 #if defined(HEYOKA_HAVE_REAL128)
179     } else if constexpr (std::is_same_v<T, mppp::real128>) {
180         return llvm_add_bc_array_f128(s, n);
181 #endif
182     } else {
183         static_assert(always_false_v<T>, "Unhandled type.");
184     }
185 }
186 
187 // Double-length primitives.
188 
189 // Addition.
190 std::pair<llvm::Value *, llvm::Value *> llvm_dl_add(llvm_state &, llvm::Value *, llvm::Value *, llvm::Value *,
191                                                     llvm::Value *);
192 
193 // Less-than.
194 llvm::Value *llvm_dl_lt(llvm_state &, llvm::Value *, llvm::Value *, llvm::Value *, llvm::Value *);
195 
196 // Greater-than.
197 llvm::Value *llvm_dl_gt(llvm_state &, llvm::Value *, llvm::Value *, llvm::Value *, llvm::Value *);
198 
199 // Helpers to double check the modifications needed
200 // by LLVM deprecations.
201 bool llvm_depr_GEP_type_check(llvm::Value *, llvm::Type *);
202 
203 } // namespace heyoka::detail
204 
205 #endif
206