GCC Code Coverage Report


Directory: ../
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 98.6% 70 / 9 / 80
Functions: 100.0% 8 / 0 / 8
Branches: 56.1% 46 / 36 / 118

src/iroptimizer/IROptimizer.cpp
Line Branch Exec Source
1 // Copyright (c) 2021-2026 ChilliBits. All rights reserved.
2
3 #include "IROptimizer.h"
4
5 #include <SourceFile.h>
6 #include <global/GlobalResourceManager.h>
7 #include <driver/Driver.h>
8
9 #include <llvm/Analysis/ModuleSummaryAnalysis.h>
10 #include <llvm/Transforms/Instrumentation/AddressSanitizer.h>
11 #include <llvm/Transforms/Instrumentation/MemorySanitizer.h>
12 #include <llvm/Transforms/Instrumentation/ThreadSanitizer.h>
13 #include <llvm/Transforms/Instrumentation/TypeSanitizer.h>
14 #include <llvm/Analysis/AliasAnalysis.h>
15
16 namespace spice::compiler {
17
18 915 IROptimizer::IROptimizer(GlobalResourceManager &resourceManager, SourceFile *sourceFile)
19 : CompilerPass(resourceManager, sourceFile),
20
3/4
✓ Branch 7 → 8 taken 3 times.
✓ Branch 7 → 9 taken 912 times.
✓ Branch 10 → 11 taken 915 times.
✗ Branch 10 → 16 not taken.
915 si(cliOptions.useLTO ? resourceManager.ltoContext : sourceFile->context, false, resourceManager.cliOptions.testMode,
21
5/10
✓ Branch 3 → 4 taken 915 times.
✗ Branch 3 → 24 not taken.
✓ Branch 4 → 5 taken 915 times.
✗ Branch 4 → 22 not taken.
✓ Branch 5 → 6 taken 915 times.
✗ Branch 5 → 20 not taken.
✓ Branch 6 → 7 taken 915 times.
✗ Branch 6 → 18 not taken.
✓ Branch 11 → 12 taken 915 times.
✗ Branch 11 → 14 not taken.
1830 llvm::PrintPassOptions(false, true, false)) {}
22
23 915 void IROptimizer::prepare() {
24
1/2
✓ Branch 2 → 3 taken 915 times.
✗ Branch 2 → 25 not taken.
915 llvm::PipelineTuningOptions pto;
25
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 915 times.
915 if (!resourceManager.cliOptions.testMode)
26 si.registerCallbacks(pic, &moduleAnalysisMgr);
27
1/2
✓ Branch 6 → 7 taken 915 times.
✗ Branch 6 → 21 not taken.
915 passBuilder = std::make_unique<llvm::PassBuilder>(sourceFile->targetMachine.get(), pto, std::nullopt, &pic);
28
29
1/2
✓ Branch 9 → 10 taken 915 times.
✗ Branch 9 → 24 not taken.
1830 functionAnalysisMgr.registerPass([&] { return passBuilder->buildDefaultAAPipeline(); });
30
31
1/2
✓ Branch 11 → 12 taken 915 times.
✗ Branch 11 → 25 not taken.
915 passBuilder->registerModuleAnalyses(moduleAnalysisMgr);
32
1/2
✓ Branch 13 → 14 taken 915 times.
✗ Branch 13 → 25 not taken.
915 passBuilder->registerCGSCCAnalyses(cgsccAnalysisMgr);
33
1/2
✓ Branch 15 → 16 taken 915 times.
✗ Branch 15 → 25 not taken.
915 passBuilder->registerFunctionAnalyses(functionAnalysisMgr);
34
1/2
✓ Branch 17 → 18 taken 915 times.
✗ Branch 17 → 25 not taken.
915 passBuilder->registerLoopAnalyses(loopAnalysisMgr);
35
1/2
✓ Branch 19 → 20 taken 915 times.
✗ Branch 19 → 25 not taken.
915 passBuilder->crossRegisterProxies(loopAnalysisMgr, functionAnalysisMgr, cgsccAnalysisMgr, moduleAnalysisMgr);
36 915 }
37
38 912 void IROptimizer::optimizeDefault() {
39 if (cliOptions.printDebugOutput && cliOptions.dump.dumpIR && !cliOptions.dump.dumpToFiles) // GCOV_EXCL_LINE
40 std::cout << "\nOptimizing on level " + std::to_string(static_cast<uint8_t>(cliOptions.optLevel)) // GCOV_EXCL_LINE
41 << " ...\n"; // GCOV_EXCL_LINE
42
43 // Prepare pipeline
44 912 const llvm::OptimizationLevel llvmOptLevel = getLLVMOptLevelFromSpiceOptLevel();
45
1/2
✓ Branch 14 → 15 taken 912 times.
✗ Branch 14 → 30 not taken.
912 llvm::ModulePassManager modulePassMgr = passBuilder->buildPerModuleDefaultPipeline(llvmOptLevel);
46
47 // Add optional passes
48
1/2
✓ Branch 15 → 16 taken 912 times.
✗ Branch 15 → 28 not taken.
912 addInstrumentationPassToPipeline(modulePassMgr);
49
50 // Run pipeline
51
1/2
✓ Branch 17 → 18 taken 912 times.
✗ Branch 17 → 27 not taken.
912 modulePassMgr.run(*sourceFile->llvmModule, moduleAnalysisMgr);
52 912 }
53
54 2 void IROptimizer::optimizePreLink() {
55 if (cliOptions.printDebugOutput && cliOptions.dump.dumpIR && !cliOptions.dump.dumpToFiles) // GCOV_EXCL_LINE
56 std::cout << "\nOptimizing on level " + std::to_string(static_cast<uint8_t>(cliOptions.optLevel)) // GCOV_EXCL_LINE
57 << " (pre-link) ...\n"; // GCOV_EXCL_LINE
58
59 // Prepare pipeline
60 2 const llvm::OptimizationLevel llvmOptLevel = getLLVMOptLevelFromSpiceOptLevel();
61
1/2
✓ Branch 14 → 15 taken 2 times.
✗ Branch 14 → 33 not taken.
2 llvm::ModulePassManager modulePassMgr = passBuilder->buildLTOPreLinkDefaultPipeline(llvmOptLevel);
62
63 // Run pipeline
64
1/2
✓ Branch 16 → 17 taken 2 times.
✗ Branch 16 → 29 not taken.
2 modulePassMgr.run(*sourceFile->llvmModule, moduleAnalysisMgr);
65
66 // Generate module summary index
67 llvm::ModuleSummaryIndexAnalysis moduleSummaryIndexAnalysis;
68
1/2
✓ Branch 19 → 20 taken 2 times.
✗ Branch 19 → 30 not taken.
2 moduleSummaryIndexAnalysis.run(*sourceFile->llvmModule, moduleAnalysisMgr);
69 2 }
70
71 1 void IROptimizer::optimizePostLink() {
72 if (cliOptions.printDebugOutput && cliOptions.dump.dumpIR && !cliOptions.dump.dumpToFiles) // GCOV_EXCL_LINE
73 std::cout << "\nOptimizing on level " + std::to_string(static_cast<uint8_t>(cliOptions.optLevel)) // GCOV_EXCL_LINE
74 << " (post-link) ...\n"; // GCOV_EXCL_LINE
75 1 llvm::Module &ltoModule = *resourceManager.ltoModule;
76
77 // Compute module summary index
78 llvm::ModuleSummaryIndexAnalysis moduleSummaryIndexAnalysis;
79
1/2
✓ Branch 13 → 14 taken 1 time.
✗ Branch 13 → 35 not taken.
1 llvm::ModuleSummaryIndex moduleSummaryIndex = moduleSummaryIndexAnalysis.run(ltoModule, moduleAnalysisMgr);
80 1 moduleSummaryIndex.setWithWholeProgramVisibility();
81
82 // Prepare pipeline
83 1 const llvm::OptimizationLevel llvmOptLevel = getLLVMOptLevelFromSpiceOptLevel();
84
1/2
✓ Branch 17 → 18 taken 1 time.
✗ Branch 17 → 33 not taken.
1 llvm::ModulePassManager modulePassMgr = passBuilder->buildLTODefaultPipeline(llvmOptLevel, &moduleSummaryIndex);
85
86 // Add optional passes
87
1/2
✓ Branch 18 → 19 taken 1 time.
✗ Branch 18 → 31 not taken.
1 addInstrumentationPassToPipeline(modulePassMgr);
88
89 // Run pipeline
90
1/2
✓ Branch 19 → 20 taken 1 time.
✗ Branch 19 → 30 not taken.
1 modulePassMgr.run(ltoModule, moduleAnalysisMgr);
91 1 }
92
93 913 void IROptimizer::addInstrumentationPassToPipeline(llvm::ModulePassManager &modulePassMgr) const {
94
5/6
✓ Branch 2 → 3 taken 898 times.
✓ Branch 2 → 4 taken 5 times.
✓ Branch 2 → 8 taken 6 times.
✓ Branch 2 → 13 taken 2 times.
✓ Branch 2 → 18 taken 2 times.
✗ Branch 2 → 20 not taken.
913 switch (cliOptions.instrumentation.sanitizer) {
95 898 case Sanitizer::NONE: {
96 898 return;
97 }
98 5 case Sanitizer::ADDRESS: {
99 5 llvm::AddressSanitizerOptions asanOptions;
100 5 asanOptions.UseAfterScope = true;
101
2/4
✓ Branch 4 → 5 taken 5 times.
✗ Branch 4 → 21 not taken.
✓ Branch 5 → 6 taken 5 times.
✗ Branch 5 → 21 not taken.
5 modulePassMgr.addPass(llvm::AddressSanitizerPass(asanOptions));
102 5 break;
103 }
104 6 case Sanitizer::THREAD: {
105
1/2
✓ Branch 8 → 9 taken 6 times.
✗ Branch 8 → 23 not taken.
6 modulePassMgr.addPass(llvm::ModuleThreadSanitizerPass());
106
2/4
✓ Branch 9 → 10 taken 6 times.
✗ Branch 9 → 26 not taken.
✓ Branch 10 → 11 taken 6 times.
✗ Branch 10 → 24 not taken.
6 modulePassMgr.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::ThreadSanitizerPass()));
107 6 break;
108 }
109 2 case Sanitizer::MEMORY: {
110
1/2
✓ Branch 13 → 14 taken 2 times.
✗ Branch 13 → 29 not taken.
2 llvm::MemorySanitizerOptions msanOptions;
111 2 msanOptions.EagerChecks = true;
112
1/2
✓ Branch 15 → 16 taken 2 times.
✗ Branch 15 → 28 not taken.
2 modulePassMgr.addPass(llvm::MemorySanitizerPass(msanOptions));
113 2 break;
114 }
115 2 case Sanitizer::TYPE: {
116
1/2
✓ Branch 18 → 19 taken 2 times.
✗ Branch 18 → 30 not taken.
2 modulePassMgr.addPass(llvm::TypeSanitizerPass());
117 2 break;
118 }
119 }
120 }
121
122 915 llvm::OptimizationLevel IROptimizer::getLLVMOptLevelFromSpiceOptLevel() const {
123
6/6
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 4 taken 23 times.
✓ Branch 2 → 5 taken 6 times.
✓ Branch 2 → 6 taken 1 time.
✓ Branch 2 → 7 taken 1 time.
✓ Branch 2 → 8 taken 883 times.
915 switch (cliOptions.optLevel) {
124 1 case OptLevel::O1:
125 1 return llvm::OptimizationLevel::O1;
126 23 case OptLevel::O2:
127 23 return llvm::OptimizationLevel::O2;
128 6 case OptLevel::O3:
129 6 return llvm::OptimizationLevel::O3;
130 1 case OptLevel::Os:
131 1 return llvm::OptimizationLevel::Os;
132 1 case OptLevel::Oz:
133 1 return llvm::OptimizationLevel::Oz;
134 883 default:
135 883 return llvm::OptimizationLevel::O0;
136 }
137 }
138
139 } // namespace spice::compiler
140