Implement log and log2 intrinsics in SkRP.

These already existed in Raster Pipeline, so they just needed to be
wired up into the SkRP builder and codegen. I also ported over the
SkVM unit test for log2 since we didn't have an RP equivalent.

Change-Id: Ida15486084ebd76f50f9aaa3c3c0e7d0c1b399f8
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/658080
Auto-Submit: John Stiles <johnstiles@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: John Stiles <johnstiles@google.com>
diff --git a/src/core/SkRasterPipelineOpList.h b/src/core/SkRasterPipelineOpList.h
index d1246b4..2d4a4f8 100644
--- a/src/core/SkRasterPipelineOpList.h
+++ b/src/core/SkRasterPipelineOpList.h
@@ -130,6 +130,7 @@
     M(sin_float)        M(cos_float)           M(tan_float)                                   \
     M(asin_float)       M(acos_float)          M(atan_float)          M(atan2_n_floats)       \
     M(sqrt_float)       M(pow_n_floats)        M(exp_float)                                   \
+    M(log_float)        M(log2_float)                                                         \
     M(copy_constant)    M(copy_2_constants)    M(copy_3_constants)    M(copy_4_constants)     \
     M(copy_slot_masked) M(copy_2_slots_masked) M(copy_3_slots_masked) M(copy_4_slots_masked)  \
     M(copy_from_indirect_unmasked) M(copy_from_indirect_uniform_unmasked)                     \
diff --git a/src/opts/SkRasterPipeline_opts.h b/src/opts/SkRasterPipeline_opts.h
index 3eaeed0..49ab5de 100644
--- a/src/opts/SkRasterPipeline_opts.h
+++ b/src/opts/SkRasterPipeline_opts.h
@@ -1035,7 +1035,7 @@
 
 SI F fract(F v) { return v - floor_(v); }
 
-// See http://www.machinedlearnings.com/2011/06/fast-approximate-logarithm-exponential.html.
+// See http://www.machinedlearnings.com/2011/06/fast-approximate-logarithm-exponential.html
 SI F approx_log2(F x) {
     // e - 127 is a fair approximation of log2(x) in its own right...
     F e = cast(sk_bit_cast<U32>(x)) * (1.0f / (1<<23));
@@ -3719,6 +3719,8 @@
 STAGE_TAIL(atan_float, F* dst) { *dst = atan_(*dst); }
 STAGE_TAIL(sqrt_float, F* dst) { *dst = sqrt_(*dst); }
 STAGE_TAIL(exp_float, F* dst)  { *dst = approx_exp(*dst); }
+STAGE_TAIL(log_float, F* dst)  { *dst = approx_log(*dst); }
+STAGE_TAIL(log2_float, F* dst) { *dst = approx_log2(*dst); }
 
 // Binary operations take two adjacent inputs, and write their output in the first position.
 template <typename T, void (*ApplyFn)(T*, T*)>
diff --git a/src/sksl/codegen/SkSLRasterPipelineBuilder.cpp b/src/sksl/codegen/SkSLRasterPipelineBuilder.cpp
index 395cb94..b42a585 100644
--- a/src/sksl/codegen/SkSLRasterPipelineBuilder.cpp
+++ b/src/sksl/codegen/SkSLRasterPipelineBuilder.cpp
@@ -42,6 +42,8 @@
     case BuilderOp::atan_float:         \
     case BuilderOp::cos_float:          \
     case BuilderOp::exp_float:          \
+    case BuilderOp::log_float:          \
+    case BuilderOp::log2_float:         \
     case BuilderOp::sin_float:          \
     case BuilderOp::sqrt_float:         \
     case BuilderOp::tan_float
@@ -2045,6 +2047,8 @@
             case POp::ceil_float:
             case POp::cos_float:
             case POp::exp_float:
+            case POp::log_float:
+            case POp::log2_float:
             case POp::floor_float:
             case POp::sin_float:
             case POp::sqrt_float:
@@ -2486,6 +2490,14 @@
                 opText = opArg1 + " = exp(" + opArg1 + ")";
                 break;
 
+            case POp::log_float:
+                opText = opArg1 + " = log(" + opArg1 + ")";
+                break;
+
+            case POp::log2_float:
+                opText = opArg1 + " = log2(" + opArg1 + ")";
+                break;
+
             case POp::pow_n_floats:
                 opText = opArg1 + " = pow(" + opArg1 + ", " + opArg2 + ")";
                 break;
diff --git a/src/sksl/codegen/SkSLRasterPipelineCodeGenerator.cpp b/src/sksl/codegen/SkSLRasterPipelineCodeGenerator.cpp
index 5a0e7d1..396f4b6 100644
--- a/src/sksl/codegen/SkSLRasterPipelineCodeGenerator.cpp
+++ b/src/sksl/codegen/SkSLRasterPipelineCodeGenerator.cpp
@@ -2570,6 +2570,20 @@
             return this->pushExpression(arg0) &&
                    this->pushLengthIntrinsic(arg0.type().slotCount());
 
+        case IntrinsicKind::k_log_IntrinsicKind:
+            if (!this->pushExpression(arg0)) {
+                return unsupported();
+            }
+            fBuilder.unary_op(BuilderOp::log_float, arg0.type().slotCount());
+            return true;
+
+        case IntrinsicKind::k_log2_IntrinsicKind:
+            if (!this->pushExpression(arg0)) {
+                return unsupported();
+            }
+            fBuilder.unary_op(BuilderOp::log2_float, arg0.type().slotCount());
+            return true;
+
         case IntrinsicKind::k_normalize_IntrinsicKind:
             // Implement normalize as `x / length(x)`. First, push the expression.
             if (!this->pushExpression(arg0)) {
diff --git a/tests/SkRasterPipelineOptsTest.cpp b/tests/SkRasterPipelineOptsTest.cpp
index d4e4cea..162bf2d 100644
--- a/tests/SkRasterPipelineOptsTest.cpp
+++ b/tests/SkRasterPipelineOptsTest.cpp
@@ -175,3 +175,16 @@
         }
     }
 }
