IR_LOOP now has two children: the body code, and the tail code.
Tail code is the "i++" part of a for-loop, or the expression at the end
of a "do {} while(expr);" loop.
"continue" translates into: "execute tail code; CONT;"
Also, the test for infinite do/while loops was incorrect.
return;
for (i = 0; i < 3; i++)
_slang_free_ir_tree(n->Children[i]);
- /* Do not free n->BranchNode since it's a child elsewhere */
+ /* Do not free n->List since it's a child elsewhere */
free(n);
#endif
}
assert(loopNode->Opcode == IR_LOOP);
if (n) {
/* insert this node at head of linked list */
- n->BranchNode = loopNode->BranchNode;
- loopNode->BranchNode = n;
+ n->List = loopNode->List;
+ loopNode->List = n;
}
return n;
}
n = new_node1(breakTrue ? IR_BREAK_IF_TRUE : IR_BREAK_IF_FALSE, cond);
if (n) {
/* insert this node at head of linked list */
- n->BranchNode = loopNode->BranchNode;
- loopNode->BranchNode = n;
+ n->List = loopNode->List;
+ loopNode->List = n;
}
return n;
}
n = new_node1(contTrue ? IR_CONT_IF_TRUE : IR_CONT_IF_FALSE, cond);
if (n) {
/* insert this node at head of linked list */
- n->BranchNode = loopNode->BranchNode;
- loopNode->BranchNode = n;
- }
- return n;
-}
-
-
-static slang_ir_node *
-new_cont(slang_ir_node *loopNode)
-{
- slang_ir_node *n = new_node0(IR_CONT);
- assert(loopNode);
- assert(loopNode->Opcode == IR_LOOP);
- if (n) {
- /* insert this node at head of linked list */
- n->BranchNode = loopNode->BranchNode;
- loopNode->BranchNode = n;
+ n->List = loopNode->List;
+ loopNode->List = n;
}
return n;
}
loop->Children[0] = new_seq(breakIf, body);
/* Do infinite loop detection */
- if (!loop->BranchNode && isConst && constTrue) {
+ /* loop->List is head of linked list of break/continue nodes */
+ if (!loop->List && isConst && constTrue) {
/* infinite loop detected */
A->CurLoop = prevLoop; /* clean-up */
slang_info_log_error(A->log, "Infinite loop detected!");
/*
* LOOP:
* body code (child[0])
- * BREAK if !expr (child[1])
+ * tail code:
+ * BREAK if !expr (child[1])
*/
- slang_ir_node *prevLoop, *loop, *cond, *breakIf, *body;
+ slang_ir_node *prevLoop, *loop, *cond;
GLboolean isConst, constTrue;
- /* Check if loop condition is a constant */
- isConst = _slang_is_constant_cond(&oper->children[0], &constTrue);
-
loop = new_loop(NULL);
/* save old, push new loop */
prevLoop = A->CurLoop;
A->CurLoop = loop;
- body = _slang_gen_operation(A, &oper->children[0]);
- cond = new_cond(_slang_gen_operation(A, &oper->children[1]));
+ /* loop body: */
+ loop->Children[0] = _slang_gen_operation(A, &oper->children[0]);
+
+ /* Check if loop condition is a constant */
+ isConst = _slang_is_constant_cond(&oper->children[1], &constTrue);
if (isConst && constTrue) {
- /* while(nonzero constant), no conditional break */
- breakIf = NULL;
+ /* do { } while(1) ==> no conditional break */
+ loop->Children[1] = NULL; /* no tail code */
}
else {
- breakIf = new_break_if(A->CurLoop, cond, GL_FALSE);
+ cond = new_cond(_slang_gen_operation(A, &oper->children[1]));
+ loop->Children[1] = new_break_if(A->CurLoop, cond, GL_FALSE);
}
- loop->Children[0] = new_seq(body, breakIf);
+
+ /* XXX we should do infinite loop detection, as above */
/* pop loop, restore prev */
A->CurLoop = prevLoop;
_slang_gen_for(slang_assemble_ctx * A, const slang_operation *oper)
{
/*
- * init (child[0])
+ * init code (child[0])
* LOOP:
* BREAK if !expr (child[1])
* body code (child[3])
- * incr code (child[2]) // XXX continue here
+ * tail code:
+ * incr code (child[2]) // XXX continue here
*/
slang_ir_node *prevLoop, *loop, *cond, *breakIf, *body, *init, *incr;
breakIf = new_break_if(A->CurLoop, cond, GL_FALSE);
body = _slang_gen_operation(A, &oper->children[3]);
incr = _slang_gen_operation(A, &oper->children[2]);
- loop->Children[0] = new_seq(breakIf,
- new_seq(body, incr));
+
+ loop->Children[0] = new_seq(breakIf, body);
+ loop->Children[1] = incr; /* tail code */
/* pop loop, restore prev */
A->CurLoop = prevLoop;
}
+static slang_ir_node *
+_slang_gen_continue(slang_assemble_ctx * A, const slang_operation *oper)
+{
+ slang_ir_node *n, *loopNode;
+ assert(oper->type == SLANG_OPER_CONTINUE);
+ loopNode = A->CurLoop;
+ assert(loopNode);
+ assert(loopNode->Opcode == IR_LOOP);
+ n = new_node0(IR_CONT);
+ if (n) {
+ n->Parent = loopNode;
+ /* insert this node at head of linked list */
+ n->List = loopNode->List;
+ loopNode->List = n;
+ }
+ return n;
+}
+
+
/**
* Determine if the given operation is of a specific type.
*/
if (!A->CurLoop) {
slang_info_log_error(A->log, "'continue' not in loop");
}
- return new_cont(A->CurLoop);
+ return _slang_gen_continue(A, oper);
case SLANG_OPER_DISCARD:
return new_node0(IR_KILL);
printf("ELSE\n");
slang_print_ir(n->Children[2], indent+3);
}
+ spaces(indent);
printf("ENDIF\n");
break;
case IR_LOOP:
printf("LOOP\n");
slang_print_ir(n->Children[0], indent+3);
+ if (n->Children[1]) {
+ spaces(indent);
+ printf("TAIL:\n");
+ slang_print_ir(n->Children[1], indent+3);
+ }
spaces(indent);
printf("ENDLOOP\n");
break;
}
+/**
+ * Emit an instruction that's just a comment.
+ */
+static struct prog_instruction *
+emit_comment(slang_emit_info *emitInfo, const char *s)
+{
+ struct prog_instruction *inst = new_instruction(emitInfo, OPCODE_NOP);
+ if (inst) {
+ inst->Comment = _mesa_strdup(s);
+ }
+ return inst;
+}
+
/**
* Generate code for a simple arithmetic instruction.
emit_label(slang_emit_info *emitInfo, const slang_ir_node *n)
{
assert(n->Label);
+#if 0
+ /* XXX this fails in loop tail code - investigate someday */
assert(_slang_label_get_location(n->Label) < 0);
_slang_label_set_location(n->Label, emitInfo->prog->NumInstructions,
emitInfo->prog);
+#else
+ if (_slang_label_get_location(n->Label) < 0)
+ _slang_label_set_location(n->Label, emitInfo->prog->NumInstructions,
+ emitInfo->prog);
+#endif
return NULL;
}
assert(n->Children[1]->Store->Index >= 0);
+#if 0
assert(!n->Store);
+#endif
n->Store = n->Children[0]->Store;
#if PEEPHOLE_OPTIMIZATIONS
{
struct gl_program *prog = emitInfo->prog;
struct prog_instruction *beginInst, *endInst;
- GLuint beginInstLoc, endInstLoc;
+ GLuint beginInstLoc, tailInstLoc, endInstLoc;
slang_ir_node *ir;
+ slang_print_ir(n, 10);
+
/* emit OPCODE_BGNLOOP */
beginInstLoc = prog->NumInstructions;
if (emitInfo->EmitHighLevelInstructions) {
/* body */
emit(emitInfo, n->Children[0]);
+ /* tail */
+ tailInstLoc = prog->NumInstructions;
+ if (n->Children[1]) {
+ if (emitInfo->EmitComments)
+ emit_comment(emitInfo, "Loop tail code:");
+ emit(emitInfo, n->Children[1]);
+ }
+
endInstLoc = prog->NumInstructions;
if (emitInfo->EmitHighLevelInstructions) {
/* emit OPCODE_ENDLOOP */
endInst = new_instruction(emitInfo, OPCODE_BRA);
endInst->DstReg.CondMask = COND_TR; /* always true */
}
- /* end instruction's BranchTarget points to top of loop */
+ /* ENDLOOP's BranchTarget points to the BGNLOOP inst */
endInst->BranchTarget = beginInstLoc;
if (emitInfo->EmitHighLevelInstructions) {
* BREAK and CONT nodes, filling in their BranchTarget fields (which
* will point to the ENDLOOP+1 or BGNLOOP instructions, respectively).
*/
- for (ir = n->BranchNode; ir; ir = ir->BranchNode) {
+ for (ir = n->List; ir; ir = ir->List) {
struct prog_instruction *inst = prog->Instructions + ir->InstLocation;
assert(inst->BranchTarget < 0);
if (ir->Opcode == IR_BREAK ||
inst->Opcode == OPCODE_CONT0 ||
inst->Opcode == OPCODE_CONT1 ||
inst->Opcode == OPCODE_BRA);
- /* to go instruction at top of loop */
- inst->BranchTarget = beginInstLoc;
+ /* go to instruction at tail of loop */
+ inst->BranchTarget = endInstLoc;
}
}
return NULL;
{
gl_inst_opcode opcode;
struct prog_instruction *inst;
- n->InstLocation = emitInfo->prog->NumInstructions;
+
+ if (n->Opcode == IR_CONT) {
+ /* we need to execute the loop's tail code before doing CONT */
+ assert(n->Parent);
+ assert(n->Parent->Opcode == IR_LOOP);
+ if (n->Parent->Children[1]) {
+ /* emit tail code */
+ if (emitInfo->EmitComments) {
+ emit_comment(emitInfo, "continue - tail code:");
+ }
+ emit(emitInfo, n->Parent->Children[1]);
+ }
+ }
+
+ /* opcode selection */
if (emitInfo->EmitHighLevelInstructions) {
opcode = (n->Opcode == IR_CONT) ? OPCODE_CONT : OPCODE_BRK;
}
else {
opcode = OPCODE_BRA;
}
+ n->InstLocation = emitInfo->prog->NumInstructions;
inst = new_instruction(emitInfo, opcode);
inst->DstReg.CondMask = COND_TR; /* always true */
return inst;
inst->DstReg.CondMask = breakTrue ? COND_NE : COND_EQ;
}
else {
- /* BRK0, BRK1, CONT0, CONT1 */
+ /* BRK0, BRK1, CONT0, CONT1 uses SrcReg[0] as the condition */
storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store);
}
return inst;
assert(n->Children[1]);
emit(emitInfo, n->Children[0]);
inst = emit(emitInfo, n->Children[1]);
+#if 0
assert(!n->Store);
+#endif
n->Store = n->Children[1]->Store;
return inst;
assert(n->Store);
assert(n->Store->File != PROGRAM_UNDEFINED);
assert(n->Store->Size > 0);
- assert(n->Store->Index < 0);
+ /*assert(n->Store->Index < 0);*/
if (!n->Var || n->Var->isTemp) {
/* a nameless/temporary variable, will be freed after first use */
- if (!_slang_alloc_temp(emitInfo->vt, n->Store)) {
+ /*NEW*/
+ if (n->Store->Index < 0 && !_slang_alloc_temp(emitInfo->vt, n->Store)) {
slang_info_log_error(emitInfo->log,
"Ran out of registers, too many temporaries");
return NULL;
_mesa_swizzle_string(n->Store->Swizzle, 0, GL_FALSE),
(n->Var ? (char *) n->Var->a_name : "anonymous"),
n->Store->Size);
- inst = new_instruction(emitInfo, OPCODE_NOP);
- inst->Comment = _mesa_strdup(s);
+ inst = emit_comment(emitInfo, s);
return inst;
}
return NULL;
emitInfo.EmitHighLevelInstructions = ctx->Shader.EmitHighLevelInstructions;
emitInfo.EmitCondCodes = 0; /* XXX temporary! */
- emitInfo.EmitComments = ctx->Shader.EmitComments;
+ emitInfo.EmitComments = 1 + ctx->Shader.EmitComments;
(void) emit(&emitInfo, n);
IR_COND, /* conditional expression/predicate */
IR_IF, /* high-level IF/then/else */
+ /* Children[0] = conditional expression */
+ /* Children[1] = if-true part */
+ /* Children[2] = if-else part, or NULL */
IR_BEGIN_SUB, /* begin subroutine */
IR_END_SUB, /* end subroutine */
IR_CALL, /* call subroutine */
IR_LOOP, /* high-level loop-begin / loop-end */
+ /* Children[0] = loop body */
+ /* Children[1] = loop tail code, or NULL */
+
IR_CONT, /* continue loop */
+ /* n->Parent = ptr to parent IR_LOOP Node */
IR_BREAK, /* break loop */
IR_BREAK_IF_TRUE,
IR_BREAK_IF_FALSE,
IR_CONT_IF_TRUE,
IR_CONT_IF_FALSE,
+ /* Children[0] = the condition expression */
IR_MOVE,
GLuint Writemask; /**< If Opcode == IR_MOVE */
GLfloat Value[4]; /**< If Opcode == IR_FLOAT */
slang_variable *Var; /**< If Opcode == IR_VAR or IR_VAR_DECL */
- struct slang_ir_node_ *BranchNode; /**< Used for branching instructions */
+ struct slang_ir_node_ *List; /**< For various linked lists */
+ struct slang_ir_node_ *Parent; /**< Pointer to logical parent (ie. loop) */
slang_label *Label; /**< Used for branches */
} slang_ir_node;