oppc/code: emit only function body
[openpower-isa.git] / src / openpower / oppc / pc_code.py
index 67d4f42feba24e743f08b1fc10b88d9ca04f6a24..d490a85dbc3019d921c7b6307e5b7a1f33e69c92 100644 (file)
 import collections
+import contextlib
 
 import openpower.oppc.pc_ast as pc_ast
 import openpower.oppc.pc_util as pc_util
+import openpower.oppc.pc_pseudocode as pc_pseudocode
+
+
+class Transient(pc_ast.Node):
+    def __init__(self, value="UINT64_C(0)", bits="(uint8_t)OPPC_XLEN"):
+        self.__value = value
+        self.__bits = bits
+
+        return super().__init__()
+
+    def __repr__(self):
+        return f"{hex(id(self))}@{self.__class__.__name__}({self.__value}, {self.__bits})"
+
+    def __str__(self):
+        return f"oppc_transient(&(struct oppc_value){{}}, {self.__value}, {self.__bits})"
+
+
+class Call(pc_ast.Dataclass):
+    name: str
+    code: tuple
+    stmt: bool
+
+
+class Instruction(pc_ast.Node):
+    pass
 
 
 class CodeVisitor(pc_util.Visitor):
-    def __init__(self, name, root):
+    def __init__(self, insn, root):
+        if not isinstance(root, pc_ast.Scope):
+            raise ValueError(root)
+
         self.__root = root
+        self.__insn = insn
+        self.__decls = set()
         self.__header = object()
         self.__footer = object()
         self.__code = collections.defaultdict(lambda: pc_util.Code())
-        self.__decls = collections.defaultdict(list)
         self.__regfetch = collections.defaultdict(list)
         self.__regstore = collections.defaultdict(list)
+        self.__pseudocode = pc_pseudocode.PseudocodeVisitor(root=root)
 
         super().__init__(root=root)
 
-        self.__code[self.__header].emit("void")
-        self.__code[self.__header].emit(f"oppc_{name}(void) {{")
-        with self.__code[self.__header]:
-            for decl in self.__decls:
-                self.__code[self.__header].emit(f"uint64_t {decl};")
-        self.__code[self.__footer].emit(f"}}")
+        for decl in self.__decls:
+            self.__code[self.__header].emit(stmt=f"struct oppc_value {decl};")
+        decls = sorted(filter(lambda decl: decl in insn.fields, self.__decls))
+        if decls:
+            self.__code[self.__header].emit()
+        for decl in decls:
+            bits = f"{len(insn.fields[decl])}"
+            transient = Transient(bits=bits)
+            symbol = pc_ast.Symbol(decl)
+            assign = pc_ast.AssignExpr(lvalue=symbol, rvalue=transient)
+            self.traverse(root=assign)
+            for (level, stmt) in self[assign]:
+                self[self.__header].emit(stmt=stmt, level=level)
+            for (lbit, rbit) in enumerate(insn.fields[decl]):
+                lsymbol = pc_ast.Symbol(decl)
+                rsymbol = Instruction()
+                lindex = Transient(value=str(lbit))
+                rindex = Transient(value=str(rbit))
+                lvalue = pc_ast.SubscriptExpr(index=lindex, subject=lsymbol)
+                rvalue = pc_ast.SubscriptExpr(index=rindex, subject=rsymbol)
+                assign = pc_ast.AssignExpr(lvalue=lvalue, rvalue=rvalue)
+                self.traverse(root=assign)
+                for (level, stmt) in self[assign]:
+                    self[self.__header].emit(stmt=stmt, level=level)
+            self.__code[self.__header].emit()
+        if decls:
+            self.__code[self.__header].emit()
 
     def __iter__(self):
-        yield from self.__code[self.__header]
-        yield from self.__code[self.__root]
-        yield from self.__code[self.__footer]
+        yield from self[self.__header]
+        for (level, stmt) in self[self.__root]:
+            yield ((level - 1), stmt)
+        yield from self[self.__footer]
 
     def __getitem__(self, node):
         return self.__code[node]
 
