start adding graphics pipeline
[kazan.git] / src / llvm_wrapper / llvm_wrapper.h
1 /*
2 * Copyright 2017 Jacob Lifshay
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in all
12 * copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 *
22 */
23 #ifndef LLVM_WRAPPER_LLVM_WRAPPER_H_
24 #define LLVM_WRAPPER_LLVM_WRAPPER_H_
25
26 #include <llvm-c/Core.h>
27 #include <llvm-c/Target.h>
28 #include <llvm-c/TargetMachine.h>
29 #include <llvm-c/OrcBindings.h>
30 #include <llvm-c/Analysis.h>
31 #include <memory>
32 #include <type_traits>
33 #include <utility>
34 #include <string>
35 #include <cassert>
36 #include <stdexcept>
37 #include "util/string_view.h"
38 #include "util/variant.h"
39
40 namespace vulkan_cpu
41 {
42 namespace llvm_wrapper
43 {
44 template <typename T, typename Deleter>
45 class Wrapper
46 {
47 static_assert(std::is_pointer<T>::value, "");
48
49 private:
50 T value;
51
52 public:
53 constexpr Wrapper() noexcept : value(nullptr)
54 {
55 }
56 constexpr explicit Wrapper(T value) noexcept : value(value)
57 {
58 }
59 Wrapper(Wrapper &&rt) noexcept : value(rt.value)
60 {
61 rt.value = nullptr;
62 }
63 Wrapper &operator=(Wrapper rt) noexcept
64 {
65 swap(rt);
66 return *this;
67 }
68 ~Wrapper() noexcept
69 {
70 if(value)
71 Deleter()(value);
72 }
73 void swap(Wrapper &other) noexcept
74 {
75 using std::swap;
76 swap(value, other.value);
77 }
78 T get() const noexcept
79 {
80 return value;
81 }
82 explicit operator T() const noexcept
83 {
84 return value;
85 }
86 explicit operator bool() const noexcept
87 {
88 return value != nullptr;
89 }
90 T release() noexcept
91 {
92 auto retval = value;
93 value = nullptr;
94 return retval;
95 }
96 void reset(T value) noexcept
97 {
98 *this = Wrapper(value);
99 }
100 };
101
102 struct LLVM_string_deleter
103 {
104 void operator()(char *str)
105 {
106 ::LLVMDisposeMessage(str);
107 }
108 };
109
110 class LLVM_string : public Wrapper<char *, LLVM_string_deleter>
111 {
112 public:
113 constexpr LLVM_string() noexcept : Wrapper()
114 {
115 }
116 static LLVM_string wrap(char *value) noexcept
117 {
118 LLVM_string retval;
119 retval.reset(value);
120 return retval;
121 }
122 static LLVM_string from(const char *value)
123 {
124 return wrap(::LLVMCreateMessage(value));
125 }
126 static LLVM_string from(const std::string &value)
127 {
128 return from(value.c_str());
129 }
130 static LLVM_string from(util::string_view value)
131 {
132 return from(std::string(value));
133 }
134 operator util::string_view() const
135 {
136 assert(*this);
137 return util::string_view(get());
138 }
139 explicit operator std::string() const
140 {
141 assert(*this);
142 return get();
143 }
144 explicit operator char *() const // override non-explicit operator
145 {
146 return get();
147 }
148 };
149
150 struct Context_deleter
151 {
152 void operator()(::LLVMContextRef context) noexcept
153 {
154 ::LLVMContextDispose(context);
155 }
156 };
157
158 struct Context : public Wrapper<::LLVMContextRef, Context_deleter>
159 {
160 using Wrapper::Wrapper;
161
162 private:
163 static void init_helper();
164
165 public:
166 static void init()
167 {
168 static int v = (init_helper(), 0);
169 static_cast<void>(v);
170 }
171 static Context create()
172 {
173 init();
174 return Context(::LLVMContextCreate());
175 }
176 };
177
178 struct Target_deleter
179 {
180 void operator()(::LLVMTargetRef target) noexcept
181 {
182 static_cast<void>(target);
183 }
184 };
185
186 struct Target : public Wrapper<::LLVMTargetRef, Target_deleter>
187 {
188 using Wrapper::Wrapper;
189 static LLVM_string get_default_target_triple()
190 {
191 Context::init();
192 return LLVM_string::wrap(::LLVMGetDefaultTargetTriple());
193 }
194 static LLVM_string get_process_target_triple();
195 static LLVM_string get_host_cpu_name();
196 static LLVM_string get_host_cpu_features();
197 typedef util::variant<Target, LLVM_string> Target_or_error_message;
198 static Target_or_error_message get_target_from_target_triple(const char *triple)
199 {
200 Context::init();
201 ::LLVMTargetRef target = nullptr;
202 char *error_message = nullptr;
203 if(::LLVMGetTargetFromTriple(triple, &target, &error_message) == 0)
204 return Target(target);
205 return LLVM_string::wrap(error_message);
206 }
207 static Target get_native_target()
208 {
209 Context::init();
210 auto native_triple = get_process_target_triple();
211 auto retval = get_target_from_target_triple(native_triple.get());
212 auto *target = util::get_if<Target>(&retval);
213 if(!target)
214 throw std::runtime_error(
215 "can't find target for native triple (" + std::string(native_triple) + "): "
216 + util::get<LLVM_string>(retval).get());
217 return std::move(*target);
218 }
219 };
220
221 struct Target_data_deleter
222 {
223 void operator()(::LLVMTargetDataRef v) noexcept
224 {
225 ::LLVMDisposeTargetData(v);
226 }
227 };
228
229 struct Target_data : public Wrapper<::LLVMTargetDataRef, Target_data_deleter>
230 {
231 using Wrapper::Wrapper;
232 static LLVM_string to_string(::LLVMTargetDataRef td)
233 {
234 return LLVM_string::wrap(::LLVMCopyStringRepOfTargetData(td));
235 }
236 LLVM_string to_string() const
237 {
238 return to_string(get());
239 }
240 static Target_data from_string(const char *str)
241 {
242 return Target_data(::LLVMCreateTargetData(str));
243 }
244 static std::size_t get_pointer_alignment(::LLVMTargetDataRef td) noexcept;
245 std::size_t get_pointer_alignment() const noexcept
246 {
247 return get_pointer_alignment(get());
248 }
249 };
250
251 struct Target_machine_deleter
252 {
253 void operator()(::LLVMTargetMachineRef tm) noexcept
254 {
255 ::LLVMDisposeTargetMachine(tm);
256 }
257 };
258
259 struct Target_machine : public Wrapper<::LLVMTargetMachineRef, Target_machine_deleter>
260 {
261 using Wrapper::Wrapper;
262 static Target_machine create_native_target_machine();
263 static Target get_target(::LLVMTargetMachineRef tm)
264 {
265 return Target(::LLVMGetTargetMachineTarget(tm));
266 }
267 Target get_target() const
268 {
269 return get_target(get());
270 }
271 static LLVM_string get_target_triple(::LLVMTargetMachineRef tm)
272 {
273 return LLVM_string::wrap(::LLVMGetTargetMachineTriple(tm));
274 }
275 LLVM_string get_target_triple() const
276 {
277 return get_target_triple(get());
278 }
279 static Target_data create_target_data_layout(::LLVMTargetMachineRef tm)
280 {
281 return Target_data(::LLVMCreateTargetDataLayout(tm));
282 }
283 Target_data create_target_data_layout() const
284 {
285 return create_target_data_layout(get());
286 }
287 static LLVM_string get_cpu(::LLVMTargetMachineRef tm)
288 {
289 return LLVM_string::wrap(::LLVMGetTargetMachineCPU(tm));
290 }
291 LLVM_string get_cpu() const
292 {
293 return get_cpu(get());
294 }
295 static LLVM_string get_feature_string(::LLVMTargetMachineRef tm)
296 {
297 return LLVM_string::wrap(::LLVMGetTargetMachineFeatureString(tm));
298 }
299 LLVM_string get_feature_string() const
300 {
301 return get_feature_string(get());
302 }
303 };
304
305 struct Module_deleter
306 {
307 void operator()(::LLVMModuleRef module) noexcept
308 {
309 ::LLVMDisposeModule(module);
310 }
311 };
312
313 struct Module : public Wrapper<::LLVMModuleRef, Module_deleter>
314 {
315 using Wrapper::Wrapper;
316 static Module create(const char *id, ::LLVMContextRef context)
317 {
318 return Module(::LLVMModuleCreateWithNameInContext(id, context));
319 }
320 static Module create_with_target_machine(const char *id,
321 ::LLVMContextRef context,
322 ::LLVMTargetMachineRef target_machine)
323 {
324 Module retval = create(id, context);
325 retval.set_target_machine(target_machine);
326 return retval;
327 }
328 static void set_target_machine(::LLVMModuleRef module, ::LLVMTargetMachineRef target_machine);
329 static void set_function_target_machine(::LLVMValueRef function,
330 ::LLVMTargetMachineRef target_machine);
331 void set_target_machine(::LLVMTargetMachineRef target_machine)
332 {
333 set_target_machine(get(), target_machine);
334 }
335 };
336
337 inline LLVM_string print_type_to_string(::LLVMTypeRef type)
338 {
339 return LLVM_string::wrap(::LLVMPrintTypeToString(type));
340 }
341
342 struct Builder_deleter
343 {
344 void operator()(::LLVMBuilderRef v) noexcept
345 {
346 return ::LLVMDisposeBuilder(v);
347 }
348 };
349
350 struct Builder : public Wrapper<::LLVMBuilderRef, Builder_deleter>
351 {
352 using Wrapper::Wrapper;
353 static Builder create(::LLVMContextRef context)
354 {
355 return Builder(::LLVMCreateBuilderInContext(context));
356 }
357 static ::LLVMValueRef build_smod(::LLVMBuilderRef builder,
358 ::LLVMValueRef lhs,
359 ::LLVMValueRef rhs,
360 const char *result_name)
361 {
362 auto srem_result = ::LLVMBuildSRem(builder, lhs, rhs, "");
363 auto zero_constant = ::LLVMConstInt(::LLVMTypeOf(lhs), 0, false);
364 auto different_signs = ::LLVMBuildICmp(
365 builder, ::LLVMIntSLT, ::LLVMBuildXor(builder, lhs, rhs, ""), zero_constant, "");
366 auto imperfectly_divides =
367 ::LLVMBuildICmp(builder, ::LLVMIntNE, srem_result, zero_constant, "");
368 auto adjustment =
369 ::LLVMBuildSelect(builder,
370 ::LLVMBuildAnd(builder, different_signs, imperfectly_divides, ""),
371 rhs,
372 zero_constant,
373 "");
374 return ::LLVMBuildAdd(builder, srem_result, adjustment, result_name);
375 }
376 ::LLVMValueRef build_smod(::LLVMValueRef lhs, ::LLVMValueRef rhs, const char *result_name) const
377 {
378 return build_smod(get(), lhs, rhs, result_name);
379 }
380 };
381
382 inline ::LLVMTypeRef get_scalar_or_vector_element_type(::LLVMTypeRef type)
383 {
384 if(::LLVMGetTypeKind(type) == ::LLVMTypeKind::LLVMVectorTypeKind)
385 return ::LLVMGetElementType(type);
386 return type;
387 }
388
389 // TODO: add CMake tests to determine which Orc version we need
390 #if 0
391 // added error code return from LLVMOrcAddEagerlyCompiledIR
392 #define LLVM_WRAPPER_ORC_REVISION_NUMBER 307350
393 #elif 0
394 // added shared modules
395 #define LLVM_WRAPPER_ORC_REVISION_NUMBER 306182
396 #else
397 // initial revision
398 #define LLVM_WRAPPER_ORC_REVISION_NUMBER 251482
399 #endif
400
401 #if LLVM_WRAPPER_ORC_REVISION_NUMBER >= 306166
402 struct Orc_shared_module_ref_deleter
403 {
404 void operator()(::LLVMSharedModuleRef v) noexcept
405 {
406 ::LLVMOrcDisposeSharedModuleRef(v);
407 }
408 };
409
410 struct Orc_shared_module_ref : public Wrapper<::LLVMSharedModuleRef, Orc_shared_module_ref_deleter>
411 {
412 using Wrapper::Wrapper;
413 static Orc_shared_module_ref make(Module module)
414 {
415 return Orc_shared_module_ref(::LLVMOrcMakeSharedModule(module.release()));
416 }
417 };
418 #endif
419
420 struct Orc_jit_stack_deleter
421 {
422 void operator()(::LLVMOrcJITStackRef v) noexcept
423 {
424 ::LLVMOrcDisposeInstance(v);
425 }
426 };
427
428 struct Orc_jit_stack : public Wrapper<::LLVMOrcJITStackRef, Orc_jit_stack_deleter>
429 {
430 using Wrapper::Wrapper;
431 static Orc_jit_stack create(Target_machine target_machine)
432 {
433 return Orc_jit_stack(::LLVMOrcCreateInstance(target_machine.release()));
434 }
435 static ::LLVMOrcModuleHandle add_eagerly_compiled_ir(
436 ::LLVMOrcJITStackRef orc_jit_stack,
437 Module module,
438 ::LLVMOrcSymbolResolverFn symbol_resolver_callback,
439 void *symbol_resolver_user_data)
440 {
441 ::LLVMOrcModuleHandle retval{};
442 #if LLVM_WRAPPER_ORC_REVISION_NUMBER >= 307350
443 if(::LLVMOrcErrorSuccess
444 != ::LLVMOrcAddEagerlyCompiledIR(orc_jit_stack,
445 &retval,
446 Orc_shared_module_ref::make(std::move(module)).get(),
447 symbol_resolver_callback,
448 symbol_resolver_user_data))
449 throw std::runtime_error(std::string("LLVM Orc Error: ")
450 + ::LLVMOrcGetErrorMsg(orc_jit_stack));
451 #elif LLVM_WRAPPER_ORC_REVISION_NUMBER >= 306182
452 retval = ::LLVMOrcAddEagerlyCompiledIR(orc_jit_stack,
453 Orc_shared_module_ref::make(std::move(module)).get(),
454 symbol_resolver_callback,
455 symbol_resolver_user_data);
456 #elif LLVM_WRAPPER_ORC_REVISION_NUMBER >= 251482
457 retval = ::LLVMOrcAddEagerlyCompiledIR(
458 orc_jit_stack, module.release(), symbol_resolver_callback, symbol_resolver_user_data);
459 #else
460 #error unsupported LLVM_WRAPPER_ORC_REVISION_NUMBER
461 #endif
462 return retval;
463 }
464 ::LLVMOrcModuleHandle add_eagerly_compiled_ir(
465 Module module,
466 ::LLVMOrcSymbolResolverFn symbol_resolver_callback,
467 void *symbol_resolver_user_data)
468 {
469 return add_eagerly_compiled_ir(
470 get(), std::move(module), symbol_resolver_callback, symbol_resolver_user_data);
471 }
472 static std::uintptr_t get_symbol_address(::LLVMOrcJITStackRef orc_jit_stack,
473 const char *symbol_name)
474 {
475 return ::LLVMOrcGetSymbolAddress(orc_jit_stack, symbol_name);
476 }
477 template <typename T>
478 static T *get_symbol(::LLVMOrcJITStackRef orc_jit_stack, const char *symbol_name)
479 {
480 return reinterpret_cast<T *>(get_symbol_address(orc_jit_stack, symbol_name));
481 }
482 std::uintptr_t get_symbol_address(const char *symbol_name)
483 {
484 return get_symbol_address(get(), symbol_name);
485 }
486 template <typename T>
487 T *get_symbol(const char *symbol_name)
488 {
489 return get_symbol<T>(get(), symbol_name);
490 }
491 };
492
493 template <typename T>
494 struct Create_llvm_type
495 {
496 static_assert(!std::is_same<T, T>::value, "Create_llvm_type not implemented for type T");
497 ::LLVMTypeRef operator()(::LLVMContextRef context) const = delete;
498 };
499
500 template <typename T>
501 struct Create_llvm_type<const T> : public Create_llvm_type<T>
502 {
503 };
504
505 template <>
506 struct Create_llvm_type<void>
507 {
508 ::LLVMTypeRef operator()(::LLVMContextRef context) const
509 {
510 return ::LLVMVoidTypeInContext(context);
511 }
512 };
513
514 template <>
515 struct Create_llvm_type<bool>
516 {
517 ::LLVMTypeRef operator()(::LLVMContextRef context) const
518 {
519 return ::LLVMIntTypeInContext(context,
520 std::numeric_limits<unsigned char>::digits * sizeof(bool));
521 }
522 };
523
524 template <>
525 struct Create_llvm_type<char>
526 {
527 ::LLVMTypeRef operator()(::LLVMContextRef context) const
528 {
529 return ::LLVMIntTypeInContext(context, std::numeric_limits<unsigned char>::digits);
530 }
531 };
532
533 template <>
534 struct Create_llvm_type<unsigned char>
535 {
536 ::LLVMTypeRef operator()(::LLVMContextRef context) const
537 {
538 return ::LLVMIntTypeInContext(context, std::numeric_limits<unsigned char>::digits);
539 }
540 };
541
542 template <>
543 struct Create_llvm_type<signed char>
544 {
545 ::LLVMTypeRef operator()(::LLVMContextRef context) const
546 {
547 return ::LLVMIntTypeInContext(context, std::numeric_limits<unsigned char>::digits);
548 }
549 };
550
551 template <>
552 struct Create_llvm_type<short>
553 {
554 ::LLVMTypeRef operator()(::LLVMContextRef context) const
555 {
556 return ::LLVMIntTypeInContext(context, std::numeric_limits<unsigned short>::digits);
557 }
558 };
559
560 template <>
561 struct Create_llvm_type<unsigned short>
562 {
563 ::LLVMTypeRef operator()(::LLVMContextRef context) const
564 {
565 return ::LLVMIntTypeInContext(context, std::numeric_limits<unsigned short>::digits);
566 }
567 };
568
569 template <>
570 struct Create_llvm_type<int>
571 {
572 ::LLVMTypeRef operator()(::LLVMContextRef context) const
573 {
574 return ::LLVMIntTypeInContext(context, std::numeric_limits<unsigned>::digits);
575 }
576 };
577
578 template <>
579 struct Create_llvm_type<unsigned>
580 {
581 ::LLVMTypeRef operator()(::LLVMContextRef context) const
582 {
583 return ::LLVMIntTypeInContext(context, std::numeric_limits<unsigned>::digits);
584 }
585 };
586
587 template <>
588 struct Create_llvm_type<long>
589 {
590 ::LLVMTypeRef operator()(::LLVMContextRef context) const
591 {
592 return ::LLVMIntTypeInContext(context, std::numeric_limits<unsigned long>::digits);
593 }
594 };
595
596 template <>
597 struct Create_llvm_type<unsigned long>
598 {
599 ::LLVMTypeRef operator()(::LLVMContextRef context) const
600 {
601 return ::LLVMIntTypeInContext(context, std::numeric_limits<unsigned long>::digits);
602 }
603 };
604
605 template <>
606 struct Create_llvm_type<long long>
607 {
608 ::LLVMTypeRef operator()(::LLVMContextRef context) const
609 {
610 return ::LLVMIntTypeInContext(context, std::numeric_limits<unsigned long long>::digits);
611 }
612 };
613
614 template <>
615 struct Create_llvm_type<unsigned long long>
616 {
617 ::LLVMTypeRef operator()(::LLVMContextRef context) const
618 {
619 return ::LLVMIntTypeInContext(context, std::numeric_limits<unsigned long long>::digits);
620 }
621 };
622
623 template <typename T>
624 struct Create_llvm_type<T *>
625 {
626 ::LLVMTypeRef operator()(::LLVMContextRef context) const
627 {
628 constexpr unsigned default_address_space = 0;
629 return ::LLVMPointerType(Create_llvm_type<T>()(context), default_address_space);
630 }
631 };
632
633 template <>
634 struct Create_llvm_type<void *> : public Create_llvm_type<unsigned char *>
635 {
636 };
637
638 template <>
639 struct Create_llvm_type<const void *> : public Create_llvm_type<const unsigned char *>
640 {
641 };
642
643 template <typename T, std::size_t N>
644 struct Create_llvm_type<T[N]>
645 {
646 ::LLVMTypeRef operator()(::LLVMContextRef context) const
647 {
648 return ::LLVMArrayType(Create_llvm_type<T>()(context), N);
649 }
650 };
651
652 template <typename Return_type, typename ...Args>
653 struct Create_llvm_type<Return_type (*)(Args...)>
654 {
655 ::LLVMTypeRef operator()(::LLVMContextRef context) const
656 {
657 ::LLVMTypeRef arguments[] = {Create_llvm_type<Args>()(context)...};
658 constexpr bool is_var_arg = false;
659 return ::LLVMFunctionType(
660 Create_llvm_type<Return_type>()(context), arguments, sizeof...(Args), is_var_arg);
661 }
662 };
663 }
664 }
665
666 #endif /* LLVM_WRAPPER_LLVM_WRAPPER_H_ */