+
+DEF_TEST(SkRasterPipelineOpts_Log2, r) {
+    using F = SK_OPTS_NS::F;
+
+    constexpr float kTolerance = 0.001f;
+    for (float value : {0.25f, 0.5f, 1.0f, 2.0f, 4.0f, 8.0f}) {
+        F result = SK_OPTS_NS::approx_log2(value);
+        F expected = std::log2(value);
+        F delta = SK_OPTS_NS::abs_(expected - result);
+
+        REPORTER_ASSERT(r, SK_OPTS_NS::all(delta < kTolerance));
+    }
+}
diff --git a/tests/sksl/intrinsics/Log.skrp b/tests/sksl/intrinsics/Log.skrp
index 3ef3d71..eaa03e3 100644
--- a/tests/sksl/intrinsics/Log.skrp
+++ b/tests/sksl/intrinsics/Log.skrp
@@ -1,4 +1,60 @@
-### 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. copy_constant                  $4 = inputVal(0)
+    4. log_float                      $4 = log($4)
+    5. copy_constant                  $5 = expected(0)
+    6. cmpeq_float                    $4 = equal($4, $5)
+    7. copy_2_constants               $5..6 = inputVal(0..1)
+    8. log_float                      $5 = log($5)
+    9. log_float                      $6 = log($6)
+   10. copy_2_constants               $7..8 = expected(0..1)
+   11. cmpeq_2_floats                 $5..6 = equal($5..6, $7..8)
+   12. bitwise_and_int                $5 &= $6
+   13. bitwise_and_int                $4 &= $5
+   14. copy_3_constants               $5..7 = inputVal(0..2)
+   15. log_float                      $5 = log($5)
+   16. log_float                      $6 = log($6)
+   17. log_float                      $7 = log($7)
+   18. copy_3_constants               $8..10 = expected(0..2)
+   19. cmpeq_3_floats                 $5..7 = equal($5..7, $8..10)
+   20. bitwise_and_int                $6 &= $7
+   21. bitwise_and_int                $5 &= $6
+   22. bitwise_and_int                $4 &= $5
+   23. copy_4_constants               $5..8 = inputVal
+   24. log_float                      $5 = log($5)
+   25. log_float                      $6 = log($6)
+   26. log_float                      $7 = log($7)
+   27. log_float                      $8 = log($8)
+   28. copy_4_constants               $9..12 = expected
+   29. cmpeq_4_floats                 $5..8 = equal($5..8, $9..12)
+   30. bitwise_and_2_ints             $5..6 &= $7..8
+   31. bitwise_and_int                $5 &= $6
+   32. bitwise_and_int                $4 &= $5
+   33. zero_slot_unmasked             $5 = 0
+   34. copy_constant                  $6 = expected(0)
+   35. cmpeq_float                    $5 = equal($5, $6)
+   36. bitwise_and_int                $4 &= $5
+   37. zero_2_slots_unmasked          $5..6 = 0
+   38. copy_2_constants               $7..8 = expected(0..1)
+   39. cmpeq_2_floats                 $5..6 = equal($5..6, $7..8)
+   40. bitwise_and_int                $5 &= $6
+   41. bitwise_and_int                $4 &= $5
+   42. zero_3_slots_unmasked          $5..7 = 0
+   43. copy_3_constants               $8..10 = expected(0..2)
+   44. cmpeq_3_floats                 $5..7 = equal($5..7, $8..10)
+   45. bitwise_and_int                $6 &= $7
+   46. bitwise_and_int                $5 &= $6
+   47. bitwise_and_int                $4 &= $5
+   48. zero_4_slots_unmasked          $5..8 = 0
+   49. copy_4_constants               $9..12 = expected
+   50. cmpeq_4_floats                 $5..8 = equal($5..8, $9..12)
+   51. bitwise_and_2_ints             $5..6 &= $7..8
+   52. bitwise_and_int                $5 &= $6
+   53. bitwise_and_int                $4 &= $5
+   54. branch_if_no_active_lanes_eq   branch +3 (label 0 at #57) if no lanes of $4 == 0xFFFFFFFF
+   55. copy_4_constants               $0..3 = colorGreen
+   56. jump                           jump +3 (label 1 at #59)
+   57. label                          label 0x00000000
+   58. copy_4_constants               $0..3 = colorRed
+   59. label                          label 0x00000001
+   60. load_src                       src.rgba = $0..3
diff --git a/tests/sksl/intrinsics/Log2.skrp b/tests/sksl/intrinsics/Log2.skrp
index 3ef3d71..bd4817c 100644
--- a/tests/sksl/intrinsics/Log2.skrp
+++ b/tests/sksl/intrinsics/Log2.skrp
@@ -1,4 +1,66 @@
-### 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. copy_constant                  $4 = inputVal(0)
+    4. log2_float                     $4 = log2($4)
+    5. copy_constant                  $5 = expected(0)
+    6. cmpeq_float                    $4 = equal($4, $5)
+    7. copy_2_constants               $5..6 = inputVal(0..1)
+    8. log2_float                     $5 = log2($5)
+    9. log2_float                     $6 = log2($6)
+   10. copy_2_constants               $7..8 = expected(0..1)
+   11. cmpeq_2_floats                 $5..6 = equal($5..6, $7..8)
+   12. bitwise_and_int                $5 &= $6
+   13. bitwise_and_int                $4 &= $5
+   14. copy_3_constants               $5..7 = inputVal(0..2)
+   15. log2_float                     $5 = log2($5)
+   16. log2_float                     $6 = log2($6)
+   17. log2_float                     $7 = log2($7)
+   18. copy_3_constants               $8..10 = expected(0..2)
+   19. cmpeq_3_floats                 $5..7 = equal($5..7, $8..10)
+   20. bitwise_and_int                $6 &= $7
+   21. bitwise_and_int                $5 &= $6
+   22. bitwise_and_int                $4 &= $5
+   23. copy_4_constants               $5..8 = inputVal
+   24. log2_float                     $5 = log2($5)
+   25. log2_float                     $6 = log2($6)
+   26. log2_float                     $7 = log2($7)
+   27. log2_float                     $8 = log2($8)
+   28. copy_4_constants               $9..12 = expected
+   29. cmpeq_4_floats                 $5..8 = equal($5..8, $9..12)
+   30. bitwise_and_2_ints             $5..6 &= $7..8
+   31. bitwise_and_int                $5 &= $6
+   32. bitwise_and_int                $4 &= $5
+   33. zero_slot_unmasked             $5 = 0
+   34. copy_constant                  $6 = expected(0)
+   35. cmpeq_float                    $5 = equal($5, $6)
+   36. bitwise_and_int                $4 &= $5
+   37. zero_slot_unmasked             $5 = 0
+   38. copy_constant                  $6 = 0x3F800000 (1.0)
+   39. copy_2_constants               $7..8 = expected(0..1)
+   40. cmpeq_2_floats                 $5..6 = equal($5..6, $7..8)
+   41. bitwise_and_int                $5 &= $6
+   42. bitwise_and_int                $4 &= $5
+   43. zero_slot_unmasked             $5 = 0
+   44. copy_constant                  $6 = 0x3F800000 (1.0)
+   45. copy_constant                  $7 = 0x40000000 (2.0)
+   46. copy_3_constants               $8..10 = expected(0..2)
+   47. cmpeq_3_floats                 $5..7 = equal($5..7, $8..10)
+   48. bitwise_and_int                $6 &= $7
+   49. bitwise_and_int                $5 &= $6
+   50. bitwise_and_int                $4 &= $5
+   51. zero_slot_unmasked             $5 = 0
+   52. copy_constant                  $6 = 0x3F800000 (1.0)
+   53. copy_constant                  $7 = 0x40000000 (2.0)
+   54. copy_constant                  $8 = 0x40400000 (3.0)
+   55. copy_4_constants               $9..12 = expected
+   56. cmpeq_4_floats                 $5..8 = equal($5..8, $9..12)
+   57. bitwise_and_2_ints             $5..6 &= $7..8
+   58. bitwise_and_int                $5 &= $6
+   59. bitwise_and_int                $4 &= $5
+   60. branch_if_no_active_lanes_eq   branch +3 (label 0 at #63) if no lanes of $4 == 0xFFFFFFFF
+   61. copy_4_constants               $0..3 = colorGreen
+   62. jump                           jump +3 (label 1 at #65)
+   63. label                          label 0x00000000
+   64. copy_4_constants               $0..3 = colorRed
+   65. label                          label 0x00000001
+   66. load_src                       src.rgba = $0..3