src/global/GlobalResourceManager.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // Copyright (c) 2021-2026 ChilliBits. All rights reserved. | ||
| 2 | |||
| 3 | #include "GlobalResourceManager.h" | ||
| 4 | |||
| 5 | #include <cassert> | ||
| 6 | #include <thread> | ||
| 7 | |||
| 8 | #include <SourceFile.h> | ||
| 9 | #include <driver/Driver.h> | ||
| 10 | #include <global/TypeNameDisambiguator.h> | ||
| 11 | #include <global/TypeRegistry.h> | ||
| 12 | #include <symboltablebuilder/Scope.h> // IWYU pragma: keep - Scope | ||
| 13 | #include <typechecker/FunctionManager.h> | ||
| 14 | #include <typechecker/InterfaceManager.h> | ||
| 15 | #include <typechecker/StructManager.h> | ||
| 16 | #include <typechecker/UnionManager.h> | ||
| 17 | #include <util/FileUtil.h> | ||
| 18 | |||
| 19 | #include <llvm/IR/Module.h> | ||
| 20 | #include <llvm/Support/ManagedStatic.h> | ||
| 21 | #include <llvm/Support/TargetSelect.h> | ||
| 22 | #include <llvm/TargetParser/Host.h> | ||
| 23 | #include <llvm/TargetParser/SubtargetFeature.h> | ||
| 24 | |||
| 25 | namespace spice::compiler { | ||
| 26 | |||
| 27 | 1380 | GlobalResourceManager::GlobalResourceManager(const CliOptions &cliOptions) | |
| 28 |
6/12✓ Branch 4 → 5 taken 1380 times.
✗ Branch 4 → 95 not taken.
✓ Branch 8 → 9 taken 1380 times.
✗ Branch 8 → 89 not taken.
✓ Branch 9 → 10 taken 1380 times.
✗ Branch 9 → 89 not taken.
✓ Branch 13 → 14 taken 1380 times.
✗ Branch 13 → 81 not taken.
✓ Branch 14 → 15 taken 1380 times.
✗ Branch 14 → 79 not taken.
✓ Branch 16 → 17 taken 1380 times.
✗ Branch 16 → 77 not taken.
|
1380 | : cliOptions(cliOptions), linker(cliOptions), cacheManager(cliOptions), runtimeModuleManager(*this) { |
| 29 | // Initialize the required LLVM targets | ||
| 30 |
2/2✓ Branch 22 → 23 taken 1364 times.
✓ Branch 22 → 26 taken 16 times.
|
1380 | if (cliOptions.isNativeTarget) { |
| 31 |
1/2✓ Branch 23 → 24 taken 1364 times.
✗ Branch 23 → 73 not taken.
|
1364 | llvm::InitializeNativeTarget(); |
| 32 |
1/2✓ Branch 24 → 25 taken 1364 times.
✗ Branch 24 → 73 not taken.
|
1364 | llvm::InitializeNativeTargetAsmPrinter(); |
| 33 |
1/2✓ Branch 25 → 30 taken 1364 times.
✗ Branch 25 → 73 not taken.
|
1364 | llvm::InitializeNativeTargetAsmParser(); |
| 34 | } else { // GCOV_EXCL_START | ||
| 35 | − | llvm::InitializeAllTargets(); | |
| 36 | − | llvm::InitializeAllTargetMCs(); | |
| 37 | − | llvm::InitializeAllAsmPrinters(); | |
| 38 | − | llvm::InitializeAllAsmParsers(); | |
| 39 | } // GCOV_EXCL_STOP | ||
| 40 | |||
| 41 | // Create cpu name and features strings | ||
| 42 |
1/2✓ Branch 30 → 31 taken 1380 times.
✗ Branch 30 → 73 not taken.
|
1380 | cpuName = "generic"; |
| 43 |
4/4✓ Branch 31 → 32 taken 1364 times.
✓ Branch 31 → 55 taken 16 times.
✓ Branch 32 → 33 taken 14 times.
✓ Branch 32 → 55 taken 1350 times.
|
1380 | if (cliOptions.isNativeTarget && cliOptions.useCPUFeatures) { |
| 44 | // Retrieve native CPU name and the supported CPU features | ||
| 45 |
2/4✓ Branch 33 → 34 taken 14 times.
✗ Branch 33 → 62 not taken.
✓ Branch 34 → 35 taken 14 times.
✗ Branch 34 → 62 not taken.
|
14 | cpuName = llvm::sys::getHostCPUName(); |
| 46 |
2/4✓ Branch 35 → 36 taken 14 times.
✗ Branch 35 → 63 not taken.
✓ Branch 36 → 37 taken 14 times.
✗ Branch 36 → 63 not taken.
|
14 | llvm::SubtargetFeatures features; |
| 47 |
9/16✓ Branch 37 → 38 taken 14 times.
✗ Branch 37 → 67 not taken.
✓ Branch 38 → 39 taken 14 times.
✗ Branch 38 → 65 not taken.
✓ Branch 39 → 40 taken 14 times.
✗ Branch 39 → 65 not taken.
✓ Branch 42 → 43 taken 1610 times.
✗ Branch 42 → 64 not taken.
✓ Branch 43 → 44 taken 1610 times.
✗ Branch 43 → 64 not taken.
✓ Branch 45 → 46 taken 1610 times.
✗ Branch 45 → 65 not taken.
✓ Branch 47 → 48 taken 1624 times.
✗ Branch 47 → 65 not taken.
✓ Branch 48 → 41 taken 1610 times.
✓ Branch 48 → 49 taken 14 times.
|
3234 | for (const auto &[feature, isEnabled] : llvm::sys::getHostCPUFeatures()) |
| 48 |
1/2✓ Branch 44 → 45 taken 1610 times.
✗ Branch 44 → 64 not taken.
|
1610 | features.AddFeature(feature, isEnabled); |
| 49 |
1/2✓ Branch 50 → 51 taken 14 times.
✗ Branch 50 → 68 not taken.
|
14 | cpuFeatures = features.getString(); |
| 50 | 14 | } | |
| 51 | |||
| 52 |
2/2✓ Branch 55 → 56 taken 1 time.
✓ Branch 55 → 61 taken 1379 times.
|
1380 | if (cliOptions.useLTO) { |
| 53 | // Discard value names if not required | ||
| 54 |
1/2✓ Branch 56 → 57 taken 1 time.
✗ Branch 56 → 73 not taken.
|
1 | ltoContext.setDiscardValueNames(!cliOptions.namesForIRValues); |
| 55 | // Create lto module | ||
| 56 |
1/2✓ Branch 57 → 58 taken 1 time.
✗ Branch 57 → 72 not taken.
|
1 | ltoModule = std::make_unique<llvm::Module>(LTO_FILE_NAME, ltoContext); |
| 57 | } | ||
| 58 | 1380 | } | |
| 59 | |||
| 60 | 1380 | GlobalResourceManager::~GlobalResourceManager() { | |
| 61 | // Notify all global components to prepare to destroy | ||
| 62 | 1380 | TypeRegistry::clear(); | |
| 63 | 1380 | TypeNameDisambiguator::clear(); | |
| 64 | 1380 | FunctionManager::cleanup(); | |
| 65 | 1380 | StructManager::cleanup(); | |
| 66 | 1380 | InterfaceManager::cleanup(); | |
| 67 | 1380 | UnionManager::cleanup(); | |
| 68 | // Cleanup all LLVM statics | ||
| 69 | 1380 | llvm::llvm_shutdown(); | |
| 70 | 1380 | } | |
| 71 | |||
| 72 | 7251 | SourceFile *GlobalResourceManager::createSourceFile(SourceFile *parent, const std::string &depName, | |
| 73 | const std::filesystem::path &path, bool isStdFile) { | ||
| 74 | // Check if the source file was already added (e.g. by another source file that imports it) | ||
| 75 |
3/6✓ Branch 2 → 3 taken 7251 times.
✗ Branch 2 → 22 not taken.
✓ Branch 3 → 4 taken 7251 times.
✗ Branch 3 → 20 not taken.
✓ Branch 4 → 5 taken 7251 times.
✗ Branch 4 → 18 not taken.
|
7251 | const std::string filePathStr = weakly_canonical(absolute(path)).string(); |
| 76 | |||
| 77 | // Create the new source file if it does not exist yet | ||
| 78 |
3/4✓ Branch 7 → 8 taken 7251 times.
✗ Branch 7 → 27 not taken.
✓ Branch 8 → 9 taken 5602 times.
✓ Branch 8 → 13 taken 1649 times.
|
7251 | if (!sourceFiles.contains(filePathStr)) |
| 79 |
2/4✓ Branch 9 → 10 taken 5602 times.
✗ Branch 9 → 26 not taken.
✓ Branch 10 → 11 taken 5602 times.
✗ Branch 10 → 24 not taken.
|
5602 | sourceFiles.emplace(filePathStr, std::make_unique<SourceFile>(*this, parent, depName, path, isStdFile)); |
| 80 | |||
| 81 |
1/2✓ Branch 13 → 14 taken 7251 times.
✗ Branch 13 → 27 not taken.
|
14502 | return sourceFiles.at(filePathStr).get(); |
| 82 | 7251 | } | |
| 83 | |||
| 84 | 6154 | uint64_t GlobalResourceManager::getNextCustomTypeId() { return nextCustomTypeId++; } | |
| 85 | |||
| 86 | 371699 | uint64_t GlobalResourceManager::getNextScopeId() { return nextScopeId++; } | |
| 87 | |||
| 88 | /** | ||
| 89 | * Get the id of the given AST node. Node ids are assigned in creation order per source file, so unlike the node address, | ||
| 90 | * they are the same in every compiler run | ||
| 91 | * | ||
| 92 | * @param node AST node | ||
| 93 | * @return Node id / 0 if the node was not created by the AST builder | ||
| 94 | */ | ||
| 95 | 53846 | size_t GlobalResourceManager::getNodeId(const ASTNode *node) const { | |
| 96 |
1/2✓ Branch 2 → 3 taken 53846 times.
✗ Branch 2 → 12 not taken.
|
53846 | const auto it = nodeToNodeId.find(node); |
| 97 |
1/2✓ Branch 5 → 6 taken 53846 times.
✗ Branch 5 → 8 not taken.
|
107692 | return it != nodeToNodeId.end() ? it->second : 0; |
| 98 | } | ||
| 99 | |||
| 100 | /** | ||
| 101 | * Determine how many source files may be compiled at the same time, based on the --jobs/-j cli option | ||
| 102 | * | ||
| 103 | * @return Number of compile jobs (always >= 1) | ||
| 104 | */ | ||
| 105 | 870 | size_t GlobalResourceManager::getCompileJobCount() const { | |
| 106 | // An explicit job count always wins | ||
| 107 |
2/2✓ Branch 2 → 3 taken 854 times.
✓ Branch 2 → 4 taken 16 times.
|
870 | if (cliOptions.compileJobCount > 0) |
| 108 | 854 | return cliOptions.compileJobCount; | |
| 109 | |||
| 110 | // Otherwise derive the job count from the machine. hardware_concurrency may return 0 if it cannot be determined, in | ||
| 111 | // which case we fall back to a serial back end. | ||
| 112 | 16 | const unsigned int hardwareConcurrency = std::thread::hardware_concurrency(); | |
| 113 |
1/2✓ Branch 5 → 6 taken 16 times.
✗ Branch 5 → 7 not taken.
|
16 | return hardwareConcurrency > 0 ? hardwareConcurrency : 1; |
| 114 | } | ||
| 115 | |||
| 116 | /** | ||
| 117 | * Get the worker pool for parallel compiler passes. The pool is created on first use and re-used afterwards. | ||
| 118 | * | ||
| 119 | * @param threadCount Number of worker threads to create the pool with | ||
| 120 | * @return Thread pool | ||
| 121 | */ | ||
| 122 | 16 | ThreadPool &GlobalResourceManager::getThreadPool(size_t threadCount) { | |
| 123 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 16 times.
|
16 | assert(threadCount > 0); |
| 124 |
2/2✓ Branch 5 → 6 taken 10 times.
✓ Branch 5 → 10 taken 6 times.
|
16 | if (!threadPool) |
| 125 |
1/2✓ Branch 6 → 7 taken 10 times.
✗ Branch 6 → 12 not taken.
|
10 | threadPool = std::make_unique<ThreadPool>(threadCount); |
| 126 | 16 | return *threadPool; | |
| 127 | } | ||
| 128 | |||
| 129 | ✗ | size_t GlobalResourceManager::getTotalLineCount() const { | |
| 130 | ✗ | const auto acc = [](size_t sum, const auto &sourceFile) { return sum + FileUtil::getLineCount(sourceFile.second->filePath); }; | |
| 131 | ✗ | return std::accumulate(sourceFiles.begin(), sourceFiles.end(), 0, acc); | |
| 132 | } | ||
| 133 | |||
| 134 | } // namespace spice::compiler | ||
| 135 |