| @@ -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); | |||
| } | |||
| } | |||