i965/vec4: Simplify opt_reduce_swizzle() using the swizzle utils.
[mesa.git] / src / mesa / drivers / dri / i965 / brw_shader.cpp
index e38dfd6635dbe1942d261a3fb7d5a9e122ed69dd..51c965c4e77697d0b8452bfc4d333415ad3925c3 100644 (file)
  * IN THE SOFTWARE.
  */
 
-extern "C" {
 #include "main/macros.h"
 #include "brw_context.h"
-}
 #include "brw_vs.h"
 #include "brw_gs.h"
 #include "brw_fs.h"
@@ -157,7 +155,7 @@ brw_link_shader(struct gl_context *ctx, struct gl_shader_program *shProg)
                                   ? BITFIELD_INSERT_TO_BFM_BFI
                                   : 0;
       lower_instructions(shader->base.ir,
-                        MOD_TO_FRACT |
+                        MOD_TO_FLOOR |
                         DIV_TO_MUL_RCP |
                         SUB_TO_ADD_NEG |
                         EXP_TO_EXP2 |
@@ -242,6 +240,7 @@ brw_link_shader(struct gl_context *ctx, struct gl_shader_program *shProg)
       do_set_program_inouts(shader->base.ir, prog, shader->base.Stage);
 
       prog->SamplersUsed = shader->base.active_samplers;
+      prog->ShadowSamplers = shader->base.shadow_samplers;
       _mesa_update_shader_textures_used(shProg, prog);
 
       _mesa_reference_program(ctx, &shader->base.Program, prog);
@@ -307,6 +306,7 @@ brw_type_for_base_type(const struct glsl_type *type)
    case GLSL_TYPE_VOID:
    case GLSL_TYPE_ERROR:
    case GLSL_TYPE_INTERFACE:
+   case GLSL_TYPE_DOUBLE:
       unreachable("not reached");
    }
 
@@ -469,6 +469,8 @@ brw_instruction_name(enum opcode op)
    case SHADER_OPCODE_URB_WRITE_SIMD8:
       return "gen8_urb_write_simd8";
 
+   case VEC4_OPCODE_MOV_BYTES:
+      return "mov_bytes";
    case VEC4_OPCODE_PACK_BYTES:
       return "pack_bytes";
    case VEC4_OPCODE_UNPACK_UNIFORM:
@@ -582,7 +584,7 @@ brw_saturate_immediate(enum brw_reg_type type, struct brw_reg *reg)
       unsigned ud;
       int d;
       float f;
-   } imm = { reg->dw1.ud }, sat_imm;
+   } imm = { reg->dw1.ud }, sat_imm = { 0 };
 
    switch (type) {
    case BRW_REGISTER_TYPE_UD:
@@ -601,18 +603,15 @@ brw_saturate_immediate(enum brw_reg_type type, struct brw_reg *reg)
       sat_imm.f = CLAMP(imm.f, 0.0f, 1.0f);
       break;
    case BRW_REGISTER_TYPE_UB:
-      sat_imm.ud = CLAMP(imm.ud, 0, UCHAR_MAX);
-      break;
    case BRW_REGISTER_TYPE_B:
-      sat_imm.d = CLAMP(imm.d, CHAR_MIN, CHAR_MAX);
-      break;
+      unreachable("no UB/B immediates");
    case BRW_REGISTER_TYPE_V:
    case BRW_REGISTER_TYPE_UV:
    case BRW_REGISTER_TYPE_VF:
-      assert(!"unimplemented: saturate vector immediate");
+      unreachable("unimplemented: saturate vector immediate");
    case BRW_REGISTER_TYPE_DF:
    case BRW_REGISTER_TYPE_HF:
-      assert(!"unimplemented: saturate DF/HF immediate");
+      unreachable("unimplemented: saturate DF/HF immediate");
    }
 
    if (imm.ud != sat_imm.ud) {
@@ -622,6 +621,80 @@ brw_saturate_immediate(enum brw_reg_type type, struct brw_reg *reg)
    return false;
 }
 
