blob: 5403ba362814057ad46e2047d96a3f730b4a54c8 [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"
ethannicholasccb1dd82016-10-11 08:47:04 -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
971void SPIRVCodeGenerator::writeStruct(const Type& type, SpvId resultId) {
972 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()) {
ethannicholas0730be72016-09-01 07:59:02 -0700977 types.push_back(this->getType(*f.fType));
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++) {
ethannicholas0730be72016-09-01 07:59:02 -0700986 size_t size = type.fields()[i].fType->size();
987 size_t alignment = type.fields()[i].fType->alignment();
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,
ethannicholas0730be72016-09-01 07:59:02 -07001003 (SpvId) type.fields()[i].fType->stride(), fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001004 }
1005 offset += size;
ethannicholas0730be72016-09-01 07:59:02 -07001006 Type::Kind kind = type.fields()[i].fType->kind();
ethannicholasb3058bd2016-07-01 08:22:01 -07001007 if ((kind == Type::kArray_Kind || kind == Type::kStruct_Kind) && offset % alignment != 0) {
1008 offset += alignment - offset % alignment;
1009 }
1010 ASSERT(offset % alignment == 0);
1011 }
1012}
1013
1014SpvId SPIRVCodeGenerator::getType(const Type& type) {
1015 auto entry = fTypeMap.find(type.name());
1016 if (entry == fTypeMap.end()) {
1017 SpvId result = this->nextId();
1018 switch (type.kind()) {
1019 case Type::kScalar_Kind:
ethannicholasd598f792016-07-25 10:08:54 -07001020 if (type == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001021 this->writeInstruction(SpvOpTypeBool, result, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001022 } else if (type == *fContext.fInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001023 this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001024 } else if (type == *fContext.fUInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001025 this->writeInstruction(SpvOpTypeInt, result, 32, 0, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001026 } else if (type == *fContext.fFloat_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001027 this->writeInstruction(SpvOpTypeFloat, result, 32, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001028 } else if (type == *fContext.fDouble_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001029 this->writeInstruction(SpvOpTypeFloat, result, 64, fConstantBuffer);
1030 } else {
1031 ASSERT(false);
1032 }
1033 break;
1034 case Type::kVector_Kind:
1035 this->writeInstruction(SpvOpTypeVector, result,
ethannicholasd598f792016-07-25 10:08:54 -07001036 this->getType(type.componentType()),
ethannicholasb3058bd2016-07-01 08:22:01 -07001037 type.columns(), fConstantBuffer);
1038 break;
1039 case Type::kMatrix_Kind:
ethannicholasd598f792016-07-25 10:08:54 -07001040 this->writeInstruction(SpvOpTypeMatrix, result,
1041 this->getType(index_type(fContext, type)),
ethannicholasb3058bd2016-07-01 08:22:01 -07001042 type.columns(), fConstantBuffer);
1043 break;
1044 case Type::kStruct_Kind:
1045 this->writeStruct(type, result);
1046 break;
1047 case Type::kArray_Kind: {
1048 if (type.columns() > 0) {
ethannicholasd598f792016-07-25 10:08:54 -07001049 IntLiteral count(fContext, Position(), type.columns());
ethannicholasb3058bd2016-07-01 08:22:01 -07001050 this->writeInstruction(SpvOpTypeArray, result,
ethannicholasd598f792016-07-25 10:08:54 -07001051 this->getType(type.componentType()),
ethannicholasb3058bd2016-07-01 08:22:01 -07001052 this->writeIntLiteral(count), fConstantBuffer);
1053 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
1054 (int32_t) type.stride(), fDecorationBuffer);
1055 } else {
1056 ABORT("runtime-sized arrays are not yet supported");
1057 this->writeInstruction(SpvOpTypeRuntimeArray, result,
ethannicholasd598f792016-07-25 10:08:54 -07001058 this->getType(type.componentType()), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001059 }
1060 break;
1061 }
1062 case Type::kSampler_Kind: {
1063 SpvId image = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001064 this->writeInstruction(SpvOpTypeImage, image, this->getType(*fContext.fFloat_Type),
ethannicholasb3058bd2016-07-01 08:22:01 -07001065 type.dimensions(), type.isDepth(), type.isArrayed(),
1066 type.isMultisampled(), type.isSampled(),
1067 SpvImageFormatUnknown, fConstantBuffer);
1068 this->writeInstruction(SpvOpTypeSampledImage, result, image, fConstantBuffer);
1069 break;
1070 }
1071 default:
ethannicholasd598f792016-07-25 10:08:54 -07001072 if (type == *fContext.fVoid_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001073 this->writeInstruction(SpvOpTypeVoid, result, fConstantBuffer);
1074 } else {
1075 ABORT("invalid type: %s", type.description().c_str());
1076 }
1077 }
1078 fTypeMap[type.name()] = result;
1079 return result;
1080 }
1081 return entry->second;
1082}
1083
ethannicholasd598f792016-07-25 10:08:54 -07001084SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) {
1085 std::string key = function.fReturnType.description() + "(";
ethannicholasb3058bd2016-07-01 08:22:01 -07001086 std::string separator = "";
ethannicholasd598f792016-07-25 10:08:54 -07001087 for (size_t i = 0; i < function.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001088 key += separator;
1089 separator = ", ";
ethannicholasd598f792016-07-25 10:08:54 -07001090 key += function.fParameters[i]->fType.description();
ethannicholasb3058bd2016-07-01 08:22:01 -07001091 }
1092 key += ")";
1093 auto entry = fTypeMap.find(key);
1094 if (entry == fTypeMap.end()) {
1095 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001096 int32_t length = 3 + (int32_t) function.fParameters.size();
1097 SpvId returnType = this->getType(function.fReturnType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001098 std::vector<SpvId> parameterTypes;
ethannicholasd598f792016-07-25 10:08:54 -07001099 for (size_t i = 0; i < function.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001100 // glslang seems to treat all function arguments as pointers whether they need to be or
1101 // not. I was initially puzzled by this until I ran bizarre failures with certain
1102 // patterns of function calls and control constructs, as exemplified by this minimal
1103 // failure case:
1104 //
1105 // void sphere(float x) {
1106 // }
1107 //
1108 // void map() {
1109 // sphere(1.0);
1110 // }
1111 //
1112 // void main() {
1113 // for (int i = 0; i < 1; i++) {
1114 // map();
1115 // }
1116 // }
1117 //
1118 // As of this writing, compiling this in the "obvious" way (with sphere taking a float)
1119 // crashes. Making it take a float* and storing the argument in a temporary variable,
1120 // as glslang does, fixes it. It's entirely possible I simply missed whichever part of
1121 // the spec makes this make sense.
1122// if (is_out(function->fParameters[i])) {
ethannicholasd598f792016-07-25 10:08:54 -07001123 parameterTypes.push_back(this->getPointerType(function.fParameters[i]->fType,
ethannicholasb3058bd2016-07-01 08:22:01 -07001124 SpvStorageClassFunction));
1125// } else {
ethannicholasd598f792016-07-25 10:08:54 -07001126// parameterTypes.push_back(this->getType(function.fParameters[i]->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -07001127// }
1128 }
1129 this->writeOpCode(SpvOpTypeFunction, length, fConstantBuffer);
1130 this->writeWord(result, fConstantBuffer);
1131 this->writeWord(returnType, fConstantBuffer);
1132 for (SpvId id : parameterTypes) {
1133 this->writeWord(id, fConstantBuffer);
1134 }
1135 fTypeMap[key] = result;
1136 return result;
1137 }
1138 return entry->second;
1139}
1140
ethannicholasd598f792016-07-25 10:08:54 -07001141SpvId SPIRVCodeGenerator::getPointerType(const Type& type,
ethannicholasb3058bd2016-07-01 08:22:01 -07001142 SpvStorageClass_ storageClass) {
ethannicholasd598f792016-07-25 10:08:54 -07001143 std::string key = type.description() + "*" + to_string(storageClass);
ethannicholasb3058bd2016-07-01 08:22:01 -07001144 auto entry = fTypeMap.find(key);
1145 if (entry == fTypeMap.end()) {
1146 SpvId result = this->nextId();
1147 this->writeInstruction(SpvOpTypePointer, result, storageClass,
ethannicholasd598f792016-07-25 10:08:54 -07001148 this->getType(type), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001149 fTypeMap[key] = result;
1150 return result;
1151 }
1152 return entry->second;
1153}
1154
ethannicholasf789b382016-08-03 12:43:36 -07001155SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001156 switch (expr.fKind) {
1157 case Expression::kBinary_Kind:
1158 return this->writeBinaryExpression((BinaryExpression&) expr, out);
1159 case Expression::kBoolLiteral_Kind:
1160 return this->writeBoolLiteral((BoolLiteral&) expr);
1161 case Expression::kConstructor_Kind:
1162 return this->writeConstructor((Constructor&) expr, out);
1163 case Expression::kIntLiteral_Kind:
1164 return this->writeIntLiteral((IntLiteral&) expr);
1165 case Expression::kFieldAccess_Kind:
1166 return this->writeFieldAccess(((FieldAccess&) expr), out);
1167 case Expression::kFloatLiteral_Kind:
1168 return this->writeFloatLiteral(((FloatLiteral&) expr));
1169 case Expression::kFunctionCall_Kind:
1170 return this->writeFunctionCall((FunctionCall&) expr, out);
1171 case Expression::kPrefix_Kind:
1172 return this->writePrefixExpression((PrefixExpression&) expr, out);
1173 case Expression::kPostfix_Kind:
1174 return this->writePostfixExpression((PostfixExpression&) expr, out);
1175 case Expression::kSwizzle_Kind:
1176 return this->writeSwizzle((Swizzle&) expr, out);
1177 case Expression::kVariableReference_Kind:
1178 return this->writeVariableReference((VariableReference&) expr, out);
1179 case Expression::kTernary_Kind:
1180 return this->writeTernaryExpression((TernaryExpression&) expr, out);
1181 case Expression::kIndex_Kind:
1182 return this->writeIndexExpression((IndexExpression&) expr, out);
1183 default:
1184 ABORT("unsupported expression: %s", expr.description().c_str());
1185 }
1186 return -1;
1187}
1188
ethannicholasf789b382016-08-03 12:43:36 -07001189SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, std::ostream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001190 auto intrinsic = fIntrinsicMap.find(c.fFunction.fName);
ethannicholasb3058bd2016-07-01 08:22:01 -07001191 ASSERT(intrinsic != fIntrinsicMap.end());
ethannicholasd598f792016-07-25 10:08:54 -07001192 const Type& type = c.fArguments[0]->fType;
ethannicholasb3058bd2016-07-01 08:22:01 -07001193 int32_t intrinsicId;
ethannicholasd598f792016-07-25 10:08:54 -07001194 if (std::get<0>(intrinsic->second) == kSpecial_IntrinsicKind || is_float(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001195 intrinsicId = std::get<1>(intrinsic->second);
ethannicholasd598f792016-07-25 10:08:54 -07001196 } else if (is_signed(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001197 intrinsicId = std::get<2>(intrinsic->second);
ethannicholasd598f792016-07-25 10:08:54 -07001198 } else if (is_unsigned(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001199 intrinsicId = std::get<3>(intrinsic->second);
ethannicholasd598f792016-07-25 10:08:54 -07001200 } else if (is_bool(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001201 intrinsicId = std::get<4>(intrinsic->second);
1202 } else {
1203 ABORT("invalid call %s, cannot operate on '%s'", c.description().c_str(),
ethannicholasd598f792016-07-25 10:08:54 -07001204 type.description().c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -07001205 }
1206 switch (std::get<0>(intrinsic->second)) {
1207 case kGLSL_STD_450_IntrinsicKind: {
1208 SpvId result = this->nextId();
1209 std::vector<SpvId> arguments;
1210 for (size_t i = 0; i < c.fArguments.size(); i++) {
1211 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1212 }
1213 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001214 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001215 this->writeWord(result, out);
1216 this->writeWord(fGLSLExtendedInstructions, out);
1217 this->writeWord(intrinsicId, out);
1218 for (SpvId id : arguments) {
1219 this->writeWord(id, out);
1220 }
1221 return result;
1222 }
1223 case kSPIRV_IntrinsicKind: {
1224 SpvId result = this->nextId();
1225 std::vector<SpvId> arguments;
1226 for (size_t i = 0; i < c.fArguments.size(); i++) {
1227 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1228 }
1229 this->writeOpCode((SpvOp_) intrinsicId, 3 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001230 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001231 this->writeWord(result, out);
1232 for (SpvId id : arguments) {
1233 this->writeWord(id, out);
1234 }
1235 return result;
1236 }
1237 case kSpecial_IntrinsicKind:
1238 return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId, out);
1239 default:
1240 ABORT("unsupported intrinsic kind");
1241 }
1242}
1243
ethannicholasf789b382016-08-03 12:43:36 -07001244SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind,
ethannicholasb3058bd2016-07-01 08:22:01 -07001245 std::ostream& out) {
1246 SpvId result = this->nextId();
1247 switch (kind) {
1248 case kAtan_SpecialIntrinsic: {
1249 std::vector<SpvId> arguments;
1250 for (size_t i = 0; i < c.fArguments.size(); i++) {
1251 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1252 }
1253 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001254 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001255 this->writeWord(result, out);
1256 this->writeWord(fGLSLExtendedInstructions, out);
1257 this->writeWord(arguments.size() == 2 ? GLSLstd450Atan2 : GLSLstd450Atan, out);
1258 for (SpvId id : arguments) {
1259 this->writeWord(id, out);
1260 }
1261 return result;
1262 }
1263 case kTexture_SpecialIntrinsic: {
ethannicholasd598f792016-07-25 10:08:54 -07001264 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001265 SpvId sampler = this->writeExpression(*c.fArguments[0], out);
1266 SpvId uv = this->writeExpression(*c.fArguments[1], out);
1267 if (c.fArguments.size() == 3) {
1268 this->writeInstruction(SpvOpImageSampleImplicitLod, type, result, sampler, uv,
1269 SpvImageOperandsBiasMask,
1270 this->writeExpression(*c.fArguments[2], out),
1271 out);
1272 } else {
1273 ASSERT(c.fArguments.size() == 2);
1274 this->writeInstruction(SpvOpImageSampleImplicitLod, type, result, sampler, uv, out);
1275 }
1276 break;
1277 }
1278 case kTextureProj_SpecialIntrinsic: {
ethannicholasd598f792016-07-25 10:08:54 -07001279 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001280 SpvId sampler = this->writeExpression(*c.fArguments[0], out);
1281 SpvId uv = this->writeExpression(*c.fArguments[1], out);
1282 if (c.fArguments.size() == 3) {
1283 this->writeInstruction(SpvOpImageSampleProjImplicitLod, type, result, sampler, uv,
1284 SpvImageOperandsBiasMask,
1285 this->writeExpression(*c.fArguments[2], out),
1286 out);
1287 } else {
1288 ASSERT(c.fArguments.size() == 2);
1289 this->writeInstruction(SpvOpImageSampleProjImplicitLod, type, result, sampler, uv,
1290 out);
1291 }
1292 break;
1293 }
1294 case kTexture2D_SpecialIntrinsic: {
1295 SpvId img = this->writeExpression(*c.fArguments[0], out);
1296 SpvId coords = this->writeExpression(*c.fArguments[1], out);
1297 this->writeInstruction(SpvOpImageSampleImplicitLod,
ethannicholasd598f792016-07-25 10:08:54 -07001298 this->getType(c.fType),
ethannicholasb3058bd2016-07-01 08:22:01 -07001299 result,
1300 img,
1301 coords,
1302 out);
1303 break;
1304 }
1305 }
1306 return result;
1307}
1308
ethannicholasf789b382016-08-03 12:43:36 -07001309SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, std::ostream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001310 const auto& entry = fFunctionMap.find(&c.fFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07001311 if (entry == fFunctionMap.end()) {
1312 return this->writeIntrinsicCall(c, out);
1313 }
1314 // stores (variable, type, lvalue) pairs to extract and save after the function call is complete
1315 std::vector<std::tuple<SpvId, SpvId, std::unique_ptr<LValue>>> lvalues;
1316 std::vector<SpvId> arguments;
1317 for (size_t i = 0; i < c.fArguments.size(); i++) {
1318 // id of temporary variable that we will use to hold this argument, or 0 if it is being
1319 // passed directly
1320 SpvId tmpVar;
1321 // if we need a temporary var to store this argument, this is the value to store in the var
1322 SpvId tmpValueId;
ethannicholasd598f792016-07-25 10:08:54 -07001323 if (is_out(*c.fFunction.fParameters[i])) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001324 std::unique_ptr<LValue> lv = this->getLValue(*c.fArguments[i], out);
1325 SpvId ptr = lv->getPointer();
1326 if (ptr) {
1327 arguments.push_back(ptr);
1328 continue;
1329 } else {
1330 // lvalue cannot simply be read and written via a pointer (e.g. a swizzle). Need to
1331 // copy it into a temp, call the function, read the value out of the temp, and then
1332 // update the lvalue.
1333 tmpValueId = lv->load(out);
1334 tmpVar = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001335 lvalues.push_back(std::make_tuple(tmpVar, this->getType(c.fArguments[i]->fType),
ethannicholasb3058bd2016-07-01 08:22:01 -07001336 std::move(lv)));
1337 }
1338 } else {
1339 // see getFunctionType for an explanation of why we're always using pointer parameters
1340 tmpValueId = this->writeExpression(*c.fArguments[i], out);
1341 tmpVar = this->nextId();
1342 }
1343 this->writeInstruction(SpvOpVariable,
1344 this->getPointerType(c.fArguments[i]->fType,
1345 SpvStorageClassFunction),
1346 tmpVar,
1347 SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001348 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001349 this->writeInstruction(SpvOpStore, tmpVar, tmpValueId, out);
1350 arguments.push_back(tmpVar);
1351 }
1352 SpvId result = this->nextId();
1353 this->writeOpCode(SpvOpFunctionCall, 4 + (int32_t) c.fArguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001354 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001355 this->writeWord(result, out);
1356 this->writeWord(entry->second, out);
1357 for (SpvId id : arguments) {
1358 this->writeWord(id, out);
1359 }
1360 // now that the call is complete, we may need to update some lvalues with the new values of out
1361 // arguments
1362 for (const auto& tuple : lvalues) {
1363 SpvId load = this->nextId();
1364 this->writeInstruction(SpvOpLoad, std::get<1>(tuple), load, std::get<0>(tuple), out);
1365 std::get<2>(tuple)->store(load, out);
1366 }
1367 return result;
1368}
1369
ethannicholasf789b382016-08-03 12:43:36 -07001370SpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) {
ethannicholasd598f792016-07-25 10:08:54 -07001371 ASSERT(c.fType.kind() == Type::kVector_Kind && c.isConstant());
ethannicholasb3058bd2016-07-01 08:22:01 -07001372 SpvId result = this->nextId();
1373 std::vector<SpvId> arguments;
1374 for (size_t i = 0; i < c.fArguments.size(); i++) {
1375 arguments.push_back(this->writeExpression(*c.fArguments[i], fConstantBuffer));
1376 }
ethannicholasd598f792016-07-25 10:08:54 -07001377 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001378 if (c.fArguments.size() == 1) {
1379 // with a single argument, a vector will have all of its entries equal to the argument
ethannicholasd598f792016-07-25 10:08:54 -07001380 this->writeOpCode(SpvOpConstantComposite, 3 + c.fType.columns(), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001381 this->writeWord(type, fConstantBuffer);
1382 this->writeWord(result, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001383 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001384 this->writeWord(arguments[0], fConstantBuffer);
1385 }
1386 } else {
1387 this->writeOpCode(SpvOpConstantComposite, 3 + (int32_t) c.fArguments.size(),
1388 fConstantBuffer);
1389 this->writeWord(type, fConstantBuffer);
1390 this->writeWord(result, fConstantBuffer);
1391 for (SpvId id : arguments) {
1392 this->writeWord(id, fConstantBuffer);
1393 }
1394 }
1395 return result;
1396}
1397
ethannicholasf789b382016-08-03 12:43:36 -07001398SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, std::ostream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001399 ASSERT(c.fType == *fContext.fFloat_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07001400 ASSERT(c.fArguments.size() == 1);
ethannicholasd598f792016-07-25 10:08:54 -07001401 ASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001402 SpvId result = this->nextId();
1403 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
ethannicholasd598f792016-07-25 10:08:54 -07001404 if (c.fArguments[0]->fType == *fContext.fInt_Type) {
1405 this->writeInstruction(SpvOpConvertSToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001406 out);
ethannicholasd598f792016-07-25 10:08:54 -07001407 } else if (c.fArguments[0]->fType == *fContext.fUInt_Type) {
1408 this->writeInstruction(SpvOpConvertUToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001409 out);
ethannicholasd598f792016-07-25 10:08:54 -07001410 } else if (c.fArguments[0]->fType == *fContext.fFloat_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001411 return parameter;
1412 }
1413 return result;
1414}
1415
ethannicholasf789b382016-08-03 12:43:36 -07001416SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, std::ostream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001417 ASSERT(c.fType == *fContext.fInt_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07001418 ASSERT(c.fArguments.size() == 1);
ethannicholasd598f792016-07-25 10:08:54 -07001419 ASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001420 SpvId result = this->nextId();
1421 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
ethannicholasd598f792016-07-25 10:08:54 -07001422 if (c.fArguments[0]->fType == *fContext.fFloat_Type) {
1423 this->writeInstruction(SpvOpConvertFToS, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001424 out);
ethannicholasd598f792016-07-25 10:08:54 -07001425 } else if (c.fArguments[0]->fType == *fContext.fUInt_Type) {
1426 this->writeInstruction(SpvOpSatConvertUToS, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001427 out);
ethannicholasd598f792016-07-25 10:08:54 -07001428 } else if (c.fArguments[0]->fType == *fContext.fInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001429 return parameter;
1430 }
1431 return result;
1432}
1433
ethannicholasf789b382016-08-03 12:43:36 -07001434SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, std::ostream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001435 ASSERT(c.fType.kind() == Type::kMatrix_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001436 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1437 // an instruction
1438 std::vector<SpvId> arguments;
1439 for (size_t i = 0; i < c.fArguments.size(); i++) {
1440 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1441 }
1442 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001443 int rows = c.fType.rows();
1444 int columns = c.fType.columns();
ethannicholasb3058bd2016-07-01 08:22:01 -07001445 // FIXME this won't work to create a matrix from another matrix
1446 if (arguments.size() == 1) {
1447 // with a single argument, a matrix will have all of its diagonal entries equal to the
1448 // argument and its other values equal to zero
1449 // FIXME this won't work for int matrices
ethannicholasd598f792016-07-25 10:08:54 -07001450 FloatLiteral zero(fContext, Position(), 0);
ethannicholasb3058bd2016-07-01 08:22:01 -07001451 SpvId zeroId = this->writeFloatLiteral(zero);
1452 std::vector<SpvId> columnIds;
1453 for (int column = 0; column < columns; column++) {
ethannicholasd598f792016-07-25 10:08:54 -07001454 this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.rows(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001455 out);
ethannicholasd598f792016-07-25 10:08:54 -07001456 this->writeWord(this->getType(c.fType.componentType().toCompound(fContext, rows, 1)),
1457 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001458 SpvId columnId = this->nextId();
1459 this->writeWord(columnId, out);
1460 columnIds.push_back(columnId);
ethannicholasd598f792016-07-25 10:08:54 -07001461 for (int row = 0; row < c.fType.columns(); row++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001462 this->writeWord(row == column ? arguments[0] : zeroId, out);
1463 }
1464 }
1465 this->writeOpCode(SpvOpCompositeConstruct, 3 + columns,
1466 out);
ethannicholasd598f792016-07-25 10:08:54 -07001467 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001468 this->writeWord(result, out);
1469 for (SpvId id : columnIds) {
1470 this->writeWord(id, out);
1471 }
1472 } else {
1473 std::vector<SpvId> columnIds;
1474 int currentCount = 0;
1475 for (size_t i = 0; i < arguments.size(); i++) {
ethannicholasd598f792016-07-25 10:08:54 -07001476 if (c.fArguments[i]->fType.kind() == Type::kVector_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001477 ASSERT(currentCount == 0);
1478 columnIds.push_back(arguments[i]);
1479 currentCount = 0;
1480 } else {
ethannicholasd598f792016-07-25 10:08:54 -07001481 ASSERT(c.fArguments[i]->fType.kind() == Type::kScalar_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001482 if (currentCount == 0) {
ethannicholasd598f792016-07-25 10:08:54 -07001483 this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.rows(), out);
1484 this->writeWord(this->getType(c.fType.componentType().toCompound(fContext, rows,
1485 1)),
ethannicholasb3058bd2016-07-01 08:22:01 -07001486 out);
1487 SpvId id = this->nextId();
1488 this->writeWord(id, out);
1489 columnIds.push_back(id);
1490 }
1491 this->writeWord(arguments[i], out);
1492 currentCount = (currentCount + 1) % rows;
1493 }
1494 }
1495 ASSERT(columnIds.size() == (size_t) columns);
1496 this->writeOpCode(SpvOpCompositeConstruct, 3 + columns, out);
ethannicholasd598f792016-07-25 10:08:54 -07001497 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001498 this->writeWord(result, out);
1499 for (SpvId id : columnIds) {
1500 this->writeWord(id, out);
1501 }
1502 }
1503 return result;
1504}
1505
ethannicholasf789b382016-08-03 12:43:36 -07001506SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, std::ostream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001507 ASSERT(c.fType.kind() == Type::kVector_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001508 if (c.isConstant()) {
1509 return this->writeConstantVector(c);
1510 }
1511 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1512 // an instruction
1513 std::vector<SpvId> arguments;
1514 for (size_t i = 0; i < c.fArguments.size(); i++) {
1515 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1516 }
1517 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001518 if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) {
1519 this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.columns(), out);
1520 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001521 this->writeWord(result, out);
ethannicholasd598f792016-07-25 10:08:54 -07001522 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001523 this->writeWord(arguments[0], out);
1524 }
1525 } else {
1526 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) c.fArguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001527 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001528 this->writeWord(result, out);
1529 for (SpvId id : arguments) {
1530 this->writeWord(id, out);
1531 }
1532 }
1533 return result;
1534}
1535
ethannicholasf789b382016-08-03 12:43:36 -07001536SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, std::ostream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001537 if (c.fType == *fContext.fFloat_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001538 return this->writeFloatConstructor(c, out);
ethannicholasd598f792016-07-25 10:08:54 -07001539 } else if (c.fType == *fContext.fInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001540 return this->writeIntConstructor(c, out);
1541 }
ethannicholasd598f792016-07-25 10:08:54 -07001542 switch (c.fType.kind()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001543 case Type::kVector_Kind:
1544 return this->writeVectorConstructor(c, out);
1545 case Type::kMatrix_Kind:
1546 return this->writeMatrixConstructor(c, out);
1547 default:
1548 ABORT("unsupported constructor: %s", c.description().c_str());
1549 }
1550}
1551
1552SpvStorageClass_ get_storage_class(const Modifiers& modifiers) {
1553 if (modifiers.fFlags & Modifiers::kIn_Flag) {
1554 return SpvStorageClassInput;
1555 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
1556 return SpvStorageClassOutput;
1557 } else if (modifiers.fFlags & Modifiers::kUniform_Flag) {
1558 return SpvStorageClassUniform;
1559 } else {
1560 return SpvStorageClassFunction;
1561 }
1562}
1563
ethannicholasf789b382016-08-03 12:43:36 -07001564SpvStorageClass_ get_storage_class(const Expression& expr) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001565 switch (expr.fKind) {
1566 case Expression::kVariableReference_Kind:
ethannicholasd598f792016-07-25 10:08:54 -07001567 return get_storage_class(((VariableReference&) expr).fVariable.fModifiers);
ethannicholasb3058bd2016-07-01 08:22:01 -07001568 case Expression::kFieldAccess_Kind:
1569 return get_storage_class(*((FieldAccess&) expr).fBase);
1570 case Expression::kIndex_Kind:
1571 return get_storage_class(*((IndexExpression&) expr).fBase);
1572 default:
1573 return SpvStorageClassFunction;
1574 }
1575}
1576
ethannicholasf789b382016-08-03 12:43:36 -07001577std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001578 std::vector<SpvId> chain;
1579 switch (expr.fKind) {
1580 case Expression::kIndex_Kind: {
1581 IndexExpression& indexExpr = (IndexExpression&) expr;
1582 chain = this->getAccessChain(*indexExpr.fBase, out);
1583 chain.push_back(this->writeExpression(*indexExpr.fIndex, out));
1584 break;
1585 }
1586 case Expression::kFieldAccess_Kind: {
1587 FieldAccess& fieldExpr = (FieldAccess&) expr;
1588 chain = this->getAccessChain(*fieldExpr.fBase, out);
ethannicholasd598f792016-07-25 10:08:54 -07001589 IntLiteral index(fContext, Position(), fieldExpr.fFieldIndex);
ethannicholasb3058bd2016-07-01 08:22:01 -07001590 chain.push_back(this->writeIntLiteral(index));
1591 break;
1592 }
1593 default:
1594 chain.push_back(this->getLValue(expr, out)->getPointer());
1595 }
1596 return chain;
1597}
1598
1599class PointerLValue : public SPIRVCodeGenerator::LValue {
1600public:
1601 PointerLValue(SPIRVCodeGenerator& gen, SpvId pointer, SpvId type)
1602 : fGen(gen)
1603 , fPointer(pointer)
1604 , fType(type) {}
1605
1606 virtual SpvId getPointer() override {
1607 return fPointer;
1608 }
1609
1610 virtual SpvId load(std::ostream& out) override {
1611 SpvId result = fGen.nextId();
1612 fGen.writeInstruction(SpvOpLoad, fType, result, fPointer, out);
1613 return result;
1614 }
1615
1616 virtual void store(SpvId value, std::ostream& out) override {
1617 fGen.writeInstruction(SpvOpStore, fPointer, value, out);
1618 }
1619
1620private:
1621 SPIRVCodeGenerator& fGen;
1622 const SpvId fPointer;
1623 const SpvId fType;
1624};
1625
1626class SwizzleLValue : public SPIRVCodeGenerator::LValue {
1627public:
1628 SwizzleLValue(SPIRVCodeGenerator& gen, SpvId vecPointer, const std::vector<int>& components,
1629 const Type& baseType, const Type& swizzleType)
1630 : fGen(gen)
1631 , fVecPointer(vecPointer)
1632 , fComponents(components)
1633 , fBaseType(baseType)
1634 , fSwizzleType(swizzleType) {}
1635
1636 virtual SpvId getPointer() override {
1637 return 0;
1638 }
1639
1640 virtual SpvId load(std::ostream& out) override {
1641 SpvId base = fGen.nextId();
1642 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1643 SpvId result = fGen.nextId();
1644 fGen.writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) fComponents.size(), out);
1645 fGen.writeWord(fGen.getType(fSwizzleType), out);
1646 fGen.writeWord(result, out);
1647 fGen.writeWord(base, out);
1648 fGen.writeWord(base, out);
1649 for (int component : fComponents) {
1650 fGen.writeWord(component, out);
1651 }
1652 return result;
1653 }
1654
1655 virtual void store(SpvId value, std::ostream& out) override {
1656 // use OpVectorShuffle to mix and match the vector components. We effectively create
1657 // a virtual vector out of the concatenation of the left and right vectors, and then
1658 // select components from this virtual vector to make the result vector. For
1659 // instance, given:
1660 // vec3 L = ...;
1661 // vec3 R = ...;
1662 // L.xz = R.xy;
1663 // we end up with the virtual vector (L.x, L.y, L.z, R.x, R.y, R.z). Then we want
1664 // our result vector to look like (R.x, L.y, R.y), so we need to select indices
1665 // (3, 1, 4).
1666 SpvId base = fGen.nextId();
1667 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1668 SpvId shuffle = fGen.nextId();
1669 fGen.writeOpCode(SpvOpVectorShuffle, 5 + fBaseType.columns(), out);
1670 fGen.writeWord(fGen.getType(fBaseType), out);
1671 fGen.writeWord(shuffle, out);
1672 fGen.writeWord(base, out);
1673 fGen.writeWord(value, out);
1674 for (int i = 0; i < fBaseType.columns(); i++) {
1675 // current offset into the virtual vector, defaults to pulling the unmodified
1676 // value from the left side
1677 int offset = i;
1678 // check to see if we are writing this component
1679 for (size_t j = 0; j < fComponents.size(); j++) {
1680 if (fComponents[j] == i) {
1681 // we're writing to this component, so adjust the offset to pull from
1682 // the correct component of the right side instead of preserving the
1683 // value from the left
1684 offset = (int) (j + fBaseType.columns());
1685 break;
1686 }
1687 }
1688 fGen.writeWord(offset, out);
1689 }
1690 fGen.writeInstruction(SpvOpStore, fVecPointer, shuffle, out);
1691 }
1692
1693private:
1694 SPIRVCodeGenerator& fGen;
1695 const SpvId fVecPointer;
1696 const std::vector<int>& fComponents;
1697 const Type& fBaseType;
1698 const Type& fSwizzleType;
1699};
1700
ethannicholasf789b382016-08-03 12:43:36 -07001701std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const Expression& expr,
ethannicholasb3058bd2016-07-01 08:22:01 -07001702 std::ostream& out) {
1703 switch (expr.fKind) {
1704 case Expression::kVariableReference_Kind: {
ethannicholasd598f792016-07-25 10:08:54 -07001705 const Variable& var = ((VariableReference&) expr).fVariable;
1706 auto entry = fVariableMap.find(&var);
ethannicholasb3058bd2016-07-01 08:22:01 -07001707 ASSERT(entry != fVariableMap.end());
1708 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1709 *this,
1710 entry->second,
ethannicholasd598f792016-07-25 10:08:54 -07001711 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001712 }
1713 case Expression::kIndex_Kind: // fall through
1714 case Expression::kFieldAccess_Kind: {
1715 std::vector<SpvId> chain = this->getAccessChain(expr, out);
1716 SpvId member = this->nextId();
1717 this->writeOpCode(SpvOpAccessChain, (SpvId) (3 + chain.size()), out);
1718 this->writeWord(this->getPointerType(expr.fType, get_storage_class(expr)), out);
1719 this->writeWord(member, out);
1720 for (SpvId idx : chain) {
1721 this->writeWord(idx, out);
1722 }
1723 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1724 *this,
1725 member,
ethannicholasd598f792016-07-25 10:08:54 -07001726 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001727 }
1728
1729 case Expression::kSwizzle_Kind: {
1730 Swizzle& swizzle = (Swizzle&) expr;
1731 size_t count = swizzle.fComponents.size();
1732 SpvId base = this->getLValue(*swizzle.fBase, out)->getPointer();
1733 ASSERT(base);
1734 if (count == 1) {
ethannicholasd598f792016-07-25 10:08:54 -07001735 IntLiteral index(fContext, Position(), swizzle.fComponents[0]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001736 SpvId member = this->nextId();
1737 this->writeInstruction(SpvOpAccessChain,
1738 this->getPointerType(swizzle.fType,
1739 get_storage_class(*swizzle.fBase)),
1740 member,
1741 base,
1742 this->writeIntLiteral(index),
1743 out);
1744 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1745 *this,
1746 member,
ethannicholasd598f792016-07-25 10:08:54 -07001747 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001748 } else {
1749 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new SwizzleLValue(
1750 *this,
1751 base,
1752 swizzle.fComponents,
ethannicholasd598f792016-07-25 10:08:54 -07001753 swizzle.fBase->fType,
1754 expr.fType));
ethannicholasb3058bd2016-07-01 08:22:01 -07001755 }
1756 }
1757
1758 default:
1759 // expr isn't actually an lvalue, create a dummy variable for it. This case happens due
1760 // to the need to store values in temporary variables during function calls (see
1761 // comments in getFunctionType); erroneous uses of rvalues as lvalues should have been
1762 // caught by IRGenerator
1763 SpvId result = this->nextId();
1764 SpvId type = this->getPointerType(expr.fType, SpvStorageClassFunction);
ethannicholasd598f792016-07-25 10:08:54 -07001765 this->writeInstruction(SpvOpVariable, type, result, SpvStorageClassFunction,
1766 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001767 this->writeInstruction(SpvOpStore, result, this->writeExpression(expr, out), out);
1768 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1769 *this,
1770 result,
ethannicholasd598f792016-07-25 10:08:54 -07001771 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001772 }
1773}
1774
ethannicholasf789b382016-08-03 12:43:36 -07001775SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, std::ostream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001776 auto entry = fVariableMap.find(&ref.fVariable);
ethannicholasb3058bd2016-07-01 08:22:01 -07001777 ASSERT(entry != fVariableMap.end());
1778 SpvId var = entry->second;
1779 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001780 this->writeInstruction(SpvOpLoad, this->getType(ref.fVariable.fType), result, var, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001781 return result;
1782}
1783
ethannicholasf789b382016-08-03 12:43:36 -07001784SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001785 return getLValue(expr, out)->load(out);
1786}
1787
ethannicholasf789b382016-08-03 12:43:36 -07001788SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001789 return getLValue(f, out)->load(out);
1790}
1791
ethannicholasf789b382016-08-03 12:43:36 -07001792SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001793 SpvId base = this->writeExpression(*swizzle.fBase, out);
1794 SpvId result = this->nextId();
1795 size_t count = swizzle.fComponents.size();
1796 if (count == 1) {
ethannicholasd598f792016-07-25 10:08:54 -07001797 this->writeInstruction(SpvOpCompositeExtract, this->getType(swizzle.fType), result, base,
ethannicholasb3058bd2016-07-01 08:22:01 -07001798 swizzle.fComponents[0], out);
1799 } else {
1800 this->writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) count, out);
ethannicholasd598f792016-07-25 10:08:54 -07001801 this->writeWord(this->getType(swizzle.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001802 this->writeWord(result, out);
1803 this->writeWord(base, out);
1804 this->writeWord(base, out);
1805 for (int component : swizzle.fComponents) {
1806 this->writeWord(component, out);
1807 }
1808 }
1809 return result;
1810}
1811
1812SpvId SPIRVCodeGenerator::writeBinaryOperation(const Type& resultType,
1813 const Type& operandType, SpvId lhs,
1814 SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt,
1815 SpvOp_ ifUInt, SpvOp_ ifBool, std::ostream& out) {
1816 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001817 if (is_float(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001818 this->writeInstruction(ifFloat, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001819 } else if (is_signed(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001820 this->writeInstruction(ifInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001821 } else if (is_unsigned(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001822 this->writeInstruction(ifUInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001823 } else if (operandType == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001824 this->writeInstruction(ifBool, this->getType(resultType), result, lhs, rhs, out);
1825 } else {
1826 ABORT("invalid operandType: %s", operandType.description().c_str());
1827 }
1828 return result;
1829}
1830
1831bool is_assignment(Token::Kind op) {
1832 switch (op) {
1833 case Token::EQ: // fall through
1834 case Token::PLUSEQ: // fall through
1835 case Token::MINUSEQ: // fall through
1836 case Token::STAREQ: // fall through
1837 case Token::SLASHEQ: // fall through
1838 case Token::PERCENTEQ: // fall through
1839 case Token::SHLEQ: // fall through
1840 case Token::SHREQ: // fall through
1841 case Token::BITWISEOREQ: // fall through
1842 case Token::BITWISEXOREQ: // fall through
1843 case Token::BITWISEANDEQ: // fall through
1844 case Token::LOGICALOREQ: // fall through
1845 case Token::LOGICALXOREQ: // fall through
1846 case Token::LOGICALANDEQ:
1847 return true;
1848 default:
1849 return false;
1850 }
1851}
1852
ethannicholasf789b382016-08-03 12:43:36 -07001853SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001854 // handle cases where we don't necessarily evaluate both LHS and RHS
1855 switch (b.fOperator) {
1856 case Token::EQ: {
1857 SpvId rhs = this->writeExpression(*b.fRight, out);
1858 this->getLValue(*b.fLeft, out)->store(rhs, out);
1859 return rhs;
1860 }
1861 case Token::LOGICALAND:
1862 return this->writeLogicalAnd(b, out);
1863 case Token::LOGICALOR:
1864 return this->writeLogicalOr(b, out);
1865 default:
1866 break;
1867 }
1868
1869 // "normal" operators
ethannicholasd598f792016-07-25 10:08:54 -07001870 const Type& resultType = b.fType;
ethannicholasb3058bd2016-07-01 08:22:01 -07001871 std::unique_ptr<LValue> lvalue;
1872 SpvId lhs;
1873 if (is_assignment(b.fOperator)) {
1874 lvalue = this->getLValue(*b.fLeft, out);
1875 lhs = lvalue->load(out);
1876 } else {
1877 lvalue = nullptr;
1878 lhs = this->writeExpression(*b.fLeft, out);
1879 }
1880 SpvId rhs = this->writeExpression(*b.fRight, out);
1881 // component type we are operating on: float, int, uint
1882 const Type* operandType;
1883 // IR allows mismatched types in expressions (e.g. vec2 * float), but they need special handling
1884 // in SPIR-V
1885 if (b.fLeft->fType != b.fRight->fType) {
ethannicholasd598f792016-07-25 10:08:54 -07001886 if (b.fLeft->fType.kind() == Type::kVector_Kind &&
1887 b.fRight->fType.isNumber()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001888 // promote number to vector
1889 SpvId vec = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001890 this->writeOpCode(SpvOpCompositeConstruct, 3 + b.fType.columns(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001891 this->writeWord(this->getType(resultType), out);
1892 this->writeWord(vec, out);
1893 for (int i = 0; i < resultType.columns(); i++) {
1894 this->writeWord(rhs, out);
1895 }
1896 rhs = vec;
ethannicholasd598f792016-07-25 10:08:54 -07001897 operandType = &b.fRight->fType;
1898 } else if (b.fRight->fType.kind() == Type::kVector_Kind &&
1899 b.fLeft->fType.isNumber()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001900 // promote number to vector
1901 SpvId vec = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001902 this->writeOpCode(SpvOpCompositeConstruct, 3 + b.fType.columns(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001903 this->writeWord(this->getType(resultType), out);
1904 this->writeWord(vec, out);
1905 for (int i = 0; i < resultType.columns(); i++) {
1906 this->writeWord(lhs, out);
1907 }
1908 lhs = vec;
1909 ASSERT(!lvalue);
ethannicholasd598f792016-07-25 10:08:54 -07001910 operandType = &b.fLeft->fType;
1911 } else if (b.fLeft->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001912 SpvOp_ op;
ethannicholasd598f792016-07-25 10:08:54 -07001913 if (b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001914 op = SpvOpMatrixTimesMatrix;
ethannicholasd598f792016-07-25 10:08:54 -07001915 } else if (b.fRight->fType.kind() == Type::kVector_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001916 op = SpvOpMatrixTimesVector;
1917 } else {
ethannicholasd598f792016-07-25 10:08:54 -07001918 ASSERT(b.fRight->fType.kind() == Type::kScalar_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001919 op = SpvOpMatrixTimesScalar;
1920 }
1921 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001922 this->writeInstruction(op, this->getType(b.fType), result, lhs, rhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001923 if (b.fOperator == Token::STAREQ) {
1924 lvalue->store(result, out);
1925 } else {
1926 ASSERT(b.fOperator == Token::STAR);
1927 }
1928 return result;
ethannicholasd598f792016-07-25 10:08:54 -07001929 } else if (b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001930 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001931 if (b.fLeft->fType.kind() == Type::kVector_Kind) {
1932 this->writeInstruction(SpvOpVectorTimesMatrix, this->getType(b.fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07001933 lhs, rhs, out);
1934 } else {
ethannicholasd598f792016-07-25 10:08:54 -07001935 ASSERT(b.fLeft->fType.kind() == Type::kScalar_Kind);
1936 this->writeInstruction(SpvOpMatrixTimesScalar, this->getType(b.fType), result, rhs,
ethannicholasb3058bd2016-07-01 08:22:01 -07001937 lhs, out);
1938 }
1939 if (b.fOperator == Token::STAREQ) {
1940 lvalue->store(result, out);
1941 } else {
1942 ASSERT(b.fOperator == Token::STAR);
1943 }
1944 return result;
1945 } else {
1946 ABORT("unsupported binary expression: %s", b.description().c_str());
1947 }
1948 } else {
ethannicholasd598f792016-07-25 10:08:54 -07001949 operandType = &b.fLeft->fType;
1950 ASSERT(*operandType == b.fRight->fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001951 }
1952 switch (b.fOperator) {
1953 case Token::EQEQ:
ethannicholasd598f792016-07-25 10:08:54 -07001954 ASSERT(resultType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07001955 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdEqual,
1956 SpvOpIEqual, SpvOpIEqual, SpvOpLogicalEqual, out);
1957 case Token::NEQ:
ethannicholasd598f792016-07-25 10:08:54 -07001958 ASSERT(resultType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07001959 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdNotEqual,
1960 SpvOpINotEqual, SpvOpINotEqual, SpvOpLogicalNotEqual,
1961 out);
1962 case Token::GT:
ethannicholasd598f792016-07-25 10:08:54 -07001963 ASSERT(resultType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07001964 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
1965 SpvOpFOrdGreaterThan, SpvOpSGreaterThan,
1966 SpvOpUGreaterThan, SpvOpUndef, out);
1967 case Token::LT:
ethannicholasd598f792016-07-25 10:08:54 -07001968 ASSERT(resultType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07001969 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdLessThan,
1970 SpvOpSLessThan, SpvOpULessThan, SpvOpUndef, out);
1971 case Token::GTEQ:
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,
1974 SpvOpFOrdGreaterThanEqual, SpvOpSGreaterThanEqual,
1975 SpvOpUGreaterThanEqual, SpvOpUndef, out);
1976 case Token::LTEQ:
ethannicholasd598f792016-07-25 10:08:54 -07001977 ASSERT(resultType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07001978 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
1979 SpvOpFOrdLessThanEqual, SpvOpSLessThanEqual,
1980 SpvOpULessThanEqual, SpvOpUndef, out);
1981 case Token::PLUS:
1982 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
1983 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
1984 case Token::MINUS:
1985 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
1986 SpvOpISub, SpvOpISub, SpvOpUndef, out);
1987 case Token::STAR:
ethannicholasd598f792016-07-25 10:08:54 -07001988 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
1989 b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001990 // matrix multiply
1991 SpvId result = this->nextId();
1992 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
1993 lhs, rhs, out);
1994 return result;
1995 }
1996 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
1997 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
1998 case Token::SLASH:
1999 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
2000 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
2001 case Token::PLUSEQ: {
2002 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
2003 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2004 ASSERT(lvalue);
2005 lvalue->store(result, out);
2006 return result;
2007 }
2008 case Token::MINUSEQ: {
2009 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
2010 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2011 ASSERT(lvalue);
2012 lvalue->store(result, out);
2013 return result;
2014 }
2015 case Token::STAREQ: {
ethannicholasd598f792016-07-25 10:08:54 -07002016 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
2017 b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002018 // matrix multiply
2019 SpvId result = this->nextId();
2020 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2021 lhs, rhs, out);
2022 ASSERT(lvalue);
2023 lvalue->store(result, out);
2024 return result;
2025 }
2026 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
2027 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
2028 ASSERT(lvalue);
2029 lvalue->store(result, out);
2030 return result;
2031 }
2032 case Token::SLASHEQ: {
2033 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
2034 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
2035 ASSERT(lvalue);
2036 lvalue->store(result, out);
2037 return result;
2038 }
2039 default:
2040 // FIXME: missing support for some operators (bitwise, &&=, ||=, shift...)
2041 ABORT("unsupported binary expression: %s", b.description().c_str());
2042 }
2043}
2044
ethannicholasf789b382016-08-03 12:43:36 -07002045SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002046 ASSERT(a.fOperator == Token::LOGICALAND);
ethannicholasd598f792016-07-25 10:08:54 -07002047 BoolLiteral falseLiteral(fContext, Position(), false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002048 SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
2049 SpvId lhs = this->writeExpression(*a.fLeft, out);
2050 SpvId rhsLabel = this->nextId();
2051 SpvId end = this->nextId();
2052 SpvId lhsBlock = fCurrentBlock;
2053 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2054 this->writeInstruction(SpvOpBranchConditional, lhs, rhsLabel, end, out);
2055 this->writeLabel(rhsLabel, out);
2056 SpvId rhs = this->writeExpression(*a.fRight, out);
2057 SpvId rhsBlock = fCurrentBlock;
2058 this->writeInstruction(SpvOpBranch, end, out);
2059 this->writeLabel(end, out);
2060 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002061 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, falseConstant,
2062 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002063 return result;
2064}
2065
ethannicholasf789b382016-08-03 12:43:36 -07002066SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002067 ASSERT(o.fOperator == Token::LOGICALOR);
ethannicholasd598f792016-07-25 10:08:54 -07002068 BoolLiteral trueLiteral(fContext, Position(), true);
ethannicholasb3058bd2016-07-01 08:22:01 -07002069 SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
2070 SpvId lhs = this->writeExpression(*o.fLeft, out);
2071 SpvId rhsLabel = this->nextId();
2072 SpvId end = this->nextId();
2073 SpvId lhsBlock = fCurrentBlock;
2074 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2075 this->writeInstruction(SpvOpBranchConditional, lhs, end, rhsLabel, out);
2076 this->writeLabel(rhsLabel, out);
2077 SpvId rhs = this->writeExpression(*o.fRight, out);
2078 SpvId rhsBlock = fCurrentBlock;
2079 this->writeInstruction(SpvOpBranch, end, out);
2080 this->writeLabel(end, out);
2081 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002082 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, trueConstant,
2083 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002084 return result;
2085}
2086
ethannicholasf789b382016-08-03 12:43:36 -07002087SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002088 SpvId test = this->writeExpression(*t.fTest, out);
2089 if (t.fIfTrue->isConstant() && t.fIfFalse->isConstant()) {
2090 // both true and false are constants, can just use OpSelect
2091 SpvId result = this->nextId();
2092 SpvId trueId = this->writeExpression(*t.fIfTrue, out);
2093 SpvId falseId = this->writeExpression(*t.fIfFalse, out);
ethannicholasd598f792016-07-25 10:08:54 -07002094 this->writeInstruction(SpvOpSelect, this->getType(t.fType), result, test, trueId, falseId,
ethannicholasb3058bd2016-07-01 08:22:01 -07002095 out);
2096 return result;
2097 }
2098 // was originally using OpPhi to choose the result, but for some reason that is crashing on
2099 // Adreno. Switched to storing the result in a temp variable as glslang does.
2100 SpvId var = this->nextId();
2101 this->writeInstruction(SpvOpVariable, this->getPointerType(t.fType, SpvStorageClassFunction),
ethannicholasd598f792016-07-25 10:08:54 -07002102 var, SpvStorageClassFunction, fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002103 SpvId trueLabel = this->nextId();
2104 SpvId falseLabel = this->nextId();
2105 SpvId end = this->nextId();
2106 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2107 this->writeInstruction(SpvOpBranchConditional, test, trueLabel, falseLabel, out);
2108 this->writeLabel(trueLabel, out);
2109 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfTrue, out), out);
2110 this->writeInstruction(SpvOpBranch, end, out);
2111 this->writeLabel(falseLabel, out);
2112 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfFalse, out), out);
2113 this->writeInstruction(SpvOpBranch, end, out);
2114 this->writeLabel(end, out);
2115 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002116 this->writeInstruction(SpvOpLoad, this->getType(t.fType), result, var, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002117 return result;
2118}
2119
ethannicholasd598f792016-07-25 10:08:54 -07002120std::unique_ptr<Expression> create_literal_1(const Context& context, const Type& type) {
2121 if (type == *context.fInt_Type) {
2122 return std::unique_ptr<Expression>(new IntLiteral(context, Position(), 1));
ethannicholasb3058bd2016-07-01 08:22:01 -07002123 }
ethannicholasd598f792016-07-25 10:08:54 -07002124 else if (type == *context.fFloat_Type) {
2125 return std::unique_ptr<Expression>(new FloatLiteral(context, Position(), 1.0));
ethannicholasb3058bd2016-07-01 08:22:01 -07002126 } else {
2127 ABORT("math is unsupported on type '%s'")
2128 }
2129}
2130
ethannicholasf789b382016-08-03 12:43:36 -07002131SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002132 if (p.fOperator == Token::MINUS) {
2133 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002134 SpvId typeId = this->getType(p.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07002135 SpvId expr = this->writeExpression(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002136 if (is_float(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002137 this->writeInstruction(SpvOpFNegate, typeId, result, expr, out);
ethannicholasd598f792016-07-25 10:08:54 -07002138 } else if (is_signed(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002139 this->writeInstruction(SpvOpSNegate, typeId, result, expr, out);
2140 } else {
2141 ABORT("unsupported prefix expression %s", p.description().c_str());
2142 };
2143 return result;
2144 }
2145 switch (p.fOperator) {
2146 case Token::PLUS:
2147 return this->writeExpression(*p.fOperand, out);
2148 case Token::PLUSPLUS: {
2149 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002150 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
2151 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
ethannicholasb3058bd2016-07-01 08:22:01 -07002152 SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef,
2153 out);
2154 lv->store(result, out);
2155 return result;
2156 }
2157 case Token::MINUSMINUS: {
2158 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002159 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
2160 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
ethannicholasb3058bd2016-07-01 08:22:01 -07002161 SpvOpFSub, SpvOpISub, SpvOpISub, SpvOpUndef,
2162 out);
2163 lv->store(result, out);
2164 return result;
2165 }
ethannicholasccb1dd82016-10-11 08:47:04 -07002166 case Token::LOGICALNOT: {
ethannicholasd598f792016-07-25 10:08:54 -07002167 ASSERT(p.fOperand->fType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002168 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002169 this->writeInstruction(SpvOpLogicalNot, this->getType(p.fOperand->fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002170 this->writeExpression(*p.fOperand, out), out);
2171 return result;
2172 }
ethannicholasccb1dd82016-10-11 08:47:04 -07002173 case Token::BITWISENOT: {
2174 SpvId result = this->nextId();
2175 this->writeInstruction(SpvOpNot, this->getType(p.fOperand->fType), result,
2176 this->writeExpression(*p.fOperand, out), out);
2177 return result;
2178 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002179 default:
2180 ABORT("unsupported prefix expression: %s", p.description().c_str());
2181 }
2182}
2183
ethannicholasf789b382016-08-03 12:43:36 -07002184SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002185 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
2186 SpvId result = lv->load(out);
ethannicholasd598f792016-07-25 10:08:54 -07002187 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002188 switch (p.fOperator) {
2189 case Token::PLUSPLUS: {
ethannicholasd598f792016-07-25 10:08:54 -07002190 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002191 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2192 lv->store(temp, out);
2193 return result;
2194 }
2195 case Token::MINUSMINUS: {
ethannicholasd598f792016-07-25 10:08:54 -07002196 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002197 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2198 lv->store(temp, out);
2199 return result;
2200 }
2201 default:
2202 ABORT("unsupported postfix expression %s", p.description().c_str());
2203 }
2204}
2205
ethannicholasf789b382016-08-03 12:43:36 -07002206SpvId SPIRVCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002207 if (b.fValue) {
2208 if (fBoolTrue == 0) {
2209 fBoolTrue = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002210 this->writeInstruction(SpvOpConstantTrue, this->getType(b.fType), fBoolTrue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002211 fConstantBuffer);
2212 }
2213 return fBoolTrue;
2214 } else {
2215 if (fBoolFalse == 0) {
2216 fBoolFalse = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002217 this->writeInstruction(SpvOpConstantFalse, this->getType(b.fType), fBoolFalse,
ethannicholasb3058bd2016-07-01 08:22:01 -07002218 fConstantBuffer);
2219 }
2220 return fBoolFalse;
2221 }
2222}
2223
ethannicholasf789b382016-08-03 12:43:36 -07002224SpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) {
ethannicholasd598f792016-07-25 10:08:54 -07002225 if (i.fType == *fContext.fInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002226 auto entry = fIntConstants.find(i.fValue);
2227 if (entry == fIntConstants.end()) {
2228 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002229 this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002230 fConstantBuffer);
2231 fIntConstants[i.fValue] = result;
2232 return result;
2233 }
2234 return entry->second;
2235 } else {
ethannicholasd598f792016-07-25 10:08:54 -07002236 ASSERT(i.fType == *fContext.fUInt_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002237 auto entry = fUIntConstants.find(i.fValue);
2238 if (entry == fUIntConstants.end()) {
2239 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002240 this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002241 fConstantBuffer);
2242 fUIntConstants[i.fValue] = result;
2243 return result;
2244 }
2245 return entry->second;
2246 }
2247}
2248
ethannicholasf789b382016-08-03 12:43:36 -07002249SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
ethannicholasd598f792016-07-25 10:08:54 -07002250 if (f.fType == *fContext.fFloat_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002251 float value = (float) f.fValue;
2252 auto entry = fFloatConstants.find(value);
2253 if (entry == fFloatConstants.end()) {
2254 SpvId result = this->nextId();
2255 uint32_t bits;
2256 ASSERT(sizeof(bits) == sizeof(value));
2257 memcpy(&bits, &value, sizeof(bits));
ethannicholasd598f792016-07-25 10:08:54 -07002258 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result, bits,
ethannicholasb3058bd2016-07-01 08:22:01 -07002259 fConstantBuffer);
2260 fFloatConstants[value] = result;
2261 return result;
2262 }
2263 return entry->second;
2264 } else {
ethannicholasd598f792016-07-25 10:08:54 -07002265 ASSERT(f.fType == *fContext.fDouble_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002266 auto entry = fDoubleConstants.find(f.fValue);
2267 if (entry == fDoubleConstants.end()) {
2268 SpvId result = this->nextId();
2269 uint64_t bits;
2270 ASSERT(sizeof(bits) == sizeof(f.fValue));
2271 memcpy(&bits, &f.fValue, sizeof(bits));
ethannicholasd598f792016-07-25 10:08:54 -07002272 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002273 bits & 0xffffffff, bits >> 32, fConstantBuffer);
2274 fDoubleConstants[f.fValue] = result;
2275 return result;
2276 }
2277 return entry->second;
2278 }
2279}
2280
ethannicholasd598f792016-07-25 10:08:54 -07002281SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, std::ostream& out) {
2282 SpvId result = fFunctionMap[&f];
2283 this->writeInstruction(SpvOpFunction, this->getType(f.fReturnType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002284 SpvFunctionControlMaskNone, this->getFunctionType(f), out);
ethannicholasd598f792016-07-25 10:08:54 -07002285 this->writeInstruction(SpvOpName, result, f.fName.c_str(), fNameBuffer);
2286 for (size_t i = 0; i < f.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002287 SpvId id = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002288 fVariableMap[f.fParameters[i]] = id;
ethannicholasb3058bd2016-07-01 08:22:01 -07002289 SpvId type;
ethannicholasd598f792016-07-25 10:08:54 -07002290 type = this->getPointerType(f.fParameters[i]->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002291 this->writeInstruction(SpvOpFunctionParameter, type, id, out);
2292 }
2293 return result;
2294}
2295
ethannicholasd598f792016-07-25 10:08:54 -07002296SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002297 SpvId result = this->writeFunctionStart(f.fDeclaration, out);
2298 this->writeLabel(this->nextId(), out);
ethannicholasd598f792016-07-25 10:08:54 -07002299 if (f.fDeclaration.fName == "main") {
ethannicholasb3058bd2016-07-01 08:22:01 -07002300 out << fGlobalInitializersBuffer.str();
2301 }
2302 std::stringstream bodyBuffer;
2303 this->writeBlock(*f.fBody, bodyBuffer);
2304 out << fVariableBuffer.str();
2305 fVariableBuffer.str("");
2306 out << bodyBuffer.str();
2307 if (fCurrentBlock) {
2308 this->writeInstruction(SpvOpReturn, out);
2309 }
2310 this->writeInstruction(SpvOpFunctionEnd, out);
2311 return result;
2312}
2313
2314void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target) {
2315 if (layout.fLocation >= 0) {
2316 this->writeInstruction(SpvOpDecorate, target, SpvDecorationLocation, layout.fLocation,
2317 fDecorationBuffer);
2318 }
2319 if (layout.fBinding >= 0) {
2320 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBinding, layout.fBinding,
2321 fDecorationBuffer);
2322 }
2323 if (layout.fIndex >= 0) {
2324 this->writeInstruction(SpvOpDecorate, target, SpvDecorationIndex, layout.fIndex,
2325 fDecorationBuffer);
2326 }
2327 if (layout.fSet >= 0) {
2328 this->writeInstruction(SpvOpDecorate, target, SpvDecorationDescriptorSet, layout.fSet,
2329 fDecorationBuffer);
2330 }
ethannicholasccb1dd82016-10-11 08:47:04 -07002331 if (layout.fBuiltin >= 0 && layout.fBuiltin != SK_FRAGCOLOR_BUILTIN) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002332 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBuiltIn, layout.fBuiltin,
2333 fDecorationBuffer);
2334 }
2335}
2336
2337void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int member) {
2338 if (layout.fLocation >= 0) {
2339 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationLocation,
2340 layout.fLocation, fDecorationBuffer);
2341 }
2342 if (layout.fBinding >= 0) {
2343 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBinding,
2344 layout.fBinding, fDecorationBuffer);
2345 }
2346 if (layout.fIndex >= 0) {
2347 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationIndex,
2348 layout.fIndex, fDecorationBuffer);
2349 }
2350 if (layout.fSet >= 0) {
2351 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationDescriptorSet,
2352 layout.fSet, fDecorationBuffer);
2353 }
2354 if (layout.fBuiltin >= 0) {
2355 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBuiltIn,
2356 layout.fBuiltin, fDecorationBuffer);
2357 }
2358}
2359
ethannicholasf789b382016-08-03 12:43:36 -07002360SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
ethannicholasd598f792016-07-25 10:08:54 -07002361 SpvId type = this->getType(intf.fVariable.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07002362 SpvId result = this->nextId();
2363 this->writeInstruction(SpvOpDecorate, type, SpvDecorationBlock, fDecorationBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07002364 SpvStorageClass_ storageClass = get_storage_class(intf.fVariable.fModifiers);
ethannicholasb3058bd2016-07-01 08:22:01 -07002365 SpvId ptrType = this->nextId();
2366 this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, type, fConstantBuffer);
2367 this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07002368 this->writeLayout(intf.fVariable.fModifiers.fLayout, result);
2369 fVariableMap[&intf.fVariable] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002370 return result;
2371}
2372
ethannicholasccb1dd82016-10-11 08:47:04 -07002373#define BUILTIN_IGNORE 9999
2374void SPIRVCodeGenerator::writeGlobalVars(Program::Kind kind, const VarDeclarations& decl,
2375 std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002376 for (size_t i = 0; i < decl.fVars.size(); i++) {
ethannicholas14fe8cc2016-09-07 13:37:16 -07002377 const VarDeclaration& varDecl = decl.fVars[i];
2378 const Variable* var = varDecl.fVar;
ethannicholasccb1dd82016-10-11 08:47:04 -07002379 if (var->fModifiers.fLayout.fBuiltin == BUILTIN_IGNORE) {
2380 continue;
2381 }
2382 if (var->fModifiers.fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN &&
2383 kind != Program::kFragment_Kind) {
2384 continue;
2385 }
ethannicholas14fe8cc2016-09-07 13:37:16 -07002386 if (!var->fIsReadFrom && !var->fIsWrittenTo &&
2387 !(var->fModifiers.fFlags & (Modifiers::kIn_Flag |
2388 Modifiers::kOut_Flag |
2389 Modifiers::kUniform_Flag))) {
ethannicholasd598f792016-07-25 10:08:54 -07002390 // variable is dead and not an input / output var (the Vulkan debug layers complain if
2391 // we elide an interface var, even if it's dead)
ethannicholasb3058bd2016-07-01 08:22:01 -07002392 continue;
2393 }
2394 SpvStorageClass_ storageClass;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002395 if (var->fModifiers.fFlags & Modifiers::kIn_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002396 storageClass = SpvStorageClassInput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002397 } else if (var->fModifiers.fFlags & Modifiers::kOut_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002398 storageClass = SpvStorageClassOutput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002399 } else if (var->fModifiers.fFlags & Modifiers::kUniform_Flag) {
2400 if (var->fType.kind() == Type::kSampler_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002401 storageClass = SpvStorageClassUniformConstant;
2402 } else {
2403 storageClass = SpvStorageClassUniform;
2404 }
2405 } else {
2406 storageClass = SpvStorageClassPrivate;
2407 }
2408 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002409 fVariableMap[var] = id;
2410 SpvId type = this->getPointerType(var->fType, storageClass);
ethannicholasb3058bd2016-07-01 08:22:01 -07002411 this->writeInstruction(SpvOpVariable, type, id, storageClass, fConstantBuffer);
ethannicholas14fe8cc2016-09-07 13:37:16 -07002412 this->writeInstruction(SpvOpName, id, var->fName.c_str(), fNameBuffer);
2413 if (var->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002414 this->writeInstruction(SpvOpMemberDecorate, id, (SpvId) i, SpvDecorationColMajor,
2415 fDecorationBuffer);
2416 this->writeInstruction(SpvOpMemberDecorate, id, (SpvId) i, SpvDecorationMatrixStride,
ethannicholas14fe8cc2016-09-07 13:37:16 -07002417 (SpvId) var->fType.stride(), fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002418 }
ethannicholas14fe8cc2016-09-07 13:37:16 -07002419 if (varDecl.fValue) {
ethannicholasf789b382016-08-03 12:43:36 -07002420 ASSERT(!fCurrentBlock);
2421 fCurrentBlock = -1;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002422 SpvId value = this->writeExpression(*varDecl.fValue, fGlobalInitializersBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002423 this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
ethannicholasf789b382016-08-03 12:43:36 -07002424 fCurrentBlock = 0;
ethannicholasb3058bd2016-07-01 08:22:01 -07002425 }
ethannicholas14fe8cc2016-09-07 13:37:16 -07002426 this->writeLayout(var->fModifiers.fLayout, id);
ethannicholasb3058bd2016-07-01 08:22:01 -07002427 }
2428}
2429
ethannicholas14fe8cc2016-09-07 13:37:16 -07002430void SPIRVCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, std::ostream& out) {
2431 for (const auto& varDecl : decl.fVars) {
2432 const Variable* var = varDecl.fVar;
ethannicholasb3058bd2016-07-01 08:22:01 -07002433 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002434 fVariableMap[var] = id;
2435 SpvId type = this->getPointerType(var->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002436 this->writeInstruction(SpvOpVariable, type, id, SpvStorageClassFunction, fVariableBuffer);
ethannicholas14fe8cc2016-09-07 13:37:16 -07002437 this->writeInstruction(SpvOpName, id, var->fName.c_str(), fNameBuffer);
2438 if (varDecl.fValue) {
2439 SpvId value = this->writeExpression(*varDecl.fValue, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002440 this->writeInstruction(SpvOpStore, id, value, out);
2441 }
2442 }
2443}
2444
ethannicholasf789b382016-08-03 12:43:36 -07002445void SPIRVCodeGenerator::writeStatement(const Statement& s, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002446 switch (s.fKind) {
2447 case Statement::kBlock_Kind:
2448 this->writeBlock((Block&) s, out);
2449 break;
2450 case Statement::kExpression_Kind:
2451 this->writeExpression(*((ExpressionStatement&) s).fExpression, out);
2452 break;
2453 case Statement::kReturn_Kind:
2454 this->writeReturnStatement((ReturnStatement&) s, out);
2455 break;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002456 case Statement::kVarDeclarations_Kind:
2457 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002458 break;
2459 case Statement::kIf_Kind:
2460 this->writeIfStatement((IfStatement&) s, out);
2461 break;
2462 case Statement::kFor_Kind:
2463 this->writeForStatement((ForStatement&) s, out);
2464 break;
2465 case Statement::kBreak_Kind:
2466 this->writeInstruction(SpvOpBranch, fBreakTarget.top(), out);
2467 break;
2468 case Statement::kContinue_Kind:
2469 this->writeInstruction(SpvOpBranch, fContinueTarget.top(), out);
2470 break;
2471 case Statement::kDiscard_Kind:
2472 this->writeInstruction(SpvOpKill, out);
2473 break;
2474 default:
2475 ABORT("unsupported statement: %s", s.description().c_str());
2476 }
2477}
2478
ethannicholasf789b382016-08-03 12:43:36 -07002479void SPIRVCodeGenerator::writeBlock(const Block& b, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002480 for (size_t i = 0; i < b.fStatements.size(); i++) {
2481 this->writeStatement(*b.fStatements[i], out);
2482 }
2483}
2484
ethannicholasf789b382016-08-03 12:43:36 -07002485void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002486 SpvId test = this->writeExpression(*stmt.fTest, out);
2487 SpvId ifTrue = this->nextId();
2488 SpvId ifFalse = this->nextId();
2489 if (stmt.fIfFalse) {
2490 SpvId end = this->nextId();
2491 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2492 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2493 this->writeLabel(ifTrue, out);
2494 this->writeStatement(*stmt.fIfTrue, out);
2495 if (fCurrentBlock) {
2496 this->writeInstruction(SpvOpBranch, end, out);
2497 }
2498 this->writeLabel(ifFalse, out);
2499 this->writeStatement(*stmt.fIfFalse, out);
2500 if (fCurrentBlock) {
2501 this->writeInstruction(SpvOpBranch, end, out);
2502 }
2503 this->writeLabel(end, out);
2504 } else {
2505 this->writeInstruction(SpvOpSelectionMerge, ifFalse, SpvSelectionControlMaskNone, out);
2506 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2507 this->writeLabel(ifTrue, out);
2508 this->writeStatement(*stmt.fIfTrue, out);
2509 if (fCurrentBlock) {
2510 this->writeInstruction(SpvOpBranch, ifFalse, out);
2511 }
2512 this->writeLabel(ifFalse, out);
2513 }
2514}
2515
ethannicholasf789b382016-08-03 12:43:36 -07002516void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002517 if (f.fInitializer) {
2518 this->writeStatement(*f.fInitializer, out);
2519 }
2520 SpvId header = this->nextId();
2521 SpvId start = this->nextId();
2522 SpvId body = this->nextId();
2523 SpvId next = this->nextId();
2524 fContinueTarget.push(next);
2525 SpvId end = this->nextId();
2526 fBreakTarget.push(end);
2527 this->writeInstruction(SpvOpBranch, header, out);
2528 this->writeLabel(header, out);
2529 this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
ethannicholasf789b382016-08-03 12:43:36 -07002530 this->writeInstruction(SpvOpBranch, start, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002531 this->writeLabel(start, out);
2532 SpvId test = this->writeExpression(*f.fTest, out);
2533 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2534 this->writeLabel(body, out);
2535 this->writeStatement(*f.fStatement, out);
2536 if (fCurrentBlock) {
2537 this->writeInstruction(SpvOpBranch, next, out);
2538 }
2539 this->writeLabel(next, out);
2540 if (f.fNext) {
2541 this->writeExpression(*f.fNext, out);
2542 }
2543 this->writeInstruction(SpvOpBranch, header, out);
2544 this->writeLabel(end, out);
2545 fBreakTarget.pop();
2546 fContinueTarget.pop();
2547}
2548
ethannicholasf789b382016-08-03 12:43:36 -07002549void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002550 if (r.fExpression) {
2551 this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.fExpression, out),
2552 out);
2553 } else {
2554 this->writeInstruction(SpvOpReturn, out);
2555 }
2556}
2557
ethannicholasf789b382016-08-03 12:43:36 -07002558void SPIRVCodeGenerator::writeInstructions(const Program& program, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002559 fGLSLExtendedInstructions = this->nextId();
2560 std::stringstream body;
2561 std::vector<SpvId> interfaceVars;
2562 // assign IDs to functions
2563 for (size_t i = 0; i < program.fElements.size(); i++) {
2564 if (program.fElements[i]->fKind == ProgramElement::kFunction_Kind) {
2565 FunctionDefinition& f = (FunctionDefinition&) *program.fElements[i];
ethannicholasd598f792016-07-25 10:08:54 -07002566 fFunctionMap[&f.fDeclaration] = this->nextId();
ethannicholasb3058bd2016-07-01 08:22:01 -07002567 }
2568 }
2569 for (size_t i = 0; i < program.fElements.size(); i++) {
2570 if (program.fElements[i]->fKind == ProgramElement::kInterfaceBlock_Kind) {
2571 InterfaceBlock& intf = (InterfaceBlock&) *program.fElements[i];
2572 SpvId id = this->writeInterfaceBlock(intf);
ethannicholasd598f792016-07-25 10:08:54 -07002573 if ((intf.fVariable.fModifiers.fFlags & Modifiers::kIn_Flag) ||
2574 (intf.fVariable.fModifiers.fFlags & Modifiers::kOut_Flag)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002575 interfaceVars.push_back(id);
2576 }
2577 }
2578 }
2579 for (size_t i = 0; i < program.fElements.size(); i++) {
2580 if (program.fElements[i]->fKind == ProgramElement::kVar_Kind) {
ethannicholasccb1dd82016-10-11 08:47:04 -07002581 this->writeGlobalVars(program.fKind, ((VarDeclarations&) *program.fElements[i]),
2582 body);
ethannicholasb3058bd2016-07-01 08:22:01 -07002583 }
2584 }
2585 for (size_t i = 0; i < program.fElements.size(); i++) {
2586 if (program.fElements[i]->fKind == ProgramElement::kFunction_Kind) {
2587 this->writeFunction(((FunctionDefinition&) *program.fElements[i]), body);
2588 }
2589 }
ethannicholasd598f792016-07-25 10:08:54 -07002590 const FunctionDeclaration* main = nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -07002591 for (auto entry : fFunctionMap) {
ethannicholasf789b382016-08-03 12:43:36 -07002592 if (entry.first->fName == "main") {
ethannicholasb3058bd2016-07-01 08:22:01 -07002593 main = entry.first;
2594 }
2595 }
2596 ASSERT(main);
2597 for (auto entry : fVariableMap) {
ethannicholasd598f792016-07-25 10:08:54 -07002598 const Variable* var = entry.first;
ethannicholasb3058bd2016-07-01 08:22:01 -07002599 if (var->fStorage == Variable::kGlobal_Storage &&
2600 ((var->fModifiers.fFlags & Modifiers::kIn_Flag) ||
2601 (var->fModifiers.fFlags & Modifiers::kOut_Flag))) {
2602 interfaceVars.push_back(entry.second);
2603 }
2604 }
2605 this->writeCapabilities(out);
2606 this->writeInstruction(SpvOpExtInstImport, fGLSLExtendedInstructions, "GLSL.std.450", out);
2607 this->writeInstruction(SpvOpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450, out);
2608 this->writeOpCode(SpvOpEntryPoint, (SpvId) (3 + (strlen(main->fName.c_str()) + 4) / 4) +
2609 (int32_t) interfaceVars.size(), out);
2610 switch (program.fKind) {
2611 case Program::kVertex_Kind:
2612 this->writeWord(SpvExecutionModelVertex, out);
2613 break;
2614 case Program::kFragment_Kind:
2615 this->writeWord(SpvExecutionModelFragment, out);
2616 break;
2617 }
2618 this->writeWord(fFunctionMap[main], out);
2619 this->writeString(main->fName.c_str(), out);
2620 for (int var : interfaceVars) {
2621 this->writeWord(var, out);
2622 }
2623 if (program.fKind == Program::kFragment_Kind) {
2624 this->writeInstruction(SpvOpExecutionMode,
2625 fFunctionMap[main],
2626 SpvExecutionModeOriginUpperLeft,
2627 out);
2628 }
2629 for (size_t i = 0; i < program.fElements.size(); i++) {
2630 if (program.fElements[i]->fKind == ProgramElement::kExtension_Kind) {
2631 this->writeInstruction(SpvOpSourceExtension,
2632 ((Extension&) *program.fElements[i]).fName.c_str(),
2633 out);
2634 }
2635 }
2636
2637 out << fNameBuffer.str();
2638 out << fDecorationBuffer.str();
2639 out << fConstantBuffer.str();
2640 out << fExternalFunctionsBuffer.str();
2641 out << body.str();
2642}
2643
ethannicholasf789b382016-08-03 12:43:36 -07002644void SPIRVCodeGenerator::generateCode(const Program& program, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002645 this->writeWord(SpvMagicNumber, out);
2646 this->writeWord(SpvVersion, out);
2647 this->writeWord(SKSL_MAGIC, out);
2648 std::stringstream buffer;
2649 this->writeInstructions(program, buffer);
2650 this->writeWord(fIdCount, out);
2651 this->writeWord(0, out); // reserved, always zero
2652 out << buffer.str();
2653}
2654
2655}