| 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 |