Represent vector-cast constructors with ConstructorVectorCast.

Making a VectorCast from a compile-time constant will perform the cast
at compile-time instead; previously, we did not apply this optimization.
This simplified a few test outputs in subtle ways. (In particular, the
SPIR-V codegen used to occasionally decorate OpConstantComposite of
constant numbers with RelaxedPrecision, and no longer appears to do
this. This should have no effect on results either way AFAICS.)

Because we don't return VectorCast constructors containing compile-time
constant values, we do not need to implement compareConstant for this
constructor; they only wrap non-compile-time-constant expressions.

Change-Id: I28c1f337f64d6f20fb86bc0f58e225af4bd7b26c
Bug: skia:11032
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/392197
Auto-Submit: John Stiles <johnstiles@google.com>
Commit-Queue: John Stiles <johnstiles@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
diff --git a/src/sksl/SkSLMetalCodeGenerator.cpp b/src/sksl/SkSLMetalCodeGenerator.cpp
index 70fe559..038dd90 100644
--- a/src/sksl/SkSLMetalCodeGenerator.cpp
+++ b/src/sksl/SkSLMetalCodeGenerator.cpp
@@ -13,6 +13,7 @@
 #include "src/sksl/ir/SkSLConstructorArray.h"
 #include "src/sksl/ir/SkSLConstructorDiagonalMatrix.h"
 #include "src/sksl/ir/SkSLConstructorSplat.h"
+#include "src/sksl/ir/SkSLConstructorVectorCast.h"
 #include "src/sksl/ir/SkSLExpressionStatement.h"
 #include "src/sksl/ir/SkSLExtension.h"
 #include "src/sksl/ir/SkSLIndexExpression.h"
@@ -175,17 +176,15 @@
             this->writeConstructor(expr.as<Constructor>(), parentPrecedence);
             break;
         case Expression::Kind::kConstructorArray:
-            this->writeConstructorArray(expr.as<ConstructorArray>(), parentPrecedence);
+            this->writeAnyConstructor(expr.asAnyConstructor(), "{", "}", parentPrecedence);
             break;
         case Expression::Kind::kConstructorDiagonalMatrix:
-            this->writeSingleArgumentConstructor(expr.as<ConstructorDiagonalMatrix>(),
-                                                 parentPrecedence);
+        case Expression::Kind::kConstructorSplat:
+            this->writeAnyConstructor(expr.asAnyConstructor(), "(", ")", parentPrecedence);
             break;
         case Expression::Kind::kConstructorScalarCast:
-            this->writeConstructorScalarCast(expr.as<ConstructorScalarCast>(), parentPrecedence);
-            break;
-        case Expression::Kind::kConstructorSplat:
-            this->writeSingleArgumentConstructor(expr.as<ConstructorSplat>(), parentPrecedence);
+        case Expression::Kind::kConstructorVectorCast:
+            this->writeCastConstructor(expr.asAnyConstructor(), "(", ")", parentPrecedence);
             break;
         case Expression::Kind::kIntLiteral:
             this->writeIntLiteral(expr.as<IntLiteral>());
@@ -559,14 +558,14 @@
             this->write(SAMPLER_SUFFIX);
             this->write(", ");
             const Type& arg1Type = arguments[1]->type();
-            if (arg1Type == *fContext.fTypes.fFloat3) {
+            if (arg1Type.columns() == 3) {
                 // have to store the vector in a temp variable to avoid double evaluating it
                 String tmpVar = this->getTempVariable(arg1Type);
                 this->write("(" + tmpVar + " = ");
                 this->writeExpression(*arguments[1], Precedence::kSequence);
                 this->write(", " + tmpVar + ".xy / " + tmpVar + ".z))");
             } else {
-                SkASSERT(arg1Type == *fContext.fTypes.fFloat2);
+                SkASSERT(arg1Type.columns() == 2);
                 this->writeExpression(*arguments[1], Precedence::kSequence);
                 this->write(")");
             }
@@ -1055,18 +1054,6 @@
     const Type& constructorType = c.type();
     SkASSERT(!constructorType.isArray());
 
-    // 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;
-        }
-    }
-
     // Emit and invoke a matrix-constructor helper method if one is necessary.
     if (this->matrixConstructHelperIsNeeded(c)) {
         this->write(this->getMatrixConstructHelper(c));
@@ -1109,38 +1096,35 @@
     this->write(")");
 }
 
-void MetalCodeGenerator::writeSingleArgumentConstructor(const SingleArgumentConstructor& c,
-                                                        Precedence parentPrecedence) {
+void MetalCodeGenerator::writeAnyConstructor(const AnyConstructor& c,
+                                             const char* leftBracket,
+                                             const char* rightBracket,
+                                             Precedence parentPrecedence) {
     this->writeType(c.type());
-    this->write("(");
-    this->writeExpression(*c.argument(), Precedence::kSequence);
-    this->write(")");
-}
-
-void MetalCodeGenerator::writeConstructorArray(const ConstructorArray& c,
-                                               Precedence parentPrecedence) {
-    this->writeType(c.type());
-    this->write("{");
+    this->write(leftBracket);
     const char* separator = "";
-    for (const std::unique_ptr<Expression>& arg : c.arguments()) {
+    for (const std::unique_ptr<Expression>& arg : c.argumentSpan()) {
         this->write(separator);
         separator = ", ";
         this->writeExpression(*arg, Precedence::kSequence);
     }
-    this->write("}");
+    this->write(rightBracket);
 }
 
-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;
+void MetalCodeGenerator::writeCastConstructor(const AnyConstructor& c,
+                                              const char* leftBracket,
+                                              const char* rightBracket,
+                                              Precedence parentPrecedence) {
+    // If the type is coercible, emit it directly without the cast.
+    auto args = c.argumentSpan();
+    if (args.size() == 1) {
+        if (this->canCoerce(c.type(), args.front()->type())) {
+            this->writeExpression(*args.front(), parentPrecedence);
+            return;
+        }
     }
 
-    return this->writeSingleArgumentConstructor(c, parentPrecedence);
+    return this->writeAnyConstructor(c, leftBracket, rightBracket, parentPrecedence);
 }
 
 void MetalCodeGenerator::writeFragCoord() {
@@ -2269,7 +2253,8 @@
         case Expression::Kind::kConstructorArray:
         case Expression::Kind::kConstructorDiagonalMatrix:
         case Expression::Kind::kConstructorScalarCast:
-        case Expression::Kind::kConstructorSplat: {
+        case Expression::Kind::kConstructorSplat:
+        case Expression::Kind::kConstructorVectorCast: {
             const AnyConstructor& c = e->asAnyConstructor();
             Requirements result = kNo_Requirements;
             for (const auto& arg : c.argumentSpan()) {