+    def __setitem__(self, node, code):
+        self.__code[node] = code
+
+    def transient(self,
+            value="UINT64_C(0)",
+            bits="(uint8_t)OPPC_XLEN"):
+        transient = Transient(value=value, bits=bits)
+        self.traverse(root=transient)
+        return transient
+
+    def call(self, name, code, stmt=False):
+        def validate(item):
+            def validate(item):
+                (level, stmt) = item
+                if not isinstance(level, int):
+                    raise ValueError(level)
+                if not isinstance(stmt, str):
+                    raise ValueError(stmt)
+                return (level, stmt)
+
+            return tuple(map(validate, item))
+
+        code = tuple(map(validate, code))
+        call = Call(name=name, code=code, stmt=stmt)
+        self.traverse(root=call)
+        return call
+
+    def fixup_ternary(self, node):
+        self[node].clear()
+        test = self.call(name="oppc_cast_bool", code=[
+            self[node.test],
+        ])
+        self[node].emit(stmt="(")
+        with self[node]:
+            for (level, stmt) in self[test]:
+                self[node].emit(stmt=stmt, level=level)
+            self[node].emit(stmt="?")
+            for (level, stmt) in self[node.body]:
+                self[node].emit(stmt=stmt, level=level)
+            self[node].emit(stmt=":")
+            for (level, stmt) in self[node.orelse]:
+                self[node].emit(stmt=stmt, level=level)
+        self[node].emit(stmt=")")
+
+    def fixup_attr(self, node, assign=False):
+        root = node
+        code = tuple(self[root])
+        attribute_or_subscript = (
+            pc_ast.Attribute,
+            pc_ast.SubscriptExpr,
+            pc_ast.RangeSubscriptExpr,
+        )
+        while isinstance(node.subject, attribute_or_subscript):
+            node = node.subject
+
+        def wrap(code):
+            def wrap(item):
+                (level, stmt) = item
+                if not (not stmt or
+                        stmt.startswith("/*") or
+                        stmt.endswith((",", "(", "{", "*/"))):
+                    stmt = (stmt + ",")
+                return (level, stmt)
+
+            return tuple(map(wrap, code))
+
+        code = pc_util.Code()
+        for (level, stmt) in wrap(self[node.subject]):
+            code.emit(stmt=stmt, level=level)
+        for (level, stmt) in wrap(self[root]):
+            code.emit(stmt=stmt, level=level)
+
+        # discard the last comma
+        (level, stmt) = code[-1]
+        code[-1] = (level, stmt[:-1])
+
+        if not assign:
+            call = self.call(name="oppc_attr", code=[
+                code,
+            ])
+            code = self[call]
+        self[root] = code
+
+    @contextlib.contextmanager
+    def pseudocode(self, node):
+        if node in self.__pseudocode:
+            for (level, stmt) in self.__pseudocode[node]:
+                self[node].emit(stmt=f"/* {stmt} */", level=level)
+        yield
+
     @pc_util.Hook(pc_ast.Scope)
     def Scope(self, node):
         yield node
@@ -47,12 +190,54 @@ class CodeVisitor(pc_util.Visitor):
         if isinstance(node.rvalue, (pc_ast.GPR, pc_ast.FPR)):
             self.__regfetch[str(node.rvalue)].append(node.rvalue)
 
