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"
|
||||
|
||||
|
||||
static GLboolean UseHighLevelInstructions = GL_TRUE;
|
||||
|
||||
static slang_ir_node *
|
||||
_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[1] = right;
|
||||
n->Writemask = WRITEMASK_XYZW;
|
||||
n->InstLocation = -1;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
@@ -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 *
|
||||
_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"
|
||||
* eval expr (child[0]), updating condcodes
|
||||
* branch if false to "__endWhile"
|
||||
* code body
|
||||
* body code
|
||||
* jump "__startWhile"
|
||||
* 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.
|
||||
*/
|
||||
@@ -1517,7 +1585,7 @@ _slang_gen_if(slang_assemble_ctx * A, const slang_operation *oper)
|
||||
* IF/ELSE/ENDIF instructions
|
||||
*/
|
||||
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
|
||||
@@ -1529,6 +1597,10 @@ _slang_gen_if2(slang_assemble_ctx * A, const slang_operation *oper)
|
||||
* "false" code block
|
||||
* 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]);
|
||||
slang_ir_node *ifNode, *cond, *trueBody, *elseNode, *falseBody, *endifNode;
|
||||
slang_ir_node *tree;
|
||||
@@ -2261,6 +2333,9 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper)
|
||||
return _slang_gen_operation(A, &oper->children[0]);
|
||||
break;
|
||||
case slang_oper_while:
|
||||
if (UseHighLevelInstructions)
|
||||
return _slang_gen_hl_while(A, oper);
|
||||
else
|
||||
return _slang_gen_while(A, oper);
|
||||
case slang_oper_do:
|
||||
return _slang_gen_do(A, oper);
|
||||
@@ -2427,8 +2502,9 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper)
|
||||
case slang_oper_identifier:
|
||||
return _slang_gen_variable(A, oper);
|
||||
case slang_oper_if:
|
||||
if (A->program->Target == GL_FRAGMENT_PROGRAM_ARB) {
|
||||
return _slang_gen_if(A, oper);
|
||||
if (A->program->Target == GL_FRAGMENT_PROGRAM_ARB
|
||||
&& UseHighLevelInstructions) {
|
||||
return _slang_gen_hl_if(A, oper);
|
||||
}
|
||||
else {
|
||||
/* 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).
|
||||
* 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:
|
||||
return emit_cond(vt, n, prog);
|
||||
|
||||
case IR_NOT:
|
||||
return emit_not(vt, n, prog);
|
||||
|
||||
case IR_LABEL:
|
||||
return emit_label(n->Target, prog);
|
||||
case IR_JUMP:
|
||||
@@ -1235,6 +1274,39 @@ emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
|
||||
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:
|
||||
_mesa_problem(NULL, "Unexpected IR opcode in emit()\n");
|
||||
abort();
|
||||
|
@@ -150,6 +150,8 @@ typedef struct slang_ir_node_
|
||||
GLfloat Value[4]; /**< If Opcode == IR_FLOAT */
|
||||
slang_variable *Var; /**< If Opcode == IR_VAR or IR_VAR_DECL */
|
||||
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;
|
||||
|
||||
|
||||
|
@@ -625,7 +625,7 @@ execute_program( GLcontext *ctx,
|
||||
GLuint column )
|
||||
{
|
||||
const GLuint MAX_EXEC = 10000;
|
||||
GLuint pc, total = 0;
|
||||
GLint pc, total = 0, loopDepth = 0;
|
||||
|
||||
if (DEBUG_FRAG) {
|
||||
printf("execute fragment program --------------------\n");
|
||||
@@ -642,7 +642,7 @@ execute_program( GLcontext *ctx,
|
||||
}
|
||||
|
||||
if (DEBUG_FRAG) {
|
||||
_mesa_print_instruction(inst);
|
||||
_mesa_print_instruction(inst, 0);
|
||||
}
|
||||
|
||||
switch (inst->Opcode) {
|
||||
@@ -676,8 +676,13 @@ execute_program( GLcontext *ctx,
|
||||
}
|
||||
break;
|
||||
case OPCODE_BGNLOOP: /* begin loop */
|
||||
loopDepth++;
|
||||
break;
|
||||
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;
|
||||
case OPCODE_BGNSUB: /* begin subroutine */
|
||||
break;
|
||||
@@ -701,7 +706,19 @@ execute_program( GLcontext *ctx,
|
||||
}
|
||||
break;
|
||||
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;
|
||||
case OPCODE_CAL: /* Call subroutine */
|
||||
{
|
||||
@@ -880,20 +897,25 @@ execute_program( GLcontext *ctx,
|
||||
/* do if-clause (just continue execution) */
|
||||
}
|
||||
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;
|
||||
do {
|
||||
pc++;
|
||||
inst = program->Base.Instructions + pc;
|
||||
if (inst->Opcode == OPCODE_END) {
|
||||
/* mal-formed program! */
|
||||
abort();
|
||||
_mesa_problem(ctx, "END found before ELSE/ENDIF");
|
||||
return GL_FALSE;
|
||||
}
|
||||
else if (inst->Opcode == OPCODE_IF) {
|
||||
/* nested if */
|
||||
ifDepth++;
|
||||
}
|
||||
else if (inst->Opcode == OPCODE_ELSE) {
|
||||
if (ifDepth == 0) {
|
||||
if (ifDepth == 1) {
|
||||
/* ok, continue normal execution */
|
||||
break;
|
||||
}
|
||||
@@ -1335,6 +1357,10 @@ execute_program( GLcontext *ctx,
|
||||
result[2] = (a[2] > b[2]) ? 1.0F : 0.0F;
|
||||
result[3] = (a[3] > b[3]) ? 1.0F : 0.0F;
|
||||
store_vector4( inst, machine, result );
|
||||
if (DEBUG_FRAG) {
|
||||
printf("SGT %g %g %g %g\n",
|
||||
result[0], result[1], result[2], result[3]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OPCODE_SIN:
|
||||
|
@@ -497,7 +497,7 @@ static void debug_insn( struct prog_instruction *inst, const char *fn,
|
||||
}
|
||||
|
||||
_mesa_printf("%d:\t", line);
|
||||
_mesa_print_instruction(inst);
|
||||
_mesa_print_instruction(inst, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user