Skip to content

Commit 68a1e9e

Browse files
committed
Finish first NewPM prototype
1 parent 21abe0b commit 68a1e9e

File tree

1 file changed

+204
-87
lines changed

1 file changed

+204
-87
lines changed

src/zig_llvm.cpp

Lines changed: 204 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,15 @@
5757

5858
#include <lld/Common/Driver.h>
5959

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+
6069
#if __GNUC__ >= 9
6170
#pragma GCC diagnostic pop
6271
#endif
@@ -183,6 +192,109 @@ unsigned ZigLLVMDataLayoutGetProgramAddressSpace(LLVMTargetDataRef TD) {
183192
return unwrap(TD)->getProgramAddressSpace();
184193
}
185194

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+
186298
bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
187299
char **error_message, bool is_debug,
188300
bool is_small, bool time_report, bool tsan, bool lto,
@@ -216,100 +328,105 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
216328

217329
Module* module = unwrap(module_ref);
218330

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))
222337
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);
248338
} 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);
253417
}
254418

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+
}
258423
}
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);
267426
}
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-
}
311427

312-
// MPM goes out of scope and writes to the out streams
428+
if (time_report) {
429+
TimerGroup::printAll(errs());
313430
}
314431

315432
delete dest_asm;

0 commit comments

Comments
 (0)