| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 1 // Copyright 2014 the V8 project authors. All rights reserved. | 
|  | 2 // Use of this source code is governed by a BSD-style license that can be | 
|  | 3 // found in the LICENSE file. | 
|  | 4 | 
|  | 5 #include <limits> | 
|  | 6 | 
|  | 7 #include "src/v8.h" | 
|  | 8 #include "test/cctest/cctest.h" | 
|  | 9 #include "test/cctest/compiler/graph-builder-tester.h" | 
|  | 10 | 
|  | 11 #include "src/compiler/node-matchers.h" | 
|  | 12 #include "src/compiler/representation-change.h" | 
|  | 13 #include "src/compiler/typer.h" | 
|  | 14 | 
|  | 15 using namespace v8::internal; | 
|  | 16 using namespace v8::internal::compiler; | 
|  | 17 | 
|  | 18 namespace v8 {  // for friendiness. | 
|  | 19 namespace internal { | 
|  | 20 namespace compiler { | 
|  | 21 | 
|  | 22 class RepresentationChangerTester : public HandleAndZoneScope, | 
|  | 23                                     public GraphAndBuilders { | 
|  | 24  public: | 
|  | 25   RepresentationChangerTester() | 
|  | 26       : GraphAndBuilders(main_zone()), | 
|  | 27         typer_(main_zone()), | 
|  | 28         jsgraph_(main_graph_, &main_common_, &typer_), | 
|  | 29         changer_(&jsgraph_, &main_simplified_, &main_machine_, main_isolate()) { | 
|  | 30   } | 
|  | 31 | 
|  | 32   Typer typer_; | 
|  | 33   JSGraph jsgraph_; | 
|  | 34   RepresentationChanger changer_; | 
|  | 35 | 
|  | 36   Isolate* isolate() { return main_isolate(); } | 
|  | 37   Graph* graph() { return main_graph_; } | 
|  | 38   CommonOperatorBuilder* common() { return &main_common_; } | 
|  | 39   JSGraph* jsgraph() { return &jsgraph_; } | 
|  | 40   RepresentationChanger* changer() { return &changer_; } | 
|  | 41 | 
|  | 42   // TODO(titzer): use ValueChecker / ValueUtil | 
|  | 43   void CheckInt32Constant(Node* n, int32_t expected) { | 
|  | 44     ValueMatcher<int32_t> m(n); | 
|  | 45     CHECK(m.HasValue()); | 
|  | 46     CHECK_EQ(expected, m.Value()); | 
|  | 47   } | 
|  | 48 | 
|  | 49   void CheckHeapConstant(Node* n, Object* expected) { | 
|  | 50     ValueMatcher<Handle<Object> > m(n); | 
|  | 51     CHECK(m.HasValue()); | 
|  | 52     CHECK_EQ(expected, *m.Value()); | 
|  | 53   } | 
|  | 54 | 
|  | 55   void CheckNumberConstant(Node* n, double expected) { | 
|  | 56     ValueMatcher<double> m(n); | 
|  | 57     CHECK_EQ(IrOpcode::kNumberConstant, n->opcode()); | 
|  | 58     CHECK(m.HasValue()); | 
|  | 59     CHECK_EQ(expected, m.Value()); | 
|  | 60   } | 
|  | 61 | 
|  | 62   Node* Parameter(int index = 0) { | 
|  | 63     return graph()->NewNode(common()->Parameter(index)); | 
|  | 64   } | 
|  | 65 | 
|  | 66   void CheckTypeError(RepTypeUnion from, RepTypeUnion to) { | 
|  | 67     changer()->testing_type_errors_ = true; | 
|  | 68     changer()->type_error_ = false; | 
|  | 69     Node* n = Parameter(0); | 
|  | 70     Node* c = changer()->GetRepresentationFor(n, from, to); | 
|  | 71     CHECK_EQ(n, c); | 
|  | 72     CHECK(changer()->type_error_); | 
|  | 73   } | 
|  | 74 | 
|  | 75   void CheckNop(RepTypeUnion from, RepTypeUnion to) { | 
|  | 76     Node* n = Parameter(0); | 
|  | 77     Node* c = changer()->GetRepresentationFor(n, from, to); | 
|  | 78     CHECK_EQ(n, c); | 
|  | 79   } | 
|  | 80 }; | 
|  | 81 } | 
|  | 82 } | 
|  | 83 }  // namespace v8::internal::compiler | 
|  | 84 | 
|  | 85 | 
|  | 86 static const RepType all_reps[] = {rBit, rWord32, rWord64, rFloat64, rTagged}; | 
|  | 87 | 
|  | 88 | 
|  | 89 // TODO(titzer): lift this to ValueHelper | 
|  | 90 static const double double_inputs[] = { | 
|  | 91     0.0,   -0.0,    1.0,    -1.0,        0.1,         1.4,    -1.7, | 
|  | 92     2,     5,       6,      982983,      888,         -999.8, 3.1e7, | 
|  | 93     -2e66, 2.3e124, -12e73, V8_INFINITY, -V8_INFINITY}; | 
|  | 94 | 
|  | 95 | 
|  | 96 static const int32_t int32_inputs[] = { | 
|  | 97     0,      1,                                -1, | 
|  | 98     2,      5,                                6, | 
|  | 99     982983, 888,                              -999, | 
|  | 100     65535,  static_cast<int32_t>(0xFFFFFFFF), static_cast<int32_t>(0x80000000)}; | 
|  | 101 | 
|  | 102 | 
|  | 103 static const uint32_t uint32_inputs[] = { | 
|  | 104     0,      1,   static_cast<uint32_t>(-1),   2,     5,          6, | 
|  | 105     982983, 888, static_cast<uint32_t>(-999), 65535, 0xFFFFFFFF, 0x80000000}; | 
|  | 106 | 
|  | 107 | 
|  | 108 TEST(BoolToBit_constant) { | 
|  | 109   RepresentationChangerTester r; | 
|  | 110 | 
|  | 111   Node* true_node = r.jsgraph()->TrueConstant(); | 
|  | 112   Node* true_bit = r.changer()->GetRepresentationFor(true_node, rTagged, rBit); | 
|  | 113   r.CheckInt32Constant(true_bit, 1); | 
|  | 114 | 
|  | 115   Node* false_node = r.jsgraph()->FalseConstant(); | 
|  | 116   Node* false_bit = | 
|  | 117       r.changer()->GetRepresentationFor(false_node, rTagged, rBit); | 
|  | 118   r.CheckInt32Constant(false_bit, 0); | 
|  | 119 } | 
|  | 120 | 
|  | 121 | 
|  | 122 TEST(BitToBool_constant) { | 
|  | 123   RepresentationChangerTester r; | 
|  | 124 | 
|  | 125   for (int i = -5; i < 5; i++) { | 
|  | 126     Node* node = r.jsgraph()->Int32Constant(i); | 
|  | 127     Node* val = r.changer()->GetRepresentationFor(node, rBit, rTagged); | 
|  | 128     r.CheckHeapConstant(val, i == 0 ? r.isolate()->heap()->false_value() | 
|  | 129                                     : r.isolate()->heap()->true_value()); | 
|  | 130   } | 
|  | 131 } | 
|  | 132 | 
|  | 133 | 
|  | 134 TEST(ToTagged_constant) { | 
|  | 135   RepresentationChangerTester r; | 
|  | 136 | 
|  | 137   for (size_t i = 0; i < ARRAY_SIZE(double_inputs); i++) { | 
|  | 138     Node* n = r.jsgraph()->Float64Constant(double_inputs[i]); | 
|  | 139     Node* c = r.changer()->GetRepresentationFor(n, rFloat64, rTagged); | 
|  | 140     r.CheckNumberConstant(c, double_inputs[i]); | 
|  | 141   } | 
|  | 142 | 
|  | 143   for (size_t i = 0; i < ARRAY_SIZE(int32_inputs); i++) { | 
|  | 144     Node* n = r.jsgraph()->Int32Constant(int32_inputs[i]); | 
|  | 145     Node* c = r.changer()->GetRepresentationFor(n, rWord32 | tInt32, rTagged); | 
|  | 146     r.CheckNumberConstant(c, static_cast<double>(int32_inputs[i])); | 
|  | 147   } | 
|  | 148 | 
|  | 149   for (size_t i = 0; i < ARRAY_SIZE(uint32_inputs); i++) { | 
|  | 150     Node* n = r.jsgraph()->Int32Constant(uint32_inputs[i]); | 
|  | 151     Node* c = r.changer()->GetRepresentationFor(n, rWord32 | tUint32, rTagged); | 
|  | 152     r.CheckNumberConstant(c, static_cast<double>(uint32_inputs[i])); | 
|  | 153   } | 
|  | 154 } | 
|  | 155 | 
|  | 156 | 
|  | 157 static void CheckChange(IrOpcode::Value expected, RepTypeUnion from, | 
|  | 158                         RepTypeUnion to) { | 
|  | 159   RepresentationChangerTester r; | 
|  | 160 | 
|  | 161   Node* n = r.Parameter(); | 
|  | 162   Node* c = r.changer()->GetRepresentationFor(n, from, to); | 
|  | 163 | 
|  | 164   CHECK_NE(c, n); | 
|  | 165   CHECK_EQ(expected, c->opcode()); | 
|  | 166   CHECK_EQ(n, c->InputAt(0)); | 
|  | 167 } | 
|  | 168 | 
|  | 169 | 
|  | 170 TEST(SingleChanges) { | 
|  | 171   CheckChange(IrOpcode::kChangeBoolToBit, rTagged, rBit); | 
|  | 172   CheckChange(IrOpcode::kChangeBitToBool, rBit, rTagged); | 
|  | 173 | 
|  | 174   CheckChange(IrOpcode::kChangeInt32ToTagged, rWord32 | tInt32, rTagged); | 
|  | 175   CheckChange(IrOpcode::kChangeUint32ToTagged, rWord32 | tUint32, rTagged); | 
|  | 176   CheckChange(IrOpcode::kChangeFloat64ToTagged, rFloat64, rTagged); | 
|  | 177 | 
|  | 178   CheckChange(IrOpcode::kChangeTaggedToInt32, rTagged | tInt32, rWord32); | 
|  | 179   CheckChange(IrOpcode::kChangeTaggedToUint32, rTagged | tUint32, rWord32); | 
|  | 180   CheckChange(IrOpcode::kChangeTaggedToFloat64, rTagged, rFloat64); | 
|  | 181 | 
|  | 182   // Int32,Uint32 <-> Float64 are actually machine conversions. | 
|  | 183   CheckChange(IrOpcode::kConvertInt32ToFloat64, rWord32 | tInt32, rFloat64); | 
|  | 184   CheckChange(IrOpcode::kConvertUint32ToFloat64, rWord32 | tUint32, rFloat64); | 
|  | 185   CheckChange(IrOpcode::kConvertFloat64ToInt32, rFloat64 | tInt32, rWord32); | 
|  | 186   CheckChange(IrOpcode::kConvertFloat64ToUint32, rFloat64 | tUint32, rWord32); | 
|  | 187 } | 
|  | 188 | 
|  | 189 | 
|  | 190 TEST(SignednessInWord32) { | 
|  | 191   RepresentationChangerTester r; | 
|  | 192 | 
|  | 193   // TODO(titzer): these are currently type errors because the output type is | 
|  | 194   // not specified. Maybe the RepresentationChanger should assume anything to or | 
|  | 195   // from {rWord32} is {tInt32}, i.e. signed, if not it is explicitly otherwise? | 
|  | 196   r.CheckTypeError(rTagged, rWord32 | tInt32); | 
|  | 197   r.CheckTypeError(rTagged, rWord32 | tUint32); | 
|  | 198   r.CheckTypeError(rWord32, rFloat64); | 
|  | 199   r.CheckTypeError(rFloat64, rWord32); | 
|  | 200 | 
|  | 201   //  CheckChange(IrOpcode::kChangeTaggedToInt32, rTagged, rWord32 | tInt32); | 
|  | 202   //  CheckChange(IrOpcode::kChangeTaggedToUint32, rTagged, rWord32 | tUint32); | 
|  | 203   //  CheckChange(IrOpcode::kConvertInt32ToFloat64, rWord32, rFloat64); | 
|  | 204   //  CheckChange(IrOpcode::kConvertFloat64ToInt32, rFloat64, rWord32); | 
|  | 205 } | 
|  | 206 | 
|  | 207 | 
|  | 208 TEST(Nops) { | 
|  | 209   RepresentationChangerTester r; | 
|  | 210 | 
|  | 211   // X -> X is always a nop for any single representation X. | 
|  | 212   for (size_t i = 0; i < ARRAY_SIZE(all_reps); i++) { | 
|  | 213     r.CheckNop(all_reps[i], all_reps[i]); | 
|  | 214   } | 
|  | 215 | 
|  | 216   // 32-bit or 64-bit words can be used as branch conditions (rBit). | 
|  | 217   r.CheckNop(rWord32, rBit); | 
|  | 218   r.CheckNop(rWord32, rBit | tBool); | 
|  | 219   r.CheckNop(rWord64, rBit); | 
|  | 220   r.CheckNop(rWord64, rBit | tBool); | 
|  | 221 | 
|  | 222   // rBit (result of comparison) is implicitly a wordish thing. | 
|  | 223   r.CheckNop(rBit, rWord32); | 
|  | 224   r.CheckNop(rBit | tBool, rWord32); | 
|  | 225   r.CheckNop(rBit, rWord64); | 
|  | 226   r.CheckNop(rBit | tBool, rWord64); | 
|  | 227 } | 
|  | 228 | 
|  | 229 | 
|  | 230 TEST(TypeErrors) { | 
|  | 231   RepresentationChangerTester r; | 
|  | 232 | 
|  | 233   // Floats cannot be implicitly converted to/from comparison conditions. | 
|  | 234   r.CheckTypeError(rFloat64, rBit); | 
|  | 235   r.CheckTypeError(rFloat64, rBit | tBool); | 
|  | 236   r.CheckTypeError(rBit, rFloat64); | 
|  | 237   r.CheckTypeError(rBit | tBool, rFloat64); | 
|  | 238 | 
|  | 239   // Word64 is internal and shouldn't be implicitly converted. | 
|  | 240   r.CheckTypeError(rWord64, rTagged | tBool); | 
|  | 241   r.CheckTypeError(rWord64, rTagged); | 
|  | 242   r.CheckTypeError(rWord64, rTagged | tBool); | 
|  | 243   r.CheckTypeError(rTagged, rWord64); | 
|  | 244   r.CheckTypeError(rTagged | tBool, rWord64); | 
|  | 245 | 
|  | 246   // Word64 / Word32 shouldn't be implicitly converted. | 
|  | 247   r.CheckTypeError(rWord64, rWord32); | 
|  | 248   r.CheckTypeError(rWord32, rWord64); | 
|  | 249   r.CheckTypeError(rWord64, rWord32 | tInt32); | 
|  | 250   r.CheckTypeError(rWord32 | tInt32, rWord64); | 
|  | 251   r.CheckTypeError(rWord64, rWord32 | tUint32); | 
|  | 252   r.CheckTypeError(rWord32 | tUint32, rWord64); | 
|  | 253 | 
|  | 254   for (size_t i = 0; i < ARRAY_SIZE(all_reps); i++) { | 
|  | 255     for (size_t j = 0; j < ARRAY_SIZE(all_reps); j++) { | 
|  | 256       if (i == j) continue; | 
|  | 257       // Only a single from representation is allowed. | 
|  | 258       r.CheckTypeError(all_reps[i] | all_reps[j], rTagged); | 
|  | 259     } | 
|  | 260   } | 
|  | 261 } | 
|  | 262 | 
|  | 263 | 
|  | 264 TEST(CompleteMatrix) { | 
|  | 265   // TODO(titzer): test all variants in the matrix. | 
|  | 266   // rB | 
|  | 267   // tBrB | 
|  | 268   // tBrT | 
|  | 269   // rW32 | 
|  | 270   // tIrW32 | 
|  | 271   // tUrW32 | 
|  | 272   // rW64 | 
|  | 273   // tIrW64 | 
|  | 274   // tUrW64 | 
|  | 275   // rF64 | 
|  | 276   // tIrF64 | 
|  | 277   // tUrF64 | 
|  | 278   // tArF64 | 
|  | 279   // rT | 
|  | 280   // tArT | 
|  | 281 } | 
| OLD | NEW | 
|---|