sksl can now fold constant vector or matrix equality expressions

Bug: skia:
Change-Id: Icaddae68e53ed3629bcdc04b5f0b541d9e4398e2
Reviewed-on: https://skia-review.googlesource.com/14260
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
Reviewed-by: Ben Wagner <benjaminwagner@google.com>
diff --git a/src/sksl/ir/SkSLConstructor.h b/src/sksl/ir/SkSLConstructor.h
index 208031a..05f4096 100644
--- a/src/sksl/ir/SkSLConstructor.h
+++ b/src/sksl/ir/SkSLConstructor.h
@@ -81,6 +81,44 @@
         return true;
     }
 
+    bool compareConstant(const Context& context, const Expression& other) const override {
+        ASSERT(other.fKind == Expression::kConstructor_Kind && other.fType == fType);
+        Constructor& c = (Constructor&) other;
+        if (c.fType.kind() == Type::kVector_Kind) {
+            for (int i = 0; i < fType.columns(); i++) {
+                if (!this->getVecComponent(i).compareConstant(context, c.getVecComponent(i))) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        // shouldn't be possible to have a constant constructor that isn't a vector or matrix;
+        // a constant scalar constructor should have been collapsed down to the appropriate
+        // literal
+        ASSERT(fType.kind() == Type::kMatrix_Kind);
+        const FloatLiteral fzero(context, Position(), 0);
+        const IntLiteral izero(context, Position(), 0);
+        const Expression* zero;
+        if (fType.componentType() == *context.fFloat_Type) {
+            zero = &fzero;
+        } else {
+            ASSERT(fType.componentType() == *context.fInt_Type);
+            zero = &izero;
+        }
+        for (int col = 0; col < fType.columns(); col++) {
+            for (int row = 0; row < fType.rows(); row++) {
+                const Expression* component1 = getMatComponent(col, row);
+                const Expression* component2 = c.getMatComponent(col, row);
+                if (!(component1 ? component1 : zero)->compareConstant(
+                                                                context,
+                                                                component2 ? *component2 : *zero)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
     const Expression& getVecComponent(int index) const {
         ASSERT(fType.kind() == Type::kVector_Kind);
         if (fArguments.size() == 1 && fArguments[0]->fType.kind() == Type::kScalar_Kind) {
@@ -118,6 +156,51 @@
         return ((IntLiteral&) c).fValue;
     }
 
+    // null return should be interpreted as zero
+    const Expression* getMatComponent(int col, int row) const {
+        ASSERT(this->isConstant());
+        ASSERT(fType.kind() == Type::kMatrix_Kind);
+        ASSERT(col < fType.columns() && row < fType.rows());
+        if (fArguments.size() == 1) {
+            if (fArguments[0]->fType.kind() == Type::kScalar_Kind) {
+                // single scalar argument, so matrix is of the form:
+                // x 0 0
+                // 0 x 0
+                // 0 0 x
+                // return x if col == row
+                return col == row ? fArguments[0].get() : nullptr;
+            }
+            if (fArguments[0]->fType.kind() == Type::kMatrix_Kind) {
+                ASSERT(fArguments[0]->fKind == Expression::kConstructor_Kind);
+                // single matrix argument. make sure we're within the argument's bounds.
+                const Type& argType = ((Constructor&) *fArguments[0]).fType;
+                if (col < argType.columns() && row < argType.rows()) {
+                    // within bounds, defer to argument
+                    return ((Constructor&) *fArguments[0]).getMatComponent(col, row);
+                }
+                // out of bounds, return 0
+                return nullptr;
+            }
+        }
+        int currentIndex = 0;
+        int targetIndex = col * fType.rows() + row;
+        for (const auto& arg : fArguments) {
+            ASSERT(targetIndex >= currentIndex);
+            ASSERT(arg->fType.rows() == 1);
+            if (currentIndex + arg->fType.columns() > targetIndex) {
+                if (arg->fType.columns() == 1) {
+                    return arg.get();
+                } else {
+                    ASSERT(arg->fType.kind() == Type::kVector_Kind);
+                    ASSERT(arg->fKind == Expression::kConstructor_Kind);
+                    return &((Constructor&) *arg).getVecComponent(targetIndex - currentIndex);
+                }
+            }
+            currentIndex += arg->fType.columns();
+        }
+        ABORT("can't happen, matrix component out of bounds");
+    }
+
     std::vector<std::unique_ptr<Expression>> fArguments;
 
     typedef Expression INHERITED;