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