xref: /aosp_15_r20/external/swiftshader/src/Pipeline/SpirvShaderArithmetic.cpp (revision 03ce13f70fcc45d86ee91b7ee4cab1936a95046e)
1*03ce13f7SAndroid Build Coastguard Worker // Copyright 2019 The SwiftShader Authors. All Rights Reserved.
2*03ce13f7SAndroid Build Coastguard Worker //
3*03ce13f7SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*03ce13f7SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*03ce13f7SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*03ce13f7SAndroid Build Coastguard Worker //
7*03ce13f7SAndroid Build Coastguard Worker //    http://www.apache.org/licenses/LICENSE-2.0
8*03ce13f7SAndroid Build Coastguard Worker //
9*03ce13f7SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*03ce13f7SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*03ce13f7SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*03ce13f7SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*03ce13f7SAndroid Build Coastguard Worker // limitations under the License.
14*03ce13f7SAndroid Build Coastguard Worker 
15*03ce13f7SAndroid Build Coastguard Worker #include "SpirvShader.hpp"
16*03ce13f7SAndroid Build Coastguard Worker #include "SpirvShaderDebug.hpp"
17*03ce13f7SAndroid Build Coastguard Worker 
18*03ce13f7SAndroid Build Coastguard Worker #include "ShaderCore.hpp"
19*03ce13f7SAndroid Build Coastguard Worker 
20*03ce13f7SAndroid Build Coastguard Worker #include <spirv/unified1/spirv.hpp>
21*03ce13f7SAndroid Build Coastguard Worker 
22*03ce13f7SAndroid Build Coastguard Worker #include <limits>
23*03ce13f7SAndroid Build Coastguard Worker 
24*03ce13f7SAndroid Build Coastguard Worker namespace sw {
25*03ce13f7SAndroid Build Coastguard Worker 
EmitVectorTimesScalar(Spirv::InsnIterator insn)26*03ce13f7SAndroid Build Coastguard Worker void SpirvEmitter::EmitVectorTimesScalar(Spirv::InsnIterator insn)
27*03ce13f7SAndroid Build Coastguard Worker {
28*03ce13f7SAndroid Build Coastguard Worker 	auto &type = shader.getType(insn.resultTypeId());
29*03ce13f7SAndroid Build Coastguard Worker 	auto &dst = createIntermediate(insn.resultId(), type.componentCount);
30*03ce13f7SAndroid Build Coastguard Worker 	auto lhs = Operand(shader, *this, insn.word(3));
31*03ce13f7SAndroid Build Coastguard Worker 	auto rhs = Operand(shader, *this, insn.word(4));
32*03ce13f7SAndroid Build Coastguard Worker 
33*03ce13f7SAndroid Build Coastguard Worker 	for(auto i = 0u; i < type.componentCount; i++)
34*03ce13f7SAndroid Build Coastguard Worker 	{
35*03ce13f7SAndroid Build Coastguard Worker 		dst.move(i, lhs.Float(i) * rhs.Float(0));
36*03ce13f7SAndroid Build Coastguard Worker 	}
37*03ce13f7SAndroid Build Coastguard Worker }
38*03ce13f7SAndroid Build Coastguard Worker 
EmitMatrixTimesVector(Spirv::InsnIterator insn)39*03ce13f7SAndroid Build Coastguard Worker void SpirvEmitter::EmitMatrixTimesVector(Spirv::InsnIterator insn)
40*03ce13f7SAndroid Build Coastguard Worker {
41*03ce13f7SAndroid Build Coastguard Worker 	auto &type = shader.getType(insn.resultTypeId());
42*03ce13f7SAndroid Build Coastguard Worker 	auto &dst = createIntermediate(insn.resultId(), type.componentCount);
43*03ce13f7SAndroid Build Coastguard Worker 	auto lhs = Operand(shader, *this, insn.word(3));
44*03ce13f7SAndroid Build Coastguard Worker 	auto rhs = Operand(shader, *this, insn.word(4));
45*03ce13f7SAndroid Build Coastguard Worker 
46*03ce13f7SAndroid Build Coastguard Worker 	for(auto i = 0u; i < type.componentCount; i++)
47*03ce13f7SAndroid Build Coastguard Worker 	{
48*03ce13f7SAndroid Build Coastguard Worker 		SIMD::Float v = lhs.Float(i) * rhs.Float(0);
49*03ce13f7SAndroid Build Coastguard Worker 		for(auto j = 1u; j < rhs.componentCount; j++)
50*03ce13f7SAndroid Build Coastguard Worker 		{
51*03ce13f7SAndroid Build Coastguard Worker 			v = MulAdd(lhs.Float(i + type.componentCount * j), rhs.Float(j), v);
52*03ce13f7SAndroid Build Coastguard Worker 		}
53*03ce13f7SAndroid Build Coastguard Worker 		dst.move(i, v);
54*03ce13f7SAndroid Build Coastguard Worker 	}
55*03ce13f7SAndroid Build Coastguard Worker }
56*03ce13f7SAndroid Build Coastguard Worker 
EmitVectorTimesMatrix(Spirv::InsnIterator insn)57*03ce13f7SAndroid Build Coastguard Worker void SpirvEmitter::EmitVectorTimesMatrix(Spirv::InsnIterator insn)
58*03ce13f7SAndroid Build Coastguard Worker {
59*03ce13f7SAndroid Build Coastguard Worker 	auto &type = shader.getType(insn.resultTypeId());
60*03ce13f7SAndroid Build Coastguard Worker 	auto &dst = createIntermediate(insn.resultId(), type.componentCount);
61*03ce13f7SAndroid Build Coastguard Worker 	auto lhs = Operand(shader, *this, insn.word(3));
62*03ce13f7SAndroid Build Coastguard Worker 	auto rhs = Operand(shader, *this, insn.word(4));
63*03ce13f7SAndroid Build Coastguard Worker 
64*03ce13f7SAndroid Build Coastguard Worker 	for(auto i = 0u; i < type.componentCount; i++)
65*03ce13f7SAndroid Build Coastguard Worker 	{
66*03ce13f7SAndroid Build Coastguard Worker 		SIMD::Float v = lhs.Float(0) * rhs.Float(i * lhs.componentCount);
67*03ce13f7SAndroid Build Coastguard Worker 		for(auto j = 1u; j < lhs.componentCount; j++)
68*03ce13f7SAndroid Build Coastguard Worker 		{
69*03ce13f7SAndroid Build Coastguard Worker 			v = MulAdd(lhs.Float(j), rhs.Float(i * lhs.componentCount + j), v);
70*03ce13f7SAndroid Build Coastguard Worker 		}
71*03ce13f7SAndroid Build Coastguard Worker 		dst.move(i, v);
72*03ce13f7SAndroid Build Coastguard Worker 	}
73*03ce13f7SAndroid Build Coastguard Worker }
74*03ce13f7SAndroid Build Coastguard Worker 
EmitMatrixTimesMatrix(Spirv::InsnIterator insn)75*03ce13f7SAndroid Build Coastguard Worker void SpirvEmitter::EmitMatrixTimesMatrix(Spirv::InsnIterator insn)
76*03ce13f7SAndroid Build Coastguard Worker {
77*03ce13f7SAndroid Build Coastguard Worker 	auto &type = shader.getType(insn.resultTypeId());
78*03ce13f7SAndroid Build Coastguard Worker 	auto &dst = createIntermediate(insn.resultId(), type.componentCount);
79*03ce13f7SAndroid Build Coastguard Worker 	auto lhs = Operand(shader, *this, insn.word(3));
80*03ce13f7SAndroid Build Coastguard Worker 	auto rhs = Operand(shader, *this, insn.word(4));
81*03ce13f7SAndroid Build Coastguard Worker 
82*03ce13f7SAndroid Build Coastguard Worker 	auto numColumns = type.definition.word(3);
83*03ce13f7SAndroid Build Coastguard Worker 	auto numRows = shader.getType(type.definition.word(2)).definition.word(3);
84*03ce13f7SAndroid Build Coastguard Worker 	auto numAdds = shader.getObjectType(insn.word(3)).definition.word(3);
85*03ce13f7SAndroid Build Coastguard Worker 
86*03ce13f7SAndroid Build Coastguard Worker 	for(auto row = 0u; row < numRows; row++)
87*03ce13f7SAndroid Build Coastguard Worker 	{
88*03ce13f7SAndroid Build Coastguard Worker 		for(auto col = 0u; col < numColumns; col++)
89*03ce13f7SAndroid Build Coastguard Worker 		{
90*03ce13f7SAndroid Build Coastguard Worker 			SIMD::Float v = lhs.Float(row) * rhs.Float(col * numAdds);
91*03ce13f7SAndroid Build Coastguard Worker 			for(auto i = 1u; i < numAdds; i++)
92*03ce13f7SAndroid Build Coastguard Worker 			{
93*03ce13f7SAndroid Build Coastguard Worker 				v = MulAdd(lhs.Float(i * numRows + row), rhs.Float(col * numAdds + i), v);
94*03ce13f7SAndroid Build Coastguard Worker 			}
95*03ce13f7SAndroid Build Coastguard Worker 			dst.move(numRows * col + row, v);
96*03ce13f7SAndroid Build Coastguard Worker 		}
97*03ce13f7SAndroid Build Coastguard Worker 	}
98*03ce13f7SAndroid Build Coastguard Worker }
99*03ce13f7SAndroid Build Coastguard Worker 
EmitOuterProduct(Spirv::InsnIterator insn)100*03ce13f7SAndroid Build Coastguard Worker void SpirvEmitter::EmitOuterProduct(Spirv::InsnIterator insn)
101*03ce13f7SAndroid Build Coastguard Worker {
102*03ce13f7SAndroid Build Coastguard Worker 	auto &type = shader.getType(insn.resultTypeId());
103*03ce13f7SAndroid Build Coastguard Worker 	auto &dst = createIntermediate(insn.resultId(), type.componentCount);
104*03ce13f7SAndroid Build Coastguard Worker 	auto lhs = Operand(shader, *this, insn.word(3));
105*03ce13f7SAndroid Build Coastguard Worker 	auto rhs = Operand(shader, *this, insn.word(4));
106*03ce13f7SAndroid Build Coastguard Worker 
107*03ce13f7SAndroid Build Coastguard Worker 	auto numRows = lhs.componentCount;
108*03ce13f7SAndroid Build Coastguard Worker 	auto numCols = rhs.componentCount;
109*03ce13f7SAndroid Build Coastguard Worker 
110*03ce13f7SAndroid Build Coastguard Worker 	for(auto col = 0u; col < numCols; col++)
111*03ce13f7SAndroid Build Coastguard Worker 	{
112*03ce13f7SAndroid Build Coastguard Worker 		for(auto row = 0u; row < numRows; row++)
113*03ce13f7SAndroid Build Coastguard Worker 		{
114*03ce13f7SAndroid Build Coastguard Worker 			dst.move(col * numRows + row, lhs.Float(row) * rhs.Float(col));
115*03ce13f7SAndroid Build Coastguard Worker 		}
116*03ce13f7SAndroid Build Coastguard Worker 	}
117*03ce13f7SAndroid Build Coastguard Worker }
118*03ce13f7SAndroid Build Coastguard Worker 
EmitTranspose(Spirv::InsnIterator insn)119*03ce13f7SAndroid Build Coastguard Worker void SpirvEmitter::EmitTranspose(Spirv::InsnIterator insn)
120*03ce13f7SAndroid Build Coastguard Worker {
121*03ce13f7SAndroid Build Coastguard Worker 	auto &type = shader.getType(insn.resultTypeId());
122*03ce13f7SAndroid Build Coastguard Worker 	auto &dst = createIntermediate(insn.resultId(), type.componentCount);
123*03ce13f7SAndroid Build Coastguard Worker 	auto mat = Operand(shader, *this, insn.word(3));
124*03ce13f7SAndroid Build Coastguard Worker 
125*03ce13f7SAndroid Build Coastguard Worker 	auto numCols = type.definition.word(3);
126*03ce13f7SAndroid Build Coastguard Worker 	auto numRows = shader.getType(type.definition.word(2)).componentCount;
127*03ce13f7SAndroid Build Coastguard Worker 
128*03ce13f7SAndroid Build Coastguard Worker 	for(auto col = 0u; col < numCols; col++)
129*03ce13f7SAndroid Build Coastguard Worker 	{
130*03ce13f7SAndroid Build Coastguard Worker 		for(auto row = 0u; row < numRows; row++)
131*03ce13f7SAndroid Build Coastguard Worker 		{
132*03ce13f7SAndroid Build Coastguard Worker 			dst.move(col * numRows + row, mat.Float(row * numCols + col));
133*03ce13f7SAndroid Build Coastguard Worker 		}
134*03ce13f7SAndroid Build Coastguard Worker 	}
135*03ce13f7SAndroid Build Coastguard Worker }
136*03ce13f7SAndroid Build Coastguard Worker 
EmitBitcastPointer(Spirv::Object::ID resultID,Operand & src)137*03ce13f7SAndroid Build Coastguard Worker void SpirvEmitter::EmitBitcastPointer(Spirv::Object::ID resultID, Operand &src)
138*03ce13f7SAndroid Build Coastguard Worker {
139*03ce13f7SAndroid Build Coastguard Worker 	if(src.isPointer())  // Pointer -> Integer bits
140*03ce13f7SAndroid Build Coastguard Worker 	{
141*03ce13f7SAndroid Build Coastguard Worker 		if(sizeof(void *) == 4)  // 32-bit pointers
142*03ce13f7SAndroid Build Coastguard Worker 		{
143*03ce13f7SAndroid Build Coastguard Worker 			SIMD::UInt bits;
144*03ce13f7SAndroid Build Coastguard Worker 			src.Pointer().castTo(bits);
145*03ce13f7SAndroid Build Coastguard Worker 
146*03ce13f7SAndroid Build Coastguard Worker 			auto &dst = createIntermediate(resultID, 1);
147*03ce13f7SAndroid Build Coastguard Worker 			dst.move(0, bits);
148*03ce13f7SAndroid Build Coastguard Worker 		}
149*03ce13f7SAndroid Build Coastguard Worker 		else  // 64-bit pointers
150*03ce13f7SAndroid Build Coastguard Worker 		{
151*03ce13f7SAndroid Build Coastguard Worker 			ASSERT(sizeof(void *) == 8);
152*03ce13f7SAndroid Build Coastguard Worker 			// Casting a 64 bit pointer into 2 32bit integers
153*03ce13f7SAndroid Build Coastguard Worker 			auto &ptr = src.Pointer();
154*03ce13f7SAndroid Build Coastguard Worker 			SIMD::UInt lowerBits, upperBits;
155*03ce13f7SAndroid Build Coastguard Worker 			ptr.castTo(lowerBits, upperBits);
156*03ce13f7SAndroid Build Coastguard Worker 
157*03ce13f7SAndroid Build Coastguard Worker 			auto &dst = createIntermediate(resultID, 2);
158*03ce13f7SAndroid Build Coastguard Worker 			dst.move(0, lowerBits);
159*03ce13f7SAndroid Build Coastguard Worker 			dst.move(1, upperBits);
160*03ce13f7SAndroid Build Coastguard Worker 		}
161*03ce13f7SAndroid Build Coastguard Worker 	}
162*03ce13f7SAndroid Build Coastguard Worker 	else  // Integer bits -> Pointer
163*03ce13f7SAndroid Build Coastguard Worker 	{
164*03ce13f7SAndroid Build Coastguard Worker 		if(sizeof(void *) == 4)  // 32-bit pointers
165*03ce13f7SAndroid Build Coastguard Worker 		{
166*03ce13f7SAndroid Build Coastguard Worker 			createPointer(resultID, SIMD::Pointer(src.UInt(0)));
167*03ce13f7SAndroid Build Coastguard Worker 		}
168*03ce13f7SAndroid Build Coastguard Worker 		else  // 64-bit pointers
169*03ce13f7SAndroid Build Coastguard Worker 		{
170*03ce13f7SAndroid Build Coastguard Worker 			ASSERT(sizeof(void *) == 8);
171*03ce13f7SAndroid Build Coastguard Worker 			// Casting two 32-bit integers into a 64-bit pointer
172*03ce13f7SAndroid Build Coastguard Worker 			createPointer(resultID, SIMD::Pointer(src.UInt(0), src.UInt(1)));
173*03ce13f7SAndroid Build Coastguard Worker 		}
174*03ce13f7SAndroid Build Coastguard Worker 	}
175*03ce13f7SAndroid Build Coastguard Worker }
176*03ce13f7SAndroid Build Coastguard Worker 
EmitUnaryOp(Spirv::InsnIterator insn)177*03ce13f7SAndroid Build Coastguard Worker void SpirvEmitter::EmitUnaryOp(Spirv::InsnIterator insn)
178*03ce13f7SAndroid Build Coastguard Worker {
179*03ce13f7SAndroid Build Coastguard Worker 	auto &type = shader.getType(insn.resultTypeId());
180*03ce13f7SAndroid Build Coastguard Worker 	auto src = Operand(shader, *this, insn.word(3));
181*03ce13f7SAndroid Build Coastguard Worker 
182*03ce13f7SAndroid Build Coastguard Worker 	bool dstIsPointer = shader.getObject(insn.resultId()).kind == Spirv::Object::Kind::Pointer;
183*03ce13f7SAndroid Build Coastguard Worker 	bool srcIsPointer = src.isPointer();
184*03ce13f7SAndroid Build Coastguard Worker 	if(srcIsPointer || dstIsPointer)
185*03ce13f7SAndroid Build Coastguard Worker 	{
186*03ce13f7SAndroid Build Coastguard Worker 		ASSERT(insn.opcode() == spv::OpBitcast);
187*03ce13f7SAndroid Build Coastguard Worker 		ASSERT(srcIsPointer || (type.componentCount == 1));  // When the ouput is a pointer, it's a single pointer
188*03ce13f7SAndroid Build Coastguard Worker 
189*03ce13f7SAndroid Build Coastguard Worker 		return EmitBitcastPointer(insn.resultId(), src);
190*03ce13f7SAndroid Build Coastguard Worker 	}
191*03ce13f7SAndroid Build Coastguard Worker 
192*03ce13f7SAndroid Build Coastguard Worker 	auto &dst = createIntermediate(insn.resultId(), type.componentCount);
193*03ce13f7SAndroid Build Coastguard Worker 
194*03ce13f7SAndroid Build Coastguard Worker 	for(auto i = 0u; i < type.componentCount; i++)
195*03ce13f7SAndroid Build Coastguard Worker 	{
196*03ce13f7SAndroid Build Coastguard Worker 		switch(insn.opcode())
197*03ce13f7SAndroid Build Coastguard Worker 		{
198*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpNot:
199*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpLogicalNot:  // logical not == bitwise not due to all-bits boolean representation
200*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, ~src.UInt(i));
201*03ce13f7SAndroid Build Coastguard Worker 			break;
202*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpBitFieldInsert:
203*03ce13f7SAndroid Build Coastguard Worker 			{
204*03ce13f7SAndroid Build Coastguard Worker 				auto insert = Operand(shader, *this, insn.word(4)).UInt(i);
205*03ce13f7SAndroid Build Coastguard Worker 				auto offset = Operand(shader, *this, insn.word(5)).UInt(0);
206*03ce13f7SAndroid Build Coastguard Worker 				auto count = Operand(shader, *this, insn.word(6)).UInt(0);
207*03ce13f7SAndroid Build Coastguard Worker 				auto one = SIMD::UInt(1);
208*03ce13f7SAndroid Build Coastguard Worker 				auto v = src.UInt(i);
209*03ce13f7SAndroid Build Coastguard Worker 				auto mask = Bitmask32(offset + count) ^ Bitmask32(offset);
210*03ce13f7SAndroid Build Coastguard Worker 				dst.move(i, (v & ~mask) | ((insert << offset) & mask));
211*03ce13f7SAndroid Build Coastguard Worker 			}
212*03ce13f7SAndroid Build Coastguard Worker 			break;
213*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpBitFieldSExtract:
214*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpBitFieldUExtract:
215*03ce13f7SAndroid Build Coastguard Worker 			{
216*03ce13f7SAndroid Build Coastguard Worker 				auto offset = Operand(shader, *this, insn.word(4)).UInt(0);
217*03ce13f7SAndroid Build Coastguard Worker 				auto count = Operand(shader, *this, insn.word(5)).UInt(0);
218*03ce13f7SAndroid Build Coastguard Worker 				auto one = SIMD::UInt(1);
219*03ce13f7SAndroid Build Coastguard Worker 				auto v = src.UInt(i);
220*03ce13f7SAndroid Build Coastguard Worker 				SIMD::UInt out = (v >> offset) & Bitmask32(count);
221*03ce13f7SAndroid Build Coastguard Worker 				if(insn.opcode() == spv::OpBitFieldSExtract)
222*03ce13f7SAndroid Build Coastguard Worker 				{
223*03ce13f7SAndroid Build Coastguard Worker 					auto sign = out & NthBit32(count - one);
224*03ce13f7SAndroid Build Coastguard Worker 					auto sext = ~(sign - one);
225*03ce13f7SAndroid Build Coastguard Worker 					out |= sext;
226*03ce13f7SAndroid Build Coastguard Worker 				}
227*03ce13f7SAndroid Build Coastguard Worker 				dst.move(i, out);
228*03ce13f7SAndroid Build Coastguard Worker 			}
229*03ce13f7SAndroid Build Coastguard Worker 			break;
230*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpBitReverse:
231*03ce13f7SAndroid Build Coastguard Worker 			{
232*03ce13f7SAndroid Build Coastguard Worker 				// TODO: Add an intrinsic to reactor. Even if there isn't a
233*03ce13f7SAndroid Build Coastguard Worker 				// single vector instruction, there may be target-dependent
234*03ce13f7SAndroid Build Coastguard Worker 				// ways to make this faster.
235*03ce13f7SAndroid Build Coastguard Worker 				// https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel
236*03ce13f7SAndroid Build Coastguard Worker 				SIMD::UInt v = src.UInt(i);
237*03ce13f7SAndroid Build Coastguard Worker 				v = ((v >> 1) & SIMD::UInt(0x55555555)) | ((v & SIMD::UInt(0x55555555)) << 1);
238*03ce13f7SAndroid Build Coastguard Worker 				v = ((v >> 2) & SIMD::UInt(0x33333333)) | ((v & SIMD::UInt(0x33333333)) << 2);
239*03ce13f7SAndroid Build Coastguard Worker 				v = ((v >> 4) & SIMD::UInt(0x0F0F0F0F)) | ((v & SIMD::UInt(0x0F0F0F0F)) << 4);
240*03ce13f7SAndroid Build Coastguard Worker 				v = ((v >> 8) & SIMD::UInt(0x00FF00FF)) | ((v & SIMD::UInt(0x00FF00FF)) << 8);
241*03ce13f7SAndroid Build Coastguard Worker 				v = (v >> 16) | (v << 16);
242*03ce13f7SAndroid Build Coastguard Worker 				dst.move(i, v);
243*03ce13f7SAndroid Build Coastguard Worker 			}
244*03ce13f7SAndroid Build Coastguard Worker 			break;
245*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpBitCount:
246*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, CountBits(src.UInt(i)));
247*03ce13f7SAndroid Build Coastguard Worker 			break;
248*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpSNegate:
249*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, -src.Int(i));
250*03ce13f7SAndroid Build Coastguard Worker 			break;
251*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpFNegate:
252*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, -src.Float(i));
253*03ce13f7SAndroid Build Coastguard Worker 			break;
254*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpConvertFToU:
255*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, SIMD::UInt(src.Float(i)));
256*03ce13f7SAndroid Build Coastguard Worker 			break;
257*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpConvertFToS:
258*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, SIMD::Int(src.Float(i)));
259*03ce13f7SAndroid Build Coastguard Worker 			break;
260*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpConvertSToF:
261*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, SIMD::Float(src.Int(i)));
262*03ce13f7SAndroid Build Coastguard Worker 			break;
263*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpConvertUToF:
264*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, SIMD::Float(src.UInt(i)));
265*03ce13f7SAndroid Build Coastguard Worker 			break;
266*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpBitcast:
267*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, src.Float(i));
268*03ce13f7SAndroid Build Coastguard Worker 			break;
269*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpIsInf:
270*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, IsInf(src.Float(i)));
271*03ce13f7SAndroid Build Coastguard Worker 			break;
272*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpIsNan:
273*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, IsNan(src.Float(i)));
274*03ce13f7SAndroid Build Coastguard Worker 			break;
275*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpDPdx:
276*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpDPdxCoarse:
277*03ce13f7SAndroid Build Coastguard Worker 			// Derivative instructions: FS invocations are laid out like so:
278*03ce13f7SAndroid Build Coastguard Worker 			//    0 1
279*03ce13f7SAndroid Build Coastguard Worker 			//    2 3
280*03ce13f7SAndroid Build Coastguard Worker 			ASSERT(SIMD::Width == 4);  // All cross-lane instructions will need care when using a different width
281*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, SIMD::Float(Extract(src.Float(i), 1) - Extract(src.Float(i), 0)));
282*03ce13f7SAndroid Build Coastguard Worker 			break;
283*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpDPdy:
284*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpDPdyCoarse:
285*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, SIMD::Float(Extract(src.Float(i), 2) - Extract(src.Float(i), 0)));
286*03ce13f7SAndroid Build Coastguard Worker 			break;
287*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpFwidth:
288*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpFwidthCoarse:
289*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, SIMD::Float(Abs(Extract(src.Float(i), 1) - Extract(src.Float(i), 0)) + Abs(Extract(src.Float(i), 2) - Extract(src.Float(i), 0))));
290*03ce13f7SAndroid Build Coastguard Worker 			break;
291*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpDPdxFine:
292*03ce13f7SAndroid Build Coastguard Worker 			{
293*03ce13f7SAndroid Build Coastguard Worker 				auto firstRow = Extract(src.Float(i), 1) - Extract(src.Float(i), 0);
294*03ce13f7SAndroid Build Coastguard Worker 				auto secondRow = Extract(src.Float(i), 3) - Extract(src.Float(i), 2);
295*03ce13f7SAndroid Build Coastguard Worker 				SIMD::Float v = SIMD::Float(firstRow);
296*03ce13f7SAndroid Build Coastguard Worker 				v = Insert(v, secondRow, 2);
297*03ce13f7SAndroid Build Coastguard Worker 				v = Insert(v, secondRow, 3);
298*03ce13f7SAndroid Build Coastguard Worker 				dst.move(i, v);
299*03ce13f7SAndroid Build Coastguard Worker 			}
300*03ce13f7SAndroid Build Coastguard Worker 			break;
301*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpDPdyFine:
302*03ce13f7SAndroid Build Coastguard Worker 			{
303*03ce13f7SAndroid Build Coastguard Worker 				auto firstColumn = Extract(src.Float(i), 2) - Extract(src.Float(i), 0);
304*03ce13f7SAndroid Build Coastguard Worker 				auto secondColumn = Extract(src.Float(i), 3) - Extract(src.Float(i), 1);
305*03ce13f7SAndroid Build Coastguard Worker 				SIMD::Float v = SIMD::Float(firstColumn);
306*03ce13f7SAndroid Build Coastguard Worker 				v = Insert(v, secondColumn, 1);
307*03ce13f7SAndroid Build Coastguard Worker 				v = Insert(v, secondColumn, 3);
308*03ce13f7SAndroid Build Coastguard Worker 				dst.move(i, v);
309*03ce13f7SAndroid Build Coastguard Worker 			}
310*03ce13f7SAndroid Build Coastguard Worker 			break;
311*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpFwidthFine:
312*03ce13f7SAndroid Build Coastguard Worker 			{
313*03ce13f7SAndroid Build Coastguard Worker 				auto firstRow = Extract(src.Float(i), 1) - Extract(src.Float(i), 0);
314*03ce13f7SAndroid Build Coastguard Worker 				auto secondRow = Extract(src.Float(i), 3) - Extract(src.Float(i), 2);
315*03ce13f7SAndroid Build Coastguard Worker 				SIMD::Float dpdx = SIMD::Float(firstRow);
316*03ce13f7SAndroid Build Coastguard Worker 				dpdx = Insert(dpdx, secondRow, 2);
317*03ce13f7SAndroid Build Coastguard Worker 				dpdx = Insert(dpdx, secondRow, 3);
318*03ce13f7SAndroid Build Coastguard Worker 				auto firstColumn = Extract(src.Float(i), 2) - Extract(src.Float(i), 0);
319*03ce13f7SAndroid Build Coastguard Worker 				auto secondColumn = Extract(src.Float(i), 3) - Extract(src.Float(i), 1);
320*03ce13f7SAndroid Build Coastguard Worker 				SIMD::Float dpdy = SIMD::Float(firstColumn);
321*03ce13f7SAndroid Build Coastguard Worker 				dpdy = Insert(dpdy, secondColumn, 1);
322*03ce13f7SAndroid Build Coastguard Worker 				dpdy = Insert(dpdy, secondColumn, 3);
323*03ce13f7SAndroid Build Coastguard Worker 				dst.move(i, Abs(dpdx) + Abs(dpdy));
324*03ce13f7SAndroid Build Coastguard Worker 			}
325*03ce13f7SAndroid Build Coastguard Worker 			break;
326*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpQuantizeToF16:
327*03ce13f7SAndroid Build Coastguard Worker 			{
328*03ce13f7SAndroid Build Coastguard Worker 				// Note: keep in sync with the specialization constant version in EvalSpecConstantUnaryOp
329*03ce13f7SAndroid Build Coastguard Worker 				auto abs = Abs(src.Float(i));
330*03ce13f7SAndroid Build Coastguard Worker 				auto sign = src.Int(i) & SIMD::Int(0x80000000);
331*03ce13f7SAndroid Build Coastguard Worker 				auto isZero = CmpLT(abs, SIMD::Float(0.000061035f));
332*03ce13f7SAndroid Build Coastguard Worker 				auto isInf = CmpGT(abs, SIMD::Float(65504.0f));
333*03ce13f7SAndroid Build Coastguard Worker 				auto isNaN = IsNan(abs);
334*03ce13f7SAndroid Build Coastguard Worker 				auto isInfOrNan = isInf | isNaN;
335*03ce13f7SAndroid Build Coastguard Worker 				SIMD::Int v = src.Int(i) & SIMD::Int(0xFFFFE000);
336*03ce13f7SAndroid Build Coastguard Worker 				v &= ~isZero | SIMD::Int(0x80000000);
337*03ce13f7SAndroid Build Coastguard Worker 				v = sign | (isInfOrNan & SIMD::Int(0x7F800000)) | (~isInfOrNan & v);
338*03ce13f7SAndroid Build Coastguard Worker 				v |= isNaN & SIMD::Int(0x400000);
339*03ce13f7SAndroid Build Coastguard Worker 				dst.move(i, v);
340*03ce13f7SAndroid Build Coastguard Worker 			}
341*03ce13f7SAndroid Build Coastguard Worker 			break;
342*03ce13f7SAndroid Build Coastguard Worker 		default:
343*03ce13f7SAndroid Build Coastguard Worker 			UNREACHABLE("%s", shader.OpcodeName(insn.opcode()));
344*03ce13f7SAndroid Build Coastguard Worker 		}
345*03ce13f7SAndroid Build Coastguard Worker 	}
346*03ce13f7SAndroid Build Coastguard Worker }
347*03ce13f7SAndroid Build Coastguard Worker 
EmitBinaryOp(Spirv::InsnIterator insn)348*03ce13f7SAndroid Build Coastguard Worker void SpirvEmitter::EmitBinaryOp(Spirv::InsnIterator insn)
349*03ce13f7SAndroid Build Coastguard Worker {
350*03ce13f7SAndroid Build Coastguard Worker 	auto &type = shader.getType(insn.resultTypeId());
351*03ce13f7SAndroid Build Coastguard Worker 	auto &dst = createIntermediate(insn.resultId(), type.componentCount);
352*03ce13f7SAndroid Build Coastguard Worker 	auto &lhsType = shader.getObjectType(insn.word(3));
353*03ce13f7SAndroid Build Coastguard Worker 	auto lhs = Operand(shader, *this, insn.word(3));
354*03ce13f7SAndroid Build Coastguard Worker 	auto rhs = Operand(shader, *this, insn.word(4));
355*03ce13f7SAndroid Build Coastguard Worker 
356*03ce13f7SAndroid Build Coastguard Worker 	for(auto i = 0u; i < lhsType.componentCount; i++)
357*03ce13f7SAndroid Build Coastguard Worker 	{
358*03ce13f7SAndroid Build Coastguard Worker 		switch(insn.opcode())
359*03ce13f7SAndroid Build Coastguard Worker 		{
360*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpIAdd:
361*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, lhs.Int(i) + rhs.Int(i));
362*03ce13f7SAndroid Build Coastguard Worker 			break;
363*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpISub:
364*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, lhs.Int(i) - rhs.Int(i));
365*03ce13f7SAndroid Build Coastguard Worker 			break;
366*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpIMul:
367*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, lhs.Int(i) * rhs.Int(i));
368*03ce13f7SAndroid Build Coastguard Worker 			break;
369*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpSDiv:
370*03ce13f7SAndroid Build Coastguard Worker 			{
371*03ce13f7SAndroid Build Coastguard Worker 				SIMD::Int a = lhs.Int(i);
372*03ce13f7SAndroid Build Coastguard Worker 				SIMD::Int b = rhs.Int(i);
373*03ce13f7SAndroid Build Coastguard Worker 				b = b | CmpEQ(b, SIMD::Int(0));                                       // prevent divide-by-zero
374*03ce13f7SAndroid Build Coastguard Worker 				a = a | (CmpEQ(a, SIMD::Int(0x80000000)) & CmpEQ(b, SIMD::Int(-1)));  // prevent integer overflow
375*03ce13f7SAndroid Build Coastguard Worker 				dst.move(i, a / b);
376*03ce13f7SAndroid Build Coastguard Worker 			}
377*03ce13f7SAndroid Build Coastguard Worker 			break;
378*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpUDiv:
379*03ce13f7SAndroid Build Coastguard Worker 			{
380*03ce13f7SAndroid Build Coastguard Worker 				auto zeroMask = As<SIMD::UInt>(CmpEQ(rhs.Int(i), SIMD::Int(0)));
381*03ce13f7SAndroid Build Coastguard Worker 				dst.move(i, lhs.UInt(i) / (rhs.UInt(i) | zeroMask));
382*03ce13f7SAndroid Build Coastguard Worker 			}
383*03ce13f7SAndroid Build Coastguard Worker 			break;
384*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpSRem:
385*03ce13f7SAndroid Build Coastguard Worker 			{
386*03ce13f7SAndroid Build Coastguard Worker 				SIMD::Int a = lhs.Int(i);
387*03ce13f7SAndroid Build Coastguard Worker 				SIMD::Int b = rhs.Int(i);
388*03ce13f7SAndroid Build Coastguard Worker 				b = b | CmpEQ(b, SIMD::Int(0));                                       // prevent divide-by-zero
389*03ce13f7SAndroid Build Coastguard Worker 				a = a | (CmpEQ(a, SIMD::Int(0x80000000)) & CmpEQ(b, SIMD::Int(-1)));  // prevent integer overflow
390*03ce13f7SAndroid Build Coastguard Worker 				dst.move(i, a % b);
391*03ce13f7SAndroid Build Coastguard Worker 			}
392*03ce13f7SAndroid Build Coastguard Worker 			break;
393*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpSMod:
394*03ce13f7SAndroid Build Coastguard Worker 			{
395*03ce13f7SAndroid Build Coastguard Worker 				SIMD::Int a = lhs.Int(i);
396*03ce13f7SAndroid Build Coastguard Worker 				SIMD::Int b = rhs.Int(i);
397*03ce13f7SAndroid Build Coastguard Worker 				b = b | CmpEQ(b, SIMD::Int(0));                                       // prevent divide-by-zero
398*03ce13f7SAndroid Build Coastguard Worker 				a = a | (CmpEQ(a, SIMD::Int(0x80000000)) & CmpEQ(b, SIMD::Int(-1)));  // prevent integer overflow
399*03ce13f7SAndroid Build Coastguard Worker 				auto mod = a % b;
400*03ce13f7SAndroid Build Coastguard Worker 				// If a and b have opposite signs, the remainder operation takes
401*03ce13f7SAndroid Build Coastguard Worker 				// the sign from a but OpSMod is supposed to take the sign of b.
402*03ce13f7SAndroid Build Coastguard Worker 				// Adding b will ensure that the result has the correct sign and
403*03ce13f7SAndroid Build Coastguard Worker 				// that it is still congruent to a modulo b.
404*03ce13f7SAndroid Build Coastguard Worker 				//
405*03ce13f7SAndroid Build Coastguard Worker 				// See also http://mathforum.org/library/drmath/view/52343.html
406*03ce13f7SAndroid Build Coastguard Worker 				auto signDiff = CmpNEQ(CmpGE(a, SIMD::Int(0)), CmpGE(b, SIMD::Int(0)));
407*03ce13f7SAndroid Build Coastguard Worker 				auto fixedMod = mod + (b & CmpNEQ(mod, SIMD::Int(0)) & signDiff);
408*03ce13f7SAndroid Build Coastguard Worker 				dst.move(i, As<SIMD::Float>(fixedMod));
409*03ce13f7SAndroid Build Coastguard Worker 			}
410*03ce13f7SAndroid Build Coastguard Worker 			break;
411*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpUMod:
412*03ce13f7SAndroid Build Coastguard Worker 			{
413*03ce13f7SAndroid Build Coastguard Worker 				auto zeroMask = As<SIMD::UInt>(CmpEQ(rhs.Int(i), SIMD::Int(0)));
414*03ce13f7SAndroid Build Coastguard Worker 				dst.move(i, lhs.UInt(i) % (rhs.UInt(i) | zeroMask));
415*03ce13f7SAndroid Build Coastguard Worker 			}
416*03ce13f7SAndroid Build Coastguard Worker 			break;
417*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpIEqual:
418*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpLogicalEqual:
419*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, CmpEQ(lhs.Int(i), rhs.Int(i)));
420*03ce13f7SAndroid Build Coastguard Worker 			break;
421*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpINotEqual:
422*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpLogicalNotEqual:
423*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, CmpNEQ(lhs.Int(i), rhs.Int(i)));
424*03ce13f7SAndroid Build Coastguard Worker 			break;
425*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpUGreaterThan:
426*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, CmpGT(lhs.UInt(i), rhs.UInt(i)));
427*03ce13f7SAndroid Build Coastguard Worker 			break;
428*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpSGreaterThan:
429*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, CmpGT(lhs.Int(i), rhs.Int(i)));
430*03ce13f7SAndroid Build Coastguard Worker 			break;
431*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpUGreaterThanEqual:
432*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, CmpGE(lhs.UInt(i), rhs.UInt(i)));
433*03ce13f7SAndroid Build Coastguard Worker 			break;
434*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpSGreaterThanEqual:
435*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, CmpGE(lhs.Int(i), rhs.Int(i)));
436*03ce13f7SAndroid Build Coastguard Worker 			break;
437*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpULessThan:
438*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, CmpLT(lhs.UInt(i), rhs.UInt(i)));
439*03ce13f7SAndroid Build Coastguard Worker 			break;
440*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpSLessThan:
441*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, CmpLT(lhs.Int(i), rhs.Int(i)));
442*03ce13f7SAndroid Build Coastguard Worker 			break;
443*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpULessThanEqual:
444*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, CmpLE(lhs.UInt(i), rhs.UInt(i)));
445*03ce13f7SAndroid Build Coastguard Worker 			break;
446*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpSLessThanEqual:
447*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, CmpLE(lhs.Int(i), rhs.Int(i)));
448*03ce13f7SAndroid Build Coastguard Worker 			break;
449*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpFAdd:
450*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, lhs.Float(i) + rhs.Float(i));
451*03ce13f7SAndroid Build Coastguard Worker 			break;
452*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpFSub:
453*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, lhs.Float(i) - rhs.Float(i));
454*03ce13f7SAndroid Build Coastguard Worker 			break;
455*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpFMul:
456*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, lhs.Float(i) * rhs.Float(i));
457*03ce13f7SAndroid Build Coastguard Worker 			break;
458*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpFDiv:
459*03ce13f7SAndroid Build Coastguard Worker 			// TODO(b/169760262): Optimize using reciprocal instructions (2.5 ULP).
460*03ce13f7SAndroid Build Coastguard Worker 			// TODO(b/222218659): Optimize for RelaxedPrecision (2.5 ULP).
461*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, lhs.Float(i) / rhs.Float(i));
462*03ce13f7SAndroid Build Coastguard Worker 			break;
463*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpFMod:
464*03ce13f7SAndroid Build Coastguard Worker 			// TODO(b/126873455): Inaccurate for values greater than 2^24.
465*03ce13f7SAndroid Build Coastguard Worker 			// TODO(b/169760262): Optimize using reciprocal instructions.
466*03ce13f7SAndroid Build Coastguard Worker 			// TODO(b/222218659): Optimize for RelaxedPrecision.
467*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, lhs.Float(i) - rhs.Float(i) * Floor(lhs.Float(i) / rhs.Float(i)));
468*03ce13f7SAndroid Build Coastguard Worker 			break;
469*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpFRem:
470*03ce13f7SAndroid Build Coastguard Worker 			// TODO(b/169760262): Optimize using reciprocal instructions.
471*03ce13f7SAndroid Build Coastguard Worker 			// TODO(b/222218659): Optimize for RelaxedPrecision.
472*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, lhs.Float(i) % rhs.Float(i));
473*03ce13f7SAndroid Build Coastguard Worker 			break;
474*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpFOrdEqual:
475*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, CmpEQ(lhs.Float(i), rhs.Float(i)));
476*03ce13f7SAndroid Build Coastguard Worker 			break;
477*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpFUnordEqual:
478*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, CmpUEQ(lhs.Float(i), rhs.Float(i)));
479*03ce13f7SAndroid Build Coastguard Worker 			break;
480*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpFOrdNotEqual:
481*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, CmpNEQ(lhs.Float(i), rhs.Float(i)));
482*03ce13f7SAndroid Build Coastguard Worker 			break;
483*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpFUnordNotEqual:
484*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, CmpUNEQ(lhs.Float(i), rhs.Float(i)));
485*03ce13f7SAndroid Build Coastguard Worker 			break;
486*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpFOrdLessThan:
487*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, CmpLT(lhs.Float(i), rhs.Float(i)));
488*03ce13f7SAndroid Build Coastguard Worker 			break;
489*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpFUnordLessThan:
490*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, CmpULT(lhs.Float(i), rhs.Float(i)));
491*03ce13f7SAndroid Build Coastguard Worker 			break;
492*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpFOrdGreaterThan:
493*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, CmpGT(lhs.Float(i), rhs.Float(i)));
494*03ce13f7SAndroid Build Coastguard Worker 			break;
495*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpFUnordGreaterThan:
496*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, CmpUGT(lhs.Float(i), rhs.Float(i)));
497*03ce13f7SAndroid Build Coastguard Worker 			break;
498*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpFOrdLessThanEqual:
499*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, CmpLE(lhs.Float(i), rhs.Float(i)));
500*03ce13f7SAndroid Build Coastguard Worker 			break;
501*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpFUnordLessThanEqual:
502*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, CmpULE(lhs.Float(i), rhs.Float(i)));
503*03ce13f7SAndroid Build Coastguard Worker 			break;
504*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpFOrdGreaterThanEqual:
505*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, CmpGE(lhs.Float(i), rhs.Float(i)));
506*03ce13f7SAndroid Build Coastguard Worker 			break;
507*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpFUnordGreaterThanEqual:
508*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, CmpUGE(lhs.Float(i), rhs.Float(i)));
509*03ce13f7SAndroid Build Coastguard Worker 			break;
510*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpShiftRightLogical:
511*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, lhs.UInt(i) >> rhs.UInt(i));
512*03ce13f7SAndroid Build Coastguard Worker 			break;
513*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpShiftRightArithmetic:
514*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, lhs.Int(i) >> rhs.Int(i));
515*03ce13f7SAndroid Build Coastguard Worker 			break;
516*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpShiftLeftLogical:
517*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, lhs.UInt(i) << rhs.UInt(i));
518*03ce13f7SAndroid Build Coastguard Worker 			break;
519*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpBitwiseOr:
520*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpLogicalOr:
521*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, lhs.UInt(i) | rhs.UInt(i));
522*03ce13f7SAndroid Build Coastguard Worker 			break;
523*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpBitwiseXor:
524*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, lhs.UInt(i) ^ rhs.UInt(i));
525*03ce13f7SAndroid Build Coastguard Worker 			break;
526*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpBitwiseAnd:
527*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpLogicalAnd:
528*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, lhs.UInt(i) & rhs.UInt(i));
529*03ce13f7SAndroid Build Coastguard Worker 			break;
530*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpSMulExtended:
531*03ce13f7SAndroid Build Coastguard Worker 			// Extended ops: result is a structure containing two members of the same type as lhs & rhs.
532*03ce13f7SAndroid Build Coastguard Worker 			// In our flat view then, component i is the i'th component of the first member;
533*03ce13f7SAndroid Build Coastguard Worker 			// component i + N is the i'th component of the second member.
534*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, lhs.Int(i) * rhs.Int(i));
535*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i + lhsType.componentCount, MulHigh(lhs.Int(i), rhs.Int(i)));
536*03ce13f7SAndroid Build Coastguard Worker 			break;
537*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpUMulExtended:
538*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, lhs.UInt(i) * rhs.UInt(i));
539*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i + lhsType.componentCount, MulHigh(lhs.UInt(i), rhs.UInt(i)));
540*03ce13f7SAndroid Build Coastguard Worker 			break;
541*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpIAddCarry:
542*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, lhs.UInt(i) + rhs.UInt(i));
543*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i + lhsType.componentCount, CmpLT(dst.UInt(i), lhs.UInt(i)) >> 31);
544*03ce13f7SAndroid Build Coastguard Worker 			break;
545*03ce13f7SAndroid Build Coastguard Worker 		case spv::OpISubBorrow:
546*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i, lhs.UInt(i) - rhs.UInt(i));
547*03ce13f7SAndroid Build Coastguard Worker 			dst.move(i + lhsType.componentCount, CmpLT(lhs.UInt(i), rhs.UInt(i)) >> 31);
548*03ce13f7SAndroid Build Coastguard Worker 			break;
549*03ce13f7SAndroid Build Coastguard Worker 		default:
550*03ce13f7SAndroid Build Coastguard Worker 			UNREACHABLE("%s", shader.OpcodeName(insn.opcode()));
551*03ce13f7SAndroid Build Coastguard Worker 		}
552*03ce13f7SAndroid Build Coastguard Worker 	}
553*03ce13f7SAndroid Build Coastguard Worker 
554*03ce13f7SAndroid Build Coastguard Worker 	SPIRV_SHADER_DBG("{0}: {1}", insn.word(2), dst);
555*03ce13f7SAndroid Build Coastguard Worker 	SPIRV_SHADER_DBG("{0}: {1}", insn.word(3), lhs);
556*03ce13f7SAndroid Build Coastguard Worker 	SPIRV_SHADER_DBG("{0}: {1}", insn.word(4), rhs);
557*03ce13f7SAndroid Build Coastguard Worker }
558*03ce13f7SAndroid Build Coastguard Worker 
EmitDot(Spirv::InsnIterator insn)559*03ce13f7SAndroid Build Coastguard Worker void SpirvEmitter::EmitDot(Spirv::InsnIterator insn)
560*03ce13f7SAndroid Build Coastguard Worker {
561*03ce13f7SAndroid Build Coastguard Worker 	auto &type = shader.getType(insn.resultTypeId());
562*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(type.componentCount == 1);
563*03ce13f7SAndroid Build Coastguard Worker 	auto &dst = createIntermediate(insn.resultId(), type.componentCount);
564*03ce13f7SAndroid Build Coastguard Worker 	auto &lhsType = shader.getObjectType(insn.word(3));
565*03ce13f7SAndroid Build Coastguard Worker 	auto lhs = Operand(shader, *this, insn.word(3));
566*03ce13f7SAndroid Build Coastguard Worker 	auto rhs = Operand(shader, *this, insn.word(4));
567*03ce13f7SAndroid Build Coastguard Worker 
568*03ce13f7SAndroid Build Coastguard Worker 	auto opcode = insn.opcode();
569*03ce13f7SAndroid Build Coastguard Worker 	switch(opcode)
570*03ce13f7SAndroid Build Coastguard Worker 	{
571*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpDot:
572*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, FDot(lhsType.componentCount, lhs, rhs));
573*03ce13f7SAndroid Build Coastguard Worker 		break;
574*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpSDot:
575*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, SDot(lhsType.componentCount, lhs, rhs, nullptr));
576*03ce13f7SAndroid Build Coastguard Worker 		break;
577*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpUDot:
578*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, UDot(lhsType.componentCount, lhs, rhs, nullptr));
579*03ce13f7SAndroid Build Coastguard Worker 		break;
580*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpSUDot:
581*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, SUDot(lhsType.componentCount, lhs, rhs, nullptr));
582*03ce13f7SAndroid Build Coastguard Worker 		break;
583*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpSDotAccSat:
584*03ce13f7SAndroid Build Coastguard Worker 		{
585*03ce13f7SAndroid Build Coastguard Worker 			auto accum = Operand(shader, *this, insn.word(5));
586*03ce13f7SAndroid Build Coastguard Worker 			dst.move(0, SDot(lhsType.componentCount, lhs, rhs, &accum));
587*03ce13f7SAndroid Build Coastguard Worker 		}
588*03ce13f7SAndroid Build Coastguard Worker 		break;
589*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpUDotAccSat:
590*03ce13f7SAndroid Build Coastguard Worker 		{
591*03ce13f7SAndroid Build Coastguard Worker 			auto accum = Operand(shader, *this, insn.word(5));
592*03ce13f7SAndroid Build Coastguard Worker 			dst.move(0, UDot(lhsType.componentCount, lhs, rhs, &accum));
593*03ce13f7SAndroid Build Coastguard Worker 		}
594*03ce13f7SAndroid Build Coastguard Worker 		break;
595*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpSUDotAccSat:
596*03ce13f7SAndroid Build Coastguard Worker 		{
597*03ce13f7SAndroid Build Coastguard Worker 			auto accum = Operand(shader, *this, insn.word(5));
598*03ce13f7SAndroid Build Coastguard Worker 			dst.move(0, SUDot(lhsType.componentCount, lhs, rhs, &accum));
599*03ce13f7SAndroid Build Coastguard Worker 		}
600*03ce13f7SAndroid Build Coastguard Worker 		break;
601*03ce13f7SAndroid Build Coastguard Worker 	default:
602*03ce13f7SAndroid Build Coastguard Worker 		UNREACHABLE("%s", shader.OpcodeName(opcode));
603*03ce13f7SAndroid Build Coastguard Worker 		break;
604*03ce13f7SAndroid Build Coastguard Worker 	}
605*03ce13f7SAndroid Build Coastguard Worker 
606*03ce13f7SAndroid Build Coastguard Worker 	SPIRV_SHADER_DBG("{0}: {1}", insn.resultId(), dst);
607*03ce13f7SAndroid Build Coastguard Worker 	SPIRV_SHADER_DBG("{0}: {1}", insn.word(3), lhs);
608*03ce13f7SAndroid Build Coastguard Worker 	SPIRV_SHADER_DBG("{0}: {1}", insn.word(4), rhs);
609*03ce13f7SAndroid Build Coastguard Worker }
610*03ce13f7SAndroid Build Coastguard Worker 
FDot(unsigned numComponents,const Operand & x,const Operand & y)611*03ce13f7SAndroid Build Coastguard Worker SIMD::Float SpirvEmitter::FDot(unsigned numComponents, const Operand &x, const Operand &y)
612*03ce13f7SAndroid Build Coastguard Worker {
613*03ce13f7SAndroid Build Coastguard Worker 	SIMD::Float d = x.Float(0) * y.Float(0);
614*03ce13f7SAndroid Build Coastguard Worker 
615*03ce13f7SAndroid Build Coastguard Worker 	for(auto i = 1u; i < numComponents; i++)
616*03ce13f7SAndroid Build Coastguard Worker 	{
617*03ce13f7SAndroid Build Coastguard Worker 		d = MulAdd(x.Float(i), y.Float(i), d);
618*03ce13f7SAndroid Build Coastguard Worker 	}
619*03ce13f7SAndroid Build Coastguard Worker 
620*03ce13f7SAndroid Build Coastguard Worker 	return d;
621*03ce13f7SAndroid Build Coastguard Worker }
622*03ce13f7SAndroid Build Coastguard Worker 
SDot(unsigned numComponents,const Operand & x,const Operand & y,const Operand * accum)623*03ce13f7SAndroid Build Coastguard Worker SIMD::Int SpirvEmitter::SDot(unsigned numComponents, const Operand &x, const Operand &y, const Operand *accum)
624*03ce13f7SAndroid Build Coastguard Worker {
625*03ce13f7SAndroid Build Coastguard Worker 	SIMD::Int d(0);
626*03ce13f7SAndroid Build Coastguard Worker 
627*03ce13f7SAndroid Build Coastguard Worker 	if(numComponents == 1)  // 4x8bit packed
628*03ce13f7SAndroid Build Coastguard Worker 	{
629*03ce13f7SAndroid Build Coastguard Worker 		numComponents = 4;
630*03ce13f7SAndroid Build Coastguard Worker 		for(auto i = 0u; i < numComponents; i++)
631*03ce13f7SAndroid Build Coastguard Worker 		{
632*03ce13f7SAndroid Build Coastguard Worker 			Int4 xs(As<SByte4>(Extract(x.Int(0), i)));
633*03ce13f7SAndroid Build Coastguard Worker 			Int4 ys(As<SByte4>(Extract(y.Int(0), i)));
634*03ce13f7SAndroid Build Coastguard Worker 
635*03ce13f7SAndroid Build Coastguard Worker 			Int4 xy = xs * ys;
636*03ce13f7SAndroid Build Coastguard Worker 			rr::Int sum = Extract(xy, 0) + Extract(xy, 1) + Extract(xy, 2) + Extract(xy, 3);
637*03ce13f7SAndroid Build Coastguard Worker 
638*03ce13f7SAndroid Build Coastguard Worker 			d = Insert(d, sum, i);
639*03ce13f7SAndroid Build Coastguard Worker 		}
640*03ce13f7SAndroid Build Coastguard Worker 	}
641*03ce13f7SAndroid Build Coastguard Worker 	else
642*03ce13f7SAndroid Build Coastguard Worker 	{
643*03ce13f7SAndroid Build Coastguard Worker 		d = x.Int(0) * y.Int(0);
644*03ce13f7SAndroid Build Coastguard Worker 
645*03ce13f7SAndroid Build Coastguard Worker 		for(auto i = 1u; i < numComponents; i++)
646*03ce13f7SAndroid Build Coastguard Worker 		{
647*03ce13f7SAndroid Build Coastguard Worker 			d += x.Int(i) * y.Int(i);
648*03ce13f7SAndroid Build Coastguard Worker 		}
649*03ce13f7SAndroid Build Coastguard Worker 	}
650*03ce13f7SAndroid Build Coastguard Worker 
651*03ce13f7SAndroid Build Coastguard Worker 	if(accum)
652*03ce13f7SAndroid Build Coastguard Worker 	{
653*03ce13f7SAndroid Build Coastguard Worker 		d = AddSat(d, accum->Int(0));
654*03ce13f7SAndroid Build Coastguard Worker 	}
655*03ce13f7SAndroid Build Coastguard Worker 
656*03ce13f7SAndroid Build Coastguard Worker 	return d;
657*03ce13f7SAndroid Build Coastguard Worker }
658*03ce13f7SAndroid Build Coastguard Worker 
UDot(unsigned numComponents,const Operand & x,const Operand & y,const Operand * accum)659*03ce13f7SAndroid Build Coastguard Worker SIMD::UInt SpirvEmitter::UDot(unsigned numComponents, const Operand &x, const Operand &y, const Operand *accum)
660*03ce13f7SAndroid Build Coastguard Worker {
661*03ce13f7SAndroid Build Coastguard Worker 	SIMD::UInt d(0);
662*03ce13f7SAndroid Build Coastguard Worker 
663*03ce13f7SAndroid Build Coastguard Worker 	if(numComponents == 1)  // 4x8bit packed
664*03ce13f7SAndroid Build Coastguard Worker 	{
665*03ce13f7SAndroid Build Coastguard Worker 		numComponents = 4;
666*03ce13f7SAndroid Build Coastguard Worker 		for(auto i = 0u; i < numComponents; i++)
667*03ce13f7SAndroid Build Coastguard Worker 		{
668*03ce13f7SAndroid Build Coastguard Worker 			Int4 xs(As<Byte4>(Extract(x.Int(0), i)));
669*03ce13f7SAndroid Build Coastguard Worker 			Int4 ys(As<Byte4>(Extract(y.Int(0), i)));
670*03ce13f7SAndroid Build Coastguard Worker 
671*03ce13f7SAndroid Build Coastguard Worker 			UInt4 xy = xs * ys;
672*03ce13f7SAndroid Build Coastguard Worker 			rr::UInt sum = Extract(xy, 0) + Extract(xy, 1) + Extract(xy, 2) + Extract(xy, 3);
673*03ce13f7SAndroid Build Coastguard Worker 
674*03ce13f7SAndroid Build Coastguard Worker 			d = Insert(d, sum, i);
675*03ce13f7SAndroid Build Coastguard Worker 		}
676*03ce13f7SAndroid Build Coastguard Worker 	}
677*03ce13f7SAndroid Build Coastguard Worker 	else
678*03ce13f7SAndroid Build Coastguard Worker 	{
679*03ce13f7SAndroid Build Coastguard Worker 		d = x.UInt(0) * y.UInt(0);
680*03ce13f7SAndroid Build Coastguard Worker 
681*03ce13f7SAndroid Build Coastguard Worker 		for(auto i = 1u; i < numComponents; i++)
682*03ce13f7SAndroid Build Coastguard Worker 		{
683*03ce13f7SAndroid Build Coastguard Worker 			d += x.UInt(i) * y.UInt(i);
684*03ce13f7SAndroid Build Coastguard Worker 		}
685*03ce13f7SAndroid Build Coastguard Worker 	}
686*03ce13f7SAndroid Build Coastguard Worker 
687*03ce13f7SAndroid Build Coastguard Worker 	if(accum)
688*03ce13f7SAndroid Build Coastguard Worker 	{
689*03ce13f7SAndroid Build Coastguard Worker 		d = AddSat(d, accum->UInt(0));
690*03ce13f7SAndroid Build Coastguard Worker 	}
691*03ce13f7SAndroid Build Coastguard Worker 
692*03ce13f7SAndroid Build Coastguard Worker 	return d;
693*03ce13f7SAndroid Build Coastguard Worker }
694*03ce13f7SAndroid Build Coastguard Worker 
SUDot(unsigned numComponents,const Operand & x,const Operand & y,const Operand * accum)695*03ce13f7SAndroid Build Coastguard Worker SIMD::Int SpirvEmitter::SUDot(unsigned numComponents, const Operand &x, const Operand &y, const Operand *accum)
696*03ce13f7SAndroid Build Coastguard Worker {
697*03ce13f7SAndroid Build Coastguard Worker 	SIMD::Int d(0);
698*03ce13f7SAndroid Build Coastguard Worker 
699*03ce13f7SAndroid Build Coastguard Worker 	if(numComponents == 1)  // 4x8bit packed
700*03ce13f7SAndroid Build Coastguard Worker 	{
701*03ce13f7SAndroid Build Coastguard Worker 		numComponents = 4;
702*03ce13f7SAndroid Build Coastguard Worker 		for(auto i = 0u; i < numComponents; i++)
703*03ce13f7SAndroid Build Coastguard Worker 		{
704*03ce13f7SAndroid Build Coastguard Worker 			Int4 xs(As<SByte4>(Extract(x.Int(0), i)));
705*03ce13f7SAndroid Build Coastguard Worker 			Int4 ys(As<Byte4>(Extract(y.Int(0), i)));
706*03ce13f7SAndroid Build Coastguard Worker 
707*03ce13f7SAndroid Build Coastguard Worker 			Int4 xy = xs * ys;
708*03ce13f7SAndroid Build Coastguard Worker 			rr::Int sum = Extract(xy, 0) + Extract(xy, 1) + Extract(xy, 2) + Extract(xy, 3);
709*03ce13f7SAndroid Build Coastguard Worker 
710*03ce13f7SAndroid Build Coastguard Worker 			d = Insert(d, sum, i);
711*03ce13f7SAndroid Build Coastguard Worker 		}
712*03ce13f7SAndroid Build Coastguard Worker 	}
713*03ce13f7SAndroid Build Coastguard Worker 	else
714*03ce13f7SAndroid Build Coastguard Worker 	{
715*03ce13f7SAndroid Build Coastguard Worker 		d = x.Int(0) * As<SIMD::Int>(y.UInt(0));
716*03ce13f7SAndroid Build Coastguard Worker 
717*03ce13f7SAndroid Build Coastguard Worker 		for(auto i = 1u; i < numComponents; i++)
718*03ce13f7SAndroid Build Coastguard Worker 		{
719*03ce13f7SAndroid Build Coastguard Worker 			d += x.Int(i) * As<SIMD::Int>(y.UInt(i));
720*03ce13f7SAndroid Build Coastguard Worker 		}
721*03ce13f7SAndroid Build Coastguard Worker 	}
722*03ce13f7SAndroid Build Coastguard Worker 
723*03ce13f7SAndroid Build Coastguard Worker 	if(accum)
724*03ce13f7SAndroid Build Coastguard Worker 	{
725*03ce13f7SAndroid Build Coastguard Worker 		d = AddSat(d, accum->Int(0));
726*03ce13f7SAndroid Build Coastguard Worker 	}
727*03ce13f7SAndroid Build Coastguard Worker 
728*03ce13f7SAndroid Build Coastguard Worker 	return d;
729*03ce13f7SAndroid Build Coastguard Worker }
730*03ce13f7SAndroid Build Coastguard Worker 
AddSat(RValue<SIMD::Int> a,RValue<SIMD::Int> b)731*03ce13f7SAndroid Build Coastguard Worker SIMD::Int SpirvEmitter::AddSat(RValue<SIMD::Int> a, RValue<SIMD::Int> b)
732*03ce13f7SAndroid Build Coastguard Worker {
733*03ce13f7SAndroid Build Coastguard Worker 	SIMD::Int sum = a + b;
734*03ce13f7SAndroid Build Coastguard Worker 	SIMD::Int sSign = sum >> 31;
735*03ce13f7SAndroid Build Coastguard Worker 	SIMD::Int aSign = a >> 31;
736*03ce13f7SAndroid Build Coastguard Worker 	SIMD::Int bSign = b >> 31;
737*03ce13f7SAndroid Build Coastguard Worker 
738*03ce13f7SAndroid Build Coastguard Worker 	// Overflow happened if both numbers added have the same sign and the sum has a different sign
739*03ce13f7SAndroid Build Coastguard Worker 	SIMD::Int oob = ~(aSign ^ bSign) & (aSign ^ sSign);
740*03ce13f7SAndroid Build Coastguard Worker 	SIMD::Int overflow = oob & sSign;
741*03ce13f7SAndroid Build Coastguard Worker 	SIMD::Int underflow = oob & aSign;
742*03ce13f7SAndroid Build Coastguard Worker 
743*03ce13f7SAndroid Build Coastguard Worker 	return (overflow & std::numeric_limits<int32_t>::max()) |
744*03ce13f7SAndroid Build Coastguard Worker 	       (underflow & std::numeric_limits<int32_t>::min()) |
745*03ce13f7SAndroid Build Coastguard Worker 	       (~oob & sum);
746*03ce13f7SAndroid Build Coastguard Worker }
747*03ce13f7SAndroid Build Coastguard Worker 
AddSat(RValue<SIMD::UInt> a,RValue<SIMD::UInt> b)748*03ce13f7SAndroid Build Coastguard Worker SIMD::UInt SpirvEmitter::AddSat(RValue<SIMD::UInt> a, RValue<SIMD::UInt> b)
749*03ce13f7SAndroid Build Coastguard Worker {
750*03ce13f7SAndroid Build Coastguard Worker 	SIMD::UInt sum = a + b;
751*03ce13f7SAndroid Build Coastguard Worker 
752*03ce13f7SAndroid Build Coastguard Worker 	// Overflow happened if the sum of unsigned integers is smaller than either of the 2 numbers being added
753*03ce13f7SAndroid Build Coastguard Worker 	// Note: CmpLT()'s return value is automatically set to UINT_MAX when true
754*03ce13f7SAndroid Build Coastguard Worker 	return CmpLT(sum, a) | sum;
755*03ce13f7SAndroid Build Coastguard Worker }
756*03ce13f7SAndroid Build Coastguard Worker 
757*03ce13f7SAndroid Build Coastguard Worker }  // namespace sw