Add support for casting ints and floats to bool.

These casts are implemented as `notEqual(x, 0)`.
This causes five additional tests to pass (58/190):

inliner/TernaryTestCanBeInlined.sksl
inliner/TernaryResultsCannotBeInlined.sksl
inliner/ShortCircuitEvaluationsCannotInlineRightHandSide.sksl
inliner/IfTestCanBeInlined.sksl
inliner/IfElseChainWithReturnsCanBeInlined.sksl

Change-Id: I6ad5442fdd4f3d5d9aaaa4b04db14ecc305465c7
Bug: skia:13676
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/625677
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/SkSLRasterPipelineBuilder.cpp b/src/sksl/codegen/SkSLRasterPipelineBuilder.cpp
index 213e2af..2c10df5 100644
--- a/src/sksl/codegen/SkSLRasterPipelineBuilder.cpp
+++ b/src/sksl/codegen/SkSLRasterPipelineBuilder.cpp
@@ -127,6 +127,7 @@
 
         case BuilderOp::push_slots:
         case BuilderOp::push_uniform:
+        case BuilderOp::push_zeros:
             return inst.fImmA;
 
         case ALL_SINGLE_SLOT_BINARY_OP_CASES:
@@ -557,6 +558,11 @@
                 this->appendCopyConstants(pipeline, alloc, dst, UniformA(), inst.fImmA);
                 break;
             }
+            case BuilderOp::push_zeros: {
+                float* dst = tempStackPtr;
+                this->appendMultiSlotUnaryOp(pipeline, SkRP::zero_slot_unmasked, dst, inst.fImmA);
+                break;
+            }
             case BuilderOp::push_condition_mask: {
                 float* dst = tempStackPtr;
                 this->append(pipeline, SkRP::store_condition_mask, dst);
diff --git a/src/sksl/codegen/SkSLRasterPipelineBuilder.h b/src/sksl/codegen/SkSLRasterPipelineBuilder.h
index de76bee..1e79020 100644
--- a/src/sksl/codegen/SkSLRasterPipelineBuilder.h
+++ b/src/sksl/codegen/SkSLRasterPipelineBuilder.h
@@ -47,6 +47,7 @@
     push_literal_f,
     push_slots,
     push_uniform,
+    push_zeros,
     copy_stack_to_slots,
     copy_stack_to_slots_unmasked,
     discard_stack,
@@ -272,6 +273,11 @@
         fInstructions.push_back({BuilderOp::push_uniform, {src.index}, src.count});
     }
 
+    void push_zeros(int count) {
+        // Translates into zero_slot_unmasked in Raster Pipeline.
+        fInstructions.push_back({BuilderOp::push_zeros, {}, count});
+    }
+
     void push_slots(SlotRange src) {
         SkASSERT(src.count >= 0);
         if (src.count > 0) {
diff --git a/src/sksl/codegen/SkSLRasterPipelineCodeGenerator.cpp b/src/sksl/codegen/SkSLRasterPipelineCodeGenerator.cpp
index 731ced3..dee1aa0 100644
--- a/src/sksl/codegen/SkSLRasterPipelineCodeGenerator.cpp
+++ b/src/sksl/codegen/SkSLRasterPipelineCodeGenerator.cpp
@@ -1050,6 +1050,7 @@
 bool Generator::pushConstructorCast(const AnyConstructor& c) {
     SkASSERT(c.argumentSpan().size() == 1);
     const Expression& inner = *c.argumentSpan().front();
+    SkASSERT(inner.type().slotCount() == c.type().slotCount());
 
     if (!this->pushExpression(inner)) {
         return unsupported();
@@ -1058,6 +1059,11 @@
         // Since we ignore type precision, this cast is effectively a no-op.
         return true;
     }
+    if (c.type().componentType().isBoolean()) {
+        // Converting int or float to boolean can be accomplished via `notEqual(x, 0)`.
+        fBuilder.push_zeros(c.type().slotCount());
+        return this->binaryOp(inner.type(), kNotEqualOps);
+    }
 
     // TODO: add RP op to convert values on stack from the inner type to the outer type
     return unsupported();
diff --git a/tests/RasterPipelineBuilderTest.cpp b/tests/RasterPipelineBuilderTest.cpp
index 267965a..ac99cb1 100644
--- a/tests/RasterPipelineBuilderTest.cpp
+++ b/tests/RasterPipelineBuilderTest.cpp
@@ -423,6 +423,7 @@
     5. bitwise_not                    $4 = ~$4
 )");
 }
+
 DEF_TEST(RasterPipelineBuilderUniforms, r) {
     // Create a very simple nonsense program.
     SkSL::RP::Builder builder;
@@ -444,6 +445,27 @@
 )");
 }
 
+DEF_TEST(RasterPipelineBuilderPushZeros, r) {
+    // Create a very simple nonsense program.
+    SkSL::RP::Builder builder;
+    builder.push_zeros(1);      // push into 0
+    builder.push_zeros(2);      // push into 1~2
+    builder.push_zeros(3);      // push into 3~5
+    builder.push_zeros(4);      // push into 6~9
+    builder.push_zeros(5);      // push into 10~14
+    builder.discard_stack(15);  // balance stack
+    std::unique_ptr<SkSL::RP::Program> program = builder.finish(/*numValueSlots=*/0,
+                                                                /*numUniformSlots=*/10);
+    check(r, *program,
+R"(    1. zero_slot_unmasked             $0 = 0
+    2. zero_2_slots_unmasked          $1..2 = 0
+    3. zero_3_slots_unmasked          $3..5 = 0
+    4. zero_4_slots_unmasked          $6..9 = 0
+    5. zero_4_slots_unmasked          $10..13 = 0
+    6. zero_slot_unmasked             $14 = 0
+)");
+}
+
 DEF_TEST(RasterPipelineBuilderTernaryFloatOps, r) {
     using BuilderOp = SkSL::RP::BuilderOp;