Commit bbd62e4a authored by bmeurer@chromium.org's avatar bmeurer@chromium.org

[turbofan] Improve testability of the InstructionSelector.

Allow to pass the set of supported CPU features to
the InstructionSelector, so it can be tested without
messing with the command line flags.

Also add InstructionSelector sample for ia32.

TEST=cctest/test-instruction-selector,cctest/test-instruction-selector-{arm,ia32}
R=svenpanne@chromium.org

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22876 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 337015e5
......@@ -176,6 +176,11 @@ class CpuFeatures : public AllStatic {
ProbeImpl(cross_compile);
}
static unsigned SupportedFeatures() {
Probe(false);
return supported_;
}
static bool IsSupported(CpuFeature f) {
return (supported_ & (1u << f)) != 0;
}
......
......@@ -437,7 +437,7 @@ void InstructionSelector::VisitWord32And(Node* node) {
return;
}
}
if (CpuFeatures::IsSupported(ARMv7) && m.right().HasValue()) {
if (IsSupported(ARMv7) && m.right().HasValue()) {
uint32_t value = m.right().Value();
uint32_t width = CompilerIntrinsics::CountSetBits(value);
uint32_t msb = CompilerIntrinsics::CountLeadingZeros(value);
......@@ -525,7 +525,7 @@ void InstructionSelector::VisitWord32Shl(Node* node) {
void InstructionSelector::VisitWord32Shr(Node* node) {
ArmOperandGenerator g(this);
Int32BinopMatcher m(node);
if (CpuFeatures::IsSupported(ARMv7) && m.left().IsWord32And() &&
if (IsSupported(ARMv7) && m.left().IsWord32And() &&
m.right().IsInRange(0, 31)) {
int32_t lsb = m.right().Value();
Int32BinopMatcher mleft(m.left().node());
......@@ -573,7 +573,7 @@ void InstructionSelector::VisitInt32Add(Node* node) {
void InstructionSelector::VisitInt32Sub(Node* node) {
ArmOperandGenerator g(this);
Int32BinopMatcher m(node);
if (CpuFeatures::IsSupported(MLS) && m.right().IsInt32Mul() &&
if (IsSupported(MLS) && m.right().IsInt32Mul() &&
CanCover(node, m.right().node())) {
Int32BinopMatcher mright(m.right().node());
Emit(kArmMls, g.DefineAsRegister(node), g.UseRegister(mright.left().node()),
......@@ -615,7 +615,7 @@ static void EmitDiv(InstructionSelector* selector, ArchOpcode div_opcode,
InstructionOperand* left_operand,
InstructionOperand* right_operand) {
ArmOperandGenerator g(selector);
if (CpuFeatures::IsSupported(SUDIV)) {
if (selector->IsSupported(SUDIV)) {
selector->Emit(div_opcode, result_operand, left_operand, right_operand);
return;
}
......@@ -662,7 +662,7 @@ static void VisitMod(InstructionSelector* selector, Node* node,
InstructionOperand* right_operand = g.UseRegister(m.right().node());
EmitDiv(selector, div_opcode, f64i32_opcode, i32f64_opcode, div_operand,
left_operand, right_operand);
if (CpuFeatures::IsSupported(MLS)) {
if (selector->IsSupported(MLS)) {
selector->Emit(kArmMls, result_operand, div_operand, right_operand,
left_operand);
return;
......
......@@ -14,10 +14,12 @@ namespace internal {
namespace compiler {
InstructionSelector::InstructionSelector(InstructionSequence* sequence,
SourcePositionTable* source_positions)
SourcePositionTable* source_positions,
Features features)
: zone_(sequence->isolate()),
sequence_(sequence),
source_positions_(source_positions),
features_(features),
current_block_(NULL),
instructions_(InstructionDeque::allocator_type(zone())),
defined_(graph()->NodeCount(), false, BoolVector::allocator_type(zone())),
......
......@@ -22,8 +22,12 @@ class FlagsContinuation;
class InstructionSelector V8_FINAL {
public:
explicit InstructionSelector(InstructionSequence* sequence,
SourcePositionTable* source_positions);
// Forward declarations.
class Features;
InstructionSelector(InstructionSequence* sequence,
SourcePositionTable* source_positions,
Features features = SupportedFeatures());
// Visit code for the entire graph with the included schedule.
void SelectInstructions();
......@@ -54,6 +58,32 @@ class InstructionSelector V8_FINAL {
InstructionOperand* *temps = NULL);
Instruction* Emit(Instruction* instr);
// ===========================================================================
// ============== Architecture-independent CPU feature methods. ==============
// ===========================================================================
class Features V8_FINAL {
public:
Features() : bits_(0) {}
explicit Features(unsigned bits) : bits_(bits) {}
explicit Features(CpuFeature f) : bits_(1u << f) {}
Features(CpuFeature f1, CpuFeature f2) : bits_((1u << f1) | (1u << f2)) {}
bool Contains(CpuFeature f) const { return (bits_ & (1u << f)); }
private:
unsigned bits_;
};
bool IsSupported(CpuFeature feature) const {
return features_.Contains(feature);
}
// Returns the features supported on the target platform.
static Features SupportedFeatures() {
return Features(CpuFeatures::SupportedFeatures());
}
private:
friend class OperandGenerator;
......@@ -168,6 +198,7 @@ class InstructionSelector V8_FINAL {
Zone zone_;
InstructionSequence* sequence_;
SourcePositionTable* source_positions_;
Features features_;
BasicBlock* current_block_;
Instructions instructions_;
BoolVector defined_;
......
......@@ -171,6 +171,7 @@
'conditions': [
['v8_target_arch=="ia32"', {
'sources': [ ### gcmole(arch:ia32) ###
'compiler/test-instruction-selector-ia32.cc',
'test-assembler-ia32.cc',
'test-code-stubs.cc',
'test-code-stubs-ia32.cc',
......
......@@ -36,15 +36,27 @@ class InstructionSelectorTester : public HandleAndZoneScope,
return array;
}
explicit InstructionSelectorTester(Mode mode = kTargetMode)
InstructionSelectorTester()
: RawMachineAssembler(
new (main_zone()) Graph(main_zone()), new (main_zone())
MachineCallDescriptorBuilder(kMachineWord32, kParameterCount,
BuildParameterArray(main_zone())),
MachineOperatorBuilder::pointer_rep()),
mode_(mode) {}
MachineOperatorBuilder::pointer_rep()) {}
void SelectInstructions() {
void SelectInstructions(CpuFeature feature) {
SelectInstructions(InstructionSelector::Features(feature));
}
void SelectInstructions(CpuFeature feature1, CpuFeature feature2) {
SelectInstructions(InstructionSelector::Features(feature1, feature2));
}
void SelectInstructions(Mode mode = kTargetMode) {
SelectInstructions(InstructionSelector::Features(), mode);
}
void SelectInstructions(InstructionSelector::Features features,
Mode mode = kTargetMode) {
OFStream out(stdout);
Schedule* schedule = Export();
CHECK_NE(0, graph()->NodeCount());
......@@ -52,7 +64,7 @@ class InstructionSelectorTester : public HandleAndZoneScope,
Linkage linkage(&info, call_descriptor());
InstructionSequence sequence(&linkage, graph(), schedule);
SourcePositionTable source_positions(graph());
InstructionSelector selector(&sequence, &source_positions);
InstructionSelector selector(&sequence, &source_positions, features);
selector.SelectInstructions();
out << "--- Code sequence after instruction selection --- " << endl
<< sequence;
......@@ -60,7 +72,7 @@ class InstructionSelectorTester : public HandleAndZoneScope,
i != sequence.end(); ++i) {
Instruction* instr = *i;
if (instr->opcode() < 0) continue;
if (mode_ == kTargetMode) {
if (mode == kTargetMode) {
switch (ArchOpcodeField::decode(instr->opcode())) {
#define CASE(Name) \
case k##Name: \
......@@ -98,9 +110,6 @@ class InstructionSelectorTester : public HandleAndZoneScope,
VirtualRegisterSet doubles;
VirtualRegisterSet references;
std::deque<Constant> immediates;
private:
Mode mode_;
};
......
// Copyright 2014 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 "test/cctest/compiler/instruction-selector-tester.h"
#include "test/cctest/compiler/value-helper.h"
using namespace v8::internal;
using namespace v8::internal::compiler;
TEST(InstructionSelectorInt32AddP) {
InstructionSelectorTester m;
m.Return(m.Int32Add(m.Parameter(0), m.Parameter(1)));
m.SelectInstructions();
CHECK_EQ(1, m.code.size());
CHECK_EQ(kIA32Add, m.code[0]->arch_opcode());
}
TEST(InstructionSelectorInt32AddImm) {
FOR_INT32_INPUTS(i) {
int32_t imm = *i;
{
InstructionSelectorTester m;
m.Return(m.Int32Add(m.Parameter(0), m.Int32Constant(imm)));
m.SelectInstructions();
CHECK_EQ(1, m.code.size());
CHECK_EQ(kIA32Add, m.code[0]->arch_opcode());
CHECK_EQ(2, m.code[0]->InputCount());
CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1)));
}
{
InstructionSelectorTester m;
m.Return(m.Int32Add(m.Int32Constant(imm), m.Parameter(0)));
m.SelectInstructions();
CHECK_EQ(1, m.code.size());
CHECK_EQ(kIA32Add, m.code[0]->arch_opcode());
CHECK_EQ(2, m.code[0]->InputCount());
CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1)));
}
}
}
TEST(InstructionSelectorInt32SubP) {
InstructionSelectorTester m;
m.Return(m.Int32Sub(m.Parameter(0), m.Parameter(1)));
m.SelectInstructions();
CHECK_EQ(1, m.code.size());
CHECK_EQ(kIA32Sub, m.code[0]->arch_opcode());
CHECK_EQ(1, m.code[0]->OutputCount());
}
TEST(InstructionSelectorInt32SubImm) {
FOR_INT32_INPUTS(i) {
int32_t imm = *i;
InstructionSelectorTester m;
m.Return(m.Int32Sub(m.Parameter(0), m.Int32Constant(imm)));
m.SelectInstructions();
CHECK_EQ(1, m.code.size());
CHECK_EQ(kIA32Sub, m.code[0]->arch_opcode());
CHECK_EQ(2, m.code[0]->InputCount());
CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1)));
}
}
......@@ -7,16 +7,16 @@
using namespace v8::internal;
using namespace v8::internal::compiler;
#if V8_TURBOFAN_TARGET
#if V8_TURBOFAN_BACKEND
TEST(InstructionSelectionReturnZero) {
InstructionSelectorTester m(InstructionSelectorTester::kInternalMode);
InstructionSelectorTester m;
m.Return(m.Int32Constant(0));
m.SelectInstructions();
m.SelectInstructions(InstructionSelectorTester::kInternalMode);
CHECK_EQ(2, static_cast<int>(m.code.size()));
CHECK_EQ(kArchNop, m.code[0]->opcode());
CHECK_EQ(kArchRet, m.code[1]->opcode());
CHECK_EQ(1, static_cast<int>(m.code[1]->InputCount()));
}
#endif
#endif // !V8_TURBOFAN_BACKEND
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