Commit 2502cb242a

Noam Preil <pleasantatk@gmail.com>
2020-02-10 01:52:50
Improve support for generating LLVM IR/asm files
1 parent cbc4e59
lib/std/build.zig
@@ -1155,6 +1155,9 @@ pub const LibExeObjStep = struct {
     frameworks: BufSet,
     verbose_link: bool,
     verbose_cc: bool,
+    produce_ir: bool,
+    produce_asm: bool,
+    produce_bin: bool,
     disable_gen_h: bool,
     bundle_compiler_rt: bool,
     disable_stack_probing: bool,
@@ -1285,6 +1288,9 @@ pub const LibExeObjStep = struct {
             .builder = builder,
             .verbose_link = false,
             .verbose_cc = false,
+            .produce_ir = false,
+            .produce_asm = false,
+            .produce_bin = true,
             .build_mode = builtin.Mode.Debug,
             .is_dynamic = is_dynamic,
             .kind = kind,
@@ -1941,6 +1947,10 @@ pub const LibExeObjStep = struct {
         if (builder.verbose_link or self.verbose_link) zig_args.append("--verbose-link") catch unreachable;
         if (builder.verbose_cc or self.verbose_cc) zig_args.append("--verbose-cc") catch unreachable;
 
+        try zig_args.append(if (self.produce_ir) "-femit-llvm-ir" else "-fno-emit-llvm-ir");
+        try zig_args.append(if (self.produce_asm) "-femit-asm" else "-fno-emit-asm");
+        try zig_args.append(if (self.produce_bin) "-femit-bin" else "-fno-emit-bin");
+
         if (self.strip) {
             try zig_args.append("--strip");
         }
src/all_types.hpp
@@ -1966,12 +1966,6 @@ enum CodeModel {
     CodeModelLarge,
 };
 
-enum EmitFileType {
-    EmitFileTypeBinary,
-    EmitFileTypeAssembly,
-    EmitFileTypeLLVMIr,
-};
-
 struct LinkLib {
     Buf *name;
     Buf *path;
@@ -2204,6 +2198,8 @@ struct CodeGen {
     bool verbose_cimport;
     bool verbose_cc;
     bool verbose_llvm_cpu_features;
+    bool emit_asm;
+    bool emit_llvm_ir;
     bool error_during_imports;
     bool generate_error_name_table;
     bool enable_cache; // mutually exclusive with output_dir
@@ -2236,7 +2232,6 @@ struct CodeGen {
     size_t version_patch;
     const char *linker_script;
 
-    EmitFileType emit_file_type;
     BuildMode build_mode;
     OutType out_type;
     const ZigTarget *zig_target;
src/codegen.cpp
@@ -121,10 +121,6 @@ void codegen_set_lib_version(CodeGen *g, size_t major, size_t minor, size_t patc
     g->version_patch = patch;
 }
 
-void codegen_set_emit_file_type(CodeGen *g, EmitFileType emit_file_type) {
-    g->emit_file_type = emit_file_type;
-}
-
 void codegen_set_each_lib_rpath(CodeGen *g, bool each_lib_rpath) {
     g->each_lib_rpath = each_lib_rpath;
 }
@@ -7919,6 +7915,14 @@ static void do_code_gen(CodeGen *g) {
     }
 }
 
+void codegen_set_emit_asm(CodeGen *g, bool emit) {
+    g->emit_asm = emit;
+}
+
+void codegen_set_emit_llvm_ir(CodeGen *g, bool emit) {
+    g->emit_llvm_ir = emit;
+}
+
 static void zig_llvm_emit_output(CodeGen *g) {
     g->pass1_arena->destruct(&heap::c_allocator);
     g->pass1_arena = nullptr;
@@ -7927,48 +7931,40 @@ static void zig_llvm_emit_output(CodeGen *g) {
 
     Buf *output_path = &g->o_file_output_path;
     char *err_msg = nullptr;
-    switch (g->emit_file_type) {
-        case EmitFileTypeBinary:
-            if (g->disable_bin_generation)
-                return;
-            if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path),
-                        ZigLLVM_EmitBinary, &err_msg, g->build_mode == BuildModeDebug, is_small,
-                        g->enable_time_report))
-            {
-                zig_panic("unable to write object file %s: %s", buf_ptr(output_path), err_msg);
-            }
-            validate_inline_fns(g);
-            g->link_objects.append(output_path);
-            if (g->bundle_compiler_rt && (g->out_type == OutTypeObj ||
-                (g->out_type == OutTypeLib && !g->is_dynamic)))
-            {
-                zig_link_add_compiler_rt(g, g->sub_progress_node);
-            }
-            break;
-
-        case EmitFileTypeAssembly:
-            if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path),
-                        ZigLLVM_EmitAssembly, &err_msg, g->build_mode == BuildModeDebug, is_small,
-                        g->enable_time_report))
-            {
-                zig_panic("unable to write assembly file %s: %s", buf_ptr(output_path), err_msg);
-            }
-            validate_inline_fns(g);
-            break;
-
-        case EmitFileTypeLLVMIr:
-            if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path),
-                        ZigLLVM_EmitLLVMIr, &err_msg, g->build_mode == BuildModeDebug, is_small,
-                        g->enable_time_report))
-            {
-                zig_panic("unable to write llvm-ir file %s: %s", buf_ptr(output_path), err_msg);
-            }
-            validate_inline_fns(g);
-            break;
-
-        default:
-            zig_unreachable();
+    if (!g->disable_bin_generation) {
+        if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path),
+                    ZigLLVM_EmitBinary, &err_msg, g->build_mode == BuildModeDebug, is_small,
+                    g->enable_time_report))
+        {
+            zig_panic("unable to write object file %s: %s", buf_ptr(output_path), err_msg);
+        }
+        validate_inline_fns(g);
+        g->link_objects.append(output_path);
+        if (g->bundle_compiler_rt && (g->out_type == OutTypeObj ||
+            (g->out_type == OutTypeLib && !g->is_dynamic)))
+        {
+            zig_link_add_compiler_rt(g, g->sub_progress_node);
+        }
     }
