i965: Add support for IF/ELSE/ENDIF control flow on Ivybridge.
authorKenneth Graunke <kenneth@whitecape.org>
Wed, 16 Mar 2011 06:53:40 +0000 (23:53 -0700)
committerKenneth Graunke <kenneth@whitecape.org>
Wed, 18 May 2011 06:33:01 +0000 (23:33 -0700)
Ivybridge's IF instruction doesn't support conditional modifiers.
It also introduces UIP, which must point to the ENDIF instruction.

ELSE and ENDIF remain the same except that JIP moves from dst to src1.

Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
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 cff6bcad7fd2a7555ca99d70e0c7daeeb37151d7..fb03b62a4c9740d81b45457b747184dae5df55e2 100644 (file)
@@ -950,11 +950,17 @@ brw_IF(struct brw_compile *p, GLuint execute_size)
       brw_set_dest(p, insn, brw_ip_reg());
       brw_set_src0(p, insn, brw_ip_reg());
       brw_set_src1(p, insn, brw_imm_d(0x0));
-   } else {
+   } else if (intel->gen == 6) {
       brw_set_dest(p, insn, brw_imm_w(0));
       insn->bits1.branch_gen6.jump_count = 0;
       brw_set_src0(p, insn, retype(brw_null_reg(), BRW_REGISTER_TYPE_D));
       brw_set_src1(p, insn, retype(brw_null_reg(), BRW_REGISTER_TYPE_D));
+   } else {
+      brw_set_dest(p, insn, retype(brw_null_reg(), BRW_REGISTER_TYPE_D));
+      brw_set_src0(p, insn, retype(brw_null_reg(), BRW_REGISTER_TYPE_D));
+      brw_set_src1(p, insn, brw_imm_ud(0));
+      insn->bits3.break_cont.jip = 0;
+      insn->bits3.break_cont.uip = 0;
    }
 
    insn->header.execution_size = execute_size;
@@ -970,6 +976,9 @@ brw_IF(struct brw_compile *p, GLuint execute_size)
    return insn;
 }
 
+/* This function is only used for gen6-style IF instructions with an
+ * embedded comparison (conditional modifier).  It is not used on gen7.
+ */
 struct brw_instruction *
 gen6_IF(struct brw_compile *p, uint32_t conditional,
        struct brw_reg src0, struct brw_reg src1)
@@ -1071,9 +1080,12 @@ patch_IF_ELSE(struct brw_compile *p,
         if_inst->bits3.if_else.jump_count = br * (endif_inst - if_inst + 1);
         if_inst->bits3.if_else.pop_count = 0;
         if_inst->bits3.if_else.pad0 = 0;
-      } else {
+      } else if (intel->gen == 6) {
         /* As of gen6, there is no IFF and IF must point to the ENDIF. */
         if_inst->bits1.branch_gen6.jump_count = br * (endif_inst - if_inst);
+      } else {
+        if_inst->bits3.break_cont.uip = br * (endif_inst - if_inst);
+        if_inst->bits3.break_cont.jip = br * (endif_inst - if_inst);
       }
    } else {
       else_inst->header.execution_size = if_inst->header.execution_size;
@@ -1095,9 +1107,15 @@ patch_IF_ELSE(struct brw_compile *p,
         else_inst->bits3.if_else.jump_count = br*(endif_inst - else_inst + 1);
         else_inst->bits3.if_else.pop_count = 1;
         else_inst->bits3.if_else.pad0 = 0;
-      } else {
+      } else if (intel->gen == 6) {
         /* BRW_OPCODE_ELSE on gen6 should point to the matching ENDIF. */
         else_inst->bits1.branch_gen6.jump_count = br*(endif_inst - else_inst);
+      } else {
+        /* The IF instruction's JIP should point just past the ELSE */
+        if_inst->bits3.break_cont.jip = br * (else_inst - if_inst + 1);
+        /* The IF instruction's UIP and ELSE's JIP should point to ENDIF */
+        if_inst->bits3.break_cont.uip = br * (endif_inst - if_inst);
+        else_inst->bits3.break_cont.jip = br * (endif_inst - else_inst);
       }
    }
 }
