authorgravatar for minyihh@uci.eduMin-Yih Hsu <minyihh@uci.edu> 2021-04-05 13:26:15-07:00
committergravatar for minyihh@uci.eduMin-Yih Hsu <minyihh@uci.edu> 2021-04-09 16:51:35-07:00
log6b3eaa62e86d2652cf0b0802d704ab16d148c2ce
tree3e150f815fea01fc581b92aa9beb306d71d6b386
parent000c0845b1ac30fe57690d71cb84847b42ad762a

Revert "Revert back to the old LLVM PassManager"

This reverts commit 09008125e7944ae01bb907f2eb8dbff41d7a0715.

1 files changed, 135 insertions(+), 96 deletions(-)

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