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-22 23:34:25 +0300
committerJacques Lucke <jacques@blender.org>2021-08-22 23:34:25 +0300
commiteed93aaa07a95ba2fd5c8fdf947e4b430eed4c02 (patch)
treea3e789f3bd3c673ef1c04b57fb4d80aaced0db1d
parentfc0bb6cdee233ed5c544a33a87734af7deeab5c9 (diff)
make dot output more compacttemp-multi-function-procedure
-rw-r--r--source/blender/functions/FN_multi_function_procedure.hh6
-rw-r--r--source/blender/functions/intern/multi_function_procedure.cc316
2 files changed, 232 insertions, 90 deletions
diff --git a/source/blender/functions/FN_multi_function_procedure.hh b/source/blender/functions/FN_multi_function_procedure.hh
index aacc3f9331f..07aa84e0f94 100644
--- a/source/blender/functions/FN_multi_function_procedure.hh
+++ b/source/blender/functions/FN_multi_function_procedure.hh
@@ -78,6 +78,7 @@ class MFInstruction : NonCopyable, NonMovable {
public:
MFInstructionType type() const;
Span<MFInstruction *> prev();
+ Span<const MFInstruction *> prev() const;
};
class MFCallInstruction : public MFInstruction {
@@ -268,6 +269,11 @@ inline Span<MFInstruction *> MFInstruction::prev()
return prev_;
}
+inline Span<const MFInstruction *> MFInstruction::prev() const
+{
+ return prev_;
+}
+
/* --------------------------------------------------------------------
* MFCallInstruction inline methods.
*/
diff --git a/source/blender/functions/intern/multi_function_procedure.cc b/source/blender/functions/intern/multi_function_procedure.cc
index 28c42b5a4e2..4eb7403ea09 100644
--- a/source/blender/functions/intern/multi_function_procedure.cc
+++ b/source/blender/functions/intern/multi_function_procedure.cc
@@ -222,16 +222,6 @@ MFProcedure::~MFProcedure()
}
}
-static std::string optional_variable_to_string(const MFVariable *variable)
-{
- if (variable == nullptr) {
- return "<null>";
- }
- std::stringstream ss;
- ss << variable->name() << "$" << variable->id();
- return ss.str();
-}
-
bool MFProcedure::validate() const
{
if (entry_ == nullptr) {
@@ -498,108 +488,254 @@ 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 << "<none>";
+ }
+ else {
+ ss << "$" << variable->id();
+ if (!variable->name().is_empty()) {
+ ss << "(" << variable->name() << ")";
+ }
+ }
+}
+
+static void instruction_to_string(const MFCallInstruction &instruction, std::stringstream &ss)
+{
+ const MultiFunction &fn = instruction.fn();
+ ss << fn.name() << " - ";
+ for (const int param_index : fn.param_indices()) {
+ const MFParamType param_type = fn.param_type(param_index);
+ const MFVariable *variable = instruction.params()[param_index];
+ switch (param_type.interface_type()) {
+ case MFParamType::Input: {
+ ss << "in";
+ break;
+ }
+ case MFParamType::Mutable: {
+ ss << "mut";
+ break;
+ }
+ case MFParamType::Output: {
+ ss << "out";
+ break;
+ }
+ }
+ ss << " ";
+ variable_to_string(variable, ss);
+ if (param_index < fn.param_amount() - 1) {
+ ss << ", ";
+ }
+ }
+}
+
+static void instruction_to_string(const MFDestructInstruction &instruction, std::stringstream &ss)
+{
+ ss << "Destruct ";
+ variable_to_string(instruction.variable(), ss);
+}
+
+static void instruction_to_string(const MFDummyInstruction &UNUSED(instruction),
+ std::stringstream &ss)
+{
+ ss << "Dummy";
+}
+
+static void instruction_to_string(const MFReturnInstruction &UNUSED(instruction),
+ std::stringstream &ss)
+{
+ ss << "Return";
+}
+
+static void instruction_to_string(const MFBranchInstruction &instruction, std::stringstream &ss)
+{
+ ss << "Branch on ";
+ 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());
+
+ Set<const MFInstruction *> handled_instructions;
+
dot::DirectedGraph digraph;
- Map<MFInstruction *, dot::Node *> dot_nodes;
+ Map<const MFInstruction *, dot::Node *> dot_nodes_by_begin;
+ Map<const MFInstruction *, dot::Node *> dot_nodes_by_end;
- for (MFCallInstruction *instruction : call_instructions_) {
+ for (const MFInstruction *representative : all_instructions) {
+ if (handled_instructions.contains(representative)) {
+ continue;
+ }
+ Vector<const MFInstruction *> block_instructions = get_instructions_in_block(*this,
+ *representative);
std::stringstream ss;
- const MultiFunction &fn = instruction->fn();
- ss << fn.name();
- ss << "(";
- for (const int param_index : fn.param_indices()) {
- MFParamType param_type = fn.param_type(param_index);
- switch (param_type.interface_type()) {
- case MFParamType::Input: {
- ss << "in: ";
+
+ for (const MFInstruction *current : block_instructions) {
+ handled_instructions.add_new(current);
+ switch (current->type()) {
+ case MFInstructionType::Call: {
+ instruction_to_string(*static_cast<const MFCallInstruction *>(current), ss);
break;
}
- case MFParamType::Output: {
- ss << "out: ";
+ case MFInstructionType::Destruct: {
+ instruction_to_string(*static_cast<const MFDestructInstruction *>(current), ss);
break;
}
- case MFParamType::Mutable: {
- ss << "mut: ";
+ case MFInstructionType::Dummy: {
+ instruction_to_string(*static_cast<const MFDummyInstruction *>(current), ss);
+ 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);
break;
}
}
- MFVariable *variable = instruction->params()[param_index];
- ss << optional_variable_to_string(variable);
- if (param_index < fn.param_amount() - 1) {
- ss << ", ";
- }
+ ss << "\\l";
}
- ss << ")";
- dot::Node &dot_node = digraph.new_node(ss.str());
- dot_node.set_shape(dot::Attr_shape::Rectangle);
- dot_nodes.add_new(instruction, &dot_node);
- }
- for (MFBranchInstruction *instruction : branch_instructions_) {
- MFVariable *variable = instruction->condition();
- std::stringstream ss;
- ss << "Branch: " << optional_variable_to_string(variable);
- dot::Node &dot_node = digraph.new_node(ss.str());
- dot_node.set_shape(dot::Attr_shape::Rectangle);
- dot_nodes.add_new(instruction, &dot_node);
- }
- for (MFDestructInstruction *instruction : destruct_instructions_) {
- MFVariable *variable = instruction->variable();
- std::stringstream ss;
- ss << "Destruct: " << optional_variable_to_string(variable);
+
dot::Node &dot_node = digraph.new_node(ss.str());
dot_node.set_shape(dot::Attr_shape::Rectangle);
- dot_nodes.add_new(instruction, &dot_node);
- }
- for (MFDummyInstruction *instruction : dummy_instructions_) {
- dot::Node &dot_node = digraph.new_node("Dummy");
- dot_node.set_shape(dot::Attr_shape::Rectangle);
- dot_nodes.add_new(instruction, &dot_node);
- }
- for (MFReturnInstruction *instruction : return_instructions_) {
- dot::Node &dot_node = digraph.new_node("");
- dot_node.set_shape(dot::Attr_shape::Circle);
- dot_nodes.add_new(instruction, &dot_node);
+ dot_nodes_by_begin.add_new(block_instructions.first(), &dot_node);
+ dot_nodes_by_end.add_new(block_instructions.last(), &dot_node);
}
- auto create_missing_end_node = [&]() -> dot::Node & {
- dot::Node &node = digraph.new_node("");
- node.set_shape(dot::Attr_shape::Diamond);
- node.set_background_color("red");
- return node;
- };
-
- auto add_edge_to_instruction_or_end = [&](dot::Node &dot_from, MFInstruction *to) {
- if (to == nullptr) {
- dot::Node &dot_end_node = create_missing_end_node();
- digraph.new_edge(dot_from, dot_end_node);
- }
- else {
- dot::Node &dot_to = *dot_nodes.lookup(to);
- digraph.new_edge(dot_from, dot_to);
+ 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 (MFCallInstruction *instruction : call_instructions_) {
- dot::Node &dot_node = *dot_nodes.lookup(instruction);
- add_edge_to_instruction_or_end(dot_node, instruction->next());
- }
- for (MFBranchInstruction *instruction : branch_instructions_) {
- dot::Node &dot_node = *dot_nodes.lookup(instruction);
- add_edge_to_instruction_or_end(dot_node, instruction->branch_true());
- add_edge_to_instruction_or_end(dot_node, instruction->branch_false());
- }
- for (MFDestructInstruction *instruction : destruct_instructions_) {
- dot::Node &dot_node = *dot_nodes.lookup(instruction);
- add_edge_to_instruction_or_end(dot_node, instruction->next());
- }
- for (MFDummyInstruction *instruction : dummy_instructions_) {
- dot::Node &dot_node = *dot_nodes.lookup(instruction);
- add_edge_to_instruction_or_end(dot_node, instruction->next());
+ 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: {
+ const MFInstruction *to_instruction =
+ static_cast<const MFCallInstruction &>(from_instruction).next();
+ create_edge(from_node, to_instruction);
+ break;
+ }
+ case MFInstructionType::Destruct: {
+ const MFInstruction *to_instruction =
+ static_cast<const MFDestructInstruction &>(from_instruction).next();
+ create_edge(from_node, to_instruction);
+ 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: {
+ break;
+ }
+ 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;
+ }
+ }
}
- dot::Node &dot_entry = digraph.new_node("Entry");
- add_edge_to_instruction_or_end(dot_entry, entry_);
+ dot::Node &entry_node = digraph.new_node("Entry");
+ entry_node.set_shape(dot::Attr_shape::Circle);
+ create_edge(entry_node, entry_);
return digraph.to_dot_string();
}