📄 slang_codegen.c
字号:
{ "float_cosine", IR_COS, 1, 1 }, { "float_noise1", IR_NOISE1, 1, 1}, { "float_noise2", IR_NOISE2, 1, 1}, { "float_noise3", IR_NOISE3, 1, 1}, { "float_noise4", IR_NOISE4, 1, 1}, { NULL, IR_NOP, 0, 0 }};static slang_ir_node *new_node3(slang_ir_opcode op, slang_ir_node *c0, slang_ir_node *c1, slang_ir_node *c2){ slang_ir_node *n = (slang_ir_node *) _slang_alloc(sizeof(slang_ir_node)); if (n) { n->Opcode = op; n->Children[0] = c0; n->Children[1] = c1; n->Children[2] = c2; n->Writemask = WRITEMASK_XYZW; n->InstLocation = -1; } return n;}static slang_ir_node *new_node2(slang_ir_opcode op, slang_ir_node *c0, slang_ir_node *c1){ return new_node3(op, c0, c1, NULL);}static slang_ir_node *new_node1(slang_ir_opcode op, slang_ir_node *c0){ return new_node3(op, c0, NULL, NULL);}static slang_ir_node *new_node0(slang_ir_opcode op){ return new_node3(op, NULL, NULL, NULL);}/** * Create sequence of two nodes. */static slang_ir_node *new_seq(slang_ir_node *left, slang_ir_node *right){ if (!left) return right; if (!right) return left; return new_node2(IR_SEQ, left, right);}static slang_ir_node *new_label(slang_label *label){ slang_ir_node *n = new_node0(IR_LABEL); assert(label); if (n) n->Label = label; return n;}static slang_ir_node *new_float_literal(const float v[4], GLuint size){ slang_ir_node *n = new_node0(IR_FLOAT); assert(size <= 4); COPY_4V(n->Value, v); /* allocate a storage object, but compute actual location (Index) later */ n->Store = _slang_new_ir_storage(PROGRAM_CONSTANT, -1, size); return n;}static slang_ir_node *new_not(slang_ir_node *n){ return new_node1(IR_NOT, n);}/** * Non-inlined function call. */static slang_ir_node *new_function_call(slang_ir_node *code, slang_label *name){ slang_ir_node *n = new_node1(IR_CALL, code); assert(name); if (n) n->Label = name; return n;}/** * Unconditional jump. */static slang_ir_node *new_return(slang_label *dest){ slang_ir_node *n = new_node0(IR_RETURN); assert(dest); if (n) n->Label = dest; return n;}static slang_ir_node *new_loop(slang_ir_node *body){ return new_node1(IR_LOOP, body);}static slang_ir_node *new_break(slang_ir_node *loopNode){ slang_ir_node *n = new_node0(IR_BREAK); assert(loopNode); assert(loopNode->Opcode == IR_LOOP); if (n) { /* insert this node at head of linked list */ n->List = loopNode->List; loopNode->List = n; } return n;}/** * Make new IR_BREAK_IF_TRUE. */static slang_ir_node *new_break_if_true(slang_ir_node *loopNode, slang_ir_node *cond){ slang_ir_node *n; assert(loopNode); assert(loopNode->Opcode == IR_LOOP); n = new_node1(IR_BREAK_IF_TRUE, cond); if (n) { /* insert this node at head of linked list */ n->List = loopNode->List; loopNode->List = n; } return n;}/** * Make new IR_CONT_IF_TRUE node. */static slang_ir_node *new_cont_if_true(slang_ir_node *loopNode, slang_ir_node *cond){ slang_ir_node *n; assert(loopNode); assert(loopNode->Opcode == IR_LOOP); n = new_node1(IR_CONT_IF_TRUE, cond); if (n) { /* insert this node at head of linked list */ n->List = loopNode->List; loopNode->List = n; } return n;}static slang_ir_node *new_cond(slang_ir_node *n){ slang_ir_node *c = new_node1(IR_COND, n); return c;}static slang_ir_node *new_if(slang_ir_node *cond, slang_ir_node *ifPart, slang_ir_node *elsePart){ return new_node3(IR_IF, cond, ifPart, elsePart);}/** * New IR_VAR node - a reference to a previously declared variable. */static slang_ir_node *new_var(slang_assemble_ctx *A, slang_operation *oper, slang_atom name){ slang_ir_node *n; slang_variable *var = _slang_locate_variable(oper->locals, name, GL_TRUE); if (!var) return NULL; assert(var->declared); assert(!oper->var || oper->var == var); n = new_node0(IR_VAR); if (n) { _slang_attach_storage(n, var); /* printf("new_var %s store=%p\n", (char*)name, (void*) n->Store); */ } return n;}/** * Check if the given function is really just a wrapper for a * basic assembly instruction. */static GLbooleanslang_is_asm_function(const slang_function *fun){ if (fun->body->type == SLANG_OPER_BLOCK_NO_NEW_SCOPE && fun->body->num_children == 1 && fun->body->children[0].type == SLANG_OPER_ASM) { return GL_TRUE; } return GL_FALSE;}static GLboolean_slang_is_noop(const slang_operation *oper){ if (!oper || oper->type == SLANG_OPER_VOID || (oper->num_children == 1 && oper->children[0].type == SLANG_OPER_VOID)) return GL_TRUE; else return GL_FALSE;}/** * 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;}/** * Count the number of operations of the given time rooted at 'oper'. */static GLuint_slang_count_node_type(slang_operation *oper, slang_operation_type type){ GLuint i, count = 0; if (oper->type == type) { return 1; } for (i = 0; i < oper->num_children; i++) { count += _slang_count_node_type(&oper->children[i], type); } return count;}/** * Check if the 'return' statement found under 'oper' is a "tail return" * that can be no-op'd. For example: * * void func(void) * { * .. do something .. * return; // this is a no-op * } * * This is used when determining if a function can be inlined. If the * 'return' is not the last statement, we can't inline the function since * we still need the semantic behaviour of the 'return' but we don't want * to accidentally return from the _calling_ function. We'd need to use an * unconditional branch, but we don't have such a GPU instruction (not * always, at least). */static GLboolean_slang_is_tail_return(const slang_operation *oper){ GLuint k = oper->num_children; while (k > 0) { const slang_operation *last = &oper->children[k - 1]; if (last->type == SLANG_OPER_RETURN) return GL_TRUE; else if (last->type == SLANG_OPER_IDENTIFIER || last->type == SLANG_OPER_LABEL) k--; /* try prev child */ else if (last->type == SLANG_OPER_BLOCK_NO_NEW_SCOPE || last->type == SLANG_OPER_BLOCK_NEW_SCOPE) /* try sub-children */ return _slang_is_tail_return(last); else break; } return GL_FALSE;}static voidslang_resolve_variable(slang_operation *oper){ if (oper->type == SLANG_OPER_IDENTIFIER && !oper->var) { oper->var = _slang_locate_variable(oper->locals, oper->a_id, GL_TRUE); }}/** * Replace particular variables (SLANG_OPER_IDENTIFIER) with new expressions. */static voidslang_substitute(slang_assemble_ctx *A, slang_operation *oper, GLuint substCount, slang_variable **substOld, slang_operation **substNew, GLboolean isLHS){ switch (oper->type) { case SLANG_OPER_VARIABLE_DECL: { slang_variable *v = _slang_locate_variable(oper->locals, oper->a_id, GL_TRUE); assert(v); if (v->initializer && oper->num_children == 0) { /* set child of oper to copy of initializer */ oper->num_children = 1; oper->children = slang_operation_new(1); slang_operation_copy(&oper->children[0], v->initializer); } if (oper->num_children == 1) { /* the initializer */ slang_substitute(A, &oper->children[0], substCount, substOld, substNew, GL_FALSE); } } break; case SLANG_OPER_IDENTIFIER: assert(oper->num_children == 0); if (1/**!isLHS XXX FIX */) { slang_atom id = oper->a_id; slang_variable *v; GLuint i; v = _slang_locate_variable(oper->locals, id, GL_TRUE); if (!v) { _mesa_problem(NULL, "var %s not found!\n", (char *) oper->a_id); return; } /* look for a substitution */ for (i = 0; i < substCount; i++) { if (v == substOld[i]) { /* OK, replace this SLANG_OPER_IDENTIFIER with a new expr */#if 0 /* DEBUG only */ if (substNew[i]->type == SLANG_OPER_IDENTIFIER) { assert(substNew[i]->var); assert(substNew[i]->var->a_name); printf("Substitute %s with %s in id node %p\n", (char*)v->a_name, (char*) substNew[i]->var->a_name, (void*) oper); } else { printf("Substitute %s with %f in id node %p\n", (char*)v->a_name, substNew[i]->literal[0], (void*) oper); }#endif slang_operation_copy(oper, substNew[i]); break; } } } break; case SLANG_OPER_RETURN: /* do return replacement here too */ assert(oper->num_children == 0 || oper->num_children == 1); if (oper->num_children == 1 && !_slang_is_noop(&oper->children[0])) { /* replace: * return expr; * with: * __retVal = expr; * return; * 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; blockOper->locals->outer_scope = oper->locals->outer_scope; blockOper->children = slang_operation_new(2); assignOper = blockOper->children + 0; returnOper = blockOper->children + 1; assignOper->type = SLANG_OPER_ASSIGN; assignOper->num_children = 2; assignOper->locals->outer_scope = blockOper->locals; assignOper->children = slang_operation_new(2); assignOper->children[0].type = SLANG_OPER_IDENTIFIER; assignOper->children[0].a_id = slang_atom_pool_atom(A->atoms, "__retVal"); assignOper->children[0].locals->outer_scope = assignOper->locals; slang_operation_copy(&assignOper->children[1], &oper->children[0]); returnOper->type = SLANG_OPER_RETURN; /* return w/ no value */ assert(returnOper->num_children == 0); /* do substitutions on the "__retVal = expr" sub-tree */ slang_substitute(A, assignOper, substCount, substOld, substNew, GL_FALSE); /* install new code */ 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: case SLANG_OPER_SUBSCRIPT: /* special case: * child[0] can't have substitutions but child[1] can. */ slang_substitute(A, &oper->children[0],
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -