Merge branch 'master' of ../mesa into vulkan
[mesa.git] / src / gallium / drivers / r600 / sb / sb_bc_parser.cpp
index d787e5b1238d1504f1db7acd022ffd24687aa131..19bd0784a61eb5c1bc64bff6a4853ba012f2b6f8 100644 (file)
 #define BCP_DUMP(q)
 #endif
 
-extern "C" {
 #include "r600_pipe.h"
 #include "r600_shader.h"
-}
 
 #include <stack>
 
@@ -97,7 +95,7 @@ int bc_parser::decode_shader() {
                if ((r = decode_cf(i, eop)))
                        return r;
 
-       } while (!eop || (i >> 1) <= max_cf);
+       } while (!eop || (i >> 1) < max_cf);
 
        return 0;
 }
@@ -137,6 +135,16 @@ int bc_parser::parse_decls() {
                }
        }
 
+       // GS inputs can add indirect addressing
+       if (sh->target == TARGET_GS) {
+               if (pshader->num_arrays) {
+                       for (unsigned i = 0; i < pshader->num_arrays; ++i) {
+                               r600_shader_array &a = pshader->arrays[i];
+                               sh->add_gpr_array(a.gpr_start, a.gpr_count, a.comp_mask);
+                       }
+               }
+       }
+
        if (sh->target == TARGET_VS || sh->target == TARGET_ES)
                sh->add_input(0, 1, 0x0F);
        else if (sh->target == TARGET_GS) {
@@ -722,6 +730,16 @@ int bc_parser::prepare_ir() {
                                        c->flags |= NF_DONT_HOIST | NF_DONT_MOVE;
                                }
 
+                               if (flags & CF_EMIT) {
+                                       // Instruction implicitly depends on prior [EMIT_][CUT]_VERTEX
+                                       c->src.push_back(sh->get_special_value(SV_GEOMETRY_EMIT));
+                                       c->dst.push_back(sh->get_special_value(SV_GEOMETRY_EMIT));
+                                       if (sh->target == TARGET_ES) {
+                                               // For ES shaders this is an export
+                                               c->flags |= NF_DONT_KILL;
+                                       }
+                               }
+
                                if (!burst_count--)
                                        break;
 
@@ -738,6 +756,23 @@ int bc_parser::prepare_ir() {
 
                        c->bc.end_of_program = eop;
 
+               } else if (flags & CF_EMIT) {
+                       /* quick peephole */
+                       cf_node *prev = static_cast<cf_node *>(c->prev);
+                       if (c->bc.op == CF_OP_CUT_VERTEX &&
+                               prev && prev->is_valid() &&
+                               prev->bc.op == CF_OP_EMIT_VERTEX &&
+                               c->bc.count == prev->bc.count) {
+                               prev->bc.set_op(CF_OP_EMIT_CUT_VERTEX);
+                               prev->bc.end_of_program = c->bc.end_of_program;
+                               c->remove();
+                       }
+                       else {
+                               c->flags |= NF_DONT_KILL | NF_DONT_HOIST | NF_DONT_MOVE;
+
+                               c->src.push_back(sh->get_special_value(SV_GEOMETRY_EMIT));
+                               c->dst.push_back(sh->get_special_value(SV_GEOMETRY_EMIT));
+                       }
                }
        }
 
@@ -746,6 +781,7 @@ int bc_parser::prepare_ir() {
 }
 
 int bc_parser::prepare_loop(cf_node* c) {
+       assert(c->bc.addr-1 < cf_map.size());
 
        cf_node *end = cf_map[c->bc.addr - 1];
        assert(end->bc.op == CF_OP_LOOP_END);
@@ -758,13 +794,19 @@ int bc_parser::prepare_loop(cf_node* c) {
        c->insert_before(reg);
        rep->move(c, end->next);
 
+       reg->src_loop = true;
+
        loop_stack.push(reg);
        return 0;
 }
 
 int bc_parser::prepare_if(cf_node* c) {
+       assert(c->bc.addr-1 < cf_map.size());
        cf_node *c_else = NULL, *end = cf_map[c->bc.addr];
 
+       if (!end)
+               return 0; // not quite sure how this happens, malformed input?
+
        BCP_DUMP(
                sblog << "parsing JUMP @" << c->bc.id;
                sblog << "\n";
@@ -790,7 +832,7 @@ int bc_parser::prepare_if(cf_node* c) {
        if (c_else->parent != c->parent)
                c_else = NULL;
 
-       if (end->parent != c->parent)
+       if (end && end->parent != c->parent)
                end = NULL;
 
        region_node *reg = sh->create_region();