Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
compiler_builder_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_IR_Builder.H>
40
41using namespace Aleph;
42
44{
46 Compiler_HIR_Context hir_ctx(1 << 15);
47 Compiler_HIR_Builder hir(hir_ctx);
48
49 auto * module = hir.make_module();
50 auto * body = hir.make_block();
51 auto * function = hir.make_function(
52 "add",
54 {types.integer_type(), types.integer_type()}, types.integer_type()),
55 {});
56 hir.add_parameter(*function, "x", types.integer_type());
57 hir.add_parameter(*function, "y", types.integer_type());
58 hir.set_body(*function, body);
59 hir.append_function(*module, function);
60
61 auto * sum = hir.make_binary(hir.make_variable("x", types.integer_type()),
62 Compiler_Operator_Kind::Plus,
63 hir.make_variable("y", types.integer_type()),
64 types.integer_type());
65 hir.append_statement(*body, hir.make_return_stmt(sum));
66
67 auto * call = hir.make_call(
68 hir.make_variable("add",
70 {types.integer_type(), types.integer_type()},
71 types.integer_type())),
72 types.integer_type());
73 hir.append_argument(*call, hir.make_integer_constant(40, types.integer_type()));
74 hir.append_argument(*call, hir.make_integer_constant(2, types.integer_type()));
76 *module, hir.make_let_stmt("value", types.integer_type(), {}, call));
77
79 compiler_dump_hir_module(module, types),
80 "HIRModule\n"
81 " Function(add): fn(Int, Int) -> Int\n"
82 " Params: x: Int, y: Int\n"
83 " Body:\n"
84 " Block\n"
85 " Return\n"
86 " Binary(Plus): Int\n"
87 " Variable(x): Int\n"
88 " Variable(y): Int\n"
89 " Let(value): Int\n"
90 " Call: Int\n"
91 " Callee:\n"
92 " Variable(add): fn(Int, Int) -> Int\n"
93 " Args:\n"
94 " Constant(Integer, 40): Int\n"
95 " Constant(Integer, 2): Int\n");
96}
97
99{
101 Compiler_IR_Context ir_ctx(1 << 15);
102 Compiler_IR_Builder ir(ir_ctx);
103
104 auto * module = ir.make_module();
105 const auto global_value = ir.add_global_slot(*module, "value", types.integer_type());
106
107 auto * function = ir.make_function(
108 "add",
109 types.make_function_type(
110 {types.integer_type(), types.integer_type()}, types.integer_type()));
111 const auto function_id = ir.append_function(*module, function);
112 const auto x
113 = ir.add_local_slot(*function,
114 Compiler_IR_Slot_Kind::Parameter,
115 "x",
116 types.integer_type());
117 const auto y
118 = ir.add_local_slot(*function,
119 Compiler_IR_Slot_Kind::Parameter,
120 "y",
121 types.integer_type());
122 const auto entry = ir.create_block(*function, "entry");
123 const auto exit = ir.create_block(*function, "exit");
124 ir.set_entry_block(*function, entry);
125 ir.set_exit_block(*function, exit);
126
127 const auto vx = ir.emit_load_local(*function, entry, x, types.integer_type());
128 const auto vy = ir.emit_load_local(*function, entry, y, types.integer_type());
129 const auto sum = ir.emit_binary(
130 *function, entry, Compiler_Operator_Kind::Plus, vx, vy, types.integer_type());
131 ir.set_return(*function, entry, sum);
132 ir.set_exit(*function, exit);
133
134 auto * top = ir.make_function("<top-level>");
135 ir.set_top_level(*module, top);
136 const auto top_entry = ir.create_block(*top, "entry");
137 const auto top_exit = ir.create_block(*top, "exit");
138 ir.set_entry_block(*top, top_entry);
139 ir.set_exit_block(*top, top_exit);
140
141 const auto add_ref = ir.emit_function_ref(
142 *top,
143 top_entry,
144 function_id,
145 types.make_function_type(
146 {types.integer_type(), types.integer_type()}, types.integer_type()));
148 arguments.append(ir.emit_constant(*top, top_entry, types.integer_type(), "40"));
149 arguments.append(ir.emit_constant(*top, top_entry, types.integer_type(), "2"));
150 const auto call
151 = ir.emit_call(*top, top_entry, add_ref, arguments, types.integer_type());
152 ir.emit_store_global(*top, top_entry, global_value, call, types.integer_type());
153 ir.set_jump(*top, top_entry, top_exit);
154 ir.set_exit(*top, top_exit);
155
156 const auto report = validate_ir_module(*module);
157 ASSERT_TRUE(report.valid);
158 EXPECT_TRUE(report.warnings.is_empty());
159 EXPECT_EQ(
160 compiler_dump_ir_module(module, &types),
161 "IRModule\n"
162 " Globals:\n"
163 " g0 value: Int\n"
164 " IRFunction(add): fn(Int, Int) -> Int\n"
165 " Entry: B0\n"
166 " Exit: B1\n"
167 " Slots:\n"
168 " s0 [Parameter] x: Int\n"
169 " s1 [Parameter] y: Int\n"
170 " Block B0 [entry]\n"
171 " Instructions:\n"
172 " v1 = Load s0 : Int\n"
173 " v2 = Load s1 : Int\n"
174 " v3 = Binary(Plus) [v1, v2] : Int\n"
175 " Terminator: Return [v3]\n"
176 " Successors: B1\n"
177 " Block B1 [exit]\n"
178 " Instructions: <none>\n"
179 " Terminator: Exit\n"
180 " Successors: <none>\n"
181 " IRFunction(<top-level>)\n"
182 " Entry: B0\n"
183 " Exit: B1\n"
184 " Block B0 [entry]\n"
185 " Instructions:\n"
186 " v1 = FunctionRef f0 : fn(Int, Int) -> Int\n"
187 " v2 = Constant(40) : Int\n"
188 " v3 = Constant(2) : Int\n"
189 " v4 = Call [v1, v2, v3] : Int\n"
190 " Store g0 [v4] : Int\n"
191 " Terminator: Jump\n"
192 " Successors: B1\n"
193 " Block B1 [exit]\n"
194 " Instructions: <none>\n"
195 " Terminator: Exit\n"
196 " Successors: <none>\n");
197}
198
200{
201 Compiler_IR_Context ir_ctx(1 << 15);
202 Compiler_IR_Builder ir(ir_ctx);
203
204 auto * function = ir.make_function("manual");
205 const auto exit = ir.create_block(*function, "exit");
206 ir.set_exit_block(*function, exit);
207 ir.set_exit(*function, exit);
208
209 EXPECT_THROW(ir.set_exit(*function, exit), std::runtime_error);
210}
211
213{
214 Compiler_IR_Context ir_ctx(1 << 15);
215 Compiler_IR_Builder ir(ir_ctx);
216
217 auto * function = ir.make_function("manual");
218 const auto entry = ir.create_block(*function, "entry");
219 const auto exit = ir.create_block(*function, "exit");
220 ir.set_entry_block(*function, entry);
221 ir.set_jump(*function, entry, exit);
222 ir.set_exit(*function, exit);
223
224 EXPECT_EQ(function->exit_block, exit);
225
226 const auto report = validate_ir_function(*function);
227 EXPECT_TRUE(report.valid);
228}
Reusable builder helpers for constructing HIR directly.
Reusable builder helpers for constructing explicit IR directly.
Small reusable helper that allocates and connects HIR nodes.
static void append_top_level_statement(Compiler_HIR_Module &module, Compiler_HIR_Stmt *stmt)
Appends one top-level statement to module and updates the span.
Compiler_HIR_Let_Stmt * make_let_stmt(std::string name, const Compiler_Type_Id type_id, const Source_Span &name_span={}, Compiler_HIR_Expr *initializer=nullptr, const Source_Span &span={}) const
Allocates one lexical binding statement.
static void set_body(Compiler_HIR_Function &function, Compiler_HIR_Block_Stmt *body) noexcept
Attaches body to function and refreshes the aggregate span.
Compiler_HIR_Variable_Expr * make_variable(std::string name, const Compiler_Type_Id type_id=0, const Source_Span &span={}) const
Allocates one variable-reference expression.
Compiler_HIR_Call_Expr * make_call(Compiler_HIR_Expr *callee, const Compiler_Type_Id type_id=0, const Source_Span &lparen_span={}, const Source_Span &rparen_span={}) const
Allocates one call expression without arguments.
static void append_statement(Compiler_HIR_Block_Stmt &block, Compiler_HIR_Stmt *stmt)
Appends one nested statement to block and updates the span.
static Compiler_HIR_Param & add_parameter(Compiler_HIR_Function &function, std::string name, const Compiler_Type_Id type_id, const Source_Span &span={})
Adds one parameter metadata entry to function.
Compiler_HIR_Block_Stmt * make_block(const Source_Span &lbrace={}, const Source_Span &rbrace={}) const
Allocates one structured block statement.
static void append_function(Compiler_HIR_Module &module, Compiler_HIR_Function *function)
Appends one function to module and updates the module span.
Compiler_HIR_Binary_Expr * make_binary(Compiler_HIR_Expr *lhs, const Compiler_Operator_Kind op, Compiler_HIR_Expr *rhs, const Compiler_Type_Id type_id=0, const Source_Span &operator_span={}) const
Allocates one binary expression.
Compiler_HIR_Function * make_function(std::string name, const Compiler_Type_Id type_id=0, const Source_Span &name_span={}, Compiler_HIR_Block_Stmt *body=nullptr, const Source_Span &span={}) const
Allocates one function node without inserting it into any module.
Compiler_HIR_Return_Stmt * make_return_stmt(Compiler_HIR_Expr *value=nullptr, const Source_Span &span={}) const
Allocates one return statement.
Compiler_HIR_Constant_Expr * make_integer_constant(const long long value, const Compiler_Type_Id type_id, const Source_Span &span={}) const
Allocates one integer constant expression.
static void append_argument(Compiler_HIR_Call_Expr &call, Compiler_HIR_Expr *argument)
Appends one argument to call and updates the aggregate span.
Arena-backed ownership context for HIR nodes.
Small reusable helper that allocates and connects IR nodes.
static void emit_store_global(Compiler_IR_Function &function, const Compiler_IR_Block_Id block_id, const Compiler_IR_Global_Slot_Id slot_id, const Compiler_IR_Value_Id value_id, const Compiler_Type_Id type_id, const Source_Span &span={})
Emits one store into a global slot.
static Compiler_IR_Value_Id emit_constant(Compiler_IR_Function &function, const Compiler_IR_Block_Id block_id, const Compiler_Type_Id type_id, std::string text, const Source_Span &span={}, const bool bool_value=false)
Emits one constant instruction.
static Compiler_IR_Function_Id append_function(Compiler_IR_Module &module, Compiler_IR_Function *function)
Appends one non-top-level function to module and assigns its id.
static Compiler_IR_Local_Slot_Id add_local_slot(Compiler_IR_Function &function, const Compiler_IR_Slot_Kind kind, std::string name, const Compiler_Type_Id type_id, const Source_Span &span={})
Appends one local or parameter slot to function.
static void set_exit_block(Compiler_IR_Function &function, const Compiler_IR_Block_Id block_id)
Marks one block as the canonical exit block.
static Compiler_IR_Block_Id create_block(Compiler_IR_Function &function, std::string label)
Creates one empty block and returns its id.
static Compiler_IR_Value_Id emit_load_local(Compiler_IR_Function &function, const Compiler_IR_Block_Id block_id, const Compiler_IR_Local_Slot_Id slot_id, const Compiler_Type_Id type_id, const Source_Span &span={})
Emits one load from a local or parameter slot.
static void set_entry_block(Compiler_IR_Function &function, const Compiler_IR_Block_Id block_id)
Marks one block as the canonical entry block.
static Compiler_IR_Global_Slot_Id add_global_slot(Compiler_IR_Module &module, std::string name, const Compiler_Type_Id type_id, const Source_Span &span={})
Appends one global slot to module.
static void set_exit(Compiler_IR_Function &function, const Compiler_IR_Block_Id block_id, const Source_Span &span={})
Sets one block terminator to Exit.
static Compiler_IR_Value_Id emit_call(Compiler_IR_Function &function, const Compiler_IR_Block_Id block_id, const Compiler_IR_Value_Id callee, const DynArray< Compiler_IR_Value_Id > &arguments, const Compiler_Type_Id type_id, const Source_Span &span={})
Emits one call instruction.
static void set_return(Compiler_IR_Function &function, const Compiler_IR_Block_Id from, const Compiler_IR_Value_Id return_value, const Source_Span &span={})
Sets one return terminator and connects it to the exit block.
static void set_jump(Compiler_IR_Function &function, const Compiler_IR_Block_Id from, const Compiler_IR_Block_Id to, const Source_Span &span={})
Sets one jump terminator and predecessor/successor edge.
Compiler_IR_Function * make_function(std::string name, const Compiler_Type_Id type_id=0, const Source_Span &span={}, const Compiler_HIR_Function *source_function=nullptr) const
Allocates one function without inserting it into a module.
static Compiler_IR_Value_Id emit_binary(Compiler_IR_Function &function, const Compiler_IR_Block_Id block_id, const Compiler_Operator_Kind op, const Compiler_IR_Value_Id lhs, const Compiler_IR_Value_Id rhs, const Compiler_Type_Id type_id, const Source_Span &span={})
Emits one binary instruction.
static Compiler_IR_Value_Id emit_function_ref(Compiler_IR_Function &function, const Compiler_IR_Block_Id block_id, const Compiler_IR_Function_Id function_id, const Compiler_Type_Id type_id, const Source_Span &span={})
Emits one function reference instruction.
static Compiler_IR_Function * set_top_level(Compiler_IR_Module &module, Compiler_IR_Function *function)
Installs one top-level function body in module.
Arena-backed ownership context for IR nodes.
Context owning all compiler type nodes.
Compiler_Type_Id make_function_type(const DynArray< Compiler_Type_Id > &parameters, const Compiler_Type_Id result)
Creates a function type.
Compiler_Type_Id integer_type() const noexcept
Returns the preloaded Int type id.
T & append()
Allocate a new entry to the end of array.
#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
static mpfr_t y
Definition mpfr_mul_d.c:3
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
std::string compiler_dump_ir_module(const Compiler_IR_Module *module, const Compiler_Type_Context *types=nullptr)
Dumps all lowered IR in one module deterministically.
Compiler_IR_Validation_Report validate_ir_module(const Compiler_IR_Module &module)
Validates all functions in one lowered IR module.
void exit(const char *file, int line, const char *format,...)
Print a message and exit the program.
Definition ahDefs.C:125
std::string compiler_dump_hir_module(const Compiler_HIR_Module *module, const Compiler_Type_Context &types)
Dumps one HIR module in a deterministic text format.
Compiler_IR_Validation_Report validate_ir_function(const Compiler_IR_Function &function, const Compiler_IR_Module *module=nullptr)
Validates one lowered IR function structurally.
T sum(const Container &container, const T &init=T{})
Compute sum of all elements.