📄 slang_emit.c
字号:
/* * Mesa 3-D graphics library * Version: 7.1 * * Copyright (C) 2005-2008 Brian Paul All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *//** * \file slang_emit.c * Emit program instructions (PI code) from IR trees. * \author Brian Paul *//*** *** NOTES *** *** To emit GPU instructions, we basically just do an in-order traversal *** of the IR tree. ***/#include "main/imports.h"#include "main/context.h"#include "main/macros.h"#include "shader/program.h"#include "shader/prog_instruction.h"#include "shader/prog_parameter.h"#include "shader/prog_print.h"#include "slang_builtin.h"#include "slang_emit.h"#include "slang_mem.h"#define PEEPHOLE_OPTIMIZATIONS 1#define ANNOTATE 0typedef struct{ slang_info_log *log; slang_var_table *vt; struct gl_program *prog; struct gl_program **Subroutines; GLuint NumSubroutines; /* code-gen options */ GLboolean EmitHighLevelInstructions; GLboolean EmitCondCodes; GLboolean EmitComments; GLboolean EmitBeginEndSub; /* XXX TEMPORARY */} slang_emit_info;static struct gl_program *new_subroutine(slang_emit_info *emitInfo, GLuint *id){ GET_CURRENT_CONTEXT(ctx); const GLuint n = emitInfo->NumSubroutines; emitInfo->Subroutines = (struct gl_program **) _mesa_realloc(emitInfo->Subroutines, n * sizeof(struct gl_program), (n + 1) * sizeof(struct gl_program)); emitInfo->Subroutines[n] = ctx->Driver.NewProgram(ctx, emitInfo->prog->Target, 0); emitInfo->Subroutines[n]->Parameters = emitInfo->prog->Parameters; emitInfo->NumSubroutines++; *id = n; return emitInfo->Subroutines[n];}/** * Convert a writemask to a swizzle. Used for testing cond codes because * we only want to test the cond code component(s) that was set by the * previous instruction. */static GLuintwritemask_to_swizzle(GLuint writemask){ if (writemask == WRITEMASK_X) return SWIZZLE_XXXX; if (writemask == WRITEMASK_Y) return SWIZZLE_YYYY; if (writemask == WRITEMASK_Z) return SWIZZLE_ZZZZ; if (writemask == WRITEMASK_W) return SWIZZLE_WWWW; return SWIZZLE_XYZW; /* shouldn't be hit */}/** * Swizzle a swizzle (function composition). * That is, return swz2(swz1), or said another way: swz1.szw2 * Example: swizzle_swizzle(".zwxx", ".xxyw") yields ".zzwx" */GLuint_slang_swizzle_swizzle(GLuint swz1, GLuint swz2){ GLuint i, swz, s[4]; for (i = 0; i < 4; i++) { GLuint c = GET_SWZ(swz2, i); if (c <= SWIZZLE_W) s[i] = GET_SWZ(swz1, c); else s[i] = c; } swz = MAKE_SWIZZLE4(s[0], s[1], s[2], s[3]); return swz;}/** * Allocate storage for the given node (if it hasn't already been allocated). * * Typically this is temporary storage for an intermediate result (such as * for a multiply or add, etc). * * If n->Store does not exist it will be created and will be of the size * specified by defaultSize. */static GLbooleanalloc_node_storage(slang_emit_info *emitInfo, slang_ir_node *n, GLint defaultSize){ assert(!n->Var); if (!n->Store) { assert(defaultSize > 0); n->Store = _slang_new_ir_storage(PROGRAM_TEMPORARY, -1, defaultSize); } /* now allocate actual register(s). I.e. set n->Store->Index >= 0 */ if (n->Store->Index < 0) { if (!_slang_alloc_temp(emitInfo->vt, n->Store)) { slang_info_log_error(emitInfo->log, "Ran out of registers, too many temporaries"); _slang_free(n->Store); n->Store = NULL; return GL_FALSE; } } return GL_TRUE;}/** * Free temporary storage, if n->Store is, in fact, temp storage. * Otherwise, no-op. */static voidfree_node_storage(slang_var_table *vt, slang_ir_node *n){ if (n->Store->File == PROGRAM_TEMPORARY && n->Store->Index >= 0 && n->Opcode != IR_SWIZZLE) { if (_slang_is_temp(vt, n->Store)) { _slang_free_temp(vt, n->Store); n->Store->Index = -1; n->Store = NULL; /* XXX this may not be needed */ } }}/** * Helper function to allocate a short-term temporary. * Free it with _slang_free_temp(). */static GLbooleanalloc_local_temp(slang_emit_info *emitInfo, slang_ir_storage *temp, GLint size){ assert(size >= 1); assert(size <= 4); _mesa_bzero(temp, sizeof(*temp)); temp->Size = size; temp->File = PROGRAM_TEMPORARY; temp->Index = -1; return _slang_alloc_temp(emitInfo->vt, temp);}/** * Remove any SWIZZLE_NIL terms from given swizzle mask. * For a swizzle like .z??? generate .zzzz (replicate single component). * Else, for .wx?? generate .wxzw (insert default component for the position). */static GLuintfix_swizzle(GLuint swizzle){ GLuint c0 = GET_SWZ(swizzle, 0), c1 = GET_SWZ(swizzle, 1), c2 = GET_SWZ(swizzle, 2), c3 = GET_SWZ(swizzle, 3); if (c1 == SWIZZLE_NIL && c2 == SWIZZLE_NIL && c3 == SWIZZLE_NIL) { /* smear first component across all positions */ c1 = c2 = c3 = c0; } else { /* insert default swizzle components */ if (c0 == SWIZZLE_NIL) c0 = SWIZZLE_X; if (c1 == SWIZZLE_NIL) c1 = SWIZZLE_Y; if (c2 == SWIZZLE_NIL) c2 = SWIZZLE_Z; if (c3 == SWIZZLE_NIL) c3 = SWIZZLE_W; } return MAKE_SWIZZLE4(c0, c1, c2, c3);}/** * Convert IR storage to an instruction dst register. */static voidstorage_to_dst_reg(struct prog_dst_register *dst, const slang_ir_storage *st, GLuint writemask){ const GLint size = st->Size; GLint index = st->Index; GLuint swizzle = st->Swizzle; /* if this is storage relative to some parent storage, walk up the tree */ while (st->Parent) { st = st->Parent; index += st->Index; swizzle = _slang_swizzle_swizzle(st->Swizzle, swizzle); } assert(st->File != PROGRAM_UNDEFINED); dst->File = st->File; assert(index >= 0); dst->Index = index; assert(size >= 1); assert(size <= 4); if (size == 1) { GLuint comp = GET_SWZ(swizzle, 0); assert(comp < 4); dst->WriteMask = WRITEMASK_X << comp; } else { dst->WriteMask = writemask; }}/** * Convert IR storage to an instruction src register. */static voidstorage_to_src_reg(struct prog_src_register *src, const slang_ir_storage *st){ const GLboolean relAddr = st->RelAddr; GLint index = st->Index; GLuint swizzle = st->Swizzle; /* if this is storage relative to some parent storage, walk up the tree */ while (st->Parent) { st = st->Parent; index += st->Index; swizzle = _slang_swizzle_swizzle(fix_swizzle(st->Swizzle), swizzle); } assert(st->File >= 0);#if 1 /* XXX temporary */ if (st->File == PROGRAM_UNDEFINED) { slang_ir_storage *st0 = (slang_ir_storage *) st; st0->File = PROGRAM_TEMPORARY; }#endif assert(st->File < PROGRAM_UNDEFINED); src->File = st->File; assert(index >= 0); src->Index = index; swizzle = fix_swizzle(swizzle); assert(GET_SWZ(swizzle, 0) <= SWIZZLE_W); assert(GET_SWZ(swizzle, 1) <= SWIZZLE_W); assert(GET_SWZ(swizzle, 2) <= SWIZZLE_W); assert(GET_SWZ(swizzle, 3) <= SWIZZLE_W); src->Swizzle = swizzle; src->RelAddr = relAddr;}/* * Setup an instrucion src register to point to a scalar constant. */static voidconstant_to_src_reg(struct prog_src_register *src, GLfloat val, slang_emit_info *emitInfo){ GLuint zeroSwizzle; GLint zeroReg; GLfloat value[4]; value[0] = val; zeroReg = _mesa_add_unnamed_constant(emitInfo->prog->Parameters, value, 1, &zeroSwizzle); assert(zeroReg >= 0); src->File = PROGRAM_CONSTANT; src->Index = zeroReg; src->Swizzle = zeroSwizzle;}/** * Add new instruction at end of given program. * \param prog the program to append instruction onto * \param opcode opcode for the new instruction * \return pointer to the new instruction */static struct prog_instruction *new_instruction(slang_emit_info *emitInfo, gl_inst_opcode opcode){ struct gl_program *prog = emitInfo->prog; struct prog_instruction *inst;#if 0 /* print prev inst */ if (prog->NumInstructions > 0) { _mesa_print_instruction(prog->Instructions + prog->NumInstructions - 1); }#endif prog->Instructions = _mesa_realloc_instructions(prog->Instructions, prog->NumInstructions, prog->NumInstructions + 1); inst = prog->Instructions + prog->NumInstructions; prog->NumInstructions++; _mesa_init_instructions(inst, 1); inst->Opcode = opcode; inst->BranchTarget = -1; /* invalid */ /* printf("New inst %d: %p %s\n", prog->NumInstructions-1,(void*)inst, _mesa_opcode_string(inst->Opcode)); */ return inst;}/** * Return pointer to last instruction in program. */static struct prog_instruction *prev_instruction(slang_emit_info *emitInfo){ struct gl_program *prog = emitInfo->prog; if (prog->NumInstructions == 0) return NULL; else return prog->Instructions + prog->NumInstructions - 1;}static struct prog_instruction *emit(slang_emit_info *emitInfo, slang_ir_node *n);/** * Return an annotation string for given node's storage. */static char *storage_annotation(const slang_ir_node *n, const struct gl_program *prog){#if ANNOTATE const slang_ir_storage *st = n->Store; static char s[100] = ""; if (!st) return _mesa_strdup(""); switch (st->File) { case PROGRAM_CONSTANT: if (st->Index >= 0) { const GLfloat *val = prog->Parameters->ParameterValues[st->Index]; if (st->Swizzle == SWIZZLE_NOOP) sprintf(s, "{%g, %g, %g, %g}", val[0], val[1], val[2], val[3]); else { sprintf(s, "%g", val[GET_SWZ(st->Swizzle, 0)]); } } break; case PROGRAM_TEMPORARY: if (n->Var) sprintf(s, "%s", (char *) n->Var->a_name); else sprintf(s, "t[%d]", st->Index); break; case PROGRAM_STATE_VAR: case PROGRAM_UNIFORM: sprintf(s, "%s", prog->Parameters->Parameters[st->Index].Name); break; case PROGRAM_VARYING: sprintf(s, "%s", prog->Varying->Parameters[st->Index].Name); break; case PROGRAM_INPUT: sprintf(s, "input[%d]", st->Index); break; case PROGRAM_OUTPUT: sprintf(s, "output[%d]", st->Index); break; default: s[0] = 0; } return _mesa_strdup(s);#else return NULL;#endif}/** * Return an annotation string for an instruction. */static char *instruction_annotation(gl_inst_opcode opcode, char *dstAnnot, char *srcAnnot0, char *srcAnnot1, char *srcAnnot2){#if ANNOTATE const char *operator; char *s; int len = 50; if (dstAnnot) len += strlen(dstAnnot); else dstAnnot = _mesa_strdup(""); if (srcAnnot0) len += strlen(srcAnnot0); else srcAnnot0 = _mesa_strdup(""); if (srcAnnot1) len += strlen(srcAnnot1); else srcAnnot1 = _mesa_strdup(""); if (srcAnnot2) len += strlen(srcAnnot2); else srcAnnot2 = _mesa_strdup(""); switch (opcode) { case OPCODE_ADD: operator = "+"; break; case OPCODE_SUB: operator = "-"; break; case OPCODE_MUL: operator = "*"; break; case OPCODE_DP3: operator = "DP3"; break; case OPCODE_DP4: operator = "DP4"; break; case OPCODE_XPD: operator = "XPD"; break; case OPCODE_RSQ: operator = "RSQ"; break; case OPCODE_SGT: operator = ">"; break; default: operator = ","; } s = (char *) malloc(len); sprintf(s, "%s = %s %s %s %s", dstAnnot, srcAnnot0, operator, srcAnnot1, srcAnnot2); assert(_mesa_strlen(s) < len); free(dstAnnot); free(srcAnnot0); free(srcAnnot1); free(srcAnnot2);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -