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/bigint_operations.h" | 7 #include "vm/bigint_operations.h" |
8 #include "vm/bit_vector.h" | 8 #include "vm/bit_vector.h" |
9 #include "vm/cpu.h" | 9 #include "vm/cpu.h" |
10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
(...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
305 | 305 |
306 bool BinarySmiOpInstr::AttributesEqual(Instruction* other) const { | 306 bool BinarySmiOpInstr::AttributesEqual(Instruction* other) const { |
307 BinarySmiOpInstr* other_op = other->AsBinarySmiOp(); | 307 BinarySmiOpInstr* other_op = other->AsBinarySmiOp(); |
308 ASSERT(other_op != NULL); | 308 ASSERT(other_op != NULL); |
309 return (op_kind() == other_op->op_kind()) && | 309 return (op_kind() == other_op->op_kind()) && |
310 (overflow_ == other_op->overflow_) && | 310 (overflow_ == other_op->overflow_) && |
311 (is_truncating_ == other_op->is_truncating_); | 311 (is_truncating_ == other_op->is_truncating_); |
312 } | 312 } |
313 | 313 |
314 | 314 |
| 315 bool BinaryInt32OpInstr::AttributesEqual(Instruction* other) const { |
| 316 BinaryInt32OpInstr* other_op = other->AsBinaryInt32Op(); |
| 317 ASSERT(other_op != NULL); |
| 318 return (op_kind() == other_op->op_kind()) && |
| 319 (overflow_ == other_op->overflow_) && |
| 320 (is_truncating_ == other_op->is_truncating_); |
| 321 } |
| 322 |
| 323 |
315 EffectSet LoadFieldInstr::Dependencies() const { | 324 EffectSet LoadFieldInstr::Dependencies() const { |
316 return immutable_ ? EffectSet::None() : EffectSet::All(); | 325 return immutable_ ? EffectSet::None() : EffectSet::All(); |
317 } | 326 } |
318 | 327 |
319 | 328 |
320 bool LoadFieldInstr::AttributesEqual(Instruction* other) const { | 329 bool LoadFieldInstr::AttributesEqual(Instruction* other) const { |
321 LoadFieldInstr* other_load = other->AsLoadField(); | 330 LoadFieldInstr* other_load = other->AsLoadField(); |
322 ASSERT(other_load != NULL); | 331 ASSERT(other_load != NULL); |
323 if (field() != NULL) { | 332 if (field() != NULL) { |
324 return (other_load->field() != NULL) && | 333 return (other_load->field() != NULL) && |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
381 } | 390 } |
382 | 391 |
383 | 392 |
384 bool ConstantInstr::AttributesEqual(Instruction* other) const { | 393 bool ConstantInstr::AttributesEqual(Instruction* other) const { |
385 ConstantInstr* other_constant = other->AsConstant(); | 394 ConstantInstr* other_constant = other->AsConstant(); |
386 ASSERT(other_constant != NULL); | 395 ASSERT(other_constant != NULL); |
387 return (value().raw() == other_constant->value().raw()); | 396 return (value().raw() == other_constant->value().raw()); |
388 } | 397 } |
389 | 398 |
390 | 399 |
391 UnboxedConstantInstr::UnboxedConstantInstr(const Object& value) | 400 UnboxedConstantInstr::UnboxedConstantInstr(const Object& value, |
392 : ConstantInstr(value), constant_address_(0) { | 401 Representation representation) |
393 // Only doubles supported for now. | 402 : ConstantInstr(value), |
394 ASSERT(value.IsDouble()); | 403 representation_(representation), |
395 constant_address_ = | 404 constant_address_(0) { |
396 FlowGraphBuilder::FindDoubleConstant(Double::Cast(value).value()); | 405 if (representation_ == kUnboxedDouble) { |
| 406 ASSERT(value.IsDouble()); |
| 407 constant_address_ = |
| 408 FlowGraphBuilder::FindDoubleConstant(Double::Cast(value).value()); |
| 409 } |
397 } | 410 } |
398 | 411 |
399 | 412 |
400 bool Value::BindsTo32BitMaskConstant() const { | 413 bool Value::BindsTo32BitMaskConstant() const { |
401 if (!definition()->IsUnboxInteger() || !definition()->IsUnboxUint32()) { | 414 if (!definition()->IsUnboxInteger() || !definition()->IsUnboxUint32()) { |
402 return false; | 415 return false; |
403 } | 416 } |
404 // Two cases to consider: UnboxInteger and UnboxUint32. | 417 // Two cases to consider: UnboxInteger and UnboxUint32. |
405 if (definition()->IsUnboxInteger()) { | 418 if (definition()->IsUnboxInteger()) { |
406 UnboxIntegerInstr* instr = definition()->AsUnboxInteger(); | 419 UnboxIntegerInstr* instr = definition()->AsUnboxInteger(); |
(...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
671 } | 684 } |
672 | 685 |
673 set_previous_use(NULL); | 686 set_previous_use(NULL); |
674 set_next_use(NULL); | 687 set_next_use(NULL); |
675 } | 688 } |
676 | 689 |
677 | 690 |
678 // True if the definition has a single input use and is used only in | 691 // True if the definition has a single input use and is used only in |
679 // environments at the same instruction as that input use. | 692 // environments at the same instruction as that input use. |
680 bool Definition::HasOnlyUse(Value* use) const { | 693 bool Definition::HasOnlyUse(Value* use) const { |
681 if ((input_use_list() != use) || (use->next_use() != NULL)) return false; | 694 if (!HasOnlyInputUse(use)) { |
| 695 return false; |
| 696 } |
682 | 697 |
683 Instruction* target = use->instruction(); | 698 Instruction* target = use->instruction(); |
684 for (Value::Iterator it(env_use_list()); !it.Done(); it.Advance()) { | 699 for (Value::Iterator it(env_use_list()); !it.Done(); it.Advance()) { |
685 if (it.Current()->instruction() != target) return false; | 700 if (it.Current()->instruction() != target) return false; |
686 } | 701 } |
687 return true; | 702 return true; |
688 } | 703 } |
689 | 704 |
690 | 705 |
| 706 bool Definition::HasOnlyInputUse(Value* use) const { |
| 707 return (input_use_list() == use) && (use->next_use() == NULL); |
| 708 } |
| 709 |
| 710 |
691 void Definition::ReplaceUsesWith(Definition* other) { | 711 void Definition::ReplaceUsesWith(Definition* other) { |
692 ASSERT(other != NULL); | 712 ASSERT(other != NULL); |
693 ASSERT(this != other); | 713 ASSERT(this != other); |
694 | 714 |
695 Value* current = NULL; | 715 Value* current = NULL; |
696 Value* next = input_use_list(); | 716 Value* next = input_use_list(); |
697 if (next != NULL) { | 717 if (next != NULL) { |
698 // Change all the definitions. | 718 // Change all the definitions. |
699 while (next != NULL) { | 719 while (next != NULL) { |
700 current = next; | 720 current = next; |
(...skipping 441 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1142 ASSERT(index == 0); | 1162 ASSERT(index == 0); |
1143 return successor(); | 1163 return successor(); |
1144 } | 1164 } |
1145 | 1165 |
1146 | 1166 |
1147 void Instruction::Goto(JoinEntryInstr* entry) { | 1167 void Instruction::Goto(JoinEntryInstr* entry) { |
1148 LinkTo(new GotoInstr(entry)); | 1168 LinkTo(new GotoInstr(entry)); |
1149 } | 1169 } |
1150 | 1170 |
1151 | 1171 |
| 1172 bool UnboxedIntConverterInstr::CanDeoptimize() const { |
| 1173 return (to() == kUnboxedInt32) && |
| 1174 !Range::Fits(value()->definition()->range(), |
| 1175 RangeBoundary::kRangeBoundaryInt32); |
| 1176 } |
| 1177 |
| 1178 |
| 1179 bool UnboxInt32Instr::CanDeoptimize() const { |
| 1180 const intptr_t value_cid = value()->Type()->ToCid(); |
| 1181 if (value_cid == kSmiCid) { |
| 1182 return false; |
| 1183 } else if (value_cid == kMintCid) { |
| 1184 return !Range::Fits(value()->definition()->range(), |
| 1185 RangeBoundary::kRangeBoundaryInt32); |
| 1186 } else { |
| 1187 return true; |
| 1188 } |
| 1189 } |
| 1190 |
| 1191 |
| 1192 bool BinaryInt32OpInstr::CanDeoptimize() const { |
| 1193 switch (op_kind()) { |
| 1194 case Token::kBIT_AND: |
| 1195 case Token::kBIT_OR: |
| 1196 case Token::kBIT_XOR: |
| 1197 return false; |
| 1198 |
| 1199 case Token::kSHR: |
| 1200 return false; |
| 1201 |
| 1202 case Token::kSHL: |
| 1203 return true; |
| 1204 |
| 1205 case Token::kMOD: { |
| 1206 UNREACHABLE(); |
| 1207 } |
| 1208 |
| 1209 default: |
| 1210 return overflow_; |
| 1211 } |
| 1212 } |
| 1213 |
| 1214 |
1152 bool BinarySmiOpInstr::CanDeoptimize() const { | 1215 bool BinarySmiOpInstr::CanDeoptimize() const { |
1153 if (FLAG_throw_on_javascript_int_overflow && (Smi::kBits > 32)) { | 1216 if (FLAG_throw_on_javascript_int_overflow && (Smi::kBits > 32)) { |
1154 // If Smi's are bigger than 32-bits, then the instruction could deoptimize | 1217 // If Smi's are bigger than 32-bits, then the instruction could deoptimize |
1155 // if the result is too big. | 1218 // if the result is too big. |
1156 return true; | 1219 return true; |
1157 } | 1220 } |
1158 switch (op_kind()) { | 1221 switch (op_kind()) { |
1159 case Token::kBIT_AND: | 1222 case Token::kBIT_AND: |
1160 case Token::kBIT_OR: | 1223 case Token::kBIT_OR: |
1161 case Token::kBIT_XOR: | 1224 case Token::kBIT_XOR: |
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1418 left(), | 1481 left(), |
1419 truncation_mask); | 1482 truncation_mask); |
1420 if (result != NULL) { | 1483 if (result != NULL) { |
1421 return result; | 1484 return result; |
1422 } | 1485 } |
1423 | 1486 |
1424 return this; | 1487 return this; |
1425 } | 1488 } |
1426 | 1489 |
1427 | 1490 |
| 1491 Definition* BinaryInt32OpInstr::Canonicalize(FlowGraph* flow_graph) { |
| 1492 Definition* result = NULL; |
| 1493 |
| 1494 result = CanonicalizeCommutativeArithmetic(op_kind(), |
| 1495 kSmiCid, |
| 1496 left(), |
| 1497 right()); |
| 1498 if (result != NULL) { |
| 1499 return result; |
| 1500 } |
| 1501 |
| 1502 result = CanonicalizeCommutativeArithmetic(op_kind(), |
| 1503 kSmiCid, |
| 1504 right(), |
| 1505 left()); |
| 1506 if (result != NULL) { |
| 1507 return result; |
| 1508 } |
| 1509 |
| 1510 return this; |
| 1511 } |
| 1512 |
| 1513 |
1428 // Optimizations that eliminate or simplify individual instructions. | 1514 // Optimizations that eliminate or simplify individual instructions. |
1429 Instruction* Instruction::Canonicalize(FlowGraph* flow_graph) { | 1515 Instruction* Instruction::Canonicalize(FlowGraph* flow_graph) { |
1430 return this; | 1516 return this; |
1431 } | 1517 } |
1432 | 1518 |
1433 | 1519 |
1434 Definition* Definition::Canonicalize(FlowGraph* flow_graph) { | 1520 Definition* Definition::Canonicalize(FlowGraph* flow_graph) { |
1435 return this; | 1521 return this; |
1436 } | 1522 } |
1437 | 1523 |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1616 // Fold away BoxDouble(UnboxDouble(v)) if value is known to be double. | 1702 // Fold away BoxDouble(UnboxDouble(v)) if value is known to be double. |
1617 UnboxDoubleInstr* defn = value()->definition()->AsUnboxDouble(); | 1703 UnboxDoubleInstr* defn = value()->definition()->AsUnboxDouble(); |
1618 if ((defn != NULL) && (defn->value()->Type()->ToCid() == kDoubleCid)) { | 1704 if ((defn != NULL) && (defn->value()->Type()->ToCid() == kDoubleCid)) { |
1619 return defn->value()->definition(); | 1705 return defn->value()->definition(); |
1620 } | 1706 } |
1621 | 1707 |
1622 return this; | 1708 return this; |
1623 } | 1709 } |
1624 | 1710 |
1625 | 1711 |
| 1712 bool BoxIntNInstr::ValueFitsSmi() const { |
| 1713 Range* range = value()->definition()->range(); |
| 1714 return Range::Fits(range, RangeBoundary::kRangeBoundarySmi); |
| 1715 } |
| 1716 |
| 1717 |
| 1718 Definition* BoxIntNInstr::Canonicalize(FlowGraph* flow_graph) { |
| 1719 if ((input_use_list() == NULL) && !HasTryBlockUse(env_use_list())) { |
| 1720 // Environments can accomodate any representation. No need to box. |
| 1721 return value()->definition(); |
| 1722 } |
| 1723 |
| 1724 return this; |
| 1725 } |
| 1726 |
| 1727 |
| 1728 Definition* UnboxIntNInstr::Canonicalize(FlowGraph* flow_graph) { |
| 1729 if (!HasUses()) return NULL; |
| 1730 |
| 1731 // Fold away UnboxInt<N>Instr(BoxInt<N>Instr(v)). |
| 1732 BoxIntNInstr* box_defn = value()->definition()->AsBoxIntN(); |
| 1733 if (box_defn != NULL) { |
| 1734 if (box_defn->value()->definition()->representation() == representation()) { |
| 1735 return box_defn->value()->definition(); |
| 1736 } else { |
| 1737 UnboxedIntConverterInstr* converter = new UnboxedIntConverterInstr( |
| 1738 box_defn->value()->definition()->representation(), |
| 1739 representation(), |
| 1740 box_defn->value()->CopyWithType(), |
| 1741 representation() == kUnboxedInt32 ? deopt_id_ : Isolate::kNoDeoptId); |
| 1742 flow_graph->InsertBefore(this, converter, env(), FlowGraph::kValue); |
| 1743 return converter; |
| 1744 } |
| 1745 } |
| 1746 |
| 1747 return this; |
| 1748 } |
| 1749 |
| 1750 |
| 1751 Definition* UnboxedIntConverterInstr::Canonicalize(FlowGraph* flow_graph) { |
| 1752 if (!HasUses()) return NULL; |
| 1753 |
| 1754 UnboxedIntConverterInstr* box_defn = |
| 1755 value()->definition()->AsUnboxedIntConverter(); |
| 1756 if ((box_defn != NULL) && (box_defn->representation() == from())) { |
| 1757 if (box_defn->from() == to()) { |
| 1758 return box_defn->value()->definition(); |
| 1759 } |
| 1760 |
| 1761 UnboxedIntConverterInstr* converter = new UnboxedIntConverterInstr( |
| 1762 box_defn->from(), |
| 1763 representation(), |
| 1764 box_defn->value()->CopyWithType(), |
| 1765 to() == kUnboxedInt32 ? deopt_id_ : NULL); |
| 1766 flow_graph->InsertBefore(this, converter, env(), FlowGraph::kValue); |
| 1767 return converter; |
| 1768 } |
| 1769 |
| 1770 UnboxIntegerInstr* unbox_defn = value()->definition()->AsUnboxInteger(); |
| 1771 if (unbox_defn != NULL && |
| 1772 (from() == kUnboxedMint) && |
| 1773 (to() == kUnboxedInt32) && |
| 1774 unbox_defn->HasOnlyInputUse(value())) { |
| 1775 // TODO(vegorov): there is a duplication of code between UnboxedIntCoverter |
| 1776 // and code path that unboxes Mint into Int32. We should just schedule |
| 1777 // these instructions close to each other instead of fusing them. |
| 1778 Definition* replacement = |
| 1779 new UnboxInt32Instr(unbox_defn->value()->CopyWithType(), deopt_id_); |
| 1780 flow_graph->InsertBefore(this, |
| 1781 replacement, |
| 1782 env(), |
| 1783 FlowGraph::kValue); |
| 1784 return replacement; |
| 1785 } |
| 1786 |
| 1787 return this; |
| 1788 } |
| 1789 |
| 1790 |
| 1791 Definition* UnboxInt32Instr::Canonicalize(FlowGraph* flow_graph) { |
| 1792 Definition* replacement = UnboxIntNInstr::Canonicalize(flow_graph); |
| 1793 if (replacement != this) { |
| 1794 return replacement; |
| 1795 } |
| 1796 |
| 1797 ConstantInstr* c = value()->definition()->AsConstant(); |
| 1798 if ((c != NULL) && c->value().IsSmi()) { |
| 1799 UnboxedConstantInstr* uc = |
| 1800 new UnboxedConstantInstr(c->value(), kUnboxedInt32); |
| 1801 flow_graph->InsertBefore(this, uc, NULL, FlowGraph::kValue); |
| 1802 return uc; |
| 1803 } |
| 1804 |
| 1805 return this; |
| 1806 } |
| 1807 |
| 1808 |
1626 Definition* UnboxDoubleInstr::Canonicalize(FlowGraph* flow_graph) { | 1809 Definition* UnboxDoubleInstr::Canonicalize(FlowGraph* flow_graph) { |
1627 if (!HasUses()) return NULL; | 1810 if (!HasUses()) return NULL; |
1628 // Fold away UnboxDouble(BoxDouble(v)). | 1811 // Fold away UnboxDouble(BoxDouble(v)). |
1629 BoxDoubleInstr* box_defn = value()->definition()->AsBoxDouble(); | 1812 BoxDoubleInstr* box_defn = value()->definition()->AsBoxDouble(); |
1630 if (box_defn != NULL) { | 1813 if (box_defn != NULL) { |
1631 return box_defn->value()->definition(); | 1814 return box_defn->value()->definition(); |
1632 } | 1815 } |
1633 | 1816 |
1634 ConstantInstr* c = value()->definition()->AsConstant(); | 1817 ConstantInstr* c = value()->definition()->AsConstant(); |
1635 if ((c != NULL) && c->value().IsDouble()) { | 1818 if ((c != NULL) && c->value().IsDouble()) { |
1636 UnboxedConstantInstr* uc = new UnboxedConstantInstr(c->value()); | 1819 UnboxedConstantInstr* uc = |
| 1820 new UnboxedConstantInstr(c->value(), kUnboxedDouble); |
1637 flow_graph->InsertBefore(this, uc, NULL, FlowGraph::kValue); | 1821 flow_graph->InsertBefore(this, uc, NULL, FlowGraph::kValue); |
1638 return uc; | 1822 return uc; |
1639 } | 1823 } |
1640 | 1824 |
1641 return this; | 1825 return this; |
1642 } | 1826 } |
1643 | 1827 |
1644 | 1828 |
| 1829 Definition* BoxIntegerInstr::Canonicalize(FlowGraph* flow_graph) { |
| 1830 if ((input_use_list() == NULL) && !HasTryBlockUse(env_use_list())) { |
| 1831 // Environments can accomodate any representation. No need to box. |
| 1832 return value()->definition(); |
| 1833 } |
| 1834 |
| 1835 UnboxedIntConverterInstr* conv = |
| 1836 value()->definition()->AsUnboxedIntConverter(); |
| 1837 if (conv != NULL) { |
| 1838 Definition* replacement = this; |
| 1839 |
| 1840 switch (conv->from()) { |
| 1841 case kUnboxedInt32: |
| 1842 replacement = new BoxInt32Instr(conv->value()->CopyWithType()); |
| 1843 break; |
| 1844 case kUnboxedUint32: |
| 1845 replacement = new BoxUint32Instr(conv->value()->CopyWithType()); |
| 1846 break; |
| 1847 default: |
| 1848 UNREACHABLE(); |
| 1849 break; |
| 1850 } |
| 1851 |
| 1852 if (replacement != this) { |
| 1853 flow_graph->InsertBefore(this, |
| 1854 replacement, |
| 1855 NULL, |
| 1856 FlowGraph::kValue); |
| 1857 } |
| 1858 |
| 1859 return replacement; |
| 1860 } |
| 1861 |
| 1862 return this; |
| 1863 } |
| 1864 |
| 1865 |
| 1866 Definition* UnboxIntegerInstr::Canonicalize(FlowGraph* flow_graph) { |
| 1867 if (!HasUses()) return NULL; |
| 1868 return this; |
| 1869 } |
| 1870 |
| 1871 |
1645 Definition* BoxFloat32x4Instr::Canonicalize(FlowGraph* flow_graph) { | 1872 Definition* BoxFloat32x4Instr::Canonicalize(FlowGraph* flow_graph) { |
1646 if ((input_use_list() == NULL) && !HasTryBlockUse(env_use_list())) { | 1873 if ((input_use_list() == NULL) && !HasTryBlockUse(env_use_list())) { |
1647 // Environments can accomodate any representation. No need to box. | 1874 // Environments can accomodate any representation. No need to box. |
1648 return value()->definition(); | 1875 return value()->definition(); |
1649 } | 1876 } |
1650 | 1877 |
1651 // Fold away BoxFloat32x4(UnboxFloat32x4(v)). | 1878 // Fold away BoxFloat32x4(UnboxFloat32x4(v)). |
1652 UnboxFloat32x4Instr* defn = value()->definition()->AsUnboxFloat32x4(); | 1879 UnboxFloat32x4Instr* defn = value()->definition()->AsUnboxFloat32x4(); |
1653 if ((defn != NULL) && (defn->value()->Type()->ToCid() == kFloat32x4Cid)) { | 1880 if ((defn != NULL) && (defn->value()->Type()->ToCid() == kFloat32x4Cid)) { |
1654 return defn->value()->definition(); | 1881 return defn->value()->definition(); |
(...skipping 1206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2861 case Token::kTRUNCDIV: return 0; | 3088 case Token::kTRUNCDIV: return 0; |
2862 case Token::kMOD: return 1; | 3089 case Token::kMOD: return 1; |
2863 default: UNIMPLEMENTED(); return -1; | 3090 default: UNIMPLEMENTED(); return -1; |
2864 } | 3091 } |
2865 } | 3092 } |
2866 | 3093 |
2867 | 3094 |
2868 #undef __ | 3095 #undef __ |
2869 | 3096 |
2870 } // namespace dart | 3097 } // namespace dart |
OLD | NEW |