Flutter Engine
The Flutter Engine
flow_graph.h
Go to the documentation of this 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
3// BSD-style license that can be found in the LICENSE file.
4
5#ifndef RUNTIME_VM_COMPILER_BACKEND_FLOW_GRAPH_H_
6#define RUNTIME_VM_COMPILER_BACKEND_FLOW_GRAPH_H_
7
8#if defined(DART_PRECOMPILED_RUNTIME)
9#error "AOT runtime should not use compiler sources (including header files)"
10#endif // defined(DART_PRECOMPILED_RUNTIME)
11
12#include <utility>
13
14#include "vm/bit_vector.h"
17#include "vm/growable_array.h"
18#include "vm/hash_map.h"
19#include "vm/parser.h"
20#include "vm/thread.h"
21
22namespace dart {
23
24class LoopHierarchy;
25class VariableLivenessAnalysis;
26
27namespace compiler {
28class GraphIntrinsifier;
29}
30
31class BlockIterator : public ValueObject {
32 public:
34 : block_order_(block_order), current_(0) {}
35
37 : ValueObject(),
38 block_order_(other.block_order_),
39 current_(other.current_) {}
40
41 void Advance() {
42 ASSERT(!Done());
43 current_++;
44 }
45
46 bool Done() const { return current_ >= block_order_.length(); }
47
48 BlockEntryInstr* Current() const { return block_order_[current_]; }
49
50 private:
51 const GrowableArray<BlockEntryInstr*>& block_order_;
52 intptr_t current_;
53};
54
58};
59
64
65 static Key KeyOf(Pair kv) {
67 }
68
69 static Value ValueOf(Pair kv) { return kv; }
70
71 static inline uword Hash(Key key) {
72 if (key.constant.IsSmi()) {
73 return Smi::Cast(key.constant).Value();
74 }
75 if (key.constant.IsDouble()) {
76 return static_cast<intptr_t>(bit_cast<int32_t, float>(
77 static_cast<float>(Double::Cast(key.constant).value())));
78 }
79 if (key.constant.IsMint()) {
80 return static_cast<intptr_t>(Mint::Cast(key.constant).value());
81 }
82 if (key.constant.IsString()) {
83 return String::Cast(key.constant).Hash();
84 }
85 return key.constant.GetClassId();
86 }
87
88 static inline bool IsKeyEqual(Pair kv, Key key) {
89 return (kv->value().ptr() == key.constant.ptr()) &&
90 (kv->representation() == key.representation);
91 }
92};
93
95 // The first blockid used for prologue building. This information can be used
96 // by the inliner for budget calculations: The prologue code falls away when
97 // inlining, so we should not include it in the budget.
98 intptr_t min_block_id;
99
100 // The last blockid used for prologue building. This information can be used
101 // by the inliner for budget calculations: The prologue code falls away when
102 // inlining, so we should not include it in the budget.
103 intptr_t max_block_id;
104
105 PrologueInfo(intptr_t min, intptr_t max)
107
108 bool Contains(intptr_t block_id) const {
109 return min_block_id <= block_id && block_id <= max_block_id;
110 }
111};
112
113// Class to encapsulate the construction and manipulation of the flow graph.
114class FlowGraph : public ZoneAllocated {
115 public:
116 enum class CompilationMode {
117 kUnoptimized,
118 kOptimized,
119 kIntrinsic,
120 };
121
124 intptr_t max_block_id,
126 CompilationMode compilation_mode);
127
128 // Function properties.
129 const ParsedFunction& parsed_function() const { return parsed_function_; }
130 const Function& function() const { return parsed_function_.function(); }
131
132 void Print(const char* phase = "unknown");
133
134 // The number of directly accessable parameters (above the frame pointer).
135 // All other parameters can only be indirectly loaded via metadata found in
136 // the arguments descriptor.
137 intptr_t num_direct_parameters() const { return num_direct_parameters_; }
138
139 // The number of variables (or boxes) which code can load from / store to.
140 // The SSA renaming will insert phi's for them (and only them - i.e. there
141 // will be no phi insertion for [LocalVariable]s pointing to the expression
142 // stack!).
143 intptr_t variable_count() const {
144 return num_direct_parameters_ + parsed_function_.num_stack_locals();
145 }
146
147 // The number of variables during OSR, which may include stack slots
148 // that pass in initial contents for the expression stack.
149 intptr_t osr_variable_count() const {
152 }
153
155 intptr_t index);
156
158
159 // The number of variables (or boxes) inside the functions frame - meaning
160 // below the frame pointer. This does not include the expression stack.
161 intptr_t num_stack_locals() const {
162 return parsed_function_.num_stack_locals();
163 }
164
165 bool IsIrregexpFunction() const { return function().IsIrregexpFunction(); }
166
169 }
170
171 intptr_t SuspendStateEnvIndex() const { return EnvIndex(SuspendStateVar()); }
172
175 }
176
177 intptr_t CurrentContextEnvIndex() const {
178 return EnvIndex(parsed_function().current_context_var());
179 }
180
181 intptr_t RawTypeArgumentEnvIndex() const {
182 return EnvIndex(parsed_function().RawTypeArgumentsVariable());
183 }
184
185 intptr_t ArgumentDescriptorEnvIndex() const {
186 return EnvIndex(parsed_function().arg_desc_var());
187 }
188
189 intptr_t EnvIndex(const LocalVariable* variable) const {
190 ASSERT(!variable->is_captured());
191 return num_direct_parameters_ - variable->index().value();
192 }
193
194 // Context and :suspend_state variables are never pruned and
195 // artificially kept alive.
196 bool IsImmortalVariable(intptr_t env_index) const {
197 return (env_index == CurrentContextEnvIndex()) ||
198 (SuspendStateVar() != nullptr &&
199 env_index == SuspendStateEnvIndex());
200 }
201
202 // Flow graph orders.
203 const GrowableArray<BlockEntryInstr*>& preorder() const { return preorder_; }
205 return postorder_;
206 }
208 return reverse_postorder_;
209 }
211 return optimized_block_order_;
212 }
213
214 // In AOT these are guaranteed to be topologically sorted, but not in JIT.
217
218 // Iterators.
221 }
223 return BlockIterator(postorder());
224 }
225
226 void EnsureSSATempIndex(Definition* defn, Definition* replacement);
227
229 Instruction* current,
230 Instruction* replacement);
231
233 const Cids& cids,
234 intptr_t deopt_id,
236
238 Definition* index,
239 intptr_t deopt_id);
240
241 void AddExactnessGuard(InstanceCallInstr* call, intptr_t receiver_cid);
242
243 intptr_t current_ssa_temp_index() const { return current_ssa_temp_index_; }
244 void set_current_ssa_temp_index(intptr_t index) {
245 current_ssa_temp_index_ = index;
246 }
247
248 intptr_t max_vreg() const {
250 }
251
252 enum class ToCheck { kNoCheck, kCheckNull, kCheckCid };
253
254 // Uses CHA to determine if the called method can be overridden.
255 // Return value indicates that the call needs no check at all,
256 // just a null check, or a full class check.
258 UntaggedFunction::Kind kind) const;
259
260 Thread* thread() const { return thread_; }
261 Zone* zone() const { return thread()->zone(); }
263
264 intptr_t max_block_id() const { return max_block_id_; }
265 void set_max_block_id(intptr_t id) { max_block_id_ = id; }
266 intptr_t allocate_block_id() { return ++max_block_id_; }
267
268 GraphEntryInstr* graph_entry() const { return graph_entry_; }
269
270 ConstantInstr* constant_null() const { return constant_null_; }
271
272 ConstantInstr* constant_dead() const { return constant_dead_; }
273
275 def->set_ssa_temp_index(current_ssa_temp_index_);
276 current_ssa_temp_index_++;
277 }
278
279 intptr_t InstructionCount() const;
280
281 // Returns the definition for the object from the constant pool if
282 // one exists, otherwise returns nullptr.
284 const Object& object,
285 Representation representation = kTagged) const;
286
287 // Always returns a definition for the object from the constant pool,
288 // allocating one if it doesn't already exist.
289 ConstantInstr* GetConstant(const Object& object,
290 Representation representation = kTagged);
291
294 Definition* defn);
295
296 // Tries to create a constant definition with the given value which can be
297 // used to replace the given operation. Ensures that the representation of
298 // the replacement matches the representation of the original definition.
299 // If the given value can't be represented using matching representation
300 // then returns op itself.
302 const Object& value);
303
304 // Returns true if the given constant value can be represented in the given
305 // representation.
306 static bool IsConstantRepresentable(const Object& value,
307 Representation target_rep,
308 bool tagged_value_must_be_smi);
309
311
313 Instruction* instr,
315 UseKind use_kind) {
316 InsertAfter(next->previous(), instr, env, use_kind);
317 }
319 Instruction* instr,
321 UseKind use_kind) {
322 InsertSpeculativeAfter(next->previous(), instr, env, use_kind);
323 }
325 Instruction* instr,
327 UseKind use_kind);
328
329 // Inserts a speculative [instr] after existing [prev] instruction.
330 //
331 // If the inserted [instr] deopts eagerly or lazily we will always continue in
332 // unoptimized code at before-call using the given [env].
333 //
334 // This is mainly used during inlining / call specializing when replacing
335 // calls with N specialized instructions where the inserted [1..N[
336 // instructions cannot continue in unoptimized code after-call since they
337 // would miss instructions following the one that lazy-deopted.
338 //
339 // For example specializing an instance call to an implicit field setter
340 //
341 // InstanceCall:<id>(v0, set:<name>, args = [v1])
342 //
343 // to
344 //
345 // v2 <- AssertAssignable:<id>(v1, ...)
346 // StoreField(v0, v2)
347 //
348 // If the [AssertAssignable] causes a lazy-deopt on return, we'll have to
349 // *re-try* the implicit setter call in unoptimized mode, i.e. lazy deopt to
350 // before-call (otherwise - if we continued after-call - the
351 // StoreField would not be performed).
353 Instruction* instr,
355 UseKind use_kind);
357 Instruction* instr,
359 UseKind use_kind);
361 Instruction* instr,
363 UseKind use_kind);
364
365 // Operations on the flow graph.
366 void ComputeSSA(ZoneGrowableArray<Definition*>* inlining_parameters);
367
368 // Verification method for debugging.
369 bool VerifyRedefinitions();
370
371 void DiscoverBlocks();
372
373 void MergeBlocks();
374
375 // Insert a redefinition of an original definition after prev and rename all
376 // dominated uses of the original. If an equivalent redefinition is already
377 // present, nothing is inserted.
378 // Returns the redefinition, if a redefinition was inserted, nullptr
379 // otherwise.
381 Definition* original,
382 CompileType compile_type);
383
384 // Remove the redefinition instructions inserted to inhibit code motion.
385 void RemoveRedefinitions(bool keep_checks = false);
386
387 // Insert MoveArgument instructions and remove explicit def-use
388 // relations between calls and their arguments.
389 //
390 // Compute the maximum number of arguments.
391 void InsertMoveArguments();
392
393 // Copy deoptimization target from one instruction to another if we still
394 // have to keep deoptimization environment at gotos for LICM purposes.
396 if (is_licm_allowed()) {
397 to->InheritDeoptTarget(zone(), from);
398 }
399 }
400
401 // Returns true if every Goto in the graph is expected to have a
402 // deoptimization environment and can be used as deoptimization target
403 // for hoisted instructions.
404 bool is_licm_allowed() const { return licm_allowed_; }
405
406 // Stop preserving environments on Goto instructions. LICM is not allowed
407 // after this point.
408 void disallow_licm() { licm_allowed_ = false; }
409
410 // Returns true if mismatch in input/output representations is allowed.
412 return unmatched_representations_allowed_;
413 }
414
415 // After the last SelectRepresentations pass all further transformations
416 // should maintain matching input/output representations.
418 unmatched_representations_allowed_ = false;
419 }
420
421 // Returns true if this flow graph was built for a huge method
422 // and certain optimizations should be disabled.
423 bool is_huge_method() const { return huge_method_; }
424 // Mark this flow graph as huge and disable certain optimizations.
425 void mark_huge_method() { huge_method_ = true; }
426
427 PrologueInfo prologue_info() const { return prologue_info_; }
428
429 // Computes the loop hierarchy of the flow graph on demand.
431 if (loop_hierarchy_ == nullptr) {
432 loop_hierarchy_ = ComputeLoops();
433 }
434 return loop_hierarchy();
435 }
436
437 const LoopHierarchy& loop_hierarchy() const { return *loop_hierarchy_; }
438
439 // Resets the loop hierarchy of the flow graph. Use this to
440 // force a recomputation of loop detection by the next call
441 // to GetLoopHierarchy() (note that this does not immediately
442 // reset the loop_info fields of block entries, although
443 // these will be overwritten by that next call).
445 loop_hierarchy_ = nullptr;
446 loop_invariant_loads_ = nullptr;
447 }
448
449 // Per loop header invariant loads sets. Each set contains load id for
450 // those loads that are not affected by anything in the loop and can be
451 // hoisted out. Sets are computed by LoadOptimizer.
453 return loop_invariant_loads_;
454 }
457 loop_invariant_loads_ = loop_invariant_loads;
458 }
459
460 bool IsCompiledForOsr() const { return graph_entry()->IsCompiledForOsr(); }
461
462 BitVector* captured_parameters() const { return captured_parameters_; }
463
464 intptr_t inlining_id() const { return inlining_id_; }
465 void set_inlining_id(intptr_t value) { inlining_id_ = value; }
466
467 // Returns true if any instructions were canonicalized away.
468 bool Canonicalize();
469
470 // Attaches new ICData's to static/instance calls which don't already have
471 // them.
473
475
476 // Remove environments from the instructions which do not deoptimize.
478
479 // Extract typed data payloads prior to any LoadIndexed, StoreIndexed, or
480 // MemoryCopy instruction where the incoming typed data array(s) are not
481 // proven to be internal typed data objects at compile time.
482 //
483 // Once this is done, no intra-block code motion should be performed.
485
486 bool IsReceiver(Definition* def) const;
487
488 // Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the
489 // shift can be a truncating Smi shift-left and result is always Smi.
490 // Merge instructions (only per basic-block).
491 void TryOptimizePatterns();
492
493 // Replaces uses that are dominated by dom of 'def' with 'other'.
494 // Note: uses that occur at instruction dom itself are not dominated by it.
495 static void RenameDominatedUses(Definition* def,
497 Definition* other);
498
499 // Renames uses of redefined values to make sure that uses of redefined
500 // values that are dominated by a redefinition are renamed.
502
503 bool should_print() const { return should_print_; }
504 const uint8_t* compiler_pass_filters() const {
505 return compiler_pass_filters_;
506 }
507
508 bool should_reorder_blocks() const { return should_reorder_blocks_; }
509
511 return should_remove_all_bounds_checks_;
512 }
513
514 //
515 // High-level utilities.
516 //
517
518 // Logical-AND (for use in short-circuit diamond).
519 struct LogicalAnd {
523 };
524
525 // Constructs a diamond control flow at the instruction, inheriting
526 // properties from inherit and using the given compare. Returns the
527 // join (and true/false blocks in out parameters). Updates dominance
528 // relation, but not the succ/pred ordering on block.
530 Instruction* inherit,
532 TargetEntryInstr** block_true,
533 TargetEntryInstr** block_false);
534
535 // As above, but with a short-circuit on two comparisons.
537 Instruction* inherit,
538 const LogicalAnd& condition,
539 TargetEntryInstr** block_true,
540 TargetEntryInstr** block_false);
541
542 // Adds a 2-way phi.
544
545 // SSA transformation methods and fields.
546 void ComputeDominators(GrowableArray<BitVector*>* dominance_frontier);
547
549
550 const Array& coverage_array() const { return *coverage_array_; }
551 void set_coverage_array(const Array& array) { coverage_array_ = &array; }
552
553 // Renumbers SSA values and basic blocks to make numbering dense.
554 // Preserves order among block ids.
555 //
556 // Also collects definitions which are detached from the flow graph
557 // but still referenced (currently only MaterializeObject instructions
558 // can be detached).
559 void CompactSSA(ZoneGrowableArray<Definition*>* detached_defs = nullptr);
560
561 // Maximum number of word-sized slots needed for outgoing arguments.
562 intptr_t max_argument_slot_count() const {
563 RELEASE_ASSERT(max_argument_slot_count_ >= 0);
564 return max_argument_slot_count_;
565 }
567 RELEASE_ASSERT(max_argument_slot_count_ == -1);
568 max_argument_slot_count_ = count;
569 }
570
571 const std::pair<Location, Representation>& GetDirectParameterInfoAt(
572 intptr_t i) {
573 return direct_parameter_locations_[i];
574 }
575
576 static intptr_t ComputeLocationsOfFixedParameters(
577 Zone* zone,
578 const Function& function,
579 bool should_assign_stack_locations = false,
580 compiler::ParameterInfoArray* parameter_info = nullptr);
581
582 static intptr_t ComputeArgumentsSizeInWords(const Function& function,
583 intptr_t arguments_count);
584
585 static constexpr CompilationMode CompilationModeFrom(bool is_optimizing) {
586 return is_optimizing ? CompilationMode::kOptimized
588 }
589
590 // If either IsExternalPayloadClassId([cid]) or
591 // IsExternalPayloadClassId(array()->Type()->ToCid()) is true and
592 // [array] (an input of [instr]) is tagged, inserts a load of the array
593 // payload as an untagged pointer and rebinds [array] to the new load.
594 //
595 // Otherwise does not change the flow graph.
596 //
597 // Returns whether any changes were made to the flow graph.
599 Value* array,
600 classid_t cid);
601
602 private:
603 friend class FlowGraphCompiler; // TODO(ajcbik): restructure
604 friend class FlowGraphChecker;
605 friend class IfConverter;
606 friend class BranchSimplifier;
607 friend class ConstantPropagator;
610
611 void CompressPath(intptr_t start_index,
612 intptr_t current_index,
615
616 void AddSyntheticPhis(BlockEntryInstr* block);
617
618 void Rename(GrowableArray<PhiInstr*>* live_phis,
619 VariableLivenessAnalysis* variable_liveness,
620 ZoneGrowableArray<Definition*>* inlining_parameters);
621 void RenameRecursive(BlockEntryInstr* block_entry,
623 GrowableArray<PhiInstr*>* live_phis,
624 VariableLivenessAnalysis* variable_liveness,
625 ZoneGrowableArray<Definition*>* inlining_parameters);
626#if defined(DEBUG)
627 // Validates no phis are missing on join entry instructions.
628 void ValidatePhis();
629#endif // defined(DEBUG)
630
631 void PopulateEnvironmentFromFunctionEntry(
632 FunctionEntryInstr* function_entry,
634 GrowableArray<PhiInstr*>* live_phis,
635 VariableLivenessAnalysis* variable_liveness,
636 ZoneGrowableArray<Definition*>* inlining_parameters);
637
638 void PopulateEnvironmentFromOsrEntry(OsrEntryInstr* osr_entry,
640
641 void PopulateEnvironmentFromCatchEntry(CatchBlockEntryInstr* catch_entry,
643
644 void AttachEnvironment(Instruction* instr, GrowableArray<Definition*>* env);
645
646 void InsertPhis(const GrowableArray<BlockEntryInstr*>& preorder,
647 const GrowableArray<BitVector*>& assigned_vars,
648 const GrowableArray<BitVector*>& dom_frontier,
649 GrowableArray<PhiInstr*>* live_phis);
650
651 void RemoveDeadPhis(GrowableArray<PhiInstr*>* live_phis);
652
653 void ReplacePredecessor(BlockEntryInstr* old_block,
654 BlockEntryInstr* new_block);
655
656 // Finds the blocks in the natural loop for the back edge m->n. The
657 // algorithm is described in "Advanced Compiler Design & Implementation"
658 // (Muchnick) p192. Returns a BitVector indexed by block pre-order
659 // number where each bit indicates membership in the loop.
660 BitVector* FindLoopBlocks(BlockEntryInstr* m, BlockEntryInstr* n) const;
661
662 // Finds the natural loops in the flow graph and attaches the loop
663 // information to each entry block. Returns the loop hierarchy.
664 LoopHierarchy* ComputeLoops() const;
665
666 void InsertConversionsFor(Definition* def);
667 void ConvertUse(Value* use, Representation from);
668 void InsertConversion(Representation from,
670 Value* use,
671 bool is_environment_use);
672
673 // Insert allocation of a record instance for [def]
674 // which returns an unboxed record.
675 void InsertRecordBoxing(Definition* def);
676
677 void ComputeIsReceiver(PhiInstr* phi) const;
678 void ComputeIsReceiverRecursive(PhiInstr* phi,
679 GrowableArray<PhiInstr*>* unmark) const;
680
681 void OptimizeLeftShiftBitAndSmiOp(
682 ForwardInstructionIterator* current_iterator,
683 Definition* bit_and_instr,
684 Definition* left_instr,
685 Definition* right_instr);
686
687 void TryMergeTruncDivMod(GrowableArray<BinarySmiOpInstr*>* merge_candidates);
688
689 void AppendExtractNthOutputForMerged(Definition* instr,
690 intptr_t ix,
691 Representation rep,
692 intptr_t cid);
693
694 void ExtractUntaggedPayload(Instruction* instr,
695 Value* array,
696 const Slot& slot,
697 InnerPointerAccess access);
698
699 void ExtractNonInternalTypedDataPayload(Instruction* instr,
700 Value* array,
701 classid_t cid);
702
703 Thread* thread_;
704
705 // DiscoverBlocks computes parent_ and assigned_vars_ which are then used
706 // if/when computing SSA.
708
709 intptr_t current_ssa_temp_index_;
710 intptr_t max_block_id_;
711
712 // Flow graph fields.
713 const ParsedFunction& parsed_function_;
714 intptr_t num_direct_parameters_;
715 compiler::ParameterInfoArray direct_parameter_locations_;
716 GraphEntryInstr* graph_entry_;
719 GrowableArray<BlockEntryInstr*> reverse_postorder_;
720 GrowableArray<BlockEntryInstr*> optimized_block_order_;
721 ConstantInstr* constant_null_;
722 ConstantInstr* constant_dead_;
723
724 bool licm_allowed_;
725 bool unmatched_representations_allowed_ = true;
726 bool huge_method_ = false;
727 const bool should_reorder_blocks_;
728
729 const PrologueInfo prologue_info_;
730
731 // Loop related fields.
732 LoopHierarchy* loop_hierarchy_;
733 ZoneGrowableArray<BitVector*>* loop_invariant_loads_;
734
735 DirectChainedHashMap<ConstantPoolTrait> constant_instr_pool_;
736 BitVector* captured_parameters_;
737
738 intptr_t inlining_id_;
739 bool should_print_;
740 const bool should_remove_all_bounds_checks_;
741 uint8_t* compiler_pass_filters_ = nullptr;
742
743 intptr_t max_argument_slot_count_ = -1;
744
745 const Array* coverage_array_ = &Array::empty_array();
746};
747
749 public:
750 LivenessAnalysis(intptr_t variable_count,
751 const GrowableArray<BlockEntryInstr*>& postorder);
752
753 void Analyze();
754
755 virtual ~LivenessAnalysis() {}
756
757 BitVector* GetLiveInSetAt(intptr_t postorder_number) const {
758 return live_in_[postorder_number];
759 }
760
761 BitVector* GetLiveOutSetAt(intptr_t postorder_number) const {
762 return live_out_[postorder_number];
763 }
764
766 return GetLiveInSetAt(block->postorder_number());
767 }
768
770 return kill_[block->postorder_number()];
771 }
772
774 return GetLiveOutSetAt(block->postorder_number());
775 }
776
777 // Print results of liveness analysis.
778 void Dump();
779
780 protected:
781 // Compute initial values for live-out, kill and live-in sets.
782 virtual void ComputeInitialSets() = 0;
783
784 // Update live-out set for the given block: live-out should contain
785 // all values that are live-in for block's successors.
786 // Returns true if live-out set was changed.
787 bool UpdateLiveOut(const BlockEntryInstr& instr);
788
789 // Update live-in set for the given block: live-in should contain
790 // all values that are live-out from the block and are not defined
791 // by this block.
792 // Returns true if live-in set was changed.
793 bool UpdateLiveIn(const BlockEntryInstr& instr);
794
795 // Perform fix-point iteration updating live-out and live-in sets
796 // for blocks until they stop changing.
798
799 Zone* zone() const { return zone_; }
800
802
803 const intptr_t variable_count_;
804
806
807 // Live-out sets for each block. They contain indices of variables
808 // that are live out from this block. That is values that were (1) either
809 // defined in this block or live into it, and (2) that are used in some
810 // successor block.
812
813 // Kill sets for each block. They contain indices of variables that
814 // are defined by this block.
816
817 // Live-in sets for each block. They contain indices of variables
818 // that are used by this block or its successors.
820};
821
823 public:
824 DefinitionWorklist(FlowGraph* flow_graph, intptr_t initial_capacity)
825 : defs_(initial_capacity),
826 contains_vector_(new BitVector(flow_graph->zone(),
827 flow_graph->current_ssa_temp_index())) {}
828
829 void Add(Definition* defn) {
830 if (!Contains(defn)) {
831 defs_.Add(defn);
832 contains_vector_->Add(defn->ssa_temp_index());
833 }
834 }
835
836 bool Contains(Definition* defn) const {
837 return (defn->ssa_temp_index() >= 0) &&
838 contains_vector_->Contains(defn->ssa_temp_index());
839 }
840
841 bool IsEmpty() const { return defs_.is_empty(); }
842
844 Definition* defn = defs_.RemoveLast();
845 contains_vector_->Remove(defn->ssa_temp_index());
846 return defn;
847 }
848
849 const GrowableArray<Definition*>& definitions() const { return defs_; }
850 BitVector* contains_vector() const { return contains_vector_; }
851
852 void Clear() {
853 defs_.TruncateTo(0);
854 contains_vector_->Clear();
855 }
856
857 private:
859 BitVector* contains_vector_;
860};
861
862} // namespace dart
863
864#endif // RUNTIME_VM_COMPILER_BACKEND_FLOW_GRAPH_H_
int count
Definition: FontMgrTest.cpp:50
static float next(float f)
static float prev(float f)
#define RELEASE_ASSERT(cond)
Definition: assert.h:327
void Add(intptr_t i)
Definition: bit_vector.h:63
bool Contains(intptr_t i) const
Definition: bit_vector.h:91
void Remove(intptr_t i)
Definition: bit_vector.h:68
intptr_t postorder_number() const
Definition: il.h:1658
intptr_t stack_depth() const
Definition: il.h:1756
BlockIterator(const GrowableArray< BlockEntryInstr * > &block_order)
Definition: flow_graph.h:33
bool Done() const
Definition: flow_graph.h:46
BlockEntryInstr * Current() const
Definition: flow_graph.h:48
BlockIterator(const BlockIterator &other)
Definition: flow_graph.h:36
Definition: il.h:736
const Object & value() const
Definition: il.h:4230
BitVector * contains_vector() const
Definition: flow_graph.h:850
bool Contains(Definition *defn) const
Definition: flow_graph.h:836
void Add(Definition *defn)
Definition: flow_graph.h:829
Definition * RemoveLast()
Definition: flow_graph.h:843
const GrowableArray< Definition * > & definitions() const
Definition: flow_graph.h:849
DefinitionWorklist(FlowGraph *flow_graph, intptr_t initial_capacity)
Definition: flow_graph.h:824
void set_ssa_temp_index(intptr_t index)
Definition: il.h:2504
intptr_t ssa_temp_index() const
Definition: il.h:2503
const GrowableArray< BlockEntryInstr * > & reverse_postorder() const
Definition: flow_graph.h:207
GraphEntryInstr * graph_entry() const
Definition: flow_graph.h:268
ConstantInstr * GetConstant(const Object &object, Representation representation=kTagged)
Definition: flow_graph.cc:187
IsolateGroup * isolate_group() const
Definition: flow_graph.h:262
bool should_print() const
Definition: flow_graph.h:503
PrologueInfo prologue_info() const
Definition: flow_graph.h:427
bool VerifyRedefinitions()
Definition: flow_graph.cc:652
void EnsureSSATempIndex(Definition *defn, Definition *replacement)
Definition: flow_graph.cc:90
Instruction * AppendTo(Instruction *prev, Instruction *instr, Environment *env, UseKind use_kind)
Definition: flow_graph.cc:298
static constexpr CompilationMode CompilationModeFrom(bool is_optimizing)
Definition: flow_graph.h:585
void set_coverage_array(const Array &array)
Definition: flow_graph.h:551
void CompactSSA(ZoneGrowableArray< Definition * > *detached_defs=nullptr)
Definition: flow_graph.cc:3123
intptr_t max_argument_slot_count() const
Definition: flow_graph.h:562
bool IsCompiledForOsr() const
Definition: flow_graph.h:460
ConstantInstr * constant_dead() const
Definition: flow_graph.h:272
ConstantInstr * GetExistingConstant(const Object &object, Representation representation=kTagged) const
Definition: flow_graph.cc:180
Zone * zone() const
Definition: flow_graph.h:261
intptr_t current_ssa_temp_index() const
Definition: flow_graph.h:243
bool IsReceiver(Definition *def) const
Definition: flow_graph.cc:478
intptr_t ArgumentDescriptorEnvIndex() const
Definition: flow_graph.h:185
static Representation ReturnRepresentationOf(const Function &function)
Definition: flow_graph.cc:125
intptr_t inlining_id() const
Definition: flow_graph.h:464
const uint8_t * compiler_pass_filters() const
Definition: flow_graph.h:504
void ReplaceCurrentInstruction(ForwardInstructionIterator *iterator, Instruction *current, Instruction *replacement)
Definition: flow_graph.cc:141
bool should_remove_all_bounds_checks() const
Definition: flow_graph.h:510
JoinEntryInstr * NewDiamond(Instruction *instruction, Instruction *inherit, ComparisonInstr *compare, TargetEntryInstr **block_true, TargetEntryInstr **block_false)
Definition: flow_graph.cc:2858
Instruction * AppendSpeculativeTo(Instruction *prev, Instruction *instr, Environment *env, UseKind use_kind)
Definition: flow_graph.cc:312
Thread * thread() const
Definition: flow_graph.h:260
intptr_t InstructionCount() const
Definition: flow_graph.cc:1896
ToCheck CheckForInstanceCall(InstanceCallInstr *call, UntaggedFunction::Kind kind) const
Definition: flow_graph.cc:493
void RemoveRedefinitions(bool keep_checks=false)
Definition: flow_graph.cc:1810
void mark_huge_method()
Definition: flow_graph.h:425
bool IsIrregexpFunction() const
Definition: flow_graph.h:165
intptr_t SuspendStateEnvIndex() const
Definition: flow_graph.h:171
const GrowableArray< BlockEntryInstr * > & preorder() const
Definition: flow_graph.h:203
void set_current_ssa_temp_index(intptr_t index)
Definition: flow_graph.h:244
void CreateCommonConstants()
Definition: flow_graph.cc:1143
void AddExactnessGuard(InstanceCallInstr *call, intptr_t receiver_cid)
Definition: flow_graph.cc:627
const std::pair< Location, Representation > & GetDirectParameterInfoAt(intptr_t i)
Definition: flow_graph.h:571
void InsertSpeculativeAfter(Instruction *prev, Instruction *instr, Environment *env, UseKind use_kind)
Definition: flow_graph.cc:288
void set_max_argument_slot_count(intptr_t count)
Definition: flow_graph.h:566
void set_loop_invariant_loads(ZoneGrowableArray< BitVector * > *loop_invariant_loads)
Definition: flow_graph.h:455
BlockIterator postorder_iterator() const
Definition: flow_graph.h:222
Definition * CreateCheckBound(Definition *length, Definition *index, intptr_t deopt_id)
Definition: flow_graph.cc:616
intptr_t max_block_id() const
Definition: flow_graph.h:264
const GrowableArray< BlockEntryInstr * > & optimized_block_order() const
Definition: flow_graph.h:210
static intptr_t ComputeArgumentsSizeInWords(const Function &function, intptr_t arguments_count)
Definition: flow_graph.cc:96
void InsertMoveArguments()
Definition: flow_graph.cc:2946
void Print(const char *phase="unknown")
Definition: flow_graph.cc:3012
void DiscoverBlocks()
Definition: flow_graph.cc:346
const GrowableArray< BlockEntryInstr * > & postorder() const
Definition: flow_graph.h:204
intptr_t num_stack_locals() const
Definition: flow_graph.h:161
void ComputeDominators(GrowableArray< BitVector * > *dominance_frontier)
Definition: flow_graph.cc:975
static Representation ParameterRepresentationAt(const Function &function, intptr_t index)
Definition: flow_graph.cc:109
intptr_t max_vreg() const
Definition: flow_graph.h:248
void set_inlining_id(intptr_t value)
Definition: flow_graph.h:465
void EliminateEnvironments()
Definition: flow_graph.cc:2351
void disallow_unmatched_representations()
Definition: flow_graph.h:417
const Array & coverage_array() const
Definition: flow_graph.h:550
intptr_t CurrentContextEnvIndex() const
Definition: flow_graph.h:177
static intptr_t ComputeLocationsOfFixedParameters(Zone *zone, const Function &function, bool should_assign_stack_locations=false, compiler::ParameterInfoArray *parameter_info=nullptr)
Definition: flow_graph.cc:1204
BitVector * captured_parameters() const
Definition: flow_graph.h:462
void set_max_block_id(intptr_t id)
Definition: flow_graph.h:265
ConstantInstr * constant_null() const
Definition: flow_graph.h:270
Instruction * CreateCheckClass(Definition *to_check, const Cids &cids, intptr_t deopt_id, const InstructionSource &source)
Definition: flow_graph.cc:604
const LoopHierarchy & GetLoopHierarchy()
Definition: flow_graph.h:430
const Function & function() const
Definition: flow_graph.h:130
const ParsedFunction & parsed_function() const
Definition: flow_graph.h:129
bool is_huge_method() const
Definition: flow_graph.h:423
bool is_licm_allowed() const
Definition: flow_graph.h:404
void ResetLoopHierarchy()
Definition: flow_graph.h:444
intptr_t num_direct_parameters() const
Definition: flow_graph.h:137
ZoneGrowableArray< BitVector * > * loop_invariant_loads() const
Definition: flow_graph.h:452
const LoopHierarchy & loop_hierarchy() const
Definition: flow_graph.h:437
void RenameUsesDominatedByRedefinitions()
Definition: flow_graph.cc:2653
FlowGraph(const ParsedFunction &parsed_function, GraphEntryInstr *graph_entry, intptr_t max_block_id, PrologueInfo prologue_info, CompilationMode compilation_mode)
Definition: flow_graph.cc:46
bool unmatched_representations_allowed() const
Definition: flow_graph.h:411
Definition * TryCreateConstantReplacementFor(Definition *op, const Object &value)
Definition: flow_graph.cc:236
intptr_t osr_variable_count() const
Definition: flow_graph.h:149
void PopulateWithICData(const Function &function)
Definition: flow_graph.cc:2528
RedefinitionInstr * EnsureRedefinition(Instruction *prev, Definition *original, CompileType compile_type)
Definition: flow_graph.cc:1777
void TryOptimizePatterns()
Definition: flow_graph.cc:2570
PhiInstr * AddPhi(JoinEntryInstr *join, Definition *d1, Definition *d2)
Definition: flow_graph.cc:2927
void AddToGraphInitialDefinitions(Definition *defn)
Definition: flow_graph.cc:258
bool ExtractExternalUntaggedPayload(Instruction *instr, Value *array, classid_t cid)
Definition: flow_graph.cc:2393
void CopyDeoptTarget(Instruction *to, Instruction *from)
Definition: flow_graph.h:395
void AllocateSSAIndex(Definition *def)
Definition: flow_graph.h:274
static bool IsConstantRepresentable(const Object &value, Representation target_rep, bool tagged_value_must_be_smi)
Definition: flow_graph.cc:205
BlockIterator reverse_postorder_iterator() const
Definition: flow_graph.h:219
void ComputeSSA(ZoneGrowableArray< Definition * > *inlining_parameters)
Definition: flow_graph.cc:926
LocalVariable * CurrentContextVar() const
Definition: flow_graph.h:173
intptr_t RawTypeArgumentEnvIndex() const
Definition: flow_graph.h:181
void InsertBefore(Instruction *next, Instruction *instr, Environment *env, UseKind use_kind)
Definition: flow_graph.h:312
static void RenameDominatedUses(Definition *def, Instruction *dom, Definition *other)
Definition: flow_graph.cc:2642
LocalVariable * SuspendStateVar() const
Definition: flow_graph.h:167
friend class FlowGraphChecker
Definition: flow_graph.h:604
void SelectRepresentations()
Definition: flow_graph.cc:2298
intptr_t variable_count() const
Definition: flow_graph.h:143
void AddToInitialDefinitions(BlockEntryWithInitialDefs *entry, Definition *defn)
Definition: flow_graph.cc:263
void ExtractNonInternalTypedDataPayloads()
Definition: flow_graph.cc:2444
void MergeBlocks()
Definition: flow_graph.cc:389
GrowableArray< BlockEntryInstr * > * CodegenBlockOrder()
Definition: flow_graph.cc:170
intptr_t allocate_block_id()
Definition: flow_graph.h:266
void InsertAfter(Instruction *prev, Instruction *instr, Environment *env, UseKind use_kind)
Definition: flow_graph.cc:273
void InsertSpeculativeBefore(Instruction *next, Instruction *instr, Environment *env, UseKind use_kind)
Definition: flow_graph.h:318
bool should_reorder_blocks() const
Definition: flow_graph.h:508
bool IsImmortalVariable(intptr_t env_index) const
Definition: flow_graph.h:196
void disallow_licm()
Definition: flow_graph.h:408
intptr_t EnvIndex(const LocalVariable *variable) const
Definition: flow_graph.h:189
bool IsIrregexpFunction() const
Definition: object.h:3898
bool IsCompiledForOsr() const
Definition: il.cc:1257
OsrEntryInstr * osr_entry() const
Definition: il.h:2007
void InheritDeoptTarget(Zone *zone, Instruction *other)
Definition: il.cc:1569
virtual Representation representation() const
Definition: il.h:1260
const intptr_t variable_count_
Definition: flow_graph.h:803
virtual ~LivenessAnalysis()
Definition: flow_graph.h:755
virtual void ComputeInitialSets()=0
GrowableArray< BitVector * > kill_
Definition: flow_graph.h:815
void ComputeLiveInAndLiveOutSets()
Definition: flow_graph.cc:711
bool UpdateLiveOut(const BlockEntryInstr &instr)
Definition: flow_graph.cc:689
BitVector * GetKillSet(BlockEntryInstr *block) const
Definition: flow_graph.h:769
LivenessAnalysis(intptr_t variable_count, const GrowableArray< BlockEntryInstr * > &postorder)
Definition: flow_graph.cc:679
BitVector * GetLiveOutSetAt(intptr_t postorder_number) const
Definition: flow_graph.h:761
GrowableArray< BitVector * > live_out_
Definition: flow_graph.h:811
Zone * zone() const
Definition: flow_graph.h:799
BitVector * GetLiveOutSet(BlockEntryInstr *block) const
Definition: flow_graph.h:773
GrowableArray< BitVector * > live_in_
Definition: flow_graph.h:819
BitVector * GetLiveInSet(BlockEntryInstr *block) const
Definition: flow_graph.h:765
BitVector * GetLiveInSetAt(intptr_t postorder_number) const
Definition: flow_graph.h:757
const GrowableArray< BlockEntryInstr * > & postorder_
Definition: flow_graph.h:805
bool UpdateLiveIn(const BlockEntryInstr &instr)
Definition: flow_graph.cc:704
VariableIndex index() const
Definition: scopes.h:202
bool is_captured() const
Definition: scopes.h:143
ObjectPtr ptr() const
Definition: object.h:332
const Function & function() const
Definition: parser.h:73
int num_stack_locals() const
Definition: parser.h:194
LocalVariable * current_context_var() const
Definition: parser.h:128
LocalVariable * suspend_state_var() const
Definition: parser.h:103
Zone * zone() const
Definition: thread_state.h:37
IsolateGroup * isolate_group() const
Definition: thread.h:541
Definition: il.h:75
int value() const
Definition: scopes.h:69
#define ASSERT(E)
SkBitmap source
Definition: examples.cpp:28
uint8_t value
static float max(float r, float g, float b)
Definition: hsl.cpp:49
static float min(float r, float g, float b)
Definition: hsl.cpp:48
size_t length
double y
double x
Definition: dart_vm.cc:33
InnerPointerAccess
Definition: il.h:6295
static constexpr intptr_t kMaxLocationCount
Definition: locations.h:73
int32_t classid_t
Definition: globals.h:524
Representation
Definition: locations.h:66
uintptr_t uword
Definition: globals.h:501
const intptr_t cid
Definition: dom.py:1
def call(args)
Definition: dom.py:159
Definition: __init__.py:1
int compare(const void *untyped_lhs, const void *untyped_rhs)
Definition: skdiff.h:161
static SkString join(const CommandLineFlags::StringArray &)
Definition: skpbench.cpp:741
static Key KeyOf(Pair kv)
Definition: flow_graph.h:65
static uword Hash(Key key)
Definition: flow_graph.h:71
ConstantInstr * Value
Definition: flow_graph.h:61
static bool IsKeyEqual(Pair kv, Key key)
Definition: flow_graph.h:88
ConstantAndRepresentation Key
Definition: flow_graph.h:62
ConstantInstr * Pair
Definition: flow_graph.h:63
static Value ValueOf(Pair kv)
Definition: flow_graph.h:69
ComparisonInstr * oper1
Definition: flow_graph.h:521
LogicalAnd(ComparisonInstr *x, ComparisonInstr *y)
Definition: flow_graph.h:520
ComparisonInstr * oper2
Definition: flow_graph.h:522
intptr_t max_block_id
Definition: flow_graph.h:103
intptr_t min_block_id
Definition: flow_graph.h:98
bool Contains(intptr_t block_id) const
Definition: flow_graph.h:108
PrologueInfo(intptr_t min, intptr_t max)
Definition: flow_graph.h:105
const uintptr_t id