📄 slang_codegen.c
字号:
substCount, substOld, substNew, GL_TRUE); slang_substitute(A, &oper->children[1], substCount, substOld, substNew, GL_FALSE); break; case SLANG_OPER_FIELD: /* XXX NEW - test */ slang_substitute(A, &oper->children[0], substCount, substOld, substNew, GL_TRUE); break; default: { GLuint i; for (i = 0; i < oper->num_children; i++) slang_substitute(A, &oper->children[i], substCount, substOld, substNew, GL_FALSE); } }}/** * Produce inline code for a call to an assembly instruction. * This is typically used to compile a call to a built-in function like this: * * vec4 mix(const vec4 x, const vec4 y, const vec4 a) * { * __asm vec4_lrp __retVal, a, y, x; * } * * * A call to * r = mix(p1, p2, p3); * * Becomes: * * mov * / \ * r vec4_lrp * / | \ * p3 p2 p1 * * We basically translate a SLANG_OPER_CALL into a SLANG_OPER_ASM. */static slang_operation *slang_inline_asm_function(slang_assemble_ctx *A, slang_function *fun, slang_operation *oper){ const GLuint numArgs = oper->num_children; GLuint i; slang_operation *inlined; const GLboolean haveRetValue = _slang_function_has_return_value(fun); slang_variable **substOld; slang_operation **substNew; ASSERT(slang_is_asm_function(fun)); ASSERT(fun->param_count == numArgs + haveRetValue); /* printf("Inline %s as %s\n", (char*) fun->header.a_name, (char*) fun->body->children[0].a_id); */ /* * We'll substitute formal params with actual args in the asm call. */ substOld = (slang_variable **) _slang_alloc(numArgs * sizeof(slang_variable *)); substNew = (slang_operation **) _slang_alloc(numArgs * sizeof(slang_operation *)); for (i = 0; i < numArgs; i++) { substOld[i] = fun->parameters->variables[i]; substNew[i] = oper->children + i; } /* make a copy of the code to inline */ inlined = slang_operation_new(1); slang_operation_copy(inlined, &fun->body->children[0]); if (haveRetValue) { /* get rid of the __retVal child */ inlined->num_children--; for (i = 0; i < inlined->num_children; i++) { inlined->children[i] = inlined->children[i + 1]; } } /* now do formal->actual substitutions */ slang_substitute(A, inlined, numArgs, substOld, substNew, GL_FALSE); _slang_free(substOld); _slang_free(substNew);#if 0 printf("+++++++++++++ inlined asm function %s +++++++++++++\n", (char *) fun->header.a_name); slang_print_tree(inlined, 3); printf("+++++++++++++++++++++++++++++++++++++++++++++++++++\n");#endif return inlined;}/** * Inline the given function call operation. * Return a new slang_operation that corresponds to the inlined code. */static slang_operation *slang_inline_function_call(slang_assemble_ctx * A, slang_function *fun, slang_operation *oper, slang_operation *returnOper){ typedef enum { SUBST = 1, COPY_IN, COPY_OUT } ParamMode; ParamMode *paramMode; const GLboolean haveRetValue = _slang_function_has_return_value(fun); const GLuint numArgs = oper->num_children; const GLuint totalArgs = numArgs + haveRetValue; slang_operation *args = oper->children; slang_operation *inlined, *top; slang_variable **substOld; slang_operation **substNew; GLuint substCount, numCopyIn, i; slang_function *prevFunction; slang_variable_scope *newScope = NULL; /* save / push */ prevFunction = A->CurFunction; A->CurFunction = fun; /*assert(oper->type == SLANG_OPER_CALL); (or (matrix) multiply, etc) */ assert(fun->param_count == totalArgs); /* allocate temporary arrays */ paramMode = (ParamMode *) _slang_alloc(totalArgs * sizeof(ParamMode)); substOld = (slang_variable **) _slang_alloc(totalArgs * sizeof(slang_variable *)); substNew = (slang_operation **) _slang_alloc(totalArgs * sizeof(slang_operation *));#if 0 printf("\nInline call to %s (total vars=%d nparams=%d)\n", (char *) fun->header.a_name, fun->parameters->num_variables, numArgs);#endif if (haveRetValue && !returnOper) { /* Create 3-child comma sequence for inlined code: * child[0]: declare __resultTmp * child[1]: inlined function body * child[2]: __resultTmp */ slang_operation *commaSeq; slang_operation *declOper = NULL; slang_variable *resultVar; commaSeq = slang_operation_new(1); commaSeq->type = SLANG_OPER_SEQUENCE; assert(commaSeq->locals); commaSeq->locals->outer_scope = oper->locals->outer_scope; commaSeq->num_children = 3; commaSeq->children = slang_operation_new(3); /* allocate the return var */ resultVar = slang_variable_scope_grow(commaSeq->locals); /* printf("Alloc __resultTmp in scope %p for retval of calling %s\n", (void*)commaSeq->locals, (char *) fun->header.a_name); */ resultVar->a_name = slang_atom_pool_atom(A->atoms, "__resultTmp"); resultVar->type = fun->header.type; /* XXX copy? */ resultVar->isTemp = GL_TRUE; /* child[0] = __resultTmp declaration */ declOper = &commaSeq->children[0]; declOper->type = SLANG_OPER_VARIABLE_DECL; declOper->a_id = resultVar->a_name; declOper->locals->outer_scope = commaSeq->locals; /* child[1] = function body */ inlined = &commaSeq->children[1]; inlined->locals->outer_scope = commaSeq->locals; /* child[2] = __resultTmp reference */ returnOper = &commaSeq->children[2]; returnOper->type = SLANG_OPER_IDENTIFIER; returnOper->a_id = resultVar->a_name; returnOper->locals->outer_scope = commaSeq->locals; top = commaSeq; } else { top = inlined = slang_operation_new(1); /* XXXX this may be inappropriate!!!! */ inlined->locals->outer_scope = oper->locals->outer_scope; } assert(inlined->locals); /* Examine the parameters, look for inout/out params, look for possible * substitutions, etc: * param type behaviour * in copy actual to local * const in substitute param with actual * out copy out */ substCount = 0; for (i = 0; i < totalArgs; i++) { slang_variable *p = fun->parameters->variables[i]; /* printf("Param %d: %s %s \n", i, slang_type_qual_string(p->type.qualifier), (char *) p->a_name); */ if (p->type.qualifier == SLANG_QUAL_INOUT || p->type.qualifier == SLANG_QUAL_OUT) { /* an output param */ slang_operation *arg; if (i < numArgs) arg = &args[i]; else arg = returnOper; paramMode[i] = SUBST; if (arg->type == SLANG_OPER_IDENTIFIER) slang_resolve_variable(arg); /* replace parameter 'p' with argument 'arg' */ substOld[substCount] = p; substNew[substCount] = arg; /* will get copied */ substCount++; } else if (p->type.qualifier == SLANG_QUAL_CONST) { /* a constant input param */ if (args[i].type == SLANG_OPER_IDENTIFIER || args[i].type == SLANG_OPER_LITERAL_FLOAT) { /* replace all occurances of this parameter variable with the * actual argument variable or a literal. */ paramMode[i] = SUBST; slang_resolve_variable(&args[i]); substOld[substCount] = p; substNew[substCount] = &args[i]; /* will get copied */ substCount++; } else { paramMode[i] = COPY_IN; } } else { paramMode[i] = COPY_IN; } assert(paramMode[i]); } /* actual code inlining: */ slang_operation_copy(inlined, fun->body); /*** XXX review this */ assert(inlined->type == SLANG_OPER_BLOCK_NO_NEW_SCOPE || inlined->type == SLANG_OPER_BLOCK_NEW_SCOPE); inlined->type = SLANG_OPER_BLOCK_NEW_SCOPE;#if 0 printf("======================= orig body code ======================\n"); printf("=== params scope = %p\n", (void*) fun->parameters); slang_print_tree(fun->body, 8); printf("======================= copied code =========================\n"); slang_print_tree(inlined, 8);#endif /* do parameter substitution in inlined code: */ slang_substitute(A, inlined, substCount, substOld, substNew, GL_FALSE);#if 0 printf("======================= subst code ==========================\n"); slang_print_tree(inlined, 8); printf("=============================================================\n");#endif /* New prolog statements: (inserted before the inlined code) * Copy the 'in' arguments. */ numCopyIn = 0; for (i = 0; i < numArgs; i++) { if (paramMode[i] == COPY_IN) { slang_variable *p = fun->parameters->variables[i]; /* declare parameter 'p' */ slang_operation *decl = slang_operation_insert(&inlined->num_children, &inlined->children, numCopyIn); decl->type = SLANG_OPER_VARIABLE_DECL; assert(decl->locals); decl->locals->outer_scope = inlined->locals; decl->a_id = p->a_name; decl->num_children = 1; decl->children = slang_operation_new(1); /* child[0] is the var's initializer */ slang_operation_copy(&decl->children[0], args + i); /* add parameter 'p' to the local variable scope here */ { slang_variable *pCopy = slang_variable_scope_grow(inlined->locals); pCopy->type = p->type; pCopy->a_name = p->a_name; pCopy->array_len = p->array_len; } newScope = inlined->locals; numCopyIn++; } } /* Now add copies of the function's local vars to the new variable scope */ for (i = totalArgs; i < fun->parameters->num_variables; i++) { slang_variable *p = fun->parameters->variables[i]; slang_variable *pCopy = slang_variable_scope_grow(inlined->locals); pCopy->type = p->type; pCopy->a_name = p->a_name; pCopy->array_len = p->array_len; } /* New epilog statements: * 1. Create end of function label to jump to from return statements. * 2. Copy the 'out' parameter vars */ { slang_operation *lab = slang_operation_insert(&inlined->num_children, &inlined->children, inlined->num_children); lab->type = SLANG_OPER_LABEL; lab->label = A->curFuncEndLabel; } for (i = 0; i < totalArgs; i++) { if (paramMode[i] == COPY_OUT) { const slang_variable *p = fun->parameters->variables[i]; /* actualCallVar = outParam */ /*if (i > 0 || !haveRetValue)*/ slang_operation *ass = slang_operation_insert(&inlined->num_children, &inlined->children, inlined->num_children); ass->type = SLANG_OPER_ASSIGN; ass->num_children = 2; ass->locals->outer_scope = inlined->locals; ass->children = slang_operation_new(2); ass->children[0] = args[i]; /*XXX copy */ ass->children[1].type = SLANG_OPER_IDENTIFIER; ass->children[1].a_id = p->a_name; ass->children[1].locals->outer_scope = ass->locals; } } _slang_free(paramMode); _slang_free(substOld); _slang_free(substNew); /* Update scoping to use the new local vars instead of the * original function's vars. This is especially important * for nested inlining. */ if (newScope) slang_replace_scope(inlined, fun->parameters, newScope);#if 0 printf("Done Inline call to %s (total vars=%d nparams=%d)\n\n", (char *) fun->header.a_name, fun->parameters->num_variables, numArgs); slang_print_tree(top, 0);#endif /* pop */ A->CurFunction = prevFunction; return top;}static slang_ir_node *_slang_gen_function_call(slang_assemble_ctx *A, slang_function *fun, slang_operation *oper, slang_operation *dest){ slang_ir_node *n; slang_operation *inlined; slang_label *prevFuncEndLabel; char name[200]; prevFuncEndLabel = A->curFuncEndLabel; sprintf(name, "__endOfFunc_%s_", (char *) fun->header.a_name); A->curFuncEndLabel = _slang_label_new(name); assert(A->curFuncEndLabel); if (slang_is_asm_function(fun) && !dest) { /* assemble assembly function - tree style */ inlined = slang_inline_asm_function(A, fun, oper); } else { /* non-assembly function */ /* We always generate an "inline-able" block of code here. * We may either: * 1. insert the inline code * 2. Generate a call to the "inline" code as a subroutine */ slang_operation *ret = NULL; inlined = slang_inline_function_call(A, fun, oper, dest); if (!inlined) return NULL; ret = _slang_find_node_type(inlined, SLANG_OPER_RETURN); if (ret) { /* check if this is a "tail" return */ if (_slang_count_node_type(inlined, SLANG_OPER_RETURN) == 1 && _slang_is_tail_return(inlined)) { /* The only RETURN is the last stmt in the function, no-op it * and inline the function body. */ ret->type = SLANG_OPER_NONE; } else { slang_operation *callOper; /* The function we're calling has one or more 'return' statements. * So, we can't truly inline this function because we need to * implement 'return' with RET (and CAL). * Nevertheless, we performed "inlining" to make a new instance * of the function body to deal with static register allocation. * * XXX check if there's one 'return' and if it's the very last * statement in the function - we can optimize that case. */ assert(inlined->type == SLANG_OPER_BLOCK_NEW_SCOPE || inlined->type == SLANG_OPER_SEQUENCE); if (_slang_function_has_return_value(fun) && !dest) { assert(inlined->children[0].type == SLANG_OPER_VARIABLE_DECL); assert(inlined->children[2].type == SLANG_OPER_IDENTIFIER); callOper = &inlined->children[1]; } else { callOper = inlined; } callOper->type = SLANG_OPER_NON_INLINED_CALL; callOper->fun = fun; callOper->label = _slang_label_new_unique((char*) fun->header.a_name); } } } if (!inlined) return NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -