Flutter Engine
The Flutter Engine
Static Public Member Functions | List of all members
dart::BranchSimplifier Class Reference

#include <branch_optimizer.h>

Inheritance diagram for dart::BranchSimplifier:
dart::AllStatic

Static Public Member Functions

static void Simplify (FlowGraph *flow_graph)
 
static JoinEntryInstrToJoinEntry (Zone *zone, BlockEntryInstr *target)
 
static TargetEntryInstrToTargetEntry (Zone *zone, BlockEntryInstr *target)
 

Detailed Description

Definition at line 28 of file branch_optimizer.h.

Member Function Documentation

◆ Simplify()

void dart::BranchSimplifier::Simplify ( FlowGraph flow_graph)
static

Definition at line 98 of file branch_optimizer.cc.

98 {
99 // Optimize some branches that test the value of a phi. When it is safe
100 // to do so, push the branch to each of the predecessor blocks. This is
101 // an optimization when (a) it can avoid materializing a boolean object at
102 // the phi only to test its value, and (b) it can expose opportunities for
103 // constant propagation and unreachable code elimination. This
104 // optimization is intended to run after inlining which creates
105 // opportunities for optimization (a) and before constant folding which
106 // can perform optimization (b).
107
108 // Begin with a worklist of join blocks ending in branches. They are
109 // candidates for the pattern below.
110 Zone* zone = flow_graph->zone();
111 const GrowableArray<BlockEntryInstr*>& postorder = flow_graph->postorder();
112 GrowableArray<BlockEntryInstr*> worklist(postorder.length());
113 for (BlockIterator it(postorder); !it.Done(); it.Advance()) {
114 BlockEntryInstr* block = it.Current();
115 if (block->IsJoinEntry() && block->last_instruction()->IsBranch()) {
116 worklist.Add(block);
117 }
118 }
119
120 // Rewrite until no more instance of the pattern exists.
121 bool changed = false;
122 while (!worklist.is_empty()) {
123 // All blocks in the worklist are join blocks (ending with a branch).
124 JoinEntryInstr* block = worklist.RemoveLast()->AsJoinEntry();
125 ASSERT(block != nullptr);
126
127 if (Match(block)) {
128 changed = true;
129
130 // The branch will be copied and pushed to all the join's
131 // predecessors. Convert the true and false target blocks into join
132 // blocks to join the control flows from all of the true
133 // (respectively, false) targets of the copied branches.
134 //
135 // The converted join block will have no phis, so it cannot be another
136 // instance of the pattern. There is thus no need to add it to the
137 // worklist.
138 BranchInstr* branch = block->last_instruction()->AsBranch();
139 ASSERT(branch != nullptr);
140 JoinEntryInstr* join_true = ToJoinEntry(zone, branch->true_successor());
141 JoinEntryInstr* join_false = ToJoinEntry(zone, branch->false_successor());
142
143 ComparisonInstr* comparison = branch->comparison();
144 PhiInstr* phi = comparison->left()->definition()->AsPhi();
145 ConstantInstr* constant = comparison->right()->definition()->AsConstant();
146 ASSERT(constant != nullptr);
147 // Copy the constant and branch and push it to all the predecessors.
148 for (intptr_t i = 0, count = block->PredecessorCount(); i < count; ++i) {
149 GotoInstr* old_goto =
150 block->PredecessorAt(i)->last_instruction()->AsGoto();
151 ASSERT(old_goto != nullptr);
152
153 // Replace the goto in each predecessor with a rewritten branch,
154 // rewritten to use the corresponding phi input instead of the phi.
155 Value* new_left = phi->InputAt(i)->Copy(zone);
156 Value* new_right = new (zone) Value(constant);
157 BranchInstr* new_branch =
158 CloneBranch(zone, branch, new_left, new_right);
159 if (branch->env() == nullptr) {
160 new_branch->InheritDeoptTarget(zone, old_goto);
161 } else {
162 // Take the environment from the branch if it has one.
163 new_branch->InheritDeoptTarget(zone, branch);
164 // InheritDeoptTarget gave the new branch's comparison the same
165 // deopt id that it gave the new branch. The id should be the
166 // deopt id of the original comparison.
167 new_branch->comparison()->SetDeoptId(*comparison);
168 // The phi can be used in the branch's environment. Rename such
169 // uses.
170 Definition* replacement = phi->InputAt(i)->definition();
171 new_branch->ReplaceInEnvironment(phi, replacement);
172 }
173
174 new_branch->InsertBefore(old_goto);
175 new_branch->set_next(nullptr); // Detaching the goto from the graph.
176 old_goto->UnuseAllInputs();
177
178 // Update the predecessor block. We may have created another
179 // instance of the pattern so add it to the worklist if necessary.
180 BlockEntryInstr* branch_block = new_branch->GetBlock();
181 branch_block->set_last_instruction(new_branch);
182 if (branch_block->IsJoinEntry()) worklist.Add(branch_block);
183
184 // Connect the branch to the true and false joins, via empty target
185 // blocks.
186 TargetEntryInstr* true_target = new (zone) TargetEntryInstr(
187 flow_graph->max_block_id() + 1, block->try_index(), DeoptId::kNone);
188 true_target->InheritDeoptTarget(zone, join_true);
189 TargetEntryInstr* false_target = new (zone) TargetEntryInstr(
190 flow_graph->max_block_id() + 2, block->try_index(), DeoptId::kNone);
191 false_target->InheritDeoptTarget(zone, join_false);
192 flow_graph->set_max_block_id(flow_graph->max_block_id() + 2);
193 *new_branch->true_successor_address() = true_target;
194 *new_branch->false_successor_address() = false_target;
195 GotoInstr* goto_true = new (zone) GotoInstr(join_true, DeoptId::kNone);
196 goto_true->InheritDeoptTarget(zone, join_true);
197 true_target->LinkTo(goto_true);
198 true_target->set_last_instruction(goto_true);
199 GotoInstr* goto_false =
200 new (zone) GotoInstr(join_false, DeoptId::kNone);
201 goto_false->InheritDeoptTarget(zone, join_false);
202 false_target->LinkTo(goto_false);
203 false_target->set_last_instruction(goto_false);
204 }
205 // When all predecessors have been rewritten, the original block is
206 // unreachable from the graph.
207 phi->UnuseAllInputs();
208 branch->UnuseAllInputs();
209 block->UnuseAllInputs();
210 ASSERT(!phi->HasUses());
211 }
212 }
213
214 if (changed) {
215 // We may have changed the block order and the dominator tree.
216 flow_graph->DiscoverBlocks();
217 GrowableArray<BitVector*> dominance_frontier;
218 flow_graph->ComputeDominators(&dominance_frontier);
219 }
220}
int count
Definition: FontMgrTest.cpp:50
static JoinEntryInstr * ToJoinEntry(Zone *zone, BlockEntryInstr *target)
static constexpr intptr_t kNone
Definition: deopt_id.h:27
#define ASSERT(E)

