| ... | @@ -20,7 +20,6 @@ | ... | @@ -20,7 +20,6 @@ |
| 20 | #pragma GCC diagnostic ignored "-Winit-list-lifetime" | 20 | #pragma GCC diagnostic ignored "-Winit-list-lifetime" |
| 21 | #endif | 21 | #endif |
| 22 | | 22 | |
| 23 | #include <llvm/Analysis/AliasAnalysis.h> | | |
| 24 | #include <llvm/Analysis/TargetLibraryInfo.h> | 23 | #include <llvm/Analysis/TargetLibraryInfo.h> |
| 25 | #include <llvm/Analysis/TargetTransformInfo.h> | 24 | #include <llvm/Analysis/TargetTransformInfo.h> |
| 26 | #include <llvm/Bitcode/BitcodeWriter.h> | 25 | #include <llvm/Bitcode/BitcodeWriter.h> |
| ... | @@ -31,12 +30,9 @@ | ... | @@ -31,12 +30,9 @@ |
| 31 | #include <llvm/IR/Instructions.h> | 30 | #include <llvm/IR/Instructions.h> |
| 32 | #include <llvm/IR/LegacyPassManager.h> | 31 | #include <llvm/IR/LegacyPassManager.h> |
| 33 | #include <llvm/IR/Module.h> | 32 | #include <llvm/IR/Module.h> |
| 34 | #include <llvm/IR/PassManager.h> | | |
| 35 | #include <llvm/IR/Verifier.h> | 33 | #include <llvm/IR/Verifier.h> |
| 36 | #include <llvm/InitializePasses.h> | 34 | #include <llvm/InitializePasses.h> |
| 37 | #include <llvm/MC/SubtargetFeature.h> | 35 | #include <llvm/MC/SubtargetFeature.h> |
| 38 | #include <llvm/Passes/PassBuilder.h> | | |
| 39 | #include <llvm/Passes/StandardInstrumentations.h> | | |
| 40 | #include <llvm/Object/Archive.h> | 36 | #include <llvm/Object/Archive.h> |
| 41 | #include <llvm/Object/ArchiveWriter.h> | 37 | #include <llvm/Object/ArchiveWriter.h> |
| 42 | #include <llvm/Object/COFF.h> | 38 | #include <llvm/Object/COFF.h> |
| ... | @@ -58,9 +54,6 @@ | ... | @@ -58,9 +54,6 @@ |
| 58 | #include <llvm/Transforms/Instrumentation/ThreadSanitizer.h> | 54 | #include <llvm/Transforms/Instrumentation/ThreadSanitizer.h> |
| 59 | #include <llvm/Transforms/Scalar.h> | 55 | #include <llvm/Transforms/Scalar.h> |
| 60 | #include <llvm/Transforms/Utils.h> | 56 | #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> | | |
| 64 | | 57 | |
| 65 | #include <lld/Common/Driver.h> | 58 | #include <lld/Common/Driver.h> |
| 66 | | 59 | |
| ... | @@ -98,6 +91,14 @@ char *ZigLLVMGetNativeFeatures(void) { | ... | @@ -98,6 +91,14 @@ char *ZigLLVMGetNativeFeatures(void) { |
| 98 | return strdup((const char *)StringRef(features.getString()).bytes_begin()); | 91 | return strdup((const char *)StringRef(features.getString()).bytes_begin()); |
| 99 | } | 92 | } |
| 100 | | 93 | |
| | 94 | static void addDiscriminatorsPass(const PassManagerBuilder &Builder, legacy::PassManagerBase &PM) { |
| | 95 | PM.add(createAddDiscriminatorsPass()); |
| | 96 | } |
| | 97 | |
| | 98 | static void addThreadSanitizerPass(const PassManagerBuilder &Builder, legacy::PassManagerBase &PM) { |
| | 99 | PM.add(createThreadSanitizerLegacyPassPass()); |
| | 100 | } |
| | 101 | |
| 101 | #ifndef NDEBUG | 102 | #ifndef NDEBUG |
| 102 | static const bool assertions_on = true; | 103 | static const bool assertions_on = true; |
| 103 | #else | 104 | #else |
| ... | @@ -187,16 +188,14 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM | ... | @@ -187,16 +188,14 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM |
| 187 | bool is_small, bool time_report, bool tsan, bool lto, | 188 | bool is_small, bool time_report, bool tsan, bool lto, |
| 188 | const char *asm_filename, const char *bin_filename, const char *llvm_ir_filename) | 189 | const char *asm_filename, const char *bin_filename, const char *llvm_ir_filename) |
| 189 | { | 190 | { |
| 190 | // TODO: Maybe we should collect time trace rather than using timer | | |
| 191 | // to get a more hierarchical timeline view | | |
| 192 | TimePassesIsEnabled = time_report; | 191 | TimePassesIsEnabled = time_report; |
| 193 | | 192 | |
| 194 | raw_fd_ostream *dest_asm_ptr = nullptr; | 193 | raw_fd_ostream *dest_asm = nullptr; |
| 195 | raw_fd_ostream *dest_bin_ptr = nullptr; | 194 | raw_fd_ostream *dest_bin = nullptr; |
| 196 | | 195 | |
| 197 | if (asm_filename) { | 196 | if (asm_filename) { |
| 198 | std::error_code EC; | 197 | std::error_code EC; |
| 199 | dest_asm_ptr = new(std::nothrow) raw_fd_ostream(asm_filename, EC, sys::fs::F_None); | 198 | dest_asm = new(std::nothrow) raw_fd_ostream(asm_filename, EC, sys::fs::F_None); |
| 200 | if (EC) { | 199 | if (EC) { |
| 201 | *error_message = strdup((const char *)StringRef(EC.message()).bytes_begin()); | 200 | *error_message = strdup((const char *)StringRef(EC.message()).bytes_begin()); |
| 202 | return true; | 201 | return true; |
| ... | @@ -204,155 +203,117 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM | ... | @@ -204,155 +203,117 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM |
| 204 | } | 203 | } |
| 205 | if (bin_filename) { | 204 | if (bin_filename) { |
| 206 | std::error_code EC; | 205 | std::error_code EC; |
| 207 | dest_bin_ptr = new(std::nothrow) raw_fd_ostream(bin_filename, EC, sys::fs::F_None); | 206 | dest_bin = new(std::nothrow) raw_fd_ostream(bin_filename, EC, sys::fs::F_None); |
| 208 | if (EC) { | 207 | if (EC) { |
| 209 | *error_message = strdup((const char *)StringRef(EC.message()).bytes_begin()); | 208 | *error_message = strdup((const char *)StringRef(EC.message()).bytes_begin()); |
| 210 | return true; | 209 | return true; |
| 211 | } | 210 | } |
| 212 | } | 211 | } |
| 213 | | 212 | |
| 214 | std::unique_ptr<raw_fd_ostream> dest_asm(dest_asm_ptr), | 213 | TargetMachine* target_machine = reinterpret_cast<TargetMachine*>(targ_machine_ref); |
| 215 | dest_bin(dest_bin_ptr); | 214 | target_machine->setO0WantsFastISel(true); |
| 216 | | 215 | |
| 217 | TargetMachine &target_machine = *reinterpret_cast<TargetMachine*>(targ_machine_ref); | 216 | Module* module = unwrap(module_ref); |
| 218 | target_machine.setO0WantsFastISel(true); | 217 | |
| 219 | | 218 | PassManagerBuilder *PMBuilder = new(std::nothrow) PassManagerBuilder(); |
| 220 | Module &module = *unwrap(module_ref); | 219 | if (PMBuilder == nullptr) { |
| 221 | | 220 | *error_message = strdup("memory allocation failure"); |
| 222 | // Pipeline configurations | 221 | return true; |
| 223 | PipelineTuningOptions pipeline_opts; | | |
| 224 | pipeline_opts.LoopUnrolling = !is_debug; | | |
| 225 | pipeline_opts.SLPVectorization = !is_debug; | | |
| 226 | pipeline_opts.LoopVectorization = !is_debug; | | |
| 227 | pipeline_opts.LoopInterleaving = !is_debug; | | |
| 228 | pipeline_opts.MergeFunctions = !is_debug; | | |
| 229 | | | |
| 230 | // Instrumentations | | |
| 231 | PassInstrumentationCallbacks instr_callbacks; | | |
| 232 | StandardInstrumentations std_instrumentations(false); | | |
| 233 | std_instrumentations.registerCallbacks(instr_callbacks); | | |
| 234 | | | |
| 235 | PassBuilder pass_builder(false, &target_machine, pipeline_opts, | | |
| 236 | None, &instr_callbacks); | | |
| 237 | using OptimizationLevel = typename PassBuilder::OptimizationLevel; | | |
| 238 | | | |
| 239 | LoopAnalysisManager loop_am; | | |
| 240 | FunctionAnalysisManager function_am; | | |
| 241 | CGSCCAnalysisManager cgscc_am; | | |
| 242 | ModuleAnalysisManager module_am; | | |
| 243 | | | |
| 244 | // Register the AA manager first so that our version is the one used | | |
| 245 | function_am.registerPass([&] { | | |
| 246 | return pass_builder.buildDefaultAAPipeline(); | | |
| 247 | }); | | |
| 248 | | | |
| 249 | Triple target_triple(module.getTargetTriple()); | | |
| 250 | auto tlii = std::make_unique<TargetLibraryInfoImpl>(target_triple); | | |
| 251 | function_am.registerPass([&] { return TargetLibraryAnalysis(*tlii); }); | | |
| 252 | | | |
| 253 | // Initialize the AnalysisManagers | | |
| 254 | pass_builder.registerModuleAnalyses(module_am); | | |
| 255 | pass_builder.registerCGSCCAnalyses(cgscc_am); | | |
| 256 | pass_builder.registerFunctionAnalyses(function_am); | | |
| 257 | pass_builder.registerLoopAnalyses(loop_am); | | |
| 258 | pass_builder.crossRegisterProxies(loop_am, function_am, | | |
| 259 | cgscc_am, module_am); | | |
| 260 | | | |
| 261 | // IR verification | | |
| 262 | if (assertions_on) { | | |
| 263 | // Verify the input | | |
| 264 | pass_builder.registerPipelineStartEPCallback( | | |
| 265 | [](ModulePassManager &module_pm, OptimizationLevel OL) { | | |
| 266 | module_pm.addPass(VerifierPass()); | | |
| 267 | }); | | |
| 268 | // Verify the output | | |
| 269 | pass_builder.registerOptimizerLastEPCallback( | | |
| 270 | [](ModulePassManager &module_pm, OptimizationLevel OL) { | | |
| 271 | module_pm.addPass(VerifierPass()); | | |
| 272 | }); | | |
| 273 | } | 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; |
| 274 | | 244 | |
| 275 | // Passes for either debug or release build | | |
| 276 | if (is_debug) { | 245 | if (is_debug) { |
| 277 | // NOTE: Always inliner will go away (in debug build) | 246 | PMBuilder->Inliner = createAlwaysInlinerLegacyPass(false); |
| 278 | // when the self-hosted compiler becomes mature. | | |
| 279 | pass_builder.registerPipelineStartEPCallback( | | |
| 280 | [](ModulePassManager &module_pm, OptimizationLevel OL) { | | |
| 281 | module_pm.addPass(AlwaysInlinerPass()); | | |
| 282 | }); | | |
| 283 | } else { | 247 | } else { |
| 284 | pass_builder.registerPipelineStartEPCallback( | 248 | target_machine->adjustPassManager(*PMBuilder); |
| 285 | [](ModulePassManager &module_pm, OptimizationLevel OL) { | 249 | |
| 286 | module_pm.addPass( | 250 | PMBuilder->addExtension(PassManagerBuilder::EP_EarlyAsPossible, addDiscriminatorsPass); |
| 287 | createModuleToFunctionPassAdaptor(AddDiscriminatorsPass())); | 251 | PMBuilder->Inliner = createFunctionInliningPass(PMBuilder->OptLevel, PMBuilder->SizeLevel, false); |
| 288 | }); | | |
| 289 | } | 252 | } |
| 290 | | 253 | |
| 291 | // Thread sanitizer | | |
| 292 | if (tsan) { | 254 | if (tsan) { |
| 293 | pass_builder.registerOptimizerLastEPCallback( | 255 | PMBuilder->addExtension(PassManagerBuilder::EP_OptimizerLast, addThreadSanitizerPass); |
| 294 | [](ModulePassManager &module_pm, OptimizationLevel level) { | 256 | PMBuilder->addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0, addThreadSanitizerPass); |
| 295 | module_pm.addPass(ThreadSanitizerPass()); | | |
| 296 | }); | | |
| 297 | } | 257 | } |
| 298 | | 258 | |
| 299 | ModulePassManager module_pm; | 259 | // Set up the per-function pass manager. |
| 300 | OptimizationLevel opt_level; | 260 | legacy::FunctionPassManager FPM = legacy::FunctionPassManager(module); |
| 301 | // Setting up the optimization level | 261 | auto tliwp = new(std::nothrow) TargetLibraryInfoWrapperPass(tlii); |
| 302 | if (is_debug) | 262 | FPM.add(tliwp); |
| 303 | opt_level = OptimizationLevel::O0; | 263 | FPM.add(createTargetTransformInfoWrapperPass(target_machine->getTargetIRAnalysis())); |
| 304 | else if (is_small) | 264 | if (assertions_on) { |
| 305 | opt_level = OptimizationLevel::Oz; | 265 | FPM.add(createVerifierPass()); |
| 306 | else | | |
| 307 | opt_level = OptimizationLevel::O3; | | |
| 308 | | | |
| 309 | // Initialize the PassManager | | |
| 310 | if (lto) { | | |
| 311 | module_pm = pass_builder.buildLTOPreLinkDefaultPipeline(opt_level); | | |
| 312 | module_pm.addPass(CanonicalizeAliasesPass()); | | |
| 313 | module_pm.addPass(NameAnonGlobalPass()); | | |
| 314 | } else { | | |
| 315 | module_pm = pass_builder.buildPerModuleDefaultPipeline(opt_level); | | |
| 316 | } | 266 | } |
| 317 | | 267 | PMBuilder->populateFunctionPassManager(FPM); |
| 318 | // Unfortunately we don't have new PM for code generation | 268 | |
| 319 | legacy::PassManager codegen_pm; | 269 | { |
| 320 | codegen_pm.add( | 270 | // Set up the per-module pass manager. |
| 321 | createTargetTransformInfoWrapperPass(target_machine.getTargetIRAnalysis())); | 271 | legacy::PassManager MPM; |
| 322 | | 272 | MPM.add(createTargetTransformInfoWrapperPass(target_machine->getTargetIRAnalysis())); |
| 323 | if (dest_bin && !lto) { | 273 | PMBuilder->populateModulePassManager(MPM); |
| 324 | if (target_machine.addPassesToEmitFile(codegen_pm, *dest_bin, nullptr, CGFT_ObjectFile)) { | 274 | |
| 325 | *error_message = strdup("TargetMachine can't emit an object file"); | 275 | // Set output passes. |
| 326 | return true; | 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 | } |
| 327 | } | 281 | } |
| 328 | } | 282 | if (dest_asm) { |
| 329 | if (dest_asm) { | 283 | if (target_machine->addPassesToEmitFile(MPM, *dest_asm, nullptr, CGFT_AssemblyFile)) { |
| 330 | if (target_machine.addPassesToEmitFile(codegen_pm, *dest_asm, nullptr, CGFT_AssemblyFile)) { | 284 | *error_message = strdup("TargetMachine can't emit an assembly file"); |
| 331 | *error_message = strdup("TargetMachine can't emit an assembly file"); | 285 | return true; |
| 332 | return true; | 286 | } |
| 333 | } | 287 | } |
| 334 | } | | |
| 335 | | 288 | |
| 336 | // Optimization phase | 289 | // run per function optimization passes |
| 337 | module_pm.run(module, module_am); | 290 | FPM.doInitialization(); |
| | 291 | for (Function &F : *module) |
| | 292 | if (!F.isDeclaration()) |
| | 293 | FPM.run(F); |
| | 294 | FPM.doFinalization(); |
| 338 | | 295 | |
| 339 | // Code generation phase | 296 | MPM.run(*module); |
| 340 | codegen_pm.run(module); | | |
| 341 | | 297 | |
| 342 | if (llvm_ir_filename) { | 298 | if (llvm_ir_filename) { |
| 343 | if (LLVMPrintModuleToFile(module_ref, llvm_ir_filename, error_message)) { | 299 | if (LLVMPrintModuleToFile(module_ref, llvm_ir_filename, error_message)) { |
| 344 | return true; | 300 | return true; |
| | 301 | } |
| | 302 | } |
| | 303 | if (dest_bin && lto) { |
| | 304 | WriteBitcodeToFile(*module, *dest_bin); |
| 345 | } | 305 | } |
| 346 | } | | |
| 347 | | 306 | |
| 348 | if (dest_bin && lto) { | 307 | if (time_report) { |
| 349 | WriteBitcodeToFile(module, *dest_bin); | 308 | TimerGroup::printAll(errs()); |
| 350 | } | 309 | } |
| 351 | | 310 | |
| 352 | if (time_report) { | 311 | // MPM goes out of scope and writes to the out streams |
| 353 | TimerGroup::printAll(errs()); | | |
| 354 | } | 312 | } |
| 355 | | 313 | |
| | 314 | delete dest_asm; |
| | 315 | delete dest_bin; |
| | 316 | |
| 356 | return false; | 317 | return false; |
| 357 | } | 318 | } |
| 358 | | 319 | |