[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.
This commit is contained in:
Bill Currie 2024-10-01 14:13:16 +09:00
parent a97fc8154a
commit fc4e8cb350
9 changed files with 214 additions and 21 deletions

View file

@ -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

View file

@ -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

View file

@ -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 \

View file

@ -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)
{

View file

@ -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");
}

View file

@ -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);

View file

@ -0,0 +1,115 @@
/*
expr_process.c
expression processing
Copyright (C) 2024 Bill Currie <bill@taniwha.org>
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 <string.h>
#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);
}

View file

@ -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;

View file

@ -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);
}
;