v8/test/cctest/compiler/test-code-generator.cc
Michael Starzinger 3bccb99557 Remove compiler distinction from RegisterConfiguration.
This removes the obsolete {Crankshaft} factory method as it returns the
same configuration as the {Turbofan} factory by now. We now consistently
use {RegisterConfiguration::Default} everywhere.

R=jkummerow@chromium.org
BUG=v8:6408

Change-Id: I6be25774aa6714ef4dc1ef6856bb6dbc95593a29
Reviewed-on: https://chromium-review.googlesource.com/597858
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47109}
2017-08-03 07:47:36 +00:00

200 lines
7.8 KiB
C++

// Copyright 2017 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/codegen.h"
#include "src/compilation-info.h"
#include "src/compiler/code-generator.h"
#include "src/compiler/instruction.h"
#include "src/compiler/linkage.h"
#include "src/isolate.h"
#include "test/cctest/cctest.h"
namespace v8 {
namespace internal {
namespace compiler {
class CodeGeneratorTester : public InitializedHandleScope {
public:
CodeGeneratorTester()
: zone_(main_isolate()->allocator(), ZONE_NAME),
info_(ArrayVector("test"), main_isolate(), &zone_,
Code::ComputeFlags(Code::STUB)),
descriptor_(Linkage::GetJSCallDescriptor(&zone_, false, 0,
CallDescriptor::kNoFlags)),
linkage_(descriptor_),
blocks_(&zone_),
sequence_(main_isolate(), &zone_, &blocks_),
frame_(descriptor_->CalculateFixedFrameSize()),
generator_(&zone_, &frame_, &linkage_, &sequence_, &info_,
base::Optional<OsrHelper>(), kNoSourcePosition) {
info_.set_prologue_offset(generator_.tasm()->pc_offset());
}
enum PushTypeFlag {
kRegisterPush = CodeGenerator::kRegisterPush,
kStackSlotPush = CodeGenerator::kStackSlotPush,
kScalarPush = CodeGenerator::kScalarPush
};
void CheckAssembleTailCallGaps(Instruction* instr,
int first_unused_stack_slot,
CodeGeneratorTester::PushTypeFlag push_type) {
generator_.AssembleTailCallBeforeGap(instr, first_unused_stack_slot);
#if defined(V8_TARGET_ARCH_ARM) || defined(V8_TARGET_ARCH_S390) || \
defined(V8_TARGET_ARCH_PPC)
// Only folding register pushes is supported on ARM.
bool supported = ((push_type & CodeGenerator::kRegisterPush) == push_type);
#elif defined(V8_TARGET_ARCH_X64) || defined(V8_TARGET_ARCH_IA32) || \
defined(V8_TARGET_ARCH_X87)
bool supported = ((push_type & CodeGenerator::kScalarPush) == push_type);
#else
bool supported = false;
#endif
if (supported) {
// Architectures supporting folding adjacent pushes should now have
// resolved all moves.
for (const auto& move :
*instr->parallel_moves()[Instruction::FIRST_GAP_POSITION]) {
CHECK(move->IsEliminated());
}
}
generator_.AssembleGaps(instr);
generator_.AssembleTailCallAfterGap(instr, first_unused_stack_slot);
}
Handle<Code> Finalize() {
generator_.FinishCode();
generator_.safepoints()->Emit(generator_.tasm(),
frame_.GetTotalFrameSlotCount());
return generator_.FinalizeCode();
}
void Disassemble() {
HandleScope scope(main_isolate());
Handle<Code> code = Finalize();
if (FLAG_print_code) {
code->Print();
}
}
Zone* zone() { return &zone_; }
private:
Zone zone_;
CompilationInfo info_;
CallDescriptor* descriptor_;
Linkage linkage_;
ZoneVector<InstructionBlock*> blocks_;
InstructionSequence sequence_;
Frame frame_;
CodeGenerator generator_;
};
TEST(AssembleTailCallGap) {
const RegisterConfiguration* conf = RegisterConfiguration::Default();
// This test assumes at least 4 registers are allocatable.
CHECK(conf->num_allocatable_general_registers() >= 4);
auto r0 = AllocatedOperand(LocationOperand::REGISTER,
MachineRepresentation::kTagged,
conf->GetAllocatableGeneralCode(0));
auto r1 = AllocatedOperand(LocationOperand::REGISTER,
MachineRepresentation::kTagged,
conf->GetAllocatableGeneralCode(1));
auto r2 = AllocatedOperand(LocationOperand::REGISTER,
MachineRepresentation::kTagged,
conf->GetAllocatableGeneralCode(2));
auto r3 = AllocatedOperand(LocationOperand::REGISTER,
MachineRepresentation::kTagged,
conf->GetAllocatableGeneralCode(3));
auto slot_minus_4 = AllocatedOperand(LocationOperand::STACK_SLOT,
MachineRepresentation::kTagged, -4);
auto slot_minus_3 = AllocatedOperand(LocationOperand::STACK_SLOT,
MachineRepresentation::kTagged, -3);
auto slot_minus_2 = AllocatedOperand(LocationOperand::STACK_SLOT,
MachineRepresentation::kTagged, -2);
auto slot_minus_1 = AllocatedOperand(LocationOperand::STACK_SLOT,
MachineRepresentation::kTagged, -1);
// Avoid slot 0 for architectures which use it store the return address.
int first_slot = V8_TARGET_ARCH_STORES_RETURN_ADDRESS_ON_STACK ? 1 : 0;
auto slot_0 = AllocatedOperand(LocationOperand::STACK_SLOT,
MachineRepresentation::kTagged, first_slot);
auto slot_1 =
AllocatedOperand(LocationOperand::STACK_SLOT,
MachineRepresentation::kTagged, first_slot + 1);
auto slot_2 =
AllocatedOperand(LocationOperand::STACK_SLOT,
MachineRepresentation::kTagged, first_slot + 2);
auto slot_3 =
AllocatedOperand(LocationOperand::STACK_SLOT,
MachineRepresentation::kTagged, first_slot + 3);
// These tests all generate series of moves that the code generator should
// detect as adjacent pushes. Depending on the architecture, we make sure
// these moves get eliminated.
// Also, disassembling with `--print-code` is useful when debugging.
{
// Generate a series of register pushes only.
CodeGeneratorTester c;
Instruction* instr = Instruction::New(c.zone(), kArchNop);
instr->GetOrCreateParallelMove(Instruction::FIRST_GAP_POSITION, c.zone())
->AddMove(r3, slot_0);
instr->GetOrCreateParallelMove(Instruction::FIRST_GAP_POSITION, c.zone())
->AddMove(r2, slot_1);
instr->GetOrCreateParallelMove(Instruction::FIRST_GAP_POSITION, c.zone())
->AddMove(r1, slot_2);
instr->GetOrCreateParallelMove(Instruction::FIRST_GAP_POSITION, c.zone())
->AddMove(r0, slot_3);
c.CheckAssembleTailCallGaps(instr, first_slot + 4,
CodeGeneratorTester::kRegisterPush);
c.Disassemble();
}
{
// Generate a series of stack pushes only.
CodeGeneratorTester c;
Instruction* instr = Instruction::New(c.zone(), kArchNop);
instr->GetOrCreateParallelMove(Instruction::FIRST_GAP_POSITION, c.zone())
->AddMove(slot_minus_4, slot_0);
instr->GetOrCreateParallelMove(Instruction::FIRST_GAP_POSITION, c.zone())
->AddMove(slot_minus_3, slot_1);
instr->GetOrCreateParallelMove(Instruction::FIRST_GAP_POSITION, c.zone())
->AddMove(slot_minus_2, slot_2);
instr->GetOrCreateParallelMove(Instruction::FIRST_GAP_POSITION, c.zone())
->AddMove(slot_minus_1, slot_3);
c.CheckAssembleTailCallGaps(instr, first_slot + 4,
CodeGeneratorTester::kStackSlotPush);
c.Disassemble();
}
{
// Generate a mix of stack and register pushes.
CodeGeneratorTester c;
Instruction* instr = Instruction::New(c.zone(), kArchNop);
instr->GetOrCreateParallelMove(Instruction::FIRST_GAP_POSITION, c.zone())
->AddMove(slot_minus_2, slot_0);
instr->GetOrCreateParallelMove(Instruction::FIRST_GAP_POSITION, c.zone())
->AddMove(r1, slot_1);
instr->GetOrCreateParallelMove(Instruction::FIRST_GAP_POSITION, c.zone())
->AddMove(slot_minus_1, slot_2);
instr->GetOrCreateParallelMove(Instruction::FIRST_GAP_POSITION, c.zone())
->AddMove(r0, slot_3);
c.CheckAssembleTailCallGaps(instr, first_slot + 4,
CodeGeneratorTester::kScalarPush);
c.Disassemble();
}
}
} // namespace compiler
} // namespace internal
} // namespace v8