GCC Code Coverage Report


Directory: ../
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 100.0% 2 / 0 / 2
Functions: -% 0 / 0 / 0
Branches: -% 0 / 0 / 0

src/driver/Driver.h
Line Branch Exec Source
1 // Copyright (c) 2021-2026 ChilliBits. All rights reserved.
2
3 #pragma once
4
5 #include <util/GlobalDefinitions.h>
6
7 #include <llvm/TargetParser/Triple.h>
8
9 #include <CLI/CLI.hpp>
10
11 // Undef conflicting macros (only problematic on Windows)
12 #undef TRUE
13 #undef FALSE
14 #undef CONST
15
16 namespace spice::compiler {
17
18 const char *const TARGET_UNKNOWN = "unknown";
19 const char *const ENV_VAR_DOCKERIZED = "SPICE_DOCKERIZED";
20
21 enum class OptLevel : uint8_t {
22 O0 = 0, // No optimization
23 O1 = 1, // Only basic optimizations
24 O2 = 2, // Default optimization level
25 O3 = 3, // Aggressively optimize for performance
26 Os = 4, // Optimize for code size
27 Oz = 5, // Aggressively optimize for code size
28 };
29
30 enum class DebugInfoLevel : uint8_t {
31 NONE = 0, // Do not emit any debug info
32 LINE_ONLY = 1, // Only emit DWARF line tables, no type, variable or scope info
33 FULL = 2, // Emit full debug info, incl. types, variables and lexical scopes
34 };
35 const char *const DEBUG_INFO_NONE = "none";
36 const char *const DEBUG_INFO_LINE_ONLY = "line-only";
37 const char *const DEBUG_INFO_FULL = "full";
38
39 enum class Sanitizer : uint8_t {
40 NONE = 0, // No sanitizer
41 ADDRESS = 1, // Sanitize memory accesses
42 THREAD = 2, // Sanitize threads for data race prevention
43 MEMORY = 3, // Sanitize against uninitialized memory reads
44 TYPE = 4, // Sanitize type casts and accesses
45 };
46 const char *const SANITIZER_NONE = "none";
47 const char *const SANITIZER_ADDRESS = "address";
48 const char *const SANITIZER_THREAD = "thread";
49 const char *const SANITIZER_MEMORY = "memory";
50 const char *const SANITIZER_TYPE = "type";
51
52 enum class BuildMode : uint8_t {
53 DEBUG = 0, // Default build mode, uses -O0 per default
54 RELEASE = 1, // Build without debug information and with -O2 per default
55 TEST = 2, // Build with test main function and always emit assertions
56 };
57 const char *const BUILD_MODE_DEBUG = "debug";
58 const char *const BUILD_MODE_RELEASE = "release";
59 const char *const BUILD_MODE_TEST = "test";
60
61 enum class OutputContainer : uint8_t {
62 EXECUTABLE = 0, // On Linux and macOS no extension, on Windows .exe files
63 OBJECT_FILE = 1, // On Linux and macOS .o files and on Windows .obj files
64 STATIC_LIBRARY = 2, // On Linux and macOS .a files and on Windows .lib files
65 SHARED_LIBRARY = 3, // On Linux .so, on macOS .dylib and on Windows .dll files
66 MAX,
67 };
68
69 const char *const OUTPUT_CONTAINER_EXECUTABLE = "exec";
70 const char *const OUTPUT_CONTAINER_OBJECT_FILE = "obj";
71 const char *const OUTPUT_CONTAINER_STATIC_LIBRARY = "lib";
72 const char *const OUTPUT_CONTAINER_SHARED_LIBRARY = "dylib";
73
74 enum class Backend : uint8_t {
75 LLVM = 0, // Standard LLVM CodeGen backend (default)
76 TPDE = 1, // Experimental TPDE backend — fast, -O0-quality codegen (opt-in via SPICE_ENABLE_TPDE)
77 };
78 const char *const BACKEND_LLVM = "llvm";
79 const char *const BACKEND_TPDE = "tpde";
80
81 /**
82 * Representation of the various cli options
83 */
84 struct CliOptions {
85 std::filesystem::path mainSourceFile; // e.g. ./main.spice
86 llvm::Triple targetTriple; // In format: <arch><sub>-<vendor>-<sys>-<abi>
87 std::string targetArch = TARGET_UNKNOWN;
88 std::string targetVendor = TARGET_UNKNOWN;
89 std::string targetOs = TARGET_UNKNOWN;
90 bool isNativeTarget = true;
91 bool useCPUFeatures = true;
92 bool execute = false;
93 std::filesystem::path cacheDir; // Where the cache files go. Should always be a temp directory
94 std::filesystem::path outputDir = "./"; // Where the object files go. Should always be a temp directory
95 std::filesystem::path outputPath; // Where the output binary goes.
96 BuildMode buildMode = BuildMode::DEBUG; // Default build mode is debug
97 OutputContainer outputContainer = OutputContainer::EXECUTABLE; // Default output container is executable
98 unsigned short compileJobCount = 0; // 0 for auto
99 bool ignoreCache = false;
100 std::string llvmArgs;
101 bool printDebugOutput = false;
102 struct DumpSettings {
103 bool dumpCST = false;
104 bool dumpAST = false;
105 bool dumpSymbolTable = false;
106 bool dumpTypes = false;
107 bool dumpCacheStats = false;
108 bool dumpDependencyGraph = false;
109 bool dumpIR = false;
110 bool dumpAssembly = false;
111 bool dumpObjectFiles = false;
112 bool dumpToFiles = false;
113 bool abortAfterDump = false;
114 } dump;
115 bool namesForIRValues = false;
116 bool useLifetimeMarkers = false;
117 bool useTBAAMetadata = false;
118 OptLevel optLevel = OptLevel::O0; // The default optimization level for debug build mode is O0
119 bool useLTO = false;
120 Backend backend = Backend::LLVM; // Codegen backend selection (TPDE is experimental, opt-in at build time)
121 bool noEntryFct = false;
122 bool generateTestMain = false;
123 bool staticLinking = false;
124 struct InstrumentationSettings {
125 DebugInfoLevel debugInfoLevel = DebugInfoLevel::NONE;
126 bool codeCoverage = false;
127 Sanitizer sanitizer = Sanitizer::NONE;
128
129 2164970 [[nodiscard]] ALWAYS_INLINE bool emitsDebugInfo() const { return debugInfoLevel != DebugInfoLevel::NONE; }
130 458368 [[nodiscard]] ALWAYS_INLINE bool emitsFullDebugInfo() const { return debugInfoLevel == DebugInfoLevel::FULL; }
131 } instrumentation;
132 bool disableVerifier = !SPICE_DEBUG;
133 bool testMode = false;
134 bool comparableOutput = false;
135 std::map<std::string, std::string> buildVars;
136 // New fields must be appended here, at the very end: test/TestRunner.cpp positionally aggregate-initializes
137 // CliOptions, so inserting a field anywhere else silently shifts every field after it into the wrong slot.
138 bool lintOnly = false;
139 bool keepFramePointers = false;
140 bool stripSymbols = false;
141 };
142
143 /**
144 * Helper class to set up the driver and command line parser
145 */
146 class Driver {
147 public:
148 // Constructors
149 explicit Driver(CliOptions &foreignCliOptions, bool dryRun = false);
150
151 // Delete copy ctor and assignment operator
152 Driver(const Driver &) = delete;
153 Driver &operator=(const Driver &) = delete;
154
155 // Public methods
156 int parse(int argc, const char *argv[]);
157 void enrich() const;
158 void runBinary() const;
159
160 // Public members
161 CliOptions &cliOptions;
162 bool shouldCompile = false;
163 bool shouldInstall = false;
164 bool shouldUninstall = false;
165 bool shouldExecute = false;
166 bool performDryRun = false; // For unit testing purposes
167
168 private:
169 // Private methods
170 void addBuildSubcommand();
171 void addRunSubcommand();
172 void addTestSubcommand();
173 void addLintSubcommand();
174 void addInstallSubcommand();
175 void addUninstallSubcommand();
176 void addCompileSubcommandOptions(CLI::App *subCmd) const;
177 void addInstrumentationOptions(CLI::App *subCmd);
178 static void ensureNotDockerized();
179
180 // Members
181 CLI::App app = CLI::App("Spice Programming Language", "spice");
182 // Whether the user named a debug info level themselves. DebugInfoLevel::NONE is also the default, so without this
183 // an explicit '--debug-info=none' would be indistinguishable from not passing the option at all.
184 bool debugInfoLevelSetExplicitly = false;
185 };
186
187 } // namespace spice::compiler
188