Implement switch constructs.

Bug swiftshader:6

Change-Id: Ifd28cab11e814dd09515ad8721f8d3d86123f19c
Reviewed-on: https://swiftshader-review.googlesource.com/7970
Reviewed-by: Nicolas Capens <capn@google.com>
Tested-by: Nicolas Capens <capn@google.com>
Reviewed-on: https://swiftshader-review.googlesource.com/8165
Reviewed-by: Alexis Hétu <sugoi@google.com>
diff --git a/src/Reactor/LLVMReactor.cpp b/src/Reactor/LLVMReactor.cpp
index 199a0f3..66e330d 100644
--- a/src/Reactor/LLVMReactor.cpp
+++ b/src/Reactor/LLVMReactor.cpp
@@ -81,6 +81,7 @@
 
 	class Type : public llvm::Type {};
 	class Value : public llvm::Value {};
+	class SwitchCases : public llvm::SwitchInst {};
 	class BasicBlock : public llvm::BasicBlock {};
 
 	inline Type *T(llvm::Type *t)
@@ -661,14 +662,14 @@
 		return V(::builder->CreateSelect(C, ifTrue, ifFalse));
 	}
 
-	Value *Nucleus::createSwitch(Value *v, BasicBlock *Dest, unsigned NumCases)
+	SwitchCases *Nucleus::createSwitch(Value *control, BasicBlock *defaultBranch, unsigned numCases)
 	{
-		return V(::builder->CreateSwitch(v, Dest, NumCases));
+		return reinterpret_cast<SwitchCases*>(::builder->CreateSwitch(control, defaultBranch, numCases));
 	}
 
-	void Nucleus::addSwitchCase(Value *Switch, int Case, BasicBlock *Branch)
+	void Nucleus::addSwitchCase(SwitchCases *switchCases, int label, BasicBlock *branch)
 	{
-		reinterpret_cast<SwitchInst*>(Switch)->addCase(llvm::ConstantInt::get(Type::getInt32Ty(*::context), Case, true), Branch);
+		switchCases->addCase(llvm::ConstantInt::get(Type::getInt32Ty(*::context), label, true), branch);
 	}
 
 	void Nucleus::createUnreachable()
diff --git a/src/Reactor/Nucleus.hpp b/src/Reactor/Nucleus.hpp
index 8cb8787..ddca385 100644
--- a/src/Reactor/Nucleus.hpp
+++ b/src/Reactor/Nucleus.hpp
@@ -23,6 +23,7 @@
 {
 	class Type;
 	class Value;
+	class SwitchCases;
 	class BasicBlock;
 	class Routine;
 
@@ -144,8 +145,8 @@
 
 		// Other instructions
 		static Value *createSelect(Value *C, Value *ifTrue, Value *ifFalse);
-		static Value *createSwitch(Value *V, BasicBlock *Dest, unsigned NumCases);
-		static void addSwitchCase(Value *Switch, int Case, BasicBlock *Branch);
+		static SwitchCases *createSwitch(Value *control, BasicBlock *defaultBranch, unsigned numCases);
+		static void addSwitchCase(SwitchCases *switchCases, int label, BasicBlock *branch);
 		static void createUnreachable();
 
 		// Constant values
diff --git a/src/Reactor/SubzeroReactor.cpp b/src/Reactor/SubzeroReactor.cpp
index 20843d5..62a240a 100644
--- a/src/Reactor/SubzeroReactor.cpp
+++ b/src/Reactor/SubzeroReactor.cpp
@@ -72,6 +72,7 @@
 	};
 
 	class Value : public Ice::Variable {};
+	class SwitchCases : public Ice::InstSwitch {};
 	class BasicBlock : public Ice::CfgNode {};
 
 	Ice::Type T(Type *t)
@@ -218,15 +219,15 @@
 		case R_X86_64_NONE:
 			// No relocation
 			break;
-	//	case R_X86_64_64:
-	//		*patchSite = (int32_t)((intptr_t)symbolValue + *patchSite) + relocation->r_addend;
-	//		break;
+		case R_X86_64_64:
+			*(int64_t*)patchSite = (int64_t)((intptr_t)symbolValue + *(int64_t*)patchSite) + relocation.r_addend;
+			break;
 		case R_X86_64_PC32:
 			*patchSite = (int32_t)((intptr_t)symbolValue + *patchSite - (intptr_t)patchSite) + relocation.r_addend;
 			break;
