| 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 |