summaryrefslogtreecommitdiff
path: root/src/mesa/drivers/dri/i965/brw_eu_emit.c
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2010-12-01 11:46:46 -0800
committerEric Anholt <eric@anholt.net>2010-12-01 16:14:33 -0800
commit00e5a743e2ee3981a34b95067a97fa73c0f5d779 (patch)
tree804daa4d50727dacd1d36b6402eb2bf0896d1692 /src/mesa/drivers/dri/i965/brw_eu_emit.c
parent4890e0f09c934e3ffb692b417e5444e43685c876 (diff)
i965: Add support for gen6 BREAK ISA emit.
There are now two targets: the hop-to-end-of-block target, and the target for where to resume execution for active channels.
Diffstat (limited to 'src/mesa/drivers/dri/i965/brw_eu_emit.c')
-rw-r--r--src/mesa/drivers/dri/i965/brw_eu_emit.c92
1 files changed, 86 insertions, 6 deletions
diff --git a/src/mesa/drivers/dri/i965/brw_eu_emit.c b/src/mesa/drivers/dri/i965/brw_eu_emit.c
index 660f5b4845..7eb7bdfa1e 100644
--- a/src/mesa/drivers/dri/i965/brw_eu_emit.c
+++ b/src/mesa/drivers/dri/i965/brw_eu_emit.c
@@ -1029,16 +1029,24 @@ void brw_ENDIF(struct brw_compile *p,
struct brw_instruction *brw_BREAK(struct brw_compile *p, int pop_count)
{
+ struct intel_context *intel = &p->brw->intel;
struct brw_instruction *insn;
+
insn = next_insn(p, BRW_OPCODE_BREAK);
- brw_set_dest(insn, brw_ip_reg());
- brw_set_src0(insn, brw_ip_reg());
- brw_set_src1(insn, brw_imm_d(0x0));
+ if (intel->gen >= 6) {
+ brw_set_dest(insn, retype(brw_null_reg(), BRW_REGISTER_TYPE_D));
+ brw_set_src0(insn, retype(brw_null_reg(), BRW_REGISTER_TYPE_D));
+ brw_set_src1(insn, brw_imm_d(0x0));
+ } else {
+ brw_set_dest(insn, brw_ip_reg());
+ brw_set_src0(insn, brw_ip_reg());
+ brw_set_src1(insn, brw_imm_d(0x0));
+ insn->bits3.if_else.pad0 = 0;
+ insn->bits3.if_else.pop_count = pop_count;
+ }
insn->header.compression_control = BRW_COMPRESSION_NONE;
insn->header.execution_size = BRW_EXECUTE_8;
- /* insn->header.mask_control = BRW_MASK_DISABLE; */
- insn->bits3.if_else.pad0 = 0;
- insn->bits3.if_else.pop_count = pop_count;
+
return insn;
}
@@ -2013,6 +2021,78 @@ void brw_urb_WRITE(struct brw_compile *p,
swizzle);
}
+static int
+brw_find_next_block_end(struct brw_compile *p, int start)
+{
+ int ip;
+
+ for (ip = start + 1; ip < p->nr_insn; ip++) {
+ struct brw_instruction *insn = &p->store[ip];
+
+ switch (insn->header.opcode) {
+ case BRW_OPCODE_ENDIF:
+ case BRW_OPCODE_ELSE:
+ case BRW_OPCODE_WHILE:
+ return ip;
+ }
+ }
+ assert(!"not reached");
+ return start + 1;
+}
+
+/* There is no DO instruction on gen6, so to find the end of the loop
+ * we have to see if the loop is jumping back before our start
+ * instruction.
+ */
+static int
+brw_find_loop_end(struct brw_compile *p, int start)
+{
+ int ip;
+ int br = 2;
+
+ for (ip = start + 1; ip < p->nr_insn; ip++) {
+ struct brw_instruction *insn = &p->store[ip];
+
+ if (insn->header.opcode == BRW_OPCODE_WHILE) {
+ if (ip + insn->bits1.branch_gen6.jump_count / br < start)
+ return ip;
+ }
+ }
+ assert(!"not reached");
+ return start + 1;
+}
+
+/* After program generation, go back and update the UIP and JIP of
+ * BREAK and CONT instructions to their correct locations.
+ */
+void
+brw_set_uip_jip(struct brw_compile *p)
+{
+ struct intel_context *intel = &p->brw->intel;
+ int ip;
+ int br = 2;
+
+ if (intel->gen < 6)
+ return;
+
+ for (ip = 0; ip < p->nr_insn; ip++) {
+ struct brw_instruction *insn = &p->store[ip];
+
+ switch (insn->header.opcode) {
+ case BRW_OPCODE_BREAK:
+ insn->bits3.break_cont.jip = br * (brw_find_next_block_end(p, ip) - ip);
+ insn->bits3.break_cont.uip = br * (brw_find_loop_end(p, ip) - ip + 1);
+ break;
+ case BRW_OPCODE_CONTINUE:
+ /* JIP is set at CONTINUE emit time, since that's when we
+ * know where the start of the loop is.
+ */
+ insn->bits3.break_cont.uip = br * (brw_find_next_block_end(p, ip) - ip);
+ break;
+ }
+ }
+}
+
void brw_ff_sync(struct brw_compile *p,
struct brw_reg dest,
GLuint msg_reg_nr,