typed-optimization-unittest.cc 10.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/compiler/typed-optimization.h"
#include "src/code-factory.h"
#include "src/compilation-dependencies.h"
#include "src/compiler/access-builder.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/js-operator.h"
#include "src/compiler/machine-operator.h"
#include "src/compiler/node-properties.h"
#include "src/compiler/operator-properties.h"
#include "src/isolate-inl.h"
#include "test/unittests/compiler/compiler-test-utils.h"
#include "test/unittests/compiler/graph-unittest.h"
#include "test/unittests/compiler/node-test-utils.h"
#include "testing/gmock-support.h"

using testing::IsNaN;

namespace v8 {
namespace internal {
namespace compiler {
25
namespace typed_optimization_unittest {
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64

namespace {

const double kFloat64Values[] = {
    -V8_INFINITY,  -4.23878e+275, -5.82632e+265, -6.60355e+220,
    -6.26172e+212, -2.56222e+211, -4.82408e+201, -1.84106e+157,
    -1.63662e+127, -1.55772e+100, -1.67813e+72,  -2.3382e+55,
    -3.179e+30,    -1.441e+09,    -1.0647e+09,   -7.99361e+08,
    -5.77375e+08,  -2.20984e+08,  -32757,        -13171,
    -9970,         -3984,         -107,          -105,
    -92,           -77,           -61,           -0.000208163,
    -1.86685e-06,  -1.17296e-10,  -9.26358e-11,  -5.08004e-60,
    -1.74753e-65,  -1.06561e-71,  -5.67879e-79,  -5.78459e-130,
    -2.90989e-171, -7.15489e-243, -3.76242e-252, -1.05639e-263,
    -4.40497e-267, -2.19666e-273, -4.9998e-276,  -5.59821e-278,
    -2.03855e-282, -5.99335e-283, -7.17554e-284, -3.11744e-309,
    -0.0,          0.0,           2.22507e-308,  1.30127e-270,
    7.62898e-260,  4.00313e-249,  3.16829e-233,  1.85244e-228,
    2.03544e-129,  1.35126e-110,  1.01182e-106,  5.26333e-94,
    1.35292e-90,   2.85394e-83,   1.78323e-77,   5.4967e-57,
    1.03207e-25,   4.57401e-25,   1.58738e-05,   2,
    125,           2310,          9636,          14802,
    17168,         28945,         29305,         4.81336e+07,
    1.41207e+08,   4.65962e+08,   1.40499e+09,   2.12648e+09,
    8.80006e+30,   1.4446e+45,    1.12164e+54,   2.48188e+89,
    6.71121e+102,  3.074e+112,    4.9699e+152,   5.58383e+166,
    4.30654e+172,  7.08824e+185,  9.6586e+214,   2.028e+223,
    6.63277e+243,  1.56192e+261,  1.23202e+269,  5.72883e+289,
    8.5798e+290,   1.40256e+294,  1.79769e+308,  V8_INFINITY};

const double kIntegerValues[] = {-V8_INFINITY, INT_MIN, -1000.0,  -42.0,
                                 -1.0,         0.0,     1.0,      42.0,
                                 1000.0,       INT_MAX, UINT_MAX, V8_INFINITY};

}  // namespace

class TypedOptimizationTest : public TypedGraphTest {
 public:
  TypedOptimizationTest()
65
      : TypedGraphTest(3), simplified_(zone()), deps_(isolate(), zone()) {}
66 67 68 69 70
  ~TypedOptimizationTest() override {}

 protected:
  Reduction Reduce(Node* node) {
    MachineOperatorBuilder machine(zone());
71 72
    JSOperatorBuilder javascript(zone());
    JSGraph jsgraph(isolate(), graph(), common(), &javascript, simplified(),
73 74 75
                    &machine);
    // TODO(titzer): mock the GraphReducer here for better unit testing.
    GraphReducer graph_reducer(zone(), graph());
76
    TypedOptimization reducer(&graph_reducer, &deps_, &jsgraph);
77 78 79
    return reducer.Reduce(node);
  }

80
  SimplifiedOperatorBuilder* simplified() { return &simplified_; }
81 82

