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
26 self.__current_thread = None
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.function_invocations
39
40 @current_process_function_invocations.setter
42 self.__current_process.function_invocations = val
43
44 @property
46 return self.__current_function.assignments
47
48 @property
50 return self.__current_function.function_invocations
51
52 @property
54 if self.__current_function:
55 return self.__current_function.function_invocations
56 elif self.__current_process:
57 return self.__current_process.function_invocations
58 elif self.__current_thread:
59 return self.__current_thread.function_invocations
60 else:
61 raise ValueError('Current scope is not set')
62
63 @current_function_assignments.setter
65 self.__current_function.assignments = val
66
67 def hprocess(self, tree):
68 self.__current_process = tree
69 tree.function_invocations = []
71 self.__push_up(tree)
72 self.__current_process = None
73 return tree
74
75 def hthreadswitch(self, tree):
76 # NOTE: this is only used for generated functions
77 self.__current_thread = tree
78 tree.function_invocations = []
79 self.__push_up(tree)
80 self.__current_process = None
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
157 self.__current_function = tree
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
177 self.__current_function = None
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):
218 for f in self.current_function_nodes:
219 if f.children[0] == func_name:
220 return f
221 # try fuzzy search
222 for f in self.current_function_nodes:
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 dprint(arg_node, arg_tpe)
295 if is_tree_type(arg_node, 'hvarref'):
296 return arg_node.children[0]
297 elif is_tree_types(arg_node, ['hliteral', 'hbinop', 'hmethodcall', 'syscread', 'hunop', 'hslice']):
298 warn('Complex expression or constant used for in/out argument, '
299 'this will cause phantom argument to be created and the output result will be discarded. '
300 'Consider using non-reference or const-reference instead')
301 phantom_var = self.new_phantom_var_name(arg_tpe)
302 arg_node.phantom_var = phantom_var
303 return phantom_var
304 elif isinstance(arg_node, str): # strings can be treated as an ID
305 return arg_node
306 raise ValueError('Unsupported form of function argument')
307
308 def augment_name_stub(self, tree):
309 tree.name_stub = dict()
310 tree.phantom_vars = dict()
311 names_to_stub = set()
312 for invoc in tree.function_invocations:
313 invoc_params = invoc.children[1:]
314 f_name = invoc.children[0]
315 func_node = self.__search_current_function(f_name)
316 func_name, ret_type, func_params, local_vars, func_body = self.__extract_func_def(func_node)
317 if func_params is not None:
318 for idx, param in func_params.io_params:
319 arg_node = invoc_params[idx]
320 tpe = func_params.children[idx].children[1]
321 name = self.__extract_name_from_method_args(arg_node, tpe)
322 if hasattr(arg_node, 'phantom_var'):
323 tree.phantom_vars[name] = tpe
324 names_to_stub.add(name)
325 # dprint(tree.phantom_vars)
326 # actually, we can finalized the name of the stub here
327 for nm in names_to_stub:
328 stub = ProcessVarNameStub(nm, self.search_id_def(nm))
329 stub.insert_name(lambda x: self.search_id_def(x, True))
330 tree.name_stub[nm] = stub
331
332 def hprocess(self, tree):
333 # dprint(tree.children[0], tree.pretty())
334 self.__current_process = tree
335 self.push_scope()
336 self.__push_up(tree)
337 self.augment_name_stub(tree)
338 self.pop_scope()
339 self.__current_process = None
340 return tree
341
342 def hfunction(self, tree):
343 self.__current_function = tree
344 self.push_scope()
345 self.__push_up(tree)
346
347 # func_name, ret_type, func_params, local_vars, func_body = self.__extract_func_def(tree)
348 # dprint(func_params.pretty())
349
350 self.augment_name_stub(tree)
351 self.pop_scope()
352 self.__current_function = None
353 return tree
__push_up(self, current_node)
Definition top_down.py:29