OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler/machine-operator-reducer.h" | 5 #include "src/compiler/machine-operator-reducer.h" |
6 | 6 |
7 #include "src/base/bits.h" | 7 #include "src/base/bits.h" |
8 #include "src/base/division-by-constant.h" | 8 #include "src/base/division-by-constant.h" |
9 #include "src/codegen.h" | 9 #include "src/codegen.h" |
10 #include "src/compiler/diamond.h" | 10 #include "src/compiler/diamond.h" |
(...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
343 NodeProperties::ChangeOp(node, machine()->Float64Sub()); | 343 NodeProperties::ChangeOp(node, machine()->Float64Sub()); |
344 return Changed(node); | 344 return Changed(node); |
345 } | 345 } |
346 if (m.right().Is(1)) return Replace(m.left().node()); // x * 1.0 => x | 346 if (m.right().Is(1)) return Replace(m.left().node()); // x * 1.0 => x |
347 if (m.right().IsNaN()) { // x * NaN => NaN | 347 if (m.right().IsNaN()) { // x * NaN => NaN |
348 return Replace(m.right().node()); | 348 return Replace(m.right().node()); |
349 } | 349 } |
350 if (m.IsFoldable()) { // K * K => K | 350 if (m.IsFoldable()) { // K * K => K |
351 return ReplaceFloat64(m.left().Value() * m.right().Value()); | 351 return ReplaceFloat64(m.left().Value() * m.right().Value()); |
352 } | 352 } |
353 return ReduceFloat52Mul(node); | 353 break; |
354 } | 354 } |
355 case IrOpcode::kFloat64Div: { | 355 case IrOpcode::kFloat64Div: { |
356 Float64BinopMatcher m(node); | 356 Float64BinopMatcher m(node); |
357 if (m.right().Is(1)) return Replace(m.left().node()); // x / 1.0 => x | 357 if (m.right().Is(1)) return Replace(m.left().node()); // x / 1.0 => x |
358 if (m.right().IsNaN()) { // x / NaN => NaN | 358 if (m.right().IsNaN()) { // x / NaN => NaN |
359 return Replace(m.right().node()); | 359 return Replace(m.right().node()); |
360 } | 360 } |
361 if (m.left().IsNaN()) { // NaN / x => NaN | 361 if (m.left().IsNaN()) { // NaN / x => NaN |
362 return Replace(m.left().node()); | 362 return Replace(m.left().node()); |
363 } | 363 } |
364 if (m.IsFoldable()) { // K / K => K | 364 if (m.IsFoldable()) { // K / K => K |
365 return ReplaceFloat64(m.left().Value() / m.right().Value()); | 365 return ReplaceFloat64(m.left().Value() / m.right().Value()); |
366 } | 366 } |
367 return ReduceFloat52Div(node); | 367 break; |
368 } | 368 } |
369 case IrOpcode::kFloat64Mod: { | 369 case IrOpcode::kFloat64Mod: { |
370 Float64BinopMatcher m(node); | 370 Float64BinopMatcher m(node); |
371 if (m.right().Is(0)) { // x % 0 => NaN | 371 if (m.right().Is(0)) { // x % 0 => NaN |
372 return ReplaceFloat64(std::numeric_limits<double>::quiet_NaN()); | 372 return ReplaceFloat64(std::numeric_limits<double>::quiet_NaN()); |
373 } | 373 } |
374 if (m.right().IsNaN()) { // x % NaN => NaN | 374 if (m.right().IsNaN()) { // x % NaN => NaN |
375 return Replace(m.right().node()); | 375 return Replace(m.right().node()); |
376 } | 376 } |
377 if (m.left().IsNaN()) { // NaN % x => NaN | 377 if (m.left().IsNaN()) { // NaN % x => NaN |
(...skipping 695 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1073 node->ReplaceInput( | 1073 node->ReplaceInput( |
1074 1, m.right().HasValue() | 1074 1, m.right().HasValue() |
1075 ? Float32Constant(static_cast<float>(m.right().Value())) | 1075 ? Float32Constant(static_cast<float>(m.right().Value())) |
1076 : m.right().InputAt(0)); | 1076 : m.right().InputAt(0)); |
1077 return Changed(node); | 1077 return Changed(node); |
1078 } | 1078 } |
1079 return NoChange(); | 1079 return NoChange(); |
1080 } | 1080 } |
1081 | 1081 |
1082 | 1082 |
1083 Reduction MachineOperatorReducer::ReduceFloat52Mul(Node* node) { | |
1084 if (!machine()->Is64()) return NoChange(); | |
1085 | |
1086 Float64BinopMatcher m(node); | |
1087 if (!m.left().IsChangeInt32ToFloat64() || | |
1088 !m.right().IsChangeInt32ToFloat64()) { | |
1089 return NoChange(); | |
1090 } | |
1091 | |
1092 Type* type = NodeProperties::GetType(node); | |
1093 Type::RangeType* range = type->GetRange(); | |
1094 | |
1095 // JavaScript has 52 bit precision in multiplication | |
1096 if (range == nullptr || range->Min() < 0.0 || | |
1097 range->Max() > 0xFFFFFFFFFFFFFULL) { | |
1098 return NoChange(); | |
1099 } | |
1100 | |
1101 Node* mul = graph()->NewNode(machine()->Int64Mul(), m.left().InputAt(0), | |
1102 m.right().InputAt(0)); | |
1103 | |
1104 Type* range_type = Type::Range(range->Min(), range->Max(), graph()->zone()); | |
1105 | |
1106 // TODO(indutny): Is Type::Number() a proper thing here? It looks like | |
1107 // every other place is using Type:Internal() for int64 values. | |
1108 // Should we off-load range propagation to Typer? | |
1109 NodeProperties::SetType( | |
1110 mul, Type::Intersect(range_type, Type::Number(), graph()->zone())); | |
1111 | |
1112 Node* out = graph()->NewNode(machine()->RoundInt64ToFloat64(), mul); | |
1113 return Replace(out); | |
1114 } | |
1115 | |
1116 | |
1117 Reduction MachineOperatorReducer::ReduceFloat52Div(Node* node) { | |
1118 if (!machine()->Is64()) return NoChange(); | |
1119 | |
1120 Float64BinopMatcher m(node); | |
1121 if (!m.left().IsRoundInt64ToFloat64()) return NoChange(); | |
1122 | |
1123 // Right value should be positive... | |
1124 if (!m.right().HasValue() || m.right().Value() <= 0) return NoChange(); | |
1125 | |
1126 // ...integer... | |
1127 int64_t value = static_cast<int64_t>(m.right().Value()); | |
1128 if (value != static_cast<int64_t>(m.right().Value())) return NoChange(); | |
1129 | |
1130 // ...and should be a power of two. | |
1131 if (!base::bits::IsPowerOfTwo64(value)) return NoChange(); | |
1132 | |
1133 Node* left = m.left().InputAt(0); | |
1134 Type::RangeType* range = NodeProperties::GetType(left)->GetRange(); | |
1135 | |
1136 // The RoundInt64ToFloat64 input should fit into 52bit integer | |
1137 if (range == nullptr || range->Min() < 0 || | |
1138 range->Max() > 0xFFFFFFFFFFFFFULL) { | |
1139 return NoChange(); | |
1140 } | |
1141 | |
1142 // The result should fit into 32bit word | |
1143 int64_t min = static_cast<int64_t>(range->Min()) / value; | |
1144 int64_t max = static_cast<int64_t>(range->Max()) / value; | |
1145 if (min < 0 || max > 0xFFFFFFFLL) { | |
1146 return NoChange(); | |
1147 } | |
1148 | |
1149 int64_t shift = WhichPowerOf2_64(static_cast<int64_t>(m.right().Value())); | |
1150 | |
1151 // Replace division with 64bit right shift | |
1152 Node* shr = | |
1153 graph()->NewNode(machine()->Word64Shr(), left, | |
1154 graph()->NewNode(common()->Int64Constant(shift))); | |
1155 | |
1156 Type* range_type = Type::Range(min, max, graph()->zone()); | |
1157 NodeProperties::SetType( | |
1158 shr, Type::Intersect(range_type, Type::Number(), graph()->zone())); | |
1159 | |
1160 Node* out = graph()->NewNode(machine()->RoundInt64ToFloat64(), shr); | |
1161 return Replace(out); | |
1162 } | |
1163 | |
1164 | |
1165 CommonOperatorBuilder* MachineOperatorReducer::common() const { | 1083 CommonOperatorBuilder* MachineOperatorReducer::common() const { |
1166 return jsgraph()->common(); | 1084 return jsgraph()->common(); |
1167 } | 1085 } |
1168 | 1086 |
1169 | 1087 |
1170 MachineOperatorBuilder* MachineOperatorReducer::machine() const { | 1088 MachineOperatorBuilder* MachineOperatorReducer::machine() const { |
1171 return jsgraph()->machine(); | 1089 return jsgraph()->machine(); |
1172 } | 1090 } |
1173 | 1091 |
1174 | 1092 |
1175 Graph* MachineOperatorReducer::graph() const { return jsgraph()->graph(); } | 1093 Graph* MachineOperatorReducer::graph() const { return jsgraph()->graph(); } |
1176 | 1094 |
1177 } // namespace compiler | 1095 } // namespace compiler |
1178 } // namespace internal | 1096 } // namespace internal |
1179 } // namespace v8 | 1097 } // namespace v8 |
OLD | NEW |