summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian <brian@yutani.localnet.net>2007-02-05 18:01:02 -0700
committerBrian <brian@yutani.localnet.net>2007-02-05 18:01:02 -0700
commit2755c798f3cb89fcd4ece16cd740af1cd86a6b99 (patch)
tree423205b0b37cf79f08f4b2b0a6d2a845e6f1dbc2
parent86080796471df6a9e126fd536b21c3b10cb5310c (diff)
BRK instruction's BranchTarget field now used for efficiently breaking out of loops.
BRK's BranchTarget field actually points to the top of the loop, not the bottom, since we don't know the later's location yet. In the interpreter, basically do an indirect jump to update the PC.
-rw-r--r--src/mesa/shader/prog_print.c8
-rw-r--r--src/mesa/shader/slang/slang_codegen.c90
-rw-r--r--src/mesa/shader/slang/slang_emit.c24
-rw-r--r--src/mesa/swrast/s_fragprog.c30
4 files changed, 123 insertions, 29 deletions
diff --git a/src/mesa/shader/prog_print.c b/src/mesa/shader/prog_print.c
index aea11da0db..3d4a474b05 100644
--- a/src/mesa/shader/prog_print.c
+++ b/src/mesa/shader/prog_print.c
@@ -332,17 +332,17 @@ _mesa_print_instruction(const struct prog_instruction *inst, GLint indent)
_mesa_printf("ENDIF\n");
break;
case OPCODE_BGNLOOP:
- _mesa_printf("BGNLOOP\n");
+ _mesa_printf("BGNLOOP (end at %d)\n", inst->BranchTarget);
return indent + 3;
case OPCODE_ENDLOOP:
_mesa_printf("ENDLOOP (goto %d)\n", inst->BranchTarget);
break;
case OPCODE_BRK:
/* XXX just like BRA */
- _mesa_printf("BRK %u (%s%s)",
- inst->BranchTarget,
+ _mesa_printf("BRK (%s%s) (for loop beginning at %d)",
condcode_string(inst->DstReg.CondMask),
- swizzle_string(inst->DstReg.CondSwizzle, 0, GL_FALSE));
+ swizzle_string(inst->DstReg.CondSwizzle, 0, GL_FALSE),
+ inst->BranchTarget);
print_comment(inst);
break;
case OPCODE_BGNSUB:
diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c
index 7a1881c68e..a5f033d912 100644
--- a/src/mesa/shader/slang/slang_codegen.c
+++ b/src/mesa/shader/slang/slang_codegen.c
@@ -590,6 +590,18 @@ new_end_loop(slang_ir_node *beginNode)
}
+static slang_ir_node *
+new_break(slang_ir_node *beginNode)
+{
+ slang_ir_node *n = new_node(IR_BREAK, NULL, NULL);
+ assert(beginNode);
+ if (n) {
+ n->BranchNode = beginNode;
+ }
+ return n;
+}
+
+
/**
* Child[0] is the condition.
* XXX we might re-design IR_IF so Children[1] is the "then" body and
@@ -1430,7 +1442,7 @@ _slang_gen_hl_while(slang_assemble_ctx * A, const slang_operation *oper)
* IF !expr THEN
* BRK
* ENDIF
- * body code
+ * body code (child[1])
* ENDLOOP
*/
slang_ir_node *beginLoop, *endLoop, *ifThen, *endif;
@@ -1445,7 +1457,7 @@ _slang_gen_hl_while(slang_assemble_ctx * A, const slang_operation *oper)
ifThen = new_if(cond);
tree = new_seq(beginLoop, ifThen);
- brk = new_node(IR_BREAK, NULL, NULL);
+ brk = new_break(beginLoop);
tree = new_seq(tree, brk);
endif = new_endif(ifThen);
@@ -1572,6 +1584,73 @@ _slang_gen_for(slang_assemble_ctx * A, const slang_operation *oper)
/**
+ * Generate IR tree for a for-loop, using high-level BGNLOOP/ENDLOOP and
+ * IF/ENDIF instructions.
+ *
+ * XXX note done yet!
+ */
+static slang_ir_node *
+_slang_gen_hl_for(slang_assemble_ctx * A, const slang_operation *oper)
+{
+ /*
+ * init code (child[0])
+ * BGNLOOP
+ * eval expr (child[1]), updating condcodes
+ * IF !expr THEN
+ * BRK
+ * ENDIF
+ * code body (child[3])
+ * label "__continueFor" // jump here for "continue"
+ * incr code (child[2])
+ * ENDLOOP
+ */
+ slang_atom startAtom = slang_atom_pool_gen(A->atoms, "__startFor");
+ slang_atom contAtom = slang_atom_pool_gen(A->atoms, "__continueFor");
+ slang_atom endAtom = slang_atom_pool_gen(A->atoms, "__endFor");
+ slang_ir_node *init, *startLab, *cond, *bra, *body, *contLab;
+ slang_ir_node *incr, *jump, *endLab, *tree;
+ slang_atom prevLoopBreak = A->CurLoopBreak;
+ slang_atom prevLoopCont = A->CurLoopCont;
+
+ /* Push this loop */
+ A->CurLoopBreak = endAtom;
+ A->CurLoopCont = contAtom;
+
+ init = _slang_gen_operation(A, &oper->children[0]);
+ startLab = new_label(startAtom);
+ tree = new_seq(init, startLab);
+
+ cond = _slang_gen_operation(A, &oper->children[1]);
+ cond = _slang_gen_cond(cond);
+ tree = new_seq(tree, cond);
+
+ bra = new_cjump(endAtom, 0);
+ tree = new_seq(tree, bra);
+
+ body = _slang_gen_operation(A, &oper->children[3]);
+ tree = new_seq(tree, body);
+
+ contLab = new_label(contAtom);
+ tree = new_seq(tree, contLab);
+
+ incr = _slang_gen_operation(A, &oper->children[2]);
+ tree = new_seq(tree, incr);
+
+ jump = new_jump(startAtom);
+ tree = new_seq(tree, jump);
+
+ endLab = new_label(endAtom);
+ tree = new_seq(tree, endLab);
+
+ /* Pop this loop */
+ A->CurLoopBreak = prevLoopBreak;
+ A->CurLoopCont = prevLoopCont;
+
+ return tree;
+}
+
+
+/**
* Generate IR tree for an if/then/else conditional using BRAnch instructions.
*/
static slang_ir_node *
@@ -2378,16 +2457,21 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper)
case slang_oper_do:
return _slang_gen_do(A, oper);
case slang_oper_for:
- return _slang_gen_for(A, oper);
+ if (UseHighLevelInstructions)
+ return _slang_gen_hl_for(A, oper);
+ else
+ return _slang_gen_for(A, oper);
case slang_oper_break:
if (!A->CurLoopBreak) {
RETURN_ERROR("'break' not in loop", 0);
}
+ /* XXX emit IR_BREAK instruction */
return new_jump(A->CurLoopBreak);
case slang_oper_continue:
if (!A->CurLoopCont) {
RETURN_ERROR("'continue' not in loop", 0);
}
+ /* XXX emit IR_CONT instruction */
return new_jump(A->CurLoopCont);
case slang_oper_discard:
return new_node(IR_KILL, NULL, NULL);
diff --git a/src/mesa/shader/slang/slang_emit.c b/src/mesa/shader/slang/slang_emit.c
index b890a6d93c..3faacdd4cf 100644
--- a/src/mesa/shader/slang/slang_emit.c
+++ b/src/mesa/shader/slang/slang_emit.c
@@ -1265,24 +1265,29 @@ emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
}
case IR_ELSE:
{
- struct prog_instruction *inst;
+ struct prog_instruction *inst, *ifInst;
n->InstLocation = prog->NumInstructions;
inst = new_instruction(prog, OPCODE_ELSE);
/* point IF's BranchTarget just after this instruction */
assert(n->BranchNode);
assert(n->BranchNode->InstLocation >= 0);
- prog->Instructions[n->BranchNode->InstLocation].BranchTarget = prog->NumInstructions;
+ ifInst = prog->Instructions + n->BranchNode->InstLocation;
+ assert(ifInst->Opcode == OPCODE_IF);
+ ifInst->BranchTarget = prog->NumInstructions;
return inst;
}
case IR_ENDIF:
{
- struct prog_instruction *inst;
+ struct prog_instruction *inst, *elseInst;
n->InstLocation = prog->NumInstructions;
inst = new_instruction(prog, OPCODE_ENDIF);
/* point ELSE's BranchTarget to just after this inst */
assert(n->BranchNode);
assert(n->BranchNode->InstLocation >= 0);
- prog->Instructions[n->BranchNode->InstLocation].BranchTarget = prog->NumInstructions;
+ elseInst = prog->Instructions + n->BranchNode->InstLocation;
+ assert(elseInst->Opcode == OPCODE_ELSE ||
+ elseInst->Opcode == OPCODE_IF);
+ elseInst->BranchTarget = prog->NumInstructions;
return inst;
}
@@ -1295,12 +1300,15 @@ emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
break;
case IR_END_LOOP:
{
- struct prog_instruction *inst;
+ struct prog_instruction *inst, *beginInst;
inst = new_instruction(prog, OPCODE_ENDLOOP);
assert(n->BranchNode);
assert(n->BranchNode->InstLocation >= 0);
/* The instruction BranchTarget points to top of loop */
inst->BranchTarget = n->BranchNode->InstLocation;
+ /* Update BEGIN_LOOP's BranchTarget to point to this instruction */
+ beginInst = prog->Instructions + n->BranchNode->InstLocation;
+ beginInst->BranchTarget = prog->NumInstructions - 1;
return inst;
}
case IR_CONT:
@@ -1310,6 +1318,12 @@ emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
struct prog_instruction *inst;
inst = new_instruction(prog, OPCODE_BRK);
inst->DstReg.CondMask = COND_TR; /* always true */
+ /* This instruction's branch target is top of loop, not bottom of
+ * loop because we don't know where it is yet!
+ */
+ assert(n->BranchNode);
+ assert(n->BranchNode->InstLocation >= 0);
+ inst->BranchTarget = n->BranchNode->InstLocation;
return inst;
}
case IR_BEGIN_SUB:
diff --git a/src/mesa/swrast/s_fragprog.c b/src/mesa/swrast/s_fragprog.c
index fbd25c0fbf..12c8aee6ea 100644
--- a/src/mesa/swrast/s_fragprog.c
+++ b/src/mesa/swrast/s_fragprog.c
@@ -625,7 +625,7 @@ execute_program( GLcontext *ctx,
GLuint column )
{
const GLuint MAX_EXEC = 10000;
- GLint pc, total = 0, loopDepth = 0;
+ GLint pc, total = 0;
if (DEBUG_FRAG) {
printf("execute fragment program --------------------\n");
@@ -676,11 +676,8 @@ execute_program( GLcontext *ctx,
}
break;
case OPCODE_BGNLOOP: /* begin loop */
- loopDepth++;
break;
case OPCODE_ENDLOOP: /* end loop */
- loopDepth--;
- assert(loopDepth >= 0);
/* subtract 1 here since pc is incremented by for(pc) loop */
pc = inst->BranchTarget - 1; /* go to matching BNGLOOP */
break;
@@ -706,19 +703,18 @@ execute_program( GLcontext *ctx,
}
break;
case OPCODE_BRK: /* break out of loop */
- if (loopDepth == 0) {
- _mesa_problem(ctx, "BRK not inside a loop");
- }
- /* search for OPCODE_ENDLOOP */
- do {
- pc++;
- inst = program->Base.Instructions + pc;
- if (inst->Opcode == OPCODE_ENDLOOP) {
- loopDepth--;
- assert(loopDepth >= 0);
- break;
- }
- } while (pc < maxInst);
+ {
+ /* The location of the ENDLOOP instruction is saved in the
+ * BGNLOOP instruction. Get that instruction and jump to
+ * its BranchTarget + 1.
+ */
+ const struct prog_instruction *loopBeginInst
+ = program->Base.Instructions + inst->BranchTarget;
+ ASSERT(loopBeginInst->Opcode == OPCODE_BGNLOOP);
+ ASSERT(loopBeginInst->BranchTarget >= 0);
+ /* we'll add one at bottom of for-loop */
+ pc = loopBeginInst->BranchTarget;
+ }
break;
case OPCODE_CAL: /* Call subroutine */
{