mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-25 05:01:24 +00:00
[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:
parent
91a93d7803
commit
28e8697ae6
7 changed files with 163 additions and 21 deletions
|
@ -89,6 +89,12 @@ typedef struct designator_s {
|
|||
const expr_t *index;
|
||||
} designator_t;
|
||||
|
||||
typedef struct {
|
||||
const type_t *type;
|
||||
symbol_t *field;
|
||||
int offset;
|
||||
} initstate_t;
|
||||
|
||||
typedef struct element_s {
|
||||
struct element_s *next; ///< next in chain
|
||||
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);
|
||||
element_t *new_element (const expr_t *expr, designator_t *designator);
|
||||
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 *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,
|
||||
element_chain_t *element_chain);
|
||||
void build_element_chain (element_chain_t *element_chain, const type_t *type,
|
||||
|
|
|
@ -43,6 +43,8 @@ typedef struct {
|
|||
symtab_t *symtab, expr_t *block);
|
||||
void (*vararg_int) (const expr_t *e);
|
||||
|
||||
const expr_t *(*initialized_temp) (const type_t *type, const expr_t *src);
|
||||
|
||||
unsigned label_id;
|
||||
} target_t;
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@
|
|||
#include "tools/qfcc/include/strpool.h"
|
||||
#include "tools/qfcc/include/struct.h"
|
||||
#include "tools/qfcc/include/symtab.h"
|
||||
#include "tools/qfcc/include/target.h"
|
||||
#include "tools/qfcc/include/type.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;
|
||||
|
||||
dst = convert_name (dst);
|
||||
if (dst->type == ex_error) {
|
||||
if (is_error (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))) {
|
||||
dst = pointer_deref (dst);
|
||||
}
|
||||
|
@ -332,7 +336,7 @@ assign_expr (const expr_t *dst, const expr_t *src)
|
|||
|
||||
if (src && !is_memset (src)) {
|
||||
src = convert_name (src);
|
||||
if (src->type == ex_error) {
|
||||
if (is_error (src)) {
|
||||
return src;
|
||||
}
|
||||
|
||||
|
@ -347,8 +351,8 @@ assign_expr (const expr_t *dst, const expr_t *src)
|
|||
src = new_nil_expr ();
|
||||
}
|
||||
if (src->type == ex_compound) {
|
||||
src = initialized_temp_expr (dst_type, src);
|
||||
if (src->type == ex_error) {
|
||||
src = current_target.initialized_temp (dst_type, src);
|
||||
if (is_error (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
|
||||
// of the tests
|
||||
src = convert_from_bool (src, dst_type);
|
||||
if (src->type == ex_error) {
|
||||
if (is_error (src)) {
|
||||
return src;
|
||||
}
|
||||
src_type = get_type (src);
|
||||
|
|
|
@ -82,7 +82,7 @@ new_element (const expr_t *expr, designator_t *designator)
|
|||
return element;
|
||||
}
|
||||
|
||||
static element_t *
|
||||
element_t *
|
||||
append_init_element (element_chain_t *element_chain, element_t *element)
|
||||
{
|
||||
element->next = 0;
|
||||
|
@ -143,12 +143,6 @@ designator_index (const designator_t *des, int ele_size, int array_count)
|
|||
return index * ele_size;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const type_t *type;
|
||||
symbol_t *field;
|
||||
int offset;
|
||||
} initstate_t;
|
||||
|
||||
static initstate_t
|
||||
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};
|
||||
}
|
||||
|
||||
static int
|
||||
bool
|
||||
skip_field (symbol_t *field)
|
||||
{
|
||||
if (field->sy_type != sy_offset) {
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
if (field->no_auto_init) {
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
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)
|
||||
|| (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;
|
||||
}
|
||||
|
@ -362,7 +357,7 @@ assign_elements (expr_t *local_expr, const expr_t *init,
|
|||
set_delete (initialized);
|
||||
}
|
||||
|
||||
expr_t *
|
||||
const expr_t *
|
||||
initialized_temp_expr (const type_t *type, const expr_t *expr)
|
||||
{
|
||||
if (expr->type == ex_compound && expr->compound.type) {
|
||||
|
|
|
@ -210,4 +210,5 @@ target_t ruamoko_target = {
|
|||
.build_scope = ruamoko_build_scope,
|
||||
.build_code = ruamoko_build_code,
|
||||
.declare_sym = declare_def,
|
||||
.initialized_temp = initialized_temp_expr,
|
||||
};
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "tools/qfcc/include/diagnostic.h"
|
||||
#include "tools/qfcc/include/function.h"
|
||||
#include "tools/qfcc/include/glsl-lang.h"
|
||||
#include "tools/qfcc/include/options.h"
|
||||
#include "tools/qfcc/include/qfcc.h"
|
||||
#include "tools/qfcc/include/spirv.h"
|
||||
#include "tools/qfcc/include/statements.h"
|
||||
|
@ -1120,6 +1121,32 @@ spirv_value (const expr_t *e, spirvctx_t *ctx)
|
|||
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
|
||||
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_temp] = spirv_temp,//FIXME don't want
|
||||
[ex_value] = spirv_value,
|
||||
[ex_compound] = spirv_compound,
|
||||
[ex_assign] = spirv_assign,
|
||||
[ex_branch] = spirv_branch,
|
||||
[ex_return] = spirv_return,
|
||||
|
@ -1651,7 +1679,7 @@ spirv_declare_sym (specifier_t spec, const expr_t *init, symtab_t *symtab,
|
|||
if (init) {
|
||||
if (!block && is_constexpr (init)) {
|
||||
} else if (block) {
|
||||
auto r = pointer_deref (new_symbol_expr (sym));
|
||||
auto r = new_symbol_expr (sym);
|
||||
auto e = assign_expr (r, init);
|
||||
append_expr (block, e);
|
||||
} 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 = {
|
||||
.value_too_large = spirv_value_too_large,
|
||||
.build_scope = spirv_build_scope,
|
||||
.build_code = spirv_build_code,
|
||||
.declare_sym = spirv_declare_sym,
|
||||
.initialized_temp = spirv_initialized_temp,
|
||||
};
|
||||
|
|
|
@ -145,6 +145,7 @@ target_t v6_target = {
|
|||
.build_code = v6p_build_code,
|
||||
.declare_sym = declare_def,
|
||||
.vararg_int = vararg_int,
|
||||
.initialized_temp = initialized_temp_expr,
|
||||
};
|
||||
|
||||
target_t v6p_target = {
|
||||
|
@ -153,4 +154,5 @@ target_t v6p_target = {
|
|||
.build_code = v6p_build_code,
|
||||
.declare_sym = declare_def,
|
||||
.vararg_int = vararg_int,
|
||||
.initialized_temp = initialized_temp_expr,
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue