glsl: introduce data section to ir_variable
[mesa.git] / src / mesa / drivers / dri / i965 / brw_fs.cpp
index b724dca4f60de873aef42b5a465a975065501450..374801fab207eb19c9ce64790b69221b7dc4901f 100644 (file)
@@ -46,6 +46,7 @@ extern "C" {
 #include "brw_wm.h"
 }
 #include "brw_fs.h"
+#include "brw_dead_control_flow.h"
 #include "main/uniforms.h"
 #include "brw_fs_live_variables.h"
 #include "glsl/glsl_types.h"
@@ -183,6 +184,7 @@ ALU1(CBIT)
 ALU3(MAD)
 ALU2(ADDC)
 ALU2(SUBB)
+ALU2(SEL)
 
 /** Gen4 predicated IF. */
 fs_inst *
@@ -193,11 +195,11 @@ fs_visitor::IF(uint32_t predicate)
    return inst;
 }
 
-/** Gen6+ IF with embedded comparison. */
+/** Gen6 IF with embedded comparison. */
 fs_inst *
 fs_visitor::IF(fs_reg src0, fs_reg src1, uint32_t condition)
 {
-   assert(brw->gen >= 6);
+   assert(brw->gen == 6);
    fs_inst *inst = new(mem_ctx) fs_inst(BRW_OPCODE_IF,
                                         reg_null_d, src0, src1);
    inst->conditional_mod = condition;
@@ -415,7 +417,7 @@ fs_reg::fs_reg(uint32_t u)
    this->imm.u = u;
 }
 
-/** Fixed brw_reg Immediate value constructor. */
+/** Fixed brw_reg. */
 fs_reg::fs_reg(struct brw_reg fixed_hw_reg)
 {
    init();
@@ -466,6 +468,14 @@ fs_reg::is_one() const
    return type == BRW_REGISTER_TYPE_F ? imm.f == 1.0 : imm.i == 1;
 }
 
+bool
+fs_reg::is_null() const
+{
+   return file == HW_REG &&
+          fixed_hw_reg.file == BRW_ARCHITECTURE_REGISTER_FILE &&
+          fixed_hw_reg.nr == BRW_ARF_NULL;
+}
+
 bool
 fs_reg::is_valid_3src() const
 {
@@ -496,6 +506,8 @@ fs_visitor::type_size(const struct glsl_type *type)
        * link time.
        */
       return 0;
+   case GLSL_TYPE_ATOMIC_UINT:
+      return 0;
    case GLSL_TYPE_VOID:
    case GLSL_TYPE_ERROR:
    case GLSL_TYPE_INTERFACE:
@@ -681,19 +693,6 @@ fs_visitor::pop_force_uncompressed()
    assert(force_uncompressed_stack >= 0);
 }
 
