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 
17 #include "ShaderCore.hpp"
18 
19 #include <spirv/unified1/GLSL.std.450.h>
20 #include <spirv/unified1/spirv.hpp>
21 
22 namespace {
23 constexpr float PI = 3.141592653589793f;
24 }
25 
26 namespace sw {
27 
EmitExtGLSLstd450(InsnIterator insn,EmitState * state) const28 SpirvShader::EmitResult SpirvShader::EmitExtGLSLstd450(InsnIterator insn, EmitState *state) const
29 {
30 	auto &type = getType(insn.word(1));
31 	auto &dst = state->createIntermediate(insn.word(2), type.sizeInComponents);
32 	auto extInstIndex = static_cast<GLSLstd450>(insn.word(4));
33 
34 	switch(extInstIndex)
35 	{
36 		case GLSLstd450FAbs:
37 		{
38 			auto src = GenericValue(this, state, insn.word(5));
39 			for(auto i = 0u; i < type.sizeInComponents; i++)
40 			{
41 				dst.move(i, Abs(src.Float(i)));
42 			}
43 			break;
44 		}
45 		case GLSLstd450SAbs:
46 		{
47 			auto src = GenericValue(this, state, insn.word(5));
48 			for(auto i = 0u; i < type.sizeInComponents; i++)
49 			{
50 				dst.move(i, Abs(src.Int(i)));
51 			}
52 			break;
53 		}
54 		case GLSLstd450Cross:
55 		{
56 			auto lhs = GenericValue(this, state, insn.word(5));
57 			auto rhs = GenericValue(this, state, insn.word(6));
58 			dst.move(0, lhs.Float(1) * rhs.Float(2) - rhs.Float(1) * lhs.Float(2));
59 			dst.move(1, lhs.Float(2) * rhs.Float(0) - rhs.Float(2) * lhs.Float(0));
60 			dst.move(2, lhs.Float(0) * rhs.Float(1) - rhs.Float(0) * lhs.Float(1));
61 			break;
62 		}
63 		case GLSLstd450Floor:
64 		{
65 			auto src = GenericValue(this, state, insn.word(5));
66 			for(auto i = 0u; i < type.sizeInComponents; i++)
67 			{
68 				dst.move(i, Floor(src.Float(i)));
69 			}
70 			break;
71 		}
72 		case GLSLstd450Trunc:
73 		{
74 			auto src = GenericValue(this, state, insn.word(5));
75 			for(auto i = 0u; i < type.sizeInComponents; i++)
76 			{
77 				dst.move(i, Trunc(src.Float(i)));
78 			}
79 			break;
80 		}
81 		case GLSLstd450Ceil:
82 		{
83 			auto src = GenericValue(this, state, insn.word(5));
84 			for(auto i = 0u; i < type.sizeInComponents; i++)
85 			{
86 				dst.move(i, Ceil(src.Float(i)));
87 			}
88 			break;
89 		}
90 		case GLSLstd450Fract:
91 		{
92 			auto src = GenericValue(this, state, insn.word(5));
93 			for(auto i = 0u; i < type.sizeInComponents; i++)
94 			{
95 				dst.move(i, Frac(src.Float(i)));
96 			}
97 			break;
98 		}
99 		case GLSLstd450Round:
100 		{
101 			auto src = GenericValue(this, state, insn.word(5));
102 			for(auto i = 0u; i < type.sizeInComponents; i++)
103 			{
104 				dst.move(i, Round(src.Float(i)));
105 			}
106 			break;
107 		}
108 		case GLSLstd450RoundEven:
109 		{
110 			auto src = GenericValue(this, state, insn.word(5));
111 			for(auto i = 0u; i < type.sizeInComponents; i++)
112 			{
113 				auto x = Round(src.Float(i));
114 				// dst = round(src) + ((round(src) < src) * 2 - 1) * (fract(src) == 0.5) * isOdd(round(src));
115 				dst.move(i, x + ((SIMD::Float(CmpLT(x, src.Float(i)) & SIMD::Int(1)) * SIMD::Float(2.0f)) - SIMD::Float(1.0f)) *
116 				                    SIMD::Float(CmpEQ(Frac(src.Float(i)), SIMD::Float(0.5f)) & SIMD::Int(1)) * SIMD::Float(Int4(x) & SIMD::Int(1)));
117 			}
118 			break;
119 		}
120 		case GLSLstd450FMin:
121 		{
122 			auto lhs = GenericValue(this, state, insn.word(5));
123 			auto rhs = GenericValue(this, state, insn.word(6));
124 			for(auto i = 0u; i < type.sizeInComponents; i++)
125 			{
126 				dst.move(i, Min(lhs.Float(i), rhs.Float(i)));
127 			}
128 			break;
129 		}
130 		case GLSLstd450FMax:
131 		{
132 			auto lhs = GenericValue(this, state, insn.word(5));
133 			auto rhs = GenericValue(this, state, insn.word(6));
134 			for(auto i = 0u; i < type.sizeInComponents; i++)
135 			{
136 				dst.move(i, Max(lhs.Float(i), rhs.Float(i)));
137 			}
138 			break;
139 		}
140 		case GLSLstd450SMin:
141 		{
142 			auto lhs = GenericValue(this, state, insn.word(5));
143 			auto rhs = GenericValue(this, state, insn.word(6));
144 			for(auto i = 0u; i < type.sizeInComponents; i++)
145 			{
146 				dst.move(i, Min(lhs.Int(i), rhs.Int(i)));
147 			}
148 			break;
149 		}
150 		case GLSLstd450SMax:
151 		{
152 			auto lhs = GenericValue(this, state, insn.word(5));
153 			auto rhs = GenericValue(this, state, insn.word(6));
154 			for(auto i = 0u; i < type.sizeInComponents; i++)
155 			{
156 				dst.move(i, Max(lhs.Int(i), rhs.Int(i)));
157 			}
158 			break;
159 		}
160 		case GLSLstd450UMin:
161 		{
162 			auto lhs = GenericValue(this, state, insn.word(5));
163 			auto rhs = GenericValue(this, state, insn.word(6));
164 			for(auto i = 0u; i < type.sizeInComponents; i++)
165 			{
166 				dst.move(i, Min(lhs.UInt(i), rhs.UInt(i)));
167 			}
168 			break;
169 		}
170 		case GLSLstd450UMax:
171 		{
172 			auto lhs = GenericValue(this, state, insn.word(5));
173 			auto rhs = GenericValue(this, state, insn.word(6));
174 			for(auto i = 0u; i < type.sizeInComponents; i++)
175 			{
176 				dst.move(i, Max(lhs.UInt(i), rhs.UInt(i)));
177 			}
178 			break;
179 		}
180 		case GLSLstd450Step:
181 		{
182 			auto edge = GenericValue(this, state, insn.word(5));
183 			auto x = GenericValue(this, state, insn.word(6));
184 			for(auto i = 0u; i < type.sizeInComponents; i++)
185 			{
186 				dst.move(i, CmpNLT(x.Float(i), edge.Float(i)) & As<SIMD::Int>(SIMD::Float(1.0f)));
187 			}
188 			break;
189 		}
190 		case GLSLstd450SmoothStep:
191 		{
192 			auto edge0 = GenericValue(this, state, insn.word(5));
193 			auto edge1 = GenericValue(this, state, insn.word(6));
194 			auto x = GenericValue(this, state, insn.word(7));
195 			for(auto i = 0u; i < type.sizeInComponents; i++)
196 			{
197 				auto tx = Min(Max((x.Float(i) - edge0.Float(i)) /
198 				                      (edge1.Float(i) - edge0.Float(i)),
199 				                  SIMD::Float(0.0f)),
200 				              SIMD::Float(1.0f));
201 				dst.move(i, tx * tx * (Float4(3.0f) - Float4(2.0f) * tx));
202 			}
203 			break;
204 		}
205 		case GLSLstd450FMix:
206 		{
207 			auto x = GenericValue(this, state, insn.word(5));
208 			auto y = GenericValue(this, state, insn.word(6));
209 			auto a = GenericValue(this, state, insn.word(7));
210 			for(auto i = 0u; i < type.sizeInComponents; i++)
211 			{
212 				dst.move(i, a.Float(i) * (y.Float(i) - x.Float(i)) + x.Float(i));
213 			}
214 			break;
215 		}
216 		case GLSLstd450FClamp:
217 		{
218 			auto x = GenericValue(this, state, insn.word(5));
219 			auto minVal = GenericValue(this, state, insn.word(6));
220 			auto maxVal = GenericValue(this, state, insn.word(7));
221 			for(auto i = 0u; i < type.sizeInComponents; i++)
222 			{
223 				dst.move(i, Min(Max(x.Float(i), minVal.Float(i)), maxVal.Float(i)));
224 			}
225 			break;
226 		}
227 		case GLSLstd450SClamp:
228 		{
229 			auto x = GenericValue(this, state, insn.word(5));
230 			auto minVal = GenericValue(this, state, insn.word(6));
231 			auto maxVal = GenericValue(this, state, insn.word(7));
232 			for(auto i = 0u; i < type.sizeInComponents; i++)
233 			{
234 				dst.move(i, Min(Max(x.Int(i), minVal.Int(i)), maxVal.Int(i)));
235 			}
236 			break;
237 		}
238 		case GLSLstd450UClamp:
239 		{
240 			auto x = GenericValue(this, state, insn.word(5));
241 			auto minVal = GenericValue(this, state, insn.word(6));
242 			auto maxVal = GenericValue(this, state, insn.word(7));
243 			for(auto i = 0u; i < type.sizeInComponents; i++)
244 			{
245 				dst.move(i, Min(Max(x.UInt(i), minVal.UInt(i)), maxVal.UInt(i)));
246 			}
247 			break;
248 		}
249 		case GLSLstd450FSign:
250 		{
251 			auto src = GenericValue(this, state, insn.word(5));
252 			for(auto i = 0u; i < type.sizeInComponents; i++)
253 			{
254 				auto neg = As<SIMD::Int>(CmpLT(src.Float(i), SIMD::Float(-0.0f))) & As<SIMD::Int>(SIMD::Float(-1.0f));
255 				auto pos = As<SIMD::Int>(CmpNLE(src.Float(i), SIMD::Float(+0.0f))) & As<SIMD::Int>(SIMD::Float(1.0f));
256 				dst.move(i, neg | pos);
257 			}
258 			break;
259 		}
260 		case GLSLstd450SSign:
261 		{
262 			auto src = GenericValue(this, state, insn.word(5));
263 			for(auto i = 0u; i < type.sizeInComponents; i++)
264 			{
265 				auto neg = CmpLT(src.Int(i), SIMD::Int(0)) & SIMD::Int(-1);
266 				auto pos = CmpNLE(src.Int(i), SIMD::Int(0)) & SIMD::Int(1);
267 				dst.move(i, neg | pos);
268 			}
269 			break;
270 		}
271 		case GLSLstd450Reflect:
272 		{
273 			auto I = GenericValue(this, state, insn.word(5));
274 			auto N = GenericValue(this, state, insn.word(6));
275 
276 			SIMD::Float d = Dot(type.sizeInComponents, I, N);
277 
278 			for(auto i = 0u; i < type.sizeInComponents; i++)
279 			{
280 				dst.move(i, I.Float(i) - SIMD::Float(2.0f) * d * N.Float(i));
281 			}
282 			break;
283 		}
284 		case GLSLstd450Refract:
285 		{
286 			auto I = GenericValue(this, state, insn.word(5));
287 			auto N = GenericValue(this, state, insn.word(6));
288 			auto eta = GenericValue(this, state, insn.word(7));
289 
290 			SIMD::Float d = Dot(type.sizeInComponents, I, N);
291 			SIMD::Float k = SIMD::Float(1.0f) - eta.Float(0) * eta.Float(0) * (SIMD::Float(1.0f) - d * d);
292 			SIMD::Int pos = CmpNLT(k, SIMD::Float(0.0f));
293 			SIMD::Float t = (eta.Float(0) * d + Sqrt(k));
294 
295 			for(auto i = 0u; i < type.sizeInComponents; i++)
296 			{
297 				dst.move(i, pos & As<SIMD::Int>(eta.Float(0) * I.Float(i) - t * N.Float(i)));
298 			}
299 			break;
300 		}
301 		case GLSLstd450FaceForward:
302 		{
303 			auto N = GenericValue(this, state, insn.word(5));
304 			auto I = GenericValue(this, state, insn.word(6));
305 			auto Nref = GenericValue(this, state, insn.word(7));
306 
307 			SIMD::Float d = Dot(type.sizeInComponents, I, Nref);
308 			SIMD::Int neg = CmpLT(d, SIMD::Float(0.0f));
309 
310 			for(auto i = 0u; i < type.sizeInComponents; i++)
311 			{
312 				auto n = N.Float(i);
313 				dst.move(i, (neg & As<SIMD::Int>(n)) | (~neg & As<SIMD::Int>(-n)));
314 			}
315 			break;
316 		}
317 		case GLSLstd450Length:
318 		{
319 			auto x = GenericValue(this, state, insn.word(5));
320 			SIMD::Float d = Dot(getType(getObject(insn.word(5)).type).sizeInComponents, x, x);
321 
322 			dst.move(0, Sqrt(d));
323 			break;
324 		}
325 		case GLSLstd450Normalize:
326 		{
327 			auto x = GenericValue(this, state, insn.word(5));
328 			SIMD::Float d = Dot(getType(getObject(insn.word(5)).type).sizeInComponents, x, x);
329 			SIMD::Float invLength = SIMD::Float(1.0f) / Sqrt(d);
330 
331 			for(auto i = 0u; i < type.sizeInComponents; i++)
332 			{
333 				dst.move(i, invLength * x.Float(i));
334 			}
335 			break;
336 		}
337 		case GLSLstd450Distance:
338 		{
339 			auto p0 = GenericValue(this, state, insn.word(5));
340 			auto p1 = GenericValue(this, state, insn.word(6));
341 			auto p0Type = getType(p0.type);
342 
343 			// sqrt(dot(p0-p1, p0-p1))
344 			SIMD::Float d = (p0.Float(0) - p1.Float(0)) * (p0.Float(0) - p1.Float(0));
345 
346 			for(auto i = 1u; i < p0Type.sizeInComponents; i++)
347 			{
348 				d += (p0.Float(i) - p1.Float(i)) * (p0.Float(i) - p1.Float(i));
349 			}
350 
351 			dst.move(0, Sqrt(d));
352 			break;
353 		}
354 		case GLSLstd450Modf:
355 		{
356 			auto val = GenericValue(this, state, insn.word(5));
357 			auto ptrId = Object::ID(insn.word(6));
358 			auto ptrTy = getType(getObject(ptrId).type);
359 			auto ptr = GetPointerToData(ptrId, 0, state);
360 			bool interleavedByLane = IsStorageInterleavedByLane(ptrTy.storageClass);
361 			// TODO: GLSL modf() takes an output parameter and thus the pointer is assumed
362 			// to be in bounds even for inactive lanes.
363 			// - Clarify the SPIR-V spec.
364 			// - Eliminate lane masking and assume interleaving.
365 			auto robustness = OutOfBoundsBehavior::UndefinedBehavior;
366 
367 			for(auto i = 0u; i < type.sizeInComponents; i++)
368 			{
369 				SIMD::Float whole, frac;
370 				std::tie(whole, frac) = Modf(val.Float(i));
371 				dst.move(i, frac);
372 				auto p = ptr + (i * sizeof(float));
373 				if(interleavedByLane) { p = InterleaveByLane(p); }
374 				p.Store(whole, robustness, state->activeLaneMask());
375 			}
376 			break;
377 		}
378 		case GLSLstd450ModfStruct:
379 		{
380 			auto val = GenericValue(this, state, insn.word(5));
381 			auto valTy = getType(val.type);
382 
383 			for(auto i = 0u; i < valTy.sizeInComponents; i++)
384 			{
385 				SIMD::Float whole, frac;
386 				std::tie(whole, frac) = Modf(val.Float(i));
387 				dst.move(i, frac);
388 				dst.move(i + valTy.sizeInComponents, whole);
389 			}
390 			break;
391 		}
392 		case GLSLstd450PackSnorm4x8:
393 		{
394 			auto val = GenericValue(this, state, insn.word(5));
395 			dst.move(0, (SIMD::Int(Round(Min(Max(val.Float(0), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(127.0f))) &
396 			             SIMD::Int(0xFF)) |
397 			                ((SIMD::Int(Round(Min(Max(val.Float(1), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(127.0f))) &
398 			                  SIMD::Int(0xFF))
399 			                 << 8) |
400 			                ((SIMD::Int(Round(Min(Max(val.Float(2), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(127.0f))) &
401 			                  SIMD::Int(0xFF))
402 			                 << 16) |
403 			                ((SIMD::Int(Round(Min(Max(val.Float(3), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(127.0f))) &
404 			                  SIMD::Int(0xFF))
405 			                 << 24));
406 			break;
407 		}
408 		case GLSLstd450PackUnorm4x8:
409 		{
410 			auto val = GenericValue(this, state, insn.word(5));
411 			dst.move(0, (SIMD::UInt(Round(Min(Max(val.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) |
412 			                ((SIMD::UInt(Round(Min(Max(val.Float(1), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) << 8) |
413 			                ((SIMD::UInt(Round(Min(Max(val.Float(2), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) << 16) |
414 			                ((SIMD::UInt(Round(Min(Max(val.Float(3), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) << 24));
415 			break;
416 		}
417 		case GLSLstd450PackSnorm2x16:
418 		{
419 			auto val = GenericValue(this, state, insn.word(5));
420 			dst.move(0, (SIMD::Int(Round(Min(Max(val.Float(0), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(32767.0f))) &
421 			             SIMD::Int(0xFFFF)) |
422 			                ((SIMD::Int(Round(Min(Max(val.Float(1), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(32767.0f))) &
423 			                  SIMD::Int(0xFFFF))
424 			                 << 16));
425 			break;
426 		}
427 		case GLSLstd450PackUnorm2x16:
428 		{
429 			auto val = GenericValue(this, state, insn.word(5));
430 			dst.move(0, (SIMD::UInt(Round(Min(Max(val.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(65535.0f))) &
431 			             SIMD::UInt(0xFFFF)) |
432 			                ((SIMD::UInt(Round(Min(Max(val.Float(1), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(65535.0f))) &
433 			                  SIMD::UInt(0xFFFF))
434 			                 << 16));
435 			break;
436 		}
437 		case GLSLstd450PackHalf2x16:
438 		{
439 			auto val = GenericValue(this, state, insn.word(5));
440 			dst.move(0, floatToHalfBits(val.UInt(0), false) | floatToHalfBits(val.UInt(1), true));
441 			break;
442 		}
443 		case GLSLstd450UnpackSnorm4x8:
444 		{
445 			auto val = GenericValue(this, state, insn.word(5));
446 			dst.move(0, Min(Max(SIMD::Float(((val.Int(0) << 24) & SIMD::Int(0xFF000000))) * SIMD::Float(1.0f / float(0x7f000000)), SIMD::Float(-1.0f)), SIMD::Float(1.0f)));
447 			dst.move(1, Min(Max(SIMD::Float(((val.Int(0) << 16) & SIMD::Int(0xFF000000))) * SIMD::Float(1.0f / float(0x7f000000)), SIMD::Float(-1.0f)), SIMD::Float(1.0f)));
448 			dst.move(2, Min(Max(SIMD::Float(((val.Int(0) << 8) & SIMD::Int(0xFF000000))) * SIMD::Float(1.0f / float(0x7f000000)), SIMD::Float(-1.0f)), SIMD::Float(1.0f)));
449 			dst.move(3, Min(Max(SIMD::Float(((val.Int(0)) & SIMD::Int(0xFF000000))) * SIMD::Float(1.0f / float(0x7f000000)), SIMD::Float(-1.0f)), SIMD::Float(1.0f)));
450 			break;
451 		}
452 		case GLSLstd450UnpackUnorm4x8:
453 		{
454 			auto val = GenericValue(this, state, insn.word(5));
455 			dst.move(0, SIMD::Float((val.UInt(0) & SIMD::UInt(0xFF))) * SIMD::Float(1.0f / 255.f));
456 			dst.move(1, SIMD::Float(((val.UInt(0) >> 8) & SIMD::UInt(0xFF))) * SIMD::Float(1.0f / 255.f));
457 			dst.move(2, SIMD::Float(((val.UInt(0) >> 16) & SIMD::UInt(0xFF))) * SIMD::Float(1.0f / 255.f));
458 			dst.move(3, SIMD::Float(((val.UInt(0) >> 24) & SIMD::UInt(0xFF))) * SIMD::Float(1.0f / 255.f));
459 			break;
460 		}
461 		case GLSLstd450UnpackSnorm2x16:
462 		{
463 			auto val = GenericValue(this, state, insn.word(5));
464 			// clamp(f / 32767.0, -1.0, 1.0)
465 			dst.move(0, Min(Max(SIMD::Float(As<SIMD::Int>((val.UInt(0) & SIMD::UInt(0x0000FFFF)) << 16)) *
466 			                        SIMD::Float(1.0f / float(0x7FFF0000)),
467 			                    SIMD::Float(-1.0f)),
468 			                SIMD::Float(1.0f)));
469 			dst.move(1, Min(Max(SIMD::Float(As<SIMD::Int>(val.UInt(0) & SIMD::UInt(0xFFFF0000))) * SIMD::Float(1.0f / float(0x7FFF0000)),
470 			                    SIMD::Float(-1.0f)),
471 			                SIMD::Float(1.0f)));
472 			break;
473 		}
474 		case GLSLstd450UnpackUnorm2x16:
475 		{
476 			auto val = GenericValue(this, state, insn.word(5));
477 			// f / 65535.0
478 			dst.move(0, SIMD::Float((val.UInt(0) & SIMD::UInt(0x0000FFFF)) << 16) * SIMD::Float(1.0f / float(0xFFFF0000)));
479 			dst.move(1, SIMD::Float(val.UInt(0) & SIMD::UInt(0xFFFF0000)) * SIMD::Float(1.0f / float(0xFFFF0000)));
480 			break;
481 		}
482 		case GLSLstd450UnpackHalf2x16:
483 		{
484 			auto val = GenericValue(this, state, insn.word(5));
485 			dst.move(0, halfToFloatBits(val.UInt(0) & SIMD::UInt(0x0000FFFF)));
486 			dst.move(1, halfToFloatBits((val.UInt(0) & SIMD::UInt(0xFFFF0000)) >> 16));
487 			break;
488 		}
489 		case GLSLstd450Fma:
490 		{
491 			auto a = GenericValue(this, state, insn.word(5));
492 			auto b = GenericValue(this, state, insn.word(6));
493 			auto c = GenericValue(this, state, insn.word(7));
494 			for(auto i = 0u; i < type.sizeInComponents; i++)
495 			{
496 				dst.move(i, FMA(a.Float(i), b.Float(i), c.Float(i)));
497 			}
498 			break;
499 		}
500 		case GLSLstd450Frexp:
501 		{
502 			auto val = GenericValue(this, state, insn.word(5));
503 			auto ptrId = Object::ID(insn.word(6));
504 			auto ptrTy = getType(getObject(ptrId).type);
505 			auto ptr = GetPointerToData(ptrId, 0, state);
506 			bool interleavedByLane = IsStorageInterleavedByLane(ptrTy.storageClass);
507 			// TODO: GLSL frexp() takes an output parameter and thus the pointer is assumed
508 			// to be in bounds even for inactive lanes.
509 			// - Clarify the SPIR-V spec.
510 			// - Eliminate lane masking and assume interleaving.
511 			auto robustness = OutOfBoundsBehavior::UndefinedBehavior;
512 
513 			for(auto i = 0u; i < type.sizeInComponents; i++)
514 			{
515 				SIMD::Float significand;
516 				SIMD::Int exponent;
517 				std::tie(significand, exponent) = Frexp(val.Float(i));
518 
519 				dst.move(i, significand);
520 
521 				auto p = ptr + (i * sizeof(float));
522 				if(interleavedByLane) { p = InterleaveByLane(p); }
523 				p.Store(exponent, robustness, state->activeLaneMask());
524 			}
525 			break;
526 		}
527 		case GLSLstd450FrexpStruct:
528 		{
529 			auto val = GenericValue(this, state, insn.word(5));
530 			auto numComponents = getType(val.type).sizeInComponents;
531 			for(auto i = 0u; i < numComponents; i++)
532 			{
533 				auto significandAndExponent = Frexp(val.Float(i));
534 				dst.move(i, significandAndExponent.first);
535 				dst.move(i + numComponents, significandAndExponent.second);
536 			}
537 			break;
538 		}
539 		case GLSLstd450Ldexp:
540 		{
541 			auto significand = GenericValue(this, state, insn.word(5));
542 			auto exponent = GenericValue(this, state, insn.word(6));
543 			for(auto i = 0u; i < type.sizeInComponents; i++)
544 			{
545 				// Assumes IEEE 754
546 				auto in = significand.Float(i);
547 				auto significandExponent = Exponent(in);
548 				auto combinedExponent = exponent.Int(i) + significandExponent;
549 				auto isSignificandZero = SIMD::UInt(CmpEQ(significand.Int(i), SIMD::Int(0)));
550 				auto isSignificandInf = SIMD::UInt(IsInf(in));
551 				auto isSignificandNaN = SIMD::UInt(IsNan(in));
552 				auto isExponentNotTooSmall = SIMD::UInt(CmpGE(combinedExponent, SIMD::Int(-126)));
553 				auto isExponentNotTooLarge = SIMD::UInt(CmpLE(combinedExponent, SIMD::Int(128)));
554 				auto isExponentInBounds = isExponentNotTooSmall & isExponentNotTooLarge;
555 
556 				SIMD::UInt v;
557 				v = significand.UInt(i) & SIMD::UInt(0x7FFFFF);                          // Add significand.
558 				v |= (SIMD::UInt(combinedExponent + SIMD::Int(126)) << SIMD::UInt(23));  // Add exponent.
559 				v &= isExponentInBounds;                                                 // Clear v if the exponent is OOB.
560 
561 				v |= significand.UInt(i) & SIMD::UInt(0x80000000);     // Add sign bit.
562 				v |= ~isExponentNotTooLarge & SIMD::UInt(0x7F800000);  // Mark as inf if the exponent is too great.
563 
564 				// If the input significand is zero, inf or nan, just return the
565 				// input significand.
566 				auto passthrough = isSignificandZero | isSignificandInf | isSignificandNaN;
567 				v = (v & ~passthrough) | (significand.UInt(i) & passthrough);
568 
569 				dst.move(i, As<SIMD::Float>(v));
570 			}
571 			break;
572 		}
573 		case GLSLstd450Radians:
574 		{
575 			auto degrees = GenericValue(this, state, insn.word(5));
576 			for(auto i = 0u; i < type.sizeInComponents; i++)
577 			{
578 				dst.move(i, degrees.Float(i) * SIMD::Float(PI / 180.0f));
579 			}
580 			break;
581 		}
582 		case GLSLstd450Degrees:
583 		{
584 			auto radians = GenericValue(this, state, insn.word(5));
585 			for(auto i = 0u; i < type.sizeInComponents; i++)
586 			{
587 				dst.move(i, radians.Float(i) * SIMD::Float(180.0f / PI));
588 			}
589 			break;
590 		}
591 		case GLSLstd450Sin:
592 		{
593 			auto radians = GenericValue(this, state, insn.word(5));
594 			for(auto i = 0u; i < type.sizeInComponents; i++)
595 			{
596 				dst.move(i, Sin(radians.Float(i)));
597 			}
598 			break;
599 		}
600 		case GLSLstd450Cos:
601 		{
602 			auto radians = GenericValue(this, state, insn.word(5));
603 			for(auto i = 0u; i < type.sizeInComponents; i++)
604 			{
605 				dst.move(i, Cos(radians.Float(i)));
606 			}
607 			break;
608 		}
609 		case GLSLstd450Tan:
610 		{
611 			auto radians = GenericValue(this, state, insn.word(5));
612 			for(auto i = 0u; i < type.sizeInComponents; i++)
613 			{
614 				dst.move(i, Tan(radians.Float(i)));
615 			}
616 			break;
617 		}
618 		case GLSLstd450Asin:
619 		{
620 			auto val = GenericValue(this, state, insn.word(5));
621 			for(auto i = 0u; i < type.sizeInComponents; i++)
622 			{
623 				dst.move(i, Asin(val.Float(i)));
624 			}
625 			break;
626 		}
627 		case GLSLstd450Acos:
628 		{
629 			auto val = GenericValue(this, state, insn.word(5));
630 			for(auto i = 0u; i < type.sizeInComponents; i++)
631 			{
632 				dst.move(i, Acos(val.Float(i)));
633 			}
634 			break;
635 		}
636 		case GLSLstd450Atan:
637 		{
638 			auto val = GenericValue(this, state, insn.word(5));
639 			for(auto i = 0u; i < type.sizeInComponents; i++)
640 			{
641 				dst.move(i, Atan(val.Float(i)));
642 			}
643 			break;
644 		}
645 		case GLSLstd450Sinh:
646 		{
647 			auto val = GenericValue(this, state, insn.word(5));
648 			for(auto i = 0u; i < type.sizeInComponents; i++)
649 			{
650 				dst.move(i, Sinh(val.Float(i)));
651 			}
652 			break;
653 		}
654 		case GLSLstd450Cosh:
655 		{
656 			auto val = GenericValue(this, state, insn.word(5));
657 			for(auto i = 0u; i < type.sizeInComponents; i++)
658 			{
659 				dst.move(i, Cosh(val.Float(i)));
660 			}
661 			break;
662 		}
663 		case GLSLstd450Tanh:
664 		{
665 			auto val = GenericValue(this, state, insn.word(5));
666 			for(auto i = 0u; i < type.sizeInComponents; i++)
667 			{
668 				dst.move(i, Tanh(val.Float(i)));
669 			}
670 			break;
671 		}
672 		case GLSLstd450Asinh:
673 		{
674 			auto val = GenericValue(this, state, insn.word(5));
675 			for(auto i = 0u; i < type.sizeInComponents; i++)
676 			{
677 				dst.move(i, Asinh(val.Float(i)));
678 			}
679 			break;
680 		}
681 		case GLSLstd450Acosh:
682 		{
683 			auto val = GenericValue(this, state, insn.word(5));
684 			for(auto i = 0u; i < type.sizeInComponents; i++)
685 			{
686 				dst.move(i, Acosh(val.Float(i)));
687 			}
688 			break;
689 		}
690 		case GLSLstd450Atanh:
691 		{
692 			auto val = GenericValue(this, state, insn.word(5));
693 			for(auto i = 0u; i < type.sizeInComponents; i++)
694 			{
695 				dst.move(i, Atanh(val.Float(i)));
696 			}
697 			break;
698 		}
699 		case GLSLstd450Atan2:
700 		{
701 			auto x = GenericValue(this, state, insn.word(5));
702 			auto y = GenericValue(this, state, insn.word(6));
703 			for(auto i = 0u; i < type.sizeInComponents; i++)
704 			{
705 				dst.move(i, Atan2(x.Float(i), y.Float(i)));
706 			}
707 			break;
708 		}
709 		case GLSLstd450Pow:
710 		{
711 			auto x = GenericValue(this, state, insn.word(5));
712 			auto y = GenericValue(this, state, insn.word(6));
713 			for(auto i = 0u; i < type.sizeInComponents; i++)
714 			{
715 				dst.move(i, Pow(x.Float(i), y.Float(i)));
716 			}
717 			break;
718 		}
719 		case GLSLstd450Exp:
720 		{
721 			auto val = GenericValue(this, state, insn.word(5));
722 			for(auto i = 0u; i < type.sizeInComponents; i++)
723 			{
724 				dst.move(i, Exp(val.Float(i)));
725 			}
726 			break;
727 		}
728 		case GLSLstd450Log:
729 		{
730 			auto val = GenericValue(this, state, insn.word(5));
731 			for(auto i = 0u; i < type.sizeInComponents; i++)
732 			{
733 				dst.move(i, Log(val.Float(i)));
734 			}
735 			break;
736 		}
737 		case GLSLstd450Exp2:
738 		{
739 			auto val = GenericValue(this, state, insn.word(5));
740 			for(auto i = 0u; i < type.sizeInComponents; i++)
741 			{
742 				dst.move(i, Exp2(val.Float(i)));
743 			}
744 			break;
745 		}
746 		case GLSLstd450Log2:
747 		{
748 			auto val = GenericValue(this, state, insn.word(5));
749 			for(auto i = 0u; i < type.sizeInComponents; i++)
750 			{
751 				dst.move(i, Log2(val.Float(i)));
752 			}
753 			break;
754 		}
755 		case GLSLstd450Sqrt:
756 		{
757 			auto val = GenericValue(this, state, insn.word(5));
758 			for(auto i = 0u; i < type.sizeInComponents; i++)
759 			{
760 				dst.move(i, Sqrt(val.Float(i)));
761 			}
762 			break;
763 		}
764 		case GLSLstd450InverseSqrt:
765 		{
766 			auto val = GenericValue(this, state, insn.word(5));
767 			Decorations d;
768 			ApplyDecorationsForId(&d, insn.word(5));
769 			if(d.RelaxedPrecision)
770 			{
771 				for(auto i = 0u; i < type.sizeInComponents; i++)
772 				{
773 					dst.move(i, RcpSqrt_pp(val.Float(i)));
774 				}
775 			}
776 			else
777 			{
778 				for(auto i = 0u; i < type.sizeInComponents; i++)
779 				{
780 					dst.move(i, SIMD::Float(1.0f) / Sqrt(val.Float(i)));
781 				}
782 			}
783 			break;
784 		}
785 		case GLSLstd450Determinant:
786 		{
787 			auto mat = GenericValue(this, state, insn.word(5));
788 			auto numComponents = getType(mat.type).sizeInComponents;
789 			switch(numComponents)
790 			{
791 				case 4:  // 2x2
792 					dst.move(0, Determinant(
793 					                mat.Float(0), mat.Float(1),
794 					                mat.Float(2), mat.Float(3)));
795 					break;
796 				case 9:  // 3x3
797 					dst.move(0, Determinant(
798 					                mat.Float(0), mat.Float(1), mat.Float(2),
799 					                mat.Float(3), mat.Float(4), mat.Float(5),
800 					                mat.Float(6), mat.Float(7), mat.Float(8)));
801 					break;
802 				case 16:  // 4x4
803 					dst.move(0, Determinant(
804 					                mat.Float(0), mat.Float(1), mat.Float(2), mat.Float(3),
805 					                mat.Float(4), mat.Float(5), mat.Float(6), mat.Float(7),
806 					                mat.Float(8), mat.Float(9), mat.Float(10), mat.Float(11),
807 					                mat.Float(12), mat.Float(13), mat.Float(14), mat.Float(15)));
808 					break;
809 				default:
810 					UNREACHABLE("GLSLstd450Determinant can only operate with square matrices. Got %d elements", int(numComponents));
811 			}
812 			break;
813 		}
814 		case GLSLstd450MatrixInverse:
815 		{
816 			auto mat = GenericValue(this, state, insn.word(5));
817 			auto numComponents = getType(mat.type).sizeInComponents;
818 			switch(numComponents)
819 			{
820 				case 4:  // 2x2
821 				{
822 					auto inv = MatrixInverse(
823 					    mat.Float(0), mat.Float(1),
824 					    mat.Float(2), mat.Float(3));
825 					for(uint32_t i = 0; i < inv.size(); i++)
826 					{
827 						dst.move(i, inv[i]);
828 					}
829 					break;
830 				}
831 				case 9:  // 3x3
832 				{
833 					auto inv = MatrixInverse(
834 					    mat.Float(0), mat.Float(1), mat.Float(2),
835 					    mat.Float(3), mat.Float(4), mat.Float(5),
836 					    mat.Float(6), mat.Float(7), mat.Float(8));
837 					for(uint32_t i = 0; i < inv.size(); i++)
838 					{
839 						dst.move(i, inv[i]);
840 					}
841 					break;
842 				}
843 				case 16:  // 4x4
844 				{
845 					auto inv = MatrixInverse(
846 					    mat.Float(0), mat.Float(1), mat.Float(2), mat.Float(3),
847 					    mat.Float(4), mat.Float(5), mat.Float(6), mat.Float(7),
848 					    mat.Float(8), mat.Float(9), mat.Float(10), mat.Float(11),
849 					    mat.Float(12), mat.Float(13), mat.Float(14), mat.Float(15));
850 					for(uint32_t i = 0; i < inv.size(); i++)
851 					{
852 						dst.move(i, inv[i]);
853 					}
854 					break;
855 				}
856 				default:
857 					UNREACHABLE("GLSLstd450MatrixInverse can only operate with square matrices. Got %d elements", int(numComponents));
858 			}
859 			break;
860 		}
861 		case GLSLstd450IMix:
862 		{
863 			UNREACHABLE("GLSLstd450IMix has been removed from the specification");
864 			break;
865 		}
866 		case GLSLstd450PackDouble2x32:
867 		{
868 			UNSUPPORTED("SPIR-V Float64 Capability (GLSLstd450PackDouble2x32)");
869 			break;
870 		}
871 		case GLSLstd450UnpackDouble2x32:
872 		{
873 			UNSUPPORTED("SPIR-V Float64 Capability (GLSLstd450UnpackDouble2x32)");
874 			break;
875 		}
876 		case GLSLstd450FindILsb:
877 		{
878 			auto val = GenericValue(this, state, insn.word(5));
879 			for(auto i = 0u; i < type.sizeInComponents; i++)
880 			{
881 				auto v = val.UInt(i);
882 				dst.move(i, Cttz(v, true) | CmpEQ(v, SIMD::UInt(0)));
883 			}
884 			break;
885 		}
886 		case GLSLstd450FindSMsb:
887 		{
888 			auto val = GenericValue(this, state, insn.word(5));
889 			for(auto i = 0u; i < type.sizeInComponents; i++)
890 			{
891 				auto v = val.UInt(i) ^ As<SIMD::UInt>(CmpLT(val.Int(i), SIMD::Int(0)));
892 				dst.move(i, SIMD::UInt(31) - Ctlz(v, false));
893 			}
894 			break;
895 		}
896 		case GLSLstd450FindUMsb:
897 		{
898 			auto val = GenericValue(this, state, insn.word(5));
899 			for(auto i = 0u; i < type.sizeInComponents; i++)
900 			{
901 				dst.move(i, SIMD::UInt(31) - Ctlz(val.UInt(i), false));
902 			}
903 			break;
904 		}
905 		case GLSLstd450InterpolateAtCentroid:
906 		{
907 			UNSUPPORTED("SPIR-V SampleRateShading Capability (GLSLstd450InterpolateAtCentroid)");
908 			break;
909 		}
910 		case GLSLstd450InterpolateAtSample:
911 		{
912 			UNSUPPORTED("SPIR-V SampleRateShading Capability (GLSLstd450InterpolateAtCentroid)");
913 			break;
914 		}
915 		case GLSLstd450InterpolateAtOffset:
916 		{
917 			UNSUPPORTED("SPIR-V SampleRateShading Capability (GLSLstd450InterpolateAtCentroid)");
918 			break;
919 		}
920 		case GLSLstd450NMin:
921 		{
922 			auto x = GenericValue(this, state, insn.word(5));
923 			auto y = GenericValue(this, state, insn.word(6));
924 			for(auto i = 0u; i < type.sizeInComponents; i++)
925 			{
926 				dst.move(i, NMin(x.Float(i), y.Float(i)));
927 			}
928 			break;
929 		}
930 		case GLSLstd450NMax:
931 		{
932 			auto x = GenericValue(this, state, insn.word(5));
933 			auto y = GenericValue(this, state, insn.word(6));
934 			for(auto i = 0u; i < type.sizeInComponents; i++)
935 			{
936 				dst.move(i, NMax(x.Float(i), y.Float(i)));
937 			}
938 			break;
939 		}
940 		case GLSLstd450NClamp:
941 		{
942 			auto x = GenericValue(this, state, insn.word(5));
943 			auto minVal = GenericValue(this, state, insn.word(6));
944 			auto maxVal = GenericValue(this, state, insn.word(7));
945 			for(auto i = 0u; i < type.sizeInComponents; i++)
946 			{
947 				auto clamp = NMin(NMax(x.Float(i), minVal.Float(i)), maxVal.Float(i));
948 				dst.move(i, clamp);
949 			}
950 			break;
951 		}
952 		default:
953 			UNREACHABLE("ExtInst %d", int(extInstIndex));
954 			break;
955 	}
956 
957 	return EmitResult::Continue;
958 }
959 
960 }  // namespace sw