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/shader/slang | |
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/shader/slang')
-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 |
3 files changed, 156 insertions, 6 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; |