-	//	case R_X86_64_32S:
-	//		*patchSite = (int32_t)((intptr_t)symbolValue + *patchSite) + relocation.r_addend;
-	//		break;
+		case R_X86_64_32S:
+			*patchSite = (int32_t)((intptr_t)symbolValue + *patchSite) + relocation.r_addend;
+			break;
 		default:
 			assert(false && "Unsupported relocation type");
 			return nullptr;
@@ -446,6 +447,7 @@
 		objectWriter->writeFunctionCode(::function->getFunctionName(), false, assembler.get());
 		::context->lowerGlobals("last");
 		::context->lowerConstants();
+		::context->lowerJumpTables();
 		objectWriter->setUndefinedSyms(::context->getConstantExternSyms());
 		objectWriter->writeNonUserSections();
 
@@ -1034,14 +1036,17 @@
 		return V(result);
 	}
 
-	Value *Nucleus::createSwitch(Value *v, BasicBlock *Dest, unsigned NumCases)
+	SwitchCases *Nucleus::createSwitch(Value *control, BasicBlock *defaultBranch, unsigned numCases)
 	{
-		assert(false && "UNIMPLEMENTED"); return nullptr;
+		auto switchInst = Ice::InstSwitch::create(::function, numCases, control, defaultBranch);
+		::basicBlock->appendInst(switchInst);
+
+		return reinterpret_cast<SwitchCases*>(switchInst);
 	}
 
-	void Nucleus::addSwitchCase(Value *Switch, int Case, BasicBlock *Branch)
+	void Nucleus::addSwitchCase(SwitchCases *switchCases, int label, BasicBlock *branch)
 	{
-		assert(false && "UNIMPLEMENTED"); return;
+		switchCases->addBranch(label, label, branch);
 	}
 
 	void Nucleus::createUnreachable()
diff --git a/src/Shader/PixelProgram.cpp b/src/Shader/PixelProgram.cpp
index b1bae30..ecf164f 100644
--- a/src/Shader/PixelProgram.cpp
+++ b/src/Shader/PixelProgram.cpp
@@ -1741,11 +1741,11 @@
 				UInt index = callStack[--stackIndex];
 
 				Value *value = index.loadValue();
-				Value *switchInst = Nucleus::createSwitch(value, unreachableBlock, (int)callRetBlock[currentLabel].size());
+				SwitchCases *switchCases = Nucleus::createSwitch(value, unreachableBlock, (int)callRetBlock[currentLabel].size());
 
 				for(unsigned int i = 0; i < callRetBlock[currentLabel].size(); i++)
 				{
-					Nucleus::addSwitchCase(switchInst, i, callRetBlock[currentLabel][i]);
+					Nucleus::addSwitchCase(switchCases, i, callRetBlock[currentLabel][i]);
 				}
 			}
 			else if(callRetBlock[currentLabel].size() == 1)   // Jump directly to the unique return destination
diff --git a/src/Shader/VertexProgram.cpp b/src/Shader/VertexProgram.cpp
index 5c3f8b4..26d61e0 100644
--- a/src/Shader/VertexProgram.cpp
+++ b/src/Shader/VertexProgram.cpp
@@ -1503,11 +1503,11 @@
 				UInt index = callStack[--stackIndex];
 
 				Value *value = index.loadValue();
-				Value *switchInst = Nucleus::createSwitch(value, unreachableBlock, (int)callRetBlock[currentLabel].size());
+				SwitchCases *switchCases = Nucleus::createSwitch(value, unreachableBlock, (int)callRetBlock[currentLabel].size());
 
 				for(unsigned int i = 0; i < callRetBlock[currentLabel].size(); i++)
 				{
-					Nucleus::addSwitchCase(switchInst, i, callRetBlock[currentLabel][i]);
+					Nucleus::addSwitchCase(switchCases, i, callRetBlock[currentLabel][i]);
 				}
 			}
 			else if(callRetBlock[currentLabel].size() == 1)   // Jump directly to the unique return destination
diff --git a/third_party/pnacl-subzero b/third_party/pnacl-subzero
index 21f78bb..83425de 160000
--- a/third_party/pnacl-subzero
+++ b/third_party/pnacl-subzero
@@ -1 +1 @@
-Subproject commit 21f78bb1b7cd9040ce5baea3be51f7be49a1bb1f
+Subproject commit 83425dec5ecae21e092a9a440845ce99a13ded69