55 return procedure.
entry();
75 name_ = std::move(name);
80 if (next_ !=
nullptr) {
81 next_->
prev_.remove_first_occurrence_and_reorder(*
this);
83 if (instruction !=
nullptr) {
84 instruction->
prev_.append(*
this);
91 if (params_[param_index] !=
nullptr) {
92 params_[param_index]->users_.remove_first_occurrence_and_reorder(
this);
94 if (variable !=
nullptr) {
99 variable->users_.append(
this);
101 params_[param_index] = variable;
114 if (condition_ !=
nullptr) {
115 condition_->users_.remove_first_occurrence_and_reorder(
this);
117 if (variable !=
nullptr) {
118 variable->users_.append(
this);
120 condition_ = variable;
125 if (branch_true_ !=
nullptr) {
126 branch_true_->
prev_.remove_first_occurrence_and_reorder({*
this,
true});
128 if (instruction !=
nullptr) {
129 instruction->
prev_.append({*
this,
true});
131 branch_true_ = instruction;
136 if (branch_false_ !=
nullptr) {
137 branch_false_->
prev_.remove_first_occurrence_and_reorder({*
this,
false});
139 if (instruction !=
nullptr) {
140 instruction->
prev_.append({*
this,
false});
142 branch_false_ = instruction;
147 if (variable_ !=
nullptr) {
148 variable_->users_.remove_first_occurrence_and_reorder(
this);
150 if (variable !=
nullptr) {
151 variable->users_.append(
this);
158 if (next_ !=
nullptr) {
159 next_->
prev_.remove_first_occurrence_and_reorder(*
this);
161 if (instruction !=
nullptr) {
162 instruction->
prev_.append(*
this);
169 if (next_ !=
nullptr) {
170 next_->
prev_.remove_first_occurrence_and_reorder(*
this);
172 if (instruction !=
nullptr) {
173 instruction->
prev_.append(*
this);
181 variable.name_ = std::move(name);
182 variable.data_type_ = data_type;
183 variable.index_in_graph_ = variables_.size();
184 variables_.append(&variable);
192 instruction.fn_ = &fn;
194 instruction.params_.fill(
nullptr);
195 call_instructions_.append(&instruction);
203 branch_instructions_.append(&instruction);
211 destruct_instructions_.append(&instruction);
219 dummy_instructions_.append(&instruction);
227 return_instructions_.append(&instruction);
233 params_.append({interface_type, &variable});
238 if (entry_ !=
nullptr) {
248 instruction->~CallInstruction();
251 instruction->~BranchInstruction();
254 instruction->~DestructInstruction();
257 instruction->~DummyInstruction();
260 instruction->~ReturnInstruction();
262 for (
Variable *variable : variables_) {
263 variable->~Variable();
269 if (entry_ ==
nullptr) {
272 if (!this->validate_all_instruction_pointers_set()) {
275 if (!this->validate_all_params_provided()) {
278 if (!this->validate_same_variables_in_one_call()) {
281 if (!this->validate_parameters()) {
284 if (!this->validate_initialization()) {
290bool Procedure::validate_all_instruction_pointers_set()
const
293 if (instruction->next_ ==
nullptr) {
297 for (
const DestructInstruction *instruction : destruct_instructions_) {
298 if (instruction->next_ ==
nullptr) {
302 for (
const BranchInstruction *instruction : branch_instructions_) {
303 if (instruction->branch_true_ ==
nullptr) {
306 if (instruction->branch_false_ ==
nullptr) {
310 for (
const DummyInstruction *instruction : dummy_instructions_) {
311 if (instruction->next_ ==
nullptr) {
318bool Procedure::validate_all_params_provided()
const
320 for (
const CallInstruction *instruction : call_instructions_) {
321 const MultiFunction &fn = instruction->fn();
322 for (
const int param_index : fn.param_indices()) {
323 const ParamType param_type = fn.param_type(param_index);
328 const Variable *variable = instruction->params_[param_index];
329 if (variable ==
nullptr) {
334 for (
const BranchInstruction *instruction : branch_instructions_) {
335 if (instruction->condition_ ==
nullptr) {
339 for (
const DestructInstruction *instruction : destruct_instructions_) {
340 if (instruction->variable_ ==
nullptr) {
347bool Procedure::validate_same_variables_in_one_call()
const
349 for (
const CallInstruction *instruction : call_instructions_) {
350 const MultiFunction &fn = *instruction->fn_;
351 for (
const int param_index : fn.param_indices()) {
352 const ParamType param_type = fn.param_type(param_index);
353 const Variable *variable = instruction->params_[param_index];
354 if (variable ==
nullptr) {
357 for (
const int other_param_index : fn.param_indices()) {
358 if (other_param_index == param_index) {
361 const Variable *other_variable = instruction->params_[other_param_index];
362 if (other_variable != variable) {
369 const ParamType other_param_type = fn.param_type(other_param_index);
380bool Procedure::validate_parameters()
const
383 for (
const Parameter ¶m : params_) {
392bool Procedure::validate_initialization()
const
395 for (
const DestructInstruction *instruction : destruct_instructions_) {
396 const Variable &variable = *instruction->variable_;
397 const InitState
state = this->find_initialization_state_before_instruction(*instruction,
399 if (!
state.can_be_initialized) {
403 for (
const BranchInstruction *instruction : branch_instructions_) {
404 const Variable &variable = *instruction->condition_;
405 const InitState
state = this->find_initialization_state_before_instruction(*instruction,
407 if (!
state.can_be_initialized) {
411 for (
const CallInstruction *instruction : call_instructions_) {
412 const MultiFunction &fn = *instruction->fn_;
413 for (
const int param_index : fn.param_indices()) {
414 const ParamType param_type = fn.param_type(param_index);
416 if (!instruction->params_[param_index]) {
419 const Variable &variable = *instruction->params_[param_index];
420 const InitState
state = this->find_initialization_state_before_instruction(*instruction,
422 switch (param_type.interface_type()) {
425 if (!
state.can_be_initialized) {
431 if (!
state.can_be_uninitialized) {
439 Set<const Variable *> variables_that_should_be_initialized_on_return;
440 for (
const Parameter ¶m : params_) {
442 variables_that_should_be_initialized_on_return.add_new(param.variable);
445 for (
const ReturnInstruction *instruction : return_instructions_) {
446 for (
const Variable *variable : variables_) {
447 const InitState init_state = this->find_initialization_state_before_instruction(*instruction,
449 if (variables_that_should_be_initialized_on_return.contains(variable)) {
450 if (!init_state.can_be_initialized) {
455 if (!init_state.can_be_uninitialized) {
464Procedure::InitState Procedure::find_initialization_state_before_instruction(
465 const Instruction &target_instruction,
const Variable &target_variable)
const
469 auto check_entry_instruction = [&]() {
470 bool caller_initialized_variable =
false;
471 for (
const Parameter ¶m : params_) {
472 if (param.variable == &target_variable) {
474 caller_initialized_variable =
true;
479 if (caller_initialized_variable) {
480 state.can_be_initialized =
true;
483 state.can_be_uninitialized =
true;
487 if (&target_instruction == entry_) {
488 check_entry_instruction();
491 Set<const Instruction *> checked_instructions;
492 Stack<const Instruction *> instructions_to_check;
493 for (
const InstructionCursor &cursor : target_instruction.prev_) {
494 if (cursor.instruction() !=
nullptr) {
495 instructions_to_check.push(cursor.instruction());
499 while (!instructions_to_check.is_empty()) {
500 const Instruction &instruction = *instructions_to_check.pop();
501 if (!checked_instructions.add(&instruction)) {
505 bool state_modified =
false;
506 switch (instruction.type_) {
508 const CallInstruction &call_instruction =
static_cast<const CallInstruction &
>(
510 const MultiFunction &fn = *call_instruction.fn_;
511 for (
const int param_index : fn.param_indices()) {
512 if (call_instruction.params_[param_index] == &target_variable) {
513 const ParamType param_type = fn.param_type(param_index);
515 state.can_be_initialized =
true;
516 state_modified =
true;
524 const DestructInstruction &destruct_instruction =
static_cast<const DestructInstruction &
>(
526 if (destruct_instruction.variable_ == &target_variable) {
527 state.can_be_uninitialized =
true;
528 state_modified =
true;
540 if (!state_modified) {
541 if (&instruction == entry_) {
542 check_entry_instruction();
544 for (
const InstructionCursor &cursor : instruction.prev_) {
545 if (cursor.instruction() !=
nullptr) {
546 instructions_to_check.push(cursor.instruction());
575 auto add_instructions = [&](
auto instructions) {
576 all_instructions.
extend(instructions.begin(), instructions.end());
578 add_instructions(procedure_.call_instructions_);
579 add_instructions(procedure_.branch_instructions_);
580 add_instructions(procedure_.destruct_instructions_);
581 add_instructions(procedure_.dummy_instructions_);
582 add_instructions(procedure_.return_instructions_);
586 for (
const Instruction *representative : all_instructions) {
587 if (handled_instructions.
contains(representative)) {
592 std::stringstream ss;
595 for (
const Instruction *current : block_instructions) {
596 handled_instructions.
add_new(current);
597 switch (current->type()) {
619 ss << R
"(<br align="left" />)";
624 dot_node.
set_shape(dot::Attr_shape::Rectangle);
625 dot_nodes_by_begin_.
add_new(block_instructions.
first(), &dot_node);
626 dot_nodes_by_end_.
add_new(block_instructions.
last(), &dot_node);
632 auto create_edge = [&](
dot::Node &from_node,
634 if (to_instruction ==
nullptr) {
636 to_node.
set_shape(dot::Attr_shape::Diamond);
637 return digraph_.
new_edge(from_node, to_node);
640 return digraph_.
new_edge(from_node, to_node);
643 for (
auto item : dot_nodes_by_end_.
items()) {
646 switch (from_instruction.
type()) {
650 create_edge(from_node, to_instruction);
656 create_edge(from_node, to_instruction);
662 create_edge(from_node, to_instruction);
673 create_edge(from_node, to_true_instruction).attributes.set(
"color",
"#118811");
674 create_edge(from_node, to_false_instruction).attributes.set(
"color",
"#881111");
681 create_edge(entry_node, procedure_.
entry());
686 if (instruction.
prev().size() != 1) {
689 if (
ELEM(instruction.
prev()[0].type(),
702 current = current->
prev()[0].instruction();
703 if (current == &representative) {
715 switch (instruction.
type()) {
733 if (
next ==
nullptr) {
736 if (
next == &block_begin) {
749 for (
const Instruction *current = &begin; current !=
nullptr;
752 instructions.
append(current);
759 if (variable ==
nullptr) {
763 ss <<
"$" << variable->index_in_procedure();
764 if (!variable->name().is_empty()) {
765 ss <<
"(" << variable->name() <<
")";
782 ss << R
"(<font color="grey30">)";
823 outgoing_parameters.
append(param);
826 for (
const int param_index : outgoing_parameters.
index_range()) {
829 if (param_index < outgoing_parameters.
size() - 1) {
843 std::stringstream ss;
848 incoming_parameters.
append(param);
851 for (
const int param_index : incoming_parameters.
index_range()) {
854 if (param_index < incoming_parameters.
size() - 1) {
860 node.
set_shape(dot::Attr_shape::Ellipse);
destruct_ptr< T > construct(Args &&...args)
MutableSpan< T > allocate_array(int64_t size)
const Value & lookup(const Key &key) const
void add_new(const Key &key, const Value &value)
ItemIterator items() const
bool contains(const Key &key) const
void add_new(const Key &key)
constexpr int64_t size() const
constexpr IndexRange index_range() const
void append(const T &value)
const T & last(const int64_t n=0) const
IndexRange index_range() const
void extend(Span< T > array)
DirectedEdge & new_edge(NodePort from, NodePort to)
std::string to_dot_string() const
Node & new_node(StringRef label)
void set_shape(Attr_shape shape)
void set_branch_true(Instruction *instruction)
Instruction * branch_false()
Instruction * branch_true()
void set_condition(Variable *variable)
void set_branch_false(Instruction *instruction)
Span< Variable * > params()
void set_param_variable(int param_index, Variable *variable)
const MultiFunction & fn() const
void set_params(Span< Variable * > variables)
void set_next(Instruction *instruction)
void set_variable(Variable *variable)
void set_next(Instruction *instruction)
void set_next(Instruction *instruction)
static InstructionCursor ForEntry()
void set_next(Procedure &procedure, Instruction *new_instruction) const
Instruction * next(Procedure &procedure) const
Span< InstructionCursor > prev() const
Vector< InstructionCursor > prev_
InstructionType type() const
virtual std::string debug_name() const
ParamType param_type(int param_index) const
IndexRange param_indices() const
const DataType & data_type() const
InterfaceType interface_type() const
void instruction_to_string(const DestructInstruction &instruction, std::stringstream &ss)
void variable_to_string(const Variable *variable, std::stringstream &ss)
void instruction_to_string(const BranchInstruction &instruction, std::stringstream &ss)
const Instruction & get_first_instruction_in_block(const Instruction &representative)
const Instruction * get_next_instruction_in_block(const Instruction &instruction, const Instruction &block_begin)
void instruction_to_string(const ReturnInstruction &, std::stringstream &ss)
void instruction_to_string(const CallInstruction &instruction, std::stringstream &ss)
void instruction_to_string(const DummyInstruction &, std::stringstream &ss)
ProcedureDotExport(const Procedure &procedure)
Vector< const Instruction * > get_instructions_in_block(const Instruction &representative)
void instruction_name_format(StringRef name, std::stringstream &ss)
bool has_to_be_block_begin(const Instruction &instruction)
dot::Node & create_entry_node()
BranchInstruction & new_branch_instruction()
std::string to_dot() const
CallInstruction & new_call_instruction(const MultiFunction &fn)
DestructInstruction & new_destruct_instruction()
Span< Variable * > variables()
void set_entry(Instruction &entry)
ReturnInstruction & new_return_instruction()
DummyInstruction & new_dummy_instruction()
void add_parameter(ParamType::InterfaceType interface_type, Variable &variable)
Span< ConstParameter > params() const
Variable & new_variable(DataType data_type, std::string name="")
void set_name(std::string name)
const Variable * variable