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/SkStringView.h"
11 #include "src/sksl/SkSLConstantFolder.h"
12 #include "src/sksl/SkSLContext.h"
13 #include "src/sksl/SkSLProgramSettings.h"
14 #include "src/sksl/ir/SkSLConstructor.h"
15 #include "src/sksl/ir/SkSLConstructorArrayCast.h"
16 #include "src/sksl/ir/SkSLConstructorCompoundCast.h"
17 #include "src/sksl/ir/SkSLConstructorScalarCast.h"
18 #include "src/sksl/ir/SkSLProgram.h"
19 #include "src/sksl/ir/SkSLSymbolTable.h"
20 #include "src/sksl/ir/SkSLType.h"
21
22 #include <optional>
23 #include <string_view>
24
25 namespace SkSL {
26
27 static constexpr int kMaxStructDepth = 8;
28
29 class AliasType final : public Type {
30 public:
AliasType(std::string_view name,const Type & targetType)31 AliasType(std::string_view name, const Type& targetType)
32 : INHERITED(name, targetType.abbreviatedName(), targetType.typeKind())
33 , fTargetType(targetType) {}
34
resolve() const35 const Type& resolve() const override {
36 return fTargetType;
37 }
38
componentType() const39 const Type& componentType() const override {
40 return fTargetType.componentType();
41 }
42
numberKind() const43 NumberKind numberKind() const override {
44 return fTargetType.numberKind();
45 }
46
priority() const47 int priority() const override {
48 return fTargetType.priority();
49 }
50
columns() const51 int columns() const override {
52 return fTargetType.columns();
53 }
54
rows() const55 int rows() const override {
56 return fTargetType.rows();
57 }
58
bitWidth() const59 int bitWidth() const override {
60 return fTargetType.bitWidth();
61 }
62
isPrivate() const63 bool isPrivate() const override {
64 return fTargetType.isPrivate();
65 }
66
isAllowedInES2() const67 bool isAllowedInES2() const override {
68 return fTargetType.isAllowedInES2();
69 }
70
slotCount() const71 size_t slotCount() const override {
72 return fTargetType.slotCount();
73 }
74
isDepth() const75 bool isDepth() const override {
76 return fTargetType.isDepth();
77 }
78
isArrayedTexture() const79 bool isArrayedTexture() const override {
80 return fTargetType.isArrayedTexture();
81 }
82
isScalar() const83 bool isScalar() const override {
84 return fTargetType.isScalar();
85 }
86
isLiteral() const87 bool isLiteral() const override {
88 return fTargetType.isLiteral();
89 }
90
isVector() const91 bool isVector() const override {
92 return fTargetType.isVector();
93 }
94
isMatrix() const95 bool isMatrix() const override {
96 return fTargetType.isMatrix();
97 }
98
isArray() const99 bool isArray() const override {
100 return fTargetType.isArray();
101 }
102
isStruct() const103 bool isStruct() const override {
104 return fTargetType.isStruct();
105 }
106
isInterfaceBlock() const107 bool isInterfaceBlock() const override {
108 return fTargetType.isInterfaceBlock();
109 }
110
coercibleTypes() const111 const std::vector<const Type*>& coercibleTypes() const override {
112 return fTargetType.coercibleTypes();
113 }
114
115 private:
116 using INHERITED = Type;
117
118 const Type& fTargetType;
119 };
120
121 class ArrayType final : public Type {
122 public:
123 inline static constexpr TypeKind kTypeKind = TypeKind::kArray;
124
ArrayType(std::string_view name,const char * abbrev,const Type & componentType,int count)125 ArrayType(std::string_view name, const char* abbrev, const Type& componentType, int count)
126 : INHERITED(name, abbrev, kTypeKind)
127 , fComponentType(componentType)
128 , fCount(count) {
129 // Only allow explicitly-sized arrays.
130 SkASSERT(count > 0);
131 // Disallow multi-dimensional arrays.
132 SkASSERT(!componentType.is<ArrayType>());
133 }
134
isArray() const135 bool isArray() const override {
136 return true;
137 }
138
componentType() const139 const Type& componentType() const override {
140 return fComponentType;
141 }
142
columns() const143 int columns() const override {
144 return fCount;
145 }
146
bitWidth() const147 int bitWidth() const override {
148 return this->componentType().bitWidth();
149 }
150
isPrivate() const151 bool isPrivate() const override {
152 return fComponentType.isPrivate();
153 }
154
isAllowedInES2() const155 bool isAllowedInES2() const override {
156 return fComponentType.isAllowedInES2();
157 }
158
slotCount() const159 size_t slotCount() const override {
160 SkASSERT(fCount > 0);
161 return fCount * fComponentType.slotCount();
162 }
163
164 private:
165 using INHERITED = Type;
166
167 const Type& fComponentType;
168 int fCount;
169 };
170
171 class GenericType final : public Type {
172 public:
173 inline static constexpr TypeKind kTypeKind = TypeKind::kGeneric;
174
GenericType(const char * name,std::vector<const Type * > coercibleTypes)175 GenericType(const char* name, std::vector<const Type*> coercibleTypes)
176 : INHERITED(name, "G", kTypeKind)
177 , fCoercibleTypes(std::move(coercibleTypes)) {}
178
coercibleTypes() const179 const std::vector<const Type*>& coercibleTypes() const override {
180 return fCoercibleTypes;
181 }
182
183 private:
184 using INHERITED = Type;
185
186 std::vector<const Type*> fCoercibleTypes;
187 };
188
189 class LiteralType : public Type {
190 public:
191 inline static constexpr TypeKind kTypeKind = TypeKind::kLiteral;
192
LiteralType(const char * name,const Type & scalarType,int8_t priority)193 LiteralType(const char* name, const Type& scalarType, int8_t priority)
194 : INHERITED(name, "L", kTypeKind)
195 , fScalarType(scalarType)
196 , fPriority(priority) {}
197
scalarTypeForLiteral() const198 const Type& scalarTypeForLiteral() const override {
199 return fScalarType;
200 }
201
priority() const202 int priority() const override {
203 return fPriority;
204 }
205
columns() const206 int columns() const override {
207 return 1;
208 }
209
rows() const210 int rows() const override {
211 return 1;
212 }
213
numberKind() const214 NumberKind numberKind() const override {
215 return fScalarType.numberKind();
216 }
217
bitWidth() const218 int bitWidth() const override {
219 return fScalarType.bitWidth();
220 }
221
isScalar() const222 bool isScalar() const override {
223 return true;
224 }
225
isLiteral() const226 bool isLiteral() const override {
227 return true;
228 }
229
isPrivate() const230 bool isPrivate() const override {
231 return true;
232 }
233
slotCount() const234 size_t slotCount() const override {
235 return 1;
236 }
237
238 private:
239 using INHERITED = Type;
240
241 const Type& fScalarType;
242 int8_t fPriority;
243 };
244
245
246 class ScalarType final : public Type {
247 public:
248 inline static constexpr TypeKind kTypeKind = TypeKind::kScalar;
249
ScalarType(std::string_view name,const char * abbrev,NumberKind numberKind,int8_t priority,int8_t bitWidth)250 ScalarType(std::string_view name, const char* abbrev, NumberKind numberKind, int8_t priority,
251 int8_t bitWidth)
252 : INHERITED(name, abbrev, kTypeKind)
253 , fNumberKind(numberKind)
254 , fPriority(priority)
255 , fBitWidth(bitWidth) {}
256
numberKind() const257 NumberKind numberKind() const override {
258 return fNumberKind;
259 }
260
priority() const261 int priority() const override {
262 return fPriority;
263 }
264
bitWidth() const265 int bitWidth() const override {
266 return fBitWidth;
267 }
268
columns() const269 int columns() const override {
270 return 1;
271 }
272
rows() const273 int rows() const override {
274 return 1;
275 }
276
isScalar() const277 bool isScalar() const override {
278 return true;
279 }
280
isAllowedInES2() const281 bool isAllowedInES2() const override {
282 return fNumberKind != NumberKind::kUnsigned;
283 }
284
slotCount() const285 size_t slotCount() const override {
286 return 1;
287 }
288
289 private:
290 using INHERITED = Type;
291
292 NumberKind fNumberKind;
293 int8_t fPriority;
294 int8_t fBitWidth;
295 };
296
297 class MatrixType final : public Type {
298 public:
299 inline static constexpr TypeKind kTypeKind = TypeKind::kMatrix;
300
MatrixType(std::string_view name,const char * abbrev,const Type & componentType,int8_t columns,int8_t rows)301 MatrixType(std::string_view name, const char* abbrev, const Type& componentType,
302 int8_t columns, int8_t rows)
303 : INHERITED(name, abbrev, kTypeKind)
304 , fComponentType(componentType.as<ScalarType>())
305 , fColumns(columns)
306 , fRows(rows) {
307 SkASSERT(columns >= 2 && columns <= 4);
308 SkASSERT(rows >= 2 && rows <= 4);
309 }
310
componentType() const311 const ScalarType& componentType() const override {
312 return fComponentType;
313 }
314
columns() const315 int columns() const override {
316 return fColumns;
317 }
318
rows() const319 int rows() const override {
320 return fRows;
321 }
322
bitWidth() const323 int bitWidth() const override {
324 return this->componentType().bitWidth();
325 }
326
isMatrix() const327 bool isMatrix() const override {
328 return true;
329 }
330
isAllowedInES2() const331 bool isAllowedInES2() const override {
332 return fColumns == fRows;
333 }
334
slotCount() const335 size_t slotCount() const override {
336 return fColumns * fRows;
337 }
338
339 private:
340 using INHERITED = Type;
341
342 const ScalarType& fComponentType;
343 int8_t fColumns;
344 int8_t fRows;
345 };
346
347 class TextureType final : public Type {
348 public:
349 inline static constexpr TypeKind kTypeKind = TypeKind::kTexture;
350
TextureType(const char * name,SpvDim_ dimensions,bool isDepth,bool isArrayed,bool isMultisampled,bool isSampled)351 TextureType(const char* name, SpvDim_ dimensions, bool isDepth, bool isArrayed,
352 bool isMultisampled, bool isSampled)
353 : INHERITED(name, "T", kTypeKind)
354 , fDimensions(dimensions)
355 , fIsDepth(isDepth)
356 , fIsArrayed(isArrayed)
357 , fIsMultisampled(isMultisampled)
358 , fIsSampled(isSampled) {}
359
dimensions() const360 SpvDim_ dimensions() const override {
361 return fDimensions;
362 }
363
isDepth() const364 bool isDepth() const override {
365 return fIsDepth;
366 }
367
isArrayedTexture() const368 bool isArrayedTexture() const override {
369 return fIsArrayed;
370 }
371
isMultisampled() const372 bool isMultisampled() const override {
373 return fIsMultisampled;
374 }
375
isSampled() const376 bool isSampled() const override {
377 return fIsSampled;
378 }
379
380 private:
381 using INHERITED = Type;
382
383 SpvDim_ fDimensions;
384 bool fIsDepth;
385 bool fIsArrayed;
386 bool fIsMultisampled;
387 bool fIsSampled;
388 };
389
390 class SamplerType final : public Type {
391 public:
392 inline static constexpr TypeKind kTypeKind = TypeKind::kSampler;
393
SamplerType(const char * name,const Type & textureType)394 SamplerType(const char* name, const Type& textureType)
395 : INHERITED(name, "Z", kTypeKind)
396 , fTextureType(textureType.as<TextureType>()) {}
397
textureType() const398 const TextureType& textureType() const override {
399 return fTextureType;
400 }
401
dimensions() const402 SpvDim_ dimensions() const override {
403 return fTextureType.dimensions();
404 }
405
isDepth() const406 bool isDepth() const override {
407 return fTextureType.isDepth();
408 }
409
isArrayedTexture() const410 bool isArrayedTexture() const override {
411 return fTextureType.isArrayedTexture();
412 }
413
isMultisampled() const414 bool isMultisampled() const override {
415 return fTextureType.isMultisampled();
416 }
417
isSampled() const418 bool isSampled() const override {
419 return fTextureType.isSampled();
420 }
421
422 private:
423 using INHERITED = Type;
424
425 const TextureType& fTextureType;
426 };
427
428 class StructType final : public Type {
429 public:
430 inline static constexpr TypeKind kTypeKind = TypeKind::kStruct;
431
StructType(int line,std::string_view name,std::vector<Field> fields,bool interfaceBlock)432 StructType(int line, std::string_view name, std::vector<Field> fields, bool interfaceBlock)
433 : INHERITED(std::move(name), "S", kTypeKind, line)
434 , fFields(std::move(fields))
435 , fInterfaceBlock(interfaceBlock) {}
436
fields() const437 const std::vector<Field>& fields() const override {
438 return fFields;
439 }
440
isStruct() const441 bool isStruct() const override {
442 return true;
443 }
444
isInterfaceBlock() const445 bool isInterfaceBlock() const override {
446 return fInterfaceBlock;
447 }
448
isPrivate() const449 bool isPrivate() const override {
450 return std::any_of(fFields.begin(), fFields.end(), [](const Field& f) {
451 return f.fType->isPrivate();
452 });
453 }
454
isAllowedInES2() const455 bool isAllowedInES2() const override {
456 return std::all_of(fFields.begin(), fFields.end(), [](const Field& f) {
457 return f.fType->isAllowedInES2();
458 });
459 }
460
slotCount() const461 size_t slotCount() const override {
462 size_t slots = 0;
463 for (const Field& field : fFields) {
464 slots += field.fType->slotCount();
465 }
466 return slots;
467 }
468
469 private:
470 using INHERITED = Type;
471
472 std::vector<Field> fFields;
473 bool fInterfaceBlock;
474 };
475
476 class VectorType final : public Type {
477 public:
478 inline static constexpr TypeKind kTypeKind = TypeKind::kVector;
479
VectorType(std::string_view name,const char * abbrev,const Type & componentType,int8_t columns)480 VectorType(std::string_view name, const char* abbrev, const Type& componentType,
481 int8_t columns)
482 : INHERITED(name, abbrev, kTypeKind)
483 , fComponentType(componentType.as<ScalarType>())
484 , fColumns(columns) {
485 SkASSERT(columns >= 2 && columns <= 4);
486 }
487
componentType() const488 const ScalarType& componentType() const override {
489 return fComponentType;
490 }
491
columns() const492 int columns() const override {
493 return fColumns;
494 }
495
rows() const496 int rows() const override {
497 return 1;
498 }
499
bitWidth() const500 int bitWidth() const override {
501 return this->componentType().bitWidth();
502 }
503
isVector() const504 bool isVector() const override {
505 return true;
506 }
507
isAllowedInES2() const508 bool isAllowedInES2() const override {
509 return fComponentType.isAllowedInES2();
510 }
511
slotCount() const512 size_t slotCount() const override {
513 return fColumns;
514 }
515
516 private:
517 using INHERITED = Type;
518
519 const ScalarType& fComponentType;
520 int8_t fColumns;
521 };
522
getArrayName(int arraySize) const523 std::string Type::getArrayName(int arraySize) const {
524 std::string_view name = this->name();
525 return String::printf("%.*s[%d]", (int)name.size(), name.data(), arraySize);
526 }
527
MakeAliasType(std::string_view name,const Type & targetType)528 std::unique_ptr<Type> Type::MakeAliasType(std::string_view name, const Type& targetType) {
529 return std::make_unique<AliasType>(std::move(name), targetType);
530 }
531
MakeArrayType(std::string_view name,const Type & componentType,int columns)532 std::unique_ptr<Type> Type::MakeArrayType(std::string_view name, const Type& componentType,
533 int columns) {
534 return std::make_unique<ArrayType>(std::move(name), componentType.abbreviatedName(),
535 componentType, columns);
536 }
537
MakeGenericType(const char * name,std::vector<const Type * > types)538 std::unique_ptr<Type> Type::MakeGenericType(const char* name, std::vector<const Type*> types) {
539 return std::make_unique<GenericType>(name, std::move(types));
540 }
541
MakeLiteralType(const char * name,const Type & scalarType,int8_t priority)542 std::unique_ptr<Type> Type::MakeLiteralType(const char* name, const Type& scalarType,
543 int8_t priority) {
544 return std::make_unique<LiteralType>(name, scalarType, priority);
545 }
546
MakeMatrixType(std::string_view name,const char * abbrev,const Type & componentType,int columns,int8_t rows)547 std::unique_ptr<Type> Type::MakeMatrixType(std::string_view name, const char* abbrev,
548 const Type& componentType, int columns, int8_t rows) {
549 return std::make_unique<MatrixType>(name, abbrev, componentType, columns, rows);
550 }
551
MakeSamplerType(const char * name,const Type & textureType)552 std::unique_ptr<Type> Type::MakeSamplerType(const char* name, const Type& textureType) {
553 return std::make_unique<SamplerType>(name, textureType);
554 }
555
MakeSpecialType(const char * name,const char * abbrev,Type::TypeKind typeKind)556 std::unique_ptr<Type> Type::MakeSpecialType(const char* name, const char* abbrev,
557 Type::TypeKind typeKind) {
558 return std::unique_ptr<Type>(new Type(name, abbrev, typeKind));
559 }
560
MakeScalarType(std::string_view name,const char * abbrev,Type::NumberKind numberKind,int8_t priority,int8_t bitWidth)561 std::unique_ptr<Type> Type::MakeScalarType(std::string_view name, const char* abbrev,
562 Type::NumberKind numberKind, int8_t priority,
563 int8_t bitWidth) {
564 return std::make_unique<ScalarType>(name, abbrev, numberKind, priority, bitWidth);
565
566 }
567
MakeStructType(int line,std::string_view name,std::vector<Field> fields,bool interfaceBlock)568 std::unique_ptr<Type> Type::MakeStructType(int line, std::string_view name,
569 std::vector<Field> fields, bool interfaceBlock) {
570 return std::make_unique<StructType>(line, name, std::move(fields), interfaceBlock);
571 }
572
MakeTextureType(const char * name,SpvDim_ dimensions,bool isDepth,bool isArrayedTexture,bool isMultisampled,bool isSampled)573 std::unique_ptr<Type> Type::MakeTextureType(const char* name, SpvDim_ dimensions, bool isDepth,
574 bool isArrayedTexture, bool isMultisampled,
575 bool isSampled) {
576 return std::make_unique<TextureType>(name, dimensions, isDepth, isArrayedTexture,
577 isMultisampled, isSampled);
578 }
579
MakeVectorType(std::string_view name,const char * abbrev,const Type & componentType,int columns)580 std::unique_ptr<Type> Type::MakeVectorType(std::string_view name, const char* abbrev,
581 const Type& componentType, int columns) {
582 return std::make_unique<VectorType>(name, abbrev, componentType, columns);
583 }
584
coercionCost(const Type & other) const585 CoercionCost Type::coercionCost(const Type& other) const {
586 if (this->matches(other)) {
587 return CoercionCost::Free();
588 }
589 if (this->typeKind() == other.typeKind() &&
590 (this->isVector() || this->isMatrix() || this->isArray())) {
591 // Vectors/matrices/arrays of the same size can be coerced if their component type can be.
592 if (this->isMatrix() && (this->rows() != other.rows())) {
593 return CoercionCost::Impossible();
594 }
595 if (this->columns() != other.columns()) {
596 return CoercionCost::Impossible();
597 }
598 return this->componentType().coercionCost(other.componentType());
599 }
600 if (this->isNumber() && other.isNumber()) {
601 if (this->isLiteral() && this->isInteger()) {
602 return CoercionCost::Free();
603 } else if (this->numberKind() != other.numberKind()) {
604 return CoercionCost::Impossible();
605 } else if (other.priority() >= this->priority()) {
606 return CoercionCost::Normal(other.priority() - this->priority());
607 } else {
608 return CoercionCost::Narrowing(this->priority() - other.priority());
609 }
610 }
611 if (fTypeKind == TypeKind::kGeneric) {
612 const std::vector<const Type*>& types = this->coercibleTypes();
613 for (size_t i = 0; i < types.size(); i++) {
614 if (types[i]->matches(other)) {
615 return CoercionCost::Normal((int) i + 1);
616 }
617 }
618 }
619 return CoercionCost::Impossible();
620 }
621
applyPrecisionQualifiers(const Context & context,Modifiers * modifiers,SymbolTable * symbols,int line) const622 const Type* Type::applyPrecisionQualifiers(const Context& context,
623 Modifiers* modifiers,
624 SymbolTable* symbols,
625 int line) const {
626 // SkSL doesn't support low precision, so `lowp` is interpreted as medium precision.
627 bool highp = modifiers->fFlags & Modifiers::kHighp_Flag;
628 bool mediump = modifiers->fFlags & Modifiers::kMediump_Flag;
629 bool lowp = modifiers->fFlags & Modifiers::kLowp_Flag;
630
631 if (!lowp && !mediump && !highp) {
632 // No precision qualifiers here. Return the type as-is.
633 return this;
634 }
635
636 if (!ProgramConfig::IsRuntimeEffect(context.fConfig->fKind)) {
637 // We want to discourage precision modifiers internally. Instead, use the type that
638 // corresponds to the precision you need. (e.g. half vs float, short vs int)
639 context.fErrors->error(line, "precision qualifiers are not allowed");
640 return nullptr;
641 }
642
643 if ((int(lowp) + int(mediump) + int(highp)) != 1) {
644 context.fErrors->error(line, "only one precision qualifier can be used");
645 return nullptr;
646 }
647
648 // We're going to return a whole new type, so the modifier bits can be cleared out.
649 modifiers->fFlags &= ~(Modifiers::kHighp_Flag |
650 Modifiers::kMediump_Flag |
651 Modifiers::kLowp_Flag);
652
653 const Type& component = this->componentType();
654 if (component.highPrecision()) {
655 if (highp) {
656 // Type is already high precision, and we are requesting high precision. Return as-is.
657 return this;
658 }
659
660 // Ascertain the mediump equivalent type for this type, if any.
661 const Type* mediumpType;
662 switch (component.numberKind()) {
663 case Type::NumberKind::kFloat:
664 mediumpType = context.fTypes.fHalf.get();
665 break;
666
667 case Type::NumberKind::kSigned:
668 mediumpType = context.fTypes.fShort.get();
669 break;
670
671 case Type::NumberKind::kUnsigned:
672 mediumpType = context.fTypes.fUShort.get();
673 break;
674
675 default:
676 mediumpType = nullptr;
677 break;
678 }
679
680 if (mediumpType) {
681 // Convert the mediump component type into the final vector/matrix/array type as needed.
682 return this->isArray()
683 ? symbols->addArrayDimension(mediumpType, this->columns())
684 : &mediumpType->toCompound(context, this->columns(), this->rows());
685 }
686 }
687
688 context.fErrors->error(line, "type '" + this->displayName() +
689 "' does not support precision qualifiers");
690 return nullptr;
691 }
692
toCompound(const Context & context,int columns,int rows) const693 const Type& Type::toCompound(const Context& context, int columns, int rows) const {
694 SkASSERT(this->isScalar());
695 if (columns == 1 && rows == 1) {
696 return *this;
697 }
698 if (this->matches(*context.fTypes.fFloat) || this->matches(*context.fTypes.fFloatLiteral)) {
699 switch (rows) {
700 case 1:
701 switch (columns) {
702 case 1: return *context.fTypes.fFloat;
703 case 2: return *context.fTypes.fFloat2;
704 case 3: return *context.fTypes.fFloat3;
705 case 4: return *context.fTypes.fFloat4;
706 default: SK_ABORT("unsupported vector column count (%d)", columns);
707 }
708 case 2:
709 switch (columns) {
710 case 2: return *context.fTypes.fFloat2x2;
711 case 3: return *context.fTypes.fFloat3x2;
712 case 4: return *context.fTypes.fFloat4x2;
713 default: SK_ABORT("unsupported matrix column count (%d)", columns);
714 }
715 case 3:
716 switch (columns) {
717 case 2: return *context.fTypes.fFloat2x3;
718 case 3: return *context.fTypes.fFloat3x3;
719 case 4: return *context.fTypes.fFloat4x3;
720 default: SK_ABORT("unsupported matrix column count (%d)", columns);
721 }
722 case 4:
723 switch (columns) {
724 case 2: return *context.fTypes.fFloat2x4;
725 case 3: return *context.fTypes.fFloat3x4;
726 case 4: return *context.fTypes.fFloat4x4;
727 default: SK_ABORT("unsupported matrix column count (%d)", columns);
728 }
729 default: SK_ABORT("unsupported row count (%d)", rows);
730 }
731 } else if (this->matches(*context.fTypes.fHalf)) {
732 switch (rows) {
733 case 1:
734 switch (columns) {
735 case 1: return *context.fTypes.fHalf;
736 case 2: return *context.fTypes.fHalf2;
737 case 3: return *context.fTypes.fHalf3;
738 case 4: return *context.fTypes.fHalf4;
739 default: SK_ABORT("unsupported vector column count (%d)", columns);
740 }
741 case 2:
742 switch (columns) {
743 case 2: return *context.fTypes.fHalf2x2;
744 case 3: return *context.fTypes.fHalf3x2;
745 case 4: return *context.fTypes.fHalf4x2;
746 default: SK_ABORT("unsupported matrix column count (%d)", columns);
747 }
748 case 3:
749 switch (columns) {
750 case 2: return *context.fTypes.fHalf2x3;
751 case 3: return *context.fTypes.fHalf3x3;
752 case 4: return *context.fTypes.fHalf4x3;
753 default: SK_ABORT("unsupported matrix column count (%d)", columns);
754 }
755 case 4:
756 switch (columns) {
757 case 2: return *context.fTypes.fHalf2x4;
758 case 3: return *context.fTypes.fHalf3x4;
759 case 4: return *context.fTypes.fHalf4x4;
760 default: SK_ABORT("unsupported matrix column count (%d)", columns);
761 }
762 default: SK_ABORT("unsupported row count (%d)", rows);
763 }
764 } else if (this->matches(*context.fTypes.fInt) || this->matches(*context.fTypes.fIntLiteral)) {
765 switch (rows) {
766 case 1:
767 switch (columns) {
768 case 1: return *context.fTypes.fInt;
769 case 2: return *context.fTypes.fInt2;
770 case 3: return *context.fTypes.fInt3;
771 case 4: return *context.fTypes.fInt4;
772 default: SK_ABORT("unsupported vector column count (%d)", columns);
773 }
774 default: SK_ABORT("unsupported row count (%d)", rows);
775 }
776 } else if (this->matches(*context.fTypes.fShort)) {
777 switch (rows) {
778 case 1:
779 switch (columns) {
780 case 1: return *context.fTypes.fShort;
781 case 2: return *context.fTypes.fShort2;
782 case 3: return *context.fTypes.fShort3;
783 case 4: return *context.fTypes.fShort4;
784 default: SK_ABORT("unsupported vector column count (%d)", columns);
785 }
786 default: SK_ABORT("unsupported row count (%d)", rows);
787 }
788 } else if (this->matches(*context.fTypes.fUInt)) {
789 switch (rows) {
790 case 1:
791 switch (columns) {
792 case 1: return *context.fTypes.fUInt;
793 case 2: return *context.fTypes.fUInt2;
794 case 3: return *context.fTypes.fUInt3;
795 case 4: return *context.fTypes.fUInt4;
796 default: SK_ABORT("unsupported vector column count (%d)", columns);
797 }
798 default: SK_ABORT("unsupported row count (%d)", rows);
799 }
800 } else if (this->matches(*context.fTypes.fUShort)) {
801 switch (rows) {
802 case 1:
803 switch (columns) {
804 case 1: return *context.fTypes.fUShort;
805 case 2: return *context.fTypes.fUShort2;
806 case 3: return *context.fTypes.fUShort3;
807 case 4: return *context.fTypes.fUShort4;
808 default: SK_ABORT("unsupported vector column count (%d)", columns);
809 }
810 default: SK_ABORT("unsupported row count (%d)", rows);
811 }
812 } else if (this->matches(*context.fTypes.fBool)) {
813 switch (rows) {
814 case 1:
815 switch (columns) {
816 case 1: return *context.fTypes.fBool;
817 case 2: return *context.fTypes.fBool2;
818 case 3: return *context.fTypes.fBool3;
819 case 4: return *context.fTypes.fBool4;
820 default: SK_ABORT("unsupported vector column count (%d)", columns);
821 }
822 default: SK_ABORT("unsupported row count (%d)", rows);
823 }
824 }
825 SkDEBUGFAILF("unsupported toCompound type %s", this->description().c_str());
826 return *context.fTypes.fVoid;
827 }
828
clone(SymbolTable * symbolTable) const829 const Type* Type::clone(SymbolTable* symbolTable) const {
830 // Many types are built-ins, and exist in every SymbolTable by default.
831 if (this->isInBuiltinTypes()) {
832 return this;
833 }
834 // Even if the type isn't a built-in, it might already exist in the SymbolTable.
835 const Symbol* clonedSymbol = (*symbolTable)[this->name()];
836 if (clonedSymbol != nullptr) {
837 const Type& clonedType = clonedSymbol->as<Type>();
838 SkASSERT(clonedType.typeKind() == this->typeKind());
839 return &clonedType;
840 }
841 // This type actually needs to be cloned into the destination SymbolTable.
842 switch (this->typeKind()) {
843 case TypeKind::kArray: {
844 return symbolTable->addArrayDimension(&this->componentType(), this->columns());
845 }
846 case TypeKind::kStruct: {
847 const std::string* name = symbolTable->takeOwnershipOfString(std::string(this->name()));
848 return symbolTable->add(Type::MakeStructType(
849 this->fLine, *name, this->fields(), this->isInterfaceBlock()));
850 }
851 default:
852 SkDEBUGFAILF("don't know how to clone type '%s'", this->description().c_str());
853 return nullptr;
854 }
855 }
856
coerceExpression(std::unique_ptr<Expression> expr,const Context & context) const857 std::unique_ptr<Expression> Type::coerceExpression(std::unique_ptr<Expression> expr,
858 const Context& context) const {
859 if (!expr || expr->isIncomplete(context)) {
860 return nullptr;
861 }
862 if (expr->type().matches(*this)) {
863 return expr;
864 }
865
866 const int line = expr->fLine;
867 const Program::Settings& settings = context.fConfig->fSettings;
868 if (!expr->coercionCost(*this).isPossible(settings.fAllowNarrowingConversions)) {
869 context.fErrors->error(line, "expected '" + this->displayName() + "', but found '" +
870 expr->type().displayName() + "'");
871 return nullptr;
872 }
873
874 if (this->isScalar()) {
875 return ConstructorScalarCast::Make(context, line, *this, std::move(expr));
876 }
877 if (this->isVector() || this->isMatrix()) {
878 return ConstructorCompoundCast::Make(context, line, *this, std::move(expr));
879 }
880 if (this->isArray()) {
881 return ConstructorArrayCast::Make(context, line, *this, std::move(expr));
882 }
883 context.fErrors->error(line, "cannot construct '" + this->displayName() + "'");
884 return nullptr;
885 }
886
isPrivate() const887 bool Type::isPrivate() const {
888 return skstd::starts_with(this->name(), '$');
889 }
890
isOrContainsArray() const891 bool Type::isOrContainsArray() const {
892 if (this->isStruct()) {
893 for (const Field& f : this->fields()) {
894 if (f.fType->isOrContainsArray()) {
895 return true;
896 }
897 }
898 return false;
899 }
900
901 return this->isArray();
902 }
903
isTooDeeplyNested(int limit) const904 bool Type::isTooDeeplyNested(int limit) const {
905 if (limit < 0) {
906 return true;
907 }
908
909 if (this->isStruct()) {
910 for (const Type::Field& f : this->fields()) {
911 if (f.fType->isTooDeeplyNested(limit - 1)) {
912 return true;
913 }
914 }
915 }
916
917 return false;
918 }
919
isTooDeeplyNested() const920 bool Type::isTooDeeplyNested() const {
921 return this->isTooDeeplyNested(kMaxStructDepth);
922 }
923
isAllowedInES2(const Context & context) const924 bool Type::isAllowedInES2(const Context& context) const {
925 return !context.fConfig->strictES2Mode() || this->isAllowedInES2();
926 }
927
checkForOutOfRangeLiteral(const Context & context,const Expression & expr) const928 bool Type::checkForOutOfRangeLiteral(const Context& context, const Expression& expr) const {
929 bool foundError = false;
930 const Type& baseType = this->componentType();
931 if (baseType.isInteger()) {
932 // Replace constant expressions with their corresponding values.
933 const Expression* valueExpr = ConstantFolder::GetConstantValueForVariable(expr);
934 if (valueExpr->supportsConstantValues()) {
935 // Iterate over every constant subexpression in the value.
936 int numSlots = valueExpr->type().slotCount();
937 for (int slot = 0; slot < numSlots; ++slot) {
938 std::optional<double> slotVal = valueExpr->getConstantValue(slot);
939 // Check for Literal values that are out of range for the base type.
940 if (slotVal.has_value() &&
941 baseType.checkForOutOfRangeLiteral(context, *slotVal, valueExpr->fLine)) {
942 foundError = true;
943 }
944 }
945 }
946 }
947
948 // We don't need range checks for floats or booleans; any matched-type value is acceptable.
949 return foundError;
950 }
951
checkForOutOfRangeLiteral(const Context & context,double value,int line) const952 bool Type::checkForOutOfRangeLiteral(const Context& context, double value, int line) const {
953 SkASSERT(this->isScalar());
954 if (this->isInteger()) {
955 if (value < this->minimumValue() || value > this->maximumValue()) {
956 // We found a value that can't fit in the type. Flag it as an error.
957 context.fErrors->error(
958 line,
959 SkSL::String::printf("integer is out of range for type '%s': %.0f",
960 this->displayName().c_str(),
961 std::floor(value)));
962 return true;
963 }
964 }
965 return false;
966 }
967
convertArraySize(const Context & context,std::unique_ptr<Expression> size) const968 SKSL_INT Type::convertArraySize(const Context& context, std::unique_ptr<Expression> size) const {
969 size = context.fTypes.fInt->coerceExpression(std::move(size), context);
970 if (!size) {
971 return 0;
972 }
973 if (this->isArray()) {
974 context.fErrors->error(size->fLine, "multi-dimensional arrays are not supported");
975 return 0;
976 }
977 if (this->isVoid()) {
978 context.fErrors->error(size->fLine, "type 'void' may not be used in an array");
979 return 0;
980 }
981 if (this->isOpaque()) {
982 context.fErrors->error(size->fLine, "opaque type '" + std::string(this->name()) +
983 "' may not be used in an array");
984 return 0;
985 }
986 SKSL_INT count;
987 if (!ConstantFolder::GetConstantInt(*size, &count)) {
988 context.fErrors->error(size->fLine, "array size must be an integer");
989 return 0;
990 }
991 if (count <= 0) {
992 context.fErrors->error(size->fLine, "array size must be positive");
993 return 0;
994 }
995 if (!SkTFitsIn<int32_t>(count)) {
996 context.fErrors->error(size->fLine, "array size is too large");
997 return 0;
998 }
999 return static_cast<int>(count);
1000 }
1001
1002 } // namespace SkSL
1003