+bool
+brw_negate_immediate(enum brw_reg_type type, struct brw_reg *reg)
+{
+   switch (type) {
+   case BRW_REGISTER_TYPE_D:
+   case BRW_REGISTER_TYPE_UD:
+      reg->dw1.d = -reg->dw1.d;
+      return true;
+   case BRW_REGISTER_TYPE_W:
+   case BRW_REGISTER_TYPE_UW:
+      reg->dw1.d = -(int16_t)reg->dw1.ud;
+      return true;
+   case BRW_REGISTER_TYPE_F:
+      reg->dw1.f = -reg->dw1.f;
+      return true;
+   case BRW_REGISTER_TYPE_VF:
+      reg->dw1.ud ^= 0x80808080;
+      return true;
+   case BRW_REGISTER_TYPE_UB:
+   case BRW_REGISTER_TYPE_B:
+      unreachable("no UB/B immediates");
+   case BRW_REGISTER_TYPE_UV:
+   case BRW_REGISTER_TYPE_V:
+      assert(!"unimplemented: negate UV/V immediate");
+   case BRW_REGISTER_TYPE_UQ:
+   case BRW_REGISTER_TYPE_Q:
+      assert(!"unimplemented: negate UQ/Q immediate");
+   case BRW_REGISTER_TYPE_DF:
+   case BRW_REGISTER_TYPE_HF:
+      assert(!"unimplemented: negate DF/HF immediate");
+   }
+
+   return false;
+}
+
+bool
+brw_abs_immediate(enum brw_reg_type type, struct brw_reg *reg)
+{
+   switch (type) {
+   case BRW_REGISTER_TYPE_D:
+      reg->dw1.d = abs(reg->dw1.d);
+      return true;
+   case BRW_REGISTER_TYPE_W:
+      reg->dw1.d = abs((int16_t)reg->dw1.ud);
+      return true;
+   case BRW_REGISTER_TYPE_F:
+      reg->dw1.f = fabsf(reg->dw1.f);
+      return true;
+   case BRW_REGISTER_TYPE_VF:
+      reg->dw1.ud &= ~0x80808080;
+      return true;
+   case BRW_REGISTER_TYPE_UB:
+   case BRW_REGISTER_TYPE_B:
+      unreachable("no UB/B immediates");
+   case BRW_REGISTER_TYPE_UQ:
+   case BRW_REGISTER_TYPE_UD:
+   case BRW_REGISTER_TYPE_UW:
+   case BRW_REGISTER_TYPE_UV:
+      /* Presumably the absolute value modifier on an unsigned source is a
+       * nop, but it would be nice to confirm.
+       */
+      assert(!"unimplemented: abs unsigned immediate");
+   case BRW_REGISTER_TYPE_V:
+      assert(!"unimplemented: abs V immediate");
+   case BRW_REGISTER_TYPE_Q:
+      assert(!"unimplemented: abs Q immediate");
+   case BRW_REGISTER_TYPE_DF:
+   case BRW_REGISTER_TYPE_HF:
+      assert(!"unimplemented: abs DF/HF immediate");
+   }
+
+   return false;
+}
+
 backend_visitor::backend_visitor(struct brw_context *brw,
                                  struct gl_shader_program *shader_prog,
                                  struct gl_program *prog,
@@ -637,6 +710,9 @@ backend_visitor::backend_visitor(struct brw_context *brw,
      cfg(NULL),
      stage(stage)
 {
+   debug_enabled = INTEL_DEBUG & intel_debug_flag_for_shader_stage(stage);
+   stage_name = _mesa_shader_stage_to_string(stage);
+   stage_abbrev = _mesa_shader_stage_to_abbrev(stage);
 }
 
 bool
@@ -659,6 +735,22 @@ backend_reg::is_one() const
           : fixed_hw_reg.dw1.d == 1;
 }
 
+bool
+backend_reg::is_negative_one() const
+{
+   if (file != IMM)
+      return false;
+
+   switch (type) {
+   case BRW_REGISTER_TYPE_F:
+      return fixed_hw_reg.dw1.f == -1.0;
+   case BRW_REGISTER_TYPE_D:
+      return fixed_hw_reg.dw1.d == -1;
+   default:
+      return false;
+   }
+}
+
 bool
 backend_reg::is_null() const
 {
@@ -676,6 +768,34 @@ backend_reg::is_accumulator() const
           fixed_hw_reg.nr == BRW_ARF_ACCUMULATOR;
 }
 
+bool
+backend_instruction::is_commutative() const
+{
+   switch (opcode) {
+   case BRW_OPCODE_AND:
+   case BRW_OPCODE_OR:
+   case BRW_OPCODE_XOR:
+   case BRW_OPCODE_ADD:
+   case BRW_OPCODE_MUL:
+      return true;
+   case BRW_OPCODE_SEL:
+      /* MIN and MAX are commutative. */
+      if (conditional_mod == BRW_CONDITIONAL_GE ||
+          conditional_mod == BRW_CONDITIONAL_L) {
+         return true;
+      }
+      /* fallthrough */
+   default:
+      return false;
+   }
+}
+
+bool
+backend_instruction::is_3src() const
+{
+   return opcode < ARRAY_SIZE(opcode_descs) && opcode_descs[opcode].nsrc == 3;
+}
+
 bool
 backend_instruction::is_tex() const
 {
@@ -788,6 +908,53 @@ backend_instruction::can_do_saturate() const
    }
 }
 
