blob: 28709daba5055d88106b0583a622e51ae22681a6 [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#ifndef sw_SpirvShader_hpp
16#define sw_SpirvShader_hpp
17
Chris Forbesd5aed492019-02-02 15:18:52 -080018#include "ShaderCore.hpp"
Ben Claytonab51bbf2019-02-20 14:36:27 +000019#include "SpirvID.hpp"
Ben Clayton76e9bc02019-02-26 15:02:18 +000020#include "System/Types.hpp"
21#include "Vulkan/VkDebug.hpp"
22#include "Vulkan/VkConfig.h"
Nicolas Capens86509d92019-03-21 13:23:50 -040023#include "Device/Config.hpp"
24
25#include <spirv/unified1/spirv.hpp>
Chris Forbesaf4ed532018-12-06 18:33:27 -080026
Ben Clayton76e9bc02019-02-26 15:02:18 +000027#include <array>
Ben Clayton6fae32c2019-02-28 20:06:42 +000028#include <cstring>
Ben Clayton49d81582019-03-12 20:05:04 +000029#include <functional>
Chris Forbesaf4ed532018-12-06 18:33:27 -080030#include <string>
31#include <vector>
Ben Clayton64f78f52019-03-21 17:21:06 +000032#include <unordered_set>
Chris Forbesaf4ed532018-12-06 18:33:27 -080033#include <unordered_map>
34#include <cstdint>
Chris Forbesef4ab0f2019-01-18 08:11:03 -080035#include <type_traits>
Chris Forbesd5aed492019-02-02 15:18:52 -080036#include <memory>
Ben Clayton513ed1d2019-03-28 16:07:00 +000037#include <queue>
Chris Forbesaf4ed532018-12-06 18:33:27 -080038
Ben Clayton76e9bc02019-02-26 15:02:18 +000039namespace vk
40{
41 class PipelineLayout;
42} // namespace vk
43
Chris Forbesaf4ed532018-12-06 18:33:27 -080044namespace sw
45{
Ben Clayton24ea5152019-02-26 11:02:42 +000046 // Forward declarations.
47 class SpirvRoutine;
Chris Forbes868ed902019-03-13 17:39:45 -070048 class GenericValue;
Ben Clayton24ea5152019-02-26 11:02:42 +000049
50 // SIMD contains types that represent multiple scalars packed into a single
51 // vector data type. Types in the SIMD namespace provide a semantic hint
52 // that the data should be treated as a per-execution-lane scalar instead of
53 // a typical euclidean-style vector type.
54 namespace SIMD
55 {
56 // Width is the number of per-lane scalars packed into each SIMD vector.
57 static constexpr int Width = 4;
58
59 using Float = rr::Float4;
60 using Int = rr::Int4;
Ben Claytondd1e37e2019-02-28 19:59:15 +000061 using UInt = rr::UInt4;
Ben Clayton3d497382019-04-08 16:16:12 -040062
63 struct Pointer
64 {
65 Pointer(rr::Pointer<Byte> base) : base(base), offset(0), uniform(true) {}
66 Pointer(rr::Pointer<Byte> base, SIMD::Int offset) : base(base), offset(offset), uniform(false) {}
67
68 // Base address for the pointer, common across all lanes.
69 rr::Pointer<rr::Float> base;
70
71 // Per lane offsets from base.
72 // If uniform is false, all offsets are considered zero.
73 Int offset;
74
75 // True if all offsets are zero.
76 bool uniform;
77 };
Ben Clayton24ea5152019-02-26 11:02:42 +000078 }
79
Chris Forbese4ef5f72019-02-15 16:00:08 -080080 // Incrementally constructed complex bundle of rvalues
81 // Effectively a restricted vector, supporting only:
82 // - allocation to a (runtime-known) fixed size
83 // - in-place construction of elements
84 // - const operator[]
85 class Intermediate
86 {
87 public:
Nicolas Capens5851ef42019-03-19 14:28:18 -040088 Intermediate(uint32_t size) : scalar(new rr::Value*[size]), size(size) {
Nicolas Capens5851ef42019-03-19 14:28:18 -040089 memset(scalar, 0, sizeof(rr::Value*) * size);
Ben Clayton6fae32c2019-02-28 20:06:42 +000090 }
Chris Forbese4ef5f72019-02-15 16:00:08 -080091
92 ~Intermediate()
93 {
Nicolas Capens5851ef42019-03-19 14:28:18 -040094 delete[] scalar;
Chris Forbese4ef5f72019-02-15 16:00:08 -080095 }
96
Nicolas Capens80c796b2019-03-19 21:38:44 -040097 void move(uint32_t i, RValue<SIMD::Float> &&scalar) { emplace(i, scalar.value); }
98 void move(uint32_t i, RValue<SIMD::Int> &&scalar) { emplace(i, scalar.value); }
99 void move(uint32_t i, RValue<SIMD::UInt> &&scalar) { emplace(i, scalar.value); }
Chris Forbese4ef5f72019-02-15 16:00:08 -0800100
Nicolas Capens80c796b2019-03-19 21:38:44 -0400101 void move(uint32_t i, const RValue<SIMD::Float> &scalar) { emplace(i, scalar.value); }
102 void move(uint32_t i, const RValue<SIMD::Int> &scalar) { emplace(i, scalar.value); }
103 void move(uint32_t i, const RValue<SIMD::UInt> &scalar) { emplace(i, scalar.value); }
Ben Clayton093be462019-03-08 08:37:24 +0000104
Ben Clayton9b62c5e2019-03-08 09:32:34 +0000105 // Value retrieval functions.
106 RValue<SIMD::Float> Float(uint32_t i) const
Chris Forbese4ef5f72019-02-15 16:00:08 -0800107 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +0000108 ASSERT(i < size);
Nicolas Capens5851ef42019-03-19 14:28:18 -0400109 ASSERT(scalar[i] != nullptr);
110 return As<SIMD::Float>(scalar[i]); // TODO(b/128539387): RValue<SIMD::Float>(scalar)
Chris Forbese4ef5f72019-02-15 16:00:08 -0800111 }
Nicolas Capens5851ef42019-03-19 14:28:18 -0400112
113 RValue<SIMD::Int> Int(uint32_t i) const
114 {
115 ASSERT(i < size);
116 ASSERT(scalar[i] != nullptr);
117 return As<SIMD::Int>(scalar[i]); // TODO(b/128539387): RValue<SIMD::Int>(scalar)
118 }
119
120 RValue<SIMD::UInt> UInt(uint32_t i) const
121 {
122 ASSERT(i < size);
123 ASSERT(scalar[i] != nullptr);
124 return As<SIMD::UInt>(scalar[i]); // TODO(b/128539387): RValue<SIMD::UInt>(scalar)
125 }
Chris Forbese4ef5f72019-02-15 16:00:08 -0800126
127 // No copy/move construction or assignment
128 Intermediate(Intermediate const &) = delete;
129 Intermediate(Intermediate &&) = delete;
130 Intermediate & operator=(Intermediate const &) = delete;
131 Intermediate & operator=(Intermediate &&) = delete;
132
133 private:
Nicolas Capens5851ef42019-03-19 14:28:18 -0400134 void emplace(uint32_t i, rr::Value *value)
135 {
136 ASSERT(i < size);
137 ASSERT(scalar[i] == nullptr);
138 scalar[i] = value;
139 }
Chris Forbese4ef5f72019-02-15 16:00:08 -0800140
Nicolas Capens5851ef42019-03-19 14:28:18 -0400141 rr::Value **const scalar;
Chris Forbese4ef5f72019-02-15 16:00:08 -0800142 uint32_t size;
143 };
144
Chris Forbesaf4ed532018-12-06 18:33:27 -0800145 class SpirvShader
146 {
147 public:
148 using InsnStore = std::vector<uint32_t>;
149 InsnStore insns;
150
151 /* Pseudo-iterator over SPIRV instructions, designed to support range-based-for. */
152 class InsnIterator
153 {
154 InsnStore::const_iterator iter;
155
156 public:
157 spv::Op opcode() const
158 {
159 return static_cast<spv::Op>(*iter & spv::OpCodeMask);
160 }
161
162 uint32_t wordCount() const
Chris Forbes4a979dc2019-01-17 09:36:46 -0800163 {
164 return *iter >> spv::WordCountShift;
165 }
Chris Forbesaf4ed532018-12-06 18:33:27 -0800166
167 uint32_t word(uint32_t n) const
168 {
169 ASSERT(n < wordCount());
170 return iter[n];
171 }
172
Chris Forbes38f85b32019-02-12 20:10:05 +0000173 uint32_t const * wordPointer(uint32_t n) const
174 {
175 ASSERT(n < wordCount());
176 return &iter[n];
177 }
178
Ben Clayton9fd02e02019-03-21 18:47:15 +0000179 bool operator==(InsnIterator const &other) const
180 {
181 return iter == other.iter;
182 }
183
Chris Forbesaf4ed532018-12-06 18:33:27 -0800184 bool operator!=(InsnIterator const &other) const
185 {
186 return iter != other.iter;
187 }
188
189 InsnIterator operator*() const
Chris Forbes4a979dc2019-01-17 09:36:46 -0800190 {
191 return *this;
192 }
Chris Forbesaf4ed532018-12-06 18:33:27 -0800193
194 InsnIterator &operator++()
195 {
196 iter += wordCount();
197 return *this;
198 }
199
200 InsnIterator const operator++(int)
201 {
202 InsnIterator ret{*this};
203 iter += wordCount();
204 return ret;
205 }
206
207 InsnIterator(InsnIterator const &other) = default;
208
209 InsnIterator() = default;
210
211 explicit InsnIterator(InsnStore::const_iterator iter) : iter{iter}
Chris Forbes4a979dc2019-01-17 09:36:46 -0800212 {
213 }
Chris Forbesaf4ed532018-12-06 18:33:27 -0800214 };
215
216 /* range-based-for interface */
217 InsnIterator begin() const
Chris Forbes4a979dc2019-01-17 09:36:46 -0800218 {
219 return InsnIterator{insns.cbegin() + 5};
220 }
Chris Forbesaf4ed532018-12-06 18:33:27 -0800221
222 InsnIterator end() const
Chris Forbes4a979dc2019-01-17 09:36:46 -0800223 {
224 return InsnIterator{insns.cend()};
225 }
Chris Forbesaf4ed532018-12-06 18:33:27 -0800226
Ben Claytone205d342019-02-20 10:22:09 +0000227 class Type
228 {
229 public:
Ben Claytonaf973b62019-03-13 18:19:20 +0000230 using ID = SpirvID<Type>;
231
Nicolas Capens29090852019-03-19 16:22:35 -0400232 spv::Op opcode() const { return definition.opcode(); }
233
Ben Claytone205d342019-02-20 10:22:09 +0000234 InsnIterator definition;
Ben Clayton9a162482019-02-25 11:54:43 +0000235 spv::StorageClass storageClass = static_cast<spv::StorageClass>(-1);
Ben Claytone205d342019-02-20 10:22:09 +0000236 uint32_t sizeInComponents = 0;
237 bool isBuiltInBlock = false;
Ben Clayton9a162482019-02-25 11:54:43 +0000238
239 // Inner element type for pointers, arrays, vectors and matrices.
Ben Claytonaf973b62019-03-13 18:19:20 +0000240 ID element;
Ben Claytone205d342019-02-20 10:22:09 +0000241 };
242
Chris Forbes296aa252018-12-27 11:48:21 -0800243 class Object
244 {
245 public:
Ben Claytonaf973b62019-03-13 18:19:20 +0000246 using ID = SpirvID<Object>;
247
Nicolas Capens29090852019-03-19 16:22:35 -0400248 spv::Op opcode() const { return definition.opcode(); }
249
Chris Forbes296aa252018-12-27 11:48:21 -0800250 InsnIterator definition;
Ben Claytonaf973b62019-03-13 18:19:20 +0000251 Type::ID type;
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800252 std::unique_ptr<uint32_t[]> constantValue = nullptr;
Chris Forbes296aa252018-12-27 11:48:21 -0800253
254 enum class Kind
255 {
Ben Clayton484e08e2019-04-05 12:11:39 +0100256 // Invalid default kind.
257 // If we get left with an object in this state, the module was
258 // broken.
259 Unknown,
260
261 // TODO: Better document this kind.
262 // A shader interface variable pointer.
263 // Pointer with uniform address across all lanes.
264 // Pointer held by SpirvRoutine::pointers
265 InterfaceVariable,
266
267 // Constant value held by Object::constantValue.
268 Constant,
269
270 // Value held by SpirvRoutine::intermediates.
271 Intermediate,
272
273 // DivergentPointer formed from a base pointer and per-lane offset.
274 // Base pointer held by SpirvRoutine::pointers
275 // Per-lane offset held by SpirvRoutine::intermediates.
276 DivergentPointer,
277
278 // Pointer with uniform address across all lanes.
279 // Pointer held by SpirvRoutine::pointers
280 NonDivergentPointer,
281
Ben Clayton6b511342019-04-05 12:12:30 +0100282 // A pointer to a vk::DescriptorSet*.
283 // Pointer held by SpirvRoutine::pointers.
284 DescriptorSet,
Nicolas Capens82eb22e2019-04-10 01:15:43 -0400285 };
Ben Clayton6b511342019-04-05 12:12:30 +0100286
Nicolas Capens82eb22e2019-04-10 01:15:43 -0400287 Kind kind = Kind::Unknown;
Chris Forbes296aa252018-12-27 11:48:21 -0800288 };
289
Ben Clayton9b156612019-03-13 19:48:31 +0000290 // Block is an interval of SPIR-V instructions, starting with the
291 // opening OpLabel, and ending with a termination instruction.
292 class Block
293 {
294 public:
295 using ID = SpirvID<Block>;
Ben Clayton64f78f52019-03-21 17:21:06 +0000296 using Set = std::unordered_set<ID>;
297
298 // Edge represents the graph edge between two blocks.
299 struct Edge
300 {
301 ID from;
302 ID to;
303
304 bool operator == (const Edge& other) const { return from == other.from && to == other.to; }
305
306 struct Hash
307 {
308 std::size_t operator()(const Edge& edge) const noexcept
309 {
310 return std::hash<uint32_t>()(edge.from.value() * 31 + edge.to.value());
311 }
312 };
313 };
Ben Clayton9b156612019-03-13 19:48:31 +0000314
315 Block() = default;
316 Block(const Block& other) = default;
Ben Clayton64f78f52019-03-21 17:21:06 +0000317 explicit Block(InsnIterator begin, InsnIterator end);
Ben Clayton9b156612019-03-13 19:48:31 +0000318
319 /* range-based-for interface */
320 inline InsnIterator begin() const { return begin_; }
321 inline InsnIterator end() const { return end_; }
322
Ben Clayton64f78f52019-03-21 17:21:06 +0000323 enum Kind
324 {
325 Simple, // OpBranch or other simple terminator.
326 StructuredBranchConditional, // OpSelectionMerge + OpBranchConditional
327 UnstructuredBranchConditional, // OpBranchConditional
328 StructuredSwitch, // OpSelectionMerge + OpSwitch
329 UnstructuredSwitch, // OpSwitch
330 Loop, // OpLoopMerge + [OpBranchConditional | OpBranch]
331 };
332
333 Kind kind;
Ben Claytonfe3f0132019-03-26 11:10:16 +0000334 InsnIterator mergeInstruction; // Structured control flow merge instruction.
335 InsnIterator branchInstruction; // Branch instruction.
Ben Clayton64f78f52019-03-21 17:21:06 +0000336 ID mergeBlock; // Structured flow merge block.
337 ID continueTarget; // Loop continue block.
338 Set ins; // Blocks that branch into this block.
339 Set outs; // Blocks that this block branches to.
340
Ben Clayton9b156612019-03-13 19:48:31 +0000341 private:
342 InsnIterator begin_;
343 InsnIterator end_;
344 };
345
Ben Claytonab51bbf2019-02-20 14:36:27 +0000346 struct TypeOrObject {}; // Dummy struct to represent a Type or Object.
347
348 // TypeOrObjectID is an identifier that represents a Type or an Object,
Ben Claytonaf973b62019-03-13 18:19:20 +0000349 // and supports implicit casting to and from Type::ID or Object::ID.
Ben Claytonab51bbf2019-02-20 14:36:27 +0000350 class TypeOrObjectID : public SpirvID<TypeOrObject>
351 {
352 public:
353 using Hash = std::hash<SpirvID<TypeOrObject>>;
354
355 inline TypeOrObjectID(uint32_t id) : SpirvID(id) {}
Ben Claytonaf973b62019-03-13 18:19:20 +0000356 inline TypeOrObjectID(Type::ID id) : SpirvID(id.value()) {}
357 inline TypeOrObjectID(Object::ID id) : SpirvID(id.value()) {}
358 inline operator Type::ID() const { return Type::ID(value()); }
359 inline operator Object::ID() const { return Object::ID(value()); }
Ben Claytonab51bbf2019-02-20 14:36:27 +0000360 };
361
Chris Forbesaf4ed532018-12-06 18:33:27 -0800362 int getSerialID() const
Chris Forbes4a979dc2019-01-17 09:36:46 -0800363 {
364 return serialID;
365 }
Chris Forbesaf4ed532018-12-06 18:33:27 -0800366
367 explicit SpirvShader(InsnStore const &insns);
368
369 struct Modes
370 {
371 bool EarlyFragmentTests : 1;
372 bool DepthReplacing : 1;
373 bool DepthGreater : 1;
374 bool DepthLess : 1;
375 bool DepthUnchanged : 1;
Chris Forbes8b0a2812019-01-17 10:10:09 -0800376 bool ContainsKill : 1;
Chris Forbes93f70b32019-02-10 21:26:27 +0000377 bool NeedsCentroid : 1;
Chris Forbesaf4ed532018-12-06 18:33:27 -0800378
379 // Compute workgroup dimensions
Ben Clayton62758f52019-03-13 14:18:58 +0000380 int WorkgroupSizeX = 1, WorkgroupSizeY = 1, WorkgroupSizeZ = 1;
Chris Forbesaf4ed532018-12-06 18:33:27 -0800381 };
382
383 Modes const &getModes() const
Chris Forbes4a979dc2019-01-17 09:36:46 -0800384 {
385 return modes;
386 }
Chris Forbesaf4ed532018-12-06 18:33:27 -0800387
Chris Forbes2e7f35b2019-01-17 09:51:39 -0800388 enum AttribType : unsigned char
389 {
390 ATTRIBTYPE_FLOAT,
391 ATTRIBTYPE_INT,
392 ATTRIBTYPE_UINT,
Chris Forbesc25b8072018-12-10 15:10:39 -0800393 ATTRIBTYPE_UNUSED,
Chris Forbes2e7f35b2019-01-17 09:51:39 -0800394
395 ATTRIBTYPE_LAST = ATTRIBTYPE_UINT
396 };
397
Chris Forbes8b0a2812019-01-17 10:10:09 -0800398 bool hasBuiltinInput(spv::BuiltIn b) const
399 {
400 return inputBuiltins.find(b) != inputBuiltins.end();
401 }
402
Chris Forbesc25b8072018-12-10 15:10:39 -0800403 struct Decorations
404 {
Nicolas Capens82eb22e2019-04-10 01:15:43 -0400405 int32_t Location = -1;
406 int32_t Component = 0;
407 spv::BuiltIn BuiltIn = static_cast<spv::BuiltIn>(-1);
408 int32_t Offset = -1;
409 int32_t ArrayStride = -1;
410 int32_t MatrixStride = 1;
411
Chris Forbesc25b8072018-12-10 15:10:39 -0800412 bool HasLocation : 1;
413 bool HasComponent : 1;
414 bool HasBuiltIn : 1;
Nicolas Capens82eb22e2019-04-10 01:15:43 -0400415 bool HasOffset : 1;
416 bool HasArrayStride : 1;
417 bool HasMatrixStride : 1;
418
Chris Forbesc25b8072018-12-10 15:10:39 -0800419 bool Flat : 1;
420 bool Centroid : 1;
Chris Forbes5839dcf2018-12-10 19:02:58 -0800421 bool NoPerspective : 1;
Chris Forbesc25b8072018-12-10 15:10:39 -0800422 bool Block : 1;
423 bool BufferBlock : 1;
Ben Clayton8448cc52019-04-09 16:24:31 -0400424 bool RelaxedPrecision : 1;
Chris Forbesc25b8072018-12-10 15:10:39 -0800425
426 Decorations()
Nicolas Capens82eb22e2019-04-10 01:15:43 -0400427 : Location{-1}, Component{0},
Ben Claytond073d8e2019-02-26 11:06:50 +0000428 BuiltIn{static_cast<spv::BuiltIn>(-1)},
Chris Forbes65321072019-03-07 16:13:56 -0800429 Offset{-1}, ArrayStride{-1}, MatrixStride{-1},
Ben Claytond073d8e2019-02-26 11:06:50 +0000430 HasLocation{false}, HasComponent{false},
Nicolas Capens82eb22e2019-04-10 01:15:43 -0400431 HasBuiltIn{false}, HasOffset{false},
432 HasArrayStride{false}, HasMatrixStride{false},
433 Flat{false}, Centroid{false}, NoPerspective{false},
434 Block{false}, BufferBlock{false},
Ben Clayton8448cc52019-04-09 16:24:31 -0400435 RelaxedPrecision{false}
Chris Forbesc25b8072018-12-10 15:10:39 -0800436 {
437 }
438
439 Decorations(Decorations const &) = default;
440
441 void Apply(Decorations const &src);
442
443 void Apply(spv::Decoration decoration, uint32_t arg);
444 };
445
Ben Claytonab51bbf2019-02-20 14:36:27 +0000446 std::unordered_map<TypeOrObjectID, Decorations, TypeOrObjectID::Hash> decorations;
Ben Claytonaf973b62019-03-13 18:19:20 +0000447 std::unordered_map<Type::ID, std::vector<Decorations>> memberDecorations;
Chris Forbesc25b8072018-12-10 15:10:39 -0800448
Nicolas Capens82eb22e2019-04-10 01:15:43 -0400449 struct DescriptorDecorations
450 {
451 int32_t DescriptorSet = -1;
452 int32_t Binding = -1;
453
454 void Apply(DescriptorDecorations const &src);
455 };
456
457 std::unordered_map<Object::ID, DescriptorDecorations> descriptorDecorations;
458
Chris Forbes5839dcf2018-12-10 19:02:58 -0800459 struct InterfaceComponent
460 {
461 AttribType Type;
462 bool Flat : 1;
463 bool Centroid : 1;
464 bool NoPerspective : 1;
465
466 InterfaceComponent()
467 : Type{ATTRIBTYPE_UNUSED}, Flat{false}, Centroid{false}, NoPerspective{false}
468 {
469 }
470 };
471
Chris Forbesbde34082018-12-28 12:03:10 -0800472 struct BuiltinMapping
473 {
Ben Claytonaf973b62019-03-13 18:19:20 +0000474 Object::ID Id;
Chris Forbesbde34082018-12-28 12:03:10 -0800475 uint32_t FirstComponent;
476 uint32_t SizeInComponents;
477 };
478
Chris Forbes5839dcf2018-12-10 19:02:58 -0800479 std::vector<InterfaceComponent> inputs;
480 std::vector<InterfaceComponent> outputs;
481
Chris Forbesc61271e2019-02-19 17:01:28 -0800482 void emitProlog(SpirvRoutine *routine) const;
Ben Claytonc0cf68b2019-03-21 17:46:08 +0000483 void emit(SpirvRoutine *routine, RValue<SIMD::Int> const &activeLaneMask) const;
Chris Forbesc61271e2019-02-19 17:01:28 -0800484 void emitEpilog(SpirvRoutine *routine) const;
Chris Forbesef4ab0f2019-01-18 08:11:03 -0800485
486 using BuiltInHash = std::hash<std::underlying_type<spv::BuiltIn>::type>;
487 std::unordered_map<spv::BuiltIn, BuiltinMapping, BuiltInHash> inputBuiltins;
488 std::unordered_map<spv::BuiltIn, BuiltinMapping, BuiltInHash> outputBuiltins;
Chris Forbesaf4ed532018-12-06 18:33:27 -0800489
Ben Claytonaf973b62019-03-13 18:19:20 +0000490 Type const &getType(Type::ID id) const
Chris Forbes840809a2019-01-14 14:30:20 -0800491 {
492 auto it = types.find(id);
Ben Clayton00424c12019-03-17 17:29:30 +0000493 ASSERT_MSG(it != types.end(), "Unknown type %d", id.value());
Chris Forbes840809a2019-01-14 14:30:20 -0800494 return it->second;
495 }
496
Ben Claytonaf973b62019-03-13 18:19:20 +0000497 Object const &getObject(Object::ID id) const
Chris Forbesd5aed492019-02-02 15:18:52 -0800498 {
Chris Forbes1c658232019-02-01 17:12:25 -0800499 auto it = defs.find(id);
Ben Clayton00424c12019-03-17 17:29:30 +0000500 ASSERT_MSG(it != defs.end(), "Unknown object %d", id.value());
Chris Forbes1c658232019-02-01 17:12:25 -0800501 return it->second;
502 }
503
Ben Clayton9b156612019-03-13 19:48:31 +0000504 Block const &getBlock(Block::ID id) const
505 {
506 auto it = blocks.find(id);
Ben Claytonaf26cfe2019-03-21 17:32:44 +0000507 ASSERT_MSG(it != blocks.end(), "Unknown block %d", id.value());
Ben Clayton9b156612019-03-13 19:48:31 +0000508 return it->second;
509 }
510
Chris Forbesd5aed492019-02-02 15:18:52 -0800511 private:
512 const int serialID;
513 static volatile int serialCounter;
514 Modes modes;
Ben Claytonab51bbf2019-02-20 14:36:27 +0000515 HandleMap<Type> types;
516 HandleMap<Object> defs;
Ben Clayton9b156612019-03-13 19:48:31 +0000517 HandleMap<Block> blocks;
518 Block::ID mainBlockId; // Block of the entry point function.
519
Ben Clayton513ed1d2019-03-28 16:07:00 +0000520 // Walks all reachable the blocks starting from id adding them to
521 // reachable.
522 void TraverseReachableBlocks(Block::ID id, Block::Set& reachable);
Ben Claytonfe3f0132019-03-26 11:10:16 +0000523
524 // Assigns Block::ins from Block::outs for every block.
525 void AssignBlockIns();
526
Ben Clayton0bb83b82019-02-26 11:41:07 +0000527 // DeclareType creates a Type for the given OpTypeX instruction, storing
528 // it into the types map. It is called from the analysis pass (constructor).
529 void DeclareType(InsnIterator insn);
530
Chris Forbesaf4ed532018-12-06 18:33:27 -0800531 void ProcessExecutionMode(InsnIterator it);
Chris Forbes739a7fb2018-12-08 13:09:40 -0800532
533 uint32_t ComputeTypeSize(InsnIterator insn);
Ben Claytonab51bbf2019-02-20 14:36:27 +0000534 void ApplyDecorationsForId(Decorations *d, TypeOrObjectID id) const;
Ben Claytonaf973b62019-03-13 18:19:20 +0000535 void ApplyDecorationsForIdMember(Decorations *d, Type::ID id, uint32_t member) const;
Chris Forbes5839dcf2018-12-10 19:02:58 -0800536
Nicolas Capens82eb22e2019-04-10 01:15:43 -0400537 // Creates an Object for the instruction's result in 'defs'.
538 void DefineResult(const InsnIterator &insn);
539
Ben Clayton831db962019-02-27 14:57:18 +0000540 // Returns true if data in the given storage class is word-interleaved
Ben Claytonff1cede2019-03-08 08:23:34 +0000541 // by each SIMD vector lane, otherwise data is stored linerally.
Ben Clayton831db962019-02-27 14:57:18 +0000542 //
Ben Claytonff1cede2019-03-08 08:23:34 +0000543 // Each lane addresses a single word, picked by a base pointer and an
544 // integer offset.
Ben Clayton831db962019-02-27 14:57:18 +0000545 //
Ben Claytonff1cede2019-03-08 08:23:34 +0000546 // A word is currently 32 bits (single float, int32_t, uint32_t).
547 // A lane is a single element of a SIMD vector register.
Ben Clayton831db962019-02-27 14:57:18 +0000548 //
Ben Claytonff1cede2019-03-08 08:23:34 +0000549 // Storage interleaved by lane - (IsStorageInterleavedByLane() == true):
550 // ---------------------------------------------------------------------
Ben Clayton831db962019-02-27 14:57:18 +0000551 //
Ben Claytonff1cede2019-03-08 08:23:34 +0000552 // Address = PtrBase + sizeof(Word) * (SIMD::Width * LaneOffset + LaneIndex)
Ben Clayton831db962019-02-27 14:57:18 +0000553 //
Ben Claytonff1cede2019-03-08 08:23:34 +0000554 // Assuming SIMD::Width == 4:
555 //
556 // Lane[0] | Lane[1] | Lane[2] | Lane[3]
557 // ===========+===========+===========+==========
558 // LaneOffset=0: | Word[0] | Word[1] | Word[2] | Word[3]
559 // ---------------+-----------+-----------+-----------+----------
560 // LaneOffset=1: | Word[4] | Word[5] | Word[6] | Word[7]
561 // ---------------+-----------+-----------+-----------+----------
562 // LaneOffset=2: | Word[8] | Word[9] | Word[a] | Word[b]
563 // ---------------+-----------+-----------+-----------+----------
564 // LaneOffset=3: | Word[c] | Word[d] | Word[e] | Word[f]
565 //
566 //
567 // Linear storage - (IsStorageInterleavedByLane() == false):
568 // ---------------------------------------------------------
569 //
570 // Address = PtrBase + sizeof(Word) * LaneOffset
571 //
572 // Lane[0] | Lane[1] | Lane[2] | Lane[3]
573 // ===========+===========+===========+==========
574 // LaneOffset=0: | Word[0] | Word[0] | Word[0] | Word[0]
575 // ---------------+-----------+-----------+-----------+----------
576 // LaneOffset=1: | Word[1] | Word[1] | Word[1] | Word[1]
577 // ---------------+-----------+-----------+-----------+----------
578 // LaneOffset=2: | Word[2] | Word[2] | Word[2] | Word[2]
579 // ---------------+-----------+-----------+-----------+----------
580 // LaneOffset=3: | Word[3] | Word[3] | Word[3] | Word[3]
Ben Clayton831db962019-02-27 14:57:18 +0000581 //
582 static bool IsStorageInterleavedByLane(spv::StorageClass storageClass);
583
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800584 template<typename F>
Ben Claytonaf973b62019-03-13 18:19:20 +0000585 int VisitInterfaceInner(Type::ID id, Decorations d, F f) const;
Chris Forbes5839dcf2018-12-10 19:02:58 -0800586
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800587 template<typename F>
Ben Claytonaf973b62019-03-13 18:19:20 +0000588 void VisitInterface(Object::ID id, F f) const;
Chris Forbes5839dcf2018-12-10 19:02:58 -0800589
Ben Claytonaf973b62019-03-13 18:19:20 +0000590 uint32_t GetConstantInt(Object::ID id) const;
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800591 Object& CreateConstant(InsnIterator it);
Chris Forbesbde34082018-12-28 12:03:10 -0800592
Chris Forbes049ff382019-02-02 15:16:43 -0800593 void ProcessInterfaceVariable(Object &object);
Chris Forbes38f85b32019-02-12 20:10:05 +0000594
Ben Clayton3d497382019-04-08 16:16:12 -0400595 // Returns a SIMD::Pointer to the underlying data for the given pointer
596 // object.
597 // Handles objects of the following kinds:
Ben Clayton6b511342019-04-05 12:12:30 +0100598 // • DescriptorSet
Ben Clayton484e08e2019-04-05 12:11:39 +0100599 // • DivergentPointer
600 // • InterfaceVariable
601 // • NonDivergentPointer
602 // Calling GetPointerToData with objects of any other kind will assert.
Ben Clayton3d497382019-04-08 16:16:12 -0400603 SIMD::Pointer GetPointerToData(Object::ID id, int arrayIndex, SpirvRoutine *routine) const;
Ben Clayton484e08e2019-04-05 12:11:39 +0100604
Ben Clayton3d497382019-04-08 16:16:12 -0400605 SIMD::Pointer WalkExplicitLayoutAccessChain(Object::ID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const;
Ben Claytonaf973b62019-03-13 18:19:20 +0000606 SIMD::Int WalkAccessChain(Object::ID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const;
607 uint32_t WalkLiteralAccessChain(Type::ID id, uint32_t numIndexes, uint32_t const *indexes) const;
Ben Claytond4e4c662019-02-26 11:54:34 +0000608
Ben Claytonc0cf68b2019-03-21 17:46:08 +0000609 // EmitState holds control-flow state for the emit() pass.
610 class EmitState
611 {
612 public:
613 RValue<SIMD::Int> activeLaneMask() const
614 {
615 ASSERT(activeLaneMaskValue != nullptr);
616 return RValue<SIMD::Int>(activeLaneMaskValue);
617 }
618
619 void setActiveLaneMask(RValue<SIMD::Int> mask)
620 {
621 activeLaneMaskValue = mask.value;
622 }
623
624 // Add a new active lane mask edge from the current block to out.
625 // The edge mask value will be (mask AND activeLaneMaskValue).
626 // If multiple active lane masks are added for the same edge, then
627 // they will be ORed together.
628 void addOutputActiveLaneMaskEdge(Block::ID out, RValue<SIMD::Int> mask);
629
630 // Add a new active lane mask for the edge from -> to.
631 // If multiple active lane masks are added for the same edge, then
632 // they will be ORed together.
633 void addActiveLaneMaskEdge(Block::ID from, Block::ID to, RValue<SIMD::Int> mask);
634
Ben Claytonc0cf68b2019-03-21 17:46:08 +0000635 SpirvRoutine *routine = nullptr; // The current routine being built.
636 rr::Value *activeLaneMaskValue = nullptr; // The current active lane mask.
637 Block::ID currentBlock; // The current block being built.
638 Block::Set visited; // Blocks already built.
639 std::unordered_map<Block::Edge, RValue<SIMD::Int>, Block::Edge::Hash> edgeActiveLaneMasks;
Ben Clayton513ed1d2019-03-28 16:07:00 +0000640 std::queue<Block::ID> *pending;
Ben Claytonc0cf68b2019-03-21 17:46:08 +0000641 };
642
643 // EmitResult is an enumerator of result values from the Emit functions.
644 enum class EmitResult
645 {
646 Continue, // No termination instructions.
647 Terminator, // Reached a termination instruction.
648 };
649
Ben Claytone747b3c2019-03-21 19:35:15 +0000650 // existsPath returns true if there's a direct or indirect flow from
Ben Clayton513ed1d2019-03-28 16:07:00 +0000651 // the 'from' block to the 'to' block that does not pass through
652 // notPassingThrough.
653 bool existsPath(Block::ID from, Block::ID to, Block::ID notPassingThrough) const;
Ben Claytone747b3c2019-03-21 19:35:15 +0000654
Ben Claytonfe3f0132019-03-26 11:10:16 +0000655 // Lookup the active lane mask for the edge from -> to.
656 // If from is unreachable, then a mask of all zeros is returned.
657 // Asserts if from is reachable and the edge does not exist.
658 RValue<SIMD::Int> GetActiveLaneMaskEdge(EmitState *state, Block::ID from, Block::ID to) const;
659
Ben Clayton513ed1d2019-03-28 16:07:00 +0000660 // Emit all the unvisited blocks (except for ignore) in BFS order,
661 // starting with id.
662 void EmitBlocks(Block::ID id, EmitState *state, Block::ID ignore = 0) const;
663 void EmitNonLoop(EmitState *state) const;
Ben Claytone747b3c2019-03-21 19:35:15 +0000664 void EmitLoop(EmitState *state) const;
Ben Clayton513ed1d2019-03-28 16:07:00 +0000665
666 void EmitInstructions(InsnIterator begin, InsnIterator end, EmitState *state) const;
Ben Claytonc0cf68b2019-03-21 17:46:08 +0000667 EmitResult EmitInstruction(InsnIterator insn, EmitState *state) const;
668
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000669 // Emit pass instructions:
Ben Claytonc0cf68b2019-03-21 17:46:08 +0000670 EmitResult EmitVariable(InsnIterator insn, EmitState *state) const;
671 EmitResult EmitLoad(InsnIterator insn, EmitState *state) const;
672 EmitResult EmitStore(InsnIterator insn, EmitState *state) const;
673 EmitResult EmitAccessChain(InsnIterator insn, EmitState *state) const;
674 EmitResult EmitCompositeConstruct(InsnIterator insn, EmitState *state) const;
675 EmitResult EmitCompositeInsert(InsnIterator insn, EmitState *state) const;
676 EmitResult EmitCompositeExtract(InsnIterator insn, EmitState *state) const;
677 EmitResult EmitVectorShuffle(InsnIterator insn, EmitState *state) const;
678 EmitResult EmitVectorTimesScalar(InsnIterator insn, EmitState *state) const;
Chris Forbes06f4ed72019-03-28 09:53:20 +1300679 EmitResult EmitMatrixTimesVector(InsnIterator insn, EmitState *state) const;
Chris Forbesa563dd82019-03-28 10:32:55 +1300680 EmitResult EmitVectorTimesMatrix(InsnIterator insn, EmitState *state) const;
Chris Forbes51562f12019-03-28 19:08:39 -0700681 EmitResult EmitMatrixTimesMatrix(InsnIterator insn, EmitState *state) const;
Ben Clayton3ee52992019-04-08 11:01:23 -0400682 EmitResult EmitOuterProduct(InsnIterator insn, EmitState *state) const;
Ben Clayton620f7082019-04-08 11:12:08 -0400683 EmitResult EmitTranspose(InsnIterator insn, EmitState *state) const;
Ben Claytonc0cf68b2019-03-21 17:46:08 +0000684 EmitResult EmitVectorExtractDynamic(InsnIterator insn, EmitState *state) const;
685 EmitResult EmitVectorInsertDynamic(InsnIterator insn, EmitState *state) const;
686 EmitResult EmitUnaryOp(InsnIterator insn, EmitState *state) const;
687 EmitResult EmitBinaryOp(InsnIterator insn, EmitState *state) const;
688 EmitResult EmitDot(InsnIterator insn, EmitState *state) const;
689 EmitResult EmitSelect(InsnIterator insn, EmitState *state) const;
690 EmitResult EmitExtendedInstruction(InsnIterator insn, EmitState *state) const;
691 EmitResult EmitAny(InsnIterator insn, EmitState *state) const;
692 EmitResult EmitAll(InsnIterator insn, EmitState *state) const;
693 EmitResult EmitBranch(InsnIterator insn, EmitState *state) const;
Ben Clayton9fd02e02019-03-21 18:47:15 +0000694 EmitResult EmitBranchConditional(InsnIterator insn, EmitState *state) const;
Ben Clayton213a8ce2019-03-21 18:57:23 +0000695 EmitResult EmitSwitch(InsnIterator insn, EmitState *state) const;
Ben Clayton9fd02e02019-03-21 18:47:15 +0000696 EmitResult EmitUnreachable(InsnIterator insn, EmitState *state) const;
697 EmitResult EmitReturn(InsnIterator insn, EmitState *state) const;
Chris Forbes97e95892019-04-02 13:37:37 +1300698 EmitResult EmitKill(InsnIterator insn, EmitState *state) const;
Ben Clayton9fd02e02019-03-21 18:47:15 +0000699 EmitResult EmitPhi(InsnIterator insn, EmitState *state) const;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000700
Nicolas Capens86509d92019-03-21 13:23:50 -0400701 // OpcodeName() returns the name of the opcode op.
702 // If NDEBUG is defined, then OpcodeName() will only return the numerical code.
Ben Claytond4e4c662019-02-26 11:54:34 +0000703 static std::string OpcodeName(spv::Op op);
Nicolas Capens86509d92019-03-21 13:23:50 -0400704 static std::memory_order MemoryOrder(spv::MemorySemanticsMask memorySemantics);
Chris Forbes868ed902019-03-13 17:39:45 -0700705
706 // Helper as we often need to take dot products as part of doing other things.
707 SIMD::Float Dot(unsigned numComponents, GenericValue const & x, GenericValue const & y) const;
Ben Claytonfc77af12019-04-09 10:48:00 -0400708
Chris Forbes50e64932019-04-08 17:49:27 -0700709 SIMD::UInt FloatToHalfBits(SIMD::UInt floatBits, bool storeInUpperBits) const;
710 SIMD::UInt HalfToFloatBits(SIMD::UInt halfBits) const;
Ben Claytonfc77af12019-04-09 10:48:00 -0400711
712 // Splits x into a floating-point significand in the range [0.5, 1.0)
713 // and an integral exponent of two, such that:
714 // x = significand * 2^exponent
715 // Returns the pair <significand, exponent>
716 std::pair<SIMD::Float, SIMD::Int> Frexp(RValue<SIMD::Float> val) const;
Chris Forbesaf4ed532018-12-06 18:33:27 -0800717 };
Ben Claytonab51bbf2019-02-20 14:36:27 +0000718
719 class SpirvRoutine
720 {
721 public:
Ben Clayton76e9bc02019-02-26 15:02:18 +0000722 SpirvRoutine(vk::PipelineLayout const *pipelineLayout);
723
Ben Clayton47747612019-04-04 16:27:35 +0100724 using Variable = Array<SIMD::Float>;
Ben Clayton24ea5152019-02-26 11:02:42 +0000725
Ben Clayton76e9bc02019-02-26 15:02:18 +0000726 vk::PipelineLayout const * const pipelineLayout;
727
Ben Clayton47747612019-04-04 16:27:35 +0100728 std::unordered_map<SpirvShader::Object::ID, Variable> variables;
Ben Claytonab51bbf2019-02-20 14:36:27 +0000729
Ben Claytonaf973b62019-03-13 18:19:20 +0000730 std::unordered_map<SpirvShader::Object::ID, Intermediate> intermediates;
Ben Claytonab51bbf2019-02-20 14:36:27 +0000731
Ben Clayton484e08e2019-04-05 12:11:39 +0100732 std::unordered_map<SpirvShader::Object::ID, Pointer<Byte> > pointers;
Ben Clayton831db962019-02-27 14:57:18 +0000733
Ben Clayton47747612019-04-04 16:27:35 +0100734 Variable inputs = Variable{MAX_INTERFACE_COMPONENTS};
735 Variable outputs = Variable{MAX_INTERFACE_COMPONENTS};
Ben Claytonab51bbf2019-02-20 14:36:27 +0000736
Ben Clayton225a1302019-04-02 12:28:22 +0100737 Pointer<Pointer<Byte>> descriptorSets;
738 Pointer<Int> descriptorDynamicOffsets;
Chris Forbesa30de542019-03-18 18:51:55 -0700739 Pointer<Byte> pushConstants;
Chris Forbes97e95892019-04-02 13:37:37 +1300740 Int killMask = Int{0};
Ben Clayton76e9bc02019-02-26 15:02:18 +0000741
Ben Clayton47747612019-04-04 16:27:35 +0100742 void createVariable(SpirvShader::Object::ID id, uint32_t size)
Ben Claytonab51bbf2019-02-20 14:36:27 +0000743 {
Ben Clayton47747612019-04-04 16:27:35 +0100744 bool added = variables.emplace(id, Variable(size)).second;
745 ASSERT_MSG(added, "Variable %d created twice", id.value());
Ben Claytonab51bbf2019-02-20 14:36:27 +0000746 }
747
Ben Clayton484e08e2019-04-05 12:11:39 +0100748 template <typename T>
749 void createPointer(SpirvShader::Object::ID id, Pointer<T> ptrBase)
750 {
751 bool added = pointers.emplace(id, ptrBase).second;
752 ASSERT_MSG(added, "Pointer %d created twice", id.value());
753 }
754
755 template <typename T>
756 void createPointer(SpirvShader::Object::ID id, RValue<Pointer<T>> ptrBase)
757 {
758 createPointer(id, Pointer<T>(ptrBase));
759 }
760
761 template <typename T>
762 void createPointer(SpirvShader::Object::ID id, Reference<Pointer<T>> ptrBase)
763 {
764 createPointer(id, Pointer<T>(ptrBase));
765 }
766
Ben Claytonaf973b62019-03-13 18:19:20 +0000767 Intermediate& createIntermediate(SpirvShader::Object::ID id, uint32_t size)
Ben Claytonab51bbf2019-02-20 14:36:27 +0000768 {
Chris Forbes928dfee2019-02-26 21:22:32 -0800769 auto it = intermediates.emplace(std::piecewise_construct,
Ben Claytonab51bbf2019-02-20 14:36:27 +0000770 std::forward_as_tuple(id),
771 std::forward_as_tuple(size));
Ben Clayton0e3d3282019-04-04 15:53:04 +0100772 ASSERT_MSG(it.second, "Intermediate %d created twice", id.value());
Chris Forbes928dfee2019-02-26 21:22:32 -0800773 return it.first->second;
Ben Claytonab51bbf2019-02-20 14:36:27 +0000774 }
775
Ben Clayton47747612019-04-04 16:27:35 +0100776 Variable& getVariable(SpirvShader::Object::ID id)
Ben Claytonab51bbf2019-02-20 14:36:27 +0000777 {
Ben Clayton47747612019-04-04 16:27:35 +0100778 auto it = variables.find(id);
779 ASSERT_MSG(it != variables.end(), "Unknown variables %d", id.value());
Ben Claytonab51bbf2019-02-20 14:36:27 +0000780 return it->second;
781 }
782
Ben Claytonaf973b62019-03-13 18:19:20 +0000783 Intermediate const& getIntermediate(SpirvShader::Object::ID id) const
Ben Claytonab51bbf2019-02-20 14:36:27 +0000784 {
785 auto it = intermediates.find(id);
Ben Claytonaf26cfe2019-03-21 17:32:44 +0000786 ASSERT_MSG(it != intermediates.end(), "Unknown intermediate %d", id.value());
Ben Claytonab51bbf2019-02-20 14:36:27 +0000787 return it->second;
788 }
Ben Clayton831db962019-02-27 14:57:18 +0000789
Ben Clayton484e08e2019-04-05 12:11:39 +0100790 Pointer<Byte>& getPointer(SpirvShader::Object::ID id)
Ben Clayton831db962019-02-27 14:57:18 +0000791 {
Ben Clayton484e08e2019-04-05 12:11:39 +0100792 auto it = pointers.find(id);
793 ASSERT_MSG(it != pointers.end(), "Unknown pointer %d", id.value());
Ben Clayton831db962019-02-27 14:57:18 +0000794 return it->second;
795 }
Ben Claytonab51bbf2019-02-20 14:36:27 +0000796 };
797
Chris Forbesd30b5ac2019-02-26 21:53:56 -0800798 class GenericValue
799 {
800 // Generic wrapper over either per-lane intermediate value, or a constant.
801 // Constants are transparently widened to per-lane values in operator[].
802 // This is appropriate in most cases -- if we're not going to do something
803 // significantly different based on whether the value is uniform across lanes.
804
805 SpirvShader::Object const &obj;
806 Intermediate const *intermediate;
807
808 public:
Ben Claytonaf973b62019-03-13 18:19:20 +0000809 GenericValue(SpirvShader const *shader, SpirvRoutine const *routine, SpirvShader::Object::ID objId) :
Chris Forbesd30b5ac2019-02-26 21:53:56 -0800810 obj(shader->getObject(objId)),
Ben Clayton16ab9e92019-04-08 10:57:35 -0400811 intermediate(obj.kind == SpirvShader::Object::Kind::Intermediate ? &routine->getIntermediate(objId) : nullptr),
812 type(obj.type) {}
Chris Forbesd30b5ac2019-02-26 21:53:56 -0800813
Ben Clayton9b62c5e2019-03-08 09:32:34 +0000814 RValue<SIMD::Float> Float(uint32_t i) const
Chris Forbesd30b5ac2019-02-26 21:53:56 -0800815 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +0000816 if (intermediate != nullptr)
817 {
818 return intermediate->Float(i);
819 }
Chris Forbesd30b5ac2019-02-26 21:53:56 -0800820 auto constantValue = reinterpret_cast<float *>(obj.constantValue.get());
Ben Clayton24ea5152019-02-26 11:02:42 +0000821 return RValue<SIMD::Float>(constantValue[i]);
Chris Forbesd30b5ac2019-02-26 21:53:56 -0800822 }
Ben Clayton9b62c5e2019-03-08 09:32:34 +0000823
824 RValue<SIMD::Int> Int(uint32_t i) const
825 {
826 return As<SIMD::Int>(Float(i));
827 }
828
829 RValue<SIMD::UInt> UInt(uint32_t i) const
830 {
831 return As<SIMD::UInt>(Float(i));
832 }
Ben Clayton16ab9e92019-04-08 10:57:35 -0400833
834 SpirvShader::Type::ID const type;
Chris Forbesd30b5ac2019-02-26 21:53:56 -0800835 };
836
Chris Forbesaf4ed532018-12-06 18:33:27 -0800837}
838
Chris Forbesc25b8072018-12-10 15:10:39 -0800839#endif // sw_SpirvShader_hpp