◆ ToJoinEntry()

JoinEntryInstr * dart::BranchSimplifier::ToJoinEntry ( Zone zone,
BlockEntryInstr target 
)
static

Definition at line 61 of file branch_optimizer.cc.

62 {
63 // Convert a target block into a join block. Branches will be duplicated
64 // so the former true and false targets become joins of the control flows
65 // from all the duplicated branches.
66 JoinEntryInstr* join = new (zone)
67 JoinEntryInstr(target->block_id(), target->try_index(), DeoptId::kNone);
68 join->InheritDeoptTarget(zone, target);
69 join->LinkTo(target->next());
70 join->set_last_instruction(target->last_instruction());
71 target->UnuseAllInputs();
72 return join;
73}
uint32_t * target
static SkString join(const CommandLineFlags::StringArray &)
Definition: skpbench.cpp:741

◆ ToTargetEntry()

TargetEntryInstr * dart::BranchSimplifier::ToTargetEntry ( Zone zone,
BlockEntryInstr target 
)
static

Definition at line 75 of file branch_optimizer.cc.

76 {
77 auto replacement = new (zone)
78 TargetEntryInstr(target->block_id(), target->try_index(), DeoptId::kNone);
79 replacement->InheritDeoptTarget(zone, target);
80 replacement->LinkTo(target->next());
81 replacement->set_last_instruction(target->last_instruction());
82 target->UnuseAllInputs();
83 return replacement;
84}

The documentation for this class was generated from the following files: