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:
Brian
2007-02-07 15:12:13 -07:00
parent 1f99a7514e
commit 4aa487e796
5 changed files with 128 additions and 85 deletions

View File

@@ -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);

View File

@@ -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;
} }

View File

@@ -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,

View File

@@ -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;

View File

@@ -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;