GCC Code Coverage Report


src/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
25 / 31, 11 excl
80.6%
Branches:
8 / 14
57.1%
Functions:
3 / 4
75.0%

objectemitter/tpde-object-emitter.spice
Line Branch Exec Source
1 // Copyright (c) 2021-2026 ChilliBits. All rights reserved.
2
3 // Std imports
4 import "std/data/vector";
5 import "std/io/file";
6 import "std/io/filepath";
7 import "std/bindings/llvm/llvm" as llvm;
8 import "std/bindings/tpde/tpde" as tpde;
9
10 // Own imports
11 import "@/exception/fatal-error";
12 import "@/exception/compiler-error";
13 import "@/objectemitter/abstract-object-emitter";
14
15 /**
16 * Object emitter backed by the experimental TPDE compiler back-end framework.
17 *
18 * Consumes an LLVM module directly and emits an ELF object at roughly -O0 code quality but significantly faster than LLVM
19 * CodeGen at -O0. Supported targets: ELF on x86_64 or aarch64; small code model; PIC relocation only; no LTO.
20 *
21 * The emitter uses the std TPDE bindings, which are only backed by TPDE, if the TPDE libraries were linked into the compiler
22 * (see std/bindings/tpde). The driver rejects the TPDE backend otherwise, so this emitter is only used if TPDE is available.
23 */
24 public type TPDEObjectEmitter struct : IAbstractObjectEmitter {
25 llvm::Module* module
26 }
27
28 3497 public p TPDEObjectEmitter.ctor(llvm::Module* module) {
29 3497 this.module = module;
30 3497 }
31
32 2 public p TPDEObjectEmitter.emit(const FilePath& objectPath) {
33 2 const string objectPathString = objectPath.toString();
34
35 // Create a TPDE compiler for the module's target triple
36 2 const String tripleString = this.module.getTargetTripleString();
37 2 const llvm::Triple triple = llvm::Triple(tripleString.getRaw());
38 2 tpde::Compiler compiler = tpde::Compiler(triple);
39
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if !compiler.isValid() {
40 − const String message = "The TPDE backend does not support target triple '" + tripleString + "'"; // LCOV_EXCL_LINE
41 − raiseObjectEmitterError(CompilerErrorType::WRONG_OUTPUT_TYPE, message); // LCOV_EXCL_LINE
42 − } // LCOV_EXCL_LINE
43
44 // Compile to an in-memory ELF object
45 2 Vector<byte> objBytes;
46 2 String errorMessage;
47
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if compiler.compileToBuffer(*this.module, objBytes, errorMessage) {
48 ✗ raiseObjectEmitterError(CompilerErrorType::WRONG_OUTPUT_TYPE, errorMessage);
49 ✗ }
50
51 // Write to the requested path
52 2 Result<File> fileResult = openFile(objectPathString, "wb");
53
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if !fileResult.isOk() {
54 − const String message = "File '" + String(objectPathString) + "' could not be opened"; // LCOV_EXCL_LINE
55 − raiseObjectEmitterError(CompilerErrorType::CANT_OPEN_OUTPUT_FILE, message); // LCOV_EXCL_LINE
56 − } // LCOV_EXCL_LINE
57 2 File file = fileResult.unwrap();
58 2 bool writeFailed = false;
59
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 5816 times.
5818 foreach byte objByte : objBytes {
60
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5816 times.
5816 if !file.write(cast<char>(objByte)) {
61 − writeFailed = true; // LCOV_EXCL_LINE
62 − break; // LCOV_EXCL_LINE
63 } // LCOV_EXCL_LINE
64 5816 }
65 2 const bool closeFailed = !file.close();
66
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 if writeFailed || closeFailed {
67 − const String message = "File '" + String(objectPathString) + "' could not be written"; // LCOV_EXCL_LINE
68 − raiseObjectEmitterError(CompilerErrorType::CANT_OPEN_OUTPUT_FILE, message); // LCOV_EXCL_LINE
69 − } // LCOV_EXCL_LINE
70 2 }
71
72 2 public p TPDEObjectEmitter.getASMString(String& output) {
73 // TPDE emits ELF bytes directly and does not expose an assembly listing
74 2 output = String("; Assembly listing is not available under the TPDE backend.\n; Use --backend=llvm to obtain assembly output.\n");
75 2 }
76
77 /**
78 * Abort with a compiler error
79 *
80 * @param errorType Type of the compiler error
81 * @param message Error message suffix
82 */
83 ✗ p raiseObjectEmitterError(CompilerErrorType errorType, const String& message) {
84 ✗ const CompilerError error = CompilerError(errorType, message.getRaw());
85 ✗ abortWithError(error.getMessage());
86 ✗ }
87