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