[gtk+/wip/otte/shader: 90/150] gskslexpression: Implement Division



commit d6e568a0ffa9521381d2d89115d613010c0ec704
Author: Benjamin Otte <otte redhat com>
Date:   Thu Oct 5 00:40:20 2017 +0200

    gskslexpression: Implement Division
    
    Split out arithmetic expressions and implement constant evaluation SPV
    writing for division.

 gsk/gskslexpression.c |  654 ++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 511 insertions(+), 143 deletions(-)
---
diff --git a/gsk/gskslexpression.c b/gsk/gskslexpression.c
index 3347abb..6e4fd52 100644
--- a/gsk/gskslexpression.c
+++ b/gsk/gskslexpression.c
@@ -365,6 +365,28 @@ static void (* mult_funcs[]) (gpointer, gpointer) = {
   [GSK_SL_DOUBLE] = gsk_sl_expression_multiplication_double,
 };
 
+GSK_SL_OPERATION_FUNC_SCALAR(gsk_sl_expression_division_int, gint32, x = y == 0 ? G_MAXINT32 : x / y;)
+GSK_SL_OPERATION_FUNC_SCALAR(gsk_sl_expression_division_uint, guint32, x = y == 0 ? G_MAXUINT32 : x / y;)
+GSK_SL_OPERATION_FUNC_SCALAR(gsk_sl_expression_division_float, float, x /= y;)
+GSK_SL_OPERATION_FUNC_SCALAR(gsk_sl_expression_division_double, double, x /= y;)
+GSK_SL_OPERATION_FUNC_SCALAR(gsk_sl_expression_division_int_inv, gint32, x = x == 0 ? G_MAXINT32 : y / x;)
+GSK_SL_OPERATION_FUNC_SCALAR(gsk_sl_expression_division_uint_inv, guint32, x = x == 0 ? G_MAXUINT32 : y / x;)
+GSK_SL_OPERATION_FUNC_SCALAR(gsk_sl_expression_division_float_inv, float, x = y / x;)
+GSK_SL_OPERATION_FUNC_SCALAR(gsk_sl_expression_division_double_inv, double, x = y / x;)
+static void (* div_funcs[]) (gpointer, gpointer) = {
+  [GSK_SL_INT] = gsk_sl_expression_division_int,
+  [GSK_SL_UINT] = gsk_sl_expression_division_uint,
+  [GSK_SL_FLOAT] = gsk_sl_expression_division_float,
+  [GSK_SL_DOUBLE] = gsk_sl_expression_division_double,
+};
+static void (* div_inv_funcs[]) (gpointer, gpointer) = {
+  [GSK_SL_INT] = gsk_sl_expression_division_int_inv,
+  [GSK_SL_UINT] = gsk_sl_expression_division_uint_inv,
+  [GSK_SL_FLOAT] = gsk_sl_expression_division_float_inv,
+  [GSK_SL_DOUBLE] = gsk_sl_expression_division_double_inv,
+};
+
+
 static GskSlValue *
 gsk_sl_expression_multiplication_get_constant (const GskSlExpression *expression)
 {
@@ -684,86 +706,10 @@ static const GskSlExpressionClass GSK_SL_EXPRESSION_MULTIPLICATION = {
   gsk_sl_expression_multiplication_write_spv
 };
 
-/* OPERATION */
-
-typedef enum {
-  GSK_SL_OPERATION_DIV,
-  GSK_SL_OPERATION_MOD,
-  GSK_SL_OPERATION_ADD,
-  GSK_SL_OPERATION_SUB,
-  GSK_SL_OPERATION_LSHIFT,
-  GSK_SL_OPERATION_RSHIFT,
-  GSK_SL_OPERATION_LESS,
-  GSK_SL_OPERATION_GREATER,
-  GSK_SL_OPERATION_LESS_EQUAL,
-  GSK_SL_OPERATION_GREATER_EQUAL,
-  GSK_SL_OPERATION_EQUAL,
-  GSK_SL_OPERATION_NOT_EQUAL,
-  GSK_SL_OPERATION_AND,
-  GSK_SL_OPERATION_XOR,
-  GSK_SL_OPERATION_OR,
-  GSK_SL_OPERATION_LOGICAL_AND,
-  GSK_SL_OPERATION_LOGICAL_XOR,
-  GSK_SL_OPERATION_LOGICAL_OR
-} GskSlOperation;
-
-typedef struct _GskSlExpressionOperation GskSlExpressionOperation;
-
-struct _GskSlExpressionOperation {
-  GskSlExpression parent;
-
-  GskSlOperation op;
-  GskSlExpression *left;
-  GskSlExpression *right;
-};
-
-static void
-gsk_sl_expression_operation_free (GskSlExpression *expression)
-{
-  GskSlExpressionOperation *operation = (GskSlExpressionOperation *) expression;
-
-  gsk_sl_expression_unref (operation->left);
-  if (operation->right)
-    gsk_sl_expression_unref (operation->right);
-
-  g_slice_free (GskSlExpressionOperation, operation);
-}
-
-static void
-gsk_sl_expression_operation_print (const GskSlExpression *expression,
-                                   GskSlPrinter          *printer)
-{
-  const char *op_str[] = {
-    [GSK_SL_OPERATION_DIV] = " / ",
-    [GSK_SL_OPERATION_MOD] = " % ",
-    [GSK_SL_OPERATION_ADD] = " + ",
-    [GSK_SL_OPERATION_SUB] = " - ",
-    [GSK_SL_OPERATION_LSHIFT] = " << ",
-    [GSK_SL_OPERATION_RSHIFT] = " >> ",
-    [GSK_SL_OPERATION_LESS] = " < ",
-    [GSK_SL_OPERATION_GREATER] = " > ",
-    [GSK_SL_OPERATION_LESS_EQUAL] = " <= ",
-    [GSK_SL_OPERATION_GREATER_EQUAL] = " >= ",
-    [GSK_SL_OPERATION_EQUAL] = " == ",
-    [GSK_SL_OPERATION_NOT_EQUAL] = " != ",
-    [GSK_SL_OPERATION_AND] = " & ",
-    [GSK_SL_OPERATION_XOR] = " ^ ",
-    [GSK_SL_OPERATION_OR] = " | ",
-    [GSK_SL_OPERATION_LOGICAL_AND] = " && ",
-    [GSK_SL_OPERATION_LOGICAL_XOR] = " ^^ ",
-    [GSK_SL_OPERATION_LOGICAL_OR] = " || "
-  };
-  GskSlExpressionOperation *operation = (GskSlExpressionOperation *) expression;
-
-  /* XXX: figure out the need for bracketing here */
-
-  gsk_sl_expression_print (operation->left, printer);
-  gsk_sl_printer_append (printer, op_str[operation->op]);
-  gsk_sl_expression_print (operation->right, printer);
-}
+/* ARITHMETIC */
 
 static GskSlType *
-gsk_sl_expression_arithmetic_type_check (GskSlPreprocessor *stream,
+gsk_sl_expression_arithmetic_type_check (GskSlPreprocessor *preproc,
                                          GskSlType         *ltype,
                                          GskSlType         *rtype)
 {
@@ -777,12 +723,9 @@ gsk_sl_expression_arithmetic_type_check (GskSlPreprocessor *stream,
     scalar = gsk_sl_type_get_scalar_type (rtype);
   else
     {
-      if (stream)
-        {
-          gsk_sl_preprocessor_error (stream, TYPE_MISMATCH,
-                                     "Operand types %s and %s do not share compatible scalar types.",
-                                     gsk_sl_type_get_name (ltype), gsk_sl_type_get_name (rtype));
-        }
+      gsk_sl_preprocessor_error (preproc, TYPE_MISMATCH,
+                                 "Operand types %s and %s do not share compatible scalar types.",
+                                 gsk_sl_type_get_name (ltype), gsk_sl_type_get_name (rtype));
       return NULL;
     }
 
@@ -800,18 +743,16 @@ gsk_sl_expression_arithmetic_type_check (GskSlPreprocessor *stream,
             }
           else
             {
-              if (stream)
-                gsk_sl_preprocessor_error (stream, TYPE_MISMATCH,
-                                           "Matrix types %s and %s have different size.",
-                                           gsk_sl_type_get_name (ltype), gsk_sl_type_get_name (rtype));
+              gsk_sl_preprocessor_error (preproc, TYPE_MISMATCH,
+                                         "Matrix types %s and %s have different size.",
+                                         gsk_sl_type_get_name (ltype), gsk_sl_type_get_name (rtype));
               return NULL;
             }
         }
       else if (gsk_sl_type_is_vector (rtype))
         {
-          if (stream)
-            gsk_sl_preprocessor_error (stream, TYPE_MISMATCH,
-                                       "Cannot perform arithmetic operation between matrix and vector.");
+          gsk_sl_preprocessor_error (preproc, TYPE_MISMATCH,
+                                     "Cannot perform arithmetic arithmetic between matrix and vector.");
           return NULL;
         }
       else if (gsk_sl_type_is_scalar (rtype))
@@ -822,9 +763,8 @@ gsk_sl_expression_arithmetic_type_check (GskSlPreprocessor *stream,
         }
       else
         {
-          if (stream)
-            gsk_sl_preprocessor_error (stream, TYPE_MISMATCH,
-                                       "Right operand is incompatible type for arithemtic operation.");
+          gsk_sl_preprocessor_error (preproc, TYPE_MISMATCH,
+                                     "Right operand is incompatible type for arithemtic arithmetic.");
           return NULL;
         }
     }
@@ -832,18 +772,16 @@ gsk_sl_expression_arithmetic_type_check (GskSlPreprocessor *stream,
     {
       if (gsk_sl_type_is_matrix (rtype))
         {
-          if (stream)
-            gsk_sl_preprocessor_error (stream, TYPE_MISMATCH, "Cannot perform arithmetic operation between 
vector and matrix.");
+          gsk_sl_preprocessor_error (preproc, TYPE_MISMATCH, "Cannot perform arithmetic arithmetic between 
vector and matrix.");
           return NULL;
         }
       else if (gsk_sl_type_is_vector (rtype))
         {
           if (gsk_sl_type_get_length (ltype) != gsk_sl_type_get_length (rtype))
             {
-              if (stream)
-                gsk_sl_preprocessor_error (stream, TYPE_MISMATCH,
-                                           "Vector operands %s and %s to arithmetic operation have different 
length.",
-                                           gsk_sl_type_get_name (ltype), gsk_sl_type_get_name (rtype));
+              gsk_sl_preprocessor_error (preproc, TYPE_MISMATCH,
+                                         "Vector operands %s and %s to arithmetic arithmetic have different 
length.",
+                                         gsk_sl_type_get_name (ltype), gsk_sl_type_get_name (rtype));
               return NULL;
             }
           return gsk_sl_type_get_vector (scalar, gsk_sl_type_get_length (ltype));
@@ -855,9 +793,8 @@ gsk_sl_expression_arithmetic_type_check (GskSlPreprocessor *stream,
         }
       else
         {
-          if (stream)
-            gsk_sl_preprocessor_error (stream, TYPE_MISMATCH,
-                                       "Right operand is incompatible type for arithemtic operation.");
+          gsk_sl_preprocessor_error (preproc, TYPE_MISMATCH,
+                                     "Right operand is incompatible type for arithemtic arithmetic.");
           return NULL;
         }
     }
@@ -880,19 +817,454 @@ gsk_sl_expression_arithmetic_type_check (GskSlPreprocessor *stream,
         }
       else
         {
-          if (stream)
-            gsk_sl_preprocessor_error (stream, TYPE_MISMATCH, "Right operand is incompatible type for 
arithemtic operation.");
+          gsk_sl_preprocessor_error (preproc, TYPE_MISMATCH, "Right operand is incompatible type for 
arithemtic arithmetic.");
           return NULL;
         }
     }
   else
     {
-      if (stream)
-        gsk_sl_preprocessor_error (stream, TYPE_MISMATCH, "Left operand is incompatible type for arithemtic 
operation.");
+      gsk_sl_preprocessor_error (preproc, TYPE_MISMATCH, "Left operand is incompatible type for arithemtic 
arithmetic.");
       return NULL;
     }
 }
 
+typedef struct _GskSlExpressionArithmetic GskSlExpressionArithmetic;
+
+struct _GskSlExpressionArithmetic {
+  GskSlExpression parent;
+
+  GskSlType *type;
+  GskSlExpression *left;
+  GskSlExpression *right;
+};
+
+static void
+gsk_sl_expression_arithmetic_free (GskSlExpression *expression)
+{
+  GskSlExpressionArithmetic *arithmetic = (GskSlExpressionArithmetic *) expression;
+
+  gsk_sl_type_unref (arithmetic->type);
+  gsk_sl_expression_unref (arithmetic->left);
+  gsk_sl_expression_unref (arithmetic->right);
+
+  g_slice_free (GskSlExpressionArithmetic, arithmetic);
+}
+
+static void
+gsk_sl_expression_division_print (const GskSlExpression *expression,
+                                  GskSlPrinter          *printer)
+{
+  GskSlExpressionArithmetic *arithmetic = (GskSlExpressionArithmetic *) expression;
+
+  gsk_sl_expression_print (arithmetic->left, printer);
+  gsk_sl_printer_append (printer, " / ");
+  gsk_sl_expression_print (arithmetic->right, printer);
+}
+
+static void
+gsk_sl_expression_addition_print (const GskSlExpression *expression,
+                                  GskSlPrinter          *printer)
+{
+  GskSlExpressionArithmetic *arithmetic = (GskSlExpressionArithmetic *) expression;
+
+  gsk_sl_expression_print (arithmetic->left, printer);
+  gsk_sl_printer_append (printer, " + ");
+  gsk_sl_expression_print (arithmetic->right, printer);
+}
+
+static void
+gsk_sl_expression_subtraction_print (const GskSlExpression *expression,
+                                     GskSlPrinter          *printer)
+{
+  GskSlExpressionArithmetic *arithmetic = (GskSlExpressionArithmetic *) expression;
+
+  gsk_sl_expression_print (arithmetic->left, printer);
+  gsk_sl_printer_append (printer, " - ");
+  gsk_sl_expression_print (arithmetic->right, printer);
+}
+
+static GskSlType *
+gsk_sl_expression_arithmetic_get_return_type (const GskSlExpression *expression)
+{
+  GskSlExpressionArithmetic *arithmetic = (GskSlExpressionArithmetic *) expression;
+
+  return arithmetic->type;
+}
+
+static GskSlValue *
+gsk_sl_expression_division_get_constant (const GskSlExpression *expression)
+{
+  const GskSlExpressionArithmetic *arithmetic = (const GskSlExpressionArithmetic *) expression;
+  GskSlValue *result, *lvalue, *rvalue;
+  GskSlType *ltype, *rtype;
+  GskSlScalarType scalar;
+  gsize ln, rn;
+
+  scalar = gsk_sl_type_get_scalar_type (arithmetic->type);
+  lvalue = gsk_sl_expression_get_constant (arithmetic->left);
+  if (lvalue == NULL)
+    return NULL;
+  rvalue = gsk_sl_expression_get_constant (arithmetic->right);
+  if (rvalue == NULL)
+    {
+      gsk_sl_value_free (lvalue);
+      return NULL;
+    }
+  lvalue = gsk_sl_value_convert_components (lvalue, scalar);
+  rvalue = gsk_sl_value_convert_components (rvalue, scalar);
+  ltype = gsk_sl_value_get_type (lvalue);
+  rtype = gsk_sl_value_get_type (rvalue);
+
+  ln = gsk_sl_type_get_n_components (ltype);
+  rn = gsk_sl_type_get_n_components (rtype);
+  if (ln == 1)
+    {
+      gsk_sl_value_componentwise (rvalue, div_inv_funcs[scalar], gsk_sl_value_get_data (lvalue));
+      gsk_sl_value_free (lvalue);
+      result = rvalue;
+    }
+  else if (rn == 1)
+    {
+      gsk_sl_value_componentwise (lvalue, div_funcs[scalar], gsk_sl_value_get_data (rvalue));
+      gsk_sl_value_free (rvalue);
+      result = lvalue;
+    }
+  else
+    {
+      guchar *ldata, *rdata;
+      gsize i, stride;
+
+      stride = gsk_sl_scalar_type_get_size (scalar);
+      ldata = gsk_sl_value_get_data (lvalue);
+      rdata = gsk_sl_value_get_data (rvalue);
+      for (i = 0; i < ln; i++)
+        {
+          div_funcs[scalar] (ldata + i * stride, rdata + i * stride);
+        }
+      gsk_sl_value_free (rvalue);
+      result = lvalue;
+    }
+
+  return result;
+}
+
+static guint32
+gsk_sl_expression_division_write_spv (const GskSlExpression *expression,
+                                      GskSpvWriter          *writer)
+{
+  const GskSlExpressionArithmetic *arithmetic = (const GskSlExpressionArithmetic *) expression;
+  GskSlType *ltype, *rtype;
+  guint32 left_id, right_id, result_id, result_type_id;
+
+  ltype = gsk_sl_expression_get_return_type (arithmetic->left);
+  rtype = gsk_sl_expression_get_return_type (arithmetic->right);
+
+  left_id = gsk_sl_expression_write_spv (arithmetic->left, writer);
+  if (gsk_sl_type_get_scalar_type (ltype) != gsk_sl_type_get_scalar_type (arithmetic->type))
+    {
+      GskSlType *new_type = gsk_sl_type_get_matching (ltype, gsk_sl_type_get_scalar_type (arithmetic->type));
+      left_id = gsk_spv_writer_add_conversion (writer, left_id, ltype, new_type);
+      ltype = new_type;
+    }
+  right_id = gsk_sl_expression_write_spv (arithmetic->right, writer);
+  if (gsk_sl_type_get_scalar_type (rtype) != gsk_sl_type_get_scalar_type (arithmetic->type))
+    {
+      GskSlType *new_type = gsk_sl_type_get_matching (rtype, gsk_sl_type_get_scalar_type (arithmetic->type));
+      right_id = gsk_spv_writer_add_conversion (writer, right_id, rtype, new_type);
+      rtype = new_type;
+    }
+
+  result_type_id = gsk_spv_writer_get_id_for_type (writer, arithmetic->type);
+
+  if (gsk_sl_type_is_matrix (ltype))
+    {
+      if (gsk_sl_type_is_matrix (rtype))
+        {
+          gsize cols = gsk_sl_type_get_length (ltype);
+          gsize c;
+          guint32 col_type_id, left_part_id, right_part_id, ids[cols + 2];
+
+          col_type_id = gsk_spv_writer_get_id_for_type (writer, gsk_sl_type_get_index_type (ltype));
+          for (c = 0; c < cols; c++)
+            {
+              left_part_id = gsk_spv_writer_next_id (writer);
+              gsk_spv_writer_add (writer,
+                                  GSK_SPV_WRITER_SECTION_CODE,
+                                  5, GSK_SPV_OP_COMPOSITE_EXTRACT,
+                                  (guint32[4]) { col_type_id,
+                                                 left_part_id,
+                                                 left_id,
+                                                 c });
+              right_part_id = gsk_spv_writer_next_id (writer);
+              gsk_spv_writer_add (writer,
+                                  GSK_SPV_WRITER_SECTION_CODE,
+                                  5, GSK_SPV_OP_COMPOSITE_EXTRACT,
+                                  (guint32[4]) { col_type_id,
+                                                 right_part_id,
+                                                 right_id,
+                                                 c });
+              ids[2 + c] = gsk_spv_writer_next_id (writer);
+              gsk_spv_writer_add (writer,
+                                  GSK_SPV_WRITER_SECTION_CODE,
+                                  5, GSK_SPV_OP_F_DIV,
+                                  (guint32[4]) { col_type_id,
+                                                 ids[2 + c],
+                                                 left_part_id,
+                                                 right_part_id });
+            }
+
+          ids[0] = result_type_id;
+          ids[1] = gsk_spv_writer_next_id (writer);
+          gsk_spv_writer_add (writer,
+                              GSK_SPV_WRITER_SECTION_CODE,
+                              3 + cols, GSK_SPV_OP_COMPOSITE_CONSTRUCT,
+                              ids);
+
+          return ids[1];
+        }
+      else if (gsk_sl_type_is_scalar (rtype))
+        {
+          guint32 tmp_id, one_id, rtype_id;
+
+          rtype_id = gsk_spv_writer_get_id_for_type (writer, rtype);
+          one_id = gsk_spv_writer_get_id_for_one (writer, gsk_sl_type_get_scalar_type (arithmetic->type));
+          tmp_id = gsk_spv_writer_next_id (writer);
+          gsk_spv_writer_add (writer,
+                              GSK_SPV_WRITER_SECTION_CODE,
+                              5, GSK_SPV_OP_F_DIV,
+                              (guint32[4]) { rtype_id,
+                                             tmp_id,
+                                             one_id,
+                                             right_id });
+
+          result_id = gsk_spv_writer_next_id (writer);
+          gsk_spv_writer_add (writer,
+                              GSK_SPV_WRITER_SECTION_CODE,
+                              5, GSK_SPV_OP_MATRIX_TIMES_SCALAR,
+                              (guint32[4]) { result_type_id,
+                                             result_id,
+                                             left_id,
+                                             tmp_id });
+
+          return result_id;
+        }
+      else
+        {
+          g_assert_not_reached ();
+          return 0;
+        }
+    }
+  else if (gsk_sl_type_is_matrix (rtype))
+    {
+      guint32 tmp_id, one_id, ltype_id;
+
+      ltype_id = gsk_spv_writer_get_id_for_type (writer, ltype);
+      one_id = gsk_spv_writer_get_id_for_one (writer, gsk_sl_type_get_scalar_type (arithmetic->type));
+      tmp_id = gsk_spv_writer_next_id (writer);
+      gsk_spv_writer_add (writer,
+                          GSK_SPV_WRITER_SECTION_CODE,
+                          5, GSK_SPV_OP_F_DIV,
+                          (guint32[4]) { ltype_id,
+                                         tmp_id,
+                                         one_id,
+                                         left_id });
+
+      result_id = gsk_spv_writer_next_id (writer);
+      gsk_spv_writer_add (writer,
+                          GSK_SPV_WRITER_SECTION_CODE,
+                          5, GSK_SPV_OP_MATRIX_TIMES_SCALAR,
+                          (guint32[4]) { result_type_id,
+                                         result_id,
+                                         right_id,
+                                         tmp_id });
+
+      return result_id;
+    }
+  else
+    {
+      /* ltype and rtype are not matices */
+
+      if (gsk_sl_type_is_scalar (ltype) && gsk_sl_type_is_vector (rtype))
+        {
+           guint32 tmp_id = gsk_spv_writer_next_id (writer);
+           gsk_spv_writer_add (writer,
+                               GSK_SPV_WRITER_SECTION_CODE,
+                               3 + gsk_sl_type_get_length (rtype), GSK_SPV_OP_COMPOSITE_CONSTRUCT,
+                              (guint32[6]) { result_type_id,
+                                             tmp_id,
+                                             left_id, left_id, left_id, left_id });
+           left_id = tmp_id;
+        }
+      else if (gsk_sl_type_is_scalar (rtype) && gsk_sl_type_is_vector (ltype))
+        {
+           guint32 tmp_id = gsk_spv_writer_next_id (writer);
+           gsk_spv_writer_add (writer,
+                               GSK_SPV_WRITER_SECTION_CODE,
+                               3 + gsk_sl_type_get_length (ltype), GSK_SPV_OP_COMPOSITE_CONSTRUCT,
+                              (guint32[6]) { result_type_id,
+                                             tmp_id,
+                                             right_id, right_id, right_id, right_id });
+           right_id = tmp_id;
+        }
+
+      /* ltype and rtype have the same number of components now */
+
+      result_id = gsk_spv_writer_next_id (writer);
+      switch (gsk_sl_type_get_scalar_type (arithmetic->type))
+        {
+        case GSK_SL_FLOAT:
+        case GSK_SL_DOUBLE:
+          gsk_spv_writer_add (writer,
+                              GSK_SPV_WRITER_SECTION_CODE,
+                              5, GSK_SPV_OP_F_DIV,
+                              (guint32[4]) { result_type_id,
+                                             result_id,
+                                             left_id,
+                                             right_id });
+          break;
+        case GSK_SL_INT:
+          gsk_spv_writer_add (writer,
+                              GSK_SPV_WRITER_SECTION_CODE,
+                              5, GSK_SPV_OP_S_DIV,
+                              (guint32[4]) { result_type_id,
+                                             result_id,
+                                             left_id,
+                                             right_id });
+          break;
+        case GSK_SL_UINT:
+          gsk_spv_writer_add (writer,
+                              GSK_SPV_WRITER_SECTION_CODE,
+                              5, GSK_SPV_OP_U_DIV,
+                              (guint32[4]) { result_type_id,
+                                             result_id,
+                                             left_id,
+                                             right_id });
+          break;
+        case GSK_SL_VOID:
+        case GSK_SL_BOOL:
+        default:
+          g_assert_not_reached ();
+          break;
+        }
+
+      return result_id;
+    }
+}
+
+static GskSlValue *
+gsk_sl_expression_arithmetic_get_constant (const GskSlExpression *expression)
+{
+  //GskSlExpressionArithmetic *arithmetic = (const GskSlExpressionArithmetic *) expression;
+
+  /* FIXME: These need constant evaluations */
+  return NULL;
+}
+
+static guint32
+gsk_sl_expression_arithmetic_write_spv (const GskSlExpression *expression,
+                                        GskSpvWriter          *writer)
+{
+  g_assert_not_reached ();
+
+  return 0;
+}
+
+static const GskSlExpressionClass GSK_SL_EXPRESSION_DIVISION = {
+  gsk_sl_expression_arithmetic_free,
+  gsk_sl_expression_division_print,
+  gsk_sl_expression_arithmetic_get_return_type,
+  gsk_sl_expression_division_get_constant,
+  gsk_sl_expression_division_write_spv
+};
+
+static const GskSlExpressionClass GSK_SL_EXPRESSION_ADDITION = {
+  gsk_sl_expression_arithmetic_free,
+  gsk_sl_expression_addition_print,
+  gsk_sl_expression_arithmetic_get_return_type,
+  gsk_sl_expression_arithmetic_get_constant,
+  gsk_sl_expression_arithmetic_write_spv
+};
+
+static const GskSlExpressionClass GSK_SL_EXPRESSION_SUBTRACTION = {
+  gsk_sl_expression_arithmetic_free,
+  gsk_sl_expression_subtraction_print,
+  gsk_sl_expression_arithmetic_get_return_type,
+  gsk_sl_expression_arithmetic_get_constant,
+  gsk_sl_expression_arithmetic_write_spv
+};
+
+/* OPERATION */
+
+typedef enum {
+  GSK_SL_OPERATION_MOD,
+  GSK_SL_OPERATION_LSHIFT,
+  GSK_SL_OPERATION_RSHIFT,
+  GSK_SL_OPERATION_LESS,
+  GSK_SL_OPERATION_GREATER,
+  GSK_SL_OPERATION_LESS_EQUAL,
+  GSK_SL_OPERATION_GREATER_EQUAL,
+  GSK_SL_OPERATION_EQUAL,
+  GSK_SL_OPERATION_NOT_EQUAL,
+  GSK_SL_OPERATION_AND,
+  GSK_SL_OPERATION_XOR,
+  GSK_SL_OPERATION_OR,
+  GSK_SL_OPERATION_LOGICAL_AND,
+  GSK_SL_OPERATION_LOGICAL_XOR,
+  GSK_SL_OPERATION_LOGICAL_OR
+} GskSlOperation;
+
+typedef struct _GskSlExpressionOperation GskSlExpressionOperation;
+
+struct _GskSlExpressionOperation {
+  GskSlExpression parent;
+
+  GskSlOperation op;
+  GskSlExpression *left;
+  GskSlExpression *right;
+};
+
+static void
+gsk_sl_expression_operation_free (GskSlExpression *expression)
+{
+  GskSlExpressionOperation *operation = (GskSlExpressionOperation *) expression;
+
+  gsk_sl_expression_unref (operation->left);
+  if (operation->right)
+    gsk_sl_expression_unref (operation->right);
+
+  g_slice_free (GskSlExpressionOperation, operation);
+}
+
+static void
+gsk_sl_expression_operation_print (const GskSlExpression *expression,
+                                   GskSlPrinter          *printer)
+{
+  const char *op_str[] = {
+    [GSK_SL_OPERATION_MOD] = " % ",
+    [GSK_SL_OPERATION_LSHIFT] = " << ",
+    [GSK_SL_OPERATION_RSHIFT] = " >> ",
+    [GSK_SL_OPERATION_LESS] = " < ",
+    [GSK_SL_OPERATION_GREATER] = " > ",
+    [GSK_SL_OPERATION_LESS_EQUAL] = " <= ",
+    [GSK_SL_OPERATION_GREATER_EQUAL] = " >= ",
+    [GSK_SL_OPERATION_EQUAL] = " == ",
+    [GSK_SL_OPERATION_NOT_EQUAL] = " != ",
+    [GSK_SL_OPERATION_AND] = " & ",
+    [GSK_SL_OPERATION_XOR] = " ^ ",
+    [GSK_SL_OPERATION_OR] = " | ",
+    [GSK_SL_OPERATION_LOGICAL_AND] = " && ",
+    [GSK_SL_OPERATION_LOGICAL_XOR] = " ^^ ",
+    [GSK_SL_OPERATION_LOGICAL_OR] = " || "
+  };
+  GskSlExpressionOperation *operation = (GskSlExpressionOperation *) expression;
+
+  /* XXX: figure out the need for bracketing here */
+
+  gsk_sl_expression_print (operation->left, printer);
+  gsk_sl_printer_append (printer, op_str[operation->op]);
+  gsk_sl_expression_print (operation->right, printer);
+}
+
 static GskSlType *
 gsk_sl_expression_bitwise_type_check (GskSlPreprocessor *stream,
                                       GskSlType         *ltype,
@@ -1033,12 +1405,6 @@ gsk_sl_expression_operation_get_return_type (const GskSlExpression *expression)
 
   switch (operation->op)
   {
-    case GSK_SL_OPERATION_DIV:
-    case GSK_SL_OPERATION_ADD:
-    case GSK_SL_OPERATION_SUB:
-      return gsk_sl_expression_arithmetic_type_check (NULL,
-                                                      gsk_sl_expression_get_return_type (operation->left),
-                                                      gsk_sl_expression_get_return_type (operation->right));
     case GSK_SL_OPERATION_LSHIFT:
     case GSK_SL_OPERATION_RSHIFT:
       return gsk_sl_expression_get_return_type (operation->left);
@@ -1428,9 +1794,7 @@ gsk_sl_expression_constructor_write_spv (const GskSlExpression *expression,
       value_id = gsk_sl_expression_write_spv (constructor->arguments[0], writer);
       if (gsk_sl_type_get_scalar_type (value_type) != gsk_sl_type_get_scalar_type (type))
         {
-          GskSlType *new_value_type = gsk_sl_type_get_matrix (gsk_sl_type_get_scalar_type (type),
-                                                              gsk_sl_type_get_length (value_type),
-                                                              gsk_sl_type_get_length (value_col_type));
+          GskSlType *new_value_type = gsk_sl_type_get_matching (value_type, gsk_sl_type_get_scalar_type 
(type));
           value_id = gsk_spv_writer_add_conversion (writer, value_id, value_type, new_value_type);
           value_type = new_value_type;
         }
@@ -2817,16 +3181,19 @@ gsk_sl_expression_parse_multiplicative (GskSlScope        *scope,
         }
       else if (op == DIV)
         {
-          if (gsk_sl_expression_arithmetic_type_check (stream,
-                                                       gsk_sl_expression_get_return_type (expression),
-                                                       gsk_sl_expression_get_return_type (right)))
+          GskSlType *result_type;
+
+          result_type = gsk_sl_expression_arithmetic_type_check (stream,
+                                                                 gsk_sl_expression_get_return_type 
(expression),
+                                                                 gsk_sl_expression_get_return_type (right));
+          if (result_type)
             {
-              GskSlExpressionOperation *operation;
-              operation = gsk_sl_expression_new (GskSlExpressionOperation, &GSK_SL_EXPRESSION_OPERATION);
-              operation->op = GSK_SL_OPERATION_DIV;
-              operation->left = expression;
-              operation->right = right;
-              expression = (GskSlExpression *) operation;
+              GskSlExpressionArithmetic *division;
+              division = gsk_sl_expression_new (GskSlExpressionArithmetic, &GSK_SL_EXPRESSION_DIVISION);
+              division->type = gsk_sl_type_ref (result_type);
+              division->left = expression;
+              division->right = right;
+              expression = (GskSlExpression *) division;
             }
           else
             {
@@ -2861,39 +3228,40 @@ gsk_sl_expression_parse_additive (GskSlScope        *scope,
                                   GskSlPreprocessor *stream)
 {
   const GskSlToken *token;
-  GskSlExpression *expression;
-  GskSlExpressionOperation *operation;
-  GskSlOperation op;
+  GskSlExpression *expression, *right;
+  GskSlType *result_type;
+  enum { ADD, SUB } op;
 
   expression = gsk_sl_expression_parse_multiplicative (scope, stream);
-  if (expression == NULL)
-    return NULL;
 
   while (TRUE)
     {
       token = gsk_sl_preprocessor_get (stream);
       if (gsk_sl_token_is (token, GSK_SL_TOKEN_PLUS))
-        op = GSK_SL_OPERATION_ADD;
+        op = ADD;
       else if (gsk_sl_token_is (token, GSK_SL_TOKEN_DASH))
-        op = GSK_SL_OPERATION_SUB;
+        op = SUB;
       else
         return expression;
 
-      operation = gsk_sl_expression_new (GskSlExpressionOperation, &GSK_SL_EXPRESSION_OPERATION);
-      operation->left = expression;
-      operation->op = op;
-      gsk_sl_preprocessor_consume (stream, (GskSlExpression *) operation);
-      operation->right = gsk_sl_expression_parse_additive (scope, stream);
-      if (!gsk_sl_expression_arithmetic_type_check (stream,
-                                                    gsk_sl_expression_get_return_type (operation->left),
-                                                    gsk_sl_expression_get_return_type (operation->right)))
+      gsk_sl_preprocessor_consume (stream, NULL);
+      right = gsk_sl_expression_parse_additive (scope, stream);
+      result_type = gsk_sl_expression_arithmetic_type_check (stream,
+                                                             gsk_sl_expression_get_return_type (expression),
+                                                             gsk_sl_expression_get_return_type (right));
+      if (result_type)
         {
-          gsk_sl_expression_ref (expression);
-          gsk_sl_expression_unref ((GskSlExpression *) operation);
+          GskSlExpressionArithmetic *arithmetic;
+
+          arithmetic = gsk_sl_expression_new (GskSlExpressionArithmetic, op == ADD ? 
&GSK_SL_EXPRESSION_ADDITION : &GSK_SL_EXPRESSION_SUBTRACTION);
+          arithmetic->type = gsk_sl_type_ref (result_type);
+          arithmetic->left = expression;
+          arithmetic->right = right;
+          expression = (GskSlExpression *) arithmetic;
         }
       else
         {
-          expression = (GskSlExpression *) operation;
+          gsk_sl_expression_unref ((GskSlExpression *) right);
         }
     }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]