nir: Rename parallel_copy_copy to parallel_copy_entry and add a foreach macro
[mesa.git] / src / glsl / nir / glsl_to_nir.cpp
index 6b90da5481c0a8bc91b6272735dd2cc942c66b2b..d0737d01db16a3dc5581a0d193f37f834c7e41a8 100644 (file)
@@ -330,12 +330,18 @@ nir_visitor::visit(ir_variable *ir)
    var->data.max_array_access = ir->data.max_array_access;
 
    var->num_state_slots = ir->get_num_state_slots();
-   var->state_slots = ralloc_array(var, nir_state_slot, var->num_state_slots);
-   ir_state_slot *state_slots = ir->get_state_slots();
-   for (unsigned i = 0; i < var->num_state_slots; i++) {
-      for (unsigned j = 0; j < 5; j++)
-         var->state_slots[i].tokens[j] = state_slots[i].tokens[j];
-      var->state_slots[i].swizzle = state_slots[i].swizzle;
+   if (var->num_state_slots > 0) {
+      var->state_slots = ralloc_array(var, nir_state_slot,
+                                      var->num_state_slots);
+
+      ir_state_slot *state_slots = ir->get_state_slots();
+      for (unsigned i = 0; i < var->num_state_slots; i++) {
+         for (unsigned j = 0; j < 5; j++)
+            var->state_slots[i].tokens[j] = state_slots[i].tokens[j];
+         var->state_slots[i].swizzle = state_slots[i].swizzle;
+      }
+   } else {
+      var->state_slots = NULL;
    }
 
    var->constant_value = constant_copy(ir->constant_value, var);
@@ -608,24 +614,24 @@ nir_visitor::visit(ir_call *ir)
          assert(0);
       }
 
-      nir_register *reg = nir_local_reg_create(impl);
-      reg->num_components = 1;
-
       nir_intrinsic_instr *instr = nir_intrinsic_instr_create(shader, op);
       ir_dereference *param =
          (ir_dereference *) ir->actual_parameters.get_head();
       param->accept(this);
       instr->variables[0] = this->deref_head;
-      instr->dest.reg.reg = reg;
+      instr->dest.is_ssa = true;
+      nir_ssa_def_init(&instr->instr, &instr->dest.ssa, 1, NULL);
 
       nir_instr_insert_after_cf_list(this->cf_node_list, &instr->instr);
 
       nir_intrinsic_instr *store_instr =
-         nir_intrinsic_instr_create(shader, nir_intrinsic_store_var_vec1);
+         nir_intrinsic_instr_create(shader, nir_intrinsic_store_var);
+      store_instr->num_components = 1;
 
       ir->return_deref->accept(this);
       store_instr->variables[0] = this->deref_head;
-      store_instr->src[0].reg.reg = reg;
+      store_instr->src[0].is_ssa = true;
+      store_instr->src[0].ssa = &instr->dest.ssa;
 
       nir_instr_insert_after_cf_list(this->cf_node_list, &store_instr->instr);
 
