Add SwiftShader source to repo

Oct 6 code drop from Transgaming
Review URL: https://chromereviews.googleplex.com/3846015
diff --git a/src/Shader/Shader.cpp b/src/Shader/Shader.cpp
new file mode 100644
index 0000000..43e8bdc
--- /dev/null
+++ b/src/Shader/Shader.cpp
@@ -0,0 +1,1318 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2011 TransGaming Inc.
+//
+// All rights reserved. No part of this software may be copied, distributed, transmitted,
+// transcribed, stored in a retrieval system, translated into any human or computer
+// language by any means, or disclosed to third parties without the explicit written
+// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
+// or implied, including but not limited to any patent rights, are granted to you.
+//
+
+#include "Shader.hpp"
+
+#include "Math.hpp"
+#include "Debug.hpp"
+
+#include <stdarg.h>
+#include <fstream>
+#include <sstream>
+
+namespace sw
+{
+	Shader::Instruction::Instruction()
+	{
+		operation.opcode = Operation::OPCODE_NOP;
+		destinationParameter.type = Parameter::PARAMETER_VOID;
+		sourceParameter[0].type = Parameter::PARAMETER_VOID;
+		sourceParameter[1].type = Parameter::PARAMETER_VOID;
+		sourceParameter[2].type = Parameter::PARAMETER_VOID;
+		sourceParameter[3].type = Parameter::PARAMETER_VOID;
+	}
+
+	Shader::Instruction::Instruction(const unsigned long *token, int size, unsigned char majorVersion)
+	{
+		parseOperationToken(*token++, majorVersion);
+
+		if(operation.opcode == Operation::OPCODE_IF ||
+		   operation.opcode == Operation::OPCODE_IFC ||
+		   operation.opcode == Operation::OPCODE_LOOP ||
+		   operation.opcode == Operation::OPCODE_REP ||
+		   operation.opcode == Operation::OPCODE_BREAKC ||
+		   operation.opcode == Operation::OPCODE_BREAKP)   // No destination operand
+		{
+			if(size > 0) parseSourceToken(0, token++, majorVersion);
+			if(size > 1) parseSourceToken(1, token++, majorVersion);
+			if(size > 2) parseSourceToken(2, token++, majorVersion);
+			if(size > 3) ASSERT(false);
+		}
+		else if(operation.opcode == Operation::OPCODE_DCL)
+		{
+			parseDeclarationToken(*token++);
+			parseDestinationToken(token++, majorVersion);
+		}
+		else
+		{
+			if(size > 0)
+			{
+				parseDestinationToken(token, majorVersion);
+
+				if(destinationParameter.relative && majorVersion >= 3)
+				{
+					token++;
+					size--;
+				}
+				
+				token++;
+				size--;
+			}
+
+			if(operation.predicate)
+			{
+				ASSERT(size != 0);
+
+				operation.predicateNot = (SourceParameter::Modifier)((*token & 0x0F000000) >> 24) == SourceParameter::MODIFIER_NOT;
+				operation.predicateSwizzle = (unsigned char)((*token & 0x00FF0000) >> 16);
+				
+				token++;
+				size--;
+			}
+
+			for(int i = 0; size > 0; i++)
+			{
+				parseSourceToken(i, token, majorVersion);
+
+				token++;
+				size--;
+
+				if(sourceParameter[i].relative && majorVersion >= 2)
+				{
+					token++;
+					size--;
+				}
+			}
+		}
+	}
+
+	Shader::Instruction::~Instruction()
+	{
+	}
+
+	Shader::Instruction::Operation::Opcode Shader::Instruction::getOpcode() const
+	{
+		return operation.opcode;
+	}
+
+	const Shader::Instruction::DestinationParameter &Shader::Instruction::getDestinationParameter() const
+	{
+		return destinationParameter;
+	}
+
+	const Shader::Instruction::SourceParameter &Shader::Instruction::getSourceParameter(int i) const
+	{
+		return sourceParameter[i];
+	}
+
+	bool Shader::Instruction::isCoissue() const
+	{
+		return operation.coissue;
+	}
+
+	bool Shader::Instruction::isProject() const
+	{
+		return operation.project;
+	}
+
+	bool Shader::Instruction::isBias() const
+	{
+		return operation.bias;
+	}
+
+	bool Shader::Instruction::isPredicate() const
+	{
+		return operation.predicate;
+	}
+
+	bool Shader::Instruction::isPredicateNot() const
+	{
+		return operation.predicateNot;
+	}
+
+	unsigned char Shader::Instruction::getPredicateSwizzle() const
+	{
+		return operation.predicateSwizzle;
+	}
+
+	Shader::Instruction::Operation::Control Shader::Instruction::getControl() const
+	{
+		return operation.control;
+	}
+
+	Shader::Instruction::Operation::Usage Shader::Instruction::getUsage() const
+	{
+		return operation.usage;
+	}
+
+	unsigned char Shader::Instruction::getUsageIndex() const
+	{
+		return operation.usageIndex;
+	}
+
+	Shader::Instruction::Operation::SamplerType Shader::Instruction::getSamplerType() const
+	{
+		return operation.samplerType;
+	}
+
+	std::string Shader::Instruction::string(ShaderType shaderType, unsigned short version) const
+	{
+		std::string instructionString;
+		
+		if(operation.opcode != Operation::OPCODE_DCL)
+		{
+			instructionString += operation.coissue ? "+ " : "";
+			
+			if(operation.predicate)
+			{
+				instructionString += operation.predicateNot ? "(!p0" : "(p0";
+				instructionString += swizzleString(Parameter::PARAMETER_PREDICATE, operation.predicateSwizzle);
+				instructionString += ") ";
+			}
+
+			instructionString += operation.string(version) + operation.controlString() + destinationParameter.shiftString() + destinationParameter.modifierString();
+
+			if(destinationParameter.type != Parameter::PARAMETER_VOID)
+			{
+				instructionString += " " + destinationParameter.string(shaderType, version) +
+				                           destinationParameter.relativeString() +
+				                           destinationParameter.maskString(); 
+			}
+
+			for(int i = 0; i < 4; i++)
+			{
+				if(sourceParameter[i].type != Parameter::PARAMETER_VOID)
+				{
+					instructionString += (destinationParameter.type != Parameter::PARAMETER_VOID || i > 0) ? ", " : " ";
+					instructionString += sourceParameter[i].preModifierString() +
+										 sourceParameter[i].string(shaderType, version) +
+										 sourceParameter[i].relativeString() + 
+										 sourceParameter[i].postModifierString() + 
+										 sourceParameter[i].swizzleString();
+				}
+			}
+		}
+		else   // DCL
+		{
+			instructionString += "dcl";
+
+			if(destinationParameter.type == Parameter::PARAMETER_SAMPLER)
+			{
+				switch(operation.samplerType)
+				{
+				case Operation::SAMPLER_UNKNOWN:	instructionString += " ";			break;
+				case Operation::SAMPLER_1D:			instructionString += "_1d ";		break;
+				case Operation::SAMPLER_2D:			instructionString += "_2d ";		break;
+				case Operation::SAMPLER_CUBE:		instructionString += "_cube ";		break;
+				case Operation::SAMPLER_VOLUME:		instructionString += "_volume ";	break;
+				default:
+					ASSERT(false);
+				}
+
+				instructionString += destinationParameter.string(shaderType, version);
+			}
+			else if(destinationParameter.type == Parameter::PARAMETER_INPUT ||
+				    destinationParameter.type == Parameter::PARAMETER_OUTPUT ||
+				    destinationParameter.type == Parameter::PARAMETER_TEXTURE)
+			{
+				if(version >= 0x0300)
+				{
+					switch(operation.usage)
+					{
+					case Operation::USAGE_POSITION:		instructionString += "_position";		break;
+					case Operation::USAGE_BLENDWEIGHT:	instructionString += "_blendweight";	break;
+					case Operation::USAGE_BLENDINDICES:	instructionString += "_blendindices";	break;
+					case Operation::USAGE_NORMAL:		instructionString += "_normal";			break;
+					case Operation::USAGE_PSIZE:		instructionString += "_psize";			break;
+					case Operation::USAGE_TEXCOORD:		instructionString += "_texcoord";		break;
+					case Operation::USAGE_TANGENT:		instructionString += "_tangent";		break;
+					case Operation::USAGE_BINORMAL:		instructionString += "_binormal";		break;
+					case Operation::USAGE_TESSFACTOR:	instructionString += "_tessfactor";		break;
+					case Operation::USAGE_POSITIONT:	instructionString += "_positiont";		break;
+					case Operation::USAGE_COLOR:		instructionString += "_color";			break;
+					case Operation::USAGE_FOG:			instructionString += "_fog";			break;
+					case Operation::USAGE_DEPTH:		instructionString += "_depth";			break;
+					case Operation::USAGE_SAMPLE:		instructionString += "_sample";			break;
+					default:
+						ASSERT(false);
+					}
+
+					if(operation.usageIndex > 0)
+					{
+						std::ostringstream buffer;
+
+						buffer << (int)operation.usageIndex;
+
+						instructionString += buffer.str();
+					}
+				}
+				else ASSERT(destinationParameter.type != Parameter::PARAMETER_OUTPUT);
+
+				instructionString += " ";
+
+				instructionString += destinationParameter.string(shaderType, version);
+				instructionString += destinationParameter.maskString();
+			}
+			else if(destinationParameter.type == Parameter::PARAMETER_MISCTYPE)   // vPos and vFace
+			{
+				instructionString += " ";
+
+				instructionString += destinationParameter.string(shaderType, version);
+			}
+			else ASSERT(false);
+		}
+
+		return instructionString;
+	}
+
+	std::string Shader::Instruction::Operation::string(unsigned short version) const
+	{
+		switch(opcode)
+		{
+		case OPCODE_NOP:			return "nop";
+		case OPCODE_MOV:			return "mov";
+		case OPCODE_ADD:			return "add";
+		case OPCODE_SUB:			return "sub";
+		case OPCODE_MAD:			return "mad";
+		case OPCODE_MUL:			return "mul";
+		case OPCODE_RCP:			return "rcp";
+		case OPCODE_RSQ:			return "rsq";
+		case OPCODE_DP3:			return "dp3";
+		case OPCODE_DP4:			return "dp4";
+		case OPCODE_MIN:			return "min";
+		case OPCODE_MAX:			return "max";
+		case OPCODE_SLT:			return "slt";
+		case OPCODE_SGE:			return "sge";
+		case OPCODE_EXP:			return "exp";
+		case OPCODE_LOG:			return "log";
+		case OPCODE_LIT:			return "lit";
+		case OPCODE_DST:			return "dst";
+		case OPCODE_LRP:			return "lrp";
+		case OPCODE_FRC:			return "frc";
+		case OPCODE_M4X4:			return "m4x4";
+		case OPCODE_M4X3:			return "m4x3";
+		case OPCODE_M3X4:			return "m3x4";
+		case OPCODE_M3X3:			return "m3x3";
+		case OPCODE_M3X2:			return "m3x2";
+		case OPCODE_CALL:			return "call";
+		case OPCODE_CALLNZ:			return "callnz";
+		case OPCODE_LOOP:			return "loop";
+		case OPCODE_RET:			return "ret";
+		case OPCODE_ENDLOOP:		return "endloop";
+		case OPCODE_LABEL:			return "label";
+		case OPCODE_DCL:			return "dcl";
+		case OPCODE_POW:			return "pow";
+		case OPCODE_CRS:			return "crs";
+		case OPCODE_SGN:			return "sgn";
+		case OPCODE_ABS:			return "abs";
+		case OPCODE_NRM:			return "nrm";
+		case OPCODE_SINCOS:			return "sincos";
+		case OPCODE_REP:			return "rep";
+		case OPCODE_ENDREP:			return "endrep";
+		case OPCODE_IF:				return "if";
+		case OPCODE_IFC:			return "ifc";
+		case OPCODE_ELSE:			return "else";
+		case OPCODE_ENDIF:			return "endif";
+		case OPCODE_BREAK:			return "break";
+		case OPCODE_BREAKC:			return "breakc";
+		case OPCODE_MOVA:			return "mova";
+		case OPCODE_DEFB:			return "defb";
+		case OPCODE_DEFI:			return "defi";
+		case OPCODE_TEXCOORD:		return "texcoord";
+		case OPCODE_TEXKILL:		return "texkill";
+		case OPCODE_TEX:
+			if(version < 0x0104)	return "tex";
+			else					return "texld";
+		case OPCODE_TEXBEM:			return "texbem";
+		case OPCODE_TEXBEML:		return "texbeml";
+		case OPCODE_TEXREG2AR:		return "texreg2ar";
+		case OPCODE_TEXREG2GB:		return "texreg2gb";
+		case OPCODE_TEXM3X2PAD:		return "texm3x2pad";
+		case OPCODE_TEXM3X2TEX:		return "texm3x2tex";
+		case OPCODE_TEXM3X3PAD:		return "texm3x3pad";
+		case OPCODE_TEXM3X3TEX:		return "texm3x3tex";
+		case OPCODE_RESERVED0:		return "reserved0";
+		case OPCODE_TEXM3X3SPEC:	return "texm3x3spec";
+		case OPCODE_TEXM3X3VSPEC:	return "texm3x3vspec";
+		case OPCODE_EXPP:			return "expp";
+		case OPCODE_LOGP:			return "logp";
+		case OPCODE_CND:			return "cnd";
+		case OPCODE_DEF:			return "def";
+		case OPCODE_TEXREG2RGB:		return "texreg2rgb";
+		case OPCODE_TEXDP3TEX:		return "texdp3tex";
+		case OPCODE_TEXM3X2DEPTH:	return "texm3x2depth";
+		case OPCODE_TEXDP3:			return "texdp3";
+		case OPCODE_TEXM3X3:		return "texm3x3";
+		case OPCODE_TEXDEPTH:		return "texdepth";
+		case OPCODE_CMP:			return "cmp";
+		case OPCODE_BEM:			return "bem";
+		case OPCODE_DP2ADD:			return "dp2add";
+		case OPCODE_DSX:			return "dsx";
+		case OPCODE_DSY:			return "dsy";
+		case OPCODE_TEXLDD:			return "texldd";
+		case OPCODE_SETP:			return "setp";
+		case OPCODE_TEXLDL:			return "texldl";
+		case OPCODE_BREAKP:			return "breakp";
+		case OPCODE_PHASE:			return "phase";
+		case OPCODE_COMMENT:		return "comment";
+		case OPCODE_END:			return "end";
+		case OPCODE_PS_1_0:			return "ps_1_0";
+		case OPCODE_PS_1_1:			return "ps_1_1";
+		case OPCODE_PS_1_2:			return "ps_1_2";
+		case OPCODE_PS_1_3:			return "ps_1_3";
+		case OPCODE_PS_1_4:			return "ps_1_4";
+		case OPCODE_PS_2_0:			return "ps_2_0";
+		case OPCODE_PS_2_x:			return "ps_2_x";
+		case OPCODE_PS_3_0:			return "ps_3_0";
+		case OPCODE_VS_1_0:			return "vs_1_0";
+		case OPCODE_VS_1_1:			return "vs_1_1";
+		case OPCODE_VS_2_0:			return "vs_2_0";
+		case OPCODE_VS_2_x:			return "vs_2_x";
+		case OPCODE_VS_2_sw:		return "vs_2_sw";
+		case OPCODE_VS_3_0:			return "vs_3_0";
+		case OPCODE_VS_3_sw:		return "vs_3_sw";
+		default:
+			ASSERT(false);
+		}
+
+		return "<unknown>";
+	}
+
+	std::string Shader::Instruction::Operation::controlString() const
+	{
+		if(opcode != OPCODE_LOOP && opcode != OPCODE_BREAKC && opcode != OPCODE_IFC && opcode != OPCODE_SETP)
+		{
+			if(project) return "p";
+
+			if(bias) return "b";
+
+			// FIXME: LOD
+		}
+
+		switch(control)
+		{
+		case 1: return "_gt";
+		case 2: return "_eq";
+		case 3: return "_ge";
+		case 4: return "_lt";
+		case 5: return "_ne";
+		case 6: return "_le";
+		default:
+			return "";
+		//	ASSERT(false);   // FIXME
+		}
+	}
+
+	std::string Shader::Instruction::DestinationParameter::modifierString() const
+	{
+		if(type == PARAMETER_VOID || type == PARAMETER_LABEL)
+		{
+			return "";
+		}
+
+		std::string modifierString;
+
+		if(saturate)
+		{
+			modifierString += "_sat";
+		}
+
+		if(partialPrecision)
+		{
+			modifierString += "_pp";
+		}
+
+		if(centroid)
+		{
+			modifierString += "_centroid";
+		}
+
+		return modifierString;
+	}
+
+	std::string Shader::Instruction::DestinationParameter::shiftString() const
+	{
+		if(type == PARAMETER_VOID || type == PARAMETER_LABEL)
+		{
+			return "";
+		}
+
+		switch(shift)
+		{
+		case 0:		return "";
+		case 1:		return "_x2";
+		case 2:		return "_x4"; 
+		case 3:		return "_x8";
+		case -1:	return "_d2";
+		case -2:	return "_d4"; 
+		case -3:	return "_d8";
+		default:
+			return "";
+		//	ASSERT(false);   // FIXME
+		}
+	}
+
+	std::string Shader::Instruction::DestinationParameter::maskString() const
+	{
+		if(type == PARAMETER_VOID || type == PARAMETER_LABEL)
+		{
+			return "";
+		}
+
+		switch(mask)
+		{
+		case 0x0:	return "";
+		case 0x1:	return ".x";
+		case 0x2:	return ".y";
+		case 0x3:	return ".xy";
+		case 0x4:	return ".z";
+		case 0x5:	return ".xz";
+		case 0x6:	return ".yz";
+		case 0x7:	return ".xyz";
+		case 0x8:	return ".w";
+		case 0x9:	return ".xw";
+		case 0xA:	return ".yw";
+		case 0xB:	return ".xyw";
+		case 0xC:	return ".zw";
+		case 0xD:	return ".xzw";
+		case 0xE:	return ".yzw";
+		case 0xF:	return "";
+		default:
+			ASSERT(false);
+		}
+
+		return "";
+	}
+
+	std::string Shader::Instruction::SourceParameter::preModifierString() const
+	{
+		if(type == PARAMETER_VOID)
+		{
+			return "";
+		}
+
+		switch(modifier)
+		{
+		case MODIFIER_NONE:			return "";
+		case MODIFIER_NEGATE:		return "-";
+		case MODIFIER_BIAS:			return "";
+		case MODIFIER_BIAS_NEGATE:	return "-";
+		case MODIFIER_SIGN:			return "";
+		case MODIFIER_SIGN_NEGATE:	return "-";
+		case MODIFIER_COMPLEMENT:	return "1-";
+		case MODIFIER_X2:			return "";
+		case MODIFIER_X2_NEGATE:	return "-";
+		case MODIFIER_DZ:			return "";
+		case MODIFIER_DW:			return "";
+		case MODIFIER_ABS:			return "";
+		case MODIFIER_ABS_NEGATE:	return "-";
+		case MODIFIER_NOT:			return "!";
+		default:
+			ASSERT(false);
+		}
+
+		return "";
+	}
+
+	std::string Shader::Instruction::Parameter::relativeString() const
+	{
+		if(!relative) return "";
+
+		if(relativeType == Parameter::PARAMETER_ADDR)
+		{
+			switch(relativeSwizzle & 0x03)
+			{
+			case 0: return "[a0.x]";
+			case 1: return "[a0.y]";
+			case 2: return "[a0.z]";
+			case 3: return "[a0.w]";
+			}
+		}
+		else if(relativeType == Parameter::PARAMETER_LOOP)
+		{
+			return "[aL]";
+		}
+		else ASSERT(false);
+
+		return "";
+	}
+
+	std::string Shader::Instruction::SourceParameter::postModifierString() const
+	{
+		if(type == PARAMETER_VOID)
+		{
+			return "";
+		}
+
+		switch(modifier)
+		{
+		case MODIFIER_NONE:			return "";
+		case MODIFIER_NEGATE:		return "";
+		case MODIFIER_BIAS:			return "_bias";
+		case MODIFIER_BIAS_NEGATE:	return "_bias";
+		case MODIFIER_SIGN:			return "_bx2";
+		case MODIFIER_SIGN_NEGATE:	return "_bx2";
+		case MODIFIER_COMPLEMENT:	return "";
+		case MODIFIER_X2:			return "_x2";
+		case MODIFIER_X2_NEGATE:	return "_x2";
+		case MODIFIER_DZ:			return "_dz";
+		case MODIFIER_DW:			return "_dw";
+		case MODIFIER_ABS:			return "_abs";
+		case MODIFIER_ABS_NEGATE:	return "_abs";
+		case MODIFIER_NOT:			return "";
+		default:
+			ASSERT(false);
+		}
+
+		return "";
+	}
+
+	std::string Shader::Instruction::SourceParameter::swizzleString() const
+	{
+		return Instruction::swizzleString(type, swizzle);
+	}
+
+	void Shader::Instruction::parseOperationToken(unsigned long token, unsigned char majorVersion)
+	{
+		if((token & 0xFFFF0000) == 0xFFFF0000 || (token & 0xFFFF0000) == 0xFFFE0000)   // Version token
+		{
+			operation.opcode = (Operation::Opcode)token;
+			operation.predicate = false;
+			operation.coissue = false;
+		}
+		else
+		{
+			operation.opcode = (Operation::Opcode)(token & 0x0000FFFF);
+			operation.control = (Operation::Control)((token & 0x00FF0000) >> 16);
+
+			int size = (token & 0x0F000000) >> 24;
+
+			operation.predicate = (token & 0x10000000) != 0x00000000;
+			operation.coissue = (token & 0x40000000) != 0x00000000;
+
+			if(majorVersion < 2)
+			{
+				if(size != 0)
+				{
+					ASSERT(false);   // Reserved
+				}
+			}
+
+			if(majorVersion < 2)
+			{
+				if(operation.predicate)
+				{
+					ASSERT(false);
+				}
+			}
+
+			if((token & 0x20000000) != 0x00000000)
+			{
+				ASSERT(false);   // Reserved
+			}
+
+			if(majorVersion >= 2)
+			{
+				if(operation.coissue)
+				{
+					ASSERT(false);   // Reserved
+				}
+			}
+
+			if((token & 0x80000000) != 0x00000000)
+			{
+				ASSERT(false);
+			}
+		}
+	}
+
+	void Shader::Instruction::parseDeclarationToken(unsigned long token)
+	{
+		operation.samplerType = (Operation::SamplerType)((token & 0x78000000) >> 27);
+		operation.usage = (Operation::Usage)(token & 0x0000001F);
+		operation.usageIndex = (unsigned char)((token & 0x000F0000) >> 16);
+	}
+
+	void Shader::Instruction::parseDestinationToken(const unsigned long *token, unsigned char majorVersion)
+	{
+		destinationParameter.index = (unsigned short)(token[0] & 0x000007FF);
+		destinationParameter.type = (Parameter::Type)(((token[0] & 0x00001800) >> 8) | ((token[0] & 0x70000000) >> 28));
+
+		// TODO: Check type and index range
+
+		destinationParameter.relative = (token[0] & 0x00002000) != 0x00000000;
+		destinationParameter.relativeType = Parameter::PARAMETER_ADDR;
+		destinationParameter.relativeSwizzle = 0x00;
+
+		if(destinationParameter.relative && majorVersion >= 3)
+		{
+			destinationParameter.relativeType = (Parameter::Type)(((token[1] & 0x00001800) >> 8) | ((token[1] & 0x70000000) >> 28));
+			destinationParameter.relativeSwizzle = (unsigned char)((token[1] & 0x00FF0000) >> 16);
+		}
+		else if(destinationParameter.relative) ASSERT(false);   // Reserved
+
+		if((token[0] & 0x0000C000) != 0x00000000)
+		{
+			ASSERT(false);   // Reserved
+		}
+
+		destinationParameter.mask = (unsigned char)((token[0] & 0x000F0000) >> 16);
+		destinationParameter.saturate = (token[0] & 0x00100000) != 0;
+		destinationParameter.partialPrecision = (token[0] & 0x00200000) != 0;
+		destinationParameter.centroid = (token[0] & 0x00400000) != 0;
+		destinationParameter.shift = (signed char)((token[0] & 0x0F000000) >> 20) >> 4;
+
+		if(majorVersion >= 2)
+		{
+			if(destinationParameter.shift)
+			{
+				ASSERT(false);   // Reserved
+			}
+		}
+
+		if((token[0] & 0x80000000) != 0x80000000)
+		{
+			ASSERT(false);
+		}
+	}
+
+	void Shader::Instruction::parseSourceToken(int i, const unsigned long *token, unsigned char majorVersion)
+	{
+		// Defaults
+		sourceParameter[i].value = (float&)*token;
+		sourceParameter[i].type = Parameter::PARAMETER_VOID;
+		sourceParameter[i].modifier = SourceParameter::MODIFIER_NONE;
+		sourceParameter[i].swizzle = 0xE4;
+		sourceParameter[i].relative = false;
+		sourceParameter[i].relativeType = Parameter::PARAMETER_ADDR;
+		sourceParameter[i].relativeSwizzle = 0x00;
+		
+		switch(operation.opcode)
+		{
+		case Instruction::Operation::OPCODE_DEF:
+			sourceParameter[i].type = Parameter::PARAMETER_FLOATLITERAL;
+			break;
+		case Instruction::Operation::OPCODE_DEFB:
+			sourceParameter[i].type = Parameter::PARAMETER_BOOLLITERAL;
+			break;
+		case Instruction::Operation::OPCODE_DEFI:
+			sourceParameter[i].type = Parameter::PARAMETER_INTLITERAL;
+			break;
+		default:
+			sourceParameter[i].index = (unsigned short)(token[0] & 0x000007FF);
+			sourceParameter[i].type = (Parameter::Type)(((token[0] & 0x00001800) >> 8) | ((token[0] & 0x70000000) >> 28));
+
+			// FIXME: Check type and index range
+
+			sourceParameter[i].relative = (token[0] & 0x00002000) != 0x00000000;
+
+			if((token[0] & 0x0000C000) != 0x00000000)
+			{
+				if(operation.opcode != Operation::OPCODE_DEF &&
+				   operation.opcode != Operation::OPCODE_DEFI &&
+				   operation.opcode != Operation::OPCODE_DEFB)
+				{
+					ASSERT(false);
+				}
+			}
+
+			sourceParameter[i].swizzle = (unsigned char)((token[0] & 0x00FF0000) >> 16);
+			sourceParameter[i].modifier = (SourceParameter::Modifier)((token[0] & 0x0F000000) >> 24);
+
+			if((token[0] & 0x80000000) != 0x80000000)
+			{
+				if(operation.opcode != Operation::OPCODE_DEF &&
+				   operation.opcode != Operation::OPCODE_DEFI &&
+				   operation.opcode != Operation::OPCODE_DEFB)
+				{
+					ASSERT(false);
+				}
+			}
+
+			if(sourceParameter[i].relative && majorVersion >= 2)
+			{
+				sourceParameter[i].relativeType = (Parameter::Type)(((token[1] & 0x00001800) >> 8) | ((token[1] & 0x70000000) >> 28));
+				sourceParameter[i].relativeSwizzle = (unsigned char)((token[1] & 0x00FF0000) >> 16);
+			}
+		}
+	}
+
+	std::string Shader::Instruction::swizzleString(Parameter::Type type, unsigned char swizzle)
+	{
+		if(type == Parameter::PARAMETER_VOID || type == Parameter::PARAMETER_LABEL || swizzle == 0xE4)
+		{
+			return "";
+		}
+
+		int x = (swizzle & 0x03) >> 0;
+		int y = (swizzle & 0x0C) >> 2;
+		int z = (swizzle & 0x30) >> 4;
+		int w = (swizzle & 0xC0) >> 6;
+
+		std::string swizzleString = ".";
+
+		switch(x)
+		{
+		case 0: swizzleString += "x"; break;
+		case 1: swizzleString += "y"; break;
+		case 2: swizzleString += "z"; break;
+		case 3: swizzleString += "w"; break;
+		}
+
+		if(!(x == y && y == z && z == w))
+		{
+			switch(y)
+			{
+			case 0: swizzleString += "x"; break;
+			case 1: swizzleString += "y"; break;
+			case 2: swizzleString += "z"; break;
+			case 3: swizzleString += "w"; break;
+			}
+
+			if(!(y == z && z == w))
+			{
+				switch(z)
+				{
+				case 0: swizzleString += "x"; break;
+				case 1: swizzleString += "y"; break;
+				case 2: swizzleString += "z"; break;
+				case 3: swizzleString += "w"; break;
+				}
+
+				if(!(z == w))
+				{
+					switch(w)
+					{
+					case 0: swizzleString += "x"; break;
+					case 1: swizzleString += "y"; break;
+					case 2: swizzleString += "z"; break;
+					case 3: swizzleString += "w"; break;
+					}
+				}
+			}
+		}
+
+		return swizzleString;
+	}
+
+	std::string Shader::Instruction::Parameter::string(ShaderType shaderType, unsigned short version) const
+	{
+		std::ostringstream buffer;
+
+		if(type == PARAMETER_FLOATLITERAL)
+		{
+			buffer << value;
+
+			return buffer.str();
+		}
+		else
+		{
+			if(type != PARAMETER_RASTOUT && !(type == PARAMETER_ADDR && shaderType == SHADER_VERTEX) && type != PARAMETER_LOOP && type != PARAMETER_PREDICATE && type != PARAMETER_MISCTYPE)
+			{
+				buffer << index;
+
+				return typeString(shaderType, version) + buffer.str();
+			}
+			else
+			{
+				return typeString(shaderType, version);
+			}
+		}
+	}
+
+	std::string Shader::Instruction::Parameter::typeString(ShaderType shaderType, unsigned short version) const
+	{
+		switch(type)
+		{
+		case PARAMETER_TEMP:			return "r";
+		case PARAMETER_INPUT:			return "v";
+		case PARAMETER_CONST:			return "c";
+		case PARAMETER_TEXTURE:
+	//	case PARAMETER_ADDR:
+			if(shaderType == SHADER_PIXEL)	return "t";
+			else							return "a0";
+		case PARAMETER_RASTOUT:
+			if(index == 0)              return "oPos";
+			else if(index == 1)         return "oFog";
+			else if(index == 2)         return "oPts";
+			else                        ASSERT(false);
+		case PARAMETER_ATTROUT:			return "oD";
+		case PARAMETER_TEXCRDOUT:
+	//	case PARAMETER_OUTPUT:			return "";
+			if(version < 0x0300)		return "oT";
+			else						return "o";
+		case PARAMETER_CONSTINT:		return "i";
+		case PARAMETER_COLOROUT:		return "oC";
+		case PARAMETER_DEPTHOUT:		return "oDepth";
+		case PARAMETER_SAMPLER:			return "s";
+	//	case PARAMETER_CONST2:			return "";
+	//	case PARAMETER_CONST3:			return "";
+	//	case PARAMETER_CONST4:			return "";
+		case PARAMETER_CONSTBOOL:		return "b";
+		case PARAMETER_LOOP:			return "aL";
+	//	case PARAMETER_TEMPFLOAT16:		return "";
+		case PARAMETER_MISCTYPE:
+			if(index == 0)				return "vPos";
+			else if(index == 1)			return "vFace";
+			else						ASSERT(false);
+		case PARAMETER_LABEL:			return "l";
+		case PARAMETER_PREDICATE:		return "p0";
+		case PARAMETER_FLOATLITERAL:	return "";
+		case PARAMETER_BOOLLITERAL:		return "";
+		case PARAMETER_INTLITERAL:		return "";
+	//	case PARAMETER_VOID:			return "";
+		default:
+			ASSERT(false);
+		}
+
+		return "";
+	}
+
+	Shader::Shader(const unsigned long *shaderToken)
+	{
+		instruction = 0;
+		length = 0;
+
+		tokenCount = 0;
+
+		while(shaderToken[tokenCount] != 0x0000FFFF)
+		{
+			tokenCount += sw::Shader::size(shaderToken[tokenCount], (unsigned short)(shaderToken[0] & 0xFFFF)) + 1;
+		}
+
+		tokenCount += 1;
+
+		this->shaderToken = new unsigned long[tokenCount];
+		memcpy(this->shaderToken, shaderToken, tokenCount * sizeof(unsigned long));
+
+		unsigned long *hashTokens = new unsigned long[tokenCount];
+		memcpy(hashTokens, shaderToken, tokenCount * sizeof(unsigned long));
+		removeComments(hashTokens, tokenCount);
+		hash = FNV_1((unsigned char*)hashTokens, tokenCount * sizeof(unsigned long));
+		delete[] hashTokens;
+	}
+
+	Shader::~Shader()
+	{
+		delete[] shaderToken;
+		shaderToken = 0;
+
+		for(int i = 0; i < length; i++)
+		{
+			delete instruction[i];
+			instruction[i] = 0;
+		}
+
+		delete[] instruction;
+		instruction = 0;
+	}
+
+	void Shader::getFunction(void *data, unsigned int *size)
+	{
+		if(data)
+		{
+			memcpy(data, shaderToken, tokenCount * 4);
+		}
+
+		*size = tokenCount * 4;
+	}
+
+	int Shader::size(unsigned long opcode) const
+	{
+		return size(opcode, version);
+	}
+
+	int Shader::size(unsigned long opcode, unsigned short version)
+	{
+		if(version > 0x0300)
+		{
+			ASSERT(false);
+		}
+
+		static const char size[] =
+		{
+			0,   // NOP = 0
+			2,   // MOV
+			3,   // ADD
+			3,   // SUB
+			4,   // MAD
+			3,   // MUL
+			2,   // RCP
+			2,   // RSQ
+			3,   // DP3
+			3,   // DP4
+			3,   // MIN
+			3,   // MAX
+			3,   // SLT
+			3,   // SGE
+			2,   // EXP
+			2,   // LOG
+			2,   // LIT
+			3,   // DST
+			4,   // LRP
+			2,   // FRC
+			3,   // M4x4
+			3,   // M4x3
+			3,   // M3x4
+			3,   // M3x3
+			3,   // M3x2
+			1,   // CALL
+			2,   // CALLNZ
+			2,   // LOOP
+			0,   // RET
+			0,   // ENDLOOP
+			1,   // LABEL
+			2,   // DCL
+			3,   // POW
+			3,   // CRS
+			4,   // SGN
+			2,   // ABS
+			2,   // NRM
+			4,   // SINCOS
+			1,   // REP
+			0,   // ENDREP
+			1,   // IF
+			2,   // IFC
+			0,   // ELSE
+			0,   // ENDIF
+			0,   // BREAK
+			2,   // BREAKC
+			2,   // MOVA
+			2,   // DEFB
+			5,   // DEFI
+			-1,  // 49
+			-1,  // 50
+			-1,  // 51
+			-1,  // 52
+			-1,  // 53
+			-1,  // 54
+			-1,  // 55
+			-1,  // 56
+			-1,  // 57
+			-1,  // 58
+			-1,  // 59
+			-1,  // 60
+			-1,  // 61
+			-1,  // 62
+			-1,  // 63
+			1,   // TEXCOORD = 64
+			1,   // TEXKILL
+			1,   // TEX
+			2,   // TEXBEM
+			2,   // TEXBEML
+			2,   // TEXREG2AR
+			2,   // TEXREG2GB
+			2,   // TEXM3x2PAD
+			2,   // TEXM3x2TEX
+			2,   // TEXM3x3PAD
+			2,   // TEXM3x3TEX
+			-1,  // RESERVED0
+			3,   // TEXM3x3SPEC
+			2,   // TEXM3x3VSPEC
+			2,   // EXPP
+			2,   // LOGP
+			4,   // CND
+			5,   // DEF
+			2,   // TEXREG2RGB
+			2,   // TEXDP3TEX
+			2,   // TEXM3x2DEPTH
+			2,   // TEXDP3
+			2,   // TEXM3x3
+			1,   // TEXDEPTH
+			4,   // CMP
+			3,   // BEM
+			4,   // DP2ADD
+			2,   // DSX
+			2,   // DSY
+			5,   // TEXLDD
+			3,   // SETP
+			3,   // TEXLDL
+			2,   // BREAKP
+			-1,  // 97
+			-1,  // 98
+			-1,  // 99
+			-1,  // 100
+			-1,  // 101
+			-1,  // 102
+			-1,  // 103
+			-1,  // 104
+			-1,  // 105
+			-1,  // 106
+			-1,  // 107
+			-1,  // 108
+			-1,  // 109
+			-1,  // 110
+			-1,  // 111
+			-1,  // 112
+		};
+
+		int length = 0;
+
+		if((opcode & 0x0000FFFF) == ShaderOperation::OPCODE_COMMENT)
+		{
+			return (opcode & 0x7FFF0000) >> 16;
+		}
+
+		if(opcode != ShaderOperation::OPCODE_PS_1_0 &&
+		   opcode != ShaderOperation::OPCODE_PS_1_1 &&
+		   opcode != ShaderOperation::OPCODE_PS_1_2 &&
+		   opcode != ShaderOperation::OPCODE_PS_1_3 &&
+		   opcode != ShaderOperation::OPCODE_PS_1_4 &&
+		   opcode != ShaderOperation::OPCODE_PS_2_0 &&
+		   opcode != ShaderOperation::OPCODE_PS_2_x &&
+		   opcode != ShaderOperation::OPCODE_PS_3_0 &&
+		   opcode != ShaderOperation::OPCODE_VS_1_0 &&
+		   opcode != ShaderOperation::OPCODE_VS_1_1 &&
+		   opcode != ShaderOperation::OPCODE_VS_2_0 &&
+		   opcode != ShaderOperation::OPCODE_VS_2_x &&
+		   opcode != ShaderOperation::OPCODE_VS_2_sw &&
+		   opcode != ShaderOperation::OPCODE_VS_3_0 &&
+		   opcode != ShaderOperation::OPCODE_VS_3_sw &&
+		   opcode != ShaderOperation::OPCODE_PHASE &&
+		   opcode != ShaderOperation::OPCODE_END)
+		{
+			if(version >= 0x0200)
+			{
+				length = (opcode & 0x0F000000) >> 24;
+			}
+			else
+			{
+				length = size[opcode & 0x0000FFFF];
+			}
+		}
+
+		if(length < 0)
+		{
+			ASSERT(false);
+		}
+
+		if(version == 0x0104)
+		{
+			switch(opcode & 0x0000FFFF)
+			{
+			case ShaderOperation::OPCODE_TEX:
+				length += 1;
+				break;
+			case ShaderOperation::OPCODE_TEXCOORD:
+				length += 1;
+				break;
+			default:
+				break;
+			}
+		}
+
+		return length;
+	}
+
+	bool Shader::maskContainsComponent(int mask, int component)
+	{
+		return (mask & (1 << component)) != 0;
+	}
+
+	bool Shader::swizzleContainsComponent(int swizzle, int component)
+	{
+		if((swizzle & 0x03) >> 0 == component) return true;
+		if((swizzle & 0x0C) >> 2 == component) return true;
+		if((swizzle & 0x30) >> 4 == component) return true;
+		if((swizzle & 0xC0) >> 6 == component) return true;
+
+		return false;
+	}
+
+	bool Shader::swizzleContainsComponentMasked(int swizzle, int component, int mask)
+	{
+		if(mask & 0x1) if((swizzle & 0x03) >> 0 == component) return true;
+		if(mask & 0x2) if((swizzle & 0x0C) >> 2 == component) return true;
+		if(mask & 0x4) if((swizzle & 0x30) >> 4 == component) return true;
+		if(mask & 0x8) if((swizzle & 0xC0) >> 6 == component) return true;
+
+		return false;
+	}
+
+	bool Shader::containsDynamicBranching() const
+	{
+		return dynamicBranching;
+	}
+
+	bool Shader::usesSampler(int index) const
+	{
+		return (sampler & (1 << index)) != 0;
+	}
+
+	int64_t Shader::getHash() const
+	{
+		return hash;
+	}
+
+	int Shader::getLength() const
+	{
+		return length;
+	}
+
+	Shader::ShaderType Shader::getShaderType() const
+	{
+		return shaderType;
+	}
+
+	unsigned short Shader::getVersion() const
+	{
+		return version;
+	}
+
+	void Shader::print(const char *fileName, ...) const
+	{
+		char fullName[1024 + 1];
+
+		va_list vararg;
+		va_start(vararg, fileName);
+		vsnprintf(fullName, 1024, fileName, vararg);
+		va_end(vararg);
+
+		std::ofstream file(fullName, std::ofstream::out | std::ofstream::app);
+
+		for(int i = 0; i < length; i++)
+		{
+			file << instruction[i]->string(shaderType, version) << std::endl;
+		}
+	}
+
+	void Shader::printInstruction(int index, const char *fileName) const
+	{
+		std::ofstream file(fileName, std::ofstream::out | std::ofstream::app);
+
+		file << instruction[index]->string(shaderType, version) << std::endl;
+	}
+
+	const ShaderInstruction *Shader::getInstruction(int i) const
+	{
+		if(i < 0 || i >= length)
+		{
+			ASSERT(false);
+		}
+
+		return instruction[i];
+	}
+
+	void Shader::analyzeDirtyConstants()
+	{
+		dirtyConstantsF = 0;
+		dirtyConstantsI = 0;
+		dirtyConstantsB = 0;
+
+		for(int i = 0; i < length; i++)
+		{
+			switch(instruction[i]->operation.opcode)
+			{
+			case ShaderOperation::OPCODE_DEF:
+				if(instruction[i]->destinationParameter.index + 1 > dirtyConstantsF)
+				{
+					dirtyConstantsF = instruction[i]->destinationParameter.index + 1;
+				}
+				break;
+			case ShaderOperation::OPCODE_DEFI:
+				if(instruction[i]->destinationParameter.index + 1 > dirtyConstantsI)
+				{
+					dirtyConstantsI = instruction[i]->destinationParameter.index + 1;
+				}
+				break;
+			case ShaderOperation::OPCODE_DEFB:
+				if(instruction[i]->destinationParameter.index + 1 > dirtyConstantsB)
+				{
+					dirtyConstantsB = instruction[i]->destinationParameter.index + 1;
+				}
+				break;
+			}
+		}
+	}
+
+	void Shader::analyzeDynamicBranching()
+	{
+		dynamicBranching = false;
+
+		for(int i = 0; i < length; i++)
+		{
+			switch(instruction[i]->getOpcode())
+			{
+			case ShaderOperation::OPCODE_CALLNZ:
+			case ShaderOperation::OPCODE_IF:
+			case ShaderOperation::OPCODE_IFC:
+			case ShaderOperation::OPCODE_BREAK:
+			case ShaderOperation::OPCODE_BREAKC:
+			case ShaderOperation::OPCODE_SETP:
+			case ShaderOperation::OPCODE_BREAKP:
+				if(instruction[i]->sourceParameter[0].type != ShaderParameter::PARAMETER_CONSTBOOL)
+				{
+					dynamicBranching = true;
+					break;
+				}
+			}
+		}
+	}
+
+	void Shader::analyzeSamplers()
+	{
+		sampler = 0;
+
+		for(int i = 0; i < length; i++)
+		{
+			switch(instruction[i]->getOpcode())
+			{
+			case ShaderOperation::OPCODE_TEX:
+			case ShaderOperation::OPCODE_TEXBEM:
+			case ShaderOperation::OPCODE_TEXBEML:
+			case ShaderOperation::OPCODE_TEXREG2AR:
+			case ShaderOperation::OPCODE_TEXREG2GB:
+			case ShaderOperation::OPCODE_TEXM3X2TEX:
+			case ShaderOperation::OPCODE_TEXM3X3TEX:
+			case ShaderOperation::OPCODE_TEXM3X3SPEC:
+			case ShaderOperation::OPCODE_TEXM3X3VSPEC:
+			case ShaderOperation::OPCODE_TEXREG2RGB:
+			case ShaderOperation::OPCODE_TEXDP3TEX:
+			case ShaderOperation::OPCODE_TEXM3X2DEPTH:
+			case ShaderOperation::OPCODE_TEXLDD:
+			case ShaderOperation::OPCODE_TEXLDL:
+				{
+					ShaderParameter &dst = instruction[i]->destinationParameter;
+					ShaderParameter &src1 = instruction[i]->sourceParameter[1];
+
+					if(majorVersion >= 2)
+					{
+						ASSERT(src1.type == ShaderParameter::PARAMETER_SAMPLER);
+						sampler |= 1 << src1.index;
+					}
+					else
+					{
+						sampler |= 1 << dst.index;
+					}
+				}
+				break;
+			}
+		}
+	}
+
+	void Shader::removeComments(unsigned long *shaderToken, int tokenCount)
+	{
+		for(int i = 0; i < tokenCount; )
+		{
+			int instructionSize = sw::Shader::size(shaderToken[i], (unsigned short)(shaderToken[0] & 0xFFFF)) + 1;
+
+			if((shaderToken[i] & 0x0000FFFF) == ShaderOperation::OPCODE_COMMENT)
+			{
+				for(int j = 0; j < instructionSize; j++)
+				{
+					shaderToken[i + j] = ShaderOperation::OPCODE_NOP;
+				}
+			}
+
+			i += instructionSize;
+		}
+	}
+}