-        stmt = " ".join([
-            str(self[node.lvalue]),
-            "=",
-            str(self[node.rvalue]),
-        ])
-        self[node].emit(stmt=f"{stmt};")
+        if isinstance(node.rvalue, pc_ast.IfExpr):
+            self.fixup_ternary(node=node.rvalue)
+        if isinstance(node.lvalue, pc_ast.Attribute):
+            self.fixup_attr(node=node.lvalue, assign=True)
+        if isinstance(node.rvalue, pc_ast.Attribute):
+            self.fixup_attr(node=node.rvalue)
+
+        if isinstance(node.lvalue, pc_ast.Sequence):
+            if not isinstance(node.rvalue, pc_ast.Sequence):
+                raise ValueError(node.rvalue)
+            if len(node.lvalue) != len(node.rvalue):
+                raise ValueError(node)
+            for (lvalue, rvalue) in zip(node.lvalue, node.rvalue):
+                assign = node.__class__(
+                    lvalue=lvalue.clone(),
+                    rvalue=rvalue.clone(),
+                )
+                self.traverse(root=assign)
+                for (level, stmt) in self[assign]:
+                    self[node].emit(stmt=stmt, level=level)
+            return
+
+        if isinstance(node.lvalue, pc_ast.SubscriptExpr):
+            call = self.call(name="oppc_subscript_assign", stmt=True, code=[
+                self[node.lvalue.subject],
+                self[node.lvalue.index],
+                self[node.rvalue],
+            ])
+        elif isinstance(node.lvalue, pc_ast.RangeSubscriptExpr):
+            call = self.call(name="oppc_range_subscript_assign", stmt=True, code=[
+                self[node.lvalue.subject],
+                self[node.lvalue.start],
+                self[node.lvalue.end],
+                self[node.rvalue],
+            ])
+        elif isinstance(node.lvalue, pc_ast.Attribute):
+            call = self.call(name="oppc_attr_assign", stmt=True, code=[
+                self[node.lvalue],
+                self[node.rvalue],
+            ])
+        else:
+            call = self.call(name="oppc_assign", stmt=True, code=[
+                self[node.lvalue],
+                self[node.rvalue],
+            ])
+        with self.pseudocode(node=node):
+            for (level, stmt) in self[call]:
+                self[node].emit(stmt=stmt, level=level)
 
     @pc_util.Hook(pc_ast.BinaryExpr)
     def BinaryExpr(self, node):
@@ -61,101 +246,357 @@ class CodeVisitor(pc_util.Visitor):
             self.__regfetch[str(node.left)].append(node.left)
         if isinstance(node.right, (pc_ast.GPR, pc_ast.FPR)):
             self.__regfetch[str(node.right)].append(node.left)
