/**
- * Generate IR tree for a while-loop using high-level LOOP, IF instructions.
+ * Generate loop code using high-level IR_LOOP instruction
*/
static slang_ir_node *
_slang_gen_hl_while(slang_assemble_ctx * A, const slang_operation *oper)
/**
+ * Generate IR tree for a do-while loop using high-level LOOP, IF instructions.
+ */
+static slang_ir_node *
+_slang_gen_hl_do(slang_assemble_ctx * A, const slang_operation *oper)
+{
+ slang_ir_node *prevLoop;
+ /*
+ * LOOP:
+ * body code (child[0])
+ * eval expr (child[1]), updating condcodes
+ * IF !expr:
+ * BRK
+ */
+ slang_ir_node *ifThen, *cond, *body, *loop;
+
+ loop = new_loop(NULL);
+
+ /* save old, push new loop */
+ prevLoop = A->CurLoop;
+ A->CurLoop = loop;
+
+ body = _slang_gen_operation(A, &oper->children[0]);
+
+ cond = _slang_gen_operation(A, &oper->children[1]);
+ cond = new_node1(IR_NOT, cond);
+ cond = _slang_gen_cond(cond);
+
+ ifThen = new_if(cond,
+ new_break(A->CurLoop),
+ NULL);
+
+ loop->Children[0] = new_seq(body, ifThen);
+
+ A->CurLoop = prevLoop; /* pop loop, restore prev */
+
+ return loop;
+}
+
+
+/**
* Generate IR tree for a for-loop.
*/
static slang_ir_node *
/**
- * Generate IR tree for a for-loop, using high-level BGNLOOP/ENDLOOP and
- * IF/ENDIF instructions.
- *
- * XXX note done yet!
+ * Generate for-loop using high-level IR_LOOP instruction.
*/
static slang_ir_node *
_slang_gen_hl_for(slang_assemble_ctx * A, const slang_operation *oper)
{
+ slang_ir_node *prevLoop;
/*
- * init code (child[0])
- * BGNLOOP
+ * init (child[0])
+ * LOOP:
* eval expr (child[1]), updating condcodes
- * IF !expr THEN
+ * IF !expr:
* BRK
- * ENDIF
- * code body (child[3])
- * label "__continueFor" // jump here for "continue"
- * incr code (child[2])
- * ENDLOOP
+ * body code (child[3])
+ * incr code (child[2]) // XXX continue here
*/
- 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;
+ slang_ir_node *init, *ifThen, *cond, *body, *loop, *incr;
init = _slang_gen_operation(A, &oper->children[0]);
- startLab = new_label(startAtom);
- tree = new_seq(init, startLab);
+ loop = new_loop(NULL);
+
+ /* save old, push new loop */
+ prevLoop = A->CurLoop;
+ A->CurLoop = loop;
cond = _slang_gen_operation(A, &oper->children[1]);
+ cond = new_node1(IR_NOT, cond);
cond = _slang_gen_cond(cond);
- tree = new_seq(tree, cond);
- bra = new_cjump(endAtom, 0);
- tree = new_seq(tree, bra);
+ ifThen = new_if(cond,
+ new_break(A->CurLoop),
+ NULL);
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);
+ loop->Children[0] = new_seq(ifThen,
+ new_seq(body,incr));
- /* Pop this loop */
- A->CurLoopBreak = prevLoopBreak;
- A->CurLoopCont = prevLoopCont;
+ A->CurLoop = prevLoop; /* pop loop, restore prev */
- return tree;
+ return new_seq(init, loop);
}
else
return _slang_gen_while(A, oper);
case slang_oper_do:
- return _slang_gen_do(A, oper);
+ if (UseHighLevelInstructions)
+ return _slang_gen_hl_do(A, oper);
+ else
+ return _slang_gen_do(A, oper);
case slang_oper_for:
if (UseHighLevelInstructions)
return _slang_gen_hl_for(A, oper);
#define ANNOTATE 1
+static GLboolean EmitHighLevelInstructions = GL_FALSE;
+
+
/**
* Assembly and IR info
*/
case IR_LOOP:
{
struct prog_instruction *beginInst, *endInst;
- GLuint endInstLoc;
- slang_ir_node *p;
+ GLuint beginInstLoc, endInstLoc;
+ slang_ir_node *ir;
- /* save location of this instruction, used by OPCODE_ENDLOOP */
- n->InstLocation = prog->NumInstructions;
- (void) new_instruction(prog, OPCODE_BGNLOOP);
+ /* emit OPCODE_BGNLOOP */
+ beginInstLoc = prog->NumInstructions;
+ if (EmitHighLevelInstructions) {
+ (void) new_instruction(prog, OPCODE_BGNLOOP);
+ }
/* body */
emit(vt, n->Children[0], prog);
endInstLoc = prog->NumInstructions;
- endInst = new_instruction(prog, OPCODE_ENDLOOP);
- /* The ENDLOOP's BranchTarget points to top of loop */
- endInst->BranchTarget = n->InstLocation;
- /* Update BGNLOOP's BranchTarget to point to this instruction */
- beginInst = prog->Instructions + n->InstLocation;
- beginInst->BranchTarget = prog->NumInstructions - 1;
+ if (EmitHighLevelInstructions) {
+ /* emit OPCODE_ENDLOOP */
+ endInst = new_instruction(prog, OPCODE_ENDLOOP);
+ }
+ else {
+ /* emit unconditional BRA-nch */
+ endInst = new_instruction(prog, OPCODE_BRA);
+ endInst->DstReg.CondMask = COND_TR; /* always true */
+ }
+ /* end instruction's BranchTarget points to top of loop */
+ endInst->BranchTarget = beginInstLoc;
+
+ if (EmitHighLevelInstructions) {
+ /* BGNLOOP's BranchTarget points to the ENDLOOP inst */
+ beginInst = prog->Instructions + beginInstLoc;
+ 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.
+ * of BREAK and CONT nodes, filling in their BranchTarget fields
+ * (which will point to the ENDLOOP or ENDLOOP+1 instructions).
*/
- for (p = n->BranchNode; p; p = p->BranchNode) {
- if (p->Opcode == IR_BREAK) {
- struct prog_instruction *brkInst
- = prog->Instructions + p->InstLocation;
- assert(brkInst->Opcode == OPCODE_BRK);
- brkInst->BranchTarget = endInstLoc + 1;
+ for (ir = n->BranchNode; ir; ir = ir->BranchNode) {
+ struct prog_instruction *inst
+ = prog->Instructions + ir->InstLocation;
+ if (ir->Opcode == IR_BREAK) {
+ assert(inst->Opcode == OPCODE_BRK ||
+ inst->Opcode == OPCODE_BRA);
+ inst->BranchTarget = endInstLoc + 1;
}
else {
- assert(p->Opcode == IR_CONT);
- struct prog_instruction *contInst
- = prog->Instructions + p->InstLocation;
- assert(contInst->Opcode == OPCODE_CONT);
- contInst->BranchTarget = endInstLoc;
+ assert(ir->Opcode == IR_CONT);
+ assert(inst->Opcode == OPCODE_CONT ||
+ inst->Opcode == OPCODE_BRA);
+ inst->BranchTarget = endInstLoc;
}
}
return NULL;
}
- case IR_CONT:
- {
- struct prog_instruction *inst;
- n->InstLocation = prog->NumInstructions;
- inst = new_instruction(prog, OPCODE_CONT);
- inst->DstReg.CondMask = COND_TR; /* always true */
- return inst;
- }
case IR_BREAK:
+ /* fall-through */
+ case IR_CONT:
{
+ gl_inst_opcode opcode;
struct prog_instruction *inst;
n->InstLocation = prog->NumInstructions;
- inst = new_instruction(prog, OPCODE_BRK);
+ if (EmitHighLevelInstructions) {
+ opcode = (n->Opcode == IR_CONT) ? OPCODE_CONT : OPCODE_BRK;
+ }
+ else {
+ opcode = OPCODE_BRA;
+ }
+ inst = new_instruction(prog, opcode);
inst->DstReg.CondMask = COND_TR; /* always true */
return inst;
}
/**
- * Intermediate Representation opcode
+ * Intermediate Representation opcodes
*/
typedef enum
{
IR_CONT, /* continue loop */
IR_BREAK, /* break loop */
+ IR_BREAK_IF_TRUE,
+ IR_BREAK_IF_FALSE,
+ IR_CONT_IF_TRUE,
+ IR_CONT_IF_FALSE,
+
IR_MOVE,
IR_ADD,
IR_SUB,
for (i = 0; i < prog->NumInstructions; i++) {
struct prog_instruction *inst = prog->Instructions + i;
- if (inst->Opcode == OPCODE_BRA) {
+ if (inst->Opcode == OPCODE_BRA && inst->BranchTarget < 0) {
for (j = 0; j < numTargets; j++) {
if (!strcmp(inst->Comment, targets[j].Name)) {
inst->BranchTarget = targets[j].Pos;
}
}
break;
- case OPCODE_BGNLOOP: /* begin loop */
+ case OPCODE_BGNLOOP:
+ /* no-op */
break;
- case OPCODE_ENDLOOP: /* end loop */
+ case OPCODE_ENDLOOP:
/* subtract 1 here since pc is incremented by for(pc) loop */
pc = inst->BranchTarget - 1; /* go to matching BNGLOOP */
break;
test_cc(machine->CondCodes[GET_SWZ(swizzle, 2)], condMask) ||
test_cc(machine->CondCodes[GET_SWZ(swizzle, 3)], condMask)) {
/* take branch */
- pc = inst->BranchTarget;
- /*
- printf("Take branch to %u\n", pc);
- */
+ pc = inst->BranchTarget - 1;
}
}
break;
return GL_TRUE; /* Per GL_NV_vertex_program2 spec */
}
machine->CallStack[machine->StackDepth++] = pc + 1;
- pc = inst->BranchTarget;
+ pc = inst->BranchTarget; /* XXX - 1 ??? */
}
}
break;