Represent scalar-cast constructors with ConstructorScalarCast.
Change-Id: Iff8477f3797c83059c823ca9287493b7f30db71b Bug: skia:11032 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/392438 Auto-Submit: John Stiles <johnstiles@google.com> Commit-Queue: Brian Osman <brianosman@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
This commit is contained in:
parent
1f56479d6e
commit
fd7252fa23
@ -98,6 +98,8 @@ skia_sksl_sources = [
|
||||
"$_src/sksl/ir/SkSLConstructorArray.h",
|
||||
"$_src/sksl/ir/SkSLConstructorDiagonalMatrix.cpp",
|
||||
"$_src/sksl/ir/SkSLConstructorDiagonalMatrix.h",
|
||||
"$_src/sksl/ir/SkSLConstructorScalarCast.cpp",
|
||||
"$_src/sksl/ir/SkSLConstructorScalarCast.h",
|
||||
"$_src/sksl/ir/SkSLConstructorSplat.cpp",
|
||||
"$_src/sksl/ir/SkSLConstructorSplat.h",
|
||||
"$_src/sksl/ir/SkSLContinueStatement.h",
|
||||
|
@ -750,7 +750,11 @@ bool Analysis::IsSameExpressionTree(const Expression& left, const Expression& ri
|
||||
case Expression::Kind::kConstructor:
|
||||
case Expression::Kind::kConstructorArray:
|
||||
case Expression::Kind::kConstructorDiagonalMatrix:
|
||||
case Expression::Kind::kConstructorScalarCast:
|
||||
case Expression::Kind::kConstructorSplat: {
|
||||
if (left.kind() != right.kind()) {
|
||||
return false;
|
||||
}
|
||||
const AnyConstructor& leftCtor = left.asAnyConstructor();
|
||||
const AnyConstructor& rightCtor = right.asAnyConstructor();
|
||||
const auto leftSpan = leftCtor.argumentSpan();
|
||||
@ -1020,6 +1024,7 @@ public:
|
||||
case Expression::Kind::kConstructor:
|
||||
case Expression::Kind::kConstructorArray:
|
||||
case Expression::Kind::kConstructorDiagonalMatrix:
|
||||
case Expression::Kind::kConstructorScalarCast:
|
||||
case Expression::Kind::kConstructorSplat:
|
||||
case Expression::Kind::kFieldAccess:
|
||||
case Expression::Kind::kIndex:
|
||||
@ -1145,6 +1150,7 @@ template <typename T> bool TProgramVisitor<T>::visitExpression(typename T::Expre
|
||||
case Expression::Kind::kConstructor:
|
||||
case Expression::Kind::kConstructorArray:
|
||||
case Expression::Kind::kConstructorDiagonalMatrix:
|
||||
case Expression::Kind::kConstructorScalarCast:
|
||||
case Expression::Kind::kConstructorSplat: {
|
||||
auto& c = e.asAnyConstructor();
|
||||
for (auto& arg : c.argumentSpan()) {
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "src/sksl/ir/SkSLConstructor.h"
|
||||
#include "src/sksl/ir/SkSLConstructorArray.h"
|
||||
#include "src/sksl/ir/SkSLConstructorDiagonalMatrix.h"
|
||||
#include "src/sksl/ir/SkSLConstructorScalarCast.h"
|
||||
#include "src/sksl/ir/SkSLConstructorSplat.h"
|
||||
#include "src/sksl/ir/SkSLContinueStatement.h"
|
||||
#include "src/sksl/ir/SkSLDiscardStatement.h"
|
||||
@ -302,6 +303,12 @@ void Dehydrator::write(const Expression* e) {
|
||||
this->writeExpressionSpan(e->as<ConstructorDiagonalMatrix>().argumentSpan());
|
||||
break;
|
||||
|
||||
case Expression::Kind::kConstructorScalarCast:
|
||||
this->writeCommand(Rehydrator::kConstructorScalarCast_Command);
|
||||
this->write(e->type());
|
||||
this->writeExpressionSpan(e->as<ConstructorScalarCast>().argumentSpan());
|
||||
break;
|
||||
|
||||
case Expression::Kind::kConstructorSplat:
|
||||
this->writeCommand(Rehydrator::kConstructorSplat_Command);
|
||||
this->write(e->type());
|
||||
|
@ -199,7 +199,8 @@ void GLSLCodeGenerator::writeExpression(const Expression& expr, Precedence paren
|
||||
this->writeBoolLiteral(expr.as<BoolLiteral>());
|
||||
break;
|
||||
case Expression::Kind::kConstructor:
|
||||
this->writeConstructor(expr.as<Constructor>(), parentPrecedence);
|
||||
case Expression::Kind::kConstructorScalarCast:
|
||||
this->writeConstructorAsNecessary(expr.asAnyConstructor(), parentPrecedence);
|
||||
break;
|
||||
case Expression::Kind::kConstructorArray:
|
||||
case Expression::Kind::kConstructorDiagonalMatrix:
|
||||
@ -725,17 +726,19 @@ void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
|
||||
this->write(")");
|
||||
}
|
||||
|
||||
void GLSLCodeGenerator::writeConstructor(const Constructor& c, Precedence parentPrecedence) {
|
||||
if (c.arguments().size() == 1 &&
|
||||
(this->getTypeName(c.type()) == this->getTypeName(c.arguments()[0]->type()) ||
|
||||
(c.type().isScalar() &&
|
||||
c.arguments()[0]->type() == *fContext.fTypes.fFloatLiteral))) {
|
||||
// in cases like half(float), they're different types as far as SkSL is concerned but the
|
||||
// same type as far as GLSL is concerned. We avoid a redundant float(float) by just writing
|
||||
// out the inner expression here.
|
||||
this->writeExpression(*c.arguments()[0], parentPrecedence);
|
||||
void GLSLCodeGenerator::writeConstructorAsNecessary(const AnyConstructor& c,
|
||||
Precedence parentPrecedence) {
|
||||
const auto arguments = c.argumentSpan();
|
||||
if (arguments.size() == 1 &&
|
||||
(this->getTypeName(c.type()) == this->getTypeName(arguments.front()->type()) ||
|
||||
(arguments.front()->type() == *fContext.fTypes.fFloatLiteral))) {
|
||||
// In cases like half(float), they're different types as far as SkSL is concerned but
|
||||
// the same type as far as GLSL is concerned. We avoid a redundant float(float) by just
|
||||
// writing out the inner expression here.
|
||||
this->writeExpression(*arguments.front(), parentPrecedence);
|
||||
return;
|
||||
}
|
||||
// This cast should be emitted as-is.
|
||||
return this->writeAnyConstructor(c, parentPrecedence);
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "src/sksl/ir/SkSLBinaryExpression.h"
|
||||
#include "src/sksl/ir/SkSLBoolLiteral.h"
|
||||
#include "src/sksl/ir/SkSLConstructor.h"
|
||||
#include "src/sksl/ir/SkSLConstructorScalarCast.h"
|
||||
#include "src/sksl/ir/SkSLDoStatement.h"
|
||||
#include "src/sksl/ir/SkSLExtension.h"
|
||||
#include "src/sksl/ir/SkSLFieldAccess.h"
|
||||
@ -134,7 +135,7 @@ protected:
|
||||
|
||||
virtual void writeFunctionCall(const FunctionCall& c);
|
||||
|
||||
void writeConstructor(const Constructor& c, Precedence parentPrecedence);
|
||||
void writeConstructorAsNecessary(const AnyConstructor& c, Precedence parentPrecedence);
|
||||
|
||||
void writeAnyConstructor(const AnyConstructor& c, Precedence parentPrecedence);
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "src/sksl/ir/SkSLConstructor.h"
|
||||
#include "src/sksl/ir/SkSLConstructorArray.h"
|
||||
#include "src/sksl/ir/SkSLConstructorDiagonalMatrix.h"
|
||||
#include "src/sksl/ir/SkSLConstructorScalarCast.h"
|
||||
#include "src/sksl/ir/SkSLConstructorSplat.h"
|
||||
#include "src/sksl/ir/SkSLContinueStatement.h"
|
||||
#include "src/sksl/ir/SkSLDiscardStatement.h"
|
||||
@ -327,6 +328,12 @@ std::unique_ptr<Expression> Inliner::inlineExpression(int offset,
|
||||
*ctor.type().clone(symbolTableForExpression),
|
||||
expr(ctor.argument()));
|
||||
}
|
||||
case Expression::Kind::kConstructorScalarCast: {
|
||||
const ConstructorScalarCast& ctor = expression.as<ConstructorScalarCast>();
|
||||
return ConstructorScalarCast::Make(*fContext, offset,
|
||||
*ctor.type().clone(symbolTableForExpression),
|
||||
expr(ctor.argument()));
|
||||
}
|
||||
case Expression::Kind::kConstructorSplat: {
|
||||
const ConstructorSplat& ctor = expression.as<ConstructorSplat>();
|
||||
return ConstructorSplat::Make(*fContext, offset,
|
||||
@ -930,6 +937,7 @@ public:
|
||||
case Expression::Kind::kConstructor:
|
||||
case Expression::Kind::kConstructorArray:
|
||||
case Expression::Kind::kConstructorDiagonalMatrix:
|
||||
case Expression::Kind::kConstructorScalarCast:
|
||||
case Expression::Kind::kConstructorSplat: {
|
||||
AnyConstructor& constructorExpr = (*expr)->asAnyConstructor();
|
||||
for (std::unique_ptr<Expression>& arg : constructorExpr.argumentSpan()) {
|
||||
|
@ -181,6 +181,9 @@ void MetalCodeGenerator::writeExpression(const Expression& expr, Precedence pare
|
||||
this->writeSingleArgumentConstructor(expr.as<ConstructorDiagonalMatrix>(),
|
||||
parentPrecedence);
|
||||
break;
|
||||
case Expression::Kind::kConstructorScalarCast:
|
||||
this->writeConstructorScalarCast(expr.as<ConstructorScalarCast>(), parentPrecedence);
|
||||
break;
|
||||
case Expression::Kind::kConstructorSplat:
|
||||
this->writeSingleArgumentConstructor(expr.as<ConstructorSplat>(), parentPrecedence);
|
||||
break;
|
||||
@ -1055,26 +1058,13 @@ void MetalCodeGenerator::writeConstructor(const Constructor& c, Precedence paren
|
||||
// Handle special cases for single-argument constructors.
|
||||
if (c.arguments().size() == 1) {
|
||||
// If the type is coercible, emit it directly.
|
||||
// (This will no longer be needed when VectorCast is added.)
|
||||
const Expression& arg = *c.arguments().front();
|
||||
const Type& argType = arg.type();
|
||||
if (this->canCoerce(constructorType, argType)) {
|
||||
this->writeExpression(arg, parentPrecedence);
|
||||
return;
|
||||
}
|
||||
|
||||
// Metal supports creating matrices with a scalar on the diagonal via the single-argument
|
||||
// matrix constructor.
|
||||
if (constructorType.isMatrix() && argType.isNumber()) {
|
||||
const Type& matrix = constructorType;
|
||||
this->write("float");
|
||||
this->write(to_string(matrix.columns()));
|
||||
this->write("x");
|
||||
this->write(to_string(matrix.rows()));
|
||||
this->write("(");
|
||||
this->writeExpression(arg, parentPrecedence);
|
||||
this->write(")");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Emit and invoke a matrix-constructor helper method if one is necessary.
|
||||
@ -1140,6 +1130,19 @@ void MetalCodeGenerator::writeConstructorArray(const ConstructorArray& c,
|
||||
this->write("}");
|
||||
}
|
||||
|
||||
void MetalCodeGenerator::writeConstructorScalarCast(const ConstructorScalarCast& c,
|
||||
Precedence parentPrecedence) {
|
||||
// If the type is coercible, emit it directly.
|
||||
const Expression& arg = *c.argument();
|
||||
const Type& argType = arg.type();
|
||||
if (this->canCoerce(c.type(), argType)) {
|
||||
this->writeExpression(arg, parentPrecedence);
|
||||
return;
|
||||
}
|
||||
|
||||
return this->writeSingleArgumentConstructor(c, parentPrecedence);
|
||||
}
|
||||
|
||||
void MetalCodeGenerator::writeFragCoord() {
|
||||
if (fRTHeightName.length()) {
|
||||
this->write("float4(_fragCoord.x, ");
|
||||
@ -2265,6 +2268,7 @@ MetalCodeGenerator::Requirements MetalCodeGenerator::requirements(const Expressi
|
||||
case Expression::Kind::kConstructor:
|
||||
case Expression::Kind::kConstructorArray:
|
||||
case Expression::Kind::kConstructorDiagonalMatrix:
|
||||
case Expression::Kind::kConstructorScalarCast:
|
||||
case Expression::Kind::kConstructorSplat: {
|
||||
const AnyConstructor& c = e->asAnyConstructor();
|
||||
Requirements result = kNo_Requirements;
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "src/sksl/ir/SkSLBoolLiteral.h"
|
||||
#include "src/sksl/ir/SkSLConstructor.h"
|
||||
#include "src/sksl/ir/SkSLConstructorArray.h"
|
||||
#include "src/sksl/ir/SkSLConstructorScalarCast.h"
|
||||
#include "src/sksl/ir/SkSLDoStatement.h"
|
||||
#include "src/sksl/ir/SkSLExtension.h"
|
||||
#include "src/sksl/ir/SkSLFieldAccess.h"
|
||||
@ -232,6 +233,8 @@ protected:
|
||||
|
||||
void writeConstructorArray(const ConstructorArray& c, Precedence parentPrecedence);
|
||||
|
||||
void writeConstructorScalarCast(const ConstructorScalarCast& c, Precedence parentPrecedence);
|
||||
|
||||
void writeSingleArgumentConstructor(const SingleArgumentConstructor& c,
|
||||
Precedence parentPrecedence);
|
||||
|
||||
|
@ -412,6 +412,7 @@ void PipelineStageCodeGenerator::writeExpression(const Expression& expr,
|
||||
case Expression::Kind::kConstructor:
|
||||
case Expression::Kind::kConstructorArray:
|
||||
case Expression::Kind::kConstructorDiagonalMatrix:
|
||||
case Expression::Kind::kConstructorScalarCast:
|
||||
case Expression::Kind::kConstructorSplat:
|
||||
this->writeAnyConstructor(expr.asAnyConstructor(), parentPrecedence);
|
||||
break;
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "src/sksl/ir/SkSLConstructor.h"
|
||||
#include "src/sksl/ir/SkSLConstructorArray.h"
|
||||
#include "src/sksl/ir/SkSLConstructorDiagonalMatrix.h"
|
||||
#include "src/sksl/ir/SkSLConstructorScalarCast.h"
|
||||
#include "src/sksl/ir/SkSLConstructorSplat.h"
|
||||
#include "src/sksl/ir/SkSLContinueStatement.h"
|
||||
#include "src/sksl/ir/SkSLDiscardStatement.h"
|
||||
@ -471,6 +472,12 @@ std::unique_ptr<Expression> Rehydrator::expression() {
|
||||
return ConstructorDiagonalMatrix::Make(fContext, /*offset=*/-1, *type,
|
||||
std::move(args[0]));
|
||||
}
|
||||
case Rehydrator::kConstructorScalarCast_Command: {
|
||||
const Type* type = this->type();
|
||||
ExpressionArray args = this->expressionArray();
|
||||
SkASSERT(args.size() == 1);
|
||||
return ConstructorScalarCast::Make(fContext, /*offset=*/-1, *type, std::move(args[0]));
|
||||
}
|
||||
case Rehydrator::kConstructorSplat_Command: {
|
||||
const Type* type = this->type();
|
||||
ExpressionArray args = this->expressionArray();
|
||||
|
@ -54,7 +54,7 @@ public:
|
||||
kConstructorArray_Command,
|
||||
kConstructorDiagonalMatrix_Command,
|
||||
kConstructorSplat_Command,
|
||||
kConstructorVectorCast_Command,
|
||||
kConstructorScalarCast_Command,
|
||||
kConstructorReserved1_Command,
|
||||
kConstructorReserved2_Command,
|
||||
kConstructorReserved3_Command,
|
||||
|
@ -715,6 +715,8 @@ SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, OutputStream&
|
||||
return this->writeArrayConstructor(expr.as<ConstructorArray>(), out);
|
||||
case Expression::Kind::kConstructorDiagonalMatrix:
|
||||
return this->writeConstructorDiagonalMatrix(expr.as<ConstructorDiagonalMatrix>(), out);
|
||||
case Expression::Kind::kConstructorScalarCast:
|
||||
return this->writeConstructorScalarCast(expr.as<ConstructorScalarCast>(), out);
|
||||
case Expression::Kind::kConstructorSplat:
|
||||
return this->writeConstructorSplat(expr.as<ConstructorSplat>(), out);
|
||||
case Expression::Kind::kIntLiteral:
|
||||
@ -1219,10 +1221,10 @@ SpvId SPIRVCodeGenerator::writeConstantVector(const AnyConstructor& c) {
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, OutputStream& out) {
|
||||
SkASSERT(c.arguments().size() == 1);
|
||||
SpvId SPIRVCodeGenerator::writeFloatConstructor(const AnyConstructor& c, OutputStream& out) {
|
||||
SkASSERT(c.argumentSpan().size() == 1);
|
||||
SkASSERT(c.type().isFloat());
|
||||
const Expression& ctorExpr = *c.arguments()[0];
|
||||
const Expression& ctorExpr = *c.argumentSpan().front();
|
||||
SpvId expressionId = this->writeExpression(ctorExpr, out);
|
||||
return this->castScalarToFloat(expressionId, ctorExpr.type(), c.type(), out);
|
||||
}
|
||||
@ -1255,10 +1257,10 @@ SpvId SPIRVCodeGenerator::castScalarToFloat(SpvId inputId, const Type& inputType
|
||||
return result;
|
||||
}
|
||||
|
||||
SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, OutputStream& out) {
|
||||
SkASSERT(c.arguments().size() == 1);
|
||||
SpvId SPIRVCodeGenerator::writeIntConstructor(const AnyConstructor& c, OutputStream& out) {
|
||||
SkASSERT(c.argumentSpan().size() == 1);
|
||||
SkASSERT(c.type().isSigned());
|
||||
const Expression& ctorExpr = *c.arguments()[0];
|
||||
const Expression& ctorExpr = *c.argumentSpan().front();
|
||||
SpvId expressionId = this->writeExpression(ctorExpr, out);
|
||||
return this->castScalarToSignedInt(expressionId, ctorExpr.type(), c.type(), out);
|
||||
}
|
||||
@ -1292,10 +1294,10 @@ SpvId SPIRVCodeGenerator::castScalarToSignedInt(SpvId inputId, const Type& input
|
||||
return result;
|
||||
}
|
||||
|
||||
SpvId SPIRVCodeGenerator::writeUIntConstructor(const Constructor& c, OutputStream& out) {
|
||||
SkASSERT(c.arguments().size() == 1);
|
||||
SpvId SPIRVCodeGenerator::writeUIntConstructor(const AnyConstructor& c, OutputStream& out) {
|
||||
SkASSERT(c.argumentSpan().size() == 1);
|
||||
SkASSERT(c.type().isUnsigned());
|
||||
const Expression& ctorExpr = *c.arguments()[0];
|
||||
const Expression& ctorExpr = *c.argumentSpan().front();
|
||||
SpvId expressionId = this->writeExpression(ctorExpr, out);
|
||||
return this->castScalarToUnsignedInt(expressionId, ctorExpr.type(), c.type(), out);
|
||||
}
|
||||
@ -1329,10 +1331,10 @@ SpvId SPIRVCodeGenerator::castScalarToUnsignedInt(SpvId inputId, const Type& inp
|
||||
return result;
|
||||
}
|
||||
|
||||
SpvId SPIRVCodeGenerator::writeBooleanConstructor(const Constructor& c, OutputStream& out) {
|
||||
SkASSERT(c.arguments().size() == 1);
|
||||
SpvId SPIRVCodeGenerator::writeBooleanConstructor(const AnyConstructor& c, OutputStream& out) {
|
||||
SkASSERT(c.argumentSpan().size() == 1);
|
||||
SkASSERT(c.type().isBoolean());
|
||||
const Expression& ctorExpr = *c.arguments()[0];
|
||||
const Expression& ctorExpr = *c.argumentSpan().front();
|
||||
SpvId expressionId = this->writeExpression(ctorExpr, out);
|
||||
return this->castScalarToBoolean(expressionId, ctorExpr.type(), c.type(), out);
|
||||
}
|
||||
@ -1685,24 +1687,36 @@ SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, OutputStream& o
|
||||
this->getActualType(type) == this->getActualType(c.arguments()[0]->type())) {
|
||||
return this->writeExpression(*c.arguments()[0], out);
|
||||
}
|
||||
if (type.isVector()) {
|
||||
return this->writeVectorConstructor(c, out);
|
||||
}
|
||||
if (type.isMatrix()) {
|
||||
return this->writeMatrixConstructor(c, out);
|
||||
}
|
||||
fErrors.error(c.fOffset, "unsupported constructor: " + c.description());
|
||||
return -1;
|
||||
}
|
||||
|
||||
SpvId SPIRVCodeGenerator::writeConstructorScalarCast(const ConstructorScalarCast& c,
|
||||
OutputStream& out) {
|
||||
const Type& type = c.type();
|
||||
if (this->getActualType(type) == this->getActualType(c.argument()->type())) {
|
||||
return this->writeExpression(*c.argument(), out);
|
||||
}
|
||||
if (type.isFloat()) {
|
||||
return this->writeFloatConstructor(c, out);
|
||||
} else if (type.isSigned()) {
|
||||
}
|
||||
if (type.isSigned()) {
|
||||
return this->writeIntConstructor(c, out);
|
||||
} else if (type.isUnsigned()) {
|
||||
}
|
||||
if (type.isUnsigned()) {
|
||||
return this->writeUIntConstructor(c, out);
|
||||
} else if (type.isBoolean()) {
|
||||
}
|
||||
if (type.isBoolean()) {
|
||||
return this->writeBooleanConstructor(c, out);
|
||||
}
|
||||
switch (type.typeKind()) {
|
||||
case Type::TypeKind::kVector:
|
||||
return this->writeVectorConstructor(c, out);
|
||||
case Type::TypeKind::kMatrix:
|
||||
return this->writeMatrixConstructor(c, out);
|
||||
default:
|
||||
fErrors.error(c.fOffset, "unsupported constructor: " + c.description());
|
||||
return -1;
|
||||
}
|
||||
fErrors.error(c.fOffset, "unsupported scalar constructor: " + c.description());
|
||||
return -1;
|
||||
}
|
||||
|
||||
SpvId SPIRVCodeGenerator::writeConstructorDiagonalMatrix(const ConstructorDiagonalMatrix& c,
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "src/sksl/ir/SkSLConstructor.h"
|
||||
#include "src/sksl/ir/SkSLConstructorArray.h"
|
||||
#include "src/sksl/ir/SkSLConstructorDiagonalMatrix.h"
|
||||
#include "src/sksl/ir/SkSLConstructorScalarCast.h"
|
||||
#include "src/sksl/ir/SkSLConstructorSplat.h"
|
||||
#include "src/sksl/ir/SkSLDoStatement.h"
|
||||
#include "src/sksl/ir/SkSLFieldAccess.h"
|
||||
@ -244,22 +245,22 @@ private:
|
||||
|
||||
SpvId writeConstantVector(const AnyConstructor& c);
|
||||
|
||||
SpvId writeFloatConstructor(const Constructor& c, OutputStream& out);
|
||||
SpvId writeFloatConstructor(const AnyConstructor& c, OutputStream& out);
|
||||
|
||||
SpvId castScalarToFloat(SpvId inputId, const Type& inputType, const Type& outputType,
|
||||
OutputStream& out);
|
||||
|
||||
SpvId writeIntConstructor(const Constructor& c, OutputStream& out);
|
||||
SpvId writeIntConstructor(const AnyConstructor& c, OutputStream& out);
|
||||
|
||||
SpvId castScalarToSignedInt(SpvId inputId, const Type& inputType, const Type& outputType,
|
||||
OutputStream& out);
|
||||
|
||||
SpvId writeUIntConstructor(const Constructor& c, OutputStream& out);
|
||||
SpvId writeUIntConstructor(const AnyConstructor& c, OutputStream& out);
|
||||
|
||||
SpvId castScalarToUnsignedInt(SpvId inputId, const Type& inputType, const Type& outputType,
|
||||
OutputStream& out);
|
||||
|
||||
SpvId writeBooleanConstructor(const Constructor& c, OutputStream& out);
|
||||
SpvId writeBooleanConstructor(const AnyConstructor& c, OutputStream& out);
|
||||
|
||||
SpvId castScalarToBoolean(SpvId inputId, const Type& inputType, const Type& outputType,
|
||||
OutputStream& out);
|
||||
@ -292,6 +293,8 @@ private:
|
||||
|
||||
SpvId writeConstructorDiagonalMatrix(const ConstructorDiagonalMatrix& c, OutputStream& out);
|
||||
|
||||
SpvId writeConstructorScalarCast(const ConstructorScalarCast& c, OutputStream& out);
|
||||
|
||||
SpvId writeConstructorSplat(const ConstructorSplat& c, OutputStream& out);
|
||||
|
||||
SpvId writeFieldAccess(const FieldAccess& f, OutputStream& out);
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "src/sksl/ir/SkSLConstructor.h"
|
||||
#include "src/sksl/ir/SkSLConstructorArray.h"
|
||||
#include "src/sksl/ir/SkSLConstructorDiagonalMatrix.h"
|
||||
#include "src/sksl/ir/SkSLConstructorScalarCast.h"
|
||||
#include "src/sksl/ir/SkSLConstructorSplat.h"
|
||||
#include "src/sksl/ir/SkSLContinueStatement.h"
|
||||
#include "src/sksl/ir/SkSLDoStatement.h"
|
||||
@ -248,6 +249,7 @@ private:
|
||||
Value writeConstructor(const Constructor& c);
|
||||
Value writeMultiArgumentConstructor(const MultiArgumentConstructor& c);
|
||||
Value writeConstructorDiagonalMatrix(const ConstructorDiagonalMatrix& c);
|
||||
Value writeConstructorScalarCast(const ConstructorScalarCast& c);
|
||||
Value writeConstructorSplat(const ConstructorSplat& c);
|
||||
Value writeFunctionCall(const FunctionCall& c);
|
||||
Value writeExternalFunctionCall(const ExternalFunctionCall& c);
|
||||
@ -260,6 +262,8 @@ private:
|
||||
Value writeTernaryExpression(const TernaryExpression& t);
|
||||
Value writeVariableExpression(const VariableReference& expr);
|
||||
|
||||
Value writeTypeConversion(const Value& src, Type::NumberKind srcKind, Type::NumberKind dstKind);
|
||||
|
||||
void writeStatement(const Statement& s);
|
||||
void writeBlock(const Block& b);
|
||||
void writeBreakStatement();
|
||||
@ -685,62 +689,7 @@ Value SkVMGenerator::writeConstructor(const Constructor& c) {
|
||||
// TODO: Handle signed vs. unsigned. GLSL ES 1.0 only has 'int', so no problem yet.
|
||||
if (srcKind != dstKind) {
|
||||
// One argument constructors can do type conversion
|
||||
Value dst(src.slots());
|
||||
switch (dstKind) {
|
||||
case Type::NumberKind::kFloat:
|
||||
if (srcKind == Type::NumberKind::kSigned) {
|
||||
// int -> float
|
||||
for (size_t i = 0; i < src.slots(); ++i) {
|
||||
dst[i] = skvm::to_F32(i32(src[i]));
|
||||
}
|
||||
return dst;
|
||||
} else if (srcKind == Type::NumberKind::kBoolean) {
|
||||
// bool -> float
|
||||
for (size_t i = 0; i < src.slots(); ++i) {
|
||||
dst[i] = skvm::select(i32(src[i]), 1.0f, 0.0f);
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
break;
|
||||
|
||||
case Type::NumberKind::kSigned:
|
||||
if (srcKind == Type::NumberKind::kFloat) {
|
||||
// float -> int
|
||||
for (size_t i = 0; i < src.slots(); ++i) {
|
||||
dst[i] = skvm::trunc(f32(src[i]));
|
||||
}
|
||||
return dst;
|
||||
} else if (srcKind == Type::NumberKind::kBoolean) {
|
||||
// bool -> int
|
||||
for (size_t i = 0; i < src.slots(); ++i) {
|
||||
dst[i] = skvm::select(i32(src[i]), 1, 0);
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
break;
|
||||
|
||||
case Type::NumberKind::kBoolean:
|
||||
if (srcKind == Type::NumberKind::kSigned) {
|
||||
// int -> bool
|
||||
for (size_t i = 0; i < src.slots(); ++i) {
|
||||
dst[i] = i32(src[i]) != 0;
|
||||
}
|
||||
return dst;
|
||||
} else if (srcKind == Type::NumberKind::kFloat) {
|
||||
// float -> bool
|
||||
for (size_t i = 0; i < src.slots(); ++i) {
|
||||
dst[i] = f32(src[i]) != 0.0;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
SkDEBUGFAILF("Unsupported type conversion: %s -> %s", srcType.displayName().c_str(),
|
||||
dstType.displayName().c_str());
|
||||
return {};
|
||||
return this->writeTypeConversion(src, srcKind, dstKind);
|
||||
}
|
||||
|
||||
// Matrices can be constructed from scalars or other matrices
|
||||
@ -774,6 +723,84 @@ Value SkVMGenerator::writeConstructor(const Constructor& c) {
|
||||
return {};
|
||||
}
|
||||
|
||||
Value SkVMGenerator::writeTypeConversion(const Value& src,
|
||||
Type::NumberKind srcKind,
|
||||
Type::NumberKind dstKind) {
|
||||
// Conversion among "similar" types (floatN <-> halfN), (shortN <-> intN), etc. is a no-op.
|
||||
if (srcKind == dstKind) {
|
||||
return src;
|
||||
}
|
||||
|
||||
// TODO: Handle signed vs. unsigned. GLSL ES 1.0 only has 'int', so no problem yet.
|
||||
Value dst(src.slots());
|
||||
switch (dstKind) {
|
||||
case Type::NumberKind::kFloat:
|
||||
if (srcKind == Type::NumberKind::kSigned) {
|
||||
// int -> float
|
||||
for (size_t i = 0; i < src.slots(); ++i) {
|
||||
dst[i] = skvm::to_F32(i32(src[i]));
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
if (srcKind == Type::NumberKind::kBoolean) {
|
||||
// bool -> float
|
||||
for (size_t i = 0; i < src.slots(); ++i) {
|
||||
dst[i] = skvm::select(i32(src[i]), 1.0f, 0.0f);
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
break;
|
||||
|
||||
case Type::NumberKind::kSigned:
|
||||
if (srcKind == Type::NumberKind::kFloat) {
|
||||
// float -> int
|
||||
for (size_t i = 0; i < src.slots(); ++i) {
|
||||
dst[i] = skvm::trunc(f32(src[i]));
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
if (srcKind == Type::NumberKind::kBoolean) {
|
||||
// bool -> int
|
||||
for (size_t i = 0; i < src.slots(); ++i) {
|
||||
dst[i] = skvm::select(i32(src[i]), 1, 0);
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
break;
|
||||
|
||||
case Type::NumberKind::kBoolean:
|
||||
if (srcKind == Type::NumberKind::kSigned) {
|
||||
// int -> bool
|
||||
for (size_t i = 0; i < src.slots(); ++i) {
|
||||
dst[i] = i32(src[i]) != 0;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
if (srcKind == Type::NumberKind::kFloat) {
|
||||
// float -> bool
|
||||
for (size_t i = 0; i < src.slots(); ++i) {
|
||||
dst[i] = f32(src[i]) != 0.0;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
SkDEBUGFAILF("Unsupported type conversion: %d -> %d", srcKind, dstKind);
|
||||
return {};
|
||||
}
|
||||
|
||||
Value SkVMGenerator::writeConstructorScalarCast(const ConstructorScalarCast& c) {
|
||||
const Type& srcType = c.argument()->type();
|
||||
const Type& dstType = c.type();
|
||||
Type::NumberKind srcKind = base_number_kind(srcType);
|
||||
Type::NumberKind dstKind = base_number_kind(dstType);
|
||||
Value src = this->writeExpression(*c.argument());
|
||||
return this->writeTypeConversion(src, srcKind, dstKind);
|
||||
}
|
||||
|
||||
Value SkVMGenerator::writeConstructorSplat(const ConstructorSplat& c) {
|
||||
SkASSERT(c.type().isVector());
|
||||
SkASSERT(c.argument()->type().isScalar());
|
||||
@ -1464,6 +1491,8 @@ Value SkVMGenerator::writeExpression(const Expression& e) {
|
||||
return this->writeMultiArgumentConstructor(e.as<ConstructorArray>());
|
||||
case Expression::Kind::kConstructorDiagonalMatrix:
|
||||
return this->writeConstructorDiagonalMatrix(e.as<ConstructorDiagonalMatrix>());
|
||||
case Expression::Kind::kConstructorScalarCast:
|
||||
return this->writeConstructorScalarCast(e.as<ConstructorScalarCast>());
|
||||
case Expression::Kind::kConstructorSplat:
|
||||
return this->writeConstructorSplat(e.as<ConstructorSplat>());
|
||||
case Expression::Kind::kFieldAccess:
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "src/sksl/ir/SkSLBoolLiteral.h"
|
||||
#include "src/sksl/ir/SkSLConstructorArray.h"
|
||||
#include "src/sksl/ir/SkSLConstructorDiagonalMatrix.h"
|
||||
#include "src/sksl/ir/SkSLConstructorScalarCast.h"
|
||||
#include "src/sksl/ir/SkSLConstructorSplat.h"
|
||||
#include "src/sksl/ir/SkSLFloatLiteral.h"
|
||||
#include "src/sksl/ir/SkSLIntLiteral.h"
|
||||
@ -29,7 +30,7 @@ std::unique_ptr<Expression> Constructor::Convert(const Context& context,
|
||||
return std::move(args[0]);
|
||||
}
|
||||
if (type.isScalar()) {
|
||||
return MakeScalarConstructor(context, offset, type.scalarTypeForLiteral(), std::move(args));
|
||||
return ConstructorScalarCast::Convert(context, offset, type, std::move(args));
|
||||
}
|
||||
if (type.isVector() || type.isMatrix()) {
|
||||
return MakeCompoundConstructor(context, offset, type, std::move(args));
|
||||
@ -42,33 +43,6 @@ std::unique_ptr<Expression> Constructor::Convert(const Context& context,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> Constructor::MakeScalarConstructor(const Context& context,
|
||||
int offset,
|
||||
const Type& type,
|
||||
ExpressionArray args) {
|
||||
SkASSERT(type.isScalar());
|
||||
if (args.size() != 1) {
|
||||
context.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 (!argType.isScalar()) {
|
||||
context.fErrors.error(offset, "invalid argument to '" + type.displayName() +
|
||||
"' constructor (expected a number or bool, but found '" +
|
||||
argType.displayName() + "')");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (std::unique_ptr<Expression> converted = SimplifyConversion(type, *args[0])) {
|
||||
return converted;
|
||||
}
|
||||
|
||||
return std::make_unique<Constructor>(offset, type, std::move(args));
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> Constructor::MakeCompoundConstructor(const Context& context,
|
||||
int offset,
|
||||
const Type& type,
|
||||
@ -83,9 +57,9 @@ std::unique_ptr<Expression> Constructor::MakeCompoundConstructor(const Context&
|
||||
// A constructor containing a single scalar is a splat (for vectors) or diagonal matrix (for
|
||||
// matrices). In either event, it's legal regardless of the scalar's type. Synthesize an
|
||||
// explicit conversion to the proper type (this is a no-op if it's unnecessary).
|
||||
std::unique_ptr<Expression> typecast = Constructor::Convert(context, offset,
|
||||
type.componentType(),
|
||||
std::move(args));
|
||||
std::unique_ptr<Expression> typecast = ConstructorScalarCast::Make(context, offset,
|
||||
type.componentType(),
|
||||
std::move(args[0]));
|
||||
SkASSERT(typecast);
|
||||
|
||||
// Matrix-from-scalar creates a diagonal matrix; vector-from-scalar creates a splat.
|
||||
@ -146,9 +120,9 @@ std::unique_ptr<Expression> Constructor::MakeCompoundConstructor(const Context&
|
||||
int argsToOptimize = 0;
|
||||
int currBit = 1;
|
||||
for (const std::unique_ptr<Expression>& arg : args) {
|
||||
if (arg->is<Constructor>()) {
|
||||
Constructor& inner = arg->as<Constructor>();
|
||||
if (inner.arguments().size() > 1 &&
|
||||
if (arg->isAnyConstructor()) {
|
||||
AnyConstructor& inner = arg->asAnyConstructor();
|
||||
if (inner.argumentSpan().size() > 1 &&
|
||||
inner.type().componentType() == type.componentType()) {
|
||||
argsToOptimize |= currBit;
|
||||
}
|
||||
@ -164,8 +138,8 @@ std::unique_ptr<Expression> Constructor::MakeCompoundConstructor(const Context&
|
||||
currBit = 1;
|
||||
for (std::unique_ptr<Expression>& arg : args) {
|
||||
if (argsToOptimize & currBit) {
|
||||
Constructor& inner = arg->as<Constructor>();
|
||||
for (std::unique_ptr<Expression>& innerArg : inner.arguments()) {
|
||||
AnyConstructor& inner = arg->asAnyConstructor();
|
||||
for (std::unique_ptr<Expression>& innerArg : inner.argumentSpan()) {
|
||||
flattened.push_back(std::move(innerArg));
|
||||
}
|
||||
} else {
|
||||
@ -180,48 +154,6 @@ std::unique_ptr<Expression> Constructor::MakeCompoundConstructor(const Context&
|
||||
return std::make_unique<Constructor>(offset, type, std::move(args));
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> Constructor::SimplifyConversion(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 FloatLiteral::Make(expr.fOffset, (SKSL_FLOAT)value, &constructorType);
|
||||
} else if (constructorType.isInteger()) {
|
||||
// promote uint(1) to 1u
|
||||
return IntLiteral::Make(expr.fOffset, value, &constructorType);
|
||||
} else if (constructorType.isBoolean()) {
|
||||
// promote bool(1) to true/false
|
||||
return BoolLiteral::Make(expr.fOffset, value != 0, &constructorType);
|
||||
}
|
||||
} else if (expr.is<FloatLiteral>()) {
|
||||
float value = expr.as<FloatLiteral>().value();
|
||||
if (constructorType.isFloat()) {
|
||||
// promote float(1.23) to 1.23
|
||||
return FloatLiteral::Make(expr.fOffset, value, &constructorType);
|
||||
} else if (constructorType.isInteger()) {
|
||||
// promote uint(1.23) to 1u
|
||||
return IntLiteral::Make(expr.fOffset, (SKSL_INT)value, &constructorType);
|
||||
} else if (constructorType.isBoolean()) {
|
||||
// promote bool(1.23) to true/false
|
||||
return BoolLiteral::Make(expr.fOffset, value != 0.0f, &constructorType);
|
||||
}
|
||||
} else if (expr.is<BoolLiteral>()) {
|
||||
bool value = expr.as<BoolLiteral>().value();
|
||||
if (constructorType.isFloat()) {
|
||||
// promote float(true) to 1.0
|
||||
return FloatLiteral::Make(expr.fOffset, value ? 1.0f : 0.0f, &constructorType);
|
||||
} else if (constructorType.isInteger()) {
|
||||
// promote uint(true) to 1u
|
||||
return IntLiteral::Make(expr.fOffset, value ? 1 : 0, &constructorType);
|
||||
} else if (constructorType.isBoolean()) {
|
||||
// promote bool(true) to true/false
|
||||
return BoolLiteral::Make(expr.fOffset, value, &constructorType);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Expression::ComparisonResult Constructor::compareConstant(const Expression& other) const {
|
||||
if (other.is<ConstructorDiagonalMatrix>()) {
|
||||
return other.compareConstant(*this);
|
||||
|
@ -179,14 +179,6 @@ public:
|
||||
const Type& type,
|
||||
ExpressionArray args);
|
||||
|
||||
// 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 Type& constructorType,
|
||||
const Expression& expr);
|
||||
|
||||
std::unique_ptr<Expression> clone() const override {
|
||||
return std::make_unique<Constructor>(fOffset, this->type(), this->cloneArguments());
|
||||
}
|
||||
|
98
src/sksl/ir/SkSLConstructorScalarCast.cpp
Normal file
98
src/sksl/ir/SkSLConstructorScalarCast.cpp
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2021 Google LLC
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "src/sksl/ir/SkSLConstructorScalarCast.h"
|
||||
|
||||
namespace SkSL {
|
||||
|
||||
static std::unique_ptr<Expression> cast_scalar_literal(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 FloatLiteral::Make(expr.fOffset, (SKSL_FLOAT)value, &constructorType);
|
||||
} else if (constructorType.isInteger()) {
|
||||
// promote uint(1) to 1u
|
||||
return IntLiteral::Make(expr.fOffset, value, &constructorType);
|
||||
} else if (constructorType.isBoolean()) {
|
||||
// promote bool(1) to true/false
|
||||
return BoolLiteral::Make(expr.fOffset, value != 0, &constructorType);
|
||||
}
|
||||
} else if (expr.is<FloatLiteral>()) {
|
||||
float value = expr.as<FloatLiteral>().value();
|
||||
if (constructorType.isFloat()) {
|
||||
// promote float(1.23) to 1.23
|
||||
return FloatLiteral::Make(expr.fOffset, value, &constructorType);
|
||||
} else if (constructorType.isInteger()) {
|
||||
// promote uint(1.23) to 1u
|
||||
return IntLiteral::Make(expr.fOffset, (SKSL_INT)value, &constructorType);
|
||||
} else if (constructorType.isBoolean()) {
|
||||
// promote bool(1.23) to true/false
|
||||
return BoolLiteral::Make(expr.fOffset, value != 0.0f, &constructorType);
|
||||
}
|
||||
} else if (expr.is<BoolLiteral>()) {
|
||||
bool value = expr.as<BoolLiteral>().value();
|
||||
if (constructorType.isFloat()) {
|
||||
// promote float(true) to 1.0
|
||||
return FloatLiteral::Make(expr.fOffset, value ? 1.0f : 0.0f, &constructorType);
|
||||
} else if (constructorType.isInteger()) {
|
||||
// promote uint(true) to 1u
|
||||
return IntLiteral::Make(expr.fOffset, value ? 1 : 0, &constructorType);
|
||||
} else if (constructorType.isBoolean()) {
|
||||
// promote bool(true) to true/false
|
||||
return BoolLiteral::Make(expr.fOffset, value, &constructorType);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> ConstructorScalarCast::Convert(const Context& context,
|
||||
int offset,
|
||||
const Type& rawType,
|
||||
ExpressionArray args) {
|
||||
// As you might expect, scalar-cast constructors should only be created with scalar types.
|
||||
const Type& type = rawType.scalarTypeForLiteral();
|
||||
SkASSERT(type.isScalar());
|
||||
|
||||
if (args.size() != 1) {
|
||||
context.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 (!argType.isScalar()) {
|
||||
context.fErrors.error(offset, "invalid argument to '" + type.displayName() +
|
||||
"' constructor (expected a number or bool, but found '" +
|
||||
argType.displayName() + "')");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return ConstructorScalarCast::Make(context, offset, type, std::move(args[0]));
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> ConstructorScalarCast::Make(const Context& context,
|
||||
int offset,
|
||||
const Type& type,
|
||||
std::unique_ptr<Expression> arg) {
|
||||
SkASSERT(type.isScalar());
|
||||
SkASSERT(arg->type().isScalar());
|
||||
|
||||
// No cast required when the types match.
|
||||
if (arg->type() == type) {
|
||||
return arg;
|
||||
}
|
||||
// We can cast scalar literals at compile-time.
|
||||
if (std::unique_ptr<Expression> converted = cast_scalar_literal(type, *arg)) {
|
||||
return converted;
|
||||
}
|
||||
return std::make_unique<ConstructorScalarCast>(offset, type, std::move(arg));
|
||||
}
|
||||
|
||||
} // namespace SkSL
|
61
src/sksl/ir/SkSLConstructorScalarCast.h
Normal file
61
src/sksl/ir/SkSLConstructorScalarCast.h
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2021 Google LLC
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SKSL_CONSTRUCTOR_SCALAR_CAST
|
||||
#define SKSL_CONSTRUCTOR_SCALAR_CAST
|
||||
|
||||
#include "include/private/SkSLDefines.h"
|
||||
#include "src/sksl/SkSLContext.h"
|
||||
#include "src/sksl/ir/SkSLConstructor.h"
|
||||
#include "src/sksl/ir/SkSLExpression.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace SkSL {
|
||||
|
||||
/**
|
||||
* Represents the construction of a scalar cast, such as `float(intVariable)`.
|
||||
*
|
||||
* These always contain exactly 1 scalar of a differing type, and are never constant.
|
||||
*/
|
||||
class ConstructorScalarCast final : public SingleArgumentConstructor {
|
||||
public:
|
||||
static constexpr Kind kExpressionKind = Kind::kConstructorScalarCast;
|
||||
|
||||
ConstructorScalarCast(int offset, const Type& type, std::unique_ptr<Expression> arg)
|
||||
: INHERITED(offset, kExpressionKind, &type, std::move(arg)) {}
|
||||
|
||||
// ConstructorScalarCast::Convert will typecheck and create scalar-constructor expressions.
|
||||
// Reports errors via the ErrorReporter; returns null on error.
|
||||
static std::unique_ptr<Expression> Convert(const Context& context,
|
||||
int offset,
|
||||
const Type& rawType,
|
||||
ExpressionArray args);
|
||||
|
||||
// ConstructorScalarCast::Make casts a scalar expression. Casts that can be evaluated at
|
||||
// compile-time will do so (e.g. `int(4.1)` --> `IntLiteral(4)`). Errors reported via SkASSERT.
|
||||
static std::unique_ptr<Expression> Make(const Context& context,
|
||||
int offset,
|
||||
const Type& type,
|
||||
std::unique_ptr<Expression> arg);
|
||||
|
||||
std::unique_ptr<Expression> clone() const override {
|
||||
return std::make_unique<ConstructorScalarCast>(fOffset, this->type(), argument()->clone());
|
||||
}
|
||||
|
||||
bool isCompileTimeConstant() const override {
|
||||
// If this were a compile-time constant, we would have created a literal instead.
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
using INHERITED = SingleArgumentConstructor;
|
||||
};
|
||||
|
||||
} // namespace SkSL
|
||||
|
||||
#endif
|
@ -33,6 +33,7 @@ public:
|
||||
kConstructor,
|
||||
kConstructorArray,
|
||||
kConstructorDiagonalMatrix,
|
||||
kConstructorScalarCast,
|
||||
kConstructorSplat,
|
||||
kDefined,
|
||||
kExternalFunctionCall,
|
||||
|
@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include "src/sksl/ir/SkSLConstructor.h"
|
||||
#include "src/sksl/ir/SkSLConstructorScalarCast.h"
|
||||
#include "src/sksl/ir/SkSLConstructorSplat.h"
|
||||
#include "src/sksl/ir/SkSLSwizzle.h"
|
||||
|
||||
@ -95,10 +96,9 @@ std::unique_ptr<Expression> Swizzle::Convert(const Context& context,
|
||||
case SwizzleComponent::ZERO:
|
||||
if (constantZeroIdx == -1) {
|
||||
// Synthesize a 'type(0)' argument at the end of the constructor.
|
||||
ExpressionArray zeroArgs;
|
||||
zeroArgs.push_back(IntLiteral::Make(context, offset, /*value=*/0));
|
||||
constructorArgs.push_back(Constructor::Convert(context, offset, *numberType,
|
||||
std::move(zeroArgs)));
|
||||
constructorArgs.push_back(ConstructorScalarCast::Make(
|
||||
context, offset, *numberType,
|
||||
IntLiteral::Make(context, offset, /*value=*/0)));
|
||||
constantZeroIdx = constantFieldIdx++;
|
||||
}
|
||||
swizzleComponents.push_back(constantZeroIdx);
|
||||
@ -106,10 +106,9 @@ std::unique_ptr<Expression> Swizzle::Convert(const Context& context,
|
||||
case SwizzleComponent::ONE:
|
||||
if (constantOneIdx == -1) {
|
||||
// Synthesize a 'type(1)' argument at the end of the constructor.
|
||||
ExpressionArray oneArgs;
|
||||
oneArgs.push_back(IntLiteral::Make(context, offset, /*value=*/1));
|
||||
constructorArgs.push_back(Constructor::Convert(context, offset, *numberType,
|
||||
std::move(oneArgs)));
|
||||
constructorArgs.push_back(ConstructorScalarCast::Make(
|
||||
context, offset, *numberType,
|
||||
IntLiteral::Make(context, offset, /*value=*/1)));
|
||||
constantOneIdx = constantFieldIdx++;
|
||||
}
|
||||
swizzleComponents.push_back(constantOneIdx);
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "src/sksl/SkSLContext.h"
|
||||
#include "src/sksl/ir/SkSLConstructor.h"
|
||||
#include "src/sksl/ir/SkSLConstructorScalarCast.h"
|
||||
#include "src/sksl/ir/SkSLFunctionReference.h"
|
||||
#include "src/sksl/ir/SkSLSymbolTable.h"
|
||||
#include "src/sksl/ir/SkSLType.h"
|
||||
@ -269,10 +270,10 @@ std::unique_ptr<Expression> Type::coerceExpression(std::unique_ptr<Expression> e
|
||||
|
||||
ExpressionArray args;
|
||||
args.push_back(std::move(expr));
|
||||
if (!this->isScalar()) {
|
||||
return Constructor::Convert(context, offset, *this, std::move(args));
|
||||
if (this->isScalar()) {
|
||||
return ConstructorScalarCast::Convert(context, offset, *this, std::move(args));
|
||||
}
|
||||
return Constructor::Convert(context, offset, this->scalarTypeForLiteral(), std::move(args));
|
||||
return Constructor::Convert(context, offset, *this, std::move(args));
|
||||
}
|
||||
|
||||
bool Type::isOrContainsArray() const {
|
||||
|
Loading…
Reference in New Issue
Block a user