Chromium Code Reviews| 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; | |
|
Mircea Trofin
2016/10/19 23:00:41
static const int
jbramley
2016/10/20 10:16:12
It's decremented in the loop so it can't be const.
Mircea Trofin
2016/10/20 16:41:11
I think the "2" could be a constant, but perhaps i
jbramley
2016/10/21 10:11:14
Acknowledged.
| |
| 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, calculate a score according to the priorities | |
| 2213 // described above, and pick the best one. | |
| 2214 int predecessor_hint_preference = 0; | |
| 2215 // The scores are combined by addition, in order to support non-trivial | |
| 2216 // heuristics. It is co-incidental that they are currently powers of two. | |
|
Mircea Trofin
2016/10/19 23:00:41
could you expand the comment to explain what a non
jbramley
2016/10/20 10:16:12
"Non-trivial" was probably the wrong phrase; it's
Mircea Trofin
2016/10/20 16:41:11
I think it's more intuitive to go with the bitwise
jbramley
2016/10/21 10:11:14
Done.
| |
| 2217 const int kNotDeferredBlockPreference = 4; | |
| 2218 const int kMoveIsAllocatedPreference = 2; | |
| 2219 const int kBlockIsEmptyPreference = 1; | |
| 2220 | |
| 2221 // - Avoid hints from deferred blocks. | |
| 2222 if (!predecessor_block->IsDeferred()) { | |
| 2223 predecessor_hint_preference += kNotDeferredBlockPreference; | |
| 2224 } | |
| 2225 | |
| 2226 // - Prefer hints from allocated (or explicit) operands. | |
| 2227 // | |
| 2228 // Already-allocated or explicit operands are typically assigned using | |
| 2229 // the parallel moves on the last instruction. For example: | |
| 2230 // | |
| 2231 // gap (v101 = [x0|R|w32]) (v100 = v101) | |
| 2232 // ArchJmp | |
| 2233 // ... | |
| 2234 // phi: v100 = v101 v102 | |
| 2235 // | |
| 2236 // We have already found the END move, so look for a matching START move | |
| 2237 // from an allocated (or explicit) operand. | |
| 2238 // | |
| 2239 // Note that we cannot simply look up data()->live_ranges()[vreg] here | |
| 2240 // because the live ranges are still being built when this function is | |
| 2241 // called. | |
|
Mircea Trofin
2016/10/19 23:00:41
Could you add a TODO (v8) here, perhaps we find a
jbramley
2016/10/20 10:16:12
Done. I think predecessor_limit would still be nee
Mircea Trofin
2016/10/20 16:41:11
Acknowledged.
| |
| 2242 auto moves = predecessor_instr->GetParallelMove(Instruction::START); | |
| 2243 if (moves != nullptr) { | |
| 2244 for (MoveOperands* move : *moves) { | |
| 2245 InstructionOperand& to = move->destination(); | |
| 2246 if (predecessor_hint->Equals(to)) { | |
| 2247 if (move->source().IsAllocated() || move->source().IsExplicit()) { | |
| 2248 predecessor_hint_preference += kMoveIsAllocatedPreference; | |
| 2249 } | |
| 2250 break; | |
| 2251 } | |
| 2252 } | |
| 2253 } | |
| 2254 | |
| 2255 // - Prefer hints from empty blocks. | |
| 2256 if (predecessor_block->last_instruction_index() == | |
| 2257 predecessor_block->first_instruction_index()) { | |
| 2258 predecessor_hint_preference += kBlockIsEmptyPreference; | |
| 2259 } | |
| 2260 | |
| 2261 if ((hint == nullptr) || | |
| 2262 (predecessor_hint_preference > hint_preference)) { | |
| 2263 // Take the hint from this predecessor. | |
| 2264 hint = predecessor_hint; | |
| 2265 hint_preference = predecessor_hint_preference; | |
| 2266 } | |
| 2267 | |
| 2268 if (--predecessor_limit <= 0) break; | |
| 2181 } | 2269 } |
| 2182 DCHECK_NOT_NULL(instr); | 2270 DCHECK_NOT_NULL(hint); |
| 2183 | 2271 |
| 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( | 2272 LifetimePosition block_start = LifetimePosition::GapFromInstructionIndex( |
| 2195 block->first_instruction_index()); | 2273 block->first_instruction_index()); |
| 2196 UsePosition* use_pos = Define(block_start, &phi->output(), hint, | 2274 UsePosition* use_pos = Define(block_start, &phi->output(), hint, |
| 2197 UsePosition::HintTypeForOperand(*hint)); | 2275 UsePosition::HintTypeForOperand(*hint)); |
| 2198 MapPhiHint(hint, use_pos); | 2276 MapPhiHint(hint, use_pos); |
| 2199 } | 2277 } |
| 2200 } | 2278 } |
| 2201 | 2279 |
| 2202 | 2280 |
| 2203 void LiveRangeBuilder::ProcessLoopHeader(const InstructionBlock* block, | 2281 void LiveRangeBuilder::ProcessLoopHeader(const InstructionBlock* block, |
| (...skipping 1511 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3715 } | 3793 } |
| 3716 } | 3794 } |
| 3717 } | 3795 } |
| 3718 } | 3796 } |
| 3719 } | 3797 } |
| 3720 | 3798 |
| 3721 | 3799 |
| 3722 } // namespace compiler | 3800 } // namespace compiler |
| 3723 } // namespace internal | 3801 } // namespace internal |
| 3724 } // namespace v8 | 3802 } // namespace v8 |
| OLD | NEW |