Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 #ifndef VM_INTERMEDIATE_LANGUAGE_H_ | 5 #ifndef VM_INTERMEDIATE_LANGUAGE_H_ |
| 6 #define VM_INTERMEDIATE_LANGUAGE_H_ | 6 #define VM_INTERMEDIATE_LANGUAGE_H_ |
| 7 | 7 |
| 8 #include "vm/allocation.h" | 8 #include "vm/allocation.h" |
| 9 #include "vm/ast.h" | 9 #include "vm/ast.h" |
| 10 #include "vm/growable_array.h" | 10 #include "vm/growable_array.h" |
| 11 #include "vm/handles_impl.h" | 11 #include "vm/handles_impl.h" |
| 12 #include "vm/locations.h" | 12 #include "vm/locations.h" |
| 13 #include "vm/object.h" | 13 #include "vm/object.h" |
| 14 | 14 |
| 15 namespace dart { | 15 namespace dart { |
| 16 | 16 |
| 17 class BitVector; | 17 class BitVector; |
| 18 class BlockEntryInstr; | 18 class BlockEntryInstr; |
| 19 class BufferFormatter; | 19 class BufferFormatter; |
| 20 class ComparisonInstr; | 20 class ComparisonInstr; |
| 21 class ControlInstruction; | 21 class ControlInstruction; |
| 22 class Definition; | 22 class Definition; |
| 23 class Environment; | 23 class Environment; |
| 24 class FlowGraphCompiler; | 24 class FlowGraphCompiler; |
| 25 class FlowGraphVisitor; | 25 class FlowGraphVisitor; |
| 26 class Instruction; | 26 class Instruction; |
| 27 class LocalVariable; | 27 class LocalVariable; |
| 28 class Range; | |
| 28 | 29 |
| 29 | 30 |
| 30 // TODO(srdjan): Add _ByteArrayBase, get:length. | 31 // TODO(srdjan): Add _ByteArrayBase, get:length. |
| 31 | 32 |
| 32 #define RECOGNIZED_LIST(V) \ | 33 #define RECOGNIZED_LIST(V) \ |
| 33 V(ObjectArray, get:length, ObjectArrayLength) \ | 34 V(ObjectArray, get:length, ObjectArrayLength) \ |
| 34 V(ImmutableArray, get:length, ImmutableArrayLength) \ | 35 V(ImmutableArray, get:length, ImmutableArrayLength) \ |
| 35 V(GrowableObjectArray, get:length, GrowableArrayLength) \ | 36 V(GrowableObjectArray, get:length, GrowableArrayLength) \ |
| 36 V(GrowableObjectArray, get:capacity, GrowableArrayCapacity) \ | 37 V(GrowableObjectArray, get:capacity, GrowableArrayCapacity) \ |
| 37 V(StringBase, get:length, StringBaseLength) \ | 38 V(StringBase, get:length, StringBaseLength) \ |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 73 | 74 |
| 74 Instruction* instruction() const { return instruction_; } | 75 Instruction* instruction() const { return instruction_; } |
| 75 void set_instruction(Instruction* instruction) { instruction_ = instruction; } | 76 void set_instruction(Instruction* instruction) { instruction_ = instruction; } |
| 76 | 77 |
| 77 intptr_t use_index() const { return use_index_; } | 78 intptr_t use_index() const { return use_index_; } |
| 78 void set_use_index(intptr_t index) { use_index_ = index; } | 79 void set_use_index(intptr_t index) { use_index_ = index; } |
| 79 | 80 |
| 80 void AddToInputUseList(); | 81 void AddToInputUseList(); |
| 81 void AddToEnvUseList(); | 82 void AddToEnvUseList(); |
| 82 | 83 |
| 84 void RemoveFromInputUseList(); | |
| 85 | |
| 83 Value* Copy() { return new Value(definition_); } | 86 Value* Copy() { return new Value(definition_); } |
| 84 | 87 |
| 85 RawAbstractType* CompileType() const; | 88 RawAbstractType* CompileType() const; |
| 86 intptr_t ResultCid() const; | 89 intptr_t ResultCid() const; |
| 87 | 90 |
| 88 void PrintTo(BufferFormatter* f) const; | 91 void PrintTo(BufferFormatter* f) const; |
| 89 | 92 |
| 90 const char* DebugName() const { return "Value"; } | 93 const char* DebugName() const { return "Value"; } |
| 91 | 94 |
| 92 // Return true if the value represents a constant. | 95 // Return true if the value represents a constant. |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 245 M(SmiToDouble) \ | 248 M(SmiToDouble) \ |
| 246 M(CheckClass) \ | 249 M(CheckClass) \ |
| 247 M(CheckSmi) \ | 250 M(CheckSmi) \ |
| 248 M(Constant) \ | 251 M(Constant) \ |
| 249 M(CheckEitherNonSmi) \ | 252 M(CheckEitherNonSmi) \ |
| 250 M(UnboxedDoubleBinaryOp) \ | 253 M(UnboxedDoubleBinaryOp) \ |
| 251 M(MathSqrt) \ | 254 M(MathSqrt) \ |
| 252 M(UnboxDouble) \ | 255 M(UnboxDouble) \ |
| 253 M(BoxDouble) \ | 256 M(BoxDouble) \ |
| 254 M(CheckArrayBound) \ | 257 M(CheckArrayBound) \ |
| 258 M(Constraint) \ | |
| 255 | 259 |
| 256 | 260 |
| 257 #define FORWARD_DECLARATION(type) class type##Instr; | 261 #define FORWARD_DECLARATION(type) class type##Instr; |
| 258 FOR_EACH_INSTRUCTION(FORWARD_DECLARATION) | 262 FOR_EACH_INSTRUCTION(FORWARD_DECLARATION) |
| 259 #undef FORWARD_DECLARATION | 263 #undef FORWARD_DECLARATION |
| 260 | 264 |
| 261 | 265 |
| 262 // Functions required in all concrete instruction classes. | 266 // Functions required in all concrete instruction classes. |
| 263 #define DECLARE_INSTRUCTION(type) \ | 267 #define DECLARE_INSTRUCTION(type) \ |
| 264 virtual Tag tag() const { return k##type; } \ | 268 virtual Tag tag() const { return k##type; } \ |
| 265 virtual void Accept(FlowGraphVisitor* visitor); \ | 269 virtual void Accept(FlowGraphVisitor* visitor); \ |
| 266 virtual type##Instr* As##type() { return this; } \ | 270 virtual type##Instr* As##type() { return this; } \ |
| 267 virtual const char* DebugName() const { return #type; } \ | 271 virtual const char* DebugName() const { return #type; } \ |
| 268 virtual LocationSummary* MakeLocationSummary() const; \ | 272 virtual LocationSummary* MakeLocationSummary() const; \ |
| 269 virtual void EmitNativeCode(FlowGraphCompiler* compiler); \ | 273 virtual void EmitNativeCode(FlowGraphCompiler* compiler); \ |
| 270 | 274 |
| 271 | 275 |
| 272 class Instruction : public ZoneAllocated { | 276 class Instruction : public ZoneAllocated { |
| 273 public: | 277 public: |
| 274 #define DECLARE_TAG(type) k##type, | 278 #define DECLARE_TAG(type) k##type, |
| 275 enum Tag { | 279 enum Tag { |
| 276 FOR_EACH_INSTRUCTION(DECLARE_TAG) | 280 FOR_EACH_INSTRUCTION(DECLARE_TAG) |
| 277 }; | 281 }; |
| 278 #undef DECLARE_TAG | 282 #undef DECLARE_TAG |
| 279 | 283 |
| 280 Instruction() | 284 Instruction() |
| 281 : deopt_id_(Isolate::Current()->GetNextDeoptId()), | 285 : range_(NULL), |
| 286 deopt_id_(Isolate::Current()->GetNextDeoptId()), | |
| 282 lifetime_position_(-1), | 287 lifetime_position_(-1), |
| 283 previous_(NULL), | 288 previous_(NULL), |
| 284 next_(NULL), | 289 next_(NULL), |
| 285 env_(NULL), | 290 env_(NULL), |
| 286 expr_id_(-1) { } | 291 expr_id_(-1) { } |
| 287 | 292 |
| 288 virtual Tag tag() const = 0; | 293 virtual Tag tag() const = 0; |
| 289 | 294 |
| 290 intptr_t deopt_id() const { | 295 intptr_t deopt_id() const { |
| 291 ASSERT(CanDeoptimize()); | 296 ASSERT(CanDeoptimize()); |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 428 | 433 |
| 429 // Representation of the value produced by this computation. | 434 // Representation of the value produced by this computation. |
| 430 virtual Representation representation() const { | 435 virtual Representation representation() const { |
| 431 return kTagged; | 436 return kTagged; |
| 432 } | 437 } |
| 433 | 438 |
| 434 bool WasEliminated() const { | 439 bool WasEliminated() const { |
| 435 return next() == NULL; | 440 return next() == NULL; |
| 436 } | 441 } |
| 437 | 442 |
| 443 virtual bool InferRange() { | |
| 444 return false; | |
| 445 } | |
| 446 | |
| 447 virtual Range* range(); | |
| 448 | |
| 438 // Returns deoptimization id that corresponds to the deoptimization target | 449 // Returns deoptimization id that corresponds to the deoptimization target |
| 439 // that input operands conversions inserted for this instruction can jump | 450 // that input operands conversions inserted for this instruction can jump |
| 440 // to. | 451 // to. |
| 441 virtual intptr_t DeoptimizationTarget() const { | 452 virtual intptr_t DeoptimizationTarget() const { |
| 442 UNREACHABLE(); | 453 UNREACHABLE(); |
| 443 return Isolate::kNoDeoptId; | 454 return Isolate::kNoDeoptId; |
| 444 } | 455 } |
| 445 | 456 |
| 446 // Returns a replacement for the instruction or NULL if the instruction can | 457 // Returns a replacement for the instruction or NULL if the instruction can |
| 447 // be eliminated. By default returns the this instruction which means no | 458 // be eliminated. By default returns the this instruction which means no |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 484 UNREACHABLE(); | 495 UNREACHABLE(); |
| 485 return false; | 496 return false; |
| 486 } | 497 } |
| 487 | 498 |
| 488 protected: | 499 protected: |
| 489 // Fetch deopt id without checking if this computation can deoptimize. | 500 // Fetch deopt id without checking if this computation can deoptimize. |
| 490 intptr_t GetDeoptId() const { | 501 intptr_t GetDeoptId() const { |
| 491 return deopt_id_; | 502 return deopt_id_; |
| 492 } | 503 } |
| 493 | 504 |
| 505 Range* range_; | |
|
Florian Schneider
2012/09/21 08:56:44
It seems that range_ can be made a member of Defin
Kevin Millikin (Google)
2012/09/21 08:59:33
Does it buy us anything to make this a pointer ins
Vyacheslav Egorov (Google)
2012/09/21 20:08:07
Done.
Vyacheslav Egorov (Google)
2012/09/21 20:08:07
Pointer allows use also to express _|_ state which
| |
| 506 | |
| 494 private: | 507 private: |
| 495 friend class Definition; // Needed for InsertBefore, InsertAfter. | 508 friend class Definition; // Needed for InsertBefore, InsertAfter. |
| 496 | 509 |
| 497 // Classes that set deopt_id_. | 510 // Classes that set deopt_id_. |
| 498 friend class UnboxDoubleInstr; | 511 friend class UnboxDoubleInstr; |
| 499 friend class UnboxedDoubleBinaryOpInstr; | 512 friend class UnboxedDoubleBinaryOpInstr; |
| 500 friend class MathSqrtInstr; | 513 friend class MathSqrtInstr; |
| 501 friend class CheckClassInstr; | 514 friend class CheckClassInstr; |
| 502 friend class CheckSmiInstr; | 515 friend class CheckSmiInstr; |
| 503 friend class CheckArrayBoundInstr; | 516 friend class CheckArrayBoundInstr; |
| (...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 716 | 729 |
| 717 virtual bool HasSideEffect() const { return false; } | 730 virtual bool HasSideEffect() const { return false; } |
| 718 | 731 |
| 719 intptr_t try_index() const { return try_index_; } | 732 intptr_t try_index() const { return try_index_; } |
| 720 | 733 |
| 721 BitVector* loop_info() const { return loop_info_; } | 734 BitVector* loop_info() const { return loop_info_; } |
| 722 void set_loop_info(BitVector* loop_info) { | 735 void set_loop_info(BitVector* loop_info) { |
| 723 loop_info_ = loop_info; | 736 loop_info_ = loop_info; |
| 724 } | 737 } |
| 725 | 738 |
| 739 virtual BlockEntryInstr* GetBlock() const { | |
| 740 return const_cast<BlockEntryInstr*>(this); | |
| 741 } | |
| 742 | |
| 726 protected: | 743 protected: |
| 727 explicit BlockEntryInstr(intptr_t try_index) | 744 explicit BlockEntryInstr(intptr_t try_index) |
| 728 : try_index_(try_index), | 745 : try_index_(try_index), |
| 729 preorder_number_(-1), | 746 preorder_number_(-1), |
| 730 postorder_number_(-1), | 747 postorder_number_(-1), |
| 731 block_id_(-1), | 748 block_id_(-1), |
| 732 dominator_(NULL), | 749 dominator_(NULL), |
| 733 dominated_blocks_(1), | 750 dominated_blocks_(1), |
| 734 last_instruction_(NULL), | 751 last_instruction_(NULL), |
| 735 parallel_move_(NULL), | 752 parallel_move_(NULL), |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 922 | 939 |
| 923 GrowableArray<BlockEntryInstr*> predecessors_; | 940 GrowableArray<BlockEntryInstr*> predecessors_; |
| 924 ZoneGrowableArray<PhiInstr*>* phis_; | 941 ZoneGrowableArray<PhiInstr*>* phis_; |
| 925 intptr_t phi_count_; | 942 intptr_t phi_count_; |
| 926 GrowableArray<BlockEntryInstr*> stale_predecessors_; | 943 GrowableArray<BlockEntryInstr*> stale_predecessors_; |
| 927 | 944 |
| 928 DISALLOW_COPY_AND_ASSIGN(JoinEntryInstr); | 945 DISALLOW_COPY_AND_ASSIGN(JoinEntryInstr); |
| 929 }; | 946 }; |
| 930 | 947 |
| 931 | 948 |
| 949 class PhiIterator : public ValueObject { | |
| 950 public: | |
| 951 explicit PhiIterator(JoinEntryInstr* join) | |
| 952 : phis_(join->phis()), index_(-1) { | |
| 953 Advance(); | |
| 954 } | |
| 955 | |
| 956 void Advance() { | |
|
Kevin Millikin (Google)
2012/09/21 08:59:33
Simpler:
void Advance() {
++index_;
while (!D
Vyacheslav Egorov (Google)
2012/09/21 20:08:07
This is how it looked initially. I just wanted to
| |
| 957 if (Done()) return; | |
|
Florian Schneider
2012/09/21 08:56:44
I'd rather write ASSERT(!Done());
Vyacheslav Egorov (Google)
2012/09/21 20:08:07
Done.
| |
| 958 | |
| 959 intptr_t i = index_ + 1; | |
| 960 while ((i < phis_->length()) && ((*phis_)[i] == NULL)) { | |
| 961 i++; | |
| 962 } | |
| 963 index_ = i; | |
| 964 } | |
| 965 | |
| 966 bool Done() const { | |
| 967 return (phis_ == NULL) || (index_ >= phis_->length()); | |
| 968 } | |
| 969 | |
| 970 PhiInstr* Current() const { | |
| 971 return (*phis_)[index_]; | |
| 972 } | |
| 973 | |
| 974 private: | |
| 975 ZoneGrowableArray<PhiInstr*>* phis_; | |
| 976 intptr_t index_; | |
| 977 }; | |
| 978 | |
| 979 | |
| 932 class TargetEntryInstr : public BlockEntryInstr { | 980 class TargetEntryInstr : public BlockEntryInstr { |
| 933 public: | 981 public: |
| 934 explicit TargetEntryInstr(intptr_t try_index) | 982 explicit TargetEntryInstr(intptr_t try_index) |
| 935 : BlockEntryInstr(try_index), | 983 : BlockEntryInstr(try_index), |
| 936 predecessor_(NULL), | 984 predecessor_(NULL), |
| 937 catch_try_index_(CatchClauseNode::kInvalidTryIndex) { } | 985 catch_try_index_(CatchClauseNode::kInvalidTryIndex) { } |
| 938 | 986 |
| 939 // Used for exception catch entries. | 987 // Used for exception catch entries. |
| 940 TargetEntryInstr(intptr_t try_index, intptr_t catch_try_index) | 988 TargetEntryInstr(intptr_t try_index, intptr_t catch_try_index) |
| 941 : BlockEntryInstr(try_index), | 989 : BlockEntryInstr(try_index), |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1099 DISALLOW_COPY_AND_ASSIGN(Definition); | 1147 DISALLOW_COPY_AND_ASSIGN(Definition); |
| 1100 }; | 1148 }; |
| 1101 | 1149 |
| 1102 | 1150 |
| 1103 class PhiInstr : public Definition { | 1151 class PhiInstr : public Definition { |
| 1104 public: | 1152 public: |
| 1105 explicit PhiInstr(JoinEntryInstr* block, intptr_t num_inputs) | 1153 explicit PhiInstr(JoinEntryInstr* block, intptr_t num_inputs) |
| 1106 : block_(block), | 1154 : block_(block), |
| 1107 inputs_(num_inputs), | 1155 inputs_(num_inputs), |
| 1108 is_alive_(false), | 1156 is_alive_(false), |
| 1109 representation_(kTagged) { | 1157 representation_(kTagged), |
| 1158 has_unranged_inputs_(true) { | |
| 1110 for (intptr_t i = 0; i < num_inputs; ++i) { | 1159 for (intptr_t i = 0; i < num_inputs; ++i) { |
| 1111 inputs_.Add(NULL); | 1160 inputs_.Add(NULL); |
| 1112 } | 1161 } |
| 1113 } | 1162 } |
| 1114 | 1163 |
| 1115 // Get the block entry for that instruction. | 1164 // Get the block entry for that instruction. |
| 1116 virtual BlockEntryInstr* GetBlock() const { return block(); } | 1165 virtual BlockEntryInstr* GetBlock() const { return block(); } |
| 1117 JoinEntryInstr* block() const { return block_; } | 1166 JoinEntryInstr* block() const { return block_; } |
| 1118 | 1167 |
| 1119 virtual RawAbstractType* CompileType() const; | 1168 virtual RawAbstractType* CompileType() const; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1158 virtual intptr_t ResultCid() const { | 1207 virtual intptr_t ResultCid() const { |
| 1159 UNREACHABLE(); | 1208 UNREACHABLE(); |
| 1160 return kIllegalCid; | 1209 return kIllegalCid; |
| 1161 } | 1210 } |
| 1162 | 1211 |
| 1163 DECLARE_INSTRUCTION(Phi) | 1212 DECLARE_INSTRUCTION(Phi) |
| 1164 | 1213 |
| 1165 virtual void PrintTo(BufferFormatter* f) const; | 1214 virtual void PrintTo(BufferFormatter* f) const; |
| 1166 virtual void PrintToVisualizer(BufferFormatter* f) const; | 1215 virtual void PrintToVisualizer(BufferFormatter* f) const; |
| 1167 | 1216 |
| 1217 virtual bool InferRange(); | |
| 1218 | |
| 1219 virtual Range* range() { return range_; } | |
| 1220 | |
| 1168 private: | 1221 private: |
| 1169 friend class JoinEntryInstr; // Direct access to inputs_ array. | 1222 friend class JoinEntryInstr; // Direct access to inputs_ array. |
| 1170 | 1223 |
| 1171 JoinEntryInstr* block_; | 1224 JoinEntryInstr* block_; |
| 1172 GrowableArray<Value*> inputs_; | 1225 GrowableArray<Value*> inputs_; |
| 1173 bool is_alive_; | 1226 bool is_alive_; |
| 1174 Representation representation_; | 1227 Representation representation_; |
| 1175 | 1228 |
| 1229 bool has_unranged_inputs_; | |
|
Florian Schneider
2012/09/21 08:56:44
Maybe rename to has_inputs_without_range_.
Vyacheslav Egorov (Google)
2012/09/21 20:08:07
Done.
| |
| 1230 | |
| 1176 DISALLOW_COPY_AND_ASSIGN(PhiInstr); | 1231 DISALLOW_COPY_AND_ASSIGN(PhiInstr); |
| 1177 }; | 1232 }; |
| 1178 | 1233 |
| 1179 | 1234 |
| 1180 class ParameterInstr : public Definition { | 1235 class ParameterInstr : public Definition { |
| 1181 public: | 1236 public: |
| 1182 explicit ParameterInstr(intptr_t index, GraphEntryInstr* block) | 1237 explicit ParameterInstr(intptr_t index, GraphEntryInstr* block) |
| 1183 : index_(index), block_(block) { } | 1238 : index_(index), block_(block) { } |
| 1184 | 1239 |
| 1185 DECLARE_INSTRUCTION(Parameter) | 1240 DECLARE_INSTRUCTION(Parameter) |
| (...skipping 337 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1523 protected: | 1578 protected: |
| 1524 EmbeddedArray<Value*, N> inputs_; | 1579 EmbeddedArray<Value*, N> inputs_; |
| 1525 | 1580 |
| 1526 private: | 1581 private: |
| 1527 friend class BranchInstr; | 1582 friend class BranchInstr; |
| 1528 | 1583 |
| 1529 LocationSummary* locs_; | 1584 LocationSummary* locs_; |
| 1530 }; | 1585 }; |
| 1531 | 1586 |
| 1532 | 1587 |
| 1588 class RangeBoundary : public ValueObject { | |
| 1589 public: | |
| 1590 enum Kind { kUnknown, kSymbol, kConstant }; | |
| 1591 | |
| 1592 RangeBoundary() : kind_(kUnknown), value_(0), offs_(0) { } | |
|
Kevin Millikin (Google)
2012/09/21 08:59:33
Please burn two characters to spell out 'offset'.
Vyacheslav Egorov (Google)
2012/09/21 20:08:07
Done.
| |
| 1593 | |
| 1594 static RangeBoundary FromConstant(intptr_t val) { | |
| 1595 return RangeBoundary(kConstant, val, 0); | |
| 1596 } | |
| 1597 | |
| 1598 static RangeBoundary FromDefinition(Definition* defn, intptr_t offs = 0) { | |
| 1599 return RangeBoundary(kSymbol, reinterpret_cast<intptr_t>(defn), offs); | |
| 1600 } | |
| 1601 | |
| 1602 static RangeBoundary MinSmi() { | |
| 1603 return FromConstant(Smi::kMinValue); | |
| 1604 } | |
| 1605 | |
| 1606 static RangeBoundary MaxSmi() { | |
| 1607 return FromConstant(Smi::kMaxValue); | |
| 1608 } | |
| 1609 | |
| 1610 static RangeBoundary OverflowedMinSmi() { | |
| 1611 return FromConstant(Smi::kMinValue - 1); | |
| 1612 } | |
| 1613 | |
| 1614 static RangeBoundary OverflowedMaxSmi() { | |
| 1615 return FromConstant(Smi::kMaxValue + 1); | |
| 1616 } | |
| 1617 | |
| 1618 static RangeBoundary Min(RangeBoundary a, RangeBoundary b) { | |
| 1619 const intptr_t min_a = a.LowerBound().value(); | |
| 1620 const intptr_t min_b = b.LowerBound().value(); | |
| 1621 | |
| 1622 return RangeBoundary::FromConstant((min_a < min_b) ? min_a : min_b); | |
|
Kevin Millikin (Google)
2012/09/21 08:59:33
You can spell this Utils::Minimum(min_a, min_b)
Vyacheslav Egorov (Google)
2012/09/21 20:08:07
Done.
| |
| 1623 } | |
| 1624 | |
| 1625 static RangeBoundary Max(RangeBoundary a, RangeBoundary b) { | |
| 1626 const intptr_t max_a = a.UpperBound().value(); | |
| 1627 const intptr_t max_b = b.UpperBound().value(); | |
| 1628 | |
| 1629 return RangeBoundary::FromConstant((max_a > max_b) ? max_a : max_b); | |
| 1630 } | |
| 1631 | |
| 1632 bool Overflowed() const { | |
| 1633 return !Smi::IsValid(value()); | |
| 1634 } | |
| 1635 | |
| 1636 RangeBoundary Clamp() const { | |
| 1637 if (IsConstant()) { | |
| 1638 if (value() < Smi::kMinValue) return MinSmi(); | |
| 1639 if (value() > Smi::kMaxValue) return MaxSmi(); | |
| 1640 } | |
| 1641 return *this; | |
| 1642 } | |
| 1643 | |
| 1644 bool Equals(const RangeBoundary& other) const { | |
| 1645 return (kind_ == other.kind_) && (value_ == other.value_); | |
|
Florian Schneider
2012/09/21 08:56:44
&& (offs_ == other.offs_)
Vyacheslav Egorov (Google)
2012/09/21 20:08:07
Nice catch!
| |
| 1646 } | |
| 1647 | |
| 1648 bool IsUnknown() const { return kind_ == kUnknown; } | |
| 1649 bool IsConstant() const { return kind_ == kConstant; } | |
| 1650 bool IsSymbol() const { return kind_ == kSymbol; } | |
| 1651 | |
| 1652 intptr_t value() const { | |
| 1653 ASSERT(IsConstant()); | |
| 1654 return value_; | |
| 1655 } | |
| 1656 | |
| 1657 Definition* symbol() const { | |
| 1658 ASSERT(IsSymbol()); | |
| 1659 return reinterpret_cast<Definition*>(value_); | |
| 1660 } | |
| 1661 | |
| 1662 RangeBoundary LowerBound() const; | |
| 1663 RangeBoundary UpperBound() const; | |
| 1664 | |
| 1665 static RangeBoundary WidenMin(const RangeBoundary& old_min, | |
| 1666 const RangeBoundary& new_min) { | |
| 1667 if (new_min.LowerBound().value() < old_min.LowerBound().value()) { | |
| 1668 return MinSmi(); | |
| 1669 } | |
| 1670 return new_min; | |
| 1671 } | |
| 1672 | |
| 1673 static RangeBoundary WidenMax(const RangeBoundary& old_max, | |
| 1674 const RangeBoundary& new_max) { | |
| 1675 if (new_max.UpperBound().value() > old_max.UpperBound().value()) { | |
| 1676 return MaxSmi(); | |
| 1677 } | |
| 1678 return new_max; | |
| 1679 } | |
| 1680 | |
| 1681 void PrintTo(BufferFormatter* f) const; | |
| 1682 | |
| 1683 static RangeBoundary Add(const RangeBoundary& a, | |
| 1684 const RangeBoundary& b, | |
| 1685 const RangeBoundary& overflow) { | |
| 1686 ASSERT(a.IsConstant() && b.IsConstant()); | |
| 1687 | |
| 1688 intptr_t result = a.value() + b.value(); | |
| 1689 if (!Smi::IsValid64(result)) { | |
|
Florian Schneider
2012/09/21 08:56:44
I think this should be Smi::IsValid(intptr_t value
Vyacheslav Egorov (Google)
2012/09/21 20:08:07
Yes. 64 is a leftover of an experiment.
| |
| 1690 return overflow; | |
| 1691 } | |
| 1692 return RangeBoundary::FromConstant(result); | |
| 1693 } | |
| 1694 | |
| 1695 static RangeBoundary Sub(const RangeBoundary& a, | |
| 1696 const RangeBoundary& b, | |
| 1697 const RangeBoundary& overflow) { | |
| 1698 ASSERT(a.IsConstant() && b.IsConstant()); | |
| 1699 | |
| 1700 intptr_t result = a.value() - b.value(); | |
| 1701 if (!Smi::IsValid64(result)) { | |
|
Florian Schneider
2012/09/21 08:56:44
Use Smi::IsValid(intptr_t value) here too.
Vyacheslav Egorov (Google)
2012/09/21 20:08:07
Done.
| |
| 1702 return overflow; | |
| 1703 } | |
| 1704 return RangeBoundary::FromConstant(result); | |
| 1705 } | |
| 1706 | |
| 1707 private: | |
| 1708 RangeBoundary(Kind kind, intptr_t value, intptr_t offs) | |
| 1709 : kind_(kind), value_(value), offs_(offs) { } | |
| 1710 | |
| 1711 Kind kind_; | |
| 1712 intptr_t value_; | |
| 1713 intptr_t offs_; | |
| 1714 }; | |
| 1715 | |
| 1716 | |
| 1717 class Range : public ZoneAllocated { | |
| 1718 public: | |
| 1719 Range(RangeBoundary min, RangeBoundary max) : min_(min), max_(max) { } | |
| 1720 | |
| 1721 static Range* Unknown() { | |
| 1722 return new Range(RangeBoundary::MinSmi(), RangeBoundary::MaxSmi()); | |
| 1723 } | |
| 1724 | |
| 1725 void PrintTo(BufferFormatter* f) const; | |
| 1726 | |
| 1727 const RangeBoundary& min() { return min_; } | |
| 1728 const RangeBoundary& max() { return max_; } | |
| 1729 | |
| 1730 bool Equals(Range* other) { | |
| 1731 return min_.Equals(other->min_) && max_.Equals(other->max_); | |
| 1732 } | |
| 1733 | |
| 1734 static bool Update(Range** range_slot, | |
| 1735 const RangeBoundary& min, | |
| 1736 const RangeBoundary& max) { | |
| 1737 if (*range_slot == NULL) { | |
| 1738 *range_slot = new Range(min, max); | |
| 1739 return true; | |
| 1740 } | |
| 1741 | |
| 1742 Range* range = *range_slot; | |
| 1743 if (range->min_.Equals(min) && range->max_.Equals(max)) { | |
| 1744 return false; | |
| 1745 } | |
| 1746 | |
| 1747 range->min_ = min; | |
| 1748 range->max_ = max; | |
| 1749 | |
| 1750 return true; | |
| 1751 } | |
| 1752 | |
| 1753 static RangeBoundary ConstantMin(Range* range) { | |
| 1754 if (range == NULL) return RangeBoundary::MinSmi(); | |
| 1755 return range->min().LowerBound(); | |
| 1756 } | |
| 1757 | |
| 1758 static RangeBoundary ConstantMax(Range* range) { | |
| 1759 if (range == NULL) return RangeBoundary::MaxSmi(); | |
| 1760 return range->max().UpperBound(); | |
| 1761 } | |
| 1762 | |
| 1763 private: | |
| 1764 RangeBoundary min_; | |
| 1765 RangeBoundary max_; | |
| 1766 }; | |
| 1767 | |
| 1768 | |
| 1769 class ConstraintInstr : public TemplateDefinition<2> { | |
| 1770 public: | |
| 1771 ConstraintInstr(Value* value, Range* constraint) | |
| 1772 : constraint_(constraint) { | |
| 1773 inputs_[0] = value; | |
| 1774 inputs_[1] = NULL; // Dependency. | |
| 1775 } | |
| 1776 | |
| 1777 DECLARE_INSTRUCTION(Constraint) | |
| 1778 | |
| 1779 virtual RawAbstractType* CompileType() const { | |
| 1780 return Type::SmiType(); | |
| 1781 } | |
| 1782 | |
| 1783 virtual bool CanDeoptimize() const { return false; } | |
| 1784 | |
| 1785 virtual bool HasSideEffect() const { return false; } | |
| 1786 | |
| 1787 virtual intptr_t ResultCid() const { return kSmiCid; } | |
| 1788 | |
| 1789 virtual bool AttributesEqual(Definition* other) const { | |
| 1790 UNREACHABLE(); | |
| 1791 return false; | |
| 1792 } | |
| 1793 | |
| 1794 virtual void PrintOperandsTo(BufferFormatter* f) const; | |
| 1795 | |
| 1796 Value* value() const { return inputs_[0]; } | |
| 1797 Range* constraint() const { return constraint_; } | |
| 1798 | |
| 1799 virtual bool InferRange(); | |
| 1800 | |
| 1801 virtual Range* range() { | |
| 1802 return range_; | |
| 1803 } | |
| 1804 | |
| 1805 void AddDependency(Definition* defn) { | |
| 1806 Value* val = new Value(defn); | |
| 1807 val->set_use_index(1); | |
| 1808 val->set_instruction(this); | |
| 1809 val->AddToInputUseList(); | |
| 1810 set_dependency(val); | |
| 1811 } | |
| 1812 | |
| 1813 void RemoveDependency() { | |
| 1814 if (dependency() != NULL) { | |
| 1815 dependency()->RemoveFromInputUseList(); | |
| 1816 set_dependency(NULL); | |
| 1817 } | |
| 1818 } | |
| 1819 | |
| 1820 private: | |
| 1821 Value* dependency() { | |
| 1822 return inputs_[1]; | |
| 1823 } | |
| 1824 | |
| 1825 void set_dependency(Value* value) { | |
| 1826 inputs_[1] = value; | |
| 1827 } | |
| 1828 | |
| 1829 Range* constraint_; | |
| 1830 | |
| 1831 DISALLOW_COPY_AND_ASSIGN(ConstraintInstr); | |
| 1832 }; | |
| 1833 | |
| 1834 | |
| 1533 class ConstantInstr : public TemplateDefinition<0> { | 1835 class ConstantInstr : public TemplateDefinition<0> { |
| 1534 public: | 1836 public: |
| 1535 explicit ConstantInstr(const Object& value) : value_(value) { } | 1837 explicit ConstantInstr(const Object& value) |
| 1838 : value_(value) { } | |
| 1536 | 1839 |
| 1537 DECLARE_INSTRUCTION(Constant) | 1840 DECLARE_INSTRUCTION(Constant) |
| 1538 virtual RawAbstractType* CompileType() const; | 1841 virtual RawAbstractType* CompileType() const; |
| 1539 | 1842 |
| 1540 const Object& value() const { return value_; } | 1843 const Object& value() const { return value_; } |
| 1541 | 1844 |
| 1542 virtual void PrintOperandsTo(BufferFormatter* f) const; | 1845 virtual void PrintOperandsTo(BufferFormatter* f) const; |
| 1543 | 1846 |
| 1544 virtual bool CanDeoptimize() const { return false; } | 1847 virtual bool CanDeoptimize() const { return false; } |
| 1545 | 1848 |
| 1546 virtual bool HasSideEffect() const { return false; } | 1849 virtual bool HasSideEffect() const { return false; } |
| 1547 | 1850 |
| 1548 virtual intptr_t ResultCid() const; | 1851 virtual intptr_t ResultCid() const; |
| 1549 | 1852 |
| 1550 virtual bool AttributesEqual(Instruction* other) const; | 1853 virtual bool AttributesEqual(Instruction* other) const; |
| 1551 virtual bool AffectedBySideEffect() const { return false; } | 1854 virtual bool AffectedBySideEffect() const { return false; } |
| 1552 | 1855 |
| 1856 virtual Range* range() { | |
|
Kevin Millikin (Google)
2012/09/21 08:59:33
This is disconcerting. Simpler just to treat smi
Vyacheslav Egorov (Google)
2012/09/21 20:08:07
Initially I wanted to make range() assert when you
| |
| 1857 ASSERT(value_.IsSmi()); | |
| 1858 if (range_ == NULL) { | |
| 1859 intptr_t value = Smi::Cast(value_).Value(); | |
| 1860 range_ = new Range(RangeBoundary::FromConstant(value), | |
| 1861 RangeBoundary::FromConstant(value)); | |
| 1862 } | |
| 1863 return range_; | |
| 1864 } | |
| 1865 | |
| 1553 private: | 1866 private: |
| 1554 const Object& value_; | 1867 const Object& value_; |
| 1555 | 1868 |
| 1556 DISALLOW_COPY_AND_ASSIGN(ConstantInstr); | 1869 DISALLOW_COPY_AND_ASSIGN(ConstantInstr); |
| 1557 }; | 1870 }; |
| 1558 | 1871 |
| 1559 | 1872 |
| 1560 class AssertAssignableInstr : public TemplateDefinition<3> { | 1873 class AssertAssignableInstr : public TemplateDefinition<3> { |
| 1561 public: | 1874 public: |
| 1562 AssertAssignableInstr(intptr_t token_pos, | 1875 AssertAssignableInstr(intptr_t token_pos, |
| (...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1848 InstanceCallInstr* instance_call_; | 2161 InstanceCallInstr* instance_call_; |
| 1849 const ICData& ic_data_; | 2162 const ICData& ic_data_; |
| 1850 const bool with_checks_; | 2163 const bool with_checks_; |
| 1851 | 2164 |
| 1852 DISALLOW_COPY_AND_ASSIGN(PolymorphicInstanceCallInstr); | 2165 DISALLOW_COPY_AND_ASSIGN(PolymorphicInstanceCallInstr); |
| 1853 }; | 2166 }; |
| 1854 | 2167 |
| 1855 | 2168 |
| 1856 class ComparisonInstr : public TemplateDefinition<2> { | 2169 class ComparisonInstr : public TemplateDefinition<2> { |
| 1857 public: | 2170 public: |
| 1858 ComparisonInstr(Token::Kind kind, Value* left, Value* right) : kind_(kind) { | 2171 ComparisonInstr(Token::Kind kind, Value* left, Value* right) |
| 2172 : kind_(kind) { | |
| 1859 ASSERT(left != NULL); | 2173 ASSERT(left != NULL); |
| 1860 ASSERT(right != NULL); | 2174 ASSERT(right != NULL); |
| 1861 inputs_[0] = left; | 2175 inputs_[0] = left; |
| 1862 inputs_[1] = right; | 2176 inputs_[1] = right; |
| 1863 } | 2177 } |
| 1864 | 2178 |
| 1865 Value* left() const { return inputs_[0]; } | 2179 Value* left() const { return inputs_[0]; } |
| 1866 Value* right() const { return inputs_[1]; } | 2180 Value* right() const { return inputs_[1]; } |
| 1867 | 2181 |
| 1868 virtual ComparisonInstr* AsComparison() { return this; } | 2182 virtual ComparisonInstr* AsComparison() { return this; } |
| (...skipping 1275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3144 }; | 3458 }; |
| 3145 | 3459 |
| 3146 | 3460 |
| 3147 class BinarySmiOpInstr : public TemplateDefinition<2> { | 3461 class BinarySmiOpInstr : public TemplateDefinition<2> { |
| 3148 public: | 3462 public: |
| 3149 BinarySmiOpInstr(Token::Kind op_kind, | 3463 BinarySmiOpInstr(Token::Kind op_kind, |
| 3150 InstanceCallInstr* instance_call, | 3464 InstanceCallInstr* instance_call, |
| 3151 Value* left, | 3465 Value* left, |
| 3152 Value* right) | 3466 Value* right) |
| 3153 : op_kind_(op_kind), | 3467 : op_kind_(op_kind), |
| 3154 instance_call_(instance_call) { | 3468 instance_call_(instance_call), |
| 3469 overflow_(true) { | |
| 3155 ASSERT(left != NULL); | 3470 ASSERT(left != NULL); |
| 3156 ASSERT(right != NULL); | 3471 ASSERT(right != NULL); |
| 3157 inputs_[0] = left; | 3472 inputs_[0] = left; |
| 3158 inputs_[1] = right; | 3473 inputs_[1] = right; |
| 3159 } | 3474 } |
| 3160 | 3475 |
| 3161 Value* left() const { return inputs_[0]; } | 3476 Value* left() const { return inputs_[0]; } |
| 3162 Value* right() const { return inputs_[1]; } | 3477 Value* right() const { return inputs_[1]; } |
| 3163 | 3478 |
| 3164 Token::Kind op_kind() const { return op_kind_; } | 3479 Token::Kind op_kind() const { return op_kind_; } |
| 3165 | 3480 |
| 3166 InstanceCallInstr* instance_call() const { return instance_call_; } | 3481 InstanceCallInstr* instance_call() const { return instance_call_; } |
| 3167 | 3482 |
| 3168 const ICData* ic_data() const { return instance_call()->ic_data(); } | 3483 const ICData* ic_data() const { return instance_call()->ic_data(); } |
| 3169 | 3484 |
| 3170 virtual void PrintOperandsTo(BufferFormatter* f) const; | 3485 virtual void PrintOperandsTo(BufferFormatter* f) const; |
| 3171 | 3486 |
| 3172 DECLARE_INSTRUCTION(BinarySmiOp) | 3487 DECLARE_INSTRUCTION(BinarySmiOp) |
| 3173 virtual RawAbstractType* CompileType() const; | 3488 virtual RawAbstractType* CompileType() const; |
| 3174 | 3489 |
| 3175 virtual bool CanDeoptimize() const; | 3490 virtual bool CanDeoptimize() const; |
| 3176 | 3491 |
| 3177 virtual bool HasSideEffect() const { return false; } | 3492 virtual bool HasSideEffect() const { return false; } |
| 3178 | 3493 |
| 3179 virtual bool AffectedBySideEffect() const { return false; } | 3494 virtual bool AffectedBySideEffect() const { return false; } |
| 3180 virtual bool AttributesEqual(Instruction* other) const; | 3495 virtual bool AttributesEqual(Instruction* other) const; |
|
Florian Schneider
2012/09/21 08:56:44
You need to update AttributesEqual to check of ove
Vyacheslav Egorov (Google)
2012/09/21 20:08:07
Yes, thanks for reminding me. I kept this in mind,
| |
| 3181 | 3496 |
| 3182 virtual intptr_t ResultCid() const; | 3497 virtual intptr_t ResultCid() const; |
| 3183 | 3498 |
| 3499 void set_overflow(bool overflow) { | |
| 3500 overflow_ = overflow; | |
| 3501 } | |
| 3502 | |
| 3503 void PrintTo(BufferFormatter* f) const; | |
| 3504 | |
| 3505 virtual bool InferRange(); | |
| 3506 virtual Range* range() { return range_; } | |
| 3507 | |
| 3184 private: | 3508 private: |
| 3185 const Token::Kind op_kind_; | 3509 const Token::Kind op_kind_; |
| 3186 InstanceCallInstr* instance_call_; | 3510 InstanceCallInstr* instance_call_; |
| 3511 bool overflow_; | |
| 3187 | 3512 |
| 3188 DISALLOW_COPY_AND_ASSIGN(BinarySmiOpInstr); | 3513 DISALLOW_COPY_AND_ASSIGN(BinarySmiOpInstr); |
| 3189 }; | 3514 }; |
| 3190 | 3515 |
| 3191 | 3516 |
| 3192 class BinaryMintOpInstr : public TemplateDefinition<2> { | 3517 class BinaryMintOpInstr : public TemplateDefinition<2> { |
| 3193 public: | 3518 public: |
| 3194 BinaryMintOpInstr(Token::Kind op_kind, | 3519 BinaryMintOpInstr(Token::Kind op_kind, |
| 3195 InstanceCallInstr* instance_call, | 3520 InstanceCallInstr* instance_call, |
| 3196 Value* left, | 3521 Value* left, |
| (...skipping 462 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3659 ForwardInstructionIterator* current_iterator_; | 3984 ForwardInstructionIterator* current_iterator_; |
| 3660 | 3985 |
| 3661 private: | 3986 private: |
| 3662 DISALLOW_COPY_AND_ASSIGN(FlowGraphVisitor); | 3987 DISALLOW_COPY_AND_ASSIGN(FlowGraphVisitor); |
| 3663 }; | 3988 }; |
| 3664 | 3989 |
| 3665 | 3990 |
| 3666 } // namespace dart | 3991 } // namespace dart |
| 3667 | 3992 |
| 3668 #endif // VM_INTERMEDIATE_LANGUAGE_H_ | 3993 #endif // VM_INTERMEDIATE_LANGUAGE_H_ |
| OLD | NEW |