blob: aaf3805053d79d238555cdab46c54d96e6cb5f24 [file] [log] [blame]
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/compiler/backend/locations_helpers.h"
#include "vm/dart_api_impl.h"
#include "vm/dart_entry.h"
#include "vm/unit_test.h"
namespace dart {
#define Reg(index) (static_cast<Register>(index))
#define Fpu(index) (static_cast<FpuRegister>(index))
#define ReqReg Location::RequiresRegister()
#define ReqFpu Location::RequiresFpuRegister()
#define RegLoc(index) Location::RegisterLocation(Reg(index))
#define FpuLoc(index) Location::FpuRegisterLocation(Fpu(index))
typedef ZoneGrowableArray<Location> LocationArray;
static LocationArray* MakeLocationArray() {
LocationArray* arr = new LocationArray();
return arr;
}
static LocationArray* MakeLocationArray(Location loc0) {
LocationArray* arr = new LocationArray();
arr->Add(loc0);
return arr;
}
static LocationArray* MakeLocationArray(Location loc0, Location loc1) {
LocationArray* arr = new LocationArray();
arr->Add(loc0);
arr->Add(loc1);
return arr;
}
static void ValidateSummary(LocationSummary* locs,
Location expected_output,
const LocationArray* expected_inputs,
const LocationArray* expected_temps) {
EXPECT(locs->out(0).Equals(expected_output));
EXPECT_EQ(expected_inputs->length(), locs->input_count());
for (intptr_t i = 0; i < expected_inputs->length(); i++) {
EXPECT(locs->in(i).Equals(expected_inputs->At(i)));
}
EXPECT_EQ(expected_temps->length(), locs->temp_count());
for (intptr_t i = 0; i < expected_temps->length(); i++) {
EXPECT(locs->temp(i).Equals(expected_temps->At(i)));
}
}
static void FillSummary(LocationSummary* locs,
Location expected_output,
const LocationArray* expected_inputs,
const LocationArray* expected_temps) {
locs->set_out(0, expected_output);
for (intptr_t i = 0; i < expected_inputs->length(); i++) {
locs->set_in(i, expected_inputs->At(i));
}
for (intptr_t i = 0; i < expected_temps->length(); i++) {
locs->set_temp(i, expected_temps->At(i));
}
}
class MockInstruction : public ZoneAllocated {
public:
virtual ~MockInstruction() {}
LocationSummary* locs() {
if (locs_ == NULL) {
locs_ = MakeLocationSummary(Thread::Current()->zone(), false);
}
return locs_;
}
virtual LocationSummary* MakeLocationSummary(Zone* zone, bool opt) const = 0;
virtual void EmitNativeCode(FlowGraphCompiler* compiler) = 0;
private:
LocationSummary* locs_;
};
#define INSTRUCTION_TEST(Name, Arity, Signature, ExpectedOut, ExpectedIn, \
ExpectedTemp, AllocatedOut, AllocatedIn, \
AllocatedTemp) \
class Name##Instr : public MockInstruction { \
public: \
LocationSummary* MakeLocationSummary(Zone* zone, bool opt) const; \
void EmitNativeCode(FlowGraphCompiler* compiler); \
virtual intptr_t InputCount() const { return Arity; } \
}; \
TEST_CASE(LocationsHelpers_##Name) { \
const Location expected_out = ExpectedOut; \
const LocationArray* expected_inputs = MakeLocationArray ExpectedIn; \
const LocationArray* expected_temps = MakeLocationArray ExpectedTemp; \
\
const Location allocated_out = AllocatedOut; \
const LocationArray* allocated_inputs = MakeLocationArray AllocatedIn; \
const LocationArray* allocated_temps = MakeLocationArray AllocatedTemp; \
\
Name##Instr* instr = new Name##Instr(); \
LocationSummary* locs = instr->locs(); \
\
ValidateSummary(locs, expected_out, expected_inputs, expected_temps); \
FillSummary(locs, allocated_out, allocated_inputs, allocated_temps); \
\
instr->EmitNativeCode(NULL); \
} \
DEFINE_BACKEND(Name, Signature)
// Reg -> Reg
INSTRUCTION_TEST(Unary,
1,
(Register out, Register in),
ReqReg,
(ReqReg),
(),
RegLoc(0),
(RegLoc(1)),
()) {
EXPECT_EQ(Reg(0), out);
EXPECT_EQ(Reg(1), in);
}
// (Reg, Fpu) -> Reg
INSTRUCTION_TEST(Binary1,
2,
(Register out, Register in0, FpuRegister in1),
ReqReg,
(ReqReg, Location::RequiresFpuRegister()),
(),
RegLoc(0),
(RegLoc(1), FpuLoc(2)),
()) {
EXPECT_EQ(Reg(0), out);
EXPECT_EQ(Reg(1), in0);
EXPECT_EQ(Fpu(2), in1);
}
// (Fpu, Reg) -> Reg
INSTRUCTION_TEST(Binary2,
2,
(Register out, FpuRegister in0, Register in1),
ReqReg,
(ReqFpu, ReqReg),
(),
RegLoc(0),
(FpuLoc(1), RegLoc(2)),
()) {
EXPECT_EQ(Reg(0), out);
EXPECT_EQ(Fpu(1), in0);
EXPECT_EQ(Reg(2), in1);
}
// -> Reg(3)
INSTRUCTION_TEST(FixedOutput,
0,
(Fixed<Register, Reg(3)> out),
RegLoc(3),
(),
(),
RegLoc(3),
(),
()) {
EXPECT_EQ(Reg(3), Reg(out));
}
// Fpu(3) -> Fpu
INSTRUCTION_TEST(FixedInput,
1,
(FpuRegister out, Fixed<FpuRegister, Fpu(3)> in),
ReqFpu,
(FpuLoc(3)),
(),
FpuLoc(0),
(FpuLoc(3)),
()) {
EXPECT_EQ(Fpu(0), out);
EXPECT_EQ(Fpu(3), Fpu(in));
}
// Reg -> SameAsFirstInput
INSTRUCTION_TEST(SameAsFirstInput,
2,
(SameAsFirstInput, Register in0, Register in1),
Location::SameAsFirstInput(),
(ReqReg, ReqReg),
(),
RegLoc(0),
(RegLoc(0), RegLoc(1)),
()) {
EXPECT_EQ(Reg(0), in0);
EXPECT_EQ(Reg(1), in1);
}
// {Temps: Fpu, Reg} (Reg, Fpu) -> Reg
INSTRUCTION_TEST(Temps,
2,
(Register out,
Register in0,
FpuRegister in1,
Temp<FpuRegister> temp0,
Temp<Register> temp1),
ReqReg,
(ReqReg, ReqFpu),
(ReqFpu, ReqReg),
RegLoc(0),
(RegLoc(1), FpuLoc(2)),
(FpuLoc(3), RegLoc(4))) {
EXPECT_EQ(Reg(0), out);
EXPECT_EQ(Reg(1), in0);
EXPECT_EQ(Fpu(2), in1);
EXPECT_EQ(Fpu(3), Fpu(temp0));
EXPECT_EQ(Reg(4), Reg(temp1));
}
// {Temps: Fpu(3)} -> Fpu
INSTRUCTION_TEST(FixedTemp,
0,
(FpuRegister out, Temp<Fixed<FpuRegister, Fpu(3)> > temp),
ReqFpu,
(),
(FpuLoc(3)),
FpuLoc(4),
(),
(FpuLoc(3))) {
EXPECT_EQ(Fpu(4), out);
EXPECT_EQ(Fpu(3), Fpu(temp));
}
} // namespace dart