OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/base/adapters.h" | 5 #include "src/base/adapters.h" |
6 #include "src/compiler/linkage.h" | 6 #include "src/compiler/linkage.h" |
7 #include "src/compiler/register-allocator.h" | 7 #include "src/compiler/register-allocator.h" |
8 #include "src/string-stream.h" | 8 #include "src/string-stream.h" |
9 | 9 |
10 namespace v8 { | 10 namespace v8 { |
(...skipping 2146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2157 } | 2157 } |
2158 | 2158 |
2159 | 2159 |
2160 void LiveRangeBuilder::ProcessPhis(const InstructionBlock* block, | 2160 void LiveRangeBuilder::ProcessPhis(const InstructionBlock* block, |
2161 BitVector* live) { | 2161 BitVector* live) { |
2162 for (PhiInstruction* phi : block->phis()) { | 2162 for (PhiInstruction* phi : block->phis()) { |
2163 // The live range interval already ends at the first instruction of the | 2163 // The live range interval already ends at the first instruction of the |
2164 // block. | 2164 // block. |
2165 int phi_vreg = phi->virtual_register(); | 2165 int phi_vreg = phi->virtual_register(); |
2166 live->Remove(phi_vreg); | 2166 live->Remove(phi_vreg); |
2167 // Select the hint from the first predecessor block that preceeds this block | 2167 // Select a hint from a predecessor block that preceeds this block in the |
2168 // in the rpo ordering. Prefer non-deferred blocks. The enforcement of | 2168 // rpo order. In order of priority: |
2169 // hinting in rpo order is required because hint resolution that happens | 2169 // - Avoid hints from deferred blocks. |
2170 // later in the compiler pipeline visits instructions in reverse rpo, | 2170 // - Prefer hints from allocated (or explicit) operands. |
2171 // relying on the fact that phis are encountered before their hints. | 2171 // - Prefer hints from empty blocks (containing just parallel moves and a |
2172 const Instruction* instr = nullptr; | 2172 // jump). In these cases, if we can elide the moves, the jump threader |
2173 const InstructionBlock::Predecessors& predecessors = block->predecessors(); | 2173 // is likely to be able to elide the jump. |
2174 for (size_t i = 0; i < predecessors.size(); ++i) { | 2174 // The enforcement of hinting in rpo order is required because hint |
| 2175 // resolution that happens later in the compiler pipeline visits |
| 2176 // instructions in reverse rpo order, relying on the fact that phis are |
| 2177 // encountered before their hints. |
| 2178 InstructionOperand* hint = nullptr; |
| 2179 int hint_preference = 0; |
| 2180 |
| 2181 // The cost of hinting increases with the number of predecessors. At the |
| 2182 // same time, the typical benefit decreases, since this hinting only |
| 2183 // optimises the execution path through one predecessor. A limit of 2 is |
| 2184 // sufficient to hit the common if/else pattern. |
| 2185 int predecessor_limit = 2; |
| 2186 |
| 2187 for (RpoNumber predecessor : block->predecessors()) { |
2175 const InstructionBlock* predecessor_block = | 2188 const InstructionBlock* predecessor_block = |
2176 code()->InstructionBlockAt(predecessors[i]); | 2189 code()->InstructionBlockAt(predecessor); |
2177 if (predecessor_block->rpo_number() < block->rpo_number()) { | 2190 DCHECK_EQ(predecessor_block->rpo_number(), predecessor); |
2178 instr = GetLastInstruction(code(), predecessor_block); | 2191 |
2179 if (!predecessor_block->IsDeferred()) break; | 2192 // Only take hints from earlier rpo numbers. |
| 2193 if (predecessor >= block->rpo_number()) continue; |
| 2194 |
| 2195 // Look up the predecessor instruction. |
| 2196 const Instruction* predecessor_instr = |
| 2197 GetLastInstruction(code(), predecessor_block); |
| 2198 InstructionOperand* predecessor_hint = nullptr; |
| 2199 // Phis are assigned in the END position of the last instruction in each |
| 2200 // predecessor block. |
| 2201 for (MoveOperands* move : |
| 2202 *predecessor_instr->GetParallelMove(Instruction::END)) { |
| 2203 InstructionOperand& to = move->destination(); |
| 2204 if (to.IsUnallocated() && |
| 2205 UnallocatedOperand::cast(to).virtual_register() == phi_vreg) { |
| 2206 predecessor_hint = &move->source(); |
| 2207 break; |
| 2208 } |
2180 } | 2209 } |
| 2210 DCHECK_NOT_NULL(predecessor_hint); |
| 2211 |
| 2212 // For each predecessor, generate a score according to the priorities |
| 2213 // described above, and pick the best one. Flags in higher-order bits have |
| 2214 // a higher priority than those in lower-order bits. |
| 2215 int predecessor_hint_preference = 0; |
| 2216 const int kNotDeferredBlockPreference = (1 << 2); |
| 2217 const int kMoveIsAllocatedPreference = (1 << 1); |
| 2218 const int kBlockIsEmptyPreference = (1 << 0); |
| 2219 |
| 2220 // - Avoid hints from deferred blocks. |
| 2221 if (!predecessor_block->IsDeferred()) { |
| 2222 predecessor_hint_preference |= kNotDeferredBlockPreference; |
| 2223 } |
| 2224 |
| 2225 // - Prefer hints from allocated (or explicit) operands. |
| 2226 // |
| 2227 // Already-allocated or explicit operands are typically assigned using |
| 2228 // the parallel moves on the last instruction. For example: |
| 2229 // |
| 2230 // gap (v101 = [x0|R|w32]) (v100 = v101) |
| 2231 // ArchJmp |
| 2232 // ... |
| 2233 // phi: v100 = v101 v102 |
| 2234 // |
| 2235 // We have already found the END move, so look for a matching START move |
| 2236 // from an allocated (or explicit) operand. |
| 2237 // |
| 2238 // Note that we cannot simply look up data()->live_ranges()[vreg] here |
| 2239 // because the live ranges are still being built when this function is |
| 2240 // called. |
| 2241 // TODO(v8): Find a way to separate hinting from live range analysis in |
| 2242 // BuildLiveRanges so that we can use the O(1) live-range look-up. |
| 2243 auto moves = predecessor_instr->GetParallelMove(Instruction::START); |
| 2244 if (moves != nullptr) { |
| 2245 for (MoveOperands* move : *moves) { |
| 2246 InstructionOperand& to = move->destination(); |
| 2247 if (predecessor_hint->Equals(to)) { |
| 2248 if (move->source().IsAllocated() || move->source().IsExplicit()) { |
| 2249 predecessor_hint_preference |= kMoveIsAllocatedPreference; |
| 2250 } |
| 2251 break; |
| 2252 } |
| 2253 } |
| 2254 } |
| 2255 |
| 2256 // - Prefer hints from empty blocks. |
| 2257 if (predecessor_block->last_instruction_index() == |
| 2258 predecessor_block->first_instruction_index()) { |
| 2259 predecessor_hint_preference |= kBlockIsEmptyPreference; |
| 2260 } |
| 2261 |
| 2262 if ((hint == nullptr) || |
| 2263 (predecessor_hint_preference > hint_preference)) { |
| 2264 // Take the hint from this predecessor. |
| 2265 hint = predecessor_hint; |
| 2266 hint_preference = predecessor_hint_preference; |
| 2267 } |
| 2268 |
| 2269 if (--predecessor_limit <= 0) break; |
2181 } | 2270 } |
2182 DCHECK_NOT_NULL(instr); | 2271 DCHECK_NOT_NULL(hint); |
2183 | 2272 |
2184 InstructionOperand* hint = nullptr; | |
2185 for (MoveOperands* move : *instr->GetParallelMove(Instruction::END)) { | |
2186 InstructionOperand& to = move->destination(); | |
2187 if (to.IsUnallocated() && | |
2188 UnallocatedOperand::cast(to).virtual_register() == phi_vreg) { | |
2189 hint = &move->source(); | |
2190 break; | |
2191 } | |
2192 } | |
2193 DCHECK(hint != nullptr); | |
2194 LifetimePosition block_start = LifetimePosition::GapFromInstructionIndex( | 2273 LifetimePosition block_start = LifetimePosition::GapFromInstructionIndex( |
2195 block->first_instruction_index()); | 2274 block->first_instruction_index()); |
2196 UsePosition* use_pos = Define(block_start, &phi->output(), hint, | 2275 UsePosition* use_pos = Define(block_start, &phi->output(), hint, |
2197 UsePosition::HintTypeForOperand(*hint)); | 2276 UsePosition::HintTypeForOperand(*hint)); |
2198 MapPhiHint(hint, use_pos); | 2277 MapPhiHint(hint, use_pos); |
2199 } | 2278 } |
2200 } | 2279 } |
2201 | 2280 |
2202 | 2281 |
2203 void LiveRangeBuilder::ProcessLoopHeader(const InstructionBlock* block, | 2282 void LiveRangeBuilder::ProcessLoopHeader(const InstructionBlock* block, |
(...skipping 1511 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3715 } | 3794 } |
3716 } | 3795 } |
3717 } | 3796 } |
3718 } | 3797 } |
3719 } | 3798 } |
3720 | 3799 |
3721 | 3800 |
3722 } // namespace compiler | 3801 } // namespace compiler |
3723 } // namespace internal | 3802 } // namespace internal |
3724 } // namespace v8 | 3803 } // namespace v8 |
OLD | NEW |