From 7ad6aff92826ba5831c367383442de3d5e1d5239 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 15 Nov 2024 09:56:36 +0900 Subject: [PATCH] [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). --- tools/qfcc/source/dot_expr.c | 21 +++++++++- tools/qfcc/source/expr_process.c | 14 ++++++- tools/qfcc/source/glsl-parse.y | 2 +- tools/qfcc/source/target_spirv.c | 70 +++++++++++++++++++++++++++++++- 4 files changed, 102 insertions(+), 5 deletions(-) diff --git a/tools/qfcc/source/dot_expr.c b/tools/qfcc/source/dot_expr.c index 4243fd4a1..5b61c4d32 100644 --- a/tools/qfcc/source/dot_expr.c +++ b/tools/qfcc/source/dot_expr.c @@ -348,6 +348,25 @@ print_type_expr (dstring_t *dstr, const expr_t *e, int level, int id, 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 print_field (dstring_t *dstr, const expr_t *e, int level, int id, 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_type] = print_type_expr, [ex_incop] = nullptr, - [ex_cond] = nullptr, + [ex_cond] = print_cond, [ex_field] = print_field, [ex_array] = nullptr, [ex_decl] = nullptr, diff --git a/tools/qfcc/source/expr_process.c b/tools/qfcc/source/expr_process.c index 99e42e486..46a3abd97 100644 --- a/tools/qfcc/source/expr_process.c +++ b/tools/qfcc/source/expr_process.c @@ -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 * proc_decl (const expr_t *expr) { @@ -352,10 +361,9 @@ const expr_t * expr_process (const expr_t *expr) { static process_f funcs[ex_count] = { + [ex_block] = proc_block, [ex_expr] = proc_expr, [ex_uexpr] = proc_uexpr, - [ex_field] = proc_field, - [ex_block] = proc_block, [ex_symbol] = proc_symbol, [ex_vector] = proc_vector, [ex_value] = proc_value, @@ -363,6 +371,8 @@ expr_process (const expr_t *expr) [ex_assign] = proc_assign, [ex_branch] = proc_branch, [ex_return] = proc_return, + [ex_cond] = proc_cond, + [ex_field] = proc_field, [ex_decl] = proc_decl, }; diff --git a/tools/qfcc/source/glsl-parse.y b/tools/qfcc/source/glsl-parse.y index bae8e560e..eb00310ca 100644 --- a/tools/qfcc/source/glsl-parse.y +++ b/tools/qfcc/source/glsl-parse.y @@ -595,7 +595,7 @@ conditional_expression : logical_or_expression | logical_or_expression '?' expression ':' assignment_expression { - $$ = conditional_expr ($1, $3, $5); + $$ = new_cond_expr ($1, $3, $5); } ; diff --git a/tools/qfcc/source/target_spirv.c b/tools/qfcc/source/target_spirv.c index 0af757ee2..55b9b35c1 100644 --- a/tools/qfcc/source/target_spirv.c +++ b/tools/qfcc/source/target_spirv.c @@ -657,7 +657,7 @@ static spvop_t spv_ops[] = { {"eq", SpvOpIEqual, SPV_INT, SPV_INT }, {"eq", SpvOpFOrdEqual, SPV_FLOAT, SPV_FLOAT }, - {"eq", SpvOpFOrdNotEqual, SPV_FLOAT, SPV_FLOAT }, + {"ne", SpvOpFOrdNotEqual, SPV_FLOAT, SPV_FLOAT }, {"ne", SpvOpINotEqual, SPV_INT, SPV_INT }, {"le", SpvOpULessThanEqual, SPV_UINT, SPV_UINT }, {"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; } +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 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); if (!op_name) { if (e->expr.op > 32 && e->expr.op < 127) { @@ -1074,6 +1122,25 @@ spirv_extend (const expr_t *e, spirvctx_t *ctx) 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 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_return] = spirv_return, [ex_extend] = spirv_extend, + [ex_cond] = spirv_cond, [ex_field] = spirv_field, };