Commit fc7c2c55 authored by Ross McIlroy's avatar Ross McIlroy Committed by Commit Bot

[Interpreter] Remove peephole optimizer.

All the optimizations have now been moved to either the BytecodeGenerator
or the BytecodeArrayWriter/Builder.

BUG=v8:6194

Change-Id: Ie5c5d55e824c94ffb503af376c72bc64ad1f6f81
Reviewed-on: https://chromium-review.googlesource.com/469349
Commit-Queue: Ross McIlroy <rmcilroy@chromium.org>
Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Reviewed-by: 's avatarMichael Achenbach <machenbach@chromium.org>
Cr-Commit-Position: refs/heads/master@{#44564}
parent 1f3a863b
......@@ -141,7 +141,6 @@ if (v8_enable_v8_checks == "") {
# snapshots.
is_target_simulator = target_cpu != v8_target_cpu
v8_generated_peephole_source = "$target_gen_dir/bytecode-peephole-table.cc"
v8_random_seed = "314159265"
v8_toolset_for_shell = "host"
......@@ -747,29 +746,6 @@ action("run_mksnapshot") {
}
}
action("run_mkpeephole") {
visibility = [ ":*" ] # Only targets in this file can depend on this.
deps = [
":mkpeephole($v8_snapshot_toolchain)",
]
outputs = [
v8_generated_peephole_source,
]
sources = []
script = "tools/run.py"
args = [
"./" + rebase_path(get_label_info(":mkpeephole($v8_snapshot_toolchain)",
"root_out_dir") + "/mkpeephole",
root_build_dir),
rebase_path(v8_generated_peephole_source, root_build_dir),
]
}
action("v8_dump_build_config") {
script = "tools/testrunner/utils/dump_build_config.py"
outputs = [
......@@ -1656,9 +1632,6 @@ v8_source_set("v8_base") {
"src/interpreter/bytecode-label.h",
"src/interpreter/bytecode-operands.cc",
"src/interpreter/bytecode-operands.h",
"src/interpreter/bytecode-peephole-optimizer.cc",
"src/interpreter/bytecode-peephole-optimizer.h",
"src/interpreter/bytecode-peephole-table.h",
"src/interpreter/bytecode-pipeline.cc",
"src/interpreter/bytecode-pipeline.h",
"src/interpreter/bytecode-register-allocator.h",
......@@ -2383,9 +2356,6 @@ v8_source_set("v8_base") {
"src/inspector:inspector",
]
sources += [ v8_generated_peephole_source ]
deps += [ ":run_mkpeephole" ]
if (v8_enable_i18n_support) {
deps += [ "//third_party/icu" ]
if (is_win) {
......@@ -2638,34 +2608,6 @@ if (current_toolchain == v8_snapshot_toolchain) {
}
}
v8_executable("mkpeephole") {
# mkpeephole needs to be built for the build host so the peephole lookup
# table can built during build. The table depends on the properties of
# bytecodes that are described in bytecodes.{cc,h}.
visibility = [ ":*" ] # Only targets in this file can depend on this.
sources = [
"src/interpreter/bytecode-operands.cc",
"src/interpreter/bytecode-operands.h",
"src/interpreter/bytecode-peephole-optimizer.h",
"src/interpreter/bytecode-traits.h",
"src/interpreter/bytecodes.cc",
"src/interpreter/bytecodes.h",
"src/interpreter/mkpeephole.cc",
]
configs = [
":external_config",
":internal_config",
]
deps = [
":v8_libbase",
"//build/config/sanitizers:deps",
"//build/win:default_exe_manifest",
]
}
###############################################################################
# Public targets
#
......
......@@ -253,18 +253,6 @@
}, {
'want_separate_host_toolset': 0,
}],
['(v8_target_arch=="arm" and host_arch!="arm") or \
(v8_target_arch=="arm64" and host_arch!="arm64") or \
(v8_target_arch=="mipsel" and host_arch!="mipsel") or \
(v8_target_arch=="mips64el" and host_arch!="mips64el") or \
(v8_target_arch=="mips" and host_arch!="mips") or \
(v8_target_arch=="mips64" and host_arch!="mips64") or \
(v8_target_arch=="x64" and host_arch!="x64") or \
(OS=="android" or OS=="qnx")', {
'want_separate_host_toolset_mkpeephole': 1,
}, {
'want_separate_host_toolset_mkpeephole': 0,
}],
['OS == "win"', {
'os_posix%': 0,
}, {
......
......@@ -74,7 +74,6 @@
# Chrome needs this definition unconditionally. For standalone V8 builds,
# it's handled in gypfiles/standalone.gypi.
'want_separate_host_toolset%': 1,
'want_separate_host_toolset_mkpeephole%': 1,
# Toolset the shell binary should be compiled for. Possible values are
# 'host' and 'target'.
......
......@@ -319,7 +319,6 @@ DEFINE_BOOL(ignition_deadcode, true,
DEFINE_BOOL(ignition_osr, true, "enable support for OSR from ignition code")
DEFINE_BOOL(ignition_elide_noneffectful_bytecodes, true,
"elide bytecodes which won't have any external effect")
DEFINE_BOOL(ignition_peephole, true, "use ignition peephole optimizer")
DEFINE_BOOL(ignition_reo, true, "use ignition register equivalence optimizer")
DEFINE_BOOL(ignition_filter_expression_positions, true,
"filter expression positions before the bytecode pipeline")
......
......@@ -8,7 +8,6 @@
#include "src/interpreter/bytecode-array-writer.h"
#include "src/interpreter/bytecode-dead-code-optimizer.h"
#include "src/interpreter/bytecode-label.h"
#include "src/interpreter/bytecode-peephole-optimizer.h"
#include "src/interpreter/bytecode-register-optimizer.h"
#include "src/interpreter/interpreter-intrinsics.h"
#include "src/objects-inl.h"
......@@ -62,10 +61,6 @@ BytecodeArrayBuilder::BytecodeArrayBuilder(
pipeline_ = new (zone) BytecodeDeadCodeOptimizer(pipeline_);
}
if (FLAG_ignition_peephole) {
pipeline_ = new (zone) BytecodePeepholeOptimizer(pipeline_);
}
if (FLAG_ignition_reo) {
register_optimizer_ = new (zone) BytecodeRegisterOptimizer(
zone, &register_allocator_, fixed_register_count(), parameter_count,
......
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/interpreter/bytecode-peephole-optimizer.h"
#include "src/objects-inl.h"
#include "src/objects.h"
namespace v8 {
namespace internal {
namespace interpreter {
BytecodePeepholeOptimizer::BytecodePeepholeOptimizer(
BytecodePipelineStage* next_stage)
: next_stage_(next_stage),
last_(BytecodeNode::Illegal(BytecodeSourceInfo())) {
InvalidateLast();
}
// override
Handle<BytecodeArray> BytecodePeepholeOptimizer::ToBytecodeArray(
Isolate* isolate, int register_count, int parameter_count,
Handle<FixedArray> handler_table) {
Flush();
return next_stage_->ToBytecodeArray(isolate, register_count, parameter_count,
handler_table);
}
// override
void BytecodePeepholeOptimizer::BindLabel(BytecodeLabel* label) {
Flush();
next_stage_->BindLabel(label);
}
// override
void BytecodePeepholeOptimizer::BindLabel(const BytecodeLabel& target,
BytecodeLabel* label) {
// There is no need to flush here, it will have been flushed when
// |target| was bound.
next_stage_->BindLabel(target, label);
}
// override
void BytecodePeepholeOptimizer::WriteJump(BytecodeNode* node,
BytecodeLabel* label) {
// Handlers for jump bytecodes do not emit |node| as WriteJump()
// requires the |label| and having a label argument in all action
// handlers results in dead work in the non-jump case.
ApplyPeepholeAction(node);
next_stage()->WriteJump(node, label);
}
// override
void BytecodePeepholeOptimizer::Write(BytecodeNode* node) {
// Handlers for non-jump bytecodes run to completion emitting
// bytecode to next stage as appropriate.
ApplyPeepholeAction(node);
}
void BytecodePeepholeOptimizer::Flush() {
if (LastIsValid()) {
next_stage_->Write(&last_);
InvalidateLast();
}
}
void BytecodePeepholeOptimizer::InvalidateLast() {
last_ = BytecodeNode::Illegal(BytecodeSourceInfo());
}
bool BytecodePeepholeOptimizer::LastIsValid() const {
return last_.bytecode() != Bytecode::kIllegal;
}
void BytecodePeepholeOptimizer::SetLast(const BytecodeNode* const node) {
// An action shouldn't leave a NOP as last bytecode unless it has
// source position information. NOP without source information can
// always be elided.
DCHECK(node->bytecode() != Bytecode::kNop || node->source_info().is_valid());
last_ = *node;
}
bool BytecodePeepholeOptimizer::CanElideLastBasedOnSourcePosition(
const BytecodeNode* const current) const {
//
// The rules for allowing the elision of the last bytecode based
// on source position are:
//
// C U R R E N T
// +--------+--------+--------+
// | None | Expr | Stmt |
// L +--------+--------+--------+--------+
// | None | YES | YES | YES |
// A +--------+--------+--------+--------+
// | Expr | YES | MAYBE | MAYBE |
// S +--------+--------+--------+--------+
// | Stmt | YES | NO | NO |
// T +--------+--------+--------+--------+
//
// The goal is not lose any statement positions and not lose useful
// expression positions. Whenever the last bytecode is elided it's
// source position information is applied to the current node
// updating it if necessary.
//
// The last bytecode could be elided for the MAYBE cases if the last
// bytecode is known not to throw. If it throws, the system would
// not have correct stack trace information. The appropriate check
// for this would be Bytecodes::IsWithoutExternalSideEffects(). By
// default, the upstream bytecode generator filters out unneeded
// expression position information so there is neglible benefit to
// handling MAYBE specially. Hence MAYBE is treated the same as NO.
//
return (!last_.source_info().is_valid() ||
!current->source_info().is_valid());
}
namespace {
} // namespace
void BytecodePeepholeOptimizer::DefaultAction(
BytecodeNode* const node, const PeepholeActionAndData* action_data) {
DCHECK(LastIsValid());
DCHECK(!Bytecodes::IsJump(node->bytecode()));
next_stage()->Write(last());
SetLast(node);
}
void BytecodePeepholeOptimizer::UpdateLastAction(
BytecodeNode* const node, const PeepholeActionAndData* action_data) {
DCHECK(!LastIsValid());
DCHECK(!Bytecodes::IsJump(node->bytecode()));
SetLast(node);
}
void BytecodePeepholeOptimizer::UpdateLastIfSourceInfoPresentAction(
BytecodeNode* const node, const PeepholeActionAndData* action_data) {
DCHECK(!LastIsValid());
DCHECK(!Bytecodes::IsJump(node->bytecode()));
if (node->source_info().is_valid()) {
SetLast(node);
}
}
void BytecodePeepholeOptimizer::ElideCurrentAction(
BytecodeNode* const node, const PeepholeActionAndData* action_data) {
DCHECK(LastIsValid());
DCHECK(!Bytecodes::IsJump(node->bytecode()));
if (node->source_info().is_valid()) {
// Preserve the source information by replacing the node bytecode
// with a no op bytecode.
BytecodeNode new_node(BytecodeNode::Nop(node->source_info()));
DefaultAction(&new_node);
} else {
// Nothing to do, keep last and wait for next bytecode to pair with it.
}
}
void BytecodePeepholeOptimizer::ElideCurrentIfOperand0MatchesAction(
BytecodeNode* const node, const PeepholeActionAndData* action_data) {
DCHECK(LastIsValid());
DCHECK(!Bytecodes::IsJump(node->bytecode()));
if (last()->operand(0) == node->operand(0)) {
ElideCurrentAction(node);
} else {
DefaultAction(node);
}
}
void BytecodePeepholeOptimizer::ElideLastAction(
BytecodeNode* const node, const PeepholeActionAndData* action_data) {
DCHECK(LastIsValid());
DCHECK(!Bytecodes::IsJump(node->bytecode()));
if (CanElideLastBasedOnSourcePosition(node)) {
if (last()->source_info().is_valid()) {
// |node| can not have a valid source position if the source
// position of last() is valid (per rules in
// CanElideLastBasedOnSourcePosition()).
node->set_source_info(last()->source_info());
}
SetLast(node);
} else {
DefaultAction(node);
}
}
void BytecodePeepholeOptimizer::ChangeBytecodeAction(
BytecodeNode* const node, const PeepholeActionAndData* action_data) {
DCHECK(LastIsValid());
DCHECK(!Bytecodes::IsJump(node->bytecode()));
node->replace_bytecode(action_data->bytecode);
DefaultAction(node);
}
void BytecodePeepholeOptimizer::DefaultJumpAction(
BytecodeNode* const node, const PeepholeActionAndData* action_data) {
DCHECK(LastIsValid());
DCHECK(Bytecodes::IsJump(node->bytecode()));
next_stage()->Write(last());
InvalidateLast();
}
void BytecodePeepholeOptimizer::UpdateLastJumpAction(
BytecodeNode* const node, const PeepholeActionAndData* action_data) {
DCHECK(!LastIsValid());
DCHECK(Bytecodes::IsJump(node->bytecode()));
}
void BytecodePeepholeOptimizer::ElideLastBeforeJumpAction(
BytecodeNode* const node, const PeepholeActionAndData* action_data) {
DCHECK(LastIsValid());
DCHECK(Bytecodes::IsJump(node->bytecode()));
if (!CanElideLastBasedOnSourcePosition(node)) {
next_stage()->Write(last());
} else if (!node->source_info().is_valid()) {
node->set_source_info(last()->source_info());
}
InvalidateLast();
}
void BytecodePeepholeOptimizer::ApplyPeepholeAction(BytecodeNode* const node) {
// A single table is used for looking up peephole optimization
// matches as it is observed to have better performance. This is
// inspite of the fact that jump bytecodes and non-jump bytecodes
// have different processing logic, in particular a jump bytecode
// always needs to emit the jump via WriteJump().
const PeepholeActionAndData* const action_data =
PeepholeActionTable::Lookup(last()->bytecode(), node->bytecode());
switch (action_data->action) {
#define CASE(Action) \
case PeepholeAction::k##Action: \
Action(node, action_data); \
break;
PEEPHOLE_ACTION_LIST(CASE)
#undef CASE
default:
UNREACHABLE();
break;
}
}
} // namespace interpreter
} // namespace internal
} // namespace v8
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_INTERPRETER_BYTECODE_PEEPHOLE_OPTIMIZER_H_
#define V8_INTERPRETER_BYTECODE_PEEPHOLE_OPTIMIZER_H_
#include "src/base/compiler-specific.h"
#include "src/globals.h"
#include "src/interpreter/bytecode-peephole-table.h"
#include "src/interpreter/bytecode-pipeline.h"
namespace v8 {
namespace internal {
namespace interpreter {
class BytecodePeepholeActionAndData;
// An optimization stage for performing peephole optimizations on
// generated bytecode. The optimizer may buffer one bytecode
// internally.
class V8_EXPORT_PRIVATE BytecodePeepholeOptimizer final
: public NON_EXPORTED_BASE(BytecodePipelineStage),
public NON_EXPORTED_BASE(ZoneObject) {
public:
explicit BytecodePeepholeOptimizer(BytecodePipelineStage* next_stage);
// BytecodePipelineStage interface.
void Write(BytecodeNode* node) override;
void WriteJump(BytecodeNode* node, BytecodeLabel* label) override;
void BindLabel(BytecodeLabel* label) override;
void BindLabel(const BytecodeLabel& target, BytecodeLabel* label) override;
Handle<BytecodeArray> ToBytecodeArray(
Isolate* isolate, int register_count, int parameter_count,
Handle<FixedArray> handler_table) override;
private:
#define DECLARE_ACTION(Action) \
void Action(BytecodeNode* const node, \
const PeepholeActionAndData* const action_data = nullptr);
PEEPHOLE_ACTION_LIST(DECLARE_ACTION)
#undef DECLARE_ACTION
void ApplyPeepholeAction(BytecodeNode* const node);
void Flush();
bool CanElideLastBasedOnSourcePosition(
const BytecodeNode* const current) const;
void InvalidateLast();
bool LastIsValid() const;
void SetLast(const BytecodeNode* const node);
BytecodePipelineStage* next_stage() const { return next_stage_; }
BytecodeNode* last() { return &last_; }
BytecodePipelineStage* next_stage_;
BytecodeNode last_;
DISALLOW_COPY_AND_ASSIGN(BytecodePeepholeOptimizer);
};
} // namespace interpreter
} // namespace internal
} // namespace v8
#endif // V8_INTERPRETER_BYTECODE_PEEPHOLE_OPTIMIZER_H_
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_INTERPRETER_BYTECODE_PEEPHOLE_TABLE_H_
#define V8_INTERPRETER_BYTECODE_PEEPHOLE_TABLE_H_
#include "src/interpreter/bytecodes.h"
namespace v8 {
namespace internal {
namespace interpreter {
#define PEEPHOLE_NON_JUMP_ACTION_LIST(V) \
V(DefaultAction) \
V(UpdateLastAction) \
V(UpdateLastIfSourceInfoPresentAction) \
V(ElideCurrentAction) \
V(ElideCurrentIfOperand0MatchesAction) \
V(ElideLastAction) \
V(ChangeBytecodeAction)
#define PEEPHOLE_JUMP_ACTION_LIST(V) \
V(DefaultJumpAction) \
V(UpdateLastJumpAction) \
V(ElideLastBeforeJumpAction)
#define PEEPHOLE_ACTION_LIST(V) \
PEEPHOLE_NON_JUMP_ACTION_LIST(V) \
PEEPHOLE_JUMP_ACTION_LIST(V)
// Actions to take when a pair of bytes is encountered. A handler
// exists for each action.
enum class PeepholeAction : uint8_t {
#define DECLARE_PEEPHOLE_ACTION(Action) k##Action,
PEEPHOLE_ACTION_LIST(DECLARE_PEEPHOLE_ACTION)
#undef DECLARE_PEEPHOLE_ACTION
};
// Tuple of action to take when pair of bytecodes is encountered and
// optional data to invoke handler with.
struct PeepholeActionAndData final {
// Action to take when tuple of bytecodes encountered.
PeepholeAction action;
// Replacement bytecode (if valid).
Bytecode bytecode;
};
// Lookup table for matching pairs of bytecodes to peephole optimization
// actions. The contents of the table are generated by mkpeephole.cc.
struct PeepholeActionTable final {
public:
static const PeepholeActionAndData* Lookup(Bytecode last, Bytecode current);
private:
static const size_t kNumberOfBytecodes =
static_cast<size_t>(Bytecode::kLast) + 1;
static const PeepholeActionAndData row_data_[][kNumberOfBytecodes];
static const PeepholeActionAndData* const row_[kNumberOfBytecodes];
};
} // namespace interpreter
} // namespace internal
} // namespace v8
#endif // V8_INTERPRETER_BYTECODE_PEEPHOLE_TABLE_H_
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <array>
#include <fstream>
#include <map>
#include <string>
#include <vector>
#include "src/globals.h"
#include "src/interpreter/bytecode-peephole-table.h"
#include "src/interpreter/bytecodes.h"
namespace v8 {
namespace internal {
namespace interpreter {
const char* ActionName(PeepholeAction action) {
switch (action) {
#define CASE(Name) \
case PeepholeAction::k##Name: \
return "PeepholeAction::k" #Name;
PEEPHOLE_ACTION_LIST(CASE)
#undef CASE
default:
UNREACHABLE();
return "";
}
}
std::string BytecodeName(Bytecode bytecode) {
return "Bytecode::k" + std::string(Bytecodes::ToString(bytecode));
}
class PeepholeActionTableWriter final {
public:
static const size_t kNumberOfBytecodes =
static_cast<size_t>(Bytecode::kLast) + 1;
typedef std::array<PeepholeActionAndData, kNumberOfBytecodes> Row;
void BuildTable();
void Write(std::ostream& os);
private:
static const char* kIndent;
static const char* kNamespaceElements[];
void WriteHeader(std::ostream& os);
void WriteIncludeFiles(std::ostream& os);
void WriteClassMethods(std::ostream& os);
void WriteUniqueRows(std::ostream& os);
void WriteRowMap(std::ostream& os);
void WriteRow(std::ostream& os, size_t row_index);
void WriteOpenNamespace(std::ostream& os);
void WriteCloseNamespace(std::ostream& os);
PeepholeActionAndData LookupActionAndData(Bytecode last, Bytecode current);
void BuildRow(Bytecode last, Row* row);
size_t HashRow(const Row* row);
void InsertRow(size_t row_index, const Row* const row, size_t row_hash,
std::map<size_t, size_t>* hash_to_row_map);
bool RowsEqual(const Row* const first, const Row* const second);
std::vector<Row>* table() { return &table_; }
// Table of unique rows.
std::vector<Row> table_;
// Mapping of row index to unique row index.
std::array<size_t, kNumberOfBytecodes> row_map_;
};
const char* PeepholeActionTableWriter::kIndent = " ";
const char* PeepholeActionTableWriter::kNamespaceElements[] = {"v8", "internal",
"interpreter"};
// static
PeepholeActionAndData PeepholeActionTableWriter::LookupActionAndData(
Bytecode last, Bytecode current) {
// If there is no last bytecode to optimize against, store the incoming
// bytecode or for jumps emit incoming bytecode immediately.
if (last == Bytecode::kIllegal) {
if (Bytecodes::IsJump(current)) {
return {PeepholeAction::kUpdateLastJumpAction, Bytecode::kIllegal};
} else if (current == Bytecode::kNop) {
return {PeepholeAction::kUpdateLastIfSourceInfoPresentAction,
Bytecode::kIllegal};
} else {
return {PeepholeAction::kUpdateLastAction, Bytecode::kIllegal};
}
}
// No matches, take the default action.
if (Bytecodes::IsJump(current)) {
return {PeepholeAction::kDefaultJumpAction, Bytecode::kIllegal};
} else {
return {PeepholeAction::kDefaultAction, Bytecode::kIllegal};
}
}
void PeepholeActionTableWriter::Write(std::ostream& os) {
WriteHeader(os);
WriteIncludeFiles(os);
WriteOpenNamespace(os);
WriteUniqueRows(os);
WriteRowMap(os);
WriteClassMethods(os);
WriteCloseNamespace(os);
}
void PeepholeActionTableWriter::WriteHeader(std::ostream& os) {
os << "// Copyright 2016 the V8 project authors. All rights reserved.\n"
<< "// Use of this source code is governed by a BSD-style license that\n"
<< "// can be found in the LICENSE file.\n\n"
<< "// Autogenerated by " __FILE__ ". Do not edit.\n\n";
}
void PeepholeActionTableWriter::WriteIncludeFiles(std::ostream& os) {
os << "#include \"src/interpreter/bytecode-peephole-table.h\"\n\n";
}
void PeepholeActionTableWriter::WriteUniqueRows(std::ostream& os) {
os << "const PeepholeActionAndData PeepholeActionTable::row_data_["
<< table_.size() << "][" << kNumberOfBytecodes << "] = {\n";
for (size_t i = 0; i < table_.size(); ++i) {
os << "{\n";
WriteRow(os, i);
os << "},\n";
}
os << "};\n\n";
}
void PeepholeActionTableWriter::WriteRowMap(std::ostream& os) {
os << "const PeepholeActionAndData* const PeepholeActionTable::row_["
<< kNumberOfBytecodes << "] = {\n";
for (size_t i = 0; i < kNumberOfBytecodes; ++i) {
os << kIndent << " PeepholeActionTable::row_data_[" << row_map_[i]
<< "], \n";
}
os << "};\n\n";
}
void PeepholeActionTableWriter::WriteRow(std::ostream& os, size_t row_index) {
const Row row = table_.at(row_index);
for (PeepholeActionAndData action_data : row) {
os << kIndent << "{" << ActionName(action_data.action) << ","
<< BytecodeName(action_data.bytecode) << "},\n";
}
}
void PeepholeActionTableWriter::WriteOpenNamespace(std::ostream& os) {
for (auto element : kNamespaceElements) {
os << "namespace " << element << " {\n";
}
os << "\n";
}
void PeepholeActionTableWriter::WriteCloseNamespace(std::ostream& os) {
for (auto element : kNamespaceElements) {
os << "} // namespace " << element << "\n";
}
}
void PeepholeActionTableWriter::WriteClassMethods(std::ostream& os) {
os << "// static\n"
<< "const PeepholeActionAndData*\n"
<< "PeepholeActionTable::Lookup(Bytecode last, Bytecode current) {\n"
<< kIndent
<< "return &row_[Bytecodes::ToByte(last)][Bytecodes::ToByte(current)];\n"
<< "}\n\n";
}
void PeepholeActionTableWriter::BuildTable() {
std::map<size_t, size_t> hash_to_row_map;
Row row;
for (size_t i = 0; i < kNumberOfBytecodes; ++i) {
uint8_t byte_value = static_cast<uint8_t>(i);
Bytecode last = Bytecodes::FromByte(byte_value);
BuildRow(last, &row);
size_t row_hash = HashRow(&row);
InsertRow(i, &row, row_hash, &hash_to_row_map);
}
}
void PeepholeActionTableWriter::BuildRow(Bytecode last, Row* row) {
for (size_t i = 0; i < kNumberOfBytecodes; ++i) {
uint8_t byte_value = static_cast<uint8_t>(i);
Bytecode current = Bytecodes::FromByte(byte_value);
PeepholeActionAndData action_data = LookupActionAndData(last, current);
row->at(i) = action_data;
}
}
// static
bool PeepholeActionTableWriter::RowsEqual(const Row* const first,
const Row* const second) {
return memcmp(first, second, sizeof(*first)) == 0;
}
// static
void PeepholeActionTableWriter::InsertRow(
size_t row_index, const Row* const row, size_t row_hash,
std::map<size_t, size_t>* hash_to_row_map) {
// Insert row if no existing row matches, otherwise use existing row.
auto iter = hash_to_row_map->find(row_hash);
if (iter == hash_to_row_map->end()) {
row_map_[row_index] = table()->size();
table()->push_back(*row);
} else {
row_map_[row_index] = iter->second;
// If the following DCHECK fails, the HashRow() is not adequate.
DCHECK(RowsEqual(&table()->at(iter->second), row));
}
}
// static
size_t PeepholeActionTableWriter::HashRow(const Row* row) {
static const size_t kHashShift = 3;
std::size_t result = (1u << 31) - 1u;
const uint8_t* raw_data = reinterpret_cast<const uint8_t*>(row);
for (size_t i = 0; i < sizeof(*row); ++i) {
size_t top_bits = result >> (kBitsPerByte * sizeof(size_t) - kHashShift);
result = (result << kHashShift) ^ top_bits ^ raw_data[i];
}
return result;
}
} // namespace interpreter
} // namespace internal
} // namespace v8
int main(int argc, const char* argv[]) {
CHECK_EQ(argc, 2);
std::ofstream ofs(argv[1], std::ofstream::trunc);
v8::internal::interpreter::PeepholeActionTableWriter writer;
writer.BuildTable();
writer.Write(ofs);
ofs.flush();
ofs.close();
return 0;
}
......@@ -35,7 +35,6 @@
'v8_extra_library_files%': [],
'v8_experimental_extra_library_files%': [],
'mksnapshot_exec': '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)mksnapshot<(EXECUTABLE_SUFFIX)',
'mkpeephole_exec': '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)mkpeephole<(EXECUTABLE_SUFFIX)',
'v8_os_page_size%': 0,
},
'includes': ['../gypfiles/toolchain.gypi', '../gypfiles/features.gypi', 'inspector/inspector.gypi'],
......@@ -383,13 +382,6 @@
'<(DEPTH)',
'<(SHARED_INTERMEDIATE_DIR)'
],
'actions':[{
'action_name': 'run mkpeephole',
'inputs': ['<(mkpeephole_exec)'],
'outputs': ['<(INTERMEDIATE_DIR)/bytecode-peephole-table.cc'],
'action': ['<(mkpeephole_exec)', '<(INTERMEDIATE_DIR)/bytecode-peephole-table.cc' ],
'process_outputs_as_sources': 1,
}],
'sources': [ ### gcmole(all) ###
'<@(inspector_all_sources)',
'../include/v8-debug.h',
......@@ -1050,9 +1042,6 @@
'interpreter/bytecode-label.h',
'interpreter/bytecode-operands.cc',
'interpreter/bytecode-operands.h',
'interpreter/bytecode-peephole-optimizer.cc',
'interpreter/bytecode-peephole-optimizer.h',
'interpreter/bytecode-peephole-table.h',
'interpreter/bytecode-pipeline.cc',
'interpreter/bytecode-pipeline.h',
'interpreter/bytecode-register.cc',
......@@ -1404,11 +1393,6 @@
}, {
'toolsets': ['target'],
}],
['want_separate_host_toolset_mkpeephole==1', {
'dependencies': ['mkpeephole#host'],
}, {
'dependencies': ['mkpeephole'],
}],
['v8_target_arch=="arm"', {
'sources': [ ### gcmole(arch:arm) ###
'arm/assembler-arm-inl.h',
......@@ -1930,8 +1914,7 @@
}],
],
'conditions': [
['want_separate_host_toolset==1 or \
want_separate_host_toolset_mkpeephole==1', {
['want_separate_host_toolset==1', {
'toolsets': ['host', 'target'],
}, {
'toolsets': ['target'],
......@@ -2500,29 +2483,5 @@
}],
],
},
{
'target_name': 'mkpeephole',
'type': 'executable',
'dependencies': [ 'v8_libbase' ],
'include_dirs+': [
'..',
],
'sources': [
'interpreter/bytecode-operands.h',
'interpreter/bytecode-operands.cc',
'interpreter/bytecode-peephole-table.h',
'interpreter/bytecode-traits.h',
'interpreter/bytecodes.h',
'interpreter/bytecodes.cc',
'interpreter/mkpeephole.cc'
],
'conditions': [
['want_separate_host_toolset_mkpeephole==1', {
'toolsets': ['host'],
}, {
'toolsets': ['target'],
}],
],
},
],
}
......@@ -21,7 +21,6 @@ namespace interpreter {
// Format is <command-line flag> <flag name> <bit index>
#define OPTIMIZATION_FLAGS(V) \
V(FLAG_ignition_reo, kUseReo, 0) \
V(FLAG_ignition_peephole, kUsePeephole, 1) \
V(FLAG_ignition_filter_expression_positions, kUseFilterExpressionPositions, \
2) \
V(FLAG_ignition_deadcode, kUseDeadCode, 3)
......@@ -35,20 +34,13 @@ OPTIMIZATION_FLAGS(DECLARE_BIT)
// because it provides easier to comprehend failure case for humans.
#define TEST_CASES(V) \
V(UsingReo, kUseReo) \
V(UsingPeephole, kUsePeephole) \
V(UsingDeadCode, kUseDeadCode) \
V(UsingFilterExpressionPositions, kUseFilterExpressionPositions) \
V(UsingReoAndPeephole, kUseReo | kUsePeephole) \
V(UsingReoAndFilterExpressionPositions, \
kUseReo | kUseFilterExpressionPositions) \
V(UsingReoAndDeadCode, kUseReo | kUseDeadCode) \
V(UsingPeepholeAndFilterExpressionPositions, \
kUsePeephole | kUseFilterExpressionPositions) \
V(UsingPeepholeAndDeadCode, kUsePeephole | kUseDeadCode) \
V(UsingFilterExpressionPositionsAndDeadCode, \
kUseFilterExpressionPositions | kUseDeadCode) \
V(UsingAllOptimizations, \
kUseReo | kUsePeephole | kUseFilterExpressionPositions | kUseDeadCode)
kUseReo | kUseFilterExpressionPositions | kUseDeadCode)
struct TestCaseData {
TestCaseData(const char* const script,
......
......@@ -118,7 +118,6 @@ v8_executable("unittests") {
"interpreter/bytecode-dead-code-optimizer-unittest.cc",
"interpreter/bytecode-decoder-unittest.cc",
"interpreter/bytecode-operands-unittest.cc",
"interpreter/bytecode-peephole-optimizer-unittest.cc",
"interpreter/bytecode-pipeline-unittest.cc",
"interpreter/bytecode-register-allocator-unittest.cc",
"interpreter/bytecode-register-optimizer-unittest.cc",
......
......@@ -28,7 +28,6 @@ class BytecodeAnalysisTest : public TestWithIsolateAndZone {
CHECK_NULL(save_flags_);
save_flags_ = new SaveFlags();
i::FLAG_ignition_elide_noneffectful_bytecodes = false;
i::FLAG_ignition_peephole = false;
i::FLAG_ignition_reo = false;
TestWithIsolateAndZone::SetUpTestCase();
......
......@@ -220,16 +220,6 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.CompareUndefined()
.CompareNull();
// Emit peephole optimizations of equality with Null or Undefined.
builder.LoadUndefined()
.CompareOperation(Token::Value::EQ, reg, 1)
.LoadNull()
.CompareOperation(Token::Value::EQ, reg, 1)
.LoadUndefined()
.CompareOperation(Token::Value::EQ_STRICT, reg, 1)
.LoadNull()
.CompareOperation(Token::Value::EQ_STRICT, reg, 1);
// Emit conversion operator invocations.
builder.ConvertAccumulatorToNumber(reg, 1)
.ConvertAccumulatorToObject(reg)
......@@ -418,10 +408,6 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
// Insert entry for nop bytecode as this often gets optimized out.
scorecard[Bytecodes::ToByte(Bytecode::kNop)] = 1;
if (!FLAG_ignition_peephole) {
// Insert entries for bytecodes only emitted by peephole optimizer.
}
if (!FLAG_type_profile) {
// Bytecode for CollectTypeProfile is only emitted when
// Type Information for DevTools is turned on.
......@@ -522,12 +508,6 @@ TEST_F(BytecodeArrayBuilderTest, Constants) {
CHECK_EQ(array->constant_pool()->length(), 3);
}
static Bytecode PeepholeToBoolean(Bytecode jump_bytecode) {
return FLAG_ignition_peephole
? Bytecodes::GetJumpWithoutToBoolean(jump_bytecode)
: jump_bytecode;
}
TEST_F(BytecodeArrayBuilderTest, ForwardJumps) {
CanonicalHandleScope canonical(isolate());
static const int kFarJumpDistance = 256 + 20;
......@@ -581,16 +561,14 @@ TEST_F(BytecodeArrayBuilderTest, ForwardJumps) {
// Ignore compare operation.
iterator.Advance();
CHECK_EQ(iterator.current_bytecode(),
PeepholeToBoolean(Bytecode::kJumpIfToBooleanTrue));
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrue);
CHECK_EQ(iterator.GetUnsignedImmediateOperand(0), 17);
iterator.Advance();
// Ignore compare operation.
iterator.Advance();
CHECK_EQ(iterator.current_bytecode(),
PeepholeToBoolean(Bytecode::kJumpIfToBooleanFalse));
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalse);
CHECK_EQ(iterator.GetUnsignedImmediateOperand(0), 12);
iterator.Advance();
......@@ -616,8 +594,7 @@ TEST_F(BytecodeArrayBuilderTest, ForwardJumps) {
// Ignore compare operation.
iterator.Advance();
CHECK_EQ(iterator.current_bytecode(),
PeepholeToBoolean(Bytecode::kJumpIfToBooleanTrueConstant));
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrueConstant);
CHECK_EQ(*iterator.GetConstantForIndexOperand(0),
Smi::FromInt(kFarJumpDistance - 5));
iterator.Advance();
......@@ -625,8 +602,7 @@ TEST_F(BytecodeArrayBuilderTest, ForwardJumps) {
// Ignore compare operation.
iterator.Advance();
CHECK_EQ(iterator.current_bytecode(),
PeepholeToBoolean(Bytecode::kJumpIfToBooleanFalseConstant));
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalseConstant);
CHECK_EQ(*iterator.GetConstantForIndexOperand(0),
Smi::FromInt(kFarJumpDistance - 10));
iterator.Advance();
......
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/v8.h"
#include "src/factory.h"
#include "src/interpreter/bytecode-label.h"
#include "src/interpreter/bytecode-peephole-optimizer.h"
#include "src/objects-inl.h"
#include "src/objects.h"
#include "test/unittests/test-utils.h"
namespace v8 {
namespace internal {
namespace interpreter {
class BytecodePeepholeOptimizerTest : public BytecodePipelineStage,
public TestWithIsolateAndZone {
public:
BytecodePeepholeOptimizerTest()
: peephole_optimizer_(this),
last_written_(BytecodeNode::Illegal(BytecodeSourceInfo())) {}
~BytecodePeepholeOptimizerTest() override {}
void Reset() {
last_written_ = BytecodeNode::Illegal(BytecodeSourceInfo());
write_count_ = 0;
}
void Write(BytecodeNode* node) override {
write_count_++;
last_written_ = *node;
}
void WriteJump(BytecodeNode* node, BytecodeLabel* label) override {
write_count_++;
last_written_ = *node;
}
void BindLabel(BytecodeLabel* label) override {}
void BindLabel(const BytecodeLabel& target, BytecodeLabel* label) override {}
Handle<BytecodeArray> ToBytecodeArray(
Isolate* isolate, int fixed_register_count, int parameter_count,
Handle<FixedArray> handle_table) override {
return Handle<BytecodeArray>();
}
void Flush() {
optimizer()->ToBytecodeArray(isolate(), 0, 0,
factory()->empty_fixed_array());
}
BytecodePeepholeOptimizer* optimizer() { return &peephole_optimizer_; }
int write_count() const { return write_count_; }
const BytecodeNode& last_written() const { return last_written_; }
private:
BytecodePeepholeOptimizer peephole_optimizer_;
int write_count_ = 0;
BytecodeNode last_written_;
};
// Sanity tests.
TEST_F(BytecodePeepholeOptimizerTest, FlushOnJump) {
CHECK_EQ(write_count(), 0);
BytecodeNode add(Bytecode::kAdd, Register(0).ToOperand(), 1);
optimizer()->Write(&add);
CHECK_EQ(write_count(), 0);
BytecodeLabel target;
BytecodeNode jump(Bytecode::kJump, 0);
optimizer()->WriteJump(&jump, &target);
CHECK_EQ(write_count(), 2);
CHECK_EQ(jump, last_written());
}
TEST_F(BytecodePeepholeOptimizerTest, FlushOnBind) {
CHECK_EQ(write_count(), 0);
BytecodeNode add(Bytecode::kAdd, Register(0).ToOperand(), 1);
optimizer()->Write(&add);
CHECK_EQ(write_count(), 0);
BytecodeLabel target;
optimizer()->BindLabel(&target);
CHECK_EQ(write_count(), 1);
CHECK_EQ(add, last_written());
}
// Tests covering BytecodePeepholeOptimizer::UpdateLastAndCurrentBytecodes().
} // namespace interpreter
} // namespace internal
} // namespace v8
......@@ -106,7 +106,6 @@
'interpreter/bytecode-dead-code-optimizer-unittest.cc',
'interpreter/bytecode-decoder-unittest.cc',
'interpreter/bytecode-operands-unittest.cc',
'interpreter/bytecode-peephole-optimizer-unittest.cc',
'interpreter/bytecode-pipeline-unittest.cc',
'interpreter/bytecode-register-allocator-unittest.cc',
'interpreter/bytecode-register-optimizer-unittest.cc',
......
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