From bd9615bbc59b0ce626bb32e2a005fccec20e7331 Mon Sep 17 00:00:00 2001 From: Brian Date: Thu, 8 Feb 2007 17:40:29 -0700 Subject: Check for constant-valued while/do loop conditions. Allows us to: 1. avoid generating constant-valued BRK test for while(1).. 2. discard entire loop for while(0). 3. detection infinite loops at compile-time. --- src/mesa/shader/slang/slang_codegen.c | 66 ++++++++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 8 deletions(-) (limited to 'src/mesa/shader/slang') diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index 7566ad2e9f..6285454860 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -1408,19 +1408,48 @@ _slang_gen_function_call_name(slang_assemble_ctx *A, const char *name, } +static GLboolean +_slang_is_constant_cond(const slang_operation *oper, GLboolean *value) +{ + if (oper->type == slang_oper_literal_float || + oper->type == slang_oper_literal_int || + oper->type == slang_oper_literal_bool) { + if (oper->literal[0]) + *value = GL_TRUE; + else + *value = GL_FALSE; + return GL_TRUE; + } + else if (oper->type == slang_oper_expression && + oper->num_children == 1) { + return _slang_is_constant_cond(&oper->children[0], value); + } + return GL_FALSE; +} + + + /** * 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_ir_node *prevLoop; /* * LOOP: * BREAK if !expr (child[0]) * body code (child[1]) */ - slang_ir_node *loop, *cond, *breakIf, *body; + slang_ir_node *prevLoop, *loop, *cond, *breakIf, *body; + GLboolean isConst, constTrue; + + /* Check if loop condition is a constant */ + isConst = _slang_is_constant_cond(&oper->children[0], &constTrue); + + if (isConst && !constTrue) { + /* loop is never executed! */ + return new_node0(IR_NOP); + } loop = new_loop(NULL); @@ -1429,10 +1458,23 @@ _slang_gen_while(slang_assemble_ctx * A, const slang_operation *oper) A->CurLoop = loop; cond = new_cond(_slang_gen_operation(A, &oper->children[0])); - breakIf = new_break_if(A->CurLoop, cond, GL_FALSE); + if (isConst && constTrue) { + /* while(nonzero constant), no conditional break */ + breakIf = NULL; + } + else { + breakIf = new_break_if(A->CurLoop, cond, GL_FALSE); + } body = _slang_gen_operation(A, &oper->children[1]); loop->Children[0] = new_seq(breakIf, body); + /* Do infinite loop detection */ + if (loop->BranchNode == 0 && isConst && constTrue) { + /* infinite loop detected */ + A->CurLoop = prevLoop; /* clean-up */ + RETURN_ERROR("Infinite loop detected!", 0); + } + /* pop loop, restore prev */ A->CurLoop = prevLoop; @@ -1446,13 +1488,16 @@ _slang_gen_while(slang_assemble_ctx * A, const slang_operation *oper) static slang_ir_node * _slang_gen_do(slang_assemble_ctx * A, const slang_operation *oper) { - slang_ir_node *prevLoop; /* * LOOP: * body code (child[0]) * BREAK if !expr (child[1]) */ - slang_ir_node *loop, *cond, *breakIf, *body; + slang_ir_node *prevLoop, *loop, *cond, *breakIf, *body; + GLboolean isConst, constTrue; + + /* Check if loop condition is a constant */ + isConst = _slang_is_constant_cond(&oper->children[0], &constTrue); loop = new_loop(NULL); @@ -1462,7 +1507,13 @@ _slang_gen_do(slang_assemble_ctx * A, const slang_operation *oper) body = _slang_gen_operation(A, &oper->children[0]); cond = new_cond(_slang_gen_operation(A, &oper->children[1])); - breakIf = new_break_if(A->CurLoop, cond, GL_FALSE); + if (isConst && constTrue) { + /* while(nonzero constant), no conditional break */ + breakIf = NULL; + } + else { + breakIf = new_break_if(A->CurLoop, cond, GL_FALSE); + } loop->Children[0] = new_seq(body, breakIf); /* pop loop, restore prev */ @@ -1478,7 +1529,6 @@ _slang_gen_do(slang_assemble_ctx * A, const slang_operation *oper) static slang_ir_node * _slang_gen_for(slang_assemble_ctx * A, const slang_operation *oper) { - slang_ir_node *prevLoop; /* * init (child[0]) * LOOP: @@ -1486,7 +1536,7 @@ _slang_gen_for(slang_assemble_ctx * A, const slang_operation *oper) * body code (child[3]) * incr code (child[2]) // XXX continue here */ - slang_ir_node *loop, *cond, *breakIf, *body, *init, *incr; + slang_ir_node *prevLoop, *loop, *cond, *breakIf, *body, *init, *incr; init = _slang_gen_operation(A, &oper->children[0]); loop = new_loop(NULL); -- cgit v1.2.3