ARM: Avoid duplicate vmla when merging vmul and vadd

Avoid generating duplicate vmla instructions for vmul/vadd sequences where the
vmul has more than one use.

For example: function f(a, b, c) { return (a * b) + c + (a * b); }

Previously, this would produce a vmul for the subexpression (a * b), then vmla
for (a * b) + c, then vmla for (a * b) + [(a * b) + c].

Now it produces vmul, vadd, vadd, as expected.

BUG=
R=ulan@chromium.org

Review URL: https://codereview.chromium.org/323423003

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21899 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 5eb7ce90
...@@ -1500,8 +1500,8 @@ LInstruction* LChunkBuilder::DoMul(HMul* instr) { ...@@ -1500,8 +1500,8 @@ LInstruction* LChunkBuilder::DoMul(HMul* instr) {
return DefineAsRegister(mul); return DefineAsRegister(mul);
} else if (instr->representation().IsDouble()) { } else if (instr->representation().IsDouble()) {
if (instr->UseCount() == 1 && (instr->uses().value()->IsAdd() || if (instr->HasOneUse() && (instr->uses().value()->IsAdd() ||
instr->uses().value()->IsSub())) { instr->uses().value()->IsSub())) {
HBinaryOperation* use = HBinaryOperation::cast(instr->uses().value()); HBinaryOperation* use = HBinaryOperation::cast(instr->uses().value());
if (use->IsAdd() && instr == use->left()) { if (use->IsAdd() && instr == use->left()) {
...@@ -1547,7 +1547,7 @@ LInstruction* LChunkBuilder::DoSub(HSub* instr) { ...@@ -1547,7 +1547,7 @@ LInstruction* LChunkBuilder::DoSub(HSub* instr) {
} }
return result; return result;
} else if (instr->representation().IsDouble()) { } else if (instr->representation().IsDouble()) {
if (instr->right()->IsMul()) { if (instr->right()->IsMul() && instr->right()->HasOneUse()) {
return DoMultiplySub(instr->left(), HMul::cast(instr->right())); return DoMultiplySub(instr->left(), HMul::cast(instr->right()));
} }
...@@ -1618,12 +1618,12 @@ LInstruction* LChunkBuilder::DoAdd(HAdd* instr) { ...@@ -1618,12 +1618,12 @@ LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
LInstruction* result = DefineAsRegister(add); LInstruction* result = DefineAsRegister(add);
return result; return result;
} else if (instr->representation().IsDouble()) { } else if (instr->representation().IsDouble()) {
if (instr->left()->IsMul()) { if (instr->left()->IsMul() && instr->left()->HasOneUse()) {
return DoMultiplyAdd(HMul::cast(instr->left()), instr->right()); return DoMultiplyAdd(HMul::cast(instr->left()), instr->right());
} }
if (instr->right()->IsMul()) { if (instr->right()->IsMul() && instr->right()->HasOneUse()) {
ASSERT(!instr->left()->IsMul()); ASSERT(!instr->left()->IsMul() || !instr->left()->HasOneUse());
return DoMultiplyAdd(HMul::cast(instr->right()), instr->left()); return DoMultiplyAdd(HMul::cast(instr->right()), instr->left());
} }
......
...@@ -1581,7 +1581,7 @@ HValue* HUnaryMathOperation::Canonicalize() { ...@@ -1581,7 +1581,7 @@ HValue* HUnaryMathOperation::Canonicalize() {
val, representation(), false, false)); val, representation(), false, false));
} }
} }
if (op() == kMathFloor && value()->IsDiv() && value()->UseCount() == 1) { if (op() == kMathFloor && value()->IsDiv() && value()->HasOneUse()) {
HDiv* hdiv = HDiv::cast(value()); HDiv* hdiv = HDiv::cast(value());
HValue* left = hdiv->left(); HValue* left = hdiv->left();
...@@ -2149,7 +2149,7 @@ void InductionVariableData::ChecksRelatedToLength::UseNewIndexInCurrentBlock( ...@@ -2149,7 +2149,7 @@ void InductionVariableData::ChecksRelatedToLength::UseNewIndexInCurrentBlock(
added_index()->SetOperandAt(1, index_base); added_index()->SetOperandAt(1, index_base);
added_index()->SetOperandAt(2, added_constant()); added_index()->SetOperandAt(2, added_constant());
first_check_in_block()->SetOperandAt(0, added_index()); first_check_in_block()->SetOperandAt(0, added_index());
if (previous_index->UseCount() == 0) { if (previous_index->HasNoUses()) {
previous_index->DeleteAndReplaceWith(NULL); previous_index->DeleteAndReplaceWith(NULL);
} }
} }
...@@ -2893,7 +2893,7 @@ bool HConstant::EmitAtUses() { ...@@ -2893,7 +2893,7 @@ bool HConstant::EmitAtUses() {
// TODO(titzer): this seems like a hack that should be fixed by custom OSR. // TODO(titzer): this seems like a hack that should be fixed by custom OSR.
return true; return true;
} }
if (UseCount() == 0) return true; if (HasNoUses()) return true;
if (IsCell()) return false; if (IsCell()) return false;
if (representation().IsDouble()) return false; if (representation().IsDouble()) return false;
if (representation().IsExternal()) return false; if (representation().IsExternal()) return false;
......
...@@ -663,6 +663,9 @@ class HValue : public ZoneObject { ...@@ -663,6 +663,9 @@ class HValue : public ZoneObject {
void DeleteAndReplaceWith(HValue* other); void DeleteAndReplaceWith(HValue* other);
void ReplaceAllUsesWith(HValue* other); void ReplaceAllUsesWith(HValue* other);
bool HasNoUses() const { return use_list_ == NULL; } bool HasNoUses() const { return use_list_ == NULL; }
bool HasOneUse() const {
return use_list_ != NULL && use_list_->tail() == NULL;
}
bool HasMultipleUses() const { bool HasMultipleUses() const {
return use_list_ != NULL && use_list_->tail() != NULL; return use_list_ != NULL && use_list_->tail() != NULL;
} }
...@@ -3760,7 +3763,7 @@ class HBinaryOperation : public HTemplateInstruction<3> { ...@@ -3760,7 +3763,7 @@ class HBinaryOperation : public HTemplateInstruction<3> {
// Otherwise, if there is only one use of the right operand, it would be // Otherwise, if there is only one use of the right operand, it would be
// better off on the left for platforms that only have 2-arg arithmetic // better off on the left for platforms that only have 2-arg arithmetic
// ops (e.g ia32, x64) that clobber the left operand. // ops (e.g ia32, x64) that clobber the left operand.
return right()->UseCount() == 1; return right()->HasOneUse();
} }
HValue* BetterLeftOperand() { HValue* BetterLeftOperand() {
......
...@@ -1492,7 +1492,7 @@ LInstruction* LChunkBuilder::DoMul(HMul* instr) { ...@@ -1492,7 +1492,7 @@ LInstruction* LChunkBuilder::DoMul(HMul* instr) {
} else if (instr->representation().IsDouble()) { } else if (instr->representation().IsDouble()) {
if (kArchVariant == kMips32r2) { if (kArchVariant == kMips32r2) {
if (instr->UseCount() == 1 && instr->uses().value()->IsAdd()) { if (instr->HasOneUse() && instr->uses().value()->IsAdd()) {
HAdd* add = HAdd::cast(instr->uses().value()); HAdd* add = HAdd::cast(instr->uses().value());
if (instr == add->left()) { if (instr == add->left()) {
// This mul is the lhs of an add. The add and mul will be folded // This mul is the lhs of an add. The add and mul will be folded
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment