oppc: support attributes
authorDmitry Selyutin <ghostmansd@gmail.com>
Sun, 14 Jan 2024 18:12:03 +0000 (21:12 +0300)
committerDmitry Selyutin <ghostmansd@gmail.com>
Tue, 16 Jan 2024 19:10:07 +0000 (22:10 +0300)
src/openpower/oppc/pc_code.py

index d7cdeef5ee8fcbc9ee7844215f517f35531f35c9..107099fac84ad2302a5673f3346d8bfeafeef52e 100644 (file)
@@ -26,6 +26,7 @@ class Call(pc_ast.Dataclass):
 class CodeVisitor(pc_util.Visitor):
     def __init__(self, name, root):
         self.__root = root
+        self.__attrs = {}
         self.__header = object()
         self.__footer = object()
         self.__code = collections.defaultdict(lambda: pc_util.Code())
@@ -51,6 +52,9 @@ class CodeVisitor(pc_util.Visitor):
     def __getitem__(self, node):
         return self.__code[node]
 
+    def __setitem__(self, node, code):
+        self.__code[node] = code
+
     def transient(self, node,
             value="UINT64_C(0)",
             bits="(uint8_t)OPPC_XLEN"):
@@ -75,7 +79,7 @@ class CodeVisitor(pc_util.Visitor):
         self.traverse(root=call)
         return call
 
-    def ternary(self, node):
+    def fixup_ternary(self, node):
         self[node].clear()
         test = self.call(name="oppc_bool", node=node, code=[
             self[node.test],
@@ -92,6 +96,45 @@ class CodeVisitor(pc_util.Visitor):
                 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", node=root, code=[
+                code,
+            ])
+            code = self[call]
+        self[root] = code
+
     @contextlib.contextmanager
     def pseudocode(self, node):
         for (level, stmt) in self.__pseudocode[node]:
@@ -115,7 +158,11 @@ class CodeVisitor(pc_util.Visitor):
             self.__regfetch[str(node.rvalue)].append(node.rvalue)
 
         if isinstance(node.rvalue, pc_ast.IfExpr):
-            self.ternary(node=node.rvalue)
+            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.SubscriptExpr):
             call = self.call(name="oppc_subscript_assign", node=node, stmt=True, code=[
@@ -130,6 +177,11 @@ class CodeVisitor(pc_util.Visitor):
                 self[node.lvalue.end],
                 self[node.rvalue],
             ])
+        elif isinstance(node.lvalue, pc_ast.Attribute):
+            call = self.call(name="oppc_attr_assign", stmt=True, node=node, code=[
+                self[node.lvalue],
+                self[node.rvalue],
+            ])
         else:
             call = self.call(name="oppc_assign", stmt=True, node=node, code=[
                 self[node.lvalue],
@@ -154,9 +206,13 @@ class CodeVisitor(pc_util.Visitor):
             pc_ast.LtU, pc_ast.GtU,
         )
         if isinstance(node.left, pc_ast.IfExpr):
-            self.ternary(node=node.left)
+            self.fixup_ternary(node=node.left)
         if isinstance(node.right, pc_ast.IfExpr):
-            self.ternary(node=node.right)
+            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)
 
         if isinstance(node.op, comparison):
             call = self.call(name=str(self[node.op]), node=node, code=[
@@ -178,7 +234,7 @@ class CodeVisitor(pc_util.Visitor):
     def UnaryExpr(self, node):
         yield node
         if isinstance(node.value, pc_ast.IfExpr):
-            self.ternary(node=node.value)
+            self.fixup_ternary(node=node.value)
         call = self.call(name=str(self[node.op]), node=node, code=[
             self[node.value],
         ])
@@ -487,6 +543,19 @@ class CodeVisitor(pc_util.Visitor):
         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.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)
+        self.__attrs[node] = symbol
+
     @pc_util.Hook(pc_ast.Symbol)
     def Symbol(self, node):
         yield node