text: // Modifications copyright Amazon.com, Inc. or its affiliates
  // Modifications copyright Crytek GmbH
  
  #include "internal_includes/toGLSLInstruction.h"
  #include "internal_includes/toGLSLOperand.h"
  #include "internal_includes/languages.h"
  #include "bstrlib.h"
  #include "stdio.h"
  #include <stdlib.h>
  #include "internal_includes/debug.h"
  
  #ifndef min
  #define min(a,b)            (((a) < (b)) ? (a) : (b))
  #endif
  
  extern void AddIndentation(HLSLCrossCompilerContext* psContext);
  static int IsIntegerImmediateOpcode(OPCODE_TYPE eOpcode);
  
  // Calculate the bits set in mask
  static int WriteMaskToComponentCount(uint32_t writeMask)
  {
  	uint32_t count;
  	// In HLSL bytecode writemask 0 also means everything
  	if (writeMask == 0)
  		return 4;
  
  	// Count bits set
  	// https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSet64
  	count = (writeMask * 0x200040008001ULL & 0x111111111111111ULL) % 0xf;
  
  	return (int)count;
  }
  
  static uint32_t BuildComponentMaskFromElementCount(int count)
  {
  	// Translate numComponents into bitmask
  	// 1 -> 1, 2 -> 3, 3 -> 7 and 4 -> 15
  	return (1 << count) - 1;
  }
  
  
  // This function prints out the destination name, possible destination writemask, assignment operator
  // and any possible conversions needed based on the eSrcType+ui32SrcElementCount (type and size of data expected to be coming in)
  // As an output, pNeedsParenthesis will be filled with the amount of closing parenthesis needed
  // and pSrcCount will be filled with the number of components expected
  // ui32CompMask can be used to only write to 1 or more components (used by MOVC)
  static void AddOpAssignToDestWithMask(HLSLCrossCompilerContext* psContext, const Operand* psDest,
  	SHADER_VARIABLE_TYPE eSrcType, uint32_t ui32SrcElementCount, const char *szAssignmentOp, int *pNeedsParenthesis, uint32_t ui32CompMask)
  {
  	uint32_t ui32DestElementCount = GetNumSwizzleElementsWithMask(psDest, ui32CompMask);
  	bstring glsl = *psContext->currentShaderString;
  	SHADER_VARIABLE_TYPE eDestDataType = GetOperandDataType(psContext, psDest);
  	ASSERT(pNeedsParenthesis != NULL);
  
  	*pNeedsParenthesis = 0;
  
  	TranslateOperandWithMask(psContext, psDest, TO_FLAG_DESTINATION, ui32CompMask);
  
  	// Simple path: types match.
  	if (eDestDataType == eSrcType)
  	{
  		// Cover cases where the HLSL language expects the rest of the components to be default-filled
  		// eg. MOV r0, c0.x => Temp[0] = vec4(c0.x);
  		if (ui32DestElementCount > ui32SrcElementCount)
  		{
  			bformata(glsl, " %s %s(", szAssignmentOp, GetConstructorForType(eDestDataType, ui32DestElementCount));
  			*pNeedsParenthesis = 1;
  		}
  		else
  			bformata(glsl, " %s ", szAssignmentOp);
  		return;
  	}
  
  	switch (eDestDataType)
  	{
  	case SVT_INT:
  		if (eSrcType == SVT_FLOAT && psContext->psShader->ui32MajorVersion > 3)
  		{
  			bformata(glsl, " %s floatBitsToInt(", szAssignmentOp);
  			// Cover cases where the HLSL language expects the rest of the components to be default-filled
  			if (ui32DestElementCount > ui32SrcElementCount)
  			{
  				bformata(glsl, "%s(", GetConstructorForType(eSrcType, ui32DestElementCount));
  				(*pNeedsParenthesis)++;
  			}
  		}
  		else
  			bformata(glsl, " %s %s(", szAssignmentOp, GetConstructorForType(eDestDataType, ui32DestElementCount));
  		break;
  	case SVT_UINT:
  		if (eSrcType == SVT_FLOAT && psContext->psShader->ui32MajorVersion > 3)
  		{
  			bformata(glsl, " %s floatBitsToUint(", szAssignmentOp);
  			// Cover cases where the HLSL language expects the rest of the components to be default-filled
  			if (ui32DestElementCount > ui32SrcElementCount)
  			{
  				bformata(glsl, "%s(", GetConstructorForType(eSrcType, ui32DestElementCount));
  				(*pNeedsParenthesis)++;
  			}
  		}
  		else
  			bformata(glsl, " %s %s(", szAssignmentOp, GetConstructorForType(eDestDataType, ui32DestElementCount));
  		break;
  
  	case SVT_FLOAT:
  		if (psContext->psShader->ui32MajorVersion > 3)
  		{
  			if (eSrcType == SVT_INT)
  				bformata(glsl, " %s intBitsToFloat(", szAssignmentOp);
  			else
  				bformata(glsl, " %s uintBitsToFloat(", szAssignmentOp);
  			// Cover cases where the HLSL language expects the rest of the components to be default-filled
  			if (ui32DestElementCount > ui32SrcElementCount)
  			{
  				bformata(glsl, "%s(", GetConstructorForType(eSrcType, ui32DestElementCount));
  				(*pNeedsParenthesis)++;
  			}
  
  		}
  		else
  			bformata(glsl, " %s %s(", szAssignmentOp, GetConstructorForType(eDestDataType, ui32DestElementCount));
  		break;
  	default:
  		// TODO: Handle bools?
  		break;
  	}
  	(*pNeedsParenthesis)++;
  	return;
  }
  
  static void AddAssignToDest(HLSLCrossCompilerContext* psContext, const Operand* psDest,
  	SHADER_VARIABLE_TYPE eSrcType, uint32_t ui32SrcElementCount, int* pNeedsParenthesis)
  {
  	AddOpAssignToDestWithMask(psContext, psDest, eSrcType, ui32SrcElementCount, "=", pNeedsParenthesis, OPERAND_4_COMPONENT_MASK_ALL);
  }
  
  static void AddAssignPrologue(HLSLCrossCompilerContext *psContext, int numParenthesis)
  {
  	bstring glsl = *psContext->currentShaderString;
  	while (numParenthesis != 0)
  	{
  		bcatcstr(glsl, ")");
  		numParenthesis--;
  	}
  	bcatcstr(glsl, ";\n");
  
  }
  static uint32_t ResourceReturnTypeToFlag(const RESOURCE_RETURN_TYPE eType)
  {
  	if (eType == RETURN_TYPE_SINT)
  	{
  		return TO_FLAG_INTEGER;
  	}
  	else if (eType == RETURN_TYPE_UINT)
  	{
  		return TO_FLAG_UNSIGNED_INTEGER;
  	}
  	else
  	{
  		return TO_FLAG_NONE;
  	}
  }
  
  
  typedef enum
  {
  	CMP_EQ,
  	CMP_LT,
  	CMP_GE,
  	CMP_NE,
  } ComparisonType;
  
  static void AddComparision(HLSLCrossCompilerContext* psContext, Instruction* psInst, ComparisonType eType,
  	uint32_t typeFlag, Instruction* psNextInst)
  {
  	// Multiple cases to consider here:
  	// For shader model <=3: all comparisons are floats
  	// otherwise:
  	// OPCODE_LT, _GT, _NE etc: inputs are floats, outputs UINT 0xffffffff or 0. typeflag: TO_FLAG_NONE
  	// OPCODE_ILT, _IGT etc: comparisons are signed ints, outputs UINT 0xffffffff or 0 typeflag TO_FLAG_INTEGER
  	// _ULT, UGT etc: inputs unsigned ints, outputs UINTs typeflag TO_FLAG_UNSIGNED_INTEGER
  	//
  	// Additional complexity: if dest swizzle element count is 1, we can use normal comparison operators, otherwise glsl intrinsics.
  
  
  	bstring glsl = *psContext->currentShaderString;
  	const uint32_t destElemCount = GetNumSwizzleElements(&psInst->asOperands[0]);
  	const uint32_t s0ElemCount = GetNumSwizzleElements(&psInst->asOperands[1]);
  	const uint32_t s1ElemCount = GetNumSwizzleElements(&psInst->asOperands[2]);
  
  	int floatResult = 0;
  	int needsParenthesis = 0;
  
  	ASSERT(s0ElemCount == s1ElemCount || s1ElemCount == 1 || s0ElemCount == 1);
  	if (s0ElemCount != s1ElemCount)
  	{
  		// Set the proper auto-expand flag is either argument is scalar
  		typeFlag |= (TO_AUTO_EXPAND_TO_VEC2 << (max(s0ElemCount, s1ElemCount)-2));
  	}
  
  	if (psContext->psShader->ui32MajorVersion < 4)
  	{
  		floatResult = 1;
  	}
  
  	if (destElemCount > 1)
  	{
  		const char* glslOpcode[] = {
  			"equal",
  			"lessThan",
  			"greaterThanEqual",
  			"notEqual",
  		};
  
  		AddIndentation(psContext);
  		AddAssignToDest(psContext, &psInst->asOperands[0], floatResult ? SVT_FLOAT : SVT_UINT, destElemCount, &needsParenthesis);
  
  		bcatcstr(glsl, GetConstructorForType(floatResult ? SVT_FLOAT : SVT_UINT, destElemCount));
  		bformata(glsl, "(%s(", glslOpcode[eType]);
  		TranslateOperand(psContext, &psInst->asOperands[1], typeFlag);
  		bcatcstr(glsl, ", ");
  		TranslateOperand(psContext, &psInst->asOperands[2], typeFlag);
  		bcatcstr(glsl, "))");
  		if (!floatResult)
  		{
  			bcatcstr(glsl, " * 0xFFFFFFFFu");
  		}
  
  		AddAssignPrologue(psContext, needsParenthesis);
  	}
  	else
  	{
  		const char* glslOpcode[] = {
  			"==",
  			"<",
  			">=",
  			"!=",
  		};
  
  		//Scalar compare
  
  		// Optimization shortcut for the IGE+BREAKC_NZ combo:
  		// First print out the if(cond)->break directly, and then
  		// to guarantee correctness with side-effects, re-run
  		// the actual comparison. In most cases, the second run will
  		// be removed by the shader compiler optimizer pass (dead code elimination)
  		// This also makes it easier for some GLSL optimizers to recognize the for loop.
  
  		if (psInst->eOpcode == OPCODE_IGE &&
  			psNextInst &&
  			psNextInst->eOpcode == OPCODE_BREAKC &&
  			(psInst->asOperands[0].ui32RegisterNumber == psNextInst->asOperands[0].ui32RegisterNumber))
  		{
  
  			AddIndentation(psContext);
  			bcatcstr(glsl, "// IGE+BREAKC opt\n");
  			AddIndentation(psContext);
  
  			if (psNextInst->eBooleanTestType == INSTRUCTION_TEST_NONZERO)
  				bcatcstr(glsl, "if ((");
  			else
  				bcatcstr(glsl, "if (!(");
  			TranslateOperand(psContext, &psInst->asOperands[1], typeFlag);
  			bformata(glsl, "%s ", glslOpcode[eType]);
  			TranslateOperand(psContext, &psInst->asOperands[2], typeFlag);
  			bcatcstr(glsl, ")) { break; }\n");
  
  			// Mark the BREAKC instruction as already handled
  			psNextInst->eOpcode = OPCODE_NOP;
  
  			// Continue as usual
  		}
  
  		AddIndentation(psContext);
  		AddAssignToDest(psContext, &psInst->asOperands[0], floatResult ? SVT_FLOAT : SVT_UINT, destElemCount, &needsParenthesis);
  
  		bcatcstr(glsl, "(");
  		TranslateOperand(psContext, &psInst->asOperands[1], typeFlag);
  		bformata(glsl, "%s", glslOpcode[eType]);
  		TranslateOperand(psContext, &psInst->asOperands[2], typeFlag);
  		if (floatResult)
  		{
  			bcatcstr(glsl, ") ? 1.0 : 0.0");
  		}
  		else
  		{
  			bcatcstr(glsl, ") ? 0xFFFFFFFFu : 0u");
  		}
  		AddAssignPrologue(psContext, needsParenthesis);
  	}
  }
  
  
  static void AddMOVBinaryOp(HLSLCrossCompilerContext* psContext, const Operand *pDest, Operand *pSrc)
  {
  	int numParenthesis = 0;
  	int destComponents = GetMaxComponentFromComponentMask(pDest);
  	int srcSwizzleCount = GetNumSwizzleElements(pSrc);
  	uint32_t writeMask = GetOperandWriteMask(pDest);
  
  	const SHADER_VARIABLE_TYPE eSrcType = GetOperandDataTypeEx(psContext, pSrc, GetOperandDataType(psContext, pDest));
  	uint32_t flags = SVTTypeToFlag(eSrcType);
  
  	AddAssignToDest(psContext, pDest, eSrcType, srcSwizzleCount, &numParenthesis);
  	TranslateOperandWithMask(psContext, pSrc, flags, writeMask);
  
  	AddAssignPrologue(psContext, numParenthesis);
  }
  
  static uint32_t ElemCountToAutoExpandFlag(uint32_t elemCount)
  {
  	return TO_AUTO_EXPAND_TO_VEC2 << (elemCount - 2);
  }
  
  static void AddMOVCBinaryOp(HLSLCrossCompilerContext* psContext, const Operand *pDest, const Operand *src0, Operand *src1, Operand *src2)
  {
  	bstring glsl = *psContext->currentShaderString;
  	uint32_t destElemCount = GetNumSwizzleElements(pDest);
  	uint32_t s0ElemCount = GetNumSwizzleElements(src0);
  	uint32_t s1ElemCount = GetNumSwizzleElements(src1);
  	uint32_t s2ElemCount = GetNumSwizzleElements(src2);
  	uint32_t destWriteMask = GetOperandWriteMask(pDest);
  	uint32_t destElem;
  
  	const SHADER_VARIABLE_TYPE eDestType = GetOperandDataType(psContext, pDest);
  	const SHADER_VARIABLE_TYPE eSrc0Type = GetOperandDataType(psContext, src0);
  	/*
  	for each component in dest[.mask]
  	if the corresponding component in src0 (POS-swizzle)
  	has any bit set
  	{
  	copy this component (POS-swizzle) from src1 into dest
  	}
  	else
  	{
  	copy this component (POS-swizzle) from src2 into dest
  	}
  	endfor
  	*/
  
  	/* Single-component conditional variable (src0) */
  	if (s0ElemCount == 1 || IsSwizzleReplicated(src0))
  	{
  		int numParenthesis = 0;
  		AddIndentation(psContext);
  		AddAssignToDest(psContext, pDest, eDestType, destElemCount, &numParenthesis);
  		bcatcstr(glsl, "(");
  		TranslateOperand(psContext, src0, TO_AUTO_BITCAST_TO_INT);
  		if (s0ElemCount > 1)
  			bcatcstr(glsl, ".x");
  		if (psContext->psShader->ui32MajorVersion < 4)
  		{
  			//cmp opcode uses >= 0
  			bcatcstr(glsl, " >= 0) ? ");
  		}
  		else
  		{
  			bcatcstr(glsl, " != 0) ? ");
  		}
  
  		if (s1ElemCount == 1 && destElemCount > 1)
  			TranslateOperand(psContext, src1, SVTTypeToFlag(eDestType) | ElemCountToAutoExpandFlag(destElemCount) );
  		else
  			TranslateOperandWithMask(psContext, src1, SVTTypeToFlag(eDestType), destWriteMask);
  
  		bcatcstr(glsl, " : ");
  		if (s2ElemCount == 1 && destElemCount > 1)
  			TranslateOperand(psContext, src2, SVTTypeToFlag(eDestType) | ElemCountToAutoExpandFlag(destElemCount));
  		else
  			TranslateOperandWithMask(psContext, src2, SVTTypeToFlag(eDestType), destWriteMask);
  
  		AddAssignPrologue(psContext, numParenthesis);
  	}
  	else
  	{
  		// TODO: We can actually do this in one op using mix().
  		int srcElem = 0;
  		for (destElem = 0; destElem < 4; ++destElem)
  		{
  			int numParenthesis = 0;
  			if (pDest->eSelMode == OPERAND_4_COMPONENT_MASK_MODE && pDest->ui32CompMask != 0 && !(pDest->ui32CompMask & (1 << destElem)))
  				continue;
  
  			AddIndentation(psContext);
  			AddOpAssignToDestWithMask(psContext, pDest, eDestType, 1, "=", &numParenthesis, 1 << destElem);
  			bcatcstr(glsl, "(");
  			TranslateOperandWithMask(psContext, src0, TO_AUTO_BITCAST_TO_INT, 1 << srcElem);
  			if (psContext->psShader->ui32MajorVersion < 4)
  			{
  				//cmp opcode uses >= 0
  				bcatcstr(glsl, " >= 0) ? ");
  			}
  			else
  			{
  				bcatcstr(glsl, " != 0) ? ");
  			}
  
  			TranslateOperandWithMask(psContext, src1, SVTTypeToFlag(eDestType), 1 << srcElem);
  			bcatcstr(glsl, " : ");
  			TranslateOperandWithMask(psContext, src2, SVTTypeToFlag(eDestType), 1 << srcElem);
  
  			AddAssignPrologue(psContext, numParenthesis);
  
  			srcElem++;
  		}
  	}
  }
  
  // Returns nonzero if operands are identical, only cares about temp registers currently.
  static int AreTempOperandsIdentical(const Operand * psA, const Operand * psB)
  {
  	if (!psA || !psB)
  		return 0;
  
  	if (psA->eType != OPERAND_TYPE_TEMP || psB->eType != OPERAND_TYPE_TEMP)
  		return 0;
  
  	if (psA->eModifier != psB->eModifier)
  		return 0;
  
  	if (psA->iNumComponents != psB->iNumComponents)
  		return 0;
  
  	if (psA->ui32RegisterNumber != psB->ui32RegisterNumber)
  		return 0;
  
  	if (psA->eSelMode != psB->eSelMode)
  		return 0;
  
  	if (psA->eSelMode == OPERAND_4_COMPONENT_MASK_MODE && psA->ui32CompMask != psB->ui32CompMask)
  		return 0;
  
  	if (psA->eSelMode != OPERAND_4_COMPONENT_MASK_MODE && psA->ui32Swizzle != psB->ui32Swizzle)
  		return 0;
  
  	return 1;
  }
  
  // Returns nonzero if the operation is commutative
  static int IsOperationCommutative(OPCODE_TYPE eOpCode)
  {
  	switch (eOpCode)
  	{
  	case OPCODE_DADD:
  	case OPCODE_IADD:
  	case OPCODE_ADD:
  	case OPCODE_MUL:
  	case OPCODE_IMUL:
  	case OPCODE_OR:
  	case OPCODE_AND:
  		return 1;
  	default:
  		return 0;
  	};
  }
  
  static void CallBinaryOp(HLSLCrossCompilerContext* psContext, const char* name, Instruction* psInst,
  	int dest, int src0, int src1, SHADER_VARIABLE_TYPE eDataType)
  {
  	bstring glsl = *psContext->currentShaderString;
  	uint32_t src1SwizCount = GetNumSwizzleElements(&psInst->asOperands[src1]);
  	uint32_t src0SwizCount = GetNumSwizzleElements(&psInst->asOperands[src0]);
  	uint32_t dstSwizCount = GetNumSwizzleElements(&psInst->asOperands[dest]);
  	uint32_t destMask = GetOperandWriteMask(&psInst->asOperands[dest]);
  	int needsParenthesis = 0;
  
  	AddIndentation(psContext);
  
  	if (src1SwizCount == src0SwizCount == dstSwizCount)
  	{
  		// Optimization for readability (and to make for loops in WebGL happy): detect cases where either src == dest and emit +=, -= etc. instead.
  		if (AreTempOperandsIdentical(&psInst->asOperands[dest], &psInst->asOperands[src0]) != 0)
  		{
  			AddOpAssignToDestWithMask(psContext, &psInst->asOperands[dest], eDataType, dstSwizCount, name, &needsParenthesis, OPERAND_4_COMPONENT_MASK_ALL);
  			TranslateOperand(psContext, &psInst->asOperands[src1], SVTTypeToFlag(eDataType));
  			AddAssignPrologue(psContext, needsParenthesis);
  			return;
  		}
  		else if (AreTempOperandsIdentical(&psInst->asOperands[dest], &psInst->asOperands[src1]) != 0 && (IsOperationCommutative(psInst->eOpcode) != 0))
  		{
  			AddOpAssignToDestWithMask(psContext, &psInst->asOperands[dest], eDataType, dstSwizCount, name, &needsParenthesis, OPERAND_4_COMPONENT_MASK_ALL);
  			TranslateOperand(psContext, &psInst->asOperands[src0], SVTTypeToFlag(eDataType));
  			AddAssignPrologue(psContext, needsParenthesis);
  			return;
  		}
  	}
  
  	AddAssignToDest(psContext, &psInst->asOperands[dest], eDataType, dstSwizCount, &needsParenthesis);
  
  	TranslateOperandWithMask(psContext, &psInst->asOperands[src0], SVTTypeToFlag(eDataType), destMask);
  	bformata(glsl, " %s ", name);
  	TranslateOperandWithMask(psContext, &psInst->asOperands[src1], SVTTypeToFlag(eDataType), destMask);
  	AddAssignPrologue(psContext, needsParenthesis);
  }
  
  static void CallTernaryOp(HLSLCrossCompilerContext* psContext, const char* op1, const char* op2, Instruction* psInst,
  	int dest, int src0, int src1, int src2, uint32_t dataType)
  {
  	bstring glsl = *psContext->currentShaderString;
  	uint32_t src2SwizCount = GetNumSwizzleElements(&psInst->asOperands[src2]);
  	uint32_t src1SwizCount = GetNumSwizzleElements(&psInst->asOperands[src1]);
  	uint32_t src0SwizCount = GetNumSwizzleElements(&psInst->asOperands[src0]);
  	uint32_t dstSwizCount = GetNumSwizzleElements(&psInst->asOperands[dest]);
  	uint32_t destMask = GetOperandWriteMask(&psInst->asOperands[dest]);
  
  	uint32_t ui32Flags = dataType;
  	int numParenthesis = 0;
  
  	AddIndentation(psContext);
  
  	AddAssignToDest(psContext, &psInst->asOperands[dest], TypeFlagsToSVTType(dataType), dstSwizCount, &numParenthesis);
  
  	TranslateOperandWithMask(psContext, &psInst->asOperands[src0], ui32Flags, destMask);
  	bformata(glsl, " %s ", op1);
  	TranslateOperandWithMask(psContext, &psInst->asOperands[src1], ui32Flags, destMask);
  	bformata(glsl, " %s ", op2);
  	TranslateOperandWithMask(psContext, &psInst->asOperands[src2], ui32Flags, destMask);
  	AddAssignPrologue(psContext, numParenthesis);
  }
  
  static void CallHelper3(HLSLCrossCompilerContext* psContext, const char* name, Instruction* psInst,
  	int dest, int src0, int src1, int src2, int paramsShouldFollowWriteMask)
  {
  	uint32_t ui32Flags = TO_AUTO_BITCAST_TO_FLOAT;
  	bstring glsl = *psContext->currentShaderString;
  	uint32_t destMask = paramsShouldFollowWriteMask ? GetOperandWriteMask(&psInst->asOperands[dest]) : OPERAND_4_COMPONENT_MASK_ALL;
  	uint32_t src2SwizCount = GetNumSwizzleElements(&psInst->asOperands[src2]);
  	uint32_t src1SwizCount = GetNumSwizzleElements(&psInst->asOperands[src1]);
  	uint32_t src0SwizCount = GetNumSwizzleElements(&psInst->asOperands[src0]);
  	uint32_t dstSwizCount = GetNumSwizzleElements(&psInst->asOperands[dest]);
  	int numParenthesis = 0;
  
  
  	AddIndentation(psContext);
  
  	AddAssignToDest(psContext, &psInst->asOperands[dest], SVT_FLOAT, dstSwizCount, &numParenthesis);
  
  	bformata(glsl, "%s(", name);
  	numParenthesis++;
  	TranslateOperandWithMask(psContext, &psInst->asOperands[src0], ui32Flags, destMask);
  	bcatcstr(glsl, ", ");
  	TranslateOperandWithMask(psContext, &psInst->asOperands[src1], ui32Flags, destMask);
  	bcatcstr(glsl, ", ");
  	TranslateOperandWithMask(psContext, &psInst->asOperands[src2], ui32Flags, destMask);
  	AddAssignPrologue(psContext, numParenthesis);
  }
  
  static void CallHelper2(HLSLCrossCompilerContext* psContext, const char* name, Instruction* psInst,
  	int dest, int src0, int src1, int paramsShouldFollowWriteMask)
  {
  	uint32_t ui32Flags = TO_AUTO_BITCAST_TO_FLOAT;
  	bstring glsl = *psContext->currentShaderString;
  	uint32_t destMask = paramsShouldFollowWriteMask ? GetOperandWriteMask(&psInst->asOperands[dest]) : OPERAND_4_COMPONENT_MASK_ALL;
  	uint32_t src1SwizCount = GetNumSwizzleElements(&psInst->asOperands[src1]);
  	uint32_t src0SwizCount = GetNumSwizzleElements(&psInst->asOperands[src0]);
  	uint32_t dstSwizCount = GetNumSwizzleElements(&psInst->asOperands[dest]);
  
  	int isDotProduct = (strncmp(name, "dot", 3) == 0) ? 1 : 0;
  	int numParenthesis = 0;
  
  	AddIndentation(psContext);
  	AddAssignToDest(psContext, &psInst->asOperands[dest], SVT_FLOAT, isDotProduct ? 1 : dstSwizCount, &numParenthesis);
  
  	bformata(glsl, "%s(", name);
  	numParenthesis++;
  
  	TranslateOperandWithMask(psContext, &psInst->asOperands[src0], ui32Flags, destMask);
  	bcatcstr(glsl, ", ");
  	TranslateOperandWithMask(psContext, &psInst->asOperands[src1], ui32Flags, destMask);
  
  	AddAssignPrologue(psContext, numParenthesis);
  }
  
  static void CallHelper2Int(HLSLCrossCompilerContext* psContext, const char* name, Instruction* psInst,
  	int dest, int src0, int src1, int paramsShouldFollowWriteMask)
  {
  	uint32_t ui32Flags = TO_AUTO_BITCAST_TO_INT;
  	bstring glsl = *psContext->currentShaderString;
  	uint32_t src1SwizCount = GetNumSwizzleElements(&psInst->asOperands[src1]);
  	uint32_t src0SwizCount = GetNumSwizzleElements(&psInst->asOperands[src0]);
  	uint32_t dstSwizCount = GetNumSwizzleElements(&psInst->asOperands[dest]);
  	uint32_t destMask = paramsShouldFollowWriteMask ? GetOperandWriteMask(&psInst->asOperands[dest]) : OPERAND_4_COMPONENT_MASK_ALL;
  	int numParenthesis = 0;
  
  	AddIndentation(psContext);
  
  	AddAssignToDest(psContext, &psInst->asOperands[dest], SVT_INT, dstSwizCount, &numParenthesis);
  
  	bformata(glsl, "%s(", name);
  	numParenthesis++;
  	TranslateOperandWithMask(psContext, &psInst->asOperands[src0], ui32Flags, destMask);
  	bcatcstr(glsl, ", ");
  	TranslateOperandWithMask(psContext, &psInst->asOperands[src1], ui32Flags, destMask);
  	AddAssignPrologue(psContext, numParenthesis);
  }
  
  static void CallHelper2UInt(HLSLCrossCompilerContext* psContext, const char* name, Instruction* psInst,
  	int dest, int src0, int src1, int paramsShouldFollowWriteMask)
  {
  	uint32_t ui32Flags = TO_AUTO_BITCAST_TO_UINT;
  	bstring glsl = *psContext->currentShaderString;
  	uint32_t src1SwizCount = GetNumSwizzleElements(&psInst->asOperands[src1]);
  	uint32_t src0SwizCount = GetNumSwizzleElements(&psInst->asOperands[src0]);
  	uint32_t dstSwizCount = GetNumSwizzleElements(&psInst->asOperands[dest]);
  	uint32_t destMask = paramsShouldFollowWriteMask ? GetOperandWriteMask(&psInst->asOperands[dest]) : OPERAND_4_COMPONENT_MASK_ALL;
  	int numParenthesis = 0;
  
  	AddIndentation(psContext);
  
  	AddAssignToDest(psContext, &psInst->asOperands[dest], SVT_UINT, dstSwizCount, &numParenthesis);
  
  	bformata(glsl, "%s(", name);
  	numParenthesis++;
  	TranslateOperandWithMask(psContext, &psInst->asOperands[src0], ui32Flags, destMask);
  	bcatcstr(glsl, ", ");
  	TranslateOperandWithMask(psContext, &psInst->asOperands[src1], ui32Flags, destMask);
  	AddAssignPrologue(psContext, numParenthesis);
  }
  
  static void CallHelper1(HLSLCrossCompilerContext* psContext, const char* name, Instruction* psInst,
  	int dest, int src0, int paramsShouldFollowWriteMask)
  {
  	uint32_t ui32Flags = TO_AUTO_BITCAST_TO_FLOAT;
  	bstring glsl = *psContext->currentShaderString;
  	uint32_t src0SwizCount = GetNumSwizzleElements(&psInst->asOperands[src0]);
  	uint32_t dstSwizCount = GetNumSwizzleElements(&psInst->asOperands[dest]);
  	uint32_t destMask = paramsShouldFollowWriteMask ? GetOperandWriteMask(&psInst->asOperands[dest]) : OPERAND_4_COMPONENT_MASK_ALL;
  	int numParenthesis = 0;
  
  	AddIndentation(psContext);
  
  	AddAssignToDest(psContext, &psInst->asOperands[dest], SVT_FLOAT, dstSwizCount, &numParenthesis);
  
  	bformata(glsl, "%s(", name);
  	numParenthesis++;
  	TranslateOperandWithMask(psContext, &psInst->asOperands[src0], ui32Flags, destMask);
  	AddAssignPrologue(psContext, numParenthesis);
  }
  
  //Result is an int.
  static void CallHelper1Int(HLSLCrossCompilerContext* psContext,
  	const char* name,
  	Instruction* psInst,
  	const int dest,
  	const int src0,
  	int paramsShouldFollowWriteMask)
  {
  	uint32_t ui32Flags = TO_AUTO_BITCAST_TO_INT;
  	bstring glsl = *psContext->currentShaderString;
  	uint32_t src0SwizCount = GetNumSwizzleElements(&psInst->asOperands[src0]);
  	uint32_t dstSwizCount = GetNumSwizzleElements(&psInst->asOperands[dest]);
  	uint32_t destMask = paramsShouldFollowWriteMask ? GetOperandWriteMask(&psInst->asOperands[dest]) : OPERAND_4_COMPONENT_MASK_ALL;
  	int numParenthesis = 0;
  
  	AddIndentation(psContext);
  
  	AddAssignToDest(psContext, &psInst->asOperands[dest], SVT_INT, dstSwizCount, &numParenthesis);
  
  	bformata(glsl, "%s(", name);
  	numParenthesis++;
  	TranslateOperandWithMask(psContext, &psInst->asOperands[src0], ui32Flags, destMask);
  	AddAssignPrologue(psContext, numParenthesis);
  }
  
  static void TranslateTexelFetch(HLSLCrossCompilerContext* psContext,
  	Instruction* psInst,
  	ResourceBinding* psBinding,
  	bstring glsl)
  {
  	int numParenthesis = 0;
  	uint32_t destCount = GetNumSwizzleElements(&psInst->asOperands[0]);
  	AddIndentation(psContext);
  	AddAssignToDest(psContext, &psInst->asOperands[0], TypeFlagsToSVTType(ResourceReturnTypeToFlag(psBinding->ui32ReturnType)), 4, &numParenthesis);
  	bcatcstr(glsl, "texelFetch(");
  
  	switch (psBinding->eDimension)
  	{
  	case REFLECT_RESOURCE_DIMENSION_TEXTURE1D:
  	case REFLECT_RESOURCE_DIMENSION_BUFFER:
  	{
  		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
  		bcatcstr(glsl, ", ");
  		TranslateOperandWithMask(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER, OPERAND_4_COMPONENT_MASK_X);
  		if (psBinding->eDimension != REFLECT_RESOURCE_DIMENSION_BUFFER)
  			bcatcstr(glsl, ", 0"); // Buffers don't have LOD
  		bcatcstr(glsl, ")");
  		break;
  	}
  	case REFLECT_RESOURCE_DIMENSION_TEXTURE2DARRAY:
  	case REFLECT_RESOURCE_DIMENSION_TEXTURE3D:
  	{
  		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
  		bcatcstr(glsl, ", ");
  		TranslateOperandWithMask(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER | TO_AUTO_EXPAND_TO_VEC3, 7 /* .xyz */);
  		bcatcstr(glsl, ", 0)");
  		break;
  	}
  	case REFLECT_RESOURCE_DIMENSION_TEXTURE2D:
  	case REFLECT_RESOURCE_DIMENSION_TEXTURE1DARRAY:
  	{
  		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
  		bcatcstr(glsl, ", ");
  		TranslateOperandWithMask(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER | TO_AUTO_EXPAND_TO_VEC2, 3 /* .xy */);
  		bcatcstr(glsl, ", 0)");
  		break;
  	}
  	case REFLECT_RESOURCE_DIMENSION_TEXTURE2DMS: // TODO does this make any sense at all?
  	{
  		ASSERT(psInst->eOpcode == OPCODE_LD_MS);
  		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
  		bcatcstr(glsl, ", ");
  		TranslateOperandWithMask(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER | TO_AUTO_EXPAND_TO_VEC2, 3 /* .xy */);
  		bcatcstr(glsl, ", ");
  		TranslateOperandWithMask(psContext, &psInst->asOperands[3], TO_FLAG_INTEGER, OPERAND_4_COMPONENT_MASK_X);
  		bcatcstr(glsl, ")");
  		break;
  	}
  	case REFLECT_RESOURCE_DIMENSION_TEXTURE2DMSARRAY:
  	{
  		ASSERT(psInst->eOpcode == OPCODE_LD_MS);
  		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
  		bcatcstr(glsl, ", ");
  		TranslateOperandWithMask(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER | TO_AUTO_EXPAND_TO_VEC3, 7 /* .xyz */);
  		bcatcstr(glsl, ", ");
  		TranslateOperandWithMask(psContext, &psInst->asOperands[3], TO_FLAG_INTEGER, OPERAND_4_COMPONENT_MASK_X);
  		bcatcstr(glsl, ")");
  		break;
  	}
  	case REFLECT_RESOURCE_DIMENSION_TEXTURECUBE:
  	case REFLECT_RESOURCE_DIMENSION_TEXTURECUBEARRAY:
  	case REFLECT_RESOURCE_DIMENSION_BUFFEREX:
  	default:
  	{
  		ASSERT(0);
  		break;
  	}
  	}
  
  	AddSwizzleUsingElementCount(psContext, destCount);
  	AddAssignPrologue(psContext, numParenthesis);
  }
  
  static void TranslateTexelFetchOffset(HLSLCrossCompilerContext* psContext,
  	Instruction* psInst,
  	ResourceBinding* psBinding,
  	bstring glsl)
  {
  	int numParenthesis = 0;
  	uint32_t destCount = GetNumSwizzleElements(&psInst->asOperands[0]);
  	AddIndentation(psContext);
  	AddAssignToDest(psContext, &psInst->asOperands[0], TypeFlagsToSVTType(ResourceReturnTypeToFlag(psBinding->ui32ReturnType)), 4, &numParenthesis);
  
  	bcatcstr(glsl, "texelFetchOffset(");
  
  	switch (psBinding->eDimension)
  	{
  	case REFLECT_RESOURCE_DIMENSION_TEXTURE1D:
  	{
  		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
  		bcatcstr(glsl, ", ");
  		TranslateOperandWithMask(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER, OPERAND_4_COMPONENT_MASK_X);
  		bformata(glsl, ", 0, %d)", psInst->iUAddrOffset);
  		break;
  	}
  	case REFLECT_RESOURCE_DIMENSION_TEXTURE2DARRAY:
  	{
  		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
  		bcatcstr(glsl, ", ");
  		TranslateOperandWithMask(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER | TO_AUTO_EXPAND_TO_VEC3, 7 /* .xyz */);
  		bformata(glsl, ", 0, ivec2(%d, %d))",
  			psInst->iUAddrOffset,
  			psInst->iVAddrOffset);
  		break;
  	}
  	case REFLECT_RESOURCE_DIMENSION_TEXTURE3D:
  	{
  		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
  		bcatcstr(glsl, ", ");
  		TranslateOperandWithMask(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER | TO_AUTO_EXPAND_TO_VEC3, 7 /* .xyz */);
  		bformata(glsl, ", 0, ivec3(%d, %d, %d))",
  			psInst->iUAddrOffset,
  			psInst->iVAddrOffset,
  			psInst->iWAddrOffset);
  		break;
  	}
  	case REFLECT_RESOURCE_DIMENSION_TEXTURE2D:
  	{
  		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
  		bcatcstr(glsl, ", ");
  		TranslateOperandWithMask(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER | TO_AUTO_EXPAND_TO_VEC2, 3 /* .xy */);
  		bformata(glsl, ", 0, ivec2(%d, %d))", psInst->iUAddrOffset, psInst->iVAddrOffset);
  		break;
  	}
  	case REFLECT_RESOURCE_DIMENSION_TEXTURE1DARRAY:
  	{
  		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
  		bcatcstr(glsl, ", ");
  		TranslateOperandWithMask(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER | TO_AUTO_EXPAND_TO_VEC2, 3 /* .xy */);
  		bformata(glsl, ", 0, int(%d))", psInst->iUAddrOffset);
  		break;
  	}
  	case REFLECT_RESOURCE_DIMENSION_BUFFER:
  	case REFLECT_RESOURCE_DIMENSION_TEXTURE2DMS:
  	case REFLECT_RESOURCE_DIMENSION_TEXTURE2DMSARRAY:
  	case REFLECT_RESOURCE_DIMENSION_TEXTURECUBE:
  	case REFLECT_RESOURCE_DIMENSION_TEXTURECUBEARRAY:
  	case REFLECT_RESOURCE_DIMENSION_BUFFEREX:
  	default:
  	{
  		ASSERT(0);
  		break;
  	}
  	}
  
  	AddSwizzleUsingElementCount(psContext, destCount);
  	AddAssignPrologue(psContext, numParenthesis);
  }
  
  
  //Makes sure the texture coordinate swizzle is appropriate for the texture type.
  //i.e. vecX for X-dimension texture.
  //Currently supports floating point coord only, so not used for texelFetch.
  static void TranslateTexCoord(HLSLCrossCompilerContext* psContext,
  	const RESOURCE_DIMENSION eResDim,
  	Operand* psTexCoordOperand)
  {
  	int numParenthesis = 0;
  	uint32_t flags = TO_AUTO_BITCAST_TO_FLOAT;
  	bstring glsl = *psContext->currentShaderString;
  	uint32_t opMask = OPERAND_4_COMPONENT_MASK_ALL;
  
  	switch (eResDim)
  	{
  	case RESOURCE_DIMENSION_TEXTURE1D:
  	{
  		//Vec1 texcoord. Mask out the other components.
  		opMask = OPERAND_4_COMPONENT_MASK_X;
  		break;
  	}
  	case RESOURCE_DIMENSION_TEXTURE2D:
  	case RESOURCE_DIMENSION_TEXTURE1DARRAY:
  	{
  		//Vec2 texcoord. Mask out the other components.
  		opMask = OPERAND_4_COMPONENT_MASK_X | OPERAND_4_COMPONENT_MASK_Y;
  		flags |= TO_AUTO_EXPAND_TO_VEC2;
  		break;
  	}
  	case RESOURCE_DIMENSION_TEXTURECUBE:
  	case RESOURCE_DIMENSION_TEXTURE3D:
  	case RESOURCE_DIMENSION_TEXTURE2DARRAY:
  	{
  		//Vec3 texcoord. Mask out the other components.
  		opMask = OPERAND_4_COMPONENT_MASK_X | OPERAND_4_COMPONENT_MASK_Y | OPERAND_4_COMPONENT_MASK_Z;
  		flags |= TO_AUTO_EXPAND_TO_VEC3;
  		break;
  	}
  	case RESOURCE_DIMENSION_TEXTURECUBEARRAY:
  	{
  		flags |= TO_AUTO_EXPAND_TO_VEC4;
  		break;
  	}
  	default:
  	{
  		ASSERT(0);
  		break;
  	}
  	}
  
  	//FIXME detect when integer coords are needed.
  	TranslateOperandWithMask(psContext, psTexCoordOperand, flags, opMask);
  }
  
  static int GetNumTextureDimensions(HLSLCrossCompilerContext* psContext,
  	const RESOURCE_DIMENSION eResDim)
  {
  	int constructor = 0;
  	bstring glsl = *psContext->currentShaderString;
  
  	switch (eResDim)
  	{
  	case RESOURCE_DIMENSION_TEXTURE1D:
  	{
  		return 1;
  	}
  	case RESOURCE_DIMENSION_TEXTURE2D:
  	case RESOURCE_DIMENSION_TEXTURE1DARRAY:
  	case RESOURCE_DIMENSION_TEXTURECUBE:
  	{
  		return 2;
  	}
  
  	case RESOURCE_DIMENSION_TEXTURE3D:
  	case RESOURCE_DIMENSION_TEXTURE2DARRAY:
  	case RESOURCE_DIMENSION_TEXTURECUBEARRAY:
  	{
  		return 3;
  	}
  	default:
  	{
  		ASSERT(0);
  		break;
  	}
  	}
  	return 0;
  }
  
  void GetResInfoData(HLSLCrossCompilerContext* psContext, Instruction* psInst, int index, int destElem)
  {
  	bstring glsl = *psContext->currentShaderString;
  	int numParenthesis = 0;
  	const RESINFO_RETURN_TYPE eResInfoReturnType = psInst->eResInfoReturnType;
  	const RESOURCE_DIMENSION eResDim = psContext->psShader->aeResourceDims[psInst->asOperands[2].ui32RegisterNumber];
  
  	AddIndentation(psContext);
  	AddOpAssignToDestWithMask(psContext, &psInst->asOperands[0], eResInfoReturnType == RESINFO_INSTRUCTION_RETURN_UINT ? SVT_UINT : SVT_FLOAT, 1, "=", &numParenthesis, 1 << destElem);
  
  	//[width, height, depth or array size, total-mip-count]
  	if (index < 3)
  	{
  		int dim = GetNumTextureDimensions(psContext, eResDim);
  		bcatcstr(glsl, "(");
  		if (dim < (index + 1))
  		{
  			bcatcstr(glsl, eResInfoReturnType == RESINFO_INSTRUCTION_RETURN_UINT ? "0u" : "0.0");
  		}
  		else
  		{
  			if (eResInfoReturnType == RESINFO_INSTRUCTION_RETURN_UINT)
  			{
  				bformata(glsl, "uvec%d(textureSize(", dim);
  			}
  			else if (eResInfoReturnType == RESINFO_INSTRUCTION_RETURN_RCPFLOAT)
  			{
  				bformata(glsl, "vec%d(1.0) / vec%d(textureSize(", dim, dim);
  			}
  			else
  			{
  				bformata(glsl, "vec%d(textureSize(", dim);
  			}
  			TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
  			bcatcstr(glsl, ", ");
  			TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER);
  			bcatcstr(glsl, "))");
  
  			switch (index)
  			{
  			case 0:
  				bcatcstr(glsl, ".x");
  				break;
  			case 1:
  				bcatcstr(glsl, ".y");
  				break;
  			case 2:
  				bcatcstr(glsl, ".z");
  				break;
  			}
  		}
  
  		bcatcstr(glsl, ")");
  	}
  	else
  	{
  		if (eResInfoReturnType == RESINFO_INSTRUCTION_RETURN_UINT)
  			bcatcstr(glsl, "uint(");
  		else
  			bcatcstr(glsl, "float(");
  		bcatcstr(glsl, "textureQueryLevels(");
  		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
  		bcatcstr(glsl, "))");
  	}
  	AddAssignPrologue(psContext, numParenthesis);
  }
  
  #define TEXSMP_FLAG_NONE 0x0
  #define TEXSMP_FLAG_LOD 0x1 //LOD comes from operand
  #define TEXSMP_FLAG_DEPTHCOMPARE 0x2
  #define TEXSMP_FLAG_FIRSTLOD 0x4 //LOD is 0
  #define TEXSMP_FLAG_BIAS 0x8
  #define TEXSMP_FLAGS_GRAD 0x10
  
  // TODO FIXME: non-float samplers!
  static void TranslateTextureSample(HLSLCrossCompilerContext* psContext, Instruction* psInst,
  	uint32_t ui32Flags)
  {
  	bstring glsl = *psContext->currentShaderString;
  	int numParenthesis = 0;
  
  	const char* funcName = "texture";
  	const char* offset = "";
  	const char* depthCmpCoordType = "";
  	const char* gradSwizzle = "";
  
  	uint32_t ui32NumOffsets = 0;
  
  	const RESOURCE_DIMENSION eResDim = psContext->psShader->aeResourceDims[psInst->asOperands[2].ui32RegisterNumber];
  
  	const int iHaveOverloadedTexFuncs = HaveOverloadedTextureFuncs(psContext->psShader->eTargetLanguage);
  
  	const int useCombinedTextureSamplers = (psContext->flags & HLSLCC_FLAG_COMBINE_TEXTURE_SAMPLERS) ? 1 : 0;
  
  	ASSERT(psInst->asOperands[2].ui32RegisterNumber < MAX_TEXTURES);
  
  	if (psInst->bAddressOffset)
  	{
  		offset = "Offset";
  	}
  
  	switch (eResDim)
  	{
  	case RESOURCE_DIMENSION_TEXTURE1D:
  	{
  		depthCmpCoordType = "vec2";
  		gradSwizzle = ".x";
  		ui32NumOffsets = 1;
  		if (!iHaveOverloadedTexFuncs)
  		{
  			funcName = "texture1D";
  			if (ui32Flags & TEXSMP_FLAG_DEPTHCOMPARE)
  			{
  				funcName = "shadow1D";
  			}
  		}
  		break;
  	}
  	case RESOURCE_DIMENSION_TEXTURE2D:
  	{
  		depthCmpCoordType = "vec3";
  		gradSwizzle = ".xy";
  		ui32NumOffsets = 2;
  		if (!iHaveOverloadedTexFuncs)
  		{
  			funcName = "texture2D";
  			if (ui32Flags & TEXSMP_FLAG_DEPTHCOMPARE)
  			{
  				funcName = "shadow2D";
  			}
  		}
  		break;
  	}
  	case RESOURCE_DIMENSION_TEXTURECUBE:
  	{
  		depthCmpCoordType = "vec3";
  		gradSwizzle = ".xyz";
  		ui32NumOffsets = 3;
  		if (!iHaveOverloadedTexFuncs)
  		{
  			funcName = "textureCube";
  		}
  		break;
  	}
  	case RESOURCE_DIMENSION_TEXTURE3D:
  	{
  		depthCmpCoordType = "vec4";
  		gradSwizzle = ".xyz";
  		ui32NumOffsets = 3;
  		if (!iHaveOverloadedTexFuncs)
  		{
  			funcName = "texture3D";
  		}
  		break;
  	}
  	case RESOURCE_DIMENSION_TEXTURE1DARRAY:
  	{
  		depthCmpCoordType = "vec3";
  		gradSwizzle = ".x";
  		ui32NumOffsets = 1;
  		break;
  	}
  	case RESOURCE_DIMENSION_TEXTURE2DARRAY:
  	{
  		depthCmpCoordType = "vec4";
  		gradSwizzle = ".xy";
  		ui32NumOffsets = 2;
  		break;
  	}
  	case RESOURCE_DIMENSION_TEXTURECUBEARRAY:
  	{
  		gradSwizzle = ".xyz";
  		ui32NumOffsets = 3;
  		if (ui32Flags & TEXSMP_FLAG_DEPTHCOMPARE)
  		{
  			SHADER_VARIABLE_TYPE dataType = SVT_FLOAT; // TODO!!
  			//Special. Reference is a separate argument.
  			AddIndentation(psContext);
  
  			AddAssignToDest(psContext, &psInst->asOperands[0], dataType, 1, &numParenthesis);
  			if (ui32Flags & (TEXSMP_FLAG_LOD | TEXSMP_FLAG_FIRSTLOD))
  			{
  				bcatcstr(glsl, "textureLod(");
  			}
  			else
  			{
  				bcatcstr(glsl, "texture(");
  			}
  			if (!useCombinedTextureSamplers)
  				ResourceName(glsl, psContext, RGROUP_TEXTURE, psInst->asOperands[2].ui32RegisterNumber, (ui32Flags & TEXSMP_FLAG_DEPTHCOMPARE) ? 1 : 0);
  			else
  				bconcat(glsl, TextureSamplerName(&psContext->psShader->sInfo, psInst->asOperands[2].ui32RegisterNumber, psInst->asOperands[3].ui32RegisterNumber, (ui32Flags & TEXSMP_FLAG_DEPTHCOMPARE) ? 1 : 0));
  			bcatcstr(glsl, ",");
  			TranslateTexCoord(psContext, eResDim, &psInst->asOperands[1]);
  			bcatcstr(glsl, ",");
  			//.z = reference.
  			TranslateOperand(psContext, &psInst->asOperands[4], TO_AUTO_BITCAST_TO_FLOAT);
  
  			if (ui32Flags & TEXSMP_FLAG_FIRSTLOD)
  			{
  				bcatcstr(glsl, ", 0.0");
  			}
  
  			bcatcstr(glsl, ")");
  			// Doesn't make any sense to do swizzles here, depth comparison returns a scalar.
  			AddAssignPrologue(psContext, numParenthesis);
  			return;
  		}
  
  		break;
  	}
  	default:
  	{
  		ASSERT(0);
  		break;
  	}
  	}
  
  	if (ui32Flags & TEXSMP_FLAG_DEPTHCOMPARE)
  	{
  		//For non-cubeMap Arrays the reference value comes from the
  		//texture coord vector in GLSL. For cubmap arrays there is a
  		//separate parameter.
  		//It is always separate paramter in HLSL.
  		SHADER_VARIABLE_TYPE dataType = SVT_FLOAT; // TODO!!
  		AddIndentation(psContext);
  		AddAssignToDest(psContext, &psInst->asOperands[0], dataType, GetNumSwizzleElements(&psInst->asOperands[2]), &numParenthesis);
  		if (ui32Flags & (TEXSMP_FLAG_LOD | TEXSMP_FLAG_FIRSTLOD))
  		{
  			bformata(glsl, "%sLod%s(", funcName, offset);
  		}
  		else
  		{
  			bformata(glsl, "%s%s(", funcName, offset);
  		}
  		if (!useCombinedTextureSamplers)
  			ResourceName(glsl, psContext, RGROUP_TEXTURE, psInst->asOperands[2].ui32RegisterNumber, 1);
  		else
  			bconcat(glsl, TextureSamplerName(&psContext->psShader->sInfo, psInst->asOperands[2].ui32RegisterNumber, psInst->asOperands[3].ui32RegisterNumber, 1));
  		bformata(glsl, ", %s(", depthCmpCoordType);
  		TranslateTexCoord(psContext, eResDim, &psInst->asOperands[1]);
  		bcatcstr(glsl, ",");
  		//.z = reference.
  		TranslateOperand(psContext, &psInst->asOperands[4], TO_AUTO_BITCAST_TO_FLOAT);
  		bcatcstr(glsl, ")");
  
  		if (ui32Flags & TEXSMP_FLAG_FIRSTLOD)
  		{
  			bcatcstr(glsl, ", 0.0");
  		}
  
  		bcatcstr(glsl, ")");
  	}
  	else
  	{
  		SHADER_VARIABLE_TYPE dataType = SVT_FLOAT; // TODO!!
  		AddIndentation(psContext);
  		AddAssignToDest(psContext, &psInst->asOperands[0], dataType, GetNumSwizzleElements(&psInst->asOperands[2]), &numParenthesis);
  
  		if (ui32Flags & (TEXSMP_FLAG_LOD | TEXSMP_FLAG_FIRSTLOD))
  		{
  			bformata(glsl, "%sLod%s(", funcName, offset);
  		}
  		else
  			if (ui32Flags & TEXSMP_FLAGS_GRAD)
  			{
  			bformata(glsl, "%sGrad%s(", funcName, offset);
  			}
  			else
  			{
  				bformata(glsl, "%s%s(", funcName, offset);
  			}
  		if (!useCombinedTextureSamplers)
  			TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);//resource
  		else
  			bconcat(glsl, TextureSamplerName(&psContext->psShader->sInfo, psInst->asOperands[2].ui32RegisterNumber, psInst->asOperands[3].ui32RegisterNumber, 0));
  		bcatcstr(glsl, ", ");
  		TranslateTexCoord(psContext, eResDim, &psInst->asOperands[1]);
  
  		if (ui32Flags & (TEXSMP_FLAG_LOD))
  		{
  			bcatcstr(glsl, ", ");
  			TranslateOperand(psContext, &psInst->asOperands[4], TO_AUTO_BITCAST_TO_FLOAT);
  			if (psContext->psShader->ui32MajorVersion < 4)
  			{
  				bcatcstr(glsl, ".w");
  			}
  		}
  		else
  			if (ui32Flags & TEXSMP_FLAG_FIRSTLOD)
  			{
  			bcatcstr(glsl, ", 0.0");
  			}
  			else
  				if (ui32Flags & TEXSMP_FLAGS_GRAD)
  				{
  			bcatcstr(glsl, ", vec4(");
  			TranslateOperand(psContext, &psInst->asOperands[4], TO_AUTO_BITCAST_TO_FLOAT);//dx
  			bcatcstr(glsl, ")");
  			bcatcstr(glsl, gradSwizzle);
  			bcatcstr(glsl, ", vec4(");
  			TranslateOperand(psContext, &psInst->asOperands[5], TO_AUTO_BITCAST_TO_FLOAT);//dy
  			bcatcstr(glsl, ")");
  			bcatcstr(glsl, gradSwizzle);
  				}
  
  		if (psInst->bAddressOffset)
  		{
  			if (ui32NumOffsets == 1)
  			{
  				bformata(glsl, ", %d",
  					psInst->iUAddrOffset);
  			}
  			else
  				if (ui32NumOffsets == 2)
  				{
  				bformata(glsl, ", ivec2(%d, %d)",
  					psInst->iUAddrOffset,
  					psInst->iVAddrOffset);
  				}
  				else
  					if (ui32NumOffsets == 3)
  					{
  				bformata(glsl, ", ivec3(%d, %d, %d)",
  					psInst->iUAddrOffset,
  					psInst->iVAddrOffset,
  					psInst->iWAddrOffset);
  					}
  		}
  
  		if (ui32Flags & (TEXSMP_FLAG_BIAS))
  		{
  			bcatcstr(glsl, ", ");
  			TranslateOperand(psContext, &psInst->asOperands[4], TO_AUTO_BITCAST_TO_FLOAT);
  		}
  
  		bcatcstr(glsl, ")");
  	}
  
  	if (!(ui32Flags & TEXSMP_FLAG_DEPTHCOMPARE))
  	{
  		// iWriteMaskEnabled is forced off during DecodeOperand because swizzle on sampler uniforms
  		// does not make sense. But need to re-enable to correctly swizzle this particular instruction.
  		psInst->asOperands[2].iWriteMaskEnabled = 1;
  		TranslateOperandSwizzleWithMask(psContext, &psInst->asOperands[2], GetOperandWriteMask(&psInst->asOperands[0]));
  	}
  	AddAssignPrologue(psContext, numParenthesis);
  }
  
  static ShaderVarType* LookupStructuredVar(HLSLCrossCompilerContext* psContext,
  	Operand* psResource,
  	Operand* psByteOffset,
  	uint32_t ui32Component)
  {
  	ConstantBuffer* psCBuf = NULL;
  	ShaderVarType* psVarType = NULL;
  	uint32_t aui32Swizzle[4] = { OPERAND_4_COMPONENT_X };
  	int byteOffset = ((int*)psByteOffset->afImmediates)[0] + 4 * ui32Component;
  	int vec4Offset = 0;
  	int32_t index = -1;
  	int32_t rebase = -1;
  	int found;
  
  	ASSERT(psByteOffset->eType == OPERAND_TYPE_IMMEDIATE32);
  	//TODO: multi-component stores and vector writes need testing.
  
  	//aui32Swizzle[0] = psInst->asOperands[0].aui32Swizzle[component];
  
  	switch (byteOffset % 16)
  	{
  	case 0:
  		aui32Swizzle[0] = 0;
  		break;
  	case 4:
  		aui32Swizzle[0] = 1;
  		break;
  	case 8:
  		aui32Swizzle[0] = 2;
  		break;
  	case 12:
  		aui32Swizzle[0] = 3;
  		break;
  	}
  
  	switch (psResource->eType)
  	{
  	case OPERAND_TYPE_RESOURCE:
  		GetConstantBufferFromBindingPoint(RGROUP_TEXTURE, psResource->ui32RegisterNumber, &psContext->psShader->sInfo, &psCBuf);
  		break;
  	case OPERAND_TYPE_UNORDERED_ACCESS_VIEW:
  		GetConstantBufferFromBindingPoint(RGROUP_UAV, psResource->ui32RegisterNumber, &psContext->psShader->sInfo, &psCBuf);
  		break;
  	case OPERAND_TYPE_THREAD_GROUP_SHARED_MEMORY:
  	{
  		//dcl_tgsm_structured defines the amount of memory and a stride.
  		ASSERT(psResource->ui32RegisterNumber < MAX_GROUPSHARED);
  		return &psContext->psShader->sGroupSharedVarType[psResource->ui32RegisterNumber];
  	}
  	default:
  		ASSERT(0);
  		break;
  	}
  
  	found = GetShaderVarFromOffset(vec4Offset, aui32Swizzle, psCBuf, &psVarType, &index, &rebase);
  	ASSERT(found);
  
  	return psVarType;
  }
  
  
  static void TranslateShaderStorageStore(HLSLCrossCompilerContext* psContext, Instruction* psInst)
  {
  	bstring glsl = *psContext->currentShaderString;
  	ShaderVarType* psVarType = NULL;
  	uint32_t ui32DataTypeFlag = TO_FLAG_INTEGER;
  	int component;
  	int srcComponent = 0;
  
  	Operand* psDest = 0;
  	Operand* psDestAddr = 0;
  	Operand* psDestByteOff = 0;
  	Operand* psSrc = 0;
  	int structured = 0;
  	int groupshared = 0;
  
  	switch (psInst->eOpcode)
  	{
  	case OPCODE_STORE_STRUCTURED:
  		psDest = &psInst->asOperands[0];
  		psDestAddr = &psInst->asOperands[1];
  		psDestByteOff = &psInst->asOperands[2];
  		psSrc = &psInst->asOperands[3];
  		structured = 1;
  
  		break;
  	case OPCODE_STORE_RAW:
  		psDest = &psInst->asOperands[0];
  		psDestByteOff = &psInst->asOperands[1];
  		psSrc = &psInst->asOperands[2];
  		break;
  	}
  
  	for (component = 0; component < 4; component++)
  	{
  		const char* swizzleString[] = { ".x", ".y", ".z", ".w" };
  		ASSERT(psInst->asOperands[0].eSelMode == OPERAND_4_COMPONENT_MASK_MODE);
  		if (psInst->asOperands[0].ui32CompMask & (1 << component))
  		{
  			SHADER_VARIABLE_TYPE eSrcDataType = GetOperandDataType(psContext, psSrc);
  
  			if (structured && psDest->eType != OPERAND_TYPE_THREAD_GROUP_SHARED_MEMORY)
  			{
  				psVarType = LookupStructuredVar(psContext, psDest, psDestByteOff, component);
  			}
  
  			AddIndentation(psContext);
  
  			if (structured && psDest->eType == OPERAND_TYPE_RESOURCE)
  			{
  				bformata(glsl, "StructuredRes%d", psDest->ui32RegisterNumber);
  			}
  			else
  			{
  				TranslateOperand(psContext, psDest, TO_FLAG_DESTINATION | TO_FLAG_NAME_ONLY);
  			}
  			bformata(glsl, "[");
  			if (structured) //Dest address and dest byte offset
  			{
  				if (psDest->eType == OPERAND_TYPE_THREAD_GROUP_SHARED_MEMORY)
  				{
  					TranslateOperand(psContext, psDestAddr, TO_FLAG_INTEGER | TO_FLAG_UNSIGNED_INTEGER);
  					bformata(glsl, "].value[");
  					TranslateOperand(psContext, psDestByteOff, TO_FLAG_INTEGER | TO_FLAG_UNSIGNED_INTEGER);
  					bformata(glsl, "/4u ");//bytes to floats
  				}
  				else
  				{
  					TranslateOperand(psContext, psDestAddr, TO_FLAG_INTEGER | TO_FLAG_UNSIGNED_INTEGER);
  				}
  			}
  			else
  			{
  				TranslateOperand(psContext, psDestByteOff, TO_FLAG_INTEGER | TO_FLAG_UNSIGNED_INTEGER);
  			}
  
  			//RAW: change component using index offset
  			if (!structured || (psDest->eType == OPERAND_TYPE_THREAD_GROUP_SHARED_MEMORY))
  			{
  				bformata(glsl, " + %d", component);
  			}
  
  			bformata(glsl, "]");
  
  			if (structured && psDest->eType != OPERAND_TYPE_THREAD_GROUP_SHARED_MEMORY)
  			{
  				if (strcmp(psVarType->Name, "$Element") != 0)
  				{
  					bformata(glsl, ".%s", psVarType->Name);
  				}
  			}
  
  			if (structured)
  			{
  				uint32_t flags = TO_FLAG_UNSIGNED_INTEGER;
  				if (psVarType)
  				{
  					if (psVarType->Type == SVT_INT)
  					{
  						flags = TO_FLAG_INTEGER;
  					}
  					else if (psVarType->Type == SVT_FLOAT)
  					{
  						flags = TO_FLAG_NONE;
  					}
  				}
  				//TGSM always uint
  				bformata(glsl, " = (");
  				if (GetNumSwizzleElements(psSrc) > 1)
  					TranslateOperandWithMask(psContext, psSrc, flags, 1 << (srcComponent++));
  				else
  					TranslateOperandWithMask(psContext, psSrc, flags, OPERAND_4_COMPONENT_MASK_X);
  
  			}
  			else
  			{
  				//Dest type is currently always a uint array.
  				bformata(glsl, " = (");
  				if (GetNumSwizzleElements(psSrc) > 1)
  					TranslateOperandWithMask(psContext, psSrc, TO_FLAG_UNSIGNED_INTEGER, 1 << (srcComponent++));
  				else
  					TranslateOperandWithMask(psContext, psSrc, TO_FLAG_UNSIGNED_INTEGER, OPERAND_4_COMPONENT_MASK_X);
  			}
  
  			//Double takes an extra slot.
  			if (psVarType && psVarType->Type == SVT_DOUBLE)
  			{
  				if (structured && psDest->eType == OPERAND_TYPE_THREAD_GROUP_SHARED_MEMORY)
  					bcatcstr(glsl, ")");
  				component++;
  			}
  
  			bformata(glsl, ");\n");
  		}
  	}
  }
  static void TranslateShaderStorageLoad(HLSLCrossCompilerContext* psContext, Instruction* psInst)
  {
  	bstring glsl = *psContext->currentShaderString;
  	ShaderVarType* psVarType = NULL;
  	uint32_t aui32Swizzle[4] = { OPERAND_4_COMPONENT_X };
  	uint32_t ui32DataTypeFlag = TO_FLAG_INTEGER;
  	int component;
  	int destComponent = 0;
  	int numParenthesis = 0;
  	Operand* psDest = 0;
  	Operand* psSrcAddr = 0;
  	Operand* psSrcByteOff = 0;
  	Operand* psSrc = 0;
  	int structured = 0;
  
  	switch (psInst->eOpcode)
  	{
  	case OPCODE_LD_STRUCTURED:
  		psDest = &psInst->asOperands[0];
  		psSrcAddr = &psInst->asOperands[1];
  		psSrcByteOff = &psInst->asOperands[2];
  		psSrc = &psInst->asOperands[3];
  		structured = 1;
  		break;
  	case OPCODE_LD_RAW:
  		psDest = &psInst->asOperands[0];
  		psSrcByteOff = &psInst->asOperands[1];
  		psSrc = &psInst->asOperands[2];
  		break;
  	}
  
  	if (psInst->eOpcode == OPCODE_LD_RAW)
  	{
  		int numParenthesis = 0;
  		int firstItemAdded = 0;
  		uint32_t destCount = GetNumSwizzleElements(psDest);
  		uint32_t destMask = GetOperandWriteMask(psDest);
  		AddIndentation(psContext);
  		AddAssignToDest(psContext, psDest, SVT_UINT, destCount, &numParenthesis);
  		if (destCount > 1)
  		{
  			bformata(glsl, "%s(", GetConstructorForType(SVT_UINT, destCount));
  			numParenthesis++;
  		}
  		for (component = 0; component < 4; component++)
  		{
  			if (!(destMask & (1 << component)))
  				continue;
  
  			if (firstItemAdded)
  				bcatcstr(glsl, ", ");
  			else
  				firstItemAdded = 1;
  
  			bformata(glsl, "RawRes%d[((", psSrc->ui32RegisterNumber);
  			TranslateOperand(psContext, psSrcByteOff, TO_FLAG_INTEGER);
  			bcatcstr(glsl, ") >> 2)");
  			if (psSrc->eSelMode == OPERAND_4_COMPONENT_SWIZZLE_MODE && psSrc->aui32Swizzle[component] != 0)
  			{
  				bformata(glsl, " + %d", psSrc->aui32Swizzle[component]);
  			}
  			bcatcstr(glsl, "]");
  		}
  		AddAssignPrologue(psContext, numParenthesis);
  	}
  	else
  	{
  		int numParenthesis = 0;
  		int firstItemAdded = 0;
  		uint32_t destCount = GetNumSwizzleElements(psDest);
  		uint32_t destMask = GetOperandWriteMask(psDest);
  		ASSERT(psInst->eOpcode == OPCODE_LD_STRUCTURED);
  		AddIndentation(psContext);
  		AddAssignToDest(psContext, psDest, SVT_UINT, destCount, &numParenthesis);
  		if (destCount > 1)
  		{
  			bformata(glsl, "%s(", GetConstructorForType(SVT_UINT, destCount));
  			numParenthesis++;
  		}
  		for (component = 0; component < 4; component++)
  		{
  			ShaderVarType *psVar = NULL;
  			int addedBitcast = 0;
  			if (!(destMask & (1 << component)))
  				continue;
  
  			if (firstItemAdded)
  				bcatcstr(glsl, ", ");
  			else
  				firstItemAdded = 1;
  
  			if (psSrc->eType == OPERAND_TYPE_THREAD_GROUP_SHARED_MEMORY)
  			{
  				// input already in uints
  				TranslateOperand(psContext, psSrc, TO_FLAG_NAME_ONLY);
  				bcatcstr(glsl, "[");
  				TranslateOperand(psContext, psSrcAddr, TO_FLAG_INTEGER);
  				bcatcstr(glsl, "].value[(");
  				TranslateOperand(psContext, psSrcByteOff, TO_FLAG_UNSIGNED_INTEGER);
  				bformata(glsl, " >> 2u) + %d]", psSrc->eSelMode == OPERAND_4_COMPONENT_SWIZZLE_MODE ? psSrc->aui32Swizzle[component] : component);
  			}
  			else
  			{
  				ConstantBuffer *psCBuf = NULL;
  				psVar = LookupStructuredVar(psContext, psSrc, psSrcByteOff, psSrc->eSelMode == OPERAND_4_COMPONENT_SWIZZLE_MODE ? psSrc->aui32Swizzle[component] : component);
  				GetConstantBufferFromBindingPoint(RGROUP_UAV, psSrc->ui32RegisterNumber, &psContext->psShader->sInfo, &psCBuf);
  
  				if (psVar->Type == SVT_FLOAT)
  				{
  					bcatcstr(glsl, "floatBitsToUint(");
  					addedBitcast = 1;
  				}
  				else if (psVar->Type == SVT_DOUBLE)
  				{
  					bcatcstr(glsl, "unpackDouble2x32(");
  					addedBitcast = 1;
  				}
  				if (psSrc->eType == OPERAND_TYPE_UNORDERED_ACCESS_VIEW)
  				{
  					bformata(glsl, "%s[", psCBuf->Name);
  					TranslateOperand(psContext, psSrcAddr, TO_FLAG_INTEGER);
  					bcatcstr(glsl, "]");
  					if (strcmp(psVar->Name, "$Element") != 0)
  					{
  						bcatcstr(glsl, ".");
  						bcatcstr(glsl, psVar->Name);
  					}
  				}
  				else
  				{
  					bformata(glsl, "StructuredRes%d[", psSrc->ui32RegisterNumber);
  					TranslateOperand(psContext, psSrcAddr, TO_FLAG_INTEGER);
  					bcatcstr(glsl, "].");
  
  					bcatcstr(glsl, psVar->Name);
  				}
  
  				if (addedBitcast)
  					bcatcstr(glsl, ")");
  				if (psVar->Type == SVT_DOUBLE)
  					component++; // doubles take up 2 slots
  			}
  
  		}
  		AddAssignPrologue(psContext, numParenthesis);
  
  		return;
  
  	}
  
  #if 0
  
  	//(int)GetNumSwizzleElements(&psInst->asOperands[0])
  	for (component = 0; component < 4; component++)
  	{
  		const char* swizzleString[] = { ".x", ".y", ".z", ".w" };
  		ASSERT(psDest->eSelMode == OPERAND_4_COMPONENT_MASK_MODE);
  		if (psDest->ui32CompMask & (1 << component))
  		{
  			if (structured && psSrc->eType != OPERAND_TYPE_THREAD_GROUP_SHARED_MEMORY)
  			{
  				psVarType = LookupStructuredVar(psContext, psSrc, psSrcByteOff, psSrc->aui32Swizzle[component]);
  			}
  
  			AddIndentation(psContext);
  
  			aui32Swizzle[0] = psSrc->aui32Swizzle[component];
  
  			TranslateOperand(psContext, psDest, TO_FLAG_DESTINATION);
  			if (GetNumSwizzleElements(psDest) > 1)
  				bformata(glsl, swizzleString[destComponent++]);
  
  			if (psVarType)
  			{
  				// TODO completely broken now after AddAssignToDest refactorings.
  				AddAssignToDest(psContext, psDest, SVTTypeToFlag(psVarType->Type), GetNumSwizzleElements(psDest), &numParenthesis);
  			}
  			else
  			{
  				AddAssignToDest(psContext, psDest, TO_FLAG_NONE, GetNumSwizzleElements(psDest), &numParenthesis);
  			}
  
  			if (psSrc->eType == OPERAND_TYPE_RESOURCE)
  			{
  				if (structured)
  					bformata(glsl, "(StructuredRes%d[", psSrc->ui32RegisterNumber);
  				else
  					bformata(glsl, "(RawRes%d[", psSrc->ui32RegisterNumber);
  			}
  			else
  			{
  				bformata(glsl, "(");
  				TranslateOperand(psContext, psSrc, TO_FLAG_NAME_ONLY);
  				bformata(glsl, "[");
  				Translate
  			}
  
  			if (structured) //src address and src byte offset
  			{
  				if (psSrc->eType == OPERAND_TYPE_THREAD_GROUP_SHARED_MEMORY)
  				{
  					TranslateOperand(psContext, psSrcAddr, TO_FLAG_INTEGER | TO_FLAG_UNSIGNED_INTEGER);
  					bformata(glsl, "].value[");
  					TranslateOperand(psContext, psSrcByteOff, TO_FLAG_INTEGER | TO_FLAG_UNSIGNED_INTEGER);
  					bformata(glsl, "/4u ");//bytes to floats
  				}
  				else
  				{
  					TranslateOperand(psContext, psSrcAddr, TO_FLAG_INTEGER | TO_FLAG_UNSIGNED_INTEGER);
  				}
  			}
  			else
  			{
  				TranslateOperand(psContext, psSrcByteOff, TO_FLAG_INTEGER | TO_FLAG_UNSIGNED_INTEGER);
  			}
  
  			//RAW: change component using index offset
  			if (!structured || (psSrc->eType == OPERAND_TYPE_THREAD_GROUP_SHARED_MEMORY))
  			{
  				bformata(glsl, " + %d", psSrc->aui32Swizzle[component]);
  			}
  
  			bformata(glsl, "]");
  			if (structured && psSrc->eType != OPERAND_TYPE_THREAD_GROUP_SHARED_MEMORY)
  			{
  				if (strcmp(psVarType->Name, "$Element") != 0)
  				{
  					bformata(glsl, ".%s", psVarType->Name);
  				}
  
  				if (psVarType->Type == SVT_DOUBLE)
  				{
  					//Double takes an extra slot.
  					component++;
  				}
  			}
  
  			bformata(glsl, ");\n");
  		}
  	}
  #endif
  }
  
  void TranslateAtomicMemOp(HLSLCrossCompilerContext* psContext, Instruction* psInst)
  {
  	bstring glsl = *psContext->currentShaderString;
  	int numParenthesis = 0;
  	ShaderVarType* psVarType = NULL;
  	uint32_t ui32DataTypeFlag = TO_FLAG_INTEGER;
  	const char* func = "";
  	Operand* dest = 0;
  	Operand* previousValue = 0;
  	Operand* destAddr = 0;
  	Operand* src = 0;
  	Operand* compare = 0;
  
  	switch (psInst->eOpcode)
  	{
  	case OPCODE_IMM_ATOMIC_IADD:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//IMM_ATOMIC_IADD\n");
  #endif
  		func = "atomicAdd";
  		previousValue = &psInst->asOperands[0];
  		dest = &psInst->asOperands[1];
  		destAddr = &psInst->asOperands[2];
  		src = &psInst->asOperands[3];
  		break;
  	}
  	case OPCODE_ATOMIC_IADD:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//ATOMIC_IADD\n");
  #endif
  		func = "atomicAdd";
  		dest = &psInst->asOperands[0];
  		destAddr = &psInst->asOperands[1];
  		src = &psInst->asOperands[2];
  		break;
  	}
  	case OPCODE_IMM_ATOMIC_AND:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//IMM_ATOMIC_AND\n");
  #endif
  		func = "atomicAnd";
  		previousValue = &psInst->asOperands[0];
  		dest = &psInst->asOperands[1];
  		destAddr = &psInst->asOperands[2];
  		src = &psInst->asOperands[3];
  		break;
  	}
  	case OPCODE_ATOMIC_AND:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//ATOMIC_AND\n");
  #endif
  		func = "atomicAnd";
  		dest = &psInst->asOperands[0];
  		destAddr = &psInst->asOperands[1];
  		src = &psInst->asOperands[2];
  		break;
  	}
  	case OPCODE_IMM_ATOMIC_OR:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//IMM_ATOMIC_OR\n");
  #endif
  		func = "atomicOr";
  		previousValue = &psInst->asOperands[0];
  		dest = &psInst->asOperands[1];
  		destAddr = &psInst->asOperands[2];
  		src = &psInst->asOperands[3];
  		break;
  	}
  	case OPCODE_ATOMIC_OR:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//ATOMIC_OR\n");
  #endif
  		func = "atomicOr";
  		dest = &psInst->asOperands[0];
  		destAddr = &psInst->asOperands[1];
  		src = &psInst->asOperands[2];
  		break;
  	}
  	case OPCODE_IMM_ATOMIC_XOR:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//IMM_ATOMIC_XOR\n");
  #endif
  		func = "atomicXor";
  		previousValue = &psInst->asOperands[0];
  		dest = &psInst->asOperands[1];
  		destAddr = &psInst->asOperands[2];
  		src = &psInst->asOperands[3];
  		break;
  	}
  	case OPCODE_ATOMIC_XOR:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//ATOMIC_XOR\n");
  #endif
  		func = "atomicXor";
  		dest = &psInst->asOperands[0];
  		destAddr = &psInst->asOperands[1];
  		src = &psInst->asOperands[2];
  		break;
  	}
  
  	case OPCODE_IMM_ATOMIC_EXCH:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//IMM_ATOMIC_EXCH\n");
  #endif
  		func = "atomicExchange";
  		previousValue = &psInst->asOperands[0];
  		dest = &psInst->asOperands[1];
  		destAddr = &psInst->asOperands[2];
  		src = &psInst->asOperands[3];
  		break;
  	}
  	case OPCODE_IMM_ATOMIC_CMP_EXCH:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//IMM_ATOMIC_CMP_EXC\n");
  #endif
  		func = "atomicCompSwap";
  		previousValue = &psInst->asOperands[0];
  		dest = &psInst->asOperands[1];
  		destAddr = &psInst->asOperands[2];
  		compare = &psInst->asOperands[3];
  		src = &psInst->asOperands[4];
  		break;
  	}
  	case OPCODE_ATOMIC_CMP_STORE:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//ATOMIC_CMP_STORE\n");
  #endif
  		func = "atomicCompSwap";
  		previousValue = 0;
  		dest = &psInst->asOperands[0];
  		destAddr = &psInst->asOperands[1];
  		compare = &psInst->asOperands[2];
  		src = &psInst->asOperands[3];
  		break;
  	}
  	case OPCODE_IMM_ATOMIC_UMIN:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//IMM_ATOMIC_UMIN\n");
  #endif
  		func = "atomicMin";
  		previousValue = &psInst->asOperands[0];
  		dest = &psInst->asOperands[1];
  		destAddr = &psInst->asOperands[2];
  		src = &psInst->asOperands[3];
  		break;
  	}
  	case OPCODE_ATOMIC_UMIN:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//ATOMIC_UMIN\n");
  #endif
  		func = "atomicMin";
  		dest = &psInst->asOperands[0];
  		destAddr = &psInst->asOperands[1];
  		src = &psInst->asOperands[2];
  		break;
  	}
  	case OPCODE_IMM_ATOMIC_IMIN:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//IMM_ATOMIC_IMIN\n");
  #endif
  		func = "atomicMin";
  		previousValue = &psInst->asOperands[0];
  		dest = &psInst->asOperands[1];
  		destAddr = &psInst->asOperands[2];
  		src = &psInst->asOperands[3];
  		break;
  	}
  	case OPCODE_ATOMIC_IMIN:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//ATOMIC_IMIN\n");
  #endif
  		func = "atomicMin";
  		dest = &psInst->asOperands[0];
  		destAddr = &psInst->asOperands[1];
  		src = &psInst->asOperands[2];
  		break;
  	}
  	case OPCODE_IMM_ATOMIC_UMAX:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//IMM_ATOMIC_UMAX\n");
  #endif
  		func = "atomicMax";
  		previousValue = &psInst->asOperands[0];
  		dest = &psInst->asOperands[1];
  		destAddr = &psInst->asOperands[2];
  		src = &psInst->asOperands[3];
  		break;
  	}
  	case OPCODE_ATOMIC_UMAX:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//ATOMIC_UMAX\n");
  #endif
  		func = "atomicMax";
  		dest = &psInst->asOperands[0];
  		destAddr = &psInst->asOperands[1];
  		src = &psInst->asOperands[2];
  		break;
  	}
  	case OPCODE_IMM_ATOMIC_IMAX:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//IMM_ATOMIC_IMAX\n");
  #endif
  		func = "atomicMax";
  		previousValue = &psInst->asOperands[0];
  		dest = &psInst->asOperands[1];
  		destAddr = &psInst->asOperands[2];
  		src = &psInst->asOperands[3];
  		break;
  	}
  	case OPCODE_ATOMIC_IMAX:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//ATOMIC_IMAX\n");
  #endif
  		func = "atomicMax";
  		dest = &psInst->asOperands[0];
  		destAddr = &psInst->asOperands[1];
  		src = &psInst->asOperands[2];
  		break;
  	}
  	}
  
  	AddIndentation(psContext);
  
  	psVarType = LookupStructuredVar(psContext, dest, destAddr, 0);
  	if (psVarType->Type == SVT_UINT)
  	{
  		ui32DataTypeFlag = TO_FLAG_UNSIGNED_INTEGER | TO_AUTO_BITCAST_TO_UINT;
  	}
  	else
  	{
  		ui32DataTypeFlag = TO_FLAG_INTEGER | TO_AUTO_BITCAST_TO_INT;
  	}
  
  	if (previousValue)
  	{
  		AddAssignToDest(psContext, previousValue, psVarType->Type, 1, &numParenthesis);
  	}
  	bcatcstr(glsl, func);
  	bformata(glsl, "(");
  	ResourceName(glsl, psContext, RGROUP_UAV, dest->ui32RegisterNumber, 0);
  	bformata(glsl, "[0]");
  	if (strcmp(psVarType->Name, "$Element") != 0)
  	{
  		bformata(glsl, ".%s", psVarType->Name);
  	}
  
  	bcatcstr(glsl, ", ");
  
  	if (compare)
  	{
  		TranslateOperand(psContext, compare, ui32DataTypeFlag);
  		bcatcstr(glsl, ", ");
  	}
  
  	TranslateOperand(psContext, src, ui32DataTypeFlag);
  	bcatcstr(glsl, ")");
  	if (previousValue)
  	{
  		AddAssignPrologue(psContext, numParenthesis);
  	}
  	else
  		bcatcstr(glsl, ";\n");
  }
  
  static void TranslateConditional(HLSLCrossCompilerContext* psContext,
  	Instruction* psInst,
  	bstring glsl)
  {
  	const char* statement = "";
  	if (psInst->eOpcode == OPCODE_BREAKC)
  	{
  		statement = "break";
  	}
  	else if (psInst->eOpcode == OPCODE_CONTINUEC)
  	{
  		statement = "continue";
  	}
  	else if (psInst->eOpcode == OPCODE_RETC)
  	{
  		statement = "return";
  	}
  
  	if (psContext->psShader->ui32MajorVersion < 4)
  	{
  		bcatcstr(glsl, "if(");
  
  		TranslateOperand(psContext, &psInst->asOperands[0], SVTTypeToFlag(GetOperandDataType(psContext, &psInst->asOperands[0])));
  		switch (psInst->eDX9TestType)
  		{
  		case D3DSPC_GT:
  		{
  			bcatcstr(glsl, " > ");
  			break;
  		}
  		case D3DSPC_EQ:
  		{
  			bcatcstr(glsl, " == ");
  			break;
  		}
  		case D3DSPC_GE:
  		{
  			bcatcstr(glsl, " >= ");
  			break;
  		}
  		case D3DSPC_LT:
  		{
  			bcatcstr(glsl, " < ");
  			break;
  		}
  		case D3DSPC_NE:
  		{
  			bcatcstr(glsl, " != ");
  			break;
  		}
  		case D3DSPC_LE:
  		{
  			bcatcstr(glsl, " <= ");
  			break;
  		}
  		case D3DSPC_BOOLEAN:
  		{
  			bcatcstr(glsl, " != 0");
  			break;
  		}
  		default:
  		{
  			break;
  		}
  		}
  
  		if (psInst->eDX9TestType != D3DSPC_BOOLEAN)
  		{
  			TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_NONE);
  		}
  
  		if (psInst->eOpcode != OPCODE_IF)
  		{
  			bformata(glsl, "){ %s; }\n", statement);
  		}
  		else
  		{
  			bcatcstr(glsl, "){\n");
  		}
  	}
  	else
  	{
  		if (psInst->eBooleanTestType == INSTRUCTION_TEST_ZERO)
  		{
  			bcatcstr(glsl, "if((");
  			TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_UNSIGNED_INTEGER);
  
  			if (psInst->eOpcode != OPCODE_IF)
  			{
  				bformata(glsl, ")==0u){%s;}\n", statement);
  			}
  			else
  			{
  				bcatcstr(glsl, ")==0u){\n");
  			}
  		}
  		else
  		{
  			ASSERT(psInst->eBooleanTestType == INSTRUCTION_TEST_NONZERO);
  			bcatcstr(glsl, "if((");
  			TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_UNSIGNED_INTEGER);
  
  			if (psInst->eOpcode != OPCODE_IF)
  			{
  				bformata(glsl, ")!=0u){%s;}\n", statement);
  			}
  			else
  			{
  				bcatcstr(glsl, ")!=0u){\n");
  			}
  		}
  	}
  }
  
  // Returns the "more important" type of a and b, currently int < uint < float
  static SHADER_VARIABLE_TYPE SelectHigherType(SHADER_VARIABLE_TYPE a, SHADER_VARIABLE_TYPE b)
  {
  	if (a == SVT_FLOAT || b == SVT_FLOAT)
  		return SVT_FLOAT;
  	// Apart from floats, the enum values are fairly well-ordered, use that directly.
  	return a > b ? a : b;
  }
  
  // Helper function to set the vector type of 1 or more components in a vector
  // If the existing values (that we're writing to) are all SVT_VOID, just upgrade the value and we're done
  // Otherwise, set all the components in the vector that currently are set to that same value OR are now being written to
  // to the "highest" type value (ordering int->uint->float)
  static void SetVectorType(SHADER_VARIABLE_TYPE *aeTempVecType, uint32_t regBaseIndex, uint32_t componentMask, SHADER_VARIABLE_TYPE eType)
  {
  	int existingTypesFound = 0;
  	int i = 0;
  	for (i = 0; i < 4; i++)
  	{
  		if (componentMask & (1 << i))
  		{
  			if (aeTempVecType[regBaseIndex + i] != SVT_VOID)
  			{
  				existingTypesFound = 1;
  				break;
  			}
  		}
  	}
  
  	if (existingTypesFound != 0)
  	{
  		// Expand the mask to include all components that are used, also upgrade type
  		for (i = 0; i < 4; i++)
  		{
  			if (aeTempVecType[regBaseIndex + i] != SVT_VOID)
  			{
  				componentMask |= (1 << i);
  				eType = SelectHigherType(eType, aeTempVecType[regBaseIndex + i]);
  			}
  		}
  	}
  
  	// Now componentMask contains the components we actually need to update and eType may have been changed to something else.
  	// Write the results
  	for (i = 0; i < 4; i++)
  	{
  		if (componentMask & (1 << i))
  		{
  			aeTempVecType[regBaseIndex + i] = eType;
  		}
  	}
  
  }
  
  static void MarkOperandAs(Operand *psOperand, SHADER_VARIABLE_TYPE eType, SHADER_VARIABLE_TYPE *aeTempVecType)
  {
  	if (psOperand->eType == OPERAND_TYPE_INDEXABLE_TEMP || psOperand->eType == OPERAND_TYPE_TEMP)
  	{
  		const uint32_t ui32RegIndex = psOperand->ui32RegisterNumber * 4;
  
  		if (psOperand->eSelMode == OPERAND_4_COMPONENT_SELECT_1_MODE)
  		{
  			SetVectorType(aeTempVecType, ui32RegIndex, 1 << psOperand->aui32Swizzle[0], eType);
  		}
  		else if (psOperand->eSelMode == OPERAND_4_COMPONENT_SWIZZLE_MODE)
  		{
  			// 0xf == all components, swizzle order doesn't matter.
  			SetVectorType(aeTempVecType, ui32RegIndex, 0xf, eType);
  		}
  		else if (psOperand->eSelMode == OPERAND_4_COMPONENT_MASK_MODE)
  		{
  			uint32_t ui32CompMask = psOperand->ui32CompMask;
  			if (!psOperand->ui32CompMask)
  			{
  				ui32CompMask = OPERAND_4_COMPONENT_MASK_ALL;
  			}
  
  			SetVectorType(aeTempVecType, ui32RegIndex, ui32CompMask, eType);
  		}
  	}
  }
  
  static void MarkAllOperandsAs(Instruction* psInst, SHADER_VARIABLE_TYPE eType, SHADER_VARIABLE_TYPE *aeTempVecType)
  {
  	uint32_t i = 0;
  	for (i = 0; i < psInst->ui32NumOperands; i++)
  	{
  		MarkOperandAs(&psInst->asOperands[i], eType, aeTempVecType);
  	}
  }
  
  static void WriteOperandTypes(Operand *psOperand, const SHADER_VARIABLE_TYPE *aeTempVecType)
  {
  	const uint32_t ui32RegIndex = psOperand->ui32RegisterNumber * 4;
  
  	if (psOperand->eType != OPERAND_TYPE_TEMP)
  		return;
  
  	if (psOperand->eSelMode == OPERAND_4_COMPONENT_SELECT_1_MODE)
  	{
  		psOperand->aeDataType[psOperand->aui32Swizzle[0]] = aeTempVecType[ui32RegIndex + psOperand->aui32Swizzle[0]];
  	}
  	else if (psOperand->eSelMode == OPERAND_4_COMPONENT_SWIZZLE_MODE)
  	{
  		if (psOperand->ui32Swizzle == (NO_SWIZZLE))
  		{
  			psOperand->aeDataType[0] = aeTempVecType[ui32RegIndex];
  			psOperand->aeDataType[1] = aeTempVecType[ui32RegIndex + 1];
  			psOperand->aeDataType[2] = aeTempVecType[ui32RegIndex + 2];
  			psOperand->aeDataType[3] = aeTempVecType[ui32RegIndex + 3];
  		}
  		else
  		{
  			psOperand->aeDataType[psOperand->aui32Swizzle[0]] = aeTempVecType[ui32RegIndex + psOperand->aui32Swizzle[0]];
  			psOperand->aeDataType[psOperand->aui32Swizzle[1]] = aeTempVecType[ui32RegIndex + psOperand->aui32Swizzle[1]];
  			psOperand->aeDataType[psOperand->aui32Swizzle[2]] = aeTempVecType[ui32RegIndex + psOperand->aui32Swizzle[2]];
  			psOperand->aeDataType[psOperand->aui32Swizzle[3]] = aeTempVecType[ui32RegIndex + psOperand->aui32Swizzle[3]];
  		}
  	}
  	else if (psOperand->eSelMode == OPERAND_4_COMPONENT_MASK_MODE)
  	{
  		int c = 0;
  		uint32_t ui32CompMask = psOperand->ui32CompMask;
  		if (!psOperand->ui32CompMask)
  		{
  			ui32CompMask = OPERAND_4_COMPONENT_MASK_ALL;
  		}
  
  		for (; c < 4; ++c)
  		{
  			if (ui32CompMask & (1 << c))
  			{
  				psOperand->aeDataType[c] = aeTempVecType[ui32RegIndex + c];
  			}
  		}
  	}
  }
  
  // Mark scalars from CBs. TODO: Do we need to do the same for vec2/3's as well? There may be swizzles involved which make it vec4 or something else again.
  static void SetCBOperandComponents(HLSLCrossCompilerContext *psContext, Operand *psOperand)
  {
  	ConstantBuffer* psCBuf = NULL;
  	ShaderVarType* psVarType = NULL;
  	int32_t index = -1;
  	int rebase = 0;
  
  	if (psOperand->eType != OPERAND_TYPE_CONSTANT_BUFFER)
  		return;
  
  	GetConstantBufferFromBindingPoint(RGROUP_CBUFFER, psOperand->aui32ArraySizes[0], &psContext->psShader->sInfo, &psCBuf);
  	GetShaderVarFromOffset(psOperand->aui32ArraySizes[1], psOperand->aui32Swizzle, psCBuf, &psVarType, &index, &rebase);
  
  	if (psVarType->Class == SVC_SCALAR)
  		psOperand->iNumComponents = 1;
  
  }
  
  
  void SetDataTypes(HLSLCrossCompilerContext* psContext, Instruction* psInst, const int32_t i32InstCount)
  {
  	int32_t i;
  	Instruction *psFirstInst = psInst;
  
  	SHADER_VARIABLE_TYPE aeTempVecType[MAX_TEMP_VEC4 * 4];
  
  	if (psContext->psShader->ui32MajorVersion <= 3)
  	{
  		for (i = 0; i < MAX_TEMP_VEC4 * 4; ++i)
  		{
  			aeTempVecType[i] = SVT_FLOAT;
  		}
  	}
  	else
  	{
  		// Start with void, then move up the chain void->int->uint->float
  		for (i = 0; i < MAX_TEMP_VEC4 * 4; ++i)
  		{
  			aeTempVecType[i] = SVT_VOID;
  		}
  	}
  
  //	if (psContext->psShader->ui32MajorVersion <= 3)
  	{
  		// First pass, do analysis: deduce the data type based on opcodes, fill out aeTempVecType table
  		// Only ever to int->float promotion (or int->uint), never the other way around
  		for (i = 0; i < i32InstCount; ++i, psInst++)
  		{
  			int k = 0;
  			if (psInst->ui32NumOperands == 0)
  				continue;
  
  			switch (psInst->eOpcode)
  			{
  				// All float-only ops
  			case OPCODE_ADD:
  			case OPCODE_DERIV_RTX:
  			case OPCODE_DERIV_RTY:
  			case OPCODE_DIV:
  			case OPCODE_DP2:
  			case OPCODE_DP3:
  			case OPCODE_DP4:
  			case OPCODE_EQ:
  			case OPCODE_EXP:
  			case OPCODE_FRC:
  			case OPCODE_LOG:
  			case OPCODE_MAD:
  			case OPCODE_MIN:
  			case OPCODE_MAX:
  			case OPCODE_MUL:
  			case OPCODE_NE:
  			case OPCODE_ROUND_NE:
  			case OPCODE_ROUND_NI:
  			case OPCODE_ROUND_PI:
  			case OPCODE_ROUND_Z:
  			case OPCODE_RSQ:
  			case OPCODE_SAMPLE:
  			case OPCODE_SAMPLE_C:
  			case OPCODE_SAMPLE_C_LZ:
  			case OPCODE_SAMPLE_L:
  			case OPCODE_SAMPLE_D:
  			case OPCODE_SAMPLE_B:
  			case OPCODE_SQRT:
  			case OPCODE_SINCOS:
  			case OPCODE_LOD:
  			case OPCODE_GATHER4:
  
  			case OPCODE_DERIV_RTX_COARSE:
  			case OPCODE_DERIV_RTX_FINE:
  			case OPCODE_DERIV_RTY_COARSE:
  			case OPCODE_DERIV_RTY_FINE:
  			case OPCODE_GATHER4_C:
  			case OPCODE_GATHER4_PO:
  			case OPCODE_GATHER4_PO_C:
  			case OPCODE_RCP:
  
  				MarkAllOperandsAs(psInst, SVT_FLOAT, aeTempVecType);
  				break;
  
  				// Int-only ops, no need to do anything
  			case OPCODE_AND:
  			case OPCODE_BREAKC:
  			case OPCODE_CALLC:
  			case OPCODE_CONTINUEC:
  			case OPCODE_IADD:
  			case OPCODE_IEQ:
  			case OPCODE_IGE:
  			case OPCODE_ILT:
  			case OPCODE_IMAD:
  			case OPCODE_IMAX:
  			case OPCODE_IMIN:
  			case OPCODE_IMUL:
  			case OPCODE_INE:
  			case OPCODE_INEG:
  			case OPCODE_ISHL:
  			case OPCODE_ISHR:
  			case OPCODE_IF:
  			case OPCODE_NOT:
  			case OPCODE_OR:
  			case OPCODE_RETC:
  			case OPCODE_XOR:
  			case OPCODE_BUFINFO:
  			case OPCODE_COUNTBITS:
  			case OPCODE_FIRSTBIT_HI:
  			case OPCODE_FIRSTBIT_LO:
  			case OPCODE_FIRSTBIT_SHI:
  			case OPCODE_UBFE:
  			case OPCODE_IBFE:
  			case OPCODE_BFI:
  			case OPCODE_BFREV:
  			case OPCODE_ATOMIC_AND:
  			case OPCODE_ATOMIC_OR:
  			case OPCODE_ATOMIC_XOR:
  			case OPCODE_ATOMIC_CMP_STORE:
  			case OPCODE_ATOMIC_IADD:
  			case OPCODE_ATOMIC_IMAX:
  			case OPCODE_ATOMIC_IMIN:
  			case OPCODE_ATOMIC_UMAX:
  			case OPCODE_ATOMIC_UMIN:
  			case OPCODE_IMM_ATOMIC_ALLOC:
  			case OPCODE_IMM_ATOMIC_CONSUME:
  			case OPCODE_IMM_ATOMIC_IADD:
  			case OPCODE_IMM_ATOMIC_AND:
  			case OPCODE_IMM_ATOMIC_OR:
  			case OPCODE_IMM_ATOMIC_XOR:
  			case OPCODE_IMM_ATOMIC_EXCH:
  			case OPCODE_IMM_ATOMIC_CMP_EXCH:
  			case OPCODE_IMM_ATOMIC_IMAX:
  			case OPCODE_IMM_ATOMIC_IMIN:
  			case OPCODE_IMM_ATOMIC_UMAX:
  			case OPCODE_IMM_ATOMIC_UMIN:
  			case OPCODE_MOV:
  			case OPCODE_MOVC:
  			case OPCODE_SWAPC:
  				MarkAllOperandsAs(psInst, SVT_INT, aeTempVecType);
  				break;
  				// uint ops
  			case OPCODE_UDIV:
  			case OPCODE_ULT:
  			case OPCODE_UGE:
  			case OPCODE_UMUL:
  			case OPCODE_UMAD:
  			case OPCODE_UMAX:
  			case OPCODE_UMIN:
  			case OPCODE_USHR:
  			case OPCODE_UADDC:
  			case OPCODE_USUBB:
  				MarkAllOperandsAs(psInst, SVT_UINT, aeTempVecType);
  				break;
  
  				// Need special handling
  			case OPCODE_FTOI:
  			case OPCODE_FTOU:
  				MarkOperandAs(&psInst->asOperands[0], psInst->eOpcode == OPCODE_FTOI ? SVT_INT : SVT_UINT, aeTempVecType);
  				MarkOperandAs(&psInst->asOperands[1], SVT_FLOAT, aeTempVecType);
  				break;
  
  			case OPCODE_GE:
  			case OPCODE_LT:
  				MarkOperandAs(&psInst->asOperands[0], SVT_UINT, aeTempVecType);
  				MarkOperandAs(&psInst->asOperands[1], SVT_FLOAT, aeTempVecType);
  				MarkOperandAs(&psInst->asOperands[2], SVT_FLOAT, aeTempVecType);
  				break;
  
  			case OPCODE_ITOF:
  			case OPCODE_UTOF:
  				MarkOperandAs(&psInst->asOperands[0], SVT_FLOAT, aeTempVecType);
  				MarkOperandAs(&psInst->asOperands[1], psInst->eOpcode == OPCODE_ITOF ? SVT_INT : SVT_UINT, aeTempVecType);
  				break;
  
  			case OPCODE_LD:
  			case OPCODE_LD_MS:
  				// TODO: Would need to know the sampler return type
  				MarkOperandAs(&psInst->asOperands[0], SVT_FLOAT, aeTempVecType);
  				break;
  
  
  			case OPCODE_RESINFO:
  			{
  				if (psInst->eResInfoReturnType != RESINFO_INSTRUCTION_RETURN_UINT)
  					MarkAllOperandsAs(psInst, SVT_FLOAT, aeTempVecType);
  				break;
  			}
  
  			case OPCODE_SAMPLE_INFO:
  				// TODO decode the _uint flag
  				MarkOperandAs(&psInst->asOperands[0], SVT_FLOAT, aeTempVecType);
  				break;
  
  			case OPCODE_SAMPLE_POS:
  				MarkOperandAs(&psInst->asOperands[0], SVT_FLOAT, aeTempVecType);
  				break;
  
  
  			case OPCODE_LD_UAV_TYPED:
  			case OPCODE_STORE_UAV_TYPED:
  			case OPCODE_LD_RAW:
  			case OPCODE_STORE_RAW:
  			case OPCODE_LD_STRUCTURED:
  			case OPCODE_STORE_STRUCTURED:
  				MarkOperandAs(&psInst->asOperands[0], SVT_INT, aeTempVecType);
  				break;
  
  			case OPCODE_F32TOF16:
  			case OPCODE_F16TOF32:
  				// TODO
  				break;
  
  
  
  				// No-operands, should never get here anyway
  				/*				case OPCODE_BREAK:
  								case OPCODE_CALL:
  								case OPCODE_CASE:
  								case OPCODE_CONTINUE:
  								case OPCODE_CUT:
  								case OPCODE_DEFAULT:
  								case OPCODE_DISCARD:
  								case OPCODE_ELSE:
  								case OPCODE_EMIT:
  								case OPCODE_EMITTHENCUT:
  								case OPCODE_ENDIF:
  								case OPCODE_ENDLOOP:
  								case OPCODE_ENDSWITCH:
  
  								case OPCODE_LABEL:
  								case OPCODE_LOOP:
  								case OPCODE_CUSTOMDATA:
  								case OPCODE_NOP:
  								case OPCODE_RET:
  								case OPCODE_SWITCH:
  								case OPCODE_DCL_RESOURCE: // DCL* opcodes have
  								case OPCODE_DCL_CONSTANT_BUFFER: // custom operand formats.
  								case OPCODE_DCL_SAMPLER:
  								case OPCODE_DCL_INDEX_RANGE:
  								case OPCODE_DCL_GS_OUTPUT_PRIMITIVE_TOPOLOGY:
  								case OPCODE_DCL_GS_INPUT_PRIMITIVE:
  								case OPCODE_DCL_MAX_OUTPUT_VERTEX_COUNT:
  								case OPCODE_DCL_INPUT:
  								case OPCODE_DCL_INPUT_SGV:
  								case OPCODE_DCL_INPUT_SIV:
  								case OPCODE_DCL_INPUT_PS:
  								case OPCODE_DCL_INPUT_PS_SGV:
  								case OPCODE_DCL_INPUT_PS_SIV:
  								case OPCODE_DCL_OUTPUT:
  								case OPCODE_DCL_OUTPUT_SGV:
  								case OPCODE_DCL_OUTPUT_SIV:
  								case OPCODE_DCL_TEMPS:
  								case OPCODE_DCL_INDEXABLE_TEMP:
  								case OPCODE_DCL_GLOBAL_FLAGS:
  
  
  								case OPCODE_HS_DECLS: // token marks beginning of HS sub-shader
  								case OPCODE_HS_CONTROL_POINT_PHASE: // token marks beginning of HS sub-shader
  								case OPCODE_HS_FORK_PHASE: // token marks beginning of HS sub-shader
  								case OPCODE_HS_JOIN_PHASE: // token marks beginning of HS sub-shader
  
  								case OPCODE_EMIT_STREAM:
  								case OPCODE_CUT_STREAM:
  								case OPCODE_EMITTHENCUT_STREAM:
  								case OPCODE_INTERFACE_CALL:
  
  
  								case OPCODE_DCL_STREAM:
  								case OPCODE_DCL_FUNCTION_BODY:
  								case OPCODE_DCL_FUNCTION_TABLE:
  								case OPCODE_DCL_INTERFACE:
  
  								case OPCODE_DCL_INPUT_CONTROL_POINT_COUNT:
  								case OPCODE_DCL_OUTPUT_CONTROL_POINT_COUNT:
  								case OPCODE_DCL_TESS_DOMAIN:
  								case OPCODE_DCL_TESS_PARTITIONING:
  								case OPCODE_DCL_TESS_OUTPUT_PRIMITIVE:
  								case OPCODE_DCL_HS_MAX_TESSFACTOR:
  								case OPCODE_DCL_HS_FORK_PHASE_INSTANCE_COUNT:
  								case OPCODE_DCL_HS_JOIN_PHASE_INSTANCE_COUNT:
  
  								case OPCODE_DCL_THREAD_GROUP:
  								case OPCODE_DCL_UNORDERED_ACCESS_VIEW_TYPED:
  								case OPCODE_DCL_UNORDERED_ACCESS_VIEW_RAW:
  								case OPCODE_DCL_UNORDERED_ACCESS_VIEW_STRUCTURED:
  								case OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_RAW:
  								case OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_STRUCTURED:
  								case OPCODE_DCL_RESOURCE_RAW:
  								case OPCODE_DCL_RESOURCE_STRUCTURED:
  								case OPCODE_SYNC:
  
  								// TODO
  								case OPCODE_DADD:
  								case OPCODE_DMAX:
  								case OPCODE_DMIN:
  								case OPCODE_DMUL:
  								case OPCODE_DEQ:
  								case OPCODE_DGE:
  								case OPCODE_DLT:
  								case OPCODE_DNE:
  								case OPCODE_DMOV:
  								case OPCODE_DMOVC:
  								case OPCODE_DTOF:
  								case OPCODE_FTOD:
  
  								case OPCODE_EVAL_SNAPPED:
  								case OPCODE_EVAL_SAMPLE_INDEX:
  								case OPCODE_EVAL_CENTROID:
  
  								case OPCODE_DCL_GS_INSTANCE_COUNT:
  
  								case OPCODE_ABORT:
  								case OPCODE_DEBUG_BREAK:*/
  
  			default:
  				break;
  			}
  		}
  	}
  
  	// Fill the rest of aeTempVecType, just in case.
  	for (i = 0; i < MAX_TEMP_VEC4 * 4; i++)
  	{
  		if (aeTempVecType[i] == SVT_VOID)
  			aeTempVecType[i] = SVT_INT;
  	}
  
  	// Now the aeTempVecType table has been filled with (mostly) valid data, write it back to all operands
  	psInst = psFirstInst;
  	for (i = 0; i < i32InstCount; ++i, psInst++)
  	{
  		int k = 0;
  
  		if (psInst->ui32NumOperands == 0)
  			continue;
  
  		//Preserve the current type on dest array index
  		if (psInst->asOperands[0].eType == OPERAND_TYPE_INDEXABLE_TEMP)
  		{
  			Operand* psSubOperand = psInst->asOperands[0].psSubOperand[1];
  			if (psSubOperand != 0)
  			{
  				WriteOperandTypes(psSubOperand, aeTempVecType);
  			}
  		}
  		if (psInst->asOperands[0].eType == OPERAND_TYPE_CONSTANT_BUFFER)
  			SetCBOperandComponents(psContext, &psInst->asOperands[0]);
  
  		//Preserve the current type on sources.
  		for (k = psInst->ui32NumOperands - 1; k >= (int)psInst->ui32FirstSrc; --k)
  		{
  			int32_t subOperand;
  			Operand* psOperand = &psInst->asOperands[k];
  
  			WriteOperandTypes(psOperand, aeTempVecType);
  			if (psOperand->eType == OPERAND_TYPE_CONSTANT_BUFFER)
  				SetCBOperandComponents(psContext, psOperand);
  
  			for (subOperand = 0; subOperand < MAX_SUB_OPERANDS; subOperand++)
  			{
  				if (psOperand->psSubOperand[subOperand] != 0)
  				{
  					Operand* psSubOperand = psOperand->psSubOperand[subOperand];
  					WriteOperandTypes(psSubOperand, aeTempVecType);
  					if (psSubOperand->eType == OPERAND_TYPE_CONSTANT_BUFFER)
  						SetCBOperandComponents(psContext, psSubOperand);
  				}
  			}
  
  			//Set immediates
  			if (IsIntegerImmediateOpcode(psInst->eOpcode))
  			{
  				if (psOperand->eType == OPERAND_TYPE_IMMEDIATE32)
  				{
  					psOperand->iIntegerImmediate = 1;
  				}
  			}
  		}
  
  		//Process the destination last in order to handle instructions
  		//where the destination register is also used as a source.
  		for (k = 0; k < (int)psInst->ui32FirstSrc; ++k)
  		{
  			Operand* psOperand = &psInst->asOperands[k];
  			WriteOperandTypes(psOperand, aeTempVecType);
  		}
  	}
  }
  
  void TranslateInstruction(HLSLCrossCompilerContext* psContext, Instruction* psInst, Instruction* psNextInst)
  {
  	bstring glsl = *psContext->currentShaderString;
  	int numParenthesis = 0;
  
  #ifdef _DEBUG
  	AddIndentation(psContext);
  	bformata(glsl, "//Instruction %d\n", psInst->id);
  #if 0
  	if(psInst->id == 73)
  	{
  		ASSERT(1); //Set breakpoint here to debug an instruction from its ID.
  	}
  #endif
  #endif
  
  	switch (psInst->eOpcode)
  	{
  	case OPCODE_FTOI:
  	case OPCODE_FTOU:
  	{
  		uint32_t dstCount = GetNumSwizzleElements(&psInst->asOperands[0]);
  		uint32_t srcCount = GetNumSwizzleElements(&psInst->asOperands[1]);
  		uint32_t ui32DstFlags = TO_FLAG_DESTINATION;
  		const SHADER_VARIABLE_TYPE eSrcType = GetOperandDataType(psContext, &psInst->asOperands[1]);
  		const SHADER_VARIABLE_TYPE eDestType = GetOperandDataType(psContext, &psInst->asOperands[0]);
  
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		if (psInst->eOpcode == OPCODE_FTOU)
  			bcatcstr(glsl, "//FTOU\n");
  		else
  			bcatcstr(glsl, "//FTOI\n");
  #endif
  
  		AddIndentation(psContext);
  
  		AddAssignToDest(psContext, &psInst->asOperands[0], psInst->eOpcode == OPCODE_FTOU ? SVT_UINT : SVT_INT, srcCount, &numParenthesis);
  		bcatcstr(glsl, GetConstructorForType(psInst->eOpcode == OPCODE_FTOU ? SVT_UINT : SVT_INT, srcCount == dstCount ? dstCount : 4));
  		bcatcstr(glsl, "("); // 1
  		TranslateOperand(psContext, &psInst->asOperands[1], TO_AUTO_BITCAST_TO_FLOAT);
  		bcatcstr(glsl, ")"); // 1
  		// Add destination writemask if the component counts do not match
  		if (srcCount != dstCount)
  			AddSwizzleUsingElementCount(psContext, dstCount);
  		AddAssignPrologue(psContext, numParenthesis);
  		break;
  	}
  
  	case OPCODE_MOV:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//MOV\n");
  #endif
  		AddIndentation(psContext);
  		AddMOVBinaryOp(psContext, &psInst->asOperands[0], &psInst->asOperands[1]);
  		break;
  	}
  	case OPCODE_ITOF://signed to float
  	case OPCODE_UTOF://unsigned to float
  	{
  		const SHADER_VARIABLE_TYPE eDestType = GetOperandDataType(psContext, &psInst->asOperands[0]);
  		const SHADER_VARIABLE_TYPE eSrcType = GetOperandDataType(psContext, &psInst->asOperands[1]);
  		uint32_t dstCount = GetNumSwizzleElements(&psInst->asOperands[0]);
  		uint32_t srcCount = GetNumSwizzleElements(&psInst->asOperands[1]);
  
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		if (psInst->eOpcode == OPCODE_ITOF)
  		{
  			bcatcstr(glsl, "//ITOF\n");
  		}
  		else
  		{
  			bcatcstr(glsl, "//UTOF\n");
  		}
  #endif
  		AddIndentation(psContext);
  		AddAssignToDest(psContext, &psInst->asOperands[0], SVT_FLOAT, srcCount, &numParenthesis);
  		bcatcstr(glsl, GetConstructorForType(SVT_FLOAT, srcCount == dstCount ? dstCount : 4));
  		bcatcstr(glsl, "("); // 1
  		TranslateOperand(psContext, &psInst->asOperands[1], psInst->eOpcode == OPCODE_UTOF ? TO_AUTO_BITCAST_TO_UINT : TO_AUTO_BITCAST_TO_INT);
  		bcatcstr(glsl, ")"); // 1
  		// Add destination writemask if the component counts do not match
  		if (srcCount != dstCount)
  			AddSwizzleUsingElementCount(psContext, dstCount);
  		AddAssignPrologue(psContext, numParenthesis);
  		break;
  	}
  	case OPCODE_MAD:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//MAD\n");
  #endif
  		CallTernaryOp(psContext, "*", "+", psInst, 0, 1, 2, 3, TO_FLAG_NONE);
  		break;
  	}
  	case OPCODE_IMAD:
  	{
  		uint32_t ui32Flags = TO_FLAG_INTEGER;
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//IMAD\n");
  #endif
  
  		if (GetOperandDataType(psContext, &psInst->asOperands[0]) == SVT_UINT)
  		{
  			ui32Flags = TO_FLAG_UNSIGNED_INTEGER;
  		}
  
  		CallTernaryOp(psContext, "*", "+", psInst, 0, 1, 2, 3, ui32Flags);
  		break;
  	}
  	case OPCODE_DADD:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//DADD\n");
  #endif
  		CallBinaryOp(psContext, "+", psInst, 0, 1, 2, SVT_DOUBLE);
  		break;
  	}
  	case OPCODE_IADD:
  	{
  		SHADER_VARIABLE_TYPE eType = SVT_INT;
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//IADD\n");
  #endif
  		//Is this a signed or unsigned add?
  		if (GetOperandDataType(psContext, &psInst->asOperands[0]) == SVT_UINT)
  		{
  			eType = SVT_UINT;
  		}
  		CallBinaryOp(psContext, "+", psInst, 0, 1, 2, eType);
  		break;
  	}
  	case OPCODE_ADD:
  	{
  
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//ADD\n");
  #endif
  		CallBinaryOp(psContext, "+", psInst, 0, 1, 2, SVT_FLOAT);
  		break;
  	}
  	case OPCODE_OR:
  	{
  		/*Todo: vector version */
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//OR\n");
  #endif
  		CallBinaryOp(psContext, "|", psInst, 0, 1, 2, SVT_UINT);
  		break;
  	}
  	case OPCODE_AND:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//AND\n");
  #endif
  		CallBinaryOp(psContext, "&", psInst, 0, 1, 2, SVT_UINT);
  		break;
  	}
  	case OPCODE_GE:
  	{
  		/*
  			dest = vec4(greaterThanEqual(vec4(srcA), vec4(srcB));
  			Caveat: The result is a boolean but HLSL asm returns 0xFFFFFFFF/0x0 instead.
  			*/
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//GE\n");
  #endif
  		AddComparision(psContext, psInst, CMP_GE, TO_FLAG_NONE, NULL);
  		break;
  	}
  	case OPCODE_MUL:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//MUL\n");
  #endif
  		CallBinaryOp(psContext, "*", psInst, 0, 1, 2, SVT_FLOAT);
  		break;
  	}
  	case OPCODE_IMUL:
  	{
  		SHADER_VARIABLE_TYPE eType = SVT_INT;
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//IMUL\n");
  #endif
  		if (GetOperandDataType(psContext, &psInst->asOperands[1]) == SVT_UINT)
  		{
  			eType = SVT_UINT;
  		}
  
  		ASSERT(psInst->asOperands[0].eType == OPERAND_TYPE_NULL);
  
  		CallBinaryOp(psContext, "*", psInst, 1, 2, 3, eType);
  		break;
  	}
  	case OPCODE_UDIV:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//UDIV\n");
  #endif
  		//destQuotient, destRemainder, src0, src1
  		CallBinaryOp(psContext, "/", psInst, 0, 2, 3, SVT_UINT);
  		CallBinaryOp(psContext, "%", psInst, 1, 2, 3, SVT_UINT);
  		break;
  	}
  	case OPCODE_DIV:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//DIV\n");
  #endif
  		CallBinaryOp(psContext, "/", psInst, 0, 1, 2, SVT_FLOAT);
  		break;
  	}
  	case OPCODE_SINCOS:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//SINCOS\n");
  #endif
  		// Need careful ordering if src == dest[0], as then the cos() will be reading from wrong value
  		if (psInst->asOperands[0].eType == psInst->asOperands[2].eType &&
  			psInst->asOperands[0].ui32RegisterNumber == psInst->asOperands[2].ui32RegisterNumber)
  		{
  			// sin() result overwrites source, do cos() first.
  			// The case where both write the src shouldn't really happen anyway.
  			if (psInst->asOperands[1].eType != OPERAND_TYPE_NULL)
  			{
  				CallHelper1(psContext, "cos", psInst, 1, 2, 1);
  			}
  
  			if (psInst->asOperands[0].eType != OPERAND_TYPE_NULL)
  			{
  				CallHelper1(psContext, "sin", psInst, 0, 2, 1);
  			}
  		}
  		else
  		{
  			if (psInst->asOperands[0].eType != OPERAND_TYPE_NULL)
  			{
  				CallHelper1(psContext, "sin", psInst, 0, 2, 1);
  			}
  
  			if (psInst->asOperands[1].eType != OPERAND_TYPE_NULL)
  			{
  				CallHelper1(psContext, "cos", psInst, 1, 2, 1);
  			}
  		}
  		break;
  	}
  
  	case OPCODE_DP2:
  	{
  		SHADER_VARIABLE_TYPE eDestDataType = GetOperandDataType(psContext, &psInst->asOperands[0]);
  		int numParenthesis = 0;
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//DP2\n");
  #endif
  		AddIndentation(psContext);
  		AddAssignToDest(psContext, &psInst->asOperands[0], SVT_FLOAT, 1, &numParenthesis);
  		bcatcstr(glsl, "dot(");
  		TranslateOperandWithMask(psContext, &psInst->asOperands[1], TO_AUTO_BITCAST_TO_FLOAT, 3 /* .xy */);
  		bcatcstr(glsl, ", ");
  		TranslateOperandWithMask(psContext, &psInst->asOperands[2], TO_AUTO_BITCAST_TO_FLOAT, 3 /* .xy */);
  		bcatcstr(glsl, ")");
  		AddAssignPrologue(psContext, numParenthesis);
  		break;
  	}
  	case OPCODE_DP3:
  	{
  		int numParenthesis = 0;
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//DP3\n");
  #endif
  		AddIndentation(psContext);
  		AddAssignToDest(psContext, &psInst->asOperands[0], SVT_FLOAT, 1, &numParenthesis);
  		bcatcstr(glsl, "dot(");
  		TranslateOperandWithMask(psContext, &psInst->asOperands[1], TO_AUTO_BITCAST_TO_FLOAT, 7 /* .xyz */);
  		bcatcstr(glsl, ", ");
  		TranslateOperandWithMask(psContext, &psInst->asOperands[2], TO_AUTO_BITCAST_TO_FLOAT, 7 /* .xyz */);
  		bcatcstr(glsl, ")");
  		AddAssignPrologue(psContext, numParenthesis);
  		break;
  	}
  	case OPCODE_DP4:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//DP4\n");
  #endif
  		CallHelper2(psContext, "dot", psInst, 0, 1, 2, 0);
  		break;
  	}
  	case OPCODE_INE:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//INE\n");
  #endif
  		AddComparision(psContext, psInst, CMP_NE, TO_FLAG_INTEGER, NULL);
  		break;
  	}
  	case OPCODE_NE:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//NE\n");
  #endif
  		AddComparision(psContext, psInst, CMP_NE, TO_FLAG_NONE, NULL);
  		break;
  	}
  	case OPCODE_IGE:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//IGE\n");
  #endif
  		AddComparision(psContext, psInst, CMP_GE, TO_FLAG_INTEGER, psNextInst);
  		break;
  	}
  	case OPCODE_ILT:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//ILT\n");
  #endif
  		AddComparision(psContext, psInst, CMP_LT, TO_FLAG_INTEGER, NULL);
  		break;
  	}
  	case OPCODE_LT:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//LT\n");
  #endif
  		AddComparision(psContext, psInst, CMP_LT, TO_FLAG_NONE, NULL);
  		break;
  	}
  	case OPCODE_IEQ:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//IEQ\n");
  #endif
  		AddComparision(psContext, psInst, CMP_EQ, TO_FLAG_INTEGER, NULL);
  		break;
  	}
  	case OPCODE_ULT:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//ULT\n");
  #endif
  		AddComparision(psContext, psInst, CMP_LT, TO_FLAG_UNSIGNED_INTEGER, NULL);
  		break;
  	}
  	case OPCODE_UGE:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//UGE\n");
  #endif
  		AddComparision(psContext, psInst, CMP_GE, TO_FLAG_UNSIGNED_INTEGER, NULL);
  		break;
  	}
  	case OPCODE_MOVC:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//MOVC\n");
  #endif
  		AddMOVCBinaryOp(psContext, &psInst->asOperands[0], &psInst->asOperands[1], &psInst->asOperands[2], &psInst->asOperands[3]);
  		break;
  	}
  	case OPCODE_SWAPC:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//SWAPC\n");
  #endif
  		// TODO needs temps!!
  		AddMOVCBinaryOp(psContext, &psInst->asOperands[0], &psInst->asOperands[2], &psInst->asOperands[4], &psInst->asOperands[3]);
  		AddMOVCBinaryOp(psContext, &psInst->asOperands[1], &psInst->asOperands[2], &psInst->asOperands[3], &psInst->asOperands[4]);
  		break;
  	}
  
  	case OPCODE_LOG:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//LOG\n");
  #endif
  		CallHelper1(psContext, "log2", psInst, 0, 1, 1);
  		break;
  	}
  	case OPCODE_RSQ:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//RSQ\n");
  #endif
  		CallHelper1(psContext, "inversesqrt", psInst, 0, 1, 1);
  		break;
  	}
  	case OPCODE_EXP:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//EXP\n");
  #endif
  		CallHelper1(psContext, "exp2", psInst, 0, 1, 1);
  		break;
  	}
  	case OPCODE_SQRT:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//SQRT\n");
  #endif
  		CallHelper1(psContext, "sqrt", psInst, 0, 1, 1);
  		break;
  	}
  	case OPCODE_ROUND_PI:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//ROUND_PI\n");
  #endif
  		CallHelper1(psContext, "ceil", psInst, 0, 1, 1);
  		break;
  	}
  	case OPCODE_ROUND_NI:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//ROUND_NI\n");
  #endif
  		CallHelper1(psContext, "floor", psInst, 0, 1, 1);
  		break;
  	}
  	case OPCODE_ROUND_Z:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//ROUND_Z\n");
  #endif
  		CallHelper1(psContext, "trunc", psInst, 0, 1, 1);
  		break;
  	}
  	case OPCODE_ROUND_NE:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//ROUND_NE\n");
  #endif
  		CallHelper1(psContext, "roundEven", psInst, 0, 1, 1);
  		break;
  	}
  	case OPCODE_FRC:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//FRC\n");
  #endif
  		CallHelper1(psContext, "fract", psInst, 0, 1, 1);
  		break;
  	}
  	case OPCODE_IMAX:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//IMAX\n");
  #endif
  		CallHelper2Int(psContext, "max", psInst, 0, 1, 2, 1);
  		break;
  	}
  	case OPCODE_MAX:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//MAX\n");
  #endif
  		CallHelper2(psContext, "max", psInst, 0, 1, 2, 1);
  		break;
  	}
  	case OPCODE_IMIN:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//IMIN\n");
  #endif
  		CallHelper2Int(psContext, "min", psInst, 0, 1, 2, 1);
  		break;
  	}
  	case OPCODE_MIN:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//MIN\n");
  #endif
  		CallHelper2(psContext, "min", psInst, 0, 1, 2, 1);
  		break;
  	}
  	case OPCODE_GATHER4:
  	{
  		//dest, coords, tex, sampler
  		const RESOURCE_DIMENSION eResDim = psContext->psShader->aeResourceDims[psInst->asOperands[2].ui32RegisterNumber];
  		const int useCombinedTextureSamplers = (psContext->flags & HLSLCC_FLAG_COMBINE_TEXTURE_SAMPLERS) ? 1 : 0;
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//GATHER4\n");
  #endif
  		//gather4 r7.xyzw, r3.xyxx, t3.xyzw, s0.x
  		AddIndentation(psContext); // TODO FIXME integer samplers
  		AddAssignToDest(psContext, &psInst->asOperands[0], SVT_FLOAT, GetNumSwizzleElements(&psInst->asOperands[2]), &numParenthesis);
  		bcatcstr(glsl, "textureGather(");
  
  		if (!useCombinedTextureSamplers)
  			ResourceName(glsl, psContext, RGROUP_TEXTURE, psInst->asOperands[2].ui32RegisterNumber, 0);
  		else
  			bconcat(glsl, TextureSamplerName(&psContext->psShader->sInfo, psInst->asOperands[2].ui32RegisterNumber, psInst->asOperands[3].ui32RegisterNumber, 0));
  
  		bcatcstr(glsl, ", ");
  		TranslateTexCoord(psContext, eResDim, &psInst->asOperands[1]);
  		bcatcstr(glsl, ")");
  		// iWriteMaskEnabled is forced off during DecodeOperand because swizzle on sampler uniforms
  		// does not make sense. But need to re-enable to correctly swizzle this particular instruction.
  		psInst->asOperands[2].iWriteMaskEnabled = 1;
  		TranslateOperandSwizzle(psContext, &psInst->asOperands[2]);
  
  		AddSwizzleUsingElementCount(psContext, GetNumSwizzleElements(&psInst->asOperands[0]));
  		AddAssignPrologue(psContext, numParenthesis);
  		break;
  	}
  	case OPCODE_GATHER4_PO_C:
  	{
  		//dest, coords, offset, tex, sampler, srcReferenceValue
  		const RESOURCE_DIMENSION eResDim = psContext->psShader->aeResourceDims[psInst->asOperands[3].ui32RegisterNumber];
  		const int useCombinedTextureSamplers = (psContext->flags & HLSLCC_FLAG_COMBINE_TEXTURE_SAMPLERS) ? 1 : 0;
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//GATHER4_PO_C\n");
  #endif
  
  		AddIndentation(psContext); // TODO FIXME integer samplers
  		AddAssignToDest(psContext, &psInst->asOperands[0], SVT_FLOAT, GetNumSwizzleElements(&psInst->asOperands[2]), &numParenthesis);
  		bcatcstr(glsl, "textureGatherOffset(");
  
  		if (!useCombinedTextureSamplers)
  			ResourceName(glsl, psContext, RGROUP_TEXTURE, psInst->asOperands[3].ui32RegisterNumber, 1);
  		else
  			bconcat(glsl, TextureSamplerName(&psContext->psShader->sInfo, psInst->asOperands[3].ui32RegisterNumber, psInst->asOperands[3].ui32RegisterNumber, 1));
  
  		bcatcstr(glsl, ", ");
  
  		TranslateTexCoord(psContext, eResDim, &psInst->asOperands[1]);
  
  		bcatcstr(glsl, ", ");
  		TranslateOperand(psContext, &psInst->asOperands[5], TO_FLAG_NONE);
  
  		bcatcstr(glsl, ", ivec2(");
  		//ivec2 offset
  		psInst->asOperands[2].aui32Swizzle[2] = 0xFFFFFFFF;
  		psInst->asOperands[2].aui32Swizzle[3] = 0xFFFFFFFF;
  		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
  		bcatcstr(glsl, "))");
  		// iWriteMaskEnabled is forced off during DecodeOperand because swizzle on sampler uniforms
  		// does not make sense. But need to re-enable to correctly swizzle this particular instruction.
  		psInst->asOperands[2].iWriteMaskEnabled = 1;
  		TranslateOperandSwizzle(psContext, &psInst->asOperands[3]);
  		AddSwizzleUsingElementCount(psContext, GetNumSwizzleElements(&psInst->asOperands[0]));
  		AddAssignPrologue(psContext, numParenthesis);
  		break;
  	}
  	case OPCODE_GATHER4_PO:
  	{
  		//dest, coords, offset, tex, sampler
  		const int useCombinedTextureSamplers = (psContext->flags & HLSLCC_FLAG_COMBINE_TEXTURE_SAMPLERS) ? 1 : 0;
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//GATHER4_PO\n");
  #endif
  
  		AddIndentation(psContext); // TODO FIXME integer samplers
  		AddAssignToDest(psContext, &psInst->asOperands[0], SVT_FLOAT, GetNumSwizzleElements(&psInst->asOperands[2]), &numParenthesis);
  		bcatcstr(glsl, "textureGatherOffset(");
  
  		if (!useCombinedTextureSamplers)
  			ResourceName(glsl, psContext, RGROUP_TEXTURE, psInst->asOperands[3].ui32RegisterNumber, 0);
  		else
  			bconcat(glsl, TextureSamplerName(&psContext->psShader->sInfo, psInst->asOperands[3].ui32RegisterNumber, psInst->asOperands[4].ui32RegisterNumber, 0));
  
  		bcatcstr(glsl, ", ");
  		//Texture coord cannot be vec4
  		//Determining if it is a vec3 for vec2 yet to be done.
  		psInst->asOperands[1].aui32Swizzle[2] = 0xFFFFFFFF;
  		psInst->asOperands[1].aui32Swizzle[3] = 0xFFFFFFFF;
  		TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_NONE);
  
  		bcatcstr(glsl, ", ivec2(");
  		//ivec2 offset
  		psInst->asOperands[2].aui32Swizzle[2] = 0xFFFFFFFF;
  		psInst->asOperands[2].aui32Swizzle[3] = 0xFFFFFFFF;
  		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
  		bcatcstr(glsl, "))");
  		// iWriteMaskEnabled is forced off during DecodeOperand because swizzle on sampler uniforms
  		// does not make sense. But need to re-enable to correctly swizzle this particular instruction.
  		psInst->asOperands[2].iWriteMaskEnabled = 1;
  		TranslateOperandSwizzle(psContext, &psInst->asOperands[3]);
  		AddSwizzleUsingElementCount(psContext, GetNumSwizzleElements(&psInst->asOperands[0]));
  		AddAssignPrologue(psContext, numParenthesis);
  		break;
  	}
  	case OPCODE_GATHER4_C:
  	{
  		//dest, coords, tex, sampler srcReferenceValue
  		const int useCombinedTextureSamplers = (psContext->flags & HLSLCC_FLAG_COMBINE_TEXTURE_SAMPLERS) ? 1 : 0;
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//GATHER4_C\n");
  #endif
  
  		AddIndentation(psContext); // TODO FIXME integer samplers
  		AddAssignToDest(psContext, &psInst->asOperands[0], SVT_FLOAT, GetNumSwizzleElements(&psInst->asOperands[2]), &numParenthesis);
  		bcatcstr(glsl, "textureGather(");
  
  		if (!useCombinedTextureSamplers)
  			ResourceName(glsl, psContext, RGROUP_TEXTURE, psInst->asOperands[2].ui32RegisterNumber, 1);
  		else
  			bconcat(glsl, TextureSamplerName(&psContext->psShader->sInfo, psInst->asOperands[2].ui32RegisterNumber, psInst->asOperands[3].ui32RegisterNumber, 1));
  
  		bcatcstr(glsl, ", ");
  		//Texture coord cannot be vec4
  		//Determining if it is a vec3 for vec2 yet to be done.
  		psInst->asOperands[1].aui32Swizzle[2] = 0xFFFFFFFF;
  		psInst->asOperands[1].aui32Swizzle[3] = 0xFFFFFFFF;
  		TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_NONE);
  
  		bcatcstr(glsl, ", ");
  		TranslateOperand(psContext, &psInst->asOperands[4], TO_FLAG_NONE);
  		bcatcstr(glsl, ")");
  		// iWriteMaskEnabled is forced off during DecodeOperand because swizzle on sampler uniforms
  		// does not make sense. But need to re-enable to correctly swizzle this particular instruction.
  		psInst->asOperands[2].iWriteMaskEnabled = 1;
  		TranslateOperandSwizzle(psContext, &psInst->asOperands[2]);
  		AddSwizzleUsingElementCount(psContext, GetNumSwizzleElements(&psInst->asOperands[0]));
  		AddAssignPrologue(psContext, numParenthesis);
  		break;
  	}
  	case OPCODE_SAMPLE:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//SAMPLE\n");
  #endif
  		TranslateTextureSample(psContext, psInst, TEXSMP_FLAG_NONE);
  		break;
  	}
  	case OPCODE_SAMPLE_L:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//SAMPLE_L\n");
  #endif
  		TranslateTextureSample(psContext, psInst, TEXSMP_FLAG_LOD);
  		break;
  	}
  	case OPCODE_SAMPLE_C:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//SAMPLE_C\n");
  #endif
  
  		TranslateTextureSample(psContext, psInst, TEXSMP_FLAG_DEPTHCOMPARE);
  		break;
  	}
  	case OPCODE_SAMPLE_C_LZ:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//SAMPLE_C_LZ\n");
  #endif
  
  		TranslateTextureSample(psContext, psInst, TEXSMP_FLAG_DEPTHCOMPARE | TEXSMP_FLAG_FIRSTLOD);
  		break;
  	}
  	case OPCODE_SAMPLE_D:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//SAMPLE_D\n");
  #endif
  
  		TranslateTextureSample(psContext, psInst, TEXSMP_FLAGS_GRAD);
  		break;
  	}
  	case OPCODE_SAMPLE_B:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//SAMPLE_B\n");
  #endif
  
  		TranslateTextureSample(psContext, psInst, TEXSMP_FLAG_BIAS);
  		break;
  	}
  	case OPCODE_RET:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//RET\n");
  #endif
  		if (psContext->havePostShaderCode[psContext->currentPhase])
  		{
  #ifdef _DEBUG
  			AddIndentation(psContext);
  			bcatcstr(glsl, "//--- Post shader code ---\n");
  #endif
  			bconcat(glsl, psContext->postShaderCode[psContext->currentPhase]);
  #ifdef _DEBUG
  			AddIndentation(psContext);
  			bcatcstr(glsl, "//--- End post shader code ---\n");
  #endif
  		}
  		AddIndentation(psContext);
  		bcatcstr(glsl, "return;\n");
  		break;
  	}
  	case OPCODE_INTERFACE_CALL:
  	{
  		const char* name;
  		ShaderVar* psVar;
  		uint32_t varFound;
  
  		uint32_t funcPointer;
  		uint32_t funcTableIndex;
  		uint32_t funcTable;
  		uint32_t funcBodyIndex;
  		uint32_t funcBody;
  		uint32_t ui32NumBodiesPerTable;
  
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//INTERFACE_CALL\n");
  #endif
  
  		ASSERT(psInst->asOperands[0].eIndexRep[0] == OPERAND_INDEX_IMMEDIATE32);
  
  		funcPointer = psInst->asOperands[0].aui32ArraySizes[0];
  		funcTableIndex = psInst->asOperands[0].aui32ArraySizes[1];
  		funcBodyIndex = psInst->ui32FuncIndexWithinInterface;
  
  		ui32NumBodiesPerTable = psContext->psShader->funcPointer[funcPointer].ui32NumBodiesPerTable;
  
  		funcTable = psContext->psShader->funcPointer[funcPointer].aui32FuncTables[funcTableIndex];
  
  		funcBody = psContext->psShader->funcTable[funcTable].aui32FuncBodies[funcBodyIndex];
  
  		varFound = GetInterfaceVarFromOffset(funcPointer, &psContext->psShader->sInfo, &psVar);
  
  		ASSERT(varFound);
  
  		name = &psVar->Name[0];
  
  		AddIndentation(psContext);
  		bcatcstr(glsl, name);
  		TranslateOperandIndexMAD(psContext, &psInst->asOperands[0], 1, ui32NumBodiesPerTable, funcBodyIndex);
  		//bformata(glsl, "[%d]", funcBodyIndex);
  		bcatcstr(glsl, "();\n");
  		break;
  	}
  	case OPCODE_LABEL:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//LABEL\n");
  #endif
  		--psContext->indent;
  		AddIndentation(psContext);
  		bcatcstr(glsl, "}\n"); //Closing brace ends the previous function.
  		AddIndentation(psContext);
  
  		bcatcstr(glsl, "subroutine(SubroutineType)\n");
  		bcatcstr(glsl, "void ");
  		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
  		bcatcstr(glsl, "(){\n");
  		++psContext->indent;
  		break;
  	}
  	case OPCODE_COUNTBITS:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//COUNTBITS\n");
  #endif
  		AddIndentation(psContext);
  		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_INTEGER | TO_FLAG_DESTINATION);
  		bcatcstr(glsl, " = bitCount(");
  		TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER);
  		bcatcstr(glsl, ");\n");
  		break;
  	}
  	case OPCODE_FIRSTBIT_HI:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//FIRSTBIT_HI\n");
  #endif
  		AddIndentation(psContext);
  		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_UNSIGNED_INTEGER | TO_FLAG_DESTINATION);
  		bcatcstr(glsl, " = findMSB(");
  		TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_UNSIGNED_INTEGER);
  		bcatcstr(glsl, ");\n");
  		break;
  	}
  	case OPCODE_FIRSTBIT_LO:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//FIRSTBIT_LO\n");
  #endif
  		AddIndentation(psContext);
  		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_UNSIGNED_INTEGER | TO_FLAG_DESTINATION);
  		bcatcstr(glsl, " = findLSB(");
  		TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_UNSIGNED_INTEGER);
  		bcatcstr(glsl, ");\n");
  		break;
  	}
  	case OPCODE_FIRSTBIT_SHI: //signed high
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//FIRSTBIT_SHI\n");
  #endif
  		AddIndentation(psContext);
  		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_INTEGER | TO_FLAG_DESTINATION);
  		bcatcstr(glsl, " = findMSB(");
  		TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER);
  		bcatcstr(glsl, ");\n");
  		break;
  	}
  	case OPCODE_BFREV:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//BFREV\n");
  #endif
  		AddIndentation(psContext);
  		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_INTEGER | TO_FLAG_DESTINATION);
  		bcatcstr(glsl, " = bitfieldReverse(");
  		TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER);
  		bcatcstr(glsl, ");\n");
  		break;
  	}
  	case OPCODE_BFI:
  	{
  		uint32_t numelements_width = GetNumSwizzleElements(&psInst->asOperands[1]);
  		uint32_t numelements_offset = GetNumSwizzleElements(&psInst->asOperands[2]);
  		uint32_t numelements_dest = GetNumSwizzleElements(&psInst->asOperands[0]);
  		uint32_t numoverall_elements = min(min(numelements_width, numelements_offset), numelements_dest);
  		uint32_t i, j;
  		static const char* bfi_elementidx[] = { "x", "y", "z", "w" };
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//BFI\n");
  #endif
  
  		AddIndentation(psContext);
  		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_INTEGER | TO_FLAG_DESTINATION);
  		bformata(glsl, " = ivec%d(", numoverall_elements);
  		for (i = 0; i < numoverall_elements; ++i)
  		{
  			bcatcstr(glsl, "bitfieldInsert(");
  
  			for (j = 4; j >= 1; --j)
  			{
  				uint32_t opSwizzleCount = GetNumSwizzleElements(&psInst->asOperands[j]);
  
  				if (opSwizzleCount != 1)
  					bcatcstr(glsl, " (");
  				TranslateOperand(psContext, &psInst->asOperands[j], TO_FLAG_INTEGER);
  				if (opSwizzleCount != 1)
  					bformata(glsl, " ).%s", bfi_elementidx[i]);
  				if (j != 1)
  					bcatcstr(glsl, ",");
  			}
  
  			bcatcstr(glsl, ") ");
  			if (i + 1 != numoverall_elements)
  				bcatcstr(glsl, ", ");
  		}
  
  		bcatcstr(glsl, ").");
  		for (i = 0; i < numoverall_elements; ++i)
  			bformata(glsl, "%s", bfi_elementidx[i]);
  		bcatcstr(glsl, ";\n");
  		break;
  	}
  	case OPCODE_CUT:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//CUT\n");
  #endif
  		AddIndentation(psContext);
  		bcatcstr(glsl, "EndPrimitive();\n");
  		break;
  	}
  	case OPCODE_EMIT:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//EMIT\n");
  #endif
  		if (psContext->havePostShaderCode[psContext->currentPhase])
  		{
  #ifdef _DEBUG
  			AddIndentation(psContext);
  			bcatcstr(glsl, "//--- Post shader code ---\n");
  #endif
  			bconcat(glsl, psContext->postShaderCode[psContext->currentPhase]);
  #ifdef _DEBUG
  			AddIndentation(psContext);
  			bcatcstr(glsl, "//--- End post shader code ---\n");
  #endif
  		}
  
  		AddIndentation(psContext);
  		bcatcstr(glsl, "EmitVertex();\n");
  		break;
  	}
  	case OPCODE_EMITTHENCUT:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//EMITTHENCUT\n");
  #endif
  		AddIndentation(psContext);
  		bcatcstr(glsl, "EmitVertex();\nEndPrimitive();\n");
  		break;
  	}
  
  	case OPCODE_CUT_STREAM:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//CUT\n");
  #endif
  		AddIndentation(psContext);
  		bcatcstr(glsl, "EndStreamPrimitive(");
  		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
  		bcatcstr(glsl, ");\n");
  
  		break;
  	}
  	case OPCODE_EMIT_STREAM:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//EMIT_STREAM\n");
  #endif
  		if (psContext->havePostShaderCode[psContext->currentPhase])
  		{
  #ifdef _DEBUG
  			AddIndentation(psContext);
  			bcatcstr(glsl, "//--- Post shader code ---\n");
  #endif
  			bconcat(glsl, psContext->postShaderCode[psContext->currentPhase]);
  #ifdef _DEBUG
  			AddIndentation(psContext);
  			bcatcstr(glsl, "//--- End post shader code ---\n");
  #endif
  		}
  
  		AddIndentation(psContext);
  		bcatcstr(glsl, "EmitStreamVertex(");
  		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
  		bcatcstr(glsl, ");\n");
  		break;
  	}
  	case OPCODE_EMITTHENCUT_STREAM:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//EMITTHENCUT\n");
  #endif
  		AddIndentation(psContext);
  		bcatcstr(glsl, "EmitStreamVertex(");
  		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
  		bcatcstr(glsl, ");\n");
  		bcatcstr(glsl, "EndStreamPrimitive(");
  		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
  		bcatcstr(glsl, ");\n");
  		break;
  	}
  	case OPCODE_REP:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//REP\n");
  #endif
  		//Need to handle nesting.
  		//Max of 4 for rep - 'Flow Control Limitations' http://msdn.microsoft.com/en-us/library/windows/desktop/bb219848(v=vs.85).aspx
  
  		AddIndentation(psContext);
  		bcatcstr(glsl, "RepCounter = ");
  		TranslateOperandWithMask(psContext, &psInst->asOperands[0], TO_FLAG_INTEGER, OPERAND_4_COMPONENT_MASK_X);
  		bcatcstr(glsl, ";\n");
  
  		AddIndentation(psContext);
  		bcatcstr(glsl, "while(RepCounter!=0){\n");
  		++psContext->indent;
  		break;
  	}
  	case OPCODE_ENDREP:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//ENDREP\n");
  #endif
  		AddIndentation(psContext);
  		bcatcstr(glsl, "RepCounter--;\n");
  
  		--psContext->indent;
  
  		AddIndentation(psContext);
  		bcatcstr(glsl, "}\n");
  		break;
  	}
  	case OPCODE_LOOP:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//LOOP\n");
  #endif
  		AddIndentation(psContext);
  
  		if (psInst->ui32NumOperands == 2)
  		{
  			//DX9 version
  			ASSERT(psInst->asOperands[0].eType == OPERAND_TYPE_SPECIAL_LOOPCOUNTER);
  			bcatcstr(glsl, "for(");
  			bcatcstr(glsl, "LoopCounter = ");
  			TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_NONE);
  			bcatcstr(glsl, ".y, ZeroBasedCounter = 0;");
  			bcatcstr(glsl, "ZeroBasedCounter < ");
  			TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_NONE);
  			bcatcstr(glsl, ".x;");
  
  			bcatcstr(glsl, "LoopCounter += ");
  			TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_NONE);
  			bcatcstr(glsl, ".z, ZeroBasedCounter++){\n");
  			++psContext->indent;
  		}
  		else
  		{
  			bcatcstr(glsl, "while(true){\n");
  			++psContext->indent;
  		}
  		break;
  	}
  	case OPCODE_ENDLOOP:
  	{
  		--psContext->indent;
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//ENDLOOP\n");
  #endif
  		AddIndentation(psContext);
  		bcatcstr(glsl, "}\n");
  		break;
  	}
  	case OPCODE_BREAK:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//BREAK\n");
  #endif
  		AddIndentation(psContext);
  		bcatcstr(glsl, "break;\n");
  		break;
  	}
  	case OPCODE_BREAKC:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//BREAKC\n");
  #endif
  		AddIndentation(psContext);
  
  		TranslateConditional(psContext, psInst, glsl);
  		break;
  	}
  	case OPCODE_CONTINUEC:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//CONTINUEC\n");
  #endif
  		AddIndentation(psContext);
  
  		TranslateConditional(psContext, psInst, glsl);
  		break;
  	}
  	case OPCODE_IF:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//IF\n");
  #endif
  		AddIndentation(psContext);
  
  		TranslateConditional(psContext, psInst, glsl);
  		++psContext->indent;
  		break;
  	}
  	case OPCODE_RETC:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//RETC\n");
  #endif
  		AddIndentation(psContext);
  
  		TranslateConditional(psContext, psInst, glsl);
  		break;
  	}
  	case OPCODE_ELSE:
  	{
  		--psContext->indent;
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//ELSE\n");
  #endif
  		AddIndentation(psContext);
  		bcatcstr(glsl, "} else {\n");
  		psContext->indent++;
  		break;
  	}
  	case OPCODE_ENDSWITCH:
  	case OPCODE_ENDIF:
  	{
  		--psContext->indent;
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//ENDIF\n");
  		AddIndentation(psContext);
  		bcatcstr(glsl, "}\n");
  		break;
  	}
  	case OPCODE_CONTINUE:
  	{
  		AddIndentation(psContext);
  		bcatcstr(glsl, "continue;\n");
  		break;
  	}
  	case OPCODE_DEFAULT:
  	{
  		--psContext->indent;
  		AddIndentation(psContext);
  		bcatcstr(glsl, "default:\n");
  		++psContext->indent;
  		break;
  	}
  	case OPCODE_NOP:
  	{
  		break;
  	}
  	case OPCODE_SYNC:
  	{
  		const uint32_t ui32SyncFlags = psInst->ui32SyncFlags;
  
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//SYNC\n");
  #endif
  
  		if (ui32SyncFlags & SYNC_THREADS_IN_GROUP)
  		{
  			AddIndentation(psContext);
  			bcatcstr(glsl, "groupMemoryBarrier();\n");
  		}
  		if (ui32SyncFlags & SYNC_THREAD_GROUP_SHARED_MEMORY)
  		{
  			AddIndentation(psContext);
  			bcatcstr(glsl, "memoryBarrierShared();\n");
  		}
  		if (ui32SyncFlags & (SYNC_UNORDERED_ACCESS_VIEW_MEMORY_GROUP | SYNC_UNORDERED_ACCESS_VIEW_MEMORY_GLOBAL))
  		{
  			AddIndentation(psContext);
  			bcatcstr(glsl, "memoryBarrier();\n");
  		}
  		break;
  	}
  	case OPCODE_SWITCH:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//SWITCH\n");
  #endif
  		AddIndentation(psContext);
  		bcatcstr(glsl, "switch(int(");
  		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_INTEGER);
  		bcatcstr(glsl, ")){\n");
  
  		psContext->indent += 2;
  		break;
  	}
  	case OPCODE_CASE:
  	{
  		--psContext->indent;
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//case\n");
  #endif
  		AddIndentation(psContext);
  
  		bcatcstr(glsl, "case ");
  		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_INTEGER);
  		bcatcstr(glsl, ":\n");
  
  		++psContext->indent;
  		break;
  	}
  	case OPCODE_EQ:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//EQ\n");
  #endif
  		AddComparision(psContext, psInst, CMP_EQ, TO_FLAG_NONE, NULL);
  		break;
  	}
  	case OPCODE_USHR:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//USHR\n");
  #endif
  		CallBinaryOp(psContext, ">>", psInst, 0, 1, 2, SVT_UINT);
  		break;
  	}
  	case OPCODE_ISHL:
  	{
  		SHADER_VARIABLE_TYPE eType = SVT_INT;
  
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//ISHL\n");
  #endif
  
  		if (GetOperandDataType(psContext, &psInst->asOperands[0]) == SVT_UINT)
  		{
  			eType = SVT_UINT;
  		}
  
  		CallBinaryOp(psContext, "<<", psInst, 0, 1, 2, eType);
  		break;
  	}
  	case OPCODE_ISHR:
  	{
  		SHADER_VARIABLE_TYPE eType = SVT_INT;
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//ISHR\n");
  #endif
  
  		if (GetOperandDataType(psContext, &psInst->asOperands[0]) == SVT_UINT)
  		{
  			eType = SVT_UINT;
  		}
  
  		CallBinaryOp(psContext, ">>", psInst, 0, 1, 2, eType);
  		break;
  	}
  	case OPCODE_LD:
  	case OPCODE_LD_MS:
  	{
  		ResourceBinding* psBinding = 0;
  		uint32_t dstSwizCount = GetNumSwizzleElements(&psInst->asOperands[0]);
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		if (psInst->eOpcode == OPCODE_LD)
  			bcatcstr(glsl, "//LD\n");
  		else
  			bcatcstr(glsl, "//LD_MS\n");
  #endif
  
  		GetResourceFromBindingPoint(RGROUP_TEXTURE, psInst->asOperands[2].ui32RegisterNumber, &psContext->psShader->sInfo, &psBinding);
  
  		if (psInst->bAddressOffset)
  		{
  			TranslateTexelFetchOffset(psContext, psInst, psBinding, glsl);
  		}
  		else
  		{
  			TranslateTexelFetch(psContext, psInst, psBinding, glsl);
  		}
  		break;
  	}
  	case OPCODE_DISCARD:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//DISCARD\n");
  #endif
  		AddIndentation(psContext);
  		if (psContext->psShader->ui32MajorVersion <= 3)
  		{
  			bcatcstr(glsl, "if(any(lessThan((");
  			TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_NONE);
  
  			if (psContext->psShader->ui32MajorVersion == 1)
  			{
  				/* SM1.X only kills based on the rgb channels */
  				bcatcstr(glsl, ").xyz, vec3(0)))){discard;}\n");
  			}
  			else
  			{
  				bcatcstr(glsl, "), vec4(0)))){discard;}\n");
  			}
  		}
  		else if (psInst->eBooleanTestType == INSTRUCTION_TEST_ZERO)
  		{
  			bcatcstr(glsl, "if((");
  			TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_INTEGER);
  			bcatcstr(glsl, ")==0){discard;}\n");
  		}
  		else
  		{
  			ASSERT(psInst->eBooleanTestType == INSTRUCTION_TEST_NONZERO);
  			bcatcstr(glsl, "if((");
  			TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_INTEGER);
  			bcatcstr(glsl, ")!=0){discard;}\n");
  		}
  		break;
  	}
  	case OPCODE_LOD:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//LOD\n");
  #endif
  		//LOD computes the following vector (ClampedLOD, NonClampedLOD, 0, 0)
  
  		AddIndentation(psContext);
  		AddAssignToDest(psContext, &psInst->asOperands[0], SVT_FLOAT, 4, &numParenthesis);
  
  		//If the core language does not have query-lod feature,
  		//then the extension is used. The name of the function
  		//changed between extension and core.
  		if (HaveQueryLod(psContext->psShader->eTargetLanguage))
  		{
  			bcatcstr(glsl, "textureQueryLod(");
  		}
  		else
  		{
  			bcatcstr(glsl, "textureQueryLOD(");
  		}
  
  		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
  		bcatcstr(glsl, ",");
  		TranslateTexCoord(psContext,
  			psContext->psShader->aeResourceDims[psInst->asOperands[2].ui32RegisterNumber],
  			&psInst->asOperands[1]);
  		bcatcstr(glsl, ")");
  
  		//The swizzle on srcResource allows the returned values to be swizzled arbitrarily before they are written to the destination.
  
  		// iWriteMaskEnabled is forced off during DecodeOperand because swizzle on sampler uniforms
  		// does not make sense. But need to re-enable to correctly swizzle this particular instruction.
  		psInst->asOperands[2].iWriteMaskEnabled = 1;
  		TranslateOperandSwizzleWithMask(psContext, &psInst->asOperands[2], GetOperandWriteMask(&psInst->asOperands[0]));
  		AddAssignPrologue(psContext, numParenthesis);
  		break;
  	}
  	case OPCODE_EVAL_CENTROID:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//EVAL_CENTROID\n");
  #endif
  		AddIndentation(psContext);
  		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
  		bcatcstr(glsl, " = interpolateAtCentroid(");
  		//interpolateAtCentroid accepts in-qualified variables.
  		//As long as bytecode only writes vX registers in declarations
  		//we should be able to use the declared name directly.
  		TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_DECLARATION_NAME);
  		bcatcstr(glsl, ");\n");
  		break;
  	}
  	case OPCODE_EVAL_SAMPLE_INDEX:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//EVAL_SAMPLE_INDEX\n");
  #endif
  		AddIndentation(psContext);
  		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
  		bcatcstr(glsl, " = interpolateAtSample(");
  		//interpolateAtSample accepts in-qualified variables.
  		//As long as bytecode only writes vX registers in declarations
  		//we should be able to use the declared name directly.
  		TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_DECLARATION_NAME);
  		bcatcstr(glsl, ", ");
  		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_INTEGER);
  		bcatcstr(glsl, ");\n");
  		break;
  	}
  	case OPCODE_EVAL_SNAPPED:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//EVAL_SNAPPED\n");
  #endif
  		AddIndentation(psContext);
  		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
  		bcatcstr(glsl, " = interpolateAtOffset(");
  		//interpolateAtOffset accepts in-qualified variables.
  		//As long as bytecode only writes vX registers in declarations
  		//we should be able to use the declared name directly.
  		TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_DECLARATION_NAME);
  		bcatcstr(glsl, ", ");
  		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_INTEGER);
  		bcatcstr(glsl, ".xy);\n");
  		break;
  	}
  	case OPCODE_LD_STRUCTURED:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//LD_STRUCTURED\n");
  #endif
  		TranslateShaderStorageLoad(psContext, psInst);
  		break;
  	}
  	case OPCODE_LD_UAV_TYPED:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//LD_UAV_TYPED\n");
  #endif
  		switch (psInst->eResDim)
  		{
  		case RESOURCE_DIMENSION_TEXTURE1D:
  			AddIndentation(psContext);
  			TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
  			bcatcstr(glsl, " = imageLoad(");
  			TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NAME_ONLY);
  			bcatcstr(glsl, ", (");
  			TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER);
  			bformata(glsl, ").x)");
  			TranslateOperandSwizzle(psContext, &psInst->asOperands[0]);
  			bcatcstr(glsl, ";\n");
  			break;
  		case RESOURCE_DIMENSION_TEXTURECUBE:
  		case RESOURCE_DIMENSION_TEXTURE1DARRAY:
  		case RESOURCE_DIMENSION_TEXTURE2D:
  		case RESOURCE_DIMENSION_TEXTURE2DMS:
  			AddIndentation(psContext);
  			TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
  			bcatcstr(glsl, " = imageLoad(");
  			TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NAME_ONLY);
  			bcatcstr(glsl, ", (");
  			TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER);
  			bformata(glsl, ").xy)");
  			TranslateOperandSwizzle(psContext, &psInst->asOperands[0]);
  			bcatcstr(glsl, ";\n");
  			break;
  		case RESOURCE_DIMENSION_TEXTURE3D:
  		case RESOURCE_DIMENSION_TEXTURE2DARRAY:
  		case RESOURCE_DIMENSION_TEXTURE2DMSARRAY:
  		case RESOURCE_DIMENSION_TEXTURECUBEARRAY:
  			AddIndentation(psContext);
  			TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
  			bcatcstr(glsl, " = imageLoad(");
  			TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NAME_ONLY);
  			bcatcstr(glsl, ", (");
  			TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER);
  			bformata(glsl, ").xyz)");
  			TranslateOperandSwizzle(psContext, &psInst->asOperands[0]);
  			bcatcstr(glsl, ";\n");
  			break;
  		}
  		break;
  	}
  	case OPCODE_STORE_RAW:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//STORE_RAW\n");
  #endif
  		TranslateShaderStorageStore(psContext, psInst);
  		break;
  	}
  	case OPCODE_STORE_STRUCTURED:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//STORE_STRUCTURED\n");
  #endif
  		TranslateShaderStorageStore(psContext, psInst);
  		break;
  	}
  
  	case OPCODE_STORE_UAV_TYPED:
  	{
  		ResourceBinding* psRes;
  		int foundResource;
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//STORE_UAV_TYPED\n");
  #endif
  		AddIndentation(psContext);
  
  		foundResource = GetResourceFromBindingPoint(RGROUP_UAV,
  			psInst->asOperands[0].ui32RegisterNumber,
  			&psContext->psShader->sInfo,
  			&psRes);
  
  		ASSERT(foundResource);
  
  		bcatcstr(glsl, "imageStore(");
  		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_NAME_ONLY);
  		switch (psRes->eDimension)
  		{
  		case REFLECT_RESOURCE_DIMENSION_TEXTURE1D:
  			bcatcstr(glsl, ", int(");
  			TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_NAME_ONLY);
  			bcatcstr(glsl, "), ");
  			break;
  		case REFLECT_RESOURCE_DIMENSION_TEXTURE2D:
  		case REFLECT_RESOURCE_DIMENSION_TEXTURE1DARRAY:
  		case REFLECT_RESOURCE_DIMENSION_TEXTURE2DMS:
  			bcatcstr(glsl, ", ivec2(");
  			TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_NAME_ONLY);
  			bcatcstr(glsl, ".xy), ");
  			break;
  		case REFLECT_RESOURCE_DIMENSION_TEXTURE2DARRAY:
  		case REFLECT_RESOURCE_DIMENSION_TEXTURE3D:
  		case REFLECT_RESOURCE_DIMENSION_TEXTURE2DMSARRAY:
  		case REFLECT_RESOURCE_DIMENSION_TEXTURECUBE:
  			bcatcstr(glsl, ", ivec3(");
  			TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_NAME_ONLY);
  			bcatcstr(glsl, ".xyz), ");
  			break;
  		case REFLECT_RESOURCE_DIMENSION_TEXTURECUBEARRAY:
  			bcatcstr(glsl, ", ivec4(");
  			TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_NAME_ONLY);
  			bcatcstr(glsl, ".xyzw) ");
  			break;
  		};
  
  		TranslateOperand(psContext, &psInst->asOperands[2], ResourceReturnTypeToFlag(psRes->ui32ReturnType));
  		bformata(glsl, ");\n");
  
  		break;
  	}
  	case OPCODE_LD_RAW:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//LD_RAW\n");
  #endif
  
  		TranslateShaderStorageLoad(psContext, psInst);
  		break;
  	}
  
  	case OPCODE_ATOMIC_CMP_STORE:
  	case OPCODE_IMM_ATOMIC_AND:
  	case OPCODE_ATOMIC_AND:
  	case OPCODE_IMM_ATOMIC_IADD:
  	case OPCODE_ATOMIC_IADD:
  	case OPCODE_ATOMIC_OR:
  	case OPCODE_ATOMIC_XOR:
  	case OPCODE_ATOMIC_IMIN:
  	case OPCODE_ATOMIC_UMIN:
  	case OPCODE_IMM_ATOMIC_IMAX:
  	case OPCODE_IMM_ATOMIC_IMIN:
  	case OPCODE_IMM_ATOMIC_UMAX:
  	case OPCODE_IMM_ATOMIC_UMIN:
  	case OPCODE_IMM_ATOMIC_OR:
  	case OPCODE_IMM_ATOMIC_XOR:
  	case OPCODE_IMM_ATOMIC_EXCH:
  	case OPCODE_IMM_ATOMIC_CMP_EXCH:
  	{
  		TranslateAtomicMemOp(psContext, psInst);
  		break;
  	}
  	case OPCODE_UBFE:
  	case OPCODE_IBFE:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		if (psInst->eOpcode == OPCODE_UBFE)
  			bcatcstr(glsl, "//OPCODE_UBFE\n");
  		else
  			bcatcstr(glsl, "//OPCODE_IBFE\n");
  #endif
  		AddIndentation(psContext);
  		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
  		bcatcstr(glsl, " = bitfieldExtract(");
  		TranslateOperand(psContext, &psInst->asOperands[3], TO_FLAG_NONE);
  		bcatcstr(glsl, ", ");
  		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
  		bcatcstr(glsl, ", ");
  		TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_NONE);
  		bcatcstr(glsl, ");\n");
  		break;
  	}
  	case OPCODE_RCP:
  	{
  		const uint32_t destElemCount = GetNumSwizzleElements(&psInst->asOperands[0]);
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//RCP\n");
  #endif
  		AddIndentation(psContext);
  		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
  		bcatcstr(glsl, " = (vec4(1.0) / vec4(");
  		TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_NONE);
  		bcatcstr(glsl, "))");
  		AddSwizzleUsingElementCount(psContext, destElemCount);
  		bcatcstr(glsl, ";\n");
  		break;
  	}
  	case OPCODE_F32TOF16:
  	{
  		const uint32_t destElemCount = GetNumSwizzleElements(&psInst->asOperands[0]);
  		const uint32_t s0ElemCount = GetNumSwizzleElements(&psInst->asOperands[1]);
  		uint32_t destElem;
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//F32TOF16\n");
  #endif
  		for (destElem = 0; destElem < destElemCount; ++destElem)
  		{
  			const char* swizzle[] = { ".x", ".y", ".z", ".w" };
  
  			//unpackHalf2x16 converts two f16s packed into uint to two f32s.
  
  			//dest.swiz.x = unpackHalf2x16(src.swiz.x).x
  			//dest.swiz.y = unpackHalf2x16(src.swiz.y).x
  			//dest.swiz.z = unpackHalf2x16(src.swiz.z).x
  			//dest.swiz.w = unpackHalf2x16(src.swiz.w).x
  
  			AddIndentation(psContext);
  			TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
  			if (destElemCount>1)
  				bcatcstr(glsl, swizzle[destElem]);
  
  			bcatcstr(glsl, " = unpackHalf2x16(");
  			TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_UNSIGNED_INTEGER);
  			if (s0ElemCount > 1)
  				bcatcstr(glsl, swizzle[destElem]);
  			bcatcstr(glsl, ").x;\n");
  
  		}
  		break;
  	}
  	case OPCODE_F16TOF32:
  	{
  		const uint32_t destElemCount = GetNumSwizzleElements(&psInst->asOperands[0]);
  		const uint32_t s0ElemCount = GetNumSwizzleElements(&psInst->asOperands[1]);
  		uint32_t destElem;
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//F16TOF32\n");
  #endif
  		for (destElem = 0; destElem < destElemCount; ++destElem)
  		{
  			const char* swizzle[] = { ".x", ".y", ".z", ".w" };
  
  			//packHalf2x16 converts two f32s to two f16s packed into a uint.
  
  			//dest.swiz.x = packHalf2x16(vec2(src.swiz.x)) & 0xFFFF
  			//dest.swiz.y = packHalf2x16(vec2(src.swiz.y)) & 0xFFFF
  			//dest.swiz.z = packHalf2x16(vec2(src.swiz.z)) & 0xFFFF
  			//dest.swiz.w = packHalf2x16(vec2(src.swiz.w)) & 0xFFFF
  
  			AddIndentation(psContext);
  			TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION | TO_FLAG_UNSIGNED_INTEGER);
  			if (destElemCount>1)
  				bcatcstr(glsl, swizzle[destElem]);
  
  			bcatcstr(glsl, " = packHalf2x16(vec2(");
  			TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_NONE);
  			if (s0ElemCount > 1)
  				bcatcstr(glsl, swizzle[destElem]);
  			bcatcstr(glsl, ")) & 0xFFFF;\n");
  
  		}
  		break;
  	}
  	case OPCODE_INEG:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//INEG\n");
  #endif
  		//dest = 0 - src0
  		AddIndentation(psContext);
  		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION | TO_FLAG_INTEGER);
  		bcatcstr(glsl, " = 0 - ");
  		TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_NONE | TO_FLAG_INTEGER);
  		bcatcstr(glsl, ";\n");
  		break;
  	}
  	case OPCODE_DERIV_RTX_COARSE:
  	case OPCODE_DERIV_RTX_FINE:
  	case OPCODE_DERIV_RTX:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//DERIV_RTX\n");
  #endif
  		CallHelper1(psContext, "dFdx", psInst, 0, 1, 1);
  		break;
  	}
  	case OPCODE_DERIV_RTY_COARSE:
  	case OPCODE_DERIV_RTY_FINE:
  	case OPCODE_DERIV_RTY:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//DERIV_RTY\n");
  #endif
  		CallHelper1(psContext, "dFdy", psInst, 0, 1, 1);
  		break;
  	}
  	case OPCODE_LRP:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//LRP\n");
  #endif
  		CallHelper3(psContext, "mix", psInst, 0, 2, 3, 1, 1);
  		break;
  	}
  	case OPCODE_DP2ADD:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//DP2ADD\n");
  #endif
  		AddIndentation(psContext);
  		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
  		bcatcstr(glsl, " = dot(vec2(");
  		TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_NONE);
  		bcatcstr(glsl, "), vec2(");
  		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
  		bcatcstr(glsl, ")) + ");
  		TranslateOperand(psContext, &psInst->asOperands[3], TO_FLAG_NONE);
  		bcatcstr(glsl, ";\n");
  		break;
  	}
  	case OPCODE_POW:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//POW\n");
  #endif
  		AddIndentation(psContext);
  		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
  		bcatcstr(glsl, " = pow(abs(");
  		TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_NONE);
  		bcatcstr(glsl, "), ");
  		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
  		bcatcstr(glsl, ");\n");
  		break;
  	}
  
  	case OPCODE_IMM_ATOMIC_ALLOC:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//IMM_ATOMIC_ALLOC\n");
  #endif
  		AddIndentation(psContext);
  		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
  		bcatcstr(glsl, " = int(atomicCounterIncrement(");
  		ResourceName(glsl, psContext, RGROUP_UAV, psInst->asOperands[1].ui32RegisterNumber, 0);
  		bformata(glsl, "_counter");
  		bcatcstr(glsl, "));\n");
  		break;
  	}
  	case OPCODE_IMM_ATOMIC_CONSUME:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//IMM_ATOMIC_CONSUME\n");
  #endif
  		AddIndentation(psContext);
  		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
  		//Temps are always signed and atomci counters are always unsigned
  		//at the moment.
  		bcatcstr(glsl, " = int(atomicCounterDecrement(");
  		ResourceName(glsl, psContext, RGROUP_UAV, psInst->asOperands[1].ui32RegisterNumber, 0);
  		bformata(glsl, "_counter");
  		bcatcstr(glsl, "));\n");
  		break;
  	}
  
  	case OPCODE_NOT:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//INOT\n");
  #endif
  		AddIndentation(psContext);
  		AddAssignToDest(psContext, &psInst->asOperands[0], SVT_INT, GetNumSwizzleElements(&psInst->asOperands[1]), &numParenthesis);
  
  		bcatcstr(glsl, "~");
  		TranslateOperandWithMask(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER, GetOperandWriteMask(&psInst->asOperands[0]));
  		AddAssignPrologue(psContext, numParenthesis);
  		break;
  	}
  	case OPCODE_XOR:
  	{
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//XOR\n");
  #endif
  
  		CallBinaryOp(psContext, "^", psInst, 0, 1, 2, SVT_UINT);
  		break;
  	}
  	case OPCODE_RESINFO:
  	{
  
  		const RESOURCE_DIMENSION eResDim = psContext->psShader->aeResourceDims[psInst->asOperands[2].ui32RegisterNumber];
  		const RESINFO_RETURN_TYPE eResInfoReturnType = psInst->eResInfoReturnType;
  		uint32_t destElemCount = GetNumSwizzleElements(&psInst->asOperands[0]);
  		uint32_t destElem;
  #ifdef _DEBUG
  		AddIndentation(psContext);
  		bcatcstr(glsl, "//RESINFO\n");
  #endif
  
  		for (destElem = 0; destElem < destElemCount; ++destElem)
  		{
  			const char* swizzle[] = { ".x", ".y", ".z", ".w" };
  
  			GetResInfoData(psContext, psInst, psInst->asOperands[2].aui32Swizzle[destElem], destElem);
  		}
  
  		break;
  	}
  
  
  	case OPCODE_DMAX:
  	case OPCODE_DMIN:
  	case OPCODE_DMUL:
  	case OPCODE_DEQ:
  	case OPCODE_DGE:
  	case OPCODE_DLT:
  	case OPCODE_DNE:
  	case OPCODE_DMOV:
  	case OPCODE_DMOVC:
  	case OPCODE_DTOF:
  	case OPCODE_FTOD:
  	case OPCODE_DDIV:
  	case OPCODE_DFMA:
  	case OPCODE_DRCP:
  	case OPCODE_MSAD:
  	case OPCODE_DTOI:
  	case OPCODE_DTOU:
  	case OPCODE_ITOD:
  	case OPCODE_UTOD:
  	default:
  	{
  		ASSERT(0);
  		break;
  	}
  	}
  
  	if (psInst->bSaturate) //Saturate is only for floating point data (float opcodes or MOV)
  	{
  		int dstCount = GetNumSwizzleElements(&psInst->asOperands[0]);
  		AddIndentation(psContext);
  		AddAssignToDest(psContext, &psInst->asOperands[0], SVT_FLOAT, dstCount, &numParenthesis);
  		bcatcstr(glsl, "clamp(");
  
  		TranslateOperand(psContext, &psInst->asOperands[0], TO_AUTO_BITCAST_TO_FLOAT);
  		bcatcstr(glsl, ", 0.0, 1.0)");
  		AddAssignPrologue(psContext, numParenthesis);
  	}
  }
  
  static int IsIntegerImmediateOpcode(OPCODE_TYPE eOpcode)
  {
  	switch (eOpcode)
  	{
  	case OPCODE_IADD:
  	case OPCODE_IF:
  	case OPCODE_IEQ:
  	case OPCODE_IGE:
  	case OPCODE_ILT:
  	case OPCODE_IMAD:
  	case OPCODE_IMAX:
  	case OPCODE_IMIN:
  	case OPCODE_IMUL:
  	case OPCODE_INE:
  	case OPCODE_INEG:
  	case OPCODE_ISHL:
  	case OPCODE_ISHR:
  	case OPCODE_ITOF:
  	case OPCODE_USHR:
  	case OPCODE_AND:
  	case OPCODE_OR:
  	case OPCODE_XOR:
  	case OPCODE_BREAKC:
  	case OPCODE_CONTINUEC:
  	case OPCODE_RETC:
  	case OPCODE_DISCARD:
  		//MOV is typeless.
  		//Treat immediates as int, bitcast to float if necessary
  	case OPCODE_MOV:
  	case OPCODE_MOVC:
  	{
  		return 1;
  	}
  	default:
  	{
  		return 0;
  	}
  	}
  }
  
  int InstructionUsesRegister(const Instruction* psInst, const Operand* psOperand)
  {
  	uint32_t operand;
  	for (operand = 0; operand < psInst->ui32NumOperands; ++operand)
  	{
  		if (psInst->asOperands[operand].eType == psOperand->eType)
  		{
  			if (psInst->asOperands[operand].ui32RegisterNumber == psOperand->ui32RegisterNumber)
  			{
  				if (CompareOperandSwizzles(&psInst->asOperands[operand], psOperand))
  				{
  					return 1;
  				}
  			}
  		}
  	}
  	return 0;
  }
  
  void MarkIntegerImmediates(HLSLCrossCompilerContext* psContext)
  {
  	const uint32_t count = psContext->psShader->asPhase[MAIN_PHASE].pui32InstCount[0];
  	Instruction* psInst = psContext->psShader->asPhase[MAIN_PHASE].ppsInst[0];
  	uint32_t i;
  
  	for (i = 0; i < count;)
  	{
  		if (psInst[i].eOpcode == OPCODE_MOV && psInst[i].asOperands[1].eType == OPERAND_TYPE_IMMEDIATE32 &&
  			psInst[i].asOperands[0].eType == OPERAND_TYPE_TEMP)
  		{
  			uint32_t k;
  
  			for (k = i + 1; k < count; ++k)
  			{
  				if (psInst[k].eOpcode == OPCODE_ILT)
  				{
  					k = k;
  				}
  				if (InstructionUsesRegister(&psInst[k], &psInst[i].asOperands[0]))
  				{
  					if (IsIntegerImmediateOpcode(psInst[k].eOpcode))
  					{
  						psInst[i].asOperands[1].iIntegerImmediate = 1;
  					}
  
  					goto next_iteration;
  				}
  			}
  		}
  	next_iteration:
  		++i;
  	}
  }
  