-void
-fs_visitor::push_force_sechalf()
-{
-   force_sechalf_stack++;
-}
-
-void
-fs_visitor::pop_force_sechalf()
-{
-   force_sechalf_stack--;
-   assert(force_sechalf_stack >= 0);
-}
-
 /**
  * Returns true if the instruction has a flag that means it won't
  * update an entire destination register.
@@ -722,6 +721,19 @@ fs_inst::regs_read(fs_visitor *v, int arg)
    return 1;
 }
 
+bool
+fs_inst::reads_flag()
+{
+   return predicate;
+}
+
+bool
+fs_inst::writes_flag()
+{
+   return (conditional_mod && opcode != BRW_OPCODE_SEL) ||
+          opcode == FS_OPCODE_MOV_DISPATCH_TO_FLAGS;
+}
+
 /**
  * Returns how many MRFs an FS opcode will write over.
  *
@@ -755,6 +767,7 @@ fs_visitor::implied_mrf_writes(fs_inst *inst)
    case SHADER_OPCODE_TXD:
    case SHADER_OPCODE_TXF:
    case SHADER_OPCODE_TXF_MS:
+   case SHADER_OPCODE_TXF_MCS:
    case SHADER_OPCODE_TG4:
    case SHADER_OPCODE_TG4_OFFSET:
    case SHADER_OPCODE_TXL:
@@ -764,12 +777,15 @@ fs_visitor::implied_mrf_writes(fs_inst *inst)
    case FS_OPCODE_FB_WRITE:
       return 2;
    case FS_OPCODE_UNIFORM_PULL_CONSTANT_LOAD:
-   case FS_OPCODE_UNSPILL:
+   case SHADER_OPCODE_GEN4_SCRATCH_READ:
       return 1;
    case FS_OPCODE_VARYING_PULL_CONSTANT_LOAD:
       return inst->mlen;
-   case FS_OPCODE_SPILL:
+   case SHADER_OPCODE_GEN4_SCRATCH_WRITE:
       return 2;
+   case SHADER_OPCODE_UNTYPED_ATOMIC:
+   case SHADER_OPCODE_UNTYPED_SURFACE_READ:
+      return 0;
    default:
       assert(!"not reached");
       return inst->mlen;
@@ -1068,8 +1084,8 @@ fs_visitor::emit_general_interpolation(ir_variable *ir)
                */
                struct brw_reg interp = interp_reg(location, k);
                emit_linterp(attr, fs_reg(interp), interpolation_mode,
-                            ir->centroid);
-               if (brw->needs_unlit_centroid_workaround && ir->centroid) {
+                            ir->data.centroid);
+               if (brw->needs_unlit_centroid_workaround && ir->data.centroid) {
                   /* Get the pixel/sample mask into f0 so that we know
                    * which pixels are lit.  Then, for each channel that is
                    * unlit, replace the centroid data with non-centroid
@@ -1119,6 +1135,126 @@ fs_visitor::emit_frontfacing_interpolation(ir_variable *ir)
    return reg;
 }
 
+void
+fs_visitor::compute_sample_position(fs_reg dst, fs_reg int_sample_pos)
+{
+   assert(dst.type == BRW_REGISTER_TYPE_F);
+
+   if (c->key.compute_pos_offset) {
+      /* Convert int_sample_pos to floating point */
+      emit(MOV(dst, int_sample_pos));
+      /* Scale to the range [0, 1] */
+      emit(MUL(dst, dst, fs_reg(1 / 16.0f)));
+   }
+   else {
+      /* From ARB_sample_shading specification:
+       * "When rendering to a non-multisample buffer, or if multisample
+       *  rasterization is disabled, gl_SamplePosition will always be
+       *  (0.5, 0.5).
+       */
+      emit(MOV(dst, fs_reg(0.5f)));
+   }
+}
+
+fs_reg *
+fs_visitor::emit_samplepos_setup(ir_variable *ir)
+{
+   assert(brw->gen >= 6);
+   assert(ir->type == glsl_type::vec2_type);
+
+   this->current_annotation = "compute sample position";
+   fs_reg *reg = new(this->mem_ctx) fs_reg(this, ir->type);
+   fs_reg pos = *reg;
+   fs_reg int_sample_x = fs_reg(this, glsl_type::int_type);
+   fs_reg int_sample_y = fs_reg(this, glsl_type::int_type);
+
+   /* WM will be run in MSDISPMODE_PERSAMPLE. So, only one of SIMD8 or SIMD16
+    * mode will be enabled.
+    *
+    * From the Ivy Bridge PRM, volume 2 part 1, page 344:
+    * R31.1:0         Position Offset X/Y for Slot[3:0]
+    * R31.3:2         Position Offset X/Y for Slot[7:4]
+    * .....
+    *
+    * The X, Y sample positions come in as bytes in  thread payload. So, read
+    * the positions using vstride=16, width=8, hstride=2.
+    */
+   struct brw_reg sample_pos_reg =
+      stride(retype(brw_vec1_grf(c->sample_pos_reg, 0),
+                    BRW_REGISTER_TYPE_B), 16, 8, 2);
+
+   emit(MOV(int_sample_x, fs_reg(sample_pos_reg)));
+   if (dispatch_width == 16) {
+      int_sample_x.sechalf = true;
+      fs_inst *inst = emit(MOV(int_sample_x,
+                               fs_reg(suboffset(sample_pos_reg, 16))));
+      inst->force_sechalf = true;
+      int_sample_x.sechalf = false;
+   }
+   /* Compute gl_SamplePosition.x */
+   compute_sample_position(pos, int_sample_x);
+   pos.reg_offset++;
+   emit(MOV(int_sample_y, fs_reg(suboffset(sample_pos_reg, 1))));
+   if (dispatch_width == 16) {
+      int_sample_y.sechalf = true;
+      fs_inst *inst = emit(MOV(int_sample_y,
+                               fs_reg(suboffset(sample_pos_reg, 17))));
+      inst->force_sechalf = true;
+      int_sample_y.sechalf = false;
+   }
+   /* Compute gl_SamplePosition.y */
+   compute_sample_position(pos, int_sample_y);
+   return reg;
+}
+
+fs_reg *
+fs_visitor::emit_sampleid_setup(ir_variable *ir)
+{
+   assert(brw->gen >= 6);
+
+   this->current_annotation = "compute sample id";
+   fs_reg *reg = new(this->mem_ctx) fs_reg(this, ir->type);
+
+   if (c->key.compute_sample_id) {
+      fs_reg t1 = fs_reg(this, glsl_type::int_type);
+      fs_reg t2 = fs_reg(this, glsl_type::int_type);
+      t2.type = BRW_REGISTER_TYPE_UW;
+
+      /* The PS will be run in MSDISPMODE_PERSAMPLE. For example with
+       * 8x multisampling, subspan 0 will represent sample N (where N
+       * is 0, 2, 4 or 6), subspan 1 will represent sample 1, 3, 5 or
+       * 7. We can find the value of N by looking at R0.0 bits 7:6
+       * ("Starting Sample Pair Index (SSPI)") and multiplying by two
+       * (since samples are always delivered in pairs). That is, we
+       * compute 2*((R0.0 & 0xc0) >> 6) == (R0.0 & 0xc0) >> 5. Then
+       * we need to add N to the sequence (0, 0, 0, 0, 1, 1, 1, 1) in
+       * case of SIMD8 and sequence (0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2,
+       * 2, 3, 3, 3, 3) in case of SIMD16. We compute this sequence by
+       * populating a temporary variable with the sequence (0, 1, 2, 3),
+       * and then reading from it using vstride=1, width=4, hstride=0.
+       * These computations hold good for 4x multisampling as well.
+       */
+      emit(BRW_OPCODE_AND, t1,
+           fs_reg(retype(brw_vec1_grf(0, 0), BRW_REGISTER_TYPE_D)),
+           fs_reg(brw_imm_d(0xc0)));
+      emit(BRW_OPCODE_SHR, t1, t1, fs_reg(5));
+      /* This works for both SIMD8 and SIMD16 */
+      emit(MOV(t2, brw_imm_v(0x3210)));
+      /* This special instruction takes care of setting vstride=1,
+       * width=4, hstride=0 of t2 during an ADD instruction.
+       */
+      emit(FS_OPCODE_SET_SAMPLE_ID, *reg, t1, t2);
+   } else {
+      /* As per GL_ARB_sample_shading specification:
+       * "When rendering to a non-multisample buffer, or if multisample
+       *  rasterization is disabled, gl_SampleID will always be zero."
+       */
+      emit(BRW_OPCODE_MOV, *reg, fs_reg(0));
+   }
+
+   return reg;
+}
+
 fs_reg
 fs_visitor::fix_math_operand(fs_reg src)
 {
@@ -1846,6 +1982,50 @@ fs_visitor::opt_algebraic()
             break;
          }
          break;
