Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacques Lucke <jacques@blender.org>2021-08-29 13:27:39 +0300
committerJacques Lucke <jacques@blender.org>2021-08-29 13:27:39 +0300
commit35bf6b9790fd3ca1a62216860765d9faa2f71fa1 (patch)
treeb949d94044bd9917c41fe91da5d605adfafbad04 /source/blender/functions/intern/multi_function_procedure.cc
parente5a59e876e3d7bfd4f7034e0a77571d56b11697f (diff)
move dot graph generation into utility class
Diffstat (limited to 'source/blender/functions/intern/multi_function_procedure.cc')
-rw-r--r--source/blender/functions/intern/multi_function_procedure.cc451
1 files changed, 236 insertions, 215 deletions
diff --git a/source/blender/functions/intern/multi_function_procedure.cc b/source/blender/functions/intern/multi_function_procedure.cc
index d98664712bf..1782d50371f 100644
--- a/source/blender/functions/intern/multi_function_procedure.cc
+++ b/source/blender/functions/intern/multi_function_procedure.cc
@@ -488,264 +488,285 @@ MFProcedure::InitState MFProcedure::find_initialization_state_before_instruction
return state;
}
-static bool has_to_be_block_begin(const MFProcedure &procedure, const MFInstruction &instruction)
-{
- if (procedure.entry() == &instruction) {
- return true;
- }
- if (instruction.prev().size() != 1) {
- return true;
- }
- if (instruction.prev()[0]->type() == MFInstructionType::Branch) {
- return true;
- }
- return false;
-}
-
-static const MFInstruction &get_first_instruction_in_block(const MFProcedure &procedure,
- const MFInstruction &representative)
-{
- const MFInstruction *current = &representative;
- while (!has_to_be_block_begin(procedure, *current)) {
- current = current->prev()[0];
- if (current == &representative) {
- /* There is a loop without entry or exit, just break it up here. */
- break;
- }
- }
- return *current;
-}
-
-static const MFInstruction *get_next_instruction_in_block(const MFProcedure &procedure,
- const MFInstruction &instruction,
- const MFInstruction &block_begin)
-{
- const MFInstruction *next = nullptr;
- switch (instruction.type()) {
- case MFInstructionType::Call: {
- next = static_cast<const MFCallInstruction &>(instruction).next();
- break;
- }
- case MFInstructionType::Destruct: {
- next = static_cast<const MFDestructInstruction &>(instruction).next();
- break;
- }
- case MFInstructionType::Dummy: {
- next = static_cast<const MFDummyInstruction &>(instruction).next();
- break;
- }
- case MFInstructionType::Return:
- case MFInstructionType::Branch: {
- break;
- }
- }
- if (next == nullptr) {
- return nullptr;
- }
- if (next == &block_begin) {
- return nullptr;
- }
- if (has_to_be_block_begin(procedure, *next)) {
- return nullptr;
- }
- return next;
-}
-
-static Vector<const MFInstruction *> get_instructions_in_block(const MFProcedure &procedure,
- const MFInstruction &representative)
-{
- Vector<const MFInstruction *> instructions;
- const MFInstruction &begin = get_first_instruction_in_block(procedure, representative);
- for (const MFInstruction *current = &begin; current != nullptr;
- current = get_next_instruction_in_block(procedure, *current, begin)) {
- instructions.append(current);
- }
- return instructions;
-}
-
-static void variable_to_string(const MFVariable *variable, std::stringstream &ss)
-{
- if (variable == nullptr) {
- ss << "null";
- }
- else {
- ss << "$" << variable->id();
- if (!variable->name().is_empty()) {
- ss << "(" << variable->name() << ")";
- }
- }
-}
-
-static void instruction_name_format(StringRef name, std::stringstream &ss)
-{
- ss << name;
-}
-
-static void instruction_to_string(const MFCallInstruction &instruction, std::stringstream &ss)
-{
- const MultiFunction &fn = instruction.fn();
- instruction_name_format(fn.name() + ": ", ss);
- for (const int param_index : fn.param_indices()) {
- const MFParamType param_type = fn.param_type(param_index);
- const MFVariable *variable = instruction.params()[param_index];
- ss << R"(<font color="grey30">)";
- switch (param_type.interface_type()) {
- case MFParamType::Input: {
- ss << "in";
- break;
- }
- case MFParamType::Mutable: {
- ss << "mut";
- break;
+class MFProcedureDotExport {
+ private:
+ const MFProcedure &procedure_;
+ dot::DirectedGraph digraph_;
+ Map<const MFInstruction *, dot::Node *> dot_nodes_by_begin_;
+ Map<const MFInstruction *, dot::Node *> dot_nodes_by_end_;
+
+ public:
+ MFProcedureDotExport(const MFProcedure &procedure) : procedure_(procedure)
+ {
+ }
+
+ std::string generate()
+ {
+ this->create_nodes();
+ this->create_edges();
+ return digraph_.to_dot_string();
+ }
+
+ void create_nodes()
+ {
+ Vector<const MFInstruction *> all_instructions;
+ auto add_instructions = [&](auto instructions) {
+ all_instructions.extend(instructions.begin(), instructions.end());
+ };
+ add_instructions(procedure_.call_instructions_);
+ add_instructions(procedure_.branch_instructions_);
+ add_instructions(procedure_.destruct_instructions_);
+ add_instructions(procedure_.dummy_instructions_);
+ add_instructions(procedure_.return_instructions_);
+
+ Set<const MFInstruction *> handled_instructions;
+
+ for (const MFInstruction *representative : all_instructions) {
+ if (handled_instructions.contains(representative)) {
+ continue;
}
- case MFParamType::Output: {
- ss << "out";
- break;
+ Vector<const MFInstruction *> block_instructions = this->get_instructions_in_block(
+ *representative);
+ std::stringstream ss;
+ ss << "<";
+
+ for (const MFInstruction *current : block_instructions) {
+ handled_instructions.add_new(current);
+ switch (current->type()) {
+ case MFInstructionType::Call: {
+ this->instruction_to_string(*static_cast<const MFCallInstruction *>(current), ss);
+ break;
+ }
+ case MFInstructionType::Destruct: {
+ this->instruction_to_string(*static_cast<const MFDestructInstruction *>(current), ss);
+ break;
+ }
+ case MFInstructionType::Dummy: {
+ this->instruction_to_string(*static_cast<const MFDummyInstruction *>(current), ss);
+ break;
+ }
+ case MFInstructionType::Return: {
+ this->instruction_to_string(*static_cast<const MFReturnInstruction *>(current), ss);
+ break;
+ }
+ case MFInstructionType::Branch: {
+ this->instruction_to_string(*static_cast<const MFBranchInstruction *>(current), ss);
+ break;
+ }
+ }
+ ss << R"(<br align="left" />)";
}
- }
- ss << " </font> ";
- variable_to_string(variable, ss);
- if (param_index < fn.param_amount() - 1) {
- ss << ", ";
- }
- }
-}
-
-static void instruction_to_string(const MFDestructInstruction &instruction, std::stringstream &ss)
-{
- instruction_name_format("Destruct ", ss);
- variable_to_string(instruction.variable(), ss);
-}
-
-static void instruction_to_string(const MFDummyInstruction &UNUSED(instruction),
- std::stringstream &ss)
-{
- instruction_name_format("Dummy ", ss);
-}
-
-static void instruction_to_string(const MFReturnInstruction &UNUSED(instruction),
- std::stringstream &ss)
-{
- instruction_name_format("Return ", ss);
-}
-
-static void instruction_to_string(const MFBranchInstruction &instruction, std::stringstream &ss)
-{
- instruction_name_format("Branch ", ss);
- variable_to_string(instruction.condition(), ss);
-}
-
-std::string MFProcedure::to_dot() const
-{
- Vector<const MFInstruction *> all_instructions;
- all_instructions.extend(call_instructions_.begin(), call_instructions_.end());
- all_instructions.extend(branch_instructions_.begin(), branch_instructions_.end());
- all_instructions.extend(destruct_instructions_.begin(), destruct_instructions_.end());
- all_instructions.extend(dummy_instructions_.begin(), dummy_instructions_.end());
- all_instructions.extend(return_instructions_.begin(), return_instructions_.end());
+ ss << ">";
- Set<const MFInstruction *> handled_instructions;
-
- dot::DirectedGraph digraph;
- Map<const MFInstruction *, dot::Node *> dot_nodes_by_begin;
- Map<const MFInstruction *, dot::Node *> dot_nodes_by_end;
-
- for (const MFInstruction *representative : all_instructions) {
- if (handled_instructions.contains(representative)) {
- continue;
+ dot::Node &dot_node = digraph_.new_node(ss.str());
+ dot_node.set_shape(dot::Attr_shape::Rectangle);
+ dot_nodes_by_begin_.add_new(block_instructions.first(), &dot_node);
+ dot_nodes_by_end_.add_new(block_instructions.last(), &dot_node);
}
- Vector<const MFInstruction *> block_instructions = get_instructions_in_block(*this,
- *representative);
- std::stringstream ss;
- ss << "<";
+ }
- for (const MFInstruction *current : block_instructions) {
- handled_instructions.add_new(current);
- switch (current->type()) {
+ void create_edges()
+ {
+ auto create_edge = [&](dot::Node &from_node,
+ const MFInstruction *to_instruction) -> dot::DirectedEdge & {
+ if (to_instruction == nullptr) {
+ dot::Node &to_node = digraph_.new_node("missing");
+ to_node.set_shape(dot::Attr_shape::Diamond);
+ return digraph_.new_edge(from_node, to_node);
+ }
+ dot::Node &to_node = *dot_nodes_by_begin_.lookup(to_instruction);
+ return digraph_.new_edge(from_node, to_node);
+ };
+
+ for (auto item : dot_nodes_by_end_.items()) {
+ const MFInstruction &from_instruction = *item.key;
+ dot::Node &from_node = *item.value;
+ switch (from_instruction.type()) {
case MFInstructionType::Call: {
- instruction_to_string(*static_cast<const MFCallInstruction *>(current), ss);
+ const MFInstruction *to_instruction =
+ static_cast<const MFCallInstruction &>(from_instruction).next();
+ create_edge(from_node, to_instruction);
break;
}
case MFInstructionType::Destruct: {
- instruction_to_string(*static_cast<const MFDestructInstruction *>(current), ss);
+ const MFInstruction *to_instruction =
+ static_cast<const MFDestructInstruction &>(from_instruction).next();
+ create_edge(from_node, to_instruction);
break;
}
case MFInstructionType::Dummy: {
- instruction_to_string(*static_cast<const MFDummyInstruction *>(current), ss);
+ const MFInstruction *to_instruction =
+ static_cast<const MFDummyInstruction &>(from_instruction).next();
+ create_edge(from_node, to_instruction);
break;
}
case MFInstructionType::Return: {
- instruction_to_string(*static_cast<const MFReturnInstruction *>(current), ss);
break;
}
case MFInstructionType::Branch: {
- instruction_to_string(*static_cast<const MFBranchInstruction *>(current), ss);
+ const MFBranchInstruction &branch_instruction = static_cast<const MFBranchInstruction &>(
+ from_instruction);
+ const MFInstruction *to_true_instruction = branch_instruction.branch_true();
+ const MFInstruction *to_false_instruction = branch_instruction.branch_false();
+ create_edge(from_node, to_true_instruction).attributes.set("color", "#118811");
+ create_edge(from_node, to_false_instruction).attributes.set("color", "#881111");
break;
}
}
- ss << R"(<br align="left" />)";
}
- ss << ">";
- dot::Node &dot_node = digraph.new_node(ss.str());
- dot_node.set_shape(dot::Attr_shape::Rectangle);
- dot_nodes_by_begin.add_new(block_instructions.first(), &dot_node);
- dot_nodes_by_end.add_new(block_instructions.last(), &dot_node);
+ dot::Node &entry_node = digraph_.new_node("Entry");
+ entry_node.set_shape(dot::Attr_shape::Circle);
+ create_edge(entry_node, procedure_.entry());
}
- auto create_edge = [&](dot::Node &from_node,
- const MFInstruction *to_instruction) -> dot::DirectedEdge & {
- if (to_instruction == nullptr) {
- dot::Node &to_node = digraph.new_node("missing");
- to_node.set_shape(dot::Attr_shape::Diamond);
- return digraph.new_edge(from_node, to_node);
+ bool has_to_be_block_begin(const MFInstruction &instruction)
+ {
+ if (procedure_.entry() == &instruction) {
+ return true;
}
- dot::Node &to_node = *dot_nodes_by_begin.lookup(to_instruction);
- return digraph.new_edge(from_node, to_node);
- };
+ if (instruction.prev().size() != 1) {
+ return true;
+ }
+ if (instruction.prev()[0]->type() == MFInstructionType::Branch) {
+ return true;
+ }
+ return false;
+ }
- for (auto item : dot_nodes_by_end.items()) {
- const MFInstruction &from_instruction = *item.key;
- dot::Node &from_node = *item.value;
- switch (from_instruction.type()) {
+ const MFInstruction &get_first_instruction_in_block(const MFInstruction &representative)
+ {
+ const MFInstruction *current = &representative;
+ while (!this->has_to_be_block_begin(*current)) {
+ current = current->prev()[0];
+ if (current == &representative) {
+ /* There is a loop without entry or exit, just break it up here. */
+ break;
+ }
+ }
+ return *current;
+ }
+
+ const MFInstruction *get_next_instruction_in_block(const MFInstruction &instruction,
+ const MFInstruction &block_begin)
+ {
+ const MFInstruction *next = nullptr;
+ switch (instruction.type()) {
case MFInstructionType::Call: {
- const MFInstruction *to_instruction =
- static_cast<const MFCallInstruction &>(from_instruction).next();
- create_edge(from_node, to_instruction);
+ next = static_cast<const MFCallInstruction &>(instruction).next();
break;
}
case MFInstructionType::Destruct: {
- const MFInstruction *to_instruction =
- static_cast<const MFDestructInstruction &>(from_instruction).next();
- create_edge(from_node, to_instruction);
+ next = static_cast<const MFDestructInstruction &>(instruction).next();
break;
}
case MFInstructionType::Dummy: {
- const MFInstruction *to_instruction =
- static_cast<const MFDummyInstruction &>(from_instruction).next();
- create_edge(from_node, to_instruction);
- break;
- }
- case MFInstructionType::Return: {
+ next = static_cast<const MFDummyInstruction &>(instruction).next();
break;
}
+ case MFInstructionType::Return:
case MFInstructionType::Branch: {
- const MFBranchInstruction &branch_instruction = static_cast<const MFBranchInstruction &>(
- from_instruction);
- const MFInstruction *to_true_instruction = branch_instruction.branch_true();
- const MFInstruction *to_false_instruction = branch_instruction.branch_false();
- create_edge(from_node, to_true_instruction).attributes.set("color", "#118811");
- create_edge(from_node, to_false_instruction).attributes.set("color", "#881111");
break;
}
}
+ if (next == nullptr) {
+ return nullptr;
+ }
+ if (next == &block_begin) {
+ return nullptr;
+ }
+ if (this->has_to_be_block_begin(*next)) {
+ return nullptr;
+ }
+ return next;
}
- dot::Node &entry_node = digraph.new_node("Entry");
- entry_node.set_shape(dot::Attr_shape::Circle);
- create_edge(entry_node, entry_);
+ Vector<const MFInstruction *> get_instructions_in_block(const MFInstruction &representative)
+ {
+ Vector<const MFInstruction *> instructions;
+ const MFInstruction &begin = this->get_first_instruction_in_block(representative);
+ for (const MFInstruction *current = &begin; current != nullptr;
+ current = this->get_next_instruction_in_block(*current, begin)) {
+ instructions.append(current);
+ }
+ return instructions;
+ }
- return digraph.to_dot_string();
+ void variable_to_string(const MFVariable *variable, std::stringstream &ss)
+ {
+ if (variable == nullptr) {
+ ss << "null";
+ }
+ else {
+ ss << "$" << variable->id();
+ if (!variable->name().is_empty()) {
+ ss << "(" << variable->name() << ")";
+ }
+ }
+ }
+
+ void instruction_name_format(StringRef name, std::stringstream &ss)
+ {
+ ss << name;
+ }
+
+ void instruction_to_string(const MFCallInstruction &instruction, std::stringstream &ss)
+ {
+ const MultiFunction &fn = instruction.fn();
+ this->instruction_name_format(fn.name() + ": ", ss);
+ for (const int param_index : fn.param_indices()) {
+ const MFParamType param_type = fn.param_type(param_index);
+ const MFVariable *variable = instruction.params()[param_index];
+ ss << R"(<font color="grey30">)";
+ switch (param_type.interface_type()) {
+ case MFParamType::Input: {
+ ss << "in";
+ break;
+ }
+ case MFParamType::Mutable: {
+ ss << "mut";
+ break;
+ }
+ case MFParamType::Output: {
+ ss << "out";
+ break;
+ }
+ }
+ ss << " </font> ";
+ variable_to_string(variable, ss);
+ if (param_index < fn.param_amount() - 1) {
+ ss << ", ";
+ }
+ }
+ }
+
+ void instruction_to_string(const MFDestructInstruction &instruction, std::stringstream &ss)
+ {
+ instruction_name_format("Destruct ", ss);
+ variable_to_string(instruction.variable(), ss);
+ }
+
+ void instruction_to_string(const MFDummyInstruction &UNUSED(instruction), std::stringstream &ss)
+ {
+ instruction_name_format("Dummy ", ss);
+ }
+
+ void instruction_to_string(const MFReturnInstruction &UNUSED(instruction), std::stringstream &ss)
+ {
+ instruction_name_format("Return ", ss);
+ }
+
+ void instruction_to_string(const MFBranchInstruction &instruction, std::stringstream &ss)
+ {
+ instruction_name_format("Branch ", ss);
+ variable_to_string(instruction.condition(), ss);
+ }
+};
+
+std::string MFProcedure::to_dot() const
+{
+ MFProcedureDotExport dot_export{*this};
+ return dot_export.generate();
}
} // namespace blender::fn