From: Brian Date: Fri, 23 Mar 2007 23:48:42 +0000 (-0600) Subject: Fix issues related to the 'continue' statement. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=d1934c2065751e2c594316c5abd2c49c47bfc1b8;p=mesa.git Fix issues related to the 'continue' statement. 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. --- diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index 4e41aa87002..2eb509b4d1b 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -414,7 +414,7 @@ _slang_free_ir_tree(slang_ir_node *n) 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 } @@ -515,8 +515,8 @@ new_break(slang_ir_node *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; } @@ -534,8 +534,8 @@ new_break_if(slang_ir_node *loopNode, slang_ir_node *cond, GLboolean breakTrue) 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; } @@ -553,23 +553,8 @@ new_cont_if(slang_ir_node *loopNode, slang_ir_node *cond, GLboolean contTrue) 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; } @@ -1369,7 +1354,8 @@ _slang_gen_while(slang_assemble_ctx * A, const slang_operation *oper) 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!"); @@ -1392,30 +1378,33 @@ _slang_gen_do(slang_assemble_ctx * A, const slang_operation *oper) /* * 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; @@ -1431,11 +1420,12 @@ static slang_ir_node * _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; @@ -1450,8 +1440,9 @@ _slang_gen_for(slang_assemble_ctx * A, const slang_operation *oper) 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; @@ -1460,6 +1451,25 @@ _slang_gen_for(slang_assemble_ctx * A, const slang_operation *oper) } +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. */ @@ -2364,7 +2374,7 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper) 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); diff --git a/src/mesa/shader/slang/slang_emit.c b/src/mesa/shader/slang/slang_emit.c index 9e476b8a0fa..6ec20daabb6 100644 --- a/src/mesa/shader/slang/slang_emit.c +++ b/src/mesa/shader/slang/slang_emit.c @@ -316,6 +316,7 @@ slang_print_ir(const slang_ir_node *n, int indent) printf("ELSE\n"); slang_print_ir(n->Children[2], indent+3); } + spaces(indent); printf("ENDIF\n"); break; @@ -335,6 +336,11 @@ slang_print_ir(const slang_ir_node *n, int indent) 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; @@ -685,6 +691,19 @@ instruction_annotation(gl_inst_opcode opcode, char *dstAnnot, } +/** + * 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. @@ -1005,9 +1024,16 @@ static struct prog_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; } @@ -1097,7 +1123,9 @@ emit_move(slang_emit_info *emitInfo, slang_ir_node *n) assert(n->Children[1]->Store->Index >= 0); +#if 0 assert(!n->Store); +#endif n->Store = n->Children[0]->Store; #if PEEPHOLE_OPTIMIZATIONS @@ -1316,9 +1344,11 @@ emit_loop(slang_emit_info *emitInfo, slang_ir_node *n) { 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) { @@ -1328,6 +1358,14 @@ emit_loop(slang_emit_info *emitInfo, slang_ir_node *n) /* 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 */ @@ -1338,7 +1376,7 @@ emit_loop(slang_emit_info *emitInfo, slang_ir_node *n) 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) { @@ -1351,7 +1389,7 @@ emit_loop(slang_emit_info *emitInfo, slang_ir_node *n) * 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 || @@ -1372,8 +1410,8 @@ emit_loop(slang_emit_info *emitInfo, slang_ir_node *n) 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; @@ -1389,13 +1427,28 @@ emit_cont_break(slang_emit_info *emitInfo, slang_ir_node *n) { 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; @@ -1456,7 +1509,7 @@ emit_cont_break_if(slang_emit_info *emitInfo, slang_ir_node *n, 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; @@ -1607,7 +1660,9 @@ emit(slang_emit_info *emitInfo, slang_ir_node *n) 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; @@ -1623,10 +1678,11 @@ emit(slang_emit_info *emitInfo, slang_ir_node *n) 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; @@ -1654,8 +1710,7 @@ emit(slang_emit_info *emitInfo, slang_ir_node *n) _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; @@ -1828,7 +1883,7 @@ _slang_emit_code(slang_ir_node *n, slang_var_table *vt, 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); diff --git a/src/mesa/shader/slang/slang_ir.h b/src/mesa/shader/slang/slang_ir.h index cc9df69e722..37dd38eaa5d 100644 --- a/src/mesa/shader/slang/slang_ir.h +++ b/src/mesa/shader/slang/slang_ir.h @@ -53,6 +53,9 @@ typedef enum 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 */ @@ -60,13 +63,18 @@ typedef enum 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, @@ -161,7 +169,8 @@ typedef struct slang_ir_node_ 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;