OSDN Git Service

Fix initialization order warnings.
[android-x86/external-swiftshader.git] / src / OpenGL / compiler / OutputASM.cpp
1 // SwiftShader Software Renderer\r
2 //\r
3 // Copyright(c) 2005-2013 TransGaming Inc.\r
4 //\r
5 // All rights reserved. No part of this software may be copied, distributed, transmitted,\r
6 // transcribed, stored in a retrieval system, translated into any human or computer\r
7 // language by any means, or disclosed to third parties without the explicit written\r
8 // agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express\r
9 // or implied, including but not limited to any patent rights, are granted to you.\r
10 //\r
11 \r
12 #include "OutputASM.h"\r
13 \r
14 #include "common/debug.h"\r
15 #include "InfoSink.h"\r
16 \r
17 #include "libGLESv2/Shader.h"\r
18 \r
19 #include <GLES2/gl2.h>\r
20 #include <GLES2/gl2ext.h>\r
21 #include <GLES3/gl3.h>\r
22 \r
23 namespace glsl\r
24 {\r
25         // Integer to TString conversion\r
26         TString str(int i)\r
27         {\r
28                 char buffer[20];\r
29                 sprintf(buffer, "%d", i);\r
30                 return buffer;\r
31         }\r
32 \r
33         class Temporary : public TIntermSymbol\r
34         {\r
35         public:\r
36                 Temporary(OutputASM *assembler) : TIntermSymbol(TSymbolTableLevel::nextUniqueId(), "tmp", TType(EbtFloat, EbpHigh, EvqTemporary, 4, 1, false)), assembler(assembler)\r
37                 {\r
38                 }\r
39 \r
40                 ~Temporary()\r
41                 {\r
42                         assembler->freeTemporary(this);\r
43                 }\r
44 \r
45         private:\r
46                 OutputASM *const assembler;\r
47         };\r
48 \r
49         class Constant : public TIntermConstantUnion\r
50         {\r
51         public:\r
52                 Constant(float x, float y, float z, float w) : TIntermConstantUnion(constants, TType(EbtFloat, EbpHigh, EvqConstExpr, 4, 1, false))\r
53                 {\r
54                         constants[0].setFConst(x);\r
55                         constants[1].setFConst(y);\r
56                         constants[2].setFConst(z);\r
57                         constants[3].setFConst(w);\r
58                 }\r
59 \r
60                 Constant(bool b) : TIntermConstantUnion(constants, TType(EbtBool, EbpHigh, EvqConstExpr, 1, 1, false))\r
61                 {\r
62                         constants[0].setBConst(b);\r
63                 }\r
64 \r
65                 Constant(int i) : TIntermConstantUnion(constants, TType(EbtInt, EbpHigh, EvqConstExpr, 1, 1, false))\r
66                 {\r
67                         constants[0].setIConst(i);\r
68                 }\r
69 \r
70                 ~Constant()\r
71                 {\r
72                 }\r
73 \r
74         private:\r
75                 ConstantUnion constants[4];\r
76         };\r
77 \r
78         Uniform::Uniform(GLenum type, GLenum precision, const std::string &name, int arraySize, int registerIndex, int offset, int blockId) :\r
79                 type(type), precision(precision), name(name), arraySize(arraySize), registerIndex(registerIndex), offset(offset), blockId(blockId)\r
80         {\r
81         }\r
82 \r
83         UniformBlock::UniformBlock(const std::string& name, const std::string& instanceName, unsigned int dataSize, unsigned int arraySize,\r
84                                    TLayoutBlockStorage layout, bool isRowMajorLayout, int registerIndex, int blockId) :\r
85                 name(name), instanceName(instanceName), dataSize(dataSize), arraySize(arraySize), layout(layout),\r
86                 isRowMajorLayout(isRowMajorLayout), registerIndex(registerIndex), blockId(blockId)\r
87         {\r
88         }\r
89 \r
90         Attribute::Attribute()\r
91         {\r
92                 type = GL_NONE;\r
93                 arraySize = 0;\r
94                 registerIndex = 0;\r
95         }\r
96 \r
97         Attribute::Attribute(GLenum type, const std::string &name, int arraySize, int location, int registerIndex)\r
98         {\r
99                 this->type = type;\r
100                 this->name = name;\r
101                 this->arraySize = arraySize;\r
102                 this->location = location;\r
103                 this->registerIndex = registerIndex;\r
104         }\r
105 \r
106         sw::PixelShader *Shader::getPixelShader() const\r
107         {\r
108                 return 0;\r
109         }\r
110 \r
111         sw::VertexShader *Shader::getVertexShader() const\r
112         {\r
113                 return 0;\r
114         }\r
115 \r
116         OutputASM::TextureFunction::TextureFunction(const TString& nodeName) : method(IMPLICIT), proj(false), offset(false)\r
117         {\r
118                 TString name = TFunction::unmangleName(nodeName);\r
119 \r
120                 if(name == "texture2D" || name == "textureCube" || name == "texture" || name == "texture3D")\r
121                 {\r
122                         method = IMPLICIT;\r
123                 }\r
124                 else if(name == "texture2DProj" || name == "textureProj")\r
125                 {\r
126                         method = IMPLICIT;\r
127                         proj = true;\r
128                 }\r
129                 else if(name == "texture2DLod" || name == "textureCubeLod" || name == "textureLod")\r
130                 {\r
131                         method = LOD;\r
132                 }\r
133                 else if(name == "texture2DProjLod" || name == "textureProjLod")\r
134                 {\r
135                         method = LOD;\r
136                         proj = true;\r
137                 }\r
138                 else if(name == "textureSize")\r
139                 {\r
140                         method = SIZE;\r
141                 }\r
142                 else if(name == "textureOffset")\r
143                 {\r
144                         method = IMPLICIT;\r
145                         offset = true;\r
146                 }\r
147                 else if(name == "textureProjOffset")\r
148                 {\r
149                         method = IMPLICIT;\r
150                         offset = true;\r
151                         proj = true;\r
152                 }\r
153                 else if(name == "textureLodOffset")\r
154                 {\r
155                         method = LOD;\r
156                         offset = true;\r
157                 }\r
158                 else if(name == "textureProjLodOffset")\r
159                 {\r
160                         method = LOD;\r
161                         proj = true;\r
162                         offset = true;\r
163                 }\r
164                 else if(name == "texelFetch")\r
165                 {\r
166                         method = FETCH;\r
167                 }\r
168                 else if(name == "texelFetchOffset")\r
169                 {\r
170                         method = FETCH;\r
171                         offset = true;\r
172                 }\r
173                 else if(name == "textureGrad")\r
174                 {\r
175                         method = GRAD;\r
176                 }\r
177                 else if(name == "textureGradOffset")\r
178                 {\r
179                         method = GRAD;\r
180                         offset = true;\r
181                 }\r
182                 else if(name == "textureProjGrad")\r
183                 {\r
184                         method = GRAD;\r
185                         proj = true;\r
186                 }\r
187                 else if(name == "textureProjGradOffset")\r
188                 {\r
189                         method = GRAD;\r
190                         proj = true;\r
191                         offset = true;\r
192                 }\r
193                 else UNREACHABLE(0);\r
194         }\r
195 \r
196         OutputASM::OutputASM(TParseContext &context, Shader *shaderObject) : TIntermTraverser(true, true, true), shaderObject(shaderObject), mContext(context)\r
197         {\r
198                 shader = 0;\r
199                 pixelShader = 0;\r
200                 vertexShader = 0;\r
201 \r
202                 if(shaderObject)\r
203                 {\r
204                         shader = shaderObject->getShader();\r
205                         pixelShader = shaderObject->getPixelShader();\r
206                         vertexShader = shaderObject->getVertexShader();\r
207                 }\r
208 \r
209                 functionArray.push_back(Function(0, "main(", 0, 0));\r
210                 currentFunction = 0;\r
211                 outputQualifier = EvqOutput; // Set outputQualifier to any value other than EvqFragColor or EvqFragData\r
212         }\r
213 \r
214         OutputASM::~OutputASM()\r
215         {\r
216         }\r
217 \r
218         void OutputASM::output()\r
219         {\r
220                 if(shader)\r
221                 {\r
222                         emitShader(GLOBAL);\r
223 \r
224                         if(functionArray.size() > 1)   // Only call main() when there are other functions\r
225                         {\r
226                                 Instruction *callMain = emit(sw::Shader::OPCODE_CALL);\r
227                                 callMain->dst.type = sw::Shader::PARAMETER_LABEL;\r
228                                 callMain->dst.index = 0;   // main()\r
229 \r
230                                 emit(sw::Shader::OPCODE_RET);\r
231                         }\r
232 \r
233                         emitShader(FUNCTION);\r
234                 }\r
235         }\r
236 \r
237         void OutputASM::emitShader(Scope scope)\r
238         {\r
239                 emitScope = scope;\r
240                 currentScope = GLOBAL;\r
241                 mContext.getTreeRoot()->traverse(this);\r
242         }\r
243 \r
244         void OutputASM::freeTemporary(Temporary *temporary)\r
245         {\r
246                 free(temporaries, temporary);\r
247         }\r
248 \r
249         sw::Shader::Opcode OutputASM::getOpcode(sw::Shader::Opcode op, TIntermTyped *in) const\r
250         {\r
251                 TBasicType baseType = in->getType().getBasicType();\r
252 \r
253                 switch(op)\r
254                 {\r
255                 case sw::Shader::OPCODE_NEG:\r
256                         switch(baseType)\r
257                         {\r
258                         case EbtInt:\r
259                         case EbtUInt:\r
260                                 return sw::Shader::OPCODE_INEG;\r
261                         case EbtFloat:\r
262                         default:\r
263                                 return op;\r
264                         }\r
265                 case sw::Shader::OPCODE_ADD:\r
266                         switch(baseType)\r
267                         {\r
268                         case EbtInt:\r
269                         case EbtUInt:\r
270                                 return sw::Shader::OPCODE_IADD;\r
271                         case EbtFloat:\r
272                         default:\r
273                                 return op;\r
274                         }\r
275                 case sw::Shader::OPCODE_SUB:\r
276                         switch(baseType)\r
277                         {\r
278                         case EbtInt:\r
279                         case EbtUInt:\r
280                                 return sw::Shader::OPCODE_ISUB;\r
281                         case EbtFloat:\r
282                         default:\r
283                                 return op;\r
284                         }\r
285                 case sw::Shader::OPCODE_MUL:\r
286                         switch(baseType)\r
287                         {\r
288                         case EbtInt:\r
289                         case EbtUInt:\r
290                                 return sw::Shader::OPCODE_IMUL;\r
291                         case EbtFloat:\r
292                         default:\r
293                                 return op;\r
294                         }\r
295                 case sw::Shader::OPCODE_DIV:\r
296                         switch(baseType)\r
297                         {\r
298                         case EbtInt:\r
299                                 return sw::Shader::OPCODE_IDIV;\r
300                         case EbtUInt:\r
301                                 return sw::Shader::OPCODE_UDIV;\r
302                         case EbtFloat:\r
303                         default:\r
304                                 return op;\r
305                         }\r
306                 case sw::Shader::OPCODE_IMOD:\r
307                         return baseType == EbtUInt ? sw::Shader::OPCODE_UMOD : op;\r
308                 case sw::Shader::OPCODE_ISHR:\r
309                         return baseType == EbtUInt ? sw::Shader::OPCODE_USHR : op;\r
310                 case sw::Shader::OPCODE_MIN:\r
311                         switch(baseType)\r
312                         {\r
313                         case EbtInt:\r
314                                 return sw::Shader::OPCODE_IMIN;\r
315                         case EbtUInt:\r
316                                 return sw::Shader::OPCODE_UMIN;\r
317                         case EbtFloat:\r
318                         default:\r
319                                 return op;\r
320                         }\r
321                 case sw::Shader::OPCODE_MAX:\r
322                         switch(baseType)\r
323                         {\r
324                         case EbtInt:\r
325                                 return sw::Shader::OPCODE_IMAX;\r
326                         case EbtUInt:\r
327                                 return sw::Shader::OPCODE_UMAX;\r
328                         case EbtFloat:\r
329                         default:\r
330                                 return op;\r
331                         }\r
332                 default:\r
333                         return op;\r
334                 }\r
335         }\r
336 \r
337         void OutputASM::visitSymbol(TIntermSymbol *symbol)\r
338         {\r
339                 // Vertex varyings don't have to be actively used to successfully link\r
340                 // against pixel shaders that use them. So make sure they're declared.\r
341                 if(symbol->getQualifier() == EvqVaryingOut || symbol->getQualifier() == EvqInvariantVaryingOut || symbol->getQualifier() == EvqVertexOut)\r
342                 {\r
343                         if(symbol->getBasicType() != EbtInvariant)   // Typeless declarations are not new varyings\r
344                         {\r
345                                 declareVarying(symbol, -1);\r
346                         }\r
347                 }\r
348         }\r
349 \r
350         bool OutputASM::visitBinary(Visit visit, TIntermBinary *node)\r
351         {\r
352                 if(currentScope != emitScope)\r
353                 {\r
354                         return false;\r
355                 }\r
356 \r
357                 TIntermTyped *result = node;\r
358                 TIntermTyped *left = node->getLeft();\r
359                 TIntermTyped *right = node->getRight();\r
360                 const TType &leftType = left->getType();\r
361                 const TType &rightType = right->getType();\r
362                 const TType &resultType = node->getType();\r
363                 \r
364                 switch(node->getOp())\r
365                 {\r
366                 case EOpAssign:\r
367                         if(visit == PostVisit)\r
368                         {\r
369                                 assignLvalue(left, right);\r
370                                 copy(result, right);\r
371                         }\r
372                         break;\r
373                 case EOpInitialize:\r
374                         if(visit == PostVisit)\r
375                         {\r
376                                 copy(left, right);\r
377                         }\r
378                         break;\r
379                 case EOpMatrixTimesScalarAssign:\r
380                         if(visit == PostVisit)\r
381                         {\r
382                                 for(int i = 0; i < leftType.getNominalSize(); i++)\r
383                                 {\r
384                                         Instruction *mul = emit(sw::Shader::OPCODE_MUL, result, left, right);\r
385                                         mul->dst.index += i;\r
386                                         argument(mul->src[0], left, i);\r
387                                 }\r
388 \r
389                                 assignLvalue(left, result);\r
390                         }\r
391                         break;\r
392                 case EOpVectorTimesMatrixAssign:\r
393                         if(visit == PostVisit)\r
394                         {\r
395                                 int size = leftType.getNominalSize();\r
396 \r
397                                 for(int i = 0; i < size; i++)\r
398                                 {\r
399                                         Instruction *dot = emit(sw::Shader::OPCODE_DP(size), result, left, right);\r
400                                         dot->dst.mask = 1 << i;\r
401                                         argument(dot->src[1], right, i);\r
402                                 }\r
403 \r
404                                 assignLvalue(left, result);\r
405                         }\r
406                         break;\r
407                 case EOpMatrixTimesMatrixAssign:\r
408                         if(visit == PostVisit)\r
409                         {\r
410                                 int dim = leftType.getNominalSize();\r
411 \r
412                                 for(int i = 0; i < dim; i++)\r
413                                 {\r
414                                         Instruction *mul = emit(sw::Shader::OPCODE_MUL, result, left, right);\r
415                                         mul->dst.index += i;\r
416                                         argument(mul->src[1], right, i);\r
417                                         mul->src[1].swizzle = 0x00;\r
418 \r
419                                         for(int j = 1; j < dim; j++)\r
420                                         {\r
421                                                 Instruction *mad = emit(sw::Shader::OPCODE_MAD, result, left, right, result);\r
422                                                 mad->dst.index += i;\r
423                                                 argument(mad->src[0], left, j);\r
424                                                 argument(mad->src[1], right, i);\r
425                                                 mad->src[1].swizzle = j * 0x55;\r
426                                                 argument(mad->src[2], result, i);\r
427                                         }\r
428                                 }\r
429 \r
430                                 assignLvalue(left, result);\r
431                         }\r
432                         break;\r
433                 case EOpIndexDirect:\r
434                         if(visit == PostVisit)\r
435                         {\r
436                                 int index = right->getAsConstantUnion()->getIConst(0);\r
437 \r
438                                 if(result->isMatrix() || result->isStruct())\r
439                                 {\r
440                                         ASSERT(left->isArray());\r
441                                         copy(result, left, index * left->elementRegisterCount());\r
442                                 }\r
443                                 else if(result->isRegister())\r
444                                 {\r
445                                         Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, left);\r
446 \r
447                                         if(left->isRegister())\r
448                                         {\r
449                                                 mov->src[0].swizzle = index;\r
450                                         }\r
451                                         else if(left->isArray())\r
452                                         {\r
453                                                 argument(mov->src[0], left, index * left->elementRegisterCount());\r
454                                         }\r
455                                         else if(left->isMatrix())\r
456                                         {\r
457                                                 ASSERT(index < left->getNominalSize());   // FIXME: Report semantic error\r
458                                                 argument(mov->src[0], left, index);\r
459                                         }\r
460                                         else UNREACHABLE(0);\r
461                                 }\r
462                                 else UNREACHABLE(0);\r
463                         }\r
464                         break;\r
465                 case EOpIndexIndirect:\r
466                         if(visit == PostVisit)\r
467                         {\r
468                                 if(left->isArray() || left->isMatrix())\r
469                                 {\r
470                                         for(int index = 0; index < result->totalRegisterCount(); index++)\r
471                                         {\r
472                                                 Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, left);\r
473                                                 mov->dst.index += index;\r
474                                                 mov->dst.mask = writeMask(result, index);\r
475                                                 argument(mov->src[0], left, index);\r
476 \r
477                                                 if(left->totalRegisterCount() > 1)\r
478                                                 {\r
479                                                         sw::Shader::SourceParameter relativeRegister;\r
480                                                         argument(relativeRegister, right);\r
481 \r
482                                                         mov->src[0].rel.type = relativeRegister.type;\r
483                                                         mov->src[0].rel.index = relativeRegister.index;\r
484                                                         mov->src[0].rel.scale = result->totalRegisterCount();\r
485                                                         mov->src[0].rel.deterministic = !(vertexShader && left->getQualifier() == EvqUniform);\r
486                                                 }\r
487                                         }\r
488                                 }\r
489                                 else if(left->isRegister())\r
490                                 {\r
491                                         emit(sw::Shader::OPCODE_EXTRACT, result, left, right);\r
492                                 }\r
493                                 else UNREACHABLE(0);\r
494                         }\r
495                         break;\r
496                 case EOpIndexDirectStruct:\r
497                 case EOpIndexDirectInterfaceBlock:\r
498                         if(visit == PostVisit)\r
499                         {\r
500                                 ASSERT(leftType.isStruct() || (leftType.isInterfaceBlock()));\r
501 \r
502                                 const TFieldList& fields = (node->getOp() == EOpIndexDirectStruct) ?\r
503                                                            leftType.getStruct()->fields() :\r
504                                                            leftType.getInterfaceBlock()->fields();\r
505                                 int index = right->getAsConstantUnion()->getIConst(0);\r
506                                 int fieldOffset = 0;\r
507 \r
508                                 for(int i = 0; i < index; i++)\r
509                                 {\r
510                                         fieldOffset += fields[i]->type()->totalRegisterCount();\r
511                                 }\r
512 \r
513                                 copy(result, left, fieldOffset);\r
514                         }\r
515                         break;\r
516                 case EOpVectorSwizzle:\r
517                         if(visit == PostVisit)\r
518                         {\r
519                                 int swizzle = 0;\r
520                                 TIntermAggregate *components = right->getAsAggregate();\r
521 \r
522                                 if(components)\r
523                                 {\r
524                                         TIntermSequence &sequence = components->getSequence();\r
525                                         int component = 0;\r
526 \r
527                                         for(TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)\r
528                                         {\r
529                                                 TIntermConstantUnion *element = (*sit)->getAsConstantUnion();\r
530 \r
531                                                 if(element)\r
532                                                 {\r
533                                                         int i = element->getUnionArrayPointer()[0].getIConst();\r
534                                                         swizzle |= i << (component * 2);\r
535                                                         component++;\r
536                                                 }\r
537                                                 else UNREACHABLE(0);\r
538                                         }\r
539                                 }\r
540                                 else UNREACHABLE(0);\r
541 \r
542                                 Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, left);\r
543                                 mov->src[0].swizzle = swizzle;\r
544                         }\r
545                         break;\r
546                 case EOpAddAssign: if(visit == PostVisit) emitAssign(getOpcode(sw::Shader::OPCODE_ADD, result), result, left, left, right); break;\r
547                 case EOpAdd:       if(visit == PostVisit) emitBinary(getOpcode(sw::Shader::OPCODE_ADD, result), result, left, right);       break;\r
548                 case EOpSubAssign: if(visit == PostVisit) emitAssign(getOpcode(sw::Shader::OPCODE_SUB, result), result, left, left, right); break;\r
549                 case EOpSub:       if(visit == PostVisit) emitBinary(getOpcode(sw::Shader::OPCODE_SUB, result), result, left, right);       break;\r
550                 case EOpMulAssign: if(visit == PostVisit) emitAssign(getOpcode(sw::Shader::OPCODE_MUL, result), result, left, left, right); break;\r
551                 case EOpMul:       if(visit == PostVisit) emitBinary(getOpcode(sw::Shader::OPCODE_MUL, result), result, left, right);       break;\r
552                 case EOpDivAssign: if(visit == PostVisit) emitAssign(getOpcode(sw::Shader::OPCODE_DIV, result), result, left, left, right); break;\r
553                 case EOpDiv:       if(visit == PostVisit) emitBinary(getOpcode(sw::Shader::OPCODE_DIV, result), result, left, right);       break;\r
554                 case EOpIModAssign:          if(visit == PostVisit) emitAssign(getOpcode(sw::Shader::OPCODE_IMOD, result), result, left, left, right); break;\r
555                 case EOpIMod:                if(visit == PostVisit) emitBinary(getOpcode(sw::Shader::OPCODE_IMOD, result), result, left, right);       break;\r
556                 case EOpBitShiftLeftAssign:  if(visit == PostVisit) emitAssign(sw::Shader::OPCODE_SHL, result, left, left, right); break;\r
557                 case EOpBitShiftLeft:        if(visit == PostVisit) emitBinary(sw::Shader::OPCODE_SHL, result, left, right);       break;\r
558                 case EOpBitShiftRightAssign: if(visit == PostVisit) emitAssign(getOpcode(sw::Shader::OPCODE_ISHR, result), result, left, left, right); break;\r
559                 case EOpBitShiftRight:       if(visit == PostVisit) emitBinary(getOpcode(sw::Shader::OPCODE_ISHR, result), result, left, right);       break;\r
560                 case EOpBitwiseAndAssign:    if(visit == PostVisit) emitAssign(sw::Shader::OPCODE_AND, result, left, left, right); break;\r
561                 case EOpBitwiseAnd:          if(visit == PostVisit) emitBinary(sw::Shader::OPCODE_AND, result, left, right);       break;\r
562                 case EOpBitwiseXorAssign:    if(visit == PostVisit) emitAssign(sw::Shader::OPCODE_XOR, result, left, left, right); break;\r
563                 case EOpBitwiseXor:          if(visit == PostVisit) emitBinary(sw::Shader::OPCODE_XOR, result, left, right);       break;\r
564                 case EOpBitwiseOrAssign:     if(visit == PostVisit) emitAssign(sw::Shader::OPCODE_OR, result, left, left, right);  break;\r
565                 case EOpBitwiseOr:           if(visit == PostVisit) emitBinary(sw::Shader::OPCODE_OR, result, left, right);        break;\r
566                 case EOpEqual:\r
567                         if(visit == PostVisit)\r
568                         {\r
569                                 emitBinary(sw::Shader::OPCODE_EQ, result, left, right);\r
570 \r
571                                 for(int index = 1; index < left->totalRegisterCount(); index++)\r
572                                 {\r
573                                         Temporary equal(this);\r
574                                         Instruction *eq = emit(sw::Shader::OPCODE_EQ, &equal, left, right);\r
575                                         argument(eq->src[0], left, index);\r
576                                         argument(eq->src[1], right, index);\r
577                                         emit(sw::Shader::OPCODE_AND, result, result, &equal);\r
578                                 }\r
579                         }\r
580                         break;\r
581                 case EOpNotEqual:\r
582                         if(visit == PostVisit)\r
583                         {\r
584                                 emitBinary(sw::Shader::OPCODE_NE, result, left, right);\r
585 \r
586                                 for(int index = 1; index < left->totalRegisterCount(); index++)\r
587                                 {\r
588                                         Temporary notEqual(this);\r
589                                         Instruction *eq = emit(sw::Shader::OPCODE_NE, &notEqual, left, right);\r
590                                         argument(eq->src[0], left, index);\r
591                                         argument(eq->src[1], right, index);\r
592                                         emit(sw::Shader::OPCODE_OR, result, result, &notEqual);\r
593                                 }\r
594                         }\r
595                         break;\r
596                 case EOpLessThan:                if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_LT, result, left, right); break;\r
597                 case EOpGreaterThan:             if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_GT, result, left, right); break;\r
598                 case EOpLessThanEqual:           if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_LE, result, left, right); break;\r
599                 case EOpGreaterThanEqual:        if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_GE, result, left, right); break;\r
600                 case EOpVectorTimesScalarAssign: if(visit == PostVisit) emitAssign(getOpcode(sw::Shader::OPCODE_MUL, left), result, left, left, right); break;\r
601                 case EOpVectorTimesScalar:       if(visit == PostVisit) emit(getOpcode(sw::Shader::OPCODE_MUL, left), result, left, right); break;\r
602                 case EOpMatrixTimesScalar:\r
603                         if(visit == PostVisit)\r
604                         {\r
605                                 for(int i = 0; i < leftType.getNominalSize(); i++)\r
606                                 {\r
607                                         Instruction *mul = emit(sw::Shader::OPCODE_MUL, result, left, right);\r
608                                         mul->dst.index += i;\r
609                                         argument(mul->src[0], left, i);\r
610                                 }\r
611                         }\r
612                         break;\r
613                 case EOpVectorTimesMatrix:\r
614                         if(visit == PostVisit)\r
615                         {\r
616                                 sw::Shader::Opcode dpOpcode = sw::Shader::OPCODE_DP(leftType.getNominalSize());\r
617 \r
618                                 int size = rightType.getNominalSize();\r
619                                 for(int i = 0; i < size; i++)\r
620                                 {\r
621                                         Instruction *dot = emit(dpOpcode, result, left, right);\r
622                                         dot->dst.mask = 1 << i;\r
623                                         argument(dot->src[1], right, i);\r
624                                 }\r
625                         }\r
626                         break;\r
627                 case EOpMatrixTimesVector:\r
628                         if(visit == PostVisit)\r
629                         {\r
630                                 Instruction *mul = emit(sw::Shader::OPCODE_MUL, result, left, right);\r
631                                 mul->src[1].swizzle = 0x00;\r
632 \r
633                                 int size = rightType.getNominalSize();\r
634                                 for(int i = 1; i < size; i++)\r
635                                 {\r
636                                         Instruction *mad = emit(sw::Shader::OPCODE_MAD, result, left, right, result);\r
637                                         argument(mad->src[0], left, i);\r
638                                         mad->src[1].swizzle = i * 0x55;\r
639                                 }\r
640                         }\r
641                         break;\r
642                 case EOpMatrixTimesMatrix:\r
643                         if(visit == PostVisit)\r
644                         {\r
645                                 int dim = leftType.getNominalSize();\r
646 \r
647                                 int size = rightType.getNominalSize();\r
648                                 for(int i = 0; i < size; i++)\r
649                                 {\r
650                                         Instruction *mul = emit(sw::Shader::OPCODE_MUL, result, left, right);\r
651                                         mul->dst.index += i;\r
652                                         argument(mul->src[1], right, i);\r
653                                         mul->src[1].swizzle = 0x00;\r
654 \r
655                                         for(int j = 1; j < dim; j++)\r
656                                         {\r
657                                                 Instruction *mad = emit(sw::Shader::OPCODE_MAD, result, left, right, result);\r
658                                                 mad->dst.index += i;\r
659                                                 argument(mad->src[0], left, j);\r
660                                                 argument(mad->src[1], right, i);\r
661                                                 mad->src[1].swizzle = j * 0x55;\r
662                                                 argument(mad->src[2], result, i);\r
663                                         }\r
664                                 }\r
665                         }\r
666                         break;\r
667                 case EOpLogicalOr:\r
668                         if(trivial(right, 6))\r
669                         {\r
670                                 if(visit == PostVisit)\r
671                                 {\r
672                                         emit(sw::Shader::OPCODE_OR, result, left, right);\r
673                                 }\r
674                         }\r
675                         else   // Short-circuit evaluation\r
676                         {\r
677                                 if(visit == InVisit)\r
678                                 {\r
679                                         emit(sw::Shader::OPCODE_MOV, result, left);\r
680                                         Instruction *ifnot = emit(sw::Shader::OPCODE_IF, 0, result);\r
681                                         ifnot->src[0].modifier = sw::Shader::MODIFIER_NOT;\r
682                                 }\r
683                                 else if(visit == PostVisit)\r
684                                 {\r
685                                         emit(sw::Shader::OPCODE_MOV, result, right);\r
686                                         emit(sw::Shader::OPCODE_ENDIF);\r
687                                 }\r
688                         }\r
689                         break;\r
690                 case EOpLogicalXor:        if(visit == PostVisit) emit(sw::Shader::OPCODE_XOR, result, left, right); break;\r
691                 case EOpLogicalAnd:\r
692                         if(trivial(right, 6))\r
693                         {\r
694                                 if(visit == PostVisit)\r
695                                 {\r
696                                         emit(sw::Shader::OPCODE_AND, result, left, right);\r
697                                 }\r
698                         }\r
699                         else   // Short-circuit evaluation\r
700                         {\r
701                                 if(visit == InVisit)\r
702                                 {\r
703                                         emit(sw::Shader::OPCODE_MOV, result, left);\r
704                                         emit(sw::Shader::OPCODE_IF, 0, result);\r
705                                 }\r
706                                 else if(visit == PostVisit)\r
707                                 {\r
708                                         emit(sw::Shader::OPCODE_MOV, result, right);\r
709                                         emit(sw::Shader::OPCODE_ENDIF);\r
710                                 }\r
711                         }\r
712                         break;\r
713                 default: UNREACHABLE(node->getOp());\r
714                 }\r
715 \r
716                 return true;\r
717         }\r
718 \r
719         void OutputASM::emitDeterminant(TIntermTyped *result, TIntermTyped *arg, int size, int col, int row, int outCol, int outRow)\r
720         {\r
721                 switch(size)\r
722                 {\r
723                 case 1: // Used for cofactor computation only\r
724                         {\r
725                                 // For a 2x2 matrix, the cofactor is simply a transposed move or negate\r
726                                 bool isMov = (row == col);\r
727                                 sw::Shader::Opcode op = isMov ? sw::Shader::OPCODE_MOV : sw::Shader::OPCODE_NEG;\r
728                                 Instruction *mov = emit(op, result, arg);\r
729                                 mov->src[0].index += isMov ? 1 - row : row;\r
730                                 mov->src[0].swizzle = 0x55 * (isMov ? 1 - col : col);\r
731                                 mov->dst.index += outCol;\r
732                                 mov->dst.mask = 1 << outRow;\r
733                         }\r
734                         break;\r
735                 case 2:\r
736                         {\r
737                                 static const unsigned int swizzle[3] = { 0x99, 0x88, 0x44 }; // xy?? : yzyz, xzxz, xyxy\r
738 \r
739                                 bool isCofactor = (col >= 0) && (row >= 0);\r
740                                 int col0 = (isCofactor && (col <= 0)) ? 1 : 0;\r
741                                 int col1 = (isCofactor && (col <= 1)) ? 2 : 1;\r
742                                 bool negate = isCofactor && ((col & 0x01) ^ (row & 0x01));\r
743 \r
744                                 Instruction *det = emit(sw::Shader::OPCODE_DET2, result, arg, arg);\r
745                                 det->src[0].index += negate ? col1 : col0;\r
746                                 det->src[1].index += negate ? col0 : col1;\r
747                                 det->src[0].swizzle = det->src[1].swizzle = swizzle[isCofactor ? row : 2];\r
748                                 det->dst.index += outCol;\r
749                                 det->dst.mask = 1 << outRow;\r
750                         }\r
751                         break;\r
752                 case 3:\r
753                         {\r
754                                 static const unsigned int swizzle[4] = { 0xF9, 0xF8, 0xF4, 0xE4 }; // xyz? : yzww, xzww, xyww, xyzw\r
755 \r
756                                 bool isCofactor = (col >= 0) && (row >= 0);\r
757                                 int col0 = (isCofactor && (col <= 0)) ? 1 : 0;\r
758                                 int col1 = (isCofactor && (col <= 1)) ? 2 : 1;\r
759                                 int col2 = (isCofactor && (col <= 2)) ? 3 : 2;\r
760                                 bool negate = isCofactor && ((col & 0x01) ^ (row & 0x01));\r
761 \r
762                                 Instruction *det = emit(sw::Shader::OPCODE_DET3, result, arg, arg, arg);\r
763                                 det->src[0].index += col0;\r
764                                 det->src[1].index += negate ? col2 : col1;\r
765                                 det->src[2].index += negate ? col1 : col2;\r
766                                 det->src[0].swizzle = det->src[1].swizzle = det->src[2].swizzle = swizzle[isCofactor ? row : 3];\r
767                                 det->dst.index += outCol;\r
768                                 det->dst.mask = 1 << outRow;\r
769                         }\r
770                         break;\r
771                 case 4:\r
772                         {\r
773                                 Instruction *det = emit(sw::Shader::OPCODE_DET4, result, arg, arg, arg, arg);\r
774                                 det->src[1].index += 1;\r
775                                 det->src[2].index += 2;\r
776                                 det->src[3].index += 3;\r
777                                 det->dst.index += outCol;\r
778                                 det->dst.mask = 1 << outRow;\r
779                         }\r
780                         break;\r
781                 default:\r
782                         UNREACHABLE(size);\r
783                         break;\r
784                 }\r
785         }\r
786 \r
787         bool OutputASM::visitUnary(Visit visit, TIntermUnary *node)\r
788         {\r
789                 if(currentScope != emitScope)\r
790                 {\r
791                         return false;\r
792                 }\r
793 \r
794                 TIntermTyped *result = node;\r
795                 TIntermTyped *arg = node->getOperand();\r
796                 TBasicType basicType = arg->getType().getBasicType();\r
797 \r
798                 union\r
799                 {\r
800                         float f;\r
801                         int i;\r
802                 } one_value;\r
803 \r
804                 if(basicType == EbtInt || basicType == EbtUInt)\r
805                 {\r
806                         one_value.i = 1;\r
807                 }\r
808                 else\r
809                 {\r
810                         one_value.f = 1.0f;\r
811                 }\r
812 \r
813                 Constant one(one_value.f, one_value.f, one_value.f, one_value.f);\r
814                 Constant rad(1.74532925e-2f, 1.74532925e-2f, 1.74532925e-2f, 1.74532925e-2f);\r
815                 Constant deg(5.72957795e+1f, 5.72957795e+1f, 5.72957795e+1f, 5.72957795e+1f);\r
816 \r
817                 switch(node->getOp())\r
818                 {\r
819                 case EOpNegative:\r
820                         if(visit == PostVisit)\r
821                         {\r
822                                 sw::Shader::Opcode negOpcode = getOpcode(sw::Shader::OPCODE_NEG, arg);\r
823                                 for(int index = 0; index < arg->totalRegisterCount(); index++)\r
824                                 {\r
825                                         Instruction *neg = emit(negOpcode, result, arg);\r
826                                         neg->dst.index += index;\r
827                                         argument(neg->src[0], arg, index);\r
828                                 }\r
829                         }\r
830                         break;\r
831                 case EOpVectorLogicalNot: if(visit == PostVisit) emit(sw::Shader::OPCODE_NOT, result, arg); break;\r
832                 case EOpLogicalNot:       if(visit == PostVisit) emit(sw::Shader::OPCODE_NOT, result, arg); break;\r
833                 case EOpPostIncrement:\r
834                         if(visit == PostVisit)\r
835                         {\r
836                                 copy(result, arg);\r
837 \r
838                                 sw::Shader::Opcode addOpcode = getOpcode(sw::Shader::OPCODE_ADD, arg);\r
839                                 for(int index = 0; index < arg->totalRegisterCount(); index++)\r
840                                 {\r
841                                         Instruction *add = emit(addOpcode, arg, arg, &one);\r
842                                         add->dst.index += index;\r
843                                         argument(add->src[0], arg, index);\r
844                                 }\r
845 \r
846                                 assignLvalue(arg, arg);\r
847                         }\r
848                         break;\r
849                 case EOpPostDecrement:\r
850                         if(visit == PostVisit)\r
851                         {\r
852                                 copy(result, arg);\r
853 \r
854                                 sw::Shader::Opcode subOpcode = getOpcode(sw::Shader::OPCODE_SUB, arg);\r
855                                 for(int index = 0; index < arg->totalRegisterCount(); index++)\r
856                                 {\r
857                                         Instruction *sub = emit(subOpcode, arg, arg, &one);\r
858                                         sub->dst.index += index;\r
859                                         argument(sub->src[0], arg, index);\r
860                                 }\r
861 \r
862                                 assignLvalue(arg, arg);\r
863                         }\r
864                         break;\r
865                 case EOpPreIncrement:\r
866                         if(visit == PostVisit)\r
867                         {\r
868                                 sw::Shader::Opcode addOpcode = getOpcode(sw::Shader::OPCODE_ADD, arg);\r
869                                 for(int index = 0; index < arg->totalRegisterCount(); index++)\r
870                                 {\r
871                                         Instruction *add = emit(addOpcode, result, arg, &one);\r
872                                         add->dst.index += index;\r
873                                         argument(add->src[0], arg, index);\r
874                                 }\r
875 \r
876                                 assignLvalue(arg, result);\r
877                         }\r
878                         break;\r
879                 case EOpPreDecrement:\r
880                         if(visit == PostVisit)\r
881                         {\r
882                                 sw::Shader::Opcode subOpcode = getOpcode(sw::Shader::OPCODE_SUB, arg);\r
883                                 for(int index = 0; index < arg->totalRegisterCount(); index++)\r
884                                 {\r
885                                         Instruction *sub = emit(subOpcode, result, arg, &one);\r
886                                         sub->dst.index += index;\r
887                                         argument(sub->src[0], arg, index);\r
888                                 }\r
889 \r
890                                 assignLvalue(arg, result);\r
891                         }\r
892                         break;\r
893                 case EOpRadians:          if(visit == PostVisit) emit(sw::Shader::OPCODE_MUL, result, arg, &rad); break;\r
894                 case EOpDegrees:          if(visit == PostVisit) emit(sw::Shader::OPCODE_MUL, result, arg, &deg); break;\r
895                 case EOpSin:              if(visit == PostVisit) emit(sw::Shader::OPCODE_SIN, result, arg); break;\r
896                 case EOpCos:              if(visit == PostVisit) emit(sw::Shader::OPCODE_COS, result, arg); break;\r
897                 case EOpTan:              if(visit == PostVisit) emit(sw::Shader::OPCODE_TAN, result, arg); break;\r
898                 case EOpAsin:             if(visit == PostVisit) emit(sw::Shader::OPCODE_ASIN, result, arg); break;\r
899                 case EOpAcos:             if(visit == PostVisit) emit(sw::Shader::OPCODE_ACOS, result, arg); break;\r
900                 case EOpAtan:             if(visit == PostVisit) emit(sw::Shader::OPCODE_ATAN, result, arg); break;\r
901                 case EOpSinh:             if(visit == PostVisit) emit(sw::Shader::OPCODE_SINH, result, arg); break;\r
902                 case EOpCosh:             if(visit == PostVisit) emit(sw::Shader::OPCODE_COSH, result, arg); break;\r
903                 case EOpTanh:             if(visit == PostVisit) emit(sw::Shader::OPCODE_TANH, result, arg); break;\r
904                 case EOpAsinh:            if(visit == PostVisit) emit(sw::Shader::OPCODE_ASINH, result, arg); break;\r
905                 case EOpAcosh:            if(visit == PostVisit) emit(sw::Shader::OPCODE_ACOSH, result, arg); break;\r
906                 case EOpAtanh:            if(visit == PostVisit) emit(sw::Shader::OPCODE_ATANH, result, arg); break;\r
907                 case EOpExp:              if(visit == PostVisit) emit(sw::Shader::OPCODE_EXP, result, arg); break;\r
908                 case EOpLog:              if(visit == PostVisit) emit(sw::Shader::OPCODE_LOG, result, arg); break;\r
909                 case EOpExp2:             if(visit == PostVisit) emit(sw::Shader::OPCODE_EXP2, result, arg); break;\r
910                 case EOpLog2:             if(visit == PostVisit) emit(sw::Shader::OPCODE_LOG2, result, arg); break;\r
911                 case EOpSqrt:             if(visit == PostVisit) emit(sw::Shader::OPCODE_SQRT, result, arg); break;\r
912                 case EOpInverseSqrt:      if(visit == PostVisit) emit(sw::Shader::OPCODE_RSQ, result, arg); break;\r
913                 case EOpAbs:              if(visit == PostVisit) emit(sw::Shader::OPCODE_ABS, result, arg); break;\r
914                 case EOpSign:             if(visit == PostVisit) emit(sw::Shader::OPCODE_SGN, result, arg); break;\r
915                 case EOpFloor:            if(visit == PostVisit) emit(sw::Shader::OPCODE_FLOOR, result, arg); break;\r
916                 case EOpTrunc:            if(visit == PostVisit) emit(sw::Shader::OPCODE_TRUNC, result, arg); break;\r
917                 case EOpRound:            if(visit == PostVisit) emit(sw::Shader::OPCODE_ROUND, result, arg); break;\r
918                 case EOpRoundEven:        if(visit == PostVisit) emit(sw::Shader::OPCODE_ROUNDEVEN, result, arg); break;\r
919                 case EOpCeil:             if(visit == PostVisit) emit(sw::Shader::OPCODE_CEIL, result, arg, result); break;\r
920                 case EOpFract:            if(visit == PostVisit) emit(sw::Shader::OPCODE_FRC, result, arg); break;\r
921                 case EOpIsNan:            if(visit == PostVisit) emit(sw::Shader::OPCODE_ISNAN, result, arg); break;\r
922                 case EOpIsInf:            if(visit == PostVisit) emit(sw::Shader::OPCODE_ISINF, result, arg); break;\r
923                 case EOpLength:           if(visit == PostVisit) emit(sw::Shader::OPCODE_LEN(dim(arg)), result, arg); break;\r
924                 case EOpNormalize:        if(visit == PostVisit) emit(sw::Shader::OPCODE_NRM(dim(arg)), result, arg); break;\r
925                 case EOpDFdx:             if(visit == PostVisit) emit(sw::Shader::OPCODE_DFDX, result, arg); break;\r
926                 case EOpDFdy:             if(visit == PostVisit) emit(sw::Shader::OPCODE_DFDY, result, arg); break;\r
927                 case EOpFwidth:           if(visit == PostVisit) emit(sw::Shader::OPCODE_FWIDTH, result, arg); break;\r
928                 case EOpAny:              if(visit == PostVisit) emit(sw::Shader::OPCODE_ANY, result, arg); break;\r
929                 case EOpAll:              if(visit == PostVisit) emit(sw::Shader::OPCODE_ALL, result, arg); break;\r
930                 case EOpFloatBitsToInt:   if(visit == PostVisit) emit(sw::Shader::OPCODE_FLOATBITSTOINT, result, arg); break;\r
931                 case EOpFloatBitsToUint:  if(visit == PostVisit) emit(sw::Shader::OPCODE_FLOATBITSTOUINT, result, arg); break;\r
932                 case EOpIntBitsToFloat:   if(visit == PostVisit) emit(sw::Shader::OPCODE_INTBITSTOFLOAT, result, arg); break;\r
933                 case EOpUintBitsToFloat:  if(visit == PostVisit) emit(sw::Shader::OPCODE_UINTBITSTOFLOAT, result, arg); break;\r
934                 case EOpPackSnorm2x16:    if(visit == PostVisit) emit(sw::Shader::OPCODE_PACKSNORM2x16, result, arg); break;\r
935                 case EOpPackUnorm2x16:    if(visit == PostVisit) emit(sw::Shader::OPCODE_PACKUNORM2x16, result, arg); break;\r
936                 case EOpPackHalf2x16:     if(visit == PostVisit) emit(sw::Shader::OPCODE_PACKHALF2x16, result, arg); break;\r
937                 case EOpUnpackSnorm2x16:  if(visit == PostVisit) emit(sw::Shader::OPCODE_UNPACKSNORM2x16, result, arg); break;\r
938                 case EOpUnpackUnorm2x16:  if(visit == PostVisit) emit(sw::Shader::OPCODE_UNPACKUNORM2x16, result, arg); break;\r
939                 case EOpUnpackHalf2x16:   if(visit == PostVisit) emit(sw::Shader::OPCODE_UNPACKHALF2x16, result, arg); break;\r
940                 case EOpTranspose:\r
941                         if(visit == PostVisit)\r
942                         {\r
943                                 int numCols = arg->getNominalSize();\r
944                                 int numRows = arg->getSecondarySize();\r
945                                 for(int i = 0; i < numCols; ++i)\r
946                                 {\r
947                                         for(int j = 0; j < numRows; ++j)\r
948                                         {\r
949                                                 Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, arg);\r
950                                                 mov->src[0].index += i;\r
951                                                 mov->src[0].swizzle = 0x55 * j;\r
952                                                 mov->dst.index += j;\r
953                                                 mov->dst.mask = 1 << i;\r
954                                         }\r
955                                 }\r
956                         }\r
957                         break;\r
958                 case EOpDeterminant:\r
959                         if(visit == PostVisit)\r
960                         {\r
961                                 int size = arg->getNominalSize();\r
962                                 ASSERT(size == arg->getSecondarySize());\r
963 \r
964                                 emitDeterminant(result, arg, size);\r
965                         }\r
966                         break;\r
967                 case EOpInverse:\r
968                         if(visit == PostVisit)\r
969                         {\r
970                                 int size = arg->getNominalSize();\r
971                                 ASSERT(size == arg->getSecondarySize());\r
972 \r
973                                 // Compute transposed matrix of cofactors\r
974                                 for(int i = 0; i < size; ++i)\r
975                                 {\r
976                                         for(int j = 0; j < size; ++j)\r
977                                         {\r
978                                                 // For a 2x2 matrix, the cofactor is simply a transposed move or negate\r
979                                                 // For a 3x3 or 4x4 matrix, the cofactor is a transposed determinant\r
980                                                 emitDeterminant(result, arg, size - 1, j, i, i, j);\r
981                                         }\r
982                                 }\r
983 \r
984                                 // Compute 1 / determinant\r
985                                 Temporary invDet(this);\r
986                                 emitDeterminant(&invDet, arg, size);\r
987                                 Constant one(1.0f, 1.0f, 1.0f, 1.0f);\r
988                                 Instruction *div = emit(sw::Shader::OPCODE_DIV, &invDet, &one, &invDet);\r
989                                 div->src[1].swizzle = 0x00; // xxxx\r
990 \r
991                                 // Divide transposed matrix of cofactors by determinant\r
992                                 for(int i = 0; i < size; ++i)\r
993                                 {\r
994                                         Instruction *div = emit(sw::Shader::OPCODE_MUL, result, result, &invDet);\r
995                                         div->src[0].index += i;\r
996                                         div->dst.index += i;\r
997                                 }\r
998                         }\r
999                         break;\r
1000                 default: UNREACHABLE(node->getOp());\r
1001                 }\r
1002 \r
1003                 return true;\r
1004         }\r
1005 \r
1006         bool OutputASM::visitAggregate(Visit visit, TIntermAggregate *node)\r
1007         {\r
1008                 if(currentScope != emitScope && node->getOp() != EOpFunction && node->getOp() != EOpSequence)\r
1009                 {\r
1010                         return false;\r
1011                 }\r
1012 \r
1013                 Constant zero(0.0f, 0.0f, 0.0f, 0.0f);\r
1014 \r
1015                 TIntermTyped *result = node;\r
1016                 const TType &resultType = node->getType();\r
1017                 TIntermSequence &arg = node->getSequence();\r
1018                 int argumentCount = arg.size();\r
1019 \r
1020                 switch(node->getOp())\r
1021                 {\r
1022                 case EOpSequence:           break;\r
1023                 case EOpDeclaration:        break;\r
1024                 case EOpPrototype:          break;\r
1025                 case EOpComma:\r
1026                         if(visit == PostVisit)\r
1027                         {\r
1028                                 copy(result, arg[1]);\r
1029                         }\r
1030                         break;\r
1031                 case EOpFunction:\r
1032                         if(visit == PreVisit)\r
1033                         {\r
1034                                 const TString &name = node->getName();\r
1035 \r
1036                                 if(emitScope == FUNCTION)\r
1037                                 {\r
1038                                         if(functionArray.size() > 1)   // No need for a label when there's only main()\r
1039                                         {\r
1040                                                 Instruction *label = emit(sw::Shader::OPCODE_LABEL);\r
1041                                                 label->dst.type = sw::Shader::PARAMETER_LABEL;\r
1042 \r
1043                                                 const Function *function = findFunction(name);\r
1044                                                 ASSERT(function);   // Should have been added during global pass\r
1045                                                 label->dst.index = function->label;\r
1046                                                 currentFunction = function->label;\r
1047                                         }\r
1048                                 }\r
1049                                 else if(emitScope == GLOBAL)\r
1050                                 {\r
1051                                         if(name != "main(")\r
1052                                         {\r
1053                                                 TIntermSequence &arguments = node->getSequence()[0]->getAsAggregate()->getSequence();\r
1054                                                 functionArray.push_back(Function(functionArray.size(), name, &arguments, node));\r
1055                                         }\r
1056                                 }\r
1057                                 else UNREACHABLE(emitScope);\r
1058 \r
1059                                 currentScope = FUNCTION;\r
1060                         }\r
1061                         else if(visit == PostVisit)\r
1062                         {\r
1063                                 if(emitScope == FUNCTION)\r
1064                                 {\r
1065                                         if(functionArray.size() > 1)   // No need to return when there's only main()\r
1066                                         {\r
1067                                                 emit(sw::Shader::OPCODE_RET);\r
1068                                         }\r
1069                                 }\r
1070 \r
1071                                 currentScope = GLOBAL;\r
1072                         }\r
1073                         break;\r
1074                 case EOpFunctionCall:\r
1075                         if(visit == PostVisit)\r
1076                         {\r
1077                                 if(node->isUserDefined())\r
1078                                 {\r
1079                                         const TString &name = node->getName();\r
1080                                         const Function *function = findFunction(name);\r
1081 \r
1082                                         if(!function)\r
1083                                         {\r
1084                                                 mContext.error(node->getLine(), "function definition not found", name.c_str());\r
1085                                                 return false;\r
1086                                         }\r
1087 \r
1088                                         TIntermSequence &arguments = *function->arg;\r
1089 \r
1090                                         for(int i = 0; i < argumentCount; i++)\r
1091                                         {\r
1092                                                 TIntermTyped *in = arguments[i]->getAsTyped();\r
1093 \r
1094                                                 if(in->getQualifier() == EvqIn ||\r
1095                                                    in->getQualifier() == EvqInOut ||\r
1096                                                    in->getQualifier() == EvqConstReadOnly)\r
1097                                                 {\r
1098                                                         copy(in, arg[i]);\r
1099                                                 }\r
1100                                         }\r
1101 \r
1102                                         Instruction *call = emit(sw::Shader::OPCODE_CALL);\r
1103                                         call->dst.type = sw::Shader::PARAMETER_LABEL;\r
1104                                         call->dst.index = function->label;\r
1105 \r
1106                                         if(function->ret && function->ret->getType().getBasicType() != EbtVoid)\r
1107                                         {\r
1108                                                 copy(result, function->ret);\r
1109                                         }\r
1110 \r
1111                                         for(int i = 0; i < argumentCount; i++)\r
1112                                         {\r
1113                                                 TIntermTyped *argument = arguments[i]->getAsTyped();\r
1114                                                 TIntermTyped *out = arg[i]->getAsTyped();\r
1115                                                                 \r
1116                                                 if(argument->getQualifier() == EvqOut ||\r
1117                                                    argument->getQualifier() == EvqInOut)\r
1118                                                 {\r
1119                                                         copy(out, argument);\r
1120                                                 }\r
1121                                         }\r
1122                                 }\r
1123                                 else\r
1124                                 {\r
1125                                         const TextureFunction textureFunction(node->getName());\r
1126                                         switch(textureFunction.method)\r
1127                                         {\r
1128                                         case TextureFunction::IMPLICIT:\r
1129                                                 {\r
1130                                                         TIntermTyped *t = arg[1]->getAsTyped();\r
1131 \r
1132                                                         TIntermNode* offset = textureFunction.offset ? arg[2] : 0;\r
1133 \r
1134                                                         if(argumentCount == 2 || (textureFunction.offset && argumentCount == 3))\r
1135                                                         {\r
1136                                                                 Instruction *tex = emit(textureFunction.offset ? sw::Shader::OPCODE_TEXOFFSET : sw::Shader::OPCODE_TEX,\r
1137                                                                                         result, arg[1], arg[0], offset);\r
1138                                                                 if(textureFunction.proj)\r
1139                                                                 {\r
1140                                                                         tex->project = true;\r
1141 \r
1142                                                                         switch(t->getNominalSize())\r
1143                                                                         {\r
1144                                                                         case 2: tex->src[0].swizzle = 0x54; break; // xyyy\r
1145                                                                         case 3: tex->src[0].swizzle = 0xA4; break; // xyzz\r
1146                                                                         case 4: break; // xyzw\r
1147                                                                         default:\r
1148                                                                                 UNREACHABLE(t->getNominalSize());\r
1149                                                                                 break;\r
1150                                                                         }\r
1151                                                                 }\r
1152                                                         }\r
1153                                                         else if(argumentCount == 3 || (textureFunction.offset && argumentCount == 4))   // bias\r
1154                                                         {\r
1155                                                                 Temporary proj(this);\r
1156                                                                 if(textureFunction.proj)\r
1157                                                                 {\r
1158                                                                         Instruction *div = emit(sw::Shader::OPCODE_DIV, &proj, arg[1], arg[1]);\r
1159                                                                         div->dst.mask = 0x3;\r
1160 \r
1161                                                                         switch(t->getNominalSize())\r
1162                                                                         {\r
1163                                                                         case 2:\r
1164                                                                         case 3:\r
1165                                                                         case 4:\r
1166                                                                                 div->src[1].swizzle = 0x55 * (t->getNominalSize() - 1);\r
1167                                                                                 break;\r
1168                                                                         default:\r
1169                                                                                 UNREACHABLE(t->getNominalSize());\r
1170                                                                                 break;\r
1171                                                                         }\r
1172                                                                 }\r
1173                                                                 else\r
1174                                                                 {\r
1175                                                                         emit(sw::Shader::OPCODE_MOV, &proj, arg[1]);\r
1176                                                                 }\r
1177 \r
1178                                                                 Instruction *bias = emit(sw::Shader::OPCODE_MOV, &proj, arg[textureFunction.offset ? 3 : 2]);\r
1179                                                                 bias->dst.mask = 0x8;\r
1180 \r
1181                                                                 Instruction *tex = emit(textureFunction.offset ? sw::Shader::OPCODE_TEXOFFSET : sw::Shader::OPCODE_TEX, \r
1182                                                                                         result, &proj, arg[0], offset); // FIXME: Implement an efficient TEXLDB instruction\r
1183                                                                 tex->bias = true;\r
1184                                                         }\r
1185                                                         else UNREACHABLE(argumentCount);\r
1186                                                 }\r
1187                                                 break;\r
1188                                         case TextureFunction::LOD:\r
1189                                                 {\r
1190                                                         TIntermTyped *t = arg[1]->getAsTyped();\r
1191                                                         Temporary proj(this);\r
1192 \r
1193                                                         if(textureFunction.proj)\r
1194                                                         {\r
1195                                                                         Instruction *div = emit(sw::Shader::OPCODE_DIV, &proj, arg[1], arg[1]);\r
1196                                                                         div->dst.mask = 0x3;\r
1197 \r
1198                                                                 switch(t->getNominalSize())\r
1199                                                                 {\r
1200                                                                 case 2:\r
1201                                                                 case 3:\r
1202                                                                 case 4:\r
1203                                                                         div->src[1].swizzle = 0x55 * (t->getNominalSize() - 1);\r
1204                                                                         break;\r
1205                                                                 default:\r
1206                                                                         UNREACHABLE(t->getNominalSize());\r
1207                                                                         break;\r
1208                                                                 }\r
1209                                                         }\r
1210                                                         else\r
1211                                                         {\r
1212                                                                 emit(sw::Shader::OPCODE_MOV, &proj, arg[1]);\r
1213                                                         }\r
1214 \r
1215                                                         Instruction *lod = emit(sw::Shader::OPCODE_MOV, &proj, arg[2]);\r
1216                                                         lod->dst.mask = 0x8;\r
1217 \r
1218                                                         emit(textureFunction.offset ? sw::Shader::OPCODE_TEXLDLOFFSET : sw::Shader::OPCODE_TEXLDL,\r
1219                                                              result, &proj, arg[0], textureFunction.offset ? arg[3] : 0);\r
1220                                                 }\r
1221                                                 break;\r
1222                                         case TextureFunction::FETCH:\r
1223                                                 {\r
1224                                                         TIntermTyped *t = arg[1]->getAsTyped();\r
1225 \r
1226                                                         if(argumentCount == 3 || (textureFunction.offset && argumentCount == 4))\r
1227                                                         {\r
1228                                                                 TIntermNode* offset = textureFunction.offset ? arg[3] : 0;\r
1229 \r
1230                                                                 emit(textureFunction.offset ? sw::Shader::OPCODE_TEXELFETCHOFFSET : sw::Shader::OPCODE_TEXELFETCH,\r
1231                                                                      result, arg[1], arg[0], arg[2], offset);\r
1232                                                         }\r
1233                                                         else UNREACHABLE(argumentCount);\r
1234                                                 }\r
1235                                                 break;\r
1236                                         case TextureFunction::GRAD:\r
1237                                                 {\r
1238                                                         TIntermTyped *t = arg[1]->getAsTyped();\r
1239 \r
1240                                                         if(argumentCount == 4 || (textureFunction.offset && argumentCount == 5))\r
1241                                                         {\r
1242                                                                 Temporary uvwb(this);\r
1243 \r
1244                                                                 if(textureFunction.proj)\r
1245                                                                 {\r
1246                                                                         Instruction *div = emit(sw::Shader::OPCODE_DIV, &uvwb, arg[1], arg[1]);\r
1247                                                                         div->dst.mask = 0x3;\r
1248 \r
1249                                                                         switch(t->getNominalSize())\r
1250                                                                         {\r
1251                                                                         case 2:\r
1252                                                                         case 3:\r
1253                                                                         case 4:\r
1254                                                                                 div->src[1].swizzle = 0x55 * (t->getNominalSize() - 1);\r
1255                                                                                 break;\r
1256                                                                         default:\r
1257                                                                                 UNREACHABLE(t->getNominalSize());\r
1258                                                                                 break;\r
1259                                                                         }\r
1260                                                                 }\r
1261                                                                 else\r
1262                                                                 {\r
1263                                                                         emit(sw::Shader::OPCODE_MOV, &uvwb, arg[1]);\r
1264                                                                 }\r
1265 \r
1266                                                                 TIntermNode* offset = textureFunction.offset ? arg[4] : 0;\r
1267 \r
1268                                                                 emit(textureFunction.offset ? sw::Shader::OPCODE_TEXGRADOFFSET : sw::Shader::OPCODE_TEXGRAD,\r
1269                                                                      result, &uvwb, arg[0], arg[2], arg[3], offset);\r
1270                                                         }\r
1271                                                         else UNREACHABLE(argumentCount);\r
1272                                                 }\r
1273                                                 break;\r
1274                                         case TextureFunction::SIZE:\r
1275                                                 emit(sw::Shader::OPCODE_TEXSIZE, result, arg[1], arg[0]);\r
1276                                                 break;\r
1277                                         default:\r
1278                                                 UNREACHABLE(textureFunction.method);\r
1279                                         }\r
1280                                 }\r
1281                         }\r
1282                         break;\r
1283                 case EOpParameters:\r
1284                         break;\r
1285                 case EOpConstructFloat:\r
1286                 case EOpConstructVec2:\r
1287                 case EOpConstructVec3:\r
1288                 case EOpConstructVec4:\r
1289                 case EOpConstructBool:\r
1290                 case EOpConstructBVec2:\r
1291                 case EOpConstructBVec3:\r
1292                 case EOpConstructBVec4:\r
1293                 case EOpConstructInt:\r
1294                 case EOpConstructIVec2:\r
1295                 case EOpConstructIVec3:\r
1296                 case EOpConstructIVec4:\r
1297                 case EOpConstructUInt:\r
1298                 case EOpConstructUVec2:\r
1299                 case EOpConstructUVec3:\r
1300                 case EOpConstructUVec4:\r
1301                         if(visit == PostVisit)\r
1302                         {\r
1303                                 int component = 0;\r
1304 \r
1305                                 for(int i = 0; i < argumentCount; i++)\r
1306                                 {\r
1307                                         TIntermTyped *argi = arg[i]->getAsTyped();\r
1308                                         int size = argi->getNominalSize();\r
1309 \r
1310                                         if(!argi->isMatrix())\r
1311                                         {\r
1312                                                 Instruction *mov = emitCast(result, argi);\r
1313                                                 mov->dst.mask = (0xF << component) & 0xF;\r
1314                                                 mov->src[0].swizzle = readSwizzle(argi, size) << (component * 2);\r
1315 \r
1316                                                 component += size;\r
1317                                         }\r
1318                                         else   // Matrix\r
1319                                         {\r
1320                                                 int column = 0;\r
1321 \r
1322                                                 while(component < resultType.getNominalSize())\r
1323                                                 {\r
1324                                                         Instruction *mov = emitCast(result, argi);\r
1325                                                         mov->dst.mask = (0xF << component) & 0xF;\r
1326                                                         mov->src[0].index += column;\r
1327                                                         mov->src[0].swizzle = readSwizzle(argi, size) << (component * 2);\r
1328 \r
1329                                                         column++;\r
1330                                                         component += size;\r
1331                                                 }\r
1332                                         }\r
1333                                 }\r
1334                         }\r
1335                         break;\r
1336                 case EOpConstructMat2:\r
1337                 case EOpConstructMat2x3:\r
1338                 case EOpConstructMat2x4:\r
1339                 case EOpConstructMat3x2:\r
1340                 case EOpConstructMat3:\r
1341                 case EOpConstructMat3x4:\r
1342                 case EOpConstructMat4x2:\r
1343                 case EOpConstructMat4x3:\r
1344                 case EOpConstructMat4:\r
1345                         if(visit == PostVisit)\r
1346                         {\r
1347                                 TIntermTyped *arg0 = arg[0]->getAsTyped();\r
1348                                 const int outCols = result->getNominalSize();\r
1349                                 const int outRows = result->getSecondarySize();\r
1350 \r
1351                                 if(arg0->isScalar() && arg.size() == 1)   // Construct scale matrix\r
1352                                 {\r
1353                                         for(int i = 0; i < outCols; i++)\r
1354                                         {\r
1355                                                 Instruction *init = emit(sw::Shader::OPCODE_MOV, result, &zero);\r
1356                                                 init->dst.index += i;\r
1357                                                 Instruction *mov = emitCast(result, arg0);\r
1358                                                 mov->dst.index += i;\r
1359                                                 mov->dst.mask = 1 << i;\r
1360                                                 ASSERT(mov->src[0].swizzle == 0x00);\r
1361                                         }\r
1362                                 }\r
1363                                 else if(arg0->isMatrix())\r
1364                                 {\r
1365                                         const int inCols = arg0->getNominalSize();\r
1366                                         const int inRows = arg0->getSecondarySize();\r
1367 \r
1368                                         for(int i = 0; i < outCols; i++)\r
1369                                         {\r
1370                                                 if(i >= inCols || outRows > inRows)\r
1371                                                 {\r
1372                                                         // Initialize to identity matrix\r
1373                                                         Constant col((i == 0 ? 1.0f : 0.0f), (i == 1 ? 1.0f : 0.0f), (i == 2 ? 1.0f : 0.0f), (i == 3 ? 1.0f : 0.0f));\r
1374                                                         Instruction *mov = emitCast(result, &col);\r
1375                                                         mov->dst.index += i;\r
1376                                                 }\r
1377 \r
1378                                                 if(i < inCols)\r
1379                                                 {\r
1380                                                         Instruction *mov = emitCast(result, arg0);\r
1381                                                         mov->dst.index += i;\r
1382                                                         mov->dst.mask = 0xF >> (4 - inRows);\r
1383                                                         argument(mov->src[0], arg0, i);\r
1384                                                 }\r
1385                                         }\r
1386                                 }\r
1387                                 else\r
1388                                 {\r
1389                                         int column = 0;\r
1390                                         int row = 0;\r
1391 \r
1392                                         for(int i = 0; i < argumentCount; i++)\r
1393                                         {\r
1394                                                 TIntermTyped *argi = arg[i]->getAsTyped();\r
1395                                                 int size = argi->getNominalSize();\r
1396                                                 int element = 0;\r
1397 \r
1398                                                 while(element < size)\r
1399                                                 {\r
1400                                                         Instruction *mov = emitCast(result, argi);\r
1401                                                         mov->dst.index += column;\r
1402                                                         mov->dst.mask = (0xF << row) & 0xF;\r
1403                                                         mov->src[0].swizzle = (readSwizzle(argi, size) << (row * 2)) + 0x55 * element;\r
1404 \r
1405                                                         int end = row + size - element;\r
1406                                                         column = end >= outRows ? column + 1 : column;\r
1407                                                         element = element + outRows - row;\r
1408                                                         row = end >= outRows ? 0 : end;\r
1409                                                 }\r
1410                                         }\r
1411                                 }\r
1412                         }\r
1413                         break;\r
1414                 case EOpConstructStruct:\r
1415                         if(visit == PostVisit)\r
1416                         {\r
1417                                 int offset = 0;\r
1418                                 for(int i = 0; i < argumentCount; i++)\r
1419                                 {\r
1420                                         TIntermTyped *argi = arg[i]->getAsTyped();\r
1421                                         int size = argi->totalRegisterCount();\r
1422 \r
1423                                         for(int index = 0; index < size; index++)\r
1424                                         {\r
1425                                                 Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, argi);\r
1426                                                 mov->dst.index += index + offset;\r
1427                                                 mov->dst.mask = writeMask(result, offset + index);\r
1428                                                 argument(mov->src[0], argi, index);\r
1429                                         }\r
1430 \r
1431                                         offset += size;\r
1432                                 }\r
1433                         }\r
1434                         break;\r
1435                 case EOpLessThan:         if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_LT, result, arg[0], arg[1]); break;\r
1436                 case EOpGreaterThan:      if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_GT, result, arg[0], arg[1]); break;\r
1437                 case EOpLessThanEqual:    if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_LE, result, arg[0], arg[1]); break;\r
1438                 case EOpGreaterThanEqual: if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_GE, result, arg[0], arg[1]); break;\r
1439                 case EOpVectorEqual:      if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_EQ, result, arg[0], arg[1]); break;\r
1440                 case EOpVectorNotEqual:   if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_NE, result, arg[0], arg[1]); break;\r
1441                 case EOpMod:              if(visit == PostVisit) emit(sw::Shader::OPCODE_MOD, result, arg[0], arg[1]); break;\r
1442                 case EOpPow:              if(visit == PostVisit) emit(sw::Shader::OPCODE_POW, result, arg[0], arg[1]); break;\r
1443                 case EOpAtan:             if(visit == PostVisit) emit(sw::Shader::OPCODE_ATAN2, result, arg[0], arg[1]); break;\r
1444                 case EOpMin:              if(visit == PostVisit) emit(getOpcode(sw::Shader::OPCODE_MIN, result), result, arg[0], arg[1]); break;\r
1445                 case EOpMax:              if(visit == PostVisit) emit(getOpcode(sw::Shader::OPCODE_MAX, result), result, arg[0], arg[1]); break;\r
1446                 case EOpClamp:\r
1447                         if(visit == PostVisit)\r
1448                         {\r
1449                                 emit(getOpcode(sw::Shader::OPCODE_MAX, result), result, arg[0], arg[1]);\r
1450                                 emit(getOpcode(sw::Shader::OPCODE_MIN, result), result, result, arg[2]);\r
1451                         }\r
1452                         break;\r
1453                 case EOpMix:         if(visit == PostVisit) emit(sw::Shader::OPCODE_LRP, result, arg[2], arg[1], arg[0]); break;\r
1454                 case EOpStep:        if(visit == PostVisit) emit(sw::Shader::OPCODE_STEP, result, arg[0], arg[1]); break;\r
1455                 case EOpSmoothStep:  if(visit == PostVisit) emit(sw::Shader::OPCODE_SMOOTH, result, arg[0], arg[1], arg[2]); break;\r
1456                 case EOpDistance:    if(visit == PostVisit) emit(sw::Shader::OPCODE_DIST(dim(arg[0])), result, arg[0], arg[1]); break;\r
1457                 case EOpDot:         if(visit == PostVisit) emit(sw::Shader::OPCODE_DP(dim(arg[0])), result, arg[0], arg[1]); break;\r
1458                 case EOpCross:       if(visit == PostVisit) emit(sw::Shader::OPCODE_CRS, result, arg[0], arg[1]); break;\r
1459                 case EOpFaceForward: if(visit == PostVisit) emit(sw::Shader::OPCODE_FORWARD(dim(arg[0])), result, arg[0], arg[1], arg[2]); break;\r
1460                 case EOpReflect:     if(visit == PostVisit) emit(sw::Shader::OPCODE_REFLECT(dim(arg[0])), result, arg[0], arg[1]); break;\r
1461                 case EOpRefract:     if(visit == PostVisit) emit(sw::Shader::OPCODE_REFRACT(dim(arg[0])), result, arg[0], arg[1], arg[2]); break;\r
1462                 case EOpMul:\r
1463                         if(visit == PostVisit)\r
1464                         {\r
1465                                 TIntermTyped *arg0 = arg[0]->getAsTyped();\r
1466                                 TIntermTyped *arg1 = arg[1]->getAsTyped();\r
1467                                 ASSERT((arg0->getNominalSize() == arg1->getNominalSize()) && (arg0->getSecondarySize() == arg1->getSecondarySize()));\r
1468 \r
1469                                 int size = arg0->getNominalSize();\r
1470                                 for(int i = 0; i < size; i++)\r
1471                                 {\r
1472                                         Instruction *mul = emit(sw::Shader::OPCODE_MUL, result, arg[0], arg[1]);\r
1473                                         mul->dst.index += i;\r
1474                                         argument(mul->src[0], arg[0], i);\r
1475                                         argument(mul->src[1], arg[1], i);\r
1476                                 }\r
1477                         }\r
1478                         break;\r
1479                 case EOpOuterProduct:\r
1480                         if(visit == PostVisit)\r
1481                         {\r
1482                                 for(int i = 0; i < dim(arg[1]); i++)\r
1483                                 {\r
1484                                         Instruction *mul = emit(sw::Shader::OPCODE_MUL, result, arg[0], arg[1]);\r
1485                                         mul->dst.index += i;\r
1486                                         mul->src[1].swizzle = 0x55 * i;\r
1487                                 }\r
1488                         }\r
1489                         break;\r
1490                 default: UNREACHABLE(node->getOp());\r
1491                 }\r
1492 \r
1493                 return true;\r
1494         }\r
1495 \r
1496         bool OutputASM::visitSelection(Visit visit, TIntermSelection *node)\r
1497         {\r
1498                 if(currentScope != emitScope)\r
1499                 {\r
1500                         return false;\r
1501                 }\r
1502 \r
1503                 TIntermTyped *condition = node->getCondition();\r
1504                 TIntermNode *trueBlock = node->getTrueBlock();\r
1505                 TIntermNode *falseBlock = node->getFalseBlock();\r
1506                 TIntermConstantUnion *constantCondition = condition->getAsConstantUnion();\r
1507 \r
1508                 condition->traverse(this);\r
1509 \r
1510                 if(node->usesTernaryOperator())\r
1511                 {\r
1512                         if(constantCondition)\r
1513                         {\r
1514                                 bool trueCondition = constantCondition->getUnionArrayPointer()->getBConst();\r
1515 \r
1516                                 if(trueCondition)\r
1517                                 {\r
1518                                         trueBlock->traverse(this);\r
1519                                         copy(node, trueBlock);\r
1520                                 }\r
1521                                 else\r
1522                                 {\r
1523                                         falseBlock->traverse(this);\r
1524                                         copy(node, falseBlock);\r
1525                                 }\r
1526                         }\r
1527                         else if(trivial(node, 6))   // Fast to compute both potential results and no side effects\r
1528                         {\r
1529                                 trueBlock->traverse(this);\r
1530                                 falseBlock->traverse(this);\r
1531                                 emit(sw::Shader::OPCODE_SELECT, node, condition, trueBlock, falseBlock);\r
1532                         }\r
1533                         else\r
1534                         {\r
1535                                 emit(sw::Shader::OPCODE_IF, 0, condition);\r
1536 \r
1537                                 if(trueBlock)\r
1538                                 {\r
1539                                         trueBlock->traverse(this);\r
1540                                         copy(node, trueBlock);\r
1541                                 }\r
1542 \r
1543                                 if(falseBlock)\r
1544                                 {\r
1545                                         emit(sw::Shader::OPCODE_ELSE);\r
1546                                         falseBlock->traverse(this);\r
1547                                         copy(node, falseBlock);\r
1548                                 }\r
1549 \r
1550                                 emit(sw::Shader::OPCODE_ENDIF);\r
1551                         }\r
1552                 }\r
1553                 else  // if/else statement\r
1554                 {\r
1555                         if(constantCondition)\r
1556                         {\r
1557                                 bool trueCondition = constantCondition->getUnionArrayPointer()->getBConst();\r
1558 \r
1559                                 if(trueCondition)\r
1560                                 {\r
1561                                         if(trueBlock)\r
1562                                         {\r
1563                                                 trueBlock->traverse(this);\r
1564                                         }\r
1565                                 }\r
1566                                 else\r
1567                                 {\r
1568                                         if(falseBlock)\r
1569                                         {\r
1570                                                 falseBlock->traverse(this);\r
1571                                         }\r
1572                                 }\r
1573                         }\r
1574                         else\r
1575                         {\r
1576                                 emit(sw::Shader::OPCODE_IF, 0, condition);\r
1577 \r
1578                                 if(trueBlock)\r
1579                                 {\r
1580                                         trueBlock->traverse(this);\r
1581                                 }\r
1582 \r
1583                                 if(falseBlock)\r
1584                                 {\r
1585                                         emit(sw::Shader::OPCODE_ELSE);\r
1586                                         falseBlock->traverse(this);\r
1587                                 }\r
1588 \r
1589                                 emit(sw::Shader::OPCODE_ENDIF);\r
1590                         }\r
1591                 }\r
1592 \r
1593                 return false;\r
1594         }\r
1595 \r
1596         bool OutputASM::visitLoop(Visit visit, TIntermLoop *node)\r
1597         {\r
1598                 if(currentScope != emitScope)\r
1599                 {\r
1600                         return false;\r
1601                 }\r
1602 \r
1603                 unsigned int iterations = loopCount(node);\r
1604 \r
1605                 if(iterations == 0)\r
1606                 {\r
1607                         return false;\r
1608                 }\r
1609 \r
1610                 bool unroll = (iterations <= 4);\r
1611 \r
1612                 if(unroll)\r
1613                 {\r
1614                         DetectLoopDiscontinuity detectLoopDiscontinuity;\r
1615                         unroll = !detectLoopDiscontinuity.traverse(node);\r
1616                 }\r
1617 \r
1618                 TIntermNode *init = node->getInit();\r
1619                 TIntermTyped *condition = node->getCondition();\r
1620                 TIntermTyped *expression = node->getExpression();\r
1621                 TIntermNode *body = node->getBody();\r
1622                 \r
1623                 if(node->getType() == ELoopDoWhile)\r
1624                 {\r
1625                         Temporary iterate(this);\r
1626                         Constant True(true);\r
1627                         emit(sw::Shader::OPCODE_MOV, &iterate, &True);\r
1628 \r
1629                         emit(sw::Shader::OPCODE_WHILE, 0, &iterate);   // FIXME: Implement real do-while\r
1630 \r
1631                         if(body)\r
1632                         {\r
1633                                 body->traverse(this);\r
1634                         }\r
1635 \r
1636                         emit(sw::Shader::OPCODE_TEST);\r
1637 \r
1638                         condition->traverse(this);\r
1639                         emit(sw::Shader::OPCODE_MOV, &iterate, condition);\r
1640 \r
1641                         emit(sw::Shader::OPCODE_ENDWHILE);\r
1642                 }\r
1643                 else\r
1644                 {\r
1645                         if(init)\r
1646                         {\r
1647                                 init->traverse(this);\r
1648                         }\r
1649 \r
1650                         if(unroll)\r
1651                         {\r
1652                                 for(unsigned int i = 0; i < iterations; i++)\r
1653                                 {\r
1654                                 //      condition->traverse(this);   // Condition could contain statements, but not in an unrollable loop\r
1655 \r
1656                                         if(body)\r
1657                                         {\r
1658                                                 body->traverse(this);\r
1659                                         }\r
1660 \r
1661                                         if(expression)\r
1662                                         {\r
1663                                                 expression->traverse(this);\r
1664                                         }\r
1665                                 }\r
1666                         }\r
1667                         else\r
1668                         {\r
1669                                 if(condition)\r
1670                                 {\r
1671                                         condition->traverse(this);\r
1672                                 }\r
1673 \r
1674                                 emit(sw::Shader::OPCODE_WHILE, 0, condition);\r
1675 \r
1676                                 if(body)\r
1677                                 {\r
1678                                         body->traverse(this);\r
1679                                 }\r
1680 \r
1681                                 emit(sw::Shader::OPCODE_TEST);\r
1682 \r
1683                                 if(expression)\r
1684                                 {\r
1685                                         expression->traverse(this);\r
1686                                 }\r
1687 \r
1688                                 if(condition)\r
1689                                 {\r
1690                                         condition->traverse(this);\r
1691                                 }\r
1692 \r
1693                                 emit(sw::Shader::OPCODE_ENDWHILE);\r
1694                         }\r
1695                 }\r
1696 \r
1697                 return false;\r
1698         }\r
1699 \r
1700         bool OutputASM::visitBranch(Visit visit, TIntermBranch *node)\r
1701         {\r
1702                 if(currentScope != emitScope)\r
1703                 {\r
1704                         return false;\r
1705                 }\r
1706 \r
1707                 switch(node->getFlowOp())\r
1708                 {\r
1709                 case EOpKill:      if(visit == PostVisit) emit(sw::Shader::OPCODE_DISCARD);  break;\r
1710                 case EOpBreak:     if(visit == PostVisit) emit(sw::Shader::OPCODE_BREAK);    break;\r
1711                 case EOpContinue:  if(visit == PostVisit) emit(sw::Shader::OPCODE_CONTINUE); break;\r
1712                 case EOpReturn:\r
1713                         if(visit == PostVisit)\r
1714                         {\r
1715                                 TIntermTyped *value = node->getExpression();\r
1716 \r
1717                                 if(value)\r
1718                                 {\r
1719                                         copy(functionArray[currentFunction].ret, value);\r
1720                                 }\r
1721 \r
1722                                 emit(sw::Shader::OPCODE_LEAVE);\r
1723                         }\r
1724                         break;\r
1725                 default: UNREACHABLE(node->getFlowOp());\r
1726                 }\r
1727 \r
1728                 return true;\r
1729         }\r
1730 \r
1731         bool OutputASM::isSamplerRegister(TIntermTyped *operand)\r
1732         {\r
1733                 return operand && isSamplerRegister(operand->getType());\r
1734         }\r
1735 \r
1736         bool OutputASM::isSamplerRegister(const TType &type)\r
1737         {\r
1738                 // A sampler register's qualifiers can be:\r
1739                 // - EvqUniform: The sampler uniform is used as is in the code (default case).\r
1740                 // - EvqTemporary: The sampler is indexed. It's still a sampler register.\r
1741                 // - EvqIn (and other similar types): The sampler has been passed as a function argument. At this point,\r
1742                 //                                    the sampler has been copied and is no longer a sampler register.\r
1743                 return IsSampler(type.getBasicType()) && (type.getQualifier() == EvqUniform || type.getQualifier() == EvqTemporary);\r
1744         }\r
1745 \r
1746         Instruction *OutputASM::emit(sw::Shader::Opcode op, TIntermTyped *dst, TIntermNode *src0, TIntermNode *src1, TIntermNode *src2, TIntermNode *src3, TIntermNode *src4, int index)\r
1747         {\r
1748                 if(isSamplerRegister(dst))\r
1749                 {\r
1750                         op = sw::Shader::OPCODE_NULL;   // Can't assign to a sampler, but this is hit when indexing sampler arrays\r
1751                 }\r
1752 \r
1753                 Instruction *instruction = new Instruction(op);\r
1754 \r
1755                 if(dst)\r
1756                 {\r
1757                         instruction->dst.type = registerType(dst);\r
1758                         instruction->dst.index = registerIndex(dst) + index;\r
1759                         instruction->dst.mask = writeMask(dst);\r
1760                         instruction->dst.integer = (dst->getBasicType() == EbtInt);\r
1761                 }\r
1762 \r
1763                 argument(instruction->src[0], src0, index);\r
1764                 argument(instruction->src[1], src1, index);\r
1765                 argument(instruction->src[2], src2, index);\r
1766                 argument(instruction->src[3], src3, index);\r
1767                 argument(instruction->src[4], src4, index);\r
1768 \r
1769                 shader->append(instruction);\r
1770 \r
1771                 return instruction;\r
1772         }\r
1773 \r
1774         Instruction *OutputASM::emitCast(TIntermTyped *dst, TIntermTyped *src)\r
1775         {\r
1776                 switch(src->getBasicType())\r
1777                 {\r
1778                 case EbtBool:\r
1779                         switch(dst->getBasicType())\r
1780                         {\r
1781                         case EbtInt:   return emit(sw::Shader::OPCODE_B2I, dst, src);\r
1782                         case EbtUInt:  return emit(sw::Shader::OPCODE_B2U, dst, src);\r
1783                         case EbtFloat: return emit(sw::Shader::OPCODE_B2F, dst, src);\r
1784                         default:       break;\r
1785                         }\r
1786                         break;\r
1787                 case EbtInt:\r
1788                         switch(dst->getBasicType())\r
1789                         {\r
1790                         case EbtBool:  return emit(sw::Shader::OPCODE_I2B, dst, src);\r
1791                         case EbtFloat: return emit(sw::Shader::OPCODE_I2F, dst, src);\r
1792                         default:       break;\r
1793                         }\r
1794                         break;\r
1795                 case EbtUInt:\r
1796                         switch(dst->getBasicType())\r
1797                         {\r
1798                         case EbtBool:  return emit(sw::Shader::OPCODE_U2B, dst, src);\r
1799                         case EbtFloat: return emit(sw::Shader::OPCODE_U2F, dst, src);\r
1800                         default:       break;\r
1801                         }\r
1802                         break;\r
1803                 case EbtFloat:\r
1804                         switch(dst->getBasicType())\r
1805                         {\r
1806                         case EbtBool: return emit(sw::Shader::OPCODE_F2B, dst, src);\r
1807                         case EbtInt:  return emit(sw::Shader::OPCODE_F2I, dst, src);\r
1808                         case EbtUInt: return emit(sw::Shader::OPCODE_F2U, dst, src);\r
1809                         default:      break;\r
1810                         }\r
1811                         break;\r
1812                 default:\r
1813                         break;\r
1814                 }\r
1815 \r
1816                 return emit(sw::Shader::OPCODE_MOV, dst, src);\r
1817         }\r
1818 \r
1819         void OutputASM::emitBinary(sw::Shader::Opcode op, TIntermTyped *dst, TIntermNode *src0, TIntermNode *src1, TIntermNode *src2)\r
1820         {\r
1821                 for(int index = 0; index < dst->elementRegisterCount(); index++)\r
1822                 {\r
1823                         emit(op, dst, src0, src1, src2, 0, 0, index);\r
1824                 }\r
1825         }\r
1826 \r
1827         void OutputASM::emitAssign(sw::Shader::Opcode op, TIntermTyped *result, TIntermTyped *lhs, TIntermTyped *src0, TIntermTyped *src1)\r
1828         {\r
1829                 emitBinary(op, result, src0, src1);\r
1830                 assignLvalue(lhs, result);\r
1831         }\r
1832 \r
1833         void OutputASM::emitCmp(sw::Shader::Control cmpOp, TIntermTyped *dst, TIntermNode *left, TIntermNode *right, int index)\r
1834         {\r
1835                 sw::Shader::Opcode opcode;\r
1836                 switch(left->getAsTyped()->getBasicType())\r
1837                 {\r
1838                 case EbtBool:\r
1839                 case EbtInt:\r
1840                         opcode = sw::Shader::OPCODE_ICMP;\r
1841                         break;\r
1842                 case EbtUInt:\r
1843                         opcode = sw::Shader::OPCODE_UCMP;\r
1844                         break;\r
1845                 default:\r
1846                         opcode = sw::Shader::OPCODE_CMP;\r
1847                         break;\r
1848                 }\r
1849 \r
1850                 Instruction *cmp = emit(opcode, dst, left, right);\r
1851                 cmp->control = cmpOp;\r
1852                 argument(cmp->src[0], left, index);\r
1853                 argument(cmp->src[1], right, index);\r
1854         }\r
1855 \r
1856         int componentCount(const TType &type, int registers)\r
1857         {\r
1858                 if(registers == 0)\r
1859                 {\r
1860                         return 0;\r
1861                 }\r
1862 \r
1863                 if(type.isArray() && registers >= type.elementRegisterCount())\r
1864                 {\r
1865                         int index = registers / type.elementRegisterCount();\r
1866                         registers -= index * type.elementRegisterCount();\r
1867                         return index * type.getElementSize() + componentCount(type, registers);\r
1868                 }\r
1869 \r
1870                 if(type.isStruct() || type.isInterfaceBlock())\r
1871                 {\r
1872                         const TFieldList& fields = type.getStruct() ? type.getStruct()->fields() : type.getInterfaceBlock()->fields();\r
1873                         int elements = 0;\r
1874 \r
1875                         for(TFieldList::const_iterator field = fields.begin(); field != fields.end(); field++)\r
1876                         {\r
1877                                 const TType &fieldType = *((*field)->type());\r
1878 \r
1879                                 if(fieldType.totalRegisterCount() <= registers)\r
1880                                 {\r
1881                                         registers -= fieldType.totalRegisterCount();\r
1882                                         elements += fieldType.getObjectSize();\r
1883                                 }\r
1884                                 else   // Register within this field\r
1885                                 {\r
1886                                         return elements + componentCount(fieldType, registers);\r
1887                                 }\r
1888                         }\r
1889                 }\r
1890                 else if(type.isMatrix())\r
1891                 {\r
1892                         return registers * type.registerSize();\r
1893                 }\r
1894                 \r
1895                 UNREACHABLE(0);\r
1896                 return 0;\r
1897         }\r
1898 \r
1899         int registerSize(const TType &type, int registers)\r
1900         {\r
1901                 if(registers == 0)\r
1902                 {\r
1903                         if(type.isStruct())\r
1904                         {\r
1905                                 return registerSize(*((*(type.getStruct()->fields().begin()))->type()), 0);\r
1906                         }\r
1907 \r
1908                         return type.registerSize();\r
1909                 }\r
1910 \r
1911                 if(type.isArray() && registers >= type.elementRegisterCount())\r
1912                 {\r
1913                         int index = registers / type.elementRegisterCount();\r
1914                         registers -= index * type.elementRegisterCount();\r
1915                         return registerSize(type, registers);\r
1916                 }\r
1917 \r
1918                 if(type.isStruct() || type.isInterfaceBlock())\r
1919                 {\r
1920                         const TFieldList& fields = type.getStruct() ? type.getStruct()->fields() : type.getInterfaceBlock()->fields();\r
1921                         int elements = 0;\r
1922 \r
1923                         for(TFieldList::const_iterator field = fields.begin(); field != fields.end(); field++)\r
1924                         {\r
1925                                 const TType &fieldType = *((*field)->type());\r
1926                                 \r
1927                                 if(fieldType.totalRegisterCount() <= registers)\r
1928                                 {\r
1929                                         registers -= fieldType.totalRegisterCount();\r
1930                                         elements += fieldType.getObjectSize();\r
1931                                 }\r
1932                                 else   // Register within this field\r
1933                                 {\r
1934                                         return registerSize(fieldType, registers);\r
1935                                 }\r
1936                         }\r
1937                 }\r
1938                 else if(type.isMatrix())\r
1939                 {\r
1940                         return registerSize(type, 0);\r
1941                 }\r
1942                 \r
1943                 UNREACHABLE(0);\r
1944                 return 0;\r
1945         }\r
1946 \r
1947         void OutputASM::argument(sw::Shader::SourceParameter &parameter, TIntermNode *argument, int index)\r
1948         {\r
1949                 if(argument)\r
1950                 {\r
1951                         TIntermTyped *arg = argument->getAsTyped();\r
1952                         const TType &type = arg->getType();\r
1953                         index = (index >= arg->totalRegisterCount()) ? arg->totalRegisterCount() - 1 : index;\r
1954 \r
1955                         int size = registerSize(type, index);\r
1956 \r
1957                         parameter.type = registerType(arg);\r
1958 \r
1959                         if(arg->getQualifier() == EvqConstExpr)\r
1960                         {\r
1961                                 int component = componentCount(type, index);\r
1962                                 ConstantUnion *constants = arg->getAsConstantUnion()->getUnionArrayPointer();\r
1963 \r
1964                                 for(int i = 0; i < 4; i++)\r
1965                                 {\r
1966                                         if(size == 1)   // Replicate\r
1967                                         {\r
1968                                                 parameter.value[i] = constants[component + 0].getAsFloat();\r
1969                                         }\r
1970                                         else if(i < size)\r
1971                                         {\r
1972                                                 parameter.value[i] = constants[component + i].getAsFloat();\r
1973                                         }\r
1974                                         else\r
1975                                         {\r
1976                                                 parameter.value[i] = 0.0f;\r
1977                                         }\r
1978                                 }\r
1979                         }\r
1980                         else\r
1981                         {\r
1982                                 parameter.index = registerIndex(arg) + index;\r
1983 \r
1984                                 if(isSamplerRegister(arg))\r
1985                                 {\r
1986                                         TIntermBinary *binary = argument->getAsBinaryNode();\r
1987 \r
1988                                         if(binary)\r
1989                                         {\r
1990                                                 TIntermTyped *left = binary->getLeft();\r
1991                                                 TIntermTyped *right = binary->getRight();\r
1992 \r
1993                                                 switch(binary->getOp())\r
1994                                                 {\r
1995                                                 case EOpIndexDirect:\r
1996                                                         parameter.index += right->getAsConstantUnion()->getIConst(0);\r
1997                                                         break;\r
1998                                                 case EOpIndexIndirect:\r
1999                                                         if(left->getArraySize() > 1)\r
2000                                                         {\r
2001                                                                 parameter.rel.type = registerType(binary->getRight());\r
2002                                                                 parameter.rel.index = registerIndex(binary->getRight());\r
2003                                                                 parameter.rel.scale = 1;\r
2004                                                                 parameter.rel.deterministic = true;\r
2005                                                         }\r
2006                                                         break;\r
2007                                                 case EOpIndexDirectStruct:\r
2008                                                 case EOpIndexDirectInterfaceBlock:\r
2009                                                         parameter.index += right->getAsConstantUnion()->getIConst(0);\r
2010                                                         break;\r
2011                                                 default:\r
2012                                                         UNREACHABLE(binary->getOp());\r
2013                                                 }\r
2014                                         }\r
2015                                 }\r
2016                         }\r
2017 \r
2018                         if(!IsSampler(arg->getBasicType()))\r
2019                         {\r
2020                                 parameter.swizzle = readSwizzle(arg, size);\r
2021                         }\r
2022                 }\r
2023         }\r
2024 \r
2025         void OutputASM::copy(TIntermTyped *dst, TIntermNode *src, int offset)\r
2026         {\r
2027                 for(int index = 0; index < dst->totalRegisterCount(); index++)\r
2028                 {\r
2029                         Instruction *mov = emit(sw::Shader::OPCODE_MOV, dst, src);\r
2030                         mov->dst.index += index;\r
2031                         mov->dst.mask = writeMask(dst, index);\r
2032                         argument(mov->src[0], src, offset + index);\r
2033                 }\r
2034         }\r
2035 \r
2036         int swizzleElement(int swizzle, int index)\r
2037         {\r
2038                 return (swizzle >> (index * 2)) & 0x03;\r
2039         }\r
2040 \r
2041         int swizzleSwizzle(int leftSwizzle, int rightSwizzle)\r
2042         {\r
2043                 return (swizzleElement(leftSwizzle, swizzleElement(rightSwizzle, 0)) << 0) |\r
2044                        (swizzleElement(leftSwizzle, swizzleElement(rightSwizzle, 1)) << 2) |\r
2045                        (swizzleElement(leftSwizzle, swizzleElement(rightSwizzle, 2)) << 4) |\r
2046                        (swizzleElement(leftSwizzle, swizzleElement(rightSwizzle, 3)) << 6);\r
2047         }\r
2048 \r
2049         void OutputASM::assignLvalue(TIntermTyped *dst, TIntermTyped *src)\r
2050         {\r
2051                 if(src &&\r
2052                         ((src->isVector() && (!dst->isVector() || (dst->getNominalSize() != dst->getNominalSize()))) ||\r
2053                          (src->isMatrix() && (!dst->isMatrix() || (src->getNominalSize() != dst->getNominalSize()) || (src->getSecondarySize() != dst->getSecondarySize())))))\r
2054                 {\r
2055                         return mContext.error(src->getLine(), "Result type should match the l-value type in compound assignment", src->isVector() ? "vector" : "matrix");\r
2056                 }\r
2057 \r
2058                 TIntermBinary *binary = dst->getAsBinaryNode();\r
2059 \r
2060                 if(binary && binary->getOp() == EOpIndexIndirect && dst->isScalar())\r
2061                 {\r
2062                         Instruction *insert = new Instruction(sw::Shader::OPCODE_INSERT);\r
2063                         \r
2064                         Temporary address(this);\r
2065                         lvalue(insert->dst, address, dst);\r
2066 \r
2067                         insert->src[0].type = insert->dst.type;\r
2068                         insert->src[0].index = insert->dst.index;\r
2069                         insert->src[0].rel = insert->dst.rel;\r
2070                         argument(insert->src[1], src);\r
2071                         argument(insert->src[2], binary->getRight());\r
2072 \r
2073                         shader->append(insert);\r
2074                 }\r
2075                 else\r
2076                 {\r
2077                         for(int offset = 0; offset < dst->totalRegisterCount(); offset++)\r
2078                         {\r
2079                                 Instruction *mov = new Instruction(sw::Shader::OPCODE_MOV);\r
2080                         \r
2081                                 Temporary address(this);\r
2082                                 int swizzle = lvalue(mov->dst, address, dst);\r
2083                                 mov->dst.index += offset;\r
2084 \r
2085                                 if(offset > 0)\r
2086                                 {\r
2087                                         mov->dst.mask = writeMask(dst, offset);\r
2088                                 }\r
2089 \r
2090                                 argument(mov->src[0], src, offset);\r
2091                                 mov->src[0].swizzle = swizzleSwizzle(mov->src[0].swizzle, swizzle);\r
2092 \r
2093                                 shader->append(mov);\r
2094                         }\r
2095                 }\r
2096         }\r
2097 \r
2098         int OutputASM::lvalue(sw::Shader::DestinationParameter &dst, Temporary &address, TIntermTyped *node)\r
2099         {\r
2100                 TIntermTyped *result = node;\r
2101                 TIntermBinary *binary = node->getAsBinaryNode();\r
2102                 TIntermSymbol *symbol = node->getAsSymbolNode();\r
2103 \r
2104                 if(binary)\r
2105                 {\r
2106                         TIntermTyped *left = binary->getLeft();\r
2107                         TIntermTyped *right = binary->getRight();\r
2108 \r
2109                         int leftSwizzle = lvalue(dst, address, left);   // Resolve the l-value of the left side\r
2110 \r
2111                         switch(binary->getOp())\r
2112                         {\r
2113                         case EOpIndexDirect:\r
2114                                 {\r
2115                                         int rightIndex = right->getAsConstantUnion()->getIConst(0);\r
2116 \r
2117                                         if(left->isRegister())\r
2118                                         {\r
2119                                                 int leftMask = dst.mask;\r
2120                                                 \r
2121                                                 dst.mask = 1;\r
2122                                                 while((leftMask & dst.mask) == 0)\r
2123                                                 {\r
2124                                                         dst.mask = dst.mask << 1;\r
2125                                                 }\r
2126 \r
2127                                                 int element = swizzleElement(leftSwizzle, rightIndex);\r
2128                                                 dst.mask = 1 << element;\r
2129                                                 \r
2130                                                 return element;\r
2131                                         }\r
2132                                         else if(left->isArray() || left->isMatrix())\r
2133                                         {\r
2134                                                 dst.index += rightIndex * result->totalRegisterCount();\r
2135                                                 return 0xE4;\r
2136                                         }\r
2137                                         else UNREACHABLE(0);\r
2138                                 }\r
2139                                 break;\r
2140                         case EOpIndexIndirect:\r
2141                                 {\r
2142                                         if(left->isRegister())\r
2143                                         {\r
2144                                                 // Requires INSERT instruction (handled by calling function)\r
2145                                         }\r
2146                                         else if(left->isArray() || left->isMatrix())\r
2147                                         {\r
2148                                                 int scale = result->totalRegisterCount();\r
2149 \r
2150                                                 if(dst.rel.type == sw::Shader::PARAMETER_VOID)   // Use the index register as the relative address directly\r
2151                                                 {\r
2152                                                         if(left->totalRegisterCount() > 1)\r
2153                                                         {\r
2154                                                                 sw::Shader::SourceParameter relativeRegister;\r
2155                                                                 argument(relativeRegister, right);\r
2156 \r
2157                                                                 dst.rel.index = relativeRegister.index;\r
2158                                                                 dst.rel.type = relativeRegister.type;\r
2159                                                                 dst.rel.scale = scale;\r
2160                                                                 dst.rel.deterministic = !(vertexShader && left->getQualifier() == EvqUniform);\r
2161                                                         }\r
2162                                                 }\r
2163                                                 else if(dst.rel.index != registerIndex(&address))   // Move the previous index register to the address register\r
2164                                                 {\r
2165                                                         if(scale == 1)\r
2166                                                         {\r
2167                                                                 Constant oldScale((int)dst.rel.scale);\r
2168                                                                 Instruction *mad = emit(sw::Shader::OPCODE_IMAD, &address, &address, &oldScale, right);\r
2169                                                                 mad->src[0].index = dst.rel.index;\r
2170                                                                 mad->src[0].type = dst.rel.type;\r
2171                                                         }\r
2172                                                         else\r
2173                                                         {\r
2174                                                                 Constant oldScale((int)dst.rel.scale);\r
2175                                                                 Instruction *mul = emit(sw::Shader::OPCODE_IMUL, &address, &address, &oldScale);\r
2176                                                                 mul->src[0].index = dst.rel.index;\r
2177                                                                 mul->src[0].type = dst.rel.type;\r
2178 \r
2179                                                                 Constant newScale(scale);\r
2180                                                                 emit(sw::Shader::OPCODE_IMAD, &address, right, &newScale, &address);\r
2181                                                         }\r
2182 \r
2183                                                         dst.rel.type = sw::Shader::PARAMETER_TEMP;\r
2184                                                         dst.rel.index = registerIndex(&address);\r
2185                                                         dst.rel.scale = 1;\r
2186                                                 }\r
2187                                                 else   // Just add the new index to the address register\r
2188                                                 {\r
2189                                                         if(scale == 1)\r
2190                                                         {\r
2191                                                                 emit(sw::Shader::OPCODE_IADD, &address, &address, right);\r
2192                                                         }\r
2193                                                         else\r
2194                                                         {\r
2195                                                                 Constant newScale(scale);\r
2196                                                                 emit(sw::Shader::OPCODE_IMAD, &address, right, &newScale, &address);\r
2197                                                         }\r
2198                                                 }\r
2199                                         }\r
2200                                         else UNREACHABLE(0);\r
2201                                 }\r
2202                                 break;\r
2203                         case EOpIndexDirectStruct:\r
2204                         case EOpIndexDirectInterfaceBlock:\r
2205                                 {\r
2206                                         const TFieldList& fields = (binary->getOp() == EOpIndexDirectStruct) ?\r
2207                                                                left->getType().getStruct()->fields() :\r
2208                                                                left->getType().getInterfaceBlock()->fields();\r
2209                                         int index = right->getAsConstantUnion()->getIConst(0);\r
2210                                         int fieldOffset = 0;\r
2211 \r
2212                                         for(int i = 0; i < index; i++)\r
2213                                         {\r
2214                                                 fieldOffset += fields[i]->type()->totalRegisterCount();\r
2215                                         }\r
2216 \r
2217                                         dst.type = registerType(left);\r
2218                                         dst.index += fieldOffset;\r
2219                                         dst.mask = writeMask(right);\r
2220 \r
2221                                         return 0xE4;\r
2222                                 }\r
2223                                 break;\r
2224                         case EOpVectorSwizzle:\r
2225                                 {\r
2226                                         ASSERT(left->isRegister());\r
2227 \r
2228                                         int leftMask = dst.mask;\r
2229 \r
2230                                         int swizzle = 0;\r
2231                                         int rightMask = 0;\r
2232 \r
2233                                         TIntermSequence &sequence = right->getAsAggregate()->getSequence();\r
2234 \r
2235                                         for(unsigned int i = 0; i < sequence.size(); i++)\r
2236                                         {\r
2237                                                 int index = sequence[i]->getAsConstantUnion()->getIConst(0);\r
2238 \r
2239                                                 int element = swizzleElement(leftSwizzle, index);\r
2240                                                 rightMask = rightMask | (1 << element);\r
2241                                                 swizzle = swizzle | swizzleElement(leftSwizzle, i) << (element * 2);\r
2242                                         }\r
2243                                         \r
2244                                         dst.mask = leftMask & rightMask;\r
2245 \r
2246                                         return swizzle;\r
2247                                 }\r
2248                                 break;\r
2249                         default:\r
2250                                 UNREACHABLE(binary->getOp());   // Not an l-value operator\r
2251                                 break;\r
2252                         }\r
2253                 }\r
2254                 else if(symbol)\r
2255                 {\r
2256                         dst.type = registerType(symbol);\r
2257                         dst.index = registerIndex(symbol);\r
2258                         dst.mask = writeMask(symbol);\r
2259                         return 0xE4;\r
2260                 }\r
2261 \r
2262                 return 0xE4;\r
2263         }\r
2264 \r
2265         sw::Shader::ParameterType OutputASM::registerType(TIntermTyped *operand)\r
2266         {\r
2267                 if(isSamplerRegister(operand))\r
2268                 {\r
2269                         return sw::Shader::PARAMETER_SAMPLER;\r
2270                 }\r
2271 \r
2272                 const TQualifier qualifier = operand->getQualifier();\r
2273                 if((EvqFragColor == qualifier) || (EvqFragData == qualifier))\r
2274                 {\r
2275                         if(((EvqFragData == qualifier) && (EvqFragColor == outputQualifier)) ||\r
2276                            ((EvqFragColor == qualifier) && (EvqFragData == outputQualifier)))\r
2277                         {\r
2278                                 mContext.error(operand->getLine(), "static assignment to both gl_FragData and gl_FragColor", "");\r
2279                         }\r
2280                         outputQualifier = qualifier;\r
2281                 }\r
2282 \r
2283                 switch(qualifier)\r
2284                 {\r
2285                 case EvqTemporary:           return sw::Shader::PARAMETER_TEMP;\r
2286                 case EvqGlobal:              return sw::Shader::PARAMETER_TEMP;\r
2287                 case EvqConstExpr:           return sw::Shader::PARAMETER_FLOAT4LITERAL;   // All converted to float\r
2288                 case EvqAttribute:           return sw::Shader::PARAMETER_INPUT;\r
2289                 case EvqVaryingIn:           return sw::Shader::PARAMETER_INPUT;\r
2290                 case EvqVaryingOut:          return sw::Shader::PARAMETER_OUTPUT;\r
2291                 case EvqVertexIn:            return sw::Shader::PARAMETER_INPUT;\r
2292                 case EvqFragmentOut:         return sw::Shader::PARAMETER_COLOROUT;\r
2293                 case EvqVertexOut:           return sw::Shader::PARAMETER_OUTPUT;\r
2294                 case EvqFragmentIn:          return sw::Shader::PARAMETER_INPUT;\r
2295                 case EvqInvariantVaryingIn:  return sw::Shader::PARAMETER_INPUT;    // FIXME: Guarantee invariance at the backend\r
2296                 case EvqInvariantVaryingOut: return sw::Shader::PARAMETER_OUTPUT;   // FIXME: Guarantee invariance at the backend \r
2297                 case EvqSmooth:              return sw::Shader::PARAMETER_OUTPUT;\r
2298                 case EvqFlat:                return sw::Shader::PARAMETER_OUTPUT;\r
2299                 case EvqCentroidOut:         return sw::Shader::PARAMETER_OUTPUT;\r
2300                 case EvqSmoothIn:            return sw::Shader::PARAMETER_INPUT;\r
2301                 case EvqFlatIn:              return sw::Shader::PARAMETER_INPUT;\r
2302                 case EvqCentroidIn:          return sw::Shader::PARAMETER_INPUT;\r
2303                 case EvqUniform:             return sw::Shader::PARAMETER_CONST;\r
2304                 case EvqIn:                  return sw::Shader::PARAMETER_TEMP;\r
2305                 case EvqOut:                 return sw::Shader::PARAMETER_TEMP;\r
2306                 case EvqInOut:               return sw::Shader::PARAMETER_TEMP;\r
2307                 case EvqConstReadOnly:       return sw::Shader::PARAMETER_TEMP;\r
2308                 case EvqPosition:            return sw::Shader::PARAMETER_OUTPUT;\r
2309                 case EvqPointSize:           return sw::Shader::PARAMETER_OUTPUT;\r
2310                 case EvqInstanceID:          return sw::Shader::PARAMETER_MISCTYPE;\r
2311                 case EvqFragCoord:           return sw::Shader::PARAMETER_MISCTYPE;\r
2312                 case EvqFrontFacing:         return sw::Shader::PARAMETER_MISCTYPE;\r
2313                 case EvqPointCoord:          return sw::Shader::PARAMETER_INPUT;\r
2314                 case EvqFragColor:           return sw::Shader::PARAMETER_COLOROUT;\r
2315                 case EvqFragData:            return sw::Shader::PARAMETER_COLOROUT;\r
2316                 case EvqFragDepth:           return sw::Shader::PARAMETER_DEPTHOUT;\r
2317                 default: UNREACHABLE(qualifier);\r
2318                 }\r
2319 \r
2320                 return sw::Shader::PARAMETER_VOID;\r
2321         }\r
2322 \r
2323         int OutputASM::registerIndex(TIntermTyped *operand)\r
2324         {\r
2325                 if(isSamplerRegister(operand))\r
2326                 {\r
2327                         return samplerRegister(operand);\r
2328                 }\r
2329 \r
2330                 switch(operand->getQualifier())\r
2331                 {\r
2332                 case EvqTemporary:           return temporaryRegister(operand);\r
2333                 case EvqGlobal:              return temporaryRegister(operand);\r
2334                 case EvqConstExpr:           UNREACHABLE(EvqConstExpr);\r
2335                 case EvqAttribute:           return attributeRegister(operand);\r
2336                 case EvqVaryingIn:           return varyingRegister(operand);\r
2337                 case EvqVaryingOut:          return varyingRegister(operand);\r
2338                 case EvqVertexIn:            return attributeRegister(operand);\r
2339                 case EvqFragmentOut:         return fragmentOutputRegister(operand);\r
2340                 case EvqVertexOut:           return varyingRegister(operand);\r
2341                 case EvqFragmentIn:          return varyingRegister(operand);\r
2342                 case EvqInvariantVaryingIn:  return varyingRegister(operand);\r
2343                 case EvqInvariantVaryingOut: return varyingRegister(operand);\r
2344                 case EvqSmooth:              return varyingRegister(operand);\r
2345                 case EvqFlat:                return varyingRegister(operand);\r
2346                 case EvqCentroidOut:         return varyingRegister(operand);\r
2347                 case EvqSmoothIn:            return varyingRegister(operand);\r
2348                 case EvqFlatIn:              return varyingRegister(operand);\r
2349                 case EvqCentroidIn:          return varyingRegister(operand);\r
2350                 case EvqUniform:             return uniformRegister(operand);\r
2351                 case EvqIn:                  return temporaryRegister(operand);\r
2352                 case EvqOut:                 return temporaryRegister(operand);\r
2353                 case EvqInOut:               return temporaryRegister(operand);\r
2354                 case EvqConstReadOnly:       return temporaryRegister(operand);\r
2355                 case EvqPosition:            return varyingRegister(operand);\r
2356                 case EvqPointSize:           return varyingRegister(operand);\r
2357                 case EvqInstanceID:          vertexShader->instanceIdDeclared = true; return 0;\r
2358                 case EvqFragCoord:           pixelShader->vPosDeclared = true;  return 0;\r
2359                 case EvqFrontFacing:         pixelShader->vFaceDeclared = true; return 1;\r
2360                 case EvqPointCoord:          return varyingRegister(operand);\r
2361                 case EvqFragColor:           return 0;\r
2362                 case EvqFragData:            return 0;\r
2363                 case EvqFragDepth:           return 0;\r
2364                 default: UNREACHABLE(operand->getQualifier());\r
2365                 }\r
2366 \r
2367                 return 0;\r
2368         }\r
2369 \r
2370         int OutputASM::writeMask(TIntermTyped *destination, int index)\r
2371         {\r
2372                 if(destination->getQualifier() == EvqPointSize)\r
2373                 {\r
2374                         return 0x2;   // Point size stored in the y component\r
2375                 }\r
2376 \r
2377                 return 0xF >> (4 - registerSize(destination->getType(), index));\r
2378         }\r
2379 \r
2380         int OutputASM::readSwizzle(TIntermTyped *argument, int size)\r
2381         {\r
2382                 if(argument->getQualifier() == EvqPointSize)\r
2383                 {\r
2384                         return 0x55;   // Point size stored in the y component\r
2385                 }\r
2386 \r
2387                 static const unsigned char swizzleSize[5] = {0x00, 0x00, 0x54, 0xA4, 0xE4};   // (void), xxxx, xyyy, xyzz, xyzw\r
2388 \r
2389                 return swizzleSize[size];\r
2390         }\r
2391 \r
2392         // Conservatively checks whether an expression is fast to compute and has no side effects\r
2393         bool OutputASM::trivial(TIntermTyped *expression, int budget)\r
2394         {\r
2395                 if(!expression->isRegister())\r
2396                 {\r
2397                         return false;\r
2398                 }\r
2399 \r
2400                 return cost(expression, budget) >= 0;\r
2401         }\r
2402 \r
2403         // Returns the remaining computing budget (if < 0 the expression is too expensive or has side effects)\r
2404         int OutputASM::cost(TIntermNode *expression, int budget)\r
2405         {\r
2406                 if(budget < 0)\r
2407                 {\r
2408                         return budget;\r
2409                 }\r
2410 \r
2411                 if(expression->getAsSymbolNode())\r
2412                 {\r
2413                         return budget;\r
2414                 }\r
2415                 else if(expression->getAsConstantUnion())\r
2416                 {\r
2417                         return budget;\r
2418                 }\r
2419                 else if(expression->getAsBinaryNode())\r
2420                 {\r
2421                         TIntermBinary *binary = expression->getAsBinaryNode();\r
2422 \r
2423                         switch(binary->getOp())\r
2424                         {\r
2425                         case EOpVectorSwizzle:\r
2426                         case EOpIndexDirect:\r
2427                         case EOpIndexDirectStruct:\r
2428                         case EOpIndexDirectInterfaceBlock:\r
2429                                 return cost(binary->getLeft(), budget - 0);\r
2430                         case EOpAdd:\r
2431                         case EOpSub:\r
2432                         case EOpMul:\r
2433                                 return cost(binary->getLeft(), cost(binary->getRight(), budget - 1));\r
2434                         default:\r
2435                                 return -1;\r
2436                         }\r
2437                 }\r
2438                 else if(expression->getAsUnaryNode())\r
2439                 {\r
2440                         TIntermUnary *unary = expression->getAsUnaryNode();\r
2441 \r
2442                         switch(unary->getOp())\r
2443                         {\r
2444                         case EOpAbs:\r
2445                         case EOpNegative:\r
2446                                 return cost(unary->getOperand(), budget - 1);\r
2447                         default:\r
2448                                 return -1;\r
2449                         }\r
2450                 }\r
2451                 else if(expression->getAsSelectionNode())\r
2452                 {\r
2453                         TIntermSelection *selection = expression->getAsSelectionNode();\r
2454 \r
2455                         if(selection->usesTernaryOperator())\r
2456                         {\r
2457                                 TIntermTyped *condition = selection->getCondition();\r
2458                                 TIntermNode *trueBlock = selection->getTrueBlock();\r
2459                                 TIntermNode *falseBlock = selection->getFalseBlock();\r
2460                                 TIntermConstantUnion *constantCondition = condition->getAsConstantUnion();\r
2461 \r
2462                                 if(constantCondition)\r
2463                                 {\r
2464                                         bool trueCondition = constantCondition->getUnionArrayPointer()->getBConst();\r
2465 \r
2466                                         if(trueCondition)\r
2467                                         {\r
2468                                                 return cost(trueBlock, budget - 0);\r
2469                                         }\r
2470                                         else\r
2471                                         {\r
2472                                                 return cost(falseBlock, budget - 0);\r
2473                                         }\r
2474                                 }\r
2475                                 else\r
2476                                 {\r
2477                                         return cost(trueBlock, cost(falseBlock, budget - 2));\r
2478                                 }\r
2479                         }\r
2480                 }\r
2481 \r
2482                 return -1;\r
2483         }\r
2484 \r
2485         const Function *OutputASM::findFunction(const TString &name)\r
2486         {\r
2487                 for(unsigned int f = 0; f < functionArray.size(); f++)\r
2488                 {\r
2489                         if(functionArray[f].name == name)\r
2490                         {\r
2491                                 return &functionArray[f];\r
2492                         }\r
2493                 }\r
2494 \r
2495                 return 0;\r
2496         }\r
2497         \r
2498         int OutputASM::temporaryRegister(TIntermTyped *temporary)\r
2499         {\r
2500                 return allocate(temporaries, temporary);\r
2501         }\r
2502 \r
2503         int OutputASM::varyingRegister(TIntermTyped *varying)\r
2504         {\r
2505                 int var = lookup(varyings, varying);\r
2506 \r
2507                 if(var == -1)\r
2508                 {\r
2509                         var = allocate(varyings, varying);\r
2510                         int componentCount = varying->registerSize();\r
2511                         int registerCount = varying->totalRegisterCount();\r
2512 \r
2513                         if(pixelShader)\r
2514                         {\r
2515                                 if((var + registerCount) > sw::PixelShader::MAX_INPUT_VARYINGS)\r
2516                                 {\r
2517                                         mContext.error(varying->getLine(), "Varyings packing failed: Too many varyings", "fragment shader");\r
2518                                         return 0;\r
2519                                 }\r
2520 \r
2521                                 if(varying->getQualifier() == EvqPointCoord)\r
2522                                 {\r
2523                                         ASSERT(varying->isRegister());\r
2524                                         if(componentCount >= 1) pixelShader->semantic[var][0] = sw::Shader::Semantic(sw::Shader::USAGE_TEXCOORD, var);\r
2525                                         if(componentCount >= 2) pixelShader->semantic[var][1] = sw::Shader::Semantic(sw::Shader::USAGE_TEXCOORD, var);\r
2526                                         if(componentCount >= 3) pixelShader->semantic[var][2] = sw::Shader::Semantic(sw::Shader::USAGE_TEXCOORD, var);\r
2527                                         if(componentCount >= 4) pixelShader->semantic[var][3] = sw::Shader::Semantic(sw::Shader::USAGE_TEXCOORD, var);\r
2528                                 }\r
2529                                 else\r
2530                                 {\r
2531                                         for(int i = 0; i < varying->totalRegisterCount(); i++)\r
2532                                         {\r
2533                                                 if(componentCount >= 1) pixelShader->semantic[var + i][0] = sw::Shader::Semantic(sw::Shader::USAGE_COLOR, var + i);\r
2534                                                 if(componentCount >= 2) pixelShader->semantic[var + i][1] = sw::Shader::Semantic(sw::Shader::USAGE_COLOR, var + i);\r
2535                                                 if(componentCount >= 3) pixelShader->semantic[var + i][2] = sw::Shader::Semantic(sw::Shader::USAGE_COLOR, var + i);\r
2536                                                 if(componentCount >= 4) pixelShader->semantic[var + i][3] = sw::Shader::Semantic(sw::Shader::USAGE_COLOR, var + i);\r
2537                                         }\r
2538                                 }\r
2539                         }\r
2540                         else if(vertexShader)\r
2541                         {\r
2542                                 if((var + registerCount) > sw::VertexShader::MAX_OUTPUT_VARYINGS)\r
2543                                 {\r
2544                                         mContext.error(varying->getLine(), "Varyings packing failed: Too many varyings", "vertex shader");\r
2545                                         return 0;\r
2546                                 }\r
2547 \r
2548                                 if(varying->getQualifier() == EvqPosition)\r
2549                                 {\r
2550                                         ASSERT(varying->isRegister());\r
2551                                         vertexShader->output[var][0] = sw::Shader::Semantic(sw::Shader::USAGE_POSITION, 0);\r
2552                                         vertexShader->output[var][1] = sw::Shader::Semantic(sw::Shader::USAGE_POSITION, 0);\r
2553                                         vertexShader->output[var][2] = sw::Shader::Semantic(sw::Shader::USAGE_POSITION, 0);\r
2554                                         vertexShader->output[var][3] = sw::Shader::Semantic(sw::Shader::USAGE_POSITION, 0);\r
2555                                         vertexShader->positionRegister = var;\r
2556                                 }\r
2557                                 else if(varying->getQualifier() == EvqPointSize)\r
2558                                 {\r
2559                                         ASSERT(varying->isRegister());\r
2560                                         vertexShader->output[var][0] = sw::Shader::Semantic(sw::Shader::USAGE_PSIZE, 0);\r
2561                                         vertexShader->output[var][1] = sw::Shader::Semantic(sw::Shader::USAGE_PSIZE, 0);\r
2562                                         vertexShader->output[var][2] = sw::Shader::Semantic(sw::Shader::USAGE_PSIZE, 0);\r
2563                                         vertexShader->output[var][3] = sw::Shader::Semantic(sw::Shader::USAGE_PSIZE, 0);\r
2564                                         vertexShader->pointSizeRegister = var;\r
2565                                 }\r
2566                                 else\r
2567                                 {\r
2568                                         // Semantic indexes for user varyings will be assigned during program link to match the pixel shader\r
2569                                 }\r
2570                         }\r
2571                         else UNREACHABLE(0);\r
2572 \r
2573                         declareVarying(varying, var);\r
2574                 }\r
2575 \r
2576                 return var;\r
2577         }\r
2578 \r
2579         void OutputASM::declareVarying(TIntermTyped *varying, int reg)\r
2580         {\r
2581                 if(varying->getQualifier() != EvqPointCoord)   // gl_PointCoord does not need linking\r
2582                 {\r
2583                         const TType &type = varying->getType();\r
2584                         const char *name = varying->getAsSymbolNode()->getSymbol().c_str();\r
2585                         VaryingList &activeVaryings = shaderObject->varyings;\r
2586                         \r
2587                         // Check if this varying has been declared before without having a register assigned\r
2588                         for(VaryingList::iterator v = activeVaryings.begin(); v != activeVaryings.end(); v++)\r
2589                         {\r
2590                                 if(v->name == name)\r
2591                                 {\r
2592                                         if(reg >= 0)\r
2593                                         {\r
2594                                                 ASSERT(v->reg < 0 || v->reg == reg);\r
2595                                                 v->reg = reg;\r
2596                                         }\r
2597 \r
2598                                         return;\r
2599                                 }\r
2600                         }\r
2601                         \r
2602                         activeVaryings.push_back(glsl::Varying(glVariableType(type), name, varying->getArraySize(), reg, 0));\r
2603                 }\r
2604         }\r
2605 \r
2606         int OutputASM::uniformRegister(TIntermTyped *uniform)\r
2607         {\r
2608                 const TType &type = uniform->getType();\r
2609                 ASSERT(!IsSampler(type.getBasicType()));\r
2610                 TInterfaceBlock *block = type.getAsInterfaceBlock();\r
2611                 TIntermSymbol *symbol = uniform->getAsSymbolNode();\r
2612                 ASSERT(symbol || block);\r
2613 \r
2614                 if(symbol || block)\r
2615                 {\r
2616                         int index = lookup(uniforms, uniform);\r
2617 \r
2618                         if(index == -1)\r
2619                         {\r
2620                                 index = allocate(uniforms, uniform);\r
2621                                 const TString &name = symbol ? symbol->getSymbol() : block->name();\r
2622 \r
2623                                 declareUniform(type, name, index);\r
2624                         }\r
2625 \r
2626                         return index;\r
2627                 }\r
2628 \r
2629                 return 0;\r
2630         }\r
2631 \r
2632         int OutputASM::attributeRegister(TIntermTyped *attribute)\r
2633         {\r
2634                 ASSERT(!attribute->isArray());\r
2635 \r
2636                 int index = lookup(attributes, attribute);\r
2637 \r
2638                 if(index == -1)\r
2639                 {\r
2640                         TIntermSymbol *symbol = attribute->getAsSymbolNode();\r
2641                         ASSERT(symbol);\r
2642 \r
2643                         if(symbol)\r
2644                         {\r
2645                                 index = allocate(attributes, attribute);\r
2646                                 const TType &type = attribute->getType();\r
2647                                 int registerCount = attribute->totalRegisterCount();\r
2648 \r
2649                                 if(vertexShader && (index + registerCount) <= sw::VertexShader::MAX_INPUT_ATTRIBUTES)\r
2650                                 {\r
2651                                         for(int i = 0; i < registerCount; i++)\r
2652                                         {\r
2653                                                 vertexShader->input[index + i] = sw::Shader::Semantic(sw::Shader::USAGE_TEXCOORD, index + i);\r
2654                                         }\r
2655                                 }\r
2656 \r
2657                                 ActiveAttributes &activeAttributes = shaderObject->activeAttributes;\r
2658 \r
2659                                 const char *name = symbol->getSymbol().c_str();\r
2660                                 activeAttributes.push_back(Attribute(glVariableType(type), name, type.getArraySize(), type.getLayoutQualifier().location, index));\r
2661                         }\r
2662                 }\r
2663 \r
2664                 return index;\r
2665         }\r
2666 \r
2667         int OutputASM::fragmentOutputRegister(TIntermTyped *fragmentOutput)\r
2668         {\r
2669                 return allocate(fragmentOutputs, fragmentOutput);\r
2670         }\r
2671 \r
2672         int OutputASM::samplerRegister(TIntermTyped *sampler)\r
2673         {\r
2674                 ASSERT(IsSampler(sampler->getType().getBasicType()));\r
2675                 TIntermSymbol *symbol = sampler->getAsSymbolNode();\r
2676                 TIntermBinary *binary = sampler->getAsBinaryNode();\r
2677 \r
2678                 if(symbol)\r
2679                 {\r
2680                         return samplerRegister(symbol);\r
2681                 }\r
2682                 else if(binary)\r
2683                 {\r
2684                         ASSERT(binary->getOp() == EOpIndexDirect || binary->getOp() == EOpIndexIndirect ||\r
2685                                    binary->getOp() == EOpIndexDirectStruct || binary->getOp() == EOpIndexDirectInterfaceBlock);\r
2686 \r
2687                         return samplerRegister(binary->getLeft());   // Index added later\r
2688                 }\r
2689                 else UNREACHABLE(0);\r
2690 \r
2691                 return 0;\r
2692         }\r
2693 \r
2694         int OutputASM::samplerRegister(TIntermSymbol *sampler)\r
2695         {\r
2696                 const TType &type = sampler->getType();\r
2697                 ASSERT(IsSampler(type.getBasicType()) || type.getStruct());   // Structures can contain samplers\r
2698 \r
2699                 int index = lookup(samplers, sampler);\r
2700 \r
2701                 if(index == -1)\r
2702                 {\r
2703                         index = allocate(samplers, sampler);\r
2704 \r
2705                         if(sampler->getQualifier() == EvqUniform)\r
2706                         {\r
2707                                 const char *name = sampler->getSymbol().c_str();\r
2708                                 declareUniform(type, name, index);\r
2709                         }\r
2710                 }\r
2711 \r
2712                 return index;\r
2713         }\r
2714 \r
2715         int OutputASM::lookup(VariableArray &list, TIntermTyped *variable)\r
2716         {\r
2717                 for(unsigned int i = 0; i < list.size(); i++)\r
2718                 {\r
2719                         if(list[i] == variable)\r
2720                         {\r
2721                                 return i;   // Pointer match\r
2722                         }\r
2723                 }\r
2724 \r
2725                 TIntermSymbol *varSymbol = variable->getAsSymbolNode();\r
2726                 TInterfaceBlock *varBlock = variable->getType().getAsInterfaceBlock();\r
2727 \r
2728                 if(varSymbol)\r
2729                 {\r
2730                         for(unsigned int i = 0; i < list.size(); i++)\r
2731                         {\r
2732                                 if(list[i])\r
2733                                 {\r
2734                                         TIntermSymbol *listSymbol = list[i]->getAsSymbolNode();\r
2735 \r
2736                                         if(listSymbol)\r
2737                                         {\r
2738                                                 if(listSymbol->getId() == varSymbol->getId())\r
2739                                                 {\r
2740                                                         ASSERT(listSymbol->getSymbol() == varSymbol->getSymbol());\r
2741                                                         ASSERT(listSymbol->getType() == varSymbol->getType());\r
2742                                                         ASSERT(listSymbol->getQualifier() == varSymbol->getQualifier());\r
2743 \r
2744                                                         return i;\r
2745                                                 }\r
2746                                         }\r
2747                                 }\r
2748                         }\r
2749                 }\r
2750                 else if(varBlock)\r
2751                 {\r
2752                         for(unsigned int i = 0; i < list.size(); i++)\r
2753                         {\r
2754                                 if(list[i])\r
2755                                 {\r
2756                                         TInterfaceBlock *listBlock = list[i]->getType().getAsInterfaceBlock();\r
2757 \r
2758                                         if(listBlock)\r
2759                                         {\r
2760                                                 if(listBlock->name() == varBlock->name())\r
2761                                                 {\r
2762                                                         ASSERT(listBlock->arraySize() == varBlock->arraySize());\r
2763                                                         ASSERT(listBlock->fields() == varBlock->fields());\r
2764                                                         ASSERT(listBlock->blockStorage() == varBlock->blockStorage());\r
2765                                                         ASSERT(listBlock->matrixPacking() == varBlock->matrixPacking());\r
2766 \r
2767                                                         return i;\r
2768                                                 }\r
2769                                         }\r
2770                                 }\r
2771                         }\r
2772                 }\r
2773 \r
2774                 return -1;\r
2775         }\r
2776 \r
2777         int OutputASM::allocate(VariableArray &list, TIntermTyped *variable)\r
2778         {\r
2779                 int index = lookup(list, variable);\r
2780 \r
2781                 if(index == -1)\r
2782                 {\r
2783                         unsigned int registerCount = variable->totalRegisterCount();\r
2784 \r
2785                         for(unsigned int i = 0; i < list.size(); i++)\r
2786                         {\r
2787                                 if(list[i] == 0)\r
2788                                 {\r
2789                                         unsigned int j = 1;\r
2790                                         for( ; j < registerCount && (i + j) < list.size(); j++)\r
2791                                         {\r
2792                                                 if(list[i + j] != 0)\r
2793                                                 {\r
2794                                                         break;\r
2795                                                 }\r
2796                                         }\r
2797 \r
2798                                         if(j == registerCount)   // Found free slots\r
2799                                         {\r
2800                                                 for(unsigned int j = 0; j < registerCount; j++)\r
2801                                                 {\r
2802                                                         list[i + j] = variable;\r
2803                                                 }\r
2804 \r
2805                                                 return i;\r
2806                                         }\r
2807                                 }\r
2808                         }\r
2809 \r
2810                         index = list.size();\r
2811 \r
2812                         for(unsigned int i = 0; i < registerCount; i++)\r
2813                         {\r
2814                                 list.push_back(variable);\r
2815                         }\r
2816                 }\r
2817 \r
2818                 return index;\r
2819         }\r
2820 \r
2821         void OutputASM::free(VariableArray &list, TIntermTyped *variable)\r
2822         {\r
2823                 int index = lookup(list, variable);\r
2824 \r
2825                 if(index >= 0)\r
2826                 {\r
2827                         list[index] = 0;\r
2828                 }\r
2829         }\r
2830 \r
2831         void OutputASM::declareUniform(const TType &type, const TString &name, int registerIndex, int offset, int blockId)\r
2832         {\r
2833                 const TStructure *structure = type.getStruct();\r
2834                 const TInterfaceBlock *block = (type.isInterfaceBlock() || (blockId == -1)) ? type.getInterfaceBlock() : nullptr;\r
2835                 ActiveUniforms &activeUniforms = shaderObject->activeUniforms;\r
2836 \r
2837                 if(block)\r
2838                 {\r
2839                         ActiveUniformBlocks &activeUniformBlocks = shaderObject->activeUniformBlocks;\r
2840                         blockId = activeUniformBlocks.size();\r
2841                         unsigned int dataSize = block->objectSize() * 4; // FIXME: assuming 4 bytes per element\r
2842                         activeUniformBlocks.push_back(UniformBlock(block->name().c_str(), block->hasInstanceName() ? block->instanceName().c_str() : std::string(), dataSize,\r
2843                                                                    block->arraySize(), block->blockStorage(), block->matrixPacking() == EmpRowMajor, registerIndex, blockId));\r
2844                 }\r
2845 \r
2846                 if(!structure && !block)\r
2847                 {\r
2848                         if(blockId >= 0)\r
2849                         {\r
2850                                 shaderObject->activeUniformBlocks[blockId].fields.push_back(activeUniforms.size());\r
2851                         }\r
2852                         activeUniforms.push_back(Uniform(glVariableType(type), glVariablePrecision(type), name.c_str(), type.getArraySize(), registerIndex, offset, blockId));\r
2853 \r
2854                         if(isSamplerRegister(type))\r
2855                         {\r
2856                                 for(int i = 0; i < type.totalRegisterCount(); i++)\r
2857                                 {\r
2858                                         shader->declareSampler(registerIndex + i);\r
2859                                 }\r
2860                         }\r
2861                 }\r
2862                 else\r
2863                 {\r
2864                         const TFieldList& fields = structure ? structure->fields() : block->fields();\r
2865                         const bool containerHasName = structure || block->hasInstanceName();\r
2866                         const TString &containerName = structure ? name : (containerHasName ? block->instanceName() : TString());\r
2867                         if(type.isArray() && (structure || type.isInterfaceBlock()))\r
2868                         {\r
2869                                 int fieldRegisterIndex = (blockId == -1) ? registerIndex : 0;\r
2870                                 int fieldOffset = 0;\r
2871 \r
2872                                 for(int i = 0; i < type.getArraySize(); i++)\r
2873                                 {\r
2874                                         for(size_t j = 0; j < fields.size(); j++)\r
2875                                         {\r
2876                                                 const TType &fieldType = *(fields[j]->type());\r
2877                                                 const TString &fieldName = fields[j]->name();\r
2878 \r
2879                                                 const TString uniformName = containerHasName ? containerName + "[" + str(i) + "]." + fieldName : fieldName;\r
2880                                                 declareUniform(fieldType, uniformName, fieldRegisterIndex, fieldOffset, blockId);\r
2881                                                 int registerCount = fieldType.totalRegisterCount();\r
2882                                                 fieldRegisterIndex += registerCount;\r
2883                                                 fieldOffset += registerCount * fieldType.registerSize();\r
2884                                         }\r
2885                                 }\r
2886                         }\r
2887                         else\r
2888                         {\r
2889                                 int fieldRegisterIndex = (blockId == -1) ? registerIndex : 0;\r
2890                                 int fieldOffset = 0;\r
2891 \r
2892                                 for(size_t i = 0; i < fields.size(); i++)\r
2893                                 {\r
2894                                         const TType &fieldType = *(fields[i]->type());\r
2895                                         const TString &fieldName = fields[i]->name();\r
2896 \r
2897                                         const TString uniformName = containerHasName ? containerName + "." + fieldName : fieldName;\r
2898                                         declareUniform(fieldType, uniformName, fieldRegisterIndex, fieldOffset, blockId);\r
2899                                         int registerCount = fieldType.totalRegisterCount();\r
2900                                         fieldRegisterIndex += registerCount;\r
2901                                         fieldOffset += registerCount * fieldType.registerSize();\r
2902                                 }\r
2903                         }\r
2904                 }\r
2905         }\r
2906 \r
2907         GLenum OutputASM::glVariableType(const TType &type)\r
2908         {\r
2909                 switch(type.getBasicType())\r
2910                 {\r
2911                 case EbtFloat:\r
2912                         if(type.isScalar())\r
2913                         {\r
2914                                 return GL_FLOAT;\r
2915                         }\r
2916                         else if(type.isVector())\r
2917                         {\r
2918                                 switch(type.getNominalSize())\r
2919                                 {\r
2920                                 case 2: return GL_FLOAT_VEC2;\r
2921                                 case 3: return GL_FLOAT_VEC3;\r
2922                                 case 4: return GL_FLOAT_VEC4;\r
2923                                 default: UNREACHABLE(type.getNominalSize());\r
2924                                 }\r
2925                         }\r
2926                         else if(type.isMatrix())\r
2927                         {\r
2928                                 switch(type.getNominalSize())\r
2929                                 {\r
2930                                 case 2:\r
2931                                         switch(type.getSecondarySize())\r
2932                                         {\r
2933                                         case 2: return GL_FLOAT_MAT2;\r
2934                                         case 3: return GL_FLOAT_MAT2x3;\r
2935                                         case 4: return GL_FLOAT_MAT2x4;\r
2936                                         default: UNREACHABLE(type.getSecondarySize());\r
2937                                         }\r
2938                                 case 3:\r
2939                                         switch(type.getSecondarySize())\r
2940                                         {\r
2941                                         case 2: return GL_FLOAT_MAT3x2;\r
2942                                         case 3: return GL_FLOAT_MAT3;\r
2943                                         case 4: return GL_FLOAT_MAT3x4;\r
2944                                         default: UNREACHABLE(type.getSecondarySize());\r
2945                                         }\r
2946                                 case 4:\r
2947                                         switch(type.getSecondarySize())\r
2948                                         {\r
2949                                         case 2: return GL_FLOAT_MAT4x2;\r
2950                                         case 3: return GL_FLOAT_MAT4x3;\r
2951                                         case 4: return GL_FLOAT_MAT4;\r
2952                                         default: UNREACHABLE(type.getSecondarySize());\r
2953                                         }\r
2954                                 default: UNREACHABLE(type.getNominalSize());\r
2955                                 }\r
2956                         }\r
2957                         else UNREACHABLE(0);\r
2958                         break;\r
2959                 case EbtInt:\r
2960                         if(type.isScalar())\r
2961                         {\r
2962                                 return GL_INT;\r
2963                         }\r
2964                         else if(type.isVector())\r
2965                         {\r
2966                                 switch(type.getNominalSize())\r
2967                                 {\r
2968                                 case 2: return GL_INT_VEC2;\r
2969                                 case 3: return GL_INT_VEC3;\r
2970                                 case 4: return GL_INT_VEC4;\r
2971                                 default: UNREACHABLE(type.getNominalSize());\r
2972                                 }\r
2973                         }\r
2974                         else UNREACHABLE(0);\r
2975                         break;\r
2976                 case EbtUInt:\r
2977                         if(type.isScalar())\r
2978                         {\r
2979                                 return GL_UNSIGNED_INT;\r
2980                         }\r
2981                         else if(type.isVector())\r
2982                         {\r
2983                                 switch(type.getNominalSize())\r
2984                                 {\r
2985                                 case 2: return GL_UNSIGNED_INT_VEC2;\r
2986                                 case 3: return GL_UNSIGNED_INT_VEC3;\r
2987                                 case 4: return GL_UNSIGNED_INT_VEC4;\r
2988                                 default: UNREACHABLE(type.getNominalSize());\r
2989                                 }\r
2990                         }\r
2991                         else UNREACHABLE(0);\r
2992                         break;\r
2993                 case EbtBool:\r
2994                         if(type.isScalar())\r
2995                         {\r
2996                                 return GL_BOOL;\r
2997                         }\r
2998                         else if(type.isVector())\r
2999                         {\r
3000                                 switch(type.getNominalSize())\r
3001                                 {\r
3002                                 case 2: return GL_BOOL_VEC2;\r
3003                                 case 3: return GL_BOOL_VEC3;\r
3004                                 case 4: return GL_BOOL_VEC4;\r
3005                                 default: UNREACHABLE(type.getNominalSize());\r
3006                                 }\r
3007                         }\r
3008                         else UNREACHABLE(0);\r
3009                         break;\r
3010                 case EbtSampler2D:\r
3011                         return GL_SAMPLER_2D;\r
3012                 case EbtISampler2D:\r
3013                         return GL_INT_SAMPLER_2D;\r
3014                 case EbtUSampler2D:\r
3015                         return GL_UNSIGNED_INT_SAMPLER_2D;\r
3016                 case EbtSamplerCube:\r
3017                         return GL_SAMPLER_CUBE;\r
3018                 case EbtISamplerCube:\r
3019                         return GL_INT_SAMPLER_CUBE;\r
3020                 case EbtUSamplerCube:\r
3021                         return GL_UNSIGNED_INT_SAMPLER_CUBE;\r
3022                 case EbtSamplerExternalOES:\r
3023                         return GL_SAMPLER_EXTERNAL_OES;\r
3024                 case EbtSampler3D:\r
3025                         return GL_SAMPLER_3D_OES;\r
3026                 case EbtISampler3D:\r
3027                         return GL_INT_SAMPLER_3D;\r
3028                 case EbtUSampler3D:\r
3029                         return GL_UNSIGNED_INT_SAMPLER_3D;\r
3030                 case EbtSampler2DArray:\r
3031                         return GL_SAMPLER_2D_ARRAY;\r
3032                 case EbtISampler2DArray:\r
3033                         return GL_INT_SAMPLER_2D_ARRAY;\r
3034                 case EbtUSampler2DArray:\r
3035                         return GL_UNSIGNED_INT_SAMPLER_2D_ARRAY;\r
3036                 case EbtSampler2DShadow:\r
3037                         return GL_SAMPLER_2D_SHADOW;\r
3038                 case EbtSamplerCubeShadow:\r
3039                         return GL_SAMPLER_CUBE_SHADOW;\r
3040                 case EbtSampler2DArrayShadow:\r
3041                         return GL_SAMPLER_2D_ARRAY_SHADOW;\r
3042                 default:\r
3043                         UNREACHABLE(type.getBasicType());\r
3044                         break;\r
3045                 }\r
3046 \r
3047                 return GL_NONE;\r
3048         }\r
3049 \r
3050         GLenum OutputASM::glVariablePrecision(const TType &type)\r
3051         {\r
3052                 if(type.getBasicType() == EbtFloat)\r
3053                 {\r
3054                         switch(type.getPrecision())\r
3055                         {\r
3056                         case EbpHigh:   return GL_HIGH_FLOAT;\r
3057                         case EbpMedium: return GL_MEDIUM_FLOAT;\r
3058                         case EbpLow:    return GL_LOW_FLOAT;\r
3059                         case EbpUndefined:\r
3060                                 // Should be defined as the default precision by the parser\r
3061                         default: UNREACHABLE(type.getPrecision());\r
3062                         }\r
3063                 }\r
3064                 else if(type.getBasicType() == EbtInt)\r
3065                 {\r
3066                         switch(type.getPrecision())\r
3067                         {\r
3068                         case EbpHigh:   return GL_HIGH_INT;\r
3069                         case EbpMedium: return GL_MEDIUM_INT;\r
3070                         case EbpLow:    return GL_LOW_INT;\r
3071                         case EbpUndefined:\r
3072                                 // Should be defined as the default precision by the parser\r
3073                         default: UNREACHABLE(type.getPrecision());\r
3074                         }\r
3075                 }\r
3076 \r
3077                 // Other types (boolean, sampler) don't have a precision\r
3078                 return GL_NONE;\r
3079         }\r
3080 \r
3081         int OutputASM::dim(TIntermNode *v)\r
3082         {\r
3083                 TIntermTyped *vector = v->getAsTyped();\r
3084                 ASSERT(vector && vector->isRegister());\r
3085                 return vector->getNominalSize();\r
3086         }\r
3087 \r
3088         int OutputASM::dim2(TIntermNode *m)\r
3089         {\r
3090                 TIntermTyped *matrix = m->getAsTyped();\r
3091                 ASSERT(matrix && matrix->isMatrix() && !matrix->isArray());\r
3092                 return matrix->getSecondarySize();\r
3093         }\r
3094 \r
3095         // Returns ~0 if no loop count could be determined\r
3096         unsigned int OutputASM::loopCount(TIntermLoop *node)\r
3097         {\r
3098                 // Parse loops of the form:\r
3099                 // for(int index = initial; index [comparator] limit; index += increment)\r
3100                 TIntermSymbol *index = 0;\r
3101                 TOperator comparator = EOpNull;\r
3102                 int initial = 0;\r
3103                 int limit = 0;\r
3104                 int increment = 0;\r
3105 \r
3106                 // Parse index name and intial value\r
3107                 if(node->getInit())\r
3108                 {\r
3109                         TIntermAggregate *init = node->getInit()->getAsAggregate();\r
3110 \r
3111                         if(init)\r
3112                         {\r
3113                                 TIntermSequence &sequence = init->getSequence();\r
3114                                 TIntermTyped *variable = sequence[0]->getAsTyped();\r
3115 \r
3116                                 if(variable && variable->getQualifier() == EvqTemporary)\r
3117                                 {\r
3118                                         TIntermBinary *assign = variable->getAsBinaryNode();\r
3119 \r
3120                                         if(assign->getOp() == EOpInitialize)\r
3121                                         {\r
3122                                                 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();\r
3123                                                 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();\r
3124 \r
3125                                                 if(symbol && constant)\r
3126                                                 {\r
3127                                                         if(constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)\r
3128                                                         {\r
3129                                                                 index = symbol;\r
3130                                                                 initial = constant->getUnionArrayPointer()[0].getIConst();\r
3131                                                         }\r
3132                                                 }\r
3133                                         }\r
3134                                 }\r
3135                         }\r
3136                 }\r
3137 \r
3138                 // Parse comparator and limit value\r
3139                 if(index && node->getCondition())\r
3140                 {\r
3141                         TIntermBinary *test = node->getCondition()->getAsBinaryNode();\r
3142 \r
3143                         if(test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())\r
3144                         {\r
3145                                 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();\r
3146 \r
3147                                 if(constant)\r
3148                                 {\r
3149                                         if(constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)\r
3150                                         {\r
3151                                                 comparator = test->getOp();\r
3152                                                 limit = constant->getUnionArrayPointer()[0].getIConst();\r
3153                                         }\r
3154                                 }\r
3155                         }\r
3156                 }\r
3157 \r
3158                 // Parse increment\r
3159                 if(index && comparator != EOpNull && node->getExpression())\r
3160                 {\r
3161                         TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();\r
3162                         TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();\r
3163 \r
3164                         if(binaryTerminal)\r
3165                         {\r
3166                                 TOperator op = binaryTerminal->getOp();\r
3167                                 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();\r
3168 \r
3169                                 if(constant)\r
3170                                 {\r
3171                                         if(constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)\r
3172                                         {\r
3173                                                 int value = constant->getUnionArrayPointer()[0].getIConst();\r
3174 \r
3175                                                 switch(op)\r
3176                                                 {\r
3177                                                 case EOpAddAssign: increment = value;  break;\r
3178                                                 case EOpSubAssign: increment = -value; break;\r
3179                                                 default: UNIMPLEMENTED();\r
3180                                                 }\r
3181                                         }\r
3182                                 }\r
3183                         }\r
3184                         else if(unaryTerminal)\r
3185                         {\r
3186                                 TOperator op = unaryTerminal->getOp();\r
3187 \r
3188                                 switch(op)\r
3189                                 {\r
3190                                 case EOpPostIncrement: increment = 1;  break;\r
3191                                 case EOpPostDecrement: increment = -1; break;\r
3192                                 case EOpPreIncrement:  increment = 1;  break;\r
3193                                 case EOpPreDecrement:  increment = -1; break;\r
3194                                 default: UNIMPLEMENTED();\r
3195                                 }\r
3196                         }\r
3197                 }\r
3198 \r
3199                 if(index && comparator != EOpNull && increment != 0)\r
3200                 {\r
3201                         if(comparator == EOpLessThanEqual)\r
3202                         {\r
3203                                 comparator = EOpLessThan;\r
3204                                 limit += 1;\r
3205                         }\r
3206 \r
3207                         if(comparator == EOpLessThan)\r
3208                         {\r
3209                                 int iterations = (limit - initial) / increment;\r
3210 \r
3211                                 if(iterations <= 0)\r
3212                                 {\r
3213                                         iterations = 0;\r
3214                                 }\r
3215 \r
3216                                 return iterations;\r
3217                         }\r
3218                         else UNIMPLEMENTED();   // Falls through\r
3219                 }\r
3220 \r
3221                 return ~0;\r
3222         }\r
3223 \r
3224         bool DetectLoopDiscontinuity::traverse(TIntermNode *node)\r
3225         {\r
3226                 loopDepth = 0;\r
3227                 loopDiscontinuity = false;\r
3228                 \r
3229                 node->traverse(this);\r
3230                 \r
3231                 return loopDiscontinuity;\r
3232         }\r
3233 \r
3234         bool DetectLoopDiscontinuity::visitLoop(Visit visit, TIntermLoop *loop)\r
3235         {\r
3236                 if(visit == PreVisit)\r
3237                 {\r
3238                         loopDepth++;\r
3239                 }\r
3240                 else if(visit == PostVisit)\r
3241                 {\r
3242                         loopDepth++;\r
3243                 }\r
3244 \r
3245                 return true;\r
3246         }\r
3247 \r
3248         bool DetectLoopDiscontinuity::visitBranch(Visit visit, TIntermBranch *node)\r
3249         {\r
3250                 if(loopDiscontinuity)\r
3251                 {\r
3252                         return false;\r
3253                 }\r
3254 \r
3255                 if(!loopDepth)\r
3256                 {\r
3257                         return true;\r
3258                 }\r
3259         \r
3260                 switch(node->getFlowOp())\r
3261                 {\r
3262                 case EOpKill:\r
3263                         break;\r
3264                 case EOpBreak:\r
3265                 case EOpContinue:\r
3266                 case EOpReturn:\r
3267                         loopDiscontinuity = true;\r
3268                         break;\r
3269                 default: UNREACHABLE(node->getFlowOp());\r
3270                 }\r
3271 \r
3272                 return !loopDiscontinuity;\r
3273         }\r
3274 \r
3275         bool DetectLoopDiscontinuity::visitAggregate(Visit visit, TIntermAggregate *node)\r
3276         {\r
3277                 return !loopDiscontinuity;\r
3278         }\r
3279 }\r