OSDN Git Service

gl_VertexID implementation
[android-x86/external-swiftshader.git] / src / OpenGL / compiler / OutputASM.cpp
index 4334f38..2c8222e 100644 (file)
-// SwiftShader Software Renderer\r
-//\r
-// Copyright(c) 2005-2013 TransGaming Inc.\r
-//\r
-// All rights reserved. No part of this software may be copied, distributed, transmitted,\r
-// transcribed, stored in a retrieval system, translated into any human or computer\r
-// language by any means, or disclosed to third parties without the explicit written\r
-// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express\r
-// or implied, including but not limited to any patent rights, are granted to you.\r
-//\r
-\r
-#include "OutputASM.h"\r
-\r
-#include "common/debug.h"\r
-#include "InfoSink.h"\r
-\r
-#include "libGLESv2/Shader.h"\r
-\r
-#define GL_APICALL\r
-#include <GLES2/gl2.h>\r
-#include <GLES2/gl2ext.h>\r
-#include <GLES3/gl3.h>\r
-\r
-namespace glsl\r
-{\r
-       // Integer to TString conversion\r
-       TString str(int i)\r
-       {\r
-               char buffer[20];\r
-               sprintf(buffer, "%d", i);\r
-               return buffer;\r
-       }\r
-\r
-       class Temporary : public TIntermSymbol\r
-       {\r
-       public:\r
-               Temporary(OutputASM *assembler) : TIntermSymbol(0, "tmp", TType(EbtFloat, EbpHigh, EvqTemporary, 4, 1, false)), assembler(assembler)\r
-               {\r
-               }\r
-\r
-               ~Temporary()\r
-               {\r
-                       assembler->freeTemporary(this);\r
-               }\r
-\r
-       private:\r
-               OutputASM *const assembler;\r
-       };\r
-\r
-       class Constant : public TIntermConstantUnion\r
-       {\r
-       public:\r
-               Constant(float x, float y, float z, float w) : TIntermConstantUnion(constants, TType(EbtFloat, EbpHigh, EvqConstExpr, 4, 1, false))\r
-               {\r
-                       constants[0].setFConst(x);\r
-                       constants[1].setFConst(y);\r
-                       constants[2].setFConst(z);\r
-                       constants[3].setFConst(w);\r
-               }\r
-\r
-               Constant(bool b) : TIntermConstantUnion(constants, TType(EbtBool, EbpHigh, EvqConstExpr, 1, 1, false))\r
-               {\r
-                       constants[0].setBConst(b);\r
-               }\r
-\r
-               Constant(int i) : TIntermConstantUnion(constants, TType(EbtInt, EbpHigh, EvqConstExpr, 1, 1, false))\r
-               {\r
-                       constants[0].setIConst(i);\r
-               }\r
-\r
-               ~Constant()\r
-               {\r
-               }\r
-\r
-       private:\r
-               ConstantUnion constants[4];\r
-       };\r
-\r
-       Uniform::Uniform(GLenum type, GLenum precision, const std::string &name, int arraySize, int registerIndex)\r
-       {\r
-               this->type = type;\r
-               this->precision = precision;\r
-               this->name = name;\r
-               this->arraySize = arraySize;\r
-               this->registerIndex = registerIndex;\r
-       }\r
-\r
-       Attribute::Attribute()\r
-       {\r
-               type = GL_NONE;\r
-               arraySize = 0;\r
-               registerIndex = 0;\r
-       }\r
-\r
-       Attribute::Attribute(GLenum type, const std::string &name, int arraySize, int registerIndex)\r
-       {\r
-               this->type = type;\r
-               this->name = name;\r
-               this->arraySize = arraySize;\r
-               this->registerIndex = registerIndex;\r
-       }\r
-\r
-       sw::PixelShader *Shader::getPixelShader() const\r
-       {\r
-               return 0;\r
-       }\r
-\r
-       sw::VertexShader *Shader::getVertexShader() const\r
-       {\r
-               return 0;\r
-       }\r
-\r
-       OutputASM::OutputASM(TParseContext &context, Shader *shaderObject) : TIntermTraverser(true, true, true), mContext(context), shaderObject(shaderObject)\r
-       {\r
-               shader = 0;\r
-               pixelShader = 0;\r
-               vertexShader = 0;\r
-\r
-               if(shaderObject)\r
-               {\r
-                       shader = shaderObject->getShader();\r
-                       pixelShader = shaderObject->getPixelShader();\r
-                       vertexShader = shaderObject->getVertexShader();\r
-               }\r
-\r
-               functionArray.push_back(Function(0, "main(", 0, 0));\r
-               currentFunction = 0;\r
-               outputQualifier = EvqOutput; // Set outputQualifier to any value other than EvqFragColor or EvqFragData\r
-       }\r
-\r
-       OutputASM::~OutputASM()\r
-       {\r
-       }\r
-\r
-       void OutputASM::output()\r
-       {\r
-               if(shader)\r
-               {\r
-                       emitShader(GLOBAL);\r
-\r
-                       if(functionArray.size() > 1)   // Only call main() when there are other functions\r
-                       {\r
-                               Instruction *callMain = emit(sw::Shader::OPCODE_CALL);\r
-                               callMain->dst.type = sw::Shader::PARAMETER_LABEL;\r
-                               callMain->dst.index = 0;   // main()\r
-\r
-                               emit(sw::Shader::OPCODE_RET);\r
-                       }\r
-\r
-                       emitShader(FUNCTION);\r
-               }\r
-       }\r
-\r
-       void OutputASM::emitShader(Scope scope)\r
-       {\r
-               emitScope = scope;\r
-               currentScope = GLOBAL;\r
-               mContext.treeRoot->traverse(this);\r
-       }\r
-\r
-       void OutputASM::freeTemporary(Temporary *temporary)\r
-       {\r
-               free(temporaries, temporary);\r
-       }\r
-\r
-       void OutputASM::visitSymbol(TIntermSymbol *symbol)\r
-       {\r
-               // Vertex varyings don't have to be actively used to successfully link\r
-               // against pixel shaders that use them. So make sure they're declared.\r
-               if(symbol->getQualifier() == EvqVaryingOut || symbol->getQualifier() == EvqInvariantVaryingOut)\r
-               {\r
-                       if(symbol->getBasicType() != EbtInvariant)   // Typeless declarations are not new varyings\r
-                       {\r
-                               declareVarying(symbol, -1);\r
-                       }\r
-               }\r
-       }\r
-\r
-       bool OutputASM::visitBinary(Visit visit, TIntermBinary *node)\r
-       {\r
-               if(currentScope != emitScope)\r
-               {\r
-                       return false;\r
-               }\r
-\r
-               TIntermTyped *result = node;\r
-               TIntermTyped *left = node->getLeft();\r
-               TIntermTyped *right = node->getRight();\r
-               const TType &leftType = left->getType();\r
-               const TType &rightType = right->getType();\r
-               const TType &resultType = node->getType();\r
-               \r
-               switch(node->getOp())\r
-               {\r
-               case EOpAssign:\r
-                       if(visit == PostVisit)\r
-                       {\r
-                               assignLvalue(left, right);\r
-                               copy(result, right);\r
-                       }\r
-                       break;\r
-               case EOpInitialize:\r
-                       if(visit == PostVisit)\r
-                       {\r
-                               copy(left, right);\r
-                       }\r
-                       break;\r
-               case EOpMatrixTimesScalarAssign:\r
-                       if(visit == PostVisit)\r
-                       {\r
-                               for(int i = 0; i < leftType.getNominalSize(); i++)\r
-                               {\r
-                                       Instruction *mul = emit(sw::Shader::OPCODE_MUL, result, left, right);\r
-                                       mul->dst.index += i;\r
-                                       argument(mul->src[0], left, i);\r
-                               }\r
-\r
-                               assignLvalue(left, result);\r
-                       }\r
-                       break;\r
-               case EOpVectorTimesMatrixAssign:\r
-                       if(visit == PostVisit)\r
-                       {\r
-                               int size = leftType.getNominalSize();\r
-\r
-                               for(int i = 0; i < size; i++)\r
-                               {\r
-                                       Instruction *dot = emit(sw::Shader::OPCODE_DP(size), result, left, right);\r
-                                       dot->dst.mask = 1 << i;\r
-                                       argument(dot->src[1], right, i);\r
-                               }\r
-\r
-                               assignLvalue(left, result);\r
-                       }\r
-                       break;\r
-               case EOpMatrixTimesMatrixAssign:\r
-                       if(visit == PostVisit)\r
-                       {\r
-                               int dim = leftType.getNominalSize();\r
-\r
-                               for(int i = 0; i < dim; i++)\r
-                               {\r
-                                       Instruction *mul = emit(sw::Shader::OPCODE_MUL, result, left, right);\r
-                                       mul->dst.index += i;\r
-                                       argument(mul->src[1], right, i);\r
-                                       mul->src[1].swizzle = 0x00;\r
-\r
-                                       for(int j = 1; j < dim; j++)\r
-                                       {\r
-                                               Instruction *mad = emit(sw::Shader::OPCODE_MAD, result, left, right, result);\r
-                                               mad->dst.index += i;\r
-                                               argument(mad->src[0], left, j);\r
-                                               argument(mad->src[1], right, i);\r
-                                               mad->src[1].swizzle = j * 0x55;\r
-                                               argument(mad->src[2], result, i);\r
-                                       }\r
-                               }\r
-\r
-                               assignLvalue(left, result);\r
-                       }\r
-                       break;\r
-               case EOpIndexDirect:\r
-                       if(visit == PostVisit)\r
-                       {\r
-                               int index = right->getAsConstantUnion()->getIConst(0);\r
-\r
-                               if(result->isMatrix() || result->isStruct())\r
-                               {\r
-                                       ASSERT(left->isArray());\r
-                                       copy(result, left, index * left->elementRegisterCount());\r
-                               }\r
-                               else if(result->isRegister())\r
-                               {\r
-                                       Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, left);\r
-\r
-                                       if(left->isRegister())\r
-                                       {\r
-                                               mov->src[0].swizzle = index;\r
-                                       }\r
-                                       else if(left->isArray())\r
-                                       {\r
-                                               argument(mov->src[0], left, index * left->elementRegisterCount());\r
-                                       }\r
-                                       else if(left->isMatrix())\r
-                                       {\r
-                                               ASSERT(index < left->getNominalSize());   // FIXME: Report semantic error\r
-                                               argument(mov->src[0], left, index);\r
-                                       }\r
-                                       else UNREACHABLE();\r
-                               }\r
-                               else UNREACHABLE();\r
-                       }\r
-                       break;\r
-               case EOpIndexIndirect:\r
-                       if(visit == PostVisit)\r
-                       {\r
-                               if(left->isArray() || left->isMatrix())\r
-                               {\r
-                                       for(int index = 0; index < result->totalRegisterCount(); index++)\r
-                                       {\r
-                                               Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, left);\r
-                                               mov->dst.index += index;\r
-                                               mov->dst.mask = writeMask(result, index);\r
-                                               argument(mov->src[0], left, index);\r
-\r
-                                               if(left->totalRegisterCount() > 1)\r
-                                               {\r
-                                                       sw::Shader::SourceParameter relativeRegister;\r
-                                                       argument(relativeRegister, right);\r
-\r
-                                                       mov->src[0].rel.type = relativeRegister.type;\r
-                                                       mov->src[0].rel.index = relativeRegister.index;\r
-                                                       mov->src[0].rel.scale = result->totalRegisterCount();\r
-                                                       mov->src[0].rel.deterministic = !(vertexShader && left->getQualifier() == EvqUniform);\r
-                                               }\r
-                                       }\r
-                               }\r
-                               else if(left->isRegister())\r
-                               {\r
-                                       emit(sw::Shader::OPCODE_EXTRACT, result, left, right);\r
-                               }\r
-                               else UNREACHABLE();\r
-                       }\r
-                       break;\r
-               case EOpIndexDirectStruct:\r
-                       if(visit == PostVisit)\r
-                       {\r
-                               ASSERT(leftType.isStruct());\r
-\r
-                               const TTypeList *structure = leftType.getStruct();\r
-                               const TString &fieldName = rightType.getFieldName();\r
-                               int fieldOffset = 0;\r
-\r
-                               for(size_t i = 0; i < structure->size(); i++)\r
-                               {\r
-                                       const TType &fieldType = *(*structure)[i].type;\r
-\r
-                                       if(fieldType.getFieldName() == fieldName)\r
-                                       {\r
-                                               break;\r
-                                       }\r
-\r
-                                       fieldOffset += fieldType.totalRegisterCount();\r
-                               }\r
-\r
-                               copy(result, left, fieldOffset);\r
-                       }\r
-                       break;\r
-               case EOpVectorSwizzle:\r
-                       if(visit == PostVisit)\r
-                       {\r
-                               int swizzle = 0;\r
-                               TIntermAggregate *components = right->getAsAggregate();\r
-\r
-                               if(components)\r
-                               {\r
-                                       TIntermSequence &sequence = components->getSequence();\r
-                                       int component = 0;\r
-\r
-                                       for(TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)\r
-                                       {\r
-                                               TIntermConstantUnion *element = (*sit)->getAsConstantUnion();\r
-\r
-                                               if(element)\r
-                                               {\r
-                                                       int i = element->getUnionArrayPointer()[0].getIConst();\r
-                                                       swizzle |= i << (component * 2);\r
-                                                       component++;\r
-                                               }\r
-                                               else UNREACHABLE();\r
-                                       }\r
-                               }\r
-                               else UNREACHABLE();\r
-\r
-                               Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, left);\r
-                               mov->src[0].swizzle = swizzle;\r
-                       }\r
-                       break;\r
-               case EOpAddAssign: if(visit == PostVisit) emitAssign(sw::Shader::OPCODE_ADD, result, left, left, right); break;\r
-               case EOpAdd:       if(visit == PostVisit) emitBinary(sw::Shader::OPCODE_ADD, result, left, right);       break;\r
-               case EOpSubAssign: if(visit == PostVisit) emitAssign(sw::Shader::OPCODE_SUB, result, left, left, right); break;\r
-               case EOpSub:       if(visit == PostVisit) emitBinary(sw::Shader::OPCODE_SUB, result, left, right);       break;\r
-               case EOpMulAssign: if(visit == PostVisit) emitAssign(sw::Shader::OPCODE_MUL, result, left, left, right); break;\r
-               case EOpMul:       if(visit == PostVisit) emitBinary(sw::Shader::OPCODE_MUL, result, left, right);       break;\r
-               case EOpDivAssign: if(visit == PostVisit) emitAssign(sw::Shader::OPCODE_DIV, result, left, left, right); break;\r
-               case EOpDiv:       if(visit == PostVisit) emitBinary(sw::Shader::OPCODE_DIV, result, left, right);       break;\r
-               case EOpEqual:\r
-                       if(visit == PostVisit)\r
-                       {\r
-                               emitCmp(sw::Shader::CONTROL_EQ, result, left, right);\r
-\r
-                               for(int index = 1; index < left->totalRegisterCount(); index++)\r
-                               {\r
-                                       Temporary equal(this);\r
-                                       emitCmp(sw::Shader::CONTROL_EQ, &equal, left, right, index);\r
-                                       emit(sw::Shader::OPCODE_AND, result, result, &equal);\r
-                               }\r
-                       }\r
-                       break;\r
-               case EOpNotEqual:\r
-                       if(visit == PostVisit)\r
-                       {\r
-                               emitCmp(sw::Shader::CONTROL_NE, result, left, right);\r
-\r
-                               for(int index = 1; index < left->totalRegisterCount(); index++)\r
-                               {\r
-                                       Temporary notEqual(this);\r
-                                       emitCmp(sw::Shader::CONTROL_NE, &notEqual, left, right, index);\r
-                                       emit(sw::Shader::OPCODE_OR, result, result, &notEqual);\r
-                               }\r
-                       }\r
-                       break;\r
-               case EOpLessThan:                if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_LT, result, left, right); break;\r
-               case EOpGreaterThan:             if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_GT, result, left, right); break;\r
-               case EOpLessThanEqual:           if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_LE, result, left, right); break;\r
-               case EOpGreaterThanEqual:        if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_GE, result, left, right); break;\r
-               case EOpVectorTimesScalarAssign: if(visit == PostVisit) emitAssign(sw::Shader::OPCODE_MUL, result, left, left, right); break;\r
-               case EOpVectorTimesScalar:       if(visit == PostVisit) emit(sw::Shader::OPCODE_MUL, result, left, right); break;\r
-               case EOpMatrixTimesScalar:\r
-                       if(visit == PostVisit)\r
-                       {\r
-                               for(int i = 0; i < leftType.getNominalSize(); i++)\r
-                               {\r
-                                       Instruction *mul = emit(sw::Shader::OPCODE_MUL, result, left, right);\r
-                                       mul->dst.index += i;\r
-                                       argument(mul->src[0], left, i);\r
-                               }\r
-                       }\r
-                       break;\r
-               case EOpVectorTimesMatrix:\r
-                       if(visit == PostVisit)\r
-                       {\r
-                               int size = leftType.getNominalSize();\r
-\r
-                               for(int i = 0; i < size; i++)\r
-                               {\r
-                                       Instruction *dot = emit(sw::Shader::OPCODE_DP(size), result, left, right);\r
-                                       dot->dst.mask = 1 << i;\r
-                                       argument(dot->src[1], right, i);\r
-                               }\r
-                       }\r
-                       break;\r
-               case EOpMatrixTimesVector:\r
-                       if(visit == PostVisit)\r
-                       {\r
-                               Instruction *mul = emit(sw::Shader::OPCODE_MUL, result, left, right);\r
-                               mul->src[1].swizzle = 0x00;\r
-\r
-                               for(int i = 1; i < leftType.getNominalSize(); i++)\r
-                               {\r
-                                       Instruction *mad = emit(sw::Shader::OPCODE_MAD, result, left, right, result);\r
-                                       argument(mad->src[0], left, i);\r
-                                       mad->src[1].swizzle = i * 0x55;\r
-                               }\r
-                       }\r
-                       break;\r
-               case EOpMatrixTimesMatrix:\r
-                       if(visit == PostVisit)\r
-                       {\r
-                               int dim = leftType.getNominalSize();\r
-\r
-                               for(int i = 0; i < dim; i++)\r
-                               {\r
-                                       Instruction *mul = emit(sw::Shader::OPCODE_MUL, result, left, right);\r
-                                       mul->dst.index += i;\r
-                                       argument(mul->src[1], right, i);\r
-                                       mul->src[1].swizzle = 0x00;\r
-\r
-                                       for(int j = 1; j < dim; j++)\r
-                                       {\r
-                                               Instruction *mad = emit(sw::Shader::OPCODE_MAD, result, left, right, result);\r
-                                               mad->dst.index += i;\r
-                                               argument(mad->src[0], left, j);\r
-                                               argument(mad->src[1], right, i);\r
-                                               mad->src[1].swizzle = j * 0x55;\r
-                                               argument(mad->src[2], result, i);\r
-                                       }\r
-                               }\r
-                       }\r
-                       break;\r
-               case EOpLogicalOr:\r
-                       if(trivial(right, 6))\r
-                       {\r
-                               if(visit == PostVisit)\r
-                               {\r
-                                       emit(sw::Shader::OPCODE_OR, result, left, right);\r
-                               }\r
-                       }\r
-                       else   // Short-circuit evaluation\r
-                       {\r
-                               if(visit == InVisit)\r
-                               {\r
-                                       emit(sw::Shader::OPCODE_MOV, result, left);\r
-                                       Instruction *ifnot = emit(sw::Shader::OPCODE_IF, 0, result);\r
-                                       ifnot->src[0].modifier = sw::Shader::MODIFIER_NOT;\r
-                               }\r
-                               else if(visit == PostVisit)\r
-                               {\r
-                                       emit(sw::Shader::OPCODE_MOV, result, right);\r
-                                       emit(sw::Shader::OPCODE_ENDIF);\r
-                               }\r
-                       }\r
-                       break;\r
-               case EOpLogicalXor:        if(visit == PostVisit) emit(sw::Shader::OPCODE_XOR, result, left, right); break;\r
-               case EOpLogicalAnd:\r
-                       if(trivial(right, 6))\r
-                       {\r
-                               if(visit == PostVisit)\r
-                               {\r
-                                       emit(sw::Shader::OPCODE_AND, result, left, right);\r
-                               }\r
-                       }\r
-                       else   // Short-circuit evaluation\r
-                       {\r
-                               if(visit == InVisit)\r
-                               {\r
-                                       emit(sw::Shader::OPCODE_MOV, result, left);\r
-                                       emit(sw::Shader::OPCODE_IF, 0, result);\r
-                               }\r
-                               else if(visit == PostVisit)\r
-                               {\r
-                                       emit(sw::Shader::OPCODE_MOV, result, right);\r
-                                       emit(sw::Shader::OPCODE_ENDIF);\r
-                               }\r
-                       }\r
-                       break;\r
-               default: UNREACHABLE();\r
-               }\r
-\r
-               return true;\r
-       }\r
-\r
-       bool OutputASM::visitUnary(Visit visit, TIntermUnary *node)\r
-       {\r
-               if(currentScope != emitScope)\r
-               {\r
-                       return false;\r
-               }\r
-\r
-               Constant one(1.0f, 1.0f, 1.0f, 1.0f);\r
-               Constant rad(1.74532925e-2f, 1.74532925e-2f, 1.74532925e-2f, 1.74532925e-2f);\r
-               Constant deg(5.72957795e+1f, 5.72957795e+1f, 5.72957795e+1f, 5.72957795e+1f);\r
-\r
-               TIntermTyped *result = node;\r
-               TIntermTyped *arg = node->getOperand();\r
-\r
-               switch(node->getOp())\r
-               {\r
-               case EOpNegative:\r
-                       if(visit == PostVisit)\r
-                       {\r
-                               for(int index = 0; index < arg->totalRegisterCount(); index++)\r
-                               {\r
-                                       Instruction *neg = emit(sw::Shader::OPCODE_MOV, result, arg);\r
-                                       neg->dst.index += index;\r
-                                       argument(neg->src[0], arg, index);\r
-                                       neg->src[0].modifier = sw::Shader::MODIFIER_NEGATE;\r
-                               }\r
-                       }\r
-                       break;\r
-               case EOpVectorLogicalNot: if(visit == PostVisit) emit(sw::Shader::OPCODE_NOT, result, arg); break;\r
-               case EOpLogicalNot:       if(visit == PostVisit) emit(sw::Shader::OPCODE_NOT, result, arg); break;\r
-               case EOpPostIncrement:\r
-                       if(visit == PostVisit)\r
-                       {\r
-                               copy(result, arg);\r
-\r
-                               for(int index = 0; index < arg->totalRegisterCount(); index++)\r
-                               {\r
-                                       Instruction *add = emit(sw::Shader::OPCODE_ADD, arg, arg, &one);\r
-                                       add->dst.index += index;\r
-                                       argument(add->src[0], arg, index);\r
-                               }\r
-\r
-                               assignLvalue(arg, arg);\r
-                       }\r
-                       break;\r
-               case EOpPostDecrement:\r
-                       if(visit == PostVisit)\r
-                       {\r
-                               copy(result, arg);\r
-\r
-                               for(int index = 0; index < arg->totalRegisterCount(); index++)\r
-                               {\r
-                                       Instruction *sub = emit(sw::Shader::OPCODE_SUB, arg, arg, &one);\r
-                                       sub->dst.index += index;\r
-                                       argument(sub->src[0], arg, index);\r
-                               }\r
-\r
-                               assignLvalue(arg, arg);\r
-                       }\r
-                       break;\r
-               case EOpPreIncrement:\r
-                       if(visit == PostVisit)\r
-                       {\r
-                               for(int index = 0; index < arg->totalRegisterCount(); index++)\r
-                               {\r
-                                       Instruction *add = emit(sw::Shader::OPCODE_ADD, result, arg, &one);\r
-                                       add->dst.index += index;\r
-                                       argument(add->src[0], arg, index);\r
-                               }\r
-\r
-                               assignLvalue(arg, result);\r
-                       }\r
-                       break;\r
-               case EOpPreDecrement:\r
-                       if(visit == PostVisit)\r
-                       {\r
-                               for(int index = 0; index < arg->totalRegisterCount(); index++)\r
-                               {\r
-                                       Instruction *sub = emit(sw::Shader::OPCODE_SUB, result, arg, &one);\r
-                                       sub->dst.index += index;\r
-                                       argument(sub->src[0], arg, index);\r
-                               }\r
-\r
-                               assignLvalue(arg, result);\r
-                       }\r
-                       break;\r
-               case EOpRadians:          if(visit == PostVisit) emit(sw::Shader::OPCODE_MUL, result, arg, &rad); break;\r
-               case EOpDegrees:          if(visit == PostVisit) emit(sw::Shader::OPCODE_MUL, result, arg, &deg); break;\r
-               case EOpSin:              if(visit == PostVisit) emit(sw::Shader::OPCODE_SIN, result, arg); break;\r
-               case EOpCos:              if(visit == PostVisit) emit(sw::Shader::OPCODE_COS, result, arg); break;\r
-               case EOpTan:              if(visit == PostVisit) emit(sw::Shader::OPCODE_TAN, result, arg); break;\r
-               case EOpAsin:             if(visit == PostVisit) emit(sw::Shader::OPCODE_ASIN, result, arg); break;\r
-               case EOpAcos:             if(visit == PostVisit) emit(sw::Shader::OPCODE_ACOS, result, arg); break;\r
-               case EOpAtan:             if(visit == PostVisit) emit(sw::Shader::OPCODE_ATAN, result, arg); break;\r
-               case EOpSinh:             if(visit == PostVisit) emit(sw::Shader::OPCODE_SINH, result, arg); break;\r
-               case EOpCosh:             if(visit == PostVisit) emit(sw::Shader::OPCODE_COSH, result, arg); break;\r
-               case EOpTanh:             if(visit == PostVisit) emit(sw::Shader::OPCODE_TANH, result, arg); break;\r
-               case EOpAsinh:            if(visit == PostVisit) emit(sw::Shader::OPCODE_ASINH, result, arg); break;\r
-               case EOpAcosh:            if(visit == PostVisit) emit(sw::Shader::OPCODE_ACOSH, result, arg); break;\r
-               case EOpAtanh:            if(visit == PostVisit) emit(sw::Shader::OPCODE_ATANH, result, arg); break;\r
-               case EOpExp:              if(visit == PostVisit) emit(sw::Shader::OPCODE_EXP, result, arg); break;\r
-               case EOpLog:              if(visit == PostVisit) emit(sw::Shader::OPCODE_LOG, result, arg); break;\r
-               case EOpExp2:             if(visit == PostVisit) emit(sw::Shader::OPCODE_EXP2, result, arg); break;\r
-               case EOpLog2:             if(visit == PostVisit) emit(sw::Shader::OPCODE_LOG2, result, arg); break;\r
-               case EOpSqrt:             if(visit == PostVisit) emit(sw::Shader::OPCODE_SQRT, result, arg); break;\r
-               case EOpInverseSqrt:      if(visit == PostVisit) emit(sw::Shader::OPCODE_RSQ, result, arg); break;\r
-               case EOpAbs:              if(visit == PostVisit) emit(sw::Shader::OPCODE_ABS, result, arg); break;\r
-               case EOpSign:             if(visit == PostVisit) emit(sw::Shader::OPCODE_SGN, result, arg); break;\r
-               case EOpFloor:            if(visit == PostVisit) emit(sw::Shader::OPCODE_FLOOR, result, arg); break;\r
-               case EOpTrunc:            if(visit == PostVisit) emit(sw::Shader::OPCODE_TRUNC, result, arg); break;\r
-               case EOpRound:            if(visit == PostVisit) emit(sw::Shader::OPCODE_ROUND, result, arg); break;\r
-               case EOpRoundEven:        if(visit == PostVisit) emit(sw::Shader::OPCODE_ROUNDEVEN, result, arg); break;\r
-               case EOpCeil:             if(visit == PostVisit) emit(sw::Shader::OPCODE_CEIL, result, arg, result); break;\r
-               case EOpFract:            if(visit == PostVisit) emit(sw::Shader::OPCODE_FRC, result, arg); break;\r
-               case EOpIsNan:            if(visit == PostVisit) emit(sw::Shader::OPCODE_ISNAN, result, arg); break;\r
-               case EOpIsInf:            if(visit == PostVisit) emit(sw::Shader::OPCODE_ISINF, result, arg); break;\r
-               case EOpLength:           if(visit == PostVisit) emit(sw::Shader::OPCODE_LEN(dim(arg)), result, arg); break;\r
-               case EOpNormalize:        if(visit == PostVisit) emit(sw::Shader::OPCODE_NRM(dim(arg)), result, arg); break;\r
-               case EOpDFdx:             if(visit == PostVisit) emit(sw::Shader::OPCODE_DFDX, result, arg); break;\r
-               case EOpDFdy:             if(visit == PostVisit) emit(sw::Shader::OPCODE_DFDY, result, arg); break;\r
-               case EOpFwidth:           if(visit == PostVisit) emit(sw::Shader::OPCODE_FWIDTH, result, arg); break;\r
-               case EOpAny:              if(visit == PostVisit) emit(sw::Shader::OPCODE_ANY, result, arg); break;\r
-               case EOpAll:              if(visit == PostVisit) emit(sw::Shader::OPCODE_ALL, result, arg); break;\r
-               default: UNREACHABLE();\r
-               }\r
-\r
-               return true;\r
-       }\r
-\r
-       bool OutputASM::visitAggregate(Visit visit, TIntermAggregate *node)\r
-       {\r
-               if(currentScope != emitScope && node->getOp() != EOpFunction && node->getOp() != EOpSequence)\r
-               {\r
-                       return false;\r
-               }\r
-\r
-               Constant zero(0.0f, 0.0f, 0.0f, 0.0f);\r
-\r
-               TIntermTyped *result = node;\r
-               const TType &resultType = node->getType();\r
-               TIntermSequence &arg = node->getSequence();\r
-               int argumentCount = arg.size();\r
-\r
-               switch(node->getOp())\r
-               {\r
-               case EOpSequence:           break;\r
-               case EOpDeclaration:        break;\r
-               case EOpPrototype:          break;\r
-               case EOpComma:\r
-                       if(visit == PostVisit)\r
-                       {\r
-                               copy(result, arg[1]);\r
-                       }\r
-                       break;\r
-               case EOpFunction:\r
-                       if(visit == PreVisit)\r
-                       {\r
-                               const TString &name = node->getName();\r
-\r
-                               if(emitScope == FUNCTION)\r
-                               {\r
-                                       if(functionArray.size() > 1)   // No need for a label when there's only main()\r
-                                       {\r
-                                               Instruction *label = emit(sw::Shader::OPCODE_LABEL);\r
-                                               label->dst.type = sw::Shader::PARAMETER_LABEL;\r
-\r
-                                               const Function *function = findFunction(name);\r
-                                               ASSERT(function);   // Should have been added during global pass\r
-                                               label->dst.index = function->label;\r
-                                               currentFunction = function->label;\r
-                                       }\r
-                               }\r
-                               else if(emitScope == GLOBAL)\r
-                               {\r
-                                       if(name != "main(")\r
-                                       {\r
-                                               TIntermSequence &arguments = node->getSequence()[0]->getAsAggregate()->getSequence();\r
-                                               functionArray.push_back(Function(functionArray.size(), name, &arguments, node));\r
-                                       }\r
-                               }\r
-                               else UNREACHABLE();\r
-\r
-                               currentScope = FUNCTION;\r
-                       }\r
-                       else if(visit == PostVisit)\r
-                       {\r
-                               if(emitScope == FUNCTION)\r
-                               {\r
-                                       if(functionArray.size() > 1)   // No need to return when there's only main()\r
-                                       {\r
-                                               emit(sw::Shader::OPCODE_RET);\r
-                                       }\r
-                               }\r
-\r
-                               currentScope = GLOBAL;\r
-                       }\r
-                       break;\r
-               case EOpFunctionCall:\r
-                       if(visit == PostVisit)\r
-                       {\r
-                               if(node->isUserDefined())\r
-                               {\r
-                                       const TString &name = node->getName();\r
-                                       const Function *function = findFunction(name);\r
-\r
-                                       if(!function)\r
-                                       {\r
-                                               mContext.error(node->getLine(), "function definition not found", name.c_str());\r
-                                               return false;\r
-                                       }\r
-\r
-                                       TIntermSequence &arguments = *function->arg;\r
-\r
-                                       for(int i = 0; i < argumentCount; i++)\r
-                                       {\r
-                                               TIntermTyped *in = arguments[i]->getAsTyped();\r
-\r
-                                               if(in->getQualifier() == EvqIn ||\r
-                                                  in->getQualifier() == EvqInOut ||\r
-                                                  in->getQualifier() == EvqConstReadOnly)\r
-                                               {\r
-                                                       copy(in, arg[i]);\r
-                                               }\r
-                                       }\r
-\r
-                                       Instruction *call = emit(sw::Shader::OPCODE_CALL);\r
-                                       call->dst.type = sw::Shader::PARAMETER_LABEL;\r
-                                       call->dst.index = function->label;\r
-\r
-                                       if(function->ret && function->ret->getType().getBasicType() != EbtVoid)\r
-                                       {\r
-                                               copy(result, function->ret);\r
-                                       }\r
-\r
-                                       for(int i = 0; i < argumentCount; i++)\r
-                                       {\r
-                                               TIntermTyped *argument = arguments[i]->getAsTyped();\r
-                                               TIntermTyped *out = arg[i]->getAsTyped();\r
-                                                               \r
-                                               if(argument->getQualifier() == EvqOut ||\r
-                                                  argument->getQualifier() == EvqInOut)\r
-                                               {\r
-                                                       copy(out, argument);\r
-                                               }\r
-                                       }\r
-                               }\r
-                               else\r
-                               {\r
-                                       TString name = TFunction::unmangleName(node->getName());\r
-\r
-                                       if(name == "texture" || name == "texture2D" || name == "textureCube" || name == "texture3D")\r
-                                       {\r
-                                               if(argumentCount == 2)\r
-                                               {\r
-                                                       emit(sw::Shader::OPCODE_TEX, result, arg[1], arg[0]);\r
-                                               }\r
-                                               else if(argumentCount == 3)   // bias\r
-                                               {\r
-                                                       Temporary uvwb(this);\r
-                                                       emit(sw::Shader::OPCODE_MOV, &uvwb, arg[1]);\r
-                                                       Instruction *bias = emit(sw::Shader::OPCODE_MOV, &uvwb, arg[2]);\r
-                                                       bias->dst.mask = 0x8;\r
-\r
-                                                       Instruction *tex = emit(sw::Shader::OPCODE_TEX, result, &uvwb, arg[0]);   // FIXME: Implement an efficient TEXLDB instruction\r
-                                                       tex->bias = true;\r
-                                               }\r
-                                               else UNREACHABLE();\r
-                                       }\r
-                                       else if(name == "texture2DProj")\r
-                                       {\r
-                                               TIntermTyped *t = arg[1]->getAsTyped();\r
-\r
-                                               if(argumentCount == 2)\r
-                                               {\r
-                                                       Instruction *tex = emit(sw::Shader::OPCODE_TEX, result, arg[1], arg[0]);\r
-                                                       tex->project = true;\r
-\r
-                                                       if(t->getNominalSize() == 3)\r
-                                                       {\r
-                                                               tex->src[0].swizzle = 0xA4;\r
-                                                       }\r
-                                                       else ASSERT(t->getNominalSize() == 4);\r
-                                               }\r
-                                               else if(argumentCount == 3)   // bias\r
-                                               {\r
-                                                       Temporary proj(this);\r
-\r
-                                                       if(t->getNominalSize() == 3)\r
-                                                       {\r
-                                                               Instruction *div = emit(sw::Shader::OPCODE_DIV, &proj, arg[1], arg[1]);\r
-                                                               div->src[1].swizzle = 0xAA;\r
-                                                               div->dst.mask = 0x3;\r
-                                                       }\r
-                                                       else if(t->getNominalSize() == 4)\r
-                                                       {\r
-                                                               Instruction *div = emit(sw::Shader::OPCODE_DIV, &proj, arg[1], arg[1]);\r
-                                                               div->src[1].swizzle = 0xFF;\r
-                                                               div->dst.mask = 0x3;\r
-                                                       }\r
-                                                       else UNREACHABLE();\r
-\r
-                                                       Instruction *bias = emit(sw::Shader::OPCODE_MOV, &proj, arg[2]);\r
-                                                       bias->dst.mask = 0x8;\r
-\r
-                                                       Instruction *tex = emit(sw::Shader::OPCODE_TEX, result, &proj, arg[0]);\r
-                                                       tex->bias = true;\r
-                                               }\r
-                                               else UNREACHABLE();\r
-                                       }\r
-                                       else if(name == "texture2DLod" || name == "textureCubeLod")\r
-                                       {\r
-                                               Temporary uvwb(this);\r
-                                               emit(sw::Shader::OPCODE_MOV, &uvwb, arg[1]);\r
-                                               Instruction *lod = emit(sw::Shader::OPCODE_MOV, &uvwb, arg[2]);\r
-                                               lod->dst.mask = 0x8;\r
-\r
-                                               emit(sw::Shader::OPCODE_TEXLDL, result, &uvwb, arg[0]);\r
-                                       }\r
-                                       else if(name == "texture2DProjLod")\r
-                                       {\r
-                                               TIntermTyped *t = arg[1]->getAsTyped();\r
-                                               Temporary proj(this);\r
-\r
-                                               if(t->getNominalSize() == 3)\r
-                                               {\r
-                                                       Instruction *div = emit(sw::Shader::OPCODE_DIV, &proj, arg[1], arg[1]);\r
-                                                       div->src[1].swizzle = 0xAA;\r
-                                                       div->dst.mask = 0x3;\r
-                                               }\r
-                                               else if(t->getNominalSize() == 4)\r
-                                               {\r
-                                                       Instruction *div = emit(sw::Shader::OPCODE_DIV, &proj, arg[1], arg[1]);\r
-                                                       div->src[1].swizzle = 0xFF;\r
-                                                       div->dst.mask = 0x3;\r
-                                               }\r
-                                               else UNREACHABLE();\r
-\r
-                                               Instruction *lod = emit(sw::Shader::OPCODE_MOV, &proj, arg[2]);\r
-                                               lod->dst.mask = 0x8;\r
-\r
-                                               emit(sw::Shader::OPCODE_TEXLDL, result, &proj, arg[0]);\r
-                                       }\r
-                                       else UNREACHABLE();\r
-                               }\r
-                       }\r
-                       break;\r
-               case EOpParameters:\r
-                       break;\r
-               case EOpConstructFloat:\r
-               case EOpConstructVec2:\r
-               case EOpConstructVec3:\r
-               case EOpConstructVec4:\r
-               case EOpConstructBool:\r
-               case EOpConstructBVec2:\r
-               case EOpConstructBVec3:\r
-               case EOpConstructBVec4:\r
-               case EOpConstructInt:\r
-               case EOpConstructIVec2:\r
-               case EOpConstructIVec3:\r
-               case EOpConstructIVec4:\r
-                       if(visit == PostVisit)\r
-                       {\r
-                               int component = 0;\r
-\r
-                               for(int i = 0; i < argumentCount; i++)\r
-                               {\r
-                                       TIntermTyped *argi = arg[i]->getAsTyped();\r
-                                       int size = argi->getNominalSize();\r
-\r
-                                       if(!argi->isMatrix())\r
-                                       {\r
-                                               Instruction *mov = emitCast(result, argi);\r
-                                               mov->dst.mask = (0xF << component) & 0xF;\r
-                                               mov->src[0].swizzle = readSwizzle(argi, size) << (component * 2);\r
-\r
-                                               component += size;\r
-                                       }\r
-                                       else   // Matrix\r
-                                       {\r
-                                               int column = 0;\r
-\r
-                                               while(component < resultType.getNominalSize())\r
-                                               {\r
-                                                       Instruction *mov = emitCast(result, argi);\r
-                                                       mov->dst.mask = (0xF << component) & 0xF;\r
-                                                       mov->src[0].index += column;\r
-                                                       mov->src[0].swizzle = readSwizzle(argi, size) << (component * 2);\r
-\r
-                                                       column++;\r
-                                                       component += size;\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-                       break;\r
-               case EOpConstructMat2:\r
-               case EOpConstructMat2x3:\r
-               case EOpConstructMat2x4:\r
-               case EOpConstructMat3x2:\r
-               case EOpConstructMat3:\r
-               case EOpConstructMat3x4:\r
-               case EOpConstructMat4x2:\r
-               case EOpConstructMat4x3:\r
-               case EOpConstructMat4:\r
-                       if(visit == PostVisit)\r
-                       {\r
-                               TIntermTyped *arg0 = arg[0]->getAsTyped();\r
-                               const int dim = result->getNominalSize();\r
-\r
-                               if(arg0->isScalar() && arg.size() == 1)   // Construct scale matrix\r
-                               {\r
-                                       for(int i = 0; i < dim; i++)\r
-                                       {\r
-                                               Instruction *init = emit(sw::Shader::OPCODE_MOV, result, &zero);\r
-                                               init->dst.index += i;\r
-                                               Instruction *mov = emitCast(result, arg0);\r
-                                               mov->dst.index += i;\r
-                                               mov->dst.mask = 1 << i;\r
-                                               ASSERT(mov->src[0].swizzle == 0x00);\r
-                                       }\r
-                               }\r
-                               else if(arg0->isMatrix())\r
-                               {\r
-                                       for(int i = 0; i < dim; i++)\r
-                                       {\r
-                                               if(dim > dim2(arg0))\r
-                                               {\r
-                                                       // Initialize to identity matrix\r
-                                                       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
-                                                       Instruction *mov = emitCast(result, &col);\r
-                                                       mov->dst.index += i;\r
-                                               }\r
-\r
-                                               if(i < dim2(arg0))\r
-                                               {\r
-                                                       Instruction *mov = emitCast(result, arg0);\r
-                                                       mov->dst.index += i;\r
-                                                       mov->dst.mask = 0xF >> (4 - dim2(arg0));\r
-                                                       argument(mov->src[0], arg0, i);\r
-                                               }\r
-                                       }\r
-                               }\r
-                               else\r
-                               {\r
-                                       int column = 0;\r
-                                       int row = 0;\r
-\r
-                                       for(int i = 0; i < argumentCount; i++)\r
-                                       {\r
-                                               TIntermTyped *argi = arg[i]->getAsTyped();\r
-                                               int size = argi->getNominalSize();\r
-                                               int element = 0;\r
-\r
-                                               while(element < size)\r
-                                               {\r
-                                                       Instruction *mov = emitCast(result, argi);\r
-                                                       mov->dst.index += column;\r
-                                                       mov->dst.mask = (0xF << row) & 0xF;\r
-                                                       mov->src[0].swizzle = (readSwizzle(argi, size) << (row * 2)) + 0x55 * element;\r
-\r
-                                                       int end = row + size - element;\r
-                                                       column = end >= dim ? column + 1 : column;\r
-                                                       element = element + dim - row;\r
-                                                       row = end >= dim ? 0 : end;\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-                       break;\r
-               case EOpConstructStruct:\r
-                       if(visit == PostVisit)\r
-                       {\r
-                               int offset = 0;\r
-                               for(int i = 0; i < argumentCount; i++)\r
-                               {\r
-                                       TIntermTyped *argi = arg[i]->getAsTyped();\r
-                                       int size = argi->totalRegisterCount();\r
-\r
-                                       for(int index = 0; index < size; index++)\r
-                                       {\r
-                                               Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, argi);\r
-                                               mov->dst.index += index + offset;\r
-                                               mov->dst.mask = writeMask(result, offset + index);\r
-                                               argument(mov->src[0], argi, index);\r
-                                       }\r
-\r
-                                       offset += size;\r
-                               }\r
-                       }\r
-                       break;\r
-               case EOpLessThan:         if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_LT, result, arg[0], arg[1]); break;\r
-               case EOpGreaterThan:      if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_GT, result, arg[0], arg[1]); break;\r
-               case EOpLessThanEqual:    if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_LE, result, arg[0], arg[1]); break;\r
-               case EOpGreaterThanEqual: if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_GE, result, arg[0], arg[1]); break;\r
-               case EOpVectorEqual:      if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_EQ, result, arg[0], arg[1]); break;\r
-               case EOpVectorNotEqual:   if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_NE, result, arg[0], arg[1]); break;\r
-               case EOpMod:              if(visit == PostVisit) emit(sw::Shader::OPCODE_MOD, result, arg[0], arg[1]); break;\r
-               case EOpPow:              if(visit == PostVisit) emit(sw::Shader::OPCODE_POW, result, arg[0], arg[1]); break;\r
-               case EOpAtan:             if(visit == PostVisit) emit(sw::Shader::OPCODE_ATAN2, result, arg[0], arg[1]); break;\r
-               case EOpMin:              if(visit == PostVisit) emit(sw::Shader::OPCODE_MIN, result, arg[0], arg[1]); break;\r
-               case EOpMax:              if(visit == PostVisit) emit(sw::Shader::OPCODE_MAX, result, arg[0], arg[1]); break;\r
-               case EOpClamp:\r
-                       if(visit == PostVisit)\r
-                       {\r
-                               emit(sw::Shader::OPCODE_MAX, result, arg[0], arg[1]);\r
-                               emit(sw::Shader::OPCODE_MIN, result, result, arg[2]);\r
-                       }\r
-                       break;\r
-               case EOpMix:         if(visit == PostVisit) emit(sw::Shader::OPCODE_LRP, result, arg[2], arg[1], arg[0]); break;\r
-               case EOpStep:        if(visit == PostVisit) emit(sw::Shader::OPCODE_STEP, result, arg[0], arg[1]); break;\r
-               case EOpSmoothStep:  if(visit == PostVisit) emit(sw::Shader::OPCODE_SMOOTH, result, arg[0], arg[1], arg[2]); break;\r
-               case EOpFloatBitsToInt:  if(visit == PostVisit) emit(sw::Shader::OPCODE_FLOATBITSTOINT, result, arg[0]); break;\r
-               case EOpFloatBitsToUint: if(visit == PostVisit) emit(sw::Shader::OPCODE_FLOATBITSTOUINT, result, arg[0]); break;\r
-               case EOpIntBitsToFloat:  if(visit == PostVisit) emit(sw::Shader::OPCODE_INTBITSTOFLOAT, result, arg[0]); break;\r
-               case EOpUintBitsToFloat: if(visit == PostVisit) emit(sw::Shader::OPCODE_UINTBITSTOFLOAT, result, arg[0]); break;\r
-               case EOpPackSnorm2x16:   if(visit == PostVisit) emit(sw::Shader::OPCODE_PACKSNORM2x16, result, arg[0]); break;\r
-               case EOpPackUnorm2x16:   if(visit == PostVisit) emit(sw::Shader::OPCODE_PACKUNORM2x16, result, arg[0]); break;\r
-               case EOpPackHalf2x16:    if(visit == PostVisit) emit(sw::Shader::OPCODE_PACKHALF2x16, result, arg[0]); break;\r
-               case EOpUnpackSnorm2x16: if(visit == PostVisit) emit(sw::Shader::OPCODE_UNPACKSNORM2x16, result, arg[0]); break;\r
-               case EOpUnpackUnorm2x16: if(visit == PostVisit) emit(sw::Shader::OPCODE_UNPACKUNORM2x16, result, arg[0]); break;\r
-               case EOpUnpackHalf2x16:  if(visit == PostVisit) emit(sw::Shader::OPCODE_UNPACKHALF2x16, result, arg[0]); break;\r
-               case EOpDistance:    if(visit == PostVisit) emit(sw::Shader::OPCODE_DIST(dim(arg[0])), result, arg[0], arg[1]); break;\r
-               case EOpDot:         if(visit == PostVisit) emit(sw::Shader::OPCODE_DP(dim(arg[0])), result, arg[0], arg[1]); break;\r
-               case EOpCross:       if(visit == PostVisit) emit(sw::Shader::OPCODE_CRS, result, arg[0], arg[1]); break;\r
-               case EOpFaceForward: if(visit == PostVisit) emit(sw::Shader::OPCODE_FORWARD(dim(arg[0])), result, arg[0], arg[1], arg[2]); break;\r
-               case EOpReflect:     if(visit == PostVisit) emit(sw::Shader::OPCODE_REFLECT(dim(arg[0])), result, arg[0], arg[1]); break;\r
-               case EOpRefract:     if(visit == PostVisit) emit(sw::Shader::OPCODE_REFRACT(dim(arg[0])), result, arg[0], arg[1], arg[2]); break;\r
-               case EOpMul:\r
-                       if(visit == PostVisit)\r
-                       {\r
-                               ASSERT(dim2(arg[0]) == dim2(arg[1]));\r
-\r
-                               for(int i = 0; i < dim2(arg[0]); i++)\r
-                               {\r
-                                       Instruction *mul = emit(sw::Shader::OPCODE_MUL, result, arg[0], arg[1]);\r
-                                       mul->dst.index += i;\r
-                                       argument(mul->src[0], arg[0], i);\r
-                                       argument(mul->src[1], arg[1], i);\r
-                               }\r
-                       }\r
-                       break;\r
-               default: UNREACHABLE();\r
-               }\r
-\r
-               return true;\r
-       }\r
-\r
-       bool OutputASM::visitSelection(Visit visit, TIntermSelection *node)\r
-       {\r
-               if(currentScope != emitScope)\r
-               {\r
-                       return false;\r
-               }\r
-\r
-               TIntermTyped *condition = node->getCondition();\r
-               TIntermNode *trueBlock = node->getTrueBlock();\r
-               TIntermNode *falseBlock = node->getFalseBlock();\r
-               TIntermConstantUnion *constantCondition = condition->getAsConstantUnion();\r
-\r
-               condition->traverse(this);\r
-\r
-               if(node->usesTernaryOperator())\r
-               {\r
-                       if(constantCondition)\r
-                       {\r
-                               bool trueCondition = constantCondition->getUnionArrayPointer()->getBConst();\r
-\r
-                               if(trueCondition)\r
-                               {\r
-                                       trueBlock->traverse(this);\r
-                                       copy(node, trueBlock);\r
-                               }\r
-                               else\r
-                               {\r
-                                       falseBlock->traverse(this);\r
-                                       copy(node, falseBlock);\r
-                               }\r
-                       }\r
-                       else if(trivial(node, 6))   // Fast to compute both potential results and no side effects\r
-                       {\r
-                               trueBlock->traverse(this);\r
-                               falseBlock->traverse(this);\r
-                               emit(sw::Shader::OPCODE_SELECT, node, condition, trueBlock, falseBlock);\r
-                       }\r
-                       else\r
-                       {\r
-                               emit(sw::Shader::OPCODE_IF, 0, condition);\r
-\r
-                               if(trueBlock)\r
-                               {\r
-                                       trueBlock->traverse(this);\r
-                                       copy(node, trueBlock);\r
-                               }\r
-\r
-                               if(falseBlock)\r
-                               {\r
-                                       emit(sw::Shader::OPCODE_ELSE);\r
-                                       falseBlock->traverse(this);\r
-                                       copy(node, falseBlock);\r
-                               }\r
-\r
-                               emit(sw::Shader::OPCODE_ENDIF);\r
-                       }\r
-               }\r
-               else  // if/else statement\r
-               {\r
-                       if(constantCondition)\r
-                       {\r
-                               bool trueCondition = constantCondition->getUnionArrayPointer()->getBConst();\r
-\r
-                               if(trueCondition)\r
-                               {\r
-                                       if(trueBlock)\r
-                                       {\r
-                                               trueBlock->traverse(this);\r
-                                       }\r
-                               }\r
-                               else\r
-                               {\r
-                                       if(falseBlock)\r
-                                       {\r
-                                               falseBlock->traverse(this);\r
-                                       }\r
-                               }\r
-                       }\r
-                       else\r
-                       {\r
-                               emit(sw::Shader::OPCODE_IF, 0, condition);\r
-\r
-                               if(trueBlock)\r
-                               {\r
-                                       trueBlock->traverse(this);\r
-                               }\r
-\r
-                               if(falseBlock)\r
-                               {\r
-                                       emit(sw::Shader::OPCODE_ELSE);\r
-                                       falseBlock->traverse(this);\r
-                               }\r
-\r
-                               emit(sw::Shader::OPCODE_ENDIF);\r
-                       }\r
-               }\r
-\r
-               return false;\r
-       }\r
-\r
-       bool OutputASM::visitLoop(Visit visit, TIntermLoop *node)\r
-       {\r
-               if(currentScope != emitScope)\r
-               {\r
-                       return false;\r
-               }\r
-\r
-               unsigned int iterations = loopCount(node);\r
-\r
-               if(iterations == 0)\r
-               {\r
-                       return false;\r
-               }\r
-\r
-               bool unroll = (iterations <= 4);\r
-\r
-               if(unroll)\r
-               {\r
-                       DetectLoopDiscontinuity detectLoopDiscontinuity;\r
-                       unroll = !detectLoopDiscontinuity.traverse(node);\r
-               }\r
-\r
-               TIntermNode *init = node->getInit();\r
-               TIntermTyped *condition = node->getCondition();\r
-               TIntermTyped *expression = node->getExpression();\r
-               TIntermNode *body = node->getBody();\r
-\r
-               if(node->getType() == ELoopDoWhile)\r
-               {\r
-                       Temporary iterate(this);\r
-                       Constant True(true);\r
-                       emit(sw::Shader::OPCODE_MOV, &iterate, &True);\r
-\r
-                       emit(sw::Shader::OPCODE_WHILE, 0, &iterate);   // FIXME: Implement real do-while\r
-\r
-                       if(body)\r
-                       {\r
-                               body->traverse(this);\r
-                       }\r
-\r
-                       emit(sw::Shader::OPCODE_TEST);\r
-\r
-                       condition->traverse(this);\r
-                       emit(sw::Shader::OPCODE_MOV, &iterate, condition);\r
-\r
-                       emit(sw::Shader::OPCODE_ENDWHILE);\r
-               }\r
-               else\r
-               {\r
-                       if(init)\r
-                       {\r
-                               init->traverse(this);\r
-                       }\r
-\r
-                       if(unroll)\r
-                       {\r
-                               for(unsigned int i = 0; i < iterations; i++)\r
-                               {\r
-                               //      condition->traverse(this);   // Condition could contain statements, but not in an unrollable loop\r
-\r
-                                       if(body)\r
-                                       {\r
-                                               body->traverse(this);\r
-                                       }\r
-\r
-                                       if(expression)\r
-                                       {\r
-                                               expression->traverse(this);\r
-                                       }\r
-                               }\r
-                       }\r
-                       else\r
-                       {\r
-                               condition->traverse(this);\r
-\r
-                               emit(sw::Shader::OPCODE_WHILE, 0, condition);\r
-\r
-                               if(body)\r
-                               {\r
-                                       body->traverse(this);\r
-                               }\r
-\r
-                               emit(sw::Shader::OPCODE_TEST);\r
-\r
-                               if(expression)\r
-                               {\r
-                                       expression->traverse(this);\r
-                               }\r
-\r
-                               condition->traverse(this);\r
-\r
-                               emit(sw::Shader::OPCODE_ENDWHILE);\r
-                       }\r
-               }\r
-\r
-               return false;\r
-       }\r
-\r
-       bool OutputASM::visitBranch(Visit visit, TIntermBranch *node)\r
-       {\r
-               if(currentScope != emitScope)\r
-               {\r
-                       return false;\r
-               }\r
-\r
-               switch(node->getFlowOp())\r
-               {\r
-               case EOpKill:      if(visit == PostVisit) emit(sw::Shader::OPCODE_DISCARD);  break;\r
-               case EOpBreak:     if(visit == PostVisit) emit(sw::Shader::OPCODE_BREAK);    break;\r
-               case EOpContinue:  if(visit == PostVisit) emit(sw::Shader::OPCODE_CONTINUE); break;\r
-               case EOpReturn:\r
-                       if(visit == PostVisit)\r
-                       {\r
-                               TIntermTyped *value = node->getExpression();\r
-\r
-                               if(value)\r
-                               {\r
-                                       copy(functionArray[currentFunction].ret, value);\r
-                               }\r
-\r
-                               emit(sw::Shader::OPCODE_LEAVE);\r
-                       }\r
-                       break;\r
-               default: UNREACHABLE();\r
-               }\r
-\r
-               return true;\r
-       }\r
-\r
-       bool OutputASM::isSamplerRegister(TIntermTyped *operand)\r
-       {\r
-               return operand && isSamplerRegister(operand->getType());\r
-       }\r
-\r
-       bool OutputASM::isSamplerRegister(const TType &type)\r
-       {\r
-               // A sampler register's qualifiers can be:\r
-               // - EvqUniform: The sampler uniform is used as is in the code (default case).\r
-               // - EvqTemporary: The sampler is indexed. It's still a sampler register.\r
-               // - EvqIn (and other similar types): The sampler has been passed as a function argument. At this point,\r
-               //                                    the sampler has been copied and is no longer a sampler register.\r
-               return IsSampler(type.getBasicType()) && (type.getQualifier() == EvqUniform || type.getQualifier() == EvqTemporary);\r
-       }\r
-\r
-       Instruction *OutputASM::emit(sw::Shader::Opcode op, TIntermTyped *dst, TIntermNode *src0, TIntermNode *src1, TIntermNode *src2, int index)\r
-       {\r
-               if(isSamplerRegister(dst))\r
-               {\r
-                       op = sw::Shader::OPCODE_NULL;   // Can't assign to a sampler, but this is hit when indexing sampler arrays\r
-               }\r
-\r
-               Instruction *instruction = new Instruction(op);\r
-\r
-               if(dst)\r
-               {\r
-                       instruction->dst.type = registerType(dst);\r
-                       instruction->dst.index = registerIndex(dst) + index;\r
-                       instruction->dst.mask = writeMask(dst);\r
-                       instruction->dst.integer = (dst->getBasicType() == EbtInt);\r
-               }\r
-\r
-               argument(instruction->src[0], src0, index);\r
-               argument(instruction->src[1], src1, index);\r
-               argument(instruction->src[2], src2, index);\r
-\r
-               shader->append(instruction);\r
-\r
-               return instruction;\r
-       }\r
-\r
-       Instruction *OutputASM::emitCast(TIntermTyped *dst, TIntermTyped *src)\r
-       {\r
-               // Integers are implemented as float\r
-               if((dst->getBasicType() == EbtFloat || dst->getBasicType() == EbtInt) && src->getBasicType() == EbtBool)\r
-               {\r
-                       return emit(sw::Shader::OPCODE_B2F, dst, src);\r
-               }\r
-               if(dst->getBasicType() == EbtBool && (src->getBasicType() == EbtFloat || src->getBasicType() == EbtInt))\r
-               {\r
-                       return emit(sw::Shader::OPCODE_F2B, dst, src);\r
-               }\r
-               if(dst->getBasicType() == EbtInt && src->getBasicType() == EbtFloat)\r
-               {\r
-                       return emit(sw::Shader::OPCODE_TRUNC, dst, src);\r
-               }\r
-\r
-               return emit(sw::Shader::OPCODE_MOV, dst, src);\r
-       }\r
-\r
-       void OutputASM::emitBinary(sw::Shader::Opcode op, TIntermTyped *dst, TIntermNode *src0, TIntermNode *src1, TIntermNode *src2)\r
-       {\r
-               for(int index = 0; index < dst->elementRegisterCount(); index++)\r
-               {\r
-                       emit(op, dst, src0, src1, src2, index);\r
-               }\r
-       }\r
-\r
-       void OutputASM::emitAssign(sw::Shader::Opcode op, TIntermTyped *result, TIntermTyped *lhs, TIntermTyped *src0, TIntermTyped *src1)\r
-       {\r
-               emitBinary(op, result, src0, src1);\r
-               assignLvalue(lhs, result);\r
-       }\r
-\r
-       void OutputASM::emitCmp(sw::Shader::Control cmpOp, TIntermTyped *dst, TIntermNode *left, TIntermNode *right, int index)\r
-       {\r
-               bool boolean = (left->getAsTyped()->getBasicType() == EbtBool);\r
-               sw::Shader::Opcode opcode = boolean ? sw::Shader::OPCODE_ICMP : sw::Shader::OPCODE_CMP;\r
-\r
-               Instruction *cmp = emit(opcode, dst, left, right);\r
-               cmp->control = cmpOp;\r
-               argument(cmp->src[0], left, index);\r
-               argument(cmp->src[1], right, index);\r
-       }\r
-\r
-       int componentCount(const TType &type, int registers)\r
-       {\r
-               if(registers == 0)\r
-               {\r
-                       return 0;\r
-               }\r
-\r
-               if(type.isArray() && registers >= type.elementRegisterCount())\r
-               {\r
-                       int index = registers / type.elementRegisterCount();\r
-                       registers -= index * type.elementRegisterCount();\r
-                       return index * type.getElementSize() + componentCount(type, registers);\r
-               }\r
-\r
-               if(type.isStruct())\r
-               {\r
-                       TTypeList *structure = type.getStruct();\r
-                       int elements = 0;\r
-\r
-                       for(TTypeList::const_iterator field = structure->begin(); field != structure->end(); field++)\r
-                       {\r
-                               const TType &fieldType = *field->type;\r
-\r
-                               if(fieldType.totalRegisterCount() <= registers)\r
-                               {\r
-                                       registers -= fieldType.totalRegisterCount();\r
-                                       elements += fieldType.getObjectSize();\r
-                               }\r
-                               else   // Register within this field\r
-                               {\r
-                                       return elements + componentCount(fieldType, registers);\r
-                               }\r
-                       }\r
-               }\r
-               else if(type.isMatrix())\r
-               {\r
-                       return registers * type.getNominalSize();\r
-               }\r
-               \r
-               UNREACHABLE();\r
-               return 0;\r
-       }\r
-\r
-       int registerSize(const TType &type, int registers)\r
-       {\r
-               if(registers == 0)\r
-               {\r
-                       if(type.isStruct())\r
-                       {\r
-                               return registerSize(*type.getStruct()->begin()->type, 0);\r
-                       }\r
-\r
-                       return type.getNominalSize();\r
-               }\r
-\r
-               if(type.isArray() && registers >= type.elementRegisterCount())\r
-               {\r
-                       int index = registers / type.elementRegisterCount();\r
-                       registers -= index * type.elementRegisterCount();\r
-                       return registerSize(type, registers);\r
-               }\r
-\r
-               if(type.isStruct())\r
-               {\r
-                       TTypeList *structure = type.getStruct();\r
-                       int elements = 0;\r
-\r
-                       for(TTypeList::const_iterator field = structure->begin(); field != structure->end(); field++)\r
-                       {\r
-                               const TType &fieldType = *field->type;\r
-                               \r
-                               if(fieldType.totalRegisterCount() <= registers)\r
-                               {\r
-                                       registers -= fieldType.totalRegisterCount();\r
-                                       elements += fieldType.getObjectSize();\r
-                               }\r
-                               else   // Register within this field\r
-                               {\r
-                                       return registerSize(fieldType, registers);\r
-                               }\r
-                       }\r
-               }\r
-               else if(type.isMatrix())\r
-               {\r
-                       return registerSize(type, 0);\r
-               }\r
-               \r
-               UNREACHABLE();\r
-               return 0;\r
-       }\r
-\r
-       void OutputASM::argument(sw::Shader::SourceParameter &parameter, TIntermNode *argument, int index)\r
-       {\r
-               if(argument)\r
-               {\r
-                       TIntermTyped *arg = argument->getAsTyped();\r
-                       const TType &type = arg->getType();\r
-                       const TTypeList *structure = type.getStruct();\r
-                       index = (index >= arg->totalRegisterCount()) ? arg->totalRegisterCount() - 1 : index;\r
-\r
-                       int size = registerSize(type, index);\r
-\r
-                       parameter.type = registerType(arg);\r
-\r
-                       if(arg->getQualifier() == EvqConstExpr)\r
-                       {\r
-                               int component = componentCount(type, index);\r
-                               ConstantUnion *constants = arg->getAsConstantUnion()->getUnionArrayPointer();\r
-\r
-                               for(int i = 0; i < 4; i++)\r
-                               {\r
-                                       if(size == 1)   // Replicate\r
-                                       {\r
-                                               parameter.value[i] = constants[component + 0].getAsFloat();\r
-                                       }\r
-                                       else if(i < size)\r
-                                       {\r
-                                               parameter.value[i] = constants[component + i].getAsFloat();\r
-                                       }\r
-                                       else\r
-                                       {\r
-                                               parameter.value[i] = 0.0f;\r
-                                       }\r
-                               }\r
-                       }\r
-                       else\r
-                       {\r
-                               parameter.index = registerIndex(arg) + index;\r
-\r
-                               if(isSamplerRegister(arg))\r
-                               {\r
-                                       TIntermBinary *binary = argument->getAsBinaryNode();\r
-\r
-                                       if(binary)\r
-                                       {\r
-                                               TIntermTyped *left = binary->getLeft();\r
-                                               TIntermTyped *right = binary->getRight();\r
-\r
-                                               if(binary->getOp() == EOpIndexDirect)\r
-                                               {\r
-                                                       parameter.index += right->getAsConstantUnion()->getIConst(0);\r
-                                               }\r
-                                               else if(binary->getOp() == EOpIndexIndirect)\r
-                                               {\r
-                                                       if(left->getArraySize() > 1)\r
-                                                       {\r
-                                                               parameter.rel.type = registerType(binary->getRight());\r
-                                                               parameter.rel.index = registerIndex(binary->getRight());\r
-                                                               parameter.rel.scale = 1;\r
-                                                               parameter.rel.deterministic = true;\r
-                                                       }\r
-                                               }\r
-                                               else if(binary->getOp() == EOpIndexDirectStruct)\r
-                                               {\r
-                                                       parameter.index += right->getAsConstantUnion()->getIConst(0);\r
-                                               }\r
-                                               else UNREACHABLE();\r
-                                       }\r
-                               }\r
-                       }\r
-\r
-                       if(!IsSampler(arg->getBasicType()))\r
-                       {\r
-                               parameter.swizzle = readSwizzle(arg, size);\r
-                       }\r
-               }\r
-       }\r
-\r
-       void OutputASM::copy(TIntermTyped *dst, TIntermNode *src, int offset)\r
-       {\r
-               for(int index = 0; index < dst->totalRegisterCount(); index++)\r
-               {\r
-                       Instruction *mov = emit(sw::Shader::OPCODE_MOV, dst, src);\r
-                       mov->dst.index += index;\r
-                       mov->dst.mask = writeMask(dst, index);\r
-                       argument(mov->src[0], src, offset + index);\r
-               }\r
-       }\r
-\r
-       int swizzleElement(int swizzle, int index)\r
-       {\r
-               return (swizzle >> (index * 2)) & 0x03;\r
-       }\r
-\r
-       int swizzleSwizzle(int leftSwizzle, int rightSwizzle)\r
-       {\r
-               return (swizzleElement(leftSwizzle, swizzleElement(rightSwizzle, 0)) << 0) |\r
-                      (swizzleElement(leftSwizzle, swizzleElement(rightSwizzle, 1)) << 2) |\r
-                      (swizzleElement(leftSwizzle, swizzleElement(rightSwizzle, 2)) << 4) |\r
-                      (swizzleElement(leftSwizzle, swizzleElement(rightSwizzle, 3)) << 6);\r
-       }\r
-\r
-       void OutputASM::assignLvalue(TIntermTyped *dst, TIntermTyped *src)\r
-       {\r
-               if(src &&\r
-                       ((src->isVector() && (!dst->isVector() || (dst->getNominalSize() != dst->getNominalSize()))) ||\r
-                        (src->isMatrix() && (!dst->isMatrix() || (src->getNominalSize() != dst->getNominalSize())))))\r
-               {\r
-                       return mContext.error(src->getLine(), "Result type should match the l-value type in compound assignment", src->isVector() ? "vector" : "matrix");\r
-               }\r
-\r
-               TIntermBinary *binary = dst->getAsBinaryNode();\r
-\r
-               if(binary && binary->getOp() == EOpIndexIndirect && dst->isScalar())\r
-               {\r
-                       Instruction *insert = new Instruction(sw::Shader::OPCODE_INSERT);\r
-                       \r
-                       Temporary address(this);\r
-                       lvalue(insert->dst, address, dst);\r
-\r
-                       insert->src[0].type = insert->dst.type;\r
-                       insert->src[0].index = insert->dst.index;\r
-                       insert->src[0].rel = insert->dst.rel;\r
-                       argument(insert->src[1], src);\r
-                       argument(insert->src[2], binary->getRight());\r
-\r
-                       shader->append(insert);\r
-               }\r
-               else\r
-               {\r
-                       for(int offset = 0; offset < dst->totalRegisterCount(); offset++)\r
-                       {\r
-                               Instruction *mov = new Instruction(sw::Shader::OPCODE_MOV);\r
-                       \r
-                               Temporary address(this);\r
-                               int swizzle = lvalue(mov->dst, address, dst);\r
-                               mov->dst.index += offset;\r
-\r
-                               if(offset > 0)\r
-                               {\r
-                                       mov->dst.mask = writeMask(dst, offset);\r
-                               }\r
-\r
-                               argument(mov->src[0], src, offset);\r
-                               mov->src[0].swizzle = swizzleSwizzle(mov->src[0].swizzle, swizzle);\r
-\r
-                               shader->append(mov);\r
-                       }\r
-               }\r
-       }\r
-\r
-       int OutputASM::lvalue(sw::Shader::DestinationParameter &dst, Temporary &address, TIntermTyped *node)\r
-       {\r
-               TIntermTyped *result = node;\r
-               TIntermBinary *binary = node->getAsBinaryNode();\r
-               TIntermSymbol *symbol = node->getAsSymbolNode();\r
-\r
-               if(binary)\r
-               {\r
-                       TIntermTyped *left = binary->getLeft();\r
-                       TIntermTyped *right = binary->getRight();\r
-\r
-                       int leftSwizzle = lvalue(dst, address, left);   // Resolve the l-value of the left side\r
-\r
-                       switch(binary->getOp())\r
-                       {\r
-                       case EOpIndexDirect:\r
-                               {\r
-                                       int rightIndex = right->getAsConstantUnion()->getIConst(0);\r
-\r
-                                       if(left->isRegister())\r
-                                       {\r
-                                               int leftMask = dst.mask;\r
-                                               \r
-                                               dst.mask = 1;\r
-                                               while((leftMask & dst.mask) == 0)\r
-                                               {\r
-                                                       dst.mask = dst.mask << 1;\r
-                                               }\r
-\r
-                                               int element = swizzleElement(leftSwizzle, rightIndex);\r
-                                               dst.mask = 1 << element;\r
-                                               \r
-                                               return element;\r
-                                       }\r
-                                       else if(left->isArray() || left->isMatrix())\r
-                                       {\r
-                                               dst.index += rightIndex * result->totalRegisterCount();\r
-                                               return 0xE4;\r
-                                       }\r
-                                       else UNREACHABLE();\r
-                               }\r
-                               break;\r
-                       case EOpIndexIndirect:\r
-                               {\r
-                                       if(left->isRegister())\r
-                                       {\r
-                                               // Requires INSERT instruction (handled by calling function)\r
-                                       }\r
-                                       else if(left->isArray() || left->isMatrix())\r
-                                       {\r
-                                               int scale = result->totalRegisterCount();\r
-\r
-                                               if(dst.rel.type == sw::Shader::PARAMETER_VOID)   // Use the index register as the relative address directly\r
-                                               {\r
-                                                       if(left->totalRegisterCount() > 1)\r
-                                                       {\r
-                                                               sw::Shader::SourceParameter relativeRegister;\r
-                                                               argument(relativeRegister, right);\r
-\r
-                                                               dst.rel.index = relativeRegister.index;\r
-                                                               dst.rel.type = relativeRegister.type;\r
-                                                               dst.rel.scale = scale;\r
-                                                               dst.rel.deterministic = !(vertexShader && left->getQualifier() == EvqUniform);\r
-                                                       }\r
-                                               }\r
-                                               else if(dst.rel.index != registerIndex(&address))   // Move the previous index register to the address register\r
-                                               {\r
-                                                       if(scale == 1)\r
-                                                       {\r
-                                                               Constant oldScale((int)dst.rel.scale);\r
-                                                               Instruction *mad = emit(sw::Shader::OPCODE_MAD, &address, &address, &oldScale, right);\r
-                                                               mad->src[0].index = dst.rel.index;\r
-                                                               mad->src[0].type = dst.rel.type;\r
-                                                       }\r
-                                                       else\r
-                                                       {\r
-                                                               Constant oldScale((int)dst.rel.scale);\r
-                                                               Instruction *mul = emit(sw::Shader::OPCODE_MUL, &address, &address, &oldScale);\r
-                                                               mul->src[0].index = dst.rel.index;\r
-                                                               mul->src[0].type = dst.rel.type;\r
-\r
-                                                               Constant newScale(scale);\r
-                                                               emit(sw::Shader::OPCODE_MAD, &address, right, &newScale, &address);\r
-                                                       }\r
-\r
-                                                       dst.rel.type = sw::Shader::PARAMETER_TEMP;\r
-                                                       dst.rel.index = registerIndex(&address);\r
-                                                       dst.rel.scale = 1;\r
-                                               }\r
-                                               else   // Just add the new index to the address register\r
-                                               {\r
-                                                       if(scale == 1)\r
-                                                       {\r
-                                                               emit(sw::Shader::OPCODE_ADD, &address, &address, right);\r
-                                                       }\r
-                                                       else\r
-                                                       {\r
-                                                               Constant newScale(scale);\r
-                                                               emit(sw::Shader::OPCODE_MAD, &address, right, &newScale, &address);\r
-                                                       }\r
-                                               }\r
-                                       }\r
-                                       else UNREACHABLE();\r
-                               }\r
-                               break;\r
-                       case EOpIndexDirectStruct:\r
-                               {\r
-                                       const TTypeList *structure = left->getType().getStruct();\r
-                                       const TString &fieldName = right->getType().getFieldName();\r
-\r
-                                       int offset = 0;\r
-                                       for(TTypeList::const_iterator field = structure->begin(); field != structure->end(); field++)\r
-                                       {\r
-                                               if(field->type->getFieldName() == fieldName)\r
-                                               {\r
-                                                       dst.type = registerType(left);\r
-                                                       dst.index += offset;\r
-                                                       dst.mask = writeMask(right);\r
-                                                       \r
-                                                       return 0xE4;\r
-                                               }\r
-\r
-                                               offset += field->type->totalRegisterCount();\r
-                                       }\r
-                               }\r
-                               break;\r
-                       case EOpVectorSwizzle:\r
-                               {\r
-                                       ASSERT(left->isRegister());\r
-\r
-                                       int leftMask = dst.mask;\r
-\r
-                                       int swizzle = 0;\r
-                                       int rightMask = 0;\r
-\r
-                                       TIntermSequence &sequence = right->getAsAggregate()->getSequence();\r
-\r
-                                       for(unsigned int i = 0; i < sequence.size(); i++)\r
-                                       {\r
-                                               int index = sequence[i]->getAsConstantUnion()->getIConst(0);\r
-\r
-                                               int element = swizzleElement(leftSwizzle, index);\r
-                                               rightMask = rightMask | (1 << element);\r
-                                               swizzle = swizzle | swizzleElement(leftSwizzle, i) << (element * 2);\r
-                                       }\r
-                                       \r
-                                       dst.mask = leftMask & rightMask;\r
-\r
-                                       return swizzle;\r
-                               }\r
-                               break;\r
-                       default:\r
-                               UNREACHABLE();   // Not an l-value operator\r
-                               break;\r
-                       }\r
-               }\r
-               else if(symbol)\r
-               {\r
-                       dst.type = registerType(symbol);\r
-                       dst.index = registerIndex(symbol);\r
-                       dst.mask = writeMask(symbol);\r
-                       return 0xE4;\r
-               }\r
-\r
-               return 0xE4;\r
-       }\r
-\r
-       sw::Shader::ParameterType OutputASM::registerType(TIntermTyped *operand)\r
-       {\r
-               if(isSamplerRegister(operand))\r
-               {\r
-                       return sw::Shader::PARAMETER_SAMPLER;\r
-               }\r
-\r
-               const TQualifier qualifier = operand->getQualifier();\r
-               if((EvqFragColor == qualifier) || (EvqFragData == qualifier))\r
-               {\r
-                       if(((EvqFragData == qualifier) && (EvqFragColor == outputQualifier)) ||\r
-                          ((EvqFragColor == qualifier) && (EvqFragData == outputQualifier)))\r
-                       {\r
-                               mContext.error(operand->getLine(), "static assignment to both gl_FragData and gl_FragColor", "");\r
-                       }\r
-                       outputQualifier = qualifier;\r
-               }\r
-\r
-               switch(qualifier)\r
-               {\r
-               case EvqTemporary:           return sw::Shader::PARAMETER_TEMP;\r
-               case EvqGlobal:              return sw::Shader::PARAMETER_TEMP;\r
-               case EvqConstExpr:           return sw::Shader::PARAMETER_FLOAT4LITERAL;   // All converted to float\r
-               case EvqAttribute:           return sw::Shader::PARAMETER_INPUT;\r
-               case EvqVaryingIn:           return sw::Shader::PARAMETER_INPUT;\r
-               case EvqVaryingOut:          return sw::Shader::PARAMETER_OUTPUT;\r
-               case EvqInvariantVaryingIn:  return sw::Shader::PARAMETER_INPUT;    // FIXME: Guarantee invariance at the backend\r
-               case EvqInvariantVaryingOut: return sw::Shader::PARAMETER_OUTPUT;   // FIXME: Guarantee invariance at the backend \r
-               case EvqUniform:             return sw::Shader::PARAMETER_CONST;\r
-               case EvqIn:                  return sw::Shader::PARAMETER_TEMP;\r
-               case EvqOut:                 return sw::Shader::PARAMETER_TEMP;\r
-               case EvqInOut:               return sw::Shader::PARAMETER_TEMP;\r
-               case EvqConstReadOnly:       return sw::Shader::PARAMETER_TEMP;\r
-               case EvqPosition:            return sw::Shader::PARAMETER_OUTPUT;\r
-               case EvqPointSize:           return sw::Shader::PARAMETER_OUTPUT;\r
-               case EvqFragCoord:           return sw::Shader::PARAMETER_MISCTYPE;\r
-               case EvqFrontFacing:         return sw::Shader::PARAMETER_MISCTYPE;\r
-               case EvqPointCoord:          return sw::Shader::PARAMETER_INPUT;\r
-               case EvqFragColor:           return sw::Shader::PARAMETER_COLOROUT;\r
-               case EvqFragData:            return sw::Shader::PARAMETER_COLOROUT;\r
-               default: UNREACHABLE();\r
-               }\r
-\r
-               return sw::Shader::PARAMETER_VOID;\r
-       }\r
-\r
-       int OutputASM::registerIndex(TIntermTyped *operand)\r
-       {\r
-               if(isSamplerRegister(operand))\r
-               {\r
-                       return samplerRegister(operand);\r
-               }\r
-\r
-               switch(operand->getQualifier())\r
-               {\r
-               case EvqTemporary:           return temporaryRegister(operand);\r
-               case EvqGlobal:              return temporaryRegister(operand);\r
-               case EvqConstExpr:           UNREACHABLE();\r
-               case EvqAttribute:           return attributeRegister(operand);\r
-               case EvqVaryingIn:           return varyingRegister(operand);\r
-               case EvqVaryingOut:          return varyingRegister(operand);\r
-               case EvqInvariantVaryingIn:  return varyingRegister(operand);\r
-               case EvqInvariantVaryingOut: return varyingRegister(operand);\r
-               case EvqUniform:             return uniformRegister(operand);\r
-               case EvqIn:                  return temporaryRegister(operand);\r
-               case EvqOut:                 return temporaryRegister(operand);\r
-               case EvqInOut:               return temporaryRegister(operand);\r
-               case EvqConstReadOnly:       return temporaryRegister(operand);\r
-               case EvqPosition:            return varyingRegister(operand);\r
-               case EvqPointSize:           return varyingRegister(operand);\r
-               case EvqFragCoord:           pixelShader->vPosDeclared = true;  return 0;\r
-               case EvqFrontFacing:         pixelShader->vFaceDeclared = true; return 1;\r
-               case EvqPointCoord:          return varyingRegister(operand);\r
-               case EvqFragColor:           return 0;\r
-               case EvqFragData:            return 0;\r
-               default: UNREACHABLE();\r
-               }\r
-\r
-               return 0;\r
-       }\r
-\r
-       int OutputASM::writeMask(TIntermTyped *destination, int index)\r
-       {\r
-               if(destination->getQualifier() == EvqPointSize)\r
-               {\r
-                       return 0x2;   // Point size stored in the y component\r
-               }\r
-\r
-               return 0xF >> (4 - registerSize(destination->getType(), index));\r
-       }\r
-\r
-       int OutputASM::readSwizzle(TIntermTyped *argument, int size)\r
-       {\r
-               if(argument->getQualifier() == EvqPointSize)\r
-               {\r
-                       return 0x55;   // Point size stored in the y component\r
-               }\r
-\r
-               static const unsigned char swizzleSize[5] = {0x00, 0x00, 0x54, 0xA4, 0xE4};   // (void), xxxx, xyyy, xyzz, xyzw\r
-\r
-               return swizzleSize[size];\r
-       }\r
-\r
-       // Conservatively checks whether an expression is fast to compute and has no side effects\r
-       bool OutputASM::trivial(TIntermTyped *expression, int budget)\r
-       {\r
-               if(!expression->isRegister())\r
-               {\r
-                       return false;\r
-               }\r
-\r
-               return cost(expression, budget) >= 0;\r
-       }\r
-\r
-       // Returns the remaining computing budget (if < 0 the expression is too expensive or has side effects)\r
-       int OutputASM::cost(TIntermNode *expression, int budget)\r
-       {\r
-               if(budget < 0)\r
-               {\r
-                       return budget;\r
-               }\r
-\r
-               if(expression->getAsSymbolNode())\r
-               {\r
-                       return budget;\r
-               }\r
-               else if(expression->getAsConstantUnion())\r
-               {\r
-                       return budget;\r
-               }\r
-               else if(expression->getAsBinaryNode())\r
-               {\r
-                       TIntermBinary *binary = expression->getAsBinaryNode();\r
-\r
-                       switch(binary->getOp())\r
-                       {\r
-                       case EOpVectorSwizzle:\r
-                       case EOpIndexDirect:\r
-                       case EOpIndexDirectStruct:\r
-                               return cost(binary->getLeft(), budget - 0);\r
-                       case EOpAdd:\r
-                       case EOpSub:\r
-                       case EOpMul:\r
-                               return cost(binary->getLeft(), cost(binary->getRight(), budget - 1));\r
-                       default:\r
-                               return -1;\r
-                       }\r
-               }\r
-               else if(expression->getAsUnaryNode())\r
-               {\r
-                       TIntermUnary *unary = expression->getAsUnaryNode();\r
-\r
-                       switch(unary->getOp())\r
-                       {\r
-                       case EOpAbs:\r
-                       case EOpNegative:\r
-                               return cost(unary->getOperand(), budget - 1);\r
-                       default:\r
-                               return -1;\r
-                       }\r
-               }\r
-               else if(expression->getAsSelectionNode())\r
-               {\r
-                       TIntermSelection *selection = expression->getAsSelectionNode();\r
-\r
-                       if(selection->usesTernaryOperator())\r
-                       {\r
-                               TIntermTyped *condition = selection->getCondition();\r
-                               TIntermNode *trueBlock = selection->getTrueBlock();\r
-                               TIntermNode *falseBlock = selection->getFalseBlock();\r
-                               TIntermConstantUnion *constantCondition = condition->getAsConstantUnion();\r
-\r
-                               if(constantCondition)\r
-                               {\r
-                                       bool trueCondition = constantCondition->getUnionArrayPointer()->getBConst();\r
-\r
-                                       if(trueCondition)\r
-                                       {\r
-                                               return cost(trueBlock, budget - 0);\r
-                                       }\r
-                                       else\r
-                                       {\r
-                                               return cost(falseBlock, budget - 0);\r
-                                       }\r
-                               }\r
-                               else\r
-                               {\r
-                                       return cost(trueBlock, cost(falseBlock, budget - 2));\r
-                               }\r
-                       }\r
-               }\r
-\r
-               return -1;\r
-       }\r
-\r
-       const Function *OutputASM::findFunction(const TString &name)\r
-       {\r
-               for(unsigned int f = 0; f < functionArray.size(); f++)\r
-               {\r
-                       if(functionArray[f].name == name)\r
-                       {\r
-                               return &functionArray[f];\r
-                       }\r
-               }\r
-\r
-               return 0;\r
-       }\r
-       \r
-       int OutputASM::temporaryRegister(TIntermTyped *temporary)\r
-       {\r
-               return allocate(temporaries, temporary);\r
-       }\r
-\r
-       int OutputASM::varyingRegister(TIntermTyped *varying)\r
-       {\r
-               int var = lookup(varyings, varying);\r
-\r
-               if(var == -1)\r
-               {\r
-                       var = allocate(varyings, varying);\r
-                       int componentCount = varying->getNominalSize();\r
-                       int registerCount = varying->totalRegisterCount();\r
-\r
-                       if(pixelShader)\r
-                       {\r
-                               if((var + registerCount) > sw::PixelShader::MAX_INPUT_VARYINGS)\r
-                               {\r
-                                       mContext.error(varying->getLine(), "Varyings packing failed: Too many varyings", "fragment shader");\r
-                                       return 0;\r
-                               }\r
-\r
-                               if(varying->getQualifier() == EvqPointCoord)\r
-                               {\r
-                                       ASSERT(varying->isRegister());\r
-                                       if(componentCount >= 1) pixelShader->semantic[var][0] = sw::Shader::Semantic(sw::Shader::USAGE_TEXCOORD, var);\r
-                                       if(componentCount >= 2) pixelShader->semantic[var][1] = sw::Shader::Semantic(sw::Shader::USAGE_TEXCOORD, var);\r
-                                       if(componentCount >= 3) pixelShader->semantic[var][2] = sw::Shader::Semantic(sw::Shader::USAGE_TEXCOORD, var);\r
-                                       if(componentCount >= 4) pixelShader->semantic[var][3] = sw::Shader::Semantic(sw::Shader::USAGE_TEXCOORD, var);\r
-                               }\r
-                               else\r
-                               {\r
-                                       for(int i = 0; i < varying->totalRegisterCount(); i++)\r
-                                       {\r
-                                               if(componentCount >= 1) pixelShader->semantic[var + i][0] = sw::Shader::Semantic(sw::Shader::USAGE_COLOR, var + i);\r
-                                               if(componentCount >= 2) pixelShader->semantic[var + i][1] = sw::Shader::Semantic(sw::Shader::USAGE_COLOR, var + i);\r
-                                               if(componentCount >= 3) pixelShader->semantic[var + i][2] = sw::Shader::Semantic(sw::Shader::USAGE_COLOR, var + i);\r
-                                               if(componentCount >= 4) pixelShader->semantic[var + i][3] = sw::Shader::Semantic(sw::Shader::USAGE_COLOR, var + i);\r
-                                       }\r
-                               }\r
-                       }\r
-                       else if(vertexShader)\r
-                       {\r
-                               if((var + registerCount) > sw::VertexShader::MAX_OUTPUT_VARYINGS)\r
-                               {\r
-                                       mContext.error(varying->getLine(), "Varyings packing failed: Too many varyings", "vertex shader");\r
-                                       return 0;\r
-                               }\r
-\r
-                               if(varying->getQualifier() == EvqPosition)\r
-                               {\r
-                                       ASSERT(varying->isRegister());\r
-                                       vertexShader->output[var][0] = sw::Shader::Semantic(sw::Shader::USAGE_POSITION, 0);\r
-                                       vertexShader->output[var][1] = sw::Shader::Semantic(sw::Shader::USAGE_POSITION, 0);\r
-                                       vertexShader->output[var][2] = sw::Shader::Semantic(sw::Shader::USAGE_POSITION, 0);\r
-                                       vertexShader->output[var][3] = sw::Shader::Semantic(sw::Shader::USAGE_POSITION, 0);\r
-                                       vertexShader->positionRegister = var;\r
-                               }\r
-                               else if(varying->getQualifier() == EvqPointSize)\r
-                               {\r
-                                       ASSERT(varying->isRegister());\r
-                                       vertexShader->output[var][0] = sw::Shader::Semantic(sw::Shader::USAGE_PSIZE, 0);\r
-                                       vertexShader->output[var][1] = sw::Shader::Semantic(sw::Shader::USAGE_PSIZE, 0);\r
-                                       vertexShader->output[var][2] = sw::Shader::Semantic(sw::Shader::USAGE_PSIZE, 0);\r
-                                       vertexShader->output[var][3] = sw::Shader::Semantic(sw::Shader::USAGE_PSIZE, 0);\r
-                                       vertexShader->pointSizeRegister = var;\r
-                               }\r
-                               else\r
-                               {\r
-                                       // Semantic indexes for user varyings will be assigned during program link to match the pixel shader\r
-                               }\r
-                       }\r
-                       else UNREACHABLE();\r
-\r
-                       declareVarying(varying, var);\r
-               }\r
-\r
-               return var;\r
-       }\r
-\r
-       void OutputASM::declareVarying(TIntermTyped *varying, int reg)\r
-       {\r
-               if(varying->getQualifier() != EvqPointCoord)   // gl_PointCoord does not need linking\r
-               {\r
-                       const TType &type = varying->getType();\r
-                       const char *name = varying->getAsSymbolNode()->getSymbol().c_str();\r
-                       VaryingList &activeVaryings = shaderObject->varyings;\r
-                       \r
-                       // Check if this varying has been declared before without having a register assigned\r
-                       for(VaryingList::iterator v = activeVaryings.begin(); v != activeVaryings.end(); v++)\r
-                       {\r
-                               if(v->name == name)\r
-                               {\r
-                                       if(reg >= 0)\r
-                                       {\r
-                                               ASSERT(v->reg < 0 || v->reg == reg);\r
-                                               v->reg = reg;\r
-                                       }\r
-\r
-                                       return;\r
-                               }\r
-                       }\r
-                       \r
-                       activeVaryings.push_back(glsl::Varying(glVariableType(type), name, varying->getArraySize(), reg, 0));\r
-               }\r
-       }\r
-\r
-       int OutputASM::uniformRegister(TIntermTyped *uniform)\r
-       {\r
-               const TType &type = uniform->getType();\r
-               ASSERT(!IsSampler(type.getBasicType()));\r
-               TIntermSymbol *symbol = uniform->getAsSymbolNode();\r
-               ASSERT(symbol);\r
-\r
-               if(symbol)\r
-               {\r
-                       int index = lookup(uniforms, uniform);\r
-\r
-                       if(index == -1)\r
-                       {\r
-                               index = allocate(uniforms, uniform);\r
-                               const TString &name = symbol->getSymbol().c_str();\r
-\r
-                               declareUniform(type, name, index);\r
-                       }\r
-\r
-                       return index;\r
-               }\r
-\r
-               return 0;\r
-       }\r
-\r
-       int OutputASM::attributeRegister(TIntermTyped *attribute)\r
-       {\r
-               ASSERT(!attribute->isArray());\r
-               ASSERT(attribute->getBasicType() == EbtFloat);\r
-\r
-               int index = lookup(attributes, attribute);\r
-\r
-               if(index == -1)\r
-               {\r
-                       TIntermSymbol *symbol = attribute->getAsSymbolNode();\r
-                       ASSERT(symbol);\r
-\r
-                       if(symbol)\r
-                       {\r
-                               index = allocate(attributes, attribute);\r
-                               const TType &type = attribute->getType();\r
-                               int registerCount = attribute->totalRegisterCount();\r
-\r
-                               if(vertexShader && (index + registerCount) <= sw::VertexShader::MAX_INPUT_ATTRIBUTES)\r
-                               {\r
-                                       for(int i = 0; i < registerCount; i++)\r
-                                       {\r
-                                               vertexShader->input[index + i] = sw::Shader::Semantic(sw::Shader::USAGE_TEXCOORD, index + i);\r
-                                       }\r
-                               }\r
-\r
-                               ActiveAttributes &activeAttributes = shaderObject->activeAttributes;\r
-\r
-                               const char *name = symbol->getSymbol().c_str();\r
-                               activeAttributes.push_back(Attribute(glVariableType(type), name, 0, index));\r
-                       }\r
-               }\r
-\r
-               return index;\r
-       }\r
-\r
-       int OutputASM::samplerRegister(TIntermTyped *sampler)\r
-       {\r
-               ASSERT(IsSampler(sampler->getType().getBasicType()));\r
-               TIntermSymbol *symbol = sampler->getAsSymbolNode();\r
-               TIntermBinary *binary = sampler->getAsBinaryNode();\r
-\r
-               if(symbol)\r
-               {\r
-                       return samplerRegister(symbol);\r
-               }\r
-               else if(binary)\r
-               {\r
-                       ASSERT(binary->getOp() == EOpIndexDirect || binary->getOp() == EOpIndexIndirect || binary->getOp() == EOpIndexDirectStruct);\r
-\r
-                       return samplerRegister(binary->getLeft());   // Index added later\r
-               }\r
-               else UNREACHABLE();\r
-\r
-               return 0;\r
-       }\r
-\r
-       int OutputASM::samplerRegister(TIntermSymbol *sampler)\r
-       {\r
-               const TType &type = sampler->getType();\r
-               ASSERT(IsSampler(type.getBasicType()) || type.getStruct());   // Structures can contain samplers\r
-\r
-               int index = lookup(samplers, sampler);\r
-\r
-               if(index == -1)\r
-               {\r
-                       index = allocate(samplers, sampler);\r
-\r
-                       if(sampler->getQualifier() == EvqUniform)\r
-                       {\r
-                               const char *name = sampler->getSymbol().c_str();\r
-                               declareUniform(type, name, index);\r
-                       }\r
-               }\r
-\r
-               return index;\r
-       }\r
-\r
-       int OutputASM::lookup(VariableArray &list, TIntermTyped *variable)\r
-       {\r
-               for(unsigned int i = 0; i < list.size(); i++)\r
-               {\r
-                       if(list[i] == variable)\r
-                       {\r
-                               return i;   // Pointer match\r
-                       }\r
-               }\r
-\r
-               TIntermSymbol *varSymbol = variable->getAsSymbolNode();\r
-\r
-               if(varSymbol)\r
-               {\r
-                       for(unsigned int i = 0; i < list.size(); i++)\r
-                       {\r
-                               if(list[i])\r
-                               {\r
-                                       TIntermSymbol *listSymbol = list[i]->getAsSymbolNode();\r
-\r
-                                       if(listSymbol)\r
-                                       {\r
-                                               if(listSymbol->getId() == varSymbol->getId())\r
-                                               {\r
-                                                       ASSERT(listSymbol->getSymbol() == varSymbol->getSymbol());\r
-                                                       ASSERT(listSymbol->getType() == varSymbol->getType());\r
-                                                       ASSERT(listSymbol->getQualifier() == varSymbol->getQualifier());\r
-\r
-                                                       return i;\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-\r
-               return -1;\r
-       }\r
-\r
-       int OutputASM::allocate(VariableArray &list, TIntermTyped *variable)\r
-       {\r
-               int index = lookup(list, variable);\r
-\r
-               if(index == -1)\r
-               {\r
-                       unsigned int registerCount = variable->totalRegisterCount();\r
-\r
-                       for(unsigned int i = 0; i < list.size(); i++)\r
-                       {\r
-                               if(list[i] == 0)\r
-                               {\r
-                                       unsigned int j = 1;\r
-                                       for( ; j < registerCount && (i + j) < list.size(); j++)\r
-                                       {\r
-                                               if(list[i + j] != 0)\r
-                                               {\r
-                                                       break;\r
-                                               }\r
-                                       }\r
-\r
-                                       if(j == registerCount)   // Found free slots\r
-                                       {\r
-                                               for(unsigned int j = 0; j < registerCount; j++)\r
-                                               {\r
-                                                       list[i + j] = variable;\r
-                                               }\r
-\r
-                                               return i;\r
-                                       }\r
-                               }\r
-                       }\r
-\r
-                       index = list.size();\r
-\r
-                       for(unsigned int i = 0; i < registerCount; i++)\r
-                       {\r
-                               list.push_back(variable);\r
-                       }\r
-               }\r
-\r
-               return index;\r
-       }\r
-\r
-       void OutputASM::free(VariableArray &list, TIntermTyped *variable)\r
-       {\r
-               int index = lookup(list, variable);\r
-\r
-               if(index >= 0)\r
-               {\r
-                       list[index] = 0;\r
-               }\r
-       }\r
-\r
-       void OutputASM::declareUniform(const TType &type, const TString &name, int index)\r
-       {\r
-               const TTypeList *structure = type.getStruct();\r
-               ActiveUniforms &activeUniforms = shaderObject->activeUniforms;\r
-\r
-               if(!structure)\r
-               {\r
-                       activeUniforms.push_back(Uniform(glVariableType(type), glVariablePrecision(type), name.c_str(), type.getArraySize(), index));\r
-\r
-                       if(isSamplerRegister(type))\r
-                       {\r
-                               for(int i = 0; i < type.totalRegisterCount(); i++)\r
-                               {\r
-                                       shader->declareSampler(index + i);\r
-                               }\r
-                       }\r
-               }\r
-               else\r
-               {\r
-                       if(type.isArray())\r
-                       {\r
-                               int elementIndex = index;\r
-\r
-                               for(int i = 0; i < type.getArraySize(); i++)\r
-                               {\r
-                                       for(size_t j = 0; j < structure->size(); j++)\r
-                                       {\r
-                                               const TType &fieldType = *(*structure)[j].type;\r
-                                               const TString &fieldName = fieldType.getFieldName();\r
-\r
-                                               const TString uniformName = name + "[" + str(i) + "]." + fieldName;\r
-                                               declareUniform(fieldType, uniformName, elementIndex);\r
-                                               elementIndex += fieldType.totalRegisterCount();\r
-                                       }\r
-                               }\r
-                       }\r
-                       else\r
-                       {\r
-                               int fieldIndex = index;\r
-\r
-                               for(size_t i = 0; i < structure->size(); i++)\r
-                               {\r
-                                       const TType &fieldType = *(*structure)[i].type;\r
-                                       const TString &fieldName = fieldType.getFieldName();\r
-\r
-                                       const TString uniformName = name + "." + fieldName;\r
-                                       declareUniform(fieldType, uniformName, fieldIndex);\r
-                                       fieldIndex += fieldType.totalRegisterCount();\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-\r
-       GLenum OutputASM::glVariableType(const TType &type)\r
-       {\r
-               if(type.getBasicType() == EbtFloat)\r
-               {\r
-                       if(type.isScalar())\r
-                       {\r
-                               return GL_FLOAT;\r
-                       }\r
-                       else if(type.isVector())\r
-                       {\r
-                               switch(type.getNominalSize())\r
-                               {\r
-                               case 2: return GL_FLOAT_VEC2;\r
-                               case 3: return GL_FLOAT_VEC3;\r
-                               case 4: return GL_FLOAT_VEC4;\r
-                               default: UNREACHABLE();\r
-                               }\r
-                       }\r
-                       else if(type.isMatrix())\r
-                       {\r
-                               switch(type.getNominalSize())\r
-                               {\r
-                               case 2:\r
-                                       switch(type.getSecondarySize())\r
-                                       {\r
-                                       case 2: return GL_FLOAT_MAT2;\r
-                                       case 3: return GL_FLOAT_MAT2x3;\r
-                                       case 4: return GL_FLOAT_MAT2x4;\r
-                                       default: UNREACHABLE();\r
-                                       }\r
-                               case 3:\r
-                                       switch(type.getSecondarySize())\r
-                                       {\r
-                                       case 2: return GL_FLOAT_MAT3x2;\r
-                                       case 3: return GL_FLOAT_MAT3;\r
-                                       case 4: return GL_FLOAT_MAT4x2;\r
-                                       default: UNREACHABLE();\r
-                                       }\r
-                               case 4:\r
-                                       switch(type.getSecondarySize())\r
-                                       {\r
-                                       case 2: return GL_FLOAT_MAT4x2;\r
-                                       case 3: return GL_FLOAT_MAT4x3;\r
-                                       case 4: return GL_FLOAT_MAT4;\r
-                                       default: UNREACHABLE();\r
-                                       }\r
-                               default: UNREACHABLE();\r
-                               }\r
-                       }\r
-                       else UNREACHABLE();\r
-               }\r
-               else if(type.getBasicType() == EbtInt)\r
-               {\r
-                       if(type.isScalar())\r
-                       {\r
-                               return GL_INT;\r
-                       }\r
-                       else if(type.isVector())\r
-                       {\r
-                               switch(type.getNominalSize())\r
-                               {\r
-                               case 2: return GL_INT_VEC2;\r
-                               case 3: return GL_INT_VEC3;\r
-                               case 4: return GL_INT_VEC4;\r
-                               default: UNREACHABLE();\r
-                               }\r
-                       }\r
-                       else UNREACHABLE();\r
-               }\r
-               else if(type.getBasicType() == EbtBool)\r
-               {\r
-                       if(type.isScalar())\r
-                       {\r
-                               return GL_BOOL;\r
-                       }\r
-                       else if(type.isVector())\r
-                       {\r
-                               switch(type.getNominalSize())\r
-                               {\r
-                               case 2: return GL_BOOL_VEC2;\r
-                               case 3: return GL_BOOL_VEC3;\r
-                               case 4: return GL_BOOL_VEC4;\r
-                               default: UNREACHABLE();\r
-                               }\r
-                       }\r
-                       else UNREACHABLE();\r
-               }\r
-               else if(type.getBasicType() == EbtSampler2D)\r
-               {\r
-                       return GL_SAMPLER_2D;\r
-               }\r
-               else if(type.getBasicType() == EbtSamplerCube)\r
-               {\r
-                       return GL_SAMPLER_CUBE;\r
-               }\r
-               else if(type.getBasicType() == EbtSamplerExternalOES)\r
-               {\r
-                       return GL_SAMPLER_EXTERNAL_OES;\r
-               }\r
-               else if(type.getBasicType() == EbtSampler3D)\r
-               {\r
-                       return GL_SAMPLER_3D_OES;\r
-               }\r
-               else UNREACHABLE();\r
-\r
-               return GL_NONE;\r
-       }\r
-\r
-       GLenum OutputASM::glVariablePrecision(const TType &type)\r
-       {\r
-               if(type.getBasicType() == EbtFloat)\r
-               {\r
-                       switch(type.getPrecision())\r
-                       {\r
-                       case EbpHigh:   return GL_HIGH_FLOAT;\r
-                       case EbpMedium: return GL_MEDIUM_FLOAT;\r
-                       case EbpLow:    return GL_LOW_FLOAT;\r
-                       case EbpUndefined:\r
-                               // Should be defined as the default precision by the parser\r
-                       default: UNREACHABLE();\r
-                       }\r
-               }\r
-               else if(type.getBasicType() == EbtInt)\r
-               {\r
-                       switch (type.getPrecision())\r
-                       {\r
-                       case EbpHigh:   return GL_HIGH_INT;\r
-                       case EbpMedium: return GL_MEDIUM_INT;\r
-                       case EbpLow:    return GL_LOW_INT;\r
-                       case EbpUndefined:\r
-                               // Should be defined as the default precision by the parser\r
-                       default: UNREACHABLE();\r
-                       }\r
-               }\r
-\r
-               // Other types (boolean, sampler) don't have a precision\r
-               return GL_NONE;\r
-       }\r
-\r
-       int OutputASM::dim(TIntermNode *v)\r
-       {\r
-               TIntermTyped *vector = v->getAsTyped();\r
-               ASSERT(vector && vector->isRegister());\r
-               return vector->getNominalSize();\r
-       }\r
-\r
-       int OutputASM::dim2(TIntermNode *m)\r
-       {\r
-               TIntermTyped *matrix = m->getAsTyped();\r
-               ASSERT(matrix && matrix->isMatrix() && !matrix->isArray());\r
-               return matrix->getSecondarySize();\r
-       }\r
-\r
-       // Returns ~0 if no loop count could be determined\r
-       unsigned int OutputASM::loopCount(TIntermLoop *node)\r
-       {\r
-               // Parse loops of the form:\r
-               // for(int index = initial; index [comparator] limit; index += increment)\r
-               TIntermSymbol *index = 0;\r
-               TOperator comparator = EOpNull;\r
-               int initial = 0;\r
-               int limit = 0;\r
-               int increment = 0;\r
-\r
-               // Parse index name and intial value\r
-               if(node->getInit())\r
-               {\r
-                       TIntermAggregate *init = node->getInit()->getAsAggregate();\r
-\r
-                       if(init)\r
-                       {\r
-                               TIntermSequence &sequence = init->getSequence();\r
-                               TIntermTyped *variable = sequence[0]->getAsTyped();\r
-\r
-                               if(variable && variable->getQualifier() == EvqTemporary)\r
-                               {\r
-                                       TIntermBinary *assign = variable->getAsBinaryNode();\r
-\r
-                                       if(assign->getOp() == EOpInitialize)\r
-                                       {\r
-                                               TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();\r
-                                               TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();\r
-\r
-                                               if(symbol && constant)\r
-                                               {\r
-                                                       if(constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)\r
-                                                       {\r
-                                                               index = symbol;\r
-                                                               initial = constant->getUnionArrayPointer()[0].getIConst();\r
-                                                       }\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-\r
-               // Parse comparator and limit value\r
-               if(index && node->getCondition())\r
-               {\r
-                       TIntermBinary *test = node->getCondition()->getAsBinaryNode();\r
-\r
-                       if(test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())\r
-                       {\r
-                               TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();\r
-\r
-                               if(constant)\r
-                               {\r
-                                       if(constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)\r
-                                       {\r
-                                               comparator = test->getOp();\r
-                                               limit = constant->getUnionArrayPointer()[0].getIConst();\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-\r
-               // Parse increment\r
-               if(index && comparator != EOpNull && node->getExpression())\r
-               {\r
-                       TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();\r
-                       TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();\r
-\r
-                       if(binaryTerminal)\r
-                       {\r
-                               TOperator op = binaryTerminal->getOp();\r
-                               TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();\r
-\r
-                               if(constant)\r
-                               {\r
-                                       if(constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)\r
-                                       {\r
-                                               int value = constant->getUnionArrayPointer()[0].getIConst();\r
-\r
-                                               switch(op)\r
-                                               {\r
-                                               case EOpAddAssign: increment = value;  break;\r
-                                               case EOpSubAssign: increment = -value; break;\r
-                                               default: UNIMPLEMENTED();\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-                       else if(unaryTerminal)\r
-                       {\r
-                               TOperator op = unaryTerminal->getOp();\r
-\r
-                               switch(op)\r
-                               {\r
-                               case EOpPostIncrement: increment = 1;  break;\r
-                               case EOpPostDecrement: increment = -1; break;\r
-                               case EOpPreIncrement:  increment = 1;  break;\r
-                               case EOpPreDecrement:  increment = -1; break;\r
-                               default: UNIMPLEMENTED();\r
-                               }\r
-                       }\r
-               }\r
-\r
-               if(index && comparator != EOpNull && increment != 0)\r
-               {\r
-                       if(comparator == EOpLessThanEqual)\r
-                       {\r
-                               comparator = EOpLessThan;\r
-                               limit += 1;\r
-                       }\r
-\r
-                       if(comparator == EOpLessThan)\r
-                       {\r
-                               int iterations = (limit - initial) / increment;\r
-\r
-                               if(iterations <= 0)\r
-                               {\r
-                                       iterations = 0;\r
-                               }\r
-\r
-                               return iterations;\r
-                       }\r
-                       else UNIMPLEMENTED();   // Falls through\r
-               }\r
-\r
-               return ~0;\r
-       }\r
-\r
-       bool DetectLoopDiscontinuity::traverse(TIntermNode *node)\r
-       {\r
-               loopDepth = 0;\r
-               loopDiscontinuity = false;\r
-               \r
-               node->traverse(this);\r
-               \r
-               return loopDiscontinuity;\r
-       }\r
-\r
-       bool DetectLoopDiscontinuity::visitLoop(Visit visit, TIntermLoop *loop)\r
-       {\r
-               if(visit == PreVisit)\r
-               {\r
-                       loopDepth++;\r
-               }\r
-               else if(visit == PostVisit)\r
-               {\r
-                       loopDepth++;\r
-               }\r
-\r
-               return true;\r
-       }\r
-\r
-       bool DetectLoopDiscontinuity::visitBranch(Visit visit, TIntermBranch *node)\r
-       {\r
-               if(loopDiscontinuity)\r
-               {\r
-                       return false;\r
-               }\r
-\r
-               if(!loopDepth)\r
-               {\r
-                       return true;\r
-               }\r
-       \r
-               switch(node->getFlowOp())\r
-               {\r
-               case EOpKill:\r
-                       break;\r
-               case EOpBreak:\r
-               case EOpContinue:\r
-               case EOpReturn:\r
-                       loopDiscontinuity = true;\r
-                       break;\r
-               default: UNREACHABLE();\r
-               }\r
-\r
-               return !loopDiscontinuity;\r
-       }\r
-\r
-       bool DetectLoopDiscontinuity::visitAggregate(Visit visit, TIntermAggregate *node)\r
-       {\r
-               return !loopDiscontinuity;\r
-       }\r
-}\r
+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "OutputASM.h"
+#include "Common/Math.hpp"
+
+#include "common/debug.h"
+#include "InfoSink.h"
+
+#include "libGLESv2/Shader.h"
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GLES3/gl3.h>
+
+#include <stdlib.h>
+
+namespace glsl
+{
+       // Integer to TString conversion
+       TString str(int i)
+       {
+               char buffer[20];
+               sprintf(buffer, "%d", i);
+               return buffer;
+       }
+
+       class Temporary : public TIntermSymbol
+       {
+       public:
+               Temporary(OutputASM *assembler) : TIntermSymbol(TSymbolTableLevel::nextUniqueId(), "tmp", TType(EbtFloat, EbpHigh, EvqTemporary, 4, 1, false)), assembler(assembler)
+               {
+               }
+
+               ~Temporary()
+               {
+                       assembler->freeTemporary(this);
+               }
+
+       private:
+               OutputASM *const assembler;
+       };
+
+       class Constant : public TIntermConstantUnion
+       {
+       public:
+               Constant(float x, float y, float z, float w) : TIntermConstantUnion(constants, TType(EbtFloat, EbpHigh, EvqConstExpr, 4, 1, false))
+               {
+                       constants[0].setFConst(x);
+                       constants[1].setFConst(y);
+                       constants[2].setFConst(z);
+                       constants[3].setFConst(w);
+               }
+
+               Constant(bool b) : TIntermConstantUnion(constants, TType(EbtBool, EbpHigh, EvqConstExpr, 1, 1, false))
+               {
+                       constants[0].setBConst(b);
+               }
+
+               Constant(int i) : TIntermConstantUnion(constants, TType(EbtInt, EbpHigh, EvqConstExpr, 1, 1, false))
+               {
+                       constants[0].setIConst(i);
+               }
+
+               ~Constant()
+               {
+               }
+
+       private:
+               ConstantUnion constants[4];
+       };
+
+       Uniform::Uniform(GLenum type, GLenum precision, const std::string &name, int arraySize, int registerIndex, int blockId, const BlockMemberInfo& blockMemberInfo) :
+               type(type), precision(precision), name(name), arraySize(arraySize), registerIndex(registerIndex), blockId(blockId), blockInfo(blockMemberInfo)
+       {
+       }
+
+       UniformBlock::UniformBlock(const std::string& name, unsigned int dataSize, unsigned int arraySize,
+                                  TLayoutBlockStorage layout, bool isRowMajorLayout, int registerIndex, int blockId) :
+               name(name), dataSize(dataSize), arraySize(arraySize), layout(layout),
+               isRowMajorLayout(isRowMajorLayout), registerIndex(registerIndex), blockId(blockId)
+       {
+       }
+
+       BlockLayoutEncoder::BlockLayoutEncoder(bool rowMajor)
+               : mCurrentOffset(0), isRowMajor(rowMajor)
+       {
+       }
+
+       BlockMemberInfo BlockLayoutEncoder::encodeType(const TType &type)
+       {
+               int arrayStride;
+               int matrixStride;
+
+               getBlockLayoutInfo(type, type.getArraySize(), isRowMajor, &arrayStride, &matrixStride);
+
+               const BlockMemberInfo memberInfo(static_cast<int>(mCurrentOffset * BytesPerComponent),
+                                                static_cast<int>(arrayStride * BytesPerComponent),
+                                                static_cast<int>(matrixStride * BytesPerComponent),
+                                                (matrixStride > 0) && isRowMajor);
+
+               advanceOffset(type, type.getArraySize(), isRowMajor, arrayStride, matrixStride);
+
+               return memberInfo;
+       }
+
+       // static
+       size_t BlockLayoutEncoder::getBlockRegister(const BlockMemberInfo &info)
+       {
+               return (info.offset / BytesPerComponent) / ComponentsPerRegister;
+       }
+
+       // static
+       size_t BlockLayoutEncoder::getBlockRegisterElement(const BlockMemberInfo &info)
+       {
+               return (info.offset / BytesPerComponent) % ComponentsPerRegister;
+       }
+
+       void BlockLayoutEncoder::nextRegister()
+       {
+               mCurrentOffset = sw::align(mCurrentOffset, ComponentsPerRegister);
+       }
+
+       Std140BlockEncoder::Std140BlockEncoder(bool rowMajor) : BlockLayoutEncoder(rowMajor)
+       {
+       }
+
+       void Std140BlockEncoder::enterAggregateType()
+       {
+               nextRegister();
+       }
+
+       void Std140BlockEncoder::exitAggregateType()
+       {
+               nextRegister();
+       }
+
+       void Std140BlockEncoder::getBlockLayoutInfo(const TType &type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut)
+       {
+               size_t baseAlignment = 0;
+               int matrixStride = 0;
+               int arrayStride = 0;
+
+               if(type.isMatrix())
+               {
+                       baseAlignment = ComponentsPerRegister;
+                       matrixStride = ComponentsPerRegister;
+
+                       if(arraySize > 0)
+                       {
+                               const int numRegisters = isRowMajorMatrix ? type.getSecondarySize() : type.getNominalSize();
+                               arrayStride = ComponentsPerRegister * numRegisters;
+                       }
+               }
+               else if(arraySize > 0)
+               {
+                       baseAlignment = ComponentsPerRegister;
+                       arrayStride = ComponentsPerRegister;
+               }
+               else
+               {
+                       const size_t numComponents = type.getElementSize();
+                       baseAlignment = (numComponents == 3 ? 4u : numComponents);
+               }
+
+               mCurrentOffset = sw::align(mCurrentOffset, baseAlignment);
+
+               *matrixStrideOut = matrixStride;
+               *arrayStrideOut = arrayStride;
+       }
+
+       void Std140BlockEncoder::advanceOffset(const TType &type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride)
+       {
+               if(arraySize > 0)
+               {
+                       mCurrentOffset += arrayStride * arraySize;
+               }
+               else if(type.isMatrix())
+               {
+                       ASSERT(matrixStride == ComponentsPerRegister);
+                       const int numRegisters = isRowMajorMatrix ? type.getSecondarySize() : type.getNominalSize();
+                       mCurrentOffset += ComponentsPerRegister * numRegisters;
+               }
+               else
+               {
+                       mCurrentOffset += type.getElementSize();
+               }
+       }
+
+       Attribute::Attribute()
+       {
+               type = GL_NONE;
+               arraySize = 0;
+               registerIndex = 0;
+       }
+
+       Attribute::Attribute(GLenum type, const std::string &name, int arraySize, int location, int registerIndex)
+       {
+               this->type = type;
+               this->name = name;
+               this->arraySize = arraySize;
+               this->location = location;
+               this->registerIndex = registerIndex;
+       }
+
+       sw::PixelShader *Shader::getPixelShader() const
+       {
+               return 0;
+       }
+
+       sw::VertexShader *Shader::getVertexShader() const
+       {
+               return 0;
+       }
+
+       OutputASM::TextureFunction::TextureFunction(const TString& nodeName) : method(IMPLICIT), proj(false), offset(false)
+       {
+               TString name = TFunction::unmangleName(nodeName);
+
+               if(name == "texture2D" || name == "textureCube" || name == "texture" || name == "texture3D")
+               {
+                       method = IMPLICIT;
+               }
+               else if(name == "texture2DProj" || name == "textureProj")
+               {
+                       method = IMPLICIT;
+                       proj = true;
+               }
+               else if(name == "texture2DLod" || name == "textureCubeLod" || name == "textureLod")
+               {
+                       method = LOD;
+               }
+               else if(name == "texture2DProjLod" || name == "textureProjLod")
+               {
+                       method = LOD;
+                       proj = true;
+               }
+               else if(name == "textureSize")
+               {
+                       method = SIZE;
+               }
+               else if(name == "textureOffset")
+               {
+                       method = IMPLICIT;
+                       offset = true;
+               }
+               else if(name == "textureProjOffset")
+               {
+                       method = IMPLICIT;
+                       offset = true;
+                       proj = true;
+               }
+               else if(name == "textureLodOffset")
+               {
+                       method = LOD;
+                       offset = true;
+               }
+               else if(name == "textureProjLodOffset")
+               {
+                       method = LOD;
+                       proj = true;
+                       offset = true;
+               }
+               else if(name == "texelFetch")
+               {
+                       method = FETCH;
+               }
+               else if(name == "texelFetchOffset")
+               {
+                       method = FETCH;
+                       offset = true;
+               }
+               else if(name == "textureGrad")
+               {
+                       method = GRAD;
+               }
+               else if(name == "textureGradOffset")
+               {
+                       method = GRAD;
+                       offset = true;
+               }
+               else if(name == "textureProjGrad")
+               {
+                       method = GRAD;
+                       proj = true;
+               }
+               else if(name == "textureProjGradOffset")
+               {
+                       method = GRAD;
+                       proj = true;
+                       offset = true;
+               }
+               else UNREACHABLE(0);
+       }
+
+       OutputASM::OutputASM(TParseContext &context, Shader *shaderObject) : TIntermTraverser(true, true, true), shaderObject(shaderObject), mContext(context)
+       {
+               shader = 0;
+               pixelShader = 0;
+               vertexShader = 0;
+
+               if(shaderObject)
+               {
+                       shader = shaderObject->getShader();
+                       pixelShader = shaderObject->getPixelShader();
+                       vertexShader = shaderObject->getVertexShader();
+               }
+
+               functionArray.push_back(Function(0, "main(", 0, 0));
+               currentFunction = 0;
+               outputQualifier = EvqOutput; // Set outputQualifier to any value other than EvqFragColor or EvqFragData
+       }
+
+       OutputASM::~OutputASM()
+       {
+       }
+
+       void OutputASM::output()
+       {
+               if(shader)
+               {
+                       emitShader(GLOBAL);
+
+                       if(functionArray.size() > 1)   // Only call main() when there are other functions
+                       {
+                               Instruction *callMain = emit(sw::Shader::OPCODE_CALL);
+                               callMain->dst.type = sw::Shader::PARAMETER_LABEL;
+                               callMain->dst.index = 0;   // main()
+
+                               emit(sw::Shader::OPCODE_RET);
+                       }
+
+                       emitShader(FUNCTION);
+               }
+       }
+
+       void OutputASM::emitShader(Scope scope)
+       {
+               emitScope = scope;
+               currentScope = GLOBAL;
+               mContext.getTreeRoot()->traverse(this);
+       }
+
+       void OutputASM::freeTemporary(Temporary *temporary)
+       {
+               free(temporaries, temporary);
+       }
+
+       sw::Shader::Opcode OutputASM::getOpcode(sw::Shader::Opcode op, TIntermTyped *in) const
+       {
+               TBasicType baseType = in->getType().getBasicType();
+
+               switch(op)
+               {
+               case sw::Shader::OPCODE_NEG:
+                       switch(baseType)
+                       {
+                       case EbtInt:
+                       case EbtUInt:
+                               return sw::Shader::OPCODE_INEG;
+                       case EbtFloat:
+                       default:
+                               return op;
+                       }
+               case sw::Shader::OPCODE_ABS:
+                       switch(baseType)
+                       {
+                       case EbtInt:
+                               return sw::Shader::OPCODE_IABS;
+                       case EbtFloat:
+                       default:
+                               return op;
+                       }
+               case sw::Shader::OPCODE_SGN:
+                       switch(baseType)
+                       {
+                       case EbtInt:
+                               return sw::Shader::OPCODE_ISGN;
+                       case EbtFloat:
+                       default:
+                               return op;
+                       }
+               case sw::Shader::OPCODE_ADD:
+                       switch(baseType)
+                       {
+                       case EbtInt:
+                       case EbtUInt:
+                               return sw::Shader::OPCODE_IADD;
+                       case EbtFloat:
+                       default:
+                               return op;
+                       }
+               case sw::Shader::OPCODE_SUB:
+                       switch(baseType)
+                       {
+                       case EbtInt:
+                       case EbtUInt:
+                               return sw::Shader::OPCODE_ISUB;
+                       case EbtFloat:
+                       default:
+                               return op;
+                       }
+               case sw::Shader::OPCODE_MUL:
+                       switch(baseType)
+                       {
+                       case EbtInt:
+                       case EbtUInt:
+                               return sw::Shader::OPCODE_IMUL;
+                       case EbtFloat:
+                       default:
+                               return op;
+                       }
+               case sw::Shader::OPCODE_DIV:
+                       switch(baseType)
+                       {
+                       case EbtInt:
+                               return sw::Shader::OPCODE_IDIV;
+                       case EbtUInt:
+                               return sw::Shader::OPCODE_UDIV;
+                       case EbtFloat:
+                       default:
+                               return op;
+                       }
+               case sw::Shader::OPCODE_IMOD:
+                       return baseType == EbtUInt ? sw::Shader::OPCODE_UMOD : op;
+               case sw::Shader::OPCODE_ISHR:
+                       return baseType == EbtUInt ? sw::Shader::OPCODE_USHR : op;
+               case sw::Shader::OPCODE_MIN:
+                       switch(baseType)
+                       {
+                       case EbtInt:
+                               return sw::Shader::OPCODE_IMIN;
+                       case EbtUInt:
+                               return sw::Shader::OPCODE_UMIN;
+                       case EbtFloat:
+                       default:
+                               return op;
+                       }
+               case sw::Shader::OPCODE_MAX:
+                       switch(baseType)
+                       {
+                       case EbtInt:
+                               return sw::Shader::OPCODE_IMAX;
+                       case EbtUInt:
+                               return sw::Shader::OPCODE_UMAX;
+                       case EbtFloat:
+                       default:
+                               return op;
+                       }
+               default:
+                       return op;
+               }
+       }
+
+       void OutputASM::visitSymbol(TIntermSymbol *symbol)
+       {
+               // Vertex varyings don't have to be actively used to successfully link
+               // against pixel shaders that use them. So make sure they're declared.
+               if(symbol->getQualifier() == EvqVaryingOut || symbol->getQualifier() == EvqInvariantVaryingOut || symbol->getQualifier() == EvqVertexOut)
+               {
+                       if(symbol->getBasicType() != EbtInvariant)   // Typeless declarations are not new varyings
+                       {
+                               declareVarying(symbol, -1);
+                       }
+               }
+
+               TInterfaceBlock* block = symbol->getType().getInterfaceBlock();
+               // OpenGL ES 3.0.4 spec, section 2.12.6 Uniform Variables:
+               // "All members of a named uniform block declared with a shared or std140 layout qualifier
+               // are considered active, even if they are not referenced in any shader in the program.
+               // The uniform block itself is also considered active, even if no member of the block is referenced."
+               if(block && ((block->blockStorage() == EbsShared) || (block->blockStorage() == EbsStd140)))
+               {
+                       uniformRegister(symbol);
+               }
+       }
+
+       bool OutputASM::visitBinary(Visit visit, TIntermBinary *node)
+       {
+               if(currentScope != emitScope)
+               {
+                       return false;
+               }
+
+               TIntermTyped *result = node;
+               TIntermTyped *left = node->getLeft();
+               TIntermTyped *right = node->getRight();
+               const TType &leftType = left->getType();
+               const TType &rightType = right->getType();
+
+               if(isSamplerRegister(result))
+               {
+                       return false;   // Don't traverse, the register index is determined statically
+               }
+
+               switch(node->getOp())
+               {
+               case EOpAssign:
+                       if(visit == PostVisit)
+                       {
+                               assignLvalue(left, right);
+                               copy(result, right);
+                       }
+                       break;
+               case EOpInitialize:
+                       if(visit == PostVisit)
+                       {
+                               copy(left, right);
+                       }
+                       break;
+               case EOpMatrixTimesScalarAssign:
+                       if(visit == PostVisit)
+                       {
+                               for(int i = 0; i < leftType.getNominalSize(); i++)
+                               {
+                                       emit(sw::Shader::OPCODE_MUL, result, i, left, i, right);
+                               }
+
+                               assignLvalue(left, result);
+                       }
+                       break;
+               case EOpVectorTimesMatrixAssign:
+                       if(visit == PostVisit)
+                       {
+                               int size = leftType.getNominalSize();
+
+                               for(int i = 0; i < size; i++)
+                               {
+                                       Instruction *dot = emit(sw::Shader::OPCODE_DP(size), result, 0, left, 0, right, i);
+                                       dot->dst.mask = 1 << i;
+                               }
+
+                               assignLvalue(left, result);
+                       }
+                       break;
+               case EOpMatrixTimesMatrixAssign:
+                       if(visit == PostVisit)
+                       {
+                               int dim = leftType.getNominalSize();
+
+                               for(int i = 0; i < dim; i++)
+                               {
+                                       Instruction *mul = emit(sw::Shader::OPCODE_MUL, result, i, left, 0, right, i);
+                                       mul->src[1].swizzle = 0x00;
+
+                                       for(int j = 1; j < dim; j++)
+                                       {
+                                               Instruction *mad = emit(sw::Shader::OPCODE_MAD, result, i, left, j, right, i, result, i);
+                                               mad->src[1].swizzle = j * 0x55;
+                                       }
+                               }
+
+                               assignLvalue(left, result);
+                       }
+                       break;
+               case EOpIndexDirect:
+                       if(visit == PostVisit)
+                       {
+                               int index = right->getAsConstantUnion()->getIConst(0);
+
+                               if(result->isMatrix() || result->isStruct() || result->isInterfaceBlock())
+                               {
+                                       ASSERT(left->isArray());
+                                       copy(result, left, index * left->elementRegisterCount());
+                               }
+                               else if(result->isRegister())
+                               {
+                                       int srcIndex = 0;
+                                       if(left->isRegister())
+                                       {
+                                               srcIndex = 0;
+                                       }
+                                       else if(left->isArray())
+                                       {
+                                               srcIndex = index * left->elementRegisterCount();
+                                       }
+                                       else if(left->isMatrix())
+                                       {
+                                               ASSERT(index < left->getNominalSize());   // FIXME: Report semantic error
+                                               srcIndex = index;
+                                       }
+                                       else UNREACHABLE(0);
+
+                                       Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, 0, left, srcIndex);
+
+                                       if(left->isRegister())
+                                       {
+                                               mov->src[0].swizzle = index;
+                                       }
+                               }
+                               else UNREACHABLE(0);
+                       }
+                       break;
+               case EOpIndexIndirect:
+                       if(visit == PostVisit)
+                       {
+                               if(left->isArray() || left->isMatrix())
+                               {
+                                       for(int index = 0; index < result->totalRegisterCount(); index++)
+                                       {
+                                               Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, index, left, index);
+                                               mov->dst.mask = writeMask(result, index);
+
+                                               if(left->totalRegisterCount() > 1)
+                                               {
+                                                       sw::Shader::SourceParameter relativeRegister;
+                                                       argument(relativeRegister, right);
+
+                                                       mov->src[0].rel.type = relativeRegister.type;
+                                                       mov->src[0].rel.index = relativeRegister.index;
+                                                       mov->src[0].rel.scale = result->totalRegisterCount();
+                                                       mov->src[0].rel.deterministic = !(vertexShader && left->getQualifier() == EvqUniform);
+                                               }
+                                       }
+                               }
+                               else if(left->isRegister())
+                               {
+                                       emit(sw::Shader::OPCODE_EXTRACT, result, left, right);
+                               }
+                               else UNREACHABLE(0);
+                       }
+                       break;
+               case EOpIndexDirectStruct:
+               case EOpIndexDirectInterfaceBlock:
+                       if(visit == PostVisit)
+                       {
+                               ASSERT(leftType.isStruct() || (leftType.isInterfaceBlock()));
+
+                               const TFieldList& fields = (node->getOp() == EOpIndexDirectStruct) ?
+                                                          leftType.getStruct()->fields() :
+                                                          leftType.getInterfaceBlock()->fields();
+                               int index = right->getAsConstantUnion()->getIConst(0);
+                               int fieldOffset = 0;
+
+                               for(int i = 0; i < index; i++)
+                               {
+                                       fieldOffset += fields[i]->type()->totalRegisterCount();
+                               }
+
+                               copy(result, left, fieldOffset);
+                       }
+                       break;
+               case EOpVectorSwizzle:
+                       if(visit == PostVisit)
+                       {
+                               int swizzle = 0;
+                               TIntermAggregate *components = right->getAsAggregate();
+
+                               if(components)
+                               {
+                                       TIntermSequence &sequence = components->getSequence();
+                                       int component = 0;
+
+                                       for(TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
+                                       {
+                                               TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
+
+                                               if(element)
+                                               {
+                                                       int i = element->getUnionArrayPointer()[0].getIConst();
+                                                       swizzle |= i << (component * 2);
+                                                       component++;
+                                               }
+                                               else UNREACHABLE(0);
+                                       }
+                               }
+                               else UNREACHABLE(0);
+
+                               Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, left);
+                               mov->src[0].swizzle = swizzle;
+                       }
+                       break;
+               case EOpAddAssign: if(visit == PostVisit) emitAssign(getOpcode(sw::Shader::OPCODE_ADD, result), result, left, left, right); break;
+               case EOpAdd:       if(visit == PostVisit) emitBinary(getOpcode(sw::Shader::OPCODE_ADD, result), result, left, right);       break;
+               case EOpSubAssign: if(visit == PostVisit) emitAssign(getOpcode(sw::Shader::OPCODE_SUB, result), result, left, left, right); break;
+               case EOpSub:       if(visit == PostVisit) emitBinary(getOpcode(sw::Shader::OPCODE_SUB, result), result, left, right);       break;
+               case EOpMulAssign: if(visit == PostVisit) emitAssign(getOpcode(sw::Shader::OPCODE_MUL, result), result, left, left, right); break;
+               case EOpMul:       if(visit == PostVisit) emitBinary(getOpcode(sw::Shader::OPCODE_MUL, result), result, left, right);       break;
+               case EOpDivAssign: if(visit == PostVisit) emitAssign(getOpcode(sw::Shader::OPCODE_DIV, result), result, left, left, right); break;
+               case EOpDiv:       if(visit == PostVisit) emitBinary(getOpcode(sw::Shader::OPCODE_DIV, result), result, left, right);       break;
+               case EOpIModAssign:          if(visit == PostVisit) emitAssign(getOpcode(sw::Shader::OPCODE_IMOD, result), result, left, left, right); break;
+               case EOpIMod:                if(visit == PostVisit) emitBinary(getOpcode(sw::Shader::OPCODE_IMOD, result), result, left, right);       break;
+               case EOpBitShiftLeftAssign:  if(visit == PostVisit) emitAssign(sw::Shader::OPCODE_SHL, result, left, left, right); break;
+               case EOpBitShiftLeft:        if(visit == PostVisit) emitBinary(sw::Shader::OPCODE_SHL, result, left, right);       break;
+               case EOpBitShiftRightAssign: if(visit == PostVisit) emitAssign(getOpcode(sw::Shader::OPCODE_ISHR, result), result, left, left, right); break;
+               case EOpBitShiftRight:       if(visit == PostVisit) emitBinary(getOpcode(sw::Shader::OPCODE_ISHR, result), result, left, right);       break;
+               case EOpBitwiseAndAssign:    if(visit == PostVisit) emitAssign(sw::Shader::OPCODE_AND, result, left, left, right); break;
+               case EOpBitwiseAnd:          if(visit == PostVisit) emitBinary(sw::Shader::OPCODE_AND, result, left, right);       break;
+               case EOpBitwiseXorAssign:    if(visit == PostVisit) emitAssign(sw::Shader::OPCODE_XOR, result, left, left, right); break;
+               case EOpBitwiseXor:          if(visit == PostVisit) emitBinary(sw::Shader::OPCODE_XOR, result, left, right);       break;
+               case EOpBitwiseOrAssign:     if(visit == PostVisit) emitAssign(sw::Shader::OPCODE_OR, result, left, left, right);  break;
+               case EOpBitwiseOr:           if(visit == PostVisit) emitBinary(sw::Shader::OPCODE_OR, result, left, right);        break;
+               case EOpEqual:
+                       if(visit == PostVisit)
+                       {
+                               emitBinary(sw::Shader::OPCODE_EQ, result, left, right);
+
+                               for(int index = 1; index < left->totalRegisterCount(); index++)
+                               {
+                                       Temporary equal(this);
+                                       emit(sw::Shader::OPCODE_EQ, &equal, 0, left, index, right, index);
+                                       emit(sw::Shader::OPCODE_AND, result, result, &equal);
+                               }
+                       }
+                       break;
+               case EOpNotEqual:
+                       if(visit == PostVisit)
+                       {
+                               emitBinary(sw::Shader::OPCODE_NE, result, left, right);
+
+                               for(int index = 1; index < left->totalRegisterCount(); index++)
+                               {
+                                       Temporary notEqual(this);
+                                       emit(sw::Shader::OPCODE_NE, &notEqual, 0, left, index, right, index);
+                                       emit(sw::Shader::OPCODE_OR, result, result, &notEqual);
+                               }
+                       }
+                       break;
+               case EOpLessThan:                if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_LT, result, left, right); break;
+               case EOpGreaterThan:             if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_GT, result, left, right); break;
+               case EOpLessThanEqual:           if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_LE, result, left, right); break;
+               case EOpGreaterThanEqual:        if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_GE, result, left, right); break;
+               case EOpVectorTimesScalarAssign: if(visit == PostVisit) emitAssign(getOpcode(sw::Shader::OPCODE_MUL, left), result, left, left, right); break;
+               case EOpVectorTimesScalar:       if(visit == PostVisit) emit(getOpcode(sw::Shader::OPCODE_MUL, left), result, left, right); break;
+               case EOpMatrixTimesScalar:
+                       if(visit == PostVisit)
+                       {
+                               if(left->isMatrix())
+                               {
+                                       for(int i = 0; i < leftType.getNominalSize(); i++)
+                                       {
+                                               emit(sw::Shader::OPCODE_MUL, result, i, left, i, right, 0);
+                                       }
+                               }
+                               else if(right->isMatrix())
+                               {
+                                       for(int i = 0; i < rightType.getNominalSize(); i++)
+                                       {
+                                               emit(sw::Shader::OPCODE_MUL, result, i, left, 0, right, i);
+                                       }
+                               }
+                               else UNREACHABLE(0);
+                       }
+                       break;
+               case EOpVectorTimesMatrix:
+                       if(visit == PostVisit)
+                       {
+                               sw::Shader::Opcode dpOpcode = sw::Shader::OPCODE_DP(leftType.getNominalSize());
+
+                               int size = rightType.getNominalSize();
+                               for(int i = 0; i < size; i++)
+                               {
+                                       Instruction *dot = emit(dpOpcode, result, 0, left, 0, right, i);
+                                       dot->dst.mask = 1 << i;
+                               }
+                       }
+                       break;
+               case EOpMatrixTimesVector:
+                       if(visit == PostVisit)
+                       {
+                               Instruction *mul = emit(sw::Shader::OPCODE_MUL, result, left, right);
+                               mul->src[1].swizzle = 0x00;
+
+                               int size = rightType.getNominalSize();
+                               for(int i = 1; i < size; i++)
+                               {
+                                       Instruction *mad = emit(sw::Shader::OPCODE_MAD, result, 0, left, i, right, 0, result);
+                                       mad->src[1].swizzle = i * 0x55;
+                               }
+                       }
+                       break;
+               case EOpMatrixTimesMatrix:
+                       if(visit == PostVisit)
+                       {
+                               int dim = leftType.getNominalSize();
+
+                               int size = rightType.getNominalSize();
+                               for(int i = 0; i < size; i++)
+                               {
+                                       Instruction *mul = emit(sw::Shader::OPCODE_MUL, result, i, left, 0, right, i);
+                                       mul->src[1].swizzle = 0x00;
+
+                                       for(int j = 1; j < dim; j++)
+                                       {
+                                               Instruction *mad = emit(sw::Shader::OPCODE_MAD, result, i, left, j, right, i, result, i);
+                                               mad->src[1].swizzle = j * 0x55;
+                                       }
+                               }
+                       }
+                       break;
+               case EOpLogicalOr:
+                       if(trivial(right, 6))
+                       {
+                               if(visit == PostVisit)
+                               {
+                                       emit(sw::Shader::OPCODE_OR, result, left, right);
+                               }
+                       }
+                       else   // Short-circuit evaluation
+                       {
+                               if(visit == InVisit)
+                               {
+                                       emit(sw::Shader::OPCODE_MOV, result, left);
+                                       Instruction *ifnot = emit(sw::Shader::OPCODE_IF, 0, result);
+                                       ifnot->src[0].modifier = sw::Shader::MODIFIER_NOT;
+                               }
+                               else if(visit == PostVisit)
+                               {
+                                       emit(sw::Shader::OPCODE_MOV, result, right);
+                                       emit(sw::Shader::OPCODE_ENDIF);
+                               }
+                       }
+                       break;
+               case EOpLogicalXor:        if(visit == PostVisit) emit(sw::Shader::OPCODE_XOR, result, left, right); break;
+               case EOpLogicalAnd:
+                       if(trivial(right, 6))
+                       {
+                               if(visit == PostVisit)
+                               {
+                                       emit(sw::Shader::OPCODE_AND, result, left, right);
+                               }
+                       }
+                       else   // Short-circuit evaluation
+                       {
+                               if(visit == InVisit)
+                               {
+                                       emit(sw::Shader::OPCODE_MOV, result, left);
+                                       emit(sw::Shader::OPCODE_IF, 0, result);
+                               }
+                               else if(visit == PostVisit)
+                               {
+                                       emit(sw::Shader::OPCODE_MOV, result, right);
+                                       emit(sw::Shader::OPCODE_ENDIF);
+                               }
+                       }
+                       break;
+               default: UNREACHABLE(node->getOp());
+               }
+
+               return true;
+       }
+
+       void OutputASM::emitDeterminant(TIntermTyped *result, TIntermTyped *arg, int size, int col, int row, int outCol, int outRow)
+       {
+               switch(size)
+               {
+               case 1: // Used for cofactor computation only
+                       {
+                               // For a 2x2 matrix, the cofactor is simply a transposed move or negate
+                               bool isMov = (row == col);
+                               sw::Shader::Opcode op = isMov ? sw::Shader::OPCODE_MOV : sw::Shader::OPCODE_NEG;
+                               Instruction *mov = emit(op, result, outCol, arg, isMov ? 1 - row : row);
+                               mov->src[0].swizzle = 0x55 * (isMov ? 1 - col : col);
+                               mov->dst.mask = 1 << outRow;
+                       }
+                       break;
+               case 2:
+                       {
+                               static const unsigned int swizzle[3] = { 0x99, 0x88, 0x44 }; // xy?? : yzyz, xzxz, xyxy
+
+                               bool isCofactor = (col >= 0) && (row >= 0);
+                               int col0 = (isCofactor && (col <= 0)) ? 1 : 0;
+                               int col1 = (isCofactor && (col <= 1)) ? 2 : 1;
+                               bool negate = isCofactor && ((col & 0x01) ^ (row & 0x01));
+
+                               Instruction *det = emit(sw::Shader::OPCODE_DET2, result, outCol, arg, negate ? col1 : col0, arg, negate ? col0 : col1);
+                               det->src[0].swizzle = det->src[1].swizzle = swizzle[isCofactor ? row : 2];
+                               det->dst.mask = 1 << outRow;
+                       }
+                       break;
+               case 3:
+                       {
+                               static const unsigned int swizzle[4] = { 0xF9, 0xF8, 0xF4, 0xE4 }; // xyz? : yzww, xzww, xyww, xyzw
+
+                               bool isCofactor = (col >= 0) && (row >= 0);
+                               int col0 = (isCofactor && (col <= 0)) ? 1 : 0;
+                               int col1 = (isCofactor && (col <= 1)) ? 2 : 1;
+                               int col2 = (isCofactor && (col <= 2)) ? 3 : 2;
+                               bool negate = isCofactor && ((col & 0x01) ^ (row & 0x01));
+
+                               Instruction *det = emit(sw::Shader::OPCODE_DET3, result, outCol, arg, col0, arg, negate ? col2 : col1, arg, negate ? col1 : col2);
+                               det->src[0].swizzle = det->src[1].swizzle = det->src[2].swizzle = swizzle[isCofactor ? row : 3];
+                               det->dst.mask = 1 << outRow;
+                       }
+                       break;
+               case 4:
+                       {
+                               Instruction *det = emit(sw::Shader::OPCODE_DET4, result, outCol, arg, 0, arg, 1, arg, 2, arg, 3);
+                               det->dst.mask = 1 << outRow;
+                       }
+                       break;
+               default:
+                       UNREACHABLE(size);
+                       break;
+               }
+       }
+
+       bool OutputASM::visitUnary(Visit visit, TIntermUnary *node)
+       {
+               if(currentScope != emitScope)
+               {
+                       return false;
+               }
+
+               TIntermTyped *result = node;
+               TIntermTyped *arg = node->getOperand();
+               TBasicType basicType = arg->getType().getBasicType();
+
+               union
+               {
+                       float f;
+                       int i;
+               } one_value;
+
+               if(basicType == EbtInt || basicType == EbtUInt)
+               {
+                       one_value.i = 1;
+               }
+               else
+               {
+                       one_value.f = 1.0f;
+               }
+
+               Constant one(one_value.f, one_value.f, one_value.f, one_value.f);
+               Constant rad(1.74532925e-2f, 1.74532925e-2f, 1.74532925e-2f, 1.74532925e-2f);
+               Constant deg(5.72957795e+1f, 5.72957795e+1f, 5.72957795e+1f, 5.72957795e+1f);
+
+               switch(node->getOp())
+               {
+               case EOpNegative:
+                       if(visit == PostVisit)
+                       {
+                               sw::Shader::Opcode negOpcode = getOpcode(sw::Shader::OPCODE_NEG, arg);
+                               for(int index = 0; index < arg->totalRegisterCount(); index++)
+                               {
+                                       emit(negOpcode, result, index, arg, index);
+                               }
+                       }
+                       break;
+               case EOpVectorLogicalNot: if(visit == PostVisit) emit(sw::Shader::OPCODE_NOT, result, arg); break;
+               case EOpLogicalNot:       if(visit == PostVisit) emit(sw::Shader::OPCODE_NOT, result, arg); break;
+               case EOpPostIncrement:
+                       if(visit == PostVisit)
+                       {
+                               copy(result, arg);
+
+                               sw::Shader::Opcode addOpcode = getOpcode(sw::Shader::OPCODE_ADD, arg);
+                               for(int index = 0; index < arg->totalRegisterCount(); index++)
+                               {
+                                       emit(addOpcode, arg, index, arg, index, &one);
+                               }
+
+                               assignLvalue(arg, arg);
+                       }
+                       break;
+               case EOpPostDecrement:
+                       if(visit == PostVisit)
+                       {
+                               copy(result, arg);
+
+                               sw::Shader::Opcode subOpcode = getOpcode(sw::Shader::OPCODE_SUB, arg);
+                               for(int index = 0; index < arg->totalRegisterCount(); index++)
+                               {
+                                       emit(subOpcode, arg, index, arg, index, &one);
+                               }
+
+                               assignLvalue(arg, arg);
+                       }
+                       break;
+               case EOpPreIncrement:
+                       if(visit == PostVisit)
+                       {
+                               sw::Shader::Opcode addOpcode = getOpcode(sw::Shader::OPCODE_ADD, arg);
+                               for(int index = 0; index < arg->totalRegisterCount(); index++)
+                               {
+                                       emit(addOpcode, result, index, arg, index, &one);
+                               }
+
+                               assignLvalue(arg, result);
+                       }
+                       break;
+               case EOpPreDecrement:
+                       if(visit == PostVisit)
+                       {
+                               sw::Shader::Opcode subOpcode = getOpcode(sw::Shader::OPCODE_SUB, arg);
+                               for(int index = 0; index < arg->totalRegisterCount(); index++)
+                               {
+                                       emit(subOpcode, result, index, arg, index, &one);
+                               }
+
+                               assignLvalue(arg, result);
+                       }
+                       break;
+               case EOpRadians:          if(visit == PostVisit) emit(sw::Shader::OPCODE_MUL, result, arg, &rad); break;
+               case EOpDegrees:          if(visit == PostVisit) emit(sw::Shader::OPCODE_MUL, result, arg, &deg); break;
+               case EOpSin:              if(visit == PostVisit) emit(sw::Shader::OPCODE_SIN, result, arg); break;
+               case EOpCos:              if(visit == PostVisit) emit(sw::Shader::OPCODE_COS, result, arg); break;
+               case EOpTan:              if(visit == PostVisit) emit(sw::Shader::OPCODE_TAN, result, arg); break;
+               case EOpAsin:             if(visit == PostVisit) emit(sw::Shader::OPCODE_ASIN, result, arg); break;
+               case EOpAcos:             if(visit == PostVisit) emit(sw::Shader::OPCODE_ACOS, result, arg); break;
+               case EOpAtan:             if(visit == PostVisit) emit(sw::Shader::OPCODE_ATAN, result, arg); break;
+               case EOpSinh:             if(visit == PostVisit) emit(sw::Shader::OPCODE_SINH, result, arg); break;
+               case EOpCosh:             if(visit == PostVisit) emit(sw::Shader::OPCODE_COSH, result, arg); break;
+               case EOpTanh:             if(visit == PostVisit) emit(sw::Shader::OPCODE_TANH, result, arg); break;
+               case EOpAsinh:            if(visit == PostVisit) emit(sw::Shader::OPCODE_ASINH, result, arg); break;
+               case EOpAcosh:            if(visit == PostVisit) emit(sw::Shader::OPCODE_ACOSH, result, arg); break;
+               case EOpAtanh:            if(visit == PostVisit) emit(sw::Shader::OPCODE_ATANH, result, arg); break;
+               case EOpExp:              if(visit == PostVisit) emit(sw::Shader::OPCODE_EXP, result, arg); break;
+               case EOpLog:              if(visit == PostVisit) emit(sw::Shader::OPCODE_LOG, result, arg); break;
+               case EOpExp2:             if(visit == PostVisit) emit(sw::Shader::OPCODE_EXP2, result, arg); break;
+               case EOpLog2:             if(visit == PostVisit) emit(sw::Shader::OPCODE_LOG2, result, arg); break;
+               case EOpSqrt:             if(visit == PostVisit) emit(sw::Shader::OPCODE_SQRT, result, arg); break;
+               case EOpInverseSqrt:      if(visit == PostVisit) emit(sw::Shader::OPCODE_RSQ, result, arg); break;
+               case EOpAbs:              if(visit == PostVisit) emit(getOpcode(sw::Shader::OPCODE_ABS, result), result, arg); break;
+               case EOpSign:             if(visit == PostVisit) emit(getOpcode(sw::Shader::OPCODE_SGN, result), result, arg); break;
+               case EOpFloor:            if(visit == PostVisit) emit(sw::Shader::OPCODE_FLOOR, result, arg); break;
+               case EOpTrunc:            if(visit == PostVisit) emit(sw::Shader::OPCODE_TRUNC, result, arg); break;
+               case EOpRound:            if(visit == PostVisit) emit(sw::Shader::OPCODE_ROUND, result, arg); break;
+               case EOpRoundEven:        if(visit == PostVisit) emit(sw::Shader::OPCODE_ROUNDEVEN, result, arg); break;
+               case EOpCeil:             if(visit == PostVisit) emit(sw::Shader::OPCODE_CEIL, result, arg, result); break;
+               case EOpFract:            if(visit == PostVisit) emit(sw::Shader::OPCODE_FRC, result, arg); break;
+               case EOpIsNan:            if(visit == PostVisit) emit(sw::Shader::OPCODE_ISNAN, result, arg); break;
+               case EOpIsInf:            if(visit == PostVisit) emit(sw::Shader::OPCODE_ISINF, result, arg); break;
+               case EOpLength:           if(visit == PostVisit) emit(sw::Shader::OPCODE_LEN(dim(arg)), result, arg); break;
+               case EOpNormalize:        if(visit == PostVisit) emit(sw::Shader::OPCODE_NRM(dim(arg)), result, arg); break;
+               case EOpDFdx:             if(visit == PostVisit) emit(sw::Shader::OPCODE_DFDX, result, arg); break;
+               case EOpDFdy:             if(visit == PostVisit) emit(sw::Shader::OPCODE_DFDY, result, arg); break;
+               case EOpFwidth:           if(visit == PostVisit) emit(sw::Shader::OPCODE_FWIDTH, result, arg); break;
+               case EOpAny:              if(visit == PostVisit) emit(sw::Shader::OPCODE_ANY, result, arg); break;
+               case EOpAll:              if(visit == PostVisit) emit(sw::Shader::OPCODE_ALL, result, arg); break;
+               case EOpFloatBitsToInt:   if(visit == PostVisit) emit(sw::Shader::OPCODE_FLOATBITSTOINT, result, arg); break;
+               case EOpFloatBitsToUint:  if(visit == PostVisit) emit(sw::Shader::OPCODE_FLOATBITSTOUINT, result, arg); break;
+               case EOpIntBitsToFloat:   if(visit == PostVisit) emit(sw::Shader::OPCODE_INTBITSTOFLOAT, result, arg); break;
+               case EOpUintBitsToFloat:  if(visit == PostVisit) emit(sw::Shader::OPCODE_UINTBITSTOFLOAT, result, arg); break;
+               case EOpPackSnorm2x16:    if(visit == PostVisit) emit(sw::Shader::OPCODE_PACKSNORM2x16, result, arg); break;
+               case EOpPackUnorm2x16:    if(visit == PostVisit) emit(sw::Shader::OPCODE_PACKUNORM2x16, result, arg); break;
+               case EOpPackHalf2x16:     if(visit == PostVisit) emit(sw::Shader::OPCODE_PACKHALF2x16, result, arg); break;
+               case EOpUnpackSnorm2x16:  if(visit == PostVisit) emit(sw::Shader::OPCODE_UNPACKSNORM2x16, result, arg); break;
+               case EOpUnpackUnorm2x16:  if(visit == PostVisit) emit(sw::Shader::OPCODE_UNPACKUNORM2x16, result, arg); break;
+               case EOpUnpackHalf2x16:   if(visit == PostVisit) emit(sw::Shader::OPCODE_UNPACKHALF2x16, result, arg); break;
+               case EOpTranspose:
+                       if(visit == PostVisit)
+                       {
+                               int numCols = arg->getNominalSize();
+                               int numRows = arg->getSecondarySize();
+                               for(int i = 0; i < numCols; ++i)
+                               {
+                                       for(int j = 0; j < numRows; ++j)
+                                       {
+                                               Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, j, arg, i);
+                                               mov->src[0].swizzle = 0x55 * j;
+                                               mov->dst.mask = 1 << i;
+                                       }
+                               }
+                       }
+                       break;
+               case EOpDeterminant:
+                       if(visit == PostVisit)
+                       {
+                               int size = arg->getNominalSize();
+                               ASSERT(size == arg->getSecondarySize());
+
+                               emitDeterminant(result, arg, size);
+                       }
+                       break;
+               case EOpInverse:
+                       if(visit == PostVisit)
+                       {
+                               int size = arg->getNominalSize();
+                               ASSERT(size == arg->getSecondarySize());
+
+                               // Compute transposed matrix of cofactors
+                               for(int i = 0; i < size; ++i)
+                               {
+                                       for(int j = 0; j < size; ++j)
+                                       {
+                                               // For a 2x2 matrix, the cofactor is simply a transposed move or negate
+                                               // For a 3x3 or 4x4 matrix, the cofactor is a transposed determinant
+                                               emitDeterminant(result, arg, size - 1, j, i, i, j);
+                                       }
+                               }
+
+                               // Compute 1 / determinant
+                               Temporary invDet(this);
+                               emitDeterminant(&invDet, arg, size);
+                               Constant one(1.0f, 1.0f, 1.0f, 1.0f);
+                               Instruction *div = emit(sw::Shader::OPCODE_DIV, &invDet, &one, &invDet);
+                               div->src[1].swizzle = 0x00; // xxxx
+
+                               // Divide transposed matrix of cofactors by determinant
+                               for(int i = 0; i < size; ++i)
+                               {
+                                       emit(sw::Shader::OPCODE_MUL, result, i, result, i, &invDet);
+                               }
+                       }
+                       break;
+               default: UNREACHABLE(node->getOp());
+               }
+
+               return true;
+       }
+
+       bool OutputASM::visitAggregate(Visit visit, TIntermAggregate *node)
+       {
+               if(currentScope != emitScope && node->getOp() != EOpFunction && node->getOp() != EOpSequence)
+               {
+                       return false;
+               }
+
+               Constant zero(0.0f, 0.0f, 0.0f, 0.0f);
+
+               TIntermTyped *result = node;
+               const TType &resultType = node->getType();
+               TIntermSequence &arg = node->getSequence();
+               size_t argumentCount = arg.size();
+
+               switch(node->getOp())
+               {
+               case EOpSequence:             break;
+               case EOpDeclaration:          break;
+               case EOpInvariantDeclaration: break;
+               case EOpPrototype:            break;
+               case EOpComma:
+                       if(visit == PostVisit)
+                       {
+                               copy(result, arg[1]);
+                       }
+                       break;
+               case EOpFunction:
+                       if(visit == PreVisit)
+                       {
+                               const TString &name = node->getName();
+
+                               if(emitScope == FUNCTION)
+                               {
+                                       if(functionArray.size() > 1)   // No need for a label when there's only main()
+                                       {
+                                               Instruction *label = emit(sw::Shader::OPCODE_LABEL);
+                                               label->dst.type = sw::Shader::PARAMETER_LABEL;
+
+                                               const Function *function = findFunction(name);
+                                               ASSERT(function);   // Should have been added during global pass
+                                               label->dst.index = function->label;
+                                               currentFunction = function->label;
+                                       }
+                               }
+                               else if(emitScope == GLOBAL)
+                               {
+                                       if(name != "main(")
+                                       {
+                                               TIntermSequence &arguments = node->getSequence()[0]->getAsAggregate()->getSequence();
+                                               functionArray.push_back(Function(functionArray.size(), name, &arguments, node));
+                                       }
+                               }
+                               else UNREACHABLE(emitScope);
+
+                               currentScope = FUNCTION;
+                       }
+                       else if(visit == PostVisit)
+                       {
+                               if(emitScope == FUNCTION)
+                               {
+                                       if(functionArray.size() > 1)   // No need to return when there's only main()
+                                       {
+                                               emit(sw::Shader::OPCODE_RET);
+                                       }
+                               }
+
+                               currentScope = GLOBAL;
+                       }
+                       break;
+               case EOpFunctionCall:
+                       if(visit == PostVisit)
+                       {
+                               if(node->isUserDefined())
+                               {
+                                       const TString &name = node->getName();
+                                       const Function *function = findFunction(name);
+
+                                       if(!function)
+                                       {
+                                               mContext.error(node->getLine(), "function definition not found", name.c_str());
+                                               return false;
+                                       }
+
+                                       TIntermSequence &arguments = *function->arg;
+
+                                       for(size_t i = 0; i < argumentCount; i++)
+                                       {
+                                               TIntermTyped *in = arguments[i]->getAsTyped();
+
+                                               if(in->getQualifier() == EvqIn ||
+                                                  in->getQualifier() == EvqInOut ||
+                                                  in->getQualifier() == EvqConstReadOnly)
+                                               {
+                                                       copy(in, arg[i]);
+                                               }
+                                       }
+
+                                       Instruction *call = emit(sw::Shader::OPCODE_CALL);
+                                       call->dst.type = sw::Shader::PARAMETER_LABEL;
+                                       call->dst.index = function->label;
+
+                                       if(function->ret && function->ret->getType().getBasicType() != EbtVoid)
+                                       {
+                                               copy(result, function->ret);
+                                       }
+
+                                       for(size_t i = 0; i < argumentCount; i++)
+                                       {
+                                               TIntermTyped *argument = arguments[i]->getAsTyped();
+                                               TIntermTyped *out = arg[i]->getAsTyped();
+
+                                               if(argument->getQualifier() == EvqOut ||
+                                                  argument->getQualifier() == EvqInOut)
+                                               {
+                                                       assignLvalue(out, argument);
+                                               }
+                                       }
+                               }
+                               else
+                               {
+                                       const TextureFunction textureFunction(node->getName());
+                                       TIntermTyped *t = arg[1]->getAsTyped();
+
+                                       Temporary coord(this);
+
+                                       if(textureFunction.proj)
+                                       {
+                                               Instruction *rcp = emit(sw::Shader::OPCODE_RCPX, &coord, arg[1]);
+                                               rcp->src[0].swizzle = 0x55 * (t->getNominalSize() - 1);
+                                               rcp->dst.mask = 0x7;
+
+                                               Instruction *mul = emit(sw::Shader::OPCODE_MUL, &coord, arg[1], &coord);
+                                               mul->dst.mask = 0x7;
+                                       }
+                                       else
+                                       {
+                                               emit(sw::Shader::OPCODE_MOV, &coord, arg[1]);
+                                       }
+
+                                       switch(textureFunction.method)
+                                       {
+                                       case TextureFunction::IMPLICIT:
+                                               {
+                                                       TIntermNode* offset = textureFunction.offset ? arg[2] : 0;
+
+                                                       if(argumentCount == 2 || (textureFunction.offset && argumentCount == 3))
+                                                       {
+                                                               emit(textureFunction.offset ? sw::Shader::OPCODE_TEXOFFSET : sw::Shader::OPCODE_TEX,
+                                                                    result, &coord, arg[0], offset);
+                                                       }
+                                                       else if(argumentCount == 3 || (textureFunction.offset && argumentCount == 4))   // bias
+                                                       {
+                                                               Instruction *bias = emit(sw::Shader::OPCODE_MOV, &coord, arg[textureFunction.offset ? 3 : 2]);
+                                                               bias->dst.mask = 0x8;
+
+                                                               Instruction *tex = emit(textureFunction.offset ? sw::Shader::OPCODE_TEXOFFSET : sw::Shader::OPCODE_TEX,
+                                                                                       result, &coord, arg[0], offset); // FIXME: Implement an efficient TEXLDB instruction
+                                                               tex->bias = true;
+                                                       }
+                                                       else UNREACHABLE(argumentCount);
+                                               }
+                                               break;
+                                       case TextureFunction::LOD:
+                                               {
+                                                       Instruction *lod = emit(sw::Shader::OPCODE_MOV, &coord, arg[2]);
+                                                       lod->dst.mask = 0x8;
+
+                                                       emit(textureFunction.offset ? sw::Shader::OPCODE_TEXLDLOFFSET : sw::Shader::OPCODE_TEXLDL,
+                                                            result, &coord, arg[0], textureFunction.offset ? arg[3] : nullptr);
+                                               }
+                                               break;
+                                       case TextureFunction::FETCH:
+                                               {
+                                                       if(argumentCount == 3 || (textureFunction.offset && argumentCount == 4))
+                                                       {
+                                                               Instruction *lod = emit(sw::Shader::OPCODE_MOV, &coord, arg[2]);
+                                                               lod->dst.mask = 0x8;
+
+                                                               TIntermNode *offset = textureFunction.offset ? arg[3] : nullptr;
+
+                                                               emit(textureFunction.offset ? sw::Shader::OPCODE_TEXELFETCHOFFSET : sw::Shader::OPCODE_TEXELFETCH,
+                                                                    result, &coord, arg[0], offset);
+                                                       }
+                                                       else UNREACHABLE(argumentCount);
+                                               }
+                                               break;
+                                       case TextureFunction::GRAD:
+                                               {
+                                                       if(argumentCount == 4 || (textureFunction.offset && argumentCount == 5))
+                                                       {
+                                                               TIntermNode *offset = textureFunction.offset ? arg[4] : nullptr;
+
+                                                               emit(textureFunction.offset ? sw::Shader::OPCODE_TEXGRADOFFSET : sw::Shader::OPCODE_TEXGRAD,
+                                                                    result, &coord, arg[0], arg[2], arg[3], offset);
+                                                       }
+                                                       else UNREACHABLE(argumentCount);
+                                               }
+                                               break;
+                                       case TextureFunction::SIZE:
+                                               emit(sw::Shader::OPCODE_TEXSIZE, result, arg[1], arg[0]);
+                                               break;
+                                       default:
+                                               UNREACHABLE(textureFunction.method);
+                                       }
+                               }
+                       }
+                       break;
+               case EOpParameters:
+                       break;
+               case EOpConstructFloat:
+               case EOpConstructVec2:
+               case EOpConstructVec3:
+               case EOpConstructVec4:
+               case EOpConstructBool:
+               case EOpConstructBVec2:
+               case EOpConstructBVec3:
+               case EOpConstructBVec4:
+               case EOpConstructInt:
+               case EOpConstructIVec2:
+               case EOpConstructIVec3:
+               case EOpConstructIVec4:
+               case EOpConstructUInt:
+               case EOpConstructUVec2:
+               case EOpConstructUVec3:
+               case EOpConstructUVec4:
+                       if(visit == PostVisit)
+                       {
+                               int component = 0;
+                               int arrayMaxIndex = result->isArray() ? result->getArraySize() - 1 : 0;
+                               int arrayComponents = result->getType().getElementSize();
+                               for(size_t i = 0; i < argumentCount; i++)
+                               {
+                                       TIntermTyped *argi = arg[i]->getAsTyped();
+                                       int size = argi->getNominalSize();
+                                       int arrayIndex = std::min(component / arrayComponents, arrayMaxIndex);
+                                       int swizzle = component - (arrayIndex * arrayComponents);
+
+                                       if(!argi->isMatrix())
+                                       {
+                                               Instruction *mov = emitCast(result, arrayIndex, argi, 0);
+                                               mov->dst.mask = (0xF << swizzle) & 0xF;
+                                               mov->src[0].swizzle = readSwizzle(argi, size) << (swizzle * 2);
+
+                                               component += size;
+                                       }
+                                       else   // Matrix
+                                       {
+                                               int column = 0;
+
+                                               while(component < resultType.getNominalSize())
+                                               {
+                                                       Instruction *mov = emitCast(result, arrayIndex, argi, column);
+                                                       mov->dst.mask = (0xF << swizzle) & 0xF;
+                                                       mov->src[0].swizzle = readSwizzle(argi, size) << (swizzle * 2);
+
+                                                       column++;
+                                                       component += size;
+                                               }
+                                       }
+                               }
+                       }
+                       break;
+               case EOpConstructMat2:
+               case EOpConstructMat2x3:
+               case EOpConstructMat2x4:
+               case EOpConstructMat3x2:
+               case EOpConstructMat3:
+               case EOpConstructMat3x4:
+               case EOpConstructMat4x2:
+               case EOpConstructMat4x3:
+               case EOpConstructMat4:
+                       if(visit == PostVisit)
+                       {
+                               TIntermTyped *arg0 = arg[0]->getAsTyped();
+                               const int outCols = result->getNominalSize();
+                               const int outRows = result->getSecondarySize();
+
+                               if(arg0->isScalar() && arg.size() == 1)   // Construct scale matrix
+                               {
+                                       for(int i = 0; i < outCols; i++)
+                                       {
+                                               emit(sw::Shader::OPCODE_MOV, result, i, &zero);
+                                               Instruction *mov = emitCast(result, i, arg0, 0);
+                                               mov->dst.mask = 1 << i;
+                                               ASSERT(mov->src[0].swizzle == 0x00);
+                                       }
+                               }
+                               else if(arg0->isMatrix())
+                               {
+                                       int arraySize = result->isArray() ? result->getArraySize() : 1;
+
+                                       for(int n = 0; n < arraySize; n++)
+                                       {
+                                               TIntermTyped *argi = arg[n]->getAsTyped();
+                                               const int inCols = argi->getNominalSize();
+                                               const int inRows = argi->getSecondarySize();
+
+                                               for(int i = 0; i < outCols; i++)
+                                               {
+                                                       if(i >= inCols || outRows > inRows)
+                                                       {
+                                                               // Initialize to identity matrix
+                                                               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));
+                                                               emitCast(result, i + n * outCols, &col, 0);
+                                                       }
+
+                                                       if(i < inCols)
+                                                       {
+                                                               Instruction *mov = emitCast(result, i + n * outCols, argi, i);
+                                                               mov->dst.mask = 0xF >> (4 - inRows);
+                                                       }
+                                               }
+                                       }
+                               }
+                               else
+                               {
+                                       int column = 0;
+                                       int row = 0;
+
+                                       for(size_t i = 0; i < argumentCount; i++)
+                                       {
+                                               TIntermTyped *argi = arg[i]->getAsTyped();
+                                               int size = argi->getNominalSize();
+                                               int element = 0;
+
+                                               while(element < size)
+                                               {
+                                                       Instruction *mov = emitCast(result, column, argi, 0);
+                                                       mov->dst.mask = (0xF << row) & 0xF;
+                                                       mov->src[0].swizzle = (readSwizzle(argi, size) << (row * 2)) + 0x55 * element;
+
+                                                       int end = row + size - element;
+                                                       column = end >= outRows ? column + 1 : column;
+                                                       element = element + outRows - row;
+                                                       row = end >= outRows ? 0 : end;
+                                               }
+                                       }
+                               }
+                       }
+                       break;
+               case EOpConstructStruct:
+                       if(visit == PostVisit)
+                       {
+                               int offset = 0;
+                               for(size_t i = 0; i < argumentCount; i++)
+                               {
+                                       TIntermTyped *argi = arg[i]->getAsTyped();
+                                       int size = argi->totalRegisterCount();
+
+                                       for(int index = 0; index < size; index++)
+                                       {
+                                               Instruction *mov = emit(sw::Shader::OPCODE_MOV, result, index + offset, argi, index);
+                                               mov->dst.mask = writeMask(result, offset + index);
+                                       }
+
+                                       offset += size;
+                               }
+                       }
+                       break;
+               case EOpLessThan:         if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_LT, result, arg[0], arg[1]); break;
+               case EOpGreaterThan:      if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_GT, result, arg[0], arg[1]); break;
+               case EOpLessThanEqual:    if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_LE, result, arg[0], arg[1]); break;
+               case EOpGreaterThanEqual: if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_GE, result, arg[0], arg[1]); break;
+               case EOpVectorEqual:      if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_EQ, result, arg[0], arg[1]); break;
+               case EOpVectorNotEqual:   if(visit == PostVisit) emitCmp(sw::Shader::CONTROL_NE, result, arg[0], arg[1]); break;
+               case EOpMod:              if(visit == PostVisit) emit(sw::Shader::OPCODE_MOD, result, arg[0], arg[1]); break;
+               case EOpModf:
+                       if(visit == PostVisit)
+                       {
+                               TIntermTyped* arg1 = arg[1]->getAsTyped();
+                               emit(sw::Shader::OPCODE_TRUNC, arg1, arg[0]);
+                               assignLvalue(arg1, arg1);
+                               emitBinary(sw::Shader::OPCODE_SUB, result, arg[0], arg1);
+                       }
+                       break;
+               case EOpPow:              if(visit == PostVisit) emit(sw::Shader::OPCODE_POW, result, arg[0], arg[1]); break;
+               case EOpAtan:             if(visit == PostVisit) emit(sw::Shader::OPCODE_ATAN2, result, arg[0], arg[1]); break;
+               case EOpMin:              if(visit == PostVisit) emit(getOpcode(sw::Shader::OPCODE_MIN, result), result, arg[0], arg[1]); break;
+               case EOpMax:              if(visit == PostVisit) emit(getOpcode(sw::Shader::OPCODE_MAX, result), result, arg[0], arg[1]); break;
+               case EOpClamp:
+                       if(visit == PostVisit)
+                       {
+                               emit(getOpcode(sw::Shader::OPCODE_MAX, result), result, arg[0], arg[1]);
+                               emit(getOpcode(sw::Shader::OPCODE_MIN, result), result, result, arg[2]);
+                       }
+                       break;
+               case EOpMix:         if(visit == PostVisit) emit(sw::Shader::OPCODE_LRP, result, arg[2], arg[1], arg[0]); break;
+               case EOpStep:        if(visit == PostVisit) emit(sw::Shader::OPCODE_STEP, result, arg[0], arg[1]); break;
+               case EOpSmoothStep:  if(visit == PostVisit) emit(sw::Shader::OPCODE_SMOOTH, result, arg[0], arg[1], arg[2]); break;
+               case EOpDistance:    if(visit == PostVisit) emit(sw::Shader::OPCODE_DIST(dim(arg[0])), result, arg[0], arg[1]); break;
+               case EOpDot:         if(visit == PostVisit) emit(sw::Shader::OPCODE_DP(dim(arg[0])), result, arg[0], arg[1]); break;
+               case EOpCross:       if(visit == PostVisit) emit(sw::Shader::OPCODE_CRS, result, arg[0], arg[1]); break;
+               case EOpFaceForward: if(visit == PostVisit) emit(sw::Shader::OPCODE_FORWARD(dim(arg[0])), result, arg[0], arg[1], arg[2]); break;
+               case EOpReflect:     if(visit == PostVisit) emit(sw::Shader::OPCODE_REFLECT(dim(arg[0])), result, arg[0], arg[1]); break;
+               case EOpRefract:     if(visit == PostVisit) emit(sw::Shader::OPCODE_REFRACT(dim(arg[0])), result, arg[0], arg[1], arg[2]); break;
+               case EOpMul:
+                       if(visit == PostVisit)
+                       {
+                               TIntermTyped *arg0 = arg[0]->getAsTyped();
+                               ASSERT((arg0->getNominalSize() == arg[1]->getAsTyped()->getNominalSize()) &&
+                                      (arg0->getSecondarySize() == arg[1]->getAsTyped()->getSecondarySize()));
+
+                               int size = arg0->getNominalSize();
+                               for(int i = 0; i < size; i++)
+                               {
+                                       emit(sw::Shader::OPCODE_MUL, result, i, arg[0], i, arg[1], i);
+                               }
+                       }
+                       break;
+               case EOpOuterProduct:
+                       if(visit == PostVisit)
+                       {
+                               for(int i = 0; i < dim(arg[1]); i++)
+                               {
+                                       Instruction *mul = emit(sw::Shader::OPCODE_MUL, result, i, arg[0], 0, arg[1]);
+                                       mul->src[1].swizzle = 0x55 * i;
+                               }
+                       }
+                       break;
+               default: UNREACHABLE(node->getOp());
+               }
+
+               return true;
+       }
+
+       bool OutputASM::visitSelection(Visit visit, TIntermSelection *node)
+       {
+               if(currentScope != emitScope)
+               {
+                       return false;
+               }
+
+               TIntermTyped *condition = node->getCondition();
+               TIntermNode *trueBlock = node->getTrueBlock();
+               TIntermNode *falseBlock = node->getFalseBlock();
+               TIntermConstantUnion *constantCondition = condition->getAsConstantUnion();
+
+               condition->traverse(this);
+
+               if(node->usesTernaryOperator())
+               {
+                       if(constantCondition)
+                       {
+                               bool trueCondition = constantCondition->getUnionArrayPointer()->getBConst();
+
+                               if(trueCondition)
+                               {
+                                       trueBlock->traverse(this);
+                                       copy(node, trueBlock);
+                               }
+                               else
+                               {
+                                       falseBlock->traverse(this);
+                                       copy(node, falseBlock);
+                               }
+                       }
+                       else if(trivial(node, 6))   // Fast to compute both potential results and no side effects
+                       {
+                               trueBlock->traverse(this);
+                               falseBlock->traverse(this);
+                               emit(sw::Shader::OPCODE_SELECT, node, condition, trueBlock, falseBlock);
+                       }
+                       else
+                       {
+                               emit(sw::Shader::OPCODE_IF, 0, condition);
+
+                               if(trueBlock)
+                               {
+                                       trueBlock->traverse(this);
+                                       copy(node, trueBlock);
+                               }
+
+                               if(falseBlock)
+                               {
+                                       emit(sw::Shader::OPCODE_ELSE);
+                                       falseBlock->traverse(this);
+                                       copy(node, falseBlock);
+                               }
+
+                               emit(sw::Shader::OPCODE_ENDIF);
+                       }
+               }
+               else  // if/else statement
+               {
+                       if(constantCondition)
+                       {
+                               bool trueCondition = constantCondition->getUnionArrayPointer()->getBConst();
+
+                               if(trueCondition)
+                               {
+                                       if(trueBlock)
+                                       {
+                                               trueBlock->traverse(this);
+                                       }
+                               }
+                               else
+                               {
+                                       if(falseBlock)
+                                       {
+                                               falseBlock->traverse(this);
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               emit(sw::Shader::OPCODE_IF, 0, condition);
+
+                               if(trueBlock)
+                               {
+                                       trueBlock->traverse(this);
+                               }
+
+                               if(falseBlock)
+                               {
+                                       emit(sw::Shader::OPCODE_ELSE);
+                                       falseBlock->traverse(this);
+                               }
+
+                               emit(sw::Shader::OPCODE_ENDIF);
+                       }
+               }
+
+               return false;
+       }
+
+       bool OutputASM::visitLoop(Visit visit, TIntermLoop *node)
+       {
+               if(currentScope != emitScope)
+               {
+                       return false;
+               }
+
+               unsigned int iterations = loopCount(node);
+
+               if(iterations == 0)
+               {
+                       return false;
+               }
+
+               bool unroll = (iterations <= 4);
+
+               if(unroll)
+               {
+                       LoopUnrollable loopUnrollable;
+                       unroll = loopUnrollable.traverse(node);
+               }
+
+               TIntermNode *init = node->getInit();
+               TIntermTyped *condition = node->getCondition();
+               TIntermTyped *expression = node->getExpression();
+               TIntermNode *body = node->getBody();
+               Constant True(true);
+
+               if(node->getType() == ELoopDoWhile)
+               {
+                       Temporary iterate(this);
+                       emit(sw::Shader::OPCODE_MOV, &iterate, &True);
+
+                       emit(sw::Shader::OPCODE_WHILE, 0, &iterate);   // FIXME: Implement real do-while
+
+                       if(body)
+                       {
+                               body->traverse(this);
+                       }
+
+                       emit(sw::Shader::OPCODE_TEST);
+
+                       condition->traverse(this);
+                       emit(sw::Shader::OPCODE_MOV, &iterate, condition);
+
+                       emit(sw::Shader::OPCODE_ENDWHILE);
+               }
+               else
+               {
+                       if(init)
+                       {
+                               init->traverse(this);
+                       }
+
+                       if(unroll)
+                       {
+                               for(unsigned int i = 0; i < iterations; i++)
+                               {
+                               //      condition->traverse(this);   // Condition could contain statements, but not in an unrollable loop
+
+                                       if(body)
+                                       {
+                                               body->traverse(this);
+                                       }
+
+                                       if(expression)
+                                       {
+                                               expression->traverse(this);
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               if(condition)
+                               {
+                                       condition->traverse(this);
+                               }
+                               else
+                               {
+                                       condition = &True;
+                               }
+
+                               emit(sw::Shader::OPCODE_WHILE, 0, condition);
+
+                               if(body)
+                               {
+                                       body->traverse(this);
+                               }
+
+                               emit(sw::Shader::OPCODE_TEST);
+
+                               if(expression)
+                               {
+                                       expression->traverse(this);
+                               }
+
+                               if(condition)
+                               {
+                                       condition->traverse(this);
+                               }
+
+                               emit(sw::Shader::OPCODE_ENDWHILE);
+                       }
+               }
+
+               return false;
+       }
+
+       bool OutputASM::visitBranch(Visit visit, TIntermBranch *node)
+       {
+               if(currentScope != emitScope)
+               {
+                       return false;
+               }
+
+               switch(node->getFlowOp())
+               {
+               case EOpKill:      if(visit == PostVisit) emit(sw::Shader::OPCODE_DISCARD);  break;
+               case EOpBreak:     if(visit == PostVisit) emit(sw::Shader::OPCODE_BREAK);    break;
+               case EOpContinue:  if(visit == PostVisit) emit(sw::Shader::OPCODE_CONTINUE); break;
+               case EOpReturn:
+                       if(visit == PostVisit)
+                       {
+                               TIntermTyped *value = node->getExpression();
+
+                               if(value)
+                               {
+                                       copy(functionArray[currentFunction].ret, value);
+                               }
+
+                               emit(sw::Shader::OPCODE_LEAVE);
+                       }
+                       break;
+               default: UNREACHABLE(node->getFlowOp());
+               }
+
+               return true;
+       }
+
+       bool OutputASM::visitSwitch(Visit visit, TIntermSwitch *node)
+       {
+               if(currentScope != emitScope)
+               {
+                       return false;
+               }
+
+               TIntermTyped* switchValue = node->getInit();
+               TIntermAggregate* opList = node->getStatementList();
+
+               if(!switchValue || !opList)
+               {
+                       return false;
+               }
+
+               switchValue->traverse(this);
+
+               emit(sw::Shader::OPCODE_SWITCH);
+
+               TIntermSequence& sequence = opList->getSequence();
+               TIntermSequence::iterator it = sequence.begin();
+               TIntermSequence::iterator defaultIt = sequence.end();
+               int nbCases = 0;
+               for(; it != sequence.end(); ++it)
+               {
+                       TIntermCase* currentCase = (*it)->getAsCaseNode();
+                       if(currentCase)
+                       {
+                               TIntermSequence::iterator caseIt = it;
+
+                               TIntermTyped* condition = currentCase->getCondition();
+                               if(condition) // non default case
+                               {
+                                       if(nbCases != 0)
+                                       {
+                                               emit(sw::Shader::OPCODE_ELSE);
+                                       }
+
+                                       condition->traverse(this);
+                                       Temporary result(this);
+                                       emitBinary(sw::Shader::OPCODE_EQ, &result, switchValue, condition);
+                                       emit(sw::Shader::OPCODE_IF, 0, &result);
+                                       nbCases++;
+
+                                       for(++caseIt; caseIt != sequence.end(); ++caseIt)
+                                       {
+                                               (*caseIt)->traverse(this);
+                                               if((*caseIt)->getAsBranchNode()) // Kill, Break, Continue or Return
+                                               {
+                                                       break;
+                                               }
+                                       }
+                               }
+                               else
+                               {
+                                       defaultIt = it; // The default case might not be the last case, keep it for last
+                               }
+                       }
+               }
+
+               // If there's a default case, traverse it here
+               if(defaultIt != sequence.end())
+               {
+                       emit(sw::Shader::OPCODE_ELSE);
+                       for(++defaultIt; defaultIt != sequence.end(); ++defaultIt)
+                       {
+                               (*defaultIt)->traverse(this);
+                               if((*defaultIt)->getAsBranchNode()) // Kill, Break, Continue or Return
+                               {
+                                       break;
+                               }
+                       }
+               }
+
+               for(int i = 0; i < nbCases; ++i)
+               {
+                       emit(sw::Shader::OPCODE_ENDIF);
+               }
+
+               emit(sw::Shader::OPCODE_ENDSWITCH);
+
+               return false;
+       }
+
+       Instruction *OutputASM::emit(sw::Shader::Opcode op, TIntermTyped *dst, TIntermNode *src0, TIntermNode *src1, TIntermNode *src2, TIntermNode *src3, TIntermNode *src4)
+       {
+               return emit(op, dst, 0, src0, 0, src1, 0, src2, 0, src3, 0, src4, 0);
+       }
+
+       Instruction *OutputASM::emit(sw::Shader::Opcode op, TIntermTyped *dst, int dstIndex, TIntermNode *src0, int index0, TIntermNode *src1, int index1,
+                                    TIntermNode *src2, int index2, TIntermNode *src3, int index3, TIntermNode *src4, int index4)
+       {
+               Instruction *instruction = new Instruction(op);
+
+               if(dst)
+               {
+                       instruction->dst.type = registerType(dst);
+                       instruction->dst.index = registerIndex(dst) + dstIndex;
+                       instruction->dst.mask = writeMask(dst);
+                       instruction->dst.integer = (dst->getBasicType() == EbtInt);
+               }
+
+               argument(instruction->src[0], src0, index0);
+               argument(instruction->src[1], src1, index1);
+               argument(instruction->src[2], src2, index2);
+               argument(instruction->src[3], src3, index3);
+               argument(instruction->src[4], src4, index4);
+
+               shader->append(instruction);
+
+               return instruction;
+       }
+
+       Instruction *OutputASM::emitCast(TIntermTyped *dst, TIntermTyped *src)
+       {
+               return emitCast(dst, 0, src, 0);
+       }
+
+       Instruction *OutputASM::emitCast(TIntermTyped *dst, int dstIndex, TIntermTyped *src, int srcIndex)
+       {
+               switch(src->getBasicType())
+               {
+               case EbtBool:
+                       switch(dst->getBasicType())
+                       {
+                       case EbtInt:   return emit(sw::Shader::OPCODE_B2I, dst, dstIndex, src, srcIndex);
+                       case EbtUInt:  return emit(sw::Shader::OPCODE_B2I, dst, dstIndex, src, srcIndex);
+                       case EbtFloat: return emit(sw::Shader::OPCODE_B2F, dst, dstIndex, src, srcIndex);
+                       default:       break;
+                       }
+                       break;
+               case EbtInt:
+                       switch(dst->getBasicType())
+                       {
+                       case EbtBool:  return emit(sw::Shader::OPCODE_I2B, dst, dstIndex, src, srcIndex);
+                       case EbtFloat: return emit(sw::Shader::OPCODE_I2F, dst, dstIndex, src, srcIndex);
+                       default:       break;
+                       }
+                       break;
+               case EbtUInt:
+                       switch(dst->getBasicType())
+                       {
+                       case EbtBool:  return emit(sw::Shader::OPCODE_I2B, dst, dstIndex, src, srcIndex);
+                       case EbtFloat: return emit(sw::Shader::OPCODE_U2F, dst, dstIndex, src, srcIndex);
+                       default:       break;
+                       }
+                       break;
+               case EbtFloat:
+                       switch(dst->getBasicType())
+                       {
+                       case EbtBool: return emit(sw::Shader::OPCODE_F2B, dst, dstIndex, src, srcIndex);
+                       case EbtInt:  return emit(sw::Shader::OPCODE_F2I, dst, dstIndex, src, srcIndex);
+                       case EbtUInt: return emit(sw::Shader::OPCODE_F2U, dst, dstIndex, src, srcIndex);
+                       default:      break;
+                       }
+                       break;
+               default:
+                       break;
+               }
+
+               ASSERT((src->getBasicType() == dst->getBasicType()) ||
+                     ((src->getBasicType() == EbtInt) && (dst->getBasicType() == EbtUInt)) ||
+                     ((src->getBasicType() == EbtUInt) && (dst->getBasicType() == EbtInt)));
+
+               return emit(sw::Shader::OPCODE_MOV, dst, dstIndex, src, srcIndex);
+       }
+
+       void OutputASM::emitBinary(sw::Shader::Opcode op, TIntermTyped *dst, TIntermNode *src0, TIntermNode *src1, TIntermNode *src2)
+       {
+               for(int index = 0; index < dst->elementRegisterCount(); index++)
+               {
+                       emit(op, dst, index, src0, index, src1, index, src2, index);
+               }
+       }
+
+       void OutputASM::emitAssign(sw::Shader::Opcode op, TIntermTyped *result, TIntermTyped *lhs, TIntermTyped *src0, TIntermTyped *src1)
+       {
+               emitBinary(op, result, src0, src1);
+               assignLvalue(lhs, result);
+       }
+
+       void OutputASM::emitCmp(sw::Shader::Control cmpOp, TIntermTyped *dst, TIntermNode *left, TIntermNode *right, int index)
+       {
+               sw::Shader::Opcode opcode;
+               switch(left->getAsTyped()->getBasicType())
+               {
+               case EbtBool:
+               case EbtInt:
+                       opcode = sw::Shader::OPCODE_ICMP;
+                       break;
+               case EbtUInt:
+                       opcode = sw::Shader::OPCODE_UCMP;
+                       break;
+               default:
+                       opcode = sw::Shader::OPCODE_CMP;
+                       break;
+               }
+
+               Instruction *cmp = emit(opcode, dst, 0, left, index, right, index);
+               cmp->control = cmpOp;
+       }
+
+       int componentCount(const TType &type, int registers)
+       {
+               if(registers == 0)
+               {
+                       return 0;
+               }
+
+               if(type.isArray() && registers >= type.elementRegisterCount())
+               {
+                       int index = registers / type.elementRegisterCount();
+                       registers -= index * type.elementRegisterCount();
+                       return index * type.getElementSize() + componentCount(type, registers);
+               }
+
+               if(type.isStruct() || type.isInterfaceBlock())
+               {
+                       const TFieldList& fields = type.getStruct() ? type.getStruct()->fields() : type.getInterfaceBlock()->fields();
+                       int elements = 0;
+
+                       for(TFieldList::const_iterator field = fields.begin(); field != fields.end(); field++)
+                       {
+                               const TType &fieldType = *((*field)->type());
+
+                               if(fieldType.totalRegisterCount() <= registers)
+                               {
+                                       registers -= fieldType.totalRegisterCount();
+                                       elements += fieldType.getObjectSize();
+                               }
+                               else   // Register within this field
+                               {
+                                       return elements + componentCount(fieldType, registers);
+                               }
+                       }
+               }
+               else if(type.isMatrix())
+               {
+                       return registers * type.registerSize();
+               }
+
+               UNREACHABLE(0);
+               return 0;
+       }
+
+       int registerSize(const TType &type, int registers)
+       {
+               if(registers == 0)
+               {
+                       if(type.isStruct())
+                       {
+                               return registerSize(*((*(type.getStruct()->fields().begin()))->type()), 0);
+                       }
+                       else if(type.isInterfaceBlock())
+                       {
+                               return registerSize(*((*(type.getInterfaceBlock()->fields().begin()))->type()), 0);
+                       }
+
+                       return type.registerSize();
+               }
+
+               if(type.isArray() && registers >= type.elementRegisterCount())
+               {
+                       int index = registers / type.elementRegisterCount();
+                       registers -= index * type.elementRegisterCount();
+                       return registerSize(type, registers);
+               }
+
+               if(type.isStruct() || type.isInterfaceBlock())
+               {
+                       const TFieldList& fields = type.getStruct() ? type.getStruct()->fields() : type.getInterfaceBlock()->fields();
+                       int elements = 0;
+
+                       for(TFieldList::const_iterator field = fields.begin(); field != fields.end(); field++)
+                       {
+                               const TType &fieldType = *((*field)->type());
+
+                               if(fieldType.totalRegisterCount() <= registers)
+                               {
+                                       registers -= fieldType.totalRegisterCount();
+                                       elements += fieldType.getObjectSize();
+                               }
+                               else   // Register within this field
+                               {
+                                       return registerSize(fieldType, registers);
+                               }
+                       }
+               }
+               else if(type.isMatrix())
+               {
+                       return registerSize(type, 0);
+               }
+
+               UNREACHABLE(0);
+               return 0;
+       }
+
+       int OutputASM::getBlockId(TIntermTyped *arg)
+       {
+               if(arg)
+               {
+                       const TType &type = arg->getType();
+                       TInterfaceBlock* block = type.getInterfaceBlock();
+                       if(block && (type.getQualifier() == EvqUniform))
+                       {
+                               // Make sure the uniform block is declared
+                               uniformRegister(arg);
+
+                               const char* blockName = block->name().c_str();
+
+                               // Fetch uniform block index from array of blocks
+                               for(ActiveUniformBlocks::const_iterator it = shaderObject->activeUniformBlocks.begin(); it != shaderObject->activeUniformBlocks.end(); ++it)
+                               {
+                                       if(blockName == it->name)
+                                       {
+                                               return it->blockId;
+                                       }
+                               }
+
+                               ASSERT(false);
+                       }
+               }
+
+               return -1;
+       }
+
+       OutputASM::ArgumentInfo OutputASM::getArgumentInfo(TIntermTyped *arg, int index)
+       {
+               const TType &type = arg->getType();
+               int blockId = getBlockId(arg);
+               ArgumentInfo argumentInfo(BlockMemberInfo::getDefaultBlockInfo(), type, -1, -1);
+               if(blockId != -1)
+               {
+                       argumentInfo.bufferIndex = 0;
+                       for(int i = 0; i < blockId; ++i)
+                       {
+                               int blockArraySize = shaderObject->activeUniformBlocks[i].arraySize;
+                               argumentInfo.bufferIndex += blockArraySize > 0 ? blockArraySize : 1;
+                       }
+
+                       const BlockDefinitionIndexMap& blockDefinition = blockDefinitions[blockId];
+
+                       BlockDefinitionIndexMap::const_iterator itEnd = blockDefinition.end();
+                       BlockDefinitionIndexMap::const_iterator it = itEnd;
+
+                       argumentInfo.clampedIndex = index;
+                       if(type.isInterfaceBlock())
+                       {
+                               // Offset index to the beginning of the selected instance
+                               int blockRegisters = type.elementRegisterCount();
+                               int bufferOffset = argumentInfo.clampedIndex / blockRegisters;
+                               argumentInfo.bufferIndex += bufferOffset;
+                               argumentInfo.clampedIndex -= bufferOffset * blockRegisters;
+                       }
+
+                       int regIndex = registerIndex(arg);
+                       for(int i = regIndex + argumentInfo.clampedIndex; i >= regIndex; --i)
+                       {
+                               it = blockDefinition.find(i);
+                               if(it != itEnd)
+                               {
+                                       argumentInfo.clampedIndex -= (i - regIndex);
+                                       break;
+                               }
+                       }
+                       ASSERT(it != itEnd);
+
+                       argumentInfo.typedMemberInfo = it->second;
+
+                       int registerCount = argumentInfo.typedMemberInfo.type.totalRegisterCount();
+                       argumentInfo.clampedIndex = (argumentInfo.clampedIndex >= registerCount) ? registerCount - 1 : argumentInfo.clampedIndex;
+               }
+               else
+               {
+                       argumentInfo.clampedIndex = (index >= arg->totalRegisterCount()) ? arg->totalRegisterCount() - 1 : index;
+               }
+
+               return argumentInfo;
+       }
+
+       void OutputASM::argument(sw::Shader::SourceParameter &parameter, TIntermNode *argument, int index)
+       {
+               if(argument)
+               {
+                       TIntermTyped *arg = argument->getAsTyped();
+                       Temporary unpackedUniform(this);
+
+                       const TType& srcType = arg->getType();
+                       TInterfaceBlock* srcBlock = srcType.getInterfaceBlock();
+                       if(srcBlock && (srcType.getQualifier() == EvqUniform))
+                       {
+                               const ArgumentInfo argumentInfo = getArgumentInfo(arg, index);
+                               const TType &memberType = argumentInfo.typedMemberInfo.type;
+
+                               if(memberType.getBasicType() == EbtBool)
+                               {
+                                       ASSERT(argumentInfo.clampedIndex < (memberType.isArray() ? memberType.getArraySize() : 1)); // index < arraySize
+
+                                       // Convert the packed bool, which is currently an int, to a true bool
+                                       Instruction *instruction = new Instruction(sw::Shader::OPCODE_I2B);
+                                       instruction->dst.type = sw::Shader::PARAMETER_TEMP;
+                                       instruction->dst.index = registerIndex(&unpackedUniform);
+                                       instruction->src[0].type = sw::Shader::PARAMETER_CONST;
+                                       instruction->src[0].bufferIndex = argumentInfo.bufferIndex;
+                                       instruction->src[0].index = argumentInfo.typedMemberInfo.offset + argumentInfo.clampedIndex * argumentInfo.typedMemberInfo.arrayStride;
+
+                                       shader->append(instruction);
+
+                                       arg = &unpackedUniform;
+                                       index = 0;
+                               }
+                               else if((srcBlock->matrixPacking() == EmpRowMajor) && memberType.isMatrix())
+                               {
+                                       int numCols = memberType.getNominalSize();
+                                       int numRows = memberType.getSecondarySize();
+
+                                       ASSERT(argumentInfo.clampedIndex < (numCols * (memberType.isArray() ? memberType.getArraySize() : 1))); // index < cols * arraySize
+
+                                       unsigned int dstIndex = registerIndex(&unpackedUniform);
+                                       unsigned int srcSwizzle = (argumentInfo.clampedIndex % numCols) * 0x55;
+                                       int arrayIndex = argumentInfo.clampedIndex / numCols;
+                                       int matrixStartOffset = argumentInfo.typedMemberInfo.offset + arrayIndex * argumentInfo.typedMemberInfo.arrayStride;
+
+                                       for(int j = 0; j < numRows; ++j)
+                                       {
+                                               // Transpose the row major matrix
+                                               Instruction *instruction = new Instruction(sw::Shader::OPCODE_MOV);
+                                               instruction->dst.type = sw::Shader::PARAMETER_TEMP;
+                                               instruction->dst.index = dstIndex;
+                                               instruction->dst.mask = 1 << j;
+                                               instruction->src[0].type = sw::Shader::PARAMETER_CONST;
+                                               instruction->src[0].bufferIndex = argumentInfo.bufferIndex;
+                                               instruction->src[0].index = matrixStartOffset + j * argumentInfo.typedMemberInfo.matrixStride;
+                                               instruction->src[0].swizzle = srcSwizzle;
+
+                                               shader->append(instruction);
+                                       }
+
+                                       arg = &unpackedUniform;
+                                       index = 0;
+                               }
+                       }
+
+                       const ArgumentInfo argumentInfo = getArgumentInfo(arg, index);
+                       const TType &type = argumentInfo.typedMemberInfo.type;
+
+                       int size = registerSize(type, argumentInfo.clampedIndex);
+
+                       parameter.type = registerType(arg);
+                       parameter.bufferIndex = argumentInfo.bufferIndex;
+
+                       if(arg->getAsConstantUnion() && arg->getAsConstantUnion()->getUnionArrayPointer())
+                       {
+                               int component = componentCount(type, argumentInfo.clampedIndex);
+                               ConstantUnion *constants = arg->getAsConstantUnion()->getUnionArrayPointer();
+
+                               for(int i = 0; i < 4; i++)
+                               {
+                                       if(size == 1)   // Replicate
+                                       {
+                                               parameter.value[i] = constants[component + 0].getAsFloat();
+                                       }
+                                       else if(i < size)
+                                       {
+                                               parameter.value[i] = constants[component + i].getAsFloat();
+                                       }
+                                       else
+                                       {
+                                               parameter.value[i] = 0.0f;
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               parameter.index = registerIndex(arg) + argumentInfo.clampedIndex;
+
+                               if(parameter.bufferIndex != -1)
+                               {
+                                       int stride = (argumentInfo.typedMemberInfo.matrixStride > 0) ? argumentInfo.typedMemberInfo.matrixStride : argumentInfo.typedMemberInfo.arrayStride;
+                                       parameter.index = argumentInfo.typedMemberInfo.offset + argumentInfo.clampedIndex * stride;
+                               }
+                       }
+
+                       if(!IsSampler(arg->getBasicType()))
+                       {
+                               parameter.swizzle = readSwizzle(arg, size);
+                       }
+               }
+       }
+
+       void OutputASM::copy(TIntermTyped *dst, TIntermNode *src, int offset)
+       {
+               for(int index = 0; index < dst->totalRegisterCount(); index++)
+               {
+                       Instruction *mov = emit(sw::Shader::OPCODE_MOV, dst, index, src, offset + index);
+                       mov->dst.mask = writeMask(dst, index);
+               }
+       }
+
+       int swizzleElement(int swizzle, int index)
+       {
+               return (swizzle >> (index * 2)) & 0x03;
+       }
+
+       int swizzleSwizzle(int leftSwizzle, int rightSwizzle)
+       {
+               return (swizzleElement(leftSwizzle, swizzleElement(rightSwizzle, 0)) << 0) |
+                      (swizzleElement(leftSwizzle, swizzleElement(rightSwizzle, 1)) << 2) |
+                      (swizzleElement(leftSwizzle, swizzleElement(rightSwizzle, 2)) << 4) |
+                      (swizzleElement(leftSwizzle, swizzleElement(rightSwizzle, 3)) << 6);
+       }
+
+       void OutputASM::assignLvalue(TIntermTyped *dst, TIntermTyped *src)
+       {
+               if(src &&
+                       ((src->isVector() && (!dst->isVector() || (src->getNominalSize() != dst->getNominalSize()))) ||
+                        (src->isMatrix() && (!dst->isMatrix() || (src->getNominalSize() != dst->getNominalSize()) || (src->getSecondarySize() != dst->getSecondarySize())))))
+               {
+                       return mContext.error(src->getLine(), "Result type should match the l-value type in compound assignment", src->isVector() ? "vector" : "matrix");
+               }
+
+               TIntermBinary *binary = dst->getAsBinaryNode();
+
+               if(binary && binary->getOp() == EOpIndexIndirect && binary->getLeft()->isVector() && dst->isScalar())
+               {
+                       Instruction *insert = new Instruction(sw::Shader::OPCODE_INSERT);
+
+                       Temporary address(this);
+                       lvalue(insert->dst, address, dst);
+
+                       insert->src[0].type = insert->dst.type;
+                       insert->src[0].index = insert->dst.index;
+                       insert->src[0].rel = insert->dst.rel;
+                       argument(insert->src[1], src);
+                       argument(insert->src[2], binary->getRight());
+
+                       shader->append(insert);
+               }
+               else
+               {
+                       for(int offset = 0; offset < dst->totalRegisterCount(); offset++)
+                       {
+                               Instruction *mov = new Instruction(sw::Shader::OPCODE_MOV);
+
+                               Temporary address(this);
+                               int swizzle = lvalue(mov->dst, address, dst);
+                               mov->dst.index += offset;
+
+                               if(offset > 0)
+                               {
+                                       mov->dst.mask = writeMask(dst, offset);
+                               }
+
+                               argument(mov->src[0], src, offset);
+                               mov->src[0].swizzle = swizzleSwizzle(mov->src[0].swizzle, swizzle);
+
+                               shader->append(mov);
+                       }
+               }
+       }
+
+       int OutputASM::lvalue(sw::Shader::DestinationParameter &dst, Temporary &address, TIntermTyped *node)
+       {
+               TIntermTyped *result = node;
+               TIntermBinary *binary = node->getAsBinaryNode();
+               TIntermSymbol *symbol = node->getAsSymbolNode();
+
+               if(binary)
+               {
+                       TIntermTyped *left = binary->getLeft();
+                       TIntermTyped *right = binary->getRight();
+
+                       int leftSwizzle = lvalue(dst, address, left);   // Resolve the l-value of the left side
+
+                       switch(binary->getOp())
+                       {
+                       case EOpIndexDirect:
+                               {
+                                       int rightIndex = right->getAsConstantUnion()->getIConst(0);
+
+                                       if(left->isRegister())
+                                       {
+                                               int leftMask = dst.mask;
+
+                                               dst.mask = 1;
+                                               while((leftMask & dst.mask) == 0)
+                                               {
+                                                       dst.mask = dst.mask << 1;
+                                               }
+
+                                               int element = swizzleElement(leftSwizzle, rightIndex);
+                                               dst.mask = 1 << element;
+
+                                               return element;
+                                       }
+                                       else if(left->isArray() || left->isMatrix())
+                                       {
+                                               dst.index += rightIndex * result->totalRegisterCount();
+                                               return 0xE4;
+                                       }
+                                       else UNREACHABLE(0);
+                               }
+                               break;
+                       case EOpIndexIndirect:
+                               {
+                                       if(left->isRegister())
+                                       {
+                                               // Requires INSERT instruction (handled by calling function)
+                                       }
+                                       else if(left->isArray() || left->isMatrix())
+                                       {
+                                               int scale = result->totalRegisterCount();
+
+                                               if(dst.rel.type == sw::Shader::PARAMETER_VOID)   // Use the index register as the relative address directly
+                                               {
+                                                       if(left->totalRegisterCount() > 1)
+                                                       {
+                                                               sw::Shader::SourceParameter relativeRegister;
+                                                               argument(relativeRegister, right);
+
+                                                               dst.rel.index = relativeRegister.index;
+                                                               dst.rel.type = relativeRegister.type;
+                                                               dst.rel.scale = scale;
+                                                               dst.rel.deterministic = !(vertexShader && left->getQualifier() == EvqUniform);
+                                                       }
+                                               }
+                                               else if(dst.rel.index != registerIndex(&address))   // Move the previous index register to the address register
+                                               {
+                                                       if(scale == 1)
+                                                       {
+                                                               Constant oldScale((int)dst.rel.scale);
+                                                               Instruction *mad = emit(sw::Shader::OPCODE_IMAD, &address, &address, &oldScale, right);
+                                                               mad->src[0].index = dst.rel.index;
+                                                               mad->src[0].type = dst.rel.type;
+                                                       }
+                                                       else
+                                                       {
+                                                               Constant oldScale((int)dst.rel.scale);
+                                                               Instruction *mul = emit(sw::Shader::OPCODE_IMUL, &address, &address, &oldScale);
+                                                               mul->src[0].index = dst.rel.index;
+                                                               mul->src[0].type = dst.rel.type;
+
+                                                               Constant newScale(scale);
+                                                               emit(sw::Shader::OPCODE_IMAD, &address, right, &newScale, &address);
+                                                       }
+
+                                                       dst.rel.type = sw::Shader::PARAMETER_TEMP;
+                                                       dst.rel.index = registerIndex(&address);
+                                                       dst.rel.scale = 1;
+                                               }
+                                               else   // Just add the new index to the address register
+                                               {
+                                                       if(scale == 1)
+                                                       {
+                                                               emit(sw::Shader::OPCODE_IADD, &address, &address, right);
+                                                       }
+                                                       else
+                                                       {
+                                                               Constant newScale(scale);
+                                                               emit(sw::Shader::OPCODE_IMAD, &address, right, &newScale, &address);
+                                                       }
+                                               }
+                                       }
+                                       else UNREACHABLE(0);
+                               }
+                               break;
+                       case EOpIndexDirectStruct:
+                       case EOpIndexDirectInterfaceBlock:
+                               {
+                                       const TFieldList& fields = (binary->getOp() == EOpIndexDirectStruct) ?
+                                                                  left->getType().getStruct()->fields() :
+                                                                  left->getType().getInterfaceBlock()->fields();
+                                       int index = right->getAsConstantUnion()->getIConst(0);
+                                       int fieldOffset = 0;
+
+                                       for(int i = 0; i < index; i++)
+                                       {
+                                               fieldOffset += fields[i]->type()->totalRegisterCount();
+                                       }
+
+                                       dst.type = registerType(left);
+                                       dst.index += fieldOffset;
+                                       dst.mask = writeMask(result);
+
+                                       return 0xE4;
+                               }
+                               break;
+                       case EOpVectorSwizzle:
+                               {
+                                       ASSERT(left->isRegister());
+
+                                       int leftMask = dst.mask;
+
+                                       int swizzle = 0;
+                                       int rightMask = 0;
+
+                                       TIntermSequence &sequence = right->getAsAggregate()->getSequence();
+
+                                       for(unsigned int i = 0; i < sequence.size(); i++)
+                                       {
+                                               int index = sequence[i]->getAsConstantUnion()->getIConst(0);
+
+                                               int element = swizzleElement(leftSwizzle, index);
+                                               rightMask = rightMask | (1 << element);
+                                               swizzle = swizzle | swizzleElement(leftSwizzle, i) << (element * 2);
+                                       }
+
+                                       dst.mask = leftMask & rightMask;
+
+                                       return swizzle;
+                               }
+                               break;
+                       default:
+                               UNREACHABLE(binary->getOp());   // Not an l-value operator
+                               break;
+                       }
+               }
+               else if(symbol)
+               {
+                       dst.type = registerType(symbol);
+                       dst.index = registerIndex(symbol);
+                       dst.mask = writeMask(symbol);
+                       return 0xE4;
+               }
+
+               return 0xE4;
+       }
+
+       sw::Shader::ParameterType OutputASM::registerType(TIntermTyped *operand)
+       {
+               if(isSamplerRegister(operand))
+               {
+                       return sw::Shader::PARAMETER_SAMPLER;
+               }
+
+               const TQualifier qualifier = operand->getQualifier();
+               if((EvqFragColor == qualifier) || (EvqFragData == qualifier))
+               {
+                       if(((EvqFragData == qualifier) && (EvqFragColor == outputQualifier)) ||
+                          ((EvqFragColor == qualifier) && (EvqFragData == outputQualifier)))
+                       {
+                               mContext.error(operand->getLine(), "static assignment to both gl_FragData and gl_FragColor", "");
+                       }
+                       outputQualifier = qualifier;
+               }
+
+               if(qualifier == EvqConstExpr && (!operand->getAsConstantUnion() || !operand->getAsConstantUnion()->getUnionArrayPointer()))
+               {
+                       return sw::Shader::PARAMETER_TEMP;
+               }
+
+               switch(qualifier)
+               {
+               case EvqTemporary:           return sw::Shader::PARAMETER_TEMP;
+               case EvqGlobal:              return sw::Shader::PARAMETER_TEMP;
+               case EvqConstExpr:           return sw::Shader::PARAMETER_FLOAT4LITERAL;   // All converted to float
+               case EvqAttribute:           return sw::Shader::PARAMETER_INPUT;
+               case EvqVaryingIn:           return sw::Shader::PARAMETER_INPUT;
+               case EvqVaryingOut:          return sw::Shader::PARAMETER_OUTPUT;
+               case EvqVertexIn:            return sw::Shader::PARAMETER_INPUT;
+               case EvqFragmentOut:         return sw::Shader::PARAMETER_COLOROUT;
+               case EvqVertexOut:           return sw::Shader::PARAMETER_OUTPUT;
+               case EvqFragmentIn:          return sw::Shader::PARAMETER_INPUT;
+               case EvqInvariantVaryingIn:  return sw::Shader::PARAMETER_INPUT;    // FIXME: Guarantee invariance at the backend
+               case EvqInvariantVaryingOut: return sw::Shader::PARAMETER_OUTPUT;   // FIXME: Guarantee invariance at the backend
+               case EvqSmooth:              return sw::Shader::PARAMETER_OUTPUT;
+               case EvqFlat:                return sw::Shader::PARAMETER_OUTPUT;
+               case EvqCentroidOut:         return sw::Shader::PARAMETER_OUTPUT;
+               case EvqSmoothIn:            return sw::Shader::PARAMETER_INPUT;
+               case EvqFlatIn:              return sw::Shader::PARAMETER_INPUT;
+               case EvqCentroidIn:          return sw::Shader::PARAMETER_INPUT;
+               case EvqUniform:             return sw::Shader::PARAMETER_CONST;
+               case EvqIn:                  return sw::Shader::PARAMETER_TEMP;
+               case EvqOut:                 return sw::Shader::PARAMETER_TEMP;
+               case EvqInOut:               return sw::Shader::PARAMETER_TEMP;
+               case EvqConstReadOnly:       return sw::Shader::PARAMETER_TEMP;
+               case EvqPosition:            return sw::Shader::PARAMETER_OUTPUT;
+               case EvqPointSize:           return sw::Shader::PARAMETER_OUTPUT;
+               case EvqInstanceID:          return sw::Shader::PARAMETER_MISCTYPE;
+               case EvqVertexID:            return sw::Shader::PARAMETER_MISCTYPE;
+               case EvqFragCoord:           return sw::Shader::PARAMETER_MISCTYPE;
+               case EvqFrontFacing:         return sw::Shader::PARAMETER_MISCTYPE;
+               case EvqPointCoord:          return sw::Shader::PARAMETER_INPUT;
+               case EvqFragColor:           return sw::Shader::PARAMETER_COLOROUT;
+               case EvqFragData:            return sw::Shader::PARAMETER_COLOROUT;
+               case EvqFragDepth:           return sw::Shader::PARAMETER_DEPTHOUT;
+               default: UNREACHABLE(qualifier);
+               }
+
+               return sw::Shader::PARAMETER_VOID;
+       }
+
+       bool OutputASM::hasFlatQualifier(TIntermTyped *operand)
+       {
+               const TQualifier qualifier = operand->getQualifier();
+               return qualifier == EvqFlat || qualifier == EvqFlatOut || qualifier == EvqFlatIn;
+       }
+
+       unsigned int OutputASM::registerIndex(TIntermTyped *operand)
+       {
+               if(isSamplerRegister(operand))
+               {
+                       return samplerRegister(operand);
+               }
+
+               switch(operand->getQualifier())
+               {
+               case EvqTemporary:           return temporaryRegister(operand);
+               case EvqGlobal:              return temporaryRegister(operand);
+               case EvqConstExpr:           return temporaryRegister(operand);   // Unevaluated constant expression
+               case EvqAttribute:           return attributeRegister(operand);
+               case EvqVaryingIn:           return varyingRegister(operand);
+               case EvqVaryingOut:          return varyingRegister(operand);
+               case EvqVertexIn:            return attributeRegister(operand);
+               case EvqFragmentOut:         return fragmentOutputRegister(operand);
+               case EvqVertexOut:           return varyingRegister(operand);
+               case EvqFragmentIn:          return varyingRegister(operand);
+               case EvqInvariantVaryingIn:  return varyingRegister(operand);
+               case EvqInvariantVaryingOut: return varyingRegister(operand);
+               case EvqSmooth:              return varyingRegister(operand);
+               case EvqFlat:                return varyingRegister(operand);
+               case EvqCentroidOut:         return varyingRegister(operand);
+               case EvqSmoothIn:            return varyingRegister(operand);
+               case EvqFlatIn:              return varyingRegister(operand);
+               case EvqCentroidIn:          return varyingRegister(operand);
+               case EvqUniform:             return uniformRegister(operand);
+               case EvqIn:                  return temporaryRegister(operand);
+               case EvqOut:                 return temporaryRegister(operand);
+               case EvqInOut:               return temporaryRegister(operand);
+               case EvqConstReadOnly:       return temporaryRegister(operand);
+               case EvqPosition:            return varyingRegister(operand);
+               case EvqPointSize:           return varyingRegister(operand);
+               case EvqInstanceID:          vertexShader->declareInstanceId(); return sw::Shader::InstanceIDIndex;
+               case EvqVertexID:            vertexShader->declareVertexId(); return sw::Shader::VertexIDIndex;
+               case EvqFragCoord:           pixelShader->declareVPos();  return sw::Shader::VPosIndex;
+               case EvqFrontFacing:         pixelShader->declareVFace(); return sw::Shader::VFaceIndex;
+               case EvqPointCoord:          return varyingRegister(operand);
+               case EvqFragColor:           return 0;
+               case EvqFragData:            return fragmentOutputRegister(operand);
+               case EvqFragDepth:           return 0;
+               default: UNREACHABLE(operand->getQualifier());
+               }
+
+               return 0;
+       }
+
+       int OutputASM::writeMask(TIntermTyped *destination, int index)
+       {
+               if(destination->getQualifier() == EvqPointSize)
+               {
+                       return 0x2;   // Point size stored in the y component
+               }
+
+               return 0xF >> (4 - registerSize(destination->getType(), index));
+       }
+
+       int OutputASM::readSwizzle(TIntermTyped *argument, int size)
+       {
+               if(argument->getQualifier() == EvqPointSize)
+               {
+                       return 0x55;   // Point size stored in the y component
+               }
+
+               static const unsigned char swizzleSize[5] = {0x00, 0x00, 0x54, 0xA4, 0xE4};   // (void), xxxx, xyyy, xyzz, xyzw
+
+               return swizzleSize[size];
+       }
+
+       // Conservatively checks whether an expression is fast to compute and has no side effects
+       bool OutputASM::trivial(TIntermTyped *expression, int budget)
+       {
+               if(!expression->isRegister())
+               {
+                       return false;
+               }
+
+               return cost(expression, budget) >= 0;
+       }
+
+       // Returns the remaining computing budget (if < 0 the expression is too expensive or has side effects)
+       int OutputASM::cost(TIntermNode *expression, int budget)
+       {
+               if(budget < 0)
+               {
+                       return budget;
+               }
+
+               if(expression->getAsSymbolNode())
+               {
+                       return budget;
+               }
+               else if(expression->getAsConstantUnion())
+               {
+                       return budget;
+               }
+               else if(expression->getAsBinaryNode())
+               {
+                       TIntermBinary *binary = expression->getAsBinaryNode();
+
+                       switch(binary->getOp())
+                       {
+                       case EOpVectorSwizzle:
+                       case EOpIndexDirect:
+                       case EOpIndexDirectStruct:
+                       case EOpIndexDirectInterfaceBlock:
+                               return cost(binary->getLeft(), budget - 0);
+                       case EOpAdd:
+                       case EOpSub:
+                       case EOpMul:
+                               return cost(binary->getLeft(), cost(binary->getRight(), budget - 1));
+                       default:
+                               return -1;
+                       }
+               }
+               else if(expression->getAsUnaryNode())
+               {
+                       TIntermUnary *unary = expression->getAsUnaryNode();
+
+                       switch(unary->getOp())
+                       {
+                       case EOpAbs:
+                       case EOpNegative:
+                               return cost(unary->getOperand(), budget - 1);
+                       default:
+                               return -1;
+                       }
+               }
+               else if(expression->getAsSelectionNode())
+               {
+                       TIntermSelection *selection = expression->getAsSelectionNode();
+
+                       if(selection->usesTernaryOperator())
+                       {
+                               TIntermTyped *condition = selection->getCondition();
+                               TIntermNode *trueBlock = selection->getTrueBlock();
+                               TIntermNode *falseBlock = selection->getFalseBlock();
+                               TIntermConstantUnion *constantCondition = condition->getAsConstantUnion();
+
+                               if(constantCondition)
+                               {
+                                       bool trueCondition = constantCondition->getUnionArrayPointer()->getBConst();
+
+                                       if(trueCondition)
+                                       {
+                                               return cost(trueBlock, budget - 0);
+                                       }
+                                       else
+                                       {
+                                               return cost(falseBlock, budget - 0);
+                                       }
+                               }
+                               else
+                               {
+                                       return cost(trueBlock, cost(falseBlock, budget - 2));
+                               }
+                       }
+               }
+
+               return -1;
+       }
+
+       const Function *OutputASM::findFunction(const TString &name)
+       {
+               for(unsigned int f = 0; f < functionArray.size(); f++)
+               {
+                       if(functionArray[f].name == name)
+                       {
+                               return &functionArray[f];
+                       }
+               }
+
+               return 0;
+       }
+
+       int OutputASM::temporaryRegister(TIntermTyped *temporary)
+       {
+               return allocate(temporaries, temporary);
+       }
+
+       int OutputASM::varyingRegister(TIntermTyped *varying)
+       {
+               int var = lookup(varyings, varying);
+
+               if(var == -1)
+               {
+                       var = allocate(varyings, varying);
+                       int componentCount = varying->registerSize();
+                       int registerCount = varying->totalRegisterCount();
+
+                       if(pixelShader)
+                       {
+                               if((var + registerCount) > sw::MAX_FRAGMENT_INPUTS)
+                               {
+                                       mContext.error(varying->getLine(), "Varyings packing failed: Too many varyings", "fragment shader");
+                                       return 0;
+                               }
+
+                               if(varying->getQualifier() == EvqPointCoord)
+                               {
+                                       ASSERT(varying->isRegister());
+                                       pixelShader->setInput(var, componentCount, sw::Shader::Semantic(sw::Shader::USAGE_TEXCOORD, var));
+                               }
+                               else
+                               {
+                                       for(int i = 0; i < varying->totalRegisterCount(); i++)
+                                       {
+                                               bool flat = hasFlatQualifier(varying);
+
+                                               pixelShader->setInput(var + i, componentCount, sw::Shader::Semantic(sw::Shader::USAGE_COLOR, var + i, flat));
+                                       }
+                               }
+                       }
+                       else if(vertexShader)
+                       {
+                               if((var + registerCount) > sw::MAX_VERTEX_OUTPUTS)
+                               {
+                                       mContext.error(varying->getLine(), "Varyings packing failed: Too many varyings", "vertex shader");
+                                       return 0;
+                               }
+
+                               if(varying->getQualifier() == EvqPosition)
+                               {
+                                       ASSERT(varying->isRegister());
+                                       vertexShader->setPositionRegister(var);
+                               }
+                               else if(varying->getQualifier() == EvqPointSize)
+                               {
+                                       ASSERT(varying->isRegister());
+                                       vertexShader->setPointSizeRegister(var);
+                               }
+                               else
+                               {
+                                       // Semantic indexes for user varyings will be assigned during program link to match the pixel shader
+                               }
+                       }
+                       else UNREACHABLE(0);
+
+                       declareVarying(varying, var);
+               }
+
+               return var;
+       }
+
+       void OutputASM::declareVarying(TIntermTyped *varying, int reg)
+       {
+               if(varying->getQualifier() != EvqPointCoord)   // gl_PointCoord does not need linking
+               {
+                       const TType &type = varying->getType();
+                       const char *name = varying->getAsSymbolNode()->getSymbol().c_str();
+                       VaryingList &activeVaryings = shaderObject->varyings;
+
+                       // Check if this varying has been declared before without having a register assigned
+                       for(VaryingList::iterator v = activeVaryings.begin(); v != activeVaryings.end(); v++)
+                       {
+                               if(v->name == name)
+                               {
+                                       if(reg >= 0)
+                                       {
+                                               ASSERT(v->reg < 0 || v->reg == reg);
+                                               v->reg = reg;
+                                       }
+
+                                       return;
+                               }
+                       }
+
+                       activeVaryings.push_back(glsl::Varying(glVariableType(type), name, varying->getArraySize(), reg, 0));
+               }
+       }
+
+       int OutputASM::uniformRegister(TIntermTyped *uniform)
+       {
+               const TType &type = uniform->getType();
+               ASSERT(!IsSampler(type.getBasicType()));
+               TInterfaceBlock *block = type.getAsInterfaceBlock();
+               TIntermSymbol *symbol = uniform->getAsSymbolNode();
+               ASSERT(symbol || block);
+
+               if(symbol || block)
+               {
+                       TInterfaceBlock* parentBlock = type.getInterfaceBlock();
+                       bool isBlockMember = (!block && parentBlock);
+                       int index = isBlockMember ? lookup(uniforms, parentBlock) : lookup(uniforms, uniform);
+
+                       if(index == -1 || isBlockMember)
+                       {
+                               if(index == -1)
+                               {
+                                       index = allocate(uniforms, uniform);
+                               }
+
+                               // Verify if the current uniform is a member of an already declared block
+                               const TString &name = symbol ? symbol->getSymbol() : block->name();
+                               int blockMemberIndex = blockMemberLookup(type, name, index);
+                               if(blockMemberIndex == -1)
+                               {
+                                       declareUniform(type, name, index);
+                               }
+                               else
+                               {
+                                       index = blockMemberIndex;
+                               }
+                       }
+
+                       return index;
+               }
+
+               return 0;
+       }
+
+       int OutputASM::attributeRegister(TIntermTyped *attribute)
+       {
+               ASSERT(!attribute->isArray());
+
+               int index = lookup(attributes, attribute);
+
+               if(index == -1)
+               {
+                       TIntermSymbol *symbol = attribute->getAsSymbolNode();
+                       ASSERT(symbol);
+
+                       if(symbol)
+                       {
+                               index = allocate(attributes, attribute);
+                               const TType &type = attribute->getType();
+                               int registerCount = attribute->totalRegisterCount();
+                               sw::VertexShader::AttribType attribType = sw::VertexShader::ATTRIBTYPE_FLOAT;
+                               switch(type.getBasicType())
+                               {
+                               case EbtInt:
+                                       attribType = sw::VertexShader::ATTRIBTYPE_INT;
+                                       break;
+                               case EbtUInt:
+                                       attribType = sw::VertexShader::ATTRIBTYPE_UINT;
+                                       break;
+                               case EbtFloat:
+                               default:
+                                       break;
+                               }
+
+                               if(vertexShader && (index + registerCount) <= sw::MAX_VERTEX_INPUTS)
+                               {
+                                       for(int i = 0; i < registerCount; i++)
+                                       {
+                                               vertexShader->setInput(index + i, sw::Shader::Semantic(sw::Shader::USAGE_TEXCOORD, index + i, false), attribType);
+                                       }
+                               }
+
+                               ActiveAttributes &activeAttributes = shaderObject->activeAttributes;
+
+                               const char *name = symbol->getSymbol().c_str();
+                               activeAttributes.push_back(Attribute(glVariableType(type), name, type.getArraySize(), type.getLayoutQualifier().location, index));
+                       }
+               }
+
+               return index;
+       }
+
+       int OutputASM::fragmentOutputRegister(TIntermTyped *fragmentOutput)
+       {
+               return allocate(fragmentOutputs, fragmentOutput);
+       }
+
+       int OutputASM::samplerRegister(TIntermTyped *sampler)
+       {
+               const TType &type = sampler->getType();
+               ASSERT(IsSampler(type.getBasicType()) || type.isStruct());   // Structures can contain samplers
+
+               TIntermSymbol *symbol = sampler->getAsSymbolNode();
+               TIntermBinary *binary = sampler->getAsBinaryNode();
+
+               if(symbol)
+               {
+                       switch(type.getQualifier())
+                       {
+                       case EvqUniform:
+                               return samplerRegister(symbol);
+                       case EvqIn:
+                       case EvqConstReadOnly:
+                               // Function arguments are not (uniform) sampler registers
+                               return -1;
+                       default:
+                               UNREACHABLE(type.getQualifier());
+                       }
+               }
+               else if(binary)
+               {
+                       TIntermTyped *left = binary->getLeft();
+                       TIntermTyped *right = binary->getRight();
+                       const TType &leftType = left->getType();
+                       int index = right->getAsConstantUnion() ? right->getAsConstantUnion()->getIConst(0) : 0;
+                       int offset = 0;
+
+                       switch(binary->getOp())
+                       {
+                       case EOpIndexDirect:
+                               ASSERT(left->isArray());
+                               offset = index * leftType.elementRegisterCount();
+                               break;
+                       case EOpIndexDirectStruct:
+                               ASSERT(leftType.isStruct());
+                               {
+                                       const TFieldList &fields = leftType.getStruct()->fields();
+
+                                       for(int i = 0; i < index; i++)
+                                       {
+                                               offset += fields[i]->type()->totalRegisterCount();
+                                       }
+                               }
+                               break;
+                       case EOpIndexIndirect:               // Indirect indexing produces a temporary, not a sampler register
+                               return -1;
+                       case EOpIndexDirectInterfaceBlock:   // Interface blocks can't contain samplers
+                       default:
+                               UNREACHABLE(binary->getOp());
+                               return -1;
+                       }
+
+                       int base = samplerRegister(left);
+
+                       if(base < 0)
+                       {
+                               return -1;
+                       }
+
+                       return base + offset;
+               }
+
+               UNREACHABLE(0);
+               return -1;   // Not a (uniform) sampler register
+       }
+
+       int OutputASM::samplerRegister(TIntermSymbol *sampler)
+       {
+               const TType &type = sampler->getType();
+               ASSERT(IsSampler(type.getBasicType()) || type.isStruct());   // Structures can contain samplers
+
+               int index = lookup(samplers, sampler);
+
+               if(index == -1)
+               {
+                       index = allocate(samplers, sampler);
+
+                       if(sampler->getQualifier() == EvqUniform)
+                       {
+                               const char *name = sampler->getSymbol().c_str();
+                               declareUniform(type, name, index);
+                       }
+               }
+
+               return index;
+       }
+
+       bool OutputASM::isSamplerRegister(TIntermTyped *operand)
+       {
+               return operand && IsSampler(operand->getBasicType()) && samplerRegister(operand) >= 0;
+       }
+
+       int OutputASM::lookup(VariableArray &list, TIntermTyped *variable)
+       {
+               for(unsigned int i = 0; i < list.size(); i++)
+               {
+                       if(list[i] == variable)
+                       {
+                               return i;   // Pointer match
+                       }
+               }
+
+               TIntermSymbol *varSymbol = variable->getAsSymbolNode();
+               TInterfaceBlock *varBlock = variable->getType().getAsInterfaceBlock();
+
+               if(varBlock)
+               {
+                       for(unsigned int i = 0; i < list.size(); i++)
+                       {
+                               if(list[i])
+                               {
+                                       TInterfaceBlock *listBlock = list[i]->getType().getAsInterfaceBlock();
+
+                                       if(listBlock)
+                                       {
+                                               if(listBlock->name() == varBlock->name())
+                                               {
+                                                       ASSERT(listBlock->arraySize() == varBlock->arraySize());
+                                                       ASSERT(listBlock->fields() == varBlock->fields());
+                                                       ASSERT(listBlock->blockStorage() == varBlock->blockStorage());
+                                                       ASSERT(listBlock->matrixPacking() == varBlock->matrixPacking());
+
+                                                       return i;
+                                               }
+                                       }
+                               }
+                       }
+               }
+               else if(varSymbol)
+               {
+                       for(unsigned int i = 0; i < list.size(); i++)
+                       {
+                               if(list[i])
+                               {
+                                       TIntermSymbol *listSymbol = list[i]->getAsSymbolNode();
+
+                                       if(listSymbol)
+                                       {
+                                               if(listSymbol->getId() == varSymbol->getId())
+                                               {
+                                                       ASSERT(listSymbol->getSymbol() == varSymbol->getSymbol());
+                                                       ASSERT(listSymbol->getType() == varSymbol->getType());
+                                                       ASSERT(listSymbol->getQualifier() == varSymbol->getQualifier());
+
+                                                       return i;
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               return -1;
+       }
+
+       int OutputASM::lookup(VariableArray &list, TInterfaceBlock *block)
+       {
+               for(unsigned int i = 0; i < list.size(); i++)
+               {
+                       if(list[i] && (list[i]->getType().getInterfaceBlock() == block))
+                       {
+                               return i;   // Pointer match
+                       }
+               }
+               return -1;
+       }
+
+       int OutputASM::allocate(VariableArray &list, TIntermTyped *variable)
+       {
+               int index = lookup(list, variable);
+
+               if(index == -1)
+               {
+                       unsigned int registerCount = variable->blockRegisterCount();
+
+                       for(unsigned int i = 0; i < list.size(); i++)
+                       {
+                               if(list[i] == 0)
+                               {
+                                       unsigned int j = 1;
+                                       for( ; j < registerCount && (i + j) < list.size(); j++)
+                                       {
+                                               if(list[i + j] != 0)
+                                               {
+                                                       break;
+                                               }
+                                       }
+
+                                       if(j == registerCount)   // Found free slots
+                                       {
+                                               for(unsigned int j = 0; j < registerCount; j++)
+                                               {
+                                                       list[i + j] = variable;
+                                               }
+
+                                               return i;
+                                       }
+                               }
+                       }
+
+                       index = list.size();
+
+                       for(unsigned int i = 0; i < registerCount; i++)
+                       {
+                               list.push_back(variable);
+                       }
+               }
+
+               return index;
+       }
+
+       void OutputASM::free(VariableArray &list, TIntermTyped *variable)
+       {
+               int index = lookup(list, variable);
+
+               if(index >= 0)
+               {
+                       list[index] = 0;
+               }
+       }
+
+       int OutputASM::blockMemberLookup(const TType &type, const TString &name, int registerIndex)
+       {
+               const TInterfaceBlock *block = type.getInterfaceBlock();
+
+               if(block)
+               {
+                       ActiveUniformBlocks &activeUniformBlocks = shaderObject->activeUniformBlocks;
+                       const TFieldList& fields = block->fields();
+                       const TString &blockName = block->name();
+                       int fieldRegisterIndex = registerIndex;
+
+                       if(!type.isInterfaceBlock())
+                       {
+                               // This is a uniform that's part of a block, let's see if the block is already defined
+                               for(size_t i = 0; i < activeUniformBlocks.size(); ++i)
+                               {
+                                       if(activeUniformBlocks[i].name == blockName.c_str())
+                                       {
+                                               // The block is already defined, find the register for the current uniform and return it
+                                               for(size_t j = 0; j < fields.size(); j++)
+                                               {
+                                                       const TString &fieldName = fields[j]->name();
+                                                       if(fieldName == name)
+                                                       {
+                                                               return fieldRegisterIndex;
+                                                       }
+
+                                                       fieldRegisterIndex += fields[j]->type()->totalRegisterCount();
+                                               }
+
+                                               ASSERT(false);
+                                               return fieldRegisterIndex;
+                                       }
+                               }
+                       }
+               }
+
+               return -1;
+       }
+
+       void OutputASM::declareUniform(const TType &type, const TString &name, int registerIndex, int blockId, BlockLayoutEncoder* encoder)
+       {
+               const TStructure *structure = type.getStruct();
+               const TInterfaceBlock *block = (type.isInterfaceBlock() || (blockId == -1)) ? type.getInterfaceBlock() : nullptr;
+
+               if(!structure && !block)
+               {
+                       ActiveUniforms &activeUniforms = shaderObject->activeUniforms;
+                       const BlockMemberInfo blockInfo = encoder ? encoder->encodeType(type) : BlockMemberInfo::getDefaultBlockInfo();
+                       if(blockId >= 0)
+                       {
+                               blockDefinitions[blockId][registerIndex] = TypedMemberInfo(blockInfo, type);
+                               shaderObject->activeUniformBlocks[blockId].fields.push_back(activeUniforms.size());
+                       }
+                       int fieldRegisterIndex = encoder ? shaderObject->activeUniformBlocks[blockId].registerIndex + BlockLayoutEncoder::getBlockRegister(blockInfo) : registerIndex;
+                       activeUniforms.push_back(Uniform(glVariableType(type), glVariablePrecision(type), name.c_str(), type.getArraySize(),
+                                                        fieldRegisterIndex, blockId, blockInfo));
+                       if(IsSampler(type.getBasicType()))
+                       {
+                               for(int i = 0; i < type.totalRegisterCount(); i++)
+                               {
+                                       shader->declareSampler(fieldRegisterIndex + i);
+                               }
+                       }
+               }
+               else if(block)
+               {
+                       ActiveUniformBlocks &activeUniformBlocks = shaderObject->activeUniformBlocks;
+                       const TFieldList& fields = block->fields();
+                       const TString &blockName = block->name();
+                       int fieldRegisterIndex = registerIndex;
+                       bool isUniformBlockMember = !type.isInterfaceBlock() && (blockId == -1);
+
+                       blockId = activeUniformBlocks.size();
+                       bool isRowMajor = block->matrixPacking() == EmpRowMajor;
+                       activeUniformBlocks.push_back(UniformBlock(blockName.c_str(), 0, block->arraySize(),
+                                                                  block->blockStorage(), isRowMajor, registerIndex, blockId));
+                       blockDefinitions.push_back(BlockDefinitionIndexMap());
+
+                       Std140BlockEncoder currentBlockEncoder(isRowMajor);
+                       currentBlockEncoder.enterAggregateType();
+                       for(size_t i = 0; i < fields.size(); i++)
+                       {
+                               const TType &fieldType = *(fields[i]->type());
+                               const TString &fieldName = fields[i]->name();
+                               if(isUniformBlockMember && (fieldName == name))
+                               {
+                                       registerIndex = fieldRegisterIndex;
+                               }
+
+                               const TString uniformName = block->hasInstanceName() ? blockName + "." + fieldName : fieldName;
+
+                               declareUniform(fieldType, uniformName, fieldRegisterIndex, blockId, &currentBlockEncoder);
+                               fieldRegisterIndex += fieldType.totalRegisterCount();
+                       }
+                       currentBlockEncoder.exitAggregateType();
+                       activeUniformBlocks[blockId].dataSize = currentBlockEncoder.getBlockSize();
+               }
+               else
+               {
+                       int fieldRegisterIndex = registerIndex;
+
+                       const TFieldList& fields = structure->fields();
+                       if(type.isArray() && (structure || type.isInterfaceBlock()))
+                       {
+                               for(int i = 0; i < type.getArraySize(); i++)
+                               {
+                                       if(encoder)
+                                       {
+                                               encoder->enterAggregateType();
+                                       }
+                                       for(size_t j = 0; j < fields.size(); j++)
+                                       {
+                                               const TType &fieldType = *(fields[j]->type());
+                                               const TString &fieldName = fields[j]->name();
+                                               const TString uniformName = name + "[" + str(i) + "]." + fieldName;
+
+                                               declareUniform(fieldType, uniformName, fieldRegisterIndex, blockId, encoder);
+                                               fieldRegisterIndex += fieldType.totalRegisterCount();
+                                       }
+                                       if(encoder)
+                                       {
+                                               encoder->exitAggregateType();
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               if(encoder)
+                               {
+                                       encoder->enterAggregateType();
+                               }
+                               for(size_t i = 0; i < fields.size(); i++)
+                               {
+                                       const TType &fieldType = *(fields[i]->type());
+                                       const TString &fieldName = fields[i]->name();
+                                       const TString uniformName = name + "." + fieldName;
+
+                                       declareUniform(fieldType, uniformName, fieldRegisterIndex, blockId, encoder);
+                                       fieldRegisterIndex += fieldType.totalRegisterCount();
+                               }
+                               if(encoder)
+                               {
+                                       encoder->exitAggregateType();
+                               }
+                       }
+               }
+       }
+
+       GLenum OutputASM::glVariableType(const TType &type)
+       {
+               switch(type.getBasicType())
+               {
+               case EbtFloat:
+                       if(type.isScalar())
+                       {
+                               return GL_FLOAT;
+                       }
+                       else if(type.isVector())
+                       {
+                               switch(type.getNominalSize())
+                               {
+                               case 2: return GL_FLOAT_VEC2;
+                               case 3: return GL_FLOAT_VEC3;
+                               case 4: return GL_FLOAT_VEC4;
+                               default: UNREACHABLE(type.getNominalSize());
+                               }
+                       }
+                       else if(type.isMatrix())
+                       {
+                               switch(type.getNominalSize())
+                               {
+                               case 2:
+                                       switch(type.getSecondarySize())
+                                       {
+                                       case 2: return GL_FLOAT_MAT2;
+                                       case 3: return GL_FLOAT_MAT2x3;
+                                       case 4: return GL_FLOAT_MAT2x4;
+                                       default: UNREACHABLE(type.getSecondarySize());
+                                       }
+                               case 3:
+                                       switch(type.getSecondarySize())
+                                       {
+                                       case 2: return GL_FLOAT_MAT3x2;
+                                       case 3: return GL_FLOAT_MAT3;
+                                       case 4: return GL_FLOAT_MAT3x4;
+                                       default: UNREACHABLE(type.getSecondarySize());
+                                       }
+                               case 4:
+                                       switch(type.getSecondarySize())
+                                       {
+                                       case 2: return GL_FLOAT_MAT4x2;
+                                       case 3: return GL_FLOAT_MAT4x3;
+                                       case 4: return GL_FLOAT_MAT4;
+                                       default: UNREACHABLE(type.getSecondarySize());
+                                       }
+                               default: UNREACHABLE(type.getNominalSize());
+                               }
+                       }
+                       else UNREACHABLE(0);
+                       break;
+               case EbtInt:
+                       if(type.isScalar())
+                       {
+                               return GL_INT;
+                       }
+                       else if(type.isVector())
+                       {
+                               switch(type.getNominalSize())
+                               {
+                               case 2: return GL_INT_VEC2;
+                               case 3: return GL_INT_VEC3;
+                               case 4: return GL_INT_VEC4;
+                               default: UNREACHABLE(type.getNominalSize());
+                               }
+                       }
+                       else UNREACHABLE(0);
+                       break;
+               case EbtUInt:
+                       if(type.isScalar())
+                       {
+                               return GL_UNSIGNED_INT;
+                       }
+                       else if(type.isVector())
+                       {
+                               switch(type.getNominalSize())
+                               {
+                               case 2: return GL_UNSIGNED_INT_VEC2;
+                               case 3: return GL_UNSIGNED_INT_VEC3;
+                               case 4: return GL_UNSIGNED_INT_VEC4;
+                               default: UNREACHABLE(type.getNominalSize());
+                               }
+                       }
+                       else UNREACHABLE(0);
+                       break;
+               case EbtBool:
+                       if(type.isScalar())
+                       {
+                               return GL_BOOL;
+                       }
+                       else if(type.isVector())
+                       {
+                               switch(type.getNominalSize())
+                               {
+                               case 2: return GL_BOOL_VEC2;
+                               case 3: return GL_BOOL_VEC3;
+                               case 4: return GL_BOOL_VEC4;
+                               default: UNREACHABLE(type.getNominalSize());
+                               }
+                       }
+                       else UNREACHABLE(0);
+                       break;
+               case EbtSampler2D:
+                       return GL_SAMPLER_2D;
+               case EbtISampler2D:
+                       return GL_INT_SAMPLER_2D;
+               case EbtUSampler2D:
+                       return GL_UNSIGNED_INT_SAMPLER_2D;
+               case EbtSamplerCube:
+                       return GL_SAMPLER_CUBE;
+               case EbtISamplerCube:
+                       return GL_INT_SAMPLER_CUBE;
+               case EbtUSamplerCube:
+                       return GL_UNSIGNED_INT_SAMPLER_CUBE;
+               case EbtSamplerExternalOES:
+                       return GL_SAMPLER_EXTERNAL_OES;
+               case EbtSampler3D:
+                       return GL_SAMPLER_3D_OES;
+               case EbtISampler3D:
+                       return GL_INT_SAMPLER_3D;
+               case EbtUSampler3D:
+                       return GL_UNSIGNED_INT_SAMPLER_3D;
+               case EbtSampler2DArray:
+                       return GL_SAMPLER_2D_ARRAY;
+               case EbtISampler2DArray:
+                       return GL_INT_SAMPLER_2D_ARRAY;
+               case EbtUSampler2DArray:
+                       return GL_UNSIGNED_INT_SAMPLER_2D_ARRAY;
+               case EbtSampler2DShadow:
+                       return GL_SAMPLER_2D_SHADOW;
+               case EbtSamplerCubeShadow:
+                       return GL_SAMPLER_CUBE_SHADOW;
+               case EbtSampler2DArrayShadow:
+                       return GL_SAMPLER_2D_ARRAY_SHADOW;
+               default:
+                       UNREACHABLE(type.getBasicType());
+                       break;
+               }
+
+               return GL_NONE;
+       }
+
+       GLenum OutputASM::glVariablePrecision(const TType &type)
+       {
+               if(type.getBasicType() == EbtFloat)
+               {
+                       switch(type.getPrecision())
+                       {
+                       case EbpHigh:   return GL_HIGH_FLOAT;
+                       case EbpMedium: return GL_MEDIUM_FLOAT;
+                       case EbpLow:    return GL_LOW_FLOAT;
+                       case EbpUndefined:
+                               // Should be defined as the default precision by the parser
+                       default: UNREACHABLE(type.getPrecision());
+                       }
+               }
+               else if(type.getBasicType() == EbtInt)
+               {
+                       switch(type.getPrecision())
+                       {
+                       case EbpHigh:   return GL_HIGH_INT;
+                       case EbpMedium: return GL_MEDIUM_INT;
+                       case EbpLow:    return GL_LOW_INT;
+                       case EbpUndefined:
+                               // Should be defined as the default precision by the parser
+                       default: UNREACHABLE(type.getPrecision());
+                       }
+               }
+
+               // Other types (boolean, sampler) don't have a precision
+               return GL_NONE;
+       }
+
+       int OutputASM::dim(TIntermNode *v)
+       {
+               TIntermTyped *vector = v->getAsTyped();
+               ASSERT(vector && vector->isRegister());
+               return vector->getNominalSize();
+       }
+
+       int OutputASM::dim2(TIntermNode *m)
+       {
+               TIntermTyped *matrix = m->getAsTyped();
+               ASSERT(matrix && matrix->isMatrix() && !matrix->isArray());
+               return matrix->getSecondarySize();
+       }
+
+       // Returns ~0u if no loop count could be determined
+       unsigned int OutputASM::loopCount(TIntermLoop *node)
+       {
+               // Parse loops of the form:
+               // for(int index = initial; index [comparator] limit; index += increment)
+               TIntermSymbol *index = 0;
+               TOperator comparator = EOpNull;
+               int initial = 0;
+               int limit = 0;
+               int increment = 0;
+
+               // Parse index name and intial value
+               if(node->getInit())
+               {
+                       TIntermAggregate *init = node->getInit()->getAsAggregate();
+
+                       if(init)
+                       {
+                               TIntermSequence &sequence = init->getSequence();
+                               TIntermTyped *variable = sequence[0]->getAsTyped();
+
+                               if(variable && variable->getQualifier() == EvqTemporary && variable->getBasicType() == EbtInt)
+                               {
+                                       TIntermBinary *assign = variable->getAsBinaryNode();
+
+                                       if(assign && assign->getOp() == EOpInitialize)
+                                       {
+                                               TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
+                                               TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
+
+                                               if(symbol && constant)
+                                               {
+                                                       if(constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
+                                                       {
+                                                               index = symbol;
+                                                               initial = constant->getUnionArrayPointer()[0].getIConst();
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               // Parse comparator and limit value
+               if(index && node->getCondition())
+               {
+                       TIntermBinary *test = node->getCondition()->getAsBinaryNode();
+                       TIntermSymbol *left = test ? test->getLeft()->getAsSymbolNode() : nullptr;
+
+                       if(left && (left->getId() == index->getId()))
+                       {
+                               TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
+
+                               if(constant)
+                               {
+                                       if(constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
+                                       {
+                                               comparator = test->getOp();
+                                               limit = constant->getUnionArrayPointer()[0].getIConst();
+                                       }
+                               }
+                       }
+               }
+
+               // Parse increment
+               if(index && comparator != EOpNull && node->getExpression())
+               {
+                       TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
+                       TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
+
+                       if(binaryTerminal)
+                       {
+                               TOperator op = binaryTerminal->getOp();
+                               TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
+
+                               if(constant)
+                               {
+                                       if(constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
+                                       {
+                                               int value = constant->getUnionArrayPointer()[0].getIConst();
+
+                                               switch(op)
+                                               {
+                                               case EOpAddAssign: increment = value;  break;
+                                               case EOpSubAssign: increment = -value; break;
+                                               default: UNIMPLEMENTED();
+                                               }
+                                       }
+                               }
+                       }
+                       else if(unaryTerminal)
+                       {
+                               TOperator op = unaryTerminal->getOp();
+
+                               switch(op)
+                               {
+                               case EOpPostIncrement: increment = 1;  break;
+                               case EOpPostDecrement: increment = -1; break;
+                               case EOpPreIncrement:  increment = 1;  break;
+                               case EOpPreDecrement:  increment = -1; break;
+                               default: UNIMPLEMENTED();
+                               }
+                       }
+               }
+
+               if(index && comparator != EOpNull && increment != 0)
+               {
+                       if(comparator == EOpLessThanEqual)
+                       {
+                               comparator = EOpLessThan;
+                               limit += 1;
+                       }
+                       else if(comparator == EOpGreaterThanEqual)
+                       {
+                               comparator = EOpLessThan;
+                               limit -= 1;
+                               std::swap(initial, limit);
+                               increment = -increment;
+                       }
+                       else if(comparator == EOpGreaterThan)
+                       {
+                               comparator = EOpLessThan;
+                               std::swap(initial, limit);
+                               increment = -increment;
+                       }
+
+                       if(comparator == EOpLessThan)
+                       {
+                               if(!(initial < limit))   // Never loops
+                               {
+                                       return 0;
+                               }
+
+                               int iterations = (limit - initial + abs(increment) - 1) / increment;   // Ceiling division
+
+                               if(iterations < 0)
+                               {
+                                       return ~0u;
+                               }
+
+                               return iterations;
+                       }
+                       else UNIMPLEMENTED();   // Falls through
+               }
+
+               return ~0u;
+       }
+
+       bool LoopUnrollable::traverse(TIntermNode *node)
+       {
+               loopDepth = 0;
+               loopUnrollable = true;
+
+               node->traverse(this);
+
+               return loopUnrollable;
+       }
+
+       bool LoopUnrollable::visitLoop(Visit visit, TIntermLoop *loop)
+       {
+               if(visit == PreVisit)
+               {
+                       loopDepth++;
+               }
+               else if(visit == PostVisit)
+               {
+                       loopDepth++;
+               }
+
+               return true;
+       }
+
+       bool LoopUnrollable::visitBranch(Visit visit, TIntermBranch *node)
+       {
+               if(!loopUnrollable)
+               {
+                       return false;
+               }
+
+               if(!loopDepth)
+               {
+                       return true;
+               }
+
+               switch(node->getFlowOp())
+               {
+               case EOpKill:
+               case EOpReturn:
+                       break;
+               case EOpBreak:
+               case EOpContinue:
+                       loopUnrollable = false;
+                       break;
+               default: UNREACHABLE(node->getFlowOp());
+               }
+
+               return loopUnrollable;
+       }
+
+       bool LoopUnrollable::visitAggregate(Visit visit, TIntermAggregate *node)
+       {
+               return loopUnrollable;
+       }
+}