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.
This commit is contained in:
Brian
2007-02-05 15:00:07 -07:00
parent 5db088d70f
commit cf92c72797
5 changed files with 189 additions and 13 deletions

View File

@@ -47,6 +47,8 @@
#include "slang_print.h" #include "slang_print.h"
static GLboolean UseHighLevelInstructions = GL_TRUE;
static slang_ir_node * static slang_ir_node *
_slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper); _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[0] = left;
n->Children[1] = right; n->Children[1] = right;
n->Writemask = WRITEMASK_XYZW; n->Writemask = WRITEMASK_XYZW;
n->InstLocation = -1;
} }
return n; 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. * 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 * static slang_ir_node *
_slang_gen_while(slang_assemble_ctx * A, const slang_operation *oper) _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" * label "__startWhile"
* eval expr (child[0]), updating condcodes * eval expr (child[0]), updating condcodes
* branch if false to "__endWhile" * branch if false to "__endWhile"
* code body * body code
* jump "__startWhile" * jump "__startWhile"
* label "__endWhile" * label "__endWhile"
*/ */
@@ -1353,6 +1376,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. * Generate IR tree for a do-while-loop.
*/ */
@@ -1517,7 +1585,7 @@ _slang_gen_if(slang_assemble_ctx * A, const slang_operation *oper)
* IF/ELSE/ENDIF instructions * IF/ELSE/ENDIF instructions
*/ */
static slang_ir_node * 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 * eval expr (child[0]), updating condcodes
@@ -1529,6 +1597,10 @@ _slang_gen_if2(slang_assemble_ctx * A, const slang_operation *oper)
* "false" code block * "false" code block
* label "__endif" * 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]); const GLboolean haveElseClause = !_slang_is_noop(&oper->children[2]);
slang_ir_node *ifNode, *cond, *trueBody, *elseNode, *falseBody, *endifNode; slang_ir_node *ifNode, *cond, *trueBody, *elseNode, *falseBody, *endifNode;
slang_ir_node *tree; 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]); return _slang_gen_operation(A, &oper->children[0]);
break; break;
case slang_oper_while: 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: case slang_oper_do:
return _slang_gen_do(A, oper); return _slang_gen_do(A, oper);
case slang_oper_for: case slang_oper_for:
@@ -2427,8 +2502,9 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper)
case slang_oper_identifier: case slang_oper_identifier:
return _slang_gen_variable(A, oper); return _slang_gen_variable(A, oper);
case slang_oper_if: case slang_oper_if:
if (A->program->Target == GL_FRAGMENT_PROGRAM_ARB) { if (A->program->Target == GL_FRAGMENT_PROGRAM_ARB
return _slang_gen_if(A, oper); && UseHighLevelInstructions) {
return _slang_gen_hl_if(A, oper);
} }
else { else {
/* XXX update tnl executor */ /* XXX update tnl executor */

View File

@@ -1005,6 +1005,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). * Remove any SWIZZLE_NIL terms from given swizzle mask (smear prev term).
* Ex: fix_swizzle("zyNN") -> "zyyy" * 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: case IR_COND:
return emit_cond(vt, n, prog); return emit_cond(vt, n, prog);
case IR_NOT:
return emit_not(vt, n, prog);
case IR_LABEL: case IR_LABEL:
return emit_label(n->Target, prog); return emit_label(n->Target, prog);
case IR_JUMP: case IR_JUMP:
@@ -1235,6 +1274,39 @@ emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
return inst; 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: default:
_mesa_problem(NULL, "Unexpected IR opcode in emit()\n"); _mesa_problem(NULL, "Unexpected IR opcode in emit()\n");
abort(); abort();

View File

@@ -150,6 +150,8 @@ typedef struct slang_ir_node_
GLfloat Value[4]; /**< If Opcode == IR_FLOAT */ GLfloat Value[4]; /**< If Opcode == IR_FLOAT */
slang_variable *Var; /**< If Opcode == IR_VAR or IR_VAR_DECL */ slang_variable *Var; /**< If Opcode == IR_VAR or IR_VAR_DECL */
slang_ir_storage *Store; /**< location of result of this operation */ 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; } slang_ir_node;

View File

@@ -625,7 +625,7 @@ execute_program( GLcontext *ctx,
GLuint column ) GLuint column )
{ {
const GLuint MAX_EXEC = 10000; const GLuint MAX_EXEC = 10000;
GLuint pc, total = 0; GLint pc, total = 0, loopDepth = 0;
if (DEBUG_FRAG) { if (DEBUG_FRAG) {
printf("execute fragment program --------------------\n"); printf("execute fragment program --------------------\n");
@@ -642,7 +642,7 @@ execute_program( GLcontext *ctx,
} }
if (DEBUG_FRAG) { if (DEBUG_FRAG) {
_mesa_print_instruction(inst); _mesa_print_instruction(inst, 0);
} }
switch (inst->Opcode) { switch (inst->Opcode) {
@@ -676,8 +676,13 @@ execute_program( GLcontext *ctx,
} }
break; break;
case OPCODE_BGNLOOP: /* begin loop */ case OPCODE_BGNLOOP: /* begin loop */
loopDepth++;
break; break;
case OPCODE_ENDLOOP: /* end loop */ 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; break;
case OPCODE_BGNSUB: /* begin subroutine */ case OPCODE_BGNSUB: /* begin subroutine */
break; break;
@@ -701,7 +706,19 @@ execute_program( GLcontext *ctx,
} }
break; break;
case OPCODE_BRK: /* break out of loop */ 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; break;
case OPCODE_CAL: /* Call subroutine */ case OPCODE_CAL: /* Call subroutine */
{ {
@@ -880,20 +897,25 @@ execute_program( GLcontext *ctx,
/* do if-clause (just continue execution) */ /* do if-clause (just continue execution) */
} }
else { 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; GLint ifDepth = 1;
do { do {
pc++; pc++;
inst = program->Base.Instructions + pc; inst = program->Base.Instructions + pc;
if (inst->Opcode == OPCODE_END) { if (inst->Opcode == OPCODE_END) {
/* mal-formed program! */ /* mal-formed program! */
abort(); _mesa_problem(ctx, "END found before ELSE/ENDIF");
return GL_FALSE;
} }
else if (inst->Opcode == OPCODE_IF) { else if (inst->Opcode == OPCODE_IF) {
/* nested if */
ifDepth++; ifDepth++;
} }
else if (inst->Opcode == OPCODE_ELSE) { else if (inst->Opcode == OPCODE_ELSE) {
if (ifDepth == 0) { if (ifDepth == 1) {
/* ok, continue normal execution */ /* ok, continue normal execution */
break; break;
} }
@@ -1335,6 +1357,10 @@ execute_program( GLcontext *ctx,
result[2] = (a[2] > b[2]) ? 1.0F : 0.0F; result[2] = (a[2] > b[2]) ? 1.0F : 0.0F;
result[3] = (a[3] > b[3]) ? 1.0F : 0.0F; result[3] = (a[3] > b[3]) ? 1.0F : 0.0F;
store_vector4( inst, machine, result ); store_vector4( inst, machine, result );
if (DEBUG_FRAG) {
printf("SGT %g %g %g %g\n",
result[0], result[1], result[2], result[3]);
}
} }
break; break;
case OPCODE_SIN: case OPCODE_SIN:

View File

@@ -497,7 +497,7 @@ static void debug_insn( struct prog_instruction *inst, const char *fn,
} }
_mesa_printf("%d:\t", line); _mesa_printf("%d:\t", line);
_mesa_print_instruction(inst); _mesa_print_instruction(inst, 0);
} }
} }