oppc/code: rename oppc_int to oppc_value
[openpower-isa.git] / src / openpower / oppc / pc_code.py
1 import collections
2 import contextlib
3
4 import openpower.oppc.pc_ast as pc_ast
5 import openpower.oppc.pc_util as pc_util
6 import openpower.oppc.pc_pseudocode as pc_pseudocode
7
8
9 class Transient(pc_ast.Node):
10 def __init__(self, value="UINT64_C(0)", bits="(uint8_t)OPPC_XLEN"):
11 self.__value = value
12 self.__bits = bits
13
14 return super().__init__()
15
16 def __str__(self):
17 return f"oppc_transient(&(struct oppc_value){{}}, {self.__value}, {self.__bits})"
18
19
20 class CCall(pc_ast.Dataclass):
21 name: str
22 code: tuple
23 stmt: bool
24
25
26 class CodeVisitor(pc_util.Visitor):
27 def __init__(self, name, root):
28 self.__root = root
29 self.__header = object()
30 self.__footer = object()
31 self.__code = collections.defaultdict(lambda: pc_util.Code())
32 self.__decls = collections.defaultdict(list)
33 self.__regfetch = collections.defaultdict(list)
34 self.__regstore = collections.defaultdict(list)
35 self.__pseudocode = pc_pseudocode.PseudocodeVisitor(root=root)
36
37 super().__init__(root=root)
38
39 self.__code[self.__header].emit(stmt="void")
40 self.__code[self.__header].emit(stmt=f"oppc_{name}(void) {{")
41 with self.__code[self.__header]:
42 for decl in self.__decls:
43 self.__code[self.__header].emit(stmt=f"struct oppc_value {decl};")
44 self.__code[self.__footer].emit(stmt=f"}}")
45
46 def __iter__(self):
47 yield from self.__code[self.__header]
48 yield from self.__code[self.__root]
49 yield from self.__code[self.__footer]
50
51 def __getitem__(self, node):
52 return self.__code[node]
53
54 def transient(self, node,
55 value="UINT64_C(0)",
56 bits="(uint8_t)OPPC_XLEN"):
57 transient = Transient(value=value, bits=bits)
58 self.traverse(root=transient)
59 return transient
60
61 def ccall(self, node, name, code, stmt=False):
62 def validate(item):
63 def validate(item):
64 (level, stmt) = item
65 if not isinstance(level, int):
66 raise ValueError(level)
67 if not isinstance(stmt, str):
68 raise ValueError(stmt)
69 return (level, stmt)
70
71 return tuple(map(validate, item))
72
73 code = tuple(map(validate, code))
74 ccall = CCall(name=name, code=code, stmt=stmt)
75 self.traverse(root=ccall)
76 return ccall
77
78 def ternary(self, node):
79 self[node].clear()
80 self[node].emit(stmt="(")
81 with self[node]:
82 for (level, stmt) in self[node.test]:
83 self[node].emit(stmt=stmt, level=level)
84 self[node].emit(stmt="?")
85 for (level, stmt) in self[node.body]:
86 self[node].emit(stmt=stmt, level=level)
87 self[node].emit(stmt=":")
88 for (level, stmt) in self[node.orelse]:
89 self[node].emit(stmt=stmt, level=level)
90 self[node].emit(stmt=")")
91
92 @contextlib.contextmanager
93 def pseudocode(self, node):
94 for (level, stmt) in self.__pseudocode[node]:
95 self[node].emit(stmt=f"/* {stmt} */", level=level)
96 yield
97
98 @pc_util.Hook(pc_ast.Scope)
99 def Scope(self, node):
100 yield node
101 with self[node]:
102 for subnode in node:
103 for (level, stmt) in self[subnode]:
104 self[node].emit(stmt=stmt, level=level)
105
106 @pc_util.Hook(pc_ast.AssignExpr, pc_ast.AssignIEAExpr)
107 def AssignExpr(self, node):
108 yield node
109 if isinstance(node.lvalue, (pc_ast.GPR, pc_ast.FPR)):
110 self.__regstore[str(node.lvalue)].append(node.lvalue)
111 if isinstance(node.rvalue, (pc_ast.GPR, pc_ast.FPR)):
112 self.__regfetch[str(node.rvalue)].append(node.rvalue)
113
114 if isinstance(node.rvalue, pc_ast.IfExpr):
115 self.ternary(node=node.rvalue)
116
117 if isinstance(node.lvalue, pc_ast.SubscriptExpr):
118 ccall = self.ccall(name="oppc_subscript_assign", node=node, stmt=True, code=[
119 self[node.lvalue.subject],
120 self[node.lvalue.index],
121 self[node.rvalue],
122 ])
123 elif isinstance(node.lvalue, pc_ast.RangeSubscriptExpr):
124 ccall = self.ccall(name="oppc_range_subscript_assign", node=node, stmt=True, code=[
125 self[node.lvalue.subject],
126 self[node.lvalue.start],
127 self[node.lvalue.end],
128 self[node.rvalue],
129 ])
130 else:
131 ccall = self.ccall(name="oppc_assign", stmt=True, node=node, code=[
132 self[node.lvalue],
133 self[node.rvalue],
134 ])
135 with self.pseudocode(node=node):
136 for (level, stmt) in self[ccall]:
137 self[node].emit(stmt=stmt, level=level)
138
139 @pc_util.Hook(pc_ast.BinaryExpr)
140 def BinaryExpr(self, node):
141 yield node
142 if isinstance(node.left, (pc_ast.GPR, pc_ast.FPR)):
143 self.__regfetch[str(node.left)].append(node.left)
144 if isinstance(node.right, (pc_ast.GPR, pc_ast.FPR)):
145 self.__regfetch[str(node.right)].append(node.left)
146
147 comparison = (
148 pc_ast.Lt, pc_ast.Le,
149 pc_ast.Eq, pc_ast.NotEq,
150 pc_ast.Ge, pc_ast.Gt,
151 )
152 if isinstance(node.left, pc_ast.IfExpr):
153 self.ternary(node=node.left)
154 if isinstance(node.right, pc_ast.IfExpr):
155 self.ternary(node=node.right)
156
157 if isinstance(node.op, comparison):
158 ccall = self.ccall(name=str(self[node.op]), node=node, code=[
159 self[node.left],
160 self[node.right],
161 ])
162 else:
163 transient = self.transient(node=node)
164 ccall = self.ccall(name=str(self[node.op]), node=node, code=[
165 self[transient],
166 self[node.left],
167 self[node.right],
168 ])
169 with self.pseudocode(node=node):
170 for (level, stmt) in self[ccall]:
171 self[node].emit(stmt=stmt, level=level)
172
173 @pc_util.Hook(pc_ast.UnaryExpr)
174 def UnaryExpr(self, node):
175 yield node
176 if isinstance(node.value, pc_ast.IfExpr):
177 self.ternary(node=node.value)
178 ccall = self.ccall(name=str(self[node.op]), node=node, code=[
179 self[node.value],
180 ])
181 with self.pseudocode(node=node):
182 for (level, stmt) in self[ccall]:
183 self[node].emit(stmt=stmt, level=level)
184
185 @pc_util.Hook(
186 pc_ast.Not, pc_ast.Add, pc_ast.Sub,
187 pc_ast.Mul, pc_ast.Div, pc_ast.Mod,
188 pc_ast.Lt, pc_ast.Le,
189 pc_ast.Eq, pc_ast.NotEq,
190 pc_ast.Ge, pc_ast.Gt,
191 pc_ast.LShift, pc_ast.RShift,
192 pc_ast.BitAnd, pc_ast.BitOr, pc_ast.BitXor,
193 )
194 def Op(self, node):
195 yield node
196 op = {
197 pc_ast.Not: "oppc_not",
198 pc_ast.Add: "oppc_add",
199 pc_ast.Sub: "oppc_sub",
200 pc_ast.Mul: "oppc_mul",
201 pc_ast.Div: "oppc_div",
202 pc_ast.Mod: "oppc_mod",
203 pc_ast.Lt: "oppc_lt",
204 pc_ast.Le: "oppc_le",
205 pc_ast.Eq: "oppc_eq",
206 pc_ast.NotEq: "oppc_noteq",
207 pc_ast.Ge: "oppc_ge",
208 pc_ast.Gt: "oppc_gt",
209 pc_ast.LShift: "oppc_lshift",
210 pc_ast.RShift: "oppc_rshift",
211 pc_ast.BitAnd: "oppc_and",
212 pc_ast.BitOr: "oppc_or",
213 pc_ast.BitXor: "oppc_xor",
214 }[node.__class__]
215 self[node].emit(stmt=op)
216
217 @pc_util.Hook(pc_ast.BinLiteral, pc_ast.DecLiteral, pc_ast.HexLiteral)
218 def Integer(self, node):
219 yield node
220 fmt = hex
221 value = str(node)
222 if isinstance(node, pc_ast.BinLiteral):
223 bits = f"UINT8_C({str(len(value[2:]))})"
224 value = int(value, 2)
225 elif isinstance(node, pc_ast.HexLiteral):
226 bits = f"UINT8_C({str(len(value[2:]) * 4)})"
227 value = int(value, 16)
228 else:
229 bits = "(uint8_t)OPPC_XLEN"
230 value = int(value)
231 fmt = str
232 if (value > ((2**64) - 1)):
233 raise NotImplementedError()
234 value = f"UINT64_C({fmt(value)})"
235 transient = self.transient(node=node, value=value, bits=bits)
236 with self.pseudocode(node=node):
237 for (level, stmt) in self[transient]:
238 self[node].emit(stmt=stmt, level=level)
239
240 @pc_util.Hook(Transient)
241 def Transient(self, node):
242 yield node
243 self[node].emit(stmt=str(node))
244
245 @pc_util.Hook(CCall)
246 def CCall(self, node):
247 yield node
248 end = (";" if node.stmt else "")
249 if len(node.code) == 0:
250 self[node].emit(stmt=f"{str(node.name)}(){end}")
251 else:
252 self[node].emit(stmt=f"{str(node.name)}(")
253 with self[node]:
254 (*head, tail) = node.code
255 for code in head:
256 for (level, stmt) in code:
257 self[node].emit(stmt=stmt, level=level)
258 (level, stmt) = self[node][-1]
259 if not (not stmt or
260 stmt.startswith("/*") or
261 stmt.endswith((",", "(", "{", "*/"))):
262 stmt = (stmt + ",")
263 self[node][-1] = (level, stmt)
264 for (level, stmt) in tail:
265 self[node].emit(stmt=stmt, level=level)
266 self[node].emit(stmt=f"){end}")
267
268 @pc_util.Hook(pc_ast.GPR)
269 def GPR(self, node):
270 yield node
271 with self.pseudocode(node=node):
272 self[node].emit(stmt=f"&OPPC_GPR[OPPC_GPR_{str(node)}]")
273
274 @pc_util.Hook(pc_ast.FPR)
275 def FPR(self, node):
276 yield node
277 with self.pseudocode(node=node):
278 self[node].emit(stmt=f"&OPPC_FPR[OPPC_FPR_{str(node)}]")
279
280 @pc_util.Hook(pc_ast.RepeatExpr)
281 def RepeatExpr(self, node):
282 yield node
283 transient = self.transient(node=node)
284 ccall = self.ccall(name="oppc_repeat", node=node, code=[
285 self[transient],
286 self[node.subject],
287 self[node.times],
288 ])
289 for (level, stmt) in self[ccall]:
290 self[node].emit(stmt=stmt, level=level)
291
292 @pc_util.Hook(pc_ast.XLEN)
293 def XLEN(self, node):
294 yield node
295 (value, bits) = ("OPPC_XLEN", "(uint8_t)OPPC_XLEN")
296 transient = self.transient(node=node, value=value, bits=bits)
297 with self.pseudocode(node=node):
298 for (level, stmt) in self[transient]:
299 self[node].emit(stmt=stmt, level=level)
300
301 @pc_util.Hook(pc_ast.SubscriptExpr)
302 def SubscriptExpr(self, node):
303 yield node
304 ccall = self.ccall(name="oppc_subscript", node=node, code=[
305 self[node.subject],
306 self[node.index],
307 ])
308 for (level, stmt) in self[ccall]:
309 self[node].emit(stmt=stmt, level=level)
310
311 @pc_util.Hook(pc_ast.RangeSubscriptExpr)
312 def RangeSubscriptExpr(self, node):
313 yield node
314 ccall = self.ccall(name="oppc_subscript", node=node, code=[
315 self[node.subject],
316 self[node.start],
317 self[node.end],
318 ])
319 for (level, stmt) in self[ccall]:
320 self[node].emit(stmt=stmt, level=level)
321
322 @pc_util.Hook(pc_ast.ForExpr)
323 def ForExpr(self, node):
324 yield node
325
326 enter = pc_ast.AssignExpr(
327 lvalue=node.subject.clone(),
328 rvalue=node.start.clone(),
329 )
330 match = pc_ast.BinaryExpr(
331 left=node.subject.clone(),
332 op=pc_ast.Le("<="),
333 right=node.end.clone(),
334 )
335 leave = pc_ast.AssignExpr(
336 lvalue=node.subject.clone(),
337 rvalue=pc_ast.BinaryExpr(
338 left=node.subject.clone(),
339 op=pc_ast.Add("+"),
340 right=node.end.clone(),
341 ),
342 )
343 with self.pseudocode(node=node):
344 (level, stmt) = self[node][0]
345 self[node].clear()
346 self[node].emit(stmt=stmt, level=level)
347 self[node].emit(stmt="for (")
348 with self[node]:
349 with self[node]:
350 for subnode in (enter, match, leave):
351 self.__pseudocode.traverse(root=subnode)
352 self.traverse(root=subnode)
353 for (level, stmt) in self[subnode]:
354 self[node].emit(stmt=stmt, level=level)
355 (level, stmt) = self[node][-1]
356 if subnode is match:
357 stmt = f"{stmt};"
358 elif subnode is leave:
359 stmt = stmt[:-1]
360 self[node][-1] = (level, stmt)
361 (level, stmt) = self[node][0]
362 self[node].emit(stmt=stmt, level=level)
363 self[node].emit(stmt=") {")
364 for (level, stmt) in self[node.body]:
365 self[node].emit(stmt=stmt, level=level)
366 self[node].emit(stmt="}")
367
368 @pc_util.Hook(pc_ast.WhileExpr)
369 def WhileExpr(self, node):
370 yield node
371 self[node].emit(stmt="while (")
372 with self[node]:
373 with self[node]:
374 for (level, stmt) in self[node.test]:
375 self[node].emit(stmt=stmt, level=level)
376 self[node].emit(") {")
377 for (level, stmt) in self[node.body]:
378 self[node].emit(stmt=stmt, level=level)
379 if node.orelse:
380 self[node].emit(stmt="} else {")
381 for (level, stmt) in self[node.orelse]:
382 self[node].emit(stmt=stmt, level=level)
383 self[node].emit(stmt="}")
384
385 @pc_util.Hook(pc_ast.IfExpr)
386 def IfExpr(self, node):
387 yield node
388 self[node].emit(stmt="if (")
389 with self[node]:
390 for (level, stmt) in self[node.test]:
391 self[node].emit(stmt=stmt, level=level)
392 self[node].emit(stmt=") {")
393 for (level, stmt) in self[node.body]:
394 self[node].emit(stmt=stmt, level=level)
395 if node.orelse:
396 self[node].emit(stmt="} else {")
397 for (level, stmt) in self[node.orelse]:
398 self[node].emit(stmt=stmt, level=level)
399 self[node].emit(stmt="}")
400
401 @pc_util.Hook(pc_ast.Call.Name)
402 def CallName(self, node):
403 yield node
404 self[node].emit(stmt=str(node))
405
406 @pc_util.Hook(pc_ast.Call.Arguments)
407 def CallArguments(self, node):
408 yield node
409 for subnode in node:
410 if isinstance(subnode, (pc_ast.GPR, pc_ast.FPR)):
411 self.__regfetch[str(subnode)].append(subnode)
412
413 @pc_util.Hook(pc_ast.Call)
414 def Call(self, node):
415 yield node
416 code = tuple(map(lambda arg: self[arg], node.args))
417 ccall = self.ccall(name=str(node.name), node=node, code=code)
418 for (level, stmt) in self[ccall]:
419 self[node].emit(stmt=stmt, level=level)
420
421 @pc_util.Hook(pc_ast.Symbol)
422 def Symbol(self, node):
423 yield node
424 self.__decls[str(node)].append(node)
425 with self.pseudocode(node=node):
426 self[node].emit(stmt=f"&{str(node)}")
427
428 @pc_util.Hook(pc_ast.Node)
429 def Node(self, node):
430 raise NotImplementedError(type(node))
431
432
433 def code(name, root):
434 yield from CodeVisitor(name=name, root=root)