|
57 | 57 |
|
58 | 58 | #include <lld/Common/Driver.h>
|
59 | 59 |
|
| 60 | +// FIXME: Guard with macro |
| 61 | +// Headers for the new pass manager |
| 62 | +#include "llvm/IR/PassManager.h" |
| 63 | +#include "llvm/Passes/PassBuilder.h" |
| 64 | +#include "llvm/Passes/StandardInstrumentations.h" |
| 65 | +#include "llvm/Transforms/Utils/AddDiscriminators.h" |
| 66 | +#include "llvm/Transforms/Utils/CanonicalizeAliases.h" |
| 67 | +#include "llvm/Transforms/Utils/NameAnonGlobals.h" |
| 68 | + |
60 | 69 | #if __GNUC__ >= 9
|
61 | 70 | #pragma GCC diagnostic pop
|
62 | 71 | #endif
|
@@ -183,6 +192,109 @@ unsigned ZigLLVMDataLayoutGetProgramAddressSpace(LLVMTargetDataRef TD) {
|
183 | 192 | return unwrap(TD)->getProgramAddressSpace();
|
184 | 193 | }
|
185 | 194 |
|
| 195 | +static bool emitUsingNewPM(Module &module, TargetMachine &target_machine, |
| 196 | + bool is_debug, bool is_small, |
| 197 | + bool time_report, bool tsan, bool lto, |
| 198 | + raw_fd_ostream *dest_asm, raw_fd_ostream *dest_bin, |
| 199 | + char **error_message) { |
| 200 | + PipelineTuningOptions pipeline_opts; |
| 201 | + pipeline_opts.LoopUnrolling = !is_debug; |
| 202 | + pipeline_opts.SLPVectorization = !is_debug; |
| 203 | + pipeline_opts.LoopVectorization = !is_debug; |
| 204 | + pipeline_opts.LoopInterleaving = !is_debug; |
| 205 | + |
| 206 | + PassInstrumentationCallbacks instr_callbacks; |
| 207 | + StandardInstrumentations std_instrumentations; |
| 208 | + std_instrumentations.registerCallbacks(instr_callbacks); |
| 209 | + |
| 210 | + PassBuilder pass_builder(&target_machine, pipeline_opts, |
| 211 | + None, &instr_callbacks); |
| 212 | + using OptimizationLevel = typename PassBuilder::OptimizationLevel; |
| 213 | + |
| 214 | + LoopAnalysisManager loop_am; |
| 215 | + FunctionAnalysisManager function_am; |
| 216 | + CGSCCAnalysisManager cgscc_am; |
| 217 | + ModuleAnalysisManager module_am; |
| 218 | + |
| 219 | + // Register the AA manager first so that our version is the one used |
| 220 | + function_am.registerPass([&] { |
| 221 | + return pass_builder.buildDefaultAAPipeline(); |
| 222 | + }); |
| 223 | + |
| 224 | + Triple target_triple(module.getTargetTriple()); |
| 225 | + auto tlii = std::make_unique<TargetLibraryInfoImpl>(target_triple); |
| 226 | + function_am.registerPass([&] { return TargetLibraryAnalysis(*tlii); }); |
| 227 | + |
| 228 | + pass_builder.registerModuleAnalyses(module_am); |
| 229 | + pass_builder.registerCGSCCAnalyses(cgscc_am); |
| 230 | + pass_builder.registerFunctionAnalyses(function_am); |
| 231 | + pass_builder.registerLoopAnalyses(loop_am); |
| 232 | + pass_builder.crossRegisterProxies(loop_am, function_am, |
| 233 | + cgscc_am, module_am); |
| 234 | + |
| 235 | + if (!is_debug) { |
| 236 | + pass_builder.registerPipelineStartEPCallback( |
| 237 | + [](ModulePassManager &module_pm) { |
| 238 | + module_pm.addPass( |
| 239 | + createModuleToFunctionPassAdaptor(AddDiscriminatorsPass())); |
| 240 | + }); |
| 241 | + } |
| 242 | + |
| 243 | + if (tsan) { |
| 244 | + pass_builder.registerOptimizerLastEPCallback( |
| 245 | + [](ModulePassManager &module_pm, OptimizationLevel level) { |
| 246 | + // Will be enabled regardless of optimization level |
| 247 | + module_pm.addPass(ThreadSanitizerPass()); |
| 248 | + }); |
| 249 | + } |
| 250 | + |
| 251 | + ModulePassManager module_pm; |
| 252 | + // FIXME: NewPM can not detach speed level from size level |
| 253 | + // we can't create something like "maximum speed level and optimal size level" |
| 254 | + // which is what the original code wanted to achieve |
| 255 | + OptimizationLevel opt_level; |
| 256 | + if (is_debug) |
| 257 | + opt_level = OptimizationLevel::O0; |
| 258 | + else if (is_small) |
| 259 | + opt_level = OptimizationLevel::Oz; |
| 260 | + else |
| 261 | + opt_level = OptimizationLevel::O3; |
| 262 | + |
| 263 | + if (lto) { |
| 264 | + module_pm = pass_builder.buildLTOPreLinkDefaultPipeline(opt_level); |
| 265 | + module_pm.addPass(CanonicalizeAliasesPass()); |
| 266 | + module_pm.addPass(NameAnonGlobalPass()); |
| 267 | + } else { |
| 268 | + module_pm = pass_builder.buildPerModuleDefaultPipeline(opt_level); |
| 269 | + } |
| 270 | + |
| 271 | + // Unfortunately we don't have new PM for code generation |
| 272 | + legacy::PassManager codegen_pm; |
| 273 | + codegen_pm.add( |
| 274 | + createTargetTransformInfoWrapperPass(target_machine.getTargetIRAnalysis())); |
| 275 | + |
| 276 | + if (dest_bin && !lto) { |
| 277 | + if (target_machine.addPassesToEmitFile(codegen_pm, *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(codegen_pm, *dest_asm, nullptr, CGFT_AssemblyFile)) { |
| 284 | + *error_message = strdup("TargetMachine can't emit an assembly file"); |
| 285 | + return true; |
| 286 | + } |
| 287 | + } |
| 288 | + |
| 289 | + // optimization |
| 290 | + module_pm.run(module, module_am); |
| 291 | + |
| 292 | + // code generation |
| 293 | + codegen_pm.run(module); |
| 294 | + |
| 295 | + return false; |
| 296 | +} |
| 297 | + |
186 | 298 | bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
|
187 | 299 | char **error_message, bool is_debug,
|
188 | 300 | bool is_small, bool time_report, bool tsan, bool lto,
|
@@ -216,100 +328,105 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
|
216 | 328 |
|
217 | 329 | Module* module = unwrap(module_ref);
|
218 | 330 |
|
219 |
| - PassManagerBuilder *PMBuilder = new(std::nothrow) PassManagerBuilder(); |
220 |
| - if (PMBuilder == nullptr) { |
221 |
| - *error_message = strdup("memory allocation failure"); |
| 331 | + if (use_newpm) { |
| 332 | + if (emitUsingNewPM(*module, *target_machine, |
| 333 | + is_debug, is_small, |
| 334 | + time_report, tsan, lto, |
| 335 | + dest_asm, dest_bin, |
| 336 | + error_message)) |
222 | 337 | return true;
|
223 |
| - } |
224 |
| - PMBuilder->OptLevel = target_machine->getOptLevel(); |
225 |
| - PMBuilder->SizeLevel = is_small ? 2 : 0; |
226 |
| - |
227 |
| - PMBuilder->DisableTailCalls = is_debug; |
228 |
| - PMBuilder->DisableUnrollLoops = is_debug; |
229 |
| - PMBuilder->SLPVectorize = !is_debug; |
230 |
| - PMBuilder->LoopVectorize = !is_debug; |
231 |
| - PMBuilder->LoopsInterleaved = !PMBuilder->DisableUnrollLoops; |
232 |
| - PMBuilder->RerollLoops = !is_debug; |
233 |
| - // Leaving NewGVN as default (off) because when on it caused issue #673 |
234 |
| - //PMBuilder->NewGVN = !is_debug; |
235 |
| - PMBuilder->DisableGVNLoadPRE = is_debug; |
236 |
| - PMBuilder->VerifyInput = assertions_on; |
237 |
| - PMBuilder->VerifyOutput = assertions_on; |
238 |
| - PMBuilder->MergeFunctions = !is_debug; |
239 |
| - PMBuilder->PrepareForLTO = lto; |
240 |
| - PMBuilder->PrepareForThinLTO = false; |
241 |
| - PMBuilder->PerformThinLTO = false; |
242 |
| - |
243 |
| - TargetLibraryInfoImpl tlii(Triple(module->getTargetTriple())); |
244 |
| - PMBuilder->LibraryInfo = &tlii; |
245 |
| - |
246 |
| - if (is_debug) { |
247 |
| - PMBuilder->Inliner = createAlwaysInlinerLegacyPass(false); |
248 | 338 | } else {
|
249 |
| - target_machine->adjustPassManager(*PMBuilder); |
250 |
| - |
251 |
| - PMBuilder->addExtension(PassManagerBuilder::EP_EarlyAsPossible, addDiscriminatorsPass); |
252 |
| - PMBuilder->Inliner = createFunctionInliningPass(PMBuilder->OptLevel, PMBuilder->SizeLevel, false); |
| 339 | + PassManagerBuilder *PMBuilder = new(std::nothrow) PassManagerBuilder(); |
| 340 | + if (PMBuilder == nullptr) { |
| 341 | + *error_message = strdup("memory allocation failure"); |
| 342 | + return true; |
| 343 | + } |
| 344 | + PMBuilder->OptLevel = target_machine->getOptLevel(); |
| 345 | + PMBuilder->SizeLevel = is_small ? 2 : 0; |
| 346 | + |
| 347 | + PMBuilder->DisableTailCalls = is_debug; |
| 348 | + PMBuilder->DisableUnrollLoops = is_debug; |
| 349 | + PMBuilder->SLPVectorize = !is_debug; |
| 350 | + PMBuilder->LoopVectorize = !is_debug; |
| 351 | + PMBuilder->LoopsInterleaved = !PMBuilder->DisableUnrollLoops; |
| 352 | + PMBuilder->RerollLoops = !is_debug; |
| 353 | + // Leaving NewGVN as default (off) because when on it caused issue #673 |
| 354 | + //PMBuilder->NewGVN = !is_debug; |
| 355 | + PMBuilder->DisableGVNLoadPRE = is_debug; |
| 356 | + PMBuilder->VerifyInput = assertions_on; |
| 357 | + PMBuilder->VerifyOutput = assertions_on; |
| 358 | + PMBuilder->MergeFunctions = !is_debug; |
| 359 | + PMBuilder->PrepareForLTO = lto; |
| 360 | + PMBuilder->PrepareForThinLTO = false; |
| 361 | + PMBuilder->PerformThinLTO = false; |
| 362 | + |
| 363 | + TargetLibraryInfoImpl tlii(Triple(module->getTargetTriple())); |
| 364 | + PMBuilder->LibraryInfo = &tlii; |
| 365 | + |
| 366 | + if (is_debug) { |
| 367 | + PMBuilder->Inliner = createAlwaysInlinerLegacyPass(false); |
| 368 | + } else { |
| 369 | + target_machine->adjustPassManager(*PMBuilder); |
| 370 | + |
| 371 | + PMBuilder->addExtension(PassManagerBuilder::EP_EarlyAsPossible, addDiscriminatorsPass); |
| 372 | + PMBuilder->Inliner = createFunctionInliningPass(PMBuilder->OptLevel, PMBuilder->SizeLevel, false); |
| 373 | + } |
| 374 | + |
| 375 | + if (tsan) { |
| 376 | + PMBuilder->addExtension(PassManagerBuilder::EP_OptimizerLast, addThreadSanitizerPass); |
| 377 | + PMBuilder->addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0, addThreadSanitizerPass); |
| 378 | + } |
| 379 | + |
| 380 | + // Set up the per-function pass manager. |
| 381 | + legacy::FunctionPassManager FPM = legacy::FunctionPassManager(module); |
| 382 | + auto tliwp = new(std::nothrow) TargetLibraryInfoWrapperPass(tlii); |
| 383 | + FPM.add(tliwp); |
| 384 | + FPM.add(createTargetTransformInfoWrapperPass(target_machine->getTargetIRAnalysis())); |
| 385 | + if (assertions_on) { |
| 386 | + FPM.add(createVerifierPass()); |
| 387 | + } |
| 388 | + PMBuilder->populateFunctionPassManager(FPM); |
| 389 | + |
| 390 | + // Set up the per-module pass manager. |
| 391 | + legacy::PassManager MPM; |
| 392 | + MPM.add(createTargetTransformInfoWrapperPass(target_machine->getTargetIRAnalysis())); |
| 393 | + PMBuilder->populateModulePassManager(MPM); |
| 394 | + |
| 395 | + // Set output passes. |
| 396 | + if (dest_bin && !lto) { |
| 397 | + if (target_machine->addPassesToEmitFile(MPM, *dest_bin, nullptr, CGFT_ObjectFile)) { |
| 398 | + *error_message = strdup("TargetMachine can't emit an object file"); |
| 399 | + return true; |
| 400 | + } |
| 401 | + } |
| 402 | + if (dest_asm) { |
| 403 | + if (target_machine->addPassesToEmitFile(MPM, *dest_asm, nullptr, CGFT_AssemblyFile)) { |
| 404 | + *error_message = strdup("TargetMachine can't emit an assembly file"); |
| 405 | + return true; |
| 406 | + } |
| 407 | + } |
| 408 | + |
| 409 | + // run per function optimization passes |
| 410 | + FPM.doInitialization(); |
| 411 | + for (Function &F : *module) |
| 412 | + if (!F.isDeclaration()) |
| 413 | + FPM.run(F); |
| 414 | + FPM.doFinalization(); |
| 415 | + |
| 416 | + MPM.run(*module); |
253 | 417 | }
|
254 | 418 |
|
255 |
| - if (tsan) { |
256 |
| - PMBuilder->addExtension(PassManagerBuilder::EP_OptimizerLast, addThreadSanitizerPass); |
257 |
| - PMBuilder->addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0, addThreadSanitizerPass); |
| 419 | + if (llvm_ir_filename) { |
| 420 | + if (LLVMPrintModuleToFile(module_ref, llvm_ir_filename, error_message)) { |
| 421 | + return true; |
| 422 | + } |
258 | 423 | }
|
259 |
| - |
260 |
| - // Set up the per-function pass manager. |
261 |
| - legacy::FunctionPassManager FPM = legacy::FunctionPassManager(module); |
262 |
| - auto tliwp = new(std::nothrow) TargetLibraryInfoWrapperPass(tlii); |
263 |
| - FPM.add(tliwp); |
264 |
| - FPM.add(createTargetTransformInfoWrapperPass(target_machine->getTargetIRAnalysis())); |
265 |
| - if (assertions_on) { |
266 |
| - FPM.add(createVerifierPass()); |
| 424 | + if (dest_bin && lto) { |
| 425 | + WriteBitcodeToFile(*module, *dest_bin); |
267 | 426 | }
|
268 |
| - PMBuilder->populateFunctionPassManager(FPM); |
269 |
| - |
270 |
| - { |
271 |
| - // Set up the per-module pass manager. |
272 |
| - legacy::PassManager MPM; |
273 |
| - MPM.add(createTargetTransformInfoWrapperPass(target_machine->getTargetIRAnalysis())); |
274 |
| - PMBuilder->populateModulePassManager(MPM); |
275 |
| - |
276 |
| - // Set output passes. |
277 |
| - if (dest_bin && !lto) { |
278 |
| - if (target_machine->addPassesToEmitFile(MPM, *dest_bin, nullptr, CGFT_ObjectFile)) { |
279 |
| - *error_message = strdup("TargetMachine can't emit an object file"); |
280 |
| - return true; |
281 |
| - } |
282 |
| - } |
283 |
| - if (dest_asm) { |
284 |
| - if (target_machine->addPassesToEmitFile(MPM, *dest_asm, nullptr, CGFT_AssemblyFile)) { |
285 |
| - *error_message = strdup("TargetMachine can't emit an assembly file"); |
286 |
| - return true; |
287 |
| - } |
288 |
| - } |
289 |
| - |
290 |
| - // run per function optimization passes |
291 |
| - FPM.doInitialization(); |
292 |
| - for (Function &F : *module) |
293 |
| - if (!F.isDeclaration()) |
294 |
| - FPM.run(F); |
295 |
| - FPM.doFinalization(); |
296 |
| - |
297 |
| - MPM.run(*module); |
298 |
| - |
299 |
| - if (llvm_ir_filename) { |
300 |
| - if (LLVMPrintModuleToFile(module_ref, llvm_ir_filename, error_message)) { |
301 |
| - return true; |
302 |
| - } |
303 |
| - } |
304 |
| - if (dest_bin && lto) { |
305 |
| - WriteBitcodeToFile(*module, *dest_bin); |
306 |
| - } |
307 |
| - |
308 |
| - if (time_report) { |
309 |
| - TimerGroup::printAll(errs()); |
310 |
| - } |
311 | 427 |
|
312 |
| - // MPM goes out of scope and writes to the out streams |
| 428 | + if (time_report) { |
| 429 | + TimerGroup::printAll(errs()); |
313 | 430 | }
|
314 | 431 |
|
315 | 432 | delete dest_asm;
|
|
0 commit comments