Use IR_LOOP to represent do-while and for-loops.
Also, start moving high vs. low-level instruction selection into slang_emit.c
This commit is contained in:
@@ -1423,7 +1423,7 @@ _slang_gen_while(slang_assemble_ctx * A, const slang_operation *oper)
|
||||
|
||||
|
||||
/**
|
||||
* 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)
|
||||
@@ -1509,6 +1509,46 @@ _slang_gen_do(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.
|
||||
*/
|
||||
@@ -1573,69 +1613,48 @@ _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!
|
||||
* 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);
|
||||
loop->Children[0] = new_seq(ifThen,
|
||||
new_seq(body,incr));
|
||||
|
||||
endLab = new_label(endAtom);
|
||||
tree = new_seq(tree, endLab);
|
||||
A->CurLoop = prevLoop; /* pop loop, restore prev */
|
||||
|
||||
/* Pop this loop */
|
||||
A->CurLoopBreak = prevLoopBreak;
|
||||
A->CurLoopCont = prevLoopCont;
|
||||
|
||||
return tree;
|
||||
return new_seq(init, loop);
|
||||
}
|
||||
|
||||
|
||||
@@ -2434,7 +2453,10 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper)
|
||||
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);
|
||||
|
@@ -43,6 +43,9 @@
|
||||
#define ANNOTATE 1
|
||||
|
||||
|
||||
static GLboolean EmitHighLevelInstructions = GL_FALSE;
|
||||
|
||||
|
||||
/**
|
||||
* Assembly and IR info
|
||||
*/
|
||||
@@ -1304,57 +1307,72 @@ emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
|
||||
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_BREAK:
|
||||
/* fall-through */
|
||||
case IR_CONT:
|
||||
{
|
||||
gl_inst_opcode opcode;
|
||||
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:
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@@ -39,7 +39,7 @@
|
||||
|
||||
|
||||
/**
|
||||
* Intermediate Representation opcode
|
||||
* Intermediate Representation opcodes
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
@@ -64,6 +64,11 @@ 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,
|
||||
|
@@ -298,7 +298,7 @@ _slang_resolve_branches(struct gl_program *prog)
|
||||
|
||||
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;
|
||||
|
@@ -675,9 +675,10 @@ execute_program( GLcontext *ctx,
|
||||
}
|
||||
}
|
||||
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;
|
||||
@@ -695,10 +696,7 @@ execute_program( GLcontext *ctx,
|
||||
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;
|
||||
@@ -721,7 +719,7 @@ execute_program( GLcontext *ctx,
|
||||
return GL_TRUE; /* Per GL_NV_vertex_program2 spec */
|
||||
}
|
||||
machine->CallStack[machine->StackDepth++] = pc + 1;
|
||||
pc = inst->BranchTarget;
|
||||
pc = inst->BranchTarget; /* XXX - 1 ??? */
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
Reference in New Issue
Block a user