12 class HInstructionMap
FINAL :
public ZoneObject {
20 free_list_head_(kNil),
21 side_effects_tracker_(side_effects_tracker) {
22 ResizeLists(kInitialSize, zone);
23 Resize(kInitialSize, zone);
26 void Kill(SideEffects side_effects);
29 present_depends_on_.Add(side_effects_tracker_->ComputeDependsOn(instr));
36 return new(zone) HInstructionMap(zone,
this);
39 bool IsEmpty()
const {
return count_ == 0; }
47 static const int kNil = -1;
50 static const int kInitialSize = 16;
77 HSideEffectMap& operator= (
const HSideEffectMap& other);
79 void Kill(SideEffects side_effects);
83 bool IsEmpty()
const {
return count_ == 0; }
100 va_start(arguments, msg);
108 #define TRACE_GVN_1(msg, a1) \
109 if (FLAG_trace_gvn) { \
113 #define TRACE_GVN_2(msg, a1, a2) \
114 if (FLAG_trace_gvn) { \
115 TraceGVN(msg, a1, a2); \
118 #define TRACE_GVN_3(msg, a1, a2, a3) \
119 if (FLAG_trace_gvn) { \
120 TraceGVN(msg, a1, a2, a3); \
123 #define TRACE_GVN_4(msg, a1, a2, a3, a4) \
124 if (FLAG_trace_gvn) { \
125 TraceGVN(msg, a1, a2, a3, a4); \
128 #define TRACE_GVN_5(msg, a1, a2, a3, a4, a5) \
129 if (FLAG_trace_gvn) { \
130 TraceGVN(msg, a1, a2, a3, a4, a5); \
134 HInstructionMap::HInstructionMap(Zone* zone,
const HInstructionMap* other)
135 : array_size_(other->array_size_),
136 lists_size_(other->lists_size_),
137 count_(other->count_),
138 present_depends_on_(other->present_depends_on_),
139 array_(zone->
NewArray<HInstructionMapListElement>(other->array_size_)),
140 lists_(zone->
NewArray<HInstructionMapListElement>(other->lists_size_)),
141 free_list_head_(other->free_list_head_),
142 side_effects_tracker_(other->side_effects_tracker_) {
144 array_size_ *
sizeof(HInstructionMapListElement));
146 lists_size_ *
sizeof(HInstructionMapListElement));
150 void HInstructionMap::Kill(SideEffects changes) {
151 if (!present_depends_on_.ContainsAnyOf(changes))
return;
152 present_depends_on_.RemoveAll();
153 for (
int i = 0;
i < array_size_; ++
i) {
154 HInstruction* instr = array_[
i].instr;
159 for (
int current = array_[
i].next; current != kNil; current = next) {
160 next = lists_[current].next;
161 HInstruction* instr = lists_[current].instr;
162 SideEffects depends_on = side_effects_tracker_->ComputeDependsOn(instr);
163 if (depends_on.ContainsAnyOf(changes)) {
166 lists_[current].next = free_list_head_;
167 free_list_head_ = current;
170 lists_[current].next = kept;
172 present_depends_on_.Add(depends_on);
175 array_[
i].next = kept;
178 instr = array_[
i].instr;
179 SideEffects depends_on = side_effects_tracker_->ComputeDependsOn(instr);
180 if (depends_on.ContainsAnyOf(changes)) {
182 int head = array_[
i].next;
184 array_[
i].instr =
NULL;
186 array_[
i].instr = lists_[head].instr;
187 array_[
i].next = lists_[head].next;
188 lists_[head].next = free_list_head_;
189 free_list_head_ = head;
192 present_depends_on_.Add(depends_on);
199 HInstruction* HInstructionMap::Lookup(HInstruction* instr)
const {
202 if (array_[pos].instr !=
NULL) {
203 if (array_[pos].instr->Equals(instr))
return array_[pos].instr;
204 int next = array_[pos].next;
205 while (next != kNil) {
206 if (lists_[next].instr->Equals(instr))
return lists_[next].instr;
207 next = lists_[next].next;
214 void HInstructionMap::Resize(
int new_size, Zone* zone) {
215 DCHECK(new_size > count_);
220 if (free_list_head_ == kNil) {
221 ResizeLists(lists_size_ << 1, zone);
224 HInstructionMapListElement* new_array =
225 zone->NewArray<HInstructionMapListElement>(new_size);
226 memset(new_array, 0,
sizeof(HInstructionMapListElement) * new_size);
228 HInstructionMapListElement* old_array = array_;
229 int old_size = array_size_;
231 int old_count = count_;
234 array_size_ = new_size;
237 if (old_array !=
NULL) {
239 for (
int i = 0;
i < old_size; ++
i) {
240 if (old_array[
i].instr !=
NULL) {
241 int current = old_array[
i].next;
242 while (current != kNil) {
243 Insert(lists_[current].instr, zone);
244 int next = lists_[current].next;
245 lists_[current].next = free_list_head_;
246 free_list_head_ = current;
250 Insert(old_array[
i].instr, zone);
255 DCHECK(count_ == old_count);
259 void HInstructionMap::ResizeLists(
int new_size, Zone* zone) {
260 DCHECK(new_size > lists_size_);
262 HInstructionMapListElement* new_lists =
263 zone->NewArray<HInstructionMapListElement>(new_size);
264 memset(new_lists, 0,
sizeof(HInstructionMapListElement) * new_size);
266 HInstructionMapListElement* old_lists = lists_;
267 int old_size = lists_size_;
269 lists_size_ = new_size;
272 if (old_lists !=
NULL) {
273 MemCopy(lists_, old_lists, old_size *
sizeof(HInstructionMapListElement));
275 for (
int i = old_size;
i < lists_size_; ++
i) {
276 lists_[
i].next = free_list_head_;
282 void HInstructionMap::Insert(HInstruction* instr, Zone* zone) {
285 if (count_ >= array_size_ >> 1) Resize(array_size_ << 1, zone);
286 DCHECK(count_ < array_size_);
289 if (array_[pos].instr ==
NULL) {
290 array_[pos].instr = instr;
291 array_[pos].next = kNil;
293 if (free_list_head_ == kNil) {
294 ResizeLists(lists_size_ << 1, zone);
296 int new_element_pos = free_list_head_;
297 DCHECK(new_element_pos != kNil);
298 free_list_head_ = lists_[free_list_head_].next;
299 lists_[new_element_pos].instr = instr;
300 lists_[new_element_pos].next = array_[pos].next;
301 DCHECK(array_[pos].next == kNil || lists_[array_[pos].next].instr !=
NULL);
302 array_[pos].next = new_element_pos;
307 HSideEffectMap::HSideEffectMap() : count_(0) {
312 HSideEffectMap::HSideEffectMap(HSideEffectMap* other) : count_(other->count_) {
317 HSideEffectMap& HSideEffectMap::operator=(
const HSideEffectMap& other) {
318 if (
this != &other) {
325 void HSideEffectMap::Kill(SideEffects side_effects) {
328 if (data_[
i] !=
NULL) count_--;
335 void HSideEffectMap::Store(SideEffects side_effects, HInstruction* instr) {
338 if (data_[
i] ==
NULL) count_++;
345 SideEffects SideEffectsTracker::ComputeChanges(HInstruction* instr) {
347 SideEffects result(instr->ChangesFlags());
348 if (result.ContainsFlag(kGlobalVars)) {
349 if (instr->IsStoreGlobalCell() &&
350 ComputeGlobalVar(HStoreGlobalCell::cast(instr)->cell(), &index)) {
351 result.RemoveFlag(kGlobalVars);
352 result.AddSpecial(GlobalVar(index));
354 for (index = 0; index < kNumberOfGlobalVars; ++index) {
355 result.AddSpecial(GlobalVar(index));
359 if (result.ContainsFlag(kInobjectFields)) {
360 if (instr->IsStoreNamedField() &&
361 ComputeInobjectField(HStoreNamedField::cast(instr)->access(), &index)) {
362 result.RemoveFlag(kInobjectFields);
363 result.AddSpecial(InobjectField(index));
365 for (index = 0; index < kNumberOfInobjectFields; ++index) {
366 result.AddSpecial(InobjectField(index));
374 SideEffects SideEffectsTracker::ComputeDependsOn(HInstruction* instr) {
376 SideEffects result(instr->DependsOnFlags());
377 if (result.ContainsFlag(kGlobalVars)) {
378 if (instr->IsLoadGlobalCell() &&
379 ComputeGlobalVar(HLoadGlobalCell::cast(instr)->cell(), &index)) {
380 result.RemoveFlag(kGlobalVars);
381 result.AddSpecial(GlobalVar(index));
383 for (index = 0; index < kNumberOfGlobalVars; ++index) {
384 result.AddSpecial(GlobalVar(index));
388 if (result.ContainsFlag(kInobjectFields)) {
389 if (instr->IsLoadNamedField() &&
390 ComputeInobjectField(HLoadNamedField::cast(instr)->access(), &index)) {
391 result.RemoveFlag(kInobjectFields);
392 result.AddSpecial(InobjectField(index));
394 for (index = 0; index < kNumberOfInobjectFields; ++index) {
395 result.AddSpecial(InobjectField(index));
404 SideEffectsTracker* t = te.
tracker;
405 const char* separator =
"";
413 #define DECLARE_FLAG(Type) \
425 for (
int index = 0; index < t->num_global_vars_; ++index) {
426 if (te.
effects.ContainsSpecial(t->GlobalVar(index))) {
427 os << separator <<
"[" << *t->global_vars_[index].handle() <<
"]";
431 for (
int index = 0; index < t->num_inobject_fields_; ++index) {
432 if (te.
effects.ContainsSpecial(t->InobjectField(index))) {
433 os << separator << t->inobject_fields_[index];
442 bool SideEffectsTracker::ComputeGlobalVar(
Unique<Cell> cell,
int* index) {
443 for (
int i = 0;
i < num_global_vars_; ++
i) {
444 if (cell == global_vars_[
i]) {
449 if (num_global_vars_ < kNumberOfGlobalVars) {
450 if (FLAG_trace_gvn) {
452 os <<
"Tracking global var [" << *cell.
handle() <<
"] "
453 <<
"(mapped to index " << num_global_vars_ <<
")" <<
endl;
455 *index = num_global_vars_;
456 global_vars_[num_global_vars_++] = cell;
463 bool SideEffectsTracker::ComputeInobjectField(HObjectAccess access,
465 for (
int i = 0;
i < num_inobject_fields_; ++
i) {
466 if (access.Equals(inobject_fields_[
i])) {
471 if (num_inobject_fields_ < kNumberOfInobjectFields) {
472 if (FLAG_trace_gvn) {
474 os <<
"Tracking inobject field access " << access <<
" (mapped to index "
475 << num_inobject_fields_ <<
")" <<
endl;
477 *index = num_inobject_fields_;
478 inobject_fields_[num_inobject_fields_++] = access;
485 HGlobalValueNumberingPhase::HGlobalValueNumberingPhase(HGraph* graph)
486 : HPhase(
"H_Global value numbering", graph),
487 removed_side_effects_(
false),
488 block_side_effects_(graph->blocks()->length(), zone()),
489 loop_side_effects_(graph->blocks()->length(), zone()),
490 visited_on_paths_(graph->blocks()->length(), zone()) {
491 DCHECK(!AllowHandleAllocation::IsAllowed());
492 block_side_effects_.AddBlock(
493 SideEffects(),
graph->blocks()->length(),
zone());
494 loop_side_effects_.AddBlock(
495 SideEffects(),
graph->blocks()->length(),
zone());
499 void HGlobalValueNumberingPhase::Run() {
500 DCHECK(!removed_side_effects_);
501 for (
int i = FLAG_gvn_iterations;
i > 0; --
i) {
503 ComputeBlockSideEffects();
506 if (FLAG_loop_invariant_code_motion) LoopInvariantCodeMotion();
512 if (!removed_side_effects_)
break;
513 removed_side_effects_ =
false;
516 DCHECK_EQ(block_side_effects_.length(), graph()->blocks()->length());
517 DCHECK_EQ(loop_side_effects_.length(), graph()->blocks()->length());
518 for (
int i = 0;
i < graph()->blocks()->length(); ++
i) {
519 block_side_effects_[
i].RemoveAll();
520 loop_side_effects_[
i].RemoveAll();
522 visited_on_paths_.Clear();
527 void HGlobalValueNumberingPhase::ComputeBlockSideEffects() {
528 for (
int i = graph()->blocks()->length() - 1;
i >= 0; --
i) {
530 HBasicBlock* block = graph()->blocks()->at(
i);
531 SideEffects side_effects;
532 if (block->IsReachable() && !block->IsDeoptimizing()) {
533 int id = block->block_id();
534 for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
535 HInstruction* instr = it.Current();
536 side_effects.Add(side_effects_tracker_.ComputeChanges(instr));
538 block_side_effects_[id].Add(side_effects);
541 if (block->IsLoopHeader()) {
542 loop_side_effects_[id].Add(side_effects);
546 if (block->HasParentLoopHeader()) {
547 HBasicBlock* with_parent = block;
548 if (block->IsLoopHeader()) side_effects = loop_side_effects_[id];
550 HBasicBlock* parent_block = with_parent->parent_loop_header();
551 loop_side_effects_[parent_block->block_id()].Add(side_effects);
552 with_parent = parent_block;
553 }
while (with_parent->HasParentLoopHeader());
560 void HGlobalValueNumberingPhase::LoopInvariantCodeMotion() {
561 TRACE_GVN_1(
"Using optimistic loop invariant code motion: %s\n",
562 graph()->use_optimistic_licm() ?
"yes" :
"no");
563 for (
int i = graph()->blocks()->length() - 1;
i >= 0; --
i) {
564 HBasicBlock* block = graph()->blocks()->at(
i);
565 if (block->IsLoopHeader()) {
566 SideEffects side_effects = loop_side_effects_[block->block_id()];
567 if (FLAG_trace_gvn) {
569 os <<
"Try loop invariant motion for " << *block <<
" changes "
570 << Print(side_effects) <<
endl;
572 HBasicBlock* last = block->loop_information()->GetLastBackEdge();
573 for (
int j = block->block_id(); j <= last->block_id(); ++j) {
574 ProcessLoopBlock(graph()->blocks()->at(j), block, side_effects);
581 void HGlobalValueNumberingPhase::ProcessLoopBlock(
583 HBasicBlock* loop_header,
584 SideEffects loop_kills) {
585 HBasicBlock* pre_header = loop_header->predecessors()->at(0);
586 if (FLAG_trace_gvn) {
588 os <<
"Loop invariant code motion for " << *block <<
" depends on "
589 << Print(loop_kills) <<
endl;
591 HInstruction* instr = block->first();
592 while (instr !=
NULL) {
593 HInstruction* next = instr->next();
595 SideEffects changes = side_effects_tracker_.ComputeChanges(instr);
596 SideEffects depends_on = side_effects_tracker_.ComputeDependsOn(instr);
597 if (FLAG_trace_gvn) {
599 os <<
"Checking instruction i" << instr->id() <<
" ("
600 << instr->Mnemonic() <<
") changes " << Print(changes)
601 <<
", depends on " << Print(depends_on) <<
". Loop changes "
602 << Print(loop_kills) <<
endl;
604 bool can_hoist = !depends_on.ContainsAnyOf(loop_kills);
605 if (can_hoist && !graph()->use_optimistic_licm()) {
606 can_hoist = block->IsLoopSuccessorDominator();
610 bool inputs_loop_invariant =
true;
611 for (
int i = 0;
i < instr->OperandCount(); ++
i) {
612 if (instr->OperandAt(
i)->IsDefinedAfter(pre_header)) {
613 inputs_loop_invariant =
false;
617 if (inputs_loop_invariant && ShouldMove(instr, loop_header)) {
618 TRACE_GVN_2(
"Hoisting loop invariant instruction i%d to block B%d\n",
619 instr->id(), pre_header->block_id());
622 instr->InsertBefore(pre_header->end());
623 if (instr->HasSideEffects()) removed_side_effects_ =
true;
632 bool HGlobalValueNumberingPhase::AllowCodeMotion() {
633 return info()->IsStub() || info()->opt_count() + 1 < FLAG_max_opt_count;
637 bool HGlobalValueNumberingPhase::ShouldMove(HInstruction* instr,
638 HBasicBlock* loop_header) {
641 return AllowCodeMotion() && !instr->block()->IsDeoptimizing() &&
642 instr->block()->IsReachable();
647 HGlobalValueNumberingPhase::CollectSideEffectsOnPathsToDominatedBlock(
648 HBasicBlock* dominator, HBasicBlock* dominated) {
649 SideEffects side_effects;
650 for (
int i = 0;
i < dominated->predecessors()->length(); ++
i) {
651 HBasicBlock* block = dominated->predecessors()->at(
i);
652 if (dominator->block_id() < block->block_id() &&
653 block->block_id() < dominated->block_id() &&
654 !visited_on_paths_.Contains(block->block_id())) {
655 visited_on_paths_.Add(block->block_id());
656 side_effects.Add(block_side_effects_[block->block_id()]);
657 if (block->IsLoopHeader()) {
658 side_effects.Add(loop_side_effects_[block->block_id()]);
660 side_effects.Add(CollectSideEffectsOnPathsToDominatedBlock(
677 HBasicBlock* entry_block,
678 HInstructionMap* entry_map) {
689 HBasicBlock** dominator) {
692 *dominator =
block();
694 if (result ==
NULL) {
696 if (dominator_state !=
NULL) {
699 *dominator = dominator_state->
block();
711 HInstructionMap*
map,
727 HInstructionMap*
map,
763 TRACE_GVN_2(
"Backtracking from block B%d to block b%d\n",
785 void HGlobalValueNumberingPhase::AnalyzeGraph() {
786 HBasicBlock* entry_block = graph()->entry_block();
787 HInstructionMap* entry_map =
788 new(zone()) HInstructionMap(zone(), &side_effects_tracker_);
792 while (current !=
NULL) {
793 HBasicBlock* block = current->
block();
794 HInstructionMap*
map = current->
map();
795 HSideEffectMap* dominators = current->
dominators();
799 block->IsLoopHeader() ?
" (loop header)" :
"");
802 if (block->IsLoopHeader()) {
803 map->Kill(loop_side_effects_[block->block_id()]);
804 dominators->Kill(loop_side_effects_[block->block_id()]);
808 for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
812 HValue* other = dominators->at(
i);
815 TRACE_GVN_5(
"Side-effect #%d in %d (%s) is dominated by %d (%s)\n",
822 removed_side_effects_ =
true;
830 SideEffects changes = side_effects_tracker_.ComputeChanges(instr);
831 if (!changes.IsEmpty()) {
835 dominators->Store(changes, instr);
836 if (FLAG_trace_gvn) {
838 os <<
"Instruction i" << instr->
id() <<
" changes " << Print(changes)
848 TRACE_GVN_4(
"Replacing instruction i%d (%s) with i%d (%s)\n",
856 map->Add(instr, zone());
861 HBasicBlock* dominator_block;
867 HBasicBlock* dominated = next->
block();
868 HInstructionMap* successor_map = next->
map();
869 HSideEffectMap* successor_dominators = next->
dominators();
876 if ((!successor_map->IsEmpty() || !successor_dominators->IsEmpty()) &&
877 dominator_block->block_id() + 1 < dominated->block_id()) {
878 visited_on_paths_.Clear();
879 SideEffects side_effects_on_all_paths =
880 CollectSideEffectsOnPathsToDominatedBlock(dominator_block,
882 successor_map->Kill(side_effects_on_all_paths);
883 successor_dominators->Kill(side_effects_on_all_paths);
static void VPrint(const char *format, va_list args)
HInstruction * operator[](int i) const
void Store(SideEffects side_effects, HInstruction *instr)
void Kill(SideEffects side_effects)
HSideEffectMap(HSideEffectMap *other)
HInstruction * at(int i) const
bool Contains(E element) const
Source to read snapshot and builtins files from.
void ResizeLists(int new_size, Zone *zone)
SideEffectsTracker * side_effects_tracker_
HInstructionMap(Zone *zone, const HInstructionMap *other)
HInstructionMap(Zone *zone, SideEffectsTracker *side_effects_tracker)
HInstruction * Lookup(HInstruction *instr) const
void Resize(int new_size, Zone *zone)
void Kill(SideEffects side_effects)
HInstructionMapListElement * array_
HInstructionMapListElement * lists_
void Insert(HInstruction *instr, Zone *zone)
HInstructionMap * Copy(Zone *zone) const
void Add(HInstruction *instr, Zone *zone)
uint32_t Bound(uint32_t value) const
SideEffects present_depends_on_
static GvnBasicBlockState * CreateEntry(Zone *zone, HBasicBlock *entry_block, HInstructionMap *entry_map)
HSideEffectMap * dominators()
GvnBasicBlockState * next_
GvnBasicBlockState * next_in_dominator_tree_traversal(Zone *zone, HBasicBlock **dominator)
GvnBasicBlockState * push(Zone *zone, HBasicBlock *block)
GvnBasicBlockState * next_dominated(Zone *zone)
HSideEffectMap dominators_
GvnBasicBlockState * pop()
GvnBasicBlockState * previous_
void Initialize(HBasicBlock *block, HInstructionMap *map, HSideEffectMap *dominators, bool copy_map, Zone *zone)
GvnBasicBlockState(GvnBasicBlockState *previous, HBasicBlock *block, HInstructionMap *map, HSideEffectMap *dominators, Zone *zone)
bool Equals(HValue *other)
bool HasSideEffects() const
bool HasObservableSideEffects() const
GVNFlagSet DependsOnFlags() const
const char * Mnemonic() const
bool CheckFlag(Flag f) const
@ kTrackSideEffectDominators
void DeleteAndReplaceWith(HValue *other)
virtual bool HandleSideEffectDominator(GVNFlag side_effect, HValue *dominator)
Handle< T > handle() const
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf map
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be NULL
#define TRACE_GVN_1(msg, a1)
#define TRACE_GVN_2(msg, a1, a2)
#define TRACE_GVN_4(msg, a1, a2, a3, a4)
#define TRACE_GVN_5(msg, a1, a2, a3, a4, a5)
#define DECLARE_FLAG(Type)
#define GVN_TRACKED_FLAG_LIST(V)
#define GVN_UNTRACKED_FLAG_LIST(V)
#define DCHECK(condition)
#define DCHECK_EQ(v1, v2)
static GVNFlag GVNFlagFromInt(int i)
T * NewArray(size_t size)
void TraceGVN(const char *msg,...)
@ kNumberOfTrackedSideEffects
OStream & endl(OStream &os)
kFeedbackVectorOffset flag
OStream & operator<<(OStream &os, const TrackedEffects &te)
void MemCopy(void *dest, const void *src, size_t size)
Debugger support for the V8 JavaScript engine.
SideEffectsTracker * tracker