72 inline constexpr size_t
75 return std::numeric_limits<size_t>::max();
101 return "StoreGlobal";
109 return "FunctionRef";
249 template <
typename T,
typename...
Args>
T *
254 <<
"Compiler_SSA_Context: arena allocation failed";
258 [](
void * raw)
noexcept
260 static_cast<T *
>(raw)->~
T();
269 for (
size_t i =
owned.size(); i > 0; --i)
271 auto &[ptr, destroy] =
owned.access(i - 1);
272 if (destroy !=
nullptr and ptr !=
nullptr)
288 namespace Compiler_SSA_Detail
321 return "B" + std::to_string(
id);
327 return "v" + std::to_string(
id);
333 return "s" + std::to_string(
id);
339 return "g" + std::to_string(
id);
345 return "f" + std::to_string(
id);
356 const std::string & text,
359 const std::string
padding(indent,
' ');
361 while (begin < text.size())
363 const auto end = text.find(
'\n', begin);
364 if (end == std::string::npos)
371 out <<
padding << text.substr(begin, end - begin) <<
'\n';
382 for (
size_t i = 0; i <
ids.size(); ++i)
383 if (
ids.access(i) ==
id)
392 for (
size_t i = 0; i < function.
blocks.size(); ++i)
402 const auto block_id =
worklist.pop();
407 const auto &
block = function.
blocks.access(block_id);
419 inline Normalized_IR_Function
433 for (
size_t i = 0; i < source.
blocks.size(); ++i)
436 for (
size_t i = 0; i < source.
blocks.size(); ++i)
447 for (
size_t i = 0; i <
normalized.function.blocks.size(); ++i)
453 for (
size_t j = 0; j <
source_block.terminator.successors.size(); ++j)
455 const auto succ =
source_block.terminator.successors.access(j);
469 for (
size_t i = 0; i <
normalized.function.blocks.size(); ++i)
470 normalized.function.blocks.access(i).predecessors.clear();
471 for (
size_t i = 0; i <
normalized.function.blocks.size(); ++i)
472 for (
size_t j = 0; j <
normalized.function.blocks.access(i).terminator.successors.size(); ++j)
474 const auto succ =
normalized.function.blocks.access(i).terminator.successors.access(j);
477 normalized.function.blocks.access(succ).predecessors.append(i);
491 info.reachable_blocks.append(
false);
493 info.dominators.append({});
494 info.dominance_frontiers.append({});
495 info.dominator_tree_children.append({});
507 if (
not info.reachable_blocks.access(i))
511 info.dominators.access(i).set(i,
true);
514 if (
info.reachable_blocks.access(j))
515 info.dominators.access(i).set(j,
true);
522 for (
size_t block_id = 0; block_id <
block_count; ++block_id)
524 if (
not info.reachable_blocks.access(block_id)
531 const auto &
block = function.
blocks.access(block_id);
554 info.dominators.access(block_id)))
562 for (
size_t block_id = 0; block_id <
block_count; ++block_id)
564 if (
not info.reachable_blocks.access(block_id)
598 info.immediate_dominators.access(block_id) =
idom;
600 info.dominator_tree_children.access(
idom).append(block_id);
603 for (
size_t block_id = 0; block_id <
block_count; ++block_id)
605 if (
not info.reachable_blocks.access(block_id))
608 const auto &
block = function.
blocks.access(block_id);
616 and runner !=
info.immediate_dominators.access(block_id))
619 info.dominance_frontiers.access(runner).append(block_id);
620 runner =
info.immediate_dominators.access(runner);
631 ++function.next_value_id;
632 return function.next_value_id;
639 return function.
blocks.access(
id);
646 return function.
blocks.access(
id);
653 if (slot_id >=
stacks.size()
or stacks.access(slot_id).is_empty())
655 return stacks.access(slot_id).access(
stacks.access(slot_id).size() - 1);
685 for (
size_t i = 0; i <
out_block.phis.size(); ++i)
693 for (
size_t i = 0; i <
in_block.instructions.size(); ++i)
746 if (
not inst.operands.is_empty())
770 for (
size_t operand = 0; operand <
inst.operands.size(); ++operand)
772 if (
inst.result_id != 0)
790 for (
size_t i = 0; i <
out_block.terminator.successors.size(); ++i)
828 const bool top_level)
const
832 function->
id = source.
id;
833 function->top_level = top_level;
834 function->name = source.
name;
835 function->span = source.
span;
836 function->type_id = source.
type_id;
837 function->source_function = &source;
839 function->entry_block =
normalized.function.entry_block;
840 function->exit_block =
normalized.function.exit_block;
841 function->dominance =
844 for (
size_t i = 0; i <
normalized.function.blocks.size(); ++i)
852 function->blocks.append(std::move(block));
858 for (
size_t i = 0; i <
normalized.function.blocks.size(); ++i)
868 for (
size_t i = 0; i <
normalized.function.local_slots.size(); ++i)
871 for (
size_t slot_id = 0; slot_id <
normalized.function.local_slots.size(); ++slot_id)
878 for (
size_t block_id = 0; block_id <
normalized.function.blocks.size(); ++block_id)
880 const auto & block =
normalized.function.blocks.access(block_id);
895 for (
size_t slot_id = 0; slot_id <
normalized.function.local_slots.size(); ++slot_id)
901 if (
def_block >= function->dominance.dominance_frontiers.size())
905 i < function->dominance.dominance_frontiers.access(
def_block).
size();
909 function->dominance.dominance_frontiers.access(
def_block).access(i);
915 normalized.function.local_slots.access(slot_id).type_id,
916 normalized.function.local_slots.access(slot_id).span});
924 for (
size_t block_id = 0; block_id < function->blocks.size(); ++block_id)
925 for (
size_t i = 0; i <
phi_specs.access(block_id).
size(); ++i)
929 phi.type_id =
phi_specs.access(block_id).access(i).type_id;
931 for (
size_t operand = 0;
932 operand < function->blocks.access(block_id).predecessors.size();
934 phi.operands.append(0);
935 function->blocks.access(block_id).phis.append(std::move(
phi));
939 for (
size_t i = 0; i <
normalized.function.local_slots.size(); ++i)
942 for (
size_t slot_id = 0; slot_id <
normalized.function.local_slots.size(); ++slot_id)
956 for (
size_t i = 0; i <=
normalized.function.next_value_id; ++i)
964 function->entry_block,
982 <<
"Compiler_SSA_Lowering::lower_module(): null IR module";
986 for (
size_t i = 0; i <
module->functions.size(); ++i)
987 result->functions.append(lower_function_internal(*module->
functions.access(i),
false));
989 result->top_level = lower_function_internal(*module->
top_level,
true);
1007 if (function.
blocks.is_empty())
1009 fail(
"SSA function '" + function.
name +
"' has no blocks");
1014 fail(
"SSA function '" + function.
name +
"' has invalid entry block");
1016 fail(
"SSA function '" + function.
name +
"' has invalid exit block");
1023 fail(
"SSA function '" + function.
name
1024 +
"' has mismatched dominance metadata sizes");
1033 for (
size_t i = 0; i < function.
parameters.size(); ++i)
1037 fail(
"SSA parameter in function '" + function.
name +
"' has invalid value id");
1039 != Compiler_SSA_Detail::Definition_Location::Kind::Invalid)
1040 fail(
"SSA function '" + function.
name +
"' defines value "
1044 {Compiler_SSA_Detail::Definition_Location::Kind::Parameter,
1049 for (
size_t block_id = 0; block_id < function.
blocks.size(); ++block_id)
1051 const auto & block = function.
blocks.access(block_id);
1052 if (block.
id != block_id)
1053 fail(
"SSA function '" + function.
name
1054 +
"' has mismatched block id at "
1058 +
" in function '" + function.
name +
"' is unterminated");
1063 +
" must not have an immediate dominator");
1070 +
" of function '" + function.
name +
"' has invalid result id");
1072 != Compiler_SSA_Detail::Definition_Location::Kind::Invalid)
1073 fail(
"SSA function '" + function.
name +
"' defines value "
1077 {Compiler_SSA_Detail::Definition_Location::Kind::Phi,
1083 +
" references an invalid local slot");
1086 +
" must have one operand per predecessor");
1092 if ((
inst.kind == Compiler_SSA_Instruction_Kind::Constant
1093 or inst.kind == Compiler_SSA_Instruction_Kind::Load_Global
1094 or inst.kind == Compiler_SSA_Instruction_Kind::Unary
1095 or inst.kind == Compiler_SSA_Instruction_Kind::Binary
1096 or inst.kind == Compiler_SSA_Instruction_Kind::Call
1097 or inst.kind == Compiler_SSA_Instruction_Kind::Function_Ref)
1100 +
" of function '" + function.
name +
"' must define a result");
1102 if (
inst.result_id != 0)
1106 +
" of function '" + function.
name +
"' has invalid result id");
1108 != Compiler_SSA_Detail::Definition_Location::Kind::Invalid)
1109 fail(
"SSA function '" + function.
name +
"' defines value "
1113 {Compiler_SSA_Detail::Definition_Location::Kind::Instruction,
1118 if ((
inst.kind == Compiler_SSA_Instruction_Kind::Load_Global
1119 or inst.kind == Compiler_SSA_Instruction_Kind::Store_Global)
1120 and (module ==
nullptr or inst.global_slot_id >= module->global_slots.size()))
1121 fail(
"SSA instruction references invalid global slot in function '"
1122 + function.
name +
"'");
1123 if (
inst.kind == Compiler_SSA_Instruction_Kind::Function_Ref
1124 and (module ==
nullptr or inst.function_id >= module->functions.size()))
1125 fail(
"SSA instruction references invalid function id in function '"
1126 + function.
name +
"'");
1143 const std::string & context)
1147 fail(context +
" references invalid SSA value");
1152 if (def.kind == Compiler_SSA_Detail::Definition_Location::Kind::Invalid)
1154 fail(context +
" references undefined SSA value "
1161 if (def.kind == Compiler_SSA_Detail::Definition_Location::Kind::Parameter)
1166 fail(context +
" references non-dominating SSA value "
1171 if (def.kind == Compiler_SSA_Detail::Definition_Location::Kind::Parameter)
1176 if (def.kind == Compiler_SSA_Detail::Definition_Location::Kind::Phi)
1180 fail(context +
" references SSA value defined later in the same block");
1185 fail(context +
" references non-dominating SSA value "
1189 for (
size_t block_id = 0; block_id < function.
blocks.size(); ++block_id)
1191 const auto & block = function.
blocks.access(block_id);
1210 if (block.
terminator.
kind == Compiler_IR_Terminator_Kind::Branch)
1217 else if (block.
terminator.
kind == Compiler_IR_Terminator_Kind::Return)
1237 if (
not child.valid)
1239 for (
size_t i = 0; i < child.errors.size(); ++i)
1240 report.errors.append(child.errors.access(i));
1241 for (
size_t i = 0; i < child.warnings.size(); ++i)
1242 report.warnings.append(child.warnings.access(i));
1245 for (
size_t i = 0; i <
module.functions.size(); ++i)
1259 std::ostringstream
out;
1260 if (function ==
nullptr)
1262 out <<
"<null-ssa-function>\n";
1266 out <<
"SSAFunction(" << function->
name <<
")";
1267 if (types !=
nullptr and function->
type_id != 0)
1268 out <<
": " << types->to_string(function->
type_id);
1275 out <<
" Parameters:\n";
1276 for (
size_t i = 0; i < function->
parameters.size(); ++i)
1288 for (
size_t block_id = 0; block_id < function->
blocks.size(); ++block_id)
1290 const auto & block = function->
blocks.access(block_id);
1293 <<
", " << block.
label <<
"]\n";
1295 if (block.
phis.is_empty())
1296 out <<
" Phis: <none>\n";
1315 if (types !=
nullptr and phi.type_id != 0)
1316 out <<
" : " << types->to_string(
phi.type_id);
1322 out <<
" Instructions: <none>\n";
1325 out <<
" Instructions:\n";
1330 if (
inst.result_id != 0)
1333 if (
inst.kind == Compiler_SSA_Instruction_Kind::Load_Global
1334 or inst.kind == Compiler_SSA_Instruction_Kind::Store_Global)
1336 else if (
inst.kind == Compiler_SSA_Instruction_Kind::Function_Ref)
1338 else if (
inst.kind == Compiler_SSA_Instruction_Kind::Unary
1339 or inst.kind == Compiler_SSA_Instruction_Kind::Binary)
1341 else if (
inst.kind == Compiler_SSA_Instruction_Kind::Constant)
1342 out <<
'(' <<
inst.text <<
')';
1344 if (
not inst.operands.is_empty())
1347 for (
size_t operand = 0; operand <
inst.operands.size(); ++operand)
1356 if (types !=
nullptr and inst.type_id != 0)
1357 out <<
" : " << types->to_string(
inst.type_id);
1362 out <<
" Terminator: "
1364 if (block.
terminator.
kind == Compiler_IR_Terminator_Kind::Branch)
1366 else if (block.
terminator.
kind == Compiler_IR_Terminator_Kind::Return)
1370 out <<
" Successors:";
1377 out << (i == 0 ?
" " :
", ");
1390 out <<
" Frontier:";
1397 out << (i == 0 ?
" " :
", ");
1413 std::ostringstream
out;
1414 if (module ==
nullptr)
1416 out <<
"<null-ssa-module>\n";
1420 out <<
"SSAModule\n";
1423 out <<
" Globals:\n";
1424 for (
size_t i = 0; i <
module->global_slots.size(); ++i)
1426 const auto &
slot =
module->global_slots.access(i);
1428 <<
" " <<
slot.name;
1429 if (types !=
nullptr and slot.type_id != 0)
1430 out <<
": " << types->to_string(
slot.type_id);
1435 for (
size_t i = 0; i <
module->functions.size(); ++i)
Reusable dataflow analyses and dead-code elimination over Compiler_IR_Model.H.
Memory arena for fast bulk allocations.
Exception handling system with formatted messages for Aleph-w.
#define ah_runtime_error_unless(C)
Throws std::runtime_error if condition does NOT hold.
size_t size_t int32_t * out
Arena allocator for fast bump-pointer allocation.
void reset() noexcept
Reset arena, making all memory available again.
static constexpr size_t DEFAULT_SIZE
Default arena size (1 MB).
Arena-backed ownership context for SSA functions and modules.
DynArray< Owned_Object > owned
Compiler_SSA_Context & operator=(const Compiler_SSA_Context &)=delete
T * make(Args &&... args)
Allocates and constructs one SSA object in the arena.
Compiler_SSA_Context(const Compiler_SSA_Context &)=delete
~Compiler_SSA_Context() noexcept
Destroys all managed objects and rewinds the arena.
Compiler_SSA_Context(const size_t arena_size=AhArenaAllocator::DEFAULT_SIZE)
Constructs an SSA context.
void reset() noexcept
Resets the arena and destroys all tracked objects.
Lowers non-SSA IR to SSA form for all reachable blocks.
Compiler_SSA_Context * ctx
Compiler_SSA_Lowering(Compiler_SSA_Context &context) noexcept
Builds an SSA lowerer over ctx.
Compiler_SSA_Module * lower_module(const Compiler_IR_Module *module) const
Lowers one IR module to SSA form.
Compiler_SSA_Function * lower_function_internal(const Compiler_IR_Function &source, const bool top_level) const
Context owning all compiler type nodes.
void clear() noexcept
Empties the container.
size_t size() const noexcept
Return the current dimension of array.
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().
Freq_Node * pred
Predecessor node in level-order traversal.
bool bit_set_equals(const Compiler_Dataflow_Bit_Set &lhs, const Compiler_Dataflow_Bit_Set &rhs) noexcept
Compiler_Dataflow_Bit_Set bit_set_intersection(const Compiler_Dataflow_Bit_Set &lhs, const Compiler_Dataflow_Bit_Set &rhs)
std::string block_name(const Compiler_IR_Block_Id id)
std::string function_name(const Compiler_IR_Function_Id id)
std::string block_name(const Compiler_SSA_Block_Id id)
const char * token_name(const Compiler_Operator_Kind kind) noexcept
size_t predecessor_index(const Compiler_SSA_Block &block, const Compiler_SSA_Block_Id predecessor)
void append_indented_text(std::ostream &out, const std::string &text, const size_t indent)
Compiler_SSA_Value_Id current_slot_value(const DynArray< DynArray< Compiler_SSA_Value_Id > > &stacks, const Compiler_IR_Local_Slot_Id slot_id) noexcept
Compiler_SSA_Block & block(Compiler_SSA_Function &function, const Compiler_SSA_Block_Id id)
size_t next_value(Compiler_SSA_Function &function) noexcept
std::string value_name(const Compiler_SSA_Value_Id id)
Normalized_IR_Function normalize_ir_function(const Compiler_IR_Function &source)
void rename_recursive(Compiler_SSA_Function &output, const Compiler_IR_Function &normalized, const Compiler_SSA_Dominance_Info &dominance, const DynArray< DynArray< Phi_Spec > > &phi_specs, Compiler_SSA_Block_Id block_id, DynArray< DynArray< Compiler_SSA_Value_Id > > &slot_stacks, DynArray< Compiler_SSA_Value_Id > &renamed_values)
std::string local_slot_name(const Compiler_IR_Local_Slot_Id id)
std::string global_slot_name(const Compiler_IR_Global_Slot_Id id)
bool contains_block_id(const DynArray< Compiler_SSA_Block_Id > &ids, const Compiler_SSA_Block_Id id) noexcept
Compiler_SSA_Dominance_Info compute_dominance_info(const Compiler_IR_Function &function)
DynArray< bool > compute_reachable_blocks(const Compiler_IR_Function &function)
Main namespace for Aleph-w library functions.
const char * compiler_ir_terminator_kind_name(const Compiler_IR_Terminator_Kind kind) noexcept
Stable debug name for one terminator kind.
Compiler_SSA_Validation_Report validate_ssa_module(const Compiler_SSA_Module &module)
Validates all functions in one SSA module.
@ Store_Global
globals[slot] <- src
@ Binary
dst <- op(lhs, rhs)
@ Load_Global
dst <- globals[slot]
@ Call
dst <- callee(args...)
size_t Compiler_IR_Function_Id
@ Function_Ref
Reference to one bytecode function in the current module.
void message(const char *file, int line, const char *format,...)
Print an informational message with file and line info.
size_t size(Node *root) noexcept
const char * compiler_operator_name(const Compiler_Operator_Kind kind) noexcept
Returns a stable debug name for one operator kind.
Compiler_SSA_Validation_Report validate_ssa_function(const Compiler_SSA_Function &function, const Compiler_SSA_Module *module=nullptr)
Validates one SSA function structurally and semantically.
size_t Compiler_SSA_Block_Id
and
Check uniqueness with explicit hash + equality functors.
std::decay_t< typename HeadC::Item_Type > T
constexpr size_t compiler_ssa_invalid_id() noexcept
Returns the sentinel invalid SSA id.
std::string compiler_dump_ssa_function(const Compiler_SSA_Function *function, const Compiler_SSA_Module *module=nullptr, const Compiler_Type_Context *types=nullptr)
Dumps one SSA function deterministically.
constexpr size_t compiler_ir_invalid_id() noexcept
Returns the sentinel invalid IR id.
const char * compiler_ssa_instruction_kind_name(const Compiler_SSA_Instruction_Kind kind) noexcept
Returns a stable debug name for an SSA instruction kind.
Compiler_SSA_Instruction_Kind
Instruction kinds supported by the SSA form.
size_t Compiler_IR_Block_Id
Itor3 merge(Itor1 source1Beg, Itor1 source1End, Itor2 source2Beg, Itor2 source2End, Itor3 destBeg)
Merge two sorted ranges.
size_t Compiler_IR_Global_Slot_Id
size_t Compiler_SSA_Value_Id
Compiler_IR_Terminator_Kind
Terminator kinds supported by the MVP IR.
std::string compiler_dump_ssa_module(const Compiler_SSA_Module *module, const Compiler_Type_Context *types=nullptr)
Dumps all SSA functions in one module deterministically.
Compiler_Operator_Kind
Stable operator kinds shared by reusable compiler layers.
size_t Compiler_IR_Local_Slot_Id
Small reusable bit-set for slot-domain dataflow analyses.
void resize(const size_t count, const bool value=false)
Clears all existing bits and resizes the set to count elements.
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.
std::string name
Debug or source-level name.
Compiler_Type_Id type_id
Full function type, when known.
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.
Lowered IR module with shared global slots and functions.
DynArray< Compiler_IR_Function * > functions
Lowered non-top-level functions.
Compiler_IR_Function * top_level
Optional top-level body lowered as a function.
One SSA basic block containing phis, instructions, and a terminator.
Source_Span span
Aggregate source span.
DynArray< Compiler_SSA_Block_Id > predecessors
Predecessor ids in deterministic order.
Compiler_SSA_Block_Id id
Dense SSA block id.
Compiler_IR_Block_Id source_block_id
Original IR block id before SSA normalization.
DynArray< Compiler_SSA_Instruction > instructions
Linear SSA instruction list.
bool is_terminated() const noexcept
Returns whether the block already has a terminator.
std::string label
Deterministic debug label.
Compiler_SSA_Terminator terminator
Explicit block terminator.
DynArray< Compiler_SSA_Phi > phis
Phi nodes evaluated before instructions.
void(* destroy)(void *) noexcept
Compiler_SSA_Block_Id block_id
DynArray< Compiler_IR_Block_Id > source_block_ids
Compiler_IR_Function function
Compiler_IR_Local_Slot_Id slot_id
Dominance metadata computed for one SSA function.
DynArray< bool > reachable_blocks
Reachability from entry for each SSA block.
DynArray< Compiler_Dataflow_Bit_Set > dominators
Dominator sets by block.
DynArray< DynArray< Compiler_SSA_Block_Id > > dominance_frontiers
Dominance frontier for each block.
DynArray< Compiler_SSA_Block_Id > immediate_dominators
Immediate dominator, or invalid for entry/unreachable.
DynArray< DynArray< Compiler_SSA_Block_Id > > dominator_tree_children
Dominator-tree children by block.
SSA form for one function or top-level body lowered from IR.
Compiler_SSA_Block_Id entry_block
Canonical entry block.
std::string name
Debug/source name.
bool is_top_level() const noexcept
Returns whether this SSA function represents the top-level body.
DynArray< Compiler_SSA_Block > blocks
Reachable SSA blocks in deterministic order.
Compiler_SSA_Dominance_Info dominance
Dominance metadata over blocks.
DynArray< Compiler_IR_Slot > local_slots
Original local/parameter slots for debug and phi ownership.
Compiler_SSA_Block_Id exit_block
Canonical exit block.
bool top_level
Whether this function represents the lowered top-level body.
Compiler_SSA_Value_Id next_value_id
Next SSA value id to allocate.
Source_Span span
Source span of the function/body.
Compiler_IR_Function_Id id
Stable function id within the source module.
const Compiler_IR_Function * source_function
Original non-SSA IR function.
DynArray< Compiler_SSA_Parameter > parameters
Entry parameter SSA definitions.
Compiler_Type_Id type_id
Full function type, when known.
One SSA instruction producing an optional explicit result value.
Source_Span span
Source region associated with the instruction.
Compiler_Type_Id type_id
Result or stored type.
bool bool_value
Decoded boolean payload for bool constants.
Compiler_SSA_Value_Id result_id
Produced value id, or 0 for void instructions.
Compiler_SSA_Instruction_Kind kind
Instruction category.
Compiler_IR_Global_Slot_Id global_slot_id
Referenced global slot, when relevant.
std::string text
Constant spelling or debug payload.
Compiler_IR_Function_Id function_id
Referenced callee function, when relevant.
Compiler_Operator_Kind op
Unary/binary operator when relevant.
DynArray< Compiler_SSA_Value_Id > operands
Input SSA values in deterministic order.
SSA module sharing global slots with the source IR module.
Compiler_SSA_Function * top_level
Optional lowered top-level body.
DynArray< Compiler_IR_Slot > global_slots
Shared global slot layout from the source IR module.
DynArray< Compiler_SSA_Function * > functions
Lowered non-top-level functions.
SSA parameter definition that seeds renaming for one IR parameter slot.
Compiler_SSA_Value_Id value_id
SSA value defined by the parameter.
std::string name
Debug/source name.
Compiler_IR_Local_Slot_Id slot_id
Original IR slot represented by this parameter.
Compiler_Type_Id type_id
Parameter type.
Source_Span span
Parameter declaration span.
Phi node merging values for one original IR local slot.
Compiler_IR_Local_Slot_Id slot_id
Original local/parameter slot represented by the phi.
Compiler_Type_Id type_id
Merged type.
Source_Span span
Source location associated with the slot declaration.
Compiler_SSA_Value_Id result_id
SSA value produced by the phi.
DynArray< Compiler_SSA_Value_Id > operands
Incoming values aligned with predecessor order.
Explicit terminator for one SSA basic block.
Source_Span span
Source region associated with the terminator.
Compiler_SSA_Value_Id return_value
Return value, when relevant.
DynArray< Compiler_SSA_Block_Id > successors
Successors in deterministic order.
Compiler_IR_Terminator_Kind kind
Terminator category.
Compiler_SSA_Value_Id condition_value
Branch condition, when relevant.
Validation report for one SSA function or module.
DynArray< std::string > warnings
Non-fatal observations.
DynArray< std::string > errors
Hard validation failures.
bool valid
Whether all hard validation checks passed.
Half-open byte range inside a source file.
Lazy and scalable dynamic array implementation.