34 case Type::Destruct: {
51 return procedure.
entry();
71 name_ = std::move(
name);
76 if (next_ !=
nullptr) {
77 next_->
prev_.remove_first_occurrence_and_reorder(*
this);
79 if (instruction !=
nullptr) {
80 instruction->
prev_.append(*
this);
87 if (params_[param_index] !=
nullptr) {
88 params_[param_index]->users_.remove_first_occurrence_and_reorder(
this);
90 if (variable !=
nullptr) {
92 variable->users_.append(
this);
94 params_[param_index] = variable;
107 if (condition_ !=
nullptr) {
108 condition_->users_.remove_first_occurrence_and_reorder(
this);
110 if (variable !=
nullptr) {
111 variable->users_.append(
this);
113 condition_ = variable;
118 if (branch_true_ !=
nullptr) {
119 branch_true_->
prev_.remove_first_occurrence_and_reorder({*
this,
true});
121 if (instruction !=
nullptr) {
122 instruction->
prev_.append({*
this,
true});
124 branch_true_ = instruction;
129 if (branch_false_ !=
nullptr) {
130 branch_false_->
prev_.remove_first_occurrence_and_reorder({*
this,
false});
132 if (instruction !=
nullptr) {
133 instruction->
prev_.append({*
this,
false});
135 branch_false_ = instruction;
140 if (variable_ !=
nullptr) {
141 variable_->users_.remove_first_occurrence_and_reorder(
this);
151 if (next_ !=
nullptr) {
152 next_->
prev_.remove_first_occurrence_and_reorder(*
this);
154 if (instruction !=
nullptr) {
155 instruction->
prev_.append(*
this);
162 if (next_ !=
nullptr) {
163 next_->
prev_.remove_first_occurrence_and_reorder(*
this);
165 if (instruction !=
nullptr) {
166 instruction->
prev_.append(*
this);
174 variable.name_ = std::move(name);
175 variable.data_type_ = data_type;
176 variable.index_in_graph_ = variables_.size();
177 variables_.append(&variable);
185 instruction.fn_ = &fn;
187 instruction.params_.fill(
nullptr);
188 call_instructions_.append(&instruction);
196 branch_instructions_.append(&instruction);
204 destruct_instructions_.append(&instruction);
212 dummy_instructions_.append(&instruction);
220 return_instructions_.append(&instruction);
226 params_.append({interface_type, &variable});
231 if (entry_ !=
nullptr) {
241 instruction->~MFCallInstruction();
244 instruction->~MFBranchInstruction();
247 instruction->~MFDestructInstruction();
250 instruction->~MFDummyInstruction();
253 instruction->~MFReturnInstruction();
256 variable->~MFVariable();
262 if (entry_ ==
nullptr) {
265 if (!this->validate_all_instruction_pointers_set()) {
268 if (!this->validate_all_params_provided()) {
271 if (!this->validate_same_variables_in_one_call()) {
274 if (!this->validate_parameters()) {
277 if (!this->validate_initialization()) {
283 bool MFProcedure::validate_all_instruction_pointers_set()
const
286 if (instruction->next_ ==
nullptr) {
291 if (instruction->next_ ==
nullptr) {
296 if (instruction->branch_true_ ==
nullptr) {
299 if (instruction->branch_false_ ==
nullptr) {
303 for (
const MFDummyInstruction *instruction : dummy_instructions_) {
304 if (instruction->next_ ==
nullptr) {
311 bool MFProcedure::validate_all_params_provided()
const
314 const MultiFunction &fn = instruction->fn();
315 for (
const int param_index : fn.param_indices()) {
316 const MFParamType param_type = fn.param_type(param_index);
321 const MFVariable *variable = instruction->params_[param_index];
322 if (variable ==
nullptr) {
328 if (instruction->condition_ ==
nullptr) {
333 if (instruction->variable_ ==
nullptr) {
340 bool MFProcedure::validate_same_variables_in_one_call()
const
343 const MultiFunction &fn = *instruction->fn_;
344 for (
const int param_index : fn.param_indices()) {
345 const MFParamType param_type = fn.param_type(param_index);
346 const MFVariable *variable = instruction->params_[param_index];
347 if (variable ==
nullptr) {
350 for (
const int other_param_index : fn.param_indices()) {
351 if (other_param_index == param_index) {
354 const MFVariable *other_variable = instruction->params_[other_param_index];
355 if (other_variable != variable) {
362 const MFParamType other_param_type = fn.param_type(other_param_index);
373 bool MFProcedure::validate_parameters()
const
376 for (
const MFParameter ¶m : params_) {
385 bool MFProcedure::validate_initialization()
const
389 const MFVariable &variable = *instruction->variable_;
390 const InitState
state = this->find_initialization_state_before_instruction(*instruction,
392 if (!
state.can_be_initialized) {
397 const MFVariable &variable = *instruction->condition_;
398 const InitState
state = this->find_initialization_state_before_instruction(*instruction,
400 if (!
state.can_be_initialized) {
405 const MultiFunction &fn = *instruction->fn_;
406 for (
const int param_index : fn.param_indices()) {
407 const MFParamType param_type = fn.param_type(param_index);
409 if (!instruction->params_[param_index]) {
412 const MFVariable &variable = *instruction->params_[param_index];
413 const InitState
state = this->find_initialization_state_before_instruction(*instruction,
415 switch (param_type.interface_type()) {
418 if (!
state.can_be_initialized) {
424 if (!
state.can_be_uninitialized) {
432 Set<const MFVariable *> variables_that_should_be_initialized_on_return;
433 for (
const MFParameter ¶m : params_) {
435 variables_that_should_be_initialized_on_return.add_new(param.variable);
438 for (
const MFReturnInstruction *instruction : return_instructions_) {
439 for (
const MFVariable *variable : variables_) {
440 const InitState init_state = this->find_initialization_state_before_instruction(*instruction,
442 if (variables_that_should_be_initialized_on_return.contains(variable)) {
443 if (!init_state.can_be_initialized) {
448 if (!init_state.can_be_uninitialized) {
457 MFProcedure::InitState MFProcedure::find_initialization_state_before_instruction(
462 auto check_entry_instruction = [&]() {
463 bool caller_initialized_variable =
false;
464 for (
const MFParameter ¶m : params_) {
465 if (param.variable == &target_variable) {
467 caller_initialized_variable =
true;
472 if (caller_initialized_variable) {
473 state.can_be_initialized =
true;
476 state.can_be_uninitialized =
true;
480 if (&target_instruction == entry_) {
481 check_entry_instruction();
484 Set<const MFInstruction *> checked_instructions;
485 Stack<const MFInstruction *> instructions_to_check;
486 for (
const MFInstructionCursor &cursor : target_instruction.prev_) {
487 if (cursor.instruction() !=
nullptr) {
488 instructions_to_check.push(cursor.instruction());
492 while (!instructions_to_check.is_empty()) {
493 const MFInstruction &instruction = *instructions_to_check.pop();
494 if (!checked_instructions.add(&instruction)) {
498 bool state_modified =
false;
499 switch (instruction.type_) {
503 const MultiFunction &fn = *call_instruction.fn_;
504 for (
const int param_index : fn.param_indices()) {
505 if (call_instruction.params_[param_index] == &target_variable) {
506 const MFParamType param_type = fn.
param_type(param_index);
508 state.can_be_initialized =
true;
509 state_modified =
true;
519 if (destruct_instruction.variable_ == &target_variable) {
520 state.can_be_uninitialized =
true;
521 state_modified =
true;
533 if (!state_modified) {
534 if (&instruction == entry_) {
535 check_entry_instruction();
537 for (
const MFInstructionCursor &cursor : instruction.prev_) {
538 if (cursor.instruction() !=
nullptr) {
539 instructions_to_check.push(cursor.instruction());
570 auto add_instructions = [&](
auto instructions) {
571 all_instructions.
extend(instructions.begin(), instructions.end());
573 add_instructions(procedure_.call_instructions_);
574 add_instructions(procedure_.branch_instructions_);
575 add_instructions(procedure_.destruct_instructions_);
576 add_instructions(procedure_.dummy_instructions_);
577 add_instructions(procedure_.return_instructions_);
581 for (
const MFInstruction *representative : all_instructions) {
582 if (handled_instructions.
contains(representative)) {
587 std::stringstream ss;
591 handled_instructions.
add_new(current);
592 switch (current->type()) {
614 ss << R
"(<br align="left" />)";
619 dot_node.
set_shape(dot::Attr_shape::Rectangle);
620 dot_nodes_by_begin_.
add_new(block_instructions.
first(), &dot_node);
621 dot_nodes_by_end_.
add_new(block_instructions.
last(), &dot_node);
627 auto create_edge = [&](
dot::Node &from_node,
629 if (to_instruction ==
nullptr) {
631 to_node.
set_shape(dot::Attr_shape::Diamond);
632 return digraph_.
new_edge(from_node, to_node);
635 return digraph_.
new_edge(from_node, to_node);
638 for (
auto item : dot_nodes_by_end_.
items()) {
641 switch (from_instruction.
type()) {
645 create_edge(from_node, to_instruction);
651 create_edge(from_node, to_instruction);
657 create_edge(from_node, to_instruction);
668 create_edge(from_node, to_true_instruction).attributes.set(
"color",
"#118811");
669 create_edge(from_node, to_false_instruction).attributes.set(
"color",
"#881111");
676 create_edge(entry_node, procedure_.
entry());
681 if (instruction.
prev().size() != 1) {
684 if (
ELEM(instruction.
prev()[0].type(),
685 MFInstructionCursor::Type::Branch,
696 current = current->
prev()[0].instruction();
697 if (current == &representative) {
709 switch (instruction.
type()) {
727 if (
next ==
nullptr) {
730 if (
next == &block_begin) {
743 for (
const MFInstruction *current = &begin; current !=
nullptr;
745 instructions.
append(current);
752 if (variable ==
nullptr) {
758 ss <<
"(" << variable->
name() <<
")";
775 ss << R
"(<font color="grey30">)";
816 outgoing_parameters.
append(param);
819 for (
const int param_index : outgoing_parameters.
index_range()) {
822 if (param_index < outgoing_parameters.
size() - 1) {
836 std::stringstream ss;
841 incoming_parameters.
append(param);
844 for (
const int param_index : incoming_parameters.
index_range()) {
847 if (param_index < incoming_parameters.
size() - 1) {
853 node.set_shape(dot::Attr_shape::Ellipse);
MutableSpan< T > allocate_array(int64_t size)
destruct_ptr< T > construct(Args &&...args)
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
constexpr bool is_empty() 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(MFInstruction *instruction)
MFInstruction * branch_true()
MFInstruction * branch_false()
void set_condition(MFVariable *variable)
void set_branch_false(MFInstruction *instruction)
void set_next(MFInstruction *instruction)
void set_param_variable(int param_index, MFVariable *variable)
const MultiFunction & fn() const
void set_params(Span< MFVariable * > variables)
Span< MFVariable * > params()
void set_variable(MFVariable *variable)
void set_next(MFInstruction *instruction)
void set_next(MFInstruction *instruction)
MFInstruction * next(MFProcedure &procedure) const
void set_next(MFProcedure &procedure, MFInstruction *new_instruction) const
static MFInstructionCursor ForEntry()
Vector< MFInstructionCursor > prev_
MFInstructionType type() const
Span< MFInstructionCursor > prev() const
MFDataType data_type() const
InterfaceType interface_type() const
void instruction_to_string(const MFDummyInstruction &UNUSED(instruction), std::stringstream &ss)
void instruction_to_string(const MFReturnInstruction &UNUSED(instruction), std::stringstream &ss)
const MFInstruction * get_next_instruction_in_block(const MFInstruction &instruction, const MFInstruction &block_begin)
Vector< const MFInstruction * > get_instructions_in_block(const MFInstruction &representative)
void instruction_to_string(const MFBranchInstruction &instruction, std::stringstream &ss)
dot::Node & create_entry_node()
void variable_to_string(const MFVariable *variable, std::stringstream &ss)
bool has_to_be_block_begin(const MFInstruction &instruction)
MFProcedureDotExport(const MFProcedure &procedure)
const MFInstruction & get_first_instruction_in_block(const MFInstruction &representative)
void instruction_to_string(const MFCallInstruction &instruction, std::stringstream &ss)
void instruction_to_string(const MFDestructInstruction &instruction, std::stringstream &ss)
void instruction_name_format(StringRef name, std::stringstream &ss)
MFBranchInstruction & new_branch_instruction()
void add_parameter(MFParamType::InterfaceType interface_type, MFVariable &variable)
MFDummyInstruction & new_dummy_instruction()
Span< MFVariable * > variables()
void set_entry(MFInstruction &entry)
MFReturnInstruction & new_return_instruction()
MFCallInstruction & new_call_instruction(const MultiFunction &fn)
std::string to_dot() const
MFDestructInstruction & new_destruct_instruction()
MFVariable & new_variable(MFDataType data_type, std::string name="")
Span< ConstMFParameter > params() const
StringRefNull name() const
MFDataType data_type() const
void set_name(std::string name)
int index_in_procedure() const
MFParamType param_type(int param_index) const
virtual std::string debug_name() const
IndexRange param_indices() const
fn::MFInstruction MFInstruction
fn::MFDestructInstruction MFDestructInstruction
fn::MFBranchInstruction MFBranchInstruction
fn::MFCallInstruction MFCallInstruction
fn::MFVariable MFVariable
const MFVariable * variable