From 86080796471df6a9e126fd536b21c3b10cb5310c Mon Sep 17 00:00:00 2001 From: Brian Date: Mon, 5 Feb 2007 17:18:10 -0700 Subject: Use IR node's BranchNode field for IF/ELSE/ENDIF instructions. This allows us to back-patch the IF/ELSE instruction's BranchTarget field to point to the location of the ELSE/ENDIF instructions. No longer have to search for ELSE/ENDIF in the interpreter. Also makes it trivial to translate IF/ELSE instructions into conditional/unconditional BRA instructions. --- src/mesa/shader/prog_print.c | 7 ++-- src/mesa/shader/slang/slang_codegen.c | 64 ++++++++++++++++++++++++++++------- src/mesa/shader/slang/slang_emit.c | 12 +++++++ src/mesa/swrast/s_fragprog.c | 57 ++++--------------------------- 4 files changed, 73 insertions(+), 67 deletions(-) diff --git a/src/mesa/shader/prog_print.c b/src/mesa/shader/prog_print.c index 208c998661..aea11da0db 100644 --- a/src/mesa/shader/prog_print.c +++ b/src/mesa/shader/prog_print.c @@ -319,13 +319,14 @@ _mesa_print_instruction(const struct prog_instruction *inst, GLint indent) print_comment(inst); break; case OPCODE_IF: - _mesa_printf("IF (%s%s)", + _mesa_printf("IF (%s%s) (if false, goto %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); return indent + 3; case OPCODE_ELSE: - _mesa_printf("ELSE\n"); + _mesa_printf("ELSE (goto %d)\n", inst->BranchTarget); return indent + 3; case OPCODE_ENDIF: _mesa_printf("ENDIF\n"); diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index c70f73f15a..7a1881c68e 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -590,6 +590,47 @@ new_end_loop(slang_ir_node *beginNode) } +/** + * Child[0] is the condition. + * XXX we might re-design IR_IF so Children[1] is the "then" body and + * Children[0] is the "else" body. + */ +static slang_ir_node * +new_if(slang_ir_node *cond) +{ + slang_ir_node *n = new_node(IR_IF, NULL, NULL); + assert(cond); + if (n) { + n->Children[0] = cond; + } + return n; +} + + +static slang_ir_node * +new_else(slang_ir_node *ifNode) +{ + slang_ir_node *n = new_node(IR_ELSE, NULL, NULL); + assert(ifNode); + if (n) { + n->BranchNode = ifNode; + } + return n; +} + + +static slang_ir_node * +new_endif(slang_ir_node *elseOrIfNode) +{ + slang_ir_node *n = new_node(IR_ENDIF, NULL, NULL); + assert(elseOrIfNode); + if (n) { + n->BranchNode = elseOrIfNode; + } + return n; +} + + /** * New IR_VAR node - a reference to a previously declared variable. */ @@ -1401,13 +1442,13 @@ _slang_gen_hl_while(slang_assemble_ctx * A, const slang_operation *oper) cond = new_node(IR_NOT, cond, NULL); cond = _slang_gen_cond(cond); - ifThen = new_node(IR_IF, cond, NULL); + ifThen = new_if(cond); tree = new_seq(beginLoop, ifThen); brk = new_node(IR_BREAK, NULL, NULL); tree = new_seq(tree, brk); - endif = new_node(IR_ENDIF, NULL, NULL); + endif = new_endif(ifThen); tree = new_seq(tree, endif); body = _slang_gen_operation(A, &oper->children[1]); @@ -1589,13 +1630,11 @@ _slang_gen_hl_if(slang_assemble_ctx * A, const slang_operation *oper) { /* * eval expr (child[0]), updating condcodes - * branch if false to _else or _endif - * "true" code block - * if haveElseClause clause: - * jump "__endif" - * label "__else" - * "false" code block - * label "__endif" + * IF expr THEN + * if-body code + * ELSE + * else-body code + * ENDIF */ /* XXX special cases to check for: * if body of conditiona is just a "break", emit a conditional break @@ -1608,21 +1647,20 @@ _slang_gen_hl_if(slang_assemble_ctx * A, const slang_operation *oper) cond = _slang_gen_operation(A, &oper->children[0]); cond = _slang_gen_cond(cond); /*assert(cond->Store);*/ - ifNode = new_node(IR_IF, cond, NULL); + ifNode = new_if(cond); trueBody = _slang_gen_operation(A, &oper->children[1]); tree = new_seq(ifNode, trueBody); if (haveElseClause) { - /* else clause */ - elseNode = new_node(IR_ELSE, NULL, NULL); + elseNode = new_else(ifNode); tree = new_seq(tree, elseNode); falseBody = _slang_gen_operation(A, &oper->children[2]); tree = new_seq(tree, falseBody); } - endifNode = new_node(IR_ENDIF, NULL, NULL); + endifNode = new_endif(haveElseClause ? elseNode : ifNode); tree = new_seq(tree, endifNode); return tree; diff --git a/src/mesa/shader/slang/slang_emit.c b/src/mesa/shader/slang/slang_emit.c index 311eea1e6a..b890a6d93c 100644 --- a/src/mesa/shader/slang/slang_emit.c +++ b/src/mesa/shader/slang/slang_emit.c @@ -1036,6 +1036,7 @@ emit_not(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog) free_temp_storage(vt, n->Children[0]); + inst->Comment = _mesa_strdup("NOT"); return inst; } @@ -1259,18 +1260,29 @@ emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog) inst = new_instruction(prog, OPCODE_IF); inst->DstReg.CondMask = COND_NE; /* if cond is non-zero */ inst->DstReg.CondSwizzle = SWIZZLE_X; + n->InstLocation = prog->NumInstructions - 1; return inst; } case IR_ELSE: { struct prog_instruction *inst; + 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; return inst; } case IR_ENDIF: { struct prog_instruction *inst; + 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; return inst; } diff --git a/src/mesa/swrast/s_fragprog.c b/src/mesa/swrast/s_fragprog.c index 287dd9b1db..fbd25c0fbf 100644 --- a/src/mesa/swrast/s_fragprog.c +++ b/src/mesa/swrast/s_fragprog.c @@ -897,62 +897,17 @@ execute_program( GLcontext *ctx, /* do if-clause (just continue execution) */ } else { - /* search for else-clause or endif */ - /* XXX could encode location of the else/endif statement - * in the IF instruction to avoid searching... - */ - GLint ifDepth = 1; - do { - pc++; - inst = program->Base.Instructions + pc; - if (inst->Opcode == OPCODE_END) { - /* mal-formed program! */ - _mesa_problem(ctx, "END found before ELSE/ENDIF"); - return GL_FALSE; - } - else if (inst->Opcode == OPCODE_IF) { - /* nested if */ - ifDepth++; - } - else if (inst->Opcode == OPCODE_ELSE) { - if (ifDepth == 1) { - /* ok, continue normal execution */ - break; - } - } - else if (inst->Opcode == OPCODE_ENDIF) { - ifDepth--; - if (ifDepth == 0) { - /* ok, continue normal execution */ - break; - } - } - assert(ifDepth >= 0); - } while (pc < maxInst); + /* go to the instruction after ELSE or ENDIF */ + assert(inst->BranchTarget >= 0); + pc = inst->BranchTarget - 1; } } break; case OPCODE_ELSE: { - /* find/goto ENDIF */ - GLint ifDepth = 1; - do { - pc++; - inst = program->Base.Instructions + pc; - if (inst->Opcode == OPCODE_END) { - /* mal-formed program! */ - abort(); - } - else if (inst->Opcode == OPCODE_IF) { - ifDepth++; - } - else if (inst->Opcode == OPCODE_ENDIF) { - ifDepth--; - if (ifDepth == 0) - break; - } - assert(ifDepth >= 0); - } while (pc < maxInst); + /* goto ENDIF */ + assert(inst->BranchTarget >= 0); + pc = inst->BranchTarget - 1; } break; case OPCODE_ENDIF: -- cgit v1.2.3