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
"{hex(id(self))}@{self.__class__.__name__}({self.__value}, {self.__bits})"
20 return f
"oppc_transient(&(struct oppc_value){{}}, {self.__value}, {self.__bits})"
23 class Call(pc_ast
.Dataclass
):
29 class Instruction(pc_ast
.Node
):
33 class CodeVisitor(pc_util
.Visitor
):
34 def __init__(self
, insn
, root
):
35 if not isinstance(root
, pc_ast
.Scope
):
36 raise ValueError(root
)
41 self
.__header
= object()
42 self
.__footer
= object()
43 self
.__code
= collections
.defaultdict(lambda: pc_util
.Code())
44 self
.__regfetch
= collections
.defaultdict(list)
45 self
.__regstore
= collections
.defaultdict(list)
46 self
.__pseudocode
= pc_pseudocode
.PseudocodeVisitor(root
=root
)
48 super().__init
__(root
=root
)
50 for decl
in self
.__decls
:
51 self
.__code
[self
.__header
].emit(stmt
=f
"struct oppc_value {decl};")
52 decls
= sorted(filter(lambda decl
: decl
in insn
.fields
, self
.__decls
))
54 self
.__code
[self
.__header
].emit()
56 bits
= f
"{len(insn.fields[decl])}"
57 transient
= Transient(bits
=bits
)
58 symbol
= pc_ast
.Symbol(decl
)
59 assign
= pc_ast
.AssignExpr(lvalue
=symbol
, rvalue
=transient
)
60 self
.traverse(root
=assign
)
61 for (level
, stmt
) in self
[assign
]:
62 self
[self
.__header
].emit(stmt
=stmt
, level
=level
)
63 for (lbit
, rbit
) in enumerate(insn
.fields
[decl
]):
64 lsymbol
= pc_ast
.Symbol(decl
)
65 rsymbol
= Instruction()
66 lindex
= Transient(value
=str(lbit
))
67 rindex
= Transient(value
=str(rbit
))
68 lvalue
= pc_ast
.SubscriptExpr(index
=lindex
, subject
=lsymbol
)
69 rvalue
= pc_ast
.SubscriptExpr(index
=rindex
, subject
=rsymbol
)
70 assign
= pc_ast
.AssignExpr(lvalue
=lvalue
, rvalue
=rvalue
)
71 self
.traverse(root
=assign
)
72 for (level
, stmt
) in self
[assign
]:
73 self
[self
.__header
].emit(stmt
=stmt
, level
=level
)
74 self
.__code
[self
.__header
].emit()
76 self
.__code
[self
.__header
].emit()
79 yield from self
[self
.__header
]
80 for (level
, stmt
) in self
[self
.__root
]:
81 yield ((level
- 1), stmt
)
82 yield from self
[self
.__footer
]
84 def __getitem__(self
, node
):
85 return self
.__code
[node
]
87 def __setitem__(self
, node
, code
):
88 self
.__code
[node
] = code
92 bits
="(uint8_t)OPPC_XLEN"):
93 transient
= Transient(value
=value
, bits
=bits
)
94 self
.traverse(root
=transient
)
97 def call(self
, name
, code
, stmt
=False):
101 if not isinstance(level
, int):
102 raise ValueError(level
)
103 if not isinstance(stmt
, str):
104 raise ValueError(stmt
)
107 return tuple(map(validate
, item
))
109 code
= tuple(map(validate
, code
))
110 call
= Call(name
=name
, code
=code
, stmt
=stmt
)
111 self
.traverse(root
=call
)
114 def fixup_ternary(self
, node
):
116 test
= self
.call(name
="oppc_cast_bool", code
=[
119 self
[node
].emit(stmt
="(")
121 for (level
, stmt
) in self
[test
]:
122 self
[node
].emit(stmt
=stmt
, level
=level
)
123 self
[node
].emit(stmt
="?")
124 for (level
, stmt
) in self
[node
.body
]:
125 self
[node
].emit(stmt
=stmt
, level
=level
)
126 self
[node
].emit(stmt
=":")
127 for (level
, stmt
) in self
[node
.orelse
]:
128 self
[node
].emit(stmt
=stmt
, level
=level
)
129 self
[node
].emit(stmt
=")")
131 def fixup_attr(self
, node
, assign
=False):
133 code
= tuple(self
[root
])
134 attribute_or_subscript
= (
136 pc_ast
.SubscriptExpr
,
137 pc_ast
.RangeSubscriptExpr
,
139 while isinstance(node
.subject
, attribute_or_subscript
):
146 stmt
.startswith("/*") or
147 stmt
.endswith((",", "(", "{", "*/"))):
151 return tuple(map(wrap
, code
))
153 code
= pc_util
.Code()
154 for (level
, stmt
) in wrap(self
[node
.subject
]):
155 code
.emit(stmt
=stmt
, level
=level
)
156 for (level
, stmt
) in wrap(self
[root
]):
157 code
.emit(stmt
=stmt
, level
=level
)
159 # discard the last comma
160 (level
, stmt
) = code
[-1]
161 code
[-1] = (level
, stmt
[:-1])
164 call
= self
.call(name
="oppc_attr", code
=[
170 @contextlib.contextmanager
171 def pseudocode(self
, node
):
172 if node
in self
.__pseudocode
:
173 for (level
, stmt
) in self
.__pseudocode
[node
]:
174 self
[node
].emit(stmt
=f
"/* {stmt} */", level
=level
)
177 @pc_util.Hook(pc_ast
.Scope
)
178 def Scope(self
, node
):
182 for (level
, stmt
) in self
[subnode
]:
183 self
[node
].emit(stmt
=stmt
, level
=level
)
185 @pc_util.Hook(pc_ast
.AssignExpr
, pc_ast
.AssignIEAExpr
)
186 def AssignExpr(self
, node
):
188 if isinstance(node
.lvalue
, (pc_ast
.GPR
, pc_ast
.FPR
)):
189 self
.__regstore
[str(node
.lvalue
)].append(node
.lvalue
)
190 if isinstance(node
.rvalue
, (pc_ast
.GPR
, pc_ast
.FPR
)):
191 self
.__regfetch
[str(node
.rvalue
)].append(node
.rvalue
)
193 if isinstance(node
.rvalue
, pc_ast
.IfExpr
):
194 self
.fixup_ternary(node
=node
.rvalue
)
195 if isinstance(node
.lvalue
, pc_ast
.Attribute
):
196 self
.fixup_attr(node
=node
.lvalue
, assign
=True)
197 if isinstance(node
.rvalue
, pc_ast
.Attribute
):
198 self
.fixup_attr(node
=node
.rvalue
)
200 if isinstance(node
.lvalue
, pc_ast
.Sequence
):
201 if not isinstance(node
.rvalue
, pc_ast
.Sequence
):
202 raise ValueError(node
.rvalue
)
203 if len(node
.lvalue
) != len(node
.rvalue
):
204 raise ValueError(node
)
205 for (lvalue
, rvalue
) in zip(node
.lvalue
, node
.rvalue
):
206 assign
= node
.__class
__(
207 lvalue
=lvalue
.clone(),
208 rvalue
=rvalue
.clone(),
210 self
.traverse(root
=assign
)
211 for (level
, stmt
) in self
[assign
]:
212 self
[node
].emit(stmt
=stmt
, level
=level
)
215 if isinstance(node
.lvalue
, pc_ast
.SubscriptExpr
):
216 call
= self
.call(name
="oppc_subscript_assign", stmt
=True, code
=[
217 self
[node
.lvalue
.subject
],
218 self
[node
.lvalue
.index
],
221 elif isinstance(node
.lvalue
, pc_ast
.RangeSubscriptExpr
):
222 call
= self
.call(name
="oppc_range_subscript_assign", stmt
=True, code
=[
223 self
[node
.lvalue
.subject
],
224 self
[node
.lvalue
.start
],
225 self
[node
.lvalue
.end
],
228 elif isinstance(node
.lvalue
, pc_ast
.Attribute
):
229 call
= self
.call(name
="oppc_attr_assign", stmt
=True, code
=[
234 call
= self
.call(name
="oppc_assign", stmt
=True, code
=[
238 with self
.pseudocode(node
=node
):
239 for (level
, stmt
) in self
[call
]:
240 self
[node
].emit(stmt
=stmt
, level
=level
)
242 @pc_util.Hook(pc_ast
.BinaryExpr
)
243 def BinaryExpr(self
, node
):
245 if isinstance(node
.left
, (pc_ast
.GPR
, pc_ast
.FPR
)):
246 self
.__regfetch
[str(node
.left
)].append(node
.left
)
247 if isinstance(node
.right
, (pc_ast
.GPR
, pc_ast
.FPR
)):
248 self
.__regfetch
[str(node
.right
)].append(node
.left
)
250 if isinstance(node
.left
, pc_ast
.IfExpr
):
251 self
.fixup_ternary(node
=node
.left
)
252 if isinstance(node
.right
, pc_ast
.IfExpr
):
253 self
.fixup_ternary(node
=node
.right
)
254 if isinstance(node
.left
, pc_ast
.Attribute
):
255 self
.fixup_attr(node
=node
.left
)
256 if isinstance(node
.right
, pc_ast
.Attribute
):
257 self
.fixup_attr(node
=node
.right
)
260 pc_ast
.Lt
, pc_ast
.Le
,
261 pc_ast
.Eq
, pc_ast
.Ne
,
262 pc_ast
.Ge
, pc_ast
.Gt
,
263 pc_ast
.LtU
, pc_ast
.GtU
,
265 if isinstance(node
.op
, comparison
):
266 transient
= self
.transient(bits
="UINT8_C(1)")
268 transient
= self
.transient()
269 call
= self
.call(name
=str(self
[node
.op
]), code
=[
274 with self
.pseudocode(node
=node
):
275 for (level
, stmt
) in self
[call
]:
276 self
[node
].emit(stmt
=stmt
, level
=level
)
278 @pc_util.Hook(pc_ast
.UnaryExpr
)
279 def UnaryExpr(self
, node
):
281 if isinstance(node
.value
, pc_ast
.IfExpr
):
282 self
.fixup_ternary(node
=node
.value
)
283 transient
= self
.transient()
284 call
= self
.call(name
=str(self
[node
.op
]), code
=[
288 with self
.pseudocode(node
=node
):
289 for (level
, stmt
) in self
[call
]:
290 self
[node
].emit(stmt
=stmt
, level
=level
)
293 pc_ast
.Not
, pc_ast
.Add
, pc_ast
.Sub
,
294 pc_ast
.Mul
, pc_ast
.Div
, pc_ast
.Mod
,
295 pc_ast
.Lt
, pc_ast
.Le
,
296 pc_ast
.Eq
, pc_ast
.Ne
,
297 pc_ast
.Ge
, pc_ast
.Gt
,
298 pc_ast
.LtU
, pc_ast
.GtU
,
299 pc_ast
.LShift
, pc_ast
.RShift
,
300 pc_ast
.BitAnd
, pc_ast
.BitOr
, pc_ast
.BitXor
,
306 pc_ast
.Not
: "oppc_not",
307 pc_ast
.Add
: "oppc_add",
308 pc_ast
.Sub
: "oppc_sub",
309 pc_ast
.Mul
: "oppc_mul",
310 pc_ast
.Div
: "oppc_div",
311 pc_ast
.Mod
: "oppc_mod",
312 pc_ast
.Lt
: "oppc_lt",
313 pc_ast
.Le
: "oppc_le",
314 pc_ast
.Eq
: "oppc_eq",
315 pc_ast
.Ne
: "oppc_ne",
316 pc_ast
.LtU
: "oppc_ltu",
317 pc_ast
.GtU
: "oppc_gtu",
318 pc_ast
.Ge
: "oppc_ge",
319 pc_ast
.Gt
: "oppc_gt",
320 pc_ast
.LShift
: "oppc_lshift",
321 pc_ast
.RShift
: "oppc_rshift",
322 pc_ast
.BitAnd
: "oppc_and",
323 pc_ast
.BitOr
: "oppc_or",
324 pc_ast
.BitXor
: "oppc_xor",
325 pc_ast
.BitConcat
: "oppc_concat",
327 self
[node
].emit(stmt
=op
)
329 @pc_util.Hook(pc_ast
.StringLiteral
)
330 def StringLiteral(self
, node
):
332 escaped
= repr(str(node
))[1:-1]
333 self
[node
].emit(stmt
=f
"\"{escaped}\"")
335 @pc_util.Hook(pc_ast
.BinLiteral
, pc_ast
.DecLiteral
, pc_ast
.HexLiteral
)
336 def Integer(self
, node
):
340 if isinstance(node
, pc_ast
.BinLiteral
):
341 bits
= f
"UINT8_C({str(len(value[2:]))})"
342 value
= int(value
, 2)
343 elif isinstance(node
, pc_ast
.HexLiteral
):
344 bits
= f
"UINT8_C({str(len(value[2:]) * 4)})"
345 value
= int(value
, 16)
347 bits
= "(uint8_t)OPPC_XLEN"
350 if (value
> ((2**64) - 1)):
351 raise NotImplementedError()
352 value
= f
"UINT64_C({fmt(value)})"
353 transient
= self
.transient(value
=value
, bits
=bits
)
354 with self
.pseudocode(node
=node
):
355 for (level
, stmt
) in self
[transient
]:
356 self
[node
].emit(stmt
=stmt
, level
=level
)
358 @pc_util.Hook(Transient
)
359 def Transient(self
, node
):
361 self
[node
].emit(stmt
=str(node
))
364 def CCall(self
, node
):
366 end
= (";" if node
.stmt
else "")
367 if len(node
.code
) == 0:
368 self
[node
].emit(stmt
=f
"{str(node.name)}(){end}")
370 self
[node
].emit(stmt
=f
"{str(node.name)}(")
372 (*head
, tail
) = node
.code
374 for (level
, stmt
) in code
:
375 self
[node
].emit(stmt
=stmt
, level
=level
)
376 (level
, stmt
) = self
[node
][-1]
378 stmt
.startswith("/*") or
379 stmt
.endswith((",", "(", "{", "*/"))):
381 self
[node
][-1] = (level
, stmt
)
382 for (level
, stmt
) in tail
:
383 self
[node
].emit(stmt
=stmt
, level
=level
)
384 self
[node
].emit(stmt
=f
"){end}")
386 @pc_util.Hook(pc_ast
.GPR
)
389 with self
.pseudocode(node
=node
):
390 self
[node
].emit(stmt
=f
"OPPC_GPR_{str(node)}")
392 @pc_util.Hook(pc_ast
.GPRZero
)
393 def GPRZero(self
, node
):
396 test
= pc_ast
.Symbol(name
)
397 body
= pc_ast
.Scope([pc_ast
.GPR(name
)])
398 orelse
= pc_ast
.Scope([Transient()])
399 ifexpr
= pc_ast
.IfExpr(test
=test
, body
=body
, orelse
=orelse
)
400 self
.traverse(root
=ifexpr
)
401 self
.fixup_ternary(node
=ifexpr
)
402 for (level
, stmt
) in self
[ifexpr
]:
403 self
[node
].emit(stmt
=stmt
, level
=level
)
405 @pc_util.Hook(pc_ast
.FPR
)
408 with self
.pseudocode(node
=node
):
409 self
[node
].emit(stmt
=f
"OPPC_FPR_{str(node)}")
411 @pc_util.Hook(pc_ast
.RepeatExpr
)
412 def RepeatExpr(self
, node
):
414 transient
= self
.transient()
415 call
= self
.call(name
="oppc_repeat", code
=[
420 for (level
, stmt
) in self
[call
]:
421 self
[node
].emit(stmt
=stmt
, level
=level
)
423 @pc_util.Hook(pc_ast
.XLEN
)
424 def XLEN(self
, node
):
426 (value
, bits
) = ("OPPC_XLEN", "(uint8_t)OPPC_XLEN")
427 transient
= self
.transient(value
=value
, bits
=bits
)
428 with self
.pseudocode(node
=node
):
429 for (level
, stmt
) in self
[transient
]:
430 self
[node
].emit(stmt
=stmt
, level
=level
)
432 @pc_util.Hook(pc_ast
.Overflow
, pc_ast
.CR3
, pc_ast
.CR5
,
433 pc_ast
.XER
, pc_ast
.Reserve
, pc_ast
.Special
)
434 def Special(self
, node
):
436 with self
.pseudocode(node
=node
):
437 self
[node
].emit(stmt
=f
"OPPC_{str(node).upper()}")
439 @pc_util.Hook(pc_ast
.SubscriptExpr
)
440 def SubscriptExpr(self
, node
):
442 transient
= self
.transient(bits
="UINT8_C(1)")
443 call
= self
.call(name
="oppc_subscript", code
=[
448 for (level
, stmt
) in self
[call
]:
449 self
[node
].emit(stmt
=stmt
, level
=level
)
451 @pc_util.Hook(pc_ast
.RangeSubscriptExpr
)
452 def RangeSubscriptExpr(self
, node
):
454 transient
= self
.transient()
455 call
= self
.call(name
="oppc_range_subscript", code
=[
461 for (level
, stmt
) in self
[call
]:
462 self
[node
].emit(stmt
=stmt
, level
=level
)
464 @pc_util.Hook(pc_ast
.ForExpr
)
465 def ForExpr(self
, node
):
468 enter
= pc_ast
.AssignExpr(
469 lvalue
=node
.subject
.clone(),
470 rvalue
=node
.start
.clone(),
472 match
= pc_ast
.BinaryExpr(
473 left
=node
.subject
.clone(),
475 right
=node
.end
.clone(),
477 leave
= pc_ast
.AssignExpr(
478 lvalue
=node
.subject
.clone(),
479 rvalue
=pc_ast
.BinaryExpr(
480 left
=node
.subject
.clone(),
482 right
=node
.end
.clone(),
485 with self
.pseudocode(node
=node
):
486 (level
, stmt
) = self
[node
][0]
488 self
[node
].emit(stmt
=stmt
, level
=level
)
489 self
[node
].emit(stmt
="for (")
492 for subnode
in (enter
, match
, leave
):
493 self
.__pseudocode
.traverse(root
=subnode
)
494 self
.traverse(root
=subnode
)
495 for (level
, stmt
) in self
[subnode
]:
496 self
[node
].emit(stmt
=stmt
, level
=level
)
497 (level
, stmt
) = self
[node
][-1]
500 elif subnode
is leave
:
502 self
[node
][-1] = (level
, stmt
)
503 (level
, stmt
) = self
[node
][0]
504 self
[node
].emit(stmt
=stmt
, level
=level
)
505 self
[node
].emit(stmt
=") {")
506 for (level
, stmt
) in self
[node
.body
]:
507 self
[node
].emit(stmt
=stmt
, level
=level
)
508 self
[node
].emit(stmt
="}")
510 @pc_util.Hook(pc_ast
.WhileExpr
)
511 def WhileExpr(self
, node
):
513 self
[node
].emit(stmt
="while (")
516 for (level
, stmt
) in self
[node
.test
]:
517 self
[node
].emit(stmt
=stmt
, level
=level
)
518 self
[node
].emit(") {")
519 for (level
, stmt
) in self
[node
.body
]:
520 self
[node
].emit(stmt
=stmt
, level
=level
)
522 self
[node
].emit(stmt
="} else {")
523 for (level
, stmt
) in self
[node
.orelse
]:
524 self
[node
].emit(stmt
=stmt
, level
=level
)
525 self
[node
].emit(stmt
="}")
527 @pc_util.Hook(pc_ast
.IfExpr
)
528 def IfExpr(self
, node
):
530 test
= self
.call(name
="oppc_cast_bool", code
=[
533 self
[node
].emit(stmt
="if (")
535 for (level
, stmt
) in self
[test
]:
536 self
[node
].emit(stmt
=stmt
, level
=level
)
537 self
[node
].emit(stmt
=") {")
538 for (level
, stmt
) in self
[node
.body
]:
539 self
[node
].emit(stmt
=stmt
, level
=level
)
541 self
[node
].emit(stmt
="} else {")
542 for (level
, stmt
) in self
[node
.orelse
]:
543 self
[node
].emit(stmt
=stmt
, level
=level
)
544 self
[node
].emit(stmt
="}")
546 @pc_util.Hook(pc_ast
.SwitchExpr
)
547 def SwitchExpr(self
, node
):
549 subject
= self
.call(name
="oppc_cast_int64", code
=[
552 self
[node
].emit(stmt
="switch (")
554 for (level
, stmt
) in self
[subject
]:
555 self
[node
].emit(stmt
=stmt
, level
=level
)
556 self
[node
].emit(") {")
558 for (level
, stmt
) in self
[node
.cases
]:
559 self
[node
].emit(stmt
=stmt
, level
=level
)
561 @pc_util.Hook(pc_ast
.Cases
)
562 def Cases(self
, node
):
565 for (level
, stmt
) in self
[subnode
]:
566 self
[node
].emit(stmt
=stmt
, level
=level
)
568 @pc_util.Hook(pc_ast
.Case
)
569 def Case(self
, node
):
571 for (level
, stmt
) in self
[node
.labels
]:
572 self
[node
].emit(stmt
=stmt
, level
=level
)
573 for (level
, stmt
) in self
[node
.body
]:
574 self
[node
].emit(stmt
=stmt
, level
=level
)
576 @pc_util.Hook(pc_ast
.Labels
)
577 def Labels(self
, node
):
579 if ((len(node
) == 1) and isinstance(node
[-1], pc_ast
.DefaultLabel
)):
582 labels
= ", ".join(map(lambda label
: str(self
[label
]), node
))
583 stmt
= f
"case ({labels}):"
584 self
[node
].emit(stmt
=stmt
)
586 @pc_util.Hook(pc_ast
.Label
)
587 def Label(self
, node
):
589 self
[node
].emit(stmt
=str(node
))
591 @pc_util.Hook(pc_ast
.LeaveKeyword
)
592 def LeaveKeyword(self
, node
):
594 self
[node
].emit(stmt
="break;")
596 @pc_util.Hook(pc_ast
.Call
.Name
)
597 def CallName(self
, node
):
599 self
[node
].emit(stmt
=str(node
))
601 @pc_util.Hook(pc_ast
.Call
.Arguments
)
602 def CallArguments(self
, node
):
605 if isinstance(subnode
, (pc_ast
.GPR
, pc_ast
.FPR
)):
606 self
.__regfetch
[str(subnode
)].append(subnode
)
608 @pc_util.Hook(pc_ast
.Call
)
609 def Call(self
, node
):
612 transient
= self
.transient()
613 code
= [self
[transient
]]
616 code
.extend(map(lambda arg
: self
[arg
], node
.args
))
617 name
= f
"OPPC_CALL_{str(node.name)}"
618 with self
.pseudocode(node
=node
):
619 call
= self
.call(name
=name
, code
=code
)
620 for (level
, stmt
) in self
[call
]:
621 self
[node
].emit(stmt
=stmt
, level
=level
)
623 @pc_util.Hook(pc_ast
.Attribute
.Name
)
624 def AttributeName(self
, node
):
627 @pc_util.Hook(pc_ast
.Sequence
)
628 def Sequence(self
, node
):
631 @pc_util.Hook(pc_ast
.Attribute
)
632 def Attribute(self
, node
):
634 attr
= str(self
.__pseudocode
[node
])
635 symbol
= f
"OPPC_ATTR_{attr.replace('.', '_')}"
636 self
[node
].emit(f
"/* {attr} */")
637 self
[node
].emit(stmt
=symbol
)
639 @pc_util.Hook(pc_ast
.Symbol
)
640 def Symbol(self
, node
):
642 with self
.pseudocode(node
=node
):
644 if decl
not in ("fallthrough",):
645 if decl
in ("TRAP",):
646 self
[node
].emit(stmt
=f
"OPPC_CALL_{decl}();")
648 if node
in self
.__pseudocode
:
649 self
.__decls
.add(decl
)
650 self
[node
].emit(stmt
=f
"&{decl}")
652 @pc_util.Hook(Instruction
)
653 def Instruction(self
, node
):
655 self
[node
].emit("insn")
657 @pc_util.Hook(pc_ast
.Node
)
658 def Node(self
, node
):
659 raise NotImplementedError(type(node
))
662 def code(insn
, root
):
663 yield from CodeVisitor(insn
=insn
, root
=root
)