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