Commit 44b520f5 authored by ahaas's avatar ahaas Committed by Commit bot

Implement the BufferedRawMachineAssemblerTester.

This utility makes it possible to test TF graphs that accept parameters of any machine type (even int64 and float64), which are previously problematic due to the complexity of C calling conventions.

R=titzer@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#31698}
parent e66d4f87
...@@ -13,7 +13,7 @@ namespace compiler { ...@@ -13,7 +13,7 @@ namespace compiler {
#define FOREACH_CTYPE_MACHINE_TYPE_MAPPING(V) \ #define FOREACH_CTYPE_MACHINE_TYPE_MAPPING(V) \
V(void, kMachNone) \ V(void, kMachNone) \
V(bool, kMachBool) \ V(bool, kMachUint8) \
V(int8_t, kMachInt8) \ V(int8_t, kMachInt8) \
V(uint8_t, kMachUint8) \ V(uint8_t, kMachUint8) \
V(int16_t, kMachInt16) \ V(int16_t, kMachInt16) \
......
...@@ -159,6 +159,13 @@ class CallHelper { ...@@ -159,6 +159,13 @@ class CallHelper {
return DoCall(FUNCTION_CAST<FType*>(Generate()), p1, p2, p3, p4); return DoCall(FUNCTION_CAST<FType*>(Generate()), p1, p2, p3, p4);
} }
template <typename P1, typename P2, typename P3, typename P4, typename P5>
R Call(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
typedef R V8_CDECL FType(P1, P2, P3, P4, P5);
csig_->VerifyParams<P1, P2, P3, P4, P5>();
return DoCall(FUNCTION_CAST<FType*>(Generate()), p1, p2, p3, p4, p5);
}
protected: protected:
CSignature* csig_; CSignature* csig_;
...@@ -204,11 +211,20 @@ class CallHelper { ...@@ -204,11 +211,20 @@ class CallHelper {
Simulator::CallArgument::End()}; Simulator::CallArgument::End()};
return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f), args)); return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f), args));
} }
template <typename F, typename P1, typename P2, typename P3, typename P4,
typename P5>
R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
Simulator::CallArgument args[] = {
Simulator::CallArgument(p1), Simulator::CallArgument(p2),
Simulator::CallArgument(p3), Simulator::CallArgument(p4),
Simulator::CallArgument(p5), Simulator::CallArgument::End()};
return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f), args));
}
#elif USE_SIMULATOR && (V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64) #elif USE_SIMULATOR && (V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64)
uintptr_t CallSimulator(byte* f, int64_t p1 = 0, int64_t p2 = 0, uintptr_t CallSimulator(byte* f, int64_t p1 = 0, int64_t p2 = 0,
int64_t p3 = 0, int64_t p4 = 0) { int64_t p3 = 0, int64_t p4 = 0, int64_t p5 = 0) {
Simulator* simulator = Simulator::current(isolate_); Simulator* simulator = Simulator::current(isolate_);
return static_cast<uintptr_t>(simulator->Call(f, 4, p1, p2, p3, p4)); return static_cast<uintptr_t>(simulator->Call(f, 5, p1, p2, p3, p4, p5));
} }
...@@ -240,12 +256,20 @@ class CallHelper { ...@@ -240,12 +256,20 @@ class CallHelper {
ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3), ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3),
ParameterTraits<P4>::Cast(p4))); ParameterTraits<P4>::Cast(p4)));
} }
template <typename F, typename P1, typename P2, typename P3, typename P4,
typename P5>
R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
return CastReturnValue<R>(CallSimulator(
FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3),
ParameterTraits<P4>::Cast(p4), ParameterTraits<P5>::Cast(p5)));
}
#elif USE_SIMULATOR && \ #elif USE_SIMULATOR && \
(V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_PPC) (V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_PPC)
uintptr_t CallSimulator(byte* f, int32_t p1 = 0, int32_t p2 = 0, uintptr_t CallSimulator(byte* f, int32_t p1 = 0, int32_t p2 = 0,
int32_t p3 = 0, int32_t p4 = 0) { int32_t p3 = 0, int32_t p4 = 0, int32_t p5 = 0) {
Simulator* simulator = Simulator::current(isolate_); Simulator* simulator = Simulator::current(isolate_);
return static_cast<uintptr_t>(simulator->Call(f, 4, p1, p2, p3, p4)); return static_cast<uintptr_t>(simulator->Call(f, 5, p1, p2, p3, p4, p5));
} }
template <typename F> template <typename F>
R DoCall(F* f) { R DoCall(F* f) {
...@@ -275,6 +299,14 @@ class CallHelper { ...@@ -275,6 +299,14 @@ class CallHelper {
ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3), ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3),
ParameterTraits<P4>::Cast(p4))); ParameterTraits<P4>::Cast(p4)));
} }
template <typename F, typename P1, typename P2, typename P3, typename P4,
typename P5>
R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
return CastReturnValue<R>(CallSimulator(
FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3),
ParameterTraits<P4>::Cast(p4), ParameterTraits<P5>::Cast(p5)));
}
#else #else
template <typename F> template <typename F>
R DoCall(F* f) { R DoCall(F* f) {
...@@ -296,6 +328,11 @@ class CallHelper { ...@@ -296,6 +328,11 @@ class CallHelper {
R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) { R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) {
return f(p1, p2, p3, p4); return f(p1, p2, p3, p4);
} }
template <typename F, typename P1, typename P2, typename P3, typename P4,
typename P5>
R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
return f(p1, p2, p3, p4, p5);
}
#endif #endif
Isolate* isolate_; Isolate* isolate_;
......
...@@ -570,6 +570,145 @@ TEST(RunBinopTester) { ...@@ -570,6 +570,145 @@ TEST(RunBinopTester) {
} }
} }
#if V8_TARGET_ARCH_64_BIT
// TODO(ahaas): run int64 tests on all platforms when supported.
TEST(RunBufferedRawMachineAssemblerTesterTester) {
{
BufferedRawMachineAssemblerTester<int64_t> m;
m.Return(m.Int64Constant(0x12500000000));
CHECK_EQ(0x12500000000, m.Call());
}
{
BufferedRawMachineAssemblerTester<double> m(kMachFloat64);
m.Return(m.Parameter(0));
FOR_FLOAT64_INPUTS(i) { CheckDoubleEq(*i, m.Call(*i)); }
}
{
BufferedRawMachineAssemblerTester<int64_t> m(kMachInt64, kMachInt64);
m.Return(m.Int64Add(m.Parameter(0), m.Parameter(1)));
FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) {
CHECK_EQ(*i + *j, m.Call(*i, *j));
CHECK_EQ(*j + *i, m.Call(*j, *i));
}
}
}
{
BufferedRawMachineAssemblerTester<int64_t> m(kMachInt64, kMachInt64,
kMachInt64);
m.Return(
m.Int64Add(m.Int64Add(m.Parameter(0), m.Parameter(1)), m.Parameter(2)));
FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) {
CHECK_EQ(*i + *i + *j, m.Call(*i, *i, *j));
CHECK_EQ(*i + *j + *i, m.Call(*i, *j, *i));
CHECK_EQ(*j + *i + *i, m.Call(*j, *i, *i));
}
}
}
{
BufferedRawMachineAssemblerTester<int64_t> m(kMachInt64, kMachInt64,
kMachInt64, kMachInt64);
m.Return(m.Int64Add(
m.Int64Add(m.Int64Add(m.Parameter(0), m.Parameter(1)), m.Parameter(2)),
m.Parameter(3)));
FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) {
CHECK_EQ(*i + *i + *i + *j, m.Call(*i, *i, *i, *j));
CHECK_EQ(*i + *i + *j + *i, m.Call(*i, *i, *j, *i));
CHECK_EQ(*i + *j + *i + *i, m.Call(*i, *j, *i, *i));
CHECK_EQ(*j + *i + *i + *i, m.Call(*j, *i, *i, *i));
}
}
}
{
BufferedRawMachineAssemblerTester<void> m;
int64_t result;
m.Store(MachineTypeForC<int64_t>(), m.PointerConstant(&result),
m.Int64Constant(0x12500000000), kNoWriteBarrier);
m.Return(m.Int32Constant(0));
m.Call();
CHECK_EQ(0x12500000000, result);
}
{
BufferedRawMachineAssemblerTester<void> m(kMachFloat64);
double result;
m.Store(MachineTypeForC<double>(), m.PointerConstant(&result),
m.Parameter(0), kNoWriteBarrier);
m.Return(m.Int32Constant(0));
FOR_FLOAT64_INPUTS(i) {
m.Call(*i);
CheckDoubleEq(*i, result);
}
}
{
BufferedRawMachineAssemblerTester<void> m(kMachInt64, kMachInt64);
int64_t result;
m.Store(MachineTypeForC<int64_t>(), m.PointerConstant(&result),
m.Int64Add(m.Parameter(0), m.Parameter(1)), kNoWriteBarrier);
m.Return(m.Int32Constant(0));
FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) {
m.Call(*i, *j);
CHECK_EQ(*i + *j, result);
m.Call(*j, *i);
CHECK_EQ(*j + *i, result);
}
}
}
{
BufferedRawMachineAssemblerTester<void> m(kMachInt64, kMachInt64,
kMachInt64);
int64_t result;
m.Store(
MachineTypeForC<int64_t>(), m.PointerConstant(&result),
m.Int64Add(m.Int64Add(m.Parameter(0), m.Parameter(1)), m.Parameter(2)),
kNoWriteBarrier);
m.Return(m.Int32Constant(0));
FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) {
m.Call(*i, *i, *j);
CHECK_EQ(*i + *i + *j, result);
m.Call(*i, *j, *i);
CHECK_EQ(*i + *j + *i, result);
m.Call(*j, *i, *i);
CHECK_EQ(*j + *i + *i, result);
}
}
}
{
BufferedRawMachineAssemblerTester<void> m(kMachInt64, kMachInt64,
kMachInt64, kMachInt64);
int64_t result;
m.Store(MachineTypeForC<int64_t>(), m.PointerConstant(&result),
m.Int64Add(m.Int64Add(m.Int64Add(m.Parameter(0), m.Parameter(1)),
m.Parameter(2)),
m.Parameter(3)),
kNoWriteBarrier);
m.Return(m.Int32Constant(0));
FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) {
m.Call(*i, *i, *i, *j);
CHECK_EQ(*i + *i + *i + *j, result);
m.Call(*i, *i, *j, *i);
CHECK_EQ(*i + *i + *j + *i, result);
m.Call(*i, *j, *i, *i);
CHECK_EQ(*i + *j + *i + *i, result);
m.Call(*j, *i, *i, *i);
CHECK_EQ(*j + *i + *i + *i, result);
}
}
}
}
#endif
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -73,6 +73,207 @@ class RawMachineAssemblerTester : public HandleAndZoneScope, ...@@ -73,6 +73,207 @@ class RawMachineAssemblerTester : public HandleAndZoneScope,
}; };
template <typename ReturnType>
class BufferedRawMachineAssemblerTester
: public RawMachineAssemblerTester<int32_t> {
public:
BufferedRawMachineAssemblerTester()
: BufferedRawMachineAssemblerTester(0, kMachNone, kMachNone, kMachNone,
kMachNone) {}
explicit BufferedRawMachineAssemblerTester(MachineType p0)
: BufferedRawMachineAssemblerTester(1, p0, kMachNone, kMachNone,
kMachNone) {}
BufferedRawMachineAssemblerTester(MachineType p0, MachineType p1)
: BufferedRawMachineAssemblerTester(2, p0, p1, kMachNone, kMachNone) {}
BufferedRawMachineAssemblerTester(MachineType p0, MachineType p1,
MachineType p2)
: BufferedRawMachineAssemblerTester(3, p0, p1, p2, kMachNone) {}
BufferedRawMachineAssemblerTester(MachineType p0, MachineType p1,
MachineType p2, MachineType p3)
: BufferedRawMachineAssemblerTester(4, p0, p1, p2, p3) {}
// The BufferedRawMachineAssemblerTester does not pass parameters directly
// to the constructed IR graph. Instead it passes a pointer to the parameter
// to the IR graph, and adds Load nodes to the IR graph to load the
// parameters from memory. Thereby it is possible to pass 64 bit parameters
// to the IR graph.
Node* Parameter(size_t index) {
CHECK(index >= 0 && index < 4);
return parameter_nodes_[index];
}
// The BufferedRawMachineAssemblerTester adds a Store node to the IR graph
// to store the graph's return value in memory. The memory address for the
// Store node is provided as a parameter. By storing the return value in
// memory it is possible to return 64 bit values.
void Return(Node* input) {
Store(MachineTypeForC<ReturnType>(),
RawMachineAssembler::Parameter(return_parameter_index_), input,
kNoWriteBarrier);
RawMachineAssembler::Return(Int32Constant(1234));
}
ReturnType Call() {
ReturnType return_value;
test_graph_signature_->VerifyParams();
CallHelper<int32_t>::Call(reinterpret_cast<void*>(&return_value));
return return_value;
}
template <typename P0>
ReturnType Call(P0 p0) {
ReturnType return_value;
test_graph_signature_->VerifyParams<P0>();
CallHelper<int32_t>::Call(reinterpret_cast<void*>(&p0),
reinterpret_cast<void*>(&return_value));
return return_value;
}
template <typename P0, typename P1>
ReturnType Call(P0 p0, P1 p1) {
ReturnType return_value;
test_graph_signature_->VerifyParams<P0, P1>();
CallHelper<int32_t>::Call(reinterpret_cast<void*>(&p0),
reinterpret_cast<void*>(&p1),
reinterpret_cast<void*>(&return_value));
return return_value;
}
template <typename P0, typename P1, typename P2>
ReturnType Call(P0 p0, P1 p1, P2 p2) {
ReturnType return_value;
test_graph_signature_->VerifyParams<P0, P1, P2>();
CallHelper<int32_t>::Call(
reinterpret_cast<void*>(&p0), reinterpret_cast<void*>(&p1),
reinterpret_cast<void*>(&p2), reinterpret_cast<void*>(&return_value));
return return_value;
}
template <typename P0, typename P1, typename P2, typename P3>
ReturnType Call(P0 p0, P1 p1, P2 p2, P3 p3) {
ReturnType return_value;
test_graph_signature_->VerifyParams<P0, P1, P2, P3>();
CallHelper<int32_t>::Call(
reinterpret_cast<void*>(&p0), reinterpret_cast<void*>(&p1),
reinterpret_cast<void*>(&p2), reinterpret_cast<void*>(&p3),
reinterpret_cast<void*>(&return_value));
return return_value;
}
private:
BufferedRawMachineAssemblerTester(uint32_t return_parameter_index,
MachineType p0, MachineType p1,
MachineType p2, MachineType p3)
: RawMachineAssemblerTester<int32_t>(
kMachPtr, p0 == kMachNone ? kMachNone : kMachPtr,
p1 == kMachNone ? kMachNone : kMachPtr,
p2 == kMachNone ? kMachNone : kMachPtr,
p3 == kMachNone ? kMachNone : kMachPtr),
test_graph_signature_(
CSignature::New(main_zone(), kMachInt32, p0, p1, p2, p3)),
return_parameter_index_(return_parameter_index) {
parameter_nodes_[0] =
p0 == kMachNone ? nullptr : Load(p0, RawMachineAssembler::Parameter(0));
parameter_nodes_[1] =
p1 == kMachNone ? nullptr : Load(p1, RawMachineAssembler::Parameter(1));
parameter_nodes_[2] =
p2 == kMachNone ? nullptr : Load(p2, RawMachineAssembler::Parameter(2));
parameter_nodes_[3] =
p3 == kMachNone ? nullptr : Load(p3, RawMachineAssembler::Parameter(3));
}
CSignature* test_graph_signature_;
Node* parameter_nodes_[4];
uint32_t return_parameter_index_;
};
template <>
class BufferedRawMachineAssemblerTester<void>
: public RawMachineAssemblerTester<void> {
public:
BufferedRawMachineAssemblerTester(MachineType p0 = kMachNone,
MachineType p1 = kMachNone,
MachineType p2 = kMachNone,
MachineType p3 = kMachNone)
: RawMachineAssemblerTester<void>(p0 == kMachNone ? kMachNone : kMachPtr,
p1 == kMachNone ? kMachNone : kMachPtr,
p2 == kMachNone ? kMachNone : kMachPtr,
p3 == kMachNone ? kMachNone : kMachPtr),
test_graph_signature_(
CSignature::New(RawMachineAssemblerTester<void>::main_zone(),
kMachNone, p0, p1, p2, p3)) {
parameter_nodes_[0] =
p0 == kMachNone ? nullptr : Load(p0, RawMachineAssembler::Parameter(0));
parameter_nodes_[1] =
p1 == kMachNone ? nullptr : Load(p1, RawMachineAssembler::Parameter(1));
parameter_nodes_[2] =
p2 == kMachNone ? nullptr : Load(p2, RawMachineAssembler::Parameter(2));
parameter_nodes_[3] =
p3 == kMachNone ? nullptr : Load(p3, RawMachineAssembler::Parameter(3));
}
// The BufferedRawMachineAssemblerTester does not pass parameters directly
// to the constructed IR graph. Instead it passes a pointer to the parameter
// to the IR graph, and adds Load nodes to the IR graph to load the
// parameters from memory. Thereby it is possible to pass 64 bit parameters
// to the IR graph.
Node* Parameter(size_t index) {
CHECK(index >= 0 && index < 4);
return parameter_nodes_[index];
}
void Call() {
test_graph_signature_->VerifyParams();
CallHelper<void>::Call();
}
template <typename P0>
void Call(P0 p0) {
test_graph_signature_->VerifyParams<P0>();
CallHelper<void>::Call(reinterpret_cast<void*>(&p0));
}
template <typename P0, typename P1>
void Call(P0 p0, P1 p1) {
test_graph_signature_->VerifyParams<P0, P1>();
CallHelper<void>::Call(reinterpret_cast<void*>(&p0),
reinterpret_cast<void*>(&p1));
}
template <typename P0, typename P1, typename P2>
void Call(P0 p0, P1 p1, P2 p2) {
test_graph_signature_->VerifyParams<P0, P1, P2>();
CallHelper<void>::Call(reinterpret_cast<void*>(&p0),
reinterpret_cast<void*>(&p1),
reinterpret_cast<void*>(&p2));
}
template <typename P0, typename P1, typename P2, typename P3>
void Call(P0 p0, P1 p1, P2 p2, P3 p3) {
test_graph_signature_->VerifyParams<P0, P1, P2, P3>();
CallHelper<void>::Call(
reinterpret_cast<void*>(&p0), reinterpret_cast<void*>(&p1),
reinterpret_cast<void*>(&p2), reinterpret_cast<void*>(&p3));
}
private:
CSignature* test_graph_signature_;
Node* parameter_nodes_[4];
};
static const bool USE_RESULT_BUFFER = true; static const bool USE_RESULT_BUFFER = true;
static const bool USE_RETURN_REGISTER = false; static const bool USE_RETURN_REGISTER = false;
static const int32_t CHECK_VALUE = 0x99BEEDCE; static const int32_t CHECK_VALUE = 0x99BEEDCE;
......
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