Commit 89c41535 authored by mmassi@chromium.org's avatar mmassi@chromium.org

Foundation for the use of informative definitions in Crankshaft.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13543 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 80157b61
......@@ -501,8 +501,6 @@ bool LCodeGen::IsInteger32(LConstantOperand* op) const {
int LCodeGen::ToInteger32(LConstantOperand* op) const {
HConstant* constant = chunk_->LookupConstant(op);
ASSERT(chunk_->LookupLiteralRepresentation(op).IsInteger32());
ASSERT(constant->HasInteger32Value());
return constant->Integer32Value();
}
......
......@@ -35,7 +35,6 @@ namespace v8 {
namespace internal {
// TODO(svenpanne) Merge with OptimizingCompiler::OptimizeGraph().
static LChunk* OptimizeGraph(HGraph* graph) {
AssertNoAllocation no_gc;
NoHandleAllocation no_handles;
......@@ -129,7 +128,8 @@ void CodeStubGraphBuilder<KeyedLoadFastElementStub>::BuildCodeStub() {
HInstruction* load = BuildUncheckedMonomorphicElementAccess(
GetParameter(0), GetParameter(1), NULL, NULL,
casted_stub()->is_js_array(), casted_stub()->elements_kind(), false);
casted_stub()->is_js_array(), casted_stub()->elements_kind(),
false, Representation::Tagged());
AddInstruction(load);
HReturn* ret = new(zone) HReturn(load, context());
......
......@@ -774,6 +774,28 @@ void HBoundsCheck::PrintDataTo(StringStream* stream) {
}
void HBoundsCheck::InferRepresentation(HInferRepresentation* h_infer) {
ASSERT(CheckFlag(kFlexibleRepresentation));
Representation r;
if (key_mode_ == DONT_ALLOW_SMI_KEY ||
!length()->representation().IsTagged()) {
r = Representation::Integer32();
} else if (index()->representation().IsTagged() ||
(index()->IsConstant() &&
HConstant::cast(index())->HasInteger32Value() &&
Smi::IsValid(HConstant::cast(index())->Integer32Value()))) {
// If the index is tagged, or a constant that holds a Smi, allow the length
// to be tagged, since it is usually already tagged from loading it out of
// the length field of a JSArray. This allows for direct comparison without
// untagging.
r = Representation::Tagged();
} else {
r = Representation::Integer32();
}
UpdateRepresentation(r, h_infer, "boundscheck");
}
void HCallConstantFunction::PrintDataTo(StringStream* stream) {
if (IsApplyFunction()) {
stream->Add("optimized apply ");
......
......@@ -673,6 +673,31 @@ class HValue: public ZoneObject {
return NULL;
}
// There are HInstructions that do not really change a value, they
// only add pieces of information to it (like bounds checks, map checks,
// smi checks...).
// We call these instructions "informative definitions", or "iDef".
// One of the iDef operands is special because it is the value that is
// "transferred" to the output, we call it the "redefined operand".
// If an HValue is an iDef it must override RedefinedOperandIndex() so that
// it does not return kNoRedefinedOperand;
static const int kNoRedefinedOperand = -1;
virtual int RedefinedOperandIndex() { return kNoRedefinedOperand; }
bool IsInformativeDefinition() {
return RedefinedOperandIndex() != kNoRedefinedOperand;
}
HValue* RedefinedOperand() {
ASSERT(IsInformativeDefinition());
return OperandAt(RedefinedOperandIndex());
}
// This method must always return the original HValue SSA definition
// (regardless of any iDef of this value).
HValue* ActualValue() {
return IsInformativeDefinition() ? RedefinedOperand()->ActualValue()
: this;
}
bool IsDefinedAfter(HBasicBlock* other) const;
// Operands.
......@@ -3020,44 +3045,38 @@ enum BoundsCheckKeyMode {
class HBoundsCheck: public HTemplateInstruction<2> {
public:
HBoundsCheck(HValue* index, HValue* length,
BoundsCheckKeyMode key_mode = DONT_ALLOW_SMI_KEY)
BoundsCheckKeyMode key_mode = DONT_ALLOW_SMI_KEY,
Representation r = Representation::None())
: key_mode_(key_mode) {
SetOperandAt(0, index);
SetOperandAt(1, length);
set_representation(Representation::Integer32());
if (r.IsNone()) {
// In the normal compilation pipeline the representation is flexible
// (see comment to RequiredInputRepresentation).
SetFlag(kFlexibleRepresentation);
} else {
// When compiling stubs we want to set the representation explicitly
// so the compilation pipeline can skip the HInferRepresentation phase.
set_representation(r);
}
SetFlag(kUseGVN);
}
virtual Representation RequiredInputRepresentation(int arg_index) {
if (key_mode_ == DONT_ALLOW_SMI_KEY ||
!length()->representation().IsTagged()) {
return Representation::Integer32();
}
// If the index is tagged and isn't constant, then allow the length
// to be tagged, since it is usually already tagged from loading it out of
// the length field of a JSArray. This allows for direct comparison without
// untagging.
if (index()->representation().IsTagged() && !index()->IsConstant()) {
return Representation::Tagged();
}
// Also allow the length to be tagged if the index is constant, because
// it can be tagged to allow direct comparison.
if (index()->IsConstant() &&
index()->representation().IsInteger32() &&
arg_index == 1) {
return Representation::Tagged();
}
return Representation::Integer32();
return representation();
}
virtual Representation observed_input_representation(int index) {
return Representation::Integer32();
}
virtual void PrintDataTo(StringStream* stream);
virtual void InferRepresentation(HInferRepresentation* h_infer);
HValue* index() { return OperandAt(0); }
HValue* length() { return OperandAt(1); }
virtual int RedefinedOperandIndex() { return 0; }
DECLARE_CONCRETE_INSTRUCTION(BoundsCheck)
protected:
......@@ -4433,6 +4452,11 @@ class ArrayInstructionInterface {
virtual bool IsDehoisted() = 0;
virtual void SetDehoisted(bool is_dehoisted) = 0;
virtual ~ArrayInstructionInterface() { };
static Representation KeyedAccessIndexRequirement(Representation r) {
return r.IsInteger32() ? Representation::Integer32()
: Representation::Tagged();
}
};
......@@ -4516,7 +4540,10 @@ class HLoadKeyed
return is_external() ? Representation::External()
: Representation::Tagged();
}
if (index == 1) return Representation::Integer32();
if (index == 1) {
return ArrayInstructionInterface::KeyedAccessIndexRequirement(
OperandAt(1)->representation());
}
return Representation::None();
}
......@@ -4731,7 +4758,8 @@ class HStoreKeyed
return is_external() ? Representation::External()
: Representation::Tagged();
} else if (index == 1) {
return Representation::Integer32();
return ArrayInstructionInterface::KeyedAccessIndexRequirement(
OperandAt(1)->representation());
}
ASSERT_EQ(index, 2);
......
......@@ -745,7 +745,8 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
HCheckMaps* mapcheck,
bool is_js_array,
ElementsKind elements_kind,
bool is_store) {
bool is_store,
Representation checked_index_representation) {
Zone* zone = this->zone();
// No GVNFlag is necessary for ElementsKind if there is an explicit dependency
// on a HElementsTransition instruction. The flag can also be removed if the
......@@ -773,8 +774,8 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
HInstruction* checked_key = NULL;
if (IsExternalArrayElementsKind(elements_kind)) {
length = AddInstruction(new(zone) HFixedArrayBaseLength(elements));
checked_key = AddInstruction(new(zone) HBoundsCheck(key, length,
ALLOW_SMI_KEY));
checked_key = AddInstruction(new(zone) HBoundsCheck(
key, length, ALLOW_SMI_KEY, checked_index_representation));
HLoadExternalArrayPointer* external_elements =
new(zone) HLoadExternalArrayPointer(elements);
AddInstruction(external_elements);
......@@ -791,8 +792,8 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
} else {
length = AddInstruction(new(zone) HFixedArrayBaseLength(elements));
}
checked_key = AddInstruction(new(zone) HBoundsCheck(key, length,
ALLOW_SMI_KEY));
checked_key = AddInstruction(new(zone) HBoundsCheck(
key, length, ALLOW_SMI_KEY, checked_index_representation));
return BuildFastElementAccess(elements, checked_key, val, mapcheck,
elements_kind, is_store);
}
......@@ -3586,10 +3587,12 @@ bool HGraph::Optimize(SmartArrayPointer<char>* bailout_reason) {
HStackCheckEliminator sce(this);
sce.Process();
EliminateRedundantBoundsChecks();
DehoistSimpleArrayIndexComputations();
if (FLAG_array_bounds_checks_elimination) EliminateRedundantBoundsChecks();
if (FLAG_array_index_dehoisting) DehoistSimpleArrayIndexComputations();
if (FLAG_dead_code_elimination) DeadCodeElimination();
RestoreActualValues();
return true;
}
......@@ -3727,6 +3730,7 @@ class BoundsCheckBbData: public ZoneObject {
new_check->index()->representation(),
new_offset);
if (!result) return false;
upper_check_->ReplaceAllUsesWith(upper_check_->index());
upper_check_->SetOperandAt(0, added_upper_index_);
}
} else if (new_offset < lower_offset_) {
......@@ -3742,6 +3746,7 @@ class BoundsCheckBbData: public ZoneObject {
new_check->index()->representation(),
new_offset);
if (!result) return false;
lower_check_->ReplaceAllUsesWith(lower_check_->index());
lower_check_->SetOperandAt(0, added_lower_index_);
}
} else {
......@@ -3749,7 +3754,7 @@ class BoundsCheckBbData: public ZoneObject {
}
if (!keep_new_check) {
new_check->DeleteAndReplaceWith(NULL);
new_check->DeleteAndReplaceWith(new_check->ActualValue());
}
return true;
......@@ -3885,10 +3890,6 @@ void HGraph::EliminateRedundantBoundsChecks(HBasicBlock* bb,
if (!i->IsBoundsCheck()) continue;
HBoundsCheck* check = HBoundsCheck::cast(i);
check->ReplaceAllUsesWith(check->index());
if (!FLAG_array_bounds_checks_elimination) continue;
int32_t offset;
BoundsCheckKey* key =
BoundsCheckKey::Create(zone(), check, &offset);
......@@ -3906,7 +3907,7 @@ void HGraph::EliminateRedundantBoundsChecks(HBasicBlock* bb,
NULL);
*data_p = bb_data_list;
} else if (data->OffsetIsCovered(offset)) {
check->DeleteAndReplaceWith(NULL);
check->DeleteAndReplaceWith(check->ActualValue());
} else if (data->BasicBlock() != bb ||
!data->CoverCheck(check, offset)) {
// If the check is in the current BB we try to modify it by calling
......@@ -3955,7 +3956,7 @@ void HGraph::EliminateRedundantBoundsChecks() {
static void DehoistArrayIndex(ArrayInstructionInterface* array_operation) {
HValue* index = array_operation->GetKey();
HValue* index = array_operation->GetKey()->ActualValue();
if (!index->representation().IsInteger32()) return;
HConstant* constant;
......@@ -4003,8 +4004,6 @@ static void DehoistArrayIndex(ArrayInstructionInterface* array_operation) {
void HGraph::DehoistSimpleArrayIndexComputations() {
if (!FLAG_array_index_dehoisting) return;
HPhase phase("H_Dehoist index computations", this);
for (int i = 0; i < blocks()->length(); ++i) {
for (HInstruction* instr = blocks()->at(i)->first();
......@@ -4056,6 +4055,30 @@ void HGraph::DeadCodeElimination() {
}
void HGraph::RestoreActualValues() {
HPhase phase("H_Restore actual values", this);
for (int block_index = 0; block_index < blocks()->length(); block_index++) {
HBasicBlock* block = blocks()->at(block_index);
#ifdef DEBUG
for (int i = 0; i < block->phis()->length(); i++) {
HPhi* phi = block->phis()->at(i);
ASSERT(phi->ActualValue() == phi);
}
#endif
for (HInstruction* instruction = block->first();
instruction != NULL;
instruction = instruction->next()) {
if (instruction->ActualValue() != instruction) {
instruction->ReplaceAllUsesWith(instruction->ActualValue());
}
}
}
}
void HOptimizedGraphBuilder::AddPhi(HPhi* instr) {
ASSERT(current_block() != NULL);
current_block()->AddPhi(instr);
......
......@@ -273,6 +273,7 @@ class HGraph: public ZoneObject {
void EliminateRedundantBoundsChecks();
void DehoistSimpleArrayIndexComputations();
void DeadCodeElimination();
void RestoreActualValues();
void PropagateDeoptimizingMark();
void EliminateUnusedInstructions();
......@@ -897,7 +898,8 @@ class HGraphBuilder {
HCheckMaps* mapcheck,
bool is_js_array,
ElementsKind elements_kind,
bool is_store);
bool is_store,
Representation checked_index_representation = Representation::None());
private:
HGraphBuilder();
......
......@@ -502,8 +502,6 @@ XMMRegister LCodeGen::ToDoubleRegister(LOperand* op) const {
int LCodeGen::ToInteger32(LConstantOperand* op) const {
HConstant* constant = chunk_->LookupConstant(op);
ASSERT(chunk_->LookupLiteralRepresentation(op).IsInteger32());
ASSERT(constant->HasInteger32Value());
return constant->Integer32Value();
}
......@@ -3207,13 +3205,6 @@ Operand LCodeGen::BuildFastArrayOperand(
uint32_t additional_index) {
Register elements_pointer_reg = ToRegister(elements_pointer);
int shift_size = ElementsKindToShiftSize(elements_kind);
// Even though the HLoad/StoreKeyed instructions force the input
// representation for the key to be an integer, the input gets replaced during
// bound check elimination with the index argument to the bounds check, which
// can be tagged, so that case must be handled here, too.
if (key_representation.IsTagged() && (shift_size >= 1)) {
shift_size -= kSmiTagSize;
}
if (key->IsConstantOperand()) {
int constant_value = ToInteger32(LConstantOperand::cast(key));
if (constant_value & 0xF0000000) {
......@@ -3223,6 +3214,10 @@ Operand LCodeGen::BuildFastArrayOperand(
((constant_value + additional_index) << shift_size)
+ offset);
} else {
// Take the tag bit into account while computing the shift size.
if (key_representation.IsTagged() && (shift_size >= 1)) {
shift_size -= kSmiTagSize;
}
ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
return Operand(elements_pointer_reg,
ToRegister(key),
......
......@@ -490,8 +490,6 @@ bool LCodeGen::IsInteger32(LConstantOperand* op) const {
int LCodeGen::ToInteger32(LConstantOperand* op) const {
HConstant* constant = chunk_->LookupConstant(op);
ASSERT(chunk_->LookupLiteralRepresentation(op).IsInteger32());
ASSERT(constant->HasInteger32Value());
return constant->Integer32Value();
}
......
......@@ -425,8 +425,6 @@ bool LCodeGen::IsTaggedConstant(LConstantOperand* op) const {
int LCodeGen::ToInteger32(LConstantOperand* op) const {
HConstant* constant = chunk_->LookupConstant(op);
ASSERT(chunk_->LookupLiteralRepresentation(op).IsInteger32());
ASSERT(constant->HasInteger32Value());
return constant->Integer32Value();
}
......
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