blob: b899e4fcbd4a98590c8e79fe26645fe931582a46 [file] [log] [blame]
ethannicholasb3058bd2016-07-01 08:22:01 -07001/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkSLSPIRVCodeGenerator.h"
9
10#include "string.h"
11
12#include "GLSL.std.450.h"
13
14#include "ir/SkSLExpressionStatement.h"
15#include "ir/SkSLExtension.h"
16#include "ir/SkSLIndexExpression.h"
17#include "ir/SkSLVariableReference.h"
ethannicholas5961bc92016-10-12 06:39:56 -070018#include "SkSLCompiler.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070019
20namespace SkSL {
21
22#define SPIRV_DEBUG 0
23
24static const int32_t SKSL_MAGIC = 0x0; // FIXME: we should probably register a magic number
25
26void SPIRVCodeGenerator::setupIntrinsics() {
27#define ALL_GLSL(x) std::make_tuple(kGLSL_STD_450_IntrinsicKind, GLSLstd450 ## x, GLSLstd450 ## x, \
28 GLSLstd450 ## x, GLSLstd450 ## x)
29#define BY_TYPE_GLSL(ifFloat, ifInt, ifUInt) std::make_tuple(kGLSL_STD_450_IntrinsicKind, \
30 GLSLstd450 ## ifFloat, \
31 GLSLstd450 ## ifInt, \
32 GLSLstd450 ## ifUInt, \
33 SpvOpUndef)
34#define SPECIAL(x) std::make_tuple(kSpecial_IntrinsicKind, k ## x ## _SpecialIntrinsic, \
35 k ## x ## _SpecialIntrinsic, k ## x ## _SpecialIntrinsic, \
36 k ## x ## _SpecialIntrinsic)
37 fIntrinsicMap["round"] = ALL_GLSL(Round);
38 fIntrinsicMap["roundEven"] = ALL_GLSL(RoundEven);
39 fIntrinsicMap["trunc"] = ALL_GLSL(Trunc);
40 fIntrinsicMap["abs"] = BY_TYPE_GLSL(FAbs, SAbs, SAbs);
41 fIntrinsicMap["sign"] = BY_TYPE_GLSL(FSign, SSign, SSign);
42 fIntrinsicMap["floor"] = ALL_GLSL(Floor);
43 fIntrinsicMap["ceil"] = ALL_GLSL(Ceil);
44 fIntrinsicMap["fract"] = ALL_GLSL(Fract);
45 fIntrinsicMap["radians"] = ALL_GLSL(Radians);
46 fIntrinsicMap["degrees"] = ALL_GLSL(Degrees);
47 fIntrinsicMap["sin"] = ALL_GLSL(Sin);
48 fIntrinsicMap["cos"] = ALL_GLSL(Cos);
49 fIntrinsicMap["tan"] = ALL_GLSL(Tan);
50 fIntrinsicMap["asin"] = ALL_GLSL(Asin);
51 fIntrinsicMap["acos"] = ALL_GLSL(Acos);
52 fIntrinsicMap["atan"] = SPECIAL(Atan);
53 fIntrinsicMap["sinh"] = ALL_GLSL(Sinh);
54 fIntrinsicMap["cosh"] = ALL_GLSL(Cosh);
55 fIntrinsicMap["tanh"] = ALL_GLSL(Tanh);
56 fIntrinsicMap["asinh"] = ALL_GLSL(Asinh);
57 fIntrinsicMap["acosh"] = ALL_GLSL(Acosh);
58 fIntrinsicMap["atanh"] = ALL_GLSL(Atanh);
59 fIntrinsicMap["pow"] = ALL_GLSL(Pow);
60 fIntrinsicMap["exp"] = ALL_GLSL(Exp);
61 fIntrinsicMap["log"] = ALL_GLSL(Log);
62 fIntrinsicMap["exp2"] = ALL_GLSL(Exp2);
63 fIntrinsicMap["log2"] = ALL_GLSL(Log2);
64 fIntrinsicMap["sqrt"] = ALL_GLSL(Sqrt);
65 fIntrinsicMap["inversesqrt"] = ALL_GLSL(InverseSqrt);
66 fIntrinsicMap["determinant"] = ALL_GLSL(Determinant);
67 fIntrinsicMap["matrixInverse"] = ALL_GLSL(MatrixInverse);
68 fIntrinsicMap["mod"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpFMod, SpvOpSMod,
69 SpvOpUMod, SpvOpUndef);
70 fIntrinsicMap["min"] = BY_TYPE_GLSL(FMin, SMin, UMin);
71 fIntrinsicMap["max"] = BY_TYPE_GLSL(FMax, SMax, UMax);
72 fIntrinsicMap["clamp"] = BY_TYPE_GLSL(FClamp, SClamp, UClamp);
73 fIntrinsicMap["dot"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDot, SpvOpUndef,
74 SpvOpUndef, SpvOpUndef);
75 fIntrinsicMap["mix"] = ALL_GLSL(FMix);
76 fIntrinsicMap["step"] = ALL_GLSL(Step);
77 fIntrinsicMap["smoothstep"] = ALL_GLSL(SmoothStep);
78 fIntrinsicMap["fma"] = ALL_GLSL(Fma);
79 fIntrinsicMap["frexp"] = ALL_GLSL(Frexp);
80 fIntrinsicMap["ldexp"] = ALL_GLSL(Ldexp);
81
82#define PACK(type) fIntrinsicMap["pack" #type] = ALL_GLSL(Pack ## type); \
83 fIntrinsicMap["unpack" #type] = ALL_GLSL(Unpack ## type)
84 PACK(Snorm4x8);
85 PACK(Unorm4x8);
86 PACK(Snorm2x16);
87 PACK(Unorm2x16);
88 PACK(Half2x16);
89 PACK(Double2x32);
90 fIntrinsicMap["length"] = ALL_GLSL(Length);
91 fIntrinsicMap["distance"] = ALL_GLSL(Distance);
92 fIntrinsicMap["cross"] = ALL_GLSL(Cross);
93 fIntrinsicMap["normalize"] = ALL_GLSL(Normalize);
94 fIntrinsicMap["faceForward"] = ALL_GLSL(FaceForward);
95 fIntrinsicMap["reflect"] = ALL_GLSL(Reflect);
96 fIntrinsicMap["refract"] = ALL_GLSL(Refract);
97 fIntrinsicMap["findLSB"] = ALL_GLSL(FindILsb);
98 fIntrinsicMap["findMSB"] = BY_TYPE_GLSL(FindSMsb, FindSMsb, FindUMsb);
99 fIntrinsicMap["dFdx"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdx, SpvOpUndef,
100 SpvOpUndef, SpvOpUndef);
101 fIntrinsicMap["dFdy"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdy, SpvOpUndef,
102 SpvOpUndef, SpvOpUndef);
103 fIntrinsicMap["dFdy"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdy, SpvOpUndef,
104 SpvOpUndef, SpvOpUndef);
105 fIntrinsicMap["texture"] = SPECIAL(Texture);
106 fIntrinsicMap["texture2D"] = SPECIAL(Texture2D);
107 fIntrinsicMap["textureProj"] = SPECIAL(TextureProj);
108
109 fIntrinsicMap["any"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
110 SpvOpUndef, SpvOpUndef, SpvOpAny);
111 fIntrinsicMap["all"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
112 SpvOpUndef, SpvOpUndef, SpvOpAll);
113 fIntrinsicMap["equal"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpFOrdEqual,
114 SpvOpIEqual, SpvOpIEqual,
115 SpvOpLogicalEqual);
116 fIntrinsicMap["notEqual"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpFOrdNotEqual,
117 SpvOpINotEqual, SpvOpINotEqual,
118 SpvOpLogicalNotEqual);
119 fIntrinsicMap["lessThan"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpSLessThan,
120 SpvOpULessThan, SpvOpFOrdLessThan,
121 SpvOpUndef);
122 fIntrinsicMap["lessThanEqual"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpSLessThanEqual,
123 SpvOpULessThanEqual, SpvOpFOrdLessThanEqual,
124 SpvOpUndef);
125 fIntrinsicMap["greaterThan"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpSGreaterThan,
126 SpvOpUGreaterThan, SpvOpFOrdGreaterThan,
127 SpvOpUndef);
128 fIntrinsicMap["greaterThanEqual"] = std::make_tuple(kSPIRV_IntrinsicKind,
129 SpvOpSGreaterThanEqual,
130 SpvOpUGreaterThanEqual,
131 SpvOpFOrdGreaterThanEqual,
132 SpvOpUndef);
133
134// interpolateAt* not yet supported...
135}
136
137void SPIRVCodeGenerator::writeWord(int32_t word, std::ostream& out) {
138#if SPIRV_DEBUG
139 out << "(" << word << ") ";
140#else
141 out.write((const char*) &word, sizeof(word));
142#endif
143}
144
ethannicholasd598f792016-07-25 10:08:54 -0700145static bool is_float(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700146 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700147 return is_float(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700148 }
ethannicholasd598f792016-07-25 10:08:54 -0700149 return type == *context.fFloat_Type || type == *context.fDouble_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700150}
151
ethannicholasd598f792016-07-25 10:08:54 -0700152static bool is_signed(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700153 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700154 return is_signed(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700155 }
ethannicholasd598f792016-07-25 10:08:54 -0700156 return type == *context.fInt_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700157}
158
ethannicholasd598f792016-07-25 10:08:54 -0700159static bool is_unsigned(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700160 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700161 return is_unsigned(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700162 }
ethannicholasd598f792016-07-25 10:08:54 -0700163 return type == *context.fUInt_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700164}
165
ethannicholasd598f792016-07-25 10:08:54 -0700166static bool is_bool(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700167 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700168 return is_bool(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700169 }
ethannicholasd598f792016-07-25 10:08:54 -0700170 return type == *context.fBool_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700171}
172
ethannicholasd598f792016-07-25 10:08:54 -0700173static bool is_out(const Variable& var) {
174 return (var.fModifiers.fFlags & Modifiers::kOut_Flag) != 0;
ethannicholasb3058bd2016-07-01 08:22:01 -0700175}
176
177#if SPIRV_DEBUG
178static std::string opcode_text(SpvOp_ opCode) {
179 switch (opCode) {
180 case SpvOpNop:
181 return "Nop";
182 case SpvOpUndef:
183 return "Undef";
184 case SpvOpSourceContinued:
185 return "SourceContinued";
186 case SpvOpSource:
187 return "Source";
188 case SpvOpSourceExtension:
189 return "SourceExtension";
190 case SpvOpName:
191 return "Name";
192 case SpvOpMemberName:
193 return "MemberName";
194 case SpvOpString:
195 return "String";
196 case SpvOpLine:
197 return "Line";
198 case SpvOpExtension:
199 return "Extension";
200 case SpvOpExtInstImport:
201 return "ExtInstImport";
202 case SpvOpExtInst:
203 return "ExtInst";
204 case SpvOpMemoryModel:
205 return "MemoryModel";
206 case SpvOpEntryPoint:
207 return "EntryPoint";
208 case SpvOpExecutionMode:
209 return "ExecutionMode";
210 case SpvOpCapability:
211 return "Capability";
212 case SpvOpTypeVoid:
213 return "TypeVoid";
214 case SpvOpTypeBool:
215 return "TypeBool";
216 case SpvOpTypeInt:
217 return "TypeInt";
218 case SpvOpTypeFloat:
219 return "TypeFloat";
220 case SpvOpTypeVector:
221 return "TypeVector";
222 case SpvOpTypeMatrix:
223 return "TypeMatrix";
224 case SpvOpTypeImage:
225 return "TypeImage";
226 case SpvOpTypeSampler:
227 return "TypeSampler";
228 case SpvOpTypeSampledImage:
229 return "TypeSampledImage";
230 case SpvOpTypeArray:
231 return "TypeArray";
232 case SpvOpTypeRuntimeArray:
233 return "TypeRuntimeArray";
234 case SpvOpTypeStruct:
235 return "TypeStruct";
236 case SpvOpTypeOpaque:
237 return "TypeOpaque";
238 case SpvOpTypePointer:
239 return "TypePointer";
240 case SpvOpTypeFunction:
241 return "TypeFunction";
242 case SpvOpTypeEvent:
243 return "TypeEvent";
244 case SpvOpTypeDeviceEvent:
245 return "TypeDeviceEvent";
246 case SpvOpTypeReserveId:
247 return "TypeReserveId";
248 case SpvOpTypeQueue:
249 return "TypeQueue";
250 case SpvOpTypePipe:
251 return "TypePipe";
252 case SpvOpTypeForwardPointer:
253 return "TypeForwardPointer";
254 case SpvOpConstantTrue:
255 return "ConstantTrue";
256 case SpvOpConstantFalse:
257 return "ConstantFalse";
258 case SpvOpConstant:
259 return "Constant";
260 case SpvOpConstantComposite:
261 return "ConstantComposite";
262 case SpvOpConstantSampler:
263 return "ConstantSampler";
264 case SpvOpConstantNull:
265 return "ConstantNull";
266 case SpvOpSpecConstantTrue:
267 return "SpecConstantTrue";
268 case SpvOpSpecConstantFalse:
269 return "SpecConstantFalse";
270 case SpvOpSpecConstant:
271 return "SpecConstant";
272 case SpvOpSpecConstantComposite:
273 return "SpecConstantComposite";
274 case SpvOpSpecConstantOp:
275 return "SpecConstantOp";
276 case SpvOpFunction:
277 return "Function";
278 case SpvOpFunctionParameter:
279 return "FunctionParameter";
280 case SpvOpFunctionEnd:
281 return "FunctionEnd";
282 case SpvOpFunctionCall:
283 return "FunctionCall";
284 case SpvOpVariable:
285 return "Variable";
286 case SpvOpImageTexelPointer:
287 return "ImageTexelPointer";
288 case SpvOpLoad:
289 return "Load";
290 case SpvOpStore:
291 return "Store";
292 case SpvOpCopyMemory:
293 return "CopyMemory";
294 case SpvOpCopyMemorySized:
295 return "CopyMemorySized";
296 case SpvOpAccessChain:
297 return "AccessChain";
298 case SpvOpInBoundsAccessChain:
299 return "InBoundsAccessChain";
300 case SpvOpPtrAccessChain:
301 return "PtrAccessChain";
302 case SpvOpArrayLength:
303 return "ArrayLength";
304 case SpvOpGenericPtrMemSemantics:
305 return "GenericPtrMemSemantics";
306 case SpvOpInBoundsPtrAccessChain:
307 return "InBoundsPtrAccessChain";
308 case SpvOpDecorate:
309 return "Decorate";
310 case SpvOpMemberDecorate:
311 return "MemberDecorate";
312 case SpvOpDecorationGroup:
313 return "DecorationGroup";
314 case SpvOpGroupDecorate:
315 return "GroupDecorate";
316 case SpvOpGroupMemberDecorate:
317 return "GroupMemberDecorate";
318 case SpvOpVectorExtractDynamic:
319 return "VectorExtractDynamic";
320 case SpvOpVectorInsertDynamic:
321 return "VectorInsertDynamic";
322 case SpvOpVectorShuffle:
323 return "VectorShuffle";
324 case SpvOpCompositeConstruct:
325 return "CompositeConstruct";
326 case SpvOpCompositeExtract:
327 return "CompositeExtract";
328 case SpvOpCompositeInsert:
329 return "CompositeInsert";
330 case SpvOpCopyObject:
331 return "CopyObject";
332 case SpvOpTranspose:
333 return "Transpose";
334 case SpvOpSampledImage:
335 return "SampledImage";
336 case SpvOpImageSampleImplicitLod:
337 return "ImageSampleImplicitLod";
338 case SpvOpImageSampleExplicitLod:
339 return "ImageSampleExplicitLod";
340 case SpvOpImageSampleDrefImplicitLod:
341 return "ImageSampleDrefImplicitLod";
342 case SpvOpImageSampleDrefExplicitLod:
343 return "ImageSampleDrefExplicitLod";
344 case SpvOpImageSampleProjImplicitLod:
345 return "ImageSampleProjImplicitLod";
346 case SpvOpImageSampleProjExplicitLod:
347 return "ImageSampleProjExplicitLod";
348 case SpvOpImageSampleProjDrefImplicitLod:
349 return "ImageSampleProjDrefImplicitLod";
350 case SpvOpImageSampleProjDrefExplicitLod:
351 return "ImageSampleProjDrefExplicitLod";
352 case SpvOpImageFetch:
353 return "ImageFetch";
354 case SpvOpImageGather:
355 return "ImageGather";
356 case SpvOpImageDrefGather:
357 return "ImageDrefGather";
358 case SpvOpImageRead:
359 return "ImageRead";
360 case SpvOpImageWrite:
361 return "ImageWrite";
362 case SpvOpImage:
363 return "Image";
364 case SpvOpImageQueryFormat:
365 return "ImageQueryFormat";
366 case SpvOpImageQueryOrder:
367 return "ImageQueryOrder";
368 case SpvOpImageQuerySizeLod:
369 return "ImageQuerySizeLod";
370 case SpvOpImageQuerySize:
371 return "ImageQuerySize";
372 case SpvOpImageQueryLod:
373 return "ImageQueryLod";
374 case SpvOpImageQueryLevels:
375 return "ImageQueryLevels";
376 case SpvOpImageQuerySamples:
377 return "ImageQuerySamples";
378 case SpvOpConvertFToU:
379 return "ConvertFToU";
380 case SpvOpConvertFToS:
381 return "ConvertFToS";
382 case SpvOpConvertSToF:
383 return "ConvertSToF";
384 case SpvOpConvertUToF:
385 return "ConvertUToF";
386 case SpvOpUConvert:
387 return "UConvert";
388 case SpvOpSConvert:
389 return "SConvert";
390 case SpvOpFConvert:
391 return "FConvert";
392 case SpvOpQuantizeToF16:
393 return "QuantizeToF16";
394 case SpvOpConvertPtrToU:
395 return "ConvertPtrToU";
396 case SpvOpSatConvertSToU:
397 return "SatConvertSToU";
398 case SpvOpSatConvertUToS:
399 return "SatConvertUToS";
400 case SpvOpConvertUToPtr:
401 return "ConvertUToPtr";
402 case SpvOpPtrCastToGeneric:
403 return "PtrCastToGeneric";
404 case SpvOpGenericCastToPtr:
405 return "GenericCastToPtr";
406 case SpvOpGenericCastToPtrExplicit:
407 return "GenericCastToPtrExplicit";
408 case SpvOpBitcast:
409 return "Bitcast";
410 case SpvOpSNegate:
411 return "SNegate";
412 case SpvOpFNegate:
413 return "FNegate";
414 case SpvOpIAdd:
415 return "IAdd";
416 case SpvOpFAdd:
417 return "FAdd";
418 case SpvOpISub:
419 return "ISub";
420 case SpvOpFSub:
421 return "FSub";
422 case SpvOpIMul:
423 return "IMul";
424 case SpvOpFMul:
425 return "FMul";
426 case SpvOpUDiv:
427 return "UDiv";
428 case SpvOpSDiv:
429 return "SDiv";
430 case SpvOpFDiv:
431 return "FDiv";
432 case SpvOpUMod:
433 return "UMod";
434 case SpvOpSRem:
435 return "SRem";
436 case SpvOpSMod:
437 return "SMod";
438 case SpvOpFRem:
439 return "FRem";
440 case SpvOpFMod:
441 return "FMod";
442 case SpvOpVectorTimesScalar:
443 return "VectorTimesScalar";
444 case SpvOpMatrixTimesScalar:
445 return "MatrixTimesScalar";
446 case SpvOpVectorTimesMatrix:
447 return "VectorTimesMatrix";
448 case SpvOpMatrixTimesVector:
449 return "MatrixTimesVector";
450 case SpvOpMatrixTimesMatrix:
451 return "MatrixTimesMatrix";
452 case SpvOpOuterProduct:
453 return "OuterProduct";
454 case SpvOpDot:
455 return "Dot";
456 case SpvOpIAddCarry:
457 return "IAddCarry";
458 case SpvOpISubBorrow:
459 return "ISubBorrow";
460 case SpvOpUMulExtended:
461 return "UMulExtended";
462 case SpvOpSMulExtended:
463 return "SMulExtended";
464 case SpvOpAny:
465 return "Any";
466 case SpvOpAll:
467 return "All";
468 case SpvOpIsNan:
469 return "IsNan";
470 case SpvOpIsInf:
471 return "IsInf";
472 case SpvOpIsFinite:
473 return "IsFinite";
474 case SpvOpIsNormal:
475 return "IsNormal";
476 case SpvOpSignBitSet:
477 return "SignBitSet";
478 case SpvOpLessOrGreater:
479 return "LessOrGreater";
480 case SpvOpOrdered:
481 return "Ordered";
482 case SpvOpUnordered:
483 return "Unordered";
484 case SpvOpLogicalEqual:
485 return "LogicalEqual";
486 case SpvOpLogicalNotEqual:
487 return "LogicalNotEqual";
488 case SpvOpLogicalOr:
489 return "LogicalOr";
490 case SpvOpLogicalAnd:
491 return "LogicalAnd";
492 case SpvOpLogicalNot:
493 return "LogicalNot";
494 case SpvOpSelect:
495 return "Select";
496 case SpvOpIEqual:
497 return "IEqual";
498 case SpvOpINotEqual:
499 return "INotEqual";
500 case SpvOpUGreaterThan:
501 return "UGreaterThan";
502 case SpvOpSGreaterThan:
503 return "SGreaterThan";
504 case SpvOpUGreaterThanEqual:
505 return "UGreaterThanEqual";
506 case SpvOpSGreaterThanEqual:
507 return "SGreaterThanEqual";
508 case SpvOpULessThan:
509 return "ULessThan";
510 case SpvOpSLessThan:
511 return "SLessThan";
512 case SpvOpULessThanEqual:
513 return "ULessThanEqual";
514 case SpvOpSLessThanEqual:
515 return "SLessThanEqual";
516 case SpvOpFOrdEqual:
517 return "FOrdEqual";
518 case SpvOpFUnordEqual:
519 return "FUnordEqual";
520 case SpvOpFOrdNotEqual:
521 return "FOrdNotEqual";
522 case SpvOpFUnordNotEqual:
523 return "FUnordNotEqual";
524 case SpvOpFOrdLessThan:
525 return "FOrdLessThan";
526 case SpvOpFUnordLessThan:
527 return "FUnordLessThan";
528 case SpvOpFOrdGreaterThan:
529 return "FOrdGreaterThan";
530 case SpvOpFUnordGreaterThan:
531 return "FUnordGreaterThan";
532 case SpvOpFOrdLessThanEqual:
533 return "FOrdLessThanEqual";
534 case SpvOpFUnordLessThanEqual:
535 return "FUnordLessThanEqual";
536 case SpvOpFOrdGreaterThanEqual:
537 return "FOrdGreaterThanEqual";
538 case SpvOpFUnordGreaterThanEqual:
539 return "FUnordGreaterThanEqual";
540 case SpvOpShiftRightLogical:
541 return "ShiftRightLogical";
542 case SpvOpShiftRightArithmetic:
543 return "ShiftRightArithmetic";
544 case SpvOpShiftLeftLogical:
545 return "ShiftLeftLogical";
546 case SpvOpBitwiseOr:
547 return "BitwiseOr";
548 case SpvOpBitwiseXor:
549 return "BitwiseXor";
550 case SpvOpBitwiseAnd:
551 return "BitwiseAnd";
552 case SpvOpNot:
553 return "Not";
554 case SpvOpBitFieldInsert:
555 return "BitFieldInsert";
556 case SpvOpBitFieldSExtract:
557 return "BitFieldSExtract";
558 case SpvOpBitFieldUExtract:
559 return "BitFieldUExtract";
560 case SpvOpBitReverse:
561 return "BitReverse";
562 case SpvOpBitCount:
563 return "BitCount";
564 case SpvOpDPdx:
565 return "DPdx";
566 case SpvOpDPdy:
567 return "DPdy";
568 case SpvOpFwidth:
569 return "Fwidth";
570 case SpvOpDPdxFine:
571 return "DPdxFine";
572 case SpvOpDPdyFine:
573 return "DPdyFine";
574 case SpvOpFwidthFine:
575 return "FwidthFine";
576 case SpvOpDPdxCoarse:
577 return "DPdxCoarse";
578 case SpvOpDPdyCoarse:
579 return "DPdyCoarse";
580 case SpvOpFwidthCoarse:
581 return "FwidthCoarse";
582 case SpvOpEmitVertex:
583 return "EmitVertex";
584 case SpvOpEndPrimitive:
585 return "EndPrimitive";
586 case SpvOpEmitStreamVertex:
587 return "EmitStreamVertex";
588 case SpvOpEndStreamPrimitive:
589 return "EndStreamPrimitive";
590 case SpvOpControlBarrier:
591 return "ControlBarrier";
592 case SpvOpMemoryBarrier:
593 return "MemoryBarrier";
594 case SpvOpAtomicLoad:
595 return "AtomicLoad";
596 case SpvOpAtomicStore:
597 return "AtomicStore";
598 case SpvOpAtomicExchange:
599 return "AtomicExchange";
600 case SpvOpAtomicCompareExchange:
601 return "AtomicCompareExchange";
602 case SpvOpAtomicCompareExchangeWeak:
603 return "AtomicCompareExchangeWeak";
604 case SpvOpAtomicIIncrement:
605 return "AtomicIIncrement";
606 case SpvOpAtomicIDecrement:
607 return "AtomicIDecrement";
608 case SpvOpAtomicIAdd:
609 return "AtomicIAdd";
610 case SpvOpAtomicISub:
611 return "AtomicISub";
612 case SpvOpAtomicSMin:
613 return "AtomicSMin";
614 case SpvOpAtomicUMin:
615 return "AtomicUMin";
616 case SpvOpAtomicSMax:
617 return "AtomicSMax";
618 case SpvOpAtomicUMax:
619 return "AtomicUMax";
620 case SpvOpAtomicAnd:
621 return "AtomicAnd";
622 case SpvOpAtomicOr:
623 return "AtomicOr";
624 case SpvOpAtomicXor:
625 return "AtomicXor";
626 case SpvOpPhi:
627 return "Phi";
628 case SpvOpLoopMerge:
629 return "LoopMerge";
630 case SpvOpSelectionMerge:
631 return "SelectionMerge";
632 case SpvOpLabel:
633 return "Label";
634 case SpvOpBranch:
635 return "Branch";
636 case SpvOpBranchConditional:
637 return "BranchConditional";
638 case SpvOpSwitch:
639 return "Switch";
640 case SpvOpKill:
641 return "Kill";
642 case SpvOpReturn:
643 return "Return";
644 case SpvOpReturnValue:
645 return "ReturnValue";
646 case SpvOpUnreachable:
647 return "Unreachable";
648 case SpvOpLifetimeStart:
649 return "LifetimeStart";
650 case SpvOpLifetimeStop:
651 return "LifetimeStop";
652 case SpvOpGroupAsyncCopy:
653 return "GroupAsyncCopy";
654 case SpvOpGroupWaitEvents:
655 return "GroupWaitEvents";
656 case SpvOpGroupAll:
657 return "GroupAll";
658 case SpvOpGroupAny:
659 return "GroupAny";
660 case SpvOpGroupBroadcast:
661 return "GroupBroadcast";
662 case SpvOpGroupIAdd:
663 return "GroupIAdd";
664 case SpvOpGroupFAdd:
665 return "GroupFAdd";
666 case SpvOpGroupFMin:
667 return "GroupFMin";
668 case SpvOpGroupUMin:
669 return "GroupUMin";
670 case SpvOpGroupSMin:
671 return "GroupSMin";
672 case SpvOpGroupFMax:
673 return "GroupFMax";
674 case SpvOpGroupUMax:
675 return "GroupUMax";
676 case SpvOpGroupSMax:
677 return "GroupSMax";
678 case SpvOpReadPipe:
679 return "ReadPipe";
680 case SpvOpWritePipe:
681 return "WritePipe";
682 case SpvOpReservedReadPipe:
683 return "ReservedReadPipe";
684 case SpvOpReservedWritePipe:
685 return "ReservedWritePipe";
686 case SpvOpReserveReadPipePackets:
687 return "ReserveReadPipePackets";
688 case SpvOpReserveWritePipePackets:
689 return "ReserveWritePipePackets";
690 case SpvOpCommitReadPipe:
691 return "CommitReadPipe";
692 case SpvOpCommitWritePipe:
693 return "CommitWritePipe";
694 case SpvOpIsValidReserveId:
695 return "IsValidReserveId";
696 case SpvOpGetNumPipePackets:
697 return "GetNumPipePackets";
698 case SpvOpGetMaxPipePackets:
699 return "GetMaxPipePackets";
700 case SpvOpGroupReserveReadPipePackets:
701 return "GroupReserveReadPipePackets";
702 case SpvOpGroupReserveWritePipePackets:
703 return "GroupReserveWritePipePackets";
704 case SpvOpGroupCommitReadPipe:
705 return "GroupCommitReadPipe";
706 case SpvOpGroupCommitWritePipe:
707 return "GroupCommitWritePipe";
708 case SpvOpEnqueueMarker:
709 return "EnqueueMarker";
710 case SpvOpEnqueueKernel:
711 return "EnqueueKernel";
712 case SpvOpGetKernelNDrangeSubGroupCount:
713 return "GetKernelNDrangeSubGroupCount";
714 case SpvOpGetKernelNDrangeMaxSubGroupSize:
715 return "GetKernelNDrangeMaxSubGroupSize";
716 case SpvOpGetKernelWorkGroupSize:
717 return "GetKernelWorkGroupSize";
718 case SpvOpGetKernelPreferredWorkGroupSizeMultiple:
719 return "GetKernelPreferredWorkGroupSizeMultiple";
720 case SpvOpRetainEvent:
721 return "RetainEvent";
722 case SpvOpReleaseEvent:
723 return "ReleaseEvent";
724 case SpvOpCreateUserEvent:
725 return "CreateUserEvent";
726 case SpvOpIsValidEvent:
727 return "IsValidEvent";
728 case SpvOpSetUserEventStatus:
729 return "SetUserEventStatus";
730 case SpvOpCaptureEventProfilingInfo:
731 return "CaptureEventProfilingInfo";
732 case SpvOpGetDefaultQueue:
733 return "GetDefaultQueue";
734 case SpvOpBuildNDRange:
735 return "BuildNDRange";
736 case SpvOpImageSparseSampleImplicitLod:
737 return "ImageSparseSampleImplicitLod";
738 case SpvOpImageSparseSampleExplicitLod:
739 return "ImageSparseSampleExplicitLod";
740 case SpvOpImageSparseSampleDrefImplicitLod:
741 return "ImageSparseSampleDrefImplicitLod";
742 case SpvOpImageSparseSampleDrefExplicitLod:
743 return "ImageSparseSampleDrefExplicitLod";
744 case SpvOpImageSparseSampleProjImplicitLod:
745 return "ImageSparseSampleProjImplicitLod";
746 case SpvOpImageSparseSampleProjExplicitLod:
747 return "ImageSparseSampleProjExplicitLod";
748 case SpvOpImageSparseSampleProjDrefImplicitLod:
749 return "ImageSparseSampleProjDrefImplicitLod";
750 case SpvOpImageSparseSampleProjDrefExplicitLod:
751 return "ImageSparseSampleProjDrefExplicitLod";
752 case SpvOpImageSparseFetch:
753 return "ImageSparseFetch";
754 case SpvOpImageSparseGather:
755 return "ImageSparseGather";
756 case SpvOpImageSparseDrefGather:
757 return "ImageSparseDrefGather";
758 case SpvOpImageSparseTexelsResident:
759 return "ImageSparseTexelsResident";
760 case SpvOpNoLine:
761 return "NoLine";
762 case SpvOpAtomicFlagTestAndSet:
763 return "AtomicFlagTestAndSet";
764 case SpvOpAtomicFlagClear:
765 return "AtomicFlagClear";
766 case SpvOpImageSparseRead:
767 return "ImageSparseRead";
768 default:
769 ABORT("unsupported SPIR-V op");
770 }
771}
772#endif
773
774void SPIRVCodeGenerator::writeOpCode(SpvOp_ opCode, int length, std::ostream& out) {
775 ASSERT(opCode != SpvOpUndef);
776 switch (opCode) {
777 case SpvOpReturn: // fall through
778 case SpvOpReturnValue: // fall through
ethannicholas552882f2016-07-07 06:30:48 -0700779 case SpvOpKill: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -0700780 case SpvOpBranch: // fall through
781 case SpvOpBranchConditional:
782 ASSERT(fCurrentBlock);
783 fCurrentBlock = 0;
784 break;
785 case SpvOpConstant: // fall through
786 case SpvOpConstantTrue: // fall through
787 case SpvOpConstantFalse: // fall through
788 case SpvOpConstantComposite: // fall through
789 case SpvOpTypeVoid: // fall through
790 case SpvOpTypeInt: // fall through
791 case SpvOpTypeFloat: // fall through
792 case SpvOpTypeBool: // fall through
793 case SpvOpTypeVector: // fall through
794 case SpvOpTypeMatrix: // fall through
795 case SpvOpTypeArray: // fall through
796 case SpvOpTypePointer: // fall through
797 case SpvOpTypeFunction: // fall through
798 case SpvOpTypeRuntimeArray: // fall through
799 case SpvOpTypeStruct: // fall through
800 case SpvOpTypeImage: // fall through
801 case SpvOpTypeSampledImage: // fall through
802 case SpvOpVariable: // fall through
803 case SpvOpFunction: // fall through
804 case SpvOpFunctionParameter: // fall through
805 case SpvOpFunctionEnd: // fall through
806 case SpvOpExecutionMode: // fall through
807 case SpvOpMemoryModel: // fall through
808 case SpvOpCapability: // fall through
809 case SpvOpExtInstImport: // fall through
810 case SpvOpEntryPoint: // fall through
811 case SpvOpSource: // fall through
812 case SpvOpSourceExtension: // fall through
813 case SpvOpName: // fall through
814 case SpvOpMemberName: // fall through
815 case SpvOpDecorate: // fall through
816 case SpvOpMemberDecorate:
817 break;
818 default:
819 ASSERT(fCurrentBlock);
820 }
821#if SPIRV_DEBUG
822 out << std::endl << opcode_text(opCode) << " ";
823#else
824 this->writeWord((length << 16) | opCode, out);
825#endif
826}
827
828void SPIRVCodeGenerator::writeLabel(SpvId label, std::ostream& out) {
829 fCurrentBlock = label;
830 this->writeInstruction(SpvOpLabel, label, out);
831}
832
833void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, std::ostream& out) {
834 this->writeOpCode(opCode, 1, out);
835}
836
837void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, std::ostream& out) {
838 this->writeOpCode(opCode, 2, out);
839 this->writeWord(word1, out);
840}
841
842void SPIRVCodeGenerator::writeString(const char* string, std::ostream& out) {
843 size_t length = strlen(string);
844 out << string;
845 switch (length % 4) {
846 case 1:
847 out << (char) 0;
848 // fall through
849 case 2:
850 out << (char) 0;
851 // fall through
852 case 3:
853 out << (char) 0;
854 break;
855 default:
856 this->writeWord(0, out);
857 }
858}
859
860void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, const char* string, std::ostream& out) {
861 int32_t length = (int32_t) strlen(string);
862 this->writeOpCode(opCode, 1 + (length + 4) / 4, out);
863 this->writeString(string, out);
864}
865
866
867void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, const char* string,
868 std::ostream& out) {
869 int32_t length = (int32_t) strlen(string);
870 this->writeOpCode(opCode, 2 + (length + 4) / 4, out);
871 this->writeWord(word1, out);
872 this->writeString(string, out);
873}
874
875void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
876 const char* string, std::ostream& out) {
877 int32_t length = (int32_t) strlen(string);
878 this->writeOpCode(opCode, 3 + (length + 4) / 4, out);
879 this->writeWord(word1, out);
880 this->writeWord(word2, out);
881 this->writeString(string, out);
882}
883
884void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
885 std::ostream& out) {
886 this->writeOpCode(opCode, 3, out);
887 this->writeWord(word1, out);
888 this->writeWord(word2, out);
889}
890
891void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
892 int32_t word3, std::ostream& out) {
893 this->writeOpCode(opCode, 4, out);
894 this->writeWord(word1, out);
895 this->writeWord(word2, out);
896 this->writeWord(word3, out);
897}
898
899void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
900 int32_t word3, int32_t word4, std::ostream& out) {
901 this->writeOpCode(opCode, 5, out);
902 this->writeWord(word1, out);
903 this->writeWord(word2, out);
904 this->writeWord(word3, out);
905 this->writeWord(word4, out);
906}
907
908void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
909 int32_t word3, int32_t word4, int32_t word5,
910 std::ostream& out) {
911 this->writeOpCode(opCode, 6, out);
912 this->writeWord(word1, out);
913 this->writeWord(word2, out);
914 this->writeWord(word3, out);
915 this->writeWord(word4, out);
916 this->writeWord(word5, out);
917}
918
919void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
920 int32_t word3, int32_t word4, int32_t word5,
921 int32_t word6, std::ostream& out) {
922 this->writeOpCode(opCode, 7, out);
923 this->writeWord(word1, out);
924 this->writeWord(word2, out);
925 this->writeWord(word3, out);
926 this->writeWord(word4, out);
927 this->writeWord(word5, out);
928 this->writeWord(word6, out);
929}
930
931void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
932 int32_t word3, int32_t word4, int32_t word5,
933 int32_t word6, int32_t word7, std::ostream& out) {
934 this->writeOpCode(opCode, 8, out);
935 this->writeWord(word1, out);
936 this->writeWord(word2, out);
937 this->writeWord(word3, out);
938 this->writeWord(word4, out);
939 this->writeWord(word5, out);
940 this->writeWord(word6, out);
941 this->writeWord(word7, out);
942}
943
944void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
945 int32_t word3, int32_t word4, int32_t word5,
946 int32_t word6, int32_t word7, int32_t word8,
947 std::ostream& out) {
948 this->writeOpCode(opCode, 9, out);
949 this->writeWord(word1, out);
950 this->writeWord(word2, out);
951 this->writeWord(word3, out);
952 this->writeWord(word4, out);
953 this->writeWord(word5, out);
954 this->writeWord(word6, out);
955 this->writeWord(word7, out);
956 this->writeWord(word8, out);
957}
958
959void SPIRVCodeGenerator::writeCapabilities(std::ostream& out) {
960 for (uint64_t i = 0, bit = 1; i <= kLast_Capability; i++, bit <<= 1) {
961 if (fCapabilities & bit) {
962 this->writeInstruction(SpvOpCapability, (SpvId) i, out);
963 }
964 }
965}
966
967SpvId SPIRVCodeGenerator::nextId() {
968 return fIdCount++;
969}
970
ethannicholasfa5f65a2016-11-15 12:53:05 -0800971void SPIRVCodeGenerator::writeStruct(const Type& type, const MemoryLayout& layout, SpvId resultId) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700972 this->writeInstruction(SpvOpName, resultId, type.name().c_str(), fNameBuffer);
973 // go ahead and write all of the field types, so we don't inadvertently write them while we're
974 // in the middle of writing the struct instruction
975 std::vector<SpvId> types;
976 for (const auto& f : type.fields()) {
ethannicholasfa5f65a2016-11-15 12:53:05 -0800977 types.push_back(this->getType(*f.fType, layout));
ethannicholasb3058bd2016-07-01 08:22:01 -0700978 }
979 this->writeOpCode(SpvOpTypeStruct, 2 + (int32_t) types.size(), fConstantBuffer);
980 this->writeWord(resultId, fConstantBuffer);
981 for (SpvId id : types) {
982 this->writeWord(id, fConstantBuffer);
983 }
984 size_t offset = 0;
985 for (int32_t i = 0; i < (int32_t) type.fields().size(); i++) {
ethannicholasfa5f65a2016-11-15 12:53:05 -0800986 size_t size = layout.size(*type.fields()[i].fType);
987 size_t alignment = layout.alignment(*type.fields()[i].fType);
ethannicholasb3058bd2016-07-01 08:22:01 -0700988 size_t mod = offset % alignment;
989 if (mod != 0) {
990 offset += alignment - mod;
991 }
992 this->writeInstruction(SpvOpMemberName, resultId, i, type.fields()[i].fName.c_str(),
993 fNameBuffer);
994 this->writeLayout(type.fields()[i].fModifiers.fLayout, resultId, i);
995 if (type.fields()[i].fModifiers.fLayout.fBuiltin < 0) {
996 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i, SpvDecorationOffset,
997 (SpvId) offset, fDecorationBuffer);
998 }
ethannicholas0730be72016-09-01 07:59:02 -0700999 if (type.fields()[i].fType->kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001000 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationColMajor,
1001 fDecorationBuffer);
1002 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationMatrixStride,
ethannicholasfa5f65a2016-11-15 12:53:05 -08001003 (SpvId) layout.stride(*type.fields()[i].fType),
1004 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001005 }
1006 offset += size;
ethannicholas0730be72016-09-01 07:59:02 -07001007 Type::Kind kind = type.fields()[i].fType->kind();
ethannicholasb3058bd2016-07-01 08:22:01 -07001008 if ((kind == Type::kArray_Kind || kind == Type::kStruct_Kind) && offset % alignment != 0) {
1009 offset += alignment - offset % alignment;
1010 }
1011 ASSERT(offset % alignment == 0);
1012 }
1013}
1014
1015SpvId SPIRVCodeGenerator::getType(const Type& type) {
ethannicholasfa5f65a2016-11-15 12:53:05 -08001016 return this->getType(type, fDefaultLayout);
1017}
1018
1019SpvId SPIRVCodeGenerator::getType(const Type& type, const MemoryLayout& layout) {
1020 std::string key = type.name() + to_string((int) layout.fStd);
1021 auto entry = fTypeMap.find(key);
ethannicholasb3058bd2016-07-01 08:22:01 -07001022 if (entry == fTypeMap.end()) {
1023 SpvId result = this->nextId();
1024 switch (type.kind()) {
1025 case Type::kScalar_Kind:
ethannicholasd598f792016-07-25 10:08:54 -07001026 if (type == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001027 this->writeInstruction(SpvOpTypeBool, result, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001028 } else if (type == *fContext.fInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001029 this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001030 } else if (type == *fContext.fUInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001031 this->writeInstruction(SpvOpTypeInt, result, 32, 0, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001032 } else if (type == *fContext.fFloat_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001033 this->writeInstruction(SpvOpTypeFloat, result, 32, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001034 } else if (type == *fContext.fDouble_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001035 this->writeInstruction(SpvOpTypeFloat, result, 64, fConstantBuffer);
1036 } else {
1037 ASSERT(false);
1038 }
1039 break;
1040 case Type::kVector_Kind:
1041 this->writeInstruction(SpvOpTypeVector, result,
ethannicholasfa5f65a2016-11-15 12:53:05 -08001042 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -07001043 type.columns(), fConstantBuffer);
1044 break;
1045 case Type::kMatrix_Kind:
ethannicholasd598f792016-07-25 10:08:54 -07001046 this->writeInstruction(SpvOpTypeMatrix, result,
ethannicholasfa5f65a2016-11-15 12:53:05 -08001047 this->getType(index_type(fContext, type), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -07001048 type.columns(), fConstantBuffer);
1049 break;
1050 case Type::kStruct_Kind:
ethannicholasfa5f65a2016-11-15 12:53:05 -08001051 this->writeStruct(type, layout, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001052 break;
1053 case Type::kArray_Kind: {
1054 if (type.columns() > 0) {
ethannicholasd598f792016-07-25 10:08:54 -07001055 IntLiteral count(fContext, Position(), type.columns());
ethannicholasb3058bd2016-07-01 08:22:01 -07001056 this->writeInstruction(SpvOpTypeArray, result,
ethannicholasfa5f65a2016-11-15 12:53:05 -08001057 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -07001058 this->writeIntLiteral(count), fConstantBuffer);
1059 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
ethannicholasfa5f65a2016-11-15 12:53:05 -08001060 (int32_t) layout.stride(type),
1061 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001062 } else {
1063 ABORT("runtime-sized arrays are not yet supported");
1064 this->writeInstruction(SpvOpTypeRuntimeArray, result,
ethannicholasfa5f65a2016-11-15 12:53:05 -08001065 this->getType(type.componentType(), layout),
1066 fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001067 }
1068 break;
1069 }
1070 case Type::kSampler_Kind: {
1071 SpvId image = this->nextId();
ethannicholasfa5f65a2016-11-15 12:53:05 -08001072 this->writeInstruction(SpvOpTypeImage, image,
1073 this->getType(*fContext.fFloat_Type, layout),
ethannicholasb3058bd2016-07-01 08:22:01 -07001074 type.dimensions(), type.isDepth(), type.isArrayed(),
1075 type.isMultisampled(), type.isSampled(),
1076 SpvImageFormatUnknown, fConstantBuffer);
1077 this->writeInstruction(SpvOpTypeSampledImage, result, image, fConstantBuffer);
1078 break;
1079 }
1080 default:
ethannicholasd598f792016-07-25 10:08:54 -07001081 if (type == *fContext.fVoid_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001082 this->writeInstruction(SpvOpTypeVoid, result, fConstantBuffer);
1083 } else {
1084 ABORT("invalid type: %s", type.description().c_str());
1085 }
1086 }
ethannicholasfa5f65a2016-11-15 12:53:05 -08001087 fTypeMap[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001088 return result;
1089 }
1090 return entry->second;
1091}
1092
ethannicholasd598f792016-07-25 10:08:54 -07001093SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) {
1094 std::string key = function.fReturnType.description() + "(";
ethannicholasb3058bd2016-07-01 08:22:01 -07001095 std::string separator = "";
ethannicholasd598f792016-07-25 10:08:54 -07001096 for (size_t i = 0; i < function.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001097 key += separator;
1098 separator = ", ";
ethannicholasd598f792016-07-25 10:08:54 -07001099 key += function.fParameters[i]->fType.description();
ethannicholasb3058bd2016-07-01 08:22:01 -07001100 }
1101 key += ")";
1102 auto entry = fTypeMap.find(key);
1103 if (entry == fTypeMap.end()) {
1104 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001105 int32_t length = 3 + (int32_t) function.fParameters.size();
1106 SpvId returnType = this->getType(function.fReturnType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001107 std::vector<SpvId> parameterTypes;
ethannicholasd598f792016-07-25 10:08:54 -07001108 for (size_t i = 0; i < function.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001109 // glslang seems to treat all function arguments as pointers whether they need to be or
1110 // not. I was initially puzzled by this until I ran bizarre failures with certain
1111 // patterns of function calls and control constructs, as exemplified by this minimal
1112 // failure case:
1113 //
1114 // void sphere(float x) {
1115 // }
1116 //
1117 // void map() {
1118 // sphere(1.0);
1119 // }
1120 //
1121 // void main() {
1122 // for (int i = 0; i < 1; i++) {
1123 // map();
1124 // }
1125 // }
1126 //
1127 // As of this writing, compiling this in the "obvious" way (with sphere taking a float)
1128 // crashes. Making it take a float* and storing the argument in a temporary variable,
1129 // as glslang does, fixes it. It's entirely possible I simply missed whichever part of
1130 // the spec makes this make sense.
1131// if (is_out(function->fParameters[i])) {
ethannicholasd598f792016-07-25 10:08:54 -07001132 parameterTypes.push_back(this->getPointerType(function.fParameters[i]->fType,
ethannicholasb3058bd2016-07-01 08:22:01 -07001133 SpvStorageClassFunction));
1134// } else {
ethannicholasd598f792016-07-25 10:08:54 -07001135// parameterTypes.push_back(this->getType(function.fParameters[i]->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -07001136// }
1137 }
1138 this->writeOpCode(SpvOpTypeFunction, length, fConstantBuffer);
1139 this->writeWord(result, fConstantBuffer);
1140 this->writeWord(returnType, fConstantBuffer);
1141 for (SpvId id : parameterTypes) {
1142 this->writeWord(id, fConstantBuffer);
1143 }
1144 fTypeMap[key] = result;
1145 return result;
1146 }
1147 return entry->second;
1148}
1149
ethannicholasfa5f65a2016-11-15 12:53:05 -08001150SpvId SPIRVCodeGenerator::getPointerType(const Type& type, SpvStorageClass_ storageClass) {
1151 return this->getPointerType(type, fDefaultLayout, storageClass);
1152}
1153
1154SpvId SPIRVCodeGenerator::getPointerType(const Type& type, const MemoryLayout& layout,
ethannicholasb3058bd2016-07-01 08:22:01 -07001155 SpvStorageClass_ storageClass) {
ethannicholasfa5f65a2016-11-15 12:53:05 -08001156 std::string key = type.description() + "*" + to_string(layout.fStd) + to_string(storageClass);
ethannicholasb3058bd2016-07-01 08:22:01 -07001157 auto entry = fTypeMap.find(key);
1158 if (entry == fTypeMap.end()) {
1159 SpvId result = this->nextId();
1160 this->writeInstruction(SpvOpTypePointer, result, storageClass,
ethannicholasd598f792016-07-25 10:08:54 -07001161 this->getType(type), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001162 fTypeMap[key] = result;
1163 return result;
1164 }
1165 return entry->second;
1166}
1167
ethannicholasf789b382016-08-03 12:43:36 -07001168SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001169 switch (expr.fKind) {
1170 case Expression::kBinary_Kind:
1171 return this->writeBinaryExpression((BinaryExpression&) expr, out);
1172 case Expression::kBoolLiteral_Kind:
1173 return this->writeBoolLiteral((BoolLiteral&) expr);
1174 case Expression::kConstructor_Kind:
1175 return this->writeConstructor((Constructor&) expr, out);
1176 case Expression::kIntLiteral_Kind:
1177 return this->writeIntLiteral((IntLiteral&) expr);
1178 case Expression::kFieldAccess_Kind:
1179 return this->writeFieldAccess(((FieldAccess&) expr), out);
1180 case Expression::kFloatLiteral_Kind:
1181 return this->writeFloatLiteral(((FloatLiteral&) expr));
1182 case Expression::kFunctionCall_Kind:
1183 return this->writeFunctionCall((FunctionCall&) expr, out);
1184 case Expression::kPrefix_Kind:
1185 return this->writePrefixExpression((PrefixExpression&) expr, out);
1186 case Expression::kPostfix_Kind:
1187 return this->writePostfixExpression((PostfixExpression&) expr, out);
1188 case Expression::kSwizzle_Kind:
1189 return this->writeSwizzle((Swizzle&) expr, out);
1190 case Expression::kVariableReference_Kind:
1191 return this->writeVariableReference((VariableReference&) expr, out);
1192 case Expression::kTernary_Kind:
1193 return this->writeTernaryExpression((TernaryExpression&) expr, out);
1194 case Expression::kIndex_Kind:
1195 return this->writeIndexExpression((IndexExpression&) expr, out);
1196 default:
1197 ABORT("unsupported expression: %s", expr.description().c_str());
1198 }
1199 return -1;
1200}
1201
ethannicholasf789b382016-08-03 12:43:36 -07001202SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, std::ostream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001203 auto intrinsic = fIntrinsicMap.find(c.fFunction.fName);
ethannicholasb3058bd2016-07-01 08:22:01 -07001204 ASSERT(intrinsic != fIntrinsicMap.end());
ethannicholasd598f792016-07-25 10:08:54 -07001205 const Type& type = c.fArguments[0]->fType;
ethannicholasb3058bd2016-07-01 08:22:01 -07001206 int32_t intrinsicId;
ethannicholasd598f792016-07-25 10:08:54 -07001207 if (std::get<0>(intrinsic->second) == kSpecial_IntrinsicKind || is_float(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001208 intrinsicId = std::get<1>(intrinsic->second);
ethannicholasd598f792016-07-25 10:08:54 -07001209 } else if (is_signed(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001210 intrinsicId = std::get<2>(intrinsic->second);
ethannicholasd598f792016-07-25 10:08:54 -07001211 } else if (is_unsigned(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001212 intrinsicId = std::get<3>(intrinsic->second);
ethannicholasd598f792016-07-25 10:08:54 -07001213 } else if (is_bool(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001214 intrinsicId = std::get<4>(intrinsic->second);
1215 } else {
1216 ABORT("invalid call %s, cannot operate on '%s'", c.description().c_str(),
ethannicholasd598f792016-07-25 10:08:54 -07001217 type.description().c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -07001218 }
1219 switch (std::get<0>(intrinsic->second)) {
1220 case kGLSL_STD_450_IntrinsicKind: {
1221 SpvId result = this->nextId();
1222 std::vector<SpvId> arguments;
1223 for (size_t i = 0; i < c.fArguments.size(); i++) {
1224 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1225 }
1226 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001227 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001228 this->writeWord(result, out);
1229 this->writeWord(fGLSLExtendedInstructions, out);
1230 this->writeWord(intrinsicId, out);
1231 for (SpvId id : arguments) {
1232 this->writeWord(id, out);
1233 }
1234 return result;
1235 }
1236 case kSPIRV_IntrinsicKind: {
1237 SpvId result = this->nextId();
1238 std::vector<SpvId> arguments;
1239 for (size_t i = 0; i < c.fArguments.size(); i++) {
1240 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1241 }
1242 this->writeOpCode((SpvOp_) intrinsicId, 3 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001243 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001244 this->writeWord(result, out);
1245 for (SpvId id : arguments) {
1246 this->writeWord(id, out);
1247 }
1248 return result;
1249 }
1250 case kSpecial_IntrinsicKind:
1251 return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId, out);
1252 default:
1253 ABORT("unsupported intrinsic kind");
1254 }
1255}
1256
ethannicholasf789b382016-08-03 12:43:36 -07001257SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind,
ethannicholasb3058bd2016-07-01 08:22:01 -07001258 std::ostream& out) {
1259 SpvId result = this->nextId();
1260 switch (kind) {
1261 case kAtan_SpecialIntrinsic: {
1262 std::vector<SpvId> arguments;
1263 for (size_t i = 0; i < c.fArguments.size(); i++) {
1264 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1265 }
1266 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001267 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001268 this->writeWord(result, out);
1269 this->writeWord(fGLSLExtendedInstructions, out);
1270 this->writeWord(arguments.size() == 2 ? GLSLstd450Atan2 : GLSLstd450Atan, out);
1271 for (SpvId id : arguments) {
1272 this->writeWord(id, out);
1273 }
1274 return result;
1275 }
1276 case kTexture_SpecialIntrinsic: {
ethannicholasd598f792016-07-25 10:08:54 -07001277 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001278 SpvId sampler = this->writeExpression(*c.fArguments[0], out);
1279 SpvId uv = this->writeExpression(*c.fArguments[1], out);
1280 if (c.fArguments.size() == 3) {
1281 this->writeInstruction(SpvOpImageSampleImplicitLod, type, result, sampler, uv,
1282 SpvImageOperandsBiasMask,
1283 this->writeExpression(*c.fArguments[2], out),
1284 out);
1285 } else {
1286 ASSERT(c.fArguments.size() == 2);
1287 this->writeInstruction(SpvOpImageSampleImplicitLod, type, result, sampler, uv, out);
1288 }
1289 break;
1290 }
1291 case kTextureProj_SpecialIntrinsic: {
ethannicholasd598f792016-07-25 10:08:54 -07001292 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001293 SpvId sampler = this->writeExpression(*c.fArguments[0], out);
1294 SpvId uv = this->writeExpression(*c.fArguments[1], out);
1295 if (c.fArguments.size() == 3) {
1296 this->writeInstruction(SpvOpImageSampleProjImplicitLod, type, result, sampler, uv,
1297 SpvImageOperandsBiasMask,
1298 this->writeExpression(*c.fArguments[2], out),
1299 out);
1300 } else {
1301 ASSERT(c.fArguments.size() == 2);
1302 this->writeInstruction(SpvOpImageSampleProjImplicitLod, type, result, sampler, uv,
1303 out);
1304 }
1305 break;
1306 }
1307 case kTexture2D_SpecialIntrinsic: {
1308 SpvId img = this->writeExpression(*c.fArguments[0], out);
1309 SpvId coords = this->writeExpression(*c.fArguments[1], out);
1310 this->writeInstruction(SpvOpImageSampleImplicitLod,
ethannicholasd598f792016-07-25 10:08:54 -07001311 this->getType(c.fType),
ethannicholasb3058bd2016-07-01 08:22:01 -07001312 result,
1313 img,
1314 coords,
1315 out);
1316 break;
1317 }
1318 }
1319 return result;
1320}
1321
ethannicholasf789b382016-08-03 12:43:36 -07001322SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, std::ostream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001323 const auto& entry = fFunctionMap.find(&c.fFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07001324 if (entry == fFunctionMap.end()) {
1325 return this->writeIntrinsicCall(c, out);
1326 }
1327 // stores (variable, type, lvalue) pairs to extract and save after the function call is complete
1328 std::vector<std::tuple<SpvId, SpvId, std::unique_ptr<LValue>>> lvalues;
1329 std::vector<SpvId> arguments;
1330 for (size_t i = 0; i < c.fArguments.size(); i++) {
1331 // id of temporary variable that we will use to hold this argument, or 0 if it is being
1332 // passed directly
1333 SpvId tmpVar;
1334 // if we need a temporary var to store this argument, this is the value to store in the var
1335 SpvId tmpValueId;
ethannicholasd598f792016-07-25 10:08:54 -07001336 if (is_out(*c.fFunction.fParameters[i])) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001337 std::unique_ptr<LValue> lv = this->getLValue(*c.fArguments[i], out);
1338 SpvId ptr = lv->getPointer();
1339 if (ptr) {
1340 arguments.push_back(ptr);
1341 continue;
1342 } else {
1343 // lvalue cannot simply be read and written via a pointer (e.g. a swizzle). Need to
1344 // copy it into a temp, call the function, read the value out of the temp, and then
1345 // update the lvalue.
1346 tmpValueId = lv->load(out);
1347 tmpVar = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001348 lvalues.push_back(std::make_tuple(tmpVar, this->getType(c.fArguments[i]->fType),
ethannicholasb3058bd2016-07-01 08:22:01 -07001349 std::move(lv)));
1350 }
1351 } else {
1352 // see getFunctionType for an explanation of why we're always using pointer parameters
1353 tmpValueId = this->writeExpression(*c.fArguments[i], out);
1354 tmpVar = this->nextId();
1355 }
1356 this->writeInstruction(SpvOpVariable,
1357 this->getPointerType(c.fArguments[i]->fType,
1358 SpvStorageClassFunction),
1359 tmpVar,
1360 SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001361 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001362 this->writeInstruction(SpvOpStore, tmpVar, tmpValueId, out);
1363 arguments.push_back(tmpVar);
1364 }
1365 SpvId result = this->nextId();
1366 this->writeOpCode(SpvOpFunctionCall, 4 + (int32_t) c.fArguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001367 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001368 this->writeWord(result, out);
1369 this->writeWord(entry->second, out);
1370 for (SpvId id : arguments) {
1371 this->writeWord(id, out);
1372 }
1373 // now that the call is complete, we may need to update some lvalues with the new values of out
1374 // arguments
1375 for (const auto& tuple : lvalues) {
1376 SpvId load = this->nextId();
1377 this->writeInstruction(SpvOpLoad, std::get<1>(tuple), load, std::get<0>(tuple), out);
1378 std::get<2>(tuple)->store(load, out);
1379 }
1380 return result;
1381}
1382
ethannicholasf789b382016-08-03 12:43:36 -07001383SpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) {
ethannicholasd598f792016-07-25 10:08:54 -07001384 ASSERT(c.fType.kind() == Type::kVector_Kind && c.isConstant());
ethannicholasb3058bd2016-07-01 08:22:01 -07001385 SpvId result = this->nextId();
1386 std::vector<SpvId> arguments;
1387 for (size_t i = 0; i < c.fArguments.size(); i++) {
1388 arguments.push_back(this->writeExpression(*c.fArguments[i], fConstantBuffer));
1389 }
ethannicholasd598f792016-07-25 10:08:54 -07001390 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001391 if (c.fArguments.size() == 1) {
1392 // with a single argument, a vector will have all of its entries equal to the argument
ethannicholasd598f792016-07-25 10:08:54 -07001393 this->writeOpCode(SpvOpConstantComposite, 3 + c.fType.columns(), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001394 this->writeWord(type, fConstantBuffer);
1395 this->writeWord(result, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001396 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001397 this->writeWord(arguments[0], fConstantBuffer);
1398 }
1399 } else {
1400 this->writeOpCode(SpvOpConstantComposite, 3 + (int32_t) c.fArguments.size(),
1401 fConstantBuffer);
1402 this->writeWord(type, fConstantBuffer);
1403 this->writeWord(result, fConstantBuffer);
1404 for (SpvId id : arguments) {
1405 this->writeWord(id, fConstantBuffer);
1406 }
1407 }
1408 return result;
1409}
1410
ethannicholasf789b382016-08-03 12:43:36 -07001411SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, std::ostream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001412 ASSERT(c.fType == *fContext.fFloat_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07001413 ASSERT(c.fArguments.size() == 1);
ethannicholasd598f792016-07-25 10:08:54 -07001414 ASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001415 SpvId result = this->nextId();
1416 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
ethannicholasd598f792016-07-25 10:08:54 -07001417 if (c.fArguments[0]->fType == *fContext.fInt_Type) {
1418 this->writeInstruction(SpvOpConvertSToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001419 out);
ethannicholasd598f792016-07-25 10:08:54 -07001420 } else if (c.fArguments[0]->fType == *fContext.fUInt_Type) {
1421 this->writeInstruction(SpvOpConvertUToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001422 out);
ethannicholasd598f792016-07-25 10:08:54 -07001423 } else if (c.fArguments[0]->fType == *fContext.fFloat_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001424 return parameter;
1425 }
1426 return result;
1427}
1428
ethannicholasf789b382016-08-03 12:43:36 -07001429SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, std::ostream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001430 ASSERT(c.fType == *fContext.fInt_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07001431 ASSERT(c.fArguments.size() == 1);
ethannicholasd598f792016-07-25 10:08:54 -07001432 ASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001433 SpvId result = this->nextId();
1434 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
ethannicholasd598f792016-07-25 10:08:54 -07001435 if (c.fArguments[0]->fType == *fContext.fFloat_Type) {
1436 this->writeInstruction(SpvOpConvertFToS, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001437 out);
ethannicholasd598f792016-07-25 10:08:54 -07001438 } else if (c.fArguments[0]->fType == *fContext.fUInt_Type) {
1439 this->writeInstruction(SpvOpSatConvertUToS, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001440 out);
ethannicholasd598f792016-07-25 10:08:54 -07001441 } else if (c.fArguments[0]->fType == *fContext.fInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001442 return parameter;
1443 }
1444 return result;
1445}
1446
ethannicholasf789b382016-08-03 12:43:36 -07001447SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, std::ostream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001448 ASSERT(c.fType.kind() == Type::kMatrix_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001449 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1450 // an instruction
1451 std::vector<SpvId> arguments;
1452 for (size_t i = 0; i < c.fArguments.size(); i++) {
1453 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1454 }
1455 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001456 int rows = c.fType.rows();
1457 int columns = c.fType.columns();
ethannicholasb3058bd2016-07-01 08:22:01 -07001458 // FIXME this won't work to create a matrix from another matrix
1459 if (arguments.size() == 1) {
1460 // with a single argument, a matrix will have all of its diagonal entries equal to the
1461 // argument and its other values equal to zero
1462 // FIXME this won't work for int matrices
ethannicholasd598f792016-07-25 10:08:54 -07001463 FloatLiteral zero(fContext, Position(), 0);
ethannicholasb3058bd2016-07-01 08:22:01 -07001464 SpvId zeroId = this->writeFloatLiteral(zero);
1465 std::vector<SpvId> columnIds;
1466 for (int column = 0; column < columns; column++) {
ethannicholasd598f792016-07-25 10:08:54 -07001467 this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.rows(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001468 out);
ethannicholasd598f792016-07-25 10:08:54 -07001469 this->writeWord(this->getType(c.fType.componentType().toCompound(fContext, rows, 1)),
1470 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001471 SpvId columnId = this->nextId();
1472 this->writeWord(columnId, out);
1473 columnIds.push_back(columnId);
ethannicholasd598f792016-07-25 10:08:54 -07001474 for (int row = 0; row < c.fType.columns(); row++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001475 this->writeWord(row == column ? arguments[0] : zeroId, out);
1476 }
1477 }
1478 this->writeOpCode(SpvOpCompositeConstruct, 3 + columns,
1479 out);
ethannicholasd598f792016-07-25 10:08:54 -07001480 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001481 this->writeWord(result, out);
1482 for (SpvId id : columnIds) {
1483 this->writeWord(id, out);
1484 }
1485 } else {
1486 std::vector<SpvId> columnIds;
1487 int currentCount = 0;
1488 for (size_t i = 0; i < arguments.size(); i++) {
ethannicholasd598f792016-07-25 10:08:54 -07001489 if (c.fArguments[i]->fType.kind() == Type::kVector_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001490 ASSERT(currentCount == 0);
1491 columnIds.push_back(arguments[i]);
1492 currentCount = 0;
1493 } else {
ethannicholasd598f792016-07-25 10:08:54 -07001494 ASSERT(c.fArguments[i]->fType.kind() == Type::kScalar_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001495 if (currentCount == 0) {
ethannicholasd598f792016-07-25 10:08:54 -07001496 this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.rows(), out);
1497 this->writeWord(this->getType(c.fType.componentType().toCompound(fContext, rows,
1498 1)),
ethannicholasb3058bd2016-07-01 08:22:01 -07001499 out);
1500 SpvId id = this->nextId();
1501 this->writeWord(id, out);
1502 columnIds.push_back(id);
1503 }
1504 this->writeWord(arguments[i], out);
1505 currentCount = (currentCount + 1) % rows;
1506 }
1507 }
1508 ASSERT(columnIds.size() == (size_t) columns);
1509 this->writeOpCode(SpvOpCompositeConstruct, 3 + columns, out);
ethannicholasd598f792016-07-25 10:08:54 -07001510 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001511 this->writeWord(result, out);
1512 for (SpvId id : columnIds) {
1513 this->writeWord(id, out);
1514 }
1515 }
1516 return result;
1517}
1518
ethannicholasf789b382016-08-03 12:43:36 -07001519SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, std::ostream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001520 ASSERT(c.fType.kind() == Type::kVector_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001521 if (c.isConstant()) {
1522 return this->writeConstantVector(c);
1523 }
1524 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1525 // an instruction
1526 std::vector<SpvId> arguments;
1527 for (size_t i = 0; i < c.fArguments.size(); i++) {
1528 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1529 }
1530 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001531 if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) {
1532 this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.columns(), out);
1533 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001534 this->writeWord(result, out);
ethannicholasd598f792016-07-25 10:08:54 -07001535 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001536 this->writeWord(arguments[0], out);
1537 }
1538 } else {
1539 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) c.fArguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001540 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001541 this->writeWord(result, out);
1542 for (SpvId id : arguments) {
1543 this->writeWord(id, out);
1544 }
1545 }
1546 return result;
1547}
1548
ethannicholasf789b382016-08-03 12:43:36 -07001549SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, std::ostream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001550 if (c.fType == *fContext.fFloat_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001551 return this->writeFloatConstructor(c, out);
ethannicholasd598f792016-07-25 10:08:54 -07001552 } else if (c.fType == *fContext.fInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001553 return this->writeIntConstructor(c, out);
1554 }
ethannicholasd598f792016-07-25 10:08:54 -07001555 switch (c.fType.kind()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001556 case Type::kVector_Kind:
1557 return this->writeVectorConstructor(c, out);
1558 case Type::kMatrix_Kind:
1559 return this->writeMatrixConstructor(c, out);
1560 default:
1561 ABORT("unsupported constructor: %s", c.description().c_str());
1562 }
1563}
1564
1565SpvStorageClass_ get_storage_class(const Modifiers& modifiers) {
1566 if (modifiers.fFlags & Modifiers::kIn_Flag) {
ethannicholasfa5f65a2016-11-15 12:53:05 -08001567 ASSERT(!modifiers.fLayout.fPushConstant);
ethannicholasb3058bd2016-07-01 08:22:01 -07001568 return SpvStorageClassInput;
1569 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
ethannicholasfa5f65a2016-11-15 12:53:05 -08001570 ASSERT(!modifiers.fLayout.fPushConstant);
ethannicholasb3058bd2016-07-01 08:22:01 -07001571 return SpvStorageClassOutput;
1572 } else if (modifiers.fFlags & Modifiers::kUniform_Flag) {
ethannicholasfa5f65a2016-11-15 12:53:05 -08001573 if (modifiers.fLayout.fPushConstant) {
1574 return SpvStorageClassPushConstant;
1575 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001576 return SpvStorageClassUniform;
1577 } else {
1578 return SpvStorageClassFunction;
1579 }
1580}
1581
ethannicholasf789b382016-08-03 12:43:36 -07001582SpvStorageClass_ get_storage_class(const Expression& expr) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001583 switch (expr.fKind) {
1584 case Expression::kVariableReference_Kind:
ethannicholasd598f792016-07-25 10:08:54 -07001585 return get_storage_class(((VariableReference&) expr).fVariable.fModifiers);
ethannicholasb3058bd2016-07-01 08:22:01 -07001586 case Expression::kFieldAccess_Kind:
1587 return get_storage_class(*((FieldAccess&) expr).fBase);
1588 case Expression::kIndex_Kind:
1589 return get_storage_class(*((IndexExpression&) expr).fBase);
1590 default:
1591 return SpvStorageClassFunction;
1592 }
1593}
1594
ethannicholasf789b382016-08-03 12:43:36 -07001595std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001596 std::vector<SpvId> chain;
1597 switch (expr.fKind) {
1598 case Expression::kIndex_Kind: {
1599 IndexExpression& indexExpr = (IndexExpression&) expr;
1600 chain = this->getAccessChain(*indexExpr.fBase, out);
1601 chain.push_back(this->writeExpression(*indexExpr.fIndex, out));
1602 break;
1603 }
1604 case Expression::kFieldAccess_Kind: {
1605 FieldAccess& fieldExpr = (FieldAccess&) expr;
1606 chain = this->getAccessChain(*fieldExpr.fBase, out);
ethannicholasd598f792016-07-25 10:08:54 -07001607 IntLiteral index(fContext, Position(), fieldExpr.fFieldIndex);
ethannicholasb3058bd2016-07-01 08:22:01 -07001608 chain.push_back(this->writeIntLiteral(index));
1609 break;
1610 }
1611 default:
1612 chain.push_back(this->getLValue(expr, out)->getPointer());
1613 }
1614 return chain;
1615}
1616
1617class PointerLValue : public SPIRVCodeGenerator::LValue {
1618public:
1619 PointerLValue(SPIRVCodeGenerator& gen, SpvId pointer, SpvId type)
1620 : fGen(gen)
1621 , fPointer(pointer)
1622 , fType(type) {}
1623
1624 virtual SpvId getPointer() override {
1625 return fPointer;
1626 }
1627
1628 virtual SpvId load(std::ostream& out) override {
1629 SpvId result = fGen.nextId();
1630 fGen.writeInstruction(SpvOpLoad, fType, result, fPointer, out);
1631 return result;
1632 }
1633
1634 virtual void store(SpvId value, std::ostream& out) override {
1635 fGen.writeInstruction(SpvOpStore, fPointer, value, out);
1636 }
1637
1638private:
1639 SPIRVCodeGenerator& fGen;
1640 const SpvId fPointer;
1641 const SpvId fType;
1642};
1643
1644class SwizzleLValue : public SPIRVCodeGenerator::LValue {
1645public:
1646 SwizzleLValue(SPIRVCodeGenerator& gen, SpvId vecPointer, const std::vector<int>& components,
1647 const Type& baseType, const Type& swizzleType)
1648 : fGen(gen)
1649 , fVecPointer(vecPointer)
1650 , fComponents(components)
1651 , fBaseType(baseType)
1652 , fSwizzleType(swizzleType) {}
1653
1654 virtual SpvId getPointer() override {
1655 return 0;
1656 }
1657
1658 virtual SpvId load(std::ostream& out) override {
1659 SpvId base = fGen.nextId();
1660 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1661 SpvId result = fGen.nextId();
1662 fGen.writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) fComponents.size(), out);
1663 fGen.writeWord(fGen.getType(fSwizzleType), out);
1664 fGen.writeWord(result, out);
1665 fGen.writeWord(base, out);
1666 fGen.writeWord(base, out);
1667 for (int component : fComponents) {
1668 fGen.writeWord(component, out);
1669 }
1670 return result;
1671 }
1672
1673 virtual void store(SpvId value, std::ostream& out) override {
1674 // use OpVectorShuffle to mix and match the vector components. We effectively create
1675 // a virtual vector out of the concatenation of the left and right vectors, and then
1676 // select components from this virtual vector to make the result vector. For
1677 // instance, given:
1678 // vec3 L = ...;
1679 // vec3 R = ...;
1680 // L.xz = R.xy;
1681 // we end up with the virtual vector (L.x, L.y, L.z, R.x, R.y, R.z). Then we want
1682 // our result vector to look like (R.x, L.y, R.y), so we need to select indices
1683 // (3, 1, 4).
1684 SpvId base = fGen.nextId();
1685 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1686 SpvId shuffle = fGen.nextId();
1687 fGen.writeOpCode(SpvOpVectorShuffle, 5 + fBaseType.columns(), out);
1688 fGen.writeWord(fGen.getType(fBaseType), out);
1689 fGen.writeWord(shuffle, out);
1690 fGen.writeWord(base, out);
1691 fGen.writeWord(value, out);
1692 for (int i = 0; i < fBaseType.columns(); i++) {
1693 // current offset into the virtual vector, defaults to pulling the unmodified
1694 // value from the left side
1695 int offset = i;
1696 // check to see if we are writing this component
1697 for (size_t j = 0; j < fComponents.size(); j++) {
1698 if (fComponents[j] == i) {
1699 // we're writing to this component, so adjust the offset to pull from
1700 // the correct component of the right side instead of preserving the
1701 // value from the left
1702 offset = (int) (j + fBaseType.columns());
1703 break;
1704 }
1705 }
1706 fGen.writeWord(offset, out);
1707 }
1708 fGen.writeInstruction(SpvOpStore, fVecPointer, shuffle, out);
1709 }
1710
1711private:
1712 SPIRVCodeGenerator& fGen;
1713 const SpvId fVecPointer;
1714 const std::vector<int>& fComponents;
1715 const Type& fBaseType;
1716 const Type& fSwizzleType;
1717};
1718
ethannicholasf789b382016-08-03 12:43:36 -07001719std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const Expression& expr,
ethannicholasb3058bd2016-07-01 08:22:01 -07001720 std::ostream& out) {
1721 switch (expr.fKind) {
1722 case Expression::kVariableReference_Kind: {
ethannicholasd598f792016-07-25 10:08:54 -07001723 const Variable& var = ((VariableReference&) expr).fVariable;
1724 auto entry = fVariableMap.find(&var);
ethannicholasb3058bd2016-07-01 08:22:01 -07001725 ASSERT(entry != fVariableMap.end());
1726 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1727 *this,
1728 entry->second,
ethannicholasd598f792016-07-25 10:08:54 -07001729 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001730 }
1731 case Expression::kIndex_Kind: // fall through
1732 case Expression::kFieldAccess_Kind: {
1733 std::vector<SpvId> chain = this->getAccessChain(expr, out);
1734 SpvId member = this->nextId();
1735 this->writeOpCode(SpvOpAccessChain, (SpvId) (3 + chain.size()), out);
1736 this->writeWord(this->getPointerType(expr.fType, get_storage_class(expr)), out);
1737 this->writeWord(member, out);
1738 for (SpvId idx : chain) {
1739 this->writeWord(idx, out);
1740 }
1741 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1742 *this,
1743 member,
ethannicholasd598f792016-07-25 10:08:54 -07001744 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001745 }
1746
1747 case Expression::kSwizzle_Kind: {
1748 Swizzle& swizzle = (Swizzle&) expr;
1749 size_t count = swizzle.fComponents.size();
1750 SpvId base = this->getLValue(*swizzle.fBase, out)->getPointer();
1751 ASSERT(base);
1752 if (count == 1) {
ethannicholasd598f792016-07-25 10:08:54 -07001753 IntLiteral index(fContext, Position(), swizzle.fComponents[0]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001754 SpvId member = this->nextId();
1755 this->writeInstruction(SpvOpAccessChain,
1756 this->getPointerType(swizzle.fType,
1757 get_storage_class(*swizzle.fBase)),
1758 member,
1759 base,
1760 this->writeIntLiteral(index),
1761 out);
1762 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1763 *this,
1764 member,
ethannicholasd598f792016-07-25 10:08:54 -07001765 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001766 } else {
1767 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new SwizzleLValue(
1768 *this,
1769 base,
1770 swizzle.fComponents,
ethannicholasd598f792016-07-25 10:08:54 -07001771 swizzle.fBase->fType,
1772 expr.fType));
ethannicholasb3058bd2016-07-01 08:22:01 -07001773 }
1774 }
1775
1776 default:
1777 // expr isn't actually an lvalue, create a dummy variable for it. This case happens due
1778 // to the need to store values in temporary variables during function calls (see
1779 // comments in getFunctionType); erroneous uses of rvalues as lvalues should have been
1780 // caught by IRGenerator
1781 SpvId result = this->nextId();
1782 SpvId type = this->getPointerType(expr.fType, SpvStorageClassFunction);
ethannicholasd598f792016-07-25 10:08:54 -07001783 this->writeInstruction(SpvOpVariable, type, result, SpvStorageClassFunction,
1784 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001785 this->writeInstruction(SpvOpStore, result, this->writeExpression(expr, out), out);
1786 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1787 *this,
1788 result,
ethannicholasd598f792016-07-25 10:08:54 -07001789 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001790 }
1791}
1792
ethannicholasf789b382016-08-03 12:43:36 -07001793SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, std::ostream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001794 auto entry = fVariableMap.find(&ref.fVariable);
ethannicholasb3058bd2016-07-01 08:22:01 -07001795 ASSERT(entry != fVariableMap.end());
1796 SpvId var = entry->second;
1797 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001798 this->writeInstruction(SpvOpLoad, this->getType(ref.fVariable.fType), result, var, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001799 return result;
1800}
1801
ethannicholasf789b382016-08-03 12:43:36 -07001802SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001803 return getLValue(expr, out)->load(out);
1804}
1805
ethannicholasf789b382016-08-03 12:43:36 -07001806SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001807 return getLValue(f, out)->load(out);
1808}
1809
ethannicholasf789b382016-08-03 12:43:36 -07001810SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001811 SpvId base = this->writeExpression(*swizzle.fBase, out);
1812 SpvId result = this->nextId();
1813 size_t count = swizzle.fComponents.size();
1814 if (count == 1) {
ethannicholasd598f792016-07-25 10:08:54 -07001815 this->writeInstruction(SpvOpCompositeExtract, this->getType(swizzle.fType), result, base,
ethannicholasb3058bd2016-07-01 08:22:01 -07001816 swizzle.fComponents[0], out);
1817 } else {
1818 this->writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) count, out);
ethannicholasd598f792016-07-25 10:08:54 -07001819 this->writeWord(this->getType(swizzle.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001820 this->writeWord(result, out);
1821 this->writeWord(base, out);
1822 this->writeWord(base, out);
1823 for (int component : swizzle.fComponents) {
1824 this->writeWord(component, out);
1825 }
1826 }
1827 return result;
1828}
1829
1830SpvId SPIRVCodeGenerator::writeBinaryOperation(const Type& resultType,
1831 const Type& operandType, SpvId lhs,
1832 SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt,
1833 SpvOp_ ifUInt, SpvOp_ ifBool, std::ostream& out) {
1834 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001835 if (is_float(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001836 this->writeInstruction(ifFloat, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001837 } else if (is_signed(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001838 this->writeInstruction(ifInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001839 } else if (is_unsigned(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001840 this->writeInstruction(ifUInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001841 } else if (operandType == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001842 this->writeInstruction(ifBool, this->getType(resultType), result, lhs, rhs, out);
1843 } else {
1844 ABORT("invalid operandType: %s", operandType.description().c_str());
1845 }
1846 return result;
1847}
1848
1849bool is_assignment(Token::Kind op) {
1850 switch (op) {
1851 case Token::EQ: // fall through
1852 case Token::PLUSEQ: // fall through
1853 case Token::MINUSEQ: // fall through
1854 case Token::STAREQ: // fall through
1855 case Token::SLASHEQ: // fall through
1856 case Token::PERCENTEQ: // fall through
1857 case Token::SHLEQ: // fall through
1858 case Token::SHREQ: // fall through
1859 case Token::BITWISEOREQ: // fall through
1860 case Token::BITWISEXOREQ: // fall through
1861 case Token::BITWISEANDEQ: // fall through
1862 case Token::LOGICALOREQ: // fall through
1863 case Token::LOGICALXOREQ: // fall through
1864 case Token::LOGICALANDEQ:
1865 return true;
1866 default:
1867 return false;
1868 }
1869}
1870
ethannicholasf789b382016-08-03 12:43:36 -07001871SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001872 // handle cases where we don't necessarily evaluate both LHS and RHS
1873 switch (b.fOperator) {
1874 case Token::EQ: {
1875 SpvId rhs = this->writeExpression(*b.fRight, out);
1876 this->getLValue(*b.fLeft, out)->store(rhs, out);
1877 return rhs;
1878 }
1879 case Token::LOGICALAND:
1880 return this->writeLogicalAnd(b, out);
1881 case Token::LOGICALOR:
1882 return this->writeLogicalOr(b, out);
1883 default:
1884 break;
1885 }
1886
1887 // "normal" operators
ethannicholasd598f792016-07-25 10:08:54 -07001888 const Type& resultType = b.fType;
ethannicholasb3058bd2016-07-01 08:22:01 -07001889 std::unique_ptr<LValue> lvalue;
1890 SpvId lhs;
1891 if (is_assignment(b.fOperator)) {
1892 lvalue = this->getLValue(*b.fLeft, out);
1893 lhs = lvalue->load(out);
1894 } else {
1895 lvalue = nullptr;
1896 lhs = this->writeExpression(*b.fLeft, out);
1897 }
1898 SpvId rhs = this->writeExpression(*b.fRight, out);
1899 // component type we are operating on: float, int, uint
1900 const Type* operandType;
1901 // IR allows mismatched types in expressions (e.g. vec2 * float), but they need special handling
1902 // in SPIR-V
1903 if (b.fLeft->fType != b.fRight->fType) {
ethannicholasd598f792016-07-25 10:08:54 -07001904 if (b.fLeft->fType.kind() == Type::kVector_Kind &&
1905 b.fRight->fType.isNumber()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001906 // promote number to vector
1907 SpvId vec = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001908 this->writeOpCode(SpvOpCompositeConstruct, 3 + b.fType.columns(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001909 this->writeWord(this->getType(resultType), out);
1910 this->writeWord(vec, out);
1911 for (int i = 0; i < resultType.columns(); i++) {
1912 this->writeWord(rhs, out);
1913 }
1914 rhs = vec;
ethannicholasd598f792016-07-25 10:08:54 -07001915 operandType = &b.fRight->fType;
1916 } else if (b.fRight->fType.kind() == Type::kVector_Kind &&
1917 b.fLeft->fType.isNumber()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001918 // promote number to vector
1919 SpvId vec = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001920 this->writeOpCode(SpvOpCompositeConstruct, 3 + b.fType.columns(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001921 this->writeWord(this->getType(resultType), out);
1922 this->writeWord(vec, out);
1923 for (int i = 0; i < resultType.columns(); i++) {
1924 this->writeWord(lhs, out);
1925 }
1926 lhs = vec;
1927 ASSERT(!lvalue);
ethannicholasd598f792016-07-25 10:08:54 -07001928 operandType = &b.fLeft->fType;
1929 } else if (b.fLeft->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001930 SpvOp_ op;
ethannicholasd598f792016-07-25 10:08:54 -07001931 if (b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001932 op = SpvOpMatrixTimesMatrix;
ethannicholasd598f792016-07-25 10:08:54 -07001933 } else if (b.fRight->fType.kind() == Type::kVector_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001934 op = SpvOpMatrixTimesVector;
1935 } else {
ethannicholasd598f792016-07-25 10:08:54 -07001936 ASSERT(b.fRight->fType.kind() == Type::kScalar_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001937 op = SpvOpMatrixTimesScalar;
1938 }
1939 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001940 this->writeInstruction(op, this->getType(b.fType), result, lhs, rhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001941 if (b.fOperator == Token::STAREQ) {
1942 lvalue->store(result, out);
1943 } else {
1944 ASSERT(b.fOperator == Token::STAR);
1945 }
1946 return result;
ethannicholasd598f792016-07-25 10:08:54 -07001947 } else if (b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001948 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001949 if (b.fLeft->fType.kind() == Type::kVector_Kind) {
1950 this->writeInstruction(SpvOpVectorTimesMatrix, this->getType(b.fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07001951 lhs, rhs, out);
1952 } else {
ethannicholasd598f792016-07-25 10:08:54 -07001953 ASSERT(b.fLeft->fType.kind() == Type::kScalar_Kind);
1954 this->writeInstruction(SpvOpMatrixTimesScalar, this->getType(b.fType), result, rhs,
ethannicholasb3058bd2016-07-01 08:22:01 -07001955 lhs, out);
1956 }
1957 if (b.fOperator == Token::STAREQ) {
1958 lvalue->store(result, out);
1959 } else {
1960 ASSERT(b.fOperator == Token::STAR);
1961 }
1962 return result;
1963 } else {
1964 ABORT("unsupported binary expression: %s", b.description().c_str());
1965 }
1966 } else {
ethannicholasd598f792016-07-25 10:08:54 -07001967 operandType = &b.fLeft->fType;
1968 ASSERT(*operandType == b.fRight->fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001969 }
1970 switch (b.fOperator) {
1971 case Token::EQEQ:
ethannicholasd598f792016-07-25 10:08:54 -07001972 ASSERT(resultType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07001973 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdEqual,
1974 SpvOpIEqual, SpvOpIEqual, SpvOpLogicalEqual, out);
1975 case Token::NEQ:
ethannicholasd598f792016-07-25 10:08:54 -07001976 ASSERT(resultType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07001977 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdNotEqual,
1978 SpvOpINotEqual, SpvOpINotEqual, SpvOpLogicalNotEqual,
1979 out);
1980 case Token::GT:
ethannicholasd598f792016-07-25 10:08:54 -07001981 ASSERT(resultType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07001982 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
1983 SpvOpFOrdGreaterThan, SpvOpSGreaterThan,
1984 SpvOpUGreaterThan, SpvOpUndef, out);
1985 case Token::LT:
ethannicholasd598f792016-07-25 10:08:54 -07001986 ASSERT(resultType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07001987 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdLessThan,
1988 SpvOpSLessThan, SpvOpULessThan, SpvOpUndef, out);
1989 case Token::GTEQ:
ethannicholasd598f792016-07-25 10:08:54 -07001990 ASSERT(resultType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07001991 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
1992 SpvOpFOrdGreaterThanEqual, SpvOpSGreaterThanEqual,
1993 SpvOpUGreaterThanEqual, SpvOpUndef, out);
1994 case Token::LTEQ:
ethannicholasd598f792016-07-25 10:08:54 -07001995 ASSERT(resultType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07001996 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
1997 SpvOpFOrdLessThanEqual, SpvOpSLessThanEqual,
1998 SpvOpULessThanEqual, SpvOpUndef, out);
1999 case Token::PLUS:
2000 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
2001 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2002 case Token::MINUS:
2003 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
2004 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2005 case Token::STAR:
ethannicholasd598f792016-07-25 10:08:54 -07002006 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
2007 b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002008 // matrix multiply
2009 SpvId result = this->nextId();
2010 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2011 lhs, rhs, out);
2012 return result;
2013 }
2014 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
2015 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
2016 case Token::SLASH:
2017 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
2018 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
2019 case Token::PLUSEQ: {
2020 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
2021 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2022 ASSERT(lvalue);
2023 lvalue->store(result, out);
2024 return result;
2025 }
2026 case Token::MINUSEQ: {
2027 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
2028 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2029 ASSERT(lvalue);
2030 lvalue->store(result, out);
2031 return result;
2032 }
2033 case Token::STAREQ: {
ethannicholasd598f792016-07-25 10:08:54 -07002034 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
2035 b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002036 // matrix multiply
2037 SpvId result = this->nextId();
2038 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2039 lhs, rhs, out);
2040 ASSERT(lvalue);
2041 lvalue->store(result, out);
2042 return result;
2043 }
2044 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
2045 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
2046 ASSERT(lvalue);
2047 lvalue->store(result, out);
2048 return result;
2049 }
2050 case Token::SLASHEQ: {
2051 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
2052 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
2053 ASSERT(lvalue);
2054 lvalue->store(result, out);
2055 return result;
2056 }
2057 default:
2058 // FIXME: missing support for some operators (bitwise, &&=, ||=, shift...)
2059 ABORT("unsupported binary expression: %s", b.description().c_str());
2060 }
2061}
2062
ethannicholasf789b382016-08-03 12:43:36 -07002063SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002064 ASSERT(a.fOperator == Token::LOGICALAND);
ethannicholasd598f792016-07-25 10:08:54 -07002065 BoolLiteral falseLiteral(fContext, Position(), false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002066 SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
2067 SpvId lhs = this->writeExpression(*a.fLeft, out);
2068 SpvId rhsLabel = this->nextId();
2069 SpvId end = this->nextId();
2070 SpvId lhsBlock = fCurrentBlock;
2071 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2072 this->writeInstruction(SpvOpBranchConditional, lhs, rhsLabel, end, out);
2073 this->writeLabel(rhsLabel, out);
2074 SpvId rhs = this->writeExpression(*a.fRight, out);
2075 SpvId rhsBlock = fCurrentBlock;
2076 this->writeInstruction(SpvOpBranch, end, out);
2077 this->writeLabel(end, out);
2078 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002079 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, falseConstant,
2080 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002081 return result;
2082}
2083
ethannicholasf789b382016-08-03 12:43:36 -07002084SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002085 ASSERT(o.fOperator == Token::LOGICALOR);
ethannicholasd598f792016-07-25 10:08:54 -07002086 BoolLiteral trueLiteral(fContext, Position(), true);
ethannicholasb3058bd2016-07-01 08:22:01 -07002087 SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
2088 SpvId lhs = this->writeExpression(*o.fLeft, out);
2089 SpvId rhsLabel = this->nextId();
2090 SpvId end = this->nextId();
2091 SpvId lhsBlock = fCurrentBlock;
2092 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2093 this->writeInstruction(SpvOpBranchConditional, lhs, end, rhsLabel, out);
2094 this->writeLabel(rhsLabel, out);
2095 SpvId rhs = this->writeExpression(*o.fRight, out);
2096 SpvId rhsBlock = fCurrentBlock;
2097 this->writeInstruction(SpvOpBranch, end, out);
2098 this->writeLabel(end, out);
2099 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002100 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, trueConstant,
2101 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002102 return result;
2103}
2104
ethannicholasf789b382016-08-03 12:43:36 -07002105SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002106 SpvId test = this->writeExpression(*t.fTest, out);
2107 if (t.fIfTrue->isConstant() && t.fIfFalse->isConstant()) {
2108 // both true and false are constants, can just use OpSelect
2109 SpvId result = this->nextId();
2110 SpvId trueId = this->writeExpression(*t.fIfTrue, out);
2111 SpvId falseId = this->writeExpression(*t.fIfFalse, out);
ethannicholasd598f792016-07-25 10:08:54 -07002112 this->writeInstruction(SpvOpSelect, this->getType(t.fType), result, test, trueId, falseId,
ethannicholasb3058bd2016-07-01 08:22:01 -07002113 out);
2114 return result;
2115 }
2116 // was originally using OpPhi to choose the result, but for some reason that is crashing on
2117 // Adreno. Switched to storing the result in a temp variable as glslang does.
2118 SpvId var = this->nextId();
2119 this->writeInstruction(SpvOpVariable, this->getPointerType(t.fType, SpvStorageClassFunction),
ethannicholasd598f792016-07-25 10:08:54 -07002120 var, SpvStorageClassFunction, fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002121 SpvId trueLabel = this->nextId();
2122 SpvId falseLabel = this->nextId();
2123 SpvId end = this->nextId();
2124 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2125 this->writeInstruction(SpvOpBranchConditional, test, trueLabel, falseLabel, out);
2126 this->writeLabel(trueLabel, out);
2127 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfTrue, out), out);
2128 this->writeInstruction(SpvOpBranch, end, out);
2129 this->writeLabel(falseLabel, out);
2130 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfFalse, out), out);
2131 this->writeInstruction(SpvOpBranch, end, out);
2132 this->writeLabel(end, out);
2133 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002134 this->writeInstruction(SpvOpLoad, this->getType(t.fType), result, var, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002135 return result;
2136}
2137
ethannicholasd598f792016-07-25 10:08:54 -07002138std::unique_ptr<Expression> create_literal_1(const Context& context, const Type& type) {
2139 if (type == *context.fInt_Type) {
2140 return std::unique_ptr<Expression>(new IntLiteral(context, Position(), 1));
ethannicholasb3058bd2016-07-01 08:22:01 -07002141 }
ethannicholasd598f792016-07-25 10:08:54 -07002142 else if (type == *context.fFloat_Type) {
2143 return std::unique_ptr<Expression>(new FloatLiteral(context, Position(), 1.0));
ethannicholasb3058bd2016-07-01 08:22:01 -07002144 } else {
2145 ABORT("math is unsupported on type '%s'")
2146 }
2147}
2148
ethannicholasf789b382016-08-03 12:43:36 -07002149SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002150 if (p.fOperator == Token::MINUS) {
2151 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002152 SpvId typeId = this->getType(p.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07002153 SpvId expr = this->writeExpression(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002154 if (is_float(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002155 this->writeInstruction(SpvOpFNegate, typeId, result, expr, out);
ethannicholasd598f792016-07-25 10:08:54 -07002156 } else if (is_signed(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002157 this->writeInstruction(SpvOpSNegate, typeId, result, expr, out);
2158 } else {
2159 ABORT("unsupported prefix expression %s", p.description().c_str());
2160 };
2161 return result;
2162 }
2163 switch (p.fOperator) {
2164 case Token::PLUS:
2165 return this->writeExpression(*p.fOperand, out);
2166 case Token::PLUSPLUS: {
2167 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002168 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
2169 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
ethannicholasb3058bd2016-07-01 08:22:01 -07002170 SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef,
2171 out);
2172 lv->store(result, out);
2173 return result;
2174 }
2175 case Token::MINUSMINUS: {
2176 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002177 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
2178 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
ethannicholasb3058bd2016-07-01 08:22:01 -07002179 SpvOpFSub, SpvOpISub, SpvOpISub, SpvOpUndef,
2180 out);
2181 lv->store(result, out);
2182 return result;
2183 }
ethannicholas5961bc92016-10-12 06:39:56 -07002184 case Token::LOGICALNOT: {
ethannicholasd598f792016-07-25 10:08:54 -07002185 ASSERT(p.fOperand->fType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002186 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002187 this->writeInstruction(SpvOpLogicalNot, this->getType(p.fOperand->fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002188 this->writeExpression(*p.fOperand, out), out);
2189 return result;
2190 }
ethannicholas5961bc92016-10-12 06:39:56 -07002191 case Token::BITWISENOT: {
2192 SpvId result = this->nextId();
2193 this->writeInstruction(SpvOpNot, this->getType(p.fOperand->fType), result,
2194 this->writeExpression(*p.fOperand, out), out);
2195 return result;
2196 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002197 default:
2198 ABORT("unsupported prefix expression: %s", p.description().c_str());
2199 }
2200}
2201
ethannicholasf789b382016-08-03 12:43:36 -07002202SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002203 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
2204 SpvId result = lv->load(out);
ethannicholasd598f792016-07-25 10:08:54 -07002205 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002206 switch (p.fOperator) {
2207 case Token::PLUSPLUS: {
ethannicholasd598f792016-07-25 10:08:54 -07002208 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002209 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2210 lv->store(temp, out);
2211 return result;
2212 }
2213 case Token::MINUSMINUS: {
ethannicholasd598f792016-07-25 10:08:54 -07002214 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002215 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2216 lv->store(temp, out);
2217 return result;
2218 }
2219 default:
2220 ABORT("unsupported postfix expression %s", p.description().c_str());
2221 }
2222}
2223
ethannicholasf789b382016-08-03 12:43:36 -07002224SpvId SPIRVCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002225 if (b.fValue) {
2226 if (fBoolTrue == 0) {
2227 fBoolTrue = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002228 this->writeInstruction(SpvOpConstantTrue, this->getType(b.fType), fBoolTrue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002229 fConstantBuffer);
2230 }
2231 return fBoolTrue;
2232 } else {
2233 if (fBoolFalse == 0) {
2234 fBoolFalse = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002235 this->writeInstruction(SpvOpConstantFalse, this->getType(b.fType), fBoolFalse,
ethannicholasb3058bd2016-07-01 08:22:01 -07002236 fConstantBuffer);
2237 }
2238 return fBoolFalse;
2239 }
2240}
2241
ethannicholasf789b382016-08-03 12:43:36 -07002242SpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) {
ethannicholasd598f792016-07-25 10:08:54 -07002243 if (i.fType == *fContext.fInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002244 auto entry = fIntConstants.find(i.fValue);
2245 if (entry == fIntConstants.end()) {
2246 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002247 this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002248 fConstantBuffer);
2249 fIntConstants[i.fValue] = result;
2250 return result;
2251 }
2252 return entry->second;
2253 } else {
ethannicholasd598f792016-07-25 10:08:54 -07002254 ASSERT(i.fType == *fContext.fUInt_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002255 auto entry = fUIntConstants.find(i.fValue);
2256 if (entry == fUIntConstants.end()) {
2257 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002258 this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002259 fConstantBuffer);
2260 fUIntConstants[i.fValue] = result;
2261 return result;
2262 }
2263 return entry->second;
2264 }
2265}
2266
ethannicholasf789b382016-08-03 12:43:36 -07002267SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
ethannicholasd598f792016-07-25 10:08:54 -07002268 if (f.fType == *fContext.fFloat_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002269 float value = (float) f.fValue;
2270 auto entry = fFloatConstants.find(value);
2271 if (entry == fFloatConstants.end()) {
2272 SpvId result = this->nextId();
2273 uint32_t bits;
2274 ASSERT(sizeof(bits) == sizeof(value));
2275 memcpy(&bits, &value, sizeof(bits));
ethannicholasd598f792016-07-25 10:08:54 -07002276 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result, bits,
ethannicholasb3058bd2016-07-01 08:22:01 -07002277 fConstantBuffer);
2278 fFloatConstants[value] = result;
2279 return result;
2280 }
2281 return entry->second;
2282 } else {
ethannicholasd598f792016-07-25 10:08:54 -07002283 ASSERT(f.fType == *fContext.fDouble_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002284 auto entry = fDoubleConstants.find(f.fValue);
2285 if (entry == fDoubleConstants.end()) {
2286 SpvId result = this->nextId();
2287 uint64_t bits;
2288 ASSERT(sizeof(bits) == sizeof(f.fValue));
2289 memcpy(&bits, &f.fValue, sizeof(bits));
ethannicholasd598f792016-07-25 10:08:54 -07002290 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002291 bits & 0xffffffff, bits >> 32, fConstantBuffer);
2292 fDoubleConstants[f.fValue] = result;
2293 return result;
2294 }
2295 return entry->second;
2296 }
2297}
2298
ethannicholasd598f792016-07-25 10:08:54 -07002299SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, std::ostream& out) {
2300 SpvId result = fFunctionMap[&f];
2301 this->writeInstruction(SpvOpFunction, this->getType(f.fReturnType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002302 SpvFunctionControlMaskNone, this->getFunctionType(f), out);
ethannicholasd598f792016-07-25 10:08:54 -07002303 this->writeInstruction(SpvOpName, result, f.fName.c_str(), fNameBuffer);
2304 for (size_t i = 0; i < f.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002305 SpvId id = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002306 fVariableMap[f.fParameters[i]] = id;
ethannicholasb3058bd2016-07-01 08:22:01 -07002307 SpvId type;
ethannicholasd598f792016-07-25 10:08:54 -07002308 type = this->getPointerType(f.fParameters[i]->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002309 this->writeInstruction(SpvOpFunctionParameter, type, id, out);
2310 }
2311 return result;
2312}
2313
ethannicholasd598f792016-07-25 10:08:54 -07002314SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002315 SpvId result = this->writeFunctionStart(f.fDeclaration, out);
2316 this->writeLabel(this->nextId(), out);
ethannicholasd598f792016-07-25 10:08:54 -07002317 if (f.fDeclaration.fName == "main") {
ethannicholasb3058bd2016-07-01 08:22:01 -07002318 out << fGlobalInitializersBuffer.str();
2319 }
2320 std::stringstream bodyBuffer;
2321 this->writeBlock(*f.fBody, bodyBuffer);
2322 out << fVariableBuffer.str();
2323 fVariableBuffer.str("");
2324 out << bodyBuffer.str();
2325 if (fCurrentBlock) {
2326 this->writeInstruction(SpvOpReturn, out);
2327 }
2328 this->writeInstruction(SpvOpFunctionEnd, out);
2329 return result;
2330}
2331
2332void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target) {
2333 if (layout.fLocation >= 0) {
2334 this->writeInstruction(SpvOpDecorate, target, SpvDecorationLocation, layout.fLocation,
2335 fDecorationBuffer);
2336 }
2337 if (layout.fBinding >= 0) {
2338 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBinding, layout.fBinding,
2339 fDecorationBuffer);
2340 }
2341 if (layout.fIndex >= 0) {
2342 this->writeInstruction(SpvOpDecorate, target, SpvDecorationIndex, layout.fIndex,
2343 fDecorationBuffer);
2344 }
2345 if (layout.fSet >= 0) {
2346 this->writeInstruction(SpvOpDecorate, target, SpvDecorationDescriptorSet, layout.fSet,
2347 fDecorationBuffer);
2348 }
ethannicholas5961bc92016-10-12 06:39:56 -07002349 if (layout.fBuiltin >= 0 && layout.fBuiltin != SK_FRAGCOLOR_BUILTIN) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002350 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBuiltIn, layout.fBuiltin,
2351 fDecorationBuffer);
2352 }
2353}
2354
2355void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int member) {
2356 if (layout.fLocation >= 0) {
2357 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationLocation,
2358 layout.fLocation, fDecorationBuffer);
2359 }
2360 if (layout.fBinding >= 0) {
2361 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBinding,
2362 layout.fBinding, fDecorationBuffer);
2363 }
2364 if (layout.fIndex >= 0) {
2365 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationIndex,
2366 layout.fIndex, fDecorationBuffer);
2367 }
2368 if (layout.fSet >= 0) {
2369 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationDescriptorSet,
2370 layout.fSet, fDecorationBuffer);
2371 }
2372 if (layout.fBuiltin >= 0) {
2373 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBuiltIn,
2374 layout.fBuiltin, fDecorationBuffer);
2375 }
2376}
2377
ethannicholasf789b382016-08-03 12:43:36 -07002378SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
ethannicholasfa5f65a2016-11-15 12:53:05 -08002379 MemoryLayout layout = intf.fVariable.fModifiers.fLayout.fPushConstant ?
2380 MemoryLayout(MemoryLayout::k430_Standard) :
2381 fDefaultLayout;
2382 SpvId type = this->getType(intf.fVariable.fType, layout);
ethannicholasb3058bd2016-07-01 08:22:01 -07002383 SpvId result = this->nextId();
2384 this->writeInstruction(SpvOpDecorate, type, SpvDecorationBlock, fDecorationBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07002385 SpvStorageClass_ storageClass = get_storage_class(intf.fVariable.fModifiers);
ethannicholasb3058bd2016-07-01 08:22:01 -07002386 SpvId ptrType = this->nextId();
2387 this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, type, fConstantBuffer);
2388 this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07002389 this->writeLayout(intf.fVariable.fModifiers.fLayout, result);
2390 fVariableMap[&intf.fVariable] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002391 return result;
2392}
2393
ethannicholas5961bc92016-10-12 06:39:56 -07002394#define BUILTIN_IGNORE 9999
2395void SPIRVCodeGenerator::writeGlobalVars(Program::Kind kind, const VarDeclarations& decl,
2396 std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002397 for (size_t i = 0; i < decl.fVars.size(); i++) {
ethannicholas14fe8cc2016-09-07 13:37:16 -07002398 const VarDeclaration& varDecl = decl.fVars[i];
2399 const Variable* var = varDecl.fVar;
ethannicholas5961bc92016-10-12 06:39:56 -07002400 if (var->fModifiers.fLayout.fBuiltin == BUILTIN_IGNORE) {
2401 continue;
2402 }
2403 if (var->fModifiers.fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN &&
2404 kind != Program::kFragment_Kind) {
2405 continue;
2406 }
ethannicholas14fe8cc2016-09-07 13:37:16 -07002407 if (!var->fIsReadFrom && !var->fIsWrittenTo &&
2408 !(var->fModifiers.fFlags & (Modifiers::kIn_Flag |
2409 Modifiers::kOut_Flag |
2410 Modifiers::kUniform_Flag))) {
ethannicholasd598f792016-07-25 10:08:54 -07002411 // variable is dead and not an input / output var (the Vulkan debug layers complain if
2412 // we elide an interface var, even if it's dead)
ethannicholasb3058bd2016-07-01 08:22:01 -07002413 continue;
2414 }
2415 SpvStorageClass_ storageClass;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002416 if (var->fModifiers.fFlags & Modifiers::kIn_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002417 storageClass = SpvStorageClassInput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002418 } else if (var->fModifiers.fFlags & Modifiers::kOut_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002419 storageClass = SpvStorageClassOutput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002420 } else if (var->fModifiers.fFlags & Modifiers::kUniform_Flag) {
2421 if (var->fType.kind() == Type::kSampler_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002422 storageClass = SpvStorageClassUniformConstant;
2423 } else {
2424 storageClass = SpvStorageClassUniform;
2425 }
2426 } else {
2427 storageClass = SpvStorageClassPrivate;
2428 }
2429 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002430 fVariableMap[var] = id;
2431 SpvId type = this->getPointerType(var->fType, storageClass);
ethannicholasb3058bd2016-07-01 08:22:01 -07002432 this->writeInstruction(SpvOpVariable, type, id, storageClass, fConstantBuffer);
ethannicholas14fe8cc2016-09-07 13:37:16 -07002433 this->writeInstruction(SpvOpName, id, var->fName.c_str(), fNameBuffer);
2434 if (var->fType.kind() == Type::kMatrix_Kind) {
ethannicholasfa5f65a2016-11-15 12:53:05 -08002435 this->writeInstruction(SpvOpMemberDecorate, id, (SpvId) i, SpvDecorationColMajor,
ethannicholasb3058bd2016-07-01 08:22:01 -07002436 fDecorationBuffer);
ethannicholasfa5f65a2016-11-15 12:53:05 -08002437 this->writeInstruction(SpvOpMemberDecorate, id, (SpvId) i, SpvDecorationMatrixStride,
2438 (SpvId) fDefaultLayout.stride(var->fType),
2439 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002440 }
ethannicholas14fe8cc2016-09-07 13:37:16 -07002441 if (varDecl.fValue) {
ethannicholasf789b382016-08-03 12:43:36 -07002442 ASSERT(!fCurrentBlock);
2443 fCurrentBlock = -1;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002444 SpvId value = this->writeExpression(*varDecl.fValue, fGlobalInitializersBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002445 this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
ethannicholasf789b382016-08-03 12:43:36 -07002446 fCurrentBlock = 0;
ethannicholasb3058bd2016-07-01 08:22:01 -07002447 }
ethannicholas14fe8cc2016-09-07 13:37:16 -07002448 this->writeLayout(var->fModifiers.fLayout, id);
ethannicholasb3058bd2016-07-01 08:22:01 -07002449 }
2450}
2451
ethannicholas14fe8cc2016-09-07 13:37:16 -07002452void SPIRVCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, std::ostream& out) {
2453 for (const auto& varDecl : decl.fVars) {
2454 const Variable* var = varDecl.fVar;
ethannicholasb3058bd2016-07-01 08:22:01 -07002455 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002456 fVariableMap[var] = id;
2457 SpvId type = this->getPointerType(var->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002458 this->writeInstruction(SpvOpVariable, type, id, SpvStorageClassFunction, fVariableBuffer);
ethannicholas14fe8cc2016-09-07 13:37:16 -07002459 this->writeInstruction(SpvOpName, id, var->fName.c_str(), fNameBuffer);
2460 if (varDecl.fValue) {
2461 SpvId value = this->writeExpression(*varDecl.fValue, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002462 this->writeInstruction(SpvOpStore, id, value, out);
2463 }
2464 }
2465}
2466
ethannicholasf789b382016-08-03 12:43:36 -07002467void SPIRVCodeGenerator::writeStatement(const Statement& s, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002468 switch (s.fKind) {
2469 case Statement::kBlock_Kind:
2470 this->writeBlock((Block&) s, out);
2471 break;
2472 case Statement::kExpression_Kind:
2473 this->writeExpression(*((ExpressionStatement&) s).fExpression, out);
2474 break;
2475 case Statement::kReturn_Kind:
2476 this->writeReturnStatement((ReturnStatement&) s, out);
2477 break;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002478 case Statement::kVarDeclarations_Kind:
2479 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002480 break;
2481 case Statement::kIf_Kind:
2482 this->writeIfStatement((IfStatement&) s, out);
2483 break;
2484 case Statement::kFor_Kind:
2485 this->writeForStatement((ForStatement&) s, out);
2486 break;
2487 case Statement::kBreak_Kind:
2488 this->writeInstruction(SpvOpBranch, fBreakTarget.top(), out);
2489 break;
2490 case Statement::kContinue_Kind:
2491 this->writeInstruction(SpvOpBranch, fContinueTarget.top(), out);
2492 break;
2493 case Statement::kDiscard_Kind:
2494 this->writeInstruction(SpvOpKill, out);
2495 break;
2496 default:
2497 ABORT("unsupported statement: %s", s.description().c_str());
2498 }
2499}
2500
ethannicholasf789b382016-08-03 12:43:36 -07002501void SPIRVCodeGenerator::writeBlock(const Block& b, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002502 for (size_t i = 0; i < b.fStatements.size(); i++) {
2503 this->writeStatement(*b.fStatements[i], out);
2504 }
2505}
2506
ethannicholasf789b382016-08-03 12:43:36 -07002507void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002508 SpvId test = this->writeExpression(*stmt.fTest, out);
2509 SpvId ifTrue = this->nextId();
2510 SpvId ifFalse = this->nextId();
2511 if (stmt.fIfFalse) {
2512 SpvId end = this->nextId();
2513 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2514 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2515 this->writeLabel(ifTrue, out);
2516 this->writeStatement(*stmt.fIfTrue, out);
2517 if (fCurrentBlock) {
2518 this->writeInstruction(SpvOpBranch, end, out);
2519 }
2520 this->writeLabel(ifFalse, out);
2521 this->writeStatement(*stmt.fIfFalse, out);
2522 if (fCurrentBlock) {
2523 this->writeInstruction(SpvOpBranch, end, out);
2524 }
2525 this->writeLabel(end, out);
2526 } else {
2527 this->writeInstruction(SpvOpSelectionMerge, ifFalse, SpvSelectionControlMaskNone, out);
2528 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2529 this->writeLabel(ifTrue, out);
2530 this->writeStatement(*stmt.fIfTrue, out);
2531 if (fCurrentBlock) {
2532 this->writeInstruction(SpvOpBranch, ifFalse, out);
2533 }
2534 this->writeLabel(ifFalse, out);
2535 }
2536}
2537
ethannicholasf789b382016-08-03 12:43:36 -07002538void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002539 if (f.fInitializer) {
2540 this->writeStatement(*f.fInitializer, out);
2541 }
2542 SpvId header = this->nextId();
2543 SpvId start = this->nextId();
2544 SpvId body = this->nextId();
2545 SpvId next = this->nextId();
2546 fContinueTarget.push(next);
2547 SpvId end = this->nextId();
2548 fBreakTarget.push(end);
2549 this->writeInstruction(SpvOpBranch, header, out);
2550 this->writeLabel(header, out);
2551 this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
ethannicholasf789b382016-08-03 12:43:36 -07002552 this->writeInstruction(SpvOpBranch, start, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002553 this->writeLabel(start, out);
ethannicholas22f939e2016-10-13 13:25:34 -07002554 if (f.fTest) {
2555 SpvId test = this->writeExpression(*f.fTest, out);
2556 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2557 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002558 this->writeLabel(body, out);
2559 this->writeStatement(*f.fStatement, out);
2560 if (fCurrentBlock) {
2561 this->writeInstruction(SpvOpBranch, next, out);
2562 }
2563 this->writeLabel(next, out);
2564 if (f.fNext) {
2565 this->writeExpression(*f.fNext, out);
2566 }
2567 this->writeInstruction(SpvOpBranch, header, out);
2568 this->writeLabel(end, out);
2569 fBreakTarget.pop();
2570 fContinueTarget.pop();
2571}
2572
ethannicholasf789b382016-08-03 12:43:36 -07002573void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002574 if (r.fExpression) {
2575 this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.fExpression, out),
2576 out);
2577 } else {
2578 this->writeInstruction(SpvOpReturn, out);
2579 }
2580}
2581
ethannicholasf789b382016-08-03 12:43:36 -07002582void SPIRVCodeGenerator::writeInstructions(const Program& program, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002583 fGLSLExtendedInstructions = this->nextId();
2584 std::stringstream body;
2585 std::vector<SpvId> interfaceVars;
2586 // assign IDs to functions
2587 for (size_t i = 0; i < program.fElements.size(); i++) {
2588 if (program.fElements[i]->fKind == ProgramElement::kFunction_Kind) {
2589 FunctionDefinition& f = (FunctionDefinition&) *program.fElements[i];
ethannicholasd598f792016-07-25 10:08:54 -07002590 fFunctionMap[&f.fDeclaration] = this->nextId();
ethannicholasb3058bd2016-07-01 08:22:01 -07002591 }
2592 }
2593 for (size_t i = 0; i < program.fElements.size(); i++) {
2594 if (program.fElements[i]->fKind == ProgramElement::kInterfaceBlock_Kind) {
2595 InterfaceBlock& intf = (InterfaceBlock&) *program.fElements[i];
2596 SpvId id = this->writeInterfaceBlock(intf);
ethannicholasd598f792016-07-25 10:08:54 -07002597 if ((intf.fVariable.fModifiers.fFlags & Modifiers::kIn_Flag) ||
2598 (intf.fVariable.fModifiers.fFlags & Modifiers::kOut_Flag)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002599 interfaceVars.push_back(id);
2600 }
2601 }
2602 }
2603 for (size_t i = 0; i < program.fElements.size(); i++) {
2604 if (program.fElements[i]->fKind == ProgramElement::kVar_Kind) {
ethannicholas5961bc92016-10-12 06:39:56 -07002605 this->writeGlobalVars(program.fKind, ((VarDeclarations&) *program.fElements[i]),
2606 body);
ethannicholasb3058bd2016-07-01 08:22:01 -07002607 }
2608 }
2609 for (size_t i = 0; i < program.fElements.size(); i++) {
2610 if (program.fElements[i]->fKind == ProgramElement::kFunction_Kind) {
2611 this->writeFunction(((FunctionDefinition&) *program.fElements[i]), body);
2612 }
2613 }
ethannicholasd598f792016-07-25 10:08:54 -07002614 const FunctionDeclaration* main = nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -07002615 for (auto entry : fFunctionMap) {
ethannicholasf789b382016-08-03 12:43:36 -07002616 if (entry.first->fName == "main") {
ethannicholasb3058bd2016-07-01 08:22:01 -07002617 main = entry.first;
2618 }
2619 }
2620 ASSERT(main);
2621 for (auto entry : fVariableMap) {
ethannicholasd598f792016-07-25 10:08:54 -07002622 const Variable* var = entry.first;
ethannicholasb3058bd2016-07-01 08:22:01 -07002623 if (var->fStorage == Variable::kGlobal_Storage &&
2624 ((var->fModifiers.fFlags & Modifiers::kIn_Flag) ||
2625 (var->fModifiers.fFlags & Modifiers::kOut_Flag))) {
2626 interfaceVars.push_back(entry.second);
2627 }
2628 }
2629 this->writeCapabilities(out);
2630 this->writeInstruction(SpvOpExtInstImport, fGLSLExtendedInstructions, "GLSL.std.450", out);
2631 this->writeInstruction(SpvOpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450, out);
2632 this->writeOpCode(SpvOpEntryPoint, (SpvId) (3 + (strlen(main->fName.c_str()) + 4) / 4) +
2633 (int32_t) interfaceVars.size(), out);
2634 switch (program.fKind) {
2635 case Program::kVertex_Kind:
2636 this->writeWord(SpvExecutionModelVertex, out);
2637 break;
2638 case Program::kFragment_Kind:
2639 this->writeWord(SpvExecutionModelFragment, out);
2640 break;
2641 }
2642 this->writeWord(fFunctionMap[main], out);
2643 this->writeString(main->fName.c_str(), out);
2644 for (int var : interfaceVars) {
2645 this->writeWord(var, out);
2646 }
2647 if (program.fKind == Program::kFragment_Kind) {
2648 this->writeInstruction(SpvOpExecutionMode,
2649 fFunctionMap[main],
2650 SpvExecutionModeOriginUpperLeft,
2651 out);
2652 }
2653 for (size_t i = 0; i < program.fElements.size(); i++) {
2654 if (program.fElements[i]->fKind == ProgramElement::kExtension_Kind) {
2655 this->writeInstruction(SpvOpSourceExtension,
2656 ((Extension&) *program.fElements[i]).fName.c_str(),
2657 out);
2658 }
2659 }
2660
2661 out << fNameBuffer.str();
2662 out << fDecorationBuffer.str();
2663 out << fConstantBuffer.str();
2664 out << fExternalFunctionsBuffer.str();
2665 out << body.str();
2666}
2667
ethannicholasf789b382016-08-03 12:43:36 -07002668void SPIRVCodeGenerator::generateCode(const Program& program, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002669 this->writeWord(SpvMagicNumber, out);
2670 this->writeWord(SpvVersion, out);
2671 this->writeWord(SKSL_MAGIC, out);
2672 std::stringstream buffer;
2673 this->writeInstructions(program, buffer);
2674 this->writeWord(fIdCount, out);
2675 this->writeWord(0, out); // reserved, always zero
2676 out << buffer.str();
2677}
2678
2679}