NEURON
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
105  program_symtab = node.get_symbol_table();
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
Auto generated AST classes declaration.
Base class for all block scoped nodes.
Definition: block.hpp:41
Base class for all AST node.
Definition: node.hpp:40
Represents top level AST node for whole NMODL input.
Definition: program.hpp:39
std::vector< std::shared_ptr< Symbol > > get_variables_with_properties(syminfo::NmodlType properties, bool all=false) const
get variables with properties
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)
Visitor to return Def-Use chain for a given variable in the block/node
bool node_for_def_use_analysis(const ast::Node &node) const
symtab::SymbolTable * program_symtab
void visit_program(const ast::Program &node) override
visit node of type ast::Program
bool is_solve_procedure(const ast::Node &node) const
std::vector< std::string > variables_to_optimize() const
bool ignore_verbatim
ignore verbatim blocks while localizing
#define v
Definition: md1redef.h:11
Visitor to return Def-Use chain for a given variable in the block/node
virtual std::shared_ptr< StatementBlock > get_statement_block() const
Return associated statement block for the AST node.
Definition: ast.cpp:32
@ CONSTRUCTOR_BLOCK
type of ast::ConstructorBlock
@ BREAKPOINT_BLOCK
type of ast::BreakpointBlock
@ DERIVATIVE_BLOCK
type of ast::DerivativeBlock
@ BEFORE_BLOCK
type of ast::BeforeBlock
@ DESTRUCTOR_BLOCK
type of ast::DestructorBlock
@ DISCRETE_BLOCK
type of ast::DiscreteBlock
@ NET_RECEIVE_BLOCK
type of ast::NetReceiveBlock
@ AFTER_BLOCK
type of ast::AfterBlock
@ INITIAL_BLOCK
type of ast::InitialBlock
@ NON_LINEAR_BLOCK
type of ast::NonLinearBlock
@ FOR_NETCON
type of ast::ForNetcon
@ LINEAR_BLOCK
type of ast::LinearBlock
@ BA_BLOCK
type of ast::BABlock
Visitor to transform global variable usage to local
char Symbol
Definition: nrnconf.h:25
NmodlType
NMODL variable properties.
@ CD
global or local variable is conditionally defined
@ U
global variable is used
@ D
global variable is defined
LocalVar * add_local_variable(StatementBlock &node, Identifier *varname)
encapsulates code generation backend implementations
Definition: ast_common.hpp:26
logger_type logger
Definition: logger.cpp:34
static Node * node(Object *)
Definition: netcvode.cpp:291
short type
Definition: cabvars.h:10
int find(const int, const int, const int, const int, const int)
Implement various classes to represent various Symbol properties.