improvements which allow zig to emit multiple things at once

example: zig build-obj test.zig -femit-llvm-ir -femit-asm

this will generate all three: test.o test.s test.ll
master
Andrew Kelley 2020-02-18 21:59:43 -05:00
parent dba12cd693
commit d7968c6d33
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
8 changed files with 174 additions and 171 deletions

View File

@ -1155,9 +1155,9 @@ pub const LibExeObjStep = struct {
frameworks: BufSet,
verbose_link: bool,
verbose_cc: bool,
emit_ir: bool,
emit_asm: bool,
emit_bin: bool,
emit_llvm_ir: bool = false,
emit_asm: bool = false,
emit_bin: bool = true,
disable_gen_h: bool,
bundle_compiler_rt: bool,
disable_stack_probing: bool,
@ -1288,9 +1288,6 @@ pub const LibExeObjStep = struct {
.builder = builder,
.verbose_link = false,
.verbose_cc = false,
.emit_ir = false,
.emit_asm = false,
.emit_bin = true,
.build_mode = builtin.Mode.Debug,
.is_dynamic = is_dynamic,
.kind = kind,
@ -1947,9 +1944,9 @@ 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.emit_ir) "-femit-llvm-ir" else "-fno-emit-llvm-ir");
try zig_args.append(if (self.emit_asm) "-femit-asm" else "-fno-emit-asm");
try zig_args.append(if (self.emit_bin) "-femit-bin" else "-fno-emit-bin");
if (self.emit_llvm_ir) try zig_args.append("-femit-llvm-ir");
if (self.emit_asm) try zig_args.append("-femit-asm");
if (!self.emit_bin) try zig_args.append("-fno-emit-bin");
if (self.strip) {
try zig_args.append("--strip");

View File

@ -2136,8 +2136,10 @@ struct CodeGen {
Buf llvm_triple_str;
Buf global_asm;
Buf output_file_path;
Buf o_file_output_path;
Buf bin_file_output_path;
Buf asm_file_output_path;
Buf llvm_ir_file_output_path;
Buf *cache_dir;
// As an input parameter, mutually exclusive with enable_cache. But it gets
// populated in codegen_build_and_link.
@ -2198,8 +2200,6 @@ 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
@ -2253,7 +2253,9 @@ struct CodeGen {
bool function_sections;
bool enable_dump_analysis;
bool enable_doc_generation;
bool disable_bin_generation;
bool emit_bin;
bool emit_asm;
bool emit_llvm_ir;
bool test_is_evented;
CodeModel code_model;

View File

@ -7915,55 +7915,49 @@ 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;
bool is_small = g->build_mode == BuildModeSmallRelease;
Buf *output_path = &g->o_file_output_path;
char *err_msg = nullptr;
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))
const char *asm_filename = nullptr;
const char *bin_filename = nullptr;
const char *llvm_ir_filename = nullptr;
if (g->emit_bin) bin_filename = buf_ptr(&g->o_file_output_path);
if (g->emit_asm) asm_filename = buf_ptr(&g->asm_file_output_path);
if (g->emit_llvm_ir) llvm_ir_filename = buf_ptr(&g->llvm_ir_file_output_path);
// Unfortunately, LLVM shits the bed when we ask for both binary and assembly. So we call the entire
// pipeline multiple times if this is requested.
if (asm_filename != nullptr && bin_filename != nullptr) {
if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, &err_msg, g->build_mode == BuildModeDebug,
is_small, g->enable_time_report, nullptr, bin_filename, llvm_ir_filename))
{
zig_panic("unable to write object file %s: %s", buf_ptr(output_path), err_msg);
fprintf(stderr, "LLVM failed to emit file: %s\n", err_msg);
exit(1);
}
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)))
{
bin_filename = nullptr;
llvm_ir_filename = nullptr;
}
if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, &err_msg, g->build_mode == BuildModeDebug,
is_small, g->enable_time_report, asm_filename, bin_filename, llvm_ir_filename))
{
fprintf(stderr, "LLVM failed to emit file: %s\n", err_msg);
exit(1);
}
validate_inline_fns(g);
if (g->emit_bin) {
g->link_objects.append(&g->o_file_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;
@ -10446,7 +10440,9 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
cache_bool(ch, g->function_sections);
cache_bool(ch, g->enable_dump_analysis);
cache_bool(ch, g->enable_doc_generation);
cache_bool(ch, g->disable_bin_generation);
cache_bool(ch, g->emit_bin);
cache_bool(ch, g->emit_llvm_ir);
cache_bool(ch, g->emit_asm);
cache_buf_opt(ch, g->mmacosx_version_min);
cache_buf_opt(ch, g->mios_version_min);
cache_usize(ch, g->version_major);
@ -10491,15 +10487,15 @@ static void resolve_out_paths(CodeGen *g) {
assert(g->output_dir != nullptr);
assert(g->root_out_name != nullptr);
Buf *out_basename = buf_create_from_buf(g->root_out_name);
Buf *o_basename = buf_create_from_buf(g->root_out_name);
if (!g->disable_bin_generation) {
if (g->emit_bin) {
Buf *out_basename = buf_create_from_buf(g->root_out_name);
Buf *o_basename = buf_create_from_buf(g->root_out_name);
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));
buf_init_from_buf(&g->bin_file_output_path, g->link_objects.at(0));
return;
}
if (need_llvm_module(g) && g->link_objects.length != 0 && !g->enable_cache &&
@ -10524,20 +10520,21 @@ static void resolve_out_paths(CodeGen *g) {
g->version_major, g->version_minor, g->version_patch));
break;
}
os_path_join(g->output_dir, o_basename, &g->o_file_output_path);
os_path_join(g->output_dir, out_basename, &g->bin_file_output_path);
}
else if (g->emit_asm) {
if (g->emit_asm) {
Buf *asm_basename = buf_create_from_buf(g->root_out_name);
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);
buf_append_str(asm_basename, asm_ext);
os_path_join(g->output_dir, asm_basename, &g->asm_file_output_path);
}
else if (g->emit_llvm_ir) {
if (g->emit_llvm_ir) {
Buf *llvm_ir_basename = buf_create_from_buf(g->root_out_name);
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);
buf_append_str(llvm_ir_basename, llvm_ir_ext);
os_path_join(g->output_dir, llvm_ir_basename, &g->llvm_ir_file_output_path);
}
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);
}
void codegen_build_and_link(CodeGen *g) {
@ -10699,7 +10696,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 &&
if (g->emit_bin &&
(g->out_type != OutTypeObj || g->link_objects.length > 1 ||
(!need_llvm_module(g) && !g->enable_cache)))
{
@ -10777,6 +10774,7 @@ CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget
Stage2LibCInstallation *libc, Buf *cache_dir, bool is_test_build, Stage2ProgressNode *progress_node)
{
CodeGen *g = heap::c_allocator.create<CodeGen>();
g->emit_bin = true;
g->pass1_arena = heap::ArenaAllocator::construct(&heap::c_allocator, &heap::c_allocator, "pass1");
g->main_progress_node = progress_node;

View File

@ -26,9 +26,6 @@ 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_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);

View File

@ -605,7 +605,7 @@ static const char *build_libc_object(CodeGen *parent_gen, const char *name, CFil
c_source_files.append(c_file);
child_gen->c_source_files = c_source_files;
codegen_build_and_link(child_gen);
return buf_ptr(&child_gen->output_file_path);
return buf_ptr(&child_gen->bin_file_output_path);
}
static const char *path_from_zig_lib(CodeGen *g, const char *dir, const char *subpath) {
@ -682,7 +682,7 @@ static const char *build_libunwind(CodeGen *parent, Stage2ProgressNode *progress
}
child_gen->c_source_files = c_source_files;
codegen_build_and_link(child_gen);
return buf_ptr(&child_gen->output_file_path);
return buf_ptr(&child_gen->bin_file_output_path);
}
static void mingw_add_cc_args(CodeGen *parent, CFile *c_file) {
@ -1123,7 +1123,7 @@ static const char *build_musl(CodeGen *parent, Stage2ProgressNode *progress_node
child_gen->c_source_files = c_source_files;
codegen_build_and_link(child_gen);
return buf_ptr(&child_gen->output_file_path);
return buf_ptr(&child_gen->bin_file_output_path);
}
static void add_msvcrt_os_dep(CodeGen *parent, CodeGen *child_gen, const char *src_path) {
@ -1253,7 +1253,7 @@ static const char *get_libc_crt_file(CodeGen *parent, const char *file, Stage2Pr
child_gen->c_source_files.append(c_file);
}
codegen_build_and_link(child_gen);
return buf_ptr(&child_gen->output_file_path);
return buf_ptr(&child_gen->bin_file_output_path);
} else if (strcmp(file, "msvcrt-os.lib") == 0) {
CodeGen *child_gen = create_child_codegen(parent, nullptr, OutTypeLib, nullptr, "msvcrt-os", progress_node);
@ -1270,7 +1270,7 @@ static const char *get_libc_crt_file(CodeGen *parent, const char *file, Stage2Pr
}
}
codegen_build_and_link(child_gen);
return buf_ptr(&child_gen->output_file_path);
return buf_ptr(&child_gen->bin_file_output_path);
} else if (strcmp(file, "mingwex.lib") == 0) {
CodeGen *child_gen = create_child_codegen(parent, nullptr, OutTypeLib, nullptr, "mingwex", progress_node);
@ -1295,7 +1295,7 @@ static const char *get_libc_crt_file(CodeGen *parent, const char *file, Stage2Pr
zig_unreachable();
}
codegen_build_and_link(child_gen);
return buf_ptr(&child_gen->output_file_path);
return buf_ptr(&child_gen->bin_file_output_path);
} else {
zig_unreachable();
}
@ -1365,7 +1365,7 @@ static const char *get_libc_crt_file(CodeGen *parent, const char *file, Stage2Pr
codegen_add_object(child_gen, buf_create_from_str(start_os));
codegen_add_object(child_gen, buf_create_from_str(abi_note_o));
codegen_build_and_link(child_gen);
return buf_ptr(&child_gen->output_file_path);
return buf_ptr(&child_gen->bin_file_output_path);
} else if (strcmp(file, "libc_nonshared.a") == 0) {
CodeGen *child_gen = create_child_codegen(parent, nullptr, OutTypeLib, nullptr, "c_nonshared", progress_node);
{
@ -1445,7 +1445,7 @@ static const char *get_libc_crt_file(CodeGen *parent, const char *file, Stage2Pr
build_libc_object(parent, deps[i].name, c_file, progress_node)));
}
codegen_build_and_link(child_gen);
return buf_ptr(&child_gen->output_file_path);
return buf_ptr(&child_gen->bin_file_output_path);
} else {
zig_unreachable();
}
@ -1519,7 +1519,7 @@ static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path,
child_gen->want_stack_check = WantStackCheckDisabled;
codegen_build_and_link(child_gen);
return &child_gen->output_file_path;
return &child_gen->bin_file_output_path;
}
static Buf *build_compiler_rt(CodeGen *parent_gen, OutType child_out_type, Stage2ProgressNode *progress_node) {
@ -1681,7 +1681,7 @@ static void construct_linker_job_elf(LinkJob *lj) {
} else if (is_dyn_lib) {
lj->args.append("-shared");
assert(buf_len(&g->output_file_path) != 0);
assert(buf_len(&g->bin_file_output_path) != 0);
soname = buf_sprintf("lib%s.so.%" ZIG_PRI_usize, buf_ptr(g->root_out_name), g->version_major);
}
@ -1690,7 +1690,7 @@ static void construct_linker_job_elf(LinkJob *lj) {
}
lj->args.append("-o");
lj->args.append(buf_ptr(&g->output_file_path));
lj->args.append(buf_ptr(&g->bin_file_output_path));
if (lj->link_in_crt) {
const char *crt1o;
@ -1872,7 +1872,7 @@ static void construct_linker_job_wasm(LinkJob *lj) {
}
lj->args.append("--allow-undefined");
lj->args.append("-o");
lj->args.append(buf_ptr(&g->output_file_path));
lj->args.append(buf_ptr(&g->bin_file_output_path));
// .o files
for (size_t i = 0; i < g->link_objects.length; i += 1) {
@ -2248,7 +2248,7 @@ static void construct_linker_job_coff(LinkJob *lj) {
lj->args.append("-DLL");
}
lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&g->output_file_path))));
lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&g->bin_file_output_path))));
if (g->libc_link_lib != nullptr && g->libc != nullptr) {
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", g->libc->crt_dir)));
@ -2501,7 +2501,7 @@ static void construct_linker_job_macho(LinkJob *lj) {
//lj->args.append("-install_name");
//lj->args.append(buf_ptr(dylib_install_name));
assert(buf_len(&g->output_file_path) != 0);
assert(buf_len(&g->bin_file_output_path) != 0);
}
lj->args.append("-arch");
@ -2532,14 +2532,14 @@ static void construct_linker_job_macho(LinkJob *lj) {
}
lj->args.append("-o");
lj->args.append(buf_ptr(&g->output_file_path));
lj->args.append(buf_ptr(&g->bin_file_output_path));
for (size_t i = 0; i < g->rpath_list.length; i += 1) {
Buf *rpath = g->rpath_list.at(i);
add_rpath(lj, rpath);
}
if (is_dyn_lib) {
add_rpath(lj, &g->output_file_path);
add_rpath(lj, &g->bin_file_output_path);
}
if (is_dyn_lib) {
@ -2659,14 +2659,14 @@ void codegen_link(CodeGen *g) {
progress_name, strlen(progress_name), 0));
}
if (g->verbose_link) {
fprintf(stderr, "ar rcs %s", buf_ptr(&g->output_file_path));
fprintf(stderr, "ar rcs %s", buf_ptr(&g->bin_file_output_path));
for (size_t i = 0; i < file_names.length; i += 1) {
fprintf(stderr, " %s", file_names.at(i));
}
fprintf(stderr, "\n");
}
if (ZigLLVMWriteArchive(buf_ptr(&g->output_file_path), file_names.items, file_names.length, os_type)) {
fprintf(stderr, "Unable to write archive '%s'\n", buf_ptr(&g->output_file_path));
if (ZigLLVMWriteArchive(buf_ptr(&g->bin_file_output_path), file_names.items, file_names.length, os_type)) {
fprintf(stderr, "Unable to write archive '%s'\n", buf_ptr(&g->bin_file_output_path));
exit(1);
}
return;

View File

@ -62,17 +62,21 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
" -fno-stack-check disable stack probing in safe builds\n"
" -fsanitize-c enable C undefined behavior detection in unsafe builds\n"
" -fno-sanitize-c disable C undefined behavior detection in safe builds\n"
" --emit [asm|bin|llvm-ir] emit a specific file format as compilation output\n"
" --emit [asm|bin|llvm-ir] (deprecated) emit a specific file format as compilation output\n"
" -fPIC enable Position Independent Code\n"
" -fno-PIC disable Position Independent Code\n"
" -ftime-report print timing diagnostics\n"
" -fstack-report print stack size diagnostics\n"
#ifdef ZIG_ENABLE_MEM_PROFILE
" -fmem-report print memory usage diagnostics\n"
#endif
" -fdump-analysis write analysis.json file with type information\n"
" -femit-docs create a docs/ dir with html documentation\n"
" -fno-emit-bin skip emitting machine code\n"
" -fno-emit-docs do not produce docs/ dir with html documentation\n"
" -femit-bin (default) output machine code\n"
" -fno-emit-bin do not output machine code\n"
" -femit-asm output .s (assembly code)\n"
" -fno-emit-asm (default) do not output .s (assembly code)\n"
" -femit-llvm-ir produce a .ll file with LLVM IR\n"
" -fno-emit-llvm-ir (default) do not produce a .ll file with LLVM IR\n"
" --libc [file] Provide a file which specifies libc paths\n"
" --name [name] override output name\n"
" --output-dir [dir] override output directory (defaults to cwd)\n"
@ -423,7 +427,7 @@ static int main0(int argc, char **argv) {
bool stack_report = false;
bool enable_dump_analysis = false;
bool enable_doc_generation = false;
bool disable_bin_generation = false;
bool emit_bin = true;
bool emit_asm = false;
bool emit_llvm_ir = false;
const char *cache_dir = nullptr;
@ -553,7 +557,7 @@ static int main0(int argc, char **argv) {
}
Termination term;
args.items[0] = buf_ptr(&g->output_file_path);
args.items[0] = buf_ptr(&g->bin_file_output_path);
os_spawn_process(args, &term);
if (term.how != TerminationIdClean || term.code != 0) {
fprintf(stderr, "\nBuild failed. The following command failed:\n");
@ -632,8 +636,6 @@ static int main0(int argc, char **argv) {
enable_dump_analysis = true;
} else if (strcmp(arg, "-femit-docs") == 0) {
enable_doc_generation = true;
} else if (strcmp(arg, "-fno-emit-bin") == 0) {
disable_bin_generation = true;
} else if (strcmp(arg, "--enable-valgrind") == 0) {
valgrind_support = ValgrindSupportEnabled;
} else if (strcmp(arg, "--disable-valgrind") == 0) {
@ -703,9 +705,9 @@ static int main0(int argc, char **argv) {
} else if (strcmp(arg, "--test-evented-io") == 0) {
test_evented_io = true;
} else if (strcmp(arg, "-femit-bin") == 0) {
disable_bin_generation = false;
emit_bin = true;
} else if (strcmp(arg, "-fno-emit-bin") == 0) {
disable_bin_generation = true;
emit_bin = false;
} else if (strcmp(arg, "-femit-asm") == 0) {
emit_asm = true;
} else if (strcmp(arg, "-fno-emit-asm") == 0) {
@ -746,12 +748,12 @@ static int main0(int argc, char **argv) {
} else if (strcmp(arg, "--emit") == 0) {
if (strcmp(argv[i], "asm") == 0) {
emit_asm = true;
disable_bin_generation = true;
emit_bin = false;
} else if (strcmp(argv[i], "bin") == 0) {
disable_bin_generation = false;
emit_bin = true;
} else if (strcmp(argv[i], "llvm-ir") == 0) {
emit_llvm_ir = true;
disable_bin_generation = true;
emit_bin = false;
} else {
fprintf(stderr, "--emit options are 'asm', 'bin', or 'llvm-ir'\n");
return print_error_usage(arg0);
@ -1113,8 +1115,8 @@ static int main0(int argc, char **argv) {
{
fprintf(stderr, "Expected source file argument.\n");
return print_error_usage(arg0);
} else if (cmd == CmdRun && disable_bin_generation) {
fprintf(stderr, "Cannot run non-executable file.\n");
} else if (cmd == CmdRun && !emit_bin) {
fprintf(stderr, "Cannot run without emitting a binary file.\n");
return print_error_usage(arg0);
}
@ -1191,7 +1193,10 @@ static int main0(int argc, char **argv) {
g->enable_stack_report = stack_report;
g->enable_dump_analysis = enable_dump_analysis;
g->enable_doc_generation = enable_doc_generation;
g->disable_bin_generation = disable_bin_generation;
g->emit_bin = emit_bin;
g->emit_asm = emit_asm;
g->emit_llvm_ir = emit_llvm_ir;
codegen_set_out_name(g, buf_out_name);
codegen_set_lib_version(g, ver_major, ver_minor, ver_patch);
g->want_single_threaded = want_single_threaded;
@ -1277,9 +1282,6 @@ static int main0(int argc, char **argv) {
if (cmd == CmdBuild || cmd == CmdRun) {
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);
if (root_progress_node != nullptr) {
@ -1297,7 +1299,7 @@ static int main0(int argc, char **argv) {
mem::print_report();
#endif
const char *exec_path = buf_ptr(&g->output_file_path);
const char *exec_path = buf_ptr(&g->bin_file_output_path);
ZigList<const char*> args = {0};
args.append(exec_path);
@ -1317,21 +1319,21 @@ static int main0(int argc, char **argv) {
} else if (cmd == CmdBuild) {
if (g->enable_cache) {
#if defined(ZIG_OS_WINDOWS)
buf_replace(&g->output_file_path, '/', '\\');
buf_replace(&g->bin_file_output_path, '/', '\\');
#endif
if (final_output_dir_step != nullptr) {
Buf *dest_basename = buf_alloc();
os_path_split(&g->output_file_path, nullptr, dest_basename);
os_path_split(&g->bin_file_output_path, nullptr, dest_basename);
Buf *dest_path = buf_alloc();
os_path_join(final_output_dir_step, dest_basename, dest_path);
if ((err = os_update_file(&g->output_file_path, dest_path))) {
fprintf(stderr, "unable to copy %s to %s: %s\n", buf_ptr(&g->output_file_path),
if ((err = os_update_file(&g->bin_file_output_path, dest_path))) {
fprintf(stderr, "unable to copy %s to %s: %s\n", buf_ptr(&g->bin_file_output_path),
buf_ptr(dest_path), err_str(err));
return main_exit(root_progress_node, EXIT_FAILURE);
}
} else {
if (printf("%s\n", buf_ptr(&g->output_file_path)) < 0)
if (printf("%s\n", buf_ptr(&g->bin_file_output_path)) < 0)
return main_exit(root_progress_node, EXIT_FAILURE);
}
}
@ -1346,9 +1348,6 @@ 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_asm(g, emit_asm);
codegen_set_emit_llvm_ir(g, emit_llvm_ir);
ZigTarget native;
get_native_target(&native);
@ -1367,17 +1366,17 @@ static int main0(int argc, char **argv) {
zig_print_stack_report(g, stdout);
}
if (g->disable_bin_generation) {
if (!g->emit_bin) {
fprintf(stderr, "Semantic analysis complete. No binary produced due to -fno-emit-bin.\n");
return main_exit(root_progress_node, EXIT_SUCCESS);
}
Buf *test_exe_path_unresolved = &g->output_file_path;
Buf *test_exe_path_unresolved = &g->bin_file_output_path;
Buf *test_exe_path = buf_alloc();
*test_exe_path = os_path_resolve(&test_exe_path_unresolved, 1);
if (disable_bin_generation) {
fprintf(stderr, "Created %s but skipping execution because it is non executable.\n",
if (!g->emit_bin) {
fprintf(stderr, "Created %s but skipping execution because no binary generated.\n",
buf_ptr(test_exe_path));
return main_exit(root_progress_node, EXIT_SUCCESS);
}

View File

@ -161,17 +161,32 @@ unsigned ZigLLVMDataLayoutGetProgramAddressSpace(LLVMTargetDataRef TD) {
}
bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
const char *filename, ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug,
bool is_small, bool time_report)
char **error_message, bool is_debug,
bool is_small, bool time_report,
const char *asm_filename, const char *bin_filename, const char *llvm_ir_filename)
{
TimePassesIsEnabled = time_report;
std::error_code EC;
raw_fd_ostream dest(filename, EC, sys::fs::F_None);
if (EC) {
*error_message = strdup((const char *)StringRef(EC.message()).bytes_begin());
return true;
raw_fd_ostream *dest_asm = nullptr;
raw_fd_ostream *dest_bin = nullptr;
if (asm_filename) {
std::error_code EC;
dest_asm = new(std::nothrow) raw_fd_ostream(asm_filename, EC, sys::fs::F_None);
if (EC) {
*error_message = strdup((const char *)StringRef(EC.message()).bytes_begin());
return true;
}
}
if (bin_filename) {
std::error_code EC;
dest_bin = new(std::nothrow) raw_fd_ostream(bin_filename, EC, sys::fs::F_None);
if (EC) {
*error_message = strdup((const char *)StringRef(EC.message()).bytes_begin());
return true;
}
}
TargetMachine* target_machine = reinterpret_cast<TargetMachine*>(targ_machine_ref);
target_machine->setO0WantsFastISel(true);
@ -222,49 +237,51 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
}
PMBuilder->populateFunctionPassManager(FPM);
// Set up the per-module pass manager.
legacy::PassManager MPM;
MPM.add(createTargetTransformInfoWrapperPass(target_machine->getTargetIRAnalysis()));
PMBuilder->populateModulePassManager(MPM);
{
// Set up the per-module pass manager.
legacy::PassManager MPM;
MPM.add(createTargetTransformInfoWrapperPass(target_machine->getTargetIRAnalysis()));
PMBuilder->populateModulePassManager(MPM);
// Set output pass.
TargetMachine::CodeGenFileType ft;
if (output_type != ZigLLVM_EmitLLVMIr) {
switch (output_type) {
case ZigLLVM_EmitAssembly:
ft = TargetMachine::CGFT_AssemblyFile;
break;
case ZigLLVM_EmitBinary:
ft = TargetMachine::CGFT_ObjectFile;
break;
default:
abort();
// Set output passes.
if (dest_bin) {
if (target_machine->addPassesToEmitFile(MPM, *dest_bin, nullptr, TargetMachine::CGFT_ObjectFile)) {
*error_message = strdup("TargetMachine can't emit an object file");
return true;
}
}
if (dest_asm) {
if (target_machine->addPassesToEmitFile(MPM, *dest_asm, nullptr, TargetMachine::CGFT_AssemblyFile)) {
*error_message = strdup("TargetMachine can't emit an assembly file");
return true;
}
}
if (target_machine->addPassesToEmitFile(MPM, dest, nullptr, ft)) {
*error_message = strdup("TargetMachine can't emit a file of this type");
return true;
// run per function optimization passes
FPM.doInitialization();
for (Function &F : *module)
if (!F.isDeclaration())
FPM.run(F);
FPM.doFinalization();
MPM.run(*module);
if (llvm_ir_filename) {
if (LLVMPrintModuleToFile(module_ref, llvm_ir_filename, error_message)) {
return true;
}
}
}
// run per function optimization passes
FPM.doInitialization();
for (Function &F : *module)
if (!F.isDeclaration())
FPM.run(F);
FPM.doFinalization();
MPM.run(*module);
if (output_type == ZigLLVM_EmitLLVMIr) {
if (LLVMPrintModuleToFile(module_ref, filename, error_message)) {
return true;
if (time_report) {
TimerGroup::printAll(errs());
}
// MPM goes out of scope and writes to the out streams
}
if (time_report) {
TimerGroup::printAll(errs());
}
delete dest_asm;
delete dest_bin;
return false;
}

View File

@ -46,17 +46,10 @@ ZIG_EXTERN_C void ZigLLVMInitializeLowerIntrinsicsPass(LLVMPassRegistryRef R);
ZIG_EXTERN_C char *ZigLLVMGetHostCPUName(void);
ZIG_EXTERN_C char *ZigLLVMGetNativeFeatures(void);
// We use a custom enum here since LLVM does not expose LLVMIr as an emit
// output through the same mechanism as assembly/binary.
enum ZigLLVM_EmitOutputType {
ZigLLVM_EmitAssembly,
ZigLLVM_EmitBinary,
ZigLLVM_EmitLLVMIr,
};
ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
const char *filename, enum ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug,
bool is_small, bool time_report);
char **error_message, bool is_debug,
bool is_small, bool time_report,
const char *asm_filename, const char *bin_filename, const char *llvm_ir_filename);
ZIG_EXTERN_C LLVMTargetMachineRef ZigLLVMCreateTargetMachine(LLVMTargetRef T, const char *Triple,
const char *CPU, const char *Features, LLVMCodeGenOptLevel Level, LLVMRelocMode Reloc,