diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a54b1de9..857b1675a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -369,11 +369,11 @@ endif() target_include_directories(c3c PRIVATE - "${CMAKE_SOURCE_DIR}/src/") + "${CMAKE_SOURCE_DIR}/src/" "${CMAKE_SOURCE_DIR}/wrapper/include/") target_include_directories(c3c_wrappers PRIVATE - "${CMAKE_SOURCE_DIR}/wrapper/src/") + "${CMAKE_SOURCE_DIR}/wrapper/include/") target_include_directories(miniz PUBLIC "${CMAKE_SOURCE_DIR}/dependencies/miniz/") diff --git a/releasenotes.md b/releasenotes.md index 7a8990f46..6eac58261 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -1,5 +1,16 @@ # C3C Release Notes +## 0.6.2 Change list + +### Changes / improvements +- Updated LLVM passes + +### Fixes +None + +### Stdlib changes +None + ## 0.6.1 Change list ### Changes / improvements diff --git a/src/build/build.h b/src/build/build.h index af7c78546..3d81e9b73 100644 --- a/src/build/build.h +++ b/src/build/build.h @@ -144,7 +144,26 @@ typedef enum SINGLE_MODULE_ON = 1 } SingleModule; +typedef enum +{ + UNROLL_LOOPS_NOT_SET = -1, + UNROLL_LOOPS_OFF = 0, + UNROLL_LOOPS_ON = 1 +} UnrollLoops; +typedef enum +{ + MERGE_FUNCTIONS_NOT_SET = -1, + MERGE_FUNCTIONS_OFF = 0, + MERGE_FUNCTIONS_ON = 1 +} MergeFunctions; + +typedef enum +{ + VECTORIZATION_NOT_SET = -1, + VECTORIZATION_OFF = 0, + VECTORIZATION_ON = 1 +} AutoVectorization; typedef enum { STRIP_UNUSED_NOT_SET = -1, @@ -361,6 +380,10 @@ typedef struct BuildOptions_ SafetyLevel safety_level; PanicLevel panic_level; SingleModule single_module; + UnrollLoops unroll_loops; + MergeFunctions merge_functions; + AutoVectorization loop_vectorization; + AutoVectorization slp_vectorization; bool emit_llvm; bool emit_asm; bool benchmark_mode; @@ -488,6 +511,7 @@ typedef struct bool print_input; bool print_linking; bool no_entry; + bool kernel_build; int build_threads; TrustLevel trust_level; OptimizationSetting optsetting; @@ -500,6 +524,10 @@ typedef struct LinkLibc link_libc; StripUnused strip_unused; DebugInfo debug_info; + MergeFunctions merge_functions; + UnrollLoops unroll_loops; + AutoVectorization loop_vectorization; + AutoVectorization slp_vectorization; RelocModel reloc_model; ArchOsTarget arch_os_target; CompilerBackend backend; @@ -573,6 +601,10 @@ static BuildTarget default_build_target = { .emit_stdlib = EMIT_STDLIB_NOT_SET, .linker_type = LINKER_TYPE_NOT_SET, .single_module = SINGLE_MODULE_NOT_SET, + .unroll_loops = UNROLL_LOOPS_NOT_SET, + .merge_functions = MERGE_FUNCTIONS_NOT_SET, + .slp_vectorization = VECTORIZATION_NOT_SET, + .loop_vectorization = VECTORIZATION_NOT_SET, .strip_unused = STRIP_UNUSED_NOT_SET, .symtab_size = DEFAULT_SYMTAB_SIZE, .reloc_model = RELOC_DEFAULT, diff --git a/src/build/build_options.c b/src/build/build_options.c index 1d7308251..1ebeed223 100644 --- a/src/build/build_options.c +++ b/src/build/build_options.c @@ -1139,6 +1139,10 @@ BuildOptions parse_arguments(int argc, const char *argv[]) .linker_type = LINKER_TYPE_NOT_SET, .strip_unused = STRIP_UNUSED_NOT_SET, .single_module = SINGLE_MODULE_NOT_SET, + .unroll_loops = UNROLL_LOOPS_NOT_SET, + .merge_functions = MERGE_FUNCTIONS_NOT_SET, + .slp_vectorization = VECTORIZATION_NOT_SET, + .loop_vectorization = VECTORIZATION_NOT_SET, .files = NULL, .build_dir = NULL, .output_dir = NULL, diff --git a/src/build/builder.c b/src/build/builder.c index ab984ba3f..d6d9167a3 100644 --- a/src/build/builder.c +++ b/src/build/builder.c @@ -92,6 +92,7 @@ bool command_accepts_files(CompilerCommand command) UNREACHABLE } + void update_build_target_with_opt_level(BuildTarget *target, OptimizationSetting level) { if (level == OPT_SETTING_NOT_SET) level = OPT_SETTING_O0; @@ -100,6 +101,10 @@ void update_build_target_with_opt_level(BuildTarget *target, OptimizationSetting DebugInfo debug = DEBUG_INFO_FULL; SafetyLevel safety_level = SAFETY_ON; PanicLevel panic_level = PANIC_ON; + UnrollLoops unroll_loops = UNROLL_LOOPS_OFF; + AutoVectorization vectorization = VECTORIZATION_OFF; + AutoVectorization slp_vectorization = VECTORIZATION_OFF; + MergeFunctions merge_functions = MERGE_FUNCTIONS_OFF; bool single_module = false; FpOpt fp_opt = FP_STRICT; switch (level) @@ -108,43 +113,68 @@ void update_build_target_with_opt_level(BuildTarget *target, OptimizationSetting break; case OPT_SETTING_O1: optlevel = OPTIMIZATION_MORE; + slp_vectorization = VECTORIZATION_ON; + unroll_loops = UNROLL_LOOPS_ON; + vectorization = VECTORIZATION_ON; break; case OPT_SETTING_O2: + merge_functions = MERGE_FUNCTIONS_ON; optlevel = OPTIMIZATION_MORE; safety_level = SAFETY_OFF; + slp_vectorization = VECTORIZATION_ON; + unroll_loops = UNROLL_LOOPS_ON; + vectorization = VECTORIZATION_ON; break; case OPT_SETTING_O3: + merge_functions = MERGE_FUNCTIONS_ON; optlevel = OPTIMIZATION_MORE; safety_level = SAFETY_OFF; single_module = true; + slp_vectorization = VECTORIZATION_ON; + unroll_loops = UNROLL_LOOPS_ON; + vectorization = VECTORIZATION_ON; break; case OPT_SETTING_O4: - optlevel = OPTIMIZATION_AGGRESSIVE; - safety_level = SAFETY_OFF; - panic_level = PANIC_OFF; fp_opt = FP_RELAXED; + merge_functions = MERGE_FUNCTIONS_ON; + optlevel = OPTIMIZATION_AGGRESSIVE; + panic_level = PANIC_OFF; + safety_level = SAFETY_OFF; single_module = true; + slp_vectorization = VECTORIZATION_ON; + unroll_loops = UNROLL_LOOPS_ON; + vectorization = VECTORIZATION_ON; break; case OPT_SETTING_O5: - optlevel = OPTIMIZATION_AGGRESSIVE; - safety_level = SAFETY_OFF; - panic_level = PANIC_OFF; fp_opt = FP_FAST; + merge_functions = MERGE_FUNCTIONS_ON; + optlevel = OPTIMIZATION_AGGRESSIVE; + panic_level = PANIC_OFF; + safety_level = SAFETY_OFF; single_module = true; + slp_vectorization = VECTORIZATION_ON; + unroll_loops = UNROLL_LOOPS_ON; + vectorization = VECTORIZATION_ON; break; case OPT_SETTING_OSMALL: + merge_functions = MERGE_FUNCTIONS_ON; optlevel = OPTIMIZATION_MORE; optsize = SIZE_OPTIMIZATION_SMALL; - safety_level = SAFETY_OFF; panic_level = PANIC_OFF; + safety_level = SAFETY_OFF; + slp_vectorization = VECTORIZATION_ON; + vectorization = VECTORIZATION_ON; break; case OPT_SETTING_OTINY: + debug = DEBUG_INFO_NONE; + merge_functions = MERGE_FUNCTIONS_ON; optlevel = OPTIMIZATION_MORE; optsize = SIZE_OPTIMIZATION_TINY; - safety_level = SAFETY_OFF; panic_level = PANIC_OFF; + safety_level = SAFETY_OFF; single_module = true; - debug = DEBUG_INFO_NONE; + slp_vectorization = VECTORIZATION_ON; + vectorization = VECTORIZATION_OFF; break; case OPT_SETTING_NOT_SET: default: @@ -157,6 +187,10 @@ void update_build_target_with_opt_level(BuildTarget *target, OptimizationSetting if (target->debug_info == DEBUG_INFO_NOT_SET) target->debug_info = debug; if (target->feature.fp_math == FP_DEFAULT) target->feature.fp_math = fp_opt; if (target->single_module == SINGLE_MODULE_NOT_SET && single_module) target->single_module = SINGLE_MODULE_ON; + if (target->unroll_loops == UNROLL_LOOPS_NOT_SET) target->unroll_loops = unroll_loops; + if (target->merge_functions == MERGE_FUNCTIONS_NOT_SET) target->merge_functions = merge_functions; + if (target->slp_vectorization == VECTORIZATION_NOT_SET) target->slp_vectorization = slp_vectorization; + if (target->loop_vectorization == VECTORIZATION_NOT_SET) target->loop_vectorization = vectorization; } static void update_build_target_from_options(BuildTarget *target, BuildOptions *options) { @@ -234,46 +268,23 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions * target->read_stdin = options->read_stdin; - if (options->cc) target->cc = options->cc; - if (options->optlevel != OPTIMIZATION_NOT_SET) - { - target->optlevel = options->optlevel; - } - if (options->optsize != SIZE_OPTIMIZATION_NOT_SET) - { - target->optsize = options->optsize; - } - if (options->single_module != SINGLE_MODULE_NOT_SET) - { - target->single_module = options->single_module; - } - if (options->safety_level != SAFETY_NOT_SET) - { - target->feature.safe_mode = options->safety_level; - } - if (options->panic_level != PANIC_NOT_SET) - { - target->feature.panic_level = options->panic_level; - } + if (options->optlevel != OPTIMIZATION_NOT_SET) target->optlevel = options->optlevel; + if (options->optsize != SIZE_OPTIMIZATION_NOT_SET) target->optsize = options->optsize; + if (options->single_module != SINGLE_MODULE_NOT_SET) target->single_module = options->single_module; + if (options->unroll_loops != UNROLL_LOOPS_NOT_SET) target->unroll_loops = options->unroll_loops; + if (options->merge_functions != MERGE_FUNCTIONS_NOT_SET) target->merge_functions = options->merge_functions; + if (options->loop_vectorization != VECTORIZATION_NOT_SET) target->loop_vectorization = options->loop_vectorization; + if (options->slp_vectorization != VECTORIZATION_NOT_SET) target->slp_vectorization = options->slp_vectorization; + if (options->safety_level != SAFETY_NOT_SET) target->feature.safe_mode = options->safety_level; + if (options->panic_level != PANIC_NOT_SET) target->feature.panic_level = options->panic_level; if (options->strip_unused != STRIP_UNUSED_NOT_SET) target->strip_unused = options->strip_unused; - - if (options->memory_environment != MEMORY_ENV_NOT_SET) - { - target->memory_environment = options->memory_environment; - } - if (options->debug_info_override != DEBUG_INFO_NOT_SET) - { - target->debug_info = options->debug_info_override; - } - if (options->arch_os_target_override != ARCH_OS_TARGET_DEFAULT) - { - target->arch_os_target = options->arch_os_target_override; - } - target->print_linking = options->print_linking; + if (options->memory_environment != MEMORY_ENV_NOT_SET) target->memory_environment = options->memory_environment; + if (options->debug_info_override != DEBUG_INFO_NOT_SET) target->debug_info = options->debug_info_override; + if (options->arch_os_target_override != ARCH_OS_TARGET_DEFAULT) target->arch_os_target = options->arch_os_target_override; if (options->reloc_model != RELOC_DEFAULT) target->reloc_model = options->reloc_model; - if (options->symtab_size) target->symtab_size = options->symtab_size; + target->print_linking = options->print_linking; for (int i = 0; i < options->linker_arg_count; i++) { diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index 1063ceb1e..270c3e6d2 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -8,6 +8,7 @@ #if PLATFORM_POSIX #include #endif +#include "c3_llvm.h" #define MAX_OUTPUT_FILES 1000000 #define MAX_MODULES 100000 @@ -29,7 +30,6 @@ double compiler_link_time; const char* c3_suffix_list[3] = { ".c3", ".c3t", ".c3i" }; -extern int llvm_version_major; void compiler_init(const char *std_lib_dir) { diff --git a/src/compiler/linker.c b/src/compiler/linker.c index 3a20cf213..0260c39d7 100644 --- a/src/compiler/linker.c +++ b/src/compiler/linker.c @@ -1,27 +1,10 @@ #include "compiler_internal.h" +#include "c3_llvm.h" #if PLATFORM_POSIX #include #endif -// Copied from wrapper.cpp -typedef enum -{ - AR_GNU, - AR_DARWIN, - AR_DARWIN64, - AR_BSD, - AR_GNU64, - AR_COFF, -} ArFormat; - -extern bool llvm_link_elf(const char **args, int arg_count, const char **error_string); -extern bool llvm_link_macho(const char **args, int arg_count, const char **error_string); -extern bool llvm_link_coff(const char **args, int arg_count, const char **error_string); -extern bool llvm_link_wasm(const char **args, int arg_count, const char **error_string); -extern UNUSED bool llvm_link_mingw(const char **args, int arg_count, const char **error_string); -extern bool llvm_ar(const char *out_name, const char **args, size_t count, int ArFormat); - typedef enum { diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 4711060d7..aa08d6f1e 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -4,7 +4,7 @@ #include "llvm_codegen_internal.h" #include "compiler_tests/benchmark.h" - +#include "c3_llvm.h" #include #include #include @@ -83,7 +83,7 @@ static void gencontext_destroy(GenContext *context) LLVMBuilderRef llvm_create_builder(GenContext *c) { LLVMBuilderRef builder = LLVMCreateBuilderInContext(c->context); - LLVMBuilderSetFastMathFlags(builder, active_target.feature.fp_math); + LLVMBuilderSetFastMathFlags(builder, (FastMathOption)active_target.feature.fp_math); return builder; } @@ -946,45 +946,53 @@ static void llvm_emit_type_decls(GenContext *context, Decl *decl) static inline void llvm_optimize(GenContext *c) { - LLVMPassBuilderOptionsRef options = LLVMCreatePassBuilderOptions(); - LLVMPassBuilderOptionsSetVerifyEach(options, active_target.emit_llvm); + bool should_debug = false; #ifndef NDEBUG - LLVMPassBuilderOptionsSetDebugLogging(options, debug_log); + should_debug = debug_log; #endif - const char *passes = NULL; + LLVMOptLevels level; switch (active_target.optsize) { case SIZE_OPTIMIZATION_SMALL: - passes = "default"; + level = LLVM_Os; break; case SIZE_OPTIMIZATION_TINY: - passes = "default"; + level = LLVM_Oz; break; default: + switch (active_target.optlevel) + { + case OPTIMIZATION_NONE: + case OPTIMIZATION_NOT_SET: + level = LLVM_O0; + break; + case OPTIMIZATION_LESS: + level = LLVM_O1; + break; + case OPTIMIZATION_MORE: + level = LLVM_O2; + break; + case OPTIMIZATION_AGGRESSIVE: + level = LLVM_O3; + break; + } break; } - switch (active_target.optlevel) + LLVMPasses passes = { + .opt_level = level, + .should_verify = active_target.emit_llvm, + .should_debug = should_debug, + .is_kernel = active_target.kernel_build, + .opt.vectorize_loops = active_target.loop_vectorization == VECTORIZATION_ON, + .opt.slp_vectorize = active_target.slp_vectorization == VECTORIZATION_ON, + .opt.unroll_loops = active_target.unroll_loops == UNROLL_LOOPS_ON, + .opt.interleave_loops = active_target.unroll_loops == UNROLL_LOOPS_ON, + .opt.merge_functions = active_target.merge_functions == MERGE_FUNCTIONS_ON + }; + if (!llvm_run_passes(c->module, c->machine, &passes)) { - case OPTIMIZATION_NONE: - case OPTIMIZATION_NOT_SET: - passes = "default"; - break; - case OPTIMIZATION_LESS: - if (!passes) passes = "default"; - break; - case OPTIMIZATION_MORE: - if (!passes) passes = "default"; - break; - case OPTIMIZATION_AGGRESSIVE: - if (!passes) passes = "default"; - break; + error_exit("Failed to run passes."); } - LLVMErrorRef err = LLVMRunPasses(c->module, passes, c->machine, options); - if (err) - { - error_exit("An error occurred: %s.", LLVMGetErrorMessage(err)); - } - LLVMDisposePassBuilderOptions(options); } const char *llvm_codegen(void *context) diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index 5da9aa019..6cdbda8c6 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -13,7 +13,7 @@ #include #include #include "dwarf.h" - +#include "c3_llvm.h" #define SLICE_MAX_UNROLL 4 extern const char *varargslots_name; @@ -293,10 +293,6 @@ void gencontext_init_file_emit(GenContext *c, CompilationUnit *unit); void gencontext_end_file_emit(GenContext *c, CompilationUnit *ast); void gencontext_end_module(GenContext *context); -// Patched functions -LLVMValueRef LLVMConstBswap(LLVMValueRef ConstantVal); -void LLVMBuilderSetFastMathFlags(LLVMBuilderRef Builder, FpOpt option); -void LLVMSetDSOLocal(LLVMValueRef Global, bool value); #ifndef LLVMCreateTypeAttribute LLVMAttributeRef LLVMCreateTypeAttribute(LLVMContextRef C, unsigned KindID, diff --git a/src/compiler/target.c b/src/compiler/target.c index bb70236c8..05ddf22a9 100644 --- a/src/compiler/target.c +++ b/src/compiler/target.c @@ -2,8 +2,8 @@ #include #include #include "compiler_internal.h" +#include "c3_llvm.h" -extern void LLVMSetTargetMachineUseInitArray(LLVMTargetMachineRef ref, bool use_init_array); static bool x64features_contains(X86Features *cpu_features, X86Feature feature); static ObjectFormatType object_format_from_os(OsType os, ArchType arch_type); static unsigned arch_pointer_bit_width(OsType os, ArchType arch); @@ -1798,10 +1798,11 @@ void *llvm_target_machine_create(void) } INFO_LOG("CPU: %s", platform_target.cpu); INFO_LOG("Features: %s", platform_target.features); + LLVMCodeModel model = active_target.kernel_build ? LLVMCodeModelKernel : LLVMCodeModelDefault; void *result = LLVMCreateTargetMachine(target, platform_target.target_triple, platform_target.cpu ? platform_target.cpu : "", platform_target.features ? platform_target.features : "", (LLVMCodeGenOptLevel)platform_target.llvm_opt_level, - reloc_mode, LLVMCodeModelDefault); + reloc_mode, model); LLVMSetTargetMachineUseInitArray(result, true); if (!result) error_exit("Failed to create target machine."); LLVMSetTargetMachineAsmVerbosity(result, 1); diff --git a/src/version.h b/src/version.h index 688ec2f1b..02392bec5 100644 --- a/src/version.h +++ b/src/version.h @@ -1,2 +1,2 @@ -#define COMPILER_VERSION "0.6.1" +#define COMPILER_VERSION "0.6.2" #define PRERELEASE 1 \ No newline at end of file diff --git a/wrapper/include/c3_llvm.h b/wrapper/include/c3_llvm.h new file mode 100644 index 000000000..377f8b160 --- /dev/null +++ b/wrapper/include/c3_llvm.h @@ -0,0 +1,84 @@ +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern int llvm_version_major; + +typedef enum +{ + DEFAULT = -1, + STRICT, + RELAXED, + FAST +} FastMathOption; + +typedef enum +{ + AR_GNU, + AR_DARWIN, + AR_DARWIN64, + AR_BSD, + AR_GNU64, + AR_COFF, +} ArFormat; + +typedef enum +{ + LLVM_O0, + LLVM_O1, + LLVM_O2, + LLVM_O3, + LLVM_Os, + LLVM_Oz +} LLVMOptLevels; + +typedef struct +{ + bool should_debug; + bool should_verify; + LLVMOptLevels opt_level; + bool is_kernel; + struct + { + bool recover; + bool mem_sanitize; + bool mem_track_origins; + bool mem_retval; + bool thread_sanitize; + bool address_sanitize; + bool asan_use_globals_gc; + bool asan_use_odr_indicator; + bool asan_use_after_scope; + bool asan_use_after_return; + bool asan_use_global_dstor; + bool hwaddress_sanitize; + } sanitizer; + struct + { + bool unroll_loops; + bool interleave_loops; + bool vectorize_loops; + bool slp_vectorize; + bool merge_functions; + } opt; +} LLVMPasses; + +bool llvm_run_passes(LLVMModuleRef m, LLVMTargetMachineRef tm, LLVMPasses *passes); +bool llvm_link_elf(const char **args, int arg_count, const char **error_string); +bool llvm_link_macho(const char **args, int arg_count, const char **error_string); +bool llvm_link_coff(const char **args, int arg_count, const char **error_string); +bool llvm_link_wasm(const char **args, int arg_count, const char **error_string); +bool llvm_link_mingw(const char **args, int arg_count, const char **error_string); +bool llvm_ar(const char *out_name, const char **args, size_t count, int ArFormat); + +LLVMValueRef LLVMConstBswap(LLVMValueRef ConstantVal); +void LLVMBuilderSetFastMathFlags(LLVMBuilderRef Builder, FastMathOption option); +void LLVMSetDSOLocal(LLVMValueRef Global, bool value); +void LLVMSetTargetMachineUseInitArray(LLVMTargetMachineRef ref, bool use_init_array); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/wrapper/src/wrapper.cpp b/wrapper/src/wrapper.cpp index 61b159c3c..be9e62a15 100644 --- a/wrapper/src/wrapper.cpp +++ b/wrapper/src/wrapper.cpp @@ -1,14 +1,32 @@ // For hacking the C API +#include +#include "c3_llvm.h" #include "llvm/IR/IRBuilder.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ArchiveWriter.h" #include "llvm/Object/IRObjectFile.h" #include "llvm/Object/SymbolicFile.h" -#include "llvm-c/TargetMachine.h" #include "llvm/Target/TargetMachine.h" #include "lld/Common/CommonLinkerContext.h" #include "llvm/IR/GlobalValue.h" +#include "llvm-c/Transforms/PassBuilder.h" +#include "llvm-c/TargetMachine.h" +#include "llvm-c/Target.h" +#include "llvm/IR/Verifier.h" +#include "llvm/Passes/PassBuilder.h" +#include "llvm/Passes/StandardInstrumentations.h" +#include "llvm/Support/CBindingWrapping.h" +#include "llvm/Transforms/Instrumentation/MemorySanitizer.h" +#include "llvm/Transforms/Instrumentation/AddressSanitizer.h" +#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h" +#include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h" +#include "llvm/Transforms/Scalar/EarlyCSE.h" +#include "llvm/Transforms/Scalar/GVN.h" +#include "llvm/Transforms/Scalar/JumpThreading.h" +#include "llvm/Transforms/InstCombine/InstCombine.h" +#include "llvm/TargetParser/Triple.h" +#include "llvm/Analysis/GlobalsModRef.h" #define LINK_SIG \ bool link(llvm::ArrayRef args, llvm::raw_ostream &stdoutOS, \ @@ -51,23 +69,6 @@ typedef enum MINGW } ObjFormat; -typedef enum -{ - AR_GNU, - AR_DARWIN, - AR_DARWIN64, - AR_BSD, - AR_GNU64, - AR_COFF, -} ArFormat; - -typedef enum -{ - STRICT, - RELAXED, - FAST -} FastMathOption; - static bool llvm_link(ObjFormat format, const char **args, int arg_count, const char** error_string) { std::vector arg_vector = std::vector(); @@ -127,113 +128,216 @@ static bool llvm_link(ObjFormat format, const char **args, int arg_count, const return success; } - extern "C" { - bool llvm_ar(const char *out_name, const char **args, size_t count, int ArFormat) + +bool llvm_run_passes(LLVMModuleRef m, LLVMTargetMachineRef tm, + LLVMPasses *passes) +{ + llvm::TargetMachine *Machine = reinterpret_cast(tm); + llvm::Module *Mod = llvm::unwrap(m); + llvm::PassInstrumentationCallbacks PIC; + llvm::PipelineTuningOptions PTO{}; + PTO.LoopUnrolling = passes->opt.unroll_loops; + PTO.LoopInterleaving = passes->opt.interleave_loops; + PTO.LoopVectorization = passes->opt.vectorize_loops; + PTO.SLPVectorization = passes->opt.slp_vectorize; + PTO.MergeFunctions = passes->opt.merge_functions; + PTO.CallGraphProfile = true; // We always use integrated ASM + PTO.UnifiedLTO = false; + + llvm::PassBuilder PB(Machine, PTO, std::nullopt, &PIC); + + llvm::LoopAnalysisManager LAM; + llvm::FunctionAnalysisManager FAM; + llvm::CGSCCAnalysisManager CGAM; + llvm::ModuleAnalysisManager MAM; + PB.registerLoopAnalyses(LAM); + PB.registerFunctionAnalyses(FAM); + PB.registerCGSCCAnalyses(CGAM); + PB.registerModuleAnalyses(MAM); + PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); + + llvm::StandardInstrumentations SI(Mod->getContext(), passes->should_debug, passes->should_verify); + SI.registerCallbacks(PIC, &MAM); + + // Assignment tracking pass is not enabled, but could be added + // Skipping TargetLibraryAnalysis + + llvm::OptimizationLevel level; + switch (passes->opt_level) { - llvm::object::Archive::Kind kind; - switch (ArFormat) + case LLVM_O0: + level = llvm::OptimizationLevel::O0; + break; + case LLVM_O1: + level = llvm::OptimizationLevel::O1; + break; + case LLVM_O2: + level = llvm::OptimizationLevel::O2; + break; + case LLVM_O3: + level = llvm::OptimizationLevel::O3; + break; + case LLVM_Os: + level = llvm::OptimizationLevel::Os; + break; + case LLVM_Oz: + level = llvm::OptimizationLevel::Oz; + break; + default: + exit(-1); + } + llvm::ModulePassManager MPM = PB.buildPerModuleDefaultPipeline(level, false); + + if (passes->should_verify) + { + MPM.addPass(llvm::VerifierPass()); + } + if (passes->sanitizer.mem_sanitize) + { + llvm::MemorySanitizerOptions options(passes->sanitizer.mem_track_origins, + passes->sanitizer.recover, + passes->is_kernel, + passes->sanitizer.mem_retval); + + MPM.addPass(llvm::MemorySanitizerPass(options)); + if (passes->opt_level != LLVM_O0) { - case AR_BSD: - kind = llvm::object::Archive::K_BSD; - break; - case AR_DARWIN: - kind = llvm::object::Archive::K_DARWIN; - break; - case AR_DARWIN64: - kind = llvm::object::Archive::K_DARWIN64; - break; - case AR_GNU: - kind = llvm::object::Archive::K_GNU; - break; - case AR_GNU64: - kind = llvm::object::Archive::K_GNU64; - break; - case AR_COFF: - kind = llvm::object::Archive::K_GNU; - break; - default: - assert(false); + // Add another function pass like Clang does. + MPM.addPass(llvm::RequireAnalysisPass()); + llvm::FunctionPassManager FPM; + FPM.addPass(llvm::EarlyCSEPass(true /* Enable mem-ssa. */)); + FPM.addPass(llvm::InstCombinePass()); + FPM.addPass(llvm::JumpThreadingPass()); + FPM.addPass(llvm::GVNPass()); + FPM.addPass(llvm::InstCombinePass()); + MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); } - bool is_win = ArFormat == AR_COFF; - std::vector new_members {}; - for (size_t i = 0; i < count; i++) + } + if (passes->sanitizer.thread_sanitize) + { + MPM.addPass(llvm::ModuleThreadSanitizerPass()); + MPM.addPass(createModuleToFunctionPassAdaptor(llvm::ThreadSanitizerPass())); + } + + if (passes->sanitizer.address_sanitize) + { + llvm::AddressSanitizerOptions Opts; + bool use_globals_gc = false; // No need to add this yet. + Opts.CompileKernel = passes->is_kernel; + Opts.Recover = passes->sanitizer.recover; + Opts.UseAfterScope = passes->sanitizer.asan_use_after_scope; + Opts.UseAfterReturn = passes->sanitizer.asan_use_after_return + ? llvm::AsanDetectStackUseAfterReturnMode::Always + : llvm::AsanDetectStackUseAfterReturnMode::Never; + bool is_windows = Machine->getTargetTriple().isOSWindows(); + MPM.addPass(llvm::AddressSanitizerPass(Opts, + use_globals_gc, + !is_windows, + passes->sanitizer.asan_use_global_dstor + ? llvm::AsanDtorKind::Global + : llvm::AsanDtorKind::None)); + } + if (passes->sanitizer.hwaddress_sanitize) + { + MPM.addPass(llvm::HWAddressSanitizerPass({ + passes->is_kernel, + passes->sanitizer.recover, + passes->opt_level == LLVM_O0 + })); + } + // MPM.addPass(DataFlowSanitizerPass(LangOpts.NoSanitizeFiles)); + + MPM.run(*Mod, MAM); + return true; +} + +bool llvm_ar(const char *out_name, const char **args, size_t count, int ArFormat) +{ + llvm::object::Archive::Kind kind; + switch (ArFormat) + { + case AR_BSD: + kind = llvm::object::Archive::K_BSD; + break; + case AR_DARWIN: + kind = llvm::object::Archive::K_DARWIN; + break; + case AR_DARWIN64: + kind = llvm::object::Archive::K_DARWIN64; + break; + case AR_GNU: + kind = llvm::object::Archive::K_GNU; + break; + case AR_GNU64: + kind = llvm::object::Archive::K_GNU64; + break; + case AR_COFF: + kind = llvm::object::Archive::K_GNU; + break; + default: + assert(false); + } + bool is_win = ArFormat == AR_COFF; + std::vector new_members{}; + for (size_t i = 0; i < count; i++) + { + auto member = llvm::NewArchiveMember::getFile(std::string(args[i]), false); + if (!member) return false; + if (is_win) { - auto member = llvm::NewArchiveMember::getFile(std::string(args[i]), false); - if (!member) return false; - if (is_win) - { - // Needs relative paths. - const char *rel_name = strrchr(args[i], '/'); - if (rel_name) member->MemberName = rel_name + 1; - } - new_members.push_back(std::move(*member)); + // Needs relative paths. + const char *rel_name = strrchr(args[i], '/'); + if (rel_name) member->MemberName = rel_name + 1; } + new_members.push_back(std::move(*member)); + } #if LLVM_VERSION_MAJOR > 17 - return !llvm::writeArchive(std::string(out_name), std::move(new_members), llvm::SymtabWritingMode::NormalSymtab, kind, true, false, nullptr); + return !llvm::writeArchive(std::string(out_name), std::move(new_members), llvm::SymtabWritingMode::NormalSymtab, kind, true, false, nullptr); #else - return !llvm::writeArchive(std::string(out_name), std::move(new_members), true, kind, true, false, nullptr); + return !llvm::writeArchive(std::string(out_name), std::move(new_members), true, kind, true, false, nullptr); #endif - } +} - int llvm_version_major = LLVM_VERSION_MAJOR; +int llvm_version_major = LLVM_VERSION_MAJOR; - void LLVMSetTargetMachineUseInitArray(LLVMTargetMachineRef ref, bool use_init_array) +void LLVMSetTargetMachineUseInitArray(LLVMTargetMachineRef ref, bool use_init_array) +{ + auto machine = reinterpret_cast(ref); + machine->Options.UseInitArray = use_init_array; +} +void LLVMSetDSOLocal(LLVMValueRef Global, bool value) +{ + llvm::unwrap(Global)->setDSOLocal(value); +} + +void LLVMBuilderSetFastMathFlags(LLVMBuilderRef Builder, FastMathOption option) +{ + llvm::FastMathFlags math_flags {}; + switch (option) { - auto machine = reinterpret_cast(ref); - machine->Options.UseInitArray = use_init_array; - } - void LLVMSetDSOLocal(LLVMValueRef Global, bool value) - { - llvm::unwrap(Global)->setDSOLocal(value); + case RELAXED: + math_flags.setAllowReassoc(true); + math_flags.setAllowReciprocal(true); + math_flags.setAllowContract(true); + break; + case FAST: + math_flags.setFast(true); + break; + case STRICT: + default: + return; } + llvm::unwrap(Builder)->setFastMathFlags(math_flags); +} - void LLVMBuilderSetFastMathFlags(LLVMBuilderRef Builder, FastMathOption option) - { - llvm::FastMathFlags math_flags {}; - switch (option) - { - case RELAXED: - math_flags.setAllowReassoc(true); - math_flags.setAllowReciprocal(true); - math_flags.setAllowContract(true); - break; - case FAST: - math_flags.setFast(true); - break; - case STRICT: - default: - return; - } - llvm::unwrap(Builder)->setFastMathFlags(math_flags); - } - - LLVMValueRef LLVMConstBswap(LLVMValueRef ConstantVal) - { - llvm::Constant *Val = llvm::unwrap(ConstantVal); - const llvm::APInt& i = Val->getUniqueInteger(); - return llvm::wrap(llvm::Constant::getIntegerValue(Val->getType(), i.byteSwap())); - } -#if LLVM_VERSION_MAJOR < 14 - LLVMValueRef LLVMConstGEP2(LLVMTypeRef Ty, LLVMValueRef ConstantVal, - LLVMValueRef *ConstantIndices, unsigned NumIndices) { - llvm::ArrayRef IdxList(llvm::unwrap(ConstantIndices, NumIndices), - NumIndices); - llvm::Constant *Val = llvm::unwrap(ConstantVal); - return wrap(llvm::ConstantExpr::getGetElementPtr(llvm::unwrap(Ty), Val, IdxList)); - } - - LLVMValueRef LLVMConstInBoundsGEP2(LLVMTypeRef Ty, - LLVMValueRef ConstantVal, - LLVMValueRef *ConstantIndices, - unsigned NumIndices) { - llvm::ArrayRef IdxList(llvm::unwrap(ConstantIndices, NumIndices), - NumIndices); - llvm::Constant *Val = llvm::unwrap(ConstantVal); - return wrap(llvm::ConstantExpr::getInBoundsGetElementPtr(llvm::unwrap(Ty), Val, IdxList)); - } -#endif +LLVMValueRef LLVMConstBswap(LLVMValueRef ConstantVal) +{ + llvm::Constant *Val = llvm::unwrap(ConstantVal); + const llvm::APInt &i = Val->getUniqueInteger(); + return llvm::wrap(llvm::Constant::getIntegerValue(Val->getType(), i.byteSwap())); +} bool llvm_link_elf(const char **args, int arg_count, const char** error_string) { @@ -261,5 +365,4 @@ bool llvm_link_mingw(const char **args, int arg_count, const char** error_string } - }