+    if (g->emit_asm) {
+        if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path),
+                    ZigLLVM_EmitAssembly, &err_msg, g->build_mode == BuildModeDebug, is_small,
+                    g->enable_time_report))
+        {
+            zig_panic("unable to write assembly file %s: %s", buf_ptr(output_path), err_msg);
+        }
+        validate_inline_fns(g);
+    }
+    if (g->emit_llvm_ir) {
+        if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path),
+                    ZigLLVM_EmitLLVMIr, &err_msg, g->build_mode == BuildModeDebug, is_small,
+                    g->enable_time_report))
+        {
+            zig_panic("unable to write llvm-ir file %s: %s", buf_ptr(output_path), err_msg);
+        }
+        validate_inline_fns(g);
+    }
+
     LLVMDisposeModule(g->module);
     g->module = nullptr;
     LLVMDisposeTargetData(g->target_data_ref);
@@ -10497,53 +10493,48 @@ static void resolve_out_paths(CodeGen *g) {
 
     Buf *out_basename = buf_create_from_buf(g->root_out_name);
     Buf *o_basename = buf_create_from_buf(g->root_out_name);
-    switch (g->emit_file_type) {
-        case EmitFileTypeBinary: {
-            switch (g->out_type) {
-                case OutTypeUnknown:
-                    zig_unreachable();
-                case OutTypeObj:
-                    if (g->enable_cache && g->link_objects.length == 1 && !need_llvm_module(g)) {
-                        buf_init_from_buf(&g->output_file_path, g->link_objects.at(0));
-                        return;
-                    }
-                    if (need_llvm_module(g) && g->link_objects.length != 0 && !g->enable_cache &&
-                        buf_eql_buf(o_basename, out_basename))
-                    {
-                        // make it not collide with main output object
-                        buf_append_str(o_basename, ".root");
-                    }
-                    buf_append_str(o_basename, target_o_file_ext(g->zig_target));
-                    buf_append_str(out_basename, target_o_file_ext(g->zig_target));
-                    break;
-                case OutTypeExe:
-                    buf_append_str(o_basename, target_o_file_ext(g->zig_target));
-                    buf_append_str(out_basename, target_exe_file_ext(g->zig_target));
-                    break;
-                case OutTypeLib:
-                    buf_append_str(o_basename, target_o_file_ext(g->zig_target));
-                    buf_resize(out_basename, 0);
-                    buf_append_str(out_basename, target_lib_file_prefix(g->zig_target));
-                    buf_append_buf(out_basename, g->root_out_name);
-                    buf_append_str(out_basename, target_lib_file_ext(g->zig_target, !g->is_dynamic,
-                                g->version_major, g->version_minor, g->version_patch));
-                    break;
-            }
-            break;
-        }
-        case EmitFileTypeAssembly: {
-            const char *asm_ext = target_asm_file_ext(g->zig_target);
-            buf_append_str(o_basename, asm_ext);
-            buf_append_str(out_basename, asm_ext);
-            break;
-        }
-        case EmitFileTypeLLVMIr: {
-            const char *llvm_ir_ext = target_llvm_ir_file_ext(g->zig_target);
-            buf_append_str(o_basename, llvm_ir_ext);
-            buf_append_str(out_basename, llvm_ir_ext);
-            break;
+    if (!g->disable_bin_generation) {
+        switch (g->out_type) {
+            case OutTypeUnknown:
+                zig_unreachable();
+            case OutTypeObj:
+                if (g->enable_cache && g->link_objects.length == 1 && !need_llvm_module(g)) {
+                    buf_init_from_buf(&g->output_file_path, g->link_objects.at(0));
+                    return;
+                }
+                if (need_llvm_module(g) && g->link_objects.length != 0 && !g->enable_cache &&
+                    buf_eql_buf(o_basename, out_basename))
+                {
+                    // make it not collide with main output object
+                    buf_append_str(o_basename, ".root");
+                }
+                buf_append_str(o_basename, target_o_file_ext(g->zig_target));
+                buf_append_str(out_basename, target_o_file_ext(g->zig_target));
+                break;
+            case OutTypeExe:
+                buf_append_str(o_basename, target_o_file_ext(g->zig_target));
+                buf_append_str(out_basename, target_exe_file_ext(g->zig_target));
+                break;
+            case OutTypeLib:
+                buf_append_str(o_basename, target_o_file_ext(g->zig_target));
+                buf_resize(out_basename, 0);
+                buf_append_str(out_basename, target_lib_file_prefix(g->zig_target));
+                buf_append_buf(out_basename, g->root_out_name);
+                buf_append_str(out_basename, target_lib_file_ext(g->zig_target, !g->is_dynamic,
+                            g->version_major, g->version_minor, g->version_patch));
+                break;
         }
     }
+    else if (g->emit_asm) {
+        const char *asm_ext = target_asm_file_ext(g->zig_target);
+        buf_append_str(o_basename, asm_ext);
+        buf_append_str(out_basename, asm_ext);
+    }
+    else if (g->emit_llvm_ir) {
+        const char *llvm_ir_ext = target_llvm_ir_file_ext(g->zig_target);
+        buf_append_str(o_basename, llvm_ir_ext);
+        buf_append_str(out_basename, llvm_ir_ext);
+    }
 
     os_path_join(g->output_dir, o_basename, &g->o_file_output_path);
     os_path_join(g->output_dir, out_basename, &g->output_file_path);
@@ -10708,7 +10699,7 @@ void codegen_build_and_link(CodeGen *g) {
         // If there is more than one object, we have to link them (with -r).
         // Finally, if we didn't make an object from zig source, and we don't have caching enabled,
         // then we have an object from C source that we must copy to the output dir which we do with a -r link.
-        if (!g->disable_bin_generation && g->emit_file_type == EmitFileTypeBinary &&
+        if (!g->disable_bin_generation  &&
                 (g->out_type != OutTypeObj || g->link_objects.length > 1 ||
                     (!need_llvm_module(g) && !g->enable_cache)))
         {
src/codegen.hpp
@@ -26,7 +26,9 @@ void codegen_set_clang_argv(CodeGen *codegen, const char **args, size_t len);
 void codegen_set_llvm_argv(CodeGen *codegen, const char **args, size_t len);
 void codegen_set_each_lib_rpath(CodeGen *codegen, bool each_lib_rpath);
 
-void codegen_set_emit_file_type(CodeGen *g, EmitFileType emit_file_type);
+void codegen_set_emit_asm(CodeGen *codegen, bool emit);
+void codegen_set_emit_llvm_ir(CodeGen *codegen, bool emit);
+
 void codegen_set_strip(CodeGen *codegen, bool strip);
 void codegen_set_errmsg_color(CodeGen *codegen, ErrColor err_color);
 void codegen_set_out_name(CodeGen *codegen, Buf *out_name);
src/main.cpp
@@ -376,7 +376,6 @@ static int main0(int argc, char **argv) {
     }
 
     Cmd cmd = CmdNone;
-    EmitFileType emit_file_type = EmitFileTypeBinary;
     const char *in_file = nullptr;
     Buf *output_dir = nullptr;
     bool strip = false;
@@ -425,6 +424,8 @@ static int main0(int argc, char **argv) {
     bool enable_dump_analysis = false;
     bool enable_doc_generation = false;
     bool disable_bin_generation = false;
+    bool emit_asm = false;
+    bool emit_llvm_ir = false;
     const char *cache_dir = nullptr;
     CliPkg *cur_pkg = heap::c_allocator.create<CliPkg>();
     BuildMode build_mode = BuildModeDebug;
@@ -701,6 +702,18 @@ static int main0(int argc, char **argv) {
                 function_sections = true;
             } else if (strcmp(arg, "--test-evented-io") == 0) {
                 test_evented_io = true;
+            } else if (strcmp(arg, "-femit-bin") == 0) {
+                disable_bin_generation = false;
+            } else if (strcmp(arg, "-fno-emit-bin") == 0) {
+                disable_bin_generation = true;
+            } else if (strcmp(arg, "-femit-asm") == 0) {
+                emit_asm = true;
+            } else if (strcmp(arg, "-fno-emit-asm") == 0) {
+                emit_asm = false;
+            } else if (strcmp(arg, "-femit-llvm-ir") == 0) {
+                emit_llvm_ir = true;
+            } else if (strcmp(arg, "-fno-emit-llvm-ir") == 0) {
+                emit_llvm_ir = false;
             } else if (i + 1 >= argc) {
                 fprintf(stderr, "Expected another argument after %s\n", arg);
                 return print_error_usage(arg0);
@@ -732,11 +745,11 @@ static int main0(int argc, char **argv) {
                     }
                 } else if (strcmp(arg, "--emit") == 0) {
                     if (strcmp(argv[i], "asm") == 0) {
-                        emit_file_type = EmitFileTypeAssembly;
+                        emit_asm = true;
                     } else if (strcmp(argv[i], "bin") == 0) {
-                        emit_file_type = EmitFileTypeBinary;
+                        disable_bin_generation = false;
                     } else if (strcmp(argv[i], "llvm-ir") == 0) {
-                        emit_file_type = EmitFileTypeLLVMIr;
+                        emit_llvm_ir = true;
                     } else {
                         fprintf(stderr, "--emit options are 'asm', 'bin', or 'llvm-ir'\n");
                         return print_error_usage(arg0);
@@ -1026,8 +1039,8 @@ static int main0(int argc, char **argv) {
         return print_error_usage(arg0);
     }
 
-    if (emit_file_type != EmitFileTypeBinary && in_file == nullptr) {
-        fprintf(stderr, "A root source file is required when using `--emit asm` or `--emit llvm-ir`\n");
+    if ((emit_asm || emit_llvm_ir) && in_file == nullptr) {
+        fprintf(stderr, "A root source file is required when using `-femit-asm` or `-femit-llvm-ir`\n");
         return print_error_usage(arg0);
     }
 
@@ -1098,7 +1111,7 @@ static int main0(int argc, char **argv) {
             {
                 fprintf(stderr, "Expected source file argument.\n");
                 return print_error_usage(arg0);
-            } else if (cmd == CmdRun && emit_file_type != EmitFileTypeBinary) {
+            } else if (cmd == CmdRun && disable_bin_generation) {
                 fprintf(stderr, "Cannot run non-executable file.\n");
                 return print_error_usage(arg0);
             }
@@ -1262,7 +1275,8 @@ static int main0(int argc, char **argv) {
 
 
             if (cmd == CmdBuild || cmd == CmdRun) {
-                codegen_set_emit_file_type(g, emit_file_type);
+                codegen_set_emit_asm(g, emit_asm);
+                codegen_set_emit_llvm_ir(g, emit_llvm_ir);
 
                 g->enable_cache = get_cache_opt(enable_cache, cmd == CmdRun);
                 codegen_build_and_link(g);
@@ -1330,7 +1344,8 @@ static int main0(int argc, char **argv) {
                     codegen_print_timing_report(g, stderr);
                 return main_exit(root_progress_node, EXIT_SUCCESS);
             } else if (cmd == CmdTest) {
-                codegen_set_emit_file_type(g, emit_file_type);
+                codegen_set_emit_asm(g, emit_asm);
+                codegen_set_emit_llvm_ir(g, emit_llvm_ir);
 
                 ZigTarget native;
                 get_native_target(&native);
@@ -1359,7 +1374,7 @@ static int main0(int argc, char **argv) {
                 Buf *test_exe_path = buf_alloc();
                 *test_exe_path = os_path_resolve(&test_exe_path_unresolved, 1);
 
-                if (emit_file_type != EmitFileTypeBinary) {
+                if (disable_bin_generation) {
                     fprintf(stderr, "Created %s but skipping execution because it is non executable.\n",
                             buf_ptr(test_exe_path));
                     return main_exit(root_progress_node, EXIT_SUCCESS);