_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:
}
+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
* IF !expr THEN
* BRK
* ENDIF
- * body code
+ * body code (child[1])
* ENDLOOP
*/
slang_ir_node *beginLoop, *endLoop, *ifThen, *endif;
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);
}
+/**
+ * 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.
*/
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);
}
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;
}
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:
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:
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");
}
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;
}
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 */
{