GCC Code Coverage Report


Directory: ../
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 89.8% 292 / 3 / 328
Functions: 84.4% 27 / 0 / 32
Branches: 49.9% 390 / 8 / 790

src/driver/Driver.cpp
Line Branch Exec Source
1 // Copyright (c) 2021-2026 ChilliBits. All rights reserved.
2
3 #include "Driver.h"
4
5 #include <exception/CliError.h>
6 #include <util/CommonUtil.h>
7 #include <util/CompilerWarning.h>
8 #include <util/SystemUtil.h>
9
10 #include <llvm/Support/CommandLine.h>
11 #include <llvm/TargetParser/Host.h>
12 #include <llvm/TargetParser/Triple.h>
13
14 namespace spice::compiler {
15
16
3/6
✓ Branch 4 → 5 taken 624 times.
✗ Branch 4 → 52 not taken.
✓ Branch 7 → 8 taken 624 times.
✗ Branch 7 → 46 not taken.
✓ Branch 8 → 9 taken 624 times.
✗ Branch 8 → 44 not taken.
2496 Driver::Driver(CliOptions &foreignCliOptions, bool dryRun) : cliOptions(foreignCliOptions), performDryRun(dryRun) {
17 // Allow positional args
18 624 app.positionals_at_end();
19 624 app.allow_extras(false);
20
2/4
✓ Branch 15 → 16 taken 624 times.
✗ Branch 15 → 58 not taken.
✓ Branch 17 → 18 taken 624 times.
✗ Branch 17 → 56 not taken.
624 app.footer("(c) Marc Auberer 2021-" + std::to_string(CommonUtil::getCurrentYear()));
21
22 // Add version flag
23
3/6
✓ Branch 24 → 25 taken 624 times.
✗ Branch 24 → 68 not taken.
✓ Branch 27 → 28 taken 624 times.
✗ Branch 27 → 62 not taken.
✓ Branch 28 → 29 taken 624 times.
✗ Branch 28 → 60 not taken.
2496 app.set_version_flag("--version,-v", CommonUtil::buildVersionInfo());
24
25 // Create sub-commands
26
1/2
✓ Branch 34 → 35 taken 624 times.
✗ Branch 34 → 75 not taken.
624 addBuildSubcommand();
27
1/2
✓ Branch 35 → 36 taken 624 times.
✗ Branch 35 → 75 not taken.
624 addRunSubcommand();
28
1/2
✓ Branch 36 → 37 taken 624 times.
✗ Branch 36 → 75 not taken.
624 addTestSubcommand();
29
1/2
✓ Branch 37 → 38 taken 624 times.
✗ Branch 37 → 75 not taken.
624 addLintSubcommand();
30
1/2
✓ Branch 38 → 39 taken 624 times.
✗ Branch 38 → 75 not taken.
624 addInstallSubcommand();
31
1/2
✓ Branch 39 → 40 taken 624 times.
✗ Branch 39 → 75 not taken.
624 addUninstallSubcommand();
32
33 624 app.final_callback([&] {
34 // Print help text for the root command if no sub-command was given
35
2/4
✓ Branch 2 → 3 taken 619 times.
✗ Branch 2 → 124 not taken.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 15 taken 619 times.
619 if (app.get_subcommands().empty()) {
36 std::cout << app.help();
37 return;
38 }
39
40
4/4
✓ Branch 15 → 16 taken 618 times.
✓ Branch 15 → 17 taken 1 time.
✓ Branch 16 → 17 taken 1 time.
✓ Branch 16 → 52 taken 617 times.
619 if (shouldInstall || shouldUninstall) {
41 // Prepare the installation path
42
1/2
✓ Branch 17 → 18 taken 2 times.
✗ Branch 17 → 152 not taken.
2 std::filesystem::path installPath = SystemUtil::getSpiceBinDir();
43
2/4
✓ Branch 18 → 19 taken 2 times.
✗ Branch 18 → 136 not taken.
✓ Branch 19 → 20 taken 2 times.
✗ Branch 19 → 134 not taken.
2 installPath /= cliOptions.mainSourceFile.stem();
44
1/2
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 23 taken 2 times.
2 if (!performDryRun)
45 create_directories(installPath);
46
1/2
✗ Branch 23 → 24 not taken.
✓ Branch 23 → 25 taken 2 times.
2 assert(cliOptions.outputContainer == OutputContainer::EXECUTABLE);
47
3/6
✓ Branch 25 → 26 taken 2 times.
✗ Branch 25 → 139 not taken.
✓ Branch 26 → 27 taken 2 times.
✗ Branch 26 → 139 not taken.
✓ Branch 27 → 28 taken 2 times.
✗ Branch 27 → 137 not taken.
2 installPath.replace_extension(SystemUtil::getOutputFileExtension(cliOptions, OutputContainer::EXECUTABLE));
48
49 // If the binary should be installed, set the output path to the Spice bin directory
50
2/2
✓ Branch 29 → 30 taken 1 time.
✓ Branch 29 → 31 taken 1 time.
2 if (shouldInstall)
51
1/2
✓ Branch 30 → 31 taken 1 time.
✗ Branch 30 → 150 not taken.
1 cliOptions.outputPath = installPath;
52
53 // If the binary should be uninstalled, check if the executable exists and uninstall it
54
3/4
✓ Branch 31 → 32 taken 1 time.
✓ Branch 31 → 50 taken 1 time.
✗ Branch 32 → 33 not taken.
✓ Branch 32 → 50 taken 1 time.
2 if (shouldUninstall && !performDryRun) {
55 if (exists(installPath) && std::filesystem::remove(installPath))
56 std::cout << "Successfully uninstalled.\n";
57 else
58 CompilerWarning(UNINSTALL_FAILED, "The executable was not found at the expected location").print();
59 }
60 2 }
61
62 // Abort here if we do not need to compile
63
2/2
✓ Branch 52 → 53 taken 1 time.
✓ Branch 52 → 54 taken 618 times.
619 if (!shouldCompile)
64 1 return;
65
66 // Set output path and dir
67
2/2
✓ Branch 54 → 55 taken 4 times.
✓ Branch 54 → 82 taken 614 times.
618 if (shouldExecute) {
68 4 cliOptions.execute = true;
69 const uint64_t millis =
70
1/2
✓ Branch 57 → 58 taken 4 times.
✗ Branch 57 → 153 not taken.
4 duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
71
8/16
✓ Branch 59 → 60 taken 4 times.
✗ Branch 59 → 175 not taken.
✓ Branch 60 → 61 taken 4 times.
✗ Branch 60 → 173 not taken.
✓ Branch 61 → 62 taken 4 times.
✗ Branch 61 → 169 not taken.
✓ Branch 62 → 63 taken 4 times.
✗ Branch 62 → 165 not taken.
✓ Branch 63 → 64 taken 4 times.
✗ Branch 63 → 162 not taken.
✓ Branch 64 → 65 taken 4 times.
✗ Branch 64 → 160 not taken.
✓ Branch 65 → 66 taken 4 times.
✗ Branch 65 → 158 not taken.
✓ Branch 66 → 67 taken 4 times.
✗ Branch 66 → 156 not taken.
4 cliOptions.outputDir = std::filesystem::temp_directory_path() / "spice" / "output" / std::to_string(millis);
72
2/4
✓ Branch 76 → 77 taken 4 times.
✗ Branch 76 → 180 not taken.
✓ Branch 77 → 78 taken 4 times.
✗ Branch 77 → 178 not taken.
4 cliOptions.outputPath = cliOptions.outputDir / cliOptions.mainSourceFile.filename();
73
2/2
✓ Branch 83 → 84 taken 1 time.
✓ Branch 83 → 99 taken 613 times.
614 } else if (!cliOptions.outputPath.empty()) {
74
1/2
✗ Branch 85 → 86 not taken.
✓ Branch 85 → 93 taken 1 time.
1 if (is_directory(cliOptions.outputPath)) {
75 cliOptions.outputDir = cliOptions.outputPath;
76 cliOptions.outputPath = cliOptions.outputDir / cliOptions.mainSourceFile.filename();
77
1/2
✓ Branch 94 → 95 taken 1 time.
✗ Branch 94 → 106 not taken.
1 } else if (cliOptions.outputPath.has_parent_path()) {
78
1/2
✓ Branch 95 → 96 taken 1 time.
✗ Branch 95 → 186 not taken.
1 cliOptions.outputDir = cliOptions.outputPath.parent_path();
79 }
80 } else {
81 613 cliOptions.outputDir = "./";
82
2/4
✓ Branch 100 → 101 taken 613 times.
✗ Branch 100 → 189 not taken.
✓ Branch 101 → 102 taken 613 times.
✗ Branch 101 → 187 not taken.
613 cliOptions.outputPath = cliOptions.outputDir / cliOptions.mainSourceFile.filename();
83 }
84
85 // Set output file extension
86
3/6
✓ Branch 106 → 107 taken 618 times.
✗ Branch 106 → 193 not taken.
✓ Branch 107 → 108 taken 618 times.
✗ Branch 107 → 193 not taken.
✓ Branch 108 → 109 taken 618 times.
✗ Branch 108 → 191 not taken.
618 cliOptions.outputPath.replace_extension(SystemUtil::getOutputFileExtension(cliOptions, cliOptions.outputContainer));
87
88 // Set cache dir
89
5/10
✓ Branch 110 → 111 taken 618 times.
✗ Branch 110 → 206 not taken.
✓ Branch 111 → 112 taken 618 times.
✗ Branch 111 → 202 not taken.
✓ Branch 112 → 113 taken 618 times.
✗ Branch 112 → 199 not taken.
✓ Branch 113 → 114 taken 618 times.
✗ Branch 113 → 197 not taken.
✓ Branch 114 → 115 taken 618 times.
✗ Branch 114 → 195 not taken.
618 cliOptions.cacheDir = std::filesystem::temp_directory_path() / "spice" / "cache";
90
91 // Create directories in case they not exist yet
92 618 create_directories(cliOptions.cacheDir);
93 618 create_directories(cliOptions.outputDir);
94 });
95 624 }
96
97 /**
98 * Start the parsing process
99 *
100 * @param argc Argument count
101 * @param argv Argument vector
102 * @return Return code
103 */
104 624 int Driver::parse(int argc, const char *argv[]) {
105 try {
106
2/2
✓ Branch 2 → 3 taken 619 times.
✓ Branch 2 → 5 taken 1 time.
624 app.parse(argc, argv);
107 619 return EXIT_SUCCESS;
108
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 1 time.
1 } catch (const CLI::ParseError &parseError) {
109
1/2
✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 11 not taken.
1 return app.exit(parseError);
110 1 }
111 }
112
113 /**
114 * Initialize the cli options based on the input of the user
115 */
116 620 void Driver::enrich() const {
117 // Make path of given main source file canonical and relative
118
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 9 taken 620 times.
620 if (!performDryRun)
119 cliOptions.mainSourceFile = relative(cliOptions.mainSourceFile);
120
121 // Propagate llvm args to llvm
122
1/2
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 39 taken 620 times.
620 if (!cliOptions.llvmArgs.empty()) {
123 const std::vector<std::string> result = CommonUtil::split("llvm " + cliOptions.llvmArgs);
124 std::vector<const char *> resultCStr;
125 resultCStr.reserve(result.size());
126 for (const std::string &str : result)
127 resultCStr.push_back(str.c_str());
128 llvm::cl::ParseCommandLineOptions(static_cast<int>(result.size()), resultCStr.data());
129 }
130
131 // Propagate target information
132
3/6
✓ Branch 39 → 40 taken 620 times.
✗ Branch 39 → 241 not taken.
✓ Branch 41 → 42 taken 620 times.
✗ Branch 41 → 239 not taken.
✓ Branch 42 → 43 taken 620 times.
✗ Branch 42 → 237 not taken.
620 const llvm::Triple defaultTriple(llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple()));
133
2/2
✓ Branch 46 → 47 taken 613 times.
✓ Branch 46 → 65 taken 7 times.
620 if (cliOptions.targetTriple.empty()) {
134
2/4
✓ Branch 47 → 48 taken 613 times.
✗ Branch 47 → 365 not taken.
✓ Branch 48 → 49 taken 613 times.
✗ Branch 48 → 57 not taken.
613 if (cliOptions.targetArch == TARGET_UNKNOWN) { // We have nothing -> obtain native triplet
135
1/2
✓ Branch 49 → 50 taken 613 times.
✗ Branch 49 → 365 not taken.
613 cliOptions.targetTriple = defaultTriple;
136
2/4
✓ Branch 50 → 51 taken 613 times.
✗ Branch 50 → 244 not taken.
✓ Branch 51 → 52 taken 613 times.
✗ Branch 51 → 244 not taken.
613 cliOptions.targetArch = defaultTriple.getArchName();
137
2/4
✓ Branch 52 → 53 taken 613 times.
✗ Branch 52 → 245 not taken.
✓ Branch 53 → 54 taken 613 times.
✗ Branch 53 → 245 not taken.
613 cliOptions.targetVendor = defaultTriple.getVendorName();
138
2/4
✓ Branch 54 → 55 taken 613 times.
✗ Branch 54 → 246 not taken.
✓ Branch 55 → 56 taken 613 times.
✗ Branch 55 → 246 not taken.
613 cliOptions.targetOs = defaultTriple.getOSName();
139 613 cliOptions.isNativeTarget = true;
140 } else { // We have arch, vendor and os -> obtain triplet
141 cliOptions.targetTriple = llvm::Triple(cliOptions.targetArch, cliOptions.targetVendor, cliOptions.targetOs);
142 cliOptions.isNativeTarget = cliOptions.targetTriple == defaultTriple;
143 }
144 } else { // Obtain arch, vendor and os by the triplet
145
2/4
✓ Branch 65 → 66 taken 7 times.
✗ Branch 65 → 253 not taken.
✓ Branch 66 → 67 taken 7 times.
✗ Branch 66 → 251 not taken.
7 const llvm::Triple triple(cliOptions.targetTriple.normalize());
146
2/4
✓ Branch 68 → 69 taken 7 times.
✗ Branch 68 → 254 not taken.
✓ Branch 69 → 70 taken 7 times.
✗ Branch 69 → 254 not taken.
7 cliOptions.targetArch = triple.getArchName();
147
2/4
✓ Branch 70 → 71 taken 7 times.
✗ Branch 70 → 255 not taken.
✓ Branch 71 → 72 taken 7 times.
✗ Branch 71 → 255 not taken.
7 cliOptions.targetVendor = triple.getVendorName();
148
2/4
✓ Branch 72 → 73 taken 7 times.
✗ Branch 72 → 256 not taken.
✓ Branch 73 → 74 taken 7 times.
✗ Branch 73 → 256 not taken.
7 cliOptions.targetOs = triple.getOSName();
149
1/2
✓ Branch 74 → 75 taken 7 times.
✗ Branch 74 → 257 not taken.
7 cliOptions.isNativeTarget = triple == defaultTriple;
150 7 }
151
152 // Always preserve IR value names when dumping IR
153
2/2
✓ Branch 77 → 78 taken 1 time.
✓ Branch 77 → 79 taken 619 times.
620 if (cliOptions.dump.dumpIR)
154 1 cliOptions.namesForIRValues = true;
155
156 // Enable test mode when test mode was selected
157
2/2
✓ Branch 79 → 80 taken 2 times.
✓ Branch 79 → 81 taken 618 times.
620 if (cliOptions.buildMode == BuildMode::TEST) {
158 2 cliOptions.noEntryFct = true;
159 2 cliOptions.generateTestMain = true;
160 }
161
162 620 const Sanitizer sanitizer = cliOptions.instrumentation.sanitizer;
163 // Memory sanitizer is only supported on Linux
164
4/6
✓ Branch 82 → 83 taken 4 times.
✓ Branch 82 → 85 taken 616 times.
✗ Branch 83 → 84 not taken.
✓ Branch 83 → 85 taken 4 times.
✗ Branch 86 → 87 not taken.
✓ Branch 86 → 95 taken 620 times.
620 if (!cliOptions.targetTriple.isOSLinux() && sanitizer == Sanitizer::MEMORY)
165 throw CliError(FEATURE_NOT_SUPPORTED_FOR_TARGET, "Memory sanitizer is only supported for Linux targets");
166 // Some sanitizers need lifetime markers to work properly
167
4/4
✓ Branch 95 → 96 taken 613 times.
✓ Branch 95 → 97 taken 7 times.
✓ Branch 96 → 97 taken 3 times.
✓ Branch 96 → 98 taken 610 times.
620 if (sanitizer == Sanitizer::ADDRESS || sanitizer == Sanitizer::MEMORY)
168 10 cliOptions.useLifetimeMarkers = true;
169 // Type sanitizer needs TBAA metadata to work properly
170
2/2
✓ Branch 98 → 99 taken 2 times.
✓ Branch 98 → 100 taken 618 times.
620 if (sanitizer == Sanitizer::TYPE)
171 2 cliOptions.useTBAAMetadata = true;
172
173 // Code coverage instrumentation needs debug info to map counters back to source locations
174
2/2
✓ Branch 100 → 101 taken 3 times.
✓ Branch 100 → 110 taken 617 times.
620 if (cliOptions.instrumentation.codeCoverage) {
175 3 cliOptions.instrumentation.generateDebugInfo = true;
176
2/2
✓ Branch 101 → 102 taken 1 time.
✓ Branch 101 → 110 taken 2 times.
3 if (cliOptions.useLTO)
177
2/4
✓ Branch 105 → 106 taken 1 time.
✗ Branch 105 → 272 not taken.
✓ Branch 106 → 107 taken 1 time.
✗ Branch 106 → 269 not taken.
3 throw CliError(INCOMPATIBLE_OPTIONS, "Code coverage instrumentation is not supported in combination with LTO");
178 }
179
180 // Infer build vars from other options
181
2/2
✓ Branch 2 → 3 taken 1233 times.
✓ Branch 2 → 4 taken 1862 times.
3095 const auto boolToString = [](bool input) { return input ? "true" : "false"; };
182
3/6
✓ Branch 113 → 114 taken 619 times.
✗ Branch 113 → 280 not taken.
✓ Branch 114 → 115 taken 619 times.
✗ Branch 114 → 278 not taken.
✓ Branch 115 → 116 taken 619 times.
✗ Branch 115 → 278 not taken.
1238 cliOptions.buildVars["spice.is_debug"] = boolToString(cliOptions.buildMode == BuildMode::DEBUG);
183
3/6
✓ Branch 121 → 122 taken 619 times.
✗ Branch 121 → 286 not taken.
✓ Branch 122 → 123 taken 619 times.
✗ Branch 122 → 284 not taken.
✓ Branch 123 → 124 taken 619 times.
✗ Branch 123 → 284 not taken.
1238 cliOptions.buildVars["spice.is_release"] = boolToString(cliOptions.buildMode == BuildMode::RELEASE);
184
3/6
✓ Branch 129 → 130 taken 619 times.
✗ Branch 129 → 292 not taken.
✓ Branch 130 → 131 taken 619 times.
✗ Branch 130 → 290 not taken.
✓ Branch 131 → 132 taken 619 times.
✗ Branch 131 → 290 not taken.
1238 cliOptions.buildVars["spice.is_test"] = boolToString(cliOptions.buildMode == BuildMode::TEST);
185
3/6
✓ Branch 137 → 138 taken 619 times.
✗ Branch 137 → 298 not taken.
✓ Branch 138 → 139 taken 619 times.
✗ Branch 138 → 296 not taken.
✓ Branch 139 → 140 taken 619 times.
✗ Branch 139 → 296 not taken.
1238 cliOptions.buildVars["spice.link_static"] = boolToString(cliOptions.staticLinking);
186
3/6
✓ Branch 145 → 146 taken 619 times.
✗ Branch 145 → 304 not taken.
✓ Branch 146 → 147 taken 619 times.
✗ Branch 146 → 302 not taken.
✓ Branch 147 → 148 taken 619 times.
✗ Branch 147 → 302 not taken.
1238 cliOptions.buildVars["spice.is_native_target"] = boolToString(cliOptions.isNativeTarget);
187
3/6
✓ Branch 153 → 154 taken 619 times.
✗ Branch 153 → 310 not taken.
✓ Branch 154 → 155 taken 619 times.
✗ Branch 154 → 308 not taken.
✓ Branch 155 → 156 taken 619 times.
✗ Branch 155 → 308 not taken.
1238 cliOptions.buildVars["spice.target_triple"] = cliOptions.targetTriple.str();
188
5/8
✓ Branch 158 → 159 taken 5 times.
✓ Branch 158 → 160 taken 614 times.
✓ Branch 163 → 164 taken 619 times.
✗ Branch 163 → 316 not taken.
✓ Branch 164 → 165 taken 619 times.
✗ Branch 164 → 314 not taken.
✓ Branch 165 → 166 taken 619 times.
✗ Branch 165 → 314 not taken.
1238 cliOptions.buildVars["spice.backend"] = cliOptions.backend == Backend::TPDE ? BACKEND_TPDE : BACKEND_LLVM;
189
190 // Prevent incompatible option combinations
191
3/4
✓ Branch 168 → 169 taken 1 time.
✓ Branch 168 → 178 taken 618 times.
✓ Branch 169 → 170 taken 1 time.
✗ Branch 169 → 178 not taken.
619 if (cliOptions.staticLinking && cliOptions.outputContainer == OutputContainer::SHARED_LIBRARY)
192
2/4
✓ Branch 173 → 174 taken 1 time.
✗ Branch 173 → 323 not taken.
✓ Branch 174 → 175 taken 1 time.
✗ Branch 174 → 320 not taken.
3 throw CliError(INCOMPATIBLE_OPTIONS, "Cannot link statically if compiling shared library");
193
194 // Guards for the experimental TPDE backend — ELF only, x86_64/aarch64 only, no LTO
195
2/2
✓ Branch 178 → 179 taken 5 times.
✓ Branch 178 → 220 taken 613 times.
618 if (cliOptions.backend == Backend::TPDE) {
196
2/2
✓ Branch 179 → 180 taken 1 time.
✓ Branch 179 → 188 taken 4 times.
5 if (cliOptions.useLTO)
197
2/4
✓ Branch 183 → 184 taken 1 time.
✗ Branch 183 → 332 not taken.
✓ Branch 184 → 185 taken 1 time.
✗ Branch 184 → 329 not taken.
3 throw CliError(INCOMPATIBLE_OPTIONS, "The TPDE backend does not support LTO");
198
2/2
✓ Branch 188 → 189 taken 1 time.
✓ Branch 188 → 197 taken 3 times.
4 if (cliOptions.instrumentation.codeCoverage)
199
2/4
✓ Branch 192 → 193 taken 1 time.
✗ Branch 192 → 341 not taken.
✓ Branch 193 → 194 taken 1 time.
✗ Branch 193 → 338 not taken.
3 throw CliError(INCOMPATIBLE_OPTIONS, "The TPDE backend does not support code coverage instrumentation");
200
2/2
✓ Branch 198 → 199 taken 1 time.
✓ Branch 198 → 207 taken 2 times.
3 if (!cliOptions.targetTriple.isOSLinux())
201
2/4
✓ Branch 202 → 203 taken 1 time.
✗ Branch 202 → 350 not taken.
✓ Branch 203 → 204 taken 1 time.
✗ Branch 203 → 347 not taken.
3 throw CliError(FEATURE_NOT_SUPPORTED_FOR_TARGET, "The TPDE backend only supports ELF targets (Linux)");
202 2 const llvm::Triple::ArchType arch = cliOptions.targetTriple.getArch();
203
3/4
✓ Branch 208 → 209 taken 1 time.
✓ Branch 208 → 218 taken 1 time.
✓ Branch 209 → 210 taken 1 time.
✗ Branch 209 → 218 not taken.
2 if (arch != llvm::Triple::x86_64 && arch != llvm::Triple::aarch64)
204
2/4
✓ Branch 213 → 214 taken 1 time.
✗ Branch 213 → 359 not taken.
✓ Branch 214 → 215 taken 1 time.
✗ Branch 214 → 356 not taken.
3 throw CliError(FEATURE_NOT_SUPPORTED_FOR_TARGET, "The TPDE backend only supports x86_64 and aarch64");
205
1/2
✗ Branch 218 → 219 not taken.
✓ Branch 218 → 220 taken 1 time.
1 if (cliOptions.optLevel != OptLevel::O0)
206 std::cout << "\033[33mWarning: the TPDE backend does not optimize; -O flag will be ignored\033[0m\n";
207 }
208 620 }
209
210 /**
211 * Executes the built executable
212 */
213 void Driver::runBinary() const {
214 // Print status message
215 if (cliOptions.printDebugOutput)
216 std::cout << "Running executable ...\n\n";
217
218 // Run executable, inheriting our standard streams so its output goes straight to the terminal
219 std::filesystem::path executablePath = cliOptions.outputPath;
220 executablePath.make_preferred();
221 const int exitCode = SystemUtil::run(executablePath.string());
222 if (exitCode != EXIT_SUCCESS)
223 throw CliError(NON_ZERO_EXIT_CODE, "Your Spice executable exited with non-zero exit code " + std::to_string(exitCode));
224 }
225
226 /**
227 * Add build subcommand to cli interface
228 */
229 624 void Driver::addBuildSubcommand() {
230 // Create sub-command itself
231
3/6
✓ Branch 4 → 5 taken 624 times.
✗ Branch 4 → 160 not taken.
✓ Branch 7 → 8 taken 624 times.
✗ Branch 7 → 154 not taken.
✓ Branch 8 → 9 taken 624 times.
✗ Branch 8 → 152 not taken.
2496 CLI::App *subCmd = app.add_subcommand("build", "Builds your Spice program and emits an executable");
232
2/4
✓ Branch 15 → 16 taken 624 times.
✗ Branch 15 → 166 not taken.
✓ Branch 16 → 17 taken 624 times.
✗ Branch 16 → 164 not taken.
1248 subCmd->alias("b");
233 624 subCmd->allow_non_standard_option_names();
234 624 subCmd->configurable();
235 624 subCmd->callback([&] {
236 611 shouldCompile = true;
237 611 });
238
239
1/2
✓ Branch 24 → 25 taken 624 times.
✗ Branch 24 → 308 not taken.
624 addCompileSubcommandOptions(subCmd);
240
1/2
✓ Branch 25 → 26 taken 624 times.
✗ Branch 25 → 308 not taken.
624 addInstrumentationOptions(subCmd);
241
242 631 const auto outputContainerCallback = [&](const CLI::results_t &results) {
243
1/2
✓ Branch 3 → 4 taken 7 times.
✗ Branch 3 → 29 not taken.
7 std::string inputString = results.front();
244
1/2
✓ Branch 5 → 6 taken 7 times.
✗ Branch 5 → 27 not taken.
7 std::ranges::transform(inputString, inputString.begin(), tolower);
245
246
3/4
✓ Branch 6 → 7 taken 7 times.
✗ Branch 6 → 27 not taken.
✓ Branch 7 → 8 taken 2 times.
✓ Branch 7 → 9 taken 5 times.
7 if (inputString == OUTPUT_CONTAINER_EXECUTABLE)
247 2 cliOptions.outputContainer = OutputContainer::EXECUTABLE;
248
3/4
✓ Branch 9 → 10 taken 5 times.
✗ Branch 9 → 27 not taken.
✓ Branch 10 → 11 taken 1 time.
✓ Branch 10 → 12 taken 4 times.
5 else if (inputString == OUTPUT_CONTAINER_OBJECT_FILE)
249 1 cliOptions.outputContainer = OutputContainer::OBJECT_FILE;
250
3/4
✓ Branch 12 → 13 taken 4 times.
✗ Branch 12 → 27 not taken.
✓ Branch 13 → 14 taken 1 time.
✓ Branch 13 → 15 taken 3 times.
4 else if (inputString == OUTPUT_CONTAINER_STATIC_LIBRARY)
251 1 cliOptions.outputContainer = OutputContainer::STATIC_LIBRARY;
252
3/4
✓ Branch 15 → 16 taken 3 times.
✗ Branch 15 → 27 not taken.
✓ Branch 16 → 17 taken 2 times.
✓ Branch 16 → 18 taken 1 time.
3 else if (inputString == OUTPUT_CONTAINER_SHARED_LIBRARY)
253 2 cliOptions.outputContainer = OutputContainer::SHARED_LIBRARY;
254 else
255
1/2
✓ Branch 19 → 20 taken 1 time.
✗ Branch 19 → 24 not taken.
1 throw CliError(INVALID_OUTPUT_CONTAINER, inputString);
256
257 6 return true;
258 7 };
259
260 // --output-container
261
2/4
✓ Branch 33 → 34 taken 624 times.
✗ Branch 33 → 172 not taken.
✓ Branch 34 → 35 taken 624 times.
✗ Branch 34 → 170 not taken.
2496 subCmd->add_option("--output-container", outputContainerCallback,
262
1/2
✓ Branch 29 → 30 taken 624 times.
✗ Branch 29 → 181 not taken.
1872 "Format of the compilation output container: exec (default), obj, lib, dylib)");
263 // --target-triple
264
2/4
✓ Branch 46 → 47 taken 624 times.
✗ Branch 46 → 190 not taken.
✓ Branch 47 → 48 taken 624 times.
✗ Branch 47 → 188 not taken.
1872 subCmd->add_option<llvm::Triple>("--target,--target-triple,-t", cliOptions.targetTriple,
265
1/2
✓ Branch 43 → 44 taken 624 times.
✗ Branch 43 → 196 not taken.
1248 "Target triple for the emitted executable (for cross-compiling)");
266 // --target-arch
267
2/4
✓ Branch 57 → 58 taken 624 times.
✗ Branch 57 → 202 not taken.
✓ Branch 58 → 59 taken 624 times.
✗ Branch 58 → 200 not taken.
1872 subCmd->add_option<std::string>("--target-arch", cliOptions.targetArch,
268
1/2
✓ Branch 54 → 55 taken 624 times.
✗ Branch 54 → 208 not taken.
1248 "Target arch for emitted executable (for cross-compiling)");
269 // --target-vendor
270
2/4
✓ Branch 68 → 69 taken 624 times.
✗ Branch 68 → 214 not taken.
✓ Branch 69 → 70 taken 624 times.
✗ Branch 69 → 212 not taken.
1872 subCmd->add_option<std::string>("--target-vendor", cliOptions.targetVendor,
271
1/2
✓ Branch 65 → 66 taken 624 times.
✗ Branch 65 → 220 not taken.
1248 "Target vendor for emitted executable (for cross-compiling)");
272 // --target-os
273
3/6
✓ Branch 76 → 77 taken 624 times.
✗ Branch 76 → 232 not taken.
✓ Branch 79 → 80 taken 624 times.
✗ Branch 79 → 226 not taken.
✓ Branch 80 → 81 taken 624 times.
✗ Branch 80 → 224 not taken.
2496 subCmd->add_option<std::string>("--target-os", cliOptions.targetOs, "Target os for emitted executable (for cross-compiling)");
274 // --output
275
3/6
✓ Branch 87 → 88 taken 624 times.
✗ Branch 87 → 244 not taken.
✓ Branch 90 → 91 taken 624 times.
✗ Branch 90 → 238 not taken.
✓ Branch 91 → 92 taken 624 times.
✗ Branch 91 → 236 not taken.
2496 subCmd->add_option<std::filesystem::path>("--output,-o", cliOptions.outputPath, "Set the output file path");
276 // --disable-verifier
277
3/6
✓ Branch 98 → 99 taken 624 times.
✗ Branch 98 → 256 not taken.
✓ Branch 101 → 102 taken 624 times.
✗ Branch 101 → 250 not taken.
✓ Branch 102 → 103 taken 624 times.
✗ Branch 102 → 248 not taken.
2496 subCmd->add_flag<bool>("--disable-verifier", cliOptions.disableVerifier, "Disable LLVM module and function verification");
278 // --no-entry
279
3/6
✓ Branch 109 → 110 taken 624 times.
✗ Branch 109 → 268 not taken.
✓ Branch 112 → 113 taken 624 times.
✗ Branch 112 → 262 not taken.
✓ Branch 113 → 114 taken 624 times.
✗ Branch 113 → 260 not taken.
2496 subCmd->add_flag<bool>("--no-entry", cliOptions.noEntryFct, "Do not generate main function");
280 // --static
281
3/6
✓ Branch 120 → 121 taken 624 times.
✗ Branch 120 → 280 not taken.
✓ Branch 123 → 124 taken 624 times.
✗ Branch 123 → 274 not taken.
✓ Branch 124 → 125 taken 624 times.
✗ Branch 124 → 272 not taken.
2496 subCmd->add_flag<bool>("--static", cliOptions.staticLinking, "Link statically");
282 // --dump-to-files
283
3/6
✓ Branch 131 → 132 taken 624 times.
✗ Branch 131 → 292 not taken.
✓ Branch 134 → 135 taken 624 times.
✗ Branch 134 → 286 not taken.
✓ Branch 135 → 136 taken 624 times.
✗ Branch 135 → 284 not taken.
2496 subCmd->add_flag<bool>("--dump-to-files", cliOptions.dump.dumpToFiles, "Redirect dumps to files instead of printing");
284 // --abort-after-dump
285
2/4
✓ Branch 145 → 146 taken 624 times.
✗ Branch 145 → 298 not taken.
✓ Branch 146 → 147 taken 624 times.
✗ Branch 146 → 296 not taken.
1872 subCmd->add_flag<bool>("--abort-after-dump", cliOptions.dump.abortAfterDump,
286
1/2
✓ Branch 142 → 143 taken 624 times.
✗ Branch 142 → 304 not taken.
1248 "Abort the compilation process after dumping the first requested resource");
287 624 }
288
289 /**
290 * Add run subcommand to cli interface
291 */
292 624 void Driver::addRunSubcommand() {
293 // Create sub-command itself
294
3/6
✓ Branch 4 → 5 taken 624 times.
✗ Branch 4 → 45 not taken.
✓ Branch 7 → 8 taken 624 times.
✗ Branch 7 → 39 not taken.
✓ Branch 8 → 9 taken 624 times.
✗ Branch 8 → 37 not taken.
2496 CLI::App *subCmd = app.add_subcommand("run", "Builds your Spice program and runs it immediately");
295
2/4
✓ Branch 15 → 16 taken 624 times.
✗ Branch 15 → 51 not taken.
✓ Branch 16 → 17 taken 624 times.
✗ Branch 16 → 49 not taken.
1248 subCmd->alias("r");
296 624 subCmd->allow_non_standard_option_names();
297 624 subCmd->callback([&] {
298 2 shouldCompile = shouldExecute = true;
299 2 });
300
301 624 addCompileSubcommandOptions(subCmd);
302 624 addInstrumentationOptions(subCmd);
303
304 // --disable-verifier
305
3/6
✓ Branch 27 → 28 taken 624 times.
✗ Branch 27 → 63 not taken.
✓ Branch 30 → 31 taken 624 times.
✗ Branch 30 → 57 not taken.
✓ Branch 31 → 32 taken 624 times.
✗ Branch 31 → 55 not taken.
2496 subCmd->add_flag<bool>("--disable-verifier", cliOptions.disableVerifier, "Disable LLVM module and function verification");
306 624 }
307
308 /**
309 * Add test subcommand to cli interface
310 */
311 624 void Driver::addTestSubcommand() {
312 // Create sub-command itself
313
3/6
✓ Branch 4 → 5 taken 624 times.
✗ Branch 4 → 45 not taken.
✓ Branch 7 → 8 taken 624 times.
✗ Branch 7 → 39 not taken.
✓ Branch 8 → 9 taken 624 times.
✗ Branch 8 → 37 not taken.
2496 CLI::App *subCmd = app.add_subcommand("test", "Builds your Spice program and runs all enclosed tests");
314
2/4
✓ Branch 15 → 16 taken 624 times.
✗ Branch 15 → 51 not taken.
✓ Branch 16 → 17 taken 624 times.
✗ Branch 16 → 49 not taken.
1248 subCmd->alias("t");
315 624 subCmd->allow_non_standard_option_names();
316 624 subCmd->callback([&] {
317 2 shouldCompile = shouldExecute = true;
318 2 cliOptions.buildMode = BuildMode::TEST;
319 2 cliOptions.generateTestMain = true; // An alternative entry function is generated
320 2 cliOptions.noEntryFct = true; // To not have two main functions, disable normal main
321 2 });
322
323 624 addCompileSubcommandOptions(subCmd);
324 624 addInstrumentationOptions(subCmd);
325
326 // --disable-verifier
327
3/6
✓ Branch 27 → 28 taken 624 times.
✗ Branch 27 → 63 not taken.
✓ Branch 30 → 31 taken 624 times.
✗ Branch 30 → 57 not taken.
✓ Branch 31 → 32 taken 624 times.
✗ Branch 31 → 55 not taken.
2496 subCmd->add_flag<bool>("--disable-verifier", cliOptions.disableVerifier, "Disable LLVM module and function verification");
328 624 }
329
330 /**
331 * Add lint subcommand to cli interface
332 */
333 624 void Driver::addLintSubcommand() {
334 // Create sub-command itself
335
3/6
✓ Branch 4 → 5 taken 624 times.
✗ Branch 4 → 33 not taken.
✓ Branch 7 → 8 taken 624 times.
✗ Branch 7 → 27 not taken.
✓ Branch 8 → 9 taken 624 times.
✗ Branch 8 → 25 not taken.
2496 CLI::App *subCmd = app.add_subcommand("lint", "Checks your Spice program for style and best-practice issues");
336
2/4
✓ Branch 15 → 16 taken 624 times.
✗ Branch 15 → 39 not taken.
✓ Branch 16 → 17 taken 624 times.
✗ Branch 16 → 37 not taken.
1248 subCmd->alias("l");
337 624 subCmd->allow_non_standard_option_names();
338 624 subCmd->callback([&] {
339 2 shouldCompile = true;
340 2 cliOptions.lintOnly = true;
341 2 });
342
343 624 addCompileSubcommandOptions(subCmd);
344 624 }
345
346 /**
347 * Add install subcommand to cli interface
348 */
349 624 void Driver::addInstallSubcommand() {
350 // Create sub-command itself
351
3/6
✓ Branch 4 → 5 taken 624 times.
✗ Branch 4 → 33 not taken.
✓ Branch 7 → 8 taken 624 times.
✗ Branch 7 → 27 not taken.
✓ Branch 8 → 9 taken 624 times.
✗ Branch 8 → 25 not taken.
2496 CLI::App *subCmd = app.add_subcommand("install", "Builds your Spice program and installs it to a directory in the PATH");
352
2/4
✓ Branch 15 → 16 taken 624 times.
✗ Branch 15 → 39 not taken.
✓ Branch 16 → 17 taken 624 times.
✗ Branch 16 → 37 not taken.
1248 subCmd->alias("i");
353 624 subCmd->allow_non_standard_option_names();
354 624 subCmd->callback([&] {
355 1 shouldCompile = true;
356 1 shouldInstall = true;
357 1 ensureNotDockerized();
358 1 });
359
360 624 addCompileSubcommandOptions(subCmd);
361 624 }
362
363 /**
364 * Add uninstall subcommand to cli interface
365 */
366 624 void Driver::addUninstallSubcommand() {
367 // Create sub-command itself
368
3/6
✓ Branch 4 → 5 taken 624 times.
✗ Branch 4 → 52 not taken.
✓ Branch 7 → 8 taken 624 times.
✗ Branch 7 → 46 not taken.
✓ Branch 8 → 9 taken 624 times.
✗ Branch 8 → 44 not taken.
2496 CLI::App *subCmd = app.add_subcommand("uninstall", "Uninstalls a Spice program from the system");
369
2/4
✓ Branch 15 → 16 taken 624 times.
✗ Branch 15 → 58 not taken.
✓ Branch 16 → 17 taken 624 times.
✗ Branch 16 → 56 not taken.
1248 subCmd->alias("u");
370 624 subCmd->allow_non_standard_option_names();
371 624 subCmd->callback([&] {
372 1 shouldUninstall = true;
373 1 ensureNotDockerized();
374 1 });
375
376 // Source file
377
2/4
✓ Branch 25 → 26 taken 624 times.
✗ Branch 25 → 79 not taken.
✓ Branch 28 → 29 taken 624 times.
✗ Branch 28 → 73 not taken.
2496 subCmd->add_option<std::filesystem::path>("<main-source-file>", cliOptions.mainSourceFile, "Main source file")
378
3/6
✓ Branch 29 → 30 taken 624 times.
✗ Branch 29 → 71 not taken.
✓ Branch 33 → 34 taken 624 times.
✗ Branch 33 → 64 not taken.
✓ Branch 34 → 35 taken 624 times.
✗ Branch 34 → 62 not taken.
2496 ->check(CLI::ExistingFile)
379 624 ->required();
380 624 }
381
382 3120 void Driver::addCompileSubcommandOptions(CLI::App *subCmd) const {
383 3125 const auto buildModeCallback = [&](const CLI::results_t &results) {
384
1/2
✓ Branch 3 → 4 taken 5 times.
✗ Branch 3 → 26 not taken.
5 std::string inputString = results.front();
385
1/2
✓ Branch 5 → 6 taken 5 times.
✗ Branch 5 → 24 not taken.
5 std::ranges::transform(inputString, inputString.begin(), tolower);
386
387
2/4
✓ Branch 6 → 7 taken 5 times.
✗ Branch 6 → 24 not taken.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 5 times.
5 if (inputString == BUILD_MODE_DEBUG)
388 cliOptions.buildMode = BuildMode::DEBUG;
389
3/4
✓ Branch 9 → 10 taken 5 times.
✗ Branch 9 → 24 not taken.
✓ Branch 10 → 11 taken 4 times.
✓ Branch 10 → 12 taken 1 time.
5 else if (inputString == BUILD_MODE_RELEASE)
390 4 cliOptions.buildMode = BuildMode::RELEASE;
391
2/4
✓ Branch 12 → 13 taken 1 time.
✗ Branch 12 → 24 not taken.
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 1 time.
1 else if (inputString == BUILD_MODE_TEST)
392 cliOptions.buildMode = BuildMode::TEST;
393 else
394
1/2
✓ Branch 16 → 17 taken 1 time.
✗ Branch 16 → 21 not taken.
1 throw CliError(INVALID_BUILD_MODE, inputString);
395
396 4 return true;
397 5 };
398 3123 const auto buildVarCallback = [&](const std::vector<std::string> &inputs) {
399
2/2
✓ Branch 29 → 4 taken 17 times.
✓ Branch 29 → 30 taken 3 times.
23 for (const std::string &input : inputs) {
400 // Skip empty inputs
401
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 17 times.
17 if (input.empty())
402 continue;
403
404 // Parse structure: "key=value". If no value given, save "true" as value.
405 17 const size_t splitPos = input.find_first_of('=');
406
2/2
✓ Branch 10 → 11 taken 12 times.
✓ Branch 10 → 18 taken 5 times.
17 if (splitPos != std::string::npos) {
407
1/2
✓ Branch 11 → 12 taken 12 times.
✗ Branch 11 → 36 not taken.
12 const std::string key = input.substr(0, splitPos);
408
1/2
✓ Branch 12 → 13 taken 12 times.
✗ Branch 12 → 34 not taken.
12 const std::string value = input.substr(splitPos + 1);
409
2/4
✓ Branch 13 → 14 taken 12 times.
✗ Branch 13 → 32 not taken.
✓ Branch 14 → 15 taken 12 times.
✗ Branch 14 → 32 not taken.
12 cliOptions.buildVars[key] = value;
410 12 } else {
411
2/4
✓ Branch 18 → 19 taken 5 times.
✗ Branch 18 → 37 not taken.
✓ Branch 19 → 20 taken 5 times.
✗ Branch 19 → 37 not taken.
5 cliOptions.buildVars[input] = "true";
412 }
413 }
414 3 return true;
415 3120 };
416
417 // --build-mode
418
3/6
✓ Branch 5 → 6 taken 3120 times.
✗ Branch 5 → 333 not taken.
✓ Branch 9 → 10 taken 3120 times.
✗ Branch 9 → 324 not taken.
✓ Branch 10 → 11 taken 3120 times.
✗ Branch 10 → 322 not taken.
15600 subCmd->add_option("--build-mode,-m", buildModeCallback, "Build mode: debug (default), release, test");
419 // --llvm-args
420
3/6
✓ Branch 19 → 20 taken 3120 times.
✗ Branch 19 → 348 not taken.
✓ Branch 22 → 23 taken 3120 times.
✗ Branch 22 → 342 not taken.
✓ Branch 23 → 24 taken 3120 times.
✗ Branch 23 → 340 not taken.
12480 subCmd->add_option<std::string>("--llvm-args,-llvm", cliOptions.llvmArgs, "Additional arguments for LLVM")->join(' ');
421 // --jobs
422
2/4
✓ Branch 34 → 35 taken 3120 times.
✗ Branch 34 → 354 not taken.
✓ Branch 35 → 36 taken 3120 times.
✗ Branch 35 → 352 not taken.
9360 subCmd->add_option<unsigned short>("--jobs,-j", cliOptions.compileJobCount,
423
1/2
✓ Branch 31 → 32 taken 3120 times.
✗ Branch 31 → 360 not taken.
6240 "Number of source files to compile in parallel in the back end (0 = auto)");
424 // --build-var
425
1/2
✓ Branch 47 → 48 taken 3120 times.
✗ Branch 47 → 364 not taken.
6240 CLI::Option *buildVarOption = subCmd->add_option_function<std::vector<std::string>>(
426
2/4
✓ Branch 42 → 43 taken 3120 times.
✗ Branch 42 → 375 not taken.
✓ Branch 46 → 47 taken 3120 times.
✗ Branch 46 → 366 not taken.
12480 "--build-var,-b", buildVarCallback, "Add build variable to parametrize the compiled program (e.g. -v key=value)");
427 3120 buildVarOption->multi_option_policy(CLI::MultiOptionPolicy::TakeAll);
428 // --ignore-cache
429
3/6
✓ Branch 56 → 57 taken 3120 times.
✗ Branch 56 → 387 not taken.
✓ Branch 59 → 60 taken 3120 times.
✗ Branch 59 → 381 not taken.
✓ Branch 60 → 61 taken 3120 times.
✗ Branch 60 → 379 not taken.
12480 subCmd->add_flag<bool>("--ignore-cache", cliOptions.ignoreCache, "Force re-compilation of all source files");
430 // --use-lifetime-markers
431
2/4
✓ Branch 70 → 71 taken 3120 times.
✗ Branch 70 → 393 not taken.
✓ Branch 71 → 72 taken 3120 times.
✗ Branch 71 → 391 not taken.
9360 subCmd->add_flag<bool>("--use-lifetime-markers", cliOptions.useLifetimeMarkers,
432
1/2
✓ Branch 67 → 68 taken 3120 times.
✗ Branch 67 → 399 not taken.
6240 "Generate lifetime markers to enhance optimizations");
433 // --use-tbaa-metadata
434
2/4
✓ Branch 81 → 82 taken 3120 times.
✗ Branch 81 → 405 not taken.
✓ Branch 82 → 83 taken 3120 times.
✗ Branch 82 → 403 not taken.
9360 subCmd->add_flag<bool>("--use-tbaa-metadata", cliOptions.useTBAAMetadata,
435
1/2
✓ Branch 78 → 79 taken 3120 times.
✗ Branch 78 → 411 not taken.
6240 "Generate metadata for type-based alias analysis to enhance optimizations");
436
437 // Opt levels
438
3/6
✓ Branch 89 → 90 taken 3120 times.
✗ Branch 89 → 427 not taken.
✓ Branch 93 → 94 taken 3120 times.
✗ Branch 93 → 417 not taken.
✓ Branch 94 → 95 taken 3120 times.
✗ Branch 94 → 415 not taken.
12480 subCmd->add_flag_callback("-O0", [&] { cliOptions.optLevel = OptLevel::O0; }, "Disable optimization.");
439
3/6
✓ Branch 102 → 103 taken 3120 times.
✗ Branch 102 → 443 not taken.
✓ Branch 106 → 107 taken 3120 times.
✗ Branch 106 → 433 not taken.
✓ Branch 107 → 108 taken 3120 times.
✗ Branch 107 → 431 not taken.
12480 subCmd->add_flag_callback("-O1", [&] { cliOptions.optLevel = OptLevel::O1; }, "Only basic optimization is applied.");
440
3/6
✓ Branch 115 → 116 taken 3120 times.
✗ Branch 115 → 459 not taken.
✓ Branch 119 → 120 taken 3120 times.
✗ Branch 119 → 449 not taken.
✓ Branch 120 → 121 taken 3120 times.
✗ Branch 120 → 447 not taken.
12480 subCmd->add_flag_callback("-O2", [&] { cliOptions.optLevel = OptLevel::O2; }, "More advanced optimization is applied.");
441
3/6
✓ Branch 128 → 129 taken 3120 times.
✗ Branch 128 → 475 not taken.
✓ Branch 132 → 133 taken 3120 times.
✗ Branch 132 → 465 not taken.
✓ Branch 133 → 134 taken 3120 times.
✗ Branch 133 → 463 not taken.
12480 subCmd->add_flag_callback("-O3", [&] { cliOptions.optLevel = OptLevel::O3; }, "Aggressive optimization for best performance.");
442
3/6
✓ Branch 141 → 142 taken 3120 times.
✗ Branch 141 → 491 not taken.
✓ Branch 145 → 146 taken 3120 times.
✗ Branch 145 → 481 not taken.
✓ Branch 146 → 147 taken 3120 times.
✗ Branch 146 → 479 not taken.
12480 subCmd->add_flag_callback("-Os", [&] { cliOptions.optLevel = OptLevel::Os; }, "Size optimization for output executable.");
443
3/6
✓ Branch 154 → 155 taken 3120 times.
✗ Branch 154 → 507 not taken.
✓ Branch 158 → 159 taken 3120 times.
✗ Branch 158 → 497 not taken.
✓ Branch 159 → 160 taken 3120 times.
✗ Branch 159 → 495 not taken.
12480 subCmd->add_flag_callback("-Oz", [&] { cliOptions.optLevel = OptLevel::Oz; }, "Aggressive optimization for best size.");
444
3/6
✓ Branch 167 → 168 taken 3120 times.
✗ Branch 167 → 519 not taken.
✓ Branch 170 → 171 taken 3120 times.
✗ Branch 170 → 513 not taken.
✓ Branch 171 → 172 taken 3120 times.
✗ Branch 171 → 511 not taken.
12480 subCmd->add_flag<bool>("-lto", cliOptions.useLTO, "Enable link time optimization (LTO)");
445
446 // --backend
447 3127 const auto backendCallback = [&](const CLI::results_t &results) {
448
1/2
✓ Branch 3 → 4 taken 7 times.
✗ Branch 3 → 23 not taken.
7 std::string inputString = results.front();
449
1/2
✓ Branch 5 → 6 taken 7 times.
✗ Branch 5 → 21 not taken.
7 std::ranges::transform(inputString, inputString.begin(), tolower);
450
451
3/4
✓ Branch 6 → 7 taken 7 times.
✗ Branch 6 → 21 not taken.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 7 → 9 taken 6 times.
7 if (inputString == BACKEND_LLVM) {
452 1 cliOptions.backend = Backend::LLVM;
453
3/4
✓ Branch 9 → 10 taken 6 times.
✗ Branch 9 → 21 not taken.
✓ Branch 10 → 11 taken 5 times.
✓ Branch 10 → 12 taken 1 time.
6 } else if (inputString == BACKEND_TPDE) {
454 #ifdef SPICE_ENABLE_TPDE
455 5 cliOptions.backend = Backend::TPDE;
456 #else
457 throw CliError(FEATURE_NOT_SUPPORTED_FOR_TARGET,
458 "The TPDE backend is not available in this build. Rebuild the compiler with "
459 "-DSPICE_ENABLE_TPDE=ON.");
460 #endif
461 } else {
462
1/2
✓ Branch 13 → 14 taken 1 time.
✗ Branch 13 → 18 not taken.
1 throw CliError(INVALID_BACKEND, inputString);
463 }
464
465 6 return true;
466 7 };
467
2/4
✓ Branch 183 → 184 taken 3120 times.
✗ Branch 183 → 525 not taken.
✓ Branch 184 → 185 taken 3120 times.
✗ Branch 184 → 523 not taken.
12480 subCmd->add_option("--backend", backendCallback,
468
1/2
✓ Branch 179 → 180 taken 3120 times.
✗ Branch 179 → 534 not taken.
9360 "Codegen backend: llvm (default), tpde (experimental — fast, unoptimized; requires opt-in build)");
469
470 // --debug-output
471
3/6
✓ Branch 193 → 194 taken 3120 times.
✗ Branch 193 → 549 not taken.
✓ Branch 196 → 197 taken 3120 times.
✗ Branch 196 → 543 not taken.
✓ Branch 197 → 198 taken 3120 times.
✗ Branch 197 → 541 not taken.
12480 subCmd->add_flag<bool>("--debug-output,-d", cliOptions.printDebugOutput, "Enable debug output");
472 // --dump-cst
473
3/6
✓ Branch 204 → 205 taken 3120 times.
✗ Branch 204 → 561 not taken.
✓ Branch 207 → 208 taken 3120 times.
✗ Branch 207 → 555 not taken.
✓ Branch 208 → 209 taken 3120 times.
✗ Branch 208 → 553 not taken.
12480 subCmd->add_flag<bool>("--dump-cst,-cst", cliOptions.dump.dumpCST, "Dump CST as serialized string and SVG image");
474 // --dump-ast
475
3/6
✓ Branch 215 → 216 taken 3120 times.
✗ Branch 215 → 573 not taken.
✓ Branch 218 → 219 taken 3120 times.
✗ Branch 218 → 567 not taken.
✓ Branch 219 → 220 taken 3120 times.
✗ Branch 219 → 565 not taken.
12480 subCmd->add_flag<bool>("--dump-ast,-ast", cliOptions.dump.dumpAST, "Dump AST as serialized string and SVG image");
476 // --dump-symtab
477
3/6
✓ Branch 226 → 227 taken 3120 times.
✗ Branch 226 → 585 not taken.
✓ Branch 229 → 230 taken 3120 times.
✗ Branch 229 → 579 not taken.
✓ Branch 230 → 231 taken 3120 times.
✗ Branch 230 → 577 not taken.
12480 subCmd->add_flag<bool>("--dump-symtab", cliOptions.dump.dumpSymbolTable, "Dump serialized symbol tables");
478 // --dump-types
479
3/6
✓ Branch 237 → 238 taken 3120 times.
✗ Branch 237 → 597 not taken.
✓ Branch 240 → 241 taken 3120 times.
✗ Branch 240 → 591 not taken.
✓ Branch 241 → 242 taken 3120 times.
✗ Branch 241 → 589 not taken.
12480 subCmd->add_flag<bool>("--dump-types", cliOptions.dump.dumpTypes, "Dump all used types");
480 // --dump-cache-stats
481
3/6
✓ Branch 248 → 249 taken 3120 times.
✗ Branch 248 → 609 not taken.
✓ Branch 251 → 252 taken 3120 times.
✗ Branch 251 → 603 not taken.
✓ Branch 252 → 253 taken 3120 times.
✗ Branch 252 → 601 not taken.
12480 subCmd->add_flag<bool>("--dump-cache-stats", cliOptions.dump.dumpCacheStats, "Dump stats for compiler-internal lookup caches");
482 // --dump-ir
483
3/6
✓ Branch 259 → 260 taken 3120 times.
✗ Branch 259 → 621 not taken.
✓ Branch 262 → 263 taken 3120 times.
✗ Branch 262 → 615 not taken.
✓ Branch 263 → 264 taken 3120 times.
✗ Branch 263 → 613 not taken.
12480 subCmd->add_flag<bool>("--dump-ir,-ir", cliOptions.dump.dumpIR, "Dump LLVM-IR");
484 // --dump-assembly
485
3/6
✓ Branch 270 → 271 taken 3120 times.
✗ Branch 270 → 633 not taken.
✓ Branch 273 → 274 taken 3120 times.
✗ Branch 273 → 627 not taken.
✓ Branch 274 → 275 taken 3120 times.
✗ Branch 274 → 625 not taken.
12480 subCmd->add_flag<bool>("--dump-assembly,-asm,-s", cliOptions.dump.dumpAssembly, "Dump Assembly code");
486 // --dump-object-file
487
3/6
✓ Branch 281 → 282 taken 3120 times.
✗ Branch 281 → 645 not taken.
✓ Branch 284 → 285 taken 3120 times.
✗ Branch 284 → 639 not taken.
✓ Branch 285 → 286 taken 3120 times.
✗ Branch 285 → 637 not taken.
12480 subCmd->add_flag<bool>("--dump-object-file", cliOptions.dump.dumpObjectFiles, "Dump object files");
488 // --dump-dependency-graph
489
3/6
✓ Branch 292 → 293 taken 3120 times.
✗ Branch 292 → 657 not taken.
✓ Branch 295 → 296 taken 3120 times.
✗ Branch 295 → 651 not taken.
✓ Branch 296 → 297 taken 3120 times.
✗ Branch 296 → 649 not taken.
12480 subCmd->add_flag<bool>("--dump-dependency-graph", cliOptions.dump.dumpDependencyGraph, "Dump compile unit dependency graph");
490
491 // Source file
492
2/4
✓ Branch 303 → 304 taken 3120 times.
✗ Branch 303 → 678 not taken.
✓ Branch 306 → 307 taken 3120 times.
✗ Branch 306 → 672 not taken.
12480 subCmd->add_option<std::filesystem::path>("<main-source-file>", cliOptions.mainSourceFile, "Main source file")
493
3/6
✓ Branch 307 → 308 taken 3120 times.
✗ Branch 307 → 670 not taken.
✓ Branch 311 → 312 taken 3120 times.
✗ Branch 311 → 663 not taken.
✓ Branch 312 → 313 taken 3120 times.
✗ Branch 312 → 661 not taken.
12480 ->check(CLI::ExistingFile)
494 3120 ->required();
495 3120 }
496
497 1872 void Driver::addInstrumentationOptions(CLI::App *subCmd) const {
498 1888 const auto sanitizerCallback = [&](const CLI::results_t &results) {
499
1/2
✓ Branch 3 → 4 taken 16 times.
✗ Branch 3 → 32 not taken.
16 std::string inputString = results.front();
500
1/2
✓ Branch 5 → 6 taken 16 times.
✗ Branch 5 → 30 not taken.
16 std::ranges::transform(inputString, inputString.begin(), tolower);
501
502
2/4
✓ Branch 6 → 7 taken 16 times.
✗ Branch 6 → 30 not taken.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 16 times.
16 if (inputString == SANITIZER_NONE)
503 cliOptions.instrumentation.sanitizer = Sanitizer::NONE;
504
3/4
✓ Branch 9 → 10 taken 16 times.
✗ Branch 9 → 30 not taken.
✓ Branch 10 → 11 taken 7 times.
✓ Branch 10 → 12 taken 9 times.
16 else if (inputString == SANITIZER_ADDRESS)
505 7 cliOptions.instrumentation.sanitizer = Sanitizer::ADDRESS;
506
3/4
✓ Branch 12 → 13 taken 9 times.
✗ Branch 12 → 30 not taken.
✓ Branch 13 → 14 taken 3 times.
✓ Branch 13 → 15 taken 6 times.
9 else if (inputString == SANITIZER_THREAD)
507 3 cliOptions.instrumentation.sanitizer = Sanitizer::THREAD;
508
3/4
✓ Branch 15 → 16 taken 6 times.
✗ Branch 15 → 30 not taken.
✓ Branch 16 → 17 taken 3 times.
✓ Branch 16 → 18 taken 3 times.
6 else if (inputString == SANITIZER_MEMORY)
509 3 cliOptions.instrumentation.sanitizer = Sanitizer::MEMORY;
510
3/4
✓ Branch 18 → 19 taken 3 times.
✗ Branch 18 → 30 not taken.
✓ Branch 19 → 20 taken 2 times.
✓ Branch 19 → 21 taken 1 time.
3 else if (inputString == SANITIZER_TYPE)
511 2 cliOptions.instrumentation.sanitizer = Sanitizer::TYPE;
512 else
513
1/2
✓ Branch 22 → 23 taken 1 time.
✗ Branch 22 → 27 not taken.
1 throw CliError(INVALID_SANITIZER, inputString);
514
515 15 return true;
516 16 };
517
518 // --debug-info
519
3/6
✓ Branch 4 → 5 taken 1872 times.
✗ Branch 4 → 48 not taken.
✓ Branch 7 → 8 taken 1872 times.
✗ Branch 7 → 42 not taken.
✓ Branch 8 → 9 taken 1872 times.
✗ Branch 8 → 40 not taken.
7488 subCmd->add_flag<bool>("--debug-info,-g", cliOptions.instrumentation.generateDebugInfo, "Generate debug info");
520 // --sanitizer
521
3/6
✓ Branch 16 → 17 taken 1872 times.
✗ Branch 16 → 63 not taken.
✓ Branch 20 → 21 taken 1872 times.
✗ Branch 20 → 54 not taken.
✓ Branch 21 → 22 taken 1872 times.
✗ Branch 21 → 52 not taken.
9360 subCmd->add_option("--sanitizer", sanitizerCallback, "Enable sanitizer: none (default), address, thread, memory, type");
522 // --coverage
523
2/4
✓ Branch 33 → 34 taken 1872 times.
✗ Branch 33 → 72 not taken.
✓ Branch 34 → 35 taken 1872 times.
✗ Branch 34 → 70 not taken.
5616 subCmd->add_flag<bool>("--coverage", cliOptions.instrumentation.codeCoverage,
524
1/2
✓ Branch 30 → 31 taken 1872 times.
✗ Branch 30 → 78 not taken.
3744 "Instrument code for coverage analysis (gcov-compatible .gcno/.gcda output)");
525 1872 }
526
527 /**
528 * Ensure that the compiler is not running in a Docker container
529 */
530 2 void Driver::ensureNotDockerized() {
531 2 const char *envValue = std::getenv(ENV_VAR_DOCKERIZED);
532 if (envValue != nullptr && std::strcmp(envValue, "true") == 0) { // LCOV_EXCL_START
533 const auto msg = "This feature is not supported in a containerized environment. Please use the standalone version of Spice.";
534 throw CliError(FEATURE_NOT_SUPPORTED_WHEN_DOCKERIZED, msg);
535 } // LCOV_EXCL_STOP
536 2 }
537
538 } // namespace spice::compiler
539