[qfcc] Implement vector expressions for spir-v

And fix a little goof with VectorShuffle (c&p coding bites again).
This commit is contained in:
Bill Currie 2024-11-18 14:55:32 +09:00
parent 39514e4f3d
commit 9b2240aaf8
6 changed files with 109 additions and 91 deletions

View file

@ -44,6 +44,7 @@ typedef struct {
void (*vararg_int) (const expr_t *e);
const expr_t *(*initialized_temp) (const type_t *type, const expr_t *src);
const expr_t *(*assign_vector) (const expr_t *dst, const expr_t *src);
unsigned label_id;
} target_t;

View file

@ -217,93 +217,6 @@ check_types_compatible (const expr_t *dst, const expr_t *src)
return type_mismatch (dst, src, '=');
}
static void
copy_qv_elements (expr_t *block, const expr_t *dst, const expr_t *src)
{
const expr_t *dx, *sx;
const expr_t *dy, *sy;
const expr_t *dz, *sz;
const expr_t *dw, *sw;
const expr_t *ds, *ss;
const expr_t *dv, *sv;
int count = list_count (&src->vector.list);
const expr_t *components[count];
list_scatter (&src->vector.list, components);
if (is_vector (src->vector.type)) {
// guaranteed to have three elements
sx = components[0];
sy = components[1];
sz = components[2];
dx = field_expr (dst, new_name_expr ("x"));
dy = field_expr (dst, new_name_expr ("y"));
dz = field_expr (dst, new_name_expr ("z"));
append_expr (block, assign_expr (dx, sx));
append_expr (block, assign_expr (dy, sy));
append_expr (block, assign_expr (dz, sz));
} else {
// guaranteed to have two or four elements
if (count == 4) {
// four vals: x, y, z, w
sx = components[0];
sy = components[1];
sz = components[2];
sw = components[3];
dx = field_expr (dst, new_name_expr ("x"));
dy = field_expr (dst, new_name_expr ("y"));
dz = field_expr (dst, new_name_expr ("z"));
dw = field_expr (dst, new_name_expr ("w"));
append_expr (block, assign_expr (dx, sx));
append_expr (block, assign_expr (dy, sy));
append_expr (block, assign_expr (dz, sz));
append_expr (block, assign_expr (dw, sw));
} else {
// v, s
sv = components[0];
ss = components[1];
dv = field_expr (dst, new_name_expr ("v"));
ds = field_expr (dst, new_name_expr ("s"));
append_expr (block, assign_expr (dv, sv));
append_expr (block, assign_expr (ds, ss));
}
}
}
static int
copy_elements (expr_t *block, const expr_t *dst, const expr_t *src, int base)
{
int index = 0;
for (auto li = src->vector.list.head; li; li = li->next) {
auto e = li->expr;
if (e->type == ex_vector) {
index += copy_elements (block, dst, e, index + base);
} else {
auto type = get_type (e);
auto dst_ele = new_offset_alias_expr (type, dst, index + base);
append_expr (block, assign_expr (dst_ele, e));
index += type_width (type);
}
}
return index;
}
static const expr_t *
assign_vector_expr (const expr_t *dst, const expr_t *src)
{
if (src->type == ex_vector && dst->type != ex_vector) {
expr_t *block = new_block_expr (0);
if (options.code.progsversion < PROG_VERSION) {
copy_qv_elements (block, dst, src);
} else {
copy_elements (block, dst, src, 0);
}
block->block.result = dst;
return block;
}
return 0;
}
static int __attribute__((pure))
is_memset (const expr_t *e)
{
@ -386,8 +299,8 @@ assign_expr (const expr_t *dst, const expr_t *src)
// check_types_compatible will take care of everything
return expr;
}
if ((expr = assign_vector_expr (dst, src))) {
return expr;
if (src->type == ex_vector) {
return current_target.assign_vector (dst, src);
}
} else {
src = convert_nil (src, dst_type);

View file

@ -105,7 +105,7 @@ new_vector_list (const expr_t *expr_list)
break;
case 3:
// shuffle any vectors to the beginning of the list (there should
// be only one, but futhre...)
// be only one, but future...)
for (int i = 1; i < count; i++) {
if (is_nonscalar (get_type (elements[i]))) {
auto t = elements[i];

View file

@ -205,10 +205,39 @@ ruamoko_build_code (function_t *func, const expr_t *statements)
defspace_alloc_aligned_highwater (space, 0, STACK_ALIGN);
}
static int
copy_elements (expr_t *block, const expr_t *dst, const expr_t *src, int base)
{
int index = 0;
for (auto li = src->vector.list.head; li; li = li->next) {
auto e = li->expr;
if (e->type == ex_vector) {
index += copy_elements (block, dst, e, index + base);
} else {
auto type = get_type (e);
auto dst_ele = new_offset_alias_expr (type, dst, index + base);
append_expr (block, assign_expr (dst_ele, e));
index += type_width (type);
}
}
return index;
}
static const expr_t *
ruamoko_assign_vector (const expr_t *dst, const expr_t *src)
{
expr_t *block = new_block_expr (0);
copy_elements (block, dst, src, 0);
block->block.result = dst;
return block;
}
target_t ruamoko_target = {
.value_too_large = ruamoko_value_too_large,
.build_scope = ruamoko_build_scope,
.build_code = ruamoko_build_code,
.declare_sym = declare_def,
.initialized_temp = initialized_temp_expr,
.assign_vector = ruamoko_assign_vector,
};

View file

@ -1266,7 +1266,7 @@ spirv_swizzle (const expr_t *e, spirvctx_t *ctx)
unsigned src_id = spirv_emit_expr (e->swizzle.src, ctx);
unsigned tid = type_id (e->swizzle.type, ctx);
unsigned id = spirv_id (ctx);
auto insn = spirv_new_insn (SpvOpVectorShuffle, 4 + count, ctx->code_space);
auto insn = spirv_new_insn (SpvOpVectorShuffle, 5 + count, ctx->code_space);
INSN (insn, 1) = tid;
INSN (insn, 2) = id;
INSN (insn, 3) = src_id;
@ -1822,10 +1822,29 @@ spirv_initialized_temp (const type_t *type, const expr_t *src)
return new;
}
static const expr_t *
spirv_assign_vector (const expr_t *dst, const expr_t *src)
{
int count = list_count (&src->vector.list);
const expr_t *elements[count];
list_scatter (&src->vector.list, elements);
scoped_src_loc (src);
auto new = new_compound_init ();
new->compound.type = src->vector.type;
for (int i = 0; i < count; i++) {
auto ele = new_element (elements[i], nullptr);
append_init_element (&new->compound, ele);
}
return new_assign_expr (dst, 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,
.assign_vector = spirv_assign_vector,
};

View file

@ -139,6 +139,60 @@ vararg_int (const expr_t *e)
}
}
static const expr_t *
v6p_assign_vector (const expr_t *dst, const expr_t *src)
{
expr_t *block = new_block_expr (0);
const expr_t *dx, *sx;
const expr_t *dy, *sy;
const expr_t *dz, *sz;
const expr_t *dw, *sw;
const expr_t *ds, *ss;
const expr_t *dv, *sv;
int count = list_count (&src->vector.list);
const expr_t *components[count];
list_scatter (&src->vector.list, components);
if (is_vector (src->vector.type)) {
// guaranteed to have three elements
sx = components[0];
sy = components[1];
sz = components[2];
dx = field_expr (dst, new_name_expr ("x"));
dy = field_expr (dst, new_name_expr ("y"));
dz = field_expr (dst, new_name_expr ("z"));
append_expr (block, assign_expr (dx, sx));
append_expr (block, assign_expr (dy, sy));
append_expr (block, assign_expr (dz, sz));
} else {
// guaranteed to have two or four elements
if (count == 4) {
// four vals: x, y, z, w
sx = components[0];
sy = components[1];
sz = components[2];
sw = components[3];
dx = field_expr (dst, new_name_expr ("x"));
dy = field_expr (dst, new_name_expr ("y"));
dz = field_expr (dst, new_name_expr ("z"));
dw = field_expr (dst, new_name_expr ("w"));
append_expr (block, assign_expr (dx, sx));
append_expr (block, assign_expr (dy, sy));
append_expr (block, assign_expr (dz, sz));
append_expr (block, assign_expr (dw, sw));
} else {
// v, s
sv = components[0];
ss = components[1];
dv = field_expr (dst, new_name_expr ("v"));
ds = field_expr (dst, new_name_expr ("s"));
append_expr (block, assign_expr (dv, sv));
append_expr (block, assign_expr (ds, ss));
}
}
return block;
}
target_t v6_target = {
.value_too_large = v6_value_too_large,
.build_scope = v6p_build_scope,
@ -146,6 +200,7 @@ target_t v6_target = {
.declare_sym = declare_def,
.vararg_int = vararg_int,
.initialized_temp = initialized_temp_expr,
.assign_vector = v6p_assign_vector,
};
target_t v6p_target = {
@ -155,4 +210,5 @@ target_t v6p_target = {
.declare_sym = declare_def,
.vararg_int = vararg_int,
.initialized_temp = initialized_temp_expr,
.assign_vector = v6p_assign_vector,
};