+      case BRW_OPCODE_OR:
+         if (inst->src[0].equals(inst->src[1])) {
+            inst->opcode = BRW_OPCODE_MOV;
+            inst->src[1] = reg_undef;
+            progress = true;
+            break;
+         }
+         break;
+      case BRW_OPCODE_SEL:
+         if (inst->saturate && inst->src[1].file == IMM) {
+            switch (inst->conditional_mod) {
+            case BRW_CONDITIONAL_LE:
+            case BRW_CONDITIONAL_L:
+               switch (inst->src[1].type) {
+               case BRW_REGISTER_TYPE_F:
+                  if (inst->src[1].imm.f >= 1.0f) {
+                     inst->opcode = BRW_OPCODE_MOV;
+                     inst->src[1] = reg_undef;
+                     progress = true;
+                  }
+                  break;
+               default:
+                  break;
+               }
+               break;
+            case BRW_CONDITIONAL_GE:
+            case BRW_CONDITIONAL_G:
+               switch (inst->src[1].type) {
+               case BRW_REGISTER_TYPE_F:
+                  if (inst->src[1].imm.f <= 0.0f) {
+                     inst->opcode = BRW_OPCODE_MOV;
+                     inst->src[1] = reg_undef;
+                     inst->conditional_mod = BRW_CONDITIONAL_NONE;
+                     progress = true;
+                  }
+                  break;
+               default:
+                  break;
+               }
+            default:
+               break;
+            }
+         }
+         break;
       default:
         break;
       }
