[gtk+/wip/otte/shader: 25/26] gskslexpression: Implement conditional expressions
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/otte/shader: 25/26] gskslexpression: Implement conditional expressions
- Date: Mon, 23 Oct 2017 03:19:20 +0000 (UTC)
commit e6bf74bcf6e791f069396968afe33e8494bc7027
Author: Benjamin Otte <otte redhat com>
Date: Mon Oct 23 04:37:28 2017 +0200
gskslexpression: Implement conditional expressions
Is_with_tests ? Commit_it : Commit_it_anyway
gsk/gskslexpression.c | 222 +++++++++++++++++++-
.../condition-in-conditional-is-not-bool.glsl | 7 +
.../errors/incompatible-types-in-conditional.glsl | 7 +
.../gsksl/errors/missing-colon-in-conditional.glsl | 7 +
4 files changed, 240 insertions(+), 3 deletions(-)
---
diff --git a/gsk/gskslexpression.c b/gsk/gskslexpression.c
index ba2e2de..21ce8c3 100644
--- a/gsk/gskslexpression.c
+++ b/gsk/gskslexpression.c
@@ -605,6 +605,149 @@ static const GskSlExpressionClass GSK_SL_EXPRESSION_LOGICAL_OR = {
gsk_sl_expression_default_get_spv_access_chain
};
+/* CONDITIONAL */
+
+typedef struct _GskSlExpressionConditional GskSlExpressionConditional;
+
+struct _GskSlExpressionConditional {
+ GskSlExpression parent;
+
+ GskSlExpression *condition;
+ GskSlType *type;
+ GskSlExpression *left;
+ GskSlExpression *right;
+};
+
+static void
+gsk_sl_expression_conditional_free (GskSlExpression *expression)
+{
+ GskSlExpressionConditional *conditional = (GskSlExpressionConditional *) expression;
+
+ gsk_sl_expression_unref (conditional->condition);
+ gsk_sl_type_unref (conditional->type);
+ gsk_sl_expression_unref (conditional->left);
+ gsk_sl_expression_unref (conditional->right);
+
+ g_slice_free (GskSlExpressionConditional, conditional);
+}
+
+static void
+gsk_sl_expression_conditional_print (const GskSlExpression *expression,
+ GskSlPrinter *printer)
+{
+ GskSlExpressionConditional *conditional = (GskSlExpressionConditional *) expression;
+
+ gsk_sl_expression_print (conditional->condition, printer);
+ gsk_sl_printer_append (printer, " ? ");
+ gsk_sl_expression_print (conditional->left, printer);
+ gsk_sl_printer_append (printer, " : ");
+ gsk_sl_expression_print (conditional->right, printer);
+}
+
+static GskSlType *
+gsk_sl_expression_conditional_get_return_type (const GskSlExpression *expression)
+{
+ GskSlExpressionConditional *conditional = (GskSlExpressionConditional *) expression;
+
+ return conditional->type;
+}
+
+static GskSlValue *
+gsk_sl_expression_conditional_get_constant (const GskSlExpression *expression)
+{
+ const GskSlExpressionConditional *conditional = (const GskSlExpressionConditional *) expression;
+ GskSlValue *cond, *lvalue, *rvalue;
+
+ cond = gsk_sl_expression_get_constant (conditional->condition);
+ if (cond == NULL)
+ return NULL;
+ lvalue = gsk_sl_expression_get_constant (conditional->left);
+ if (lvalue == NULL)
+ {
+ gsk_sl_value_free (cond);
+ return NULL;
+ }
+ rvalue = gsk_sl_expression_get_constant (conditional->right);
+ if (rvalue == NULL)
+ {
+ gsk_sl_value_free (cond);
+ gsk_sl_value_free (lvalue);
+ return NULL;
+ }
+
+ if (*(guint32 *) gsk_sl_value_get_data (cond))
+ {
+ gsk_sl_value_free (cond);
+ gsk_sl_value_free (rvalue);
+ return lvalue;
+ }
+ else
+ {
+ gsk_sl_value_free (cond);
+ gsk_sl_value_free (lvalue);
+ return rvalue;
+ }
+}
+
+static guint32
+gsk_sl_expression_conditional_write_spv (const GskSlExpression *expression,
+ GskSpvWriter *writer)
+{
+ const GskSlExpressionConditional *conditional = (const GskSlExpressionConditional *) expression;
+ guint32 true_id, false_id, after_id;
+ guint32 condition_id, left_id, right_id, result_id;
+
+ condition_id = gsk_sl_expression_write_spv (conditional->condition, writer);
+
+ true_id = gsk_spv_writer_make_id (writer);
+ false_id = gsk_spv_writer_make_id (writer);
+ after_id = gsk_spv_writer_make_id (writer);
+
+ gsk_spv_writer_selection_merge (writer, after_id, 0);
+ gsk_spv_writer_branch_conditional (writer, condition_id, true_id, false_id, NULL, 0);
+
+ gsk_spv_writer_start_code_block (writer, true_id, 0, 0);
+ gsk_spv_writer_label (writer, GSK_SPV_WRITER_SECTION_CODE, true_id);
+ left_id = gsk_sl_expression_write_spv (conditional->left, writer);
+ left_id = gsk_spv_writer_convert (writer,
+ left_id,
+ gsk_sl_expression_get_return_type (conditional->left),
+ conditional->type);
+ gsk_spv_writer_branch (writer, after_id);
+
+ gsk_spv_writer_start_code_block (writer, false_id, 0, 0);
+ gsk_spv_writer_label (writer, GSK_SPV_WRITER_SECTION_CODE, false_id);
+ right_id = gsk_sl_expression_write_spv (conditional->right, writer);
+ right_id = gsk_spv_writer_convert (writer,
+ right_id,
+ gsk_sl_expression_get_return_type (conditional->right),
+ conditional->type);
+ gsk_spv_writer_branch (writer, after_id);
+
+ gsk_spv_writer_start_code_block (writer, after_id, 0, 0);
+ gsk_spv_writer_label (writer, GSK_SPV_WRITER_SECTION_CODE, after_id);
+
+ result_id = gsk_spv_writer_phi (writer,
+ conditional->type,
+ (guint32 **) (guint32[4][2]) {
+ { left_id, true_id },
+ { right_id, false_id }
+ },
+ 2);
+
+ return result_id;
+}
+
+static const GskSlExpressionClass GSK_SL_EXPRESSION_CONDITIONAL = {
+ gsk_sl_expression_conditional_free,
+ gsk_sl_expression_conditional_print,
+ gsk_sl_expression_default_is_assignable,
+ gsk_sl_expression_conditional_get_return_type,
+ gsk_sl_expression_conditional_get_constant,
+ gsk_sl_expression_conditional_write_spv,
+ gsk_sl_expression_default_get_spv_access_chain
+};
+
/* REFERENCE */
typedef struct _GskSlExpressionReference GskSlExpressionReference;
@@ -3100,10 +3243,83 @@ gsk_sl_expression_parse_logical_or (GskSlScope *scope,
static GskSlExpression *
gsk_sl_expression_parse_conditional (GskSlScope *scope,
- GskSlPreprocessor *stream)
+ GskSlPreprocessor *preproc)
{
- /* XXX: support conditionals */
- return gsk_sl_expression_parse_logical_or (scope, stream);
+ GskSlExpressionConditional *conditional;
+ GskSlExpression *expr, *left, *right;
+ GskSlType *type, *expr_type, *left_type, *right_type;
+ const GskSlToken *token;
+ gboolean success = TRUE;
+
+ expr = gsk_sl_expression_parse_logical_or (scope, preproc);
+
+ token = gsk_sl_preprocessor_get (preproc);
+ if (!gsk_sl_token_is (token, GSK_SL_TOKEN_QUESTION))
+ return expr;
+ gsk_sl_preprocessor_consume (preproc, NULL);
+
+ expr_type = gsk_sl_expression_get_return_type (expr);
+ if (!gsk_sl_type_equal (expr_type, gsk_sl_type_get_scalar (GSK_SL_BOOL)))
+ {
+ gsk_sl_preprocessor_error (preproc, TYPE_MISMATCH,
+ "Condition in conditional expression returns %s, not bool",
+ gsk_sl_type_get_name (expr_type));
+ success = FALSE;
+ }
+ else
+ {
+ GskSlValue *value = gsk_sl_expression_get_constant (expr);
+
+ if (value)
+ {
+ gsk_sl_preprocessor_warn (preproc, CONSTANT,
+ "Conditional expression is always %s",
+ *(guint32 *) gsk_sl_value_get_data (value) ? "true" : "false");
+ gsk_sl_value_free (value);
+ }
+ }
+
+ left = gsk_sl_expression_parse (scope, preproc);
+
+ token = gsk_sl_preprocessor_get (preproc);
+ if (!gsk_sl_token_is (token, GSK_SL_TOKEN_COLON))
+ {
+ gsk_sl_preprocessor_error (preproc, SYNTAX, "Expected \":\" while parsing conditional expression");
+ gsk_sl_expression_unref (expr);
+ return left;
+ }
+ gsk_sl_preprocessor_consume (preproc, NULL);
+
+ right = gsk_sl_expression_parse_assignment (scope, preproc);
+
+ left_type = gsk_sl_expression_get_return_type (left);
+ right_type = gsk_sl_expression_get_return_type (right);
+ if (gsk_sl_type_can_convert (left_type, right_type))
+ type = left_type;
+ else if (gsk_sl_type_can_convert (right_type, left_type))
+ type = right_type;
+ else
+ {
+ gsk_sl_preprocessor_error (preproc, TYPE_MISMATCH,
+ "Types %s and %s in conditional expression are not compatible.",
+ gsk_sl_type_get_name (left_type), gsk_sl_type_get_name (right_type));
+ success = FALSE;
+ }
+
+ if (!success)
+ {
+ gsk_sl_expression_unref (expr);
+ gsk_sl_expression_unref (right);
+ return left;
+ }
+
+ conditional = gsk_sl_expression_new (GskSlExpressionConditional, &GSK_SL_EXPRESSION_CONDITIONAL);
+ conditional->condition = expr;
+ conditional->type = gsk_sl_type_ref (type);
+ conditional->left = left;
+ conditional->right = right;
+
+ return (GskSlExpression *) conditional;
}
GskSlExpression *
diff --git a/testsuite/gsksl/errors/condition-in-conditional-is-not-bool.glsl
b/testsuite/gsksl/errors/condition-in-conditional-is-not-bool.glsl
new file mode 100644
index 0000000..cae267b
--- /dev/null
+++ b/testsuite/gsksl/errors/condition-in-conditional-is-not-bool.glsl
@@ -0,0 +1,7 @@
+
+void
+main ()
+{
+ int b;
+ int y = b ? 1 : 0;
+}
diff --git a/testsuite/gsksl/errors/incompatible-types-in-conditional.glsl
b/testsuite/gsksl/errors/incompatible-types-in-conditional.glsl
new file mode 100644
index 0000000..64403a1
--- /dev/null
+++ b/testsuite/gsksl/errors/incompatible-types-in-conditional.glsl
@@ -0,0 +1,7 @@
+
+void
+main ()
+{
+ bool b;
+ int y = b ? 1 : true;
+}
diff --git a/testsuite/gsksl/errors/missing-colon-in-conditional.glsl
b/testsuite/gsksl/errors/missing-colon-in-conditional.glsl
new file mode 100644
index 0000000..ed714b4
--- /dev/null
+++ b/testsuite/gsksl/errors/missing-colon-in-conditional.glsl
@@ -0,0 +1,7 @@
+
+void
+main ()
+{
+ bool b;
+ int y = b ? 1;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]