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