diff options
author | Brian <[email protected]> | 2007-02-05 18:01:02 -0700 |
---|---|---|
committer | Brian <[email protected]> | 2007-02-05 18:01:02 -0700 |
commit | 2755c798f3cb89fcd4ece16cd740af1cd86a6b99 (patch) | |
tree | 423205b0b37cf79f08f4b2b0a6d2a845e6f1dbc2 /src/mesa/shader/slang/slang_emit.c | |
parent | 86080796471df6a9e126fd536b21c3b10cb5310c (diff) |
BRK instruction's BranchTarget field now used for efficiently breaking out of loops.
BRK's BranchTarget field actually points to the top of the loop, not the
bottom, since we don't know the later's location yet. In the interpreter,
basically do an indirect jump to update the PC.
Diffstat (limited to 'src/mesa/shader/slang/slang_emit.c')
-rw-r--r-- | src/mesa/shader/slang/slang_emit.c | 24 |
1 files changed, 19 insertions, 5 deletions
diff --git a/src/mesa/shader/slang/slang_emit.c b/src/mesa/shader/slang/slang_emit.c index b890a6d93c2..3faacdd4cf8 100644 --- a/src/mesa/shader/slang/slang_emit.c +++ b/src/mesa/shader/slang/slang_emit.c @@ -1265,24 +1265,29 @@ emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog) } 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; } @@ -1295,12 +1300,15 @@ emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog) 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: @@ -1310,6 +1318,12 @@ emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog) 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: |