Add support for Field lvalues.

This allows the code generator to compile assignment into struct
fields. However, non-lvalue field-access expressions have not been
implemented yet, so those assignments cannot be read back.
Surprisingly, we do have one test which now passes because it
meets these criteria.

Change-Id: I2bd46469c6b542d2fb41bce135e7cac43281fe3c
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/639859
Commit-Queue: Arman Uguray <armansito@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
Reviewed-by: Arman Uguray <armansito@google.com>
diff --git a/src/sksl/codegen/SkSLRasterPipelineCodeGenerator.cpp b/src/sksl/codegen/SkSLRasterPipelineCodeGenerator.cpp
index a33f5f3..c1d3533 100644
--- a/src/sksl/codegen/SkSLRasterPipelineCodeGenerator.cpp
+++ b/src/sksl/codegen/SkSLRasterPipelineCodeGenerator.cpp
@@ -37,6 +37,7 @@
 #include "src/sksl/ir/SkSLDoStatement.h"
 #include "src/sksl/ir/SkSLExpression.h"
 #include "src/sksl/ir/SkSLExpressionStatement.h"
+#include "src/sksl/ir/SkSLFieldAccess.h"
 #include "src/sksl/ir/SkSLForStatement.h"
 #include "src/sksl/ir/SkSLFunctionCall.h"
 #include "src/sksl/ir/SkSLFunctionDeclaration.h"
@@ -498,16 +499,12 @@
         SlotMap in = fParent->getSlotMap(gen);
 
         // Take a subset of the parent's slots.
+        // TODO(skia:13676): support non-constant indices
         int numElements = fIndexedType.slotCount();
+        int startingIndex = numElements * fIndexExpr.as<Literal>().intValue();
 
         SlotMap out;
-        out.slots.resize(numElements);
-        // TODO(skia:13676): support non-constant indices
-        int startingIndex = numElements * fIndexExpr.as<Literal>().intValue();
-        for (int count = 0; count < numElements; ++count) {
-            out.slots[count] = in.slots[startingIndex + count];
-        }
-
+        out.slots.push_back_n(numElements, &in.slots[startingIndex]);
         return out;
     }
 
@@ -520,6 +517,40 @@
     const Type& fIndexedType;
 };
 
+class FieldLValue final : public LValue {
+public:
+    FieldLValue(std::unique_ptr<LValue> p, const FieldAccess& fieldAccess)
+            : fParent(std::move(p)) {
+        // Calculate the slot range of this field in the parent.
+        SkSpan<const Type::Field> fields = fieldAccess.base()->type().fields();
+        const int fieldIndex = fieldAccess.fieldIndex();
+
+        fInitialSlot = 0;
+        for (int index = 0; index < fieldIndex; ++index) {
+            fInitialSlot += fields[index].fType->slotCount();
+        }
+        fNumSlots = fields[fieldIndex].fType->slotCount();
+    }
+
+    SlotMap getSlotMap(Generator* gen) const override {
+        // Get the slot map from the base expression.
+        SlotMap in = fParent->getSlotMap(gen);
+
+        // Take a subset of the parent's slots.
+        SlotMap out;
+        out.slots.push_back_n(fNumSlots, &in.slots[fInitialSlot]);
+        return out;
+    }
+
+    bool isUniform() const override {
+        return fParent->isUniform();
+    }
+
+    std::unique_ptr<LValue> fParent;
+    int fInitialSlot = 0;
+    int fNumSlots = 0;
+};
+
 std::unique_ptr<LValue> LValue::Make(const Expression& e) {
     if (e.is<VariableReference>()) {
         return std::make_unique<VariableLValue>(e.as<VariableReference>().variable());
@@ -529,6 +560,11 @@
             return std::make_unique<SwizzleLValue>(std::move(base), e.as<Swizzle>().components());
         }
     }
