Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
bytecode_interpreter_example.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 <iostream>
37
39
40using namespace Aleph;
41
42namespace
43{
46 {
48 block.id = 1;
49 block.label = "exit";
50 block.terminator.kind = Compiler_IR_Terminator_Kind::Exit;
51 return block;
52 }
53
56 {
57 Compiler_IR_Module module;
58
60 global.id = 0;
61 global.kind = Compiler_IR_Slot_Kind::Global;
62 global.name = "answer";
63 module.global_slots.append(global);
64
65 auto * function = new Compiler_IR_Function();
66 function->id = 0;
67 function->name = "choose";
68 function->entry_block = 0;
69 function->exit_block = 1;
70 function->next_value_id = 5;
71
73 flag.id = 0;
74 flag.kind = Compiler_IR_Slot_Kind::Parameter;
75 flag.name = "flag";
76 function->local_slots.append(flag);
77
79 value.id = 1;
80 value.kind = Compiler_IR_Slot_Kind::Local;
81 value.name = "value";
82 function->local_slots.append(value);
83
85 entry.id = 0;
86 entry.label = "entry";
87
89 zero.kind = Compiler_IR_Instruction_Kind::Constant;
90 zero.result_id = 1;
91 zero.text = "0";
92 entry.instructions.append(zero);
93
95 init_store.kind = Compiler_IR_Instruction_Kind::Store;
96 init_store.local_slot_id = 1;
97 init_store.operands.append(1);
98 entry.instructions.append(init_store);
99
101 load_flag.kind = Compiler_IR_Instruction_Kind::Load;
102 load_flag.result_id = 2;
103 load_flag.local_slot_id = 0;
104 entry.instructions.append(load_flag);
105
106 entry.terminator.kind = Compiler_IR_Terminator_Kind::Branch;
107 entry.terminator.condition_value = 2;
110
112 exit.id = 1;
113 exit.label = "exit";
114 exit.terminator.kind = Compiler_IR_Terminator_Kind::Exit;
115 exit.predecessors.append(3);
116
118 then_block.id = 2;
119 then_block.label = "if.then.0";
120
122 one.kind = Compiler_IR_Instruction_Kind::Constant;
123 one.result_id = 3;
124 one.text = "1";
125 then_block.instructions.append(one);
126
128 then_store.kind = Compiler_IR_Instruction_Kind::Store;
129 then_store.local_slot_id = 1;
130 then_store.operands.append(3);
131 then_block.instructions.append(then_store);
132
133 then_block.terminator.kind = Compiler_IR_Terminator_Kind::Jump;
134 then_block.terminator.successors.append(3);
135 then_block.predecessors.append(0);
136
138 join_block.id = 3;
139 join_block.label = "if.end.0";
140
142 load_value.kind = Compiler_IR_Instruction_Kind::Load;
143 load_value.result_id = 5;
144 load_value.local_slot_id = 1;
145 join_block.instructions.append(load_value);
146
147 join_block.terminator.kind = Compiler_IR_Terminator_Kind::Return;
148 join_block.terminator.return_value = 5;
149 join_block.terminator.successors.append(1);
150 join_block.predecessors.append(2);
151 join_block.predecessors.append(4);
152
154 else_block.id = 4;
155 else_block.label = "if.else.0";
156
158 two.kind = Compiler_IR_Instruction_Kind::Constant;
159 two.result_id = 4;
160 two.text = "2";
161 else_block.instructions.append(two);
162
164 else_store.kind = Compiler_IR_Instruction_Kind::Store;
165 else_store.local_slot_id = 1;
166 else_store.operands.append(4);
167 else_block.instructions.append(else_store);
168
169 else_block.terminator.kind = Compiler_IR_Terminator_Kind::Jump;
170 else_block.terminator.successors.append(3);
171 else_block.predecessors.append(0);
172
173 function->blocks.append(entry);
174 function->blocks.append(exit);
175 function->blocks.append(then_block);
176 function->blocks.append(join_block);
177 function->blocks.append(else_block);
178 module.functions.append(function);
179
180 auto * top = new Compiler_IR_Function();
181 top->id = compiler_ir_invalid_id();
182 top->name = "<top-level>";
183 top->entry_block = 0;
184 top->exit_block = 1;
185 top->next_value_id = 3;
186
188 top_entry.id = 0;
189 top_entry.label = "entry";
190
192 function_ref.kind = Compiler_IR_Instruction_Kind::Function_Ref;
193 function_ref.result_id = 1;
194 function_ref.function_id = 0;
195 top_entry.instructions.append(function_ref);
196
198 constant.kind = Compiler_IR_Instruction_Kind::Constant;
199 constant.result_id = 2;
200 constant.text = "true";
201 constant.bool_value = true;
202 top_entry.instructions.append(constant);
203
205 call.kind = Compiler_IR_Instruction_Kind::Call;
206 call.result_id = 3;
207 call.operands.append(1);
208 call.operands.append(2);
209 top_entry.instructions.append(call);
210
212 store_global.kind = Compiler_IR_Instruction_Kind::Store;
213 store_global.global_slot_id = 0;
214 store_global.operands.append(3);
215 top_entry.instructions.append(store_global);
216
217 top_entry.terminator.kind = Compiler_IR_Terminator_Kind::Jump;
218 top_entry.terminator.successors.append(1);
219
220 auto top_exit = make_exit_block();
221 top_exit.predecessors.append(0);
222
223 top->blocks.append(top_entry);
224 top->blocks.append(top_exit);
225 module.top_level = top;
226 return module;
227 }
228
229 void
230 print_result(const char * label,
232 const Compiler_Bytecode_Module * module)
233 {
234 std::cout << label << ": " << compiler_bytecode_completion_kind_name(result.kind);
235 if (result.ok())
236 std::cout << " -> " << compiler_bytecode_value_to_string(result.value, module);
237 else
238 std::cout << " [" << result.error.code << "] " << result.error.message;
239 std::cout << " (steps=" << result.executed_instructions << ")\n";
240 }
241}
242
243int main()
244{
245 Compiler_Bytecode_Context ctx(1 << 16);
247
248 auto module = make_demo_module();
249 const auto * bytecode = lowering.lower_module(&module);
251
252 std::cout << compiler_dump_bytecode_module(bytecode) << '\n';
253 if (not report.valid)
254 {
255 std::cout << "Validation errors:\n";
256 for (size_t i = 0; i < report.errors.size(); ++i)
257 std::cout << "- " << report.errors.access(i) << '\n';
258 delete module.functions.access(0);
259 delete module.top_level;
260 return 1;
261 }
262
264 const auto top_level = vm.run_top_level();
265
268 const auto direct_call = vm.call_function(0, arguments);
269
270 print_result("TopLevel", top_level, bytecode);
271 print_result("Call choose(false)", direct_call, bytecode);
272 std::cout << '\n' << vm.dump_globals();
273
274 delete module.functions.access(0);
275 delete module.top_level;
276 return top_level.ok() and direct_call.ok() ? 0 : 1;
277}
Simple portable VM for executing the register bytecode in Bytecode.H.
size_t size_t int32_t value
Definition ca-c-api.h:116
Arena-backed ownership context for bytecode functions and modules.
Definition Bytecode.H:254
Lowers explicit IR into register-based bytecode.
Definition Bytecode.H:581
Small portable VM for executing one Compiler_Bytecode_Module.
T & append()
Allocate a new entry to the end of array.
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
void print_result(const string &label, const Multipoly &poly)
Compiler_SSA_Block & block(Compiler_SSA_Function &function, const Compiler_SSA_Block_Id id)
Definition SSA.H:636
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
and
Check uniqueness with explicit hash + equality functors.
std::string compiler_dump_bytecode_module(const Compiler_Bytecode_Module *module, const Compiler_Type_Context *types=nullptr)
Dumps all lowered bytecode in one module deterministically.
Definition Bytecode.H:1081
constexpr size_t compiler_ir_invalid_id() noexcept
Returns the sentinel invalid IR id.
Compiler_Bytecode_Validation_Report validate_bytecode_module(const Compiler_Bytecode_Module &module)
Validates all bytecode functions in one module.
Definition Bytecode.H:900
std::string compiler_bytecode_value_to_string(const Compiler_Bytecode_Value &value, const Compiler_Bytecode_Module *module=nullptr)
Renders one bytecode value deterministically.
const char * compiler_bytecode_completion_kind_name(const Compiler_Bytecode_Completion_Kind kind) noexcept
Stable debug name for one execution completion kind.
Result of one bytecode execution request.
Compiler_Bytecode_Runtime_Error error
Structured failure when kind == Runtime_Error.
size_t executed_instructions
Number of bytecode instructions observed by the VM.
bool ok() const noexcept
Returns whether execution completed without runtime errors.
Compiler_Bytecode_Completion_Kind kind
Final completion category.
Compiler_Bytecode_Value value
Produced return value or final Unit.
Bytecode module sharing global slot layout with the source IR module.
Definition Bytecode.H:246
std::string message
Human-readable runtime message.
std::string code
Stable runtime code such as BCV013.
static Compiler_Bytecode_Value make_bool(const bool value)
Builds a boolean runtime value.
One basic block of IR instructions.
std::string label
Deterministic debug label.
Compiler_IR_Terminator terminator
Explicit block terminator.
DynArray< Compiler_IR_Instruction > instructions
Linear instruction list.
Compiler_IR_Block_Id id
Stable block id.
Lowered IR for one function or top-level body.
One instruction producing an optional explicit result value.
std::string text
Constant spelling or debug payload.
Compiler_IR_Instruction_Kind kind
Instruction category.
Compiler_IR_Value_Id result_id
Produced value id, or 0 for void instructions.
DynArray< Compiler_IR_Value_Id > operands
Input values in deterministic order.
Lowered IR module with shared global slots and functions.
One storage slot used by the IR.
std::string name
Debug name of the slot.
size_t id
Stable slot id within its storage space.
Compiler_IR_Slot_Kind kind
Slot storage category.
Compiler_IR_Terminator_Kind kind
Terminator category.
DynArray< Compiler_IR_Block_Id > successors
Successor blocks in deterministic order.
Compiler_IR_Value_Id condition_value
Branch condition value, if any.
Compiler_SSA_Block_Id id
Dense SSA block id.
Definition SSA.H:163
std::string label
Deterministic debug label.
Definition SSA.H:165
Compiler_SSA_Terminator terminator
Explicit block terminator.
Definition SSA.H:169
Compiler_IR_Terminator_Kind kind
Terminator category.
Definition SSA.H:153