From 8099c4cf8e00a5bef217fc26e44a074dd98b638c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 22 Sep 2024 12:28:37 +0900 Subject: [PATCH] [qfcc] Support the idea of constexpr It's nowhere near complete, but unary and binary expressions that are marked as constant will not be subject to constant folding. This is necessary for proper support of specialization constants. --- tools/qfcc/include/expr.h | 10 ++++++++ tools/qfcc/source/expr.c | 16 +++++++++++- tools/qfcc/source/glsl-declaration.c | 38 +++++++++++++++++++++++++++- tools/qfcc/source/glsl-layout.c | 12 +++++++-- 4 files changed, 72 insertions(+), 4 deletions(-) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 134fd149b..0bac39688 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -63,6 +63,7 @@ typedef struct ex_expr_s { bool commutative; ///< e1 and e2 can be swapped bool anticommute; ///< e1 and e2 can be swapped with negation bool associative; ///< a op (b op c) == (a op b) op c + bool constant; ///< constant that has/will not been folded const type_t *type; ///< the type of the result of this expression const expr_t *e1; ///< left side of binary, sole of unary const expr_t *e2; ///< right side of binary, null for unary @@ -758,11 +759,20 @@ bool is_error (const expr_t *e) __attribute__((pure)); /** Check if the expression refers to a constant value. + This does not included computed constants that have not been folded. + \param e The expression to check. \return True if the expression is constant. */ int is_constant (const expr_t *e) __attribute__((pure)); +/** Check if the expression refers to a constant expression or value. + + \param e The expression to check. + \return True if the expression is constant. +*/ +bool is_constexpr (const expr_t *e) __attribute__((pure)); + /** Check if the expression refers to a variable. \param e The expression to check. diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 48bdb7809..d82a846f5 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -568,6 +568,7 @@ new_binary_expr (int op, const expr_t *e1, const expr_t *e2) expr_t *e = new_expr (); e->type = ex_expr; e->nodag = e1->nodag | e2->nodag; + e->expr.constant = is_constexpr (e1) && is_constexpr (e2); e->expr.op = op; e->expr.e1 = e1; e->expr.e2 = e2; @@ -596,12 +597,13 @@ new_unary_expr (int op, const expr_t *e1) { if (e1 && e1->type == ex_error) { - internal_error (e1, "error expr in new_binary_expr"); + internal_error (e1, "error expr in new_unary_expr"); } expr_t *e = new_expr (); e->type = ex_uexpr; e->nodag = e1->nodag; + e->expr.constant = is_constexpr (e1); e->expr.op = op; e->expr.e1 = e1; return e; @@ -970,6 +972,18 @@ is_constant (const expr_t *e) return 0; } +bool +is_constexpr (const expr_t *e) +{ + while (e->type == ex_alias) { + e = e->alias.expr; + } + if ((e->type == ex_expr || e->type == ex_uexpr) && e->expr.constant) { + return true; + } + return is_constant (e); +} + int is_variable (const expr_t *e) { diff --git a/tools/qfcc/source/glsl-declaration.c b/tools/qfcc/source/glsl-declaration.c index 3c6c52ecd..a22d85162 100644 --- a/tools/qfcc/source/glsl-declaration.c +++ b/tools/qfcc/source/glsl-declaration.c @@ -45,6 +45,9 @@ void glsl_parse_declaration (specifier_t spec, symbol_t *sym, const type_t *array, const expr_t *init, symtab_t *symtab) { + if (sym->type) { + internal_error (0, "unexected typed symbol"); + } if (array) { spec.type = append_type (array, spec.type); spec.type = find_type (spec.type); @@ -66,7 +69,40 @@ glsl_parse_declaration (specifier_t spec, symbol_t *sym, const type_t *array, } else { spec.sym = sym; if (spec.sym) { - spec.sym = declare_symbol (spec, init, symtab); + if (spec.is_const && !init) { + error (0, "uninitialized const %s", sym->name); + init = new_zero_expr (spec.type); + } + if (spec.is_const && init->type != ex_compound) { + auto type = get_type (init); + if (type != spec.type && type_assignable (spec.type, type)) { + if (!init->implicit && !type_promotes (spec.type, type)) { + warning (init, "initialization of %s with %s" + " (use a cast)\n)", + get_type_string (spec.type), + get_type_string (type)); + } + init = cast_expr (spec.type, init); + } + if (get_type (init) != spec.type) { + error (init, "type mismatch in initializer"); + init = new_zero_expr (spec.type); + } + if (!is_constexpr (init)) { + error (init, "non-constant initializer"); + init = new_zero_expr (spec.type); + } + sym->type = spec.type; + sym->sy_type = sy_expr; + sym->expr = init; + auto s = symtab_lookup (symtab, sym->name); + if (s && s->table == symtab) { + error (0, "%s redeclared", sym->name); + } + symtab_addsymbol (symtab, sym); + } else { + spec.sym = declare_symbol (spec, init, symtab); + } } glsl_apply_attributes (attributes, spec); } diff --git a/tools/qfcc/source/glsl-layout.c b/tools/qfcc/source/glsl-layout.c index f994883af..c48d4a91f 100644 --- a/tools/qfcc/source/glsl-layout.c +++ b/tools/qfcc/source/glsl-layout.c @@ -60,6 +60,14 @@ glsl_layout_location (specifier_t spec, const expr_t *qual_name, get_value_string (val->value)); } +static void +glsl_layout_constant_id (specifier_t spec, const expr_t *qual_name, + const expr_t *val) +{ + notice (qual_name, "%s %s", expr_string (qual_name), + get_value_string (val->value)); +} + static void glsl_layout_binding (specifier_t spec, const expr_t *qual_name, const expr_t *val) @@ -466,7 +474,7 @@ static layout_qual_t layout_qualifiers[] = { }, { .name = "constant_id", - .apply = E(nullptr), + .apply = E(glsl_layout_constant_id), .obj_mask = D(var), .var_type = V(scalar), }, @@ -765,7 +773,7 @@ layout_check_qualifier (const layout_qual_t *qual, specifier_t spec) && qual->var_type != var_type) { return false; } - if (!(qual->if_mask & if_mask)) { + if (qual->if_mask != if_mask && !(qual->if_mask & if_mask)) { return false; } if (qual->stage_filter) {