Add support for float remainder to interpreter

Change-Id: I267c99c8c36b1d39abe9cf196996db43edb2b839
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/212721
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
diff --git a/src/sksl/SkSLByteCode.h b/src/sksl/SkSLByteCode.h
index 0454a4b..df8b964 100644
--- a/src/sksl/SkSLByteCode.h
+++ b/src/sksl/SkSLByteCode.h
@@ -72,6 +72,7 @@
     kPop,
     // Followed by a 32 bit value containing the value to push
     kPushImmediate,
+    kRemainderF,
     kRemainderS,
     kRemainderU,
     // Followed by a byte indicating the number of slots being returned
diff --git a/src/sksl/SkSLByteCodeGenerator.cpp b/src/sksl/SkSLByteCodeGenerator.cpp
index 086afa5..699fda2 100644
--- a/src/sksl/SkSLByteCodeGenerator.cpp
+++ b/src/sksl/SkSLByteCodeGenerator.cpp
@@ -277,7 +277,7 @@
         case Token::Kind::PERCENT:
             this->writeTypedInstruction(b.fLeft->fType, ByteCodeInstruction::kRemainderS,
                                         ByteCodeInstruction::kRemainderU,
-                                        ByteCodeInstruction::kInvalid);
+                                        ByteCodeInstruction::kRemainderF);
             break;
         case Token::Kind::PLUS:
             this->writeTypedInstruction(b.fLeft->fType, ByteCodeInstruction::kAddI,
diff --git a/src/sksl/SkSLInterpreter.cpp b/src/sksl/SkSLInterpreter.cpp
index e0de1bd..f33cf42 100644
--- a/src/sksl/SkSLInterpreter.cpp
+++ b/src/sksl/SkSLInterpreter.cpp
@@ -160,6 +160,7 @@
             case ByteCodeInstruction::kPushImmediate:
                 printf("pushimmediate %s", value_string(READ32()).c_str());
                 break;
+            case ByteCodeInstruction::kRemainderF: printf("remainderf"); break;
             case ByteCodeInstruction::kRemainderS: printf("remainders"); break;
             case ByteCodeInstruction::kRemainderU: printf("remainderu"); break;
             case ByteCodeInstruction::kReturn: printf("return %d", READ8()); break;
@@ -350,6 +351,12 @@
             case ByteCodeInstruction::kPushImmediate:
                 PUSH(Value((int) READ32()));
                 break;
+            case ByteCodeInstruction::kRemainderF: {
+                float b = POP().fFloat;
+                Value* a = &TOP();
+                *a = Value(fmodf(a->fFloat, b));
+                break;
+            }
             BINARY_OP(kRemainderS, int32_t, fSigned, %)
             BINARY_OP(kRemainderU, uint32_t, fUnsigned, %)
             case ByteCodeInstruction::kReturn: {
@@ -481,6 +488,19 @@
                     VECTOR_BINARY_OP(kMultiplyS, int32_t, fSigned, *)
                     VECTOR_BINARY_OP(kMultiplyU, uint32_t, fUnsigned, *)
                     VECTOR_BINARY_OP(kMultiplyF, float, fFloat, *)
+                    case ByteCodeInstruction::kRemainderF: {
+                        Value result[VECTOR_MAX];
+                        for (int i = count - 1; i >= 0; --i) {
+                            result[i] = POP();
+                        }
+                        for (int i = count - 1; i >= 0; --i) {
+                            result[i] = fmodf(POP().fFloat, result[i].fFloat);
+                        }
+                        for (int i = 0; i < count; ++i) {
+                            PUSH(result[i]);
+                        }
+                        break;
+                    }
                     VECTOR_BINARY_OP(kRemainderS, int32_t, fSigned, %)
                     VECTOR_BINARY_OP(kRemainderU, uint32_t, fUnsigned, %)
                     case ByteCodeInstruction::kStore: {
diff --git a/tests/SkSLInterpreterTest.cpp b/tests/SkSLInterpreterTest.cpp
index 6953397..d00469c 100644
--- a/tests/SkSLInterpreterTest.cpp
+++ b/tests/SkSLInterpreterTest.cpp
@@ -133,6 +133,10 @@
 }
 
 DEF_TEST(SkSLInterpreterRemainder, r) {
+    test(r, "void main(inout half4 color) { color.r = color.r % color.g; }", 3.125, 2, 0, 0,
+         1.125, 2, 0, 0);
+    test(r, "void main(inout half4 color) { color %= half4(1, 2, 3, 4); }", 9.5, 9.5, 9.5, 9.5,
+         0.5, 1.5, 0.5, 1.5);
     test(r, "void main(inout half4 color) { int a = 8; int b = 3; a %= b; color.r = a; }", 0, 0, 0,
          0, 2, 0, 0, 0);
     test(r, "void main(inout half4 color) { int a = 8; int b = 3; color.r = a % b; }", 0, 0, 0, 0,