GCC Code Coverage Report


Directory: ../
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 34.2% 26 / 6 / 82
Functions: 100.0% 2 / 0 / 2
Branches: 15.7% 31 / 0 / 198

src/irgenerator/GenTargetDependent.cpp
Line Branch Exec Source
1 // Copyright (c) 2021-2026 ChilliBits. All rights reserved.
2
3 #include "IRGenerator.h"
4
5 #include <driver/Driver.h>
6
7 namespace spice::compiler {
8
9 1 std::string IRGenerator::getSysCallAsmString(uint8_t numRegs) const {
10 1 const llvm::Triple &targetTriple = cliOptions.targetTriple;
11
1/2
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 107 not taken.
1 std::stringstream asmString;
12
13 // For each OS/architecture we have a mapping of operand index -> register.
14
2/4
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 105 not taken.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 39 taken 1 time.
1 if (targetTriple.isOSDarwin()) {
15 if (targetTriple.getArch() == llvm::Triple::ArchType::x86_64) {
16 static constexpr const char *regs[] = {"%rax", "%rdi", "%rsi", "%rdx", "%r10", "%r8", "%r9"};
17 for (uint8_t i = 0; i < numRegs; i++) {
18 asmString << "movq $" << std::to_string(i) << ", " << regs[i] << "\n";
19 // macOS x86_64 syscall numbers are offset by 0x2000000 (BSD syscall class). "$$" emits a literal '$'.
20 if (i == 0)
21 asmString << "addq $$" << std::to_string(0x2000000) << ", %rax\n";
22 }
23 asmString << "syscall\n";
24 } else if (targetTriple.isAArch64()) {
25 static constexpr const char *regs[] = {"x16", "x0", "x1", "x2", "x3", "x4", "x5"};
26 for (uint8_t i = 0; i < numRegs; ++i)
27 asmString << "mov " << regs[i] << ", $" << std::to_string(i) << "\n";
28 asmString << "svc #0x80\n";
29 } else { // LCOV_EXCL_LINE
30 assert_fail("Unsupported macOS target for inline assembly"); // LCOV_EXCL_LINE
31 } // LCOV_EXCL_LINE
32
1/2
✓ Branch 40 → 41 taken 1 time.
✗ Branch 40 → 81 not taken.
1 } else if (targetTriple.isOSLinux()) {
33
1/2
✓ Branch 42 → 43 taken 1 time.
✗ Branch 42 → 54 not taken.
1 if (targetTriple.getArch() == llvm::Triple::ArchType::x86_64) {
34 static constexpr const char *regs[] = {"%rax", "%rdi", "%rsi", "%rdx", "%r10", "%r8", "%r9"};
35
2/2
✓ Branch 52 → 44 taken 4 times.
✓ Branch 52 → 53 taken 1 time.
5 for (uint8_t i = 0; i < numRegs; ++i)
36
5/10
✓ Branch 44 → 45 taken 4 times.
✗ Branch 44 → 105 not taken.
✓ Branch 46 → 47 taken 4 times.
✗ Branch 46 → 96 not taken.
✓ Branch 47 → 48 taken 4 times.
✗ Branch 47 → 96 not taken.
✓ Branch 48 → 49 taken 4 times.
✗ Branch 48 → 96 not taken.
✓ Branch 49 → 50 taken 4 times.
✗ Branch 49 → 96 not taken.
4 asmString << "movq $" << std::to_string(i) << ", " << regs[i] << "\n";
37
1/2
✓ Branch 53 → 82 taken 1 time.
✗ Branch 53 → 105 not taken.
1 asmString << "syscall\n";
38 } else if (targetTriple.getArch() == llvm::Triple::ArchType::x86) {
39 // Note: Using movl for 32-bit registers.
40 static constexpr const char *regs[] = {"%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "%ebp"};
41 for (uint8_t i = 0; i < numRegs; ++i)
42 asmString << "movl $" << std::to_string(i) << ", " << regs[i] << "\n";
43 asmString << "int $0x80\n";
44 } else if (targetTriple.isAArch64()) {
45 static constexpr const char *regs[] = {"x8", "x0", "x1", "x2", "x3", "x4", "x5"};
46 for (uint8_t i = 0; i < numRegs; ++i)
47 asmString << "mov " << regs[i] << ", $" << std::to_string(i) << "\n";
48 asmString << "svc 0\n";
49 } else { // LCOV_EXCL_LINE
50 assert_fail("Unsupported Linux target for inline assembly"); // LCOV_EXCL_LINE
51 } // LCOV_EXCL_LINE
52 } else { // LCOV_EXCL_LINE
53 assert_fail("Unsupported target for inline assembly"); // LCOV_EXCL_LINE
54 } // LCOV_EXCL_LINE
55
56
1/2
✓ Branch 82 → 83 taken 1 time.
✗ Branch 82 → 105 not taken.
2 return asmString.str();
57 1 }
58
59 1 std::string IRGenerator::getSysCallConstraintString(uint8_t numRegs) const {
60 1 const llvm::Triple &targetTriple = cliOptions.targetTriple;
61
1/2
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 87 not taken.
1 std::stringstream constraints;
62
63 // Generate a comma-separated constraint string: first the operand constraints,
64 // then the corresponding clobbers, then extra clobbers.
65
2/4
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 85 not taken.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 34 taken 1 time.
1 if (targetTriple.isOSDarwin()) {
66 if (targetTriple.getArch() == llvm::Triple::ArchType::x86_64) {
67 static constexpr const char *clobbers[] = {"~{rax}", "~{rdi}", "~{rsi}", "~{rdx}", "~{r10}", "~{r8}", "~{r9}"};
68 for (uint8_t i = 0; i < numRegs; i++) {
69 constraints << "r";
70 if (i != numRegs - 1)
71 constraints << ",";
72 }
73 for (uint8_t i = 0; i < numRegs; i++)
74 constraints << "," << clobbers[i];
75 constraints << ",~{dirflag},~{fpsr},~{flags}";
76 } else if (targetTriple.isAArch64()) {
77 static constexpr const char *clobbers[] = {"~{x16}", "~{x0}", "~{x1}", "~{x2}", "~{x3}", "~{x4}", "~{x5}"};
78 for (uint8_t i = 0; i < numRegs; i++) {
79 constraints << "r";
80 if (i != numRegs - 1)
81 constraints << ",";
82 }
83 for (uint8_t i = 0; i < numRegs; i++)
84 constraints << "," << clobbers[i];
85 constraints << ",~{dirflag},~{fpsr},~{flags}";
86 } else { // LCOV_EXCL_LINE
87 assert_fail("Unsupported macOS target for inline assembly"); // LCOV_EXCL_LINE
88 } // LCOV_EXCL_LINE
89
1/2
✓ Branch 35 → 36 taken 1 time.
✗ Branch 35 → 79 not taken.
1 } else if (targetTriple.isOSLinux()) {
90
1/2
✓ Branch 37 → 38 taken 1 time.
✗ Branch 37 → 50 not taken.
1 if (targetTriple.getArch() == llvm::Triple::ArchType::x86_64) {
91 static constexpr const char *clobbers[] = {"~{rax}", "~{rdi}", "~{rsi}", "~{rdx}", "~{r10}", "~{r8}", "~{r9}"};
92
2/2
✓ Branch 43 → 39 taken 4 times.
✓ Branch 43 → 44 taken 1 time.
5 for (uint8_t i = 0; i < numRegs; i++) {
93
1/2
✓ Branch 39 → 40 taken 4 times.
✗ Branch 39 → 85 not taken.
4 constraints << "r";
94
2/2
✓ Branch 40 → 41 taken 3 times.
✓ Branch 40 → 42 taken 1 time.
4 if (i != numRegs - 1)
95
1/2
✓ Branch 41 → 42 taken 3 times.
✗ Branch 41 → 85 not taken.
3 constraints << ",";
96 }
97
2/2
✓ Branch 48 → 45 taken 4 times.
✓ Branch 48 → 49 taken 1 time.
5 for (uint8_t i = 0; i < numRegs; i++)
98
2/4
✓ Branch 45 → 46 taken 4 times.
✗ Branch 45 → 85 not taken.
✓ Branch 46 → 47 taken 4 times.
✗ Branch 46 → 85 not taken.
4 constraints << "," << clobbers[i];
99
1/2
✓ Branch 49 → 80 taken 1 time.
✗ Branch 49 → 85 not taken.
1 constraints << ",~{dirflag},~{fpsr},~{flags}";
100 } else if (targetTriple.getArch() == llvm::Triple::ArchType::x86) {
101 static constexpr const char *clobbers[] = {"~{eax}", "~{ebx}", "~{ecx}", "~{edx}", "~{esi}", "~{edi}", "~{ebp}"};
102 for (uint8_t i = 0; i < numRegs; i++) {
103 constraints << "r";
104 if (i != numRegs - 1)
105 constraints << ",";
106 }
107 for (uint8_t i = 0; i < numRegs; i++)
108 constraints << "," << clobbers[i];
109 constraints << ",~{dirflag},~{fpsr},~{flags}";
110 } else if (targetTriple.isAArch64()) {
111 static constexpr const char *clobbers[] = {"~{x8}", "~{x0}", "~{x1}", "~{x2}", "~{x3}", "~{x4}", "~{x5}"};
112 for (uint8_t i = 0; i < numRegs; i++) {
113 constraints << "r";
114 if (i != numRegs - 1)
115 constraints << ",";
116 }
117 for (uint8_t i = 0; i < numRegs; i++)
118 constraints << "," << clobbers[i];
119 constraints << ",~{dirflag},~{fpsr},~{flags}";
120 } else { // LCOV_EXCL_LINE
121 assert_fail("Unsupported Linux target for inline assembly"); // LCOV_EXCL_LINE
122 } // LCOV_EXCL_LINE
123 } else { // LCOV_EXCL_LINE
124 assert_fail("Unsupported target for inline assembly"); // LCOV_EXCL_LINE
125 } // LCOV_EXCL_LINE
126
127
1/2
✓ Branch 80 → 81 taken 1 time.
✗ Branch 80 → 85 not taken.
2 return constraints.str();
128 1 }
129
130 } // namespace spice::compiler
131