📄 slang_emit.c
字号:
static struct prog_instruction *emit_swizzle(slang_emit_info *emitInfo, slang_ir_node *n){ struct prog_instruction *inst; inst = emit(emitInfo, n->Children[0]); /* setup storage info, if needed */ if (!n->Store->Parent) n->Store->Parent = n->Children[0]->Store; assert(n->Store->Parent); return inst;}/** * Dereference array element. Just resolve storage for the array * element represented by this node. */static struct prog_instruction *emit_array_element(slang_emit_info *emitInfo, slang_ir_node *n){ slang_ir_storage *root; assert(n->Opcode == IR_ELEMENT); assert(n->Store); assert(n->Store->File == PROGRAM_UNDEFINED); assert(n->Store->Parent); assert(n->Store->Size > 0); root = n->Store; while (root->Parent) root = root->Parent; if (root->File == PROGRAM_STATE_VAR) { GLint index = _slang_alloc_statevar(n, emitInfo->prog->Parameters); assert(n->Store->Index == index); return NULL; } /* do codegen for array */ emit(emitInfo, n->Children[0]); if (n->Children[1]->Opcode == IR_FLOAT) { /* Constant array index. * Set Store's index to be the offset of the array element in * the register file. */ const GLint element = (GLint) n->Children[1]->Value[0]; const GLint sz = (n->Store->Size + 3) / 4; /* size in slots/registers */ n->Store->Index = sz * element; assert(n->Store->Parent); } else { /* Variable array index */ struct prog_instruction *inst; /* do codegen for array index expression */ emit(emitInfo, n->Children[1]); inst = new_instruction(emitInfo, OPCODE_ARL); storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask); storage_to_src_reg(&inst->SrcReg[0], n->Children[1]->Store); inst->DstReg.File = PROGRAM_ADDRESS; inst->DstReg.Index = 0; /* always address register [0] */ inst->Comment = _mesa_strdup("ARL ADDR"); n->Store->RelAddr = GL_TRUE; } /* if array element size is one, make sure we only access X */ if (n->Store->Size == 1) n->Store->Swizzle = SWIZZLE_XXXX; return NULL; /* no instruction */}/** * Resolve storage for accessing a structure field. */static struct prog_instruction *emit_struct_field(slang_emit_info *emitInfo, slang_ir_node *n){ slang_ir_storage *root = n->Store; assert(n->Opcode == IR_FIELD); while (root->Parent) root = root->Parent; /* If this is the field of a state var, allocate constant/uniform * storage for it now if we haven't already. * Note that we allocate storage (uniform/constant slots) for state * variables here rather than at declaration time so we only allocate * space for the ones that we actually use! */ if (root->File == PROGRAM_STATE_VAR) { root->Index = _slang_alloc_statevar(n, emitInfo->prog->Parameters); if (root->Index < 0) { slang_info_log_error(emitInfo->log, "Error parsing state variable"); return NULL; } } else { /* do codegen for struct */ emit(emitInfo, n->Children[0]); } return NULL; /* no instruction */}/** * Emit code for a variable declaration. * This usually doesn't result in any code generation, but just * memory allocation. */static struct prog_instruction *emit_var_decl(slang_emit_info *emitInfo, slang_ir_node *n){ struct prog_instruction *inst; assert(n->Store); assert(n->Store->File != PROGRAM_UNDEFINED); assert(n->Store->Size > 0); /*assert(n->Store->Index < 0);*/ if (!n->Var || n->Var->isTemp) { /* a nameless/temporary variable, will be freed after first use */ /*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; } } else { /* a regular variable */ _slang_add_variable(emitInfo->vt, n->Var); if (!_slang_alloc_var(emitInfo->vt, n->Store)) { slang_info_log_error(emitInfo->log, "Ran out of registers, too many variables"); return NULL; } /* printf("IR_VAR_DECL %s %d store %p\n", (char*) n->Var->a_name, n->Store->Index, (void*) n->Store); */ assert(n->Var->aux == n->Store); } if (emitInfo->EmitComments) { /* emit NOP with comment describing the variable's storage location */ char s[1000]; sprintf(s, "TEMP[%d]%s = variable %s (size %d)", n->Store->Index, _mesa_swizzle_string(n->Store->Swizzle, 0, GL_FALSE), (n->Var ? (char *) n->Var->a_name : "anonymous"), n->Store->Size); inst = emit_comment(emitInfo, s); return inst; } return NULL;}/** * Emit code for a reference to a variable. * Actually, no code is generated but we may do some memory alloation. * In particular, state vars (uniforms) are allocated on an as-needed basis. */static struct prog_instruction *emit_var_ref(slang_emit_info *emitInfo, slang_ir_node *n){ assert(n->Store); assert(n->Store->File != PROGRAM_UNDEFINED); if (n->Store->File == PROGRAM_STATE_VAR && n->Store->Index < 0) { n->Store->Index = _slang_alloc_statevar(n, emitInfo->prog->Parameters); } else if (n->Store->File == PROGRAM_UNIFORM) { /* mark var as used */ _mesa_use_uniform(emitInfo->prog->Parameters, (char *) n->Var->a_name); } if (n->Store->Index < 0) { /* probably ran out of registers */ return NULL; } assert(n->Store->Size > 0); return NULL;}static struct prog_instruction *emit(slang_emit_info *emitInfo, slang_ir_node *n){ struct prog_instruction *inst; if (!n) return NULL; if (emitInfo->log->error_flag) { return NULL; } switch (n->Opcode) { case IR_SEQ: /* sequence of two sub-trees */ assert(n->Children[0]); assert(n->Children[1]); emit(emitInfo, n->Children[0]); if (emitInfo->log->error_flag) return NULL; inst = emit(emitInfo, n->Children[1]);#if 0 assert(!n->Store);#endif n->Store = n->Children[1]->Store; return inst; case IR_SCOPE: /* new variable scope */ _slang_push_var_table(emitInfo->vt); inst = emit(emitInfo, n->Children[0]); _slang_pop_var_table(emitInfo->vt); return inst; case IR_VAR_DECL: /* Variable declaration - allocate a register for it */ inst = emit_var_decl(emitInfo, n); return inst; case IR_VAR: /* Reference to a variable * Storage should have already been resolved/allocated. */ return emit_var_ref(emitInfo, n); case IR_ELEMENT: return emit_array_element(emitInfo, n); case IR_FIELD: return emit_struct_field(emitInfo, n); case IR_SWIZZLE: return emit_swizzle(emitInfo, n); /* Simple arithmetic */ /* unary */ case IR_MOVE: case IR_RSQ: case IR_RCP: case IR_FLOOR: case IR_FRAC: case IR_F_TO_I: case IR_I_TO_F: case IR_ABS: case IR_SIN: case IR_COS: case IR_DDX: case IR_DDY: case IR_EXP: case IR_EXP2: case IR_LOG2: case IR_NOISE1: case IR_NOISE2: case IR_NOISE3: case IR_NOISE4: /* binary */ case IR_ADD: case IR_SUB: case IR_MUL: case IR_DOT4: case IR_DOT3: case IR_CROSS: case IR_MIN: case IR_MAX: case IR_SEQUAL: case IR_SNEQUAL: case IR_SGE: case IR_SGT: case IR_SLE: case IR_SLT: case IR_POW: /* trinary operators */ case IR_LRP: return emit_arith(emitInfo, n); case IR_EQUAL: case IR_NOTEQUAL: return emit_compare(emitInfo, n); case IR_CLAMP: return emit_clamp(emitInfo, n); case IR_TEX: case IR_TEXB: case IR_TEXP: return emit_tex(emitInfo, n); case IR_NEG: return emit_negation(emitInfo, n); case IR_FLOAT: /* find storage location for this float constant */ n->Store->Index = _mesa_add_unnamed_constant(emitInfo->prog->Parameters, n->Value, n->Store->Size, &n->Store->Swizzle); if (n->Store->Index < 0) { slang_info_log_error(emitInfo->log, "Ran out of space for constants"); return NULL; } return NULL; case IR_COPY: return emit_copy(emitInfo, n); case IR_COND: return emit_cond(emitInfo, n); case IR_NOT: return emit_not(emitInfo, n); case IR_LABEL: return emit_label(emitInfo, n); case IR_KILL: return emit_kill(emitInfo); case IR_CALL: /* new variable scope for subroutines/function calls */ _slang_push_var_table(emitInfo->vt); inst = emit_fcall(emitInfo, n); _slang_pop_var_table(emitInfo->vt); return inst; case IR_IF: return emit_if(emitInfo, n); case IR_LOOP: return emit_loop(emitInfo, n); case IR_BREAK_IF_TRUE: case IR_CONT_IF_TRUE: return emit_cont_break_if_true(emitInfo, n); case IR_BREAK: /* fall-through */ case IR_CONT: return emit_cont_break(emitInfo, n); case IR_BEGIN_SUB: return new_instruction(emitInfo, OPCODE_BGNSUB); case IR_END_SUB: return new_instruction(emitInfo, OPCODE_ENDSUB); case IR_RETURN: return emit_return(emitInfo, n); case IR_NOP: return NULL; default: _mesa_problem(NULL, "Unexpected IR opcode in emit()\n"); } return NULL;}/** * After code generation, any subroutines will be in separate program * objects. This function appends all the subroutines onto the main * program and resolves the linking of all the branch/call instructions. * XXX this logic should really be part of the linking process... */static void_slang_resolve_subroutines(slang_emit_info *emitInfo){ GET_CURRENT_CONTEXT(ctx); struct gl_program *mainP = emitInfo->prog; GLuint *subroutineLoc, i, total; subroutineLoc = (GLuint *) _mesa_malloc(emitInfo->NumSubroutines * sizeof(GLuint)); /* total number of instructions */ total = mainP->NumInstructions; for (i = 0; i < emitInfo->NumSubroutines; i++) { subroutineLoc[i] = total; total += emitInfo->Subroutines[i]->NumInstructions; } /* adjust BrancTargets within the functions */ for (i = 0; i < emitInfo->NumSubroutines; i++) { struct gl_program *sub = emitInfo->Subroutines[i]; GLuint j; for (j = 0; j < sub->NumInstructions; j++) { struct prog_instruction *inst = sub->Instructions + j; if (inst->Opcode != OPCODE_CAL && inst->BranchTarget >= 0) { inst->BranchTarget += subroutineLoc[i]; } } } /* append subroutines' instructions after main's instructions */ mainP->Instructions = _mesa_realloc_instructions(mainP->Instructions, mainP->NumInstructions, total); mainP->NumInstructions = total; for (i = 0; i < emitInfo->NumSubroutines; i++) { struct gl_program *sub = emitInfo->Subroutines[i]; _mesa_copy_instructions(mainP->Instructions + subroutineLoc[i], sub->Instructions, sub->NumInstructions); /* delete subroutine code */ sub->Parameters = NULL; /* prevent double-free */ _mesa_reference_program(ctx, &emitInfo->Subroutines[i], NULL); } /* free subroutine list */ if (emitInfo->Subroutines) { _mesa_free(emitInfo->Subroutines); emitInfo->Subroutines = NULL; } emitInfo->NumSubroutines = 0; /* Examine CAL instructions. * At this point, the BranchTarget field of the CAL instruction is * the number/id of the subroutine to call (an index into the * emitInfo->Subroutines list). * Translate that into an actual instruction location now. */ for (i = 0; i < mainP->NumInstructions; i++) { struct prog_instruction *inst = mainP->Instructions + i; if (inst->Opcode == OPCODE_CAL) { const GLuint f = inst->BranchTarget; inst->BranchTarget = subroutineLoc[f]; } } _mesa_free(subroutineLoc);}GLboolean_slang_emit_code(slang_ir_node *n, slang_var_table *vt, struct gl_program *prog, GLboolean withEnd, slang_info_log *log){ GET_CURRENT_CONTEXT(ctx); GLboolean success; slang_emit_info emitInfo; GLuint maxUniforms; emitInfo.log = log; emitInfo.vt = vt; emitInfo.prog = prog; emitInfo.Subroutines = NULL; emitInfo.NumSubroutines = 0; emitInfo.EmitHighLevelInstructions = ctx->Shader.EmitHighLevelInstructions; emitInfo.EmitCondCodes = ctx->Shader.EmitCondCodes; emitInfo.EmitComments = ctx->Shader.EmitComments; emitInfo.EmitBeginEndSub = GL_TRUE; if (!emitInfo.EmitCondCodes) { emitInfo.EmitHighLevelInstructions = GL_TRUE; } /* Check uniform/constant limits */ if (prog->Target == GL_FRAGMENT_PROGRAM_ARB) { maxUniforms = ctx->Const.FragmentProgram.MaxUniformComponents / 4; } else { assert(prog->Target == GL_VERTEX_PROGRAM_ARB); maxUniforms = ctx->Const.VertexProgram.MaxUniformComponents / 4; } if (prog->Parameters->NumParameters > maxUniforms) { slang_info_log_error(log, "Constant/uniform register limit exceeded"); return GL_FALSE; } (void) emit(&emitInfo, n); /* finish up by adding the END opcode to program */ if (withEnd) { struct prog_instruction *inst; inst = new_instruction(&emitInfo, OPCODE_END); } _slang_resolve_subroutines(&emitInfo); success = GL_TRUE;#if 0 printf("*********** End emit code (%u inst):\n", prog->NumInstructions); _mesa_print_program(prog); _mesa_print_program_parameters(ctx,prog);#endif return success;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -