LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/sksl - SkSLSPIRVCodeGenerator.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 1508 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 91 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13