Chromium Code Reviews| Index: src/compiler/move-optimizer.cc |
| diff --git a/src/compiler/move-optimizer.cc b/src/compiler/move-optimizer.cc |
| index 953692dc13b423bce3eef94b5028053d054bb35f..badc90942fb91c10ea319f1d40089ea32a737c3e 100644 |
| --- a/src/compiler/move-optimizer.cc |
| +++ b/src/compiler/move-optimizer.cc |
| @@ -27,8 +27,68 @@ struct MoveKeyCompare { |
| typedef ZoneMap<MoveKey, unsigned, MoveKeyCompare> MoveMap; |
| typedef ZoneSet<InstructionOperand, CompareOperandModuloType> OperandSet; |
| -bool Blocks(const OperandSet& set, const InstructionOperand& operand) { |
| - return set.find(operand) != set.end(); |
| +#define REP_BIT(rep) (1 << static_cast<int>(rep)); |
| + |
| +bool HasMixedFPReps(int reps) { |
| + return reps && !base::bits::IsPowerOfTwo32(reps); |
| +} |
| + |
| +void InsertOp(OperandSet* set, const InstructionOperand& op, int* fp_reg_reps) { |
|
Mircea Trofin
2016/10/12 21:09:26
would it be overkill to define InsertOp as a membe
bbudge
2016/10/12 23:07:17
OperandSet is only a typedef. We could have it inh
Mircea Trofin
2016/10/14 20:58:39
Mind adding a todo on the typedef to investigate d
bbudge
2016/10/15 01:30:25
I replaced the typedef with a class. It's much cle
|
| + set->insert(op); |
| + if (!kSimpleFPAliasing && op.IsFPRegister()) |
| + *fp_reg_reps |= REP_BIT(LocationOperand::cast(op).representation()); |
| +} |
| + |
| +bool ContainsOpOrAlias(const OperandSet& set, const InstructionOperand& op, |
|
Mircea Trofin
2016/10/12 21:09:26
same for this API
bbudge
2016/10/12 23:07:17
Ditto
|
| + int fp_reg_reps) { |
| + if (set.find(op) != set.end()) return true; |
| + |
| + if (!kSimpleFPAliasing && op.IsFPRegister()) { |
| + // Platforms where FP registers have complex aliasing need extra checks. |
| + const LocationOperand& loc = LocationOperand::cast(op); |
| + MachineRepresentation rep = loc.representation(); |
| + // If we haven't encountered mixed FP registers, skip the extra checks. |
| + fp_reg_reps |= REP_BIT(rep); |
| + if (!HasMixedFPReps(fp_reg_reps)) return false; |
| + |
| + // Check register against aliasing registers of other FP representations. |
| + MachineRepresentation other_rep1, other_rep2; |
| + switch (rep) { |
| + case MachineRepresentation::kFloat32: |
| + other_rep1 = MachineRepresentation::kFloat64; |
| + other_rep2 = MachineRepresentation::kSimd128; |
| + break; |
| + case MachineRepresentation::kFloat64: |
| + other_rep1 = MachineRepresentation::kFloat32; |
| + other_rep2 = MachineRepresentation::kSimd128; |
| + break; |
| + case MachineRepresentation::kSimd128: |
| + other_rep1 = MachineRepresentation::kFloat32; |
| + other_rep2 = MachineRepresentation::kFloat64; |
| + break; |
| + default: |
| + UNREACHABLE(); |
| + break; |
| + } |
| + const RegisterConfiguration* config = RegisterConfiguration::Turbofan(); |
| + int base = -1; |
| + int aliases = |
| + config->GetAliases(rep, loc.register_code(), other_rep1, &base); |
| + DCHECK(aliases > 0 || (aliases == 0 && base == -1)); |
| + while (aliases--) { |
| + if (set.find(AllocatedOperand(LocationOperand::REGISTER, other_rep1, |
| + base + aliases)) != set.end()) |
| + return true; |
| + } |
| + aliases = config->GetAliases(rep, loc.register_code(), other_rep2, &base); |
| + DCHECK(aliases > 0 || (aliases == 0 && base == -1)); |
| + while (aliases--) { |
| + if (set.find(AllocatedOperand(LocationOperand::REGISTER, other_rep2, |
| + base + aliases)) != set.end()) |
| + return true; |
| + } |
| + } |
| + return false; |
| } |
| int FindFirstNonEmptySlot(const Instruction* instr) { |
| @@ -94,25 +154,27 @@ void MoveOptimizer::RemoveClobberedDestinations(Instruction* instruction) { |
| OperandSet outputs(local_zone()); |
| OperandSet inputs(local_zone()); |
| + int input_fp_reg_reps = 0; |
| + int output_fp_reg_reps = 0; |
| // Outputs and temps are treated together as potentially clobbering a |
| // destination operand. |
| for (size_t i = 0; i < instruction->OutputCount(); ++i) { |
| - outputs.insert(*instruction->OutputAt(i)); |
| + InsertOp(&outputs, *instruction->OutputAt(i), &output_fp_reg_reps); |
| } |
| for (size_t i = 0; i < instruction->TempCount(); ++i) { |
| - outputs.insert(*instruction->TempAt(i)); |
| + InsertOp(&outputs, *instruction->TempAt(i), &output_fp_reg_reps); |
| } |
| // Input operands block elisions. |
| for (size_t i = 0; i < instruction->InputCount(); ++i) { |
| - inputs.insert(*instruction->InputAt(i)); |
| + InsertOp(&inputs, *instruction->InputAt(i), &input_fp_reg_reps); |
| } |
| // Elide moves made redundant by the instruction. |
| for (MoveOperands* move : *moves) { |
| - if (outputs.find(move->destination()) != outputs.end() && |
| - inputs.find(move->destination()) == inputs.end()) { |
| + if (ContainsOpOrAlias(outputs, move->destination(), output_fp_reg_reps) && |
| + !ContainsOpOrAlias(inputs, move->destination(), input_fp_reg_reps)) { |
| move->Eliminate(); |
| } |
| } |
| @@ -121,7 +183,7 @@ void MoveOptimizer::RemoveClobberedDestinations(Instruction* instruction) { |
| // the one for its input. |
| if (instruction->IsRet() || instruction->IsTailCall()) { |
| for (MoveOperands* move : *moves) { |
| - if (inputs.find(move->destination()) == inputs.end()) { |
| + if (!ContainsOpOrAlias(inputs, move->destination(), input_fp_reg_reps)) { |
| move->Eliminate(); |
| } |
| } |
| @@ -136,11 +198,13 @@ void MoveOptimizer::MigrateMoves(Instruction* to, Instruction* from) { |
| OperandSet dst_cant_be(local_zone()); |
| OperandSet src_cant_be(local_zone()); |
| + int dst_fp_reg_reps = 0; |
| + int src_fp_reg_reps = 0; |
| // If an operand is an input to the instruction, we cannot move assignments |
| // where it appears on the LHS. |
| for (size_t i = 0; i < from->InputCount(); ++i) { |
| - dst_cant_be.insert(*from->InputAt(i)); |
| + InsertOp(&dst_cant_be, *from->InputAt(i), &dst_fp_reg_reps); |
| } |
| // If an operand is output to the instruction, we cannot move assignments |
| // where it appears on the RHS, because we would lose its value before the |
| @@ -149,10 +213,10 @@ void MoveOptimizer::MigrateMoves(Instruction* to, Instruction* from) { |
| // The output can't appear on the LHS because we performed |
| // RemoveClobberedDestinations for the "from" instruction. |
| for (size_t i = 0; i < from->OutputCount(); ++i) { |
| - src_cant_be.insert(*from->OutputAt(i)); |
| + InsertOp(&src_cant_be, *from->OutputAt(i), &src_fp_reg_reps); |
| } |
| for (size_t i = 0; i < from->TempCount(); ++i) { |
| - src_cant_be.insert(*from->TempAt(i)); |
| + InsertOp(&src_cant_be, *from->TempAt(i), &src_fp_reg_reps); |
| } |
| for (MoveOperands* move : *from_moves) { |
| if (move->IsRedundant()) continue; |
| @@ -160,7 +224,7 @@ void MoveOptimizer::MigrateMoves(Instruction* to, Instruction* from) { |
| // move "z = dest", because z would become y rather than "V". |
| // We assume CompressMoves has happened before this, which means we don't |
| // have more than one assignment to dest. |
| - src_cant_be.insert(move->destination()); |
| + InsertOp(&src_cant_be, move->destination(), &src_fp_reg_reps); |
| } |
| ZoneSet<MoveKey, MoveKeyCompare> move_candidates(local_zone()); |
| @@ -168,7 +232,7 @@ void MoveOptimizer::MigrateMoves(Instruction* to, Instruction* from) { |
| // destination operands are eligible for being moved down. |
| for (MoveOperands* move : *from_moves) { |
| if (move->IsRedundant()) continue; |
| - if (!Blocks(dst_cant_be, move->destination())) { |
| + if (!ContainsOpOrAlias(dst_cant_be, move->destination(), dst_fp_reg_reps)) { |
| MoveKey key = {move->source(), move->destination()}; |
| move_candidates.insert(key); |
| } |
| @@ -183,8 +247,8 @@ void MoveOptimizer::MigrateMoves(Instruction* to, Instruction* from) { |
| auto current = iter; |
| ++iter; |
| InstructionOperand src = current->source; |
| - if (Blocks(src_cant_be, src)) { |
| - src_cant_be.insert(current->destination); |
| + if (ContainsOpOrAlias(src_cant_be, src, src_fp_reg_reps)) { |
| + InsertOp(&src_cant_be, current->destination, &src_fp_reg_reps); |
| move_candidates.erase(current); |
| changed = true; |
| } |
| @@ -223,8 +287,7 @@ void MoveOptimizer::CompressMoves(ParallelMove* left, MoveOpVector* right) { |
| // merging the two gaps. |
| for (MoveOperands* move : *right) { |
| if (move->IsRedundant()) continue; |
| - MoveOperands* to_eliminate = left->PrepareInsertAfter(move); |
| - if (to_eliminate != nullptr) eliminated.push_back(to_eliminate); |
| + left->PrepareInsertAfter(move, &eliminated); |
| } |
| // Eliminate dead moves. |
| for (MoveOperands* to_eliminate : eliminated) { |