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.
#include "slang_print.h"
+static GLboolean UseHighLevelInstructions = GL_TRUE;
+
static slang_ir_node *
_slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper);
n->Children[0] = left;
n->Children[1] = right;
n->Writemask = WRITEMASK_XYZW;
+ n->InstLocation = -1;
}
return n;
}
}
+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.
*/
/**
- * 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)
* label "__startWhile"
* eval expr (child[0]), updating condcodes
* branch if false to "__endWhile"
- * code body
+ * body code
* jump "__startWhile"
* label "__endWhile"
*/
}
+/**
+ * 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.
*/
* 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
* "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;
return _slang_gen_operation(A, &oper->children[0]);
break;
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:
return _slang_gen_do(A, oper);
case slang_oper_for:
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 */
}
+/**
+ * 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"
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:
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();
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;
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");
}
if (DEBUG_FRAG) {
- _mesa_print_instruction(inst);
+ _mesa_print_instruction(inst, 0);
}
switch (inst->Opcode) {
}
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;
}
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 */
{
/* 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;
}
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:
}
_mesa_printf("%d:\t", line);
- _mesa_print_instruction(inst);
+ _mesa_print_instruction(inst, 0);
}
}