diff --git a/src/codegen.cpp b/src/codegen.cpp index 54a76d9b54..938798f505 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3826,8 +3826,8 @@ static void do_code_gen(CodeGen *g) { Buf *out_file_o = buf_create_from_buf(g->root_out_name); const char *o_ext = target_o_file_ext(&g->zig_target); buf_append_str(out_file_o, o_ext); - if (LLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(out_file_o), - LLVMObjectFile, &err_msg)) + if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(out_file_o), + LLVMObjectFile, &err_msg, !g->is_release_build)) { zig_panic("unable to write object file: %s", err_msg); } diff --git a/src/link.cpp b/src/link.cpp index ebabdd46aa..b9328eff28 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -746,18 +746,10 @@ void codegen_link(CodeGen *g, const char *out_file) { buf_resize(&lj.out_file, 0); } - bool is_optimized = g->is_release_build; - if (is_optimized) { - if (g->verbose) { - fprintf(stderr, "\nOptimization:\n"); - fprintf(stderr, "---------------\n"); - } - - ZigLLVMOptimizeModule(g->target_machine, g->module); - - if (g->verbose) { - LLVMDumpModule(g->module); - } + if (g->verbose) { + fprintf(stderr, "\nOptimization:\n"); + fprintf(stderr, "---------------\n"); + LLVMDumpModule(g->module); } if (g->verbose) { fprintf(stderr, "\nLink:\n"); diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp index d946426b54..1f9a82543f 100644 --- a/src/zig_llvm.cpp +++ b/src/zig_llvm.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -72,66 +73,108 @@ char *ZigLLVMGetNativeFeatures(void) { return strdup(features.getString().c_str()); } -static void addAddDiscriminatorsPass(const PassManagerBuilder &Builder, legacy::PassManagerBase &PM) { +static void addDiscriminatorsPass(const PassManagerBuilder &Builder, legacy::PassManagerBase &PM) { PM.add(createAddDiscriminatorsPass()); } +#ifndef NDEBUG +static const bool assertions_on = true; +#else +static const bool assertions_on = false; +#endif -void ZigLLVMOptimizeModule(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref) { +bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref, + const char *filename, LLVMCodeGenFileType file_type, char **error_message, bool is_debug) +{ + std::error_code EC; + raw_fd_ostream dest(filename, EC, sys::fs::F_None); + if (EC) { + *error_message = strdup(EC.message().c_str()); + return true; + } TargetMachine* target_machine = reinterpret_cast(targ_machine_ref); + target_machine->setO0WantsFastISel(true); + Module* module = unwrap(module_ref); - TargetLibraryInfoImpl tlii(Triple(module->getTargetTriple())); PassManagerBuilder *PMBuilder = new PassManagerBuilder(); PMBuilder->OptLevel = target_machine->getOptLevel(); PMBuilder->SizeLevel = 0; - PMBuilder->BBVectorize = true; - PMBuilder->SLPVectorize = true; - PMBuilder->LoopVectorize = true; - PMBuilder->DisableUnitAtATime = false; - PMBuilder->DisableUnrollLoops = false; - PMBuilder->MergeFunctions = true; - PMBuilder->PrepareForLTO = true; - PMBuilder->RerollLoops = true; - - PMBuilder->addExtension(PassManagerBuilder::EP_EarlyAsPossible, addAddDiscriminatorsPass); + PMBuilder->DisableTailCalls = is_debug; + PMBuilder->DisableUnitAtATime = is_debug; + PMBuilder->DisableUnrollLoops = is_debug; + PMBuilder->BBVectorize = !is_debug; + PMBuilder->SLPVectorize = !is_debug; + PMBuilder->LoopVectorize = !is_debug; + PMBuilder->RerollLoops = !is_debug; + PMBuilder->LoadCombine = !is_debug; + PMBuilder->NewGVN = !is_debug; + PMBuilder->DisableGVNLoadPRE = is_debug; + PMBuilder->VerifyInput = assertions_on; + PMBuilder->VerifyOutput = assertions_on; + PMBuilder->MergeFunctions = !is_debug; + PMBuilder->PrepareForLTO = false; + PMBuilder->PrepareForThinLTO = false; + PMBuilder->PerformThinLTO = false; + TargetLibraryInfoImpl tlii(Triple(module->getTargetTriple())); PMBuilder->LibraryInfo = &tlii; - PMBuilder->Inliner = createFunctionInliningPass(PMBuilder->OptLevel, PMBuilder->SizeLevel); + if (is_debug) { + PMBuilder->Inliner = createAlwaysInlinerLegacyPass(false); + } else { + PMBuilder->addExtension(PassManagerBuilder::EP_EarlyAsPossible, + [&](const PassManagerBuilder &, legacy::PassManagerBase &PM) { + target_machine->addEarlyAsPossiblePasses(PM); + }); + + PMBuilder->addExtension(PassManagerBuilder::EP_EarlyAsPossible, addDiscriminatorsPass); + PMBuilder->Inliner = createFunctionInliningPass(PMBuilder->OptLevel, PMBuilder->SizeLevel); + } // Set up the per-function pass manager. - legacy::FunctionPassManager *FPM = new legacy::FunctionPassManager(module); - FPM->add(createTargetTransformInfoWrapperPass(target_machine->getTargetIRAnalysis())); -#ifndef NDEBUG - bool verify_module = true; -#else - bool verify_module = false; -#endif - if (verify_module) { - FPM->add(createVerifierPass()); + legacy::FunctionPassManager FPM = legacy::FunctionPassManager(module); + FPM.add(new TargetLibraryInfoWrapperPass(tlii)); + FPM.add(createTargetTransformInfoWrapperPass(target_machine->getTargetIRAnalysis())); + if (assertions_on) { + FPM.add(createVerifierPass()); } - PMBuilder->populateFunctionPassManager(*FPM); + PMBuilder->populateFunctionPassManager(FPM); // Set up the per-module pass manager. - legacy::PassManager *MPM = new legacy::PassManager(); - MPM->add(createTargetTransformInfoWrapperPass(target_machine->getTargetIRAnalysis())); - - PMBuilder->populateModulePassManager(*MPM); + legacy::PassManager MPM; + MPM.add(createTargetTransformInfoWrapperPass(target_machine->getTargetIRAnalysis())); + PMBuilder->populateModulePassManager(MPM); + TargetMachine::CodeGenFileType ft; + switch (file_type) { + case LLVMAssemblyFile: + ft = TargetMachine::CGFT_AssemblyFile; + break; + default: + ft = TargetMachine::CGFT_ObjectFile; + break; + } + if (target_machine->addPassesToEmitFile(MPM, dest, ft)) { + *error_message = strdup("TargetMachine can't emit a file of this type"); + return true; + } // run per function optimization passes - FPM->doInitialization(); + FPM.doInitialization(); for (Function &F : *module) if (!F.isDeclaration()) - FPM->run(F); - FPM->doFinalization(); + FPM.run(F); + FPM.doFinalization(); - // run per module optimization passes - MPM->run(*module); + MPM.run(*module); + + dest.flush(); + return false; } + LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args, unsigned NumArgs, unsigned CC, const char *Name) { diff --git a/src/zig_llvm.hpp b/src/zig_llvm.hpp index 684b0ed301..39069c9cef 100644 --- a/src/zig_llvm.hpp +++ b/src/zig_llvm.hpp @@ -34,7 +34,8 @@ void ZigLLVMInitializeLowerIntrinsicsPass(LLVMPassRegistryRef R); char *ZigLLVMGetHostCPUName(void); char *ZigLLVMGetNativeFeatures(void); -void ZigLLVMOptimizeModule(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref); +bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref, + const char *filename, LLVMCodeGenFileType file_type, char **error_message, bool is_debug); LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args, unsigned NumArgs, unsigned CC, const char *Name);