Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
compiler_cfg_test.cc
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
36#include <gtest/gtest.h>
37
39#include <Compiler_CFG.H>
40#include <Compiler_Parser.H>
41
42using namespace Aleph;
43
44namespace
45{
47 lower_to_cfg(const std::string & source,
50 Compiler_Ast_Context & ast_ctx,
51 Compiler_HIR_Context & hir_ctx,
54 {
55 const auto file_id = sm.add_virtual_file("main.aw", source);
56 Compiler_Parser parser(ast_ctx, sm, file_id, &dx);
57 const auto * module = parser.parse_module();
59
60 typed.analyze_module(module);
62
63 Compiler_HIR_Lowering hir_lowering(hir_ctx, typed);
64 const auto * hir = hir_lowering.lower_module(module);
65
67 return cfg_lowering.lower_module(hir);
68 }
69}
70
72{
75 Compiler_Ast_Context ast_ctx(1 << 16);
76 Compiler_HIR_Context hir_ctx(1 << 16);
79
80 const auto * cfg = lower_to_cfg(
81 "fn add(x, y) {\n"
82 " let z = x + y;\n"
83 " return z;\n"
84 "}\n"
85 "let value = add(1, 2);\n",
86 sm, dx, ast_ctx, hir_ctx, cfg_ctx, typed);
87
88 const auto report = validate_cfg_module(*cfg);
89 ASSERT_TRUE(report.valid);
90 EXPECT_TRUE(report.warnings.is_empty());
91
92 const auto dump = compiler_dump_cfg_module(cfg, &typed.type_context());
94 dump,
95 "CFGModule\n"
96 " CFGFunction(add): fn(Int, Int) -> Int\n"
97 " Entry: B0\n"
98 " Exit: B1\n"
99 " Block B0 [entry]\n"
100 " Statements:\n"
101 " Let(z): Int\n"
102 " Binary(Plus): Int\n"
103 " Variable(x): Int\n"
104 " Variable(y): Int\n"
105 " Terminator: Return\n"
106 " Value:\n"
107 " Variable(z): Int\n"
108 " Successors: B1\n"
109 " Predecessors: <none>\n"
110 " Block B1 [exit]\n"
111 " Statements: <none>\n"
112 " Terminator: Exit\n"
113 " Successors: <none>\n"
114 " Predecessors: B0\n"
115 " CFGFunction(<top-level>)\n"
116 " Entry: B0\n"
117 " Exit: B1\n"
118 " Block B0 [entry]\n"
119 " Statements:\n"
120 " Let(value): Int\n"
121 " Call: Int\n"
122 " Callee:\n"
123 " Variable(add): fn(Int, Int) -> Int\n"
124 " Args:\n"
125 " Constant(Integer, 1): Int\n"
126 " Constant(Integer, 2): Int\n"
127 " Terminator: Jump\n"
128 " Successors: B1\n"
129 " Predecessors: <none>\n"
130 " Block B1 [exit]\n"
131 " Statements: <none>\n"
132 " Terminator: Exit\n"
133 " Successors: <none>\n"
134 " Predecessors: B0\n");
135}
136
138{
141 Compiler_Ast_Context ast_ctx(1 << 16);
142 Compiler_HIR_Context hir_ctx(1 << 16);
145
146 const auto * cfg = lower_to_cfg(
147 "fn choose(flag) {\n"
148 " let value = 0;\n"
149 " if (flag) {\n"
150 " value = 1;\n"
151 " } else {\n"
152 " value = 2;\n"
153 " }\n"
154 " return value;\n"
155 "}\n",
156 sm, dx, ast_ctx, hir_ctx, cfg_ctx, typed);
157
158 const auto & function = *cfg->functions.access(0);
159 const auto report = validate_cfg_function(function);
160 ASSERT_TRUE(report.valid);
161 EXPECT_TRUE(report.warnings.is_empty());
162
163 ASSERT_EQ(function.blocks.size(), 5u);
164 EXPECT_EQ(function.blocks.access(0).terminator.kind,
165 Compiler_CFG_Terminator_Kind::Branch);
166 ASSERT_EQ(function.blocks.access(0).terminator.successors.size(), 2u);
167 EXPECT_EQ(function.blocks.access(0).terminator.successors.access(0), 2u);
168 EXPECT_EQ(function.blocks.access(0).terminator.successors.access(1), 4u);
169 EXPECT_EQ(function.blocks.access(2).terminator.kind,
170 Compiler_CFG_Terminator_Kind::Jump);
171 EXPECT_EQ(function.blocks.access(4).terminator.kind,
172 Compiler_CFG_Terminator_Kind::Jump);
173 EXPECT_EQ(function.blocks.access(3).terminator.kind,
174 Compiler_CFG_Terminator_Kind::Return);
175 EXPECT_EQ(function.blocks.access(1).terminator.kind,
176 Compiler_CFG_Terminator_Kind::Exit);
177}
178
180{
183 Compiler_Ast_Context ast_ctx(1 << 16);
184 Compiler_HIR_Context hir_ctx(1 << 16);
187
188 const auto * cfg = lower_to_cfg(
189 "fn loop(flag) {\n"
190 " while (flag) {\n"
191 " flag = false;\n"
192 " continue;\n"
193 " }\n"
194 "}\n",
195 sm, dx, ast_ctx, hir_ctx, cfg_ctx, typed);
196
197 const auto & function = *cfg->functions.access(0);
198 const auto report = validate_cfg_function(function);
199 ASSERT_TRUE(report.valid);
200 EXPECT_TRUE(report.warnings.is_empty());
201
202 ASSERT_EQ(function.blocks.size(), 5u);
203 EXPECT_EQ(function.blocks.access(0).terminator.kind,
204 Compiler_CFG_Terminator_Kind::Jump);
205 EXPECT_EQ(function.blocks.access(0).terminator.successors.access(0), 2u);
206 EXPECT_EQ(function.blocks.access(2).terminator.kind,
207 Compiler_CFG_Terminator_Kind::Branch);
208 EXPECT_EQ(function.blocks.access(2).terminator.successors.access(0), 3u);
209 EXPECT_EQ(function.blocks.access(2).terminator.successors.access(1), 4u);
210 EXPECT_EQ(function.blocks.access(3).terminator.kind,
211 Compiler_CFG_Terminator_Kind::Jump);
212 EXPECT_EQ(function.blocks.access(3).terminator.successors.access(0), 2u);
213 EXPECT_EQ(function.blocks.access(4).terminator.kind,
214 Compiler_CFG_Terminator_Kind::Jump);
215 EXPECT_EQ(function.blocks.access(4).terminator.successors.access(0), 1u);
216}
217
219{
222 Compiler_Ast_Context ast_ctx(1 << 16);
223 Compiler_HIR_Context hir_ctx(1 << 16);
226
227 const auto * cfg = lower_to_cfg(
228 "fn dead() {\n"
229 " return 1;\n"
230 " let later = 2;\n"
231 "}\n",
232 sm, dx, ast_ctx, hir_ctx, cfg_ctx, typed);
233
234 const auto report = validate_cfg_module(*cfg);
235 ASSERT_TRUE(report.valid);
236 ASSERT_EQ(report.warnings.size(), 1u);
237 EXPECT_NE(report.warnings.access(0).find("unreachable"), std::string::npos);
238}
239
241{
242 Compiler_CFG_Function function;
243 function.name = "bad_return";
244 function.entry_block = 0;
245 function.exit_block = 1;
246
247 Compiler_CFG_Block entry;
248 entry.id = 0;
249 entry.label = "entry";
250 entry.terminator.kind = Compiler_CFG_Terminator_Kind::Return;
252
254 exit.id = 1;
255 exit.label = "exit";
256 exit.terminator.kind = Compiler_CFG_Terminator_Kind::Exit;
257
259 stray.id = 2;
260 stray.label = "stray";
261 stray.terminator.kind = Compiler_CFG_Terminator_Kind::Jump;
262 stray.terminator.successors.append(1);
263 stray.predecessors.append(0);
264
265 function.blocks.append(entry);
266 function.blocks.append(exit);
267 function.blocks.append(stray);
268
269 const auto report = validate_cfg_function(function);
270 EXPECT_FALSE(report.valid);
271 bool found_canonical_exit_error = false;
272 for (size_t i = 0; i < report.errors.size(); ++i)
273 if (report.errors.access(i).find("must point to the canonical exit block")
274 != std::string::npos)
277}
Basic-block CFG representation and lowering from structured HIR.
Lowering from the current MVP typed AST into the reusable HIR model.
Recursive-descent parser for the compiler-support MVP grammar.
Arena-backed ownership context for AST nodes.
Arena-backed ownership context for CFG objects.
Transformation engine that lowers typed HIR into reusable CFGs.
Arena-backed ownership context for HIR nodes.
Lowers the MVP typed AST into HIR.
Recursive-descent parser that produces an AST in Compiler_Ast_Context.
Inference-oriented semantic pass for the MVP compiler front-end.
void analyze_module(const Compiler_Module *module)
Runs the typed semantic analysis for module.
const Compiler_Type_Context & type_context() const noexcept
Returns the internal type context.
Diagnostic accumulator and renderer.
bool has_errors() const noexcept
Returns whether any error or fatal diagnostic was emitted.
T & append()
Allocate a new entry to the end of array.
Stores source files and resolves offsets into human-readable data.
Definition ah-source.H:184
#define TEST(name)
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Definition Blossom.H:466
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
void exit(const char *file, int line, const char *format,...)
Print a message and exit the program.
Definition ahDefs.C:125
Compiler_CFG_Validation_Report validate_cfg_function(const Compiler_CFG_Function &function)
Validates one lowered CFG function structurally.
Compiler_CFG_Validation_Report validate_cfg_module(const Compiler_CFG_Module &module)
Validates all CFGs in a lowered module.
std::string compiler_dump_cfg_module(const Compiler_CFG_Module *module, const Compiler_Type_Context *types=nullptr)
Dumps a complete CFG module in text format for debugging.
Represents a single basic block in a CFG.
Compiler_CFG_Block_Id id
Unique identifier in the function.
std::string label
Human-readable debug label (e.g., "entry", "loop.body").
Compiler_CFG_Terminator terminator
How the block ends.
CFG representation of a single function or top-level body.
Compiler_CFG_Block_Id exit_block
Canonical exit block ID.
std::string name
Function or script name.
DynArray< Compiler_CFG_Block > blocks
All basic blocks belonging to this function.
Compiler_CFG_Block_Id entry_block
Starting block ID.
Aggregates all lowered CFGs for a compilation unit.
Compiler_CFG_Terminator_Kind kind
Category of terminator.
DynArray< Compiler_CFG_Block_Id > successors
List of successor block IDs.