From 64ce592679a5b08d66e3cbbf964f9e695e14aee1 Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Tue, 15 Mar 2011 23:53:40 -0700 Subject: [PATCH] i965: Add support for IF/ELSE/ENDIF control flow on Ivybridge. 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 Reviewed-by: Eric Anholt --- src/mesa/drivers/dri/i965/brw_eu_emit.c | 42 ++++++++++++++++++++++++++++----- src/mesa/drivers/dri/i965/brw_fs.cpp | 5 ++-- src/mesa/drivers/dri/i965/brw_structs.h | 1 + 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/mesa/drivers/dri/i965/brw_eu_emit.c b/src/mesa/drivers/dri/i965/brw_eu_emit.c index cff6bca..fb03b62 100644 --- a/src/mesa/drivers/dri/i965/brw_eu_emit.c +++ b/src/mesa/drivers/dri/i965/brw_eu_emit.c @@ -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); } diff --git a/src/mesa/drivers/dri/i965/brw_fs.cpp b/src/mesa/drivers/dri/i965/brw_fs.cpp index 30e771a..8dee849 100644 --- a/src/mesa/drivers/dri/i965/brw_fs.cpp +++ b/src/mesa/drivers/dri/i965/brw_fs.cpp @@ -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); diff --git a/src/mesa/drivers/dri/i965/brw_structs.h b/src/mesa/drivers/dri/i965/brw_structs.h index a63df37..ad31222 100644 --- a/src/mesa/drivers/dri/i965/brw_structs.h +++ b/src/mesa/drivers/dri/i965/brw_structs.h @@ -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 -- 2.7.4