[qfcc] Implement cast and ?: expressions for spir-v

Unfortunately, there are some bugs with the result of comparisons
(getting int instead of bool in the spir-v).
This commit is contained in:
Bill Currie 2024-11-15 09:56:36 +09:00
parent 81cc736683
commit 7ad6aff928
4 changed files with 102 additions and 5 deletions

View file

@ -348,6 +348,25 @@ print_type_expr (dstring_t *dstr, const expr_t *e, int level, int id,
str, e->loc.line); str, e->loc.line);
} }
static void
print_cond (dstring_t *dstr, const expr_t *e, int level, int id,
const expr_t *next)
{
int indent = level * 2 + 2;
_print_expr (dstr, e->cond.test, level, id, next);
_print_expr (dstr, e->cond.true_expr, level, id, next);
_print_expr (dstr, e->cond.false_expr, level, id, next);
dasprintf (dstr, "%*se_%p -> \"e_%p\" [label=\"?\"];\n", indent, "", e,
e->cond.test);
dasprintf (dstr, "%*se_%p -> \"e_%p\" [label=\"t\"];\n", indent, "", e,
e->cond.true_expr);
dasprintf (dstr, "%*se_%p -> \"e_%p\" [label=\"f\"];\n", indent, "", e,
e->cond.false_expr);
dasprintf (dstr, "%*se_%p [label=\"%s\\n%d\"];\n", indent, "", e,
"?:", e->loc.line);
}
static void static void
print_field (dstring_t *dstr, const expr_t *e, int level, int id, print_field (dstring_t *dstr, const expr_t *e, int level, int id,
const expr_t *next) const expr_t *next)
@ -814,7 +833,7 @@ _print_expr (dstring_t *dstr, const expr_t *e, int level, int id,
[ex_list] = print_list, [ex_list] = print_list,
[ex_type] = print_type_expr, [ex_type] = print_type_expr,
[ex_incop] = nullptr, [ex_incop] = nullptr,
[ex_cond] = nullptr, [ex_cond] = print_cond,
[ex_field] = print_field, [ex_field] = print_field,
[ex_array] = nullptr, [ex_array] = nullptr,
[ex_decl] = nullptr, [ex_decl] = nullptr,

View file

@ -308,6 +308,15 @@ proc_return (const expr_t *expr)
} }
} }
static const expr_t *
proc_cond (const expr_t *expr)
{
auto test = expr_process (expr->cond.test);
auto true_expr = expr_process (expr->cond.true_expr);
auto false_expr = expr_process (expr->cond.false_expr);
return new_cond_expr (test, true_expr, false_expr);
}
static const expr_t * static const expr_t *
proc_decl (const expr_t *expr) proc_decl (const expr_t *expr)
{ {
@ -352,10 +361,9 @@ const expr_t *
expr_process (const expr_t *expr) expr_process (const expr_t *expr)
{ {
static process_f funcs[ex_count] = { static process_f funcs[ex_count] = {
[ex_block] = proc_block,
[ex_expr] = proc_expr, [ex_expr] = proc_expr,
[ex_uexpr] = proc_uexpr, [ex_uexpr] = proc_uexpr,
[ex_field] = proc_field,
[ex_block] = proc_block,
[ex_symbol] = proc_symbol, [ex_symbol] = proc_symbol,
[ex_vector] = proc_vector, [ex_vector] = proc_vector,
[ex_value] = proc_value, [ex_value] = proc_value,
@ -363,6 +371,8 @@ expr_process (const expr_t *expr)
[ex_assign] = proc_assign, [ex_assign] = proc_assign,
[ex_branch] = proc_branch, [ex_branch] = proc_branch,
[ex_return] = proc_return, [ex_return] = proc_return,
[ex_cond] = proc_cond,
[ex_field] = proc_field,
[ex_decl] = proc_decl, [ex_decl] = proc_decl,
}; };

View file

@ -595,7 +595,7 @@ conditional_expression
: logical_or_expression : logical_or_expression
| logical_or_expression '?' expression ':' assignment_expression | logical_or_expression '?' expression ':' assignment_expression
{ {
$$ = conditional_expr ($1, $3, $5); $$ = new_cond_expr ($1, $3, $5);
} }
; ;

View file

@ -657,7 +657,7 @@ static spvop_t spv_ops[] = {
{"eq", SpvOpIEqual, SPV_INT, SPV_INT }, {"eq", SpvOpIEqual, SPV_INT, SPV_INT },
{"eq", SpvOpFOrdEqual, SPV_FLOAT, SPV_FLOAT }, {"eq", SpvOpFOrdEqual, SPV_FLOAT, SPV_FLOAT },
{"eq", SpvOpFOrdNotEqual, SPV_FLOAT, SPV_FLOAT }, {"ne", SpvOpFOrdNotEqual, SPV_FLOAT, SPV_FLOAT },
{"ne", SpvOpINotEqual, SPV_INT, SPV_INT }, {"ne", SpvOpINotEqual, SPV_INT, SPV_INT },
{"le", SpvOpULessThanEqual, SPV_UINT, SPV_UINT }, {"le", SpvOpULessThanEqual, SPV_UINT, SPV_UINT },
{"le", SpvOpSLessThanEqual, SPV_SINT, SPV_SINT }, {"le", SpvOpSLessThanEqual, SPV_SINT, SPV_SINT },
@ -732,9 +732,57 @@ spirv_find_op (const char *op_name, etype_t type1, etype_t type2)
return nullptr; return nullptr;
} }
static unsigned
spirv_cast (const expr_t *e, spirvctx_t *ctx)
{
auto src_type = get_type (e->expr.e1);
auto dst_type = e->expr.type;
SpvOp op = 0;
if (is_real (src_type)) {
if (is_unsigned (dst_type)) {
op = SpvOpConvertFToU;
} else if (is_signed (dst_type)) {
op = SpvOpConvertFToS;
} else if (is_real (dst_type)) {
op = SpvOpFConvert;
}
} else if (is_real (dst_type)) {
if (is_unsigned (src_type)) {
op = SpvOpConvertUToF;
} else if (is_signed (src_type)) {
op = SpvOpConvertSToF;
}
} else if (is_unsigned (dst_type)) {
if (type_size (base_type (dst_type))
!= type_size (base_type (src_type))) {
op = SpvOpUConvert;
}
} else if (is_signed (dst_type)) {
if (type_size (base_type (dst_type))
!= type_size (base_type (src_type))) {
op = SpvOpSConvert;
}
}
if (!op) {
internal_error (e, "unexpected type combination");
}
unsigned cid = spirv_emit_expr (e->expr.e1, ctx);
unsigned tid = type_id (dst_type, ctx);
unsigned id = spirv_id (ctx);
auto insn = spirv_new_insn (op, 4, ctx->code_space);
INSN (insn, 1) = tid;
INSN (insn, 2) = id;
INSN (insn, 3) = cid;
return id;
}
static unsigned static unsigned
spirv_uexpr (const expr_t *e, spirvctx_t *ctx) spirv_uexpr (const expr_t *e, spirvctx_t *ctx)
{ {
if (e->expr.op == 'C') {
return spirv_cast (e, ctx);
}
auto op_name = convert_op (e->expr.op); auto op_name = convert_op (e->expr.op);
if (!op_name) { if (!op_name) {
if (e->expr.op > 32 && e->expr.op < 127) { if (e->expr.op > 32 && e->expr.op < 127) {
@ -1074,6 +1122,25 @@ spirv_extend (const expr_t *e, spirvctx_t *ctx)
return id; return id;
} }
static unsigned
spirv_cond (const expr_t *e, spirvctx_t *ctx)
{
unsigned test_id = spirv_emit_expr (e->cond.test, ctx);
unsigned true_id = spirv_emit_expr (e->cond.true_expr, ctx);
unsigned false_id = spirv_emit_expr (e->cond.false_expr, ctx);
auto type = get_type (e);
unsigned tid = type_id (type, ctx);
unsigned id = spirv_id (ctx);
auto insn = spirv_new_insn (SpvOpSelect, 6, ctx->code_space);
INSN (insn, 1) = tid;
INSN (insn, 2) = id;
INSN (insn, 3) = test_id;
INSN (insn, 4) = true_id;
INSN (insn, 5) = false_id;
return id;
}
static unsigned static unsigned
spirv_field (const expr_t *e, spirvctx_t *ctx) spirv_field (const expr_t *e, spirvctx_t *ctx)
{ {
@ -1145,6 +1212,7 @@ spirv_emit_expr (const expr_t *e, spirvctx_t *ctx)
[ex_branch] = spirv_branch, [ex_branch] = spirv_branch,
[ex_return] = spirv_return, [ex_return] = spirv_return,
[ex_extend] = spirv_extend, [ex_extend] = spirv_extend,
[ex_cond] = spirv_cond,
[ex_field] = spirv_field, [ex_field] = spirv_field,
}; };