Added a simple dead code removal phase.

We iteratively remove all dead Hydrogen instruction until we reach a fixed point. We consider an instruction dead if it is unused, has no observable side effects and is deletable. The last part of the condition is currently not very nice: We basically have to whitelist "safe" instructions, because we are missing more detailed dependencies and/or more detailed tracking of side effects.

We disable dead code elimination for now in our test runners, because we have tons of poorly written tests which wouldn't test anymore what they are supposed to test with this phase enabled. To get test coverage for dead code elimination itself, we should enable it on a few build bots. This is not really a perfect state, but the best we can do for now.

This patch includes a few const-correctness fixes, most of them were necessary for this CL.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12697 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent bfb2db23
......@@ -202,6 +202,8 @@ DEFINE_bool(array_bounds_checks_elimination, true,
"perform array bounds checks elimination")
DEFINE_bool(array_index_dehoisting, true,
"perform array index dehoisting")
DEFINE_bool(dead_code_elimination, true, "use dead code elimination")
DEFINE_bool(trace_dead_code_elimination, false, "trace dead code elimination")
DEFINE_bool(trace_osr, false, "trace on-stack replacement")
DEFINE_int(stress_runs, 0, "number of stress runs")
......
......@@ -1854,7 +1854,7 @@ void HLoadKeyedFastElement::PrintDataTo(StringStream* stream) {
}
bool HLoadKeyedFastElement::RequiresHoleCheck() {
bool HLoadKeyedFastElement::RequiresHoleCheck() const {
if (IsFastPackedElementsKind(elements_kind())) {
return false;
}
......@@ -2090,7 +2090,7 @@ void HLoadGlobalCell::PrintDataTo(StringStream* stream) {
}
bool HLoadGlobalCell::RequiresHoleCheck() {
bool HLoadGlobalCell::RequiresHoleCheck() const {
if (details_.IsDontDelete() && !details_.IsReadOnly()) return false;
for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
HValue* use = it.value();
......
This diff is collapsed.
......@@ -3358,6 +3358,7 @@ bool HGraph::Optimize(SmartArrayPointer<char>* bailout_reason) {
EliminateRedundantBoundsChecks();
DehoistSimpleArrayIndexComputations();
if (FLAG_dead_code_elimination) DeadCodeElimination();
return true;
}
......@@ -3787,6 +3788,36 @@ void HGraph::DehoistSimpleArrayIndexComputations() {
}
void HGraph::DeadCodeElimination() {
HPhase phase("H_Dead code elimination", this);
ZoneList<HInstruction*> worklist(blocks_.length(), zone());
for (int i = 0; i < blocks()->length(); ++i) {
for (HInstruction* instr = blocks()->at(i)->first();
instr != NULL;
instr = instr->next()) {
if (instr->IsDead()) worklist.Add(instr, zone());
}
}
while (!worklist.is_empty()) {
HInstruction* instr = worklist.RemoveLast();
if (FLAG_trace_dead_code_elimination) {
HeapStringAllocator allocator;
StringStream stream(&allocator);
instr->PrintNameTo(&stream);
stream.Add(" = ");
instr->PrintTo(&stream);
PrintF("[removing dead instruction %s]\n", *stream.ToCString());
}
instr->DeleteAndReplaceWith(NULL);
for (int i = 0; i < instr->OperandCount(); ++i) {
HValue* operand = instr->OperandAt(i);
if (operand->IsDead()) worklist.Add(HInstruction::cast(operand), zone());
}
}
}
HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) {
ASSERT(current_block() != NULL);
current_block()->AddInstruction(instr);
......
......@@ -268,6 +268,7 @@ class HGraph: public ZoneObject {
void ReplaceCheckedValues();
void EliminateRedundantBoundsChecks();
void DehoistSimpleArrayIndexComputations();
void DeadCodeElimination();
void PropagateDeoptimizingMark();
// Returns false if there are phi-uses of the arguments-object
......
......@@ -96,7 +96,9 @@ class PropertyDetails BASE_EMBEDDED {
PropertyType type() { return TypeField::decode(value_); }
PropertyAttributes attributes() { return AttributesField::decode(value_); }
PropertyAttributes attributes() const {
return AttributesField::decode(value_);
}
int dictionary_index() {
return DictionaryStorageField::decode(value_);
......@@ -112,10 +114,10 @@ class PropertyDetails BASE_EMBEDDED {
return DictionaryStorageField::is_valid(index);
}
bool IsReadOnly() { return (attributes() & READ_ONLY) != 0; }
bool IsDontDelete() { return (attributes() & DONT_DELETE) != 0; }
bool IsDontEnum() { return (attributes() & DONT_ENUM) != 0; }
bool IsDeleted() { return DeletedField::decode(value_) != 0;}
bool IsReadOnly() const { return (attributes() & READ_ONLY) != 0; }
bool IsDontDelete() const { return (attributes() & DONT_DELETE) != 0; }
bool IsDontEnum() const { return (attributes() & DONT_ENUM) != 0; }
bool IsDeleted() const { return DeletedField::decode(value_) != 0;}
// Bit fields in value_ (type, shift, size). Must be public so the
// constants can be embedded in generated code.
......
......@@ -862,7 +862,11 @@ class EmbeddedContainer {
public:
EmbeddedContainer() : elems_() { }
int length() { return NumElements; }
int length() const { return NumElements; }
const ElementType& operator[](int i) const {
ASSERT(i < length());
return elems_[i];
}
ElementType& operator[](int i) {
ASSERT(i < length());
return elems_[i];
......@@ -876,7 +880,12 @@ class EmbeddedContainer {
template<typename ElementType>
class EmbeddedContainer<ElementType, 0> {
public:
int length() { return 0; }
int length() const { return 0; }
const ElementType& operator[](int i) const {
UNREACHABLE();
static ElementType t = 0;
return t;
}
ElementType& operator[](int i) {
UNREACHABLE();
static ElementType t = 0;
......
......@@ -56,9 +56,9 @@ VARIANT_FLAGS = [[],
["--stress-opt", "--always-opt"],
["--nocrankshaft"]]
MODE_FLAGS = {
"debug" : ["--nobreak-on-abort", "--enable-slow-asserts",
"--debug-code", "--verify-heap"],
"release" : ["--nobreak-on-abort"]}
"debug" : ["--nobreak-on-abort", "--nodead-code-elimination",
"--enable-slow-asserts", "--debug-code", "--verify-heap"],
"release" : ["--nobreak-on-abort", "--nodead-code-elimination"]}
def BuildOptions():
......
......@@ -684,8 +684,9 @@ SUFFIX = {
'debug' : '_g',
'release' : '' }
FLAGS = {
'debug' : ['--nobreak-on-abort', '--enable-slow-asserts', '--debug-code', '--verify-heap'],
'release' : ['--nobreak-on-abort']}
'debug' : ['--nobreak-on-abort', '--nodead-code-elimination',
'--enable-slow-asserts', '--debug-code', '--verify-heap'],
'release' : ['--nobreak-on-abort', '--nodead-code-elimination']}
TIMEOUT_SCALEFACTOR = {
'debug' : 4,
'release' : 1 }
......
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