GCC Code Coverage Report


Directory: ../
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 98.6% 71 / 9 / 81
Functions: 100.0% 9 / 0 / 9
Branches: 52.2% 48 / 36 / 128

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