From 1bf3bb51bf4a00ce52b1d84f22519fe4504e6035 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Wed, 10 Aug 2022 11:41:40 +0200 Subject: [PATCH] Add asm output option using --emit-asm. --- src/build/build_options.c | 13 ++++++++++ src/build/build_options.h | 4 +++ src/build/builder.c | 4 +++ src/compiler/compiler.c | 9 ++++++- src/compiler/llvm_codegen.c | 37 +++++++++++++++++++++++++--- src/compiler/llvm_codegen_internal.h | 1 + src/compiler/llvm_codegen_module.c | 5 ++++ src/version.h | 2 +- 8 files changed, 70 insertions(+), 5 deletions(-) diff --git a/src/build/build_options.c b/src/build/build_options.c index 2492f469b..e42dd8227 100644 --- a/src/build/build_options.c +++ b/src/build/build_options.c @@ -95,6 +95,8 @@ static void usage(void) OUTPUT(" --obj-out - Override object file output directory."); OUTPUT(" --llvm-out - Override llvm output directory for '--emit-llvm'."); OUTPUT(" --emit-llvm - Emit LLVM IR as a .ll file per module."); + OUTPUT(" --asm-out - Override llvm output directory for '--emit-asm'."); + OUTPUT(" --emit-asm - Emit asm as a .s file per module."); OUTPUT(" --target - Compile for a particular architecture + OS target."); OUTPUT(" --threads - Set the number of threads to use for compilation."); OUTPUT(" --safe - Set mode to 'safe', generating runtime traps on overflows and contract violations."); @@ -575,6 +577,11 @@ static void parse_option(BuildOptions *options) options->emit_llvm = true; return; } + if (match_longopt("emit-asm")) + { + options->emit_asm = true; + return; + } if (match_longopt("cc")) { if (at_end() || next_is_opt()) error_exit("error: --cc needs a compiler name."); @@ -633,6 +640,12 @@ static void parse_option(BuildOptions *options) options->llvm_out = next_arg(); return; } + if (match_longopt("asm-out")) + { + if (at_end() || next_is_opt()) error_exit("error: --asm-out needs a directory."); + options->asm_out = next_arg(); + return; + } if (match_longopt("lib")) { if (at_end() || next_is_opt()) error_exit("error: --lib needs a name."); diff --git a/src/build/build_options.h b/src/build/build_options.h index 11e054541..ea6a7d0bc 100644 --- a/src/build/build_options.h +++ b/src/build/build_options.h @@ -250,6 +250,7 @@ typedef struct BuildOptions_ ArchOsTarget arch_os_target_override; int safe_mode; bool emit_llvm; + bool emit_asm; bool emit_bitcode; bool test_mode; bool no_stdlib; @@ -258,6 +259,7 @@ typedef struct BuildOptions_ const char *cc; const char *build_dir; const char *llvm_out; + const char *asm_out; const char *obj_out; RelocModel reloc_model; X86VectorCapability x86_vector_capability; @@ -315,6 +317,7 @@ typedef struct const char *build_dir; const char *object_file_dir; const char *llvm_file_dir; + const char *asm_file_dir; bool run_after_compile : 1; bool test_output : 1; bool output_headers : 1; @@ -323,6 +326,7 @@ typedef struct bool parse_only : 1; bool check_only : 1; bool emit_llvm : 1; + bool emit_asm : 1; bool no_stdlib : 1; bool emit_object_files : 1; bool no_link : 1; diff --git a/src/build/builder.c b/src/build/builder.c index 05f01809f..34e83b597 100644 --- a/src/build/builder.c +++ b/src/build/builder.c @@ -178,6 +178,7 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions * } target->no_stdlib = options->no_stdlib; target->emit_llvm = options->emit_llvm; + target->emit_asm = options->emit_asm; target->force_linker = options->force_linker; target->panicfn = options->panicfn; if (options->macos.sdk) target->macos.sdk = options->macos.sdk; @@ -192,12 +193,14 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions * target->build_dir = options->build_dir ? options->build_dir : NULL; target->object_file_dir = options->obj_out ? options->obj_out : target->build_dir; target->llvm_file_dir = options->llvm_out ? options->llvm_out : target->build_dir; + target->asm_file_dir = options->asm_out ? options->asm_out : target->build_dir; } else { target->build_dir = options->build_dir ? options->build_dir : "build"; target->object_file_dir = options->obj_out ? options->obj_out : file_append_path(target->build_dir, "tmp"); target->llvm_file_dir = options->llvm_out ? options->llvm_out : file_append_path(target->build_dir, "llvm_ir"); + target->asm_file_dir = options->asm_out ? options->asm_out : file_append_path(target->build_dir, "asm"); } switch (options->compile_option) { @@ -227,6 +230,7 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions * { target->test_output = true; target->emit_llvm = false; + target->emit_asm = false; target->emit_object_files = false; } for (int i = 0; i < options->lib_dir_count; i++) diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index 9afe6051a..850dec986 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -237,7 +237,7 @@ void compiler_compile(void) void **gen_contexts = VECNEW(void*, module_count); void (*task)(void *); - if (active_target.llvm_file_dir || active_target.emit_object_files) + if (active_target.asm_file_dir || active_target.llvm_file_dir || active_target.emit_object_files) { if (active_target.build_dir && !file_exists(active_target.build_dir) && !dir_make(active_target.build_dir)) { @@ -251,6 +251,13 @@ void compiler_compile(void) error_exit("Failed to create output directory '%s'.", active_target.llvm_file_dir); } } + if (active_target.asm_file_dir && active_target.emit_asm) + { + if (!file_exists(active_target.asm_file_dir) && !dir_make(active_target.asm_file_dir)) + { + error_exit("Failed to create output directory '%s'.", active_target.asm_file_dir); + } + } if (active_target.object_file_dir && active_target.emit_object_files) { if (!file_exists(active_target.object_file_dir) && !dir_make(active_target.object_file_dir)) diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 89e2fd688..c12e603fc 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -445,7 +445,33 @@ static void gencontext_verify_ir(GenContext *context) } -void gencontext_emit_object_file(GenContext *context) +static void gencontext_emit_object_file(GenContext *context) +{ + char *err = ""; + DEBUG_LOG("Target: %s", platform_target.target_triple); + LLVMSetTarget(context->module, platform_target.target_triple); + char *layout = LLVMCopyStringRepOfTargetData(context->target_data); + LLVMSetDataLayout(context->module, layout); + LLVMDisposeMessage(layout); + + if (context->asm_filename) + { + // Generate .o or .obj file + if (LLVMTargetMachineEmitToFile(context->machine, context->module, (char *)context->asm_filename, LLVMAssemblyFile, &err)) + { + error_exit("Could not emit asm file: %s", err); + } + } + + // Generate .o or .obj file + if (LLVMTargetMachineEmitToFile(context->machine, context->module, (char *)context->object_filename, LLVMObjectFile, &err)) + { + error_exit("Could not emit object file: %s", err); + } + +} + +static void llvm_emit_asm_file(GenContext *context) { char *err = ""; DEBUG_LOG("Target: %s", platform_target.target_triple); @@ -455,9 +481,9 @@ void gencontext_emit_object_file(GenContext *context) LLVMDisposeMessage(layout); // Generate .o or .obj file - if (LLVMTargetMachineEmitToFile(context->machine, context->module, (char *)context->object_filename, LLVMObjectFile, &err)) + if (LLVMTargetMachineEmitToFile(context->machine, context->module, (char *)context->asm_filename, LLVMAssemblyFile, &err)) { - error_exit("Could not emit object file: %s", err); + error_exit("Could not emit asm file: %s", err); } } @@ -824,6 +850,11 @@ const char *llvm_codegen(void *context) object_name = c->object_filename; } + if (active_target.emit_asm) + { + llvm_emit_asm_file(context); + } + gencontext_end_module(c); gencontext_destroy(c); diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index 79c4f13de..ce314b2fe 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -81,6 +81,7 @@ typedef struct LLVMBasicBlockRef catch_block; const char *ir_filename; const char *object_filename; + const char *asm_filename; // The recipient of the error value in a catch(err = ...) expression. LLVMValueRef error_var; LLVMTypeRef bool_type; diff --git a/src/compiler/llvm_codegen_module.c b/src/compiler/llvm_codegen_module.c index d655d2138..14be72f0c 100644 --- a/src/compiler/llvm_codegen_module.c +++ b/src/compiler/llvm_codegen_module.c @@ -44,6 +44,11 @@ void gencontext_begin_module(GenContext *c) c->ir_filename = str_printf("%s.ll", result); if (active_target.llvm_file_dir) c->ir_filename = file_append_path(active_target.llvm_file_dir, c->ir_filename); c->object_filename = str_printf("%s%s", result, get_object_extension()); + if (active_target.emit_asm) + { + c->asm_filename = str_printf("%s.s", result); + if (active_target.asm_file_dir) c->asm_filename = file_append_path(active_target.asm_file_dir, c->asm_filename); + } if (active_target.object_file_dir) c->object_filename = file_append_path(active_target.object_file_dir, c->object_filename); c->panicfn = global_context.panic_fn; c->module = LLVMModuleCreateWithNameInContext(c->code_module->name->module, c->context); diff --git a/src/version.h b/src/version.h index 500fc2709..be24fb813 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.3.7" \ No newline at end of file +#define COMPILER_VERSION "0.3.8" \ No newline at end of file