📄 slang_emit.c
字号:
return s;#else return NULL;#endif}/** * Emit an instruction that's just a comment. */static struct prog_instruction *emit_comment(slang_emit_info *emitInfo, const char *s){ struct prog_instruction *inst = new_instruction(emitInfo, OPCODE_NOP); if (inst) { inst->Comment = _mesa_strdup(s); } return inst;}/** * Generate code for a simple arithmetic instruction. * Either 1, 2 or 3 operands. */static struct prog_instruction *emit_arith(slang_emit_info *emitInfo, slang_ir_node *n){ struct prog_instruction *inst; const slang_ir_info *info = _slang_ir_info(n->Opcode); char *srcAnnot[3], *dstAnnot; GLuint i; slang_ir_node *temps[3]; /* we'll save pointers to nodes/storage to free in temps[] until * the very end. */ temps[0] = temps[1] = temps[2] = NULL; assert(info); assert(info->InstOpcode != OPCODE_NOP); srcAnnot[0] = srcAnnot[1] = srcAnnot[2] = dstAnnot = NULL;#if PEEPHOLE_OPTIMIZATIONS /* Look for MAD opportunity */ if (info->NumParams == 2 && n->Opcode == IR_ADD && n->Children[0]->Opcode == IR_MUL) { /* found pattern IR_ADD(IR_MUL(A, B), C) */ emit(emitInfo, n->Children[0]->Children[0]); /* A */ emit(emitInfo, n->Children[0]->Children[1]); /* B */ emit(emitInfo, n->Children[1]); /* C */ /* generate MAD instruction */ inst = new_instruction(emitInfo, OPCODE_MAD); /* operands: A, B, C: */ storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Children[0]->Store); storage_to_src_reg(&inst->SrcReg[1], n->Children[0]->Children[1]->Store); storage_to_src_reg(&inst->SrcReg[2], n->Children[1]->Store); temps[0] = n->Children[0]->Children[0]; temps[1] = n->Children[0]->Children[1]; temps[2] = n->Children[1]; } else if (info->NumParams == 2 && n->Opcode == IR_ADD && n->Children[1]->Opcode == IR_MUL) { /* found pattern IR_ADD(A, IR_MUL(B, C)) */ emit(emitInfo, n->Children[0]); /* A */ emit(emitInfo, n->Children[1]->Children[0]); /* B */ emit(emitInfo, n->Children[1]->Children[1]); /* C */ /* generate MAD instruction */ inst = new_instruction(emitInfo, OPCODE_MAD); /* operands: B, C, A */ storage_to_src_reg(&inst->SrcReg[0], n->Children[1]->Children[0]->Store); storage_to_src_reg(&inst->SrcReg[1], n->Children[1]->Children[1]->Store); storage_to_src_reg(&inst->SrcReg[2], n->Children[0]->Store); temps[0] = n->Children[1]->Children[0]; temps[1] = n->Children[1]->Children[1]; temps[2] = n->Children[0]; } else#endif { /* normal case */ /* gen code for children */ for (i = 0; i < info->NumParams; i++) { emit(emitInfo, n->Children[i]); if (!n->Children[i] || !n->Children[i]->Store) { /* error recovery */ return NULL; } } /* gen this instruction and src registers */ inst = new_instruction(emitInfo, info->InstOpcode); for (i = 0; i < info->NumParams; i++) storage_to_src_reg(&inst->SrcReg[i], n->Children[i]->Store); /* annotation */ for (i = 0; i < info->NumParams; i++) srcAnnot[i] = storage_annotation(n->Children[i], emitInfo->prog); /* record (potential) temps to free */ for (i = 0; i < info->NumParams; i++) temps[i] = n->Children[i]; } /* result storage */ alloc_node_storage(emitInfo, n, -1); assert(n->Store->Index >= 0); if (n->Store->Size == 2) n->Writemask = WRITEMASK_XY; else if (n->Store->Size == 3) n->Writemask = WRITEMASK_XYZ; else if (n->Store->Size == 1) n->Writemask = WRITEMASK_X << GET_SWZ(n->Store->Swizzle, 0); storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask); dstAnnot = storage_annotation(n, emitInfo->prog); inst->Comment = instruction_annotation(inst->Opcode, dstAnnot, srcAnnot[0], srcAnnot[1], srcAnnot[2]); /* really free temps now */ for (i = 0; i < 3; i++) if (temps[i]) free_node_storage(emitInfo->vt, temps[i]); /*_mesa_print_instruction(inst);*/ return inst;}/** * Emit code for == and != operators. These could normally be handled * by emit_arith() except we need to be able to handle structure comparisons. */static struct prog_instruction *emit_compare(slang_emit_info *emitInfo, slang_ir_node *n){ struct prog_instruction *inst; GLint size; assert(n->Opcode == IR_EQUAL || n->Opcode == IR_NOTEQUAL); /* gen code for children */ emit(emitInfo, n->Children[0]); emit(emitInfo, n->Children[1]); if (n->Children[0]->Store->Size != n->Children[1]->Store->Size) { slang_info_log_error(emitInfo->log, "invalid operands to == or !="); return NULL; } /* final result is 1 bool */ if (!alloc_node_storage(emitInfo, n, 1)) return NULL; size = n->Children[0]->Store->Size; if (size == 1) { gl_inst_opcode opcode; opcode = n->Opcode == IR_EQUAL ? OPCODE_SEQ : OPCODE_SNE; inst = new_instruction(emitInfo, opcode); storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store); storage_to_src_reg(&inst->SrcReg[1], n->Children[1]->Store); storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask); } else if (size <= 4) { GLuint swizzle; gl_inst_opcode dotOp; slang_ir_storage tempStore; if (!alloc_local_temp(emitInfo, &tempStore, 4)) { return NULL; /* out of temps */ } if (size == 4) { dotOp = OPCODE_DP4; swizzle = SWIZZLE_XYZW; } else if (size == 3) { dotOp = OPCODE_DP3; swizzle = SWIZZLE_XYZW; } else { assert(size == 2); dotOp = OPCODE_DP3; swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y); } /* Compute inequality (temp = (A != B)) */ inst = new_instruction(emitInfo, OPCODE_SNE); storage_to_dst_reg(&inst->DstReg, &tempStore, n->Writemask); storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store); storage_to_src_reg(&inst->SrcReg[1], n->Children[1]->Store); inst->Comment = _mesa_strdup("Compare values"); /* Compute val = DOT(temp, temp) (reduction) */ inst = new_instruction(emitInfo, dotOp); storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask); storage_to_src_reg(&inst->SrcReg[0], &tempStore); storage_to_src_reg(&inst->SrcReg[1], &tempStore); inst->SrcReg[0].Swizzle = inst->SrcReg[1].Swizzle = swizzle; /*override*/ inst->Comment = _mesa_strdup("Reduce vec to bool"); _slang_free_temp(emitInfo->vt, &tempStore); /* free temp */ if (n->Opcode == IR_EQUAL) { /* compute val = !val.x with SEQ val, val, 0; */ inst = new_instruction(emitInfo, OPCODE_SEQ); storage_to_src_reg(&inst->SrcReg[0], n->Store); constant_to_src_reg(&inst->SrcReg[1], 0.0, emitInfo); storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask); inst->Comment = _mesa_strdup("Invert true/false"); } } else { /* size > 4, struct or array compare. * XXX this won't work reliably for structs with padding!! */ GLint i, num = (n->Children[0]->Store->Size + 3) / 4; slang_ir_storage accTemp, sneTemp; if (!alloc_local_temp(emitInfo, &accTemp, 4)) return NULL; if (!alloc_local_temp(emitInfo, &sneTemp, 4)) return NULL; for (i = 0; i < num; i++) { /* SNE sneTemp, left[i], right[i] */ inst = new_instruction(emitInfo, OPCODE_SNE); storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store); storage_to_src_reg(&inst->SrcReg[1], n->Children[1]->Store); inst->SrcReg[0].Index += i; inst->SrcReg[1].Index += i; if (i == 0) { storage_to_dst_reg(&inst->DstReg, &accTemp, WRITEMASK_XYZW); inst->Comment = _mesa_strdup("Begin struct/array comparison"); } else { storage_to_dst_reg(&inst->DstReg, &sneTemp, WRITEMASK_XYZW); /* ADD accTemp, accTemp, sneTemp; # like logical-OR */ inst = new_instruction(emitInfo, OPCODE_ADD); storage_to_dst_reg(&inst->DstReg, &accTemp, WRITEMASK_XYZW); storage_to_src_reg(&inst->SrcReg[0], &accTemp); storage_to_src_reg(&inst->SrcReg[1], &sneTemp); } } /* compute accTemp.x || accTemp.y || accTemp.z || accTemp.w with DOT4 */ inst = new_instruction(emitInfo, OPCODE_DP4); storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask); storage_to_src_reg(&inst->SrcReg[0], &accTemp); storage_to_src_reg(&inst->SrcReg[1], &accTemp); inst->Comment = _mesa_strdup("End struct/array comparison"); if (n->Opcode == IR_EQUAL) { /* compute tmp.x = !tmp.x via tmp.x = (tmp.x == 0) */ inst = new_instruction(emitInfo, OPCODE_SEQ); storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask); storage_to_src_reg(&inst->SrcReg[0], n->Store); constant_to_src_reg(&inst->SrcReg[1], 0.0, emitInfo); inst->Comment = _mesa_strdup("Invert true/false"); } _slang_free_temp(emitInfo->vt, &accTemp); _slang_free_temp(emitInfo->vt, &sneTemp); } /* free temps */ free_node_storage(emitInfo->vt, n->Children[0]); free_node_storage(emitInfo->vt, n->Children[1]); return inst;}/** * Generate code for an IR_CLAMP instruction. */static struct prog_instruction *emit_clamp(slang_emit_info *emitInfo, slang_ir_node *n){ struct prog_instruction *inst; slang_ir_node tmpNode; assert(n->Opcode == IR_CLAMP); /* ch[0] = value * ch[1] = min limit * ch[2] = max limit */ inst = emit(emitInfo, n->Children[0]); /* If lower limit == 0.0 and upper limit == 1.0, * set prev instruction's SaturateMode field to SATURATE_ZERO_ONE. * Else, * emit OPCODE_MIN, OPCODE_MAX sequence. */#if 0 /* XXX this isn't quite finished yet */ if (n->Children[1]->Opcode == IR_FLOAT && n->Children[1]->Value[0] == 0.0 && n->Children[1]->Value[1] == 0.0 && n->Children[1]->Value[2] == 0.0 && n->Children[1]->Value[3] == 0.0 && n->Children[2]->Opcode == IR_FLOAT && n->Children[2]->Value[0] == 1.0 && n->Children[2]->Value[1] == 1.0 && n->Children[2]->Value[2] == 1.0 && n->Children[2]->Value[3] == 1.0) { if (!inst) { inst = prev_instruction(prog); } if (inst && inst->Opcode != OPCODE_NOP) { /* and prev instruction's DstReg matches n->Children[0]->Store */ inst->SaturateMode = SATURATE_ZERO_ONE; n->Store = n->Children[0]->Store; return inst; } }#endif if (!alloc_node_storage(emitInfo, n, n->Children[0]->Store->Size)) return NULL; emit(emitInfo, n->Children[1]); emit(emitInfo, n->Children[2]); /* Some GPUs don't allow reading from output registers. So if the * dest for this clamp() is an output reg, we can't use that reg for * the intermediate result. Use a temp register instead. */ _mesa_bzero(&tmpNode, sizeof(tmpNode)); alloc_node_storage(emitInfo, &tmpNode, n->Store->Size); /* tmp = max(ch[0], ch[1]) */ inst = new_instruction(emitInfo, OPCODE_MAX); storage_to_dst_reg(&inst->DstReg, tmpNode.Store, n->Writemask); storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store); storage_to_src_reg(&inst->SrcReg[1], n->Children[1]->Store); /* n->dest = min(tmp, ch[2]) */ inst = new_instruction(emitInfo, OPCODE_MIN); storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask); storage_to_src_reg(&inst->SrcReg[0], tmpNode.Store); storage_to_src_reg(&inst->SrcReg[1], n->Children[2]->Store); free_node_storage(emitInfo->vt, &tmpNode); return inst;}static struct prog_instruction *emit_negation(slang_emit_info *emitInfo, slang_ir_node *n){ /* Implement as MOV dst, -src; */ /* XXX we could look at the previous instruction and in some circumstances * modify it to accomplish the negation. */ struct prog_instruction *inst; emit(emitInfo, n->Children[0]); if (!alloc_node_storage(emitInfo, n, n->Children[0]->Store->Size)) return NULL; inst = new_instruction(emitInfo, OPCODE_MOV); storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask); storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store); inst->SrcReg[0].NegateBase = NEGATE_XYZW; return inst;}static struct prog_instruction *emit_label(slang_emit_info *emitInfo, const slang_ir_node *n){ assert(n->Label);#if 0 /* XXX this fails in loop tail code - investigate someday */ assert(_slang_label_get_location(n->Label) < 0); _slang_label_set_location(n->Label, emitInfo->prog->NumInstructions, emitInfo->prog);#else if (_slang_label_get_location(n->Label) < 0) _slang_label_set_location(n->Label, emitInfo->prog->NumInstructions, emitInfo->prog);#endif return NULL;}/** * Emit code for a function call. * Note that for each time a function is called, we emit the function's * body code again because the set of available registers may be different. */static struct prog_instruction *emit_fcall(slang_emit_info *emitInfo, slang_ir_node *n){ struct gl_program *progSave; struct prog_instruction *inst; GLuint subroutineId; assert(n->Opcode == IR_CALL); assert(n->Label); /* save/push cur program */ progSave = emitInfo->prog; emitInfo->prog = new_subroutine(emitInfo, &subroutineId); _slang_label_set_location(n->Label, emitInfo->prog->NumInstructions, emitInfo->prog); if (emitInfo->EmitBeginEndSub) { /* BGNSUB isn't a real instruction. * We require a label (i.e. "foobar:") though, if we're going to * print the program in the NV format. The BNGSUB instruction is * really just a NOP to attach the label to. */ inst = new_instruction(emitInfo, OPCODE_BGNSUB); inst->Comment = _mesa_strdup(n->Label->Name); } /* body of function: */ emit(emitInfo, n->Children[0]); n->Store = n->Children[0]->Store; /* add RET instruction now, if needed */ inst = prev_instruction(emitInfo); if (inst && inst->Opcode != OPCODE_RET) { inst = new_instruction(emitInfo, OPCODE_RET); } if (emitInfo->EmitBeginEndSub) { inst = new_instruction(emitInfo, OPCODE_ENDSUB); inst->Comment = _mesa_strdup(n->Label->Name); } /* pop/restore cur program */ emitInfo->prog = progSave; /* emit the function call */ inst = new_instruction(emitInfo, OPCODE_CAL); /* The branch target is just the subroutine number (changed later) */ inst->BranchTarget = subroutineId; inst->Comment = _mesa_strdup(n->Label->Name); assert(inst->BranchTarget >= 0); return inst;}/** * Emit code for a 'return' statement. */static struct prog_instruction *emit_return(slang_emit_info *emitInfo, slang_ir_node *n){ struct prog_instruction *inst; assert(n); assert(n->Opcode == IR_RETURN); assert(n->Label); inst = new_instruction(emitInfo, OPCODE_RET); inst->DstReg.CondMask = COND_TR; /* always return */ return inst;}static struct prog_instruction *emit_kill(slang_emit_info *emitInfo){ struct gl_fragment_program *fp; struct prog_instruction *inst; /* NV-KILL - discard fragment depending on condition code. * Note that ARB-KILL depends on sign of vector operand. */ inst = new_instruction(emitInfo, OPCODE_KIL_NV); inst->DstReg.CondMask = COND_TR; /* always kill */ assert(emitInfo->prog->Target == GL_FRAGMENT_PROGRAM_ARB); fp = (struct gl_fragment_program *) emitInfo->prog; fp->UsesKill = GL_TRUE; return inst;}static struct prog_instruction *emit_tex(slang_emit_info *emitInfo, slang_ir_node *n){ struct prog_instruction *inst; (void) emit(emitInfo, n->Children[1]); if (n->Opcode == IR_TEX) { inst = new_instruction(emitInfo, OPCODE_TEX);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -