Jelajahi Sumber

Scalar array initialisation now supports non-constant values, which are evaluated only once

Taddeus Kroes 12 tahun lalu
induk
melakukan
60a3a48b60
4 mengubah file dengan 143 tambahan dan 17 penghapusan
  1. 2 0
      README.md
  2. 56 17
      phases/desug.ml
  3. 73 0
      test/array_single_eval.cvc
  4. 12 0
      test/array_single_eval.out

+ 2 - 0
README.md

@@ -12,3 +12,5 @@ Issues & TODO
 - Documentation for each phase, in ocamldoc format.
 - Create automated testsuite runner.
 - Assembly printer should print optimized instructions.
+- Erronous array initialisation needs more insightfull error messages and array
+  assignment needs better better type checking.

+ 56 - 17
phases/desug.ml

@@ -2,8 +2,8 @@ open Printf
 open Types
 open Util
 
-(* Create new constant variables for all ArrayConst values so that they are only
- * evaluated once *)
+(* Create new constant variables for all assigned array values so that they are
+ * only evaluated once *)
 let rec consts_to_vars node =
     let rec create_vars new_vars values = function
         | [] -> (new_vars, values)
@@ -19,7 +19,8 @@ let rec consts_to_vars node =
             create_vars new_vars (values @ [value]) tl
     in
     match node with
-    | VarDec (ctype, name, Some (ArrayConst (values, vann)), ann) ->
+    (* Add vardecs for values in arrayconst *)
+    | VarDec (ArrayDims _ as ctype, name, Some (ArrayConst (values, vann)), ann) ->
         let (new_vars, values) = create_vars [] [] values in
         let value = ArrayConst (values, vann) in
         let create_vardec (name, value) =
@@ -28,6 +29,14 @@ let rec consts_to_vars node =
         let new_vardecs = List.map create_vardec new_vars in
         Block (new_vardecs @ [VarDec (ctype, name, Some value, ann)])
 