@@ -1114,11 +1132,17 @@ brw_ELSE(struct brw_compile *p)
       brw_set_dest(p, insn, brw_ip_reg());
       brw_set_src0(p, insn, brw_ip_reg());
       brw_set_src1(p, insn, brw_imm_d(0x0));
-   } else {
+   } else if (intel->gen == 6) {
       brw_set_dest(p, insn, brw_imm_w(0));
       insn->bits1.branch_gen6.jump_count = 0;
       brw_set_src0(p, insn, retype(brw_null_reg(), BRW_REGISTER_TYPE_D));
       brw_set_src1(p, insn, retype(brw_null_reg(), BRW_REGISTER_TYPE_D));
+   } else {
+      brw_set_dest(p, insn, retype(brw_null_reg(), BRW_REGISTER_TYPE_D));
+      brw_set_src0(p, insn, retype(brw_null_reg(), BRW_REGISTER_TYPE_D));
+      brw_set_src1(p, insn, brw_imm_ud(0));
+      insn->bits3.break_cont.jip = 0;
+      insn->bits3.break_cont.uip = 0;
    }
 
    insn->header.compression_control = BRW_COMPRESSION_NONE;
@@ -1157,10 +1181,14 @@ brw_ENDIF(struct brw_compile *p)
       brw_set_dest(p, insn, retype(brw_vec4_grf(0,0), BRW_REGISTER_TYPE_UD));
       brw_set_src0(p, insn, retype(brw_vec4_grf(0,0), BRW_REGISTER_TYPE_UD));
       brw_set_src1(p, insn, brw_imm_d(0x0));
-   } else {
+   } else if (intel->gen == 6) {
       brw_set_dest(p, insn, brw_imm_w(0));
       brw_set_src0(p, insn, retype(brw_null_reg(), BRW_REGISTER_TYPE_D));
       brw_set_src1(p, insn, retype(brw_null_reg(), BRW_REGISTER_TYPE_D));
+   } else {
+      brw_set_dest(p, insn, retype(brw_null_reg(), BRW_REGISTER_TYPE_D));
+      brw_set_src0(p, insn, retype(brw_null_reg(), BRW_REGISTER_TYPE_D));
+      brw_set_src1(p, insn, brw_imm_ud(0));
    }
 
    insn->header.compression_control = BRW_COMPRESSION_NONE;
@@ -1172,8 +1200,10 @@ brw_ENDIF(struct brw_compile *p)
       insn->bits3.if_else.jump_count = 0;
       insn->bits3.if_else.pop_count = 1;
       insn->bits3.if_else.pad0 = 0;
-   } else {
+   } else if (intel->gen == 6) {
       insn->bits1.branch_gen6.jump_count = 2;
+   } else {
+      insn->bits3.break_cont.jip = 2;
    }
    patch_IF_ELSE(p, if_inst, else_inst, insn);
 }
index 30e771aea4eff09c09e29f994824b63abb947075..8dee849edd423e07923681085bebafc15b5e743d 100644 (file)
@@ -1873,7 +1873,7 @@ fs_visitor::visit(ir_if *ir)
     */
    this->base_ir = ir->condition;
 
-   if (intel->gen >= 6) {
+   if (intel->gen == 6) {
       emit_if_gen6(ir);
    } else {
       emit_bool_to_cond_code(ir->condition);
@@ -3890,7 +3890,8 @@ fs_visitor::generate_code()
 
       case BRW_OPCODE_IF:
         if (inst->src[0].file != BAD_FILE) {
-           assert(intel->gen >= 6);
+           /* The instruction has an embedded compare (only allowed on gen6) */
+           assert(intel->gen == 6);
            gen6_IF(p, inst->conditional_mod, src[0], src[1]);
         } else {
            brw_IF(p, BRW_EXECUTE_8);
index a63df37def2e6739502c33a933d4d93e924fa81c..ad31222e9ec7ef511b04b69da41b220f0f1fc844 100644 (file)
@@ -1664,6 +1664,7 @@ struct brw_instruction
         GLuint  pad0:12;
       } if_else;
 
+      /* This is also used for gen7 IF/ELSE instructions */
       struct
       {
         /* Signed jump distance to the ip to jump to if all channels