diff options
-rw-r--r-- | src/mesa/shader/prog_print.c | 8 | ||||
-rw-r--r-- | src/mesa/shader/slang/slang_codegen.c | 90 | ||||
-rw-r--r-- | src/mesa/shader/slang/slang_emit.c | 24 | ||||
-rw-r--r-- | src/mesa/swrast/s_fragprog.c | 30 |
4 files changed, 123 insertions, 29 deletions
diff --git a/src/mesa/shader/prog_print.c b/src/mesa/shader/prog_print.c index aea11da0db5..3d4a474b052 100644 --- a/src/mesa/shader/prog_print.c +++ b/src/mesa/shader/prog_print.c @@ -332,17 +332,17 @@ _mesa_print_instruction(const struct prog_instruction *inst, GLint indent) _mesa_printf("ENDIF\n"); break; case OPCODE_BGNLOOP: - _mesa_printf("BGNLOOP\n"); + _mesa_printf("BGNLOOP (end at %d)\n", inst->BranchTarget); return indent + 3; case OPCODE_ENDLOOP: _mesa_printf("ENDLOOP (goto %d)\n", inst->BranchTarget); break; case OPCODE_BRK: /* XXX just like BRA */ - _mesa_printf("BRK %u (%s%s)", - inst->BranchTarget, + _mesa_printf("BRK (%s%s) (for loop beginning at %d)", condcode_string(inst->DstReg.CondMask), - swizzle_string(inst->DstReg.CondSwizzle, 0, GL_FALSE)); + swizzle_string(inst->DstReg.CondSwizzle, 0, GL_FALSE), + inst->BranchTarget); print_comment(inst); break; case OPCODE_BGNSUB: diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index 7a1881c68ee..a5f033d9123 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -590,6 +590,18 @@ new_end_loop(slang_ir_node *beginNode) } +static slang_ir_node * +new_break(slang_ir_node *beginNode) +{ + slang_ir_node *n = new_node(IR_BREAK, NULL, NULL); + assert(beginNode); + if (n) { + n->BranchNode = beginNode; + } + return n; +} + + /** * Child[0] is the condition. * XXX we might re-design IR_IF so Children[1] is the "then" body and @@ -1430,7 +1442,7 @@ _slang_gen_hl_while(slang_assemble_ctx * A, const slang_operation *oper) * IF !expr THEN * BRK * ENDIF - * body code + * body code (child[1]) * ENDLOOP */ slang_ir_node *beginLoop, *endLoop, *ifThen, *endif; @@ -1445,7 +1457,7 @@ _slang_gen_hl_while(slang_assemble_ctx * A, const slang_operation *oper) ifThen = new_if(cond); tree = new_seq(beginLoop, ifThen); - brk = new_node(IR_BREAK, NULL, NULL); + brk = new_break(beginLoop); tree = new_seq(tree, brk); endif = new_endif(ifThen); @@ -1572,6 +1584,73 @@ _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! + */ +static slang_ir_node * +_slang_gen_hl_for(slang_assemble_ctx * A, const slang_operation *oper) +{ + /* + * init code (child[0]) + * BGNLOOP + * eval expr (child[1]), updating condcodes + * IF !expr THEN + * BRK + * ENDIF + * code body (child[3]) + * label "__continueFor" // jump here for "continue" + * incr code (child[2]) + * ENDLOOP + */ + 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; + + init = _slang_gen_operation(A, &oper->children[0]); + startLab = new_label(startAtom); + tree = new_seq(init, startLab); + + cond = _slang_gen_operation(A, &oper->children[1]); + cond = _slang_gen_cond(cond); + tree = new_seq(tree, cond); + + bra = new_cjump(endAtom, 0); + tree = new_seq(tree, bra); + + 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); + + /* Pop this loop */ + A->CurLoopBreak = prevLoopBreak; + A->CurLoopCont = prevLoopCont; + + return tree; +} + + +/** * Generate IR tree for an if/then/else conditional using BRAnch instructions. */ static slang_ir_node * @@ -2378,16 +2457,21 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper) case slang_oper_do: return _slang_gen_do(A, oper); case slang_oper_for: - return _slang_gen_for(A, oper); + if (UseHighLevelInstructions) + return _slang_gen_hl_for(A, oper); + else + return _slang_gen_for(A, oper); case slang_oper_break: if (!A->CurLoopBreak) { RETURN_ERROR("'break' not in loop", 0); } + /* XXX emit IR_BREAK instruction */ return new_jump(A->CurLoopBreak); case slang_oper_continue: if (!A->CurLoopCont) { RETURN_ERROR("'continue' not in loop", 0); } + /* XXX emit IR_CONT instruction */ return new_jump(A->CurLoopCont); case slang_oper_discard: return new_node(IR_KILL, NULL, NULL); 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: diff --git a/src/mesa/swrast/s_fragprog.c b/src/mesa/swrast/s_fragprog.c index fbd25c0fbfe..12c8aee6ea0 100644 --- a/src/mesa/swrast/s_fragprog.c +++ b/src/mesa/swrast/s_fragprog.c @@ -625,7 +625,7 @@ execute_program( GLcontext *ctx, GLuint column ) { const GLuint MAX_EXEC = 10000; - GLint pc, total = 0, loopDepth = 0; + GLint pc, total = 0; if (DEBUG_FRAG) { printf("execute fragment program --------------------\n"); @@ -676,11 +676,8 @@ execute_program( GLcontext *ctx, } break; case OPCODE_BGNLOOP: /* begin loop */ - loopDepth++; break; case OPCODE_ENDLOOP: /* end loop */ - loopDepth--; - assert(loopDepth >= 0); /* subtract 1 here since pc is incremented by for(pc) loop */ pc = inst->BranchTarget - 1; /* go to matching BNGLOOP */ break; @@ -706,19 +703,18 @@ execute_program( GLcontext *ctx, } break; case OPCODE_BRK: /* break out of loop */ - if (loopDepth == 0) { - _mesa_problem(ctx, "BRK not inside a loop"); - } - /* search for OPCODE_ENDLOOP */ - do { - pc++; - inst = program->Base.Instructions + pc; - if (inst->Opcode == OPCODE_ENDLOOP) { - loopDepth--; - assert(loopDepth >= 0); - break; - } - } while (pc < maxInst); + { + /* The location of the ENDLOOP instruction is saved in the + * BGNLOOP instruction. Get that instruction and jump to + * its BranchTarget + 1. + */ + const struct prog_instruction *loopBeginInst + = program->Base.Instructions + inst->BranchTarget; + ASSERT(loopBeginInst->Opcode == OPCODE_BGNLOOP); + ASSERT(loopBeginInst->BranchTarget >= 0); + /* we'll add one at bottom of for-loop */ + pc = loopBeginInst->BranchTarget; + } break; case OPCODE_CAL: /* Call subroutine */ { |