blob: 51db930ca7fcf4539545e50c4a1bbe622179de31 [file] [log] [blame]
Ben Claytona5ca6da2019-11-28 13:59:27 +00001// 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 <spirv/unified1/spirv.hpp>
Ben Claytona5ca6da2019-11-28 13:59:27 +000018
19namespace sw {
20
Ben Clayton0771f9b2020-01-08 12:00:25 +000021struct SpirvShader::Impl::Group
Ben Claytonbc1c0672019-12-17 20:37:37 +000022{
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +010023 // Template function to perform a binary operation.
Nicolas Capens63468082020-01-13 23:30:43 -050024 // |TYPE| should be the type of the binary operation (as a SIMD::<ScalarType>).
25 // |I| should be a type suitable to initialize the identity value.
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +010026 // |APPLY| should be a callable object that takes two RValue<TYPE> parameters
27 // and returns a new RValue<TYPE> corresponding to the operation's result.
Nicolas Capens63468082020-01-13 23:30:43 -050028 template<typename TYPE, typename I, typename APPLY>
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +010029 static void BinaryOperation(
Ben Claytonbc1c0672019-12-17 20:37:37 +000030 const SpirvShader *shader,
31 const SpirvShader::InsnIterator &insn,
32 const SpirvShader::EmitState *state,
33 Intermediate &dst,
Nicolas Capens63468082020-01-13 23:30:43 -050034 const I identityValue,
Ben Claytonbc1c0672019-12-17 20:37:37 +000035 APPLY &&apply)
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +010036 {
Nicolas Capense6f65d92020-04-08 21:55:43 -040037 SpirvShader::Operand value(shader, state, insn.word(5));
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +010038 auto &type = shader->getType(SpirvShader::Type::ID(insn.word(1)));
Nicolas Capensff9f9b52020-04-14 00:46:38 -040039 for(auto i = 0u; i < type.componentCount; i++)
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +010040 {
Nicolas Capens79dcb2a2020-05-25 13:37:46 -040041 auto mask = As<SIMD::UInt>(state->activeLaneMask()); // Considers helper invocations active. See b/151137030
Nicolas Capens63468082020-01-13 23:30:43 -050042 auto identity = TYPE(identityValue);
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +010043 SIMD::UInt v_uint = (value.UInt(i) & mask) | (As<SIMD::UInt>(identity) & ~mask);
44 TYPE v = As<TYPE>(v_uint);
Nicolas Capens81bc9d92019-12-16 15:05:57 -050045 switch(spv::GroupOperation(insn.word(4)))
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +010046 {
Ben Claytonbc1c0672019-12-17 20:37:37 +000047 case spv::GroupOperationReduce:
48 {
49 // NOTE: floating-point add and multiply are not really commutative so
50 // ensure that all values in the final lanes are identical
51 TYPE v2 = apply(v.xxzz, v.yyww); // [xy] [xy] [zw] [zw]
52 TYPE v3 = apply(v2.xxxx, v2.zzzz); // [xyzw] [xyzw] [xyzw] [xyzw]
53 dst.move(i, v3);
54 break;
55 }
56 case spv::GroupOperationInclusiveScan:
57 {
58 TYPE v2 = apply(v, Shuffle(v, identity, 0x4012) /* [id, v.y, v.z, v.w] */); // [x] [xy] [yz] [zw]
59 TYPE v3 = apply(v2, Shuffle(v2, identity, 0x4401) /* [id, id, v2.x, v2.y] */); // [x] [xy] [xyz] [xyzw]
60 dst.move(i, v3);
61 break;
62 }
63 case spv::GroupOperationExclusiveScan:
64 {
65 TYPE v2 = apply(v, Shuffle(v, identity, 0x4012) /* [id, v.y, v.z, v.w] */); // [x] [xy] [yz] [zw]
66 TYPE v3 = apply(v2, Shuffle(v2, identity, 0x4401) /* [id, id, v2.x, v2.y] */); // [x] [xy] [xyz] [xyzw]
67 auto v4 = Shuffle(v3, identity, 0x4012 /* [id, v3.x, v3.y, v3.z] */); // [i] [x] [xy] [xyz]
68 dst.move(i, v4);
69 break;
70 }
71 default:
Nicolas Capens865f8892020-01-21 14:27:10 -050072 UNSUPPORTED("EmitGroupNonUniform op: %s Group operation: %d",
73 SpirvShader::OpcodeName(type.opcode()).c_str(), insn.word(4));
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +010074 }
75 }
76 }
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +010077};
78
Ben Claytona5ca6da2019-11-28 13:59:27 +000079SpirvShader::EmitResult SpirvShader::EmitGroupNonUniform(InsnIterator insn, EmitState *state) const
80{
81 static_assert(SIMD::Width == 4, "EmitGroupNonUniform makes many assumptions that the SIMD vector width is 4");
82
83 auto &type = getType(Type::ID(insn.word(1)));
84 Object::ID resultId = insn.word(2);
85 auto scope = spv::Scope(GetConstScalarInt(insn.word(3)));
86 ASSERT_MSG(scope == spv::ScopeSubgroup, "Scope for Non Uniform Group Operations must be Subgroup for Vulkan 1.1");
87
Nicolas Capensff9f9b52020-04-14 00:46:38 -040088 auto &dst = state->createIntermediate(resultId, type.componentCount);
Ben Claytona5ca6da2019-11-28 13:59:27 +000089
Nicolas Capens81bc9d92019-12-16 15:05:57 -050090 switch(insn.opcode())
Ben Claytona5ca6da2019-11-28 13:59:27 +000091 {
Ben Claytonbc1c0672019-12-17 20:37:37 +000092 case spv::OpGroupNonUniformElect:
Ben Claytona5ca6da2019-11-28 13:59:27 +000093 {
Ben Claytonbc1c0672019-12-17 20:37:37 +000094 // Result is true only in the active invocation with the lowest id
95 // in the group, otherwise result is false.
Nicolas Capens79dcb2a2020-05-25 13:37:46 -040096 SIMD::Int active = state->activeLaneMask(); // Considers helper invocations active. See b/151137030
Ben Claytonbc1c0672019-12-17 20:37:37 +000097 // TODO: Would be nice if we could write this as:
98 // elect = active & ~(active.Oxyz | active.OOxy | active.OOOx)
99 auto v0111 = SIMD::Int(0, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
100 auto elect = active & ~(v0111 & (active.xxyz | active.xxxy | active.xxxx));
101 dst.move(0, elect);
102 break;
103 }
104
105 case spv::OpGroupNonUniformAll:
106 {
Nicolas Capense6f65d92020-04-08 21:55:43 -0400107 Operand predicate(this, state, insn.word(4));
Nicolas Capens79dcb2a2020-05-25 13:37:46 -0400108 dst.move(0, AndAll(predicate.UInt(0) | ~As<SIMD::UInt>(state->activeLaneMask()))); // Considers helper invocations active. See b/151137030
Ben Claytonbc1c0672019-12-17 20:37:37 +0000109 break;
110 }
111
112 case spv::OpGroupNonUniformAny:
113 {
Nicolas Capense6f65d92020-04-08 21:55:43 -0400114 Operand predicate(this, state, insn.word(4));
Nicolas Capens79dcb2a2020-05-25 13:37:46 -0400115 dst.move(0, OrAll(predicate.UInt(0) & As<SIMD::UInt>(state->activeLaneMask()))); // Considers helper invocations active. See b/151137030
Ben Claytonbc1c0672019-12-17 20:37:37 +0000116 break;
117 }
118
119 case spv::OpGroupNonUniformAllEqual:
120 {
Nicolas Capense6f65d92020-04-08 21:55:43 -0400121 Operand value(this, state, insn.word(4));
Ben Claytonbc1c0672019-12-17 20:37:37 +0000122 auto res = SIMD::UInt(0xffffffff);
Nicolas Capens79dcb2a2020-05-25 13:37:46 -0400123 SIMD::UInt active = As<SIMD::UInt>(state->activeLaneMask()); // Considers helper invocations active. See b/151137030
Ben Claytonbc1c0672019-12-17 20:37:37 +0000124 SIMD::UInt inactive = ~active;
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400125 for(auto i = 0u; i < type.componentCount; i++)
Ben Claytona5ca6da2019-11-28 13:59:27 +0000126 {
Ben Claytonbc1c0672019-12-17 20:37:37 +0000127 SIMD::UInt v = value.UInt(i) & active;
128 SIMD::UInt filled = v;
129 for(int j = 0; j < SIMD::Width - 1; j++)
130 {
131 filled |= filled.yzwx & inactive; // Populate inactive 'holes' with a live value
132 }
133 res &= AndAll(CmpEQ(filled.xyzw, filled.yzwx));
Ben Claytona5ca6da2019-11-28 13:59:27 +0000134 }
Ben Claytonbc1c0672019-12-17 20:37:37 +0000135 dst.move(0, res);
Ben Claytona5ca6da2019-11-28 13:59:27 +0000136 break;
Ben Claytonbc1c0672019-12-17 20:37:37 +0000137 }
138
139 case spv::OpGroupNonUniformBroadcast:
140 {
141 auto valueId = Object::ID(insn.word(4));
142 auto id = SIMD::Int(GetConstScalarInt(insn.word(5)));
Nicolas Capense6f65d92020-04-08 21:55:43 -0400143 Operand value(this, state, valueId);
Ben Claytonbc1c0672019-12-17 20:37:37 +0000144 auto mask = CmpEQ(id, SIMD::Int(0, 1, 2, 3));
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400145 for(auto i = 0u; i < type.componentCount; i++)
Ben Claytonbc1c0672019-12-17 20:37:37 +0000146 {
147 dst.move(i, OrAll(value.Int(i) & mask));
148 }
Ben Claytona5ca6da2019-11-28 13:59:27 +0000149 break;
Ben Claytonbc1c0672019-12-17 20:37:37 +0000150 }
151
152 case spv::OpGroupNonUniformBroadcastFirst:
153 {
154 auto valueId = Object::ID(insn.word(4));
Nicolas Capense6f65d92020-04-08 21:55:43 -0400155 Operand value(this, state, valueId);
Ben Claytonbc1c0672019-12-17 20:37:37 +0000156 // Result is true only in the active invocation with the lowest id
157 // in the group, otherwise result is false.
Nicolas Capens79dcb2a2020-05-25 13:37:46 -0400158 SIMD::Int active = state->activeLaneMask(); // Considers helper invocations active. See b/151137030
Ben Claytonbc1c0672019-12-17 20:37:37 +0000159 // TODO: Would be nice if we could write this as:
160 // elect = active & ~(active.Oxyz | active.OOxy | active.OOOx)
161 auto v0111 = SIMD::Int(0, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
162 auto elect = active & ~(v0111 & (active.xxyz | active.xxxy | active.xxxx));
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400163 for(auto i = 0u; i < type.componentCount; i++)
Ben Claytonbc1c0672019-12-17 20:37:37 +0000164 {
165 dst.move(i, OrAll(value.Int(i) & elect));
166 }
Ben Claytona5ca6da2019-11-28 13:59:27 +0000167 break;
Ben Claytonbc1c0672019-12-17 20:37:37 +0000168 }
169
170 case spv::OpGroupNonUniformBallot:
171 {
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400172 ASSERT(type.componentCount == 4);
Nicolas Capense6f65d92020-04-08 21:55:43 -0400173 Operand predicate(this, state, insn.word(4));
Nicolas Capens79dcb2a2020-05-25 13:37:46 -0400174 dst.move(0, SIMD::Int(SignMask(state->activeLaneMask() & predicate.Int(0)))); // Considers helper invocations active. See b/151137030
Ben Claytonbc1c0672019-12-17 20:37:37 +0000175 dst.move(1, SIMD::Int(0));
176 dst.move(2, SIMD::Int(0));
177 dst.move(3, SIMD::Int(0));
178 break;
179 }
180
181 case spv::OpGroupNonUniformInverseBallot:
182 {
183 auto valueId = Object::ID(insn.word(4));
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400184 ASSERT(type.componentCount == 1);
185 ASSERT(getType(getObject(valueId)).componentCount == 4);
Nicolas Capense6f65d92020-04-08 21:55:43 -0400186 Operand value(this, state, valueId);
Ben Claytonbc1c0672019-12-17 20:37:37 +0000187 auto bit = (value.Int(0) >> SIMD::Int(0, 1, 2, 3)) & SIMD::Int(1);
188 dst.move(0, -bit);
189 break;
190 }
191
192 case spv::OpGroupNonUniformBallotBitExtract:
193 {
194 auto valueId = Object::ID(insn.word(4));
195 auto indexId = Object::ID(insn.word(5));
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400196 ASSERT(type.componentCount == 1);
197 ASSERT(getType(getObject(valueId)).componentCount == 4);
198 ASSERT(getType(getObject(indexId)).componentCount == 1);
Nicolas Capense6f65d92020-04-08 21:55:43 -0400199 Operand value(this, state, valueId);
200 Operand index(this, state, indexId);
Ben Claytonbc1c0672019-12-17 20:37:37 +0000201 auto vecIdx = index.Int(0) / SIMD::Int(32);
202 auto bitIdx = index.Int(0) & SIMD::Int(31);
203 auto bits = (value.Int(0) & CmpEQ(vecIdx, SIMD::Int(0))) |
204 (value.Int(1) & CmpEQ(vecIdx, SIMD::Int(1))) |
205 (value.Int(2) & CmpEQ(vecIdx, SIMD::Int(2))) |
206 (value.Int(3) & CmpEQ(vecIdx, SIMD::Int(3)));
207 dst.move(0, -((bits >> bitIdx) & SIMD::Int(1)));
208 break;
209 }
210
211 case spv::OpGroupNonUniformBallotBitCount:
212 {
213 auto operation = spv::GroupOperation(insn.word(4));
214 auto valueId = Object::ID(insn.word(5));
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400215 ASSERT(type.componentCount == 1);
216 ASSERT(getType(getObject(valueId)).componentCount == 4);
Nicolas Capense6f65d92020-04-08 21:55:43 -0400217 Operand value(this, state, valueId);
Ben Claytonbc1c0672019-12-17 20:37:37 +0000218 switch(operation)
219 {
220 case spv::GroupOperationReduce:
221 dst.move(0, CountBits(value.UInt(0) & SIMD::UInt(15)));
222 break;
223 case spv::GroupOperationInclusiveScan:
224 dst.move(0, CountBits(value.UInt(0) & SIMD::UInt(1, 3, 7, 15)));
225 break;
226 case spv::GroupOperationExclusiveScan:
227 dst.move(0, CountBits(value.UInt(0) & SIMD::UInt(0, 1, 3, 7)));
228 break;
229 default:
230 UNSUPPORTED("GroupOperation %d", int(operation));
231 }
232 break;
233 }
234
235 case spv::OpGroupNonUniformBallotFindLSB:
236 {
237 auto valueId = Object::ID(insn.word(4));
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400238 ASSERT(type.componentCount == 1);
239 ASSERT(getType(getObject(valueId)).componentCount == 4);
Nicolas Capense6f65d92020-04-08 21:55:43 -0400240 Operand value(this, state, valueId);
Ben Claytonbc1c0672019-12-17 20:37:37 +0000241 dst.move(0, Cttz(value.UInt(0) & SIMD::UInt(15), true));
242 break;
243 }
244
245 case spv::OpGroupNonUniformBallotFindMSB:
246 {
247 auto valueId = Object::ID(insn.word(4));
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400248 ASSERT(type.componentCount == 1);
249 ASSERT(getType(getObject(valueId)).componentCount == 4);
Nicolas Capense6f65d92020-04-08 21:55:43 -0400250 Operand value(this, state, valueId);
Ben Claytonbc1c0672019-12-17 20:37:37 +0000251 dst.move(0, SIMD::UInt(31) - Ctlz(value.UInt(0) & SIMD::UInt(15), false));
252 break;
253 }
254
255 case spv::OpGroupNonUniformShuffle:
256 {
Nicolas Capense6f65d92020-04-08 21:55:43 -0400257 Operand value(this, state, insn.word(4));
258 Operand id(this, state, insn.word(5));
Ben Claytonbc1c0672019-12-17 20:37:37 +0000259 auto x = CmpEQ(SIMD::Int(0), id.Int(0));
260 auto y = CmpEQ(SIMD::Int(1), id.Int(0));
261 auto z = CmpEQ(SIMD::Int(2), id.Int(0));
262 auto w = CmpEQ(SIMD::Int(3), id.Int(0));
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400263 for(auto i = 0u; i < type.componentCount; i++)
Ben Claytonbc1c0672019-12-17 20:37:37 +0000264 {
265 SIMD::Int v = value.Int(i);
266 dst.move(i, (x & v.xxxx) | (y & v.yyyy) | (z & v.zzzz) | (w & v.wwww));
267 }
268 break;
269 }
270
271 case spv::OpGroupNonUniformShuffleXor:
272 {
Nicolas Capense6f65d92020-04-08 21:55:43 -0400273 Operand value(this, state, insn.word(4));
274 Operand mask(this, state, insn.word(5));
Ben Claytonbc1c0672019-12-17 20:37:37 +0000275 auto x = CmpEQ(SIMD::Int(0), SIMD::Int(0, 1, 2, 3) ^ mask.Int(0));
276 auto y = CmpEQ(SIMD::Int(1), SIMD::Int(0, 1, 2, 3) ^ mask.Int(0));
277 auto z = CmpEQ(SIMD::Int(2), SIMD::Int(0, 1, 2, 3) ^ mask.Int(0));
278 auto w = CmpEQ(SIMD::Int(3), SIMD::Int(0, 1, 2, 3) ^ mask.Int(0));
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400279 for(auto i = 0u; i < type.componentCount; i++)
Ben Claytonbc1c0672019-12-17 20:37:37 +0000280 {
281 SIMD::Int v = value.Int(i);
282 dst.move(i, (x & v.xxxx) | (y & v.yyyy) | (z & v.zzzz) | (w & v.wwww));
283 }
284 break;
285 }
286
287 case spv::OpGroupNonUniformShuffleUp:
288 {
Nicolas Capense6f65d92020-04-08 21:55:43 -0400289 Operand value(this, state, insn.word(4));
290 Operand delta(this, state, insn.word(5));
Ben Claytonbc1c0672019-12-17 20:37:37 +0000291 auto d0 = CmpEQ(SIMD::Int(0), delta.Int(0));
292 auto d1 = CmpEQ(SIMD::Int(1), delta.Int(0));
293 auto d2 = CmpEQ(SIMD::Int(2), delta.Int(0));
294 auto d3 = CmpEQ(SIMD::Int(3), delta.Int(0));
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400295 for(auto i = 0u; i < type.componentCount; i++)
Ben Claytonbc1c0672019-12-17 20:37:37 +0000296 {
297 SIMD::Int v = value.Int(i);
298 dst.move(i, (d0 & v.xyzw) | (d1 & v.xxyz) | (d2 & v.xxxy) | (d3 & v.xxxx));
299 }
300 break;
301 }
302
303 case spv::OpGroupNonUniformShuffleDown:
304 {
Nicolas Capense6f65d92020-04-08 21:55:43 -0400305 Operand value(this, state, insn.word(4));
306 Operand delta(this, state, insn.word(5));
Ben Claytonbc1c0672019-12-17 20:37:37 +0000307 auto d0 = CmpEQ(SIMD::Int(0), delta.Int(0));
308 auto d1 = CmpEQ(SIMD::Int(1), delta.Int(0));
309 auto d2 = CmpEQ(SIMD::Int(2), delta.Int(0));
310 auto d3 = CmpEQ(SIMD::Int(3), delta.Int(0));
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400311 for(auto i = 0u; i < type.componentCount; i++)
Ben Claytonbc1c0672019-12-17 20:37:37 +0000312 {
313 SIMD::Int v = value.Int(i);
314 dst.move(i, (d0 & v.xyzw) | (d1 & v.yzww) | (d2 & v.zwww) | (d3 & v.wwww));
315 }
316 break;
317 }
318
319 case spv::OpGroupNonUniformIAdd:
Nicolas Capens63468082020-01-13 23:30:43 -0500320 Impl::Group::BinaryOperation<SIMD::Int>(
321 this, insn, state, dst, 0,
322 [](auto a, auto b) { return a + b; });
Ben Claytonbc1c0672019-12-17 20:37:37 +0000323 break;
Ben Claytonbc1c0672019-12-17 20:37:37 +0000324
325 case spv::OpGroupNonUniformFAdd:
Nicolas Capens63468082020-01-13 23:30:43 -0500326 Impl::Group::BinaryOperation<SIMD::Float>(
327 this, insn, state, dst, 0.0f,
328 [](auto a, auto b) { return a + b; });
Ben Claytonbc1c0672019-12-17 20:37:37 +0000329 break;
Ben Claytonbc1c0672019-12-17 20:37:37 +0000330
331 case spv::OpGroupNonUniformIMul:
Nicolas Capens63468082020-01-13 23:30:43 -0500332 Impl::Group::BinaryOperation<SIMD::Int>(
333 this, insn, state, dst, 1,
334 [](auto a, auto b) { return a * b; });
Ben Claytonbc1c0672019-12-17 20:37:37 +0000335 break;
Ben Claytonbc1c0672019-12-17 20:37:37 +0000336
337 case spv::OpGroupNonUniformFMul:
Nicolas Capens63468082020-01-13 23:30:43 -0500338 Impl::Group::BinaryOperation<SIMD::Float>(
339 this, insn, state, dst, 1.0f,
340 [](auto a, auto b) { return a * b; });
Ben Claytonbc1c0672019-12-17 20:37:37 +0000341 break;
Ben Claytonbc1c0672019-12-17 20:37:37 +0000342
343 case spv::OpGroupNonUniformBitwiseAnd:
Nicolas Capens63468082020-01-13 23:30:43 -0500344 Impl::Group::BinaryOperation<SIMD::UInt>(
345 this, insn, state, dst, ~0u,
346 [](auto a, auto b) { return a & b; });
Ben Claytonbc1c0672019-12-17 20:37:37 +0000347 break;
Ben Claytonbc1c0672019-12-17 20:37:37 +0000348
349 case spv::OpGroupNonUniformBitwiseOr:
Nicolas Capens63468082020-01-13 23:30:43 -0500350 Impl::Group::BinaryOperation<SIMD::UInt>(
351 this, insn, state, dst, 0,
352 [](auto a, auto b) { return a | b; });
Ben Claytonbc1c0672019-12-17 20:37:37 +0000353 break;
Ben Claytonbc1c0672019-12-17 20:37:37 +0000354
355 case spv::OpGroupNonUniformBitwiseXor:
Nicolas Capens63468082020-01-13 23:30:43 -0500356 Impl::Group::BinaryOperation<SIMD::UInt>(
357 this, insn, state, dst, 0,
358 [](auto a, auto b) { return a ^ b; });
Ben Claytonbc1c0672019-12-17 20:37:37 +0000359 break;
Ben Claytonbc1c0672019-12-17 20:37:37 +0000360
361 case spv::OpGroupNonUniformSMin:
Nicolas Capens63468082020-01-13 23:30:43 -0500362 Impl::Group::BinaryOperation<SIMD::Int>(
363 this, insn, state, dst, INT32_MAX,
364 [](auto a, auto b) { return Min(a, b); });
Ben Claytonbc1c0672019-12-17 20:37:37 +0000365 break;
Ben Claytonbc1c0672019-12-17 20:37:37 +0000366
367 case spv::OpGroupNonUniformUMin:
Nicolas Capens63468082020-01-13 23:30:43 -0500368 Impl::Group::BinaryOperation<SIMD::UInt>(
369 this, insn, state, dst, ~0u,
370 [](auto a, auto b) { return Min(a, b); });
Ben Claytonbc1c0672019-12-17 20:37:37 +0000371 break;
Ben Claytonbc1c0672019-12-17 20:37:37 +0000372
373 case spv::OpGroupNonUniformFMin:
Nicolas Capens63468082020-01-13 23:30:43 -0500374 Impl::Group::BinaryOperation<SIMD::Float>(
375 this, insn, state, dst, SIMD::Float::infinity(),
376 [](auto a, auto b) { return NMin(a, b); });
Ben Claytonbc1c0672019-12-17 20:37:37 +0000377 break;
Ben Claytonbc1c0672019-12-17 20:37:37 +0000378
379 case spv::OpGroupNonUniformSMax:
Nicolas Capens63468082020-01-13 23:30:43 -0500380 Impl::Group::BinaryOperation<SIMD::Int>(
381 this, insn, state, dst, INT32_MIN,
382 [](auto a, auto b) { return Max(a, b); });
Ben Claytonbc1c0672019-12-17 20:37:37 +0000383 break;
Ben Claytonbc1c0672019-12-17 20:37:37 +0000384
385 case spv::OpGroupNonUniformUMax:
Nicolas Capens63468082020-01-13 23:30:43 -0500386 Impl::Group::BinaryOperation<SIMD::UInt>(
387 this, insn, state, dst, 0,
388 [](auto a, auto b) { return Max(a, b); });
Ben Claytonbc1c0672019-12-17 20:37:37 +0000389 break;
Ben Claytonbc1c0672019-12-17 20:37:37 +0000390
391 case spv::OpGroupNonUniformFMax:
Nicolas Capens63468082020-01-13 23:30:43 -0500392 Impl::Group::BinaryOperation<SIMD::Float>(
393 this, insn, state, dst, -SIMD::Float::infinity(),
394 [](auto a, auto b) { return NMax(a, b); });
Ben Claytonbc1c0672019-12-17 20:37:37 +0000395 break;
Ben Claytonbc1c0672019-12-17 20:37:37 +0000396
397 case spv::OpGroupNonUniformLogicalAnd:
Nicolas Capens63468082020-01-13 23:30:43 -0500398 Impl::Group::BinaryOperation<SIMD::UInt>(
399 this, insn, state, dst, ~0u,
400 [](auto a, auto b) {
Ben Claytonbc1c0672019-12-17 20:37:37 +0000401 SIMD::UInt zero = SIMD::UInt(0);
402 return CmpNEQ(a, zero) & CmpNEQ(b, zero);
403 });
404 break;
Ben Claytonbc1c0672019-12-17 20:37:37 +0000405
406 case spv::OpGroupNonUniformLogicalOr:
Nicolas Capens63468082020-01-13 23:30:43 -0500407 Impl::Group::BinaryOperation<SIMD::UInt>(
408 this, insn, state, dst, 0,
409 [](auto a, auto b) {
Ben Claytonbc1c0672019-12-17 20:37:37 +0000410 SIMD::UInt zero = SIMD::UInt(0);
411 return CmpNEQ(a, zero) | CmpNEQ(b, zero);
412 });
413 break;
Ben Claytonbc1c0672019-12-17 20:37:37 +0000414
415 case spv::OpGroupNonUniformLogicalXor:
Nicolas Capens63468082020-01-13 23:30:43 -0500416 Impl::Group::BinaryOperation<SIMD::UInt>(
417 this, insn, state, dst, 0,
418 [](auto a, auto b) {
Ben Claytonbc1c0672019-12-17 20:37:37 +0000419 SIMD::UInt zero = SIMD::UInt(0);
420 return CmpNEQ(a, zero) ^ CmpNEQ(b, zero);
421 });
422 break;
Ben Claytonbc1c0672019-12-17 20:37:37 +0000423
Ben Claytona5ca6da2019-11-28 13:59:27 +0000424 default:
Nicolas Capens865f8892020-01-21 14:27:10 -0500425 UNSUPPORTED("EmitGroupNonUniform op: %s", OpcodeName(type.opcode()).c_str());
Ben Claytona5ca6da2019-11-28 13:59:27 +0000426 }
427 return EmitResult::Continue;
428}
429
David 'Digit' Turnerb9f03f42019-12-04 19:32:34 +0100430} // namespace sw