+    if (e.is<FieldAccess>()) {
+        if (std::unique_ptr<LValue> base = LValue::Make(*e.as<FieldAccess>().base())) {
+            return std::make_unique<FieldLValue>(std::move(base), e.as<FieldAccess>());
+        }
+    }
     if (e.is<IndexExpression>()) {
         const IndexExpression& indexExpr = e.as<IndexExpression>();
 
@@ -1226,11 +1262,11 @@
 
 BuilderOp Generator::GetTypedOp(const SkSL::Type& type, const TypedOps& ops) {
     switch (type.componentType().numberKind()) {
-        case Type::NumberKind::kFloat:    return ops.fFloatOp;    break;
-        case Type::NumberKind::kSigned:   return ops.fSignedOp;   break;
-        case Type::NumberKind::kUnsigned: return ops.fUnsignedOp; break;
-        case Type::NumberKind::kBoolean:  return ops.fBooleanOp;  break;
-        default:                          SkUNREACHABLE;
+        case Type::NumberKind::kFloat:    return ops.fFloatOp;
+        case Type::NumberKind::kSigned:   return ops.fSignedOp;
+        case Type::NumberKind::kUnsigned: return ops.fUnsignedOp;
+        case Type::NumberKind::kBoolean:  return ops.fBooleanOp;
+        default:                          return BuilderOp::unsupported;
     }
 }
 
diff --git a/tests/SkSLTest.cpp b/tests/SkSLTest.cpp
index c26491a..4ed3c35 100644
--- a/tests/SkSLTest.cpp
+++ b/tests/SkSLTest.cpp
@@ -609,7 +609,7 @@
 SKSL_TEST(GPU_ES3,           kNever,      ArrayConstructors,               "shared/ArrayConstructors.sksl")
 SKSL_TEST(RP + VM + GPU_ES3, kNever,      ArrayFollowedByScalar,           "shared/ArrayFollowedByScalar.sksl")
 SKSL_TEST(VM + GPU,          kApiLevel_T, ArrayTypes,                      "shared/ArrayTypes.sksl")
-SKSL_TEST(VM + GPU,          kApiLevel_T, Assignment,                      "shared/Assignment.sksl")
+SKSL_TEST(RP + VM + GPU,     kApiLevel_T, Assignment,                      "shared/Assignment.sksl")
 SKSL_TEST(RP + VM + GPU,     kApiLevel_T, CastsRoundTowardZero,            "shared/CastsRoundTowardZero.sksl")
 SKSL_TEST(RP + VM + GPU,     kApiLevel_T, CommaMixedTypes,                 "shared/CommaMixedTypes.sksl")
 SKSL_TEST(RP + VM + GPU,     kApiLevel_T, CommaSideEffects,                "shared/CommaSideEffects.sksl")
diff --git a/tests/sksl/shared/Assignment.skrp b/tests/sksl/shared/Assignment.skrp
index 3ef3d71..feb42d8 100644
--- a/tests/sksl/shared/Assignment.skrp
+++ b/tests/sksl/shared/Assignment.skrp
@@ -1,4 +1,157 @@
-### Compilation failed:
-
-error: code is not supported
-1 error
+    1. store_src_rg                   coords = src.rg
+    2. init_lane_masks                CondMask = LoopMask = RetMask = true
+    3. zero_4_slots_unmasked          globalVar = 0
+    4. zero_4_slots_unmasked          globalStruct.f, globalStruct.af[0], globalStruct.af[1], globalStruct.af[2] = 0
+    5. zero_4_slots_unmasked          globalStruct.af[3], globalStruct.af[4], globalStruct.h4(0..1) = 0
+    6. zero_4_slots_unmasked          globalStruct.h4(2..3), globalStruct.ah4[0](0..1) = 0
+    7. zero_4_slots_unmasked          globalStruct.ah4[0](2..3), globalStruct.ah4[1](0..1) = 0
+    8. zero_4_slots_unmasked          globalStruct.ah4[1](2..3), globalStruct.ah4[2](0..1) = 0
+    9. zero_4_slots_unmasked          globalStruct.ah4[2](2..3), globalStruct.ah4[3](0..1) = 0
+   10. zero_4_slots_unmasked          globalStruct.ah4[3](2..3), globalStruct.ah4[4](0..1) = 0
+   11. zero_2_slots_unmasked          globalStruct.ah4[4](2..3) = 0
+   12. zero_slot_unmasked             i = 0
+   13. zero_slot_unmasked             $0 = 0
+   14. copy_slot_unmasked             i = $0
+   15. zero_4_slots_unmasked          i4 = 0
+   16. copy_constant                  $0 = 0x00000001 (1.401298e-45)
+   17. copy_constant                  $1 = 0x00000002 (2.802597e-45)
+   18. copy_constant                  $2 = 0x00000003 (4.203895e-45)
+   19. copy_constant                  $3 = 0x00000004 (5.605194e-45)
+   20. copy_4_slots_unmasked          i4 = $0..3
+   21. zero_4_slots_unmasked          f3x3(0..3) = 0
+   22. zero_4_slots_unmasked          f3x3(4..7) = 0
+   23. zero_slot_unmasked             f3x3(8) = 0
+   24. copy_constant                  $0 = 0x3F800000 (1.0)
+   25. copy_constant                  $1 = 0x40000000 (2.0)
+   26. copy_constant                  $2 = 0x40400000 (3.0)
+   27. copy_constant                  $3 = 0x40800000 (4.0)
+   28. copy_constant                  $4 = 0x40A00000 (5.0)
+   29. copy_constant                  $5 = 0x40C00000 (6.0)
+   30. copy_constant                  $6 = 0x40E00000 (7.0)
+   31. copy_constant                  $7 = 0x41000000 (8.0)
+   32. copy_constant                  $8 = 0x41100000 (9.0)
+   33. copy_4_slots_unmasked          f3x3(0..3) = $0..3
+   34. copy_4_slots_unmasked          f3x3(4..7) = $4..7
+   35. copy_slot_unmasked             f3x3(8) = $8
+   36. zero_4_slots_unmasked          x = 0
+   37. zero_slot_unmasked             $0 = 0
+   38. copy_slot_unmasked             x(3) = $0
+   39. zero_2_slots_unmasked          $0..1 = 0
+   40. copy_slot_unmasked             x(1) = $0
+   41. copy_slot_unmasked             x(0) = $1
+   42. zero_slot_unmasked             ai[0] = 0
+   43. zero_slot_unmasked             $0 = 0
+   44. copy_slot_unmasked             ai[0] = $0
+   45. zero_4_slots_unmasked          ai4[0] = 0
+   46. copy_constant                  $0 = 0x00000001 (1.401298e-45)
+   47. copy_constant                  $1 = 0x00000002 (2.802597e-45)
+   48. copy_constant                  $2 = 0x00000003 (4.203895e-45)
+   49. copy_constant                  $3 = 0x00000004 (5.605194e-45)
+   50. copy_4_slots_unmasked          ai4[0] = $0..3
+   51. zero_4_slots_unmasked          ah3x3[0](0..3) = 0
+   52. zero_4_slots_unmasked          ah3x3[0](4..7) = 0
+   53. zero_slot_unmasked             ah3x3[0](8) = 0
+   54. copy_constant                  $0 = 0x3F800000 (1.0)
+   55. copy_constant                  $1 = 0x40000000 (2.0)
+   56. copy_constant                  $2 = 0x40400000 (3.0)
+   57. copy_constant                  $3 = 0x40800000 (4.0)
+   58. copy_constant                  $4 = 0x40A00000 (5.0)
+   59. copy_constant                  $5 = 0x40C00000 (6.0)
+   60. copy_constant                  $6 = 0x40E00000 (7.0)
+   61. copy_constant                  $7 = 0x41000000 (8.0)
+   62. copy_constant                  $8 = 0x41100000 (9.0)
+   63. copy_4_slots_unmasked          ah3x3[0](0..3) = $0..3
+   64. copy_4_slots_unmasked          ah3x3[0](4..7) = $4..7
+   65. copy_slot_unmasked             ah3x3[0](8) = $8
+   66. zero_4_slots_unmasked          af4[0] = 0
+   67. zero_slot_unmasked             $0 = 0
+   68. copy_slot_unmasked             af4[0](0) = $0
+   69. copy_constant                  $0 = 0x3F800000 (1.0)
+   70. swizzle_4                      $0..3 = ($0..3).xxxx
+   71. copy_slot_unmasked             af4[0](1) = $0
+   72. copy_slot_unmasked             af4[0](3) = $1
+   73. copy_slot_unmasked             af4[0](0) = $2
+   74. copy_slot_unmasked             af4[0](2) = $3
+   75. zero_4_slots_unmasked          s.f, s.af[0], s.af[1], s.af[2] = 0
+   76. zero_4_slots_unmasked          s.af[3], s.af[4], s.h4(0..1) = 0
+   77. zero_4_slots_unmasked          s.h4(2..3), s.ah4[0](0..1) = 0
+   78. zero_4_slots_unmasked          s.ah4[0](2..3), s.ah4[1](0..1) = 0
+   79. zero_4_slots_unmasked          s.ah4[1](2..3), s.ah4[2](0..1) = 0
+   80. zero_4_slots_unmasked          s.ah4[2](2..3), s.ah4[3](0..1) = 0
+   81. zero_4_slots_unmasked          s.ah4[3](2..3), s.ah4[4](0..1) = 0
+   82. zero_2_slots_unmasked          s.ah4[4](2..3) = 0
+   83. zero_slot_unmasked             $0 = 0
+   84. copy_slot_unmasked             s.f = $0
+   85. zero_slot_unmasked             $0 = 0
+   86. copy_slot_unmasked             s.af[1] = $0
+   87. copy_constant                  $0 = 0x41100000 (9.0)
+   88. swizzle_3                      $0..2 = ($0..2).xxx
+   89. copy_slot_unmasked             s.h4(2) = $0
+   90. copy_2_slots_unmasked          s.h4(0..1) = $1..2
+   91. copy_constant                  $0 = 0x40A00000 (5.0)
+   92. copy_slot_unmasked             $1 = $0
+   93. copy_slot_unmasked             s.ah4[2](1) = $0
+   94. copy_slot_unmasked             s.ah4[2](3) = $1
+   95. zero_4_slots_unmasked          $0..3 = 0
+   96. copy_4_slots_unmasked          globalVar = $0..3
+   97. zero_slot_unmasked             $0 = 0
+   98. copy_slot_unmasked             globalStruct.f = $0
+   99. zero_slot_unmasked             l = 0
+  100. zero_slot_unmasked             $0 = 0
+  101. copy_slot_unmasked             l = $0
+  102. copy_2_slots_unmasked          $0..1 = ai[0], ai4[0](0)
+  103. add_int                        $0 += $1
+  104. copy_slot_unmasked             ai[0] = $0
+  105. copy_constant                  $0 = 0x3F800000 (1.0)
+  106. copy_slot_unmasked             s.f = $0
+  107. copy_constant                  $0 = 0x40000000 (2.0)
+  108. copy_slot_unmasked             s.af[0] = $0
+  109. copy_constant                  $0 = 0x3F800000 (1.0)
+  110. swizzle_4                      $0..3 = ($0..3).xxxx
+  111. copy_4_slots_unmasked          s.h4 = $0..3
+  112. copy_constant                  $0 = 0x40000000 (2.0)
+  113. swizzle_4                      $0..3 = ($0..3).xxxx
+  114. copy_4_slots_unmasked          s.ah4[0] = $0..3
+  115. copy_slot_unmasked             f = af4[0](0)
+  116. copy_slot_unmasked             $0 = f
+  117. copy_slot_unmasked             af4[0](0) = $0
+  118. label                          label 0x00000000
+  119. copy_slot_unmasked             h = ah3x3[0](0)
+  120. copy_slot_unmasked             $0 = h
+  121. copy_slot_unmasked             ah3x3[0](0) = $0
+  122. label                          label 0x00000001
+  123. copy_slot_unmasked             i₁ = i
+  124. copy_slot_unmasked             $0 = i₁
+  125. copy_slot_unmasked             i = $0
+  126. label                          label 0x00000002
+  127. copy_slot_unmasked             i₁ = i4(1)
+  128. copy_slot_unmasked             $0 = i₁
+  129. copy_slot_unmasked             i4(1) = $0
+  130. label                          label 0x00000003
+  131. copy_slot_unmasked             i₁ = ai[0]
+  132. copy_slot_unmasked             $0 = i₁
+  133. copy_slot_unmasked             ai[0] = $0
+  134. label                          label 0x00000004
+  135. copy_slot_unmasked             i₁ = ai4[0](0)
+  136. copy_slot_unmasked             $0 = i₁
+  137. copy_slot_unmasked             ai4[0](0) = $0
+  138. label                          label 0x00000005
+  139. copy_slot_unmasked             h = x(1)
+  140. copy_slot_unmasked             $0 = h
+  141. copy_slot_unmasked             x(1) = $0
+  142. label                          label 0x00000006
+  143. copy_slot_unmasked             f = s.f
+  144. copy_slot_unmasked             $0 = f
+  145. copy_slot_unmasked             s.f = $0
+  146. label                          label 0x00000007
+  147. copy_slot_unmasked             h = l
+  148. copy_slot_unmasked             $0 = h
+  149. copy_slot_unmasked             l = $0
+  150. label                          label 0x00000008
+  151. copy_slot_unmasked             f = f3x3(0)
+  152. copy_slot_unmasked             $0 = f
+  153. copy_slot_unmasked             f3x3(0) = $0
+  154. label                          label 0x00000009
+  155. copy_4_constants               $0..3 = colorGreen
+  156. copy_4_slots_unmasked          [main].result = $0..3
+  157. load_src                       src.rgba = [main].result