• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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