From 7f47b0c271931466d8ce88c0928ff2bef8f8109f Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 11 Apr 2017 03:37:44 -0400 Subject: [PATCH] run alwaysinline pass in debug mode before this commit, the optimized IR code that is displayed in --verbose mode is not actually what gets emitted to an object file. that is now corrected, and we make sure to run the alwaysinliner pass even in debug mode, so you can rely on "inline" keyword inlining a function, guaranteed. See #306 --- src/codegen.cpp | 4 +- src/link.cpp | 16 ++----- src/zig_llvm.cpp | 109 +++++++++++++++++++++++++++++++++-------------- src/zig_llvm.hpp | 3 +- 4 files changed, 84 insertions(+), 48 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 54a76d9b540a5689097cd9c0392ca40a32c3cd8b..938798f505117c1d0c4ce58a2913950b80aa841e 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 ebabdd46aae0feff35662e74d27ff75c250fc2c6..b9328eff28b66a3dfcf7a9701a7b137c309aeb79 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 d946426b54c091bacc0e9dc0855ccfa96b9e709d..1f9a82543f9564ffca549a9eea42a6fd698e2c98 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 684b0ed301f8b73e7e94bc0192358441d9540bcb..39069c9cef0c9a3f2d61a46a89b12a363b897334 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); -- 2.54.0