42#ifndef COMPILER_IR_LOWERING_MVP_H
43#define COMPILER_IR_LOWERING_MVP_H
48namespace Compiler_IR_Detail {
87 return *
module->functions.access(id);
100 for (
size_t i = 0; i <
module->global_slots.size(); ++i)
101 if (module->global_slots.access(i).name == name)
111 slot.
id =
module->global_slots.size();
114 slot.type_id = type_id;
116 module->global_slots.append(std::move(slot));
117 return module->global_slots.size() - 1;
131 module->functions.append(ir_function);
170 src.terminator.successors.append(to);
172 dst.predecessors.append(from);
183 const std::string &name,
191 slot.type_id = type_id;
213 <<
"Compiler_IR_Lowering: block already terminated";
215 blk.terminator.span = span;
229 <<
"Compiler_IR_Lowering: block already terminated";
231 blk.terminator.condition_value = condition;
232 blk.terminator.span = span;
245 <<
"Compiler_IR_Lowering: block already terminated";
247 blk.terminator.return_value =
value;
248 blk.terminator.span = span;
265 <<
"Compiler_IR_Lowering: block already terminated";
267 blk.terminator.span = span;
286 <<
"Compiler_IR_Lowering: attempted to leave empty scope stack";
291 const std::string &name,
295 <<
"Compiler_IR_Lowering: no active scope frame";
296 scopes.
access(scopes.
size() - 1).bindings.append({name, binding});
300 const std::string &name)
302 for (
size_t i = scopes.
size(); i > 0; --i)
304 const auto &[bindings] = scopes.
access(i - 1);
305 for (
size_t j = bindings.size(); j > 0; --j)
306 if (bindings.access(j - 1).first == name)
307 return bindings.access(j - 1).second;
345 inst.type_id = node->type_id;
346 inst.span = node->span;
347 inst.text = node->text;
348 inst.bool_value = node->bool_value;
356 const auto binding =
lookup(scopes, node->name);
361 inst.span = node->span;
363 switch (binding.kind)
368 inst.local_slot_id = binding.id;
375 inst.global_slot_id = binding.id;
382 inst.function_id = binding.id;
397 inst.type_id = node->type_id;
398 inst.span = node->span;
400 inst.operands.append(operand);
414 <<
"Compiler_IR_Lowering: assignment expects variable lhs";
417 const auto binding =
lookup(scopes, lhs->name);
432 load.
span = lhs->span;
444 binary.type_id = node->type_id;
456 store.
span = node->span;
472 inst.type_id = node->type_id;
473 inst.span = node->span;
475 inst.operands.append(lhs);
476 inst.operands.append(rhs);
486 for (
size_t i = 0; i < node->arguments.size(); ++i)
492 inst.type_id = node->type_id;
493 inst.span = node->span;
494 inst.operands.append(callee);
495 for (
size_t i = 0; i < arguments.
size(); ++i)
509 DynArray<std::pair<Compiler_IR_Block_Id, Compiler_IR_Block_Id>> &
loops)
539 binding.
type_id = node->binding_type;
549 binding.
type_id = node->binding_type;
552 const auto value = node->initializer !=
nullptr
558 store.
type_id = node->binding_type;
559 store.
span = node->span;
567 bind(scopes, node->name, binding);
586 for (
size_t i = 0; i < node->statements.size(); ++i)
602 if (node->else_branch !=
nullptr)
608 node->condition !=
nullptr ? node->condition->
span : node->span,
616 if (node->else_branch !=
nullptr)
640 node->condition !=
nullptr ? node->condition->
span : node->span,
656 if (
loops.is_empty())
668 if (
loops.is_empty())
684 for (
size_t i = 0; i <
module->global_slots.size(); ++i)
686 module->global_slots.
access(i).name,
687 {Compiler_IR_Detail::Binding::Kind::Global_Slot,
689 module->global_slots.access(i).type_id});
694 {Compiler_IR_Detail::Binding::Kind::Function,
695 function_ids.access(i).second,
696 function(function_ids.access(i).second).type_id});
718 {Compiler_IR_Detail::Binding::Kind::Local_Slot, slot_id, param.type_id});
726 for (
size_t i = 0; i < statements.
size(); ++i)
758 <<
"Compiler_IR_Lowering::lower_module(): null HIR module";
766 for (
size_t i = 0; i <
module->functions.size(); ++i)
769 for (
size_t i = 0; i <
module->statements.size(); ++i)
774 (
void)
builder.add_global_slot(stmt->name, stmt->binding_type, stmt->name_span);
777 for (
size_t i = 0; i <
builder.module->functions.size(); ++i)
779 auto &function =
builder.function(i);
793 top->name =
"<top-level>";
794 top->span =
module->span;
795 top->next_value_id = 0;
796 builder.module->top_level = top;
Reusable explicit-value IR model, validation, and deterministic dumps.
#define ah_runtime_error_unless(C)
Throws std::runtime_error if condition does NOT hold.
size_t size_t int32_t value
Arena-backed ownership context for IR nodes.
T * make(Args &&...args)
Allocates and constructs one IR object.
Lowers typed HIR into explicit-value IR.
const Compiler_Type_Context * types
Compiler_IR_Module * lower_module(const Compiler_HIR_Module *module) const
Lowers one HIR module into explicit-value IR.
Compiler_IR_Lowering(Compiler_IR_Context &ctx, const Compiler_Type_Context *type_ctx=nullptr) noexcept
Builds an IR lowerer over ctx.
const Compiler_Type_Context * type_context() const noexcept
Returns the optional type context used by this lowerer.
Context owning all compiler type nodes.
Compiler_Type_Id unit_type() const noexcept
Returns the preloaded Unit type id.
size_t size() const noexcept
Return the current dimension of array.
T pop()
Remove the last item of array (as if this was a stack)
T & access(const size_t i) const noexcept
Fast access without checking allocation and bound_min_clock checking.
T & append()
Allocate a new entry to the end of array.
bool is_empty() const noexcept
Return true if the array is empty.
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
bool contains_block_id(const DynArray< Compiler_IR_Block_Id > &ids, const Compiler_IR_Block_Id id) noexcept
Main namespace for Aleph-w library functions.
size_t Compiler_IR_Function_Id
Source_Span compiler_hir_merge_spans(const Source_Span &lhs, const Source_Span &rhs) noexcept
Merges two spans without depending on the parser-oriented AST layer.
and
Check uniqueness with explicit hash + equality functors.
size_t Compiler_IR_Value_Id
constexpr size_t compiler_ir_invalid_id() noexcept
Returns the sentinel invalid IR id.
size_t Compiler_IR_Block_Id
size_t Compiler_IR_Global_Slot_Id
Compiler_Operator_Kind compiler_operator_compound_base(const Compiler_Operator_Kind kind) noexcept
Returns the arithmetic operator underlying one compound assignment.
bool compiler_operator_is_compound_assignment(const Compiler_Operator_Kind kind) noexcept
Returns whether kind is one compound-assignment operator.
size_t Compiler_IR_Local_Slot_Id
Compiler_IR_Slot_Kind
Storage-space classification for slots.
Structured block statement.
DynArray< Compiler_HIR_Stmt * > statements
Nested statements.
Typed function call expression.
Typed constant expression.
Expression statement in HIR.
Base class for HIR expressions.
Compiler_HIR_Expr_Kind kind
Runtime node kind.
DynArray< Compiler_HIR_Param > parameters
Parameters in declaration order.
Compiler_HIR_Block_Stmt * body
Function body.
Structured conditional statement.
Typed lexical binding statement.
DynArray< Compiler_HIR_Function * > functions
Lowered top-level functions.
DynArray< Compiler_HIR_Stmt * > statements
Lowered top-level statements.
Source_Span span
Source region associated with the HIR node.
Compiler_HIR_Expr * value
Returned value, or nullptr.
Base class for HIR statements.
Compiler_HIR_Stmt_Kind kind
Runtime node kind.
Typed variable reference expression.
Structured while-loop statement.
One basic block of IR instructions.
std::string label
Deterministic debug label.
Compiler_IR_Block_Id id
Stable block id.
Storage class used by the lowerer for one name binding.
One lexical scope frame used during IR lowering.
DynArray< std::pair< std::string, Binding > > bindings
Lowered IR for one function or top-level body.
Compiler_IR_Value_Id next_value_id
Next value id to allocate while lowering.
DynArray< Compiler_IR_Block > blocks
Basic blocks in deterministic id order.
bool is_top_level() const noexcept
Returns whether this IR function represents the top-level body.
std::string name
Debug or source-level name.
Compiler_IR_Block_Id exit_block
Canonical exit block.
Compiler_IR_Block_Id entry_block
Canonical entry block.
DynArray< Compiler_IR_Slot > local_slots
Parameter/local slots in stable order.
Compiler_IR_Function_Id id
Stable function id within the module.
const Compiler_HIR_Function * source_function
Originating HIR function, or nullptr for top-level.
Source_Span span
Source span of the function/body.
One instruction producing an optional explicit result value.
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.
Source_Span span
Source region associated with the instruction.
Compiler_Type_Id type_id
Result type or stored value type.
Compiler_IR_Local_Slot_Id local_slot_id
Referenced local/parameter slot, when relevant.
Compiler_IR_Global_Slot_Id global_slot_id
Referenced global slot, when relevant.
const Compiler_Type_Context * types
static Compiler_IR_Detail::Binding lookup(const DynArray< Compiler_IR_Detail::Scope_Frame > &scopes, const std::string &name)
static void enter_scope(DynArray< Compiler_IR_Detail::Scope_Frame > &scopes)
DynArray< std::pair< std::string, Compiler_IR_Function_Id > > function_ids
static void bind(DynArray< Compiler_IR_Detail::Scope_Frame > &scopes, const std::string &name, const Compiler_IR_Detail::Binding &binding)
static Compiler_IR_Block & block(Compiler_IR_Function &function, const Compiler_IR_Block_Id id)
static void merge_span(Source_Span &dst, const Source_Span &src)
Compiler_IR_Global_Slot_Id find_global_slot_id(const std::string &name) const noexcept
static void leave_scope(DynArray< Compiler_IR_Detail::Scope_Frame > &scopes)
Compiler_IR_Context * ctx
Compiler_IR_Value_Id emit_unit_constant(Compiler_IR_Function &function, const Compiler_IR_Block_Id block_id, const Source_Span &span) const
void lower_function_body(Compiler_IR_Function &function, const DynArray< Compiler_HIR_Stmt * > &statements)
Compiler_IR_Function_Id find_function_id(const std::string &name) const noexcept
Compiler_IR_Global_Slot_Id add_global_slot(const std::string &name, const Compiler_Type_Id type_id, const Source_Span &span) const
void preload_global_bindings(DynArray< Compiler_IR_Detail::Scope_Frame > &scopes) const
static void set_branch(Compiler_IR_Function &function, const Compiler_IR_Block_Id from, const Compiler_IR_Value_Id condition, const Source_Span &span, const Compiler_IR_Block_Id then_block, const Compiler_IR_Block_Id else_block)
static void set_unreachable(Compiler_IR_Function &function, const Compiler_IR_Block_Id id, const Source_Span &span={})
static void add_edge(Compiler_IR_Function &function, const Compiler_IR_Block_Id from, const Compiler_IR_Block_Id to)
static void set_exit(Compiler_IR_Function &function, const Compiler_IR_Block_Id id)
static void set_return(Compiler_IR_Function &function, const Compiler_IR_Block_Id from, const Compiler_IR_Value_Id value, const Source_Span &span={})
Compiler_IR_Value_Id lower_expr(Compiler_IR_Function &function, const Compiler_HIR_Expr *expr, const Compiler_IR_Block_Id block_id, const DynArray< Compiler_IR_Detail::Scope_Frame > &scopes)
static Compiler_IR_Block_Id create_block(Compiler_IR_Function &function, std::string label)
Compiler_IR_Block_Id ensure_block(Compiler_IR_Function &function, Compiler_IR_Block_Id current)
static void emit_instruction(Compiler_IR_Function &function, const Compiler_IR_Block_Id block_id, Compiler_IR_Instruction instruction)
const Compiler_HIR_Module * hir
Compiler_IR_Block_Id lower_stmt(Compiler_IR_Function &function, const Compiler_HIR_Stmt *stmt, Compiler_IR_Block_Id current, DynArray< Compiler_IR_Detail::Scope_Frame > &scopes, DynArray< std::pair< Compiler_IR_Block_Id, Compiler_IR_Block_Id > > &loops)
Compiler_IR_Function_Id predeclare_function(const Compiler_HIR_Function *hir_function)
static Compiler_IR_Value_Id next_value(Compiler_IR_Function &function) noexcept
static Compiler_IR_Local_Slot_Id add_local_slot(Compiler_IR_Function &function, const Compiler_IR_Slot_Kind kind, const std::string &name, const Compiler_Type_Id type_id, const Source_Span &span)
Compiler_IR_Function & function(Compiler_IR_Function_Id id) const
static void set_jump(Compiler_IR_Function &function, const Compiler_IR_Block_Id from, const Compiler_IR_Block_Id to, const Source_Span &span={})
Lowered IR module with shared global slots and functions.
One storage slot used by the IR.
size_t id
Stable slot id within its storage space.
Half-open byte range inside a source file.
bool is_valid() const noexcept
Returns whether the span belongs to a registered file.