2013-07-08 09:02:09 +00:00
|
|
|
// Copyright 2013 the V8 project authors. All rights reserved.
|
2014-04-29 06:42:26 +00:00
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
2013-07-08 09:02:09 +00:00
|
|
|
|
2014-06-03 08:12:43 +00:00
|
|
|
#include "src/hydrogen-representation-changes.h"
|
2013-07-08 09:02:09 +00:00
|
|
|
|
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
|
|
|
|
|
|
|
void HRepresentationChangesPhase::InsertRepresentationChangeForUse(
|
|
|
|
HValue* value, HValue* use_value, int use_index, Representation to) {
|
|
|
|
// Insert the representation change right before its use. For phi-uses we
|
|
|
|
// insert at the end of the corresponding predecessor.
|
|
|
|
HInstruction* next = NULL;
|
|
|
|
if (use_value->IsPhi()) {
|
|
|
|
next = use_value->block()->predecessors()->at(use_index)->end();
|
|
|
|
} else {
|
|
|
|
next = HInstruction::cast(use_value);
|
|
|
|
}
|
|
|
|
// For constants we try to make the representation change at compile
|
|
|
|
// time. When a representation change is not possible without loss of
|
|
|
|
// information we treat constants like normal instructions and insert the
|
|
|
|
// change instructions for them.
|
|
|
|
HInstruction* new_value = NULL;
|
2013-07-25 11:53:38 +00:00
|
|
|
bool is_truncating_to_smi = use_value->CheckFlag(HValue::kTruncatingToSmi);
|
|
|
|
bool is_truncating_to_int = use_value->CheckFlag(HValue::kTruncatingToInt32);
|
2013-07-08 09:02:09 +00:00
|
|
|
if (value->IsConstant()) {
|
|
|
|
HConstant* constant = HConstant::cast(value);
|
|
|
|
// Try to create a new copy of the constant with the new representation.
|
2013-07-25 11:53:38 +00:00
|
|
|
if (is_truncating_to_int && to.IsInteger32()) {
|
2013-07-23 09:13:59 +00:00
|
|
|
Maybe<HConstant*> res = constant->CopyToTruncatedInt32(graph()->zone());
|
2015-03-02 12:22:27 +00:00
|
|
|
if (res.IsJust()) new_value = res.FromJust();
|
2013-07-23 09:13:59 +00:00
|
|
|
} else {
|
|
|
|
new_value = constant->CopyToRepresentation(to, graph()->zone());
|
|
|
|
}
|
2013-07-08 09:02:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (new_value == NULL) {
|
2013-08-14 08:54:27 +00:00
|
|
|
new_value = new(graph()->zone()) HChange(
|
|
|
|
value, to, is_truncating_to_smi, is_truncating_to_int);
|
2014-02-13 16:09:28 +00:00
|
|
|
if (!use_value->operand_position(use_index).IsUnknown()) {
|
2013-11-18 17:24:00 +00:00
|
|
|
new_value->set_position(use_value->operand_position(use_index));
|
2013-10-21 13:35:48 +00:00
|
|
|
} else {
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(!FLAG_hydrogen_track_positions ||
|
2014-02-13 16:09:28 +00:00
|
|
|
!graph()->info()->IsOptimizing());
|
2013-10-21 13:35:48 +00:00
|
|
|
}
|
2013-07-08 09:02:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
new_value->InsertBefore(next);
|
|
|
|
use_value->SetOperandAt(use_index, new_value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
Remove forced type changes when they can't deopt
Hydrogen attempts to force representation changes on certain operations in order
to deoptimise on the change rather than the operation. However, these forced
changes are often unnecessary on 64-bit platforms, and cause poor code
generation, so this patch makes some of them conditional on whether it's
possible for deoptimisation to occur in the change.
On ARM64, this prevents sequences like:
;;; <@46,#89> smi-tag
0x7ff282c7f050 144 lsl x4, x4, #32
;;; <@48,#90> smi-untag
0x7ff282c7f054 148 asr x5, x4, #32
;;; <@50,#31> mul-const-i-s
0x7ff282c7f058 152 lsl w6, w5, #3
BUG=
R=jkummerow@chromium.org
Review URL: https://codereview.chromium.org/303263010
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21818 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
2014-06-12 16:47:51 +00:00
|
|
|
static bool IsNonDeoptingIntToSmiChange(HChange* change) {
|
|
|
|
Representation from_rep = change->from();
|
|
|
|
Representation to_rep = change->to();
|
|
|
|
// Flags indicating Uint32 operations are set in a later Hydrogen phase.
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(!change->CheckFlag(HValue::kUint32));
|
Remove forced type changes when they can't deopt
Hydrogen attempts to force representation changes on certain operations in order
to deoptimise on the change rather than the operation. However, these forced
changes are often unnecessary on 64-bit platforms, and cause poor code
generation, so this patch makes some of them conditional on whether it's
possible for deoptimisation to occur in the change.
On ARM64, this prevents sequences like:
;;; <@46,#89> smi-tag
0x7ff282c7f050 144 lsl x4, x4, #32
;;; <@48,#90> smi-untag
0x7ff282c7f054 148 asr x5, x4, #32
;;; <@50,#31> mul-const-i-s
0x7ff282c7f058 152 lsl w6, w5, #3
BUG=
R=jkummerow@chromium.org
Review URL: https://codereview.chromium.org/303263010
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21818 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
2014-06-12 16:47:51 +00:00
|
|
|
return from_rep.IsInteger32() && to_rep.IsSmi() && SmiValuesAre32Bits();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-07-08 09:02:09 +00:00
|
|
|
void HRepresentationChangesPhase::InsertRepresentationChangesForValue(
|
|
|
|
HValue* value) {
|
|
|
|
Representation r = value->representation();
|
2014-10-06 11:42:13 +00:00
|
|
|
if (r.IsNone()) {
|
|
|
|
#ifdef DEBUG
|
|
|
|
for (HUseIterator it(value->uses()); !it.Done(); it.Advance()) {
|
|
|
|
HValue* use_value = it.value();
|
|
|
|
int use_index = it.index();
|
|
|
|
Representation req = use_value->RequiredInputRepresentation(use_index);
|
|
|
|
DCHECK(req.IsNone());
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
2014-03-06 09:47:27 +00:00
|
|
|
if (value->HasNoUses()) {
|
|
|
|
if (value->IsForceRepresentation()) value->DeleteAndReplaceWith(NULL);
|
|
|
|
return;
|
|
|
|
}
|
2013-07-08 09:02:09 +00:00
|
|
|
|
|
|
|
for (HUseIterator it(value->uses()); !it.Done(); it.Advance()) {
|
|
|
|
HValue* use_value = it.value();
|
|
|
|
int use_index = it.index();
|
|
|
|
Representation req = use_value->RequiredInputRepresentation(use_index);
|
|
|
|
if (req.IsNone() || req.Equals(r)) continue;
|
Remove forced type changes when they can't deopt
Hydrogen attempts to force representation changes on certain operations in order
to deoptimise on the change rather than the operation. However, these forced
changes are often unnecessary on 64-bit platforms, and cause poor code
generation, so this patch makes some of them conditional on whether it's
possible for deoptimisation to occur in the change.
On ARM64, this prevents sequences like:
;;; <@46,#89> smi-tag
0x7ff282c7f050 144 lsl x4, x4, #32
;;; <@48,#90> smi-untag
0x7ff282c7f054 148 asr x5, x4, #32
;;; <@50,#31> mul-const-i-s
0x7ff282c7f058 152 lsl w6, w5, #3
BUG=
R=jkummerow@chromium.org
Review URL: https://codereview.chromium.org/303263010
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21818 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
2014-06-12 16:47:51 +00:00
|
|
|
|
|
|
|
// If this is an HForceRepresentation instruction, and an HChange has been
|
|
|
|
// inserted above it, examine the input representation of the HChange. If
|
|
|
|
// that's int32, and this HForceRepresentation use is int32, and int32 to
|
|
|
|
// smi changes can't cause deoptimisation, set the input of the use to the
|
|
|
|
// input of the HChange.
|
|
|
|
if (value->IsForceRepresentation()) {
|
|
|
|
HValue* input = HForceRepresentation::cast(value)->value();
|
|
|
|
if (input->IsChange()) {
|
|
|
|
HChange* change = HChange::cast(input);
|
|
|
|
if (change->from().Equals(req) && IsNonDeoptingIntToSmiChange(change)) {
|
|
|
|
use_value->SetOperandAt(use_index, change->value());
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-07-08 09:02:09 +00:00
|
|
|
InsertRepresentationChangeForUse(value, use_value, use_index, req);
|
|
|
|
}
|
|
|
|
if (value->HasNoUses()) {
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(value->IsConstant() || value->IsForceRepresentation());
|
2013-07-08 09:02:09 +00:00
|
|
|
value->DeleteAndReplaceWith(NULL);
|
Remove forced type changes when they can't deopt
Hydrogen attempts to force representation changes on certain operations in order
to deoptimise on the change rather than the operation. However, these forced
changes are often unnecessary on 64-bit platforms, and cause poor code
generation, so this patch makes some of them conditional on whether it's
possible for deoptimisation to occur in the change.
On ARM64, this prevents sequences like:
;;; <@46,#89> smi-tag
0x7ff282c7f050 144 lsl x4, x4, #32
;;; <@48,#90> smi-untag
0x7ff282c7f054 148 asr x5, x4, #32
;;; <@50,#31> mul-const-i-s
0x7ff282c7f058 152 lsl w6, w5, #3
BUG=
R=jkummerow@chromium.org
Review URL: https://codereview.chromium.org/303263010
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21818 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
2014-06-12 16:47:51 +00:00
|
|
|
} else {
|
|
|
|
// The only purpose of a HForceRepresentation is to represent the value
|
|
|
|
// after the (possible) HChange instruction. We make it disappear.
|
|
|
|
if (value->IsForceRepresentation()) {
|
|
|
|
value->DeleteAndReplaceWith(HForceRepresentation::cast(value)->value());
|
|
|
|
}
|
2013-07-08 09:02:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void HRepresentationChangesPhase::Run() {
|
|
|
|
// Compute truncation flag for phis: Initially assume that all
|
|
|
|
// int32-phis allow truncation and iteratively remove the ones that
|
|
|
|
// are used in an operation that does not allow a truncating
|
|
|
|
// conversion.
|
2013-08-27 13:55:00 +00:00
|
|
|
ZoneList<HPhi*> int_worklist(8, zone());
|
|
|
|
ZoneList<HPhi*> smi_worklist(8, zone());
|
2013-07-08 09:02:09 +00:00
|
|
|
|
|
|
|
const ZoneList<HPhi*>* phi_list(graph()->phi_list());
|
|
|
|
for (int i = 0; i < phi_list->length(); i++) {
|
|
|
|
HPhi* phi = phi_list->at(i);
|
|
|
|
if (phi->representation().IsInteger32()) {
|
|
|
|
phi->SetFlag(HValue::kTruncatingToInt32);
|
2013-07-25 11:53:38 +00:00
|
|
|
} else if (phi->representation().IsSmi()) {
|
|
|
|
phi->SetFlag(HValue::kTruncatingToSmi);
|
2013-08-27 13:55:00 +00:00
|
|
|
phi->SetFlag(HValue::kTruncatingToInt32);
|
2013-07-08 09:02:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < phi_list->length(); i++) {
|
|
|
|
HPhi* phi = phi_list->at(i);
|
2013-08-27 13:55:00 +00:00
|
|
|
HValue* value = NULL;
|
|
|
|
if (phi->representation().IsSmiOrInteger32() &&
|
|
|
|
!phi->CheckUsesForFlag(HValue::kTruncatingToInt32, &value)) {
|
|
|
|
int_worklist.Add(phi, zone());
|
|
|
|
phi->ClearFlag(HValue::kTruncatingToInt32);
|
|
|
|
if (FLAG_trace_representation) {
|
|
|
|
PrintF("#%d Phi is not truncating Int32 because of #%d %s\n",
|
|
|
|
phi->id(), value->id(), value->Mnemonic());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (phi->representation().IsSmi() &&
|
|
|
|
!phi->CheckUsesForFlag(HValue::kTruncatingToSmi, &value)) {
|
|
|
|
smi_worklist.Add(phi, zone());
|
|
|
|
phi->ClearFlag(HValue::kTruncatingToSmi);
|
|
|
|
if (FLAG_trace_representation) {
|
|
|
|
PrintF("#%d Phi is not truncating Smi because of #%d %s\n",
|
|
|
|
phi->id(), value->id(), value->Mnemonic());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
while (!int_worklist.is_empty()) {
|
|
|
|
HPhi* current = int_worklist.RemoveLast();
|
|
|
|
for (int i = 0; i < current->OperandCount(); ++i) {
|
|
|
|
HValue* input = current->OperandAt(i);
|
|
|
|
if (input->IsPhi() &&
|
|
|
|
input->representation().IsSmiOrInteger32() &&
|
|
|
|
input->CheckFlag(HValue::kTruncatingToInt32)) {
|
2013-07-08 09:02:09 +00:00
|
|
|
if (FLAG_trace_representation) {
|
2013-08-27 13:55:00 +00:00
|
|
|
PrintF("#%d Phi is not truncating Int32 because of #%d %s\n",
|
|
|
|
input->id(), current->id(), current->Mnemonic());
|
2013-07-08 09:02:09 +00:00
|
|
|
}
|
2013-08-27 13:55:00 +00:00
|
|
|
input->ClearFlag(HValue::kTruncatingToInt32);
|
|
|
|
int_worklist.Add(HPhi::cast(input), zone());
|
2013-07-08 09:02:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-27 13:55:00 +00:00
|
|
|
while (!smi_worklist.is_empty()) {
|
|
|
|
HPhi* current = smi_worklist.RemoveLast();
|
2013-07-08 09:02:09 +00:00
|
|
|
for (int i = 0; i < current->OperandCount(); ++i) {
|
|
|
|
HValue* input = current->OperandAt(i);
|
|
|
|
if (input->IsPhi() &&
|
2013-08-27 13:55:00 +00:00
|
|
|
input->representation().IsSmi() &&
|
|
|
|
input->CheckFlag(HValue::kTruncatingToSmi)) {
|
2013-07-08 09:02:09 +00:00
|
|
|
if (FLAG_trace_representation) {
|
2013-08-27 13:55:00 +00:00
|
|
|
PrintF("#%d Phi is not truncating Smi because of #%d %s\n",
|
2013-07-08 09:02:09 +00:00
|
|
|
input->id(), current->id(), current->Mnemonic());
|
|
|
|
}
|
2013-07-25 11:53:38 +00:00
|
|
|
input->ClearFlag(HValue::kTruncatingToSmi);
|
2013-08-27 13:55:00 +00:00
|
|
|
smi_worklist.Add(HPhi::cast(input), zone());
|
2013-07-08 09:02:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const ZoneList<HBasicBlock*>* blocks(graph()->blocks());
|
|
|
|
for (int i = 0; i < blocks->length(); ++i) {
|
|
|
|
// Process phi instructions first.
|
|
|
|
const HBasicBlock* block(blocks->at(i));
|
|
|
|
const ZoneList<HPhi*>* phis = block->phis();
|
|
|
|
for (int j = 0; j < phis->length(); j++) {
|
|
|
|
InsertRepresentationChangesForValue(phis->at(j));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Process normal instructions.
|
|
|
|
for (HInstruction* current = block->first(); current != NULL; ) {
|
|
|
|
HInstruction* next = current->next();
|
|
|
|
InsertRepresentationChangesForValue(current);
|
|
|
|
current = next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} } // namespace v8::internal
|