summaryrefslogtreecommitdiff
path: root/src/mesa
diff options
context:
space:
mode:
authorBrian <brian@nostromo.localnet.net>2007-02-08 17:11:18 -0700
committerBrian <brian@nostromo.localnet.net>2007-02-08 17:11:18 -0700
commitc0a9f554be0b82f2e6ce2d9318854ecd24a1a890 (patch)
treea5bdb09db67ba8b51480d68c979e8b28928afffd /src/mesa
parent6230ae7faf46e0ebcb4807df051c8b50482089dd (diff)
optimize conditional breaks/continues
Diffstat (limited to 'src/mesa')
-rw-r--r--src/mesa/shader/slang/slang_codegen.c90
-rw-r--r--src/mesa/shader/slang/slang_emit.c20
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 2da53171ed..7566ad2e9f 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,
@@ -1537,6 +1560,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 c43f79cc72..1b43042e2d 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 */