blob: 2106bdc7dcd23f34f2047cacdb3f9e5deaa123f9 [file] [log] [blame]
Chris Forbesaf4ed532018-12-06 18:33:27 -08001// Copyright 2018 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 <spirv/unified1/spirv.hpp>
Chris Forbes9667a5b2019-03-07 09:26:48 -080016#include <spirv/unified1/GLSL.std.450.h>
Chris Forbesaf4ed532018-12-06 18:33:27 -080017#include "SpirvShader.hpp"
18#include "System/Math.hpp"
Ben Claytonefec1b92019-03-05 17:38:16 +000019#include "Vulkan/VkBuffer.hpp"
Chris Forbesebe5f7f2019-01-16 10:38:34 -080020#include "Vulkan/VkDebug.hpp"
Ben Clayton76e9bc02019-02-26 15:02:18 +000021#include "Vulkan/VkPipelineLayout.hpp"
Chris Forbesaf4ed532018-12-06 18:33:27 -080022#include "Device/Config.hpp"
23
Ben Claytonc0cf68b2019-03-21 17:46:08 +000024#ifdef Bool
25#undef Bool // b/127920555
26#endif
27
Ben Claytone747b3c2019-03-21 19:35:15 +000028namespace
29{
30 rr::RValue<rr::Bool> AnyTrue(rr::RValue<sw::SIMD::Int> const &ints)
31 {
32 return rr::SignMask(ints) != 0;
33 }
34
35 rr::RValue<rr::Bool> AnyFalse(rr::RValue<sw::SIMD::Int> const &ints)
36 {
37 return rr::SignMask(~ints) != 0;
38 }
39}
40
Chris Forbesaf4ed532018-12-06 18:33:27 -080041namespace sw
42{
43 volatile int SpirvShader::serialCounter = 1; // Start at 1, 0 is invalid shader.
44
Chris Forbes5839dcf2018-12-10 19:02:58 -080045 SpirvShader::SpirvShader(InsnStore const &insns)
46 : insns{insns}, inputs{MAX_INTERFACE_COMPONENTS},
47 outputs{MAX_INTERFACE_COMPONENTS},
48 serialID{serialCounter++}, modes{}
Chris Forbesaf4ed532018-12-06 18:33:27 -080049 {
Ben Clayton45faa082019-03-05 13:20:40 +000050 ASSERT(insns.size() > 0);
51
Chris Forbesaf4ed532018-12-06 18:33:27 -080052 // Simplifying assumptions (to be satisfied by earlier transformations)
Chris Forbesbde34082018-12-28 12:03:10 -080053 // - There is exactly one entrypoint in the module, and it's the one we want
Chris Forbesaf4ed532018-12-06 18:33:27 -080054 // - The only input/output OpVariables present are those used by the entrypoint
55
Ben Clayton9b156612019-03-13 19:48:31 +000056 Block::ID currentBlock;
57 InsnIterator blockStart;
Chris Forbese57f10e2019-03-04 10:53:07 -080058
Chris Forbes4a979dc2019-01-17 09:36:46 -080059 for (auto insn : *this)
60 {
61 switch (insn.opcode())
62 {
63 case spv::OpExecutionMode:
64 ProcessExecutionMode(insn);
65 break;
Chris Forbesaf4ed532018-12-06 18:33:27 -080066
Chris Forbesc25b8072018-12-10 15:10:39 -080067 case spv::OpDecorate:
68 {
Ben Claytonab51bbf2019-02-20 14:36:27 +000069 TypeOrObjectID targetId = insn.word(1);
Chris Forbes93f70b32019-02-10 21:26:27 +000070 auto decoration = static_cast<spv::Decoration>(insn.word(2));
Chris Forbesc25b8072018-12-10 15:10:39 -080071 decorations[targetId].Apply(
Chris Forbes93f70b32019-02-10 21:26:27 +000072 decoration,
Chris Forbesc25b8072018-12-10 15:10:39 -080073 insn.wordCount() > 3 ? insn.word(3) : 0);
Chris Forbes93f70b32019-02-10 21:26:27 +000074
75 if (decoration == spv::DecorationCentroid)
76 modes.NeedsCentroid = true;
Chris Forbesc25b8072018-12-10 15:10:39 -080077 break;
78 }
79
80 case spv::OpMemberDecorate:
81 {
Ben Claytonaf973b62019-03-13 18:19:20 +000082 Type::ID targetId = insn.word(1);
Chris Forbesc25b8072018-12-10 15:10:39 -080083 auto memberIndex = insn.word(2);
84 auto &d = memberDecorations[targetId];
85 if (memberIndex >= d.size())
86 d.resize(memberIndex + 1); // on demand; exact size would require another pass...
Chris Forbes93f70b32019-02-10 21:26:27 +000087 auto decoration = static_cast<spv::Decoration>(insn.word(3));
Chris Forbesc25b8072018-12-10 15:10:39 -080088 d[memberIndex].Apply(
Chris Forbes93f70b32019-02-10 21:26:27 +000089 decoration,
Chris Forbesc25b8072018-12-10 15:10:39 -080090 insn.wordCount() > 4 ? insn.word(4) : 0);
Chris Forbes93f70b32019-02-10 21:26:27 +000091
92 if (decoration == spv::DecorationCentroid)
93 modes.NeedsCentroid = true;
Chris Forbesc25b8072018-12-10 15:10:39 -080094 break;
95 }
96
97 case spv::OpDecorationGroup:
98 // Nothing to do here. We don't need to record the definition of the group; we'll just have
99 // the bundle of decorations float around. If we were to ever walk the decorations directly,
100 // we might think about introducing this as a real Object.
101 break;
102
103 case spv::OpGroupDecorate:
104 {
105 auto const &srcDecorations = decorations[insn.word(1)];
106 for (auto i = 2u; i < insn.wordCount(); i++)
107 {
108 // remaining operands are targets to apply the group to.
109 decorations[insn.word(i)].Apply(srcDecorations);
110 }
111 break;
112 }
113
114 case spv::OpGroupMemberDecorate:
115 {
116 auto const &srcDecorations = decorations[insn.word(1)];
117 for (auto i = 2u; i < insn.wordCount(); i += 2)
118 {
119 // remaining operands are pairs of <id>, literal for members to apply to.
120 auto &d = memberDecorations[insn.word(i)];
121 auto memberIndex = insn.word(i + 1);
122 if (memberIndex >= d.size())
123 d.resize(memberIndex + 1); // on demand resize, see above...
124 d[memberIndex].Apply(srcDecorations);
125 }
126 break;
127 }
128
Chris Forbese57f10e2019-03-04 10:53:07 -0800129 case spv::OpLabel:
Ben Clayton9b156612019-03-13 19:48:31 +0000130 {
131 ASSERT(currentBlock.value() == 0);
132 currentBlock = Block::ID(insn.word(1));
133 blockStart = insn;
Chris Forbese57f10e2019-03-04 10:53:07 -0800134 break;
Ben Clayton9b156612019-03-13 19:48:31 +0000135 }
Chris Forbese57f10e2019-03-04 10:53:07 -0800136
Ben Clayton9b156612019-03-13 19:48:31 +0000137 // Branch Instructions (subset of Termination Instructions):
138 case spv::OpBranch:
139 case spv::OpBranchConditional:
140 case spv::OpSwitch:
Chris Forbese57f10e2019-03-04 10:53:07 -0800141 case spv::OpReturn:
Ben Clayton9b156612019-03-13 19:48:31 +0000142 // fallthrough
143
144 // Termination instruction:
145 case spv::OpKill:
146 case spv::OpUnreachable:
147 {
148 ASSERT(currentBlock.value() != 0);
149 auto blockEnd = insn; blockEnd++;
150 blocks[currentBlock] = Block(blockStart, blockEnd);
151 currentBlock = Block::ID(0);
152
153 if (insn.opcode() == spv::OpKill)
154 {
155 modes.ContainsKill = true;
156 }
Chris Forbese57f10e2019-03-04 10:53:07 -0800157 break;
Ben Clayton9b156612019-03-13 19:48:31 +0000158 }
Chris Forbese57f10e2019-03-04 10:53:07 -0800159
Ben Claytone747b3c2019-03-21 19:35:15 +0000160 case spv::OpLoopMerge:
Ben Clayton9fd02e02019-03-21 18:47:15 +0000161 case spv::OpSelectionMerge:
162 break; // Nothing to do in analysis pass.
163
Chris Forbes4a979dc2019-01-17 09:36:46 -0800164 case spv::OpTypeVoid:
165 case spv::OpTypeBool:
166 case spv::OpTypeInt:
167 case spv::OpTypeFloat:
168 case spv::OpTypeVector:
169 case spv::OpTypeMatrix:
170 case spv::OpTypeImage:
171 case spv::OpTypeSampler:
172 case spv::OpTypeSampledImage:
173 case spv::OpTypeArray:
174 case spv::OpTypeRuntimeArray:
175 case spv::OpTypeStruct:
176 case spv::OpTypePointer:
177 case spv::OpTypeFunction:
Ben Clayton0bb83b82019-02-26 11:41:07 +0000178 DeclareType(insn);
Chris Forbes4a979dc2019-01-17 09:36:46 -0800179 break;
Chris Forbes296aa252018-12-27 11:48:21 -0800180
Chris Forbes4a979dc2019-01-17 09:36:46 -0800181 case spv::OpVariable:
182 {
Ben Claytonaf973b62019-03-13 18:19:20 +0000183 Type::ID typeId = insn.word(1);
184 Object::ID resultId = insn.word(2);
Chris Forbes4a979dc2019-01-17 09:36:46 -0800185 auto storageClass = static_cast<spv::StorageClass>(insn.word(3));
186 if (insn.wordCount() > 4)
187 UNIMPLEMENTED("Variable initializers not yet supported");
Chris Forbes296aa252018-12-27 11:48:21 -0800188
Chris Forbes4a979dc2019-01-17 09:36:46 -0800189 auto &object = defs[resultId];
190 object.kind = Object::Kind::Variable;
191 object.definition = insn;
Ben Clayton9a162482019-02-25 11:54:43 +0000192 object.type = typeId;
Chris Forbese9f8f5b2019-02-11 00:20:16 +0000193 object.pointerBase = insn.word(2); // base is itself
Chris Forbesc25b8072018-12-10 15:10:39 -0800194
Ben Claytonefec1b92019-03-05 17:38:16 +0000195 ASSERT(getType(typeId).storageClass == storageClass);
196
197 switch (storageClass)
Chris Forbesc25b8072018-12-10 15:10:39 -0800198 {
Ben Claytonefec1b92019-03-05 17:38:16 +0000199 case spv::StorageClassInput:
200 case spv::StorageClassOutput:
Ben Claytona1924732019-02-28 18:42:10 +0000201 ProcessInterfaceVariable(object);
Ben Claytonefec1b92019-03-05 17:38:16 +0000202 break;
203 case spv::StorageClassUniform:
204 case spv::StorageClassStorageBuffer:
Chris Forbesa30de542019-03-18 18:51:55 -0700205 case spv::StorageClassPushConstant:
Ben Claytonefec1b92019-03-05 17:38:16 +0000206 object.kind = Object::Kind::PhysicalPointer;
207 break;
208
209 case spv::StorageClassPrivate:
210 case spv::StorageClassFunction:
211 break; // Correctly handled.
212
213 case spv::StorageClassUniformConstant:
214 case spv::StorageClassWorkgroup:
215 case spv::StorageClassCrossWorkgroup:
216 case spv::StorageClassGeneric:
Ben Claytonefec1b92019-03-05 17:38:16 +0000217 case spv::StorageClassAtomicCounter:
218 case spv::StorageClassImage:
219 UNIMPLEMENTED("StorageClass %d not yet implemented", (int)storageClass);
220 break;
221
222 default:
Nicolas Capens29090852019-03-19 16:22:35 -0400223 UNREACHABLE("Unexpected StorageClass %d", storageClass); // See Appendix A of the Vulkan spec.
Ben Claytonefec1b92019-03-05 17:38:16 +0000224 break;
Chris Forbesc25b8072018-12-10 15:10:39 -0800225 }
Chris Forbes4a979dc2019-01-17 09:36:46 -0800226 break;
227 }
Chris Forbes296aa252018-12-27 11:48:21 -0800228
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800229 case spv::OpConstant:
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800230 CreateConstant(insn).constantValue[0] = insn.word(3);
231 break;
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800232 case spv::OpConstantFalse:
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800233 CreateConstant(insn).constantValue[0] = 0; // represent boolean false as zero
234 break;
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800235 case spv::OpConstantTrue:
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800236 CreateConstant(insn).constantValue[0] = ~0u; // represent boolean true as all bits set
237 break;
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800238 case spv::OpConstantNull:
Chris Forbes0e712412019-03-18 19:31:16 -0700239 case spv::OpUndef:
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800240 {
Chris Forbes0e712412019-03-18 19:31:16 -0700241 // TODO: consider a real LLVM-level undef. For now, zero is a perfectly good value.
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800242 // OpConstantNull forms a constant of arbitrary type, all zeros.
Ben Clayton9a162482019-02-25 11:54:43 +0000243 auto &object = CreateConstant(insn);
244 auto &objectTy = getType(object.type);
245 for (auto i = 0u; i < objectTy.sizeInComponents; i++)
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800246 {
247 object.constantValue[i] = 0;
248 }
249 break;
250 }
251 case spv::OpConstantComposite:
252 {
253 auto &object = CreateConstant(insn);
254 auto offset = 0u;
255 for (auto i = 0u; i < insn.wordCount() - 3; i++)
256 {
Ben Clayton9a162482019-02-25 11:54:43 +0000257 auto &constituent = getObject(insn.word(i + 3));
258 auto &constituentTy = getType(constituent.type);
259 for (auto j = 0u; j < constituentTy.sizeInComponents; j++)
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800260 object.constantValue[offset++] = constituent.constantValue[j];
261 }
Ben Clayton62758f52019-03-13 14:18:58 +0000262
263 auto objectId = Object::ID(insn.word(2));
264 auto decorationsIt = decorations.find(objectId);
265 if (decorationsIt != decorations.end() &&
266 decorationsIt->second.BuiltIn == spv::BuiltInWorkgroupSize)
267 {
268 // https://www.khronos.org/registry/vulkan/specs/1.1/html/vkspec.html#interfaces-builtin-variables :
269 // Decorating an object with the WorkgroupSize built-in
270 // decoration will make that object contain the dimensions
271 // of a local workgroup. If an object is decorated with the
272 // WorkgroupSize decoration, this must take precedence over
273 // any execution mode set for LocalSize.
274 // The object decorated with WorkgroupSize must be declared
275 // as a three-component vector of 32-bit integers.
276 ASSERT(getType(object.type).sizeInComponents == 3);
277 modes.WorkgroupSizeX = object.constantValue[0];
278 modes.WorkgroupSizeY = object.constantValue[1];
279 modes.WorkgroupSizeZ = object.constantValue[2];
280 }
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800281 break;
282 }
283
Chris Forbesbde34082018-12-28 12:03:10 -0800284 case spv::OpCapability:
Ben Clayton9b156612019-03-13 19:48:31 +0000285 break; // Various capabilities will be declared, but none affect our code generation at this point.
Chris Forbesbde34082018-12-28 12:03:10 -0800286 case spv::OpMemoryModel:
Ben Clayton9b156612019-03-13 19:48:31 +0000287 break; // Memory model does not affect our code generation until we decide to do Vulkan Memory Model support.
288
Chris Forbesbde34082018-12-28 12:03:10 -0800289 case spv::OpEntryPoint:
Ben Clayton9b156612019-03-13 19:48:31 +0000290 break;
Chris Forbes7edf5342019-02-10 22:41:21 +0000291 case spv::OpFunction:
Ben Clayton9b156612019-03-13 19:48:31 +0000292 ASSERT(mainBlockId.value() == 0); // Multiple functions found
293 // Scan forward to find the function's label.
294 for (auto it = insn; it != end() && mainBlockId.value() == 0; it++)
295 {
296 switch (it.opcode())
297 {
298 case spv::OpFunction:
299 case spv::OpFunctionParameter:
300 break;
301 case spv::OpLabel:
302 mainBlockId = Block::ID(it.word(1));
303 break;
304 default:
Ben Clayton00424c12019-03-17 17:29:30 +0000305 WARN("Unexpected opcode '%s' following OpFunction", OpcodeName(it.opcode()).c_str());
Ben Clayton9b156612019-03-13 19:48:31 +0000306 }
307 }
308 ASSERT(mainBlockId.value() != 0); // Function's OpLabel not found
309 break;
Chris Forbes7edf5342019-02-10 22:41:21 +0000310 case spv::OpFunctionEnd:
311 // Due to preprocessing, the entrypoint and its function provide no value.
312 break;
313 case spv::OpExtInstImport:
314 // We will only support the GLSL 450 extended instruction set, so no point in tracking the ID we assign it.
315 // Valid shaders will not attempt to import any other instruction sets.
Chris Forbes9667a5b2019-03-07 09:26:48 -0800316 if (0 != strcmp("GLSL.std.450", reinterpret_cast<char const *>(insn.wordPointer(2))))
317 {
318 UNIMPLEMENTED("Only GLSL extended instruction set is supported");
319 }
320 break;
Chris Forbes1776af72019-02-22 17:39:57 -0800321 case spv::OpName:
322 case spv::OpMemberName:
323 case spv::OpSource:
324 case spv::OpSourceContinued:
325 case spv::OpSourceExtension:
Chris Forbesf3a430d2019-03-08 07:51:39 -0800326 case spv::OpLine:
327 case spv::OpNoLine:
328 case spv::OpModuleProcessed:
329 case spv::OpString:
Chris Forbes1776af72019-02-22 17:39:57 -0800330 // No semantic impact
Chris Forbes7edf5342019-02-10 22:41:21 +0000331 break;
332
333 case spv::OpFunctionParameter:
334 case spv::OpFunctionCall:
335 case spv::OpSpecConstant:
336 case spv::OpSpecConstantComposite:
337 case spv::OpSpecConstantFalse:
338 case spv::OpSpecConstantOp:
339 case spv::OpSpecConstantTrue:
340 // These should have all been removed by preprocessing passes. If we see them here,
341 // our assumptions are wrong and we will probably generate wrong code.
Ben Claytonaf26cfe2019-03-21 17:32:44 +0000342 UNIMPLEMENTED("%s should have already been lowered.", OpcodeName(insn.opcode()).c_str());
Chris Forbes7edf5342019-02-10 22:41:21 +0000343 break;
344
Chris Forbes4d503052019-03-01 17:13:57 -0800345 case spv::OpFConvert:
346 case spv::OpSConvert:
347 case spv::OpUConvert:
348 UNIMPLEMENTED("No valid uses for Op*Convert until we support multiple bit widths");
349 break;
350
Chris Forbesa71b8e92019-02-10 22:42:42 +0000351 case spv::OpLoad:
352 case spv::OpAccessChain:
Chris Forbes10fd6242019-03-15 12:27:34 -0700353 case spv::OpInBoundsAccessChain:
Chris Forbesb97a9572019-02-21 16:51:42 -0800354 case spv::OpCompositeConstruct:
Chris Forbes1bc1acf2019-02-21 18:40:33 -0800355 case spv::OpCompositeInsert:
Chris Forbesb12846d2019-02-21 18:53:58 -0800356 case spv::OpCompositeExtract:
Chris Forbes83fc5442019-02-26 22:16:07 -0800357 case spv::OpVectorShuffle:
Chris Forbesfaed9d32019-03-15 10:31:08 -0700358 case spv::OpVectorTimesScalar:
Chris Forbes57e05b82019-03-28 09:16:20 +1300359 case spv::OpMatrixTimesScalar:
Chris Forbes06f4ed72019-03-28 09:53:20 +1300360 case spv::OpMatrixTimesVector:
Chris Forbesa563dd82019-03-28 10:32:55 +1300361 case spv::OpVectorTimesMatrix:
Chris Forbes51562f12019-03-28 19:08:39 -0700362 case spv::OpMatrixTimesMatrix:
Chris Forbesfaed9d32019-03-15 10:31:08 -0700363 case spv::OpVectorExtractDynamic:
364 case spv::OpVectorInsertDynamic:
Ben Claytondd1e37e2019-02-28 19:59:15 +0000365 case spv::OpNot: // Unary ops
366 case spv::OpSNegate:
367 case spv::OpFNegate:
368 case spv::OpLogicalNot:
369 case spv::OpIAdd: // Binary ops
370 case spv::OpISub:
371 case spv::OpIMul:
372 case spv::OpSDiv:
373 case spv::OpUDiv:
374 case spv::OpFAdd:
375 case spv::OpFSub:
Chris Forbes9d931532019-03-08 09:53:03 -0800376 case spv::OpFMul:
Ben Claytondd1e37e2019-02-28 19:59:15 +0000377 case spv::OpFDiv:
Chris Forbes0e4d6ff2019-03-15 13:43:36 -0700378 case spv::OpFMod:
Chris Forbes1a4c7122019-03-15 14:50:47 -0700379 case spv::OpFRem:
Ben Claytonec1aeb82019-03-04 19:33:27 +0000380 case spv::OpFOrdEqual:
381 case spv::OpFUnordEqual:
382 case spv::OpFOrdNotEqual:
383 case spv::OpFUnordNotEqual:
384 case spv::OpFOrdLessThan:
385 case spv::OpFUnordLessThan:
386 case spv::OpFOrdGreaterThan:
387 case spv::OpFUnordGreaterThan:
388 case spv::OpFOrdLessThanEqual:
389 case spv::OpFUnordLessThanEqual:
390 case spv::OpFOrdGreaterThanEqual:
391 case spv::OpFUnordGreaterThanEqual:
Ben Claytonbb8c8e22019-03-08 12:04:00 +0000392 case spv::OpSMod:
Chris Forbes71673c82019-03-14 12:55:20 -0700393 case spv::OpSRem:
Ben Claytondd1e37e2019-02-28 19:59:15 +0000394 case spv::OpUMod:
Ben Claytone95eeb12019-03-04 16:32:09 +0000395 case spv::OpIEqual:
396 case spv::OpINotEqual:
397 case spv::OpUGreaterThan:
398 case spv::OpSGreaterThan:
399 case spv::OpUGreaterThanEqual:
400 case spv::OpSGreaterThanEqual:
401 case spv::OpULessThan:
402 case spv::OpSLessThan:
403 case spv::OpULessThanEqual:
404 case spv::OpSLessThanEqual:
Ben Claytondd1e37e2019-02-28 19:59:15 +0000405 case spv::OpShiftRightLogical:
406 case spv::OpShiftRightArithmetic:
407 case spv::OpShiftLeftLogical:
408 case spv::OpBitwiseOr:
409 case spv::OpBitwiseXor:
410 case spv::OpBitwiseAnd:
411 case spv::OpLogicalOr:
412 case spv::OpLogicalAnd:
Chris Forbes787b4462019-03-08 12:16:57 -0800413 case spv::OpLogicalEqual:
414 case spv::OpLogicalNotEqual:
Chris Forbese86b6dc2019-03-01 09:08:47 -0800415 case spv::OpUMulExtended:
416 case spv::OpSMulExtended:
Chris Forbes2b287cc2019-03-01 13:24:17 -0800417 case spv::OpDot:
Chris Forbes4d503052019-03-01 17:13:57 -0800418 case spv::OpConvertFToU:
419 case spv::OpConvertFToS:
420 case spv::OpConvertSToF:
421 case spv::OpConvertUToF:
422 case spv::OpBitcast:
Ben Claytonbf943f62019-03-05 12:57:39 +0000423 case spv::OpSelect:
Chris Forbes9667a5b2019-03-07 09:26:48 -0800424 case spv::OpExtInst:
Chris Forbes3ed33ce2019-03-07 13:38:31 -0800425 case spv::OpIsInf:
426 case spv::OpIsNan:
Chris Forbes0785f692019-03-08 09:09:18 -0800427 case spv::OpAny:
428 case spv::OpAll:
Chris Forbesaff2dd02019-03-20 14:50:24 -0700429 case spv::OpDPdx:
430 case spv::OpDPdxCoarse:
431 case spv::OpDPdy:
432 case spv::OpDPdyCoarse:
433 case spv::OpFwidth:
434 case spv::OpFwidthCoarse:
435 case spv::OpDPdxFine:
436 case spv::OpDPdyFine:
437 case spv::OpFwidthFine:
Nicolas Capens5e8414e2019-03-19 16:22:35 -0400438 case spv::OpAtomicLoad:
Ben Clayton9fd02e02019-03-21 18:47:15 +0000439 case spv::OpPhi:
Chris Forbese86b6dc2019-03-01 09:08:47 -0800440 // Instructions that yield an intermediate value
Chris Forbesa71b8e92019-02-10 22:42:42 +0000441 {
Ben Claytonaf973b62019-03-13 18:19:20 +0000442 Type::ID typeId = insn.word(1);
443 Object::ID resultId = insn.word(2);
Chris Forbesa71b8e92019-02-10 22:42:42 +0000444 auto &object = defs[resultId];
Ben Clayton9a162482019-02-25 11:54:43 +0000445 object.type = typeId;
Chris Forbesa71b8e92019-02-10 22:42:42 +0000446 object.kind = Object::Kind::Value;
447 object.definition = insn;
Chris Forbesa71b8e92019-02-10 22:42:42 +0000448
Chris Forbes10fd6242019-03-15 12:27:34 -0700449 if (insn.opcode() == spv::OpAccessChain || insn.opcode() == spv::OpInBoundsAccessChain)
Chris Forbesa71b8e92019-02-10 22:42:42 +0000450 {
451 // interior ptr has two parts:
452 // - logical base ptr, common across all lanes and known at compile time
453 // - per-lane offset
Ben Claytonaf973b62019-03-13 18:19:20 +0000454 Object::ID baseId = insn.word(3);
Ben Clayton9a162482019-02-25 11:54:43 +0000455 object.pointerBase = getObject(baseId).pointerBase;
Chris Forbesa71b8e92019-02-10 22:42:42 +0000456 }
457 break;
458 }
459
Chris Forbes7edf5342019-02-10 22:41:21 +0000460 case spv::OpStore:
Nicolas Capens5e8414e2019-03-19 16:22:35 -0400461 case spv::OpAtomicStore:
Chris Forbes7edf5342019-02-10 22:41:21 +0000462 // Don't need to do anything during analysis pass
463 break;
464
Chris Forbes4a979dc2019-01-17 09:36:46 -0800465 default:
Ben Clayton00424c12019-03-17 17:29:30 +0000466 UNIMPLEMENTED("%s", OpcodeName(insn.opcode()).c_str());
Chris Forbesaf4ed532018-12-06 18:33:27 -0800467 }
468 }
Ben Clayton64f78f52019-03-21 17:21:06 +0000469
Ben Claytonfe3f0132019-03-26 11:10:16 +0000470 AssignBlockIns();
471 }
472
Ben Clayton513ed1d2019-03-28 16:07:00 +0000473 void SpirvShader::TraverseReachableBlocks(Block::ID id, SpirvShader::Block::Set& reachable)
Ben Claytonfe3f0132019-03-26 11:10:16 +0000474 {
Ben Clayton513ed1d2019-03-28 16:07:00 +0000475 if (reachable.count(id) == 0)
Ben Claytonfe3f0132019-03-26 11:10:16 +0000476 {
Ben Clayton513ed1d2019-03-28 16:07:00 +0000477 reachable.emplace(id);
478 for (auto out : getBlock(id).outs)
Ben Claytonfe3f0132019-03-26 11:10:16 +0000479 {
Ben Clayton513ed1d2019-03-28 16:07:00 +0000480 TraverseReachableBlocks(out, reachable);
Ben Claytonfe3f0132019-03-26 11:10:16 +0000481 }
482 }
483 }
484
485 void SpirvShader::AssignBlockIns()
486 {
Ben Clayton513ed1d2019-03-28 16:07:00 +0000487 Block::Set reachable;
488 TraverseReachableBlocks(mainBlockId, reachable);
489
Ben Clayton64f78f52019-03-21 17:21:06 +0000490 for (auto &it : blocks)
491 {
492 auto &blockId = it.first;
Ben Clayton513ed1d2019-03-28 16:07:00 +0000493 if (reachable.count(blockId) > 0)
Ben Clayton64f78f52019-03-21 17:21:06 +0000494 {
Ben Clayton513ed1d2019-03-28 16:07:00 +0000495 for (auto &outId : it.second.outs)
496 {
497 auto outIt = blocks.find(outId);
498 ASSERT_MSG(outIt != blocks.end(), "Block %d has a non-existent out %d", blockId.value(), outId.value());
499 auto &out = outIt->second;
500 out.ins.emplace(blockId);
501 }
Ben Clayton64f78f52019-03-21 17:21:06 +0000502 }
503 }
Chris Forbesaf4ed532018-12-06 18:33:27 -0800504 }
505
Ben Clayton0bb83b82019-02-26 11:41:07 +0000506 void SpirvShader::DeclareType(InsnIterator insn)
507 {
Ben Claytonaf973b62019-03-13 18:19:20 +0000508 Type::ID resultId = insn.word(1);
Ben Clayton0bb83b82019-02-26 11:41:07 +0000509
510 auto &type = types[resultId];
511 type.definition = insn;
512 type.sizeInComponents = ComputeTypeSize(insn);
513
514 // A structure is a builtin block if it has a builtin
515 // member. All members of such a structure are builtins.
516 switch (insn.opcode())
517 {
518 case spv::OpTypeStruct:
519 {
520 auto d = memberDecorations.find(resultId);
521 if (d != memberDecorations.end())
522 {
523 for (auto &m : d->second)
524 {
525 if (m.HasBuiltIn)
526 {
527 type.isBuiltInBlock = true;
528 break;
529 }
530 }
531 }
532 break;
533 }
534 case spv::OpTypePointer:
535 {
Ben Claytonaf973b62019-03-13 18:19:20 +0000536 Type::ID elementTypeId = insn.word(3);
Ben Clayton0bb83b82019-02-26 11:41:07 +0000537 type.element = elementTypeId;
538 type.isBuiltInBlock = getType(elementTypeId).isBuiltInBlock;
539 type.storageClass = static_cast<spv::StorageClass>(insn.word(2));
540 break;
541 }
542 case spv::OpTypeVector:
543 case spv::OpTypeMatrix:
544 case spv::OpTypeArray:
545 case spv::OpTypeRuntimeArray:
546 {
Ben Claytonaf973b62019-03-13 18:19:20 +0000547 Type::ID elementTypeId = insn.word(2);
Ben Clayton0bb83b82019-02-26 11:41:07 +0000548 type.element = elementTypeId;
549 break;
550 }
551 default:
552 break;
553 }
554 }
555
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800556 SpirvShader::Object& SpirvShader::CreateConstant(InsnIterator insn)
557 {
Ben Claytonaf973b62019-03-13 18:19:20 +0000558 Type::ID typeId = insn.word(1);
559 Object::ID resultId = insn.word(2);
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800560 auto &object = defs[resultId];
Ben Clayton9a162482019-02-25 11:54:43 +0000561 auto &objectTy = getType(typeId);
562 object.type = typeId;
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800563 object.kind = Object::Kind::Constant;
564 object.definition = insn;
Ben Clayton9a162482019-02-25 11:54:43 +0000565 object.constantValue = std::unique_ptr<uint32_t[]>(new uint32_t[objectTy.sizeInComponents]);
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800566 return object;
567 }
568
Chris Forbes049ff382019-02-02 15:16:43 -0800569 void SpirvShader::ProcessInterfaceVariable(Object &object)
Chris Forbesbde34082018-12-28 12:03:10 -0800570 {
Ben Clayton9a162482019-02-25 11:54:43 +0000571 auto &objectTy = getType(object.type);
Ben Clayton6fae32c2019-02-28 20:06:42 +0000572 ASSERT(objectTy.storageClass == spv::StorageClassInput || objectTy.storageClass == spv::StorageClassOutput);
Chris Forbesbde34082018-12-28 12:03:10 -0800573
Nicolas Capens29090852019-03-19 16:22:35 -0400574 ASSERT(objectTy.opcode() == spv::OpTypePointer);
Ben Clayton9a162482019-02-25 11:54:43 +0000575 auto pointeeTy = getType(objectTy.element);
Chris Forbesbde34082018-12-28 12:03:10 -0800576
Ben Clayton9a162482019-02-25 11:54:43 +0000577 auto &builtinInterface = (objectTy.storageClass == spv::StorageClassInput) ? inputBuiltins : outputBuiltins;
578 auto &userDefinedInterface = (objectTy.storageClass == spv::StorageClassInput) ? inputs : outputs;
579
Nicolas Capens29090852019-03-19 16:22:35 -0400580 ASSERT(object.opcode() == spv::OpVariable);
Ben Claytonaf973b62019-03-13 18:19:20 +0000581 Object::ID resultId = object.definition.word(2);
Ben Clayton9a162482019-02-25 11:54:43 +0000582
583 if (objectTy.isBuiltInBlock)
Chris Forbesbde34082018-12-28 12:03:10 -0800584 {
585 // walk the builtin block, registering each of its members separately.
Ben Clayton9a162482019-02-25 11:54:43 +0000586 auto m = memberDecorations.find(objectTy.element);
Ben Clayton6fae32c2019-02-28 20:06:42 +0000587 ASSERT(m != memberDecorations.end()); // otherwise we wouldn't have marked the type chain
Ben Clayton9a162482019-02-25 11:54:43 +0000588 auto &structType = pointeeTy.definition;
Chris Forbesbde34082018-12-28 12:03:10 -0800589 auto offset = 0u;
590 auto word = 2u;
591 for (auto &member : m->second)
592 {
Chris Forbes840809a2019-01-14 14:30:20 -0800593 auto &memberType = getType(structType.word(word));
Chris Forbesbde34082018-12-28 12:03:10 -0800594
595 if (member.HasBuiltIn)
596 {
597 builtinInterface[member.BuiltIn] = {resultId, offset, memberType.sizeInComponents};
598 }
599
600 offset += memberType.sizeInComponents;
601 ++word;
602 }
603 return;
604 }
605
606 auto d = decorations.find(resultId);
607 if (d != decorations.end() && d->second.HasBuiltIn)
608 {
Ben Clayton9a162482019-02-25 11:54:43 +0000609 builtinInterface[d->second.BuiltIn] = {resultId, 0, pointeeTy.sizeInComponents};
Chris Forbesbde34082018-12-28 12:03:10 -0800610 }
611 else
612 {
Chris Forbes049ff382019-02-02 15:16:43 -0800613 object.kind = Object::Kind::InterfaceVariable;
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800614 VisitInterface(resultId,
615 [&userDefinedInterface](Decorations const &d, AttribType type) {
616 // Populate a single scalar slot in the interface from a collection of decorations and the intended component type.
617 auto scalarSlot = (d.Location << 2) | d.Component;
Ben Clayton6fae32c2019-02-28 20:06:42 +0000618 ASSERT(scalarSlot >= 0 &&
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800619 scalarSlot < static_cast<int32_t>(userDefinedInterface.size()));
620
621 auto &slot = userDefinedInterface[scalarSlot];
622 slot.Type = type;
623 slot.Flat = d.Flat;
624 slot.NoPerspective = d.NoPerspective;
625 slot.Centroid = d.Centroid;
626 });
Chris Forbesbde34082018-12-28 12:03:10 -0800627 }
628 }
629
Chris Forbesaf4ed532018-12-06 18:33:27 -0800630 void SpirvShader::ProcessExecutionMode(InsnIterator insn)
631 {
632 auto mode = static_cast<spv::ExecutionMode>(insn.word(2));
Chris Forbes4a979dc2019-01-17 09:36:46 -0800633 switch (mode)
634 {
635 case spv::ExecutionModeEarlyFragmentTests:
636 modes.EarlyFragmentTests = true;
637 break;
638 case spv::ExecutionModeDepthReplacing:
639 modes.DepthReplacing = true;
640 break;
641 case spv::ExecutionModeDepthGreater:
642 modes.DepthGreater = true;
643 break;
644 case spv::ExecutionModeDepthLess:
645 modes.DepthLess = true;
646 break;
647 case spv::ExecutionModeDepthUnchanged:
648 modes.DepthUnchanged = true;
649 break;
650 case spv::ExecutionModeLocalSize:
Ben Clayton62758f52019-03-13 14:18:58 +0000651 modes.WorkgroupSizeX = insn.word(3);
652 modes.WorkgroupSizeY = insn.word(4);
653 modes.WorkgroupSizeZ = insn.word(5);
Chris Forbes4a979dc2019-01-17 09:36:46 -0800654 break;
655 case spv::ExecutionModeOriginUpperLeft:
656 // This is always the case for a Vulkan shader. Do nothing.
657 break;
658 default:
659 UNIMPLEMENTED("No other execution modes are permitted");
Chris Forbesaf4ed532018-12-06 18:33:27 -0800660 }
661 }
Chris Forbes739a7fb2018-12-08 13:09:40 -0800662
Ben Clayton9b156612019-03-13 19:48:31 +0000663 uint32_t SpirvShader::ComputeTypeSize(InsnIterator insn)
Chris Forbes739a7fb2018-12-08 13:09:40 -0800664 {
665 // Types are always built from the bottom up (with the exception of forward ptrs, which
666 // don't appear in Vulkan shaders. Therefore, we can always assume our component parts have
667 // already been described (and so their sizes determined)
668 switch (insn.opcode())
669 {
670 case spv::OpTypeVoid:
671 case spv::OpTypeSampler:
672 case spv::OpTypeImage:
673 case spv::OpTypeSampledImage:
674 case spv::OpTypeFunction:
675 case spv::OpTypeRuntimeArray:
676 // Objects that don't consume any space.
677 // Descriptor-backed objects currently only need exist at compile-time.
678 // Runtime arrays don't appear in places where their size would be interesting
679 return 0;
680
681 case spv::OpTypeBool:
682 case spv::OpTypeFloat:
683 case spv::OpTypeInt:
684 // All the fundamental types are 1 component. If we ever add support for 8/16/64-bit components,
685 // we might need to change this, but only 32 bit components are required for Vulkan 1.1.
686 return 1;
687
688 case spv::OpTypeVector:
689 case spv::OpTypeMatrix:
690 // Vectors and matrices both consume element count * element size.
Chris Forbes840809a2019-01-14 14:30:20 -0800691 return getType(insn.word(2)).sizeInComponents * insn.word(3);
Chris Forbes739a7fb2018-12-08 13:09:40 -0800692
693 case spv::OpTypeArray:
Chris Forbes5be4d702018-12-27 16:12:31 -0800694 {
695 // Element count * element size. Array sizes come from constant ids.
696 auto arraySize = GetConstantInt(insn.word(3));
Chris Forbes840809a2019-01-14 14:30:20 -0800697 return getType(insn.word(2)).sizeInComponents * arraySize;
Chris Forbes5be4d702018-12-27 16:12:31 -0800698 }
Chris Forbes739a7fb2018-12-08 13:09:40 -0800699
700 case spv::OpTypeStruct:
701 {
702 uint32_t size = 0;
703 for (uint32_t i = 2u; i < insn.wordCount(); i++)
704 {
Chris Forbes840809a2019-01-14 14:30:20 -0800705 size += getType(insn.word(i)).sizeInComponents;
Chris Forbes739a7fb2018-12-08 13:09:40 -0800706 }
707 return size;
708 }
709
710 case spv::OpTypePointer:
Chris Forbes0f59a2c2019-02-10 23:03:12 +0000711 // Runtime representation of a pointer is a per-lane index.
712 // Note: clients are expected to look through the pointer if they want the pointee size instead.
713 return 1;
Chris Forbes739a7fb2018-12-08 13:09:40 -0800714
715 default:
716 // Some other random insn.
717 UNIMPLEMENTED("Only types are supported");
Ben Clayton60a3d6f2019-02-26 17:24:46 +0000718 return 0;
Chris Forbes739a7fb2018-12-08 13:09:40 -0800719 }
720 }
Chris Forbesc25b8072018-12-10 15:10:39 -0800721
Ben Clayton831db962019-02-27 14:57:18 +0000722 bool SpirvShader::IsStorageInterleavedByLane(spv::StorageClass storageClass)
723 {
724 switch (storageClass)
725 {
726 case spv::StorageClassUniform:
727 case spv::StorageClassStorageBuffer:
Chris Forbesa30de542019-03-18 18:51:55 -0700728 case spv::StorageClassPushConstant:
Ben Clayton831db962019-02-27 14:57:18 +0000729 return false;
730 default:
731 return true;
732 }
733 }
734
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800735 template<typename F>
Ben Claytonaf973b62019-03-13 18:19:20 +0000736 int SpirvShader::VisitInterfaceInner(Type::ID id, Decorations d, F f) const
Chris Forbes5839dcf2018-12-10 19:02:58 -0800737 {
738 // Recursively walks variable definition and its type tree, taking into account
739 // any explicit Location or Component decorations encountered; where explicit
740 // Locations or Components are not specified, assigns them sequentially.
741 // Collected decorations are carried down toward the leaves and across
742 // siblings; Effect of decorations intentionally does not flow back up the tree.
743 //
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800744 // F is a functor to be called with the effective decoration set for every component.
745 //
746 // Returns the next available location, and calls f().
Chris Forbes5839dcf2018-12-10 19:02:58 -0800747
748 // This covers the rules in Vulkan 1.1 spec, 14.1.4 Location Assignment.
749
Chris Forbes49d664d2019-02-12 19:24:50 +0000750 ApplyDecorationsForId(&d, id);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800751
Chris Forbes840809a2019-01-14 14:30:20 -0800752 auto const &obj = getType(id);
Nicolas Capens29090852019-03-19 16:22:35 -0400753 switch(obj.opcode())
Chris Forbes5839dcf2018-12-10 19:02:58 -0800754 {
Chris Forbes5839dcf2018-12-10 19:02:58 -0800755 case spv::OpTypePointer:
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800756 return VisitInterfaceInner<F>(obj.definition.word(3), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800757 case spv::OpTypeMatrix:
758 for (auto i = 0u; i < obj.definition.word(3); i++, d.Location++)
759 {
760 // consumes same components of N consecutive locations
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800761 VisitInterfaceInner<F>(obj.definition.word(2), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800762 }
763 return d.Location;
764 case spv::OpTypeVector:
765 for (auto i = 0u; i < obj.definition.word(3); i++, d.Component++)
766 {
767 // consumes N consecutive components in the same location
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800768 VisitInterfaceInner<F>(obj.definition.word(2), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800769 }
770 return d.Location + 1;
771 case spv::OpTypeFloat:
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800772 f(d, ATTRIBTYPE_FLOAT);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800773 return d.Location + 1;
774 case spv::OpTypeInt:
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800775 f(d, obj.definition.word(3) ? ATTRIBTYPE_INT : ATTRIBTYPE_UINT);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800776 return d.Location + 1;
777 case spv::OpTypeBool:
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800778 f(d, ATTRIBTYPE_UINT);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800779 return d.Location + 1;
780 case spv::OpTypeStruct:
781 {
Chris Forbes5839dcf2018-12-10 19:02:58 -0800782 // iterate over members, which may themselves have Location/Component decorations
783 for (auto i = 0u; i < obj.definition.wordCount() - 2; i++)
784 {
Chris Forbes49d664d2019-02-12 19:24:50 +0000785 ApplyDecorationsForIdMember(&d, id, i);
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800786 d.Location = VisitInterfaceInner<F>(obj.definition.word(i + 2), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800787 d.Component = 0; // Implicit locations always have component=0
788 }
789 return d.Location;
790 }
Chris Forbes5be4d702018-12-27 16:12:31 -0800791 case spv::OpTypeArray:
792 {
793 auto arraySize = GetConstantInt(obj.definition.word(3));
794 for (auto i = 0u; i < arraySize; i++)
795 {
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800796 d.Location = VisitInterfaceInner<F>(obj.definition.word(2), d, f);
Chris Forbes5be4d702018-12-27 16:12:31 -0800797 }
798 return d.Location;
799 }
Chris Forbes5839dcf2018-12-10 19:02:58 -0800800 default:
801 // Intentionally partial; most opcodes do not participate in type hierarchies
802 return 0;
803 }
804 }
805
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800806 template<typename F>
Ben Claytonaf973b62019-03-13 18:19:20 +0000807 void SpirvShader::VisitInterface(Object::ID id, F f) const
Chris Forbes5839dcf2018-12-10 19:02:58 -0800808 {
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800809 // Walk a variable definition and call f for each component in it.
Chris Forbes5839dcf2018-12-10 19:02:58 -0800810 Decorations d{};
Chris Forbes49d664d2019-02-12 19:24:50 +0000811 ApplyDecorationsForId(&d, id);
Chris Forbes1c658232019-02-01 17:12:25 -0800812
813 auto def = getObject(id).definition;
Ben Clayton6fae32c2019-02-28 20:06:42 +0000814 ASSERT(def.opcode() == spv::OpVariable);
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800815 VisitInterfaceInner<F>(def.word(1), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800816 }
817
Chris Forbesa30de542019-03-18 18:51:55 -0700818 SIMD::Int SpirvShader::WalkExplicitLayoutAccessChain(Object::ID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const
819 {
820 // Produce a offset into external memory in sizeof(float) units
821
822 int constantOffset = 0;
823 SIMD::Int dynamicOffset = SIMD::Int(0);
824 auto &baseObject = getObject(id);
825 Type::ID typeId = getType(baseObject.type).element;
Chris Forbesfe1dd4b2019-03-19 09:06:19 -0700826 Decorations d{};
827 ApplyDecorationsForId(&d, baseObject.type);
Chris Forbesa30de542019-03-18 18:51:55 -0700828
829 // The <base> operand is an intermediate value itself, ie produced by a previous OpAccessChain.
830 // Start with its offset and build from there.
831 if (baseObject.kind == Object::Kind::Value)
832 {
833 dynamicOffset += routine->getIntermediate(id).Int(0);
834 }
835
836 for (auto i = 0u; i < numIndexes; i++)
837 {
838 auto & type = getType(typeId);
839 switch (type.definition.opcode())
840 {
841 case spv::OpTypeStruct:
842 {
843 int memberIndex = GetConstantInt(indexIds[i]);
Chris Forbesa30de542019-03-18 18:51:55 -0700844 ApplyDecorationsForIdMember(&d, typeId, memberIndex);
845 ASSERT(d.HasOffset);
846 constantOffset += d.Offset / sizeof(float);
847 typeId = type.definition.word(2u + memberIndex);
848 break;
849 }
850 case spv::OpTypeArray:
851 case spv::OpTypeRuntimeArray:
852 {
853 // TODO: b/127950082: Check bounds.
Chris Forbesa30de542019-03-18 18:51:55 -0700854 ApplyDecorationsForId(&d, typeId);
855 ASSERT(d.HasArrayStride);
856 auto & obj = getObject(indexIds[i]);
857 if (obj.kind == Object::Kind::Constant)
858 constantOffset += d.ArrayStride/sizeof(float) * GetConstantInt(indexIds[i]);
859 else
860 dynamicOffset += SIMD::Int(d.ArrayStride / sizeof(float)) * routine->getIntermediate(indexIds[i]).Int(0);
861 typeId = type.element;
862 break;
863 }
864 case spv::OpTypeMatrix:
865 {
866 // TODO: b/127950082: Check bounds.
Chris Forbesa30de542019-03-18 18:51:55 -0700867 ApplyDecorationsForId(&d, typeId);
868 ASSERT(d.HasMatrixStride);
869 auto & obj = getObject(indexIds[i]);
870 if (obj.kind == Object::Kind::Constant)
871 constantOffset += d.MatrixStride/sizeof(float) * GetConstantInt(indexIds[i]);
872 else
873 dynamicOffset += SIMD::Int(d.MatrixStride / sizeof(float)) * routine->getIntermediate(indexIds[i]).Int(0);
874 typeId = type.element;
875 break;
876 }
877 case spv::OpTypeVector:
878 {
879 auto & obj = getObject(indexIds[i]);
880 if (obj.kind == Object::Kind::Constant)
881 constantOffset += GetConstantInt(indexIds[i]);
882 else
883 dynamicOffset += routine->getIntermediate(indexIds[i]).Int(0);
884 typeId = type.element;
885 break;
886 }
887 default:
888 UNIMPLEMENTED("Unexpected type '%s' in WalkExplicitLayoutAccessChain", OpcodeName(type.definition.opcode()).c_str());
889 }
890 }
891
892 return dynamicOffset + SIMD::Int(constantOffset);
893 }
894
Ben Claytonaf973b62019-03-13 18:19:20 +0000895 SIMD::Int SpirvShader::WalkAccessChain(Object::ID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const
Chris Forbes38f85b32019-02-12 20:10:05 +0000896 {
Chris Forbes38f85b32019-02-12 20:10:05 +0000897 // TODO: avoid doing per-lane work in some cases if we can?
Chris Forbesa30de542019-03-18 18:51:55 -0700898 // Produce a *component* offset into location-oriented memory
Chris Forbes38f85b32019-02-12 20:10:05 +0000899
Chris Forbes6397ed02019-02-15 16:39:17 -0800900 int constantOffset = 0;
Ben Clayton24ea5152019-02-26 11:02:42 +0000901 SIMD::Int dynamicOffset = SIMD::Int(0);
Ben Clayton9a162482019-02-25 11:54:43 +0000902 auto &baseObject = getObject(id);
Ben Claytonaf973b62019-03-13 18:19:20 +0000903 Type::ID typeId = getType(baseObject.type).element;
Chris Forbes38f85b32019-02-12 20:10:05 +0000904
Chris Forbese4ef5f72019-02-15 16:00:08 -0800905 // The <base> operand is an intermediate value itself, ie produced by a previous OpAccessChain.
906 // Start with its offset and build from there.
Chris Forbes38f85b32019-02-12 20:10:05 +0000907 if (baseObject.kind == Object::Kind::Value)
Ben Clayton9b62c5e2019-03-08 09:32:34 +0000908 {
909 dynamicOffset += routine->getIntermediate(id).Int(0);
910 }
Chris Forbes38f85b32019-02-12 20:10:05 +0000911
912 for (auto i = 0u; i < numIndexes; i++)
913 {
914 auto & type = getType(typeId);
Nicolas Capens29090852019-03-19 16:22:35 -0400915 switch(type.opcode())
Chris Forbes38f85b32019-02-12 20:10:05 +0000916 {
917 case spv::OpTypeStruct:
918 {
919 int memberIndex = GetConstantInt(indexIds[i]);
920 int offsetIntoStruct = 0;
921 for (auto j = 0; j < memberIndex; j++) {
Chris Forbes58bee562019-02-19 17:41:41 -0800922 auto memberType = type.definition.word(2u + j);
923 offsetIntoStruct += getType(memberType).sizeInComponents;
Chris Forbes38f85b32019-02-12 20:10:05 +0000924 }
Chris Forbes6397ed02019-02-15 16:39:17 -0800925 constantOffset += offsetIntoStruct;
Chris Forbes58bee562019-02-19 17:41:41 -0800926 typeId = type.definition.word(2u + memberIndex);
Chris Forbes38f85b32019-02-12 20:10:05 +0000927 break;
928 }
929
930 case spv::OpTypeVector:
931 case spv::OpTypeMatrix:
932 case spv::OpTypeArray:
Ben Claytonfa8603c2019-03-08 16:51:42 +0000933 case spv::OpTypeRuntimeArray:
Chris Forbes38f85b32019-02-12 20:10:05 +0000934 {
Ben Claytonfa8603c2019-03-08 16:51:42 +0000935 // TODO: b/127950082: Check bounds.
Ben Clayton9a162482019-02-25 11:54:43 +0000936 auto stride = getType(type.element).sizeInComponents;
Chris Forbes38f85b32019-02-12 20:10:05 +0000937 auto & obj = getObject(indexIds[i]);
938 if (obj.kind == Object::Kind::Constant)
Chris Forbes6397ed02019-02-15 16:39:17 -0800939 constantOffset += stride * GetConstantInt(indexIds[i]);
Chris Forbes38f85b32019-02-12 20:10:05 +0000940 else
Ben Clayton9b62c5e2019-03-08 09:32:34 +0000941 dynamicOffset += SIMD::Int(stride) * routine->getIntermediate(indexIds[i]).Int(0);
Ben Clayton9a162482019-02-25 11:54:43 +0000942 typeId = type.element;
Chris Forbes38f85b32019-02-12 20:10:05 +0000943 break;
944 }
945
946 default:
Nicolas Capens29090852019-03-19 16:22:35 -0400947 UNIMPLEMENTED("Unexpected type '%s' in WalkAccessChain", OpcodeName(type.opcode()).c_str());
Chris Forbes38f85b32019-02-12 20:10:05 +0000948 }
949 }
950
Ben Clayton24ea5152019-02-26 11:02:42 +0000951 return dynamicOffset + SIMD::Int(constantOffset);
Chris Forbes38f85b32019-02-12 20:10:05 +0000952 }
953
Ben Claytonaf973b62019-03-13 18:19:20 +0000954 uint32_t SpirvShader::WalkLiteralAccessChain(Type::ID typeId, uint32_t numIndexes, uint32_t const *indexes) const
Chris Forbes9638b942019-02-21 18:39:31 -0800955 {
956 uint32_t constantOffset = 0;
957
958 for (auto i = 0u; i < numIndexes; i++)
959 {
960 auto & type = getType(typeId);
Nicolas Capens29090852019-03-19 16:22:35 -0400961 switch(type.opcode())
Chris Forbes9638b942019-02-21 18:39:31 -0800962 {
963 case spv::OpTypeStruct:
964 {
965 int memberIndex = indexes[i];
966 int offsetIntoStruct = 0;
967 for (auto j = 0; j < memberIndex; j++) {
968 auto memberType = type.definition.word(2u + j);
969 offsetIntoStruct += getType(memberType).sizeInComponents;
970 }
971 constantOffset += offsetIntoStruct;
972 typeId = type.definition.word(2u + memberIndex);
973 break;
974 }
975
976 case spv::OpTypeVector:
977 case spv::OpTypeMatrix:
978 case spv::OpTypeArray:
979 {
980 auto elementType = type.definition.word(2);
981 auto stride = getType(elementType).sizeInComponents;
982 constantOffset += stride * indexes[i];
983 typeId = elementType;
984 break;
985 }
986
987 default:
988 UNIMPLEMENTED("Unexpected type in WalkLiteralAccessChain");
989 }
990 }
991
992 return constantOffset;
993 }
994
Chris Forbesc25b8072018-12-10 15:10:39 -0800995 void SpirvShader::Decorations::Apply(spv::Decoration decoration, uint32_t arg)
996 {
997 switch (decoration)
998 {
999 case spv::DecorationLocation:
1000 HasLocation = true;
1001 Location = static_cast<int32_t>(arg);
1002 break;
1003 case spv::DecorationComponent:
1004 HasComponent = true;
1005 Component = arg;
1006 break;
Ben Claytond073d8e2019-02-26 11:06:50 +00001007 case spv::DecorationDescriptorSet:
1008 HasDescriptorSet = true;
1009 DescriptorSet = arg;
1010 break;
1011 case spv::DecorationBinding:
1012 HasBinding = true;
1013 Binding = arg;
1014 break;
Chris Forbesc25b8072018-12-10 15:10:39 -08001015 case spv::DecorationBuiltIn:
1016 HasBuiltIn = true;
1017 BuiltIn = static_cast<spv::BuiltIn>(arg);
1018 break;
1019 case spv::DecorationFlat:
1020 Flat = true;
1021 break;
1022 case spv::DecorationNoPerspective:
Chris Forbes5839dcf2018-12-10 19:02:58 -08001023 NoPerspective = true;
Chris Forbesc25b8072018-12-10 15:10:39 -08001024 break;
1025 case spv::DecorationCentroid:
1026 Centroid = true;
1027 break;
1028 case spv::DecorationBlock:
1029 Block = true;
1030 break;
1031 case spv::DecorationBufferBlock:
1032 BufferBlock = true;
1033 break;
Chris Forbes65321072019-03-07 16:13:56 -08001034 case spv::DecorationOffset:
1035 HasOffset = true;
1036 Offset = static_cast<int32_t>(arg);
1037 break;
1038 case spv::DecorationArrayStride:
1039 HasArrayStride = true;
1040 ArrayStride = static_cast<int32_t>(arg);
1041 break;
1042 case spv::DecorationMatrixStride:
1043 HasMatrixStride = true;
1044 MatrixStride = static_cast<int32_t>(arg);
1045 break;
Chris Forbesc25b8072018-12-10 15:10:39 -08001046 default:
1047 // Intentionally partial, there are many decorations we just don't care about.
1048 break;
1049 }
1050 }
1051
1052 void SpirvShader::Decorations::Apply(const sw::SpirvShader::Decorations &src)
1053 {
1054 // Apply a decoration group to this set of decorations
1055 if (src.HasBuiltIn)
1056 {
1057 HasBuiltIn = true;
1058 BuiltIn = src.BuiltIn;
1059 }
1060
1061 if (src.HasLocation)
1062 {
1063 HasLocation = true;
1064 Location = src.Location;
1065 }
1066
1067 if (src.HasComponent)
1068 {
1069 HasComponent = true;
1070 Component = src.Component;
1071 }
1072
Ben Claytond073d8e2019-02-26 11:06:50 +00001073 if (src.HasDescriptorSet)
1074 {
1075 HasDescriptorSet = true;
1076 DescriptorSet = src.DescriptorSet;
1077 }
1078
1079 if (src.HasBinding)
1080 {
1081 HasBinding = true;
1082 Binding = src.Binding;
1083 }
1084
Chris Forbes65321072019-03-07 16:13:56 -08001085 if (src.HasOffset)
1086 {
1087 HasOffset = true;
1088 Offset = src.Offset;
1089 }
1090
1091 if (src.HasArrayStride)
1092 {
1093 HasArrayStride = true;
1094 ArrayStride = src.ArrayStride;
1095 }
1096
1097 if (src.HasMatrixStride)
1098 {
1099 HasMatrixStride = true;
1100 MatrixStride = src.MatrixStride;
1101 }
1102
Chris Forbesc25b8072018-12-10 15:10:39 -08001103 Flat |= src.Flat;
Chris Forbes5839dcf2018-12-10 19:02:58 -08001104 NoPerspective |= src.NoPerspective;
Chris Forbesc25b8072018-12-10 15:10:39 -08001105 Centroid |= src.Centroid;
1106 Block |= src.Block;
1107 BufferBlock |= src.BufferBlock;
1108 }
Chris Forbesbc3a0ee2018-12-27 16:02:58 -08001109
Ben Claytonab51bbf2019-02-20 14:36:27 +00001110 void SpirvShader::ApplyDecorationsForId(Decorations *d, TypeOrObjectID id) const
Chris Forbes49d664d2019-02-12 19:24:50 +00001111 {
1112 auto it = decorations.find(id);
1113 if (it != decorations.end())
1114 d->Apply(it->second);
1115 }
1116
Ben Claytonaf973b62019-03-13 18:19:20 +00001117 void SpirvShader::ApplyDecorationsForIdMember(Decorations *d, Type::ID id, uint32_t member) const
Chris Forbes49d664d2019-02-12 19:24:50 +00001118 {
1119 auto it = memberDecorations.find(id);
1120 if (it != memberDecorations.end() && member < it->second.size())
1121 {
1122 d->Apply(it->second[member]);
1123 }
1124 }
1125
Ben Claytonaf973b62019-03-13 18:19:20 +00001126 uint32_t SpirvShader::GetConstantInt(Object::ID id) const
Chris Forbesbc3a0ee2018-12-27 16:02:58 -08001127 {
1128 // Slightly hackish access to constants very early in translation.
1129 // General consumption of constants by other instructions should
1130 // probably be just lowered to Reactor.
1131
1132 // TODO: not encountered yet since we only use this for array sizes etc,
1133 // but is possible to construct integer constant 0 via OpConstantNull.
Chris Forbesb8fb08a2019-02-13 11:45:27 -08001134 auto insn = getObject(id).definition;
Ben Clayton6fae32c2019-02-28 20:06:42 +00001135 ASSERT(insn.opcode() == spv::OpConstant);
Nicolas Capens29090852019-03-19 16:22:35 -04001136 ASSERT(getType(insn.word(1)).opcode() == spv::OpTypeInt);
Chris Forbesbc3a0ee2018-12-27 16:02:58 -08001137 return insn.word(3);
1138 }
Chris Forbesd5aed492019-02-02 15:18:52 -08001139
1140 // emit-time
1141
Chris Forbesc61271e2019-02-19 17:01:28 -08001142 void SpirvShader::emitProlog(SpirvRoutine *routine) const
Chris Forbesd5aed492019-02-02 15:18:52 -08001143 {
1144 for (auto insn : *this)
1145 {
1146 switch (insn.opcode())
1147 {
1148 case spv::OpVariable:
1149 {
Nicolas Capens29090852019-03-19 16:22:35 -04001150 Type::ID resultPointerTypeId = insn.word(1);
1151 auto resultPointerType = getType(resultPointerTypeId);
1152 auto pointeeType = getType(resultPointerType.element);
1153
1154 if(pointeeType.sizeInComponents > 0) // TODO: what to do about zero-slot objects?
Chris Forbesd5aed492019-02-02 15:18:52 -08001155 {
Nicolas Capens29090852019-03-19 16:22:35 -04001156 Object::ID resultId = insn.word(2);
1157 routine->createLvalue(resultId, pointeeType.sizeInComponents);
Chris Forbesd5aed492019-02-02 15:18:52 -08001158 }
1159 break;
1160 }
1161 default:
Chris Forbese9f8f5b2019-02-11 00:20:16 +00001162 // Nothing else produces interface variables, so can all be safely ignored.
Chris Forbesd5aed492019-02-02 15:18:52 -08001163 break;
1164 }
1165 }
1166 }
1167
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001168 void SpirvShader::emit(SpirvRoutine *routine, RValue<SIMD::Int> const &activeLaneMask) const
Chris Forbesd5aed492019-02-02 15:18:52 -08001169 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001170 EmitState state;
1171 state.setActiveLaneMask(activeLaneMask);
1172 state.routine = routine;
1173
Ben Clayton9b156612019-03-13 19:48:31 +00001174 // Emit everything up to the first label
1175 // TODO: Separate out dispatch of block from non-block instructions?
Chris Forbesd5aed492019-02-02 15:18:52 -08001176 for (auto insn : *this)
1177 {
Ben Clayton9b156612019-03-13 19:48:31 +00001178 if (insn.opcode() == spv::OpLabel)
Chris Forbesd5aed492019-02-02 15:18:52 -08001179 {
Chris Forbesd5aed492019-02-02 15:18:52 -08001180 break;
1181 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001182 EmitInstruction(insn, &state);
Ben Clayton9b156612019-03-13 19:48:31 +00001183 }
1184
Ben Clayton513ed1d2019-03-28 16:07:00 +00001185 // Emit all the blocks starting from mainBlockId.
1186 EmitBlocks(mainBlockId, &state);
1187 }
1188
1189 void SpirvShader::EmitBlocks(Block::ID id, EmitState *state, Block::ID ignore /* = 0 */) const
1190 {
1191 auto oldPending = state->pending;
1192
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001193 std::queue<Block::ID> pending;
Ben Clayton513ed1d2019-03-28 16:07:00 +00001194 state->pending = &pending;
1195 pending.push(id);
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001196 while (pending.size() > 0)
Ben Clayton9b156612019-03-13 19:48:31 +00001197 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001198 auto id = pending.front();
1199 pending.pop();
Ben Clayton513ed1d2019-03-28 16:07:00 +00001200
1201 auto const &block = getBlock(id);
1202 if (id == ignore)
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001203 {
Ben Clayton513ed1d2019-03-28 16:07:00 +00001204 continue;
1205 }
1206
1207 state->currentBlock = id;
1208
1209 switch (block.kind)
1210 {
1211 case Block::Simple:
1212 case Block::StructuredBranchConditional:
1213 case Block::UnstructuredBranchConditional:
1214 case Block::StructuredSwitch:
1215 case Block::UnstructuredSwitch:
1216 EmitNonLoop(state);
1217 break;
1218
1219 case Block::Loop:
1220 EmitLoop(state);
1221 break;
1222
1223 default:
1224 UNREACHABLE("Unexpected Block Kind: %d", int(block.kind));
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001225 }
Ben Clayton9b156612019-03-13 19:48:31 +00001226 }
Ben Clayton9b156612019-03-13 19:48:31 +00001227
Ben Clayton513ed1d2019-03-28 16:07:00 +00001228 state->pending = oldPending;
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001229 }
1230
1231 void SpirvShader::EmitInstructions(InsnIterator begin, InsnIterator end, EmitState *state) const
1232 {
1233 for (auto insn = begin; insn != end; insn++)
1234 {
1235 auto res = EmitInstruction(insn, state);
1236 switch (res)
1237 {
1238 case EmitResult::Continue:
1239 continue;
1240 case EmitResult::Terminator:
1241 break;
1242 default:
1243 UNREACHABLE("Unexpected EmitResult %d", int(res));
1244 break;
1245 }
1246 }
1247 }
1248
Ben Clayton513ed1d2019-03-28 16:07:00 +00001249 void SpirvShader::EmitNonLoop(EmitState *state) const
1250 {
1251 auto blockId = state->currentBlock;
1252 auto block = getBlock(blockId);
1253
1254 // Ensure all incoming blocks have been generated.
1255 auto depsDone = true;
1256 for (auto in : block.ins)
1257 {
1258 if (state->visited.count(in) == 0)
1259 {
1260 state->pending->emplace(in);
1261 depsDone = false;
1262 }
1263 }
1264
1265 if (!depsDone)
1266 {
1267 // come back to this once the dependencies have been generated
1268 state->pending->emplace(blockId);
1269 return;
1270 }
1271
1272 if (!state->visited.emplace(blockId).second)
1273 {
1274 return; // Already generated this block.
1275 }
1276
1277 if (blockId != mainBlockId)
1278 {
1279 // Set the activeLaneMask.
Nicolas Capens459453a2019-03-27 15:27:27 -04001280 SIMD::Int activeLaneMask(0);
Ben Clayton513ed1d2019-03-28 16:07:00 +00001281 for (auto in : block.ins)
1282 {
1283 auto inMask = GetActiveLaneMaskEdge(state, in, blockId);
Nicolas Capens459453a2019-03-27 15:27:27 -04001284 activeLaneMask |= inMask;
Ben Clayton513ed1d2019-03-28 16:07:00 +00001285 }
Nicolas Capens459453a2019-03-27 15:27:27 -04001286 state->setActiveLaneMask(activeLaneMask);
Ben Clayton513ed1d2019-03-28 16:07:00 +00001287 }
1288
1289 EmitInstructions(block.begin(), block.end(), state);
1290
1291 for (auto out : block.outs)
1292 {
1293 state->pending->emplace(out);
1294 }
1295 }
1296
Ben Claytone747b3c2019-03-21 19:35:15 +00001297 void SpirvShader::EmitLoop(EmitState *state) const
1298 {
1299 auto blockId = state->currentBlock;
1300 auto block = getBlock(blockId);
1301
Ben Clayton513ed1d2019-03-28 16:07:00 +00001302 // Ensure all incoming non-back edge blocks have been generated.
1303 auto depsDone = true;
1304 for (auto in : block.ins)
1305 {
1306 if (state->visited.count(in) == 0)
1307 {
1308 if (!existsPath(blockId, in, block.mergeBlock)) // if not a loop back edge
1309 {
1310 state->pending->emplace(in);
1311 depsDone = false;
1312 }
1313 }
1314 }
1315
1316 if (!depsDone)
1317 {
1318 // come back to this once the dependencies have been generated
1319 state->pending->emplace(blockId);
1320 return;
1321 }
1322
1323 if (!state->visited.emplace(blockId).second)
1324 {
1325 return; // Already emitted this loop.
1326 }
1327
Ben Claytone747b3c2019-03-21 19:35:15 +00001328 // loopActiveLaneMask is the mask of lanes that are continuing to loop.
1329 // This is initialized with the incoming active lane masks.
1330 SIMD::Int loopActiveLaneMask = SIMD::Int(0);
1331 for (auto in : block.ins)
1332 {
Ben Clayton513ed1d2019-03-28 16:07:00 +00001333 if (!existsPath(blockId, in, block.mergeBlock)) // if not a loop back edge
Ben Claytone747b3c2019-03-21 19:35:15 +00001334 {
Ben Claytonfe3f0132019-03-26 11:10:16 +00001335 loopActiveLaneMask |= GetActiveLaneMaskEdge(state, in, blockId);
Ben Claytone747b3c2019-03-21 19:35:15 +00001336 }
1337 }
1338
1339 // Generate an alloca for each of the loop's phis.
1340 // These will be primed with the incoming, non back edge Phi values
1341 // before the loop, and then updated just before the loop jumps back to
1342 // the block.
1343 struct LoopPhi
1344 {
Nicolas Capens5da8d8d2019-03-27 14:45:34 -04001345 LoopPhi(Object::ID id, uint32_t size) : phiId(id), storage(size) {}
1346
Ben Claytone747b3c2019-03-21 19:35:15 +00001347 Object::ID phiId; // The Phi identifier.
1348 Object::ID continueValue; // The source merge value from the loop.
1349 Array<SIMD::Int> storage; // The alloca.
1350 };
1351
1352 std::vector<LoopPhi> phis;
1353
1354 // For each OpPhi between the block start and the merge instruction:
1355 for (auto insn = block.begin(); insn != block.mergeInstruction; insn++)
1356 {
1357 if (insn.opcode() == spv::OpPhi)
1358 {
1359 auto objectId = Object::ID(insn.word(2));
1360 auto &object = getObject(objectId);
1361 auto &type = getType(object.type);
1362
Nicolas Capens5da8d8d2019-03-27 14:45:34 -04001363 LoopPhi phi(insn.word(2), type.sizeInComponents);
Ben Claytone747b3c2019-03-21 19:35:15 +00001364
1365 // Start with the Phi set to 0.
1366 for (uint32_t i = 0; i < type.sizeInComponents; i++)
1367 {
1368 phi.storage[i] = SIMD::Int(0);
1369 }
1370
1371 // For each Phi source:
1372 for (uint32_t w = 3; w < insn.wordCount(); w += 2)
1373 {
1374 auto varId = Object::ID(insn.word(w + 0));
1375 auto blockId = Block::ID(insn.word(w + 1));
Ben Clayton513ed1d2019-03-28 16:07:00 +00001376 if (existsPath(state->currentBlock, blockId, block.mergeBlock))
Ben Claytone747b3c2019-03-21 19:35:15 +00001377 {
1378 // This source is from a loop back-edge.
1379 ASSERT(phi.continueValue == 0 || phi.continueValue == varId);
1380 phi.continueValue = varId;
1381 }
1382 else
1383 {
1384 // This source is from a preceding block.
1385 for (uint32_t i = 0; i < type.sizeInComponents; i++)
1386 {
1387 auto in = GenericValue(this, state->routine, varId);
Ben Claytonfe3f0132019-03-26 11:10:16 +00001388 auto mask = GetActiveLaneMaskEdge(state, blockId, state->currentBlock);
Ben Claytone747b3c2019-03-21 19:35:15 +00001389 phi.storage[i] = phi.storage[i] | (in.Int(i) & mask);
1390 }
1391 }
1392 }
1393
1394 phis.push_back(phi);
1395 }
1396 }
1397
1398 // Create the loop basic blocks
1399 auto headerBasicBlock = Nucleus::createBasicBlock();
1400 auto mergeBasicBlock = Nucleus::createBasicBlock();
1401
1402 // Start emitting code inside the loop.
1403 Nucleus::createBr(headerBasicBlock);
1404 Nucleus::setInsertBlock(headerBasicBlock);
1405
1406 // Load the Phi values from storage.
1407 // This will load at the start of each loop.
1408 for (auto &phi : phis)
1409 {
1410 auto &type = getType(getObject(phi.phiId).type);
1411 auto &dst = state->routine->createIntermediate(phi.phiId, type.sizeInComponents);
1412 for (unsigned int i = 0u; i < type.sizeInComponents; i++)
1413 {
1414 dst.move(i, phi.storage[i]);
1415 }
1416 }
1417
1418 // Load the active lane mask.
1419 state->setActiveLaneMask(loopActiveLaneMask);
1420
1421 // Emit all the non-phi instructions in this loop header block.
1422 for (auto insn = block.begin(); insn != block.end(); insn++)
1423 {
1424 if (insn.opcode() != spv::OpPhi)
1425 {
1426 EmitInstruction(insn, state);
1427 }
1428 }
1429
Ben Clayton513ed1d2019-03-28 16:07:00 +00001430 // Emit all loop blocks, but don't emit the merge block yet.
1431 for (auto out : block.outs)
1432 {
1433 if (existsPath(out, blockId, block.mergeBlock))
1434 {
1435 EmitBlocks(out, state, block.mergeBlock);
1436 }
1437 }
1438
1439 // Rebuild the loopActiveLaneMask from the loop back edges.
Ben Claytone747b3c2019-03-21 19:35:15 +00001440 loopActiveLaneMask = SIMD::Int(0);
1441 for (auto in : block.ins)
1442 {
Ben Clayton513ed1d2019-03-28 16:07:00 +00001443 if (existsPath(blockId, in, block.mergeBlock))
Ben Claytone747b3c2019-03-21 19:35:15 +00001444 {
Ben Claytonfe3f0132019-03-26 11:10:16 +00001445 loopActiveLaneMask |= GetActiveLaneMaskEdge(state, in, blockId);
Ben Claytone747b3c2019-03-21 19:35:15 +00001446 }
1447 }
1448
1449 // Update loop phi values
1450 for (auto &phi : phis)
1451 {
1452 if (phi.continueValue != 0)
1453 {
1454 auto val = GenericValue(this, state->routine, phi.continueValue);
1455 auto &type = getType(getObject(phi.phiId).type);
1456 for (unsigned int i = 0u; i < type.sizeInComponents; i++)
1457 {
1458 phi.storage[i] = val.Int(i);
1459 }
1460 }
1461 }
1462
1463 // Loop body now done.
1464 // If any lanes are still active, jump back to the loop header,
1465 // otherwise jump to the merge block.
1466 Nucleus::createCondBr(AnyTrue(loopActiveLaneMask).value, headerBasicBlock, mergeBasicBlock);
1467
Ben Clayton513ed1d2019-03-28 16:07:00 +00001468 // Continue emitting from the merge block.
Ben Claytone747b3c2019-03-21 19:35:15 +00001469 Nucleus::setInsertBlock(mergeBasicBlock);
Ben Clayton513ed1d2019-03-28 16:07:00 +00001470 state->pending->emplace(block.mergeBlock);
Ben Claytone747b3c2019-03-21 19:35:15 +00001471 }
1472
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001473 SpirvShader::EmitResult SpirvShader::EmitInstruction(InsnIterator insn, EmitState *state) const
Ben Clayton9b156612019-03-13 19:48:31 +00001474 {
1475 switch (insn.opcode())
1476 {
1477 case spv::OpTypeVoid:
1478 case spv::OpTypeInt:
1479 case spv::OpTypeFloat:
1480 case spv::OpTypeBool:
1481 case spv::OpTypeVector:
1482 case spv::OpTypeArray:
1483 case spv::OpTypeRuntimeArray:
1484 case spv::OpTypeMatrix:
1485 case spv::OpTypeStruct:
1486 case spv::OpTypePointer:
1487 case spv::OpTypeFunction:
1488 case spv::OpExecutionMode:
1489 case spv::OpMemoryModel:
1490 case spv::OpFunction:
1491 case spv::OpFunctionEnd:
1492 case spv::OpConstant:
1493 case spv::OpConstantNull:
1494 case spv::OpConstantTrue:
1495 case spv::OpConstantFalse:
1496 case spv::OpConstantComposite:
Chris Forbes0e712412019-03-18 19:31:16 -07001497 case spv::OpUndef:
Ben Clayton9b156612019-03-13 19:48:31 +00001498 case spv::OpExtension:
1499 case spv::OpCapability:
1500 case spv::OpEntryPoint:
1501 case spv::OpExtInstImport:
1502 case spv::OpDecorate:
1503 case spv::OpMemberDecorate:
1504 case spv::OpGroupDecorate:
1505 case spv::OpGroupMemberDecorate:
1506 case spv::OpDecorationGroup:
1507 case spv::OpName:
1508 case spv::OpMemberName:
1509 case spv::OpSource:
1510 case spv::OpSourceContinued:
1511 case spv::OpSourceExtension:
1512 case spv::OpLine:
1513 case spv::OpNoLine:
1514 case spv::OpModuleProcessed:
1515 case spv::OpString:
1516 // Nothing to do at emit time. These are either fully handled at analysis time,
1517 // or don't require any work at all.
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001518 return EmitResult::Continue;
Ben Clayton9b156612019-03-13 19:48:31 +00001519
1520 case spv::OpLabel:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001521 return EmitResult::Continue;
Ben Clayton9b156612019-03-13 19:48:31 +00001522
1523 case spv::OpVariable:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001524 return EmitVariable(insn, state);
Ben Clayton9b156612019-03-13 19:48:31 +00001525
1526 case spv::OpLoad:
Nicolas Capens5e8414e2019-03-19 16:22:35 -04001527 case spv::OpAtomicLoad:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001528 return EmitLoad(insn, state);
Ben Clayton9b156612019-03-13 19:48:31 +00001529
1530 case spv::OpStore:
Nicolas Capens5e8414e2019-03-19 16:22:35 -04001531 case spv::OpAtomicStore:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001532 return EmitStore(insn, state);
Ben Clayton9b156612019-03-13 19:48:31 +00001533
1534 case spv::OpAccessChain:
Chris Forbes10fd6242019-03-15 12:27:34 -07001535 case spv::OpInBoundsAccessChain:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001536 return EmitAccessChain(insn, state);
Ben Clayton9b156612019-03-13 19:48:31 +00001537
1538 case spv::OpCompositeConstruct:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001539 return EmitCompositeConstruct(insn, state);
Ben Clayton9b156612019-03-13 19:48:31 +00001540
1541 case spv::OpCompositeInsert:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001542 return EmitCompositeInsert(insn, state);
Ben Clayton9b156612019-03-13 19:48:31 +00001543
1544 case spv::OpCompositeExtract:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001545 return EmitCompositeExtract(insn, state);
Ben Clayton9b156612019-03-13 19:48:31 +00001546
1547 case spv::OpVectorShuffle:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001548 return EmitVectorShuffle(insn, state);
Ben Clayton9b156612019-03-13 19:48:31 +00001549
Chris Forbesfaed9d32019-03-15 10:31:08 -07001550 case spv::OpVectorExtractDynamic:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001551 return EmitVectorExtractDynamic(insn, state);
Chris Forbesfaed9d32019-03-15 10:31:08 -07001552
1553 case spv::OpVectorInsertDynamic:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001554 return EmitVectorInsertDynamic(insn, state);
Chris Forbesfaed9d32019-03-15 10:31:08 -07001555
Ben Clayton9b156612019-03-13 19:48:31 +00001556 case spv::OpVectorTimesScalar:
Chris Forbes57e05b82019-03-28 09:16:20 +13001557 case spv::OpMatrixTimesScalar:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001558 return EmitVectorTimesScalar(insn, state);
Ben Clayton9b156612019-03-13 19:48:31 +00001559
Chris Forbes06f4ed72019-03-28 09:53:20 +13001560 case spv::OpMatrixTimesVector:
1561 return EmitMatrixTimesVector(insn, state);
1562
Chris Forbesa563dd82019-03-28 10:32:55 +13001563 case spv::OpVectorTimesMatrix:
1564 return EmitVectorTimesMatrix(insn, state);
1565
Chris Forbes51562f12019-03-28 19:08:39 -07001566 case spv::OpMatrixTimesMatrix:
1567 return EmitMatrixTimesMatrix(insn, state);
1568
Ben Clayton9b156612019-03-13 19:48:31 +00001569 case spv::OpNot:
1570 case spv::OpSNegate:
1571 case spv::OpFNegate:
1572 case spv::OpLogicalNot:
1573 case spv::OpConvertFToU:
1574 case spv::OpConvertFToS:
1575 case spv::OpConvertSToF:
1576 case spv::OpConvertUToF:
1577 case spv::OpBitcast:
1578 case spv::OpIsInf:
1579 case spv::OpIsNan:
Chris Forbesaff2dd02019-03-20 14:50:24 -07001580 case spv::OpDPdx:
1581 case spv::OpDPdxCoarse:
1582 case spv::OpDPdy:
1583 case spv::OpDPdyCoarse:
1584 case spv::OpFwidth:
1585 case spv::OpFwidthCoarse:
1586 case spv::OpDPdxFine:
1587 case spv::OpDPdyFine:
1588 case spv::OpFwidthFine:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001589 return EmitUnaryOp(insn, state);
Ben Clayton9b156612019-03-13 19:48:31 +00001590
1591 case spv::OpIAdd:
1592 case spv::OpISub:
1593 case spv::OpIMul:
1594 case spv::OpSDiv:
1595 case spv::OpUDiv:
1596 case spv::OpFAdd:
1597 case spv::OpFSub:
1598 case spv::OpFMul:
1599 case spv::OpFDiv:
Chris Forbes0e4d6ff2019-03-15 13:43:36 -07001600 case spv::OpFMod:
Chris Forbes1a4c7122019-03-15 14:50:47 -07001601 case spv::OpFRem:
Ben Clayton9b156612019-03-13 19:48:31 +00001602 case spv::OpFOrdEqual:
1603 case spv::OpFUnordEqual:
1604 case spv::OpFOrdNotEqual:
1605 case spv::OpFUnordNotEqual:
1606 case spv::OpFOrdLessThan:
1607 case spv::OpFUnordLessThan:
1608 case spv::OpFOrdGreaterThan:
1609 case spv::OpFUnordGreaterThan:
1610 case spv::OpFOrdLessThanEqual:
1611 case spv::OpFUnordLessThanEqual:
1612 case spv::OpFOrdGreaterThanEqual:
1613 case spv::OpFUnordGreaterThanEqual:
1614 case spv::OpSMod:
Chris Forbes71673c82019-03-14 12:55:20 -07001615 case spv::OpSRem:
Ben Clayton9b156612019-03-13 19:48:31 +00001616 case spv::OpUMod:
1617 case spv::OpIEqual:
1618 case spv::OpINotEqual:
1619 case spv::OpUGreaterThan:
1620 case spv::OpSGreaterThan:
1621 case spv::OpUGreaterThanEqual:
1622 case spv::OpSGreaterThanEqual:
1623 case spv::OpULessThan:
1624 case spv::OpSLessThan:
1625 case spv::OpULessThanEqual:
1626 case spv::OpSLessThanEqual:
1627 case spv::OpShiftRightLogical:
1628 case spv::OpShiftRightArithmetic:
1629 case spv::OpShiftLeftLogical:
1630 case spv::OpBitwiseOr:
1631 case spv::OpBitwiseXor:
1632 case spv::OpBitwiseAnd:
1633 case spv::OpLogicalOr:
1634 case spv::OpLogicalAnd:
1635 case spv::OpLogicalEqual:
1636 case spv::OpLogicalNotEqual:
1637 case spv::OpUMulExtended:
1638 case spv::OpSMulExtended:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001639 return EmitBinaryOp(insn, state);
Ben Clayton9b156612019-03-13 19:48:31 +00001640
1641 case spv::OpDot:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001642 return EmitDot(insn, state);
Ben Clayton9b156612019-03-13 19:48:31 +00001643
1644 case spv::OpSelect:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001645 return EmitSelect(insn, state);
Ben Clayton9b156612019-03-13 19:48:31 +00001646
1647 case spv::OpExtInst:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001648 return EmitExtendedInstruction(insn, state);
Ben Clayton9b156612019-03-13 19:48:31 +00001649
1650 case spv::OpAny:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001651 return EmitAny(insn, state);
Ben Clayton9b156612019-03-13 19:48:31 +00001652
1653 case spv::OpAll:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001654 return EmitAll(insn, state);
Ben Clayton9b156612019-03-13 19:48:31 +00001655
Ben Claytone37ce612019-03-13 19:57:42 +00001656 case spv::OpBranch:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001657 return EmitBranch(insn, state);
Ben Claytone37ce612019-03-13 19:57:42 +00001658
Ben Clayton9fd02e02019-03-21 18:47:15 +00001659 case spv::OpPhi:
1660 return EmitPhi(insn, state);
1661
1662 case spv::OpSelectionMerge:
Ben Claytone747b3c2019-03-21 19:35:15 +00001663 case spv::OpLoopMerge:
Ben Clayton9fd02e02019-03-21 18:47:15 +00001664 return EmitResult::Continue;
1665
1666 case spv::OpBranchConditional:
1667 return EmitBranchConditional(insn, state);
1668
Ben Clayton213a8ce2019-03-21 18:57:23 +00001669 case spv::OpSwitch:
1670 return EmitSwitch(insn, state);
1671
Ben Clayton9fd02e02019-03-21 18:47:15 +00001672 case spv::OpUnreachable:
1673 return EmitUnreachable(insn, state);
1674
1675 case spv::OpReturn:
1676 return EmitReturn(insn, state);
1677
Ben Clayton9b156612019-03-13 19:48:31 +00001678 default:
Ben Clayton00424c12019-03-17 17:29:30 +00001679 UNIMPLEMENTED("opcode: %s", OpcodeName(insn.opcode()).c_str());
Ben Clayton9b156612019-03-13 19:48:31 +00001680 break;
Chris Forbesd5aed492019-02-02 15:18:52 -08001681 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001682
1683 return EmitResult::Continue;
Chris Forbesd5aed492019-02-02 15:18:52 -08001684 }
Chris Forbesc61271e2019-02-19 17:01:28 -08001685
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001686 SpirvShader::EmitResult SpirvShader::EmitVariable(InsnIterator insn, EmitState *state) const
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001687 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001688 auto routine = state->routine;
Ben Claytonaf973b62019-03-13 18:19:20 +00001689 Object::ID resultId = insn.word(2);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001690 auto &object = getObject(resultId);
1691 auto &objectTy = getType(object.type);
Ben Claytonefec1b92019-03-05 17:38:16 +00001692 switch (objectTy.storageClass)
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001693 {
Ben Claytonefec1b92019-03-05 17:38:16 +00001694 case spv::StorageClassInput:
1695 {
1696 if (object.kind == Object::Kind::InterfaceVariable)
1697 {
1698 auto &dst = routine->getValue(resultId);
1699 int offset = 0;
1700 VisitInterface(resultId,
1701 [&](Decorations const &d, AttribType type) {
1702 auto scalarSlot = d.Location << 2 | d.Component;
1703 dst[offset++] = routine->inputs[scalarSlot];
1704 });
1705 }
1706 break;
1707 }
1708 case spv::StorageClassUniform:
1709 case spv::StorageClassStorageBuffer:
1710 {
1711 Decorations d{};
1712 ApplyDecorationsForId(&d, resultId);
1713 ASSERT(d.DescriptorSet >= 0);
1714 ASSERT(d.Binding >= 0);
1715
1716 size_t bindingOffset = routine->pipelineLayout->getBindingOffset(d.DescriptorSet, d.Binding);
1717
1718 Pointer<Byte> set = routine->descriptorSets[d.DescriptorSet]; // DescriptorSet*
1719 Pointer<Byte> binding = Pointer<Byte>(set + bindingOffset); // VkDescriptorBufferInfo*
1720 Pointer<Byte> buffer = *Pointer<Pointer<Byte>>(binding + OFFSET(VkDescriptorBufferInfo, buffer)); // vk::Buffer*
1721 Pointer<Byte> data = *Pointer<Pointer<Byte>>(buffer + vk::Buffer::DataOffset); // void*
1722 Int offset = *Pointer<Int>(binding + OFFSET(VkDescriptorBufferInfo, offset));
1723 Pointer<Byte> address = data + offset;
1724 routine->physicalPointers[resultId] = address;
1725 break;
1726 }
Chris Forbesa30de542019-03-18 18:51:55 -07001727 case spv::StorageClassPushConstant:
1728 {
1729 routine->physicalPointers[resultId] = routine->pushConstants;
1730 break;
1731 }
Ben Claytonefec1b92019-03-05 17:38:16 +00001732 default:
1733 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001734 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001735
1736 return EmitResult::Continue;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001737 }
1738
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001739 SpirvShader::EmitResult SpirvShader::EmitLoad(InsnIterator insn, EmitState *state) const
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001740 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001741 auto routine = state->routine;
Nicolas Capens86509d92019-03-21 13:23:50 -04001742 bool atomic = (insn.opcode() == spv::OpAtomicLoad);
Nicolas Capensfabdec52019-03-21 17:04:05 -04001743 Object::ID resultId = insn.word(2);
Ben Claytonaf973b62019-03-13 18:19:20 +00001744 Object::ID pointerId = insn.word(3);
Nicolas Capensfabdec52019-03-21 17:04:05 -04001745 auto &result = getObject(resultId);
1746 auto &resultTy = getType(result.type);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001747 auto &pointer = getObject(pointerId);
1748 auto &pointerBase = getObject(pointer.pointerBase);
1749 auto &pointerBaseTy = getType(pointerBase.type);
Nicolas Capens86509d92019-03-21 13:23:50 -04001750 std::memory_order memoryOrder = std::memory_order_relaxed;
1751
1752 if(atomic)
1753 {
1754 Object::ID semanticsId = insn.word(5);
1755 auto memorySemantics = static_cast<spv::MemorySemanticsMask>(getObject(semanticsId).constantValue[0]);
1756 memoryOrder = MemoryOrder(memorySemantics);
1757 }
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001758
Nicolas Capensfabdec52019-03-21 17:04:05 -04001759 ASSERT(getType(pointer.type).element == result.type);
1760 ASSERT(Type::ID(insn.word(1)) == result.type);
Nicolas Capens86509d92019-03-21 13:23:50 -04001761 ASSERT(!atomic || getType(getType(pointer.type).element).opcode() == spv::OpTypeInt); // Vulkan 1.1: "Atomic instructions must declare a scalar 32-bit integer type, for the value pointed to by Pointer."
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001762
Ben Claytonefec1b92019-03-05 17:38:16 +00001763 if (pointerBaseTy.storageClass == spv::StorageClassImage)
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001764 {
Ben Claytonefec1b92019-03-05 17:38:16 +00001765 UNIMPLEMENTED("StorageClassImage load not yet implemented");
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001766 }
1767
Ben Clayton831db962019-02-27 14:57:18 +00001768 Pointer<Float> ptrBase;
1769 if (pointerBase.kind == Object::Kind::PhysicalPointer)
1770 {
1771 ptrBase = routine->getPhysicalPointer(pointer.pointerBase);
1772 }
1773 else
1774 {
1775 ptrBase = &routine->getValue(pointer.pointerBase)[0];
1776 }
1777
1778 bool interleavedByLane = IsStorageInterleavedByLane(pointerBaseTy.storageClass);
Ben Claytone747b3c2019-03-21 19:35:15 +00001779 auto anyInactiveLanes = AnyFalse(state->activeLaneMask());
Ben Clayton831db962019-02-27 14:57:18 +00001780
Nicolas Capensfabdec52019-03-21 17:04:05 -04001781 auto load = std::unique_ptr<SIMD::Float[]>(new SIMD::Float[resultTy.sizeInComponents]);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001782
Ben Clayton49d81582019-03-12 20:05:04 +00001783 If(pointer.kind == Object::Kind::Value || anyInactiveLanes)
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001784 {
Ben Clayton49d81582019-03-12 20:05:04 +00001785 // Divergent offsets or masked lanes.
1786 auto offsets = pointer.kind == Object::Kind::Value ?
1787 As<SIMD::Int>(routine->getIntermediate(pointerId).Int(0)) :
1788 RValue<SIMD::Int>(SIMD::Int(0));
Nicolas Capensfabdec52019-03-21 17:04:05 -04001789 for (auto i = 0u; i < resultTy.sizeInComponents; i++)
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001790 {
1791 // i wish i had a Float,Float,Float,Float constructor here..
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001792 for (int j = 0; j < SIMD::Width; j++)
1793 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001794 If(Extract(state->activeLaneMask(), j) != 0)
Ben Clayton49d81582019-03-12 20:05:04 +00001795 {
1796 Int offset = Int(i) + Extract(offsets, j);
1797 if (interleavedByLane) { offset = offset * SIMD::Width + j; }
Nicolas Capens86509d92019-03-21 13:23:50 -04001798 load[i] = Insert(load[i], Load(&ptrBase[offset], sizeof(float), atomic, memoryOrder), j);
Ben Clayton49d81582019-03-12 20:05:04 +00001799 }
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001800 }
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001801 }
1802 }
Ben Clayton49d81582019-03-12 20:05:04 +00001803 Else
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001804 {
Ben Clayton49d81582019-03-12 20:05:04 +00001805 // No divergent offsets or masked lanes.
1806 if (interleavedByLane)
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001807 {
Ben Clayton49d81582019-03-12 20:05:04 +00001808 // Lane-interleaved data.
1809 Pointer<SIMD::Float> src = ptrBase;
Nicolas Capensfabdec52019-03-21 17:04:05 -04001810 for (auto i = 0u; i < resultTy.sizeInComponents; i++)
Ben Clayton49d81582019-03-12 20:05:04 +00001811 {
Nicolas Capens86509d92019-03-21 13:23:50 -04001812 load[i] = Load(&src[i], sizeof(float), atomic, memoryOrder); // TODO: optimize alignment
Ben Clayton49d81582019-03-12 20:05:04 +00001813 }
1814 }
1815 else
1816 {
1817 // Non-interleaved data.
Nicolas Capensfabdec52019-03-21 17:04:05 -04001818 for (auto i = 0u; i < resultTy.sizeInComponents; i++)
Ben Clayton49d81582019-03-12 20:05:04 +00001819 {
Nicolas Capens86509d92019-03-21 13:23:50 -04001820 load[i] = RValue<SIMD::Float>(Load(&ptrBase[i], sizeof(float), atomic, memoryOrder)); // TODO: optimize alignment
Ben Clayton49d81582019-03-12 20:05:04 +00001821 }
Ben Clayton831db962019-02-27 14:57:18 +00001822 }
1823 }
Ben Clayton49d81582019-03-12 20:05:04 +00001824
Nicolas Capensfabdec52019-03-21 17:04:05 -04001825 auto &dst = routine->createIntermediate(resultId, resultTy.sizeInComponents);
1826 for (auto i = 0u; i < resultTy.sizeInComponents; i++)
Ben Clayton831db962019-02-27 14:57:18 +00001827 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04001828 dst.move(i, load[i]);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001829 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001830
1831 return EmitResult::Continue;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001832 }
1833
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001834 SpirvShader::EmitResult SpirvShader::EmitStore(InsnIterator insn, EmitState *state) const
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001835 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001836 auto routine = state->routine;
Nicolas Capens5e8414e2019-03-19 16:22:35 -04001837 bool atomic = (insn.opcode() == spv::OpAtomicStore);
Ben Claytonaf973b62019-03-13 18:19:20 +00001838 Object::ID pointerId = insn.word(1);
Nicolas Capens5e8414e2019-03-19 16:22:35 -04001839 Object::ID objectId = insn.word(atomic ? 4 : 2);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001840 auto &object = getObject(objectId);
1841 auto &pointer = getObject(pointerId);
1842 auto &pointerTy = getType(pointer.type);
1843 auto &elementTy = getType(pointerTy.element);
1844 auto &pointerBase = getObject(pointer.pointerBase);
1845 auto &pointerBaseTy = getType(pointerBase.type);
Nicolas Capens86509d92019-03-21 13:23:50 -04001846 std::memory_order memoryOrder = std::memory_order_relaxed;
1847
1848 if(atomic)
1849 {
1850 Object::ID semanticsId = insn.word(3);
1851 auto memorySemantics = static_cast<spv::MemorySemanticsMask>(getObject(semanticsId).constantValue[0]);
1852 memoryOrder = MemoryOrder(memorySemantics);
1853 }
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001854
Nicolas Capens5e8414e2019-03-19 16:22:35 -04001855 ASSERT(!atomic || elementTy.opcode() == spv::OpTypeInt); // Vulkan 1.1: "Atomic instructions must declare a scalar 32-bit integer type, for the value pointed to by Pointer."
1856
Ben Claytonefec1b92019-03-05 17:38:16 +00001857 if (pointerBaseTy.storageClass == spv::StorageClassImage)
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001858 {
Ben Claytonefec1b92019-03-05 17:38:16 +00001859 UNIMPLEMENTED("StorageClassImage store not yet implemented");
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001860 }
1861
Ben Clayton831db962019-02-27 14:57:18 +00001862 Pointer<Float> ptrBase;
1863 if (pointerBase.kind == Object::Kind::PhysicalPointer)
1864 {
1865 ptrBase = routine->getPhysicalPointer(pointer.pointerBase);
1866 }
1867 else
1868 {
1869 ptrBase = &routine->getValue(pointer.pointerBase)[0];
1870 }
1871
1872 bool interleavedByLane = IsStorageInterleavedByLane(pointerBaseTy.storageClass);
Ben Claytone747b3c2019-03-21 19:35:15 +00001873 auto anyInactiveLanes = AnyFalse(state->activeLaneMask());
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001874
1875 if (object.kind == Object::Kind::Constant)
1876 {
Ben Clayton49d81582019-03-12 20:05:04 +00001877 // Constant source data.
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001878 auto src = reinterpret_cast<float *>(object.constantValue.get());
Ben Clayton49d81582019-03-12 20:05:04 +00001879 If(pointer.kind == Object::Kind::Value || anyInactiveLanes)
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001880 {
Ben Clayton49d81582019-03-12 20:05:04 +00001881 // Divergent offsets or masked lanes.
1882 auto offsets = pointer.kind == Object::Kind::Value ?
1883 As<SIMD::Int>(routine->getIntermediate(pointerId).Int(0)) :
1884 RValue<SIMD::Int>(SIMD::Int(0));
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001885 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1886 {
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001887 for (int j = 0; j < SIMD::Width; j++)
1888 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001889 If(Extract(state->activeLaneMask(), j) != 0)
Ben Clayton49d81582019-03-12 20:05:04 +00001890 {
1891 Int offset = Int(i) + Extract(offsets, j);
1892 if (interleavedByLane) { offset = offset * SIMD::Width + j; }
Nicolas Capens86509d92019-03-21 13:23:50 -04001893 Store(RValue<Float>(src[i]), &ptrBase[offset], sizeof(float), atomic, memoryOrder);
Ben Clayton49d81582019-03-12 20:05:04 +00001894 }
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001895 }
1896 }
1897 }
Ben Clayton49d81582019-03-12 20:05:04 +00001898 Else
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001899 {
Ben Clayton49d81582019-03-12 20:05:04 +00001900 // Constant source data.
1901 // No divergent offsets or masked lanes.
Ben Clayton831db962019-02-27 14:57:18 +00001902 Pointer<SIMD::Float> dst = ptrBase;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001903 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1904 {
Nicolas Capens86509d92019-03-21 13:23:50 -04001905 Store(RValue<SIMD::Float>(src[i]), &dst[i], sizeof(float), atomic, memoryOrder); // TODO: optimize alignment
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001906 }
1907 }
1908 }
1909 else
1910 {
Ben Clayton49d81582019-03-12 20:05:04 +00001911 // Intermediate source data.
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001912 auto &src = routine->getIntermediate(objectId);
Ben Clayton49d81582019-03-12 20:05:04 +00001913 If(pointer.kind == Object::Kind::Value || anyInactiveLanes)
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001914 {
Ben Clayton49d81582019-03-12 20:05:04 +00001915 // Divergent offsets or masked lanes.
1916 auto offsets = pointer.kind == Object::Kind::Value ?
1917 As<SIMD::Int>(routine->getIntermediate(pointerId).Int(0)) :
1918 RValue<SIMD::Int>(SIMD::Int(0));
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001919 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1920 {
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001921 for (int j = 0; j < SIMD::Width; j++)
1922 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001923 If(Extract(state->activeLaneMask(), j) != 0)
Ben Clayton49d81582019-03-12 20:05:04 +00001924 {
1925 Int offset = Int(i) + Extract(offsets, j);
1926 if (interleavedByLane) { offset = offset * SIMD::Width + j; }
Nicolas Capens86509d92019-03-21 13:23:50 -04001927 Store(Extract(src.Float(i), j), &ptrBase[offset], sizeof(float), atomic, memoryOrder);
Ben Clayton49d81582019-03-12 20:05:04 +00001928 }
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001929 }
1930 }
1931 }
Ben Clayton49d81582019-03-12 20:05:04 +00001932 Else
Ben Clayton831db962019-02-27 14:57:18 +00001933 {
Ben Clayton49d81582019-03-12 20:05:04 +00001934 // No divergent offsets or masked lanes.
1935 if (interleavedByLane)
Ben Clayton831db962019-02-27 14:57:18 +00001936 {
Ben Clayton49d81582019-03-12 20:05:04 +00001937 // Lane-interleaved data.
1938 Pointer<SIMD::Float> dst = ptrBase;
1939 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1940 {
Nicolas Capens86509d92019-03-21 13:23:50 -04001941 Store(src.Float(i), &dst[i], sizeof(float), atomic, memoryOrder); // TODO: optimize alignment
Ben Clayton49d81582019-03-12 20:05:04 +00001942 }
Ben Clayton831db962019-02-27 14:57:18 +00001943 }
Ben Clayton49d81582019-03-12 20:05:04 +00001944 else
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001945 {
Ben Clayton49d81582019-03-12 20:05:04 +00001946 // Intermediate source data. Non-interleaved data.
1947 Pointer<SIMD::Float> dst = ptrBase;
1948 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1949 {
Nicolas Capens86509d92019-03-21 13:23:50 -04001950 Store<SIMD::Float>(SIMD::Float(src.Float(i)), &dst[i], sizeof(float), atomic, memoryOrder); // TODO: optimize alignment
Ben Clayton49d81582019-03-12 20:05:04 +00001951 }
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001952 }
1953 }
1954 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001955
1956 return EmitResult::Continue;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001957 }
1958
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001959 SpirvShader::EmitResult SpirvShader::EmitAccessChain(InsnIterator insn, EmitState *state) const
Nicolas Capensfabdec52019-03-21 17:04:05 -04001960 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001961 auto routine = state->routine;
Nicolas Capensfabdec52019-03-21 17:04:05 -04001962 Type::ID typeId = insn.word(1);
1963 Object::ID resultId = insn.word(2);
1964 Object::ID baseId = insn.word(3);
1965 uint32_t numIndexes = insn.wordCount() - 4;
1966 const uint32_t *indexes = insn.wordPointer(4);
1967 auto &type = getType(typeId);
1968 ASSERT(type.sizeInComponents == 1);
1969 ASSERT(getObject(baseId).pointerBase == getObject(resultId).pointerBase);
1970
1971 auto &dst = routine->createIntermediate(resultId, type.sizeInComponents);
1972
1973 if(type.storageClass == spv::StorageClassPushConstant ||
1974 type.storageClass == spv::StorageClassUniform ||
1975 type.storageClass == spv::StorageClassStorageBuffer)
1976 {
1977 dst.move(0, WalkExplicitLayoutAccessChain(baseId, numIndexes, indexes, routine));
1978 }
1979 else
1980 {
1981 dst.move(0, WalkAccessChain(baseId, numIndexes, indexes, routine));
1982 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001983
1984 return EmitResult::Continue;
Nicolas Capensfabdec52019-03-21 17:04:05 -04001985 }
1986
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001987 SpirvShader::EmitResult SpirvShader::EmitCompositeConstruct(InsnIterator insn, EmitState *state) const
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001988 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001989 auto routine = state->routine;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001990 auto &type = getType(insn.word(1));
1991 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1992 auto offset = 0u;
1993
1994 for (auto i = 0u; i < insn.wordCount() - 3; i++)
1995 {
Ben Claytonaf973b62019-03-13 18:19:20 +00001996 Object::ID srcObjectId = insn.word(3u + i);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001997 auto & srcObject = getObject(srcObjectId);
1998 auto & srcObjectTy = getType(srcObject.type);
1999 GenericValue srcObjectAccess(this, routine, srcObjectId);
2000
2001 for (auto j = 0u; j < srcObjectTy.sizeInComponents; j++)
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002002 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002003 dst.move(offset++, srcObjectAccess.Float(j));
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002004 }
Ben Claytondfc0f3b2019-02-26 12:19:48 +00002005 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002006
2007 return EmitResult::Continue;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00002008 }
2009
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002010 SpirvShader::EmitResult SpirvShader::EmitCompositeInsert(InsnIterator insn, EmitState *state) const
Ben Claytondfc0f3b2019-02-26 12:19:48 +00002011 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002012 auto routine = state->routine;
Ben Claytonaf973b62019-03-13 18:19:20 +00002013 Type::ID resultTypeId = insn.word(1);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00002014 auto &type = getType(resultTypeId);
2015 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
2016 auto &newPartObject = getObject(insn.word(3));
2017 auto &newPartObjectTy = getType(newPartObject.type);
2018 auto firstNewComponent = WalkLiteralAccessChain(resultTypeId, insn.wordCount() - 5, insn.wordPointer(5));
2019
2020 GenericValue srcObjectAccess(this, routine, insn.word(4));
2021 GenericValue newPartObjectAccess(this, routine, insn.word(3));
2022
2023 // old components before
2024 for (auto i = 0u; i < firstNewComponent; i++)
2025 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002026 dst.move(i, srcObjectAccess.Float(i));
Ben Claytondfc0f3b2019-02-26 12:19:48 +00002027 }
2028 // new part
2029 for (auto i = 0u; i < newPartObjectTy.sizeInComponents; i++)
2030 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002031 dst.move(firstNewComponent + i, newPartObjectAccess.Float(i));
Ben Claytondfc0f3b2019-02-26 12:19:48 +00002032 }
2033 // old components after
2034 for (auto i = firstNewComponent + newPartObjectTy.sizeInComponents; i < type.sizeInComponents; i++)
2035 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002036 dst.move(i, srcObjectAccess.Float(i));
Ben Claytondfc0f3b2019-02-26 12:19:48 +00002037 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002038
2039 return EmitResult::Continue;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00002040 }
2041
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002042 SpirvShader::EmitResult SpirvShader::EmitCompositeExtract(InsnIterator insn, EmitState *state) const
Ben Claytondfc0f3b2019-02-26 12:19:48 +00002043 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002044 auto routine = state->routine;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00002045 auto &type = getType(insn.word(1));
2046 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
2047 auto &compositeObject = getObject(insn.word(3));
Ben Claytonaf973b62019-03-13 18:19:20 +00002048 Type::ID compositeTypeId = compositeObject.definition.word(1);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00002049 auto firstComponent = WalkLiteralAccessChain(compositeTypeId, insn.wordCount() - 4, insn.wordPointer(4));
2050
2051 GenericValue compositeObjectAccess(this, routine, insn.word(3));
2052 for (auto i = 0u; i < type.sizeInComponents; i++)
2053 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002054 dst.move(i, compositeObjectAccess.Float(firstComponent + i));
Ben Claytondfc0f3b2019-02-26 12:19:48 +00002055 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002056
2057 return EmitResult::Continue;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00002058 }
2059
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002060 SpirvShader::EmitResult SpirvShader::EmitVectorShuffle(InsnIterator insn, EmitState *state) const
Ben Claytondfc0f3b2019-02-26 12:19:48 +00002061 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002062 auto routine = state->routine;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00002063 auto &type = getType(insn.word(1));
2064 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
2065
Chris Forbes13eba6c2019-03-08 10:41:05 -08002066 // Note: number of components in result type, first half type, and second
2067 // half type are all independent.
2068 auto &firstHalfType = getType(getObject(insn.word(3)).type);
2069
Ben Claytondfc0f3b2019-02-26 12:19:48 +00002070 GenericValue firstHalfAccess(this, routine, insn.word(3));
2071 GenericValue secondHalfAccess(this, routine, insn.word(4));
2072
2073 for (auto i = 0u; i < type.sizeInComponents; i++)
2074 {
2075 auto selector = insn.word(5 + i);
2076 if (selector == static_cast<uint32_t>(-1))
2077 {
2078 // Undefined value. Until we decide to do real undef values, zero is as good
2079 // a value as any
Nicolas Capens80c796b2019-03-19 21:38:44 -04002080 dst.move(i, RValue<SIMD::Float>(0.0f));
Ben Claytondfc0f3b2019-02-26 12:19:48 +00002081 }
Chris Forbes13eba6c2019-03-08 10:41:05 -08002082 else if (selector < firstHalfType.sizeInComponents)
Ben Claytondfc0f3b2019-02-26 12:19:48 +00002083 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002084 dst.move(i, firstHalfAccess.Float(selector));
Ben Claytondfc0f3b2019-02-26 12:19:48 +00002085 }
2086 else
2087 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002088 dst.move(i, secondHalfAccess.Float(selector - firstHalfType.sizeInComponents));
Ben Claytondfc0f3b2019-02-26 12:19:48 +00002089 }
2090 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002091
2092 return EmitResult::Continue;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00002093 }
2094
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002095 SpirvShader::EmitResult SpirvShader::EmitVectorExtractDynamic(InsnIterator insn, EmitState *state) const
Chris Forbesfaed9d32019-03-15 10:31:08 -07002096 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002097 auto routine = state->routine;
Chris Forbesfaed9d32019-03-15 10:31:08 -07002098 auto &type = getType(insn.word(1));
2099 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
2100 auto &srcType = getType(getObject(insn.word(3)).type);
2101
2102 GenericValue src(this, routine, insn.word(3));
2103 GenericValue index(this, routine, insn.word(4));
2104
2105 SIMD::UInt v = SIMD::UInt(0);
2106
2107 for (auto i = 0u; i < srcType.sizeInComponents; i++)
2108 {
2109 v |= CmpEQ(index.UInt(0), SIMD::UInt(i)) & src.UInt(i);
2110 }
2111
Nicolas Capens80c796b2019-03-19 21:38:44 -04002112 dst.move(0, v);
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002113 return EmitResult::Continue;
Chris Forbesfaed9d32019-03-15 10:31:08 -07002114 }
2115
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002116 SpirvShader::EmitResult SpirvShader::EmitVectorInsertDynamic(InsnIterator insn, EmitState *state) const
Chris Forbesfaed9d32019-03-15 10:31:08 -07002117 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002118 auto routine = state->routine;
Chris Forbesfaed9d32019-03-15 10:31:08 -07002119 auto &type = getType(insn.word(1));
2120 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
2121
2122 GenericValue src(this, routine, insn.word(3));
2123 GenericValue component(this, routine, insn.word(4));
2124 GenericValue index(this, routine, insn.word(5));
2125
2126 for (auto i = 0u; i < type.sizeInComponents; i++)
2127 {
2128 SIMD::UInt mask = CmpEQ(SIMD::UInt(i), index.UInt(0));
Nicolas Capens80c796b2019-03-19 21:38:44 -04002129 dst.move(i, (src.UInt(i) & ~mask) | (component.UInt(0) & mask));
Chris Forbesfaed9d32019-03-15 10:31:08 -07002130 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002131 return EmitResult::Continue;
Chris Forbesfaed9d32019-03-15 10:31:08 -07002132 }
2133
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002134 SpirvShader::EmitResult SpirvShader::EmitVectorTimesScalar(InsnIterator insn, EmitState *state) const
Chris Forbes856ebf82019-03-08 15:30:18 -08002135 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002136 auto routine = state->routine;
Chris Forbes856ebf82019-03-08 15:30:18 -08002137 auto &type = getType(insn.word(1));
2138 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002139 auto lhs = GenericValue(this, routine, insn.word(3));
2140 auto rhs = GenericValue(this, routine, insn.word(4));
Chris Forbes856ebf82019-03-08 15:30:18 -08002141
2142 for (auto i = 0u; i < type.sizeInComponents; i++)
2143 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002144 dst.move(i, lhs.Float(i) * rhs.Float(0));
Chris Forbes856ebf82019-03-08 15:30:18 -08002145 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002146
2147 return EmitResult::Continue;
Chris Forbes856ebf82019-03-08 15:30:18 -08002148 }
2149
Chris Forbes06f4ed72019-03-28 09:53:20 +13002150 SpirvShader::EmitResult SpirvShader::EmitMatrixTimesVector(InsnIterator insn, EmitState *state) const
2151 {
2152 auto routine = state->routine;
2153 auto &type = getType(insn.word(1));
2154 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
2155 auto lhs = GenericValue(this, routine, insn.word(3));
2156 auto rhs = GenericValue(this, routine, insn.word(4));
2157 auto rhsType = getType(getObject(insn.word(4)).type);
2158
2159 for (auto i = 0u; i < type.sizeInComponents; i++)
2160 {
2161 SIMD::Float v = lhs.Float(i) * rhs.Float(0);
2162 for (auto j = 1u; j < rhsType.sizeInComponents; j++)
2163 {
2164 v += lhs.Float(i + type.sizeInComponents * j) * rhs.Float(j);
2165 }
2166 dst.move(i, v);
2167 }
2168
2169 return EmitResult::Continue;
2170 }
2171
Chris Forbesa563dd82019-03-28 10:32:55 +13002172 SpirvShader::EmitResult SpirvShader::EmitVectorTimesMatrix(InsnIterator insn, EmitState *state) const
2173 {
2174 auto routine = state->routine;
2175 auto &type = getType(insn.word(1));
2176 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
2177 auto lhs = GenericValue(this, routine, insn.word(3));
2178 auto rhs = GenericValue(this, routine, insn.word(4));
2179 auto lhsType = getType(getObject(insn.word(3)).type);
2180
2181 for (auto i = 0u; i < type.sizeInComponents; i++)
2182 {
2183 SIMD::Float v = lhs.Float(0) * rhs.Float(i * lhsType.sizeInComponents);
2184 for (auto j = 1u; j < lhsType.sizeInComponents; j++)
2185 {
2186 v += lhs.Float(j) * rhs.Float(i * lhsType.sizeInComponents + j);
2187 }
2188 dst.move(i, v);
2189 }
2190
2191 return EmitResult::Continue;
2192 }
2193
Chris Forbes51562f12019-03-28 19:08:39 -07002194 SpirvShader::EmitResult SpirvShader::EmitMatrixTimesMatrix(InsnIterator insn, EmitState *state) const
2195 {
2196 auto routine = state->routine;
2197 auto &type = getType(insn.word(1));
2198 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
2199 auto lhs = GenericValue(this, routine, insn.word(3));
2200 auto rhs = GenericValue(this, routine, insn.word(4));
2201
2202 auto numColumns = type.definition.word(3);
2203 auto numRows = getType(type.definition.word(2)).definition.word(3);
2204 auto numAdds = getType(getObject(insn.word(3)).type).definition.word(3);
2205
2206 for (auto row = 0u; row < numRows; row++)
2207 {
2208 for (auto col = 0u; col < numColumns; col++)
2209 {
2210 SIMD::Float v = SIMD::Float(0);
2211 for (auto i = 0u; i < numAdds; i++)
2212 {
2213 v += lhs.Float(i * numRows + row) * rhs.Float(col * numAdds + i);
2214 }
2215 dst.move(numRows * col + row, v);
2216 }
2217 }
2218
2219 return EmitResult::Continue;
2220 }
2221
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002222 SpirvShader::EmitResult SpirvShader::EmitUnaryOp(InsnIterator insn, EmitState *state) const
Ben Claytondd1e37e2019-02-28 19:59:15 +00002223 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002224 auto routine = state->routine;
Ben Claytondd1e37e2019-02-28 19:59:15 +00002225 auto &type = getType(insn.word(1));
2226 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
2227 auto src = GenericValue(this, routine, insn.word(3));
2228
2229 for (auto i = 0u; i < type.sizeInComponents; i++)
2230 {
Ben Claytondd1e37e2019-02-28 19:59:15 +00002231 switch (insn.opcode())
2232 {
2233 case spv::OpNot:
2234 case spv::OpLogicalNot: // logical not == bitwise not due to all-bits boolean representation
Nicolas Capens80c796b2019-03-19 21:38:44 -04002235 dst.move(i, ~src.UInt(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00002236 break;
2237 case spv::OpSNegate:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002238 dst.move(i, -src.Int(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00002239 break;
2240 case spv::OpFNegate:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002241 dst.move(i, -src.Float(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00002242 break;
Chris Forbes4d503052019-03-01 17:13:57 -08002243 case spv::OpConvertFToU:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002244 dst.move(i, SIMD::UInt(src.Float(i)));
Chris Forbes4d503052019-03-01 17:13:57 -08002245 break;
2246 case spv::OpConvertFToS:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002247 dst.move(i, SIMD::Int(src.Float(i)));
Chris Forbes4d503052019-03-01 17:13:57 -08002248 break;
2249 case spv::OpConvertSToF:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002250 dst.move(i, SIMD::Float(src.Int(i)));
Chris Forbes4d503052019-03-01 17:13:57 -08002251 break;
2252 case spv::OpConvertUToF:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002253 dst.move(i, SIMD::Float(src.UInt(i)));
Chris Forbes4d503052019-03-01 17:13:57 -08002254 break;
2255 case spv::OpBitcast:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002256 dst.move(i, src.Float(i));
Chris Forbes4d503052019-03-01 17:13:57 -08002257 break;
Chris Forbes3ed33ce2019-03-07 13:38:31 -08002258 case spv::OpIsInf:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002259 dst.move(i, IsInf(src.Float(i)));
Chris Forbes3ed33ce2019-03-07 13:38:31 -08002260 break;
2261 case spv::OpIsNan:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002262 dst.move(i, IsNan(src.Float(i)));
Chris Forbes3ed33ce2019-03-07 13:38:31 -08002263 break;
Chris Forbesaff2dd02019-03-20 14:50:24 -07002264 case spv::OpDPdx:
2265 case spv::OpDPdxCoarse:
2266 // Derivative instructions: FS invocations are laid out like so:
2267 // 0 1
2268 // 2 3
2269 static_assert(SIMD::Width == 4, "All cross-lane instructions will need care when using a different width");
Nicolas Capens80c796b2019-03-19 21:38:44 -04002270 dst.move(i, SIMD::Float(Extract(src.Float(i), 1) - Extract(src.Float(i), 0)));
Chris Forbesaff2dd02019-03-20 14:50:24 -07002271 break;
2272 case spv::OpDPdy:
2273 case spv::OpDPdyCoarse:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002274 dst.move(i, SIMD::Float(Extract(src.Float(i), 2) - Extract(src.Float(i), 0)));
Chris Forbesaff2dd02019-03-20 14:50:24 -07002275 break;
2276 case spv::OpFwidth:
2277 case spv::OpFwidthCoarse:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002278 dst.move(i, SIMD::Float(Abs(Extract(src.Float(i), 1) - Extract(src.Float(i), 0))
Chris Forbesaff2dd02019-03-20 14:50:24 -07002279 + Abs(Extract(src.Float(i), 2) - Extract(src.Float(i), 0))));
2280 break;
2281 case spv::OpDPdxFine:
2282 {
2283 auto firstRow = Extract(src.Float(i), 1) - Extract(src.Float(i), 0);
2284 auto secondRow = Extract(src.Float(i), 3) - Extract(src.Float(i), 2);
2285 SIMD::Float v = SIMD::Float(firstRow);
2286 v = Insert(v, secondRow, 2);
2287 v = Insert(v, secondRow, 3);
Nicolas Capens80c796b2019-03-19 21:38:44 -04002288 dst.move(i, v);
Chris Forbesaff2dd02019-03-20 14:50:24 -07002289 break;
2290 }
2291 case spv::OpDPdyFine:
2292 {
2293 auto firstColumn = Extract(src.Float(i), 2) - Extract(src.Float(i), 0);
2294 auto secondColumn = Extract(src.Float(i), 3) - Extract(src.Float(i), 1);
2295 SIMD::Float v = SIMD::Float(firstColumn);
2296 v = Insert(v, secondColumn, 1);
2297 v = Insert(v, secondColumn, 3);
Nicolas Capens80c796b2019-03-19 21:38:44 -04002298 dst.move(i, v);
Chris Forbesaff2dd02019-03-20 14:50:24 -07002299 break;
2300 }
2301 case spv::OpFwidthFine:
2302 {
2303 auto firstRow = Extract(src.Float(i), 1) - Extract(src.Float(i), 0);
2304 auto secondRow = Extract(src.Float(i), 3) - Extract(src.Float(i), 2);
2305 SIMD::Float dpdx = SIMD::Float(firstRow);
2306 dpdx = Insert(dpdx, secondRow, 2);
2307 dpdx = Insert(dpdx, secondRow, 3);
2308 auto firstColumn = Extract(src.Float(i), 2) - Extract(src.Float(i), 0);
2309 auto secondColumn = Extract(src.Float(i), 3) - Extract(src.Float(i), 1);
2310 SIMD::Float dpdy = SIMD::Float(firstColumn);
2311 dpdy = Insert(dpdy, secondColumn, 1);
2312 dpdy = Insert(dpdy, secondColumn, 3);
Nicolas Capens80c796b2019-03-19 21:38:44 -04002313 dst.move(i, Abs(dpdx) + Abs(dpdy));
Chris Forbesaff2dd02019-03-20 14:50:24 -07002314 break;
2315 }
Ben Claytondd1e37e2019-02-28 19:59:15 +00002316 default:
2317 UNIMPLEMENTED("Unhandled unary operator %s", OpcodeName(insn.opcode()).c_str());
2318 }
2319 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002320
2321 return EmitResult::Continue;
Ben Claytondd1e37e2019-02-28 19:59:15 +00002322 }
2323
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002324 SpirvShader::EmitResult SpirvShader::EmitBinaryOp(InsnIterator insn, EmitState *state) const
Ben Claytondd1e37e2019-02-28 19:59:15 +00002325 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002326 auto routine = state->routine;
Ben Claytondd1e37e2019-02-28 19:59:15 +00002327 auto &type = getType(insn.word(1));
2328 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
Chris Forbese86b6dc2019-03-01 09:08:47 -08002329 auto &lhsType = getType(getObject(insn.word(3)).type);
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002330 auto lhs = GenericValue(this, routine, insn.word(3));
2331 auto rhs = GenericValue(this, routine, insn.word(4));
Ben Claytondd1e37e2019-02-28 19:59:15 +00002332
Chris Forbese86b6dc2019-03-01 09:08:47 -08002333 for (auto i = 0u; i < lhsType.sizeInComponents; i++)
Ben Claytondd1e37e2019-02-28 19:59:15 +00002334 {
Ben Claytondd1e37e2019-02-28 19:59:15 +00002335 switch (insn.opcode())
2336 {
2337 case spv::OpIAdd:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002338 dst.move(i, lhs.Int(i) + rhs.Int(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00002339 break;
2340 case spv::OpISub:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002341 dst.move(i, lhs.Int(i) - rhs.Int(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00002342 break;
2343 case spv::OpIMul:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002344 dst.move(i, lhs.Int(i) * rhs.Int(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00002345 break;
2346 case spv::OpSDiv:
Ben Clayton49d2c132019-03-14 12:21:53 +00002347 {
Ben Claytona2749f32019-03-14 19:32:41 +00002348 SIMD::Int a = lhs.Int(i);
2349 SIMD::Int b = rhs.Int(i);
2350 b = b | CmpEQ(b, SIMD::Int(0)); // prevent divide-by-zero
2351 a = a | (CmpEQ(a, SIMD::Int(0x80000000)) & CmpEQ(b, SIMD::Int(-1))); // prevent integer overflow
Nicolas Capens80c796b2019-03-19 21:38:44 -04002352 dst.move(i, a / b);
Ben Claytondd1e37e2019-02-28 19:59:15 +00002353 break;
Ben Clayton49d2c132019-03-14 12:21:53 +00002354 }
Ben Claytondd1e37e2019-02-28 19:59:15 +00002355 case spv::OpUDiv:
Ben Clayton49d2c132019-03-14 12:21:53 +00002356 {
2357 auto zeroMask = As<SIMD::UInt>(CmpEQ(rhs.Int(i), SIMD::Int(0)));
Nicolas Capens80c796b2019-03-19 21:38:44 -04002358 dst.move(i, lhs.UInt(i) / (rhs.UInt(i) | zeroMask));
Ben Claytondd1e37e2019-02-28 19:59:15 +00002359 break;
Ben Clayton49d2c132019-03-14 12:21:53 +00002360 }
Chris Forbes71673c82019-03-14 12:55:20 -07002361 case spv::OpSRem:
2362 {
2363 SIMD::Int a = lhs.Int(i);
2364 SIMD::Int b = rhs.Int(i);
2365 b = b | CmpEQ(b, SIMD::Int(0)); // prevent divide-by-zero
2366 a = a | (CmpEQ(a, SIMD::Int(0x80000000)) & CmpEQ(b, SIMD::Int(-1))); // prevent integer overflow
Nicolas Capens80c796b2019-03-19 21:38:44 -04002367 dst.move(i, a % b);
Chris Forbes71673c82019-03-14 12:55:20 -07002368 break;
2369 }
Ben Claytonbb8c8e22019-03-08 12:04:00 +00002370 case spv::OpSMod:
2371 {
Ben Claytona2749f32019-03-14 19:32:41 +00002372 SIMD::Int a = lhs.Int(i);
2373 SIMD::Int b = rhs.Int(i);
2374 b = b | CmpEQ(b, SIMD::Int(0)); // prevent divide-by-zero
2375 a = a | (CmpEQ(a, SIMD::Int(0x80000000)) & CmpEQ(b, SIMD::Int(-1))); // prevent integer overflow
2376 auto mod = a % b;
Ben Claytonbb8c8e22019-03-08 12:04:00 +00002377 // If a and b have opposite signs, the remainder operation takes
2378 // the sign from a but OpSMod is supposed to take the sign of b.
2379 // Adding b will ensure that the result has the correct sign and
2380 // that it is still congruent to a modulo b.
2381 //
2382 // See also http://mathforum.org/library/drmath/view/52343.html
2383 auto signDiff = CmpNEQ(CmpGE(a, SIMD::Int(0)), CmpGE(b, SIMD::Int(0)));
2384 auto fixedMod = mod + (b & CmpNEQ(mod, SIMD::Int(0)) & signDiff);
Nicolas Capens80c796b2019-03-19 21:38:44 -04002385 dst.move(i, As<SIMD::Float>(fixedMod));
Ben Claytonbb8c8e22019-03-08 12:04:00 +00002386 break;
2387 }
Ben Claytondd1e37e2019-02-28 19:59:15 +00002388 case spv::OpUMod:
Chris Forbes3ebf5832019-03-14 08:15:25 -07002389 {
2390 auto zeroMask = As<SIMD::UInt>(CmpEQ(rhs.Int(i), SIMD::Int(0)));
Nicolas Capens80c796b2019-03-19 21:38:44 -04002391 dst.move(i, lhs.UInt(i) % (rhs.UInt(i) | zeroMask));
Ben Claytondd1e37e2019-02-28 19:59:15 +00002392 break;
Chris Forbes3ebf5832019-03-14 08:15:25 -07002393 }
Ben Claytone95eeb12019-03-04 16:32:09 +00002394 case spv::OpIEqual:
Chris Forbes787b4462019-03-08 12:16:57 -08002395 case spv::OpLogicalEqual:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002396 dst.move(i, CmpEQ(lhs.Int(i), rhs.Int(i)));
Ben Claytone95eeb12019-03-04 16:32:09 +00002397 break;
2398 case spv::OpINotEqual:
Chris Forbes787b4462019-03-08 12:16:57 -08002399 case spv::OpLogicalNotEqual:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002400 dst.move(i, CmpNEQ(lhs.Int(i), rhs.Int(i)));
Ben Claytone95eeb12019-03-04 16:32:09 +00002401 break;
2402 case spv::OpUGreaterThan:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002403 dst.move(i, CmpGT(lhs.UInt(i), rhs.UInt(i)));
Ben Claytone95eeb12019-03-04 16:32:09 +00002404 break;
2405 case spv::OpSGreaterThan:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002406 dst.move(i, CmpGT(lhs.Int(i), rhs.Int(i)));
Ben Claytone95eeb12019-03-04 16:32:09 +00002407 break;
2408 case spv::OpUGreaterThanEqual:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002409 dst.move(i, CmpGE(lhs.UInt(i), rhs.UInt(i)));
Ben Claytone95eeb12019-03-04 16:32:09 +00002410 break;
2411 case spv::OpSGreaterThanEqual:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002412 dst.move(i, CmpGE(lhs.Int(i), rhs.Int(i)));
Ben Claytone95eeb12019-03-04 16:32:09 +00002413 break;
2414 case spv::OpULessThan:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002415 dst.move(i, CmpLT(lhs.UInt(i), rhs.UInt(i)));
Ben Claytone95eeb12019-03-04 16:32:09 +00002416 break;
2417 case spv::OpSLessThan:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002418 dst.move(i, CmpLT(lhs.Int(i), rhs.Int(i)));
Ben Claytone95eeb12019-03-04 16:32:09 +00002419 break;
2420 case spv::OpULessThanEqual:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002421 dst.move(i, CmpLE(lhs.UInt(i), rhs.UInt(i)));
Ben Claytone95eeb12019-03-04 16:32:09 +00002422 break;
2423 case spv::OpSLessThanEqual:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002424 dst.move(i, CmpLE(lhs.Int(i), rhs.Int(i)));
Ben Claytone95eeb12019-03-04 16:32:09 +00002425 break;
Ben Claytondd1e37e2019-02-28 19:59:15 +00002426 case spv::OpFAdd:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002427 dst.move(i, lhs.Float(i) + rhs.Float(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00002428 break;
2429 case spv::OpFSub:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002430 dst.move(i, lhs.Float(i) - rhs.Float(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00002431 break;
Chris Forbes9d931532019-03-08 09:53:03 -08002432 case spv::OpFMul:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002433 dst.move(i, lhs.Float(i) * rhs.Float(i));
Chris Forbes9d931532019-03-08 09:53:03 -08002434 break;
Ben Claytondd1e37e2019-02-28 19:59:15 +00002435 case spv::OpFDiv:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002436 dst.move(i, lhs.Float(i) / rhs.Float(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00002437 break;
Chris Forbes0e4d6ff2019-03-15 13:43:36 -07002438 case spv::OpFMod:
2439 // TODO(b/126873455): inaccurate for values greater than 2^24
Nicolas Capens80c796b2019-03-19 21:38:44 -04002440 dst.move(i, lhs.Float(i) - rhs.Float(i) * Floor(lhs.Float(i) / rhs.Float(i)));
Chris Forbes0e4d6ff2019-03-15 13:43:36 -07002441 break;
Chris Forbes1a4c7122019-03-15 14:50:47 -07002442 case spv::OpFRem:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002443 dst.move(i, lhs.Float(i) % rhs.Float(i));
Chris Forbes1a4c7122019-03-15 14:50:47 -07002444 break;
Ben Claytonec1aeb82019-03-04 19:33:27 +00002445 case spv::OpFOrdEqual:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002446 dst.move(i, CmpEQ(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00002447 break;
2448 case spv::OpFUnordEqual:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002449 dst.move(i, CmpUEQ(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00002450 break;
2451 case spv::OpFOrdNotEqual:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002452 dst.move(i, CmpNEQ(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00002453 break;
2454 case spv::OpFUnordNotEqual:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002455 dst.move(i, CmpUNEQ(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00002456 break;
2457 case spv::OpFOrdLessThan:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002458 dst.move(i, CmpLT(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00002459 break;
2460 case spv::OpFUnordLessThan:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002461 dst.move(i, CmpULT(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00002462 break;
2463 case spv::OpFOrdGreaterThan:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002464 dst.move(i, CmpGT(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00002465 break;
2466 case spv::OpFUnordGreaterThan:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002467 dst.move(i, CmpUGT(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00002468 break;
2469 case spv::OpFOrdLessThanEqual:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002470 dst.move(i, CmpLE(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00002471 break;
2472 case spv::OpFUnordLessThanEqual:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002473 dst.move(i, CmpULE(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00002474 break;
2475 case spv::OpFOrdGreaterThanEqual:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002476 dst.move(i, CmpGE(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00002477 break;
2478 case spv::OpFUnordGreaterThanEqual:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002479 dst.move(i, CmpUGE(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00002480 break;
Ben Claytondd1e37e2019-02-28 19:59:15 +00002481 case spv::OpShiftRightLogical:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002482 dst.move(i, lhs.UInt(i) >> rhs.UInt(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00002483 break;
2484 case spv::OpShiftRightArithmetic:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002485 dst.move(i, lhs.Int(i) >> rhs.Int(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00002486 break;
2487 case spv::OpShiftLeftLogical:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002488 dst.move(i, lhs.UInt(i) << rhs.UInt(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00002489 break;
2490 case spv::OpBitwiseOr:
2491 case spv::OpLogicalOr:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002492 dst.move(i, lhs.UInt(i) | rhs.UInt(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00002493 break;
2494 case spv::OpBitwiseXor:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002495 dst.move(i, lhs.UInt(i) ^ rhs.UInt(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00002496 break;
2497 case spv::OpBitwiseAnd:
2498 case spv::OpLogicalAnd:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002499 dst.move(i, lhs.UInt(i) & rhs.UInt(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00002500 break;
Chris Forbese86b6dc2019-03-01 09:08:47 -08002501 case spv::OpSMulExtended:
2502 // Extended ops: result is a structure containing two members of the same type as lhs & rhs.
2503 // In our flat view then, component i is the i'th component of the first member;
2504 // component i + N is the i'th component of the second member.
Nicolas Capens80c796b2019-03-19 21:38:44 -04002505 dst.move(i, lhs.Int(i) * rhs.Int(i));
2506 dst.move(i + lhsType.sizeInComponents, MulHigh(lhs.Int(i), rhs.Int(i)));
Chris Forbese86b6dc2019-03-01 09:08:47 -08002507 break;
2508 case spv::OpUMulExtended:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002509 dst.move(i, lhs.UInt(i) * rhs.UInt(i));
2510 dst.move(i + lhsType.sizeInComponents, MulHigh(lhs.UInt(i), rhs.UInt(i)));
Chris Forbese86b6dc2019-03-01 09:08:47 -08002511 break;
Ben Claytondd1e37e2019-02-28 19:59:15 +00002512 default:
2513 UNIMPLEMENTED("Unhandled binary operator %s", OpcodeName(insn.opcode()).c_str());
2514 }
2515 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002516
2517 return EmitResult::Continue;
Ben Claytondd1e37e2019-02-28 19:59:15 +00002518 }
2519
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002520 SpirvShader::EmitResult SpirvShader::EmitDot(InsnIterator insn, EmitState *state) const
Chris Forbes2b287cc2019-03-01 13:24:17 -08002521 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002522 auto routine = state->routine;
Chris Forbes2b287cc2019-03-01 13:24:17 -08002523 auto &type = getType(insn.word(1));
Ben Claytonaf26cfe2019-03-21 17:32:44 +00002524 ASSERT(type.sizeInComponents == 1);
Chris Forbes2b287cc2019-03-01 13:24:17 -08002525 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
2526 auto &lhsType = getType(getObject(insn.word(3)).type);
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002527 auto lhs = GenericValue(this, routine, insn.word(3));
2528 auto rhs = GenericValue(this, routine, insn.word(4));
Chris Forbes2b287cc2019-03-01 13:24:17 -08002529
Nicolas Capens80c796b2019-03-19 21:38:44 -04002530 dst.move(0, Dot(lhsType.sizeInComponents, lhs, rhs));
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002531 return EmitResult::Continue;
Chris Forbes2b287cc2019-03-01 13:24:17 -08002532 }
2533
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002534 SpirvShader::EmitResult SpirvShader::EmitSelect(InsnIterator insn, EmitState *state) const
Ben Claytonbf943f62019-03-05 12:57:39 +00002535 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002536 auto routine = state->routine;
Ben Claytonbf943f62019-03-05 12:57:39 +00002537 auto &type = getType(insn.word(1));
2538 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002539 auto cond = GenericValue(this, routine, insn.word(3));
2540 auto lhs = GenericValue(this, routine, insn.word(4));
2541 auto rhs = GenericValue(this, routine, insn.word(5));
Ben Claytonbf943f62019-03-05 12:57:39 +00002542
2543 for (auto i = 0u; i < type.sizeInComponents; i++)
2544 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002545 dst.move(i, (cond.Int(i) & lhs.Int(i)) | (~cond.Int(i) & rhs.Int(i))); // FIXME: IfThenElse()
Ben Claytonbf943f62019-03-05 12:57:39 +00002546 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002547
2548 return EmitResult::Continue;
Ben Claytonbf943f62019-03-05 12:57:39 +00002549 }
2550
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002551 SpirvShader::EmitResult SpirvShader::EmitExtendedInstruction(InsnIterator insn, EmitState *state) const
Chris Forbes9667a5b2019-03-07 09:26:48 -08002552 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002553 auto routine = state->routine;
Chris Forbes9667a5b2019-03-07 09:26:48 -08002554 auto &type = getType(insn.word(1));
2555 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
2556 auto extInstIndex = static_cast<GLSLstd450>(insn.word(4));
2557
2558 switch (extInstIndex)
2559 {
2560 case GLSLstd450FAbs:
2561 {
2562 auto src = GenericValue(this, routine, insn.word(5));
2563 for (auto i = 0u; i < type.sizeInComponents; i++)
2564 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002565 dst.move(i, Abs(src.Float(i)));
Chris Forbes9667a5b2019-03-07 09:26:48 -08002566 }
2567 break;
2568 }
2569 case GLSLstd450SAbs:
2570 {
2571 auto src = GenericValue(this, routine, insn.word(5));
2572 for (auto i = 0u; i < type.sizeInComponents; i++)
2573 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002574 dst.move(i, Abs(src.Int(i)));
Chris Forbes9667a5b2019-03-07 09:26:48 -08002575 }
2576 break;
2577 }
Chris Forbes15dff362019-03-08 11:31:31 -08002578 case GLSLstd450Cross:
2579 {
2580 auto lhs = GenericValue(this, routine, insn.word(5));
2581 auto rhs = GenericValue(this, routine, insn.word(6));
Nicolas Capens80c796b2019-03-19 21:38:44 -04002582 dst.move(0, lhs.Float(1) * rhs.Float(2) - rhs.Float(1) * lhs.Float(2));
2583 dst.move(1, lhs.Float(2) * rhs.Float(0) - rhs.Float(2) * lhs.Float(0));
2584 dst.move(2, lhs.Float(0) * rhs.Float(1) - rhs.Float(0) * lhs.Float(1));
Chris Forbes15dff362019-03-08 11:31:31 -08002585 break;
2586 }
Chris Forbesc212bbd2019-03-08 12:02:27 -08002587 case GLSLstd450Floor:
2588 {
2589 auto src = GenericValue(this, routine, insn.word(5));
2590 for (auto i = 0u; i < type.sizeInComponents; i++)
2591 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002592 dst.move(i, Floor(src.Float(i)));
Chris Forbesc212bbd2019-03-08 12:02:27 -08002593 }
2594 break;
2595 }
Chris Forbesdd172cc2019-03-08 13:36:40 -08002596 case GLSLstd450Trunc:
2597 {
2598 auto src = GenericValue(this, routine, insn.word(5));
2599 for (auto i = 0u; i < type.sizeInComponents; i++)
2600 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002601 dst.move(i, Trunc(src.Float(i)));
Chris Forbesdd172cc2019-03-08 13:36:40 -08002602 }
2603 break;
2604 }
2605 case GLSLstd450Ceil:
2606 {
2607 auto src = GenericValue(this, routine, insn.word(5));
2608 for (auto i = 0u; i < type.sizeInComponents; i++)
2609 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002610 dst.move(i, Ceil(src.Float(i)));
Chris Forbesdd172cc2019-03-08 13:36:40 -08002611 }
2612 break;
2613 }
2614 case GLSLstd450Fract:
2615 {
2616 auto src = GenericValue(this, routine, insn.word(5));
2617 for (auto i = 0u; i < type.sizeInComponents; i++)
2618 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002619 dst.move(i, Frac(src.Float(i)));
Chris Forbesdd172cc2019-03-08 13:36:40 -08002620 }
2621 break;
2622 }
2623 case GLSLstd450Round:
2624 {
2625 auto src = GenericValue(this, routine, insn.word(5));
2626 for (auto i = 0u; i < type.sizeInComponents; i++)
2627 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002628 dst.move(i, Round(src.Float(i)));
Chris Forbesdd172cc2019-03-08 13:36:40 -08002629 }
2630 break;
2631 }
2632 case GLSLstd450RoundEven:
2633 {
2634 auto src = GenericValue(this, routine, insn.word(5));
2635 for (auto i = 0u; i < type.sizeInComponents; i++)
2636 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002637 auto x = Round(src.Float(i));
Chris Forbesdd172cc2019-03-08 13:36:40 -08002638 // dst = round(src) + ((round(src) < src) * 2 - 1) * (fract(src) == 0.5) * isOdd(round(src));
Nicolas Capens80c796b2019-03-19 21:38:44 -04002639 dst.move(i, x + ((SIMD::Float(CmpLT(x, src.Float(i)) & SIMD::Int(1)) * SIMD::Float(2.0f)) - SIMD::Float(1.0f)) *
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002640 SIMD::Float(CmpEQ(Frac(src.Float(i)), SIMD::Float(0.5f)) & SIMD::Int(1)) * SIMD::Float(Int4(x) & SIMD::Int(1)));
Chris Forbesdd172cc2019-03-08 13:36:40 -08002641 }
2642 break;
2643 }
Chris Forbesdb170772019-03-08 14:50:44 -08002644 case GLSLstd450FMin:
2645 {
2646 auto lhs = GenericValue(this, routine, insn.word(5));
2647 auto rhs = GenericValue(this, routine, insn.word(6));
2648 for (auto i = 0u; i < type.sizeInComponents; i++)
2649 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002650 dst.move(i, Min(lhs.Float(i), rhs.Float(i)));
Chris Forbesdb170772019-03-08 14:50:44 -08002651 }
2652 break;
2653 }
2654 case GLSLstd450FMax:
2655 {
2656 auto lhs = GenericValue(this, routine, insn.word(5));
2657 auto rhs = GenericValue(this, routine, insn.word(6));
2658 for (auto i = 0u; i < type.sizeInComponents; i++)
2659 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002660 dst.move(i, Max(lhs.Float(i), rhs.Float(i)));
Chris Forbesdb170772019-03-08 14:50:44 -08002661 }
2662 break;
2663 }
2664 case GLSLstd450SMin:
2665 {
2666 auto lhs = GenericValue(this, routine, insn.word(5));
2667 auto rhs = GenericValue(this, routine, insn.word(6));
2668 for (auto i = 0u; i < type.sizeInComponents; i++)
2669 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002670 dst.move(i, Min(lhs.Int(i), rhs.Int(i)));
Chris Forbesdb170772019-03-08 14:50:44 -08002671 }
2672 break;
2673 }
2674 case GLSLstd450SMax:
2675 {
2676 auto lhs = GenericValue(this, routine, insn.word(5));
2677 auto rhs = GenericValue(this, routine, insn.word(6));
2678 for (auto i = 0u; i < type.sizeInComponents; i++)
2679 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002680 dst.move(i, Max(lhs.Int(i), rhs.Int(i)));
Chris Forbesdb170772019-03-08 14:50:44 -08002681 }
2682 break;
2683 }
2684 case GLSLstd450UMin:
2685 {
2686 auto lhs = GenericValue(this, routine, insn.word(5));
2687 auto rhs = GenericValue(this, routine, insn.word(6));
2688 for (auto i = 0u; i < type.sizeInComponents; i++)
2689 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002690 dst.move(i, Min(lhs.UInt(i), rhs.UInt(i)));
Chris Forbesdb170772019-03-08 14:50:44 -08002691 }
2692 break;
2693 }
2694 case GLSLstd450UMax:
2695 {
2696 auto lhs = GenericValue(this, routine, insn.word(5));
2697 auto rhs = GenericValue(this, routine, insn.word(6));
2698 for (auto i = 0u; i < type.sizeInComponents; i++)
2699 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002700 dst.move(i, Max(lhs.UInt(i), rhs.UInt(i)));
Chris Forbesdb170772019-03-08 14:50:44 -08002701 }
2702 break;
2703 }
2704 case GLSLstd450Step:
2705 {
2706 auto edge = GenericValue(this, routine, insn.word(5));
2707 auto x = GenericValue(this, routine, insn.word(6));
2708 for (auto i = 0u; i < type.sizeInComponents; i++)
2709 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002710 dst.move(i, CmpNLT(x.Float(i), edge.Float(i)) & As<SIMD::Int>(SIMD::Float(1.0f)));
Chris Forbesdb170772019-03-08 14:50:44 -08002711 }
2712 break;
2713 }
2714 case GLSLstd450SmoothStep:
2715 {
2716 auto edge0 = GenericValue(this, routine, insn.word(5));
2717 auto edge1 = GenericValue(this, routine, insn.word(6));
2718 auto x = GenericValue(this, routine, insn.word(7));
2719 for (auto i = 0u; i < type.sizeInComponents; i++)
2720 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002721 auto tx = Min(Max((x.Float(i) - edge0.Float(i)) /
2722 (edge1.Float(i) - edge0.Float(i)), SIMD::Float(0.0f)), SIMD::Float(1.0f));
Nicolas Capens80c796b2019-03-19 21:38:44 -04002723 dst.move(i, tx * tx * (Float4(3.0f) - Float4(2.0f) * tx));
Chris Forbesdb170772019-03-08 14:50:44 -08002724 }
2725 break;
2726 }
2727 case GLSLstd450FMix:
2728 {
2729 auto x = GenericValue(this, routine, insn.word(5));
2730 auto y = GenericValue(this, routine, insn.word(6));
2731 auto a = GenericValue(this, routine, insn.word(7));
2732 for (auto i = 0u; i < type.sizeInComponents; i++)
2733 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002734 dst.move(i, a.Float(i) * (y.Float(i) - x.Float(i)) + x.Float(i));
Chris Forbesdb170772019-03-08 14:50:44 -08002735 }
2736 break;
2737 }
2738 case GLSLstd450FClamp:
2739 {
2740 auto x = GenericValue(this, routine, insn.word(5));
2741 auto minVal = GenericValue(this, routine, insn.word(6));
2742 auto maxVal = GenericValue(this, routine, insn.word(7));
2743 for (auto i = 0u; i < type.sizeInComponents; i++)
2744 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002745 dst.move(i, Min(Max(x.Float(i), minVal.Float(i)), maxVal.Float(i)));
Chris Forbesdb170772019-03-08 14:50:44 -08002746 }
2747 break;
2748 }
2749 case GLSLstd450SClamp:
2750 {
2751 auto x = GenericValue(this, routine, insn.word(5));
2752 auto minVal = GenericValue(this, routine, insn.word(6));
2753 auto maxVal = GenericValue(this, routine, insn.word(7));
2754 for (auto i = 0u; i < type.sizeInComponents; i++)
2755 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002756 dst.move(i, Min(Max(x.Int(i), minVal.Int(i)), maxVal.Int(i)));
Chris Forbesdb170772019-03-08 14:50:44 -08002757 }
2758 break;
2759 }
2760 case GLSLstd450UClamp:
2761 {
2762 auto x = GenericValue(this, routine, insn.word(5));
2763 auto minVal = GenericValue(this, routine, insn.word(6));
2764 auto maxVal = GenericValue(this, routine, insn.word(7));
2765 for (auto i = 0u; i < type.sizeInComponents; i++)
2766 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002767 dst.move(i, Min(Max(x.UInt(i), minVal.UInt(i)), maxVal.UInt(i)));
Chris Forbesdb170772019-03-08 14:50:44 -08002768 }
2769 break;
2770 }
2771 case GLSLstd450FSign:
2772 {
2773 auto src = GenericValue(this, routine, insn.word(5));
2774 for (auto i = 0u; i < type.sizeInComponents; i++)
2775 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002776 auto neg = As<SIMD::Int>(CmpLT(src.Float(i), SIMD::Float(-0.0f))) & As<SIMD::Int>(SIMD::Float(-1.0f));
2777 auto pos = As<SIMD::Int>(CmpNLE(src.Float(i), SIMD::Float(+0.0f))) & As<SIMD::Int>(SIMD::Float(1.0f));
Nicolas Capens80c796b2019-03-19 21:38:44 -04002778 dst.move(i, neg | pos);
Chris Forbesdb170772019-03-08 14:50:44 -08002779 }
2780 break;
2781 }
2782 case GLSLstd450SSign:
2783 {
2784 auto src = GenericValue(this, routine, insn.word(5));
2785 for (auto i = 0u; i < type.sizeInComponents; i++)
2786 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002787 auto neg = CmpLT(src.Int(i), SIMD::Int(0)) & SIMD::Int(-1);
2788 auto pos = CmpNLE(src.Int(i), SIMD::Int(0)) & SIMD::Int(1);
Nicolas Capens80c796b2019-03-19 21:38:44 -04002789 dst.move(i, neg | pos);
Chris Forbesdb170772019-03-08 14:50:44 -08002790 }
2791 break;
2792 }
Chris Forbes868ed902019-03-13 17:39:45 -07002793 case GLSLstd450Reflect:
2794 {
2795 auto I = GenericValue(this, routine, insn.word(5));
2796 auto N = GenericValue(this, routine, insn.word(6));
2797
2798 SIMD::Float d = Dot(type.sizeInComponents, I, N);
2799
2800 for (auto i = 0u; i < type.sizeInComponents; i++)
2801 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002802 dst.move(i, I.Float(i) - SIMD::Float(2.0f) * d * N.Float(i));
Chris Forbes868ed902019-03-13 17:39:45 -07002803 }
2804 break;
2805 }
2806 case GLSLstd450Refract:
2807 {
2808 auto I = GenericValue(this, routine, insn.word(5));
2809 auto N = GenericValue(this, routine, insn.word(6));
2810 auto eta = GenericValue(this, routine, insn.word(7));
2811
2812 SIMD::Float d = Dot(type.sizeInComponents, I, N);
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002813 SIMD::Float k = SIMD::Float(1.0f) - eta.Float(0) * eta.Float(0) * (SIMD::Float(1.0f) - d * d);
Chris Forbes868ed902019-03-13 17:39:45 -07002814 SIMD::Int pos = CmpNLT(k, SIMD::Float(0.0f));
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002815 SIMD::Float t = (eta.Float(0) * d + Sqrt(k));
Chris Forbes868ed902019-03-13 17:39:45 -07002816
2817 for (auto i = 0u; i < type.sizeInComponents; i++)
2818 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002819 dst.move(i, pos & As<SIMD::Int>(eta.Float(0) * I.Float(i) - t * N.Float(i)));
Chris Forbes868ed902019-03-13 17:39:45 -07002820 }
2821 break;
2822 }
2823 case GLSLstd450FaceForward:
2824 {
2825 auto N = GenericValue(this, routine, insn.word(5));
2826 auto I = GenericValue(this, routine, insn.word(6));
2827 auto Nref = GenericValue(this, routine, insn.word(7));
2828
2829 SIMD::Float d = Dot(type.sizeInComponents, I, Nref);
2830 SIMD::Int neg = CmpLT(d, SIMD::Float(0.0f));
2831
2832 for (auto i = 0u; i < type.sizeInComponents; i++)
2833 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002834 auto n = N.Float(i);
Nicolas Capens80c796b2019-03-19 21:38:44 -04002835 dst.move(i, (neg & As<SIMD::Int>(n)) | (~neg & As<SIMD::Int>(-n)));
Chris Forbes868ed902019-03-13 17:39:45 -07002836 }
2837 break;
2838 }
2839 case GLSLstd450Length:
2840 {
2841 auto x = GenericValue(this, routine, insn.word(5));
2842 SIMD::Float d = Dot(getType(getObject(insn.word(5)).type).sizeInComponents, x, x);
2843
Nicolas Capens80c796b2019-03-19 21:38:44 -04002844 dst.move(0, Sqrt(d));
Chris Forbes868ed902019-03-13 17:39:45 -07002845 break;
2846 }
2847 case GLSLstd450Normalize:
2848 {
2849 auto x = GenericValue(this, routine, insn.word(5));
2850 SIMD::Float d = Dot(getType(getObject(insn.word(5)).type).sizeInComponents, x, x);
2851 SIMD::Float invLength = SIMD::Float(1.0f) / Sqrt(d);
2852
2853 for (auto i = 0u; i < type.sizeInComponents; i++)
2854 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002855 dst.move(i, invLength * x.Float(i));
Chris Forbes868ed902019-03-13 17:39:45 -07002856 }
2857 break;
2858 }
2859 case GLSLstd450Distance:
2860 {
2861 auto p0 = GenericValue(this, routine, insn.word(5));
2862 auto p1 = GenericValue(this, routine, insn.word(6));
2863 auto p0Type = getType(getObject(insn.word(5)).type);
2864
2865 // sqrt(dot(p0-p1, p0-p1))
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002866 SIMD::Float d = (p0.Float(0) - p1.Float(0)) * (p0.Float(0) - p1.Float(0));
Chris Forbes868ed902019-03-13 17:39:45 -07002867
2868 for (auto i = 1u; i < p0Type.sizeInComponents; i++)
2869 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002870 d += (p0.Float(i) - p1.Float(i)) * (p0.Float(i) - p1.Float(i));
Chris Forbes868ed902019-03-13 17:39:45 -07002871 }
2872
Nicolas Capens80c796b2019-03-19 21:38:44 -04002873 dst.move(0, Sqrt(d));
Chris Forbes868ed902019-03-13 17:39:45 -07002874 break;
2875 }
Chris Forbes9667a5b2019-03-07 09:26:48 -08002876 default:
2877 UNIMPLEMENTED("Unhandled ExtInst %d", extInstIndex);
2878 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002879
2880 return EmitResult::Continue;
Chris Forbes9667a5b2019-03-07 09:26:48 -08002881 }
2882
Nicolas Capens86509d92019-03-21 13:23:50 -04002883 std::memory_order SpirvShader::MemoryOrder(spv::MemorySemanticsMask memorySemantics)
2884 {
2885 switch(memorySemantics)
2886 {
2887 case spv::MemorySemanticsMaskNone: return std::memory_order_relaxed;
2888 case spv::MemorySemanticsAcquireMask: return std::memory_order_acquire;
2889 case spv::MemorySemanticsReleaseMask: return std::memory_order_release;
2890 case spv::MemorySemanticsAcquireReleaseMask: return std::memory_order_acq_rel;
2891 case spv::MemorySemanticsSequentiallyConsistentMask: return std::memory_order_acq_rel; // Vulkan 1.1: "SequentiallyConsistent is treated as AcquireRelease"
2892 default:
2893 UNREACHABLE("MemorySemanticsMask %x", memorySemantics);
2894 return std::memory_order_acq_rel;
2895 }
2896 }
2897
Chris Forbes868ed902019-03-13 17:39:45 -07002898 SIMD::Float SpirvShader::Dot(unsigned numComponents, GenericValue const & x, GenericValue const & y) const
2899 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002900 SIMD::Float d = x.Float(0) * y.Float(0);
Chris Forbes868ed902019-03-13 17:39:45 -07002901
2902 for (auto i = 1u; i < numComponents; i++)
2903 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002904 d += x.Float(i) * y.Float(i);
Chris Forbes868ed902019-03-13 17:39:45 -07002905 }
2906
2907 return d;
2908 }
2909
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002910 SpirvShader::EmitResult SpirvShader::EmitAny(InsnIterator insn, EmitState *state) const
Chris Forbes0785f692019-03-08 09:09:18 -08002911 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002912 auto routine = state->routine;
Chris Forbes0785f692019-03-08 09:09:18 -08002913 auto &type = getType(insn.word(1));
Ben Claytonaf26cfe2019-03-21 17:32:44 +00002914 ASSERT(type.sizeInComponents == 1);
Chris Forbes0785f692019-03-08 09:09:18 -08002915 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
2916 auto &srcType = getType(getObject(insn.word(3)).type);
2917 auto src = GenericValue(this, routine, insn.word(3));
2918
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002919 SIMD::UInt result = src.UInt(0);
Chris Forbes0785f692019-03-08 09:09:18 -08002920
2921 for (auto i = 1u; i < srcType.sizeInComponents; i++)
2922 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002923 result |= src.UInt(i);
Chris Forbes0785f692019-03-08 09:09:18 -08002924 }
2925
Nicolas Capens80c796b2019-03-19 21:38:44 -04002926 dst.move(0, result);
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002927 return EmitResult::Continue;
Chris Forbes0785f692019-03-08 09:09:18 -08002928 }
2929
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002930 SpirvShader::EmitResult SpirvShader::EmitAll(InsnIterator insn, EmitState *state) const
Chris Forbes0785f692019-03-08 09:09:18 -08002931 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002932 auto routine = state->routine;
Chris Forbes0785f692019-03-08 09:09:18 -08002933 auto &type = getType(insn.word(1));
Ben Claytonaf26cfe2019-03-21 17:32:44 +00002934 ASSERT(type.sizeInComponents == 1);
Chris Forbes0785f692019-03-08 09:09:18 -08002935 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
2936 auto &srcType = getType(getObject(insn.word(3)).type);
2937 auto src = GenericValue(this, routine, insn.word(3));
2938
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002939 SIMD::UInt result = src.UInt(0);
Chris Forbes0785f692019-03-08 09:09:18 -08002940
2941 for (auto i = 1u; i < srcType.sizeInComponents; i++)
2942 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002943 result &= src.UInt(i);
Chris Forbes0785f692019-03-08 09:09:18 -08002944 }
2945
Nicolas Capens80c796b2019-03-19 21:38:44 -04002946 dst.move(0, result);
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002947 return EmitResult::Continue;
Chris Forbes0785f692019-03-08 09:09:18 -08002948 }
2949
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002950 SpirvShader::EmitResult SpirvShader::EmitBranch(InsnIterator insn, EmitState *state) const
Ben Claytone37ce612019-03-13 19:57:42 +00002951 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002952 auto target = Block::ID(insn.word(1));
2953 auto edge = Block::Edge{state->currentBlock, target};
2954 state->edgeActiveLaneMasks.emplace(edge, state->activeLaneMask());
2955 return EmitResult::Terminator;
Ben Claytone37ce612019-03-13 19:57:42 +00002956 }
2957
Ben Clayton9fd02e02019-03-21 18:47:15 +00002958 SpirvShader::EmitResult SpirvShader::EmitBranchConditional(InsnIterator insn, EmitState *state) const
2959 {
2960 auto block = getBlock(state->currentBlock);
2961 ASSERT(block.branchInstruction == insn);
2962
2963 auto condId = Object::ID(block.branchInstruction.word(1));
2964 auto trueBlockId = Block::ID(block.branchInstruction.word(2));
2965 auto falseBlockId = Block::ID(block.branchInstruction.word(3));
2966
2967 auto cond = GenericValue(this, state->routine, condId);
2968 ASSERT_MSG(getType(getObject(condId).type).sizeInComponents == 1, "Condition must be a Boolean type scalar");
2969
2970 // TODO: Optimize for case where all lanes take same path.
2971
2972 state->addOutputActiveLaneMaskEdge(trueBlockId, cond.Int(0));
2973 state->addOutputActiveLaneMaskEdge(falseBlockId, ~cond.Int(0));
2974
2975 return EmitResult::Terminator;
2976 }
2977
Ben Clayton213a8ce2019-03-21 18:57:23 +00002978 SpirvShader::EmitResult SpirvShader::EmitSwitch(InsnIterator insn, EmitState *state) const
2979 {
2980 auto block = getBlock(state->currentBlock);
2981 ASSERT(block.branchInstruction == insn);
2982
2983 auto selId = Object::ID(block.branchInstruction.word(1));
2984
2985 auto sel = GenericValue(this, state->routine, selId);
2986 ASSERT_MSG(getType(getObject(selId).type).sizeInComponents == 1, "Selector must be a scalar");
2987
2988 auto numCases = (block.branchInstruction.wordCount() - 3) / 2;
2989
2990 // TODO: Optimize for case where all lanes take same path.
2991
2992 SIMD::Int defaultLaneMask = state->activeLaneMask();
2993
2994 // Gather up the case label matches and calculate defaultLaneMask.
2995 std::vector<RValue<SIMD::Int>> caseLabelMatches;
2996 caseLabelMatches.reserve(numCases);
2997 for (uint32_t i = 0; i < numCases; i++)
2998 {
2999 auto label = block.branchInstruction.word(i * 2 + 3);
3000 auto caseBlockId = Block::ID(block.branchInstruction.word(i * 2 + 4));
3001 auto caseLabelMatch = CmpEQ(sel.Int(0), SIMD::Int(label));
3002 state->addOutputActiveLaneMaskEdge(caseBlockId, caseLabelMatch);
3003 defaultLaneMask &= ~caseLabelMatch;
3004 }
3005
3006 auto defaultBlockId = Block::ID(block.branchInstruction.word(2));
3007 state->addOutputActiveLaneMaskEdge(defaultBlockId, defaultLaneMask);
3008
3009 return EmitResult::Terminator;
3010 }
Ben Clayton9fd02e02019-03-21 18:47:15 +00003011
3012 SpirvShader::EmitResult SpirvShader::EmitUnreachable(InsnIterator insn, EmitState *state) const
3013 {
3014 // TODO: Log something in this case?
3015 state->setActiveLaneMask(SIMD::Int(0));
3016 return EmitResult::Terminator;
3017 }
3018
3019 SpirvShader::EmitResult SpirvShader::EmitReturn(InsnIterator insn, EmitState *state) const
3020 {
3021 state->setActiveLaneMask(SIMD::Int(0));
3022 return EmitResult::Terminator;
3023 }
3024
3025 SpirvShader::EmitResult SpirvShader::EmitPhi(InsnIterator insn, EmitState *state) const
3026 {
3027 auto routine = state->routine;
3028 auto typeId = Type::ID(insn.word(1));
3029 auto type = getType(typeId);
3030 auto objectId = Object::ID(insn.word(2));
3031
Nicolas Capens459453a2019-03-27 15:27:27 -04003032 auto tmp = std::unique_ptr<SIMD::Int[]>(new SIMD::Int[type.sizeInComponents]);
Ben Clayton9fd02e02019-03-21 18:47:15 +00003033
3034 bool first = true;
3035 for (uint32_t w = 3; w < insn.wordCount(); w += 2)
3036 {
3037 auto varId = Object::ID(insn.word(w + 0));
3038 auto blockId = Block::ID(insn.word(w + 1));
3039
3040 auto in = GenericValue(this, routine, varId);
Ben Claytonfe3f0132019-03-26 11:10:16 +00003041 auto mask = GetActiveLaneMaskEdge(state, blockId, state->currentBlock);
Ben Clayton9fd02e02019-03-21 18:47:15 +00003042
3043 for (uint32_t i = 0; i < type.sizeInComponents; i++)
3044 {
3045 auto inMasked = in.Int(i) & mask;
Nicolas Capens459453a2019-03-27 15:27:27 -04003046 tmp[i] = first ? inMasked : (tmp[i] | inMasked);
Ben Clayton9fd02e02019-03-21 18:47:15 +00003047 }
3048 first = false;
3049 }
3050
Nicolas Capens459453a2019-03-27 15:27:27 -04003051 auto &dst = routine->createIntermediate(objectId, type.sizeInComponents);
3052 for(uint32_t i = 0; i < type.sizeInComponents; i++)
3053 {
3054 dst.move(i, tmp[i]);
3055 }
3056
Ben Clayton9fd02e02019-03-21 18:47:15 +00003057 return EmitResult::Continue;
3058 }
3059
Chris Forbesc61271e2019-02-19 17:01:28 -08003060 void SpirvShader::emitEpilog(SpirvRoutine *routine) const
3061 {
3062 for (auto insn : *this)
3063 {
3064 switch (insn.opcode())
3065 {
3066 case spv::OpVariable:
3067 {
Ben Claytonaf973b62019-03-13 18:19:20 +00003068 Object::ID resultId = insn.word(2);
Chris Forbesc61271e2019-02-19 17:01:28 -08003069 auto &object = getObject(resultId);
Ben Clayton9a162482019-02-25 11:54:43 +00003070 auto &objectTy = getType(object.type);
3071 if (object.kind == Object::Kind::InterfaceVariable && objectTy.storageClass == spv::StorageClassOutput)
Chris Forbesc61271e2019-02-19 17:01:28 -08003072 {
3073 auto &dst = routine->getValue(resultId);
3074 int offset = 0;
3075 VisitInterface(resultId,
3076 [&](Decorations const &d, AttribType type) {
3077 auto scalarSlot = d.Location << 2 | d.Component;
3078 routine->outputs[scalarSlot] = dst[offset++];
3079 });
3080 }
3081 break;
3082 }
3083 default:
3084 break;
3085 }
3086 }
3087 }
Ben Clayton76e9bc02019-02-26 15:02:18 +00003088
Ben Clayton64f78f52019-03-21 17:21:06 +00003089 SpirvShader::Block::Block(InsnIterator begin, InsnIterator end) : begin_(begin), end_(end)
3090 {
3091 // Default to a Simple, this may change later.
3092 kind = Block::Simple;
3093
3094 // Walk the instructions to find the last two of the block.
3095 InsnIterator insns[2];
3096 for (auto insn : *this)
3097 {
3098 insns[0] = insns[1];
3099 insns[1] = insn;
3100 }
3101
3102 switch (insns[1].opcode())
3103 {
3104 case spv::OpBranch:
3105 branchInstruction = insns[1];
3106 outs.emplace(Block::ID(branchInstruction.word(1)));
3107
3108 switch (insns[0].opcode())
3109 {
3110 case spv::OpLoopMerge:
3111 kind = Loop;
3112 mergeInstruction = insns[0];
3113 mergeBlock = Block::ID(mergeInstruction.word(1));
3114 continueTarget = Block::ID(mergeInstruction.word(2));
3115 break;
3116
3117 default:
3118 kind = Block::Simple;
3119 break;
3120 }
3121 break;
3122
3123 case spv::OpBranchConditional:
3124 branchInstruction = insns[1];
3125 outs.emplace(Block::ID(branchInstruction.word(2)));
3126 outs.emplace(Block::ID(branchInstruction.word(3)));
3127
3128 switch (insns[0].opcode())
3129 {
3130 case spv::OpSelectionMerge:
3131 kind = StructuredBranchConditional;
3132 mergeInstruction = insns[0];
3133 mergeBlock = Block::ID(mergeInstruction.word(1));
3134 break;
3135
3136 case spv::OpLoopMerge:
3137 kind = Loop;
3138 mergeInstruction = insns[0];
3139 mergeBlock = Block::ID(mergeInstruction.word(1));
3140 continueTarget = Block::ID(mergeInstruction.word(2));
3141 break;
3142
3143 default:
3144 kind = UnstructuredBranchConditional;
3145 break;
3146 }
3147 break;
3148
3149 case spv::OpSwitch:
3150 branchInstruction = insns[1];
3151 outs.emplace(Block::ID(branchInstruction.word(2)));
3152 for (uint32_t w = 4; w < branchInstruction.wordCount(); w += 2)
3153 {
3154 outs.emplace(Block::ID(branchInstruction.word(w)));
3155 }
3156
3157 switch (insns[0].opcode())
3158 {
3159 case spv::OpSelectionMerge:
3160 kind = StructuredSwitch;
3161 mergeInstruction = insns[0];
3162 mergeBlock = Block::ID(mergeInstruction.word(1));
3163 break;
3164
3165 default:
3166 kind = UnstructuredSwitch;
3167 break;
3168 }
3169 break;
3170
3171 default:
3172 break;
3173 }
3174 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +00003175
Ben Clayton513ed1d2019-03-28 16:07:00 +00003176 bool SpirvShader::existsPath(Block::ID from, Block::ID to, Block::ID notPassingThrough) const
Ben Claytone747b3c2019-03-21 19:35:15 +00003177 {
3178 // TODO: Optimize: This can be cached on the block.
3179 Block::Set seen;
Ben Clayton513ed1d2019-03-28 16:07:00 +00003180 seen.emplace(notPassingThrough);
Ben Claytone747b3c2019-03-21 19:35:15 +00003181
3182 std::queue<Block::ID> pending;
3183 pending.emplace(from);
3184
3185 while (pending.size() > 0)
3186 {
3187 auto id = pending.front();
3188 pending.pop();
3189 for (auto out : getBlock(id).outs)
3190 {
3191 if (seen.count(out) != 0) { continue; }
3192 if (out == to) { return true; }
3193 pending.emplace(out);
3194 }
3195 seen.emplace(id);
3196 }
3197
3198 return false;
3199 }
3200
Ben Claytonc0cf68b2019-03-21 17:46:08 +00003201 void SpirvShader::EmitState::addOutputActiveLaneMaskEdge(Block::ID to, RValue<SIMD::Int> mask)
3202 {
3203 addActiveLaneMaskEdge(currentBlock, to, mask & activeLaneMask());
3204 }
3205
3206 void SpirvShader::EmitState::addActiveLaneMaskEdge(Block::ID from, Block::ID to, RValue<SIMD::Int> mask)
3207 {
3208 auto edge = Block::Edge{from, to};
3209 auto it = edgeActiveLaneMasks.find(edge);
3210 if (it == edgeActiveLaneMasks.end())
3211 {
3212 edgeActiveLaneMasks.emplace(edge, mask);
3213 }
3214 else
3215 {
3216 auto combined = it->second | mask;
3217 edgeActiveLaneMasks.erase(edge);
3218 edgeActiveLaneMasks.emplace(edge, combined);
3219 }
3220 }
3221
Ben Claytonfe3f0132019-03-26 11:10:16 +00003222 RValue<SIMD::Int> SpirvShader::GetActiveLaneMaskEdge(EmitState *state, Block::ID from, Block::ID to) const
Ben Claytonc0cf68b2019-03-21 17:46:08 +00003223 {
3224 auto edge = Block::Edge{from, to};
Ben Claytonfe3f0132019-03-26 11:10:16 +00003225 auto it = state->edgeActiveLaneMasks.find(edge);
3226 ASSERT_MSG(it != state->edgeActiveLaneMasks.end(), "Could not find edge %d -> %d", from.value(), to.value());
Ben Claytonc0cf68b2019-03-21 17:46:08 +00003227 return it->second;
3228 }
3229
Ben Clayton76e9bc02019-02-26 15:02:18 +00003230 SpirvRoutine::SpirvRoutine(vk::PipelineLayout const *pipelineLayout) :
3231 pipelineLayout(pipelineLayout)
3232 {
3233 }
3234
Chris Forbesc25b8072018-12-10 15:10:39 -08003235}