GCC Code Coverage Report


Directory: src/
File: src/analysis/analysis-borrow-checker.cpp
Date: 2025-10-24 11:14:59
Exec Total Coverage
Lines: 42 42 100.0%
Functions: 10 10 100.0%
Branches: 6 6 100.0%

Line Branch Exec Source
1 /* Copyright 2025 Jonathan S. Arney
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * https://github.com/jarney/gyoji/blob/master/LICENSE
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include <gyoji-analysis.hpp>
16 #include <stdio.h>
17
18 using namespace Gyoji::mir;
19 using namespace Gyoji::context;
20 using namespace Gyoji::analysis;
21
22 /**
23 * This class indicates an operation
24 * inside a basic block. The block
25 * is the ID of the basic block
26 * and operation is the index into
27 * that basic block indicating
28 * a specific operation.
29 */
30 class BasicBlockOperation {
31 public:
32 BasicBlockOperation(size_t _blockid, size_t _operationid);
33 BasicBlockOperation(const BasicBlockOperation & _other);
34 ~BasicBlockOperation();
35 size_t blockid;
36 size_t operationid;
37 };
38
39 /**
40 * This class represents an edge in the control-flow
41 * graph with edges between operations and the 'next'
42 * operation in the graph.
43 */
44 class CFGEdge {
45 public:
46 CFGEdge(const BasicBlockOperation & start, const BasicBlockOperation & end);
47 CFGEdge(const CFGEdge & _other);
48 ~CFGEdge();
49 BasicBlockOperation start;
50 BasicBlockOperation end;
51 };
52 ///////////////////////////////
53 // BasicBlockOperation
54 ///////////////////////////////
55 728 BasicBlockOperation::BasicBlockOperation(size_t _blockid, size_t _operationid)
56 728 : blockid(_blockid)
57 728 , operationid(_operationid)
58 728 {}
59 1732 BasicBlockOperation::BasicBlockOperation(const BasicBlockOperation & _other)
60 1732 : blockid(_other.blockid)
61 1732 , operationid(_other.operationid)
62 1732 {}
63 2460 BasicBlockOperation::~BasicBlockOperation()
64 2460 {}
65 ///////////////////////////////
66 // CFGEdge
67 ///////////////////////////////
68 364 CFGEdge::CFGEdge(const BasicBlockOperation & _start, const BasicBlockOperation & _end)
69 364 : start(_start)
70 364 , end(_end)
71 364 {}
72 502 CFGEdge::CFGEdge(const CFGEdge & _other)
73 502 : start(_other.start)
74 502 , end(_other.end)
75 502 {}
76 866 CFGEdge::~CFGEdge()
77 866 {}
78
79 ///////////////////////////////
80 // AnalysisPassBorrowChecker
81 ///////////////////////////////
82 28 AnalysisPassBorrowChecker::AnalysisPassBorrowChecker(CompilerContext & _compiler_context)
83 56 : AnalysisPass(_compiler_context, "borrow checker")
84 28 {}
85 112 AnalysisPassBorrowChecker::~AnalysisPassBorrowChecker()
86 112 {}
87
88 void
89 28 AnalysisPassBorrowChecker::check(const MIR & mir) const
90 {
91 // Here, we follow the basic plan of the 'Polonius' algorithm
92 // for borrow checking.
93
94
2/2
✓ Branch 7 taken 270 times.
✓ Branch 8 taken 28 times.
298 for (const auto & function : mir.get_functions().get_functions()) {
95 270 check(*function);
96 }
97
98 28 }
99
100 270 void AnalysisPassBorrowChecker::check(const Function & function) const
101 {
102 // We start with mapping the "edges" of the graph
103 // from the basic-blocks of the function.
104 270 const auto & blocks = function.get_blocks();
105
106 270 std::vector<CFGEdge> cfg_edges;
107
108
2/2
✓ Branch 5 taken 364 times.
✓ Branch 6 taken 270 times.
634 for (const auto & block_it : blocks) {
109 364 const BasicBlock & block = *block_it.second;
110 364 const std::vector<Gyoji::owned<Operation>> & operations = block.get_operations();
111
112 #if 0
113 // In principle, empty blocks are ok as long as
114 // they are not reachable.
115 // Each basic block must have at least one operation.
116 if (operations.size() == 0) {
117 get_compiler_context()
118 .get_errors()
119 .add_simple_error(function.get_source_ref(),
120 "Compiler bug! Please report this message(borrow)",
121 std::string("Function ") + function.get_name() + std::string(" found with empty Basic Block")
122 );
123 break;
124 }
125 #endif
126 // TODO: Finish the logic of
127 // tying blocks together in a graph
128 // by traversing it.
129 364 BasicBlockOperation startblock(block_it.first, 0);
130 364 BasicBlockOperation endblock(block_it.first, 1);
131 364 cfg_edges.push_back(CFGEdge(startblock, endblock));
132
2/2
✓ Branch 6 taken 4378 times.
✓ Branch 7 taken 364 times.
4742 for (const auto & operation_ptr : block.get_operations()) {
133 4378 const Operation & operation = *operation_ptr;
134 }
135 364 }
136
137 // TODO:
138 // We need to finish the CFG above
139 // and also extract the 'loans', the 'regions',
140 // and the 'live/killed' status of each variable from the MIR.
141
142 // Finally, we perform the graph-traversal
143 // to solve this. It should mainly take the form of
144 // a Hornsat solver, I think.
145 270 }
146