+    (* Add vardec for scalar value *)
+    | VarDec (ArrayDims _ as ctype, name, Some value, ann) as node ->
+        let scalar_name = fresh_const "scalar" in
+        Block [
+            VarDec (basetypeof node, scalar_name, Some value, ann);
+            VarDec (ctype, name, Some (Var (scalar_name, None, annof value)), ann);
+        ]
+
     | node -> transform_children consts_to_vars node
 
 (* Generate new variables for array dimensions, to avoid re-evalutation when
@@ -68,8 +77,9 @@ let rec array_dims node =
 
 (* Split variable declaration and initialisation *)
 let rec split_inits = function
-    (* Translate scalar array initialisation to ArrayScalar node,
-        * for easy replacement later on *)
+    (*
+    (* Translate scalar array initialisation to ArrayScalar node, for easy
+     * replacement later on *)
     | VarDec (ArrayDims (_, dims) as ctype, name, Some (Const _   as v), ann) ->
         let init = Some (ArrayInit (ArrayScalar v, dims)) in
         split_inits (VarDec (ctype, name, init, ann))
@@ -78,6 +88,14 @@ let rec split_inits = function
     | VarDec (ArrayDims (_, dims) as ctype, name, Some (ArrayConst _ as v), ann) ->
         let init = Some (ArrayInit (v, dims)) in
         split_inits (VarDec (ctype, name, init, ann))
+    *)
+
+    (* Wrap array initialisation in ArrayInit to pass dimensions *)
+    | VarDec (ArrayDims (_, dims) as ctype, name, Some value, ann) ->
+        Block [
+            VarDec (ctype, name, None, ann);
+            Assign (name, None, ArrayInit (value, dims), ann);
+        ]
 
     (* Variable initialisations are split into dec;assign *)
     | VarDec (ctype, name, Some init, ann) ->
@@ -205,19 +223,13 @@ let for_to_while node =
     in
     traverse (ref []) node
 
-let rec array_init = function
-    (* Transform scalar assignment into nested for-loops *)
-    | Assign (name, None, ArrayInit (ArrayScalar value, dims), ann) ->
-        let rec add_loop indices = function
-            | [] ->
-                Assign (name, Some indices, value, ann)
-            | dim :: rest ->
-                let counter = fresh_var "i" in
-                let body = Block [add_loop (indices @ [Var (counter, None, [])]) rest] in
-                For (counter, Const (IntVal 0, []), dim, Const (IntVal 1, []), body, [])
-        in
-        add_loop [] dims
+let rec sublist n = function
+    | [] when n > 0  -> raise (Invalid_argument "n")
+    | []             -> []
+    | lst when n = 0 -> lst
+    | _ :: tl        -> sublist (n - 1) tl
 
+let rec array_init = function
     (* Transform array constant inisialisation into separate assign statements
      * for all entries in the constant array *)
     (* TODO: only allow when array dimensions are constant? *)
@@ -234,6 +246,11 @@ let rec array_init = function
             | value when depth = ndims ->
                 let indices = List.map (fun i -> Const (IntVal i, [])) indices in
                 [Assign (name, Some (List.rev indices), value, ann)]
+            | value when depth < ndims ->
+                (* Use the for-loops constructed for scalar assignment *)
+                let value = ArrayInit (value, dims) in
+                let indices = List.map (fun i -> Const (IntVal i, [])) indices in
+                [array_init (Assign (name, Some (List.rev indices), value, ann))]
             | node ->
                 let msg = sprintf
                     "dimension mismatch: expected %d nesting levels, got %d"
@@ -243,6 +260,28 @@ let rec array_init = function
         in
         Block (List.rev (traverse 0 [] value))
 
+    (* Replace no indices with empty indices to have a list below *)
+    | Assign (name, None, (ArrayInit _ as value), ann) ->
+        array_init (Assign (name, Some [], value, ann))
+
+    | Assign (name, Some indices, ArrayInit (value, dims), ann) as node ->
+        let rec add_loop indices = function
+            | [] ->
+                array_init (Assign (name, Some indices, value, ann))
+            | dim :: rest ->
+                let counter = fresh_var "i" in
+                let start = Const (IntVal 0, []) in
+                let step = Const (IntVal 1, []) in
+                let body = Block [add_loop (indices @ [Var (counter, None, [])]) rest] in
+                let stop = match dim with
+                    | Dim (name, ann) -> Var (name, None, ann)
+                    | _ -> dim
+                in
+                For (counter, start, stop, step, body, [])
+        in
+        let dims_left = sublist (List.length indices) dims in
+        add_loop indices dims_left
+
     | node -> transform_children array_init node
 
 let phase = function

+ 73 - 0
test/array_single_eval.cvc

@@ -0,0 +1,73 @@
+extern void printInt(int val);
+extern void printSpaces(int num);
+extern void printNewlines(int num);
+
+int ones = 0;
+int twos = 0;
+
+int one() {
+    ones = ones + 1;
+    return 1;
+}
+
+int two() {
+    twos = twos + 1;
+    return 2;
+}
+
+void printArray1D(int[n] a) {
+    for (int i = 0, n) {
+        printInt(a[i]);
+        if (i != n - 1) printSpaces(1);
+    }
+    printNewlines(1);
+}
+
+void printArray2D(int[n, m] a) {
+    for (int i = 0, n) {
+        for (int j = 0, m) {
+            printInt(a[i, j]);
+            if (j != m - 1) printSpaces(1);
+        }
+        printNewlines(1);
+    }
+}
+
+void printArray3D(int[n, m, o] a) {
+    for (int i = 0, n) {
+        for (int j = 0, m) {
+            for (int k = 0, o) {
+                printInt(a[i, j, k]);
+                if (k != o - 1) printSpaces(1);
+            }
+            if (j != m - 1) printSpaces(2);
+        }
+        printNewlines(1);
+    }
+}
+
+export int main() {
+    int[two()] a        = one();
+    int[two(), two()] b = [[1, one()], [2, two()]];
+    int[2, 3] c         = [one(), two()];
+    int[2, 3, 3] d      = [one(), two()];
+
+    printArray1D(a);
+    printNewlines(1);
+
+    printArray2D(b);
+    printNewlines(1);
+
+    printArray2D(c);
+    printNewlines(1);
+
+    printArray3D(d);
+    printNewlines(1);
+
+    printInt(ones);
+    printSpaces(1);
+    printInt(twos);
+    printNewlines(1);
+
+    return 0;
+}

+ 12 - 0
test/array_single_eval.out

@@ -0,0 +1,12 @@
+1 1
+
+1 1
+2 2
+
+1 1 1
+2 2 2
+
+1 1 1  1 1 1  1 1 1
+2 2 2  2 2 2  2 2 2
+
+4 6