blob: efa41bfd1ad68ae3bddd1f370569e5c3b78cdfd9 [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"
18
19namespace SkSL {
20
21#define SPIRV_DEBUG 0
22
23static const int32_t SKSL_MAGIC = 0x0; // FIXME: we should probably register a magic number
24
25void SPIRVCodeGenerator::setupIntrinsics() {
26#define ALL_GLSL(x) std::make_tuple(kGLSL_STD_450_IntrinsicKind, GLSLstd450 ## x, GLSLstd450 ## x, \
27 GLSLstd450 ## x, GLSLstd450 ## x)
28#define BY_TYPE_GLSL(ifFloat, ifInt, ifUInt) std::make_tuple(kGLSL_STD_450_IntrinsicKind, \
29 GLSLstd450 ## ifFloat, \
30 GLSLstd450 ## ifInt, \
31 GLSLstd450 ## ifUInt, \
32 SpvOpUndef)
33#define SPECIAL(x) std::make_tuple(kSpecial_IntrinsicKind, k ## x ## _SpecialIntrinsic, \
34 k ## x ## _SpecialIntrinsic, k ## x ## _SpecialIntrinsic, \
35 k ## x ## _SpecialIntrinsic)
36 fIntrinsicMap["round"] = ALL_GLSL(Round);
37 fIntrinsicMap["roundEven"] = ALL_GLSL(RoundEven);
38 fIntrinsicMap["trunc"] = ALL_GLSL(Trunc);
39 fIntrinsicMap["abs"] = BY_TYPE_GLSL(FAbs, SAbs, SAbs);
40 fIntrinsicMap["sign"] = BY_TYPE_GLSL(FSign, SSign, SSign);
41 fIntrinsicMap["floor"] = ALL_GLSL(Floor);
42 fIntrinsicMap["ceil"] = ALL_GLSL(Ceil);
43 fIntrinsicMap["fract"] = ALL_GLSL(Fract);
44 fIntrinsicMap["radians"] = ALL_GLSL(Radians);
45 fIntrinsicMap["degrees"] = ALL_GLSL(Degrees);
46 fIntrinsicMap["sin"] = ALL_GLSL(Sin);
47 fIntrinsicMap["cos"] = ALL_GLSL(Cos);
48 fIntrinsicMap["tan"] = ALL_GLSL(Tan);
49 fIntrinsicMap["asin"] = ALL_GLSL(Asin);
50 fIntrinsicMap["acos"] = ALL_GLSL(Acos);
51 fIntrinsicMap["atan"] = SPECIAL(Atan);
52 fIntrinsicMap["sinh"] = ALL_GLSL(Sinh);
53 fIntrinsicMap["cosh"] = ALL_GLSL(Cosh);
54 fIntrinsicMap["tanh"] = ALL_GLSL(Tanh);
55 fIntrinsicMap["asinh"] = ALL_GLSL(Asinh);
56 fIntrinsicMap["acosh"] = ALL_GLSL(Acosh);
57 fIntrinsicMap["atanh"] = ALL_GLSL(Atanh);
58 fIntrinsicMap["pow"] = ALL_GLSL(Pow);
59 fIntrinsicMap["exp"] = ALL_GLSL(Exp);
60 fIntrinsicMap["log"] = ALL_GLSL(Log);
61 fIntrinsicMap["exp2"] = ALL_GLSL(Exp2);
62 fIntrinsicMap["log2"] = ALL_GLSL(Log2);
63 fIntrinsicMap["sqrt"] = ALL_GLSL(Sqrt);
64 fIntrinsicMap["inversesqrt"] = ALL_GLSL(InverseSqrt);
65 fIntrinsicMap["determinant"] = ALL_GLSL(Determinant);
66 fIntrinsicMap["matrixInverse"] = ALL_GLSL(MatrixInverse);
67 fIntrinsicMap["mod"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpFMod, SpvOpSMod,
68 SpvOpUMod, SpvOpUndef);
69 fIntrinsicMap["min"] = BY_TYPE_GLSL(FMin, SMin, UMin);
70 fIntrinsicMap["max"] = BY_TYPE_GLSL(FMax, SMax, UMax);
71 fIntrinsicMap["clamp"] = BY_TYPE_GLSL(FClamp, SClamp, UClamp);
72 fIntrinsicMap["dot"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDot, SpvOpUndef,
73 SpvOpUndef, SpvOpUndef);
74 fIntrinsicMap["mix"] = ALL_GLSL(FMix);
75 fIntrinsicMap["step"] = ALL_GLSL(Step);
76 fIntrinsicMap["smoothstep"] = ALL_GLSL(SmoothStep);
77 fIntrinsicMap["fma"] = ALL_GLSL(Fma);
78 fIntrinsicMap["frexp"] = ALL_GLSL(Frexp);
79 fIntrinsicMap["ldexp"] = ALL_GLSL(Ldexp);
80
81#define PACK(type) fIntrinsicMap["pack" #type] = ALL_GLSL(Pack ## type); \
82 fIntrinsicMap["unpack" #type] = ALL_GLSL(Unpack ## type)
83 PACK(Snorm4x8);
84 PACK(Unorm4x8);
85 PACK(Snorm2x16);
86 PACK(Unorm2x16);
87 PACK(Half2x16);
88 PACK(Double2x32);
89 fIntrinsicMap["length"] = ALL_GLSL(Length);
90 fIntrinsicMap["distance"] = ALL_GLSL(Distance);
91 fIntrinsicMap["cross"] = ALL_GLSL(Cross);
92 fIntrinsicMap["normalize"] = ALL_GLSL(Normalize);
93 fIntrinsicMap["faceForward"] = ALL_GLSL(FaceForward);
94 fIntrinsicMap["reflect"] = ALL_GLSL(Reflect);
95 fIntrinsicMap["refract"] = ALL_GLSL(Refract);
96 fIntrinsicMap["findLSB"] = ALL_GLSL(FindILsb);
97 fIntrinsicMap["findMSB"] = BY_TYPE_GLSL(FindSMsb, FindSMsb, FindUMsb);
98 fIntrinsicMap["dFdx"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdx, SpvOpUndef,
99 SpvOpUndef, SpvOpUndef);
100 fIntrinsicMap["dFdy"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdy, SpvOpUndef,
101 SpvOpUndef, SpvOpUndef);
102 fIntrinsicMap["dFdy"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdy, SpvOpUndef,
103 SpvOpUndef, SpvOpUndef);
104 fIntrinsicMap["texture"] = SPECIAL(Texture);
105 fIntrinsicMap["texture2D"] = SPECIAL(Texture2D);
106 fIntrinsicMap["textureProj"] = SPECIAL(TextureProj);
107
108 fIntrinsicMap["any"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
109 SpvOpUndef, SpvOpUndef, SpvOpAny);
110 fIntrinsicMap["all"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
111 SpvOpUndef, SpvOpUndef, SpvOpAll);
112 fIntrinsicMap["equal"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpFOrdEqual,
113 SpvOpIEqual, SpvOpIEqual,
114 SpvOpLogicalEqual);
115 fIntrinsicMap["notEqual"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpFOrdNotEqual,
116 SpvOpINotEqual, SpvOpINotEqual,
117 SpvOpLogicalNotEqual);
118 fIntrinsicMap["lessThan"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpSLessThan,
119 SpvOpULessThan, SpvOpFOrdLessThan,
120 SpvOpUndef);
121 fIntrinsicMap["lessThanEqual"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpSLessThanEqual,
122 SpvOpULessThanEqual, SpvOpFOrdLessThanEqual,
123 SpvOpUndef);
124 fIntrinsicMap["greaterThan"] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpSGreaterThan,
125 SpvOpUGreaterThan, SpvOpFOrdGreaterThan,
126 SpvOpUndef);
127 fIntrinsicMap["greaterThanEqual"] = std::make_tuple(kSPIRV_IntrinsicKind,
128 SpvOpSGreaterThanEqual,
129 SpvOpUGreaterThanEqual,
130 SpvOpFOrdGreaterThanEqual,
131 SpvOpUndef);
132
133// interpolateAt* not yet supported...
134}
135
136void SPIRVCodeGenerator::writeWord(int32_t word, std::ostream& out) {
137#if SPIRV_DEBUG
138 out << "(" << word << ") ";
139#else
140 out.write((const char*) &word, sizeof(word));
141#endif
142}
143
ethannicholasd598f792016-07-25 10:08:54 -0700144static bool is_float(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700145 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700146 return is_float(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700147 }
ethannicholasd598f792016-07-25 10:08:54 -0700148 return type == *context.fFloat_Type || type == *context.fDouble_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700149}
150
ethannicholasd598f792016-07-25 10:08:54 -0700151static bool is_signed(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700152 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700153 return is_signed(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700154 }
ethannicholasd598f792016-07-25 10:08:54 -0700155 return type == *context.fInt_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700156}
157
ethannicholasd598f792016-07-25 10:08:54 -0700158static bool is_unsigned(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700159 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700160 return is_unsigned(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700161 }
ethannicholasd598f792016-07-25 10:08:54 -0700162 return type == *context.fUInt_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700163}
164
ethannicholasd598f792016-07-25 10:08:54 -0700165static bool is_bool(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700166 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700167 return is_bool(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700168 }
ethannicholasd598f792016-07-25 10:08:54 -0700169 return type == *context.fBool_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700170}
171
ethannicholasd598f792016-07-25 10:08:54 -0700172static bool is_out(const Variable& var) {
173 return (var.fModifiers.fFlags & Modifiers::kOut_Flag) != 0;
ethannicholasb3058bd2016-07-01 08:22:01 -0700174}
175
176#if SPIRV_DEBUG
177static std::string opcode_text(SpvOp_ opCode) {
178 switch (opCode) {
179 case SpvOpNop:
180 return "Nop";
181 case SpvOpUndef:
182 return "Undef";
183 case SpvOpSourceContinued:
184 return "SourceContinued";
185 case SpvOpSource:
186 return "Source";
187 case SpvOpSourceExtension:
188 return "SourceExtension";
189 case SpvOpName:
190 return "Name";
191 case SpvOpMemberName:
192 return "MemberName";
193 case SpvOpString:
194 return "String";
195 case SpvOpLine:
196 return "Line";
197 case SpvOpExtension:
198 return "Extension";
199 case SpvOpExtInstImport:
200 return "ExtInstImport";
201 case SpvOpExtInst:
202 return "ExtInst";
203 case SpvOpMemoryModel:
204 return "MemoryModel";
205 case SpvOpEntryPoint:
206 return "EntryPoint";
207 case SpvOpExecutionMode:
208 return "ExecutionMode";
209 case SpvOpCapability:
210 return "Capability";
211 case SpvOpTypeVoid:
212 return "TypeVoid";
213 case SpvOpTypeBool:
214 return "TypeBool";
215 case SpvOpTypeInt:
216 return "TypeInt";
217 case SpvOpTypeFloat:
218 return "TypeFloat";
219 case SpvOpTypeVector:
220 return "TypeVector";
221 case SpvOpTypeMatrix:
222 return "TypeMatrix";
223 case SpvOpTypeImage:
224 return "TypeImage";
225 case SpvOpTypeSampler:
226 return "TypeSampler";
227 case SpvOpTypeSampledImage:
228 return "TypeSampledImage";
229 case SpvOpTypeArray:
230 return "TypeArray";
231 case SpvOpTypeRuntimeArray:
232 return "TypeRuntimeArray";
233 case SpvOpTypeStruct:
234 return "TypeStruct";
235 case SpvOpTypeOpaque:
236 return "TypeOpaque";
237 case SpvOpTypePointer:
238 return "TypePointer";
239 case SpvOpTypeFunction:
240 return "TypeFunction";
241 case SpvOpTypeEvent:
242 return "TypeEvent";
243 case SpvOpTypeDeviceEvent:
244 return "TypeDeviceEvent";
245 case SpvOpTypeReserveId:
246 return "TypeReserveId";
247 case SpvOpTypeQueue:
248 return "TypeQueue";
249 case SpvOpTypePipe:
250 return "TypePipe";
251 case SpvOpTypeForwardPointer:
252 return "TypeForwardPointer";
253 case SpvOpConstantTrue:
254 return "ConstantTrue";
255 case SpvOpConstantFalse:
256 return "ConstantFalse";
257 case SpvOpConstant:
258 return "Constant";
259 case SpvOpConstantComposite:
260 return "ConstantComposite";
261 case SpvOpConstantSampler:
262 return "ConstantSampler";
263 case SpvOpConstantNull:
264 return "ConstantNull";
265 case SpvOpSpecConstantTrue:
266 return "SpecConstantTrue";
267 case SpvOpSpecConstantFalse:
268 return "SpecConstantFalse";
269 case SpvOpSpecConstant:
270 return "SpecConstant";
271 case SpvOpSpecConstantComposite:
272 return "SpecConstantComposite";
273 case SpvOpSpecConstantOp:
274 return "SpecConstantOp";
275 case SpvOpFunction:
276 return "Function";
277 case SpvOpFunctionParameter:
278 return "FunctionParameter";
279 case SpvOpFunctionEnd:
280 return "FunctionEnd";
281 case SpvOpFunctionCall:
282 return "FunctionCall";
283 case SpvOpVariable:
284 return "Variable";
285 case SpvOpImageTexelPointer:
286 return "ImageTexelPointer";
287 case SpvOpLoad:
288 return "Load";
289 case SpvOpStore:
290 return "Store";
291 case SpvOpCopyMemory:
292 return "CopyMemory";
293 case SpvOpCopyMemorySized:
294 return "CopyMemorySized";
295 case SpvOpAccessChain:
296 return "AccessChain";
297 case SpvOpInBoundsAccessChain:
298 return "InBoundsAccessChain";
299 case SpvOpPtrAccessChain:
300 return "PtrAccessChain";
301 case SpvOpArrayLength:
302 return "ArrayLength";
303 case SpvOpGenericPtrMemSemantics:
304 return "GenericPtrMemSemantics";
305 case SpvOpInBoundsPtrAccessChain:
306 return "InBoundsPtrAccessChain";
307 case SpvOpDecorate:
308 return "Decorate";
309 case SpvOpMemberDecorate:
310 return "MemberDecorate";
311 case SpvOpDecorationGroup:
312 return "DecorationGroup";
313 case SpvOpGroupDecorate:
314 return "GroupDecorate";
315 case SpvOpGroupMemberDecorate:
316 return "GroupMemberDecorate";
317 case SpvOpVectorExtractDynamic:
318 return "VectorExtractDynamic";
319 case SpvOpVectorInsertDynamic:
320 return "VectorInsertDynamic";
321 case SpvOpVectorShuffle:
322 return "VectorShuffle";
323 case SpvOpCompositeConstruct:
324 return "CompositeConstruct";
325 case SpvOpCompositeExtract:
326 return "CompositeExtract";
327 case SpvOpCompositeInsert:
328 return "CompositeInsert";
329 case SpvOpCopyObject:
330 return "CopyObject";
331 case SpvOpTranspose:
332 return "Transpose";
333 case SpvOpSampledImage:
334 return "SampledImage";
335 case SpvOpImageSampleImplicitLod:
336 return "ImageSampleImplicitLod";
337 case SpvOpImageSampleExplicitLod:
338 return "ImageSampleExplicitLod";
339 case SpvOpImageSampleDrefImplicitLod:
340 return "ImageSampleDrefImplicitLod";
341 case SpvOpImageSampleDrefExplicitLod:
342 return "ImageSampleDrefExplicitLod";
343 case SpvOpImageSampleProjImplicitLod:
344 return "ImageSampleProjImplicitLod";
345 case SpvOpImageSampleProjExplicitLod:
346 return "ImageSampleProjExplicitLod";
347 case SpvOpImageSampleProjDrefImplicitLod:
348 return "ImageSampleProjDrefImplicitLod";
349 case SpvOpImageSampleProjDrefExplicitLod:
350 return "ImageSampleProjDrefExplicitLod";
351 case SpvOpImageFetch:
352 return "ImageFetch";
353 case SpvOpImageGather:
354 return "ImageGather";
355 case SpvOpImageDrefGather:
356 return "ImageDrefGather";
357 case SpvOpImageRead:
358 return "ImageRead";
359 case SpvOpImageWrite:
360 return "ImageWrite";
361 case SpvOpImage:
362 return "Image";
363 case SpvOpImageQueryFormat:
364 return "ImageQueryFormat";
365 case SpvOpImageQueryOrder:
366 return "ImageQueryOrder";
367 case SpvOpImageQuerySizeLod:
368 return "ImageQuerySizeLod";
369 case SpvOpImageQuerySize:
370 return "ImageQuerySize";
371 case SpvOpImageQueryLod:
372 return "ImageQueryLod";
373 case SpvOpImageQueryLevels:
374 return "ImageQueryLevels";
375 case SpvOpImageQuerySamples:
376 return "ImageQuerySamples";
377 case SpvOpConvertFToU:
378 return "ConvertFToU";
379 case SpvOpConvertFToS:
380 return "ConvertFToS";
381 case SpvOpConvertSToF:
382 return "ConvertSToF";
383 case SpvOpConvertUToF:
384 return "ConvertUToF";
385 case SpvOpUConvert:
386 return "UConvert";
387 case SpvOpSConvert:
388 return "SConvert";
389 case SpvOpFConvert:
390 return "FConvert";
391 case SpvOpQuantizeToF16:
392 return "QuantizeToF16";
393 case SpvOpConvertPtrToU:
394 return "ConvertPtrToU";
395 case SpvOpSatConvertSToU:
396 return "SatConvertSToU";
397 case SpvOpSatConvertUToS:
398 return "SatConvertUToS";
399 case SpvOpConvertUToPtr:
400 return "ConvertUToPtr";
401 case SpvOpPtrCastToGeneric:
402 return "PtrCastToGeneric";
403 case SpvOpGenericCastToPtr:
404 return "GenericCastToPtr";
405 case SpvOpGenericCastToPtrExplicit:
406 return "GenericCastToPtrExplicit";
407 case SpvOpBitcast:
408 return "Bitcast";
409 case SpvOpSNegate:
410 return "SNegate";
411 case SpvOpFNegate:
412 return "FNegate";
413 case SpvOpIAdd:
414 return "IAdd";
415 case SpvOpFAdd:
416 return "FAdd";
417 case SpvOpISub:
418 return "ISub";
419 case SpvOpFSub:
420 return "FSub";
421 case SpvOpIMul:
422 return "IMul";
423 case SpvOpFMul:
424 return "FMul";
425 case SpvOpUDiv:
426 return "UDiv";
427 case SpvOpSDiv:
428 return "SDiv";
429 case SpvOpFDiv:
430 return "FDiv";
431 case SpvOpUMod:
432 return "UMod";
433 case SpvOpSRem:
434 return "SRem";
435 case SpvOpSMod:
436 return "SMod";
437 case SpvOpFRem:
438 return "FRem";
439 case SpvOpFMod:
440 return "FMod";
441 case SpvOpVectorTimesScalar:
442 return "VectorTimesScalar";
443 case SpvOpMatrixTimesScalar:
444 return "MatrixTimesScalar";
445 case SpvOpVectorTimesMatrix:
446 return "VectorTimesMatrix";
447 case SpvOpMatrixTimesVector:
448 return "MatrixTimesVector";
449 case SpvOpMatrixTimesMatrix:
450 return "MatrixTimesMatrix";
451 case SpvOpOuterProduct:
452 return "OuterProduct";
453 case SpvOpDot:
454 return "Dot";
455 case SpvOpIAddCarry:
456 return "IAddCarry";
457 case SpvOpISubBorrow:
458 return "ISubBorrow";
459 case SpvOpUMulExtended:
460 return "UMulExtended";
461 case SpvOpSMulExtended:
462 return "SMulExtended";
463 case SpvOpAny:
464 return "Any";
465 case SpvOpAll:
466 return "All";
467 case SpvOpIsNan:
468 return "IsNan";
469 case SpvOpIsInf:
470 return "IsInf";
471 case SpvOpIsFinite:
472 return "IsFinite";
473 case SpvOpIsNormal:
474 return "IsNormal";
475 case SpvOpSignBitSet:
476 return "SignBitSet";
477 case SpvOpLessOrGreater:
478 return "LessOrGreater";
479 case SpvOpOrdered:
480 return "Ordered";
481 case SpvOpUnordered:
482 return "Unordered";
483 case SpvOpLogicalEqual:
484 return "LogicalEqual";
485 case SpvOpLogicalNotEqual:
486 return "LogicalNotEqual";
487 case SpvOpLogicalOr:
488 return "LogicalOr";
489 case SpvOpLogicalAnd:
490 return "LogicalAnd";
491 case SpvOpLogicalNot:
492 return "LogicalNot";
493 case SpvOpSelect:
494 return "Select";
495 case SpvOpIEqual:
496 return "IEqual";
497 case SpvOpINotEqual:
498 return "INotEqual";
499 case SpvOpUGreaterThan:
500 return "UGreaterThan";
501 case SpvOpSGreaterThan:
502 return "SGreaterThan";
503 case SpvOpUGreaterThanEqual:
504 return "UGreaterThanEqual";
505 case SpvOpSGreaterThanEqual:
506 return "SGreaterThanEqual";
507 case SpvOpULessThan:
508 return "ULessThan";
509 case SpvOpSLessThan:
510 return "SLessThan";
511 case SpvOpULessThanEqual:
512 return "ULessThanEqual";
513 case SpvOpSLessThanEqual:
514 return "SLessThanEqual";
515 case SpvOpFOrdEqual:
516 return "FOrdEqual";
517 case SpvOpFUnordEqual:
518 return "FUnordEqual";
519 case SpvOpFOrdNotEqual:
520 return "FOrdNotEqual";
521 case SpvOpFUnordNotEqual:
522 return "FUnordNotEqual";
523 case SpvOpFOrdLessThan:
524 return "FOrdLessThan";
525 case SpvOpFUnordLessThan:
526 return "FUnordLessThan";
527 case SpvOpFOrdGreaterThan:
528 return "FOrdGreaterThan";
529 case SpvOpFUnordGreaterThan:
530 return "FUnordGreaterThan";
531 case SpvOpFOrdLessThanEqual:
532 return "FOrdLessThanEqual";
533 case SpvOpFUnordLessThanEqual:
534 return "FUnordLessThanEqual";
535 case SpvOpFOrdGreaterThanEqual:
536 return "FOrdGreaterThanEqual";
537 case SpvOpFUnordGreaterThanEqual:
538 return "FUnordGreaterThanEqual";
539 case SpvOpShiftRightLogical:
540 return "ShiftRightLogical";
541 case SpvOpShiftRightArithmetic:
542 return "ShiftRightArithmetic";
543 case SpvOpShiftLeftLogical:
544 return "ShiftLeftLogical";
545 case SpvOpBitwiseOr:
546 return "BitwiseOr";
547 case SpvOpBitwiseXor:
548 return "BitwiseXor";
549 case SpvOpBitwiseAnd:
550 return "BitwiseAnd";
551 case SpvOpNot:
552 return "Not";
553 case SpvOpBitFieldInsert:
554 return "BitFieldInsert";
555 case SpvOpBitFieldSExtract:
556 return "BitFieldSExtract";
557 case SpvOpBitFieldUExtract:
558 return "BitFieldUExtract";
559 case SpvOpBitReverse:
560 return "BitReverse";
561 case SpvOpBitCount:
562 return "BitCount";
563 case SpvOpDPdx:
564 return "DPdx";
565 case SpvOpDPdy:
566 return "DPdy";
567 case SpvOpFwidth:
568 return "Fwidth";
569 case SpvOpDPdxFine:
570 return "DPdxFine";
571 case SpvOpDPdyFine:
572 return "DPdyFine";
573 case SpvOpFwidthFine:
574 return "FwidthFine";
575 case SpvOpDPdxCoarse:
576 return "DPdxCoarse";
577 case SpvOpDPdyCoarse:
578 return "DPdyCoarse";
579 case SpvOpFwidthCoarse:
580 return "FwidthCoarse";
581 case SpvOpEmitVertex:
582 return "EmitVertex";
583 case SpvOpEndPrimitive:
584 return "EndPrimitive";
585 case SpvOpEmitStreamVertex:
586 return "EmitStreamVertex";
587 case SpvOpEndStreamPrimitive:
588 return "EndStreamPrimitive";
589 case SpvOpControlBarrier:
590 return "ControlBarrier";
591 case SpvOpMemoryBarrier:
592 return "MemoryBarrier";
593 case SpvOpAtomicLoad:
594 return "AtomicLoad";
595 case SpvOpAtomicStore:
596 return "AtomicStore";
597 case SpvOpAtomicExchange:
598 return "AtomicExchange";
599 case SpvOpAtomicCompareExchange:
600 return "AtomicCompareExchange";
601 case SpvOpAtomicCompareExchangeWeak:
602 return "AtomicCompareExchangeWeak";
603 case SpvOpAtomicIIncrement:
604 return "AtomicIIncrement";
605 case SpvOpAtomicIDecrement:
606 return "AtomicIDecrement";
607 case SpvOpAtomicIAdd:
608 return "AtomicIAdd";
609 case SpvOpAtomicISub:
610 return "AtomicISub";
611 case SpvOpAtomicSMin:
612 return "AtomicSMin";
613 case SpvOpAtomicUMin:
614 return "AtomicUMin";
615 case SpvOpAtomicSMax:
616 return "AtomicSMax";
617 case SpvOpAtomicUMax:
618 return "AtomicUMax";
619 case SpvOpAtomicAnd:
620 return "AtomicAnd";
621 case SpvOpAtomicOr:
622 return "AtomicOr";
623 case SpvOpAtomicXor:
624 return "AtomicXor";
625 case SpvOpPhi:
626 return "Phi";
627 case SpvOpLoopMerge:
628 return "LoopMerge";
629 case SpvOpSelectionMerge:
630 return "SelectionMerge";
631 case SpvOpLabel:
632 return "Label";
633 case SpvOpBranch:
634 return "Branch";
635 case SpvOpBranchConditional:
636 return "BranchConditional";
637 case SpvOpSwitch:
638 return "Switch";
639 case SpvOpKill:
640 return "Kill";
641 case SpvOpReturn:
642 return "Return";
643 case SpvOpReturnValue:
644 return "ReturnValue";
645 case SpvOpUnreachable:
646 return "Unreachable";
647 case SpvOpLifetimeStart:
648 return "LifetimeStart";
649 case SpvOpLifetimeStop:
650 return "LifetimeStop";
651 case SpvOpGroupAsyncCopy:
652 return "GroupAsyncCopy";
653 case SpvOpGroupWaitEvents:
654 return "GroupWaitEvents";
655 case SpvOpGroupAll:
656 return "GroupAll";
657 case SpvOpGroupAny:
658 return "GroupAny";
659 case SpvOpGroupBroadcast:
660 return "GroupBroadcast";
661 case SpvOpGroupIAdd:
662 return "GroupIAdd";
663 case SpvOpGroupFAdd:
664 return "GroupFAdd";
665 case SpvOpGroupFMin:
666 return "GroupFMin";
667 case SpvOpGroupUMin:
668 return "GroupUMin";
669 case SpvOpGroupSMin:
670 return "GroupSMin";
671 case SpvOpGroupFMax:
672 return "GroupFMax";
673 case SpvOpGroupUMax:
674 return "GroupUMax";
675 case SpvOpGroupSMax:
676 return "GroupSMax";
677 case SpvOpReadPipe:
678 return "ReadPipe";
679 case SpvOpWritePipe:
680 return "WritePipe";
681 case SpvOpReservedReadPipe:
682 return "ReservedReadPipe";
683 case SpvOpReservedWritePipe:
684 return "ReservedWritePipe";
685 case SpvOpReserveReadPipePackets:
686 return "ReserveReadPipePackets";
687 case SpvOpReserveWritePipePackets:
688 return "ReserveWritePipePackets";
689 case SpvOpCommitReadPipe:
690 return "CommitReadPipe";
691 case SpvOpCommitWritePipe:
692 return "CommitWritePipe";
693 case SpvOpIsValidReserveId:
694 return "IsValidReserveId";
695 case SpvOpGetNumPipePackets:
696 return "GetNumPipePackets";
697 case SpvOpGetMaxPipePackets:
698 return "GetMaxPipePackets";
699 case SpvOpGroupReserveReadPipePackets:
700 return "GroupReserveReadPipePackets";
701 case SpvOpGroupReserveWritePipePackets:
702 return "GroupReserveWritePipePackets";
703 case SpvOpGroupCommitReadPipe:
704 return "GroupCommitReadPipe";
705 case SpvOpGroupCommitWritePipe:
706 return "GroupCommitWritePipe";
707 case SpvOpEnqueueMarker:
708 return "EnqueueMarker";
709 case SpvOpEnqueueKernel:
710 return "EnqueueKernel";
711 case SpvOpGetKernelNDrangeSubGroupCount:
712 return "GetKernelNDrangeSubGroupCount";
713 case SpvOpGetKernelNDrangeMaxSubGroupSize:
714 return "GetKernelNDrangeMaxSubGroupSize";
715 case SpvOpGetKernelWorkGroupSize:
716 return "GetKernelWorkGroupSize";
717 case SpvOpGetKernelPreferredWorkGroupSizeMultiple:
718 return "GetKernelPreferredWorkGroupSizeMultiple";
719 case SpvOpRetainEvent:
720 return "RetainEvent";
721 case SpvOpReleaseEvent:
722 return "ReleaseEvent";
723 case SpvOpCreateUserEvent:
724 return "CreateUserEvent";
725 case SpvOpIsValidEvent:
726 return "IsValidEvent";
727 case SpvOpSetUserEventStatus:
728 return "SetUserEventStatus";
729 case SpvOpCaptureEventProfilingInfo:
730 return "CaptureEventProfilingInfo";
731 case SpvOpGetDefaultQueue:
732 return "GetDefaultQueue";
733 case SpvOpBuildNDRange:
734 return "BuildNDRange";
735 case SpvOpImageSparseSampleImplicitLod:
736 return "ImageSparseSampleImplicitLod";
737 case SpvOpImageSparseSampleExplicitLod:
738 return "ImageSparseSampleExplicitLod";
739 case SpvOpImageSparseSampleDrefImplicitLod:
740 return "ImageSparseSampleDrefImplicitLod";
741 case SpvOpImageSparseSampleDrefExplicitLod:
742 return "ImageSparseSampleDrefExplicitLod";
743 case SpvOpImageSparseSampleProjImplicitLod:
744 return "ImageSparseSampleProjImplicitLod";
745 case SpvOpImageSparseSampleProjExplicitLod:
746 return "ImageSparseSampleProjExplicitLod";
747 case SpvOpImageSparseSampleProjDrefImplicitLod:
748 return "ImageSparseSampleProjDrefImplicitLod";
749 case SpvOpImageSparseSampleProjDrefExplicitLod:
750 return "ImageSparseSampleProjDrefExplicitLod";
751 case SpvOpImageSparseFetch:
752 return "ImageSparseFetch";
753 case SpvOpImageSparseGather:
754 return "ImageSparseGather";
755 case SpvOpImageSparseDrefGather:
756 return "ImageSparseDrefGather";
757 case SpvOpImageSparseTexelsResident:
758 return "ImageSparseTexelsResident";
759 case SpvOpNoLine:
760 return "NoLine";
761 case SpvOpAtomicFlagTestAndSet:
762 return "AtomicFlagTestAndSet";
763 case SpvOpAtomicFlagClear:
764 return "AtomicFlagClear";
765 case SpvOpImageSparseRead:
766 return "ImageSparseRead";
767 default:
768 ABORT("unsupported SPIR-V op");
769 }
770}
771#endif
772
773void SPIRVCodeGenerator::writeOpCode(SpvOp_ opCode, int length, std::ostream& out) {
774 ASSERT(opCode != SpvOpUndef);
775 switch (opCode) {
776 case SpvOpReturn: // fall through
777 case SpvOpReturnValue: // fall through
ethannicholas552882f2016-07-07 06:30:48 -0700778 case SpvOpKill: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -0700779 case SpvOpBranch: // fall through
780 case SpvOpBranchConditional:
781 ASSERT(fCurrentBlock);
782 fCurrentBlock = 0;
783 break;
784 case SpvOpConstant: // fall through
785 case SpvOpConstantTrue: // fall through
786 case SpvOpConstantFalse: // fall through
787 case SpvOpConstantComposite: // fall through
788 case SpvOpTypeVoid: // fall through
789 case SpvOpTypeInt: // fall through
790 case SpvOpTypeFloat: // fall through
791 case SpvOpTypeBool: // fall through
792 case SpvOpTypeVector: // fall through
793 case SpvOpTypeMatrix: // fall through
794 case SpvOpTypeArray: // fall through
795 case SpvOpTypePointer: // fall through
796 case SpvOpTypeFunction: // fall through
797 case SpvOpTypeRuntimeArray: // fall through
798 case SpvOpTypeStruct: // fall through
799 case SpvOpTypeImage: // fall through
800 case SpvOpTypeSampledImage: // fall through
801 case SpvOpVariable: // fall through
802 case SpvOpFunction: // fall through
803 case SpvOpFunctionParameter: // fall through
804 case SpvOpFunctionEnd: // fall through
805 case SpvOpExecutionMode: // fall through
806 case SpvOpMemoryModel: // fall through
807 case SpvOpCapability: // fall through
808 case SpvOpExtInstImport: // fall through
809 case SpvOpEntryPoint: // fall through
810 case SpvOpSource: // fall through
811 case SpvOpSourceExtension: // fall through
812 case SpvOpName: // fall through
813 case SpvOpMemberName: // fall through
814 case SpvOpDecorate: // fall through
815 case SpvOpMemberDecorate:
816 break;
817 default:
818 ASSERT(fCurrentBlock);
819 }
820#if SPIRV_DEBUG
821 out << std::endl << opcode_text(opCode) << " ";
822#else
823 this->writeWord((length << 16) | opCode, out);
824#endif
825}
826
827void SPIRVCodeGenerator::writeLabel(SpvId label, std::ostream& out) {
828 fCurrentBlock = label;
829 this->writeInstruction(SpvOpLabel, label, out);
830}
831
832void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, std::ostream& out) {
833 this->writeOpCode(opCode, 1, out);
834}
835
836void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, std::ostream& out) {
837 this->writeOpCode(opCode, 2, out);
838 this->writeWord(word1, out);
839}
840
841void SPIRVCodeGenerator::writeString(const char* string, std::ostream& out) {
842 size_t length = strlen(string);
843 out << string;
844 switch (length % 4) {
845 case 1:
846 out << (char) 0;
847 // fall through
848 case 2:
849 out << (char) 0;
850 // fall through
851 case 3:
852 out << (char) 0;
853 break;
854 default:
855 this->writeWord(0, out);
856 }
857}
858
859void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, const char* string, std::ostream& out) {
860 int32_t length = (int32_t) strlen(string);
861 this->writeOpCode(opCode, 1 + (length + 4) / 4, out);
862 this->writeString(string, out);
863}
864
865
866void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, const char* string,
867 std::ostream& out) {
868 int32_t length = (int32_t) strlen(string);
869 this->writeOpCode(opCode, 2 + (length + 4) / 4, out);
870 this->writeWord(word1, out);
871 this->writeString(string, out);
872}
873
874void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
875 const char* string, std::ostream& out) {
876 int32_t length = (int32_t) strlen(string);
877 this->writeOpCode(opCode, 3 + (length + 4) / 4, out);
878 this->writeWord(word1, out);
879 this->writeWord(word2, out);
880 this->writeString(string, out);
881}
882
883void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
884 std::ostream& out) {
885 this->writeOpCode(opCode, 3, out);
886 this->writeWord(word1, out);
887 this->writeWord(word2, out);
888}
889
890void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
891 int32_t word3, std::ostream& out) {
892 this->writeOpCode(opCode, 4, out);
893 this->writeWord(word1, out);
894 this->writeWord(word2, out);
895 this->writeWord(word3, out);
896}
897
898void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
899 int32_t word3, int32_t word4, std::ostream& out) {
900 this->writeOpCode(opCode, 5, out);
901 this->writeWord(word1, out);
902 this->writeWord(word2, out);
903 this->writeWord(word3, out);
904 this->writeWord(word4, out);
905}
906
907void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
908 int32_t word3, int32_t word4, int32_t word5,
909 std::ostream& out) {
910 this->writeOpCode(opCode, 6, out);
911 this->writeWord(word1, out);
912 this->writeWord(word2, out);
913 this->writeWord(word3, out);
914 this->writeWord(word4, out);
915 this->writeWord(word5, out);
916}
917
918void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
919 int32_t word3, int32_t word4, int32_t word5,
920 int32_t word6, std::ostream& out) {
921 this->writeOpCode(opCode, 7, out);
922 this->writeWord(word1, out);
923 this->writeWord(word2, out);
924 this->writeWord(word3, out);
925 this->writeWord(word4, out);
926 this->writeWord(word5, out);
927 this->writeWord(word6, out);
928}
929
930void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
931 int32_t word3, int32_t word4, int32_t word5,
932 int32_t word6, int32_t word7, std::ostream& out) {
933 this->writeOpCode(opCode, 8, out);
934 this->writeWord(word1, out);
935 this->writeWord(word2, out);
936 this->writeWord(word3, out);
937 this->writeWord(word4, out);
938 this->writeWord(word5, out);
939 this->writeWord(word6, out);
940 this->writeWord(word7, out);
941}
942
943void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
944 int32_t word3, int32_t word4, int32_t word5,
945 int32_t word6, int32_t word7, int32_t word8,
946 std::ostream& out) {
947 this->writeOpCode(opCode, 9, out);
948 this->writeWord(word1, out);
949 this->writeWord(word2, out);
950 this->writeWord(word3, out);
951 this->writeWord(word4, out);
952 this->writeWord(word5, out);
953 this->writeWord(word6, out);
954 this->writeWord(word7, out);
955 this->writeWord(word8, out);
956}
957
958void SPIRVCodeGenerator::writeCapabilities(std::ostream& out) {
959 for (uint64_t i = 0, bit = 1; i <= kLast_Capability; i++, bit <<= 1) {
960 if (fCapabilities & bit) {
961 this->writeInstruction(SpvOpCapability, (SpvId) i, out);
962 }
963 }
964}
965
966SpvId SPIRVCodeGenerator::nextId() {
967 return fIdCount++;
968}
969
970void SPIRVCodeGenerator::writeStruct(const Type& type, SpvId resultId) {
971 this->writeInstruction(SpvOpName, resultId, type.name().c_str(), fNameBuffer);
972 // go ahead and write all of the field types, so we don't inadvertently write them while we're
973 // in the middle of writing the struct instruction
974 std::vector<SpvId> types;
975 for (const auto& f : type.fields()) {
ethannicholas0730be72016-09-01 07:59:02 -0700976 types.push_back(this->getType(*f.fType));
ethannicholasb3058bd2016-07-01 08:22:01 -0700977 }
978 this->writeOpCode(SpvOpTypeStruct, 2 + (int32_t) types.size(), fConstantBuffer);
979 this->writeWord(resultId, fConstantBuffer);
980 for (SpvId id : types) {
981 this->writeWord(id, fConstantBuffer);
982 }
983 size_t offset = 0;
984 for (int32_t i = 0; i < (int32_t) type.fields().size(); i++) {
ethannicholas0730be72016-09-01 07:59:02 -0700985 size_t size = type.fields()[i].fType->size();
986 size_t alignment = type.fields()[i].fType->alignment();
ethannicholasb3058bd2016-07-01 08:22:01 -0700987 size_t mod = offset % alignment;
988 if (mod != 0) {
989 offset += alignment - mod;
990 }
991 this->writeInstruction(SpvOpMemberName, resultId, i, type.fields()[i].fName.c_str(),
992 fNameBuffer);
993 this->writeLayout(type.fields()[i].fModifiers.fLayout, resultId, i);
994 if (type.fields()[i].fModifiers.fLayout.fBuiltin < 0) {
995 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i, SpvDecorationOffset,
996 (SpvId) offset, fDecorationBuffer);
997 }
ethannicholas0730be72016-09-01 07:59:02 -0700998 if (type.fields()[i].fType->kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700999 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationColMajor,
1000 fDecorationBuffer);
1001 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationMatrixStride,
ethannicholas0730be72016-09-01 07:59:02 -07001002 (SpvId) type.fields()[i].fType->stride(), fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001003 }
1004 offset += size;
ethannicholas0730be72016-09-01 07:59:02 -07001005 Type::Kind kind = type.fields()[i].fType->kind();
ethannicholasb3058bd2016-07-01 08:22:01 -07001006 if ((kind == Type::kArray_Kind || kind == Type::kStruct_Kind) && offset % alignment != 0) {
1007 offset += alignment - offset % alignment;
1008 }
1009 ASSERT(offset % alignment == 0);
1010 }
1011}
1012
1013SpvId SPIRVCodeGenerator::getType(const Type& type) {
1014 auto entry = fTypeMap.find(type.name());
1015 if (entry == fTypeMap.end()) {
1016 SpvId result = this->nextId();
1017 switch (type.kind()) {
1018 case Type::kScalar_Kind:
ethannicholasd598f792016-07-25 10:08:54 -07001019 if (type == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001020 this->writeInstruction(SpvOpTypeBool, result, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001021 } else if (type == *fContext.fInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001022 this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001023 } else if (type == *fContext.fUInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001024 this->writeInstruction(SpvOpTypeInt, result, 32, 0, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001025 } else if (type == *fContext.fFloat_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001026 this->writeInstruction(SpvOpTypeFloat, result, 32, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001027 } else if (type == *fContext.fDouble_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001028 this->writeInstruction(SpvOpTypeFloat, result, 64, fConstantBuffer);
1029 } else {
1030 ASSERT(false);
1031 }
1032 break;
1033 case Type::kVector_Kind:
1034 this->writeInstruction(SpvOpTypeVector, result,
ethannicholasd598f792016-07-25 10:08:54 -07001035 this->getType(type.componentType()),
ethannicholasb3058bd2016-07-01 08:22:01 -07001036 type.columns(), fConstantBuffer);
1037 break;
1038 case Type::kMatrix_Kind:
ethannicholasd598f792016-07-25 10:08:54 -07001039 this->writeInstruction(SpvOpTypeMatrix, result,
1040 this->getType(index_type(fContext, type)),
ethannicholasb3058bd2016-07-01 08:22:01 -07001041 type.columns(), fConstantBuffer);
1042 break;
1043 case Type::kStruct_Kind:
1044 this->writeStruct(type, result);
1045 break;
1046 case Type::kArray_Kind: {
1047 if (type.columns() > 0) {
ethannicholasd598f792016-07-25 10:08:54 -07001048 IntLiteral count(fContext, Position(), type.columns());
ethannicholasb3058bd2016-07-01 08:22:01 -07001049 this->writeInstruction(SpvOpTypeArray, result,
ethannicholasd598f792016-07-25 10:08:54 -07001050 this->getType(type.componentType()),
ethannicholasb3058bd2016-07-01 08:22:01 -07001051 this->writeIntLiteral(count), fConstantBuffer);
1052 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
1053 (int32_t) type.stride(), fDecorationBuffer);
1054 } else {
1055 ABORT("runtime-sized arrays are not yet supported");
1056 this->writeInstruction(SpvOpTypeRuntimeArray, result,
ethannicholasd598f792016-07-25 10:08:54 -07001057 this->getType(type.componentType()), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001058 }
1059 break;
1060 }
1061 case Type::kSampler_Kind: {
1062 SpvId image = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001063 this->writeInstruction(SpvOpTypeImage, image, this->getType(*fContext.fFloat_Type),
ethannicholasb3058bd2016-07-01 08:22:01 -07001064 type.dimensions(), type.isDepth(), type.isArrayed(),
1065 type.isMultisampled(), type.isSampled(),
1066 SpvImageFormatUnknown, fConstantBuffer);
1067 this->writeInstruction(SpvOpTypeSampledImage, result, image, fConstantBuffer);
1068 break;
1069 }
1070 default:
ethannicholasd598f792016-07-25 10:08:54 -07001071 if (type == *fContext.fVoid_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001072 this->writeInstruction(SpvOpTypeVoid, result, fConstantBuffer);
1073 } else {
1074 ABORT("invalid type: %s", type.description().c_str());
1075 }
1076 }
1077 fTypeMap[type.name()] = result;
1078 return result;
1079 }
1080 return entry->second;
1081}
1082
ethannicholasd598f792016-07-25 10:08:54 -07001083SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) {
1084 std::string key = function.fReturnType.description() + "(";
ethannicholasb3058bd2016-07-01 08:22:01 -07001085 std::string separator = "";
ethannicholasd598f792016-07-25 10:08:54 -07001086 for (size_t i = 0; i < function.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001087 key += separator;
1088 separator = ", ";
ethannicholasd598f792016-07-25 10:08:54 -07001089 key += function.fParameters[i]->fType.description();
ethannicholasb3058bd2016-07-01 08:22:01 -07001090 }
1091 key += ")";
1092 auto entry = fTypeMap.find(key);
1093 if (entry == fTypeMap.end()) {
1094 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001095 int32_t length = 3 + (int32_t) function.fParameters.size();
1096 SpvId returnType = this->getType(function.fReturnType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001097 std::vector<SpvId> parameterTypes;
ethannicholasd598f792016-07-25 10:08:54 -07001098 for (size_t i = 0; i < function.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001099 // glslang seems to treat all function arguments as pointers whether they need to be or
1100 // not. I was initially puzzled by this until I ran bizarre failures with certain
1101 // patterns of function calls and control constructs, as exemplified by this minimal
1102 // failure case:
1103 //
1104 // void sphere(float x) {
1105 // }
1106 //
1107 // void map() {
1108 // sphere(1.0);
1109 // }
1110 //
1111 // void main() {
1112 // for (int i = 0; i < 1; i++) {
1113 // map();
1114 // }
1115 // }
1116 //
1117 // As of this writing, compiling this in the "obvious" way (with sphere taking a float)
1118 // crashes. Making it take a float* and storing the argument in a temporary variable,
1119 // as glslang does, fixes it. It's entirely possible I simply missed whichever part of
1120 // the spec makes this make sense.
1121// if (is_out(function->fParameters[i])) {
ethannicholasd598f792016-07-25 10:08:54 -07001122 parameterTypes.push_back(this->getPointerType(function.fParameters[i]->fType,
ethannicholasb3058bd2016-07-01 08:22:01 -07001123 SpvStorageClassFunction));
1124// } else {
ethannicholasd598f792016-07-25 10:08:54 -07001125// parameterTypes.push_back(this->getType(function.fParameters[i]->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -07001126// }
1127 }
1128 this->writeOpCode(SpvOpTypeFunction, length, fConstantBuffer);
1129 this->writeWord(result, fConstantBuffer);
1130 this->writeWord(returnType, fConstantBuffer);
1131 for (SpvId id : parameterTypes) {
1132 this->writeWord(id, fConstantBuffer);
1133 }
1134 fTypeMap[key] = result;
1135 return result;
1136 }
1137 return entry->second;
1138}
1139
ethannicholasd598f792016-07-25 10:08:54 -07001140SpvId SPIRVCodeGenerator::getPointerType(const Type& type,
ethannicholasb3058bd2016-07-01 08:22:01 -07001141 SpvStorageClass_ storageClass) {
ethannicholasd598f792016-07-25 10:08:54 -07001142 std::string key = type.description() + "*" + to_string(storageClass);
ethannicholasb3058bd2016-07-01 08:22:01 -07001143 auto entry = fTypeMap.find(key);
1144 if (entry == fTypeMap.end()) {
1145 SpvId result = this->nextId();
1146 this->writeInstruction(SpvOpTypePointer, result, storageClass,
ethannicholasd598f792016-07-25 10:08:54 -07001147 this->getType(type), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001148 fTypeMap[key] = result;
1149 return result;
1150 }
1151 return entry->second;
1152}
1153
ethannicholasf789b382016-08-03 12:43:36 -07001154SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001155 switch (expr.fKind) {
1156 case Expression::kBinary_Kind:
1157 return this->writeBinaryExpression((BinaryExpression&) expr, out);
1158 case Expression::kBoolLiteral_Kind:
1159 return this->writeBoolLiteral((BoolLiteral&) expr);
1160 case Expression::kConstructor_Kind:
1161 return this->writeConstructor((Constructor&) expr, out);
1162 case Expression::kIntLiteral_Kind:
1163 return this->writeIntLiteral((IntLiteral&) expr);
1164 case Expression::kFieldAccess_Kind:
1165 return this->writeFieldAccess(((FieldAccess&) expr), out);
1166 case Expression::kFloatLiteral_Kind:
1167 return this->writeFloatLiteral(((FloatLiteral&) expr));
1168 case Expression::kFunctionCall_Kind:
1169 return this->writeFunctionCall((FunctionCall&) expr, out);
1170 case Expression::kPrefix_Kind:
1171 return this->writePrefixExpression((PrefixExpression&) expr, out);
1172 case Expression::kPostfix_Kind:
1173 return this->writePostfixExpression((PostfixExpression&) expr, out);
1174 case Expression::kSwizzle_Kind:
1175 return this->writeSwizzle((Swizzle&) expr, out);
1176 case Expression::kVariableReference_Kind:
1177 return this->writeVariableReference((VariableReference&) expr, out);
1178 case Expression::kTernary_Kind:
1179 return this->writeTernaryExpression((TernaryExpression&) expr, out);
1180 case Expression::kIndex_Kind:
1181 return this->writeIndexExpression((IndexExpression&) expr, out);
1182 default:
1183 ABORT("unsupported expression: %s", expr.description().c_str());
1184 }
1185 return -1;
1186}
1187
ethannicholasf789b382016-08-03 12:43:36 -07001188SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, std::ostream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001189 auto intrinsic = fIntrinsicMap.find(c.fFunction.fName);
ethannicholasb3058bd2016-07-01 08:22:01 -07001190 ASSERT(intrinsic != fIntrinsicMap.end());
ethannicholasd598f792016-07-25 10:08:54 -07001191 const Type& type = c.fArguments[0]->fType;
ethannicholasb3058bd2016-07-01 08:22:01 -07001192 int32_t intrinsicId;
ethannicholasd598f792016-07-25 10:08:54 -07001193 if (std::get<0>(intrinsic->second) == kSpecial_IntrinsicKind || is_float(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001194 intrinsicId = std::get<1>(intrinsic->second);
ethannicholasd598f792016-07-25 10:08:54 -07001195 } else if (is_signed(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001196 intrinsicId = std::get<2>(intrinsic->second);
ethannicholasd598f792016-07-25 10:08:54 -07001197 } else if (is_unsigned(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001198 intrinsicId = std::get<3>(intrinsic->second);
ethannicholasd598f792016-07-25 10:08:54 -07001199 } else if (is_bool(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001200 intrinsicId = std::get<4>(intrinsic->second);
1201 } else {
1202 ABORT("invalid call %s, cannot operate on '%s'", c.description().c_str(),
ethannicholasd598f792016-07-25 10:08:54 -07001203 type.description().c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -07001204 }
1205 switch (std::get<0>(intrinsic->second)) {
1206 case kGLSL_STD_450_IntrinsicKind: {
1207 SpvId result = this->nextId();
1208 std::vector<SpvId> arguments;
1209 for (size_t i = 0; i < c.fArguments.size(); i++) {
1210 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1211 }
1212 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001213 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001214 this->writeWord(result, out);
1215 this->writeWord(fGLSLExtendedInstructions, out);
1216 this->writeWord(intrinsicId, out);
1217 for (SpvId id : arguments) {
1218 this->writeWord(id, out);
1219 }
1220 return result;
1221 }
1222 case kSPIRV_IntrinsicKind: {
1223 SpvId result = this->nextId();
1224 std::vector<SpvId> arguments;
1225 for (size_t i = 0; i < c.fArguments.size(); i++) {
1226 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1227 }
1228 this->writeOpCode((SpvOp_) intrinsicId, 3 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001229 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001230 this->writeWord(result, out);
1231 for (SpvId id : arguments) {
1232 this->writeWord(id, out);
1233 }
1234 return result;
1235 }
1236 case kSpecial_IntrinsicKind:
1237 return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId, out);
1238 default:
1239 ABORT("unsupported intrinsic kind");
1240 }
1241}
1242
ethannicholasf789b382016-08-03 12:43:36 -07001243SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind,
ethannicholasb3058bd2016-07-01 08:22:01 -07001244 std::ostream& out) {
1245 SpvId result = this->nextId();
1246 switch (kind) {
1247 case kAtan_SpecialIntrinsic: {
1248 std::vector<SpvId> arguments;
1249 for (size_t i = 0; i < c.fArguments.size(); i++) {
1250 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1251 }
1252 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001253 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001254 this->writeWord(result, out);
1255 this->writeWord(fGLSLExtendedInstructions, out);
1256 this->writeWord(arguments.size() == 2 ? GLSLstd450Atan2 : GLSLstd450Atan, out);
1257 for (SpvId id : arguments) {
1258 this->writeWord(id, out);
1259 }
1260 return result;
1261 }
1262 case kTexture_SpecialIntrinsic: {
ethannicholasd598f792016-07-25 10:08:54 -07001263 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001264 SpvId sampler = this->writeExpression(*c.fArguments[0], out);
1265 SpvId uv = this->writeExpression(*c.fArguments[1], out);
1266 if (c.fArguments.size() == 3) {
1267 this->writeInstruction(SpvOpImageSampleImplicitLod, type, result, sampler, uv,
1268 SpvImageOperandsBiasMask,
1269 this->writeExpression(*c.fArguments[2], out),
1270 out);
1271 } else {
1272 ASSERT(c.fArguments.size() == 2);
1273 this->writeInstruction(SpvOpImageSampleImplicitLod, type, result, sampler, uv, out);
1274 }
1275 break;
1276 }
1277 case kTextureProj_SpecialIntrinsic: {
ethannicholasd598f792016-07-25 10:08:54 -07001278 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001279 SpvId sampler = this->writeExpression(*c.fArguments[0], out);
1280 SpvId uv = this->writeExpression(*c.fArguments[1], out);
1281 if (c.fArguments.size() == 3) {
1282 this->writeInstruction(SpvOpImageSampleProjImplicitLod, type, result, sampler, uv,
1283 SpvImageOperandsBiasMask,
1284 this->writeExpression(*c.fArguments[2], out),
1285 out);
1286 } else {
1287 ASSERT(c.fArguments.size() == 2);
1288 this->writeInstruction(SpvOpImageSampleProjImplicitLod, type, result, sampler, uv,
1289 out);
1290 }
1291 break;
1292 }
1293 case kTexture2D_SpecialIntrinsic: {
1294 SpvId img = this->writeExpression(*c.fArguments[0], out);
1295 SpvId coords = this->writeExpression(*c.fArguments[1], out);
1296 this->writeInstruction(SpvOpImageSampleImplicitLod,
ethannicholasd598f792016-07-25 10:08:54 -07001297 this->getType(c.fType),
ethannicholasb3058bd2016-07-01 08:22:01 -07001298 result,
1299 img,
1300 coords,
1301 out);
1302 break;
1303 }
1304 }
1305 return result;
1306}
1307
ethannicholasf789b382016-08-03 12:43:36 -07001308SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, std::ostream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001309 const auto& entry = fFunctionMap.find(&c.fFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07001310 if (entry == fFunctionMap.end()) {
1311 return this->writeIntrinsicCall(c, out);
1312 }
1313 // stores (variable, type, lvalue) pairs to extract and save after the function call is complete
1314 std::vector<std::tuple<SpvId, SpvId, std::unique_ptr<LValue>>> lvalues;
1315 std::vector<SpvId> arguments;
1316 for (size_t i = 0; i < c.fArguments.size(); i++) {
1317 // id of temporary variable that we will use to hold this argument, or 0 if it is being
1318 // passed directly
1319 SpvId tmpVar;
1320 // if we need a temporary var to store this argument, this is the value to store in the var
1321 SpvId tmpValueId;
ethannicholasd598f792016-07-25 10:08:54 -07001322 if (is_out(*c.fFunction.fParameters[i])) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001323 std::unique_ptr<LValue> lv = this->getLValue(*c.fArguments[i], out);
1324 SpvId ptr = lv->getPointer();
1325 if (ptr) {
1326 arguments.push_back(ptr);
1327 continue;
1328 } else {
1329 // lvalue cannot simply be read and written via a pointer (e.g. a swizzle). Need to
1330 // copy it into a temp, call the function, read the value out of the temp, and then
1331 // update the lvalue.
1332 tmpValueId = lv->load(out);
1333 tmpVar = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001334 lvalues.push_back(std::make_tuple(tmpVar, this->getType(c.fArguments[i]->fType),
ethannicholasb3058bd2016-07-01 08:22:01 -07001335 std::move(lv)));
1336 }
1337 } else {
1338 // see getFunctionType for an explanation of why we're always using pointer parameters
1339 tmpValueId = this->writeExpression(*c.fArguments[i], out);
1340 tmpVar = this->nextId();
1341 }
1342 this->writeInstruction(SpvOpVariable,
1343 this->getPointerType(c.fArguments[i]->fType,
1344 SpvStorageClassFunction),
1345 tmpVar,
1346 SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001347 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001348 this->writeInstruction(SpvOpStore, tmpVar, tmpValueId, out);
1349 arguments.push_back(tmpVar);
1350 }
1351 SpvId result = this->nextId();
1352 this->writeOpCode(SpvOpFunctionCall, 4 + (int32_t) c.fArguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001353 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001354 this->writeWord(result, out);
1355 this->writeWord(entry->second, out);
1356 for (SpvId id : arguments) {
1357 this->writeWord(id, out);
1358 }
1359 // now that the call is complete, we may need to update some lvalues with the new values of out
1360 // arguments
1361 for (const auto& tuple : lvalues) {
1362 SpvId load = this->nextId();
1363 this->writeInstruction(SpvOpLoad, std::get<1>(tuple), load, std::get<0>(tuple), out);
1364 std::get<2>(tuple)->store(load, out);
1365 }
1366 return result;
1367}
1368
ethannicholasf789b382016-08-03 12:43:36 -07001369SpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) {
ethannicholasd598f792016-07-25 10:08:54 -07001370 ASSERT(c.fType.kind() == Type::kVector_Kind && c.isConstant());
ethannicholasb3058bd2016-07-01 08:22:01 -07001371 SpvId result = this->nextId();
1372 std::vector<SpvId> arguments;
1373 for (size_t i = 0; i < c.fArguments.size(); i++) {
1374 arguments.push_back(this->writeExpression(*c.fArguments[i], fConstantBuffer));
1375 }
ethannicholasd598f792016-07-25 10:08:54 -07001376 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001377 if (c.fArguments.size() == 1) {
1378 // with a single argument, a vector will have all of its entries equal to the argument
ethannicholasd598f792016-07-25 10:08:54 -07001379 this->writeOpCode(SpvOpConstantComposite, 3 + c.fType.columns(), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001380 this->writeWord(type, fConstantBuffer);
1381 this->writeWord(result, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001382 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001383 this->writeWord(arguments[0], fConstantBuffer);
1384 }
1385 } else {
1386 this->writeOpCode(SpvOpConstantComposite, 3 + (int32_t) c.fArguments.size(),
1387 fConstantBuffer);
1388 this->writeWord(type, fConstantBuffer);
1389 this->writeWord(result, fConstantBuffer);
1390 for (SpvId id : arguments) {
1391 this->writeWord(id, fConstantBuffer);
1392 }
1393 }
1394 return result;
1395}
1396
ethannicholasf789b382016-08-03 12:43:36 -07001397SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, std::ostream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001398 ASSERT(c.fType == *fContext.fFloat_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07001399 ASSERT(c.fArguments.size() == 1);
ethannicholasd598f792016-07-25 10:08:54 -07001400 ASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001401 SpvId result = this->nextId();
1402 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
ethannicholasd598f792016-07-25 10:08:54 -07001403 if (c.fArguments[0]->fType == *fContext.fInt_Type) {
1404 this->writeInstruction(SpvOpConvertSToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001405 out);
ethannicholasd598f792016-07-25 10:08:54 -07001406 } else if (c.fArguments[0]->fType == *fContext.fUInt_Type) {
1407 this->writeInstruction(SpvOpConvertUToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001408 out);
ethannicholasd598f792016-07-25 10:08:54 -07001409 } else if (c.fArguments[0]->fType == *fContext.fFloat_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001410 return parameter;
1411 }
1412 return result;
1413}
1414
ethannicholasf789b382016-08-03 12:43:36 -07001415SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, std::ostream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001416 ASSERT(c.fType == *fContext.fInt_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07001417 ASSERT(c.fArguments.size() == 1);
ethannicholasd598f792016-07-25 10:08:54 -07001418 ASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001419 SpvId result = this->nextId();
1420 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
ethannicholasd598f792016-07-25 10:08:54 -07001421 if (c.fArguments[0]->fType == *fContext.fFloat_Type) {
1422 this->writeInstruction(SpvOpConvertFToS, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001423 out);
ethannicholasd598f792016-07-25 10:08:54 -07001424 } else if (c.fArguments[0]->fType == *fContext.fUInt_Type) {
1425 this->writeInstruction(SpvOpSatConvertUToS, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001426 out);
ethannicholasd598f792016-07-25 10:08:54 -07001427 } else if (c.fArguments[0]->fType == *fContext.fInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001428 return parameter;
1429 }
1430 return result;
1431}
1432
ethannicholasf789b382016-08-03 12:43:36 -07001433SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, std::ostream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001434 ASSERT(c.fType.kind() == Type::kMatrix_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001435 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1436 // an instruction
1437 std::vector<SpvId> arguments;
1438 for (size_t i = 0; i < c.fArguments.size(); i++) {
1439 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1440 }
1441 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001442 int rows = c.fType.rows();
1443 int columns = c.fType.columns();
ethannicholasb3058bd2016-07-01 08:22:01 -07001444 // FIXME this won't work to create a matrix from another matrix
1445 if (arguments.size() == 1) {
1446 // with a single argument, a matrix will have all of its diagonal entries equal to the
1447 // argument and its other values equal to zero
1448 // FIXME this won't work for int matrices
ethannicholasd598f792016-07-25 10:08:54 -07001449 FloatLiteral zero(fContext, Position(), 0);
ethannicholasb3058bd2016-07-01 08:22:01 -07001450 SpvId zeroId = this->writeFloatLiteral(zero);
1451 std::vector<SpvId> columnIds;
1452 for (int column = 0; column < columns; column++) {
ethannicholasd598f792016-07-25 10:08:54 -07001453 this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.rows(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001454 out);
ethannicholasd598f792016-07-25 10:08:54 -07001455 this->writeWord(this->getType(c.fType.componentType().toCompound(fContext, rows, 1)),
1456 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001457 SpvId columnId = this->nextId();
1458 this->writeWord(columnId, out);
1459 columnIds.push_back(columnId);
ethannicholasd598f792016-07-25 10:08:54 -07001460 for (int row = 0; row < c.fType.columns(); row++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001461 this->writeWord(row == column ? arguments[0] : zeroId, out);
1462 }
1463 }
1464 this->writeOpCode(SpvOpCompositeConstruct, 3 + columns,
1465 out);
ethannicholasd598f792016-07-25 10:08:54 -07001466 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001467 this->writeWord(result, out);
1468 for (SpvId id : columnIds) {
1469 this->writeWord(id, out);
1470 }
1471 } else {
1472 std::vector<SpvId> columnIds;
1473 int currentCount = 0;
1474 for (size_t i = 0; i < arguments.size(); i++) {
ethannicholasd598f792016-07-25 10:08:54 -07001475 if (c.fArguments[i]->fType.kind() == Type::kVector_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001476 ASSERT(currentCount == 0);
1477 columnIds.push_back(arguments[i]);
1478 currentCount = 0;
1479 } else {
ethannicholasd598f792016-07-25 10:08:54 -07001480 ASSERT(c.fArguments[i]->fType.kind() == Type::kScalar_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001481 if (currentCount == 0) {
ethannicholasd598f792016-07-25 10:08:54 -07001482 this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.rows(), out);
1483 this->writeWord(this->getType(c.fType.componentType().toCompound(fContext, rows,
1484 1)),
ethannicholasb3058bd2016-07-01 08:22:01 -07001485 out);
1486 SpvId id = this->nextId();
1487 this->writeWord(id, out);
1488 columnIds.push_back(id);
1489 }
1490 this->writeWord(arguments[i], out);
1491 currentCount = (currentCount + 1) % rows;
1492 }
1493 }
1494 ASSERT(columnIds.size() == (size_t) columns);
1495 this->writeOpCode(SpvOpCompositeConstruct, 3 + columns, out);
ethannicholasd598f792016-07-25 10:08:54 -07001496 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001497 this->writeWord(result, out);
1498 for (SpvId id : columnIds) {
1499 this->writeWord(id, out);
1500 }
1501 }
1502 return result;
1503}
1504
ethannicholasf789b382016-08-03 12:43:36 -07001505SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, std::ostream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001506 ASSERT(c.fType.kind() == Type::kVector_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001507 if (c.isConstant()) {
1508 return this->writeConstantVector(c);
1509 }
1510 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1511 // an instruction
1512 std::vector<SpvId> arguments;
1513 for (size_t i = 0; i < c.fArguments.size(); i++) {
1514 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1515 }
1516 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001517 if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) {
1518 this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.columns(), out);
1519 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001520 this->writeWord(result, out);
ethannicholasd598f792016-07-25 10:08:54 -07001521 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001522 this->writeWord(arguments[0], out);
1523 }
1524 } else {
1525 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) c.fArguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001526 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001527 this->writeWord(result, out);
1528 for (SpvId id : arguments) {
1529 this->writeWord(id, out);
1530 }
1531 }
1532 return result;
1533}
1534
ethannicholasf789b382016-08-03 12:43:36 -07001535SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, std::ostream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001536 if (c.fType == *fContext.fFloat_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001537 return this->writeFloatConstructor(c, out);
ethannicholasd598f792016-07-25 10:08:54 -07001538 } else if (c.fType == *fContext.fInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001539 return this->writeIntConstructor(c, out);
1540 }
ethannicholasd598f792016-07-25 10:08:54 -07001541 switch (c.fType.kind()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001542 case Type::kVector_Kind:
1543 return this->writeVectorConstructor(c, out);
1544 case Type::kMatrix_Kind:
1545 return this->writeMatrixConstructor(c, out);
1546 default:
1547 ABORT("unsupported constructor: %s", c.description().c_str());
1548 }
1549}
1550
1551SpvStorageClass_ get_storage_class(const Modifiers& modifiers) {
1552 if (modifiers.fFlags & Modifiers::kIn_Flag) {
1553 return SpvStorageClassInput;
1554 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
1555 return SpvStorageClassOutput;
1556 } else if (modifiers.fFlags & Modifiers::kUniform_Flag) {
1557 return SpvStorageClassUniform;
1558 } else {
1559 return SpvStorageClassFunction;
1560 }
1561}
1562
ethannicholasf789b382016-08-03 12:43:36 -07001563SpvStorageClass_ get_storage_class(const Expression& expr) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001564 switch (expr.fKind) {
1565 case Expression::kVariableReference_Kind:
ethannicholasd598f792016-07-25 10:08:54 -07001566 return get_storage_class(((VariableReference&) expr).fVariable.fModifiers);
ethannicholasb3058bd2016-07-01 08:22:01 -07001567 case Expression::kFieldAccess_Kind:
1568 return get_storage_class(*((FieldAccess&) expr).fBase);
1569 case Expression::kIndex_Kind:
1570 return get_storage_class(*((IndexExpression&) expr).fBase);
1571 default:
1572 return SpvStorageClassFunction;
1573 }
1574}
1575
ethannicholasf789b382016-08-03 12:43:36 -07001576std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001577 std::vector<SpvId> chain;
1578 switch (expr.fKind) {
1579 case Expression::kIndex_Kind: {
1580 IndexExpression& indexExpr = (IndexExpression&) expr;
1581 chain = this->getAccessChain(*indexExpr.fBase, out);
1582 chain.push_back(this->writeExpression(*indexExpr.fIndex, out));
1583 break;
1584 }
1585 case Expression::kFieldAccess_Kind: {
1586 FieldAccess& fieldExpr = (FieldAccess&) expr;
1587 chain = this->getAccessChain(*fieldExpr.fBase, out);
ethannicholasd598f792016-07-25 10:08:54 -07001588 IntLiteral index(fContext, Position(), fieldExpr.fFieldIndex);
ethannicholasb3058bd2016-07-01 08:22:01 -07001589 chain.push_back(this->writeIntLiteral(index));
1590 break;
1591 }
1592 default:
1593 chain.push_back(this->getLValue(expr, out)->getPointer());
1594 }
1595 return chain;
1596}
1597
1598class PointerLValue : public SPIRVCodeGenerator::LValue {
1599public:
1600 PointerLValue(SPIRVCodeGenerator& gen, SpvId pointer, SpvId type)
1601 : fGen(gen)
1602 , fPointer(pointer)
1603 , fType(type) {}
1604
1605 virtual SpvId getPointer() override {
1606 return fPointer;
1607 }
1608
1609 virtual SpvId load(std::ostream& out) override {
1610 SpvId result = fGen.nextId();
1611 fGen.writeInstruction(SpvOpLoad, fType, result, fPointer, out);
1612 return result;
1613 }
1614
1615 virtual void store(SpvId value, std::ostream& out) override {
1616 fGen.writeInstruction(SpvOpStore, fPointer, value, out);
1617 }
1618
1619private:
1620 SPIRVCodeGenerator& fGen;
1621 const SpvId fPointer;
1622 const SpvId fType;
1623};
1624
1625class SwizzleLValue : public SPIRVCodeGenerator::LValue {
1626public:
1627 SwizzleLValue(SPIRVCodeGenerator& gen, SpvId vecPointer, const std::vector<int>& components,
1628 const Type& baseType, const Type& swizzleType)
1629 : fGen(gen)
1630 , fVecPointer(vecPointer)
1631 , fComponents(components)
1632 , fBaseType(baseType)
1633 , fSwizzleType(swizzleType) {}
1634
1635 virtual SpvId getPointer() override {
1636 return 0;
1637 }
1638
1639 virtual SpvId load(std::ostream& out) override {
1640 SpvId base = fGen.nextId();
1641 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1642 SpvId result = fGen.nextId();
1643 fGen.writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) fComponents.size(), out);
1644 fGen.writeWord(fGen.getType(fSwizzleType), out);
1645 fGen.writeWord(result, out);
1646 fGen.writeWord(base, out);
1647 fGen.writeWord(base, out);
1648 for (int component : fComponents) {
1649 fGen.writeWord(component, out);
1650 }
1651 return result;
1652 }
1653
1654 virtual void store(SpvId value, std::ostream& out) override {
1655 // use OpVectorShuffle to mix and match the vector components. We effectively create
1656 // a virtual vector out of the concatenation of the left and right vectors, and then
1657 // select components from this virtual vector to make the result vector. For
1658 // instance, given:
1659 // vec3 L = ...;
1660 // vec3 R = ...;
1661 // L.xz = R.xy;
1662 // we end up with the virtual vector (L.x, L.y, L.z, R.x, R.y, R.z). Then we want
1663 // our result vector to look like (R.x, L.y, R.y), so we need to select indices
1664 // (3, 1, 4).
1665 SpvId base = fGen.nextId();
1666 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1667 SpvId shuffle = fGen.nextId();
1668 fGen.writeOpCode(SpvOpVectorShuffle, 5 + fBaseType.columns(), out);
1669 fGen.writeWord(fGen.getType(fBaseType), out);
1670 fGen.writeWord(shuffle, out);
1671 fGen.writeWord(base, out);
1672 fGen.writeWord(value, out);
1673 for (int i = 0; i < fBaseType.columns(); i++) {
1674 // current offset into the virtual vector, defaults to pulling the unmodified
1675 // value from the left side
1676 int offset = i;
1677 // check to see if we are writing this component
1678 for (size_t j = 0; j < fComponents.size(); j++) {
1679 if (fComponents[j] == i) {
1680 // we're writing to this component, so adjust the offset to pull from
1681 // the correct component of the right side instead of preserving the
1682 // value from the left
1683 offset = (int) (j + fBaseType.columns());
1684 break;
1685 }
1686 }
1687 fGen.writeWord(offset, out);
1688 }
1689 fGen.writeInstruction(SpvOpStore, fVecPointer, shuffle, out);
1690 }
1691
1692private:
1693 SPIRVCodeGenerator& fGen;
1694 const SpvId fVecPointer;
1695 const std::vector<int>& fComponents;
1696 const Type& fBaseType;
1697 const Type& fSwizzleType;
1698};
1699
ethannicholasf789b382016-08-03 12:43:36 -07001700std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const Expression& expr,
ethannicholasb3058bd2016-07-01 08:22:01 -07001701 std::ostream& out) {
1702 switch (expr.fKind) {
1703 case Expression::kVariableReference_Kind: {
ethannicholasd598f792016-07-25 10:08:54 -07001704 const Variable& var = ((VariableReference&) expr).fVariable;
1705 auto entry = fVariableMap.find(&var);
ethannicholasb3058bd2016-07-01 08:22:01 -07001706 ASSERT(entry != fVariableMap.end());
1707 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1708 *this,
1709 entry->second,
ethannicholasd598f792016-07-25 10:08:54 -07001710 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001711 }
1712 case Expression::kIndex_Kind: // fall through
1713 case Expression::kFieldAccess_Kind: {
1714 std::vector<SpvId> chain = this->getAccessChain(expr, out);
1715 SpvId member = this->nextId();
1716 this->writeOpCode(SpvOpAccessChain, (SpvId) (3 + chain.size()), out);
1717 this->writeWord(this->getPointerType(expr.fType, get_storage_class(expr)), out);
1718 this->writeWord(member, out);
1719 for (SpvId idx : chain) {
1720 this->writeWord(idx, out);
1721 }
1722 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1723 *this,
1724 member,
ethannicholasd598f792016-07-25 10:08:54 -07001725 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001726 }
1727
1728 case Expression::kSwizzle_Kind: {
1729 Swizzle& swizzle = (Swizzle&) expr;
1730 size_t count = swizzle.fComponents.size();
1731 SpvId base = this->getLValue(*swizzle.fBase, out)->getPointer();
1732 ASSERT(base);
1733 if (count == 1) {
ethannicholasd598f792016-07-25 10:08:54 -07001734 IntLiteral index(fContext, Position(), swizzle.fComponents[0]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001735 SpvId member = this->nextId();
1736 this->writeInstruction(SpvOpAccessChain,
1737 this->getPointerType(swizzle.fType,
1738 get_storage_class(*swizzle.fBase)),
1739 member,
1740 base,
1741 this->writeIntLiteral(index),
1742 out);
1743 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1744 *this,
1745 member,
ethannicholasd598f792016-07-25 10:08:54 -07001746 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001747 } else {
1748 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new SwizzleLValue(
1749 *this,
1750 base,
1751 swizzle.fComponents,
ethannicholasd598f792016-07-25 10:08:54 -07001752 swizzle.fBase->fType,
1753 expr.fType));
ethannicholasb3058bd2016-07-01 08:22:01 -07001754 }
1755 }
1756
1757 default:
1758 // expr isn't actually an lvalue, create a dummy variable for it. This case happens due
1759 // to the need to store values in temporary variables during function calls (see
1760 // comments in getFunctionType); erroneous uses of rvalues as lvalues should have been
1761 // caught by IRGenerator
1762 SpvId result = this->nextId();
1763 SpvId type = this->getPointerType(expr.fType, SpvStorageClassFunction);
ethannicholasd598f792016-07-25 10:08:54 -07001764 this->writeInstruction(SpvOpVariable, type, result, SpvStorageClassFunction,
1765 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001766 this->writeInstruction(SpvOpStore, result, this->writeExpression(expr, out), out);
1767 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1768 *this,
1769 result,
ethannicholasd598f792016-07-25 10:08:54 -07001770 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001771 }
1772}
1773
ethannicholasf789b382016-08-03 12:43:36 -07001774SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, std::ostream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001775 auto entry = fVariableMap.find(&ref.fVariable);
ethannicholasb3058bd2016-07-01 08:22:01 -07001776 ASSERT(entry != fVariableMap.end());
1777 SpvId var = entry->second;
1778 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001779 this->writeInstruction(SpvOpLoad, this->getType(ref.fVariable.fType), result, var, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001780 return result;
1781}
1782
ethannicholasf789b382016-08-03 12:43:36 -07001783SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001784 return getLValue(expr, out)->load(out);
1785}
1786
ethannicholasf789b382016-08-03 12:43:36 -07001787SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001788 return getLValue(f, out)->load(out);
1789}
1790
ethannicholasf789b382016-08-03 12:43:36 -07001791SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001792 SpvId base = this->writeExpression(*swizzle.fBase, out);
1793 SpvId result = this->nextId();
1794 size_t count = swizzle.fComponents.size();
1795 if (count == 1) {
ethannicholasd598f792016-07-25 10:08:54 -07001796 this->writeInstruction(SpvOpCompositeExtract, this->getType(swizzle.fType), result, base,
ethannicholasb3058bd2016-07-01 08:22:01 -07001797 swizzle.fComponents[0], out);
1798 } else {
1799 this->writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) count, out);
ethannicholasd598f792016-07-25 10:08:54 -07001800 this->writeWord(this->getType(swizzle.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001801 this->writeWord(result, out);
1802 this->writeWord(base, out);
1803 this->writeWord(base, out);
1804 for (int component : swizzle.fComponents) {
1805 this->writeWord(component, out);
1806 }
1807 }
1808 return result;
1809}
1810
1811SpvId SPIRVCodeGenerator::writeBinaryOperation(const Type& resultType,
1812 const Type& operandType, SpvId lhs,
1813 SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt,
1814 SpvOp_ ifUInt, SpvOp_ ifBool, std::ostream& out) {
1815 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001816 if (is_float(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001817 this->writeInstruction(ifFloat, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001818 } else if (is_signed(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001819 this->writeInstruction(ifInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001820 } else if (is_unsigned(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001821 this->writeInstruction(ifUInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001822 } else if (operandType == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001823 this->writeInstruction(ifBool, this->getType(resultType), result, lhs, rhs, out);
1824 } else {
1825 ABORT("invalid operandType: %s", operandType.description().c_str());
1826 }
1827 return result;
1828}
1829
1830bool is_assignment(Token::Kind op) {
1831 switch (op) {
1832 case Token::EQ: // fall through
1833 case Token::PLUSEQ: // fall through
1834 case Token::MINUSEQ: // fall through
1835 case Token::STAREQ: // fall through
1836 case Token::SLASHEQ: // fall through
1837 case Token::PERCENTEQ: // fall through
1838 case Token::SHLEQ: // fall through
1839 case Token::SHREQ: // fall through
1840 case Token::BITWISEOREQ: // fall through
1841 case Token::BITWISEXOREQ: // fall through
1842 case Token::BITWISEANDEQ: // fall through
1843 case Token::LOGICALOREQ: // fall through
1844 case Token::LOGICALXOREQ: // fall through
1845 case Token::LOGICALANDEQ:
1846 return true;
1847 default:
1848 return false;
1849 }
1850}
1851
ethannicholasf789b382016-08-03 12:43:36 -07001852SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001853 // handle cases where we don't necessarily evaluate both LHS and RHS
1854 switch (b.fOperator) {
1855 case Token::EQ: {
1856 SpvId rhs = this->writeExpression(*b.fRight, out);
1857 this->getLValue(*b.fLeft, out)->store(rhs, out);
1858 return rhs;
1859 }
1860 case Token::LOGICALAND:
1861 return this->writeLogicalAnd(b, out);
1862 case Token::LOGICALOR:
1863 return this->writeLogicalOr(b, out);
1864 default:
1865 break;
1866 }
1867
1868 // "normal" operators
ethannicholasd598f792016-07-25 10:08:54 -07001869 const Type& resultType = b.fType;
ethannicholasb3058bd2016-07-01 08:22:01 -07001870 std::unique_ptr<LValue> lvalue;
1871 SpvId lhs;
1872 if (is_assignment(b.fOperator)) {
1873 lvalue = this->getLValue(*b.fLeft, out);
1874 lhs = lvalue->load(out);
1875 } else {
1876 lvalue = nullptr;
1877 lhs = this->writeExpression(*b.fLeft, out);
1878 }
1879 SpvId rhs = this->writeExpression(*b.fRight, out);
1880 // component type we are operating on: float, int, uint
1881 const Type* operandType;
1882 // IR allows mismatched types in expressions (e.g. vec2 * float), but they need special handling
1883 // in SPIR-V
1884 if (b.fLeft->fType != b.fRight->fType) {
ethannicholasd598f792016-07-25 10:08:54 -07001885 if (b.fLeft->fType.kind() == Type::kVector_Kind &&
1886 b.fRight->fType.isNumber()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001887 // promote number to vector
1888 SpvId vec = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001889 this->writeOpCode(SpvOpCompositeConstruct, 3 + b.fType.columns(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001890 this->writeWord(this->getType(resultType), out);
1891 this->writeWord(vec, out);
1892 for (int i = 0; i < resultType.columns(); i++) {
1893 this->writeWord(rhs, out);
1894 }
1895 rhs = vec;
ethannicholasd598f792016-07-25 10:08:54 -07001896 operandType = &b.fRight->fType;
1897 } else if (b.fRight->fType.kind() == Type::kVector_Kind &&
1898 b.fLeft->fType.isNumber()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001899 // promote number to vector
1900 SpvId vec = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001901 this->writeOpCode(SpvOpCompositeConstruct, 3 + b.fType.columns(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001902 this->writeWord(this->getType(resultType), out);
1903 this->writeWord(vec, out);
1904 for (int i = 0; i < resultType.columns(); i++) {
1905 this->writeWord(lhs, out);
1906 }
1907 lhs = vec;
1908 ASSERT(!lvalue);
ethannicholasd598f792016-07-25 10:08:54 -07001909 operandType = &b.fLeft->fType;
1910 } else if (b.fLeft->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001911 SpvOp_ op;
ethannicholasd598f792016-07-25 10:08:54 -07001912 if (b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001913 op = SpvOpMatrixTimesMatrix;
ethannicholasd598f792016-07-25 10:08:54 -07001914 } else if (b.fRight->fType.kind() == Type::kVector_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001915 op = SpvOpMatrixTimesVector;
1916 } else {
ethannicholasd598f792016-07-25 10:08:54 -07001917 ASSERT(b.fRight->fType.kind() == Type::kScalar_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001918 op = SpvOpMatrixTimesScalar;
1919 }
1920 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001921 this->writeInstruction(op, this->getType(b.fType), result, lhs, rhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001922 if (b.fOperator == Token::STAREQ) {
1923 lvalue->store(result, out);
1924 } else {
1925 ASSERT(b.fOperator == Token::STAR);
1926 }
1927 return result;
ethannicholasd598f792016-07-25 10:08:54 -07001928 } else if (b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001929 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001930 if (b.fLeft->fType.kind() == Type::kVector_Kind) {
1931 this->writeInstruction(SpvOpVectorTimesMatrix, this->getType(b.fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07001932 lhs, rhs, out);
1933 } else {
ethannicholasd598f792016-07-25 10:08:54 -07001934 ASSERT(b.fLeft->fType.kind() == Type::kScalar_Kind);
1935 this->writeInstruction(SpvOpMatrixTimesScalar, this->getType(b.fType), result, rhs,
ethannicholasb3058bd2016-07-01 08:22:01 -07001936 lhs, out);
1937 }
1938 if (b.fOperator == Token::STAREQ) {
1939 lvalue->store(result, out);
1940 } else {
1941 ASSERT(b.fOperator == Token::STAR);
1942 }
1943 return result;
1944 } else {
1945 ABORT("unsupported binary expression: %s", b.description().c_str());
1946 }
1947 } else {
ethannicholasd598f792016-07-25 10:08:54 -07001948 operandType = &b.fLeft->fType;
1949 ASSERT(*operandType == b.fRight->fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001950 }
1951 switch (b.fOperator) {
1952 case Token::EQEQ:
ethannicholasd598f792016-07-25 10:08:54 -07001953 ASSERT(resultType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07001954 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdEqual,
1955 SpvOpIEqual, SpvOpIEqual, SpvOpLogicalEqual, out);
1956 case Token::NEQ:
ethannicholasd598f792016-07-25 10:08:54 -07001957 ASSERT(resultType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07001958 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdNotEqual,
1959 SpvOpINotEqual, SpvOpINotEqual, SpvOpLogicalNotEqual,
1960 out);
1961 case Token::GT:
ethannicholasd598f792016-07-25 10:08:54 -07001962 ASSERT(resultType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07001963 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
1964 SpvOpFOrdGreaterThan, SpvOpSGreaterThan,
1965 SpvOpUGreaterThan, SpvOpUndef, out);
1966 case Token::LT:
ethannicholasd598f792016-07-25 10:08:54 -07001967 ASSERT(resultType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07001968 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdLessThan,
1969 SpvOpSLessThan, SpvOpULessThan, SpvOpUndef, out);
1970 case Token::GTEQ:
ethannicholasd598f792016-07-25 10:08:54 -07001971 ASSERT(resultType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07001972 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
1973 SpvOpFOrdGreaterThanEqual, SpvOpSGreaterThanEqual,
1974 SpvOpUGreaterThanEqual, SpvOpUndef, out);
1975 case Token::LTEQ:
ethannicholasd598f792016-07-25 10:08:54 -07001976 ASSERT(resultType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07001977 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
1978 SpvOpFOrdLessThanEqual, SpvOpSLessThanEqual,
1979 SpvOpULessThanEqual, SpvOpUndef, out);
1980 case Token::PLUS:
1981 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
1982 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
1983 case Token::MINUS:
1984 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
1985 SpvOpISub, SpvOpISub, SpvOpUndef, out);
1986 case Token::STAR:
ethannicholasd598f792016-07-25 10:08:54 -07001987 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
1988 b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001989 // matrix multiply
1990 SpvId result = this->nextId();
1991 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
1992 lhs, rhs, out);
1993 return result;
1994 }
1995 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
1996 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
1997 case Token::SLASH:
1998 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
1999 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
2000 case Token::PLUSEQ: {
2001 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
2002 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2003 ASSERT(lvalue);
2004 lvalue->store(result, out);
2005 return result;
2006 }
2007 case Token::MINUSEQ: {
2008 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
2009 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2010 ASSERT(lvalue);
2011 lvalue->store(result, out);
2012 return result;
2013 }
2014 case Token::STAREQ: {
ethannicholasd598f792016-07-25 10:08:54 -07002015 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
2016 b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002017 // matrix multiply
2018 SpvId result = this->nextId();
2019 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2020 lhs, rhs, out);
2021 ASSERT(lvalue);
2022 lvalue->store(result, out);
2023 return result;
2024 }
2025 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
2026 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
2027 ASSERT(lvalue);
2028 lvalue->store(result, out);
2029 return result;
2030 }
2031 case Token::SLASHEQ: {
2032 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
2033 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
2034 ASSERT(lvalue);
2035 lvalue->store(result, out);
2036 return result;
2037 }
2038 default:
2039 // FIXME: missing support for some operators (bitwise, &&=, ||=, shift...)
2040 ABORT("unsupported binary expression: %s", b.description().c_str());
2041 }
2042}
2043
ethannicholasf789b382016-08-03 12:43:36 -07002044SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002045 ASSERT(a.fOperator == Token::LOGICALAND);
ethannicholasd598f792016-07-25 10:08:54 -07002046 BoolLiteral falseLiteral(fContext, Position(), false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002047 SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
2048 SpvId lhs = this->writeExpression(*a.fLeft, out);
2049 SpvId rhsLabel = this->nextId();
2050 SpvId end = this->nextId();
2051 SpvId lhsBlock = fCurrentBlock;
2052 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2053 this->writeInstruction(SpvOpBranchConditional, lhs, rhsLabel, end, out);
2054 this->writeLabel(rhsLabel, out);
2055 SpvId rhs = this->writeExpression(*a.fRight, out);
2056 SpvId rhsBlock = fCurrentBlock;
2057 this->writeInstruction(SpvOpBranch, end, out);
2058 this->writeLabel(end, out);
2059 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002060 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, falseConstant,
2061 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002062 return result;
2063}
2064
ethannicholasf789b382016-08-03 12:43:36 -07002065SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002066 ASSERT(o.fOperator == Token::LOGICALOR);
ethannicholasd598f792016-07-25 10:08:54 -07002067 BoolLiteral trueLiteral(fContext, Position(), true);
ethannicholasb3058bd2016-07-01 08:22:01 -07002068 SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
2069 SpvId lhs = this->writeExpression(*o.fLeft, out);
2070 SpvId rhsLabel = this->nextId();
2071 SpvId end = this->nextId();
2072 SpvId lhsBlock = fCurrentBlock;
2073 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2074 this->writeInstruction(SpvOpBranchConditional, lhs, end, rhsLabel, out);
2075 this->writeLabel(rhsLabel, out);
2076 SpvId rhs = this->writeExpression(*o.fRight, out);
2077 SpvId rhsBlock = fCurrentBlock;
2078 this->writeInstruction(SpvOpBranch, end, out);
2079 this->writeLabel(end, out);
2080 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002081 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, trueConstant,
2082 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002083 return result;
2084}
2085
ethannicholasf789b382016-08-03 12:43:36 -07002086SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002087 SpvId test = this->writeExpression(*t.fTest, out);
2088 if (t.fIfTrue->isConstant() && t.fIfFalse->isConstant()) {
2089 // both true and false are constants, can just use OpSelect
2090 SpvId result = this->nextId();
2091 SpvId trueId = this->writeExpression(*t.fIfTrue, out);
2092 SpvId falseId = this->writeExpression(*t.fIfFalse, out);
ethannicholasd598f792016-07-25 10:08:54 -07002093 this->writeInstruction(SpvOpSelect, this->getType(t.fType), result, test, trueId, falseId,
ethannicholasb3058bd2016-07-01 08:22:01 -07002094 out);
2095 return result;
2096 }
2097 // was originally using OpPhi to choose the result, but for some reason that is crashing on
2098 // Adreno. Switched to storing the result in a temp variable as glslang does.
2099 SpvId var = this->nextId();
2100 this->writeInstruction(SpvOpVariable, this->getPointerType(t.fType, SpvStorageClassFunction),
ethannicholasd598f792016-07-25 10:08:54 -07002101 var, SpvStorageClassFunction, fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002102 SpvId trueLabel = this->nextId();
2103 SpvId falseLabel = this->nextId();
2104 SpvId end = this->nextId();
2105 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2106 this->writeInstruction(SpvOpBranchConditional, test, trueLabel, falseLabel, out);
2107 this->writeLabel(trueLabel, out);
2108 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfTrue, out), out);
2109 this->writeInstruction(SpvOpBranch, end, out);
2110 this->writeLabel(falseLabel, out);
2111 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfFalse, out), out);
2112 this->writeInstruction(SpvOpBranch, end, out);
2113 this->writeLabel(end, out);
2114 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002115 this->writeInstruction(SpvOpLoad, this->getType(t.fType), result, var, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002116 return result;
2117}
2118
ethannicholasd598f792016-07-25 10:08:54 -07002119std::unique_ptr<Expression> create_literal_1(const Context& context, const Type& type) {
2120 if (type == *context.fInt_Type) {
2121 return std::unique_ptr<Expression>(new IntLiteral(context, Position(), 1));
ethannicholasb3058bd2016-07-01 08:22:01 -07002122 }
ethannicholasd598f792016-07-25 10:08:54 -07002123 else if (type == *context.fFloat_Type) {
2124 return std::unique_ptr<Expression>(new FloatLiteral(context, Position(), 1.0));
ethannicholasb3058bd2016-07-01 08:22:01 -07002125 } else {
2126 ABORT("math is unsupported on type '%s'")
2127 }
2128}
2129
ethannicholasf789b382016-08-03 12:43:36 -07002130SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002131 if (p.fOperator == Token::MINUS) {
2132 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002133 SpvId typeId = this->getType(p.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07002134 SpvId expr = this->writeExpression(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002135 if (is_float(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002136 this->writeInstruction(SpvOpFNegate, typeId, result, expr, out);
ethannicholasd598f792016-07-25 10:08:54 -07002137 } else if (is_signed(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002138 this->writeInstruction(SpvOpSNegate, typeId, result, expr, out);
2139 } else {
2140 ABORT("unsupported prefix expression %s", p.description().c_str());
2141 };
2142 return result;
2143 }
2144 switch (p.fOperator) {
2145 case Token::PLUS:
2146 return this->writeExpression(*p.fOperand, out);
2147 case Token::PLUSPLUS: {
2148 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002149 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
2150 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
ethannicholasb3058bd2016-07-01 08:22:01 -07002151 SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef,
2152 out);
2153 lv->store(result, out);
2154 return result;
2155 }
2156 case Token::MINUSMINUS: {
2157 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002158 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
2159 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
ethannicholasb3058bd2016-07-01 08:22:01 -07002160 SpvOpFSub, SpvOpISub, SpvOpISub, SpvOpUndef,
2161 out);
2162 lv->store(result, out);
2163 return result;
2164 }
2165 case Token::NOT: {
ethannicholasd598f792016-07-25 10:08:54 -07002166 ASSERT(p.fOperand->fType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002167 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002168 this->writeInstruction(SpvOpLogicalNot, this->getType(p.fOperand->fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002169 this->writeExpression(*p.fOperand, out), out);
2170 return result;
2171 }
2172 default:
2173 ABORT("unsupported prefix expression: %s", p.description().c_str());
2174 }
2175}
2176
ethannicholasf789b382016-08-03 12:43:36 -07002177SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002178 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
2179 SpvId result = lv->load(out);
ethannicholasd598f792016-07-25 10:08:54 -07002180 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002181 switch (p.fOperator) {
2182 case Token::PLUSPLUS: {
ethannicholasd598f792016-07-25 10:08:54 -07002183 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002184 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2185 lv->store(temp, out);
2186 return result;
2187 }
2188 case Token::MINUSMINUS: {
ethannicholasd598f792016-07-25 10:08:54 -07002189 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002190 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2191 lv->store(temp, out);
2192 return result;
2193 }
2194 default:
2195 ABORT("unsupported postfix expression %s", p.description().c_str());
2196 }
2197}
2198
ethannicholasf789b382016-08-03 12:43:36 -07002199SpvId SPIRVCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002200 if (b.fValue) {
2201 if (fBoolTrue == 0) {
2202 fBoolTrue = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002203 this->writeInstruction(SpvOpConstantTrue, this->getType(b.fType), fBoolTrue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002204 fConstantBuffer);
2205 }
2206 return fBoolTrue;
2207 } else {
2208 if (fBoolFalse == 0) {
2209 fBoolFalse = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002210 this->writeInstruction(SpvOpConstantFalse, this->getType(b.fType), fBoolFalse,
ethannicholasb3058bd2016-07-01 08:22:01 -07002211 fConstantBuffer);
2212 }
2213 return fBoolFalse;
2214 }
2215}
2216
ethannicholasf789b382016-08-03 12:43:36 -07002217SpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) {
ethannicholasd598f792016-07-25 10:08:54 -07002218 if (i.fType == *fContext.fInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002219 auto entry = fIntConstants.find(i.fValue);
2220 if (entry == fIntConstants.end()) {
2221 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002222 this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002223 fConstantBuffer);
2224 fIntConstants[i.fValue] = result;
2225 return result;
2226 }
2227 return entry->second;
2228 } else {
ethannicholasd598f792016-07-25 10:08:54 -07002229 ASSERT(i.fType == *fContext.fUInt_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002230 auto entry = fUIntConstants.find(i.fValue);
2231 if (entry == fUIntConstants.end()) {
2232 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002233 this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002234 fConstantBuffer);
2235 fUIntConstants[i.fValue] = result;
2236 return result;
2237 }
2238 return entry->second;
2239 }
2240}
2241
ethannicholasf789b382016-08-03 12:43:36 -07002242SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
ethannicholasd598f792016-07-25 10:08:54 -07002243 if (f.fType == *fContext.fFloat_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002244 float value = (float) f.fValue;
2245 auto entry = fFloatConstants.find(value);
2246 if (entry == fFloatConstants.end()) {
2247 SpvId result = this->nextId();
2248 uint32_t bits;
2249 ASSERT(sizeof(bits) == sizeof(value));
2250 memcpy(&bits, &value, sizeof(bits));
ethannicholasd598f792016-07-25 10:08:54 -07002251 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result, bits,
ethannicholasb3058bd2016-07-01 08:22:01 -07002252 fConstantBuffer);
2253 fFloatConstants[value] = result;
2254 return result;
2255 }
2256 return entry->second;
2257 } else {
ethannicholasd598f792016-07-25 10:08:54 -07002258 ASSERT(f.fType == *fContext.fDouble_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002259 auto entry = fDoubleConstants.find(f.fValue);
2260 if (entry == fDoubleConstants.end()) {
2261 SpvId result = this->nextId();
2262 uint64_t bits;
2263 ASSERT(sizeof(bits) == sizeof(f.fValue));
2264 memcpy(&bits, &f.fValue, sizeof(bits));
ethannicholasd598f792016-07-25 10:08:54 -07002265 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002266 bits & 0xffffffff, bits >> 32, fConstantBuffer);
2267 fDoubleConstants[f.fValue] = result;
2268 return result;
2269 }
2270 return entry->second;
2271 }
2272}
2273
ethannicholasd598f792016-07-25 10:08:54 -07002274SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, std::ostream& out) {
2275 SpvId result = fFunctionMap[&f];
2276 this->writeInstruction(SpvOpFunction, this->getType(f.fReturnType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002277 SpvFunctionControlMaskNone, this->getFunctionType(f), out);
ethannicholasd598f792016-07-25 10:08:54 -07002278 this->writeInstruction(SpvOpName, result, f.fName.c_str(), fNameBuffer);
2279 for (size_t i = 0; i < f.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002280 SpvId id = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002281 fVariableMap[f.fParameters[i]] = id;
ethannicholasb3058bd2016-07-01 08:22:01 -07002282 SpvId type;
ethannicholasd598f792016-07-25 10:08:54 -07002283 type = this->getPointerType(f.fParameters[i]->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002284 this->writeInstruction(SpvOpFunctionParameter, type, id, out);
2285 }
2286 return result;
2287}
2288
ethannicholasd598f792016-07-25 10:08:54 -07002289SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002290 SpvId result = this->writeFunctionStart(f.fDeclaration, out);
2291 this->writeLabel(this->nextId(), out);
ethannicholasd598f792016-07-25 10:08:54 -07002292 if (f.fDeclaration.fName == "main") {
ethannicholasb3058bd2016-07-01 08:22:01 -07002293 out << fGlobalInitializersBuffer.str();
2294 }
2295 std::stringstream bodyBuffer;
2296 this->writeBlock(*f.fBody, bodyBuffer);
2297 out << fVariableBuffer.str();
2298 fVariableBuffer.str("");
2299 out << bodyBuffer.str();
2300 if (fCurrentBlock) {
2301 this->writeInstruction(SpvOpReturn, out);
2302 }
2303 this->writeInstruction(SpvOpFunctionEnd, out);
2304 return result;
2305}
2306
2307void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target) {
2308 if (layout.fLocation >= 0) {
2309 this->writeInstruction(SpvOpDecorate, target, SpvDecorationLocation, layout.fLocation,
2310 fDecorationBuffer);
2311 }
2312 if (layout.fBinding >= 0) {
2313 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBinding, layout.fBinding,
2314 fDecorationBuffer);
2315 }
2316 if (layout.fIndex >= 0) {
2317 this->writeInstruction(SpvOpDecorate, target, SpvDecorationIndex, layout.fIndex,
2318 fDecorationBuffer);
2319 }
2320 if (layout.fSet >= 0) {
2321 this->writeInstruction(SpvOpDecorate, target, SpvDecorationDescriptorSet, layout.fSet,
2322 fDecorationBuffer);
2323 }
2324 if (layout.fBuiltin >= 0) {
2325 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBuiltIn, layout.fBuiltin,
2326 fDecorationBuffer);
2327 }
2328}
2329
2330void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int member) {
2331 if (layout.fLocation >= 0) {
2332 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationLocation,
2333 layout.fLocation, fDecorationBuffer);
2334 }
2335 if (layout.fBinding >= 0) {
2336 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBinding,
2337 layout.fBinding, fDecorationBuffer);
2338 }
2339 if (layout.fIndex >= 0) {
2340 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationIndex,
2341 layout.fIndex, fDecorationBuffer);
2342 }
2343 if (layout.fSet >= 0) {
2344 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationDescriptorSet,
2345 layout.fSet, fDecorationBuffer);
2346 }
2347 if (layout.fBuiltin >= 0) {
2348 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBuiltIn,
2349 layout.fBuiltin, fDecorationBuffer);
2350 }
2351}
2352
ethannicholasf789b382016-08-03 12:43:36 -07002353SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
ethannicholasd598f792016-07-25 10:08:54 -07002354 SpvId type = this->getType(intf.fVariable.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07002355 SpvId result = this->nextId();
2356 this->writeInstruction(SpvOpDecorate, type, SpvDecorationBlock, fDecorationBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07002357 SpvStorageClass_ storageClass = get_storage_class(intf.fVariable.fModifiers);
ethannicholasb3058bd2016-07-01 08:22:01 -07002358 SpvId ptrType = this->nextId();
2359 this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, type, fConstantBuffer);
2360 this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07002361 this->writeLayout(intf.fVariable.fModifiers.fLayout, result);
2362 fVariableMap[&intf.fVariable] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002363 return result;
2364}
2365
ethannicholasf789b382016-08-03 12:43:36 -07002366void SPIRVCodeGenerator::writeGlobalVars(const VarDeclaration& decl, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002367 for (size_t i = 0; i < decl.fVars.size(); i++) {
ethannicholasd598f792016-07-25 10:08:54 -07002368 if (!decl.fVars[i]->fIsReadFrom && !decl.fVars[i]->fIsWrittenTo &&
2369 !(decl.fVars[i]->fModifiers.fFlags & (Modifiers::kIn_Flag |
2370 Modifiers::kOut_Flag |
2371 Modifiers::kUniform_Flag))) {
2372 // variable is dead and not an input / output var (the Vulkan debug layers complain if
2373 // we elide an interface var, even if it's dead)
ethannicholasb3058bd2016-07-01 08:22:01 -07002374 continue;
2375 }
2376 SpvStorageClass_ storageClass;
2377 if (decl.fVars[i]->fModifiers.fFlags & Modifiers::kIn_Flag) {
2378 storageClass = SpvStorageClassInput;
2379 } else if (decl.fVars[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
2380 storageClass = SpvStorageClassOutput;
2381 } else if (decl.fVars[i]->fModifiers.fFlags & Modifiers::kUniform_Flag) {
ethannicholasd598f792016-07-25 10:08:54 -07002382 if (decl.fVars[i]->fType.kind() == Type::kSampler_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002383 storageClass = SpvStorageClassUniformConstant;
2384 } else {
2385 storageClass = SpvStorageClassUniform;
2386 }
2387 } else {
2388 storageClass = SpvStorageClassPrivate;
2389 }
2390 SpvId id = this->nextId();
2391 fVariableMap[decl.fVars[i]] = id;
2392 SpvId type = this->getPointerType(decl.fVars[i]->fType, storageClass);
2393 this->writeInstruction(SpvOpVariable, type, id, storageClass, fConstantBuffer);
2394 this->writeInstruction(SpvOpName, id, decl.fVars[i]->fName.c_str(), fNameBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07002395 if (decl.fVars[i]->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002396 this->writeInstruction(SpvOpMemberDecorate, id, (SpvId) i, SpvDecorationColMajor,
2397 fDecorationBuffer);
2398 this->writeInstruction(SpvOpMemberDecorate, id, (SpvId) i, SpvDecorationMatrixStride,
ethannicholasd598f792016-07-25 10:08:54 -07002399 (SpvId) decl.fVars[i]->fType.stride(), fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002400 }
2401 if (decl.fValues[i]) {
ethannicholasf789b382016-08-03 12:43:36 -07002402 ASSERT(!fCurrentBlock);
2403 fCurrentBlock = -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002404 SpvId value = this->writeExpression(*decl.fValues[i], fGlobalInitializersBuffer);
2405 this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
ethannicholasf789b382016-08-03 12:43:36 -07002406 fCurrentBlock = 0;
ethannicholasb3058bd2016-07-01 08:22:01 -07002407 }
2408 this->writeLayout(decl.fVars[i]->fModifiers.fLayout, id);
2409 }
2410}
2411
ethannicholasf789b382016-08-03 12:43:36 -07002412void SPIRVCodeGenerator::writeVarDeclaration(const VarDeclaration& decl, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002413 for (size_t i = 0; i < decl.fVars.size(); i++) {
2414 SpvId id = this->nextId();
2415 fVariableMap[decl.fVars[i]] = id;
2416 SpvId type = this->getPointerType(decl.fVars[i]->fType, SpvStorageClassFunction);
2417 this->writeInstruction(SpvOpVariable, type, id, SpvStorageClassFunction, fVariableBuffer);
2418 this->writeInstruction(SpvOpName, id, decl.fVars[i]->fName.c_str(), fNameBuffer);
2419 if (decl.fValues[i]) {
2420 SpvId value = this->writeExpression(*decl.fValues[i], out);
2421 this->writeInstruction(SpvOpStore, id, value, out);
2422 }
2423 }
2424}
2425
ethannicholasf789b382016-08-03 12:43:36 -07002426void SPIRVCodeGenerator::writeStatement(const Statement& s, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002427 switch (s.fKind) {
2428 case Statement::kBlock_Kind:
2429 this->writeBlock((Block&) s, out);
2430 break;
2431 case Statement::kExpression_Kind:
2432 this->writeExpression(*((ExpressionStatement&) s).fExpression, out);
2433 break;
2434 case Statement::kReturn_Kind:
2435 this->writeReturnStatement((ReturnStatement&) s, out);
2436 break;
2437 case Statement::kVarDeclaration_Kind:
2438 this->writeVarDeclaration(*((VarDeclarationStatement&) s).fDeclaration, out);
2439 break;
2440 case Statement::kIf_Kind:
2441 this->writeIfStatement((IfStatement&) s, out);
2442 break;
2443 case Statement::kFor_Kind:
2444 this->writeForStatement((ForStatement&) s, out);
2445 break;
2446 case Statement::kBreak_Kind:
2447 this->writeInstruction(SpvOpBranch, fBreakTarget.top(), out);
2448 break;
2449 case Statement::kContinue_Kind:
2450 this->writeInstruction(SpvOpBranch, fContinueTarget.top(), out);
2451 break;
2452 case Statement::kDiscard_Kind:
2453 this->writeInstruction(SpvOpKill, out);
2454 break;
2455 default:
2456 ABORT("unsupported statement: %s", s.description().c_str());
2457 }
2458}
2459
ethannicholasf789b382016-08-03 12:43:36 -07002460void SPIRVCodeGenerator::writeBlock(const Block& b, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002461 for (size_t i = 0; i < b.fStatements.size(); i++) {
2462 this->writeStatement(*b.fStatements[i], out);
2463 }
2464}
2465
ethannicholasf789b382016-08-03 12:43:36 -07002466void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002467 SpvId test = this->writeExpression(*stmt.fTest, out);
2468 SpvId ifTrue = this->nextId();
2469 SpvId ifFalse = this->nextId();
2470 if (stmt.fIfFalse) {
2471 SpvId end = this->nextId();
2472 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2473 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2474 this->writeLabel(ifTrue, out);
2475 this->writeStatement(*stmt.fIfTrue, out);
2476 if (fCurrentBlock) {
2477 this->writeInstruction(SpvOpBranch, end, out);
2478 }
2479 this->writeLabel(ifFalse, out);
2480 this->writeStatement(*stmt.fIfFalse, out);
2481 if (fCurrentBlock) {
2482 this->writeInstruction(SpvOpBranch, end, out);
2483 }
2484 this->writeLabel(end, out);
2485 } else {
2486 this->writeInstruction(SpvOpSelectionMerge, ifFalse, SpvSelectionControlMaskNone, out);
2487 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2488 this->writeLabel(ifTrue, out);
2489 this->writeStatement(*stmt.fIfTrue, out);
2490 if (fCurrentBlock) {
2491 this->writeInstruction(SpvOpBranch, ifFalse, out);
2492 }
2493 this->writeLabel(ifFalse, out);
2494 }
2495}
2496
ethannicholasf789b382016-08-03 12:43:36 -07002497void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002498 if (f.fInitializer) {
2499 this->writeStatement(*f.fInitializer, out);
2500 }
2501 SpvId header = this->nextId();
2502 SpvId start = this->nextId();
2503 SpvId body = this->nextId();
2504 SpvId next = this->nextId();
2505 fContinueTarget.push(next);
2506 SpvId end = this->nextId();
2507 fBreakTarget.push(end);
2508 this->writeInstruction(SpvOpBranch, header, out);
2509 this->writeLabel(header, out);
2510 this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
ethannicholasf789b382016-08-03 12:43:36 -07002511 this->writeInstruction(SpvOpBranch, start, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002512 this->writeLabel(start, out);
2513 SpvId test = this->writeExpression(*f.fTest, out);
2514 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2515 this->writeLabel(body, out);
2516 this->writeStatement(*f.fStatement, out);
2517 if (fCurrentBlock) {
2518 this->writeInstruction(SpvOpBranch, next, out);
2519 }
2520 this->writeLabel(next, out);
2521 if (f.fNext) {
2522 this->writeExpression(*f.fNext, out);
2523 }
2524 this->writeInstruction(SpvOpBranch, header, out);
2525 this->writeLabel(end, out);
2526 fBreakTarget.pop();
2527 fContinueTarget.pop();
2528}
2529
ethannicholasf789b382016-08-03 12:43:36 -07002530void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002531 if (r.fExpression) {
2532 this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.fExpression, out),
2533 out);
2534 } else {
2535 this->writeInstruction(SpvOpReturn, out);
2536 }
2537}
2538
ethannicholasf789b382016-08-03 12:43:36 -07002539void SPIRVCodeGenerator::writeInstructions(const Program& program, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002540 fGLSLExtendedInstructions = this->nextId();
2541 std::stringstream body;
2542 std::vector<SpvId> interfaceVars;
2543 // assign IDs to functions
2544 for (size_t i = 0; i < program.fElements.size(); i++) {
2545 if (program.fElements[i]->fKind == ProgramElement::kFunction_Kind) {
2546 FunctionDefinition& f = (FunctionDefinition&) *program.fElements[i];
ethannicholasd598f792016-07-25 10:08:54 -07002547 fFunctionMap[&f.fDeclaration] = this->nextId();
ethannicholasb3058bd2016-07-01 08:22:01 -07002548 }
2549 }
2550 for (size_t i = 0; i < program.fElements.size(); i++) {
2551 if (program.fElements[i]->fKind == ProgramElement::kInterfaceBlock_Kind) {
2552 InterfaceBlock& intf = (InterfaceBlock&) *program.fElements[i];
2553 SpvId id = this->writeInterfaceBlock(intf);
ethannicholasd598f792016-07-25 10:08:54 -07002554 if ((intf.fVariable.fModifiers.fFlags & Modifiers::kIn_Flag) ||
2555 (intf.fVariable.fModifiers.fFlags & Modifiers::kOut_Flag)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002556 interfaceVars.push_back(id);
2557 }
2558 }
2559 }
2560 for (size_t i = 0; i < program.fElements.size(); i++) {
2561 if (program.fElements[i]->fKind == ProgramElement::kVar_Kind) {
2562 this->writeGlobalVars(((VarDeclaration&) *program.fElements[i]), body);
2563 }
2564 }
2565 for (size_t i = 0; i < program.fElements.size(); i++) {
2566 if (program.fElements[i]->fKind == ProgramElement::kFunction_Kind) {
2567 this->writeFunction(((FunctionDefinition&) *program.fElements[i]), body);
2568 }
2569 }
ethannicholasd598f792016-07-25 10:08:54 -07002570 const FunctionDeclaration* main = nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -07002571 for (auto entry : fFunctionMap) {
ethannicholasf789b382016-08-03 12:43:36 -07002572 if (entry.first->fName == "main") {
ethannicholasb3058bd2016-07-01 08:22:01 -07002573 main = entry.first;
2574 }
2575 }
2576 ASSERT(main);
2577 for (auto entry : fVariableMap) {
ethannicholasd598f792016-07-25 10:08:54 -07002578 const Variable* var = entry.first;
ethannicholasb3058bd2016-07-01 08:22:01 -07002579 if (var->fStorage == Variable::kGlobal_Storage &&
2580 ((var->fModifiers.fFlags & Modifiers::kIn_Flag) ||
2581 (var->fModifiers.fFlags & Modifiers::kOut_Flag))) {
2582 interfaceVars.push_back(entry.second);
2583 }
2584 }
2585 this->writeCapabilities(out);
2586 this->writeInstruction(SpvOpExtInstImport, fGLSLExtendedInstructions, "GLSL.std.450", out);
2587 this->writeInstruction(SpvOpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450, out);
2588 this->writeOpCode(SpvOpEntryPoint, (SpvId) (3 + (strlen(main->fName.c_str()) + 4) / 4) +
2589 (int32_t) interfaceVars.size(), out);
2590 switch (program.fKind) {
2591 case Program::kVertex_Kind:
2592 this->writeWord(SpvExecutionModelVertex, out);
2593 break;
2594 case Program::kFragment_Kind:
2595 this->writeWord(SpvExecutionModelFragment, out);
2596 break;
2597 }
2598 this->writeWord(fFunctionMap[main], out);
2599 this->writeString(main->fName.c_str(), out);
2600 for (int var : interfaceVars) {
2601 this->writeWord(var, out);
2602 }
2603 if (program.fKind == Program::kFragment_Kind) {
2604 this->writeInstruction(SpvOpExecutionMode,
2605 fFunctionMap[main],
2606 SpvExecutionModeOriginUpperLeft,
2607 out);
2608 }
2609 for (size_t i = 0; i < program.fElements.size(); i++) {
2610 if (program.fElements[i]->fKind == ProgramElement::kExtension_Kind) {
2611 this->writeInstruction(SpvOpSourceExtension,
2612 ((Extension&) *program.fElements[i]).fName.c_str(),
2613 out);
2614 }
2615 }
2616
2617 out << fNameBuffer.str();
2618 out << fDecorationBuffer.str();
2619 out << fConstantBuffer.str();
2620 out << fExternalFunctionsBuffer.str();
2621 out << body.str();
2622}
2623
ethannicholasf789b382016-08-03 12:43:36 -07002624void SPIRVCodeGenerator::generateCode(const Program& program, std::ostream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002625 this->writeWord(SpvMagicNumber, out);
2626 this->writeWord(SpvVersion, out);
2627 this->writeWord(SKSL_MAGIC, out);
2628 std::stringstream buffer;
2629 this->writeInstructions(program, buffer);
2630 this->writeWord(fIdCount, out);
2631 this->writeWord(0, out); // reserved, always zero
2632 out << buffer.str();
2633}
2634
2635}