Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/intermediate_language.h" | 5 #include "vm/intermediate_language.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/cpu.h" | 8 #include "vm/cpu.h" |
| 9 #include "vm/dart_entry.h" | 9 #include "vm/dart_entry.h" |
| 10 #include "vm/flow_graph_allocator.h" | 10 #include "vm/flow_graph_allocator.h" |
| (...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 295 | 295 |
| 296 | 296 |
| 297 bool MathMinMaxInstr::AttributesEqual(Instruction* other) const { | 297 bool MathMinMaxInstr::AttributesEqual(Instruction* other) const { |
| 298 MathMinMaxInstr* other_op = other->AsMathMinMax(); | 298 MathMinMaxInstr* other_op = other->AsMathMinMax(); |
| 299 ASSERT(other_op != NULL); | 299 ASSERT(other_op != NULL); |
| 300 return (op_kind() == other_op->op_kind()) && | 300 return (op_kind() == other_op->op_kind()) && |
| 301 (result_cid() == other_op->result_cid()); | 301 (result_cid() == other_op->result_cid()); |
| 302 } | 302 } |
| 303 | 303 |
| 304 | 304 |
| 305 bool BinarySmiOpInstr::AttributesEqual(Instruction* other) const { | 305 bool BinaryIntegerOpInstr::AttributesEqual(Instruction* other) const { |
| 306 BinarySmiOpInstr* other_op = other->AsBinarySmiOp(); | 306 ASSERT(other->tag() == tag()); |
| 307 ASSERT(other_op != NULL); | 307 BinaryIntegerOpInstr* other_op = static_cast<BinaryIntegerOpInstr*>(other); |
|
srdjan
2014/09/11 17:38:11
other->AsBinary... ?
| |
| 308 return (op_kind() == other_op->op_kind()) && | 308 return (op_kind() == other_op->op_kind()) && |
| 309 (overflow_ == other_op->overflow_) && | 309 (can_overflow() == other_op->can_overflow()) && |
| 310 (is_truncating_ == other_op->is_truncating_); | 310 (is_truncating() == other_op->is_truncating()); |
| 311 } | 311 } |
| 312 | 312 |
| 313 | 313 |
| 314 bool BinaryInt32OpInstr::AttributesEqual(Instruction* other) const { | |
| 315 BinaryInt32OpInstr* other_op = other->AsBinaryInt32Op(); | |
| 316 ASSERT(other_op != NULL); | |
| 317 return (op_kind() == other_op->op_kind()) && | |
| 318 (overflow_ == other_op->overflow_) && | |
| 319 (is_truncating_ == other_op->is_truncating_); | |
| 320 } | |
| 321 | |
| 322 | |
| 323 EffectSet LoadFieldInstr::Dependencies() const { | 314 EffectSet LoadFieldInstr::Dependencies() const { |
| 324 return immutable_ ? EffectSet::None() : EffectSet::All(); | 315 return immutable_ ? EffectSet::None() : EffectSet::All(); |
| 325 } | 316 } |
| 326 | 317 |
| 327 | 318 |
| 328 bool LoadFieldInstr::AttributesEqual(Instruction* other) const { | 319 bool LoadFieldInstr::AttributesEqual(Instruction* other) const { |
| 329 LoadFieldInstr* other_load = other->AsLoadField(); | 320 LoadFieldInstr* other_load = other->AsLoadField(); |
| 330 ASSERT(other_load != NULL); | 321 ASSERT(other_load != NULL); |
| 331 if (field() != NULL) { | 322 if (field() != NULL) { |
| 332 return (other_load->field() != NULL) && | 323 return (other_load->field() != NULL) && |
| (...skipping 869 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1202 return false; | 1193 return false; |
| 1203 | 1194 |
| 1204 case Token::kSHL: | 1195 case Token::kSHL: |
| 1205 return true; | 1196 return true; |
| 1206 | 1197 |
| 1207 case Token::kMOD: { | 1198 case Token::kMOD: { |
| 1208 UNREACHABLE(); | 1199 UNREACHABLE(); |
| 1209 } | 1200 } |
| 1210 | 1201 |
| 1211 default: | 1202 default: |
| 1212 return overflow_; | 1203 return can_overflow(); |
| 1213 } | 1204 } |
| 1214 } | 1205 } |
| 1215 | 1206 |
| 1216 | 1207 |
| 1217 bool BinarySmiOpInstr::CanDeoptimize() const { | 1208 bool BinarySmiOpInstr::CanDeoptimize() const { |
| 1218 if (FLAG_throw_on_javascript_int_overflow && (Smi::kBits > 32)) { | 1209 if (FLAG_throw_on_javascript_int_overflow && (Smi::kBits > 32)) { |
| 1219 // If Smi's are bigger than 32-bits, then the instruction could deoptimize | 1210 // If Smi's are bigger than 32-bits, then the instruction could deoptimize |
| 1220 // if the result is too big. | 1211 // if the result is too big. |
| 1221 return true; | 1212 return true; |
| 1222 } | 1213 } |
| 1223 switch (op_kind()) { | 1214 switch (op_kind()) { |
| 1224 case Token::kBIT_AND: | 1215 case Token::kBIT_AND: |
| 1225 case Token::kBIT_OR: | 1216 case Token::kBIT_OR: |
| 1226 case Token::kBIT_XOR: | 1217 case Token::kBIT_XOR: |
| 1227 return false; | 1218 return false; |
| 1228 case Token::kSHR: { | 1219 case Token::kSHR: { |
| 1229 // Can't deopt if shift-count is known positive. | 1220 // Can't deopt if shift-count is known positive. |
| 1230 Range* right_range = this->right()->definition()->range(); | 1221 Range* right_range = this->right()->definition()->range(); |
| 1231 return (right_range == NULL) || !right_range->IsPositive(); | 1222 return (right_range == NULL) || !right_range->IsPositive(); |
| 1232 } | 1223 } |
| 1233 case Token::kSHL: { | 1224 case Token::kSHL: { |
| 1234 Range* right_range = this->right()->definition()->range(); | 1225 Range* right_range = this->right()->definition()->range(); |
| 1235 if ((right_range != NULL) && IsTruncating()) { | 1226 if ((right_range != NULL) && !can_overflow()) { |
| 1236 // Can deoptimize if right can be negative. | 1227 // Can deoptimize if right can be negative. |
| 1237 return !right_range->IsPositive(); | 1228 return !right_range->IsPositive(); |
| 1238 } | 1229 } |
| 1239 return true; | 1230 return true; |
| 1240 } | 1231 } |
| 1241 case Token::kMOD: { | 1232 case Token::kMOD: { |
| 1242 Range* right_range = this->right()->definition()->range(); | 1233 Range* right_range = this->right()->definition()->range(); |
| 1243 return (right_range == NULL) || right_range->Overlaps(0, 0); | 1234 return (right_range == NULL) || right_range->Overlaps(0, 0); |
| 1244 } | 1235 } |
| 1245 default: | 1236 default: |
| 1246 return overflow_; | 1237 return can_overflow(); |
| 1247 } | 1238 } |
| 1248 } | 1239 } |
| 1249 | 1240 |
| 1250 | 1241 |
| 1251 bool BinarySmiOpInstr::RightIsPowerOfTwoConstant() const { | 1242 bool BinaryIntegerOpInstr::RightIsPowerOfTwoConstant() const { |
| 1252 if (!right()->definition()->IsConstant()) return false; | 1243 if (!right()->definition()->IsConstant()) return false; |
| 1253 const Object& constant = right()->definition()->AsConstant()->value(); | 1244 const Object& constant = right()->definition()->AsConstant()->value(); |
| 1254 if (!constant.IsSmi()) return false; | 1245 if (!constant.IsSmi()) return false; |
| 1255 const intptr_t int_value = Smi::Cast(constant).Value(); | 1246 const intptr_t int_value = Smi::Cast(constant).Value(); |
| 1256 return Utils::IsPowerOfTwo(Utils::Abs(int_value)); | 1247 return Utils::IsPowerOfTwo(Utils::Abs(int_value)); |
| 1257 } | 1248 } |
| 1258 | 1249 |
| 1259 | 1250 |
| 1251 | |
|
srdjan
2014/09/11 17:38:11
Two lines instead of three
| |
| 1260 static bool ToIntegerConstant(Value* value, int64_t* result) { | 1252 static bool ToIntegerConstant(Value* value, int64_t* result) { |
| 1261 if (!value->BindsToConstant()) { | 1253 if (!value->BindsToConstant()) { |
| 1262 if (value->definition()->IsUnboxDouble()) { | 1254 if (value->definition()->IsUnboxDouble()) { |
| 1263 return ToIntegerConstant(value->definition()->AsUnboxDouble()->value(), | 1255 return ToIntegerConstant(value->definition()->AsUnboxDouble()->value(), |
| 1264 result); | 1256 result); |
| 1265 } | 1257 } |
| 1266 return false; | 1258 return false; |
| 1267 } | 1259 } |
| 1268 | 1260 |
| 1269 const Object& constant = value->BoundConstant(); | 1261 const Object& constant = value->BoundConstant(); |
| 1270 if (constant.IsDouble()) { | 1262 if (constant.IsDouble()) { |
| 1271 const Double& double_constant = Double::Cast(constant); | 1263 const Double& double_constant = Double::Cast(constant); |
| 1272 *result = static_cast<int64_t>(double_constant.value()); | 1264 *result = static_cast<int64_t>(double_constant.value()); |
| 1273 return (static_cast<double>(*result) == double_constant.value()); | 1265 return (static_cast<double>(*result) == double_constant.value()); |
| 1274 } else if (constant.IsSmi()) { | 1266 } else if (constant.IsSmi()) { |
| 1275 *result = Smi::Cast(constant).Value(); | 1267 *result = Smi::Cast(constant).Value(); |
| 1276 return true; | 1268 return true; |
| 1277 } else if (constant.IsMint()) { | 1269 } else if (constant.IsMint()) { |
| 1278 *result = Mint::Cast(constant).value(); | 1270 *result = Mint::Cast(constant).value(); |
| 1279 return true; | 1271 return true; |
| 1280 } | 1272 } |
| 1281 | 1273 |
| 1282 return false; | 1274 return false; |
| 1283 } | 1275 } |
| 1284 | 1276 |
| 1285 | 1277 |
| 1286 static Definition* CanonicalizeCommutativeArithmetic( | 1278 static Definition* CanonicalizeCommutativeDoubleArithmetic( |
| 1287 Token::Kind op, | 1279 Token::Kind op, |
| 1288 intptr_t cid, | |
| 1289 Value* left, | 1280 Value* left, |
| 1290 Value* right, | 1281 Value* right) { |
| 1291 int64_t mask = static_cast<int64_t>(0xFFFFFFFFFFFFFFFFLL)) { | |
| 1292 ASSERT((cid == kSmiCid) || (cid == kDoubleCid) || (cid == kMintCid)); | |
| 1293 | |
| 1294 int64_t left_value; | 1282 int64_t left_value; |
| 1295 if (!ToIntegerConstant(left, &left_value)) { | 1283 if (!ToIntegerConstant(left, &left_value)) { |
| 1296 return NULL; | 1284 return NULL; |
| 1297 } | 1285 } |
| 1298 | 1286 |
| 1299 // Apply truncation mask to left_value. | 1287 // Can't apply 0.0 * x -> 0.0 equivalence to double operation because |
| 1300 left_value &= mask; | 1288 // 0.0 * NaN is NaN not 0.0. |
| 1301 | 1289 // Can't apply 0.0 + x -> x to double because 0.0 + (-0.0) is 0.0 not -0.0. |
| 1302 switch (op) { | 1290 switch (op) { |
| 1303 case Token::kMUL: | 1291 case Token::kMUL: |
| 1304 if (left_value == 1) { | 1292 if (left_value == 1) { |
| 1305 if ((cid == kDoubleCid) && | 1293 if (right->definition()->representation() != kUnboxedDouble) { |
| 1306 (right->definition()->representation() != kUnboxedDouble)) { | |
| 1307 // Can't yet apply the equivalence because representation selection | 1294 // Can't yet apply the equivalence because representation selection |
| 1308 // did not run yet. We need it to guarantee that right value is | 1295 // did not run yet. We need it to guarantee that right value is |
| 1309 // correctly coerced to double. The second canonicalization pass | 1296 // correctly coerced to double. The second canonicalization pass |
| 1310 // will apply this equivalence. | 1297 // will apply this equivalence. |
| 1311 return NULL; | 1298 return NULL; |
| 1312 } else { | 1299 } else { |
| 1313 return right->definition(); | 1300 return right->definition(); |
| 1314 } | 1301 } |
| 1315 } else if ((left_value == 0) && (cid != kDoubleCid)) { | |
| 1316 // Can't apply this equivalence to double operation because | |
| 1317 // 0.0 * NaN is NaN not 0.0. | |
| 1318 return left->definition(); | |
| 1319 } | |
| 1320 break; | |
| 1321 case Token::kADD: | |
| 1322 if ((left_value == 0) && (cid != kDoubleCid)) { | |
| 1323 // Can't apply this equivalence to double operations because | |
| 1324 // 0.0 + (-0.0) is 0.0 not -0.0. | |
| 1325 return right->definition(); | |
| 1326 } | |
| 1327 break; | |
| 1328 case Token::kBIT_AND: | |
| 1329 ASSERT(cid != kDoubleCid); | |
| 1330 if (left_value == 0) { | |
| 1331 return left->definition(); | |
| 1332 } else if (left_value == mask) { | |
| 1333 return right->definition(); | |
| 1334 } | |
| 1335 break; | |
| 1336 case Token::kBIT_OR: | |
| 1337 ASSERT(cid != kDoubleCid); | |
| 1338 if (left_value == 0) { | |
| 1339 return right->definition(); | |
| 1340 } else if (left_value == mask) { | |
| 1341 return left->definition(); | |
| 1342 } | |
| 1343 break; | |
| 1344 case Token::kBIT_XOR: | |
| 1345 ASSERT(cid != kDoubleCid); | |
| 1346 if (left_value == 0) { | |
| 1347 return right->definition(); | |
| 1348 } | 1302 } |
| 1349 break; | 1303 break; |
| 1350 default: | 1304 default: |
| 1351 break; | 1305 break; |
| 1352 } | 1306 } |
| 1353 | 1307 |
| 1354 return NULL; | 1308 return NULL; |
| 1355 } | 1309 } |
| 1356 | 1310 |
| 1357 | 1311 |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 1382 Definition* FloatToDoubleInstr::Canonicalize(FlowGraph* flow_graph) { | 1336 Definition* FloatToDoubleInstr::Canonicalize(FlowGraph* flow_graph) { |
| 1383 return HasUses() ? this : NULL; | 1337 return HasUses() ? this : NULL; |
| 1384 } | 1338 } |
| 1385 | 1339 |
| 1386 | 1340 |
| 1387 Definition* BinaryDoubleOpInstr::Canonicalize(FlowGraph* flow_graph) { | 1341 Definition* BinaryDoubleOpInstr::Canonicalize(FlowGraph* flow_graph) { |
| 1388 if (!HasUses()) return NULL; | 1342 if (!HasUses()) return NULL; |
| 1389 | 1343 |
| 1390 Definition* result = NULL; | 1344 Definition* result = NULL; |
| 1391 | 1345 |
| 1392 result = CanonicalizeCommutativeArithmetic(op_kind(), | 1346 result = CanonicalizeCommutativeDoubleArithmetic(op_kind(), left(), right()); |
| 1393 kDoubleCid, | |
| 1394 left(), | |
| 1395 right()); | |
| 1396 if (result == NULL) { | |
| 1397 result = CanonicalizeCommutativeArithmetic(op_kind(), | |
| 1398 kDoubleCid, | |
| 1399 right(), | |
| 1400 left()); | |
| 1401 } | |
| 1402 if (result != NULL) { | 1347 if (result != NULL) { |
| 1403 return result; | 1348 return result; |
| 1404 } | 1349 } |
| 1350 | |
| 1351 result = CanonicalizeCommutativeDoubleArithmetic(op_kind(), right(), left()); | |
| 1352 if (result != NULL) { | |
| 1353 return result; | |
| 1354 } | |
| 1405 | 1355 |
| 1406 if ((op_kind() == Token::kMUL) && | 1356 if ((op_kind() == Token::kMUL) && |
| 1407 (left()->definition() == right()->definition())) { | 1357 (left()->definition() == right()->definition())) { |
| 1408 MathUnaryInstr* math_unary = | 1358 MathUnaryInstr* math_unary = |
| 1409 new MathUnaryInstr(MathUnaryInstr::kDoubleSquare, | 1359 new MathUnaryInstr(MathUnaryInstr::kDoubleSquare, |
| 1410 new Value(left()->definition()), | 1360 new Value(left()->definition()), |
| 1411 DeoptimizationTarget()); | 1361 DeoptimizationTarget()); |
| 1412 flow_graph->InsertBefore(this, math_unary, env(), FlowGraph::kValue); | 1362 flow_graph->InsertBefore(this, math_unary, env(), FlowGraph::kValue); |
| 1413 return math_unary; | 1363 return math_unary; |
| 1414 } | 1364 } |
| 1415 | 1365 |
| 1416 return this; | 1366 return this; |
| 1417 } | 1367 } |
| 1418 | 1368 |
| 1419 | 1369 |
| 1420 Definition* BinarySmiOpInstr::Canonicalize(FlowGraph* flow_graph) { | 1370 static bool IsCommutative(Token::Kind op) { |
| 1421 Definition* result = NULL; | 1371 switch (op) { |
| 1422 | 1372 case Token::kMUL: |
| 1423 result = CanonicalizeCommutativeArithmetic(op_kind(), | 1373 case Token::kADD: |
| 1424 kSmiCid, | 1374 case Token::kBIT_AND: |
| 1425 left(), | 1375 case Token::kBIT_OR: |
| 1426 right()); | 1376 case Token::kBIT_XOR: |
| 1427 if (result != NULL) { | 1377 return true; |
| 1428 return result; | 1378 default: |
| 1429 } | 1379 return false; |
| 1430 | 1380 } |
| 1431 result = CanonicalizeCommutativeArithmetic(op_kind(), | 1381 } |
| 1432 kSmiCid, | 1382 |
| 1433 right(), | 1383 |
| 1434 left()); | 1384 static intptr_t RepresentationBits(Representation r) { |
| 1435 if (result != NULL) { | 1385 switch (r) { |
| 1436 return result; | 1386 case kTagged: |
| 1387 return kBitsPerWord - 1; | |
| 1388 case kUnboxedInt32: | |
| 1389 case kUnboxedUint32: | |
| 1390 return 32; | |
| 1391 case kUnboxedMint: | |
| 1392 return 64; | |
| 1393 default: | |
| 1394 UNREACHABLE(); | |
| 1395 return 0; | |
| 1396 } | |
| 1397 } | |
| 1398 | |
| 1399 | |
| 1400 static int64_t RepresentationMask(Representation r) { | |
| 1401 return static_cast<int64_t>( | |
| 1402 static_cast<uint64_t>(-1) >> (64 - RepresentationBits(r))); | |
|
srdjan
2014/09/11 17:38:11
4 spaces indent
| |
| 1403 } | |
| 1404 | |
| 1405 | |
| 1406 UnaryIntegerOpInstr* UnaryIntegerOpInstr::Make(Representation representation, | |
| 1407 Token::Kind op_kind, | |
| 1408 Value* value, | |
| 1409 intptr_t deopt_id, | |
| 1410 Range* range) { | |
| 1411 UnaryIntegerOpInstr* op = NULL; | |
| 1412 switch (representation) { | |
| 1413 case kTagged: | |
| 1414 op = new UnarySmiOpInstr(op_kind, value, deopt_id); | |
| 1415 break; | |
| 1416 | |
|
Cutch
2014/09/11 17:41:53
remove blank lines
| |
| 1417 case kUnboxedInt32: | |
| 1418 return NULL; | |
| 1419 | |
| 1420 case kUnboxedUint32: | |
| 1421 op = new UnaryUint32OpInstr(op_kind, value, deopt_id); | |
| 1422 break; | |
| 1423 | |
| 1424 case kUnboxedMint: | |
| 1425 op = new UnaryMintOpInstr(op_kind, value, deopt_id); | |
| 1426 break; | |
| 1427 | |
| 1428 default: | |
| 1429 UNREACHABLE(); | |
| 1430 return NULL; | |
| 1431 } | |
| 1432 | |
| 1433 if (op == NULL) { | |
| 1434 return op; | |
| 1435 } | |
|
srdjan
2014/09/11 17:38:11
Instead you could add return NULL to default (remo
Vyacheslav Egorov (Google)
2014/09/11 19:50:47
I would like to ensure that we don't forget to upd
| |
| 1436 | |
| 1437 if (!Range::IsUnknown(range)) { | |
| 1438 op->set_range(*range); | |
| 1439 } | |
| 1440 | |
| 1441 ASSERT(op->representation() == representation); | |
| 1442 return op; | |
| 1443 } | |
| 1444 | |
| 1445 | |
| 1446 BinaryIntegerOpInstr* BinaryIntegerOpInstr::Make(Representation representation, | |
| 1447 Token::Kind op_kind, | |
| 1448 Value* left, | |
| 1449 Value* right, | |
| 1450 intptr_t deopt_id, | |
| 1451 bool can_overflow, | |
| 1452 bool is_truncating, | |
| 1453 Range* range) { | |
| 1454 BinaryIntegerOpInstr* op = NULL; | |
| 1455 switch (representation) { | |
| 1456 case kTagged: | |
| 1457 op = new BinarySmiOpInstr(op_kind, left, right, deopt_id); | |
| 1458 break; | |
| 1459 | |
|
Cutch
2014/09/11 17:41:53
ditto
| |
| 1460 case kUnboxedInt32: | |
| 1461 if (!BinaryInt32OpInstr::IsSupported(op_kind, left, right)) { | |
| 1462 return NULL; | |
| 1463 } | |
| 1464 op = new BinaryInt32OpInstr(op_kind, left, right, deopt_id); | |
| 1465 break; | |
| 1466 | |
| 1467 case kUnboxedUint32: | |
| 1468 if ((op_kind == Token::kSHR) || (op_kind == Token::kSHL)) { | |
| 1469 op = new ShiftUint32OpInstr(op_kind, left, right, deopt_id); | |
| 1470 } else { | |
| 1471 op = new BinaryUint32OpInstr(op_kind, left, right, deopt_id); | |
| 1472 } | |
| 1473 break; | |
| 1474 | |
| 1475 case kUnboxedMint: | |
| 1476 if ((op_kind == Token::kSHR) || (op_kind == Token::kSHL)) { | |
| 1477 op = new ShiftMintOpInstr(op_kind, left, right, deopt_id); | |
| 1478 } else { | |
| 1479 op = new BinaryMintOpInstr(op_kind, left, right, deopt_id); | |
| 1480 } | |
| 1481 break; | |
| 1482 | |
| 1483 default: | |
| 1484 UNREACHABLE(); | |
| 1485 return NULL; | |
| 1486 } | |
| 1487 | |
| 1488 if (!Range::IsUnknown(range)) { | |
| 1489 op->set_range(*range); | |
| 1490 } | |
| 1491 | |
| 1492 op->set_can_overflow(can_overflow); | |
| 1493 if (is_truncating) { | |
| 1494 op->mark_truncating(); | |
| 1495 } | |
| 1496 | |
| 1497 ASSERT(op->representation() == representation); | |
| 1498 return op; | |
| 1499 } | |
| 1500 | |
| 1501 | |
| 1502 RawInteger* BinaryIntegerOpInstr::Evaluate(const Integer& left, | |
| 1503 const Integer& right) const { | |
| 1504 Integer& result = Integer::Handle(); | |
| 1505 | |
| 1506 switch (op_kind()) { | |
| 1507 case Token::kTRUNCDIV: | |
| 1508 case Token::kMOD: | |
| 1509 // Check right value for zero. | |
| 1510 if (right.AsInt64Value() == 0) { | |
| 1511 break; // Will throw. | |
| 1512 } | |
| 1513 // Fall through. | |
| 1514 case Token::kADD: | |
| 1515 case Token::kSUB: | |
| 1516 case Token::kMUL: { | |
| 1517 result = left.ArithmeticOp(op_kind(), right); | |
| 1518 break; | |
| 1519 } | |
| 1520 case Token::kSHL: | |
| 1521 case Token::kSHR: | |
| 1522 if (left.IsSmi() && right.IsSmi() && (Smi::Cast(right).Value() >= 0)) { | |
| 1523 result = Smi::Cast(left).ShiftOp(op_kind(), Smi::Cast(right)); | |
| 1524 } | |
| 1525 break; | |
| 1526 case Token::kBIT_AND: | |
| 1527 case Token::kBIT_OR: | |
| 1528 case Token::kBIT_XOR: { | |
| 1529 result = left.BitOp(op_kind(), right); | |
| 1530 break; | |
| 1531 } | |
| 1532 case Token::kDIV: | |
| 1533 break; | |
| 1534 default: | |
| 1535 UNREACHABLE(); | |
| 1536 } | |
| 1537 | |
| 1538 if (!result.IsNull()) { | |
| 1539 if (is_truncating()) { | |
| 1540 int64_t truncated = result.AsTruncatedInt64Value(); | |
| 1541 truncated &= RepresentationMask(representation()); | |
| 1542 result = Integer::New(truncated); | |
| 1543 } | |
| 1544 result ^= result.CheckAndCanonicalize(NULL); | |
| 1545 } | |
| 1546 | |
| 1547 return result.raw(); | |
| 1548 } | |
| 1549 | |
| 1550 | |
| 1551 Definition* BinaryIntegerOpInstr::Canonicalize(FlowGraph* flow_graph) { | |
| 1552 // If both operands are constants evaluate this expression. Might | |
| 1553 // occur due to load forwarding after constant propagation pass | |
| 1554 // have already been run. | |
| 1555 if (left()->BindsToConstant() && | |
| 1556 left()->BoundConstant().IsInteger() && | |
| 1557 right()->BindsToConstant() && | |
| 1558 right()->BoundConstant().IsInteger()) { | |
| 1559 const Integer& result = Integer::Handle( | |
| 1560 Evaluate(Integer::Cast(left()->BoundConstant()), | |
| 1561 Integer::Cast(right()->BoundConstant()))); | |
| 1562 if (!result.IsNull()) { | |
| 1563 return flow_graph->GetConstant(result); | |
| 1564 } | |
| 1565 } | |
| 1566 | |
| 1567 if (left()->BindsToConstant() && | |
| 1568 !right()->BindsToConstant() && | |
| 1569 IsCommutative(op_kind())) { | |
| 1570 Value* l = left(); | |
| 1571 Value* r = right(); | |
| 1572 SetInputAt(0, r); | |
| 1573 SetInputAt(1, l); | |
| 1574 } | |
| 1575 | |
| 1576 int64_t rhs; | |
| 1577 if (!ToIntegerConstant(right(), &rhs)) { | |
| 1578 return this; | |
| 1579 } | |
| 1580 | |
| 1581 const int64_t range_mask = RepresentationMask(representation()); | |
| 1582 if (is_truncating()) { | |
| 1583 switch (op_kind()) { | |
| 1584 case Token::kMUL: | |
| 1585 case Token::kSUB: | |
| 1586 case Token::kADD: | |
| 1587 case Token::kBIT_AND: | |
| 1588 case Token::kBIT_OR: | |
| 1589 case Token::kBIT_XOR: | |
| 1590 rhs = (rhs & range_mask); | |
| 1591 break; | |
| 1592 default: | |
| 1593 break; | |
| 1594 } | |
| 1595 } | |
| 1596 | |
| 1597 switch (op_kind()) { | |
| 1598 case Token::kMUL: | |
| 1599 if (rhs == 1) { | |
| 1600 return left()->definition(); | |
| 1601 } else if (rhs == 0) { | |
| 1602 return right()->definition(); | |
| 1603 } else if (rhs == 2) { | |
| 1604 ConstantInstr* constant_1 = | |
| 1605 flow_graph->GetConstant(Smi::Handle(Smi::New(1))); | |
| 1606 BinaryIntegerOpInstr* shift = | |
| 1607 BinaryIntegerOpInstr::Make(representation(), | |
| 1608 Token::kSHL, | |
| 1609 left()->CopyWithType(), | |
| 1610 new Value(constant_1), | |
| 1611 deopt_id_, | |
| 1612 can_overflow(), | |
| 1613 is_truncating(), | |
| 1614 range()); | |
| 1615 if (shift != NULL) { | |
| 1616 flow_graph->InsertBefore(this, shift, env(), FlowGraph::kValue); | |
| 1617 return shift; | |
| 1618 } | |
| 1619 } | |
| 1620 | |
| 1621 break; | |
| 1622 case Token::kADD: | |
| 1623 if (rhs == 0) { | |
| 1624 return left()->definition(); | |
| 1625 } | |
| 1626 break; | |
| 1627 case Token::kBIT_AND: | |
| 1628 if (rhs == 0) { | |
| 1629 return right()->definition(); | |
| 1630 } else if (rhs == range_mask) { | |
| 1631 return left()->definition(); | |
| 1632 } | |
| 1633 break; | |
| 1634 case Token::kBIT_OR: | |
| 1635 if (rhs == 0) { | |
| 1636 return left()->definition(); | |
| 1637 } else if (rhs == range_mask) { | |
| 1638 return right()->definition(); | |
| 1639 } | |
| 1640 break; | |
| 1641 case Token::kBIT_XOR: | |
| 1642 if (rhs == 0) { | |
| 1643 return left()->definition(); | |
| 1644 } else if (rhs == range_mask) { | |
| 1645 UnaryIntegerOpInstr* bit_not = | |
| 1646 UnaryIntegerOpInstr::Make(representation(), | |
| 1647 Token::kBIT_NOT, | |
| 1648 left()->CopyWithType(), | |
| 1649 deopt_id_, | |
| 1650 range()); | |
| 1651 if (bit_not != NULL) { | |
| 1652 flow_graph->InsertBefore(this, bit_not, env(), FlowGraph::kValue); | |
| 1653 return bit_not; | |
| 1654 } | |
| 1655 } | |
| 1656 break; | |
| 1657 | |
| 1658 case Token::kSUB: | |
| 1659 if (rhs == 0) { | |
| 1660 return left()->definition(); | |
| 1661 } | |
| 1662 break; | |
| 1663 | |
| 1664 case Token::kTRUNCDIV: | |
| 1665 if (rhs == 1) { | |
| 1666 return left()->definition(); | |
| 1667 } else if (rhs == -1) { | |
| 1668 UnaryIntegerOpInstr* negation = | |
| 1669 UnaryIntegerOpInstr::Make(representation(), | |
| 1670 Token::kNEGATE, | |
| 1671 left()->CopyWithType(), | |
| 1672 deopt_id_, | |
| 1673 range()); | |
| 1674 if (negation != NULL) { | |
| 1675 flow_graph->InsertBefore(this, negation, env(), FlowGraph::kValue); | |
| 1676 return negation; | |
| 1677 } | |
| 1678 } | |
| 1679 break; | |
| 1680 | |
| 1681 case Token::kSHR: | |
| 1682 if (rhs == 0) { | |
| 1683 return left()->definition(); | |
| 1684 } else if (rhs < 0) { | |
| 1685 DeoptimizeInstr* deopt = | |
| 1686 new DeoptimizeInstr(ICData::kDeoptBinarySmiOp, deopt_id_); | |
| 1687 flow_graph->InsertBefore(this, deopt, env(), FlowGraph::kEffect); | |
| 1688 return flow_graph->GetConstant(Smi::Handle(Smi::New(0))); | |
| 1689 } | |
| 1690 break; | |
| 1691 | |
| 1692 case Token::kSHL: { | |
| 1693 const intptr_t kMaxShift = RepresentationBits(representation()) - 1; | |
| 1694 if (rhs == 0) { | |
| 1695 return left()->definition(); | |
| 1696 } else if ((rhs < 0) || (rhs >= kMaxShift)) { | |
| 1697 if ((rhs < 0) || !is_truncating()) { | |
| 1698 DeoptimizeInstr* deopt = | |
| 1699 new DeoptimizeInstr(ICData::kDeoptBinarySmiOp, deopt_id_); | |
| 1700 flow_graph->InsertBefore(this, deopt, env(), FlowGraph::kEffect); | |
| 1701 } | |
| 1702 return flow_graph->GetConstant(Smi::Handle(Smi::New(0))); | |
| 1703 } | |
| 1704 break; | |
| 1705 } | |
| 1706 | |
| 1707 default: | |
| 1708 break; | |
| 1437 } | 1709 } |
| 1438 | 1710 |
| 1439 return this; | 1711 return this; |
| 1440 } | |
| 1441 | |
| 1442 | |
| 1443 Definition* BinaryMintOpInstr::Canonicalize(FlowGraph* flow_graph) { | |
| 1444 Definition* result = NULL; | |
| 1445 | |
| 1446 result = CanonicalizeCommutativeArithmetic(op_kind(), | |
| 1447 kMintCid, | |
| 1448 left(), | |
| 1449 right()); | |
| 1450 if (result != NULL) { | |
| 1451 return result; | |
| 1452 } | |
| 1453 | |
| 1454 result = CanonicalizeCommutativeArithmetic(op_kind(), | |
| 1455 kMintCid, | |
| 1456 right(), | |
| 1457 left()); | |
| 1458 if (result != NULL) { | |
| 1459 return result; | |
| 1460 } | |
| 1461 | |
| 1462 return this; | |
| 1463 } | |
| 1464 | |
| 1465 | |
| 1466 Definition* BinaryUint32OpInstr::Canonicalize(FlowGraph* flow_graph) { | |
| 1467 Definition* result = NULL; | |
| 1468 | |
| 1469 const int64_t truncation_mask = static_cast<int64_t>(0xFFFFFFFF); | |
| 1470 | |
| 1471 result = CanonicalizeCommutativeArithmetic(op_kind(), | |
| 1472 kMintCid, | |
| 1473 left(), | |
| 1474 right(), | |
| 1475 truncation_mask); | |
| 1476 if (result != NULL) { | |
| 1477 return result; | |
| 1478 } | |
| 1479 | |
| 1480 result = CanonicalizeCommutativeArithmetic(op_kind(), | |
| 1481 kMintCid, | |
| 1482 right(), | |
| 1483 left(), | |
| 1484 truncation_mask); | |
| 1485 if (result != NULL) { | |
| 1486 return result; | |
| 1487 } | |
| 1488 | |
| 1489 return this; | |
| 1490 } | |
| 1491 | |
| 1492 | |
| 1493 Definition* BinaryInt32OpInstr::Canonicalize(FlowGraph* flow_graph) { | |
| 1494 Definition* result = NULL; | |
| 1495 | |
| 1496 result = CanonicalizeCommutativeArithmetic(op_kind(), | |
| 1497 kSmiCid, | |
| 1498 left(), | |
| 1499 right()); | |
| 1500 if (result != NULL) { | |
| 1501 return result; | |
| 1502 } | |
| 1503 | |
| 1504 result = CanonicalizeCommutativeArithmetic(op_kind(), | |
| 1505 kSmiCid, | |
| 1506 right(), | |
| 1507 left()); | |
| 1508 if (result != NULL) { | |
| 1509 return result; | |
| 1510 } | |
| 1511 | |
| 1512 return this; | |
| 1513 } | 1712 } |
| 1514 | 1713 |
| 1515 | 1714 |
| 1516 // Optimizations that eliminate or simplify individual instructions. | 1715 // Optimizations that eliminate or simplify individual instructions. |
| 1517 Instruction* Instruction::Canonicalize(FlowGraph* flow_graph) { | 1716 Instruction* Instruction::Canonicalize(FlowGraph* flow_graph) { |
| 1518 return this; | 1717 return this; |
| 1519 } | 1718 } |
| 1520 | 1719 |
| 1521 | 1720 |
| 1522 Definition* Definition::Canonicalize(FlowGraph* flow_graph) { | 1721 Definition* Definition::Canonicalize(FlowGraph* flow_graph) { |
| (...skipping 1133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2656 void AssertAssignableInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2855 void AssertAssignableInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2657 compiler->GenerateAssertAssignable(token_pos(), | 2856 compiler->GenerateAssertAssignable(token_pos(), |
| 2658 deopt_id(), | 2857 deopt_id(), |
| 2659 dst_type(), | 2858 dst_type(), |
| 2660 dst_name(), | 2859 dst_name(), |
| 2661 locs()); | 2860 locs()); |
| 2662 ASSERT(locs()->in(0).reg() == locs()->out(0).reg()); | 2861 ASSERT(locs()->in(0).reg() == locs()->out(0).reg()); |
| 2663 } | 2862 } |
| 2664 | 2863 |
| 2665 | 2864 |
| 2865 LocationSummary* DeoptimizeInstr::MakeLocationSummary(Isolate* isolate, | |
| 2866 bool opt) const { | |
| 2867 return new(isolate) LocationSummary(isolate, 0, 0, LocationSummary::kNoCall); | |
| 2868 } | |
| 2869 | |
| 2870 | |
| 2871 void DeoptimizeInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | |
| 2872 __ Jump(compiler->AddDeoptStub(deopt_id(), deopt_reason_)); | |
| 2873 } | |
| 2874 | |
| 2875 | |
| 2666 Environment* Environment::From(Isolate* isolate, | 2876 Environment* Environment::From(Isolate* isolate, |
| 2667 const GrowableArray<Definition*>& definitions, | 2877 const GrowableArray<Definition*>& definitions, |
| 2668 intptr_t fixed_parameter_count, | 2878 intptr_t fixed_parameter_count, |
| 2669 const ParsedFunction* parsed_function) { | 2879 const ParsedFunction* parsed_function) { |
| 2670 Environment* env = | 2880 Environment* env = |
| 2671 new(isolate) Environment(definitions.length(), | 2881 new(isolate) Environment(definitions.length(), |
| 2672 fixed_parameter_count, | 2882 fixed_parameter_count, |
| 2673 Isolate::kNoDeoptId, | 2883 Isolate::kNoDeoptId, |
| 2674 parsed_function, | 2884 parsed_function, |
| 2675 NULL); | 2885 NULL); |
| (...skipping 439 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3115 case Token::kTRUNCDIV: return 0; | 3325 case Token::kTRUNCDIV: return 0; |
| 3116 case Token::kMOD: return 1; | 3326 case Token::kMOD: return 1; |
| 3117 default: UNIMPLEMENTED(); return -1; | 3327 default: UNIMPLEMENTED(); return -1; |
| 3118 } | 3328 } |
| 3119 } | 3329 } |
| 3120 | 3330 |
| 3121 | 3331 |
| 3122 #undef __ | 3332 #undef __ |
| 3123 | 3333 |
| 3124 } // namespace dart | 3334 } // namespace dart |
| OLD | NEW |