@@ -1869,7 +2049,7 @@ fs_visitor::dead_code_eliminate()
    foreach_list_safe(node, &this->instructions) {
       fs_inst *inst = (fs_inst *)node;
 
-      if (inst->dst.file == GRF) {
+      if (inst->dst.file == GRF && !inst->has_side_effects()) {
          bool dead = true;
 
          for (int i = 0; i < inst->regs_written; i++) {
@@ -2030,31 +2210,26 @@ fs_visitor::dead_code_eliminate_local()
                get_dead_code_hash_entry(ht, inst->dst.reg,
                                         inst->dst.reg_offset);
 
-            if (inst->is_partial_write()) {
-               /* For a partial write, we can't remove any previous dead code
-                * candidate, since we're just modifying their result, but we can
-                * be dead code eliminiated ourselves.
-                */
-               if (entry) {
-                  entry->data = inst;
+            if (entry) {
+               if (inst->is_partial_write()) {
+                  /* For a partial write, we can't remove any previous dead code
+                   * candidate, since we're just modifying their result.
+                   */
                } else {
-                  insert_dead_code_hash(ht, inst->dst.reg, inst->dst.reg_offset,
-                                        inst);
-               }
-            } else {
-               if (entry) {
                   /* We're completely updating a channel, and there was a
                    * previous write to the channel that wasn't read.  Kill it!
                    */
                   fs_inst *inst = (fs_inst *)entry->data;
                   inst->remove();
                   progress = true;
-                  _mesa_hash_table_remove(ht, entry);
                }
 
+               _mesa_hash_table_remove(ht, entry);
+            }
+
+            if (!inst->has_side_effects())
                insert_dead_code_hash(ht, inst->dst.reg, inst->dst.reg_offset,
                                      inst);
-            }
          }
       }
    }
@@ -2068,12 +2243,12 @@ fs_visitor::dead_code_eliminate_local()
 }
 
 /**
- * Implements a second type of register coalescing: This one checks if
- * the two regs involved in a raw move don't interfere, in which case
- * they can both by stored in the same place and the MOV removed.
+ * Implements register coalescing: Checks if the two registers involved in a
+ * raw move don't interfere, in which case they can both be stored in the same
+ * place and the MOV removed.
  */
 bool
-fs_visitor::register_coalesce_2()
+fs_visitor::register_coalesce()
 {
    bool progress = false;
 
@@ -2098,7 +2273,8 @@ fs_visitor::register_coalesce_2()
       int var_from = live_intervals->var_from_reg(&inst->src[0]);
       int var_to = live_intervals->var_from_reg(&inst->dst);
 
-      if (live_intervals->vars_interfere(var_from, var_to))
+      if (live_intervals->vars_interfere(var_from, var_to) &&
+          !inst->dst.equals(inst->src[0]))
          continue;
 
       int reg_from = inst->src[0].reg;
@@ -2134,151 +2310,6 @@ fs_visitor::register_coalesce_2()
    return progress;
 }
 
-bool
-fs_visitor::register_coalesce()
-{
-   bool progress = false;
-   int if_depth = 0;
-   int loop_depth = 0;
-
-   foreach_list_safe(node, &this->instructions) {
-      fs_inst *inst = (fs_inst *)node;
-
-      /* Make sure that we dominate the instructions we're going to
-       * scan for interfering with our coalescing, or we won't have
-       * scanned enough to see if anything interferes with our
-       * coalescing.  We don't dominate the following instructions if
-       * we're in a loop or an if block.
-       */
-      switch (inst->opcode) {
-      case BRW_OPCODE_DO:
-        loop_depth++;
-        break;
-      case BRW_OPCODE_WHILE:
-        loop_depth--;
-        break;
-      case BRW_OPCODE_IF:
-        if_depth++;
-        break;
-      case BRW_OPCODE_ENDIF:
-        if_depth--;
-        break;
-      default:
-        break;
-      }
-      if (loop_depth || if_depth)
-        continue;
-
-      if (inst->opcode != BRW_OPCODE_MOV ||
-         inst->is_partial_write() ||
-         inst->saturate ||
-         inst->dst.file != GRF || (inst->src[0].file != GRF &&
-                                   inst->src[0].file != UNIFORM)||
-         inst->dst.type != inst->src[0].type)
-        continue;
-
-      bool has_source_modifiers = (inst->src[0].abs ||
-                                   inst->src[0].negate ||
-                                   inst->src[0].smear != -1 ||
-                                   inst->src[0].file == UNIFORM);
-
-      /* Found a move of a GRF to a GRF.  Let's see if we can coalesce
-       * them: check for no writes to either one until the exit of the
-       * program.
-       */
-      bool interfered = false;
-
-      for (fs_inst *scan_inst = (fs_inst *)inst->next;
-          !scan_inst->is_tail_sentinel();
-          scan_inst = (fs_inst *)scan_inst->next) {
-        if (scan_inst->dst.file == GRF) {
-           if (scan_inst->overwrites_reg(inst->dst) ||
-                scan_inst->overwrites_reg(inst->src[0])) {
-              interfered = true;
-              break;
-           }
-        }
-
-         if (has_source_modifiers) {
-            for (int i = 0; i < 3; i++) {
-               if (scan_inst->src[i].file == GRF &&
-                   scan_inst->src[i].reg == inst->dst.reg &&
-                   scan_inst->src[i].reg_offset == inst->dst.reg_offset &&
-                   inst->dst.type != scan_inst->src[i].type)
-               {
-                 interfered = true;
-                 break;
-               }
-            }
-         }
-
-
-        /* The gen6 MATH instruction can't handle source modifiers or
-         * unusual register regions, so avoid coalescing those for
-         * now.  We should do something more specific.
-         */
-        if (has_source_modifiers && !can_do_source_mods(scan_inst)) {
-            interfered = true;
-           break;
-        }
-
-        if (scan_inst->mlen > 0 && scan_inst->base_mrf == -1 &&
-            scan_inst->src[0].file == GRF &&
-            scan_inst->src[0].reg == inst->dst.reg) {
-           interfered = true;
-           break;
-        }
-
-        /* The accumulator result appears to get used for the
-         * conditional modifier generation.  When negating a UD
-         * value, there is a 33rd bit generated for the sign in the
-         * accumulator value, so now you can't check, for example,
-         * equality with a 32-bit value.  See piglit fs-op-neg-uint.
-         */
-        if (scan_inst->conditional_mod &&
-            inst->src[0].negate &&
-            inst->src[0].type == BRW_REGISTER_TYPE_UD) {
-           interfered = true;
-           break;
-        }
-      }
-      if (interfered) {
-        continue;
-      }
-
-      /* Rewrite the later usage to point at the source of the move to
-       * be removed.
-       */
-      for (fs_inst *scan_inst = inst;
-          !scan_inst->is_tail_sentinel();
-          scan_inst = (fs_inst *)scan_inst->next) {
-        for (int i = 0; i < 3; i++) {
-           if (scan_inst->src[i].file == GRF &&
-               scan_inst->src[i].reg == inst->dst.reg &&
-               scan_inst->src[i].reg_offset == inst->dst.reg_offset) {
-              fs_reg new_src = inst->src[0];
-               if (scan_inst->src[i].abs) {
-                  new_src.negate = 0;
-                  new_src.abs = 1;
-               }
-              new_src.negate ^= scan_inst->src[i].negate;
-              new_src.sechalf = scan_inst->src[i].sechalf;
-              scan_inst->src[i] = new_src;
-           }
-        }
-      }
-
-      inst->remove();
-      progress = true;
-   }
-
-   if (progress)
-      invalidate_live_intervals();
-
-   return progress;
-}
-
-
 bool
 fs_visitor::compute_to_mrf()
 {
@@ -2802,7 +2833,7 @@ fs_visitor::dump_instruction(backend_instruction *be_inst)
    if (inst->saturate)
       printf(".sat");
    if (inst->conditional_mod) {
-      printf(".cmod");
+      printf("%s", conditional_modifier[inst->conditional_mod]);
       if (!inst->predicate &&
           (brw->gen < 5 || (inst->opcode != BRW_OPCODE_SEL &&
                               inst->opcode != BRW_OPCODE_IF &&
@@ -2829,7 +2860,29 @@ fs_visitor::dump_instruction(backend_instruction *be_inst)
       printf("***u%d***", inst->dst.reg);
       break;
    case HW_REG:
-      printf("hw_reg%d", inst->dst.fixed_hw_reg.nr);
+      if (inst->dst.fixed_hw_reg.file == BRW_ARCHITECTURE_REGISTER_FILE) {
+         switch (inst->dst.fixed_hw_reg.nr) {
+         case BRW_ARF_NULL:
+            printf("null");
+            break;
+         case BRW_ARF_ADDRESS:
+            printf("a0.%d", inst->dst.fixed_hw_reg.subnr);
+            break;
+         case BRW_ARF_ACCUMULATOR:
+            printf("acc%d", inst->dst.fixed_hw_reg.subnr);
+            break;
+         case BRW_ARF_FLAG:
+            printf("f%d.%d", inst->dst.fixed_hw_reg.nr & 0xf,
+                             inst->dst.fixed_hw_reg.subnr);
+            break;
+         default:
+            printf("arf%d.%d", inst->dst.fixed_hw_reg.nr & 0xf,
+                               inst->dst.fixed_hw_reg.subnr);
+            break;
+         }
+      } else {
+         printf("hw_reg%d", inst->dst.fixed_hw_reg.nr);
+      }
       if (inst->dst.fixed_hw_reg.subnr)
          printf("+%d", inst->dst.fixed_hw_reg.subnr);
       break;
@@ -2837,9 +2890,9 @@ fs_visitor::dump_instruction(backend_instruction *be_inst)
       printf("???");
       break;
    }
-   printf(", ");
+   printf(":%s, ", reg_encoding[inst->dst.type]);
 
-   for (int i = 0; i < 3; i++) {
+   for (int i = 0; i < 3 && inst->src[i].file != BAD_FILE; i++) {
       if (inst->src[i].negate)
          printf("-");
       if (inst->src[i].abs)
@@ -2882,7 +2935,29 @@ fs_visitor::dump_instruction(backend_instruction *be_inst)
             printf("-");
          if (inst->src[i].fixed_hw_reg.abs)
             printf("|");
-         printf("hw_reg%d", inst->src[i].fixed_hw_reg.nr);
+         if (inst->src[i].fixed_hw_reg.file == BRW_ARCHITECTURE_REGISTER_FILE) {
+            switch (inst->src[i].fixed_hw_reg.nr) {
+            case BRW_ARF_NULL:
+               printf("null");
+               break;
+            case BRW_ARF_ADDRESS:
+               printf("a0.%d", inst->src[i].fixed_hw_reg.subnr);
+               break;
+            case BRW_ARF_ACCUMULATOR:
+               printf("acc%d", inst->src[i].fixed_hw_reg.subnr);
+               break;
+            case BRW_ARF_FLAG:
+               printf("f%d.%d", inst->src[i].fixed_hw_reg.nr & 0xf,
+                                inst->src[i].fixed_hw_reg.subnr);
+               break;
+            default:
+               printf("arf%d.%d", inst->src[i].fixed_hw_reg.nr & 0xf,
+                                  inst->src[i].fixed_hw_reg.subnr);
+               break;
+            }
+         } else {
+            printf("hw_reg%d", inst->src[i].fixed_hw_reg.nr);
+         }
          if (inst->src[i].fixed_hw_reg.subnr)
             printf("+%d", inst->src[i].fixed_hw_reg.subnr);
          if (inst->src[i].fixed_hw_reg.abs)
@@ -2895,7 +2970,11 @@ fs_visitor::dump_instruction(backend_instruction *be_inst)
       if (inst->src[i].abs)
          printf("|");
 
-      if (i < 3)
+      if (inst->src[i].file != IMM) {
+         printf(":%s", reg_encoding[inst->src[i].type]);
+      }
+
+      if (i < 2 && inst->src[i + 1].file != BAD_FILE)
          printf(", ");
    }
 
@@ -2986,7 +3065,14 @@ fs_visitor::setup_payload_gen6()
          c->nr_payload_regs++;
       }
    }
+
+   c->prog_data.uses_pos_offset = c->key.compute_pos_offset;
    /* R31: MSAA position offsets. */
+   if (c->prog_data.uses_pos_offset) {
+      c->sample_pos_reg = c->nr_payload_regs;
+      c->nr_payload_regs++;
+   }
+
    /* R32-: bary for 32-pixel. */
    /* R58-59: interp W for 32-pixel. */
 
@@ -3000,8 +3086,11 @@ fs_visitor::assign_binding_table_offsets()
 {
    uint32_t next_binding_table_offset = 0;
 
+   /* If there are no color regions, we still perform an FB write to a null
+    * renderbuffer, which we place at surface index 0.
+    */
    c->prog_data.binding_table.render_target_start = next_binding_table_offset;
-   next_binding_table_offset += c->key.nr_color_regions;
+   next_binding_table_offset += MAX2(c->key.nr_color_regions, 1);
 
    assign_common_binding_table_offsets(next_binding_table_offset);
 }
@@ -3011,6 +3100,7 @@ fs_visitor::run()
 {
    sanity_param_count = fp->Base.Parameters->NumParameters;
    uint32_t orig_nr_params = c->prog_data.nr_params;
+   bool allocated_without_spills;
 
    assign_binding_table_offsets();
 
@@ -3036,7 +3126,7 @@ fs_visitor::run()
       /* We handle discards by keeping track of the still-live pixels in f0.1.
        * Initialize it with the dispatched pixels.
        */
-      if (fp->UsesKill) {
+      if (fp->UsesKill || c->key.alpha_test_func) {
          fs_inst *discard_init = emit(FS_OPCODE_MOV_DISPATCH_TO_FLAGS);
          discard_init->flag_subreg = 1;
       }
@@ -3060,11 +3150,15 @@ fs_visitor::run()
 
       emit(FS_OPCODE_PLACEHOLDER_HALT);
 
+      if (c->key.alpha_test_func)
+         emit_alpha_test();
+
       emit_fb_writes();
 
       split_virtual_grfs();
 
       move_uniform_array_access_to_pull_constants();
+      remove_dead_constants();
       setup_pull_constants();
 
       bool progress;
@@ -3078,40 +3172,63 @@ fs_visitor::run()
         progress = opt_algebraic() || progress;
         progress = opt_cse() || progress;
         progress = opt_copy_propagate() || progress;
+         progress = opt_peephole_sel() || progress;
+         progress = opt_peephole_predicated_break() || progress;
         progress = dead_code_eliminate() || progress;
         progress = dead_code_eliminate_local() || progress;
-        progress = register_coalesce() || progress;
-        progress = register_coalesce_2() || progress;
+         progress = dead_control_flow_eliminate(this) || progress;
+         progress = register_coalesce() || progress;
         progress = compute_to_mrf() || progress;
       } while (progress);
 
-      remove_dead_constants();
-
-      schedule_instructions(false);
-
       lower_uniform_pull_constant_loads();
 
       assign_curb_setup();
       assign_urb_setup();
 
-      if (0) {
-        /* Debug of register spilling: Go spill everything. */
-        for (int i = 0; i < virtual_grf_count; i++) {
-           spill_reg(i);
-        }
+      static enum instruction_scheduler_mode pre_modes[] = {
+         SCHEDULE_PRE,
+         SCHEDULE_PRE_NON_LIFO,
+         SCHEDULE_PRE_LIFO,
+      };
+
+      /* Try each scheduling heuristic to see if it can successfully register
+       * allocate without spilling.  They should be ordered by decreasing
+       * performance but increasing likelihood of allocating.
+       */
+      for (unsigned i = 0; i < ARRAY_SIZE(pre_modes); i++) {
+         schedule_instructions(pre_modes[i]);
+
+         if (0) {
+            assign_regs_trivial();
+            allocated_without_spills = true;
+         } else {
+            allocated_without_spills = assign_regs(false);
+         }
+         if (allocated_without_spills)
+            break;
       }
 
-      if (0)
-        assign_regs_trivial();
-      else {
-        while (!assign_regs()) {
-           if (failed)
-              break;
-        }
+      if (!allocated_without_spills) {
+         /* We assume that any spilling is worse than just dropping back to
+          * SIMD8.  There's probably actually some intermediate point where
+          * SIMD16 with a couple of spills is still better.
+          */
+         if (dispatch_width == 16) {
+            fail("Failure to register allocate.  Reduce number of "
+                 "live scalar values to avoid this.");
+         }
+
+         /* Since we're out of heuristics, just go spill registers until we
+          * get an allocation.
+          */
+         while (!assign_regs(true)) {
+            if (failed)
+               break;
+         }
       }
    }
    assert(force_uncompressed_stack == 0);
-   assert(force_sechalf_stack == 0);
 
    /* This must come after all optimization and register allocation, since
     * it inserts dead code that happens to have side effects, and it does
@@ -3122,7 +3239,8 @@ fs_visitor::run()
    if (failed)
       return false;
 
-   schedule_instructions(true);
+   if (!allocated_without_spills)
+      schedule_instructions(SCHEDULE_POST);
 
    if (dispatch_width == 8) {
       c->prog_data.reg_blocks = brw_register_blocks(grf_used);