Add support for matrix division to Metal codegen.

This CL adds a polyfill for componentwise matrix/matrix division to
Metal, as well as matrix/=matrix. Matrix/scalar and scalar/matrix
division work by splatting the scalar out to a matrix (handled in the
prior CL, http://review.skia.org/407616) and then performing
componentwise matrix/matrix division.

Working demonstration (copy-pasted from the Metal output file):
http://screen/BrqyPcbPrB7Dy4m

Change-Id: I6a8b97783be3485f7ffee551b669d14bc58e7568
Bug: skia:11125
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/407796
Commit-Queue: John Stiles <johnstiles@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
diff --git a/src/sksl/codegen/SkSLMetalCodeGenerator.cpp b/src/sksl/codegen/SkSLMetalCodeGenerator.cpp
index 79bea71..c265756 100644
--- a/src/sksl/codegen/SkSLMetalCodeGenerator.cpp
+++ b/src/sksl/codegen/SkSLMetalCodeGenerator.cpp
@@ -1215,7 +1215,15 @@
 
 void MetalCodeGenerator::writeMatrixTimesEqualHelper(const Type& left, const Type& right,
                                                      const Type& result) {
-    String key = "TimesEqual " + this->typeName(left) + ":" + this->typeName(right);
+    SkASSERT(left.isMatrix());
+    SkASSERT(right.isMatrix());
+    SkASSERT(result.isMatrix());
+    SkASSERT(left.rows() == right.rows());
+    SkASSERT(left.columns() == right.columns());
+    SkASSERT(left.rows() == result.rows());
+    SkASSERT(left.columns() == result.columns());
+
+    String key = "Matrix *= " + this->typeName(left) + ":" + this->typeName(right);
 
     auto [iter, wasInserted] = fHelpers.insert(key);
     if (wasInserted) {
@@ -1234,7 +1242,7 @@
     SkASSERT(left.rows() == right.rows());
     SkASSERT(left.columns() == right.columns());
 
-    String key = "MatrixEquality " + this->typeName(left) + ":" + this->typeName(right);
+    String key = "Matrix == " + this->typeName(left) + ":" + this->typeName(right);
 
     auto [iter, wasInserted] = fHelpers.insert(key);
     if (wasInserted) {
@@ -1259,6 +1267,36 @@
     }
 }
 
+void MetalCodeGenerator::writeMatrixDivisionHelpers(const Type& type) {
+    SkASSERT(type.isMatrix());
+
+    String key = "Matrix / " + this->typeName(type);
+
+    auto [iter, wasInserted] = fHelpers.insert(key);
+    if (wasInserted) {
+        String typeName = this->typeName(type);
+
+        fExtraFunctions.printf(
+                "thread %s operator/(const %s left, const %s right) {\n"
+                "    return %s(",
+                typeName.c_str(), typeName.c_str(), typeName.c_str(), typeName.c_str());
+
+        const char* separator = "";
+        for (int index=0; index<type.columns(); ++index) {
+            fExtraFunctions.printf("%sleft[%d] / right[%d]", separator, index, index);
+            separator = ", ";
+        }
+
+        fExtraFunctions.printf(");\n"
+                               "}\n"
+                               "thread %s& operator/=(thread %s& left, thread const %s& right) {\n"
+                               "    left = left / right;\n"
+                               "    return left;\n"
+                               "}\n",
+                               typeName.c_str(), typeName.c_str(), typeName.c_str());
+    }
+}
+
 void MetalCodeGenerator::writeArrayEqualityHelpers(const Type& type) {
     SkASSERT(type.isArray());
 
@@ -1387,13 +1425,18 @@
         default:
             break;
     }
-    if (needParens) {
-        this->write("(");
-    }
     if (leftType.isMatrix() && rightType.isMatrix() && op.kind() == Token::Kind::TK_STAREQ) {
         this->writeMatrixTimesEqualHelper(leftType, rightType, b.type());
     }
-
+    if (op.removeAssignment().kind() == Token::Kind::TK_SLASH &&
+        ((leftType.isMatrix() && rightType.isMatrix()) ||
+         (leftType.isScalar() && rightType.isMatrix()) ||
+         (leftType.isMatrix() && rightType.isScalar()))) {
+        this->writeMatrixDivisionHelpers(leftType.isMatrix() ? leftType : rightType);
+    }
+    if (needParens) {
+        this->write("(");
+    }
     bool needMatrixSplatOnScalar = rightType.isMatrix() && leftType.isScalar() &&
                                    op.removeAssignment().kind() != Token::Kind::TK_STAR;
     if (needMatrixSplatOnScalar) {