| author | |
| committer | |
| log | 795703a39cfe0d59fcd9fff7a605a7efe9c5bdb2 |
| tree | 3a0883c024420f9cd7ddee0d54cbd223a3775a32 |
| parent | a31b23c46ba2a8c28df01adc1aa0b4d878b9a5cf |
Add emit command-line option8 files changed, 125 insertions(+), 24 deletions(-)
src/all_types.hpp+7| ... | ... | @@ -1366,6 +1366,12 @@ enum BuildMode { |
| 1366 | 1366 | BuildModeSafeRelease, |
| 1367 | 1367 | }; |
| 1368 | 1368 | |
| 1369 | enum EmitFileType { | |
| 1370 | EmitFileTypeBinary, | |
| 1371 | EmitFileTypeAssembly, | |
| 1372 | EmitFileTypeLLVMIr, | |
| 1373 | }; | |
| 1374 | ||
| 1369 | 1375 | struct LinkLib { |
| 1370 | 1376 | Buf *name; |
| 1371 | 1377 | Buf *path; |
| ... | ... | @@ -1449,6 +1455,7 @@ struct CodeGen { |
| 1449 | 1455 | TypeTableEntry *entry_arg_tuple; |
| 1450 | 1456 | } builtin_types; |
| 1451 | 1457 | |
| 1458 | EmitFileType emit_file_type; | |
| 1452 | 1459 | ZigTarget zig_target; |
| 1453 | 1460 | LLVMTargetDataRef target_data_ref; |
| 1454 | 1461 | unsigned pointer_size_bytes; |
src/codegen.cpp+60-10| ... | ... | @@ -189,6 +189,10 @@ void codegen_set_is_test(CodeGen *g, bool is_test_build) { |
| 189 | 189 | g->is_test_build = is_test_build; |
| 190 | 190 | } |
| 191 | 191 | |
| 192 | void codegen_set_emit_file_type(CodeGen *g, EmitFileType emit_file_type) { | |
| 193 | g->emit_file_type = emit_file_type; | |
| 194 | } | |
| 195 | ||
| 192 | 196 | void codegen_set_is_static(CodeGen *g, bool is_static) { |
| 193 | 197 | g->is_static = is_static; |
| 194 | 198 | } |
| ... | ... | @@ -4493,24 +4497,70 @@ static void do_code_gen(CodeGen *g) { |
| 4493 | 4497 | LLVMVerifyModule(g->module, LLVMAbortProcessAction, &error); |
| 4494 | 4498 | #endif |
| 4495 | 4499 | |
| 4496 | codegen_add_time_event(g, "LLVM Emit Object"); | |
| 4500 | codegen_add_time_event(g, "LLVM Emit Output"); | |
| 4497 | 4501 | |
| 4498 | 4502 | char *err_msg = nullptr; |
| 4499 | 4503 | Buf *o_basename = buf_create_from_buf(g->root_out_name); |
| 4500 | const char *o_ext = target_o_file_ext(&g->zig_target); | |
| 4501 | buf_append_str(o_basename, o_ext); | |
| 4504 | ||
| 4505 | switch (g->emit_file_type) { | |
| 4506 | case EmitFileTypeBinary: | |
| 4507 | { | |
| 4508 | const char *o_ext = target_o_file_ext(&g->zig_target); | |
| 4509 | buf_append_str(o_basename, o_ext); | |
| 4510 | break; | |
| 4511 | } | |
| 4512 | case EmitFileTypeAssembly: | |
| 4513 | { | |
| 4514 | const char *asm_ext = target_asm_file_ext(&g->zig_target); | |
| 4515 | buf_append_str(o_basename, asm_ext); | |
| 4516 | break; | |
| 4517 | } | |
| 4518 | case EmitFileTypeLLVMIr: | |
| 4519 | { | |
| 4520 | const char *llvm_ir_ext = target_llvm_ir_file_ext(&g->zig_target); | |
| 4521 | buf_append_str(o_basename, llvm_ir_ext); | |
| 4522 | break; | |
| 4523 | } | |
| 4524 | default: | |
| 4525 | zig_unreachable(); | |
| 4526 | } | |
| 4527 | ||
| 4502 | 4528 | Buf *output_path = buf_alloc(); |
| 4503 | 4529 | os_path_join(g->cache_dir, o_basename, output_path); |
| 4504 | 4530 | ensure_cache_dir(g); |
| 4505 | if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path), | |
| 4506 | LLVMObjectFile, &err_msg, g->build_mode == BuildModeDebug)) | |
| 4507 | { | |
| 4508 | zig_panic("unable to write object file %s: %s", buf_ptr(output_path), err_msg); | |
| 4509 | } | |
| 4510 | 4531 | |
| 4511 | validate_inline_fns(g); | |
| 4532 | switch (g->emit_file_type) { | |
| 4533 | case EmitFileTypeBinary: | |
| 4534 | if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path), | |
| 4535 | ZigLLVM_EmitBinary, &err_msg, g->build_mode == BuildModeDebug)) | |
| 4536 | { | |
| 4537 | zig_panic("unable to write object file %s: %s", buf_ptr(output_path), err_msg); | |
| 4538 | } | |
| 4539 | validate_inline_fns(g); | |
| 4540 | g->link_objects.append(output_path); | |
| 4541 | break; | |
| 4542 | ||
| 4543 | case EmitFileTypeAssembly: | |
| 4544 | if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path), | |
| 4545 | ZigLLVM_EmitAssembly, &err_msg, g->build_mode == BuildModeDebug)) | |
| 4546 | { | |
| 4547 | zig_panic("unable to write assembly file %s: %s", buf_ptr(output_path), err_msg); | |
| 4548 | } | |
| 4549 | validate_inline_fns(g); | |
| 4550 | break; | |
| 4551 | ||
| 4552 | case EmitFileTypeLLVMIr: | |
| 4553 | if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path), | |
| 4554 | ZigLLVM_EmitLLVMIr, &err_msg, g->build_mode == BuildModeDebug)) | |
| 4555 | { | |
| 4556 | zig_panic("unable to write llvm-ir file %s: %s", buf_ptr(output_path), err_msg); | |
| 4557 | } | |
| 4558 | validate_inline_fns(g); | |
| 4559 | break; | |
| 4512 | 4560 | |
| 4513 | g->link_objects.append(output_path); | |
| 4561 | default: | |
| 4562 | zig_unreachable(); | |
| 4563 | } | |
| 4514 | 4564 | } |
| 4515 | 4565 | |
| 4516 | 4566 | static const uint8_t int_sizes_in_bits[] = { |
src/codegen.hpp+1| ... | ... | @@ -23,6 +23,7 @@ void codegen_set_llvm_argv(CodeGen *codegen, const char **args, size_t len); |
| 23 | 23 | void codegen_set_is_test(CodeGen *codegen, bool is_test); |
| 24 | 24 | void codegen_set_each_lib_rpath(CodeGen *codegen, bool each_lib_rpath); |
| 25 | 25 | |
| 26 | void codegen_set_emit_file_type(CodeGen *g, EmitFileType emit_file_type); | |
| 26 | 27 | void codegen_set_is_static(CodeGen *codegen, bool is_static); |
| 27 | 28 | void codegen_set_strip(CodeGen *codegen, bool strip); |
| 28 | 29 | void codegen_set_errmsg_color(CodeGen *codegen, ErrColor err_color); |
src/main.cpp+15| ... | ... | @@ -32,6 +32,7 @@ static int usage(const char *arg0) { |
| 32 | 32 | " --assembly $source add assembly file to build\n" |
| 33 | 33 | " --cache-dir $path override the cache directory\n" |
| 34 | 34 | " --color $auto|off|on enable or disable colored error messages\n" |
| 35 | " --emit $filetype emit a specific file format as compilation output\n" | |
| 35 | 36 | " --enable-timing-info print timing diagnostics\n" |
| 36 | 37 | " --libc-include-dir $path directory where libc stdlib.h resides\n" |
| 37 | 38 | " --name $name override output name\n" |
| ... | ... | @@ -269,6 +270,7 @@ int main(int argc, char **argv) { |
| 269 | 270 | |
| 270 | 271 | char *arg0 = argv[0]; |
| 271 | 272 | Cmd cmd = CmdInvalid; |
| 273 | EmitFileType emit_file_type = EmitFileTypeBinary; | |
| 272 | 274 | const char *in_file = nullptr; |
| 273 | 275 | const char *out_file = nullptr; |
| 274 | 276 | const char *out_file_h = nullptr; |
| ... | ... | @@ -535,6 +537,17 @@ int main(int argc, char **argv) { |
| 535 | 537 | fprintf(stderr, "--color options are 'auto', 'on', or 'off'\n"); |
| 536 | 538 | return usage(arg0); |
| 537 | 539 | } |
| 540 | } else if (strcmp(arg, "--emit") == 0) { | |
| 541 | if (strcmp(argv[i], "asm") == 0) { | |
| 542 | emit_file_type = EmitFileTypeAssembly; | |
| 543 | } else if (strcmp(argv[i], "bin") == 0) { | |
| 544 | emit_file_type = EmitFileTypeBinary; | |
| 545 | } else if (strcmp(argv[i], "llvm-ir") == 0) { | |
| 546 | emit_file_type = EmitFileTypeLLVMIr; | |
| 547 | } else { | |
| 548 | fprintf(stderr, "--emit options are 'asm', 'bin', or 'llvm-ir'\n"); | |
| 549 | return usage(arg0); | |
| 550 | } | |
| 538 | 551 | } else if (strcmp(arg, "--name") == 0) { |
| 539 | 552 | out_name = argv[i]; |
| 540 | 553 | } else if (strcmp(arg, "--libc-lib-dir") == 0) { |
| ... | ... | @@ -815,6 +828,8 @@ int main(int argc, char **argv) { |
| 815 | 828 | add_package(g, cur_pkg, g->root_package); |
| 816 | 829 | |
| 817 | 830 | if (cmd == CmdBuild) { |
| 831 | codegen_set_emit_file_type(g, emit_file_type); | |
| 832 | ||
| 818 | 833 | for (size_t i = 0; i < objects.length; i += 1) { |
| 819 | 834 | codegen_add_object(g, buf_create_from_str(objects.at(i))); |
| 820 | 835 | } |
src/target.cpp+8| ... | ... | @@ -555,6 +555,14 @@ const char *target_o_file_ext(ZigTarget *target) { |
| 555 | 555 | } |
| 556 | 556 | } |
| 557 | 557 | |
| 558 | const char *target_asm_file_ext(ZigTarget *target) { | |
| 559 | return ".s"; | |
| 560 | } | |
| 561 | ||
| 562 | const char *target_llvm_ir_file_ext(ZigTarget *target) { | |
| 563 | return ".ll"; | |
| 564 | } | |
| 565 | ||
| 558 | 566 | const char *target_exe_file_ext(ZigTarget *target) { |
| 559 | 567 | if (target->os == ZigLLVM_Win32) { |
| 560 | 568 | return ".exe"; |
src/target.hpp+2| ... | ... | @@ -73,6 +73,8 @@ void resolve_target_object_format(ZigTarget *target); |
| 73 | 73 | uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id); |
| 74 | 74 | |
| 75 | 75 | const char *target_o_file_ext(ZigTarget *target); |
| 76 | const char *target_asm_file_ext(ZigTarget *target); | |
| 77 | const char *target_llvm_ir_file_ext(ZigTarget *target); | |
| 76 | 78 | const char *target_exe_file_ext(ZigTarget *target); |
| 77 | 79 | |
| 78 | 80 | Buf *target_dynamic_linker(ZigTarget *target); |
src/zig_llvm.cpp+23-13| ... | ... | @@ -77,7 +77,7 @@ static const bool assertions_on = false; |
| 77 | 77 | #endif |
| 78 | 78 | |
| 79 | 79 | bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref, |
| 80 | const char *filename, LLVMCodeGenFileType file_type, char **error_message, bool is_debug) | |
| 80 | const char *filename, ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug) | |
| 81 | 81 | { |
| 82 | 82 | std::error_code EC; |
| 83 | 83 | raw_fd_ostream dest(filename, EC, sys::fs::F_None); |
| ... | ... | @@ -135,18 +135,24 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM |
| 135 | 135 | MPM.add(createTargetTransformInfoWrapperPass(target_machine->getTargetIRAnalysis())); |
| 136 | 136 | PMBuilder->populateModulePassManager(MPM); |
| 137 | 137 | |
| 138 | // Set output pass. | |
| 138 | 139 | TargetMachine::CodeGenFileType ft; |
| 139 | switch (file_type) { | |
| 140 | case LLVMAssemblyFile: | |
| 141 | ft = TargetMachine::CGFT_AssemblyFile; | |
| 142 | break; | |
| 143 | default: | |
| 144 | ft = TargetMachine::CGFT_ObjectFile; | |
| 145 | break; | |
| 146 | } | |
| 147 | if (target_machine->addPassesToEmitFile(MPM, dest, ft)) { | |
| 148 | *error_message = strdup("TargetMachine can't emit a file of this type"); | |
| 149 | return true; | |
| 140 | if (output_type != ZigLLVM_EmitLLVMIr) { | |
| 141 | switch (output_type) { | |
| 142 | case ZigLLVM_EmitAssembly: | |
| 143 | ft = TargetMachine::CGFT_AssemblyFile; | |
| 144 | break; | |
| 145 | case ZigLLVM_EmitBinary: | |
| 146 | ft = TargetMachine::CGFT_ObjectFile; | |
| 147 | break; | |
| 148 | default: | |
| 149 | abort(); | |
| 150 | } | |
| 151 | ||
| 152 | if (target_machine->addPassesToEmitFile(MPM, dest, ft)) { | |
| 153 | *error_message = strdup("TargetMachine can't emit a file of this type"); | |
| 154 | return true; | |
| 155 | } | |
| 150 | 156 | } |
| 151 | 157 | |
| 152 | 158 | // run per function optimization passes |
| ... | ... | @@ -158,7 +164,11 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM |
| 158 | 164 | |
| 159 | 165 | MPM.run(*module); |
| 160 | 166 | |
| 161 | dest.close(); | |
| 167 | if (output_type == ZigLLVM_EmitLLVMIr) { | |
| 168 | if (LLVMPrintModuleToFile(module_ref, filename, error_message)) { | |
| 169 | return true; | |
| 170 | } | |
| 171 | } | |
| 162 | 172 | |
| 163 | 173 | return false; |
| 164 | 174 | } |
src/zig_llvm.hpp+9-1| ... | ... | @@ -34,8 +34,16 @@ void ZigLLVMInitializeLowerIntrinsicsPass(LLVMPassRegistryRef R); |
| 34 | 34 | char *ZigLLVMGetHostCPUName(void); |
| 35 | 35 | char *ZigLLVMGetNativeFeatures(void); |
| 36 | 36 | |
| 37 | // We use a custom enum here since LLVM does not expose LLVMIr as an emit | |
| 38 | // output through the same mechanism as assembly/binary. | |
| 39 | enum ZigLLVM_EmitOutputType { | |
| 40 | ZigLLVM_EmitAssembly, | |
| 41 | ZigLLVM_EmitBinary, | |
| 42 | ZigLLVM_EmitLLVMIr, | |
| 43 | }; | |
| 44 | ||
| 37 | 45 | bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref, |
| 38 | const char *filename, LLVMCodeGenFileType file_type, char **error_message, bool is_debug); | |
| 46 | const char *filename, ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug); | |
| 39 | 47 | |
| 40 | 48 | LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args, |
| 41 | 49 | unsigned NumArgs, unsigned CC, bool always_inline, const char *Name); |