Unify conversion constructor simplification code.

Previously, the IR generator had code which could simplify conversion
constructors like `int(1.23)`. Separately, the optimizer's constant
propagation pass had its own separate implementation of these
simplifications as well.

This CL unifies the two implementations. Previously, the constant-
propagation pass version of the code only supported integer literals, so
this change also improves our code generation slightly.

Change-Id: I32c70a5f2aed210d03bef3166b1178a2d40cdabd
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/350024
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: John Stiles <johnstiles@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
This commit is contained in:
John Stiles 2021-01-05 18:47:09 -05:00 committed by Skia Commit-Bot
parent 6cab033499
commit 53f0ddfa4e
10 changed files with 111 additions and 127 deletions

View File

@ -2297,79 +2297,24 @@ std::unique_ptr<Expression> IRGenerator::call(int offset,
}
}
std::unique_ptr<Expression> IRGenerator::convertNumberConstructor(int offset,
std::unique_ptr<Expression> IRGenerator::convertScalarConstructor(int offset,
const Type& type,
ExpressionArray args) {
SkASSERT(type.isNumber());
SkASSERT(type.isNumber() || type.isBoolean());
if (args.size() != 1) {
fErrors.error(offset, "invalid arguments to '" + type.displayName() +
"' constructor, (expected exactly 1 argument, but found " +
to_string((uint64_t) args.size()) + ")");
return nullptr;
}
const Type& argType = args[0]->type();
if (type.isFloat()) {
if (args[0]->is<FloatLiteral>()) {
// Convert float(1.23) into a FloatLiteral. (Or half(1.23).)
return std::make_unique<FloatLiteral>(offset, args[0]->as<FloatLiteral>().value(),
&type);
}
if (args[0]->is<IntLiteral>()) {
// Convert float(123) into a FloatLiteral. (Or half(123).)
SKSL_FLOAT value = (SKSL_FLOAT)args[0]->as<IntLiteral>().value();
return std::make_unique<FloatLiteral>(offset, value, &type);
}
if (args[0]->is<BoolLiteral>()) {
// Convert float(true) into a FloatLiteral. (Or half(true).)
bool value = args[0]->as<BoolLiteral>().value();
return std::make_unique<FloatLiteral>(offset, value ? 1.0 : 0.0, &type);
}
} else if (type.isInteger()) {
if (args[0]->is<IntLiteral>()) {
// Convert int(123) into an IntLiteral. (Or uint(123), short(), byte(), etc.)
return std::make_unique<IntLiteral>(offset, args[0]->as<IntLiteral>().value(), &type);
}
if (args[0]->is<FloatLiteral>()) {
// Convert int(1.23) into an IntLiteral. (Or uint(1.23), short(), byte(), etc.)
SKSL_INT value = (SKSL_INT)args[0]->as<FloatLiteral>().value();
return std::make_unique<IntLiteral>(offset, value, &type);
}
if (args[0]->is<BoolLiteral>()) {
// Convert int(true) into an IntLiteral. (Or uint(true), short(), byte(), etc.)
bool value = args[0]->as<BoolLiteral>().value();
return std::make_unique<IntLiteral>(offset, value ? 1 : 0, &type);
}
}
if (!argType.isNumber() && !argType.isBoolean()) {
fErrors.error(offset, "invalid argument to '" + type.displayName() +
"' constructor (expected a number or bool, but found '" +
argType.displayName() + "')");
return nullptr;
}
return std::make_unique<Constructor>(offset, &type, std::move(args));
}
std::unique_ptr<Expression> IRGenerator::convertBooleanConstructor(int offset,
const Type& type,
ExpressionArray args) {
SkASSERT(type.isBoolean());
if (args.size() != 1) {
fErrors.error(offset, "invalid arguments to '" + type.displayName() +
"' constructor, (expected exactly 1 argument, but found " +
to_string((uint64_t) args.size()) + ")");
return nullptr;
std::unique_ptr<Expression> converted = Constructor::SimplifyConversion(fContext, type,
*args[0]);
if (converted) {
return converted;
}
const Type& argType = args[0]->type();
if (args[0]->is<FloatLiteral>()) {
// Convert bool(1.23) into a BoolLiteral.
return std::make_unique<BoolLiteral>(fContext, offset,
args[0]->as<FloatLiteral>().value() != 0.0);
}
if (args[0]->is<IntLiteral>()) {
// Convert bool(123) into a BoolLiteral.
return std::make_unique<BoolLiteral>(fContext, offset,
args[0]->as<IntLiteral>().value() != 0);
}
if (!argType.isNumber() && !argType.isBoolean()) {
fErrors.error(offset, "invalid argument to '" + type.displayName() +
"' constructor (expected a number or bool, but found '" +
@ -2445,11 +2390,8 @@ std::unique_ptr<Expression> IRGenerator::convertConstructor(int offset,
// Strip off redundant casts--i.e., convert Type(exprOfType) into exprOfType.
return std::move(args[0]);
}
if (type.isNumber()) {
return this->convertNumberConstructor(offset, type, std::move(args));
}
if (type.isBoolean()) {
return this->convertBooleanConstructor(offset, type, std::move(args));
if (type.isNumber() || type.isBoolean()) {
return this->convertScalarConstructor(offset, type, std::move(args));
}
if (type.isVector() || type.isMatrix()) {
return this->convertCompoundConstructor(offset, type, std::move(args));

View File

@ -179,12 +179,9 @@ private:
const Expression& right) const;
std::unique_ptr<Block> convertBlock(const ASTNode& block);
std::unique_ptr<Statement> convertBreak(const ASTNode& b);
std::unique_ptr<Expression> convertNumberConstructor(int offset,
std::unique_ptr<Expression> convertScalarConstructor(int offset,
const Type& type,
ExpressionArray params);
std::unique_ptr<Expression> convertBooleanConstructor(int offset,
const Type& type,
ExpressionArray params);
std::unique_ptr<Expression> convertCompoundConstructor(int offset,
const Type& type,
ExpressionArray params);

View File

@ -7,24 +7,62 @@
#include "src/sksl/ir/SkSLConstructor.h"
#include "src/sksl/ir/SkSLBoolLiteral.h"
#include "src/sksl/ir/SkSLFloatLiteral.h"
#include "src/sksl/ir/SkSLIntLiteral.h"
#include "src/sksl/ir/SkSLPrefixExpression.h"
namespace SkSL {
std::unique_ptr<Expression> Constructor::constantPropagate(const IRGenerator& irGenerator,
const DefinitionMap& definitions) {
if (this->arguments().size() == 1 && this->arguments()[0]->is<IntLiteral>()) {
const Context& context = irGenerator.fContext;
const Type& type = this->type();
SKSL_INT intValue = this->arguments()[0]->as<IntLiteral>().value();
// Handle conversion constructors of literal values.
if (this->arguments().size() == 1) {
return SimplifyConversion(irGenerator.fContext, this->type(), *this->arguments().front());
}
return nullptr;
}
if (type.isFloat()) {
std::unique_ptr<Expression> Constructor::SimplifyConversion(const Context& context,
const Type& constructorType,
const Expression& expr) {
if (expr.is<IntLiteral>()) {
SKSL_INT value = expr.as<IntLiteral>().value();
if (constructorType.isFloat()) {
// promote float(1) to 1.0
return std::make_unique<FloatLiteral>(context, fOffset, intValue);
} else if (type.isInteger()) {
return std::make_unique<FloatLiteral>(expr.fOffset, (SKSL_FLOAT)value,
&constructorType);
} else if (constructorType.isInteger()) {
// promote uint(1) to 1u
return std::make_unique<IntLiteral>(fOffset, intValue, &type);
} else if (&type == context.fBool_Type.get()) {
// promote bool(k) to true/false
return std::make_unique<BoolLiteral>(context, fOffset, intValue != 0);
return std::make_unique<IntLiteral>(expr.fOffset, value, &constructorType);
} else if (constructorType.isBoolean()) {
// promote bool(1) to true/false
return std::make_unique<BoolLiteral>(context, expr.fOffset, value != 0);
}
} else if (expr.is<FloatLiteral>()) {
float value = expr.as<FloatLiteral>().value();
if (constructorType.isFloat()) {
// promote float(1.23) to 1.23
return std::make_unique<FloatLiteral>(expr.fOffset, value, &constructorType);
} else if (constructorType.isInteger()) {
// promote uint(1.23) to 1u
return std::make_unique<IntLiteral>(expr.fOffset, (SKSL_INT)value, &constructorType);
} else if (constructorType.isBoolean()) {
// promote bool(1.23) to true/false
return std::make_unique<BoolLiteral>(context, expr.fOffset, value != 0.0f);
}
} else if (expr.is<BoolLiteral>()) {
bool value = expr.as<BoolLiteral>().value();
if (constructorType.isFloat()) {
// promote float(true) to 1.0
return std::make_unique<FloatLiteral>(expr.fOffset, value ? 1.0f : 0.0f,
&constructorType);
} else if (constructorType.isInteger()) {
// promote uint(true) to 1u
return std::make_unique<IntLiteral>(expr.fOffset, value ? 1 : 0, &constructorType);
} else if (constructorType.isBoolean()) {
// promote bool(true) to true/false
return std::make_unique<BoolLiteral>(context, expr.fOffset, value);
}
}
return nullptr;

View File

@ -11,9 +11,6 @@
#include "include/private/SkTArray.h"
#include "src/sksl/SkSLIRGenerator.h"
#include "src/sksl/ir/SkSLExpression.h"
#include "src/sksl/ir/SkSLFloatLiteral.h"
#include "src/sksl/ir/SkSLIntLiteral.h"
#include "src/sksl/ir/SkSLPrefixExpression.h"
namespace SkSL {
@ -45,6 +42,15 @@ public:
std::unique_ptr<Expression> constantPropagate(const IRGenerator& irGenerator,
const DefinitionMap& definitions) override;
// If the passed-in expression is a literal, performs a constructor-conversion of the literal
// value to the constructor's type and returns that converted value as a new literal. e.g., the
// constructor expression `short(3.14)` would be represented as `FloatLiteral(3.14)` along with
// type `Short`, and this would result in `IntLiteral(3, type=Short)`. Returns nullptr if the
// expression is not a literal or the conversion cannot be made.
static std::unique_ptr<Expression> SimplifyConversion(const Context& context,
const Type& constructorType,
const Expression& expr);
bool hasProperty(Property property) const override {
for (const std::unique_ptr<Expression>& arg: this->arguments()) {
if (arg->hasProperty(property)) {

View File

@ -113,7 +113,7 @@ OpDecorate %156 RelaxedPrecision
%float_8_0 = OpConstant %float 8
%float_9_0 = OpConstant %float 9
%_ptr_Function_v3float = OpTypePointer Function %v3float
%146 = OpConstantComposite %v4float %float_0_0 %float_0_0 %float_0_0 %float_0_0
%146 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
%main = OpFunction %void None %11
%12 = OpLabel
%x = OpVariable %_ptr_Function_v4float Function

View File

@ -46,8 +46,8 @@ OpDecorate %72 RelaxedPrecision
OpDecorate %75 RelaxedPrecision
OpDecorate %78 RelaxedPrecision
OpDecorate %161 RelaxedPrecision
OpDecorate %167 RelaxedPrecision
OpDecorate %170 RelaxedPrecision
OpDecorate %166 RelaxedPrecision
OpDecorate %169 RelaxedPrecision
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Output_v4float = OpTypePointer Output %v4float
@ -112,6 +112,7 @@ OpDecorate %170 RelaxedPrecision
%v2bool = OpTypeVector %bool 2
%158 = OpConstantComposite %v2bool %false %false
%_ptr_Function_bool = OpTypePointer Function %bool
%float_0_0 = OpConstant %float 0
%main = OpFunction %void None %11
%12 = OpLabel
%h3 = OpVariable %_ptr_Function_v3float Function
@ -124,8 +125,8 @@ OpDecorate %170 RelaxedPrecision
%f2 = OpVariable %_ptr_Function_v2float Function
%f3 = OpVariable %_ptr_Function_v3float Function
%f2x2 = OpVariable %_ptr_Function_mat2v2float Function
%130 = OpVariable %_ptr_Function_mat3v3float Function
%138 = OpVariable %_ptr_Function_mat4v4float Function
%129 = OpVariable %_ptr_Function_mat3v3float Function
%137 = OpVariable %_ptr_Function_mat4v4float Function
%b3 = OpVariable %_ptr_Function_v3bool Function
%b4 = OpVariable %_ptr_Function_v4bool Function
OpStore %h3 %16
@ -204,36 +205,36 @@ OpStore %114 %float_1_0
%116 = OpCompositeExtract %float %115 0
%117 = OpLoad %v3float %f3
%118 = OpCompositeExtract %float %117 0
%120 = OpCompositeConstruct %v4float %float_1_0 %116 %118 %float_4_0
OpStore %sk_FragColor %120
%123 = OpCompositeConstruct %v2float %float_2_0 %float_0
%124 = OpCompositeConstruct %v2float %float_0 %float_2_0
%122 = OpCompositeConstruct %mat2v2float %123 %124
OpStore %f2x2 %122
%125 = OpAccessChain %_ptr_Function_v2float %f2x2 %int_0
%126 = OpAccessChain %_ptr_Function_float %125 %int_0
OpStore %126 %float_1_0
%127 = OpAccessChain %_ptr_Function_v2float %f2x2 %int_0
%128 = OpLoad %v2float %127
%129 = OpCompositeExtract %float %128 0
%132 = OpCompositeConstruct %v3float %float_3_0 %float_0 %float_0
%133 = OpCompositeConstruct %v3float %float_0 %float_3_0 %float_0
%134 = OpCompositeConstruct %v3float %float_0 %float_0 %float_3_0
%131 = OpCompositeConstruct %mat3v3float %132 %133 %134
OpStore %130 %131
%135 = OpAccessChain %_ptr_Function_v3float %130 %int_0
%136 = OpLoad %v3float %135
%137 = OpCompositeExtract %float %136 0
%119 = OpCompositeConstruct %v4float %float_1 %116 %118 %float_4
OpStore %sk_FragColor %119
%122 = OpCompositeConstruct %v2float %float_2_0 %float_0
%123 = OpCompositeConstruct %v2float %float_0 %float_2_0
%121 = OpCompositeConstruct %mat2v2float %122 %123
OpStore %f2x2 %121
%124 = OpAccessChain %_ptr_Function_v2float %f2x2 %int_0
%125 = OpAccessChain %_ptr_Function_float %124 %int_0
OpStore %125 %float_1_0
%126 = OpAccessChain %_ptr_Function_v2float %f2x2 %int_0
%127 = OpLoad %v2float %126
%128 = OpCompositeExtract %float %127 0
%131 = OpCompositeConstruct %v3float %float_3_0 %float_0 %float_0
%132 = OpCompositeConstruct %v3float %float_0 %float_3_0 %float_0
%133 = OpCompositeConstruct %v3float %float_0 %float_0 %float_3_0
%130 = OpCompositeConstruct %mat3v3float %131 %132 %133
OpStore %129 %130
%134 = OpAccessChain %_ptr_Function_v3float %129 %int_0
%135 = OpLoad %v3float %134
%136 = OpCompositeExtract %float %135 0
%140 = OpCompositeConstruct %v4float %float_4_0 %float_0 %float_0 %float_0
%141 = OpCompositeConstruct %v4float %float_0 %float_4_0 %float_0 %float_0
%142 = OpCompositeConstruct %v4float %float_0 %float_0 %float_4_0 %float_0
%143 = OpCompositeConstruct %v4float %float_0 %float_0 %float_0 %float_4_0
%139 = OpCompositeConstruct %mat4v4float %140 %141 %142 %143
OpStore %138 %139
%144 = OpAccessChain %_ptr_Function_v4float %138 %int_0
OpStore %137 %139
%144 = OpAccessChain %_ptr_Function_v4float %137 %int_0
%145 = OpLoad %v4float %144
%146 = OpCompositeExtract %float %145 0
%147 = OpCompositeConstruct %v4float %129 %137 %146 %float_1
%147 = OpCompositeConstruct %v4float %128 %136 %146 %float_1
OpStore %sk_FragColor %147
OpStore %b3 %151
OpStore %b4 %156
@ -242,15 +243,13 @@ OpStore %b4 %156
OpStore %b4 %161
%162 = OpAccessChain %_ptr_Function_bool %b3 %int_2
OpStore %162 %true
%164 = OpSelect %float %true %float_1_0 %float_0
%165 = OpSelect %float %false %float_1_0 %float_0
%167 = OpLoad %v3bool %b3
%168 = OpCompositeExtract %bool %167 0
%166 = OpSelect %float %168 %float_1_0 %float_0
%170 = OpLoad %v4bool %b4
%171 = OpCompositeExtract %bool %170 0
%169 = OpSelect %float %171 %float_1_0 %float_0
%172 = OpCompositeConstruct %v4float %164 %165 %166 %169
OpStore %sk_FragColor %172
%166 = OpLoad %v3bool %b3
%167 = OpCompositeExtract %bool %166 0
%165 = OpSelect %float %167 %float_1_0 %float_0
%169 = OpLoad %v4bool %b4
%170 = OpCompositeExtract %bool %169 0
%168 = OpSelect %float %170 %float_1_0 %float_0
%171 = OpCompositeConstruct %v4float %float_1 %float_0_0 %165 %168
OpStore %sk_FragColor %171
OpReturn
OpFunctionEnd

View File

@ -68,5 +68,5 @@ void main() {
b3.z = true;
sk_FragColor = vec4(float(true), float(false), float(b3.x), float(b4.x));
sk_FragColor = vec4(1.0, 0.0, float(b3.x), float(b4.x));
}

View File

@ -76,6 +76,6 @@ fragment Outputs fragmentMain(Inputs _in [[stage_in]], bool _frontFacing [[front
b3.z = true;
_out->sk_FragColor = float4(float(true), float(bool(false)), float(b3.x), float(b4.x));
_out->sk_FragColor = float4(1.0, 0.0, float(b3.x), float(b4.x));
return *_out;
}

View File

@ -24,7 +24,8 @@ OpDecorate %sk_Clockwise BuiltIn FrontFacing
%int_0 = OpConstant %int 0
%float_0 = OpConstant %float 0
%float_1 = OpConstant %float 1
%24 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
%float_0_0 = OpConstant %float 0
%24 = OpConstantComposite %v4float %float_0_0 %float_0_0 %float_0_0 %float_0_0
%main = OpFunction %void None %11
%12 = OpLabel
OpSelectionMerge %15 None

View File

@ -22,7 +22,8 @@ OpDecorate %sk_Clockwise BuiltIn FrontFacing
%11 = OpTypeFunction %void
%float_2 = OpConstant %float 2
%int = OpTypeInt 32 1
%21 = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2
%float_2_0 = OpConstant %float 2
%21 = OpConstantComposite %v4float %float_2_0 %float_2_0 %float_2_0 %float_2_0
%main = OpFunction %void None %11
%12 = OpLabel
%14 = OpExtInst %float %1 Sqrt %float_2