From 63556fa9949f543a8134b6b5ff3d216acb71dd9f Mon Sep 17 00:00:00 2001 From: Brian Date: Fri, 23 Mar 2007 14:47:46 -0600 Subject: [PATCH] Add the ability to generate programs that doesn't use condition codes. ctx->Shader.EmitCondCodes determines if we use condition codes. If not, IF statement uses first operand's X component as the condition. Added OPCODE_BRK0, OPCODE_BRK1, OPCODE_CONT0, OPCODE_CONT1 to handle the common cases of conditional break/continue. --- src/mesa/main/mtypes.h | 6 +- src/mesa/shader/prog_execute.c | 53 +++++++++++-- src/mesa/shader/prog_instruction.c | 6 +- src/mesa/shader/prog_instruction.h | 4 + src/mesa/shader/prog_print.c | 30 ++++++- src/mesa/shader/shader_api.c | 1 + src/mesa/shader/slang/slang_emit.c | 123 ++++++++++++++++++++--------- src/mesa/tnl/t_vb_arbprogram.c | 4 + 8 files changed, 176 insertions(+), 51 deletions(-) diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index 0c9bf200d8c..828b0f2384e 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -2127,8 +2127,10 @@ struct gl_shader_program struct gl_shader_state { struct gl_shader_program *CurrentProgram; /**< The user-bound program */ - GLboolean EmitHighLevelInstructions; /**< Driver-selectable */ - GLboolean EmitComments; /**< Driver-selectable */ + /** Driver-selectable options: */ + GLboolean EmitHighLevelInstructions; /**< IF/ELSE/ENDIF vs. BRA, etc. */ + GLboolean EmitCondCodes; /**< Use condition codes? */ + GLboolean EmitComments; /**< Annotated instructions */ }; diff --git a/src/mesa/shader/prog_execute.c b/src/mesa/shader/prog_execute.c index 092c07f7b65..f881d477caa 100644 --- a/src/mesa/shader/prog_execute.c +++ b/src/mesa/shader/prog_execute.c @@ -720,6 +720,32 @@ _mesa_execute_program(GLcontext * ctx, pc = inst->BranchTarget - 1; } break; + case OPCODE_BRK0: /* Break if zero */ + /* fall-through */ + case OPCODE_CONT0: /* Continue if zero */ + { + GLfloat a[4]; + fetch_vector1(&inst->SrcReg[0], machine, a); + if (a[0] == 0.0) { + /* take branch */ + /* Subtract 1 here since we'll do pc++ at end of for-loop */ + pc = inst->BranchTarget - 1; + } + } + break; + case OPCODE_BRK1: /* Break if non-zero */ + /* fall-through */ + case OPCODE_CONT1: /* Continue if non-zero */ + { + GLfloat a[4]; + fetch_vector1(&inst->SrcReg[0], machine, a); + if (a[0] != 0.0) { + /* take branch */ + /* Subtract 1 here since we'll do pc++ at end of for-loop */ + pc = inst->BranchTarget - 1; + } + } + break; case OPCODE_CAL: /* Call subroutine (conditional) */ if (eval_condition(machine, inst)) { /* call the subroutine */ @@ -914,13 +940,26 @@ _mesa_execute_program(GLcontext * ctx, } break; case OPCODE_IF: - if (eval_condition(machine, inst)) { - /* do if-clause (just continue execution) */ - } - else { - /* go to the instruction after ELSE or ENDIF */ - assert(inst->BranchTarget >= 0); - pc = inst->BranchTarget - 1; + { + GLboolean cond; + /* eval condition */ + if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) { + GLfloat a[4]; + fetch_vector1(&inst->SrcReg[0], machine, a); + cond = (a[0] != 0.0); + } + else { + cond = eval_condition(machine, inst); + } + /* do if/else */ + if (cond) { + /* do if-clause (just continue execution) */ + } + else { + /* go to the instruction after ELSE or ENDIF */ + assert(inst->BranchTarget >= 0); + pc = inst->BranchTarget - 1; + } } break; case OPCODE_ELSE: diff --git a/src/mesa/shader/prog_instruction.c b/src/mesa/shader/prog_instruction.c index ed479a7f614..272caf6c746 100644 --- a/src/mesa/shader/prog_instruction.c +++ b/src/mesa/shader/prog_instruction.c @@ -138,9 +138,13 @@ static const struct instruction_info InstInfo[MAX_OPCODE] = { { OPCODE_BGNSUB, "BGNSUB", 0 }, { OPCODE_BRA, "BRA", 0 }, { OPCODE_BRK, "BRK", 0 }, + { OPCODE_BRK0, "BRK0", 1 }, + { OPCODE_BRK1, "BRK1", 1 }, { OPCODE_CAL, "CAL", 0 }, { OPCODE_CMP, "CMP", 3 }, - { OPCODE_CONT, "CONT", 1 }, + { OPCODE_CONT, "CONT", 0 }, + { OPCODE_CONT0, "CONT0", 1 }, + { OPCODE_CONT1, "CONT1", 1 }, { OPCODE_COS, "COS", 1 }, { OPCODE_DDX, "DDX", 1 }, { OPCODE_DDY, "DDY", 1 }, diff --git a/src/mesa/shader/prog_instruction.h b/src/mesa/shader/prog_instruction.h index c800757aa0f..dc2d2dc29b4 100644 --- a/src/mesa/shader/prog_instruction.h +++ b/src/mesa/shader/prog_instruction.h @@ -153,9 +153,13 @@ typedef enum prog_opcode { OPCODE_BGNSUB, /* opt */ OPCODE_BRA, /* 2 X */ OPCODE_BRK, /* 2 opt */ + OPCODE_BRK0, /* opt */ + OPCODE_BRK1, /* opt */ OPCODE_CAL, /* 2 2 */ OPCODE_CMP, /* X */ OPCODE_CONT, /* opt */ + OPCODE_CONT0, /* opt */ + OPCODE_CONT1, /* opt */ OPCODE_COS, /* X 2 X X */ OPCODE_DDX, /* X X */ OPCODE_DDY, /* X X */ diff --git a/src/mesa/shader/prog_print.c b/src/mesa/shader/prog_print.c index d290ce0a2a5..39d2a07812e 100644 --- a/src/mesa/shader/prog_print.c +++ b/src/mesa/shader/prog_print.c @@ -572,10 +572,20 @@ _mesa_print_instruction_opt(const struct prog_instruction *inst, GLint indent, print_comment(inst); break; case OPCODE_IF: - _mesa_printf("IF (%s%s); # (if false, goto %d)", - condcode_string(inst->DstReg.CondMask), - _mesa_swizzle_string(inst->DstReg.CondSwizzle, 0, GL_FALSE), - inst->BranchTarget); + if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) { + /* Use ordinary register */ + _mesa_printf("IF "); + print_src_reg(&inst->SrcReg[0], mode, prog); + _mesa_printf("; "); + } + else { + /* Use cond codes */ + _mesa_printf("IF (%s%s);", + condcode_string(inst->DstReg.CondMask), + _mesa_swizzle_string(inst->DstReg.CondSwizzle, + 0, GL_FALSE)); + } + _mesa_printf(" # (if false, goto %d)", inst->BranchTarget); print_comment(inst); return indent + 3; case OPCODE_ELSE: @@ -604,6 +614,18 @@ _mesa_print_instruction_opt(const struct prog_instruction *inst, GLint indent, inst->BranchTarget); print_comment(inst); break; + + case OPCODE_BRK0: + case OPCODE_BRK1: + case OPCODE_CONT0: + case OPCODE_CONT1: + _mesa_printf("%s ", _mesa_opcode_string(inst->Opcode)); + print_src_reg(&inst->SrcReg[0], mode, prog); + _mesa_printf("; "); + _mesa_printf(" # (goto %d)", inst->BranchTarget); + print_comment(inst); + break; + case OPCODE_BGNSUB: _mesa_printf("SUB"); print_comment(inst); diff --git a/src/mesa/shader/shader_api.c b/src/mesa/shader/shader_api.c index aab522e292c..88aa8c50f5b 100644 --- a/src/mesa/shader/shader_api.c +++ b/src/mesa/shader/shader_api.c @@ -206,6 +206,7 @@ _mesa_init_shader_state(GLcontext * ctx) * are generated by the GLSL compiler. */ ctx->Shader.EmitHighLevelInstructions = GL_TRUE; + ctx->Shader.EmitCondCodes = GL_TRUE; /* XXX probably want GL_FALSE... */ ctx->Shader.EmitComments = GL_FALSE; } diff --git a/src/mesa/shader/slang/slang_emit.c b/src/mesa/shader/slang/slang_emit.c index 16a054b35e5..9e476b8a0fa 100644 --- a/src/mesa/shader/slang/slang_emit.c +++ b/src/mesa/shader/slang/slang_emit.c @@ -61,6 +61,7 @@ typedef struct struct gl_program *prog; /* code-gen options */ GLboolean EmitHighLevelInstructions; + GLboolean EmitCondCodes; GLboolean EmitComments; } slang_emit_info; @@ -1155,10 +1156,6 @@ emit_move(slang_emit_info *emitInfo, slang_ir_node *n) static struct prog_instruction * emit_cond(slang_emit_info *emitInfo, slang_ir_node *n) { - /* Conditional expression (in if/while/for stmts). - * Need to update condition code register. - * Next instruction is typically an IR_IF. - */ struct prog_instruction *inst; if (!n->Children[0]) @@ -1166,28 +1163,39 @@ emit_cond(slang_emit_info *emitInfo, slang_ir_node *n) inst = emit(emitInfo, n->Children[0]); - if (inst) { - /* set inst's CondUpdate flag */ - inst->CondUpdate = GL_TRUE; - n->Store = n->Children[0]->Store; - return inst; /* XXX or null? */ + if (emitInfo->EmitCondCodes) { + /* Conditional expression (in if/while/for stmts). + * Need to update condition code register. + * Next instruction is typically an IR_IF. + */ + if (inst) { + /* set inst's CondUpdate flag */ + inst->CondUpdate = GL_TRUE; + n->Store = n->Children[0]->Store; + return inst; /* XXX or null? */ + } + else { + /* This'll happen for things like "if (i) ..." where no code + * is normally generated for the expression "i". + * Generate a move instruction just to set condition codes. + * Note: must use full 4-component vector since all four + * condition codes must be set identically. + */ + if (!alloc_temp_storage(emitInfo, n, 4)) + return NULL; + inst = new_instruction(emitInfo, OPCODE_MOV); + inst->CondUpdate = GL_TRUE; + storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask); + storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store); + _slang_free_temp(emitInfo->vt, n->Store); + inst->Comment = _mesa_strdup("COND expr"); + return inst; /* XXX or null? */ + } } else { - /* This'll happen for things like "if (i) ..." where no code - * is normally generated for the expression "i". - * Generate a move instruction just to set condition codes. - * Note: must use full 4-component vector since all four - * condition codes must be set identically. - */ - if (!alloc_temp_storage(emitInfo, n, 4)) - return NULL; - inst = new_instruction(emitInfo, OPCODE_MOV); - inst->CondUpdate = GL_TRUE; - storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask); - storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store); - _slang_free_temp(emitInfo->vt, n->Store); - inst->Comment = _mesa_strdup("COND expr"); - return inst; /* XXX or null? */ + /* No-op */ + n->Store = n->Children[0]->Store; + return NULL; } } @@ -1244,7 +1252,13 @@ emit_if(slang_emit_info *emitInfo, slang_ir_node *n) ifInstLoc = prog->NumInstructions; if (emitInfo->EmitHighLevelInstructions) { ifInst = new_instruction(emitInfo, OPCODE_IF); - ifInst->DstReg.CondMask = COND_NE; /* if cond is non-zero */ + if (emitInfo->EmitCondCodes) { + ifInst->DstReg.CondMask = COND_NE; /* if cond is non-zero */ + } + else { + /* test reg.x */ + storage_to_src_reg(&ifInst->SrcReg[0], n->Children[0]->Store); + } } else { /* conditional jump to else, or endif */ @@ -1252,8 +1266,10 @@ emit_if(slang_emit_info *emitInfo, slang_ir_node *n) ifInst->DstReg.CondMask = COND_EQ; /* BRA if cond is zero */ ifInst->Comment = _mesa_strdup("if zero"); } - /* which condition code to use: */ - ifInst->DstReg.CondSwizzle = n->Children[0]->Store->Swizzle; + if (emitInfo->EmitCondCodes) { + /* which condition code to use: */ + ifInst->DstReg.CondSwizzle = n->Children[0]->Store->Swizzle; + } /* if body */ emit(emitInfo, n->Children[1]); @@ -1342,6 +1358,8 @@ emit_loop(slang_emit_info *emitInfo, slang_ir_node *n) ir->Opcode == IR_BREAK_IF_FALSE || ir->Opcode == IR_BREAK_IF_TRUE) { assert(inst->Opcode == OPCODE_BRK || + inst->Opcode == OPCODE_BRK0 || + inst->Opcode == OPCODE_BRK1 || inst->Opcode == OPCODE_BRA); /* go to instruction after end of loop */ inst->BranchTarget = endInstLoc + 1; @@ -1351,6 +1369,8 @@ emit_loop(slang_emit_info *emitInfo, slang_ir_node *n) ir->Opcode == IR_CONT_IF_FALSE || ir->Opcode == IR_CONT_IF_TRUE); assert(inst->Opcode == OPCODE_CONT || + inst->Opcode == OPCODE_CONT0 || + inst->Opcode == OPCODE_CONT1 || inst->Opcode == OPCODE_BRA); /* to go instruction at top of loop */ inst->BranchTarget = beginInstLoc; @@ -1361,7 +1381,7 @@ emit_loop(slang_emit_info *emitInfo, slang_ir_node *n) /** - * "Continue" or "break" statement. + * Unconditional "continue" or "break" statement. * Either OPCODE_CONT, OPCODE_BRK or OPCODE_BRA will be emitted. */ static struct prog_instruction * @@ -1393,24 +1413,52 @@ emit_cont_break_if(slang_emit_info *emitInfo, slang_ir_node *n, gl_inst_opcode opcode; struct prog_instruction *inst; + assert(n->Opcode == IR_CONT_IF_TRUE || + n->Opcode == IR_CONT_IF_FALSE || + n->Opcode == IR_BREAK_IF_TRUE || + n->Opcode == IR_BREAK_IF_FALSE); + /* evaluate condition expr, setting cond codes */ inst = emit(emitInfo, n->Children[0]); - assert(inst); - inst->CondUpdate = GL_TRUE; + if (emitInfo->EmitCondCodes) { + assert(inst); + inst->CondUpdate = GL_TRUE; + } n->InstLocation = emitInfo->prog->NumInstructions; + + /* opcode selection */ if (emitInfo->EmitHighLevelInstructions) { - if (n->Opcode == IR_CONT_IF_TRUE || - n->Opcode == IR_CONT_IF_FALSE) - opcode = OPCODE_CONT; - else - opcode = OPCODE_BRK; + if (emitInfo->EmitCondCodes) { + if (n->Opcode == IR_CONT_IF_TRUE || + n->Opcode == IR_CONT_IF_FALSE) + opcode = OPCODE_CONT; + else + opcode = OPCODE_BRK; + } + else { + if (n->Opcode == IR_CONT_IF_TRUE) + opcode = OPCODE_CONT1; + else if (n->Opcode == IR_CONT_IF_FALSE) + opcode = OPCODE_CONT0; + else if (n->Opcode == IR_BREAK_IF_TRUE) + opcode = OPCODE_BRK1; + else if (n->Opcode == IR_BREAK_IF_FALSE) + opcode = OPCODE_BRK0; + } } else { opcode = OPCODE_BRA; } + inst = new_instruction(emitInfo, opcode); - inst->DstReg.CondMask = breakTrue ? COND_NE : COND_EQ; + if (emitInfo->EmitCondCodes) { + inst->DstReg.CondMask = breakTrue ? COND_NE : COND_EQ; + } + else { + /* BRK0, BRK1, CONT0, CONT1 */ + storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store); + } return inst; } @@ -1779,7 +1827,8 @@ _slang_emit_code(slang_ir_node *n, slang_var_table *vt, emitInfo.prog = prog; emitInfo.EmitHighLevelInstructions = ctx->Shader.EmitHighLevelInstructions; - emitInfo.EmitComments = 1+ctx->Shader.EmitComments; + emitInfo.EmitCondCodes = 0; /* XXX temporary! */ + emitInfo.EmitComments = ctx->Shader.EmitComments; (void) emit(&emitInfo, n); diff --git a/src/mesa/tnl/t_vb_arbprogram.c b/src/mesa/tnl/t_vb_arbprogram.c index b322d48b231..425a8669948 100644 --- a/src/mesa/tnl/t_vb_arbprogram.c +++ b/src/mesa/tnl/t_vb_arbprogram.c @@ -741,9 +741,13 @@ static gpu_function opcode_func[MAX_OPCODE+3] = do_NOP,/*BGNSUB*/ do_NOP,/*BRA*/ do_NOP,/*BRK*/ + do_NOP,/*BRK0*/ + do_NOP,/*BRK1*/ do_NOP,/*CAL*/ do_NOP,/*CMP*/ do_NOP,/*CONT*/ + do_NOP,/*CONT0*/ + do_NOP,/*CONT1*/ do_NOP,/*COS*/ do_NOP,/*DDX*/ do_NOP,/*DDY*/ -- 2.30.2