summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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 aea11da0db5..3d4a474b052 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 7a1881c68ee..a5f033d9123 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 b890a6d93c2..3faacdd4cf8 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 fbd25c0fbfe..12c8aee6ea0 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 */
{