mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-25 13:11:00 +00:00
[qfcc] Implement select (if) constructs
And break/continue too, since my test for them required select.
This commit is contained in:
parent
93d116cf16
commit
a7f9d96a02
4 changed files with 104 additions and 37 deletions
|
@ -71,11 +71,11 @@ typedef struct ex_expr_s {
|
||||||
|
|
||||||
typedef struct ex_label_s {
|
typedef struct ex_label_s {
|
||||||
struct ex_label_s *next;
|
struct ex_label_s *next;
|
||||||
struct reloc_s *refs; ///< relocations associated with this label
|
|
||||||
struct sblock_s *dest; ///< the location of this label if known
|
struct sblock_s *dest; ///< the location of this label if known
|
||||||
const char *name; ///< the name of this label
|
const char *name; ///< the name of this label
|
||||||
struct symbol_s *symbol; ///< symbol used to define this label (maybe 0)
|
struct symbol_s *symbol; ///< symbol used to define this label (maybe 0)
|
||||||
int used; ///< label is used as a target
|
int used; ///< label is used as a target
|
||||||
|
unsigned id;
|
||||||
struct daglabel_s *daglabel;
|
struct daglabel_s *daglabel;
|
||||||
} ex_label_t;
|
} ex_label_t;
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,8 @@ typedef struct {
|
||||||
void (*declare_sym) (specifier_t spec, const expr_t *init,
|
void (*declare_sym) (specifier_t spec, const expr_t *init,
|
||||||
symtab_t *symtab, expr_t *block);
|
symtab_t *symtab, expr_t *block);
|
||||||
void (*vararg_int) (const expr_t *e);
|
void (*vararg_int) (const expr_t *e);
|
||||||
|
|
||||||
|
unsigned label_id;
|
||||||
} target_t;
|
} target_t;
|
||||||
|
|
||||||
extern target_t current_target;
|
extern target_t current_target;
|
||||||
|
|
|
@ -63,6 +63,7 @@
|
||||||
#include "tools/qfcc/include/strpool.h"
|
#include "tools/qfcc/include/strpool.h"
|
||||||
#include "tools/qfcc/include/struct.h"
|
#include "tools/qfcc/include/struct.h"
|
||||||
#include "tools/qfcc/include/symtab.h"
|
#include "tools/qfcc/include/symtab.h"
|
||||||
|
#include "tools/qfcc/include/target.h"
|
||||||
#include "tools/qfcc/include/type.h"
|
#include "tools/qfcc/include/type.h"
|
||||||
#include "tools/qfcc/include/value.h"
|
#include "tools/qfcc/include/value.h"
|
||||||
|
|
||||||
|
@ -515,6 +516,7 @@ new_label_expr (void)
|
||||||
|
|
||||||
l->type = ex_label;
|
l->type = ex_label;
|
||||||
l->label.name = new_label_name ();
|
l->label.name = new_label_name ();
|
||||||
|
l->label.id = current_target.label_id++;
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,9 +59,16 @@ typedef struct spirvctx_s {
|
||||||
defspace_t *code_space;
|
defspace_t *code_space;
|
||||||
|
|
||||||
struct DARRAY_TYPE (unsigned) type_ids;
|
struct DARRAY_TYPE (unsigned) type_ids;
|
||||||
|
struct DARRAY_TYPE (unsigned) label_ids;
|
||||||
unsigned id;
|
unsigned id;
|
||||||
} spirvctx_t;
|
} spirvctx_t;
|
||||||
|
|
||||||
|
static unsigned
|
||||||
|
spirv_id (spirvctx_t *ctx)
|
||||||
|
{
|
||||||
|
return ++ctx->id;
|
||||||
|
}
|
||||||
|
|
||||||
static unsigned
|
static unsigned
|
||||||
spirv_type_id (const type_t *type, spirvctx_t *ctx)
|
spirv_type_id (const type_t *type, spirvctx_t *ctx)
|
||||||
{
|
{
|
||||||
|
@ -84,6 +91,42 @@ spirv_add_type_id (const type_t *type, unsigned id, spirvctx_t *ctx)
|
||||||
ctx->type_ids.a[type->id] = id;
|
ctx->type_ids.a[type->id] = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned
|
||||||
|
spirv_label_id (const ex_label_t *label, spirvctx_t *ctx)
|
||||||
|
{
|
||||||
|
if (label->id < ctx->label_ids.size && ctx->label_ids.a[label->id]) {
|
||||||
|
return ctx->label_ids.a[label->id];
|
||||||
|
}
|
||||||
|
unsigned id = spirv_id (ctx);
|
||||||
|
if (label->id >= ctx->label_ids.size) {
|
||||||
|
size_t base = ctx->label_ids.size;
|
||||||
|
DARRAY_RESIZE (&ctx->label_ids, label->id + 1);
|
||||||
|
while (base < label->id + 1) {
|
||||||
|
ctx->label_ids.a[base++] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx->label_ids.a[label->id] = id;
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
is_block_terminated (defspace_t *code_space)
|
||||||
|
{
|
||||||
|
def_t *last_insn = nullptr;
|
||||||
|
if (code_space->def_tail != &code_space->defs) {
|
||||||
|
last_insn = (def_t *) code_space->def_tail;
|
||||||
|
}
|
||||||
|
if (last_insn
|
||||||
|
&& ((INSN(last_insn, 0) & SpvOpCodeMask) == SpvOpReturn
|
||||||
|
|| (INSN(last_insn, 0) & SpvOpCodeMask) == SpvOpReturnValue
|
||||||
|
|| (INSN(last_insn, 0) & SpvOpCodeMask) == SpvOpUnreachable
|
||||||
|
|| (INSN(last_insn, 0) & SpvOpCodeMask) == SpvOpBranchConditional
|
||||||
|
|| (INSN(last_insn, 0) & SpvOpCodeMask) == SpvOpBranch)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static def_t *
|
static def_t *
|
||||||
spirv_new_insn (int op, int size, defspace_t *space)
|
spirv_new_insn (int op, int size, defspace_t *space)
|
||||||
{
|
{
|
||||||
|
@ -106,12 +149,6 @@ spirv_str_insn (int op, int offs, int extra, const char *str, defspace_t *space)
|
||||||
return insn;
|
return insn;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned
|
|
||||||
spirv_id (spirvctx_t *ctx)
|
|
||||||
{
|
|
||||||
return ++ctx->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
spirv_Capability (SpvCapability capability, defspace_t *space)
|
spirv_Capability (SpvCapability capability, defspace_t *space)
|
||||||
{
|
{
|
||||||
|
@ -461,6 +498,14 @@ spirv_LoopMerge (unsigned merge, unsigned cont, spirvctx_t *ctx)
|
||||||
INSN (insn, 3) = SpvLoopControlMaskNone;
|
INSN (insn, 3) = SpvLoopControlMaskNone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
spirv_SelectionMerge (unsigned merge, spirvctx_t *ctx)
|
||||||
|
{
|
||||||
|
auto insn = spirv_new_insn (SpvOpSelectionMerge, 3, ctx->code_space);
|
||||||
|
INSN (insn, 1) = merge;
|
||||||
|
INSN (insn, 2) = SpvSelectionControlMaskNone;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
spirv_Branch (unsigned label, spirvctx_t *ctx)
|
spirv_Branch (unsigned label, spirvctx_t *ctx)
|
||||||
{
|
{
|
||||||
|
@ -483,13 +528,13 @@ spirv_SplitBlock (spirvctx_t *ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
spirv_BranchConditional (unsigned test, unsigned true_label,
|
spirv_BranchConditional (bool not, unsigned test, unsigned true_label,
|
||||||
unsigned false_label, spirvctx_t *ctx)
|
unsigned false_label, spirvctx_t *ctx)
|
||||||
{
|
{
|
||||||
auto insn = spirv_new_insn (SpvOpBranchConditional, 4, ctx->code_space);
|
auto insn = spirv_new_insn (SpvOpBranchConditional, 4, ctx->code_space);
|
||||||
INSN (insn, 1) = test;
|
INSN (insn, 1) = test;
|
||||||
INSN (insn, 2) = true_label;
|
INSN (insn, 2) = not ? false_label : true_label;
|
||||||
INSN (insn, 3) = false_label;
|
INSN (insn, 3) = not ? true_label : false_label;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -639,14 +684,7 @@ spirv_function (function_t *func, spirvctx_t *ctx)
|
||||||
if (func->exprs) {
|
if (func->exprs) {
|
||||||
spirv_emit_expr (func->exprs, ctx);
|
spirv_emit_expr (func->exprs, ctx);
|
||||||
}
|
}
|
||||||
def_t *last_insn = nullptr;
|
if (!is_block_terminated (ctx->code_space)) {
|
||||||
if (ctx->code_space->def_tail != &ctx->code_space->defs) {
|
|
||||||
last_insn = (def_t *) ctx->code_space->def_tail;
|
|
||||||
}
|
|
||||||
if (!last_insn
|
|
||||||
|| ((INSN(last_insn, 0) & SpvOpCodeMask) != SpvOpReturn
|
|
||||||
&& (INSN(last_insn, 0) & SpvOpCodeMask) != SpvOpReturnValue
|
|
||||||
&& (INSN(last_insn, 0) & SpvOpCodeMask) != SpvOpUnreachable)) {
|
|
||||||
if (is_void (ret_type)) {
|
if (is_void (ret_type)) {
|
||||||
spirv_new_insn (SpvOpReturn, 1, ctx->code_space);
|
spirv_new_insn (SpvOpReturn, 1, ctx->code_space);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1160,14 +1198,25 @@ spirv_call (const expr_t *call, spirvctx_t *ctx)
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned
|
||||||
|
spirv_jump (const expr_t *e, spirvctx_t *ctx)
|
||||||
|
{
|
||||||
|
auto target_label = &e->branch.target->label;
|
||||||
|
unsigned target = spirv_label_id (target_label, ctx);
|
||||||
|
spirv_Branch (target, ctx);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static unsigned
|
static unsigned
|
||||||
spirv_branch (const expr_t *e, spirvctx_t *ctx)
|
spirv_branch (const expr_t *e, spirvctx_t *ctx)
|
||||||
{
|
{
|
||||||
if (e->branch.type == pr_branch_call) {
|
if (e->branch.type == pr_branch_call) {
|
||||||
return spirv_call (e, ctx);
|
return spirv_call (e, ctx);
|
||||||
}
|
}
|
||||||
//FIXME
|
if (e->branch.type == pr_branch_jump) {
|
||||||
return 1;
|
return spirv_jump (e, ctx);
|
||||||
|
}
|
||||||
|
internal_error (e, "unexpected branch");
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned
|
static unsigned
|
||||||
|
@ -1324,35 +1373,26 @@ spirv_field (const expr_t *e, spirvctx_t *ctx)
|
||||||
static unsigned
|
static unsigned
|
||||||
spirv_loop (const expr_t *e, spirvctx_t *ctx)
|
spirv_loop (const expr_t *e, spirvctx_t *ctx)
|
||||||
{
|
{
|
||||||
unsigned loop = spirv_id (ctx);
|
auto break_label = &e->loop.break_label->label;
|
||||||
unsigned merge = spirv_id (ctx);
|
auto continue_label = &e->loop.continue_label->label;
|
||||||
unsigned cont = spirv_id (ctx);
|
unsigned merge = spirv_label_id (break_label, ctx);
|
||||||
spirv_Branch (loop, ctx);
|
unsigned cont = spirv_label_id (continue_label, ctx);
|
||||||
spirv_LabelId (loop, ctx);
|
|
||||||
if (e->loop.do_while) {
|
if (e->loop.do_while) {
|
||||||
|
unsigned loop = spirv_SplitBlock (ctx);
|
||||||
spirv_LoopMerge (merge, cont, ctx);
|
spirv_LoopMerge (merge, cont, ctx);
|
||||||
spirv_SplitBlock (ctx);
|
spirv_SplitBlock (ctx);
|
||||||
spirv_emit_expr (e->loop.body, ctx);
|
spirv_emit_expr (e->loop.body, ctx);
|
||||||
spirv_SplitBlockId (cont, ctx);
|
spirv_SplitBlockId (cont, ctx);
|
||||||
unsigned test = spirv_emit_expr (e->loop.test, ctx);
|
unsigned test = spirv_emit_expr (e->loop.test, ctx);
|
||||||
if (e->loop.not) {
|
spirv_BranchConditional (e->loop.not, test, merge, loop, ctx);
|
||||||
spirv_BranchConditional (test, merge, loop, ctx);
|
|
||||||
} else {
|
|
||||||
spirv_BranchConditional (test, loop, merge, ctx);
|
|
||||||
}
|
|
||||||
spirv_LabelId (merge, ctx);
|
spirv_LabelId (merge, ctx);
|
||||||
} else {
|
} else {
|
||||||
spirv_Branch (loop, ctx);
|
unsigned loop = spirv_SplitBlock (ctx);
|
||||||
spirv_LabelId (loop, ctx);
|
|
||||||
spirv_LoopMerge (merge, cont, ctx);
|
spirv_LoopMerge (merge, cont, ctx);
|
||||||
spirv_SplitBlock (ctx);
|
spirv_SplitBlock (ctx);
|
||||||
unsigned body = spirv_id (ctx);
|
unsigned body = spirv_id (ctx);
|
||||||
unsigned test = spirv_emit_expr (e->loop.test, ctx);
|
unsigned test = spirv_emit_expr (e->loop.test, ctx);
|
||||||
if (e->loop.not) {
|
spirv_BranchConditional (e->loop.not, test, body, merge, ctx);
|
||||||
spirv_BranchConditional (test, merge, body, ctx);
|
|
||||||
} else {
|
|
||||||
spirv_BranchConditional (test, body, merge, ctx);
|
|
||||||
}
|
|
||||||
spirv_LabelId (body, ctx);
|
spirv_LabelId (body, ctx);
|
||||||
spirv_emit_expr (e->loop.body, ctx);
|
spirv_emit_expr (e->loop.body, ctx);
|
||||||
spirv_SplitBlockId (cont, ctx);
|
spirv_SplitBlockId (cont, ctx);
|
||||||
|
@ -1365,6 +1405,28 @@ spirv_loop (const expr_t *e, spirvctx_t *ctx)
|
||||||
static unsigned
|
static unsigned
|
||||||
spirv_select (const expr_t *e, spirvctx_t *ctx)
|
spirv_select (const expr_t *e, spirvctx_t *ctx)
|
||||||
{
|
{
|
||||||
|
unsigned merge = spirv_id (ctx);
|
||||||
|
unsigned true_label = spirv_id (ctx);
|
||||||
|
unsigned false_label = merge;
|
||||||
|
if (e->select.false_body) {
|
||||||
|
false_label = spirv_id (ctx);
|
||||||
|
}
|
||||||
|
unsigned test = spirv_emit_expr (e->select.test, ctx);
|
||||||
|
spirv_SelectionMerge (merge, ctx);
|
||||||
|
spirv_BranchConditional (e->select.not, test, true_label, false_label, ctx);
|
||||||
|
spirv_LabelId (true_label, ctx);
|
||||||
|
spirv_emit_expr (e->select.true_body, ctx);
|
||||||
|
if (!is_block_terminated (ctx->code_space)) {
|
||||||
|
spirv_Branch (merge, ctx);
|
||||||
|
}
|
||||||
|
if (e->select.false_body) {
|
||||||
|
spirv_LabelId (false_label, ctx);
|
||||||
|
spirv_emit_expr (e->select.false_body, ctx);
|
||||||
|
if (!is_block_terminated (ctx->code_space)) {
|
||||||
|
spirv_Branch (merge, ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spirv_LabelId (merge, ctx);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1423,6 +1485,7 @@ spirv_write (struct pr_info_s *pr, const char *filename)
|
||||||
.code_space = defspace_new (ds_backed),
|
.code_space = defspace_new (ds_backed),
|
||||||
.decl_space = defspace_new (ds_backed),
|
.decl_space = defspace_new (ds_backed),
|
||||||
.type_ids = DARRAY_STATIC_INIT (64),
|
.type_ids = DARRAY_STATIC_INIT (64),
|
||||||
|
.label_ids = DARRAY_STATIC_INIT (64),
|
||||||
.id = 0,
|
.id = 0,
|
||||||
};
|
};
|
||||||
auto space = defspace_new (ds_backed);
|
auto space = defspace_new (ds_backed);
|
||||||
|
|
Loading…
Reference in a new issue