• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //    http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "SpirvShader.hpp"
16 #include "SpirvShaderDebug.hpp"
17 
18 #include "ShaderCore.hpp"
19 
20 #include <spirv/unified1/spirv.hpp>
21 
22 namespace sw {
23 
EmitVectorTimesScalar(InsnIterator insn,EmitState * state) const24 SpirvShader::EmitResult SpirvShader::EmitVectorTimesScalar(InsnIterator insn, EmitState *state) const
25 {
26 	auto &type = getType(insn.resultTypeId());
27 	auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
28 	auto lhs = Operand(this, state, insn.word(3));
29 	auto rhs = Operand(this, state, insn.word(4));
30 
31 	for(auto i = 0u; i < type.componentCount; i++)
32 	{
33 		dst.move(i, lhs.Float(i) * rhs.Float(0));
34 	}
35 
36 	return EmitResult::Continue;
37 }
38 
EmitMatrixTimesVector(InsnIterator insn,EmitState * state) const39 SpirvShader::EmitResult SpirvShader::EmitMatrixTimesVector(InsnIterator insn, EmitState *state) const
40 {
41 	auto &type = getType(insn.resultTypeId());
42 	auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
43 	auto lhs = Operand(this, state, insn.word(3));
44 	auto rhs = Operand(this, state, insn.word(4));
45 
46 	for(auto i = 0u; i < type.componentCount; i++)
47 	{
48 		SIMD::Float v = lhs.Float(i) * rhs.Float(0);
49 		for(auto j = 1u; j < rhs.componentCount; j++)
50 		{
51 			v += lhs.Float(i + type.componentCount * j) * rhs.Float(j);
52 		}
53 		dst.move(i, v);
54 	}
55 
56 	return EmitResult::Continue;
57 }
58 
EmitVectorTimesMatrix(InsnIterator insn,EmitState * state) const59 SpirvShader::EmitResult SpirvShader::EmitVectorTimesMatrix(InsnIterator insn, EmitState *state) const
60 {
61 	auto &type = getType(insn.resultTypeId());
62 	auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
63 	auto lhs = Operand(this, state, insn.word(3));
64 	auto rhs = Operand(this, state, insn.word(4));
65 
66 	for(auto i = 0u; i < type.componentCount; i++)
67 	{
68 		SIMD::Float v = lhs.Float(0) * rhs.Float(i * lhs.componentCount);
69 		for(auto j = 1u; j < lhs.componentCount; j++)
70 		{
71 			v += lhs.Float(j) * rhs.Float(i * lhs.componentCount + j);
72 		}
73 		dst.move(i, v);
74 	}
75 
76 	return EmitResult::Continue;
77 }
78 
EmitMatrixTimesMatrix(InsnIterator insn,EmitState * state) const79 SpirvShader::EmitResult SpirvShader::EmitMatrixTimesMatrix(InsnIterator insn, EmitState *state) const
80 {
81 	auto &type = getType(insn.resultTypeId());
82 	auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
83 	auto lhs = Operand(this, state, insn.word(3));
84 	auto rhs = Operand(this, state, insn.word(4));
85 
86 	auto numColumns = type.definition.word(3);
87 	auto numRows = getType(type.definition.word(2)).definition.word(3);
88 	auto numAdds = getType(getObject(insn.word(3))).definition.word(3);
89 
90 	for(auto row = 0u; row < numRows; row++)
91 	{
92 		for(auto col = 0u; col < numColumns; col++)
93 		{
94 			SIMD::Float v = SIMD::Float(0);
95 			for(auto i = 0u; i < numAdds; i++)
96 			{
97 				v += lhs.Float(i * numRows + row) * rhs.Float(col * numAdds + i);
98 			}
99 			dst.move(numRows * col + row, v);
100 		}
101 	}
102 
103 	return EmitResult::Continue;
104 }
105 
EmitOuterProduct(InsnIterator insn,EmitState * state) const106 SpirvShader::EmitResult SpirvShader::EmitOuterProduct(InsnIterator insn, EmitState *state) const
107 {
108 	auto &type = getType(insn.resultTypeId());
109 	auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
110 	auto lhs = Operand(this, state, insn.word(3));
111 	auto rhs = Operand(this, state, insn.word(4));
112 
113 	auto numRows = lhs.componentCount;
114 	auto numCols = rhs.componentCount;
115 
116 	for(auto col = 0u; col < numCols; col++)
117 	{
118 		for(auto row = 0u; row < numRows; row++)
119 		{
120 			dst.move(col * numRows + row, lhs.Float(row) * rhs.Float(col));
121 		}
122 	}
123 
124 	return EmitResult::Continue;
125 }
126 
EmitTranspose(InsnIterator insn,EmitState * state) const127 SpirvShader::EmitResult SpirvShader::EmitTranspose(InsnIterator insn, EmitState *state) const
128 {
129 	auto &type = getType(insn.resultTypeId());
130 	auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
131 	auto mat = Operand(this, state, insn.word(3));
132 
133 	auto numCols = type.definition.word(3);
134 	auto numRows = getType(type.definition.word(2)).componentCount;
135 
136 	for(auto col = 0u; col < numCols; col++)
137 	{
138 		for(auto row = 0u; row < numRows; row++)
139 		{
140 			dst.move(col * numRows + row, mat.Float(row * numCols + col));
141 		}
142 	}
143 
144 	return EmitResult::Continue;
145 }
146 
EmitUnaryOp(InsnIterator insn,EmitState * state) const147 SpirvShader::EmitResult SpirvShader::EmitUnaryOp(InsnIterator insn, EmitState *state) const
148 {
149 	auto &type = getType(insn.resultTypeId());
150 	auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
151 	auto src = Operand(this, state, insn.word(3));
152 
153 	for(auto i = 0u; i < type.componentCount; i++)
154 	{
155 		switch(insn.opcode())
156 		{
157 			case spv::OpNot:
158 			case spv::OpLogicalNot:  // logical not == bitwise not due to all-bits boolean representation
159 				dst.move(i, ~src.UInt(i));
160 				break;
161 			case spv::OpBitFieldInsert:
162 			{
163 				auto insert = Operand(this, state, insn.word(4)).UInt(i);
164 				auto offset = Operand(this, state, insn.word(5)).UInt(0);
165 				auto count = Operand(this, state, insn.word(6)).UInt(0);
166 				auto one = SIMD::UInt(1);
167 				auto v = src.UInt(i);
168 				auto mask = Bitmask32(offset + count) ^ Bitmask32(offset);
169 				dst.move(i, (v & ~mask) | ((insert << offset) & mask));
170 				break;
171 			}
172 			case spv::OpBitFieldSExtract:
173 			case spv::OpBitFieldUExtract:
174 			{
175 				auto offset = Operand(this, state, insn.word(4)).UInt(0);
176 				auto count = Operand(this, state, insn.word(5)).UInt(0);
177 				auto one = SIMD::UInt(1);
178 				auto v = src.UInt(i);
179 				SIMD::UInt out = (v >> offset) & Bitmask32(count);
180 				if(insn.opcode() == spv::OpBitFieldSExtract)
181 				{
182 					auto sign = out & NthBit32(count - one);
183 					auto sext = ~(sign - one);
184 					out |= sext;
185 				}
186 				dst.move(i, out);
187 				break;
188 			}
189 			case spv::OpBitReverse:
190 			{
191 				// TODO: Add an intrinsic to reactor. Even if there isn't a
192 				// single vector instruction, there may be target-dependent
193 				// ways to make this faster.
194 				// https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel
195 				SIMD::UInt v = src.UInt(i);
196 				v = ((v >> 1) & SIMD::UInt(0x55555555)) | ((v & SIMD::UInt(0x55555555)) << 1);
197 				v = ((v >> 2) & SIMD::UInt(0x33333333)) | ((v & SIMD::UInt(0x33333333)) << 2);
198 				v = ((v >> 4) & SIMD::UInt(0x0F0F0F0F)) | ((v & SIMD::UInt(0x0F0F0F0F)) << 4);
199 				v = ((v >> 8) & SIMD::UInt(0x00FF00FF)) | ((v & SIMD::UInt(0x00FF00FF)) << 8);
200 				v = (v >> 16) | (v << 16);
201 				dst.move(i, v);
202 				break;
203 			}
204 			case spv::OpBitCount:
205 				dst.move(i, CountBits(src.UInt(i)));
206 				break;
207 			case spv::OpSNegate:
208 				dst.move(i, -src.Int(i));
209 				break;
210 			case spv::OpFNegate:
211 				dst.move(i, -src.Float(i));
212 				break;
213 			case spv::OpConvertFToU:
214 				dst.move(i, SIMD::UInt(src.Float(i)));
215 				break;
216 			case spv::OpConvertFToS:
217 				dst.move(i, SIMD::Int(src.Float(i)));
218 				break;
219 			case spv::OpConvertSToF:
220 				dst.move(i, SIMD::Float(src.Int(i)));
221 				break;
222 			case spv::OpConvertUToF:
223 				dst.move(i, SIMD::Float(src.UInt(i)));
224 				break;
225 			case spv::OpBitcast:
226 				dst.move(i, src.Float(i));
227 				break;
228 			case spv::OpIsInf:
229 				dst.move(i, IsInf(src.Float(i)));
230 				break;
231 			case spv::OpIsNan:
232 				dst.move(i, IsNan(src.Float(i)));
233 				break;
234 			case spv::OpDPdx:
235 			case spv::OpDPdxCoarse:
236 				// Derivative instructions: FS invocations are laid out like so:
237 				//    0 1
238 				//    2 3
239 				static_assert(SIMD::Width == 4, "All cross-lane instructions will need care when using a different width");
240 				dst.move(i, SIMD::Float(Extract(src.Float(i), 1) - Extract(src.Float(i), 0)));
241 				break;
242 			case spv::OpDPdy:
243 			case spv::OpDPdyCoarse:
244 				dst.move(i, SIMD::Float(Extract(src.Float(i), 2) - Extract(src.Float(i), 0)));
245 				break;
246 			case spv::OpFwidth:
247 			case spv::OpFwidthCoarse:
248 				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))));
249 				break;
250 			case spv::OpDPdxFine:
251 			{
252 				auto firstRow = Extract(src.Float(i), 1) - Extract(src.Float(i), 0);
253 				auto secondRow = Extract(src.Float(i), 3) - Extract(src.Float(i), 2);
254 				SIMD::Float v = SIMD::Float(firstRow);
255 				v = Insert(v, secondRow, 2);
256 				v = Insert(v, secondRow, 3);
257 				dst.move(i, v);
258 				break;
259 			}
260 			case spv::OpDPdyFine:
261 			{
262 				auto firstColumn = Extract(src.Float(i), 2) - Extract(src.Float(i), 0);
263 				auto secondColumn = Extract(src.Float(i), 3) - Extract(src.Float(i), 1);
264 				SIMD::Float v = SIMD::Float(firstColumn);
265 				v = Insert(v, secondColumn, 1);
266 				v = Insert(v, secondColumn, 3);
267 				dst.move(i, v);
268 				break;
269 			}
270 			case spv::OpFwidthFine:
271 			{
272 				auto firstRow = Extract(src.Float(i), 1) - Extract(src.Float(i), 0);
273 				auto secondRow = Extract(src.Float(i), 3) - Extract(src.Float(i), 2);
274 				SIMD::Float dpdx = SIMD::Float(firstRow);
275 				dpdx = Insert(dpdx, secondRow, 2);
276 				dpdx = Insert(dpdx, secondRow, 3);
277 				auto firstColumn = Extract(src.Float(i), 2) - Extract(src.Float(i), 0);
278 				auto secondColumn = Extract(src.Float(i), 3) - Extract(src.Float(i), 1);
279 				SIMD::Float dpdy = SIMD::Float(firstColumn);
280 				dpdy = Insert(dpdy, secondColumn, 1);
281 				dpdy = Insert(dpdy, secondColumn, 3);
282 				dst.move(i, Abs(dpdx) + Abs(dpdy));
283 				break;
284 			}
285 			case spv::OpQuantizeToF16:
286 			{
287 				// Note: keep in sync with the specialization constant version in EvalSpecConstantUnaryOp
288 				auto abs = Abs(src.Float(i));
289 				auto sign = src.Int(i) & SIMD::Int(0x80000000);
290 				auto isZero = CmpLT(abs, SIMD::Float(0.000061035f));
291 				auto isInf = CmpGT(abs, SIMD::Float(65504.0f));
292 				auto isNaN = IsNan(abs);
293 				auto isInfOrNan = isInf | isNaN;
294 				SIMD::Int v = src.Int(i) & SIMD::Int(0xFFFFE000);
295 				v &= ~isZero | SIMD::Int(0x80000000);
296 				v = sign | (isInfOrNan & SIMD::Int(0x7F800000)) | (~isInfOrNan & v);
297 				v |= isNaN & SIMD::Int(0x400000);
298 				dst.move(i, v);
299 				break;
300 			}
301 			default:
302 				UNREACHABLE("%s", OpcodeName(insn.opcode()));
303 		}
304 	}
305 
306 	return EmitResult::Continue;
307 }
308 
EmitBinaryOp(InsnIterator insn,EmitState * state) const309 SpirvShader::EmitResult SpirvShader::EmitBinaryOp(InsnIterator insn, EmitState *state) const
310 {
311 	auto &type = getType(insn.resultTypeId());
312 	auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
313 	auto &lhsType = getType(getObject(insn.word(3)));
314 	auto lhs = Operand(this, state, insn.word(3));
315 	auto rhs = Operand(this, state, insn.word(4));
316 
317 	for(auto i = 0u; i < lhsType.componentCount; i++)
318 	{
319 		switch(insn.opcode())
320 		{
321 			case spv::OpIAdd:
322 				dst.move(i, lhs.Int(i) + rhs.Int(i));
323 				break;
324 			case spv::OpISub:
325 				dst.move(i, lhs.Int(i) - rhs.Int(i));
326 				break;
327 			case spv::OpIMul:
328 				dst.move(i, lhs.Int(i) * rhs.Int(i));
329 				break;
330 			case spv::OpSDiv:
331 			{
332 				SIMD::Int a = lhs.Int(i);
333 				SIMD::Int b = rhs.Int(i);
334 				b = b | CmpEQ(b, SIMD::Int(0));                                       // prevent divide-by-zero
335 				a = a | (CmpEQ(a, SIMD::Int(0x80000000)) & CmpEQ(b, SIMD::Int(-1)));  // prevent integer overflow
336 				dst.move(i, a / b);
337 				break;
338 			}
339 			case spv::OpUDiv:
340 			{
341 				auto zeroMask = As<SIMD::UInt>(CmpEQ(rhs.Int(i), SIMD::Int(0)));
342 				dst.move(i, lhs.UInt(i) / (rhs.UInt(i) | zeroMask));
343 				break;
344 			}
345 			case spv::OpSRem:
346 			{
347 				SIMD::Int a = lhs.Int(i);
348 				SIMD::Int b = rhs.Int(i);
349 				b = b | CmpEQ(b, SIMD::Int(0));                                       // prevent divide-by-zero
350 				a = a | (CmpEQ(a, SIMD::Int(0x80000000)) & CmpEQ(b, SIMD::Int(-1)));  // prevent integer overflow
351 				dst.move(i, a % b);
352 				break;
353 			}
354 			case spv::OpSMod:
355 			{
356 				SIMD::Int a = lhs.Int(i);
357 				SIMD::Int b = rhs.Int(i);
358 				b = b | CmpEQ(b, SIMD::Int(0));                                       // prevent divide-by-zero
359 				a = a | (CmpEQ(a, SIMD::Int(0x80000000)) & CmpEQ(b, SIMD::Int(-1)));  // prevent integer overflow
360 				auto mod = a % b;
361 				// If a and b have opposite signs, the remainder operation takes
362 				// the sign from a but OpSMod is supposed to take the sign of b.
363 				// Adding b will ensure that the result has the correct sign and
364 				// that it is still congruent to a modulo b.
365 				//
366 				// See also http://mathforum.org/library/drmath/view/52343.html
367 				auto signDiff = CmpNEQ(CmpGE(a, SIMD::Int(0)), CmpGE(b, SIMD::Int(0)));
368 				auto fixedMod = mod + (b & CmpNEQ(mod, SIMD::Int(0)) & signDiff);
369 				dst.move(i, As<SIMD::Float>(fixedMod));
370 				break;
371 			}
372 			case spv::OpUMod:
373 			{
374 				auto zeroMask = As<SIMD::UInt>(CmpEQ(rhs.Int(i), SIMD::Int(0)));
375 				dst.move(i, lhs.UInt(i) % (rhs.UInt(i) | zeroMask));
376 				break;
377 			}
378 			case spv::OpIEqual:
379 			case spv::OpLogicalEqual:
380 				dst.move(i, CmpEQ(lhs.Int(i), rhs.Int(i)));
381 				break;
382 			case spv::OpINotEqual:
383 			case spv::OpLogicalNotEqual:
384 				dst.move(i, CmpNEQ(lhs.Int(i), rhs.Int(i)));
385 				break;
386 			case spv::OpUGreaterThan:
387 				dst.move(i, CmpGT(lhs.UInt(i), rhs.UInt(i)));
388 				break;
389 			case spv::OpSGreaterThan:
390 				dst.move(i, CmpGT(lhs.Int(i), rhs.Int(i)));
391 				break;
392 			case spv::OpUGreaterThanEqual:
393 				dst.move(i, CmpGE(lhs.UInt(i), rhs.UInt(i)));
394 				break;
395 			case spv::OpSGreaterThanEqual:
396 				dst.move(i, CmpGE(lhs.Int(i), rhs.Int(i)));
397 				break;
398 			case spv::OpULessThan:
399 				dst.move(i, CmpLT(lhs.UInt(i), rhs.UInt(i)));
400 				break;
401 			case spv::OpSLessThan:
402 				dst.move(i, CmpLT(lhs.Int(i), rhs.Int(i)));
403 				break;
404 			case spv::OpULessThanEqual:
405 				dst.move(i, CmpLE(lhs.UInt(i), rhs.UInt(i)));
406 				break;
407 			case spv::OpSLessThanEqual:
408 				dst.move(i, CmpLE(lhs.Int(i), rhs.Int(i)));
409 				break;
410 			case spv::OpFAdd:
411 				dst.move(i, lhs.Float(i) + rhs.Float(i));
412 				break;
413 			case spv::OpFSub:
414 				dst.move(i, lhs.Float(i) - rhs.Float(i));
415 				break;
416 			case spv::OpFMul:
417 				dst.move(i, lhs.Float(i) * rhs.Float(i));
418 				break;
419 			case spv::OpFDiv:
420 				dst.move(i, lhs.Float(i) / rhs.Float(i));
421 				break;
422 			case spv::OpFMod:
423 				// TODO(b/126873455): inaccurate for values greater than 2^24
424 				dst.move(i, lhs.Float(i) - rhs.Float(i) * Floor(lhs.Float(i) / rhs.Float(i)));
425 				break;
426 			case spv::OpFRem:
427 				dst.move(i, lhs.Float(i) % rhs.Float(i));
428 				break;
429 			case spv::OpFOrdEqual:
430 				dst.move(i, CmpEQ(lhs.Float(i), rhs.Float(i)));
431 				break;
432 			case spv::OpFUnordEqual:
433 				dst.move(i, CmpUEQ(lhs.Float(i), rhs.Float(i)));
434 				break;
435 			case spv::OpFOrdNotEqual:
436 				dst.move(i, CmpNEQ(lhs.Float(i), rhs.Float(i)));
437 				break;
438 			case spv::OpFUnordNotEqual:
439 				dst.move(i, CmpUNEQ(lhs.Float(i), rhs.Float(i)));
440 				break;
441 			case spv::OpFOrdLessThan:
442 				dst.move(i, CmpLT(lhs.Float(i), rhs.Float(i)));
443 				break;
444 			case spv::OpFUnordLessThan:
445 				dst.move(i, CmpULT(lhs.Float(i), rhs.Float(i)));
446 				break;
447 			case spv::OpFOrdGreaterThan:
448 				dst.move(i, CmpGT(lhs.Float(i), rhs.Float(i)));
449 				break;
450 			case spv::OpFUnordGreaterThan:
451 				dst.move(i, CmpUGT(lhs.Float(i), rhs.Float(i)));
452 				break;
453 			case spv::OpFOrdLessThanEqual:
454 				dst.move(i, CmpLE(lhs.Float(i), rhs.Float(i)));
455 				break;
456 			case spv::OpFUnordLessThanEqual:
457 				dst.move(i, CmpULE(lhs.Float(i), rhs.Float(i)));
458 				break;
459 			case spv::OpFOrdGreaterThanEqual:
460 				dst.move(i, CmpGE(lhs.Float(i), rhs.Float(i)));
461 				break;
462 			case spv::OpFUnordGreaterThanEqual:
463 				dst.move(i, CmpUGE(lhs.Float(i), rhs.Float(i)));
464 				break;
465 			case spv::OpShiftRightLogical:
466 				dst.move(i, lhs.UInt(i) >> rhs.UInt(i));
467 				break;
468 			case spv::OpShiftRightArithmetic:
469 				dst.move(i, lhs.Int(i) >> rhs.Int(i));
470 				break;
471 			case spv::OpShiftLeftLogical:
472 				dst.move(i, lhs.UInt(i) << rhs.UInt(i));
473 				break;
474 			case spv::OpBitwiseOr:
475 			case spv::OpLogicalOr:
476 				dst.move(i, lhs.UInt(i) | rhs.UInt(i));
477 				break;
478 			case spv::OpBitwiseXor:
479 				dst.move(i, lhs.UInt(i) ^ rhs.UInt(i));
480 				break;
481 			case spv::OpBitwiseAnd:
482 			case spv::OpLogicalAnd:
483 				dst.move(i, lhs.UInt(i) & rhs.UInt(i));
484 				break;
485 			case spv::OpSMulExtended:
486 				// Extended ops: result is a structure containing two members of the same type as lhs & rhs.
487 				// In our flat view then, component i is the i'th component of the first member;
488 				// component i + N is the i'th component of the second member.
489 				dst.move(i, lhs.Int(i) * rhs.Int(i));
490 				dst.move(i + lhsType.componentCount, MulHigh(lhs.Int(i), rhs.Int(i)));
491 				break;
492 			case spv::OpUMulExtended:
493 				dst.move(i, lhs.UInt(i) * rhs.UInt(i));
494 				dst.move(i + lhsType.componentCount, MulHigh(lhs.UInt(i), rhs.UInt(i)));
495 				break;
496 			case spv::OpIAddCarry:
497 				dst.move(i, lhs.UInt(i) + rhs.UInt(i));
498 				dst.move(i + lhsType.componentCount, CmpLT(dst.UInt(i), lhs.UInt(i)) >> 31);
499 				break;
500 			case spv::OpISubBorrow:
501 				dst.move(i, lhs.UInt(i) - rhs.UInt(i));
502 				dst.move(i + lhsType.componentCount, CmpLT(lhs.UInt(i), rhs.UInt(i)) >> 31);
503 				break;
504 			default:
505 				UNREACHABLE("%s", OpcodeName(insn.opcode()));
506 		}
507 	}
508 
509 	SPIRV_SHADER_DBG("{0}: {1}", insn.word(2), dst);
510 	SPIRV_SHADER_DBG("{0}: {1}", insn.word(3), lhs);
511 	SPIRV_SHADER_DBG("{0}: {1}", insn.word(4), rhs);
512 
513 	return EmitResult::Continue;
514 }
515 
EmitDot(InsnIterator insn,EmitState * state) const516 SpirvShader::EmitResult SpirvShader::EmitDot(InsnIterator insn, EmitState *state) const
517 {
518 	auto &type = getType(insn.resultTypeId());
519 	ASSERT(type.componentCount == 1);
520 	auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
521 	auto &lhsType = getType(getObject(insn.word(3)));
522 	auto lhs = Operand(this, state, insn.word(3));
523 	auto rhs = Operand(this, state, insn.word(4));
524 
525 	dst.move(0, Dot(lhsType.componentCount, lhs, rhs));
526 
527 	SPIRV_SHADER_DBG("{0}: {1}", insn.resultId(), dst);
528 	SPIRV_SHADER_DBG("{0}: {1}", insn.word(3), lhs);
529 	SPIRV_SHADER_DBG("{0}: {1}", insn.word(4), rhs);
530 
531 	return EmitResult::Continue;
532 }
533 
Dot(unsigned numComponents,Operand const & x,Operand const & y) const534 SIMD::Float SpirvShader::Dot(unsigned numComponents, Operand const &x, Operand const &y) const
535 {
536 	SIMD::Float d = x.Float(0) * y.Float(0);
537 
538 	for(auto i = 1u; i < numComponents; i++)
539 	{
540 		d += x.Float(i) * y.Float(i);
541 	}
542 
543 	return d;
544 }
545 
Frexp(RValue<SIMD::Float> val) const546 std::pair<SIMD::Float, SIMD::Int> SpirvShader::Frexp(RValue<SIMD::Float> val) const
547 {
548 	// Assumes IEEE 754
549 	auto v = As<SIMD::UInt>(val);
550 	auto isNotZero = CmpNEQ(v & SIMD::UInt(0x7FFFFFFF), SIMD::UInt(0));
551 	auto zeroSign = v & SIMD::UInt(0x80000000) & ~isNotZero;
552 	auto significand = As<SIMD::Float>((((v & SIMD::UInt(0x807FFFFF)) | SIMD::UInt(0x3F000000)) & isNotZero) | zeroSign);
553 	auto exponent = Exponent(val) & SIMD::Int(isNotZero);
554 	return std::make_pair(significand, exponent);
555 }
556 
557 }  // namespace sw