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 |