GCC Code Coverage Report


Directory: ../
File: src/iroptimizer/IROptimizer.cpp
Date: 2025-11-03 22:22:45
Coverage Exec Excl Total
Lines: 98.5% 64 9 74
Functions: 100.0% 7 0 7
Branches: 55.4% 36 36 101

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