summaryrefslogtreecommitdiffstats
path: root/src/mesa/shader/slang/slang_codegen.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/shader/slang/slang_codegen.c')
-rw-r--r--src/mesa/shader/slang/slang_codegen.c66
1 files changed, 58 insertions, 8 deletions
diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c
index 7566ad2e9f8..62854548608 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);