diff options
author | Chris Forbes <[email protected]> | 2014-09-07 21:42:50 +1200 |
---|---|---|
committer | Marek Olšák <[email protected]> | 2015-07-23 00:59:28 +0200 |
commit | 8cf72972ce2fc7df83d0572745968bbcb41a8c92 (patch) | |
tree | 007d075aa2287a9d50109a2d6a42e59b9fb4aead /src/glsl/linker.cpp | |
parent | 799afadf51ad1ff0775a1bf7b4f3954a8d368b09 (diff) |
glsl: validate restrictions on use of barrier()
With the exception of always-taken switch cases (which are
indistinguishable from straight line code in our IR), this
disallows use of the builtin barrier() function in all the
places it may not appear.
Signed-off-by: Chris Forbes <[email protected]>
Reviewed-by: Kenneth Graunke <[email protected]>
Diffstat (limited to 'src/glsl/linker.cpp')
-rw-r--r-- | src/glsl/linker.cpp | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp index eeab3a3ca91..d0445f16032 100644 --- a/src/glsl/linker.cpp +++ b/src/glsl/linker.cpp @@ -297,6 +297,97 @@ public: } }; +class barrier_use_visitor : public ir_hierarchical_visitor { +public: + barrier_use_visitor(gl_shader_program *prog) + : prog(prog), in_main(false), after_return(false), control_flow(0) + { + } + + virtual ~barrier_use_visitor() + { + /* empty */ + } + + virtual ir_visitor_status visit_enter(ir_function *ir) + { + if (strcmp(ir->name, "main") == 0) + in_main = true; + + return visit_continue; + } + + virtual ir_visitor_status visit_leave(ir_function *ir) + { + in_main = false; + after_return = false; + return visit_continue; + } + + virtual ir_visitor_status visit_leave(ir_return *ir) + { + after_return = true; + return visit_continue; + } + + virtual ir_visitor_status visit_enter(ir_if *ir) + { + ++control_flow; + return visit_continue; + } + + virtual ir_visitor_status visit_leave(ir_if *ir) + { + --control_flow; + return visit_continue; + } + + virtual ir_visitor_status visit_enter(ir_loop *ir) + { + ++control_flow; + return visit_continue; + } + + virtual ir_visitor_status visit_leave(ir_loop *ir) + { + --control_flow; + return visit_continue; + } + + /* FINISHME: `switch` is not expressed at the IR level -- it's already + * been lowered to a mess of `if`s. We'll correctly disallow any use of + * barrier() in a conditional path within the switch, but not in a path + * which is always hit. + */ + + virtual ir_visitor_status visit_enter(ir_call *ir) + { + if (ir->use_builtin && strcmp(ir->callee_name(), "barrier") == 0) { + /* Use of barrier(); determine if it is legal: */ + if (!in_main) { + linker_error(prog, "Builtin barrier() may only be used in main"); + return visit_stop; + } + + if (after_return) { + linker_error(prog, "Builtin barrier() may not be used after return"); + return visit_stop; + } + + if (control_flow != 0) { + linker_error(prog, "Builtin barrier() may not be used inside control flow"); + return visit_stop; + } + } + return visit_continue; + } + +private: + gl_shader_program *prog; + bool in_main, after_return; + int control_flow; +}; + /** * Visitor that determines the highest stream id to which a (geometry) shader * emits vertices. It also checks whether End{Stream}Primitive is ever called. @@ -2050,6 +2141,14 @@ link_intrastage_shaders(void *mem_ctx, if (ctx->Const.VertexID_is_zero_based) lower_vertex_id(linked); + /* Validate correct usage of barrier() in the tess control shader */ + if (linked->Stage == MESA_SHADER_TESS_CTRL) { + barrier_use_visitor visitor(prog); + foreach_in_list(ir_instruction, ir, linked->ir) { + ir->accept(&visitor); + } + } + /* Make a pass over all variable declarations to ensure that arrays with * unspecified sizes have a size specified. The size is inferred from the * max_array_access field. |