-        special = (
-            pc_ast.MulS,
-            pc_ast.MulU,
-            pc_ast.DivT,
-            pc_ast.Sqrt,
-            pc_ast.BitConcat
+
+        if isinstance(node.left, pc_ast.IfExpr):
+            self.fixup_ternary(node=node.left)
+        if isinstance(node.right, pc_ast.IfExpr):
+            self.fixup_ternary(node=node.right)
+        if isinstance(node.left, pc_ast.Attribute):
+            self.fixup_attr(node=node.left)
+        if isinstance(node.right, pc_ast.Attribute):
+            self.fixup_attr(node=node.right)
+
+        comparison = (
+            pc_ast.Lt, pc_ast.Le,
+            pc_ast.Eq, pc_ast.Ne,
+            pc_ast.Ge, pc_ast.Gt,
+            pc_ast.LtU, pc_ast.GtU,
         )
-        if isinstance(node.op, special):
-            raise NotImplementedError(node)
-        stmt = " ".join([
-            str(self[node.left]),
-            str(self[node.op]),
-            str(self[node.right]),
+        if isinstance(node.op, comparison):
+            transient = self.transient(bits="UINT8_C(1)")
+        else:
+            transient = self.transient()
+        call = self.call(name=str(self[node.op]), code=[
+            self[transient],
+            self[node.left],
+            self[node.right],
         ])
-        self[node].emit(stmt=f"({stmt})")
+        with self.pseudocode(node=node):
+            for (level, stmt) in self[call]:
+                self[node].emit(stmt=stmt, level=level)
 
     @pc_util.Hook(pc_ast.UnaryExpr)
     def UnaryExpr(self, node):
         yield node
-        stmt = "".join([
-            str(self[node.op]),
-            f"({str(self[node.value])})",
+        if isinstance(node.value, pc_ast.IfExpr):
+            self.fixup_ternary(node=node.value)
+        transient = self.transient()
+        call = self.call(name=str(self[node.op]), code=[
+            self[transient],
+            self[node.value],
         ])
-        self[node].emit(stmt=stmt)
+        with self.pseudocode(node=node):
+            for (level, stmt) in self[call]:
+                self[node].emit(stmt=stmt, level=level)
 
     @pc_util.Hook(
             pc_ast.Not, pc_ast.Add, pc_ast.Sub,
             pc_ast.Mul, pc_ast.Div, pc_ast.Mod,
             pc_ast.Lt, pc_ast.Le,
-            pc_ast.Eq, pc_ast.NotEq,
+            pc_ast.Eq, pc_ast.Ne,
             pc_ast.Ge, pc_ast.Gt,
+            pc_ast.LtU, pc_ast.GtU,
             pc_ast.LShift, pc_ast.RShift,
             pc_ast.BitAnd, pc_ast.BitOr, pc_ast.BitXor,
+            pc_ast.BitConcat,
         )
     def Op(self, node):
         yield node
         op = {
-            pc_ast.Not: "~",
-            pc_ast.Add: "+",
-            pc_ast.Sub: "-",
-            pc_ast.Mul: "*",
-            pc_ast.Div: "/",
-            pc_ast.Mod: "%",
-            pc_ast.Lt: "<",
-            pc_ast.Le: "<=",
-            pc_ast.Eq: "==",
-            pc_ast.NotEq: "!=",
-            pc_ast.Ge: ">=",
-            pc_ast.Gt: ">",
-            pc_ast.LShift: "<<",
-            pc_ast.RShift: "<<",
-            pc_ast.BitAnd: "&",
-            pc_ast.BitOr: "|",
-            pc_ast.BitXor: "^",
+            pc_ast.Not: "oppc_not",
+            pc_ast.Add: "oppc_add",
+            pc_ast.Sub: "oppc_sub",
+            pc_ast.Mul: "oppc_mul",
+            pc_ast.Div: "oppc_div",
+            pc_ast.Mod: "oppc_mod",
+            pc_ast.Lt: "oppc_lt",
+            pc_ast.Le: "oppc_le",
+            pc_ast.Eq: "oppc_eq",
+            pc_ast.Ne: "oppc_ne",
+            pc_ast.LtU: "oppc_ltu",
+            pc_ast.GtU: "oppc_gtu",
+            pc_ast.Ge: "oppc_ge",
+            pc_ast.Gt: "oppc_gt",
+            pc_ast.LShift: "oppc_lshift",
+            pc_ast.RShift: "oppc_rshift",
+            pc_ast.BitAnd: "oppc_and",
+            pc_ast.BitOr: "oppc_or",
+            pc_ast.BitXor: "oppc_xor",
+            pc_ast.BitConcat: "oppc_concat",
         }[node.__class__]
         self[node].emit(stmt=op)
 
+    @pc_util.Hook(pc_ast.StringLiteral)
+    def StringLiteral(self, node):
+        yield node
+        escaped = repr(str(node))[1:-1]
+        self[node].emit(stmt=f"\"{escaped}\"")
+
     @pc_util.Hook(pc_ast.BinLiteral, pc_ast.DecLiteral, pc_ast.HexLiteral)
     def Integer(self, node):
         yield node
+        fmt = hex
+        value = str(node)
         if isinstance(node, pc_ast.BinLiteral):
-            base = 2
-        elif isinstance(node, pc_ast.DecLiteral):
-            base = 10
+            bits = f"UINT8_C({str(len(value[2:]))})"
+            value = int(value, 2)
         elif isinstance(node, pc_ast.HexLiteral):
-            base = 16
+            bits = f"UINT8_C({str(len(value[2:]) * 4)})"
+            value = int(value, 16)
         else:
-            raise ValueError(node)
-        self[node].emit(stmt=f"UINT64_C({hex(int(node, base))})")
+            bits = "(uint8_t)OPPC_XLEN"
+            value = int(value)
+            fmt = str
+        if (value > ((2**64) - 1)):
+            raise NotImplementedError()
+        value = f"UINT64_C({fmt(value)})"
+        transient = self.transient(value=value, bits=bits)
+        with self.pseudocode(node=node):
+            for (level, stmt) in self[transient]:
+                self[node].emit(stmt=stmt, level=level)
+
+    @pc_util.Hook(Transient)
+    def Transient(self, node):
+        yield node
+        self[node].emit(stmt=str(node))
+
+    @pc_util.Hook(Call)
+    def CCall(self, node):
+        yield node
+        end = (";" if node.stmt else "")
+        if len(node.code) == 0:
+            self[node].emit(stmt=f"{str(node.name)}(){end}")
+        else:
+            self[node].emit(stmt=f"{str(node.name)}(")
+            with self[node]:
+                (*head, tail) = node.code
+                for code in head:
+                    for (level, stmt) in code:
+                        self[node].emit(stmt=stmt, level=level)
+                    (level, stmt) = self[node][-1]
+                    if not (not stmt or
+                            stmt.startswith("/*") or
+                            stmt.endswith((",", "(", "{", "*/"))):
+                        stmt = (stmt + ",")
+                    self[node][-1] = (level, stmt)
+                for (level, stmt) in tail:
+                    self[node].emit(stmt=stmt, level=level)
+            self[node].emit(stmt=f"){end}")
 
     @pc_util.Hook(pc_ast.GPR)
     def GPR(self, node):
         yield node
-        self[node].emit(stmt=f"ctx->gpr[OPPC_GPR_{str(node)}]")
+        with self.pseudocode(node=node):
+            self[node].emit(stmt=f"OPPC_GPR_{str(node)}")
+
+    @pc_util.Hook(pc_ast.GPRZero)
+    def GPRZero(self, node):
+        yield node
+        name = str(node)
+        test = pc_ast.Symbol(name)
+        body = pc_ast.Scope([pc_ast.GPR(name)])
+        orelse = pc_ast.Scope([Transient()])
+        ifexpr = pc_ast.IfExpr(test=test, body=body, orelse=orelse)
+        self.traverse(root=ifexpr)
+        self.fixup_ternary(node=ifexpr)
+        for (level, stmt) in self[ifexpr]:
+            self[node].emit(stmt=stmt, level=level)
 
     @pc_util.Hook(pc_ast.FPR)
     def FPR(self, node):
         yield node
-        self[node].emit(stmt=f"ctx->fpr[OPPC_FPR_{str(node)}]")
+        with self.pseudocode(node=node):
+            self[node].emit(stmt=f"OPPC_FPR_{str(node)}")
 
     @pc_util.Hook(pc_ast.RepeatExpr)
     def RepeatExpr(self, node):
         yield node
-        subject = str(self[node.subject])
-        times = str(self[node.times])
-        self[node].emit(f"oppc_repeat({subject}, {times})")
+        transient = self.transient()
+        call = self.call(name="oppc_repeat", code=[
+            self[transient],
+            self[node.subject],
+            self[node.times],
+        ])
+        for (level, stmt) in self[call]:
+            self[node].emit(stmt=stmt, level=level)
 
     @pc_util.Hook(pc_ast.XLEN)
     def XLEN(self, node):
         yield node
-        self[node].emit(f"ctx->XLEN")
+        (value, bits) = ("OPPC_XLEN", "(uint8_t)OPPC_XLEN")
+        transient = self.transient(value=value, bits=bits)
+        with self.pseudocode(node=node):
+            for (level, stmt) in self[transient]:
+                self[node].emit(stmt=stmt, level=level)
+
+    @pc_util.Hook(pc_ast.Overflow, pc_ast.CR3, pc_ast.CR5,
+            pc_ast.XER, pc_ast.Reserve, pc_ast.Special)
+    def Special(self, node):
+        yield node
+        with self.pseudocode(node=node):
+            self[node].emit(stmt=f"OPPC_{str(node).upper()}")
+
+    @pc_util.Hook(pc_ast.SubscriptExpr)
+    def SubscriptExpr(self, node):
+        yield node
+        transient = self.transient(bits="UINT8_C(1)")
+        call = self.call(name="oppc_subscript", code=[
+            self[transient],
+            self[node.subject],
+            self[node.index],
+        ])
+        for (level, stmt) in self[call]:
+            self[node].emit(stmt=stmt, level=level)
+
+    @pc_util.Hook(pc_ast.RangeSubscriptExpr)
+    def RangeSubscriptExpr(self, node):
+        yield node
+        transient = self.transient()
+        call = self.call(name="oppc_range_subscript", code=[
+            self[transient],
+            self[node.subject],
+            self[node.start],
+            self[node.end],
+        ])
+        for (level, stmt) in self[call]:
+            self[node].emit(stmt=stmt, level=level)
+
+    @pc_util.Hook(pc_ast.ForExpr)
+    def ForExpr(self, node):
+        yield node
+
+        enter = pc_ast.AssignExpr(
+            lvalue=node.subject.clone(),
+            rvalue=node.start.clone(),
+        )
+        match = pc_ast.BinaryExpr(
+            left=node.subject.clone(),
+            op=pc_ast.Le("<="),
+            right=node.end.clone(),
+        )
+        leave = pc_ast.AssignExpr(
+            lvalue=node.subject.clone(),
+            rvalue=pc_ast.BinaryExpr(
+                left=node.subject.clone(),
+                op=pc_ast.Add("+"),
+                right=node.end.clone(),
+            ),
+        )
+        with self.pseudocode(node=node):
+            (level, stmt) = self[node][0]
+        self[node].clear()
+        self[node].emit(stmt=stmt, level=level)
+        self[node].emit(stmt="for (")
+        with self[node]:
+            with self[node]:
+                for subnode in (enter, match, leave):
+                    self.__pseudocode.traverse(root=subnode)
+                    self.traverse(root=subnode)
+                    for (level, stmt) in self[subnode]:
+                        self[node].emit(stmt=stmt, level=level)
+                    (level, stmt) = self[node][-1]
+                    if subnode is match:
+                        stmt = f"{stmt};"
+                    elif subnode is leave:
+                        stmt = stmt[:-1]
+                    self[node][-1] = (level, stmt)
+        (level, stmt) = self[node][0]
+        self[node].emit(stmt=stmt, level=level)
+        self[node].emit(stmt=") {")
+        for (level, stmt) in self[node.body]:
+            self[node].emit(stmt=stmt, level=level)
+        self[node].emit(stmt="}")
+
+    @pc_util.Hook(pc_ast.WhileExpr)
+    def WhileExpr(self, node):
+        yield node
+        self[node].emit(stmt="while (")
+        with self[node]:
+            with self[node]:
+                for (level, stmt) in self[node.test]:
+                    self[node].emit(stmt=stmt, level=level)
+        self[node].emit(") {")
+        for (level, stmt) in self[node.body]:
+            self[node].emit(stmt=stmt, level=level)
+        if node.orelse:
+            self[node].emit(stmt="} else {")
+            for (level, stmt) in self[node.orelse]:
+                self[node].emit(stmt=stmt, level=level)
+        self[node].emit(stmt="}")
+
+    @pc_util.Hook(pc_ast.IfExpr)
+    def IfExpr(self, node):
+        yield node
+        test = self.call(name="oppc_cast_bool", code=[
+            self[node.test],
+        ])
+        self[node].emit(stmt="if (")
+        with self[node]:
+            for (level, stmt) in self[test]:
+                self[node].emit(stmt=stmt, level=level)
+        self[node].emit(stmt=") {")
+        for (level, stmt) in self[node.body]:
+            self[node].emit(stmt=stmt, level=level)
+        if node.orelse:
+            self[node].emit(stmt="} else {")
+            for (level, stmt) in self[node.orelse]:
+                self[node].emit(stmt=stmt, level=level)
+        self[node].emit(stmt="}")
+
+    @pc_util.Hook(pc_ast.SwitchExpr)
+    def SwitchExpr(self, node):
+        yield node
+        subject = self.call(name="oppc_cast_int64", code=[
+            self[node.subject],
+        ])
+        self[node].emit(stmt="switch (")
+        with self[node]:
+            for (level, stmt) in self[subject]:
+                self[node].emit(stmt=stmt, level=level)
+        self[node].emit(") {")
+        with self[node]:
+            for (level, stmt) in self[node.cases]:
+                self[node].emit(stmt=stmt, level=level)
+
+    @pc_util.Hook(pc_ast.Cases)
+    def Cases(self, node):
+        yield node
+        for subnode in node:
+            for (level, stmt) in self[subnode]:
+                self[node].emit(stmt=stmt, level=level)
+
+    @pc_util.Hook(pc_ast.Case)
+    def Case(self, node):
+        yield node
+        for (level, stmt) in self[node.labels]:
+            self[node].emit(stmt=stmt, level=level)
+        for (level, stmt) in self[node.body]:
+            self[node].emit(stmt=stmt, level=level)
+
+    @pc_util.Hook(pc_ast.Labels)
+    def Labels(self, node):
+        yield node
+        if ((len(node) == 1) and isinstance(node[-1], pc_ast.DefaultLabel)):
+            stmt = "default:"
+        else:
+            labels = ", ".join(map(lambda label: str(self[label]), node))
+            stmt = f"case ({labels}):"
+        self[node].emit(stmt=stmt)
+
+    @pc_util.Hook(pc_ast.Label)
+    def Label(self, node):
+        yield node
+        self[node].emit(stmt=str(node))
+
+    @pc_util.Hook(pc_ast.LeaveKeyword)
+    def LeaveKeyword(self, node):
+        yield node
+        self[node].emit(stmt="break;")
 
     @pc_util.Hook(pc_ast.Call.Name)
     def CallName(self, node):
         yield node
+        self[node].emit(stmt=str(node))
 
     @pc_util.Hook(pc_ast.Call.Arguments)
     def CallArguments(self, node):
@@ -164,16 +605,59 @@ class CodeVisitor(pc_util.Visitor):
             if isinstance(subnode, (pc_ast.GPR, pc_ast.FPR)):
                 self.__regfetch[str(subnode)].append(subnode)
 
+    @pc_util.Hook(pc_ast.Call)
+    def Call(self, node):
+        yield node
+        if node.args:
+            transient = self.transient()
+            code = [self[transient]]
+        else:
+            code = []
+        code.extend(map(lambda arg: self[arg], node.args))
+        name = f"OPPC_CALL_{str(node.name)}"
+        with self.pseudocode(node=node):
+            call = self.call(name=name, code=code)
+            for (level, stmt) in self[call]:
+                self[node].emit(stmt=stmt, level=level)
+
+    @pc_util.Hook(pc_ast.Attribute.Name)
+    def AttributeName(self, node):
+        yield node
+
+    @pc_util.Hook(pc_ast.Sequence)
+    def Sequence(self, node):
+        yield node
+
+    @pc_util.Hook(pc_ast.Attribute)
+    def Attribute(self, node):
+        yield node
+        attr = str(self.__pseudocode[node])
+        symbol = f"OPPC_ATTR_{attr.replace('.', '_')}"
+        self[node].emit(f"/* {attr} */")
+        self[node].emit(stmt=symbol)
+
     @pc_util.Hook(pc_ast.Symbol)
     def Symbol(self, node):
         yield node
-        self.__decls[str(node)].append(node)
-        self[node].emit(stmt=str(node))
+        with self.pseudocode(node=node):
+            decl = str(node)
+            if decl not in ("fallthrough",):
+                if decl in ("TRAP",):
+                    self[node].emit(stmt=f"OPPC_CALL_{decl}();")
+                else:
+                    if node in self.__pseudocode:
+                        self.__decls.add(decl)
+                    self[node].emit(stmt=f"&{decl}")
+
+    @pc_util.Hook(Instruction)
+    def Instruction(self, node):
+        yield node
+        self[node].emit("insn")
 
     @pc_util.Hook(pc_ast.Node)
     def Node(self, node):
         raise NotImplementedError(type(node))
 
 
-def code(name, root):
-    yield from CodeVisitor(name=name, root=root)
+def code(insn, root):
+    yield from CodeVisitor(insn=insn, root=root)