From 5ae49cf3ed53fda6a904d7e90feef78495ae6903 Mon Sep 17 00:00:00 2001 From: Brian Date: Sat, 20 Jan 2007 09:27:40 -0700 Subject: [PATCH] Initial implementation of OPCODE_IF/ELSE/ENDIF instructions. --- src/mesa/shader/prog_instruction.c | 3 ++ src/mesa/shader/prog_instruction.h | 3 ++ src/mesa/shader/prog_print.c | 14 +++++- src/mesa/shader/slang/slang_codegen.c | 53 ++++++++++++++++++++- src/mesa/shader/slang/slang_emit.c | 37 +++++++++++++++ src/mesa/shader/slang/slang_ir.h | 3 ++ src/mesa/swrast/s_fragprog.c | 67 +++++++++++++++++++++++++++ src/mesa/tnl/t_vb_arbprogram.c | 5 +- 8 files changed, 182 insertions(+), 3 deletions(-) diff --git a/src/mesa/shader/prog_instruction.c b/src/mesa/shader/prog_instruction.c index 1379018d4ac..3de71b8b5d0 100644 --- a/src/mesa/shader/prog_instruction.c +++ b/src/mesa/shader/prog_instruction.c @@ -130,11 +130,14 @@ static const struct instruction_info InstInfo[MAX_OPCODE] = { { OPCODE_DP4, "DP4", 2 }, { OPCODE_DPH, "DPH", 2 }, { OPCODE_DST, "DST", 2 }, + { OPCODE_ELSE, "ELSE", 0 }, { OPCODE_END, "END", 0 }, + { OPCODE_ENDIF, "ENDIF", 0 }, { OPCODE_EX2, "EX2", 1 }, { OPCODE_EXP, "EXP", 1 }, { OPCODE_FLR, "FLR", 1 }, { OPCODE_FRC, "FRC", 1 }, + { OPCODE_IF, "IF", 0 }, { OPCODE_INT, "INT", 1 }, { OPCODE_KIL, "KIL", 1 }, { OPCODE_KIL_NV, "KIL", 0 }, diff --git a/src/mesa/shader/prog_instruction.h b/src/mesa/shader/prog_instruction.h index b6598796510..b1001885e0a 100644 --- a/src/mesa/shader/prog_instruction.h +++ b/src/mesa/shader/prog_instruction.h @@ -143,11 +143,14 @@ typedef enum prog_opcode { OPCODE_DP4, /* X X X X */ OPCODE_DPH, /* X X 1.1 */ OPCODE_DST, /* X X X X */ + OPCODE_ELSE, OPCODE_END, /* X X X X */ + OPCODE_ENDIF, OPCODE_EX2, /* X X 2 X */ OPCODE_EXP, /* X X */ OPCODE_FLR, /* X X 2 X */ OPCODE_FRC, /* X X 2 X */ + OPCODE_IF, OPCODE_INT, /* */ OPCODE_KIL, /* X */ OPCODE_KIL_NV, /* X */ diff --git a/src/mesa/shader/prog_print.c b/src/mesa/shader/prog_print.c index 04b7c7d22a2..78ce752f2a2 100644 --- a/src/mesa/shader/prog_print.c +++ b/src/mesa/shader/prog_print.c @@ -295,7 +295,7 @@ _mesa_print_instruction(const struct prog_instruction *inst) print_comment(inst); break; case OPCODE_BRA: - _mesa_printf("BRA %u (%s.%s)", + _mesa_printf("BRA %u (%s%s)", inst->BranchTarget, condcode_string(inst->DstReg.CondMask), swizzle_string(inst->DstReg.CondSwizzle, 0, GL_FALSE)); @@ -305,6 +305,18 @@ _mesa_print_instruction(const struct prog_instruction *inst) _mesa_printf("CAL %u", inst->BranchTarget); print_comment(inst); break; + case OPCODE_IF: + _mesa_printf(" IF (%s%s)", + condcode_string(inst->DstReg.CondMask), + swizzle_string(inst->DstReg.CondSwizzle, 0, GL_FALSE)); + print_comment(inst); + break; + case OPCODE_ELSE: + _mesa_printf(" ELSE;\n"); + break; + case OPCODE_ENDIF: + _mesa_printf(" ENDIF;\n"); + break; case OPCODE_END: _mesa_printf("END"); print_comment(inst); diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index 6923c00562a..aba6813a8b5 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -1560,6 +1560,51 @@ _slang_gen_if(slang_assemble_ctx * A, const slang_operation *oper) } +/** + * Use high-level IF/ELSE/ENDIF instructions + */ +static slang_ir_node * +_slang_gen_if2(slang_assemble_ctx * A, const slang_operation *oper) +{ + /* + * eval expr (child[0]), updating condcodes + * branch if false to _else or _endif + * "true" code block + * if haveElseClause clause: + * jump "__endif" + * label "__else" + * "false" code block + * label "__endif" + */ + const GLboolean haveElseClause = !_slang_is_noop(&oper->children[2]); + slang_ir_node *ifNode, *cond, *trueBody, *elseNode, *falseBody, *endifNode; + slang_ir_node *tree; + + cond = _slang_gen_operation(A, &oper->children[0]); + cond = _slang_gen_cond(cond); + /*assert(cond->Store);*/ + ifNode = new_node(IR_IF, cond, NULL); + + trueBody = _slang_gen_operation(A, &oper->children[1]); + tree = new_seq(ifNode, trueBody); + + if (haveElseClause) { + /* else clause */ + elseNode = new_node(IR_ELSE, NULL, NULL); + tree = new_seq(tree, elseNode); + + falseBody = _slang_gen_operation(A, &oper->children[2]); + tree = new_seq(tree, falseBody); + } + + endifNode = new_node(IR_ENDIF, NULL, NULL); + tree = new_seq(tree, endifNode); + + return tree; +} + + + /** * Generate IR node for storage of a temporary of given size. */ @@ -2314,7 +2359,13 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper) case slang_oper_identifier: return _slang_gen_variable(A, oper); case slang_oper_if: - return _slang_gen_if(A, oper); + if (A->program->Target == GL_FRAGMENT_PROGRAM_ARB) { + return _slang_gen_if(A, oper); + } + else { + /* XXX update tnl executor */ + return _slang_gen_if(A, oper); + } case slang_oper_field: return _slang_gen_field(A, oper); case slang_oper_subscript: diff --git a/src/mesa/shader/slang/slang_emit.c b/src/mesa/shader/slang/slang_emit.c index 6c31bfc677f..44fd3752e20 100644 --- a/src/mesa/shader/slang/slang_emit.c +++ b/src/mesa/shader/slang/slang_emit.c @@ -91,6 +91,9 @@ static slang_ir_info IrInfo[] = { { IR_JUMP, "IR_JUMP", 0, 0, 0 }, { IR_CJUMP0, "IR_CJUMP0", 0, 0, 0 }, { IR_CJUMP1, "IR_CJUMP1", 0, 0, 0 }, + { IR_IF, "IR_IF", 0, 0, 0 }, + { IR_ELSE, "IR_ELSE", 0, 0, 0 }, + { IR_ENDIF, "IR_ENDIF", 0, 0, 0 }, { IR_KILL, "IR_KILL", 0, 0, 0 }, { IR_COND, "IR_COND", 0, 0, 0 }, { IR_CALL, "IR_CALL", 0, 0, 0 }, @@ -271,6 +274,18 @@ slang_print_ir(const slang_ir_node *n, int indent) printf("CJUMP1 %s\n", n->Target); slang_print_ir(n->Children[0], indent+3); break; + + case IR_IF: + printf("IF \n"); + slang_print_ir(n->Children[0], indent+3); + break; + case IR_ELSE: + printf("ELSE\n"); + break; + case IR_ENDIF: + printf("ENDIF\n"); + break; + case IR_VAR: printf("VAR %s%s at %s store %p\n", (char *) n->Var->a_name, swizzle_string(n->Store->Swizzle), @@ -862,6 +877,28 @@ emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog) case IR_KILL: return emit_kill(prog); + case IR_IF: + { + struct prog_instruction *inst; + emit(vt, n->Children[0], prog); /* the condition */ + inst = new_instruction(prog, OPCODE_IF); + inst->DstReg.CondMask = COND_NE; /* if cond is non-zero */ + inst->DstReg.CondSwizzle = SWIZZLE_X; + return inst; + } + case IR_ELSE: + { + struct prog_instruction *inst; + inst = new_instruction(prog, OPCODE_ELSE); + return inst; + } + case IR_ENDIF: + { + struct prog_instruction *inst; + inst = new_instruction(prog, OPCODE_ENDIF); + return inst; + } + 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 4072c70f902..e5a0fa8eb5f 100644 --- a/src/mesa/shader/slang/slang_ir.h +++ b/src/mesa/shader/slang/slang_ir.h @@ -51,6 +51,9 @@ typedef enum IR_CJUMP0, /* conditional jump if zero */ IR_CJUMP1, /* conditional jump if one (or non-zero) */ IR_COND, /* conditional expression */ + IR_IF, /* high-level IF */ + IR_ELSE, /* high-level ELSE */ + IR_ENDIF, /* high-level ENDIF */ IR_CALL, /* call subroutine */ IR_MOVE, IR_ADD, diff --git a/src/mesa/swrast/s_fragprog.c b/src/mesa/swrast/s_fragprog.c index b842b49616c..813345f4cd1 100644 --- a/src/mesa/swrast/s_fragprog.c +++ b/src/mesa/swrast/s_fragprog.c @@ -888,6 +888,73 @@ execute_program( GLcontext *ctx, store_vector4( inst, machine, result ); } break; + case OPCODE_IF: + { + const GLuint swizzle = inst->DstReg.CondSwizzle; + const GLuint condMask = inst->DstReg.CondMask; + if (test_cc(machine->CondCodes[GET_SWZ(swizzle, 0)], condMask) || + test_cc(machine->CondCodes[GET_SWZ(swizzle, 1)], condMask) || + test_cc(machine->CondCodes[GET_SWZ(swizzle, 2)], condMask) || + test_cc(machine->CondCodes[GET_SWZ(swizzle, 3)], condMask)) { + /* do if-clause (just continue execution) */ + } + else { + /* do else-clause, or go to endif */ + GLint ifDepth = 1; + do { + pc++; + inst = program->Base.Instructions + pc; + if (inst->Opcode == OPCODE_END) { + /* mal-formed program! */ + abort(); + } + else if (inst->Opcode == OPCODE_IF) { + ifDepth++; + } + else if (inst->Opcode == OPCODE_ELSE) { + if (ifDepth == 0) { + /* ok, continue normal execution */ + break; + } + } + else if (inst->Opcode == OPCODE_ENDIF) { + ifDepth--; + if (ifDepth == 0) { + /* ok, continue normal execution */ + break; + } + } + assert(ifDepth >= 0); + } while (pc < maxInst); + } + } + break; + case OPCODE_ELSE: + { + /* find/goto ENDIF */ + GLint ifDepth = 1; + do { + pc++; + inst = program->Base.Instructions + pc; + if (inst->Opcode == OPCODE_END) { + /* mal-formed program! */ + abort(); + } + else if (inst->Opcode == OPCODE_IF) { + ifDepth++; + } + else if (inst->Opcode == OPCODE_ENDIF) { + ifDepth--; + if (ifDepth == 0) + break; + } + assert(ifDepth >= 0); + } while (pc < maxInst); + } + break; + case OPCODE_ENDIF: + /* nothing */ + break; case OPCODE_INT: /* float to int */ { GLfloat a[4], result[4]; diff --git a/src/mesa/tnl/t_vb_arbprogram.c b/src/mesa/tnl/t_vb_arbprogram.c index 5773f0f6270..5726a66c907 100644 --- a/src/mesa/tnl/t_vb_arbprogram.c +++ b/src/mesa/tnl/t_vb_arbprogram.c @@ -746,11 +746,14 @@ static void (* const opcode_func[MAX_OPCODE+3])(struct arb_vp_machine *, union i do_DP4, do_DPH, do_DST, - do_NOP, + do_NOP,/*ELSE*/ + do_NOP,/*END*/ + do_NOP,/*ENDIF*/ do_EX2, do_EXP, do_FLR, do_FRC, + do_NOP,/*IF*/ do_INT, do_NOP,/*KIL*/ do_NOP,/*KIL_NV*/ -- 2.30.2