 private:
83
  SimplifiedOperatorBuilder simplified_;
84 85 86 87 88 89
  CompilationDependencies deps_;
};

TEST_F(TypedOptimizationTest, ParameterWithMinusZero) {
  {
    Reduction r = Reduce(
90
        Parameter(Type::NewConstant(factory()->minus_zero_value(), zone())));
91 92 93 94 95 96 97 98 99
    ASSERT_TRUE(r.Changed());
    EXPECT_THAT(r.replacement(), IsNumberConstant(-0.0));
  }
  {
    Reduction r = Reduce(Parameter(Type::MinusZero()));
    ASSERT_TRUE(r.Changed());
    EXPECT_THAT(r.replacement(), IsNumberConstant(-0.0));
  }
  {
100 101 102
    Reduction r = Reduce(Parameter(Type::Union(
        Type::MinusZero(), Type::NewConstant(factory()->NewNumber(0), zone()),
        zone())));
103 104 105 106 107 108 109
    EXPECT_FALSE(r.Changed());
  }
}

TEST_F(TypedOptimizationTest, ParameterWithNull) {
  Handle<HeapObject> null = factory()->null_value();
  {
110
    Reduction r = Reduce(Parameter(Type::NewConstant(null, zone())));
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
    ASSERT_TRUE(r.Changed());
    EXPECT_THAT(r.replacement(), IsHeapConstant(null));
  }
  {
    Reduction r = Reduce(Parameter(Type::Null()));
    ASSERT_TRUE(r.Changed());
    EXPECT_THAT(r.replacement(), IsHeapConstant(null));
  }
}

TEST_F(TypedOptimizationTest, ParameterWithNaN) {
  const double kNaNs[] = {-std::numeric_limits<double>::quiet_NaN(),
                          std::numeric_limits<double>::quiet_NaN(),
                          std::numeric_limits<double>::signaling_NaN()};
  TRACED_FOREACH(double, nan, kNaNs) {
    Handle<Object> constant = factory()->NewNumber(nan);
127
    Reduction r = Reduce(Parameter(Type::NewConstant(constant, zone())));
128 129 130 131 132
    ASSERT_TRUE(r.Changed());
    EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN()));
  }
  {
    Reduction r =
133
        Reduce(Parameter(Type::NewConstant(factory()->nan_value(), zone())));
134 135 136 137 138 139 140 141 142 143 144 145 146
    ASSERT_TRUE(r.Changed());
    EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN()));
  }
  {
    Reduction r = Reduce(Parameter(Type::NaN()));
    ASSERT_TRUE(r.Changed());
    EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN()));
  }
}

TEST_F(TypedOptimizationTest, ParameterWithPlainNumber) {
  TRACED_FOREACH(double, value, kFloat64Values) {
    Handle<Object> constant = factory()->NewNumber(value);
147
    Reduction r = Reduce(Parameter(Type::NewConstant(constant, zone())));
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
    ASSERT_TRUE(r.Changed());
    EXPECT_THAT(r.replacement(), IsNumberConstant(value));
  }
  TRACED_FOREACH(double, value, kIntegerValues) {
    Reduction r = Reduce(Parameter(Type::Range(value, value, zone())));
    ASSERT_TRUE(r.Changed());
    EXPECT_THAT(r.replacement(), IsNumberConstant(value));
  }
}

TEST_F(TypedOptimizationTest, ParameterWithUndefined) {
  Handle<HeapObject> undefined = factory()->undefined_value();
  {
    Reduction r = Reduce(Parameter(Type::Undefined()));
    ASSERT_TRUE(r.Changed());
    EXPECT_THAT(r.replacement(), IsHeapConstant(undefined));
  }
  {
166
    Reduction r = Reduce(Parameter(Type::NewConstant(undefined, zone())));
167 168 169 170 171
    ASSERT_TRUE(r.Changed());
    EXPECT_THAT(r.replacement(), IsHeapConstant(undefined));
  }
}

172 173 174 175
// -----------------------------------------------------------------------------
// ToBoolean

TEST_F(TypedOptimizationTest, ToBooleanWithFalsish) {
176 177 178 179 180 181 182 183 184 185 186
  Node* input = Parameter(
      Type::Union(
          Type::MinusZero(),
          Type::Union(
              Type::NaN(),
              Type::Union(
                  Type::Null(),
                  Type::Union(
                      Type::Undefined(),
                      Type::Union(
                          Type::Undetectable(),
187 188 189
                          Type::Union(Type::NewConstant(
                                          factory()->false_value(), zone()),
                                      Type::Range(0.0, 0.0, zone()), zone()),
190 191 192 193 194 195
                          zone()),
                      zone()),
                  zone()),
              zone()),
          zone()),
      0);
196
  Reduction r = Reduce(graph()->NewNode(simplified()->ToBoolean(), input));
197 198 199 200
  ASSERT_TRUE(r.Changed());
  EXPECT_THAT(r.replacement(), IsFalseConstant());
}

