From e748d2f2af40895f1b067aaa74ac2ca2b737a243 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 19 Sep 2023 16:15:26 +0100 Subject: Update to LLVM-17 --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main.cpp') diff --git a/src/main.cpp b/src/main.cpp index f1b62320f..3d8637757 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -85,7 +85,7 @@ gb_global Timings global_timings = {0}; #include "llvm_backend.cpp" #if defined(GB_SYSTEM_OSX) - #include + #include #if LLVM_VERSION_MAJOR < 11 #error LLVM Version 11+ is required => "brew install llvm@11" #endif -- cgit v1.2.3 From 2160484b62ebde52ba6f486ad652f1a72cfe9143 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 21 Sep 2023 09:40:33 +0100 Subject: Support `-sanitize:` for `address`, `memory`, `thread` for LLVM 17 --- src/build_settings.cpp | 16 ++++++++++++++++ src/llvm_backend.cpp | 18 +++++++++++++++++- src/main.cpp | 19 +++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) (limited to 'src/main.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 79f6e8a2c..57dac0ca3 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -264,6 +264,14 @@ u64 get_vet_flag_from_name(String const &name) { } +enum SanitizerFlags : u32 { + SanitizerFlag_NONE = 0, + SanitizerFlag_Address = 1u<<0, + SanitizerFlag_Memory = 1u<<1, + SanitizerFlag_Thread = 1u<<2, +}; + + // This stores the information for the specify architecture of this build struct BuildContext { @@ -305,6 +313,7 @@ struct BuildContext { String pdb_filepath; u64 vet_flags; + u32 sanitizer_flags; bool has_resource; String link_flags; @@ -1738,6 +1747,13 @@ gb_internal bool init_build_paths(String init_filename) { return false; } + if (build_context.sanitizer_flags & SanitizerFlag_Memory) { + if (build_context.metrics.os != TargetOs_linux) { + gb_printf_err("-sanitize:memory is only supported on linux\n"); + return false; + } + } + if (bc->target_features_string.len != 0) { enable_target_feature({}, bc->target_features_string); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 8ced9ccee..68223d8c9 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1478,12 +1478,28 @@ gb_internal WORKER_TASK_PROC(lb_llvm_module_pass_worker_proc) { passes = gb_string_appendc(passes, "default"); break; case 1: - passes = gb_string_appendc(passes, "default"); + passes = gb_string_appendc(passes, "default"); break; case 2: passes = gb_string_appendc(passes, "default"); break; } + + // asan - Linux, Darwin, Windows + // msan - linux + // tsan - Linux, Darwin + // ubsan - Linux, Darwin, Windows (NOT SUPPORTED WITH LLVM C-API) + + if (build_context.sanitizer_flags & SanitizerFlag_Address) { + passes = gb_string_appendc(passes, ",asan"); + } + if (build_context.sanitizer_flags & SanitizerFlag_Memory) { + passes = gb_string_appendc(passes, ",msan"); + } + if (build_context.sanitizer_flags & SanitizerFlag_Thread) { + passes = gb_string_appendc(passes, ",tsan"); + } + LLVMErrorRef llvm_err = LLVMRunPasses(wd->m->mod, passes, wd->target_machine, pb_options); defer (LLVMConsumeError(llvm_err)); if (llvm_err != nullptr) { diff --git a/src/main.cpp b/src/main.cpp index 3d8637757..3d2dd3c44 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -300,6 +300,8 @@ enum BuildFlagKind { BuildFlag_Tilde, + BuildFlag_Sanitize, + #if defined(GB_SYSTEM_WINDOWS) BuildFlag_IgnoreVsSearch, BuildFlag_ResourceFile, @@ -486,6 +488,8 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_Tilde, str_lit("tilde"), BuildFlagParam_None, Command__does_build); #endif + add_flag(&build_flags, BuildFlag_Sanitize, str_lit("sanitize"), BuildFlagParam_String, Command__does_build, true); + #if defined(GB_SYSTEM_WINDOWS) add_flag(&build_flags, BuildFlag_IgnoreVsSearch, str_lit("ignore-vs-search"), BuildFlagParam_None, Command__does_build); add_flag(&build_flags, BuildFlag_ResourceFile, str_lit("resource"), BuildFlagParam_String, Command__does_build); @@ -1194,6 +1198,21 @@ gb_internal bool parse_build_flags(Array args) { build_context.tilde_backend = true; break; + case BuildFlag_Sanitize: + GB_ASSERT(value.kind == ExactValue_String); + + if (str_eq_ignore_case(value.value_string, str_lit("address"))) { + build_context.sanitizer_flags |= SanitizerFlag_Address; + } else if (str_eq_ignore_case(value.value_string, str_lit("memory"))) { + build_context.sanitizer_flags |= SanitizerFlag_Memory; + } else if (str_eq_ignore_case(value.value_string, str_lit("thread"))) { + build_context.sanitizer_flags |= SanitizerFlag_Thread; + } else { + gb_printf_err("-sanitize: options are 'address', 'memory', and 'thread'\n"); + bad_flags = true; + } + break; + #if defined(GB_SYSTEM_WINDOWS) case BuildFlag_IgnoreVsSearch: { GB_ASSERT(value.kind == ExactValue_Invalid); -- cgit v1.2.3 From e82b0ea4cd1b8c750b517eee806ea4ae1e2b21a6 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 21 Sep 2023 09:48:53 +0100 Subject: Add `-o:aggressive` for LLVM 17 --- src/build_settings.cpp | 2 +- src/llvm_backend.cpp | 29 +++++++++++++++++++---------- src/llvm_backend.hpp | 1 + src/llvm_backend_opt.cpp | 3 +-- src/main.cpp | 22 +++++++++++++++++++++- 5 files changed, 43 insertions(+), 14 deletions(-) (limited to 'src/main.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 57dac0ca3..08e591a3a 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -1390,7 +1390,7 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta bc->optimization_level = -1; // -o:none } - bc->optimization_level = gb_clamp(bc->optimization_level, -1, 2); + bc->optimization_level = gb_clamp(bc->optimization_level, -1, 3); // ENFORCE DYNAMIC MAP CALLS bc->dynamic_map_calls = true; diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 68223d8c9..a09cd8b4f 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1358,6 +1358,7 @@ gb_internal WORKER_TASK_PROC(lb_llvm_function_pass_per_module) { m->function_pass_managers[lbFunctionPassManager_minimal] = LLVMCreateFunctionPassManagerForModule(m->mod); m->function_pass_managers[lbFunctionPassManager_size] = LLVMCreateFunctionPassManagerForModule(m->mod); m->function_pass_managers[lbFunctionPassManager_speed] = LLVMCreateFunctionPassManagerForModule(m->mod); + m->function_pass_managers[lbFunctionPassManager_aggressive] = LLVMCreateFunctionPassManagerForModule(m->mod); LLVMInitializeFunctionPassManager(m->function_pass_managers[lbFunctionPassManager_default]); LLVMInitializeFunctionPassManager(m->function_pass_managers[lbFunctionPassManager_default_without_memcpy]); @@ -1368,10 +1369,11 @@ gb_internal WORKER_TASK_PROC(lb_llvm_function_pass_per_module) { lb_populate_function_pass_manager(m, m->function_pass_managers[lbFunctionPassManager_default], false, build_context.optimization_level); lb_populate_function_pass_manager(m, m->function_pass_managers[lbFunctionPassManager_default_without_memcpy], true, build_context.optimization_level); - lb_populate_function_pass_manager_specific(m, m->function_pass_managers[lbFunctionPassManager_none], -1); - lb_populate_function_pass_manager_specific(m, m->function_pass_managers[lbFunctionPassManager_minimal], 0); - lb_populate_function_pass_manager_specific(m, m->function_pass_managers[lbFunctionPassManager_size], 1); - lb_populate_function_pass_manager_specific(m, m->function_pass_managers[lbFunctionPassManager_speed], 2); + lb_populate_function_pass_manager_specific(m, m->function_pass_managers[lbFunctionPassManager_none], -1); + lb_populate_function_pass_manager_specific(m, m->function_pass_managers[lbFunctionPassManager_minimal], 0); + lb_populate_function_pass_manager_specific(m, m->function_pass_managers[lbFunctionPassManager_size], 1); + lb_populate_function_pass_manager_specific(m, m->function_pass_managers[lbFunctionPassManager_speed], 2); + lb_populate_function_pass_manager_specific(m, m->function_pass_managers[lbFunctionPassManager_aggressive], 3); LLVMFinalizeFunctionPassManager(m->function_pass_managers[lbFunctionPassManager_default]); LLVMFinalizeFunctionPassManager(m->function_pass_managers[lbFunctionPassManager_default_without_memcpy]); @@ -1379,6 +1381,7 @@ gb_internal WORKER_TASK_PROC(lb_llvm_function_pass_per_module) { LLVMFinalizeFunctionPassManager(m->function_pass_managers[lbFunctionPassManager_minimal]); LLVMFinalizeFunctionPassManager(m->function_pass_managers[lbFunctionPassManager_size]); LLVMFinalizeFunctionPassManager(m->function_pass_managers[lbFunctionPassManager_speed]); + LLVMFinalizeFunctionPassManager(m->function_pass_managers[lbFunctionPassManager_aggressive]); } if (m == &m->gen->default_module) { @@ -1464,7 +1467,7 @@ gb_internal WORKER_TASK_PROC(lb_llvm_module_pass_worker_proc) { int inline_threshold = 0; LLVMPassBuilderOptionsSetInlinerThreshold(pb_options, inline_threshold); - if (build_context.optimization_level == 2) { + if (build_context.optimization_level >= 2) { LLVMPassBuilderOptionsSetLoopVectorization(pb_options, true); LLVMPassBuilderOptionsSetLoopUnrolling (pb_options, true); LLVMPassBuilderOptionsSetMergeFunctions (pb_options, true); @@ -1483,6 +1486,9 @@ gb_internal WORKER_TASK_PROC(lb_llvm_module_pass_worker_proc) { case 2: passes = gb_string_appendc(passes, "default"); break; + case 3: + passes = gb_string_appendc(passes, "default"); + break; } // asan - Linux, Darwin, Windows @@ -2105,12 +2111,15 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { // GB_ASSERT_MSG(LLVMTargetHasAsmBackend(target)); LLVMCodeGenOptLevel code_gen_level = LLVMCodeGenLevelNone; + if (!LB_USE_NEW_PASS_SYSTEM) { + build_context.optimization_level = gb_clamp(build_context.optimization_level, -1, 2); + } switch (build_context.optimization_level) { - case 0: code_gen_level = LLVMCodeGenLevelNone; break; - case 1: code_gen_level = LLVMCodeGenLevelLess; break; - case 2: code_gen_level = LLVMCodeGenLevelDefault; break; - case 3: code_gen_level = LLVMCodeGenLevelDefault; break; // NOTE(bill): force -opt:3 to be the same as -opt:2 - // case 3: code_gen_level = LLVMCodeGenLevelAggressive; break; + default:/*fallthrough*/ + case 0: code_gen_level = LLVMCodeGenLevelNone; break; + case 1: code_gen_level = LLVMCodeGenLevelLess; break; + case 2: code_gen_level = LLVMCodeGenLevelDefault; break; + case 3: code_gen_level = LLVMCodeGenLevelAggressive; break; } // NOTE(bill): Target Machine Creation diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 9386ed63e..d4da1f18a 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -117,6 +117,7 @@ enum lbFunctionPassManagerKind { lbFunctionPassManager_minimal, lbFunctionPassManager_size, lbFunctionPassManager_speed, + lbFunctionPassManager_aggressive, lbFunctionPassManager_COUNT }; diff --git a/src/llvm_backend_opt.cpp b/src/llvm_backend_opt.cpp index b7fdc60bf..2f0dc24fd 100644 --- a/src/llvm_backend_opt.cpp +++ b/src/llvm_backend_opt.cpp @@ -66,8 +66,7 @@ gb_internal void lb_populate_function_pass_manager_specific(lbModule *m, LLVMPas #endif gb_internal bool lb_opt_ignore(i32 optimization_level) { - optimization_level = gb_clamp(optimization_level, -1, 2); - return optimization_level == -1; + return optimization_level < 0; } gb_internal void lb_basic_populate_function_pass_manager(LLVMPassManagerRef fpm, i32 optimization_level) { diff --git a/src/main.cpp b/src/main.cpp index 3d2dd3c44..706bbab87 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -664,12 +664,18 @@ gb_internal bool parse_build_flags(Array args) { } else if (value.value_string == "speed") { build_context.custom_optimization_level = true; build_context.optimization_level = 2; + } else if (value.value_string == "aggressive" && LB_USE_NEW_PASS_SYSTEM) { + build_context.custom_optimization_level = true; + build_context.optimization_level = 3; } else { gb_printf_err("Invalid optimization mode for -o:, got %.*s\n", LIT(value.value_string)); gb_printf_err("Valid optimization modes:\n"); gb_printf_err("\tminimal\n"); gb_printf_err("\tsize\n"); gb_printf_err("\tspeed\n"); + if (LB_USE_NEW_PASS_SYSTEM) { + gb_printf_err("\taggressive\n"); + } gb_printf_err("\tnone (useful for -debug builds)\n"); bad_flags = true; } @@ -1668,8 +1674,13 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(1, "-o:"); print_usage_line(2, "Set the optimization mode for compilation"); - print_usage_line(2, "Accepted values: minimal, size, speed, none"); + if (LB_USE_NEW_PASS_SYSTEM) { + print_usage_line(2, "Accepted values: none, minimal, size, speed, aggressive"); + } else { + print_usage_line(2, "Accepted values: none, minimal, size, speed"); + } print_usage_line(2, "Example: -o:speed"); + print_usage_line(2, "The default is -o:minimal"); print_usage_line(0, ""); } @@ -1948,6 +1959,15 @@ gb_internal void print_show_help(String const arg0, String const &command) { } + if (run_or_build) { + print_usage_line(1, "-sanitize:"); + print_usage_line(1, "Enables sanitization analysis"); + print_usage_line(1, "Options are 'address', 'memory', and 'thread'"); + print_usage_line(1, "NOTE: This flag can be used multiple times"); + print_usage_line(0, ""); + + } + if (run_or_build) { #if defined(GB_SYSTEM_WINDOWS) print_usage_line(1, "-ignore-vs-search"); -- cgit v1.2.3 From 96fbafe3598822d8d62791d881879c4da33431ea Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 21 Sep 2023 10:38:44 +0100 Subject: Update ABI breaking changes for `f16` types (due to LLVM 15+) --- core/runtime/internal.odin | 26 +++++++++++++++----------- src/checker.cpp | 3 +++ src/llvm_backend.hpp | 14 ++++++++++++++ src/llvm_backend_opt.cpp | 10 ---------- src/main.cpp | 1 - 5 files changed, 32 insertions(+), 22 deletions(-) (limited to 'src/main.cpp') diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index 4d166bef0..7e13bb929 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -13,6 +13,9 @@ RUNTIME_LINKAGE :: "strong" when ( !IS_WASM) else "internal" RUNTIME_REQUIRE :: !ODIN_TILDE +@(private) +__float16 :: f16 when __ODIN_LLVM_F16_SUPPORTED else u16 + @(private) byte_slice :: #force_inline proc "contextless" (data: rawptr, len: int) -> []byte #no_bounds_check { @@ -755,7 +758,7 @@ quo_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 { } @(link_name="__truncsfhf2", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE) -truncsfhf2 :: proc "c" (value: f32) -> u16 { +truncsfhf2 :: proc "c" (value: f32) -> __float16 { v: struct #raw_union { i: u32, f: f32 } i, s, e, m: i32 @@ -769,7 +772,7 @@ truncsfhf2 :: proc "c" (value: f32) -> u16 { if e <= 0 { if e < -10 { - return u16(s) + return transmute(__float16)u16(s) } m = (m | 0x00800000) >> u32(1 - e) @@ -777,14 +780,14 @@ truncsfhf2 :: proc "c" (value: f32) -> u16 { m += 0x00002000 } - return u16(s | (m >> 13)) + return transmute(__float16)u16(s | (m >> 13)) } else if e == 0xff - (127 - 15) { if m == 0 { - return u16(s | 0x7c00) /* NOTE(bill): infinity */ + return transmute(__float16)u16(s | 0x7c00) /* NOTE(bill): infinity */ } else { /* NOTE(bill): NAN */ m >>= 13 - return u16(s | 0x7c00 | m | i32(m == 0)) + return transmute(__float16)u16(s | 0x7c00 | m | i32(m == 0)) } } else { if m & 0x00001000 != 0 { @@ -804,23 +807,24 @@ truncsfhf2 :: proc "c" (value: f32) -> u16 { intrinsics.volatile_store(&f, g) } - return u16(s | 0x7c00) + return transmute(__float16)u16(s | 0x7c00) } - return u16(s | (e << 10) | (m >> 13)) + return transmute(__float16)u16(s | (e << 10) | (m >> 13)) } } @(link_name="__truncdfhf2", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE) -truncdfhf2 :: proc "c" (value: f64) -> u16 { +truncdfhf2 :: proc "c" (value: f64) -> __float16 { return truncsfhf2(f32(value)) } @(link_name="__gnu_h2f_ieee", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE) -gnu_h2f_ieee :: proc "c" (value: u16) -> f32 { +gnu_h2f_ieee :: proc "c" (value_: __float16) -> f32 { fp32 :: struct #raw_union { u: u32, f: f32 } + value := transmute(u16)value_ v: fp32 magic, inf_or_nan: fp32 magic.u = u32((254 - 15) << 23) @@ -837,12 +841,12 @@ gnu_h2f_ieee :: proc "c" (value: u16) -> f32 { @(link_name="__gnu_f2h_ieee", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE) -gnu_f2h_ieee :: proc "c" (value: f32) -> u16 { +gnu_f2h_ieee :: proc "c" (value: f32) -> __float16 { return truncsfhf2(value) } @(link_name="__extendhfsf2", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE) -extendhfsf2 :: proc "c" (value: u16) -> f32 { +extendhfsf2 :: proc "c" (value: __float16) -> f32 { return gnu_h2f_ieee(value) } diff --git a/src/checker.cpp b/src/checker.cpp index 18d403d80..0be912df5 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -935,6 +935,7 @@ gb_internal i64 odin_compile_timestamp(void) { return ns_after_1970; } +gb_internal bool lb_use_new_pass_system(void); gb_internal void init_universal(void) { BuildContext *bc = &build_context; @@ -1083,6 +1084,8 @@ gb_internal void init_universal(void) { add_global_constant("ODIN_COMPILE_TIMESTAMP", t_untyped_integer, exact_value_i64(odin_compile_timestamp())); + add_global_bool_constant("__ODIN_LLVM_F16_SUPPORTED", lb_use_new_pass_system()); + // Builtin Procedures for (isize i = 0; i < gb_count_of(builtin_procs); i++) { diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index d4da1f18a..048233c08 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -48,6 +48,20 @@ #define ODIN_LLVM_MINIMUM_VERSION_14 0 #endif +#if LLVM_VERSION_MAJOR == 15 || LLVM_VERSION_MAJOR == 16 +#error "LLVM versions 15 and 16 are not supported" +#endif + +#if LLVM_VERSION_MAJOR >= 17 +#define LB_USE_NEW_PASS_SYSTEM 1 +#else +#define LB_USE_NEW_PASS_SYSTEM 0 +#endif + +gb_internal bool lb_use_new_pass_system(void) { + return LB_USE_NEW_PASS_SYSTEM; +} + struct lbProcedure; struct lbValue { diff --git a/src/llvm_backend_opt.cpp b/src/llvm_backend_opt.cpp index 2f0dc24fd..055cb5bcb 100644 --- a/src/llvm_backend_opt.cpp +++ b/src/llvm_backend_opt.cpp @@ -55,16 +55,6 @@ gb_internal void lb_populate_function_pass_manager_specific(lbModule *m, LLVMPas #define LLVM_ADD_CONSTANT_VALUE_PASS(fpm) #endif -#if LLVM_VERSION_MAJOR == 15 || LLVM_VERSION_MAJOR == 16 -#error "LLVM versions 15 and 16 are not supported" -#endif - -#if LLVM_VERSION_MAJOR >= 17 -#define LB_USE_NEW_PASS_SYSTEM 1 -#else -#define LB_USE_NEW_PASS_SYSTEM 0 -#endif - gb_internal bool lb_opt_ignore(i32 optimization_level) { return optimization_level < 0; } diff --git a/src/main.cpp b/src/main.cpp index 706bbab87..c6b6e74bf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -412,7 +412,6 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_SingleFile, str_lit("file"), BuildFlagParam_None, Command__does_build | Command__does_check); add_flag(&build_flags, BuildFlag_OutFile, str_lit("out"), BuildFlagParam_String, Command__does_build | Command_test); add_flag(&build_flags, BuildFlag_OptimizationMode, str_lit("o"), BuildFlagParam_String, Command__does_build); - add_flag(&build_flags, BuildFlag_OptimizationMode, str_lit("O"), BuildFlagParam_String, Command__does_build); add_flag(&build_flags, BuildFlag_ShowTimings, str_lit("show-timings"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_ShowMoreTimings, str_lit("show-more-timings"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_ExportTimings, str_lit("export-timings"), BuildFlagParam_String, Command__does_check); -- cgit v1.2.3 From bc401fa392c937a8935adeaacab11b1d6525ca00 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 21 Sep 2023 10:41:42 +0100 Subject: Fix wrong import due to grep-replace --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main.cpp') diff --git a/src/main.cpp b/src/main.cpp index c6b6e74bf..fca1341e6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -85,7 +85,7 @@ gb_global Timings global_timings = {0}; #include "llvm_backend.cpp" #if defined(GB_SYSTEM_OSX) - #include + #include #if LLVM_VERSION_MAJOR < 11 #error LLVM Version 11+ is required => "brew install llvm@11" #endif -- cgit v1.2.3