summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEric Anholt <[email protected]>2016-03-15 13:55:28 -0700
committerEric Anholt <[email protected]>2016-07-12 17:42:40 -0700
commit05bcd9dd960d5658801ab35d429ba9778f67cad0 (patch)
tree8e26e38f7346c608dfd0b1b34c4af9a568962c45 /src
parent54800bb71c874bc7e9953a2e6d29ea53915f5be7 (diff)
vc4: Define a QIR branch instruction
This uses the branch condition code in inst->cond to jump to either successor[0] (condition matches) or successor[0] (condition doesn't match).
Diffstat (limited to 'src')
-rw-r--r--src/gallium/drivers/vc4/vc4_qir.c38
-rw-r--r--src/gallium/drivers/vc4/vc4_qir.h15
-rw-r--r--src/gallium/drivers/vc4/vc4_qir_schedule.c8
-rw-r--r--src/gallium/drivers/vc4/vc4_qpu_emit.c9
4 files changed, 61 insertions, 9 deletions
diff --git a/src/gallium/drivers/vc4/vc4_qir.c b/src/gallium/drivers/vc4/vc4_qir.c
index 4c81b567927..982e8298ae9 100644
--- a/src/gallium/drivers/vc4/vc4_qir.c
+++ b/src/gallium/drivers/vc4/vc4_qir.c
@@ -83,6 +83,8 @@ static const struct qir_op_info qir_op_info[] = {
[QOP_TEX_RESULT] = { "tex_result", 1, 0, true },
[QOP_LOAD_IMM] = { "load_imm", 0, 1 },
+
+ [QOP_BRANCH] = { "branch", 0, 0, true },
};
static const char *
@@ -204,8 +206,12 @@ qir_is_tex(struct qinst *inst)
bool
qir_depends_on_flags(struct qinst *inst)
{
- return (inst->cond != QPU_COND_ALWAYS &&
- inst->cond != QPU_COND_NEVER);
+ if (inst->op == QOP_BRANCH) {
+ return inst->cond != QPU_COND_BRANCH_ALWAYS;
+ } else {
+ return (inst->cond != QPU_COND_ALWAYS &&
+ inst->cond != QPU_COND_NEVER);
+ }
}
bool
@@ -337,20 +343,26 @@ void
qir_dump_inst(struct vc4_compile *c, struct qinst *inst)
{
fprintf(stderr, "%s", qir_get_op_name(inst->op));
- vc4_qpu_disasm_cond(stderr, inst->cond);
+ if (inst->op == QOP_BRANCH)
+ vc4_qpu_disasm_cond_branch(stderr, inst->cond);
+ else
+ vc4_qpu_disasm_cond(stderr, inst->cond);
if (inst->sf)
fprintf(stderr, ".sf");
fprintf(stderr, " ");
- qir_print_reg(c, inst->dst, true);
- if (inst->dst.pack) {
+ if (inst->op != QOP_BRANCH) {
+ qir_print_reg(c, inst->dst, true);
if (inst->dst.pack) {
- if (qir_is_mul(inst))
- vc4_qpu_disasm_pack_mul(stderr, inst->dst.pack);
- else
- vc4_qpu_disasm_pack_a(stderr, inst->dst.pack);
+ if (inst->dst.pack) {
+ if (qir_is_mul(inst))
+ vc4_qpu_disasm_pack_mul(stderr, inst->dst.pack);
+ else
+ vc4_qpu_disasm_pack_a(stderr, inst->dst.pack);
+ }
}
}
+
for (int i = 0; i < qir_get_op_nsrc(inst->op); i++) {
fprintf(stderr, ", ");
qir_print_reg(c, inst->src[i], false);
@@ -412,6 +424,14 @@ qir_dump(struct vc4_compile *c)
fprintf(stderr, "\n");
ip++;
}
+ if (block->successors[1]) {
+ fprintf(stderr, "-> BLOCK %d, %d\n",
+ block->successors[0]->index,
+ block->successors[1]->index);
+ } else if (block->successors[0]) {
+ fprintf(stderr, "-> BLOCK %d\n",
+ block->successors[0]->index);
+ }
}
}
diff --git a/src/gallium/drivers/vc4/vc4_qir.h b/src/gallium/drivers/vc4/vc4_qir.h
index 5099b7f1f1c..ad784bb987b 100644
--- a/src/gallium/drivers/vc4/vc4_qir.h
+++ b/src/gallium/drivers/vc4/vc4_qir.h
@@ -156,6 +156,12 @@ enum qop {
QOP_TEX_RESULT,
QOP_LOAD_IMM,
+
+ /* Jumps to block->successor[0] if the qinst->cond (as a
+ * QPU_COND_BRANCH_*) passes, or block->successor[1] if not. Note
+ * that block->successor[1] may be unset if the condition is ALWAYS.
+ */
+ QOP_BRANCH,
};
struct queued_qpu_inst {
@@ -754,6 +760,15 @@ qir_LOAD_IMM(struct vc4_compile *c, uint32_t val)
qir_reg(QFILE_LOAD_IMM, val), c->undef));
}
+static inline struct qinst *
+qir_BRANCH(struct vc4_compile *c, uint8_t cond)
+{
+ struct qinst *inst = qir_inst(QOP_BRANCH, c->undef, c->undef, c->undef);
+ inst->cond = cond;
+ qir_emit_nondef(c, inst);
+ return inst;
+}
+
#define qir_for_each_block(block, c) \
list_for_each_entry(struct qblock, block, &c->blocks, link)
diff --git a/src/gallium/drivers/vc4/vc4_qir_schedule.c b/src/gallium/drivers/vc4/vc4_qir_schedule.c
index fc918040a28..903c6108824 100644
--- a/src/gallium/drivers/vc4/vc4_qir_schedule.c
+++ b/src/gallium/drivers/vc4/vc4_qir_schedule.c
@@ -388,6 +388,14 @@ choose_instruction(struct schedule_state *state)
struct schedule_node *chosen = NULL;
list_for_each_entry(struct schedule_node, n, &state->worklist, link) {
+ /* The branches aren't being tracked as dependencies. Make
+ * sure that they stay scheduled as the last instruction of
+ * the block, which is to say the first one we choose to
+ * schedule.
+ */
+ if (n->inst->op == QOP_BRANCH)
+ return n;
+
if (!chosen) {
chosen = n;
continue;
diff --git a/src/gallium/drivers/vc4/vc4_qpu_emit.c b/src/gallium/drivers/vc4/vc4_qpu_emit.c
index 1fd151acac2..2257dcce83b 100644
--- a/src/gallium/drivers/vc4/vc4_qpu_emit.c
+++ b/src/gallium/drivers/vc4/vc4_qpu_emit.c
@@ -446,6 +446,15 @@ vc4_generate_code(struct vc4_context *vc4, struct vc4_compile *c)
handle_r4_qpu_write(c, qinst, dst);
break;
+ case QOP_BRANCH:
+ /* The branch target will be updated at QPU scheduling
+ * time.
+ */
+ queue(c, (qpu_branch(qinst->cond, 0) |
+ QPU_BRANCH_REL));
+ handled_qinst_cond = true;
+ break;
+
default:
assert(qinst->op < ARRAY_SIZE(translate));
assert(translate[qinst->op].op != 0); /* NOPs */