aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Forbes <[email protected]>2014-09-07 21:42:50 +1200
committerMarek Olšák <[email protected]>2015-07-23 00:59:28 +0200
commit8cf72972ce2fc7df83d0572745968bbcb41a8c92 (patch)
tree007d075aa2287a9d50109a2d6a42e59b9fb4aead
parent799afadf51ad1ff0775a1bf7b4f3954a8d368b09 (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]>
-rw-r--r--src/glsl/linker.cpp99
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.