diff options
| -rw-r--r-- | src/mesa/shader/prog_print.c | 8 | ||||
| -rw-r--r-- | src/mesa/shader/slang/slang_codegen.c | 90 | ||||
| -rw-r--r-- | src/mesa/shader/slang/slang_emit.c | 24 | ||||
| -rw-r--r-- | src/mesa/swrast/s_fragprog.c | 28 | 
4 files changed, 122 insertions, 28 deletions
| diff --git a/src/mesa/shader/prog_print.c b/src/mesa/shader/prog_print.c index aea11da0db..3d4a474b05 100644 --- a/src/mesa/shader/prog_print.c +++ b/src/mesa/shader/prog_print.c @@ -332,17 +332,17 @@ _mesa_print_instruction(const struct prog_instruction *inst, GLint indent)        _mesa_printf("ENDIF\n");        break;     case OPCODE_BGNLOOP: -      _mesa_printf("BGNLOOP\n"); +      _mesa_printf("BGNLOOP (end at %d)\n", inst->BranchTarget);        return indent + 3;     case OPCODE_ENDLOOP:        _mesa_printf("ENDLOOP (goto %d)\n", inst->BranchTarget);        break;     case OPCODE_BRK:        /* XXX just like BRA */ -      _mesa_printf("BRK %u (%s%s)", -                   inst->BranchTarget, +      _mesa_printf("BRK (%s%s) (for loop beginning at %d)",                     condcode_string(inst->DstReg.CondMask), -                   swizzle_string(inst->DstReg.CondSwizzle, 0, GL_FALSE)); +                   swizzle_string(inst->DstReg.CondSwizzle, 0, GL_FALSE), +                   inst->BranchTarget);        print_comment(inst);        break;     case OPCODE_BGNSUB: diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index 7a1881c68e..a5f033d912 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -590,6 +590,18 @@ new_end_loop(slang_ir_node *beginNode)  } +static slang_ir_node * +new_break(slang_ir_node *beginNode) +{ +   slang_ir_node *n = new_node(IR_BREAK, NULL, NULL); +   assert(beginNode); +   if (n) { +      n->BranchNode = beginNode; +   } +   return n; +} + +  /**   * Child[0] is the condition.   * XXX we might re-design IR_IF so Children[1] is the "then" body and @@ -1430,7 +1442,7 @@ _slang_gen_hl_while(slang_assemble_ctx * A, const slang_operation *oper)      *    IF !expr THEN      *       BRK      *    ENDIF -    *    body code +    *    body code (child[1])      * ENDLOOP      */     slang_ir_node *beginLoop, *endLoop, *ifThen, *endif; @@ -1445,7 +1457,7 @@ _slang_gen_hl_while(slang_assemble_ctx * A, const slang_operation *oper)     ifThen = new_if(cond);     tree = new_seq(beginLoop, ifThen); -   brk = new_node(IR_BREAK, NULL, NULL); +   brk = new_break(beginLoop);     tree = new_seq(tree, brk);     endif = new_endif(ifThen); @@ -1572,6 +1584,73 @@ _slang_gen_for(slang_assemble_ctx * A, const slang_operation *oper)  /** + * Generate IR tree for a for-loop, using high-level BGNLOOP/ENDLOOP and + * IF/ENDIF instructions. + * + * XXX note done yet! + */ +static slang_ir_node * +_slang_gen_hl_for(slang_assemble_ctx * A, const slang_operation *oper) +{ +   /* +    * init code (child[0]) +    * BGNLOOP +    *    eval expr (child[1]), updating condcodes +    *    IF !expr THEN +    *       BRK +    *    ENDIF +    *    code body (child[3]) +    *    label "__continueFor"   // jump here for "continue" +    *    incr code (child[2]) +    * ENDLOOP +    */ +   slang_atom startAtom = slang_atom_pool_gen(A->atoms, "__startFor"); +   slang_atom contAtom = slang_atom_pool_gen(A->atoms, "__continueFor"); +   slang_atom endAtom = slang_atom_pool_gen(A->atoms, "__endFor"); +   slang_ir_node *init, *startLab, *cond, *bra, *body, *contLab; +   slang_ir_node *incr, *jump, *endLab, *tree; +   slang_atom prevLoopBreak = A->CurLoopBreak; +   slang_atom prevLoopCont = A->CurLoopCont; + +   /* Push this loop */ +   A->CurLoopBreak = endAtom; +   A->CurLoopCont = contAtom; + +   init = _slang_gen_operation(A, &oper->children[0]); +   startLab = new_label(startAtom); +   tree = new_seq(init, startLab); + +   cond = _slang_gen_operation(A, &oper->children[1]); +   cond = _slang_gen_cond(cond); +   tree = new_seq(tree, cond); + +   bra = new_cjump(endAtom, 0); +   tree = new_seq(tree, bra); + +   body = _slang_gen_operation(A, &oper->children[3]); +   tree = new_seq(tree, body); + +   contLab = new_label(contAtom); +   tree = new_seq(tree, contLab); + +   incr = _slang_gen_operation(A, &oper->children[2]); +   tree = new_seq(tree, incr); + +   jump = new_jump(startAtom); +   tree = new_seq(tree, jump); + +   endLab = new_label(endAtom); +   tree = new_seq(tree, endLab); + +   /* Pop this loop */ +   A->CurLoopBreak = prevLoopBreak; +   A->CurLoopCont = prevLoopCont; + +   return tree; +} + + +/**   * Generate IR tree for an if/then/else conditional using BRAnch instructions.   */  static slang_ir_node * @@ -2378,16 +2457,21 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper)     case slang_oper_do:        return _slang_gen_do(A, oper);     case slang_oper_for: -      return _slang_gen_for(A, oper); +      if (UseHighLevelInstructions) +         return _slang_gen_hl_for(A, oper); +      else +         return _slang_gen_for(A, oper);     case slang_oper_break:        if (!A->CurLoopBreak) {           RETURN_ERROR("'break' not in loop", 0);        } +      /* XXX emit IR_BREAK instruction */        return new_jump(A->CurLoopBreak);     case slang_oper_continue:        if (!A->CurLoopCont) {           RETURN_ERROR("'continue' not in loop", 0);        } +      /* XXX emit IR_CONT instruction */        return new_jump(A->CurLoopCont);     case slang_oper_discard:        return new_node(IR_KILL, NULL, NULL); diff --git a/src/mesa/shader/slang/slang_emit.c b/src/mesa/shader/slang/slang_emit.c index b890a6d93c..3faacdd4cf 100644 --- a/src/mesa/shader/slang/slang_emit.c +++ b/src/mesa/shader/slang/slang_emit.c @@ -1265,24 +1265,29 @@ emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)        }     case IR_ELSE:        { -         struct prog_instruction *inst; +         struct prog_instruction *inst, *ifInst;           n->InstLocation = prog->NumInstructions;           inst = new_instruction(prog, OPCODE_ELSE);           /* point IF's BranchTarget just after this instruction */           assert(n->BranchNode);           assert(n->BranchNode->InstLocation >= 0); -         prog->Instructions[n->BranchNode->InstLocation].BranchTarget = prog->NumInstructions; +         ifInst = prog->Instructions + n->BranchNode->InstLocation; +         assert(ifInst->Opcode == OPCODE_IF); +         ifInst->BranchTarget = prog->NumInstructions;           return inst;        }     case IR_ENDIF:        { -         struct prog_instruction *inst; +         struct prog_instruction *inst, *elseInst;           n->InstLocation = prog->NumInstructions;           inst = new_instruction(prog, OPCODE_ENDIF);           /* point ELSE's BranchTarget to just after this inst */           assert(n->BranchNode);           assert(n->BranchNode->InstLocation >= 0); -         prog->Instructions[n->BranchNode->InstLocation].BranchTarget = prog->NumInstructions; +         elseInst = prog->Instructions + n->BranchNode->InstLocation; +         assert(elseInst->Opcode == OPCODE_ELSE || +                elseInst->Opcode == OPCODE_IF); +         elseInst->BranchTarget = prog->NumInstructions;           return inst;        } @@ -1295,12 +1300,15 @@ emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)        break;     case IR_END_LOOP:        { -         struct prog_instruction *inst; +         struct prog_instruction *inst, *beginInst;           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; +         /* Update BEGIN_LOOP's BranchTarget to point to this instruction */ +         beginInst = prog->Instructions + n->BranchNode->InstLocation; +         beginInst->BranchTarget = prog->NumInstructions - 1;           return inst;        }     case IR_CONT: @@ -1310,6 +1318,12 @@ emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)           struct prog_instruction *inst;           inst = new_instruction(prog, OPCODE_BRK);           inst->DstReg.CondMask = COND_TR;  /* always true */ +         /* This instruction's branch target is top of loop, not bottom of +          * loop because we don't know where it is yet! +          */ +         assert(n->BranchNode); +         assert(n->BranchNode->InstLocation >= 0); +         inst->BranchTarget = n->BranchNode->InstLocation;           return inst;        }     case IR_BEGIN_SUB: diff --git a/src/mesa/swrast/s_fragprog.c b/src/mesa/swrast/s_fragprog.c index fbd25c0fbf..12c8aee6ea 100644 --- a/src/mesa/swrast/s_fragprog.c +++ b/src/mesa/swrast/s_fragprog.c @@ -625,7 +625,7 @@ execute_program( GLcontext *ctx,                   GLuint column )  {     const GLuint MAX_EXEC = 10000; -   GLint pc, total = 0, loopDepth = 0; +   GLint pc, total = 0;     if (DEBUG_FRAG) {        printf("execute fragment program --------------------\n"); @@ -676,11 +676,8 @@ 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; @@ -706,19 +703,18 @@ execute_program( GLcontext *ctx,              }              break;           case OPCODE_BRK: /* break out of loop */ -            if (loopDepth == 0) { -               _mesa_problem(ctx, "BRK not inside a loop"); +            { +               /* The location of the ENDLOOP instruction is saved in the +                * BGNLOOP instruction.  Get that instruction and jump to +                * its BranchTarget + 1. +                */ +               const struct prog_instruction *loopBeginInst +                  = program->Base.Instructions + inst->BranchTarget; +               ASSERT(loopBeginInst->Opcode == OPCODE_BGNLOOP); +               ASSERT(loopBeginInst->BranchTarget >= 0); +               /* we'll add one at bottom of for-loop */ +               pc = loopBeginInst->BranchTarget;              } -            /* 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 */              { | 
