diff options
Diffstat (limited to 'src/mesa/shader/slang/slang_codegen.c')
-rw-r--r-- | src/mesa/shader/slang/slang_codegen.c | 194 |
1 files changed, 133 insertions, 61 deletions
diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index f9dae9f7aa..93b6d9f854 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -468,13 +468,28 @@ new_float_literal(const float v[4], GLuint size) return n; } + +/** + * Inlined subroutine. + */ +static slang_ir_node * +new_inlined_function_call(slang_ir_node *code, slang_label *name) +{ + slang_ir_node *n = new_node1(IR_FUNC, code); + assert(name); + if (n) + n->Label = name; + return n; +} + + /** * Unconditional jump. */ static slang_ir_node * -new_jump(slang_label *dest) +new_return(slang_label *dest) { - slang_ir_node *n = new_node0(IR_JUMP); + slang_ir_node *n = new_node0(IR_RETURN); assert(dest); if (n) n->Label = dest; @@ -607,6 +622,24 @@ _slang_is_noop(const slang_operation *oper) /** + * Recursively search tree for a node of the given type. + */ +static slang_operation * +_slang_find_node_type(slang_operation *oper, slang_operation_type type) +{ + GLuint i; + if (oper->type == type) + return oper; + for (i = 0; i < oper->num_children; i++) { + slang_operation *p = _slang_find_node_type(&oper->children[i], type); + if (p) + return p; + } + return NULL; +} + + +/** * Produce inline code for a call to an assembly instruction. * XXX Note: children are passed as asm args in-order, not by name! */ @@ -681,11 +714,8 @@ slang_substitute(slang_assemble_ctx *A, slang_operation *oper, GLuint i; v = _slang_locate_variable(oper->locals, id, GL_TRUE); if (!v) { - printf("var %s not found!\n", (char *) oper->a_id); - _slang_print_var_scope(oper->locals, 6); - - abort(); - break; + _mesa_problem(NULL, "var %s not found!\n", (char *) oper->a_id); + return; } /* look for a substitution */ @@ -716,7 +746,7 @@ slang_substitute(slang_assemble_ctx *A, slang_operation *oper, case SLANG_OPER_RETURN: /* do return replacement here too */ assert(oper->num_children == 0 || oper->num_children == 1); - if (!_slang_is_noop(oper)) { + if (oper->num_children == 1 && !_slang_is_noop(&oper->children[0])) { /* replace: * return expr; * with: @@ -725,6 +755,14 @@ slang_substitute(slang_assemble_ctx *A, slang_operation *oper, * then do substitutions on the assignment. */ slang_operation *blockOper, *assignOper, *returnOper; + + /* check if function actually has a return type */ + assert(A->CurFunction); + if (A->CurFunction->header.type.specifier.type == SLANG_SPEC_VOID) { + slang_info_log_error(A->log, "illegal return expression"); + return; + } + blockOper = slang_operation_new(1); blockOper->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE; blockOper->num_children = 2; @@ -744,7 +782,7 @@ slang_substitute(slang_assemble_ctx *A, slang_operation *oper, slang_operation_copy(&assignOper->children[1], &oper->children[0]); - returnOper->type = SLANG_OPER_RETURN; + returnOper->type = SLANG_OPER_RETURN; /* return w/ no value */ assert(returnOper->num_children == 0); /* do substitutions on the "__retVal = expr" sub-tree */ @@ -755,6 +793,14 @@ slang_substitute(slang_assemble_ctx *A, slang_operation *oper, slang_operation_copy(oper, blockOper); slang_operation_destruct(blockOper); } + else { + /* check if return value was expected */ + assert(A->CurFunction); + if (A->CurFunction->header.type.specifier.type != SLANG_SPEC_VOID) { + slang_info_log_error(A->log, "return statement requires an expression"); + return; + } + } break; case SLANG_OPER_ASSIGN: @@ -806,6 +852,11 @@ slang_inline_function_call(slang_assemble_ctx * A, slang_function *fun, slang_variable **substOld; slang_operation **substNew; GLuint substCount, numCopyIn, i; + slang_function *prevFunction; + + /* save / push */ + prevFunction = A->CurFunction; + A->CurFunction = fun; /*assert(oper->type == SLANG_OPER_CALL); (or (matrix) multiply, etc) */ assert(fun->param_count == totalArgs); @@ -1027,6 +1078,10 @@ slang_inline_function_call(slang_assemble_ctx * A, slang_function *fun, fun->parameters->num_variables, numArgs); slang_print_tree(top, 0); #endif + + /* pop */ + A->CurFunction = prevFunction; + return top; } @@ -1052,8 +1107,18 @@ _slang_gen_function_call(slang_assemble_ctx *A, slang_function *fun, else { /* non-assembly function */ inlined = slang_inline_function_call(A, fun, oper, dest); + if (inlined) { + assert(inlined->type == SLANG_OPER_BLOCK_NEW_SCOPE || + inlined->type == SLANG_OPER_SEQUENCE); + inlined->type = SLANG_OPER_INLINED_CALL; + inlined->fun = fun; + inlined->label = _slang_label_new((char*) fun->header.a_name); + } } + if (!inlined) + return NULL; + /* Replace the function call with the inlined block */ slang_operation_destruct(oper); *oper = *inlined; @@ -1109,7 +1174,8 @@ make_writemask(const char *field) mask |= WRITEMASK_W; break; default: - abort(); + _mesa_problem(NULL, "invalid writemask in make_writemask()"); + return 0; } field++; } @@ -1703,26 +1769,25 @@ _slang_gen_logical_or(slang_assemble_ctx *A, slang_operation *oper) static slang_ir_node * _slang_gen_return(slang_assemble_ctx * A, slang_operation *oper) { - if (oper->num_children == 0 || - (oper->num_children == 1 && - oper->children[0].type == SLANG_OPER_VOID)) { - /* Convert from: - * return; - * To: - * goto __endOfFunction; - */ - slang_ir_node *n; - slang_operation gotoOp; - slang_operation_construct(&gotoOp); - gotoOp.type = SLANG_OPER_GOTO; - gotoOp.label = A->curFuncEndLabel; - assert(gotoOp.label); + const GLboolean haveReturnValue + = (oper->num_children == 1 && + oper->children[0].type != SLANG_OPER_VOID); + + /* error checking */ + assert(A->CurFunction); + if (haveReturnValue && + A->CurFunction->header.type.specifier.type == SLANG_SPEC_VOID) { + slang_info_log_error(A->log, "illegal return expression"); + return NULL; + } + else if (!haveReturnValue && + A->CurFunction->header.type.specifier.type != SLANG_SPEC_VOID) { + slang_info_log_error(A->log, "return statement requires an expression"); + return NULL; + } - /* assemble the new code */ - n = _slang_gen_operation(A, &gotoOp); - /* destroy temp code */ - slang_operation_destruct(&gotoOp); - return n; + if (!haveReturnValue) { + return new_return(A->curFuncEndLabel); } else { /* @@ -1730,9 +1795,9 @@ _slang_gen_return(slang_assemble_ctx * A, slang_operation *oper) * return expr; * To: * __retVal = expr; - * goto __endOfFunction; + * return; // goto __endOfFunction */ - slang_operation *block, *assign, *jump; + slang_operation *assign; slang_atom a_retVal; slang_ir_node *n; @@ -1743,21 +1808,15 @@ _slang_gen_return(slang_assemble_ctx * A, slang_operation *oper) { slang_variable *v = _slang_locate_variable(oper->locals, a_retVal, GL_TRUE); - assert(v); + if (!v) { + /* trying to return a value in a void-valued function */ + return NULL; + } } #endif - block = slang_operation_new(1); - block->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE; - assert(block->locals); - block->locals->outer_scope = oper->locals->outer_scope; - block->num_children = 2; - block->children = slang_operation_new(2); - - /* child[0]: __retVal = expr; */ - assign = &block->children[0]; + assign = slang_operation_new(1); assign->type = SLANG_OPER_ASSIGN; - assign->locals->outer_scope = block->locals; assign->num_children = 2; assign->children = slang_operation_new(2); /* lhs (__retVal) */ @@ -1768,22 +1827,11 @@ _slang_gen_return(slang_assemble_ctx * A, slang_operation *oper) /* XXX we might be able to avoid this copy someday */ slang_operation_copy(&assign->children[1], &oper->children[0]); - /* child[1]: goto __endOfFunction */ - jump = &block->children[1]; - jump->type = SLANG_OPER_GOTO; - assert(A->curFuncEndLabel); - /* XXX don't call function? */ - jump->label = A->curFuncEndLabel; - assert(jump->label); - -#if 0 /* debug */ - printf("NEW RETURN:\n"); - slang_print_tree(block, 0); -#endif - /* assemble the new code */ - n = _slang_gen_operation(A, block); - slang_operation_delete(block); + n = new_seq(_slang_gen_operation(A, assign), + new_return(A->curFuncEndLabel)); + + slang_operation_delete(assign); return n; } } @@ -1843,6 +1891,9 @@ _slang_gen_declaration(slang_assemble_ctx *A, slang_operation *oper) _slang_simplify(v->initializer, &A->space, A->atoms); rhs = _slang_gen_operation(A, v->initializer); #endif + if (!rhs) + return NULL; + assert(rhs); init = new_node2(IR_MOVE, var, rhs); /* @@ -2509,8 +2560,6 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper) oper, NULL); case SLANG_OPER_RETURN: return _slang_gen_return(A, oper); - case SLANG_OPER_GOTO: - return new_jump(oper->label); case SLANG_OPER_LABEL: return new_label(oper->label); case SLANG_OPER_IDENTIFIER: @@ -2557,6 +2606,7 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper) return n; } + case SLANG_OPER_INLINED_CALL: case SLANG_OPER_SEQUENCE: { slang_ir_node *tree = NULL; @@ -2565,6 +2615,9 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper) slang_ir_node *n = _slang_gen_operation(A, &oper->children[i]); tree = tree ? new_seq(tree, n) : n; } + if (oper->type == SLANG_OPER_INLINED_CALL) { + tree = new_inlined_function_call(tree, oper->label); + } return tree; } @@ -2574,8 +2627,8 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper) return new_node0(IR_NOP); default: - printf("Unhandled node type %d\n", oper->type); - abort(); + _mesa_problem(NULL, "bad node type %d in _slang_gen_operation", + oper->type); return new_node0(IR_NOP); } @@ -2774,6 +2827,23 @@ _slang_codegen_function(slang_assemble_ctx * A, slang_function * fun) /* we only really generate code for main, all other functions get * inlined. */ +#if 0 + /* do some basic error checking though */ + if (fun->header.type.specifier.type != SLANG_SPEC_VOID) { + /* check that non-void functions actually return something */ + slang_operation *op + = _slang_find_node_type(fun->body, SLANG_OPER_RETURN); + if (!op) { + slang_info_log_error(A->log, + "function \"%s\" has no return statement", + (char *) fun->header.a_name); + printf( + "function \"%s\" has no return statement\n", + (char *) fun->header.a_name); + return GL_FALSE; + } + } +#endif return GL_TRUE; /* not an error */ } @@ -2786,6 +2856,8 @@ _slang_codegen_function(slang_assemble_ctx * A, slang_function * fun) assert(A->program->Parameters ); assert(A->program->Varying); assert(A->vartable); + A->CurLoop = NULL; + A->CurFunction = fun; /* fold constant expressions, etc. */ _slang_simplify(fun->body, &A->space, A->atoms); |