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