From 4031ea1520f582fa36a6b964de7d565fe33a538d Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Wed, 17 Jun 2009 11:57:39 -0600 Subject: glsl: Added gl_shader_state::EmitContReturn field This is the start of a glsl-continue-return feature branch to support a GLSL code generator option for 'continue' and 'return' statements. Some targets don't support CONT or RET statements so we'll need to try to generate code that does not use them... --- src/mesa/shader/shader_api.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/shader_api.c b/src/mesa/shader/shader_api.c index 644cd39185..cf9f8b9222 100644 --- a/src/mesa/shader/shader_api.c +++ b/src/mesa/shader/shader_api.c @@ -402,6 +402,7 @@ _mesa_init_shader_state(GLcontext * ctx) * are generated by the GLSL compiler. */ ctx->Shader.EmitHighLevelInstructions = GL_TRUE; + ctx->Shader.EmitContReturn = GL_TRUE; ctx->Shader.EmitCondCodes = GL_FALSE; ctx->Shader.EmitComments = GL_FALSE; ctx->Shader.Flags = get_shader_flags(); -- cgit v1.2.3 From 625b0fe2684de462d1e7ea7fc8fcdfc8e3283949 Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Wed, 17 Jun 2009 13:48:52 -0600 Subject: Revert "slang: if/else/break & if/else/continue work for unrolled loops" We should just check if the loop contains a continue/break in the _slang_can_unroll_for_loop() test function... This reverts commit 989856bde47d699d7e18798df4013fbf962e1d4b. Conflicts: src/mesa/shader/slang/slang_codegen.h --- src/mesa/shader/slang/slang_codegen.c | 44 ++++++----------------------------- src/mesa/shader/slang/slang_codegen.h | 1 - 2 files changed, 7 insertions(+), 38 deletions(-) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index 6d693c9027..f19da41b0d 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -2582,20 +2582,6 @@ _slang_can_unroll_for_loop(slang_assemble_ctx * A, const slang_operation *oper) } -static void -_unroll_loop_inc(slang_assemble_ctx * A) -{ - A->UnrollLoop++; -} - - -static void -_unroll_loop_dec(slang_assemble_ctx * A) -{ - A->UnrollLoop--; -} - - /** * Unroll a for-loop. * First we determine the number of iterations to unroll. @@ -2612,9 +2598,6 @@ _slang_unroll_for_loop(slang_assemble_ctx * A, const slang_operation *oper) slang_ir_node *n, *root = NULL; slang_atom varId; - /* Set flag so code generator knows we're unrolling loops */ - _unroll_loop_inc( A ); - if (oper->children[0].type == SLANG_OPER_BLOCK_NO_NEW_SCOPE) { /* for (int i=0; ... */ slang_variable *var; @@ -2637,15 +2620,11 @@ _slang_unroll_for_loop(slang_assemble_ctx * A, const slang_operation *oper) /* make a copy of the loop body */ body = slang_operation_new(1); - if (!body) { - _unroll_loop_dec( A ); + if (!body) return NULL; - } - if (!slang_operation_copy(body, &oper->children[3])) { - _unroll_loop_dec( A ); + if (!slang_operation_copy(body, &oper->children[3])) return NULL; - } /* in body, replace instances of 'varId' with literal 'iter' */ { @@ -2656,7 +2635,6 @@ _slang_unroll_for_loop(slang_assemble_ctx * A, const slang_operation *oper) if (!oldVar) { /* undeclared loop variable */ slang_operation_delete(body); - _unroll_loop_dec( A ); return NULL; } @@ -2671,18 +2649,14 @@ _slang_unroll_for_loop(slang_assemble_ctx * A, const slang_operation *oper) /* do IR codegen for body */ n = _slang_gen_operation(A, body); - if (!n) { - _unroll_loop_dec( A ); + if (!n) return NULL; - } root = new_seq(root, n); slang_operation_delete(body); } - _unroll_loop_dec( A ); - return root; } @@ -2819,7 +2793,7 @@ _slang_gen_if(slang_assemble_ctx * A, const slang_operation *oper) if (is_operation_type(&oper->children[1], SLANG_OPER_BREAK) && !haveElseClause) { /* Special case: generate a conditional break */ - if (!A->CurLoop && A->UnrollLoop) /* trying to unroll */ + if (!A->CurLoop) /* probably trying to unroll */ return NULL; ifBody = new_break_if_true(A->CurLoop, cond); return ifBody; @@ -2827,7 +2801,7 @@ _slang_gen_if(slang_assemble_ctx * A, const slang_operation *oper) else if (is_operation_type(&oper->children[1], SLANG_OPER_CONTINUE) && !haveElseClause) { /* Special case: generate a conditional continue */ - if (!A->CurLoop && A->UnrollLoop) /* trying to unroll */ + if (!A->CurLoop) /* probably trying to unroll */ return NULL; ifBody = new_cont_if_true(A->CurLoop, cond); return ifBody; @@ -2835,8 +2809,6 @@ _slang_gen_if(slang_assemble_ctx * A, const slang_operation *oper) else { /* general case */ ifBody = _slang_gen_operation(A, &oper->children[1]); - if (!ifBody) - return NULL; if (haveElseClause) elseBody = _slang_gen_operation(A, &oper->children[2]); else @@ -4049,15 +4021,13 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper) return _slang_gen_while(A, oper); case SLANG_OPER_BREAK: if (!A->CurLoop) { - if (!A->UnrollLoop) - slang_info_log_error(A->log, "'break' not in loop"); + slang_info_log_error(A->log, "'break' not in loop"); return NULL; } return new_break(A->CurLoop); case SLANG_OPER_CONTINUE: if (!A->CurLoop) { - if (!A->UnrollLoop) - slang_info_log_error(A->log, "'continue' not in loop"); + slang_info_log_error(A->log, "'continue' not in loop"); return NULL; } return _slang_gen_continue(A, oper); diff --git a/src/mesa/shader/slang/slang_codegen.h b/src/mesa/shader/slang/slang_codegen.h index d80013ad34..ce6cc7cb8f 100644 --- a/src/mesa/shader/slang/slang_codegen.h +++ b/src/mesa/shader/slang/slang_codegen.h @@ -42,7 +42,6 @@ typedef struct slang_assemble_ctx_ struct slang_label_ *curFuncEndLabel; struct slang_ir_node_ *CurLoop; struct slang_function_ *CurFunction; - GLuint UnrollLoop; GLboolean UnresolvedRefs; } slang_assemble_ctx; -- cgit v1.2.3 From 4bc74a07561eeaa97dbde55c384998ea6aa5968c Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Wed, 17 Jun 2009 13:51:35 -0600 Subject: glsl: don't unroll loops containing continue/break Just search the AST in _slang_can_unroll_for_loop(). --- src/mesa/shader/slang/slang_codegen.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index f19da41b0d..f6274780ad 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -2488,6 +2488,12 @@ _slang_can_unroll_for_loop(slang_assemble_ctx * A, const slang_operation *oper) assert(oper->type == SLANG_OPER_FOR); assert(oper->num_children == 4); + if (_slang_find_node_type((slang_operation *) oper, SLANG_OPER_CONTINUE) || + _slang_find_node_type((slang_operation *) oper, SLANG_OPER_BREAK)) { + /* dont't unroll loops containing continue/break statements */ + return GL_FALSE; + } + /* children[0] must be either "int i=constant" or "i=constant" */ if (oper->children[0].type == SLANG_OPER_BLOCK_NO_NEW_SCOPE) { slang_variable *var; -- cgit v1.2.3 From c20bb48d3a897fd616bf4c7d4eb67ea34475985d Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Thu, 18 Jun 2009 14:11:38 -0600 Subject: glsl: added slang_assemble_ctx::EmitContReturn field, init --- src/mesa/shader/slang/slang_codegen.h | 1 + src/mesa/shader/slang/slang_compile.c | 3 +++ 2 files changed, 4 insertions(+) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_codegen.h b/src/mesa/shader/slang/slang_codegen.h index ce6cc7cb8f..bb736585aa 100644 --- a/src/mesa/shader/slang/slang_codegen.h +++ b/src/mesa/shader/slang/slang_codegen.h @@ -43,6 +43,7 @@ typedef struct slang_assemble_ctx_ struct slang_ir_node_ *CurLoop; struct slang_function_ *CurFunction; GLboolean UnresolvedRefs; + GLboolean EmitContReturn; } slang_assemble_ctx; diff --git a/src/mesa/shader/slang/slang_compile.c b/src/mesa/shader/slang/slang_compile.c index d7ad879e97..c1b97c7cb7 100644 --- a/src/mesa/shader/slang/slang_compile.c +++ b/src/mesa/shader/slang/slang_compile.c @@ -1953,6 +1953,7 @@ static int parse_init_declarator(slang_parse_ctx * C, slang_output_ctx * O, const slang_fully_specified_type * type) { + GET_CURRENT_CONTEXT(ctx); /* a hack */ slang_variable *var; slang_atom a_name; @@ -2066,6 +2067,7 @@ parse_init_declarator(slang_parse_ctx * C, slang_output_ctx * O, A.vartable = O->vartable; A.log = C->L; A.curFuncEndLabel = NULL; + A.EmitContReturn = ctx->Shader.EmitContReturn; if (!_slang_codegen_global_variable(&A, var, C->type)) RETURN0; } @@ -2430,6 +2432,7 @@ parse_code_unit(slang_parse_ctx * C, slang_code_unit * unit, A.program = o.program; A.pragmas = &shader->Pragmas; A.vartable = o.vartable; + A.EmitContReturn = ctx->Shader.EmitContReturn; A.log = C->L; /* main() takes no parameters */ -- cgit v1.2.3 From c4fd947beedbd1e2f8fdaf4ead3b2a8249bd239e Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Thu, 18 Jun 2009 14:11:59 -0600 Subject: glsl: added slang_operation_add_children() and slang_oper_child() helpers --- src/mesa/shader/slang/slang_compile_operation.c | 14 ++++++++++++++ src/mesa/shader/slang/slang_compile_operation.h | 11 +++++++++++ 2 files changed, 25 insertions(+) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_compile_operation.c b/src/mesa/shader/slang/slang_compile_operation.c index e650616880..310a46b645 100644 --- a/src/mesa/shader/slang/slang_compile_operation.c +++ b/src/mesa/shader/slang/slang_compile_operation.c @@ -272,3 +272,17 @@ _slang_operation_swap(slang_operation *oper0, slang_operation *oper1) } +void +slang_operation_add_children(slang_operation *oper, GLuint num_children) +{ + GLuint i; + assert(oper->num_children == 0); + assert(oper->children == NULL); + oper->num_children = num_children; + oper->children = slang_operation_new(num_children); + for (i = 0; i < num_children; i++) { + oper->children[i].locals = _slang_variable_scope_new(oper->locals); + } +} + + diff --git a/src/mesa/shader/slang/slang_compile_operation.h b/src/mesa/shader/slang/slang_compile_operation.h index 37af5d617c..627356bb56 100644 --- a/src/mesa/shader/slang/slang_compile_operation.h +++ b/src/mesa/shader/slang/slang_compile_operation.h @@ -161,4 +161,15 @@ extern void _slang_operation_swap(slang_operation *oper0, slang_operation *oper1); +extern void +slang_operation_add_children(slang_operation *oper, GLuint num_children); + +static INLINE slang_operation * +slang_oper_child(slang_operation *oper, GLuint child) +{ + assert(child < oper->num_children); + return &oper->children[child]; +} + + #endif /* SLANG_COMPILE_OPERATION_H */ -- cgit v1.2.3 From f66733bbeeeed767b86a14caec61a87f14d8135a Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Thu, 18 Jun 2009 14:14:53 -0600 Subject: glsl: implement continue->break transformation for for-loops --- src/mesa/shader/slang/slang_codegen.c | 170 +++++++++++++++++++++++++++++++++- 1 file changed, 167 insertions(+), 3 deletions(-) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index f6274780ad..e41b43853a 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -2485,7 +2485,9 @@ _slang_can_unroll_for_loop(slang_assemble_ctx * A, const slang_operation *oper) const char *varName; slang_atom varId; - assert(oper->type == SLANG_OPER_FOR); + if (oper->type != SLANG_OPER_FOR) + return GL_FALSE; + assert(oper->num_children == 4); if (_slang_find_node_type((slang_operation *) oper, SLANG_OPER_CONTINUE) || @@ -2667,20 +2669,181 @@ _slang_unroll_for_loop(slang_assemble_ctx * A, const slang_operation *oper) } +/** + * Transform a for-loop so that continue statements are converted to breaks. + * Then do normal IR code generation. + * + * Before: + * + * for (INIT; LOOPCOND; INCR) { + * A; + * if (IFCOND) { + * continue; + * } + * B; + * } + * + * After: + * + * { + * bool _condFlag = 1; + * for (INIT; _condFlag; ) { + * for ( ; _condFlag = LOOPCOND; INCR) { + * A; + * if (IFCOND) { + * break; + * } + * B; + * } + * if (_condFlag) + * INCR; + * } + * } + */ +static slang_ir_node * +_slang_gen_for_without_continue(slang_assemble_ctx *A, slang_operation *oper) +{ + slang_operation *top; + slang_operation *outerFor, *innerFor, *init, *cond, *incr; + slang_operation *lhs, *rhs; + + assert(oper->type == SLANG_OPER_FOR); + + top = slang_operation_new(1); + top->type = SLANG_OPER_BLOCK_NEW_SCOPE; + top->locals->outer_scope = oper->locals->outer_scope; + slang_operation_add_children(top, 2); + + /* declare: bool _condFlag = true */ + { + slang_operation *condDecl; + slang_variable *var; + + condDecl = slang_oper_child(top, 0); + condDecl->type = SLANG_OPER_VARIABLE_DECL; + var = slang_variable_scope_grow(top->locals); + slang_fully_specified_type_construct(&var->type); + var->type.specifier.type = SLANG_SPEC_BOOL; + var->a_name = slang_atom_pool_atom(A->atoms, "_condFlag"); + condDecl->a_id = var->a_name; + var->initializer = slang_operation_new(1); + var->initializer->type = SLANG_OPER_LITERAL_BOOL; + var->initializer->literal[0] = 1.0; + } + + /* build outer loop: for (INIT; _condFlag; ) { */ + outerFor = slang_oper_child(top, 1); + outerFor->type = SLANG_OPER_FOR; + slang_operation_add_children(outerFor, 4); + + init = slang_oper_child(outerFor, 0); + slang_operation_copy(init, slang_oper_child(oper, 0)); + + cond = slang_oper_child(outerFor, 1); + cond->type = SLANG_OPER_IDENTIFIER; + cond->a_id = slang_atom_pool_atom(A->atoms, "_condFlag"); + + incr = slang_oper_child(outerFor, 2); + incr->type = SLANG_OPER_VOID; + + /* body of the outer loop */ + { + slang_operation *block = slang_oper_child(outerFor, 3); + + slang_operation_add_children(block, 2); + block->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE; + + /* build inner loop: for ( ; _condFlag = LOOPCOND; INCR) { */ + { + innerFor = slang_oper_child(block, 0); + + /* make copy of orig loop */ + slang_operation_copy(innerFor, oper); + assert(innerFor->type == SLANG_OPER_FOR); + innerFor->locals->outer_scope = block->locals; + + init = slang_oper_child(innerFor, 0); + init->type = SLANG_OPER_VOID; /* leak? */ + + cond = slang_oper_child(innerFor, 1); + slang_operation_destruct(cond); + cond->type = SLANG_OPER_ASSIGN; + cond->locals = _slang_variable_scope_new(innerFor->locals); + slang_operation_add_children(cond, 2); + + lhs = slang_oper_child(cond, 0); + lhs->type = SLANG_OPER_IDENTIFIER; + lhs->a_id = slang_atom_pool_atom(A->atoms, "_condFlag"); + + rhs = slang_oper_child(cond, 1); + slang_operation_copy(rhs, slang_oper_child(oper, 1)); + } + + /* if (_condFlag) INCR; */ + { + slang_operation *ifop = slang_oper_child(block, 1); + ifop->type = SLANG_OPER_IF; + slang_operation_add_children(ifop, 2); + + /* re-use cond node build above */ + slang_operation_copy(slang_oper_child(ifop, 0), cond); + + /* incr node from original for-loop operation */ + slang_operation_copy(slang_oper_child(ifop, 1), + slang_oper_child(oper, 2)); + } + + /* finally, replace "continue" with "break" in inner for-loop */ + { + slang_operation *body = slang_oper_child(innerFor, 3); + printf("remove continue!\n"); + while (1) { + slang_operation *op =_slang_find_node_type(body, SLANG_OPER_CONTINUE); + if (op) { + op->type = SLANG_OPER_BREAK; + } + else { + break; + } + } + } + } + + slang_print_tree(top, 5); + + + return _slang_gen_operation(A, top); + //return top;//oper; +} + + + /** * Generate IR for a for-loop. Unrolling will be done when possible. */ static slang_ir_node * -_slang_gen_for(slang_assemble_ctx * A, const slang_operation *oper) +_slang_gen_for(slang_assemble_ctx * A, slang_operation *oper) { - GLboolean unroll = _slang_can_unroll_for_loop(A, oper); + GLboolean unroll; + if (!A->EmitContReturn) { + /* We don't want to emit CONT instructions. If this for-loop has + * a continue, translate it away. + */ + if (_slang_find_node_type(oper, SLANG_OPER_CONTINUE)) { + return _slang_gen_for_without_continue(A, oper); + } + } + + unroll = _slang_can_unroll_for_loop(A, oper); if (unroll) { slang_ir_node *code = _slang_unroll_for_loop(A, oper); if (code) return code; } + assert(oper->type == SLANG_OPER_FOR); + /* conventional for-loop code generation */ { /* @@ -3435,6 +3598,7 @@ _slang_gen_declaration(slang_assemble_ctx *A, slang_operation *oper) assert(oper->type == SLANG_OPER_VARIABLE_DECL); assert(oper->num_children <= 1); + /* lookup the variable by name */ var = _slang_variable_locate(oper->locals, oper->a_id, GL_TRUE); if (!var) -- cgit v1.2.3 From f38872473cc035487dbe265a520cb4c6eb3cc81c Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Thu, 18 Jun 2009 14:24:30 -0600 Subject: glsl: remove debug code, misc clean-up --- src/mesa/shader/slang/slang_codegen.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index e41b43853a..55a47b336d 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -2796,7 +2796,6 @@ _slang_gen_for_without_continue(slang_assemble_ctx *A, slang_operation *oper) /* finally, replace "continue" with "break" in inner for-loop */ { slang_operation *body = slang_oper_child(innerFor, 3); - printf("remove continue!\n"); while (1) { slang_operation *op =_slang_find_node_type(body, SLANG_OPER_CONTINUE); if (op) { @@ -2809,11 +2808,7 @@ _slang_gen_for_without_continue(slang_assemble_ctx *A, slang_operation *oper) } } - slang_print_tree(top, 5); - - return _slang_gen_operation(A, top); - //return top;//oper; } -- cgit v1.2.3 From c1f74a6734494d0531eb7dc844bb83e7d9c9f1fa Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Thu, 18 Jun 2009 16:57:23 -0600 Subject: glsl: don't allocate 0-length children array in slang_operation_copy() --- src/mesa/shader/slang/slang_compile_operation.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_compile_operation.c b/src/mesa/shader/slang/slang_compile_operation.c index 310a46b645..730cc06912 100644 --- a/src/mesa/shader/slang/slang_compile_operation.c +++ b/src/mesa/shader/slang/slang_compile_operation.c @@ -119,11 +119,13 @@ slang_operation_copy(slang_operation * x, const slang_operation * y) if (!slang_operation_construct(&z)) return GL_FALSE; z.type = y->type; - z.children = (slang_operation *) - _slang_alloc(y->num_children * sizeof(slang_operation)); - if (z.children == NULL) { - slang_operation_destruct(&z); - return GL_FALSE; + if (y->num_children > 0) { + z.children = (slang_operation *) + _slang_alloc(y->num_children * sizeof(slang_operation)); + if (z.children == NULL) { + slang_operation_destruct(&z); + return GL_FALSE; + } } for (z.num_children = 0; z.num_children < y->num_children; z.num_children++) { @@ -285,4 +287,3 @@ slang_operation_add_children(slang_operation *oper, GLuint num_children) } } - -- cgit v1.2.3 From 7e0eaca201c0a5678752e9d3de6f699ff8281f75 Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Thu, 18 Jun 2009 16:57:53 -0600 Subject: glsl: added slang_operation_literal_int/bool() helper functions --- src/mesa/shader/slang/slang_compile_operation.h | 26 +++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_compile_operation.h b/src/mesa/shader/slang/slang_compile_operation.h index 627356bb56..f07aa1c02e 100644 --- a/src/mesa/shader/slang/slang_compile_operation.h +++ b/src/mesa/shader/slang/slang_compile_operation.h @@ -172,4 +172,30 @@ slang_oper_child(slang_operation *oper, GLuint child) } +/** Init oper to a boolean literal. */ +static INLINE void +slang_operation_literal_bool(slang_operation *oper, GLboolean value) +{ + oper->type = SLANG_OPER_LITERAL_BOOL; + oper->literal[0] = + oper->literal[1] = + oper->literal[2] = + oper->literal[3] = (float) value; + oper->literal_size = 1; +} + + +/** Init oper to an int literal. */ +static INLINE void +slang_operation_literal_int(slang_operation *oper, GLint value) +{ + oper->type = SLANG_OPER_LITERAL_INT; + oper->literal[0] = + oper->literal[1] = + oper->literal[2] = + oper->literal[3] = (float) value; + oper->literal_size = 1; +} + + #endif /* SLANG_COMPILE_OPERATION_H */ -- cgit v1.2.3 From aba93643be09589318cfde33556d872b1cd9ea75 Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Thu, 18 Jun 2009 17:08:10 -0600 Subject: glsl: implement continue->break translation for do-while loops --- src/mesa/shader/slang/slang_codegen.c | 234 +++++++++++++++++++++++++++++++--- 1 file changed, 219 insertions(+), 15 deletions(-) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index 55a47b336d..5f40ddda20 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -326,6 +326,17 @@ sampler_to_texture_index(const slang_type_specifier_type type) } +/** helper to build a SLANG_OPER_IDENTIFIER node */ +static void +slang_operation_identifier(slang_operation *oper, + slang_assemble_ctx *A, + const char *name) +{ + oper->type = SLANG_OPER_IDENTIFIER; + oper->a_id = slang_atom_pool_atom(A->atoms, name); +} + + #define SWIZZLE_ZWWW MAKE_SWIZZLE4(SWIZZLE_Z, SWIZZLE_W, SWIZZLE_W, SWIZZLE_W) /** @@ -2398,6 +2409,174 @@ _slang_gen_while(slang_assemble_ctx * A, const slang_operation *oper) } +/** + * Replace 'break' and 'continue' statements inside a do-while loop. + * This is a recursive helper function used by _slang_gen_do_without_continue(). + */ +static void +replace_break_and_cont(slang_assemble_ctx *A, slang_operation *oper) +{ + switch (oper->type) { + case SLANG_OPER_BREAK: + /* replace 'break' with "_notBreakFlag = false; break" */ + { + slang_operation *block = oper; + block->type = SLANG_OPER_BLOCK_NEW_SCOPE; + slang_operation_add_children(block, 2); + { + slang_operation *assign = slang_oper_child(block, 0); + assign->type = SLANG_OPER_ASSIGN; + slang_operation_add_children(assign, 2); + { + slang_operation *lhs = slang_oper_child(assign, 0); + slang_operation_identifier(lhs, A, "_notBreakFlag"); + } + { + slang_operation *rhs = slang_oper_child(assign, 1); + slang_operation_literal_bool(rhs, GL_FALSE); + } + } + { + slang_operation *brk = slang_oper_child(block, 1); + brk->type = SLANG_OPER_BREAK; + assert(!brk->children); + } + } + break; + case SLANG_OPER_CONTINUE: + /* convert continue into a break */ + oper->type = SLANG_OPER_BREAK; + break; + case SLANG_OPER_FOR: + case SLANG_OPER_DO: + case SLANG_OPER_WHILE: + /* stop upon finding a nested loop */ + break; + default: + /* recurse */ + { + GLuint i; + for (i = 0; i < oper->num_children; i++) { + replace_break_and_cont(A, slang_oper_child(oper, i)); + } + } + } +} + + +/** + * Transform a do-while-loop so that continue statements are converted to breaks. + * Then do normal IR code generation. + * + * Before: + * + * do { + * A; + * if (IFCOND) + * continue; + * B; + * break; + * C; + * } while (LOOPCOND); + * + * After: + * + * { + * bool _notBreakFlag = 1; + * do { + * do { + * A; + * if (IFCOND) { + * break; // was continue + * } + * B; + * _notBreakFlag = 0; // was + * break; // break + * C; + * } while (0) + * } while (_notBreakFlag && LOOPCOND); + * } + */ +static slang_ir_node * +_slang_gen_do_without_continue(slang_assemble_ctx *A, slang_operation *oper) +{ + slang_operation *top; + slang_operation *innerBody; + + assert(oper->type == SLANG_OPER_DO); + + top = slang_operation_new(1); + top->type = SLANG_OPER_BLOCK_NEW_SCOPE; + top->locals->outer_scope = oper->locals->outer_scope; + slang_operation_add_children(top, 2); + + /* declare: bool _notBreakFlag = true */ + { + slang_operation *condDecl = slang_oper_child(top, 0); + slang_variable *var; + + condDecl->type = SLANG_OPER_VARIABLE_DECL; + var = slang_variable_scope_grow(top->locals); + slang_fully_specified_type_construct(&var->type); + var->type.specifier.type = SLANG_SPEC_BOOL; + var->a_name = slang_atom_pool_atom(A->atoms, "_notBreakFlag"); + condDecl->a_id = var->a_name; + var->initializer = slang_operation_new(1); + slang_operation_literal_bool(var->initializer, GL_TRUE); + } + + /* build outer do-loop: do { ... } while (_notBreakFlag && LOOPCOND) */ + { + slang_operation *outerDo = slang_oper_child(top, 1); + outerDo->type = SLANG_OPER_DO; + slang_operation_add_children(outerDo, 2); + + /* inner do-loop */ + { + slang_operation *innerDo = slang_oper_child(outerDo, 0); + innerDo->type = SLANG_OPER_DO; + slang_operation_add_children(innerDo, 2); + + /* copy original do-loop body into inner do-loop's body */ + innerBody = slang_oper_child(innerDo, 0); + slang_operation_copy(innerBody, slang_oper_child(oper, 0)); + innerBody->locals->outer_scope = innerDo->locals; + + /* inner do-loop's condition is constant/false */ + { + slang_operation *constFalse = slang_oper_child(innerDo, 1); + slang_operation_literal_bool(constFalse, GL_FALSE); + } + } + + /* _notBreakFlag && LOOPCOND */ + { + slang_operation *cond = slang_oper_child(outerDo, 1); + cond->type = SLANG_OPER_LOGICALAND; + slang_operation_add_children(cond, 2); + { + slang_operation *notBreak = slang_oper_child(cond, 0); + slang_operation_identifier(notBreak, A, "_notBreakFlag"); + } + { + slang_operation *origCond = slang_oper_child(cond, 1); + slang_operation_copy(origCond, slang_oper_child(oper, 1)); + } + } + } + + /* Finally, in innerBody, + * replace "break" with "_notBreakFlag = 0; break" + * replace "continue" with "break" + */ + replace_break_and_cont(A, innerBody); + + slang_print_tree(top, 0); + + return _slang_gen_operation(A, top); +} + + /** * Generate IR tree for a do-while loop using high-level LOOP, IF instructions. */ @@ -2413,6 +2592,15 @@ _slang_gen_do(slang_assemble_ctx * A, const slang_operation *oper) slang_ir_node *prevLoop, *loop; GLboolean isConst, constTrue; + if (!A->EmitContReturn) { + /* We don't want to emit CONT instructions. If this do-loop has + * a continue, translate it away. + */ + if (_slang_find_node_type((slang_operation *) oper, SLANG_OPER_CONTINUE)) { + return _slang_gen_do_without_continue(A, (slang_operation *) oper); + } + } + /* type-check expression */ if (!_slang_is_boolean(A, &oper->children[1])) { slang_info_log_error(A->log, "scalar/boolean expression expected for 'do/while'"); @@ -2669,6 +2857,34 @@ _slang_unroll_for_loop(slang_assemble_ctx * A, const slang_operation *oper) } +/** + * Replace 'continue' statement with 'break' inside a for-loop. + * This is a recursive helper function used by _slang_gen_for_without_continue(). + */ +static void +replace_continue_with_break(slang_assemble_ctx *A, slang_operation *oper) +{ + switch (oper->type) { + case SLANG_OPER_CONTINUE: + oper->type = SLANG_OPER_BREAK; + break; + case SLANG_OPER_FOR: + case SLANG_OPER_DO: + case SLANG_OPER_WHILE: + /* stop upon finding a nested loop */ + break; + default: + /* recurse */ + { + GLuint i; + for (i = 0; i < oper->num_children; i++) { + replace_continue_with_break(A, slang_oper_child(oper, i)); + } + } + } +} + + /** * Transform a for-loop so that continue statements are converted to breaks. * Then do normal IR code generation. @@ -2727,8 +2943,7 @@ _slang_gen_for_without_continue(slang_assemble_ctx *A, slang_operation *oper) var->a_name = slang_atom_pool_atom(A->atoms, "_condFlag"); condDecl->a_id = var->a_name; var->initializer = slang_operation_new(1); - var->initializer->type = SLANG_OPER_LITERAL_BOOL; - var->initializer->literal[0] = 1.0; + slang_operation_literal_bool(var->initializer, GL_TRUE); } /* build outer loop: for (INIT; _condFlag; ) { */ @@ -2793,19 +3008,8 @@ _slang_gen_for_without_continue(slang_assemble_ctx *A, slang_operation *oper) slang_oper_child(oper, 2)); } - /* finally, replace "continue" with "break" in inner for-loop */ - { - slang_operation *body = slang_oper_child(innerFor, 3); - while (1) { - slang_operation *op =_slang_find_node_type(body, SLANG_OPER_CONTINUE); - if (op) { - op->type = SLANG_OPER_BREAK; - } - else { - break; - } - } - } + /* finally, replace "continue" with "break" in the inner for-loop */ + replace_continue_with_break(A, slang_oper_child(innerFor, 3)); } return _slang_gen_operation(A, top); -- cgit v1.2.3 From 4dafac2b2f850caba8e1a5982aca60a7d509fde6 Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Thu, 18 Jun 2009 17:25:47 -0600 Subject: glsl: use new _slang_loop_contains_continue() helper function --- src/mesa/shader/slang/slang_codegen.c | 131 ++++++++++++++++++++++++++++++++-- 1 file changed, 126 insertions(+), 5 deletions(-) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index 5f40ddda20..64dfdaff7e 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -2347,11 +2347,123 @@ _slang_is_boolean(slang_assemble_ctx *A, slang_operation *oper) } +/** + * Check if a loop contains a 'continue' statement. + * Stop looking if we find a nested loop. + */ +static GLboolean +_slang_loop_contains_continue(const slang_operation *oper) +{ + switch (oper->type) { + case SLANG_OPER_CONTINUE: + return GL_TRUE; + case SLANG_OPER_FOR: + case SLANG_OPER_DO: + case SLANG_OPER_WHILE: + /* stop upon finding a nested loop */ + return GL_FALSE; + default: + /* recurse */ + { + GLuint i; + for (i = 0; i < oper->num_children; i++) { + if (_slang_loop_contains_continue(slang_oper_child((slang_operation *) oper, i))) + return GL_TRUE; + } + } + return GL_FALSE; + } +} + + +static slang_ir_node * +_slang_gen_while_without_continue(slang_assemble_ctx *A, slang_operation *oper) +{ +#if 0 + slang_operation *top; + slang_operation *innerBody; + + assert(oper->type == SLANG_OPER_DO); + + top = slang_operation_new(1); + top->type = SLANG_OPER_BLOCK_NEW_SCOPE; + top->locals->outer_scope = oper->locals->outer_scope; + slang_operation_add_children(top, 2); + + /* declare: bool _notBreakFlag = true */ + { + slang_operation *condDecl = slang_oper_child(top, 0); + slang_variable *var; + + condDecl->type = SLANG_OPER_VARIABLE_DECL; + var = slang_variable_scope_grow(top->locals); + slang_fully_specified_type_construct(&var->type); + var->type.specifier.type = SLANG_SPEC_BOOL; + var->a_name = slang_atom_pool_atom(A->atoms, "_notBreakFlag"); + condDecl->a_id = var->a_name; + var->initializer = slang_operation_new(1); + slang_operation_literal_bool(var->initializer, GL_TRUE); + } + + /* build outer do-loop: do { ... } while (_notBreakFlag && LOOPCOND) */ + { + slang_operation *outerDo = slang_oper_child(top, 1); + outerDo->type = SLANG_OPER_DO; + slang_operation_add_children(outerDo, 2); + + /* inner do-loop */ + { + slang_operation *innerDo = slang_oper_child(outerDo, 0); + innerDo->type = SLANG_OPER_DO; + slang_operation_add_children(innerDo, 2); + + /* copy original do-loop body into inner do-loop's body */ + innerBody = slang_oper_child(innerDo, 0); + slang_operation_copy(innerBody, slang_oper_child(oper, 0)); + innerBody->locals->outer_scope = innerDo->locals; + + /* inner do-loop's condition is constant/false */ + { + slang_operation *constFalse = slang_oper_child(innerDo, 1); + slang_operation_literal_bool(constFalse, GL_FALSE); + } + } + + /* _notBreakFlag && LOOPCOND */ + { + slang_operation *cond = slang_oper_child(outerDo, 1); + cond->type = SLANG_OPER_LOGICALAND; + slang_operation_add_children(cond, 2); + { + slang_operation *notBreak = slang_oper_child(cond, 0); + slang_operation_identifier(notBreak, A, "_notBreakFlag"); + } + { + slang_operation *origCond = slang_oper_child(cond, 1); + slang_operation_copy(origCond, slang_oper_child(oper, 1)); + } + } + } + + /* Finally, in innerBody, + * replace "break" with "_notBreakFlag = 0; break" + * replace "continue" with "break" + */ + replace_break_and_cont(A, innerBody); + + slang_print_tree(top, 0); + + return _slang_gen_operation(A, top); +#endif + return NULL; +} + + /** * Generate loop code using high-level IR_LOOP instruction */ static slang_ir_node * -_slang_gen_while(slang_assemble_ctx * A, const slang_operation *oper) +_slang_gen_while(slang_assemble_ctx * A, slang_operation *oper) { /* * LOOP: @@ -2361,6 +2473,15 @@ _slang_gen_while(slang_assemble_ctx * A, const slang_operation *oper) slang_ir_node *prevLoop, *loop, *breakIf, *body; GLboolean isConst, constTrue; + if (!A->EmitContReturn) { + /* We don't want to emit CONT instructions. If this while-loop has + * a continue, translate it away. + */ + if (_slang_loop_contains_continue(slang_oper_child(oper, 1))) { + return _slang_gen_while_without_continue(A, oper); + } + } + /* type-check expression */ if (!_slang_is_boolean(A, &oper->children[0])) { slang_info_log_error(A->log, "scalar/boolean expression expected for 'while'"); @@ -2581,7 +2702,7 @@ _slang_gen_do_without_continue(slang_assemble_ctx *A, slang_operation *oper) * Generate IR tree for a do-while loop using high-level LOOP, IF instructions. */ static slang_ir_node * -_slang_gen_do(slang_assemble_ctx * A, const slang_operation *oper) +_slang_gen_do(slang_assemble_ctx * A, slang_operation *oper) { /* * LOOP: @@ -2596,8 +2717,8 @@ _slang_gen_do(slang_assemble_ctx * A, const slang_operation *oper) /* We don't want to emit CONT instructions. If this do-loop has * a continue, translate it away. */ - if (_slang_find_node_type((slang_operation *) oper, SLANG_OPER_CONTINUE)) { - return _slang_gen_do_without_continue(A, (slang_operation *) oper); + if (_slang_loop_contains_continue(slang_oper_child(oper, 0))) { + return _slang_gen_do_without_continue(A, oper); } } @@ -3029,7 +3150,7 @@ _slang_gen_for(slang_assemble_ctx * A, slang_operation *oper) /* We don't want to emit CONT instructions. If this for-loop has * a continue, translate it away. */ - if (_slang_find_node_type(oper, SLANG_OPER_CONTINUE)) { + if (_slang_loop_contains_continue(slang_oper_child(oper, 3))) { return _slang_gen_for_without_continue(A, oper); } } -- cgit v1.2.3 From 38ddbc5588a9922854e9191cda42d37cb01e70aa Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Tue, 23 Jun 2009 10:57:59 -0600 Subject: glsl: use _slang_loop_contains_continue_or_break() to check for unrolling The previous test failed for nested loops. --- src/mesa/shader/slang/slang_codegen.c | 41 ++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index 64dfdaff7e..55f7c0e8fc 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -2367,7 +2367,41 @@ _slang_loop_contains_continue(const slang_operation *oper) { GLuint i; for (i = 0; i < oper->num_children; i++) { - if (_slang_loop_contains_continue(slang_oper_child((slang_operation *) oper, i))) + slang_operation *child = + slang_oper_child((slang_operation *) oper, i); + if (_slang_loop_contains_continue(child)) + return GL_TRUE; + } + } + return GL_FALSE; + } +} + + +/** + * Check if a loop contains a 'continue' or 'break' statement. + * Stop looking if we find a nested loop. + */ +static GLboolean +_slang_loop_contains_continue_or_break(const slang_operation *oper) +{ + switch (oper->type) { + case SLANG_OPER_CONTINUE: + case SLANG_OPER_BREAK: + return GL_TRUE; + case SLANG_OPER_FOR: + case SLANG_OPER_DO: + case SLANG_OPER_WHILE: + /* stop upon finding a nested loop */ + return GL_FALSE; + default: + /* recurse */ + { + GLuint i; + for (i = 0; i < oper->num_children; i++) { + slang_operation *child = + slang_oper_child((slang_operation *) oper, i); + if (_slang_loop_contains_continue_or_break(child)) return GL_TRUE; } } @@ -2799,11 +2833,8 @@ _slang_can_unroll_for_loop(slang_assemble_ctx * A, const slang_operation *oper) assert(oper->num_children == 4); - if (_slang_find_node_type((slang_operation *) oper, SLANG_OPER_CONTINUE) || - _slang_find_node_type((slang_operation *) oper, SLANG_OPER_BREAK)) { - /* dont't unroll loops containing continue/break statements */ + if (_slang_loop_contains_continue_or_break(oper)) return GL_FALSE; - } /* children[0] must be either "int i=constant" or "i=constant" */ if (oper->children[0].type == SLANG_OPER_BLOCK_NO_NEW_SCOPE) { -- cgit v1.2.3 From 541594b04432710b5dba74277443420c9aa97e04 Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Tue, 23 Jun 2009 12:46:11 -0600 Subject: glsl: added slang_oper_child_const() --- src/mesa/shader/slang/slang_compile_operation.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_compile_operation.h b/src/mesa/shader/slang/slang_compile_operation.h index f07aa1c02e..b701d9a957 100644 --- a/src/mesa/shader/slang/slang_compile_operation.h +++ b/src/mesa/shader/slang/slang_compile_operation.h @@ -172,6 +172,14 @@ slang_oper_child(slang_operation *oper, GLuint child) } +static INLINE const slang_operation * +slang_oper_child_const(const slang_operation *oper, GLuint child) +{ + assert(child < oper->num_children); + return &oper->children[child]; +} + + /** Init oper to a boolean literal. */ static INLINE void slang_operation_literal_bool(slang_operation *oper, GLboolean value) -- cgit v1.2.3 From 2102e301a7f218c26878deaed2d94c15cd53f292 Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Tue, 23 Jun 2009 13:33:28 -0600 Subject: glsl: fix a bug involving 'continue' in 'for' loops Need to execute the for loop's increment code before we continue. Add a slang_assemble_ctx::CurLoopOper field to keep track of the containing loop and avoid the "cont if true" path in this situation. Plus, assorted clean-ups. --- src/mesa/shader/slang/slang_codegen.c | 66 +++++++++++++++++++++++------------ src/mesa/shader/slang/slang_codegen.h | 1 + 2 files changed, 44 insertions(+), 23 deletions(-) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index 55f7c0e8fc..787bdb59c7 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -647,7 +647,7 @@ new_break(slang_ir_node *loopNode) assert(loopNode); assert(loopNode->Opcode == IR_LOOP); if (n) { - /* insert this node at head of linked list */ + /* insert this node at head of linked list of cont/break instructions */ n->List = loopNode->List; loopNode->List = n; } @@ -659,14 +659,15 @@ new_break(slang_ir_node *loopNode) * Make new IR_BREAK_IF_TRUE. */ static slang_ir_node * -new_break_if_true(slang_ir_node *loopNode, slang_ir_node *cond) +new_break_if_true(slang_assemble_ctx *A, slang_ir_node *cond) { + slang_ir_node *loopNode = A->CurLoop; slang_ir_node *n; assert(loopNode); assert(loopNode->Opcode == IR_LOOP); n = new_node1(IR_BREAK_IF_TRUE, cond); if (n) { - /* insert this node at head of linked list */ + /* insert this node at head of linked list of cont/break instructions */ n->List = loopNode->List; loopNode->List = n; } @@ -678,14 +679,16 @@ new_break_if_true(slang_ir_node *loopNode, slang_ir_node *cond) * Make new IR_CONT_IF_TRUE node. */ static slang_ir_node * -new_cont_if_true(slang_ir_node *loopNode, slang_ir_node *cond) +new_cont_if_true(slang_assemble_ctx *A, slang_ir_node *cond) { + slang_ir_node *loopNode = A->CurLoop; slang_ir_node *n; assert(loopNode); assert(loopNode->Opcode == IR_LOOP); n = new_node1(IR_CONT_IF_TRUE, cond); if (n) { - /* insert this node at head of linked list */ + n->Parent = loopNode; /* pointer to containing loop */ + /* insert this node at head of linked list of cont/break instructions */ n->List = loopNode->List; loopNode->List = n; } @@ -2367,8 +2370,7 @@ _slang_loop_contains_continue(const slang_operation *oper) { GLuint i; for (i = 0; i < oper->num_children; i++) { - slang_operation *child = - slang_oper_child((slang_operation *) oper, i); + const slang_operation *child = slang_oper_child_const(oper, i); if (_slang_loop_contains_continue(child)) return GL_TRUE; } @@ -2399,8 +2401,7 @@ _slang_loop_contains_continue_or_break(const slang_operation *oper) { GLuint i; for (i = 0; i < oper->num_children; i++) { - slang_operation *child = - slang_oper_child((slang_operation *) oper, i); + const slang_operation *child = slang_oper_child_const(oper, i); if (_slang_loop_contains_continue_or_break(child)) return GL_TRUE; } @@ -2504,6 +2505,7 @@ _slang_gen_while(slang_assemble_ctx * A, slang_operation *oper) * BREAK if !expr (child[0]) * body code (child[1]) */ + const slang_operation *prevLoopOper; slang_ir_node *prevLoop, *loop, *breakIf, *body; GLboolean isConst, constTrue; @@ -2535,6 +2537,8 @@ _slang_gen_while(slang_assemble_ctx * A, slang_operation *oper) /* save old, push new loop */ prevLoop = A->CurLoop; A->CurLoop = loop; + prevLoopOper = A->CurLoopOper; + A->CurLoopOper = oper; if (isConst && constTrue) { /* while(nonzero constant), no conditional break */ @@ -2543,7 +2547,7 @@ _slang_gen_while(slang_assemble_ctx * A, slang_operation *oper) else { slang_ir_node *cond = new_cond(new_not(_slang_gen_operation(A, &oper->children[0]))); - breakIf = new_break_if_true(A->CurLoop, cond); + breakIf = new_break_if_true(A, cond); } body = _slang_gen_operation(A, &oper->children[1]); loop->Children[0] = new_seq(breakIf, body); @@ -2559,6 +2563,7 @@ _slang_gen_while(slang_assemble_ctx * A, slang_operation *oper) /* pop loop, restore prev */ A->CurLoop = prevLoop; + A->CurLoopOper = prevLoopOper; return loop; } @@ -2744,6 +2749,7 @@ _slang_gen_do(slang_assemble_ctx * A, slang_operation *oper) * tail code: * BREAK if !expr (child[1]) */ + const slang_operation *prevLoopOper; slang_ir_node *prevLoop, *loop; GLboolean isConst, constTrue; @@ -2767,6 +2773,8 @@ _slang_gen_do(slang_assemble_ctx * A, slang_operation *oper) /* save old, push new loop */ prevLoop = A->CurLoop; A->CurLoop = loop; + prevLoopOper = A->CurLoopOper; + A->CurLoopOper = oper; /* loop body: */ loop->Children[0] = _slang_gen_operation(A, &oper->children[0]); @@ -2780,13 +2788,14 @@ _slang_gen_do(slang_assemble_ctx * A, slang_operation *oper) else { slang_ir_node *cond = new_cond(new_not(_slang_gen_operation(A, &oper->children[1]))); - loop->Children[1] = new_break_if_true(A->CurLoop, cond); + loop->Children[1] = new_break_if_true(A, cond); } /* XXX we should do infinite loop detection, as above */ /* pop loop, restore prev */ A->CurLoop = prevLoop; + A->CurLoopOper = prevLoopOper; return loop; } @@ -2833,7 +2842,7 @@ _slang_can_unroll_for_loop(slang_assemble_ctx * A, const slang_operation *oper) assert(oper->num_children == 4); - if (_slang_loop_contains_continue_or_break(oper)) + if (_slang_loop_contains_continue_or_break(slang_oper_child_const(oper, 3))) return GL_FALSE; /* children[0] must be either "int i=constant" or "i=constant" */ @@ -3205,6 +3214,7 @@ _slang_gen_for(slang_assemble_ctx * A, slang_operation *oper) * tail code: * incr code (child[2]) // XXX continue here */ + const slang_operation *prevLoopOper; slang_ir_node *prevLoop, *loop, *cond, *breakIf, *body, *init, *incr; init = _slang_gen_operation(A, &oper->children[0]); loop = new_loop(NULL); @@ -3212,9 +3222,11 @@ _slang_gen_for(slang_assemble_ctx * A, slang_operation *oper) /* save old, push new loop */ prevLoop = A->CurLoop; A->CurLoop = loop; + prevLoopOper = A->CurLoopOper; + A->CurLoopOper = oper; cond = new_cond(new_not(_slang_gen_operation(A, &oper->children[1]))); - breakIf = new_break_if_true(A->CurLoop, cond); + breakIf = new_break_if_true(A, cond); body = _slang_gen_operation(A, &oper->children[3]); incr = _slang_gen_operation(A, &oper->children[2]); @@ -3223,6 +3235,7 @@ _slang_gen_for(slang_assemble_ctx * A, slang_operation *oper) /* pop loop, restore prev */ A->CurLoop = prevLoop; + A->CurLoopOper = prevLoopOper; return new_seq(init, loop); } @@ -3232,18 +3245,22 @@ _slang_gen_for(slang_assemble_ctx * A, slang_operation *oper) static slang_ir_node * _slang_gen_continue(slang_assemble_ctx * A, const slang_operation *oper) { - slang_ir_node *n, *loopNode; + slang_ir_node *n, *cont, *incr = NULL, *loopNode; + assert(oper->type == SLANG_OPER_CONTINUE); loopNode = A->CurLoop; assert(loopNode); assert(loopNode->Opcode == IR_LOOP); - n = new_node0(IR_CONT); - if (n) { - n->Parent = loopNode; - /* insert this node at head of linked list */ - n->List = loopNode->List; - loopNode->List = n; + + cont = new_node0(IR_CONT); + if (cont) { + cont->Parent = loopNode; + /* insert this node at head of linked list of cont/break instructions */ + cont->List = loopNode->List; + loopNode->List = cont; } + + n = new_seq(incr, cont); return n; } @@ -3315,15 +3332,17 @@ _slang_gen_if(slang_assemble_ctx * A, const slang_operation *oper) /* Special case: generate a conditional break */ if (!A->CurLoop) /* probably trying to unroll */ return NULL; - ifBody = new_break_if_true(A->CurLoop, cond); + ifBody = new_break_if_true(A, cond); return ifBody; } else if (is_operation_type(&oper->children[1], SLANG_OPER_CONTINUE) - && !haveElseClause) { + && !haveElseClause + && A->CurLoopOper + && A->CurLoopOper->type != SLANG_OPER_FOR) { /* Special case: generate a conditional continue */ if (!A->CurLoop) /* probably trying to unroll */ return NULL; - ifBody = new_cont_if_true(A->CurLoop, cond); + ifBody = new_cont_if_true(A, cond); return ifBody; } else { @@ -5093,6 +5112,7 @@ _slang_codegen_function(slang_assemble_ctx * A, slang_function * fun) assert(A->program->Varying); assert(A->vartable); A->CurLoop = NULL; + A->CurLoopOper = NULL; A->CurFunction = fun; /* fold constant expressions, etc. */ diff --git a/src/mesa/shader/slang/slang_codegen.h b/src/mesa/shader/slang/slang_codegen.h index bb736585aa..64418d527b 100644 --- a/src/mesa/shader/slang/slang_codegen.h +++ b/src/mesa/shader/slang/slang_codegen.h @@ -40,6 +40,7 @@ typedef struct slang_assemble_ctx_ slang_var_table *vartable; slang_info_log *log; struct slang_label_ *curFuncEndLabel; + const slang_operation *CurLoopOper; struct slang_ir_node_ *CurLoop; struct slang_function_ *CurFunction; GLboolean UnresolvedRefs; -- cgit v1.2.3 From 08025cd4a551569c821ccb94904b9ccbbd94b632 Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Tue, 23 Jun 2009 14:05:11 -0600 Subject: glsl: implement _slang_gen_while_without_continue() --- src/mesa/shader/slang/slang_codegen.c | 197 ++++++++++++++++++++-------------- 1 file changed, 115 insertions(+), 82 deletions(-) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index 787bdb59c7..2c43e53b19 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -2411,14 +2411,102 @@ _slang_loop_contains_continue_or_break(const slang_operation *oper) } +/** + * Replace 'break' and 'continue' statements inside a do and while loops. + * This is a recursive helper function used by + * _slang_gen_do/while_without_continue(). + */ +static void +replace_break_and_cont(slang_assemble_ctx *A, slang_operation *oper) +{ + switch (oper->type) { + case SLANG_OPER_BREAK: + /* replace 'break' with "_notBreakFlag = false; break" */ + { + slang_operation *block = oper; + block->type = SLANG_OPER_BLOCK_NEW_SCOPE; + slang_operation_add_children(block, 2); + { + slang_operation *assign = slang_oper_child(block, 0); + assign->type = SLANG_OPER_ASSIGN; + slang_operation_add_children(assign, 2); + { + slang_operation *lhs = slang_oper_child(assign, 0); + slang_operation_identifier(lhs, A, "_notBreakFlag"); + } + { + slang_operation *rhs = slang_oper_child(assign, 1); + slang_operation_literal_bool(rhs, GL_FALSE); + } + } + { + slang_operation *brk = slang_oper_child(block, 1); + brk->type = SLANG_OPER_BREAK; + assert(!brk->children); + } + } + break; + case SLANG_OPER_CONTINUE: + /* convert continue into a break */ + oper->type = SLANG_OPER_BREAK; + break; + case SLANG_OPER_FOR: + case SLANG_OPER_DO: + case SLANG_OPER_WHILE: + /* stop upon finding a nested loop */ + break; + default: + /* recurse */ + { + GLuint i; + for (i = 0; i < oper->num_children; i++) { + replace_break_and_cont(A, slang_oper_child(oper, i)); + } + } + } +} + + +/** + * Transform a while-loop so that continue statements are converted to breaks. + * Then do normal IR code generation. + * + * Before: + * + * while (LOOPCOND) { + * A; + * if (IFCOND) + * continue; + * B; + * break; + * C; + * } + * + * After: + * + * { + * bool _notBreakFlag = 1; + * while (_notBreakFlag && LOOPCOND) { + * do { + * A; + * if (IFCOND) { + * break; // was continue + * } + * B; + * _notBreakFlag = 0; // was + * break; // break + * C; + * } while (0) + * } + * } + */ static slang_ir_node * _slang_gen_while_without_continue(slang_assemble_ctx *A, slang_operation *oper) { -#if 0 slang_operation *top; slang_operation *innerBody; - assert(oper->type == SLANG_OPER_DO); + assert(oper->type == SLANG_OPER_WHILE); top = slang_operation_new(1); top->type = SLANG_OPER_BLOCK_NEW_SCOPE; @@ -2440,21 +2528,36 @@ _slang_gen_while_without_continue(slang_assemble_ctx *A, slang_operation *oper) slang_operation_literal_bool(var->initializer, GL_TRUE); } - /* build outer do-loop: do { ... } while (_notBreakFlag && LOOPCOND) */ + /* build outer while-loop: while (_notBreakFlag && LOOPCOND) { ... } */ { - slang_operation *outerDo = slang_oper_child(top, 1); - outerDo->type = SLANG_OPER_DO; - slang_operation_add_children(outerDo, 2); + slang_operation *outerWhile = slang_oper_child(top, 1); + outerWhile->type = SLANG_OPER_WHILE; + slang_operation_add_children(outerWhile, 2); - /* inner do-loop */ + /* _notBreakFlag && LOOPCOND */ { - slang_operation *innerDo = slang_oper_child(outerDo, 0); + slang_operation *cond = slang_oper_child(outerWhile, 0); + cond->type = SLANG_OPER_LOGICALAND; + slang_operation_add_children(cond, 2); + { + slang_operation *notBreak = slang_oper_child(cond, 0); + slang_operation_identifier(notBreak, A, "_notBreakFlag"); + } + { + slang_operation *origCond = slang_oper_child(cond, 1); + slang_operation_copy(origCond, slang_oper_child(oper, 0)); + } + } + + /* inner loop */ + { + slang_operation *innerDo = slang_oper_child(outerWhile, 1); innerDo->type = SLANG_OPER_DO; slang_operation_add_children(innerDo, 2); /* copy original do-loop body into inner do-loop's body */ innerBody = slang_oper_child(innerDo, 0); - slang_operation_copy(innerBody, slang_oper_child(oper, 0)); + slang_operation_copy(innerBody, slang_oper_child(oper, 1)); innerBody->locals->outer_scope = innerDo->locals; /* inner do-loop's condition is constant/false */ @@ -2463,21 +2566,6 @@ _slang_gen_while_without_continue(slang_assemble_ctx *A, slang_operation *oper) slang_operation_literal_bool(constFalse, GL_FALSE); } } - - /* _notBreakFlag && LOOPCOND */ - { - slang_operation *cond = slang_oper_child(outerDo, 1); - cond->type = SLANG_OPER_LOGICALAND; - slang_operation_add_children(cond, 2); - { - slang_operation *notBreak = slang_oper_child(cond, 0); - slang_operation_identifier(notBreak, A, "_notBreakFlag"); - } - { - slang_operation *origCond = slang_oper_child(cond, 1); - slang_operation_copy(origCond, slang_oper_child(oper, 1)); - } - } } /* Finally, in innerBody, @@ -2486,10 +2574,10 @@ _slang_gen_while_without_continue(slang_assemble_ctx *A, slang_operation *oper) */ replace_break_and_cont(A, innerBody); - slang_print_tree(top, 0); + /*slang_print_tree(top, 0);*/ return _slang_gen_operation(A, top); -#endif + return NULL; } @@ -2569,61 +2657,6 @@ _slang_gen_while(slang_assemble_ctx * A, slang_operation *oper) } -/** - * Replace 'break' and 'continue' statements inside a do-while loop. - * This is a recursive helper function used by _slang_gen_do_without_continue(). - */ -static void -replace_break_and_cont(slang_assemble_ctx *A, slang_operation *oper) -{ - switch (oper->type) { - case SLANG_OPER_BREAK: - /* replace 'break' with "_notBreakFlag = false; break" */ - { - slang_operation *block = oper; - block->type = SLANG_OPER_BLOCK_NEW_SCOPE; - slang_operation_add_children(block, 2); - { - slang_operation *assign = slang_oper_child(block, 0); - assign->type = SLANG_OPER_ASSIGN; - slang_operation_add_children(assign, 2); - { - slang_operation *lhs = slang_oper_child(assign, 0); - slang_operation_identifier(lhs, A, "_notBreakFlag"); - } - { - slang_operation *rhs = slang_oper_child(assign, 1); - slang_operation_literal_bool(rhs, GL_FALSE); - } - } - { - slang_operation *brk = slang_oper_child(block, 1); - brk->type = SLANG_OPER_BREAK; - assert(!brk->children); - } - } - break; - case SLANG_OPER_CONTINUE: - /* convert continue into a break */ - oper->type = SLANG_OPER_BREAK; - break; - case SLANG_OPER_FOR: - case SLANG_OPER_DO: - case SLANG_OPER_WHILE: - /* stop upon finding a nested loop */ - break; - default: - /* recurse */ - { - GLuint i; - for (i = 0; i < oper->num_children; i++) { - replace_break_and_cont(A, slang_oper_child(oper, i)); - } - } - } -} - - /** * Transform a do-while-loop so that continue statements are converted to breaks. * Then do normal IR code generation. @@ -2731,7 +2764,7 @@ _slang_gen_do_without_continue(slang_assemble_ctx *A, slang_operation *oper) */ replace_break_and_cont(A, innerBody); - slang_print_tree(top, 0); + /*slang_print_tree(top, 0);*/ return _slang_gen_operation(A, top); } -- cgit v1.2.3 From 454a717d94f51504664b6b2e6463dd14ef2c4f7c Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Tue, 23 Jun 2009 16:17:06 -0600 Subject: glsl: remove obsolete comment --- src/mesa/shader/slang/slang_codegen.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index 2c43e53b19..7ab2135c85 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -1410,9 +1410,6 @@ _slang_gen_function_call(slang_assemble_ctx *A, slang_function *fun, * implement 'return' with RET (and CAL). * Nevertheless, we performed "inlining" to make a new instance * of the function body to deal with static register allocation. - * - * XXX check if there's one 'return' and if it's the very last - * statement in the function - we can optimize that case. */ assert(inlined->type == SLANG_OPER_BLOCK_NEW_SCOPE || inlined->type == SLANG_OPER_SEQUENCE); -- cgit v1.2.3 From f4b1a69b7d53d88e12d9baac419b48bbf8e32989 Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Tue, 23 Jun 2009 16:55:10 -0600 Subject: glsl: use slang_generate_declaration() to consolidate some code --- src/mesa/shader/slang/slang_codegen.c | 68 +++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 31 deletions(-) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index 7ab2135c85..d594650c5b 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -836,6 +836,37 @@ _slang_is_tail_return(const slang_operation *oper) } +/** + * Generate a variable declaration opeartion. + * I.e.: generate AST code for "bool flag = false;" + */ +static void +slang_generate_declaration(slang_assemble_ctx *A, + slang_variable_scope *scope, + slang_operation *decl, + slang_type_specifier_type type, + const char *name, + GLint initValue) +{ + slang_variable *var; + + assert(type == SLANG_SPEC_BOOL || + type == SLANG_SPEC_INT); + + decl->type = SLANG_OPER_VARIABLE_DECL; + + var = slang_variable_scope_grow(scope); + + slang_fully_specified_type_construct(&var->type); + + var->type.specifier.type = type; + var->a_name = slang_atom_pool_atom(A->atoms, name); + decl->a_id = var->a_name; + var->initializer = slang_operation_new(1); + slang_operation_literal_bool(var->initializer, initValue); +} + + static void slang_resolve_variable(slang_operation *oper) { @@ -2513,16 +2544,8 @@ _slang_gen_while_without_continue(slang_assemble_ctx *A, slang_operation *oper) /* declare: bool _notBreakFlag = true */ { slang_operation *condDecl = slang_oper_child(top, 0); - slang_variable *var; - - condDecl->type = SLANG_OPER_VARIABLE_DECL; - var = slang_variable_scope_grow(top->locals); - slang_fully_specified_type_construct(&var->type); - var->type.specifier.type = SLANG_SPEC_BOOL; - var->a_name = slang_atom_pool_atom(A->atoms, "_notBreakFlag"); - condDecl->a_id = var->a_name; - var->initializer = slang_operation_new(1); - slang_operation_literal_bool(var->initializer, GL_TRUE); + slang_generate_declaration(A, top->locals, condDecl, + SLANG_SPEC_BOOL, "_notBreakFlag", GL_TRUE); } /* build outer while-loop: while (_notBreakFlag && LOOPCOND) { ... } */ @@ -2703,16 +2726,8 @@ _slang_gen_do_without_continue(slang_assemble_ctx *A, slang_operation *oper) /* declare: bool _notBreakFlag = true */ { slang_operation *condDecl = slang_oper_child(top, 0); - slang_variable *var; - - condDecl->type = SLANG_OPER_VARIABLE_DECL; - var = slang_variable_scope_grow(top->locals); - slang_fully_specified_type_construct(&var->type); - var->type.specifier.type = SLANG_SPEC_BOOL; - var->a_name = slang_atom_pool_atom(A->atoms, "_notBreakFlag"); - condDecl->a_id = var->a_name; - var->initializer = slang_operation_new(1); - slang_operation_literal_bool(var->initializer, GL_TRUE); + slang_generate_declaration(A, top->locals, condDecl, + SLANG_SPEC_BOOL, "_notBreakFlag", GL_TRUE); } /* build outer do-loop: do { ... } while (_notBreakFlag && LOOPCOND) */ @@ -3124,17 +3139,8 @@ _slang_gen_for_without_continue(slang_assemble_ctx *A, slang_operation *oper) /* declare: bool _condFlag = true */ { slang_operation *condDecl; - slang_variable *var; - - condDecl = slang_oper_child(top, 0); - condDecl->type = SLANG_OPER_VARIABLE_DECL; - var = slang_variable_scope_grow(top->locals); - slang_fully_specified_type_construct(&var->type); - var->type.specifier.type = SLANG_SPEC_BOOL; - var->a_name = slang_atom_pool_atom(A->atoms, "_condFlag"); - condDecl->a_id = var->a_name; - var->initializer = slang_operation_new(1); - slang_operation_literal_bool(var->initializer, GL_TRUE); + slang_generate_declaration(A, top->locals, condDecl, + SLANG_SPEC_BOOL, "_condFlag", GL_TRUE); } /* build outer loop: for (INIT; _condFlag; ) { */ -- cgit v1.2.3 From fc0896b50b8458a503eac8945dbb1f3e29b08990 Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Tue, 23 Jun 2009 17:07:12 -0600 Subject: glsl: added slang_operation_insert_child() --- src/mesa/shader/slang/slang_compile_operation.c | 20 ++++++++++++++++++++ src/mesa/shader/slang/slang_compile_operation.h | 3 +++ 2 files changed, 23 insertions(+) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_compile_operation.c b/src/mesa/shader/slang/slang_compile_operation.c index 730cc06912..b75fd073af 100644 --- a/src/mesa/shader/slang/slang_compile_operation.c +++ b/src/mesa/shader/slang/slang_compile_operation.c @@ -265,6 +265,26 @@ slang_operation_insert(GLuint *numElements, slang_operation **array, } +/** + * Add/insert new child into given node at given position. + * \return pointer to the new child node + */ +slang_operation * +slang_operation_insert_child(slang_operation *oper, GLuint pos) +{ + slang_operation *newOp; + + newOp = slang_operation_insert(&oper->num_children, + &oper->children, + pos); + if (newOp) { + newOp->locals->outer_scope = oper->locals; + } + + return newOp; +} + + void _slang_operation_swap(slang_operation *oper0, slang_operation *oper1) { diff --git a/src/mesa/shader/slang/slang_compile_operation.h b/src/mesa/shader/slang/slang_compile_operation.h index b701d9a957..c69078b007 100644 --- a/src/mesa/shader/slang/slang_compile_operation.h +++ b/src/mesa/shader/slang/slang_compile_operation.h @@ -157,6 +157,9 @@ extern slang_operation * slang_operation_insert(GLuint *numChildren, slang_operation **children, GLuint pos); +extern slang_operation * +slang_operation_insert_child(slang_operation *oper, GLuint pos); + extern void _slang_operation_swap(slang_operation *oper0, slang_operation *oper1); -- cgit v1.2.3 From 3c6480ea42298ae46413ebfacca13100cfefaed2 Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Wed, 24 Jun 2009 08:40:56 -0600 Subject: glsl: check-point: declare _returnFlag --- src/mesa/shader/slang/slang_codegen.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index d594650c5b..3b58ee4cbd 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -1391,6 +1391,27 @@ slang_inline_function_call(slang_assemble_ctx * A, slang_function *fun, } +/** + * Insert declaration for "bool _returnFlag" in given block operation. + * This is used when we can't emit "early" return statements in subroutines. + */ +static void +declare_return_flag(slang_assemble_ctx *A, slang_operation *oper) +{ + slang_operation *decl; + + assert(oper->type == SLANG_OPER_BLOCK_NEW_SCOPE || + oper->type == SLANG_OPER_SEQUENCE); + + decl = slang_operation_insert_child(oper, 1); + + slang_generate_declaration(A, oper->locals, decl, + SLANG_SPEC_BOOL, "_returnFlag", GL_FALSE); + + slang_print_tree(oper, 0); +} + + static slang_ir_node * _slang_gen_function_call(slang_assemble_ctx *A, slang_function *fun, slang_operation *oper, slang_operation *dest) @@ -1453,6 +1474,18 @@ _slang_gen_function_call(slang_assemble_ctx *A, slang_function *fun, else { callOper = inlined; } + + if (!A->EmitContReturn) { + /* Early returns not supported. Create a _returnFlag variable + * that's set upon 'return' and tested elsewhere to no-op any + * remaining instructions in the subroutine. + */ + assert(callOper->type == SLANG_OPER_BLOCK_NEW_SCOPE || + callOper->type == SLANG_OPER_SEQUENCE); + declare_return_flag(A, callOper); + printf("DECLARE _returnFlag\n"); + + } callOper->type = SLANG_OPER_NON_INLINED_CALL; callOper->fun = fun; callOper->label = _slang_label_new_unique((char*) fun->header.a_name); -- cgit v1.2.3 From e5b53c071bf664931f7553e2a9f5ccd96b2c09cb Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Wed, 24 Jun 2009 13:16:49 -0600 Subject: glsl: added slang_oper_num_children() helper --- src/mesa/shader/slang/slang_compile_operation.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_compile_operation.h b/src/mesa/shader/slang/slang_compile_operation.h index c69078b007..06b452d3d9 100644 --- a/src/mesa/shader/slang/slang_compile_operation.h +++ b/src/mesa/shader/slang/slang_compile_operation.h @@ -167,6 +167,13 @@ _slang_operation_swap(slang_operation *oper0, slang_operation *oper1); extern void slang_operation_add_children(slang_operation *oper, GLuint num_children); + +static INLINE GLuint +slang_oper_num_children(const slang_operation *oper) +{ + return oper->num_children; +} + static INLINE slang_operation * slang_oper_child(slang_operation *oper, GLuint child) { -- cgit v1.2.3 From 5951ab311db1e716cada3ada87187e50d4434ee4 Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Wed, 24 Jun 2009 16:04:33 -0600 Subject: glsl: added slang_operation_free_children() --- src/mesa/shader/slang/slang_compile_operation.c | 14 ++++++++++++++ src/mesa/shader/slang/slang_compile_operation.h | 3 +++ 2 files changed, 17 insertions(+) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_compile_operation.c b/src/mesa/shader/slang/slang_compile_operation.c index b75fd073af..48586c2d96 100644 --- a/src/mesa/shader/slang/slang_compile_operation.c +++ b/src/mesa/shader/slang/slang_compile_operation.c @@ -200,6 +200,20 @@ slang_operation_delete(slang_operation *oper) } +void +slang_operation_free_children(slang_operation *oper) +{ + GLuint i; + for (i = 0; i < slang_oper_num_children(oper); i++) { + slang_operation *child = slang_oper_child(oper, i); + slang_operation_destruct(child); + } + _slang_free(oper->children); + oper->children = NULL; + oper->num_children = 0; +} + + slang_operation * slang_operation_grow(GLuint *numChildren, slang_operation **children) { diff --git a/src/mesa/shader/slang/slang_compile_operation.h b/src/mesa/shader/slang/slang_compile_operation.h index 06b452d3d9..d75965c235 100644 --- a/src/mesa/shader/slang/slang_compile_operation.h +++ b/src/mesa/shader/slang/slang_compile_operation.h @@ -150,6 +150,9 @@ slang_operation_new(GLuint count); extern void slang_operation_delete(slang_operation *oper); +extern void +slang_operation_free_children(slang_operation *oper); + extern slang_operation * slang_operation_grow(GLuint *numChildren, slang_operation **children); -- cgit v1.2.3 From 09313043e7d5b91465846c9064b95871f9f03cc3 Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Wed, 24 Jun 2009 16:12:20 -0600 Subject: glsl: fix uninitialized var in _slang_gen_for_without_continue() --- src/mesa/shader/slang/slang_codegen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index 3b58ee4cbd..4623b6b5bc 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -3171,7 +3171,7 @@ _slang_gen_for_without_continue(slang_assemble_ctx *A, slang_operation *oper) /* declare: bool _condFlag = true */ { - slang_operation *condDecl; + slang_operation *condDecl = slang_oper_child(top, 0); slang_generate_declaration(A, top->locals, condDecl, SLANG_SPEC_BOOL, "_condFlag", GL_TRUE); } -- cgit v1.2.3 From 515513b40925ebd94502cf0511a414d8d4f52078 Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Wed, 24 Jun 2009 16:25:00 -0600 Subject: glsl: fix up scoping for parent/children in slang_operation_copy() This will need more testing, but no regressions seen so far. --- src/mesa/shader/slang/slang_compile_operation.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_compile_operation.c b/src/mesa/shader/slang/slang_compile_operation.c index 48586c2d96..3e2bdbc91f 100644 --- a/src/mesa/shader/slang/slang_compile_operation.c +++ b/src/mesa/shader/slang/slang_compile_operation.c @@ -154,6 +154,15 @@ slang_operation_copy(slang_operation * x, const slang_operation * y) return GL_FALSE; } } + + /* update scoping for children */ + for (i = 0; i < y->num_children; i++) { + if (y->children[i].locals && + y->children[i].locals->outer_scope == y->locals) { + z.children[i].locals->outer_scope = z.locals; + } + } + #if 0 z.var = y->var; z.fun = y->fun; -- cgit v1.2.3 From b04605d544c0d423aa8482e3c29c9daded60b266 Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Wed, 24 Jun 2009 16:28:32 -0600 Subject: glsl: checkpoint: replace 'return' with __returnFlag=true; Needed for "remove early returns" transformation. --- src/mesa/shader/slang/slang_codegen.c | 75 +++++++++++++++++++++++++++++++---- 1 file changed, 68 insertions(+), 7 deletions(-) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index 4623b6b5bc..7b2c8b84f7 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -980,6 +980,8 @@ slang_substitute(slang_assemble_ctx *A, slang_operation *oper, &oper->children[0]); returnOper->type = SLANG_OPER_RETURN; /* return w/ no value */ + returnOper->locals->outer_scope = blockOper->locals; + assert(returnOper->num_children == 0); /* do substitutions on the "__retVal = expr" sub-tree */ @@ -1392,7 +1394,7 @@ slang_inline_function_call(slang_assemble_ctx * A, slang_function *fun, /** - * Insert declaration for "bool _returnFlag" in given block operation. + * Insert declaration for "bool __returnFlag" in given block operation. * This is used when we can't emit "early" return statements in subroutines. */ static void @@ -1406,12 +1408,45 @@ declare_return_flag(slang_assemble_ctx *A, slang_operation *oper) decl = slang_operation_insert_child(oper, 1); slang_generate_declaration(A, oper->locals, decl, - SLANG_SPEC_BOOL, "_returnFlag", GL_FALSE); + SLANG_SPEC_BOOL, "__returnFlag", GL_FALSE); slang_print_tree(oper, 0); } +/** + * Replace 'return' with '__returnFlag = true'. + * This is used to remove 'early returns' from functions. + */ +static void +replace_return_with_flag_set(slang_assemble_ctx *A, slang_operation *oper) +{ + slang_atom id = slang_atom_pool_atom(A->atoms, "__returnFlag"); + assert(oper->type == SLANG_OPER_RETURN); + + /* replace 'return' with __returnFlag = true' */ + slang_operation_free_children(oper); + oper->type = SLANG_OPER_ASSIGN; + slang_operation_add_children(oper, 2); + { + slang_operation *lhs = slang_oper_child(oper, 0); + lhs->type = SLANG_OPER_IDENTIFIER; + lhs->a_id = id; + } + { + slang_operation *rhs = slang_oper_child(oper, 1); + slang_operation_literal_bool(rhs, GL_TRUE); + } + + { + slang_variable *var; + var = _slang_variable_locate(oper->locals, id, GL_TRUE); + assert(var); + } + +} + + static slang_ir_node * _slang_gen_function_call(slang_assemble_ctx *A, slang_function *fun, slang_operation *oper, slang_operation *dest) @@ -1483,8 +1518,6 @@ _slang_gen_function_call(slang_assemble_ctx *A, slang_function *fun, assert(callOper->type == SLANG_OPER_BLOCK_NEW_SCOPE || callOper->type == SLANG_OPER_SEQUENCE); declare_return_flag(A, callOper); - printf("DECLARE _returnFlag\n"); - } callOper->type = SLANG_OPER_NON_INLINED_CALL; callOper->fun = fun; @@ -3871,6 +3904,8 @@ _slang_gen_return(slang_assemble_ctx * A, slang_operation *oper) const GLboolean haveReturnValue = (oper->num_children == 1 && oper->children[0].type != SLANG_OPER_VOID); + assert(oper->type == SLANG_OPER_RETURN); + /* error checking */ assert(A->CurFunction); if (haveReturnValue && @@ -3885,7 +3920,13 @@ _slang_gen_return(slang_assemble_ctx * A, slang_operation *oper) } if (!haveReturnValue) { - return new_return(A->curFuncEndLabel); + if (A->EmitContReturn) { + return new_return(A->curFuncEndLabel); + } + else { + replace_return_with_flag_set(A, oper); + return _slang_gen_operation(A, oper); + } } else { /* @@ -3926,8 +3967,28 @@ _slang_gen_return(slang_assemble_ctx * A, slang_operation *oper) slang_operation_copy(&assign->children[1], &oper->children[0]); /* assemble the new code */ - n = new_seq(_slang_gen_operation(A, assign), - new_return(A->curFuncEndLabel)); + if (A->EmitContReturn) { + n = new_seq(_slang_gen_operation(A, assign), + new_return(A->curFuncEndLabel)); + } + else { + slang_operation *setFlag = slang_operation_new(1); + setFlag->type = SLANG_OPER_ASSIGN; + setFlag->locals->outer_scope = oper->locals; + slang_operation_add_children(setFlag, 2); + { + slang_operation *lhs = slang_oper_child(setFlag, 0); + lhs->type = SLANG_OPER_IDENTIFIER; + lhs->a_id = slang_atom_pool_atom(A->atoms, "__returnFlag"); + } + { + slang_operation *rhs = slang_oper_child(setFlag, 1); + slang_operation_literal_bool(rhs, GL_TRUE); + } + n = new_seq(_slang_gen_operation(A, assign), + _slang_gen_operation(A, setFlag)); + slang_operation_delete(setFlag); + } slang_operation_delete(assign); return n; -- cgit v1.2.3 From e139434d4477c2c8fb5f59ebf3b3b9a97238684c Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Wed, 24 Jun 2009 16:36:24 -0600 Subject: glsl: add comments --- src/mesa/shader/slang/slang_compile_operation.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_compile_operation.h b/src/mesa/shader/slang/slang_compile_operation.h index d75965c235..17c6c3e349 100644 --- a/src/mesa/shader/slang/slang_compile_operation.h +++ b/src/mesa/shader/slang/slang_compile_operation.h @@ -171,12 +171,14 @@ extern void slang_operation_add_children(slang_operation *oper, GLuint num_children); +/** Return number of children of given node */ static INLINE GLuint slang_oper_num_children(const slang_operation *oper) { return oper->num_children; } +/** Return child of given operation node */ static INLINE slang_operation * slang_oper_child(slang_operation *oper, GLuint child) { @@ -185,6 +187,7 @@ slang_oper_child(slang_operation *oper, GLuint child) } +/** Return child of given operation node, const version */ static INLINE const slang_operation * slang_oper_child_const(const slang_operation *oper, GLuint child) { -- cgit v1.2.3 From 65eaafee250bdcc8e82104e45dcc152735cf8b85 Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Wed, 24 Jun 2009 16:37:01 -0600 Subject: glsl: use new helper functions in _slang_gen_logical_and/or() --- src/mesa/shader/slang/slang_codegen.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index 7b2c8b84f7..c4550bbd9b 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -3855,14 +3855,11 @@ _slang_gen_logical_and(slang_assemble_ctx *A, slang_operation *oper) select = slang_operation_new(1); select->type = SLANG_OPER_SELECT; - select->num_children = 3; - select->children = slang_operation_new(3); + slang_operation_add_children(select, 3); - slang_operation_copy(&select->children[0], &oper->children[0]); - slang_operation_copy(&select->children[1], &oper->children[1]); - select->children[2].type = SLANG_OPER_LITERAL_BOOL; - ASSIGN_4V(select->children[2].literal, 0, 0, 0, 0); /* false */ - select->children[2].literal_size = 1; + slang_operation_copy(slang_oper_child(select, 0), &oper->children[0]); + slang_operation_copy(slang_oper_child(select, 1), &oper->children[1]); + slang_operation_literal_bool(slang_oper_child(select, 2), GL_FALSE); n = _slang_gen_select(A, select); return n; @@ -3881,14 +3878,11 @@ _slang_gen_logical_or(slang_assemble_ctx *A, slang_operation *oper) select = slang_operation_new(1); select->type = SLANG_OPER_SELECT; - select->num_children = 3; - select->children = slang_operation_new(3); - - slang_operation_copy(&select->children[0], &oper->children[0]); - select->children[1].type = SLANG_OPER_LITERAL_BOOL; - ASSIGN_4V(select->children[1].literal, 1, 1, 1, 1); /* true */ - select->children[1].literal_size = 1; - slang_operation_copy(&select->children[2], &oper->children[1]); + slang_operation_add_children(select, 3); + + slang_operation_copy(slang_oper_child(select, 0), &oper->children[0]); + slang_operation_literal_bool(slang_oper_child(select, 1), GL_TRUE); + slang_operation_copy(slang_oper_child(select, 2), &oper->children[1]); n = _slang_gen_select(A, select); return n; -- cgit v1.2.3 From 2f1c5c58b33dc616a3744cd40fcae20971309b3c Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Wed, 24 Jun 2009 17:02:34 -0600 Subject: glsl: checkpoint: predicate __retVal = expr with __returnFlag The glean "function with early return (1)" test passes now. --- src/mesa/shader/slang/slang_codegen.c | 86 ++++++++++++++++++++++++----------- 1 file changed, 60 insertions(+), 26 deletions(-) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index c4550bbd9b..f182ae6e06 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -951,7 +951,7 @@ slang_substitute(slang_assemble_ctx *A, slang_operation *oper, * return; * then do substitutions on the assignment. */ - slang_operation *blockOper, *assignOper, *returnOper; + slang_operation *blockOper; /* check if function actually has a return type */ assert(A->CurFunction); @@ -962,31 +962,64 @@ slang_substitute(slang_assemble_ctx *A, slang_operation *oper, blockOper = slang_operation_new(1); blockOper->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE; - blockOper->num_children = 2; blockOper->locals->outer_scope = oper->locals->outer_scope; - blockOper->children = slang_operation_new(2); - assignOper = blockOper->children + 0; - returnOper = blockOper->children + 1; - - assignOper->type = SLANG_OPER_ASSIGN; - assignOper->num_children = 2; - assignOper->locals->outer_scope = blockOper->locals; - assignOper->children = slang_operation_new(2); - assignOper->children[0].type = SLANG_OPER_IDENTIFIER; - assignOper->children[0].a_id = slang_atom_pool_atom(A->atoms, "__retVal"); - assignOper->children[0].locals->outer_scope = assignOper->locals; + slang_operation_add_children(blockOper, 2); + + /* if EmitContReturn: + * if (!__returnFlag) { + * build: __retVal = expr; + * } + * otherwise: + * build: __retVal = expr; + */ + { + slang_operation *assignOper; - slang_operation_copy(&assignOper->children[1], - &oper->children[0]); + if (!A->EmitContReturn) { + slang_operation *ifOper = slang_oper_child(blockOper, 0); + ifOper->type = SLANG_OPER_IF; + slang_operation_add_children(ifOper, 3); + + { + slang_operation *cond = slang_oper_child(ifOper, 0); + cond->type = SLANG_OPER_IDENTIFIER; + cond->a_id = slang_atom_pool_atom(A->atoms, "__returnFlag"); + } + { + assignOper = slang_oper_child(ifOper, 1); + } + { + slang_operation *elseOper = slang_oper_child(ifOper, 2); + elseOper->type = SLANG_OPER_VOID; + } + } + else { + assignOper = slang_oper_child(blockOper, 0); + } - returnOper->type = SLANG_OPER_RETURN; /* return w/ no value */ - returnOper->locals->outer_scope = blockOper->locals; + assignOper->type = SLANG_OPER_ASSIGN; + slang_operation_add_children(assignOper, 2); + { + slang_operation *lhs = slang_oper_child(assignOper, 0); + lhs->type = SLANG_OPER_IDENTIFIER; + lhs->a_id = slang_atom_pool_atom(A->atoms, "__retVal"); + } + { + slang_operation *rhs = slang_oper_child(assignOper, 1); + slang_operation_copy(rhs, &oper->children[0]); + } - assert(returnOper->num_children == 0); + /* do substitutions on the "__retVal = expr" sub-tree */ + slang_substitute(A, assignOper, + substCount, substOld, substNew, GL_FALSE); + } - /* do substitutions on the "__retVal = expr" sub-tree */ - slang_substitute(A, assignOper, - substCount, substOld, substNew, GL_FALSE); + /* build: return; */ + { + slang_operation *returnOper = slang_oper_child(blockOper, 1); + returnOper->type = SLANG_OPER_RETURN; /* return w/ no value */ + assert(returnOper->num_children == 0); + } /* install new code */ slang_operation_copy(oper, blockOper); @@ -1408,14 +1441,14 @@ declare_return_flag(slang_assemble_ctx *A, slang_operation *oper) decl = slang_operation_insert_child(oper, 1); slang_generate_declaration(A, oper->locals, decl, - SLANG_SPEC_BOOL, "__returnFlag", GL_FALSE); + SLANG_SPEC_BOOL, "__returnFlag", GL_TRUE); slang_print_tree(oper, 0); } /** - * Replace 'return' with '__returnFlag = true'. + * Replace 'return' with '__returnFlag = false'. * This is used to remove 'early returns' from functions. */ static void @@ -1424,7 +1457,7 @@ replace_return_with_flag_set(slang_assemble_ctx *A, slang_operation *oper) slang_atom id = slang_atom_pool_atom(A->atoms, "__returnFlag"); assert(oper->type == SLANG_OPER_RETURN); - /* replace 'return' with __returnFlag = true' */ + /* replace 'return' with __returnFlag = false' */ slang_operation_free_children(oper); oper->type = SLANG_OPER_ASSIGN; slang_operation_add_children(oper, 2); @@ -1435,7 +1468,7 @@ replace_return_with_flag_set(slang_assemble_ctx *A, slang_operation *oper) } { slang_operation *rhs = slang_oper_child(oper, 1); - slang_operation_literal_bool(rhs, GL_TRUE); + slang_operation_literal_bool(rhs, GL_FALSE); } { @@ -3966,6 +3999,7 @@ _slang_gen_return(slang_assemble_ctx * A, slang_operation *oper) new_return(A->curFuncEndLabel)); } else { + /* set __returnFlag = false; */ slang_operation *setFlag = slang_operation_new(1); setFlag->type = SLANG_OPER_ASSIGN; setFlag->locals->outer_scope = oper->locals; @@ -3977,7 +4011,7 @@ _slang_gen_return(slang_assemble_ctx * A, slang_operation *oper) } { slang_operation *rhs = slang_oper_child(setFlag, 1); - slang_operation_literal_bool(rhs, GL_TRUE); + slang_operation_literal_bool(rhs, GL_FALSE); } n = new_seq(_slang_gen_operation(A, assign), _slang_gen_operation(A, setFlag)); -- cgit v1.2.3 From dd453fa37c243a98ca2e2c76d3b396e2d294350e Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Thu, 25 Jun 2009 09:30:53 -0600 Subject: glsl: remove test for loop unrolling when we hit conditional cont/break This is no longer needed since we added the new _slang_loop_contains_continue_or_break() function/test. --- src/mesa/shader/slang/slang_codegen.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index f182ae6e06..aa8e44cf60 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -3465,8 +3465,6 @@ _slang_gen_if(slang_assemble_ctx * A, const slang_operation *oper) if (is_operation_type(&oper->children[1], SLANG_OPER_BREAK) && !haveElseClause) { /* Special case: generate a conditional break */ - if (!A->CurLoop) /* probably trying to unroll */ - return NULL; ifBody = new_break_if_true(A, cond); return ifBody; } @@ -3475,8 +3473,6 @@ _slang_gen_if(slang_assemble_ctx * A, const slang_operation *oper) && A->CurLoopOper && A->CurLoopOper->type != SLANG_OPER_FOR) { /* Special case: generate a conditional continue */ - if (!A->CurLoop) /* probably trying to unroll */ - return NULL; ifBody = new_cont_if_true(A, cond); return ifBody; } -- cgit v1.2.3 From f652f15e6dad86bfc7a027978a9b67d00202259c Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Thu, 25 Jun 2009 09:50:37 -0600 Subject: glsl: rework loop nesting code --- src/mesa/shader/slang/slang_codegen.c | 118 +++++++++++++++++++++++----------- src/mesa/shader/slang/slang_codegen.h | 10 ++- 2 files changed, 87 insertions(+), 41 deletions(-) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index aa8e44cf60..b918e03aa5 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -440,6 +440,56 @@ _slang_output_index(const char *name, GLenum target) } +/** + * Called when we begin code/IR generation for a new while/do/for loop. + */ +static void +push_loop(slang_assemble_ctx *A, slang_operation *loopOper, slang_ir_node *loopIR) +{ + A->LoopOperStack[A->LoopDepth] = loopOper; + A->LoopIRStack[A->LoopDepth] = loopIR; + A->LoopDepth++; +} + + +/** + * Called when we end code/IR generation for a new while/do/for loop. + */ +static void +pop_loop(slang_assemble_ctx *A) +{ + assert(A->LoopDepth > 0); + A->LoopDepth--; +} + + +/** + * Return pointer to slang_operation for the loop we're currently inside, + * or NULL if not in a loop. + */ +static const slang_operation * +current_loop_oper(const slang_assemble_ctx *A) +{ + if (A->LoopDepth > 0) + return A->LoopOperStack[A->LoopDepth - 1]; + else + return NULL; +} + + +/** + * Return pointer to slang_ir_node for the loop we're currently inside, + * or NULL if not in a loop. + */ +static slang_ir_node * +current_loop_ir(const slang_assemble_ctx *A) +{ + if (A->LoopDepth > 0) + return A->LoopIRStack[A->LoopDepth - 1]; + else + return NULL; +} + /**********************************************************************/ @@ -661,7 +711,7 @@ new_break(slang_ir_node *loopNode) static slang_ir_node * new_break_if_true(slang_assemble_ctx *A, slang_ir_node *cond) { - slang_ir_node *loopNode = A->CurLoop; + slang_ir_node *loopNode = current_loop_ir(A); slang_ir_node *n; assert(loopNode); assert(loopNode->Opcode == IR_LOOP); @@ -681,7 +731,7 @@ new_break_if_true(slang_assemble_ctx *A, slang_ir_node *cond) static slang_ir_node * new_cont_if_true(slang_assemble_ctx *A, slang_ir_node *cond) { - slang_ir_node *loopNode = A->CurLoop; + slang_ir_node *loopNode = current_loop_ir(A); slang_ir_node *n; assert(loopNode); assert(loopNode->Opcode == IR_LOOP); @@ -2712,8 +2762,7 @@ _slang_gen_while(slang_assemble_ctx * A, slang_operation *oper) * BREAK if !expr (child[0]) * body code (child[1]) */ - const slang_operation *prevLoopOper; - slang_ir_node *prevLoop, *loop, *breakIf, *body; + slang_ir_node *loop, *breakIf, *body; GLboolean isConst, constTrue; if (!A->EmitContReturn) { @@ -2739,13 +2788,11 @@ _slang_gen_while(slang_assemble_ctx * A, slang_operation *oper) return new_node0(IR_NOP); } + /* Begin new loop */ loop = new_loop(NULL); - /* save old, push new loop */ - prevLoop = A->CurLoop; - A->CurLoop = loop; - prevLoopOper = A->CurLoopOper; - A->CurLoopOper = oper; + /* save loop state */ + push_loop(A, oper, loop); if (isConst && constTrue) { /* while(nonzero constant), no conditional break */ @@ -2763,14 +2810,13 @@ _slang_gen_while(slang_assemble_ctx * A, slang_operation *oper) /* loop->List is head of linked list of break/continue nodes */ if (!loop->List && isConst && constTrue) { /* infinite loop detected */ - A->CurLoop = prevLoop; /* clean-up */ + pop_loop(A); slang_info_log_error(A->log, "Infinite loop detected!"); return NULL; } - /* pop loop, restore prev */ - A->CurLoop = prevLoop; - A->CurLoopOper = prevLoopOper; + /* restore loop state */ + pop_loop(A); return loop; } @@ -2893,8 +2939,7 @@ _slang_gen_do(slang_assemble_ctx * A, slang_operation *oper) * tail code: * BREAK if !expr (child[1]) */ - const slang_operation *prevLoopOper; - slang_ir_node *prevLoop, *loop; + slang_ir_node *loop; GLboolean isConst, constTrue; if (!A->EmitContReturn) { @@ -2914,11 +2959,8 @@ _slang_gen_do(slang_assemble_ctx * A, slang_operation *oper) loop = new_loop(NULL); - /* save old, push new loop */ - prevLoop = A->CurLoop; - A->CurLoop = loop; - prevLoopOper = A->CurLoopOper; - A->CurLoopOper = oper; + /* save loop state */ + push_loop(A, oper, loop); /* loop body: */ loop->Children[0] = _slang_gen_operation(A, &oper->children[0]); @@ -2937,9 +2979,8 @@ _slang_gen_do(slang_assemble_ctx * A, slang_operation *oper) /* XXX we should do infinite loop detection, as above */ - /* pop loop, restore prev */ - A->CurLoop = prevLoop; - A->CurLoopOper = prevLoopOper; + /* restore loop state */ + pop_loop(A); return loop; } @@ -3349,16 +3390,12 @@ _slang_gen_for(slang_assemble_ctx * A, slang_operation *oper) * tail code: * incr code (child[2]) // XXX continue here */ - const slang_operation *prevLoopOper; - slang_ir_node *prevLoop, *loop, *cond, *breakIf, *body, *init, *incr; + slang_ir_node *loop, *cond, *breakIf, *body, *init, *incr; init = _slang_gen_operation(A, &oper->children[0]); loop = new_loop(NULL); - /* save old, push new loop */ - prevLoop = A->CurLoop; - A->CurLoop = loop; - prevLoopOper = A->CurLoopOper; - A->CurLoopOper = oper; + /* save loop state */ + push_loop(A, oper, loop); cond = new_cond(new_not(_slang_gen_operation(A, &oper->children[1]))); breakIf = new_break_if_true(A, cond); @@ -3368,9 +3405,8 @@ _slang_gen_for(slang_assemble_ctx * A, slang_operation *oper) loop->Children[0] = new_seq(breakIf, body); loop->Children[1] = incr; /* tail code */ - /* pop loop, restore prev */ - A->CurLoop = prevLoop; - A->CurLoopOper = prevLoopOper; + /* restore loop state */ + pop_loop(A); return new_seq(init, loop); } @@ -3383,7 +3419,7 @@ _slang_gen_continue(slang_assemble_ctx * A, const slang_operation *oper) slang_ir_node *n, *cont, *incr = NULL, *loopNode; assert(oper->type == SLANG_OPER_CONTINUE); - loopNode = A->CurLoop; + loopNode = current_loop_ir(A); assert(loopNode); assert(loopNode->Opcode == IR_LOOP); @@ -3470,8 +3506,8 @@ _slang_gen_if(slang_assemble_ctx * A, const slang_operation *oper) } else if (is_operation_type(&oper->children[1], SLANG_OPER_CONTINUE) && !haveElseClause - && A->CurLoopOper - && A->CurLoopOper->type != SLANG_OPER_FOR) { + && current_loop_oper(A) + && current_loop_oper(A)->type != SLANG_OPER_FOR) { /* Special case: generate a conditional continue */ ifBody = new_cont_if_true(A, cond); return ifBody; @@ -4714,13 +4750,13 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper) case SLANG_OPER_WHILE: return _slang_gen_while(A, oper); case SLANG_OPER_BREAK: - if (!A->CurLoop) { + if (!current_loop_oper(A)) { slang_info_log_error(A->log, "'break' not in loop"); return NULL; } - return new_break(A->CurLoop); + return new_break(current_loop_ir(A)); case SLANG_OPER_CONTINUE: - if (!A->CurLoop) { + if (!current_loop_oper(A)) { slang_info_log_error(A->log, "'continue' not in loop"); return NULL; } @@ -5265,8 +5301,12 @@ _slang_codegen_function(slang_assemble_ctx * A, slang_function * fun) assert(A->program->Parameters ); assert(A->program->Varying); assert(A->vartable); +#if 0 A->CurLoop = NULL; A->CurLoopOper = NULL; +#else + A->LoopDepth = 0; +#endif A->CurFunction = fun; /* fold constant expressions, etc. */ diff --git a/src/mesa/shader/slang/slang_codegen.h b/src/mesa/shader/slang/slang_codegen.h index 64418d527b..fb4fe64ace 100644 --- a/src/mesa/shader/slang/slang_codegen.h +++ b/src/mesa/shader/slang/slang_codegen.h @@ -31,6 +31,9 @@ #include "slang_compile.h" +#define MAX_LOOP_DEPTH 30 + + typedef struct slang_assemble_ctx_ { slang_atom_pool *atoms; @@ -40,8 +43,11 @@ typedef struct slang_assemble_ctx_ slang_var_table *vartable; slang_info_log *log; struct slang_label_ *curFuncEndLabel; - const slang_operation *CurLoopOper; - struct slang_ir_node_ *CurLoop; + + const slang_operation *LoopOperStack[MAX_LOOP_DEPTH]; + struct slang_ir_node_ *LoopIRStack[MAX_LOOP_DEPTH]; + GLuint LoopDepth; + struct slang_function_ *CurFunction; GLboolean UnresolvedRefs; GLboolean EmitContReturn; -- cgit v1.2.3 From ddf64be2587024e5cc36cf623c544f7ef926755a Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Thu, 25 Jun 2009 10:20:21 -0600 Subject: glsl: comments, field reordering --- src/mesa/shader/slang/slang_codegen.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_codegen.h b/src/mesa/shader/slang/slang_codegen.h index fb4fe64ace..2b55b52121 100644 --- a/src/mesa/shader/slang/slang_codegen.h +++ b/src/mesa/shader/slang/slang_codegen.h @@ -42,13 +42,16 @@ typedef struct slang_assemble_ctx_ struct gl_sl_pragmas *pragmas; slang_var_table *vartable; slang_info_log *log; - struct slang_label_ *curFuncEndLabel; + /* current loop stack */ const slang_operation *LoopOperStack[MAX_LOOP_DEPTH]; struct slang_ir_node_ *LoopIRStack[MAX_LOOP_DEPTH]; GLuint LoopDepth; + /* current function */ struct slang_function_ *CurFunction; + struct slang_label_ *curFuncEndLabel; + GLboolean UnresolvedRefs; GLboolean EmitContReturn; } slang_assemble_ctx; -- cgit v1.2.3 From 2ae297c318faf29219ae00778d6bd115735a2f27 Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Thu, 25 Jun 2009 11:12:26 -0600 Subject: glsl: fix assorted regressions related to early-return-removal --- src/mesa/shader/slang/slang_codegen.c | 48 +++++++++++++++++++++++++---------- src/mesa/shader/slang/slang_codegen.h | 1 + 2 files changed, 35 insertions(+), 14 deletions(-) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index b918e03aa5..bb1ae03569 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -832,7 +832,7 @@ _slang_find_node_type(slang_operation *oper, slang_operation_type type) * Count the number of operations of the given time rooted at 'oper'. */ static GLuint -_slang_count_node_type(slang_operation *oper, slang_operation_type type) +_slang_count_node_type(const slang_operation *oper, slang_operation_type type) { GLuint i, count = 0; if (oper->type == type) { @@ -1025,7 +1025,7 @@ slang_substitute(slang_assemble_ctx *A, slang_operation *oper, { slang_operation *assignOper; - if (!A->EmitContReturn) { + if (A->UseReturnFlag) { slang_operation *ifOper = slang_oper_child(blockOper, 0); ifOper->type = SLANG_OPER_IF; slang_operation_add_children(ifOper, 3); @@ -1493,7 +1493,7 @@ declare_return_flag(slang_assemble_ctx *A, slang_operation *oper) slang_generate_declaration(A, oper->locals, decl, SLANG_SPEC_BOOL, "__returnFlag", GL_TRUE); - slang_print_tree(oper, 0); + /*slang_print_tree(oper, 0);*/ } @@ -1526,10 +1526,31 @@ replace_return_with_flag_set(slang_assemble_ctx *A, slang_operation *oper) var = _slang_variable_locate(oper->locals, id, GL_TRUE); assert(var); } +} + +/** + * Test if the given function body has an "early return". That is, there's + * a 'return' statement that's not the very last instruction in the body. + */ +static GLboolean +has_early_return(const slang_operation *funcBody) +{ + GLuint retCount = _slang_count_node_type(funcBody, SLANG_OPER_RETURN); + if (retCount == 0) + return GL_FALSE; + else if (retCount == 1 && _slang_is_tail_return(funcBody)) + return GL_FALSE; + else + return GL_TRUE; } +/** + * Emit IR code for a function call. This does one of two things: + * 1. Inline the function's code + * 2. Create an IR for the function's body and create a real call to it. + */ static slang_ir_node * _slang_gen_function_call(slang_assemble_ctx *A, slang_function *fun, slang_operation *oper, slang_operation *dest) @@ -1555,10 +1576,13 @@ _slang_gen_function_call(slang_assemble_ctx *A, slang_function *fun, * 1. insert the inline code * 2. Generate a call to the "inline" code as a subroutine */ - - + const GLboolean earlyReturn = has_early_return(fun->body); slang_operation *ret = NULL; + if (earlyReturn && !A->EmitContReturn) { + A->UseReturnFlag = GL_TRUE; + } + inlined = slang_inline_function_call(A, fun, oper, dest); if (!inlined) return NULL; @@ -1566,8 +1590,7 @@ _slang_gen_function_call(slang_assemble_ctx *A, slang_function *fun, ret = _slang_find_node_type(inlined, SLANG_OPER_RETURN); if (ret) { /* check if this is a "tail" return */ - if (_slang_count_node_type(inlined, SLANG_OPER_RETURN) == 1 && - _slang_is_tail_return(inlined)) { + if (!earlyReturn) { /* The only RETURN is the last stmt in the function, no-op it * and inline the function body. */ @@ -1593,7 +1616,7 @@ _slang_gen_function_call(slang_assemble_ctx *A, slang_function *fun, callOper = inlined; } - if (!A->EmitContReturn) { + if (A->UseReturnFlag) { /* Early returns not supported. Create a _returnFlag variable * that's set upon 'return' and tested elsewhere to no-op any * remaining instructions in the subroutine. @@ -4030,7 +4053,7 @@ _slang_gen_return(slang_assemble_ctx * A, slang_operation *oper) n = new_seq(_slang_gen_operation(A, assign), new_return(A->curFuncEndLabel)); } - else { + else if (A->UseReturnFlag) { /* set __returnFlag = false; */ slang_operation *setFlag = slang_operation_new(1); setFlag->type = SLANG_OPER_ASSIGN; @@ -5301,12 +5324,9 @@ _slang_codegen_function(slang_assemble_ctx * A, slang_function * fun) assert(A->program->Parameters ); assert(A->program->Varying); assert(A->vartable); -#if 0 - A->CurLoop = NULL; - A->CurLoopOper = NULL; -#else + A->LoopDepth = 0; -#endif + A->UseReturnFlag = GL_FALSE; A->CurFunction = fun; /* fold constant expressions, etc. */ diff --git a/src/mesa/shader/slang/slang_codegen.h b/src/mesa/shader/slang/slang_codegen.h index 2b55b52121..ee3be55a45 100644 --- a/src/mesa/shader/slang/slang_codegen.h +++ b/src/mesa/shader/slang/slang_codegen.h @@ -51,6 +51,7 @@ typedef struct slang_assemble_ctx_ /* current function */ struct slang_function_ *CurFunction; struct slang_label_ *curFuncEndLabel; + GLboolean UseReturnFlag; GLboolean UnresolvedRefs; GLboolean EmitContReturn; -- cgit v1.2.3 From 0efd25b502cfd84e401bd29c58baf00ea2f41e96 Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Thu, 25 Jun 2009 11:32:37 -0600 Subject: glsl: code refactoring for return statements --- src/mesa/shader/slang/slang_codegen.c | 158 +++++++++++++++++++--------------- 1 file changed, 88 insertions(+), 70 deletions(-) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index bb1ae03569..0d72f4e5dc 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -75,6 +75,11 @@ const GLuint MAX_FOR_LOOP_UNROLL_COMPLEXITY = 256; static slang_ir_node * _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper); +static void +slang_substitute(slang_assemble_ctx *A, slang_operation *oper, + GLuint substCount, slang_variable **substOld, + slang_operation **substNew, GLboolean isLHS); + /** * Retrieves type information about an operation. @@ -926,6 +931,78 @@ slang_resolve_variable(slang_operation *oper) } +/** + * Generate code for "return expr;" + * We return values from functions by assinging the returned value to + * the hidden __retVal variable which is an extra 'out' parameter we add + * to the function signature. + * This code basically converts "return expr;" into "__retVal = expr; return;" + * \return the new AST code. + */ +static slang_operation * +gen_return_expression(slang_assemble_ctx *A, slang_operation *oper) +{ + slang_operation *blockOper; + + blockOper = slang_operation_new(1); + blockOper->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE; + blockOper->locals->outer_scope = oper->locals->outer_scope; + slang_operation_add_children(blockOper, 2); + + /* if EmitContReturn: + * if (!__returnFlag) { + * build: __retVal = expr; + * } + * otherwise: + * build: __retVal = expr; + */ + { + slang_operation *assignOper; + + if (A->UseReturnFlag) { + slang_operation *ifOper = slang_oper_child(blockOper, 0); + ifOper->type = SLANG_OPER_IF; + slang_operation_add_children(ifOper, 3); + { + slang_operation *cond = slang_oper_child(ifOper, 0); + cond->type = SLANG_OPER_IDENTIFIER; + cond->a_id = slang_atom_pool_atom(A->atoms, "__returnFlag"); + } + { + slang_operation *elseOper = slang_oper_child(ifOper, 2); + elseOper->type = SLANG_OPER_VOID; + } + assignOper = slang_oper_child(ifOper, 1); + } + else { + assignOper = slang_oper_child(blockOper, 0); + } + + assignOper->type = SLANG_OPER_ASSIGN; + slang_operation_add_children(assignOper, 2); + { + slang_operation *lhs = slang_oper_child(assignOper, 0); + lhs->type = SLANG_OPER_IDENTIFIER; + lhs->a_id = slang_atom_pool_atom(A->atoms, "__retVal"); + } + { + slang_operation *rhs = slang_oper_child(assignOper, 1); + slang_operation_copy(rhs, &oper->children[0]); + } + } + + /* build: return; (with no return value) */ + { + slang_operation *returnOper = slang_oper_child(blockOper, 1); + returnOper->type = SLANG_OPER_RETURN; /* return w/ no value */ + assert(returnOper->num_children == 0); + } + + return blockOper; +} + + + /** * Replace particular variables (SLANG_OPER_IDENTIFIER) with new expressions. */ @@ -994,14 +1071,7 @@ slang_substitute(slang_assemble_ctx *A, slang_operation *oper, /* do return replacement here too */ assert(oper->num_children == 0 || oper->num_children == 1); if (oper->num_children == 1 && !_slang_is_noop(&oper->children[0])) { - /* replace: - * return expr; - * with: - * __retVal = expr; - * return; - * then do substitutions on the assignment. - */ - slang_operation *blockOper; + slang_operation *newReturn; /* check if function actually has a return type */ assert(A->CurFunction); @@ -1010,70 +1080,16 @@ slang_substitute(slang_assemble_ctx *A, slang_operation *oper, return; } - blockOper = slang_operation_new(1); - blockOper->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE; - blockOper->locals->outer_scope = oper->locals->outer_scope; - slang_operation_add_children(blockOper, 2); - - /* if EmitContReturn: - * if (!__returnFlag) { - * build: __retVal = expr; - * } - * otherwise: - * build: __retVal = expr; - */ - { - slang_operation *assignOper; + /* generate new 'return' code' */ + newReturn = gen_return_expression(A, oper); - if (A->UseReturnFlag) { - slang_operation *ifOper = slang_oper_child(blockOper, 0); - ifOper->type = SLANG_OPER_IF; - slang_operation_add_children(ifOper, 3); - - { - slang_operation *cond = slang_oper_child(ifOper, 0); - cond->type = SLANG_OPER_IDENTIFIER; - cond->a_id = slang_atom_pool_atom(A->atoms, "__returnFlag"); - } - { - assignOper = slang_oper_child(ifOper, 1); - } - { - slang_operation *elseOper = slang_oper_child(ifOper, 2); - elseOper->type = SLANG_OPER_VOID; - } - } - else { - assignOper = slang_oper_child(blockOper, 0); - } + /* do substitutions on the "__retVal = expr" sub-tree */ + slang_substitute(A, slang_oper_child(newReturn, 0), + substCount, substOld, substNew, GL_FALSE); - assignOper->type = SLANG_OPER_ASSIGN; - slang_operation_add_children(assignOper, 2); - { - slang_operation *lhs = slang_oper_child(assignOper, 0); - lhs->type = SLANG_OPER_IDENTIFIER; - lhs->a_id = slang_atom_pool_atom(A->atoms, "__retVal"); - } - { - slang_operation *rhs = slang_oper_child(assignOper, 1); - slang_operation_copy(rhs, &oper->children[0]); - } - - /* do substitutions on the "__retVal = expr" sub-tree */ - slang_substitute(A, assignOper, - substCount, substOld, substNew, GL_FALSE); - } - - /* build: return; */ - { - slang_operation *returnOper = slang_oper_child(blockOper, 1); - returnOper->type = SLANG_OPER_RETURN; /* return w/ no value */ - assert(returnOper->num_children == 0); - } - - /* install new code */ - slang_operation_copy(oper, blockOper); - slang_operation_destruct(blockOper); + /* install new 'return' code */ + slang_operation_copy(oper, newReturn); + slang_operation_destruct(newReturn); } else { /* check if return value was expected */ @@ -4036,6 +4052,8 @@ _slang_gen_return(slang_assemble_ctx * A, slang_operation *oper) } #endif + /* XXX use the gen_return_expression() function here */ + assign = slang_operation_new(1); assign->type = SLANG_OPER_ASSIGN; assign->num_children = 2; -- cgit v1.2.3 From ac05996b812657bdc04e0ec0d09bd638826f52d6 Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Thu, 25 Jun 2009 11:52:37 -0600 Subject: glsl: silence a problem warning --- src/mesa/shader/slang/slang_codegen.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index 0d72f4e5dc..0339cac31d 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -1038,7 +1038,8 @@ slang_substitute(slang_assemble_ctx *A, slang_operation *oper, GLuint i; v = _slang_variable_locate(oper->locals, id, GL_TRUE); if (!v) { - _mesa_problem(NULL, "var %s not found!\n", (char *) oper->a_id); + if (_mesa_strcmp((char *) oper->a_id, "__returnFlag")) + _mesa_problem(NULL, "var %s not found!\n", (char *) oper->a_id); return; } -- cgit v1.2.3 From 16787c513b677d850ecce9697d81814a2a48fc7f Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Thu, 25 Jun 2009 14:02:41 -0600 Subject: glsl: added slang_variable::is_global field --- src/mesa/shader/slang/slang_compile_variable.h | 1 + 1 file changed, 1 insertion(+) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_compile_variable.h b/src/mesa/shader/slang/slang_compile_variable.h index a667d91b47..b4585599f2 100644 --- a/src/mesa/shader/slang/slang_compile_variable.h +++ b/src/mesa/shader/slang/slang_compile_variable.h @@ -39,6 +39,7 @@ typedef struct slang_variable_ GLuint array_len; /**< only if type == SLANG_SPEC_ARRAy */ struct slang_operation_ *initializer; /**< Optional initializer code */ GLuint size; /**< Variable's size in bytes */ + GLboolean is_global; GLboolean isTemp; /**< a named temporary (__resultTmp) */ GLboolean declared; /**< for debug */ struct slang_ir_storage_ *store; /**< Storage for this var */ -- cgit v1.2.3 From aa48becb829932f410ef93cf1bbf02e0386ea646 Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Thu, 25 Jun 2009 14:01:43 -0600 Subject: glsl: predicate assignments according to __returnFlag Fixes glean "function with early return (3)" case (when EmitContReturn=FALSE). --- src/mesa/shader/slang/slang_codegen.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index 0339cac31d..6aa18868c0 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -1676,6 +1676,8 @@ _slang_gen_function_call(slang_assemble_ctx *A, slang_function *fun, n->Comment = _slang_strdup(s); } + A->UseReturnFlag = GL_FALSE; + return n; } @@ -4356,6 +4358,9 @@ root_swizzle(const slang_ir_storage *st) static slang_ir_node * _slang_gen_assignment(slang_assemble_ctx * A, slang_operation *oper) { + slang_operation *pred = NULL; + slang_ir_node *n = NULL; + if (oper->children[0].type == SLANG_OPER_IDENTIFIER) { /* Check that var is writeable */ slang_variable *var @@ -4376,6 +4381,17 @@ _slang_gen_assignment(slang_assemble_ctx * A, slang_operation *oper) (char *) oper->children[0].a_id); return NULL; } + + /* check if we need to predicate this assignment based on __returnFlag */ + if ((var->is_global || + var->type.qualifier == SLANG_QUAL_OUT || + var->type.qualifier == SLANG_QUAL_INOUT) && A->UseReturnFlag) { + /* create predicate, used below */ + pred = slang_operation_new(1); + pred->type = SLANG_OPER_IDENTIFIER; + pred->a_id = slang_atom_pool_atom(A->atoms, "__returnFlag"); + pred->locals->outer_scope = oper->locals->outer_scope; + } } if (oper->children[0].type == SLANG_OPER_IDENTIFIER && @@ -4387,14 +4403,12 @@ _slang_gen_assignment(slang_assemble_ctx * A, slang_operation *oper) * cases such as "v.x = f();" - would help with typical vertex * transformation. */ - slang_ir_node *n; n = _slang_gen_function_call_name(A, (const char *) oper->children[1].a_id, &oper->children[1], &oper->children[0]); - return n; } else { - slang_ir_node *n, *lhs, *rhs; + slang_ir_node *lhs, *rhs; /* lhs and rhs type checking */ if (!_slang_assignment_compatible(A, @@ -4434,12 +4448,21 @@ _slang_gen_assignment(slang_assemble_ctx * A, slang_operation *oper) rhs = _slang_gen_swizzle(rhs, newSwizzle); } n = new_node2(IR_COPY, lhs, rhs); - return n; } else { return NULL; } } + + if (n && pred) { + /* predicate the assignment code on __returnFlag */ + slang_ir_node *top, *cond; + + cond = _slang_gen_operation(A, pred); + top = new_if(cond, n, NULL); + return top; + } + return n; } @@ -5045,6 +5068,8 @@ _slang_codegen_global_variable(slang_assemble_ctx *A, slang_variable *var, const GLint totalSize = _slang_array_size(size, arrayLen); GLint texIndex = sampler_to_texture_index(var->type.specifier.type); + var->is_global = GL_TRUE; + /* check for sampler2D arrays */ if (texIndex == -1 && var->type.specifier._array) texIndex = sampler_to_texture_index(var->type.specifier._array->type); -- cgit v1.2.3 From 8e6dd8bf7991d8fc4938af692e5ce880ef139b4d Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Fri, 26 Jun 2009 11:33:05 -0600 Subject: glsl: overhaul 'return' statement handling A new node type (SLANG_OPER_RETURN_INLINED) is used to denote 'return' statements inside inlined functions which need special handling. All glean glsl1 tests pass for EmitContReturn=FALSE and TRUE. --- src/mesa/shader/slang/slang_codegen.c | 416 ++++++++++++------------ src/mesa/shader/slang/slang_compile_operation.h | 1 + src/mesa/shader/slang/slang_print.c | 10 +- 3 files changed, 212 insertions(+), 215 deletions(-) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index 6aa18868c0..28d04d396d 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -818,6 +818,7 @@ _slang_is_noop(const slang_operation *oper) /** * Recursively search tree for a node of the given type. */ +#if 0 static slang_operation * _slang_find_node_type(slang_operation *oper, slang_operation_type type) { @@ -831,6 +832,7 @@ _slang_find_node_type(slang_operation *oper, slang_operation_type type) } return NULL; } +#endif /** @@ -932,41 +934,43 @@ slang_resolve_variable(slang_operation *oper) /** - * Generate code for "return expr;" + * Rewrite AST code for "return expression;". + * * We return values from functions by assinging the returned value to * the hidden __retVal variable which is an extra 'out' parameter we add * to the function signature. * This code basically converts "return expr;" into "__retVal = expr; return;" + * * \return the new AST code. */ static slang_operation * -gen_return_expression(slang_assemble_ctx *A, slang_operation *oper) +gen_return_with_expression(slang_assemble_ctx *A, slang_operation *oper) { - slang_operation *blockOper; + slang_operation *blockOper, *assignOper; + + assert(oper->type == SLANG_OPER_RETURN); blockOper = slang_operation_new(1); blockOper->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE; blockOper->locals->outer_scope = oper->locals->outer_scope; slang_operation_add_children(blockOper, 2); - /* if EmitContReturn: - * if (!__returnFlag) { - * build: __retVal = expr; - * } - * otherwise: - * build: __retVal = expr; - */ - { - slang_operation *assignOper; - - if (A->UseReturnFlag) { + if (A->UseReturnFlag) { + /* Emit: + * { + * if (__notRetFlag) + * __retVal = expr; + * __notRetFlag = 0; + * } + */ + { slang_operation *ifOper = slang_oper_child(blockOper, 0); ifOper->type = SLANG_OPER_IF; slang_operation_add_children(ifOper, 3); { slang_operation *cond = slang_oper_child(ifOper, 0); cond->type = SLANG_OPER_IDENTIFIER; - cond->a_id = slang_atom_pool_atom(A->atoms, "__returnFlag"); + cond->a_id = slang_atom_pool_atom(A->atoms, "__notRetFlag"); } { slang_operation *elseOper = slang_oper_child(ifOper, 2); @@ -974,34 +978,103 @@ gen_return_expression(slang_assemble_ctx *A, slang_operation *oper) } assignOper = slang_oper_child(ifOper, 1); } - else { - assignOper = slang_oper_child(blockOper, 0); - } - - assignOper->type = SLANG_OPER_ASSIGN; - slang_operation_add_children(assignOper, 2); { - slang_operation *lhs = slang_oper_child(assignOper, 0); - lhs->type = SLANG_OPER_IDENTIFIER; - lhs->a_id = slang_atom_pool_atom(A->atoms, "__retVal"); + slang_operation *setOper = slang_oper_child(blockOper, 1); + setOper->type = SLANG_OPER_ASSIGN; + slang_operation_add_children(setOper, 2); + { + slang_operation *lhs = slang_oper_child(setOper, 0); + lhs->type = SLANG_OPER_IDENTIFIER; + lhs->a_id = slang_atom_pool_atom(A->atoms, "__notRetFlag"); + } + { + slang_operation *rhs = slang_oper_child(setOper, 1); + slang_operation_literal_bool(rhs, GL_FALSE); + } } + } + else { + /* Emit: + * { + * __retVal = expr; + * return_inlined; + * } + */ + assignOper = slang_oper_child(blockOper, 0); { - slang_operation *rhs = slang_oper_child(assignOper, 1); - slang_operation_copy(rhs, &oper->children[0]); + slang_operation *returnOper = slang_oper_child(blockOper, 1); + returnOper->type = SLANG_OPER_RETURN_INLINED; + assert(returnOper->num_children == 0); } } - /* build: return; (with no return value) */ + /* __retVal = expression; */ + assignOper->type = SLANG_OPER_ASSIGN; + slang_operation_add_children(assignOper, 2); + { + slang_operation *lhs = slang_oper_child(assignOper, 0); + lhs->type = SLANG_OPER_IDENTIFIER; + lhs->a_id = slang_atom_pool_atom(A->atoms, "__retVal"); + } { - slang_operation *returnOper = slang_oper_child(blockOper, 1); - returnOper->type = SLANG_OPER_RETURN; /* return w/ no value */ - assert(returnOper->num_children == 0); + slang_operation *rhs = slang_oper_child(assignOper, 1); + slang_operation_copy(rhs, &oper->children[0]); } + ///blockOper->locals->outer_scope = oper->locals->outer_scope; + + /*slang_print_tree(blockOper, 0);*/ + return blockOper; } +/** + * Rewrite AST code for "return;" (no expression). + */ +static slang_operation * +gen_return_without_expression(slang_assemble_ctx *A, slang_operation *oper) +{ + slang_operation *newRet; + + assert(oper->type == SLANG_OPER_RETURN); + + if (A->UseReturnFlag) { + /* Emit: + * __notRetFlag = 0; + */ + { + newRet = slang_operation_new(1); + newRet->locals->outer_scope = oper->locals->outer_scope; + newRet->type = SLANG_OPER_ASSIGN; + slang_operation_add_children(newRet, 2); + { + slang_operation *lhs = slang_oper_child(newRet, 0); + lhs->type = SLANG_OPER_IDENTIFIER; + lhs->a_id = slang_atom_pool_atom(A->atoms, "__notRetFlag"); + } + { + slang_operation *rhs = slang_oper_child(newRet, 1); + slang_operation_literal_bool(rhs, GL_FALSE); + } + } + } + else { + /* Emit: + * return_inlined; + */ + newRet = slang_operation_new(1); + newRet->locals->outer_scope = oper->locals->outer_scope; + newRet->type = SLANG_OPER_RETURN_INLINED; + } + + /*slang_print_tree(newRet, 0);*/ + + return newRet; +} + + + /** * Replace particular variables (SLANG_OPER_IDENTIFIER) with new expressions. @@ -1038,7 +1111,7 @@ slang_substitute(slang_assemble_ctx *A, slang_operation *oper, GLuint i; v = _slang_variable_locate(oper->locals, id, GL_TRUE); if (!v) { - if (_mesa_strcmp((char *) oper->a_id, "__returnFlag")) + if (_mesa_strcmp((char *) oper->a_id, "__notRetFlag")) _mesa_problem(NULL, "var %s not found!\n", (char *) oper->a_id); return; } @@ -1069,37 +1142,22 @@ slang_substitute(slang_assemble_ctx *A, slang_operation *oper, break; case SLANG_OPER_RETURN: - /* do return replacement here too */ - assert(oper->num_children == 0 || oper->num_children == 1); - if (oper->num_children == 1 && !_slang_is_noop(&oper->children[0])) { + { slang_operation *newReturn; - - /* check if function actually has a return type */ - assert(A->CurFunction); - if (A->CurFunction->header.type.specifier.type == SLANG_SPEC_VOID) { - slang_info_log_error(A->log, "illegal return expression"); - return; - } - /* generate new 'return' code' */ - newReturn = gen_return_expression(A, oper); + if (slang_oper_child(oper, 0)->type == SLANG_OPER_VOID) + newReturn = gen_return_without_expression(A, oper); + else + newReturn = gen_return_with_expression(A, oper); - /* do substitutions on the "__retVal = expr" sub-tree */ - slang_substitute(A, slang_oper_child(newReturn, 0), + /* do substitutions on the new 'return' code */ + slang_substitute(A, newReturn, substCount, substOld, substNew, GL_FALSE); /* install new 'return' code */ slang_operation_copy(oper, newReturn); slang_operation_destruct(newReturn); } - else { - /* check if return value was expected */ - assert(A->CurFunction); - if (A->CurFunction->header.type.specifier.type != SLANG_SPEC_VOID) { - slang_info_log_error(A->log, "return statement requires an expression"); - return; - } - } break; case SLANG_OPER_ASSIGN: @@ -1494,7 +1552,7 @@ slang_inline_function_call(slang_assemble_ctx * A, slang_function *fun, /** - * Insert declaration for "bool __returnFlag" in given block operation. + * Insert declaration for "bool __notRetFlag" in given block operation. * This is used when we can't emit "early" return statements in subroutines. */ static void @@ -1508,44 +1566,31 @@ declare_return_flag(slang_assemble_ctx *A, slang_operation *oper) decl = slang_operation_insert_child(oper, 1); slang_generate_declaration(A, oper->locals, decl, - SLANG_SPEC_BOOL, "__returnFlag", GL_TRUE); + SLANG_SPEC_BOOL, "__notRetFlag", GL_TRUE); /*slang_print_tree(oper, 0);*/ } /** - * Replace 'return' with '__returnFlag = false'. - * This is used to remove 'early returns' from functions. + * Recursively replace instances of the old node type with the new type. */ static void -replace_return_with_flag_set(slang_assemble_ctx *A, slang_operation *oper) +replace_node_type(slang_operation *oper, slang_operation_type oldType, + slang_operation_type newType) { - slang_atom id = slang_atom_pool_atom(A->atoms, "__returnFlag"); - assert(oper->type == SLANG_OPER_RETURN); + GLuint i; - /* replace 'return' with __returnFlag = false' */ - slang_operation_free_children(oper); - oper->type = SLANG_OPER_ASSIGN; - slang_operation_add_children(oper, 2); - { - slang_operation *lhs = slang_oper_child(oper, 0); - lhs->type = SLANG_OPER_IDENTIFIER; - lhs->a_id = id; - } - { - slang_operation *rhs = slang_oper_child(oper, 1); - slang_operation_literal_bool(rhs, GL_FALSE); - } + if (oper->type == oldType) + oper->type = newType; - { - slang_variable *var; - var = _slang_variable_locate(oper->locals, id, GL_TRUE); - assert(var); + for (i = 0; i < slang_oper_num_children(oper); i++) { + replace_node_type(slang_oper_child(oper, i), oldType, newType); } } + /** * Test if the given function body has an "early return". That is, there's * a 'return' statement that's not the very last instruction in the body. @@ -1573,7 +1618,7 @@ _slang_gen_function_call(slang_assemble_ctx *A, slang_function *fun, slang_operation *oper, slang_operation *dest) { slang_ir_node *n; - slang_operation *inlined; + slang_operation *instance; slang_label *prevFuncEndLabel; char name[200]; @@ -1582,9 +1627,14 @@ _slang_gen_function_call(slang_assemble_ctx *A, slang_function *fun, A->curFuncEndLabel = _slang_label_new(name); assert(A->curFuncEndLabel); + /* + * 'instance' is basically a copy of the function's body with various + * transformations. + */ + if (slang_is_asm_function(fun) && !dest) { /* assemble assembly function - tree style */ - inlined = slang_inline_asm_function(A, fun, oper); + instance = slang_inline_asm_function(A, fun, oper); } else { /* non-assembly function */ @@ -1594,73 +1644,81 @@ _slang_gen_function_call(slang_assemble_ctx *A, slang_function *fun, * 2. Generate a call to the "inline" code as a subroutine */ const GLboolean earlyReturn = has_early_return(fun->body); - slang_operation *ret = NULL; if (earlyReturn && !A->EmitContReturn) { A->UseReturnFlag = GL_TRUE; } - inlined = slang_inline_function_call(A, fun, oper, dest); - if (!inlined) + instance = slang_inline_function_call(A, fun, oper, dest); + if (!instance) return NULL; - ret = _slang_find_node_type(inlined, SLANG_OPER_RETURN); - if (ret) { - /* check if this is a "tail" return */ - if (!earlyReturn) { - /* The only RETURN is the last stmt in the function, no-op it - * and inline the function body. + if (earlyReturn) { + /* The function we're calling has one or more 'return' statements + * that prevent us from inlining the function's code. + * + * In this case, change the function's body type from + * SLANG_OPER_BLOCK_NEW_SCOPE to SLANG_OPER_NON_INLINED_CALL. + * During code emit this will result in a true subroutine call. + * + * Also, convert SLANG_OPER_RETURN_INLINED nodes to SLANG_OPER_RETURN. + */ + slang_operation *callOper; + + assert(instance->type == SLANG_OPER_BLOCK_NEW_SCOPE || + instance->type == SLANG_OPER_SEQUENCE); + + if (_slang_function_has_return_value(fun) && !dest) { + assert(instance->children[0].type == SLANG_OPER_VARIABLE_DECL); + assert(instance->children[2].type == SLANG_OPER_IDENTIFIER); + callOper = &instance->children[1]; + } + else { + callOper = instance; + } + + if (A->UseReturnFlag) { + /* Early returns not supported. Create a _returnFlag variable + * that's set upon 'return' and tested elsewhere to no-op any + * remaining instructions in the subroutine. */ - ret->type = SLANG_OPER_NONE; + assert(callOper->type == SLANG_OPER_BLOCK_NEW_SCOPE || + callOper->type == SLANG_OPER_SEQUENCE); + declare_return_flag(A, callOper); } else { - slang_operation *callOper; - /* The function we're calling has one or more 'return' statements. - * So, we can't truly inline this function because we need to - * implement 'return' with RET (and CAL). - * Nevertheless, we performed "inlining" to make a new instance - * of the function body to deal with static register allocation. + /* We can emit real 'return' statements. If we generated any + * 'inline return' statements during function instantiation, + * change them back to regular 'return' statements. */ - assert(inlined->type == SLANG_OPER_BLOCK_NEW_SCOPE || - inlined->type == SLANG_OPER_SEQUENCE); - - if (_slang_function_has_return_value(fun) && !dest) { - assert(inlined->children[0].type == SLANG_OPER_VARIABLE_DECL); - assert(inlined->children[2].type == SLANG_OPER_IDENTIFIER); - callOper = &inlined->children[1]; - } - else { - callOper = inlined; - } - - if (A->UseReturnFlag) { - /* Early returns not supported. Create a _returnFlag variable - * that's set upon 'return' and tested elsewhere to no-op any - * remaining instructions in the subroutine. - */ - assert(callOper->type == SLANG_OPER_BLOCK_NEW_SCOPE || - callOper->type == SLANG_OPER_SEQUENCE); - declare_return_flag(A, callOper); - } - callOper->type = SLANG_OPER_NON_INLINED_CALL; - callOper->fun = fun; - callOper->label = _slang_label_new_unique((char*) fun->header.a_name); + replace_node_type(instance, SLANG_OPER_RETURN_INLINED, + SLANG_OPER_RETURN); } + + callOper->type = SLANG_OPER_NON_INLINED_CALL; + callOper->fun = fun; + callOper->label = _slang_label_new_unique((char*) fun->header.a_name); + } + else { + /* If there are any 'return' statements remaining, they're at the + * very end of the function and can effectively become no-ops. + */ + replace_node_type(instance, SLANG_OPER_RETURN_INLINED, + SLANG_OPER_VOID); } } - if (!inlined) + if (!instance) return NULL; - /* Replace the function call with the inlined block (or new CALL stmt) */ + /* Replace the function call with the instance block (or new CALL stmt) */ slang_operation_destruct(oper); - *oper = *inlined; - _slang_free(inlined); + *oper = *instance; + _slang_free(instance); #if 0 - assert(inlined->locals); - printf("*** Inlined code for call to %s:\n", - (char*) fun->header.a_name); + assert(instance->locals); + printf("*** Inlined code for call to %s:\n", (char*) fun->header.a_name); slang_print_tree(oper, 10); printf("\n"); #endif @@ -4005,98 +4063,26 @@ _slang_gen_return(slang_assemble_ctx * A, slang_operation *oper) const GLboolean haveReturnValue = (oper->num_children == 1 && oper->children[0].type != SLANG_OPER_VOID); - assert(oper->type == SLANG_OPER_RETURN); + assert(oper->type == SLANG_OPER_RETURN || + oper->type == SLANG_OPER_RETURN_INLINED); /* error checking */ - assert(A->CurFunction); - if (haveReturnValue && - A->CurFunction->header.type.specifier.type == SLANG_SPEC_VOID) { - slang_info_log_error(A->log, "illegal return expression"); - return NULL; - } - else if (!haveReturnValue && - A->CurFunction->header.type.specifier.type != SLANG_SPEC_VOID) { - slang_info_log_error(A->log, "return statement requires an expression"); - return NULL; - } + if (oper->type == SLANG_OPER_RETURN) { + assert(A->CurFunction); - if (!haveReturnValue) { - if (A->EmitContReturn) { - return new_return(A->curFuncEndLabel); + if (haveReturnValue && + A->CurFunction->header.type.specifier.type == SLANG_SPEC_VOID) { + slang_info_log_error(A->log, "illegal return expression"); + return NULL; } - else { - replace_return_with_flag_set(A, oper); - return _slang_gen_operation(A, oper); + else if (!haveReturnValue && + A->CurFunction->header.type.specifier.type != SLANG_SPEC_VOID) { + slang_info_log_error(A->log, "return statement requires an expression"); + return NULL; } } - else { - /* - * Convert from: - * return expr; - * To: - * __retVal = expr; - * return; // goto __endOfFunction - */ - slang_operation *assign; - slang_atom a_retVal; - slang_ir_node *n; - - a_retVal = slang_atom_pool_atom(A->atoms, "__retVal"); - assert(a_retVal); - -#if 1 /* DEBUG */ - { - slang_variable *v = - _slang_variable_locate(oper->locals, a_retVal, GL_TRUE); - if (!v) { - /* trying to return a value in a void-valued function */ - return NULL; - } - } -#endif - - /* XXX use the gen_return_expression() function here */ - - assign = slang_operation_new(1); - assign->type = SLANG_OPER_ASSIGN; - assign->num_children = 2; - assign->children = slang_operation_new(2); - /* lhs (__retVal) */ - assign->children[0].type = SLANG_OPER_IDENTIFIER; - assign->children[0].a_id = a_retVal; - assign->children[0].locals->outer_scope = assign->locals; - /* rhs (expr) */ - /* XXX we might be able to avoid this copy someday */ - slang_operation_copy(&assign->children[1], &oper->children[0]); - - /* assemble the new code */ - if (A->EmitContReturn) { - n = new_seq(_slang_gen_operation(A, assign), - new_return(A->curFuncEndLabel)); - } - else if (A->UseReturnFlag) { - /* set __returnFlag = false; */ - slang_operation *setFlag = slang_operation_new(1); - setFlag->type = SLANG_OPER_ASSIGN; - setFlag->locals->outer_scope = oper->locals; - slang_operation_add_children(setFlag, 2); - { - slang_operation *lhs = slang_oper_child(setFlag, 0); - lhs->type = SLANG_OPER_IDENTIFIER; - lhs->a_id = slang_atom_pool_atom(A->atoms, "__returnFlag"); - } - { - slang_operation *rhs = slang_oper_child(setFlag, 1); - slang_operation_literal_bool(rhs, GL_FALSE); - } - n = new_seq(_slang_gen_operation(A, assign), - _slang_gen_operation(A, setFlag)); - slang_operation_delete(setFlag); - } - slang_operation_delete(assign); - return n; - } + return new_return(A->curFuncEndLabel); } @@ -4382,14 +4368,14 @@ _slang_gen_assignment(slang_assemble_ctx * A, slang_operation *oper) return NULL; } - /* check if we need to predicate this assignment based on __returnFlag */ + /* check if we need to predicate this assignment based on __notRetFlag */ if ((var->is_global || var->type.qualifier == SLANG_QUAL_OUT || var->type.qualifier == SLANG_QUAL_INOUT) && A->UseReturnFlag) { /* create predicate, used below */ pred = slang_operation_new(1); pred->type = SLANG_OPER_IDENTIFIER; - pred->a_id = slang_atom_pool_atom(A->atoms, "__returnFlag"); + pred->a_id = slang_atom_pool_atom(A->atoms, "__notRetFlag"); pred->locals->outer_scope = oper->locals->outer_scope; } } @@ -4455,7 +4441,7 @@ _slang_gen_assignment(slang_assemble_ctx * A, slang_operation *oper) } if (n && pred) { - /* predicate the assignment code on __returnFlag */ + /* predicate the assignment code on __notRetFlag */ slang_ir_node *top, *cond; cond = _slang_gen_operation(A, pred); @@ -4947,6 +4933,8 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper) return _slang_gen_method_call(A, oper); case SLANG_OPER_RETURN: return _slang_gen_return(A, oper); + case SLANG_OPER_RETURN_INLINED: + return _slang_gen_return(A, oper); case SLANG_OPER_LABEL: return new_label(oper->label); case SLANG_OPER_IDENTIFIER: diff --git a/src/mesa/shader/slang/slang_compile_operation.h b/src/mesa/shader/slang/slang_compile_operation.h index 17c6c3e349..58f1edeed8 100644 --- a/src/mesa/shader/slang/slang_compile_operation.h +++ b/src/mesa/shader/slang/slang_compile_operation.h @@ -42,6 +42,7 @@ typedef enum slang_operation_type_ SLANG_OPER_CONTINUE, /* "continue" statement */ SLANG_OPER_DISCARD, /* "discard" (kill fragment) statement */ SLANG_OPER_RETURN, /* "return" [expr] */ + SLANG_OPER_RETURN_INLINED, /* "return" [expr] from inlined function */ SLANG_OPER_LABEL, /* a jump target */ SLANG_OPER_EXPRESSION, /* [expr] */ SLANG_OPER_IF, /* "if" [0] then [1] else [2] */ diff --git a/src/mesa/shader/slang/slang_print.c b/src/mesa/shader/slang/slang_print.c index bf1475f91d..98c7877534 100644 --- a/src/mesa/shader/slang/slang_print.c +++ b/src/mesa/shader/slang/slang_print.c @@ -261,6 +261,7 @@ slang_print_tree(const slang_operation *op, int indent) break; case SLANG_OPER_BLOCK_NEW_SCOPE: + case SLANG_OPER_NON_INLINED_CALL: spaces(indent); printf("{{ // new scope locals=%p outer=%p: ", (void *) op->locals, @@ -348,6 +349,13 @@ slang_print_tree(const slang_operation *op, int indent) slang_print_tree(&op->children[0], indent + 3); break; + case SLANG_OPER_RETURN_INLINED: + spaces(indent); + printf("RETURN_INLINED\n"); + if (op->num_children > 0) + slang_print_tree(&op->children[0], indent + 3); + break; + case SLANG_OPER_LABEL: spaces(indent); printf("LABEL %s\n", (char *) op->a_id); @@ -478,7 +486,7 @@ slang_print_tree(const slang_operation *op, int indent) (void *) scope, (void *) op->locals, (void *) op->locals->outer_scope); - assert(scope); + /*assert(scope);*/ } } break; -- cgit v1.2.3 From e80ecdf6596eb1f570ab6ae3dbcbd30660cd5b3a Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Fri, 26 Jun 2009 12:34:03 -0600 Subject: glsl: move/simplify error checking for 'return' statements --- src/mesa/shader/slang/slang_codegen.c | 36 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 22 deletions(-) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index 28d04d396d..24e9952386 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -950,6 +950,11 @@ gen_return_with_expression(slang_assemble_ctx *A, slang_operation *oper) assert(oper->type == SLANG_OPER_RETURN); + if (A->CurFunction->header.type.specifier.type == SLANG_SPEC_VOID) { + slang_info_log_error(A->log, "illegal return expression"); + return NULL; + } + blockOper = slang_operation_new(1); blockOper->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE; blockOper->locals->outer_scope = oper->locals->outer_scope; @@ -1039,6 +1044,11 @@ gen_return_without_expression(slang_assemble_ctx *A, slang_operation *oper) assert(oper->type == SLANG_OPER_RETURN); + if (A->CurFunction->header.type.specifier.type != SLANG_SPEC_VOID) { + slang_info_log_error(A->log, "return statement requires an expression"); + return NULL; + } + if (A->UseReturnFlag) { /* Emit: * __notRetFlag = 0; @@ -1150,6 +1160,9 @@ slang_substitute(slang_assemble_ctx *A, slang_operation *oper, else newReturn = gen_return_with_expression(A, oper); + if (!newReturn) + return; + /* do substitutions on the new 'return' code */ slang_substitute(A, newReturn, substCount, substOld, substNew, GL_FALSE); @@ -4060,28 +4073,7 @@ _slang_gen_logical_or(slang_assemble_ctx *A, slang_operation *oper) static slang_ir_node * _slang_gen_return(slang_assemble_ctx * A, slang_operation *oper) { - const GLboolean haveReturnValue - = (oper->num_children == 1 && oper->children[0].type != SLANG_OPER_VOID); - - assert(oper->type == SLANG_OPER_RETURN || - oper->type == SLANG_OPER_RETURN_INLINED); - - /* error checking */ - if (oper->type == SLANG_OPER_RETURN) { - assert(A->CurFunction); - - if (haveReturnValue && - A->CurFunction->header.type.specifier.type == SLANG_SPEC_VOID) { - slang_info_log_error(A->log, "illegal return expression"); - return NULL; - } - else if (!haveReturnValue && - A->CurFunction->header.type.specifier.type != SLANG_SPEC_VOID) { - slang_info_log_error(A->log, "return statement requires an expression"); - return NULL; - } - } - + assert(oper->type == SLANG_OPER_RETURN); return new_return(A->curFuncEndLabel); } -- cgit v1.2.3 From 21320b24c5350943da9ed4cb0f1e8b05a09d4ef2 Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Fri, 26 Jun 2009 16:53:46 -0600 Subject: glsl: check number of varying variables against the limit Link fails if too many varying vars. (cherry picked from master, commit cc58fbcf2c5c88f406818db60910f537e03610d6) --- src/mesa/shader/slang/slang_link.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'src/mesa/shader') diff --git a/src/mesa/shader/slang/slang_link.c b/src/mesa/shader/slang/slang_link.c index 8c9fe1ea1f..387659ff30 100644 --- a/src/mesa/shader/slang/slang_link.c +++ b/src/mesa/shader/slang/slang_link.c @@ -97,7 +97,8 @@ bits_agree(GLbitfield flags1, GLbitfield flags2, GLbitfield bit) * which inputs are centroid-sampled, invariant, etc. */ static GLboolean -link_varying_vars(struct gl_shader_program *shProg, struct gl_program *prog) +link_varying_vars(GLcontext *ctx, + struct gl_shader_program *shProg, struct gl_program *prog) { GLuint *map, i, firstVarying, newFile; GLbitfield *inOutFlags; @@ -156,8 +157,12 @@ link_varying_vars(struct gl_shader_program *shProg, struct gl_program *prog) var->Flags); } + if (shProg->Varying->NumParameters > ctx->Const.MaxVarying) { + link_error(shProg, "Too many varying variables"); + return GL_FALSE; + } + /* Map varying[i] to varying[j]. - * Plus, set prog->Input/OutputFlags[] as described above. * Note: the loop here takes care of arrays or large (sz>4) vars. */ { @@ -725,11 +730,11 @@ _slang_link(GLcontext *ctx, /* link varying vars */ if (shProg->VertexProgram) { - if (!link_varying_vars(shProg, &shProg->VertexProgram->Base)) + if (!link_varying_vars(ctx, shProg, &shProg->VertexProgram->Base)) return; } if (shProg->FragmentProgram) { - if (!link_varying_vars(shProg, &shProg->FragmentProgram->Base)) + if (!link_varying_vars(ctx, shProg, &shProg->FragmentProgram->Base)) return; } -- cgit v1.2.3