From fc4e8cb350c19cd0ffa3a08a5b634e4c2cdd96cd Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 1 Oct 2024 14:13:16 +0900 Subject: [PATCH] [qfcc] Switch to deferred expressions for glsl I plan to do this eventually for Ruamoko, but I need it to keep working for now; it's rather nice having multiple languages. I expect this will open up a lot of options for inlining, generic/template function instantiation, etc. Right now, it's helping with specialization constants in glsl. --- tools/qfcc/include/expr.h | 19 +++++ tools/qfcc/include/expr_names.h | 2 + tools/qfcc/source/Makemodule.am | 1 + tools/qfcc/source/expr.c | 40 ++++++++++ tools/qfcc/source/expr_assign.c | 4 + tools/qfcc/source/expr_dag.c | 8 ++ tools/qfcc/source/expr_process.c | 115 +++++++++++++++++++++++++++ tools/qfcc/source/glsl-declaration.c | 3 + tools/qfcc/source/glsl-parse.y | 43 +++++----- 9 files changed, 214 insertions(+), 21 deletions(-) create mode 100644 tools/qfcc/source/expr_process.c diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index c299253b4..c5c1cb960 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -321,6 +321,18 @@ typedef struct { const symbol_t *sym; } ex_type_t; +typedef struct { + int op; + bool postop; + const expr_t *expr; +} ex_incop_t; + +typedef struct { + const expr_t *test; + const expr_t *true_expr; + const expr_t *false_expr; +} ex_cond_t; + #define POINTER_VAL(p) (((p).def ? (p).def->offset : 0) + (p).val) typedef struct expr_s { @@ -364,6 +376,8 @@ typedef struct expr_s { ex_extend_t extend; ///< vector extend operation ex_multivec_t multivec; ///< geometric algebra multivector ex_type_t typ; ///< type expression + ex_incop_t incop; ///< incop expression + ex_cond_t cond; ///< ?: conditional expression }; } expr_t; @@ -872,6 +886,9 @@ expr_t *new_assign_expr (const expr_t *dst, const expr_t *src); expr_t *new_return_expr (const expr_t *ret_val); expr_t *new_adjstk_expr (int mode, int offset); expr_t *new_with_expr (int mode, int reg, const expr_t *val); +expr_t *new_incop_expr (int op, const expr_t *e, bool postop); +expr_t *new_cond_expr (const expr_t *test, const expr_t *true_expr, + const expr_t *false_expr); /** Create an expression of the correct type that references the specified parameter slot. @@ -1003,6 +1020,8 @@ void scatter_factors (const expr_t *prod, const expr_t **factors); const expr_t *gather_factors (const type_t *type, int op, const expr_t **factors, int count); +const expr_t *expr_process (const expr_t *expr); + ///@} #endif//__expr_h diff --git a/tools/qfcc/include/expr_names.h b/tools/qfcc/include/expr_names.h index 6061104fa..23492aa00 100644 --- a/tools/qfcc/include/expr_names.h +++ b/tools/qfcc/include/expr_names.h @@ -69,6 +69,8 @@ EX_EXPR(extend) ///< vector extend operation (::ex_extend_t) EX_EXPR(multivec) ///< geometric algebra multivector (::ex_multivec_t) EX_EXPR(list) ///< non-invasive list of expressions (::ex_list_t) EX_EXPR(type) ///< type expression for generics +EX_EXPR(incop) ///< pre or post increment/decrement (::ex_incop_t) +EX_EXPR(cond) ///< ?: conditional expression (::ex_cond_t) #undef EX_EXPR diff --git a/tools/qfcc/source/Makemodule.am b/tools/qfcc/source/Makemodule.am index e83365d02..7fa3eb954 100644 --- a/tools/qfcc/source/Makemodule.am +++ b/tools/qfcc/source/Makemodule.am @@ -36,6 +36,7 @@ qfcc_SOURCES = \ tools/qfcc/source/expr_dag.c \ tools/qfcc/source/expr_obj.c \ tools/qfcc/source/expr_optimize.c \ + tools/qfcc/source/expr_process.c \ tools/qfcc/source/expr_type.c \ tools/qfcc/source/expr_unary.c \ tools/qfcc/source/expr_vector.c \ diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 0e30a7d59..03cdc6087 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -206,6 +206,12 @@ get_type (const expr_t *e) return 0; case ex_type: return nullptr; + case ex_incop: + return get_type (e->incop.expr); + case ex_cond: + //FIXME true_expr and false_expr need to have the same type, + //unless one is nil + return get_type (e->cond.true_expr); case ex_count: internal_error (e, "invalid expression"); } @@ -1934,6 +1940,12 @@ has_function_call (const expr_t *e) } } return 0; + case ex_incop: + return has_function_call (e->incop.expr); + case ex_cond: + return (has_function_call (e->cond.test) + || has_function_call (e->cond.true_expr) + || has_function_call (e->cond.false_expr)); case ex_count: break; } @@ -2463,6 +2475,34 @@ conditional_expr (const expr_t *cond, const expr_t *e1, const expr_t *e2) return block; } +expr_t * +new_incop_expr (int op, const expr_t *e, bool postop) +{ + auto incop = new_expr (); + incop->type = ex_incop; + incop->incop = (ex_incop_t) { + .op = op, + .postop = postop, + .expr = e, + }; + return incop; +} + +expr_t * +new_cond_expr (const expr_t *test, const expr_t *true_expr, + const expr_t *false_expr) +{ + auto cond = new_expr (); + cond->type = ex_cond; + cond->cond = (ex_cond_t) { + .test = test, + .true_expr = true_expr, + .false_expr = false_expr, + }; + return cond; +} + + const expr_t * incop_expr (int op, const expr_t *e, int postop) { diff --git a/tools/qfcc/source/expr_assign.c b/tools/qfcc/source/expr_assign.c index f62da1b1c..9e96525dd 100644 --- a/tools/qfcc/source/expr_assign.c +++ b/tools/qfcc/source/expr_assign.c @@ -131,7 +131,11 @@ is_lvalue (const expr_t *expr) case ex_multivec: case ex_list: case ex_type: + case ex_incop: break; + case ex_cond: + return (is_lvalue (expr->cond.true_expr) + && is_lvalue (expr->cond.false_expr)); case ex_count: internal_error (expr, "invalid expression"); } diff --git a/tools/qfcc/source/expr_dag.c b/tools/qfcc/source/expr_dag.c index 52132ec88..b46b17583 100644 --- a/tools/qfcc/source/expr_dag.c +++ b/tools/qfcc/source/expr_dag.c @@ -78,6 +78,7 @@ edag_add_expr (const expr_t *expr) case ex_with: case ex_args: case ex_type: + case ex_incop: // these are never put in the dag return expr; case ex_list: @@ -181,6 +182,13 @@ edag_add_expr (const expr_t *expr) break; case ex_multivec: return expr; //FIXME ? + case ex_cond: + if (e->cond.test == expr->cond.test + && e->cond.true_expr == expr->cond.true_expr + && e->cond.false_expr == expr->cond.false_expr) { + return e; + } + break; } } DARRAY_APPEND (&expr_dag, expr); diff --git a/tools/qfcc/source/expr_process.c b/tools/qfcc/source/expr_process.c new file mode 100644 index 000000000..eb3e0b43d --- /dev/null +++ b/tools/qfcc/source/expr_process.c @@ -0,0 +1,115 @@ +/* + expr_process.c + + expression processing + + Copyright (C) 2024 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include + +#include "QF/fbsearch.h" +#include "QF/heapsort.h" +#include "QF/math/bitop.h" + +#include "tools/qfcc/include/algebra.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/rua-lang.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" +#include "tools/qfcc/include/value.h" + +typedef const expr_t *(*process_f) (const expr_t *expr); + +static const expr_t * +proc_expr (const expr_t *expr) +{ + auto e1 = expr_process (expr->expr.e1); + auto e2 = expr_process (expr->expr.e2); + if (is_error (e1)) { + return e1; + } + if (is_error (e2)) { + return e2; + } + + return binary_expr (expr->expr.op, e1, e2); +} + +static const expr_t * +proc_uexpr (const expr_t *expr) +{ + auto e1 = expr_process (expr->expr.e1); + if (is_error (e1)) { + return e1; + } + + return unary_expr (expr->expr.op, e1); +} + +static const expr_t * +proc_symbol (const expr_t *expr) +{ + return expr; +} + +static const expr_t * +proc_value (const expr_t *expr) +{ + return expr; +} + +static const expr_t * +proc_compound (const expr_t *expr) +{ + auto comp = new_compound_init (); + for (auto ele = expr->compound.head; ele; ele = ele->next) { + append_element (comp, new_element (expr_process (ele->expr), + ele->designator)); + } + return comp; +} + +const expr_t * +expr_process (const expr_t *expr) +{ + static process_f funcs[ex_count] = { + [ex_expr] = proc_expr, + [ex_uexpr] = proc_uexpr, + [ex_value] = proc_value, + [ex_compound] = proc_compound, + [ex_symbol] = proc_symbol, + }; + + if (expr->type >= ex_count) { + internal_error (expr, "bad sub-expression type: %d", expr->type); + } + if (!funcs[expr->type]) { + internal_error (expr, "unexpected sub-expression type: %s", + expr_names[expr->type]); + } + + return funcs[expr->type] (expr); +} diff --git a/tools/qfcc/source/glsl-declaration.c b/tools/qfcc/source/glsl-declaration.c index a22d85162..5351eea13 100644 --- a/tools/qfcc/source/glsl-declaration.c +++ b/tools/qfcc/source/glsl-declaration.c @@ -52,6 +52,9 @@ glsl_parse_declaration (specifier_t spec, symbol_t *sym, const type_t *array, spec.type = append_type (array, spec.type); spec.type = find_type (spec.type); } + if (init) { + init = expr_process (init); + } auto attributes = glsl_optimize_attributes (spec.attributes); if (sym && sym->sy_type == sy_expr) { auto id_list = sym->expr; diff --git a/tools/qfcc/source/glsl-parse.y b/tools/qfcc/source/glsl-parse.y index 26132d869..fedffde28 100644 --- a/tools/qfcc/source/glsl-parse.y +++ b/tools/qfcc/source/glsl-parse.y @@ -403,7 +403,7 @@ function_identifier unary_expression : postfix_expression | INCOP unary_expression { $$ = incop_expr ($1, $2, 0); } - | unary_operator unary_expression { $$ = unary_expr ($1, $2); } + | unary_operator unary_expression { $$ = new_unary_expr ($1, $2); } ; unary_operator @@ -417,15 +417,15 @@ multiplicative_expression : unary_expression | multiplicative_expression '*' unary_expression { - $$ = binary_expr ('*', $1, $3); + $$ = new_binary_expr ('*', $1, $3); } | multiplicative_expression '/' unary_expression { - $$ = binary_expr ('/', $1, $3); + $$ = new_binary_expr ('/', $1, $3); } | multiplicative_expression '%' unary_expression { - $$ = binary_expr ('%', $1, $3); + $$ = new_binary_expr ('%', $1, $3); } ; @@ -433,11 +433,11 @@ additive_expression : multiplicative_expression | additive_expression '+' multiplicative_expression { - $$ = binary_expr ('+', $1, $3); + $$ = new_binary_expr ('+', $1, $3); } | additive_expression '-' multiplicative_expression { - $$ = binary_expr ('-', $1, $3); + $$ = new_binary_expr ('-', $1, $3); } ; @@ -445,11 +445,11 @@ shift_expression : additive_expression | shift_expression SHL additive_expression { - $$ = binary_expr (QC_SHL, $1, $3); + $$ = new_binary_expr (QC_SHL, $1, $3); } | shift_expression SHR additive_expression { - $$ = binary_expr (QC_SHR, $1, $3); + $$ = new_binary_expr (QC_SHR, $1, $3); } ; @@ -457,19 +457,19 @@ relational_expression : shift_expression | relational_expression LT shift_expression { - $$ = binary_expr (QC_LT, $1, $3); + $$ = new_binary_expr (QC_LT, $1, $3); } | relational_expression GT shift_expression { - $$ = binary_expr (QC_GT, $1, $3); + $$ = new_binary_expr (QC_GT, $1, $3); } | relational_expression LE shift_expression { - $$ = binary_expr (QC_LE, $1, $3); + $$ = new_binary_expr (QC_LE, $1, $3); } | relational_expression GE shift_expression { - $$ = binary_expr (QC_GE, $1, $3); + $$ = new_binary_expr (QC_GE, $1, $3); } ; @@ -477,11 +477,11 @@ equality_expression : relational_expression | equality_expression EQ relational_expression { - $$ = binary_expr (QC_EQ, $1, $3); + $$ = new_binary_expr (QC_EQ, $1, $3); } | relational_expression NE relational_expression { - $$ = binary_expr (QC_NE, $1, $3); + $$ = new_binary_expr (QC_NE, $1, $3); } ; @@ -489,7 +489,7 @@ and_expression : equality_expression | and_expression '&' equality_expression { - $$ = binary_expr ('&', $1, $3); + $$ = new_binary_expr ('&', $1, $3); } ; @@ -497,7 +497,7 @@ exclusive_or_expression : and_expression | exclusive_or_expression '^' and_expression { - $$ = binary_expr ('^', $1, $3); + $$ = new_binary_expr ('^', $1, $3); } ; @@ -505,7 +505,7 @@ inclusive_or_expression : exclusive_or_expression | inclusive_or_expression '|' exclusive_or_expression { - $$ = binary_expr ('|', $1, $3); + $$ = new_binary_expr ('|', $1, $3); } ; @@ -545,11 +545,12 @@ assignment_expression : conditional_expression | unary_expression assignment_operator assignment_expression { - if ($2 == '=') { - $$ = assign_expr ($1, $3); - } else { - $$ = asx_expr ($2, $1, $3); + auto expr = $3; + if ($2 != '=') { + expr = paren_expr (expr); + expr = new_binary_expr ($2, $1, expr); } + $$ = new_assign_expr ($1, expr); } ;