+bool
+backend_instruction::can_do_cmod() const
+{
+   switch (opcode) {
+   case BRW_OPCODE_ADD:
+   case BRW_OPCODE_ADDC:
+   case BRW_OPCODE_AND:
+   case BRW_OPCODE_ASR:
+   case BRW_OPCODE_AVG:
+   case BRW_OPCODE_CMP:
+   case BRW_OPCODE_CMPN:
+   case BRW_OPCODE_DP2:
+   case BRW_OPCODE_DP3:
+   case BRW_OPCODE_DP4:
+   case BRW_OPCODE_DPH:
+   case BRW_OPCODE_F16TO32:
+   case BRW_OPCODE_F32TO16:
+   case BRW_OPCODE_FRC:
+   case BRW_OPCODE_LINE:
+   case BRW_OPCODE_LRP:
+   case BRW_OPCODE_LZD:
+   case BRW_OPCODE_MAC:
+   case BRW_OPCODE_MACH:
+   case BRW_OPCODE_MAD:
+   case BRW_OPCODE_MOV:
+   case BRW_OPCODE_MUL:
+   case BRW_OPCODE_NOT:
+   case BRW_OPCODE_OR:
+   case BRW_OPCODE_PLN:
+   case BRW_OPCODE_RNDD:
+   case BRW_OPCODE_RNDE:
+   case BRW_OPCODE_RNDU:
+   case BRW_OPCODE_RNDZ:
+   case BRW_OPCODE_SAD2:
+   case BRW_OPCODE_SADA2:
+   case BRW_OPCODE_SHL:
+   case BRW_OPCODE_SHR:
+   case BRW_OPCODE_SUBB:
+   case BRW_OPCODE_XOR:
+   case FS_OPCODE_CINTERP:
+   case FS_OPCODE_LINTERP:
+      return true;
+   default:
+      return false;
+   }
+}
+
 bool
 backend_instruction::reads_accumulator_implicitly() const
 {
@@ -816,6 +983,7 @@ backend_instruction::has_side_effects() const
 {
    switch (opcode) {
    case SHADER_OPCODE_UNTYPED_ATOMIC:
+   case SHADER_OPCODE_GEN4_SCRATCH_WRITE:
    case SHADER_OPCODE_URB_WRITE_SIMD8:
    case FS_OPCODE_FB_WRITE:
       return true;
@@ -852,7 +1020,8 @@ adjust_later_block_ips(bblock_t *start_block, int ip_adjustment)
 void
 backend_instruction::insert_after(bblock_t *block, backend_instruction *inst)
 {
-   assert(inst_is_in_block(block, this) || !"Instruction not in block");
+   if (!this->is_head_sentinel())
+      assert(inst_is_in_block(block, this) || !"Instruction not in block");
 
    block->end_ip++;
 
@@ -864,7 +1033,8 @@ backend_instruction::insert_after(bblock_t *block, backend_instruction *inst)
 void
 backend_instruction::insert_before(bblock_t *block, backend_instruction *inst)
 {
-   assert(inst_is_in_block(block, this) || !"Instruction not in block");
+   if (!this->is_tail_sentinel())
+      assert(inst_is_in_block(block, this) || !"Instruction not in block");
 
    block->end_ip++;
 
@@ -919,11 +1089,18 @@ backend_visitor::dump_instructions(const char *name)
          file = stderr;
    }
 
-   int ip = 0;
-   foreach_block_and_inst(block, backend_instruction, inst, cfg) {
-      if (!name)
-         fprintf(stderr, "%d: ", ip++);
-      dump_instruction(inst, file);
+   if (cfg) {
+      int ip = 0;
+      foreach_block_and_inst(block, backend_instruction, inst, cfg) {
+         fprintf(file, "%4d: ", ip++);
+         dump_instruction(inst, file);
+      }
+   } else {
+      int ip = 0;
+      foreach_in_list(backend_instruction, inst, &instructions) {
+         fprintf(file, "%4d: ", ip++);
+         dump_instruction(inst, file);
+      }
    }
 
    if (file != stderr) {
@@ -995,6 +1172,13 @@ backend_visitor::assign_common_binding_table_offsets(uint32_t next_binding_table
       stage_prog_data->binding_table.abo_start = 0xd0d0d0d0;
    }
 
+   if (shader && shader->base.NumImages) {
+      stage_prog_data->binding_table.image_start = next_binding_table_offset;
+      next_binding_table_offset += shader->base.NumImages;
+   } else {
+      stage_prog_data->binding_table.image_start = 0xd0d0d0d0;
+   }
+
    /* This may or may not be used depending on how the compile goes. */
    stage_prog_data->binding_table.pull_constants_start = next_binding_table_offset;
    next_binding_table_offset++;