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