i965: Add support for gen6 BREAK ISA emit.
authorEric Anholt <eric@anholt.net>
Wed, 1 Dec 2010 19:46:46 +0000 (11:46 -0800)
committerEric Anholt <eric@anholt.net>
Thu, 2 Dec 2010 00:14:33 +0000 (16:14 -0800)
There are now two targets: the hop-to-end-of-block target, and the
target for where to resume execution for active channels.

src/mesa/drivers/dri/i965/brw_eu.h
src/mesa/drivers/dri/i965/brw_eu_emit.c
src/mesa/drivers/dri/i965/brw_fs.cpp
src/mesa/drivers/dri/i965/brw_structs.h

index b4538e6e8a7a23f17e6880c1244334c71afc39f8..df5ce56ba616ac96abbe6cbf175beb07fa7d2156 100644 (file)
@@ -1009,6 +1009,7 @@ void brw_math_invert( struct brw_compile *p,
 void brw_set_src1( struct brw_instruction *insn,
                           struct brw_reg reg );
 
+void brw_set_uip_jip(struct brw_compile *p);
 
 /* brw_optimize.c */
 void brw_optimize(struct brw_compile *p);
index 660f5b484536126305bf12ae9278d99615922490..7eb7bdfa1eeefc46bdbd06deea45865db5a6a0c0 100644 (file)
@@ -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,
index cf45fcaa06ff84a5cef8379bde703e0ca84eab1b..46061c77ed576547359744c2c5a5a68bd59ade5e 100644 (file)
@@ -933,6 +933,10 @@ fs_visitor::visit(ir_expression *ir)
       assert(!"not reached: should be handled by lower_noise");
       break;
 
+   case ir_quadop_vector:
+      assert(!"not reached: should be handled by lower_quadop_vector");
+      break;
+
    case ir_unop_sqrt:
       emit_math(FS_OPCODE_SQRT, this->result, op[0]);
       break;
@@ -3375,10 +3379,6 @@ fs_visitor::generate_code()
         break;
 
       case BRW_OPCODE_DO:
-        /* FINISHME: We need to write the loop instruction support still. */
-        if (intel->gen >= 6)
-           this->fail = true;
-
         loop_stack[loop_stack_depth++] = brw_DO(p, BRW_EXECUTE_8);
         if_depth_in_loop[loop_stack_depth] = 0;
         break;
@@ -3388,6 +3388,10 @@ fs_visitor::generate_code()
         brw_set_predicate_control(p, BRW_PREDICATE_NONE);
         break;
       case BRW_OPCODE_CONTINUE:
+        /* FINISHME: We need to write the loop instruction support still. */
+        if (intel->gen >= 6)
+           this->fail = true;
+
         brw_CONT(p, if_depth_in_loop[loop_stack_depth]);
         brw_set_predicate_control(p, BRW_PREDICATE_NONE);
         break;
@@ -3491,6 +3495,8 @@ fs_visitor::generate_code()
       last_native_inst = p->nr_insn;
    }
 
+   brw_set_uip_jip(p);
+
    /* OK, while the INTEL_DEBUG=wm above is very nice for debugging FS
     * emit issues, it doesn't get the jump distances into the output,
     * which is often something we want to debug.  So this is here in
index 8ce9af9c4fed79a43d7b7e75e98551d926ed2ddf..8f97bd136fd1c21b44b30b18c6d89bee20b21f6f 100644 (file)
@@ -1539,6 +1539,21 @@ struct brw_instruction
         GLuint  pad0:12;
       } if_else;
 
+      struct
+      {
+        /* Signed jump distance to the ip to jump to if all channels
+         * are disabled after the break or continue.  It should point
+         * to the end of the innermost control flow block, as that's
+         * where some channel could get re-enabled.
+         */
+        int jip:16;
+
+        /* Signed jump distance to the location to resume execution
+         * of this channel if it's enabled for the break or continue.
+         */
+        int uip:16;
+      } break_cont;
+
       struct {
         GLuint function:4;
         GLuint int_type:1;