1 /*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "src/sksl/ir/SkSLType.h"
9
10 #include "include/private/SkSLLayout.h"
11 #include "include/private/SkSLString.h"
12 #include "include/sksl/SkSLErrorReporter.h"
13 #include "src/base/SkMathPriv.h"
14 #include "src/base/SkSafeMath.h"
15 #include "src/sksl/SkSLBuiltinTypes.h"
16 #include "src/sksl/SkSLConstantFolder.h"
17 #include "src/sksl/SkSLContext.h"
18 #include "src/sksl/SkSLProgramSettings.h"
19 #include "src/sksl/ir/SkSLConstructorArrayCast.h"
20 #include "src/sksl/ir/SkSLConstructorCompoundCast.h"
21 #include "src/sksl/ir/SkSLConstructorScalarCast.h"
22 #include "src/sksl/ir/SkSLExpression.h"
23 #include "src/sksl/ir/SkSLSymbolTable.h"
24
25 #include <algorithm>
26 #include <cstdint>
27 #include <limits>
28 #include <optional>
29 #include <string_view>
30 #include <utility>
31
32 namespace SkSL {
33
34 static constexpr int kMaxStructDepth = 8;
35
36 class AliasType final : public Type {
37 public:
AliasType(std::string_view name,const Type & targetType)38 AliasType(std::string_view name, const Type& targetType)
39 : INHERITED(name, targetType.abbreviatedName(), targetType.typeKind())
40 , fTargetType(targetType) {}
41
resolve() const42 const Type& resolve() const override {
43 return fTargetType;
44 }
45
componentType() const46 const Type& componentType() const override {
47 return fTargetType.componentType();
48 }
49
numberKind() const50 NumberKind numberKind() const override {
51 return fTargetType.numberKind();
52 }
53
priority() const54 int priority() const override {
55 return fTargetType.priority();
56 }
57
columns() const58 int columns() const override {
59 return fTargetType.columns();
60 }
61
rows() const62 int rows() const override {
63 return fTargetType.rows();
64 }
65
bitWidth() const66 int bitWidth() const override {
67 return fTargetType.bitWidth();
68 }
69
isAllowedInES2() const70 bool isAllowedInES2() const override {
71 return fTargetType.isAllowedInES2();
72 }
73
slotCount() const74 size_t slotCount() const override {
75 return fTargetType.slotCount();
76 }
77
dimensions() const78 SpvDim_ dimensions() const override {
79 return fTargetType.dimensions();
80 }
81
isDepth() const82 bool isDepth() const override {
83 return fTargetType.isDepth();
84 }
85
isArrayedTexture() const86 bool isArrayedTexture() const override {
87 return fTargetType.isArrayedTexture();
88 }
89
isScalar() const90 bool isScalar() const override {
91 return fTargetType.isScalar();
92 }
93
isLiteral() const94 bool isLiteral() const override {
95 return fTargetType.isLiteral();
96 }
97
isVector() const98 bool isVector() const override {
99 return fTargetType.isVector();
100 }
101
isMatrix() const102 bool isMatrix() const override {
103 return fTargetType.isMatrix();
104 }
105
isArray() const106 bool isArray() const override {
107 return fTargetType.isArray();
108 }
109
isUnsizedArray() const110 bool isUnsizedArray() const override {
111 return fTargetType.isUnsizedArray();
112 }
113
isStruct() const114 bool isStruct() const override {
115 return fTargetType.isStruct();
116 }
117
isInterfaceBlock() const118 bool isInterfaceBlock() const override {
119 return fTargetType.isInterfaceBlock();
120 }
121
isMultisampled() const122 bool isMultisampled() const override {
123 return fTargetType.isMultisampled();
124 }
125
textureAccess() const126 TextureAccess textureAccess() const override {
127 return fTargetType.textureAccess();
128 }
129
coercibleTypes() const130 SkSpan<const Type* const> coercibleTypes() const override {
131 return fTargetType.coercibleTypes();
132 }
133
134 private:
135 using INHERITED = Type;
136
137 const Type& fTargetType;
138 };
139
140 class ArrayType final : public Type {
141 public:
142 inline static constexpr TypeKind kTypeKind = TypeKind::kArray;
143
ArrayType(std::string_view name,const char * abbrev,const Type & componentType,int count)144 ArrayType(std::string_view name, const char* abbrev, const Type& componentType, int count)
145 : INHERITED(name, abbrev, kTypeKind)
146 , fComponentType(componentType)
147 , fCount(count) {
148 SkASSERT(count > 0 || count == kUnsizedArray);
149 // Disallow multi-dimensional arrays.
150 SkASSERT(!componentType.is<ArrayType>());
151 }
152
isArray() const153 bool isArray() const override {
154 return true;
155 }
156
isUnsizedArray() const157 bool isUnsizedArray() const override {
158 return fCount == kUnsizedArray;
159 }
160
componentType() const161 const Type& componentType() const override {
162 return fComponentType;
163 }
164
columns() const165 int columns() const override {
166 return fCount;
167 }
168
bitWidth() const169 int bitWidth() const override {
170 return this->componentType().bitWidth();
171 }
172
isAllowedInES2() const173 bool isAllowedInES2() const override {
174 return fComponentType.isAllowedInES2();
175 }
176
slotCount() const177 size_t slotCount() const override {
178 SkASSERT(fCount != kUnsizedArray);
179 SkASSERT(fCount > 0);
180 return fCount * fComponentType.slotCount();
181 }
182
183 private:
184 using INHERITED = Type;
185
186 const Type& fComponentType;
187 int fCount;
188 };
189
190 class GenericType final : public Type {
191 public:
192 inline static constexpr TypeKind kTypeKind = TypeKind::kGeneric;
193
GenericType(const char * name,SkSpan<const Type * const> coercibleTypes)194 GenericType(const char* name, SkSpan<const Type* const> coercibleTypes)
195 : INHERITED(name, "G", kTypeKind) {
196 fNumTypes = coercibleTypes.size();
197 SkASSERT(fNumTypes <= std::size(fCoercibleTypes));
198 std::copy(coercibleTypes.begin(), coercibleTypes.end(), fCoercibleTypes);
199 }
200
coercibleTypes() const201 SkSpan<const Type* const> coercibleTypes() const override {
202 return SkSpan(fCoercibleTypes, fNumTypes);
203 }
204
205 private:
206 using INHERITED = Type;
207
208 const Type* fCoercibleTypes[9];
209 size_t fNumTypes;
210 };
211
212 class LiteralType : public Type {
213 public:
214 inline static constexpr TypeKind kTypeKind = TypeKind::kLiteral;
215
LiteralType(const char * name,const Type & scalarType,int8_t priority)216 LiteralType(const char* name, const Type& scalarType, int8_t priority)
217 : INHERITED(name, "L", kTypeKind)
218 , fScalarType(scalarType)
219 , fPriority(priority) {}
220
scalarTypeForLiteral() const221 const Type& scalarTypeForLiteral() const override {
222 return fScalarType;
223 }
224
priority() const225 int priority() const override {
226 return fPriority;
227 }
228
columns() const229 int columns() const override {
230 return 1;
231 }
232
rows() const233 int rows() const override {
234 return 1;
235 }
236
numberKind() const237 NumberKind numberKind() const override {
238 return fScalarType.numberKind();
239 }
240
bitWidth() const241 int bitWidth() const override {
242 return fScalarType.bitWidth();
243 }
244
minimumValue() const245 double minimumValue() const override {
246 return fScalarType.minimumValue();
247 }
248
maximumValue() const249 double maximumValue() const override {
250 return fScalarType.maximumValue();
251 }
252
isScalar() const253 bool isScalar() const override {
254 return true;
255 }
256
isLiteral() const257 bool isLiteral() const override {
258 return true;
259 }
260
slotCount() const261 size_t slotCount() const override {
262 return 1;
263 }
264
265 private:
266 using INHERITED = Type;
267
268 const Type& fScalarType;
269 int8_t fPriority;
270 };
271
272
273 class ScalarType final : public Type {
274 public:
275 inline static constexpr TypeKind kTypeKind = TypeKind::kScalar;
276
ScalarType(std::string_view name,const char * abbrev,NumberKind numberKind,int8_t priority,int8_t bitWidth)277 ScalarType(std::string_view name, const char* abbrev, NumberKind numberKind, int8_t priority,
278 int8_t bitWidth)
279 : INHERITED(name, abbrev, kTypeKind)
280 , fNumberKind(numberKind)
281 , fPriority(priority)
282 , fBitWidth(bitWidth) {}
283
numberKind() const284 NumberKind numberKind() const override {
285 return fNumberKind;
286 }
287
priority() const288 int priority() const override {
289 return fPriority;
290 }
291
bitWidth() const292 int bitWidth() const override {
293 return fBitWidth;
294 }
295
columns() const296 int columns() const override {
297 return 1;
298 }
299
rows() const300 int rows() const override {
301 return 1;
302 }
303
isScalar() const304 bool isScalar() const override {
305 return true;
306 }
307
isAllowedInES2() const308 bool isAllowedInES2() const override {
309 return fNumberKind != NumberKind::kUnsigned;
310 }
311
slotCount() const312 size_t slotCount() const override {
313 return 1;
314 }
315
316 using int_limits = std::numeric_limits<int32_t>;
317 using short_limits = std::numeric_limits<int16_t>;
318 using uint_limits = std::numeric_limits<uint32_t>;
319 using ushort_limits = std::numeric_limits<uint16_t>;
320 using float_limits = std::numeric_limits<float>;
321
322 /** Returns the maximum value that can fit in the type. */
minimumValue() const323 double minimumValue() const override {
324 switch (this->numberKind()) {
325 case NumberKind::kSigned:
326 return this->highPrecision() ? int_limits::lowest()
327 : short_limits::lowest();
328
329 case NumberKind::kUnsigned:
330 return 0;
331
332 case NumberKind::kFloat:
333 default:
334 return float_limits::lowest();
335 }
336 }
337
338 /** Returns the maximum value that can fit in the type. */
maximumValue() const339 double maximumValue() const override {
340 switch (this->numberKind()) {
341 case NumberKind::kSigned:
342 return this->highPrecision() ? int_limits::max()
343 : short_limits::max();
344
345 case NumberKind::kUnsigned:
346 return this->highPrecision() ? uint_limits::max()
347 : ushort_limits::max();
348
349 case NumberKind::kFloat:
350 default:
351 return float_limits::max();
352 }
353 }
354
355 private:
356 using INHERITED = Type;
357
358 NumberKind fNumberKind;
359 int8_t fPriority;
360 int8_t fBitWidth;
361 };
362
363 class AtomicType final : public Type {
364 public:
365 inline static constexpr TypeKind kTypeKind = TypeKind::kAtomic;
366
AtomicType(std::string_view name,const char * abbrev)367 AtomicType(std::string_view name, const char* abbrev) : INHERITED(name, abbrev, kTypeKind) {}
368
isAllowedInES2() const369 bool isAllowedInES2() const override { return false; }
370
371 private:
372 using INHERITED = Type;
373 };
374
375 class MatrixType final : public Type {
376 public:
377 inline static constexpr TypeKind kTypeKind = TypeKind::kMatrix;
378
MatrixType(std::string_view name,const char * abbrev,const Type & componentType,int8_t columns,int8_t rows)379 MatrixType(std::string_view name, const char* abbrev, const Type& componentType,
380 int8_t columns, int8_t rows)
381 : INHERITED(name, abbrev, kTypeKind)
382 , fComponentType(componentType.as<ScalarType>())
383 , fColumns(columns)
384 , fRows(rows) {
385 SkASSERT(columns >= 2 && columns <= 4);
386 SkASSERT(rows >= 2 && rows <= 4);
387 }
388
componentType() const389 const ScalarType& componentType() const override {
390 return fComponentType;
391 }
392
columns() const393 int columns() const override {
394 return fColumns;
395 }
396
rows() const397 int rows() const override {
398 return fRows;
399 }
400
bitWidth() const401 int bitWidth() const override {
402 return this->componentType().bitWidth();
403 }
404
isMatrix() const405 bool isMatrix() const override {
406 return true;
407 }
408
isAllowedInES2() const409 bool isAllowedInES2() const override {
410 return fColumns == fRows;
411 }
412
slotCount() const413 size_t slotCount() const override {
414 return fColumns * fRows;
415 }
416
417 private:
418 using INHERITED = Type;
419
420 const ScalarType& fComponentType;
421 int8_t fColumns;
422 int8_t fRows;
423 };
424
425 class TextureType final : public Type {
426 public:
427 inline static constexpr TypeKind kTypeKind = TypeKind::kTexture;
428
TextureType(const char * name,SpvDim_ dimensions,bool isDepth,bool isArrayed,bool isMultisampled,TextureAccess textureAccess)429 TextureType(const char* name, SpvDim_ dimensions, bool isDepth, bool isArrayed,
430 bool isMultisampled, TextureAccess textureAccess)
431 : INHERITED(name, "T", kTypeKind)
432 , fDimensions(dimensions)
433 , fIsDepth(isDepth)
434 , fIsArrayed(isArrayed)
435 , fIsMultisampled(isMultisampled)
436 , fTextureAccess(textureAccess) {}
437
dimensions() const438 SpvDim_ dimensions() const override {
439 return fDimensions;
440 }
441
isDepth() const442 bool isDepth() const override {
443 return fIsDepth;
444 }
445
isArrayedTexture() const446 bool isArrayedTexture() const override {
447 return fIsArrayed;
448 }
449
isMultisampled() const450 bool isMultisampled() const override {
451 return fIsMultisampled;
452 }
453
textureAccess() const454 TextureAccess textureAccess() const override {
455 return fTextureAccess;
456 }
457
458 private:
459 using INHERITED = Type;
460
461 SpvDim_ fDimensions;
462 bool fIsDepth;
463 bool fIsArrayed;
464 bool fIsMultisampled;
465 TextureAccess fTextureAccess;
466 };
467
468 class SamplerType final : public Type {
469 public:
470 inline static constexpr TypeKind kTypeKind = TypeKind::kSampler;
471
SamplerType(const char * name,const Type & textureType)472 SamplerType(const char* name, const Type& textureType)
473 : INHERITED(name, "Z", kTypeKind)
474 , fTextureType(textureType.as<TextureType>()) {}
475
textureType() const476 const TextureType& textureType() const override {
477 return fTextureType;
478 }
479
dimensions() const480 SpvDim_ dimensions() const override {
481 return fTextureType.dimensions();
482 }
483
isDepth() const484 bool isDepth() const override {
485 return fTextureType.isDepth();
486 }
487
isArrayedTexture() const488 bool isArrayedTexture() const override {
489 return fTextureType.isArrayedTexture();
490 }
491
isMultisampled() const492 bool isMultisampled() const override {
493 return fTextureType.isMultisampled();
494 }
495
textureAccess() const496 TextureAccess textureAccess() const override {
497 return fTextureType.textureAccess();
498 }
499
500 private:
501 using INHERITED = Type;
502
503 const TextureType& fTextureType;
504 };
505
506 class StructType final : public Type {
507 public:
508 inline static constexpr TypeKind kTypeKind = TypeKind::kStruct;
509
StructType(Position pos,std::string_view name,std::vector<Field> fields,bool interfaceBlock)510 StructType(Position pos, std::string_view name, std::vector<Field> fields, bool interfaceBlock)
511 : INHERITED(std::move(name), "S", kTypeKind, pos)
512 , fFields(std::move(fields))
513 , fInterfaceBlock(interfaceBlock) {}
514
fields() const515 const std::vector<Field>& fields() const override {
516 return fFields;
517 }
518
isStruct() const519 bool isStruct() const override {
520 return true;
521 }
522
isInterfaceBlock() const523 bool isInterfaceBlock() const override {
524 return fInterfaceBlock;
525 }
526
isAllowedInES2() const527 bool isAllowedInES2() const override {
528 return std::all_of(fFields.begin(), fFields.end(), [](const Field& f) {
529 return f.fType->isAllowedInES2();
530 });
531 }
532
slotCount() const533 size_t slotCount() const override {
534 size_t slots = 0;
535 for (const Field& field : fFields) {
536 slots += field.fType->slotCount();
537 }
538 return slots;
539 }
540
541 private:
542 using INHERITED = Type;
543
544 std::vector<Field> fFields;
545 bool fInterfaceBlock;
546 };
547
548 class VectorType final : public Type {
549 public:
550 inline static constexpr TypeKind kTypeKind = TypeKind::kVector;
551
VectorType(std::string_view name,const char * abbrev,const Type & componentType,int8_t columns)552 VectorType(std::string_view name, const char* abbrev, const Type& componentType,
553 int8_t columns)
554 : INHERITED(name, abbrev, kTypeKind)
555 , fComponentType(componentType.as<ScalarType>())
556 , fColumns(columns) {
557 SkASSERT(columns >= 2 && columns <= 4);
558 }
559
componentType() const560 const ScalarType& componentType() const override {
561 return fComponentType;
562 }
563
columns() const564 int columns() const override {
565 return fColumns;
566 }
567
rows() const568 int rows() const override {
569 return 1;
570 }
571
bitWidth() const572 int bitWidth() const override {
573 return this->componentType().bitWidth();
574 }
575
isVector() const576 bool isVector() const override {
577 return true;
578 }
579
isAllowedInES2() const580 bool isAllowedInES2() const override {
581 return fComponentType.isAllowedInES2();
582 }
583
slotCount() const584 size_t slotCount() const override {
585 return fColumns;
586 }
587
588 private:
589 using INHERITED = Type;
590
591 const ScalarType& fComponentType;
592 int8_t fColumns;
593 };
594
getArrayName(int arraySize) const595 std::string Type::getArrayName(int arraySize) const {
596 std::string_view name = this->name();
597 if (arraySize == kUnsizedArray) {
598 return String::printf("%.*s[]", (int)name.size(), name.data());
599 }
600 return String::printf("%.*s[%d]", (int)name.size(), name.data(), arraySize);
601 }
602
MakeAliasType(std::string_view name,const Type & targetType)603 std::unique_ptr<Type> Type::MakeAliasType(std::string_view name, const Type& targetType) {
604 return std::make_unique<AliasType>(std::move(name), targetType);
605 }
606
MakeArrayType(std::string_view name,const Type & componentType,int columns)607 std::unique_ptr<Type> Type::MakeArrayType(std::string_view name, const Type& componentType,
608 int columns) {
609 return std::make_unique<ArrayType>(std::move(name), componentType.abbreviatedName(),
610 componentType, columns);
611 }
612
MakeGenericType(const char * name,SkSpan<const Type * const> types)613 std::unique_ptr<Type> Type::MakeGenericType(const char* name, SkSpan<const Type* const> types) {
614 return std::make_unique<GenericType>(name, types);
615 }
616
MakeLiteralType(const char * name,const Type & scalarType,int8_t priority)617 std::unique_ptr<Type> Type::MakeLiteralType(const char* name, const Type& scalarType,
618 int8_t priority) {
619 return std::make_unique<LiteralType>(name, scalarType, priority);
620 }
621
MakeMatrixType(std::string_view name,const char * abbrev,const Type & componentType,int columns,int8_t rows)622 std::unique_ptr<Type> Type::MakeMatrixType(std::string_view name, const char* abbrev,
623 const Type& componentType, int columns, int8_t rows) {
624 return std::make_unique<MatrixType>(name, abbrev, componentType, columns, rows);
625 }
626
MakeSamplerType(const char * name,const Type & textureType)627 std::unique_ptr<Type> Type::MakeSamplerType(const char* name, const Type& textureType) {
628 return std::make_unique<SamplerType>(name, textureType);
629 }
630
MakeSpecialType(const char * name,const char * abbrev,Type::TypeKind typeKind)631 std::unique_ptr<Type> Type::MakeSpecialType(const char* name, const char* abbrev,
632 Type::TypeKind typeKind) {
633 return std::unique_ptr<Type>(new Type(name, abbrev, typeKind));
634 }
635
MakeScalarType(std::string_view name,const char * abbrev,Type::NumberKind numberKind,int8_t priority,int8_t bitWidth)636 std::unique_ptr<Type> Type::MakeScalarType(std::string_view name, const char* abbrev,
637 Type::NumberKind numberKind, int8_t priority,
638 int8_t bitWidth) {
639 return std::make_unique<ScalarType>(name, abbrev, numberKind, priority, bitWidth);
640 }
641
MakeAtomicType(std::string_view name,const char * abbrev)642 std::unique_ptr<Type> Type::MakeAtomicType(std::string_view name, const char* abbrev) {
643 return std::make_unique<AtomicType>(name, abbrev);
644 }
645
is_too_deeply_nested(const Type * t,int limit)646 static bool is_too_deeply_nested(const Type* t, int limit) {
647 if (limit <= 0) {
648 return true;
649 }
650
651 if (t->isStruct()) {
652 for (const Type::Field& f : t->fields()) {
653 if (is_too_deeply_nested(f.fType, limit - 1)) {
654 return true;
655 }
656 }
657 }
658
659 return false;
660 }
661
MakeStructType(const Context & context,Position pos,std::string_view name,std::vector<Field> fields,bool interfaceBlock)662 std::unique_ptr<Type> Type::MakeStructType(const Context& context,
663 Position pos,
664 std::string_view name,
665 std::vector<Field> fields,
666 bool interfaceBlock) {
667 for (const Field& field : fields) {
668 if (field.fModifiers.fFlags != Modifiers::kNo_Flag) {
669 std::string desc = field.fModifiers.description();
670 desc.pop_back(); // remove trailing space
671 context.fErrors->error(field.fPosition,
672 "modifier '" + desc + "' is not permitted on a struct field");
673 }
674 if (field.fModifiers.fLayout.fFlags & Layout::kBinding_Flag) {
675 context.fErrors->error(field.fPosition,
676 "layout qualifier 'binding' is not permitted on a struct field");
677 }
678 if (field.fModifiers.fLayout.fFlags & Layout::kSet_Flag) {
679 context.fErrors->error(field.fPosition,
680 "layout qualifier 'set' is not permitted on a struct field");
681 }
682
683 if (field.fType->isVoid()) {
684 context.fErrors->error(field.fPosition, "type 'void' is not permitted in a struct");
685 }
686 if (field.fType->isOpaque() && !field.fType->isAtomic()) {
687 context.fErrors->error(field.fPosition, "opaque type '" + field.fType->displayName() +
688 "' is not permitted in a struct");
689 }
690 }
691 for (const Field& field : fields) {
692 if (is_too_deeply_nested(field.fType, kMaxStructDepth)) {
693 context.fErrors->error(pos, "struct '" + std::string(name) + "' is too deeply nested");
694 break;
695 }
696 }
697 size_t slots = 0;
698 for (const Field& field : fields) {
699 if (field.fType->isUnsizedArray()) {
700 continue;
701 }
702 slots = SkSafeMath::Add(slots, field.fType->slotCount());
703 if (slots >= kVariableSlotLimit) {
704 context.fErrors->error(pos, "struct is too large");
705 break;
706 }
707 }
708 return std::make_unique<StructType>(pos, name, std::move(fields), interfaceBlock);
709 }
710
MakeTextureType(const char * name,SpvDim_ dimensions,bool isDepth,bool isArrayedTexture,bool isMultisampled,TextureAccess textureAccess)711 std::unique_ptr<Type> Type::MakeTextureType(const char* name, SpvDim_ dimensions, bool isDepth,
712 bool isArrayedTexture, bool isMultisampled,
713 TextureAccess textureAccess) {
714 return std::make_unique<TextureType>(name, dimensions, isDepth, isArrayedTexture,
715 isMultisampled, textureAccess);
716 }
717
MakeVectorType(std::string_view name,const char * abbrev,const Type & componentType,int columns)718 std::unique_ptr<Type> Type::MakeVectorType(std::string_view name, const char* abbrev,
719 const Type& componentType, int columns) {
720 return std::make_unique<VectorType>(name, abbrev, componentType, columns);
721 }
722
coercionCost(const Type & other) const723 CoercionCost Type::coercionCost(const Type& other) const {
724 if (this->matches(other)) {
725 return CoercionCost::Free();
726 }
727 if (this->typeKind() == other.typeKind() &&
728 (this->isVector() || this->isMatrix() || this->isArray())) {
729 // Vectors/matrices/arrays of the same size can be coerced if their component type can be.
730 if (this->isMatrix() && (this->rows() != other.rows())) {
731 return CoercionCost::Impossible();
732 }
733 if (this->columns() != other.columns()) {
734 return CoercionCost::Impossible();
735 }
736 return this->componentType().coercionCost(other.componentType());
737 }
738 if (this->isNumber() && other.isNumber()) {
739 if (this->isLiteral() && this->isInteger()) {
740 return CoercionCost::Free();
741 } else if (this->numberKind() != other.numberKind()) {
742 return CoercionCost::Impossible();
743 } else if (other.priority() >= this->priority()) {
744 return CoercionCost::Normal(other.priority() - this->priority());
745 } else {
746 return CoercionCost::Narrowing(this->priority() - other.priority());
747 }
748 }
749 if (fTypeKind == TypeKind::kGeneric) {
750 SkSpan<const Type* const> types = this->coercibleTypes();
751 for (size_t i = 0; i < types.size(); i++) {
752 if (types[i]->matches(other)) {
753 return CoercionCost::Normal((int) i + 1);
754 }
755 }
756 }
757 return CoercionCost::Impossible();
758 }
759
applyQualifiers(const Context & context,Modifiers * modifiers,SymbolTable * symbols,Position pos) const760 const Type* Type::applyQualifiers(const Context& context,
761 Modifiers* modifiers,
762 SymbolTable* symbols,
763 Position pos) const {
764 const Type* type;
765 type = this->applyPrecisionQualifiers(context, modifiers, symbols, pos);
766 type = type->applyAccessQualifiers(context, modifiers, symbols, pos);
767 return type;
768 }
769
applyPrecisionQualifiers(const Context & context,Modifiers * modifiers,SymbolTable * symbols,Position pos) const770 const Type* Type::applyPrecisionQualifiers(const Context& context,
771 Modifiers* modifiers,
772 SymbolTable* symbols,
773 Position pos) const {
774 int precisionQualifiers = modifiers->fFlags & (Modifiers::kHighp_Flag |
775 Modifiers::kMediump_Flag |
776 Modifiers::kLowp_Flag);
777 if (!precisionQualifiers) {
778 // No precision qualifiers here. Return the type as-is.
779 return this;
780 }
781
782 if (!ProgramConfig::IsRuntimeEffect(context.fConfig->fKind)) {
783 // We want to discourage precision modifiers internally. Instead, use the type that
784 // corresponds to the precision you need. (e.g. half vs float, short vs int)
785 context.fErrors->error(pos, "precision qualifiers are not allowed");
786 return context.fTypes.fPoison.get();
787 }
788
789 if (SkPopCount(precisionQualifiers) > 1) {
790 context.fErrors->error(pos, "only one precision qualifier can be used");
791 return context.fTypes.fPoison.get();
792 }
793
794 // We're going to return a whole new type, so the modifier bits can be cleared out.
795 modifiers->fFlags &= ~(Modifiers::kHighp_Flag |
796 Modifiers::kMediump_Flag |
797 Modifiers::kLowp_Flag);
798
799 const Type& component = this->componentType();
800 if (component.highPrecision()) {
801 if (precisionQualifiers & Modifiers::kHighp_Flag) {
802 // Type is already high precision, and we are requesting high precision. Return as-is.
803 return this;
804 }
805
806 // SkSL doesn't support low precision, so `lowp` is interpreted as medium precision.
807 // Ascertain the mediump equivalent type for this type, if any.
808 const Type* mediumpType;
809 switch (component.numberKind()) {
810 case Type::NumberKind::kFloat:
811 mediumpType = context.fTypes.fHalf.get();
812 break;
813
814 case Type::NumberKind::kSigned:
815 mediumpType = context.fTypes.fShort.get();
816 break;
817
818 case Type::NumberKind::kUnsigned:
819 mediumpType = context.fTypes.fUShort.get();
820 break;
821
822 default:
823 mediumpType = context.fTypes.fPoison.get();
824 break;
825 }
826
827 if (mediumpType) {
828 // Convert the mediump component type into the final vector/matrix/array type as needed.
829 return this->isArray()
830 ? symbols->addArrayDimension(mediumpType, this->columns())
831 : &mediumpType->toCompound(context, this->columns(), this->rows());
832 }
833 }
834
835 context.fErrors->error(pos, "type '" + this->displayName() +
836 "' does not support precision qualifiers");
837 return context.fTypes.fPoison.get();
838 }
839
applyAccessQualifiers(const Context & context,Modifiers * modifiers,SymbolTable * symbols,Position pos) const840 const Type* Type::applyAccessQualifiers(const Context& context,
841 Modifiers* modifiers,
842 SymbolTable* symbols,
843 Position pos) const {
844 int accessQualifiers = modifiers->fFlags & (Modifiers::kReadOnly_Flag |
845 Modifiers::kWriteOnly_Flag);
846 if (!accessQualifiers) {
847 // No access qualifiers here. Return the type as-is.
848 return this;
849 }
850
851 // We're going to return a whole new type, so the modifier bits can be cleared out.
852 modifiers->fFlags &= ~(Modifiers::kReadOnly_Flag |
853 Modifiers::kWriteOnly_Flag);
854
855 if (this->matches(*context.fTypes.fReadWriteTexture2D)) {
856 switch (accessQualifiers) {
857 case Modifiers::kReadOnly_Flag:
858 return context.fTypes.fReadOnlyTexture2D.get();
859
860 case Modifiers::kWriteOnly_Flag:
861 return context.fTypes.fWriteOnlyTexture2D.get();
862
863 default:
864 context.fErrors->error(pos, "'readonly' and 'writeonly' qualifiers "
865 "cannot be combined");
866 return this;
867 }
868 }
869
870 context.fErrors->error(pos, "type '" + this->displayName() + "' does not support qualifier '" +
871 Modifiers::DescribeFlags(accessQualifiers) + "'");
872 return this;
873 }
874
toCompound(const Context & context,int columns,int rows) const875 const Type& Type::toCompound(const Context& context, int columns, int rows) const {
876 SkASSERT(this->isScalar());
877 if (columns == 1 && rows == 1) {
878 return *this;
879 }
880 if (this->matches(*context.fTypes.fFloat) || this->matches(*context.fTypes.fFloatLiteral)) {
881 switch (rows) {
882 case 1:
883 switch (columns) {
884 case 1: return *context.fTypes.fFloat;
885 case 2: return *context.fTypes.fFloat2;
886 case 3: return *context.fTypes.fFloat3;
887 case 4: return *context.fTypes.fFloat4;
888 default: SK_ABORT("unsupported vector column count (%d)", columns);
889 }
890 case 2:
891 switch (columns) {
892 case 2: return *context.fTypes.fFloat2x2;
893 case 3: return *context.fTypes.fFloat3x2;
894 case 4: return *context.fTypes.fFloat4x2;
895 default: SK_ABORT("unsupported matrix column count (%d)", columns);
896 }
897 case 3:
898 switch (columns) {
899 case 2: return *context.fTypes.fFloat2x3;
900 case 3: return *context.fTypes.fFloat3x3;
901 case 4: return *context.fTypes.fFloat4x3;
902 default: SK_ABORT("unsupported matrix column count (%d)", columns);
903 }
904 case 4:
905 switch (columns) {
906 case 2: return *context.fTypes.fFloat2x4;
907 case 3: return *context.fTypes.fFloat3x4;
908 case 4: return *context.fTypes.fFloat4x4;
909 default: SK_ABORT("unsupported matrix column count (%d)", columns);
910 }
911 default: SK_ABORT("unsupported row count (%d)", rows);
912 }
913 } else if (this->matches(*context.fTypes.fHalf)) {
914 switch (rows) {
915 case 1:
916 switch (columns) {
917 case 1: return *context.fTypes.fHalf;
918 case 2: return *context.fTypes.fHalf2;
919 case 3: return *context.fTypes.fHalf3;
920 case 4: return *context.fTypes.fHalf4;
921 default: SK_ABORT("unsupported vector column count (%d)", columns);
922 }
923 case 2:
924 switch (columns) {
925 case 2: return *context.fTypes.fHalf2x2;
926 case 3: return *context.fTypes.fHalf3x2;
927 case 4: return *context.fTypes.fHalf4x2;
928 default: SK_ABORT("unsupported matrix column count (%d)", columns);
929 }
930 case 3:
931 switch (columns) {
932 case 2: return *context.fTypes.fHalf2x3;
933 case 3: return *context.fTypes.fHalf3x3;
934 case 4: return *context.fTypes.fHalf4x3;
935 default: SK_ABORT("unsupported matrix column count (%d)", columns);
936 }
937 case 4:
938 switch (columns) {
939 case 2: return *context.fTypes.fHalf2x4;
940 case 3: return *context.fTypes.fHalf3x4;
941 case 4: return *context.fTypes.fHalf4x4;
942 default: SK_ABORT("unsupported matrix column count (%d)", columns);
943 }
944 default: SK_ABORT("unsupported row count (%d)", rows);
945 }
946 } else if (this->matches(*context.fTypes.fInt) || this->matches(*context.fTypes.fIntLiteral)) {
947 switch (rows) {
948 case 1:
949 switch (columns) {
950 case 1: return *context.fTypes.fInt;
951 case 2: return *context.fTypes.fInt2;
952 case 3: return *context.fTypes.fInt3;
953 case 4: return *context.fTypes.fInt4;
954 default: SK_ABORT("unsupported vector column count (%d)", columns);
955 }
956 default: SK_ABORT("unsupported row count (%d)", rows);
957 }
958 } else if (this->matches(*context.fTypes.fShort)) {
959 switch (rows) {
960 case 1:
961 switch (columns) {
962 case 1: return *context.fTypes.fShort;
963 case 2: return *context.fTypes.fShort2;
964 case 3: return *context.fTypes.fShort3;
965 case 4: return *context.fTypes.fShort4;
966 default: SK_ABORT("unsupported vector column count (%d)", columns);
967 }
968 default: SK_ABORT("unsupported row count (%d)", rows);
969 }
970 } else if (this->matches(*context.fTypes.fUInt)) {
971 switch (rows) {
972 case 1:
973 switch (columns) {
974 case 1: return *context.fTypes.fUInt;
975 case 2: return *context.fTypes.fUInt2;
976 case 3: return *context.fTypes.fUInt3;
977 case 4: return *context.fTypes.fUInt4;
978 default: SK_ABORT("unsupported vector column count (%d)", columns);
979 }
980 default: SK_ABORT("unsupported row count (%d)", rows);
981 }
982 } else if (this->matches(*context.fTypes.fUShort)) {
983 switch (rows) {
984 case 1:
985 switch (columns) {
986 case 1: return *context.fTypes.fUShort;
987 case 2: return *context.fTypes.fUShort2;
988 case 3: return *context.fTypes.fUShort3;
989 case 4: return *context.fTypes.fUShort4;
990 default: SK_ABORT("unsupported vector column count (%d)", columns);
991 }
992 default: SK_ABORT("unsupported row count (%d)", rows);
993 }
994 } else if (this->matches(*context.fTypes.fBool)) {
995 switch (rows) {
996 case 1:
997 switch (columns) {
998 case 1: return *context.fTypes.fBool;
999 case 2: return *context.fTypes.fBool2;
1000 case 3: return *context.fTypes.fBool3;
1001 case 4: return *context.fTypes.fBool4;
1002 default: SK_ABORT("unsupported vector column count (%d)", columns);
1003 }
1004 default: SK_ABORT("unsupported row count (%d)", rows);
1005 }
1006 }
1007 SkDEBUGFAILF("unsupported toCompound type %s", this->description().c_str());
1008 return *context.fTypes.fVoid;
1009 }
1010
clone(SymbolTable * symbolTable) const1011 const Type* Type::clone(SymbolTable* symbolTable) const {
1012 // Many types are built-ins, and exist in every SymbolTable by default.
1013 if (this->isInBuiltinTypes()) {
1014 return this;
1015 }
1016 // Even if the type isn't a built-in, it might already exist in the SymbolTable.
1017 const Symbol* clonedSymbol = symbolTable->find(this->name());
1018 if (clonedSymbol != nullptr) {
1019 const Type& clonedType = clonedSymbol->as<Type>();
1020 SkASSERT(clonedType.typeKind() == this->typeKind());
1021 return &clonedType;
1022 }
1023 // This type actually needs to be cloned into the destination SymbolTable.
1024 switch (this->typeKind()) {
1025 case TypeKind::kArray: {
1026 return symbolTable->addArrayDimension(&this->componentType(), this->columns());
1027 }
1028 case TypeKind::kStruct: {
1029 // We are cloning an existing struct, so there's no need to call MakeStructType and
1030 // fully error-check it again.
1031 const std::string* name = symbolTable->takeOwnershipOfString(std::string(this->name()));
1032 return symbolTable->add(std::make_unique<StructType>(
1033 this->fPosition, *name, this->fields(), this->isInterfaceBlock()));
1034 }
1035 default:
1036 SkDEBUGFAILF("don't know how to clone type '%s'", this->description().c_str());
1037 return nullptr;
1038 }
1039 }
1040
coerceExpression(std::unique_ptr<Expression> expr,const Context & context) const1041 std::unique_ptr<Expression> Type::coerceExpression(std::unique_ptr<Expression> expr,
1042 const Context& context) const {
1043 if (!expr || expr->isIncomplete(context)) {
1044 return nullptr;
1045 }
1046 if (expr->type().matches(*this)) {
1047 return expr;
1048 }
1049
1050 const Position pos = expr->fPosition;
1051 const ProgramSettings& settings = context.fConfig->fSettings;
1052 if (!expr->coercionCost(*this).isPossible(settings.fAllowNarrowingConversions)) {
1053 context.fErrors->error(pos, "expected '" + this->displayName() + "', but found '" +
1054 expr->type().displayName() + "'");
1055 return nullptr;
1056 }
1057
1058 if (this->isScalar()) {
1059 return ConstructorScalarCast::Make(context, pos, *this, std::move(expr));
1060 }
1061 if (this->isVector() || this->isMatrix()) {
1062 return ConstructorCompoundCast::Make(context, pos, *this, std::move(expr));
1063 }
1064 if (this->isArray()) {
1065 return ConstructorArrayCast::Make(context, pos, *this, std::move(expr));
1066 }
1067 context.fErrors->error(pos, "cannot construct '" + this->displayName() + "'");
1068 return nullptr;
1069 }
1070
is_or_contains_array(const Type * type,bool onlyMatchUnsizedArrays)1071 static bool is_or_contains_array(const Type* type, bool onlyMatchUnsizedArrays) {
1072 if (type->isStruct()) {
1073 for (const Type::Field& f : type->fields()) {
1074 if (is_or_contains_array(f.fType, onlyMatchUnsizedArrays)) {
1075 return true;
1076 }
1077 }
1078 return false;
1079 }
1080
1081 if (type->isArray()) {
1082 return onlyMatchUnsizedArrays
1083 ? (type->isUnsizedArray() || is_or_contains_array(&type->componentType(), true))
1084 : true;
1085 }
1086
1087 return false;
1088 }
1089
isOrContainsArray() const1090 bool Type::isOrContainsArray() const {
1091 return is_or_contains_array(this, /*onlyMatchUnsizedArrays=*/false);
1092 }
1093
isOrContainsUnsizedArray() const1094 bool Type::isOrContainsUnsizedArray() const {
1095 return is_or_contains_array(this, /*onlyMatchUnsizedArrays=*/true);
1096 }
1097
isOrContainsAtomic() const1098 bool Type::isOrContainsAtomic() const {
1099 if (this->isAtomic()) {
1100 return true;
1101 }
1102
1103 if (this->isArray() && this->componentType().isOrContainsAtomic()) {
1104 return true;
1105 }
1106
1107 if (this->isStruct()) {
1108 for (const Field& f : this->fields()) {
1109 if (f.fType->isOrContainsAtomic()) {
1110 return true;
1111 }
1112 }
1113 }
1114
1115 return false;
1116 }
1117
isAllowedInES2(const Context & context) const1118 bool Type::isAllowedInES2(const Context& context) const {
1119 return !context.fConfig->strictES2Mode() || this->isAllowedInES2();
1120 }
1121
checkForOutOfRangeLiteral(const Context & context,const Expression & expr) const1122 bool Type::checkForOutOfRangeLiteral(const Context& context, const Expression& expr) const {
1123 bool foundError = false;
1124 const Type& baseType = this->componentType();
1125 if (baseType.isNumber()) {
1126 // Replace constant expressions with their corresponding values.
1127 const Expression* valueExpr = ConstantFolder::GetConstantValueForVariable(expr);
1128 if (valueExpr->supportsConstantValues()) {
1129 // Iterate over every constant subexpression in the value.
1130 int numSlots = valueExpr->type().slotCount();
1131 for (int slot = 0; slot < numSlots; ++slot) {
1132 std::optional<double> slotVal = valueExpr->getConstantValue(slot);
1133 // Check for Literal values that are out of range for the base type.
1134 if (slotVal.has_value() &&
1135 baseType.checkForOutOfRangeLiteral(context, *slotVal, valueExpr->fPosition)) {
1136 foundError = true;
1137 }
1138 }
1139 }
1140 }
1141
1142 // We don't need range checks for floats or booleans; any matched-type value is acceptable.
1143 return foundError;
1144 }
1145
checkForOutOfRangeLiteral(const Context & context,double value,Position pos) const1146 bool Type::checkForOutOfRangeLiteral(const Context& context, double value, Position pos) const {
1147 SkASSERT(this->isScalar());
1148 if (!this->isNumber()) {
1149 return false;
1150 }
1151 if (value >= this->minimumValue() && value <= this->maximumValue()) {
1152 return false;
1153 }
1154 // We found a value that can't fit in our type. Flag it as an error.
1155 context.fErrors->error(pos, SkSL::String::printf("value is out of range for type '%s': %.0f",
1156 this->displayName().c_str(),
1157 value));
1158 return true;
1159 }
1160
checkIfUsableInArray(const Context & context,Position arrayPos) const1161 bool Type::checkIfUsableInArray(const Context& context, Position arrayPos) const {
1162 if (this->isArray()) {
1163 context.fErrors->error(arrayPos, "multi-dimensional arrays are not supported");
1164 return false;
1165 }
1166 if (this->isVoid()) {
1167 context.fErrors->error(arrayPos, "type 'void' may not be used in an array");
1168 return false;
1169 }
1170 if (this->isOpaque() && !this->isAtomic()) {
1171 context.fErrors->error(arrayPos, "opaque type '" + std::string(this->name()) +
1172 "' may not be used in an array");
1173 return false;
1174 }
1175 return true;
1176 }
1177
convertArraySize(const Context & context,Position arrayPos,std::unique_ptr<Expression> size) const1178 SKSL_INT Type::convertArraySize(const Context& context,
1179 Position arrayPos,
1180 std::unique_ptr<Expression> size) const {
1181 size = context.fTypes.fInt->coerceExpression(std::move(size), context);
1182 if (!size) {
1183 return 0;
1184 }
1185 if (!this->checkIfUsableInArray(context, arrayPos)) {
1186 return 0;
1187 }
1188 SKSL_INT count;
1189 if (!ConstantFolder::GetConstantInt(*size, &count)) {
1190 context.fErrors->error(size->fPosition, "array size must be an integer");
1191 return 0;
1192 }
1193 if (count <= 0) {
1194 context.fErrors->error(size->fPosition, "array size must be positive");
1195 return 0;
1196 }
1197 if (SkSafeMath::Mul(this->slotCount(), count) > kVariableSlotLimit) {
1198 context.fErrors->error(size->fPosition, "array size is too large");
1199 return 0;
1200 }
1201 return static_cast<int>(count);
1202 }
1203
description() const1204 std::string Type::Field::description() const {
1205 return fModifiers.description() + fType->displayName() + " " + std::string(fName) + ";";
1206 }
1207
1208 } // namespace SkSL
1209