⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 slang_emit.c

📁 Mesa is an open-source implementation of the OpenGL specification - a system for rendering interacti
💻 C
📖 第 1 页 / 共 4 页
字号:
   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 + -