• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 Google LLC
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/SkSLConstantFolder.h"
9 #include "src/sksl/ir/SkSLConstructorScalarCast.h"
10 
11 namespace SkSL {
12 
cast_scalar_literal(const Type & constructorType,const Expression & expr)13 static std::unique_ptr<Expression> cast_scalar_literal(const Type& constructorType,
14                                                        const Expression& expr) {
15     if (expr.is<IntLiteral>()) {
16         SKSL_INT value = expr.as<IntLiteral>().value();
17         if (constructorType.isFloat()) {
18             // promote float(1) to 1.0
19             return FloatLiteral::Make(expr.fOffset, (SKSL_FLOAT)value, &constructorType);
20         } else if (constructorType.isInteger()) {
21             // promote uint(1) to 1u
22             return IntLiteral::Make(expr.fOffset, value, &constructorType);
23         } else if (constructorType.isBoolean()) {
24             // promote bool(1) to true/false
25             return BoolLiteral::Make(expr.fOffset, value != 0, &constructorType);
26         }
27     } else if (expr.is<FloatLiteral>()) {
28         float value = expr.as<FloatLiteral>().value();
29         if (constructorType.isFloat()) {
30             // promote float(1.23) to 1.23
31             return FloatLiteral::Make(expr.fOffset, value, &constructorType);
32         } else if (constructorType.isInteger()) {
33             // promote uint(1.23) to 1u
34             return IntLiteral::Make(expr.fOffset, (SKSL_INT)value, &constructorType);
35         } else if (constructorType.isBoolean()) {
36             // promote bool(1.23) to true/false
37             return BoolLiteral::Make(expr.fOffset, value != 0.0f, &constructorType);
38         }
39     } else if (expr.is<BoolLiteral>()) {
40         bool value = expr.as<BoolLiteral>().value();
41         if (constructorType.isFloat()) {
42             // promote float(true) to 1.0
43             return FloatLiteral::Make(expr.fOffset, value ? 1.0f : 0.0f, &constructorType);
44         } else if (constructorType.isInteger()) {
45             // promote uint(true) to 1u
46             return IntLiteral::Make(expr.fOffset, value ? 1 : 0, &constructorType);
47         } else if (constructorType.isBoolean()) {
48             // promote bool(true) to true/false
49             return BoolLiteral::Make(expr.fOffset, value, &constructorType);
50         }
51     }
52     return nullptr;
53 }
54 
Convert(const Context & context,int offset,const Type & rawType,ExpressionArray args)55 std::unique_ptr<Expression> ConstructorScalarCast::Convert(const Context& context,
56                                                            int offset,
57                                                            const Type& rawType,
58                                                            ExpressionArray args) {
59     // As you might expect, scalar-cast constructors should only be created with scalar types.
60     const Type& type = rawType.scalarTypeForLiteral();
61     SkASSERT(type.isScalar());
62 
63     if (args.size() != 1) {
64         context.fErrors.error(offset, "invalid arguments to '" + type.displayName() +
65                                       "' constructor, (expected exactly 1 argument, but found " +
66                                       to_string((uint64_t)args.size()) + ")");
67         return nullptr;
68     }
69 
70     const Type& argType = args[0]->type();
71     if (!argType.isScalar()) {
72         context.fErrors.error(offset, "invalid argument to '" + type.displayName() +
73                                       "' constructor (expected a number or bool, but found '" +
74                                       argType.displayName() + "')");
75         return nullptr;
76     }
77 
78     return ConstructorScalarCast::Make(context, offset, type, std::move(args[0]));
79 }
80 
Make(const Context & context,int offset,const Type & type,std::unique_ptr<Expression> arg)81 std::unique_ptr<Expression> ConstructorScalarCast::Make(const Context& context,
82                                                         int offset,
83                                                         const Type& type,
84                                                         std::unique_ptr<Expression> arg) {
85     SkASSERT(type.isScalar());
86     SkASSERT(arg->type().isScalar());
87 
88     // No cast required when the types match.
89     if (arg->type() == type) {
90         return arg;
91     }
92     // When optimization is on, look up the value of constant variables. This allows expressions
93     // like `int(zero)` to be replaced with a literal zero.
94     if (context.fConfig->fSettings.fOptimize) {
95         arg = ConstantFolder::MakeConstantValueForVariable(std::move(arg));
96     }
97     // We can cast scalar literals at compile-time.
98     if (std::unique_ptr<Expression> converted = cast_scalar_literal(type, *arg)) {
99         return converted;
100     }
101     return std::make_unique<ConstructorScalarCast>(offset, type, std::move(arg));
102 }
103 
104 }  // namespace SkSL
105