Browse Source

Make list_read, list_append intrinsics

jonathanvdc 8 years ago
parent
commit
cf3d887870
1 changed files with 70 additions and 3 deletions
  1. 70 3
      kernel/modelverse_jit/intrinsics.py

+ 70 - 3
kernel/modelverse_jit/intrinsics.py

@@ -33,6 +33,13 @@ UNARY_INTRINSICS = {
     'float_neg' : '-'
 }
 
+def create_get_length(expression):
+    """Creates an expression that evaluates the given expression, and then
+       computes the length of its result."""
+    return tree_ir.CallInstruction(
+        tree_ir.LoadGlobalInstruction('len'),
+        [expression])
+
 # Don't compain about the variable names, pylint. It's important that we
 # get them right.
 # pylint: disable=I0011,C0103
@@ -54,6 +61,65 @@ def __dict_add(a, b, c):
             b_tmp.create_load()),
         a_tmp.create_load())
 
+def __list_read(a, b):
+    # The statements in this function generate the following code:
+    #
+    # a_tmp = a # To make sure a is evaluated before b.
+    # b_value, = yield [("RV", [b])]
+    # result, = yield [("RD", [a_tmp, b_value])]
+    # if result is None:
+    #     raise Exception("List read out of bounds: %s" % b_value)
+    # result
+
+    a_tmp = tree_ir.StoreLocalInstruction(None, a)
+    b_val = tree_ir.StoreLocalInstruction(
+        None,
+        tree_ir.ReadValueInstruction(b))
+    result = tree_ir.StoreLocalInstruction(
+        None,
+        tree_ir.ReadDictionaryValueInstruction(
+            a_tmp.create_load(), b_val.create_load()))
+
+    return tree_ir.create_block(
+        a_tmp,
+        b_val,
+        result,
+        tree_ir.SelectInstruction(
+            tree_ir.BinaryInstruction(
+                result.create_load(),
+                'is',
+                tree_ir.LiteralInstruction(None)),
+            tree_ir.RaiseInstruction(
+                tree_ir.CallInstruction(
+                    tree_ir.LoadGlobalInstruction('Exception'),
+                    [tree_ir.BinaryInstruction(
+                        tree_ir.LiteralInstruction('List read out of bounds: %s'),
+                        '%',
+                        b_val.create_load())])),
+            tree_ir.NopInstruction()),
+        result.create_load())
+
+def __list_append(a, b):
+    # We want to generate code that is more or less equivalent to:
+    #
+    # a_tmp = a
+    # b_tmp = b
+    # a_outgoing, = yield [("RO", [a_tmp])]
+    # _ = yield [("CD", [a_tmp, len(a_outgoing), b_tmp])]
+    # a
+
+    a_tmp = tree_ir.StoreLocalInstruction(None, a)
+    b_tmp = tree_ir.StoreLocalInstruction(None, b)
+    return tree_ir.create_block(
+        a_tmp,
+        tree_ir.CreateDictionaryEdgeInstruction(
+            a_tmp.create_load(),
+            create_get_length(
+                tree_ir.ReadOutgoingEdgesInstruction(
+                    a_tmp.create_load())),
+            b_tmp),
+        a_tmp.create_load())
+
 MISC_INTRINSICS = {
     # Reference equality
     'element_eq' :
@@ -159,9 +225,10 @@ MISC_INTRINSICS = {
     'list_len' :
         lambda a:
         tree_ir.CreateNodeWithValueInstruction(
-            tree_ir.CallInstruction(
-                tree_ir.LoadGlobalInstruction('len'),
-                [tree_ir.ReadOutgoingEdgesInstruction(a)]))
+            create_get_length(tree_ir.ReadOutgoingEdgesInstruction(a))),
+
+    'list_read' : __list_read,
+    'list_append' : __list_append
 }
 
 def register_intrinsics(target_jit):