mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-25 21:21:14 +00:00
[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.
This commit is contained in:
parent
e7710bb7ac
commit
8099c4cf8e
4 changed files with 72 additions and 4 deletions
|
@ -63,6 +63,7 @@ typedef struct ex_expr_s {
|
||||||
bool commutative; ///< e1 and e2 can be swapped
|
bool commutative; ///< e1 and e2 can be swapped
|
||||||
bool anticommute; ///< e1 and e2 can be swapped with negation
|
bool anticommute; ///< e1 and e2 can be swapped with negation
|
||||||
bool associative; ///< a op (b op c) == (a op b) op c
|
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 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 *e1; ///< left side of binary, sole of unary
|
||||||
const expr_t *e2; ///< right side of binary, null for 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.
|
/** 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.
|
\param e The expression to check.
|
||||||
\return True if the expression is constant.
|
\return True if the expression is constant.
|
||||||
*/
|
*/
|
||||||
int is_constant (const expr_t *e) __attribute__((pure));
|
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.
|
/** Check if the expression refers to a variable.
|
||||||
|
|
||||||
\param e The expression to check.
|
\param e The expression to check.
|
||||||
|
|
|
@ -568,6 +568,7 @@ new_binary_expr (int op, const expr_t *e1, const expr_t *e2)
|
||||||
expr_t *e = new_expr ();
|
expr_t *e = new_expr ();
|
||||||
e->type = ex_expr;
|
e->type = ex_expr;
|
||||||
e->nodag = e1->nodag | e2->nodag;
|
e->nodag = e1->nodag | e2->nodag;
|
||||||
|
e->expr.constant = is_constexpr (e1) && is_constexpr (e2);
|
||||||
e->expr.op = op;
|
e->expr.op = op;
|
||||||
e->expr.e1 = e1;
|
e->expr.e1 = e1;
|
||||||
e->expr.e2 = e2;
|
e->expr.e2 = e2;
|
||||||
|
@ -596,12 +597,13 @@ new_unary_expr (int op, const expr_t *e1)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (e1 && e1->type == ex_error) {
|
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 ();
|
expr_t *e = new_expr ();
|
||||||
e->type = ex_uexpr;
|
e->type = ex_uexpr;
|
||||||
e->nodag = e1->nodag;
|
e->nodag = e1->nodag;
|
||||||
|
e->expr.constant = is_constexpr (e1);
|
||||||
e->expr.op = op;
|
e->expr.op = op;
|
||||||
e->expr.e1 = e1;
|
e->expr.e1 = e1;
|
||||||
return e;
|
return e;
|
||||||
|
@ -970,6 +972,18 @@ is_constant (const expr_t *e)
|
||||||
return 0;
|
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
|
int
|
||||||
is_variable (const expr_t *e)
|
is_variable (const expr_t *e)
|
||||||
{
|
{
|
||||||
|
|
|
@ -45,6 +45,9 @@ void
|
||||||
glsl_parse_declaration (specifier_t spec, symbol_t *sym, const type_t *array,
|
glsl_parse_declaration (specifier_t spec, symbol_t *sym, const type_t *array,
|
||||||
const expr_t *init, symtab_t *symtab)
|
const expr_t *init, symtab_t *symtab)
|
||||||
{
|
{
|
||||||
|
if (sym->type) {
|
||||||
|
internal_error (0, "unexected typed symbol");
|
||||||
|
}
|
||||||
if (array) {
|
if (array) {
|
||||||
spec.type = append_type (array, spec.type);
|
spec.type = append_type (array, spec.type);
|
||||||
spec.type = find_type (spec.type);
|
spec.type = find_type (spec.type);
|
||||||
|
@ -66,8 +69,41 @@ glsl_parse_declaration (specifier_t spec, symbol_t *sym, const type_t *array,
|
||||||
} else {
|
} else {
|
||||||
spec.sym = sym;
|
spec.sym = sym;
|
||||||
if (spec.sym) {
|
if (spec.sym) {
|
||||||
|
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);
|
spec.sym = declare_symbol (spec, init, symtab);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
glsl_apply_attributes (attributes, spec);
|
glsl_apply_attributes (attributes, spec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,14 @@ glsl_layout_location (specifier_t spec, const expr_t *qual_name,
|
||||||
get_value_string (val->value));
|
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
|
static void
|
||||||
glsl_layout_binding (specifier_t spec, const expr_t *qual_name,
|
glsl_layout_binding (specifier_t spec, const expr_t *qual_name,
|
||||||
const expr_t *val)
|
const expr_t *val)
|
||||||
|
@ -466,7 +474,7 @@ static layout_qual_t layout_qualifiers[] = {
|
||||||
},
|
},
|
||||||
|
|
||||||
{ .name = "constant_id",
|
{ .name = "constant_id",
|
||||||
.apply = E(nullptr),
|
.apply = E(glsl_layout_constant_id),
|
||||||
.obj_mask = D(var),
|
.obj_mask = D(var),
|
||||||
.var_type = V(scalar),
|
.var_type = V(scalar),
|
||||||
},
|
},
|
||||||
|
@ -765,7 +773,7 @@ layout_check_qualifier (const layout_qual_t *qual, specifier_t spec)
|
||||||
&& qual->var_type != var_type) {
|
&& qual->var_type != var_type) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!(qual->if_mask & if_mask)) {
|
if (qual->if_mask != if_mask && !(qual->if_mask & if_mask)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (qual->stage_filter) {
|
if (qual->stage_filter) {
|
||||||
|
|
Loading…
Reference in a new issue