src/objectemitter/TPDEObjectEmitter.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // Copyright (c) 2021-2026 ChilliBits. All rights reserved. | ||
| 2 | |||
| 3 | #include "TPDEObjectEmitter.h" | ||
| 4 | |||
| 5 | #include <fstream> | ||
| 6 | #include <memory> | ||
| 7 | #include <vector> | ||
| 8 | |||
| 9 | #include <exception/CompilerError.h> | ||
| 10 | |||
| 11 | #include <llvm/IR/Module.h> | ||
| 12 | #include <llvm/TargetParser/Triple.h> | ||
| 13 | |||
| 14 | #include <tpde-llvm/LLVMCompiler.hpp> | ||
| 15 | |||
| 16 | namespace spice::compiler { | ||
| 17 | |||
| 18 | 1 | TPDEObjectEmitter::TPDEObjectEmitter(llvm::Module &module) : module(module) {} | |
| 19 | |||
| 20 | 1 | void TPDEObjectEmitter::emit(const std::filesystem::path &objectPath) const { | |
| 21 |
1/2✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 90 not taken.
|
1 | const std::string objectPathString = objectPath.string(); |
| 22 | |||
| 23 | // Create a TPDE compiler for the module's target triple | ||
| 24 |
1/2✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 88 not taken.
|
1 | const llvm::Triple triple(module.getTargetTriple()); |
| 25 |
1/2✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 86 not taken.
|
1 | const std::unique_ptr<tpde_llvm::LLVMCompiler> compiler = tpde_llvm::LLVMCompiler::create(triple); |
| 26 |
1/2✗ Branch 7 → 8 not taken.
✓ Branch 7 → 16 taken 1 time.
|
1 | if (!compiler) |
| 27 | ✗ | throw CompilerError(WRONG_OUTPUT_TYPE, | |
| 28 | − | "The TPDE backend does not support target triple '" + triple.str() + "'"); // GCOV_EXCL_LINE | |
| 29 | |||
| 30 | // Compile to an in-memory ELF object | ||
| 31 | 1 | std::vector<uint8_t> objBytes; | |
| 32 |
2/4✓ Branch 17 → 18 taken 1 time.
✗ Branch 17 → 82 not taken.
✗ Branch 18 → 19 not taken.
✓ Branch 18 → 29 taken 1 time.
|
1 | if (!compiler->compile_to_elf(module, objBytes)) |
| 33 | ✗ | throw CompilerError(WRONG_OUTPUT_TYPE, "TPDE failed to compile module '" + module.getName().str() + "'"); | |
| 34 | |||
| 35 | // Write to the requested path | ||
| 36 |
1/2✓ Branch 29 → 30 taken 1 time.
✗ Branch 29 → 82 not taken.
|
1 | std::ofstream out(objectPathString, std::ios::binary); |
| 37 |
2/4✓ Branch 30 → 31 taken 1 time.
✗ Branch 30 → 80 not taken.
✗ Branch 31 → 32 not taken.
✓ Branch 31 → 39 taken 1 time.
|
1 | if (!out) |
| 38 | − | throw CompilerError(CANT_OPEN_OUTPUT_FILE, "File '" + objectPathString + "' could not be opened"); // GCOV_EXCL_LINE | |
| 39 |
1/2✓ Branch 41 → 42 taken 1 time.
✗ Branch 41 → 80 not taken.
|
1 | out.write(reinterpret_cast<const char *>(objBytes.data()), static_cast<std::streamsize>(objBytes.size())); |
| 40 |
1/2✓ Branch 42 → 43 taken 1 time.
✗ Branch 42 → 80 not taken.
|
1 | out.flush(); |
| 41 | 1 | } | |
| 42 | |||
| 43 | 1 | void TPDEObjectEmitter::getASMString(std::string &output) const { | |
| 44 | // TPDE emits ELF bytes directly and does not expose an assembly listing. | ||
| 45 | output = "; Assembly listing is not available under the TPDE backend.\n" | ||
| 46 | 1 | "; Use --backend=llvm to obtain assembly output.\n"; | |
| 47 | 1 | } | |
| 48 | |||
| 49 | } // namespace spice::compiler | ||
| 50 |