| ... | ... | @@ -20,6 +20,7 @@ |
| 20 | 20 | #pragma GCC diagnostic ignored "-Winit-list-lifetime" |
| 21 | 21 | #endif |
| 22 | 22 | |
| 23 | #include <llvm/Analysis/AliasAnalysis.h> |
| 23 | 24 | #include <llvm/Analysis/TargetLibraryInfo.h> |
| 24 | 25 | #include <llvm/Analysis/TargetTransformInfo.h> |
| 25 | 26 | #include <llvm/Bitcode/BitcodeWriter.h> |
| ... | ... | @@ -30,9 +31,12 @@ |
| 30 | 31 | #include <llvm/IR/Instructions.h> |
| 31 | 32 | #include <llvm/IR/LegacyPassManager.h> |
| 32 | 33 | #include <llvm/IR/Module.h> |
| 34 | #include <llvm/IR/PassManager.h> |
| 33 | 35 | #include <llvm/IR/Verifier.h> |
| 34 | 36 | #include <llvm/InitializePasses.h> |
| 35 | 37 | #include <llvm/MC/SubtargetFeature.h> |
| 38 | #include <llvm/Passes/PassBuilder.h> |
| 39 | #include <llvm/Passes/StandardInstrumentations.h> |
| 36 | 40 | #include <llvm/Object/Archive.h> |
| 37 | 41 | #include <llvm/Object/ArchiveWriter.h> |
| 38 | 42 | #include <llvm/Object/COFF.h> |
| ... | ... | @@ -54,6 +58,9 @@ |
| 54 | 58 | #include <llvm/Transforms/Instrumentation/ThreadSanitizer.h> |
| 55 | 59 | #include <llvm/Transforms/Scalar.h> |
| 56 | 60 | #include <llvm/Transforms/Utils.h> |
| 61 | #include <llvm/Transforms/Utils/AddDiscriminators.h> |
| 62 | #include <llvm/Transforms/Utils/CanonicalizeAliases.h> |
| 63 | #include <llvm/Transforms/Utils/NameAnonGlobals.h> |
| 57 | 64 | |
| 58 | 65 | #include <lld/Common/Driver.h> |
| 59 | 66 | |
| ... | ... | @@ -190,12 +197,12 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM |
| 190 | 197 | { |
| 191 | 198 | TimePassesIsEnabled = time_report; |
| 192 | 199 | |
| 193 | | raw_fd_ostream *dest_asm = nullptr; |
| 194 | | raw_fd_ostream *dest_bin = nullptr; |
| 200 | raw_fd_ostream *dest_asm_ptr = nullptr; |
| 201 | raw_fd_ostream *dest_bin_ptr = nullptr; |
| 195 | 202 | |
| 196 | 203 | if (asm_filename) { |
| 197 | 204 | std::error_code EC; |
| 198 | | dest_asm = new(std::nothrow) raw_fd_ostream(asm_filename, EC, sys::fs::F_None); |
| 205 | dest_asm_ptr = new(std::nothrow) raw_fd_ostream(asm_filename, EC, sys::fs::F_None); |
| 199 | 206 | if (EC) { |
| 200 | 207 | *error_message = strdup((const char *)StringRef(EC.message()).bytes_begin()); |
| 201 | 208 | return true; |
| ... | ... | @@ -203,116 +210,128 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM |
| 203 | 210 | } |
| 204 | 211 | if (bin_filename) { |
| 205 | 212 | std::error_code EC; |
| 206 | | dest_bin = new(std::nothrow) raw_fd_ostream(bin_filename, EC, sys::fs::F_None); |
| 213 | dest_bin_ptr = new(std::nothrow) raw_fd_ostream(bin_filename, EC, sys::fs::F_None); |
| 207 | 214 | if (EC) { |
| 208 | 215 | *error_message = strdup((const char *)StringRef(EC.message()).bytes_begin()); |
| 209 | 216 | return true; |
| 210 | 217 | } |
| 211 | 218 | } |
| 212 | 219 | |
| 213 | | TargetMachine* target_machine = reinterpret_cast<TargetMachine*>(targ_machine_ref); |
| 214 | | target_machine->setO0WantsFastISel(true); |
| 215 | | |
| 216 | | Module* module = unwrap(module_ref); |
| 217 | | |
| 218 | | PassManagerBuilder *PMBuilder = new(std::nothrow) PassManagerBuilder(); |
| 219 | | if (PMBuilder == nullptr) { |
| 220 | | *error_message = strdup("memory allocation failure"); |
| 221 | | return true; |
| 222 | | } |
| 223 | | PMBuilder->OptLevel = target_machine->getOptLevel(); |
| 224 | | PMBuilder->SizeLevel = is_small ? 2 : 0; |
| 225 | | |
| 226 | | PMBuilder->DisableTailCalls = is_debug; |
| 227 | | PMBuilder->DisableUnrollLoops = is_debug; |
| 228 | | PMBuilder->SLPVectorize = !is_debug; |
| 229 | | PMBuilder->LoopVectorize = !is_debug; |
| 230 | | PMBuilder->LoopsInterleaved = !PMBuilder->DisableUnrollLoops; |
| 231 | | PMBuilder->RerollLoops = !is_debug; |
| 232 | | // Leaving NewGVN as default (off) because when on it caused issue #673 |
| 233 | | //PMBuilder->NewGVN = !is_debug; |
| 234 | | PMBuilder->DisableGVNLoadPRE = is_debug; |
| 235 | | PMBuilder->VerifyInput = assertions_on; |
| 236 | | PMBuilder->VerifyOutput = assertions_on; |
| 237 | | PMBuilder->MergeFunctions = !is_debug; |
| 238 | | PMBuilder->PrepareForLTO = lto; |
| 239 | | PMBuilder->PrepareForThinLTO = false; |
| 240 | | PMBuilder->PerformThinLTO = false; |
| 241 | | |
| 242 | | TargetLibraryInfoImpl tlii(Triple(module->getTargetTriple())); |
| 243 | | PMBuilder->LibraryInfo = &tlii; |
| 244 | | |
| 245 | | if (is_debug) { |
| 246 | | PMBuilder->Inliner = createAlwaysInlinerLegacyPass(false); |
| 247 | | } else { |
| 248 | | target_machine->adjustPassManager(*PMBuilder); |
| 249 | | |
| 250 | | PMBuilder->addExtension(PassManagerBuilder::EP_EarlyAsPossible, addDiscriminatorsPass); |
| 251 | | PMBuilder->Inliner = createFunctionInliningPass(PMBuilder->OptLevel, PMBuilder->SizeLevel, false); |
| 220 | std::unique_ptr<raw_fd_ostream> dest_asm(dest_asm_ptr), |
| 221 | dest_bin(dest_bin_ptr); |
| 222 | |
| 223 | TargetMachine &target_machine = *reinterpret_cast<TargetMachine*>(targ_machine_ref); |
| 224 | target_machine.setO0WantsFastISel(true); |
| 225 | |
| 226 | Module &module = *unwrap(module_ref); |
| 227 | |
| 228 | PipelineTuningOptions pipeline_opts; |
| 229 | pipeline_opts.LoopUnrolling = !is_debug; |
| 230 | pipeline_opts.SLPVectorization = !is_debug; |
| 231 | pipeline_opts.LoopVectorization = !is_debug; |
| 232 | pipeline_opts.LoopInterleaving = !is_debug; |
| 233 | |
| 234 | PassInstrumentationCallbacks instr_callbacks; |
| 235 | StandardInstrumentations std_instrumentations(false); |
| 236 | std_instrumentations.registerCallbacks(instr_callbacks); |
| 237 | |
| 238 | PassBuilder pass_builder(false, &target_machine, pipeline_opts, |
| 239 | None, &instr_callbacks); |
| 240 | using OptimizationLevel = typename PassBuilder::OptimizationLevel; |
| 241 | |
| 242 | LoopAnalysisManager loop_am; |
| 243 | FunctionAnalysisManager function_am; |
| 244 | CGSCCAnalysisManager cgscc_am; |
| 245 | ModuleAnalysisManager module_am; |
| 246 | |
| 247 | // Register the AA manager first so that our version is the one used |
| 248 | function_am.registerPass([&] { |
| 249 | return pass_builder.buildDefaultAAPipeline(); |
| 250 | }); |
| 251 | |
| 252 | Triple target_triple(module.getTargetTriple()); |
| 253 | auto tlii = std::make_unique<TargetLibraryInfoImpl>(target_triple); |
| 254 | function_am.registerPass([&] { return TargetLibraryAnalysis(*tlii); }); |
| 255 | |
| 256 | pass_builder.registerModuleAnalyses(module_am); |
| 257 | pass_builder.registerCGSCCAnalyses(cgscc_am); |
| 258 | pass_builder.registerFunctionAnalyses(function_am); |
| 259 | pass_builder.registerLoopAnalyses(loop_am); |
| 260 | pass_builder.crossRegisterProxies(loop_am, function_am, |
| 261 | cgscc_am, module_am); |
| 262 | |
| 263 | if (!is_debug) { |
| 264 | pass_builder.registerPipelineStartEPCallback( |
| 265 | [](ModulePassManager &module_pm, OptimizationLevel OL) { |
| 266 | module_pm.addPass( |
| 267 | createModuleToFunctionPassAdaptor(AddDiscriminatorsPass())); |
| 268 | }); |
| 252 | 269 | } |
| 253 | 270 | |
| 254 | 271 | if (tsan) { |
| 255 | | PMBuilder->addExtension(PassManagerBuilder::EP_OptimizerLast, addThreadSanitizerPass); |
| 256 | | PMBuilder->addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0, addThreadSanitizerPass); |
| 272 | pass_builder.registerOptimizerLastEPCallback( |
| 273 | [](ModulePassManager &module_pm, OptimizationLevel level) { |
| 274 | // Will be enabled regardless of optimization level |
| 275 | module_pm.addPass(ThreadSanitizerPass()); |
| 276 | }); |
| 257 | 277 | } |
| 258 | 278 | |
| 259 | | // Set up the per-function pass manager. |
| 260 | | legacy::FunctionPassManager FPM = legacy::FunctionPassManager(module); |
| 261 | | auto tliwp = new(std::nothrow) TargetLibraryInfoWrapperPass(tlii); |
| 262 | | FPM.add(tliwp); |
| 263 | | FPM.add(createTargetTransformInfoWrapperPass(target_machine->getTargetIRAnalysis())); |
| 264 | | if (assertions_on) { |
| 265 | | FPM.add(createVerifierPass()); |
| 279 | ModulePassManager module_pm; |
| 280 | // FIXME: NewPM can not detach speed level from size level |
| 281 | // we can't create something like "maximum speed level and optimal size level" |
| 282 | // which is what the original code wanted to achieve |
| 283 | OptimizationLevel opt_level; |
| 284 | if (is_debug) |
| 285 | opt_level = OptimizationLevel::O0; |
| 286 | else if (is_small) |
| 287 | opt_level = OptimizationLevel::Oz; |
| 288 | else |
| 289 | opt_level = OptimizationLevel::O3; |
| 290 | |
| 291 | if (lto) { |
| 292 | module_pm = pass_builder.buildLTOPreLinkDefaultPipeline(opt_level); |
| 293 | module_pm.addPass(CanonicalizeAliasesPass()); |
| 294 | module_pm.addPass(NameAnonGlobalPass()); |
| 295 | } else { |
| 296 | module_pm = pass_builder.buildPerModuleDefaultPipeline(opt_level); |
| 266 | 297 | } |
| 267 | | PMBuilder->populateFunctionPassManager(FPM); |
| 268 | | |
| 269 | | { |
| 270 | | // Set up the per-module pass manager. |
| 271 | | legacy::PassManager MPM; |
| 272 | | MPM.add(createTargetTransformInfoWrapperPass(target_machine->getTargetIRAnalysis())); |
| 273 | | PMBuilder->populateModulePassManager(MPM); |
| 274 | | |
| 275 | | // Set output passes. |
| 276 | | if (dest_bin && !lto) { |
| 277 | | if (target_machine->addPassesToEmitFile(MPM, *dest_bin, nullptr, CGFT_ObjectFile)) { |
| 278 | | *error_message = strdup("TargetMachine can't emit an object file"); |
| 279 | | return true; |
| 280 | | } |
| 281 | | } |
| 282 | | if (dest_asm) { |
| 283 | | if (target_machine->addPassesToEmitFile(MPM, *dest_asm, nullptr, CGFT_AssemblyFile)) { |
| 284 | | *error_message = strdup("TargetMachine can't emit an assembly file"); |
| 285 | | return true; |
| 286 | | } |
| 287 | | } |
| 288 | | |
| 289 | | // run per function optimization passes |
| 290 | | FPM.doInitialization(); |
| 291 | | for (Function &F : *module) |
| 292 | | if (!F.isDeclaration()) |
| 293 | | FPM.run(F); |
| 294 | | FPM.doFinalization(); |
| 295 | 298 | |
| 296 | | MPM.run(*module); |
| 299 | // Unfortunately we don't have new PM for code generation |
| 300 | legacy::PassManager codegen_pm; |
| 301 | codegen_pm.add( |
| 302 | createTargetTransformInfoWrapperPass(target_machine.getTargetIRAnalysis())); |
| 297 | 303 | |
| 298 | | if (llvm_ir_filename) { |
| 299 | | if (LLVMPrintModuleToFile(module_ref, llvm_ir_filename, error_message)) { |
| 300 | | return true; |
| 301 | | } |
| 304 | if (dest_bin && !lto) { |
| 305 | if (target_machine.addPassesToEmitFile(codegen_pm, *dest_bin, nullptr, CGFT_ObjectFile)) { |
| 306 | *error_message = strdup("TargetMachine can't emit an object file"); |
| 307 | return true; |
| 302 | 308 | } |
| 303 | | if (dest_bin && lto) { |
| 304 | | WriteBitcodeToFile(*module, *dest_bin); |
| 309 | } |
| 310 | if (dest_asm) { |
| 311 | if (target_machine.addPassesToEmitFile(codegen_pm, *dest_asm, nullptr, CGFT_AssemblyFile)) { |
| 312 | *error_message = strdup("TargetMachine can't emit an assembly file"); |
| 313 | return true; |
| 305 | 314 | } |
| 315 | } |
| 306 | 316 | |
| 307 | | if (time_report) { |
| 308 | | TimerGroup::printAll(errs()); |
| 309 | | } |
| 317 | // optimization |
| 318 | module_pm.run(module, module_am); |
| 310 | 319 | |
| 311 | | // MPM goes out of scope and writes to the out streams |
| 320 | // code generation |
| 321 | codegen_pm.run(module); |
| 322 | |
| 323 | if (llvm_ir_filename) { |
| 324 | if (LLVMPrintModuleToFile(module_ref, llvm_ir_filename, error_message)) { |
| 325 | return true; |
| 326 | } |
| 327 | } |
| 328 | if (dest_bin && lto) { |
| 329 | WriteBitcodeToFile(module, *dest_bin); |
| 312 | 330 | } |
| 313 | 331 | |
| 314 | | delete dest_asm; |
| 315 | | delete dest_bin; |
| 332 | if (time_report) { |
| 333 | TimerGroup::printAll(errs()); |
| 334 | } |
| 316 | 335 | |
| 317 | 336 | return false; |
| 318 | 337 | } |