From c0a9f554be0b82f2e6ce2d9318854ecd24a1a890 Mon Sep 17 00:00:00 2001 From: Brian Date: Thu, 8 Feb 2007 17:11:18 -0700 Subject: [PATCH] optimize conditional breaks/continues --- src/mesa/shader/slang/slang_codegen.c | 90 ++++++++++++++++++++++----- src/mesa/shader/slang/slang_emit.c | 20 ++++-- 2 files changed, 87 insertions(+), 23 deletions(-) diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index 2da53171ede..7566ad2e9f8 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -614,12 +614,35 @@ new_break(slang_ir_node *loopNode) } +/** + * Make new IR_BREAK_IF_TRUE or IR_BREAK_IF_FALSE node. + */ static slang_ir_node * -new_break_if_false(slang_ir_node *loopNode, slang_ir_node *cond) +new_break_if(slang_ir_node *loopNode, slang_ir_node *cond, GLboolean breakTrue) { - slang_ir_node *n = new_node1(IR_BREAK_IF_FALSE, cond); + slang_ir_node *n; + assert(loopNode); + assert(loopNode->Opcode == IR_LOOP); + n = new_node1(breakTrue ? IR_BREAK_IF_TRUE : IR_BREAK_IF_FALSE, cond); + if (n) { + /* insert this node at head of linked list */ + n->BranchNode = loopNode->BranchNode; + loopNode->BranchNode = n; + } + return n; +} + + +/** + * Make new IR_CONT_IF_TRUE or IR_CONT_IF_FALSE node. + */ +static slang_ir_node * +new_cont_if(slang_ir_node *loopNode, slang_ir_node *cond, GLboolean contTrue) +{ + slang_ir_node *n; assert(loopNode); assert(loopNode->Opcode == IR_LOOP); + n = new_node1(contTrue ? IR_CONT_IF_TRUE : IR_CONT_IF_FALSE, cond); if (n) { /* insert this node at head of linked list */ n->BranchNode = loopNode->BranchNode; @@ -1406,7 +1429,7 @@ _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_false(A->CurLoop, cond); + breakIf = new_break_if(A->CurLoop, cond, GL_FALSE); body = _slang_gen_operation(A, &oper->children[1]); loop->Children[0] = new_seq(breakIf, body); @@ -1439,7 +1462,7 @@ _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_false(A->CurLoop, cond); + breakIf = new_break_if(A->CurLoop, cond, GL_FALSE); loop->Children[0] = new_seq(body, breakIf); /* pop loop, restore prev */ @@ -1473,7 +1496,7 @@ _slang_gen_for(slang_assemble_ctx * A, const slang_operation *oper) A->CurLoop = loop; cond = new_cond(_slang_gen_operation(A, &oper->children[1])); - breakIf = new_break_if_false(A->CurLoop, cond); + breakIf = new_break_if(A->CurLoop, cond, GL_FALSE); body = _slang_gen_operation(A, &oper->children[3]); incr = _slang_gen_operation(A, &oper->children[2]); loop->Children[0] = new_seq(breakIf, @@ -1536,6 +1559,23 @@ _slang_gen_if(slang_assemble_ctx * A, const slang_operation *oper) } +/** + * Determine if the given operation is of a specific type. + */ +static GLboolean +is_operation_type(const const slang_operation *oper, slang_operation_type type) +{ + if (oper->type == type) + return GL_TRUE; + else if ((oper->type == slang_oper_block_new_scope || + oper->type == slang_oper_block_no_new_scope) && + oper->num_children == 1) + return is_operation_type(&oper->children[0], type); + else + return GL_FALSE; +} + + /** * Generate IR tree for an if/then/else conditional using high-level * IR_IF instruction. @@ -1551,24 +1591,40 @@ _slang_gen_hl_if(slang_assemble_ctx * A, const slang_operation *oper) * else-body code * ENDIF */ - /* XXX special cases to check for: - * if body of conditiona is just a "break", emit a conditional break - * instruction. - */ const GLboolean haveElseClause = !_slang_is_noop(&oper->children[2]); slang_ir_node *ifNode, *cond, *ifBody, *elseBody; cond = _slang_gen_operation(A, &oper->children[0]); cond = new_cond(cond); - ifBody = _slang_gen_operation(A, &oper->children[1]); - if (haveElseClause) - elseBody = _slang_gen_operation(A, &oper->children[2]); - else - elseBody = NULL; - - ifNode = new_if(cond, ifBody, elseBody); - return ifNode; + if (is_operation_type(&oper->children[1], slang_oper_break)) { + /* Special case: generate a conditional break */ + ifBody = new_break_if(A->CurLoop, cond, GL_TRUE); + if (haveElseClause) { + elseBody = _slang_gen_operation(A, &oper->children[2]); + return new_seq(ifBody, elseBody); + } + return ifBody; + } + else if (is_operation_type(&oper->children[1], slang_oper_continue)) { + /* Special case: generate a conditional break */ + ifBody = new_cont_if(A->CurLoop, cond, GL_TRUE); + if (haveElseClause) { + elseBody = _slang_gen_operation(A, &oper->children[2]); + return new_seq(ifBody, elseBody); + } + return ifBody; + } + else { + /* general case */ + ifBody = _slang_gen_operation(A, &oper->children[1]); + if (haveElseClause) + elseBody = _slang_gen_operation(A, &oper->children[2]); + else + elseBody = NULL; + ifNode = new_if(cond, ifBody, elseBody); + return ifNode; + } } diff --git a/src/mesa/shader/slang/slang_emit.c b/src/mesa/shader/slang/slang_emit.c index c43f79cc727..1b43042e2d9 100644 --- a/src/mesa/shader/slang/slang_emit.c +++ b/src/mesa/shader/slang/slang_emit.c @@ -1156,9 +1156,9 @@ emit_loop(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog) beginInst->BranchTarget = prog->NumInstructions - 1; } - /* Done emitting loop code. Now walk over the loop's linked list - * of BREAK and CONT nodes, filling in their BranchTarget fields - * (which will point to the ENDLOOP or ENDLOOP+1 instructions). + /* Done emitting loop code. Now walk over the loop's linked list of + * BREAK and CONT nodes, filling in their BranchTarget fields (which + * will point to the ENDLOOP+1 or BGNLOOP instructions, respectively). */ for (ir = n->BranchNode; ir; ir = ir->BranchNode) { struct prog_instruction *inst = prog->Instructions + ir->InstLocation; @@ -1186,7 +1186,8 @@ emit_loop(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog) /** - * Emit code for IR_CONT or IR_BREAK. + * "Continue" or "break" statement. + * Either OPCODE_CONT, OPCODE_BRK or OPCODE_BRA will be emitted. */ static struct prog_instruction * emit_cont_break(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog) @@ -1207,7 +1208,8 @@ emit_cont_break(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog) /** - * Conditional loop continue/break. + * Conditional "continue" or "break" statement. + * Either OPCODE_CONT, OPCODE_BRK or OPCODE_BRA will be emitted. */ static struct prog_instruction * emit_cont_break_if(slang_var_table *vt, slang_ir_node *n, @@ -1223,7 +1225,11 @@ emit_cont_break_if(slang_var_table *vt, slang_ir_node *n, n->InstLocation = prog->NumInstructions; if (EmitHighLevelInstructions) { - opcode = (n->Opcode == IR_CONT) ? OPCODE_CONT : OPCODE_BRK; + if (n->Opcode == IR_CONT_IF_TRUE || + n->Opcode == IR_CONT_IF_FALSE) + opcode = OPCODE_CONT; + else + opcode = OPCODE_BRK; } else { opcode = OPCODE_BRA; @@ -1452,8 +1458,10 @@ emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog) case IR_LOOP: return emit_loop(vt, n, prog); case IR_BREAK_IF_FALSE: + case IR_CONT_IF_FALSE: return emit_cont_break_if(vt, n, prog, GL_FALSE); case IR_BREAK_IF_TRUE: + case IR_CONT_IF_TRUE: return emit_cont_break_if(vt, n, prog, GL_TRUE); case IR_BREAK: /* fall-through */ -- 2.30.2