[qfcc] Implement specialization constants

And they even pass validation (though it turns out there's a bug in
glslangValidator regarding specialization constants with expressions (or
possibly spirv-val, but it seems to be the former as my bug report shows
signs of activity in that direction)).

https://github.com/KhronosGroup/glslang/issues/3748
This commit is contained in:
Bill Currie 2024-10-02 02:07:51 +09:00
parent a7639a685e
commit 56f8e19f63
6 changed files with 101 additions and 17 deletions

View file

@ -218,6 +218,7 @@ typedef struct ex_value_s {
const type_t *type; const type_t *type;
etype_t lltype; etype_t lltype;
unsigned id; unsigned id;
bool is_constexpr;
union { union {
uint8_t raw_value; ///< for memcpy uint8_t raw_value; ///< for memcpy
const char *string_val; ///< string constant const char *string_val; ///< string constant

View file

@ -65,6 +65,7 @@ typedef struct symbol_s {
vis_t visibility; ///< symbol visiblity. defaults to public vis_t visibility; ///< symbol visiblity. defaults to public
const char *name; ///< symbol name const char *name; ///< symbol name
sy_type_e sy_type; ///< symbol type sy_type_e sy_type; ///< symbol type
unsigned id;
const struct type_s *type; ///< type of object to which symbol refers const struct type_s *type; ///< type of object to which symbol refers
struct param_s *params; ///< the parameters if a function struct param_s *params; ///< the parameters if a function
bool no_auto_init:1; ///< skip for non-designated initializers bool no_auto_init:1; ///< skip for non-designated initializers

View file

@ -43,6 +43,7 @@ struct type_s;
struct pr_type_s; struct pr_type_s;
struct operand_s; struct operand_s;
struct ex_value_s *new_value (void);
struct ex_value_s *new_string_val (const char *string_val); struct ex_value_s *new_string_val (const char *string_val);
struct ex_value_s *new_double_val (double double_val); struct ex_value_s *new_double_val (double double_val);
struct ex_value_s *new_float_val (float float_val); struct ex_value_s *new_float_val (float float_val);

View file

@ -83,6 +83,16 @@ glsl_layout_constant_id (specifier_t spec, const expr_t *qual_name,
spec.sym->sy_type = sy_expr; spec.sym->sy_type = sy_expr;
spec.sym->expr = expr; spec.sym->expr = expr;
} }
if (spec.sym->sy_type == sy_expr && spec.sym->expr->type == ex_value) {
auto value = new_value ();
*value = *spec.sym->expr->value;
value->is_constexpr = true;
spec.sym->expr = new_value_expr (value, false);
} else {
error (spec.sym->expr,
"specialization constant must be a scalar literal");
return;
}
spec.sym->is_constexpr = true; spec.sym->is_constexpr = true;
const char *name = expr_string (qual_name); const char *name = expr_string (qual_name);
set_attribute (&spec.sym->attributes, name, val); set_attribute (&spec.sym->attributes, name, val);

View file

@ -34,6 +34,7 @@
#include "QF/quakeio.h" #include "QF/quakeio.h"
#include "tools/qfcc/include/attribute.h"
#include "tools/qfcc/include/def.h" #include "tools/qfcc/include/def.h"
#include "tools/qfcc/include/defspace.h" #include "tools/qfcc/include/defspace.h"
#include "tools/qfcc/include/diagnostic.h" #include "tools/qfcc/include/diagnostic.h"
@ -50,6 +51,7 @@ typedef struct spirvctx_s {
defspace_t *linkage; defspace_t *linkage;
defspace_t *strings; defspace_t *strings;
defspace_t *names; defspace_t *names;
defspace_t *annotations;
defspace_t *types; defspace_t *types;
defspace_t *code; defspace_t *code;
struct DARRAY_TYPE (unsigned) type_ids; struct DARRAY_TYPE (unsigned) type_ids;
@ -143,6 +145,22 @@ spirv_Name (unsigned id, const char *name, spirvctx_t *ctx)
memcpy (&D_var_o(int, def, 2), name, len); memcpy (&D_var_o(int, def, 2), name, len);
} }
static void
spirv_Decorate (unsigned id, SpvDecoration decoration, void *literal,
etype_t type, spirvctx_t *ctx)
{
if (type != ev_int) {
internal_error (0, "unexpected type");
}
int size = pr_type_size[type];
auto def = spirv_new_insn (SpvOpDecorate, 3 + size, ctx->annotations);
D_var_o(int, def, 1) = id;
D_var_o(int, def, 2) = decoration;
if (type == ev_int) {
D_var_o(int, def, 3) = *(int *)literal;
}
}
static void static void
spirv_MemberName (unsigned id, unsigned member, const char *name, spirv_MemberName (unsigned id, unsigned member, const char *name,
spirvctx_t *ctx) spirvctx_t *ctx)
@ -571,11 +589,19 @@ spirv_uexpr (const expr_t *e, spirvctx_t *ctx)
unsigned uid = spirv_emit_expr (e->expr.e1, ctx); unsigned uid = spirv_emit_expr (e->expr.e1, ctx);
unsigned tid = type_id (get_type (e), ctx); unsigned tid = type_id (get_type (e), ctx);
auto def = spirv_new_insn (spv_op->op, 4, ctx->types);
unsigned id; unsigned id;
if (e->expr.constant) {
auto def = spirv_new_insn (SpvOpSpecConstantOp, 5, ctx->types);
D_var_o(int, def, 1) = tid;
D_var_o(int, def, 2) = id = spirv_id (ctx);
D_var_o(int, def, 3) = spv_op->op;
D_var_o(int, def, 4) = uid;
} else {
auto def = spirv_new_insn (spv_op->op, 4, ctx->types);
D_var_o(int, def, 1) = tid; D_var_o(int, def, 1) = tid;
D_var_o(int, def, 2) = id = spirv_id (ctx); D_var_o(int, def, 2) = id = spirv_id (ctx);
D_var_o(int, def, 3) = uid; D_var_o(int, def, 3) = uid;
}
return id; return id;
} }
@ -603,15 +629,48 @@ spirv_expr (const expr_t *e, spirvctx_t *ctx)
unsigned bid2 = spirv_emit_expr (e->expr.e2, ctx); unsigned bid2 = spirv_emit_expr (e->expr.e2, ctx);
unsigned tid = type_id (get_type (e), ctx); unsigned tid = type_id (get_type (e), ctx);
auto def = spirv_new_insn (spv_op->op, 5, ctx->types);
unsigned id; unsigned id;
if (e->expr.constant) {
auto def = spirv_new_insn (SpvOpSpecConstantOp, 6, ctx->types);
D_var_o(int, def, 1) = tid;
D_var_o(int, def, 2) = id = spirv_id (ctx);
D_var_o(int, def, 3) = spv_op->op;
D_var_o(int, def, 4) = bid1;
D_var_o(int, def, 5) = bid2;
} else {
auto def = spirv_new_insn (spv_op->op, 5, ctx->types);
D_var_o(int, def, 1) = tid; D_var_o(int, def, 1) = tid;
D_var_o(int, def, 2) = id = spirv_id (ctx); D_var_o(int, def, 2) = id = spirv_id (ctx);
D_var_o(int, def, 3) = bid1; D_var_o(int, def, 3) = bid1;
D_var_o(int, def, 4) = bid2; D_var_o(int, def, 4) = bid2;
}
return id; return id;
} }
static unsigned
spirv_symbol (const expr_t *e, spirvctx_t *ctx)
{
auto sym = e->symbol;
if (sym->id) {
return sym->id;
}
if (sym->sy_type == sy_expr) {
sym->id = spirv_emit_expr (sym->expr, ctx);
spirv_Name (sym->id, sym->name, ctx);
for (auto attr = sym->attributes; attr; attr = attr->next) {
if (strcmp (attr->name, "constant_id") == 0) {
int specid = expr_integral (attr->params);
spirv_Decorate (sym->id, SpvDecorationSpecId,
&specid, ev_int, ctx);
}
}
} else {
internal_error (e, "unexpected symbol type: %s for %s",
symtype_str (sym->sy_type), sym->name);
}
return sym->id;
}
static unsigned static unsigned
spirv_value (const expr_t *e, spirvctx_t *ctx) spirv_value (const expr_t *e, spirvctx_t *ctx)
{ {
@ -635,6 +694,14 @@ spirv_value (const expr_t *e, spirvctx_t *ctx)
internal_error (e, "not implemented"); internal_error (e, "not implemented");
} }
} }
if (value->is_constexpr) {
op += SpvOpSpecConstantTrue - SpvOpConstantTrue;
}
if (op == SpvOpConstant && !val) {
auto def = spirv_new_insn (SpvOpConstantNull, 3, ctx->types);
D_var_o(int, def, 1) = tid;
D_var_o(int, def, 2) = value->id = spirv_id (ctx);
} else {
auto def = spirv_new_insn (op, 3 + val_size, ctx->types); auto def = spirv_new_insn (op, 3 + val_size, ctx->types);
D_var_o(int, def, 1) = tid; D_var_o(int, def, 1) = tid;
D_var_o(int, def, 2) = value->id = spirv_id (ctx); D_var_o(int, def, 2) = value->id = spirv_id (ctx);
@ -645,6 +712,7 @@ spirv_value (const expr_t *e, spirvctx_t *ctx)
D_var_o(int, def, 4) = val >> 32; D_var_o(int, def, 4) = val >> 32;
} }
} }
}
return value->id; return value->id;
} }
@ -654,6 +722,7 @@ spirv_emit_expr (const expr_t *e, spirvctx_t *ctx)
static spirv_expr_f funcs[ex_count] = { static spirv_expr_f funcs[ex_count] = {
[ex_expr] = spirv_expr, [ex_expr] = spirv_expr,
[ex_uexpr] = spirv_uexpr, [ex_uexpr] = spirv_uexpr,
[ex_symbol] = spirv_symbol,
[ex_value] = spirv_value, [ex_value] = spirv_value,
}; };
@ -681,6 +750,7 @@ spirv_write (struct pr_info_s *pr, const char *filename)
.linkage = defspace_new (ds_backed), .linkage = defspace_new (ds_backed),
.strings = defspace_new (ds_backed), .strings = defspace_new (ds_backed),
.names = defspace_new (ds_backed), .names = defspace_new (ds_backed),
.annotations = defspace_new (ds_backed),
.types = defspace_new (ds_backed), .types = defspace_new (ds_backed),
.code = defspace_new (ds_backed), .code = defspace_new (ds_backed),
.type_ids = DARRAY_STATIC_INIT (64), .type_ids = DARRAY_STATIC_INIT (64),
@ -733,6 +803,7 @@ spirv_write (struct pr_info_s *pr, const char *filename)
defspace_add_data (ctx.space, ctx.linkage->data, ctx.linkage->size); defspace_add_data (ctx.space, ctx.linkage->data, ctx.linkage->size);
defspace_add_data (ctx.space, ctx.strings->data, ctx.strings->size); defspace_add_data (ctx.space, ctx.strings->data, ctx.strings->size);
defspace_add_data (ctx.space, ctx.names->data, ctx.names->size); defspace_add_data (ctx.space, ctx.names->data, ctx.names->size);
defspace_add_data (ctx.space, ctx.annotations->data, ctx.annotations->size);
defspace_add_data (ctx.space, ctx.types->data, ctx.types->size); defspace_add_data (ctx.space, ctx.types->data, ctx.types->size);
defspace_add_data (ctx.space, ctx.code->data, ctx.code->size); defspace_add_data (ctx.space, ctx.code->data, ctx.code->size);

View file

@ -94,7 +94,7 @@ value_compare (const void *_val1, const void *_val2, void *unused)
return memcmp (&val1->raw_value, &val2->raw_value, value_size) == 0; return memcmp (&val1->raw_value, &val2->raw_value, value_size) == 0;
} }
static ex_value_t * ex_value_t *
new_value (void) new_value (void)
{ {
ex_value_t *value; ex_value_t *value;