User Guide
localize_visitor.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2023 Blue Brain Project, EPFL.
3  * See the top-level LICENSE file for details.
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
9 
10 #include <algorithm>
11 
12 #include "ast/all.hpp"
14 #include "utils/logger.hpp"
16 
17 namespace nmodl {
18 namespace visitor {
19 
20 using symtab::Symbol;
22 
24  const auto& type = node.get_node_type();
25 
26  /**
27  * Blocks where we should compute def-use chains. We are excluding
28  * procedures and functions because we expect those to be "inlined".
29  * If procedure/function is not inlined then DefUse pass returns
30  * result as "Use". So it's safe.
31  */
32  // clang-format off
33  const std::vector<ast::AstNodeType> blocks_to_analyze = {
47  };
48  // clang-format on
49  auto it = std::find(blocks_to_analyze.begin(), blocks_to_analyze.end(), type);
50  auto node_to_analyze = !(it == blocks_to_analyze.end());
51  auto solve_procedure = is_solve_procedure(node);
52  return node_to_analyze || solve_procedure;
53 }
54 
55 /*
56  * Check if given node is a procedure block and if it is used
57  * in the solve statement.
58  */
60  if (node.is_procedure_block()) {
61  const auto& symbol = program_symtab->lookup(node.get_node_name());
62  if (symbol && symbol->has_any_property(NmodlType::to_solve)) {
63  return true;
64  }
65  }
66  return false;
67 }
68 
69 std::vector<std::string> LocalizeVisitor::variables_to_optimize() const {
70  std::vector<std::string> result;
71  // clang-format off
72  const NmodlType excluded_var_properties = NmodlType::extern_var
73  | NmodlType::extern_neuron_variable
74  | NmodlType::read_ion_var
75  | NmodlType::write_ion_var
76  | NmodlType::prime_name
77  | NmodlType::nonspecific_cur_var
78  | NmodlType::pointer_var
79  | NmodlType::bbcore_pointer_var
80  | NmodlType::electrode_cur_var
81  | NmodlType::state_var;
82 
83  const NmodlType global_var_properties = NmodlType::range_var
84  | NmodlType::assigned_definition
85  | NmodlType::param_assign;
86  // clang-format on
87 
88  /**
89  * \todo Voltage v can be global variable as well as external. In order
90  * to avoid optimizations, we need to handle this case properly
91  * \todo Instead of ast node, use symbol properties to check variable type
92  */
93  const auto& variables = program_symtab->get_variables_with_properties(global_var_properties);
94 
95  for (const auto& variable: variables) {
96  if (!variable->has_any_property(excluded_var_properties)) {
97  result.push_back(variable->get_name());
98  }
99  }
100  return result;
101 }
102 
104  /// symtab visitor pass need to be run before
106  if (program_symtab == nullptr) {
107  logger->warn("LocalizeVisitor :: symbol table is not setup, returning");
108  return;
109  }
110 
111  const auto& variables = variables_to_optimize();
112  for (const auto& varname: variables) {
113  const auto& blocks = node.get_blocks();
114  std::map<DUState, std::vector<std::shared_ptr<ast::Node>>> block_usage;
115 
116  logger->debug("LocalizeVisitor: Checking DU chains for {}", varname);
117 
118  /// compute def use chains
119  for (const auto& block: blocks) {
120  if (node_for_def_use_analysis(*block)) {
122  const auto& usages = v.analyze(*block, varname);
123  auto result = usages.eval();
124  block_usage[result].push_back(block);
125  logger->debug("\tDU chain in block {} is {}",
126  block->get_node_type_name(),
127  usages.to_string());
128  }
129  }
130 
131  /// as we are doing global analysis, if any global block is "using"
132  /// variable then we can't localize the variable
133  auto it = block_usage.find(DUState::U);
134  if (it == block_usage.end()) {
135  logger->debug("LocalizeVisitor : localized variable {}", varname);
136 
137  /// all blocks that are have either definition or conditional definition
138  /// need local variable
139  for (auto state: {DUState::D, DUState::CD}) {
140  for (auto& block: block_usage[state]) {
141  auto block_ptr = dynamic_cast<ast::Block*>(block.get());
142  const auto& statement_block = block_ptr->get_statement_block();
143  ast::LocalVar* variable{};
144  auto symbol = program_symtab->lookup(varname);
145 
146  if (symbol->is_array()) {
147  variable =
148  add_local_variable(*statement_block, varname, symbol->get_length());
149  } else {
150  variable = add_local_variable(*statement_block, varname);
151  }
152 
153  /// mark variable as localized in global symbol table
154  symbol->mark_localized();
155 
156  /// insert new symbol in the symbol table of current block
157  const auto& symtab = statement_block->get_symbol_table();
158  auto new_symbol = std::make_shared<Symbol>(varname, variable);
159  new_symbol->add_property(NmodlType::local_var);
160  new_symbol->mark_created();
161  symtab->insert(new_symbol);
162  }
163  }
164  }
165  }
166 }
167 
168 } // namespace visitor
169 } // namespace nmodl
nmodl::ast::AstNodeType::DERIVATIVE_BLOCK
@ DERIVATIVE_BLOCK
type of ast::DerivativeBlock
nmodl::ast::Node
Base class for all AST node.
Definition: node.hpp:40
localize_visitor.hpp
Visitor to transform global variable usage to local
nmodl::ast::AstNodeType::FOR_NETCON
@ FOR_NETCON
type of ast::ForNetcon
nmodl::visitor::LocalizeVisitor::variables_to_optimize
std::vector< std::string > variables_to_optimize() const
Definition: localize_visitor.cpp:69
nmodl::ast::AstNodeType::INITIAL_BLOCK
@ INITIAL_BLOCK
type of ast::InitialBlock
nmodl
encapsulates code generation backend implementations
Definition: ast_common.hpp:26
nmodl::ast::AstNodeType::CONSTRUCTOR_BLOCK
@ CONSTRUCTOR_BLOCK
type of ast::ConstructorBlock
nmodl::visitor::DUChain::eval
DUState eval() const
return "effective" usage of a variable
Definition: defuse_analyze_visitor.cpp:177
nmodl::symtab::SymbolTable::get_variables_with_properties
std::vector< std::shared_ptr< Symbol > > get_variables_with_properties(syminfo::NmodlType properties, bool all=false) const
get variables with properties
Definition: symbol_table.cpp:88
nmodl::ast::Node::get_node_type
virtual AstNodeType get_node_type() const noexcept override
Return type (ast::AstNodeType) of ast node.
Definition: node.hpp:85
nmodl::ast::Ast::is_procedure_block
virtual bool is_procedure_block() const noexcept
Check if the ast node is an instance of ast::ProcedureBlock.
Definition: ast.cpp:144
symbol_properties.hpp
Implement various classes to represent various Symbol properties.
nmodl::logger
logger_type logger
Definition: logger.cpp:34
nmodl::ast::AstNodeType::DESTRUCTOR_BLOCK
@ DESTRUCTOR_BLOCK
type of ast::DestructorBlock
nmodl::visitor::DefUseAnalyzeVisitor
Visitor to return Def-Use chain for a given variable in the block/node
Definition: defuse_analyze_visitor.hpp:214
nmodl::visitor::DUState::D
@ D
global variable is defined
nmodl::visitor::DefUseAnalyzeVisitor::analyze
DUChain analyze(const ast::Ast &node, const std::string &name)
compute def-use chain for a variable within the node
Definition: defuse_analyze_visitor.cpp:419
nmodl::visitor::DUState::U
@ U
global variable is used
nmodl::visitor::LocalizeVisitor::ignore_verbatim
bool ignore_verbatim
ignore verbatim blocks while localizing
Definition: localize_visitor.hpp:86
nmodl::ast::Block
Base class for all block scoped nodes.
Definition: block.hpp:41
nmodl::ast::AstNodeType::AFTER_BLOCK
@ AFTER_BLOCK
type of ast::AfterBlock
nmodl::visitor::LocalizeVisitor::is_solve_procedure
bool is_solve_procedure(const ast::Node &node) const
Definition: localize_visitor.cpp:59
nmodl::ast::AstNodeType::NON_LINEAR_BLOCK
@ NON_LINEAR_BLOCK
type of ast::NonLinearBlock
nmodl::visitor::LocalizeVisitor::visit_program
void visit_program(const ast::Program &node) override
visit node of type ast::Program
Definition: localize_visitor.cpp:103
nmodl::ast::LocalVar
TODO.
Definition: local_var.hpp:38
defuse_analyze_visitor.hpp
Visitor to return Def-Use chain for a given variable in the block/node
nmodl::visitor::LocalizeVisitor::node_for_def_use_analysis
bool node_for_def_use_analysis(const ast::Node &node) const
Definition: localize_visitor.cpp:23
nmodl::symtab::syminfo::NmodlType
NmodlType
NMODL variable properties.
Definition: symbol_properties.hpp:116
nmodl::ast::Program::get_blocks
const NodeVector & get_blocks() const noexcept
Getter for member variable Program::blocks.
Definition: program.hpp:216
logger.hpp
Implement logger based on spdlog library.
nmodl::visitor::add_local_variable
LocalVar * add_local_variable(StatementBlock &node, Identifier *varname)
Definition: visitor_utils.cpp:92
nmodl::ast::Program::get_symbol_table
symtab::SymbolTable * get_symbol_table() const override
Return associated symbol table for the current ast node.
Definition: program.hpp:153
nmodl::visitor::DUState::CD
@ CD
global or local variable is conditionally defined
nmodl::ast::AstNodeType::DISCRETE_BLOCK
@ DISCRETE_BLOCK
type of ast::DiscreteBlock
nmodl::ast::Ast::get_statement_block
virtual std::shared_ptr< StatementBlock > get_statement_block() const
Return associated statement block for the AST node.
Definition: ast.cpp:32
nmodl::ast::Program
Represents top level AST node for whole NMODL input.
Definition: program.hpp:39
nmodl::ast::AstNodeType::BEFORE_BLOCK
@ BEFORE_BLOCK
type of ast::BeforeBlock
nmodl::visitor::LocalizeVisitor::program_symtab
symtab::SymbolTable * program_symtab
Definition: localize_visitor.hpp:88
nmodl::symtab::SymbolTable::lookup
std::shared_ptr< Symbol > lookup(const std::string &name) const
check if symbol with given name exist in the current table (but not in parents)
Definition: symbol_table.hpp:199
nmodl::ast::AstNodeType::BREAKPOINT_BLOCK
@ BREAKPOINT_BLOCK
type of ast::BreakpointBlock
nmodl::ast::AstNodeType::BA_BLOCK
@ BA_BLOCK
type of ast::BABlock
nmodl::ast::AstNodeType::NET_RECEIVE_BLOCK
@ NET_RECEIVE_BLOCK
type of ast::NetReceiveBlock
nmodl::ast::Ast::get_node_name
virtual std::string get_node_name() const
Return name of of the node.
Definition: ast.cpp:28
all.hpp
Auto generated AST classes declaration.
nmodl::ast::AstNodeType::LINEAR_BLOCK
@ LINEAR_BLOCK
type of ast::LinearBlock