[qfcc] Implement compound initializers for spir-v

They don't yet support designators, and vectors aren't treated the way I
want, but my little test works correctly.
This commit is contained in:
Bill Currie 2024-11-17 16:17:50 +09:00
parent 91a93d7803
commit 28e8697ae6
7 changed files with 163 additions and 21 deletions

View file

@ -89,6 +89,12 @@ typedef struct designator_s {
const expr_t *index; const expr_t *index;
} designator_t; } designator_t;
typedef struct {
const type_t *type;
symbol_t *field;
int offset;
} initstate_t;
typedef struct element_s { typedef struct element_s {
struct element_s *next; ///< next in chain struct element_s *next; ///< next in chain
int offset; int offset;
@ -567,8 +573,12 @@ expr_t *build_block_expr (expr_t *list, bool set_result);
designator_t *new_designator (const expr_t *field, const expr_t *index); designator_t *new_designator (const expr_t *field, const expr_t *index);
element_t *new_element (const expr_t *expr, designator_t *designator); element_t *new_element (const expr_t *expr, designator_t *designator);
expr_t *new_compound_init (void); expr_t *new_compound_init (void);
element_t *append_init_element (element_chain_t *element_chain,
element_t *element);
expr_t *append_element (expr_t *compound, element_t *element); expr_t *append_element (expr_t *compound, element_t *element);
expr_t *initialized_temp_expr (const type_t *type, const expr_t *compound); bool skip_field (symbol_t *field)__attribute__((pure));
const expr_t *initialized_temp_expr (const type_t *type,
const expr_t *compound);
void assign_elements (expr_t *local_expr, const expr_t *ptr, void assign_elements (expr_t *local_expr, const expr_t *ptr,
element_chain_t *element_chain); element_chain_t *element_chain);
void build_element_chain (element_chain_t *element_chain, const type_t *type, void build_element_chain (element_chain_t *element_chain, const type_t *type,

View file

@ -43,6 +43,8 @@ typedef struct {
symtab_t *symtab, expr_t *block); symtab_t *symtab, expr_t *block);
void (*vararg_int) (const expr_t *e); void (*vararg_int) (const expr_t *e);
const expr_t *(*initialized_temp) (const type_t *type, const expr_t *src);
unsigned label_id; unsigned label_id;
} target_t; } target_t;

View file

@ -62,6 +62,7 @@
#include "tools/qfcc/include/strpool.h" #include "tools/qfcc/include/strpool.h"
#include "tools/qfcc/include/struct.h" #include "tools/qfcc/include/struct.h"
#include "tools/qfcc/include/symtab.h" #include "tools/qfcc/include/symtab.h"
#include "tools/qfcc/include/target.h"
#include "tools/qfcc/include/type.h" #include "tools/qfcc/include/type.h"
#include "tools/qfcc/include/value.h" #include "tools/qfcc/include/value.h"
@ -316,12 +317,15 @@ assign_expr (const expr_t *dst, const expr_t *src)
const type_t *dst_type, *src_type; const type_t *dst_type, *src_type;
dst = convert_name (dst); dst = convert_name (dst);
if (dst->type == ex_error) { if (is_error (dst)) {
return dst; return dst;
} }
if ((expr = check_valid_lvalue (dst))) {
return expr; const expr_t *err;
if ((err = check_valid_lvalue (dst))) {
return err;
} }
if (is_reference (get_type (dst))) { if (is_reference (get_type (dst))) {
dst = pointer_deref (dst); dst = pointer_deref (dst);
} }
@ -332,7 +336,7 @@ assign_expr (const expr_t *dst, const expr_t *src)
if (src && !is_memset (src)) { if (src && !is_memset (src)) {
src = convert_name (src); src = convert_name (src);
if (src->type == ex_error) { if (is_error (src)) {
return src; return src;
} }
@ -347,8 +351,8 @@ assign_expr (const expr_t *dst, const expr_t *src)
src = new_nil_expr (); src = new_nil_expr ();
} }
if (src->type == ex_compound) { if (src->type == ex_compound) {
src = initialized_temp_expr (dst_type, src); src = current_target.initialized_temp (dst_type, src);
if (src->type == ex_error) { if (is_error (src)) {
return src; return src;
} }
} }
@ -370,7 +374,7 @@ assign_expr (const expr_t *dst, const expr_t *src)
// boolean expressions are chains of tests, so extract the result // boolean expressions are chains of tests, so extract the result
// of the tests // of the tests
src = convert_from_bool (src, dst_type); src = convert_from_bool (src, dst_type);
if (src->type == ex_error) { if (is_error (src)) {
return src; return src;
} }
src_type = get_type (src); src_type = get_type (src);

View file

@ -82,7 +82,7 @@ new_element (const expr_t *expr, designator_t *designator)
return element; return element;
} }
static element_t * element_t *
append_init_element (element_chain_t *element_chain, element_t *element) append_init_element (element_chain_t *element_chain, element_t *element)
{ {
element->next = 0; element->next = 0;
@ -143,12 +143,6 @@ designator_index (const designator_t *des, int ele_size, int array_count)
return index * ele_size; return index * ele_size;
} }
typedef struct {
const type_t *type;
symbol_t *field;
int offset;
} initstate_t;
static initstate_t static initstate_t
get_designated_offset (const type_t *type, const designator_t *des) get_designated_offset (const type_t *type, const designator_t *des)
{ {
@ -184,16 +178,16 @@ get_designated_offset (const type_t *type, const designator_t *des)
return (initstate_t) { .type = ele_type, .field = field, .offset = offset}; return (initstate_t) { .type = ele_type, .field = field, .offset = offset};
} }
static int bool
skip_field (symbol_t *field) skip_field (symbol_t *field)
{ {
if (field->sy_type != sy_offset) { if (field->sy_type != sy_offset) {
return 1; return true;
} }
if (field->no_auto_init) { if (field->no_auto_init) {
return 1; return true;
} }
return 0; return false;
} }
void void
@ -222,6 +216,7 @@ build_element_chain (element_chain_t *element_chain, const type_t *type,
} else if (is_struct (type) || is_union (type) } else if (is_struct (type) || is_union (type)
|| (is_nonscalar (type) && type->symtab)) { || (is_nonscalar (type) && type->symtab)) {
state.field = type->symtab->symbols; state.field = type->symtab->symbols;
// find first initializable field
while (state.field && skip_field (state.field)) { while (state.field && skip_field (state.field)) {
state.field = state.field->next; state.field = state.field->next;
} }
@ -362,7 +357,7 @@ assign_elements (expr_t *local_expr, const expr_t *init,
set_delete (initialized); set_delete (initialized);
} }
expr_t * const expr_t *
initialized_temp_expr (const type_t *type, const expr_t *expr) initialized_temp_expr (const type_t *type, const expr_t *expr)
{ {
if (expr->type == ex_compound && expr->compound.type) { if (expr->type == ex_compound && expr->compound.type) {

View file

@ -210,4 +210,5 @@ target_t ruamoko_target = {
.build_scope = ruamoko_build_scope, .build_scope = ruamoko_build_scope,
.build_code = ruamoko_build_code, .build_code = ruamoko_build_code,
.declare_sym = declare_def, .declare_sym = declare_def,
.initialized_temp = initialized_temp_expr,
}; };

View file

@ -40,6 +40,7 @@
#include "tools/qfcc/include/diagnostic.h" #include "tools/qfcc/include/diagnostic.h"
#include "tools/qfcc/include/function.h" #include "tools/qfcc/include/function.h"
#include "tools/qfcc/include/glsl-lang.h" #include "tools/qfcc/include/glsl-lang.h"
#include "tools/qfcc/include/options.h"
#include "tools/qfcc/include/qfcc.h" #include "tools/qfcc/include/qfcc.h"
#include "tools/qfcc/include/spirv.h" #include "tools/qfcc/include/spirv.h"
#include "tools/qfcc/include/statements.h" #include "tools/qfcc/include/statements.h"
@ -1120,6 +1121,32 @@ spirv_value (const expr_t *e, spirvctx_t *ctx)
return value->id; return value->id;
} }
static unsigned
spirv_compound (const expr_t *e, spirvctx_t *ctx)
{
int num_ele = 0;
for (auto ele = e->compound.head; ele; ele = ele->next) {
num_ele++;
}
unsigned ele_ids[num_ele];
int ind = 0;
for (auto ele = e->compound.head; ele; ele = ele->next) {
ele_ids[ind++] = spirv_emit_expr (ele->expr, ctx);
}
auto type = e->compound.type;
int tid = type_id (type, ctx);
int id = spirv_id (ctx);
auto insn = spirv_new_insn (SpvOpCompositeConstruct, 3 + num_ele,
ctx->code_space);
INSN (insn, 1) = tid;
INSN (insn, 2) = id;
for (int i = 0; i < num_ele; i++) {
INSN (insn, 3 + i) = ele_ids[i];
}
return id;
}
static unsigned static unsigned
spirv_assign (const expr_t *e, spirvctx_t *ctx) spirv_assign (const expr_t *e, spirvctx_t *ctx)
{ {
@ -1440,6 +1467,7 @@ spirv_emit_expr (const expr_t *e, spirvctx_t *ctx)
[ex_symbol] = spirv_symbol, [ex_symbol] = spirv_symbol,
[ex_temp] = spirv_temp,//FIXME don't want [ex_temp] = spirv_temp,//FIXME don't want
[ex_value] = spirv_value, [ex_value] = spirv_value,
[ex_compound] = spirv_compound,
[ex_assign] = spirv_assign, [ex_assign] = spirv_assign,
[ex_branch] = spirv_branch, [ex_branch] = spirv_branch,
[ex_return] = spirv_return, [ex_return] = spirv_return,
@ -1651,7 +1679,7 @@ spirv_declare_sym (specifier_t spec, const expr_t *init, symtab_t *symtab,
if (init) { if (init) {
if (!block && is_constexpr (init)) { if (!block && is_constexpr (init)) {
} else if (block) { } else if (block) {
auto r = pointer_deref (new_symbol_expr (sym)); auto r = new_symbol_expr (sym);
auto e = assign_expr (r, init); auto e = assign_expr (r, init);
append_expr (block, e); append_expr (block, e);
} else { } else {
@ -1661,9 +1689,109 @@ spirv_declare_sym (specifier_t spec, const expr_t *init, symtab_t *symtab,
} }
} }
static const expr_t *
spirv_build_element_chain (element_chain_t *element_chain, const type_t *type,
const expr_t *eles)
{
type = unalias_type (type);
initstate_t state = {};
if (is_struct (type) || (is_nonscalar (type) && type->symtab)) {
state.field = type->symtab->symbols;
// find first initializable field
while (state.field && skip_field (state.field)) {
state.field = state.field->next;
}
if (state.field) {
state.type = state.field->type;
state.offset = state.field->id;
}
} else if (is_matrix (type)) {
state.type = vector_type (base_type (type), type_rows (type));
} else if (is_nonscalar (type)) {
state.type = base_type (type);
} else if (is_array (type)) {
state.type = dereference_type (type);
} else {
return error (eles, "invalid initialization");
}
if (!state.type) {
return error (eles, "initialization of incomplete type");
}
for (auto ele = eles->compound.head; ele; ele = ele->next) {
//FIXME designated initializers
if (!state.type) {
return new_error_expr ();
}
// FIXME vectors are special (ie, check for overlaps)
if (state.offset >= type_count (type)) {
if (options.warnings.initializer) {
warning (eles, "excessive elements in initializer");
}
break;
}
if (ele->expr && ele->expr->type == ex_compound) {
const expr_t *err;
if ((err = spirv_build_element_chain (element_chain, state.type,
ele->expr))) {
return err;
}
} else {
auto element = new_element (nullptr, nullptr);
auto expr = ele->expr;
if (expr) {
expr = cast_expr (state.type, expr);
}
if (is_error (expr)) {
return expr;
}
*element = (element_t) {
.type = state.type,
.offset = state.offset,
.expr = expr,
};
append_init_element (element_chain, element);
}
state.offset += type_count (state.type);
if (state.field) {
state.field = state.field->next;
// find next initializable field
while (state.field && skip_field (state.field)) {
state.field = state.field->next;
}
if (state.field) {
state.type = state.field->type;
state.offset = state.field->id;
}
}
}
return nullptr;
}
static const expr_t *
spirv_initialized_temp (const type_t *type, const expr_t *src)
{
if (src->compound.type) {
type = src->compound.type;
}
scoped_src_loc (src);
auto new = new_compound_init ();
const expr_t *err;
if ((err = spirv_build_element_chain (&new->compound, type, src))) {
return err;
}
new->compound.type = type;
return new;
}
target_t spirv_target = { target_t spirv_target = {
.value_too_large = spirv_value_too_large, .value_too_large = spirv_value_too_large,
.build_scope = spirv_build_scope, .build_scope = spirv_build_scope,
.build_code = spirv_build_code, .build_code = spirv_build_code,
.declare_sym = spirv_declare_sym, .declare_sym = spirv_declare_sym,
.initialized_temp = spirv_initialized_temp,
}; };

View file

@ -145,6 +145,7 @@ target_t v6_target = {
.build_code = v6p_build_code, .build_code = v6p_build_code,
.declare_sym = declare_def, .declare_sym = declare_def,
.vararg_int = vararg_int, .vararg_int = vararg_int,
.initialized_temp = initialized_temp_expr,
}; };
target_t v6p_target = { target_t v6p_target = {
@ -153,4 +154,5 @@ target_t v6p_target = {
.build_code = v6p_build_code, .build_code = v6p_build_code,
.declare_sym = declare_def, .declare_sym = declare_def,
.vararg_int = vararg_int, .vararg_int = vararg_int,
.initialized_temp = initialized_temp_expr,
}; };