blob: 56129bcf3120f12815133dabf6b8754925325ae2 [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#include <queue>
25
26#ifdef Bool
27#undef Bool // b/127920555
28#endif
29
Chris Forbesaf4ed532018-12-06 18:33:27 -080030namespace sw
31{
32 volatile int SpirvShader::serialCounter = 1; // Start at 1, 0 is invalid shader.
33
Chris Forbes5839dcf2018-12-10 19:02:58 -080034 SpirvShader::SpirvShader(InsnStore const &insns)
35 : insns{insns}, inputs{MAX_INTERFACE_COMPONENTS},
36 outputs{MAX_INTERFACE_COMPONENTS},
37 serialID{serialCounter++}, modes{}
Chris Forbesaf4ed532018-12-06 18:33:27 -080038 {
Ben Clayton45faa082019-03-05 13:20:40 +000039 ASSERT(insns.size() > 0);
40
Chris Forbesaf4ed532018-12-06 18:33:27 -080041 // Simplifying assumptions (to be satisfied by earlier transformations)
Chris Forbesbde34082018-12-28 12:03:10 -080042 // - There is exactly one entrypoint in the module, and it's the one we want
Chris Forbesaf4ed532018-12-06 18:33:27 -080043 // - The only input/output OpVariables present are those used by the entrypoint
44
Ben Clayton9b156612019-03-13 19:48:31 +000045 Block::ID currentBlock;
46 InsnIterator blockStart;
Chris Forbese57f10e2019-03-04 10:53:07 -080047
Chris Forbes4a979dc2019-01-17 09:36:46 -080048 for (auto insn : *this)
49 {
50 switch (insn.opcode())
51 {
52 case spv::OpExecutionMode:
53 ProcessExecutionMode(insn);
54 break;
Chris Forbesaf4ed532018-12-06 18:33:27 -080055
Chris Forbesc25b8072018-12-10 15:10:39 -080056 case spv::OpDecorate:
57 {
Ben Claytonab51bbf2019-02-20 14:36:27 +000058 TypeOrObjectID targetId = insn.word(1);
Chris Forbes93f70b32019-02-10 21:26:27 +000059 auto decoration = static_cast<spv::Decoration>(insn.word(2));
Chris Forbesc25b8072018-12-10 15:10:39 -080060 decorations[targetId].Apply(
Chris Forbes93f70b32019-02-10 21:26:27 +000061 decoration,
Chris Forbesc25b8072018-12-10 15:10:39 -080062 insn.wordCount() > 3 ? insn.word(3) : 0);
Chris Forbes93f70b32019-02-10 21:26:27 +000063
64 if (decoration == spv::DecorationCentroid)
65 modes.NeedsCentroid = true;
Chris Forbesc25b8072018-12-10 15:10:39 -080066 break;
67 }
68
69 case spv::OpMemberDecorate:
70 {
Ben Claytonaf973b62019-03-13 18:19:20 +000071 Type::ID targetId = insn.word(1);
Chris Forbesc25b8072018-12-10 15:10:39 -080072 auto memberIndex = insn.word(2);
73 auto &d = memberDecorations[targetId];
74 if (memberIndex >= d.size())
75 d.resize(memberIndex + 1); // on demand; exact size would require another pass...
Chris Forbes93f70b32019-02-10 21:26:27 +000076 auto decoration = static_cast<spv::Decoration>(insn.word(3));
Chris Forbesc25b8072018-12-10 15:10:39 -080077 d[memberIndex].Apply(
Chris Forbes93f70b32019-02-10 21:26:27 +000078 decoration,
Chris Forbesc25b8072018-12-10 15:10:39 -080079 insn.wordCount() > 4 ? insn.word(4) : 0);
Chris Forbes93f70b32019-02-10 21:26:27 +000080
81 if (decoration == spv::DecorationCentroid)
82 modes.NeedsCentroid = true;
Chris Forbesc25b8072018-12-10 15:10:39 -080083 break;
84 }
85
86 case spv::OpDecorationGroup:
87 // Nothing to do here. We don't need to record the definition of the group; we'll just have
88 // the bundle of decorations float around. If we were to ever walk the decorations directly,
89 // we might think about introducing this as a real Object.
90 break;
91
92 case spv::OpGroupDecorate:
93 {
94 auto const &srcDecorations = decorations[insn.word(1)];
95 for (auto i = 2u; i < insn.wordCount(); i++)
96 {
97 // remaining operands are targets to apply the group to.
98 decorations[insn.word(i)].Apply(srcDecorations);
99 }
100 break;
101 }
102
103 case spv::OpGroupMemberDecorate:
104 {
105 auto const &srcDecorations = decorations[insn.word(1)];
106 for (auto i = 2u; i < insn.wordCount(); i += 2)
107 {
108 // remaining operands are pairs of <id>, literal for members to apply to.
109 auto &d = memberDecorations[insn.word(i)];
110 auto memberIndex = insn.word(i + 1);
111 if (memberIndex >= d.size())
112 d.resize(memberIndex + 1); // on demand resize, see above...
113 d[memberIndex].Apply(srcDecorations);
114 }
115 break;
116 }
117
Chris Forbese57f10e2019-03-04 10:53:07 -0800118 case spv::OpLabel:
Ben Clayton9b156612019-03-13 19:48:31 +0000119 {
120 ASSERT(currentBlock.value() == 0);
121 currentBlock = Block::ID(insn.word(1));
122 blockStart = insn;
Chris Forbese57f10e2019-03-04 10:53:07 -0800123 break;
Ben Clayton9b156612019-03-13 19:48:31 +0000124 }
Chris Forbese57f10e2019-03-04 10:53:07 -0800125
Ben Clayton9b156612019-03-13 19:48:31 +0000126 // Branch Instructions (subset of Termination Instructions):
127 case spv::OpBranch:
128 case spv::OpBranchConditional:
129 case spv::OpSwitch:
Chris Forbese57f10e2019-03-04 10:53:07 -0800130 case spv::OpReturn:
Ben Clayton9b156612019-03-13 19:48:31 +0000131 // fallthrough
132
133 // Termination instruction:
134 case spv::OpKill:
135 case spv::OpUnreachable:
136 {
137 ASSERT(currentBlock.value() != 0);
138 auto blockEnd = insn; blockEnd++;
139 blocks[currentBlock] = Block(blockStart, blockEnd);
140 currentBlock = Block::ID(0);
141
142 if (insn.opcode() == spv::OpKill)
143 {
144 modes.ContainsKill = true;
145 }
Chris Forbese57f10e2019-03-04 10:53:07 -0800146 break;
Ben Clayton9b156612019-03-13 19:48:31 +0000147 }
Chris Forbese57f10e2019-03-04 10:53:07 -0800148
Chris Forbes4a979dc2019-01-17 09:36:46 -0800149 case spv::OpTypeVoid:
150 case spv::OpTypeBool:
151 case spv::OpTypeInt:
152 case spv::OpTypeFloat:
153 case spv::OpTypeVector:
154 case spv::OpTypeMatrix:
155 case spv::OpTypeImage:
156 case spv::OpTypeSampler:
157 case spv::OpTypeSampledImage:
158 case spv::OpTypeArray:
159 case spv::OpTypeRuntimeArray:
160 case spv::OpTypeStruct:
161 case spv::OpTypePointer:
162 case spv::OpTypeFunction:
Ben Clayton0bb83b82019-02-26 11:41:07 +0000163 DeclareType(insn);
Chris Forbes4a979dc2019-01-17 09:36:46 -0800164 break;
Chris Forbes296aa252018-12-27 11:48:21 -0800165
Chris Forbes4a979dc2019-01-17 09:36:46 -0800166 case spv::OpVariable:
167 {
Ben Claytonaf973b62019-03-13 18:19:20 +0000168 Type::ID typeId = insn.word(1);
169 Object::ID resultId = insn.word(2);
Chris Forbes4a979dc2019-01-17 09:36:46 -0800170 auto storageClass = static_cast<spv::StorageClass>(insn.word(3));
171 if (insn.wordCount() > 4)
172 UNIMPLEMENTED("Variable initializers not yet supported");
Chris Forbes296aa252018-12-27 11:48:21 -0800173
Chris Forbes4a979dc2019-01-17 09:36:46 -0800174 auto &object = defs[resultId];
175 object.kind = Object::Kind::Variable;
176 object.definition = insn;
Ben Clayton9a162482019-02-25 11:54:43 +0000177 object.type = typeId;
Chris Forbese9f8f5b2019-02-11 00:20:16 +0000178 object.pointerBase = insn.word(2); // base is itself
Chris Forbesc25b8072018-12-10 15:10:39 -0800179
Ben Claytonefec1b92019-03-05 17:38:16 +0000180 ASSERT(getType(typeId).storageClass == storageClass);
181
182 switch (storageClass)
Chris Forbesc25b8072018-12-10 15:10:39 -0800183 {
Ben Claytonefec1b92019-03-05 17:38:16 +0000184 case spv::StorageClassInput:
185 case spv::StorageClassOutput:
Ben Claytona1924732019-02-28 18:42:10 +0000186 ProcessInterfaceVariable(object);
Ben Claytonefec1b92019-03-05 17:38:16 +0000187 break;
188 case spv::StorageClassUniform:
189 case spv::StorageClassStorageBuffer:
Chris Forbesa30de542019-03-18 18:51:55 -0700190 case spv::StorageClassPushConstant:
Ben Claytonefec1b92019-03-05 17:38:16 +0000191 object.kind = Object::Kind::PhysicalPointer;
192 break;
193
194 case spv::StorageClassPrivate:
195 case spv::StorageClassFunction:
196 break; // Correctly handled.
197
198 case spv::StorageClassUniformConstant:
199 case spv::StorageClassWorkgroup:
200 case spv::StorageClassCrossWorkgroup:
201 case spv::StorageClassGeneric:
Ben Claytonefec1b92019-03-05 17:38:16 +0000202 case spv::StorageClassAtomicCounter:
203 case spv::StorageClassImage:
204 UNIMPLEMENTED("StorageClass %d not yet implemented", (int)storageClass);
205 break;
206
207 default:
Nicolas Capens29090852019-03-19 16:22:35 -0400208 UNREACHABLE("Unexpected StorageClass %d", storageClass); // See Appendix A of the Vulkan spec.
Ben Claytonefec1b92019-03-05 17:38:16 +0000209 break;
Chris Forbesc25b8072018-12-10 15:10:39 -0800210 }
Chris Forbes4a979dc2019-01-17 09:36:46 -0800211 break;
212 }
Chris Forbes296aa252018-12-27 11:48:21 -0800213
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800214 case spv::OpConstant:
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800215 CreateConstant(insn).constantValue[0] = insn.word(3);
216 break;
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800217 case spv::OpConstantFalse:
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800218 CreateConstant(insn).constantValue[0] = 0; // represent boolean false as zero
219 break;
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800220 case spv::OpConstantTrue:
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800221 CreateConstant(insn).constantValue[0] = ~0u; // represent boolean true as all bits set
222 break;
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800223 case spv::OpConstantNull:
Chris Forbes0e712412019-03-18 19:31:16 -0700224 case spv::OpUndef:
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800225 {
Chris Forbes0e712412019-03-18 19:31:16 -0700226 // TODO: consider a real LLVM-level undef. For now, zero is a perfectly good value.
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800227 // OpConstantNull forms a constant of arbitrary type, all zeros.
Ben Clayton9a162482019-02-25 11:54:43 +0000228 auto &object = CreateConstant(insn);
229 auto &objectTy = getType(object.type);
230 for (auto i = 0u; i < objectTy.sizeInComponents; i++)
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800231 {
232 object.constantValue[i] = 0;
233 }
234 break;
235 }
236 case spv::OpConstantComposite:
237 {
238 auto &object = CreateConstant(insn);
239 auto offset = 0u;
240 for (auto i = 0u; i < insn.wordCount() - 3; i++)
241 {
Ben Clayton9a162482019-02-25 11:54:43 +0000242 auto &constituent = getObject(insn.word(i + 3));
243 auto &constituentTy = getType(constituent.type);
244 for (auto j = 0u; j < constituentTy.sizeInComponents; j++)
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800245 object.constantValue[offset++] = constituent.constantValue[j];
246 }
Ben Clayton62758f52019-03-13 14:18:58 +0000247
248 auto objectId = Object::ID(insn.word(2));
249 auto decorationsIt = decorations.find(objectId);
250 if (decorationsIt != decorations.end() &&
251 decorationsIt->second.BuiltIn == spv::BuiltInWorkgroupSize)
252 {
253 // https://www.khronos.org/registry/vulkan/specs/1.1/html/vkspec.html#interfaces-builtin-variables :
254 // Decorating an object with the WorkgroupSize built-in
255 // decoration will make that object contain the dimensions
256 // of a local workgroup. If an object is decorated with the
257 // WorkgroupSize decoration, this must take precedence over
258 // any execution mode set for LocalSize.
259 // The object decorated with WorkgroupSize must be declared
260 // as a three-component vector of 32-bit integers.
261 ASSERT(getType(object.type).sizeInComponents == 3);
262 modes.WorkgroupSizeX = object.constantValue[0];
263 modes.WorkgroupSizeY = object.constantValue[1];
264 modes.WorkgroupSizeZ = object.constantValue[2];
265 }
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800266 break;
267 }
268
Chris Forbesbde34082018-12-28 12:03:10 -0800269 case spv::OpCapability:
Ben Clayton9b156612019-03-13 19:48:31 +0000270 break; // Various capabilities will be declared, but none affect our code generation at this point.
Chris Forbesbde34082018-12-28 12:03:10 -0800271 case spv::OpMemoryModel:
Ben Clayton9b156612019-03-13 19:48:31 +0000272 break; // Memory model does not affect our code generation until we decide to do Vulkan Memory Model support.
273
Chris Forbesbde34082018-12-28 12:03:10 -0800274 case spv::OpEntryPoint:
Ben Clayton9b156612019-03-13 19:48:31 +0000275 break;
Chris Forbes7edf5342019-02-10 22:41:21 +0000276 case spv::OpFunction:
Ben Clayton9b156612019-03-13 19:48:31 +0000277 ASSERT(mainBlockId.value() == 0); // Multiple functions found
278 // Scan forward to find the function's label.
279 for (auto it = insn; it != end() && mainBlockId.value() == 0; it++)
280 {
281 switch (it.opcode())
282 {
283 case spv::OpFunction:
284 case spv::OpFunctionParameter:
285 break;
286 case spv::OpLabel:
287 mainBlockId = Block::ID(it.word(1));
288 break;
289 default:
Ben Clayton00424c12019-03-17 17:29:30 +0000290 WARN("Unexpected opcode '%s' following OpFunction", OpcodeName(it.opcode()).c_str());
Ben Clayton9b156612019-03-13 19:48:31 +0000291 }
292 }
293 ASSERT(mainBlockId.value() != 0); // Function's OpLabel not found
294 break;
Chris Forbes7edf5342019-02-10 22:41:21 +0000295 case spv::OpFunctionEnd:
296 // Due to preprocessing, the entrypoint and its function provide no value.
297 break;
298 case spv::OpExtInstImport:
299 // We will only support the GLSL 450 extended instruction set, so no point in tracking the ID we assign it.
300 // Valid shaders will not attempt to import any other instruction sets.
Chris Forbes9667a5b2019-03-07 09:26:48 -0800301 if (0 != strcmp("GLSL.std.450", reinterpret_cast<char const *>(insn.wordPointer(2))))
302 {
303 UNIMPLEMENTED("Only GLSL extended instruction set is supported");
304 }
305 break;
Chris Forbes1776af72019-02-22 17:39:57 -0800306 case spv::OpName:
307 case spv::OpMemberName:
308 case spv::OpSource:
309 case spv::OpSourceContinued:
310 case spv::OpSourceExtension:
Chris Forbesf3a430d2019-03-08 07:51:39 -0800311 case spv::OpLine:
312 case spv::OpNoLine:
313 case spv::OpModuleProcessed:
314 case spv::OpString:
Chris Forbes1776af72019-02-22 17:39:57 -0800315 // No semantic impact
Chris Forbes7edf5342019-02-10 22:41:21 +0000316 break;
317
318 case spv::OpFunctionParameter:
319 case spv::OpFunctionCall:
320 case spv::OpSpecConstant:
321 case spv::OpSpecConstantComposite:
322 case spv::OpSpecConstantFalse:
323 case spv::OpSpecConstantOp:
324 case spv::OpSpecConstantTrue:
325 // These should have all been removed by preprocessing passes. If we see them here,
326 // our assumptions are wrong and we will probably generate wrong code.
Ben Claytonaf26cfe2019-03-21 17:32:44 +0000327 UNIMPLEMENTED("%s should have already been lowered.", OpcodeName(insn.opcode()).c_str());
Chris Forbes7edf5342019-02-10 22:41:21 +0000328 break;
329
Chris Forbes4d503052019-03-01 17:13:57 -0800330 case spv::OpFConvert:
331 case spv::OpSConvert:
332 case spv::OpUConvert:
333 UNIMPLEMENTED("No valid uses for Op*Convert until we support multiple bit widths");
334 break;
335
Chris Forbesa71b8e92019-02-10 22:42:42 +0000336 case spv::OpLoad:
337 case spv::OpAccessChain:
Chris Forbes10fd6242019-03-15 12:27:34 -0700338 case spv::OpInBoundsAccessChain:
Chris Forbesb97a9572019-02-21 16:51:42 -0800339 case spv::OpCompositeConstruct:
Chris Forbes1bc1acf2019-02-21 18:40:33 -0800340 case spv::OpCompositeInsert:
Chris Forbesb12846d2019-02-21 18:53:58 -0800341 case spv::OpCompositeExtract:
Chris Forbes83fc5442019-02-26 22:16:07 -0800342 case spv::OpVectorShuffle:
Chris Forbesfaed9d32019-03-15 10:31:08 -0700343 case spv::OpVectorTimesScalar:
344 case spv::OpVectorExtractDynamic:
345 case spv::OpVectorInsertDynamic:
Ben Claytondd1e37e2019-02-28 19:59:15 +0000346 case spv::OpNot: // Unary ops
347 case spv::OpSNegate:
348 case spv::OpFNegate:
349 case spv::OpLogicalNot:
350 case spv::OpIAdd: // Binary ops
351 case spv::OpISub:
352 case spv::OpIMul:
353 case spv::OpSDiv:
354 case spv::OpUDiv:
355 case spv::OpFAdd:
356 case spv::OpFSub:
Chris Forbes9d931532019-03-08 09:53:03 -0800357 case spv::OpFMul:
Ben Claytondd1e37e2019-02-28 19:59:15 +0000358 case spv::OpFDiv:
Chris Forbes0e4d6ff2019-03-15 13:43:36 -0700359 case spv::OpFMod:
Chris Forbes1a4c7122019-03-15 14:50:47 -0700360 case spv::OpFRem:
Ben Claytonec1aeb82019-03-04 19:33:27 +0000361 case spv::OpFOrdEqual:
362 case spv::OpFUnordEqual:
363 case spv::OpFOrdNotEqual:
364 case spv::OpFUnordNotEqual:
365 case spv::OpFOrdLessThan:
366 case spv::OpFUnordLessThan:
367 case spv::OpFOrdGreaterThan:
368 case spv::OpFUnordGreaterThan:
369 case spv::OpFOrdLessThanEqual:
370 case spv::OpFUnordLessThanEqual:
371 case spv::OpFOrdGreaterThanEqual:
372 case spv::OpFUnordGreaterThanEqual:
Ben Claytonbb8c8e22019-03-08 12:04:00 +0000373 case spv::OpSMod:
Chris Forbes71673c82019-03-14 12:55:20 -0700374 case spv::OpSRem:
Ben Claytondd1e37e2019-02-28 19:59:15 +0000375 case spv::OpUMod:
Ben Claytone95eeb12019-03-04 16:32:09 +0000376 case spv::OpIEqual:
377 case spv::OpINotEqual:
378 case spv::OpUGreaterThan:
379 case spv::OpSGreaterThan:
380 case spv::OpUGreaterThanEqual:
381 case spv::OpSGreaterThanEqual:
382 case spv::OpULessThan:
383 case spv::OpSLessThan:
384 case spv::OpULessThanEqual:
385 case spv::OpSLessThanEqual:
Ben Claytondd1e37e2019-02-28 19:59:15 +0000386 case spv::OpShiftRightLogical:
387 case spv::OpShiftRightArithmetic:
388 case spv::OpShiftLeftLogical:
389 case spv::OpBitwiseOr:
390 case spv::OpBitwiseXor:
391 case spv::OpBitwiseAnd:
392 case spv::OpLogicalOr:
393 case spv::OpLogicalAnd:
Chris Forbes787b4462019-03-08 12:16:57 -0800394 case spv::OpLogicalEqual:
395 case spv::OpLogicalNotEqual:
Chris Forbese86b6dc2019-03-01 09:08:47 -0800396 case spv::OpUMulExtended:
397 case spv::OpSMulExtended:
Chris Forbes2b287cc2019-03-01 13:24:17 -0800398 case spv::OpDot:
Chris Forbes4d503052019-03-01 17:13:57 -0800399 case spv::OpConvertFToU:
400 case spv::OpConvertFToS:
401 case spv::OpConvertSToF:
402 case spv::OpConvertUToF:
403 case spv::OpBitcast:
Ben Claytonbf943f62019-03-05 12:57:39 +0000404 case spv::OpSelect:
Chris Forbes9667a5b2019-03-07 09:26:48 -0800405 case spv::OpExtInst:
Chris Forbes3ed33ce2019-03-07 13:38:31 -0800406 case spv::OpIsInf:
407 case spv::OpIsNan:
Chris Forbes0785f692019-03-08 09:09:18 -0800408 case spv::OpAny:
409 case spv::OpAll:
Chris Forbesaff2dd02019-03-20 14:50:24 -0700410 case spv::OpDPdx:
411 case spv::OpDPdxCoarse:
412 case spv::OpDPdy:
413 case spv::OpDPdyCoarse:
414 case spv::OpFwidth:
415 case spv::OpFwidthCoarse:
416 case spv::OpDPdxFine:
417 case spv::OpDPdyFine:
418 case spv::OpFwidthFine:
Nicolas Capens5e8414e2019-03-19 16:22:35 -0400419 case spv::OpAtomicLoad:
Chris Forbese86b6dc2019-03-01 09:08:47 -0800420 // Instructions that yield an intermediate value
Chris Forbesa71b8e92019-02-10 22:42:42 +0000421 {
Ben Claytonaf973b62019-03-13 18:19:20 +0000422 Type::ID typeId = insn.word(1);
423 Object::ID resultId = insn.word(2);
Chris Forbesa71b8e92019-02-10 22:42:42 +0000424 auto &object = defs[resultId];
Ben Clayton9a162482019-02-25 11:54:43 +0000425 object.type = typeId;
Chris Forbesa71b8e92019-02-10 22:42:42 +0000426 object.kind = Object::Kind::Value;
427 object.definition = insn;
Chris Forbesa71b8e92019-02-10 22:42:42 +0000428
Chris Forbes10fd6242019-03-15 12:27:34 -0700429 if (insn.opcode() == spv::OpAccessChain || insn.opcode() == spv::OpInBoundsAccessChain)
Chris Forbesa71b8e92019-02-10 22:42:42 +0000430 {
431 // interior ptr has two parts:
432 // - logical base ptr, common across all lanes and known at compile time
433 // - per-lane offset
Ben Claytonaf973b62019-03-13 18:19:20 +0000434 Object::ID baseId = insn.word(3);
Ben Clayton9a162482019-02-25 11:54:43 +0000435 object.pointerBase = getObject(baseId).pointerBase;
Chris Forbesa71b8e92019-02-10 22:42:42 +0000436 }
437 break;
438 }
439
Chris Forbes7edf5342019-02-10 22:41:21 +0000440 case spv::OpStore:
Nicolas Capens5e8414e2019-03-19 16:22:35 -0400441 case spv::OpAtomicStore:
Chris Forbes7edf5342019-02-10 22:41:21 +0000442 // Don't need to do anything during analysis pass
443 break;
444
Chris Forbes4a979dc2019-01-17 09:36:46 -0800445 default:
Ben Clayton00424c12019-03-17 17:29:30 +0000446 UNIMPLEMENTED("%s", OpcodeName(insn.opcode()).c_str());
Chris Forbesaf4ed532018-12-06 18:33:27 -0800447 }
448 }
Ben Clayton64f78f52019-03-21 17:21:06 +0000449
450 // Assign all Block::ins
451 for (auto &it : blocks)
452 {
453 auto &blockId = it.first;
454 auto &block = it.second;
455 for (auto &outId : block.outs)
456 {
457 auto outIt = blocks.find(outId);
458 ASSERT_MSG(outIt != blocks.end(), "Block %d has a non-existent out %d", blockId.value(), outId.value());
459 auto &out = outIt->second;
460 out.ins.emplace(blockId);
461 }
462 }
Chris Forbesaf4ed532018-12-06 18:33:27 -0800463 }
464
Ben Clayton0bb83b82019-02-26 11:41:07 +0000465 void SpirvShader::DeclareType(InsnIterator insn)
466 {
Ben Claytonaf973b62019-03-13 18:19:20 +0000467 Type::ID resultId = insn.word(1);
Ben Clayton0bb83b82019-02-26 11:41:07 +0000468
469 auto &type = types[resultId];
470 type.definition = insn;
471 type.sizeInComponents = ComputeTypeSize(insn);
472
473 // A structure is a builtin block if it has a builtin
474 // member. All members of such a structure are builtins.
475 switch (insn.opcode())
476 {
477 case spv::OpTypeStruct:
478 {
479 auto d = memberDecorations.find(resultId);
480 if (d != memberDecorations.end())
481 {
482 for (auto &m : d->second)
483 {
484 if (m.HasBuiltIn)
485 {
486 type.isBuiltInBlock = true;
487 break;
488 }
489 }
490 }
491 break;
492 }
493 case spv::OpTypePointer:
494 {
Ben Claytonaf973b62019-03-13 18:19:20 +0000495 Type::ID elementTypeId = insn.word(3);
Ben Clayton0bb83b82019-02-26 11:41:07 +0000496 type.element = elementTypeId;
497 type.isBuiltInBlock = getType(elementTypeId).isBuiltInBlock;
498 type.storageClass = static_cast<spv::StorageClass>(insn.word(2));
499 break;
500 }
501 case spv::OpTypeVector:
502 case spv::OpTypeMatrix:
503 case spv::OpTypeArray:
504 case spv::OpTypeRuntimeArray:
505 {
Ben Claytonaf973b62019-03-13 18:19:20 +0000506 Type::ID elementTypeId = insn.word(2);
Ben Clayton0bb83b82019-02-26 11:41:07 +0000507 type.element = elementTypeId;
508 break;
509 }
510 default:
511 break;
512 }
513 }
514
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800515 SpirvShader::Object& SpirvShader::CreateConstant(InsnIterator insn)
516 {
Ben Claytonaf973b62019-03-13 18:19:20 +0000517 Type::ID typeId = insn.word(1);
518 Object::ID resultId = insn.word(2);
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800519 auto &object = defs[resultId];
Ben Clayton9a162482019-02-25 11:54:43 +0000520 auto &objectTy = getType(typeId);
521 object.type = typeId;
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800522 object.kind = Object::Kind::Constant;
523 object.definition = insn;
Ben Clayton9a162482019-02-25 11:54:43 +0000524 object.constantValue = std::unique_ptr<uint32_t[]>(new uint32_t[objectTy.sizeInComponents]);
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800525 return object;
526 }
527
Chris Forbes049ff382019-02-02 15:16:43 -0800528 void SpirvShader::ProcessInterfaceVariable(Object &object)
Chris Forbesbde34082018-12-28 12:03:10 -0800529 {
Ben Clayton9a162482019-02-25 11:54:43 +0000530 auto &objectTy = getType(object.type);
Ben Clayton6fae32c2019-02-28 20:06:42 +0000531 ASSERT(objectTy.storageClass == spv::StorageClassInput || objectTy.storageClass == spv::StorageClassOutput);
Chris Forbesbde34082018-12-28 12:03:10 -0800532
Nicolas Capens29090852019-03-19 16:22:35 -0400533 ASSERT(objectTy.opcode() == spv::OpTypePointer);
Ben Clayton9a162482019-02-25 11:54:43 +0000534 auto pointeeTy = getType(objectTy.element);
Chris Forbesbde34082018-12-28 12:03:10 -0800535
Ben Clayton9a162482019-02-25 11:54:43 +0000536 auto &builtinInterface = (objectTy.storageClass == spv::StorageClassInput) ? inputBuiltins : outputBuiltins;
537 auto &userDefinedInterface = (objectTy.storageClass == spv::StorageClassInput) ? inputs : outputs;
538
Nicolas Capens29090852019-03-19 16:22:35 -0400539 ASSERT(object.opcode() == spv::OpVariable);
Ben Claytonaf973b62019-03-13 18:19:20 +0000540 Object::ID resultId = object.definition.word(2);
Ben Clayton9a162482019-02-25 11:54:43 +0000541
542 if (objectTy.isBuiltInBlock)
Chris Forbesbde34082018-12-28 12:03:10 -0800543 {
544 // walk the builtin block, registering each of its members separately.
Ben Clayton9a162482019-02-25 11:54:43 +0000545 auto m = memberDecorations.find(objectTy.element);
Ben Clayton6fae32c2019-02-28 20:06:42 +0000546 ASSERT(m != memberDecorations.end()); // otherwise we wouldn't have marked the type chain
Ben Clayton9a162482019-02-25 11:54:43 +0000547 auto &structType = pointeeTy.definition;
Chris Forbesbde34082018-12-28 12:03:10 -0800548 auto offset = 0u;
549 auto word = 2u;
550 for (auto &member : m->second)
551 {
Chris Forbes840809a2019-01-14 14:30:20 -0800552 auto &memberType = getType(structType.word(word));
Chris Forbesbde34082018-12-28 12:03:10 -0800553
554 if (member.HasBuiltIn)
555 {
556 builtinInterface[member.BuiltIn] = {resultId, offset, memberType.sizeInComponents};
557 }
558
559 offset += memberType.sizeInComponents;
560 ++word;
561 }
562 return;
563 }
564
565 auto d = decorations.find(resultId);
566 if (d != decorations.end() && d->second.HasBuiltIn)
567 {
Ben Clayton9a162482019-02-25 11:54:43 +0000568 builtinInterface[d->second.BuiltIn] = {resultId, 0, pointeeTy.sizeInComponents};
Chris Forbesbde34082018-12-28 12:03:10 -0800569 }
570 else
571 {
Chris Forbes049ff382019-02-02 15:16:43 -0800572 object.kind = Object::Kind::InterfaceVariable;
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800573 VisitInterface(resultId,
574 [&userDefinedInterface](Decorations const &d, AttribType type) {
575 // Populate a single scalar slot in the interface from a collection of decorations and the intended component type.
576 auto scalarSlot = (d.Location << 2) | d.Component;
Ben Clayton6fae32c2019-02-28 20:06:42 +0000577 ASSERT(scalarSlot >= 0 &&
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800578 scalarSlot < static_cast<int32_t>(userDefinedInterface.size()));
579
580 auto &slot = userDefinedInterface[scalarSlot];
581 slot.Type = type;
582 slot.Flat = d.Flat;
583 slot.NoPerspective = d.NoPerspective;
584 slot.Centroid = d.Centroid;
585 });
Chris Forbesbde34082018-12-28 12:03:10 -0800586 }
587 }
588
Chris Forbesaf4ed532018-12-06 18:33:27 -0800589 void SpirvShader::ProcessExecutionMode(InsnIterator insn)
590 {
591 auto mode = static_cast<spv::ExecutionMode>(insn.word(2));
Chris Forbes4a979dc2019-01-17 09:36:46 -0800592 switch (mode)
593 {
594 case spv::ExecutionModeEarlyFragmentTests:
595 modes.EarlyFragmentTests = true;
596 break;
597 case spv::ExecutionModeDepthReplacing:
598 modes.DepthReplacing = true;
599 break;
600 case spv::ExecutionModeDepthGreater:
601 modes.DepthGreater = true;
602 break;
603 case spv::ExecutionModeDepthLess:
604 modes.DepthLess = true;
605 break;
606 case spv::ExecutionModeDepthUnchanged:
607 modes.DepthUnchanged = true;
608 break;
609 case spv::ExecutionModeLocalSize:
Ben Clayton62758f52019-03-13 14:18:58 +0000610 modes.WorkgroupSizeX = insn.word(3);
611 modes.WorkgroupSizeY = insn.word(4);
612 modes.WorkgroupSizeZ = insn.word(5);
Chris Forbes4a979dc2019-01-17 09:36:46 -0800613 break;
614 case spv::ExecutionModeOriginUpperLeft:
615 // This is always the case for a Vulkan shader. Do nothing.
616 break;
617 default:
618 UNIMPLEMENTED("No other execution modes are permitted");
Chris Forbesaf4ed532018-12-06 18:33:27 -0800619 }
620 }
Chris Forbes739a7fb2018-12-08 13:09:40 -0800621
Ben Clayton9b156612019-03-13 19:48:31 +0000622 uint32_t SpirvShader::ComputeTypeSize(InsnIterator insn)
Chris Forbes739a7fb2018-12-08 13:09:40 -0800623 {
624 // Types are always built from the bottom up (with the exception of forward ptrs, which
625 // don't appear in Vulkan shaders. Therefore, we can always assume our component parts have
626 // already been described (and so their sizes determined)
627 switch (insn.opcode())
628 {
629 case spv::OpTypeVoid:
630 case spv::OpTypeSampler:
631 case spv::OpTypeImage:
632 case spv::OpTypeSampledImage:
633 case spv::OpTypeFunction:
634 case spv::OpTypeRuntimeArray:
635 // Objects that don't consume any space.
636 // Descriptor-backed objects currently only need exist at compile-time.
637 // Runtime arrays don't appear in places where their size would be interesting
638 return 0;
639
640 case spv::OpTypeBool:
641 case spv::OpTypeFloat:
642 case spv::OpTypeInt:
643 // All the fundamental types are 1 component. If we ever add support for 8/16/64-bit components,
644 // we might need to change this, but only 32 bit components are required for Vulkan 1.1.
645 return 1;
646
647 case spv::OpTypeVector:
648 case spv::OpTypeMatrix:
649 // Vectors and matrices both consume element count * element size.
Chris Forbes840809a2019-01-14 14:30:20 -0800650 return getType(insn.word(2)).sizeInComponents * insn.word(3);
Chris Forbes739a7fb2018-12-08 13:09:40 -0800651
652 case spv::OpTypeArray:
Chris Forbes5be4d702018-12-27 16:12:31 -0800653 {
654 // Element count * element size. Array sizes come from constant ids.
655 auto arraySize = GetConstantInt(insn.word(3));
Chris Forbes840809a2019-01-14 14:30:20 -0800656 return getType(insn.word(2)).sizeInComponents * arraySize;
Chris Forbes5be4d702018-12-27 16:12:31 -0800657 }
Chris Forbes739a7fb2018-12-08 13:09:40 -0800658
659 case spv::OpTypeStruct:
660 {
661 uint32_t size = 0;
662 for (uint32_t i = 2u; i < insn.wordCount(); i++)
663 {
Chris Forbes840809a2019-01-14 14:30:20 -0800664 size += getType(insn.word(i)).sizeInComponents;
Chris Forbes739a7fb2018-12-08 13:09:40 -0800665 }
666 return size;
667 }
668
669 case spv::OpTypePointer:
Chris Forbes0f59a2c2019-02-10 23:03:12 +0000670 // Runtime representation of a pointer is a per-lane index.
671 // Note: clients are expected to look through the pointer if they want the pointee size instead.
672 return 1;
Chris Forbes739a7fb2018-12-08 13:09:40 -0800673
674 default:
675 // Some other random insn.
676 UNIMPLEMENTED("Only types are supported");
Ben Clayton60a3d6f2019-02-26 17:24:46 +0000677 return 0;
Chris Forbes739a7fb2018-12-08 13:09:40 -0800678 }
679 }
Chris Forbesc25b8072018-12-10 15:10:39 -0800680
Ben Clayton831db962019-02-27 14:57:18 +0000681 bool SpirvShader::IsStorageInterleavedByLane(spv::StorageClass storageClass)
682 {
683 switch (storageClass)
684 {
685 case spv::StorageClassUniform:
686 case spv::StorageClassStorageBuffer:
Chris Forbesa30de542019-03-18 18:51:55 -0700687 case spv::StorageClassPushConstant:
Ben Clayton831db962019-02-27 14:57:18 +0000688 return false;
689 default:
690 return true;
691 }
692 }
693
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800694 template<typename F>
Ben Claytonaf973b62019-03-13 18:19:20 +0000695 int SpirvShader::VisitInterfaceInner(Type::ID id, Decorations d, F f) const
Chris Forbes5839dcf2018-12-10 19:02:58 -0800696 {
697 // Recursively walks variable definition and its type tree, taking into account
698 // any explicit Location or Component decorations encountered; where explicit
699 // Locations or Components are not specified, assigns them sequentially.
700 // Collected decorations are carried down toward the leaves and across
701 // siblings; Effect of decorations intentionally does not flow back up the tree.
702 //
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800703 // F is a functor to be called with the effective decoration set for every component.
704 //
705 // Returns the next available location, and calls f().
Chris Forbes5839dcf2018-12-10 19:02:58 -0800706
707 // This covers the rules in Vulkan 1.1 spec, 14.1.4 Location Assignment.
708
Chris Forbes49d664d2019-02-12 19:24:50 +0000709 ApplyDecorationsForId(&d, id);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800710
Chris Forbes840809a2019-01-14 14:30:20 -0800711 auto const &obj = getType(id);
Nicolas Capens29090852019-03-19 16:22:35 -0400712 switch(obj.opcode())
Chris Forbes5839dcf2018-12-10 19:02:58 -0800713 {
Chris Forbes5839dcf2018-12-10 19:02:58 -0800714 case spv::OpTypePointer:
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800715 return VisitInterfaceInner<F>(obj.definition.word(3), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800716 case spv::OpTypeMatrix:
717 for (auto i = 0u; i < obj.definition.word(3); i++, d.Location++)
718 {
719 // consumes same components of N consecutive locations
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800720 VisitInterfaceInner<F>(obj.definition.word(2), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800721 }
722 return d.Location;
723 case spv::OpTypeVector:
724 for (auto i = 0u; i < obj.definition.word(3); i++, d.Component++)
725 {
726 // consumes N consecutive components in the same location
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800727 VisitInterfaceInner<F>(obj.definition.word(2), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800728 }
729 return d.Location + 1;
730 case spv::OpTypeFloat:
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800731 f(d, ATTRIBTYPE_FLOAT);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800732 return d.Location + 1;
733 case spv::OpTypeInt:
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800734 f(d, obj.definition.word(3) ? ATTRIBTYPE_INT : ATTRIBTYPE_UINT);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800735 return d.Location + 1;
736 case spv::OpTypeBool:
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800737 f(d, ATTRIBTYPE_UINT);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800738 return d.Location + 1;
739 case spv::OpTypeStruct:
740 {
Chris Forbes5839dcf2018-12-10 19:02:58 -0800741 // iterate over members, which may themselves have Location/Component decorations
742 for (auto i = 0u; i < obj.definition.wordCount() - 2; i++)
743 {
Chris Forbes49d664d2019-02-12 19:24:50 +0000744 ApplyDecorationsForIdMember(&d, id, i);
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800745 d.Location = VisitInterfaceInner<F>(obj.definition.word(i + 2), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800746 d.Component = 0; // Implicit locations always have component=0
747 }
748 return d.Location;
749 }
Chris Forbes5be4d702018-12-27 16:12:31 -0800750 case spv::OpTypeArray:
751 {
752 auto arraySize = GetConstantInt(obj.definition.word(3));
753 for (auto i = 0u; i < arraySize; i++)
754 {
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800755 d.Location = VisitInterfaceInner<F>(obj.definition.word(2), d, f);
Chris Forbes5be4d702018-12-27 16:12:31 -0800756 }
757 return d.Location;
758 }
Chris Forbes5839dcf2018-12-10 19:02:58 -0800759 default:
760 // Intentionally partial; most opcodes do not participate in type hierarchies
761 return 0;
762 }
763 }
764
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800765 template<typename F>
Ben Claytonaf973b62019-03-13 18:19:20 +0000766 void SpirvShader::VisitInterface(Object::ID id, F f) const
Chris Forbes5839dcf2018-12-10 19:02:58 -0800767 {
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800768 // Walk a variable definition and call f for each component in it.
Chris Forbes5839dcf2018-12-10 19:02:58 -0800769 Decorations d{};
Chris Forbes49d664d2019-02-12 19:24:50 +0000770 ApplyDecorationsForId(&d, id);
Chris Forbes1c658232019-02-01 17:12:25 -0800771
772 auto def = getObject(id).definition;
Ben Clayton6fae32c2019-02-28 20:06:42 +0000773 ASSERT(def.opcode() == spv::OpVariable);
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800774 VisitInterfaceInner<F>(def.word(1), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800775 }
776
Chris Forbesa30de542019-03-18 18:51:55 -0700777 SIMD::Int SpirvShader::WalkExplicitLayoutAccessChain(Object::ID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const
778 {
779 // Produce a offset into external memory in sizeof(float) units
780
781 int constantOffset = 0;
782 SIMD::Int dynamicOffset = SIMD::Int(0);
783 auto &baseObject = getObject(id);
784 Type::ID typeId = getType(baseObject.type).element;
Chris Forbesfe1dd4b2019-03-19 09:06:19 -0700785 Decorations d{};
786 ApplyDecorationsForId(&d, baseObject.type);
Chris Forbesa30de542019-03-18 18:51:55 -0700787
788 // The <base> operand is an intermediate value itself, ie produced by a previous OpAccessChain.
789 // Start with its offset and build from there.
790 if (baseObject.kind == Object::Kind::Value)
791 {
792 dynamicOffset += routine->getIntermediate(id).Int(0);
793 }
794
795 for (auto i = 0u; i < numIndexes; i++)
796 {
797 auto & type = getType(typeId);
798 switch (type.definition.opcode())
799 {
800 case spv::OpTypeStruct:
801 {
802 int memberIndex = GetConstantInt(indexIds[i]);
Chris Forbesa30de542019-03-18 18:51:55 -0700803 ApplyDecorationsForIdMember(&d, typeId, memberIndex);
804 ASSERT(d.HasOffset);
805 constantOffset += d.Offset / sizeof(float);
806 typeId = type.definition.word(2u + memberIndex);
807 break;
808 }
809 case spv::OpTypeArray:
810 case spv::OpTypeRuntimeArray:
811 {
812 // TODO: b/127950082: Check bounds.
Chris Forbesa30de542019-03-18 18:51:55 -0700813 ApplyDecorationsForId(&d, typeId);
814 ASSERT(d.HasArrayStride);
815 auto & obj = getObject(indexIds[i]);
816 if (obj.kind == Object::Kind::Constant)
817 constantOffset += d.ArrayStride/sizeof(float) * GetConstantInt(indexIds[i]);
818 else
819 dynamicOffset += SIMD::Int(d.ArrayStride / sizeof(float)) * routine->getIntermediate(indexIds[i]).Int(0);
820 typeId = type.element;
821 break;
822 }
823 case spv::OpTypeMatrix:
824 {
825 // TODO: b/127950082: Check bounds.
Chris Forbesa30de542019-03-18 18:51:55 -0700826 ApplyDecorationsForId(&d, typeId);
827 ASSERT(d.HasMatrixStride);
828 auto & obj = getObject(indexIds[i]);
829 if (obj.kind == Object::Kind::Constant)
830 constantOffset += d.MatrixStride/sizeof(float) * GetConstantInt(indexIds[i]);
831 else
832 dynamicOffset += SIMD::Int(d.MatrixStride / sizeof(float)) * routine->getIntermediate(indexIds[i]).Int(0);
833 typeId = type.element;
834 break;
835 }
836 case spv::OpTypeVector:
837 {
838 auto & obj = getObject(indexIds[i]);
839 if (obj.kind == Object::Kind::Constant)
840 constantOffset += GetConstantInt(indexIds[i]);
841 else
842 dynamicOffset += routine->getIntermediate(indexIds[i]).Int(0);
843 typeId = type.element;
844 break;
845 }
846 default:
847 UNIMPLEMENTED("Unexpected type '%s' in WalkExplicitLayoutAccessChain", OpcodeName(type.definition.opcode()).c_str());
848 }
849 }
850
851 return dynamicOffset + SIMD::Int(constantOffset);
852 }
853
Ben Claytonaf973b62019-03-13 18:19:20 +0000854 SIMD::Int SpirvShader::WalkAccessChain(Object::ID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const
Chris Forbes38f85b32019-02-12 20:10:05 +0000855 {
Chris Forbes38f85b32019-02-12 20:10:05 +0000856 // TODO: avoid doing per-lane work in some cases if we can?
Chris Forbesa30de542019-03-18 18:51:55 -0700857 // Produce a *component* offset into location-oriented memory
Chris Forbes38f85b32019-02-12 20:10:05 +0000858
Chris Forbes6397ed02019-02-15 16:39:17 -0800859 int constantOffset = 0;
Ben Clayton24ea5152019-02-26 11:02:42 +0000860 SIMD::Int dynamicOffset = SIMD::Int(0);
Ben Clayton9a162482019-02-25 11:54:43 +0000861 auto &baseObject = getObject(id);
Ben Claytonaf973b62019-03-13 18:19:20 +0000862 Type::ID typeId = getType(baseObject.type).element;
Chris Forbes38f85b32019-02-12 20:10:05 +0000863
Chris Forbese4ef5f72019-02-15 16:00:08 -0800864 // The <base> operand is an intermediate value itself, ie produced by a previous OpAccessChain.
865 // Start with its offset and build from there.
Chris Forbes38f85b32019-02-12 20:10:05 +0000866 if (baseObject.kind == Object::Kind::Value)
Ben Clayton9b62c5e2019-03-08 09:32:34 +0000867 {
868 dynamicOffset += routine->getIntermediate(id).Int(0);
869 }
Chris Forbes38f85b32019-02-12 20:10:05 +0000870
871 for (auto i = 0u; i < numIndexes; i++)
872 {
873 auto & type = getType(typeId);
Nicolas Capens29090852019-03-19 16:22:35 -0400874 switch(type.opcode())
Chris Forbes38f85b32019-02-12 20:10:05 +0000875 {
876 case spv::OpTypeStruct:
877 {
878 int memberIndex = GetConstantInt(indexIds[i]);
879 int offsetIntoStruct = 0;
880 for (auto j = 0; j < memberIndex; j++) {
Chris Forbes58bee562019-02-19 17:41:41 -0800881 auto memberType = type.definition.word(2u + j);
882 offsetIntoStruct += getType(memberType).sizeInComponents;
Chris Forbes38f85b32019-02-12 20:10:05 +0000883 }
Chris Forbes6397ed02019-02-15 16:39:17 -0800884 constantOffset += offsetIntoStruct;
Chris Forbes58bee562019-02-19 17:41:41 -0800885 typeId = type.definition.word(2u + memberIndex);
Chris Forbes38f85b32019-02-12 20:10:05 +0000886 break;
887 }
888
889 case spv::OpTypeVector:
890 case spv::OpTypeMatrix:
891 case spv::OpTypeArray:
Ben Claytonfa8603c2019-03-08 16:51:42 +0000892 case spv::OpTypeRuntimeArray:
Chris Forbes38f85b32019-02-12 20:10:05 +0000893 {
Ben Claytonfa8603c2019-03-08 16:51:42 +0000894 // TODO: b/127950082: Check bounds.
Ben Clayton9a162482019-02-25 11:54:43 +0000895 auto stride = getType(type.element).sizeInComponents;
Chris Forbes38f85b32019-02-12 20:10:05 +0000896 auto & obj = getObject(indexIds[i]);
897 if (obj.kind == Object::Kind::Constant)
Chris Forbes6397ed02019-02-15 16:39:17 -0800898 constantOffset += stride * GetConstantInt(indexIds[i]);
Chris Forbes38f85b32019-02-12 20:10:05 +0000899 else
Ben Clayton9b62c5e2019-03-08 09:32:34 +0000900 dynamicOffset += SIMD::Int(stride) * routine->getIntermediate(indexIds[i]).Int(0);
Ben Clayton9a162482019-02-25 11:54:43 +0000901 typeId = type.element;
Chris Forbes38f85b32019-02-12 20:10:05 +0000902 break;
903 }
904
905 default:
Nicolas Capens29090852019-03-19 16:22:35 -0400906 UNIMPLEMENTED("Unexpected type '%s' in WalkAccessChain", OpcodeName(type.opcode()).c_str());
Chris Forbes38f85b32019-02-12 20:10:05 +0000907 }
908 }
909
Ben Clayton24ea5152019-02-26 11:02:42 +0000910 return dynamicOffset + SIMD::Int(constantOffset);
Chris Forbes38f85b32019-02-12 20:10:05 +0000911 }
912
Ben Claytonaf973b62019-03-13 18:19:20 +0000913 uint32_t SpirvShader::WalkLiteralAccessChain(Type::ID typeId, uint32_t numIndexes, uint32_t const *indexes) const
Chris Forbes9638b942019-02-21 18:39:31 -0800914 {
915 uint32_t constantOffset = 0;
916
917 for (auto i = 0u; i < numIndexes; i++)
918 {
919 auto & type = getType(typeId);
Nicolas Capens29090852019-03-19 16:22:35 -0400920 switch(type.opcode())
Chris Forbes9638b942019-02-21 18:39:31 -0800921 {
922 case spv::OpTypeStruct:
923 {
924 int memberIndex = indexes[i];
925 int offsetIntoStruct = 0;
926 for (auto j = 0; j < memberIndex; j++) {
927 auto memberType = type.definition.word(2u + j);
928 offsetIntoStruct += getType(memberType).sizeInComponents;
929 }
930 constantOffset += offsetIntoStruct;
931 typeId = type.definition.word(2u + memberIndex);
932 break;
933 }
934
935 case spv::OpTypeVector:
936 case spv::OpTypeMatrix:
937 case spv::OpTypeArray:
938 {
939 auto elementType = type.definition.word(2);
940 auto stride = getType(elementType).sizeInComponents;
941 constantOffset += stride * indexes[i];
942 typeId = elementType;
943 break;
944 }
945
946 default:
947 UNIMPLEMENTED("Unexpected type in WalkLiteralAccessChain");
948 }
949 }
950
951 return constantOffset;
952 }
953
Chris Forbesc25b8072018-12-10 15:10:39 -0800954 void SpirvShader::Decorations::Apply(spv::Decoration decoration, uint32_t arg)
955 {
956 switch (decoration)
957 {
958 case spv::DecorationLocation:
959 HasLocation = true;
960 Location = static_cast<int32_t>(arg);
961 break;
962 case spv::DecorationComponent:
963 HasComponent = true;
964 Component = arg;
965 break;
Ben Claytond073d8e2019-02-26 11:06:50 +0000966 case spv::DecorationDescriptorSet:
967 HasDescriptorSet = true;
968 DescriptorSet = arg;
969 break;
970 case spv::DecorationBinding:
971 HasBinding = true;
972 Binding = arg;
973 break;
Chris Forbesc25b8072018-12-10 15:10:39 -0800974 case spv::DecorationBuiltIn:
975 HasBuiltIn = true;
976 BuiltIn = static_cast<spv::BuiltIn>(arg);
977 break;
978 case spv::DecorationFlat:
979 Flat = true;
980 break;
981 case spv::DecorationNoPerspective:
Chris Forbes5839dcf2018-12-10 19:02:58 -0800982 NoPerspective = true;
Chris Forbesc25b8072018-12-10 15:10:39 -0800983 break;
984 case spv::DecorationCentroid:
985 Centroid = true;
986 break;
987 case spv::DecorationBlock:
988 Block = true;
989 break;
990 case spv::DecorationBufferBlock:
991 BufferBlock = true;
992 break;
Chris Forbes65321072019-03-07 16:13:56 -0800993 case spv::DecorationOffset:
994 HasOffset = true;
995 Offset = static_cast<int32_t>(arg);
996 break;
997 case spv::DecorationArrayStride:
998 HasArrayStride = true;
999 ArrayStride = static_cast<int32_t>(arg);
1000 break;
1001 case spv::DecorationMatrixStride:
1002 HasMatrixStride = true;
1003 MatrixStride = static_cast<int32_t>(arg);
1004 break;
Chris Forbesc25b8072018-12-10 15:10:39 -08001005 default:
1006 // Intentionally partial, there are many decorations we just don't care about.
1007 break;
1008 }
1009 }
1010
1011 void SpirvShader::Decorations::Apply(const sw::SpirvShader::Decorations &src)
1012 {
1013 // Apply a decoration group to this set of decorations
1014 if (src.HasBuiltIn)
1015 {
1016 HasBuiltIn = true;
1017 BuiltIn = src.BuiltIn;
1018 }
1019
1020 if (src.HasLocation)
1021 {
1022 HasLocation = true;
1023 Location = src.Location;
1024 }
1025
1026 if (src.HasComponent)
1027 {
1028 HasComponent = true;
1029 Component = src.Component;
1030 }
1031
Ben Claytond073d8e2019-02-26 11:06:50 +00001032 if (src.HasDescriptorSet)
1033 {
1034 HasDescriptorSet = true;
1035 DescriptorSet = src.DescriptorSet;
1036 }
1037
1038 if (src.HasBinding)
1039 {
1040 HasBinding = true;
1041 Binding = src.Binding;
1042 }
1043
Chris Forbes65321072019-03-07 16:13:56 -08001044 if (src.HasOffset)
1045 {
1046 HasOffset = true;
1047 Offset = src.Offset;
1048 }
1049
1050 if (src.HasArrayStride)
1051 {
1052 HasArrayStride = true;
1053 ArrayStride = src.ArrayStride;
1054 }
1055
1056 if (src.HasMatrixStride)
1057 {
1058 HasMatrixStride = true;
1059 MatrixStride = src.MatrixStride;
1060 }
1061
Chris Forbesc25b8072018-12-10 15:10:39 -08001062 Flat |= src.Flat;
Chris Forbes5839dcf2018-12-10 19:02:58 -08001063 NoPerspective |= src.NoPerspective;
Chris Forbesc25b8072018-12-10 15:10:39 -08001064 Centroid |= src.Centroid;
1065 Block |= src.Block;
1066 BufferBlock |= src.BufferBlock;
1067 }
Chris Forbesbc3a0ee2018-12-27 16:02:58 -08001068
Ben Claytonab51bbf2019-02-20 14:36:27 +00001069 void SpirvShader::ApplyDecorationsForId(Decorations *d, TypeOrObjectID id) const
Chris Forbes49d664d2019-02-12 19:24:50 +00001070 {
1071 auto it = decorations.find(id);
1072 if (it != decorations.end())
1073 d->Apply(it->second);
1074 }
1075
Ben Claytonaf973b62019-03-13 18:19:20 +00001076 void SpirvShader::ApplyDecorationsForIdMember(Decorations *d, Type::ID id, uint32_t member) const
Chris Forbes49d664d2019-02-12 19:24:50 +00001077 {
1078 auto it = memberDecorations.find(id);
1079 if (it != memberDecorations.end() && member < it->second.size())
1080 {
1081 d->Apply(it->second[member]);
1082 }
1083 }
1084
Ben Claytonaf973b62019-03-13 18:19:20 +00001085 uint32_t SpirvShader::GetConstantInt(Object::ID id) const
Chris Forbesbc3a0ee2018-12-27 16:02:58 -08001086 {
1087 // Slightly hackish access to constants very early in translation.
1088 // General consumption of constants by other instructions should
1089 // probably be just lowered to Reactor.
1090
1091 // TODO: not encountered yet since we only use this for array sizes etc,
1092 // but is possible to construct integer constant 0 via OpConstantNull.
Chris Forbesb8fb08a2019-02-13 11:45:27 -08001093 auto insn = getObject(id).definition;
Ben Clayton6fae32c2019-02-28 20:06:42 +00001094 ASSERT(insn.opcode() == spv::OpConstant);
Nicolas Capens29090852019-03-19 16:22:35 -04001095 ASSERT(getType(insn.word(1)).opcode() == spv::OpTypeInt);
Chris Forbesbc3a0ee2018-12-27 16:02:58 -08001096 return insn.word(3);
1097 }
Chris Forbesd5aed492019-02-02 15:18:52 -08001098
1099 // emit-time
1100
Chris Forbesc61271e2019-02-19 17:01:28 -08001101 void SpirvShader::emitProlog(SpirvRoutine *routine) const
Chris Forbesd5aed492019-02-02 15:18:52 -08001102 {
1103 for (auto insn : *this)
1104 {
1105 switch (insn.opcode())
1106 {
1107 case spv::OpVariable:
1108 {
Nicolas Capens29090852019-03-19 16:22:35 -04001109 Type::ID resultPointerTypeId = insn.word(1);
1110 auto resultPointerType = getType(resultPointerTypeId);
1111 auto pointeeType = getType(resultPointerType.element);
1112
1113 if(pointeeType.sizeInComponents > 0) // TODO: what to do about zero-slot objects?
Chris Forbesd5aed492019-02-02 15:18:52 -08001114 {
Nicolas Capens29090852019-03-19 16:22:35 -04001115 Object::ID resultId = insn.word(2);
1116 routine->createLvalue(resultId, pointeeType.sizeInComponents);
Chris Forbesd5aed492019-02-02 15:18:52 -08001117 }
1118 break;
1119 }
1120 default:
Chris Forbese9f8f5b2019-02-11 00:20:16 +00001121 // Nothing else produces interface variables, so can all be safely ignored.
Chris Forbesd5aed492019-02-02 15:18:52 -08001122 break;
1123 }
1124 }
1125 }
1126
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001127 void SpirvShader::emit(SpirvRoutine *routine, RValue<SIMD::Int> const &activeLaneMask) const
Chris Forbesd5aed492019-02-02 15:18:52 -08001128 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001129 EmitState state;
1130 state.setActiveLaneMask(activeLaneMask);
1131 state.routine = routine;
1132
Ben Clayton9b156612019-03-13 19:48:31 +00001133 // Emit everything up to the first label
1134 // TODO: Separate out dispatch of block from non-block instructions?
Chris Forbesd5aed492019-02-02 15:18:52 -08001135 for (auto insn : *this)
1136 {
Ben Clayton9b156612019-03-13 19:48:31 +00001137 if (insn.opcode() == spv::OpLabel)
Chris Forbesd5aed492019-02-02 15:18:52 -08001138 {
Chris Forbesd5aed492019-02-02 15:18:52 -08001139 break;
1140 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001141 EmitInstruction(insn, &state);
Ben Clayton9b156612019-03-13 19:48:31 +00001142 }
1143
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001144 // Emit all the blocks in BFS order, starting with the main block.
1145 std::queue<Block::ID> pending;
1146 pending.push(mainBlockId);
1147 while (pending.size() > 0)
Ben Clayton9b156612019-03-13 19:48:31 +00001148 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001149 auto id = pending.front();
1150 pending.pop();
1151 if (state.visited.count(id) == 0)
1152 {
1153 EmitBlock(id, &state);
1154 for (auto it : getBlock(id).outs)
1155 {
1156 pending.push(it);
1157 }
1158 }
Ben Clayton9b156612019-03-13 19:48:31 +00001159 }
1160 }
1161
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001162 void SpirvShader::EmitBlock(Block::ID id, EmitState *state) const
1163 {
1164 if (state->visited.count(id) > 0)
1165 {
1166 return; // Already processed this block.
1167 }
1168
1169 state->visited.emplace(id);
1170
1171 auto &block = getBlock(id);
1172
1173 switch (block.kind)
1174 {
1175 case Block::Simple:
1176 if (id != mainBlockId)
1177 {
1178 // Emit all preceeding blocks and set the activeLaneMask.
1179 Intermediate activeLaneMask(1);
1180 activeLaneMask.move(0, SIMD::Int(0));
1181 for (auto in : block.ins)
1182 {
1183 EmitBlock(in, state);
1184 auto inMask = state->getActiveLaneMaskEdge(in, id);
1185 activeLaneMask.replace(0, activeLaneMask.Int(0) | inMask);
1186 }
1187 state->setActiveLaneMask(activeLaneMask.Int(0));
1188 }
1189 state->currentBlock = id;
1190 EmitInstructions(block.begin(), block.end(), state);
1191 break;
1192
1193 default:
1194 UNIMPLEMENTED("Unhandled Block Kind: %d", int(block.kind));
1195 }
1196 }
1197
1198 void SpirvShader::EmitInstructions(InsnIterator begin, InsnIterator end, EmitState *state) const
1199 {
1200 for (auto insn = begin; insn != end; insn++)
1201 {
1202 auto res = EmitInstruction(insn, state);
1203 switch (res)
1204 {
1205 case EmitResult::Continue:
1206 continue;
1207 case EmitResult::Terminator:
1208 break;
1209 default:
1210 UNREACHABLE("Unexpected EmitResult %d", int(res));
1211 break;
1212 }
1213 }
1214 }
1215
1216 SpirvShader::EmitResult SpirvShader::EmitInstruction(InsnIterator insn, EmitState *state) const
Ben Clayton9b156612019-03-13 19:48:31 +00001217 {
1218 switch (insn.opcode())
1219 {
1220 case spv::OpTypeVoid:
1221 case spv::OpTypeInt:
1222 case spv::OpTypeFloat:
1223 case spv::OpTypeBool:
1224 case spv::OpTypeVector:
1225 case spv::OpTypeArray:
1226 case spv::OpTypeRuntimeArray:
1227 case spv::OpTypeMatrix:
1228 case spv::OpTypeStruct:
1229 case spv::OpTypePointer:
1230 case spv::OpTypeFunction:
1231 case spv::OpExecutionMode:
1232 case spv::OpMemoryModel:
1233 case spv::OpFunction:
1234 case spv::OpFunctionEnd:
1235 case spv::OpConstant:
1236 case spv::OpConstantNull:
1237 case spv::OpConstantTrue:
1238 case spv::OpConstantFalse:
1239 case spv::OpConstantComposite:
Chris Forbes0e712412019-03-18 19:31:16 -07001240 case spv::OpUndef:
Ben Clayton9b156612019-03-13 19:48:31 +00001241 case spv::OpExtension:
1242 case spv::OpCapability:
1243 case spv::OpEntryPoint:
1244 case spv::OpExtInstImport:
1245 case spv::OpDecorate:
1246 case spv::OpMemberDecorate:
1247 case spv::OpGroupDecorate:
1248 case spv::OpGroupMemberDecorate:
1249 case spv::OpDecorationGroup:
1250 case spv::OpName:
1251 case spv::OpMemberName:
1252 case spv::OpSource:
1253 case spv::OpSourceContinued:
1254 case spv::OpSourceExtension:
1255 case spv::OpLine:
1256 case spv::OpNoLine:
1257 case spv::OpModuleProcessed:
1258 case spv::OpString:
1259 // Nothing to do at emit time. These are either fully handled at analysis time,
1260 // or don't require any work at all.
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001261 return EmitResult::Continue;
Ben Clayton9b156612019-03-13 19:48:31 +00001262
1263 case spv::OpLabel:
1264 case spv::OpReturn:
1265 // TODO: when we do control flow, will need to do some work here.
1266 // Until then, there is nothing to do -- we expect there to be an initial OpLabel
1267 // in the entrypoint function, for which we do nothing; and a final OpReturn at the
1268 // end of the entrypoint function, for which we do nothing.
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001269 return EmitResult::Continue;
Ben Clayton9b156612019-03-13 19:48:31 +00001270
1271 case spv::OpVariable:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001272 return EmitVariable(insn, state);
Ben Clayton9b156612019-03-13 19:48:31 +00001273
1274 case spv::OpLoad:
Nicolas Capens5e8414e2019-03-19 16:22:35 -04001275 case spv::OpAtomicLoad:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001276 return EmitLoad(insn, state);
Ben Clayton9b156612019-03-13 19:48:31 +00001277
1278 case spv::OpStore:
Nicolas Capens5e8414e2019-03-19 16:22:35 -04001279 case spv::OpAtomicStore:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001280 return EmitStore(insn, state);
Ben Clayton9b156612019-03-13 19:48:31 +00001281
1282 case spv::OpAccessChain:
Chris Forbes10fd6242019-03-15 12:27:34 -07001283 case spv::OpInBoundsAccessChain:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001284 return EmitAccessChain(insn, state);
Ben Clayton9b156612019-03-13 19:48:31 +00001285
1286 case spv::OpCompositeConstruct:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001287 return EmitCompositeConstruct(insn, state);
Ben Clayton9b156612019-03-13 19:48:31 +00001288
1289 case spv::OpCompositeInsert:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001290 return EmitCompositeInsert(insn, state);
Ben Clayton9b156612019-03-13 19:48:31 +00001291
1292 case spv::OpCompositeExtract:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001293 return EmitCompositeExtract(insn, state);
Ben Clayton9b156612019-03-13 19:48:31 +00001294
1295 case spv::OpVectorShuffle:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001296 return EmitVectorShuffle(insn, state);
Ben Clayton9b156612019-03-13 19:48:31 +00001297
Chris Forbesfaed9d32019-03-15 10:31:08 -07001298 case spv::OpVectorExtractDynamic:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001299 return EmitVectorExtractDynamic(insn, state);
Chris Forbesfaed9d32019-03-15 10:31:08 -07001300
1301 case spv::OpVectorInsertDynamic:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001302 return EmitVectorInsertDynamic(insn, state);
Chris Forbesfaed9d32019-03-15 10:31:08 -07001303
Ben Clayton9b156612019-03-13 19:48:31 +00001304 case spv::OpVectorTimesScalar:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001305 return EmitVectorTimesScalar(insn, state);
Ben Clayton9b156612019-03-13 19:48:31 +00001306
1307 case spv::OpNot:
1308 case spv::OpSNegate:
1309 case spv::OpFNegate:
1310 case spv::OpLogicalNot:
1311 case spv::OpConvertFToU:
1312 case spv::OpConvertFToS:
1313 case spv::OpConvertSToF:
1314 case spv::OpConvertUToF:
1315 case spv::OpBitcast:
1316 case spv::OpIsInf:
1317 case spv::OpIsNan:
Chris Forbesaff2dd02019-03-20 14:50:24 -07001318 case spv::OpDPdx:
1319 case spv::OpDPdxCoarse:
1320 case spv::OpDPdy:
1321 case spv::OpDPdyCoarse:
1322 case spv::OpFwidth:
1323 case spv::OpFwidthCoarse:
1324 case spv::OpDPdxFine:
1325 case spv::OpDPdyFine:
1326 case spv::OpFwidthFine:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001327 return EmitUnaryOp(insn, state);
Ben Clayton9b156612019-03-13 19:48:31 +00001328
1329 case spv::OpIAdd:
1330 case spv::OpISub:
1331 case spv::OpIMul:
1332 case spv::OpSDiv:
1333 case spv::OpUDiv:
1334 case spv::OpFAdd:
1335 case spv::OpFSub:
1336 case spv::OpFMul:
1337 case spv::OpFDiv:
Chris Forbes0e4d6ff2019-03-15 13:43:36 -07001338 case spv::OpFMod:
Chris Forbes1a4c7122019-03-15 14:50:47 -07001339 case spv::OpFRem:
Ben Clayton9b156612019-03-13 19:48:31 +00001340 case spv::OpFOrdEqual:
1341 case spv::OpFUnordEqual:
1342 case spv::OpFOrdNotEqual:
1343 case spv::OpFUnordNotEqual:
1344 case spv::OpFOrdLessThan:
1345 case spv::OpFUnordLessThan:
1346 case spv::OpFOrdGreaterThan:
1347 case spv::OpFUnordGreaterThan:
1348 case spv::OpFOrdLessThanEqual:
1349 case spv::OpFUnordLessThanEqual:
1350 case spv::OpFOrdGreaterThanEqual:
1351 case spv::OpFUnordGreaterThanEqual:
1352 case spv::OpSMod:
Chris Forbes71673c82019-03-14 12:55:20 -07001353 case spv::OpSRem:
Ben Clayton9b156612019-03-13 19:48:31 +00001354 case spv::OpUMod:
1355 case spv::OpIEqual:
1356 case spv::OpINotEqual:
1357 case spv::OpUGreaterThan:
1358 case spv::OpSGreaterThan:
1359 case spv::OpUGreaterThanEqual:
1360 case spv::OpSGreaterThanEqual:
1361 case spv::OpULessThan:
1362 case spv::OpSLessThan:
1363 case spv::OpULessThanEqual:
1364 case spv::OpSLessThanEqual:
1365 case spv::OpShiftRightLogical:
1366 case spv::OpShiftRightArithmetic:
1367 case spv::OpShiftLeftLogical:
1368 case spv::OpBitwiseOr:
1369 case spv::OpBitwiseXor:
1370 case spv::OpBitwiseAnd:
1371 case spv::OpLogicalOr:
1372 case spv::OpLogicalAnd:
1373 case spv::OpLogicalEqual:
1374 case spv::OpLogicalNotEqual:
1375 case spv::OpUMulExtended:
1376 case spv::OpSMulExtended:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001377 return EmitBinaryOp(insn, state);
Ben Clayton9b156612019-03-13 19:48:31 +00001378
1379 case spv::OpDot:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001380 return EmitDot(insn, state);
Ben Clayton9b156612019-03-13 19:48:31 +00001381
1382 case spv::OpSelect:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001383 return EmitSelect(insn, state);
Ben Clayton9b156612019-03-13 19:48:31 +00001384
1385 case spv::OpExtInst:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001386 return EmitExtendedInstruction(insn, state);
Ben Clayton9b156612019-03-13 19:48:31 +00001387
1388 case spv::OpAny:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001389 return EmitAny(insn, state);
Ben Clayton9b156612019-03-13 19:48:31 +00001390
1391 case spv::OpAll:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001392 return EmitAll(insn, state);
Ben Clayton9b156612019-03-13 19:48:31 +00001393
Ben Claytone37ce612019-03-13 19:57:42 +00001394 case spv::OpBranch:
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001395 return EmitBranch(insn, state);
Ben Claytone37ce612019-03-13 19:57:42 +00001396
Ben Clayton9b156612019-03-13 19:48:31 +00001397 default:
Ben Clayton00424c12019-03-17 17:29:30 +00001398 UNIMPLEMENTED("opcode: %s", OpcodeName(insn.opcode()).c_str());
Ben Clayton9b156612019-03-13 19:48:31 +00001399 break;
Chris Forbesd5aed492019-02-02 15:18:52 -08001400 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001401
1402 return EmitResult::Continue;
Chris Forbesd5aed492019-02-02 15:18:52 -08001403 }
Chris Forbesc61271e2019-02-19 17:01:28 -08001404
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001405 SpirvShader::EmitResult SpirvShader::EmitVariable(InsnIterator insn, EmitState *state) const
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001406 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001407 auto routine = state->routine;
Ben Claytonaf973b62019-03-13 18:19:20 +00001408 Object::ID resultId = insn.word(2);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001409 auto &object = getObject(resultId);
1410 auto &objectTy = getType(object.type);
Ben Claytonefec1b92019-03-05 17:38:16 +00001411 switch (objectTy.storageClass)
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001412 {
Ben Claytonefec1b92019-03-05 17:38:16 +00001413 case spv::StorageClassInput:
1414 {
1415 if (object.kind == Object::Kind::InterfaceVariable)
1416 {
1417 auto &dst = routine->getValue(resultId);
1418 int offset = 0;
1419 VisitInterface(resultId,
1420 [&](Decorations const &d, AttribType type) {
1421 auto scalarSlot = d.Location << 2 | d.Component;
1422 dst[offset++] = routine->inputs[scalarSlot];
1423 });
1424 }
1425 break;
1426 }
1427 case spv::StorageClassUniform:
1428 case spv::StorageClassStorageBuffer:
1429 {
1430 Decorations d{};
1431 ApplyDecorationsForId(&d, resultId);
1432 ASSERT(d.DescriptorSet >= 0);
1433 ASSERT(d.Binding >= 0);
1434
1435 size_t bindingOffset = routine->pipelineLayout->getBindingOffset(d.DescriptorSet, d.Binding);
1436
1437 Pointer<Byte> set = routine->descriptorSets[d.DescriptorSet]; // DescriptorSet*
1438 Pointer<Byte> binding = Pointer<Byte>(set + bindingOffset); // VkDescriptorBufferInfo*
1439 Pointer<Byte> buffer = *Pointer<Pointer<Byte>>(binding + OFFSET(VkDescriptorBufferInfo, buffer)); // vk::Buffer*
1440 Pointer<Byte> data = *Pointer<Pointer<Byte>>(buffer + vk::Buffer::DataOffset); // void*
1441 Int offset = *Pointer<Int>(binding + OFFSET(VkDescriptorBufferInfo, offset));
1442 Pointer<Byte> address = data + offset;
1443 routine->physicalPointers[resultId] = address;
1444 break;
1445 }
Chris Forbesa30de542019-03-18 18:51:55 -07001446 case spv::StorageClassPushConstant:
1447 {
1448 routine->physicalPointers[resultId] = routine->pushConstants;
1449 break;
1450 }
Ben Claytonefec1b92019-03-05 17:38:16 +00001451 default:
1452 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001453 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001454
1455 return EmitResult::Continue;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001456 }
1457
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001458 SpirvShader::EmitResult SpirvShader::EmitLoad(InsnIterator insn, EmitState *state) const
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001459 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001460 auto routine = state->routine;
Nicolas Capens86509d92019-03-21 13:23:50 -04001461 bool atomic = (insn.opcode() == spv::OpAtomicLoad);
Nicolas Capensfabdec52019-03-21 17:04:05 -04001462 Object::ID resultId = insn.word(2);
Ben Claytonaf973b62019-03-13 18:19:20 +00001463 Object::ID pointerId = insn.word(3);
Nicolas Capensfabdec52019-03-21 17:04:05 -04001464 auto &result = getObject(resultId);
1465 auto &resultTy = getType(result.type);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001466 auto &pointer = getObject(pointerId);
1467 auto &pointerBase = getObject(pointer.pointerBase);
1468 auto &pointerBaseTy = getType(pointerBase.type);
Nicolas Capens86509d92019-03-21 13:23:50 -04001469 std::memory_order memoryOrder = std::memory_order_relaxed;
1470
1471 if(atomic)
1472 {
1473 Object::ID semanticsId = insn.word(5);
1474 auto memorySemantics = static_cast<spv::MemorySemanticsMask>(getObject(semanticsId).constantValue[0]);
1475 memoryOrder = MemoryOrder(memorySemantics);
1476 }
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001477
Nicolas Capensfabdec52019-03-21 17:04:05 -04001478 ASSERT(getType(pointer.type).element == result.type);
1479 ASSERT(Type::ID(insn.word(1)) == result.type);
Nicolas Capens86509d92019-03-21 13:23:50 -04001480 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 +00001481
Ben Claytonefec1b92019-03-05 17:38:16 +00001482 if (pointerBaseTy.storageClass == spv::StorageClassImage)
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001483 {
Ben Claytonefec1b92019-03-05 17:38:16 +00001484 UNIMPLEMENTED("StorageClassImage load not yet implemented");
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001485 }
1486
Ben Clayton831db962019-02-27 14:57:18 +00001487 Pointer<Float> ptrBase;
1488 if (pointerBase.kind == Object::Kind::PhysicalPointer)
1489 {
1490 ptrBase = routine->getPhysicalPointer(pointer.pointerBase);
1491 }
1492 else
1493 {
1494 ptrBase = &routine->getValue(pointer.pointerBase)[0];
1495 }
1496
1497 bool interleavedByLane = IsStorageInterleavedByLane(pointerBaseTy.storageClass);
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001498 auto anyInactiveLanes = SignMask(~state->activeLaneMask()) != 0;
Ben Clayton831db962019-02-27 14:57:18 +00001499
Nicolas Capensfabdec52019-03-21 17:04:05 -04001500 auto load = std::unique_ptr<SIMD::Float[]>(new SIMD::Float[resultTy.sizeInComponents]);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001501
Ben Clayton49d81582019-03-12 20:05:04 +00001502 If(pointer.kind == Object::Kind::Value || anyInactiveLanes)
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001503 {
Ben Clayton49d81582019-03-12 20:05:04 +00001504 // Divergent offsets or masked lanes.
1505 auto offsets = pointer.kind == Object::Kind::Value ?
1506 As<SIMD::Int>(routine->getIntermediate(pointerId).Int(0)) :
1507 RValue<SIMD::Int>(SIMD::Int(0));
Nicolas Capensfabdec52019-03-21 17:04:05 -04001508 for (auto i = 0u; i < resultTy.sizeInComponents; i++)
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001509 {
1510 // i wish i had a Float,Float,Float,Float constructor here..
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001511 for (int j = 0; j < SIMD::Width; j++)
1512 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001513 If(Extract(state->activeLaneMask(), j) != 0)
Ben Clayton49d81582019-03-12 20:05:04 +00001514 {
1515 Int offset = Int(i) + Extract(offsets, j);
1516 if (interleavedByLane) { offset = offset * SIMD::Width + j; }
Nicolas Capens86509d92019-03-21 13:23:50 -04001517 load[i] = Insert(load[i], Load(&ptrBase[offset], sizeof(float), atomic, memoryOrder), j);
Ben Clayton49d81582019-03-12 20:05:04 +00001518 }
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001519 }
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001520 }
1521 }
Ben Clayton49d81582019-03-12 20:05:04 +00001522 Else
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001523 {
Ben Clayton49d81582019-03-12 20:05:04 +00001524 // No divergent offsets or masked lanes.
1525 if (interleavedByLane)
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001526 {
Ben Clayton49d81582019-03-12 20:05:04 +00001527 // Lane-interleaved data.
1528 Pointer<SIMD::Float> src = ptrBase;
Nicolas Capensfabdec52019-03-21 17:04:05 -04001529 for (auto i = 0u; i < resultTy.sizeInComponents; i++)
Ben Clayton49d81582019-03-12 20:05:04 +00001530 {
Nicolas Capens86509d92019-03-21 13:23:50 -04001531 load[i] = Load(&src[i], sizeof(float), atomic, memoryOrder); // TODO: optimize alignment
Ben Clayton49d81582019-03-12 20:05:04 +00001532 }
1533 }
1534 else
1535 {
1536 // Non-interleaved data.
Nicolas Capensfabdec52019-03-21 17:04:05 -04001537 for (auto i = 0u; i < resultTy.sizeInComponents; i++)
Ben Clayton49d81582019-03-12 20:05:04 +00001538 {
Nicolas Capens86509d92019-03-21 13:23:50 -04001539 load[i] = RValue<SIMD::Float>(Load(&ptrBase[i], sizeof(float), atomic, memoryOrder)); // TODO: optimize alignment
Ben Clayton49d81582019-03-12 20:05:04 +00001540 }
Ben Clayton831db962019-02-27 14:57:18 +00001541 }
1542 }
Ben Clayton49d81582019-03-12 20:05:04 +00001543
Nicolas Capensfabdec52019-03-21 17:04:05 -04001544 auto &dst = routine->createIntermediate(resultId, resultTy.sizeInComponents);
1545 for (auto i = 0u; i < resultTy.sizeInComponents; i++)
Ben Clayton831db962019-02-27 14:57:18 +00001546 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04001547 dst.move(i, load[i]);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001548 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001549
1550 return EmitResult::Continue;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001551 }
1552
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001553 SpirvShader::EmitResult SpirvShader::EmitStore(InsnIterator insn, EmitState *state) const
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001554 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001555 auto routine = state->routine;
Nicolas Capens5e8414e2019-03-19 16:22:35 -04001556 bool atomic = (insn.opcode() == spv::OpAtomicStore);
Ben Claytonaf973b62019-03-13 18:19:20 +00001557 Object::ID pointerId = insn.word(1);
Nicolas Capens5e8414e2019-03-19 16:22:35 -04001558 Object::ID objectId = insn.word(atomic ? 4 : 2);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001559 auto &object = getObject(objectId);
1560 auto &pointer = getObject(pointerId);
1561 auto &pointerTy = getType(pointer.type);
1562 auto &elementTy = getType(pointerTy.element);
1563 auto &pointerBase = getObject(pointer.pointerBase);
1564 auto &pointerBaseTy = getType(pointerBase.type);
Nicolas Capens86509d92019-03-21 13:23:50 -04001565 std::memory_order memoryOrder = std::memory_order_relaxed;
1566
1567 if(atomic)
1568 {
1569 Object::ID semanticsId = insn.word(3);
1570 auto memorySemantics = static_cast<spv::MemorySemanticsMask>(getObject(semanticsId).constantValue[0]);
1571 memoryOrder = MemoryOrder(memorySemantics);
1572 }
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001573
Nicolas Capens5e8414e2019-03-19 16:22:35 -04001574 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."
1575
Ben Claytonefec1b92019-03-05 17:38:16 +00001576 if (pointerBaseTy.storageClass == spv::StorageClassImage)
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001577 {
Ben Claytonefec1b92019-03-05 17:38:16 +00001578 UNIMPLEMENTED("StorageClassImage store not yet implemented");
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001579 }
1580
Ben Clayton831db962019-02-27 14:57:18 +00001581 Pointer<Float> ptrBase;
1582 if (pointerBase.kind == Object::Kind::PhysicalPointer)
1583 {
1584 ptrBase = routine->getPhysicalPointer(pointer.pointerBase);
1585 }
1586 else
1587 {
1588 ptrBase = &routine->getValue(pointer.pointerBase)[0];
1589 }
1590
1591 bool interleavedByLane = IsStorageInterleavedByLane(pointerBaseTy.storageClass);
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001592 auto anyInactiveLanes = SignMask(~state->activeLaneMask()) != 0;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001593
1594 if (object.kind == Object::Kind::Constant)
1595 {
Ben Clayton49d81582019-03-12 20:05:04 +00001596 // Constant source data.
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001597 auto src = reinterpret_cast<float *>(object.constantValue.get());
Ben Clayton49d81582019-03-12 20:05:04 +00001598 If(pointer.kind == Object::Kind::Value || anyInactiveLanes)
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001599 {
Ben Clayton49d81582019-03-12 20:05:04 +00001600 // Divergent offsets or masked lanes.
1601 auto offsets = pointer.kind == Object::Kind::Value ?
1602 As<SIMD::Int>(routine->getIntermediate(pointerId).Int(0)) :
1603 RValue<SIMD::Int>(SIMD::Int(0));
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001604 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1605 {
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001606 for (int j = 0; j < SIMD::Width; j++)
1607 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001608 If(Extract(state->activeLaneMask(), j) != 0)
Ben Clayton49d81582019-03-12 20:05:04 +00001609 {
1610 Int offset = Int(i) + Extract(offsets, j);
1611 if (interleavedByLane) { offset = offset * SIMD::Width + j; }
Nicolas Capens86509d92019-03-21 13:23:50 -04001612 Store(RValue<Float>(src[i]), &ptrBase[offset], sizeof(float), atomic, memoryOrder);
Ben Clayton49d81582019-03-12 20:05:04 +00001613 }
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001614 }
1615 }
1616 }
Ben Clayton49d81582019-03-12 20:05:04 +00001617 Else
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001618 {
Ben Clayton49d81582019-03-12 20:05:04 +00001619 // Constant source data.
1620 // No divergent offsets or masked lanes.
Ben Clayton831db962019-02-27 14:57:18 +00001621 Pointer<SIMD::Float> dst = ptrBase;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001622 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1623 {
Nicolas Capens86509d92019-03-21 13:23:50 -04001624 Store(RValue<SIMD::Float>(src[i]), &dst[i], sizeof(float), atomic, memoryOrder); // TODO: optimize alignment
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001625 }
1626 }
1627 }
1628 else
1629 {
Ben Clayton49d81582019-03-12 20:05:04 +00001630 // Intermediate source data.
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001631 auto &src = routine->getIntermediate(objectId);
Ben Clayton49d81582019-03-12 20:05:04 +00001632 If(pointer.kind == Object::Kind::Value || anyInactiveLanes)
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001633 {
Ben Clayton49d81582019-03-12 20:05:04 +00001634 // Divergent offsets or masked lanes.
1635 auto offsets = pointer.kind == Object::Kind::Value ?
1636 As<SIMD::Int>(routine->getIntermediate(pointerId).Int(0)) :
1637 RValue<SIMD::Int>(SIMD::Int(0));
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001638 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1639 {
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001640 for (int j = 0; j < SIMD::Width; j++)
1641 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001642 If(Extract(state->activeLaneMask(), j) != 0)
Ben Clayton49d81582019-03-12 20:05:04 +00001643 {
1644 Int offset = Int(i) + Extract(offsets, j);
1645 if (interleavedByLane) { offset = offset * SIMD::Width + j; }
Nicolas Capens86509d92019-03-21 13:23:50 -04001646 Store(Extract(src.Float(i), j), &ptrBase[offset], sizeof(float), atomic, memoryOrder);
Ben Clayton49d81582019-03-12 20:05:04 +00001647 }
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001648 }
1649 }
1650 }
Ben Clayton49d81582019-03-12 20:05:04 +00001651 Else
Ben Clayton831db962019-02-27 14:57:18 +00001652 {
Ben Clayton49d81582019-03-12 20:05:04 +00001653 // No divergent offsets or masked lanes.
1654 if (interleavedByLane)
Ben Clayton831db962019-02-27 14:57:18 +00001655 {
Ben Clayton49d81582019-03-12 20:05:04 +00001656 // Lane-interleaved data.
1657 Pointer<SIMD::Float> dst = ptrBase;
1658 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1659 {
Nicolas Capens86509d92019-03-21 13:23:50 -04001660 Store(src.Float(i), &dst[i], sizeof(float), atomic, memoryOrder); // TODO: optimize alignment
Ben Clayton49d81582019-03-12 20:05:04 +00001661 }
Ben Clayton831db962019-02-27 14:57:18 +00001662 }
Ben Clayton49d81582019-03-12 20:05:04 +00001663 else
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001664 {
Ben Clayton49d81582019-03-12 20:05:04 +00001665 // Intermediate source data. Non-interleaved data.
1666 Pointer<SIMD::Float> dst = ptrBase;
1667 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1668 {
Nicolas Capens86509d92019-03-21 13:23:50 -04001669 Store<SIMD::Float>(SIMD::Float(src.Float(i)), &dst[i], sizeof(float), atomic, memoryOrder); // TODO: optimize alignment
Ben Clayton49d81582019-03-12 20:05:04 +00001670 }
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001671 }
1672 }
1673 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001674
1675 return EmitResult::Continue;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001676 }
1677
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001678 SpirvShader::EmitResult SpirvShader::EmitAccessChain(InsnIterator insn, EmitState *state) const
Nicolas Capensfabdec52019-03-21 17:04:05 -04001679 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001680 auto routine = state->routine;
Nicolas Capensfabdec52019-03-21 17:04:05 -04001681 Type::ID typeId = insn.word(1);
1682 Object::ID resultId = insn.word(2);
1683 Object::ID baseId = insn.word(3);
1684 uint32_t numIndexes = insn.wordCount() - 4;
1685 const uint32_t *indexes = insn.wordPointer(4);
1686 auto &type = getType(typeId);
1687 ASSERT(type.sizeInComponents == 1);
1688 ASSERT(getObject(baseId).pointerBase == getObject(resultId).pointerBase);
1689
1690 auto &dst = routine->createIntermediate(resultId, type.sizeInComponents);
1691
1692 if(type.storageClass == spv::StorageClassPushConstant ||
1693 type.storageClass == spv::StorageClassUniform ||
1694 type.storageClass == spv::StorageClassStorageBuffer)
1695 {
1696 dst.move(0, WalkExplicitLayoutAccessChain(baseId, numIndexes, indexes, routine));
1697 }
1698 else
1699 {
1700 dst.move(0, WalkAccessChain(baseId, numIndexes, indexes, routine));
1701 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001702
1703 return EmitResult::Continue;
Nicolas Capensfabdec52019-03-21 17:04:05 -04001704 }
1705
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001706 SpirvShader::EmitResult SpirvShader::EmitCompositeConstruct(InsnIterator insn, EmitState *state) const
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001707 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001708 auto routine = state->routine;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001709 auto &type = getType(insn.word(1));
1710 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1711 auto offset = 0u;
1712
1713 for (auto i = 0u; i < insn.wordCount() - 3; i++)
1714 {
Ben Claytonaf973b62019-03-13 18:19:20 +00001715 Object::ID srcObjectId = insn.word(3u + i);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001716 auto & srcObject = getObject(srcObjectId);
1717 auto & srcObjectTy = getType(srcObject.type);
1718 GenericValue srcObjectAccess(this, routine, srcObjectId);
1719
1720 for (auto j = 0u; j < srcObjectTy.sizeInComponents; j++)
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001721 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04001722 dst.move(offset++, srcObjectAccess.Float(j));
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001723 }
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001724 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001725
1726 return EmitResult::Continue;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001727 }
1728
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001729 SpirvShader::EmitResult SpirvShader::EmitCompositeInsert(InsnIterator insn, EmitState *state) const
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001730 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001731 auto routine = state->routine;
Ben Claytonaf973b62019-03-13 18:19:20 +00001732 Type::ID resultTypeId = insn.word(1);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001733 auto &type = getType(resultTypeId);
1734 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1735 auto &newPartObject = getObject(insn.word(3));
1736 auto &newPartObjectTy = getType(newPartObject.type);
1737 auto firstNewComponent = WalkLiteralAccessChain(resultTypeId, insn.wordCount() - 5, insn.wordPointer(5));
1738
1739 GenericValue srcObjectAccess(this, routine, insn.word(4));
1740 GenericValue newPartObjectAccess(this, routine, insn.word(3));
1741
1742 // old components before
1743 for (auto i = 0u; i < firstNewComponent; i++)
1744 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04001745 dst.move(i, srcObjectAccess.Float(i));
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001746 }
1747 // new part
1748 for (auto i = 0u; i < newPartObjectTy.sizeInComponents; i++)
1749 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04001750 dst.move(firstNewComponent + i, newPartObjectAccess.Float(i));
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001751 }
1752 // old components after
1753 for (auto i = firstNewComponent + newPartObjectTy.sizeInComponents; i < type.sizeInComponents; i++)
1754 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04001755 dst.move(i, srcObjectAccess.Float(i));
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001756 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001757
1758 return EmitResult::Continue;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001759 }
1760
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001761 SpirvShader::EmitResult SpirvShader::EmitCompositeExtract(InsnIterator insn, EmitState *state) const
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001762 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001763 auto routine = state->routine;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001764 auto &type = getType(insn.word(1));
1765 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1766 auto &compositeObject = getObject(insn.word(3));
Ben Claytonaf973b62019-03-13 18:19:20 +00001767 Type::ID compositeTypeId = compositeObject.definition.word(1);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001768 auto firstComponent = WalkLiteralAccessChain(compositeTypeId, insn.wordCount() - 4, insn.wordPointer(4));
1769
1770 GenericValue compositeObjectAccess(this, routine, insn.word(3));
1771 for (auto i = 0u; i < type.sizeInComponents; i++)
1772 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04001773 dst.move(i, compositeObjectAccess.Float(firstComponent + i));
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001774 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001775
1776 return EmitResult::Continue;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001777 }
1778
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001779 SpirvShader::EmitResult SpirvShader::EmitVectorShuffle(InsnIterator insn, EmitState *state) const
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001780 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001781 auto routine = state->routine;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001782 auto &type = getType(insn.word(1));
1783 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1784
Chris Forbes13eba6c2019-03-08 10:41:05 -08001785 // Note: number of components in result type, first half type, and second
1786 // half type are all independent.
1787 auto &firstHalfType = getType(getObject(insn.word(3)).type);
1788
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001789 GenericValue firstHalfAccess(this, routine, insn.word(3));
1790 GenericValue secondHalfAccess(this, routine, insn.word(4));
1791
1792 for (auto i = 0u; i < type.sizeInComponents; i++)
1793 {
1794 auto selector = insn.word(5 + i);
1795 if (selector == static_cast<uint32_t>(-1))
1796 {
1797 // Undefined value. Until we decide to do real undef values, zero is as good
1798 // a value as any
Nicolas Capens80c796b2019-03-19 21:38:44 -04001799 dst.move(i, RValue<SIMD::Float>(0.0f));
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001800 }
Chris Forbes13eba6c2019-03-08 10:41:05 -08001801 else if (selector < firstHalfType.sizeInComponents)
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001802 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04001803 dst.move(i, firstHalfAccess.Float(selector));
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001804 }
1805 else
1806 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04001807 dst.move(i, secondHalfAccess.Float(selector - firstHalfType.sizeInComponents));
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001808 }
1809 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001810
1811 return EmitResult::Continue;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001812 }
1813
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001814 SpirvShader::EmitResult SpirvShader::EmitVectorExtractDynamic(InsnIterator insn, EmitState *state) const
Chris Forbesfaed9d32019-03-15 10:31:08 -07001815 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001816 auto routine = state->routine;
Chris Forbesfaed9d32019-03-15 10:31:08 -07001817 auto &type = getType(insn.word(1));
1818 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1819 auto &srcType = getType(getObject(insn.word(3)).type);
1820
1821 GenericValue src(this, routine, insn.word(3));
1822 GenericValue index(this, routine, insn.word(4));
1823
1824 SIMD::UInt v = SIMD::UInt(0);
1825
1826 for (auto i = 0u; i < srcType.sizeInComponents; i++)
1827 {
1828 v |= CmpEQ(index.UInt(0), SIMD::UInt(i)) & src.UInt(i);
1829 }
1830
Nicolas Capens80c796b2019-03-19 21:38:44 -04001831 dst.move(0, v);
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001832 return EmitResult::Continue;
Chris Forbesfaed9d32019-03-15 10:31:08 -07001833 }
1834
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001835 SpirvShader::EmitResult SpirvShader::EmitVectorInsertDynamic(InsnIterator insn, EmitState *state) const
Chris Forbesfaed9d32019-03-15 10:31:08 -07001836 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001837 auto routine = state->routine;
Chris Forbesfaed9d32019-03-15 10:31:08 -07001838 auto &type = getType(insn.word(1));
1839 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1840
1841 GenericValue src(this, routine, insn.word(3));
1842 GenericValue component(this, routine, insn.word(4));
1843 GenericValue index(this, routine, insn.word(5));
1844
1845 for (auto i = 0u; i < type.sizeInComponents; i++)
1846 {
1847 SIMD::UInt mask = CmpEQ(SIMD::UInt(i), index.UInt(0));
Nicolas Capens80c796b2019-03-19 21:38:44 -04001848 dst.move(i, (src.UInt(i) & ~mask) | (component.UInt(0) & mask));
Chris Forbesfaed9d32019-03-15 10:31:08 -07001849 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001850 return EmitResult::Continue;
Chris Forbesfaed9d32019-03-15 10:31:08 -07001851 }
1852
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001853 SpirvShader::EmitResult SpirvShader::EmitVectorTimesScalar(InsnIterator insn, EmitState *state) const
Chris Forbes856ebf82019-03-08 15:30:18 -08001854 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001855 auto routine = state->routine;
Chris Forbes856ebf82019-03-08 15:30:18 -08001856 auto &type = getType(insn.word(1));
1857 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001858 auto lhs = GenericValue(this, routine, insn.word(3));
1859 auto rhs = GenericValue(this, routine, insn.word(4));
Chris Forbes856ebf82019-03-08 15:30:18 -08001860
1861 for (auto i = 0u; i < type.sizeInComponents; i++)
1862 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04001863 dst.move(i, lhs.Float(i) * rhs.Float(0));
Chris Forbes856ebf82019-03-08 15:30:18 -08001864 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001865
1866 return EmitResult::Continue;
Chris Forbes856ebf82019-03-08 15:30:18 -08001867 }
1868
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001869 SpirvShader::EmitResult SpirvShader::EmitUnaryOp(InsnIterator insn, EmitState *state) const
Ben Claytondd1e37e2019-02-28 19:59:15 +00001870 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001871 auto routine = state->routine;
Ben Claytondd1e37e2019-02-28 19:59:15 +00001872 auto &type = getType(insn.word(1));
1873 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1874 auto src = GenericValue(this, routine, insn.word(3));
1875
1876 for (auto i = 0u; i < type.sizeInComponents; i++)
1877 {
Ben Claytondd1e37e2019-02-28 19:59:15 +00001878 switch (insn.opcode())
1879 {
1880 case spv::OpNot:
1881 case spv::OpLogicalNot: // logical not == bitwise not due to all-bits boolean representation
Nicolas Capens80c796b2019-03-19 21:38:44 -04001882 dst.move(i, ~src.UInt(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00001883 break;
1884 case spv::OpSNegate:
Nicolas Capens80c796b2019-03-19 21:38:44 -04001885 dst.move(i, -src.Int(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00001886 break;
1887 case spv::OpFNegate:
Nicolas Capens80c796b2019-03-19 21:38:44 -04001888 dst.move(i, -src.Float(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00001889 break;
Chris Forbes4d503052019-03-01 17:13:57 -08001890 case spv::OpConvertFToU:
Nicolas Capens80c796b2019-03-19 21:38:44 -04001891 dst.move(i, SIMD::UInt(src.Float(i)));
Chris Forbes4d503052019-03-01 17:13:57 -08001892 break;
1893 case spv::OpConvertFToS:
Nicolas Capens80c796b2019-03-19 21:38:44 -04001894 dst.move(i, SIMD::Int(src.Float(i)));
Chris Forbes4d503052019-03-01 17:13:57 -08001895 break;
1896 case spv::OpConvertSToF:
Nicolas Capens80c796b2019-03-19 21:38:44 -04001897 dst.move(i, SIMD::Float(src.Int(i)));
Chris Forbes4d503052019-03-01 17:13:57 -08001898 break;
1899 case spv::OpConvertUToF:
Nicolas Capens80c796b2019-03-19 21:38:44 -04001900 dst.move(i, SIMD::Float(src.UInt(i)));
Chris Forbes4d503052019-03-01 17:13:57 -08001901 break;
1902 case spv::OpBitcast:
Nicolas Capens80c796b2019-03-19 21:38:44 -04001903 dst.move(i, src.Float(i));
Chris Forbes4d503052019-03-01 17:13:57 -08001904 break;
Chris Forbes3ed33ce2019-03-07 13:38:31 -08001905 case spv::OpIsInf:
Nicolas Capens80c796b2019-03-19 21:38:44 -04001906 dst.move(i, IsInf(src.Float(i)));
Chris Forbes3ed33ce2019-03-07 13:38:31 -08001907 break;
1908 case spv::OpIsNan:
Nicolas Capens80c796b2019-03-19 21:38:44 -04001909 dst.move(i, IsNan(src.Float(i)));
Chris Forbes3ed33ce2019-03-07 13:38:31 -08001910 break;
Chris Forbesaff2dd02019-03-20 14:50:24 -07001911 case spv::OpDPdx:
1912 case spv::OpDPdxCoarse:
1913 // Derivative instructions: FS invocations are laid out like so:
1914 // 0 1
1915 // 2 3
1916 static_assert(SIMD::Width == 4, "All cross-lane instructions will need care when using a different width");
Nicolas Capens80c796b2019-03-19 21:38:44 -04001917 dst.move(i, SIMD::Float(Extract(src.Float(i), 1) - Extract(src.Float(i), 0)));
Chris Forbesaff2dd02019-03-20 14:50:24 -07001918 break;
1919 case spv::OpDPdy:
1920 case spv::OpDPdyCoarse:
Nicolas Capens80c796b2019-03-19 21:38:44 -04001921 dst.move(i, SIMD::Float(Extract(src.Float(i), 2) - Extract(src.Float(i), 0)));
Chris Forbesaff2dd02019-03-20 14:50:24 -07001922 break;
1923 case spv::OpFwidth:
1924 case spv::OpFwidthCoarse:
Nicolas Capens80c796b2019-03-19 21:38:44 -04001925 dst.move(i, SIMD::Float(Abs(Extract(src.Float(i), 1) - Extract(src.Float(i), 0))
Chris Forbesaff2dd02019-03-20 14:50:24 -07001926 + Abs(Extract(src.Float(i), 2) - Extract(src.Float(i), 0))));
1927 break;
1928 case spv::OpDPdxFine:
1929 {
1930 auto firstRow = Extract(src.Float(i), 1) - Extract(src.Float(i), 0);
1931 auto secondRow = Extract(src.Float(i), 3) - Extract(src.Float(i), 2);
1932 SIMD::Float v = SIMD::Float(firstRow);
1933 v = Insert(v, secondRow, 2);
1934 v = Insert(v, secondRow, 3);
Nicolas Capens80c796b2019-03-19 21:38:44 -04001935 dst.move(i, v);
Chris Forbesaff2dd02019-03-20 14:50:24 -07001936 break;
1937 }
1938 case spv::OpDPdyFine:
1939 {
1940 auto firstColumn = Extract(src.Float(i), 2) - Extract(src.Float(i), 0);
1941 auto secondColumn = Extract(src.Float(i), 3) - Extract(src.Float(i), 1);
1942 SIMD::Float v = SIMD::Float(firstColumn);
1943 v = Insert(v, secondColumn, 1);
1944 v = Insert(v, secondColumn, 3);
Nicolas Capens80c796b2019-03-19 21:38:44 -04001945 dst.move(i, v);
Chris Forbesaff2dd02019-03-20 14:50:24 -07001946 break;
1947 }
1948 case spv::OpFwidthFine:
1949 {
1950 auto firstRow = Extract(src.Float(i), 1) - Extract(src.Float(i), 0);
1951 auto secondRow = Extract(src.Float(i), 3) - Extract(src.Float(i), 2);
1952 SIMD::Float dpdx = SIMD::Float(firstRow);
1953 dpdx = Insert(dpdx, secondRow, 2);
1954 dpdx = Insert(dpdx, secondRow, 3);
1955 auto firstColumn = Extract(src.Float(i), 2) - Extract(src.Float(i), 0);
1956 auto secondColumn = Extract(src.Float(i), 3) - Extract(src.Float(i), 1);
1957 SIMD::Float dpdy = SIMD::Float(firstColumn);
1958 dpdy = Insert(dpdy, secondColumn, 1);
1959 dpdy = Insert(dpdy, secondColumn, 3);
Nicolas Capens80c796b2019-03-19 21:38:44 -04001960 dst.move(i, Abs(dpdx) + Abs(dpdy));
Chris Forbesaff2dd02019-03-20 14:50:24 -07001961 break;
1962 }
Ben Claytondd1e37e2019-02-28 19:59:15 +00001963 default:
1964 UNIMPLEMENTED("Unhandled unary operator %s", OpcodeName(insn.opcode()).c_str());
1965 }
1966 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001967
1968 return EmitResult::Continue;
Ben Claytondd1e37e2019-02-28 19:59:15 +00001969 }
1970
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001971 SpirvShader::EmitResult SpirvShader::EmitBinaryOp(InsnIterator insn, EmitState *state) const
Ben Claytondd1e37e2019-02-28 19:59:15 +00001972 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001973 auto routine = state->routine;
Ben Claytondd1e37e2019-02-28 19:59:15 +00001974 auto &type = getType(insn.word(1));
1975 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
Chris Forbese86b6dc2019-03-01 09:08:47 -08001976 auto &lhsType = getType(getObject(insn.word(3)).type);
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001977 auto lhs = GenericValue(this, routine, insn.word(3));
1978 auto rhs = GenericValue(this, routine, insn.word(4));
Ben Claytondd1e37e2019-02-28 19:59:15 +00001979
Chris Forbese86b6dc2019-03-01 09:08:47 -08001980 for (auto i = 0u; i < lhsType.sizeInComponents; i++)
Ben Claytondd1e37e2019-02-28 19:59:15 +00001981 {
Ben Claytondd1e37e2019-02-28 19:59:15 +00001982 switch (insn.opcode())
1983 {
1984 case spv::OpIAdd:
Nicolas Capens80c796b2019-03-19 21:38:44 -04001985 dst.move(i, lhs.Int(i) + rhs.Int(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00001986 break;
1987 case spv::OpISub:
Nicolas Capens80c796b2019-03-19 21:38:44 -04001988 dst.move(i, lhs.Int(i) - rhs.Int(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00001989 break;
1990 case spv::OpIMul:
Nicolas Capens80c796b2019-03-19 21:38:44 -04001991 dst.move(i, lhs.Int(i) * rhs.Int(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00001992 break;
1993 case spv::OpSDiv:
Ben Clayton49d2c132019-03-14 12:21:53 +00001994 {
Ben Claytona2749f32019-03-14 19:32:41 +00001995 SIMD::Int a = lhs.Int(i);
1996 SIMD::Int b = rhs.Int(i);
1997 b = b | CmpEQ(b, SIMD::Int(0)); // prevent divide-by-zero
1998 a = a | (CmpEQ(a, SIMD::Int(0x80000000)) & CmpEQ(b, SIMD::Int(-1))); // prevent integer overflow
Nicolas Capens80c796b2019-03-19 21:38:44 -04001999 dst.move(i, a / b);
Ben Claytondd1e37e2019-02-28 19:59:15 +00002000 break;
Ben Clayton49d2c132019-03-14 12:21:53 +00002001 }
Ben Claytondd1e37e2019-02-28 19:59:15 +00002002 case spv::OpUDiv:
Ben Clayton49d2c132019-03-14 12:21:53 +00002003 {
2004 auto zeroMask = As<SIMD::UInt>(CmpEQ(rhs.Int(i), SIMD::Int(0)));
Nicolas Capens80c796b2019-03-19 21:38:44 -04002005 dst.move(i, lhs.UInt(i) / (rhs.UInt(i) | zeroMask));
Ben Claytondd1e37e2019-02-28 19:59:15 +00002006 break;
Ben Clayton49d2c132019-03-14 12:21:53 +00002007 }
Chris Forbes71673c82019-03-14 12:55:20 -07002008 case spv::OpSRem:
2009 {
2010 SIMD::Int a = lhs.Int(i);
2011 SIMD::Int b = rhs.Int(i);
2012 b = b | CmpEQ(b, SIMD::Int(0)); // prevent divide-by-zero
2013 a = a | (CmpEQ(a, SIMD::Int(0x80000000)) & CmpEQ(b, SIMD::Int(-1))); // prevent integer overflow
Nicolas Capens80c796b2019-03-19 21:38:44 -04002014 dst.move(i, a % b);
Chris Forbes71673c82019-03-14 12:55:20 -07002015 break;
2016 }
Ben Claytonbb8c8e22019-03-08 12:04:00 +00002017 case spv::OpSMod:
2018 {
Ben Claytona2749f32019-03-14 19:32:41 +00002019 SIMD::Int a = lhs.Int(i);
2020 SIMD::Int b = rhs.Int(i);
2021 b = b | CmpEQ(b, SIMD::Int(0)); // prevent divide-by-zero
2022 a = a | (CmpEQ(a, SIMD::Int(0x80000000)) & CmpEQ(b, SIMD::Int(-1))); // prevent integer overflow
2023 auto mod = a % b;
Ben Claytonbb8c8e22019-03-08 12:04:00 +00002024 // If a and b have opposite signs, the remainder operation takes
2025 // the sign from a but OpSMod is supposed to take the sign of b.
2026 // Adding b will ensure that the result has the correct sign and
2027 // that it is still congruent to a modulo b.
2028 //
2029 // See also http://mathforum.org/library/drmath/view/52343.html
2030 auto signDiff = CmpNEQ(CmpGE(a, SIMD::Int(0)), CmpGE(b, SIMD::Int(0)));
2031 auto fixedMod = mod + (b & CmpNEQ(mod, SIMD::Int(0)) & signDiff);
Nicolas Capens80c796b2019-03-19 21:38:44 -04002032 dst.move(i, As<SIMD::Float>(fixedMod));
Ben Claytonbb8c8e22019-03-08 12:04:00 +00002033 break;
2034 }
Ben Claytondd1e37e2019-02-28 19:59:15 +00002035 case spv::OpUMod:
Chris Forbes3ebf5832019-03-14 08:15:25 -07002036 {
2037 auto zeroMask = As<SIMD::UInt>(CmpEQ(rhs.Int(i), SIMD::Int(0)));
Nicolas Capens80c796b2019-03-19 21:38:44 -04002038 dst.move(i, lhs.UInt(i) % (rhs.UInt(i) | zeroMask));
Ben Claytondd1e37e2019-02-28 19:59:15 +00002039 break;
Chris Forbes3ebf5832019-03-14 08:15:25 -07002040 }
Ben Claytone95eeb12019-03-04 16:32:09 +00002041 case spv::OpIEqual:
Chris Forbes787b4462019-03-08 12:16:57 -08002042 case spv::OpLogicalEqual:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002043 dst.move(i, CmpEQ(lhs.Int(i), rhs.Int(i)));
Ben Claytone95eeb12019-03-04 16:32:09 +00002044 break;
2045 case spv::OpINotEqual:
Chris Forbes787b4462019-03-08 12:16:57 -08002046 case spv::OpLogicalNotEqual:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002047 dst.move(i, CmpNEQ(lhs.Int(i), rhs.Int(i)));
Ben Claytone95eeb12019-03-04 16:32:09 +00002048 break;
2049 case spv::OpUGreaterThan:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002050 dst.move(i, CmpGT(lhs.UInt(i), rhs.UInt(i)));
Ben Claytone95eeb12019-03-04 16:32:09 +00002051 break;
2052 case spv::OpSGreaterThan:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002053 dst.move(i, CmpGT(lhs.Int(i), rhs.Int(i)));
Ben Claytone95eeb12019-03-04 16:32:09 +00002054 break;
2055 case spv::OpUGreaterThanEqual:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002056 dst.move(i, CmpGE(lhs.UInt(i), rhs.UInt(i)));
Ben Claytone95eeb12019-03-04 16:32:09 +00002057 break;
2058 case spv::OpSGreaterThanEqual:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002059 dst.move(i, CmpGE(lhs.Int(i), rhs.Int(i)));
Ben Claytone95eeb12019-03-04 16:32:09 +00002060 break;
2061 case spv::OpULessThan:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002062 dst.move(i, CmpLT(lhs.UInt(i), rhs.UInt(i)));
Ben Claytone95eeb12019-03-04 16:32:09 +00002063 break;
2064 case spv::OpSLessThan:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002065 dst.move(i, CmpLT(lhs.Int(i), rhs.Int(i)));
Ben Claytone95eeb12019-03-04 16:32:09 +00002066 break;
2067 case spv::OpULessThanEqual:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002068 dst.move(i, CmpLE(lhs.UInt(i), rhs.UInt(i)));
Ben Claytone95eeb12019-03-04 16:32:09 +00002069 break;
2070 case spv::OpSLessThanEqual:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002071 dst.move(i, CmpLE(lhs.Int(i), rhs.Int(i)));
Ben Claytone95eeb12019-03-04 16:32:09 +00002072 break;
Ben Claytondd1e37e2019-02-28 19:59:15 +00002073 case spv::OpFAdd:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002074 dst.move(i, lhs.Float(i) + rhs.Float(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00002075 break;
2076 case spv::OpFSub:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002077 dst.move(i, lhs.Float(i) - rhs.Float(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00002078 break;
Chris Forbes9d931532019-03-08 09:53:03 -08002079 case spv::OpFMul:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002080 dst.move(i, lhs.Float(i) * rhs.Float(i));
Chris Forbes9d931532019-03-08 09:53:03 -08002081 break;
Ben Claytondd1e37e2019-02-28 19:59:15 +00002082 case spv::OpFDiv:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002083 dst.move(i, lhs.Float(i) / rhs.Float(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00002084 break;
Chris Forbes0e4d6ff2019-03-15 13:43:36 -07002085 case spv::OpFMod:
2086 // TODO(b/126873455): inaccurate for values greater than 2^24
Nicolas Capens80c796b2019-03-19 21:38:44 -04002087 dst.move(i, lhs.Float(i) - rhs.Float(i) * Floor(lhs.Float(i) / rhs.Float(i)));
Chris Forbes0e4d6ff2019-03-15 13:43:36 -07002088 break;
Chris Forbes1a4c7122019-03-15 14:50:47 -07002089 case spv::OpFRem:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002090 dst.move(i, lhs.Float(i) % rhs.Float(i));
Chris Forbes1a4c7122019-03-15 14:50:47 -07002091 break;
Ben Claytonec1aeb82019-03-04 19:33:27 +00002092 case spv::OpFOrdEqual:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002093 dst.move(i, CmpEQ(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00002094 break;
2095 case spv::OpFUnordEqual:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002096 dst.move(i, CmpUEQ(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00002097 break;
2098 case spv::OpFOrdNotEqual:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002099 dst.move(i, CmpNEQ(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00002100 break;
2101 case spv::OpFUnordNotEqual:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002102 dst.move(i, CmpUNEQ(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00002103 break;
2104 case spv::OpFOrdLessThan:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002105 dst.move(i, CmpLT(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00002106 break;
2107 case spv::OpFUnordLessThan:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002108 dst.move(i, CmpULT(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00002109 break;
2110 case spv::OpFOrdGreaterThan:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002111 dst.move(i, CmpGT(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00002112 break;
2113 case spv::OpFUnordGreaterThan:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002114 dst.move(i, CmpUGT(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00002115 break;
2116 case spv::OpFOrdLessThanEqual:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002117 dst.move(i, CmpLE(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00002118 break;
2119 case spv::OpFUnordLessThanEqual:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002120 dst.move(i, CmpULE(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00002121 break;
2122 case spv::OpFOrdGreaterThanEqual:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002123 dst.move(i, CmpGE(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00002124 break;
2125 case spv::OpFUnordGreaterThanEqual:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002126 dst.move(i, CmpUGE(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00002127 break;
Ben Claytondd1e37e2019-02-28 19:59:15 +00002128 case spv::OpShiftRightLogical:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002129 dst.move(i, lhs.UInt(i) >> rhs.UInt(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00002130 break;
2131 case spv::OpShiftRightArithmetic:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002132 dst.move(i, lhs.Int(i) >> rhs.Int(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00002133 break;
2134 case spv::OpShiftLeftLogical:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002135 dst.move(i, lhs.UInt(i) << rhs.UInt(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00002136 break;
2137 case spv::OpBitwiseOr:
2138 case spv::OpLogicalOr:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002139 dst.move(i, lhs.UInt(i) | rhs.UInt(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00002140 break;
2141 case spv::OpBitwiseXor:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002142 dst.move(i, lhs.UInt(i) ^ rhs.UInt(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00002143 break;
2144 case spv::OpBitwiseAnd:
2145 case spv::OpLogicalAnd:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002146 dst.move(i, lhs.UInt(i) & rhs.UInt(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00002147 break;
Chris Forbese86b6dc2019-03-01 09:08:47 -08002148 case spv::OpSMulExtended:
2149 // Extended ops: result is a structure containing two members of the same type as lhs & rhs.
2150 // In our flat view then, component i is the i'th component of the first member;
2151 // component i + N is the i'th component of the second member.
Nicolas Capens80c796b2019-03-19 21:38:44 -04002152 dst.move(i, lhs.Int(i) * rhs.Int(i));
2153 dst.move(i + lhsType.sizeInComponents, MulHigh(lhs.Int(i), rhs.Int(i)));
Chris Forbese86b6dc2019-03-01 09:08:47 -08002154 break;
2155 case spv::OpUMulExtended:
Nicolas Capens80c796b2019-03-19 21:38:44 -04002156 dst.move(i, lhs.UInt(i) * rhs.UInt(i));
2157 dst.move(i + lhsType.sizeInComponents, MulHigh(lhs.UInt(i), rhs.UInt(i)));
Chris Forbese86b6dc2019-03-01 09:08:47 -08002158 break;
Ben Claytondd1e37e2019-02-28 19:59:15 +00002159 default:
2160 UNIMPLEMENTED("Unhandled binary operator %s", OpcodeName(insn.opcode()).c_str());
2161 }
2162 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002163
2164 return EmitResult::Continue;
Ben Claytondd1e37e2019-02-28 19:59:15 +00002165 }
2166
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002167 SpirvShader::EmitResult SpirvShader::EmitDot(InsnIterator insn, EmitState *state) const
Chris Forbes2b287cc2019-03-01 13:24:17 -08002168 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002169 auto routine = state->routine;
Chris Forbes2b287cc2019-03-01 13:24:17 -08002170 auto &type = getType(insn.word(1));
Ben Claytonaf26cfe2019-03-21 17:32:44 +00002171 ASSERT(type.sizeInComponents == 1);
Chris Forbes2b287cc2019-03-01 13:24:17 -08002172 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
2173 auto &lhsType = getType(getObject(insn.word(3)).type);
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002174 auto lhs = GenericValue(this, routine, insn.word(3));
2175 auto rhs = GenericValue(this, routine, insn.word(4));
Chris Forbes2b287cc2019-03-01 13:24:17 -08002176
Nicolas Capens80c796b2019-03-19 21:38:44 -04002177 dst.move(0, Dot(lhsType.sizeInComponents, lhs, rhs));
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002178 return EmitResult::Continue;
Chris Forbes2b287cc2019-03-01 13:24:17 -08002179 }
2180
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002181 SpirvShader::EmitResult SpirvShader::EmitSelect(InsnIterator insn, EmitState *state) const
Ben Claytonbf943f62019-03-05 12:57:39 +00002182 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002183 auto routine = state->routine;
Ben Claytonbf943f62019-03-05 12:57:39 +00002184 auto &type = getType(insn.word(1));
2185 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002186 auto cond = GenericValue(this, routine, insn.word(3));
2187 auto lhs = GenericValue(this, routine, insn.word(4));
2188 auto rhs = GenericValue(this, routine, insn.word(5));
Ben Claytonbf943f62019-03-05 12:57:39 +00002189
2190 for (auto i = 0u; i < type.sizeInComponents; i++)
2191 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002192 dst.move(i, (cond.Int(i) & lhs.Int(i)) | (~cond.Int(i) & rhs.Int(i))); // FIXME: IfThenElse()
Ben Claytonbf943f62019-03-05 12:57:39 +00002193 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002194
2195 return EmitResult::Continue;
Ben Claytonbf943f62019-03-05 12:57:39 +00002196 }
2197
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002198 SpirvShader::EmitResult SpirvShader::EmitExtendedInstruction(InsnIterator insn, EmitState *state) const
Chris Forbes9667a5b2019-03-07 09:26:48 -08002199 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002200 auto routine = state->routine;
Chris Forbes9667a5b2019-03-07 09:26:48 -08002201 auto &type = getType(insn.word(1));
2202 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
2203 auto extInstIndex = static_cast<GLSLstd450>(insn.word(4));
2204
2205 switch (extInstIndex)
2206 {
2207 case GLSLstd450FAbs:
2208 {
2209 auto src = GenericValue(this, routine, insn.word(5));
2210 for (auto i = 0u; i < type.sizeInComponents; i++)
2211 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002212 dst.move(i, Abs(src.Float(i)));
Chris Forbes9667a5b2019-03-07 09:26:48 -08002213 }
2214 break;
2215 }
2216 case GLSLstd450SAbs:
2217 {
2218 auto src = GenericValue(this, routine, insn.word(5));
2219 for (auto i = 0u; i < type.sizeInComponents; i++)
2220 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002221 dst.move(i, Abs(src.Int(i)));
Chris Forbes9667a5b2019-03-07 09:26:48 -08002222 }
2223 break;
2224 }
Chris Forbes15dff362019-03-08 11:31:31 -08002225 case GLSLstd450Cross:
2226 {
2227 auto lhs = GenericValue(this, routine, insn.word(5));
2228 auto rhs = GenericValue(this, routine, insn.word(6));
Nicolas Capens80c796b2019-03-19 21:38:44 -04002229 dst.move(0, lhs.Float(1) * rhs.Float(2) - rhs.Float(1) * lhs.Float(2));
2230 dst.move(1, lhs.Float(2) * rhs.Float(0) - rhs.Float(2) * lhs.Float(0));
2231 dst.move(2, lhs.Float(0) * rhs.Float(1) - rhs.Float(0) * lhs.Float(1));
Chris Forbes15dff362019-03-08 11:31:31 -08002232 break;
2233 }
Chris Forbesc212bbd2019-03-08 12:02:27 -08002234 case GLSLstd450Floor:
2235 {
2236 auto src = GenericValue(this, routine, insn.word(5));
2237 for (auto i = 0u; i < type.sizeInComponents; i++)
2238 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002239 dst.move(i, Floor(src.Float(i)));
Chris Forbesc212bbd2019-03-08 12:02:27 -08002240 }
2241 break;
2242 }
Chris Forbesdd172cc2019-03-08 13:36:40 -08002243 case GLSLstd450Trunc:
2244 {
2245 auto src = GenericValue(this, routine, insn.word(5));
2246 for (auto i = 0u; i < type.sizeInComponents; i++)
2247 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002248 dst.move(i, Trunc(src.Float(i)));
Chris Forbesdd172cc2019-03-08 13:36:40 -08002249 }
2250 break;
2251 }
2252 case GLSLstd450Ceil:
2253 {
2254 auto src = GenericValue(this, routine, insn.word(5));
2255 for (auto i = 0u; i < type.sizeInComponents; i++)
2256 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002257 dst.move(i, Ceil(src.Float(i)));
Chris Forbesdd172cc2019-03-08 13:36:40 -08002258 }
2259 break;
2260 }
2261 case GLSLstd450Fract:
2262 {
2263 auto src = GenericValue(this, routine, insn.word(5));
2264 for (auto i = 0u; i < type.sizeInComponents; i++)
2265 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002266 dst.move(i, Frac(src.Float(i)));
Chris Forbesdd172cc2019-03-08 13:36:40 -08002267 }
2268 break;
2269 }
2270 case GLSLstd450Round:
2271 {
2272 auto src = GenericValue(this, routine, insn.word(5));
2273 for (auto i = 0u; i < type.sizeInComponents; i++)
2274 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002275 dst.move(i, Round(src.Float(i)));
Chris Forbesdd172cc2019-03-08 13:36:40 -08002276 }
2277 break;
2278 }
2279 case GLSLstd450RoundEven:
2280 {
2281 auto src = GenericValue(this, routine, insn.word(5));
2282 for (auto i = 0u; i < type.sizeInComponents; i++)
2283 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002284 auto x = Round(src.Float(i));
Chris Forbesdd172cc2019-03-08 13:36:40 -08002285 // dst = round(src) + ((round(src) < src) * 2 - 1) * (fract(src) == 0.5) * isOdd(round(src));
Nicolas Capens80c796b2019-03-19 21:38:44 -04002286 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 +00002287 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 -08002288 }
2289 break;
2290 }
Chris Forbesdb170772019-03-08 14:50:44 -08002291 case GLSLstd450FMin:
2292 {
2293 auto lhs = GenericValue(this, routine, insn.word(5));
2294 auto rhs = GenericValue(this, routine, insn.word(6));
2295 for (auto i = 0u; i < type.sizeInComponents; i++)
2296 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002297 dst.move(i, Min(lhs.Float(i), rhs.Float(i)));
Chris Forbesdb170772019-03-08 14:50:44 -08002298 }
2299 break;
2300 }
2301 case GLSLstd450FMax:
2302 {
2303 auto lhs = GenericValue(this, routine, insn.word(5));
2304 auto rhs = GenericValue(this, routine, insn.word(6));
2305 for (auto i = 0u; i < type.sizeInComponents; i++)
2306 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002307 dst.move(i, Max(lhs.Float(i), rhs.Float(i)));
Chris Forbesdb170772019-03-08 14:50:44 -08002308 }
2309 break;
2310 }
2311 case GLSLstd450SMin:
2312 {
2313 auto lhs = GenericValue(this, routine, insn.word(5));
2314 auto rhs = GenericValue(this, routine, insn.word(6));
2315 for (auto i = 0u; i < type.sizeInComponents; i++)
2316 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002317 dst.move(i, Min(lhs.Int(i), rhs.Int(i)));
Chris Forbesdb170772019-03-08 14:50:44 -08002318 }
2319 break;
2320 }
2321 case GLSLstd450SMax:
2322 {
2323 auto lhs = GenericValue(this, routine, insn.word(5));
2324 auto rhs = GenericValue(this, routine, insn.word(6));
2325 for (auto i = 0u; i < type.sizeInComponents; i++)
2326 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002327 dst.move(i, Max(lhs.Int(i), rhs.Int(i)));
Chris Forbesdb170772019-03-08 14:50:44 -08002328 }
2329 break;
2330 }
2331 case GLSLstd450UMin:
2332 {
2333 auto lhs = GenericValue(this, routine, insn.word(5));
2334 auto rhs = GenericValue(this, routine, insn.word(6));
2335 for (auto i = 0u; i < type.sizeInComponents; i++)
2336 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002337 dst.move(i, Min(lhs.UInt(i), rhs.UInt(i)));
Chris Forbesdb170772019-03-08 14:50:44 -08002338 }
2339 break;
2340 }
2341 case GLSLstd450UMax:
2342 {
2343 auto lhs = GenericValue(this, routine, insn.word(5));
2344 auto rhs = GenericValue(this, routine, insn.word(6));
2345 for (auto i = 0u; i < type.sizeInComponents; i++)
2346 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002347 dst.move(i, Max(lhs.UInt(i), rhs.UInt(i)));
Chris Forbesdb170772019-03-08 14:50:44 -08002348 }
2349 break;
2350 }
2351 case GLSLstd450Step:
2352 {
2353 auto edge = GenericValue(this, routine, insn.word(5));
2354 auto x = GenericValue(this, routine, insn.word(6));
2355 for (auto i = 0u; i < type.sizeInComponents; i++)
2356 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002357 dst.move(i, CmpNLT(x.Float(i), edge.Float(i)) & As<SIMD::Int>(SIMD::Float(1.0f)));
Chris Forbesdb170772019-03-08 14:50:44 -08002358 }
2359 break;
2360 }
2361 case GLSLstd450SmoothStep:
2362 {
2363 auto edge0 = GenericValue(this, routine, insn.word(5));
2364 auto edge1 = GenericValue(this, routine, insn.word(6));
2365 auto x = GenericValue(this, routine, insn.word(7));
2366 for (auto i = 0u; i < type.sizeInComponents; i++)
2367 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002368 auto tx = Min(Max((x.Float(i) - edge0.Float(i)) /
2369 (edge1.Float(i) - edge0.Float(i)), SIMD::Float(0.0f)), SIMD::Float(1.0f));
Nicolas Capens80c796b2019-03-19 21:38:44 -04002370 dst.move(i, tx * tx * (Float4(3.0f) - Float4(2.0f) * tx));
Chris Forbesdb170772019-03-08 14:50:44 -08002371 }
2372 break;
2373 }
2374 case GLSLstd450FMix:
2375 {
2376 auto x = GenericValue(this, routine, insn.word(5));
2377 auto y = GenericValue(this, routine, insn.word(6));
2378 auto a = GenericValue(this, routine, insn.word(7));
2379 for (auto i = 0u; i < type.sizeInComponents; i++)
2380 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002381 dst.move(i, a.Float(i) * (y.Float(i) - x.Float(i)) + x.Float(i));
Chris Forbesdb170772019-03-08 14:50:44 -08002382 }
2383 break;
2384 }
2385 case GLSLstd450FClamp:
2386 {
2387 auto x = GenericValue(this, routine, insn.word(5));
2388 auto minVal = GenericValue(this, routine, insn.word(6));
2389 auto maxVal = GenericValue(this, routine, insn.word(7));
2390 for (auto i = 0u; i < type.sizeInComponents; i++)
2391 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002392 dst.move(i, Min(Max(x.Float(i), minVal.Float(i)), maxVal.Float(i)));
Chris Forbesdb170772019-03-08 14:50:44 -08002393 }
2394 break;
2395 }
2396 case GLSLstd450SClamp:
2397 {
2398 auto x = GenericValue(this, routine, insn.word(5));
2399 auto minVal = GenericValue(this, routine, insn.word(6));
2400 auto maxVal = GenericValue(this, routine, insn.word(7));
2401 for (auto i = 0u; i < type.sizeInComponents; i++)
2402 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002403 dst.move(i, Min(Max(x.Int(i), minVal.Int(i)), maxVal.Int(i)));
Chris Forbesdb170772019-03-08 14:50:44 -08002404 }
2405 break;
2406 }
2407 case GLSLstd450UClamp:
2408 {
2409 auto x = GenericValue(this, routine, insn.word(5));
2410 auto minVal = GenericValue(this, routine, insn.word(6));
2411 auto maxVal = GenericValue(this, routine, insn.word(7));
2412 for (auto i = 0u; i < type.sizeInComponents; i++)
2413 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002414 dst.move(i, Min(Max(x.UInt(i), minVal.UInt(i)), maxVal.UInt(i)));
Chris Forbesdb170772019-03-08 14:50:44 -08002415 }
2416 break;
2417 }
2418 case GLSLstd450FSign:
2419 {
2420 auto src = GenericValue(this, routine, insn.word(5));
2421 for (auto i = 0u; i < type.sizeInComponents; i++)
2422 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002423 auto neg = As<SIMD::Int>(CmpLT(src.Float(i), SIMD::Float(-0.0f))) & As<SIMD::Int>(SIMD::Float(-1.0f));
2424 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 -04002425 dst.move(i, neg | pos);
Chris Forbesdb170772019-03-08 14:50:44 -08002426 }
2427 break;
2428 }
2429 case GLSLstd450SSign:
2430 {
2431 auto src = GenericValue(this, routine, insn.word(5));
2432 for (auto i = 0u; i < type.sizeInComponents; i++)
2433 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002434 auto neg = CmpLT(src.Int(i), SIMD::Int(0)) & SIMD::Int(-1);
2435 auto pos = CmpNLE(src.Int(i), SIMD::Int(0)) & SIMD::Int(1);
Nicolas Capens80c796b2019-03-19 21:38:44 -04002436 dst.move(i, neg | pos);
Chris Forbesdb170772019-03-08 14:50:44 -08002437 }
2438 break;
2439 }
Chris Forbes868ed902019-03-13 17:39:45 -07002440 case GLSLstd450Reflect:
2441 {
2442 auto I = GenericValue(this, routine, insn.word(5));
2443 auto N = GenericValue(this, routine, insn.word(6));
2444
2445 SIMD::Float d = Dot(type.sizeInComponents, I, N);
2446
2447 for (auto i = 0u; i < type.sizeInComponents; i++)
2448 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002449 dst.move(i, I.Float(i) - SIMD::Float(2.0f) * d * N.Float(i));
Chris Forbes868ed902019-03-13 17:39:45 -07002450 }
2451 break;
2452 }
2453 case GLSLstd450Refract:
2454 {
2455 auto I = GenericValue(this, routine, insn.word(5));
2456 auto N = GenericValue(this, routine, insn.word(6));
2457 auto eta = GenericValue(this, routine, insn.word(7));
2458
2459 SIMD::Float d = Dot(type.sizeInComponents, I, N);
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002460 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 -07002461 SIMD::Int pos = CmpNLT(k, SIMD::Float(0.0f));
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002462 SIMD::Float t = (eta.Float(0) * d + Sqrt(k));
Chris Forbes868ed902019-03-13 17:39:45 -07002463
2464 for (auto i = 0u; i < type.sizeInComponents; i++)
2465 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002466 dst.move(i, pos & As<SIMD::Int>(eta.Float(0) * I.Float(i) - t * N.Float(i)));
Chris Forbes868ed902019-03-13 17:39:45 -07002467 }
2468 break;
2469 }
2470 case GLSLstd450FaceForward:
2471 {
2472 auto N = GenericValue(this, routine, insn.word(5));
2473 auto I = GenericValue(this, routine, insn.word(6));
2474 auto Nref = GenericValue(this, routine, insn.word(7));
2475
2476 SIMD::Float d = Dot(type.sizeInComponents, I, Nref);
2477 SIMD::Int neg = CmpLT(d, SIMD::Float(0.0f));
2478
2479 for (auto i = 0u; i < type.sizeInComponents; i++)
2480 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002481 auto n = N.Float(i);
Nicolas Capens80c796b2019-03-19 21:38:44 -04002482 dst.move(i, (neg & As<SIMD::Int>(n)) | (~neg & As<SIMD::Int>(-n)));
Chris Forbes868ed902019-03-13 17:39:45 -07002483 }
2484 break;
2485 }
2486 case GLSLstd450Length:
2487 {
2488 auto x = GenericValue(this, routine, insn.word(5));
2489 SIMD::Float d = Dot(getType(getObject(insn.word(5)).type).sizeInComponents, x, x);
2490
Nicolas Capens80c796b2019-03-19 21:38:44 -04002491 dst.move(0, Sqrt(d));
Chris Forbes868ed902019-03-13 17:39:45 -07002492 break;
2493 }
2494 case GLSLstd450Normalize:
2495 {
2496 auto x = GenericValue(this, routine, insn.word(5));
2497 SIMD::Float d = Dot(getType(getObject(insn.word(5)).type).sizeInComponents, x, x);
2498 SIMD::Float invLength = SIMD::Float(1.0f) / Sqrt(d);
2499
2500 for (auto i = 0u; i < type.sizeInComponents; i++)
2501 {
Nicolas Capens80c796b2019-03-19 21:38:44 -04002502 dst.move(i, invLength * x.Float(i));
Chris Forbes868ed902019-03-13 17:39:45 -07002503 }
2504 break;
2505 }
2506 case GLSLstd450Distance:
2507 {
2508 auto p0 = GenericValue(this, routine, insn.word(5));
2509 auto p1 = GenericValue(this, routine, insn.word(6));
2510 auto p0Type = getType(getObject(insn.word(5)).type);
2511
2512 // sqrt(dot(p0-p1, p0-p1))
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002513 SIMD::Float d = (p0.Float(0) - p1.Float(0)) * (p0.Float(0) - p1.Float(0));
Chris Forbes868ed902019-03-13 17:39:45 -07002514
2515 for (auto i = 1u; i < p0Type.sizeInComponents; i++)
2516 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002517 d += (p0.Float(i) - p1.Float(i)) * (p0.Float(i) - p1.Float(i));
Chris Forbes868ed902019-03-13 17:39:45 -07002518 }
2519
Nicolas Capens80c796b2019-03-19 21:38:44 -04002520 dst.move(0, Sqrt(d));
Chris Forbes868ed902019-03-13 17:39:45 -07002521 break;
2522 }
Chris Forbes9667a5b2019-03-07 09:26:48 -08002523 default:
2524 UNIMPLEMENTED("Unhandled ExtInst %d", extInstIndex);
2525 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002526
2527 return EmitResult::Continue;
Chris Forbes9667a5b2019-03-07 09:26:48 -08002528 }
2529
Nicolas Capens86509d92019-03-21 13:23:50 -04002530 std::memory_order SpirvShader::MemoryOrder(spv::MemorySemanticsMask memorySemantics)
2531 {
2532 switch(memorySemantics)
2533 {
2534 case spv::MemorySemanticsMaskNone: return std::memory_order_relaxed;
2535 case spv::MemorySemanticsAcquireMask: return std::memory_order_acquire;
2536 case spv::MemorySemanticsReleaseMask: return std::memory_order_release;
2537 case spv::MemorySemanticsAcquireReleaseMask: return std::memory_order_acq_rel;
2538 case spv::MemorySemanticsSequentiallyConsistentMask: return std::memory_order_acq_rel; // Vulkan 1.1: "SequentiallyConsistent is treated as AcquireRelease"
2539 default:
2540 UNREACHABLE("MemorySemanticsMask %x", memorySemantics);
2541 return std::memory_order_acq_rel;
2542 }
2543 }
2544
Chris Forbes868ed902019-03-13 17:39:45 -07002545 SIMD::Float SpirvShader::Dot(unsigned numComponents, GenericValue const & x, GenericValue const & y) const
2546 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002547 SIMD::Float d = x.Float(0) * y.Float(0);
Chris Forbes868ed902019-03-13 17:39:45 -07002548
2549 for (auto i = 1u; i < numComponents; i++)
2550 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002551 d += x.Float(i) * y.Float(i);
Chris Forbes868ed902019-03-13 17:39:45 -07002552 }
2553
2554 return d;
2555 }
2556
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002557 SpirvShader::EmitResult SpirvShader::EmitAny(InsnIterator insn, EmitState *state) const
Chris Forbes0785f692019-03-08 09:09:18 -08002558 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002559 auto routine = state->routine;
Chris Forbes0785f692019-03-08 09:09:18 -08002560 auto &type = getType(insn.word(1));
Ben Claytonaf26cfe2019-03-21 17:32:44 +00002561 ASSERT(type.sizeInComponents == 1);
Chris Forbes0785f692019-03-08 09:09:18 -08002562 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
2563 auto &srcType = getType(getObject(insn.word(3)).type);
2564 auto src = GenericValue(this, routine, insn.word(3));
2565
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002566 SIMD::UInt result = src.UInt(0);
Chris Forbes0785f692019-03-08 09:09:18 -08002567
2568 for (auto i = 1u; i < srcType.sizeInComponents; i++)
2569 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002570 result |= src.UInt(i);
Chris Forbes0785f692019-03-08 09:09:18 -08002571 }
2572
Nicolas Capens80c796b2019-03-19 21:38:44 -04002573 dst.move(0, result);
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002574 return EmitResult::Continue;
Chris Forbes0785f692019-03-08 09:09:18 -08002575 }
2576
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002577 SpirvShader::EmitResult SpirvShader::EmitAll(InsnIterator insn, EmitState *state) const
Chris Forbes0785f692019-03-08 09:09:18 -08002578 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002579 auto routine = state->routine;
Chris Forbes0785f692019-03-08 09:09:18 -08002580 auto &type = getType(insn.word(1));
Ben Claytonaf26cfe2019-03-21 17:32:44 +00002581 ASSERT(type.sizeInComponents == 1);
Chris Forbes0785f692019-03-08 09:09:18 -08002582 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
2583 auto &srcType = getType(getObject(insn.word(3)).type);
2584 auto src = GenericValue(this, routine, insn.word(3));
2585
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002586 SIMD::UInt result = src.UInt(0);
Chris Forbes0785f692019-03-08 09:09:18 -08002587
2588 for (auto i = 1u; i < srcType.sizeInComponents; i++)
2589 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002590 result &= src.UInt(i);
Chris Forbes0785f692019-03-08 09:09:18 -08002591 }
2592
Nicolas Capens80c796b2019-03-19 21:38:44 -04002593 dst.move(0, result);
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002594 return EmitResult::Continue;
Chris Forbes0785f692019-03-08 09:09:18 -08002595 }
2596
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002597 SpirvShader::EmitResult SpirvShader::EmitBranch(InsnIterator insn, EmitState *state) const
Ben Claytone37ce612019-03-13 19:57:42 +00002598 {
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002599 auto target = Block::ID(insn.word(1));
2600 auto edge = Block::Edge{state->currentBlock, target};
2601 state->edgeActiveLaneMasks.emplace(edge, state->activeLaneMask());
2602 return EmitResult::Terminator;
Ben Claytone37ce612019-03-13 19:57:42 +00002603 }
2604
Chris Forbesc61271e2019-02-19 17:01:28 -08002605 void SpirvShader::emitEpilog(SpirvRoutine *routine) const
2606 {
2607 for (auto insn : *this)
2608 {
2609 switch (insn.opcode())
2610 {
2611 case spv::OpVariable:
2612 {
Ben Claytonaf973b62019-03-13 18:19:20 +00002613 Object::ID resultId = insn.word(2);
Chris Forbesc61271e2019-02-19 17:01:28 -08002614 auto &object = getObject(resultId);
Ben Clayton9a162482019-02-25 11:54:43 +00002615 auto &objectTy = getType(object.type);
2616 if (object.kind == Object::Kind::InterfaceVariable && objectTy.storageClass == spv::StorageClassOutput)
Chris Forbesc61271e2019-02-19 17:01:28 -08002617 {
2618 auto &dst = routine->getValue(resultId);
2619 int offset = 0;
2620 VisitInterface(resultId,
2621 [&](Decorations const &d, AttribType type) {
2622 auto scalarSlot = d.Location << 2 | d.Component;
2623 routine->outputs[scalarSlot] = dst[offset++];
2624 });
2625 }
2626 break;
2627 }
2628 default:
2629 break;
2630 }
2631 }
2632 }
Ben Clayton76e9bc02019-02-26 15:02:18 +00002633
Ben Clayton64f78f52019-03-21 17:21:06 +00002634 SpirvShader::Block::Block(InsnIterator begin, InsnIterator end) : begin_(begin), end_(end)
2635 {
2636 // Default to a Simple, this may change later.
2637 kind = Block::Simple;
2638
2639 // Walk the instructions to find the last two of the block.
2640 InsnIterator insns[2];
2641 for (auto insn : *this)
2642 {
2643 insns[0] = insns[1];
2644 insns[1] = insn;
2645 }
2646
2647 switch (insns[1].opcode())
2648 {
2649 case spv::OpBranch:
2650 branchInstruction = insns[1];
2651 outs.emplace(Block::ID(branchInstruction.word(1)));
2652
2653 switch (insns[0].opcode())
2654 {
2655 case spv::OpLoopMerge:
2656 kind = Loop;
2657 mergeInstruction = insns[0];
2658 mergeBlock = Block::ID(mergeInstruction.word(1));
2659 continueTarget = Block::ID(mergeInstruction.word(2));
2660 break;
2661
2662 default:
2663 kind = Block::Simple;
2664 break;
2665 }
2666 break;
2667
2668 case spv::OpBranchConditional:
2669 branchInstruction = insns[1];
2670 outs.emplace(Block::ID(branchInstruction.word(2)));
2671 outs.emplace(Block::ID(branchInstruction.word(3)));
2672
2673 switch (insns[0].opcode())
2674 {
2675 case spv::OpSelectionMerge:
2676 kind = StructuredBranchConditional;
2677 mergeInstruction = insns[0];
2678 mergeBlock = Block::ID(mergeInstruction.word(1));
2679 break;
2680
2681 case spv::OpLoopMerge:
2682 kind = Loop;
2683 mergeInstruction = insns[0];
2684 mergeBlock = Block::ID(mergeInstruction.word(1));
2685 continueTarget = Block::ID(mergeInstruction.word(2));
2686 break;
2687
2688 default:
2689 kind = UnstructuredBranchConditional;
2690 break;
2691 }
2692 break;
2693
2694 case spv::OpSwitch:
2695 branchInstruction = insns[1];
2696 outs.emplace(Block::ID(branchInstruction.word(2)));
2697 for (uint32_t w = 4; w < branchInstruction.wordCount(); w += 2)
2698 {
2699 outs.emplace(Block::ID(branchInstruction.word(w)));
2700 }
2701
2702 switch (insns[0].opcode())
2703 {
2704 case spv::OpSelectionMerge:
2705 kind = StructuredSwitch;
2706 mergeInstruction = insns[0];
2707 mergeBlock = Block::ID(mergeInstruction.word(1));
2708 break;
2709
2710 default:
2711 kind = UnstructuredSwitch;
2712 break;
2713 }
2714 break;
2715
2716 default:
2717 break;
2718 }
2719 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +00002720
2721 void SpirvShader::EmitState::addOutputActiveLaneMaskEdge(Block::ID to, RValue<SIMD::Int> mask)
2722 {
2723 addActiveLaneMaskEdge(currentBlock, to, mask & activeLaneMask());
2724 }
2725
2726 void SpirvShader::EmitState::addActiveLaneMaskEdge(Block::ID from, Block::ID to, RValue<SIMD::Int> mask)
2727 {
2728 auto edge = Block::Edge{from, to};
2729 auto it = edgeActiveLaneMasks.find(edge);
2730 if (it == edgeActiveLaneMasks.end())
2731 {
2732 edgeActiveLaneMasks.emplace(edge, mask);
2733 }
2734 else
2735 {
2736 auto combined = it->second | mask;
2737 edgeActiveLaneMasks.erase(edge);
2738 edgeActiveLaneMasks.emplace(edge, combined);
2739 }
2740 }
2741
2742 RValue<SIMD::Int> SpirvShader::EmitState::getActiveLaneMaskEdge(Block::ID from, Block::ID to)
2743 {
2744 auto edge = Block::Edge{from, to};
2745 auto it = edgeActiveLaneMasks.find(edge);
2746 ASSERT_MSG(it != edgeActiveLaneMasks.end(), "Could not find edge %d -> %d", from.value(), to.value());
2747 return it->second;
2748 }
2749
Ben Clayton76e9bc02019-02-26 15:02:18 +00002750 SpirvRoutine::SpirvRoutine(vk::PipelineLayout const *pipelineLayout) :
2751 pipelineLayout(pipelineLayout)
2752 {
2753 }
2754
Chris Forbesc25b8072018-12-10 15:10:39 -08002755}