length()

 - add length() as a special intrinsic
 - style refactoring I wrote to help debug the CL
 - impl dup2,3,4 in program_fn
 - (better) fix dup2,3,4 in byte code interpreter

Change-Id: I7cd94a4bc03efc6af2053e9e6ae18b4da94363ed
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/286896
Commit-Queue: Mike Klein <mtklein@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
diff --git a/src/sksl/SkSLByteCodeGenerator.cpp b/src/sksl/SkSLByteCodeGenerator.cpp
index 60bff34..4415fd5 100644
--- a/src/sksl/SkSLByteCodeGenerator.cpp
+++ b/src/sksl/SkSLByteCodeGenerator.cpp
@@ -48,6 +48,7 @@
         { "dot",     SpecialIntrinsic::kDot },
         { "fract",   ByteCodeInstruction::kFract },
         { "inverse", ByteCodeInstruction::kInverse2x2 },
+        { "length",  SpecialIntrinsic::kLength },
         { "sin",     ByteCodeInstruction::kSin },
         { "sqrt",    ByteCodeInstruction::kSqrt },
         { "tan",     ByteCodeInstruction::kTan },
@@ -980,24 +981,35 @@
                                                 String(c.fFunction.fName).c_str()));
         return;
     }
+    Intrinsic intrin = found->second;
+
     int count = SlotCount(c.fArguments[0]->fType);
-    if (found->second.fIsSpecial) {
-        SpecialIntrinsic special = found->second.fValue.fSpecial;
-        switch (special) {
+    if (intrin.is_special) {
+        switch (intrin.special) {
             case SpecialIntrinsic::kDot: {
                 SkASSERT(c.fArguments.size() == 2);
                 SkASSERT(count == SlotCount(c.fArguments[1]->fType));
                 this->write(vector_instruction(ByteCodeInstruction::kMultiplyF, count));
-                for (int i = count; i > 1; --i) {
+                for (int i = count-1; i --> 0;) {
                     this->write(ByteCodeInstruction::kAddF);
                 }
-                break;
-            }
+            } break;
+
+            case SpecialIntrinsic::kLength: {
+                SkASSERT(c.fArguments.size() == 1);
+                this->write(vector_instruction(ByteCodeInstruction::kDup      , count));
+                this->write(vector_instruction(ByteCodeInstruction::kMultiplyF, count));
+                for (int i = count-1; i --> 0;) {
+                    this->write(ByteCodeInstruction::kAddF);
+                }
+                this->write(ByteCodeInstruction::kSqrt);
+            } break;
+
             default:
                 SkASSERT(false);
         }
     } else {
-        switch (found->second.fValue.fInstruction) {
+        switch (intrin.instruction) {
             case ByteCodeInstruction::kATan:
             case ByteCodeInstruction::kCos:
             case ByteCodeInstruction::kFract:
@@ -1005,8 +1017,9 @@
             case ByteCodeInstruction::kSqrt:
             case ByteCodeInstruction::kTan:
                 SkASSERT(c.fArguments.size() > 0);
-                this->write(vector_instruction(found->second.fValue.fInstruction, count));
+                this->write(vector_instruction(intrin.instruction, count));
                 break;
+
             case ByteCodeInstruction::kInverse2x2: {
                 SkASSERT(c.fArguments.size() > 0);
                 auto op = ByteCodeInstruction::kInverse2x2;
@@ -1019,6 +1032,7 @@
                 this->write(op);
                 break;
             }
+
             default:
                 SkASSERT(false);
         }