Update SwiftShader to April code dump.

April code dump from Transgaming. Adds new shader compiler.
diff --git a/src/Shader/Shader.cpp b/src/Shader/Shader.cpp
index 43e8bdc..fcbc839 100644
--- a/src/Shader/Shader.cpp
+++ b/src/Shader/Shader.cpp
@@ -1,6 +1,6 @@
 // SwiftShader Software Renderer
 //
-// Copyright(c) 2005-2011 TransGaming Inc.
+// Copyright(c) 2005-2012 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
@@ -11,42 +11,137 @@
 
 #include "Shader.hpp"
 
+#include "VertexShader.hpp"
+#include "PixelShader.hpp"
 #include "Math.hpp"
 #include "Debug.hpp"
 
-#include <stdarg.h>
 #include <fstream>
 #include <sstream>
 
 namespace sw
 {
-	Shader::Instruction::Instruction()
+	volatile int Shader::serialCounter = 1;
+
+	Shader::Opcode Shader::OPCODE_DP(int i)
 	{
-		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;
+		switch(i)
+		{
+		default: ASSERT(false);
+		case 1: return OPCODE_DP1;
+		case 2: return OPCODE_DP2;
+		case 3: return OPCODE_DP3;
+		case 4: return OPCODE_DP4;
+		}
 	}
 
-	Shader::Instruction::Instruction(const unsigned long *token, int size, unsigned char majorVersion)
+	Shader::Opcode Shader::OPCODE_LEN(int i)
+	{
+		switch(i)
+		{
+		default: ASSERT(false);
+		case 1: return OPCODE_ABS;
+		case 2: return OPCODE_LEN2;
+		case 3: return OPCODE_LEN3;
+		case 4: return OPCODE_LEN4;
+		}
+	}
+
+	Shader::Opcode Shader::OPCODE_DIST(int i)
+	{
+		switch(i)
+		{
+		default: ASSERT(false);
+		case 1: return OPCODE_DIST1;
+		case 2: return OPCODE_DIST2;
+		case 3: return OPCODE_DIST3;
+		case 4: return OPCODE_DIST4;
+		}
+	}
+
+	Shader::Opcode Shader::OPCODE_NRM(int i)	
+	{
+		switch(i)
+		{
+		default: ASSERT(false);
+		case 1: return OPCODE_SGN;
+		case 2: return OPCODE_NRM2;
+		case 3: return OPCODE_NRM3;
+		case 4: return OPCODE_NRM4;
+		}
+	}
+
+	Shader::Opcode Shader::OPCODE_FORWARD(int i)
+	{
+		switch(i)
+		{
+		default: ASSERT(false);
+		case 1: return OPCODE_FORWARD1;
+		case 2: return OPCODE_FORWARD2;
+		case 3: return OPCODE_FORWARD3;
+		case 4: return OPCODE_FORWARD4;
+		}
+	}
+
+	Shader::Opcode Shader::OPCODE_REFLECT(int i)
+	{
+		switch(i)
+		{
+		default: ASSERT(false);
+		case 1: return OPCODE_REFLECT1;
+		case 2: return OPCODE_REFLECT2;
+		case 3: return OPCODE_REFLECT3;
+		case 4: return OPCODE_REFLECT4;
+		}
+	}
+
+	Shader::Opcode Shader::OPCODE_REFRACT(int i)
+	{
+		switch(i)
+		{
+		default: ASSERT(false);
+		case 1: return OPCODE_REFRACT1;
+		case 2: return OPCODE_REFRACT2;
+		case 3: return OPCODE_REFRACT3;
+		case 4: return OPCODE_REFRACT4;
+		}
+	}
+
+	Shader::Instruction::Instruction(Opcode opcode) : opcode(opcode), analysis(0)
+	{
+		control = CONTROL_RESERVED0;
+
+		predicate = false;
+		predicateNot = false;
+		predicateSwizzle = 0xE4;
+		
+		coissue = false;
+		samplerType = SAMPLER_UNKNOWN;
+		usage = USAGE_POSITION;
+		usageIndex = 0;
+	}
+
+	Shader::Instruction::Instruction(const unsigned long *token, int size, unsigned char majorVersion) : analysis(0)
 	{
 		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
+		samplerType = SAMPLER_UNKNOWN;
+		usage = USAGE_POSITION;
+		usageIndex = 0;
+
+		if(opcode == OPCODE_IF ||
+		   opcode == OPCODE_IFC ||
+		   opcode == OPCODE_LOOP ||
+		   opcode == OPCODE_REP ||
+		   opcode == OPCODE_BREAKC ||
+		   opcode == 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)
+		else if(opcode == OPCODE_DCL)
 		{
 			parseDeclarationToken(*token++);
 			parseDestinationToken(token++, majorVersion);
@@ -57,7 +152,7 @@
 			{
 				parseDestinationToken(token, majorVersion);
 
-				if(destinationParameter.relative && majorVersion >= 3)
+				if(dst.rel.type != PARAMETER_VOID && majorVersion >= 3)
 				{
 					token++;
 					size--;
@@ -67,12 +162,12 @@
 				size--;
 			}
 
-			if(operation.predicate)
+			if(predicate)
 			{
 				ASSERT(size != 0);
 
-				operation.predicateNot = (SourceParameter::Modifier)((*token & 0x0F000000) >> 24) == SourceParameter::MODIFIER_NOT;
-				operation.predicateSwizzle = (unsigned char)((*token & 0x00FF0000) >> 16);
+				predicateNot = (Modifier)((*token & 0x0F000000) >> 24) == MODIFIER_NOT;
+				predicateSwizzle = (unsigned char)((*token & 0x00FF0000) >> 16);
 				
 				token++;
 				size--;
@@ -85,7 +180,7 @@
 				token++;
 				size--;
 
-				if(sourceParameter[i].relative && majorVersion >= 2)
+				if(src[i].rel.type != PARAMETER_VOID && majorVersion >= 2)
 				{
 					token++;
 					size--;
@@ -98,105 +193,40 @@
 	{
 	}
 
-	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)
+		if(opcode != OPCODE_DCL)
 		{
-			instructionString += operation.coissue ? "+ " : "";
+			instructionString += coissue ? "+ " : "";
 			
-			if(operation.predicate)
+			if(predicate)
 			{
-				instructionString += operation.predicateNot ? "(!p0" : "(p0";
-				instructionString += swizzleString(Parameter::PARAMETER_PREDICATE, operation.predicateSwizzle);
+				instructionString += predicateNot ? "(!p0" : "(p0";
+				instructionString += swizzleString(PARAMETER_PREDICATE, predicateSwizzle);
 				instructionString += ") ";
 			}
 
-			instructionString += operation.string(version) + operation.controlString() + destinationParameter.shiftString() + destinationParameter.modifierString();
+			instructionString += operationString(version) + controlString() + dst.shiftString() + dst.modifierString();
 
-			if(destinationParameter.type != Parameter::PARAMETER_VOID)
+			if(dst.type != PARAMETER_VOID)
 			{
-				instructionString += " " + destinationParameter.string(shaderType, version) +
-				                           destinationParameter.relativeString() +
-				                           destinationParameter.maskString(); 
+				instructionString += " " + dst.string(shaderType, version) +
+				                           dst.relativeString() +
+				                           dst.maskString(); 
 			}
 
 			for(int i = 0; i < 4; i++)
 			{
-				if(sourceParameter[i].type != Parameter::PARAMETER_VOID)
+				if(src[i].type != 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();
+					instructionString += (dst.type != PARAMETER_VOID || i > 0) ? ", " : " ";
+					instructionString += src[i].preModifierString() +
+										 src[i].string(shaderType, version) +
+										 src[i].relativeString() + 
+										 src[i].postModifierString() + 
+										 src[i].swizzleString();
 				}
 			}
 		}
@@ -204,68 +234,68 @@
 		{
 			instructionString += "dcl";
 
-			if(destinationParameter.type == Parameter::PARAMETER_SAMPLER)
+			if(dst.type == PARAMETER_SAMPLER)
 			{
-				switch(operation.samplerType)
+				switch(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;
+				case SAMPLER_UNKNOWN: instructionString += " ";        break;
+				case SAMPLER_1D:      instructionString += "_1d ";     break;
+				case SAMPLER_2D:      instructionString += "_2d ";     break;
+				case SAMPLER_CUBE:    instructionString += "_cube ";   break;
+				case SAMPLER_VOLUME:  instructionString += "_volume "; break;
 				default:
 					ASSERT(false);
 				}
 
-				instructionString += destinationParameter.string(shaderType, version);
+				instructionString += dst.string(shaderType, version);
 			}
-			else if(destinationParameter.type == Parameter::PARAMETER_INPUT ||
-				    destinationParameter.type == Parameter::PARAMETER_OUTPUT ||
-				    destinationParameter.type == Parameter::PARAMETER_TEXTURE)
+			else if(dst.type == PARAMETER_INPUT ||
+				    dst.type == PARAMETER_OUTPUT ||
+				    dst.type == PARAMETER_TEXTURE)
 			{
 				if(version >= 0x0300)
 				{
-					switch(operation.usage)
+					switch(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;
+					case USAGE_POSITION:     instructionString += "_position";     break;
+					case USAGE_BLENDWEIGHT:  instructionString += "_blendweight";  break;
+					case USAGE_BLENDINDICES: instructionString += "_blendindices"; break;
+					case USAGE_NORMAL:       instructionString += "_normal";       break;
+					case USAGE_PSIZE:        instructionString += "_psize";        break;
+					case USAGE_TEXCOORD:     instructionString += "_texcoord";     break;
+					case USAGE_TANGENT:      instructionString += "_tangent";      break;
+					case USAGE_BINORMAL:     instructionString += "_binormal";     break;
+					case USAGE_TESSFACTOR:   instructionString += "_tessfactor";   break;
+					case USAGE_POSITIONT:    instructionString += "_positiont";    break;
+					case USAGE_COLOR:        instructionString += "_color";        break;
+					case USAGE_FOG:          instructionString += "_fog";          break;
+					case USAGE_DEPTH:        instructionString += "_depth";        break;
+					case USAGE_SAMPLE:       instructionString += "_sample";       break;
 					default:
 						ASSERT(false);
 					}
 
-					if(operation.usageIndex > 0)
+					if(usageIndex > 0)
 					{
 						std::ostringstream buffer;
 
-						buffer << (int)operation.usageIndex;
+						buffer << (int)usageIndex;
 
 						instructionString += buffer.str();
 					}
 				}
-				else ASSERT(destinationParameter.type != Parameter::PARAMETER_OUTPUT);
+				else ASSERT(dst.type != PARAMETER_OUTPUT);
 
 				instructionString += " ";
 
-				instructionString += destinationParameter.string(shaderType, version);
-				instructionString += destinationParameter.maskString();
+				instructionString += dst.string(shaderType, version);
+				instructionString += dst.maskString();
 			}
-			else if(destinationParameter.type == Parameter::PARAMETER_MISCTYPE)   // vPos and vFace
+			else if(dst.type == PARAMETER_MISCTYPE)   // vPos and vFace
 			{
 				instructionString += " ";
 
-				instructionString += destinationParameter.string(shaderType, version);
+				instructionString += dst.string(shaderType, version);
 			}
 			else ASSERT(false);
 		}
@@ -273,145 +303,7 @@
 		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
+	std::string Shader::DestinationParameter::modifierString() const
 	{
 		if(type == PARAMETER_VOID || type == PARAMETER_LABEL)
 		{
@@ -420,6 +312,11 @@
 
 		std::string modifierString;
 
+		if(integer)
+		{
+			modifierString += "_int";
+		}
+
 		if(saturate)
 		{
 			modifierString += "_sat";
@@ -438,7 +335,7 @@
 		return modifierString;
 	}
 
-	std::string Shader::Instruction::DestinationParameter::shiftString() const
+	std::string Shader::DestinationParameter::shiftString() const
 	{
 		if(type == PARAMETER_VOID || type == PARAMETER_LABEL)
 		{
@@ -460,7 +357,7 @@
 		}
 	}
 
-	std::string Shader::Instruction::DestinationParameter::maskString() const
+	std::string Shader::DestinationParameter::maskString() const
 	{
 		if(type == PARAMETER_VOID || type == PARAMETER_LABEL)
 		{
@@ -492,7 +389,7 @@
 		return "";
 	}
 
-	std::string Shader::Instruction::SourceParameter::preModifierString() const
+	std::string Shader::SourceParameter::preModifierString() const
 	{
 		if(type == PARAMETER_VOID)
 		{
@@ -522,30 +419,48 @@
 		return "";
 	}
 
-	std::string Shader::Instruction::Parameter::relativeString() const
+	std::string Shader::Parameter::relativeString() const
 	{
-		if(!relative) return "";
-
-		if(relativeType == Parameter::PARAMETER_ADDR)
+		if(type == PARAMETER_CONST || type == PARAMETER_INPUT || type == PARAMETER_OUTPUT || type == PARAMETER_TEMP)
 		{
-			switch(relativeSwizzle & 0x03)
+			if(rel.type == PARAMETER_VOID)
 			{
-			case 0: return "[a0.x]";
-			case 1: return "[a0.y]";
-			case 2: return "[a0.z]";
-			case 3: return "[a0.w]";
+				return "";
 			}
+			else if(rel.type == PARAMETER_ADDR)
+			{
+				switch(rel.swizzle & 0x03)
+				{
+				case 0: return "[a0.x]";
+				case 1: return "[a0.y]";
+				case 2: return "[a0.z]";
+				case 3: return "[a0.w]";
+				}
+			}
+			else if(rel.type == PARAMETER_TEMP)
+			{
+				std::ostringstream buffer;
+				buffer << rel.index;
+
+				switch(rel.swizzle & 0x03)
+				{
+				case 0: return "[r" + buffer.str() + ".x]";
+				case 1: return "[r" + buffer.str() + ".y]";
+				case 2: return "[r" + buffer.str() + ".z]";
+				case 3: return "[r" + buffer.str() + ".w]";
+				}
+			}
+			else if(rel.type == PARAMETER_LOOP)
+			{
+				return "[aL]";
+			}
+			else ASSERT(false);
 		}
-		else if(relativeType == Parameter::PARAMETER_LOOP)
-		{
-			return "[aL]";
-		}
-		else ASSERT(false);
 
 		return "";
 	}
 
-	std::string Shader::Instruction::SourceParameter::postModifierString() const
+	std::string Shader::SourceParameter::postModifierString() const
 	{
 		if(type == PARAMETER_VOID)
 		{
@@ -575,7 +490,7 @@
 		return "";
 	}
 
-	std::string Shader::Instruction::SourceParameter::swizzleString() const
+	std::string Shader::SourceParameter::swizzleString() const
 	{
 		return Instruction::swizzleString(type, swizzle);
 	}
@@ -584,19 +499,21 @@
 	{
 		if((token & 0xFFFF0000) == 0xFFFF0000 || (token & 0xFFFF0000) == 0xFFFE0000)   // Version token
 		{
-			operation.opcode = (Operation::Opcode)token;
-			operation.predicate = false;
-			operation.coissue = false;
+			opcode = (Opcode)token;
+
+			control = CONTROL_RESERVED0;
+			predicate = false;
+			coissue = false;
 		}
 		else
 		{
-			operation.opcode = (Operation::Opcode)(token & 0x0000FFFF);
-			operation.control = (Operation::Control)((token & 0x00FF0000) >> 16);
+			opcode = (Opcode)(token & 0x0000FFFF);
+			control = (Control)((token & 0x00FF0000) >> 16);
 
 			int size = (token & 0x0F000000) >> 24;
 
-			operation.predicate = (token & 0x10000000) != 0x00000000;
-			operation.coissue = (token & 0x40000000) != 0x00000000;
+			predicate = (token & 0x10000000) != 0x00000000;
+			coissue = (token & 0x40000000) != 0x00000000;
 
 			if(majorVersion < 2)
 			{
@@ -608,7 +525,7 @@
 
 			if(majorVersion < 2)
 			{
-				if(operation.predicate)
+				if(predicate)
 				{
 					ASSERT(false);
 				}
@@ -621,7 +538,7 @@
 
 			if(majorVersion >= 2)
 			{
-				if(operation.coissue)
+				if(coissue)
 				{
 					ASSERT(false);   // Reserved
 				}
@@ -636,43 +553,44 @@
 
 	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);
+		samplerType = (SamplerType)((token & 0x78000000) >> 27);
+		usage = (Usage)(token & 0x0000001F);
+		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));
+		dst.index = (unsigned short)(token[0] & 0x000007FF);
+		dst.type = (ParameterType)(((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;
+		bool relative = (token[0] & 0x00002000) != 0x00000000;
+		dst.rel.type = relative ? PARAMETER_ADDR : PARAMETER_VOID;
+		dst.rel.swizzle = 0x00;
+		dst.rel.scale = 1;
 
-		if(destinationParameter.relative && majorVersion >= 3)
+		if(relative && majorVersion >= 3)
 		{
-			destinationParameter.relativeType = (Parameter::Type)(((token[1] & 0x00001800) >> 8) | ((token[1] & 0x70000000) >> 28));
-			destinationParameter.relativeSwizzle = (unsigned char)((token[1] & 0x00FF0000) >> 16);
+			dst.rel.type = (ParameterType)(((token[1] & 0x00001800) >> 8) | ((token[1] & 0x70000000) >> 28));
+			dst.rel.swizzle = (unsigned char)((token[1] & 0x00FF0000) >> 16);
 		}
-		else if(destinationParameter.relative) ASSERT(false);   // Reserved
+		else if(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;
+		dst.mask = (unsigned char)((token[0] & 0x000F0000) >> 16);
+		dst.saturate = (token[0] & 0x00100000) != 0;
+		dst.partialPrecision = (token[0] & 0x00200000) != 0;
+		dst.centroid = (token[0] & 0x00400000) != 0;
+		dst.shift = (signed char)((token[0] & 0x0F000000) >> 20) >> 4;
 
 		if(majorVersion >= 2)
 		{
-			if(destinationParameter.shift)
+			if(dst.shift)
 			{
 				ASSERT(false);   // Reserved
 			}
@@ -687,67 +605,71 @@
 	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;
+		src[i].index = 0;
+		src[i].type = PARAMETER_VOID;
+		src[i].modifier = MODIFIER_NONE;
+		src[i].swizzle = 0xE4;
+		src[i].rel.type = PARAMETER_VOID;
+		src[i].rel.swizzle = 0x00;
+		src[i].rel.scale = 1;
 		
-		switch(operation.opcode)
+		switch(opcode)
 		{
-		case Instruction::Operation::OPCODE_DEF:
-			sourceParameter[i].type = Parameter::PARAMETER_FLOATLITERAL;
+		case OPCODE_DEF:
+			src[0].type = PARAMETER_FLOAT4LITERAL;
+			src[0].value[i] = *(float*)token;
 			break;
-		case Instruction::Operation::OPCODE_DEFB:
-			sourceParameter[i].type = Parameter::PARAMETER_BOOLLITERAL;
+		case OPCODE_DEFB:
+			src[0].type = PARAMETER_BOOL1LITERAL;
+			src[0].boolean[0] = *(int*)token;
 			break;
-		case Instruction::Operation::OPCODE_DEFI:
-			sourceParameter[i].type = Parameter::PARAMETER_INTLITERAL;
+		case OPCODE_DEFI:
+			src[0].type = PARAMETER_INT4LITERAL;
+			src[0].integer[i] = *(int*)token;
 			break;
 		default:
-			sourceParameter[i].index = (unsigned short)(token[0] & 0x000007FF);
-			sourceParameter[i].type = (Parameter::Type)(((token[0] & 0x00001800) >> 8) | ((token[0] & 0x70000000) >> 28));
+			src[i].index = (unsigned short)(token[0] & 0x000007FF);
+			src[i].type = (ParameterType)(((token[0] & 0x00001800) >> 8) | ((token[0] & 0x70000000) >> 28));
 
 			// FIXME: Check type and index range
 
-			sourceParameter[i].relative = (token[0] & 0x00002000) != 0x00000000;
+			bool relative = (token[0] & 0x00002000) != 0x00000000;
+			src[i].rel.type = relative ? PARAMETER_ADDR : PARAMETER_VOID;
 
 			if((token[0] & 0x0000C000) != 0x00000000)
 			{
-				if(operation.opcode != Operation::OPCODE_DEF &&
-				   operation.opcode != Operation::OPCODE_DEFI &&
-				   operation.opcode != Operation::OPCODE_DEFB)
+				if(opcode != OPCODE_DEF &&
+				   opcode != OPCODE_DEFI &&
+				   opcode != OPCODE_DEFB)
 				{
 					ASSERT(false);
 				}
 			}
 
-			sourceParameter[i].swizzle = (unsigned char)((token[0] & 0x00FF0000) >> 16);
-			sourceParameter[i].modifier = (SourceParameter::Modifier)((token[0] & 0x0F000000) >> 24);
+			src[i].swizzle = (unsigned char)((token[0] & 0x00FF0000) >> 16);
+			src[i].modifier = (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)
+				if(opcode != OPCODE_DEF &&
+				   opcode != OPCODE_DEFI &&
+				   opcode != OPCODE_DEFB)
 				{
 					ASSERT(false);
 				}
 			}
 
-			if(sourceParameter[i].relative && majorVersion >= 2)
+			if(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);
+				src[i].rel.type = (ParameterType)(((token[1] & 0x00001800) >> 8) | ((token[1] & 0x70000000) >> 28));
+				src[i].rel.swizzle = (unsigned char)((token[1] & 0x00FF0000) >> 16);
 			}
 		}
 	}
 
-	std::string Shader::Instruction::swizzleString(Parameter::Type type, unsigned char swizzle)
+	std::string Shader::Instruction::swizzleString(ParameterType type, unsigned char swizzle)
 	{
-		if(type == Parameter::PARAMETER_VOID || type == Parameter::PARAMETER_LABEL || swizzle == 0xE4)
+		if(type == PARAMETER_VOID || type == PARAMETER_LABEL || swizzle == 0xE4)
 		{
 			return "";
 		}
@@ -803,32 +725,230 @@
 		return swizzleString;
 	}
 
-	std::string Shader::Instruction::Parameter::string(ShaderType shaderType, unsigned short version) const
+	std::string Shader::Instruction::operationString(unsigned short version) const
 	{
-		std::ostringstream buffer;
-
-		if(type == PARAMETER_FLOATLITERAL)
+		switch(opcode)
 		{
-			buffer << value;
-
-			return buffer.str();
+		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_RCPX:			return "rcpx";
+		case OPCODE_DIV:			return "div";
+		case OPCODE_MOD:			return "mod";
+		case OPCODE_RSQX:			return "rsqx";
+		case OPCODE_SQRT:			return "sqrt";
+		case OPCODE_RSQ:			return "rsq";
+		case OPCODE_LEN2:			return "len2";
+		case OPCODE_LEN3:			return "len3";
+		case OPCODE_LEN4:			return "len4";
+		case OPCODE_DIST1:			return "dist1";
+		case OPCODE_DIST2:			return "dist2";
+		case OPCODE_DIST3:			return "dist3";
+		case OPCODE_DIST4:			return "dist4";
+		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_EXP2X:			return "exp2x";
+		case OPCODE_LOG2X:			return "log2x";
+		case OPCODE_LIT:			return "lit";
+		case OPCODE_ATT:			return "att";
+		case OPCODE_LRP:			return "lrp";
+		case OPCODE_STEP:			return "step";
+		case OPCODE_SMOOTH:			return "smooth";
+		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_POWX:			return "powx";
+		case OPCODE_CRS:			return "crs";
+		case OPCODE_SGN:			return "sgn";
+		case OPCODE_ABS:			return "abs";
+		case OPCODE_NRM2:			return "nrm2";
+		case OPCODE_NRM3:			return "nrm3";
+		case OPCODE_NRM4:			return "nrm4";
+		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_DISCARD:		return "discard";
+		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_CMP0:			return "cmp0";
+		case OPCODE_ICMP:			return "icmp";
+		case OPCODE_SELECT:			return "select";
+		case OPCODE_EXTRACT:		return "extract";
+		case OPCODE_INSERT:			return "insert";
+		case OPCODE_BEM:			return "bem";
+		case OPCODE_DP2ADD:			return "dp2add";
+		case OPCODE_DFDX:			return "dFdx";
+		case OPCODE_DFDY:			return "dFdy";
+		case OPCODE_FWIDTH:			return "fwidth";
+		case OPCODE_TEXLDD:			return "texldd";
+		case OPCODE_CMP:			return "cmp";
+		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";
+		case OPCODE_WHILE:          return "while";
+		case OPCODE_ENDWHILE:       return "endwhile";
+		case OPCODE_COS:            return "cos";
+		case OPCODE_SIN:            return "sin";
+		case OPCODE_TAN:            return "tan";
+		case OPCODE_ACOS:           return "acos";
+		case OPCODE_ASIN:           return "asin";
+		case OPCODE_ATAN:           return "atan";
+		case OPCODE_ATAN2:          return "atan2";
+		case OPCODE_DP1:            return "dp1";
+		case OPCODE_DP2:            return "dp2";
+		case OPCODE_TRUNC:          return "trunc";
+		case OPCODE_FLOOR:          return "floor";
+		case OPCODE_CEIL:           return "ceil";
+		case OPCODE_EXP2:           return "exp2";
+		case OPCODE_LOG2:           return "log2";
+		case OPCODE_EXP:            return "exp";
+		case OPCODE_LOG:            return "log";
+		case OPCODE_POW:            return "pow";
+		case OPCODE_F2B:            return "f2b";
+		case OPCODE_B2F:            return "b2f";
+		case OPCODE_ALL:            return "all";
+		case OPCODE_ANY:            return "any";
+		case OPCODE_NOT:            return "not";
+		case OPCODE_OR:             return "or";
+		case OPCODE_XOR:            return "xor";
+		case OPCODE_AND:            return "and";
+		case OPCODE_FORWARD1:       return "forward1";
+		case OPCODE_FORWARD2:       return "forward2";
+		case OPCODE_FORWARD3:       return "forward3";
+		case OPCODE_FORWARD4:       return "forward4";
+		case OPCODE_REFLECT1:       return "reflect1";
+		case OPCODE_REFLECT2:       return "reflect2";
+		case OPCODE_REFLECT3:       return "reflect3";
+		case OPCODE_REFLECT4:       return "reflect4";
+		case OPCODE_REFRACT1:       return "refract1";
+		case OPCODE_REFRACT2:       return "refract2";
+		case OPCODE_REFRACT3:       return "refract3";
+		case OPCODE_REFRACT4:       return "refract4";
+		case OPCODE_LEAVE:          return "leave";
+		case OPCODE_CONTINUE:       return "continue";
+		case OPCODE_TEST:           return "test";
+		default:
+			ASSERT(false);
 		}
-		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);
-			}
+		return "<unknown>";
+	}
+
+	std::string Shader::Instruction::controlString() const
+	{
+		if(opcode != OPCODE_LOOP && opcode != OPCODE_BREAKC && opcode != OPCODE_IFC && opcode != OPCODE_CMP)
+		{
+			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::Parameter::typeString(ShaderType shaderType, unsigned short version) const
+	std::string Shader::Parameter::string(ShaderType shaderType, unsigned short version) const
+	{
+		std::ostringstream buffer;
+
+		if(type == PARAMETER_FLOAT4LITERAL)
+		{
+			buffer << '{' << value[0] << ", " << value[1] << ", " << value[2] << ", " << value[3] << '}';
+
+			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::Parameter::typeString(ShaderType shaderType, unsigned short version) const
 	{
 		switch(type)
 		{
@@ -865,9 +985,9 @@
 			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_FLOAT4LITERAL:	return "";
+		case PARAMETER_BOOL1LITERAL:	return "";
+		case PARAMETER_INT4LITERAL:		return "";
 	//	case PARAMETER_VOID:			return "";
 		default:
 			ASSERT(false);
@@ -876,55 +996,83 @@
 		return "";
 	}
 
-	Shader::Shader(const unsigned long *shaderToken)
+	bool Shader::Instruction::isBranch() const
 	{
-		instruction = 0;
-		length = 0;
+		return opcode == OPCODE_IF || opcode == OPCODE_IFC;
+	}
+	
+	bool Shader::Instruction::isCall() const
+	{
+		return opcode == OPCODE_CALL || opcode == OPCODE_CALLNZ;
+	}
 
-		tokenCount = 0;
+	bool Shader::Instruction::isBreak() const
+	{
+		return opcode == OPCODE_BREAK || opcode == OPCODE_BREAKC || opcode == OPCODE_BREAKP;
+	}
 
-		while(shaderToken[tokenCount] != 0x0000FFFF)
-		{
-			tokenCount += sw::Shader::size(shaderToken[tokenCount], (unsigned short)(shaderToken[0] & 0xFFFF)) + 1;
-		}
+	bool Shader::Instruction::isLoop() const
+	{
+		return opcode == OPCODE_LOOP || opcode == OPCODE_REP || opcode == OPCODE_WHILE;
+	}
 
-		tokenCount += 1;
+	bool Shader::Instruction::isEndLoop() const
+	{
+		return opcode == OPCODE_ENDLOOP || opcode == OPCODE_ENDREP || opcode == OPCODE_ENDWHILE;
+	}
 
-		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() : serialID(serialCounter++)
+	{
+		usedSamplers = 0;
 	}
 
 	Shader::~Shader()
 	{
-		delete[] shaderToken;
-		shaderToken = 0;
-
-		for(int i = 0; i < length; i++)
+		for(unsigned int i = 0; i < instruction.size(); i++)
 		{
 			delete instruction[i];
 			instruction[i] = 0;
 		}
-
-		delete[] instruction;
-		instruction = 0;
 	}
 
-	void Shader::getFunction(void *data, unsigned int *size)
+	void Shader::parse(const unsigned long *token)
 	{
-		if(data)
+		minorVersion = (unsigned char)(token[0] & 0x000000FF);
+		majorVersion = (unsigned char)((token[0] & 0x0000FF00) >> 8);
+		shaderType = (ShaderType)((token[0] & 0xFFFF0000) >> 16);
+
+		int length;
+
+		if(shaderType == SHADER_VERTEX)
 		{
-			memcpy(data, shaderToken, tokenCount * 4);
+			length = VertexShader::validate(token);
 		}
+		else if(shaderType == SHADER_PIXEL)
+		{
+			length = PixelShader::validate(token);
+		}
+		else ASSERT(false);
 
-		*size = tokenCount * 4;
+		ASSERT(length != 0);
+		instruction.resize(length);
+
+		for(int i = 0; i < length; i++)
+		{
+			while((*token & 0x0000FFFF) == 0x0000FFFE)   // Comment token
+			{
+				int length = (*token & 0x7FFF0000) >> 16;
+
+				token += length + 1;
+			}
+
+			int tokenCount = size(*token);
+
+			instruction[i] = new Instruction(token, tokenCount, majorVersion);
+
+			token += 1 + tokenCount;
+		}
 	}
-
+	
 	int Shader::size(unsigned long opcode) const
 	{
 		return size(opcode, version);
@@ -1056,28 +1204,28 @@
 
 		int length = 0;
 
-		if((opcode & 0x0000FFFF) == ShaderOperation::OPCODE_COMMENT)
+		if((opcode & 0x0000FFFF) == 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(opcode != OPCODE_PS_1_0 &&
+		   opcode != OPCODE_PS_1_1 &&
+		   opcode != OPCODE_PS_1_2 &&
+		   opcode != OPCODE_PS_1_3 &&
+		   opcode != OPCODE_PS_1_4 &&
+		   opcode != OPCODE_PS_2_0 &&
+		   opcode != OPCODE_PS_2_x &&
+		   opcode != OPCODE_PS_3_0 &&
+		   opcode != OPCODE_VS_1_0 &&
+		   opcode != OPCODE_VS_1_1 &&
+		   opcode != OPCODE_VS_2_0 &&
+		   opcode != OPCODE_VS_2_x &&
+		   opcode != OPCODE_VS_2_sw &&
+		   opcode != OPCODE_VS_3_0 &&
+		   opcode != OPCODE_VS_3_sw &&
+		   opcode != OPCODE_PHASE &&
+		   opcode != OPCODE_END)
 		{
 			if(version >= 0x0200)
 			{
@@ -1098,10 +1246,10 @@
 		{
 			switch(opcode & 0x0000FFFF)
 			{
-			case ShaderOperation::OPCODE_TEX:
+			case OPCODE_TEX:
 				length += 1;
 				break;
-			case ShaderOperation::OPCODE_TEXCOORD:
+			case OPCODE_TEXCOORD:
 				length += 1;
 				break;
 			default:
@@ -1142,19 +1290,34 @@
 		return dynamicBranching;
 	}
 
-	bool Shader::usesSampler(int index) const
+	bool Shader::containsBreakInstruction() const
 	{
-		return (sampler & (1 << index)) != 0;
+		return containsBreak;
 	}
 
-	int64_t Shader::getHash() const
+	bool Shader::containsContinueInstruction() const
 	{
-		return hash;
+		return containsContinue;
+	}
+
+	bool Shader::containsLeaveInstruction() const
+	{
+		return containsLeave;
+	}
+
+	bool Shader::usesSampler(int index) const
+	{
+		return (usedSamplers & (1 << index)) != 0;
+	}
+
+	int Shader::getSerialID() const
+	{
+		return serialID;
 	}
 
 	int Shader::getLength() const
 	{
-		return length;
+		return instruction.size();
 	}
 
 	Shader::ShaderType Shader::getShaderType() const
@@ -1176,9 +1339,9 @@
 		vsnprintf(fullName, 1024, fileName, vararg);
 		va_end(vararg);
 
-		std::ofstream file(fullName, std::ofstream::out | std::ofstream::app);
+		std::ofstream file(fullName, std::ofstream::out);
 
-		for(int i = 0; i < length; i++)
+		for(unsigned int i = 0; i < instruction.size(); i++)
 		{
 			file << instruction[i]->string(shaderType, version) << std::endl;
 		}
@@ -1191,12 +1354,19 @@
 		file << instruction[index]->string(shaderType, version) << std::endl;
 	}
 
-	const ShaderInstruction *Shader::getInstruction(int i) const
+	void Shader::append(Instruction *instruction)
 	{
-		if(i < 0 || i >= length)
-		{
-			ASSERT(false);
-		}
+		this->instruction.push_back(instruction);
+	}
+
+	void Shader::declareSampler(int i)
+	{
+		usedSamplers |= 1 << i;
+	}
+
+	const Shader::Instruction *Shader::getInstruction(unsigned int i) const
+	{
+		ASSERT(i < instruction.size());
 
 		return instruction[i];
 	}
@@ -1207,26 +1377,26 @@
 		dirtyConstantsI = 0;
 		dirtyConstantsB = 0;
 
-		for(int i = 0; i < length; i++)
+		for(unsigned int i = 0; i < instruction.size(); i++)
 		{
-			switch(instruction[i]->operation.opcode)
+			switch(instruction[i]->opcode)
 			{
-			case ShaderOperation::OPCODE_DEF:
-				if(instruction[i]->destinationParameter.index + 1 > dirtyConstantsF)
+			case OPCODE_DEF:
+				if(instruction[i]->dst.index + 1 > dirtyConstantsF)
 				{
-					dirtyConstantsF = instruction[i]->destinationParameter.index + 1;
+					dirtyConstantsF = instruction[i]->dst.index + 1;
 				}
 				break;
-			case ShaderOperation::OPCODE_DEFI:
-				if(instruction[i]->destinationParameter.index + 1 > dirtyConstantsI)
+			case OPCODE_DEFI:
+				if(instruction[i]->dst.index + 1 > dirtyConstantsI)
 				{
-					dirtyConstantsI = instruction[i]->destinationParameter.index + 1;
+					dirtyConstantsI = instruction[i]->dst.index + 1;
 				}
 				break;
-			case ShaderOperation::OPCODE_DEFB:
-				if(instruction[i]->destinationParameter.index + 1 > dirtyConstantsB)
+			case OPCODE_DEFB:
+				if(instruction[i]->dst.index + 1 > dirtyConstantsB)
 				{
-					dirtyConstantsB = instruction[i]->destinationParameter.index + 1;
+					dirtyConstantsB = instruction[i]->dst.index + 1;
 				}
 				break;
 			}
@@ -1236,61 +1406,205 @@
 	void Shader::analyzeDynamicBranching()
 	{
 		dynamicBranching = false;
+		containsLeave = false;
+		containsBreak = false;
+		containsContinue = false;
 
-		for(int i = 0; i < length; i++)
+		// Determine global presence of branching instructions
+		for(unsigned int i = 0; i < instruction.size(); i++)
 		{
-			switch(instruction[i]->getOpcode())
+			switch(instruction[i]->opcode)
 			{
-			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)
+			case OPCODE_CALLNZ:
+			case OPCODE_IF:
+			case OPCODE_IFC:
+			case OPCODE_BREAK:
+			case OPCODE_BREAKC:
+			case OPCODE_CMP:
+			case OPCODE_BREAKP:
+			case OPCODE_LEAVE:
+			case OPCODE_CONTINUE:
+				if(instruction[i]->src[0].type != PARAMETER_CONSTBOOL)
 				{
 					dynamicBranching = true;
+				}
+
+				if(instruction[i]->opcode == OPCODE_LEAVE)
+				{
+					containsLeave = true;
+				}
+				
+				if(instruction[i]->isBreak())
+				{
+					containsBreak = true;
+				}
+
+				if(instruction[i]->opcode == OPCODE_CONTINUE)
+				{
+					containsContinue = true;
+				}
+			}
+		}
+
+		// Conservatively determine which instructions are affected by dynamic branching
+		int branchDepth = 0;
+		int breakDepth = 0;
+		int continueDepth = 0;
+		bool leaveReturn = false;
+
+		for(unsigned int i = 0; i < instruction.size(); i++)
+		{
+			// If statements
+			if(instruction[i]->isBranch())
+			{
+				branchDepth++;
+			}
+			else if(instruction[i]->opcode == OPCODE_ENDIF)
+			{
+				branchDepth--;
+			}
+
+			if(branchDepth > 0)
+			{
+				instruction[i]->analysisBranch = true;
+
+				if(instruction[i]->isCall())
+				{
+					markFunctionAnalysis(instruction[i]->dst.label, ANALYSIS_BRANCH);
+				}
+			}
+
+			// Break statemement
+			if(instruction[i]->isBreak())
+			{
+				breakDepth++;
+			}
+			else if(instruction[i]->isEndLoop())
+			{
+				breakDepth--;
+			}
+
+			if(breakDepth > 0)
+			{
+				if(instruction[i]->isLoop())   // Nested loop, don't make the end of it disable the break execution mask
+				{
+					breakDepth++;
+				}
+
+				instruction[i]->analysisBreak = true;
+
+				if(instruction[i]->isCall())
+				{
+					markFunctionAnalysis(instruction[i]->dst.label, ANALYSIS_BRANCH);
+				}
+			}
+
+			// Continue statement
+			if(instruction[i]->opcode == OPCODE_CONTINUE)
+			{
+				continueDepth++;
+			}
+			else if(instruction[i]->isEndLoop())
+			{
+				continueDepth--;
+			}
+
+			if(continueDepth > 0)
+			{
+				if(instruction[i]->isLoop())   // Nested loop, don't make the end of it disable the break execution mask
+				{
+					continueDepth++;
+				}
+
+				instruction[i]->analysisContinue = true;
+
+				if(instruction[i]->isCall())
+				{
+					markFunctionAnalysis(instruction[i]->dst.label, ANALYSIS_CONTINUE);
+				}
+			}
+
+			// Return (leave) statement
+			if(instruction[i]->opcode == OPCODE_LEAVE)
+			{
+				leaveReturn = true;
+			}
+			else if(instruction[i]->opcode == OPCODE_RET)   // End of the function
+			{
+				leaveReturn = false;
+			}
+
+			if(leaveReturn)
+			{
+				instruction[i]->analysisLeave = true;
+
+				if(instruction[i]->isCall())
+				{
+					markFunctionAnalysis(instruction[i]->dst.label, ANALYSIS_LEAVE);
+				}
+			}
+		}
+	}
+
+	void Shader::markFunctionAnalysis(int functionLabel, Analysis flag)
+	{
+		bool marker = false;
+		for(unsigned int i = 0; i < instruction.size(); i++)
+		{
+			if(!marker)
+			{
+				if(instruction[i]->opcode == OPCODE_LABEL && instruction[i]->dst.label == functionLabel)
+				{
+					marker = true;
+				}
+			}
+			else
+			{
+				if(instruction[i]->opcode == OPCODE_RET)
+				{
 					break;
 				}
+				else if(instruction[i]->isCall())
+				{
+					markFunctionAnalysis(instruction[i]->dst.label, flag);
+				}
+
+				instruction[i]->analysis |= flag;
 			}
 		}
 	}
 
 	void Shader::analyzeSamplers()
 	{
-		sampler = 0;
-
-		for(int i = 0; i < length; i++)
+		for(unsigned int i = 0; i < instruction.size(); i++)
 		{
-			switch(instruction[i]->getOpcode())
+			switch(instruction[i]->opcode)
 			{
-			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:
+			case OPCODE_TEX:
+			case OPCODE_TEXBEM:
+			case OPCODE_TEXBEML:
+			case OPCODE_TEXREG2AR:
+			case OPCODE_TEXREG2GB:
+			case OPCODE_TEXM3X2TEX:
+			case OPCODE_TEXM3X3TEX:
+			case OPCODE_TEXM3X3SPEC:
+			case OPCODE_TEXM3X3VSPEC:
+			case OPCODE_TEXREG2RGB:
+			case OPCODE_TEXDP3TEX:
+			case OPCODE_TEXM3X2DEPTH:
+			case OPCODE_TEXLDD:
+			case OPCODE_TEXLDL:
 				{
-					ShaderParameter &dst = instruction[i]->destinationParameter;
-					ShaderParameter &src1 = instruction[i]->sourceParameter[1];
+					Parameter &dst = instruction[i]->dst;
+					Parameter &src1 = instruction[i]->src[1];
 
 					if(majorVersion >= 2)
 					{
-						ASSERT(src1.type == ShaderParameter::PARAMETER_SAMPLER);
-						sampler |= 1 << src1.index;
+						usedSamplers |= 1 << src1.index;
 					}
 					else
 					{
-						sampler |= 1 << dst.index;
+						usedSamplers |= 1 << dst.index;
 					}
 				}
 				break;
@@ -1298,21 +1612,57 @@
 		}
 	}
 
-	void Shader::removeComments(unsigned long *shaderToken, int tokenCount)
+	// Assigns a unique index to each call instruction, on a per label basis.
+	// This is used to know what basic block to return to.
+	void Shader::analyzeCallSites()
 	{
-		for(int i = 0; i < tokenCount; )
-		{
-			int instructionSize = sw::Shader::size(shaderToken[i], (unsigned short)(shaderToken[0] & 0xFFFF)) + 1;
+		int callSiteIndex[2048] = {0};
 
-			if((shaderToken[i] & 0x0000FFFF) == ShaderOperation::OPCODE_COMMENT)
+		for(unsigned int i = 0; i < instruction.size(); i++)
+		{
+			if(instruction[i]->opcode == OPCODE_CALL || instruction[i]->opcode == OPCODE_CALLNZ)
 			{
-				for(int j = 0; j < instructionSize; j++)
+				int label = instruction[i]->dst.label;
+
+				instruction[i]->dst.callSite = callSiteIndex[label]++;
+			}
+		}
+	}
+
+	void Shader::analyzeDynamicIndexing()
+	{
+		dynamicallyIndexedTemporaries = false;
+		dynamicallyIndexedInput = false;
+		dynamicallyIndexedOutput = false;
+
+		for(unsigned int i = 0; i < instruction.size(); i++)
+		{
+			if(instruction[i]->dst.rel.type == PARAMETER_ADDR ||
+			   instruction[i]->dst.rel.type == PARAMETER_LOOP ||
+			   instruction[i]->dst.rel.type == PARAMETER_TEMP)
+			{
+				switch(instruction[i]->dst.type)
 				{
-					shaderToken[i + j] = ShaderOperation::OPCODE_NOP;
+				case PARAMETER_TEMP:   dynamicallyIndexedTemporaries = true; break;
+				case PARAMETER_INPUT:  dynamicallyIndexedInput = true;       break;
+				case PARAMETER_OUTPUT: dynamicallyIndexedOutput = true;      break;
 				}
 			}
 
-			i += instructionSize;
+			for(int j = 0; j < 3; j++)
+			{
+				if(instruction[i]->src[j].rel.type == PARAMETER_ADDR ||
+				   instruction[i]->src[j].rel.type == PARAMETER_LOOP ||
+				   instruction[i]->src[j].rel.type == PARAMETER_TEMP)
+				{
+					switch(instruction[i]->src[j].type)
+					{
+					case PARAMETER_TEMP:   dynamicallyIndexedTemporaries = true; break;
+					case PARAMETER_INPUT:  dynamicallyIndexedInput = true;       break;
+					case PARAMETER_OUTPUT: dynamicallyIndexedOutput = true;      break;
+					}
+				}
+			}
 		}
 	}
 }