}
+/**
+ * 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:
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'");
* 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:
/* 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);
}
}
/* 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);
}
}