1 /*
2  * Mesa 3-D graphics library
3  * Version:  7.3
4  *
5  * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
6  * Copyright (C) 1999-2009  VMware, Inc.  All Rights Reserved.
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the "Software"),
10  * to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons to whom the
13  * Software is furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included
16  * in all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25 
26 
27 #include "main/glheader.h"
28 #include "main/imports.h"
29 #include "main/mtypes.h"
30 #include "prog_instruction.h"
31 
32 
33 /**
34  * Initialize program instruction fields to defaults.
35  * \param inst  first instruction to initialize
36  * \param count  number of instructions to initialize
37  */
38 void
_mesa_init_instructions(struct prog_instruction * inst,GLuint count)39 _mesa_init_instructions(struct prog_instruction *inst, GLuint count)
40 {
41    GLuint i;
42 
43    memset(inst, 0, count * sizeof(struct prog_instruction));
44 
45    for (i = 0; i < count; i++) {
46       inst[i].SrcReg[0].File = PROGRAM_UNDEFINED;
47       inst[i].SrcReg[0].Swizzle = SWIZZLE_NOOP;
48       inst[i].SrcReg[1].File = PROGRAM_UNDEFINED;
49       inst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP;
50       inst[i].SrcReg[2].File = PROGRAM_UNDEFINED;
51       inst[i].SrcReg[2].Swizzle = SWIZZLE_NOOP;
52 
53       inst[i].DstReg.File = PROGRAM_UNDEFINED;
54       inst[i].DstReg.WriteMask = WRITEMASK_XYZW;
55       inst[i].DstReg.CondMask = COND_TR;
56       inst[i].DstReg.CondSwizzle = SWIZZLE_NOOP;
57 
58       inst[i].SaturateMode = SATURATE_OFF;
59       inst[i].Precision = FLOAT32;
60    }
61 }
62 
63 
64 /**
65  * Allocate an array of program instructions.
66  * \param numInst  number of instructions
67  * \return pointer to instruction memory
68  */
69 struct prog_instruction *
_mesa_alloc_instructions(GLuint numInst)70 _mesa_alloc_instructions(GLuint numInst)
71 {
72    return (struct prog_instruction *)
73       calloc(1, numInst * sizeof(struct prog_instruction));
74 }
75 
76 
77 /**
78  * Reallocate memory storing an array of program instructions.
79  * This is used when we need to append additional instructions onto an
80  * program.
81  * \param oldInst  pointer to first of old/src instructions
82  * \param numOldInst  number of instructions at <oldInst>
83  * \param numNewInst  desired size of new instruction array.
84  * \return  pointer to start of new instruction array.
85  */
86 struct prog_instruction *
_mesa_realloc_instructions(struct prog_instruction * oldInst,GLuint numOldInst,GLuint numNewInst)87 _mesa_realloc_instructions(struct prog_instruction *oldInst,
88                            GLuint numOldInst, GLuint numNewInst)
89 {
90    struct prog_instruction *newInst;
91 
92    newInst = (struct prog_instruction *)
93       _mesa_realloc(oldInst,
94                     numOldInst * sizeof(struct prog_instruction),
95                     numNewInst * sizeof(struct prog_instruction));
96 
97    return newInst;
98 }
99 
100 
101 /**
102  * Copy an array of program instructions.
103  * \param dest  pointer to destination.
104  * \param src  pointer to source.
105  * \param n  number of instructions to copy.
106  * \return pointer to destination.
107  */
108 struct prog_instruction *
_mesa_copy_instructions(struct prog_instruction * dest,const struct prog_instruction * src,GLuint n)109 _mesa_copy_instructions(struct prog_instruction *dest,
110                         const struct prog_instruction *src, GLuint n)
111 {
112    GLuint i;
113    memcpy(dest, src, n * sizeof(struct prog_instruction));
114    for (i = 0; i < n; i++) {
115       if (src[i].Comment)
116          dest[i].Comment = _mesa_strdup(src[i].Comment);
117    }
118    return dest;
119 }
120 
121 
122 /**
123  * Free an array of instructions
124  */
125 void
_mesa_free_instructions(struct prog_instruction * inst,GLuint count)126 _mesa_free_instructions(struct prog_instruction *inst, GLuint count)
127 {
128    GLuint i;
129    for (i = 0; i < count; i++) {
130       if (inst[i].Data)
131          free(inst[i].Data);
132       if (inst[i].Comment)
133          free((char *) inst[i].Comment);
134    }
135    free(inst);
136 }
137 
138 
139 /**
140  * Basic info about each instruction
141  */
142 struct instruction_info
143 {
144    gl_inst_opcode Opcode;
145    const char *Name;
146    GLuint NumSrcRegs;
147    GLuint NumDstRegs;
148 };
149 
150 /**
151  * Instruction info
152  * \note Opcode should equal array index!
153  */
154 static const struct instruction_info InstInfo[MAX_OPCODE] = {
155    { OPCODE_NOP,    "NOP",     0, 0 },
156    { OPCODE_ABS,    "ABS",     1, 1 },
157    { OPCODE_ADD,    "ADD",     2, 1 },
158    { OPCODE_AND,    "AND",     2, 1 },
159    { OPCODE_ARA,    "ARA",     1, 1 },
160    { OPCODE_ARL,    "ARL",     1, 1 },
161    { OPCODE_ARL_NV, "ARL_NV",  1, 1 },
162    { OPCODE_ARR,    "ARL",     1, 1 },
163    { OPCODE_BGNLOOP,"BGNLOOP", 0, 0 },
164    { OPCODE_BGNSUB, "BGNSUB",  0, 0 },
165    { OPCODE_BRA,    "BRA",     0, 0 },
166    { OPCODE_BRK,    "BRK",     0, 0 },
167    { OPCODE_CAL,    "CAL",     0, 0 },
168    { OPCODE_CMP,    "CMP",     3, 1 },
169    { OPCODE_CONT,   "CONT",    0, 0 },
170    { OPCODE_COS,    "COS",     1, 1 },
171    { OPCODE_DDX,    "DDX",     1, 1 },
172    { OPCODE_DDY,    "DDY",     1, 1 },
173    { OPCODE_DP2,    "DP2",     2, 1 },
174    { OPCODE_DP2A,   "DP2A",    3, 1 },
175    { OPCODE_DP3,    "DP3",     2, 1 },
176    { OPCODE_DP4,    "DP4",     2, 1 },
177    { OPCODE_DPH,    "DPH",     2, 1 },
178    { OPCODE_DST,    "DST",     2, 1 },
179    { OPCODE_ELSE,   "ELSE",    0, 0 },
180    { OPCODE_EMIT_VERTEX,   "EMIT_VERTEX",    0, 0 },
181    { OPCODE_END,    "END",     0, 0 },
182    { OPCODE_END_PRIMITIVE,    "END_PRIMITIVE",     0, 0 },
183    { OPCODE_ENDIF,  "ENDIF",   0, 0 },
184    { OPCODE_ENDLOOP,"ENDLOOP", 0, 0 },
185    { OPCODE_ENDSUB, "ENDSUB",  0, 0 },
186    { OPCODE_EX2,    "EX2",     1, 1 },
187    { OPCODE_EXP,    "EXP",     1, 1 },
188    { OPCODE_FLR,    "FLR",     1, 1 },
189    { OPCODE_FRC,    "FRC",     1, 1 },
190    { OPCODE_IF,     "IF",      1, 0 },
191    { OPCODE_KIL,    "KIL",     1, 0 },
192    { OPCODE_KIL_NV, "KIL_NV",  0, 0 },
193    { OPCODE_LG2,    "LG2",     1, 1 },
194    { OPCODE_LIT,    "LIT",     1, 1 },
195    { OPCODE_LOG,    "LOG",     1, 1 },
196    { OPCODE_LRP,    "LRP",     3, 1 },
197    { OPCODE_MAD,    "MAD",     3, 1 },
198    { OPCODE_MAX,    "MAX",     2, 1 },
199    { OPCODE_MIN,    "MIN",     2, 1 },
200    { OPCODE_MOV,    "MOV",     1, 1 },
201    { OPCODE_MUL,    "MUL",     2, 1 },
202    { OPCODE_NOISE1, "NOISE1",  1, 1 },
203    { OPCODE_NOISE2, "NOISE2",  1, 1 },
204    { OPCODE_NOISE3, "NOISE3",  1, 1 },
205    { OPCODE_NOISE4, "NOISE4",  1, 1 },
206    { OPCODE_NOT,    "NOT",     1, 1 },
207    { OPCODE_NRM3,   "NRM3",    1, 1 },
208    { OPCODE_NRM4,   "NRM4",    1, 1 },
209    { OPCODE_OR,     "OR",      2, 1 },
210    { OPCODE_PK2H,   "PK2H",    1, 1 },
211    { OPCODE_PK2US,  "PK2US",   1, 1 },
212    { OPCODE_PK4B,   "PK4B",    1, 1 },
213    { OPCODE_PK4UB,  "PK4UB",   1, 1 },
214    { OPCODE_POW,    "POW",     2, 1 },
215    { OPCODE_POPA,   "POPA",    0, 0 },
216    { OPCODE_PRINT,  "PRINT",   1, 0 },
217    { OPCODE_PUSHA,  "PUSHA",   0, 0 },
218    { OPCODE_RCC,    "RCC",     1, 1 },
219    { OPCODE_RCP,    "RCP",     1, 1 },
220    { OPCODE_RET,    "RET",     0, 0 },
221    { OPCODE_RFL,    "RFL",     1, 1 },
222    { OPCODE_RSQ,    "RSQ",     1, 1 },
223    { OPCODE_SCS,    "SCS",     1, 1 },
224    { OPCODE_SEQ,    "SEQ",     2, 1 },
225    { OPCODE_SFL,    "SFL",     0, 1 },
226    { OPCODE_SGE,    "SGE",     2, 1 },
227    { OPCODE_SGT,    "SGT",     2, 1 },
228    { OPCODE_SIN,    "SIN",     1, 1 },
229    { OPCODE_SLE,    "SLE",     2, 1 },
230    { OPCODE_SLT,    "SLT",     2, 1 },
231    { OPCODE_SNE,    "SNE",     2, 1 },
232    { OPCODE_SSG,    "SSG",     1, 1 },
233    { OPCODE_STR,    "STR",     0, 1 },
234    { OPCODE_SUB,    "SUB",     2, 1 },
235    { OPCODE_SWZ,    "SWZ",     1, 1 },
236    { OPCODE_TEX,    "TEX",     1, 1 },
237    { OPCODE_TXB,    "TXB",     1, 1 },
238    { OPCODE_TXD,    "TXD",     3, 1 },
239    { OPCODE_TXL,    "TXL",     1, 1 },
240    { OPCODE_TXP,    "TXP",     1, 1 },
241    { OPCODE_TXP_NV, "TXP_NV",  1, 1 },
242    { OPCODE_TRUNC,  "TRUNC",   1, 1 },
243    { OPCODE_UP2H,   "UP2H",    1, 1 },
244    { OPCODE_UP2US,  "UP2US",   1, 1 },
245    { OPCODE_UP4B,   "UP4B",    1, 1 },
246    { OPCODE_UP4UB,  "UP4UB",   1, 1 },
247    { OPCODE_X2D,    "X2D",     3, 1 },
248    { OPCODE_XOR,    "XOR",     2, 1 },
249    { OPCODE_XPD,    "XPD",     2, 1 }
250 };
251 
252 
253 /**
254  * Return the number of src registers for the given instruction/opcode.
255  */
256 GLuint
_mesa_num_inst_src_regs(gl_inst_opcode opcode)257 _mesa_num_inst_src_regs(gl_inst_opcode opcode)
258 {
259    ASSERT(opcode < MAX_OPCODE);
260    ASSERT(opcode == InstInfo[opcode].Opcode);
261    ASSERT(OPCODE_XPD == InstInfo[OPCODE_XPD].Opcode);
262    return InstInfo[opcode].NumSrcRegs;
263 }
264 
265 
266 /**
267  * Return the number of dst registers for the given instruction/opcode.
268  */
269 GLuint
_mesa_num_inst_dst_regs(gl_inst_opcode opcode)270 _mesa_num_inst_dst_regs(gl_inst_opcode opcode)
271 {
272    ASSERT(opcode < MAX_OPCODE);
273    ASSERT(opcode == InstInfo[opcode].Opcode);
274    ASSERT(OPCODE_XPD == InstInfo[OPCODE_XPD].Opcode);
275    return InstInfo[opcode].NumDstRegs;
276 }
277 
278 
279 GLboolean
_mesa_is_tex_instruction(gl_inst_opcode opcode)280 _mesa_is_tex_instruction(gl_inst_opcode opcode)
281 {
282    return (opcode == OPCODE_TEX ||
283            opcode == OPCODE_TXB ||
284            opcode == OPCODE_TXD ||
285            opcode == OPCODE_TXL ||
286            opcode == OPCODE_TXP);
287 }
288 
289 
290 /**
291  * Check if there's a potential src/dst register data dependency when
292  * using SOA execution.
293  * Example:
294  *   MOV T, T.yxwz;
295  * This would expand into:
296  *   MOV t0, t1;
297  *   MOV t1, t0;
298  *   MOV t2, t3;
299  *   MOV t3, t2;
300  * The second instruction will have the wrong value for t0 if executed as-is.
301  */
302 GLboolean
_mesa_check_soa_dependencies(const struct prog_instruction * inst)303 _mesa_check_soa_dependencies(const struct prog_instruction *inst)
304 {
305    GLuint i, chan;
306 
307    if (inst->DstReg.WriteMask == WRITEMASK_X ||
308        inst->DstReg.WriteMask == WRITEMASK_Y ||
309        inst->DstReg.WriteMask == WRITEMASK_Z ||
310        inst->DstReg.WriteMask == WRITEMASK_W ||
311        inst->DstReg.WriteMask == 0x0) {
312       /* no chance of data dependency */
313       return GL_FALSE;
314    }
315 
316    /* loop over src regs */
317    for (i = 0; i < 3; i++) {
318       if (inst->SrcReg[i].File == inst->DstReg.File &&
319           inst->SrcReg[i].Index == inst->DstReg.Index) {
320          /* loop over dest channels */
321          GLuint channelsWritten = 0x0;
322          for (chan = 0; chan < 4; chan++) {
323             if (inst->DstReg.WriteMask & (1 << chan)) {
324                /* check if we're reading a channel that's been written */
325                GLuint swizzle = GET_SWZ(inst->SrcReg[i].Swizzle, chan);
326                if (swizzle <= SWIZZLE_W &&
327                    (channelsWritten & (1 << swizzle))) {
328                   return GL_TRUE;
329                }
330 
331                channelsWritten |= (1 << chan);
332             }
333          }
334       }
335    }
336    return GL_FALSE;
337 }
338 
339 
340 /**
341  * Return string name for given program opcode.
342  */
343 const char *
_mesa_opcode_string(gl_inst_opcode opcode)344 _mesa_opcode_string(gl_inst_opcode opcode)
345 {
346    if (opcode < MAX_OPCODE)
347       return InstInfo[opcode].Name;
348    else {
349       static char s[20];
350       _mesa_snprintf(s, sizeof(s), "OP%u", opcode);
351       return s;
352    }
353 }
354 
355