diff options
Diffstat (limited to 'src/mesa')
-rw-r--r-- | src/mesa/shader/slang/slang_codegen.c | 131 |
1 files changed, 126 insertions, 5 deletions
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 @@ -2348,10 +2348,122 @@ _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); } } |