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:
@@ -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 */
|
||||||
|
@@ -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();
|
||||||
|
@@ -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;
|
||||||
|
|
||||||
|
|
||||||
|
@@ -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:
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user