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