@@ -654,81 +660,11 @@ nir_visitor::visit(ir_call *ir)
 void
 nir_visitor::visit(ir_assignment *ir)
 {
-   if (ir->write_mask != (1 << ir->lhs->type->vector_elements) - 1 &&
-       ir->write_mask != 0) {
-      /*
-       * We have no good way to update only part of a variable, so just load
-       * the LHS into a register, do a writemasked move, and then store it
-       * back into the LHS. Copy propagation should get rid of the mess.
-       */
-
-      ir->lhs->accept(this);
-      nir_deref_var *lhs_deref = this->deref_head;
-      nir_register *reg = nir_local_reg_create(this->impl);
-      reg->num_components = ir->lhs->type->vector_elements;
-
-      nir_intrinsic_op op;
-      switch (ir->lhs->type->vector_elements) {
-         case 1: op = nir_intrinsic_load_var_vec1; break;
-         case 2: op = nir_intrinsic_load_var_vec2; break;
-         case 3: op = nir_intrinsic_load_var_vec3; break;
-         case 4: op = nir_intrinsic_load_var_vec4; break;
-         default: assert(0); break;
-      }
-
-      nir_intrinsic_instr *load = nir_intrinsic_instr_create(this->shader, op);
-      load->dest.reg.reg = reg;
-      load->variables[0] = lhs_deref;
-      nir_instr_insert_after_cf_list(this->cf_node_list, &load->instr);
-
-      nir_alu_instr *move =
-         nir_alu_instr_create(this->shader,
-                              supports_ints ? nir_op_fmov : nir_op_imov);
-      move->dest.dest.reg.reg = reg;
-      move->dest.write_mask = ir->write_mask;
-      move->src[0].src = evaluate_rvalue(ir->rhs);
-
-      /*
-       * GLSL IR will give us the input to the write-masked assignment in a
-       * single packed vector, whereas we expect each input component to be in
-       * the same channel as the writemask. So, for example, if the writemask
-       * is xzw, then we have to swizzle x -> x, y -> z, and z -> w.
-       */
-
-      unsigned component = 0;
-      for (unsigned i = 0; i < 4; i++) {
-         if ((ir->write_mask >> i) & 1) {
-            move->src[0].swizzle[i] = component++;
-         } else {
-            move->src[0].swizzle[i] = 0;
-         }
-      }
+   unsigned num_components = ir->lhs->type->vector_elements;
 
-      if (ir->condition != NULL) {
-         move->has_predicate = true;
-         move->predicate = evaluate_rvalue(ir->condition);
-      }
-
-      nir_instr_insert_after_cf_list(this->cf_node_list, &move->instr);
-
-      switch (ir->lhs->type->vector_elements) {
-         case 1: op = nir_intrinsic_store_var_vec1; break;
-         case 2: op = nir_intrinsic_store_var_vec2; break;
-         case 3: op = nir_intrinsic_store_var_vec3; break;
-         case 4: op = nir_intrinsic_store_var_vec4; break;
-         default: assert(0); break;
-      }
-
-      nir_intrinsic_instr *store = nir_intrinsic_instr_create(this->shader, op);
-      nir_deref *store_deref = nir_copy_deref(this->shader, &lhs_deref->deref);
-      store->variables[0] = nir_deref_as_var(store_deref);
-      store->src[0].reg.reg = reg;
-      nir_instr_insert_after_cf_list(this->cf_node_list, &store->instr);
-      return;
-   }
-
-   if (ir->rhs->as_dereference() || ir->rhs->as_constant()) {
-      /* we're copying structs or arrays, so emit a copy_var */
+   if ((ir->rhs->as_dereference() || ir->rhs->as_constant()) &&
+       (ir->write_mask == (1 << num_components) - 1 || ir->write_mask == 0)) {
+      /* We're doing a plain-as-can-be copy, so emit a copy_var */
       nir_intrinsic_instr *copy =
          nir_intrinsic_instr_create(this->shader, nir_intrinsic_copy_var);
 
@@ -738,37 +674,94 @@ nir_visitor::visit(ir_assignment *ir)
       ir->rhs->accept(this);
       copy->variables[1] = this->deref_head;
 
-      if (ir->condition != NULL) {
-         copy->has_predicate = true;
-         copy->predicate = evaluate_rvalue(ir->condition);
+
+      if (ir->condition) {
+         nir_if *if_stmt = nir_if_create(this->shader);
+         if_stmt->condition = evaluate_rvalue(ir->condition);
+         nir_cf_node_insert_end(this->cf_node_list, &if_stmt->cf_node);
+         nir_instr_insert_after_cf_list(&if_stmt->then_list, &copy->instr);
+      } else {
+         nir_instr_insert_after_cf_list(this->cf_node_list, &copy->instr);
       }
-      nir_instr_insert_after_cf_list(this->cf_node_list, &copy->instr);
       return;
    }
 
    assert(ir->rhs->type->is_scalar() || ir->rhs->type->is_vector());
 
-   nir_intrinsic_op op;
-   switch (ir->lhs->type->vector_elements) {
-      case 1: op = nir_intrinsic_store_var_vec1; break;
-      case 2: op = nir_intrinsic_store_var_vec2; break;
-      case 3: op = nir_intrinsic_store_var_vec3; break;
-      case 4: op = nir_intrinsic_store_var_vec4; break;
-      default: assert(0); break;
-   }
+   ir->lhs->accept(this);
+   nir_deref_var *lhs_deref = this->deref_head;
+   nir_src src = evaluate_rvalue(ir->rhs);
 
-   nir_intrinsic_instr *store = nir_intrinsic_instr_create(this->shader, op);
+   if (ir->write_mask != (1 << num_components) - 1 && ir->write_mask != 0) {
+      /*
+       * We have no good way to update only part of a variable, so just load
+       * the LHS and do a vec operation to combine the old with the new, and
+       * then store it
+       * back into the LHS. Copy propagation should get rid of the mess.
+       */
 
-   ir->lhs->accept(this);
-   store->variables[0] = this->deref_head;
-   store->src[0] = evaluate_rvalue(ir->rhs);
+      nir_intrinsic_instr *load =
+         nir_intrinsic_instr_create(this->shader, nir_intrinsic_load_var);
+      load->num_components = ir->lhs->type->vector_elements;
+      load->dest.is_ssa = true;
+      nir_ssa_def_init(&load->instr, &load->dest.ssa,
+                       num_components, NULL);
+      load->variables[0] = lhs_deref;
+      nir_instr_insert_after_cf_list(this->cf_node_list, &load->instr);
+
+      nir_op vec_op;
+      switch (ir->lhs->type->vector_elements) {
+         case 1: vec_op = nir_op_imov; break;
+         case 2: vec_op = nir_op_vec2; break;
+         case 3: vec_op = nir_op_vec3; break;
+         case 4: vec_op = nir_op_vec4; break;
+         default: unreachable("Invalid number of components"); break;
+      }
+      nir_alu_instr *vec = nir_alu_instr_create(this->shader, vec_op);
+      vec->dest.dest.is_ssa = true;
+      nir_ssa_def_init(&vec->instr, &vec->dest.dest.ssa,
+                       num_components, NULL);
+      vec->dest.write_mask = (1 << num_components) - 1;
+
+      unsigned component = 0;
+      for (unsigned i = 0; i < ir->lhs->type->vector_elements; i++) {
+         if (ir->write_mask & (1 << i)) {
+            vec->src[i].src = src;
+
+            /* GLSL IR will give us the input to the write-masked assignment
+             * in a single packed vector.  So, for example, if the
+             * writemask is xzw, then we have to swizzle x -> x, y -> z,
+             * and z -> w and get the y component from the load.
+             */
+            vec->src[i].swizzle[0] = component++;
+         } else {
+            vec->src[i].src.is_ssa = true;
+            vec->src[i].src.ssa = &load->dest.ssa;
+            vec->src[i].swizzle[0] = i;
+         }
+      }
 
-   if (ir->condition != NULL) {
-      store->has_predicate = true;
-      store->predicate = evaluate_rvalue(ir->condition);
+      nir_instr_insert_after_cf_list(this->cf_node_list, &vec->instr);
+
+      src.is_ssa = true;
+      src.ssa = &vec->dest.dest.ssa;
    }
 
-   nir_instr_insert_after_cf_list(this->cf_node_list, &store->instr);
+   nir_intrinsic_instr *store =
+      nir_intrinsic_instr_create(this->shader, nir_intrinsic_store_var);
+   store->num_components = ir->lhs->type->vector_elements;
+   nir_deref *store_deref = nir_copy_deref(this->shader, &lhs_deref->deref);
+   store->variables[0] = nir_deref_as_var(store_deref);
+   store->src[0] = src;
+
+   if (ir->condition) {
+      nir_if *if_stmt = nir_if_create(this->shader);
+      if_stmt->condition = evaluate_rvalue(ir->condition);
+      nir_cf_node_insert_end(this->cf_node_list, &if_stmt->cf_node);
+      nir_instr_insert_after_cf_list(&if_stmt->then_list, &store->instr);
+   } else {
+      nir_instr_insert_after_cf_list(this->cf_node_list, &store->instr);
+   }
 }
 
 /*
@@ -783,7 +776,6 @@ get_instr_dest(nir_instr *instr)
    nir_alu_instr *alu_instr;
    nir_intrinsic_instr *intrinsic_instr;
    nir_tex_instr *tex_instr;
-   nir_load_const_instr *load_const_instr;
 
    switch (instr->type) {
       case nir_instr_type_alu:
@@ -797,14 +789,10 @@ get_instr_dest(nir_instr *instr)
          else
             return NULL;
 
-      case nir_instr_type_texture:
-         tex_instr = nir_instr_as_texture(instr);
+      case nir_instr_type_tex:
+         tex_instr = nir_instr_as_tex(instr);
          return &tex_instr->dest;
 
-      case nir_instr_type_load_const:
-         load_const_instr = nir_instr_as_load_const(instr);
-         return &load_const_instr->dest;
-
       default:
          assert(0);
          break;
@@ -818,8 +806,8 @@ nir_visitor::add_instr(nir_instr *instr, unsigned num_components)
 {
    nir_dest *dest = get_instr_dest(instr);
 
-   dest->reg.reg = nir_local_reg_create(this->impl);
-   dest->reg.reg->num_components = num_components;
+   dest->is_ssa = true;
+   nir_ssa_def_init(instr, &dest->ssa, num_components, NULL);
 
    nir_instr_insert_after_cf_list(this->cf_node_list, instr);
    this->result = instr;
@@ -835,43 +823,19 @@ nir_visitor::evaluate_rvalue(ir_rvalue* ir)
        * must emit a variable load.
        */
 
-      nir_intrinsic_op op;
-      switch (ir->type->vector_elements) {
-         case 1:
-            op = nir_intrinsic_load_var_vec1;
-            break;
-         case 2:
-            op = nir_intrinsic_load_var_vec2;
-            break;
-         case 3:
-            op = nir_intrinsic_load_var_vec3;
-            break;
-         case 4:
-            op = nir_intrinsic_load_var_vec4;
-            break;
-      }
-
       nir_intrinsic_instr *load_instr =
-         nir_intrinsic_instr_create(this->shader, op);
+         nir_intrinsic_instr_create(this->shader, nir_intrinsic_load_var);
+      load_instr->num_components = ir->type->vector_elements;
       load_instr->variables[0] = this->deref_head;
       add_instr(&load_instr->instr, ir->type->vector_elements);
    }
 
-   /*
-    * instr doesn't have a destination right now, give it one and then set up
-    * the source so that it points to it.
-    *
-    * TODO: once we support SSA plumb through a use_ssa boolean and use SSA
-    * here instead of creating a register.
-    */
    nir_dest *dest = get_instr_dest(this->result);
-   assert(dest->reg.reg);
-   nir_src src;
 
-   src.is_ssa = false;
-   src.reg.base_offset = 0;
-   src.reg.indirect = NULL;
-   src.reg.reg = dest->reg.reg;
+   assert(dest->is_ssa);
+   nir_src src;
+   src.is_ssa = true;
+   src.ssa = &dest->ssa;
 
    return src;
 }
@@ -915,33 +879,24 @@ nir_visitor::emit(nir_op op, unsigned dest_size, nir_src src1,
 void
 nir_visitor::visit(ir_expression *ir)
 {
-   if (ir->operation == ir_binop_ubo_load) {
+   /* Some special cases */
+   switch (ir->operation) {
+   case ir_binop_ubo_load: {
       ir_constant *const_index = ir->operands[1]->as_constant();
 
       nir_intrinsic_op op;
       if (const_index) {
-         switch (ir->type->vector_elements) {
-            case 1: op = nir_intrinsic_load_ubo_vec1; break;
-            case 2: op = nir_intrinsic_load_ubo_vec2; break;
-            case 3: op = nir_intrinsic_load_ubo_vec3; break;
-            case 4: op = nir_intrinsic_load_ubo_vec4; break;
-            default: assert(0); break;
-         }
+         op = nir_intrinsic_load_ubo;
       } else {
-         switch (ir->type->vector_elements) {
-            case 1: op = nir_intrinsic_load_ubo_vec1_indirect; break;
-            case 2: op = nir_intrinsic_load_ubo_vec2_indirect; break;
-            case 3: op = nir_intrinsic_load_ubo_vec3_indirect; break;
-            case 4: op = nir_intrinsic_load_ubo_vec4_indirect; break;
-            default: assert(0); break;
-         }
+         op = nir_intrinsic_load_ubo_indirect;
       }
       nir_intrinsic_instr *load = nir_intrinsic_instr_create(this->shader, op);
-      load->const_index[0] = ir->operands[0]->as_constant()->value.u[0];
-      load->const_index[1] = const_index ? const_index->value.u[0] : 0; /* base offset */
-      load->const_index[2] = 1; /* number of vec4's */
+      load->num_components = ir->type->vector_elements;
+      load->const_index[0] = const_index ? const_index->value.u[0] : 0; /* base offset */
+      load->const_index[1] = 1; /* number of vec4's */
+      load->src[0] = evaluate_rvalue(ir->operands[0]);
       if (!const_index)
-         load->src[0] = evaluate_rvalue(ir->operands[1]);
+         load->src[1] = evaluate_rvalue(ir->operands[1]);
       add_instr(&load->instr, ir->type->vector_elements);
 
       /*
@@ -950,16 +905,15 @@ nir_visitor::visit(ir_expression *ir)
        */
 
       if (ir->type->base_type == GLSL_TYPE_BOOL) {
-         nir_load_const_instr *const_zero = nir_load_const_instr_create(shader);
-         const_zero->num_components = 1;
+         nir_load_const_instr *const_zero = nir_load_const_instr_create(shader, 1);
          const_zero->value.u[0] = 0;
-         const_zero->dest.reg.reg = nir_local_reg_create(this->impl);
-         const_zero->dest.reg.reg->num_components = 1;
          nir_instr_insert_after_cf_list(this->cf_node_list, &const_zero->instr);
 
          nir_alu_instr *compare = nir_alu_instr_create(shader, nir_op_ine);
-         compare->src[0].src.reg.reg = load->dest.reg.reg;
-         compare->src[1].src.reg.reg = const_zero->dest.reg.reg;
+         compare->src[0].src.is_ssa = true;
+         compare->src[0].src.ssa = &load->dest.ssa;
+         compare->src[1].src.is_ssa = true;
+         compare->src[1].src.ssa = &const_zero->def;
          for (unsigned i = 0; i < ir->type->vector_elements; i++)
             compare->src[1].swizzle[i] = 0;
          compare->dest.write_mask = (1 << ir->type->vector_elements) - 1;
@@ -970,6 +924,82 @@ nir_visitor::visit(ir_expression *ir)
       return;
    }
 
+   case ir_unop_interpolate_at_centroid:
+   case ir_binop_interpolate_at_offset:
+   case ir_binop_interpolate_at_sample: {
+      ir_dereference *deref = ir->operands[0]->as_dereference();
+      ir_swizzle *swizzle = NULL;
+      if (!deref) {
+         /* the api does not allow a swizzle here, but the varying packing code
+          * may have pushed one into here.
+          */
+         swizzle = ir->operands[0]->as_swizzle();
+         assert(swizzle);
+         deref = swizzle->val->as_dereference();
+         assert(deref);
+      }
+
+      deref->accept(this);
+
+      nir_intrinsic_op op;
+      if (this->deref_head->var->data.mode == nir_var_shader_in) {
+         switch (ir->operation) {
+         case ir_unop_interpolate_at_centroid:
+            op = nir_intrinsic_interp_var_at_centroid;
+            break;
+         case ir_binop_interpolate_at_offset:
+            op = nir_intrinsic_interp_var_at_offset;
+            break;
+         case ir_binop_interpolate_at_sample:
+            op = nir_intrinsic_interp_var_at_sample;
+            break;
+         default:
+            unreachable("Invalid interpolation intrinsic");
+         }
+      } else {
+         /* This case can happen if the vertex shader does not write the
+          * given varying.  In this case, the linker will lower it to a
+          * global variable.  Since interpolating a variable makes no
+          * sense, we'll just turn it into a load which will probably
+          * eventually end up as an SSA definition.
+          */
+         assert(this->deref_head->var->data.mode == nir_var_global);
+         op = nir_intrinsic_load_var;
+      }
+
+      nir_intrinsic_instr *intrin = nir_intrinsic_instr_create(shader, op);
+      intrin->num_components = deref->type->vector_elements;
+      intrin->variables[0] = this->deref_head;
+
+      if (intrin->intrinsic == nir_intrinsic_interp_var_at_offset ||
+          intrin->intrinsic == nir_intrinsic_interp_var_at_sample)
+         intrin->src[0] = evaluate_rvalue(ir->operands[1]);
+
+      add_instr(&intrin->instr, deref->type->vector_elements);
+
+      if (swizzle) {
+         nir_alu_instr *mov = nir_alu_instr_create(shader, nir_op_imov);
+         mov->dest.write_mask = (1 << swizzle->type->vector_elements) - 1;
+         mov->src[0].src.is_ssa = true;
+         mov->src[0].src.ssa = &intrin->dest.ssa;
+
+         mov->src[0].swizzle[0] = swizzle->mask.x;
+         mov->src[0].swizzle[1] = swizzle->mask.y;
+         mov->src[0].swizzle[2] = swizzle->mask.z;
+         mov->src[0].swizzle[3] = swizzle->mask.w;
+         for (unsigned i = deref->type->vector_elements; i < 4; i++)
+            mov->src[0].swizzle[i] = 0;
+
+         add_instr(&mov->instr, swizzle->type->vector_elements);
+      }
+
+      return;
+   }
+
+   default:
+      break;
+   }
+
    nir_src srcs[4];
    for (unsigned i = 0; i < ir->get_num_operands(); i++)
       srcs[i] = evaluate_rvalue(ir->operands[i]);
@@ -998,19 +1028,16 @@ nir_visitor::visit(ir_expression *ir)
       emit(supports_ints ? nir_op_inot : nir_op_fnot, dest_size, srcs);
       break;
    case ir_unop_neg:
-      instr = emit(types[0] == GLSL_TYPE_FLOAT ? nir_op_fmov : nir_op_imov,
+      instr = emit(types[0] == GLSL_TYPE_FLOAT ? nir_op_fneg : nir_op_ineg,
                    dest_size, srcs);
-      instr->src[0].negate = true;
       break;
    case ir_unop_abs:
-      instr = emit(types[0] == GLSL_TYPE_FLOAT ? nir_op_fmov : nir_op_imov,
+      instr = emit(types[0] == GLSL_TYPE_FLOAT ? nir_op_fabs : nir_op_iabs,
                    dest_size, srcs);
-      instr->src[0].abs = true;
       break;
    case ir_unop_saturate:
       assert(types[0] == GLSL_TYPE_FLOAT);
-      instr = emit(nir_op_fmov, dest_size, srcs);
-      instr->dest.saturate = true;
+      instr = emit(nir_op_fsat, dest_size, srcs);
       break;
    case ir_unop_sign:
       emit(types[0] == GLSL_TYPE_FLOAT ? nir_op_fsign : nir_op_isign,
@@ -1753,7 +1780,10 @@ nir_visitor::visit(ir_dereference_record *ir)
 {
    ir->record->accept(this);
 
-   nir_deref_struct *deref = nir_deref_struct_create(this->shader, ir->field);
+   int field_index = this->deref_tail->type->field_index(ir->field);
+   assert(field_index >= 0);
+
+   nir_deref_struct *deref = nir_deref_struct_create(this->shader, field_index);
    deref->deref.type = ir->type;
    this->deref_tail->child = &deref->deref;
    this->deref_tail = &deref->deref;