107099fac84ad2302a5673f3346d8bfeafeef52e
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
9 class Transient(pc_ast
.Node
):
10 def __init__(self
, value
="UINT64_C(0)", bits
="(uint8_t)OPPC_XLEN"):
14 return super().__init
__()
17 return f
"oppc_transient(&(struct oppc_value){{}}, {self.__value}, {self.__bits})"
20 class Call(pc_ast
.Dataclass
):
26 class CodeVisitor(pc_util
.Visitor
):
27 def __init__(self
, name
, root
):
30 self
.__header
= object()
31 self
.__footer
= object()
32 self
.__code
= collections
.defaultdict(lambda: pc_util
.Code())
33 self
.__decls
= collections
.defaultdict(list)
34 self
.__regfetch
= collections
.defaultdict(list)
35 self
.__regstore
= collections
.defaultdict(list)
36 self
.__pseudocode
= pc_pseudocode
.PseudocodeVisitor(root
=root
)
38 super().__init
__(root
=root
)
40 self
.__code
[self
.__header
].emit(stmt
="void")
41 self
.__code
[self
.__header
].emit(stmt
=f
"oppc_{name}(void) {{")
42 with self
.__code
[self
.__header
]:
43 for decl
in self
.__decls
:
44 self
.__code
[self
.__header
].emit(stmt
=f
"struct oppc_value {decl};")
45 self
.__code
[self
.__footer
].emit(stmt
=f
"}}")
48 yield from self
.__code
[self
.__header
]
49 yield from self
.__code
[self
.__root
]
50 yield from self
.__code
[self
.__footer
]
52 def __getitem__(self
, node
):
53 return self
.__code
[node
]
55 def __setitem__(self
, node
, code
):
56 self
.__code
[node
] = code
58 def transient(self
, node
,
60 bits
="(uint8_t)OPPC_XLEN"):
61 transient
= Transient(value
=value
, bits
=bits
)
62 self
.traverse(root
=transient
)
65 def call(self
, node
, name
, code
, stmt
=False):
69 if not isinstance(level
, int):
70 raise ValueError(level
)
71 if not isinstance(stmt
, str):
72 raise ValueError(stmt
)
75 return tuple(map(validate
, item
))
77 code
= tuple(map(validate
, code
))
78 call
= Call(name
=name
, code
=code
, stmt
=stmt
)
79 self
.traverse(root
=call
)
82 def fixup_ternary(self
, node
):
84 test
= self
.call(name
="oppc_bool", node
=node
, code
=[
87 self
[node
].emit(stmt
="(")
89 for (level
, stmt
) in self
[test
]:
90 self
[node
].emit(stmt
=stmt
, level
=level
)
91 self
[node
].emit(stmt
="?")
92 for (level
, stmt
) in self
[node
.body
]:
93 self
[node
].emit(stmt
=stmt
, level
=level
)
94 self
[node
].emit(stmt
=":")
95 for (level
, stmt
) in self
[node
.orelse
]:
96 self
[node
].emit(stmt
=stmt
, level
=level
)
97 self
[node
].emit(stmt
=")")
99 def fixup_attr(self
, node
, assign
=False):
101 code
= tuple(self
[root
])
102 attribute_or_subscript
= (
104 pc_ast
.SubscriptExpr
,
105 pc_ast
.RangeSubscriptExpr
,
107 while isinstance(node
.subject
, attribute_or_subscript
):
114 stmt
.startswith("/*") or
115 stmt
.endswith((",", "(", "{", "*/"))):
119 return tuple(map(wrap
, code
))
121 code
= pc_util
.Code()
122 for (level
, stmt
) in wrap(self
[node
.subject
]):
123 code
.emit(stmt
=stmt
, level
=level
)
124 for (level
, stmt
) in wrap(self
[root
]):
125 code
.emit(stmt
=stmt
, level
=level
)
127 # discard the last comma
128 (level
, stmt
) = code
[-1]
129 code
[-1] = (level
, stmt
[:-1])
132 call
= self
.call(name
="oppc_attr", node
=root
, code
=[
138 @contextlib.contextmanager
139 def pseudocode(self
, node
):
140 for (level
, stmt
) in self
.__pseudocode
[node
]:
141 self
[node
].emit(stmt
=f
"/* {stmt} */", level
=level
)
144 @pc_util.Hook(pc_ast
.Scope
)
145 def Scope(self
, node
):
149 for (level
, stmt
) in self
[subnode
]:
150 self
[node
].emit(stmt
=stmt
, level
=level
)
152 @pc_util.Hook(pc_ast
.AssignExpr
, pc_ast
.AssignIEAExpr
)
153 def AssignExpr(self
, node
):
155 if isinstance(node
.lvalue
, (pc_ast
.GPR
, pc_ast
.FPR
)):
156 self
.__regstore
[str(node
.lvalue
)].append(node
.lvalue
)
157 if isinstance(node
.rvalue
, (pc_ast
.GPR
, pc_ast
.FPR
)):
158 self
.__regfetch
[str(node
.rvalue
)].append(node
.rvalue
)
160 if isinstance(node
.rvalue
, pc_ast
.IfExpr
):
161 self
.fixup_ternary(node
=node
.rvalue
)
162 if isinstance(node
.lvalue
, pc_ast
.Attribute
):
163 self
.fixup_attr(node
=node
.lvalue
, assign
=True)
164 if isinstance(node
.rvalue
, pc_ast
.Attribute
):
165 self
.fixup_attr(node
=node
.rvalue
)
167 if isinstance(node
.lvalue
, pc_ast
.SubscriptExpr
):
168 call
= self
.call(name
="oppc_subscript_assign", node
=node
, stmt
=True, code
=[
169 self
[node
.lvalue
.subject
],
170 self
[node
.lvalue
.index
],
173 elif isinstance(node
.lvalue
, pc_ast
.RangeSubscriptExpr
):
174 call
= self
.call(name
="oppc_range_subscript_assign", node
=node
, stmt
=True, code
=[
175 self
[node
.lvalue
.subject
],
176 self
[node
.lvalue
.start
],
177 self
[node
.lvalue
.end
],
180 elif isinstance(node
.lvalue
, pc_ast
.Attribute
):
181 call
= self
.call(name
="oppc_attr_assign", stmt
=True, node
=node
, code
=[
186 call
= self
.call(name
="oppc_assign", stmt
=True, node
=node
, code
=[
190 with self
.pseudocode(node
=node
):
191 for (level
, stmt
) in self
[call
]:
192 self
[node
].emit(stmt
=stmt
, level
=level
)
194 @pc_util.Hook(pc_ast
.BinaryExpr
)
195 def BinaryExpr(self
, node
):
197 if isinstance(node
.left
, (pc_ast
.GPR
, pc_ast
.FPR
)):
198 self
.__regfetch
[str(node
.left
)].append(node
.left
)
199 if isinstance(node
.right
, (pc_ast
.GPR
, pc_ast
.FPR
)):
200 self
.__regfetch
[str(node
.right
)].append(node
.left
)
203 pc_ast
.Lt
, pc_ast
.Le
,
204 pc_ast
.Eq
, pc_ast
.NotEq
,
205 pc_ast
.Ge
, pc_ast
.Gt
,
206 pc_ast
.LtU
, pc_ast
.GtU
,
208 if isinstance(node
.left
, pc_ast
.IfExpr
):
209 self
.fixup_ternary(node
=node
.left
)
210 if isinstance(node
.right
, pc_ast
.IfExpr
):
211 self
.fixup_ternary(node
=node
.right
)
212 if isinstance(node
.left
, pc_ast
.Attribute
):
213 self
.fixup_attr(node
=node
.left
)
214 if isinstance(node
.right
, pc_ast
.Attribute
):
215 self
.fixup_attr(node
=node
.right
)
217 if isinstance(node
.op
, comparison
):
218 call
= self
.call(name
=str(self
[node
.op
]), node
=node
, code
=[
223 transient
= self
.transient(node
=node
)
224 call
= self
.call(name
=str(self
[node
.op
]), node
=node
, code
=[
229 with self
.pseudocode(node
=node
):
230 for (level
, stmt
) in self
[call
]:
231 self
[node
].emit(stmt
=stmt
, level
=level
)
233 @pc_util.Hook(pc_ast
.UnaryExpr
)
234 def UnaryExpr(self
, node
):
236 if isinstance(node
.value
, pc_ast
.IfExpr
):
237 self
.fixup_ternary(node
=node
.value
)
238 call
= self
.call(name
=str(self
[node
.op
]), node
=node
, code
=[
241 with self
.pseudocode(node
=node
):
242 for (level
, stmt
) in self
[call
]:
243 self
[node
].emit(stmt
=stmt
, level
=level
)
246 pc_ast
.Not
, pc_ast
.Add
, pc_ast
.Sub
,
247 pc_ast
.Mul
, pc_ast
.Div
, pc_ast
.Mod
,
248 pc_ast
.Lt
, pc_ast
.Le
,
249 pc_ast
.Eq
, pc_ast
.NotEq
,
250 pc_ast
.Ge
, pc_ast
.Gt
,
251 pc_ast
.LtU
, pc_ast
.GtU
,
252 pc_ast
.LShift
, pc_ast
.RShift
,
253 pc_ast
.BitAnd
, pc_ast
.BitOr
, pc_ast
.BitXor
,
259 pc_ast
.Not
: "oppc_not",
260 pc_ast
.Add
: "oppc_add",
261 pc_ast
.Sub
: "oppc_sub",
262 pc_ast
.Mul
: "oppc_mul",
263 pc_ast
.Div
: "oppc_div",
264 pc_ast
.Mod
: "oppc_mod",
265 pc_ast
.Lt
: "oppc_lt",
266 pc_ast
.Le
: "oppc_le",
267 pc_ast
.Eq
: "oppc_eq",
268 pc_ast
.LtU
: "oppc_ltu",
269 pc_ast
.GtU
: "oppc_gtu",
270 pc_ast
.NotEq
: "oppc_noteq",
271 pc_ast
.Ge
: "oppc_ge",
272 pc_ast
.Gt
: "oppc_gt",
273 pc_ast
.LShift
: "oppc_lshift",
274 pc_ast
.RShift
: "oppc_rshift",
275 pc_ast
.BitAnd
: "oppc_and",
276 pc_ast
.BitOr
: "oppc_or",
277 pc_ast
.BitXor
: "oppc_xor",
278 pc_ast
.BitConcat
: "oppc_concat",
280 self
[node
].emit(stmt
=op
)
282 @pc_util.Hook(pc_ast
.BinLiteral
, pc_ast
.DecLiteral
, pc_ast
.HexLiteral
)
283 def Integer(self
, node
):
287 if isinstance(node
, pc_ast
.BinLiteral
):
288 bits
= f
"UINT8_C({str(len(value[2:]))})"
289 value
= int(value
, 2)
290 elif isinstance(node
, pc_ast
.HexLiteral
):
291 bits
= f
"UINT8_C({str(len(value[2:]) * 4)})"
292 value
= int(value
, 16)
294 bits
= "(uint8_t)OPPC_XLEN"
297 if (value
> ((2**64) - 1)):
298 raise NotImplementedError()
299 value
= f
"UINT64_C({fmt(value)})"
300 transient
= self
.transient(node
=node
, value
=value
, bits
=bits
)
301 with self
.pseudocode(node
=node
):
302 for (level
, stmt
) in self
[transient
]:
303 self
[node
].emit(stmt
=stmt
, level
=level
)
305 @pc_util.Hook(Transient
)
306 def Transient(self
, node
):
308 self
[node
].emit(stmt
=str(node
))
311 def CCall(self
, node
):
313 end
= (";" if node
.stmt
else "")
314 if len(node
.code
) == 0:
315 self
[node
].emit(stmt
=f
"{str(node.name)}(){end}")
317 self
[node
].emit(stmt
=f
"{str(node.name)}(")
319 (*head
, tail
) = node
.code
321 for (level
, stmt
) in code
:
322 self
[node
].emit(stmt
=stmt
, level
=level
)
323 (level
, stmt
) = self
[node
][-1]
325 stmt
.startswith("/*") or
326 stmt
.endswith((",", "(", "{", "*/"))):
328 self
[node
][-1] = (level
, stmt
)
329 for (level
, stmt
) in tail
:
330 self
[node
].emit(stmt
=stmt
, level
=level
)
331 self
[node
].emit(stmt
=f
"){end}")
333 @pc_util.Hook(pc_ast
.GPR
)
336 with self
.pseudocode(node
=node
):
337 self
[node
].emit(stmt
=f
"&OPPC_GPR[OPPC_GPR_{str(node)}]")
339 @pc_util.Hook(pc_ast
.FPR
)
342 with self
.pseudocode(node
=node
):
343 self
[node
].emit(stmt
=f
"&OPPC_FPR[OPPC_FPR_{str(node)}]")
345 @pc_util.Hook(pc_ast
.RepeatExpr
)
346 def RepeatExpr(self
, node
):
348 transient
= self
.transient(node
=node
)
349 call
= self
.call(name
="oppc_repeat", node
=node
, code
=[
354 for (level
, stmt
) in self
[call
]:
355 self
[node
].emit(stmt
=stmt
, level
=level
)
357 @pc_util.Hook(pc_ast
.XLEN
)
358 def XLEN(self
, node
):
360 (value
, bits
) = ("OPPC_XLEN", "(uint8_t)OPPC_XLEN")
361 transient
= self
.transient(node
=node
, value
=value
, bits
=bits
)
362 with self
.pseudocode(node
=node
):
363 for (level
, stmt
) in self
[transient
]:
364 self
[node
].emit(stmt
=stmt
, level
=level
)
366 @pc_util.Hook(pc_ast
.Overflow
, pc_ast
.CR3
, pc_ast
.CR5
,
367 pc_ast
.XER
, pc_ast
.Reserve
, pc_ast
.Special
)
368 def Special(self
, node
):
370 with self
.pseudocode(node
=node
):
371 self
[node
].emit(stmt
=f
"&OPPC_{str(node).upper()}")
373 @pc_util.Hook(pc_ast
.SubscriptExpr
)
374 def SubscriptExpr(self
, node
):
376 call
= self
.call(name
="oppc_subscript", node
=node
, code
=[
380 for (level
, stmt
) in self
[call
]:
381 self
[node
].emit(stmt
=stmt
, level
=level
)
383 @pc_util.Hook(pc_ast
.RangeSubscriptExpr
)
384 def RangeSubscriptExpr(self
, node
):
386 call
= self
.call(name
="oppc_subscript", node
=node
, code
=[
391 for (level
, stmt
) in self
[call
]:
392 self
[node
].emit(stmt
=stmt
, level
=level
)
394 @pc_util.Hook(pc_ast
.ForExpr
)
395 def ForExpr(self
, node
):
398 enter
= pc_ast
.AssignExpr(
399 lvalue
=node
.subject
.clone(),
400 rvalue
=node
.start
.clone(),
402 match
= pc_ast
.BinaryExpr(
403 left
=node
.subject
.clone(),
405 right
=node
.end
.clone(),
407 leave
= pc_ast
.AssignExpr(
408 lvalue
=node
.subject
.clone(),
409 rvalue
=pc_ast
.BinaryExpr(
410 left
=node
.subject
.clone(),
412 right
=node
.end
.clone(),
415 with self
.pseudocode(node
=node
):
416 (level
, stmt
) = self
[node
][0]
418 self
[node
].emit(stmt
=stmt
, level
=level
)
419 self
[node
].emit(stmt
="for (")
422 for subnode
in (enter
, match
, leave
):
423 self
.__pseudocode
.traverse(root
=subnode
)
424 self
.traverse(root
=subnode
)
425 for (level
, stmt
) in self
[subnode
]:
426 self
[node
].emit(stmt
=stmt
, level
=level
)
427 (level
, stmt
) = self
[node
][-1]
430 elif subnode
is leave
:
432 self
[node
][-1] = (level
, stmt
)
433 (level
, stmt
) = self
[node
][0]
434 self
[node
].emit(stmt
=stmt
, level
=level
)
435 self
[node
].emit(stmt
=") {")
436 for (level
, stmt
) in self
[node
.body
]:
437 self
[node
].emit(stmt
=stmt
, level
=level
)
438 self
[node
].emit(stmt
="}")
440 @pc_util.Hook(pc_ast
.WhileExpr
)
441 def WhileExpr(self
, node
):
443 self
[node
].emit(stmt
="while (")
446 for (level
, stmt
) in self
[node
.test
]:
447 self
[node
].emit(stmt
=stmt
, level
=level
)
448 self
[node
].emit(") {")
449 for (level
, stmt
) in self
[node
.body
]:
450 self
[node
].emit(stmt
=stmt
, level
=level
)
452 self
[node
].emit(stmt
="} else {")
453 for (level
, stmt
) in self
[node
.orelse
]:
454 self
[node
].emit(stmt
=stmt
, level
=level
)
455 self
[node
].emit(stmt
="}")
457 @pc_util.Hook(pc_ast
.IfExpr
)
458 def IfExpr(self
, node
):
460 test
= self
.call(name
="oppc_bool", node
=node
, code
=[
463 self
[node
].emit(stmt
="if (")
465 for (level
, stmt
) in self
[test
]:
466 self
[node
].emit(stmt
=stmt
, level
=level
)
467 self
[node
].emit(stmt
=") {")
468 for (level
, stmt
) in self
[node
.body
]:
469 self
[node
].emit(stmt
=stmt
, level
=level
)
471 self
[node
].emit(stmt
="} else {")
472 for (level
, stmt
) in self
[node
.orelse
]:
473 self
[node
].emit(stmt
=stmt
, level
=level
)
474 self
[node
].emit(stmt
="}")
476 @pc_util.Hook(pc_ast
.SwitchExpr
)
477 def SwitchExpr(self
, node
):
479 subject
= self
.call(name
="oppc_int64", node
=node
, code
=[
482 self
[node
].emit(stmt
="switch (")
484 for (level
, stmt
) in self
[subject
]:
485 self
[node
].emit(stmt
=stmt
, level
=level
)
486 self
[node
].emit(") {")
488 for (level
, stmt
) in self
[node
.cases
]:
489 self
[node
].emit(stmt
=stmt
, level
=level
)
491 @pc_util.Hook(pc_ast
.Cases
)
492 def Cases(self
, node
):
495 for (level
, stmt
) in self
[subnode
]:
496 self
[node
].emit(stmt
=stmt
, level
=level
)
498 @pc_util.Hook(pc_ast
.Case
)
499 def Case(self
, node
):
501 for (level
, stmt
) in self
[node
.labels
]:
502 self
[node
].emit(stmt
=stmt
, level
=level
)
503 for (level
, stmt
) in self
[node
.body
]:
504 self
[node
].emit(stmt
=stmt
, level
=level
)
506 @pc_util.Hook(pc_ast
.Labels
)
507 def Labels(self
, node
):
509 if ((len(node
) == 1) and isinstance(node
[-1], pc_ast
.DefaultLabel
)):
512 labels
= ", ".join(map(lambda label
: str(self
[label
]), node
))
513 stmt
= f
"case ({labels}):"
514 self
[node
].emit(stmt
=stmt
)
516 @pc_util.Hook(pc_ast
.Label
)
517 def Label(self
, node
):
519 self
[node
].emit(stmt
=str(node
))
521 @pc_util.Hook(pc_ast
.LeaveKeyword
)
522 def LeaveKeyword(self
, node
):
524 self
[node
].emit(stmt
="break;")
526 @pc_util.Hook(pc_ast
.Call
.Name
)
527 def CallName(self
, node
):
529 self
[node
].emit(stmt
=str(node
))
531 @pc_util.Hook(pc_ast
.Call
.Arguments
)
532 def CallArguments(self
, node
):
535 if isinstance(subnode
, (pc_ast
.GPR
, pc_ast
.FPR
)):
536 self
.__regfetch
[str(subnode
)].append(subnode
)
538 @pc_util.Hook(pc_ast
.Call
)
539 def Call(self
, node
):
541 code
= tuple(map(lambda arg
: self
[arg
], node
.args
))
542 call
= self
.call(name
=str(node
.name
), node
=node
, code
=code
)
543 for (level
, stmt
) in self
[call
]:
544 self
[node
].emit(stmt
=stmt
, level
=level
)
546 @pc_util.Hook(pc_ast
.Attribute
.Name
)
547 def AttributeName(self
, node
):
550 @pc_util.Hook(pc_ast
.Attribute
)
551 def Attribute(self
, node
):
553 attr
= str(self
.__pseudocode
[node
])
554 symbol
= f
"OPPC_ATTR_{attr.replace('.', '_')}"
555 self
[node
].emit(f
"/* {attr} */")
556 self
[node
].emit(stmt
=symbol
)
557 self
.__attrs
[node
] = symbol
559 @pc_util.Hook(pc_ast
.Symbol
)
560 def Symbol(self
, node
):
562 with self
.pseudocode(node
=node
):
563 if str(node
) not in ("fallthrough",):
564 self
.__decls
[str(node
)].append(node
)
565 self
[node
].emit(stmt
=f
"&{str(node)}")
567 @pc_util.Hook(pc_ast
.Node
)
568 def Node(self
, node
):
569 raise NotImplementedError(type(node
))
572 def code(name
, root
):
573 yield from CodeVisitor(name
=name
, root
=root
)