Use conditional break in for/do/while loops.
This commit is contained in:
@@ -616,6 +616,21 @@ new_break(slang_ir_node *loopNode)
|
||||
}
|
||||
|
||||
|
||||
static slang_ir_node *
|
||||
new_break_if_false(slang_ir_node *loopNode, slang_ir_node *cond)
|
||||
{
|
||||
slang_ir_node *n = new_node1(IR_BREAK_IF_FALSE, cond);
|
||||
assert(loopNode);
|
||||
assert(loopNode->Opcode == IR_LOOP);
|
||||
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)
|
||||
{
|
||||
@@ -631,6 +646,14 @@ new_cont(slang_ir_node *loopNode)
|
||||
}
|
||||
|
||||
|
||||
static slang_ir_node *
|
||||
new_cond(slang_ir_node *n)
|
||||
{
|
||||
slang_ir_node *c = new_node1(IR_COND, n);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
static slang_ir_node *
|
||||
new_if(slang_ir_node *cond, slang_ir_node *ifPart, slang_ir_node *elsePart)
|
||||
{
|
||||
@@ -1290,14 +1313,6 @@ _slang_is_noop(const slang_operation *oper)
|
||||
}
|
||||
|
||||
|
||||
static slang_ir_node *
|
||||
_slang_gen_cond(slang_ir_node *n)
|
||||
{
|
||||
slang_ir_node *c = new_node1(IR_COND, n);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
print_funcs(struct slang_function_scope_ *scope, const char *name)
|
||||
{
|
||||
@@ -1381,12 +1396,10 @@ _slang_gen_while(slang_assemble_ctx * A, const slang_operation *oper)
|
||||
slang_ir_node *prevLoop;
|
||||
/*
|
||||
* LOOP:
|
||||
* eval expr (child[0]), updating condcodes
|
||||
* IF !expr:
|
||||
* BRK
|
||||
* BREAK if !expr (child[0])
|
||||
* body code (child[1])
|
||||
*/
|
||||
slang_ir_node *ifThen, *cond, *body, *loop;
|
||||
slang_ir_node *loop, *cond, *breakIf, *body;
|
||||
|
||||
loop = new_loop(NULL);
|
||||
|
||||
@@ -1395,19 +1408,12 @@ _slang_gen_while(slang_assemble_ctx * A, const slang_operation *oper)
|
||||
A->CurLoop = loop;
|
||||
|
||||
cond = _slang_gen_operation(A, &oper->children[0]);
|
||||
cond = new_node1(IR_NOT, cond);
|
||||
cond = _slang_gen_cond(cond);
|
||||
|
||||
ifThen = new_if(cond,
|
||||
new_break(A->CurLoop),
|
||||
NULL);
|
||||
|
||||
breakIf = new_break_if_false(A->CurLoop, cond);
|
||||
body = _slang_gen_operation(A, &oper->children[1]);
|
||||
loop->Children[0] = new_seq(breakIf, body);
|
||||
|
||||
loop->Children[0] = new_seq(ifThen, body);
|
||||
|
||||
|
||||
A->CurLoop = prevLoop; /* pop loop, restore prev */
|
||||
/* pop loop, restore prev */
|
||||
A->CurLoop = prevLoop;
|
||||
|
||||
return loop;
|
||||
}
|
||||
@@ -1423,11 +1429,9 @@ _slang_gen_do(slang_assemble_ctx * A, const slang_operation *oper)
|
||||
/*
|
||||
* LOOP:
|
||||
* body code (child[0])
|
||||
* eval expr (child[1]), updating condcodes
|
||||
* IF !expr:
|
||||
* BRK
|
||||
* BREAK if !expr (child[1])
|
||||
*/
|
||||
slang_ir_node *ifThen, *cond, *body, *loop;
|
||||
slang_ir_node *loop, *cond, *breakIf, *body;
|
||||
|
||||
loop = new_loop(NULL);
|
||||
|
||||
@@ -1436,18 +1440,12 @@ _slang_gen_do(slang_assemble_ctx * A, const slang_operation *oper)
|
||||
A->CurLoop = loop;
|
||||
|
||||
body = _slang_gen_operation(A, &oper->children[0]);
|
||||
|
||||
cond = _slang_gen_operation(A, &oper->children[1]);
|
||||
cond = new_node1(IR_NOT, cond);
|
||||
cond = _slang_gen_cond(cond);
|
||||
breakIf = new_break_if_false(A->CurLoop, cond);
|
||||
loop->Children[0] = new_seq(body, breakIf);
|
||||
|
||||
ifThen = new_if(cond,
|
||||
new_break(A->CurLoop),
|
||||
NULL);
|
||||
|
||||
loop->Children[0] = new_seq(body, ifThen);
|
||||
|
||||
A->CurLoop = prevLoop; /* pop loop, restore prev */
|
||||
/* pop loop, restore prev */
|
||||
A->CurLoop = prevLoop;
|
||||
|
||||
return loop;
|
||||
}
|
||||
@@ -1463,13 +1461,11 @@ _slang_gen_for(slang_assemble_ctx * A, const slang_operation *oper)
|
||||
/*
|
||||
* init (child[0])
|
||||
* LOOP:
|
||||
* eval expr (child[1]), updating condcodes
|
||||
* IF !expr:
|
||||
* BRK
|
||||
* BREAK if !expr (child[1])
|
||||
* body code (child[3])
|
||||
* incr code (child[2]) // XXX continue here
|
||||
*/
|
||||
slang_ir_node *init, *ifThen, *cond, *body, *loop, *incr;
|
||||
slang_ir_node *loop, *cond, *breakIf, *body, *init, *incr;
|
||||
|
||||
init = _slang_gen_operation(A, &oper->children[0]);
|
||||
loop = new_loop(NULL);
|
||||
@@ -1479,21 +1475,14 @@ _slang_gen_for(slang_assemble_ctx * A, const slang_operation *oper)
|
||||
A->CurLoop = loop;
|
||||
|
||||
cond = _slang_gen_operation(A, &oper->children[1]);
|
||||
cond = new_node1(IR_NOT, cond);
|
||||
cond = _slang_gen_cond(cond);
|
||||
|
||||
ifThen = new_if(cond,
|
||||
new_break(A->CurLoop),
|
||||
NULL);
|
||||
|
||||
breakIf = new_break_if_false(A->CurLoop, cond);
|
||||
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(ifThen,
|
||||
new_seq(body,incr));
|
||||
|
||||
A->CurLoop = prevLoop; /* pop loop, restore prev */
|
||||
/* pop loop, restore prev */
|
||||
A->CurLoop = prevLoop;
|
||||
|
||||
return new_seq(init, loop);
|
||||
}
|
||||
@@ -1521,7 +1510,7 @@ _slang_gen_if(slang_assemble_ctx * A, const slang_operation *oper)
|
||||
slang_atom endifAtom = slang_atom_pool_gen(A->atoms, "__endif");
|
||||
|
||||
cond = _slang_gen_operation(A, &oper->children[0]);
|
||||
cond = _slang_gen_cond(cond);
|
||||
cond = new_cond(cond);
|
||||
/*assert(cond->Store);*/
|
||||
bra = new_cjump(haveElseClause ? elseAtom : endifAtom, 0);
|
||||
tree = new_seq(cond, bra);
|
||||
@@ -1572,7 +1561,7 @@ _slang_gen_hl_if(slang_assemble_ctx * A, const slang_operation *oper)
|
||||
slang_ir_node *ifNode, *cond, *ifBody, *elseBody;
|
||||
|
||||
cond = _slang_gen_operation(A, &oper->children[0]);
|
||||
cond = _slang_gen_cond(cond);
|
||||
cond = new_cond(cond);
|
||||
ifBody = _slang_gen_operation(A, &oper->children[1]);
|
||||
if (haveElseClause)
|
||||
elseBody = _slang_gen_operation(A, &oper->children[2]);
|
||||
@@ -1662,7 +1651,7 @@ _slang_gen_select(slang_assemble_ctx *A, slang_operation *oper)
|
||||
|
||||
/* eval condition */
|
||||
cond = _slang_gen_operation(A, &oper->children[0]);
|
||||
cond = _slang_gen_cond(cond);
|
||||
cond = new_cond(cond);
|
||||
tree = new_seq(tmpDecl, cond);
|
||||
|
||||
/* jump if false to "alt" label */
|
||||
@@ -2245,9 +2234,6 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper)
|
||||
|
||||
case slang_oper_block_no_new_scope:
|
||||
/* list of operations */
|
||||
/*
|
||||
assert(oper->num_children > 0);
|
||||
*/
|
||||
if (oper->num_children > 0)
|
||||
{
|
||||
slang_ir_node *n, *tree = NULL;
|
||||
@@ -2287,7 +2273,7 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper)
|
||||
break;
|
||||
case slang_oper_expression:
|
||||
return _slang_gen_operation(A, &oper->children[0]);
|
||||
break;
|
||||
|
||||
case slang_oper_for:
|
||||
return _slang_gen_for(A, oper);
|
||||
case slang_oper_do:
|
||||
|
||||
@@ -332,6 +332,9 @@ slang_print_ir(const slang_ir_node *n, int indent)
|
||||
case IR_BREAK:
|
||||
printf("BREAK\n");
|
||||
break;
|
||||
case IR_BREAK_IF_FALSE:
|
||||
printf("BREAK_IF_FALSE\n");
|
||||
break;
|
||||
|
||||
case IR_VAR:
|
||||
printf("VAR %s%s at %s store %p\n",
|
||||
@@ -1153,13 +1156,17 @@ emit_loop(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
|
||||
*/
|
||||
for (ir = n->BranchNode; ir; ir = ir->BranchNode) {
|
||||
struct prog_instruction *inst = prog->Instructions + ir->InstLocation;
|
||||
if (ir->Opcode == IR_BREAK) {
|
||||
if (ir->Opcode == IR_BREAK ||
|
||||
ir->Opcode == IR_BREAK_IF_FALSE ||
|
||||
ir->Opcode == IR_BREAK_IF_TRUE) {
|
||||
assert(inst->Opcode == OPCODE_BRK ||
|
||||
inst->Opcode == OPCODE_BRA);
|
||||
inst->BranchTarget = endInstLoc + 1;
|
||||
}
|
||||
else {
|
||||
assert(ir->Opcode == IR_CONT);
|
||||
assert(ir->Opcode == IR_CONT ||
|
||||
ir->Opcode == IR_CONT_IF_FALSE ||
|
||||
ir->Opcode == IR_CONT_IF_TRUE);
|
||||
assert(inst->Opcode == OPCODE_CONT ||
|
||||
inst->Opcode == OPCODE_BRA);
|
||||
/* XXX goto top of loop instead! */
|
||||
@@ -1191,6 +1198,35 @@ emit_cont_break(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Conditional loop continue/break.
|
||||
*/
|
||||
static struct prog_instruction *
|
||||
emit_cont_break_if(slang_var_table *vt, slang_ir_node *n,
|
||||
struct gl_program *prog, GLboolean breakTrue)
|
||||
{
|
||||
gl_inst_opcode opcode;
|
||||
struct prog_instruction *inst;
|
||||
|
||||
/* evaluate condition expr, setting cond codes */
|
||||
inst = emit(vt, n->Children[0], prog);
|
||||
assert(inst);
|
||||
inst->CondUpdate = GL_TRUE;
|
||||
|
||||
n->InstLocation = prog->NumInstructions;
|
||||
if (EmitHighLevelInstructions) {
|
||||
opcode = (n->Opcode == IR_CONT) ? OPCODE_CONT : OPCODE_BRK;
|
||||
}
|
||||
else {
|
||||
opcode = OPCODE_BRA;
|
||||
}
|
||||
inst = new_instruction(prog, opcode);
|
||||
inst->DstReg.CondMask = breakTrue ? COND_NE : COND_EQ;
|
||||
return inst;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Remove any SWIZZLE_NIL terms from given swizzle mask (smear prev term).
|
||||
* Ex: fix_swizzle("zyNN") -> "zyyy"
|
||||
@@ -1407,6 +1443,10 @@ emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
|
||||
|
||||
case IR_LOOP:
|
||||
return emit_loop(vt, n, prog);
|
||||
case IR_BREAK_IF_FALSE:
|
||||
return emit_cont_break_if(vt, n, prog, GL_FALSE);
|
||||
case IR_BREAK_IF_TRUE:
|
||||
return emit_cont_break_if(vt, n, prog, GL_TRUE);
|
||||
case IR_BREAK:
|
||||
/* fall-through */
|
||||
case IR_CONT:
|
||||
|
||||
Reference in New Issue
Block a user