diff options
author | Brian <[email protected]> | 2007-02-05 15:00:07 -0700 |
---|---|---|
committer | Brian <[email protected]> | 2007-02-05 15:00:07 -0700 |
commit | cf92c727979e434d148b23d20f2e4e0f4bc4de61 (patch) | |
tree | 4f4142ad5919f7684216ae580abb627878d958b0 /src/mesa | |
parent | 5db088d70fbd14620c2fc7840096a05993f8e2b9 (diff) |
Initial implementation of high-level flow-control instructions.
IF/ELSE/ENDIF and BEGIN_LOOP/END_LOOP/BREAK instructions seem to work.
Disabled by default though until better tested.
Implemented IR_NOT, but needs optimization.
Diffstat (limited to 'src/mesa')
-rw-r--r-- | src/mesa/shader/slang/slang_codegen.c | 88 | ||||
-rw-r--r-- | src/mesa/shader/slang/slang_emit.c | 72 | ||||
-rw-r--r-- | src/mesa/shader/slang/slang_ir.h | 2 | ||||
-rw-r--r-- | src/mesa/swrast/s_fragprog.c | 38 | ||||
-rw-r--r-- | src/mesa/tnl/t_vp_build.c | 2 |
5 files changed, 189 insertions, 13 deletions
diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index 72f58a9ebd1..2dd9ccc6fdc 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -47,6 +47,8 @@ #include "slang_print.h" +static GLboolean UseHighLevelInstructions = GL_TRUE; + static slang_ir_node * _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper); @@ -506,6 +508,7 @@ new_node(slang_ir_opcode op, slang_ir_node *left, slang_ir_node *right) n->Children[0] = left; n->Children[1] = right; n->Writemask = WRITEMASK_XYZW; + n->InstLocation = -1; } return n; } @@ -567,6 +570,26 @@ new_jump(slang_atom target) } +static slang_ir_node * +new_begin_loop(void) +{ + slang_ir_node *n = new_node(IR_BEGIN_LOOP, NULL, NULL); + return n; +} + + +static slang_ir_node * +new_end_loop(slang_ir_node *beginNode) +{ + slang_ir_node *n = new_node(IR_END_LOOP, NULL, NULL); + assert(beginNode); + if (n) { + n->BranchNode = beginNode; + } + return n; +} + + /** * New IR_VAR node - a reference to a previously declared variable. */ @@ -1304,7 +1327,7 @@ _slang_gen_function_call_name(slang_assemble_ctx *A, const char *name, /** - * Generate IR tree for a while-loop. + * Generate IR tree for a while-loop. Use BRA-nch instruction. */ static slang_ir_node * _slang_gen_while(slang_assemble_ctx * A, const slang_operation *oper) @@ -1313,7 +1336,7 @@ _slang_gen_while(slang_assemble_ctx * A, const slang_operation *oper) * label "__startWhile" * eval expr (child[0]), updating condcodes * branch if false to "__endWhile" - * code body + * body code * jump "__startWhile" * label "__endWhile" */ @@ -1354,6 +1377,51 @@ _slang_gen_while(slang_assemble_ctx * A, const slang_operation *oper) /** + * Generate IR tree for a while-loop using high-level BGNLOOP/ENDLOOP, + * IF/ENDIF instructions. + */ +static slang_ir_node * +_slang_gen_hl_while(slang_assemble_ctx * A, const slang_operation *oper) +{ + /* + * BGNLOOP + * eval expr (child[0]), updating condcodes + * IF !expr THEN + * BRK + * ENDIF + * body code + * ENDLOOP + */ + slang_ir_node *beginLoop, *endLoop, *ifThen, *endif; + slang_ir_node *brk, *cond, *body, *tree; + + beginLoop = new_begin_loop(); + + cond = _slang_gen_operation(A, &oper->children[0]); + cond = new_node(IR_NOT, cond, NULL); + cond = _slang_gen_cond(cond); + + ifThen = new_node(IR_IF, cond, NULL); + tree = new_seq(beginLoop, ifThen); + + brk = new_node(IR_BREAK, NULL, NULL); + tree = new_seq(tree, brk); + + endif = new_node(IR_ENDIF, NULL, NULL); + tree = new_seq(tree, endif); + + body = _slang_gen_operation(A, &oper->children[1]); + if (body) + tree = new_seq(tree, body); + + endLoop = new_end_loop(beginLoop); + tree = new_seq(tree, endLoop); + + return tree; +} + + +/** * Generate IR tree for a do-while-loop. */ static slang_ir_node * @@ -1517,7 +1585,7 @@ _slang_gen_if(slang_assemble_ctx * A, const slang_operation *oper) * IF/ELSE/ENDIF instructions */ static slang_ir_node * -_slang_gen_if2(slang_assemble_ctx * A, const slang_operation *oper) +_slang_gen_hl_if(slang_assemble_ctx * A, const slang_operation *oper) { /* * eval expr (child[0]), updating condcodes @@ -1529,6 +1597,10 @@ _slang_gen_if2(slang_assemble_ctx * A, const slang_operation *oper) * "false" code block * label "__endif" */ + /* XXX special cases to check for: + * if body of conditiona is just a "break", emit a conditional break + * instruction. + */ const GLboolean haveElseClause = !_slang_is_noop(&oper->children[2]); slang_ir_node *ifNode, *cond, *trueBody, *elseNode, *falseBody, *endifNode; slang_ir_node *tree; @@ -2261,7 +2333,10 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper) return _slang_gen_operation(A, &oper->children[0]); break; case slang_oper_while: - return _slang_gen_while(A, oper); + if (UseHighLevelInstructions) + return _slang_gen_hl_while(A, oper); + else + return _slang_gen_while(A, oper); case slang_oper_do: return _slang_gen_do(A, oper); case slang_oper_for: @@ -2427,8 +2502,9 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper) case slang_oper_identifier: return _slang_gen_variable(A, oper); case slang_oper_if: - if (A->program->Target == GL_FRAGMENT_PROGRAM_ARB) { - return _slang_gen_if(A, oper); + if (A->program->Target == GL_FRAGMENT_PROGRAM_ARB + && UseHighLevelInstructions) { + return _slang_gen_hl_if(A, oper); } else { /* XXX update tnl executor */ diff --git a/src/mesa/shader/slang/slang_emit.c b/src/mesa/shader/slang/slang_emit.c index 756bbe95879..311eea1e6ad 100644 --- a/src/mesa/shader/slang/slang_emit.c +++ b/src/mesa/shader/slang/slang_emit.c @@ -1006,6 +1006,42 @@ emit_cond(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog) /** + * Logical-NOT + */ +static struct prog_instruction * +emit_not(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog) +{ + GLfloat zero = 0.0; + slang_ir_storage st; + struct prog_instruction *inst; + + /* need zero constant */ + st.File = PROGRAM_CONSTANT; + st.Size = 1; + st.Index = _mesa_add_unnamed_constant(prog->Parameters, &zero, + 1, &st.Swizzle); + + /* child expr */ + (void) emit(vt, n->Children[0], prog); + /* XXXX if child instr is SGT convert to SLE, if SEQ, SNE, etc */ + + if (!n->Store) + if (!alloc_temp_storage(vt, n, n->Children[0]->Store->Size)) + return NULL; + + inst = new_instruction(prog, OPCODE_SEQ); + storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask); + storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store); + storage_to_src_reg(&inst->SrcReg[1], &st); + + free_temp_storage(vt, n->Children[0]); + + return inst; +} + + + +/** * Remove any SWIZZLE_NIL terms from given swizzle mask (smear prev term). * Ex: fix_swizzle("zyNN") -> "zyyy" */ @@ -1202,6 +1238,9 @@ emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog) case IR_COND: return emit_cond(vt, n, prog); + case IR_NOT: + return emit_not(vt, n, prog); + case IR_LABEL: return emit_label(n->Target, prog); case IR_JUMP: @@ -1235,6 +1274,39 @@ emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog) return inst; } + case IR_BEGIN_LOOP: + { + /* save location of this instruction, used by OPCODE_ENDLOOP */ + n->InstLocation = prog->NumInstructions; + (void) new_instruction(prog, OPCODE_BGNLOOP); + } + break; + case IR_END_LOOP: + { + struct prog_instruction *inst; + 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; + return inst; + } + case IR_CONT: + return new_instruction(prog, OPCODE_CONT); + case IR_BREAK: + { + struct prog_instruction *inst; + inst = new_instruction(prog, OPCODE_BRK); + inst->DstReg.CondMask = COND_TR; /* always true */ + return inst; + } + case IR_BEGIN_SUB: + return new_instruction(prog, OPCODE_BGNSUB); + case IR_END_SUB: + return new_instruction(prog, OPCODE_ENDSUB); + case IR_RETURN: + return new_instruction(prog, OPCODE_RET); + default: _mesa_problem(NULL, "Unexpected IR opcode in emit()\n"); abort(); diff --git a/src/mesa/shader/slang/slang_ir.h b/src/mesa/shader/slang/slang_ir.h index ac1ea4dbb4a..df5fc067790 100644 --- a/src/mesa/shader/slang/slang_ir.h +++ b/src/mesa/shader/slang/slang_ir.h @@ -150,6 +150,8 @@ typedef struct slang_ir_node_ GLfloat Value[4]; /**< If Opcode == IR_FLOAT */ slang_variable *Var; /**< If Opcode == IR_VAR or IR_VAR_DECL */ slang_ir_storage *Store; /**< location of result of this operation */ + GLint InstLocation; /**< Location of instruction emitted for this node */ + struct slang_ir_node_ *BranchNode; /**< Used for branch instructions */ } slang_ir_node; diff --git a/src/mesa/swrast/s_fragprog.c b/src/mesa/swrast/s_fragprog.c index 00231aeae8b..287dd9b1dbe 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; - GLuint pc, total = 0; + GLint pc, total = 0, loopDepth = 0; if (DEBUG_FRAG) { printf("execute fragment program --------------------\n"); @@ -642,7 +642,7 @@ execute_program( GLcontext *ctx, } if (DEBUG_FRAG) { - _mesa_print_instruction(inst); + _mesa_print_instruction(inst, 0); } switch (inst->Opcode) { @@ -676,8 +676,13 @@ 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; case OPCODE_BGNSUB: /* begin subroutine */ break; @@ -701,7 +706,19 @@ execute_program( GLcontext *ctx, } break; case OPCODE_BRK: /* break out of loop */ - /* assert inside 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); break; case OPCODE_CAL: /* Call subroutine */ { @@ -880,20 +897,25 @@ execute_program( GLcontext *ctx, /* do if-clause (just continue execution) */ } else { - /* do else-clause, or go to endif */ + /* search for else-clause or endif */ + /* XXX could encode location of the else/endif statement + * in the IF instruction to avoid searching... + */ GLint ifDepth = 1; do { pc++; inst = program->Base.Instructions + pc; if (inst->Opcode == OPCODE_END) { /* mal-formed program! */ - abort(); + _mesa_problem(ctx, "END found before ELSE/ENDIF"); + return GL_FALSE; } else if (inst->Opcode == OPCODE_IF) { + /* nested if */ ifDepth++; } else if (inst->Opcode == OPCODE_ELSE) { - if (ifDepth == 0) { + if (ifDepth == 1) { /* ok, continue normal execution */ break; } @@ -1335,6 +1357,10 @@ execute_program( GLcontext *ctx, result[2] = (a[2] > b[2]) ? 1.0F : 0.0F; result[3] = (a[3] > b[3]) ? 1.0F : 0.0F; store_vector4( inst, machine, result ); + if (DEBUG_FRAG) { + printf("SGT %g %g %g %g\n", + result[0], result[1], result[2], result[3]); + } } break; case OPCODE_SIN: diff --git a/src/mesa/tnl/t_vp_build.c b/src/mesa/tnl/t_vp_build.c index 47fed32904d..6fb14e7caa8 100644 --- a/src/mesa/tnl/t_vp_build.c +++ b/src/mesa/tnl/t_vp_build.c @@ -497,7 +497,7 @@ static void debug_insn( struct prog_instruction *inst, const char *fn, } _mesa_printf("%d:\t", line); - _mesa_print_instruction(inst); + _mesa_print_instruction(inst, 0); } } |