Implement min/max.

Bug swiftshader:15

Change-Id: I785e31724e802a3ed1bca75186e012ccc7cb336e
Reviewed-on: https://swiftshader-review.googlesource.com/7850
Reviewed-by: Nicolas Capens <capn@google.com>
Tested-by: Nicolas Capens <capn@google.com>
Reviewed-on: https://swiftshader-review.googlesource.com/8151
Reviewed-by: Alexis Hétu <sugoi@google.com>
diff --git a/src/Reactor/Main.cpp b/src/Reactor/Main.cpp
index cbf6d23..cd7be18 100644
--- a/src/Reactor/Main.cpp
+++ b/src/Reactor/Main.cpp
@@ -342,6 +342,97 @@
 	delete routine;
 }
 
+TEST(SubzeroReactorTest, MinMax)
+{
+	Routine *routine = nullptr;
+
+	{
+		Function<Int(Pointer<Byte>)> function;
+		{
+			Pointer<Byte> out = function.Arg<0>();
+
+			*Pointer<Float4>(out + 16 * 0) = Min(Float4(1.0f, 0.0f, -0.0f, +0.0f), Float4(0.0f, 1.0f, +0.0f, -0.0f));
+			*Pointer<Float4>(out + 16 * 1) = Max(Float4(1.0f, 0.0f, -0.0f, +0.0f), Float4(0.0f, 1.0f, +0.0f, -0.0f));
+
+			*Pointer<Int4>(out + 16 * 2) = Min(Int4(1, 0, -1, -0), Int4(0, 1, 0, +0));
+			*Pointer<Int4>(out + 16 * 3) = Max(Int4(1, 0, -1, -0), Int4(0, 1, 0, +0));
+			*Pointer<UInt4>(out + 16 * 4) = Min(UInt4(1, 0, -1, -0), UInt4(0, 1, 0, +0));
+			*Pointer<UInt4>(out + 16 * 5) = Max(UInt4(1, 0, -1, -0), UInt4(0, 1, 0, +0));
+
+			*Pointer<Short4>(out + 16 * 6) = Min(Short4(1, 0, -1, -0), Short4(0, 1, 0, +0));
+			*Pointer<Short4>(out + 16 * 7) = Max(Short4(1, 0, -1, -0), Short4(0, 1, 0, +0));
+			*Pointer<UShort4>(out + 16 * 8) = Min(UShort4(1, 0, -1, -0), UShort4(0, 1, 0, +0));
+			*Pointer<UShort4>(out + 16 * 9) = Max(UShort4(1, 0, -1, -0), UShort4(0, 1, 0, +0));
+
+			Return(0);
+		}
+
+		routine = function(L"one");
+
+		if(routine)
+		{
+			int out[10][4];
+
+			memset(&out, 0, sizeof(out));
+
+			int(*callable)(void*) = (int(*)(void*))routine->getEntry();
+			callable(&out);
+
+			EXPECT_EQ(out[0][0], 0x00000000);
+			EXPECT_EQ(out[0][1], 0x00000000);
+			EXPECT_EQ(out[0][2], 0x80000000);
+			EXPECT_EQ(out[0][3], 0x00000000);
+
+			EXPECT_EQ(out[1][0], 0x3F800000);
+			EXPECT_EQ(out[1][1], 0x3F800000);
+			EXPECT_EQ(out[1][2], 0x00000000);
+			EXPECT_EQ(out[1][3], 0x80000000);
+
+			EXPECT_EQ(out[2][0], 0x00000000);
+			EXPECT_EQ(out[2][1], 0x00000000);
+			EXPECT_EQ(out[2][2], 0xFFFFFFFF);
+			EXPECT_EQ(out[2][3], 0x00000000);
+
+			EXPECT_EQ(out[3][0], 0x00000001);
+			EXPECT_EQ(out[3][1], 0x00000001);
+			EXPECT_EQ(out[3][2], 0x00000000);
+			EXPECT_EQ(out[3][3], 0x00000000);
+
+			EXPECT_EQ(out[4][0], 0x00000000);
+			EXPECT_EQ(out[4][1], 0x00000000);
+			EXPECT_EQ(out[4][2], 0x00000000);
+			EXPECT_EQ(out[4][3], 0x00000000);
+
+			EXPECT_EQ(out[5][0], 0x00000001);
+			EXPECT_EQ(out[5][1], 0x00000001);
+			EXPECT_EQ(out[5][2], 0xFFFFFFFF);
+			EXPECT_EQ(out[5][3], 0x00000000);
+
+			EXPECT_EQ(out[6][0], 0x00000000);
+			EXPECT_EQ(out[6][1], 0x0000FFFF);
+			EXPECT_EQ(out[6][2], 0x00000000);
+			EXPECT_EQ(out[6][3], 0x00000000);
+
+			EXPECT_EQ(out[7][0], 0x00010001);
+			EXPECT_EQ(out[7][1], 0x00000000);
+			EXPECT_EQ(out[7][2], 0x00000000);
+			EXPECT_EQ(out[7][3], 0x00000000);
+
+			EXPECT_EQ(out[8][0], 0x00000000);
+			EXPECT_EQ(out[8][1], 0x00000000);
+			EXPECT_EQ(out[8][2], 0x00000000);
+			EXPECT_EQ(out[8][3], 0x00000000);
+
+			EXPECT_EQ(out[9][0], 0x00010001);
+			EXPECT_EQ(out[9][1], 0x0000FFFF);
+			EXPECT_EQ(out[9][2], 0x00000000);
+			EXPECT_EQ(out[9][3], 0x00000000);
+		}
+	}
+
+	delete routine;
+}
+
 int main(int argc, char **argv)
 {
 	::testing::InitGoogleTest(&argc, argv);
diff --git a/src/Reactor/SubzeroReactor.cpp b/src/Reactor/SubzeroReactor.cpp
index c15ea8e..dd0f68d 100644
--- a/src/Reactor/SubzeroReactor.cpp
+++ b/src/Reactor/SubzeroReactor.cpp
@@ -1013,7 +1013,13 @@
 
 	Value *Nucleus::createSelect(Value *C, Value *ifTrue, Value *ifFalse)
 	{
-		assert(false && "UNIMPLEMENTED"); return nullptr;
+		assert(ifTrue->getType() == ifFalse->getType());
+
+		auto result = ::function->makeVariable(ifTrue->getType());
+		auto *select = Ice::InstSelect::create(::function, result, C, ifTrue, ifFalse);
+		::basicBlock->appendInst(select);
+
+		return V(result);
 	}
 
 	Value *Nucleus::createSwitch(Value *v, BasicBlock *Dest, unsigned NumCases)
@@ -3162,12 +3168,28 @@
 
 	RValue<Short4> Max(RValue<Short4> x, RValue<Short4> y)
 	{
-		assert(false && "UNIMPLEMENTED"); return RValue<Short4>(V(nullptr));
+		Ice::Variable *condition = ::function->makeVariable(Ice::IceType_v8i1);
+		auto cmp = Ice::InstIcmp::create(::function, Ice::InstIcmp::Sle, condition, x.value, y.value);
+		::basicBlock->appendInst(cmp);
+
+		Ice::Variable *result = ::function->makeVariable(Ice::IceType_v8i16);
+		auto select = Ice::InstSelect::create(::function, result, condition, y.value, x.value);
+		::basicBlock->appendInst(select);
+
+		return RValue<Short4>(V(result));
 	}
 
 	RValue<Short4> Min(RValue<Short4> x, RValue<Short4> y)
 	{
-		assert(false && "UNIMPLEMENTED"); return RValue<Short4>(V(nullptr));
+		Ice::Variable *condition = ::function->makeVariable(Ice::IceType_v8i1);
+		auto cmp = Ice::InstIcmp::create(::function, Ice::InstIcmp::Sgt, condition, x.value, y.value);
+		::basicBlock->appendInst(cmp);
+
+		Ice::Variable *result = ::function->makeVariable(Ice::IceType_v8i16);
+		auto select = Ice::InstSelect::create(::function, result, condition, y.value, x.value);
+		::basicBlock->appendInst(select);
+
+		return RValue<Short4>(V(result));
 	}
 
 	RValue<Short4> AddSat(RValue<Short4> x, RValue<Short4> y)
@@ -3459,12 +3481,28 @@
 
 	RValue<UShort4> Max(RValue<UShort4> x, RValue<UShort4> y)
 	{
-		assert(false && "UNIMPLEMENTED"); return RValue<UShort4>(V(nullptr));
+		Ice::Variable *condition = ::function->makeVariable(Ice::IceType_v8i1);
+		auto cmp = Ice::InstIcmp::create(::function, Ice::InstIcmp::Ule, condition, x.value, y.value);
+		::basicBlock->appendInst(cmp);
+
+		Ice::Variable *result = ::function->makeVariable(Ice::IceType_v8i16);
+		auto select = Ice::InstSelect::create(::function, result, condition, y.value, x.value);
+		::basicBlock->appendInst(select);
+
+		return RValue<UShort4>(V(result));
 	}
 
 	RValue<UShort4> Min(RValue<UShort4> x, RValue<UShort4> y)
 	{
-		assert(false && "UNIMPLEMENTED"); return RValue<UShort4>(V(nullptr));
+		Ice::Variable *condition = ::function->makeVariable(Ice::IceType_v8i1);
+		auto cmp = Ice::InstIcmp::create(::function, Ice::InstIcmp::Ugt, condition, x.value, y.value);
+		::basicBlock->appendInst(cmp);
+
+		Ice::Variable *result = ::function->makeVariable(Ice::IceType_v8i16);
+		auto select = Ice::InstSelect::create(::function, result, condition, y.value, x.value);
+		::basicBlock->appendInst(select);
+
+		return RValue<UShort4>(V(result));
 	}
 
 	RValue<UShort4> AddSat(RValue<UShort4> x, RValue<UShort4> y)
@@ -5181,12 +5219,28 @@
 
 	RValue<Int4> Max(RValue<Int4> x, RValue<Int4> y)
 	{
-		assert(false && "UNIMPLEMENTED"); return RValue<Int4>(V(nullptr));
+		Ice::Variable *condition = ::function->makeVariable(Ice::IceType_v4i1);
+		auto cmp = Ice::InstIcmp::create(::function, Ice::InstIcmp::Sle, condition, x.value, y.value);
+		::basicBlock->appendInst(cmp);
+
+		Ice::Variable *result = ::function->makeVariable(Ice::IceType_v4i32);
+		auto select = Ice::InstSelect::create(::function, result, condition, y.value, x.value);
+		::basicBlock->appendInst(select);
+
+		return RValue<Int4>(V(result));
 	}
 
 	RValue<Int4> Min(RValue<Int4> x, RValue<Int4> y)
 	{
-		assert(false && "UNIMPLEMENTED"); return RValue<Int4>(V(nullptr));
+		Ice::Variable *condition = ::function->makeVariable(Ice::IceType_v4i1);
+		auto cmp = Ice::InstIcmp::create(::function, Ice::InstIcmp::Sgt, condition, x.value, y.value);
+		::basicBlock->appendInst(cmp);
+
+		Ice::Variable *result = ::function->makeVariable(Ice::IceType_v4i32);
+		auto select = Ice::InstSelect::create(::function, result, condition, y.value, x.value);
+		::basicBlock->appendInst(select);
+
+		return RValue<Int4>(V(result));
 	}
 
 	RValue<Int4> RoundInt(RValue<Float4> cast)
@@ -5510,12 +5564,28 @@
 
 	RValue<UInt4> Max(RValue<UInt4> x, RValue<UInt4> y)
 	{
-		assert(false && "UNIMPLEMENTED"); return RValue<UInt4>(V(nullptr));
+		Ice::Variable *condition = ::function->makeVariable(Ice::IceType_v4i1);
+		auto cmp = Ice::InstIcmp::create(::function, Ice::InstIcmp::Ule, condition, x.value, y.value);
+		::basicBlock->appendInst(cmp);
+
+		Ice::Variable *result = ::function->makeVariable(Ice::IceType_v4i32);
+		auto select = Ice::InstSelect::create(::function, result, condition, y.value, x.value);
+		::basicBlock->appendInst(select);
+
+		return RValue<UInt4>(V(result));
 	}
 
 	RValue<UInt4> Min(RValue<UInt4> x, RValue<UInt4> y)
 	{
-		assert(false && "UNIMPLEMENTED"); return RValue<UInt4>(V(nullptr));
+		Ice::Variable *condition = ::function->makeVariable(Ice::IceType_v4i1);
+		auto cmp = Ice::InstIcmp::create(::function, Ice::InstIcmp::Ugt, condition, x.value, y.value);
+		::basicBlock->appendInst(cmp);
+
+		Ice::Variable *result = ::function->makeVariable(Ice::IceType_v4i32);
+		auto select = Ice::InstSelect::create(::function, result, condition, y.value, x.value);
+		::basicBlock->appendInst(select);
+
+		return RValue<UInt4>(V(result));
 	}
 
 	RValue<UShort8> Pack(RValue<UInt4> x, RValue<UInt4> y)
@@ -5977,12 +6047,28 @@
 
 	RValue<Float4> Max(RValue<Float4> x, RValue<Float4> y)
 	{
-		assert(false && "UNIMPLEMENTED"); return RValue<Float4>(V(nullptr));
+		Ice::Variable *condition = ::function->makeVariable(Ice::IceType_v4i1);
+		auto cmp = Ice::InstFcmp::create(::function, Ice::InstFcmp::Ule, condition, x.value, y.value);
+		::basicBlock->appendInst(cmp);
+
+		Ice::Variable *result = ::function->makeVariable(Ice::IceType_v4f32);
+		auto select = Ice::InstSelect::create(::function, result, condition, y.value, x.value);
+		::basicBlock->appendInst(select);
+
+		return RValue<Float4>(V(result));
 	}
 
 	RValue<Float4> Min(RValue<Float4> x, RValue<Float4> y)
 	{
-		assert(false && "UNIMPLEMENTED"); return RValue<Float4>(V(nullptr));
+		Ice::Variable *condition = ::function->makeVariable(Ice::IceType_v4i1);
+		auto cmp = Ice::InstFcmp::create(::function, Ice::InstFcmp::Ugt, condition, x.value, y.value);
+		::basicBlock->appendInst(cmp);
+
+		Ice::Variable *result = ::function->makeVariable(Ice::IceType_v4f32);
+		auto select = Ice::InstSelect::create(::function, result, condition, y.value, x.value);
+		::basicBlock->appendInst(select);
+
+		return RValue<Float4>(V(result));
 	}
 
 	RValue<Float4> Rcp_pp(RValue<Float4> x, bool exactAtPow2)