systemc-clang 2.0.0
Parsing SystemC constructs
Loading...
Searching...
No Matches
function_info_pass.py
Go to the documentation of this file.
1"""collect function declaration information and invocation information in processes"""
2from lark import Token
3
4from parselib.transforms import TopDown
5from ..utils import dprint, is_tree_type, is_tree_types
6from ..grammar import UnexpectedHCodeStructureError
7from .name_stub import ProcessVarNameStub
8from warnings import warn
9from pprint import pprint
10from copy import deepcopy
11
12
14 """
15 This pass tags inout IDs assigned within the function parameters and marks the position of the inout params.
16 These information is useful for the next pass which translates the functions and their invocations
17 """
18 def __init__(self):
19 super().__init__()
20 self.__current_module = None
21 self.__local_output_ids = set()
22 self.__in_function = False
23 self.function_nodes = dict() # record the function nodes per modules
27
28 @property
32 @current_module_function_nodes.setter
34 self.function_nodes[self.__current_module] = val
35
36 @property
38 return self.__current_process__current_process.function_invocations
39
40 @current_process_function_invocations.setter
42 self.__current_process__current_process.function_invocations = val
43
44 @property
48 @property
50 return self.__current_function__current_function.function_invocations
51
52 @property
55 return self.__current_function__current_function.function_invocations
57 return self.__current_process__current_process.function_invocations
59 return self.__current_thread__current_thread.function_invocations
60 else:
61 raise ValueError('Current scope is not set')
62
63 @current_function_assignments.setter
65 self.__current_function__current_function.assignments = val
66
67 def hprocess(self, tree):
69 tree.function_invocations = []
71 self.__push_up(tree)
73 return tree
74
75 def hthreadswitch(self, tree):
76 # NOTE: this is only used for generated functions
78 tree.function_invocations = []
79 self.__push_up(tree)
81 return tree
82
91 def hfunctionparams(self, tree):
92 tree.io_params = []
93 tree.func_param_var_name = []
94 for idx, param in enumerate(tree.children):
95 var_name = param.children[0]
96 if param.data == 'funcparamio': # filter io params
97 self.__local_output_ids.add(var_name)
98 tree.io_params.append((idx, var_name))
99 tree.func_param_var_name.append(var_name)
100 return tree
101
102 def hfunctionlocalvars(self, tree):
103 tree.local_var_name = []
104 for var_decl in tree.children:
105 tree.local_var_name.append(var_decl.children[0])
106 return tree
107
108 def hfunctionbody(self, tree):
109 self.__push_back(tree)
110 return tree
111
112 def hvarref(self, tree):
113 if hasattr(tree, 'func_repl_id'):
114 if tree.children[0] in self.__local_output_ids:
115 # variable references where they should be changed to a different name
116 # dprint(tree)
117 pass
118 else:
119 # remove repl_id tags for local variables
120 delattr(tree, 'func_repl_id')
121 return tree
122
123 def harrayref(self, tree):
124 # we only expands the first parameter
125 array_ref = tree.children[0]
126 if self.__in_function and hasattr(tree, 'push_down'):
127 array_ref.func_repl_id = True
128 delattr(tree, 'push_down')
129 self.__push_up(tree)
130 return tree
131
132 def hslice(self, tree):
133 array_ref = tree.children[0]
134 if self.__in_function:
135 array_ref.func_repl_id = True
136 self.__push_up(tree)
137 return tree
138
139 def blkassign(self, tree):
140 """
141 func_repl_id being true means that this ID should be replaced by another name,
142 because the ID crosses the boundary of parameters and need special handlings for
143 blocking/non-blocking assignments
144 """
145 lhs = tree.children[0]
146 if lhs.data == 'hvarref' and self.__in_function:
147 lhs.func_repl_id = True
148 elif lhs.data == 'harrayref' and self.__in_function:
149 lhs.push_down = True
150 self.__push_up(tree)
151 if self.__in_function:
153 return tree
154
155 def hfunction(self, tree):
156 self.__in_function = True
158 tree.function_invocations = []
160 self.__push_up(tree)
161 self.__in_function = False
162 func_name = tree.children[0]
163 ret_type = None
164 func_params = None
165 local_vars = None
166 func_body = None
167 for child in tree.children[1:]:
168 if child.data == 'hfunctionparams':
169 func_params = child
170 elif child.data == 'hfunctionrettype':
171 ret_type = child
172 elif child.data == 'hfunctionlocalvars':
173 local_vars = child
174 elif child.data == 'hfunctionbody':
175 func_body = child
178 return tree
179
180 def hmethodcall(self, tree):
181 self.__push_up(tree)
182 self.current_scope_function_invocations.append(tree)
183 return tree
184
185
187 """Similar to FunctionInfoPass, but this pass collects invocation information"""
188 def __init__(self):
189 super().__init__()
195
196 def __extract_func_def(self, tree):
197 func_name = tree.children[0]
198 ret_type = None
199 func_params = None
200 local_vars = None
201 func_body = None
202 for child in tree.children[1:]:
203 if child.data == 'hfunctionparams':
204 func_params = child
205 elif child.data == 'hfunctionrettype':
206 ret_type = child
207 elif child.data == 'hfunctionlocalvars':
208 local_vars = child
209 elif child.data == 'hfunctionbody':
210 func_body = child
211 return func_name, ret_type, func_params, local_vars, func_body
212
213 @property
215 return self.__current_module.function_nodes
216
217 def __search_current_function(self, func_name):
219 if f.children[0] == func_name:
220 return f
221 # try fuzzy search
223 # dprint(f.children[0][:-1] == func_name[:-1])
224 if f.children[0][:-1] == func_name[:-1]:
225 return f
226 raise ValueError(f'Function {func_name} not found')
227
228 def push_scope(self):
229 self.__scope_stack.append(dict())
230
231 def search_id_def(self, id, allow_failure=False):
232 for stk in reversed(self.__scope_stack):
233 if id in stk:
234 return stk[id]
235 if not allow_failure:
236 raise ValueError(f'ID {id} not found in current scope')
237 return None
238
239 def copy_and_strip_io(self, tp):
240 tpe = deepcopy(tp)
241 return tpe
242
243 def add_id_type(self, id, tpe):
244 if id in self.__scope_stack[-1]:
245 raise ValueError('Redefinition of variable')
246 self.__scope_stack[-1][id] = self.copy_and_strip_io(tpe)
247
248 def portdecltype(self, tree):
249 self.add_id_type(tree.children[0].children[0], tree.children[1])
250 return tree
251
252 def sigdecltype(self, tree):
253 self.add_id_type(tree.children[0].children[0], tree.children[1])
254 return tree
255
256 def vardeclinit(self, tree):
257 # dprint(self.__current_function.children[0] if self.__current_function else None)
258 # dprint(self.__current_process.children[0] if self.__current_process else None)
259 # dprint(self.__current_module.children[0] if self.__current_module else None)
260 self.add_id_type(tree.children[0], tree.children[1])
261 return tree
262
263 def funcparamio(self, tree):
264 self.add_id_type(tree.children[0], tree.children[1])
265 return tree
266
267 def funcparami(self, tree):
268 self.add_id_type(tree.children[0], tree.children[1])
269 return tree
270
271 def pop_scope(self):
272 self.__scope_stack.pop(-1)
273
274 def hmodule(self, tree):
275 self.__current_module = tree
276 self.push_scope()
277 self.__push_up(tree)
278 self.pop_scope()
279 self.__current_module = None
280 return tree
281
282 @property
284 return '__phantom_var_{}'.format(self.__phantom_id)
285
286 def new_phantom_var_name(self, tpe):
287 while self.search_id_def(self.current_phantom_namecurrent_phantom_name, True) is not None:
288 self.__phantom_id += 1
290 self.add_id_type(phantom_var, tpe)
291 return phantom_var
292
293 def __extract_name_from_method_args(self, arg_node, arg_tpe):
294 if is_tree_type(arg_node, 'hvarref'):
295 return arg_node.children[0]
296 elif is_tree_types(arg_node, ['hliteral', 'hbinop', 'hmethodcall', 'syscread', 'hunop', 'hslice']):
297 warn('Complex expression or constant used for in/out argument, '
298 'this will cause phantom argument to be created and the output result will be discarded. '
299 'Consider using non-reference or const-reference instead')
300 phantom_var = self.new_phantom_var_name(arg_tpe)
301 arg_node.phantom_var = phantom_var
302 return phantom_var
303 elif isinstance(arg_node, str): # strings can be treated as an ID
304 return arg_node
305 raise ValueError('Unsupported form of function argument')
306
307 def augment_name_stub(self, tree):
308 tree.name_stub = dict()
309 tree.phantom_vars = dict()
310 names_to_stub = set()
311 for invoc in tree.function_invocations:
312 invoc_params = invoc.children[1:]
313 f_name = invoc.children[0]
314 func_node = self.__search_current_function(f_name)
315 func_name, ret_type, func_params, local_vars, func_body = self.__extract_func_def(func_node)
316 if func_params is not None:
317 for idx, param in func_params.io_params:
318 arg_node = invoc_params[idx]
319 tpe = func_params.children[idx].children[1]
320 name = self.__extract_name_from_method_args(arg_node, tpe)
321 if hasattr(arg_node, 'phantom_var'):
322 tree.phantom_vars[name] = tpe
323 names_to_stub.add(name)
324 # dprint(tree.phantom_vars)
325 # actually, we can finalized the name of the stub here
326 for nm in names_to_stub:
327 stub = ProcessVarNameStub(nm, self.search_id_def(nm))
328 stub.insert_name(lambda x: self.search_id_def(x, True))
329 tree.name_stub[nm] = stub
330
331 def hprocess(self, tree):
332 # dprint(tree.children[0], tree.pretty())
333 self.__current_process = tree
334 self.push_scope()
335 self.__push_up(tree)
336 self.augment_name_stub(tree)
337 self.pop_scope()
338 self.__current_process = None
339 return tree
340
341 def hfunction(self, tree):
342 self.__current_function = tree
343 self.push_scope()
344 self.__push_up(tree)
345
346 # func_name, ret_type, func_params, local_vars, func_body = self.__extract_func_def(tree)
347 # dprint(func_params.pretty())
348
349 self.augment_name_stub(tree)
350 self.pop_scope()
351 self.__current_function = None
352 return tree
__push_up(self, current_node)
Definition top_down.py:29