mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-07 09:18:04 +02:00
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.
This commit is contained in:
parent
bf020d8d7f
commit
63556fa994
8 changed files with 176 additions and 51 deletions
|
|
@ -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 */
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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*/
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue