Line data Source code
1 : /*
2 : * Copyright 2016 Google Inc.
3 : *
4 : * Use of this source code is governed by a BSD-style license that can be
5 : * found in the LICENSE file.
6 : */
7 :
8 : #include "SkSLSPIRVCodeGenerator.h"
9 :
10 : #include "GLSL.std.450.h"
11 :
12 : #include "ir/SkSLExpressionStatement.h"
13 : #include "ir/SkSLExtension.h"
14 : #include "ir/SkSLIndexExpression.h"
15 : #include "ir/SkSLVariableReference.h"
16 : #include "SkSLCompiler.h"
17 :
18 : namespace SkSL {
19 :
20 : #define SPIRV_DEBUG 0
21 :
22 : static const int32_t SKSL_MAGIC = 0x0; // FIXME: we should probably register a magic number
23 :
24 0 : void SPIRVCodeGenerator::setupIntrinsics() {
25 : #define ALL_GLSL(x) std::make_tuple(kGLSL_STD_450_IntrinsicKind, GLSLstd450 ## x, GLSLstd450 ## x, \
26 : GLSLstd450 ## x, GLSLstd450 ## x)
27 : #define BY_TYPE_GLSL(ifFloat, ifInt, ifUInt) std::make_tuple(kGLSL_STD_450_IntrinsicKind, \
28 : GLSLstd450 ## ifFloat, \
29 : GLSLstd450 ## ifInt, \
30 : GLSLstd450 ## ifUInt, \
31 : SpvOpUndef)
32 : #define SPECIAL(x) std::make_tuple(kSpecial_IntrinsicKind, k ## x ## _SpecialIntrinsic, \
33 : k ## x ## _SpecialIntrinsic, k ## x ## _SpecialIntrinsic, \
34 : k ## x ## _SpecialIntrinsic)
35 0 : fIntrinsicMap[String("round")] = ALL_GLSL(Round);
36 0 : fIntrinsicMap[String("roundEven")] = ALL_GLSL(RoundEven);
37 0 : fIntrinsicMap[String("trunc")] = ALL_GLSL(Trunc);
38 0 : fIntrinsicMap[String("abs")] = BY_TYPE_GLSL(FAbs, SAbs, SAbs);
39 0 : fIntrinsicMap[String("sign")] = BY_TYPE_GLSL(FSign, SSign, SSign);
40 0 : fIntrinsicMap[String("floor")] = ALL_GLSL(Floor);
41 0 : fIntrinsicMap[String("ceil")] = ALL_GLSL(Ceil);
42 0 : fIntrinsicMap[String("fract")] = ALL_GLSL(Fract);
43 0 : fIntrinsicMap[String("radians")] = ALL_GLSL(Radians);
44 0 : fIntrinsicMap[String("degrees")] = ALL_GLSL(Degrees);
45 0 : fIntrinsicMap[String("sin")] = ALL_GLSL(Sin);
46 0 : fIntrinsicMap[String("cos")] = ALL_GLSL(Cos);
47 0 : fIntrinsicMap[String("tan")] = ALL_GLSL(Tan);
48 0 : fIntrinsicMap[String("asin")] = ALL_GLSL(Asin);
49 0 : fIntrinsicMap[String("acos")] = ALL_GLSL(Acos);
50 0 : fIntrinsicMap[String("atan")] = SPECIAL(Atan);
51 0 : fIntrinsicMap[String("sinh")] = ALL_GLSL(Sinh);
52 0 : fIntrinsicMap[String("cosh")] = ALL_GLSL(Cosh);
53 0 : fIntrinsicMap[String("tanh")] = ALL_GLSL(Tanh);
54 0 : fIntrinsicMap[String("asinh")] = ALL_GLSL(Asinh);
55 0 : fIntrinsicMap[String("acosh")] = ALL_GLSL(Acosh);
56 0 : fIntrinsicMap[String("atanh")] = ALL_GLSL(Atanh);
57 0 : fIntrinsicMap[String("pow")] = ALL_GLSL(Pow);
58 0 : fIntrinsicMap[String("exp")] = ALL_GLSL(Exp);
59 0 : fIntrinsicMap[String("log")] = ALL_GLSL(Log);
60 0 : fIntrinsicMap[String("exp2")] = ALL_GLSL(Exp2);
61 0 : fIntrinsicMap[String("log2")] = ALL_GLSL(Log2);
62 0 : fIntrinsicMap[String("sqrt")] = ALL_GLSL(Sqrt);
63 0 : fIntrinsicMap[String("inversesqrt")] = ALL_GLSL(InverseSqrt);
64 0 : fIntrinsicMap[String("determinant")] = ALL_GLSL(Determinant);
65 0 : fIntrinsicMap[String("matrixInverse")] = ALL_GLSL(MatrixInverse);
66 0 : fIntrinsicMap[String("mod")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpFMod,
67 0 : SpvOpSMod, SpvOpUMod, SpvOpUndef);
68 0 : fIntrinsicMap[String("min")] = BY_TYPE_GLSL(FMin, SMin, UMin);
69 0 : fIntrinsicMap[String("max")] = BY_TYPE_GLSL(FMax, SMax, UMax);
70 0 : fIntrinsicMap[String("clamp")] = BY_TYPE_GLSL(FClamp, SClamp, UClamp);
71 0 : fIntrinsicMap[String("dot")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDot,
72 0 : SpvOpUndef, SpvOpUndef, SpvOpUndef);
73 0 : fIntrinsicMap[String("mix")] = ALL_GLSL(FMix);
74 0 : fIntrinsicMap[String("step")] = ALL_GLSL(Step);
75 0 : fIntrinsicMap[String("smoothstep")] = ALL_GLSL(SmoothStep);
76 0 : fIntrinsicMap[String("fma")] = ALL_GLSL(Fma);
77 0 : fIntrinsicMap[String("frexp")] = ALL_GLSL(Frexp);
78 0 : fIntrinsicMap[String("ldexp")] = ALL_GLSL(Ldexp);
79 :
80 : #define PACK(type) fIntrinsicMap[String("pack" #type)] = ALL_GLSL(Pack ## type); \
81 : fIntrinsicMap[String("unpack" #type)] = ALL_GLSL(Unpack ## type)
82 0 : PACK(Snorm4x8);
83 0 : PACK(Unorm4x8);
84 0 : PACK(Snorm2x16);
85 0 : PACK(Unorm2x16);
86 0 : PACK(Half2x16);
87 0 : PACK(Double2x32);
88 0 : fIntrinsicMap[String("length")] = ALL_GLSL(Length);
89 0 : fIntrinsicMap[String("distance")] = ALL_GLSL(Distance);
90 0 : fIntrinsicMap[String("cross")] = ALL_GLSL(Cross);
91 0 : fIntrinsicMap[String("normalize")] = ALL_GLSL(Normalize);
92 0 : fIntrinsicMap[String("faceForward")] = ALL_GLSL(FaceForward);
93 0 : fIntrinsicMap[String("reflect")] = ALL_GLSL(Reflect);
94 0 : fIntrinsicMap[String("refract")] = ALL_GLSL(Refract);
95 0 : fIntrinsicMap[String("findLSB")] = ALL_GLSL(FindILsb);
96 0 : fIntrinsicMap[String("findMSB")] = BY_TYPE_GLSL(FindSMsb, FindSMsb, FindUMsb);
97 0 : fIntrinsicMap[String("dFdx")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdx,
98 0 : SpvOpUndef, SpvOpUndef, SpvOpUndef);
99 0 : fIntrinsicMap[String("dFdy")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdy,
100 0 : SpvOpUndef, SpvOpUndef, SpvOpUndef);
101 0 : fIntrinsicMap[String("dFdy")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdy,
102 0 : SpvOpUndef, SpvOpUndef, SpvOpUndef);
103 0 : fIntrinsicMap[String("texture")] = SPECIAL(Texture);
104 :
105 0 : fIntrinsicMap[String("subpassLoad")] = SPECIAL(SubpassLoad);
106 :
107 0 : fIntrinsicMap[String("any")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
108 0 : SpvOpUndef, SpvOpUndef, SpvOpAny);
109 0 : fIntrinsicMap[String("all")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
110 0 : SpvOpUndef, SpvOpUndef, SpvOpAll);
111 0 : fIntrinsicMap[String("equal")] = std::make_tuple(kSPIRV_IntrinsicKind,
112 : SpvOpFOrdEqual, SpvOpIEqual,
113 0 : SpvOpIEqual, SpvOpLogicalEqual);
114 0 : fIntrinsicMap[String("notEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
115 : SpvOpFOrdNotEqual, SpvOpINotEqual,
116 : SpvOpINotEqual,
117 0 : SpvOpLogicalNotEqual);
118 0 : fIntrinsicMap[String("lessThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
119 : SpvOpSLessThan, SpvOpULessThan,
120 0 : SpvOpFOrdLessThan, SpvOpUndef);
121 0 : fIntrinsicMap[String("lessThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
122 : SpvOpSLessThanEqual,
123 : SpvOpULessThanEqual,
124 : SpvOpFOrdLessThanEqual,
125 0 : SpvOpUndef);
126 0 : fIntrinsicMap[String("greaterThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
127 : SpvOpSGreaterThan,
128 : SpvOpUGreaterThan,
129 : SpvOpFOrdGreaterThan,
130 0 : SpvOpUndef);
131 0 : fIntrinsicMap[String("greaterThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
132 : SpvOpSGreaterThanEqual,
133 : SpvOpUGreaterThanEqual,
134 : SpvOpFOrdGreaterThanEqual,
135 0 : SpvOpUndef);
136 : // interpolateAt* not yet supported...
137 0 : }
138 :
139 0 : void SPIRVCodeGenerator::writeWord(int32_t word, OutputStream& out) {
140 : #if SPIRV_DEBUG
141 : out << "(" << word << ") ";
142 : #else
143 0 : out.write((const char*) &word, sizeof(word));
144 : #endif
145 0 : }
146 :
147 0 : static bool is_float(const Context& context, const Type& type) {
148 0 : if (type.kind() == Type::kVector_Kind) {
149 0 : return is_float(context, type.componentType());
150 : }
151 0 : return type == *context.fFloat_Type || type == *context.fDouble_Type;
152 : }
153 :
154 0 : static bool is_signed(const Context& context, const Type& type) {
155 0 : if (type.kind() == Type::kVector_Kind) {
156 0 : return is_signed(context, type.componentType());
157 : }
158 0 : return type == *context.fInt_Type;
159 : }
160 :
161 0 : static bool is_unsigned(const Context& context, const Type& type) {
162 0 : if (type.kind() == Type::kVector_Kind) {
163 0 : return is_unsigned(context, type.componentType());
164 : }
165 0 : return type == *context.fUInt_Type;
166 : }
167 :
168 0 : static bool is_bool(const Context& context, const Type& type) {
169 0 : if (type.kind() == Type::kVector_Kind) {
170 0 : return is_bool(context, type.componentType());
171 : }
172 0 : return type == *context.fBool_Type;
173 : }
174 :
175 0 : static bool is_out(const Variable& var) {
176 0 : return (var.fModifiers.fFlags & Modifiers::kOut_Flag) != 0;
177 : }
178 :
179 : #if SPIRV_DEBUG
180 : static String opcode_text(SpvOp_ opCode) {
181 : switch (opCode) {
182 : case SpvOpNop:
183 : return String("Nop");
184 : case SpvOpUndef:
185 : return String("Undef");
186 : case SpvOpSourceContinued:
187 : return String("SourceContinued");
188 : case SpvOpSource:
189 : return String("Source");
190 : case SpvOpSourceExtension:
191 : return String("SourceExtension");
192 : case SpvOpName:
193 : return String("Name");
194 : case SpvOpMemberName:
195 : return String("MemberName");
196 : case SpvOpString:
197 : return String("String");
198 : case SpvOpLine:
199 : return String("Line");
200 : case SpvOpExtension:
201 : return String("Extension");
202 : case SpvOpExtInstImport:
203 : return String("ExtInstImport");
204 : case SpvOpExtInst:
205 : return String("ExtInst");
206 : case SpvOpMemoryModel:
207 : return String("MemoryModel");
208 : case SpvOpEntryPoint:
209 : return String("EntryPoint");
210 : case SpvOpExecutionMode:
211 : return String("ExecutionMode");
212 : case SpvOpCapability:
213 : return String("Capability");
214 : case SpvOpTypeVoid:
215 : return String("TypeVoid");
216 : case SpvOpTypeBool:
217 : return String("TypeBool");
218 : case SpvOpTypeInt:
219 : return String("TypeInt");
220 : case SpvOpTypeFloat:
221 : return String("TypeFloat");
222 : case SpvOpTypeVector:
223 : return String("TypeVector");
224 : case SpvOpTypeMatrix:
225 : return String("TypeMatrix");
226 : case SpvOpTypeImage:
227 : return String("TypeImage");
228 : case SpvOpTypeSampler:
229 : return String("TypeSampler");
230 : case SpvOpTypeSampledImage:
231 : return String("TypeSampledImage");
232 : case SpvOpTypeArray:
233 : return String("TypeArray");
234 : case SpvOpTypeRuntimeArray:
235 : return String("TypeRuntimeArray");
236 : case SpvOpTypeStruct:
237 : return String("TypeStruct");
238 : case SpvOpTypeOpaque:
239 : return String("TypeOpaque");
240 : case SpvOpTypePointer:
241 : return String("TypePointer");
242 : case SpvOpTypeFunction:
243 : return String("TypeFunction");
244 : case SpvOpTypeEvent:
245 : return String("TypeEvent");
246 : case SpvOpTypeDeviceEvent:
247 : return String("TypeDeviceEvent");
248 : case SpvOpTypeReserveId:
249 : return String("TypeReserveId");
250 : case SpvOpTypeQueue:
251 : return String("TypeQueue");
252 : case SpvOpTypePipe:
253 : return String("TypePipe");
254 : case SpvOpTypeForwardPointer:
255 : return String("TypeForwardPointer");
256 : case SpvOpConstantTrue:
257 : return String("ConstantTrue");
258 : case SpvOpConstantFalse:
259 : return String("ConstantFalse");
260 : case SpvOpConstant:
261 : return String("Constant");
262 : case SpvOpConstantComposite:
263 : return String("ConstantComposite");
264 : case SpvOpConstantSampler:
265 : return String("ConstantSampler");
266 : case SpvOpConstantNull:
267 : return String("ConstantNull");
268 : case SpvOpSpecConstantTrue:
269 : return String("SpecConstantTrue");
270 : case SpvOpSpecConstantFalse:
271 : return String("SpecConstantFalse");
272 : case SpvOpSpecConstant:
273 : return String("SpecConstant");
274 : case SpvOpSpecConstantComposite:
275 : return String("SpecConstantComposite");
276 : case SpvOpSpecConstantOp:
277 : return String("SpecConstantOp");
278 : case SpvOpFunction:
279 : return String("Function");
280 : case SpvOpFunctionParameter:
281 : return String("FunctionParameter");
282 : case SpvOpFunctionEnd:
283 : return String("FunctionEnd");
284 : case SpvOpFunctionCall:
285 : return String("FunctionCall");
286 : case SpvOpVariable:
287 : return String("Variable");
288 : case SpvOpImageTexelPointer:
289 : return String("ImageTexelPointer");
290 : case SpvOpLoad:
291 : return String("Load");
292 : case SpvOpStore:
293 : return String("Store");
294 : case SpvOpCopyMemory:
295 : return String("CopyMemory");
296 : case SpvOpCopyMemorySized:
297 : return String("CopyMemorySized");
298 : case SpvOpAccessChain:
299 : return String("AccessChain");
300 : case SpvOpInBoundsAccessChain:
301 : return String("InBoundsAccessChain");
302 : case SpvOpPtrAccessChain:
303 : return String("PtrAccessChain");
304 : case SpvOpArrayLength:
305 : return String("ArrayLength");
306 : case SpvOpGenericPtrMemSemantics:
307 : return String("GenericPtrMemSemantics");
308 : case SpvOpInBoundsPtrAccessChain:
309 : return String("InBoundsPtrAccessChain");
310 : case SpvOpDecorate:
311 : return String("Decorate");
312 : case SpvOpMemberDecorate:
313 : return String("MemberDecorate");
314 : case SpvOpDecorationGroup:
315 : return String("DecorationGroup");
316 : case SpvOpGroupDecorate:
317 : return String("GroupDecorate");
318 : case SpvOpGroupMemberDecorate:
319 : return String("GroupMemberDecorate");
320 : case SpvOpVectorExtractDynamic:
321 : return String("VectorExtractDynamic");
322 : case SpvOpVectorInsertDynamic:
323 : return String("VectorInsertDynamic");
324 : case SpvOpVectorShuffle:
325 : return String("VectorShuffle");
326 : case SpvOpCompositeConstruct:
327 : return String("CompositeConstruct");
328 : case SpvOpCompositeExtract:
329 : return String("CompositeExtract");
330 : case SpvOpCompositeInsert:
331 : return String("CompositeInsert");
332 : case SpvOpCopyObject:
333 : return String("CopyObject");
334 : case SpvOpTranspose:
335 : return String("Transpose");
336 : case SpvOpSampledImage:
337 : return String("SampledImage");
338 : case SpvOpImageSampleImplicitLod:
339 : return String("ImageSampleImplicitLod");
340 : case SpvOpImageSampleExplicitLod:
341 : return String("ImageSampleExplicitLod");
342 : case SpvOpImageSampleDrefImplicitLod:
343 : return String("ImageSampleDrefImplicitLod");
344 : case SpvOpImageSampleDrefExplicitLod:
345 : return String("ImageSampleDrefExplicitLod");
346 : case SpvOpImageSampleProjImplicitLod:
347 : return String("ImageSampleProjImplicitLod");
348 : case SpvOpImageSampleProjExplicitLod:
349 : return String("ImageSampleProjExplicitLod");
350 : case SpvOpImageSampleProjDrefImplicitLod:
351 : return String("ImageSampleProjDrefImplicitLod");
352 : case SpvOpImageSampleProjDrefExplicitLod:
353 : return String("ImageSampleProjDrefExplicitLod");
354 : case SpvOpImageFetch:
355 : return String("ImageFetch");
356 : case SpvOpImageGather:
357 : return String("ImageGather");
358 : case SpvOpImageDrefGather:
359 : return String("ImageDrefGather");
360 : case SpvOpImageRead:
361 : return String("ImageRead");
362 : case SpvOpImageWrite:
363 : return String("ImageWrite");
364 : case SpvOpImage:
365 : return String("Image");
366 : case SpvOpImageQueryFormat:
367 : return String("ImageQueryFormat");
368 : case SpvOpImageQueryOrder:
369 : return String("ImageQueryOrder");
370 : case SpvOpImageQuerySizeLod:
371 : return String("ImageQuerySizeLod");
372 : case SpvOpImageQuerySize:
373 : return String("ImageQuerySize");
374 : case SpvOpImageQueryLod:
375 : return String("ImageQueryLod");
376 : case SpvOpImageQueryLevels:
377 : return String("ImageQueryLevels");
378 : case SpvOpImageQuerySamples:
379 : return String("ImageQuerySamples");
380 : case SpvOpConvertFToU:
381 : return String("ConvertFToU");
382 : case SpvOpConvertFToS:
383 : return String("ConvertFToS");
384 : case SpvOpConvertSToF:
385 : return String("ConvertSToF");
386 : case SpvOpConvertUToF:
387 : return String("ConvertUToF");
388 : case SpvOpUConvert:
389 : return String("UConvert");
390 : case SpvOpSConvert:
391 : return String("SConvert");
392 : case SpvOpFConvert:
393 : return String("FConvert");
394 : case SpvOpQuantizeToF16:
395 : return String("QuantizeToF16");
396 : case SpvOpConvertPtrToU:
397 : return String("ConvertPtrToU");
398 : case SpvOpSatConvertSToU:
399 : return String("SatConvertSToU");
400 : case SpvOpSatConvertUToS:
401 : return String("SatConvertUToS");
402 : case SpvOpConvertUToPtr:
403 : return String("ConvertUToPtr");
404 : case SpvOpPtrCastToGeneric:
405 : return String("PtrCastToGeneric");
406 : case SpvOpGenericCastToPtr:
407 : return String("GenericCastToPtr");
408 : case SpvOpGenericCastToPtrExplicit:
409 : return String("GenericCastToPtrExplicit");
410 : case SpvOpBitcast:
411 : return String("Bitcast");
412 : case SpvOpSNegate:
413 : return String("SNegate");
414 : case SpvOpFNegate:
415 : return String("FNegate");
416 : case SpvOpIAdd:
417 : return String("IAdd");
418 : case SpvOpFAdd:
419 : return String("FAdd");
420 : case SpvOpISub:
421 : return String("ISub");
422 : case SpvOpFSub:
423 : return String("FSub");
424 : case SpvOpIMul:
425 : return String("IMul");
426 : case SpvOpFMul:
427 : return String("FMul");
428 : case SpvOpUDiv:
429 : return String("UDiv");
430 : case SpvOpSDiv:
431 : return String("SDiv");
432 : case SpvOpFDiv:
433 : return String("FDiv");
434 : case SpvOpUMod:
435 : return String("UMod");
436 : case SpvOpSRem:
437 : return String("SRem");
438 : case SpvOpSMod:
439 : return String("SMod");
440 : case SpvOpFRem:
441 : return String("FRem");
442 : case SpvOpFMod:
443 : return String("FMod");
444 : case SpvOpVectorTimesScalar:
445 : return String("VectorTimesScalar");
446 : case SpvOpMatrixTimesScalar:
447 : return String("MatrixTimesScalar");
448 : case SpvOpVectorTimesMatrix:
449 : return String("VectorTimesMatrix");
450 : case SpvOpMatrixTimesVector:
451 : return String("MatrixTimesVector");
452 : case SpvOpMatrixTimesMatrix:
453 : return String("MatrixTimesMatrix");
454 : case SpvOpOuterProduct:
455 : return String("OuterProduct");
456 : case SpvOpDot:
457 : return String("Dot");
458 : case SpvOpIAddCarry:
459 : return String("IAddCarry");
460 : case SpvOpISubBorrow:
461 : return String("ISubBorrow");
462 : case SpvOpUMulExtended:
463 : return String("UMulExtended");
464 : case SpvOpSMulExtended:
465 : return String("SMulExtended");
466 : case SpvOpAny:
467 : return String("Any");
468 : case SpvOpAll:
469 : return String("All");
470 : case SpvOpIsNan:
471 : return String("IsNan");
472 : case SpvOpIsInf:
473 : return String("IsInf");
474 : case SpvOpIsFinite:
475 : return String("IsFinite");
476 : case SpvOpIsNormal:
477 : return String("IsNormal");
478 : case SpvOpSignBitSet:
479 : return String("SignBitSet");
480 : case SpvOpLessOrGreater:
481 : return String("LessOrGreater");
482 : case SpvOpOrdered:
483 : return String("Ordered");
484 : case SpvOpUnordered:
485 : return String("Unordered");
486 : case SpvOpLogicalEqual:
487 : return String("LogicalEqual");
488 : case SpvOpLogicalNotEqual:
489 : return String("LogicalNotEqual");
490 : case SpvOpLogicalOr:
491 : return String("LogicalOr");
492 : case SpvOpLogicalAnd:
493 : return String("LogicalAnd");
494 : case SpvOpLogicalNot:
495 : return String("LogicalNot");
496 : case SpvOpSelect:
497 : return String("Select");
498 : case SpvOpIEqual:
499 : return String("IEqual");
500 : case SpvOpINotEqual:
501 : return String("INotEqual");
502 : case SpvOpUGreaterThan:
503 : return String("UGreaterThan");
504 : case SpvOpSGreaterThan:
505 : return String("SGreaterThan");
506 : case SpvOpUGreaterThanEqual:
507 : return String("UGreaterThanEqual");
508 : case SpvOpSGreaterThanEqual:
509 : return String("SGreaterThanEqual");
510 : case SpvOpULessThan:
511 : return String("ULessThan");
512 : case SpvOpSLessThan:
513 : return String("SLessThan");
514 : case SpvOpULessThanEqual:
515 : return String("ULessThanEqual");
516 : case SpvOpSLessThanEqual:
517 : return String("SLessThanEqual");
518 : case SpvOpFOrdEqual:
519 : return String("FOrdEqual");
520 : case SpvOpFUnordEqual:
521 : return String("FUnordEqual");
522 : case SpvOpFOrdNotEqual:
523 : return String("FOrdNotEqual");
524 : case SpvOpFUnordNotEqual:
525 : return String("FUnordNotEqual");
526 : case SpvOpFOrdLessThan:
527 : return String("FOrdLessThan");
528 : case SpvOpFUnordLessThan:
529 : return String("FUnordLessThan");
530 : case SpvOpFOrdGreaterThan:
531 : return String("FOrdGreaterThan");
532 : case SpvOpFUnordGreaterThan:
533 : return String("FUnordGreaterThan");
534 : case SpvOpFOrdLessThanEqual:
535 : return String("FOrdLessThanEqual");
536 : case SpvOpFUnordLessThanEqual:
537 : return String("FUnordLessThanEqual");
538 : case SpvOpFOrdGreaterThanEqual:
539 : return String("FOrdGreaterThanEqual");
540 : case SpvOpFUnordGreaterThanEqual:
541 : return String("FUnordGreaterThanEqual");
542 : case SpvOpShiftRightLogical:
543 : return String("ShiftRightLogical");
544 : case SpvOpShiftRightArithmetic:
545 : return String("ShiftRightArithmetic");
546 : case SpvOpShiftLeftLogical:
547 : return String("ShiftLeftLogical");
548 : case SpvOpBitwiseOr:
549 : return String("BitwiseOr");
550 : case SpvOpBitwiseXor:
551 : return String("BitwiseXor");
552 : case SpvOpBitwiseAnd:
553 : return String("BitwiseAnd");
554 : case SpvOpNot:
555 : return String("Not");
556 : case SpvOpBitFieldInsert:
557 : return String("BitFieldInsert");
558 : case SpvOpBitFieldSExtract:
559 : return String("BitFieldSExtract");
560 : case SpvOpBitFieldUExtract:
561 : return String("BitFieldUExtract");
562 : case SpvOpBitReverse:
563 : return String("BitReverse");
564 : case SpvOpBitCount:
565 : return String("BitCount");
566 : case SpvOpDPdx:
567 : return String("DPdx");
568 : case SpvOpDPdy:
569 : return String("DPdy");
570 : case SpvOpFwidth:
571 : return String("Fwidth");
572 : case SpvOpDPdxFine:
573 : return String("DPdxFine");
574 : case SpvOpDPdyFine:
575 : return String("DPdyFine");
576 : case SpvOpFwidthFine:
577 : return String("FwidthFine");
578 : case SpvOpDPdxCoarse:
579 : return String("DPdxCoarse");
580 : case SpvOpDPdyCoarse:
581 : return String("DPdyCoarse");
582 : case SpvOpFwidthCoarse:
583 : return String("FwidthCoarse");
584 : case SpvOpEmitVertex:
585 : return String("EmitVertex");
586 : case SpvOpEndPrimitive:
587 : return String("EndPrimitive");
588 : case SpvOpEmitStreamVertex:
589 : return String("EmitStreamVertex");
590 : case SpvOpEndStreamPrimitive:
591 : return String("EndStreamPrimitive");
592 : case SpvOpControlBarrier:
593 : return String("ControlBarrier");
594 : case SpvOpMemoryBarrier:
595 : return String("MemoryBarrier");
596 : case SpvOpAtomicLoad:
597 : return String("AtomicLoad");
598 : case SpvOpAtomicStore:
599 : return String("AtomicStore");
600 : case SpvOpAtomicExchange:
601 : return String("AtomicExchange");
602 : case SpvOpAtomicCompareExchange:
603 : return String("AtomicCompareExchange");
604 : case SpvOpAtomicCompareExchangeWeak:
605 : return String("AtomicCompareExchangeWeak");
606 : case SpvOpAtomicIIncrement:
607 : return String("AtomicIIncrement");
608 : case SpvOpAtomicIDecrement:
609 : return String("AtomicIDecrement");
610 : case SpvOpAtomicIAdd:
611 : return String("AtomicIAdd");
612 : case SpvOpAtomicISub:
613 : return String("AtomicISub");
614 : case SpvOpAtomicSMin:
615 : return String("AtomicSMin");
616 : case SpvOpAtomicUMin:
617 : return String("AtomicUMin");
618 : case SpvOpAtomicSMax:
619 : return String("AtomicSMax");
620 : case SpvOpAtomicUMax:
621 : return String("AtomicUMax");
622 : case SpvOpAtomicAnd:
623 : return String("AtomicAnd");
624 : case SpvOpAtomicOr:
625 : return String("AtomicOr");
626 : case SpvOpAtomicXor:
627 : return String("AtomicXor");
628 : case SpvOpPhi:
629 : return String("Phi");
630 : case SpvOpLoopMerge:
631 : return String("LoopMerge");
632 : case SpvOpSelectionMerge:
633 : return String("SelectionMerge");
634 : case SpvOpLabel:
635 : return String("Label");
636 : case SpvOpBranch:
637 : return String("Branch");
638 : case SpvOpBranchConditional:
639 : return String("BranchConditional");
640 : case SpvOpSwitch:
641 : return String("Switch");
642 : case SpvOpKill:
643 : return String("Kill");
644 : case SpvOpReturn:
645 : return String("Return");
646 : case SpvOpReturnValue:
647 : return String("ReturnValue");
648 : case SpvOpUnreachable:
649 : return String("Unreachable");
650 : case SpvOpLifetimeStart:
651 : return String("LifetimeStart");
652 : case SpvOpLifetimeStop:
653 : return String("LifetimeStop");
654 : case SpvOpGroupAsyncCopy:
655 : return String("GroupAsyncCopy");
656 : case SpvOpGroupWaitEvents:
657 : return String("GroupWaitEvents");
658 : case SpvOpGroupAll:
659 : return String("GroupAll");
660 : case SpvOpGroupAny:
661 : return String("GroupAny");
662 : case SpvOpGroupBroadcast:
663 : return String("GroupBroadcast");
664 : case SpvOpGroupIAdd:
665 : return String("GroupIAdd");
666 : case SpvOpGroupFAdd:
667 : return String("GroupFAdd");
668 : case SpvOpGroupFMin:
669 : return String("GroupFMin");
670 : case SpvOpGroupUMin:
671 : return String("GroupUMin");
672 : case SpvOpGroupSMin:
673 : return String("GroupSMin");
674 : case SpvOpGroupFMax:
675 : return String("GroupFMax");
676 : case SpvOpGroupUMax:
677 : return String("GroupUMax");
678 : case SpvOpGroupSMax:
679 : return String("GroupSMax");
680 : case SpvOpReadPipe:
681 : return String("ReadPipe");
682 : case SpvOpWritePipe:
683 : return String("WritePipe");
684 : case SpvOpReservedReadPipe:
685 : return String("ReservedReadPipe");
686 : case SpvOpReservedWritePipe:
687 : return String("ReservedWritePipe");
688 : case SpvOpReserveReadPipePackets:
689 : return String("ReserveReadPipePackets");
690 : case SpvOpReserveWritePipePackets:
691 : return String("ReserveWritePipePackets");
692 : case SpvOpCommitReadPipe:
693 : return String("CommitReadPipe");
694 : case SpvOpCommitWritePipe:
695 : return String("CommitWritePipe");
696 : case SpvOpIsValidReserveId:
697 : return String("IsValidReserveId");
698 : case SpvOpGetNumPipePackets:
699 : return String("GetNumPipePackets");
700 : case SpvOpGetMaxPipePackets:
701 : return String("GetMaxPipePackets");
702 : case SpvOpGroupReserveReadPipePackets:
703 : return String("GroupReserveReadPipePackets");
704 : case SpvOpGroupReserveWritePipePackets:
705 : return String("GroupReserveWritePipePackets");
706 : case SpvOpGroupCommitReadPipe:
707 : return String("GroupCommitReadPipe");
708 : case SpvOpGroupCommitWritePipe:
709 : return String("GroupCommitWritePipe");
710 : case SpvOpEnqueueMarker:
711 : return String("EnqueueMarker");
712 : case SpvOpEnqueueKernel:
713 : return String("EnqueueKernel");
714 : case SpvOpGetKernelNDrangeSubGroupCount:
715 : return String("GetKernelNDrangeSubGroupCount");
716 : case SpvOpGetKernelNDrangeMaxSubGroupSize:
717 : return String("GetKernelNDrangeMaxSubGroupSize");
718 : case SpvOpGetKernelWorkGroupSize:
719 : return String("GetKernelWorkGroupSize");
720 : case SpvOpGetKernelPreferredWorkGroupSizeMultiple:
721 : return String("GetKernelPreferredWorkGroupSizeMultiple");
722 : case SpvOpRetainEvent:
723 : return String("RetainEvent");
724 : case SpvOpReleaseEvent:
725 : return String("ReleaseEvent");
726 : case SpvOpCreateUserEvent:
727 : return String("CreateUserEvent");
728 : case SpvOpIsValidEvent:
729 : return String("IsValidEvent");
730 : case SpvOpSetUserEventStatus:
731 : return String("SetUserEventStatus");
732 : case SpvOpCaptureEventProfilingInfo:
733 : return String("CaptureEventProfilingInfo");
734 : case SpvOpGetDefaultQueue:
735 : return String("GetDefaultQueue");
736 : case SpvOpBuildNDRange:
737 : return String("BuildNDRange");
738 : case SpvOpImageSparseSampleImplicitLod:
739 : return String("ImageSparseSampleImplicitLod");
740 : case SpvOpImageSparseSampleExplicitLod:
741 : return String("ImageSparseSampleExplicitLod");
742 : case SpvOpImageSparseSampleDrefImplicitLod:
743 : return String("ImageSparseSampleDrefImplicitLod");
744 : case SpvOpImageSparseSampleDrefExplicitLod:
745 : return String("ImageSparseSampleDrefExplicitLod");
746 : case SpvOpImageSparseSampleProjImplicitLod:
747 : return String("ImageSparseSampleProjImplicitLod");
748 : case SpvOpImageSparseSampleProjExplicitLod:
749 : return String("ImageSparseSampleProjExplicitLod");
750 : case SpvOpImageSparseSampleProjDrefImplicitLod:
751 : return String("ImageSparseSampleProjDrefImplicitLod");
752 : case SpvOpImageSparseSampleProjDrefExplicitLod:
753 : return String("ImageSparseSampleProjDrefExplicitLod");
754 : case SpvOpImageSparseFetch:
755 : return String("ImageSparseFetch");
756 : case SpvOpImageSparseGather:
757 : return String("ImageSparseGather");
758 : case SpvOpImageSparseDrefGather:
759 : return String("ImageSparseDrefGather");
760 : case SpvOpImageSparseTexelsResident:
761 : return String("ImageSparseTexelsResident");
762 : case SpvOpNoLine:
763 : return String("NoLine");
764 : case SpvOpAtomicFlagTestAndSet:
765 : return String("AtomicFlagTestAndSet");
766 : case SpvOpAtomicFlagClear:
767 : return String("AtomicFlagClear");
768 : case SpvOpImageSparseRead:
769 : return String("ImageSparseRead");
770 : default:
771 : ABORT("unsupported SPIR-V op");
772 : }
773 : }
774 : #endif
775 :
776 0 : void SPIRVCodeGenerator::writeOpCode(SpvOp_ opCode, int length, OutputStream& out) {
777 0 : ASSERT(opCode != SpvOpUndef);
778 0 : switch (opCode) {
779 : case SpvOpReturn: // fall through
780 : case SpvOpReturnValue: // fall through
781 : case SpvOpKill: // fall through
782 : case SpvOpBranch: // fall through
783 : case SpvOpBranchConditional:
784 0 : ASSERT(fCurrentBlock);
785 0 : fCurrentBlock = 0;
786 0 : break;
787 : case SpvOpConstant: // fall through
788 : case SpvOpConstantTrue: // fall through
789 : case SpvOpConstantFalse: // fall through
790 : case SpvOpConstantComposite: // fall through
791 : case SpvOpTypeVoid: // fall through
792 : case SpvOpTypeInt: // fall through
793 : case SpvOpTypeFloat: // fall through
794 : case SpvOpTypeBool: // fall through
795 : case SpvOpTypeVector: // fall through
796 : case SpvOpTypeMatrix: // fall through
797 : case SpvOpTypeArray: // fall through
798 : case SpvOpTypePointer: // fall through
799 : case SpvOpTypeFunction: // fall through
800 : case SpvOpTypeRuntimeArray: // fall through
801 : case SpvOpTypeStruct: // fall through
802 : case SpvOpTypeImage: // fall through
803 : case SpvOpTypeSampledImage: // fall through
804 : case SpvOpVariable: // fall through
805 : case SpvOpFunction: // fall through
806 : case SpvOpFunctionParameter: // fall through
807 : case SpvOpFunctionEnd: // fall through
808 : case SpvOpExecutionMode: // fall through
809 : case SpvOpMemoryModel: // fall through
810 : case SpvOpCapability: // fall through
811 : case SpvOpExtInstImport: // fall through
812 : case SpvOpEntryPoint: // fall through
813 : case SpvOpSource: // fall through
814 : case SpvOpSourceExtension: // fall through
815 : case SpvOpName: // fall through
816 : case SpvOpMemberName: // fall through
817 : case SpvOpDecorate: // fall through
818 : case SpvOpMemberDecorate:
819 0 : break;
820 : default:
821 0 : ASSERT(fCurrentBlock);
822 : }
823 : #if SPIRV_DEBUG
824 : out << std::endl << opcode_text(opCode) << " ";
825 : #else
826 0 : this->writeWord((length << 16) | opCode, out);
827 : #endif
828 0 : }
829 :
830 0 : void SPIRVCodeGenerator::writeLabel(SpvId label, OutputStream& out) {
831 0 : fCurrentBlock = label;
832 0 : this->writeInstruction(SpvOpLabel, label, out);
833 0 : }
834 :
835 0 : void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, OutputStream& out) {
836 0 : this->writeOpCode(opCode, 1, out);
837 0 : }
838 :
839 0 : void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, OutputStream& out) {
840 0 : this->writeOpCode(opCode, 2, out);
841 0 : this->writeWord(word1, out);
842 0 : }
843 :
844 0 : void SPIRVCodeGenerator::writeString(const char* string, OutputStream& out) {
845 0 : size_t length = strlen(string);
846 0 : out.write(string, length);
847 0 : switch (length % 4) {
848 : case 1:
849 0 : out.write8(0);
850 : // fall through
851 : case 2:
852 0 : out.write8(0);
853 : // fall through
854 : case 3:
855 0 : out.write8(0);
856 0 : break;
857 : default:
858 0 : this->writeWord(0, out);
859 : }
860 0 : }
861 :
862 0 : void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, const char* string, OutputStream& out) {
863 0 : int32_t length = (int32_t) strlen(string);
864 0 : this->writeOpCode(opCode, 1 + (length + 4) / 4, out);
865 0 : this->writeString(string, out);
866 0 : }
867 :
868 :
869 0 : void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, const char* string,
870 : OutputStream& out) {
871 0 : int32_t length = (int32_t) strlen(string);
872 0 : this->writeOpCode(opCode, 2 + (length + 4) / 4, out);
873 0 : this->writeWord(word1, out);
874 0 : this->writeString(string, out);
875 0 : }
876 :
877 0 : void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
878 : const char* string, OutputStream& out) {
879 0 : int32_t length = (int32_t) strlen(string);
880 0 : this->writeOpCode(opCode, 3 + (length + 4) / 4, out);
881 0 : this->writeWord(word1, out);
882 0 : this->writeWord(word2, out);
883 0 : this->writeString(string, out);
884 0 : }
885 :
886 0 : void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
887 : OutputStream& out) {
888 0 : this->writeOpCode(opCode, 3, out);
889 0 : this->writeWord(word1, out);
890 0 : this->writeWord(word2, out);
891 0 : }
892 :
893 0 : void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
894 : int32_t word3, OutputStream& out) {
895 0 : this->writeOpCode(opCode, 4, out);
896 0 : this->writeWord(word1, out);
897 0 : this->writeWord(word2, out);
898 0 : this->writeWord(word3, out);
899 0 : }
900 :
901 0 : void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
902 : int32_t word3, int32_t word4, OutputStream& out) {
903 0 : this->writeOpCode(opCode, 5, out);
904 0 : this->writeWord(word1, out);
905 0 : this->writeWord(word2, out);
906 0 : this->writeWord(word3, out);
907 0 : this->writeWord(word4, out);
908 0 : }
909 :
910 0 : void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
911 : int32_t word3, int32_t word4, int32_t word5,
912 : OutputStream& out) {
913 0 : this->writeOpCode(opCode, 6, out);
914 0 : this->writeWord(word1, out);
915 0 : this->writeWord(word2, out);
916 0 : this->writeWord(word3, out);
917 0 : this->writeWord(word4, out);
918 0 : this->writeWord(word5, out);
919 0 : }
920 :
921 0 : void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
922 : int32_t word3, int32_t word4, int32_t word5,
923 : int32_t word6, OutputStream& out) {
924 0 : this->writeOpCode(opCode, 7, out);
925 0 : this->writeWord(word1, out);
926 0 : this->writeWord(word2, out);
927 0 : this->writeWord(word3, out);
928 0 : this->writeWord(word4, out);
929 0 : this->writeWord(word5, out);
930 0 : this->writeWord(word6, out);
931 0 : }
932 :
933 0 : void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
934 : int32_t word3, int32_t word4, int32_t word5,
935 : int32_t word6, int32_t word7, OutputStream& out) {
936 0 : this->writeOpCode(opCode, 8, out);
937 0 : this->writeWord(word1, out);
938 0 : this->writeWord(word2, out);
939 0 : this->writeWord(word3, out);
940 0 : this->writeWord(word4, out);
941 0 : this->writeWord(word5, out);
942 0 : this->writeWord(word6, out);
943 0 : this->writeWord(word7, out);
944 0 : }
945 :
946 0 : void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
947 : int32_t word3, int32_t word4, int32_t word5,
948 : int32_t word6, int32_t word7, int32_t word8,
949 : OutputStream& out) {
950 0 : this->writeOpCode(opCode, 9, out);
951 0 : this->writeWord(word1, out);
952 0 : this->writeWord(word2, out);
953 0 : this->writeWord(word3, out);
954 0 : this->writeWord(word4, out);
955 0 : this->writeWord(word5, out);
956 0 : this->writeWord(word6, out);
957 0 : this->writeWord(word7, out);
958 0 : this->writeWord(word8, out);
959 0 : }
960 :
961 0 : void SPIRVCodeGenerator::writeCapabilities(OutputStream& out) {
962 0 : for (uint64_t i = 0, bit = 1; i <= kLast_Capability; i++, bit <<= 1) {
963 0 : if (fCapabilities & bit) {
964 0 : this->writeInstruction(SpvOpCapability, (SpvId) i, out);
965 : }
966 : }
967 0 : }
968 :
969 0 : SpvId SPIRVCodeGenerator::nextId() {
970 0 : return fIdCount++;
971 : }
972 :
973 0 : void SPIRVCodeGenerator::writeStruct(const Type& type, const MemoryLayout& memoryLayout,
974 : SpvId resultId) {
975 0 : this->writeInstruction(SpvOpName, resultId, type.name().c_str(), fNameBuffer);
976 : // go ahead and write all of the field types, so we don't inadvertently write them while we're
977 : // in the middle of writing the struct instruction
978 0 : std::vector<SpvId> types;
979 0 : for (const auto& f : type.fields()) {
980 0 : types.push_back(this->getType(*f.fType, memoryLayout));
981 : }
982 0 : this->writeOpCode(SpvOpTypeStruct, 2 + (int32_t) types.size(), fConstantBuffer);
983 0 : this->writeWord(resultId, fConstantBuffer);
984 0 : for (SpvId id : types) {
985 0 : this->writeWord(id, fConstantBuffer);
986 : }
987 0 : size_t offset = 0;
988 0 : for (int32_t i = 0; i < (int32_t) type.fields().size(); i++) {
989 0 : size_t size = memoryLayout.size(*type.fields()[i].fType);
990 0 : size_t alignment = memoryLayout.alignment(*type.fields()[i].fType);
991 0 : const Layout& fieldLayout = type.fields()[i].fModifiers.fLayout;
992 0 : if (fieldLayout.fOffset >= 0) {
993 0 : if (fieldLayout.fOffset < (int) offset) {
994 0 : fErrors.error(type.fPosition,
995 0 : "offset of field '" + type.fields()[i].fName + "' must be at "
996 0 : "least " + to_string((int) offset));
997 : }
998 0 : if (fieldLayout.fOffset % alignment) {
999 0 : fErrors.error(type.fPosition,
1000 0 : "offset of field '" + type.fields()[i].fName + "' must be a multiple"
1001 0 : " of " + to_string((int) alignment));
1002 : }
1003 0 : offset = fieldLayout.fOffset;
1004 : } else {
1005 0 : size_t mod = offset % alignment;
1006 0 : if (mod) {
1007 0 : offset += alignment - mod;
1008 : }
1009 : }
1010 0 : this->writeInstruction(SpvOpMemberName, resultId, i, type.fields()[i].fName.c_str(),
1011 0 : fNameBuffer);
1012 0 : this->writeLayout(fieldLayout, resultId, i);
1013 0 : if (type.fields()[i].fModifiers.fLayout.fBuiltin < 0) {
1014 0 : this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i, SpvDecorationOffset,
1015 0 : (SpvId) offset, fDecorationBuffer);
1016 : }
1017 0 : if (type.fields()[i].fType->kind() == Type::kMatrix_Kind) {
1018 0 : this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationColMajor,
1019 0 : fDecorationBuffer);
1020 0 : this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationMatrixStride,
1021 0 : (SpvId) memoryLayout.stride(*type.fields()[i].fType),
1022 0 : fDecorationBuffer);
1023 : }
1024 0 : offset += size;
1025 0 : Type::Kind kind = type.fields()[i].fType->kind();
1026 0 : if ((kind == Type::kArray_Kind || kind == Type::kStruct_Kind) && offset % alignment != 0) {
1027 0 : offset += alignment - offset % alignment;
1028 : }
1029 : }
1030 0 : }
1031 :
1032 0 : SpvId SPIRVCodeGenerator::getType(const Type& type) {
1033 0 : return this->getType(type, fDefaultLayout);
1034 : }
1035 :
1036 0 : SpvId SPIRVCodeGenerator::getType(const Type& type, const MemoryLayout& layout) {
1037 0 : String key = type.name() + to_string((int) layout.fStd);
1038 0 : auto entry = fTypeMap.find(key);
1039 0 : if (entry == fTypeMap.end()) {
1040 0 : SpvId result = this->nextId();
1041 0 : switch (type.kind()) {
1042 : case Type::kScalar_Kind:
1043 0 : if (type == *fContext.fBool_Type) {
1044 0 : this->writeInstruction(SpvOpTypeBool, result, fConstantBuffer);
1045 0 : } else if (type == *fContext.fInt_Type) {
1046 0 : this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
1047 0 : } else if (type == *fContext.fUInt_Type) {
1048 0 : this->writeInstruction(SpvOpTypeInt, result, 32, 0, fConstantBuffer);
1049 0 : } else if (type == *fContext.fFloat_Type) {
1050 0 : this->writeInstruction(SpvOpTypeFloat, result, 32, fConstantBuffer);
1051 0 : } else if (type == *fContext.fDouble_Type) {
1052 0 : this->writeInstruction(SpvOpTypeFloat, result, 64, fConstantBuffer);
1053 : } else {
1054 0 : ASSERT(false);
1055 : }
1056 0 : break;
1057 : case Type::kVector_Kind:
1058 0 : this->writeInstruction(SpvOpTypeVector, result,
1059 0 : this->getType(type.componentType(), layout),
1060 0 : type.columns(), fConstantBuffer);
1061 0 : break;
1062 : case Type::kMatrix_Kind:
1063 0 : this->writeInstruction(SpvOpTypeMatrix, result,
1064 0 : this->getType(index_type(fContext, type), layout),
1065 0 : type.columns(), fConstantBuffer);
1066 0 : break;
1067 : case Type::kStruct_Kind:
1068 0 : this->writeStruct(type, layout, result);
1069 0 : break;
1070 : case Type::kArray_Kind: {
1071 0 : if (type.columns() > 0) {
1072 0 : IntLiteral count(fContext, Position(), type.columns());
1073 0 : this->writeInstruction(SpvOpTypeArray, result,
1074 0 : this->getType(type.componentType(), layout),
1075 0 : this->writeIntLiteral(count), fConstantBuffer);
1076 0 : this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
1077 0 : (int32_t) layout.stride(type),
1078 0 : fDecorationBuffer);
1079 : } else {
1080 0 : ABORT("runtime-sized arrays are not yet supported");
1081 : this->writeInstruction(SpvOpTypeRuntimeArray, result,
1082 : this->getType(type.componentType(), layout),
1083 : fConstantBuffer);
1084 : }
1085 0 : break;
1086 : }
1087 : case Type::kSampler_Kind: {
1088 0 : SpvId image = result;
1089 0 : if (SpvDimSubpassData != type.dimensions()) {
1090 0 : image = this->nextId();
1091 : }
1092 0 : this->writeInstruction(SpvOpTypeImage, image,
1093 0 : this->getType(*fContext.fFloat_Type, layout),
1094 0 : type.dimensions(), type.isDepth(), type.isArrayed(),
1095 0 : type.isMultisampled(), type.isSampled() ? 1 : 2,
1096 0 : SpvImageFormatUnknown, fConstantBuffer);
1097 0 : if (SpvDimSubpassData != type.dimensions()) {
1098 0 : this->writeInstruction(SpvOpTypeSampledImage, result, image, fConstantBuffer);
1099 : }
1100 0 : break;
1101 : }
1102 : default:
1103 0 : if (type == *fContext.fVoid_Type) {
1104 0 : this->writeInstruction(SpvOpTypeVoid, result, fConstantBuffer);
1105 : } else {
1106 0 : ABORT("invalid type: %s", type.description().c_str());
1107 : }
1108 : }
1109 0 : fTypeMap[key] = result;
1110 0 : return result;
1111 : }
1112 0 : return entry->second;
1113 : }
1114 :
1115 0 : SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) {
1116 0 : String key = function.fReturnType.description() + "(";
1117 0 : String separator;
1118 0 : for (size_t i = 0; i < function.fParameters.size(); i++) {
1119 0 : key += separator;
1120 0 : separator = ", ";
1121 0 : key += function.fParameters[i]->fType.description();
1122 : }
1123 0 : key += ")";
1124 0 : auto entry = fTypeMap.find(key);
1125 0 : if (entry == fTypeMap.end()) {
1126 0 : SpvId result = this->nextId();
1127 0 : int32_t length = 3 + (int32_t) function.fParameters.size();
1128 0 : SpvId returnType = this->getType(function.fReturnType);
1129 0 : std::vector<SpvId> parameterTypes;
1130 0 : for (size_t i = 0; i < function.fParameters.size(); i++) {
1131 : // glslang seems to treat all function arguments as pointers whether they need to be or
1132 : // not. I was initially puzzled by this until I ran bizarre failures with certain
1133 : // patterns of function calls and control constructs, as exemplified by this minimal
1134 : // failure case:
1135 : //
1136 : // void sphere(float x) {
1137 : // }
1138 : //
1139 : // void map() {
1140 : // sphere(1.0);
1141 : // }
1142 : //
1143 : // void main() {
1144 : // for (int i = 0; i < 1; i++) {
1145 : // map();
1146 : // }
1147 : // }
1148 : //
1149 : // As of this writing, compiling this in the "obvious" way (with sphere taking a float)
1150 : // crashes. Making it take a float* and storing the argument in a temporary variable,
1151 : // as glslang does, fixes it. It's entirely possible I simply missed whichever part of
1152 : // the spec makes this make sense.
1153 : // if (is_out(function->fParameters[i])) {
1154 0 : parameterTypes.push_back(this->getPointerType(function.fParameters[i]->fType,
1155 0 : SpvStorageClassFunction));
1156 : // } else {
1157 : // parameterTypes.push_back(this->getType(function.fParameters[i]->fType));
1158 : // }
1159 : }
1160 0 : this->writeOpCode(SpvOpTypeFunction, length, fConstantBuffer);
1161 0 : this->writeWord(result, fConstantBuffer);
1162 0 : this->writeWord(returnType, fConstantBuffer);
1163 0 : for (SpvId id : parameterTypes) {
1164 0 : this->writeWord(id, fConstantBuffer);
1165 : }
1166 0 : fTypeMap[key] = result;
1167 0 : return result;
1168 : }
1169 0 : return entry->second;
1170 : }
1171 :
1172 0 : SpvId SPIRVCodeGenerator::getPointerType(const Type& type, SpvStorageClass_ storageClass) {
1173 0 : return this->getPointerType(type, fDefaultLayout, storageClass);
1174 : }
1175 :
1176 0 : SpvId SPIRVCodeGenerator::getPointerType(const Type& type, const MemoryLayout& layout,
1177 : SpvStorageClass_ storageClass) {
1178 0 : String key = type.description() + "*" + to_string(layout.fStd) + to_string(storageClass);
1179 0 : auto entry = fTypeMap.find(key);
1180 0 : if (entry == fTypeMap.end()) {
1181 0 : SpvId result = this->nextId();
1182 0 : this->writeInstruction(SpvOpTypePointer, result, storageClass,
1183 0 : this->getType(type), fConstantBuffer);
1184 0 : fTypeMap[key] = result;
1185 0 : return result;
1186 : }
1187 0 : return entry->second;
1188 : }
1189 :
1190 0 : SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, OutputStream& out) {
1191 0 : switch (expr.fKind) {
1192 : case Expression::kBinary_Kind:
1193 0 : return this->writeBinaryExpression((BinaryExpression&) expr, out);
1194 : case Expression::kBoolLiteral_Kind:
1195 0 : return this->writeBoolLiteral((BoolLiteral&) expr);
1196 : case Expression::kConstructor_Kind:
1197 0 : return this->writeConstructor((Constructor&) expr, out);
1198 : case Expression::kIntLiteral_Kind:
1199 0 : return this->writeIntLiteral((IntLiteral&) expr);
1200 : case Expression::kFieldAccess_Kind:
1201 0 : return this->writeFieldAccess(((FieldAccess&) expr), out);
1202 : case Expression::kFloatLiteral_Kind:
1203 0 : return this->writeFloatLiteral(((FloatLiteral&) expr));
1204 : case Expression::kFunctionCall_Kind:
1205 0 : return this->writeFunctionCall((FunctionCall&) expr, out);
1206 : case Expression::kPrefix_Kind:
1207 0 : return this->writePrefixExpression((PrefixExpression&) expr, out);
1208 : case Expression::kPostfix_Kind:
1209 0 : return this->writePostfixExpression((PostfixExpression&) expr, out);
1210 : case Expression::kSwizzle_Kind:
1211 0 : return this->writeSwizzle((Swizzle&) expr, out);
1212 : case Expression::kVariableReference_Kind:
1213 0 : return this->writeVariableReference((VariableReference&) expr, out);
1214 : case Expression::kTernary_Kind:
1215 0 : return this->writeTernaryExpression((TernaryExpression&) expr, out);
1216 : case Expression::kIndex_Kind:
1217 0 : return this->writeIndexExpression((IndexExpression&) expr, out);
1218 : default:
1219 0 : ABORT("unsupported expression: %s", expr.description().c_str());
1220 : }
1221 : return -1;
1222 : }
1223 :
1224 0 : SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, OutputStream& out) {
1225 0 : auto intrinsic = fIntrinsicMap.find(c.fFunction.fName);
1226 0 : ASSERT(intrinsic != fIntrinsicMap.end());
1227 0 : const Type& type = c.fArguments[0]->fType;
1228 : int32_t intrinsicId;
1229 0 : if (std::get<0>(intrinsic->second) == kSpecial_IntrinsicKind || is_float(fContext, type)) {
1230 0 : intrinsicId = std::get<1>(intrinsic->second);
1231 0 : } else if (is_signed(fContext, type)) {
1232 0 : intrinsicId = std::get<2>(intrinsic->second);
1233 0 : } else if (is_unsigned(fContext, type)) {
1234 0 : intrinsicId = std::get<3>(intrinsic->second);
1235 0 : } else if (is_bool(fContext, type)) {
1236 0 : intrinsicId = std::get<4>(intrinsic->second);
1237 : } else {
1238 0 : ABORT("invalid call %s, cannot operate on '%s'", c.description().c_str(),
1239 0 : type.description().c_str());
1240 : }
1241 0 : switch (std::get<0>(intrinsic->second)) {
1242 : case kGLSL_STD_450_IntrinsicKind: {
1243 0 : SpvId result = this->nextId();
1244 0 : std::vector<SpvId> arguments;
1245 0 : for (size_t i = 0; i < c.fArguments.size(); i++) {
1246 0 : arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1247 : }
1248 0 : this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
1249 0 : this->writeWord(this->getType(c.fType), out);
1250 0 : this->writeWord(result, out);
1251 0 : this->writeWord(fGLSLExtendedInstructions, out);
1252 0 : this->writeWord(intrinsicId, out);
1253 0 : for (SpvId id : arguments) {
1254 0 : this->writeWord(id, out);
1255 : }
1256 0 : return result;
1257 : }
1258 : case kSPIRV_IntrinsicKind: {
1259 0 : SpvId result = this->nextId();
1260 0 : std::vector<SpvId> arguments;
1261 0 : for (size_t i = 0; i < c.fArguments.size(); i++) {
1262 0 : arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1263 : }
1264 0 : this->writeOpCode((SpvOp_) intrinsicId, 3 + (int32_t) arguments.size(), out);
1265 0 : this->writeWord(this->getType(c.fType), out);
1266 0 : this->writeWord(result, out);
1267 0 : for (SpvId id : arguments) {
1268 0 : this->writeWord(id, out);
1269 : }
1270 0 : return result;
1271 : }
1272 : case kSpecial_IntrinsicKind:
1273 0 : return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId, out);
1274 : default:
1275 0 : ABORT("unsupported intrinsic kind");
1276 : }
1277 : }
1278 :
1279 0 : SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind,
1280 : OutputStream& out) {
1281 0 : SpvId result = this->nextId();
1282 0 : switch (kind) {
1283 : case kAtan_SpecialIntrinsic: {
1284 0 : std::vector<SpvId> arguments;
1285 0 : for (size_t i = 0; i < c.fArguments.size(); i++) {
1286 0 : arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1287 : }
1288 0 : this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
1289 0 : this->writeWord(this->getType(c.fType), out);
1290 0 : this->writeWord(result, out);
1291 0 : this->writeWord(fGLSLExtendedInstructions, out);
1292 0 : this->writeWord(arguments.size() == 2 ? GLSLstd450Atan2 : GLSLstd450Atan, out);
1293 0 : for (SpvId id : arguments) {
1294 0 : this->writeWord(id, out);
1295 : }
1296 0 : return result;
1297 : }
1298 : case kTexture_SpecialIntrinsic: {
1299 0 : SpvOp_ op = SpvOpImageSampleImplicitLod;
1300 0 : switch (c.fArguments[0]->fType.dimensions()) {
1301 : case SpvDim1D:
1302 0 : if (c.fArguments[1]->fType == *fContext.fVec2_Type) {
1303 0 : op = SpvOpImageSampleProjImplicitLod;
1304 : } else {
1305 0 : ASSERT(c.fArguments[1]->fType == *fContext.fFloat_Type);
1306 : }
1307 0 : break;
1308 : case SpvDim2D:
1309 0 : if (c.fArguments[1]->fType == *fContext.fVec3_Type) {
1310 0 : op = SpvOpImageSampleProjImplicitLod;
1311 : } else {
1312 0 : ASSERT(c.fArguments[1]->fType == *fContext.fVec2_Type);
1313 : }
1314 0 : break;
1315 : case SpvDim3D:
1316 0 : if (c.fArguments[1]->fType == *fContext.fVec4_Type) {
1317 0 : op = SpvOpImageSampleProjImplicitLod;
1318 : } else {
1319 0 : ASSERT(c.fArguments[1]->fType == *fContext.fVec3_Type);
1320 : }
1321 0 : break;
1322 : case SpvDimCube: // fall through
1323 : case SpvDimRect: // fall through
1324 : case SpvDimBuffer: // fall through
1325 : case SpvDimSubpassData:
1326 0 : break;
1327 : }
1328 0 : SpvId type = this->getType(c.fType);
1329 0 : SpvId sampler = this->writeExpression(*c.fArguments[0], out);
1330 0 : SpvId uv = this->writeExpression(*c.fArguments[1], out);
1331 0 : if (c.fArguments.size() == 3) {
1332 0 : this->writeInstruction(op, type, result, sampler, uv,
1333 : SpvImageOperandsBiasMask,
1334 0 : this->writeExpression(*c.fArguments[2], out),
1335 0 : out);
1336 : } else {
1337 0 : ASSERT(c.fArguments.size() == 2);
1338 0 : this->writeInstruction(op, type, result, sampler, uv,
1339 0 : out);
1340 : }
1341 0 : break;
1342 : }
1343 : case kSubpassLoad_SpecialIntrinsic: {
1344 0 : SpvId img = this->writeExpression(*c.fArguments[0], out);
1345 0 : std::vector<std::unique_ptr<Expression>> args;
1346 0 : args.emplace_back(new FloatLiteral(fContext, Position(), 0.0));
1347 0 : args.emplace_back(new FloatLiteral(fContext, Position(), 0.0));
1348 0 : Constructor ctor(Position(), *fContext.fVec2_Type, std::move(args));
1349 0 : SpvId coords = this->writeConstantVector(ctor);
1350 0 : if (1 == c.fArguments.size()) {
1351 0 : this->writeInstruction(SpvOpImageRead,
1352 0 : this->getType(c.fType),
1353 : result,
1354 : img,
1355 : coords,
1356 0 : out);
1357 : } else {
1358 0 : ASSERT(2 == c.fArguments.size());
1359 0 : SpvId sample = this->writeExpression(*c.fArguments[1], out);
1360 0 : this->writeInstruction(SpvOpImageRead,
1361 0 : this->getType(c.fType),
1362 : result,
1363 : img,
1364 : coords,
1365 : SpvImageOperandsSampleMask,
1366 : sample,
1367 0 : out);
1368 : }
1369 0 : break;
1370 : }
1371 : }
1372 0 : return result;
1373 : }
1374 :
1375 0 : SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, OutputStream& out) {
1376 0 : const auto& entry = fFunctionMap.find(&c.fFunction);
1377 0 : if (entry == fFunctionMap.end()) {
1378 0 : return this->writeIntrinsicCall(c, out);
1379 : }
1380 : // stores (variable, type, lvalue) pairs to extract and save after the function call is complete
1381 0 : std::vector<std::tuple<SpvId, SpvId, std::unique_ptr<LValue>>> lvalues;
1382 0 : std::vector<SpvId> arguments;
1383 0 : for (size_t i = 0; i < c.fArguments.size(); i++) {
1384 : // id of temporary variable that we will use to hold this argument, or 0 if it is being
1385 : // passed directly
1386 : SpvId tmpVar;
1387 : // if we need a temporary var to store this argument, this is the value to store in the var
1388 : SpvId tmpValueId;
1389 0 : if (is_out(*c.fFunction.fParameters[i])) {
1390 0 : std::unique_ptr<LValue> lv = this->getLValue(*c.fArguments[i], out);
1391 0 : SpvId ptr = lv->getPointer();
1392 0 : if (ptr) {
1393 0 : arguments.push_back(ptr);
1394 0 : continue;
1395 : } else {
1396 : // lvalue cannot simply be read and written via a pointer (e.g. a swizzle). Need to
1397 : // copy it into a temp, call the function, read the value out of the temp, and then
1398 : // update the lvalue.
1399 0 : tmpValueId = lv->load(out);
1400 0 : tmpVar = this->nextId();
1401 0 : lvalues.push_back(std::make_tuple(tmpVar, this->getType(c.fArguments[i]->fType),
1402 0 : std::move(lv)));
1403 : }
1404 : } else {
1405 : // see getFunctionType for an explanation of why we're always using pointer parameters
1406 0 : tmpValueId = this->writeExpression(*c.fArguments[i], out);
1407 0 : tmpVar = this->nextId();
1408 : }
1409 0 : this->writeInstruction(SpvOpVariable,
1410 0 : this->getPointerType(c.fArguments[i]->fType,
1411 : SpvStorageClassFunction),
1412 : tmpVar,
1413 : SpvStorageClassFunction,
1414 0 : fVariableBuffer);
1415 0 : this->writeInstruction(SpvOpStore, tmpVar, tmpValueId, out);
1416 0 : arguments.push_back(tmpVar);
1417 : }
1418 0 : SpvId result = this->nextId();
1419 0 : this->writeOpCode(SpvOpFunctionCall, 4 + (int32_t) c.fArguments.size(), out);
1420 0 : this->writeWord(this->getType(c.fType), out);
1421 0 : this->writeWord(result, out);
1422 0 : this->writeWord(entry->second, out);
1423 0 : for (SpvId id : arguments) {
1424 0 : this->writeWord(id, out);
1425 : }
1426 : // now that the call is complete, we may need to update some lvalues with the new values of out
1427 : // arguments
1428 0 : for (const auto& tuple : lvalues) {
1429 0 : SpvId load = this->nextId();
1430 0 : this->writeInstruction(SpvOpLoad, std::get<1>(tuple), load, std::get<0>(tuple), out);
1431 0 : std::get<2>(tuple)->store(load, out);
1432 : }
1433 0 : return result;
1434 : }
1435 :
1436 0 : SpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) {
1437 0 : ASSERT(c.fType.kind() == Type::kVector_Kind && c.isConstant());
1438 0 : SpvId result = this->nextId();
1439 0 : std::vector<SpvId> arguments;
1440 0 : for (size_t i = 0; i < c.fArguments.size(); i++) {
1441 0 : arguments.push_back(this->writeExpression(*c.fArguments[i], fConstantBuffer));
1442 : }
1443 0 : SpvId type = this->getType(c.fType);
1444 0 : if (c.fArguments.size() == 1) {
1445 : // with a single argument, a vector will have all of its entries equal to the argument
1446 0 : this->writeOpCode(SpvOpConstantComposite, 3 + c.fType.columns(), fConstantBuffer);
1447 0 : this->writeWord(type, fConstantBuffer);
1448 0 : this->writeWord(result, fConstantBuffer);
1449 0 : for (int i = 0; i < c.fType.columns(); i++) {
1450 0 : this->writeWord(arguments[0], fConstantBuffer);
1451 : }
1452 : } else {
1453 0 : this->writeOpCode(SpvOpConstantComposite, 3 + (int32_t) c.fArguments.size(),
1454 0 : fConstantBuffer);
1455 0 : this->writeWord(type, fConstantBuffer);
1456 0 : this->writeWord(result, fConstantBuffer);
1457 0 : for (SpvId id : arguments) {
1458 0 : this->writeWord(id, fConstantBuffer);
1459 : }
1460 : }
1461 0 : return result;
1462 : }
1463 :
1464 0 : SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, OutputStream& out) {
1465 0 : ASSERT(c.fType == *fContext.fFloat_Type);
1466 0 : ASSERT(c.fArguments.size() == 1);
1467 0 : ASSERT(c.fArguments[0]->fType.isNumber());
1468 0 : SpvId result = this->nextId();
1469 0 : SpvId parameter = this->writeExpression(*c.fArguments[0], out);
1470 0 : if (c.fArguments[0]->fType == *fContext.fInt_Type) {
1471 0 : this->writeInstruction(SpvOpConvertSToF, this->getType(c.fType), result, parameter,
1472 0 : out);
1473 0 : } else if (c.fArguments[0]->fType == *fContext.fUInt_Type) {
1474 0 : this->writeInstruction(SpvOpConvertUToF, this->getType(c.fType), result, parameter,
1475 0 : out);
1476 0 : } else if (c.fArguments[0]->fType == *fContext.fFloat_Type) {
1477 0 : return parameter;
1478 : }
1479 0 : return result;
1480 : }
1481 :
1482 0 : SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, OutputStream& out) {
1483 0 : ASSERT(c.fType == *fContext.fInt_Type);
1484 0 : ASSERT(c.fArguments.size() == 1);
1485 0 : ASSERT(c.fArguments[0]->fType.isNumber());
1486 0 : SpvId result = this->nextId();
1487 0 : SpvId parameter = this->writeExpression(*c.fArguments[0], out);
1488 0 : if (c.fArguments[0]->fType == *fContext.fFloat_Type) {
1489 0 : this->writeInstruction(SpvOpConvertFToS, this->getType(c.fType), result, parameter,
1490 0 : out);
1491 0 : } else if (c.fArguments[0]->fType == *fContext.fUInt_Type) {
1492 0 : this->writeInstruction(SpvOpSatConvertUToS, this->getType(c.fType), result, parameter,
1493 0 : out);
1494 0 : } else if (c.fArguments[0]->fType == *fContext.fInt_Type) {
1495 0 : return parameter;
1496 : }
1497 0 : return result;
1498 : }
1499 :
1500 0 : void SPIRVCodeGenerator::writeUniformScaleMatrix(SpvId id, SpvId diagonal, const Type& type,
1501 : OutputStream& out) {
1502 0 : FloatLiteral zero(fContext, Position(), 0);
1503 0 : SpvId zeroId = this->writeFloatLiteral(zero);
1504 0 : std::vector<SpvId> columnIds;
1505 0 : for (int column = 0; column < type.columns(); column++) {
1506 0 : this->writeOpCode(SpvOpCompositeConstruct, 3 + type.rows(),
1507 0 : out);
1508 0 : this->writeWord(this->getType(type.componentType().toCompound(fContext, type.rows(), 1)),
1509 0 : out);
1510 0 : SpvId columnId = this->nextId();
1511 0 : this->writeWord(columnId, out);
1512 0 : columnIds.push_back(columnId);
1513 0 : for (int row = 0; row < type.columns(); row++) {
1514 0 : this->writeWord(row == column ? diagonal : zeroId, out);
1515 : }
1516 : }
1517 0 : this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(),
1518 0 : out);
1519 0 : this->writeWord(this->getType(type), out);
1520 0 : this->writeWord(id, out);
1521 0 : for (SpvId id : columnIds) {
1522 0 : this->writeWord(id, out);
1523 : }
1524 0 : }
1525 :
1526 0 : void SPIRVCodeGenerator::writeMatrixCopy(SpvId id, SpvId src, const Type& srcType,
1527 : const Type& dstType, OutputStream& out) {
1528 0 : ABORT("unimplemented");
1529 : }
1530 :
1531 0 : SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, OutputStream& out) {
1532 0 : ASSERT(c.fType.kind() == Type::kMatrix_Kind);
1533 : // go ahead and write the arguments so we don't try to write new instructions in the middle of
1534 : // an instruction
1535 0 : std::vector<SpvId> arguments;
1536 0 : for (size_t i = 0; i < c.fArguments.size(); i++) {
1537 0 : arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1538 : }
1539 0 : SpvId result = this->nextId();
1540 0 : int rows = c.fType.rows();
1541 0 : int columns = c.fType.columns();
1542 0 : if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) {
1543 0 : this->writeUniformScaleMatrix(result, arguments[0], c.fType, out);
1544 0 : } else if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kMatrix_Kind) {
1545 0 : this->writeMatrixCopy(result, arguments[0], c.fArguments[0]->fType, c.fType, out);
1546 : } else {
1547 0 : std::vector<SpvId> columnIds;
1548 0 : int currentCount = 0;
1549 0 : for (size_t i = 0; i < arguments.size(); i++) {
1550 0 : if (c.fArguments[i]->fType.kind() == Type::kVector_Kind) {
1551 0 : ASSERT(currentCount == 0);
1552 0 : columnIds.push_back(arguments[i]);
1553 0 : currentCount = 0;
1554 : } else {
1555 0 : ASSERT(c.fArguments[i]->fType.kind() == Type::kScalar_Kind);
1556 0 : if (currentCount == 0) {
1557 0 : this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.rows(), out);
1558 0 : this->writeWord(this->getType(c.fType.componentType().toCompound(fContext, rows,
1559 : 1)),
1560 0 : out);
1561 0 : SpvId id = this->nextId();
1562 0 : this->writeWord(id, out);
1563 0 : columnIds.push_back(id);
1564 : }
1565 0 : this->writeWord(arguments[i], out);
1566 0 : currentCount = (currentCount + 1) % rows;
1567 : }
1568 : }
1569 0 : ASSERT(columnIds.size() == (size_t) columns);
1570 0 : this->writeOpCode(SpvOpCompositeConstruct, 3 + columns, out);
1571 0 : this->writeWord(this->getType(c.fType), out);
1572 0 : this->writeWord(result, out);
1573 0 : for (SpvId id : columnIds) {
1574 0 : this->writeWord(id, out);
1575 : }
1576 : }
1577 0 : return result;
1578 : }
1579 :
1580 0 : SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, OutputStream& out) {
1581 0 : ASSERT(c.fType.kind() == Type::kVector_Kind);
1582 0 : if (c.isConstant()) {
1583 0 : return this->writeConstantVector(c);
1584 : }
1585 : // go ahead and write the arguments so we don't try to write new instructions in the middle of
1586 : // an instruction
1587 0 : std::vector<SpvId> arguments;
1588 0 : for (size_t i = 0; i < c.fArguments.size(); i++) {
1589 0 : arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1590 : }
1591 0 : SpvId result = this->nextId();
1592 0 : if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) {
1593 0 : this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.columns(), out);
1594 0 : this->writeWord(this->getType(c.fType), out);
1595 0 : this->writeWord(result, out);
1596 0 : for (int i = 0; i < c.fType.columns(); i++) {
1597 0 : this->writeWord(arguments[0], out);
1598 : }
1599 : } else {
1600 0 : this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) c.fArguments.size(), out);
1601 0 : this->writeWord(this->getType(c.fType), out);
1602 0 : this->writeWord(result, out);
1603 0 : for (SpvId id : arguments) {
1604 0 : this->writeWord(id, out);
1605 : }
1606 : }
1607 0 : return result;
1608 : }
1609 :
1610 0 : SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, OutputStream& out) {
1611 0 : if (c.fType == *fContext.fFloat_Type) {
1612 0 : return this->writeFloatConstructor(c, out);
1613 0 : } else if (c.fType == *fContext.fInt_Type) {
1614 0 : return this->writeIntConstructor(c, out);
1615 : }
1616 0 : switch (c.fType.kind()) {
1617 : case Type::kVector_Kind:
1618 0 : return this->writeVectorConstructor(c, out);
1619 : case Type::kMatrix_Kind:
1620 0 : return this->writeMatrixConstructor(c, out);
1621 : default:
1622 0 : ABORT("unsupported constructor: %s", c.description().c_str());
1623 : }
1624 : }
1625 :
1626 0 : SpvStorageClass_ get_storage_class(const Modifiers& modifiers) {
1627 0 : if (modifiers.fFlags & Modifiers::kIn_Flag) {
1628 0 : ASSERT(!modifiers.fLayout.fPushConstant);
1629 0 : return SpvStorageClassInput;
1630 0 : } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
1631 0 : ASSERT(!modifiers.fLayout.fPushConstant);
1632 0 : return SpvStorageClassOutput;
1633 0 : } else if (modifiers.fFlags & Modifiers::kUniform_Flag) {
1634 0 : if (modifiers.fLayout.fPushConstant) {
1635 0 : return SpvStorageClassPushConstant;
1636 : }
1637 0 : return SpvStorageClassUniform;
1638 : } else {
1639 0 : return SpvStorageClassFunction;
1640 : }
1641 : }
1642 :
1643 0 : SpvStorageClass_ get_storage_class(const Expression& expr) {
1644 0 : switch (expr.fKind) {
1645 : case Expression::kVariableReference_Kind: {
1646 0 : const Variable& var = ((VariableReference&) expr).fVariable;
1647 0 : if (var.fStorage != Variable::kGlobal_Storage) {
1648 0 : return SpvStorageClassFunction;
1649 : }
1650 0 : return get_storage_class(var.fModifiers);
1651 : }
1652 : case Expression::kFieldAccess_Kind:
1653 0 : return get_storage_class(*((FieldAccess&) expr).fBase);
1654 : case Expression::kIndex_Kind:
1655 0 : return get_storage_class(*((IndexExpression&) expr).fBase);
1656 : default:
1657 0 : return SpvStorageClassFunction;
1658 : }
1659 : }
1660 :
1661 0 : std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, OutputStream& out) {
1662 0 : std::vector<SpvId> chain;
1663 0 : switch (expr.fKind) {
1664 : case Expression::kIndex_Kind: {
1665 0 : IndexExpression& indexExpr = (IndexExpression&) expr;
1666 0 : chain = this->getAccessChain(*indexExpr.fBase, out);
1667 0 : chain.push_back(this->writeExpression(*indexExpr.fIndex, out));
1668 0 : break;
1669 : }
1670 : case Expression::kFieldAccess_Kind: {
1671 0 : FieldAccess& fieldExpr = (FieldAccess&) expr;
1672 0 : chain = this->getAccessChain(*fieldExpr.fBase, out);
1673 0 : IntLiteral index(fContext, Position(), fieldExpr.fFieldIndex);
1674 0 : chain.push_back(this->writeIntLiteral(index));
1675 0 : break;
1676 : }
1677 : default:
1678 0 : chain.push_back(this->getLValue(expr, out)->getPointer());
1679 : }
1680 0 : return chain;
1681 : }
1682 :
1683 0 : class PointerLValue : public SPIRVCodeGenerator::LValue {
1684 : public:
1685 0 : PointerLValue(SPIRVCodeGenerator& gen, SpvId pointer, SpvId type)
1686 0 : : fGen(gen)
1687 : , fPointer(pointer)
1688 0 : , fType(type) {}
1689 :
1690 0 : virtual SpvId getPointer() override {
1691 0 : return fPointer;
1692 : }
1693 :
1694 0 : virtual SpvId load(OutputStream& out) override {
1695 0 : SpvId result = fGen.nextId();
1696 0 : fGen.writeInstruction(SpvOpLoad, fType, result, fPointer, out);
1697 0 : return result;
1698 : }
1699 :
1700 0 : virtual void store(SpvId value, OutputStream& out) override {
1701 0 : fGen.writeInstruction(SpvOpStore, fPointer, value, out);
1702 0 : }
1703 :
1704 : private:
1705 : SPIRVCodeGenerator& fGen;
1706 : const SpvId fPointer;
1707 : const SpvId fType;
1708 : };
1709 :
1710 0 : class SwizzleLValue : public SPIRVCodeGenerator::LValue {
1711 : public:
1712 0 : SwizzleLValue(SPIRVCodeGenerator& gen, SpvId vecPointer, const std::vector<int>& components,
1713 : const Type& baseType, const Type& swizzleType)
1714 0 : : fGen(gen)
1715 : , fVecPointer(vecPointer)
1716 : , fComponents(components)
1717 : , fBaseType(baseType)
1718 0 : , fSwizzleType(swizzleType) {}
1719 :
1720 0 : virtual SpvId getPointer() override {
1721 0 : return 0;
1722 : }
1723 :
1724 0 : virtual SpvId load(OutputStream& out) override {
1725 0 : SpvId base = fGen.nextId();
1726 0 : fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1727 0 : SpvId result = fGen.nextId();
1728 0 : fGen.writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) fComponents.size(), out);
1729 0 : fGen.writeWord(fGen.getType(fSwizzleType), out);
1730 0 : fGen.writeWord(result, out);
1731 0 : fGen.writeWord(base, out);
1732 0 : fGen.writeWord(base, out);
1733 0 : for (int component : fComponents) {
1734 0 : fGen.writeWord(component, out);
1735 : }
1736 0 : return result;
1737 : }
1738 :
1739 0 : virtual void store(SpvId value, OutputStream& out) override {
1740 : // use OpVectorShuffle to mix and match the vector components. We effectively create
1741 : // a virtual vector out of the concatenation of the left and right vectors, and then
1742 : // select components from this virtual vector to make the result vector. For
1743 : // instance, given:
1744 : // vec3 L = ...;
1745 : // vec3 R = ...;
1746 : // L.xz = R.xy;
1747 : // we end up with the virtual vector (L.x, L.y, L.z, R.x, R.y, R.z). Then we want
1748 : // our result vector to look like (R.x, L.y, R.y), so we need to select indices
1749 : // (3, 1, 4).
1750 0 : SpvId base = fGen.nextId();
1751 0 : fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1752 0 : SpvId shuffle = fGen.nextId();
1753 0 : fGen.writeOpCode(SpvOpVectorShuffle, 5 + fBaseType.columns(), out);
1754 0 : fGen.writeWord(fGen.getType(fBaseType), out);
1755 0 : fGen.writeWord(shuffle, out);
1756 0 : fGen.writeWord(base, out);
1757 0 : fGen.writeWord(value, out);
1758 0 : for (int i = 0; i < fBaseType.columns(); i++) {
1759 : // current offset into the virtual vector, defaults to pulling the unmodified
1760 : // value from the left side
1761 0 : int offset = i;
1762 : // check to see if we are writing this component
1763 0 : for (size_t j = 0; j < fComponents.size(); j++) {
1764 0 : if (fComponents[j] == i) {
1765 : // we're writing to this component, so adjust the offset to pull from
1766 : // the correct component of the right side instead of preserving the
1767 : // value from the left
1768 0 : offset = (int) (j + fBaseType.columns());
1769 0 : break;
1770 : }
1771 : }
1772 0 : fGen.writeWord(offset, out);
1773 : }
1774 0 : fGen.writeInstruction(SpvOpStore, fVecPointer, shuffle, out);
1775 0 : }
1776 :
1777 : private:
1778 : SPIRVCodeGenerator& fGen;
1779 : const SpvId fVecPointer;
1780 : const std::vector<int>& fComponents;
1781 : const Type& fBaseType;
1782 : const Type& fSwizzleType;
1783 : };
1784 :
1785 0 : std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const Expression& expr,
1786 : OutputStream& out) {
1787 0 : switch (expr.fKind) {
1788 : case Expression::kVariableReference_Kind: {
1789 0 : const Variable& var = ((VariableReference&) expr).fVariable;
1790 0 : auto entry = fVariableMap.find(&var);
1791 0 : ASSERT(entry != fVariableMap.end());
1792 : return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1793 : *this,
1794 0 : entry->second,
1795 0 : this->getType(expr.fType)));
1796 : }
1797 : case Expression::kIndex_Kind: // fall through
1798 : case Expression::kFieldAccess_Kind: {
1799 0 : std::vector<SpvId> chain = this->getAccessChain(expr, out);
1800 0 : SpvId member = this->nextId();
1801 0 : this->writeOpCode(SpvOpAccessChain, (SpvId) (3 + chain.size()), out);
1802 0 : this->writeWord(this->getPointerType(expr.fType, get_storage_class(expr)), out);
1803 0 : this->writeWord(member, out);
1804 0 : for (SpvId idx : chain) {
1805 0 : this->writeWord(idx, out);
1806 : }
1807 : return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1808 : *this,
1809 : member,
1810 0 : this->getType(expr.fType)));
1811 : }
1812 :
1813 : case Expression::kSwizzle_Kind: {
1814 0 : Swizzle& swizzle = (Swizzle&) expr;
1815 0 : size_t count = swizzle.fComponents.size();
1816 0 : SpvId base = this->getLValue(*swizzle.fBase, out)->getPointer();
1817 0 : ASSERT(base);
1818 0 : if (count == 1) {
1819 0 : IntLiteral index(fContext, Position(), swizzle.fComponents[0]);
1820 0 : SpvId member = this->nextId();
1821 0 : this->writeInstruction(SpvOpAccessChain,
1822 0 : this->getPointerType(swizzle.fType,
1823 0 : get_storage_class(*swizzle.fBase)),
1824 : member,
1825 : base,
1826 0 : this->writeIntLiteral(index),
1827 0 : out);
1828 : return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1829 : *this,
1830 : member,
1831 0 : this->getType(expr.fType)));
1832 : } else {
1833 : return std::unique_ptr<SPIRVCodeGenerator::LValue>(new SwizzleLValue(
1834 : *this,
1835 : base,
1836 : swizzle.fComponents,
1837 0 : swizzle.fBase->fType,
1838 0 : expr.fType));
1839 : }
1840 : }
1841 :
1842 : default:
1843 : // expr isn't actually an lvalue, create a dummy variable for it. This case happens due
1844 : // to the need to store values in temporary variables during function calls (see
1845 : // comments in getFunctionType); erroneous uses of rvalues as lvalues should have been
1846 : // caught by IRGenerator
1847 0 : SpvId result = this->nextId();
1848 0 : SpvId type = this->getPointerType(expr.fType, SpvStorageClassFunction);
1849 0 : this->writeInstruction(SpvOpVariable, type, result, SpvStorageClassFunction,
1850 0 : fVariableBuffer);
1851 0 : this->writeInstruction(SpvOpStore, result, this->writeExpression(expr, out), out);
1852 : return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1853 : *this,
1854 : result,
1855 0 : this->getType(expr.fType)));
1856 : }
1857 : }
1858 :
1859 0 : SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, OutputStream& out) {
1860 0 : SpvId result = this->nextId();
1861 0 : auto entry = fVariableMap.find(&ref.fVariable);
1862 0 : ASSERT(entry != fVariableMap.end());
1863 0 : SpvId var = entry->second;
1864 0 : this->writeInstruction(SpvOpLoad, this->getType(ref.fVariable.fType), result, var, out);
1865 0 : if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
1866 0 : fProgram.fSettings.fFlipY) {
1867 : // need to remap to a top-left coordinate system
1868 0 : if (fRTHeightStructId == (SpvId) -1) {
1869 : // height variable hasn't been written yet
1870 0 : std::shared_ptr<SymbolTable> st(new SymbolTable(&fErrors));
1871 0 : ASSERT(fRTHeightFieldIndex == (SpvId) -1);
1872 0 : std::vector<Type::Field> fields;
1873 0 : fields.emplace_back(Modifiers(), String(SKSL_RTHEIGHT_NAME),
1874 0 : fContext.fFloat_Type.get());
1875 0 : String name("sksl_synthetic_uniforms");
1876 0 : Type intfStruct(Position(), name, fields);
1877 : Layout layout(-1, -1, 1, -1, -1, -1, -1, false, false, false,
1878 : Layout::Format::kUnspecified, false, Layout::kUnspecified_Primitive, -1,
1879 0 : -1);
1880 0 : Variable* intfVar = new Variable(Position(),
1881 0 : Modifiers(layout, Modifiers::kUniform_Flag),
1882 : name,
1883 : intfStruct,
1884 0 : Variable::kGlobal_Storage);
1885 0 : fSynthetics.takeOwnership(intfVar);
1886 0 : InterfaceBlock intf(Position(), intfVar, name, String(""),
1887 0 : std::vector<std::unique_ptr<Expression>>(), st);
1888 0 : fRTHeightStructId = this->writeInterfaceBlock(intf);
1889 0 : fRTHeightFieldIndex = 0;
1890 : }
1891 0 : ASSERT(fRTHeightFieldIndex != (SpvId) -1);
1892 : // write vec4(gl_FragCoord.x, u_skRTHeight - gl_FragCoord.y, 0.0, 1.0)
1893 0 : SpvId xId = this->nextId();
1894 0 : this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), xId,
1895 0 : result, 0, out);
1896 0 : IntLiteral fieldIndex(fContext, Position(), fRTHeightFieldIndex);
1897 0 : SpvId fieldIndexId = this->writeIntLiteral(fieldIndex);
1898 0 : SpvId heightPtr = this->nextId();
1899 0 : this->writeOpCode(SpvOpAccessChain, 5, out);
1900 0 : this->writeWord(this->getPointerType(*fContext.fFloat_Type, SpvStorageClassUniform), out);
1901 0 : this->writeWord(heightPtr, out);
1902 0 : this->writeWord(fRTHeightStructId, out);
1903 0 : this->writeWord(fieldIndexId, out);
1904 0 : SpvId heightRead = this->nextId();
1905 0 : this->writeInstruction(SpvOpLoad, this->getType(*fContext.fFloat_Type), heightRead,
1906 0 : heightPtr, out);
1907 0 : SpvId rawYId = this->nextId();
1908 0 : this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawYId,
1909 0 : result, 1, out);
1910 0 : SpvId flippedYId = this->nextId();
1911 0 : this->writeInstruction(SpvOpFSub, this->getType(*fContext.fFloat_Type), flippedYId,
1912 0 : heightRead, rawYId, out);
1913 0 : FloatLiteral zero(fContext, Position(), 0.0);
1914 0 : SpvId zeroId = writeFloatLiteral(zero);
1915 0 : FloatLiteral one(fContext, Position(), 1.0);
1916 0 : SpvId oneId = writeFloatLiteral(one);
1917 0 : SpvId flipped = this->nextId();
1918 0 : this->writeOpCode(SpvOpCompositeConstruct, 7, out);
1919 0 : this->writeWord(this->getType(*fContext.fVec4_Type), out);
1920 0 : this->writeWord(flipped, out);
1921 0 : this->writeWord(xId, out);
1922 0 : this->writeWord(flippedYId, out);
1923 0 : this->writeWord(zeroId, out);
1924 0 : this->writeWord(oneId, out);
1925 0 : return flipped;
1926 : }
1927 0 : return result;
1928 : }
1929 :
1930 0 : SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, OutputStream& out) {
1931 0 : return getLValue(expr, out)->load(out);
1932 : }
1933 :
1934 0 : SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, OutputStream& out) {
1935 0 : return getLValue(f, out)->load(out);
1936 : }
1937 :
1938 0 : SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, OutputStream& out) {
1939 0 : SpvId base = this->writeExpression(*swizzle.fBase, out);
1940 0 : SpvId result = this->nextId();
1941 0 : size_t count = swizzle.fComponents.size();
1942 0 : if (count == 1) {
1943 0 : this->writeInstruction(SpvOpCompositeExtract, this->getType(swizzle.fType), result, base,
1944 0 : swizzle.fComponents[0], out);
1945 : } else {
1946 0 : this->writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) count, out);
1947 0 : this->writeWord(this->getType(swizzle.fType), out);
1948 0 : this->writeWord(result, out);
1949 0 : this->writeWord(base, out);
1950 0 : this->writeWord(base, out);
1951 0 : for (int component : swizzle.fComponents) {
1952 0 : this->writeWord(component, out);
1953 : }
1954 : }
1955 0 : return result;
1956 : }
1957 :
1958 0 : SpvId SPIRVCodeGenerator::writeBinaryOperation(const Type& resultType,
1959 : const Type& operandType, SpvId lhs,
1960 : SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt,
1961 : SpvOp_ ifUInt, SpvOp_ ifBool, OutputStream& out) {
1962 0 : SpvId result = this->nextId();
1963 0 : if (is_float(fContext, operandType)) {
1964 0 : this->writeInstruction(ifFloat, this->getType(resultType), result, lhs, rhs, out);
1965 0 : } else if (is_signed(fContext, operandType)) {
1966 0 : this->writeInstruction(ifInt, this->getType(resultType), result, lhs, rhs, out);
1967 0 : } else if (is_unsigned(fContext, operandType)) {
1968 0 : this->writeInstruction(ifUInt, this->getType(resultType), result, lhs, rhs, out);
1969 0 : } else if (operandType == *fContext.fBool_Type) {
1970 0 : this->writeInstruction(ifBool, this->getType(resultType), result, lhs, rhs, out);
1971 : } else {
1972 0 : ABORT("invalid operandType: %s", operandType.description().c_str());
1973 : }
1974 0 : return result;
1975 : }
1976 :
1977 0 : bool is_assignment(Token::Kind op) {
1978 0 : switch (op) {
1979 : case Token::EQ: // fall through
1980 : case Token::PLUSEQ: // fall through
1981 : case Token::MINUSEQ: // fall through
1982 : case Token::STAREQ: // fall through
1983 : case Token::SLASHEQ: // fall through
1984 : case Token::PERCENTEQ: // fall through
1985 : case Token::SHLEQ: // fall through
1986 : case Token::SHREQ: // fall through
1987 : case Token::BITWISEOREQ: // fall through
1988 : case Token::BITWISEXOREQ: // fall through
1989 : case Token::BITWISEANDEQ: // fall through
1990 : case Token::LOGICALOREQ: // fall through
1991 : case Token::LOGICALXOREQ: // fall through
1992 : case Token::LOGICALANDEQ:
1993 0 : return true;
1994 : default:
1995 0 : return false;
1996 : }
1997 : }
1998 :
1999 0 : SpvId SPIRVCodeGenerator::foldToBool(SpvId id, const Type& operandType, OutputStream& out) {
2000 0 : if (operandType.kind() == Type::kVector_Kind) {
2001 0 : SpvId result = this->nextId();
2002 0 : this->writeInstruction(SpvOpAll, this->getType(*fContext.fBool_Type), result, id, out);
2003 0 : return result;
2004 : }
2005 0 : return id;
2006 : }
2007 :
2008 0 : SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, OutputStream& out) {
2009 : // handle cases where we don't necessarily evaluate both LHS and RHS
2010 0 : switch (b.fOperator) {
2011 : case Token::EQ: {
2012 0 : SpvId rhs = this->writeExpression(*b.fRight, out);
2013 0 : this->getLValue(*b.fLeft, out)->store(rhs, out);
2014 0 : return rhs;
2015 : }
2016 : case Token::LOGICALAND:
2017 0 : return this->writeLogicalAnd(b, out);
2018 : case Token::LOGICALOR:
2019 0 : return this->writeLogicalOr(b, out);
2020 : default:
2021 0 : break;
2022 : }
2023 :
2024 : // "normal" operators
2025 0 : const Type& resultType = b.fType;
2026 0 : std::unique_ptr<LValue> lvalue;
2027 : SpvId lhs;
2028 0 : if (is_assignment(b.fOperator)) {
2029 0 : lvalue = this->getLValue(*b.fLeft, out);
2030 0 : lhs = lvalue->load(out);
2031 : } else {
2032 0 : lvalue = nullptr;
2033 0 : lhs = this->writeExpression(*b.fLeft, out);
2034 : }
2035 0 : SpvId rhs = this->writeExpression(*b.fRight, out);
2036 : // component type we are operating on: float, int, uint
2037 : const Type* operandType;
2038 : // IR allows mismatched types in expressions (e.g. vec2 * float), but they need special handling
2039 : // in SPIR-V
2040 0 : if (b.fLeft->fType != b.fRight->fType) {
2041 0 : if (b.fLeft->fType.kind() == Type::kVector_Kind &&
2042 0 : b.fRight->fType.isNumber()) {
2043 : // promote number to vector
2044 0 : SpvId vec = this->nextId();
2045 0 : this->writeOpCode(SpvOpCompositeConstruct, 3 + b.fType.columns(), out);
2046 0 : this->writeWord(this->getType(resultType), out);
2047 0 : this->writeWord(vec, out);
2048 0 : for (int i = 0; i < resultType.columns(); i++) {
2049 0 : this->writeWord(rhs, out);
2050 : }
2051 0 : rhs = vec;
2052 0 : operandType = &b.fRight->fType;
2053 0 : } else if (b.fRight->fType.kind() == Type::kVector_Kind &&
2054 0 : b.fLeft->fType.isNumber()) {
2055 : // promote number to vector
2056 0 : SpvId vec = this->nextId();
2057 0 : this->writeOpCode(SpvOpCompositeConstruct, 3 + b.fType.columns(), out);
2058 0 : this->writeWord(this->getType(resultType), out);
2059 0 : this->writeWord(vec, out);
2060 0 : for (int i = 0; i < resultType.columns(); i++) {
2061 0 : this->writeWord(lhs, out);
2062 : }
2063 0 : lhs = vec;
2064 0 : ASSERT(!lvalue);
2065 0 : operandType = &b.fLeft->fType;
2066 0 : } else if (b.fLeft->fType.kind() == Type::kMatrix_Kind) {
2067 : SpvOp_ op;
2068 0 : if (b.fRight->fType.kind() == Type::kMatrix_Kind) {
2069 0 : op = SpvOpMatrixTimesMatrix;
2070 0 : } else if (b.fRight->fType.kind() == Type::kVector_Kind) {
2071 0 : op = SpvOpMatrixTimesVector;
2072 : } else {
2073 0 : ASSERT(b.fRight->fType.kind() == Type::kScalar_Kind);
2074 0 : op = SpvOpMatrixTimesScalar;
2075 : }
2076 0 : SpvId result = this->nextId();
2077 0 : this->writeInstruction(op, this->getType(b.fType), result, lhs, rhs, out);
2078 0 : if (b.fOperator == Token::STAREQ) {
2079 0 : lvalue->store(result, out);
2080 : } else {
2081 0 : ASSERT(b.fOperator == Token::STAR);
2082 : }
2083 0 : return result;
2084 0 : } else if (b.fRight->fType.kind() == Type::kMatrix_Kind) {
2085 0 : SpvId result = this->nextId();
2086 0 : if (b.fLeft->fType.kind() == Type::kVector_Kind) {
2087 0 : this->writeInstruction(SpvOpVectorTimesMatrix, this->getType(b.fType), result,
2088 0 : lhs, rhs, out);
2089 : } else {
2090 0 : ASSERT(b.fLeft->fType.kind() == Type::kScalar_Kind);
2091 0 : this->writeInstruction(SpvOpMatrixTimesScalar, this->getType(b.fType), result, rhs,
2092 0 : lhs, out);
2093 : }
2094 0 : if (b.fOperator == Token::STAREQ) {
2095 0 : lvalue->store(result, out);
2096 : } else {
2097 0 : ASSERT(b.fOperator == Token::STAR);
2098 : }
2099 0 : return result;
2100 : } else {
2101 0 : ABORT("unsupported binary expression: %s", b.description().c_str());
2102 : }
2103 : } else {
2104 0 : operandType = &b.fLeft->fType;
2105 0 : ASSERT(*operandType == b.fRight->fType);
2106 : }
2107 0 : switch (b.fOperator) {
2108 : case Token::EQEQ: {
2109 0 : ASSERT(resultType == *fContext.fBool_Type);
2110 0 : return this->foldToBool(this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2111 : SpvOpFOrdEqual, SpvOpIEqual,
2112 : SpvOpIEqual, SpvOpLogicalEqual, out),
2113 0 : *operandType, out);
2114 : }
2115 : case Token::NEQ:
2116 0 : ASSERT(resultType == *fContext.fBool_Type);
2117 0 : return this->foldToBool(this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2118 : SpvOpFOrdNotEqual, SpvOpINotEqual,
2119 : SpvOpINotEqual, SpvOpLogicalNotEqual,
2120 : out),
2121 0 : *operandType, out);
2122 : case Token::GT:
2123 0 : ASSERT(resultType == *fContext.fBool_Type);
2124 : return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2125 : SpvOpFOrdGreaterThan, SpvOpSGreaterThan,
2126 0 : SpvOpUGreaterThan, SpvOpUndef, out);
2127 : case Token::LT:
2128 0 : ASSERT(resultType == *fContext.fBool_Type);
2129 : return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdLessThan,
2130 0 : SpvOpSLessThan, SpvOpULessThan, SpvOpUndef, out);
2131 : case Token::GTEQ:
2132 0 : ASSERT(resultType == *fContext.fBool_Type);
2133 : return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2134 : SpvOpFOrdGreaterThanEqual, SpvOpSGreaterThanEqual,
2135 0 : SpvOpUGreaterThanEqual, SpvOpUndef, out);
2136 : case Token::LTEQ:
2137 0 : ASSERT(resultType == *fContext.fBool_Type);
2138 : return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2139 : SpvOpFOrdLessThanEqual, SpvOpSLessThanEqual,
2140 0 : SpvOpULessThanEqual, SpvOpUndef, out);
2141 : case Token::PLUS:
2142 : return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
2143 0 : SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2144 : case Token::MINUS:
2145 : return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
2146 0 : SpvOpISub, SpvOpISub, SpvOpUndef, out);
2147 : case Token::STAR:
2148 0 : if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
2149 0 : b.fRight->fType.kind() == Type::kMatrix_Kind) {
2150 : // matrix multiply
2151 0 : SpvId result = this->nextId();
2152 0 : this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2153 0 : lhs, rhs, out);
2154 0 : return result;
2155 : }
2156 : return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
2157 0 : SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
2158 : case Token::SLASH:
2159 : return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
2160 0 : SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
2161 : case Token::PLUSEQ: {
2162 : SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
2163 0 : SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2164 0 : ASSERT(lvalue);
2165 0 : lvalue->store(result, out);
2166 0 : return result;
2167 : }
2168 : case Token::MINUSEQ: {
2169 : SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
2170 0 : SpvOpISub, SpvOpISub, SpvOpUndef, out);
2171 0 : ASSERT(lvalue);
2172 0 : lvalue->store(result, out);
2173 0 : return result;
2174 : }
2175 : case Token::STAREQ: {
2176 0 : if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
2177 0 : b.fRight->fType.kind() == Type::kMatrix_Kind) {
2178 : // matrix multiply
2179 0 : SpvId result = this->nextId();
2180 0 : this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2181 0 : lhs, rhs, out);
2182 0 : ASSERT(lvalue);
2183 0 : lvalue->store(result, out);
2184 0 : return result;
2185 : }
2186 : SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
2187 0 : SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
2188 0 : ASSERT(lvalue);
2189 0 : lvalue->store(result, out);
2190 0 : return result;
2191 : }
2192 : case Token::SLASHEQ: {
2193 : SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
2194 0 : SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
2195 0 : ASSERT(lvalue);
2196 0 : lvalue->store(result, out);
2197 0 : return result;
2198 : }
2199 : default:
2200 : // FIXME: missing support for some operators (bitwise, &&=, ||=, shift...)
2201 0 : ABORT("unsupported binary expression: %s", b.description().c_str());
2202 : }
2203 : }
2204 :
2205 0 : SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, OutputStream& out) {
2206 0 : ASSERT(a.fOperator == Token::LOGICALAND);
2207 0 : BoolLiteral falseLiteral(fContext, Position(), false);
2208 0 : SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
2209 0 : SpvId lhs = this->writeExpression(*a.fLeft, out);
2210 0 : SpvId rhsLabel = this->nextId();
2211 0 : SpvId end = this->nextId();
2212 0 : SpvId lhsBlock = fCurrentBlock;
2213 0 : this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2214 0 : this->writeInstruction(SpvOpBranchConditional, lhs, rhsLabel, end, out);
2215 0 : this->writeLabel(rhsLabel, out);
2216 0 : SpvId rhs = this->writeExpression(*a.fRight, out);
2217 0 : SpvId rhsBlock = fCurrentBlock;
2218 0 : this->writeInstruction(SpvOpBranch, end, out);
2219 0 : this->writeLabel(end, out);
2220 0 : SpvId result = this->nextId();
2221 0 : this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, falseConstant,
2222 0 : lhsBlock, rhs, rhsBlock, out);
2223 0 : return result;
2224 : }
2225 :
2226 0 : SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, OutputStream& out) {
2227 0 : ASSERT(o.fOperator == Token::LOGICALOR);
2228 0 : BoolLiteral trueLiteral(fContext, Position(), true);
2229 0 : SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
2230 0 : SpvId lhs = this->writeExpression(*o.fLeft, out);
2231 0 : SpvId rhsLabel = this->nextId();
2232 0 : SpvId end = this->nextId();
2233 0 : SpvId lhsBlock = fCurrentBlock;
2234 0 : this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2235 0 : this->writeInstruction(SpvOpBranchConditional, lhs, end, rhsLabel, out);
2236 0 : this->writeLabel(rhsLabel, out);
2237 0 : SpvId rhs = this->writeExpression(*o.fRight, out);
2238 0 : SpvId rhsBlock = fCurrentBlock;
2239 0 : this->writeInstruction(SpvOpBranch, end, out);
2240 0 : this->writeLabel(end, out);
2241 0 : SpvId result = this->nextId();
2242 0 : this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, trueConstant,
2243 0 : lhsBlock, rhs, rhsBlock, out);
2244 0 : return result;
2245 : }
2246 :
2247 0 : SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, OutputStream& out) {
2248 0 : SpvId test = this->writeExpression(*t.fTest, out);
2249 0 : if (t.fIfTrue->isConstant() && t.fIfFalse->isConstant()) {
2250 : // both true and false are constants, can just use OpSelect
2251 0 : SpvId result = this->nextId();
2252 0 : SpvId trueId = this->writeExpression(*t.fIfTrue, out);
2253 0 : SpvId falseId = this->writeExpression(*t.fIfFalse, out);
2254 0 : this->writeInstruction(SpvOpSelect, this->getType(t.fType), result, test, trueId, falseId,
2255 0 : out);
2256 0 : return result;
2257 : }
2258 : // was originally using OpPhi to choose the result, but for some reason that is crashing on
2259 : // Adreno. Switched to storing the result in a temp variable as glslang does.
2260 0 : SpvId var = this->nextId();
2261 0 : this->writeInstruction(SpvOpVariable, this->getPointerType(t.fType, SpvStorageClassFunction),
2262 0 : var, SpvStorageClassFunction, fVariableBuffer);
2263 0 : SpvId trueLabel = this->nextId();
2264 0 : SpvId falseLabel = this->nextId();
2265 0 : SpvId end = this->nextId();
2266 0 : this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2267 0 : this->writeInstruction(SpvOpBranchConditional, test, trueLabel, falseLabel, out);
2268 0 : this->writeLabel(trueLabel, out);
2269 0 : this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfTrue, out), out);
2270 0 : this->writeInstruction(SpvOpBranch, end, out);
2271 0 : this->writeLabel(falseLabel, out);
2272 0 : this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfFalse, out), out);
2273 0 : this->writeInstruction(SpvOpBranch, end, out);
2274 0 : this->writeLabel(end, out);
2275 0 : SpvId result = this->nextId();
2276 0 : this->writeInstruction(SpvOpLoad, this->getType(t.fType), result, var, out);
2277 0 : return result;
2278 : }
2279 :
2280 0 : std::unique_ptr<Expression> create_literal_1(const Context& context, const Type& type) {
2281 0 : if (type == *context.fInt_Type) {
2282 0 : return std::unique_ptr<Expression>(new IntLiteral(context, Position(), 1));
2283 : }
2284 0 : else if (type == *context.fFloat_Type) {
2285 0 : return std::unique_ptr<Expression>(new FloatLiteral(context, Position(), 1.0));
2286 : } else {
2287 0 : ABORT("math is unsupported on type '%s'", type.name().c_str());
2288 : }
2289 : }
2290 :
2291 0 : SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, OutputStream& out) {
2292 0 : if (p.fOperator == Token::MINUS) {
2293 0 : SpvId result = this->nextId();
2294 0 : SpvId typeId = this->getType(p.fType);
2295 0 : SpvId expr = this->writeExpression(*p.fOperand, out);
2296 0 : if (is_float(fContext, p.fType)) {
2297 0 : this->writeInstruction(SpvOpFNegate, typeId, result, expr, out);
2298 0 : } else if (is_signed(fContext, p.fType)) {
2299 0 : this->writeInstruction(SpvOpSNegate, typeId, result, expr, out);
2300 : } else {
2301 0 : ABORT("unsupported prefix expression %s", p.description().c_str());
2302 : };
2303 0 : return result;
2304 : }
2305 0 : switch (p.fOperator) {
2306 : case Token::PLUS:
2307 0 : return this->writeExpression(*p.fOperand, out);
2308 : case Token::PLUSPLUS: {
2309 0 : std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
2310 0 : SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
2311 0 : SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
2312 : SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef,
2313 0 : out);
2314 0 : lv->store(result, out);
2315 0 : return result;
2316 : }
2317 : case Token::MINUSMINUS: {
2318 0 : std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
2319 0 : SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
2320 0 : SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
2321 : SpvOpFSub, SpvOpISub, SpvOpISub, SpvOpUndef,
2322 0 : out);
2323 0 : lv->store(result, out);
2324 0 : return result;
2325 : }
2326 : case Token::LOGICALNOT: {
2327 0 : ASSERT(p.fOperand->fType == *fContext.fBool_Type);
2328 0 : SpvId result = this->nextId();
2329 0 : this->writeInstruction(SpvOpLogicalNot, this->getType(p.fOperand->fType), result,
2330 0 : this->writeExpression(*p.fOperand, out), out);
2331 0 : return result;
2332 : }
2333 : case Token::BITWISENOT: {
2334 0 : SpvId result = this->nextId();
2335 0 : this->writeInstruction(SpvOpNot, this->getType(p.fOperand->fType), result,
2336 0 : this->writeExpression(*p.fOperand, out), out);
2337 0 : return result;
2338 : }
2339 : default:
2340 0 : ABORT("unsupported prefix expression: %s", p.description().c_str());
2341 : }
2342 : }
2343 :
2344 0 : SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, OutputStream& out) {
2345 0 : std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
2346 0 : SpvId result = lv->load(out);
2347 0 : SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
2348 0 : switch (p.fOperator) {
2349 : case Token::PLUSPLUS: {
2350 0 : SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFAdd,
2351 0 : SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2352 0 : lv->store(temp, out);
2353 0 : return result;
2354 : }
2355 : case Token::MINUSMINUS: {
2356 0 : SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFSub,
2357 0 : SpvOpISub, SpvOpISub, SpvOpUndef, out);
2358 0 : lv->store(temp, out);
2359 0 : return result;
2360 : }
2361 : default:
2362 0 : ABORT("unsupported postfix expression %s", p.description().c_str());
2363 : }
2364 : }
2365 :
2366 0 : SpvId SPIRVCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
2367 0 : if (b.fValue) {
2368 0 : if (fBoolTrue == 0) {
2369 0 : fBoolTrue = this->nextId();
2370 0 : this->writeInstruction(SpvOpConstantTrue, this->getType(b.fType), fBoolTrue,
2371 0 : fConstantBuffer);
2372 : }
2373 0 : return fBoolTrue;
2374 : } else {
2375 0 : if (fBoolFalse == 0) {
2376 0 : fBoolFalse = this->nextId();
2377 0 : this->writeInstruction(SpvOpConstantFalse, this->getType(b.fType), fBoolFalse,
2378 0 : fConstantBuffer);
2379 : }
2380 0 : return fBoolFalse;
2381 : }
2382 : }
2383 :
2384 0 : SpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) {
2385 0 : if (i.fType == *fContext.fInt_Type) {
2386 0 : auto entry = fIntConstants.find(i.fValue);
2387 0 : if (entry == fIntConstants.end()) {
2388 0 : SpvId result = this->nextId();
2389 0 : this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue,
2390 0 : fConstantBuffer);
2391 0 : fIntConstants[i.fValue] = result;
2392 0 : return result;
2393 : }
2394 0 : return entry->second;
2395 : } else {
2396 0 : ASSERT(i.fType == *fContext.fUInt_Type);
2397 0 : auto entry = fUIntConstants.find(i.fValue);
2398 0 : if (entry == fUIntConstants.end()) {
2399 0 : SpvId result = this->nextId();
2400 0 : this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue,
2401 0 : fConstantBuffer);
2402 0 : fUIntConstants[i.fValue] = result;
2403 0 : return result;
2404 : }
2405 0 : return entry->second;
2406 : }
2407 : }
2408 :
2409 0 : SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
2410 0 : if (f.fType == *fContext.fFloat_Type) {
2411 0 : float value = (float) f.fValue;
2412 0 : auto entry = fFloatConstants.find(value);
2413 0 : if (entry == fFloatConstants.end()) {
2414 0 : SpvId result = this->nextId();
2415 : uint32_t bits;
2416 : ASSERT(sizeof(bits) == sizeof(value));
2417 0 : memcpy(&bits, &value, sizeof(bits));
2418 0 : this->writeInstruction(SpvOpConstant, this->getType(f.fType), result, bits,
2419 0 : fConstantBuffer);
2420 0 : fFloatConstants[value] = result;
2421 0 : return result;
2422 : }
2423 0 : return entry->second;
2424 : } else {
2425 0 : ASSERT(f.fType == *fContext.fDouble_Type);
2426 0 : auto entry = fDoubleConstants.find(f.fValue);
2427 0 : if (entry == fDoubleConstants.end()) {
2428 0 : SpvId result = this->nextId();
2429 : uint64_t bits;
2430 : ASSERT(sizeof(bits) == sizeof(f.fValue));
2431 0 : memcpy(&bits, &f.fValue, sizeof(bits));
2432 0 : this->writeInstruction(SpvOpConstant, this->getType(f.fType), result,
2433 0 : bits & 0xffffffff, bits >> 32, fConstantBuffer);
2434 0 : fDoubleConstants[f.fValue] = result;
2435 0 : return result;
2436 : }
2437 0 : return entry->second;
2438 : }
2439 : }
2440 :
2441 0 : SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, OutputStream& out) {
2442 0 : SpvId result = fFunctionMap[&f];
2443 0 : this->writeInstruction(SpvOpFunction, this->getType(f.fReturnType), result,
2444 0 : SpvFunctionControlMaskNone, this->getFunctionType(f), out);
2445 0 : this->writeInstruction(SpvOpName, result, f.fName.c_str(), fNameBuffer);
2446 0 : for (size_t i = 0; i < f.fParameters.size(); i++) {
2447 0 : SpvId id = this->nextId();
2448 0 : fVariableMap[f.fParameters[i]] = id;
2449 : SpvId type;
2450 0 : type = this->getPointerType(f.fParameters[i]->fType, SpvStorageClassFunction);
2451 0 : this->writeInstruction(SpvOpFunctionParameter, type, id, out);
2452 : }
2453 0 : return result;
2454 : }
2455 :
2456 0 : SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, OutputStream& out) {
2457 0 : fVariableBuffer.reset();
2458 0 : SpvId result = this->writeFunctionStart(f.fDeclaration, out);
2459 0 : this->writeLabel(this->nextId(), out);
2460 0 : if (f.fDeclaration.fName == "main") {
2461 0 : write_stringstream(fGlobalInitializersBuffer, out);
2462 : }
2463 0 : StringStream bodyBuffer;
2464 0 : this->writeBlock(*f.fBody, bodyBuffer);
2465 0 : write_stringstream(fVariableBuffer, out);
2466 0 : write_stringstream(bodyBuffer, out);
2467 0 : if (fCurrentBlock) {
2468 0 : this->writeInstruction(SpvOpReturn, out);
2469 : }
2470 0 : this->writeInstruction(SpvOpFunctionEnd, out);
2471 0 : return result;
2472 : }
2473 :
2474 0 : void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target) {
2475 0 : if (layout.fLocation >= 0) {
2476 0 : this->writeInstruction(SpvOpDecorate, target, SpvDecorationLocation, layout.fLocation,
2477 0 : fDecorationBuffer);
2478 : }
2479 0 : if (layout.fBinding >= 0) {
2480 0 : this->writeInstruction(SpvOpDecorate, target, SpvDecorationBinding, layout.fBinding,
2481 0 : fDecorationBuffer);
2482 : }
2483 0 : if (layout.fIndex >= 0) {
2484 0 : this->writeInstruction(SpvOpDecorate, target, SpvDecorationIndex, layout.fIndex,
2485 0 : fDecorationBuffer);
2486 : }
2487 0 : if (layout.fSet >= 0) {
2488 0 : this->writeInstruction(SpvOpDecorate, target, SpvDecorationDescriptorSet, layout.fSet,
2489 0 : fDecorationBuffer);
2490 : }
2491 0 : if (layout.fInputAttachmentIndex >= 0) {
2492 0 : this->writeInstruction(SpvOpDecorate, target, SpvDecorationInputAttachmentIndex,
2493 0 : layout.fInputAttachmentIndex, fDecorationBuffer);
2494 : }
2495 0 : if (layout.fBuiltin >= 0 && layout.fBuiltin != SK_FRAGCOLOR_BUILTIN) {
2496 0 : this->writeInstruction(SpvOpDecorate, target, SpvDecorationBuiltIn, layout.fBuiltin,
2497 0 : fDecorationBuffer);
2498 : }
2499 0 : }
2500 :
2501 0 : void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int member) {
2502 0 : if (layout.fLocation >= 0) {
2503 0 : this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationLocation,
2504 0 : layout.fLocation, fDecorationBuffer);
2505 : }
2506 0 : if (layout.fBinding >= 0) {
2507 0 : this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBinding,
2508 0 : layout.fBinding, fDecorationBuffer);
2509 : }
2510 0 : if (layout.fIndex >= 0) {
2511 0 : this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationIndex,
2512 0 : layout.fIndex, fDecorationBuffer);
2513 : }
2514 0 : if (layout.fSet >= 0) {
2515 0 : this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationDescriptorSet,
2516 0 : layout.fSet, fDecorationBuffer);
2517 : }
2518 0 : if (layout.fInputAttachmentIndex >= 0) {
2519 0 : this->writeInstruction(SpvOpDecorate, target, member, SpvDecorationInputAttachmentIndex,
2520 0 : layout.fInputAttachmentIndex, fDecorationBuffer);
2521 : }
2522 0 : if (layout.fBuiltin >= 0) {
2523 0 : this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBuiltIn,
2524 0 : layout.fBuiltin, fDecorationBuffer);
2525 : }
2526 0 : }
2527 :
2528 0 : SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
2529 0 : MemoryLayout layout = intf.fVariable.fModifiers.fLayout.fPushConstant ?
2530 : MemoryLayout(MemoryLayout::k430_Standard) :
2531 0 : fDefaultLayout;
2532 0 : SpvId result = this->nextId();
2533 0 : const Type* type = &intf.fVariable.fType;
2534 0 : if (fProgram.fInputs.fRTHeight) {
2535 0 : ASSERT(fRTHeightStructId == (SpvId) -1);
2536 0 : ASSERT(fRTHeightFieldIndex == (SpvId) -1);
2537 0 : std::vector<Type::Field> fields = type->fields();
2538 0 : fRTHeightStructId = result;
2539 0 : fRTHeightFieldIndex = fields.size();
2540 0 : fields.emplace_back(Modifiers(), String(SKSL_RTHEIGHT_NAME), fContext.fFloat_Type.get());
2541 0 : type = new Type(type->fPosition, type->name(), fields);
2542 : }
2543 0 : SpvId typeId = this->getType(*type, layout);
2544 0 : this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBlock, fDecorationBuffer);
2545 0 : SpvStorageClass_ storageClass = get_storage_class(intf.fVariable.fModifiers);
2546 0 : SpvId ptrType = this->nextId();
2547 0 : this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, typeId, fConstantBuffer);
2548 0 : this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer);
2549 0 : this->writeLayout(intf.fVariable.fModifiers.fLayout, result);
2550 0 : fVariableMap[&intf.fVariable] = result;
2551 0 : if (fProgram.fInputs.fRTHeight) {
2552 0 : delete type;
2553 : }
2554 0 : return result;
2555 : }
2556 :
2557 : #define BUILTIN_IGNORE 9999
2558 0 : void SPIRVCodeGenerator::writeGlobalVars(Program::Kind kind, const VarDeclarations& decl,
2559 : OutputStream& out) {
2560 0 : for (size_t i = 0; i < decl.fVars.size(); i++) {
2561 0 : const VarDeclaration& varDecl = decl.fVars[i];
2562 0 : const Variable* var = varDecl.fVar;
2563 : // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2564 : // in the OpenGL backend.
2565 0 : ASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
2566 : Modifiers::kWriteOnly_Flag |
2567 : Modifiers::kCoherent_Flag |
2568 : Modifiers::kVolatile_Flag |
2569 : Modifiers::kRestrict_Flag)));
2570 0 : if (var->fModifiers.fLayout.fBuiltin == BUILTIN_IGNORE) {
2571 0 : continue;
2572 : }
2573 0 : if (var->fModifiers.fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN &&
2574 : kind != Program::kFragment_Kind) {
2575 0 : continue;
2576 : }
2577 0 : if (!var->fReadCount && !var->fWriteCount &&
2578 0 : !(var->fModifiers.fFlags & (Modifiers::kIn_Flag |
2579 : Modifiers::kOut_Flag |
2580 : Modifiers::kUniform_Flag))) {
2581 : // variable is dead and not an input / output var (the Vulkan debug layers complain if
2582 : // we elide an interface var, even if it's dead)
2583 0 : continue;
2584 : }
2585 : SpvStorageClass_ storageClass;
2586 0 : if (var->fModifiers.fFlags & Modifiers::kIn_Flag) {
2587 0 : storageClass = SpvStorageClassInput;
2588 0 : } else if (var->fModifiers.fFlags & Modifiers::kOut_Flag) {
2589 0 : storageClass = SpvStorageClassOutput;
2590 0 : } else if (var->fModifiers.fFlags & Modifiers::kUniform_Flag) {
2591 0 : if (var->fType.kind() == Type::kSampler_Kind) {
2592 0 : storageClass = SpvStorageClassUniformConstant;
2593 : } else {
2594 0 : storageClass = SpvStorageClassUniform;
2595 : }
2596 : } else {
2597 0 : storageClass = SpvStorageClassPrivate;
2598 : }
2599 0 : SpvId id = this->nextId();
2600 0 : fVariableMap[var] = id;
2601 0 : SpvId type = this->getPointerType(var->fType, storageClass);
2602 0 : this->writeInstruction(SpvOpVariable, type, id, storageClass, fConstantBuffer);
2603 0 : this->writeInstruction(SpvOpName, id, var->fName.c_str(), fNameBuffer);
2604 0 : if (var->fType.kind() == Type::kMatrix_Kind) {
2605 0 : this->writeInstruction(SpvOpMemberDecorate, id, (SpvId) i, SpvDecorationColMajor,
2606 0 : fDecorationBuffer);
2607 0 : this->writeInstruction(SpvOpMemberDecorate, id, (SpvId) i, SpvDecorationMatrixStride,
2608 0 : (SpvId) fDefaultLayout.stride(var->fType), fDecorationBuffer);
2609 : }
2610 0 : if (varDecl.fValue) {
2611 0 : ASSERT(!fCurrentBlock);
2612 0 : fCurrentBlock = -1;
2613 0 : SpvId value = this->writeExpression(*varDecl.fValue, fGlobalInitializersBuffer);
2614 0 : this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
2615 0 : fCurrentBlock = 0;
2616 : }
2617 0 : this->writeLayout(var->fModifiers.fLayout, id);
2618 : }
2619 0 : }
2620 :
2621 0 : void SPIRVCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, OutputStream& out) {
2622 0 : for (const auto& varDecl : decl.fVars) {
2623 0 : const Variable* var = varDecl.fVar;
2624 : // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2625 : // in the OpenGL backend.
2626 0 : ASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
2627 : Modifiers::kWriteOnly_Flag |
2628 : Modifiers::kCoherent_Flag |
2629 : Modifiers::kVolatile_Flag |
2630 : Modifiers::kRestrict_Flag)));
2631 0 : SpvId id = this->nextId();
2632 0 : fVariableMap[var] = id;
2633 0 : SpvId type = this->getPointerType(var->fType, SpvStorageClassFunction);
2634 0 : this->writeInstruction(SpvOpVariable, type, id, SpvStorageClassFunction, fVariableBuffer);
2635 0 : this->writeInstruction(SpvOpName, id, var->fName.c_str(), fNameBuffer);
2636 0 : if (varDecl.fValue) {
2637 0 : SpvId value = this->writeExpression(*varDecl.fValue, out);
2638 0 : this->writeInstruction(SpvOpStore, id, value, out);
2639 : }
2640 : }
2641 0 : }
2642 :
2643 0 : void SPIRVCodeGenerator::writeStatement(const Statement& s, OutputStream& out) {
2644 0 : switch (s.fKind) {
2645 : case Statement::kBlock_Kind:
2646 0 : this->writeBlock((Block&) s, out);
2647 0 : break;
2648 : case Statement::kExpression_Kind:
2649 0 : this->writeExpression(*((ExpressionStatement&) s).fExpression, out);
2650 0 : break;
2651 : case Statement::kReturn_Kind:
2652 0 : this->writeReturnStatement((ReturnStatement&) s, out);
2653 0 : break;
2654 : case Statement::kVarDeclarations_Kind:
2655 0 : this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, out);
2656 0 : break;
2657 : case Statement::kIf_Kind:
2658 0 : this->writeIfStatement((IfStatement&) s, out);
2659 0 : break;
2660 : case Statement::kFor_Kind:
2661 0 : this->writeForStatement((ForStatement&) s, out);
2662 0 : break;
2663 : case Statement::kWhile_Kind:
2664 0 : this->writeWhileStatement((WhileStatement&) s, out);
2665 0 : break;
2666 : case Statement::kDo_Kind:
2667 0 : this->writeDoStatement((DoStatement&) s, out);
2668 0 : break;
2669 : case Statement::kBreak_Kind:
2670 0 : this->writeInstruction(SpvOpBranch, fBreakTarget.top(), out);
2671 0 : break;
2672 : case Statement::kContinue_Kind:
2673 0 : this->writeInstruction(SpvOpBranch, fContinueTarget.top(), out);
2674 0 : break;
2675 : case Statement::kDiscard_Kind:
2676 0 : this->writeInstruction(SpvOpKill, out);
2677 0 : break;
2678 : default:
2679 0 : ABORT("unsupported statement: %s", s.description().c_str());
2680 : }
2681 0 : }
2682 :
2683 0 : void SPIRVCodeGenerator::writeBlock(const Block& b, OutputStream& out) {
2684 0 : for (size_t i = 0; i < b.fStatements.size(); i++) {
2685 0 : this->writeStatement(*b.fStatements[i], out);
2686 : }
2687 0 : }
2688 :
2689 0 : void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, OutputStream& out) {
2690 0 : SpvId test = this->writeExpression(*stmt.fTest, out);
2691 0 : SpvId ifTrue = this->nextId();
2692 0 : SpvId ifFalse = this->nextId();
2693 0 : if (stmt.fIfFalse) {
2694 0 : SpvId end = this->nextId();
2695 0 : this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2696 0 : this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2697 0 : this->writeLabel(ifTrue, out);
2698 0 : this->writeStatement(*stmt.fIfTrue, out);
2699 0 : if (fCurrentBlock) {
2700 0 : this->writeInstruction(SpvOpBranch, end, out);
2701 : }
2702 0 : this->writeLabel(ifFalse, out);
2703 0 : this->writeStatement(*stmt.fIfFalse, out);
2704 0 : if (fCurrentBlock) {
2705 0 : this->writeInstruction(SpvOpBranch, end, out);
2706 : }
2707 0 : this->writeLabel(end, out);
2708 : } else {
2709 0 : this->writeInstruction(SpvOpSelectionMerge, ifFalse, SpvSelectionControlMaskNone, out);
2710 0 : this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2711 0 : this->writeLabel(ifTrue, out);
2712 0 : this->writeStatement(*stmt.fIfTrue, out);
2713 0 : if (fCurrentBlock) {
2714 0 : this->writeInstruction(SpvOpBranch, ifFalse, out);
2715 : }
2716 0 : this->writeLabel(ifFalse, out);
2717 : }
2718 0 : }
2719 :
2720 0 : void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, OutputStream& out) {
2721 0 : if (f.fInitializer) {
2722 0 : this->writeStatement(*f.fInitializer, out);
2723 : }
2724 0 : SpvId header = this->nextId();
2725 0 : SpvId start = this->nextId();
2726 0 : SpvId body = this->nextId();
2727 0 : SpvId next = this->nextId();
2728 0 : fContinueTarget.push(next);
2729 0 : SpvId end = this->nextId();
2730 0 : fBreakTarget.push(end);
2731 0 : this->writeInstruction(SpvOpBranch, header, out);
2732 0 : this->writeLabel(header, out);
2733 0 : this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
2734 0 : this->writeInstruction(SpvOpBranch, start, out);
2735 0 : this->writeLabel(start, out);
2736 0 : if (f.fTest) {
2737 0 : SpvId test = this->writeExpression(*f.fTest, out);
2738 0 : this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2739 : }
2740 0 : this->writeLabel(body, out);
2741 0 : this->writeStatement(*f.fStatement, out);
2742 0 : if (fCurrentBlock) {
2743 0 : this->writeInstruction(SpvOpBranch, next, out);
2744 : }
2745 0 : this->writeLabel(next, out);
2746 0 : if (f.fNext) {
2747 0 : this->writeExpression(*f.fNext, out);
2748 : }
2749 0 : this->writeInstruction(SpvOpBranch, header, out);
2750 0 : this->writeLabel(end, out);
2751 0 : fBreakTarget.pop();
2752 0 : fContinueTarget.pop();
2753 0 : }
2754 :
2755 0 : void SPIRVCodeGenerator::writeWhileStatement(const WhileStatement& w, OutputStream& out) {
2756 : // We believe the while loop code below will work, but Skia doesn't actually use them and
2757 : // adequately testing this code in the absence of Skia exercising it isn't straightforward. For
2758 : // the time being, we just fail with an error due to the lack of testing. If you encounter this
2759 : // message, simply remove the error call below to see whether our while loop support actually
2760 : // works.
2761 0 : fErrors.error(w.fPosition, "internal error: while loop support has been disabled in SPIR-V, "
2762 0 : "see SkSLSPIRVCodeGenerator.cpp for details");
2763 :
2764 0 : SpvId header = this->nextId();
2765 0 : SpvId start = this->nextId();
2766 0 : SpvId body = this->nextId();
2767 0 : fContinueTarget.push(start);
2768 0 : SpvId end = this->nextId();
2769 0 : fBreakTarget.push(end);
2770 0 : this->writeInstruction(SpvOpBranch, header, out);
2771 0 : this->writeLabel(header, out);
2772 0 : this->writeInstruction(SpvOpLoopMerge, end, start, SpvLoopControlMaskNone, out);
2773 0 : this->writeInstruction(SpvOpBranch, start, out);
2774 0 : this->writeLabel(start, out);
2775 0 : SpvId test = this->writeExpression(*w.fTest, out);
2776 0 : this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2777 0 : this->writeLabel(body, out);
2778 0 : this->writeStatement(*w.fStatement, out);
2779 0 : if (fCurrentBlock) {
2780 0 : this->writeInstruction(SpvOpBranch, start, out);
2781 : }
2782 0 : this->writeLabel(end, out);
2783 0 : fBreakTarget.pop();
2784 0 : fContinueTarget.pop();
2785 0 : }
2786 :
2787 0 : void SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, OutputStream& out) {
2788 : // We believe the do loop code below will work, but Skia doesn't actually use them and
2789 : // adequately testing this code in the absence of Skia exercising it isn't straightforward. For
2790 : // the time being, we just fail with an error due to the lack of testing. If you encounter this
2791 : // message, simply remove the error call below to see whether our do loop support actually
2792 : // works.
2793 0 : fErrors.error(d.fPosition, "internal error: do loop support has been disabled in SPIR-V, see "
2794 0 : "SkSLSPIRVCodeGenerator.cpp for details");
2795 :
2796 0 : SpvId header = this->nextId();
2797 0 : SpvId start = this->nextId();
2798 0 : SpvId next = this->nextId();
2799 0 : fContinueTarget.push(next);
2800 0 : SpvId end = this->nextId();
2801 0 : fBreakTarget.push(end);
2802 0 : this->writeInstruction(SpvOpBranch, header, out);
2803 0 : this->writeLabel(header, out);
2804 0 : this->writeInstruction(SpvOpLoopMerge, end, start, SpvLoopControlMaskNone, out);
2805 0 : this->writeInstruction(SpvOpBranch, start, out);
2806 0 : this->writeLabel(start, out);
2807 0 : this->writeStatement(*d.fStatement, out);
2808 0 : if (fCurrentBlock) {
2809 0 : this->writeInstruction(SpvOpBranch, next, out);
2810 : }
2811 0 : this->writeLabel(next, out);
2812 0 : SpvId test = this->writeExpression(*d.fTest, out);
2813 0 : this->writeInstruction(SpvOpBranchConditional, test, start, end, out);
2814 0 : this->writeLabel(end, out);
2815 0 : fBreakTarget.pop();
2816 0 : fContinueTarget.pop();
2817 0 : }
2818 :
2819 0 : void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, OutputStream& out) {
2820 0 : if (r.fExpression) {
2821 0 : this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.fExpression, out),
2822 0 : out);
2823 : } else {
2824 0 : this->writeInstruction(SpvOpReturn, out);
2825 : }
2826 0 : }
2827 :
2828 0 : void SPIRVCodeGenerator::writeInstructions(const Program& program, OutputStream& out) {
2829 0 : fGLSLExtendedInstructions = this->nextId();
2830 0 : StringStream body;
2831 0 : std::set<SpvId> interfaceVars;
2832 : // assign IDs to functions
2833 0 : for (size_t i = 0; i < program.fElements.size(); i++) {
2834 0 : if (program.fElements[i]->fKind == ProgramElement::kFunction_Kind) {
2835 0 : FunctionDefinition& f = (FunctionDefinition&) *program.fElements[i];
2836 0 : fFunctionMap[&f.fDeclaration] = this->nextId();
2837 : }
2838 : }
2839 0 : for (size_t i = 0; i < program.fElements.size(); i++) {
2840 0 : if (program.fElements[i]->fKind == ProgramElement::kInterfaceBlock_Kind) {
2841 0 : InterfaceBlock& intf = (InterfaceBlock&) *program.fElements[i];
2842 0 : SpvId id = this->writeInterfaceBlock(intf);
2843 0 : if ((intf.fVariable.fModifiers.fFlags & Modifiers::kIn_Flag) ||
2844 0 : (intf.fVariable.fModifiers.fFlags & Modifiers::kOut_Flag)) {
2845 0 : interfaceVars.insert(id);
2846 : }
2847 : }
2848 : }
2849 0 : for (size_t i = 0; i < program.fElements.size(); i++) {
2850 0 : if (program.fElements[i]->fKind == ProgramElement::kVar_Kind) {
2851 0 : this->writeGlobalVars(program.fKind, ((VarDeclarations&) *program.fElements[i]),
2852 0 : body);
2853 : }
2854 : }
2855 0 : for (size_t i = 0; i < program.fElements.size(); i++) {
2856 0 : if (program.fElements[i]->fKind == ProgramElement::kFunction_Kind) {
2857 0 : this->writeFunction(((FunctionDefinition&) *program.fElements[i]), body);
2858 : }
2859 : }
2860 0 : const FunctionDeclaration* main = nullptr;
2861 0 : for (auto entry : fFunctionMap) {
2862 0 : if (entry.first->fName == "main") {
2863 0 : main = entry.first;
2864 : }
2865 : }
2866 0 : ASSERT(main);
2867 0 : for (auto entry : fVariableMap) {
2868 0 : const Variable* var = entry.first;
2869 0 : if (var->fStorage == Variable::kGlobal_Storage &&
2870 0 : ((var->fModifiers.fFlags & Modifiers::kIn_Flag) ||
2871 0 : (var->fModifiers.fFlags & Modifiers::kOut_Flag))) {
2872 0 : interfaceVars.insert(entry.second);
2873 : }
2874 : }
2875 0 : this->writeCapabilities(out);
2876 0 : this->writeInstruction(SpvOpExtInstImport, fGLSLExtendedInstructions, "GLSL.std.450", out);
2877 0 : this->writeInstruction(SpvOpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450, out);
2878 0 : this->writeOpCode(SpvOpEntryPoint, (SpvId) (3 + (strlen(main->fName.c_str()) + 4) / 4) +
2879 0 : (int32_t) interfaceVars.size(), out);
2880 0 : switch (program.fKind) {
2881 : case Program::kVertex_Kind:
2882 0 : this->writeWord(SpvExecutionModelVertex, out);
2883 0 : break;
2884 : case Program::kFragment_Kind:
2885 0 : this->writeWord(SpvExecutionModelFragment, out);
2886 0 : break;
2887 : case Program::kGeometry_Kind:
2888 0 : this->writeWord(SpvExecutionModelGeometry, out);
2889 0 : break;
2890 : }
2891 0 : this->writeWord(fFunctionMap[main], out);
2892 0 : this->writeString(main->fName.c_str(), out);
2893 0 : for (int var : interfaceVars) {
2894 0 : this->writeWord(var, out);
2895 : }
2896 0 : if (program.fKind == Program::kFragment_Kind) {
2897 0 : this->writeInstruction(SpvOpExecutionMode,
2898 0 : fFunctionMap[main],
2899 : SpvExecutionModeOriginUpperLeft,
2900 0 : out);
2901 : }
2902 0 : for (size_t i = 0; i < program.fElements.size(); i++) {
2903 0 : if (program.fElements[i]->fKind == ProgramElement::kExtension_Kind) {
2904 0 : this->writeInstruction(SpvOpSourceExtension,
2905 0 : ((Extension&) *program.fElements[i]).fName.c_str(),
2906 0 : out);
2907 : }
2908 : }
2909 :
2910 0 : write_stringstream(fExtraGlobalsBuffer, out);
2911 0 : write_stringstream(fNameBuffer, out);
2912 0 : write_stringstream(fDecorationBuffer, out);
2913 0 : write_stringstream(fConstantBuffer, out);
2914 0 : write_stringstream(fExternalFunctionsBuffer, out);
2915 0 : write_stringstream(body, out);
2916 0 : }
2917 :
2918 0 : bool SPIRVCodeGenerator::generateCode() {
2919 0 : ASSERT(!fErrors.errorCount());
2920 0 : this->writeWord(SpvMagicNumber, *fOut);
2921 0 : this->writeWord(SpvVersion, *fOut);
2922 0 : this->writeWord(SKSL_MAGIC, *fOut);
2923 0 : StringStream buffer;
2924 0 : this->writeInstructions(fProgram, buffer);
2925 0 : this->writeWord(fIdCount, *fOut);
2926 0 : this->writeWord(0, *fOut); // reserved, always zero
2927 0 : write_stringstream(buffer, *fOut);
2928 0 : return 0 == fErrors.errorCount();
2929 : }
2930 :
2931 : }
|