201
TEST_F(TypedOptimizationTest, ToBooleanWithTruish) {
202 203
  Node* input = Parameter(
      Type::Union(
204
          Type::NewConstant(factory()->true_value(), zone()),
205 206 207
          Type::Union(Type::DetectableReceiver(), Type::Symbol(), zone()),
          zone()),
      0);
208
  Reduction r = Reduce(graph()->NewNode(simplified()->ToBoolean(), input));
209 210 211 212
  ASSERT_TRUE(r.Changed());
  EXPECT_THAT(r.replacement(), IsTrueConstant());
}

213
TEST_F(TypedOptimizationTest, ToBooleanWithNonZeroPlainNumber) {
214
  Node* input = Parameter(Type::Range(1, V8_INFINITY, zone()), 0);
215
  Reduction r = Reduce(graph()->NewNode(simplified()->ToBoolean(), input));
216 217 218 219
  ASSERT_TRUE(r.Changed());
  EXPECT_THAT(r.replacement(), IsTrueConstant());
}

220 221
TEST_F(TypedOptimizationTest, ToBooleanWithBoolean) {
  Node* input = Parameter(Type::Boolean(), 0);
222
  Reduction r = Reduce(graph()->NewNode(simplified()->ToBoolean(), input));
223 224 225 226 227 228
  ASSERT_TRUE(r.Changed());
  EXPECT_EQ(input, r.replacement());
}

TEST_F(TypedOptimizationTest, ToBooleanWithOrderedNumber) {
  Node* input = Parameter(Type::OrderedNumber(), 0);
229
  Reduction r = Reduce(graph()->NewNode(simplified()->ToBoolean(), input));
230 231 232 233 234 235 236
  ASSERT_TRUE(r.Changed());
  EXPECT_THAT(r.replacement(),
              IsBooleanNot(IsNumberEqual(input, IsNumberConstant(0.0))));
}

TEST_F(TypedOptimizationTest, ToBooleanWithNumber) {
  Node* input = Parameter(Type::Number(), 0);
237
  Reduction r = Reduce(graph()->NewNode(simplified()->ToBoolean(), input));
238 239 240 241 242 243
  ASSERT_TRUE(r.Changed());
  EXPECT_THAT(r.replacement(), IsNumberToBoolean(input));
}

TEST_F(TypedOptimizationTest, ToBooleanWithDetectableReceiverOrNull) {
  Node* input = Parameter(Type::DetectableReceiverOrNull(), 0);
244
  Reduction r = Reduce(graph()->NewNode(simplified()->ToBoolean(), input));
245 246 247 248 249 250 251
  ASSERT_TRUE(r.Changed());
  EXPECT_THAT(r.replacement(),
              IsBooleanNot(IsReferenceEqual(input, IsNullConstant())));
}

TEST_F(TypedOptimizationTest, ToBooleanWithReceiverOrNullOrUndefined) {
  Node* input = Parameter(Type::ReceiverOrNullOrUndefined(), 0);
252
  Reduction r = Reduce(graph()->NewNode(simplified()->ToBoolean(), input));
253 254 255 256 257 258
  ASSERT_TRUE(r.Changed());
  EXPECT_THAT(r.replacement(), IsBooleanNot(IsObjectIsUndetectable(input)));
}

TEST_F(TypedOptimizationTest, ToBooleanWithString) {
  Node* input = Parameter(Type::String(), 0);
259
  Reduction r = Reduce(graph()->NewNode(simplified()->ToBoolean(), input));
260 261 262 263 264 265 266 267
  ASSERT_TRUE(r.Changed());
  EXPECT_THAT(r.replacement(),
              IsBooleanNot(IsReferenceEqual(
                  input, IsHeapConstant(factory()->empty_string()))));
}

TEST_F(TypedOptimizationTest, ToBooleanWithAny) {
  Node* input = Parameter(Type::Any(), 0);
268
  Reduction r = Reduce(graph()->NewNode(simplified()->ToBoolean(), input));
269 270 271
  ASSERT_FALSE(r.Changed());
}

272
}  // namespace typed_optimization_unittest
273 274 275
}  // namespace compiler
}  // namespace internal
}  // namespace v8