1b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas/*
2b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas * Copyright 2016 Google Inc.
3b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas *
4b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas * Use of this source code is governed by a BSD-style license that can be
5b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas * found in the LICENSE file.
6b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas */
7b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
8b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas#include "SkSLSPIRVCodeGenerator.h"
9b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
10b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas#include "string.h"
11b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
12b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas#include "GLSL.std.450.h"
13b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
14b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas#include "ir/SkSLExpressionStatement.h"
15b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas#include "ir/SkSLExtension.h"
16b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas#include "ir/SkSLIndexExpression.h"
17b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas#include "ir/SkSLVariableReference.h"
185961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas#include "SkSLCompiler.h"
19b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
20b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholasnamespace SkSL {
21b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
22b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas#define SPIRV_DEBUG 0
23b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
24b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholasstatic const int32_t SKSL_MAGIC  = 0x0; // FIXME: we should probably register a magic number
25b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
26b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholasvoid SPIRVCodeGenerator::setupIntrinsics() {
27b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas#define ALL_GLSL(x) std::make_tuple(kGLSL_STD_450_IntrinsicKind, GLSLstd450 ## x, GLSLstd450 ## x, \
28b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                    GLSLstd450 ## x, GLSLstd450 ## x)
29b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas#define BY_TYPE_GLSL(ifFloat, ifInt, ifUInt) std::make_tuple(kGLSL_STD_450_IntrinsicKind, \
30b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                                             GLSLstd450 ## ifFloat, \
31b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                                             GLSLstd450 ## ifInt, \
32b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                                             GLSLstd450 ## ifUInt, \
33b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                                             SpvOpUndef)
34b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas#define SPECIAL(x) std::make_tuple(kSpecial_IntrinsicKind, k ## x ## _SpecialIntrinsic, \
35b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                   k ## x ## _SpecialIntrinsic, k ## x ## _SpecialIntrinsic, \
36b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                   k ## x ## _SpecialIntrinsic)
379e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("round")]         = ALL_GLSL(Round);
389e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("roundEven")]     = ALL_GLSL(RoundEven);
399e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("trunc")]         = ALL_GLSL(Trunc);
409e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("abs")]           = BY_TYPE_GLSL(FAbs, SAbs, SAbs);
419e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("sign")]          = BY_TYPE_GLSL(FSign, SSign, SSign);
429e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("floor")]         = ALL_GLSL(Floor);
439e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("ceil")]          = ALL_GLSL(Ceil);
449e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("fract")]         = ALL_GLSL(Fract);
459e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("radians")]       = ALL_GLSL(Radians);
469e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("degrees")]       = ALL_GLSL(Degrees);
479e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("sin")]           = ALL_GLSL(Sin);
489e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("cos")]           = ALL_GLSL(Cos);
499e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("tan")]           = ALL_GLSL(Tan);
509e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("asin")]          = ALL_GLSL(Asin);
519e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("acos")]          = ALL_GLSL(Acos);
529e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("atan")]          = SPECIAL(Atan);
539e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("sinh")]          = ALL_GLSL(Sinh);
549e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("cosh")]          = ALL_GLSL(Cosh);
559e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("tanh")]          = ALL_GLSL(Tanh);
569e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("asinh")]         = ALL_GLSL(Asinh);
579e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("acosh")]         = ALL_GLSL(Acosh);
589e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("atanh")]         = ALL_GLSL(Atanh);
599e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("pow")]           = ALL_GLSL(Pow);
609e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("exp")]           = ALL_GLSL(Exp);
619e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("log")]           = ALL_GLSL(Log);
629e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("exp2")]          = ALL_GLSL(Exp2);
639e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("log2")]          = ALL_GLSL(Log2);
649e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("sqrt")]          = ALL_GLSL(Sqrt);
659e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("inversesqrt")]   = ALL_GLSL(InverseSqrt);
669e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("determinant")]   = ALL_GLSL(Determinant);
679e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("matrixInverse")] = ALL_GLSL(MatrixInverse);
689e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("mod")]           = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpFMod,
699e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                                                               SpvOpSMod, SpvOpUMod, SpvOpUndef);
709e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("min")]           = BY_TYPE_GLSL(FMin, SMin, UMin);
719e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("max")]           = BY_TYPE_GLSL(FMax, SMax, UMax);
729e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("clamp")]         = BY_TYPE_GLSL(FClamp, SClamp, UClamp);
739e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("dot")]           = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDot,
749e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                                                               SpvOpUndef, SpvOpUndef, SpvOpUndef);
759e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("mix")]           = ALL_GLSL(FMix);
769e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("step")]          = ALL_GLSL(Step);
779e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("smoothstep")]    = ALL_GLSL(SmoothStep);
789e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("fma")]           = ALL_GLSL(Fma);
799e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("frexp")]         = ALL_GLSL(Frexp);
809e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("ldexp")]         = ALL_GLSL(Ldexp);
819e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas
829e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas#define PACK(type) fIntrinsicMap[SkString("pack" #type)] = ALL_GLSL(Pack ## type); \
839e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                   fIntrinsicMap[SkString("unpack" #type)] = ALL_GLSL(Unpack ## type)
84b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    PACK(Snorm4x8);
85b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    PACK(Unorm4x8);
86b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    PACK(Snorm2x16);
87b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    PACK(Unorm2x16);
88b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    PACK(Half2x16);
89b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    PACK(Double2x32);
909e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("length")]      = ALL_GLSL(Length);
919e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("distance")]    = ALL_GLSL(Distance);
929e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("cross")]       = ALL_GLSL(Cross);
939e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("normalize")]   = ALL_GLSL(Normalize);
949e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("faceForward")] = ALL_GLSL(FaceForward);
959e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("reflect")]     = ALL_GLSL(Reflect);
969e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("refract")]     = ALL_GLSL(Refract);
979e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("findLSB")]     = ALL_GLSL(FindILsb);
989e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("findMSB")]     = BY_TYPE_GLSL(FindSMsb, FindSMsb, FindUMsb);
999e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("dFdx")]        = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdx,
1009e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                                                             SpvOpUndef, SpvOpUndef, SpvOpUndef);
1019e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("dFdy")]        = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdy,
1029e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                                                             SpvOpUndef, SpvOpUndef, SpvOpUndef);
1039e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("dFdy")]        = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdy,
1049e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                                                             SpvOpUndef, SpvOpUndef, SpvOpUndef);
1059e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("texture")]     = SPECIAL(Texture);
1069e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas
10764773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel    fIntrinsicMap[SkString("subpassLoad")] = SPECIAL(SubpassLoad);
10864773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel
10964773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel    fIntrinsicMap[SkString("any")]              = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
1109e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                                                                  SpvOpUndef, SpvOpUndef, SpvOpAny);
11164773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel    fIntrinsicMap[SkString("all")]              = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
1129e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                                                                  SpvOpUndef, SpvOpUndef, SpvOpAll);
1139e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("equal")]            = std::make_tuple(kSPIRV_IntrinsicKind,
1149e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                                                                  SpvOpFOrdEqual, SpvOpIEqual,
1159e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                                                                  SpvOpIEqual, SpvOpLogicalEqual);
1169e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("notEqual")]         = std::make_tuple(kSPIRV_IntrinsicKind,
1179e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                                                                  SpvOpFOrdNotEqual, SpvOpINotEqual,
1189e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                                                                  SpvOpINotEqual,
1199e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                                                                  SpvOpLogicalNotEqual);
1209e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("lessThan")]         = std::make_tuple(kSPIRV_IntrinsicKind,
1219e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                                                                  SpvOpSLessThan, SpvOpULessThan,
1229e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                                                                  SpvOpFOrdLessThan, SpvOpUndef);
1239e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("lessThanEqual")]    = std::make_tuple(kSPIRV_IntrinsicKind,
12464773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                                                  SpvOpSLessThanEqual,
1259e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                                                                  SpvOpULessThanEqual,
1269e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                                                                  SpvOpFOrdLessThanEqual,
1279e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                                                                  SpvOpUndef);
1289e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fIntrinsicMap[SkString("greaterThan")]      = std::make_tuple(kSPIRV_IntrinsicKind,
12964773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                                                  SpvOpSGreaterThan,
1309e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                                                                  SpvOpUGreaterThan,
13164773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                                                  SpvOpFOrdGreaterThan,
1329e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                                                                  SpvOpUndef);
13364773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel    fIntrinsicMap[SkString("greaterThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
13464773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                                                  SpvOpSGreaterThanEqual,
13564773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                                                  SpvOpUGreaterThanEqual,
1369e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                                                                  SpvOpFOrdGreaterThanEqual,
1379e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                                                                  SpvOpUndef);
138b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
139b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas// interpolateAt* not yet supported...
140b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
141b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
1429e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholasvoid SPIRVCodeGenerator::writeWord(int32_t word, SkWStream& out) {
143b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas#if SPIRV_DEBUG
144b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    out << "(" << word << ") ";
145b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas#else
146b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    out.write((const char*) &word, sizeof(word));
147b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas#endif
148b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
149b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
150d598f7981f34811e6f2a949207dc13638852f3f7ethannicholasstatic bool is_float(const Context& context, const Type& type) {
151b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    if (type.kind() == Type::kVector_Kind) {
152d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas        return is_float(context, type.componentType());
153b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
154d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    return type == *context.fFloat_Type || type == *context.fDouble_Type;
155b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
156b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
157d598f7981f34811e6f2a949207dc13638852f3f7ethannicholasstatic bool is_signed(const Context& context, const Type& type) {
158b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    if (type.kind() == Type::kVector_Kind) {
159d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas        return is_signed(context, type.componentType());
160b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
161d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    return type == *context.fInt_Type;
162b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
163b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
164d598f7981f34811e6f2a949207dc13638852f3f7ethannicholasstatic bool is_unsigned(const Context& context, const Type& type) {
165b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    if (type.kind() == Type::kVector_Kind) {
166d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas        return is_unsigned(context, type.componentType());
167b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
168d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    return type == *context.fUInt_Type;
169b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
170b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
171d598f7981f34811e6f2a949207dc13638852f3f7ethannicholasstatic bool is_bool(const Context& context, const Type& type) {
172b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    if (type.kind() == Type::kVector_Kind) {
173d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas        return is_bool(context, type.componentType());
174b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
175d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    return type == *context.fBool_Type;
176b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
177b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
178d598f7981f34811e6f2a949207dc13638852f3f7ethannicholasstatic bool is_out(const Variable& var) {
179d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    return (var.fModifiers.fFlags & Modifiers::kOut_Flag) != 0;
180b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
181b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
182b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas#if SPIRV_DEBUG
1839e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholasstatic SkString opcode_text(SpvOp_ opCode) {
184b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    switch (opCode) {
185b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpNop:
1869e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("Nop");
187b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpUndef:
1889e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("Undef");
189b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpSourceContinued:
1909e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("SourceContinued");
191b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpSource:
1929e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("Source");
193b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpSourceExtension:
1949e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("SourceExtension");
195b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpName:
1969e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("Name");
197b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpMemberName:
1989e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("MemberName");
199b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpString:
2009e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("String");
201b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpLine:
2029e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("Line");
203b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpExtension:
2049e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("Extension");
205b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpExtInstImport:
2069e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ExtInstImport");
207b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpExtInst:
2089e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ExtInst");
209b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpMemoryModel:
2109e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("MemoryModel");
211b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpEntryPoint:
2129e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("EntryPoint");
213b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpExecutionMode:
2149e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ExecutionMode");
215b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpCapability:
2169e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("Capability");
217b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTypeVoid:
2189e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("TypeVoid");
219b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTypeBool:
2209e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("TypeBool");
221b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTypeInt:
2229e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("TypeInt");
223b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTypeFloat:
2249e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("TypeFloat");
225b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTypeVector:
2269e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("TypeVector");
227b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTypeMatrix:
2289e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("TypeMatrix");
229b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTypeImage:
2309e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("TypeImage");
231b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTypeSampler:
2329e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("TypeSampler");
233b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTypeSampledImage:
2349e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("TypeSampledImage");
235b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTypeArray:
2369e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("TypeArray");
237b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTypeRuntimeArray:
2389e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("TypeRuntimeArray");
239b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTypeStruct:
2409e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("TypeStruct");
241b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTypeOpaque:
2429e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("TypeOpaque");
243b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTypePointer:
2449e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("TypePointer");
245b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTypeFunction:
2469e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("TypeFunction");
247b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTypeEvent:
2489e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("TypeEvent");
249b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTypeDeviceEvent:
2509e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("TypeDeviceEvent");
251b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTypeReserveId:
2529e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("TypeReserveId");
253b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTypeQueue:
2549e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("TypeQueue");
255b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTypePipe:
2569e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("TypePipe");
257b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTypeForwardPointer:
2589e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("TypeForwardPointer");
259b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpConstantTrue:
2609e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ConstantTrue");
261b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpConstantFalse:
2629e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ConstantFalse");
263b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpConstant:
2649e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("Constant");
265b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpConstantComposite:
2669e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ConstantComposite");
267b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpConstantSampler:
2689e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ConstantSampler");
269b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpConstantNull:
2709e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ConstantNull");
271b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpSpecConstantTrue:
2729e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("SpecConstantTrue");
273b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpSpecConstantFalse:
2749e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("SpecConstantFalse");
275b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpSpecConstant:
2769e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("SpecConstant");
277b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpSpecConstantComposite:
2789e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("SpecConstantComposite");
279b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpSpecConstantOp:
2809e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("SpecConstantOp");
281b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpFunction:
2829e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("Function");
283b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpFunctionParameter:
2849e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("FunctionParameter");
285b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpFunctionEnd:
2869e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("FunctionEnd");
287b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpFunctionCall:
2889e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("FunctionCall");
289b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpVariable:
2909e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("Variable");
291b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImageTexelPointer:
2929e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ImageTexelPointer");
293b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpLoad:
2949e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("Load");
295b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpStore:
2969e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("Store");
297b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpCopyMemory:
2989e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("CopyMemory");
299b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpCopyMemorySized:
3009e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("CopyMemorySized");
301b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpAccessChain:
3029e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("AccessChain");
303b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpInBoundsAccessChain:
3049e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("InBoundsAccessChain");
305b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpPtrAccessChain:
3069e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("PtrAccessChain");
307b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpArrayLength:
3089e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ArrayLength");
309b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpGenericPtrMemSemantics:
3109e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("GenericPtrMemSemantics");
311b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpInBoundsPtrAccessChain:
3129e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("InBoundsPtrAccessChain");
313b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpDecorate:
3149e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("Decorate");
315b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpMemberDecorate:
3169e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("MemberDecorate");
317b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpDecorationGroup:
3189e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("DecorationGroup");
319b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpGroupDecorate:
3209e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("GroupDecorate");
321b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpGroupMemberDecorate:
3229e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("GroupMemberDecorate");
323b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpVectorExtractDynamic:
3249e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("VectorExtractDynamic");
325b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpVectorInsertDynamic:
3269e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("VectorInsertDynamic");
327b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpVectorShuffle:
3289e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("VectorShuffle");
329b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpCompositeConstruct:
3309e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("CompositeConstruct");
331b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpCompositeExtract:
3329e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("CompositeExtract");
333b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpCompositeInsert:
3349e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("CompositeInsert");
335b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpCopyObject:
3369e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("CopyObject");
337b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTranspose:
3389e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("Transpose");
339b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpSampledImage:
3409e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("SampledImage");
341b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImageSampleImplicitLod:
3429e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ImageSampleImplicitLod");
343b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImageSampleExplicitLod:
3449e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ImageSampleExplicitLod");
345b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImageSampleDrefImplicitLod:
3469e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ImageSampleDrefImplicitLod");
347b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImageSampleDrefExplicitLod:
3489e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ImageSampleDrefExplicitLod");
349b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImageSampleProjImplicitLod:
3509e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ImageSampleProjImplicitLod");
351b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImageSampleProjExplicitLod:
3529e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ImageSampleProjExplicitLod");
353b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImageSampleProjDrefImplicitLod:
3549e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ImageSampleProjDrefImplicitLod");
355b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImageSampleProjDrefExplicitLod:
3569e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ImageSampleProjDrefExplicitLod");
357b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImageFetch:
3589e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ImageFetch");
359b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImageGather:
3609e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ImageGather");
361b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImageDrefGather:
3629e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ImageDrefGather");
363b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImageRead:
3649e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ImageRead");
365b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImageWrite:
3669e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ImageWrite");
367b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImage:
3689e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("Image");
369b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImageQueryFormat:
3709e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ImageQueryFormat");
371b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImageQueryOrder:
3729e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ImageQueryOrder");
373b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImageQuerySizeLod:
3749e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ImageQuerySizeLod");
375b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImageQuerySize:
3769e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ImageQuerySize");
377b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImageQueryLod:
3789e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ImageQueryLod");
379b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImageQueryLevels:
3809e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ImageQueryLevels");
381b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImageQuerySamples:
3829e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ImageQuerySamples");
383b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpConvertFToU:
3849e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ConvertFToU");
385b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpConvertFToS:
3869e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ConvertFToS");
387b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpConvertSToF:
3889e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ConvertSToF");
389b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpConvertUToF:
3909e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ConvertUToF");
391b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpUConvert:
3929e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("UConvert");
393b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpSConvert:
3949e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("SConvert");
395b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpFConvert:
3969e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("FConvert");
397b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpQuantizeToF16:
3989e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("QuantizeToF16");
399b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpConvertPtrToU:
4009e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ConvertPtrToU");
401b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpSatConvertSToU:
4029e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("SatConvertSToU");
403b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpSatConvertUToS:
4049e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("SatConvertUToS");
405b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpConvertUToPtr:
4069e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ConvertUToPtr");
407b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpPtrCastToGeneric:
4089e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("PtrCastToGeneric");
409b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpGenericCastToPtr:
4109e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("GenericCastToPtr");
411b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpGenericCastToPtrExplicit:
4129e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("GenericCastToPtrExplicit");
413b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpBitcast:
4149e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("Bitcast");
415b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpSNegate:
4169e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("SNegate");
417b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpFNegate:
4189e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("FNegate");
419b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpIAdd:
4209e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("IAdd");
421b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpFAdd:
4229e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("FAdd");
423b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpISub:
4249e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ISub");
425b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpFSub:
4269e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("FSub");
427b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpIMul:
4289e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("IMul");
429b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpFMul:
4309e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("FMul");
431b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpUDiv:
4329e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("UDiv");
433b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpSDiv:
4349e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("SDiv");
435b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpFDiv:
4369e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("FDiv");
437b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpUMod:
4389e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("UMod");
439b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpSRem:
4409e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("SRem");
441b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpSMod:
4429e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("SMod");
443b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpFRem:
4449e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("FRem");
445b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpFMod:
4469e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("FMod");
447b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpVectorTimesScalar:
4489e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("VectorTimesScalar");
449b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpMatrixTimesScalar:
4509e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("MatrixTimesScalar");
451b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpVectorTimesMatrix:
4529e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("VectorTimesMatrix");
453b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpMatrixTimesVector:
4549e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("MatrixTimesVector");
455b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpMatrixTimesMatrix:
4569e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("MatrixTimesMatrix");
457b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpOuterProduct:
4589e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("OuterProduct");
459b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpDot:
4609e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("Dot");
461b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpIAddCarry:
4629e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("IAddCarry");
463b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpISubBorrow:
4649e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ISubBorrow");
465b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpUMulExtended:
4669e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("UMulExtended");
467b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpSMulExtended:
4689e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("SMulExtended");
469b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpAny:
4709e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("Any");
471b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpAll:
4729e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("All");
473b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpIsNan:
4749e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("IsNan");
475b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpIsInf:
4769e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("IsInf");
477b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpIsFinite:
4789e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("IsFinite");
479b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpIsNormal:
4809e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("IsNormal");
481b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpSignBitSet:
4829e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("SignBitSet");
483b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpLessOrGreater:
4849e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("LessOrGreater");
485b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpOrdered:
4869e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("Ordered");
487b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpUnordered:
4889e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("Unordered");
489b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpLogicalEqual:
4909e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("LogicalEqual");
491b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpLogicalNotEqual:
4929e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("LogicalNotEqual");
493b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpLogicalOr:
4949e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("LogicalOr");
495b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpLogicalAnd:
4969e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("LogicalAnd");
497b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpLogicalNot:
4989e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("LogicalNot");
499b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpSelect:
5009e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("Select");
501b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpIEqual:
5029e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("IEqual");
503b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpINotEqual:
5049e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("INotEqual");
505b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpUGreaterThan:
5069e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("UGreaterThan");
507b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpSGreaterThan:
5089e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("SGreaterThan");
509b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpUGreaterThanEqual:
5109e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("UGreaterThanEqual");
511b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpSGreaterThanEqual:
5129e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("SGreaterThanEqual");
513b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpULessThan:
5149e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ULessThan");
515b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpSLessThan:
5169e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("SLessThan");
517b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpULessThanEqual:
5189e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ULessThanEqual");
519b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpSLessThanEqual:
5209e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("SLessThanEqual");
521b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpFOrdEqual:
5229e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("FOrdEqual");
523b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpFUnordEqual:
5249e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("FUnordEqual");
525b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpFOrdNotEqual:
5269e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("FOrdNotEqual");
527b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpFUnordNotEqual:
5289e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("FUnordNotEqual");
529b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpFOrdLessThan:
5309e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("FOrdLessThan");
531b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpFUnordLessThan:
5329e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("FUnordLessThan");
533b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpFOrdGreaterThan:
5349e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("FOrdGreaterThan");
535b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpFUnordGreaterThan:
5369e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("FUnordGreaterThan");
537b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpFOrdLessThanEqual:
5389e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("FOrdLessThanEqual");
539b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpFUnordLessThanEqual:
5409e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("FUnordLessThanEqual");
541b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpFOrdGreaterThanEqual:
5429e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("FOrdGreaterThanEqual");
543b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpFUnordGreaterThanEqual:
5449e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("FUnordGreaterThanEqual");
545b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpShiftRightLogical:
5469e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ShiftRightLogical");
547b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpShiftRightArithmetic:
5489e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ShiftRightArithmetic");
549b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpShiftLeftLogical:
5509e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ShiftLeftLogical");
551b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpBitwiseOr:
5529e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("BitwiseOr");
553b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpBitwiseXor:
5549e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("BitwiseXor");
555b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpBitwiseAnd:
5569e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("BitwiseAnd");
557b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpNot:
5589e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("Not");
559b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpBitFieldInsert:
5609e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("BitFieldInsert");
561b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpBitFieldSExtract:
5629e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("BitFieldSExtract");
563b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpBitFieldUExtract:
5649e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("BitFieldUExtract");
565b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpBitReverse:
5669e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("BitReverse");
567b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpBitCount:
5689e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("BitCount");
569b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpDPdx:
5709e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("DPdx");
571b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpDPdy:
5729e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("DPdy");
573b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpFwidth:
5749e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("Fwidth");
575b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpDPdxFine:
5769e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("DPdxFine");
577b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpDPdyFine:
5789e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("DPdyFine");
579b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpFwidthFine:
5809e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("FwidthFine");
581b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpDPdxCoarse:
5829e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("DPdxCoarse");
583b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpDPdyCoarse:
5849e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("DPdyCoarse");
585b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpFwidthCoarse:
5869e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("FwidthCoarse");
587b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpEmitVertex:
5889e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("EmitVertex");
589b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpEndPrimitive:
5909e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("EndPrimitive");
591b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpEmitStreamVertex:
5929e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("EmitStreamVertex");
593b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpEndStreamPrimitive:
5949e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("EndStreamPrimitive");
595b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpControlBarrier:
5969e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ControlBarrier");
597b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpMemoryBarrier:
5989e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("MemoryBarrier");
599b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpAtomicLoad:
6009e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("AtomicLoad");
601b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpAtomicStore:
6029e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("AtomicStore");
603b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpAtomicExchange:
6049e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("AtomicExchange");
605b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpAtomicCompareExchange:
6069e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("AtomicCompareExchange");
607b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpAtomicCompareExchangeWeak:
6089e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("AtomicCompareExchangeWeak");
609b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpAtomicIIncrement:
6109e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("AtomicIIncrement");
611b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpAtomicIDecrement:
6129e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("AtomicIDecrement");
613b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpAtomicIAdd:
6149e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("AtomicIAdd");
615b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpAtomicISub:
6169e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("AtomicISub");
617b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpAtomicSMin:
6189e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("AtomicSMin");
619b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpAtomicUMin:
6209e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("AtomicUMin");
621b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpAtomicSMax:
6229e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("AtomicSMax");
623b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpAtomicUMax:
6249e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("AtomicUMax");
625b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpAtomicAnd:
6269e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("AtomicAnd");
627b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpAtomicOr:
6289e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("AtomicOr");
629b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpAtomicXor:
6309e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("AtomicXor");
631b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpPhi:
6329e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("Phi");
633b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpLoopMerge:
6349e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("LoopMerge");
635b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpSelectionMerge:
6369e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("SelectionMerge");
637b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpLabel:
6389e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("Label");
639b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpBranch:
6409e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("Branch");
641b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpBranchConditional:
6429e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("BranchConditional");
643b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpSwitch:
6449e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("Switch");
645b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpKill:
6469e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("Kill");
647b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpReturn:
6489e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("Return");
649b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpReturnValue:
6509e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ReturnValue");
651b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpUnreachable:
6529e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("Unreachable");
653b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpLifetimeStart:
6549e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("LifetimeStart");
655b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpLifetimeStop:
6569e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("LifetimeStop");
657b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpGroupAsyncCopy:
6589e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("GroupAsyncCopy");
659b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpGroupWaitEvents:
6609e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("GroupWaitEvents");
661b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpGroupAll:
6629e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("GroupAll");
663b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpGroupAny:
6649e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("GroupAny");
665b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpGroupBroadcast:
6669e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("GroupBroadcast");
667b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpGroupIAdd:
6689e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("GroupIAdd");
669b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpGroupFAdd:
6709e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("GroupFAdd");
671b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpGroupFMin:
6729e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("GroupFMin");
673b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpGroupUMin:
6749e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("GroupUMin");
675b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpGroupSMin:
6769e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("GroupSMin");
677b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpGroupFMax:
6789e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("GroupFMax");
679b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpGroupUMax:
6809e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("GroupUMax");
681b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpGroupSMax:
6829e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("GroupSMax");
683b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpReadPipe:
6849e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ReadPipe");
685b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpWritePipe:
6869e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("WritePipe");
687b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpReservedReadPipe:
6889e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ReservedReadPipe");
689b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpReservedWritePipe:
6909e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ReservedWritePipe");
691b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpReserveReadPipePackets:
6929e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ReserveReadPipePackets");
693b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpReserveWritePipePackets:
6949e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ReserveWritePipePackets");
695b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpCommitReadPipe:
6969e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("CommitReadPipe");
697b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpCommitWritePipe:
6989e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("CommitWritePipe");
699b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpIsValidReserveId:
7009e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("IsValidReserveId");
701b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpGetNumPipePackets:
7029e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("GetNumPipePackets");
703b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpGetMaxPipePackets:
7049e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("GetMaxPipePackets");
705b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpGroupReserveReadPipePackets:
7069e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("GroupReserveReadPipePackets");
707b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpGroupReserveWritePipePackets:
7089e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("GroupReserveWritePipePackets");
709b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpGroupCommitReadPipe:
7109e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("GroupCommitReadPipe");
711b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpGroupCommitWritePipe:
7129e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("GroupCommitWritePipe");
713b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpEnqueueMarker:
7149e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("EnqueueMarker");
715b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpEnqueueKernel:
7169e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("EnqueueKernel");
717b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpGetKernelNDrangeSubGroupCount:
7189e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("GetKernelNDrangeSubGroupCount");
719b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpGetKernelNDrangeMaxSubGroupSize:
7209e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("GetKernelNDrangeMaxSubGroupSize");
721b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpGetKernelWorkGroupSize:
7229e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("GetKernelWorkGroupSize");
723b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpGetKernelPreferredWorkGroupSizeMultiple:
7249e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("GetKernelPreferredWorkGroupSizeMultiple");
725b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpRetainEvent:
7269e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("RetainEvent");
727b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpReleaseEvent:
7289e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ReleaseEvent");
729b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpCreateUserEvent:
7309e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("CreateUserEvent");
731b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpIsValidEvent:
7329e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("IsValidEvent");
733b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpSetUserEventStatus:
7349e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("SetUserEventStatus");
735b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpCaptureEventProfilingInfo:
7369e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("CaptureEventProfilingInfo");
737b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpGetDefaultQueue:
7389e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("GetDefaultQueue");
739b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpBuildNDRange:
7409e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("BuildNDRange");
741b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImageSparseSampleImplicitLod:
7429e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ImageSparseSampleImplicitLod");
743b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImageSparseSampleExplicitLod:
7449e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ImageSparseSampleExplicitLod");
745b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImageSparseSampleDrefImplicitLod:
7469e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ImageSparseSampleDrefImplicitLod");
747b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImageSparseSampleDrefExplicitLod:
7489e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ImageSparseSampleDrefExplicitLod");
749b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImageSparseSampleProjImplicitLod:
7509e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ImageSparseSampleProjImplicitLod");
751b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImageSparseSampleProjExplicitLod:
7529e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ImageSparseSampleProjExplicitLod");
753b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImageSparseSampleProjDrefImplicitLod:
7549e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ImageSparseSampleProjDrefImplicitLod");
755b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImageSparseSampleProjDrefExplicitLod:
7569e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ImageSparseSampleProjDrefExplicitLod");
757b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImageSparseFetch:
7589e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ImageSparseFetch");
759b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImageSparseGather:
7609e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ImageSparseGather");
761b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImageSparseDrefGather:
7629e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ImageSparseDrefGather");
763b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImageSparseTexelsResident:
7649e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ImageSparseTexelsResident");
765b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpNoLine:
7669e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("NoLine");
767b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpAtomicFlagTestAndSet:
7689e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("AtomicFlagTestAndSet");
769b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpAtomicFlagClear:
7709e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("AtomicFlagClear");
771b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpImageSparseRead:
7729e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            return SkString("ImageSparseRead");
773b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        default:
774b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            ABORT("unsupported SPIR-V op");
775b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
776b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
777b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas#endif
778b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
7799e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholasvoid SPIRVCodeGenerator::writeOpCode(SpvOp_ opCode, int length, SkWStream& out) {
780b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ASSERT(opCode != SpvOpUndef);
781b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    switch (opCode) {
782b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpReturn:      // fall through
783b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpReturnValue: // fall through
784552882f768b02a2aa20552a765913187851e382bethannicholas        case SpvOpKill:        // fall through
785b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpBranch:      // fall through
786b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpBranchConditional:
787b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            ASSERT(fCurrentBlock);
788b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            fCurrentBlock = 0;
789b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            break;
790b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpConstant:          // fall through
791b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpConstantTrue:      // fall through
792b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpConstantFalse:     // fall through
793b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpConstantComposite: // fall through
794b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTypeVoid:          // fall through
795b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTypeInt:           // fall through
796b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTypeFloat:         // fall through
797b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTypeBool:          // fall through
798b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTypeVector:        // fall through
799b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTypeMatrix:        // fall through
800b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTypeArray:         // fall through
801b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTypePointer:       // fall through
802b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTypeFunction:      // fall through
803b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTypeRuntimeArray:  // fall through
804b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTypeStruct:        // fall through
805b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTypeImage:         // fall through
806b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpTypeSampledImage:  // fall through
807b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpVariable:          // fall through
808b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpFunction:          // fall through
809b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpFunctionParameter: // fall through
810b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpFunctionEnd:       // fall through
811b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpExecutionMode:     // fall through
812b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpMemoryModel:       // fall through
813b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpCapability:        // fall through
814b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpExtInstImport:     // fall through
815b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpEntryPoint:        // fall through
816b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpSource:            // fall through
817b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpSourceExtension:   // fall through
818b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpName:              // fall through
819b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpMemberName:        // fall through
820b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpDecorate:          // fall through
821b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case SpvOpMemberDecorate:
822b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            break;
823b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        default:
824b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            ASSERT(fCurrentBlock);
825b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
826b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas#if SPIRV_DEBUG
827b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    out << std::endl << opcode_text(opCode) << " ";
828b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas#else
829b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord((length << 16) | opCode, out);
830b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas#endif
831b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
832b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
8339e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholasvoid SPIRVCodeGenerator::writeLabel(SpvId label, SkWStream& out) {
834b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    fCurrentBlock = label;
835b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeInstruction(SpvOpLabel, label, out);
836b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
837b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
8389e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholasvoid SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, SkWStream& out) {
839b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeOpCode(opCode, 1, out);
840b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
841b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
8429e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholasvoid SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, SkWStream& out) {
843b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeOpCode(opCode, 2, out);
844b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word1, out);
845b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
846b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
8479e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholasvoid SPIRVCodeGenerator::writeString(const char* string, SkWStream& out) {
848b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    size_t length = strlen(string);
8499e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    out.writeText(string);
850b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    switch (length % 4) {
851b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case 1:
8529e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            out.write8(0);
853b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            // fall through
854b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case 2:
8559e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            out.write8(0);
856b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            // fall through
857b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case 3:
8589e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            out.write8(0);
859b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            break;
860b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        default:
861b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeWord(0, out);
862b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
863b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
864b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
8659e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholasvoid SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, const char* string, SkWStream& out) {
866b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    int32_t length = (int32_t) strlen(string);
867b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeOpCode(opCode, 1 + (length + 4) / 4, out);
868b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeString(string, out);
869b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
870b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
871b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
87264773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Danielvoid SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, const char* string,
8739e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                                          SkWStream& out) {
874b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    int32_t length = (int32_t) strlen(string);
875b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeOpCode(opCode, 2 + (length + 4) / 4, out);
876b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word1, out);
877b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeString(string, out);
878b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
879b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
88064773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Danielvoid SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
8819e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                                          const char* string, SkWStream& out) {
882b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    int32_t length = (int32_t) strlen(string);
883b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeOpCode(opCode, 3 + (length + 4) / 4, out);
884b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word1, out);
885b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word2, out);
886b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeString(string, out);
887b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
888b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
88964773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Danielvoid SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
8909e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                                          SkWStream& out) {
891b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeOpCode(opCode, 3, out);
892b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word1, out);
893b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word2, out);
894b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
895b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
89664773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Danielvoid SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
8979e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                                          int32_t word3, SkWStream& out) {
898b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeOpCode(opCode, 4, out);
899b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word1, out);
900b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word2, out);
901b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word3, out);
902b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
903b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
90464773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Danielvoid SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
9059e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                                          int32_t word3, int32_t word4, SkWStream& out) {
906b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeOpCode(opCode, 5, out);
907b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word1, out);
908b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word2, out);
909b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word3, out);
910b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word4, out);
911b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
912b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
91364773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Danielvoid SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
91464773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                          int32_t word3, int32_t word4, int32_t word5,
9159e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                                          SkWStream& out) {
916b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeOpCode(opCode, 6, out);
917b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word1, out);
918b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word2, out);
919b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word3, out);
920b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word4, out);
921b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word5, out);
922b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
923b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
92464773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Danielvoid SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
925b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                          int32_t word3, int32_t word4, int32_t word5,
9269e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                                          int32_t word6, SkWStream& out) {
927b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeOpCode(opCode, 7, out);
928b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word1, out);
929b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word2, out);
930b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word3, out);
931b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word4, out);
932b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word5, out);
933b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word6, out);
934b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
935b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
93664773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Danielvoid SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
937b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                          int32_t word3, int32_t word4, int32_t word5,
9389e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                                          int32_t word6, int32_t word7, SkWStream& out) {
939b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeOpCode(opCode, 8, out);
940b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word1, out);
941b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word2, out);
942b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word3, out);
943b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word4, out);
944b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word5, out);
945b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word6, out);
946b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word7, out);
947b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
948b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
94964773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Danielvoid SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
950b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                          int32_t word3, int32_t word4, int32_t word5,
951b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                          int32_t word6, int32_t word7, int32_t word8,
9529e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                                          SkWStream& out) {
953b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeOpCode(opCode, 9, out);
954b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word1, out);
955b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word2, out);
956b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word3, out);
957b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word4, out);
958b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word5, out);
959b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word6, out);
960b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word7, out);
961b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(word8, out);
962b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
963b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
9649e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholasvoid SPIRVCodeGenerator::writeCapabilities(SkWStream& out) {
965b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    for (uint64_t i = 0, bit = 1; i <= kLast_Capability; i++, bit <<= 1) {
966b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        if (fCapabilities & bit) {
967b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeInstruction(SpvOpCapability, (SpvId) i, out);
968b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
969b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
970b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
971b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
972b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholasSpvId SPIRVCodeGenerator::nextId() {
973b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    return fIdCount++;
974b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
975b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
97619671772c1a03bd973fae54dead4defc9ee1d4c3Ethan Nicholasvoid SPIRVCodeGenerator::writeStruct(const Type& type, const MemoryLayout& memoryLayout,
97719671772c1a03bd973fae54dead4defc9ee1d4c3Ethan Nicholas                                     SpvId resultId) {
978b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeInstruction(SpvOpName, resultId, type.name().c_str(), fNameBuffer);
979b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    // go ahead and write all of the field types, so we don't inadvertently write them while we're
980b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    // in the middle of writing the struct instruction
981b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    std::vector<SpvId> types;
982b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    for (const auto& f : type.fields()) {
98319671772c1a03bd973fae54dead4defc9ee1d4c3Ethan Nicholas        types.push_back(this->getType(*f.fType, memoryLayout));
984b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
985b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeOpCode(SpvOpTypeStruct, 2 + (int32_t) types.size(), fConstantBuffer);
986b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(resultId, fConstantBuffer);
987b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    for (SpvId id : types) {
988b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeWord(id, fConstantBuffer);
989b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
990b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    size_t offset = 0;
991b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    for (int32_t i = 0; i < (int32_t) type.fields().size(); i++) {
99219671772c1a03bd973fae54dead4defc9ee1d4c3Ethan Nicholas        size_t size = memoryLayout.size(*type.fields()[i].fType);
99319671772c1a03bd973fae54dead4defc9ee1d4c3Ethan Nicholas        size_t alignment = memoryLayout.alignment(*type.fields()[i].fType);
99419671772c1a03bd973fae54dead4defc9ee1d4c3Ethan Nicholas        const Layout& fieldLayout = type.fields()[i].fModifiers.fLayout;
99519671772c1a03bd973fae54dead4defc9ee1d4c3Ethan Nicholas        if (fieldLayout.fOffset >= 0) {
996dbd44c78ec98adc07569d430f3b27e0834186a7eGreg Daniel            if (fieldLayout.fOffset < (int) offset) {
997941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                fErrors.error(type.fPosition,
998941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                              "offset of field '" + type.fields()[i].fName + "' must be at "
999941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                              "least " + to_string((int) offset));
100019671772c1a03bd973fae54dead4defc9ee1d4c3Ethan Nicholas            }
100119671772c1a03bd973fae54dead4defc9ee1d4c3Ethan Nicholas            if (fieldLayout.fOffset % alignment) {
1002941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                fErrors.error(type.fPosition,
1003941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                              "offset of field '" + type.fields()[i].fName + "' must be a multiple"
1004941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                              " of " + to_string((int) alignment));
100519671772c1a03bd973fae54dead4defc9ee1d4c3Ethan Nicholas            }
100619671772c1a03bd973fae54dead4defc9ee1d4c3Ethan Nicholas            offset = fieldLayout.fOffset;
100719671772c1a03bd973fae54dead4defc9ee1d4c3Ethan Nicholas        } else {
100819671772c1a03bd973fae54dead4defc9ee1d4c3Ethan Nicholas            size_t mod = offset % alignment;
100919671772c1a03bd973fae54dead4defc9ee1d4c3Ethan Nicholas            if (mod) {
101019671772c1a03bd973fae54dead4defc9ee1d4c3Ethan Nicholas                offset += alignment - mod;
101119671772c1a03bd973fae54dead4defc9ee1d4c3Ethan Nicholas            }
1012b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
1013b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeInstruction(SpvOpMemberName, resultId, i, type.fields()[i].fName.c_str(),
1014b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                               fNameBuffer);
101519671772c1a03bd973fae54dead4defc9ee1d4c3Ethan Nicholas        this->writeLayout(fieldLayout, resultId, i);
1016b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        if (type.fields()[i].fModifiers.fLayout.fBuiltin < 0) {
101764773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i, SpvDecorationOffset,
1018b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                   (SpvId) offset, fDecorationBuffer);
1019b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
10200730be7c303ac415484b15ef44ff1dce077a93b8ethannicholas        if (type.fields()[i].fType->kind() == Type::kMatrix_Kind) {
102164773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationColMajor,
1022b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                   fDecorationBuffer);
102364773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationMatrixStride,
102419671772c1a03bd973fae54dead4defc9ee1d4c3Ethan Nicholas                                   (SpvId) memoryLayout.stride(*type.fields()[i].fType),
10258ac838d978578c44b75a801489c985e5284dd66fethannicholas                                   fDecorationBuffer);
1026b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
1027b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        offset += size;
10280730be7c303ac415484b15ef44ff1dce077a93b8ethannicholas        Type::Kind kind = type.fields()[i].fType->kind();
1029b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        if ((kind == Type::kArray_Kind || kind == Type::kStruct_Kind) && offset % alignment != 0) {
1030b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            offset += alignment - offset % alignment;
1031b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
1032b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1033b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
1034b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
1035b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholasSpvId SPIRVCodeGenerator::getType(const Type& type) {
10368ac838d978578c44b75a801489c985e5284dd66fethannicholas    return this->getType(type, fDefaultLayout);
10378ac838d978578c44b75a801489c985e5284dd66fethannicholas}
10388ac838d978578c44b75a801489c985e5284dd66fethannicholas
10398ac838d978578c44b75a801489c985e5284dd66fethannicholasSpvId SPIRVCodeGenerator::getType(const Type& type, const MemoryLayout& layout) {
10408ac838d978578c44b75a801489c985e5284dd66fethannicholas    SkString key = type.name() + to_string((int) layout.fStd);
10418ac838d978578c44b75a801489c985e5284dd66fethannicholas    auto entry = fTypeMap.find(key);
1042b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    if (entry == fTypeMap.end()) {
1043b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        SpvId result = this->nextId();
1044b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        switch (type.kind()) {
1045b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            case Type::kScalar_Kind:
1046d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas                if (type == *fContext.fBool_Type) {
1047b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                    this->writeInstruction(SpvOpTypeBool, result, fConstantBuffer);
1048d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas                } else if (type == *fContext.fInt_Type) {
1049b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                    this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
1050d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas                } else if (type == *fContext.fUInt_Type) {
1051b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                    this->writeInstruction(SpvOpTypeInt, result, 32, 0, fConstantBuffer);
1052d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas                } else if (type == *fContext.fFloat_Type) {
1053b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                    this->writeInstruction(SpvOpTypeFloat, result, 32, fConstantBuffer);
1054d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas                } else if (type == *fContext.fDouble_Type) {
1055b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                    this->writeInstruction(SpvOpTypeFloat, result, 64, fConstantBuffer);
1056b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                } else {
1057b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                    ASSERT(false);
1058b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                }
1059b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                break;
1060b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            case Type::kVector_Kind:
106164773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                this->writeInstruction(SpvOpTypeVector, result,
10628ac838d978578c44b75a801489c985e5284dd66fethannicholas                                       this->getType(type.componentType(), layout),
1063b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                       type.columns(), fConstantBuffer);
1064b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                break;
1065b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            case Type::kMatrix_Kind:
106664773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                this->writeInstruction(SpvOpTypeMatrix, result,
10678ac838d978578c44b75a801489c985e5284dd66fethannicholas                                       this->getType(index_type(fContext, type), layout),
1068b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                       type.columns(), fConstantBuffer);
1069b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                break;
1070b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            case Type::kStruct_Kind:
10718ac838d978578c44b75a801489c985e5284dd66fethannicholas                this->writeStruct(type, layout, result);
1072b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                break;
1073b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            case Type::kArray_Kind: {
1074b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                if (type.columns() > 0) {
1075d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas                    IntLiteral count(fContext, Position(), type.columns());
107664773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                    this->writeInstruction(SpvOpTypeArray, result,
10778ac838d978578c44b75a801489c985e5284dd66fethannicholas                                           this->getType(type.componentType(), layout),
1078b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                           this->writeIntLiteral(count), fConstantBuffer);
107964773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                    this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
10808ac838d978578c44b75a801489c985e5284dd66fethannicholas                                           (int32_t) layout.stride(type),
10818ac838d978578c44b75a801489c985e5284dd66fethannicholas                                           fDecorationBuffer);
1082b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                } else {
1083b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                    ABORT("runtime-sized arrays are not yet supported");
108464773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                    this->writeInstruction(SpvOpTypeRuntimeArray, result,
10858ac838d978578c44b75a801489c985e5284dd66fethannicholas                                           this->getType(type.componentType(), layout),
10868ac838d978578c44b75a801489c985e5284dd66fethannicholas                                           fConstantBuffer);
1087b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                }
1088b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                break;
1089b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            }
1090b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            case Type::kSampler_Kind: {
109164773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                SpvId image = result;
109264773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                if (SpvDimSubpassData != type.dimensions()) {
109364773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                    image = this->nextId();
109464773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                }
10958ac838d978578c44b75a801489c985e5284dd66fethannicholas                this->writeInstruction(SpvOpTypeImage, image,
10968ac838d978578c44b75a801489c985e5284dd66fethannicholas                                       this->getType(*fContext.fFloat_Type, layout),
1097b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                       type.dimensions(), type.isDepth(), type.isArrayed(),
109864773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                       type.isMultisampled(), type.isSampled() ? 1 : 2,
1099b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                       SpvImageFormatUnknown, fConstantBuffer);
110064773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                if (SpvDimSubpassData != type.dimensions()) {
110164773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                    this->writeInstruction(SpvOpTypeSampledImage, result, image, fConstantBuffer);
110264773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                }
1103b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                break;
1104b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            }
1105b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            default:
1106d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas                if (type == *fContext.fVoid_Type) {
1107b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                    this->writeInstruction(SpvOpTypeVoid, result, fConstantBuffer);
1108b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                } else {
1109b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                    ABORT("invalid type: %s", type.description().c_str());
1110b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                }
1111b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
11128ac838d978578c44b75a801489c985e5284dd66fethannicholas        fTypeMap[key] = result;
1113b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        return result;
1114b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1115b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    return entry->second;
1116b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
1117b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
1118d598f7981f34811e6f2a949207dc13638852f3f7ethannicholasSpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) {
11199e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    SkString key = function.fReturnType.description() + "(";
11209e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    SkString separator;
1121d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    for (size_t i = 0; i < function.fParameters.size(); i++) {
1122b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        key += separator;
1123b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        separator = ", ";
1124d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas        key += function.fParameters[i]->fType.description();
1125b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1126b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    key += ")";
1127b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    auto entry = fTypeMap.find(key);
1128b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    if (entry == fTypeMap.end()) {
1129b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        SpvId result = this->nextId();
1130d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas        int32_t length = 3 + (int32_t) function.fParameters.size();
1131d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas        SpvId returnType = this->getType(function.fReturnType);
1132b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        std::vector<SpvId> parameterTypes;
1133d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas        for (size_t i = 0; i < function.fParameters.size(); i++) {
113464773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            // glslang seems to treat all function arguments as pointers whether they need to be or
113564773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            // not. I  was initially puzzled by this until I ran bizarre failures with certain
113664773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            // patterns of function calls and control constructs, as exemplified by this minimal
1137b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            // failure case:
1138b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            //
1139b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            // void sphere(float x) {
1140b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            // }
114164773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            //
1142b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            // void map() {
1143b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            //     sphere(1.0);
1144b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            // }
114564773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            //
1146b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            // void main() {
1147b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            //     for (int i = 0; i < 1; i++) {
1148b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            //         map();
1149b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            //     }
1150b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            // }
1151b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            //
115264773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            // As of this writing, compiling this in the "obvious" way (with sphere taking a float)
115364773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            // crashes. Making it take a float* and storing the argument in a temporary variable,
1154b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            // as glslang does, fixes it. It's entirely possible I simply missed whichever part of
1155b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            // the spec makes this make sense.
1156b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas//            if (is_out(function->fParameters[i])) {
1157d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas                parameterTypes.push_back(this->getPointerType(function.fParameters[i]->fType,
1158b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                                              SpvStorageClassFunction));
1159b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas//            } else {
1160d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas//                parameterTypes.push_back(this->getType(function.fParameters[i]->fType));
1161b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas//            }
1162b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
1163b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeOpCode(SpvOpTypeFunction, length, fConstantBuffer);
1164b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeWord(result, fConstantBuffer);
1165b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeWord(returnType, fConstantBuffer);
1166b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        for (SpvId id : parameterTypes) {
1167b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeWord(id, fConstantBuffer);
1168b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
1169b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        fTypeMap[key] = result;
1170b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        return result;
1171b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1172b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    return entry->second;
1173b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
1174b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
11758ac838d978578c44b75a801489c985e5284dd66fethannicholasSpvId SPIRVCodeGenerator::getPointerType(const Type& type, SpvStorageClass_ storageClass) {
11768ac838d978578c44b75a801489c985e5284dd66fethannicholas    return this->getPointerType(type, fDefaultLayout, storageClass);
11778ac838d978578c44b75a801489c985e5284dd66fethannicholas}
11788ac838d978578c44b75a801489c985e5284dd66fethannicholas
11798ac838d978578c44b75a801489c985e5284dd66fethannicholasSpvId SPIRVCodeGenerator::getPointerType(const Type& type, const MemoryLayout& layout,
1180b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                         SpvStorageClass_ storageClass) {
11818ac838d978578c44b75a801489c985e5284dd66fethannicholas    SkString key = type.description() + "*" + to_string(layout.fStd) + to_string(storageClass);
1182b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    auto entry = fTypeMap.find(key);
1183b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    if (entry == fTypeMap.end()) {
1184b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        SpvId result = this->nextId();
118564773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel        this->writeInstruction(SpvOpTypePointer, result, storageClass,
1186d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas                               this->getType(type), fConstantBuffer);
1187b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        fTypeMap[key] = result;
1188b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        return result;
1189b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1190b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    return entry->second;
1191b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
1192b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
11939e1138d56665d13641f8805cd72ae81adc255f79Ethan NicholasSpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, SkWStream& out) {
1194b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    switch (expr.fKind) {
1195b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Expression::kBinary_Kind:
1196b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return this->writeBinaryExpression((BinaryExpression&) expr, out);
1197b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Expression::kBoolLiteral_Kind:
1198b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return this->writeBoolLiteral((BoolLiteral&) expr);
1199b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Expression::kConstructor_Kind:
1200b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return this->writeConstructor((Constructor&) expr, out);
1201b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Expression::kIntLiteral_Kind:
1202b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return this->writeIntLiteral((IntLiteral&) expr);
1203b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Expression::kFieldAccess_Kind:
1204b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return this->writeFieldAccess(((FieldAccess&) expr), out);
1205b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Expression::kFloatLiteral_Kind:
1206b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return this->writeFloatLiteral(((FloatLiteral&) expr));
1207b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Expression::kFunctionCall_Kind:
1208b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return this->writeFunctionCall((FunctionCall&) expr, out);
1209b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Expression::kPrefix_Kind:
1210b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return this->writePrefixExpression((PrefixExpression&) expr, out);
1211b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Expression::kPostfix_Kind:
1212b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return this->writePostfixExpression((PostfixExpression&) expr, out);
1213b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Expression::kSwizzle_Kind:
1214b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return this->writeSwizzle((Swizzle&) expr, out);
1215b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Expression::kVariableReference_Kind:
1216b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return this->writeVariableReference((VariableReference&) expr, out);
1217b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Expression::kTernary_Kind:
1218b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return this->writeTernaryExpression((TernaryExpression&) expr, out);
1219b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Expression::kIndex_Kind:
1220b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return this->writeIndexExpression((IndexExpression&) expr, out);
1221b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        default:
1222b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            ABORT("unsupported expression: %s", expr.description().c_str());
1223b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1224b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    return -1;
1225b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
1226b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
12279e1138d56665d13641f8805cd72ae81adc255f79Ethan NicholasSpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, SkWStream& out) {
1228d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    auto intrinsic = fIntrinsicMap.find(c.fFunction.fName);
1229b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ASSERT(intrinsic != fIntrinsicMap.end());
1230d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    const Type& type = c.fArguments[0]->fType;
1231b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    int32_t intrinsicId;
1232d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    if (std::get<0>(intrinsic->second) == kSpecial_IntrinsicKind || is_float(fContext, type)) {
1233b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        intrinsicId = std::get<1>(intrinsic->second);
1234d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    } else if (is_signed(fContext, type)) {
1235b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        intrinsicId = std::get<2>(intrinsic->second);
1236d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    } else if (is_unsigned(fContext, type)) {
1237b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        intrinsicId = std::get<3>(intrinsic->second);
1238d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    } else if (is_bool(fContext, type)) {
1239b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        intrinsicId = std::get<4>(intrinsic->second);
1240b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    } else {
1241b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        ABORT("invalid call %s, cannot operate on '%s'", c.description().c_str(),
1242d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas              type.description().c_str());
1243b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1244b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    switch (std::get<0>(intrinsic->second)) {
1245b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case kGLSL_STD_450_IntrinsicKind: {
1246b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            SpvId result = this->nextId();
1247b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            std::vector<SpvId> arguments;
1248b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            for (size_t i = 0; i < c.fArguments.size(); i++) {
1249b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1250b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            }
1251b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
1252d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas            this->writeWord(this->getType(c.fType), out);
1253b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeWord(result, out);
1254b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeWord(fGLSLExtendedInstructions, out);
1255b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeWord(intrinsicId, out);
1256b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            for (SpvId id : arguments) {
1257b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                this->writeWord(id, out);
1258b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            }
1259b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return result;
1260b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
1261b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case kSPIRV_IntrinsicKind: {
1262b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            SpvId result = this->nextId();
1263b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            std::vector<SpvId> arguments;
1264b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            for (size_t i = 0; i < c.fArguments.size(); i++) {
1265b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1266b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            }
1267b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeOpCode((SpvOp_) intrinsicId, 3 + (int32_t) arguments.size(), out);
1268d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas            this->writeWord(this->getType(c.fType), out);
1269b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeWord(result, out);
1270b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            for (SpvId id : arguments) {
1271b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                this->writeWord(id, out);
1272b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            }
1273b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return result;
1274b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
1275b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case kSpecial_IntrinsicKind:
1276b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId, out);
1277b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        default:
1278b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            ABORT("unsupported intrinsic kind");
1279b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1280b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
1281b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
128264773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg DanielSpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind,
12839e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                                                SkWStream& out) {
1284b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId result = this->nextId();
1285b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    switch (kind) {
1286b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case kAtan_SpecialIntrinsic: {
1287b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            std::vector<SpvId> arguments;
1288b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            for (size_t i = 0; i < c.fArguments.size(); i++) {
1289b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1290b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            }
1291b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
1292d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas            this->writeWord(this->getType(c.fType), out);
1293b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeWord(result, out);
1294b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeWord(fGLSLExtendedInstructions, out);
1295b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeWord(arguments.size() == 2 ? GLSLstd450Atan2 : GLSLstd450Atan, out);
1296b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            for (SpvId id : arguments) {
1297b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                this->writeWord(id, out);
1298b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            }
129964773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            return result;
1300b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
1301b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case kTexture_SpecialIntrinsic: {
13022b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas            SpvOp_ op = SpvOpImageSampleImplicitLod;
13032b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas            switch (c.fArguments[0]->fType.dimensions()) {
13042b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                case SpvDim1D:
13052b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                    if (c.fArguments[1]->fType == *fContext.fVec2_Type) {
13062b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                        op = SpvOpImageSampleProjImplicitLod;
13072b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                    } else {
13082b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                        ASSERT(c.fArguments[1]->fType == *fContext.fFloat_Type);
13092b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                    }
13102b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                    break;
13112b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                case SpvDim2D:
13122b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                    if (c.fArguments[1]->fType == *fContext.fVec3_Type) {
13132b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                        op = SpvOpImageSampleProjImplicitLod;
13142b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                    } else {
13152b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                        ASSERT(c.fArguments[1]->fType == *fContext.fVec2_Type);
13162b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                    }
13172b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                    break;
13182b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                case SpvDim3D:
13192b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                    if (c.fArguments[1]->fType == *fContext.fVec4_Type) {
13202b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                        op = SpvOpImageSampleProjImplicitLod;
13212b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                    } else {
13222b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                        ASSERT(c.fArguments[1]->fType == *fContext.fVec3_Type);
13232b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                    }
13242b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                    break;
13252b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                case SpvDimCube:   // fall through
13262b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                case SpvDimRect:   // fall through
13272b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                case SpvDimBuffer: // fall through
13282b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                case SpvDimSubpassData:
13292b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                    break;
1330b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            }
1331d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas            SpvId type = this->getType(c.fType);
1332b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            SpvId sampler = this->writeExpression(*c.fArguments[0], out);
1333b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            SpvId uv = this->writeExpression(*c.fArguments[1], out);
1334b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            if (c.fArguments.size() == 3) {
13352b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                this->writeInstruction(op, type, result, sampler, uv,
1336b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                       SpvImageOperandsBiasMask,
1337b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                       this->writeExpression(*c.fArguments[2], out),
1338b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                       out);
1339b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            } else {
1340b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                ASSERT(c.fArguments.size() == 2);
13412b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                this->writeInstruction(op, type, result, sampler, uv,
1342b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                       out);
1343b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            }
1344b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            break;
1345b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
134664773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel        case kSubpassLoad_SpecialIntrinsic: {
134764773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            SpvId img = this->writeExpression(*c.fArguments[0], out);
134864773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            std::vector<std::unique_ptr<Expression>> args;
134964773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            args.emplace_back(new FloatLiteral(fContext, Position(), 0.0));
135064773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            args.emplace_back(new FloatLiteral(fContext, Position(), 0.0));
135164773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            Constructor ctor(Position(), *fContext.fVec2_Type, std::move(args));
135264773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            SpvId coords = this->writeConstantVector(ctor);
135364773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            if (1 == c.fArguments.size()) {
135464773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                this->writeInstruction(SpvOpImageRead,
135564773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                       this->getType(c.fType),
135664773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                       result,
135764773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                       img,
135864773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                       coords,
135964773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                       out);
136064773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            } else {
136164773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                SkASSERT(2 == c.fArguments.size());
136264773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                SpvId sample = this->writeExpression(*c.fArguments[1], out);
136364773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                this->writeInstruction(SpvOpImageRead,
136464773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                       this->getType(c.fType),
136564773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                       result,
136664773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                       img,
136764773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                       coords,
136864773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                       SpvImageOperandsSampleMask,
136964773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                       sample,
137064773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                       out);
137164773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            }
137264773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            break;
137364773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel        }
1374b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1375b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    return result;
1376b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
1377b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
13789e1138d56665d13641f8805cd72ae81adc255f79Ethan NicholasSpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, SkWStream& out) {
1379d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    const auto& entry = fFunctionMap.find(&c.fFunction);
1380b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    if (entry == fFunctionMap.end()) {
1381b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        return this->writeIntrinsicCall(c, out);
1382b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1383b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    // stores (variable, type, lvalue) pairs to extract and save after the function call is complete
1384b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    std::vector<std::tuple<SpvId, SpvId, std::unique_ptr<LValue>>> lvalues;
1385b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    std::vector<SpvId> arguments;
1386b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    for (size_t i = 0; i < c.fArguments.size(); i++) {
138764773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel        // id of temporary variable that we will use to hold this argument, or 0 if it is being
1388b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        // passed directly
1389b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        SpvId tmpVar;
1390b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        // if we need a temporary var to store this argument, this is the value to store in the var
1391b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        SpvId tmpValueId;
1392d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas        if (is_out(*c.fFunction.fParameters[i])) {
1393b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            std::unique_ptr<LValue> lv = this->getLValue(*c.fArguments[i], out);
1394b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            SpvId ptr = lv->getPointer();
1395b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            if (ptr) {
1396b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                arguments.push_back(ptr);
1397b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                continue;
1398b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            } else {
1399b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                // lvalue cannot simply be read and written via a pointer (e.g. a swizzle). Need to
1400b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                // copy it into a temp, call the function, read the value out of the temp, and then
1401b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                // update the lvalue.
1402b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                tmpValueId = lv->load(out);
1403b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                tmpVar = this->nextId();
1404d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas                lvalues.push_back(std::make_tuple(tmpVar, this->getType(c.fArguments[i]->fType),
1405b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                  std::move(lv)));
1406b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            }
1407b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        } else {
1408b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            // see getFunctionType for an explanation of why we're always using pointer parameters
1409b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            tmpValueId = this->writeExpression(*c.fArguments[i], out);
1410b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            tmpVar = this->nextId();
1411b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
141264773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel        this->writeInstruction(SpvOpVariable,
141364773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                               this->getPointerType(c.fArguments[i]->fType,
1414b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                                    SpvStorageClassFunction),
141564773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                               tmpVar,
1416b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                               SpvStorageClassFunction,
1417d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas                               fVariableBuffer);
1418b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeInstruction(SpvOpStore, tmpVar, tmpValueId, out);
1419b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        arguments.push_back(tmpVar);
1420b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1421b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId result = this->nextId();
1422b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeOpCode(SpvOpFunctionCall, 4 + (int32_t) c.fArguments.size(), out);
1423d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    this->writeWord(this->getType(c.fType), out);
1424b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(result, out);
1425b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(entry->second, out);
1426b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    for (SpvId id : arguments) {
1427b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeWord(id, out);
1428b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1429b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    // now that the call is complete, we may need to update some lvalues with the new values of out
1430b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    // arguments
1431b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    for (const auto& tuple : lvalues) {
1432b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        SpvId load = this->nextId();
1433b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeInstruction(SpvOpLoad, std::get<1>(tuple), load, std::get<0>(tuple), out);
1434b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        std::get<2>(tuple)->store(load, out);
1435b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1436b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    return result;
1437b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
1438b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
1439f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasSpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) {
1440d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    ASSERT(c.fType.kind() == Type::kVector_Kind && c.isConstant());
1441b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId result = this->nextId();
1442b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    std::vector<SpvId> arguments;
1443b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    for (size_t i = 0; i < c.fArguments.size(); i++) {
1444b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        arguments.push_back(this->writeExpression(*c.fArguments[i], fConstantBuffer));
1445b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1446d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    SpvId type = this->getType(c.fType);
1447b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    if (c.fArguments.size() == 1) {
1448b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        // with a single argument, a vector will have all of its entries equal to the argument
1449d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas        this->writeOpCode(SpvOpConstantComposite, 3 + c.fType.columns(), fConstantBuffer);
1450b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeWord(type, fConstantBuffer);
1451b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeWord(result, fConstantBuffer);
1452d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas        for (int i = 0; i < c.fType.columns(); i++) {
1453b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeWord(arguments[0], fConstantBuffer);
1454b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
1455b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    } else {
145664773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel        this->writeOpCode(SpvOpConstantComposite, 3 + (int32_t) c.fArguments.size(),
1457b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                          fConstantBuffer);
1458b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeWord(type, fConstantBuffer);
1459b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeWord(result, fConstantBuffer);
1460b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        for (SpvId id : arguments) {
1461b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeWord(id, fConstantBuffer);
1462b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
1463b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1464b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    return result;
1465b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
1466b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
14679e1138d56665d13641f8805cd72ae81adc255f79Ethan NicholasSpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, SkWStream& out) {
1468d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    ASSERT(c.fType == *fContext.fFloat_Type);
1469b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ASSERT(c.fArguments.size() == 1);
1470d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    ASSERT(c.fArguments[0]->fType.isNumber());
1471b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId result = this->nextId();
1472b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId parameter = this->writeExpression(*c.fArguments[0], out);
1473d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    if (c.fArguments[0]->fType == *fContext.fInt_Type) {
147464773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel        this->writeInstruction(SpvOpConvertSToF, this->getType(c.fType), result, parameter,
1475b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                               out);
1476d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    } else if (c.fArguments[0]->fType == *fContext.fUInt_Type) {
147764773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel        this->writeInstruction(SpvOpConvertUToF, this->getType(c.fType), result, parameter,
1478b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                               out);
1479d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    } else if (c.fArguments[0]->fType == *fContext.fFloat_Type) {
1480b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        return parameter;
1481b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1482b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    return result;
1483b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
1484b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
14859e1138d56665d13641f8805cd72ae81adc255f79Ethan NicholasSpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, SkWStream& out) {
1486d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    ASSERT(c.fType == *fContext.fInt_Type);
1487b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ASSERT(c.fArguments.size() == 1);
1488d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    ASSERT(c.fArguments[0]->fType.isNumber());
1489b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId result = this->nextId();
1490b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId parameter = this->writeExpression(*c.fArguments[0], out);
1491d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    if (c.fArguments[0]->fType == *fContext.fFloat_Type) {
149264773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel        this->writeInstruction(SpvOpConvertFToS, this->getType(c.fType), result, parameter,
1493b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                               out);
1494d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    } else if (c.fArguments[0]->fType == *fContext.fUInt_Type) {
149564773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel        this->writeInstruction(SpvOpSatConvertUToS, this->getType(c.fType), result, parameter,
1496b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                               out);
1497d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    } else if (c.fArguments[0]->fType == *fContext.fInt_Type) {
1498b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        return parameter;
1499b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1500b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    return result;
1501b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
1502b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
150384645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholasvoid SPIRVCodeGenerator::writeUniformScaleMatrix(SpvId id, SpvId diagonal, const Type& type,
150484645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholas                                                 SkWStream& out) {
150584645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholas    FloatLiteral zero(fContext, Position(), 0);
150684645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholas    SpvId zeroId = this->writeFloatLiteral(zero);
150784645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholas    std::vector<SpvId> columnIds;
150884645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholas    for (int column = 0; column < type.columns(); column++) {
150984645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholas        this->writeOpCode(SpvOpCompositeConstruct, 3 + type.rows(),
151084645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholas                          out);
151184645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholas        this->writeWord(this->getType(type.componentType().toCompound(fContext, type.rows(), 1)),
151284645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholas                        out);
151384645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholas        SpvId columnId = this->nextId();
151484645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholas        this->writeWord(columnId, out);
151584645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholas        columnIds.push_back(columnId);
151684645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholas        for (int row = 0; row < type.columns(); row++) {
151784645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholas            this->writeWord(row == column ? diagonal : zeroId, out);
151884645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholas        }
151984645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholas    }
152084645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholas    this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(),
152184645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholas                      out);
152284645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholas    this->writeWord(this->getType(type), out);
152384645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholas    this->writeWord(id, out);
152484645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholas    for (SpvId id : columnIds) {
152584645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholas        this->writeWord(id, out);
152684645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholas    }
152784645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholas}
152884645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholas
152984645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholasvoid SPIRVCodeGenerator::writeMatrixCopy(SpvId id, SpvId src, const Type& srcType,
153084645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholas                                         const Type& dstType, SkWStream& out) {
153184645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholas    ABORT("unimplemented");
153284645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholas}
153384645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholas
15349e1138d56665d13641f8805cd72ae81adc255f79Ethan NicholasSpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, SkWStream& out) {
1535d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    ASSERT(c.fType.kind() == Type::kMatrix_Kind);
1536b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    // go ahead and write the arguments so we don't try to write new instructions in the middle of
1537b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    // an instruction
1538b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    std::vector<SpvId> arguments;
1539b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    for (size_t i = 0; i < c.fArguments.size(); i++) {
1540b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1541b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1542b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId result = this->nextId();
1543d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    int rows = c.fType.rows();
1544d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    int columns = c.fType.columns();
154584645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholas    if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) {
154684645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholas        this->writeUniformScaleMatrix(result, arguments[0], c.fType, out);
154784645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholas    } else if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kMatrix_Kind) {
154884645e3c679581d191406b2d7ab93c3f6c5e3a63Ethan Nicholas        this->writeMatrixCopy(result, arguments[0], c.fArguments[0]->fType, c.fType, out);
1549b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    } else {
1550b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        std::vector<SpvId> columnIds;
1551b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        int currentCount = 0;
1552b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        for (size_t i = 0; i < arguments.size(); i++) {
1553d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas            if (c.fArguments[i]->fType.kind() == Type::kVector_Kind) {
1554b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                ASSERT(currentCount == 0);
1555b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                columnIds.push_back(arguments[i]);
1556b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                currentCount = 0;
1557b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            } else {
1558d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas                ASSERT(c.fArguments[i]->fType.kind() == Type::kScalar_Kind);
1559b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                if (currentCount == 0) {
1560d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas                    this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.rows(), out);
156164773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                    this->writeWord(this->getType(c.fType.componentType().toCompound(fContext, rows,
156264773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                                                                     1)),
1563b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                    out);
1564b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                    SpvId id = this->nextId();
1565b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                    this->writeWord(id, out);
1566b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                    columnIds.push_back(id);
1567b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                }
1568b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                this->writeWord(arguments[i], out);
1569b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                currentCount = (currentCount + 1) % rows;
1570b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            }
1571b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
1572b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        ASSERT(columnIds.size() == (size_t) columns);
1573b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeOpCode(SpvOpCompositeConstruct, 3 + columns, out);
1574d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas        this->writeWord(this->getType(c.fType), out);
1575b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeWord(result, out);
1576b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        for (SpvId id : columnIds) {
1577b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeWord(id, out);
1578b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
1579b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1580b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    return result;
1581b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
1582b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
15839e1138d56665d13641f8805cd72ae81adc255f79Ethan NicholasSpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, SkWStream& out) {
1584d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    ASSERT(c.fType.kind() == Type::kVector_Kind);
1585b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    if (c.isConstant()) {
1586b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        return this->writeConstantVector(c);
1587b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1588b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    // go ahead and write the arguments so we don't try to write new instructions in the middle of
1589b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    // an instruction
1590b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    std::vector<SpvId> arguments;
1591b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    for (size_t i = 0; i < c.fArguments.size(); i++) {
1592b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1593b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1594b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId result = this->nextId();
1595d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) {
1596d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas        this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.columns(), out);
1597d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas        this->writeWord(this->getType(c.fType), out);
1598b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeWord(result, out);
1599d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas        for (int i = 0; i < c.fType.columns(); i++) {
1600b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeWord(arguments[0], out);
1601b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
1602b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    } else {
1603b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) c.fArguments.size(), out);
1604d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas        this->writeWord(this->getType(c.fType), out);
1605b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeWord(result, out);
1606b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        for (SpvId id : arguments) {
1607b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeWord(id, out);
1608b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
1609b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1610b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    return result;
1611b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
1612b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
16139e1138d56665d13641f8805cd72ae81adc255f79Ethan NicholasSpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, SkWStream& out) {
1614d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    if (c.fType == *fContext.fFloat_Type) {
1615b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        return this->writeFloatConstructor(c, out);
1616d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    } else if (c.fType == *fContext.fInt_Type) {
1617b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        return this->writeIntConstructor(c, out);
1618b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1619d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    switch (c.fType.kind()) {
1620b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Type::kVector_Kind:
1621b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return this->writeVectorConstructor(c, out);
1622b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Type::kMatrix_Kind:
1623b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return this->writeMatrixConstructor(c, out);
1624b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        default:
1625b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            ABORT("unsupported constructor: %s", c.description().c_str());
1626b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1627b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
1628b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
1629b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholasSpvStorageClass_ get_storage_class(const Modifiers& modifiers) {
1630b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    if (modifiers.fFlags & Modifiers::kIn_Flag) {
16318ac838d978578c44b75a801489c985e5284dd66fethannicholas        ASSERT(!modifiers.fLayout.fPushConstant);
1632b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        return SpvStorageClassInput;
1633b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
16348ac838d978578c44b75a801489c985e5284dd66fethannicholas        ASSERT(!modifiers.fLayout.fPushConstant);
1635b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        return SpvStorageClassOutput;
1636b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    } else if (modifiers.fFlags & Modifiers::kUniform_Flag) {
16378ac838d978578c44b75a801489c985e5284dd66fethannicholas        if (modifiers.fLayout.fPushConstant) {
16388ac838d978578c44b75a801489c985e5284dd66fethannicholas            return SpvStorageClassPushConstant;
16398ac838d978578c44b75a801489c985e5284dd66fethannicholas        }
1640b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        return SpvStorageClassUniform;
1641b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    } else {
1642b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        return SpvStorageClassFunction;
1643b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1644b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
1645b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
1646f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasSpvStorageClass_ get_storage_class(const Expression& expr) {
1647b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    switch (expr.fKind) {
1648b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Expression::kVariableReference_Kind:
1649d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas            return get_storage_class(((VariableReference&) expr).fVariable.fModifiers);
1650b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Expression::kFieldAccess_Kind:
1651b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return get_storage_class(*((FieldAccess&) expr).fBase);
1652b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Expression::kIndex_Kind:
1653b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return get_storage_class(*((IndexExpression&) expr).fBase);
1654b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        default:
1655b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return SpvStorageClassFunction;
1656b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1657b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
1658b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
16599e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholasstd::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, SkWStream& out) {
1660b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    std::vector<SpvId> chain;
1661b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    switch (expr.fKind) {
1662b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Expression::kIndex_Kind: {
1663b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            IndexExpression& indexExpr = (IndexExpression&) expr;
1664b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            chain = this->getAccessChain(*indexExpr.fBase, out);
1665b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            chain.push_back(this->writeExpression(*indexExpr.fIndex, out));
1666b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            break;
1667b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
1668b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Expression::kFieldAccess_Kind: {
1669b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            FieldAccess& fieldExpr = (FieldAccess&) expr;
1670b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            chain = this->getAccessChain(*fieldExpr.fBase, out);
1671d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas            IntLiteral index(fContext, Position(), fieldExpr.fFieldIndex);
1672b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            chain.push_back(this->writeIntLiteral(index));
1673b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            break;
1674b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
1675b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        default:
1676b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            chain.push_back(this->getLValue(expr, out)->getPointer());
1677b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1678b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    return chain;
1679b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
1680b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
1681b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholasclass PointerLValue : public SPIRVCodeGenerator::LValue {
1682b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholaspublic:
168364773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel    PointerLValue(SPIRVCodeGenerator& gen, SpvId pointer, SpvId type)
1684b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    : fGen(gen)
1685b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    , fPointer(pointer)
1686b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    , fType(type) {}
1687b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
1688b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    virtual SpvId getPointer() override {
1689b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        return fPointer;
1690b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1691b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
16929e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    virtual SpvId load(SkWStream& out) override {
1693b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        SpvId result = fGen.nextId();
1694b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        fGen.writeInstruction(SpvOpLoad, fType, result, fPointer, out);
1695b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        return result;
1696b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1697b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
16989e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    virtual void store(SpvId value, SkWStream& out) override {
1699b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        fGen.writeInstruction(SpvOpStore, fPointer, value, out);
1700b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1701b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
1702b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholasprivate:
1703b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SPIRVCodeGenerator& fGen;
1704b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    const SpvId fPointer;
1705b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    const SpvId fType;
1706b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas};
1707b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
1708b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholasclass SwizzleLValue : public SPIRVCodeGenerator::LValue {
1709b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholaspublic:
171064773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel    SwizzleLValue(SPIRVCodeGenerator& gen, SpvId vecPointer, const std::vector<int>& components,
1711b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                  const Type& baseType, const Type& swizzleType)
1712b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    : fGen(gen)
1713b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    , fVecPointer(vecPointer)
1714b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    , fComponents(components)
1715b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    , fBaseType(baseType)
1716b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    , fSwizzleType(swizzleType) {}
1717b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
1718b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    virtual SpvId getPointer() override {
1719b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        return 0;
1720b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1721b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
17229e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    virtual SpvId load(SkWStream& out) override {
1723b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        SpvId base = fGen.nextId();
1724b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1725b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        SpvId result = fGen.nextId();
1726b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        fGen.writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) fComponents.size(), out);
1727b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        fGen.writeWord(fGen.getType(fSwizzleType), out);
1728b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        fGen.writeWord(result, out);
1729b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        fGen.writeWord(base, out);
1730b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        fGen.writeWord(base, out);
1731b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        for (int component : fComponents) {
1732b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            fGen.writeWord(component, out);
1733b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
1734b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        return result;
1735b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1736b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
17379e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    virtual void store(SpvId value, SkWStream& out) override {
1738b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        // use OpVectorShuffle to mix and match the vector components. We effectively create
1739b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        // a virtual vector out of the concatenation of the left and right vectors, and then
174064773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel        // select components from this virtual vector to make the result vector. For
1741b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        // instance, given:
1742b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        // vec3 L = ...;
1743b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        // vec3 R = ...;
1744b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        // L.xz = R.xy;
174564773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel        // we end up with the virtual vector (L.x, L.y, L.z, R.x, R.y, R.z). Then we want
1746b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        // our result vector to look like (R.x, L.y, R.y), so we need to select indices
1747b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        // (3, 1, 4).
1748b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        SpvId base = fGen.nextId();
1749b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1750b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        SpvId shuffle = fGen.nextId();
1751b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        fGen.writeOpCode(SpvOpVectorShuffle, 5 + fBaseType.columns(), out);
1752b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        fGen.writeWord(fGen.getType(fBaseType), out);
1753b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        fGen.writeWord(shuffle, out);
1754b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        fGen.writeWord(base, out);
1755b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        fGen.writeWord(value, out);
1756b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        for (int i = 0; i < fBaseType.columns(); i++) {
1757b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            // current offset into the virtual vector, defaults to pulling the unmodified
1758b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            // value from the left side
1759b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            int offset = i;
1760b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            // check to see if we are writing this component
1761b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            for (size_t j = 0; j < fComponents.size(); j++) {
1762b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                if (fComponents[j] == i) {
176364773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                    // we're writing to this component, so adjust the offset to pull from
1764b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                    // the correct component of the right side instead of preserving the
1765b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                    // value from the left
1766b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                    offset = (int) (j + fBaseType.columns());
1767b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                    break;
1768b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                }
1769b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            }
1770b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            fGen.writeWord(offset, out);
1771b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
1772b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        fGen.writeInstruction(SpvOpStore, fVecPointer, shuffle, out);
1773b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1774b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
1775b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholasprivate:
1776b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SPIRVCodeGenerator& fGen;
1777b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    const SpvId fVecPointer;
1778b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    const std::vector<int>& fComponents;
1779b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    const Type& fBaseType;
1780b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    const Type& fSwizzleType;
1781b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas};
1782b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
178364773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Danielstd::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const Expression& expr,
17849e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                                                                          SkWStream& out) {
1785b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    switch (expr.fKind) {
1786b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Expression::kVariableReference_Kind: {
1787d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas            const Variable& var = ((VariableReference&) expr).fVariable;
1788d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas            auto entry = fVariableMap.find(&var);
1789b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            ASSERT(entry != fVariableMap.end());
1790b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1791b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                                                       *this,
179264773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                                                       entry->second,
1793d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas                                                                       this->getType(expr.fType)));
1794b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
1795b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Expression::kIndex_Kind: // fall through
1796b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Expression::kFieldAccess_Kind: {
1797b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            std::vector<SpvId> chain = this->getAccessChain(expr, out);
1798b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            SpvId member = this->nextId();
1799b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeOpCode(SpvOpAccessChain, (SpvId) (3 + chain.size()), out);
180064773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            this->writeWord(this->getPointerType(expr.fType, get_storage_class(expr)), out);
1801b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeWord(member, out);
1802b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            for (SpvId idx : chain) {
1803b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                this->writeWord(idx, out);
1804b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            }
1805b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1806b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                                                       *this,
180764773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                                                       member,
1808d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas                                                                       this->getType(expr.fType)));
1809b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
1810b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
1811b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Expression::kSwizzle_Kind: {
1812b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            Swizzle& swizzle = (Swizzle&) expr;
1813b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            size_t count = swizzle.fComponents.size();
1814b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            SpvId base = this->getLValue(*swizzle.fBase, out)->getPointer();
1815b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            ASSERT(base);
1816b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            if (count == 1) {
1817d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas                IntLiteral index(fContext, Position(), swizzle.fComponents[0]);
1818b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                SpvId member = this->nextId();
1819b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                this->writeInstruction(SpvOpAccessChain,
182064773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                       this->getPointerType(swizzle.fType,
182164773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                                            get_storage_class(*swizzle.fBase)),
182264773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                       member,
182364773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                       base,
182464773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                       this->writeIntLiteral(index),
1825b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                       out);
1826b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1827b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                                                       *this,
182864773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                                                       member,
1829d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas                                                                       this->getType(expr.fType)));
1830b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            } else {
1831b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                return std::unique_ptr<SPIRVCodeGenerator::LValue>(new SwizzleLValue(
183264773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                                                              *this,
183364773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                                                              base,
183464773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                                                              swizzle.fComponents,
1835d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas                                                                              swizzle.fBase->fType,
1836d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas                                                                              expr.fType));
1837b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            }
1838b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
1839b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
1840b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        default:
1841b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            // expr isn't actually an lvalue, create a dummy variable for it. This case happens due
184264773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            // to the need to store values in temporary variables during function calls (see
1843b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            // comments in getFunctionType); erroneous uses of rvalues as lvalues should have been
1844b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            // caught by IRGenerator
1845b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            SpvId result = this->nextId();
1846b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            SpvId type = this->getPointerType(expr.fType, SpvStorageClassFunction);
1847d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas            this->writeInstruction(SpvOpVariable, type, result, SpvStorageClassFunction,
1848d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas                                   fVariableBuffer);
1849b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeInstruction(SpvOpStore, result, this->writeExpression(expr, out), out);
1850b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1851b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                                                       *this,
185264773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                                                       result,
1853d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas                                                                       this->getType(expr.fType)));
1854b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1855b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
1856b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
18579e1138d56665d13641f8805cd72ae81adc255f79Ethan NicholasSpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, SkWStream& out) {
1858941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    SpvId result = this->nextId();
1859d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    auto entry = fVariableMap.find(&ref.fVariable);
1860b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ASSERT(entry != fVariableMap.end());
1861b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId var = entry->second;
1862d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    this->writeInstruction(SpvOpLoad, this->getType(ref.fVariable.fType), result, var, out);
1863941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
1864941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        fProgram.fSettings.fFlipY) {
1865941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        // need to remap to a top-left coordinate system
1866941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        if (fRTHeightStructId == (SpvId) -1) {
1867941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            // height variable hasn't been written yet
1868941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            std::shared_ptr<SymbolTable> st(new SymbolTable(fErrors));
1869941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            ASSERT(fRTHeightFieldIndex == (SpvId) -1);
1870941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            std::vector<Type::Field> fields;
1871941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            fields.emplace_back(Modifiers(), SkString(SKSL_RTHEIGHT_NAME),
1872941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                                fContext.fFloat_Type.get());
1873941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            SkString name("sksl_synthetic_uniforms");
1874941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            Type intfStruct(Position(), name, fields);
1875941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            Layout layout(-1, -1, 1, -1, -1, -1, -1, false, false, false, Layout::Format::kUnspecified,
187652cad15d0b4443b763a7d41ec8d1131a7638f866Ethan Nicholas                          false, Layout::kUnspecified_Primitive, -1, -1);
1877941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            Variable intfVar(Position(), Modifiers(layout, Modifiers::kUniform_Flag), name,
1878941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                             intfStruct, Variable::kGlobal_Storage);
187950afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas            InterfaceBlock intf(Position(), intfVar, name, SkString(""),
188050afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas                                std::vector<std::unique_ptr<Expression>>(), st);
1881941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            fRTHeightStructId = this->writeInterfaceBlock(intf);
1882941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            fRTHeightFieldIndex = 0;
1883941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        }
1884941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        ASSERT(fRTHeightFieldIndex != (SpvId) -1);
1885941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        // write vec4(gl_FragCoord.x, u_skRTHeight - gl_FragCoord.y, 0.0, 1.0)
1886941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        SpvId xId = this->nextId();
1887941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), xId,
1888941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                               result, 0, out);
1889941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        IntLiteral fieldIndex(fContext, Position(), fRTHeightFieldIndex);
1890941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        SpvId fieldIndexId = this->writeIntLiteral(fieldIndex);
1891613a697ed124296620b2280533fad2eef776ba54Ethan Nicholas        SpvId heightPtr = this->nextId();
1892941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        this->writeOpCode(SpvOpAccessChain, 5, out);
1893941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        this->writeWord(this->getPointerType(*fContext.fFloat_Type, SpvStorageClassUniform), out);
1894613a697ed124296620b2280533fad2eef776ba54Ethan Nicholas        this->writeWord(heightPtr, out);
1895941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        this->writeWord(fRTHeightStructId, out);
1896941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        this->writeWord(fieldIndexId, out);
1897613a697ed124296620b2280533fad2eef776ba54Ethan Nicholas        SpvId heightRead = this->nextId();
1898613a697ed124296620b2280533fad2eef776ba54Ethan Nicholas        this->writeInstruction(SpvOpLoad, this->getType(*fContext.fFloat_Type), heightRead,
1899613a697ed124296620b2280533fad2eef776ba54Ethan Nicholas                               heightPtr, out);
1900941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        SpvId rawYId = this->nextId();
1901941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawYId,
1902941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                               result, 1, out);
1903941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        SpvId flippedYId = this->nextId();
1904941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        this->writeInstruction(SpvOpFSub, this->getType(*fContext.fFloat_Type), flippedYId,
1905941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                               heightRead, rawYId, out);
1906941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        FloatLiteral zero(fContext, Position(), 0.0);
1907941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        SpvId zeroId = writeFloatLiteral(zero);
1908941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        FloatLiteral one(fContext, Position(), 1.0);
1909941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        SpvId oneId = writeFloatLiteral(one);
1910941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        SpvId flipped = this->nextId();
1911941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        this->writeOpCode(SpvOpCompositeConstruct, 7, out);
1912941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        this->writeWord(this->getType(*fContext.fVec4_Type), out);
1913941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        this->writeWord(flipped, out);
1914941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        this->writeWord(xId, out);
1915941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        this->writeWord(flippedYId, out);
1916941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        this->writeWord(zeroId, out);
1917941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        this->writeWord(oneId, out);
1918941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        return flipped;
1919941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    }
1920b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    return result;
1921b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
1922b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
19239e1138d56665d13641f8805cd72ae81adc255f79Ethan NicholasSpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, SkWStream& out) {
1924b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    return getLValue(expr, out)->load(out);
1925b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
1926b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
19279e1138d56665d13641f8805cd72ae81adc255f79Ethan NicholasSpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, SkWStream& out) {
1928b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    return getLValue(f, out)->load(out);
1929b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
1930b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
19319e1138d56665d13641f8805cd72ae81adc255f79Ethan NicholasSpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, SkWStream& out) {
1932b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId base = this->writeExpression(*swizzle.fBase, out);
1933b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId result = this->nextId();
1934b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    size_t count = swizzle.fComponents.size();
1935b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    if (count == 1) {
193664773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel        this->writeInstruction(SpvOpCompositeExtract, this->getType(swizzle.fType), result, base,
193764773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                               swizzle.fComponents[0], out);
1938b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    } else {
1939b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) count, out);
1940d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas        this->writeWord(this->getType(swizzle.fType), out);
1941b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeWord(result, out);
1942b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeWord(base, out);
1943b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeWord(base, out);
1944b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        for (int component : swizzle.fComponents) {
1945b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeWord(component, out);
1946b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
1947b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1948b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    return result;
1949b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
1950b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
195164773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg DanielSpvId SPIRVCodeGenerator::writeBinaryOperation(const Type& resultType,
195264773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                               const Type& operandType, SpvId lhs,
195364773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                               SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt,
19549e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                                               SpvOp_ ifUInt, SpvOp_ ifBool, SkWStream& out) {
1955b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId result = this->nextId();
1956d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    if (is_float(fContext, operandType)) {
1957b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeInstruction(ifFloat, this->getType(resultType), result, lhs, rhs, out);
1958d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    } else if (is_signed(fContext, operandType)) {
1959b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeInstruction(ifInt, this->getType(resultType), result, lhs, rhs, out);
1960d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    } else if (is_unsigned(fContext, operandType)) {
1961b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeInstruction(ifUInt, this->getType(resultType), result, lhs, rhs, out);
1962d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    } else if (operandType == *fContext.fBool_Type) {
1963b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeInstruction(ifBool, this->getType(resultType), result, lhs, rhs, out);
1964b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    } else {
1965b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        ABORT("invalid operandType: %s", operandType.description().c_str());
1966b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1967b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    return result;
1968b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
1969b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
1970b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholasbool is_assignment(Token::Kind op) {
1971b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    switch (op) {
1972b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::EQ:           // fall through
1973b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::PLUSEQ:       // fall through
1974b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::MINUSEQ:      // fall through
1975b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::STAREQ:       // fall through
1976b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::SLASHEQ:      // fall through
1977b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::PERCENTEQ:    // fall through
1978b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::SHLEQ:        // fall through
1979b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::SHREQ:        // fall through
1980b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::BITWISEOREQ:  // fall through
1981b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::BITWISEXOREQ: // fall through
1982b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::BITWISEANDEQ: // fall through
1983b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::LOGICALOREQ:  // fall through
1984b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::LOGICALXOREQ: // fall through
1985b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::LOGICALANDEQ:
1986b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return true;
1987b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        default:
1988b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return false;
1989b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1990b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
1991b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
1992ef653b86b2a9cf9e0793a647e5990806bdbd6934Ethan NicholasSpvId SPIRVCodeGenerator::foldToBool(SpvId id, const Type& operandType, SkWStream& out) {
1993ef653b86b2a9cf9e0793a647e5990806bdbd6934Ethan Nicholas    if (operandType.kind() == Type::kVector_Kind) {
1994ef653b86b2a9cf9e0793a647e5990806bdbd6934Ethan Nicholas        SpvId result = this->nextId();
1995ef653b86b2a9cf9e0793a647e5990806bdbd6934Ethan Nicholas        this->writeInstruction(SpvOpAll, this->getType(*fContext.fBool_Type), result, id, out);
1996ef653b86b2a9cf9e0793a647e5990806bdbd6934Ethan Nicholas        return result;
1997ef653b86b2a9cf9e0793a647e5990806bdbd6934Ethan Nicholas    }
1998ef653b86b2a9cf9e0793a647e5990806bdbd6934Ethan Nicholas    return id;
1999ef653b86b2a9cf9e0793a647e5990806bdbd6934Ethan Nicholas}
2000ef653b86b2a9cf9e0793a647e5990806bdbd6934Ethan Nicholas
20019e1138d56665d13641f8805cd72ae81adc255f79Ethan NicholasSpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, SkWStream& out) {
2002b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    // handle cases where we don't necessarily evaluate both LHS and RHS
2003b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    switch (b.fOperator) {
2004b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::EQ: {
2005b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            SpvId rhs = this->writeExpression(*b.fRight, out);
2006b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->getLValue(*b.fLeft, out)->store(rhs, out);
2007b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return rhs;
2008b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
2009b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::LOGICALAND:
2010b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return this->writeLogicalAnd(b, out);
2011b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::LOGICALOR:
2012b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return this->writeLogicalOr(b, out);
2013b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        default:
2014b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            break;
2015b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2016b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
2017b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    // "normal" operators
2018d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    const Type& resultType = b.fType;
2019b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    std::unique_ptr<LValue> lvalue;
2020b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId lhs;
2021b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    if (is_assignment(b.fOperator)) {
2022b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        lvalue = this->getLValue(*b.fLeft, out);
2023b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        lhs = lvalue->load(out);
2024b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    } else {
2025b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        lvalue = nullptr;
2026b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        lhs = this->writeExpression(*b.fLeft, out);
2027b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2028b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId rhs = this->writeExpression(*b.fRight, out);
2029b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    // component type we are operating on: float, int, uint
2030b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    const Type* operandType;
2031b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    // IR allows mismatched types in expressions (e.g. vec2 * float), but they need special handling
2032b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    // in SPIR-V
2033b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    if (b.fLeft->fType != b.fRight->fType) {
203464773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel        if (b.fLeft->fType.kind() == Type::kVector_Kind &&
2035d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas            b.fRight->fType.isNumber()) {
2036b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            // promote number to vector
2037b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            SpvId vec = this->nextId();
2038d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas            this->writeOpCode(SpvOpCompositeConstruct, 3 + b.fType.columns(), out);
2039b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeWord(this->getType(resultType), out);
2040b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeWord(vec, out);
2041b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            for (int i = 0; i < resultType.columns(); i++) {
2042b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                this->writeWord(rhs, out);
2043b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            }
2044b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            rhs = vec;
2045d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas            operandType = &b.fRight->fType;
204664773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel        } else if (b.fRight->fType.kind() == Type::kVector_Kind &&
2047d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas                   b.fLeft->fType.isNumber()) {
2048b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            // promote number to vector
2049b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            SpvId vec = this->nextId();
2050d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas            this->writeOpCode(SpvOpCompositeConstruct, 3 + b.fType.columns(), out);
2051b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeWord(this->getType(resultType), out);
2052b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeWord(vec, out);
2053b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            for (int i = 0; i < resultType.columns(); i++) {
2054b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                this->writeWord(lhs, out);
2055b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            }
2056b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            lhs = vec;
2057b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            ASSERT(!lvalue);
2058d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas            operandType = &b.fLeft->fType;
2059d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas        } else if (b.fLeft->fType.kind() == Type::kMatrix_Kind) {
2060b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            SpvOp_ op;
2061d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas            if (b.fRight->fType.kind() == Type::kMatrix_Kind) {
2062b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                op = SpvOpMatrixTimesMatrix;
2063d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas            } else if (b.fRight->fType.kind() == Type::kVector_Kind) {
2064b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                op = SpvOpMatrixTimesVector;
2065b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            } else {
2066d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas                ASSERT(b.fRight->fType.kind() == Type::kScalar_Kind);
2067b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                op = SpvOpMatrixTimesScalar;
2068b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            }
2069b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            SpvId result = this->nextId();
2070d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas            this->writeInstruction(op, this->getType(b.fType), result, lhs, rhs, out);
2071b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            if (b.fOperator == Token::STAREQ) {
2072b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                lvalue->store(result, out);
2073b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            } else {
2074b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                ASSERT(b.fOperator == Token::STAR);
2075b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            }
2076b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return result;
2077d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas        } else if (b.fRight->fType.kind() == Type::kMatrix_Kind) {
2078b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            SpvId result = this->nextId();
2079d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas            if (b.fLeft->fType.kind() == Type::kVector_Kind) {
208064773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                this->writeInstruction(SpvOpVectorTimesMatrix, this->getType(b.fType), result,
2081b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                       lhs, rhs, out);
2082b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            } else {
2083d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas                ASSERT(b.fLeft->fType.kind() == Type::kScalar_Kind);
208464773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                this->writeInstruction(SpvOpMatrixTimesScalar, this->getType(b.fType), result, rhs,
2085b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                       lhs, out);
2086b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            }
2087b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            if (b.fOperator == Token::STAREQ) {
2088b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                lvalue->store(result, out);
2089b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            } else {
2090b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                ASSERT(b.fOperator == Token::STAR);
2091b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            }
2092b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return result;
2093b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        } else {
2094b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            ABORT("unsupported binary expression: %s", b.description().c_str());
2095b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
2096b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    } else {
2097d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas        operandType = &b.fLeft->fType;
2098d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas        ASSERT(*operandType == b.fRight->fType);
2099b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2100b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    switch (b.fOperator) {
2101ef653b86b2a9cf9e0793a647e5990806bdbd6934Ethan Nicholas        case Token::EQEQ: {
2102d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas            ASSERT(resultType == *fContext.fBool_Type);
2103ef653b86b2a9cf9e0793a647e5990806bdbd6934Ethan Nicholas            return this->foldToBool(this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2104ef653b86b2a9cf9e0793a647e5990806bdbd6934Ethan Nicholas                                                               SpvOpFOrdEqual, SpvOpIEqual,
2105ef653b86b2a9cf9e0793a647e5990806bdbd6934Ethan Nicholas                                                               SpvOpIEqual, SpvOpLogicalEqual, out),
2106ef653b86b2a9cf9e0793a647e5990806bdbd6934Ethan Nicholas                                    *operandType, out);
2107ef653b86b2a9cf9e0793a647e5990806bdbd6934Ethan Nicholas        }
2108b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::NEQ:
2109d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas            ASSERT(resultType == *fContext.fBool_Type);
2110ef653b86b2a9cf9e0793a647e5990806bdbd6934Ethan Nicholas            return this->foldToBool(this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2111ef653b86b2a9cf9e0793a647e5990806bdbd6934Ethan Nicholas                                                               SpvOpFOrdNotEqual, SpvOpINotEqual,
2112ef653b86b2a9cf9e0793a647e5990806bdbd6934Ethan Nicholas                                                               SpvOpINotEqual, SpvOpLogicalNotEqual,
2113ef653b86b2a9cf9e0793a647e5990806bdbd6934Ethan Nicholas                                                               out),
2114ef653b86b2a9cf9e0793a647e5990806bdbd6934Ethan Nicholas                                    *operandType, out);
2115b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::GT:
2116d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas            ASSERT(resultType == *fContext.fBool_Type);
211764773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
211864773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                              SpvOpFOrdGreaterThan, SpvOpSGreaterThan,
2119b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                              SpvOpUGreaterThan, SpvOpUndef, out);
2120b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::LT:
2121d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas            ASSERT(resultType == *fContext.fBool_Type);
212264773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdLessThan,
2123b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                              SpvOpSLessThan, SpvOpULessThan, SpvOpUndef, out);
2124b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::GTEQ:
2125d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas            ASSERT(resultType == *fContext.fBool_Type);
212664773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
212764773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                              SpvOpFOrdGreaterThanEqual, SpvOpSGreaterThanEqual,
2128b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                              SpvOpUGreaterThanEqual, SpvOpUndef, out);
2129b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::LTEQ:
2130d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas            ASSERT(resultType == *fContext.fBool_Type);
213164773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
213264773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                              SpvOpFOrdLessThanEqual, SpvOpSLessThanEqual,
2133b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                              SpvOpULessThanEqual, SpvOpUndef, out);
2134b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::PLUS:
213564773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
2136b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                              SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2137b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::MINUS:
213864773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
2139b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                              SpvOpISub, SpvOpISub, SpvOpUndef, out);
2140b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::STAR:
214164773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
2142d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas                b.fRight->fType.kind() == Type::kMatrix_Kind) {
2143b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                // matrix multiply
2144b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                SpvId result = this->nextId();
2145b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2146b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                       lhs, rhs, out);
2147b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                return result;
2148b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            }
214964773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
2150b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                              SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
2151b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::SLASH:
215264773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
2153b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                              SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
2154b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::PLUSEQ: {
215564773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
2156b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                                      SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2157b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            ASSERT(lvalue);
2158b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            lvalue->store(result, out);
2159b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return result;
2160b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
2161b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::MINUSEQ: {
216264773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
2163b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                                      SpvOpISub, SpvOpISub, SpvOpUndef, out);
2164b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            ASSERT(lvalue);
2165b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            lvalue->store(result, out);
2166b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return result;
2167b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
2168b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::STAREQ: {
216964773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
2170d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas                b.fRight->fType.kind() == Type::kMatrix_Kind) {
2171b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                // matrix multiply
2172b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                SpvId result = this->nextId();
2173b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2174b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                       lhs, rhs, out);
2175b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                ASSERT(lvalue);
2176b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                lvalue->store(result, out);
2177b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                return result;
2178b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            }
217964773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
2180b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                                      SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
2181b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            ASSERT(lvalue);
2182b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            lvalue->store(result, out);
2183b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return result;
2184b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
2185b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::SLASHEQ: {
218664773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
2187b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                                      SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
2188b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            ASSERT(lvalue);
2189b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            lvalue->store(result, out);
2190b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return result;
2191b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
2192b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        default:
2193b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            // FIXME: missing support for some operators (bitwise, &&=, ||=, shift...)
2194b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            ABORT("unsupported binary expression: %s", b.description().c_str());
2195b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2196b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
2197b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
21989e1138d56665d13641f8805cd72ae81adc255f79Ethan NicholasSpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, SkWStream& out) {
2199b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ASSERT(a.fOperator == Token::LOGICALAND);
2200d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    BoolLiteral falseLiteral(fContext, Position(), false);
2201b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
2202b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId lhs = this->writeExpression(*a.fLeft, out);
2203b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId rhsLabel = this->nextId();
2204b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId end = this->nextId();
2205b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId lhsBlock = fCurrentBlock;
2206b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2207b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeInstruction(SpvOpBranchConditional, lhs, rhsLabel, end, out);
2208b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeLabel(rhsLabel, out);
2209b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId rhs = this->writeExpression(*a.fRight, out);
2210b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId rhsBlock = fCurrentBlock;
2211b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeInstruction(SpvOpBranch, end, out);
2212b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeLabel(end, out);
2213b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId result = this->nextId();
221464773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel    this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, falseConstant,
2215d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas                           lhsBlock, rhs, rhsBlock, out);
2216b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    return result;
2217b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
2218b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
22199e1138d56665d13641f8805cd72ae81adc255f79Ethan NicholasSpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, SkWStream& out) {
2220b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ASSERT(o.fOperator == Token::LOGICALOR);
2221d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    BoolLiteral trueLiteral(fContext, Position(), true);
2222b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
2223b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId lhs = this->writeExpression(*o.fLeft, out);
2224b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId rhsLabel = this->nextId();
2225b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId end = this->nextId();
2226b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId lhsBlock = fCurrentBlock;
2227b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2228b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeInstruction(SpvOpBranchConditional, lhs, end, rhsLabel, out);
2229b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeLabel(rhsLabel, out);
2230b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId rhs = this->writeExpression(*o.fRight, out);
2231b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId rhsBlock = fCurrentBlock;
2232b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeInstruction(SpvOpBranch, end, out);
2233b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeLabel(end, out);
2234b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId result = this->nextId();
223564773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel    this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, trueConstant,
2236d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas                           lhsBlock, rhs, rhsBlock, out);
2237b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    return result;
2238b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
2239b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
22409e1138d56665d13641f8805cd72ae81adc255f79Ethan NicholasSpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, SkWStream& out) {
2241b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId test = this->writeExpression(*t.fTest, out);
2242b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    if (t.fIfTrue->isConstant() && t.fIfFalse->isConstant()) {
2243b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        // both true and false are constants, can just use OpSelect
2244b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        SpvId result = this->nextId();
2245b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        SpvId trueId = this->writeExpression(*t.fIfTrue, out);
2246b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        SpvId falseId = this->writeExpression(*t.fIfFalse, out);
224764773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel        this->writeInstruction(SpvOpSelect, this->getType(t.fType), result, test, trueId, falseId,
2248b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                               out);
2249b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        return result;
2250b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
225164773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel    // was originally using OpPhi to choose the result, but for some reason that is crashing on
2252b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    // Adreno. Switched to storing the result in a temp variable as glslang does.
2253b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId var = this->nextId();
225464773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel    this->writeInstruction(SpvOpVariable, this->getPointerType(t.fType, SpvStorageClassFunction),
2255d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas                           var, SpvStorageClassFunction, fVariableBuffer);
2256b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId trueLabel = this->nextId();
2257b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId falseLabel = this->nextId();
2258b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId end = this->nextId();
2259b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2260b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeInstruction(SpvOpBranchConditional, test, trueLabel, falseLabel, out);
2261b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeLabel(trueLabel, out);
2262b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfTrue, out), out);
2263b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeInstruction(SpvOpBranch, end, out);
2264b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeLabel(falseLabel, out);
2265b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfFalse, out), out);
2266b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeInstruction(SpvOpBranch, end, out);
2267b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeLabel(end, out);
2268b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId result = this->nextId();
2269d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    this->writeInstruction(SpvOpLoad, this->getType(t.fType), result, var, out);
2270b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    return result;
2271b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
2272b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
2273d598f7981f34811e6f2a949207dc13638852f3f7ethannicholasstd::unique_ptr<Expression> create_literal_1(const Context& context, const Type& type) {
2274d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    if (type == *context.fInt_Type) {
2275d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas        return std::unique_ptr<Expression>(new IntLiteral(context, Position(), 1));
2276b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2277d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    else if (type == *context.fFloat_Type) {
2278d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas        return std::unique_ptr<Expression>(new FloatLiteral(context, Position(), 1.0));
2279b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    } else {
2280b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        ABORT("math is unsupported on type '%s'")
2281b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2282b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
2283b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
22849e1138d56665d13641f8805cd72ae81adc255f79Ethan NicholasSpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, SkWStream& out) {
2285b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    if (p.fOperator == Token::MINUS) {
2286b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        SpvId result = this->nextId();
2287d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas        SpvId typeId = this->getType(p.fType);
2288b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        SpvId expr = this->writeExpression(*p.fOperand, out);
2289d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas        if (is_float(fContext, p.fType)) {
2290b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeInstruction(SpvOpFNegate, typeId, result, expr, out);
2291d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas        } else if (is_signed(fContext, p.fType)) {
2292b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeInstruction(SpvOpSNegate, typeId, result, expr, out);
2293b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        } else {
2294b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            ABORT("unsupported prefix expression %s", p.description().c_str());
2295b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        };
2296b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        return result;
2297b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2298b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    switch (p.fOperator) {
2299b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::PLUS:
2300b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return this->writeExpression(*p.fOperand, out);
2301b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::PLUSPLUS: {
2302b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
2303d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas            SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
230464773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
230564773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                                      SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef,
2306b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                                      out);
2307b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            lv->store(result, out);
2308b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return result;
2309b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
2310b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::MINUSMINUS: {
2311b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
2312d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas            SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
231364773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
231464773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                                      SpvOpFSub, SpvOpISub, SpvOpISub, SpvOpUndef,
2315b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                                      out);
2316b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            lv->store(result, out);
2317b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return result;
2318b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
23195961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        case Token::LOGICALNOT: {
2320d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas            ASSERT(p.fOperand->fType == *fContext.fBool_Type);
2321b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            SpvId result = this->nextId();
2322d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas            this->writeInstruction(SpvOpLogicalNot, this->getType(p.fOperand->fType), result,
2323b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                   this->writeExpression(*p.fOperand, out), out);
2324b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return result;
2325b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
23265961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        case Token::BITWISENOT: {
23275961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            SpvId result = this->nextId();
23285961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            this->writeInstruction(SpvOpNot, this->getType(p.fOperand->fType), result,
23295961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                                   this->writeExpression(*p.fOperand, out), out);
23305961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            return result;
23315961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        }
2332b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        default:
2333b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            ABORT("unsupported prefix expression: %s", p.description().c_str());
2334b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2335b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
2336b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
23379e1138d56665d13641f8805cd72ae81adc255f79Ethan NicholasSpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, SkWStream& out) {
2338b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
2339b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId result = lv->load(out);
2340d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
2341b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    switch (p.fOperator) {
2342b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::PLUSPLUS: {
234364773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFAdd,
2344b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                                    SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2345b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            lv->store(temp, out);
2346b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return result;
2347b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
2348b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Token::MINUSMINUS: {
234964773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFSub,
2350b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                                    SpvOpISub, SpvOpISub, SpvOpUndef, out);
2351b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            lv->store(temp, out);
2352b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return result;
2353b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
2354b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        default:
2355b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            ABORT("unsupported postfix expression %s", p.description().c_str());
2356b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2357b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
2358b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
2359f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasSpvId SPIRVCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
2360b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    if (b.fValue) {
2361b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        if (fBoolTrue == 0) {
2362b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            fBoolTrue = this->nextId();
236364773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            this->writeInstruction(SpvOpConstantTrue, this->getType(b.fType), fBoolTrue,
2364b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                   fConstantBuffer);
2365b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
2366b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        return fBoolTrue;
2367b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    } else {
2368b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        if (fBoolFalse == 0) {
2369b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            fBoolFalse = this->nextId();
237064773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            this->writeInstruction(SpvOpConstantFalse, this->getType(b.fType), fBoolFalse,
2371b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                   fConstantBuffer);
2372b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
2373b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        return fBoolFalse;
2374b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2375b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
2376b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
2377f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasSpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) {
2378d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    if (i.fType == *fContext.fInt_Type) {
2379b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        auto entry = fIntConstants.find(i.fValue);
2380b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        if (entry == fIntConstants.end()) {
2381b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            SpvId result = this->nextId();
238264773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue,
2383b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                   fConstantBuffer);
2384b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            fIntConstants[i.fValue] = result;
2385b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return result;
2386b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
2387b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        return entry->second;
2388b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    } else {
2389d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas        ASSERT(i.fType == *fContext.fUInt_Type);
2390b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        auto entry = fUIntConstants.find(i.fValue);
2391b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        if (entry == fUIntConstants.end()) {
2392b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            SpvId result = this->nextId();
239364773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue,
2394b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                   fConstantBuffer);
2395b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            fUIntConstants[i.fValue] = result;
2396b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return result;
2397b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
2398b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        return entry->second;
2399b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2400b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
2401b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
2402f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasSpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
2403d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    if (f.fType == *fContext.fFloat_Type) {
2404b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        float value = (float) f.fValue;
2405b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        auto entry = fFloatConstants.find(value);
2406b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        if (entry == fFloatConstants.end()) {
2407b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            SpvId result = this->nextId();
2408b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            uint32_t bits;
2409b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            ASSERT(sizeof(bits) == sizeof(value));
2410b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            memcpy(&bits, &value, sizeof(bits));
241164773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            this->writeInstruction(SpvOpConstant, this->getType(f.fType), result, bits,
2412b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                   fConstantBuffer);
2413b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            fFloatConstants[value] = result;
2414b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return result;
2415b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
2416b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        return entry->second;
2417b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    } else {
2418d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas        ASSERT(f.fType == *fContext.fDouble_Type);
2419b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        auto entry = fDoubleConstants.find(f.fValue);
2420b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        if (entry == fDoubleConstants.end()) {
2421b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            SpvId result = this->nextId();
2422b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            uint64_t bits;
2423b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            ASSERT(sizeof(bits) == sizeof(f.fValue));
2424b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            memcpy(&bits, &f.fValue, sizeof(bits));
242564773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            this->writeInstruction(SpvOpConstant, this->getType(f.fType), result,
2426b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                   bits & 0xffffffff, bits >> 32, fConstantBuffer);
2427b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            fDoubleConstants[f.fValue] = result;
2428b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            return result;
2429b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
2430b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        return entry->second;
2431b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2432b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
2433b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
24349e1138d56665d13641f8805cd72ae81adc255f79Ethan NicholasSpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, SkWStream& out) {
2435d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    SpvId result = fFunctionMap[&f];
243664773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel    this->writeInstruction(SpvOpFunction, this->getType(f.fReturnType), result,
2437b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                           SpvFunctionControlMaskNone, this->getFunctionType(f), out);
2438d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    this->writeInstruction(SpvOpName, result, f.fName.c_str(), fNameBuffer);
2439d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    for (size_t i = 0; i < f.fParameters.size(); i++) {
2440b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        SpvId id = this->nextId();
2441d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas        fVariableMap[f.fParameters[i]] = id;
2442b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        SpvId type;
2443d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas        type = this->getPointerType(f.fParameters[i]->fType, SpvStorageClassFunction);
2444b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeInstruction(SpvOpFunctionParameter, type, id, out);
2445b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2446b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    return result;
2447b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
2448b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
24499e1138d56665d13641f8805cd72ae81adc255f79Ethan NicholasSpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, SkWStream& out) {
2450b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId result = this->writeFunctionStart(f.fDeclaration, out);
2451b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeLabel(this->nextId(), out);
2452d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    if (f.fDeclaration.fName == "main") {
24539e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas        write_data(*fGlobalInitializersBuffer.detachAsData(), out);
2454b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
24559e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    SkDynamicMemoryWStream bodyBuffer;
2456e1d9cb82bf9004eb05831f34bb3e9e708ae0617fEthan Nicholas    this->writeBlock(*f.fBody, bodyBuffer);
24579e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    write_data(*fVariableBuffer.detachAsData(), out);
24589e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    write_data(*bodyBuffer.detachAsData(), out);
2459b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    if (fCurrentBlock) {
2460b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeInstruction(SpvOpReturn, out);
2461b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2462b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeInstruction(SpvOpFunctionEnd, out);
2463b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    return result;
2464b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
2465b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
2466b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholasvoid SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target) {
2467b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    if (layout.fLocation >= 0) {
246864773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel        this->writeInstruction(SpvOpDecorate, target, SpvDecorationLocation, layout.fLocation,
2469b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                               fDecorationBuffer);
2470b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2471b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    if (layout.fBinding >= 0) {
247264773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel        this->writeInstruction(SpvOpDecorate, target, SpvDecorationBinding, layout.fBinding,
2473b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                               fDecorationBuffer);
2474b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2475b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    if (layout.fIndex >= 0) {
247664773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel        this->writeInstruction(SpvOpDecorate, target, SpvDecorationIndex, layout.fIndex,
2477b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                               fDecorationBuffer);
2478b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2479b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    if (layout.fSet >= 0) {
248064773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel        this->writeInstruction(SpvOpDecorate, target, SpvDecorationDescriptorSet, layout.fSet,
2481b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                               fDecorationBuffer);
2482b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
248364773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel    if (layout.fInputAttachmentIndex >= 0) {
248464773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel        this->writeInstruction(SpvOpDecorate, target, SpvDecorationInputAttachmentIndex,
248564773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                               layout.fInputAttachmentIndex, fDecorationBuffer);
248664773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel    }
24875961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    if (layout.fBuiltin >= 0 && layout.fBuiltin != SK_FRAGCOLOR_BUILTIN) {
248864773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel        this->writeInstruction(SpvOpDecorate, target, SpvDecorationBuiltIn, layout.fBuiltin,
2489b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                               fDecorationBuffer);
2490b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2491b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
2492b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
2493b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholasvoid SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int member) {
2494b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    if (layout.fLocation >= 0) {
249564773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel        this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationLocation,
2496b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                               layout.fLocation, fDecorationBuffer);
2497b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2498b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    if (layout.fBinding >= 0) {
249964773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel        this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBinding,
2500b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                               layout.fBinding, fDecorationBuffer);
2501b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2502b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    if (layout.fIndex >= 0) {
250364773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel        this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationIndex,
2504b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                               layout.fIndex, fDecorationBuffer);
2505b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2506b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    if (layout.fSet >= 0) {
250764773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel        this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationDescriptorSet,
2508b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                               layout.fSet, fDecorationBuffer);
2509b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
251064773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel    if (layout.fInputAttachmentIndex >= 0) {
251164773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel        this->writeInstruction(SpvOpDecorate, target, member, SpvDecorationInputAttachmentIndex,
251264773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                               layout.fInputAttachmentIndex, fDecorationBuffer);
251364773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel    }
2514b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    if (layout.fBuiltin >= 0) {
251564773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel        this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBuiltIn,
2516b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                               layout.fBuiltin, fDecorationBuffer);
2517b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2518b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
2519b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
2520f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasSpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
25218ac838d978578c44b75a801489c985e5284dd66fethannicholas    MemoryLayout layout = intf.fVariable.fModifiers.fLayout.fPushConstant ?
25228ac838d978578c44b75a801489c985e5284dd66fethannicholas                          MemoryLayout(MemoryLayout::k430_Standard) :
25238ac838d978578c44b75a801489c985e5284dd66fethannicholas                          fDefaultLayout;
2524b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId result = this->nextId();
2525941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    const Type* type = &intf.fVariable.fType;
2526941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    if (fProgram.fInputs.fRTHeight) {
2527941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        ASSERT(fRTHeightStructId == (SpvId) -1);
2528941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        ASSERT(fRTHeightFieldIndex == (SpvId) -1);
2529941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        std::vector<Type::Field> fields = type->fields();
2530941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        fRTHeightStructId = result;
2531941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        fRTHeightFieldIndex = fields.size();
2532941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        fields.emplace_back(Modifiers(), SkString(SKSL_RTHEIGHT_NAME), fContext.fFloat_Type.get());
2533941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        type = new Type(type->fPosition, type->name(), fields);
2534941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    }
2535941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    SpvId typeId = this->getType(*type, layout);
2536941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBlock, fDecorationBuffer);
2537d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    SpvStorageClass_ storageClass = get_storage_class(intf.fVariable.fModifiers);
2538b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId ptrType = this->nextId();
2539941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, typeId, fConstantBuffer);
2540b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer);
2541d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    this->writeLayout(intf.fVariable.fModifiers.fLayout, result);
2542d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    fVariableMap[&intf.fVariable] = result;
254339b101b13da171a0ba08ae7196d1a88bc8375ef7Ethan Nicholas    if (fProgram.fInputs.fRTHeight) {
254439b101b13da171a0ba08ae7196d1a88bc8375ef7Ethan Nicholas        delete type;
254539b101b13da171a0ba08ae7196d1a88bc8375ef7Ethan Nicholas    }
2546b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    return result;
2547b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
2548b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
25495961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas#define BUILTIN_IGNORE 9999
255064773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Danielvoid SPIRVCodeGenerator::writeGlobalVars(Program::Kind kind, const VarDeclarations& decl,
25519e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                                         SkWStream& out) {
2552b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    for (size_t i = 0; i < decl.fVars.size(); i++) {
2553e1d9cb82bf9004eb05831f34bb3e9e708ae0617fEthan Nicholas        const VarDeclaration& varDecl = decl.fVars[i];
255414fe8cc16d2a98d5a96f818e4d0b7127ecad59e2ethannicholas        const Variable* var = varDecl.fVar;
2555f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon        // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2556f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon        // in the OpenGL backend.
2557f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon        ASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
2558f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon                                           Modifiers::kWriteOnly_Flag |
2559f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon                                           Modifiers::kCoherent_Flag |
2560f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon                                           Modifiers::kVolatile_Flag |
2561f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon                                           Modifiers::kRestrict_Flag)));
25625961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        if (var->fModifiers.fLayout.fBuiltin == BUILTIN_IGNORE) {
25635961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            continue;
25645961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        }
25655961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        if (var->fModifiers.fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN &&
25665961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            kind != Program::kFragment_Kind) {
25675961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            continue;
25685961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        }
256986a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas        if (!var->fReadCount && !var->fWriteCount &&
257014fe8cc16d2a98d5a96f818e4d0b7127ecad59e2ethannicholas                !(var->fModifiers.fFlags & (Modifiers::kIn_Flag |
257114fe8cc16d2a98d5a96f818e4d0b7127ecad59e2ethannicholas                                            Modifiers::kOut_Flag |
257214fe8cc16d2a98d5a96f818e4d0b7127ecad59e2ethannicholas                                            Modifiers::kUniform_Flag))) {
2573d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas            // variable is dead and not an input / output var (the Vulkan debug layers complain if
2574d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas            // we elide an interface var, even if it's dead)
2575b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            continue;
2576b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
2577b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        SpvStorageClass_ storageClass;
257814fe8cc16d2a98d5a96f818e4d0b7127ecad59e2ethannicholas        if (var->fModifiers.fFlags & Modifiers::kIn_Flag) {
2579b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            storageClass = SpvStorageClassInput;
258014fe8cc16d2a98d5a96f818e4d0b7127ecad59e2ethannicholas        } else if (var->fModifiers.fFlags & Modifiers::kOut_Flag) {
2581b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            storageClass = SpvStorageClassOutput;
258214fe8cc16d2a98d5a96f818e4d0b7127ecad59e2ethannicholas        } else if (var->fModifiers.fFlags & Modifiers::kUniform_Flag) {
258314fe8cc16d2a98d5a96f818e4d0b7127ecad59e2ethannicholas            if (var->fType.kind() == Type::kSampler_Kind) {
2584b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                storageClass = SpvStorageClassUniformConstant;
2585b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            } else {
2586b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                storageClass = SpvStorageClassUniform;
2587b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            }
2588b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        } else {
2589b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            storageClass = SpvStorageClassPrivate;
2590b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
2591b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        SpvId id = this->nextId();
259214fe8cc16d2a98d5a96f818e4d0b7127ecad59e2ethannicholas        fVariableMap[var] = id;
259314fe8cc16d2a98d5a96f818e4d0b7127ecad59e2ethannicholas        SpvId type = this->getPointerType(var->fType, storageClass);
2594b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeInstruction(SpvOpVariable, type, id, storageClass, fConstantBuffer);
259514fe8cc16d2a98d5a96f818e4d0b7127ecad59e2ethannicholas        this->writeInstruction(SpvOpName, id, var->fName.c_str(), fNameBuffer);
259614fe8cc16d2a98d5a96f818e4d0b7127ecad59e2ethannicholas        if (var->fType.kind() == Type::kMatrix_Kind) {
259764773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            this->writeInstruction(SpvOpMemberDecorate, id, (SpvId) i, SpvDecorationColMajor,
2598b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                   fDecorationBuffer);
259964773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            this->writeInstruction(SpvOpMemberDecorate, id, (SpvId) i, SpvDecorationMatrixStride,
26008ac838d978578c44b75a801489c985e5284dd66fethannicholas                                   (SpvId) fDefaultLayout.stride(var->fType), fDecorationBuffer);
2601b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
260214fe8cc16d2a98d5a96f818e4d0b7127ecad59e2ethannicholas        if (varDecl.fValue) {
2603f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            ASSERT(!fCurrentBlock);
2604f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            fCurrentBlock = -1;
260514fe8cc16d2a98d5a96f818e4d0b7127ecad59e2ethannicholas            SpvId value = this->writeExpression(*varDecl.fValue, fGlobalInitializersBuffer);
2606b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
2607f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            fCurrentBlock = 0;
2608b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
260914fe8cc16d2a98d5a96f818e4d0b7127ecad59e2ethannicholas        this->writeLayout(var->fModifiers.fLayout, id);
2610b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2611b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
2612b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
26139e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholasvoid SPIRVCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, SkWStream& out) {
261414fe8cc16d2a98d5a96f818e4d0b7127ecad59e2ethannicholas    for (const auto& varDecl : decl.fVars) {
2615e1d9cb82bf9004eb05831f34bb3e9e708ae0617fEthan Nicholas        const Variable* var = varDecl.fVar;
2616f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon        // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2617f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon        // in the OpenGL backend.
2618f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon        ASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
2619f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon                                           Modifiers::kWriteOnly_Flag |
2620f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon                                           Modifiers::kCoherent_Flag |
2621f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon                                           Modifiers::kVolatile_Flag |
2622f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon                                           Modifiers::kRestrict_Flag)));
2623b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        SpvId id = this->nextId();
262414fe8cc16d2a98d5a96f818e4d0b7127ecad59e2ethannicholas        fVariableMap[var] = id;
262514fe8cc16d2a98d5a96f818e4d0b7127ecad59e2ethannicholas        SpvId type = this->getPointerType(var->fType, SpvStorageClassFunction);
2626b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeInstruction(SpvOpVariable, type, id, SpvStorageClassFunction, fVariableBuffer);
262714fe8cc16d2a98d5a96f818e4d0b7127ecad59e2ethannicholas        this->writeInstruction(SpvOpName, id, var->fName.c_str(), fNameBuffer);
2628e1d9cb82bf9004eb05831f34bb3e9e708ae0617fEthan Nicholas        if (varDecl.fValue) {
2629e1d9cb82bf9004eb05831f34bb3e9e708ae0617fEthan Nicholas            SpvId value = this->writeExpression(*varDecl.fValue, out);
2630b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeInstruction(SpvOpStore, id, value, out);
2631b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
2632b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2633b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
2634b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
26359e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholasvoid SPIRVCodeGenerator::writeStatement(const Statement& s, SkWStream& out) {
2636b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    switch (s.fKind) {
2637b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Statement::kBlock_Kind:
2638b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeBlock((Block&) s, out);
2639b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            break;
2640b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Statement::kExpression_Kind:
2641b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeExpression(*((ExpressionStatement&) s).fExpression, out);
2642b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            break;
264364773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel        case Statement::kReturn_Kind:
2644b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeReturnStatement((ReturnStatement&) s, out);
2645b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            break;
264614fe8cc16d2a98d5a96f818e4d0b7127ecad59e2ethannicholas        case Statement::kVarDeclarations_Kind:
264714fe8cc16d2a98d5a96f818e4d0b7127ecad59e2ethannicholas            this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, out);
2648b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            break;
2649b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Statement::kIf_Kind:
2650b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeIfStatement((IfStatement&) s, out);
2651b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            break;
2652b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Statement::kFor_Kind:
2653b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeForStatement((ForStatement&) s, out);
2654b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            break;
2655fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas        case Statement::kWhile_Kind:
2656fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas            this->writeWhileStatement((WhileStatement&) s, out);
2657fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas            break;
2658fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas        case Statement::kDo_Kind:
2659fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas            this->writeDoStatement((DoStatement&) s, out);
2660fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas            break;
2661b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Statement::kBreak_Kind:
2662b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeInstruction(SpvOpBranch, fBreakTarget.top(), out);
2663b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            break;
2664b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Statement::kContinue_Kind:
2665b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeInstruction(SpvOpBranch, fContinueTarget.top(), out);
2666b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            break;
2667b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Statement::kDiscard_Kind:
2668b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeInstruction(SpvOpKill, out);
2669b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            break;
2670b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        default:
2671b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            ABORT("unsupported statement: %s", s.description().c_str());
2672b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2673b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
2674b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
26759e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholasvoid SPIRVCodeGenerator::writeBlock(const Block& b, SkWStream& out) {
2676b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    for (size_t i = 0; i < b.fStatements.size(); i++) {
2677b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeStatement(*b.fStatements[i], out);
2678b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2679b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
2680b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
26819e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholasvoid SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, SkWStream& out) {
2682b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId test = this->writeExpression(*stmt.fTest, out);
2683b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId ifTrue = this->nextId();
2684b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId ifFalse = this->nextId();
2685b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    if (stmt.fIfFalse) {
2686b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        SpvId end = this->nextId();
2687b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2688b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2689b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeLabel(ifTrue, out);
2690b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeStatement(*stmt.fIfTrue, out);
2691b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        if (fCurrentBlock) {
2692b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeInstruction(SpvOpBranch, end, out);
2693b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
2694b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeLabel(ifFalse, out);
2695b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeStatement(*stmt.fIfFalse, out);
2696b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        if (fCurrentBlock) {
2697b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeInstruction(SpvOpBranch, end, out);
2698b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
2699b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeLabel(end, out);
2700b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    } else {
2701b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeInstruction(SpvOpSelectionMerge, ifFalse, SpvSelectionControlMaskNone, out);
2702b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2703b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeLabel(ifTrue, out);
2704b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeStatement(*stmt.fIfTrue, out);
2705b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        if (fCurrentBlock) {
2706b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeInstruction(SpvOpBranch, ifFalse, out);
2707b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
2708b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeLabel(ifFalse, out);
2709b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2710b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
2711b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
27129e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholasvoid SPIRVCodeGenerator::writeForStatement(const ForStatement& f, SkWStream& out) {
2713b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    if (f.fInitializer) {
2714b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeStatement(*f.fInitializer, out);
2715b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2716b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId header = this->nextId();
2717b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId start = this->nextId();
2718b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId body = this->nextId();
2719b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId next = this->nextId();
2720b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    fContinueTarget.push(next);
2721b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    SpvId end = this->nextId();
2722b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    fBreakTarget.push(end);
2723b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeInstruction(SpvOpBranch, header, out);
2724b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeLabel(header, out);
2725b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
2726f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeInstruction(SpvOpBranch, start, out);
2727b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeLabel(start, out);
272822f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas    if (f.fTest) {
272922f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas        SpvId test = this->writeExpression(*f.fTest, out);
273022f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas        this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
273122f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas    }
2732b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeLabel(body, out);
2733b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeStatement(*f.fStatement, out);
2734b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    if (fCurrentBlock) {
2735b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeInstruction(SpvOpBranch, next, out);
2736b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2737b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeLabel(next, out);
2738b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    if (f.fNext) {
2739b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeExpression(*f.fNext, out);
2740b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2741b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeInstruction(SpvOpBranch, header, out);
2742b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeLabel(end, out);
2743b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    fBreakTarget.pop();
2744b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    fContinueTarget.pop();
2745b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
2746b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
2747fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholasvoid SPIRVCodeGenerator::writeWhileStatement(const WhileStatement& w, SkWStream& out) {
2748fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    // We believe the while loop code below will work, but Skia doesn't actually use them and
2749fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    // adequately testing this code in the absence of Skia exercising it isn't straightforward. For
2750fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    // the time being, we just fail with an error due to the lack of testing. If you encounter this
2751fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    // message, simply remove the error call below to see whether our while loop support actually
2752fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    // works.
2753fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    fErrors.error(w.fPosition, "internal error: while loop support has been disabled in SPIR-V, "
2754fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas                  "see SkSLSPIRVCodeGenerator.cpp for details");
2755fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas
2756fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    SpvId header = this->nextId();
2757fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    SpvId start = this->nextId();
2758fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    SpvId body = this->nextId();
2759fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    fContinueTarget.push(start);
2760fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    SpvId end = this->nextId();
2761fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    fBreakTarget.push(end);
2762fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    this->writeInstruction(SpvOpBranch, header, out);
2763fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    this->writeLabel(header, out);
2764fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    this->writeInstruction(SpvOpLoopMerge, end, start, SpvLoopControlMaskNone, out);
2765fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    this->writeInstruction(SpvOpBranch, start, out);
2766fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    this->writeLabel(start, out);
2767fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    SpvId test = this->writeExpression(*w.fTest, out);
2768fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2769fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    this->writeLabel(body, out);
2770fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    this->writeStatement(*w.fStatement, out);
2771fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    if (fCurrentBlock) {
2772fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas        this->writeInstruction(SpvOpBranch, start, out);
2773fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    }
2774fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    this->writeLabel(end, out);
2775fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    fBreakTarget.pop();
2776fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    fContinueTarget.pop();
2777fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas}
2778fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas
2779fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholasvoid SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, SkWStream& out) {
2780fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    // We believe the do loop code below will work, but Skia doesn't actually use them and
2781fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    // adequately testing this code in the absence of Skia exercising it isn't straightforward. For
2782fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    // the time being, we just fail with an error due to the lack of testing. If you encounter this
2783fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    // message, simply remove the error call below to see whether our do loop support actually
2784fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    // works.
2785fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    fErrors.error(d.fPosition, "internal error: do loop support has been disabled in SPIR-V, see "
2786fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas                  "SkSLSPIRVCodeGenerator.cpp for details");
2787fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas
2788fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    SpvId header = this->nextId();
2789fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    SpvId start = this->nextId();
2790fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    SpvId next = this->nextId();
2791fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    fContinueTarget.push(next);
2792fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    SpvId end = this->nextId();
2793fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    fBreakTarget.push(end);
2794fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    this->writeInstruction(SpvOpBranch, header, out);
2795fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    this->writeLabel(header, out);
2796fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    this->writeInstruction(SpvOpLoopMerge, end, start, SpvLoopControlMaskNone, out);
2797fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    this->writeInstruction(SpvOpBranch, start, out);
2798fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    this->writeLabel(start, out);
2799fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    this->writeStatement(*d.fStatement, out);
2800fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    if (fCurrentBlock) {
2801fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas        this->writeInstruction(SpvOpBranch, next, out);
2802fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    }
2803fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    this->writeLabel(next, out);
2804fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    SpvId test = this->writeExpression(*d.fTest, out);
2805fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    this->writeInstruction(SpvOpBranchConditional, test, start, end, out);
2806fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    this->writeLabel(end, out);
2807fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    fBreakTarget.pop();
2808fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas    fContinueTarget.pop();
2809fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas}
2810fd146aa1dd8ea2d83396bb3a19c7556d9297a5e0Ethan Nicholas
28119e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholasvoid SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, SkWStream& out) {
2812b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    if (r.fExpression) {
281364773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel        this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.fExpression, out),
2814b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                               out);
2815b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    } else {
2816b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeInstruction(SpvOpReturn, out);
2817b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2818b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
2819b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
28209e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholasvoid SPIRVCodeGenerator::writeInstructions(const Program& program, SkWStream& out) {
2821b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    fGLSLExtendedInstructions = this->nextId();
28229e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    SkDynamicMemoryWStream body;
28238e48c1e1d38bf0f0086971be2b077d1a2cb12131Ethan Nicholas    std::set<SpvId> interfaceVars;
2824b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    // assign IDs to functions
2825b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    for (size_t i = 0; i < program.fElements.size(); i++) {
2826b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        if (program.fElements[i]->fKind == ProgramElement::kFunction_Kind) {
2827b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            FunctionDefinition& f = (FunctionDefinition&) *program.fElements[i];
2828d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas            fFunctionMap[&f.fDeclaration] = this->nextId();
2829b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
2830b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2831b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    for (size_t i = 0; i < program.fElements.size(); i++) {
2832b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        if (program.fElements[i]->fKind == ProgramElement::kInterfaceBlock_Kind) {
2833b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            InterfaceBlock& intf = (InterfaceBlock&) *program.fElements[i];
2834b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            SpvId id = this->writeInterfaceBlock(intf);
2835d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas            if ((intf.fVariable.fModifiers.fFlags & Modifiers::kIn_Flag) ||
2836d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas                (intf.fVariable.fModifiers.fFlags & Modifiers::kOut_Flag)) {
28378e48c1e1d38bf0f0086971be2b077d1a2cb12131Ethan Nicholas                interfaceVars.insert(id);
2838b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            }
2839b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
2840b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2841b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    for (size_t i = 0; i < program.fElements.size(); i++) {
2842b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        if (program.fElements[i]->fKind == ProgramElement::kVar_Kind) {
284364773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            this->writeGlobalVars(program.fKind, ((VarDeclarations&) *program.fElements[i]),
28445961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                                  body);
2845b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
2846b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2847b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    for (size_t i = 0; i < program.fElements.size(); i++) {
2848b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        if (program.fElements[i]->fKind == ProgramElement::kFunction_Kind) {
2849b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeFunction(((FunctionDefinition&) *program.fElements[i]), body);
2850b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
2851b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2852d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    const FunctionDeclaration* main = nullptr;
2853b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    for (auto entry : fFunctionMap) {
2854f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        if (entry.first->fName == "main") {
2855b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            main = entry.first;
2856b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
2857b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2858b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ASSERT(main);
2859b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    for (auto entry : fVariableMap) {
2860d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas        const Variable* var = entry.first;
286164773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel        if (var->fStorage == Variable::kGlobal_Storage &&
2862b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                ((var->fModifiers.fFlags & Modifiers::kIn_Flag) ||
2863b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                 (var->fModifiers.fFlags & Modifiers::kOut_Flag))) {
28648e48c1e1d38bf0f0086971be2b077d1a2cb12131Ethan Nicholas            interfaceVars.insert(entry.second);
2865b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
2866b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2867b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeCapabilities(out);
2868b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeInstruction(SpvOpExtInstImport, fGLSLExtendedInstructions, "GLSL.std.450", out);
2869b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeInstruction(SpvOpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450, out);
287064773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel    this->writeOpCode(SpvOpEntryPoint, (SpvId) (3 + (strlen(main->fName.c_str()) + 4) / 4) +
2871b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                      (int32_t) interfaceVars.size(), out);
2872b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    switch (program.fKind) {
2873b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Program::kVertex_Kind:
2874b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeWord(SpvExecutionModelVertex, out);
2875b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            break;
2876b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Program::kFragment_Kind:
2877b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            this->writeWord(SpvExecutionModelFragment, out);
2878b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            break;
287952cad15d0b4443b763a7d41ec8d1131a7638f866Ethan Nicholas        case Program::kGeometry_Kind:
288052cad15d0b4443b763a7d41ec8d1131a7638f866Ethan Nicholas            this->writeWord(SpvExecutionModelGeometry, out);
288152cad15d0b4443b763a7d41ec8d1131a7638f866Ethan Nicholas            break;
2882b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2883b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeWord(fFunctionMap[main], out);
2884b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeString(main->fName.c_str(), out);
2885b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    for (int var : interfaceVars) {
2886b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        this->writeWord(var, out);
2887b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2888b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    if (program.fKind == Program::kFragment_Kind) {
288964773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel        this->writeInstruction(SpvOpExecutionMode,
289064773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                               fFunctionMap[main],
2891b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                               SpvExecutionModeOriginUpperLeft,
2892b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                               out);
2893b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
2894b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    for (size_t i = 0; i < program.fElements.size(); i++) {
2895b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        if (program.fElements[i]->fKind == ProgramElement::kExtension_Kind) {
289664773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel            this->writeInstruction(SpvOpSourceExtension,
289764773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel                                   ((Extension&) *program.fElements[i]).fName.c_str(),
2898b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas                                   out);
2899b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        }
2900b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
290164773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel
2902941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    write_data(*fExtraGlobalsBuffer.detachAsData(), out);
29039e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    write_data(*fNameBuffer.detachAsData(), out);
29049e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    write_data(*fDecorationBuffer.detachAsData(), out);
29059e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    write_data(*fConstantBuffer.detachAsData(), out);
29069e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    write_data(*fExternalFunctionsBuffer.detachAsData(), out);
29079e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    write_data(*body.detachAsData(), out);
2908b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
2909b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
2910941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholasbool SPIRVCodeGenerator::generateCode() {
2911941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    ASSERT(!fErrors.errorCount());
2912941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    this->writeWord(SpvMagicNumber, *fOut);
2913941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    this->writeWord(SpvVersion, *fOut);
2914941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    this->writeWord(SKSL_MAGIC, *fOut);
29159e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    SkDynamicMemoryWStream buffer;
2916941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    this->writeInstructions(fProgram, buffer);
2917941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    this->writeWord(fIdCount, *fOut);
2918941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    this->writeWord(0, *fOut); // reserved, always zero
2919941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    write_data(*buffer.detachAsData(), *fOut);
2920941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    return 0 == fErrors.errorCount();
2921b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
2922b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
2923b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
2924