38#include <gtest/gtest.h>
60 function.
name =
"manual";
67 slot.kind = Compiler_IR_Slot_Kind::Local;
73 entry.
label =
"entry";
76 load.
kind = Compiler_IR_Instruction_Kind::Load;
88 store.
kind = Compiler_IR_Instruction_Kind::Store;
98 exit.predecessors.append(0);
100 function.
blocks.append(entry);
109 function.
name =
"choose";
116 flag.
kind = Compiler_IR_Slot_Kind::Parameter;
122 value.kind = Compiler_IR_Slot_Kind::Local;
123 value.name =
"value";
128 entry.
label =
"entry";
131 c0.
kind = Compiler_IR_Instruction_Kind::Constant;
137 store0.
kind = Compiler_IR_Instruction_Kind::Store;
139 store0.operands.append(1);
154 exit.predecessors.append(3);
161 c1.
kind = Compiler_IR_Instruction_Kind::Constant;
167 store1.
kind = Compiler_IR_Instruction_Kind::Store;
169 store1.operands.append(3);
172 then_block.terminator.kind = Compiler_IR_Terminator_Kind::Jump;
186 join_block.terminator.kind = Compiler_IR_Terminator_Kind::Return;
197 c2.
kind = Compiler_IR_Instruction_Kind::Constant;
203 store2.
kind = Compiler_IR_Instruction_Kind::Store;
205 store2.operands.append(4);
208 else_block.terminator.kind = Compiler_IR_Terminator_Kind::Jump;
212 function.
blocks.append(entry);
224 function.
name =
"simplify";
231 slot.kind = Compiler_IR_Slot_Kind::Local;
237 entry.
label =
"entry";
240 c1.
kind = Compiler_IR_Instruction_Kind::Constant;
246 store1.
kind = Compiler_IR_Instruction_Kind::Store;
248 store1.operands.append(1);
252 cond.
kind = Compiler_IR_Instruction_Kind::Constant;
264 exit.predecessors.append(3);
271 c2.
kind = Compiler_IR_Instruction_Kind::Constant;
277 store2.
kind = Compiler_IR_Instruction_Kind::Store;
279 store2.operands.append(3);
282 then_block.terminator.kind = Compiler_IR_Terminator_Kind::Jump;
296 join_block.terminator.kind = Compiler_IR_Terminator_Kind::Return;
307 c3.
kind = Compiler_IR_Instruction_Kind::Constant;
313 store3.
kind = Compiler_IR_Instruction_Kind::Store;
315 store3.operands.append(4);
318 else_block.terminator.kind = Compiler_IR_Terminator_Kind::Jump;
322 function.
blocks.append(entry);
334 function.
name =
"stale_preds";
341 slot.kind = Compiler_IR_Slot_Kind::Local;
347 entry.
label =
"entry";
350 cond.
kind = Compiler_IR_Instruction_Kind::Constant;
362 exit.predecessors.append(4);
370 c1.
kind = Compiler_IR_Instruction_Kind::Constant;
376 s1.
kind = Compiler_IR_Instruction_Kind::Store;
377 s1.local_slot_id = 0;
378 s1.operands.append(2);
381 then_block.terminator.kind = Compiler_IR_Terminator_Kind::Jump;
390 c2.
kind = Compiler_IR_Instruction_Kind::Constant;
396 s2.
kind = Compiler_IR_Instruction_Kind::Store;
397 s2.local_slot_id = 0;
398 s2.operands.append(3);
401 else_block.terminator.kind = Compiler_IR_Terminator_Kind::Jump;
410 load_x.
kind = Compiler_IR_Instruction_Kind::Load;
415 join_block.terminator.kind = Compiler_IR_Terminator_Kind::Return;
419 function.
blocks.append(entry);
431 function.
name =
"spin";
437 entry.
label =
"entry";
451 function.
blocks.append(entry);
453 function.
blocks.append(loop);
476 function.
name =
"branch_fold";
483 slot.kind = Compiler_IR_Slot_Kind::Local;
489 entry.
label =
"entry";
492 c0.
kind = Compiler_IR_Instruction_Kind::Constant;
498 s0.
kind = Compiler_IR_Instruction_Kind::Store;
499 s0.local_slot_id = 0;
500 s0.operands.append(1);
504 cond.
kind = Compiler_IR_Instruction_Kind::Constant;
518 exit_blk.terminator.kind = Compiler_IR_Terminator_Kind::Exit;
527 c99.
kind = Compiler_IR_Instruction_Kind::Constant;
533 s99.
kind = Compiler_IR_Instruction_Kind::Store;
534 s99.local_slot_id = 0;
535 s99.operands.append(3);
538 then_block.terminator.kind = Compiler_IR_Terminator_Kind::Jump;
548 load_x.
kind = Compiler_IR_Instruction_Kind::Load;
553 join_block.terminator.kind = Compiler_IR_Terminator_Kind::Return;
563 cm1.
kind = Compiler_IR_Instruction_Kind::Constant;
569 sm1.
kind = Compiler_IR_Instruction_Kind::Store;
570 sm1.local_slot_id = 0;
571 sm1.operands.append(5);
574 else_block.terminator.kind = Compiler_IR_Terminator_Kind::Jump;
577 function.
blocks.append(entry);
603 operand.
kind = Compiler_Dataflow_Constant_Kind::Integer;
612 lhs.
kind = rhs.
kind = Compiler_Dataflow_Constant_Kind::Integer;
652 EXPECT_EQ(result.kind, Compiler_Dataflow_Constant_Kind::Unknown);
657 const auto result =
test_unary(Compiler_Operator_Kind::Minus, 42);
658 EXPECT_EQ(result.kind, Compiler_Dataflow_Constant_Kind::Integer);
669 EXPECT_EQ(result.kind, Compiler_Dataflow_Constant_Kind::Unknown);
675 EXPECT_EQ(result.kind, Compiler_Dataflow_Constant_Kind::Unknown);
681 EXPECT_EQ(result.kind, Compiler_Dataflow_Constant_Kind::Unknown);
687 EXPECT_EQ(result.kind, Compiler_Dataflow_Constant_Kind::Integer);
695 EXPECT_EQ(
r.kind, Compiler_Dataflow_Constant_Kind::Unknown);
699 EXPECT_EQ(
r.kind, Compiler_Dataflow_Constant_Kind::Unknown);
703 EXPECT_EQ(
r.kind, Compiler_Dataflow_Constant_Kind::Unknown);
728 for (
size_t i = 0; i <
optimized.function.blocks.size(); ++i)
731 if (
blk.label ==
"if.end.0")
735 for (
size_t j = 0; j <
blk.instructions.size(); ++j)
736 if (
blk.instructions.access(j).kind == Compiler_IR_Instruction_Kind::Load)
744 for (
size_t i = 0; i <
optimized.function.blocks.size(); ++i)
746 <<
"dead else block must be removed";
761 for (
size_t i = 0; i <
optimized.function.blocks.size(); ++i)
763 <<
"dead then block must be removed";
781 EXPECT_NE(
dump.find(
"UninitializedReads:"), std::string::npos);
808 Compiler_Dataflow_Constant_Kind::Integer);
840 Compiler_IR_Terminator_Kind::Jump);
844 for (
size_t i = 0; i <
optimized.function.blocks.size(); ++i)
861 Compiler_IR_Terminator_Kind::Exit);
Reusable dataflow analyses and dead-code elimination over Compiler_IR_Model.H.
size_t size_t int32_t value
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().
Compiler_Dataflow_Constant evaluate_binary(const Compiler_Operator_Kind op, const Compiler_Dataflow_Constant &lhs, const Compiler_Dataflow_Constant &rhs)
Compiler_Dataflow_Constant evaluate_unary(const Compiler_Operator_Kind op, const Compiler_Dataflow_Constant &operand)
bool parse_integer_constant(const std::string &text, long long &value) noexcept
Compiler_SSA_Block & block(Compiler_SSA_Function &function, const Compiler_SSA_Block_Id id)
Main namespace for Aleph-w library functions.
Compiler_Dataflow_Validation_Report validate_dead_code_elimination(const Compiler_Dead_Code_Elimination_Result &result, const Compiler_IR_Module *module=nullptr)
Validates the result of dead-code elimination.
Compiler_Dataflow_Function_Analysis analyze_dataflow_function(const Compiler_IR_Function &function)
Computes reachability, liveness, definite assignment, and constant propagation for one IR function.
void exit(const char *file, int line, const char *format,...)
Print a message and exit the program.
constexpr size_t compiler_ir_invalid_id() noexcept
Returns the sentinel invalid IR id.
Compiler_Dead_Code_Elimination_Result eliminate_dead_code(const Compiler_IR_Function &function)
Eliminates unreachable blocks, dead pure instructions, dead local stores, and folds constant-conditio...
Compiler_Dataflow_Validation_Report validate_dataflow_analysis(const Compiler_IR_Function &function, const Compiler_Dataflow_Function_Analysis &analysis)
Validates structural invariants of a dataflow result against its source function.
Compiler_IR_Validation_Report validate_ir_function(const Compiler_IR_Function &function, const Compiler_IR_Module *module=nullptr)
Validates one lowered IR function structurally.
std::string compiler_dump_dataflow_analysis(const Compiler_IR_Function *function, const Compiler_Dataflow_Function_Analysis &analysis, const Compiler_Type_Context *types=nullptr)
Produces a deterministic, human-readable dump of a dataflow result.
Compiler_Operator_Kind
Stable operator kinds shared by reusable compiler layers.
One propagated constant value in the local-slot lattice.
Compiler_Dataflow_Constant_Kind kind
Lattice kind.
long long integer_value
Integer payload when kind == Integer.
One basic block of IR instructions.
std::string label
Deterministic debug label.
Compiler_IR_Terminator terminator
Explicit block terminator.
DynArray< Compiler_IR_Block_Id > predecessors
Predecessor block ids.
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.
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_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.
One instruction producing an optional explicit result value.
std::string text
Constant spelling or debug payload.
bool bool_value
Decoded boolean payload for bool constants.
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.
Compiler_IR_Local_Slot_Id local_slot_id
Referenced local/parameter slot, when relevant.
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_IR_Value_Id return_value
Return value, if any.
Compiler_SSA_Block_Id id
Dense SSA block id.
std::string label
Deterministic debug label.
Compiler_SSA_Terminator terminator
Explicit block terminator.
Compiler_IR_Terminator_Kind kind
Terminator category.