summaryrefslogtreecommitdiff
path: root/ir_to_mesa.cpp
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2010-05-07 12:59:08 -0700
committerEric Anholt <eric@anholt.net>2010-06-24 15:05:20 -0700
commit64fcbbca9ca8191b5131304af2026d0ed914b765 (patch)
treea66a8b1ef9f5842eeb17aa7d5ceb9a84790988a5 /ir_to_mesa.cpp
parent0c005bd773784ee5feb2ee3d7d00c2c4335eafb4 (diff)
ir_to_mesa: Add support for loops.
Fixes CorrectParse1 and the glsl2 loop tests that don't use arrays.
Diffstat (limited to 'ir_to_mesa.cpp')
-rw-r--r--ir_to_mesa.cpp87
1 files changed, 70 insertions, 17 deletions
diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp
index f45421057b..2be5bf1ef0 100644
--- a/ir_to_mesa.cpp
+++ b/ir_to_mesa.cpp
@@ -297,18 +297,37 @@ ir_to_mesa_visitor::visit(ir_variable *ir)
void
ir_to_mesa_visitor::visit(ir_loop *ir)
{
- (void)ir;
+ assert(!ir->from);
+ assert(!ir->to);
+ assert(!ir->increment);
+ assert(!ir->counter);
- printf("Can't support loops, should be flattened before here\n");
- exit(1);
+ ir_to_mesa_emit_op1_full(this, NULL,
+ OPCODE_BGNLOOP, ir_to_mesa_undef_dst,
+ ir_to_mesa_undef);
+
+ visit_exec_list(&ir->body_instructions, this);
+
+ ir_to_mesa_emit_op1_full(this, NULL,
+ OPCODE_ENDLOOP, ir_to_mesa_undef_dst,
+ ir_to_mesa_undef);
}
void
ir_to_mesa_visitor::visit(ir_loop_jump *ir)
{
- (void) ir;
- printf("Can't support loops, should be flattened before here\n");
- exit(1);
+ switch (ir->mode) {
+ case ir_loop_jump::jump_break:
+ ir_to_mesa_emit_op1_full(this, NULL,
+ OPCODE_BRK, ir_to_mesa_undef_dst,
+ ir_to_mesa_undef);
+ break;
+ case ir_loop_jump::jump_continue:
+ ir_to_mesa_emit_op1_full(this, NULL,
+ OPCODE_CONT, ir_to_mesa_undef_dst,
+ ir_to_mesa_undef);
+ break;
+ }
}
@@ -805,32 +824,66 @@ static void
set_branchtargets(struct prog_instruction *mesa_instructions,
int num_instructions)
{
- int if_count = 0;
- struct prog_instruction **if_stack;
- int if_stack_pos = 0;
- int i;
+ int if_count = 0, loop_count;
+ int *if_stack, *loop_stack;
+ int if_stack_pos = 0, loop_stack_pos = 0;
+ int i, j;
for (i = 0; i < num_instructions; i++) {
- if (mesa_instructions[i].Opcode == OPCODE_IF)
+ switch (mesa_instructions[i].Opcode) {
+ case OPCODE_IF:
if_count++;
+ break;
+ case OPCODE_BGNLOOP:
+ loop_count++;
+ break;
+ case OPCODE_BRK:
+ case OPCODE_CONT:
+ mesa_instructions[i].BranchTarget = -1;
+ break;
+ default:
+ break;
+ }
}
- if_stack = (struct prog_instruction **)calloc(if_count, sizeof(*if_stack));
+ if_stack = (int *)calloc(if_count, sizeof(*if_stack));
+ loop_stack = (int *)calloc(loop_count, sizeof(*loop_stack));
for (i = 0; i < num_instructions; i++) {
switch (mesa_instructions[i].Opcode) {
case OPCODE_IF:
- if_stack[if_stack_pos] = mesa_instructions + i;
+ if_stack[if_stack_pos] = i;
if_stack_pos++;
break;
case OPCODE_ELSE:
- if_stack[if_stack_pos - 1]->BranchTarget = i;
- if_stack[if_stack_pos - 1] = mesa_instructions + i;
+ mesa_instructions[if_stack[if_stack_pos - 1]].BranchTarget = i;
+ if_stack[if_stack_pos - 1] = i;
break;
case OPCODE_ENDIF:
- if_stack[if_stack_pos - 1]->BranchTarget = i;
+ mesa_instructions[if_stack[if_stack_pos - 1]].BranchTarget = i;
if_stack_pos--;
break;
+ case OPCODE_BGNLOOP:
+ loop_stack[loop_stack_pos] = i;
+ loop_stack_pos++;
+ break;
+ case OPCODE_ENDLOOP:
+ loop_stack_pos--;
+ /* Rewrite any breaks/conts at this nesting level (haven't
+ * already had a BranchTarget assigned) to point to the end
+ * of the loop.
+ */
+ for (j = loop_stack[loop_stack_pos]; j < i; j++) {
+ if (mesa_instructions[j].Opcode == OPCODE_BRK ||
+ mesa_instructions[j].Opcode == OPCODE_CONT) {
+ if (mesa_instructions[j].BranchTarget == -1) {
+ mesa_instructions[j].BranchTarget = i;
+ }
+ }
+ }
+ /* The loop ends point at each other. */
+ mesa_instructions[i].BranchTarget = loop_stack[loop_stack_pos];
+ mesa_instructions[loop_stack[loop_stack_pos]].BranchTarget = i;
default:
break;
}
@@ -851,7 +904,7 @@ print_program(struct prog_instruction *mesa_instructions,
struct prog_instruction *mesa_inst = mesa_instructions + i;
ir_instruction *ir = mesa_instruction_annotation[i];
- if (last_ir != ir) {
+ if (last_ir != ir && ir) {
ir_print_visitor print;
ir->accept(&print);
printf("\n");