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/compiler/gap-resolver.h" | 5 #include "src/compiler/gap-resolver.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <functional> | 8 #include <functional> |
| 9 #include <set> | 9 #include <set> |
| 10 | 10 |
| 11 #include "src/base/adapters.h" | |
| 12 | |
| 11 namespace v8 { | 13 namespace v8 { |
| 12 namespace internal { | 14 namespace internal { |
| 13 namespace compiler { | 15 namespace compiler { |
| 14 | 16 |
| 15 namespace { | 17 namespace { |
| 16 | 18 |
| 17 inline bool Blocks(MoveOperands* move, InstructionOperand destination) { | 19 inline bool Blocks(MoveOperands* move, InstructionOperand destination) { |
| 18 return move->Blocks(destination); | 20 return move->Blocks(destination); |
| 19 } | 21 } |
| 20 | 22 |
| 21 | 23 |
| 22 inline bool IsRedundant(MoveOperands* move) { return move->IsRedundant(); } | 24 inline bool IsRedundant(MoveOperands* move) { return move->IsRedundant(); } |
| 23 | 25 |
| 24 } // namespace | 26 } // namespace |
| 25 | 27 |
| 26 | 28 |
| 27 void GapResolver::Resolve(ParallelMove* moves) const { | 29 void GapResolver::Resolve(ParallelMove* moves) const { |
| 28 // Clear redundant moves. | 30 // Clear redundant moves. |
| 29 auto it = | 31 auto it = |
| 30 std::remove_if(moves->begin(), moves->end(), std::ptr_fun(IsRedundant)); | 32 std::remove_if(moves->begin(), moves->end(), std::ptr_fun(IsRedundant)); |
| 31 moves->erase(it, moves->end()); | 33 moves->erase(it, moves->end()); |
| 32 for (MoveOperands* move : *moves) { | 34 for (MoveOperands* move : *moves) { |
| 33 if (!move->IsEliminated()) PerformMove(moves, move); | 35 if (!move->IsEliminated()) PerformMove(moves, move); |
| 34 } | 36 } |
| 35 } | 37 } |
| 36 | 38 |
| 39 namespace { | |
| 40 bool ValidPush(InstructionOperand source, | |
|
Benedikt Meurer
2016/06/30 07:57:06
Nit: IsValidPush
danno
2016/07/01 07:31:56
Done.
| |
| 41 GapResolver::PushTypeFlags push_type) { | |
| 42 if (source.IsImmediate() && | |
| 43 ((push_type & GapResolver::kImmediatePush) != 0)) { | |
| 44 return true; | |
| 45 } | |
| 46 if ((source.IsRegister() || source.IsStackSlot()) && | |
| 47 ((push_type & GapResolver::kScalarPush) != 0)) { | |
| 48 return true; | |
| 49 } | |
| 50 if ((source.IsFloatRegister() || source.IsFloatStackSlot()) && | |
| 51 ((push_type & GapResolver::kFloat32Push) != 0)) { | |
| 52 return true; | |
| 53 } | |
| 54 if ((source.IsDoubleRegister() || source.IsFloatStackSlot()) && | |
| 55 ((push_type & GapResolver::kFloat64Push) != 0)) { | |
| 56 return true; | |
| 57 } | |
| 58 return false; | |
| 59 } | |
| 60 } // namespace | |
|
Benedikt Meurer
2016/06/30 07:57:06
Nit: empty line (here and in other places for anon
danno
2016/07/01 07:31:56
Done.
| |
| 61 | |
| 62 void GapResolver::GetPushCompatibleMoves(Zone* zone, Instruction* instr, | |
|
Mircea Trofin
2016/06/30 15:32:34
Is cycles something to worry about?
danno
2016/07/01 07:31:56
Nope, since the test for valid pushes are moves wh
| |
| 63 PushTypeFlags push_type, | |
| 64 ZoneVector<MoveOperands*>* pushes) { | |
| 65 pushes->resize(0); | |
| 66 for (int i = Instruction::FIRST_GAP_POSITION; | |
| 67 i <= Instruction::LAST_GAP_POSITION; ++i) { | |
| 68 Instruction::GapPosition inner_pos = | |
| 69 static_cast<Instruction::GapPosition>(i); | |
| 70 ParallelMove* parallel_move = instr->GetParallelMove(inner_pos); | |
| 71 if (parallel_move != nullptr) { | |
| 72 for (auto& move : *parallel_move) { | |
| 73 InstructionOperand source = move->source(); | |
| 74 InstructionOperand destination = move->destination(); | |
| 75 int first_push_compatible_index = | |
| 76 V8_TARGET_ARCH_STORES_RETURN_ADDRESS_ON_STACK ? 1 : 0; | |
| 77 // If there are any moves from slots that will be overridden by pushes, | |
| 78 // then the full gap resolver must be used since optimization with | |
| 79 // pushes don't participate in the parallel move and might clobber | |
| 80 // values needed for the gap resolve. | |
| 81 if (source.IsStackSlot() && | |
| 82 LocationOperand::cast(source).index() >= | |
| 83 first_push_compatible_index) { | |
| 84 pushes->resize(0); | |
| 85 return; | |
| 86 } | |
| 87 // TODO(danno): Right now, only consider moves from the FIRST gap for | |
| 88 // pushes. Theoretically, we could extract pushes for both gaps (there | |
| 89 // are cases where this happens), but the logic for that would also have | |
| 90 // to check to make sure that non-memory inputs to the pushes from the | |
| 91 // LAST gap don't get clobbered in the FIRST gap. | |
|
Mircea Trofin
2016/06/30 15:32:33
The move optimizer should have detected and elided
danno
2016/07/01 07:31:56
Yes. The problem isn't redundancy, it's the fact t
| |
| 92 if (i == Instruction::FIRST_GAP_POSITION) { | |
| 93 if (destination.IsStackSlot() && | |
| 94 LocationOperand::cast(destination).index() >= | |
| 95 first_push_compatible_index) { | |
| 96 int index = LocationOperand::cast(destination).index(); | |
| 97 if (ValidPush(source, push_type)) { | |
| 98 if (index >= static_cast<int>(pushes->size())) { | |
| 99 pushes->resize(index + 1); | |
| 100 } | |
| 101 (*pushes)[index] = move; | |
|
Mircea Trofin
2016/06/30 15:32:34
pushes->at(index) = move rather?
Jarin
2016/06/30 16:48:04
No, please do not use vector::at - it does bounds
danno
2016/07/01 07:31:56
Done.
danno
2016/07/01 07:31:56
OK. Not done :-)
| |
| 102 } | |
| 103 } | |
| 104 } | |
| 105 } | |
| 106 } | |
| 107 } | |
| 108 | |
| 109 // For now, only support a set of continuous pushes at the end of the list. | |
| 110 size_t push_count_upper_bound = pushes->size(); | |
| 111 size_t push_begin = push_count_upper_bound; | |
| 112 for (auto move : base::Reversed(*pushes)) { | |
| 113 if (move == nullptr) break; | |
| 114 push_begin--; | |
| 115 } | |
| 116 size_t push_count = pushes->size() - push_begin; | |
| 117 std::copy(pushes->begin() + push_begin, | |
| 118 pushes->begin() + push_begin + push_count, pushes->begin()); | |
| 119 pushes->resize(push_count); | |
| 120 } | |
| 37 | 121 |
| 38 void GapResolver::PerformMove(ParallelMove* moves, MoveOperands* move) const { | 122 void GapResolver::PerformMove(ParallelMove* moves, MoveOperands* move) const { |
| 39 // Each call to this function performs a move and deletes it from the move | 123 // Each call to this function performs a move and deletes it from the move |
| 40 // graph. We first recursively perform any move blocking this one. We mark a | 124 // graph. We first recursively perform any move blocking this one. We mark a |
| 41 // move as "pending" on entry to PerformMove in order to detect cycles in the | 125 // move as "pending" on entry to PerformMove in order to detect cycles in the |
| 42 // move graph. We use operand swaps to resolve cycles, which means that a | 126 // move graph. We use operand swaps to resolve cycles, which means that a |
| 43 // call to PerformMove could change any source operand in the move graph. | 127 // call to PerformMove could change any source operand in the move graph. |
| 44 DCHECK(!move->IsPending()); | 128 DCHECK(!move->IsPending()); |
| 45 DCHECK(!move->IsRedundant()); | 129 DCHECK(!move->IsRedundant()); |
| 46 | 130 |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 107 if (other->Blocks(source)) { | 191 if (other->Blocks(source)) { |
| 108 other->set_source(destination); | 192 other->set_source(destination); |
| 109 } else if (other->Blocks(destination)) { | 193 } else if (other->Blocks(destination)) { |
| 110 other->set_source(source); | 194 other->set_source(source); |
| 111 } | 195 } |
| 112 } | 196 } |
| 113 } | 197 } |
| 114 } // namespace compiler | 198 } // namespace compiler |
| 115 } // namespace internal | 199 } // namespace internal |
| 116 } // namespace v8 | 200 } // namespace v8 |
| OLD | NEW |