Remove accidental duplication in cctest suite.
R=danno@google.com, danno@chromium.org Review URL: https://codereview.chromium.org/423313004 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22712 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
20d6798293
commit
2c328e94f9
@ -1,391 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#ifndef V8_CCTEST_COMPILER_CALL_TESTER_H_
|
||||
#define V8_CCTEST_COMPILER_CALL_TESTER_H_
|
||||
|
||||
#include "src/v8.h"
|
||||
|
||||
#include "src/simulator.h"
|
||||
|
||||
#if V8_TARGET_ARCH_IA32
|
||||
#if __GNUC__
|
||||
#define V8_CDECL __attribute__((cdecl))
|
||||
#else
|
||||
#define V8_CDECL __cdecl
|
||||
#endif
|
||||
#else
|
||||
#define V8_CDECL
|
||||
#endif
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
template <typename R>
|
||||
struct ReturnValueTraits {
|
||||
static R Cast(uintptr_t r) { return reinterpret_cast<R>(r); }
|
||||
static MachineRepresentation Representation() {
|
||||
// TODO(dcarney): detect when R is of a subclass of Object* instead of this
|
||||
// type check.
|
||||
while (false) {
|
||||
*(static_cast<Object* volatile*>(0)) = static_cast<R>(0);
|
||||
}
|
||||
return kMachineTagged;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ReturnValueTraits<int32_t*> {
|
||||
static int32_t* Cast(uintptr_t r) { return reinterpret_cast<int32_t*>(r); }
|
||||
static MachineRepresentation Representation() {
|
||||
return MachineOperatorBuilder::pointer_rep();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ReturnValueTraits<void> {
|
||||
static void Cast(uintptr_t r) {}
|
||||
static MachineRepresentation Representation() {
|
||||
return MachineOperatorBuilder::pointer_rep();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ReturnValueTraits<bool> {
|
||||
static bool Cast(uintptr_t r) { return static_cast<bool>(r); }
|
||||
static MachineRepresentation Representation() {
|
||||
return MachineOperatorBuilder::pointer_rep();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ReturnValueTraits<int32_t> {
|
||||
static int32_t Cast(uintptr_t r) { return static_cast<int32_t>(r); }
|
||||
static MachineRepresentation Representation() { return kMachineWord32; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ReturnValueTraits<uint32_t> {
|
||||
static uint32_t Cast(uintptr_t r) { return static_cast<uint32_t>(r); }
|
||||
static MachineRepresentation Representation() { return kMachineWord32; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ReturnValueTraits<int64_t> {
|
||||
static int64_t Cast(uintptr_t r) { return static_cast<int64_t>(r); }
|
||||
static MachineRepresentation Representation() { return kMachineWord64; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ReturnValueTraits<uint64_t> {
|
||||
static uint64_t Cast(uintptr_t r) { return static_cast<uint64_t>(r); }
|
||||
static MachineRepresentation Representation() { return kMachineWord64; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ReturnValueTraits<int16_t> {
|
||||
static int16_t Cast(uintptr_t r) { return static_cast<int16_t>(r); }
|
||||
static MachineRepresentation Representation() {
|
||||
return MachineOperatorBuilder::pointer_rep();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ReturnValueTraits<int8_t> {
|
||||
static int8_t Cast(uintptr_t r) { return static_cast<int8_t>(r); }
|
||||
static MachineRepresentation Representation() {
|
||||
return MachineOperatorBuilder::pointer_rep();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ReturnValueTraits<double> {
|
||||
static double Cast(uintptr_t r) {
|
||||
UNREACHABLE();
|
||||
return 0.0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename R>
|
||||
struct ParameterTraits {
|
||||
static uintptr_t Cast(R r) { return static_cast<uintptr_t>(r); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParameterTraits<int*> {
|
||||
static uintptr_t Cast(int* r) { return reinterpret_cast<uintptr_t>(r); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ParameterTraits<T*> {
|
||||
static uintptr_t Cast(void* r) { return reinterpret_cast<uintptr_t>(r); }
|
||||
};
|
||||
|
||||
class CallHelper {
|
||||
public:
|
||||
explicit CallHelper(Isolate* isolate) : isolate_(isolate) { USE(isolate_); }
|
||||
virtual ~CallHelper() {}
|
||||
|
||||
static MachineCallDescriptorBuilder* ToCallDescriptorBuilder(
|
||||
Zone* zone, MachineRepresentation return_type,
|
||||
MachineRepresentation p0 = kMachineLast,
|
||||
MachineRepresentation p1 = kMachineLast,
|
||||
MachineRepresentation p2 = kMachineLast,
|
||||
MachineRepresentation p3 = kMachineLast,
|
||||
MachineRepresentation p4 = kMachineLast) {
|
||||
const int kSize = 5;
|
||||
MachineRepresentation* params =
|
||||
zone->NewArray<MachineRepresentation>(kSize);
|
||||
params[0] = p0;
|
||||
params[1] = p1;
|
||||
params[2] = p2;
|
||||
params[3] = p3;
|
||||
params[4] = p4;
|
||||
int parameter_count = 0;
|
||||
for (int i = 0; i < kSize; ++i) {
|
||||
if (params[i] == kMachineLast) {
|
||||
break;
|
||||
}
|
||||
parameter_count++;
|
||||
}
|
||||
return new (zone)
|
||||
MachineCallDescriptorBuilder(return_type, parameter_count, params);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void VerifyParameters(int parameter_count,
|
||||
MachineRepresentation* parameters) = 0;
|
||||
virtual byte* Generate() = 0;
|
||||
|
||||
private:
|
||||
#if USE_SIMULATOR && V8_TARGET_ARCH_ARM64
|
||||
uintptr_t CallSimulator(byte* f, Simulator::CallArgument* args) {
|
||||
Simulator* simulator = Simulator::current(isolate_);
|
||||
return static_cast<uintptr_t>(simulator->CallInt64(f, args));
|
||||
}
|
||||
|
||||
template <typename R, typename F>
|
||||
R DoCall(F* f) {
|
||||
Simulator::CallArgument args[] = {Simulator::CallArgument::End()};
|
||||
return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f), args));
|
||||
}
|
||||
template <typename R, typename F, typename P1>
|
||||
R DoCall(F* f, P1 p1) {
|
||||
Simulator::CallArgument args[] = {Simulator::CallArgument(p1),
|
||||
Simulator::CallArgument::End()};
|
||||
return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f), args));
|
||||
}
|
||||
template <typename R, typename F, typename P1, typename P2>
|
||||
R DoCall(F* f, P1 p1, P2 p2) {
|
||||
Simulator::CallArgument args[] = {Simulator::CallArgument(p1),
|
||||
Simulator::CallArgument(p2),
|
||||
Simulator::CallArgument::End()};
|
||||
return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f), args));
|
||||
}
|
||||
template <typename R, typename F, typename P1, typename P2, typename P3>
|
||||
R DoCall(F* f, P1 p1, P2 p2, P3 p3) {
|
||||
Simulator::CallArgument args[] = {
|
||||
Simulator::CallArgument(p1), Simulator::CallArgument(p2),
|
||||
Simulator::CallArgument(p3), Simulator::CallArgument::End()};
|
||||
return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f), args));
|
||||
}
|
||||
template <typename R, typename F, typename P1, typename P2, typename P3,
|
||||
typename P4>
|
||||
R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) {
|
||||
Simulator::CallArgument args[] = {
|
||||
Simulator::CallArgument(p1), Simulator::CallArgument(p2),
|
||||
Simulator::CallArgument(p3), Simulator::CallArgument(p4),
|
||||
Simulator::CallArgument::End()};
|
||||
return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f), args));
|
||||
}
|
||||
#elif USE_SIMULATOR && V8_TARGET_ARCH_ARM
|
||||
uintptr_t CallSimulator(byte* f, int32_t p1 = 0, int32_t p2 = 0,
|
||||
int32_t p3 = 0, int32_t p4 = 0) {
|
||||
Simulator* simulator = Simulator::current(isolate_);
|
||||
return static_cast<uintptr_t>(simulator->Call(f, 4, p1, p2, p3, p4));
|
||||
}
|
||||
template <typename R, typename F>
|
||||
R DoCall(F* f) {
|
||||
return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f)));
|
||||
}
|
||||
template <typename R, typename F, typename P1>
|
||||
R DoCall(F* f, P1 p1) {
|
||||
return ReturnValueTraits<R>::Cast(
|
||||
CallSimulator(FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1)));
|
||||
}
|
||||
template <typename R, typename F, typename P1, typename P2>
|
||||
R DoCall(F* f, P1 p1, P2 p2) {
|
||||
return ReturnValueTraits<R>::Cast(
|
||||
CallSimulator(FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
|
||||
ParameterTraits<P2>::Cast(p2)));
|
||||
}
|
||||
template <typename R, typename F, typename P1, typename P2, typename P3>
|
||||
R DoCall(F* f, P1 p1, P2 p2, P3 p3) {
|
||||
return ReturnValueTraits<R>::Cast(CallSimulator(
|
||||
FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
|
||||
ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3)));
|
||||
}
|
||||
template <typename R, typename F, typename P1, typename P2, typename P3,
|
||||
typename P4>
|
||||
R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) {
|
||||
return ReturnValueTraits<R>::Cast(CallSimulator(
|
||||
FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
|
||||
ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3),
|
||||
ParameterTraits<P4>::Cast(p4)));
|
||||
}
|
||||
#else
|
||||
template <typename R, typename F>
|
||||
R DoCall(F* f) {
|
||||
return f();
|
||||
}
|
||||
template <typename R, typename F, typename P1>
|
||||
R DoCall(F* f, P1 p1) {
|
||||
return f(p1);
|
||||
}
|
||||
template <typename R, typename F, typename P1, typename P2>
|
||||
R DoCall(F* f, P1 p1, P2 p2) {
|
||||
return f(p1, p2);
|
||||
}
|
||||
template <typename R, typename F, typename P1, typename P2, typename P3>
|
||||
R DoCall(F* f, P1 p1, P2 p2, P3 p3) {
|
||||
return f(p1, p2, p3);
|
||||
}
|
||||
template <typename R, typename F, typename P1, typename P2, typename P3,
|
||||
typename P4>
|
||||
R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) {
|
||||
return f(p1, p2, p3, p4);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef DEBUG
|
||||
void VerifyParameters0() {}
|
||||
|
||||
template <typename P1>
|
||||
void VerifyParameters1() {}
|
||||
|
||||
template <typename P1, typename P2>
|
||||
void VerifyParameters2() {}
|
||||
|
||||
template <typename P1, typename P2, typename P3>
|
||||
void VerifyParameters3() {}
|
||||
|
||||
template <typename P1, typename P2, typename P3, typename P4>
|
||||
void VerifyParameters4() {}
|
||||
#else
|
||||
void VerifyParameters0() { VerifyParameters(0, NULL); }
|
||||
|
||||
template <typename P1>
|
||||
void VerifyParameters1() {
|
||||
MachineRepresentation parameters[] = {
|
||||
ReturnValueTraits<P1>::Representation()};
|
||||
VerifyParameters(ARRAY_SIZE(parameters), parameters);
|
||||
}
|
||||
|
||||
template <typename P1, typename P2>
|
||||
void VerifyParameters2() {
|
||||
MachineRepresentation parameters[] = {
|
||||
ReturnValueTraits<P1>::Representation(),
|
||||
ReturnValueTraits<P2>::Representation()};
|
||||
VerifyParameters(ARRAY_SIZE(parameters), parameters);
|
||||
}
|
||||
|
||||
template <typename P1, typename P2, typename P3>
|
||||
void VerifyParameters3() {
|
||||
MachineRepresentation parameters[] = {
|
||||
ReturnValueTraits<P1>::Representation(),
|
||||
ReturnValueTraits<P2>::Representation(),
|
||||
ReturnValueTraits<P3>::Representation()};
|
||||
VerifyParameters(ARRAY_SIZE(parameters), parameters);
|
||||
}
|
||||
|
||||
template <typename P1, typename P2, typename P3, typename P4>
|
||||
void VerifyParameters4() {
|
||||
MachineRepresentation parameters[] = {
|
||||
ReturnValueTraits<P1>::Representation(),
|
||||
ReturnValueTraits<P2>::Representation(),
|
||||
ReturnValueTraits<P3>::Representation(),
|
||||
ReturnValueTraits<P4>::Representation()};
|
||||
VerifyParameters(ARRAY_SIZE(parameters), parameters);
|
||||
}
|
||||
#endif
|
||||
|
||||
// TODO(dcarney): replace Call() in CallHelper2 with these.
|
||||
template <typename R>
|
||||
R Call0() {
|
||||
typedef R V8_CDECL FType();
|
||||
VerifyParameters0();
|
||||
return DoCall<R>(FUNCTION_CAST<FType*>(Generate()));
|
||||
}
|
||||
|
||||
template <typename R, typename P1>
|
||||
R Call1(P1 p1) {
|
||||
typedef R V8_CDECL FType(P1);
|
||||
VerifyParameters1<P1>();
|
||||
return DoCall<R>(FUNCTION_CAST<FType*>(Generate()), p1);
|
||||
}
|
||||
|
||||
template <typename R, typename P1, typename P2>
|
||||
R Call2(P1 p1, P2 p2) {
|
||||
typedef R V8_CDECL FType(P1, P2);
|
||||
VerifyParameters2<P1, P2>();
|
||||
return DoCall<R>(FUNCTION_CAST<FType*>(Generate()), p1, p2);
|
||||
}
|
||||
|
||||
template <typename R, typename P1, typename P2, typename P3>
|
||||
R Call3(P1 p1, P2 p2, P3 p3) {
|
||||
typedef R V8_CDECL FType(P1, P2, P3);
|
||||
VerifyParameters3<P1, P2, P3>();
|
||||
return DoCall<R>(FUNCTION_CAST<FType*>(Generate()), p1, p2, p3);
|
||||
}
|
||||
|
||||
template <typename R, typename P1, typename P2, typename P3, typename P4>
|
||||
R Call4(P1 p1, P2 p2, P3 p3, P4 p4) {
|
||||
typedef R V8_CDECL FType(P1, P2, P3, P4);
|
||||
VerifyParameters4<P1, P2, P3, P4>();
|
||||
return DoCall<R>(FUNCTION_CAST<FType*>(Generate()), p1, p2, p3, p4);
|
||||
}
|
||||
|
||||
template <typename R, typename C>
|
||||
friend class CallHelper2;
|
||||
Isolate* isolate_;
|
||||
};
|
||||
|
||||
|
||||
// TODO(dcarney): replace CallHelper with CallHelper2 and rename.
|
||||
template <typename R, typename C>
|
||||
class CallHelper2 {
|
||||
public:
|
||||
R Call() { return helper()->template Call0<R>(); }
|
||||
|
||||
template <typename P1>
|
||||
R Call(P1 p1) {
|
||||
return helper()->template Call1<R>(p1);
|
||||
}
|
||||
|
||||
template <typename P1, typename P2>
|
||||
R Call(P1 p1, P2 p2) {
|
||||
return helper()->template Call2<R>(p1, p2);
|
||||
}
|
||||
|
||||
template <typename P1, typename P2, typename P3>
|
||||
R Call(P1 p1, P2 p2, P3 p3) {
|
||||
return helper()->template Call3<R>(p1, p2, p3);
|
||||
}
|
||||
|
||||
template <typename P1, typename P2, typename P3, typename P4>
|
||||
R Call(P1 p1, P2 p2, P3 p3, P4 p4) {
|
||||
return helper()->template Call4<R>(p1, p2, p3, p4);
|
||||
}
|
||||
|
||||
private:
|
||||
CallHelper* helper() { return static_cast<C*>(this); }
|
||||
};
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_CCTEST_COMPILER_CALL_TESTER_H_
|
@ -1,578 +0,0 @@
|
||||
// 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 "src/v8.h"
|
||||
|
||||
#include "test/cctest/cctest.h"
|
||||
#include "test/cctest/compiler/codegen-tester.h"
|
||||
#include "test/cctest/compiler/value-helper.h"
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
|
||||
TEST(CompareWrapper) {
|
||||
// Who tests the testers?
|
||||
// If CompareWrapper is broken, then test expectations will be broken.
|
||||
RawMachineAssemblerTester<int32_t> m;
|
||||
CompareWrapper wWord32Equal(IrOpcode::kWord32Equal);
|
||||
CompareWrapper wInt32LessThan(IrOpcode::kInt32LessThan);
|
||||
CompareWrapper wInt32LessThanOrEqual(IrOpcode::kInt32LessThanOrEqual);
|
||||
CompareWrapper wUint32LessThan(IrOpcode::kUint32LessThan);
|
||||
CompareWrapper wUint32LessThanOrEqual(IrOpcode::kUint32LessThanOrEqual);
|
||||
|
||||
{
|
||||
FOR_INT32_INPUTS(pl) {
|
||||
FOR_INT32_INPUTS(pr) {
|
||||
int32_t a = *pl;
|
||||
int32_t b = *pr;
|
||||
CHECK_EQ(a == b, wWord32Equal.Int32Compare(a, b));
|
||||
CHECK_EQ(a < b, wInt32LessThan.Int32Compare(a, b));
|
||||
CHECK_EQ(a <= b, wInt32LessThanOrEqual.Int32Compare(a, b));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
FOR_UINT32_INPUTS(pl) {
|
||||
FOR_UINT32_INPUTS(pr) {
|
||||
uint32_t a = *pl;
|
||||
uint32_t b = *pr;
|
||||
CHECK_EQ(a == b, wWord32Equal.Int32Compare(a, b));
|
||||
CHECK_EQ(a < b, wUint32LessThan.Int32Compare(a, b));
|
||||
CHECK_EQ(a <= b, wUint32LessThanOrEqual.Int32Compare(a, b));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CHECK_EQ(true, wWord32Equal.Int32Compare(0, 0));
|
||||
CHECK_EQ(true, wWord32Equal.Int32Compare(257, 257));
|
||||
CHECK_EQ(true, wWord32Equal.Int32Compare(65539, 65539));
|
||||
CHECK_EQ(true, wWord32Equal.Int32Compare(-1, -1));
|
||||
CHECK_EQ(true, wWord32Equal.Int32Compare(0xffffffff, 0xffffffff));
|
||||
|
||||
CHECK_EQ(false, wWord32Equal.Int32Compare(0, 1));
|
||||
CHECK_EQ(false, wWord32Equal.Int32Compare(257, 256));
|
||||
CHECK_EQ(false, wWord32Equal.Int32Compare(65539, 65537));
|
||||
CHECK_EQ(false, wWord32Equal.Int32Compare(-1, -2));
|
||||
CHECK_EQ(false, wWord32Equal.Int32Compare(0xffffffff, 0xfffffffe));
|
||||
|
||||
CHECK_EQ(false, wInt32LessThan.Int32Compare(0, 0));
|
||||
CHECK_EQ(false, wInt32LessThan.Int32Compare(357, 357));
|
||||
CHECK_EQ(false, wInt32LessThan.Int32Compare(75539, 75539));
|
||||
CHECK_EQ(false, wInt32LessThan.Int32Compare(-1, -1));
|
||||
CHECK_EQ(false, wInt32LessThan.Int32Compare(0xffffffff, 0xffffffff));
|
||||
|
||||
CHECK_EQ(true, wInt32LessThan.Int32Compare(0, 1));
|
||||
CHECK_EQ(true, wInt32LessThan.Int32Compare(456, 457));
|
||||
CHECK_EQ(true, wInt32LessThan.Int32Compare(85537, 85539));
|
||||
CHECK_EQ(true, wInt32LessThan.Int32Compare(-2, -1));
|
||||
CHECK_EQ(true, wInt32LessThan.Int32Compare(0xfffffffe, 0xffffffff));
|
||||
|
||||
CHECK_EQ(false, wInt32LessThan.Int32Compare(1, 0));
|
||||
CHECK_EQ(false, wInt32LessThan.Int32Compare(457, 456));
|
||||
CHECK_EQ(false, wInt32LessThan.Int32Compare(85539, 85537));
|
||||
CHECK_EQ(false, wInt32LessThan.Int32Compare(-1, -2));
|
||||
CHECK_EQ(false, wInt32LessThan.Int32Compare(0xffffffff, 0xfffffffe));
|
||||
|
||||
CHECK_EQ(true, wInt32LessThanOrEqual.Int32Compare(0, 0));
|
||||
CHECK_EQ(true, wInt32LessThanOrEqual.Int32Compare(357, 357));
|
||||
CHECK_EQ(true, wInt32LessThanOrEqual.Int32Compare(75539, 75539));
|
||||
CHECK_EQ(true, wInt32LessThanOrEqual.Int32Compare(-1, -1));
|
||||
CHECK_EQ(true, wInt32LessThanOrEqual.Int32Compare(0xffffffff, 0xffffffff));
|
||||
|
||||
CHECK_EQ(true, wInt32LessThanOrEqual.Int32Compare(0, 1));
|
||||
CHECK_EQ(true, wInt32LessThanOrEqual.Int32Compare(456, 457));
|
||||
CHECK_EQ(true, wInt32LessThanOrEqual.Int32Compare(85537, 85539));
|
||||
CHECK_EQ(true, wInt32LessThanOrEqual.Int32Compare(-2, -1));
|
||||
CHECK_EQ(true, wInt32LessThanOrEqual.Int32Compare(0xfffffffe, 0xffffffff));
|
||||
|
||||
CHECK_EQ(false, wInt32LessThanOrEqual.Int32Compare(1, 0));
|
||||
CHECK_EQ(false, wInt32LessThanOrEqual.Int32Compare(457, 456));
|
||||
CHECK_EQ(false, wInt32LessThanOrEqual.Int32Compare(85539, 85537));
|
||||
CHECK_EQ(false, wInt32LessThanOrEqual.Int32Compare(-1, -2));
|
||||
CHECK_EQ(false, wInt32LessThanOrEqual.Int32Compare(0xffffffff, 0xfffffffe));
|
||||
|
||||
// Unsigned comparisons.
|
||||
CHECK_EQ(false, wUint32LessThan.Int32Compare(0, 0));
|
||||
CHECK_EQ(false, wUint32LessThan.Int32Compare(357, 357));
|
||||
CHECK_EQ(false, wUint32LessThan.Int32Compare(75539, 75539));
|
||||
CHECK_EQ(false, wUint32LessThan.Int32Compare(-1, -1));
|
||||
CHECK_EQ(false, wUint32LessThan.Int32Compare(0xffffffff, 0xffffffff));
|
||||
CHECK_EQ(false, wUint32LessThan.Int32Compare(0xffffffff, 0));
|
||||
CHECK_EQ(false, wUint32LessThan.Int32Compare(-2999, 0));
|
||||
|
||||
CHECK_EQ(true, wUint32LessThan.Int32Compare(0, 1));
|
||||
CHECK_EQ(true, wUint32LessThan.Int32Compare(456, 457));
|
||||
CHECK_EQ(true, wUint32LessThan.Int32Compare(85537, 85539));
|
||||
CHECK_EQ(true, wUint32LessThan.Int32Compare(-11, -10));
|
||||
CHECK_EQ(true, wUint32LessThan.Int32Compare(0xfffffffe, 0xffffffff));
|
||||
CHECK_EQ(true, wUint32LessThan.Int32Compare(0, 0xffffffff));
|
||||
CHECK_EQ(true, wUint32LessThan.Int32Compare(0, -2996));
|
||||
|
||||
CHECK_EQ(false, wUint32LessThan.Int32Compare(1, 0));
|
||||
CHECK_EQ(false, wUint32LessThan.Int32Compare(457, 456));
|
||||
CHECK_EQ(false, wUint32LessThan.Int32Compare(85539, 85537));
|
||||
CHECK_EQ(false, wUint32LessThan.Int32Compare(-10, -21));
|
||||
CHECK_EQ(false, wUint32LessThan.Int32Compare(0xffffffff, 0xfffffffe));
|
||||
|
||||
CHECK_EQ(true, wUint32LessThanOrEqual.Int32Compare(0, 0));
|
||||
CHECK_EQ(true, wUint32LessThanOrEqual.Int32Compare(357, 357));
|
||||
CHECK_EQ(true, wUint32LessThanOrEqual.Int32Compare(75539, 75539));
|
||||
CHECK_EQ(true, wUint32LessThanOrEqual.Int32Compare(-1, -1));
|
||||
CHECK_EQ(true, wUint32LessThanOrEqual.Int32Compare(0xffffffff, 0xffffffff));
|
||||
|
||||
CHECK_EQ(true, wUint32LessThanOrEqual.Int32Compare(0, 1));
|
||||
CHECK_EQ(true, wUint32LessThanOrEqual.Int32Compare(456, 457));
|
||||
CHECK_EQ(true, wUint32LessThanOrEqual.Int32Compare(85537, 85539));
|
||||
CHECK_EQ(true, wUint32LessThanOrEqual.Int32Compare(-300, -299));
|
||||
CHECK_EQ(true, wUint32LessThanOrEqual.Int32Compare(-300, -300));
|
||||
CHECK_EQ(true, wUint32LessThanOrEqual.Int32Compare(0xfffffffe, 0xffffffff));
|
||||
CHECK_EQ(true, wUint32LessThanOrEqual.Int32Compare(0, -2995));
|
||||
|
||||
CHECK_EQ(false, wUint32LessThanOrEqual.Int32Compare(1, 0));
|
||||
CHECK_EQ(false, wUint32LessThanOrEqual.Int32Compare(457, 456));
|
||||
CHECK_EQ(false, wUint32LessThanOrEqual.Int32Compare(85539, 85537));
|
||||
CHECK_EQ(false, wUint32LessThanOrEqual.Int32Compare(-130, -170));
|
||||
CHECK_EQ(false, wUint32LessThanOrEqual.Int32Compare(0xffffffff, 0xfffffffe));
|
||||
CHECK_EQ(false, wUint32LessThanOrEqual.Int32Compare(-2997, 0));
|
||||
|
||||
CompareWrapper wFloat64Equal(IrOpcode::kFloat64Equal);
|
||||
CompareWrapper wFloat64LessThan(IrOpcode::kFloat64LessThan);
|
||||
CompareWrapper wFloat64LessThanOrEqual(IrOpcode::kFloat64LessThanOrEqual);
|
||||
|
||||
// Check NaN handling.
|
||||
double nan = v8::base::OS::nan_value();
|
||||
double inf = V8_INFINITY;
|
||||
CHECK_EQ(false, wFloat64Equal.Float64Compare(nan, 0.0));
|
||||
CHECK_EQ(false, wFloat64Equal.Float64Compare(nan, 1.0));
|
||||
CHECK_EQ(false, wFloat64Equal.Float64Compare(nan, inf));
|
||||
CHECK_EQ(false, wFloat64Equal.Float64Compare(nan, -inf));
|
||||
CHECK_EQ(false, wFloat64Equal.Float64Compare(nan, nan));
|
||||
|
||||
CHECK_EQ(false, wFloat64Equal.Float64Compare(0.0, nan));
|
||||
CHECK_EQ(false, wFloat64Equal.Float64Compare(1.0, nan));
|
||||
CHECK_EQ(false, wFloat64Equal.Float64Compare(inf, nan));
|
||||
CHECK_EQ(false, wFloat64Equal.Float64Compare(-inf, nan));
|
||||
CHECK_EQ(false, wFloat64Equal.Float64Compare(nan, nan));
|
||||
|
||||
CHECK_EQ(false, wFloat64LessThan.Float64Compare(nan, 0.0));
|
||||
CHECK_EQ(false, wFloat64LessThan.Float64Compare(nan, 1.0));
|
||||
CHECK_EQ(false, wFloat64LessThan.Float64Compare(nan, inf));
|
||||
CHECK_EQ(false, wFloat64LessThan.Float64Compare(nan, -inf));
|
||||
CHECK_EQ(false, wFloat64LessThan.Float64Compare(nan, nan));
|
||||
|
||||
CHECK_EQ(false, wFloat64LessThan.Float64Compare(0.0, nan));
|
||||
CHECK_EQ(false, wFloat64LessThan.Float64Compare(1.0, nan));
|
||||
CHECK_EQ(false, wFloat64LessThan.Float64Compare(inf, nan));
|
||||
CHECK_EQ(false, wFloat64LessThan.Float64Compare(-inf, nan));
|
||||
CHECK_EQ(false, wFloat64LessThan.Float64Compare(nan, nan));
|
||||
|
||||
CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(nan, 0.0));
|
||||
CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(nan, 1.0));
|
||||
CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(nan, inf));
|
||||
CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(nan, -inf));
|
||||
CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(nan, nan));
|
||||
|
||||
CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(0.0, nan));
|
||||
CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(1.0, nan));
|
||||
CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(inf, nan));
|
||||
CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(-inf, nan));
|
||||
CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(nan, nan));
|
||||
|
||||
// Check inf handling.
|
||||
CHECK_EQ(false, wFloat64Equal.Float64Compare(inf, 0.0));
|
||||
CHECK_EQ(false, wFloat64Equal.Float64Compare(inf, 1.0));
|
||||
CHECK_EQ(true, wFloat64Equal.Float64Compare(inf, inf));
|
||||
CHECK_EQ(false, wFloat64Equal.Float64Compare(inf, -inf));
|
||||
|
||||
CHECK_EQ(false, wFloat64Equal.Float64Compare(0.0, inf));
|
||||
CHECK_EQ(false, wFloat64Equal.Float64Compare(1.0, inf));
|
||||
CHECK_EQ(true, wFloat64Equal.Float64Compare(inf, inf));
|
||||
CHECK_EQ(false, wFloat64Equal.Float64Compare(-inf, inf));
|
||||
|
||||
CHECK_EQ(false, wFloat64LessThan.Float64Compare(inf, 0.0));
|
||||
CHECK_EQ(false, wFloat64LessThan.Float64Compare(inf, 1.0));
|
||||
CHECK_EQ(false, wFloat64LessThan.Float64Compare(inf, inf));
|
||||
CHECK_EQ(false, wFloat64LessThan.Float64Compare(inf, -inf));
|
||||
|
||||
CHECK_EQ(true, wFloat64LessThan.Float64Compare(0.0, inf));
|
||||
CHECK_EQ(true, wFloat64LessThan.Float64Compare(1.0, inf));
|
||||
CHECK_EQ(false, wFloat64LessThan.Float64Compare(inf, inf));
|
||||
CHECK_EQ(true, wFloat64LessThan.Float64Compare(-inf, inf));
|
||||
|
||||
CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(inf, 0.0));
|
||||
CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(inf, 1.0));
|
||||
CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(inf, inf));
|
||||
CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(inf, -inf));
|
||||
|
||||
CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(0.0, inf));
|
||||
CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(1.0, inf));
|
||||
CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(inf, inf));
|
||||
CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(-inf, inf));
|
||||
|
||||
// Check -inf handling.
|
||||
CHECK_EQ(false, wFloat64Equal.Float64Compare(-inf, 0.0));
|
||||
CHECK_EQ(false, wFloat64Equal.Float64Compare(-inf, 1.0));
|
||||
CHECK_EQ(false, wFloat64Equal.Float64Compare(-inf, inf));
|
||||
CHECK_EQ(true, wFloat64Equal.Float64Compare(-inf, -inf));
|
||||
|
||||
CHECK_EQ(false, wFloat64Equal.Float64Compare(0.0, -inf));
|
||||
CHECK_EQ(false, wFloat64Equal.Float64Compare(1.0, -inf));
|
||||
CHECK_EQ(false, wFloat64Equal.Float64Compare(inf, -inf));
|
||||
CHECK_EQ(true, wFloat64Equal.Float64Compare(-inf, -inf));
|
||||
|
||||
CHECK_EQ(true, wFloat64LessThan.Float64Compare(-inf, 0.0));
|
||||
CHECK_EQ(true, wFloat64LessThan.Float64Compare(-inf, 1.0));
|
||||
CHECK_EQ(true, wFloat64LessThan.Float64Compare(-inf, inf));
|
||||
CHECK_EQ(false, wFloat64LessThan.Float64Compare(-inf, -inf));
|
||||
|
||||
CHECK_EQ(false, wFloat64LessThan.Float64Compare(0.0, -inf));
|
||||
CHECK_EQ(false, wFloat64LessThan.Float64Compare(1.0, -inf));
|
||||
CHECK_EQ(false, wFloat64LessThan.Float64Compare(inf, -inf));
|
||||
CHECK_EQ(false, wFloat64LessThan.Float64Compare(-inf, -inf));
|
||||
|
||||
CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(-inf, 0.0));
|
||||
CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(-inf, 1.0));
|
||||
CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(-inf, inf));
|
||||
CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(-inf, -inf));
|
||||
|
||||
CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(0.0, -inf));
|
||||
CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(1.0, -inf));
|
||||
CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(inf, -inf));
|
||||
CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(-inf, -inf));
|
||||
|
||||
// Check basic values.
|
||||
CHECK_EQ(true, wFloat64Equal.Float64Compare(0, 0));
|
||||
CHECK_EQ(true, wFloat64Equal.Float64Compare(257.1, 257.1));
|
||||
CHECK_EQ(true, wFloat64Equal.Float64Compare(65539.1, 65539.1));
|
||||
CHECK_EQ(true, wFloat64Equal.Float64Compare(-1.1, -1.1));
|
||||
|
||||
CHECK_EQ(false, wFloat64Equal.Float64Compare(0, 1));
|
||||
CHECK_EQ(false, wFloat64Equal.Float64Compare(257.2, 256.2));
|
||||
CHECK_EQ(false, wFloat64Equal.Float64Compare(65539.2, 65537.2));
|
||||
CHECK_EQ(false, wFloat64Equal.Float64Compare(-1.2, -2.2));
|
||||
|
||||
CHECK_EQ(false, wFloat64LessThan.Float64Compare(0, 0));
|
||||
CHECK_EQ(false, wFloat64LessThan.Float64Compare(357.3, 357.3));
|
||||
CHECK_EQ(false, wFloat64LessThan.Float64Compare(75539.3, 75539.3));
|
||||
CHECK_EQ(false, wFloat64LessThan.Float64Compare(-1.3, -1.3));
|
||||
|
||||
CHECK_EQ(true, wFloat64LessThan.Float64Compare(0, 1));
|
||||
CHECK_EQ(true, wFloat64LessThan.Float64Compare(456.4, 457.4));
|
||||
CHECK_EQ(true, wFloat64LessThan.Float64Compare(85537.4, 85539.4));
|
||||
CHECK_EQ(true, wFloat64LessThan.Float64Compare(-2.4, -1.4));
|
||||
|
||||
CHECK_EQ(false, wFloat64LessThan.Float64Compare(1, 0));
|
||||
CHECK_EQ(false, wFloat64LessThan.Float64Compare(457.5, 456.5));
|
||||
CHECK_EQ(false, wFloat64LessThan.Float64Compare(85539.5, 85537.5));
|
||||
CHECK_EQ(false, wFloat64LessThan.Float64Compare(-1.5, -2.5));
|
||||
|
||||
CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(0, 0));
|
||||
CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(357.6, 357.6));
|
||||
CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(75539.6, 75539.6));
|
||||
CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(-1.6, -1.6));
|
||||
|
||||
CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(0, 1));
|
||||
CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(456.7, 457.7));
|
||||
CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(85537.7, 85539.7));
|
||||
CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(-2.7, -1.7));
|
||||
|
||||
CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(1, 0));
|
||||
CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(457.8, 456.8));
|
||||
CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(85539.8, 85537.8));
|
||||
CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(-1.8, -2.8));
|
||||
}
|
||||
|
||||
|
||||
void Int32BinopInputShapeTester::TestAllInputShapes() {
|
||||
std::vector<int32_t> inputs = ValueHelper::int32_vector();
|
||||
int num_int_inputs = static_cast<int>(inputs.size());
|
||||
if (num_int_inputs > 16) num_int_inputs = 16; // limit to 16 inputs
|
||||
|
||||
for (int i = -2; i < num_int_inputs; i++) { // for all left shapes
|
||||
for (int j = -2; j < num_int_inputs; j++) { // for all right shapes
|
||||
if (i >= 0 && j >= 0) break; // No constant/constant combos
|
||||
RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32);
|
||||
Node* p0 = m.Parameter(0);
|
||||
Node* p1 = m.Parameter(1);
|
||||
Node* n0;
|
||||
Node* n1;
|
||||
|
||||
// left = Parameter | Load | Constant
|
||||
if (i == -2) {
|
||||
n0 = p0;
|
||||
} else if (i == -1) {
|
||||
n0 = m.LoadFromPointer(&input_a, kMachineWord32);
|
||||
} else {
|
||||
n0 = m.Int32Constant(inputs[i]);
|
||||
}
|
||||
|
||||
// right = Parameter | Load | Constant
|
||||
if (j == -2) {
|
||||
n1 = p1;
|
||||
} else if (j == -1) {
|
||||
n1 = m.LoadFromPointer(&input_b, kMachineWord32);
|
||||
} else {
|
||||
n1 = m.Int32Constant(inputs[j]);
|
||||
}
|
||||
|
||||
gen->gen(&m, n0, n1);
|
||||
|
||||
if (false) printf("Int32BinopInputShapeTester i=%d, j=%d\n", i, j);
|
||||
if (i >= 0) {
|
||||
input_a = inputs[i];
|
||||
RunRight(&m);
|
||||
} else if (j >= 0) {
|
||||
input_b = inputs[j];
|
||||
RunLeft(&m);
|
||||
} else {
|
||||
Run(&m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Int32BinopInputShapeTester::Run(RawMachineAssemblerTester<int32_t>* m) {
|
||||
FOR_INT32_INPUTS(pl) {
|
||||
FOR_INT32_INPUTS(pr) {
|
||||
input_a = *pl;
|
||||
input_b = *pr;
|
||||
int32_t expect = gen->expected(input_a, input_b);
|
||||
if (false) printf(" cmp(a=%d, b=%d) ?== %d\n", input_a, input_b, expect);
|
||||
CHECK_EQ(expect, m->Call(input_a, input_b));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Int32BinopInputShapeTester::RunLeft(
|
||||
RawMachineAssemblerTester<int32_t>* m) {
|
||||
FOR_UINT32_INPUTS(i) {
|
||||
input_a = *i;
|
||||
int32_t expect = gen->expected(input_a, input_b);
|
||||
if (false) printf(" cmp(a=%d, b=%d) ?== %d\n", input_a, input_b, expect);
|
||||
CHECK_EQ(expect, m->Call(input_a, input_b));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Int32BinopInputShapeTester::RunRight(
|
||||
RawMachineAssemblerTester<int32_t>* m) {
|
||||
FOR_UINT32_INPUTS(i) {
|
||||
input_b = *i;
|
||||
int32_t expect = gen->expected(input_a, input_b);
|
||||
if (false) printf(" cmp(a=%d, b=%d) ?== %d\n", input_a, input_b, expect);
|
||||
CHECK_EQ(expect, m->Call(input_a, input_b));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(ParametersEqual) {
|
||||
RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32);
|
||||
Node* p1 = m.Parameter(1);
|
||||
CHECK_NE(NULL, p1);
|
||||
Node* p0 = m.Parameter(0);
|
||||
CHECK_NE(NULL, p0);
|
||||
CHECK_EQ(p0, m.Parameter(0));
|
||||
CHECK_EQ(p1, m.Parameter(1));
|
||||
}
|
||||
|
||||
|
||||
#if V8_TURBOFAN_TARGET
|
||||
|
||||
void RunSmiConstant(int32_t v) {
|
||||
// TODO(dcarney): on x64 Smis are generated with the SmiConstantRegister
|
||||
#if !V8_TARGET_ARCH_X64
|
||||
if (Smi::IsValid(v)) {
|
||||
RawMachineAssemblerTester<Object*> m;
|
||||
m.Return(m.NumberConstant(v));
|
||||
CHECK_EQ(Smi::FromInt(v), m.Call());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void RunNumberConstant(double v) {
|
||||
RawMachineAssemblerTester<Object*> m;
|
||||
#if V8_TARGET_ARCH_X64
|
||||
// TODO(dcarney): on x64 Smis are generated with the SmiConstantRegister
|
||||
Handle<Object> number = m.isolate()->factory()->NewNumber(v);
|
||||
if (number->IsSmi()) return;
|
||||
#endif
|
||||
m.Return(m.NumberConstant(v));
|
||||
Object* result = m.Call();
|
||||
m.CheckNumber(v, result);
|
||||
}
|
||||
|
||||
|
||||
TEST(RunEmpty) {
|
||||
RawMachineAssemblerTester<int32_t> m;
|
||||
m.Return(m.Int32Constant(0));
|
||||
CHECK_EQ(0, m.Call());
|
||||
}
|
||||
|
||||
|
||||
TEST(RunInt32Constants) {
|
||||
FOR_INT32_INPUTS(i) {
|
||||
RawMachineAssemblerTester<int32_t> m;
|
||||
m.Return(m.Int32Constant(*i));
|
||||
CHECK_EQ(*i, m.Call());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(RunSmiConstants) {
|
||||
for (int32_t i = 1; i < Smi::kMaxValue && i != 0; i = i << 1) {
|
||||
RunSmiConstant(i);
|
||||
RunSmiConstant(3 * i);
|
||||
RunSmiConstant(5 * i);
|
||||
RunSmiConstant(-i);
|
||||
RunSmiConstant(i | 1);
|
||||
RunSmiConstant(i | 3);
|
||||
}
|
||||
RunSmiConstant(Smi::kMaxValue);
|
||||
RunSmiConstant(Smi::kMaxValue - 1);
|
||||
RunSmiConstant(Smi::kMinValue);
|
||||
RunSmiConstant(Smi::kMinValue + 1);
|
||||
|
||||
FOR_INT32_INPUTS(i) { RunSmiConstant(*i); }
|
||||
}
|
||||
|
||||
|
||||
TEST(RunNumberConstants) {
|
||||
{
|
||||
FOR_FLOAT64_INPUTS(i) { RunNumberConstant(*i); }
|
||||
}
|
||||
{
|
||||
FOR_INT32_INPUTS(i) { RunNumberConstant(*i); }
|
||||
}
|
||||
|
||||
for (int32_t i = 1; i < Smi::kMaxValue && i != 0; i = i << 1) {
|
||||
RunNumberConstant(i);
|
||||
RunNumberConstant(-i);
|
||||
RunNumberConstant(i | 1);
|
||||
RunNumberConstant(i | 3);
|
||||
}
|
||||
RunNumberConstant(Smi::kMaxValue);
|
||||
RunNumberConstant(Smi::kMaxValue - 1);
|
||||
RunNumberConstant(Smi::kMinValue);
|
||||
RunNumberConstant(Smi::kMinValue + 1);
|
||||
}
|
||||
|
||||
|
||||
TEST(RunEmptyString) {
|
||||
RawMachineAssemblerTester<Object*> m;
|
||||
m.Return(m.StringConstant("empty"));
|
||||
m.CheckString("empty", m.Call());
|
||||
}
|
||||
|
||||
|
||||
TEST(RunHeapConstant) {
|
||||
RawMachineAssemblerTester<Object*> m;
|
||||
m.Return(m.StringConstant("empty"));
|
||||
m.CheckString("empty", m.Call());
|
||||
}
|
||||
|
||||
|
||||
TEST(RunHeapNumberConstant) {
|
||||
RawMachineAssemblerTester<Object*> m;
|
||||
Handle<Object> number = m.isolate()->factory()->NewHeapNumber(100.5);
|
||||
m.Return(m.HeapConstant(number));
|
||||
Object* result = m.Call();
|
||||
CHECK_EQ(result, *number);
|
||||
}
|
||||
|
||||
|
||||
TEST(RunParam1) {
|
||||
RawMachineAssemblerTester<int32_t> m(kMachineWord32);
|
||||
m.Return(m.Parameter(0));
|
||||
|
||||
FOR_INT32_INPUTS(i) {
|
||||
int32_t result = m.Call(*i);
|
||||
CHECK_EQ(*i, result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(RunParam2_1) {
|
||||
RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32);
|
||||
Node* p0 = m.Parameter(0);
|
||||
Node* p1 = m.Parameter(1);
|
||||
m.Return(p0);
|
||||
USE(p1);
|
||||
|
||||
FOR_INT32_INPUTS(i) {
|
||||
int32_t result = m.Call(*i, -9999);
|
||||
CHECK_EQ(*i, result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(RunParam2_2) {
|
||||
RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32);
|
||||
Node* p0 = m.Parameter(0);
|
||||
Node* p1 = m.Parameter(1);
|
||||
m.Return(p1);
|
||||
USE(p0);
|
||||
|
||||
FOR_INT32_INPUTS(i) {
|
||||
int32_t result = m.Call(-7777, *i);
|
||||
CHECK_EQ(*i, result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(RunParam3) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32,
|
||||
kMachineWord32);
|
||||
Node* nodes[] = {m.Parameter(0), m.Parameter(1), m.Parameter(2)};
|
||||
m.Return(nodes[i]);
|
||||
|
||||
int p[] = {-99, -77, -88};
|
||||
FOR_INT32_INPUTS(j) {
|
||||
p[i] = *j;
|
||||
int32_t result = m.Call(p[0], p[1], p[2]);
|
||||
CHECK_EQ(*j, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(RunBinopTester) {
|
||||
{
|
||||
RawMachineAssemblerTester<int32_t> m;
|
||||
Int32BinopTester bt(&m);
|
||||
bt.AddReturn(bt.param0);
|
||||
|
||||
FOR_INT32_INPUTS(i) { CHECK_EQ(*i, bt.call(*i, 777)); }
|
||||
}
|
||||
|
||||
{
|
||||
RawMachineAssemblerTester<int32_t> m;
|
||||
Int32BinopTester bt(&m);
|
||||
bt.AddReturn(bt.param1);
|
||||
|
||||
FOR_INT32_INPUTS(i) { CHECK_EQ(*i, bt.call(666, *i)); }
|
||||
}
|
||||
|
||||
{
|
||||
RawMachineAssemblerTester<int32_t> m;
|
||||
Float64BinopTester bt(&m);
|
||||
bt.AddReturn(bt.param0);
|
||||
|
||||
FOR_FLOAT64_INPUTS(i) { CHECK_EQ(*i, bt.call(*i, 9.0)); }
|
||||
}
|
||||
|
||||
{
|
||||
RawMachineAssemblerTester<int32_t> m;
|
||||
Float64BinopTester bt(&m);
|
||||
bt.AddReturn(bt.param1);
|
||||
|
||||
FOR_FLOAT64_INPUTS(i) { CHECK_EQ(*i, bt.call(-11.25, *i)); }
|
||||
}
|
||||
}
|
||||
|
||||
#endif // V8_TURBOFAN_TARGET
|
@ -1,323 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#ifndef V8_CCTEST_COMPILER_CODEGEN_TESTER_H_
|
||||
#define V8_CCTEST_COMPILER_CODEGEN_TESTER_H_
|
||||
|
||||
#include "src/v8.h"
|
||||
|
||||
#include "src/compiler/pipeline.h"
|
||||
#include "src/compiler/raw-machine-assembler.h"
|
||||
#include "src/compiler/structured-machine-assembler.h"
|
||||
#include "src/simulator.h"
|
||||
#include "test/cctest/compiler/call-tester.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
template <typename MachineAssembler>
|
||||
class MachineAssemblerTester : public HandleAndZoneScope,
|
||||
public CallHelper,
|
||||
public MachineAssembler {
|
||||
public:
|
||||
MachineAssemblerTester(MachineRepresentation return_type,
|
||||
MachineRepresentation p0, MachineRepresentation p1,
|
||||
MachineRepresentation p2, MachineRepresentation p3,
|
||||
MachineRepresentation p4)
|
||||
: HandleAndZoneScope(),
|
||||
CallHelper(main_isolate()),
|
||||
MachineAssembler(new (main_zone()) Graph(main_zone()),
|
||||
ToCallDescriptorBuilder(main_zone(), return_type, p0,
|
||||
p1, p2, p3, p4),
|
||||
MachineOperatorBuilder::pointer_rep()) {}
|
||||
|
||||
Node* LoadFromPointer(void* address, MachineRepresentation rep,
|
||||
int32_t offset = 0) {
|
||||
return this->Load(rep, this->PointerConstant(address),
|
||||
this->Int32Constant(offset));
|
||||
}
|
||||
|
||||
void StoreToPointer(void* address, MachineRepresentation rep, Node* node) {
|
||||
this->Store(rep, this->PointerConstant(address), node);
|
||||
}
|
||||
|
||||
Node* StringConstant(const char* string) {
|
||||
return this->HeapConstant(
|
||||
this->isolate()->factory()->InternalizeUtf8String(string));
|
||||
}
|
||||
|
||||
void CheckNumber(double expected, Object* number) {
|
||||
CHECK(this->isolate()->factory()->NewNumber(expected)->SameValue(number));
|
||||
}
|
||||
|
||||
void CheckString(const char* expected, Object* string) {
|
||||
CHECK(
|
||||
this->isolate()->factory()->InternalizeUtf8String(expected)->SameValue(
|
||||
string));
|
||||
}
|
||||
|
||||
void GenerateCode() { Generate(); }
|
||||
|
||||
protected:
|
||||
virtual void VerifyParameters(int parameter_count,
|
||||
MachineRepresentation* parameter_types) {
|
||||
CHECK_EQ(this->parameter_count(), parameter_count);
|
||||
const MachineRepresentation* expected_types = this->parameter_types();
|
||||
for (int i = 0; i < parameter_count; i++) {
|
||||
CHECK_EQ(expected_types[i], parameter_types[i]);
|
||||
}
|
||||
}
|
||||
|
||||
virtual byte* Generate() {
|
||||
if (code_.is_null()) {
|
||||
Schedule* schedule = this->Export();
|
||||
CallDescriptor* call_descriptor = this->call_descriptor();
|
||||
Graph* graph = this->graph();
|
||||
CompilationInfo info(graph->zone()->isolate(), graph->zone());
|
||||
Linkage linkage(&info, call_descriptor);
|
||||
Pipeline pipeline(&info);
|
||||
code_ = pipeline.GenerateCodeForMachineGraph(&linkage, graph, schedule);
|
||||
}
|
||||
return this->code_.ToHandleChecked()->entry();
|
||||
}
|
||||
|
||||
private:
|
||||
MaybeHandle<Code> code_;
|
||||
};
|
||||
|
||||
|
||||
template <typename ReturnType>
|
||||
class RawMachineAssemblerTester
|
||||
: public MachineAssemblerTester<RawMachineAssembler>,
|
||||
public CallHelper2<ReturnType, RawMachineAssemblerTester<ReturnType> > {
|
||||
public:
|
||||
RawMachineAssemblerTester(MachineRepresentation p0 = kMachineLast,
|
||||
MachineRepresentation p1 = kMachineLast,
|
||||
MachineRepresentation p2 = kMachineLast,
|
||||
MachineRepresentation p3 = kMachineLast,
|
||||
MachineRepresentation p4 = kMachineLast)
|
||||
: MachineAssemblerTester(ReturnValueTraits<ReturnType>::Representation(),
|
||||
p0, p1, p2, p3, p4) {}
|
||||
};
|
||||
|
||||
|
||||
template <typename ReturnType>
|
||||
class StructuredMachineAssemblerTester
|
||||
: public MachineAssemblerTester<StructuredMachineAssembler>,
|
||||
public CallHelper2<ReturnType,
|
||||
StructuredMachineAssemblerTester<ReturnType> > {
|
||||
public:
|
||||
StructuredMachineAssemblerTester(MachineRepresentation p0 = kMachineLast,
|
||||
MachineRepresentation p1 = kMachineLast,
|
||||
MachineRepresentation p2 = kMachineLast,
|
||||
MachineRepresentation p3 = kMachineLast,
|
||||
MachineRepresentation p4 = kMachineLast)
|
||||
: MachineAssemblerTester(ReturnValueTraits<ReturnType>::Representation(),
|
||||
p0, p1, p2, p3, p4) {}
|
||||
};
|
||||
|
||||
|
||||
static const bool USE_RESULT_BUFFER = true;
|
||||
static const bool USE_RETURN_REGISTER = false;
|
||||
|
||||
// TODO(titzer): use the C-style calling convention, or any register-based
|
||||
// calling convention for binop tests.
|
||||
template <typename CType, MachineRepresentation rep, bool use_result_buffer>
|
||||
class BinopTester {
|
||||
public:
|
||||
static const int32_t CHECK_VALUE = 0x99BEEDCE;
|
||||
|
||||
explicit BinopTester(RawMachineAssemblerTester<int32_t>* tester)
|
||||
: T(tester),
|
||||
param0(T->LoadFromPointer(&p0, rep)),
|
||||
param1(T->LoadFromPointer(&p1, rep)),
|
||||
p0(static_cast<CType>(0)),
|
||||
p1(static_cast<CType>(0)),
|
||||
result(static_cast<CType>(0)) {}
|
||||
|
||||
RawMachineAssemblerTester<int32_t>* T;
|
||||
Node* param0;
|
||||
Node* param1;
|
||||
|
||||
CType call(CType a0, CType a1) {
|
||||
p0 = a0;
|
||||
p1 = a1;
|
||||
if (use_result_buffer) {
|
||||
CHECK_EQ(CHECK_VALUE, T->Call());
|
||||
return result;
|
||||
} else {
|
||||
return T->Call();
|
||||
}
|
||||
}
|
||||
|
||||
void AddReturn(Node* val) {
|
||||
if (use_result_buffer) {
|
||||
T->Store(rep, T->PointerConstant(&result), T->Int32Constant(0), val);
|
||||
T->Return(T->Int32Constant(CHECK_VALUE));
|
||||
} else {
|
||||
T->Return(val);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
CType p0;
|
||||
CType p1;
|
||||
CType result;
|
||||
};
|
||||
|
||||
|
||||
// A helper class for testing code sequences that take two int parameters and
|
||||
// return an int value.
|
||||
class Int32BinopTester
|
||||
: public BinopTester<int32_t, kMachineWord32, USE_RETURN_REGISTER> {
|
||||
public:
|
||||
explicit Int32BinopTester(RawMachineAssemblerTester<int32_t>* tester)
|
||||
: BinopTester<int32_t, kMachineWord32, USE_RETURN_REGISTER>(tester) {}
|
||||
|
||||
int32_t call(uint32_t a0, uint32_t a1) {
|
||||
p0 = static_cast<int32_t>(a0);
|
||||
p1 = static_cast<int32_t>(a1);
|
||||
return T->Call();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// A helper class for testing code sequences that take two double parameters and
|
||||
// return a double value.
|
||||
// TODO(titzer): figure out how to return doubles correctly on ia32.
|
||||
class Float64BinopTester
|
||||
: public BinopTester<double, kMachineFloat64, USE_RESULT_BUFFER> {
|
||||
public:
|
||||
explicit Float64BinopTester(RawMachineAssemblerTester<int32_t>* tester)
|
||||
: BinopTester<double, kMachineFloat64, USE_RESULT_BUFFER>(tester) {}
|
||||
};
|
||||
|
||||
|
||||
// A helper class for testing code sequences that take two pointer parameters
|
||||
// and return a pointer value.
|
||||
// TODO(titzer): pick word size of pointers based on V8_TARGET.
|
||||
template <typename Type>
|
||||
class PointerBinopTester
|
||||
: public BinopTester<Type*, kMachineWord32, USE_RETURN_REGISTER> {
|
||||
public:
|
||||
explicit PointerBinopTester(RawMachineAssemblerTester<int32_t>* tester)
|
||||
: BinopTester<Type*, kMachineWord32, USE_RETURN_REGISTER>(tester) {}
|
||||
};
|
||||
|
||||
|
||||
// A helper class for testing code sequences that take two tagged parameters and
|
||||
// return a tagged value.
|
||||
template <typename Type>
|
||||
class TaggedBinopTester
|
||||
: public BinopTester<Type*, kMachineTagged, USE_RETURN_REGISTER> {
|
||||
public:
|
||||
explicit TaggedBinopTester(RawMachineAssemblerTester<int32_t>* tester)
|
||||
: BinopTester<Type*, kMachineTagged, USE_RETURN_REGISTER>(tester) {}
|
||||
};
|
||||
|
||||
// A helper class for testing compares. Wraps a machine opcode and provides
|
||||
// evaluation routines and the operators.
|
||||
class CompareWrapper {
|
||||
public:
|
||||
explicit CompareWrapper(IrOpcode::Value op) : opcode(op) {}
|
||||
|
||||
Node* MakeNode(RawMachineAssemblerTester<int32_t>* m, Node* a, Node* b) {
|
||||
return m->NewNode(op(m->machine()), a, b);
|
||||
}
|
||||
|
||||
Operator* op(MachineOperatorBuilder* machine) {
|
||||
switch (opcode) {
|
||||
case IrOpcode::kWord32Equal:
|
||||
return machine->Word32Equal();
|
||||
case IrOpcode::kInt32LessThan:
|
||||
return machine->Int32LessThan();
|
||||
case IrOpcode::kInt32LessThanOrEqual:
|
||||
return machine->Int32LessThanOrEqual();
|
||||
case IrOpcode::kUint32LessThan:
|
||||
return machine->Uint32LessThan();
|
||||
case IrOpcode::kUint32LessThanOrEqual:
|
||||
return machine->Uint32LessThanOrEqual();
|
||||
case IrOpcode::kFloat64Equal:
|
||||
return machine->Float64Equal();
|
||||
case IrOpcode::kFloat64LessThan:
|
||||
return machine->Float64LessThan();
|
||||
case IrOpcode::kFloat64LessThanOrEqual:
|
||||
return machine->Float64LessThanOrEqual();
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool Int32Compare(int32_t a, int32_t b) {
|
||||
switch (opcode) {
|
||||
case IrOpcode::kWord32Equal:
|
||||
return a == b;
|
||||
case IrOpcode::kInt32LessThan:
|
||||
return a < b;
|
||||
case IrOpcode::kInt32LessThanOrEqual:
|
||||
return a <= b;
|
||||
case IrOpcode::kUint32LessThan:
|
||||
return static_cast<uint32_t>(a) < static_cast<uint32_t>(b);
|
||||
case IrOpcode::kUint32LessThanOrEqual:
|
||||
return static_cast<uint32_t>(a) <= static_cast<uint32_t>(b);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Float64Compare(double a, double b) {
|
||||
switch (opcode) {
|
||||
case IrOpcode::kFloat64Equal:
|
||||
return a == b;
|
||||
case IrOpcode::kFloat64LessThan:
|
||||
return a < b;
|
||||
case IrOpcode::kFloat64LessThanOrEqual:
|
||||
return a <= b;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
IrOpcode::Value opcode;
|
||||
};
|
||||
|
||||
|
||||
// A small closure class to generate code for a function of two inputs that
|
||||
// produces a single output so that it can be used in many different contexts.
|
||||
// The {expected()} method should compute the expected output for a given
|
||||
// pair of inputs.
|
||||
template <typename T>
|
||||
class BinopGen {
|
||||
public:
|
||||
virtual void gen(RawMachineAssemblerTester<int32_t>* m, Node* a, Node* b) = 0;
|
||||
virtual T expected(T a, T b) = 0;
|
||||
virtual ~BinopGen() {}
|
||||
};
|
||||
|
||||
// A helper class to generate various combination of input shape combinations
|
||||
// and run the generated code to ensure it produces the correct results.
|
||||
class Int32BinopInputShapeTester {
|
||||
public:
|
||||
explicit Int32BinopInputShapeTester(BinopGen<int32_t>* g) : gen(g) {}
|
||||
|
||||
void TestAllInputShapes();
|
||||
|
||||
private:
|
||||
BinopGen<int32_t>* gen;
|
||||
int32_t input_a;
|
||||
int32_t input_b;
|
||||
|
||||
void Run(RawMachineAssemblerTester<int32_t>* m);
|
||||
void RunLeft(RawMachineAssemblerTester<int32_t>* m);
|
||||
void RunRight(RawMachineAssemblerTester<int32_t>* m);
|
||||
};
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_CCTEST_COMPILER_CODEGEN_TESTER_H_
|
@ -1,194 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#ifndef V8_CCTEST_COMPILER_FUNCTION_TESTER_H_
|
||||
#define V8_CCTEST_COMPILER_FUNCTION_TESTER_H_
|
||||
|
||||
#include "src/v8.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
|
||||
#include "src/compiler.h"
|
||||
#include "src/compiler/pipeline.h"
|
||||
#include "src/execution.h"
|
||||
#include "src/full-codegen.h"
|
||||
#include "src/handles.h"
|
||||
#include "src/objects-inl.h"
|
||||
#include "src/parser.h"
|
||||
#include "src/rewriter.h"
|
||||
#include "src/scopes.h"
|
||||
|
||||
#define USE_CRANKSHAFT 0
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
class FunctionTester : public InitializedHandleScope {
|
||||
public:
|
||||
explicit FunctionTester(const char* source)
|
||||
: isolate(main_isolate()),
|
||||
function((FLAG_allow_natives_syntax = true, NewFunction(source))) {
|
||||
Compile(function);
|
||||
}
|
||||
|
||||
Isolate* isolate;
|
||||
Handle<JSFunction> function;
|
||||
|
||||
Handle<JSFunction> Compile(Handle<JSFunction> function) {
|
||||
#if V8_TURBOFAN_TARGET
|
||||
CompilationInfoWithZone info(function);
|
||||
|
||||
CHECK(Parser::Parse(&info));
|
||||
StrictMode strict_mode = info.function()->strict_mode();
|
||||
info.SetStrictMode(strict_mode);
|
||||
info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code()));
|
||||
CHECK(Rewriter::Rewrite(&info));
|
||||
CHECK(Scope::Analyze(&info));
|
||||
CHECK_NE(NULL, info.scope());
|
||||
|
||||
EnsureDeoptimizationSupport(&info);
|
||||
|
||||
Pipeline pipeline(&info);
|
||||
Handle<Code> code = pipeline.GenerateCode();
|
||||
|
||||
CHECK(!code.is_null());
|
||||
function->ReplaceCode(*code);
|
||||
#elif USE_CRANKSHAFT
|
||||
Handle<Code> unoptimized = Handle<Code>(function->code());
|
||||
Handle<Code> code = Compiler::GetOptimizedCode(function, unoptimized,
|
||||
Compiler::NOT_CONCURRENT);
|
||||
CHECK(!code.is_null());
|
||||
#if ENABLE_DISASSEMBLER
|
||||
if (FLAG_print_opt_code) {
|
||||
CodeTracer::Scope tracing_scope(isolate->GetCodeTracer());
|
||||
code->Disassemble("test code", tracing_scope.file());
|
||||
}
|
||||
#endif
|
||||
function->ReplaceCode(*code);
|
||||
#endif
|
||||
return function;
|
||||
}
|
||||
|
||||
static void EnsureDeoptimizationSupport(CompilationInfo* info) {
|
||||
bool should_recompile = !info->shared_info()->has_deoptimization_support();
|
||||
if (should_recompile) {
|
||||
CompilationInfoWithZone unoptimized(info->shared_info());
|
||||
// Note that we use the same AST that we will use for generating the
|
||||
// optimized code.
|
||||
unoptimized.SetFunction(info->function());
|
||||
unoptimized.PrepareForCompilation(info->scope());
|
||||
unoptimized.SetContext(info->context());
|
||||
if (should_recompile) unoptimized.EnableDeoptimizationSupport();
|
||||
bool succeeded = FullCodeGenerator::MakeCode(&unoptimized);
|
||||
CHECK(succeeded);
|
||||
Handle<SharedFunctionInfo> shared = info->shared_info();
|
||||
shared->EnableDeoptimizationSupport(*unoptimized.code());
|
||||
}
|
||||
}
|
||||
|
||||
MaybeHandle<Object> Call(Handle<Object> a, Handle<Object> b) {
|
||||
Handle<Object> args[] = {a, b};
|
||||
return Execution::Call(isolate, function, undefined(), 2, args, false);
|
||||
}
|
||||
|
||||
void CheckThrows(Handle<Object> a, Handle<Object> b) {
|
||||
TryCatch try_catch;
|
||||
MaybeHandle<Object> no_result = Call(a, b);
|
||||
CHECK(isolate->has_pending_exception());
|
||||
CHECK(try_catch.HasCaught());
|
||||
CHECK(no_result.is_null());
|
||||
// TODO(mstarzinger): Temporary workaround for issue chromium:362388.
|
||||
isolate->OptionalRescheduleException(true);
|
||||
}
|
||||
|
||||
v8::Handle<v8::Message> CheckThrowsReturnMessage(Handle<Object> a,
|
||||
Handle<Object> b) {
|
||||
TryCatch try_catch;
|
||||
MaybeHandle<Object> no_result = Call(a, b);
|
||||
CHECK(isolate->has_pending_exception());
|
||||
CHECK(try_catch.HasCaught());
|
||||
CHECK(no_result.is_null());
|
||||
// TODO(mstarzinger): Calling OptionalRescheduleException is a dirty hack,
|
||||
// it's the only way to make Message() not to assert because an external
|
||||
// exception has been caught by the try_catch.
|
||||
isolate->OptionalRescheduleException(true);
|
||||
return try_catch.Message();
|
||||
}
|
||||
|
||||
void CheckCall(Handle<Object> expected, Handle<Object> a, Handle<Object> b) {
|
||||
Handle<Object> result = Call(a, b).ToHandleChecked();
|
||||
CHECK(expected->SameValue(*result));
|
||||
}
|
||||
|
||||
void CheckCall(Handle<Object> expected, Handle<Object> a) {
|
||||
CheckCall(expected, a, undefined());
|
||||
}
|
||||
|
||||
void CheckCall(Handle<Object> expected) {
|
||||
CheckCall(expected, undefined(), undefined());
|
||||
}
|
||||
|
||||
void CheckCall(double expected, double a, double b) {
|
||||
CheckCall(Val(expected), Val(a), Val(b));
|
||||
}
|
||||
|
||||
void CheckTrue(Handle<Object> a, Handle<Object> b) {
|
||||
CheckCall(true_value(), a, b);
|
||||
}
|
||||
|
||||
void CheckTrue(Handle<Object> a) { CheckCall(true_value(), a, undefined()); }
|
||||
|
||||
void CheckTrue(double a, double b) {
|
||||
CheckCall(true_value(), Val(a), Val(b));
|
||||
}
|
||||
|
||||
void CheckFalse(Handle<Object> a, Handle<Object> b) {
|
||||
CheckCall(false_value(), a, b);
|
||||
}
|
||||
|
||||
void CheckFalse(Handle<Object> a) {
|
||||
CheckCall(false_value(), a, undefined());
|
||||
}
|
||||
|
||||
void CheckFalse(double a, double b) {
|
||||
CheckCall(false_value(), Val(a), Val(b));
|
||||
}
|
||||
|
||||
Handle<JSFunction> NewFunction(const char* source) {
|
||||
return v8::Utils::OpenHandle(
|
||||
*v8::Handle<v8::Function>::Cast(CompileRun(source)));
|
||||
}
|
||||
|
||||
Handle<JSObject> NewObject(const char* source) {
|
||||
return v8::Utils::OpenHandle(
|
||||
*v8::Handle<v8::Object>::Cast(CompileRun(source)));
|
||||
}
|
||||
|
||||
Handle<String> Val(const char* string) {
|
||||
return isolate->factory()->InternalizeUtf8String(string);
|
||||
}
|
||||
|
||||
Handle<Object> Val(double value) {
|
||||
return isolate->factory()->NewNumber(value);
|
||||
}
|
||||
|
||||
Handle<Object> infinity() { return isolate->factory()->infinity_value(); }
|
||||
|
||||
Handle<Object> minus_infinity() { return Val(-V8_INFINITY); }
|
||||
|
||||
Handle<Object> nan() { return isolate->factory()->nan_value(); }
|
||||
|
||||
Handle<Object> undefined() { return isolate->factory()->undefined_value(); }
|
||||
|
||||
Handle<Object> null() { return isolate->factory()->null_value(); }
|
||||
|
||||
Handle<Object> true_value() { return isolate->factory()->true_value(); }
|
||||
|
||||
Handle<Object> false_value() { return isolate->factory()->false_value(); }
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace v8::internal::compiler
|
||||
|
||||
#endif // V8_CCTEST_COMPILER_FUNCTION_TESTER_H_
|
@ -1,64 +0,0 @@
|
||||
// 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/graph-builder-tester.h"
|
||||
#include "src/compiler/pipeline.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
MachineCallHelper::MachineCallHelper(Zone* zone,
|
||||
MachineCallDescriptorBuilder* builder)
|
||||
: CallHelper(zone->isolate()),
|
||||
call_descriptor_builder_(builder),
|
||||
parameters_(NULL),
|
||||
graph_(NULL) {}
|
||||
|
||||
|
||||
void MachineCallHelper::InitParameters(GraphBuilder* builder,
|
||||
CommonOperatorBuilder* common) {
|
||||
ASSERT_EQ(NULL, parameters_);
|
||||
graph_ = builder->graph();
|
||||
if (parameter_count() == 0) return;
|
||||
parameters_ = builder->graph()->zone()->NewArray<Node*>(parameter_count());
|
||||
for (int i = 0; i < parameter_count(); ++i) {
|
||||
parameters_[i] = builder->NewNode(common->Parameter(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
byte* MachineCallHelper::Generate() {
|
||||
ASSERT(parameter_count() == 0 || parameters_ != NULL);
|
||||
if (code_.is_null()) {
|
||||
Zone* zone = graph_->zone();
|
||||
CompilationInfo info(zone->isolate(), zone);
|
||||
Linkage linkage(&info, call_descriptor_builder_->BuildCallDescriptor(zone));
|
||||
Pipeline pipeline(&info);
|
||||
code_ = pipeline.GenerateCodeForMachineGraph(&linkage, graph_);
|
||||
}
|
||||
return code_.ToHandleChecked()->entry();
|
||||
}
|
||||
|
||||
|
||||
void MachineCallHelper::VerifyParameters(
|
||||
int parameter_count, MachineRepresentation* parameter_types) {
|
||||
CHECK_EQ(this->parameter_count(), parameter_count);
|
||||
const MachineRepresentation* expected_types =
|
||||
call_descriptor_builder_->parameter_types();
|
||||
for (int i = 0; i < parameter_count; i++) {
|
||||
CHECK_EQ(expected_types[i], parameter_types[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Node* MachineCallHelper::Parameter(int offset) {
|
||||
ASSERT_NE(NULL, parameters_);
|
||||
ASSERT(0 <= offset && offset < parameter_count());
|
||||
return parameters_[offset];
|
||||
}
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
@ -1,111 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#ifndef V8_CCTEST_COMPILER_GRAPH_BUILDER_TESTER_H_
|
||||
#define V8_CCTEST_COMPILER_GRAPH_BUILDER_TESTER_H_
|
||||
|
||||
#include "src/v8.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
|
||||
#include "src/compiler/common-operator.h"
|
||||
#include "src/compiler/graph-builder.h"
|
||||
#include "src/compiler/machine-node-factory.h"
|
||||
#include "src/compiler/machine-operator.h"
|
||||
#include "src/compiler/simplified-node-factory.h"
|
||||
#include "src/compiler/simplified-operator.h"
|
||||
#include "test/cctest/compiler/call-tester.h"
|
||||
#include "test/cctest/compiler/simplified-graph-builder.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
// A class that just passes node creation on to the Graph.
|
||||
class DirectGraphBuilder : public GraphBuilder {
|
||||
public:
|
||||
explicit DirectGraphBuilder(Graph* graph) : GraphBuilder(graph) {}
|
||||
virtual ~DirectGraphBuilder() {}
|
||||
|
||||
protected:
|
||||
virtual Node* MakeNode(Operator* op, int value_input_count,
|
||||
Node** value_inputs) {
|
||||
return graph()->NewNode(op, value_input_count, value_inputs);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class MachineCallHelper : public CallHelper {
|
||||
public:
|
||||
MachineCallHelper(Zone* zone, MachineCallDescriptorBuilder* builder);
|
||||
|
||||
Node* Parameter(int offset);
|
||||
|
||||
protected:
|
||||
virtual byte* Generate();
|
||||
virtual void VerifyParameters(int parameter_count,
|
||||
MachineRepresentation* parameters);
|
||||
void InitParameters(GraphBuilder* builder, CommonOperatorBuilder* common);
|
||||
|
||||
private:
|
||||
int parameter_count() const {
|
||||
return call_descriptor_builder_->parameter_count();
|
||||
}
|
||||
MachineCallDescriptorBuilder* call_descriptor_builder_;
|
||||
Node** parameters_;
|
||||
// TODO(dcarney): shouldn't need graph stored.
|
||||
Graph* graph_;
|
||||
MaybeHandle<Code> code_;
|
||||
};
|
||||
|
||||
|
||||
class GraphAndBuilders {
|
||||
public:
|
||||
explicit GraphAndBuilders(Zone* zone)
|
||||
: main_graph_(new (zone) Graph(zone)),
|
||||
main_common_(zone),
|
||||
main_machine_(zone),
|
||||
main_simplified_(zone) {}
|
||||
|
||||
protected:
|
||||
// Prefixed with main_ to avoid naiming conflicts.
|
||||
Graph* const main_graph_;
|
||||
CommonOperatorBuilder main_common_;
|
||||
MachineOperatorBuilder main_machine_;
|
||||
SimplifiedOperatorBuilder main_simplified_;
|
||||
};
|
||||
|
||||
|
||||
template <typename ReturnType>
|
||||
class GraphBuilderTester
|
||||
: public HandleAndZoneScope,
|
||||
private GraphAndBuilders,
|
||||
public MachineCallHelper,
|
||||
public SimplifiedGraphBuilder,
|
||||
public CallHelper2<ReturnType, GraphBuilderTester<ReturnType> > {
|
||||
public:
|
||||
explicit GraphBuilderTester(MachineRepresentation p0,
|
||||
MachineRepresentation p1,
|
||||
MachineRepresentation p2,
|
||||
MachineRepresentation p3,
|
||||
MachineRepresentation p4)
|
||||
: GraphAndBuilders(main_zone()),
|
||||
MachineCallHelper(
|
||||
main_zone(),
|
||||
ToCallDescriptorBuilder(
|
||||
main_zone(), ReturnValueTraits<ReturnType>::Representation(),
|
||||
p0, p1, p2, p3, p4)),
|
||||
SimplifiedGraphBuilder(main_graph_, &main_common_, &main_machine_,
|
||||
&main_simplified_) {
|
||||
Begin();
|
||||
InitParameters(this, &main_common_);
|
||||
}
|
||||
virtual ~GraphBuilderTester() {}
|
||||
|
||||
Factory* factory() const { return isolate()->factory(); }
|
||||
};
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_CCTEST_COMPILER_GRAPH_BUILDER_TESTER_H_
|
@ -1,41 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#ifndef V8_CCTEST_COMPILER_GRAPH_TESTER_H_
|
||||
#define V8_CCTEST_COMPILER_GRAPH_TESTER_H_
|
||||
|
||||
#include "src/v8.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
|
||||
#include "src/compiler/common-operator.h"
|
||||
#include "src/compiler/graph.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
class GraphTester : public HandleAndZoneScope, public Graph {
|
||||
public:
|
||||
GraphTester() : Graph(main_zone()) {}
|
||||
};
|
||||
|
||||
|
||||
class GraphWithStartNodeTester : public GraphTester {
|
||||
public:
|
||||
GraphWithStartNodeTester()
|
||||
: builder_(main_zone()), start_node_(NewNode(builder_.Start())) {
|
||||
SetStart(start_node_);
|
||||
}
|
||||
|
||||
Node* start_node() { return start_node_; }
|
||||
|
||||
private:
|
||||
CommonOperatorBuilder builder_;
|
||||
Node* start_node_;
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace v8::internal::compiler
|
||||
|
||||
#endif // V8_CCTEST_COMPILER_GRAPH_TESTER_H_
|
@ -1,119 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#ifndef V8_CCTEST_COMPILER_INSTRUCTION_SELECTOR_TEST_H_
|
||||
#define V8_CCTEST_COMPILER_INSTRUCTION_SELECTOR_TEST_H_
|
||||
|
||||
#include <deque>
|
||||
#include <set>
|
||||
|
||||
#include "src/compiler/instruction-selector.h"
|
||||
#include "src/compiler/raw-machine-assembler.h"
|
||||
#include "src/ostreams.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
typedef std::set<int> VirtualRegisterSet;
|
||||
|
||||
enum InstructionSelectorTesterMode { kTargetMode, kInternalMode };
|
||||
|
||||
class InstructionSelectorTester : public HandleAndZoneScope,
|
||||
public RawMachineAssembler {
|
||||
public:
|
||||
enum Mode { kTargetMode, kInternalMode };
|
||||
|
||||
static const int kParameterCount = 3;
|
||||
static MachineRepresentation* BuildParameterArray(Zone* zone) {
|
||||
MachineRepresentation* array =
|
||||
zone->NewArray<MachineRepresentation>(kParameterCount);
|
||||
for (int i = 0; i < kParameterCount; ++i) {
|
||||
array[i] = kMachineWord32;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
explicit InstructionSelectorTester(Mode mode = kTargetMode)
|
||||
: RawMachineAssembler(
|
||||
new (main_zone()) Graph(main_zone()), new (main_zone())
|
||||
MachineCallDescriptorBuilder(kMachineWord32, kParameterCount,
|
||||
BuildParameterArray(main_zone())),
|
||||
MachineOperatorBuilder::pointer_rep()),
|
||||
mode_(mode) {}
|
||||
|
||||
void SelectInstructions() {
|
||||
OFStream out(stdout);
|
||||
Schedule* schedule = Export();
|
||||
CHECK_NE(0, graph()->NodeCount());
|
||||
CompilationInfo info(main_isolate(), main_zone());
|
||||
Linkage linkage(&info, call_descriptor());
|
||||
InstructionSequence sequence(&linkage, graph(), schedule);
|
||||
SourcePositionTable source_positions(graph());
|
||||
InstructionSelector selector(&sequence, &source_positions);
|
||||
selector.SelectInstructions();
|
||||
out << "--- Code sequence after instruction selection --- " << endl
|
||||
<< sequence;
|
||||
for (InstructionSequence::const_iterator i = sequence.begin();
|
||||
i != sequence.end(); ++i) {
|
||||
Instruction* instr = *i;
|
||||
if (instr->opcode() < 0) continue;
|
||||
if (mode_ == kTargetMode) {
|
||||
switch (ArchOpcodeField::decode(instr->opcode())) {
|
||||
#define CASE(Name) \
|
||||
case k##Name: \
|
||||
break;
|
||||
TARGET_ARCH_OPCODE_LIST(CASE)
|
||||
#undef CASE
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
code.push_back(instr);
|
||||
}
|
||||
for (int vreg = 0; vreg < sequence.VirtualRegisterCount(); ++vreg) {
|
||||
if (sequence.IsDouble(vreg)) {
|
||||
CHECK(!sequence.IsReference(vreg));
|
||||
doubles.insert(vreg);
|
||||
}
|
||||
if (sequence.IsReference(vreg)) {
|
||||
CHECK(!sequence.IsDouble(vreg));
|
||||
references.insert(vreg);
|
||||
}
|
||||
}
|
||||
immediates.assign(sequence.immediates().begin(),
|
||||
sequence.immediates().end());
|
||||
}
|
||||
|
||||
int32_t ToInt32(const InstructionOperand* operand) const {
|
||||
size_t i = operand->index();
|
||||
CHECK(i < immediates.size());
|
||||
CHECK_EQ(InstructionOperand::IMMEDIATE, operand->kind());
|
||||
return immediates[i].ToInt32();
|
||||
}
|
||||
|
||||
std::deque<Instruction*> code;
|
||||
VirtualRegisterSet doubles;
|
||||
VirtualRegisterSet references;
|
||||
std::deque<Constant> immediates;
|
||||
|
||||
private:
|
||||
Mode mode_;
|
||||
};
|
||||
|
||||
|
||||
static inline void CheckSameVreg(InstructionOperand* exp,
|
||||
InstructionOperand* val) {
|
||||
CHECK_EQ(InstructionOperand::UNALLOCATED, exp->kind());
|
||||
CHECK_EQ(InstructionOperand::UNALLOCATED, val->kind());
|
||||
CHECK_EQ(UnallocatedOperand::cast(exp)->virtual_register(),
|
||||
UnallocatedOperand::cast(val)->virtual_register());
|
||||
}
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_CCTEST_COMPILER_INSTRUCTION_SELECTOR_TEST_H_
|
@ -1,78 +0,0 @@
|
||||
// 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/simplified-graph-builder.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
SimplifiedGraphBuilder::SimplifiedGraphBuilder(
|
||||
Graph* graph, CommonOperatorBuilder* common,
|
||||
MachineOperatorBuilder* machine, SimplifiedOperatorBuilder* simplified)
|
||||
: StructuredGraphBuilder(graph, common),
|
||||
machine_(machine),
|
||||
simplified_(simplified) {}
|
||||
|
||||
|
||||
void SimplifiedGraphBuilder::Begin() {
|
||||
ASSERT(graph()->start() == NULL);
|
||||
Node* start = graph()->NewNode(common()->Start());
|
||||
graph()->SetStart(start);
|
||||
set_environment(new (zone()) Environment(this, start));
|
||||
}
|
||||
|
||||
|
||||
void SimplifiedGraphBuilder::Return(Node* value) {
|
||||
Node* control = NewNode(common()->Return(), value);
|
||||
UpdateControlDependencyToLeaveFunction(control);
|
||||
}
|
||||
|
||||
|
||||
void SimplifiedGraphBuilder::End() {
|
||||
environment()->UpdateControlDependency(exit_control());
|
||||
graph()->SetEnd(NewNode(common()->End()));
|
||||
}
|
||||
|
||||
|
||||
SimplifiedGraphBuilder::Environment::Environment(
|
||||
SimplifiedGraphBuilder* builder, Node* control_dependency)
|
||||
: StructuredGraphBuilder::Environment(builder, control_dependency) {}
|
||||
|
||||
|
||||
Node* SimplifiedGraphBuilder::Environment::Top() {
|
||||
ASSERT(!values()->empty());
|
||||
return values()->back();
|
||||
}
|
||||
|
||||
|
||||
void SimplifiedGraphBuilder::Environment::Push(Node* node) {
|
||||
values()->push_back(node);
|
||||
}
|
||||
|
||||
|
||||
Node* SimplifiedGraphBuilder::Environment::Pop() {
|
||||
ASSERT(!values()->empty());
|
||||
Node* back = values()->back();
|
||||
values()->pop_back();
|
||||
return back;
|
||||
}
|
||||
|
||||
|
||||
void SimplifiedGraphBuilder::Environment::Poke(size_t depth, Node* node) {
|
||||
ASSERT(depth < values()->size());
|
||||
size_t index = values()->size() - depth - 1;
|
||||
values()->at(index) = node;
|
||||
}
|
||||
|
||||
|
||||
Node* SimplifiedGraphBuilder::Environment::Peek(size_t depth) {
|
||||
ASSERT(depth < values()->size());
|
||||
size_t index = values()->size() - depth - 1;
|
||||
return values()->at(index);
|
||||
}
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
@ -1,72 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#ifndef V8_CCTEST_COMPILER_SIMPLIFIED_GRAPH_BUILDER_H_
|
||||
#define V8_CCTEST_COMPILER_SIMPLIFIED_GRAPH_BUILDER_H_
|
||||
|
||||
#include "src/compiler/common-operator.h"
|
||||
#include "src/compiler/graph-builder.h"
|
||||
#include "src/compiler/machine-node-factory.h"
|
||||
#include "src/compiler/machine-operator.h"
|
||||
#include "src/compiler/simplified-node-factory.h"
|
||||
#include "src/compiler/simplified-operator.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
#include "test/cctest/compiler/call-tester.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
class SimplifiedGraphBuilder
|
||||
: public StructuredGraphBuilder,
|
||||
public MachineNodeFactory<SimplifiedGraphBuilder>,
|
||||
public SimplifiedNodeFactory<SimplifiedGraphBuilder> {
|
||||
public:
|
||||
SimplifiedGraphBuilder(Graph* graph, CommonOperatorBuilder* common,
|
||||
MachineOperatorBuilder* machine,
|
||||
SimplifiedOperatorBuilder* simplified);
|
||||
virtual ~SimplifiedGraphBuilder() {}
|
||||
|
||||
class Environment : public StructuredGraphBuilder::Environment {
|
||||
public:
|
||||
Environment(SimplifiedGraphBuilder* builder, Node* control_dependency);
|
||||
|
||||
// TODO(dcarney): encode somehow and merge into StructuredGraphBuilder.
|
||||
// SSA renaming operations.
|
||||
Node* Top();
|
||||
void Push(Node* node);
|
||||
Node* Pop();
|
||||
void Poke(size_t depth, Node* node);
|
||||
Node* Peek(size_t depth);
|
||||
};
|
||||
|
||||
Isolate* isolate() const { return zone()->isolate(); }
|
||||
Zone* zone() const { return StructuredGraphBuilder::zone(); }
|
||||
CommonOperatorBuilder* common() const {
|
||||
return StructuredGraphBuilder::common();
|
||||
}
|
||||
MachineOperatorBuilder* machine() const { return machine_; }
|
||||
SimplifiedOperatorBuilder* simplified() const { return simplified_; }
|
||||
Environment* environment() {
|
||||
return reinterpret_cast<Environment*>(environment_internal());
|
||||
}
|
||||
|
||||
// Initialize graph and builder.
|
||||
void Begin();
|
||||
|
||||
void Return(Node* value);
|
||||
|
||||
// Close the graph.
|
||||
void End();
|
||||
|
||||
private:
|
||||
MachineOperatorBuilder* machine_;
|
||||
SimplifiedOperatorBuilder* simplified_;
|
||||
};
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_CCTEST_COMPILER_SIMPLIFIED_GRAPH_BUILDER_H_
|
@ -1,462 +0,0 @@
|
||||
// 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 "src/v8.h"
|
||||
|
||||
#include "test/cctest/cctest.h"
|
||||
#include "test/cctest/compiler/codegen-tester.h"
|
||||
#include "test/cctest/compiler/value-helper.h"
|
||||
|
||||
#if V8_TURBOFAN_TARGET
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
|
||||
typedef RawMachineAssembler::Label MLabel;
|
||||
|
||||
static IrOpcode::Value int32cmp_opcodes[] = {
|
||||
IrOpcode::kWord32Equal, IrOpcode::kInt32LessThan,
|
||||
IrOpcode::kInt32LessThanOrEqual, IrOpcode::kUint32LessThan,
|
||||
IrOpcode::kUint32LessThanOrEqual};
|
||||
|
||||
|
||||
TEST(BranchCombineWord32EqualZero_1) {
|
||||
// Test combining a branch with x == 0
|
||||
RawMachineAssemblerTester<int32_t> m(kMachineWord32);
|
||||
int32_t eq_constant = -1033;
|
||||
int32_t ne_constant = 825118;
|
||||
Node* p0 = m.Parameter(0);
|
||||
|
||||
MLabel blocka, blockb;
|
||||
m.Branch(m.Word32Equal(p0, m.Int32Constant(0)), &blocka, &blockb);
|
||||
m.Bind(&blocka);
|
||||
m.Return(m.Int32Constant(eq_constant));
|
||||
m.Bind(&blockb);
|
||||
m.Return(m.Int32Constant(ne_constant));
|
||||
|
||||
FOR_INT32_INPUTS(i) {
|
||||
int32_t a = *i;
|
||||
int32_t expect = a == 0 ? eq_constant : ne_constant;
|
||||
CHECK_EQ(expect, m.Call(a));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(BranchCombineWord32EqualZero_chain) {
|
||||
// Test combining a branch with a chain of x == 0 == 0 == 0 ...
|
||||
int32_t eq_constant = -1133;
|
||||
int32_t ne_constant = 815118;
|
||||
|
||||
for (int k = 0; k < 6; k++) {
|
||||
RawMachineAssemblerTester<int32_t> m(kMachineWord32);
|
||||
Node* p0 = m.Parameter(0);
|
||||
MLabel blocka, blockb;
|
||||
Node* cond = p0;
|
||||
for (int j = 0; j < k; j++) {
|
||||
cond = m.Word32Equal(cond, m.Int32Constant(0));
|
||||
}
|
||||
m.Branch(cond, &blocka, &blockb);
|
||||
m.Bind(&blocka);
|
||||
m.Return(m.Int32Constant(eq_constant));
|
||||
m.Bind(&blockb);
|
||||
m.Return(m.Int32Constant(ne_constant));
|
||||
|
||||
FOR_INT32_INPUTS(i) {
|
||||
int32_t a = *i;
|
||||
int32_t expect = (k & 1) == 1 ? (a == 0 ? eq_constant : ne_constant)
|
||||
: (a == 0 ? ne_constant : eq_constant);
|
||||
CHECK_EQ(expect, m.Call(a));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(BranchCombineInt32LessThanZero_1) {
|
||||
// Test combining a branch with x < 0
|
||||
RawMachineAssemblerTester<int32_t> m(kMachineWord32);
|
||||
int32_t eq_constant = -1433;
|
||||
int32_t ne_constant = 845118;
|
||||
Node* p0 = m.Parameter(0);
|
||||
|
||||
MLabel blocka, blockb;
|
||||
m.Branch(m.Int32LessThan(p0, m.Int32Constant(0)), &blocka, &blockb);
|
||||
m.Bind(&blocka);
|
||||
m.Return(m.Int32Constant(eq_constant));
|
||||
m.Bind(&blockb);
|
||||
m.Return(m.Int32Constant(ne_constant));
|
||||
|
||||
FOR_INT32_INPUTS(i) {
|
||||
int32_t a = *i;
|
||||
int32_t expect = a < 0 ? eq_constant : ne_constant;
|
||||
CHECK_EQ(expect, m.Call(a));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(BranchCombineUint32LessThan100_1) {
|
||||
// Test combining a branch with x < 100
|
||||
RawMachineAssemblerTester<int32_t> m(kMachineWord32);
|
||||
int32_t eq_constant = 1471;
|
||||
int32_t ne_constant = 88845718;
|
||||
Node* p0 = m.Parameter(0);
|
||||
|
||||
MLabel blocka, blockb;
|
||||
m.Branch(m.Uint32LessThan(p0, m.Int32Constant(100)), &blocka, &blockb);
|
||||
m.Bind(&blocka);
|
||||
m.Return(m.Int32Constant(eq_constant));
|
||||
m.Bind(&blockb);
|
||||
m.Return(m.Int32Constant(ne_constant));
|
||||
|
||||
FOR_UINT32_INPUTS(i) {
|
||||
uint32_t a = *i;
|
||||
int32_t expect = a < 100 ? eq_constant : ne_constant;
|
||||
CHECK_EQ(expect, m.Call(a));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(BranchCombineUint32LessThanOrEqual100_1) {
|
||||
// Test combining a branch with x <= 100
|
||||
RawMachineAssemblerTester<int32_t> m(kMachineWord32);
|
||||
int32_t eq_constant = 1479;
|
||||
int32_t ne_constant = 77845719;
|
||||
Node* p0 = m.Parameter(0);
|
||||
|
||||
MLabel blocka, blockb;
|
||||
m.Branch(m.Uint32LessThanOrEqual(p0, m.Int32Constant(100)), &blocka, &blockb);
|
||||
m.Bind(&blocka);
|
||||
m.Return(m.Int32Constant(eq_constant));
|
||||
m.Bind(&blockb);
|
||||
m.Return(m.Int32Constant(ne_constant));
|
||||
|
||||
FOR_UINT32_INPUTS(i) {
|
||||
uint32_t a = *i;
|
||||
int32_t expect = a <= 100 ? eq_constant : ne_constant;
|
||||
CHECK_EQ(expect, m.Call(a));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(BranchCombineZeroLessThanInt32_1) {
|
||||
// Test combining a branch with 0 < x
|
||||
RawMachineAssemblerTester<int32_t> m(kMachineWord32);
|
||||
int32_t eq_constant = -2033;
|
||||
int32_t ne_constant = 225118;
|
||||
Node* p0 = m.Parameter(0);
|
||||
|
||||
MLabel blocka, blockb;
|
||||
m.Branch(m.Int32LessThan(m.Int32Constant(0), p0), &blocka, &blockb);
|
||||
m.Bind(&blocka);
|
||||
m.Return(m.Int32Constant(eq_constant));
|
||||
m.Bind(&blockb);
|
||||
m.Return(m.Int32Constant(ne_constant));
|
||||
|
||||
FOR_INT32_INPUTS(i) {
|
||||
int32_t a = *i;
|
||||
int32_t expect = 0 < a ? eq_constant : ne_constant;
|
||||
CHECK_EQ(expect, m.Call(a));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(BranchCombineInt32GreaterThanZero_1) {
|
||||
// Test combining a branch with x > 0
|
||||
RawMachineAssemblerTester<int32_t> m(kMachineWord32);
|
||||
int32_t eq_constant = -1073;
|
||||
int32_t ne_constant = 825178;
|
||||
Node* p0 = m.Parameter(0);
|
||||
|
||||
MLabel blocka, blockb;
|
||||
m.Branch(m.Int32GreaterThan(p0, m.Int32Constant(0)), &blocka, &blockb);
|
||||
m.Bind(&blocka);
|
||||
m.Return(m.Int32Constant(eq_constant));
|
||||
m.Bind(&blockb);
|
||||
m.Return(m.Int32Constant(ne_constant));
|
||||
|
||||
FOR_INT32_INPUTS(i) {
|
||||
int32_t a = *i;
|
||||
int32_t expect = a > 0 ? eq_constant : ne_constant;
|
||||
CHECK_EQ(expect, m.Call(a));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(BranchCombineWord32EqualP) {
|
||||
// Test combining a branch with an Word32Equal.
|
||||
RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32);
|
||||
int32_t eq_constant = -1035;
|
||||
int32_t ne_constant = 825018;
|
||||
Node* p0 = m.Parameter(0);
|
||||
Node* p1 = m.Parameter(1);
|
||||
|
||||
MLabel blocka, blockb;
|
||||
m.Branch(m.Word32Equal(p0, p1), &blocka, &blockb);
|
||||
m.Bind(&blocka);
|
||||
m.Return(m.Int32Constant(eq_constant));
|
||||
m.Bind(&blockb);
|
||||
m.Return(m.Int32Constant(ne_constant));
|
||||
|
||||
FOR_INT32_INPUTS(i) {
|
||||
FOR_INT32_INPUTS(j) {
|
||||
int32_t a = *i;
|
||||
int32_t b = *j;
|
||||
int32_t expect = a == b ? eq_constant : ne_constant;
|
||||
CHECK_EQ(expect, m.Call(a, b));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(BranchCombineWord32EqualI) {
|
||||
int32_t eq_constant = -1135;
|
||||
int32_t ne_constant = 925718;
|
||||
|
||||
for (int left = 0; left < 2; left++) {
|
||||
FOR_INT32_INPUTS(i) {
|
||||
RawMachineAssemblerTester<int32_t> m(kMachineWord32);
|
||||
int32_t a = *i;
|
||||
|
||||
Node* p0 = m.Int32Constant(a);
|
||||
Node* p1 = m.Parameter(0);
|
||||
|
||||
MLabel blocka, blockb;
|
||||
if (left == 1) m.Branch(m.Word32Equal(p0, p1), &blocka, &blockb);
|
||||
if (left == 0) m.Branch(m.Word32Equal(p1, p0), &blocka, &blockb);
|
||||
m.Bind(&blocka);
|
||||
m.Return(m.Int32Constant(eq_constant));
|
||||
m.Bind(&blockb);
|
||||
m.Return(m.Int32Constant(ne_constant));
|
||||
|
||||
FOR_INT32_INPUTS(j) {
|
||||
int32_t b = *j;
|
||||
int32_t expect = a == b ? eq_constant : ne_constant;
|
||||
CHECK_EQ(expect, m.Call(b));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(BranchCombineInt32CmpP) {
|
||||
int32_t eq_constant = -1235;
|
||||
int32_t ne_constant = 725018;
|
||||
|
||||
for (int op = 0; op < 2; op++) {
|
||||
RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32);
|
||||
Node* p0 = m.Parameter(0);
|
||||
Node* p1 = m.Parameter(1);
|
||||
|
||||
MLabel blocka, blockb;
|
||||
if (op == 0) m.Branch(m.Int32LessThan(p0, p1), &blocka, &blockb);
|
||||
if (op == 1) m.Branch(m.Int32LessThanOrEqual(p0, p1), &blocka, &blockb);
|
||||
m.Bind(&blocka);
|
||||
m.Return(m.Int32Constant(eq_constant));
|
||||
m.Bind(&blockb);
|
||||
m.Return(m.Int32Constant(ne_constant));
|
||||
|
||||
FOR_INT32_INPUTS(i) {
|
||||
FOR_INT32_INPUTS(j) {
|
||||
int32_t a = *i;
|
||||
int32_t b = *j;
|
||||
int32_t expect = 0;
|
||||
if (op == 0) expect = a < b ? eq_constant : ne_constant;
|
||||
if (op == 1) expect = a <= b ? eq_constant : ne_constant;
|
||||
CHECK_EQ(expect, m.Call(a, b));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(BranchCombineInt32CmpI) {
|
||||
int32_t eq_constant = -1175;
|
||||
int32_t ne_constant = 927711;
|
||||
|
||||
for (int op = 0; op < 2; op++) {
|
||||
FOR_INT32_INPUTS(i) {
|
||||
RawMachineAssemblerTester<int32_t> m(kMachineWord32);
|
||||
int32_t a = *i;
|
||||
Node* p0 = m.Int32Constant(a);
|
||||
Node* p1 = m.Parameter(0);
|
||||
|
||||
MLabel blocka, blockb;
|
||||
if (op == 0) m.Branch(m.Int32LessThan(p0, p1), &blocka, &blockb);
|
||||
if (op == 1) m.Branch(m.Int32LessThanOrEqual(p0, p1), &blocka, &blockb);
|
||||
m.Bind(&blocka);
|
||||
m.Return(m.Int32Constant(eq_constant));
|
||||
m.Bind(&blockb);
|
||||
m.Return(m.Int32Constant(ne_constant));
|
||||
|
||||
FOR_INT32_INPUTS(j) {
|
||||
int32_t b = *j;
|
||||
int32_t expect = 0;
|
||||
if (op == 0) expect = a < b ? eq_constant : ne_constant;
|
||||
if (op == 1) expect = a <= b ? eq_constant : ne_constant;
|
||||
CHECK_EQ(expect, m.Call(b));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Now come the sophisticated tests for many input shape combinations.
|
||||
|
||||
// Materializes a boolean (1 or 0) from a comparison.
|
||||
class CmpMaterializeBoolGen : public BinopGen<int32_t> {
|
||||
public:
|
||||
CompareWrapper w;
|
||||
bool invert;
|
||||
|
||||
CmpMaterializeBoolGen(IrOpcode::Value opcode, bool i)
|
||||
: w(opcode), invert(i) {}
|
||||
|
||||
virtual void gen(RawMachineAssemblerTester<int32_t>* m, Node* a, Node* b) {
|
||||
Node* cond = w.MakeNode(m, a, b);
|
||||
if (invert) cond = m->Word32Equal(cond, m->Int32Constant(0));
|
||||
m->Return(cond);
|
||||
}
|
||||
virtual int32_t expected(int32_t a, int32_t b) {
|
||||
if (invert) return !w.Int32Compare(a, b) ? 1 : 0;
|
||||
return w.Int32Compare(a, b) ? 1 : 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Generates a branch and return one of two values from a comparison.
|
||||
class CmpBranchGen : public BinopGen<int32_t> {
|
||||
public:
|
||||
CompareWrapper w;
|
||||
bool invert;
|
||||
bool true_first;
|
||||
int32_t eq_constant;
|
||||
int32_t ne_constant;
|
||||
|
||||
CmpBranchGen(IrOpcode::Value opcode, bool i, bool t, int32_t eq, int32_t ne)
|
||||
: w(opcode), invert(i), true_first(t), eq_constant(eq), ne_constant(ne) {}
|
||||
|
||||
virtual void gen(RawMachineAssemblerTester<int32_t>* m, Node* a, Node* b) {
|
||||
MLabel blocka, blockb;
|
||||
Node* cond = w.MakeNode(m, a, b);
|
||||
if (invert) cond = m->Word32Equal(cond, m->Int32Constant(0));
|
||||
m->Branch(cond, &blocka, &blockb);
|
||||
if (true_first) {
|
||||
m->Bind(&blocka);
|
||||
m->Return(m->Int32Constant(eq_constant));
|
||||
m->Bind(&blockb);
|
||||
m->Return(m->Int32Constant(ne_constant));
|
||||
} else {
|
||||
m->Bind(&blockb);
|
||||
m->Return(m->Int32Constant(ne_constant));
|
||||
m->Bind(&blocka);
|
||||
m->Return(m->Int32Constant(eq_constant));
|
||||
}
|
||||
}
|
||||
virtual int32_t expected(int32_t a, int32_t b) {
|
||||
if (invert) return !w.Int32Compare(a, b) ? eq_constant : ne_constant;
|
||||
return w.Int32Compare(a, b) ? eq_constant : ne_constant;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
TEST(BranchCombineInt32CmpAllInputShapes_materialized) {
|
||||
for (size_t i = 0; i < ARRAY_SIZE(int32cmp_opcodes); i++) {
|
||||
CmpMaterializeBoolGen gen(int32cmp_opcodes[i], false);
|
||||
Int32BinopInputShapeTester tester(&gen);
|
||||
tester.TestAllInputShapes();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(BranchCombineInt32CmpAllInputShapes_inverted_materialized) {
|
||||
for (size_t i = 0; i < ARRAY_SIZE(int32cmp_opcodes); i++) {
|
||||
CmpMaterializeBoolGen gen(int32cmp_opcodes[i], true);
|
||||
Int32BinopInputShapeTester tester(&gen);
|
||||
tester.TestAllInputShapes();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(BranchCombineInt32CmpAllInputShapes_branch_true) {
|
||||
for (size_t i = 0; i < ARRAY_SIZE(int32cmp_opcodes); i++) {
|
||||
CmpBranchGen gen(int32cmp_opcodes[i], false, false, 995 + i, -1011 - i);
|
||||
Int32BinopInputShapeTester tester(&gen);
|
||||
tester.TestAllInputShapes();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(BranchCombineInt32CmpAllInputShapes_branch_false) {
|
||||
for (size_t i = 0; i < ARRAY_SIZE(int32cmp_opcodes); i++) {
|
||||
CmpBranchGen gen(int32cmp_opcodes[i], false, true, 795 + i, -2011 - i);
|
||||
Int32BinopInputShapeTester tester(&gen);
|
||||
tester.TestAllInputShapes();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(BranchCombineInt32CmpAllInputShapes_inverse_branch_true) {
|
||||
for (size_t i = 0; i < ARRAY_SIZE(int32cmp_opcodes); i++) {
|
||||
CmpBranchGen gen(int32cmp_opcodes[i], true, false, 695 + i, -3011 - i);
|
||||
Int32BinopInputShapeTester tester(&gen);
|
||||
tester.TestAllInputShapes();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(BranchCombineInt32CmpAllInputShapes_inverse_branch_false) {
|
||||
for (size_t i = 0; i < ARRAY_SIZE(int32cmp_opcodes); i++) {
|
||||
CmpBranchGen gen(int32cmp_opcodes[i], true, true, 595 + i, -4011 - i);
|
||||
Int32BinopInputShapeTester tester(&gen);
|
||||
tester.TestAllInputShapes();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(BranchCombineFloat64Compares) {
|
||||
double inf = V8_INFINITY;
|
||||
double nan = v8::base::OS::nan_value();
|
||||
double inputs[] = {0.0, 1.0, -1.0, -inf, inf, nan};
|
||||
|
||||
int32_t eq_constant = -1733;
|
||||
int32_t ne_constant = 915118;
|
||||
|
||||
double input_a = 0.0;
|
||||
double input_b = 0.0;
|
||||
|
||||
CompareWrapper cmps[] = {CompareWrapper(IrOpcode::kFloat64Equal),
|
||||
CompareWrapper(IrOpcode::kFloat64LessThan),
|
||||
CompareWrapper(IrOpcode::kFloat64LessThanOrEqual)};
|
||||
|
||||
for (size_t c = 0; c < ARRAY_SIZE(cmps); c++) {
|
||||
CompareWrapper cmp = cmps[c];
|
||||
for (int invert = 0; invert < 2; invert++) {
|
||||
RawMachineAssemblerTester<int32_t> m;
|
||||
Node* a = m.LoadFromPointer(&input_a, kMachineFloat64);
|
||||
Node* b = m.LoadFromPointer(&input_b, kMachineFloat64);
|
||||
|
||||
MLabel blocka, blockb;
|
||||
Node* cond = cmp.MakeNode(&m, a, b);
|
||||
if (invert) cond = m.Word32Equal(cond, m.Int32Constant(0));
|
||||
m.Branch(cond, &blocka, &blockb);
|
||||
m.Bind(&blocka);
|
||||
m.Return(m.Int32Constant(eq_constant));
|
||||
m.Bind(&blockb);
|
||||
m.Return(m.Int32Constant(ne_constant));
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(inputs); i++) {
|
||||
for (size_t j = 0; j < ARRAY_SIZE(inputs); j += 2) {
|
||||
input_a = inputs[i];
|
||||
input_b = inputs[i];
|
||||
int32_t expected =
|
||||
invert ? (cmp.Float64Compare(input_a, input_b) ? ne_constant
|
||||
: eq_constant)
|
||||
: (cmp.Float64Compare(input_a, input_b) ? eq_constant
|
||||
: ne_constant);
|
||||
CHECK_EQ(expected, m.Call());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // V8_TURBOFAN_TARGET
|
@ -1,331 +0,0 @@
|
||||
// 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 "src/v8.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
|
||||
#include "src/compiler/code-generator.h"
|
||||
#include "src/compiler/common-operator.h"
|
||||
#include "src/compiler/graph.h"
|
||||
#include "src/compiler/instruction-selector.h"
|
||||
#include "src/compiler/machine-operator.h"
|
||||
#include "src/compiler/node.h"
|
||||
#include "src/compiler/operator.h"
|
||||
#include "src/compiler/raw-machine-assembler.h"
|
||||
#include "src/compiler/register-allocator.h"
|
||||
#include "src/compiler/schedule.h"
|
||||
|
||||
#include "src/full-codegen.h"
|
||||
#include "src/parser.h"
|
||||
#include "src/rewriter.h"
|
||||
|
||||
#include "test/cctest/compiler/function-tester.h"
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
|
||||
typedef RawMachineAssembler::Label MLabel;
|
||||
|
||||
static Handle<JSFunction> NewFunction(const char* source) {
|
||||
return v8::Utils::OpenHandle(
|
||||
*v8::Handle<v8::Function>::Cast(CompileRun(source)));
|
||||
}
|
||||
|
||||
|
||||
class DeoptCodegenTester {
|
||||
public:
|
||||
explicit DeoptCodegenTester(HandleAndZoneScope* scope, const char* src)
|
||||
: scope_(scope),
|
||||
function(NewFunction(src)),
|
||||
info(function, scope->main_zone()),
|
||||
bailout_id(-1) {
|
||||
CHECK(Parser::Parse(&info));
|
||||
StrictMode strict_mode = info.function()->strict_mode();
|
||||
info.SetStrictMode(strict_mode);
|
||||
info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code()));
|
||||
CHECK(Rewriter::Rewrite(&info));
|
||||
CHECK(Scope::Analyze(&info));
|
||||
CHECK_NE(NULL, info.scope());
|
||||
|
||||
FunctionTester::EnsureDeoptimizationSupport(&info);
|
||||
|
||||
ASSERT(info.shared_info()->has_deoptimization_support());
|
||||
|
||||
graph = new (scope_->main_zone()) Graph(scope_->main_zone());
|
||||
}
|
||||
|
||||
virtual ~DeoptCodegenTester() { delete code; }
|
||||
|
||||
void GenerateCodeFromSchedule(Schedule* schedule) {
|
||||
OFStream os(stdout);
|
||||
os << *schedule;
|
||||
|
||||
// Initialize the codegen and generate code.
|
||||
Linkage* linkage = new (scope_->main_zone()) Linkage(&info);
|
||||
code = new v8::internal::compiler::InstructionSequence(linkage, graph,
|
||||
schedule);
|
||||
SourcePositionTable source_positions(graph);
|
||||
InstructionSelector selector(code, &source_positions);
|
||||
selector.SelectInstructions();
|
||||
|
||||
os << "----- Instruction sequence before register allocation -----\n"
|
||||
<< *code;
|
||||
|
||||
RegisterAllocator allocator(code);
|
||||
CHECK(allocator.Allocate());
|
||||
|
||||
os << "----- Instruction sequence after register allocation -----\n"
|
||||
<< *code;
|
||||
|
||||
compiler::CodeGenerator generator(code);
|
||||
result_code = generator.GenerateCode();
|
||||
|
||||
#ifdef DEBUG
|
||||
result_code->Print();
|
||||
#endif
|
||||
}
|
||||
|
||||
Zone* zone() { return scope_->main_zone(); }
|
||||
|
||||
HandleAndZoneScope* scope_;
|
||||
Handle<JSFunction> function;
|
||||
CompilationInfo info;
|
||||
BailoutId bailout_id;
|
||||
Handle<Code> result_code;
|
||||
v8::internal::compiler::InstructionSequence* code;
|
||||
Graph* graph;
|
||||
};
|
||||
|
||||
|
||||
class TrivialDeoptCodegenTester : public DeoptCodegenTester {
|
||||
public:
|
||||
explicit TrivialDeoptCodegenTester(HandleAndZoneScope* scope)
|
||||
: DeoptCodegenTester(scope,
|
||||
"function foo() { deopt(); return 42; }; foo") {}
|
||||
|
||||
void GenerateCode() {
|
||||
GenerateCodeFromSchedule(BuildGraphAndSchedule(graph));
|
||||
}
|
||||
|
||||
Schedule* BuildGraphAndSchedule(Graph* graph) {
|
||||
Isolate* isolate = info.isolate();
|
||||
CommonOperatorBuilder common(zone());
|
||||
|
||||
// Manually construct a schedule for the function below:
|
||||
// function foo() {
|
||||
// deopt();
|
||||
// }
|
||||
|
||||
MachineRepresentation parameter_reps[] = {kMachineTagged};
|
||||
MachineCallDescriptorBuilder descriptor_builder(kMachineTagged, 1,
|
||||
parameter_reps);
|
||||
|
||||
RawMachineAssembler m(graph, &descriptor_builder);
|
||||
|
||||
Handle<Object> undef_object =
|
||||
Handle<Object>(isolate->heap()->undefined_value(), isolate);
|
||||
PrintableUnique<Object> undef_constant =
|
||||
PrintableUnique<Object>::CreateUninitialized(zone(), undef_object);
|
||||
Node* undef_node = m.NewNode(common.HeapConstant(undef_constant));
|
||||
|
||||
Handle<JSFunction> deopt_function =
|
||||
NewFunction("function deopt() { %DeoptimizeFunction(foo); }; deopt");
|
||||
PrintableUnique<Object> deopt_fun_constant =
|
||||
PrintableUnique<Object>::CreateUninitialized(zone(), deopt_function);
|
||||
Node* deopt_fun_node = m.NewNode(common.HeapConstant(deopt_fun_constant));
|
||||
|
||||
MLabel deopt, cont;
|
||||
Node* call = m.CallJS0(deopt_fun_node, undef_node, &cont, &deopt);
|
||||
|
||||
m.Bind(&cont);
|
||||
m.NewNode(common.Continuation(), call);
|
||||
m.Return(undef_node);
|
||||
|
||||
m.Bind(&deopt);
|
||||
m.NewNode(common.LazyDeoptimization(), call);
|
||||
|
||||
bailout_id = GetCallBailoutId();
|
||||
FrameStateDescriptor stateDescriptor(bailout_id);
|
||||
Node* state_node = m.NewNode(common.FrameState(stateDescriptor));
|
||||
m.Deoptimize(state_node);
|
||||
|
||||
// Schedule the graph:
|
||||
Schedule* schedule = m.Export();
|
||||
|
||||
cont_block = cont.block();
|
||||
deopt_block = deopt.block();
|
||||
|
||||
return schedule;
|
||||
}
|
||||
|
||||
BailoutId GetCallBailoutId() {
|
||||
ZoneList<Statement*>* body = info.function()->body();
|
||||
for (int i = 0; i < body->length(); i++) {
|
||||
if (body->at(i)->IsExpressionStatement() &&
|
||||
body->at(i)->AsExpressionStatement()->expression()->IsCall()) {
|
||||
return body->at(i)->AsExpressionStatement()->expression()->id();
|
||||
}
|
||||
}
|
||||
CHECK(false);
|
||||
return BailoutId(-1);
|
||||
}
|
||||
|
||||
BasicBlock* cont_block;
|
||||
BasicBlock* deopt_block;
|
||||
};
|
||||
|
||||
|
||||
TEST(TurboTrivialDeoptCodegen) {
|
||||
HandleAndZoneScope scope;
|
||||
InitializedHandleScope handles;
|
||||
|
||||
FLAG_allow_natives_syntax = true;
|
||||
FLAG_turbo_deoptimization = true;
|
||||
|
||||
TrivialDeoptCodegenTester t(&scope);
|
||||
t.GenerateCode();
|
||||
|
||||
DeoptimizationInputData* data =
|
||||
DeoptimizationInputData::cast(t.result_code->deoptimization_data());
|
||||
|
||||
Label* cont_label = t.code->GetLabel(t.cont_block);
|
||||
Label* deopt_label = t.code->GetLabel(t.deopt_block);
|
||||
|
||||
// Check the patch table. It should patch the continuation address to the
|
||||
// deoptimization block address.
|
||||
CHECK_EQ(1, data->ReturnAddressPatchCount());
|
||||
CHECK_EQ(cont_label->pos(), data->ReturnAddressPc(0)->value());
|
||||
CHECK_EQ(deopt_label->pos(), data->PatchedAddressPc(0)->value());
|
||||
|
||||
// Check that we deoptimize to the right AST id.
|
||||
CHECK_EQ(1, data->DeoptCount());
|
||||
CHECK_EQ(1, data->DeoptCount());
|
||||
CHECK_EQ(t.bailout_id.ToInt(), data->AstId(0).ToInt());
|
||||
}
|
||||
|
||||
|
||||
TEST(TurboTrivialDeoptCodegenAndRun) {
|
||||
HandleAndZoneScope scope;
|
||||
InitializedHandleScope handles;
|
||||
|
||||
FLAG_allow_natives_syntax = true;
|
||||
FLAG_turbo_deoptimization = true;
|
||||
|
||||
TrivialDeoptCodegenTester t(&scope);
|
||||
t.GenerateCode();
|
||||
|
||||
t.function->ReplaceCode(*t.result_code);
|
||||
t.info.context()->native_context()->AddOptimizedCode(*t.result_code);
|
||||
|
||||
Isolate* isolate = scope.main_isolate();
|
||||
Handle<Object> result;
|
||||
bool has_pending_exception =
|
||||
!Execution::Call(isolate, t.function,
|
||||
isolate->factory()->undefined_value(), 0, NULL,
|
||||
false).ToHandle(&result);
|
||||
CHECK(!has_pending_exception);
|
||||
CHECK(result->SameValue(Smi::FromInt(42)));
|
||||
}
|
||||
|
||||
|
||||
class TrivialRuntimeDeoptCodegenTester : public DeoptCodegenTester {
|
||||
public:
|
||||
explicit TrivialRuntimeDeoptCodegenTester(HandleAndZoneScope* scope)
|
||||
: DeoptCodegenTester(
|
||||
scope,
|
||||
"function foo() { %DeoptimizeFunction(foo); return 42; }; foo") {}
|
||||
|
||||
void GenerateCode() {
|
||||
GenerateCodeFromSchedule(BuildGraphAndSchedule(graph));
|
||||
}
|
||||
|
||||
Schedule* BuildGraphAndSchedule(Graph* graph) {
|
||||
Isolate* isolate = info.isolate();
|
||||
CommonOperatorBuilder common(zone());
|
||||
|
||||
// Manually construct a schedule for the function below:
|
||||
// function foo() {
|
||||
// %DeoptimizeFunction(foo);
|
||||
// }
|
||||
|
||||
MachineRepresentation parameter_reps[] = {kMachineTagged};
|
||||
MachineCallDescriptorBuilder descriptor_builder(kMachineTagged, 2,
|
||||
parameter_reps);
|
||||
|
||||
RawMachineAssembler m(graph, &descriptor_builder);
|
||||
|
||||
Handle<Object> undef_object =
|
||||
Handle<Object>(isolate->heap()->undefined_value(), isolate);
|
||||
PrintableUnique<Object> undef_constant =
|
||||
PrintableUnique<Object>::CreateUninitialized(zone(), undef_object);
|
||||
Node* undef_node = m.NewNode(common.HeapConstant(undef_constant));
|
||||
|
||||
PrintableUnique<Object> this_fun_constant =
|
||||
PrintableUnique<Object>::CreateUninitialized(zone(), function);
|
||||
Node* this_fun_node = m.NewNode(common.HeapConstant(this_fun_constant));
|
||||
|
||||
MLabel deopt, cont;
|
||||
Node* call = m.CallRuntime1(Runtime::kDeoptimizeFunction, this_fun_node,
|
||||
&cont, &deopt);
|
||||
|
||||
m.Bind(&cont);
|
||||
m.NewNode(common.Continuation(), call);
|
||||
m.Return(undef_node);
|
||||
|
||||
m.Bind(&deopt);
|
||||
m.NewNode(common.LazyDeoptimization(), call);
|
||||
|
||||
bailout_id = GetCallBailoutId();
|
||||
FrameStateDescriptor stateDescriptor(bailout_id);
|
||||
Node* state_node = m.NewNode(common.FrameState(stateDescriptor));
|
||||
m.Deoptimize(state_node);
|
||||
|
||||
// Schedule the graph:
|
||||
Schedule* schedule = m.Export();
|
||||
|
||||
cont_block = cont.block();
|
||||
deopt_block = deopt.block();
|
||||
|
||||
return schedule;
|
||||
}
|
||||
|
||||
BailoutId GetCallBailoutId() {
|
||||
ZoneList<Statement*>* body = info.function()->body();
|
||||
for (int i = 0; i < body->length(); i++) {
|
||||
if (body->at(i)->IsExpressionStatement() &&
|
||||
body->at(i)->AsExpressionStatement()->expression()->IsCallRuntime()) {
|
||||
return body->at(i)->AsExpressionStatement()->expression()->id();
|
||||
}
|
||||
}
|
||||
CHECK(false);
|
||||
return BailoutId(-1);
|
||||
}
|
||||
|
||||
BasicBlock* cont_block;
|
||||
BasicBlock* deopt_block;
|
||||
};
|
||||
|
||||
|
||||
TEST(TurboTrivialRuntimeDeoptCodegenAndRun) {
|
||||
HandleAndZoneScope scope;
|
||||
InitializedHandleScope handles;
|
||||
|
||||
FLAG_allow_natives_syntax = true;
|
||||
FLAG_turbo_deoptimization = true;
|
||||
|
||||
TrivialRuntimeDeoptCodegenTester t(&scope);
|
||||
t.GenerateCode();
|
||||
|
||||
t.function->ReplaceCode(*t.result_code);
|
||||
t.info.context()->native_context()->AddOptimizedCode(*t.result_code);
|
||||
|
||||
Isolate* isolate = scope.main_isolate();
|
||||
Handle<Object> result;
|
||||
bool has_pending_exception =
|
||||
!Execution::Call(isolate, t.function,
|
||||
isolate->factory()->undefined_value(), 0, NULL,
|
||||
false).ToHandle(&result);
|
||||
CHECK(!has_pending_exception);
|
||||
CHECK(result->SameValue(Smi::FromInt(42)));
|
||||
}
|
@ -1,172 +0,0 @@
|
||||
// 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 "src/compiler/gap-resolver.h"
|
||||
|
||||
#include "src/base/utils/random-number-generator.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
|
||||
// The state of our move interpreter is the mapping of operands to values. Note
|
||||
// that the actual values don't really matter, all we care about is equality.
|
||||
class InterpreterState {
|
||||
public:
|
||||
typedef std::vector<MoveOperands> Moves;
|
||||
|
||||
void ExecuteInParallel(Moves moves) {
|
||||
InterpreterState copy(*this);
|
||||
for (Moves::iterator it = moves.begin(); it != moves.end(); ++it) {
|
||||
if (!it->IsRedundant()) write(it->destination(), copy.read(it->source()));
|
||||
}
|
||||
}
|
||||
|
||||
bool operator==(const InterpreterState& other) const {
|
||||
return values_ == other.values_;
|
||||
}
|
||||
|
||||
bool operator!=(const InterpreterState& other) const {
|
||||
return values_ != other.values_;
|
||||
}
|
||||
|
||||
private:
|
||||
// Internally, the state is a normalized permutation of (kind,index) pairs.
|
||||
typedef std::pair<InstructionOperand::Kind, int> Key;
|
||||
typedef Key Value;
|
||||
typedef std::map<Key, Value> OperandMap;
|
||||
|
||||
Value read(const InstructionOperand* op) const {
|
||||
OperandMap::const_iterator it = values_.find(KeyFor(op));
|
||||
return (it == values_.end()) ? ValueFor(op) : it->second;
|
||||
}
|
||||
|
||||
void write(const InstructionOperand* op, Value v) {
|
||||
if (v == ValueFor(op)) {
|
||||
values_.erase(KeyFor(op));
|
||||
} else {
|
||||
values_[KeyFor(op)] = v;
|
||||
}
|
||||
}
|
||||
|
||||
static Key KeyFor(const InstructionOperand* op) {
|
||||
return Key(op->kind(), op->index());
|
||||
}
|
||||
|
||||
static Value ValueFor(const InstructionOperand* op) {
|
||||
return Value(op->kind(), op->index());
|
||||
}
|
||||
|
||||
friend OStream& operator<<(OStream& os, const InterpreterState& is) {
|
||||
for (OperandMap::const_iterator it = is.values_.begin();
|
||||
it != is.values_.end(); ++it) {
|
||||
if (it != is.values_.begin()) os << " ";
|
||||
InstructionOperand source(it->first.first, it->first.second);
|
||||
InstructionOperand destination(it->second.first, it->second.second);
|
||||
os << MoveOperands(&source, &destination);
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
OperandMap values_;
|
||||
};
|
||||
|
||||
|
||||
// An abstract interpreter for moves, swaps and parallel moves.
|
||||
class MoveInterpreter : public GapResolver::Assembler {
|
||||
public:
|
||||
virtual void AssembleMove(InstructionOperand* source,
|
||||
InstructionOperand* destination) V8_OVERRIDE {
|
||||
InterpreterState::Moves moves;
|
||||
moves.push_back(MoveOperands(source, destination));
|
||||
state_.ExecuteInParallel(moves);
|
||||
}
|
||||
|
||||
virtual void AssembleSwap(InstructionOperand* source,
|
||||
InstructionOperand* destination) V8_OVERRIDE {
|
||||
InterpreterState::Moves moves;
|
||||
moves.push_back(MoveOperands(source, destination));
|
||||
moves.push_back(MoveOperands(destination, source));
|
||||
state_.ExecuteInParallel(moves);
|
||||
}
|
||||
|
||||
void AssembleParallelMove(const ParallelMove* pm) {
|
||||
InterpreterState::Moves moves(pm->move_operands()->begin(),
|
||||
pm->move_operands()->end());
|
||||
state_.ExecuteInParallel(moves);
|
||||
}
|
||||
|
||||
InterpreterState state() const { return state_; }
|
||||
|
||||
private:
|
||||
InterpreterState state_;
|
||||
};
|
||||
|
||||
|
||||
class ParallelMoveCreator : public HandleAndZoneScope {
|
||||
public:
|
||||
ParallelMoveCreator() : rng_(CcTest::random_number_generator()) {}
|
||||
|
||||
ParallelMove* Create(int size) {
|
||||
ParallelMove* parallel_move = new (main_zone()) ParallelMove(main_zone());
|
||||
std::set<InstructionOperand*, InstructionOperandComparator> seen;
|
||||
for (int i = 0; i < size; ++i) {
|
||||
MoveOperands mo(CreateRandomOperand(), CreateRandomOperand());
|
||||
if (!mo.IsRedundant() && seen.find(mo.destination()) == seen.end()) {
|
||||
parallel_move->AddMove(mo.source(), mo.destination(), main_zone());
|
||||
seen.insert(mo.destination());
|
||||
}
|
||||
}
|
||||
return parallel_move;
|
||||
}
|
||||
|
||||
private:
|
||||
struct InstructionOperandComparator {
|
||||
bool operator()(const InstructionOperand* x, const InstructionOperand* y) {
|
||||
return (x->kind() < y->kind()) ||
|
||||
(x->kind() == y->kind() && x->index() < y->index());
|
||||
}
|
||||
};
|
||||
|
||||
InstructionOperand* CreateRandomOperand() {
|
||||
int index = rng_->NextInt(6);
|
||||
switch (rng_->NextInt(5)) {
|
||||
case 0:
|
||||
return ConstantOperand::Create(index, main_zone());
|
||||
case 1:
|
||||
return StackSlotOperand::Create(index, main_zone());
|
||||
case 2:
|
||||
return DoubleStackSlotOperand::Create(index, main_zone());
|
||||
case 3:
|
||||
return RegisterOperand::Create(index, main_zone());
|
||||
case 4:
|
||||
return DoubleRegisterOperand::Create(index, main_zone());
|
||||
}
|
||||
UNREACHABLE();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
v8::base::RandomNumberGenerator* rng_;
|
||||
};
|
||||
|
||||
|
||||
TEST(FuzzResolver) {
|
||||
ParallelMoveCreator pmc;
|
||||
for (int size = 0; size < 20; ++size) {
|
||||
for (int repeat = 0; repeat < 50; ++repeat) {
|
||||
ParallelMove* pm = pmc.Create(size);
|
||||
|
||||
// Note: The gap resolver modifies the ParallelMove, so interpret first.
|
||||
MoveInterpreter mi1;
|
||||
mi1.AssembleParallelMove(pm);
|
||||
|
||||
MoveInterpreter mi2;
|
||||
GapResolver resolver(&mi2);
|
||||
resolver.Resolve(pm);
|
||||
|
||||
CHECK(mi1.state() == mi2.state());
|
||||
}
|
||||
}
|
||||
}
|
@ -1,659 +0,0 @@
|
||||
// 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 "src/v8.h"
|
||||
|
||||
#include "graph-tester.h"
|
||||
#include "src/compiler/generic-node-inl.h"
|
||||
#include "src/compiler/graph-reducer.h"
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
|
||||
const uint8_t OPCODE_A0 = 10;
|
||||
const uint8_t OPCODE_A1 = 11;
|
||||
const uint8_t OPCODE_A2 = 12;
|
||||
const uint8_t OPCODE_B0 = 20;
|
||||
const uint8_t OPCODE_B1 = 21;
|
||||
const uint8_t OPCODE_B2 = 22;
|
||||
const uint8_t OPCODE_C0 = 30;
|
||||
const uint8_t OPCODE_C1 = 31;
|
||||
const uint8_t OPCODE_C2 = 32;
|
||||
|
||||
static SimpleOperator OPA0(OPCODE_A0, Operator::kNoWrite, 0, 0, "opa0");
|
||||
static SimpleOperator OPA1(OPCODE_A1, Operator::kNoWrite, 1, 0, "opa1");
|
||||
static SimpleOperator OPA2(OPCODE_A2, Operator::kNoWrite, 2, 0, "opa2");
|
||||
static SimpleOperator OPB0(OPCODE_B0, Operator::kNoWrite, 0, 0, "opa0");
|
||||
static SimpleOperator OPB1(OPCODE_B1, Operator::kNoWrite, 1, 0, "opa1");
|
||||
static SimpleOperator OPB2(OPCODE_B2, Operator::kNoWrite, 2, 0, "opa2");
|
||||
static SimpleOperator OPC0(OPCODE_C0, Operator::kNoWrite, 0, 0, "opc0");
|
||||
static SimpleOperator OPC1(OPCODE_C1, Operator::kNoWrite, 1, 0, "opc1");
|
||||
static SimpleOperator OPC2(OPCODE_C2, Operator::kNoWrite, 2, 0, "opc2");
|
||||
|
||||
|
||||
// Replaces all "A" operators with "B" operators without creating new nodes.
|
||||
class InPlaceABReducer : public Reducer {
|
||||
public:
|
||||
virtual Reduction Reduce(Node* node) {
|
||||
switch (node->op()->opcode()) {
|
||||
case OPCODE_A0:
|
||||
CHECK_EQ(0, node->InputCount());
|
||||
node->set_op(&OPB0);
|
||||
return Replace(node);
|
||||
case OPCODE_A1:
|
||||
CHECK_EQ(1, node->InputCount());
|
||||
node->set_op(&OPB1);
|
||||
return Replace(node);
|
||||
case OPCODE_A2:
|
||||
CHECK_EQ(2, node->InputCount());
|
||||
node->set_op(&OPB2);
|
||||
return Replace(node);
|
||||
}
|
||||
return NoChange();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Replaces all "A" operators with "B" operators by allocating new nodes.
|
||||
class NewABReducer : public Reducer {
|
||||
public:
|
||||
explicit NewABReducer(Graph* graph) : graph_(graph) {}
|
||||
virtual Reduction Reduce(Node* node) {
|
||||
switch (node->op()->opcode()) {
|
||||
case OPCODE_A0:
|
||||
CHECK_EQ(0, node->InputCount());
|
||||
return Replace(graph_->NewNode(&OPB0));
|
||||
case OPCODE_A1:
|
||||
CHECK_EQ(1, node->InputCount());
|
||||
return Replace(graph_->NewNode(&OPB1, node->InputAt(0)));
|
||||
case OPCODE_A2:
|
||||
CHECK_EQ(2, node->InputCount());
|
||||
return Replace(
|
||||
graph_->NewNode(&OPB2, node->InputAt(0), node->InputAt(1)));
|
||||
}
|
||||
return NoChange();
|
||||
}
|
||||
Graph* graph_;
|
||||
};
|
||||
|
||||
|
||||
// Replaces all "B" operators with "C" operators without creating new nodes.
|
||||
class InPlaceBCReducer : public Reducer {
|
||||
public:
|
||||
virtual Reduction Reduce(Node* node) {
|
||||
switch (node->op()->opcode()) {
|
||||
case OPCODE_B0:
|
||||
CHECK_EQ(0, node->InputCount());
|
||||
node->set_op(&OPC0);
|
||||
return Replace(node);
|
||||
case OPCODE_B1:
|
||||
CHECK_EQ(1, node->InputCount());
|
||||
node->set_op(&OPC1);
|
||||
return Replace(node);
|
||||
case OPCODE_B2:
|
||||
CHECK_EQ(2, node->InputCount());
|
||||
node->set_op(&OPC2);
|
||||
return Replace(node);
|
||||
}
|
||||
return NoChange();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Wraps all "OPA0" nodes in "OPB1" operators by allocating new nodes.
|
||||
class A0Wrapper V8_FINAL : public Reducer {
|
||||
public:
|
||||
explicit A0Wrapper(Graph* graph) : graph_(graph) {}
|
||||
virtual Reduction Reduce(Node* node) V8_OVERRIDE {
|
||||
switch (node->op()->opcode()) {
|
||||
case OPCODE_A0:
|
||||
CHECK_EQ(0, node->InputCount());
|
||||
return Replace(graph_->NewNode(&OPB1, node));
|
||||
}
|
||||
return NoChange();
|
||||
}
|
||||
Graph* graph_;
|
||||
};
|
||||
|
||||
|
||||
// Wraps all "OPB0" nodes in two "OPC1" operators by allocating new nodes.
|
||||
class B0Wrapper V8_FINAL : public Reducer {
|
||||
public:
|
||||
explicit B0Wrapper(Graph* graph) : graph_(graph) {}
|
||||
virtual Reduction Reduce(Node* node) V8_OVERRIDE {
|
||||
switch (node->op()->opcode()) {
|
||||
case OPCODE_B0:
|
||||
CHECK_EQ(0, node->InputCount());
|
||||
return Replace(graph_->NewNode(&OPC1, graph_->NewNode(&OPC1, node)));
|
||||
}
|
||||
return NoChange();
|
||||
}
|
||||
Graph* graph_;
|
||||
};
|
||||
|
||||
|
||||
// Replaces all "OPA1" nodes with the first input.
|
||||
class A1Forwarder : public Reducer {
|
||||
virtual Reduction Reduce(Node* node) {
|
||||
switch (node->op()->opcode()) {
|
||||
case OPCODE_A1:
|
||||
CHECK_EQ(1, node->InputCount());
|
||||
return Replace(node->InputAt(0));
|
||||
}
|
||||
return NoChange();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Replaces all "OPB1" nodes with the first input.
|
||||
class B1Forwarder : public Reducer {
|
||||
virtual Reduction Reduce(Node* node) {
|
||||
switch (node->op()->opcode()) {
|
||||
case OPCODE_B1:
|
||||
CHECK_EQ(1, node->InputCount());
|
||||
return Replace(node->InputAt(0));
|
||||
}
|
||||
return NoChange();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Swaps the inputs to "OP2A" and "OP2B" nodes based on ids.
|
||||
class AB2Sorter : public Reducer {
|
||||
virtual Reduction Reduce(Node* node) {
|
||||
switch (node->op()->opcode()) {
|
||||
case OPCODE_A2:
|
||||
case OPCODE_B2:
|
||||
CHECK_EQ(2, node->InputCount());
|
||||
Node* x = node->InputAt(0);
|
||||
Node* y = node->InputAt(1);
|
||||
if (x->id() > y->id()) {
|
||||
node->ReplaceInput(0, y);
|
||||
node->ReplaceInput(1, x);
|
||||
return Replace(node);
|
||||
}
|
||||
}
|
||||
return NoChange();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Simply records the nodes visited.
|
||||
class ReducerRecorder : public Reducer {
|
||||
public:
|
||||
explicit ReducerRecorder(Zone* zone)
|
||||
: set(NodeSet::key_compare(), NodeSet::allocator_type(zone)) {}
|
||||
virtual Reduction Reduce(Node* node) {
|
||||
set.insert(node);
|
||||
return NoChange();
|
||||
}
|
||||
void CheckContains(Node* node) { CHECK_EQ(1, set.count(node)); }
|
||||
NodeSet set;
|
||||
};
|
||||
|
||||
|
||||
TEST(ReduceGraphFromEnd1) {
|
||||
GraphTester graph;
|
||||
|
||||
Node* n1 = graph.NewNode(&OPA0);
|
||||
Node* end = graph.NewNode(&OPA1, n1);
|
||||
graph.SetEnd(end);
|
||||
|
||||
GraphReducer reducer(&graph);
|
||||
ReducerRecorder recorder(graph.zone());
|
||||
reducer.AddReducer(&recorder);
|
||||
reducer.ReduceGraph();
|
||||
recorder.CheckContains(n1);
|
||||
recorder.CheckContains(end);
|
||||
}
|
||||
|
||||
|
||||
TEST(ReduceGraphFromEnd2) {
|
||||
GraphTester graph;
|
||||
|
||||
Node* n1 = graph.NewNode(&OPA0);
|
||||
Node* n2 = graph.NewNode(&OPA1, n1);
|
||||
Node* n3 = graph.NewNode(&OPA1, n1);
|
||||
Node* end = graph.NewNode(&OPA2, n2, n3);
|
||||
graph.SetEnd(end);
|
||||
|
||||
GraphReducer reducer(&graph);
|
||||
ReducerRecorder recorder(graph.zone());
|
||||
reducer.AddReducer(&recorder);
|
||||
reducer.ReduceGraph();
|
||||
recorder.CheckContains(n1);
|
||||
recorder.CheckContains(n2);
|
||||
recorder.CheckContains(n3);
|
||||
recorder.CheckContains(end);
|
||||
}
|
||||
|
||||
|
||||
TEST(ReduceInPlace1) {
|
||||
GraphTester graph;
|
||||
|
||||
Node* n1 = graph.NewNode(&OPA0);
|
||||
Node* end = graph.NewNode(&OPA1, n1);
|
||||
graph.SetEnd(end);
|
||||
|
||||
GraphReducer reducer(&graph);
|
||||
InPlaceABReducer r;
|
||||
reducer.AddReducer(&r);
|
||||
|
||||
// Tests A* => B* with in-place updates.
|
||||
for (int i = 0; i < 3; i++) {
|
||||
int before = graph.NodeCount();
|
||||
reducer.ReduceGraph();
|
||||
CHECK_EQ(before, graph.NodeCount());
|
||||
CHECK_EQ(&OPB0, n1->op());
|
||||
CHECK_EQ(&OPB1, end->op());
|
||||
CHECK_EQ(n1, end->InputAt(0));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(ReduceInPlace2) {
|
||||
GraphTester graph;
|
||||
|
||||
Node* n1 = graph.NewNode(&OPA0);
|
||||
Node* n2 = graph.NewNode(&OPA1, n1);
|
||||
Node* n3 = graph.NewNode(&OPA1, n1);
|
||||
Node* end = graph.NewNode(&OPA2, n2, n3);
|
||||
graph.SetEnd(end);
|
||||
|
||||
GraphReducer reducer(&graph);
|
||||
InPlaceABReducer r;
|
||||
reducer.AddReducer(&r);
|
||||
|
||||
// Tests A* => B* with in-place updates.
|
||||
for (int i = 0; i < 3; i++) {
|
||||
int before = graph.NodeCount();
|
||||
reducer.ReduceGraph();
|
||||
CHECK_EQ(before, graph.NodeCount());
|
||||
CHECK_EQ(&OPB0, n1->op());
|
||||
CHECK_EQ(&OPB1, n2->op());
|
||||
CHECK_EQ(n1, n2->InputAt(0));
|
||||
CHECK_EQ(&OPB1, n3->op());
|
||||
CHECK_EQ(n1, n3->InputAt(0));
|
||||
CHECK_EQ(&OPB2, end->op());
|
||||
CHECK_EQ(n2, end->InputAt(0));
|
||||
CHECK_EQ(n3, end->InputAt(1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(ReduceNew1) {
|
||||
GraphTester graph;
|
||||
|
||||
Node* n1 = graph.NewNode(&OPA0);
|
||||
Node* n2 = graph.NewNode(&OPA1, n1);
|
||||
Node* n3 = graph.NewNode(&OPA1, n1);
|
||||
Node* end = graph.NewNode(&OPA2, n2, n3);
|
||||
graph.SetEnd(end);
|
||||
|
||||
GraphReducer reducer(&graph);
|
||||
NewABReducer r(&graph);
|
||||
reducer.AddReducer(&r);
|
||||
|
||||
// Tests A* => B* while creating new nodes.
|
||||
for (int i = 0; i < 3; i++) {
|
||||
int before = graph.NodeCount();
|
||||
reducer.ReduceGraph();
|
||||
if (i == 0) {
|
||||
CHECK_NE(before, graph.NodeCount());
|
||||
} else {
|
||||
CHECK_EQ(before, graph.NodeCount());
|
||||
}
|
||||
Node* nend = graph.end();
|
||||
CHECK_NE(end, nend); // end() should be updated too.
|
||||
|
||||
Node* nn2 = nend->InputAt(0);
|
||||
Node* nn3 = nend->InputAt(1);
|
||||
Node* nn1 = nn2->InputAt(0);
|
||||
|
||||
CHECK_EQ(nn1, nn3->InputAt(0));
|
||||
|
||||
CHECK_EQ(&OPB0, nn1->op());
|
||||
CHECK_EQ(&OPB1, nn2->op());
|
||||
CHECK_EQ(&OPB1, nn3->op());
|
||||
CHECK_EQ(&OPB2, nend->op());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(Wrapping1) {
|
||||
GraphTester graph;
|
||||
|
||||
Node* end = graph.NewNode(&OPA0);
|
||||
graph.SetEnd(end);
|
||||
CHECK_EQ(1, graph.NodeCount());
|
||||
|
||||
GraphReducer reducer(&graph);
|
||||
A0Wrapper r(&graph);
|
||||
reducer.AddReducer(&r);
|
||||
|
||||
reducer.ReduceGraph();
|
||||
CHECK_EQ(2, graph.NodeCount());
|
||||
|
||||
Node* nend = graph.end();
|
||||
CHECK_NE(end, nend);
|
||||
CHECK_EQ(&OPB1, nend->op());
|
||||
CHECK_EQ(1, nend->InputCount());
|
||||
CHECK_EQ(end, nend->InputAt(0));
|
||||
}
|
||||
|
||||
|
||||
TEST(Wrapping2) {
|
||||
GraphTester graph;
|
||||
|
||||
Node* end = graph.NewNode(&OPB0);
|
||||
graph.SetEnd(end);
|
||||
CHECK_EQ(1, graph.NodeCount());
|
||||
|
||||
GraphReducer reducer(&graph);
|
||||
B0Wrapper r(&graph);
|
||||
reducer.AddReducer(&r);
|
||||
|
||||
reducer.ReduceGraph();
|
||||
CHECK_EQ(3, graph.NodeCount());
|
||||
|
||||
Node* nend = graph.end();
|
||||
CHECK_NE(end, nend);
|
||||
CHECK_EQ(&OPC1, nend->op());
|
||||
CHECK_EQ(1, nend->InputCount());
|
||||
|
||||
Node* n1 = nend->InputAt(0);
|
||||
CHECK_NE(end, n1);
|
||||
CHECK_EQ(&OPC1, n1->op());
|
||||
CHECK_EQ(1, n1->InputCount());
|
||||
CHECK_EQ(end, n1->InputAt(0));
|
||||
}
|
||||
|
||||
|
||||
TEST(Forwarding1) {
|
||||
GraphTester graph;
|
||||
|
||||
Node* n1 = graph.NewNode(&OPA0);
|
||||
Node* end = graph.NewNode(&OPA1, n1);
|
||||
graph.SetEnd(end);
|
||||
|
||||
GraphReducer reducer(&graph);
|
||||
A1Forwarder r;
|
||||
reducer.AddReducer(&r);
|
||||
|
||||
// Tests A1(x) => x
|
||||
for (int i = 0; i < 3; i++) {
|
||||
int before = graph.NodeCount();
|
||||
reducer.ReduceGraph();
|
||||
CHECK_EQ(before, graph.NodeCount());
|
||||
CHECK_EQ(&OPA0, n1->op());
|
||||
CHECK_EQ(n1, graph.end());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(Forwarding2) {
|
||||
GraphTester graph;
|
||||
|
||||
Node* n1 = graph.NewNode(&OPA0);
|
||||
Node* n2 = graph.NewNode(&OPA1, n1);
|
||||
Node* n3 = graph.NewNode(&OPA1, n1);
|
||||
Node* end = graph.NewNode(&OPA2, n2, n3);
|
||||
graph.SetEnd(end);
|
||||
|
||||
GraphReducer reducer(&graph);
|
||||
A1Forwarder r;
|
||||
reducer.AddReducer(&r);
|
||||
|
||||
// Tests reducing A2(A1(x), A1(y)) => A2(x, y).
|
||||
for (int i = 0; i < 3; i++) {
|
||||
int before = graph.NodeCount();
|
||||
reducer.ReduceGraph();
|
||||
CHECK_EQ(before, graph.NodeCount());
|
||||
CHECK_EQ(&OPA0, n1->op());
|
||||
CHECK_EQ(n1, end->InputAt(0));
|
||||
CHECK_EQ(n1, end->InputAt(1));
|
||||
CHECK_EQ(&OPA2, end->op());
|
||||
CHECK_EQ(0, n2->UseCount());
|
||||
CHECK_EQ(0, n3->UseCount());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(Forwarding3) {
|
||||
// Tests reducing a chain of A1(A1(A1(A1(x)))) => x.
|
||||
for (int i = 0; i < 8; i++) {
|
||||
GraphTester graph;
|
||||
|
||||
Node* n1 = graph.NewNode(&OPA0);
|
||||
Node* end = n1;
|
||||
for (int j = 0; j < i; j++) {
|
||||
end = graph.NewNode(&OPA1, end);
|
||||
}
|
||||
graph.SetEnd(end);
|
||||
|
||||
GraphReducer reducer(&graph);
|
||||
A1Forwarder r;
|
||||
reducer.AddReducer(&r);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
int before = graph.NodeCount();
|
||||
reducer.ReduceGraph();
|
||||
CHECK_EQ(before, graph.NodeCount());
|
||||
CHECK_EQ(&OPA0, n1->op());
|
||||
CHECK_EQ(n1, graph.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(ReduceForward1) {
|
||||
GraphTester graph;
|
||||
|
||||
Node* n1 = graph.NewNode(&OPA0);
|
||||
Node* n2 = graph.NewNode(&OPA1, n1);
|
||||
Node* n3 = graph.NewNode(&OPA1, n1);
|
||||
Node* end = graph.NewNode(&OPA2, n2, n3);
|
||||
graph.SetEnd(end);
|
||||
|
||||
GraphReducer reducer(&graph);
|
||||
InPlaceABReducer r;
|
||||
B1Forwarder f;
|
||||
reducer.AddReducer(&r);
|
||||
reducer.AddReducer(&f);
|
||||
|
||||
// Tests first reducing A => B, then B1(x) => x.
|
||||
for (int i = 0; i < 3; i++) {
|
||||
int before = graph.NodeCount();
|
||||
reducer.ReduceGraph();
|
||||
CHECK_EQ(before, graph.NodeCount());
|
||||
CHECK_EQ(&OPB0, n1->op());
|
||||
CHECK_EQ(&OPB1, n2->op());
|
||||
CHECK_EQ(n1, end->InputAt(0));
|
||||
CHECK_EQ(&OPB1, n3->op());
|
||||
CHECK_EQ(n1, end->InputAt(0));
|
||||
CHECK_EQ(&OPB2, end->op());
|
||||
CHECK_EQ(0, n2->UseCount());
|
||||
CHECK_EQ(0, n3->UseCount());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(Sorter1) {
|
||||
HandleAndZoneScope scope;
|
||||
AB2Sorter r;
|
||||
for (int i = 0; i < 6; i++) {
|
||||
GraphTester graph;
|
||||
|
||||
Node* n1 = graph.NewNode(&OPA0);
|
||||
Node* n2 = graph.NewNode(&OPA1, n1);
|
||||
Node* n3 = graph.NewNode(&OPA1, n1);
|
||||
Node* end;
|
||||
|
||||
if (i == 0) end = graph.NewNode(&OPA2, n2, n3);
|
||||
if (i == 1) end = graph.NewNode(&OPA2, n3, n2);
|
||||
if (i == 2) end = graph.NewNode(&OPA2, n2, n1);
|
||||
if (i == 3) end = graph.NewNode(&OPA2, n1, n2);
|
||||
if (i == 4) end = graph.NewNode(&OPA2, n3, n1);
|
||||
if (i == 5) end = graph.NewNode(&OPA2, n1, n3);
|
||||
|
||||
graph.SetEnd(end);
|
||||
|
||||
GraphReducer reducer(&graph);
|
||||
reducer.AddReducer(&r);
|
||||
|
||||
int before = graph.NodeCount();
|
||||
reducer.ReduceGraph();
|
||||
CHECK_EQ(before, graph.NodeCount());
|
||||
CHECK_EQ(&OPA0, n1->op());
|
||||
CHECK_EQ(&OPA1, n2->op());
|
||||
CHECK_EQ(&OPA1, n3->op());
|
||||
CHECK_EQ(&OPA2, end->op());
|
||||
CHECK_EQ(end, graph.end());
|
||||
CHECK(end->InputAt(0)->id() <= end->InputAt(1)->id());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Generate a node graph with the given permutations.
|
||||
void GenDAG(Graph* graph, int* p3, int* p2, int* p1) {
|
||||
Node* level4 = graph->NewNode(&OPA0);
|
||||
Node* level3[] = {graph->NewNode(&OPA1, level4),
|
||||
graph->NewNode(&OPA1, level4)};
|
||||
|
||||
Node* level2[] = {graph->NewNode(&OPA1, level3[p3[0]]),
|
||||
graph->NewNode(&OPA1, level3[p3[1]]),
|
||||
graph->NewNode(&OPA1, level3[p3[0]]),
|
||||
graph->NewNode(&OPA1, level3[p3[1]])};
|
||||
|
||||
Node* level1[] = {graph->NewNode(&OPA2, level2[p2[0]], level2[p2[1]]),
|
||||
graph->NewNode(&OPA2, level2[p2[2]], level2[p2[3]])};
|
||||
|
||||
Node* end = graph->NewNode(&OPA2, level1[p1[0]], level1[p1[1]]);
|
||||
graph->SetEnd(end);
|
||||
}
|
||||
|
||||
|
||||
TEST(SortForwardReduce) {
|
||||
GraphTester graph;
|
||||
|
||||
// Tests combined reductions on a series of DAGs.
|
||||
for (int j = 0; j < 2; j++) {
|
||||
int p3[] = {j, 1 - j};
|
||||
for (int m = 0; m < 2; m++) {
|
||||
int p1[] = {m, 1 - m};
|
||||
for (int k = 0; k < 24; k++) { // All permutations of 0, 1, 2, 3
|
||||
int p2[] = {-1, -1, -1, -1};
|
||||
int n = k;
|
||||
for (int d = 4; d >= 1; d--) { // Construct permutation.
|
||||
int p = n % d;
|
||||
for (int z = 0; z < 4; z++) {
|
||||
if (p2[z] == -1) {
|
||||
if (p == 0) p2[z] = d - 1;
|
||||
p--;
|
||||
}
|
||||
}
|
||||
n = n / d;
|
||||
}
|
||||
|
||||
GenDAG(&graph, p3, p2, p1);
|
||||
|
||||
GraphReducer reducer(&graph);
|
||||
AB2Sorter r1;
|
||||
A1Forwarder r2;
|
||||
InPlaceABReducer r3;
|
||||
reducer.AddReducer(&r1);
|
||||
reducer.AddReducer(&r2);
|
||||
reducer.AddReducer(&r3);
|
||||
|
||||
reducer.ReduceGraph();
|
||||
|
||||
Node* end = graph.end();
|
||||
CHECK_EQ(&OPB2, end->op());
|
||||
Node* n1 = end->InputAt(0);
|
||||
Node* n2 = end->InputAt(1);
|
||||
CHECK_NE(n1, n2);
|
||||
CHECK(n1->id() < n2->id());
|
||||
CHECK_EQ(&OPB2, n1->op());
|
||||
CHECK_EQ(&OPB2, n2->op());
|
||||
Node* n4 = n1->InputAt(0);
|
||||
CHECK_EQ(&OPB0, n4->op());
|
||||
CHECK_EQ(n4, n1->InputAt(1));
|
||||
CHECK_EQ(n4, n2->InputAt(0));
|
||||
CHECK_EQ(n4, n2->InputAt(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(Order) {
|
||||
// Test that the order of reducers doesn't matter, as they should be
|
||||
// rerun for changed nodes.
|
||||
for (int i = 0; i < 2; i++) {
|
||||
GraphTester graph;
|
||||
|
||||
Node* n1 = graph.NewNode(&OPA0);
|
||||
Node* end = graph.NewNode(&OPA1, n1);
|
||||
graph.SetEnd(end);
|
||||
|
||||
GraphReducer reducer(&graph);
|
||||
InPlaceABReducer abr;
|
||||
InPlaceBCReducer bcr;
|
||||
if (i == 0) {
|
||||
reducer.AddReducer(&abr);
|
||||
reducer.AddReducer(&bcr);
|
||||
} else {
|
||||
reducer.AddReducer(&bcr);
|
||||
reducer.AddReducer(&abr);
|
||||
}
|
||||
|
||||
// Tests A* => C* with in-place updates.
|
||||
for (int i = 0; i < 3; i++) {
|
||||
int before = graph.NodeCount();
|
||||
reducer.ReduceGraph();
|
||||
CHECK_EQ(before, graph.NodeCount());
|
||||
CHECK_EQ(&OPC0, n1->op());
|
||||
CHECK_EQ(&OPC1, end->op());
|
||||
CHECK_EQ(n1, end->InputAt(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Tests that a reducer is only applied once.
|
||||
class OneTimeReducer : public Reducer {
|
||||
public:
|
||||
OneTimeReducer(Reducer* reducer, Zone* zone)
|
||||
: reducer_(reducer),
|
||||
nodes_(NodeSet::key_compare(), NodeSet::allocator_type(zone)) {}
|
||||
virtual Reduction Reduce(Node* node) {
|
||||
CHECK_EQ(0, nodes_.count(node));
|
||||
nodes_.insert(node);
|
||||
return reducer_->Reduce(node);
|
||||
}
|
||||
Reducer* reducer_;
|
||||
NodeSet nodes_;
|
||||
};
|
||||
|
||||
|
||||
TEST(OneTimeReduce1) {
|
||||
GraphTester graph;
|
||||
|
||||
Node* n1 = graph.NewNode(&OPA0);
|
||||
Node* end = graph.NewNode(&OPA1, n1);
|
||||
graph.SetEnd(end);
|
||||
|
||||
GraphReducer reducer(&graph);
|
||||
InPlaceABReducer r;
|
||||
OneTimeReducer once(&r, graph.zone());
|
||||
reducer.AddReducer(&once);
|
||||
|
||||
// Tests A* => B* with in-place updates. Should only be applied once.
|
||||
int before = graph.NodeCount();
|
||||
reducer.ReduceGraph();
|
||||
CHECK_EQ(before, graph.NodeCount());
|
||||
CHECK_EQ(&OPB0, n1->op());
|
||||
CHECK_EQ(&OPB1, end->op());
|
||||
CHECK_EQ(n1, end->InputAt(0));
|
||||
}
|
@ -1,977 +0,0 @@
|
||||
// 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 <list>
|
||||
|
||||
#include "test/cctest/compiler/instruction-selector-tester.h"
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
|
||||
namespace {
|
||||
|
||||
typedef RawMachineAssembler::Label MLabel;
|
||||
|
||||
struct DPI {
|
||||
Operator* op;
|
||||
ArchOpcode arch_opcode;
|
||||
ArchOpcode reverse_arch_opcode;
|
||||
ArchOpcode test_arch_opcode;
|
||||
};
|
||||
|
||||
|
||||
// ARM data processing instructions.
|
||||
class DPIs V8_FINAL : public std::list<DPI>, private HandleAndZoneScope {
|
||||
public:
|
||||
DPIs() {
|
||||
MachineOperatorBuilder machine(main_zone());
|
||||
DPI and_ = {machine.Word32And(), kArmAnd, kArmAnd, kArmTst};
|
||||
push_back(and_);
|
||||
DPI or_ = {machine.Word32Or(), kArmOrr, kArmOrr, kArmOrr};
|
||||
push_back(or_);
|
||||
DPI xor_ = {machine.Word32Xor(), kArmEor, kArmEor, kArmTeq};
|
||||
push_back(xor_);
|
||||
DPI add = {machine.Int32Add(), kArmAdd, kArmAdd, kArmCmn};
|
||||
push_back(add);
|
||||
DPI sub = {machine.Int32Sub(), kArmSub, kArmRsb, kArmCmp};
|
||||
push_back(sub);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// ARM immediates.
|
||||
class Immediates V8_FINAL : public std::list<int32_t> {
|
||||
public:
|
||||
Immediates() {
|
||||
for (uint32_t imm8 = 0; imm8 < 256; ++imm8) {
|
||||
for (uint32_t rot4 = 0; rot4 < 32; rot4 += 2) {
|
||||
int32_t imm = (imm8 >> rot4) | (imm8 << (32 - rot4));
|
||||
CHECK(Assembler::ImmediateFitsAddrMode1Instruction(imm));
|
||||
push_back(imm);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Shift {
|
||||
Operator* op;
|
||||
int32_t i_low; // lowest possible immediate
|
||||
int32_t i_high; // highest possible immediate
|
||||
AddressingMode i_mode; // Operand2_R_<shift>_I
|
||||
AddressingMode r_mode; // Operand2_R_<shift>_R
|
||||
};
|
||||
|
||||
|
||||
// ARM shifts.
|
||||
class Shifts V8_FINAL : public std::list<Shift>, private HandleAndZoneScope {
|
||||
public:
|
||||
Shifts() {
|
||||
MachineOperatorBuilder machine(main_zone());
|
||||
Shift sar = {machine.Word32Sar(), 1, 32, kMode_Operand2_R_ASR_I,
|
||||
kMode_Operand2_R_ASR_R};
|
||||
Shift shl = {machine.Word32Shl(), 0, 31, kMode_Operand2_R_LSL_I,
|
||||
kMode_Operand2_R_LSL_R};
|
||||
Shift shr = {machine.Word32Shr(), 1, 32, kMode_Operand2_R_LSR_I,
|
||||
kMode_Operand2_R_LSR_R};
|
||||
push_back(sar);
|
||||
push_back(shl);
|
||||
push_back(shr);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
TEST(InstructionSelectorDPIP) {
|
||||
DPIs dpis;
|
||||
for (DPIs::const_iterator i = dpis.begin(); i != dpis.end(); ++i) {
|
||||
DPI dpi = *i;
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.NewNode(dpi.op, m.Parameter(0), m.Parameter(1)));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(dpi.arch_opcode, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(InstructionSelectorDPIAndShiftP) {
|
||||
DPIs dpis;
|
||||
Shifts shifts;
|
||||
for (DPIs::const_iterator i = dpis.begin(); i != dpis.end(); ++i) {
|
||||
DPI dpi = *i;
|
||||
for (Shifts::const_iterator j = shifts.begin(); j != shifts.end(); ++j) {
|
||||
Shift shift = *j;
|
||||
{
|
||||
InstructionSelectorTester m;
|
||||
m.Return(
|
||||
m.NewNode(dpi.op, m.Parameter(0),
|
||||
m.NewNode(shift.op, m.Parameter(1), m.Parameter(2))));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(dpi.arch_opcode, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode());
|
||||
}
|
||||
{
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.NewNode(dpi.op,
|
||||
m.NewNode(shift.op, m.Parameter(0), m.Parameter(1)),
|
||||
m.Parameter(2)));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(dpi.reverse_arch_opcode, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(InstructionSelectorDPIAndShiftImm) {
|
||||
DPIs dpis;
|
||||
Shifts shifts;
|
||||
for (DPIs::const_iterator i = dpis.begin(); i != dpis.end(); ++i) {
|
||||
DPI dpi = *i;
|
||||
for (Shifts::const_iterator j = shifts.begin(); j != shifts.end(); ++j) {
|
||||
Shift shift = *j;
|
||||
for (int32_t imm = shift.i_low; imm <= shift.i_high; ++imm) {
|
||||
{
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.NewNode(
|
||||
dpi.op, m.Parameter(0),
|
||||
m.NewNode(shift.op, m.Parameter(1), m.Int32Constant(imm))));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(dpi.arch_opcode, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode());
|
||||
}
|
||||
{
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.NewNode(
|
||||
dpi.op, m.NewNode(shift.op, m.Parameter(0), m.Int32Constant(imm)),
|
||||
m.Parameter(1)));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(dpi.reverse_arch_opcode, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(InstructionSelectorWord32AndAndWord32XorWithMinus1P) {
|
||||
{
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Word32And(m.Parameter(0),
|
||||
m.Word32Xor(m.Int32Constant(-1), m.Parameter(1))));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(kArmBic, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode());
|
||||
}
|
||||
{
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Word32And(m.Parameter(0),
|
||||
m.Word32Xor(m.Parameter(1), m.Int32Constant(-1))));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(kArmBic, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode());
|
||||
}
|
||||
{
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Word32And(m.Word32Xor(m.Int32Constant(-1), m.Parameter(0)),
|
||||
m.Parameter(1)));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(kArmBic, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode());
|
||||
}
|
||||
{
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Word32And(m.Word32Xor(m.Parameter(0), m.Int32Constant(-1)),
|
||||
m.Parameter(1)));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(kArmBic, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(InstructionSelectorWord32XorWithMinus1P) {
|
||||
{
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Word32Xor(m.Int32Constant(-1), m.Parameter(0)));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(kArmMvn, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode());
|
||||
}
|
||||
{
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Word32Xor(m.Parameter(0), m.Int32Constant(-1)));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(kArmMvn, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(InstructionSelectorInt32MulP) {
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Int32Mul(m.Parameter(0), m.Parameter(1)));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(kArmMul, m.code[0]->arch_opcode());
|
||||
}
|
||||
|
||||
|
||||
TEST(InstructionSelectorInt32MulImm) {
|
||||
// x * (2^k + 1) -> (x >> k) + x
|
||||
for (int k = 1; k < 31; ++k) {
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Int32Mul(m.Parameter(0), m.Int32Constant((1 << k) + 1)));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(kArmAdd, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(kMode_Operand2_R_LSL_I, m.code[0]->addressing_mode());
|
||||
}
|
||||
// (2^k + 1) * x -> (x >> k) + x
|
||||
for (int k = 1; k < 31; ++k) {
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Int32Mul(m.Int32Constant((1 << k) + 1), m.Parameter(0)));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(kArmAdd, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(kMode_Operand2_R_LSL_I, m.code[0]->addressing_mode());
|
||||
}
|
||||
// x * (2^k - 1) -> (x >> k) - x
|
||||
for (int k = 3; k < 31; ++k) {
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Int32Mul(m.Parameter(0), m.Int32Constant((1 << k) - 1)));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(kArmRsb, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(kMode_Operand2_R_LSL_I, m.code[0]->addressing_mode());
|
||||
}
|
||||
// (2^k - 1) * x -> (x >> k) - x
|
||||
for (int k = 3; k < 31; ++k) {
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Int32Mul(m.Int32Constant((1 << k) - 1), m.Parameter(0)));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(kArmRsb, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(kMode_Operand2_R_LSL_I, m.code[0]->addressing_mode());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// The following tests depend on the exact CPU features available, which we do
|
||||
// only fully control in a simulator build.
|
||||
#ifdef USE_SIMULATOR
|
||||
|
||||
TEST(InstructionSelectorDPIImm_ARMv7AndVFP3Disabled) {
|
||||
i::FLAG_enable_armv7 = false;
|
||||
i::FLAG_enable_vfp3 = false;
|
||||
DPIs dpis;
|
||||
Immediates immediates;
|
||||
for (DPIs::const_iterator i = dpis.begin(); i != dpis.end(); ++i) {
|
||||
DPI dpi = *i;
|
||||
for (Immediates::const_iterator j = immediates.begin();
|
||||
j != immediates.end(); ++j) {
|
||||
int32_t imm = *j;
|
||||
{
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.NewNode(dpi.op, m.Parameter(0), m.Int32Constant(imm)));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(dpi.arch_opcode, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode());
|
||||
}
|
||||
{
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.NewNode(dpi.op, m.Int32Constant(imm), m.Parameter(0)));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(dpi.reverse_arch_opcode, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(InstructionSelectorWord32AndImm_ARMv7Enabled) {
|
||||
i::FLAG_enable_armv7 = true;
|
||||
for (uint32_t width = 1; width <= 32; ++width) {
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Word32And(m.Parameter(0),
|
||||
m.Int32Constant(0xffffffffu >> (32 - width))));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(kArmUbfx, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(3, m.code[0]->InputCount());
|
||||
CHECK_EQ(0, m.ToInt32(m.code[0]->InputAt(1)));
|
||||
CHECK_EQ(width, m.ToInt32(m.code[0]->InputAt(2)));
|
||||
}
|
||||
for (uint32_t lsb = 0; lsb <= 31; ++lsb) {
|
||||
for (uint32_t width = 1; width < 32 - lsb; ++width) {
|
||||
uint32_t msk = ~((0xffffffffu >> (32 - width)) << lsb);
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Word32And(m.Parameter(0), m.Int32Constant(msk)));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(kArmBfc, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(1, m.code[0]->OutputCount());
|
||||
CHECK(UnallocatedOperand::cast(m.code[0]->Output())
|
||||
->HasSameAsInputPolicy());
|
||||
CHECK_EQ(3, m.code[0]->InputCount());
|
||||
CHECK_EQ(lsb, m.ToInt32(m.code[0]->InputAt(1)));
|
||||
CHECK_EQ(width, m.ToInt32(m.code[0]->InputAt(2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(InstructionSelectorWord32AndAndWord32ShrImm_ARMv7Enabled) {
|
||||
i::FLAG_enable_armv7 = true;
|
||||
for (uint32_t lsb = 0; lsb <= 31; ++lsb) {
|
||||
for (uint32_t width = 1; width <= 32 - lsb; ++width) {
|
||||
{
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Word32And(m.Word32Shr(m.Parameter(0), m.Int32Constant(lsb)),
|
||||
m.Int32Constant(0xffffffffu >> (32 - width))));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(kArmUbfx, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(3, m.code[0]->InputCount());
|
||||
CHECK_EQ(lsb, m.ToInt32(m.code[0]->InputAt(1)));
|
||||
CHECK_EQ(width, m.ToInt32(m.code[0]->InputAt(2)));
|
||||
}
|
||||
{
|
||||
InstructionSelectorTester m;
|
||||
m.Return(
|
||||
m.Word32And(m.Int32Constant(0xffffffffu >> (32 - width)),
|
||||
m.Word32Shr(m.Parameter(0), m.Int32Constant(lsb))));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(kArmUbfx, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(3, m.code[0]->InputCount());
|
||||
CHECK_EQ(lsb, m.ToInt32(m.code[0]->InputAt(1)));
|
||||
CHECK_EQ(width, m.ToInt32(m.code[0]->InputAt(2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(InstructionSelectorWord32ShrAndWord32AndImm_ARMv7Enabled) {
|
||||
i::FLAG_enable_armv7 = true;
|
||||
for (uint32_t lsb = 0; lsb <= 31; ++lsb) {
|
||||
for (uint32_t width = 1; width <= 32 - lsb; ++width) {
|
||||
uint32_t max = 1 << lsb;
|
||||
if (max > kMaxInt) max -= 1;
|
||||
uint32_t jnk = CcTest::random_number_generator()->NextInt(max);
|
||||
uint32_t msk = ((0xffffffffu >> (32 - width)) << lsb) | jnk;
|
||||
{
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Word32Shr(m.Word32And(m.Parameter(0), m.Int32Constant(msk)),
|
||||
m.Int32Constant(lsb)));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(kArmUbfx, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(3, m.code[0]->InputCount());
|
||||
CHECK_EQ(lsb, m.ToInt32(m.code[0]->InputAt(1)));
|
||||
CHECK_EQ(width, m.ToInt32(m.code[0]->InputAt(2)));
|
||||
}
|
||||
{
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Word32Shr(m.Word32And(m.Int32Constant(msk), m.Parameter(0)),
|
||||
m.Int32Constant(lsb)));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(kArmUbfx, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(3, m.code[0]->InputCount());
|
||||
CHECK_EQ(lsb, m.ToInt32(m.code[0]->InputAt(1)));
|
||||
CHECK_EQ(width, m.ToInt32(m.code[0]->InputAt(2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(InstructionSelectorInt32SubAndInt32MulP_MlsEnabled) {
|
||||
i::FLAG_enable_mls = true;
|
||||
InstructionSelectorTester m;
|
||||
m.Return(
|
||||
m.Int32Sub(m.Parameter(0), m.Int32Mul(m.Parameter(1), m.Parameter(2))));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(kArmMls, m.code[0]->arch_opcode());
|
||||
}
|
||||
|
||||
|
||||
TEST(InstructionSelectorInt32SubAndInt32MulP_MlsDisabled) {
|
||||
i::FLAG_enable_mls = false;
|
||||
InstructionSelectorTester m;
|
||||
m.Return(
|
||||
m.Int32Sub(m.Parameter(0), m.Int32Mul(m.Parameter(1), m.Parameter(2))));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(2, m.code.size());
|
||||
CHECK_EQ(kArmMul, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(1, m.code[0]->OutputCount());
|
||||
CHECK_EQ(kArmSub, m.code[1]->arch_opcode());
|
||||
CHECK_EQ(2, m.code[1]->InputCount());
|
||||
CheckSameVreg(m.code[0]->Output(), m.code[1]->InputAt(1));
|
||||
}
|
||||
|
||||
|
||||
TEST(InstructionSelectorInt32DivP_ARMv7AndSudivEnabled) {
|
||||
i::FLAG_enable_armv7 = true;
|
||||
i::FLAG_enable_sudiv = true;
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Int32Div(m.Parameter(0), m.Parameter(1)));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(kArmSdiv, m.code[0]->arch_opcode());
|
||||
}
|
||||
|
||||
|
||||
TEST(InstructionSelectorInt32DivP_SudivDisabled) {
|
||||
i::FLAG_enable_sudiv = false;
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Int32Div(m.Parameter(0), m.Parameter(1)));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(4, m.code.size());
|
||||
CHECK_EQ(kArmVcvtF64S32, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(1, m.code[0]->OutputCount());
|
||||
CHECK_EQ(kArmVcvtF64S32, m.code[1]->arch_opcode());
|
||||
CHECK_EQ(1, m.code[1]->OutputCount());
|
||||
CHECK_EQ(kArmVdivF64, m.code[2]->arch_opcode());
|
||||
CHECK_EQ(2, m.code[2]->InputCount());
|
||||
CHECK_EQ(1, m.code[2]->OutputCount());
|
||||
CheckSameVreg(m.code[0]->Output(), m.code[2]->InputAt(0));
|
||||
CheckSameVreg(m.code[1]->Output(), m.code[2]->InputAt(1));
|
||||
CHECK_EQ(kArmVcvtS32F64, m.code[3]->arch_opcode());
|
||||
CHECK_EQ(1, m.code[3]->InputCount());
|
||||
CheckSameVreg(m.code[2]->Output(), m.code[3]->InputAt(0));
|
||||
}
|
||||
|
||||
|
||||
TEST(InstructionSelectorInt32UDivP_ARMv7AndSudivEnabled) {
|
||||
i::FLAG_enable_armv7 = true;
|
||||
i::FLAG_enable_sudiv = true;
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Int32UDiv(m.Parameter(0), m.Parameter(1)));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(kArmUdiv, m.code[0]->arch_opcode());
|
||||
}
|
||||
|
||||
|
||||
TEST(InstructionSelectorInt32UDivP_SudivDisabled) {
|
||||
i::FLAG_enable_sudiv = false;
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Int32UDiv(m.Parameter(0), m.Parameter(1)));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(4, m.code.size());
|
||||
CHECK_EQ(kArmVcvtF64U32, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(1, m.code[0]->OutputCount());
|
||||
CHECK_EQ(kArmVcvtF64U32, m.code[1]->arch_opcode());
|
||||
CHECK_EQ(1, m.code[1]->OutputCount());
|
||||
CHECK_EQ(kArmVdivF64, m.code[2]->arch_opcode());
|
||||
CHECK_EQ(2, m.code[2]->InputCount());
|
||||
CHECK_EQ(1, m.code[2]->OutputCount());
|
||||
CheckSameVreg(m.code[0]->Output(), m.code[2]->InputAt(0));
|
||||
CheckSameVreg(m.code[1]->Output(), m.code[2]->InputAt(1));
|
||||
CHECK_EQ(kArmVcvtU32F64, m.code[3]->arch_opcode());
|
||||
CHECK_EQ(1, m.code[3]->InputCount());
|
||||
CheckSameVreg(m.code[2]->Output(), m.code[3]->InputAt(0));
|
||||
}
|
||||
|
||||
|
||||
TEST(InstructionSelectorInt32ModP_ARMv7AndMlsAndSudivEnabled) {
|
||||
i::FLAG_enable_armv7 = true;
|
||||
i::FLAG_enable_mls = true;
|
||||
i::FLAG_enable_sudiv = true;
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Int32Mod(m.Parameter(0), m.Parameter(1)));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(2, m.code.size());
|
||||
CHECK_EQ(kArmSdiv, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(1, m.code[0]->OutputCount());
|
||||
CHECK_EQ(2, m.code[0]->InputCount());
|
||||
CHECK_EQ(kArmMls, m.code[1]->arch_opcode());
|
||||
CHECK_EQ(1, m.code[1]->OutputCount());
|
||||
CHECK_EQ(3, m.code[1]->InputCount());
|
||||
CheckSameVreg(m.code[0]->Output(), m.code[1]->InputAt(0));
|
||||
CheckSameVreg(m.code[0]->InputAt(1), m.code[1]->InputAt(1));
|
||||
CheckSameVreg(m.code[0]->InputAt(0), m.code[1]->InputAt(2));
|
||||
}
|
||||
|
||||
|
||||
TEST(InstructionSelectorInt32ModP_ARMv7AndSudivEnabled) {
|
||||
i::FLAG_enable_armv7 = true;
|
||||
i::FLAG_enable_mls = false;
|
||||
i::FLAG_enable_sudiv = true;
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Int32Mod(m.Parameter(0), m.Parameter(1)));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(3, m.code.size());
|
||||
CHECK_EQ(kArmSdiv, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(1, m.code[0]->OutputCount());
|
||||
CHECK_EQ(2, m.code[0]->InputCount());
|
||||
CHECK_EQ(kArmMul, m.code[1]->arch_opcode());
|
||||
CHECK_EQ(1, m.code[1]->OutputCount());
|
||||
CHECK_EQ(2, m.code[1]->InputCount());
|
||||
CheckSameVreg(m.code[0]->Output(), m.code[1]->InputAt(0));
|
||||
CheckSameVreg(m.code[0]->InputAt(1), m.code[1]->InputAt(1));
|
||||
CHECK_EQ(kArmSub, m.code[2]->arch_opcode());
|
||||
CHECK_EQ(1, m.code[2]->OutputCount());
|
||||
CHECK_EQ(2, m.code[2]->InputCount());
|
||||
CheckSameVreg(m.code[0]->InputAt(0), m.code[2]->InputAt(0));
|
||||
CheckSameVreg(m.code[1]->Output(), m.code[2]->InputAt(1));
|
||||
}
|
||||
|
||||
|
||||
TEST(InstructionSelectorInt32ModP_ARMv7AndMlsAndSudivDisabled) {
|
||||
i::FLAG_enable_armv7 = false;
|
||||
i::FLAG_enable_mls = false;
|
||||
i::FLAG_enable_sudiv = false;
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Int32Mod(m.Parameter(0), m.Parameter(1)));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(6, m.code.size());
|
||||
CHECK_EQ(kArmVcvtF64S32, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(1, m.code[0]->OutputCount());
|
||||
CHECK_EQ(kArmVcvtF64S32, m.code[1]->arch_opcode());
|
||||
CHECK_EQ(1, m.code[1]->OutputCount());
|
||||
CHECK_EQ(kArmVdivF64, m.code[2]->arch_opcode());
|
||||
CHECK_EQ(2, m.code[2]->InputCount());
|
||||
CHECK_EQ(1, m.code[2]->OutputCount());
|
||||
CheckSameVreg(m.code[0]->Output(), m.code[2]->InputAt(0));
|
||||
CheckSameVreg(m.code[1]->Output(), m.code[2]->InputAt(1));
|
||||
CHECK_EQ(kArmVcvtS32F64, m.code[3]->arch_opcode());
|
||||
CHECK_EQ(1, m.code[3]->InputCount());
|
||||
CheckSameVreg(m.code[2]->Output(), m.code[3]->InputAt(0));
|
||||
CHECK_EQ(kArmMul, m.code[4]->arch_opcode());
|
||||
CHECK_EQ(1, m.code[4]->OutputCount());
|
||||
CHECK_EQ(2, m.code[4]->InputCount());
|
||||
CheckSameVreg(m.code[3]->Output(), m.code[4]->InputAt(0));
|
||||
CheckSameVreg(m.code[1]->InputAt(0), m.code[4]->InputAt(1));
|
||||
CHECK_EQ(kArmSub, m.code[5]->arch_opcode());
|
||||
CHECK_EQ(1, m.code[5]->OutputCount());
|
||||
CHECK_EQ(2, m.code[5]->InputCount());
|
||||
CheckSameVreg(m.code[0]->InputAt(0), m.code[5]->InputAt(0));
|
||||
CheckSameVreg(m.code[4]->Output(), m.code[5]->InputAt(1));
|
||||
}
|
||||
|
||||
|
||||
TEST(InstructionSelectorInt32UModP_ARMv7AndMlsAndSudivEnabled) {
|
||||
i::FLAG_enable_armv7 = true;
|
||||
i::FLAG_enable_mls = true;
|
||||
i::FLAG_enable_sudiv = true;
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Int32UMod(m.Parameter(0), m.Parameter(1)));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(2, m.code.size());
|
||||
CHECK_EQ(kArmUdiv, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(1, m.code[0]->OutputCount());
|
||||
CHECK_EQ(2, m.code[0]->InputCount());
|
||||
CHECK_EQ(kArmMls, m.code[1]->arch_opcode());
|
||||
CHECK_EQ(1, m.code[1]->OutputCount());
|
||||
CHECK_EQ(3, m.code[1]->InputCount());
|
||||
CheckSameVreg(m.code[0]->Output(), m.code[1]->InputAt(0));
|
||||
CheckSameVreg(m.code[0]->InputAt(1), m.code[1]->InputAt(1));
|
||||
CheckSameVreg(m.code[0]->InputAt(0), m.code[1]->InputAt(2));
|
||||
}
|
||||
|
||||
|
||||
TEST(InstructionSelectorInt32UModP_ARMv7AndSudivEnabled) {
|
||||
i::FLAG_enable_armv7 = true;
|
||||
i::FLAG_enable_mls = false;
|
||||
i::FLAG_enable_sudiv = true;
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Int32UMod(m.Parameter(0), m.Parameter(1)));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(3, m.code.size());
|
||||
CHECK_EQ(kArmUdiv, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(1, m.code[0]->OutputCount());
|
||||
CHECK_EQ(2, m.code[0]->InputCount());
|
||||
CHECK_EQ(kArmMul, m.code[1]->arch_opcode());
|
||||
CHECK_EQ(1, m.code[1]->OutputCount());
|
||||
CHECK_EQ(2, m.code[1]->InputCount());
|
||||
CheckSameVreg(m.code[0]->Output(), m.code[1]->InputAt(0));
|
||||
CheckSameVreg(m.code[0]->InputAt(1), m.code[1]->InputAt(1));
|
||||
CHECK_EQ(kArmSub, m.code[2]->arch_opcode());
|
||||
CHECK_EQ(1, m.code[2]->OutputCount());
|
||||
CHECK_EQ(2, m.code[2]->InputCount());
|
||||
CheckSameVreg(m.code[0]->InputAt(0), m.code[2]->InputAt(0));
|
||||
CheckSameVreg(m.code[1]->Output(), m.code[2]->InputAt(1));
|
||||
}
|
||||
|
||||
|
||||
TEST(InstructionSelectorInt32UModP_ARMv7AndMlsAndSudivDisabled) {
|
||||
i::FLAG_enable_armv7 = false;
|
||||
i::FLAG_enable_mls = false;
|
||||
i::FLAG_enable_sudiv = false;
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Int32UMod(m.Parameter(0), m.Parameter(1)));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(6, m.code.size());
|
||||
CHECK_EQ(kArmVcvtF64U32, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(1, m.code[0]->OutputCount());
|
||||
CHECK_EQ(kArmVcvtF64U32, m.code[1]->arch_opcode());
|
||||
CHECK_EQ(1, m.code[1]->OutputCount());
|
||||
CHECK_EQ(kArmVdivF64, m.code[2]->arch_opcode());
|
||||
CHECK_EQ(2, m.code[2]->InputCount());
|
||||
CHECK_EQ(1, m.code[2]->OutputCount());
|
||||
CheckSameVreg(m.code[0]->Output(), m.code[2]->InputAt(0));
|
||||
CheckSameVreg(m.code[1]->Output(), m.code[2]->InputAt(1));
|
||||
CHECK_EQ(kArmVcvtU32F64, m.code[3]->arch_opcode());
|
||||
CHECK_EQ(1, m.code[3]->InputCount());
|
||||
CheckSameVreg(m.code[2]->Output(), m.code[3]->InputAt(0));
|
||||
CHECK_EQ(kArmMul, m.code[4]->arch_opcode());
|
||||
CHECK_EQ(1, m.code[4]->OutputCount());
|
||||
CHECK_EQ(2, m.code[4]->InputCount());
|
||||
CheckSameVreg(m.code[3]->Output(), m.code[4]->InputAt(0));
|
||||
CheckSameVreg(m.code[1]->InputAt(0), m.code[4]->InputAt(1));
|
||||
CHECK_EQ(kArmSub, m.code[5]->arch_opcode());
|
||||
CHECK_EQ(1, m.code[5]->OutputCount());
|
||||
CHECK_EQ(2, m.code[5]->InputCount());
|
||||
CheckSameVreg(m.code[0]->InputAt(0), m.code[5]->InputAt(0));
|
||||
CheckSameVreg(m.code[4]->Output(), m.code[5]->InputAt(1));
|
||||
}
|
||||
|
||||
#endif // USE_SIMULATOR
|
||||
|
||||
|
||||
TEST(InstructionSelectorWord32EqualP) {
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Word32Equal(m.Parameter(0), m.Parameter(1)));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(kArmCmp, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode());
|
||||
CHECK_EQ(kFlags_set, m.code[0]->flags_mode());
|
||||
CHECK_EQ(kEqual, m.code[0]->flags_condition());
|
||||
}
|
||||
|
||||
|
||||
TEST(InstructionSelectorWord32EqualImm) {
|
||||
Immediates immediates;
|
||||
for (Immediates::const_iterator i = immediates.begin(); i != immediates.end();
|
||||
++i) {
|
||||
int32_t imm = *i;
|
||||
{
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(imm)));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
if (imm == 0) {
|
||||
CHECK_EQ(kArmTst, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode());
|
||||
CHECK_EQ(2, m.code[0]->InputCount());
|
||||
CheckSameVreg(m.code[0]->InputAt(0), m.code[0]->InputAt(1));
|
||||
} else {
|
||||
CHECK_EQ(kArmCmp, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode());
|
||||
}
|
||||
CHECK_EQ(kFlags_set, m.code[0]->flags_mode());
|
||||
CHECK_EQ(kEqual, m.code[0]->flags_condition());
|
||||
}
|
||||
{
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Word32Equal(m.Int32Constant(imm), m.Parameter(0)));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
if (imm == 0) {
|
||||
CHECK_EQ(kArmTst, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode());
|
||||
CHECK_EQ(2, m.code[0]->InputCount());
|
||||
CheckSameVreg(m.code[0]->InputAt(0), m.code[0]->InputAt(1));
|
||||
} else {
|
||||
CHECK_EQ(kArmCmp, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode());
|
||||
}
|
||||
CHECK_EQ(kFlags_set, m.code[0]->flags_mode());
|
||||
CHECK_EQ(kEqual, m.code[0]->flags_condition());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(InstructionSelectorWord32EqualAndDPIP) {
|
||||
DPIs dpis;
|
||||
for (DPIs::const_iterator i = dpis.begin(); i != dpis.end(); ++i) {
|
||||
DPI dpi = *i;
|
||||
{
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Word32Equal(m.NewNode(dpi.op, m.Parameter(0), m.Parameter(1)),
|
||||
m.Int32Constant(0)));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(dpi.test_arch_opcode, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode());
|
||||
CHECK_EQ(kFlags_set, m.code[0]->flags_mode());
|
||||
CHECK_EQ(kEqual, m.code[0]->flags_condition());
|
||||
}
|
||||
{
|
||||
InstructionSelectorTester m;
|
||||
m.Return(
|
||||
m.Word32Equal(m.Int32Constant(0),
|
||||
m.NewNode(dpi.op, m.Parameter(0), m.Parameter(1))));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(dpi.test_arch_opcode, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode());
|
||||
CHECK_EQ(kFlags_set, m.code[0]->flags_mode());
|
||||
CHECK_EQ(kEqual, m.code[0]->flags_condition());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(InstructionSelectorWord32EqualAndDPIImm) {
|
||||
DPIs dpis;
|
||||
Immediates immediates;
|
||||
for (DPIs::const_iterator i = dpis.begin(); i != dpis.end(); ++i) {
|
||||
DPI dpi = *i;
|
||||
for (Immediates::const_iterator j = immediates.begin();
|
||||
j != immediates.end(); ++j) {
|
||||
int32_t imm = *j;
|
||||
{
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Word32Equal(
|
||||
m.NewNode(dpi.op, m.Parameter(0), m.Int32Constant(imm)),
|
||||
m.Int32Constant(0)));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(dpi.test_arch_opcode, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode());
|
||||
CHECK_EQ(kFlags_set, m.code[0]->flags_mode());
|
||||
CHECK_EQ(kEqual, m.code[0]->flags_condition());
|
||||
}
|
||||
{
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Word32Equal(
|
||||
m.NewNode(dpi.op, m.Int32Constant(imm), m.Parameter(0)),
|
||||
m.Int32Constant(0)));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(dpi.test_arch_opcode, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode());
|
||||
CHECK_EQ(kFlags_set, m.code[0]->flags_mode());
|
||||
CHECK_EQ(kEqual, m.code[0]->flags_condition());
|
||||
}
|
||||
{
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Word32Equal(
|
||||
m.Int32Constant(0),
|
||||
m.NewNode(dpi.op, m.Parameter(0), m.Int32Constant(imm))));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(dpi.test_arch_opcode, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode());
|
||||
CHECK_EQ(kFlags_set, m.code[0]->flags_mode());
|
||||
CHECK_EQ(kEqual, m.code[0]->flags_condition());
|
||||
}
|
||||
{
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Word32Equal(
|
||||
m.Int32Constant(0),
|
||||
m.NewNode(dpi.op, m.Int32Constant(imm), m.Parameter(0))));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(dpi.test_arch_opcode, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode());
|
||||
CHECK_EQ(kFlags_set, m.code[0]->flags_mode());
|
||||
CHECK_EQ(kEqual, m.code[0]->flags_condition());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(InstructionSelectorWord32EqualAndShiftP) {
|
||||
Shifts shifts;
|
||||
for (Shifts::const_iterator i = shifts.begin(); i != shifts.end(); ++i) {
|
||||
Shift shift = *i;
|
||||
{
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Word32Equal(
|
||||
m.Parameter(0), m.NewNode(shift.op, m.Parameter(1), m.Parameter(2))));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(kArmCmp, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode());
|
||||
CHECK_EQ(kFlags_set, m.code[0]->flags_mode());
|
||||
CHECK_EQ(kEqual, m.code[0]->flags_condition());
|
||||
}
|
||||
{
|
||||
InstructionSelectorTester m;
|
||||
m.Return(m.Word32Equal(
|
||||
m.NewNode(shift.op, m.Parameter(0), m.Parameter(1)), m.Parameter(2)));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(kArmCmp, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode());
|
||||
CHECK_EQ(kFlags_set, m.code[0]->flags_mode());
|
||||
CHECK_EQ(kEqual, m.code[0]->flags_condition());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(InstructionSelectorBranchWithWord32EqualAndShiftP) {
|
||||
Shifts shifts;
|
||||
for (Shifts::const_iterator i = shifts.begin(); i != shifts.end(); ++i) {
|
||||
Shift shift = *i;
|
||||
{
|
||||
InstructionSelectorTester m;
|
||||
MLabel blocka, blockb;
|
||||
m.Branch(m.Word32Equal(m.Parameter(0), m.NewNode(shift.op, m.Parameter(1),
|
||||
m.Parameter(2))),
|
||||
&blocka, &blockb);
|
||||
m.Bind(&blocka);
|
||||
m.Return(m.Int32Constant(1));
|
||||
m.Bind(&blockb);
|
||||
m.Return(m.Int32Constant(0));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(kArmCmp, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode());
|
||||
CHECK_EQ(kFlags_branch, m.code[0]->flags_mode());
|
||||
CHECK_EQ(kEqual, m.code[0]->flags_condition());
|
||||
}
|
||||
{
|
||||
InstructionSelectorTester m;
|
||||
MLabel blocka, blockb;
|
||||
m.Branch(
|
||||
m.Word32Equal(m.NewNode(shift.op, m.Parameter(1), m.Parameter(2)),
|
||||
m.Parameter(0)),
|
||||
&blocka, &blockb);
|
||||
m.Bind(&blocka);
|
||||
m.Return(m.Int32Constant(1));
|
||||
m.Bind(&blockb);
|
||||
m.Return(m.Int32Constant(0));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(kArmCmp, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode());
|
||||
CHECK_EQ(kFlags_branch, m.code[0]->flags_mode());
|
||||
CHECK_EQ(kEqual, m.code[0]->flags_condition());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(InstructionSelectorBranchWithWord32EqualAndShiftImm) {
|
||||
Shifts shifts;
|
||||
for (Shifts::const_iterator i = shifts.begin(); i != shifts.end(); ++i) {
|
||||
Shift shift = *i;
|
||||
for (int32_t imm = shift.i_low; imm <= shift.i_high; ++imm) {
|
||||
{
|
||||
InstructionSelectorTester m;
|
||||
MLabel blocka, blockb;
|
||||
m.Branch(
|
||||
m.Word32Equal(m.Parameter(0), m.NewNode(shift.op, m.Parameter(1),
|
||||
m.Int32Constant(imm))),
|
||||
&blocka, &blockb);
|
||||
m.Bind(&blocka);
|
||||
m.Return(m.Int32Constant(1));
|
||||
m.Bind(&blockb);
|
||||
m.Return(m.Int32Constant(0));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(kArmCmp, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode());
|
||||
CHECK_EQ(kFlags_branch, m.code[0]->flags_mode());
|
||||
CHECK_EQ(kEqual, m.code[0]->flags_condition());
|
||||
}
|
||||
{
|
||||
InstructionSelectorTester m;
|
||||
MLabel blocka, blockb;
|
||||
m.Branch(m.Word32Equal(
|
||||
m.NewNode(shift.op, m.Parameter(1), m.Int32Constant(imm)),
|
||||
m.Parameter(0)),
|
||||
&blocka, &blockb);
|
||||
m.Bind(&blocka);
|
||||
m.Return(m.Int32Constant(1));
|
||||
m.Bind(&blockb);
|
||||
m.Return(m.Int32Constant(0));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(kArmCmp, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode());
|
||||
CHECK_EQ(kFlags_branch, m.code[0]->flags_mode());
|
||||
CHECK_EQ(kEqual, m.code[0]->flags_condition());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(InstructionSelectorBranchWithDPIP) {
|
||||
DPIs dpis;
|
||||
for (DPIs::const_iterator i = dpis.begin(); i != dpis.end(); ++i) {
|
||||
DPI dpi = *i;
|
||||
{
|
||||
InstructionSelectorTester m;
|
||||
MLabel blocka, blockb;
|
||||
m.Branch(m.NewNode(dpi.op, m.Parameter(0), m.Parameter(1)), &blocka,
|
||||
&blockb);
|
||||
m.Bind(&blocka);
|
||||
m.Return(m.Int32Constant(1));
|
||||
m.Bind(&blockb);
|
||||
m.Return(m.Int32Constant(0));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(dpi.test_arch_opcode, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode());
|
||||
CHECK_EQ(kFlags_branch, m.code[0]->flags_mode());
|
||||
CHECK_EQ(kNotEqual, m.code[0]->flags_condition());
|
||||
}
|
||||
{
|
||||
InstructionSelectorTester m;
|
||||
MLabel blocka, blockb;
|
||||
m.Branch(m.Word32Equal(m.Int32Constant(0),
|
||||
m.NewNode(dpi.op, m.Parameter(0), m.Parameter(1))),
|
||||
&blocka, &blockb);
|
||||
m.Bind(&blocka);
|
||||
m.Return(m.Int32Constant(1));
|
||||
m.Bind(&blockb);
|
||||
m.Return(m.Int32Constant(0));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(dpi.test_arch_opcode, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode());
|
||||
CHECK_EQ(kFlags_branch, m.code[0]->flags_mode());
|
||||
CHECK_EQ(kEqual, m.code[0]->flags_condition());
|
||||
}
|
||||
{
|
||||
InstructionSelectorTester m;
|
||||
MLabel blocka, blockb;
|
||||
m.Branch(m.Word32Equal(m.NewNode(dpi.op, m.Parameter(0), m.Parameter(1)),
|
||||
m.Int32Constant(0)),
|
||||
&blocka, &blockb);
|
||||
m.Bind(&blocka);
|
||||
m.Return(m.Int32Constant(1));
|
||||
m.Bind(&blockb);
|
||||
m.Return(m.Int32Constant(0));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(1, m.code.size());
|
||||
CHECK_EQ(dpi.test_arch_opcode, m.code[0]->arch_opcode());
|
||||
CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode());
|
||||
CHECK_EQ(kFlags_branch, m.code[0]->flags_mode());
|
||||
CHECK_EQ(kEqual, m.code[0]->flags_condition());
|
||||
}
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
// 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"
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
|
||||
TEST(InstructionSelectionReturnZero) {
|
||||
InstructionSelectorTester m(InstructionSelectorTester::kInternalMode);
|
||||
m.Return(m.Int32Constant(0));
|
||||
m.SelectInstructions();
|
||||
CHECK_EQ(2, m.code.size());
|
||||
CHECK_EQ(kArchNop, m.code[0]->opcode());
|
||||
CHECK_EQ(kArchRet, m.code[1]->opcode());
|
||||
CHECK_EQ(1, m.code[1]->InputCount());
|
||||
}
|
@ -1,349 +0,0 @@
|
||||
// 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 "src/v8.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
|
||||
#include "src/compiler/code-generator.h"
|
||||
#include "src/compiler/common-operator.h"
|
||||
#include "src/compiler/graph.h"
|
||||
#include "src/compiler/instruction.h"
|
||||
#include "src/compiler/machine-operator.h"
|
||||
#include "src/compiler/node.h"
|
||||
#include "src/compiler/operator.h"
|
||||
#include "src/compiler/schedule.h"
|
||||
#include "src/compiler/scheduler.h"
|
||||
#include "src/lithium.h"
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
|
||||
typedef v8::internal::compiler::Instruction TestInstr;
|
||||
typedef v8::internal::compiler::InstructionSequence TestInstrSeq;
|
||||
|
||||
// A testing helper for the register code abstraction.
|
||||
class InstructionTester : public HandleAndZoneScope {
|
||||
public: // We're all friends here.
|
||||
explicit InstructionTester()
|
||||
: isolate(main_isolate()),
|
||||
graph(zone()),
|
||||
schedule(zone()),
|
||||
info(static_cast<HydrogenCodeStub*>(NULL), main_isolate()),
|
||||
linkage(&info),
|
||||
common(zone()),
|
||||
machine(zone(), kMachineWord32),
|
||||
code(NULL) {}
|
||||
|
||||
Isolate* isolate;
|
||||
Graph graph;
|
||||
Schedule schedule;
|
||||
CompilationInfoWithZone info;
|
||||
Linkage linkage;
|
||||
CommonOperatorBuilder common;
|
||||
MachineOperatorBuilder machine;
|
||||
TestInstrSeq* code;
|
||||
|
||||
Zone* zone() { return main_zone(); }
|
||||
|
||||
void allocCode() {
|
||||
if (schedule.rpo_order()->size() == 0) {
|
||||
// Compute the RPO order.
|
||||
Scheduler scheduler(zone(), &graph, &schedule);
|
||||
scheduler.ComputeSpecialRPO();
|
||||
ASSERT(schedule.rpo_order()->size() > 0);
|
||||
}
|
||||
code = new TestInstrSeq(&linkage, &graph, &schedule);
|
||||
}
|
||||
|
||||
Node* Int32Constant(int32_t val) {
|
||||
Node* node = graph.NewNode(common.Int32Constant(val));
|
||||
schedule.AddNode(schedule.entry(), node);
|
||||
return node;
|
||||
}
|
||||
|
||||
Node* Float64Constant(double val) {
|
||||
Node* node = graph.NewNode(common.Float64Constant(val));
|
||||
schedule.AddNode(schedule.entry(), node);
|
||||
return node;
|
||||
}
|
||||
|
||||
Node* Parameter(int32_t which) {
|
||||
Node* node = graph.NewNode(common.Parameter(which));
|
||||
schedule.AddNode(schedule.entry(), node);
|
||||
return node;
|
||||
}
|
||||
|
||||
Node* NewNode(BasicBlock* block) {
|
||||
Node* node = graph.NewNode(common.Int32Constant(111));
|
||||
schedule.AddNode(block, node);
|
||||
return node;
|
||||
}
|
||||
|
||||
int NewInstr(BasicBlock* block) {
|
||||
InstructionCode opcode = static_cast<InstructionCode>(110);
|
||||
TestInstr* instr = TestInstr::New(zone(), opcode);
|
||||
return code->AddInstruction(instr, block);
|
||||
}
|
||||
|
||||
UnallocatedOperand* NewUnallocated(int vreg) {
|
||||
UnallocatedOperand* unallocated =
|
||||
new (zone()) UnallocatedOperand(UnallocatedOperand::ANY);
|
||||
unallocated->set_virtual_register(vreg);
|
||||
return unallocated;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
TEST(InstructionBasic) {
|
||||
InstructionTester R;
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
R.Int32Constant(i); // Add some nodes to the graph.
|
||||
}
|
||||
|
||||
BasicBlock* last = R.schedule.entry();
|
||||
for (int i = 0; i < 5; i++) {
|
||||
BasicBlock* block = R.schedule.NewBasicBlock();
|
||||
R.schedule.AddGoto(last, block);
|
||||
last = block;
|
||||
}
|
||||
|
||||
R.allocCode();
|
||||
|
||||
CHECK_EQ(R.graph.NodeCount(), R.code->ValueCount());
|
||||
|
||||
BasicBlockVector* blocks = R.schedule.rpo_order();
|
||||
CHECK_EQ(static_cast<int>(blocks->size()), R.code->BasicBlockCount());
|
||||
|
||||
int index = 0;
|
||||
for (BasicBlockVectorIter i = blocks->begin(); i != blocks->end();
|
||||
i++, index++) {
|
||||
BasicBlock* block = *i;
|
||||
CHECK_EQ(block, R.code->BlockAt(index));
|
||||
CHECK_EQ(-1, R.code->GetLoopEnd(block));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(InstructionGetBasicBlock) {
|
||||
InstructionTester R;
|
||||
|
||||
BasicBlock* b0 = R.schedule.entry();
|
||||
BasicBlock* b1 = R.schedule.NewBasicBlock();
|
||||
BasicBlock* b2 = R.schedule.NewBasicBlock();
|
||||
BasicBlock* b3 = R.schedule.exit();
|
||||
|
||||
R.schedule.AddGoto(b0, b1);
|
||||
R.schedule.AddGoto(b1, b2);
|
||||
R.schedule.AddGoto(b2, b3);
|
||||
|
||||
R.allocCode();
|
||||
|
||||
R.code->StartBlock(b0);
|
||||
int i0 = R.NewInstr(b0);
|
||||
int i1 = R.NewInstr(b0);
|
||||
R.code->EndBlock(b0);
|
||||
R.code->StartBlock(b1);
|
||||
int i2 = R.NewInstr(b1);
|
||||
int i3 = R.NewInstr(b1);
|
||||
int i4 = R.NewInstr(b1);
|
||||
int i5 = R.NewInstr(b1);
|
||||
R.code->EndBlock(b1);
|
||||
R.code->StartBlock(b2);
|
||||
int i6 = R.NewInstr(b2);
|
||||
int i7 = R.NewInstr(b2);
|
||||
int i8 = R.NewInstr(b2);
|
||||
R.code->EndBlock(b2);
|
||||
R.code->StartBlock(b3);
|
||||
R.code->EndBlock(b3);
|
||||
|
||||
CHECK_EQ(b0, R.code->GetBasicBlock(i0));
|
||||
CHECK_EQ(b0, R.code->GetBasicBlock(i1));
|
||||
|
||||
CHECK_EQ(b1, R.code->GetBasicBlock(i2));
|
||||
CHECK_EQ(b1, R.code->GetBasicBlock(i3));
|
||||
CHECK_EQ(b1, R.code->GetBasicBlock(i4));
|
||||
CHECK_EQ(b1, R.code->GetBasicBlock(i5));
|
||||
|
||||
CHECK_EQ(b2, R.code->GetBasicBlock(i6));
|
||||
CHECK_EQ(b2, R.code->GetBasicBlock(i7));
|
||||
CHECK_EQ(b2, R.code->GetBasicBlock(i8));
|
||||
|
||||
CHECK_EQ(b0, R.code->GetBasicBlock(b0->first_instruction_index()));
|
||||
CHECK_EQ(b0, R.code->GetBasicBlock(b0->last_instruction_index()));
|
||||
|
||||
CHECK_EQ(b1, R.code->GetBasicBlock(b1->first_instruction_index()));
|
||||
CHECK_EQ(b1, R.code->GetBasicBlock(b1->last_instruction_index()));
|
||||
|
||||
CHECK_EQ(b2, R.code->GetBasicBlock(b2->first_instruction_index()));
|
||||
CHECK_EQ(b2, R.code->GetBasicBlock(b2->last_instruction_index()));
|
||||
|
||||
CHECK_EQ(b3, R.code->GetBasicBlock(b3->first_instruction_index()));
|
||||
CHECK_EQ(b3, R.code->GetBasicBlock(b3->last_instruction_index()));
|
||||
}
|
||||
|
||||
|
||||
TEST(InstructionIsGapAt) {
|
||||
InstructionTester R;
|
||||
|
||||
BasicBlock* b0 = R.schedule.entry();
|
||||
R.schedule.AddReturn(b0, R.Int32Constant(1));
|
||||
|
||||
R.allocCode();
|
||||
TestInstr* i0 = TestInstr::New(R.zone(), 100);
|
||||
TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl();
|
||||
R.code->StartBlock(b0);
|
||||
R.code->AddInstruction(i0, b0);
|
||||
R.code->AddInstruction(g, b0);
|
||||
R.code->EndBlock(b0);
|
||||
|
||||
CHECK_EQ(true, R.code->InstructionAt(0)->IsBlockStart());
|
||||
|
||||
CHECK_EQ(true, R.code->IsGapAt(0)); // Label
|
||||
CHECK_EQ(true, R.code->IsGapAt(1)); // Gap
|
||||
CHECK_EQ(false, R.code->IsGapAt(2)); // i0
|
||||
CHECK_EQ(true, R.code->IsGapAt(3)); // Gap
|
||||
CHECK_EQ(true, R.code->IsGapAt(4)); // Gap
|
||||
CHECK_EQ(false, R.code->IsGapAt(5)); // g
|
||||
}
|
||||
|
||||
|
||||
TEST(InstructionIsGapAt2) {
|
||||
InstructionTester R;
|
||||
|
||||
BasicBlock* b0 = R.schedule.entry();
|
||||
BasicBlock* b1 = R.schedule.exit();
|
||||
R.schedule.AddGoto(b0, b1);
|
||||
R.schedule.AddReturn(b1, R.Int32Constant(1));
|
||||
|
||||
R.allocCode();
|
||||
TestInstr* i0 = TestInstr::New(R.zone(), 100);
|
||||
TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl();
|
||||
R.code->StartBlock(b0);
|
||||
R.code->AddInstruction(i0, b0);
|
||||
R.code->AddInstruction(g, b0);
|
||||
R.code->EndBlock(b0);
|
||||
|
||||
TestInstr* i1 = TestInstr::New(R.zone(), 102);
|
||||
TestInstr* g1 = TestInstr::New(R.zone(), 104)->MarkAsControl();
|
||||
R.code->StartBlock(b1);
|
||||
R.code->AddInstruction(i1, b1);
|
||||
R.code->AddInstruction(g1, b1);
|
||||
R.code->EndBlock(b1);
|
||||
|
||||
CHECK_EQ(true, R.code->InstructionAt(0)->IsBlockStart());
|
||||
|
||||
CHECK_EQ(true, R.code->IsGapAt(0)); // Label
|
||||
CHECK_EQ(true, R.code->IsGapAt(1)); // Gap
|
||||
CHECK_EQ(false, R.code->IsGapAt(2)); // i0
|
||||
CHECK_EQ(true, R.code->IsGapAt(3)); // Gap
|
||||
CHECK_EQ(true, R.code->IsGapAt(4)); // Gap
|
||||
CHECK_EQ(false, R.code->IsGapAt(5)); // g
|
||||
|
||||
CHECK_EQ(true, R.code->InstructionAt(6)->IsBlockStart());
|
||||
|
||||
CHECK_EQ(true, R.code->IsGapAt(6)); // Label
|
||||
CHECK_EQ(true, R.code->IsGapAt(7)); // Gap
|
||||
CHECK_EQ(false, R.code->IsGapAt(8)); // i1
|
||||
CHECK_EQ(true, R.code->IsGapAt(9)); // Gap
|
||||
CHECK_EQ(true, R.code->IsGapAt(10)); // Gap
|
||||
CHECK_EQ(false, R.code->IsGapAt(11)); // g1
|
||||
}
|
||||
|
||||
|
||||
TEST(InstructionAddGapMove) {
|
||||
InstructionTester R;
|
||||
|
||||
BasicBlock* b0 = R.schedule.entry();
|
||||
R.schedule.AddReturn(b0, R.Int32Constant(1));
|
||||
|
||||
R.allocCode();
|
||||
TestInstr* i0 = TestInstr::New(R.zone(), 100);
|
||||
TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl();
|
||||
R.code->StartBlock(b0);
|
||||
R.code->AddInstruction(i0, b0);
|
||||
R.code->AddInstruction(g, b0);
|
||||
R.code->EndBlock(b0);
|
||||
|
||||
CHECK_EQ(true, R.code->InstructionAt(0)->IsBlockStart());
|
||||
|
||||
CHECK_EQ(true, R.code->IsGapAt(0)); // Label
|
||||
CHECK_EQ(true, R.code->IsGapAt(1)); // Gap
|
||||
CHECK_EQ(false, R.code->IsGapAt(2)); // i0
|
||||
CHECK_EQ(true, R.code->IsGapAt(3)); // Gap
|
||||
CHECK_EQ(true, R.code->IsGapAt(4)); // Gap
|
||||
CHECK_EQ(false, R.code->IsGapAt(5)); // g
|
||||
|
||||
int indexes[] = {0, 1, 3, 4, -1};
|
||||
for (int i = 0; indexes[i] >= 0; i++) {
|
||||
int index = indexes[i];
|
||||
|
||||
UnallocatedOperand* op1 = R.NewUnallocated(index + 6);
|
||||
UnallocatedOperand* op2 = R.NewUnallocated(index + 12);
|
||||
|
||||
R.code->AddGapMove(index, op1, op2);
|
||||
GapInstruction* gap = R.code->GapAt(index);
|
||||
ParallelMove* move = gap->GetParallelMove(GapInstruction::START);
|
||||
CHECK_NE(NULL, move);
|
||||
const ZoneList<MoveOperands>* move_operands = move->move_operands();
|
||||
CHECK_EQ(1, move_operands->length());
|
||||
MoveOperands* cur = &move_operands->at(0);
|
||||
CHECK_EQ(op1, cur->source());
|
||||
CHECK_EQ(op2, cur->destination());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(InstructionOperands) {
|
||||
Zone zone(CcTest::InitIsolateOnce());
|
||||
|
||||
{
|
||||
TestInstr* i = TestInstr::New(&zone, 101);
|
||||
CHECK_EQ(0, i->OutputCount());
|
||||
CHECK_EQ(0, i->InputCount());
|
||||
CHECK_EQ(0, i->TempCount());
|
||||
}
|
||||
|
||||
InstructionOperand* outputs[] = {
|
||||
new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
|
||||
new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
|
||||
new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
|
||||
new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER)};
|
||||
|
||||
InstructionOperand* inputs[] = {
|
||||
new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
|
||||
new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
|
||||
new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
|
||||
new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER)};
|
||||
|
||||
InstructionOperand* temps[] = {
|
||||
new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
|
||||
new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
|
||||
new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
|
||||
new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER)};
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(outputs); i++) {
|
||||
for (size_t j = 0; j < ARRAY_SIZE(inputs); j++) {
|
||||
for (size_t k = 0; k < ARRAY_SIZE(temps); k++) {
|
||||
TestInstr* m =
|
||||
TestInstr::New(&zone, 101, i, outputs, j, inputs, k, temps);
|
||||
CHECK(i == m->OutputCount());
|
||||
CHECK(j == m->InputCount());
|
||||
CHECK(k == m->TempCount());
|
||||
|
||||
for (size_t z = 0; z < i; z++) {
|
||||
CHECK_EQ(outputs[z], m->OutputAt(z));
|
||||
}
|
||||
|
||||
for (size_t z = 0; z < j; z++) {
|
||||
CHECK_EQ(inputs[z], m->InputAt(z));
|
||||
}
|
||||
|
||||
for (size_t z = 0; z < k; z++) {
|
||||
CHECK_EQ(temps[z], m->TempAt(z));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,284 +0,0 @@
|
||||
// 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 "src/v8.h"
|
||||
|
||||
#include "src/compiler/js-graph.h"
|
||||
#include "src/compiler/node-properties-inl.h"
|
||||
#include "src/compiler/typer.h"
|
||||
#include "src/types.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
#include "test/cctest/compiler/value-helper.h"
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
|
||||
class JSCacheTesterHelper {
|
||||
protected:
|
||||
explicit JSCacheTesterHelper(Zone* zone)
|
||||
: main_graph_(zone), main_common_(zone), main_typer_(zone) {}
|
||||
Graph main_graph_;
|
||||
CommonOperatorBuilder main_common_;
|
||||
Typer main_typer_;
|
||||
};
|
||||
|
||||
|
||||
class JSConstantCacheTester : public HandleAndZoneScope,
|
||||
public JSCacheTesterHelper,
|
||||
public JSGraph {
|
||||
public:
|
||||
JSConstantCacheTester()
|
||||
: JSCacheTesterHelper(main_zone()),
|
||||
JSGraph(&main_graph_, &main_common_, &main_typer_) {}
|
||||
|
||||
Type* upper(Node* node) { return NodeProperties::GetBounds(node).upper; }
|
||||
|
||||
Handle<Object> handle(Node* node) {
|
||||
CHECK_EQ(IrOpcode::kHeapConstant, node->opcode());
|
||||
return ValueOf<Handle<Object> >(node->op());
|
||||
}
|
||||
|
||||
Factory* factory() { return main_isolate()->factory(); }
|
||||
};
|
||||
|
||||
|
||||
TEST(ZeroConstant1) {
|
||||
JSConstantCacheTester T;
|
||||
|
||||
Node* zero = T.ZeroConstant();
|
||||
|
||||
CHECK_EQ(IrOpcode::kNumberConstant, zero->opcode());
|
||||
CHECK_EQ(zero, T.Constant(0));
|
||||
CHECK_NE(zero, T.Constant(-0.0));
|
||||
CHECK_NE(zero, T.Constant(1.0));
|
||||
CHECK_NE(zero, T.Constant(v8::base::OS::nan_value()));
|
||||
CHECK_NE(zero, T.Float64Constant(0));
|
||||
CHECK_NE(zero, T.Int32Constant(0));
|
||||
|
||||
Type* t = T.upper(zero);
|
||||
|
||||
CHECK(t->Is(Type::Number()));
|
||||
CHECK(t->Is(Type::Integral32()));
|
||||
CHECK(t->Is(Type::Signed32()));
|
||||
CHECK(t->Is(Type::Unsigned32()));
|
||||
CHECK(t->Is(Type::SignedSmall()));
|
||||
CHECK(t->Is(Type::UnsignedSmall()));
|
||||
}
|
||||
|
||||
|
||||
TEST(MinusZeroConstant) {
|
||||
JSConstantCacheTester T;
|
||||
|
||||
Node* minus_zero = T.Constant(-0.0);
|
||||
Node* zero = T.ZeroConstant();
|
||||
|
||||
CHECK_EQ(IrOpcode::kNumberConstant, minus_zero->opcode());
|
||||
CHECK_EQ(minus_zero, T.Constant(-0.0));
|
||||
CHECK_NE(zero, minus_zero);
|
||||
|
||||
Type* t = T.upper(minus_zero);
|
||||
|
||||
CHECK(t->Is(Type::Number()));
|
||||
CHECK(t->Is(Type::MinusZero()));
|
||||
CHECK(!t->Is(Type::Integral32()));
|
||||
CHECK(!t->Is(Type::Signed32()));
|
||||
CHECK(!t->Is(Type::Unsigned32()));
|
||||
CHECK(!t->Is(Type::SignedSmall()));
|
||||
CHECK(!t->Is(Type::UnsignedSmall()));
|
||||
|
||||
double zero_value = ValueOf<double>(zero->op());
|
||||
double minus_zero_value = ValueOf<double>(minus_zero->op());
|
||||
|
||||
CHECK_EQ(0.0, zero_value);
|
||||
CHECK_NE(-0.0, zero_value);
|
||||
CHECK_EQ(-0.0, minus_zero_value);
|
||||
CHECK_NE(0.0, minus_zero_value);
|
||||
}
|
||||
|
||||
|
||||
TEST(ZeroConstant2) {
|
||||
JSConstantCacheTester T;
|
||||
|
||||
Node* zero = T.Constant(0);
|
||||
|
||||
CHECK_EQ(IrOpcode::kNumberConstant, zero->opcode());
|
||||
CHECK_EQ(zero, T.ZeroConstant());
|
||||
CHECK_NE(zero, T.Constant(-0.0));
|
||||
CHECK_NE(zero, T.Constant(1.0));
|
||||
CHECK_NE(zero, T.Constant(v8::base::OS::nan_value()));
|
||||
CHECK_NE(zero, T.Float64Constant(0));
|
||||
CHECK_NE(zero, T.Int32Constant(0));
|
||||
|
||||
Type* t = T.upper(zero);
|
||||
|
||||
CHECK(t->Is(Type::Number()));
|
||||
CHECK(t->Is(Type::Integral32()));
|
||||
CHECK(t->Is(Type::Signed32()));
|
||||
CHECK(t->Is(Type::Unsigned32()));
|
||||
CHECK(t->Is(Type::SignedSmall()));
|
||||
CHECK(t->Is(Type::UnsignedSmall()));
|
||||
}
|
||||
|
||||
|
||||
TEST(OneConstant1) {
|
||||
JSConstantCacheTester T;
|
||||
|
||||
Node* one = T.OneConstant();
|
||||
|
||||
CHECK_EQ(IrOpcode::kNumberConstant, one->opcode());
|
||||
CHECK_EQ(one, T.Constant(1));
|
||||
CHECK_EQ(one, T.Constant(1.0));
|
||||
CHECK_NE(one, T.Constant(1.01));
|
||||
CHECK_NE(one, T.Constant(-1.01));
|
||||
CHECK_NE(one, T.Constant(v8::base::OS::nan_value()));
|
||||
CHECK_NE(one, T.Float64Constant(1.0));
|
||||
CHECK_NE(one, T.Int32Constant(1));
|
||||
|
||||
Type* t = T.upper(one);
|
||||
|
||||
CHECK(t->Is(Type::Number()));
|
||||
CHECK(t->Is(Type::Integral32()));
|
||||
CHECK(t->Is(Type::Signed32()));
|
||||
CHECK(t->Is(Type::Unsigned32()));
|
||||
CHECK(t->Is(Type::SignedSmall()));
|
||||
CHECK(t->Is(Type::UnsignedSmall()));
|
||||
}
|
||||
|
||||
|
||||
TEST(OneConstant2) {
|
||||
JSConstantCacheTester T;
|
||||
|
||||
Node* one = T.Constant(1);
|
||||
|
||||
CHECK_EQ(IrOpcode::kNumberConstant, one->opcode());
|
||||
CHECK_EQ(one, T.OneConstant());
|
||||
CHECK_EQ(one, T.Constant(1.0));
|
||||
CHECK_NE(one, T.Constant(1.01));
|
||||
CHECK_NE(one, T.Constant(-1.01));
|
||||
CHECK_NE(one, T.Constant(v8::base::OS::nan_value()));
|
||||
CHECK_NE(one, T.Float64Constant(1.0));
|
||||
CHECK_NE(one, T.Int32Constant(1));
|
||||
|
||||
Type* t = T.upper(one);
|
||||
|
||||
CHECK(t->Is(Type::Number()));
|
||||
CHECK(t->Is(Type::Integral32()));
|
||||
CHECK(t->Is(Type::Signed32()));
|
||||
CHECK(t->Is(Type::Unsigned32()));
|
||||
CHECK(t->Is(Type::SignedSmall()));
|
||||
CHECK(t->Is(Type::UnsignedSmall()));
|
||||
}
|
||||
|
||||
|
||||
TEST(Canonicalizations) {
|
||||
JSConstantCacheTester T;
|
||||
|
||||
CHECK_EQ(T.ZeroConstant(), T.ZeroConstant());
|
||||
CHECK_EQ(T.UndefinedConstant(), T.UndefinedConstant());
|
||||
CHECK_EQ(T.TheHoleConstant(), T.TheHoleConstant());
|
||||
CHECK_EQ(T.TrueConstant(), T.TrueConstant());
|
||||
CHECK_EQ(T.FalseConstant(), T.FalseConstant());
|
||||
CHECK_EQ(T.NullConstant(), T.NullConstant());
|
||||
CHECK_EQ(T.ZeroConstant(), T.ZeroConstant());
|
||||
CHECK_EQ(T.OneConstant(), T.OneConstant());
|
||||
CHECK_EQ(T.NaNConstant(), T.NaNConstant());
|
||||
}
|
||||
|
||||
|
||||
TEST(NoAliasing) {
|
||||
JSConstantCacheTester T;
|
||||
|
||||
Node* nodes[] = {T.UndefinedConstant(), T.TheHoleConstant(), T.TrueConstant(),
|
||||
T.FalseConstant(), T.NullConstant(), T.ZeroConstant(),
|
||||
T.OneConstant(), T.NaNConstant(), T.Constant(21),
|
||||
T.Constant(22.2)};
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(nodes); i++) {
|
||||
for (size_t j = 0; j < ARRAY_SIZE(nodes); j++) {
|
||||
if (i != j) CHECK_NE(nodes[i], nodes[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(CanonicalizingNumbers) {
|
||||
JSConstantCacheTester T;
|
||||
|
||||
FOR_FLOAT64_INPUTS(i) {
|
||||
Node* node = T.Constant(*i);
|
||||
for (int j = 0; j < 5; j++) {
|
||||
CHECK_EQ(node, T.Constant(*i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(NumberTypes) {
|
||||
JSConstantCacheTester T;
|
||||
|
||||
FOR_FLOAT64_INPUTS(i) {
|
||||
double value = *i;
|
||||
Node* node = T.Constant(value);
|
||||
CHECK(T.upper(node)->Equals(Type::Of(value, T.main_zone())));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(HeapNumbers) {
|
||||
JSConstantCacheTester T;
|
||||
|
||||
FOR_FLOAT64_INPUTS(i) {
|
||||
double value = *i;
|
||||
Handle<Object> num = T.factory()->NewNumber(value);
|
||||
Handle<HeapNumber> heap = T.factory()->NewHeapNumber(value);
|
||||
Node* node1 = T.Constant(value);
|
||||
Node* node2 = T.Constant(num);
|
||||
Node* node3 = T.Constant(heap);
|
||||
CHECK_EQ(node1, node2);
|
||||
CHECK_EQ(node1, node3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(OddballHandle) {
|
||||
JSConstantCacheTester T;
|
||||
|
||||
CHECK_EQ(T.UndefinedConstant(), T.Constant(T.factory()->undefined_value()));
|
||||
CHECK_EQ(T.TheHoleConstant(), T.Constant(T.factory()->the_hole_value()));
|
||||
CHECK_EQ(T.TrueConstant(), T.Constant(T.factory()->true_value()));
|
||||
CHECK_EQ(T.FalseConstant(), T.Constant(T.factory()->false_value()));
|
||||
CHECK_EQ(T.NullConstant(), T.Constant(T.factory()->null_value()));
|
||||
CHECK_EQ(T.NaNConstant(), T.Constant(T.factory()->nan_value()));
|
||||
}
|
||||
|
||||
|
||||
TEST(OddballValues) {
|
||||
JSConstantCacheTester T;
|
||||
|
||||
CHECK_EQ(*T.factory()->undefined_value(), *T.handle(T.UndefinedConstant()));
|
||||
CHECK_EQ(*T.factory()->the_hole_value(), *T.handle(T.TheHoleConstant()));
|
||||
CHECK_EQ(*T.factory()->true_value(), *T.handle(T.TrueConstant()));
|
||||
CHECK_EQ(*T.factory()->false_value(), *T.handle(T.FalseConstant()));
|
||||
CHECK_EQ(*T.factory()->null_value(), *T.handle(T.NullConstant()));
|
||||
}
|
||||
|
||||
|
||||
TEST(OddballTypes) {
|
||||
JSConstantCacheTester T;
|
||||
|
||||
CHECK(T.upper(T.UndefinedConstant())->Is(Type::Undefined()));
|
||||
// TODO(dcarney): figure this out.
|
||||
// CHECK(T.upper(T.TheHoleConstant())->Is(Type::Internal()));
|
||||
CHECK(T.upper(T.TrueConstant())->Is(Type::Boolean()));
|
||||
CHECK(T.upper(T.FalseConstant())->Is(Type::Boolean()));
|
||||
CHECK(T.upper(T.NullConstant())->Is(Type::Null()));
|
||||
CHECK(T.upper(T.ZeroConstant())->Is(Type::Number()));
|
||||
CHECK(T.upper(T.OneConstant())->Is(Type::Number()));
|
||||
CHECK(T.upper(T.NaNConstant())->Is(Type::NaN()));
|
||||
}
|
||||
|
||||
|
||||
TEST(ExternalReferences) {
|
||||
// TODO(titzer): test canonicalization of external references.
|
||||
}
|
@ -1,252 +0,0 @@
|
||||
// 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 "src/compiler/js-context-specialization.h"
|
||||
#include "src/compiler/js-operator.h"
|
||||
#include "src/compiler/node-matchers.h"
|
||||
#include "src/compiler/node-properties-inl.h"
|
||||
#include "src/compiler/simplified-node-factory.h"
|
||||
#include "src/compiler/source-position.h"
|
||||
#include "src/compiler/typer.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
#include "test/cctest/compiler/function-tester.h"
|
||||
#include "test/cctest/compiler/graph-builder-tester.h"
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
|
||||
class ContextSpecializationTester
|
||||
: public HandleAndZoneScope,
|
||||
public DirectGraphBuilder,
|
||||
public SimplifiedNodeFactory<ContextSpecializationTester> {
|
||||
public:
|
||||
ContextSpecializationTester()
|
||||
: DirectGraphBuilder(new (main_zone()) Graph(main_zone())),
|
||||
common_(main_zone()),
|
||||
javascript_(main_zone()),
|
||||
simplified_(main_zone()),
|
||||
typer_(main_zone()),
|
||||
jsgraph_(graph(), common(), &typer_),
|
||||
info_(main_isolate(), main_zone()) {}
|
||||
|
||||
Factory* factory() { return main_isolate()->factory(); }
|
||||
CommonOperatorBuilder* common() { return &common_; }
|
||||
JSOperatorBuilder* javascript() { return &javascript_; }
|
||||
SimplifiedOperatorBuilder* simplified() { return &simplified_; }
|
||||
JSGraph* jsgraph() { return &jsgraph_; }
|
||||
CompilationInfo* info() { return &info_; }
|
||||
|
||||
private:
|
||||
CommonOperatorBuilder common_;
|
||||
JSOperatorBuilder javascript_;
|
||||
SimplifiedOperatorBuilder simplified_;
|
||||
Typer typer_;
|
||||
JSGraph jsgraph_;
|
||||
CompilationInfo info_;
|
||||
};
|
||||
|
||||
|
||||
TEST(ReduceJSLoadContext) {
|
||||
ContextSpecializationTester t;
|
||||
|
||||
Node* start = t.NewNode(t.common()->Start());
|
||||
t.graph()->SetStart(start);
|
||||
|
||||
// Make a context and initialize it a bit for this test.
|
||||
Handle<Context> native = t.factory()->NewNativeContext();
|
||||
Handle<Context> ctx1 = t.factory()->NewNativeContext();
|
||||
Handle<Context> ctx2 = t.factory()->NewNativeContext();
|
||||
ctx2->set_previous(*ctx1);
|
||||
ctx1->set_previous(*native);
|
||||
Handle<Object> expected = t.factory()->InternalizeUtf8String("gboy!");
|
||||
const int slot = Context::GLOBAL_OBJECT_INDEX;
|
||||
native->set(slot, *expected);
|
||||
|
||||
Node* const_context = t.jsgraph()->Constant(native);
|
||||
Node* param_context = t.NewNode(t.common()->Parameter(0));
|
||||
JSContextSpecializer spec(t.info(), t.jsgraph(), const_context);
|
||||
|
||||
{
|
||||
// Mutable slot, constant context, depth = 0 => do nothing.
|
||||
t.info()->SetContext(native);
|
||||
Node* load = t.NewNode(t.javascript()->LoadContext(0, 0, false),
|
||||
const_context, start, start);
|
||||
Reduction r = spec.ReduceJSLoadContext(load);
|
||||
CHECK(!r.Changed());
|
||||
}
|
||||
|
||||
{
|
||||
// Mutable slot, non-constant context, depth = 0 => do nothing.
|
||||
t.info()->SetContext(native);
|
||||
Node* load = t.NewNode(t.javascript()->LoadContext(0, 0, false),
|
||||
param_context, start, start);
|
||||
Reduction r = spec.ReduceJSLoadContext(load);
|
||||
CHECK(!r.Changed());
|
||||
}
|
||||
|
||||
{
|
||||
// Mutable slot, non-constant context, depth > 0 => fold-in parent context.
|
||||
t.info()->SetContext(ctx2);
|
||||
Node* load = t.NewNode(
|
||||
t.javascript()->LoadContext(2, Context::GLOBAL_EVAL_FUN_INDEX, false),
|
||||
param_context, start, start);
|
||||
Reduction r = spec.ReduceJSLoadContext(load);
|
||||
CHECK(r.Changed());
|
||||
CHECK_EQ(IrOpcode::kHeapConstant, r.replacement()->InputAt(0)->opcode());
|
||||
ValueMatcher<Handle<Context> > match(r.replacement()->InputAt(0));
|
||||
CHECK_EQ(*native, *match.Value());
|
||||
ContextAccess access = static_cast<Operator1<ContextAccess>*>(
|
||||
r.replacement()->op())->parameter();
|
||||
CHECK_EQ(Context::GLOBAL_EVAL_FUN_INDEX, access.index());
|
||||
CHECK_EQ(0, access.depth());
|
||||
CHECK_EQ(false, access.immutable());
|
||||
}
|
||||
|
||||
{
|
||||
// Immutable slot, constant context => specialize.
|
||||
t.info()->SetContext(native);
|
||||
Node* load = t.NewNode(t.javascript()->LoadContext(0, slot, true),
|
||||
const_context, start, start);
|
||||
Reduction r = spec.ReduceJSLoadContext(load);
|
||||
CHECK(r.Changed());
|
||||
CHECK(r.replacement() != load);
|
||||
|
||||
ValueMatcher<Handle<Object> > match(r.replacement());
|
||||
CHECK(match.HasValue());
|
||||
CHECK_EQ(*expected, *match.Value());
|
||||
}
|
||||
|
||||
{
|
||||
// Immutable slot, non-constant context => specialize.
|
||||
t.info()->SetContext(native);
|
||||
Node* load = t.NewNode(t.javascript()->LoadContext(0, slot, true),
|
||||
param_context, start, start);
|
||||
Reduction r = spec.ReduceJSLoadContext(load);
|
||||
CHECK(r.Changed());
|
||||
CHECK(r.replacement() != load);
|
||||
|
||||
ValueMatcher<Handle<Object> > match(r.replacement());
|
||||
CHECK(match.HasValue());
|
||||
CHECK_EQ(*expected, *match.Value());
|
||||
}
|
||||
|
||||
// TODO(titzer): test with other kinds of contexts, e.g. a function context.
|
||||
// TODO(sigurds): test that loads below create context are not optimized
|
||||
}
|
||||
|
||||
|
||||
// TODO(titzer): factor out common code with effects checking in typed lowering.
|
||||
static void CheckEffectInput(Node* effect, Node* use) {
|
||||
CHECK_EQ(effect, NodeProperties::GetEffectInput(use));
|
||||
}
|
||||
|
||||
|
||||
TEST(SpecializeToContext) {
|
||||
ContextSpecializationTester t;
|
||||
|
||||
Node* start = t.NewNode(t.common()->Start());
|
||||
t.graph()->SetStart(start);
|
||||
|
||||
// Make a context and initialize it a bit for this test.
|
||||
Handle<Context> native = t.factory()->NewNativeContext();
|
||||
Handle<Object> expected = t.factory()->InternalizeUtf8String("gboy!");
|
||||
const int slot = Context::GLOBAL_OBJECT_INDEX;
|
||||
native->set(slot, *expected);
|
||||
t.info()->SetContext(native);
|
||||
|
||||
Node* const_context = t.jsgraph()->Constant(native);
|
||||
Node* param_context = t.NewNode(t.common()->Parameter(0));
|
||||
JSContextSpecializer spec(t.info(), t.jsgraph(), const_context);
|
||||
|
||||
{
|
||||
// Check that SpecializeToContext() replaces values and forwards effects
|
||||
// correctly, and folds values from constant and non-constant contexts
|
||||
Node* effect_in = t.NewNode(t.common()->Start());
|
||||
Node* load = t.NewNode(t.javascript()->LoadContext(0, slot, true),
|
||||
const_context, const_context, effect_in, start);
|
||||
|
||||
|
||||
Node* value_use = t.ChangeTaggedToInt32(load);
|
||||
Node* other_load = t.NewNode(t.javascript()->LoadContext(0, slot, true),
|
||||
param_context, param_context, load, start);
|
||||
Node* effect_use = other_load;
|
||||
Node* other_use = t.ChangeTaggedToInt32(other_load);
|
||||
|
||||
// Double check the above graph is what we expect, or the test is broken.
|
||||
CheckEffectInput(effect_in, load);
|
||||
CheckEffectInput(load, effect_use);
|
||||
|
||||
// Perform the substitution on the entire graph.
|
||||
spec.SpecializeToContext();
|
||||
|
||||
// Effects should have been forwarded (not replaced with a value).
|
||||
CheckEffectInput(effect_in, effect_use);
|
||||
|
||||
// Use of {other_load} should not have been replaced.
|
||||
CHECK_EQ(other_load, other_use->InputAt(0));
|
||||
|
||||
Node* replacement = value_use->InputAt(0);
|
||||
ValueMatcher<Handle<Object> > match(replacement);
|
||||
CHECK(match.HasValue());
|
||||
CHECK_EQ(*expected, *match.Value());
|
||||
}
|
||||
// TODO(titzer): clean up above test and test more complicated effects.
|
||||
}
|
||||
|
||||
|
||||
TEST(SpecializeJSFunction_ToConstant1) {
|
||||
FunctionTester T(
|
||||
"(function() { var x = 1; function inc(a)"
|
||||
" { return a + x; } return inc; })()");
|
||||
|
||||
T.CheckCall(1.0, 0.0, 0.0);
|
||||
T.CheckCall(2.0, 1.0, 0.0);
|
||||
T.CheckCall(2.1, 1.1, 0.0);
|
||||
}
|
||||
|
||||
|
||||
TEST(SpecializeJSFunction_ToConstant2) {
|
||||
FunctionTester T(
|
||||
"(function() { var x = 1.5; var y = 2.25; var z = 3.75;"
|
||||
" function f(a) { return a - x + y - z; } return f; })()");
|
||||
|
||||
T.CheckCall(-3.0, 0.0, 0.0);
|
||||
T.CheckCall(-2.0, 1.0, 0.0);
|
||||
T.CheckCall(-1.9, 1.1, 0.0);
|
||||
}
|
||||
|
||||
|
||||
TEST(SpecializeJSFunction_ToConstant3) {
|
||||
FunctionTester T(
|
||||
"(function() { var x = -11.5; function inc()"
|
||||
" { return (function(a) { return a + x; }); }"
|
||||
" return inc(); })()");
|
||||
|
||||
T.CheckCall(-11.5, 0.0, 0.0);
|
||||
T.CheckCall(-10.5, 1.0, 0.0);
|
||||
T.CheckCall(-10.4, 1.1, 0.0);
|
||||
}
|
||||
|
||||
|
||||
TEST(SpecializeJSFunction_ToConstant_uninit) {
|
||||
{
|
||||
FunctionTester T(
|
||||
"(function() { if (false) { var x = 1; } function inc(a)"
|
||||
" { return x; } return inc; })()"); // x is undefined!
|
||||
|
||||
CHECK(T.Call(T.Val(0.0), T.Val(0.0)).ToHandleChecked()->IsUndefined());
|
||||
CHECK(T.Call(T.Val(2.0), T.Val(0.0)).ToHandleChecked()->IsUndefined());
|
||||
CHECK(T.Call(T.Val(-2.1), T.Val(0.0)).ToHandleChecked()->IsUndefined());
|
||||
}
|
||||
|
||||
{
|
||||
FunctionTester T(
|
||||
"(function() { if (false) { var x = 1; } function inc(a)"
|
||||
" { return a + x; } return inc; })()"); // x is undefined!
|
||||
|
||||
CHECK(T.Call(T.Val(0.0), T.Val(0.0)).ToHandleChecked()->IsNaN());
|
||||
CHECK(T.Call(T.Val(2.0), T.Val(0.0)).ToHandleChecked()->IsNaN());
|
||||
CHECK(T.Call(T.Val(-2.1), T.Val(0.0)).ToHandleChecked()->IsNaN());
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,113 +0,0 @@
|
||||
// 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 "src/v8.h"
|
||||
|
||||
#include "src/compiler.h"
|
||||
#include "src/zone.h"
|
||||
|
||||
#include "src/compiler/common-operator.h"
|
||||
#include "src/compiler/generic-node-inl.h"
|
||||
#include "src/compiler/graph.h"
|
||||
#include "src/compiler/linkage.h"
|
||||
#include "src/compiler/machine-operator.h"
|
||||
#include "src/compiler/node.h"
|
||||
#include "src/compiler/operator.h"
|
||||
#include "src/compiler/pipeline.h"
|
||||
#include "src/compiler/schedule.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
|
||||
#if V8_TURBOFAN_TARGET
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
|
||||
static SimpleOperator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
|
||||
0, 0, "dummy");
|
||||
|
||||
// So we can get a real JS function.
|
||||
static Handle<JSFunction> Compile(const char* source) {
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
Handle<String> source_code = isolate->factory()
|
||||
->NewStringFromUtf8(CStrVector(source))
|
||||
.ToHandleChecked();
|
||||
Handle<SharedFunctionInfo> shared_function = Compiler::CompileScript(
|
||||
source_code, Handle<String>(), 0, 0, false,
|
||||
Handle<Context>(isolate->native_context()), NULL, NULL,
|
||||
v8::ScriptCompiler::kNoCompileOptions, NOT_NATIVES_CODE);
|
||||
return isolate->factory()->NewFunctionFromSharedFunctionInfo(
|
||||
shared_function, isolate->native_context());
|
||||
}
|
||||
|
||||
|
||||
TEST(TestLinkageCreate) {
|
||||
InitializedHandleScope handles;
|
||||
Handle<JSFunction> function = Compile("a + b");
|
||||
CompilationInfoWithZone info(function);
|
||||
Linkage linkage(&info);
|
||||
}
|
||||
|
||||
|
||||
TEST(TestLinkageJSFunctionIncoming) {
|
||||
InitializedHandleScope handles;
|
||||
|
||||
const char* sources[] = {"(function() { })", "(function(a) { })",
|
||||
"(function(a,b) { })", "(function(a,b,c) { })"};
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
i::HandleScope handles(CcTest::i_isolate());
|
||||
Handle<JSFunction> function = v8::Utils::OpenHandle(
|
||||
*v8::Handle<v8::Function>::Cast(CompileRun(sources[i])));
|
||||
CompilationInfoWithZone info(function);
|
||||
Linkage linkage(&info);
|
||||
|
||||
CallDescriptor* descriptor = linkage.GetIncomingDescriptor();
|
||||
CHECK_NE(NULL, descriptor);
|
||||
|
||||
CHECK_EQ(1 + i, descriptor->ParameterCount());
|
||||
CHECK_EQ(1, descriptor->ReturnCount());
|
||||
CHECK_EQ(Operator::kNoProperties, descriptor->properties());
|
||||
CHECK_EQ(true, descriptor->IsJSFunctionCall());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(TestLinkageCodeStubIncoming) {
|
||||
Isolate* isolate = CcTest::InitIsolateOnce();
|
||||
CompilationInfoWithZone info(static_cast<HydrogenCodeStub*>(NULL), isolate);
|
||||
Linkage linkage(&info);
|
||||
// TODO(titzer): test linkage creation with a bonafide code stub.
|
||||
// this just checks current behavior.
|
||||
CHECK_EQ(NULL, linkage.GetIncomingDescriptor());
|
||||
}
|
||||
|
||||
|
||||
TEST(TestLinkageJSCall) {
|
||||
HandleAndZoneScope handles;
|
||||
Handle<JSFunction> function = Compile("a + c");
|
||||
CompilationInfoWithZone info(function);
|
||||
Linkage linkage(&info);
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
CallDescriptor* descriptor = linkage.GetJSCallDescriptor(i);
|
||||
CHECK_NE(NULL, descriptor);
|
||||
CHECK_EQ(i, descriptor->ParameterCount());
|
||||
CHECK_EQ(1, descriptor->ReturnCount());
|
||||
CHECK_EQ(Operator::kNoProperties, descriptor->properties());
|
||||
CHECK_EQ(true, descriptor->IsJSFunctionCall());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(TestLinkageRuntimeCall) {
|
||||
// TODO(titzer): test linkage creation for outgoing runtime calls.
|
||||
}
|
||||
|
||||
|
||||
TEST(TestLinkageStubCall) {
|
||||
// TODO(titzer): test linkage creation for outgoing stub calls.
|
||||
}
|
||||
|
||||
|
||||
#endif // V8_TURBOFAN_TARGET
|
@ -1,776 +0,0 @@
|
||||
// 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/cctest.h"
|
||||
|
||||
#include "src/base/utils/random-number-generator.h"
|
||||
#include "src/compiler/graph-inl.h"
|
||||
#include "src/compiler/machine-operator-reducer.h"
|
||||
#include "test/cctest/compiler/value-helper.h"
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
|
||||
template <typename T>
|
||||
Operator* NewConstantOperator(CommonOperatorBuilder* common, volatile T value);
|
||||
|
||||
template <>
|
||||
Operator* NewConstantOperator<int32_t>(CommonOperatorBuilder* common,
|
||||
volatile int32_t value) {
|
||||
return common->Int32Constant(value);
|
||||
}
|
||||
|
||||
template <>
|
||||
Operator* NewConstantOperator<double>(CommonOperatorBuilder* common,
|
||||
volatile double value) {
|
||||
return common->Float64Constant(value);
|
||||
}
|
||||
|
||||
|
||||
class ReducerTester : public HandleAndZoneScope {
|
||||
public:
|
||||
ReducerTester()
|
||||
: isolate(main_isolate()),
|
||||
binop(NULL),
|
||||
unop(NULL),
|
||||
machine(main_zone()),
|
||||
common(main_zone()),
|
||||
graph(main_zone()),
|
||||
maxuint32(Constant<int32_t>(kMaxUInt32)) {}
|
||||
|
||||
Isolate* isolate;
|
||||
Operator* binop;
|
||||
Operator* unop;
|
||||
MachineOperatorBuilder machine;
|
||||
CommonOperatorBuilder common;
|
||||
Graph graph;
|
||||
Node* maxuint32;
|
||||
|
||||
template <typename T>
|
||||
Node* Constant(volatile T value) {
|
||||
return graph.NewNode(NewConstantOperator<T>(&common, value));
|
||||
}
|
||||
|
||||
// Check that the reduction of this binop applied to constants {a} and {b}
|
||||
// yields the {expect} value.
|
||||
template <typename T>
|
||||
void CheckFoldBinop(volatile T expect, volatile T a, volatile T b) {
|
||||
CheckFoldBinop<T>(expect, Constant<T>(a), Constant<T>(b));
|
||||
}
|
||||
|
||||
// Check that the reduction of this binop applied to {a} and {b} yields
|
||||
// the {expect} value.
|
||||
template <typename T>
|
||||
void CheckFoldBinop(volatile T expect, Node* a, Node* b) {
|
||||
CHECK_NE(NULL, binop);
|
||||
Node* n = graph.NewNode(binop, a, b);
|
||||
MachineOperatorReducer reducer(&graph);
|
||||
Reduction reduction = reducer.Reduce(n);
|
||||
CHECK(reduction.Changed());
|
||||
CHECK_NE(n, reduction.replacement());
|
||||
CHECK_EQ(expect, ValueOf<T>(reduction.replacement()->op()));
|
||||
}
|
||||
|
||||
// Check that the reduction of this binop applied to {a} and {b} yields
|
||||
// the {expect} node.
|
||||
void CheckBinop(Node* expect, Node* a, Node* b) {
|
||||
CHECK_NE(NULL, binop);
|
||||
Node* n = graph.NewNode(binop, a, b);
|
||||
MachineOperatorReducer reducer(&graph);
|
||||
Reduction reduction = reducer.Reduce(n);
|
||||
CHECK(reduction.Changed());
|
||||
CHECK_EQ(expect, reduction.replacement());
|
||||
}
|
||||
|
||||
// Check that the reduction of this binop applied to {left} and {right} yields
|
||||
// this binop applied to {left_expect} and {right_expect}.
|
||||
void CheckFoldBinop(Node* left_expect, Node* right_expect, Node* left,
|
||||
Node* right) {
|
||||
CHECK_NE(NULL, binop);
|
||||
Node* n = graph.NewNode(binop, left, right);
|
||||
MachineOperatorReducer reducer(&graph);
|
||||
Reduction reduction = reducer.Reduce(n);
|
||||
CHECK(reduction.Changed());
|
||||
CHECK_EQ(binop, reduction.replacement()->op());
|
||||
CHECK_EQ(left_expect, reduction.replacement()->InputAt(0));
|
||||
CHECK_EQ(right_expect, reduction.replacement()->InputAt(1));
|
||||
}
|
||||
|
||||
// Check that the reduction of this binop applied to {left} and {right} yields
|
||||
// the {op_expect} applied to {left_expect} and {right_expect}.
|
||||
template <typename T>
|
||||
void CheckFoldBinop(volatile T left_expect, Operator* op_expect,
|
||||
Node* right_expect, Node* left, Node* right) {
|
||||
CHECK_NE(NULL, binop);
|
||||
Node* n = graph.NewNode(binop, left, right);
|
||||
MachineOperatorReducer reducer(&graph);
|
||||
Reduction r = reducer.Reduce(n);
|
||||
CHECK(r.Changed());
|
||||
CHECK_EQ(op_expect->opcode(), r.replacement()->op()->opcode());
|
||||
CHECK_EQ(left_expect, ValueOf<T>(r.replacement()->InputAt(0)->op()));
|
||||
CHECK_EQ(right_expect, r.replacement()->InputAt(1));
|
||||
}
|
||||
|
||||
// Check that the reduction of this binop applied to {left} and {right} yields
|
||||
// the {op_expect} applied to {left_expect} and {right_expect}.
|
||||
template <typename T>
|
||||
void CheckFoldBinop(Node* left_expect, Operator* op_expect,
|
||||
volatile T right_expect, Node* left, Node* right) {
|
||||
CHECK_NE(NULL, binop);
|
||||
Node* n = graph.NewNode(binop, left, right);
|
||||
MachineOperatorReducer reducer(&graph);
|
||||
Reduction r = reducer.Reduce(n);
|
||||
CHECK(r.Changed());
|
||||
CHECK_EQ(op_expect->opcode(), r.replacement()->op()->opcode());
|
||||
CHECK_EQ(left_expect, r.replacement()->InputAt(0));
|
||||
CHECK_EQ(right_expect, ValueOf<T>(r.replacement()->InputAt(1)->op()));
|
||||
}
|
||||
|
||||
// Check that if the given constant appears on the left, the reducer will
|
||||
// swap it to be on the right.
|
||||
template <typename T>
|
||||
void CheckPutConstantOnRight(volatile T constant) {
|
||||
// TODO(titzer): CHECK(binop->HasProperty(Operator::kCommutative));
|
||||
Node* p = Parameter();
|
||||
Node* k = Constant<T>(constant);
|
||||
{
|
||||
Node* n = graph.NewNode(binop, k, p);
|
||||
MachineOperatorReducer reducer(&graph);
|
||||
Reduction reduction = reducer.Reduce(n);
|
||||
CHECK(!reduction.Changed() || reduction.replacement() == n);
|
||||
CHECK_EQ(p, n->InputAt(0));
|
||||
CHECK_EQ(k, n->InputAt(1));
|
||||
}
|
||||
{
|
||||
Node* n = graph.NewNode(binop, p, k);
|
||||
MachineOperatorReducer reducer(&graph);
|
||||
Reduction reduction = reducer.Reduce(n);
|
||||
CHECK(!reduction.Changed());
|
||||
CHECK_EQ(p, n->InputAt(0));
|
||||
CHECK_EQ(k, n->InputAt(1));
|
||||
}
|
||||
}
|
||||
|
||||
// Check that if the given constant appears on the left, the reducer will
|
||||
// *NOT* swap it to be on the right.
|
||||
template <typename T>
|
||||
void CheckDontPutConstantOnRight(volatile T constant) {
|
||||
CHECK(!binop->HasProperty(Operator::kCommutative));
|
||||
Node* p = Parameter();
|
||||
Node* k = Constant<T>(constant);
|
||||
Node* n = graph.NewNode(binop, k, p);
|
||||
MachineOperatorReducer reducer(&graph);
|
||||
Reduction reduction = reducer.Reduce(n);
|
||||
CHECK(!reduction.Changed());
|
||||
CHECK_EQ(k, n->InputAt(0));
|
||||
CHECK_EQ(p, n->InputAt(1));
|
||||
}
|
||||
|
||||
Node* Parameter(int32_t index = 0) {
|
||||
return graph.NewNode(common.Parameter(index));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
TEST(ReduceWord32And) {
|
||||
ReducerTester R;
|
||||
R.binop = R.machine.Word32And();
|
||||
|
||||
FOR_INT32_INPUTS(pl) {
|
||||
FOR_INT32_INPUTS(pr) {
|
||||
int32_t x = *pl, y = *pr;
|
||||
R.CheckFoldBinop<int32_t>(x & y, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
R.CheckPutConstantOnRight(33);
|
||||
R.CheckPutConstantOnRight(44000);
|
||||
|
||||
Node* x = R.Parameter();
|
||||
Node* zero = R.Constant<int32_t>(0);
|
||||
Node* minus_1 = R.Constant<int32_t>(-1);
|
||||
|
||||
R.CheckBinop(zero, x, zero); // x & 0 => 0
|
||||
R.CheckBinop(zero, zero, x); // 0 & x => 0
|
||||
R.CheckBinop(x, x, minus_1); // x & -1 => 0
|
||||
R.CheckBinop(x, minus_1, x); // -1 & x => 0
|
||||
R.CheckBinop(x, x, x); // x & x => x
|
||||
}
|
||||
|
||||
|
||||
TEST(ReduceWord32Or) {
|
||||
ReducerTester R;
|
||||
R.binop = R.machine.Word32Or();
|
||||
|
||||
FOR_INT32_INPUTS(pl) {
|
||||
FOR_INT32_INPUTS(pr) {
|
||||
int32_t x = *pl, y = *pr;
|
||||
R.CheckFoldBinop<int32_t>(x | y, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
R.CheckPutConstantOnRight(36);
|
||||
R.CheckPutConstantOnRight(44001);
|
||||
|
||||
Node* x = R.Parameter();
|
||||
Node* zero = R.Constant<int32_t>(0);
|
||||
Node* minus_1 = R.Constant<int32_t>(-1);
|
||||
|
||||
R.CheckBinop(x, x, zero); // x & 0 => x
|
||||
R.CheckBinop(x, zero, x); // 0 & x => x
|
||||
R.CheckBinop(minus_1, x, minus_1); // x & -1 => -1
|
||||
R.CheckBinop(minus_1, minus_1, x); // -1 & x => -1
|
||||
R.CheckBinop(x, x, x); // x & x => x
|
||||
}
|
||||
|
||||
|
||||
TEST(ReduceWord32Xor) {
|
||||
ReducerTester R;
|
||||
R.binop = R.machine.Word32Xor();
|
||||
|
||||
FOR_INT32_INPUTS(pl) {
|
||||
FOR_INT32_INPUTS(pr) {
|
||||
int32_t x = *pl, y = *pr;
|
||||
R.CheckFoldBinop<int32_t>(x ^ y, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
R.CheckPutConstantOnRight(39);
|
||||
R.CheckPutConstantOnRight(4403);
|
||||
|
||||
Node* x = R.Parameter();
|
||||
Node* zero = R.Constant<int32_t>(0);
|
||||
|
||||
R.CheckBinop(x, x, zero); // x ^ 0 => x
|
||||
R.CheckBinop(x, zero, x); // 0 ^ x => x
|
||||
R.CheckFoldBinop<int32_t>(0, x, x); // x ^ x => 0
|
||||
}
|
||||
|
||||
|
||||
TEST(ReduceWord32Shl) {
|
||||
ReducerTester R;
|
||||
R.binop = R.machine.Word32Shl();
|
||||
|
||||
// TODO(titzer): out of range shifts
|
||||
FOR_INT32_INPUTS(i) {
|
||||
for (int y = 0; y < 32; y++) {
|
||||
int32_t x = *i;
|
||||
R.CheckFoldBinop<int32_t>(x << y, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
R.CheckDontPutConstantOnRight(44);
|
||||
|
||||
Node* x = R.Parameter();
|
||||
Node* zero = R.Constant<int32_t>(0);
|
||||
|
||||
R.CheckBinop(x, x, zero); // x << 0 => x
|
||||
}
|
||||
|
||||
|
||||
TEST(ReduceWord32Shr) {
|
||||
ReducerTester R;
|
||||
R.binop = R.machine.Word32Shr();
|
||||
|
||||
// TODO(titzer): test out of range shifts
|
||||
FOR_UINT32_INPUTS(i) {
|
||||
for (uint32_t y = 0; y < 32; y++) {
|
||||
uint32_t x = *i;
|
||||
R.CheckFoldBinop<int32_t>(x >> y, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
R.CheckDontPutConstantOnRight(44);
|
||||
|
||||
Node* x = R.Parameter();
|
||||
Node* zero = R.Constant<int32_t>(0);
|
||||
|
||||
R.CheckBinop(x, x, zero); // x >>> 0 => x
|
||||
}
|
||||
|
||||
|
||||
TEST(ReduceWord32Sar) {
|
||||
ReducerTester R;
|
||||
R.binop = R.machine.Word32Sar();
|
||||
|
||||
// TODO(titzer): test out of range shifts
|
||||
FOR_INT32_INPUTS(i) {
|
||||
for (int32_t y = 0; y < 32; y++) {
|
||||
int32_t x = *i;
|
||||
R.CheckFoldBinop<int32_t>(x >> y, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
R.CheckDontPutConstantOnRight(44);
|
||||
|
||||
Node* x = R.Parameter();
|
||||
Node* zero = R.Constant<int32_t>(0);
|
||||
|
||||
R.CheckBinop(x, x, zero); // x >> 0 => x
|
||||
}
|
||||
|
||||
|
||||
TEST(ReduceWord32Equal) {
|
||||
ReducerTester R;
|
||||
R.binop = R.machine.Word32Equal();
|
||||
|
||||
FOR_INT32_INPUTS(pl) {
|
||||
FOR_INT32_INPUTS(pr) {
|
||||
int32_t x = *pl, y = *pr;
|
||||
R.CheckFoldBinop<int32_t>(x == y ? 1 : 0, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
R.CheckPutConstantOnRight(48);
|
||||
R.CheckPutConstantOnRight(-48);
|
||||
|
||||
Node* x = R.Parameter(0);
|
||||
Node* y = R.Parameter(1);
|
||||
Node* zero = R.Constant<int32_t>(0);
|
||||
Node* sub = R.graph.NewNode(R.machine.Int32Sub(), x, y);
|
||||
|
||||
R.CheckFoldBinop<int32_t>(1, x, x); // x == x => 1
|
||||
R.CheckFoldBinop(x, y, sub, zero); // x - y == 0 => x == y
|
||||
R.CheckFoldBinop(x, y, zero, sub); // 0 == x - y => x == y
|
||||
}
|
||||
|
||||
|
||||
TEST(ReduceInt32Add) {
|
||||
ReducerTester R;
|
||||
R.binop = R.machine.Int32Add();
|
||||
|
||||
FOR_INT32_INPUTS(pl) {
|
||||
FOR_INT32_INPUTS(pr) {
|
||||
int32_t x = *pl, y = *pr;
|
||||
R.CheckFoldBinop<int32_t>(x + y, x, y); // TODO(titzer): signed overflow
|
||||
}
|
||||
}
|
||||
|
||||
R.CheckPutConstantOnRight(41);
|
||||
R.CheckPutConstantOnRight(4407);
|
||||
|
||||
Node* x = R.Parameter();
|
||||
Node* zero = R.Constant<int32_t>(0);
|
||||
|
||||
R.CheckBinop(x, x, zero); // x + 0 => x
|
||||
R.CheckBinop(x, zero, x); // 0 + x => x
|
||||
}
|
||||
|
||||
|
||||
TEST(ReduceInt32Sub) {
|
||||
ReducerTester R;
|
||||
R.binop = R.machine.Int32Sub();
|
||||
|
||||
FOR_INT32_INPUTS(pl) {
|
||||
FOR_INT32_INPUTS(pr) {
|
||||
int32_t x = *pl, y = *pr;
|
||||
R.CheckFoldBinop<int32_t>(x - y, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
R.CheckDontPutConstantOnRight(412);
|
||||
|
||||
Node* x = R.Parameter();
|
||||
Node* zero = R.Constant<int32_t>(0);
|
||||
|
||||
R.CheckBinop(x, x, zero); // x - 0 => x
|
||||
}
|
||||
|
||||
|
||||
TEST(ReduceInt32Mul) {
|
||||
ReducerTester R;
|
||||
R.binop = R.machine.Int32Mul();
|
||||
|
||||
FOR_INT32_INPUTS(pl) {
|
||||
FOR_INT32_INPUTS(pr) {
|
||||
int32_t x = *pl, y = *pr;
|
||||
R.CheckFoldBinop<int32_t>(x * y, x, y); // TODO(titzer): signed overflow
|
||||
}
|
||||
}
|
||||
|
||||
R.CheckPutConstantOnRight(4111);
|
||||
R.CheckPutConstantOnRight(-4407);
|
||||
|
||||
Node* x = R.Parameter();
|
||||
Node* zero = R.Constant<int32_t>(0);
|
||||
Node* one = R.Constant<int32_t>(1);
|
||||
Node* minus_one = R.Constant<int32_t>(-1);
|
||||
|
||||
R.CheckBinop(zero, x, zero); // x * 0 => 0
|
||||
R.CheckBinop(zero, zero, x); // 0 * x => 0
|
||||
R.CheckBinop(x, x, one); // x * 1 => x
|
||||
R.CheckBinop(x, one, x); // 1 * x => x
|
||||
R.CheckFoldBinop<int32_t>(0, R.machine.Int32Sub(), x, minus_one,
|
||||
x); // -1 * x => 0 - x
|
||||
R.CheckFoldBinop<int32_t>(0, R.machine.Int32Sub(), x, x,
|
||||
minus_one); // x * -1 => 0 - x
|
||||
|
||||
for (int32_t n = 1; n < 31; ++n) {
|
||||
Node* multiplier = R.Constant<int32_t>(1 << n);
|
||||
R.CheckFoldBinop<int32_t>(x, R.machine.Word32Shl(), n, x,
|
||||
multiplier); // x * 2^n => x << n
|
||||
R.CheckFoldBinop<int32_t>(x, R.machine.Word32Shl(), n, multiplier,
|
||||
x); // 2^n * x => x << n
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(ReduceInt32Div) {
|
||||
ReducerTester R;
|
||||
R.binop = R.machine.Int32Div();
|
||||
|
||||
FOR_INT32_INPUTS(pl) {
|
||||
FOR_INT32_INPUTS(pr) {
|
||||
int32_t x = *pl, y = *pr;
|
||||
if (y == 0) continue; // TODO(titzer): test / 0
|
||||
int32_t r = y == -1 ? -x : x / y; // INT_MIN / -1 may explode in C
|
||||
R.CheckFoldBinop<int32_t>(r, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
R.CheckDontPutConstantOnRight(41111);
|
||||
R.CheckDontPutConstantOnRight(-44071);
|
||||
|
||||
Node* x = R.Parameter();
|
||||
Node* one = R.Constant<int32_t>(1);
|
||||
Node* minus_one = R.Constant<int32_t>(-1);
|
||||
|
||||
R.CheckBinop(x, x, one); // x / 1 => x
|
||||
// TODO(titzer): // 0 / x => 0 if x != 0
|
||||
// TODO(titzer): // x / 2^n => x >> n and round
|
||||
R.CheckFoldBinop<int32_t>(0, R.machine.Int32Sub(), x, x,
|
||||
minus_one); // x / -1 => 0 - x
|
||||
}
|
||||
|
||||
|
||||
TEST(ReduceInt32UDiv) {
|
||||
ReducerTester R;
|
||||
R.binop = R.machine.Int32UDiv();
|
||||
|
||||
FOR_UINT32_INPUTS(pl) {
|
||||
FOR_UINT32_INPUTS(pr) {
|
||||
uint32_t x = *pl, y = *pr;
|
||||
if (y == 0) continue; // TODO(titzer): test / 0
|
||||
R.CheckFoldBinop<int32_t>(x / y, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
R.CheckDontPutConstantOnRight(41311);
|
||||
R.CheckDontPutConstantOnRight(-44371);
|
||||
|
||||
Node* x = R.Parameter();
|
||||
Node* one = R.Constant<int32_t>(1);
|
||||
|
||||
R.CheckBinop(x, x, one); // x / 1 => x
|
||||
// TODO(titzer): // 0 / x => 0 if x != 0
|
||||
|
||||
for (uint32_t n = 1; n < 32; ++n) {
|
||||
Node* divisor = R.Constant<int32_t>(1u << n);
|
||||
R.CheckFoldBinop<int32_t>(x, R.machine.Word32Shr(), n, x,
|
||||
divisor); // x / 2^n => x >> n
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(ReduceInt32Mod) {
|
||||
ReducerTester R;
|
||||
R.binop = R.machine.Int32Mod();
|
||||
|
||||
FOR_INT32_INPUTS(pl) {
|
||||
FOR_INT32_INPUTS(pr) {
|
||||
int32_t x = *pl, y = *pr;
|
||||
if (y == 0) continue; // TODO(titzer): test % 0
|
||||
int32_t r = y == -1 ? 0 : x % y; // INT_MIN % -1 may explode in C
|
||||
R.CheckFoldBinop<int32_t>(r, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
R.CheckDontPutConstantOnRight(413);
|
||||
R.CheckDontPutConstantOnRight(-4401);
|
||||
|
||||
Node* x = R.Parameter();
|
||||
Node* one = R.Constant<int32_t>(1);
|
||||
|
||||
R.CheckFoldBinop<int32_t>(0, x, one); // x % 1 => 0
|
||||
// TODO(titzer): // x % 2^n => x & 2^n-1 and round
|
||||
}
|
||||
|
||||
|
||||
TEST(ReduceInt32UMod) {
|
||||
ReducerTester R;
|
||||
R.binop = R.machine.Int32UMod();
|
||||
|
||||
FOR_INT32_INPUTS(pl) {
|
||||
FOR_INT32_INPUTS(pr) {
|
||||
uint32_t x = *pl, y = *pr;
|
||||
if (y == 0) continue; // TODO(titzer): test x % 0
|
||||
R.CheckFoldBinop<int32_t>(x % y, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
R.CheckDontPutConstantOnRight(417);
|
||||
R.CheckDontPutConstantOnRight(-4371);
|
||||
|
||||
Node* x = R.Parameter();
|
||||
Node* one = R.Constant<int32_t>(1);
|
||||
|
||||
R.CheckFoldBinop<int32_t>(0, x, one); // x % 1 => 0
|
||||
|
||||
for (uint32_t n = 1; n < 32; ++n) {
|
||||
Node* divisor = R.Constant<int32_t>(1u << n);
|
||||
R.CheckFoldBinop<int32_t>(x, R.machine.Word32And(), (1u << n) - 1, x,
|
||||
divisor); // x % 2^n => x & 2^n-1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(ReduceInt32LessThan) {
|
||||
ReducerTester R;
|
||||
R.binop = R.machine.Int32LessThan();
|
||||
|
||||
FOR_INT32_INPUTS(pl) {
|
||||
FOR_INT32_INPUTS(pr) {
|
||||
int32_t x = *pl, y = *pr;
|
||||
R.CheckFoldBinop<int32_t>(x < y ? 1 : 0, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
R.CheckDontPutConstantOnRight(41399);
|
||||
R.CheckDontPutConstantOnRight(-440197);
|
||||
|
||||
Node* x = R.Parameter(0);
|
||||
Node* y = R.Parameter(1);
|
||||
Node* zero = R.Constant<int32_t>(0);
|
||||
Node* sub = R.graph.NewNode(R.machine.Int32Sub(), x, y);
|
||||
|
||||
R.CheckFoldBinop<int32_t>(0, x, x); // x < x => 0
|
||||
R.CheckFoldBinop(x, y, sub, zero); // x - y < 0 => x < y
|
||||
R.CheckFoldBinop(y, x, zero, sub); // 0 < x - y => y < x
|
||||
}
|
||||
|
||||
|
||||
TEST(ReduceInt32LessThanOrEqual) {
|
||||
ReducerTester R;
|
||||
R.binop = R.machine.Int32LessThanOrEqual();
|
||||
|
||||
FOR_INT32_INPUTS(pl) {
|
||||
FOR_INT32_INPUTS(pr) {
|
||||
int32_t x = *pl, y = *pr;
|
||||
R.CheckFoldBinop<int32_t>(x <= y ? 1 : 0, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
FOR_INT32_INPUTS(i) { R.CheckDontPutConstantOnRight<int32_t>(*i); }
|
||||
|
||||
Node* x = R.Parameter(0);
|
||||
Node* y = R.Parameter(1);
|
||||
Node* zero = R.Constant<int32_t>(0);
|
||||
Node* sub = R.graph.NewNode(R.machine.Int32Sub(), x, y);
|
||||
|
||||
R.CheckFoldBinop<int32_t>(1, x, x); // x <= x => 1
|
||||
R.CheckFoldBinop(x, y, sub, zero); // x - y <= 0 => x <= y
|
||||
R.CheckFoldBinop(y, x, zero, sub); // 0 <= x - y => y <= x
|
||||
}
|
||||
|
||||
|
||||
TEST(ReduceUint32LessThan) {
|
||||
ReducerTester R;
|
||||
R.binop = R.machine.Uint32LessThan();
|
||||
|
||||
FOR_UINT32_INPUTS(pl) {
|
||||
FOR_UINT32_INPUTS(pr) {
|
||||
uint32_t x = *pl, y = *pr;
|
||||
R.CheckFoldBinop<int32_t>(x < y ? 1 : 0, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
R.CheckDontPutConstantOnRight(41399);
|
||||
R.CheckDontPutConstantOnRight(-440197);
|
||||
|
||||
Node* x = R.Parameter();
|
||||
Node* max = R.maxuint32;
|
||||
Node* zero = R.Constant<int32_t>(0);
|
||||
|
||||
R.CheckFoldBinop<int32_t>(0, max, x); // M < x => 0
|
||||
R.CheckFoldBinop<int32_t>(0, x, zero); // x < 0 => 0
|
||||
R.CheckFoldBinop<int32_t>(0, x, x); // x < x => 0
|
||||
}
|
||||
|
||||
|
||||
TEST(ReduceUint32LessThanOrEqual) {
|
||||
ReducerTester R;
|
||||
R.binop = R.machine.Uint32LessThanOrEqual();
|
||||
|
||||
FOR_UINT32_INPUTS(pl) {
|
||||
FOR_UINT32_INPUTS(pr) {
|
||||
uint32_t x = *pl, y = *pr;
|
||||
R.CheckFoldBinop<int32_t>(x <= y ? 1 : 0, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
R.CheckDontPutConstantOnRight(41399);
|
||||
R.CheckDontPutConstantOnRight(-440197);
|
||||
|
||||
Node* x = R.Parameter();
|
||||
Node* max = R.maxuint32;
|
||||
Node* zero = R.Constant<int32_t>(0);
|
||||
|
||||
R.CheckFoldBinop<int32_t>(1, x, max); // x <= M => 1
|
||||
R.CheckFoldBinop<int32_t>(1, zero, x); // 0 <= x => 1
|
||||
R.CheckFoldBinop<int32_t>(1, x, x); // x <= x => 1
|
||||
}
|
||||
|
||||
|
||||
TEST(ReduceLoadStore) {
|
||||
ReducerTester R;
|
||||
|
||||
Node* base = R.Constant<int32_t>(11);
|
||||
Node* index = R.Constant<int32_t>(4);
|
||||
Node* load = R.graph.NewNode(R.machine.Load(kMachineWord32), base, index);
|
||||
|
||||
{
|
||||
MachineOperatorReducer reducer(&R.graph);
|
||||
Reduction reduction = reducer.Reduce(load);
|
||||
CHECK(!reduction.Changed()); // loads should not be reduced.
|
||||
}
|
||||
|
||||
{
|
||||
Node* store =
|
||||
R.graph.NewNode(R.machine.Store(kMachineWord32), base, index, load);
|
||||
MachineOperatorReducer reducer(&R.graph);
|
||||
Reduction reduction = reducer.Reduce(store);
|
||||
CHECK(!reduction.Changed()); // stores should not be reduced.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void CheckNans(ReducerTester* R) {
|
||||
Node* x = R->Parameter();
|
||||
std::vector<double> nans = ValueHelper::nan_vector();
|
||||
for (std::vector<double>::const_iterator pl = nans.begin(); pl != nans.end();
|
||||
++pl) {
|
||||
for (std::vector<double>::const_iterator pr = nans.begin();
|
||||
pr != nans.end(); ++pr) {
|
||||
Node* nan1 = R->Constant<double>(*pl);
|
||||
Node* nan2 = R->Constant<double>(*pr);
|
||||
R->CheckBinop(nan1, x, nan1); // x % NaN => NaN
|
||||
R->CheckBinop(nan1, nan1, x); // NaN % x => NaN
|
||||
R->CheckBinop(nan1, nan2, nan1); // NaN % NaN => NaN
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(ReduceFloat64Add) {
|
||||
ReducerTester R;
|
||||
R.binop = R.machine.Float64Add();
|
||||
|
||||
FOR_FLOAT64_INPUTS(pl) {
|
||||
FOR_FLOAT64_INPUTS(pr) {
|
||||
double x = *pl, y = *pr;
|
||||
R.CheckFoldBinop<double>(x + y, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
FOR_FLOAT64_INPUTS(i) { R.CheckPutConstantOnRight(*i); }
|
||||
// TODO(titzer): CheckNans(&R);
|
||||
}
|
||||
|
||||
|
||||
TEST(ReduceFloat64Sub) {
|
||||
ReducerTester R;
|
||||
R.binop = R.machine.Float64Sub();
|
||||
|
||||
FOR_FLOAT64_INPUTS(pl) {
|
||||
FOR_FLOAT64_INPUTS(pr) {
|
||||
double x = *pl, y = *pr;
|
||||
R.CheckFoldBinop<double>(x - y, x, y);
|
||||
}
|
||||
}
|
||||
// TODO(titzer): CheckNans(&R);
|
||||
}
|
||||
|
||||
|
||||
TEST(ReduceFloat64Mul) {
|
||||
ReducerTester R;
|
||||
R.binop = R.machine.Float64Mul();
|
||||
|
||||
FOR_FLOAT64_INPUTS(pl) {
|
||||
FOR_FLOAT64_INPUTS(pr) {
|
||||
double x = *pl, y = *pr;
|
||||
R.CheckFoldBinop<double>(x * y, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
double inf = V8_INFINITY;
|
||||
R.CheckPutConstantOnRight(-inf);
|
||||
R.CheckPutConstantOnRight(-0.1);
|
||||
R.CheckPutConstantOnRight(0.1);
|
||||
R.CheckPutConstantOnRight(inf);
|
||||
|
||||
Node* x = R.Parameter();
|
||||
Node* one = R.Constant<double>(1.0);
|
||||
|
||||
R.CheckBinop(x, x, one); // x * 1.0 => x
|
||||
R.CheckBinop(x, one, x); // 1.0 * x => x
|
||||
|
||||
CheckNans(&R);
|
||||
}
|
||||
|
||||
|
||||
TEST(ReduceFloat64Div) {
|
||||
ReducerTester R;
|
||||
R.binop = R.machine.Float64Div();
|
||||
|
||||
FOR_FLOAT64_INPUTS(pl) {
|
||||
FOR_FLOAT64_INPUTS(pr) {
|
||||
double x = *pl, y = *pr;
|
||||
R.CheckFoldBinop<double>(x / y, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
Node* x = R.Parameter();
|
||||
Node* one = R.Constant<double>(1.0);
|
||||
|
||||
R.CheckBinop(x, x, one); // x / 1.0 => x
|
||||
|
||||
CheckNans(&R);
|
||||
}
|
||||
|
||||
|
||||
TEST(ReduceFloat64Mod) {
|
||||
ReducerTester R;
|
||||
R.binop = R.machine.Float64Mod();
|
||||
|
||||
FOR_FLOAT64_INPUTS(pl) {
|
||||
FOR_FLOAT64_INPUTS(pr) {
|
||||
double x = *pl, y = *pr;
|
||||
R.CheckFoldBinop<double>(modulo(x, y), x, y);
|
||||
}
|
||||
}
|
||||
|
||||
CheckNans(&R);
|
||||
}
|
||||
|
||||
|
||||
// TODO(titzer): test MachineOperatorReducer for Word64And
|
||||
// TODO(titzer): test MachineOperatorReducer for Word64Or
|
||||
// TODO(titzer): test MachineOperatorReducer for Word64Xor
|
||||
// TODO(titzer): test MachineOperatorReducer for Word64Shl
|
||||
// TODO(titzer): test MachineOperatorReducer for Word64Shr
|
||||
// TODO(titzer): test MachineOperatorReducer for Word64Sar
|
||||
// TODO(titzer): test MachineOperatorReducer for Word64Equal
|
||||
// TODO(titzer): test MachineOperatorReducer for Word64Not
|
||||
// TODO(titzer): test MachineOperatorReducer for Int64Add
|
||||
// TODO(titzer): test MachineOperatorReducer for Int64Sub
|
||||
// TODO(titzer): test MachineOperatorReducer for Int64Mul
|
||||
// TODO(titzer): test MachineOperatorReducer for Int64UMul
|
||||
// TODO(titzer): test MachineOperatorReducer for Int64Div
|
||||
// TODO(titzer): test MachineOperatorReducer for Int64UDiv
|
||||
// TODO(titzer): test MachineOperatorReducer for Int64Mod
|
||||
// TODO(titzer): test MachineOperatorReducer for Int64UMod
|
||||
// TODO(titzer): test MachineOperatorReducer for Int64Neg
|
||||
// TODO(titzer): test MachineOperatorReducer for ConvertInt32ToFloat64
|
||||
// TODO(titzer): test MachineOperatorReducer for ConvertFloat64ToInt32
|
||||
// TODO(titzer): test MachineOperatorReducer for Float64Compare
|
@ -1,330 +0,0 @@
|
||||
// Copyright 2013 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 <vector>
|
||||
|
||||
#include "src/v8.h"
|
||||
|
||||
#include "graph-tester.h"
|
||||
#include "src/compiler/common-operator.h"
|
||||
#include "src/compiler/generic-node.h"
|
||||
#include "src/compiler/generic-node-inl.h"
|
||||
#include "src/compiler/graph.h"
|
||||
#include "src/compiler/graph-inl.h"
|
||||
#include "src/compiler/graph-visualizer.h"
|
||||
#include "src/compiler/operator.h"
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
|
||||
static SimpleOperator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
|
||||
0, 0, "dummy");
|
||||
|
||||
class PreNodeVisitor : public NullNodeVisitor {
|
||||
public:
|
||||
GenericGraphVisit::Control Pre(Node* node) {
|
||||
printf("NODE ID: %d\n", node->id());
|
||||
nodes_.push_back(node);
|
||||
return GenericGraphVisit::CONTINUE;
|
||||
}
|
||||
std::vector<Node*> nodes_;
|
||||
};
|
||||
|
||||
|
||||
class PostNodeVisitor : public NullNodeVisitor {
|
||||
public:
|
||||
GenericGraphVisit::Control Post(Node* node) {
|
||||
printf("NODE ID: %d\n", node->id());
|
||||
nodes_.push_back(node);
|
||||
return GenericGraphVisit::CONTINUE;
|
||||
}
|
||||
std::vector<Node*> nodes_;
|
||||
};
|
||||
|
||||
|
||||
TEST(TestUseNodeVisitEmpty) {
|
||||
GraphWithStartNodeTester graph;
|
||||
|
||||
PreNodeVisitor node_visitor;
|
||||
graph.VisitNodeUsesFromStart(&node_visitor);
|
||||
|
||||
CHECK_EQ(1, node_visitor.nodes_.size());
|
||||
}
|
||||
|
||||
|
||||
TEST(TestUseNodePreOrderVisitSimple) {
|
||||
GraphWithStartNodeTester graph;
|
||||
Node* n2 = graph.NewNode(&dummy_operator, graph.start());
|
||||
Node* n3 = graph.NewNode(&dummy_operator, n2);
|
||||
Node* n4 = graph.NewNode(&dummy_operator, n2, n3);
|
||||
Node* n5 = graph.NewNode(&dummy_operator, n4, n2);
|
||||
graph.SetEnd(n5);
|
||||
|
||||
PreNodeVisitor node_visitor;
|
||||
graph.VisitNodeUsesFromStart(&node_visitor);
|
||||
|
||||
CHECK_EQ(5, node_visitor.nodes_.size());
|
||||
CHECK(graph.start()->id() == node_visitor.nodes_[0]->id());
|
||||
CHECK(n2->id() == node_visitor.nodes_[1]->id());
|
||||
CHECK(n3->id() == node_visitor.nodes_[2]->id());
|
||||
CHECK(n4->id() == node_visitor.nodes_[3]->id());
|
||||
CHECK(n5->id() == node_visitor.nodes_[4]->id());
|
||||
}
|
||||
|
||||
|
||||
TEST(TestInputNodePreOrderVisitSimple) {
|
||||
GraphWithStartNodeTester graph;
|
||||
Node* n2 = graph.NewNode(&dummy_operator, graph.start());
|
||||
Node* n3 = graph.NewNode(&dummy_operator, n2);
|
||||
Node* n4 = graph.NewNode(&dummy_operator, n2, n3);
|
||||
Node* n5 = graph.NewNode(&dummy_operator, n4, n2);
|
||||
graph.SetEnd(n5);
|
||||
|
||||
PreNodeVisitor node_visitor;
|
||||
graph.VisitNodeInputsFromEnd(&node_visitor);
|
||||
CHECK_EQ(5, node_visitor.nodes_.size());
|
||||
CHECK(n5->id() == node_visitor.nodes_[0]->id());
|
||||
CHECK(n4->id() == node_visitor.nodes_[1]->id());
|
||||
CHECK(n2->id() == node_visitor.nodes_[2]->id());
|
||||
CHECK(graph.start()->id() == node_visitor.nodes_[3]->id());
|
||||
CHECK(n3->id() == node_visitor.nodes_[4]->id());
|
||||
}
|
||||
|
||||
|
||||
TEST(TestUseNodePostOrderVisitSimple) {
|
||||
GraphWithStartNodeTester graph;
|
||||
Node* n2 = graph.NewNode(&dummy_operator, graph.start());
|
||||
Node* n3 = graph.NewNode(&dummy_operator, graph.start());
|
||||
Node* n4 = graph.NewNode(&dummy_operator, n2);
|
||||
Node* n5 = graph.NewNode(&dummy_operator, n2);
|
||||
Node* n6 = graph.NewNode(&dummy_operator, n2);
|
||||
Node* n7 = graph.NewNode(&dummy_operator, n3);
|
||||
Node* end_dependencies[4] = {n4, n5, n6, n7};
|
||||
Node* n8 = graph.NewNode(&dummy_operator, 4, end_dependencies);
|
||||
graph.SetEnd(n8);
|
||||
|
||||
PostNodeVisitor node_visitor;
|
||||
graph.VisitNodeUsesFromStart(&node_visitor);
|
||||
|
||||
CHECK_EQ(8, node_visitor.nodes_.size());
|
||||
CHECK(graph.end()->id() == node_visitor.nodes_[0]->id());
|
||||
CHECK(n4->id() == node_visitor.nodes_[1]->id());
|
||||
CHECK(n5->id() == node_visitor.nodes_[2]->id());
|
||||
CHECK(n6->id() == node_visitor.nodes_[3]->id());
|
||||
CHECK(n2->id() == node_visitor.nodes_[4]->id());
|
||||
CHECK(n7->id() == node_visitor.nodes_[5]->id());
|
||||
CHECK(n3->id() == node_visitor.nodes_[6]->id());
|
||||
CHECK(graph.start()->id() == node_visitor.nodes_[7]->id());
|
||||
}
|
||||
|
||||
|
||||
TEST(TestUseNodePostOrderVisitLong) {
|
||||
GraphWithStartNodeTester graph;
|
||||
Node* n2 = graph.NewNode(&dummy_operator, graph.start());
|
||||
Node* n3 = graph.NewNode(&dummy_operator, graph.start());
|
||||
Node* n4 = graph.NewNode(&dummy_operator, n2);
|
||||
Node* n5 = graph.NewNode(&dummy_operator, n2);
|
||||
Node* n6 = graph.NewNode(&dummy_operator, n3);
|
||||
Node* n7 = graph.NewNode(&dummy_operator, n3);
|
||||
Node* n8 = graph.NewNode(&dummy_operator, n5);
|
||||
Node* n9 = graph.NewNode(&dummy_operator, n5);
|
||||
Node* n10 = graph.NewNode(&dummy_operator, n9);
|
||||
Node* n11 = graph.NewNode(&dummy_operator, n9);
|
||||
Node* end_dependencies[6] = {n4, n8, n10, n11, n6, n7};
|
||||
Node* n12 = graph.NewNode(&dummy_operator, 6, end_dependencies);
|
||||
graph.SetEnd(n12);
|
||||
|
||||
PostNodeVisitor node_visitor;
|
||||
graph.VisitNodeUsesFromStart(&node_visitor);
|
||||
|
||||
CHECK_EQ(12, node_visitor.nodes_.size());
|
||||
CHECK(graph.end()->id() == node_visitor.nodes_[0]->id());
|
||||
CHECK(n4->id() == node_visitor.nodes_[1]->id());
|
||||
CHECK(n8->id() == node_visitor.nodes_[2]->id());
|
||||
CHECK(n10->id() == node_visitor.nodes_[3]->id());
|
||||
CHECK(n11->id() == node_visitor.nodes_[4]->id());
|
||||
CHECK(n9->id() == node_visitor.nodes_[5]->id());
|
||||
CHECK(n5->id() == node_visitor.nodes_[6]->id());
|
||||
CHECK(n2->id() == node_visitor.nodes_[7]->id());
|
||||
CHECK(n6->id() == node_visitor.nodes_[8]->id());
|
||||
CHECK(n7->id() == node_visitor.nodes_[9]->id());
|
||||
CHECK(n3->id() == node_visitor.nodes_[10]->id());
|
||||
CHECK(graph.start()->id() == node_visitor.nodes_[11]->id());
|
||||
}
|
||||
|
||||
|
||||
TEST(TestUseNodePreOrderVisitCycle) {
|
||||
GraphWithStartNodeTester graph;
|
||||
Node* n0 = graph.start_node();
|
||||
Node* n1 = graph.NewNode(&dummy_operator, n0);
|
||||
Node* n2 = graph.NewNode(&dummy_operator, n1);
|
||||
n0->AppendInput(graph.main_zone(), n2);
|
||||
graph.SetStart(n0);
|
||||
graph.SetEnd(n2);
|
||||
|
||||
PreNodeVisitor node_visitor;
|
||||
graph.VisitNodeUsesFromStart(&node_visitor);
|
||||
|
||||
CHECK_EQ(3, node_visitor.nodes_.size());
|
||||
CHECK(n0->id() == node_visitor.nodes_[0]->id());
|
||||
CHECK(n1->id() == node_visitor.nodes_[1]->id());
|
||||
CHECK(n2->id() == node_visitor.nodes_[2]->id());
|
||||
}
|
||||
|
||||
|
||||
struct ReenterNodeVisitor : NullNodeVisitor {
|
||||
GenericGraphVisit::Control Pre(Node* node) {
|
||||
printf("[%d] PRE NODE: %d\n", static_cast<int>(nodes_.size()), node->id());
|
||||
nodes_.push_back(node->id());
|
||||
int size = nodes_.size();
|
||||
switch (node->id()) {
|
||||
case 0:
|
||||
return size < 6 ? GenericGraphVisit::REENTER : GenericGraphVisit::SKIP;
|
||||
case 1:
|
||||
return size < 4 ? GenericGraphVisit::DEFER
|
||||
: GenericGraphVisit::CONTINUE;
|
||||
default:
|
||||
return GenericGraphVisit::REENTER;
|
||||
}
|
||||
}
|
||||
|
||||
GenericGraphVisit::Control Post(Node* node) {
|
||||
printf("[%d] POST NODE: %d\n", static_cast<int>(nodes_.size()), node->id());
|
||||
nodes_.push_back(-node->id());
|
||||
return node->id() == 4 ? GenericGraphVisit::REENTER
|
||||
: GenericGraphVisit::CONTINUE;
|
||||
}
|
||||
|
||||
void PreEdge(Node* from, int index, Node* to) {
|
||||
printf("[%d] PRE EDGE: %d-%d\n", static_cast<int>(edges_.size()),
|
||||
from->id(), to->id());
|
||||
edges_.push_back(std::make_pair(from->id(), to->id()));
|
||||
}
|
||||
|
||||
void PostEdge(Node* from, int index, Node* to) {
|
||||
printf("[%d] POST EDGE: %d-%d\n", static_cast<int>(edges_.size()),
|
||||
from->id(), to->id());
|
||||
edges_.push_back(std::make_pair(-from->id(), -to->id()));
|
||||
}
|
||||
|
||||
std::vector<int> nodes_;
|
||||
std::vector<std::pair<int, int> > edges_;
|
||||
};
|
||||
|
||||
|
||||
TEST(TestUseNodeReenterVisit) {
|
||||
GraphWithStartNodeTester graph;
|
||||
Node* n0 = graph.start_node();
|
||||
Node* n1 = graph.NewNode(&dummy_operator, n0);
|
||||
Node* n2 = graph.NewNode(&dummy_operator, n0);
|
||||
Node* n3 = graph.NewNode(&dummy_operator, n2);
|
||||
Node* n4 = graph.NewNode(&dummy_operator, n0);
|
||||
Node* n5 = graph.NewNode(&dummy_operator, n4);
|
||||
n0->AppendInput(graph.main_zone(), n3);
|
||||
graph.SetStart(n0);
|
||||
graph.SetEnd(n5);
|
||||
|
||||
ReenterNodeVisitor visitor;
|
||||
graph.VisitNodeUsesFromStart(&visitor);
|
||||
|
||||
CHECK_EQ(22, visitor.nodes_.size());
|
||||
CHECK_EQ(24, visitor.edges_.size());
|
||||
|
||||
CHECK(n0->id() == visitor.nodes_[0]);
|
||||
CHECK(n0->id() == visitor.edges_[0].first);
|
||||
CHECK(n1->id() == visitor.edges_[0].second);
|
||||
CHECK(n1->id() == visitor.nodes_[1]);
|
||||
// N1 is deferred.
|
||||
CHECK(-n1->id() == visitor.edges_[1].second);
|
||||
CHECK(-n0->id() == visitor.edges_[1].first);
|
||||
CHECK(n0->id() == visitor.edges_[2].first);
|
||||
CHECK(n2->id() == visitor.edges_[2].second);
|
||||
CHECK(n2->id() == visitor.nodes_[2]);
|
||||
CHECK(n2->id() == visitor.edges_[3].first);
|
||||
CHECK(n3->id() == visitor.edges_[3].second);
|
||||
CHECK(n3->id() == visitor.nodes_[3]);
|
||||
// Circle back to N0, which we may reenter for now.
|
||||
CHECK(n3->id() == visitor.edges_[4].first);
|
||||
CHECK(n0->id() == visitor.edges_[4].second);
|
||||
CHECK(n0->id() == visitor.nodes_[4]);
|
||||
CHECK(n0->id() == visitor.edges_[5].first);
|
||||
CHECK(n1->id() == visitor.edges_[5].second);
|
||||
CHECK(n1->id() == visitor.nodes_[5]);
|
||||
// This time N1 is no longer deferred.
|
||||
CHECK(-n1->id() == visitor.nodes_[6]);
|
||||
CHECK(-n1->id() == visitor.edges_[6].second);
|
||||
CHECK(-n0->id() == visitor.edges_[6].first);
|
||||
CHECK(n0->id() == visitor.edges_[7].first);
|
||||
CHECK(n2->id() == visitor.edges_[7].second);
|
||||
CHECK(n2->id() == visitor.nodes_[7]);
|
||||
CHECK(n2->id() == visitor.edges_[8].first);
|
||||
CHECK(n3->id() == visitor.edges_[8].second);
|
||||
CHECK(n3->id() == visitor.nodes_[8]);
|
||||
CHECK(n3->id() == visitor.edges_[9].first);
|
||||
CHECK(n0->id() == visitor.edges_[9].second);
|
||||
CHECK(n0->id() == visitor.nodes_[9]);
|
||||
// This time we break at N0 and skip it.
|
||||
CHECK(-n0->id() == visitor.edges_[10].second);
|
||||
CHECK(-n3->id() == visitor.edges_[10].first);
|
||||
CHECK(-n3->id() == visitor.nodes_[10]);
|
||||
CHECK(-n3->id() == visitor.edges_[11].second);
|
||||
CHECK(-n2->id() == visitor.edges_[11].first);
|
||||
CHECK(-n2->id() == visitor.nodes_[11]);
|
||||
CHECK(-n2->id() == visitor.edges_[12].second);
|
||||
CHECK(-n0->id() == visitor.edges_[12].first);
|
||||
CHECK(n0->id() == visitor.edges_[13].first);
|
||||
CHECK(n4->id() == visitor.edges_[13].second);
|
||||
CHECK(n4->id() == visitor.nodes_[12]);
|
||||
CHECK(n4->id() == visitor.edges_[14].first);
|
||||
CHECK(n5->id() == visitor.edges_[14].second);
|
||||
CHECK(n5->id() == visitor.nodes_[13]);
|
||||
CHECK(-n5->id() == visitor.nodes_[14]);
|
||||
CHECK(-n5->id() == visitor.edges_[15].second);
|
||||
CHECK(-n4->id() == visitor.edges_[15].first);
|
||||
CHECK(-n4->id() == visitor.nodes_[15]);
|
||||
CHECK(-n4->id() == visitor.edges_[16].second);
|
||||
CHECK(-n0->id() == visitor.edges_[16].first);
|
||||
CHECK(-n0->id() == visitor.nodes_[16]);
|
||||
CHECK(-n0->id() == visitor.edges_[17].second);
|
||||
CHECK(-n3->id() == visitor.edges_[17].first);
|
||||
CHECK(-n3->id() == visitor.nodes_[17]);
|
||||
CHECK(-n3->id() == visitor.edges_[18].second);
|
||||
CHECK(-n2->id() == visitor.edges_[18].first);
|
||||
CHECK(-n2->id() == visitor.nodes_[18]);
|
||||
CHECK(-n2->id() == visitor.edges_[19].second);
|
||||
CHECK(-n0->id() == visitor.edges_[19].first);
|
||||
// N4 may be reentered.
|
||||
CHECK(n0->id() == visitor.edges_[20].first);
|
||||
CHECK(n4->id() == visitor.edges_[20].second);
|
||||
CHECK(n4->id() == visitor.nodes_[19]);
|
||||
CHECK(n4->id() == visitor.edges_[21].first);
|
||||
CHECK(n5->id() == visitor.edges_[21].second);
|
||||
CHECK(-n5->id() == visitor.edges_[22].second);
|
||||
CHECK(-n4->id() == visitor.edges_[22].first);
|
||||
CHECK(-n4->id() == visitor.nodes_[20]);
|
||||
CHECK(-n4->id() == visitor.edges_[23].second);
|
||||
CHECK(-n0->id() == visitor.edges_[23].first);
|
||||
CHECK(-n0->id() == visitor.nodes_[21]);
|
||||
}
|
||||
|
||||
|
||||
TEST(TestPrintNodeGraphToNodeGraphviz) {
|
||||
GraphWithStartNodeTester graph;
|
||||
Node* n2 = graph.NewNode(&dummy_operator, graph.start());
|
||||
Node* n3 = graph.NewNode(&dummy_operator, graph.start());
|
||||
Node* n4 = graph.NewNode(&dummy_operator, n2);
|
||||
Node* n5 = graph.NewNode(&dummy_operator, n2);
|
||||
Node* n6 = graph.NewNode(&dummy_operator, n3);
|
||||
Node* n7 = graph.NewNode(&dummy_operator, n3);
|
||||
Node* n8 = graph.NewNode(&dummy_operator, n5);
|
||||
Node* n9 = graph.NewNode(&dummy_operator, n5);
|
||||
Node* n10 = graph.NewNode(&dummy_operator, n9);
|
||||
Node* n11 = graph.NewNode(&dummy_operator, n9);
|
||||
Node* end_dependencies[6] = {n4, n8, n10, n11, n6, n7};
|
||||
Node* n12 = graph.NewNode(&dummy_operator, 6, end_dependencies);
|
||||
graph.SetEnd(n12);
|
||||
|
||||
OFStream os(stdout);
|
||||
os << AsDOT(graph);
|
||||
}
|
@ -1,160 +0,0 @@
|
||||
// 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 "src/v8.h"
|
||||
|
||||
#include "graph-tester.h"
|
||||
#include "src/compiler/common-operator.h"
|
||||
#include "src/compiler/node-cache.h"
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
|
||||
TEST(Int32Constant_back_to_back) {
|
||||
GraphTester graph;
|
||||
Int32NodeCache cache;
|
||||
|
||||
for (int i = -2000000000; i < 2000000000; i += 3315177) {
|
||||
Node** pos = cache.Find(graph.zone(), i);
|
||||
CHECK_NE(NULL, pos);
|
||||
for (int j = 0; j < 3; j++) {
|
||||
Node** npos = cache.Find(graph.zone(), i);
|
||||
CHECK_EQ(pos, npos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(Int32Constant_five) {
|
||||
GraphTester graph;
|
||||
Int32NodeCache cache;
|
||||
CommonOperatorBuilder common(graph.zone());
|
||||
|
||||
int32_t constants[] = {static_cast<int32_t>(0x80000000), -77, 0, 1, -1};
|
||||
|
||||
Node* nodes[ARRAY_SIZE(constants)];
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(constants); i++) {
|
||||
int32_t k = constants[i];
|
||||
Node* node = graph.NewNode(common.Int32Constant(k));
|
||||
*cache.Find(graph.zone(), k) = nodes[i] = node;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(constants); i++) {
|
||||
int32_t k = constants[i];
|
||||
CHECK_EQ(nodes[i], *cache.Find(graph.zone(), k));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(Int32Constant_hits) {
|
||||
GraphTester graph;
|
||||
Int32NodeCache cache;
|
||||
const int32_t kSize = 1500;
|
||||
Node** nodes = graph.zone()->NewArray<Node*>(kSize);
|
||||
CommonOperatorBuilder common(graph.zone());
|
||||
|
||||
for (int i = 0; i < kSize; i++) {
|
||||
int32_t v = i * -55;
|
||||
nodes[i] = graph.NewNode(common.Int32Constant(v));
|
||||
*cache.Find(graph.zone(), v) = nodes[i];
|
||||
}
|
||||
|
||||
int hits = 0;
|
||||
for (int i = 0; i < kSize; i++) {
|
||||
int32_t v = i * -55;
|
||||
Node** pos = cache.Find(graph.zone(), v);
|
||||
if (*pos != NULL) {
|
||||
CHECK_EQ(nodes[i], *pos);
|
||||
hits++;
|
||||
}
|
||||
}
|
||||
CHECK_LT(4, hits);
|
||||
}
|
||||
|
||||
|
||||
TEST(Int64Constant_back_to_back) {
|
||||
GraphTester graph;
|
||||
Int64NodeCache cache;
|
||||
|
||||
for (int64_t i = -2000000000; i < 2000000000; i += 3315177) {
|
||||
Node** pos = cache.Find(graph.zone(), i);
|
||||
CHECK_NE(NULL, pos);
|
||||
for (int j = 0; j < 3; j++) {
|
||||
Node** npos = cache.Find(graph.zone(), i);
|
||||
CHECK_EQ(pos, npos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(Int64Constant_hits) {
|
||||
GraphTester graph;
|
||||
Int64NodeCache cache;
|
||||
const int32_t kSize = 1500;
|
||||
Node** nodes = graph.zone()->NewArray<Node*>(kSize);
|
||||
CommonOperatorBuilder common(graph.zone());
|
||||
|
||||
for (int i = 0; i < kSize; i++) {
|
||||
int64_t v = static_cast<int64_t>(i) * static_cast<int64_t>(5003001);
|
||||
nodes[i] = graph.NewNode(common.Int32Constant(i));
|
||||
*cache.Find(graph.zone(), v) = nodes[i];
|
||||
}
|
||||
|
||||
int hits = 0;
|
||||
for (int i = 0; i < kSize; i++) {
|
||||
int64_t v = static_cast<int64_t>(i) * static_cast<int64_t>(5003001);
|
||||
Node** pos = cache.Find(graph.zone(), v);
|
||||
if (*pos != NULL) {
|
||||
CHECK_EQ(nodes[i], *pos);
|
||||
hits++;
|
||||
}
|
||||
}
|
||||
CHECK_LT(4, hits);
|
||||
}
|
||||
|
||||
|
||||
TEST(PtrConstant_back_to_back) {
|
||||
GraphTester graph;
|
||||
PtrNodeCache cache;
|
||||
int32_t buffer[50];
|
||||
|
||||
for (int32_t* p = buffer;
|
||||
(p - buffer) < static_cast<ptrdiff_t>(ARRAY_SIZE(buffer)); p++) {
|
||||
Node** pos = cache.Find(graph.zone(), p);
|
||||
CHECK_NE(NULL, pos);
|
||||
for (int j = 0; j < 3; j++) {
|
||||
Node** npos = cache.Find(graph.zone(), p);
|
||||
CHECK_EQ(pos, npos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(PtrConstant_hits) {
|
||||
GraphTester graph;
|
||||
PtrNodeCache cache;
|
||||
const int32_t kSize = 50;
|
||||
int32_t buffer[kSize];
|
||||
Node* nodes[kSize];
|
||||
CommonOperatorBuilder common(graph.zone());
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(buffer); i++) {
|
||||
int k = static_cast<int>(i);
|
||||
int32_t* p = &buffer[i];
|
||||
nodes[i] = graph.NewNode(common.Int32Constant(k));
|
||||
*cache.Find(graph.zone(), p) = nodes[i];
|
||||
}
|
||||
|
||||
int hits = 0;
|
||||
for (size_t i = 0; i < ARRAY_SIZE(buffer); i++) {
|
||||
int32_t* p = &buffer[i];
|
||||
Node** pos = cache.Find(graph.zone(), p);
|
||||
if (*pos != NULL) {
|
||||
CHECK_EQ(nodes[i], *pos);
|
||||
hits++;
|
||||
}
|
||||
}
|
||||
CHECK_LT(4, hits);
|
||||
}
|
@ -1,813 +0,0 @@
|
||||
// Copyright 2013 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 "graph-tester.h"
|
||||
#include "src/compiler/generic-node-inl.h"
|
||||
#include "src/compiler/node.h"
|
||||
#include "src/compiler/operator.h"
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
|
||||
static SimpleOperator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
|
||||
0, 0, "dummy");
|
||||
|
||||
TEST(NodeAllocation) {
|
||||
GraphTester graph;
|
||||
Node* n1 = graph.NewNode(&dummy_operator);
|
||||
Node* n2 = graph.NewNode(&dummy_operator);
|
||||
CHECK(n2->id() != n1->id());
|
||||
}
|
||||
|
||||
|
||||
TEST(NodeWithOpcode) {
|
||||
GraphTester graph;
|
||||
Node* n1 = graph.NewNode(&dummy_operator);
|
||||
Node* n2 = graph.NewNode(&dummy_operator);
|
||||
CHECK(n1->op() == &dummy_operator);
|
||||
CHECK(n2->op() == &dummy_operator);
|
||||
}
|
||||
|
||||
|
||||
TEST(NodeInputs1) {
|
||||
GraphTester graph;
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n2 = graph.NewNode(&dummy_operator, n0);
|
||||
CHECK_EQ(1, n2->InputCount());
|
||||
CHECK(n0 == n2->InputAt(0));
|
||||
}
|
||||
|
||||
|
||||
TEST(NodeInputs2) {
|
||||
GraphTester graph;
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n1 = graph.NewNode(&dummy_operator);
|
||||
Node* n2 = graph.NewNode(&dummy_operator, n0, n1);
|
||||
CHECK_EQ(2, n2->InputCount());
|
||||
CHECK(n0 == n2->InputAt(0));
|
||||
CHECK(n1 == n2->InputAt(1));
|
||||
}
|
||||
|
||||
|
||||
TEST(NodeInputs3) {
|
||||
GraphTester graph;
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n1 = graph.NewNode(&dummy_operator);
|
||||
Node* n2 = graph.NewNode(&dummy_operator, n0, n1, n1);
|
||||
CHECK_EQ(3, n2->InputCount());
|
||||
CHECK(n0 == n2->InputAt(0));
|
||||
CHECK(n1 == n2->InputAt(1));
|
||||
CHECK(n1 == n2->InputAt(2));
|
||||
}
|
||||
|
||||
|
||||
TEST(NodeInputIteratorEmpty) {
|
||||
GraphTester graph;
|
||||
Node* n1 = graph.NewNode(&dummy_operator);
|
||||
Node::Inputs::iterator i(n1->inputs().begin());
|
||||
int input_count = 0;
|
||||
for (; i != n1->inputs().end(); ++i) {
|
||||
input_count++;
|
||||
}
|
||||
CHECK_EQ(0, input_count);
|
||||
}
|
||||
|
||||
|
||||
TEST(NodeInputIteratorOne) {
|
||||
GraphTester graph;
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n1 = graph.NewNode(&dummy_operator, n0);
|
||||
Node::Inputs::iterator i(n1->inputs().begin());
|
||||
CHECK_EQ(1, n1->InputCount());
|
||||
CHECK_EQ(n0, *i);
|
||||
++i;
|
||||
CHECK(n1->inputs().end() == i);
|
||||
}
|
||||
|
||||
|
||||
TEST(NodeUseIteratorEmpty) {
|
||||
GraphTester graph;
|
||||
Node* n1 = graph.NewNode(&dummy_operator);
|
||||
Node::Uses::iterator i(n1->uses().begin());
|
||||
int use_count = 0;
|
||||
for (; i != n1->uses().end(); ++i) {
|
||||
Node::Edge edge(i.edge());
|
||||
USE(edge);
|
||||
use_count++;
|
||||
}
|
||||
CHECK_EQ(0, use_count);
|
||||
}
|
||||
|
||||
|
||||
TEST(NodeUseIteratorOne) {
|
||||
GraphTester graph;
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n1 = graph.NewNode(&dummy_operator, n0);
|
||||
Node::Uses::iterator i(n0->uses().begin());
|
||||
CHECK_EQ(n1, *i);
|
||||
++i;
|
||||
CHECK(n0->uses().end() == i);
|
||||
}
|
||||
|
||||
|
||||
TEST(NodeUseIteratorReplaceNoUses) {
|
||||
GraphTester graph;
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n3 = graph.NewNode(&dummy_operator);
|
||||
n0->ReplaceUses(n3);
|
||||
CHECK(n0->uses().begin() == n0->uses().end());
|
||||
}
|
||||
|
||||
|
||||
TEST(NodeUseIteratorReplaceUses) {
|
||||
GraphTester graph;
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n1 = graph.NewNode(&dummy_operator, n0);
|
||||
Node* n2 = graph.NewNode(&dummy_operator, n0);
|
||||
Node* n3 = graph.NewNode(&dummy_operator);
|
||||
Node::Uses::iterator i1(n0->uses().begin());
|
||||
CHECK_EQ(n1, *i1);
|
||||
++i1;
|
||||
CHECK_EQ(n2, *i1);
|
||||
n0->ReplaceUses(n3);
|
||||
Node::Uses::iterator i2(n3->uses().begin());
|
||||
CHECK_EQ(n1, *i2);
|
||||
++i2;
|
||||
CHECK_EQ(n2, *i2);
|
||||
Node::Inputs::iterator i3(n1->inputs().begin());
|
||||
CHECK_EQ(n3, *i3);
|
||||
++i3;
|
||||
CHECK(n1->inputs().end() == i3);
|
||||
Node::Inputs::iterator i4(n2->inputs().begin());
|
||||
CHECK_EQ(n3, *i4);
|
||||
++i4;
|
||||
CHECK(n2->inputs().end() == i4);
|
||||
}
|
||||
|
||||
|
||||
TEST(NodeUseIteratorReplaceUsesSelf) {
|
||||
GraphTester graph;
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n1 = graph.NewNode(&dummy_operator, n0);
|
||||
Node* n3 = graph.NewNode(&dummy_operator);
|
||||
|
||||
n1->ReplaceInput(0, n1); // Create self-reference.
|
||||
|
||||
Node::Uses::iterator i1(n1->uses().begin());
|
||||
CHECK_EQ(n1, *i1);
|
||||
|
||||
n1->ReplaceUses(n3);
|
||||
|
||||
CHECK(n1->uses().begin() == n1->uses().end());
|
||||
|
||||
Node::Uses::iterator i2(n3->uses().begin());
|
||||
CHECK_EQ(n1, *i2);
|
||||
++i2;
|
||||
CHECK(n1->uses().end() == i2);
|
||||
}
|
||||
|
||||
|
||||
TEST(ReplaceInput) {
|
||||
GraphTester graph;
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n1 = graph.NewNode(&dummy_operator);
|
||||
Node* n2 = graph.NewNode(&dummy_operator);
|
||||
Node* n3 = graph.NewNode(&dummy_operator, n0, n1, n2);
|
||||
Node::Inputs::iterator i1(n3->inputs().begin());
|
||||
CHECK(n0 == *i1);
|
||||
CHECK_EQ(n0, n3->InputAt(0));
|
||||
++i1;
|
||||
CHECK_EQ(n1, *i1);
|
||||
CHECK_EQ(n1, n3->InputAt(1));
|
||||
++i1;
|
||||
CHECK_EQ(n2, *i1);
|
||||
CHECK_EQ(n2, n3->InputAt(2));
|
||||
++i1;
|
||||
CHECK(i1 == n3->inputs().end());
|
||||
|
||||
Node::Uses::iterator i2(n1->uses().begin());
|
||||
CHECK_EQ(n3, *i2);
|
||||
++i2;
|
||||
CHECK(i2 == n1->uses().end());
|
||||
|
||||
Node* n4 = graph.NewNode(&dummy_operator);
|
||||
Node::Uses::iterator i3(n4->uses().begin());
|
||||
CHECK(i3 == n4->uses().end());
|
||||
|
||||
n3->ReplaceInput(1, n4);
|
||||
|
||||
Node::Uses::iterator i4(n1->uses().begin());
|
||||
CHECK(i4 == n1->uses().end());
|
||||
|
||||
Node::Uses::iterator i5(n4->uses().begin());
|
||||
CHECK_EQ(n3, *i5);
|
||||
++i5;
|
||||
CHECK(i5 == n4->uses().end());
|
||||
|
||||
Node::Inputs::iterator i6(n3->inputs().begin());
|
||||
CHECK(n0 == *i6);
|
||||
CHECK_EQ(n0, n3->InputAt(0));
|
||||
++i6;
|
||||
CHECK_EQ(n4, *i6);
|
||||
CHECK_EQ(n4, n3->InputAt(1));
|
||||
++i6;
|
||||
CHECK_EQ(n2, *i6);
|
||||
CHECK_EQ(n2, n3->InputAt(2));
|
||||
++i6;
|
||||
CHECK(i6 == n3->inputs().end());
|
||||
}
|
||||
|
||||
|
||||
TEST(OwnedBy) {
|
||||
GraphTester graph;
|
||||
|
||||
{
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n1 = graph.NewNode(&dummy_operator);
|
||||
|
||||
CHECK(!n0->OwnedBy(n1));
|
||||
CHECK(!n1->OwnedBy(n0));
|
||||
|
||||
Node* n2 = graph.NewNode(&dummy_operator, n0);
|
||||
CHECK(n0->OwnedBy(n2));
|
||||
CHECK(!n2->OwnedBy(n0));
|
||||
|
||||
Node* n3 = graph.NewNode(&dummy_operator, n0);
|
||||
CHECK(!n0->OwnedBy(n2));
|
||||
CHECK(!n0->OwnedBy(n3));
|
||||
CHECK(!n2->OwnedBy(n0));
|
||||
CHECK(!n3->OwnedBy(n0));
|
||||
}
|
||||
|
||||
{
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n1 = graph.NewNode(&dummy_operator, n0);
|
||||
CHECK(n0->OwnedBy(n1));
|
||||
CHECK(!n1->OwnedBy(n0));
|
||||
Node* n2 = graph.NewNode(&dummy_operator, n0);
|
||||
CHECK(!n0->OwnedBy(n1));
|
||||
CHECK(!n0->OwnedBy(n2));
|
||||
CHECK(!n1->OwnedBy(n0));
|
||||
CHECK(!n1->OwnedBy(n2));
|
||||
CHECK(!n2->OwnedBy(n0));
|
||||
CHECK(!n2->OwnedBy(n1));
|
||||
|
||||
Node* n3 = graph.NewNode(&dummy_operator);
|
||||
n2->ReplaceInput(0, n3);
|
||||
|
||||
CHECK(n0->OwnedBy(n1));
|
||||
CHECK(!n1->OwnedBy(n0));
|
||||
CHECK(!n1->OwnedBy(n0));
|
||||
CHECK(!n1->OwnedBy(n2));
|
||||
CHECK(!n2->OwnedBy(n0));
|
||||
CHECK(!n2->OwnedBy(n1));
|
||||
CHECK(n3->OwnedBy(n2));
|
||||
CHECK(!n2->OwnedBy(n3));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(Uses) {
|
||||
GraphTester graph;
|
||||
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n1 = graph.NewNode(&dummy_operator, n0);
|
||||
CHECK_EQ(1, n0->UseCount());
|
||||
printf("A: %d vs %d\n", n0->UseAt(0)->id(), n1->id());
|
||||
CHECK(n0->UseAt(0) == n1);
|
||||
Node* n2 = graph.NewNode(&dummy_operator, n0);
|
||||
CHECK_EQ(2, n0->UseCount());
|
||||
printf("B: %d vs %d\n", n0->UseAt(1)->id(), n2->id());
|
||||
CHECK(n0->UseAt(1) == n2);
|
||||
Node* n3 = graph.NewNode(&dummy_operator, n0);
|
||||
CHECK_EQ(3, n0->UseCount());
|
||||
CHECK(n0->UseAt(2) == n3);
|
||||
}
|
||||
|
||||
|
||||
TEST(Inputs) {
|
||||
GraphTester graph;
|
||||
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n1 = graph.NewNode(&dummy_operator, n0);
|
||||
Node* n2 = graph.NewNode(&dummy_operator, n0);
|
||||
Node* n3 = graph.NewNode(&dummy_operator, n0, n1, n2);
|
||||
CHECK_EQ(3, n3->InputCount());
|
||||
CHECK(n3->InputAt(0) == n0);
|
||||
CHECK(n3->InputAt(1) == n1);
|
||||
CHECK(n3->InputAt(2) == n2);
|
||||
Node* n4 = graph.NewNode(&dummy_operator, n0, n1, n2);
|
||||
n3->AppendInput(graph.zone(), n4);
|
||||
CHECK_EQ(4, n3->InputCount());
|
||||
CHECK(n3->InputAt(0) == n0);
|
||||
CHECK(n3->InputAt(1) == n1);
|
||||
CHECK(n3->InputAt(2) == n2);
|
||||
CHECK(n3->InputAt(3) == n4);
|
||||
Node* n5 = graph.NewNode(&dummy_operator, n4);
|
||||
n3->AppendInput(graph.zone(), n4);
|
||||
CHECK_EQ(5, n3->InputCount());
|
||||
CHECK(n3->InputAt(0) == n0);
|
||||
CHECK(n3->InputAt(1) == n1);
|
||||
CHECK(n3->InputAt(2) == n2);
|
||||
CHECK(n3->InputAt(3) == n4);
|
||||
CHECK(n3->InputAt(4) == n4);
|
||||
|
||||
// Make sure uses have been hooked op correctly.
|
||||
Node::Uses uses(n4->uses());
|
||||
Node::Uses::iterator current = uses.begin();
|
||||
CHECK(current != uses.end());
|
||||
CHECK(*current == n3);
|
||||
++current;
|
||||
CHECK(current != uses.end());
|
||||
CHECK(*current == n5);
|
||||
++current;
|
||||
CHECK(current != uses.end());
|
||||
CHECK(*current == n3);
|
||||
++current;
|
||||
CHECK(current == uses.end());
|
||||
}
|
||||
|
||||
|
||||
TEST(AppendInputsAndIterator) {
|
||||
GraphTester graph;
|
||||
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n1 = graph.NewNode(&dummy_operator, n0);
|
||||
Node* n2 = graph.NewNode(&dummy_operator, n0, n1);
|
||||
|
||||
Node::Inputs inputs(n2->inputs());
|
||||
Node::Inputs::iterator current = inputs.begin();
|
||||
CHECK(current != inputs.end());
|
||||
CHECK(*current == n0);
|
||||
++current;
|
||||
CHECK(current != inputs.end());
|
||||
CHECK(*current == n1);
|
||||
++current;
|
||||
CHECK(current == inputs.end());
|
||||
|
||||
Node* n3 = graph.NewNode(&dummy_operator);
|
||||
n2->AppendInput(graph.zone(), n3);
|
||||
inputs = n2->inputs();
|
||||
current = inputs.begin();
|
||||
CHECK(current != inputs.end());
|
||||
CHECK(*current == n0);
|
||||
CHECK_EQ(0, current.index());
|
||||
++current;
|
||||
CHECK(current != inputs.end());
|
||||
CHECK(*current == n1);
|
||||
CHECK_EQ(1, current.index());
|
||||
++current;
|
||||
CHECK(current != inputs.end());
|
||||
CHECK(*current == n3);
|
||||
CHECK_EQ(2, current.index());
|
||||
++current;
|
||||
CHECK(current == inputs.end());
|
||||
}
|
||||
|
||||
|
||||
TEST(NullInputsSimple) {
|
||||
GraphTester graph;
|
||||
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n1 = graph.NewNode(&dummy_operator, n0);
|
||||
Node* n2 = graph.NewNode(&dummy_operator, n0, n1);
|
||||
CHECK_EQ(2, n2->InputCount());
|
||||
|
||||
CHECK(n0 == n2->InputAt(0));
|
||||
CHECK(n1 == n2->InputAt(1));
|
||||
CHECK_EQ(2, n0->UseCount());
|
||||
n2->ReplaceInput(0, NULL);
|
||||
CHECK(NULL == n2->InputAt(0));
|
||||
CHECK(n1 == n2->InputAt(1));
|
||||
CHECK_EQ(1, n0->UseCount());
|
||||
}
|
||||
|
||||
|
||||
TEST(NullInputsAppended) {
|
||||
GraphTester graph;
|
||||
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n1 = graph.NewNode(&dummy_operator, n0);
|
||||
Node* n2 = graph.NewNode(&dummy_operator, n0);
|
||||
Node* n3 = graph.NewNode(&dummy_operator, n0);
|
||||
n3->AppendInput(graph.zone(), n1);
|
||||
n3->AppendInput(graph.zone(), n2);
|
||||
CHECK_EQ(3, n3->InputCount());
|
||||
|
||||
CHECK(n0 == n3->InputAt(0));
|
||||
CHECK(n1 == n3->InputAt(1));
|
||||
CHECK(n2 == n3->InputAt(2));
|
||||
CHECK_EQ(1, n1->UseCount());
|
||||
n3->ReplaceInput(1, NULL);
|
||||
CHECK(n0 == n3->InputAt(0));
|
||||
CHECK(NULL == n3->InputAt(1));
|
||||
CHECK(n2 == n3->InputAt(2));
|
||||
CHECK_EQ(0, n1->UseCount());
|
||||
}
|
||||
|
||||
|
||||
TEST(ReplaceUsesFromAppendedInputs) {
|
||||
GraphTester graph;
|
||||
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n1 = graph.NewNode(&dummy_operator, n0);
|
||||
Node* n2 = graph.NewNode(&dummy_operator, n0);
|
||||
Node* n3 = graph.NewNode(&dummy_operator);
|
||||
n2->AppendInput(graph.zone(), n1);
|
||||
n2->AppendInput(graph.zone(), n0);
|
||||
CHECK_EQ(0, n3->UseCount());
|
||||
CHECK_EQ(3, n0->UseCount());
|
||||
n0->ReplaceUses(n3);
|
||||
CHECK_EQ(0, n0->UseCount());
|
||||
CHECK_EQ(3, n3->UseCount());
|
||||
|
||||
Node::Uses uses(n3->uses());
|
||||
Node::Uses::iterator current = uses.begin();
|
||||
CHECK(current != uses.end());
|
||||
CHECK(*current == n1);
|
||||
++current;
|
||||
CHECK(current != uses.end());
|
||||
CHECK(*current == n2);
|
||||
++current;
|
||||
CHECK(current != uses.end());
|
||||
CHECK(*current == n2);
|
||||
++current;
|
||||
CHECK(current == uses.end());
|
||||
}
|
||||
|
||||
|
||||
template <bool result>
|
||||
struct FixedPredicate {
|
||||
bool operator()(const Node* node) const { return result; }
|
||||
};
|
||||
|
||||
|
||||
TEST(ReplaceUsesIfWithFixedPredicate) {
|
||||
GraphTester graph;
|
||||
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n1 = graph.NewNode(&dummy_operator, n0);
|
||||
Node* n2 = graph.NewNode(&dummy_operator, n0);
|
||||
Node* n3 = graph.NewNode(&dummy_operator);
|
||||
|
||||
CHECK_EQ(0, n2->UseCount());
|
||||
n2->ReplaceUsesIf(FixedPredicate<true>(), n1);
|
||||
CHECK_EQ(0, n2->UseCount());
|
||||
n2->ReplaceUsesIf(FixedPredicate<false>(), n1);
|
||||
CHECK_EQ(0, n2->UseCount());
|
||||
|
||||
CHECK_EQ(0, n3->UseCount());
|
||||
n3->ReplaceUsesIf(FixedPredicate<true>(), n1);
|
||||
CHECK_EQ(0, n3->UseCount());
|
||||
n3->ReplaceUsesIf(FixedPredicate<false>(), n1);
|
||||
CHECK_EQ(0, n3->UseCount());
|
||||
|
||||
CHECK_EQ(2, n0->UseCount());
|
||||
CHECK_EQ(0, n1->UseCount());
|
||||
n0->ReplaceUsesIf(FixedPredicate<false>(), n1);
|
||||
CHECK_EQ(2, n0->UseCount());
|
||||
CHECK_EQ(0, n1->UseCount());
|
||||
n0->ReplaceUsesIf(FixedPredicate<true>(), n1);
|
||||
CHECK_EQ(0, n0->UseCount());
|
||||
CHECK_EQ(2, n1->UseCount());
|
||||
|
||||
n1->AppendInput(graph.zone(), n1);
|
||||
CHECK_EQ(3, n1->UseCount());
|
||||
n1->AppendInput(graph.zone(), n3);
|
||||
CHECK_EQ(1, n3->UseCount());
|
||||
n3->ReplaceUsesIf(FixedPredicate<true>(), n1);
|
||||
CHECK_EQ(4, n1->UseCount());
|
||||
CHECK_EQ(0, n3->UseCount());
|
||||
n1->ReplaceUsesIf(FixedPredicate<false>(), n3);
|
||||
CHECK_EQ(4, n1->UseCount());
|
||||
CHECK_EQ(0, n3->UseCount());
|
||||
}
|
||||
|
||||
|
||||
TEST(ReplaceUsesIfWithEqualTo) {
|
||||
GraphTester graph;
|
||||
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n1 = graph.NewNode(&dummy_operator, n0);
|
||||
Node* n2 = graph.NewNode(&dummy_operator, n0, n1);
|
||||
|
||||
CHECK_EQ(0, n2->UseCount());
|
||||
n2->ReplaceUsesIf(std::bind1st(std::equal_to<Node*>(), n1), n0);
|
||||
CHECK_EQ(0, n2->UseCount());
|
||||
|
||||
CHECK_EQ(2, n0->UseCount());
|
||||
CHECK_EQ(1, n1->UseCount());
|
||||
n1->ReplaceUsesIf(std::bind1st(std::equal_to<Node*>(), n0), n0);
|
||||
CHECK_EQ(2, n0->UseCount());
|
||||
CHECK_EQ(1, n1->UseCount());
|
||||
n0->ReplaceUsesIf(std::bind2nd(std::equal_to<Node*>(), n2), n1);
|
||||
CHECK_EQ(1, n0->UseCount());
|
||||
CHECK_EQ(2, n1->UseCount());
|
||||
}
|
||||
|
||||
|
||||
TEST(ReplaceInputMultipleUses) {
|
||||
GraphTester graph;
|
||||
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n1 = graph.NewNode(&dummy_operator);
|
||||
Node* n2 = graph.NewNode(&dummy_operator, n0);
|
||||
n2->ReplaceInput(0, n1);
|
||||
CHECK_EQ(0, n0->UseCount());
|
||||
CHECK_EQ(1, n1->UseCount());
|
||||
|
||||
Node* n3 = graph.NewNode(&dummy_operator, n0);
|
||||
n3->ReplaceInput(0, n1);
|
||||
CHECK_EQ(0, n0->UseCount());
|
||||
CHECK_EQ(2, n1->UseCount());
|
||||
}
|
||||
|
||||
|
||||
TEST(TrimInputCountInline) {
|
||||
GraphTester graph;
|
||||
|
||||
{
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n1 = graph.NewNode(&dummy_operator, n0);
|
||||
n1->TrimInputCount(1);
|
||||
CHECK_EQ(1, n1->InputCount());
|
||||
CHECK_EQ(n0, n1->InputAt(0));
|
||||
CHECK_EQ(1, n0->UseCount());
|
||||
}
|
||||
|
||||
{
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n1 = graph.NewNode(&dummy_operator, n0);
|
||||
n1->TrimInputCount(0);
|
||||
CHECK_EQ(0, n1->InputCount());
|
||||
CHECK_EQ(0, n0->UseCount());
|
||||
}
|
||||
|
||||
{
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n1 = graph.NewNode(&dummy_operator);
|
||||
Node* n2 = graph.NewNode(&dummy_operator, n0, n1);
|
||||
n2->TrimInputCount(2);
|
||||
CHECK_EQ(2, n2->InputCount());
|
||||
CHECK_EQ(1, n0->UseCount());
|
||||
CHECK_EQ(1, n1->UseCount());
|
||||
CHECK_EQ(0, n2->UseCount());
|
||||
}
|
||||
|
||||
{
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n1 = graph.NewNode(&dummy_operator);
|
||||
Node* n2 = graph.NewNode(&dummy_operator, n0, n1);
|
||||
n2->TrimInputCount(1);
|
||||
CHECK_EQ(1, n2->InputCount());
|
||||
CHECK_EQ(1, n0->UseCount());
|
||||
CHECK_EQ(0, n1->UseCount());
|
||||
CHECK_EQ(0, n2->UseCount());
|
||||
}
|
||||
|
||||
{
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n1 = graph.NewNode(&dummy_operator);
|
||||
Node* n2 = graph.NewNode(&dummy_operator, n0, n1);
|
||||
n2->TrimInputCount(0);
|
||||
CHECK_EQ(0, n2->InputCount());
|
||||
CHECK_EQ(0, n0->UseCount());
|
||||
CHECK_EQ(0, n1->UseCount());
|
||||
CHECK_EQ(0, n2->UseCount());
|
||||
}
|
||||
|
||||
{
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n2 = graph.NewNode(&dummy_operator, n0, n0);
|
||||
n2->TrimInputCount(1);
|
||||
CHECK_EQ(1, n2->InputCount());
|
||||
CHECK_EQ(1, n0->UseCount());
|
||||
CHECK_EQ(0, n2->UseCount());
|
||||
}
|
||||
|
||||
{
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n2 = graph.NewNode(&dummy_operator, n0, n0);
|
||||
n2->TrimInputCount(0);
|
||||
CHECK_EQ(0, n2->InputCount());
|
||||
CHECK_EQ(0, n0->UseCount());
|
||||
CHECK_EQ(0, n2->UseCount());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(TrimInputCountOutOfLine1) {
|
||||
GraphTester graph;
|
||||
|
||||
{
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n1 = graph.NewNode(&dummy_operator);
|
||||
n1->AppendInput(graph.zone(), n0);
|
||||
n1->TrimInputCount(1);
|
||||
CHECK_EQ(1, n1->InputCount());
|
||||
CHECK_EQ(n0, n1->InputAt(0));
|
||||
CHECK_EQ(1, n0->UseCount());
|
||||
}
|
||||
|
||||
{
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n1 = graph.NewNode(&dummy_operator);
|
||||
n1->AppendInput(graph.zone(), n0);
|
||||
CHECK_EQ(1, n1->InputCount());
|
||||
n1->TrimInputCount(0);
|
||||
CHECK_EQ(0, n1->InputCount());
|
||||
CHECK_EQ(0, n0->UseCount());
|
||||
}
|
||||
|
||||
{
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n1 = graph.NewNode(&dummy_operator);
|
||||
Node* n2 = graph.NewNode(&dummy_operator);
|
||||
n2->AppendInput(graph.zone(), n0);
|
||||
n2->AppendInput(graph.zone(), n1);
|
||||
CHECK_EQ(2, n2->InputCount());
|
||||
n2->TrimInputCount(2);
|
||||
CHECK_EQ(2, n2->InputCount());
|
||||
CHECK_EQ(n0, n2->InputAt(0));
|
||||
CHECK_EQ(n1, n2->InputAt(1));
|
||||
CHECK_EQ(1, n0->UseCount());
|
||||
CHECK_EQ(1, n1->UseCount());
|
||||
CHECK_EQ(0, n2->UseCount());
|
||||
}
|
||||
|
||||
{
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n1 = graph.NewNode(&dummy_operator);
|
||||
Node* n2 = graph.NewNode(&dummy_operator);
|
||||
n2->AppendInput(graph.zone(), n0);
|
||||
n2->AppendInput(graph.zone(), n1);
|
||||
CHECK_EQ(2, n2->InputCount());
|
||||
n2->TrimInputCount(1);
|
||||
CHECK_EQ(1, n2->InputCount());
|
||||
CHECK_EQ(n0, n2->InputAt(0));
|
||||
CHECK_EQ(1, n0->UseCount());
|
||||
CHECK_EQ(0, n1->UseCount());
|
||||
CHECK_EQ(0, n2->UseCount());
|
||||
}
|
||||
|
||||
{
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n1 = graph.NewNode(&dummy_operator);
|
||||
Node* n2 = graph.NewNode(&dummy_operator);
|
||||
n2->AppendInput(graph.zone(), n0);
|
||||
n2->AppendInput(graph.zone(), n1);
|
||||
CHECK_EQ(2, n2->InputCount());
|
||||
n2->TrimInputCount(0);
|
||||
CHECK_EQ(0, n2->InputCount());
|
||||
CHECK_EQ(0, n0->UseCount());
|
||||
CHECK_EQ(0, n1->UseCount());
|
||||
CHECK_EQ(0, n2->UseCount());
|
||||
}
|
||||
|
||||
{
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n2 = graph.NewNode(&dummy_operator);
|
||||
n2->AppendInput(graph.zone(), n0);
|
||||
n2->AppendInput(graph.zone(), n0);
|
||||
CHECK_EQ(2, n2->InputCount());
|
||||
CHECK_EQ(2, n0->UseCount());
|
||||
n2->TrimInputCount(1);
|
||||
CHECK_EQ(1, n2->InputCount());
|
||||
CHECK_EQ(1, n0->UseCount());
|
||||
CHECK_EQ(0, n2->UseCount());
|
||||
}
|
||||
|
||||
{
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n2 = graph.NewNode(&dummy_operator);
|
||||
n2->AppendInput(graph.zone(), n0);
|
||||
n2->AppendInput(graph.zone(), n0);
|
||||
CHECK_EQ(2, n2->InputCount());
|
||||
CHECK_EQ(2, n0->UseCount());
|
||||
n2->TrimInputCount(0);
|
||||
CHECK_EQ(0, n2->InputCount());
|
||||
CHECK_EQ(0, n0->UseCount());
|
||||
CHECK_EQ(0, n2->UseCount());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(TrimInputCountOutOfLine2) {
|
||||
GraphTester graph;
|
||||
|
||||
{
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n1 = graph.NewNode(&dummy_operator);
|
||||
Node* n2 = graph.NewNode(&dummy_operator, n0);
|
||||
n2->AppendInput(graph.zone(), n1);
|
||||
CHECK_EQ(2, n2->InputCount());
|
||||
n2->TrimInputCount(2);
|
||||
CHECK_EQ(2, n2->InputCount());
|
||||
CHECK_EQ(n0, n2->InputAt(0));
|
||||
CHECK_EQ(n1, n2->InputAt(1));
|
||||
CHECK_EQ(1, n0->UseCount());
|
||||
CHECK_EQ(1, n1->UseCount());
|
||||
CHECK_EQ(0, n2->UseCount());
|
||||
}
|
||||
|
||||
{
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n1 = graph.NewNode(&dummy_operator);
|
||||
Node* n2 = graph.NewNode(&dummy_operator, n0);
|
||||
n2->AppendInput(graph.zone(), n1);
|
||||
CHECK_EQ(2, n2->InputCount());
|
||||
n2->TrimInputCount(1);
|
||||
CHECK_EQ(1, n2->InputCount());
|
||||
CHECK_EQ(n0, n2->InputAt(0));
|
||||
CHECK_EQ(1, n0->UseCount());
|
||||
CHECK_EQ(0, n1->UseCount());
|
||||
CHECK_EQ(0, n2->UseCount());
|
||||
}
|
||||
|
||||
{
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n1 = graph.NewNode(&dummy_operator);
|
||||
Node* n2 = graph.NewNode(&dummy_operator, n0);
|
||||
n2->AppendInput(graph.zone(), n1);
|
||||
CHECK_EQ(2, n2->InputCount());
|
||||
n2->TrimInputCount(0);
|
||||
CHECK_EQ(0, n2->InputCount());
|
||||
CHECK_EQ(0, n0->UseCount());
|
||||
CHECK_EQ(0, n1->UseCount());
|
||||
CHECK_EQ(0, n2->UseCount());
|
||||
}
|
||||
|
||||
{
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n2 = graph.NewNode(&dummy_operator, n0);
|
||||
n2->AppendInput(graph.zone(), n0);
|
||||
CHECK_EQ(2, n2->InputCount());
|
||||
CHECK_EQ(2, n0->UseCount());
|
||||
n2->TrimInputCount(1);
|
||||
CHECK_EQ(1, n2->InputCount());
|
||||
CHECK_EQ(1, n0->UseCount());
|
||||
CHECK_EQ(0, n2->UseCount());
|
||||
}
|
||||
|
||||
{
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n2 = graph.NewNode(&dummy_operator, n0);
|
||||
n2->AppendInput(graph.zone(), n0);
|
||||
CHECK_EQ(2, n2->InputCount());
|
||||
CHECK_EQ(2, n0->UseCount());
|
||||
n2->TrimInputCount(0);
|
||||
CHECK_EQ(0, n2->InputCount());
|
||||
CHECK_EQ(0, n0->UseCount());
|
||||
CHECK_EQ(0, n2->UseCount());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(RemoveAllInputs) {
|
||||
GraphTester graph;
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n1 = graph.NewNode(&dummy_operator, n0);
|
||||
Node* n2;
|
||||
if (i == 0) {
|
||||
n2 = graph.NewNode(&dummy_operator, n0, n1);
|
||||
} else {
|
||||
n2 = graph.NewNode(&dummy_operator, n0);
|
||||
n2->AppendInput(graph.zone(), n1); // with out-of-line input.
|
||||
}
|
||||
|
||||
n0->RemoveAllInputs();
|
||||
CHECK_EQ(0, n0->InputCount());
|
||||
|
||||
CHECK_EQ(2, n0->UseCount());
|
||||
n1->RemoveAllInputs();
|
||||
CHECK_EQ(1, n1->InputCount());
|
||||
CHECK_EQ(1, n0->UseCount());
|
||||
CHECK_EQ(NULL, n1->InputAt(0));
|
||||
|
||||
CHECK_EQ(1, n1->UseCount());
|
||||
n2->RemoveAllInputs();
|
||||
CHECK_EQ(2, n2->InputCount());
|
||||
CHECK_EQ(0, n0->UseCount());
|
||||
CHECK_EQ(0, n1->UseCount());
|
||||
CHECK_EQ(NULL, n2->InputAt(0));
|
||||
CHECK_EQ(NULL, n2->InputAt(1));
|
||||
}
|
||||
|
||||
{
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n1 = graph.NewNode(&dummy_operator, n0);
|
||||
n1->ReplaceInput(0, n1); // self-reference.
|
||||
|
||||
CHECK_EQ(0, n0->UseCount());
|
||||
CHECK_EQ(1, n1->UseCount());
|
||||
n1->RemoveAllInputs();
|
||||
CHECK_EQ(1, n1->InputCount());
|
||||
CHECK_EQ(0, n1->UseCount());
|
||||
CHECK_EQ(NULL, n1->InputAt(0));
|
||||
}
|
||||
}
|
@ -1,244 +0,0 @@
|
||||
// Copyright 2013 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/compiler/operator.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
|
||||
#define NaN (v8::base::OS::nan_value())
|
||||
#define Infinity (std::numeric_limits<double>::infinity())
|
||||
|
||||
TEST(TestOperatorMnemonic) {
|
||||
SimpleOperator op1(10, 0, 0, 0, "ThisOne");
|
||||
CHECK_EQ(0, strcmp(op1.mnemonic(), "ThisOne"));
|
||||
|
||||
SimpleOperator op2(11, 0, 0, 0, "ThatOne");
|
||||
CHECK_EQ(0, strcmp(op2.mnemonic(), "ThatOne"));
|
||||
|
||||
Operator1<int> op3(12, 0, 0, 1, "Mnemonic1", 12333);
|
||||
CHECK_EQ(0, strcmp(op3.mnemonic(), "Mnemonic1"));
|
||||
|
||||
Operator1<double> op4(13, 0, 0, 1, "TheOther", 99.9);
|
||||
CHECK_EQ(0, strcmp(op4.mnemonic(), "TheOther"));
|
||||
}
|
||||
|
||||
|
||||
TEST(TestSimpleOperatorHash) {
|
||||
SimpleOperator op1(17, 0, 0, 0, "Another");
|
||||
CHECK_EQ(17, op1.HashCode());
|
||||
|
||||
SimpleOperator op2(18, 0, 0, 0, "Falsch");
|
||||
CHECK_EQ(18, op2.HashCode());
|
||||
}
|
||||
|
||||
|
||||
TEST(TestSimpleOperatorEquals) {
|
||||
SimpleOperator op1a(19, 0, 0, 0, "Another1");
|
||||
SimpleOperator op1b(19, 2, 2, 2, "Another2");
|
||||
|
||||
CHECK(op1a.Equals(&op1a));
|
||||
CHECK(op1a.Equals(&op1b));
|
||||
CHECK(op1b.Equals(&op1a));
|
||||
CHECK(op1b.Equals(&op1b));
|
||||
|
||||
SimpleOperator op2a(20, 0, 0, 0, "Falsch1");
|
||||
SimpleOperator op2b(20, 1, 1, 1, "Falsch2");
|
||||
|
||||
CHECK(op2a.Equals(&op2a));
|
||||
CHECK(op2a.Equals(&op2b));
|
||||
CHECK(op2b.Equals(&op2a));
|
||||
CHECK(op2b.Equals(&op2b));
|
||||
|
||||
CHECK(!op1a.Equals(&op2a));
|
||||
CHECK(!op1a.Equals(&op2b));
|
||||
CHECK(!op1b.Equals(&op2a));
|
||||
CHECK(!op1b.Equals(&op2b));
|
||||
|
||||
CHECK(!op2a.Equals(&op1a));
|
||||
CHECK(!op2a.Equals(&op1b));
|
||||
CHECK(!op2b.Equals(&op1a));
|
||||
CHECK(!op2b.Equals(&op1b));
|
||||
}
|
||||
|
||||
|
||||
static SmartArrayPointer<const char> OperatorToString(Operator* op) {
|
||||
OStringStream os;
|
||||
os << *op;
|
||||
return SmartArrayPointer<const char>(StrDup(os.c_str()));
|
||||
}
|
||||
|
||||
|
||||
TEST(TestSimpleOperatorPrint) {
|
||||
SimpleOperator op1a(19, 0, 0, 0, "Another1");
|
||||
SimpleOperator op1b(19, 2, 2, 2, "Another2");
|
||||
|
||||
CHECK_EQ("Another1", OperatorToString(&op1a).get());
|
||||
CHECK_EQ("Another2", OperatorToString(&op1b).get());
|
||||
|
||||
SimpleOperator op2a(20, 0, 0, 0, "Flog1");
|
||||
SimpleOperator op2b(20, 1, 1, 1, "Flog2");
|
||||
|
||||
CHECK_EQ("Flog1", OperatorToString(&op2a).get());
|
||||
CHECK_EQ("Flog2", OperatorToString(&op2b).get());
|
||||
}
|
||||
|
||||
|
||||
TEST(TestOperator1intHash) {
|
||||
Operator1<int> op1a(23, 0, 0, 0, "Wolfie", 11);
|
||||
Operator1<int> op1b(23, 2, 2, 2, "Doggie", 11);
|
||||
|
||||
CHECK_EQ(op1a.HashCode(), op1b.HashCode());
|
||||
|
||||
Operator1<int> op2a(24, 0, 0, 0, "Arfie", 3);
|
||||
Operator1<int> op2b(24, 0, 0, 0, "Arfie", 4);
|
||||
|
||||
CHECK_NE(op1a.HashCode(), op2a.HashCode());
|
||||
CHECK_NE(op2a.HashCode(), op2b.HashCode());
|
||||
}
|
||||
|
||||
|
||||
TEST(TestOperator1intEquals) {
|
||||
Operator1<int> op1a(23, 0, 0, 0, "Scratchy", 11);
|
||||
Operator1<int> op1b(23, 2, 2, 2, "Scratchy", 11);
|
||||
|
||||
CHECK(op1a.Equals(&op1a));
|
||||
CHECK(op1a.Equals(&op1b));
|
||||
CHECK(op1b.Equals(&op1a));
|
||||
CHECK(op1b.Equals(&op1b));
|
||||
|
||||
Operator1<int> op2a(24, 0, 0, 0, "Im", 3);
|
||||
Operator1<int> op2b(24, 0, 0, 0, "Im", 4);
|
||||
|
||||
CHECK(op2a.Equals(&op2a));
|
||||
CHECK(!op2a.Equals(&op2b));
|
||||
CHECK(!op2b.Equals(&op2a));
|
||||
CHECK(op2b.Equals(&op2b));
|
||||
|
||||
CHECK(!op1a.Equals(&op2a));
|
||||
CHECK(!op1a.Equals(&op2b));
|
||||
CHECK(!op1b.Equals(&op2a));
|
||||
CHECK(!op1b.Equals(&op2b));
|
||||
|
||||
CHECK(!op2a.Equals(&op1a));
|
||||
CHECK(!op2a.Equals(&op1b));
|
||||
CHECK(!op2b.Equals(&op1a));
|
||||
CHECK(!op2b.Equals(&op1b));
|
||||
|
||||
SimpleOperator op3(25, 0, 0, 0, "Weepy");
|
||||
|
||||
CHECK(!op1a.Equals(&op3));
|
||||
CHECK(!op1b.Equals(&op3));
|
||||
CHECK(!op2a.Equals(&op3));
|
||||
CHECK(!op2b.Equals(&op3));
|
||||
|
||||
CHECK(!op3.Equals(&op1a));
|
||||
CHECK(!op3.Equals(&op1b));
|
||||
CHECK(!op3.Equals(&op2a));
|
||||
CHECK(!op3.Equals(&op2b));
|
||||
}
|
||||
|
||||
|
||||
TEST(TestOperator1intPrint) {
|
||||
Operator1<int> op1(12, 0, 0, 1, "Op1Test", 0);
|
||||
CHECK_EQ("Op1Test[0]", OperatorToString(&op1).get());
|
||||
|
||||
Operator1<int> op2(12, 0, 0, 1, "Op1Test", 66666666);
|
||||
CHECK_EQ("Op1Test[66666666]", OperatorToString(&op2).get());
|
||||
|
||||
Operator1<int> op3(12, 0, 0, 1, "FooBar", 2347);
|
||||
CHECK_EQ("FooBar[2347]", OperatorToString(&op3).get());
|
||||
|
||||
Operator1<int> op4(12, 0, 0, 1, "BarFoo", -879);
|
||||
CHECK_EQ("BarFoo[-879]", OperatorToString(&op4).get());
|
||||
}
|
||||
|
||||
|
||||
TEST(TestOperator1doubleHash) {
|
||||
Operator1<double> op1a(23, 0, 0, 0, "Wolfie", 11.77);
|
||||
Operator1<double> op1b(23, 2, 2, 2, "Doggie", 11.77);
|
||||
|
||||
CHECK_EQ(op1a.HashCode(), op1b.HashCode());
|
||||
|
||||
Operator1<double> op2a(24, 0, 0, 0, "Arfie", -6.7);
|
||||
Operator1<double> op2b(24, 0, 0, 0, "Arfie", -6.8);
|
||||
|
||||
CHECK_NE(op1a.HashCode(), op2a.HashCode());
|
||||
CHECK_NE(op2a.HashCode(), op2b.HashCode());
|
||||
}
|
||||
|
||||
|
||||
TEST(TestOperator1doubleEquals) {
|
||||
Operator1<double> op1a(23, 0, 0, 0, "Scratchy", 11.77);
|
||||
Operator1<double> op1b(23, 2, 2, 2, "Scratchy", 11.77);
|
||||
|
||||
CHECK(op1a.Equals(&op1a));
|
||||
CHECK(op1a.Equals(&op1b));
|
||||
CHECK(op1b.Equals(&op1a));
|
||||
CHECK(op1b.Equals(&op1b));
|
||||
|
||||
Operator1<double> op2a(24, 0, 0, 0, "Im", 3.1);
|
||||
Operator1<double> op2b(24, 0, 0, 0, "Im", 3.2);
|
||||
|
||||
CHECK(op2a.Equals(&op2a));
|
||||
CHECK(!op2a.Equals(&op2b));
|
||||
CHECK(!op2b.Equals(&op2a));
|
||||
CHECK(op2b.Equals(&op2b));
|
||||
|
||||
CHECK(!op1a.Equals(&op2a));
|
||||
CHECK(!op1a.Equals(&op2b));
|
||||
CHECK(!op1b.Equals(&op2a));
|
||||
CHECK(!op1b.Equals(&op2b));
|
||||
|
||||
CHECK(!op2a.Equals(&op1a));
|
||||
CHECK(!op2a.Equals(&op1b));
|
||||
CHECK(!op2b.Equals(&op1a));
|
||||
CHECK(!op2b.Equals(&op1b));
|
||||
|
||||
SimpleOperator op3(25, 0, 0, 0, "Weepy");
|
||||
|
||||
CHECK(!op1a.Equals(&op3));
|
||||
CHECK(!op1b.Equals(&op3));
|
||||
CHECK(!op2a.Equals(&op3));
|
||||
CHECK(!op2b.Equals(&op3));
|
||||
|
||||
CHECK(!op3.Equals(&op1a));
|
||||
CHECK(!op3.Equals(&op1b));
|
||||
CHECK(!op3.Equals(&op2a));
|
||||
CHECK(!op3.Equals(&op2b));
|
||||
|
||||
Operator1<double> op4a(24, 0, 0, 0, "Bashful", NaN);
|
||||
Operator1<double> op4b(24, 0, 0, 0, "Bashful", NaN);
|
||||
|
||||
CHECK(op4a.Equals(&op4a));
|
||||
CHECK(op4a.Equals(&op4b));
|
||||
CHECK(op4b.Equals(&op4a));
|
||||
CHECK(op4b.Equals(&op4b));
|
||||
|
||||
CHECK(!op3.Equals(&op4a));
|
||||
CHECK(!op3.Equals(&op4b));
|
||||
CHECK(!op3.Equals(&op4a));
|
||||
CHECK(!op3.Equals(&op4b));
|
||||
}
|
||||
|
||||
|
||||
TEST(TestOperator1doublePrint) {
|
||||
Operator1<double> op1(12, 0, 0, 1, "Op1Test", 0);
|
||||
CHECK_EQ("Op1Test[0]", OperatorToString(&op1).get());
|
||||
|
||||
Operator1<double> op2(12, 0, 0, 1, "Op1Test", 7.3);
|
||||
CHECK_EQ("Op1Test[7.3]", OperatorToString(&op2).get());
|
||||
|
||||
Operator1<double> op3(12, 0, 0, 1, "FooBar", 2e+123);
|
||||
CHECK_EQ("FooBar[2e+123]", OperatorToString(&op3).get());
|
||||
|
||||
Operator1<double> op4(12, 0, 0, 1, "BarFoo", Infinity);
|
||||
CHECK_EQ("BarFoo[inf]", OperatorToString(&op4).get());
|
||||
|
||||
Operator1<double> op5(12, 0, 0, 1, "BarFoo", NaN);
|
||||
CHECK_EQ("BarFoo[nan]", OperatorToString(&op5).get());
|
||||
}
|
@ -1,223 +0,0 @@
|
||||
// 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 "src/v8.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
|
||||
#include "src/compiler/common-operator.h"
|
||||
#include "src/compiler/graph-inl.h"
|
||||
#include "src/compiler/phi-reducer.h"
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
|
||||
class PhiReducerTester : HandleAndZoneScope {
|
||||
public:
|
||||
PhiReducerTester()
|
||||
: isolate(main_isolate()),
|
||||
common(main_zone()),
|
||||
graph(main_zone()),
|
||||
self(graph.NewNode(common.Start())),
|
||||
dead(graph.NewNode(common.Dead())) {}
|
||||
|
||||
Isolate* isolate;
|
||||
CommonOperatorBuilder common;
|
||||
Graph graph;
|
||||
Node* self;
|
||||
Node* dead;
|
||||
|
||||
void CheckReduce(Node* expect, Node* phi) {
|
||||
PhiReducer reducer;
|
||||
Reduction reduction = reducer.Reduce(phi);
|
||||
if (expect == phi) {
|
||||
CHECK(!reduction.Changed());
|
||||
} else {
|
||||
CHECK(reduction.Changed());
|
||||
CHECK_EQ(expect, reduction.replacement());
|
||||
}
|
||||
}
|
||||
|
||||
Node* Int32Constant(int32_t val) {
|
||||
return graph.NewNode(common.Int32Constant(val));
|
||||
}
|
||||
|
||||
Node* Float64Constant(double val) {
|
||||
return graph.NewNode(common.Float64Constant(val));
|
||||
}
|
||||
|
||||
Node* Parameter(int32_t index = 0) {
|
||||
return graph.NewNode(common.Parameter(index));
|
||||
}
|
||||
|
||||
Node* Phi(Node* a) {
|
||||
return SetSelfReferences(graph.NewNode(common.Phi(1), a));
|
||||
}
|
||||
|
||||
Node* Phi(Node* a, Node* b) {
|
||||
return SetSelfReferences(graph.NewNode(common.Phi(2), a, b));
|
||||
}
|
||||
|
||||
Node* Phi(Node* a, Node* b, Node* c) {
|
||||
return SetSelfReferences(graph.NewNode(common.Phi(3), a, b, c));
|
||||
}
|
||||
|
||||
Node* Phi(Node* a, Node* b, Node* c, Node* d) {
|
||||
return SetSelfReferences(graph.NewNode(common.Phi(4), a, b, c, d));
|
||||
}
|
||||
|
||||
Node* PhiWithControl(Node* a, Node* control) {
|
||||
return SetSelfReferences(graph.NewNode(common.Phi(1), a, control));
|
||||
}
|
||||
|
||||
Node* PhiWithControl(Node* a, Node* b, Node* control) {
|
||||
return SetSelfReferences(graph.NewNode(common.Phi(2), a, b, control));
|
||||
}
|
||||
|
||||
Node* SetSelfReferences(Node* node) {
|
||||
Node::Inputs inputs = node->inputs();
|
||||
for (Node::Inputs::iterator iter(inputs.begin()); iter != inputs.end();
|
||||
++iter) {
|
||||
Node* input = *iter;
|
||||
if (input == self) node->ReplaceInput(iter.index(), node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
TEST(PhiReduce1) {
|
||||
PhiReducerTester R;
|
||||
Node* zero = R.Int32Constant(0);
|
||||
Node* one = R.Int32Constant(1);
|
||||
Node* oneish = R.Float64Constant(1.1);
|
||||
Node* param = R.Parameter();
|
||||
|
||||
Node* singles[] = {zero, one, oneish, param};
|
||||
for (size_t i = 0; i < ARRAY_SIZE(singles); i++) {
|
||||
R.CheckReduce(singles[i], R.Phi(singles[i]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(PhiReduce2) {
|
||||
PhiReducerTester R;
|
||||
Node* zero = R.Int32Constant(0);
|
||||
Node* one = R.Int32Constant(1);
|
||||
Node* oneish = R.Float64Constant(1.1);
|
||||
Node* param = R.Parameter();
|
||||
|
||||
Node* singles[] = {zero, one, oneish, param};
|
||||
for (size_t i = 0; i < ARRAY_SIZE(singles); i++) {
|
||||
Node* a = singles[i];
|
||||
R.CheckReduce(a, R.Phi(a, a));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(singles); i++) {
|
||||
Node* a = singles[i];
|
||||
R.CheckReduce(a, R.Phi(R.self, a));
|
||||
R.CheckReduce(a, R.Phi(a, R.self));
|
||||
}
|
||||
|
||||
for (size_t i = 1; i < ARRAY_SIZE(singles); i++) {
|
||||
Node* a = singles[i], *b = singles[0];
|
||||
Node* phi1 = R.Phi(b, a);
|
||||
R.CheckReduce(phi1, phi1);
|
||||
|
||||
Node* phi2 = R.Phi(a, b);
|
||||
R.CheckReduce(phi2, phi2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(PhiReduce3) {
|
||||
PhiReducerTester R;
|
||||
Node* zero = R.Int32Constant(0);
|
||||
Node* one = R.Int32Constant(1);
|
||||
Node* oneish = R.Float64Constant(1.1);
|
||||
Node* param = R.Parameter();
|
||||
|
||||
Node* singles[] = {zero, one, oneish, param};
|
||||
for (size_t i = 0; i < ARRAY_SIZE(singles); i++) {
|
||||
Node* a = singles[i];
|
||||
R.CheckReduce(a, R.Phi(a, a, a));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(singles); i++) {
|
||||
Node* a = singles[i];
|
||||
R.CheckReduce(a, R.Phi(R.self, a, a));
|
||||
R.CheckReduce(a, R.Phi(a, R.self, a));
|
||||
R.CheckReduce(a, R.Phi(a, a, R.self));
|
||||
}
|
||||
|
||||
for (size_t i = 1; i < ARRAY_SIZE(singles); i++) {
|
||||
Node* a = singles[i], *b = singles[0];
|
||||
Node* phi1 = R.Phi(b, a, a);
|
||||
R.CheckReduce(phi1, phi1);
|
||||
|
||||
Node* phi2 = R.Phi(a, b, a);
|
||||
R.CheckReduce(phi2, phi2);
|
||||
|
||||
Node* phi3 = R.Phi(a, a, b);
|
||||
R.CheckReduce(phi3, phi3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(PhiReduce4) {
|
||||
PhiReducerTester R;
|
||||
Node* zero = R.Int32Constant(0);
|
||||
Node* one = R.Int32Constant(1);
|
||||
Node* oneish = R.Float64Constant(1.1);
|
||||
Node* param = R.Parameter();
|
||||
|
||||
Node* singles[] = {zero, one, oneish, param};
|
||||
for (size_t i = 0; i < ARRAY_SIZE(singles); i++) {
|
||||
Node* a = singles[i];
|
||||
R.CheckReduce(a, R.Phi(a, a, a, a));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(singles); i++) {
|
||||
Node* a = singles[i];
|
||||
R.CheckReduce(a, R.Phi(R.self, a, a, a));
|
||||
R.CheckReduce(a, R.Phi(a, R.self, a, a));
|
||||
R.CheckReduce(a, R.Phi(a, a, R.self, a));
|
||||
R.CheckReduce(a, R.Phi(a, a, a, R.self));
|
||||
|
||||
R.CheckReduce(a, R.Phi(R.self, R.self, a, a));
|
||||
R.CheckReduce(a, R.Phi(a, R.self, R.self, a));
|
||||
R.CheckReduce(a, R.Phi(a, a, R.self, R.self));
|
||||
R.CheckReduce(a, R.Phi(R.self, a, a, R.self));
|
||||
}
|
||||
|
||||
for (size_t i = 1; i < ARRAY_SIZE(singles); i++) {
|
||||
Node* a = singles[i], *b = singles[0];
|
||||
Node* phi1 = R.Phi(b, a, a, a);
|
||||
R.CheckReduce(phi1, phi1);
|
||||
|
||||
Node* phi2 = R.Phi(a, b, a, a);
|
||||
R.CheckReduce(phi2, phi2);
|
||||
|
||||
Node* phi3 = R.Phi(a, a, b, a);
|
||||
R.CheckReduce(phi3, phi3);
|
||||
|
||||
Node* phi4 = R.Phi(a, a, a, b);
|
||||
R.CheckReduce(phi4, phi4);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(PhiReduceShouldIgnoreControlNodes) {
|
||||
PhiReducerTester R;
|
||||
Node* zero = R.Int32Constant(0);
|
||||
Node* one = R.Int32Constant(1);
|
||||
Node* oneish = R.Float64Constant(1.1);
|
||||
Node* param = R.Parameter();
|
||||
|
||||
Node* singles[] = {zero, one, oneish, param};
|
||||
for (size_t i = 0; i < ARRAY_SIZE(singles); ++i) {
|
||||
R.CheckReduce(singles[i], R.PhiWithControl(singles[i], R.dead));
|
||||
R.CheckReduce(singles[i], R.PhiWithControl(R.self, singles[i], R.dead));
|
||||
R.CheckReduce(singles[i], R.PhiWithControl(singles[i], R.self, R.dead));
|
||||
}
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
// Copyright 2013 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 "test/cctest/cctest.h"
|
||||
|
||||
#include "src/compiler.h"
|
||||
#include "src/compiler/pipeline.h"
|
||||
#include "src/handles.h"
|
||||
#include "src/parser.h"
|
||||
#include "src/rewriter.h"
|
||||
#include "src/scopes.h"
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
|
||||
TEST(PipelineAdd) {
|
||||
InitializedHandleScope handles;
|
||||
const char* source = "(function(a,b) { return a + b; })";
|
||||
Handle<JSFunction> function = v8::Utils::OpenHandle(
|
||||
*v8::Handle<v8::Function>::Cast(CompileRun(source)));
|
||||
CompilationInfoWithZone info(function);
|
||||
|
||||
CHECK(Parser::Parse(&info));
|
||||
StrictMode strict_mode = info.function()->strict_mode();
|
||||
info.SetStrictMode(strict_mode);
|
||||
CHECK(Rewriter::Rewrite(&info));
|
||||
CHECK(Scope::Analyze(&info));
|
||||
CHECK_NE(NULL, info.scope());
|
||||
|
||||
Pipeline pipeline(&info);
|
||||
Handle<Code> code = pipeline.GenerateCode();
|
||||
#if V8_TURBOFAN_TARGET
|
||||
CHECK(Pipeline::SupportedTarget());
|
||||
CHECK(!code.is_null());
|
||||
#else
|
||||
USE(code);
|
||||
#endif
|
||||
}
|
@ -1,281 +0,0 @@
|
||||
// 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 <limits>
|
||||
|
||||
#include "src/v8.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
#include "test/cctest/compiler/graph-builder-tester.h"
|
||||
|
||||
#include "src/compiler/node-matchers.h"
|
||||
#include "src/compiler/representation-change.h"
|
||||
#include "src/compiler/typer.h"
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
|
||||
namespace v8 { // for friendiness.
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
class RepresentationChangerTester : public HandleAndZoneScope,
|
||||
public GraphAndBuilders {
|
||||
public:
|
||||
RepresentationChangerTester()
|
||||
: GraphAndBuilders(main_zone()),
|
||||
typer_(main_zone()),
|
||||
jsgraph_(main_graph_, &main_common_, &typer_),
|
||||
changer_(&jsgraph_, &main_simplified_, &main_machine_, main_isolate()) {
|
||||
}
|
||||
|
||||
Typer typer_;
|
||||
JSGraph jsgraph_;
|
||||
RepresentationChanger changer_;
|
||||
|
||||
Isolate* isolate() { return main_isolate(); }
|
||||
Graph* graph() { return main_graph_; }
|
||||
CommonOperatorBuilder* common() { return &main_common_; }
|
||||
JSGraph* jsgraph() { return &jsgraph_; }
|
||||
RepresentationChanger* changer() { return &changer_; }
|
||||
|
||||
// TODO(titzer): use ValueChecker / ValueUtil
|
||||
void CheckInt32Constant(Node* n, int32_t expected) {
|
||||
ValueMatcher<int32_t> m(n);
|
||||
CHECK(m.HasValue());
|
||||
CHECK_EQ(expected, m.Value());
|
||||
}
|
||||
|
||||
void CheckHeapConstant(Node* n, Object* expected) {
|
||||
ValueMatcher<Handle<Object> > m(n);
|
||||
CHECK(m.HasValue());
|
||||
CHECK_EQ(expected, *m.Value());
|
||||
}
|
||||
|
||||
void CheckNumberConstant(Node* n, double expected) {
|
||||
ValueMatcher<double> m(n);
|
||||
CHECK_EQ(IrOpcode::kNumberConstant, n->opcode());
|
||||
CHECK(m.HasValue());
|
||||
CHECK_EQ(expected, m.Value());
|
||||
}
|
||||
|
||||
Node* Parameter(int index = 0) {
|
||||
return graph()->NewNode(common()->Parameter(index));
|
||||
}
|
||||
|
||||
void CheckTypeError(RepTypeUnion from, RepTypeUnion to) {
|
||||
changer()->testing_type_errors_ = true;
|
||||
changer()->type_error_ = false;
|
||||
Node* n = Parameter(0);
|
||||
Node* c = changer()->GetRepresentationFor(n, from, to);
|
||||
CHECK_EQ(n, c);
|
||||
CHECK(changer()->type_error_);
|
||||
}
|
||||
|
||||
void CheckNop(RepTypeUnion from, RepTypeUnion to) {
|
||||
Node* n = Parameter(0);
|
||||
Node* c = changer()->GetRepresentationFor(n, from, to);
|
||||
CHECK_EQ(n, c);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace v8::internal::compiler
|
||||
|
||||
|
||||
static const RepType all_reps[] = {rBit, rWord32, rWord64, rFloat64, rTagged};
|
||||
|
||||
|
||||
// TODO(titzer): lift this to ValueHelper
|
||||
static const double double_inputs[] = {
|
||||
0.0, -0.0, 1.0, -1.0, 0.1, 1.4, -1.7,
|
||||
2, 5, 6, 982983, 888, -999.8, 3.1e7,
|
||||
-2e66, 2.3e124, -12e73, V8_INFINITY, -V8_INFINITY};
|
||||
|
||||
|
||||
static const int32_t int32_inputs[] = {
|
||||
0, 1, -1,
|
||||
2, 5, 6,
|
||||
982983, 888, -999,
|
||||
65535, static_cast<int32_t>(0xFFFFFFFF), static_cast<int32_t>(0x80000000)};
|
||||
|
||||
|
||||
static const uint32_t uint32_inputs[] = {
|
||||
0, 1, static_cast<uint32_t>(-1), 2, 5, 6,
|
||||
982983, 888, static_cast<uint32_t>(-999), 65535, 0xFFFFFFFF, 0x80000000};
|
||||
|
||||
|
||||
TEST(BoolToBit_constant) {
|
||||
RepresentationChangerTester r;
|
||||
|
||||
Node* true_node = r.jsgraph()->TrueConstant();
|
||||
Node* true_bit = r.changer()->GetRepresentationFor(true_node, rTagged, rBit);
|
||||
r.CheckInt32Constant(true_bit, 1);
|
||||
|
||||
Node* false_node = r.jsgraph()->FalseConstant();
|
||||
Node* false_bit =
|
||||
r.changer()->GetRepresentationFor(false_node, rTagged, rBit);
|
||||
r.CheckInt32Constant(false_bit, 0);
|
||||
}
|
||||
|
||||
|
||||
TEST(BitToBool_constant) {
|
||||
RepresentationChangerTester r;
|
||||
|
||||
for (int i = -5; i < 5; i++) {
|
||||
Node* node = r.jsgraph()->Int32Constant(i);
|
||||
Node* val = r.changer()->GetRepresentationFor(node, rBit, rTagged);
|
||||
r.CheckHeapConstant(val, i == 0 ? r.isolate()->heap()->false_value()
|
||||
: r.isolate()->heap()->true_value());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(ToTagged_constant) {
|
||||
RepresentationChangerTester r;
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(double_inputs); i++) {
|
||||
Node* n = r.jsgraph()->Float64Constant(double_inputs[i]);
|
||||
Node* c = r.changer()->GetRepresentationFor(n, rFloat64, rTagged);
|
||||
r.CheckNumberConstant(c, double_inputs[i]);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(int32_inputs); i++) {
|
||||
Node* n = r.jsgraph()->Int32Constant(int32_inputs[i]);
|
||||
Node* c = r.changer()->GetRepresentationFor(n, rWord32 | tInt32, rTagged);
|
||||
r.CheckNumberConstant(c, static_cast<double>(int32_inputs[i]));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(uint32_inputs); i++) {
|
||||
Node* n = r.jsgraph()->Int32Constant(uint32_inputs[i]);
|
||||
Node* c = r.changer()->GetRepresentationFor(n, rWord32 | tUint32, rTagged);
|
||||
r.CheckNumberConstant(c, static_cast<double>(uint32_inputs[i]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void CheckChange(IrOpcode::Value expected, RepTypeUnion from,
|
||||
RepTypeUnion to) {
|
||||
RepresentationChangerTester r;
|
||||
|
||||
Node* n = r.Parameter();
|
||||
Node* c = r.changer()->GetRepresentationFor(n, from, to);
|
||||
|
||||
CHECK_NE(c, n);
|
||||
CHECK_EQ(expected, c->opcode());
|
||||
CHECK_EQ(n, c->InputAt(0));
|
||||
}
|
||||
|
||||
|
||||
TEST(SingleChanges) {
|
||||
CheckChange(IrOpcode::kChangeBoolToBit, rTagged, rBit);
|
||||
CheckChange(IrOpcode::kChangeBitToBool, rBit, rTagged);
|
||||
|
||||
CheckChange(IrOpcode::kChangeInt32ToTagged, rWord32 | tInt32, rTagged);
|
||||
CheckChange(IrOpcode::kChangeUint32ToTagged, rWord32 | tUint32, rTagged);
|
||||
CheckChange(IrOpcode::kChangeFloat64ToTagged, rFloat64, rTagged);
|
||||
|
||||
CheckChange(IrOpcode::kChangeTaggedToInt32, rTagged | tInt32, rWord32);
|
||||
CheckChange(IrOpcode::kChangeTaggedToUint32, rTagged | tUint32, rWord32);
|
||||
CheckChange(IrOpcode::kChangeTaggedToFloat64, rTagged, rFloat64);
|
||||
|
||||
// Int32,Uint32 <-> Float64 are actually machine conversions.
|
||||
CheckChange(IrOpcode::kConvertInt32ToFloat64, rWord32 | tInt32, rFloat64);
|
||||
CheckChange(IrOpcode::kConvertUint32ToFloat64, rWord32 | tUint32, rFloat64);
|
||||
CheckChange(IrOpcode::kConvertFloat64ToInt32, rFloat64 | tInt32, rWord32);
|
||||
CheckChange(IrOpcode::kConvertFloat64ToUint32, rFloat64 | tUint32, rWord32);
|
||||
}
|
||||
|
||||
|
||||
TEST(SignednessInWord32) {
|
||||
RepresentationChangerTester r;
|
||||
|
||||
// TODO(titzer): these are currently type errors because the output type is
|
||||
// not specified. Maybe the RepresentationChanger should assume anything to or
|
||||
// from {rWord32} is {tInt32}, i.e. signed, if not it is explicitly otherwise?
|
||||
r.CheckTypeError(rTagged, rWord32 | tInt32);
|
||||
r.CheckTypeError(rTagged, rWord32 | tUint32);
|
||||
r.CheckTypeError(rWord32, rFloat64);
|
||||
r.CheckTypeError(rFloat64, rWord32);
|
||||
|
||||
// CheckChange(IrOpcode::kChangeTaggedToInt32, rTagged, rWord32 | tInt32);
|
||||
// CheckChange(IrOpcode::kChangeTaggedToUint32, rTagged, rWord32 | tUint32);
|
||||
// CheckChange(IrOpcode::kConvertInt32ToFloat64, rWord32, rFloat64);
|
||||
// CheckChange(IrOpcode::kConvertFloat64ToInt32, rFloat64, rWord32);
|
||||
}
|
||||
|
||||
|
||||
TEST(Nops) {
|
||||
RepresentationChangerTester r;
|
||||
|
||||
// X -> X is always a nop for any single representation X.
|
||||
for (size_t i = 0; i < ARRAY_SIZE(all_reps); i++) {
|
||||
r.CheckNop(all_reps[i], all_reps[i]);
|
||||
}
|
||||
|
||||
// 32-bit or 64-bit words can be used as branch conditions (rBit).
|
||||
r.CheckNop(rWord32, rBit);
|
||||
r.CheckNop(rWord32, rBit | tBool);
|
||||
r.CheckNop(rWord64, rBit);
|
||||
r.CheckNop(rWord64, rBit | tBool);
|
||||
|
||||
// rBit (result of comparison) is implicitly a wordish thing.
|
||||
r.CheckNop(rBit, rWord32);
|
||||
r.CheckNop(rBit | tBool, rWord32);
|
||||
r.CheckNop(rBit, rWord64);
|
||||
r.CheckNop(rBit | tBool, rWord64);
|
||||
}
|
||||
|
||||
|
||||
TEST(TypeErrors) {
|
||||
RepresentationChangerTester r;
|
||||
|
||||
// Floats cannot be implicitly converted to/from comparison conditions.
|
||||
r.CheckTypeError(rFloat64, rBit);
|
||||
r.CheckTypeError(rFloat64, rBit | tBool);
|
||||
r.CheckTypeError(rBit, rFloat64);
|
||||
r.CheckTypeError(rBit | tBool, rFloat64);
|
||||
|
||||
// Word64 is internal and shouldn't be implicitly converted.
|
||||
r.CheckTypeError(rWord64, rTagged | tBool);
|
||||
r.CheckTypeError(rWord64, rTagged);
|
||||
r.CheckTypeError(rWord64, rTagged | tBool);
|
||||
r.CheckTypeError(rTagged, rWord64);
|
||||
r.CheckTypeError(rTagged | tBool, rWord64);
|
||||
|
||||
// Word64 / Word32 shouldn't be implicitly converted.
|
||||
r.CheckTypeError(rWord64, rWord32);
|
||||
r.CheckTypeError(rWord32, rWord64);
|
||||
r.CheckTypeError(rWord64, rWord32 | tInt32);
|
||||
r.CheckTypeError(rWord32 | tInt32, rWord64);
|
||||
r.CheckTypeError(rWord64, rWord32 | tUint32);
|
||||
r.CheckTypeError(rWord32 | tUint32, rWord64);
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(all_reps); i++) {
|
||||
for (size_t j = 0; j < ARRAY_SIZE(all_reps); j++) {
|
||||
if (i == j) continue;
|
||||
// Only a single from representation is allowed.
|
||||
r.CheckTypeError(all_reps[i] | all_reps[j], rTagged);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(CompleteMatrix) {
|
||||
// TODO(titzer): test all variants in the matrix.
|
||||
// rB
|
||||
// tBrB
|
||||
// tBrT
|
||||
// rW32
|
||||
// tIrW32
|
||||
// tUrW32
|
||||
// rW64
|
||||
// tIrW64
|
||||
// tUrW64
|
||||
// rF64
|
||||
// tIrF64
|
||||
// tUrF64
|
||||
// tArF64
|
||||
// rT
|
||||
// tArT
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
// 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 "v8.h"
|
||||
|
||||
#include "function-tester.h"
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
|
||||
|
||||
TEST(TurboSimpleDeopt) {
|
||||
FLAG_allow_natives_syntax = true;
|
||||
FLAG_turbo_deoptimization = true;
|
||||
|
||||
FunctionTester T(
|
||||
"(function f(a) {"
|
||||
"var b = 1;"
|
||||
"if (!%IsOptimized()) return 0;"
|
||||
"%DeoptimizeFunction(f);"
|
||||
"if (%IsOptimized()) return 0;"
|
||||
"return a + b; })");
|
||||
|
||||
T.CheckCall(T.Val(2), T.Val(1));
|
||||
}
|
||||
|
||||
|
||||
TEST(TurboTrivialDeopt) {
|
||||
FLAG_allow_natives_syntax = true;
|
||||
FLAG_turbo_deoptimization = true;
|
||||
|
||||
FunctionTester T(
|
||||
"(function foo() {"
|
||||
"%DeoptimizeFunction(foo);"
|
||||
"return 1; })");
|
||||
|
||||
T.CheckCall(T.Val(1));
|
||||
}
|
@ -1,211 +0,0 @@
|
||||
// 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 "src/v8.h"
|
||||
|
||||
#include "test/cctest/compiler/function-tester.h"
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
|
||||
|
||||
TEST(IsSmi) {
|
||||
FunctionTester T("(function(a) { return %_IsSmi(a); })");
|
||||
|
||||
T.CheckTrue(T.Val(1));
|
||||
T.CheckFalse(T.Val(1.1));
|
||||
T.CheckFalse(T.Val(-0.0));
|
||||
T.CheckTrue(T.Val(-2));
|
||||
T.CheckFalse(T.Val(-2.3));
|
||||
T.CheckFalse(T.undefined());
|
||||
}
|
||||
|
||||
|
||||
TEST(IsNonNegativeSmi) {
|
||||
FunctionTester T("(function(a) { return %_IsNonNegativeSmi(a); })");
|
||||
|
||||
T.CheckTrue(T.Val(1));
|
||||
T.CheckFalse(T.Val(1.1));
|
||||
T.CheckFalse(T.Val(-0.0));
|
||||
T.CheckFalse(T.Val(-2));
|
||||
T.CheckFalse(T.Val(-2.3));
|
||||
T.CheckFalse(T.undefined());
|
||||
}
|
||||
|
||||
|
||||
TEST(IsMinusZero) {
|
||||
FunctionTester T("(function(a) { return %_IsMinusZero(a); })");
|
||||
|
||||
T.CheckFalse(T.Val(1));
|
||||
T.CheckFalse(T.Val(1.1));
|
||||
T.CheckTrue(T.Val(-0.0));
|
||||
T.CheckFalse(T.Val(-2));
|
||||
T.CheckFalse(T.Val(-2.3));
|
||||
T.CheckFalse(T.undefined());
|
||||
}
|
||||
|
||||
|
||||
TEST(IsArray) {
|
||||
FunctionTester T("(function(a) { return %_IsArray(a); })");
|
||||
|
||||
T.CheckFalse(T.NewObject("(function() {})"));
|
||||
T.CheckTrue(T.NewObject("([1])"));
|
||||
T.CheckFalse(T.NewObject("({})"));
|
||||
T.CheckFalse(T.NewObject("(/x/)"));
|
||||
T.CheckFalse(T.undefined());
|
||||
T.CheckFalse(T.null());
|
||||
T.CheckFalse(T.Val("x"));
|
||||
T.CheckFalse(T.Val(1));
|
||||
}
|
||||
|
||||
|
||||
TEST(IsObject) {
|
||||
FunctionTester T("(function(a) { return %_IsObject(a); })");
|
||||
|
||||
T.CheckFalse(T.NewObject("(function() {})"));
|
||||
T.CheckTrue(T.NewObject("([1])"));
|
||||
T.CheckTrue(T.NewObject("({})"));
|
||||
T.CheckTrue(T.NewObject("(/x/)"));
|
||||
T.CheckFalse(T.undefined());
|
||||
T.CheckTrue(T.null());
|
||||
T.CheckFalse(T.Val("x"));
|
||||
T.CheckFalse(T.Val(1));
|
||||
}
|
||||
|
||||
|
||||
TEST(IsFunction) {
|
||||
FunctionTester T("(function(a) { return %_IsFunction(a); })");
|
||||
|
||||
T.CheckTrue(T.NewObject("(function() {})"));
|
||||
T.CheckFalse(T.NewObject("([1])"));
|
||||
T.CheckFalse(T.NewObject("({})"));
|
||||
T.CheckFalse(T.NewObject("(/x/)"));
|
||||
T.CheckFalse(T.undefined());
|
||||
T.CheckFalse(T.null());
|
||||
T.CheckFalse(T.Val("x"));
|
||||
T.CheckFalse(T.Val(1));
|
||||
}
|
||||
|
||||
|
||||
TEST(IsRegExp) {
|
||||
FunctionTester T("(function(a) { return %_IsRegExp(a); })");
|
||||
|
||||
T.CheckFalse(T.NewObject("(function() {})"));
|
||||
T.CheckFalse(T.NewObject("([1])"));
|
||||
T.CheckFalse(T.NewObject("({})"));
|
||||
T.CheckTrue(T.NewObject("(/x/)"));
|
||||
T.CheckFalse(T.undefined());
|
||||
T.CheckFalse(T.null());
|
||||
T.CheckFalse(T.Val("x"));
|
||||
T.CheckFalse(T.Val(1));
|
||||
}
|
||||
|
||||
|
||||
TEST(ClassOf) {
|
||||
FunctionTester T("(function(a) { return %_ClassOf(a); })");
|
||||
|
||||
T.CheckCall(T.Val("Function"), T.NewObject("(function() {})"));
|
||||
T.CheckCall(T.Val("Array"), T.NewObject("([1])"));
|
||||
T.CheckCall(T.Val("Object"), T.NewObject("({})"));
|
||||
T.CheckCall(T.Val("RegExp"), T.NewObject("(/x/)"));
|
||||
T.CheckCall(T.null(), T.undefined());
|
||||
T.CheckCall(T.null(), T.null());
|
||||
T.CheckCall(T.null(), T.Val("x"));
|
||||
T.CheckCall(T.null(), T.Val(1));
|
||||
}
|
||||
|
||||
|
||||
TEST(ObjectEquals) {
|
||||
FunctionTester T("(function(a,b) { return %_ObjectEquals(a,b); })");
|
||||
CompileRun("var o = {}");
|
||||
|
||||
T.CheckTrue(T.NewObject("(o)"), T.NewObject("(o)"));
|
||||
T.CheckTrue(T.Val("internal"), T.Val("internal"));
|
||||
T.CheckTrue(T.true_value(), T.true_value());
|
||||
T.CheckFalse(T.true_value(), T.false_value());
|
||||
T.CheckFalse(T.NewObject("({})"), T.NewObject("({})"));
|
||||
T.CheckFalse(T.Val("a"), T.Val("b"));
|
||||
}
|
||||
|
||||
|
||||
TEST(ValueOf) {
|
||||
FunctionTester T("(function(a) { return %_ValueOf(a); })");
|
||||
|
||||
T.CheckCall(T.Val("a"), T.Val("a"));
|
||||
T.CheckCall(T.Val("b"), T.NewObject("(new String('b'))"));
|
||||
T.CheckCall(T.Val(123), T.Val(123));
|
||||
T.CheckCall(T.Val(456), T.NewObject("(new Number(456))"));
|
||||
}
|
||||
|
||||
|
||||
TEST(SetValueOf) {
|
||||
FunctionTester T("(function(a,b) { return %_SetValueOf(a,b); })");
|
||||
|
||||
T.CheckCall(T.Val("a"), T.NewObject("(new String)"), T.Val("a"));
|
||||
T.CheckCall(T.Val(123), T.NewObject("(new Number)"), T.Val(123));
|
||||
T.CheckCall(T.Val("x"), T.undefined(), T.Val("x"));
|
||||
}
|
||||
|
||||
|
||||
TEST(StringCharFromCode) {
|
||||
FunctionTester T("(function(a) { return %_StringCharFromCode(a); })");
|
||||
|
||||
T.CheckCall(T.Val("a"), T.Val(97));
|
||||
T.CheckCall(T.Val("\xE2\x9D\x8A"), T.Val(0x274A));
|
||||
T.CheckCall(T.Val(""), T.undefined());
|
||||
}
|
||||
|
||||
|
||||
TEST(StringCharAt) {
|
||||
FunctionTester T("(function(a,b) { return %_StringCharAt(a,b); })");
|
||||
|
||||
T.CheckCall(T.Val("e"), T.Val("huge fan!"), T.Val(3));
|
||||
T.CheckCall(T.Val("f"), T.Val("\xE2\x9D\x8A fan!"), T.Val(2));
|
||||
T.CheckCall(T.Val(""), T.Val("not a fan!"), T.Val(23));
|
||||
}
|
||||
|
||||
|
||||
TEST(StringCharCodeAt) {
|
||||
FunctionTester T("(function(a,b) { return %_StringCharCodeAt(a,b); })");
|
||||
|
||||
T.CheckCall(T.Val('e'), T.Val("huge fan!"), T.Val(3));
|
||||
T.CheckCall(T.Val('f'), T.Val("\xE2\x9D\x8A fan!"), T.Val(2));
|
||||
T.CheckCall(T.nan(), T.Val("not a fan!"), T.Val(23));
|
||||
}
|
||||
|
||||
|
||||
TEST(StringAdd) {
|
||||
FunctionTester T("(function(a,b) { return %_StringAdd(a,b); })");
|
||||
|
||||
T.CheckCall(T.Val("aaabbb"), T.Val("aaa"), T.Val("bbb"));
|
||||
T.CheckCall(T.Val("aaa"), T.Val("aaa"), T.Val(""));
|
||||
T.CheckCall(T.Val("bbb"), T.Val(""), T.Val("bbb"));
|
||||
}
|
||||
|
||||
|
||||
TEST(StringSubString) {
|
||||
FunctionTester T("(function(a,b) { return %_SubString(a,b,b+3); })");
|
||||
|
||||
T.CheckCall(T.Val("aaa"), T.Val("aaabbb"), T.Val(0.0));
|
||||
T.CheckCall(T.Val("abb"), T.Val("aaabbb"), T.Val(2));
|
||||
T.CheckCall(T.Val("aaa"), T.Val("aaa"), T.Val(0.0));
|
||||
}
|
||||
|
||||
|
||||
TEST(StringCompare) {
|
||||
FunctionTester T("(function(a,b) { return %_StringCompare(a,b); })");
|
||||
|
||||
T.CheckCall(T.Val(-1), T.Val("aaa"), T.Val("bbb"));
|
||||
T.CheckCall(T.Val(0.0), T.Val("bbb"), T.Val("bbb"));
|
||||
T.CheckCall(T.Val(+1), T.Val("ccc"), T.Val("bbb"));
|
||||
}
|
||||
|
||||
|
||||
TEST(CallFunction) {
|
||||
FunctionTester T("(function(a,b) { return %_CallFunction(a, 1, 2, 3, b); })");
|
||||
CompileRun("function f(a,b,c) { return a + b + c + this.d; }");
|
||||
|
||||
T.CheckCall(T.Val(129), T.NewObject("({d:123})"), T.NewObject("f"));
|
||||
T.CheckCall(T.Val("6x"), T.NewObject("({d:'x'})"), T.NewObject("f"));
|
||||
}
|
@ -1,262 +0,0 @@
|
||||
// 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 "src/v8.h"
|
||||
|
||||
#include "test/cctest/compiler/function-tester.h"
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
|
||||
TEST(Conditional) {
|
||||
FunctionTester T("(function(a) { return a ? 23 : 42; })");
|
||||
|
||||
T.CheckCall(T.Val(23), T.true_value(), T.undefined());
|
||||
T.CheckCall(T.Val(42), T.false_value(), T.undefined());
|
||||
T.CheckCall(T.Val(42), T.undefined(), T.undefined());
|
||||
T.CheckCall(T.Val(42), T.Val(0.0), T.undefined());
|
||||
T.CheckCall(T.Val(23), T.Val(999), T.undefined());
|
||||
T.CheckCall(T.Val(23), T.Val("x"), T.undefined());
|
||||
}
|
||||
|
||||
|
||||
TEST(LogicalAnd) {
|
||||
FunctionTester T("(function(a,b) { return a && b; })");
|
||||
|
||||
T.CheckCall(T.true_value(), T.true_value(), T.true_value());
|
||||
T.CheckCall(T.false_value(), T.false_value(), T.true_value());
|
||||
T.CheckCall(T.false_value(), T.true_value(), T.false_value());
|
||||
T.CheckCall(T.false_value(), T.false_value(), T.false_value());
|
||||
|
||||
T.CheckCall(T.Val(999), T.Val(777), T.Val(999));
|
||||
T.CheckCall(T.Val(0.0), T.Val(0.0), T.Val(999));
|
||||
T.CheckCall(T.Val("b"), T.Val("a"), T.Val("b"));
|
||||
}
|
||||
|
||||
|
||||
TEST(LogicalOr) {
|
||||
FunctionTester T("(function(a,b) { return a || b; })");
|
||||
|
||||
T.CheckCall(T.true_value(), T.true_value(), T.true_value());
|
||||
T.CheckCall(T.true_value(), T.false_value(), T.true_value());
|
||||
T.CheckCall(T.true_value(), T.true_value(), T.false_value());
|
||||
T.CheckCall(T.false_value(), T.false_value(), T.false_value());
|
||||
|
||||
T.CheckCall(T.Val(777), T.Val(777), T.Val(999));
|
||||
T.CheckCall(T.Val(999), T.Val(0.0), T.Val(999));
|
||||
T.CheckCall(T.Val("a"), T.Val("a"), T.Val("b"));
|
||||
}
|
||||
|
||||
|
||||
TEST(LogicalEffect) {
|
||||
FunctionTester T("(function(a,b) { a && (b = a); return b; })");
|
||||
|
||||
T.CheckCall(T.true_value(), T.true_value(), T.true_value());
|
||||
T.CheckCall(T.true_value(), T.false_value(), T.true_value());
|
||||
T.CheckCall(T.true_value(), T.true_value(), T.false_value());
|
||||
T.CheckCall(T.false_value(), T.false_value(), T.false_value());
|
||||
|
||||
T.CheckCall(T.Val(777), T.Val(777), T.Val(999));
|
||||
T.CheckCall(T.Val(999), T.Val(0.0), T.Val(999));
|
||||
T.CheckCall(T.Val("a"), T.Val("a"), T.Val("b"));
|
||||
}
|
||||
|
||||
|
||||
TEST(IfStatement) {
|
||||
FunctionTester T("(function(a) { if (a) { return 1; } else { return 2; } })");
|
||||
|
||||
T.CheckCall(T.Val(1), T.true_value(), T.undefined());
|
||||
T.CheckCall(T.Val(2), T.false_value(), T.undefined());
|
||||
T.CheckCall(T.Val(2), T.undefined(), T.undefined());
|
||||
T.CheckCall(T.Val(2), T.Val(0.0), T.undefined());
|
||||
T.CheckCall(T.Val(1), T.Val(999), T.undefined());
|
||||
T.CheckCall(T.Val(1), T.Val("x"), T.undefined());
|
||||
}
|
||||
|
||||
|
||||
TEST(DoWhileStatement) {
|
||||
FunctionTester T("(function(a,b) { do { a+=23; } while(a < b) return a; })");
|
||||
|
||||
T.CheckCall(T.Val(24), T.Val(1), T.Val(1));
|
||||
T.CheckCall(T.Val(24), T.Val(1), T.Val(23));
|
||||
T.CheckCall(T.Val(47), T.Val(1), T.Val(25));
|
||||
T.CheckCall(T.Val("str23"), T.Val("str"), T.Val("str"));
|
||||
}
|
||||
|
||||
|
||||
TEST(WhileStatement) {
|
||||
FunctionTester T("(function(a,b) { while(a < b) { a+=23; } return a; })");
|
||||
|
||||
T.CheckCall(T.Val(1), T.Val(1), T.Val(1));
|
||||
T.CheckCall(T.Val(24), T.Val(1), T.Val(23));
|
||||
T.CheckCall(T.Val(47), T.Val(1), T.Val(25));
|
||||
T.CheckCall(T.Val("str"), T.Val("str"), T.Val("str"));
|
||||
}
|
||||
|
||||
|
||||
TEST(ForStatement) {
|
||||
FunctionTester T("(function(a,b) { for (; a < b; a+=23) {} return a; })");
|
||||
|
||||
T.CheckCall(T.Val(1), T.Val(1), T.Val(1));
|
||||
T.CheckCall(T.Val(24), T.Val(1), T.Val(23));
|
||||
T.CheckCall(T.Val(47), T.Val(1), T.Val(25));
|
||||
T.CheckCall(T.Val("str"), T.Val("str"), T.Val("str"));
|
||||
}
|
||||
|
||||
|
||||
static void TestForIn(const char* code) {
|
||||
FunctionTester T(code);
|
||||
T.CheckCall(T.undefined(), T.undefined());
|
||||
T.CheckCall(T.undefined(), T.null());
|
||||
T.CheckCall(T.undefined(), T.NewObject("({})"));
|
||||
T.CheckCall(T.undefined(), T.Val(1));
|
||||
T.CheckCall(T.Val("2"), T.Val("str"));
|
||||
T.CheckCall(T.Val("a"), T.NewObject("({'a' : 1})"));
|
||||
T.CheckCall(T.Val("2"), T.NewObject("([1, 2, 3])"));
|
||||
T.CheckCall(T.Val("a"), T.NewObject("({'a' : 1, 'b' : 1})"), T.Val("b"));
|
||||
T.CheckCall(T.Val("1"), T.NewObject("([1, 2, 3])"), T.Val("2"));
|
||||
}
|
||||
|
||||
|
||||
TEST(ForInStatement) {
|
||||
// Variable assignment.
|
||||
TestForIn(
|
||||
"(function(a, b) {"
|
||||
"var last;"
|
||||
"for (var x in a) {"
|
||||
" if (b) { delete a[b]; b = undefined; }"
|
||||
" last = x;"
|
||||
"}"
|
||||
"return last;})");
|
||||
// Indexed assignment.
|
||||
TestForIn(
|
||||
"(function(a, b) {"
|
||||
"var array = [0, 1, undefined];"
|
||||
"for (array[2] in a) {"
|
||||
" if (b) { delete a[b]; b = undefined; }"
|
||||
"}"
|
||||
"return array[2];})");
|
||||
// Named assignment.
|
||||
TestForIn(
|
||||
"(function(a, b) {"
|
||||
"var obj = {'a' : undefined};"
|
||||
"for (obj.a in a) {"
|
||||
" if (b) { delete a[b]; b = undefined; }"
|
||||
"}"
|
||||
"return obj.a;})");
|
||||
}
|
||||
|
||||
|
||||
TEST(SwitchStatement) {
|
||||
const char* src =
|
||||
"(function(a,b) {"
|
||||
" var r = '-';"
|
||||
" switch (a) {"
|
||||
" case 'x' : r += 'X-';"
|
||||
" case b + 'b': r += 'B-';"
|
||||
" default : r += 'D-';"
|
||||
" case 'y' : r += 'Y-';"
|
||||
" }"
|
||||
" return r;"
|
||||
"})";
|
||||
FunctionTester T(src);
|
||||
|
||||
T.CheckCall(T.Val("-X-B-D-Y-"), T.Val("x"), T.Val("B"));
|
||||
T.CheckCall(T.Val("-B-D-Y-"), T.Val("Bb"), T.Val("B"));
|
||||
T.CheckCall(T.Val("-D-Y-"), T.Val("z"), T.Val("B"));
|
||||
T.CheckCall(T.Val("-Y-"), T.Val("y"), T.Val("B"));
|
||||
|
||||
CompileRun("var c = 0; var o = { toString:function(){return c++} };");
|
||||
T.CheckCall(T.Val("-D-Y-"), T.Val("1b"), T.NewObject("o"));
|
||||
T.CheckCall(T.Val("-B-D-Y-"), T.Val("1b"), T.NewObject("o"));
|
||||
T.CheckCall(T.Val("-D-Y-"), T.Val("1b"), T.NewObject("o"));
|
||||
}
|
||||
|
||||
|
||||
TEST(BlockBreakStatement) {
|
||||
FunctionTester T("(function(a,b) { L:{ if (a) break L; b=1; } return b; })");
|
||||
|
||||
T.CheckCall(T.Val(7), T.true_value(), T.Val(7));
|
||||
T.CheckCall(T.Val(1), T.false_value(), T.Val(7));
|
||||
}
|
||||
|
||||
|
||||
TEST(BlockReturnStatement) {
|
||||
FunctionTester T("(function(a,b) { L:{ if (a) b=1; return b; } })");
|
||||
|
||||
T.CheckCall(T.Val(1), T.true_value(), T.Val(7));
|
||||
T.CheckCall(T.Val(7), T.false_value(), T.Val(7));
|
||||
}
|
||||
|
||||
|
||||
TEST(NestedIfConditional) {
|
||||
FunctionTester T("(function(a,b) { if (a) { b = (b?b:7) + 1; } return b; })");
|
||||
|
||||
T.CheckCall(T.Val(4), T.false_value(), T.Val(4));
|
||||
T.CheckCall(T.Val(6), T.true_value(), T.Val(5));
|
||||
T.CheckCall(T.Val(8), T.true_value(), T.undefined());
|
||||
}
|
||||
|
||||
|
||||
TEST(NestedIfLogical) {
|
||||
const char* src =
|
||||
"(function(a,b) {"
|
||||
" if (a || b) { return 1; } else { return 2; }"
|
||||
"})";
|
||||
FunctionTester T(src);
|
||||
|
||||
T.CheckCall(T.Val(1), T.true_value(), T.true_value());
|
||||
T.CheckCall(T.Val(1), T.false_value(), T.true_value());
|
||||
T.CheckCall(T.Val(1), T.true_value(), T.false_value());
|
||||
T.CheckCall(T.Val(2), T.false_value(), T.false_value());
|
||||
T.CheckCall(T.Val(1), T.Val(1.0), T.Val(1.0));
|
||||
T.CheckCall(T.Val(1), T.Val(0.0), T.Val(1.0));
|
||||
T.CheckCall(T.Val(1), T.Val(1.0), T.Val(0.0));
|
||||
T.CheckCall(T.Val(2), T.Val(0.0), T.Val(0.0));
|
||||
}
|
||||
|
||||
|
||||
TEST(NestedIfElseFor) {
|
||||
const char* src =
|
||||
"(function(a,b) {"
|
||||
" if (!a) { return b - 3; } else { for (; a < b; a++); }"
|
||||
" return a;"
|
||||
"})";
|
||||
FunctionTester T(src);
|
||||
|
||||
T.CheckCall(T.Val(1), T.false_value(), T.Val(4));
|
||||
T.CheckCall(T.Val(2), T.true_value(), T.Val(2));
|
||||
T.CheckCall(T.Val(3), T.Val(3), T.Val(1));
|
||||
}
|
||||
|
||||
|
||||
TEST(NestedWhileWhile) {
|
||||
const char* src =
|
||||
"(function(a) {"
|
||||
" var i = a; while (false) while(false) return i;"
|
||||
" return i;"
|
||||
"})";
|
||||
FunctionTester T(src);
|
||||
|
||||
T.CheckCall(T.Val(2.0), T.Val(2.0), T.Val(-1.0));
|
||||
T.CheckCall(T.Val(65.0), T.Val(65.0), T.Val(-1.0));
|
||||
}
|
||||
|
||||
|
||||
TEST(NestedForIf) {
|
||||
FunctionTester T("(function(a,b) { for (; a > 1; a--) if (b) return 1; })");
|
||||
|
||||
T.CheckCall(T.Val(1), T.Val(3), T.true_value());
|
||||
T.CheckCall(T.undefined(), T.Val(2), T.false_value());
|
||||
T.CheckCall(T.undefined(), T.Val(1), T.null());
|
||||
}
|
||||
|
||||
|
||||
TEST(NestedForConditional) {
|
||||
FunctionTester T("(function(a,b) { for (; a > 1; a--) return b ? 1 : 2; })");
|
||||
|
||||
T.CheckCall(T.Val(1), T.Val(3), T.true_value());
|
||||
T.CheckCall(T.Val(2), T.Val(2), T.false_value());
|
||||
T.CheckCall(T.undefined(), T.Val(1), T.null());
|
||||
}
|
@ -1,235 +0,0 @@
|
||||
// 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 "src/v8.h"
|
||||
|
||||
#include "test/cctest/compiler/function-tester.h"
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
|
||||
TEST(SimpleCall) {
|
||||
FunctionTester T("(function(foo,a) { return foo(a); })");
|
||||
Handle<JSFunction> foo = T.NewFunction("(function(a) { return a; })");
|
||||
|
||||
T.CheckCall(T.Val(3), foo, T.Val(3));
|
||||
T.CheckCall(T.Val(3.1), foo, T.Val(3.1));
|
||||
T.CheckCall(foo, foo, foo);
|
||||
T.CheckCall(T.Val("Abba"), foo, T.Val("Abba"));
|
||||
}
|
||||
|
||||
|
||||
TEST(SimpleCall2) {
|
||||
FunctionTester T("(function(foo,a) { return foo(a); })");
|
||||
Handle<JSFunction> foo = T.NewFunction("(function(a) { return a; })");
|
||||
T.Compile(foo);
|
||||
|
||||
T.CheckCall(T.Val(3), foo, T.Val(3));
|
||||
T.CheckCall(T.Val(3.1), foo, T.Val(3.1));
|
||||
T.CheckCall(foo, foo, foo);
|
||||
T.CheckCall(T.Val("Abba"), foo, T.Val("Abba"));
|
||||
}
|
||||
|
||||
|
||||
TEST(ConstCall) {
|
||||
FunctionTester T("(function(foo,a) { return foo(a,3); })");
|
||||
Handle<JSFunction> foo = T.NewFunction("(function(a,b) { return a + b; })");
|
||||
T.Compile(foo);
|
||||
|
||||
T.CheckCall(T.Val(6), foo, T.Val(3));
|
||||
T.CheckCall(T.Val(6.1), foo, T.Val(3.1));
|
||||
T.CheckCall(T.Val("function (a,b) { return a + b; }3"), foo, foo);
|
||||
T.CheckCall(T.Val("Abba3"), foo, T.Val("Abba"));
|
||||
}
|
||||
|
||||
|
||||
TEST(ConstCall2) {
|
||||
FunctionTester T("(function(foo,a) { return foo(a,\"3\"); })");
|
||||
Handle<JSFunction> foo = T.NewFunction("(function(a,b) { return a + b; })");
|
||||
T.Compile(foo);
|
||||
|
||||
T.CheckCall(T.Val("33"), foo, T.Val(3));
|
||||
T.CheckCall(T.Val("3.13"), foo, T.Val(3.1));
|
||||
T.CheckCall(T.Val("function (a,b) { return a + b; }3"), foo, foo);
|
||||
T.CheckCall(T.Val("Abba3"), foo, T.Val("Abba"));
|
||||
}
|
||||
|
||||
|
||||
TEST(PropertyNamedCall) {
|
||||
FunctionTester T("(function(a,b) { return a.foo(b,23); })");
|
||||
CompileRun("function foo(y,z) { return this.x + y + z; }");
|
||||
|
||||
T.CheckCall(T.Val(32), T.NewObject("({ foo:foo, x:4 })"), T.Val(5));
|
||||
T.CheckCall(T.Val("xy23"), T.NewObject("({ foo:foo, x:'x' })"), T.Val("y"));
|
||||
T.CheckCall(T.nan(), T.NewObject("({ foo:foo, y:0 })"), T.Val(3));
|
||||
}
|
||||
|
||||
|
||||
TEST(PropertyKeyedCall) {
|
||||
FunctionTester T("(function(a,b) { var f = 'foo'; return a[f](b,23); })");
|
||||
CompileRun("function foo(y,z) { return this.x + y + z; }");
|
||||
|
||||
T.CheckCall(T.Val(32), T.NewObject("({ foo:foo, x:4 })"), T.Val(5));
|
||||
T.CheckCall(T.Val("xy23"), T.NewObject("({ foo:foo, x:'x' })"), T.Val("y"));
|
||||
T.CheckCall(T.nan(), T.NewObject("({ foo:foo, y:0 })"), T.Val(3));
|
||||
}
|
||||
|
||||
|
||||
TEST(GlobalCall) {
|
||||
FunctionTester T("(function(a,b) { return foo(a,b); })");
|
||||
CompileRun("function foo(a,b) { return a + b + this.c; }");
|
||||
CompileRun("var c = 23;");
|
||||
|
||||
T.CheckCall(T.Val(32), T.Val(4), T.Val(5));
|
||||
T.CheckCall(T.Val("xy23"), T.Val("x"), T.Val("y"));
|
||||
T.CheckCall(T.nan(), T.undefined(), T.Val(3));
|
||||
}
|
||||
|
||||
|
||||
TEST(LookupCall) {
|
||||
FunctionTester T("(function(a,b) { with (a) { return foo(a,b); } })");
|
||||
|
||||
CompileRun("function f1(a,b) { return a.val + b; }");
|
||||
T.CheckCall(T.Val(5), T.NewObject("({ foo:f1, val:2 })"), T.Val(3));
|
||||
T.CheckCall(T.Val("xy"), T.NewObject("({ foo:f1, val:'x' })"), T.Val("y"));
|
||||
|
||||
CompileRun("function f2(a,b) { return this.val + b; }");
|
||||
T.CheckCall(T.Val(9), T.NewObject("({ foo:f2, val:4 })"), T.Val(5));
|
||||
T.CheckCall(T.Val("xy"), T.NewObject("({ foo:f2, val:'x' })"), T.Val("y"));
|
||||
}
|
||||
|
||||
|
||||
TEST(MismatchCallTooFew) {
|
||||
FunctionTester T("(function(a,b) { return foo(a,b); })");
|
||||
CompileRun("function foo(a,b,c) { return a + b + c; }");
|
||||
|
||||
T.CheckCall(T.nan(), T.Val(23), T.Val(42));
|
||||
T.CheckCall(T.nan(), T.Val(4.2), T.Val(2.3));
|
||||
T.CheckCall(T.Val("abundefined"), T.Val("a"), T.Val("b"));
|
||||
}
|
||||
|
||||
|
||||
TEST(MismatchCallTooMany) {
|
||||
FunctionTester T("(function(a,b) { return foo(a,b); })");
|
||||
CompileRun("function foo(a) { return a; }");
|
||||
|
||||
T.CheckCall(T.Val(23), T.Val(23), T.Val(42));
|
||||
T.CheckCall(T.Val(4.2), T.Val(4.2), T.Val(2.3));
|
||||
T.CheckCall(T.Val("a"), T.Val("a"), T.Val("b"));
|
||||
}
|
||||
|
||||
|
||||
TEST(ConstructorCall) {
|
||||
FunctionTester T("(function(a,b) { return new foo(a,b).value; })");
|
||||
CompileRun("function foo(a,b) { return { value: a + b + this.c }; }");
|
||||
CompileRun("foo.prototype.c = 23;");
|
||||
|
||||
T.CheckCall(T.Val(32), T.Val(4), T.Val(5));
|
||||
T.CheckCall(T.Val("xy23"), T.Val("x"), T.Val("y"));
|
||||
T.CheckCall(T.nan(), T.undefined(), T.Val(3));
|
||||
}
|
||||
|
||||
|
||||
// TODO(titzer): factor these out into test-runtime-calls.cc
|
||||
TEST(RuntimeCallCPP1) {
|
||||
FLAG_allow_natives_syntax = true;
|
||||
FunctionTester T("(function(a) { return %ToBool(a); })");
|
||||
|
||||
T.CheckCall(T.true_value(), T.Val(23), T.undefined());
|
||||
T.CheckCall(T.true_value(), T.Val(4.2), T.undefined());
|
||||
T.CheckCall(T.true_value(), T.Val("str"), T.undefined());
|
||||
T.CheckCall(T.true_value(), T.true_value(), T.undefined());
|
||||
T.CheckCall(T.false_value(), T.false_value(), T.undefined());
|
||||
T.CheckCall(T.false_value(), T.undefined(), T.undefined());
|
||||
T.CheckCall(T.false_value(), T.Val(0.0), T.undefined());
|
||||
}
|
||||
|
||||
|
||||
TEST(RuntimeCallCPP2) {
|
||||
FLAG_allow_natives_syntax = true;
|
||||
FunctionTester T("(function(a,b) { return %NumberAdd(a, b); })");
|
||||
|
||||
T.CheckCall(T.Val(65), T.Val(42), T.Val(23));
|
||||
T.CheckCall(T.Val(19), T.Val(42), T.Val(-23));
|
||||
T.CheckCall(T.Val(6.5), T.Val(4.2), T.Val(2.3));
|
||||
}
|
||||
|
||||
|
||||
TEST(RuntimeCallJS) {
|
||||
FLAG_allow_natives_syntax = true;
|
||||
FunctionTester T("(function(a) { return %ToString(a); })");
|
||||
|
||||
T.CheckCall(T.Val("23"), T.Val(23), T.undefined());
|
||||
T.CheckCall(T.Val("4.2"), T.Val(4.2), T.undefined());
|
||||
T.CheckCall(T.Val("str"), T.Val("str"), T.undefined());
|
||||
T.CheckCall(T.Val("true"), T.true_value(), T.undefined());
|
||||
T.CheckCall(T.Val("false"), T.false_value(), T.undefined());
|
||||
T.CheckCall(T.Val("undefined"), T.undefined(), T.undefined());
|
||||
}
|
||||
|
||||
|
||||
TEST(RuntimeCallInline) {
|
||||
FLAG_allow_natives_syntax = true;
|
||||
FunctionTester T("(function(a) { return %_IsObject(a); })");
|
||||
|
||||
T.CheckCall(T.false_value(), T.Val(23), T.undefined());
|
||||
T.CheckCall(T.false_value(), T.Val(4.2), T.undefined());
|
||||
T.CheckCall(T.false_value(), T.Val("str"), T.undefined());
|
||||
T.CheckCall(T.false_value(), T.true_value(), T.undefined());
|
||||
T.CheckCall(T.false_value(), T.false_value(), T.undefined());
|
||||
T.CheckCall(T.false_value(), T.undefined(), T.undefined());
|
||||
T.CheckCall(T.true_value(), T.NewObject("({})"), T.undefined());
|
||||
T.CheckCall(T.true_value(), T.NewObject("([])"), T.undefined());
|
||||
}
|
||||
|
||||
|
||||
TEST(RuntimeCallBooleanize) {
|
||||
// TODO(turbofan): %Booleanize will disappear, don't hesitate to remove this
|
||||
// test case, two-argument case is covered by the above test already.
|
||||
FLAG_allow_natives_syntax = true;
|
||||
FunctionTester T("(function(a,b) { return %Booleanize(a, b); })");
|
||||
|
||||
T.CheckCall(T.true_value(), T.Val(-1), T.Val(Token::LT));
|
||||
T.CheckCall(T.false_value(), T.Val(-1), T.Val(Token::EQ));
|
||||
T.CheckCall(T.false_value(), T.Val(-1), T.Val(Token::GT));
|
||||
|
||||
T.CheckCall(T.false_value(), T.Val(0.0), T.Val(Token::LT));
|
||||
T.CheckCall(T.true_value(), T.Val(0.0), T.Val(Token::EQ));
|
||||
T.CheckCall(T.false_value(), T.Val(0.0), T.Val(Token::GT));
|
||||
|
||||
T.CheckCall(T.false_value(), T.Val(1), T.Val(Token::LT));
|
||||
T.CheckCall(T.false_value(), T.Val(1), T.Val(Token::EQ));
|
||||
T.CheckCall(T.true_value(), T.Val(1), T.Val(Token::GT));
|
||||
}
|
||||
|
||||
|
||||
TEST(EvalCall) {
|
||||
FunctionTester T("(function(a,b) { return eval(a); })");
|
||||
Handle<JSObject> g(T.function->context()->global_object()->global_proxy());
|
||||
|
||||
T.CheckCall(T.Val(23), T.Val("17 + 6"), T.undefined());
|
||||
T.CheckCall(T.Val("'Y'; a"), T.Val("'Y'; a"), T.Val("b-val"));
|
||||
T.CheckCall(T.Val("b-val"), T.Val("'Y'; b"), T.Val("b-val"));
|
||||
T.CheckCall(g, T.Val("this"), T.undefined());
|
||||
T.CheckCall(g, T.Val("'use strict'; this"), T.undefined());
|
||||
|
||||
CompileRun("eval = function(x) { return x; }");
|
||||
T.CheckCall(T.Val("17 + 6"), T.Val("17 + 6"), T.undefined());
|
||||
|
||||
CompileRun("eval = function(x) { return this; }");
|
||||
T.CheckCall(g, T.Val("17 + 6"), T.undefined());
|
||||
|
||||
CompileRun("eval = function(x) { 'use strict'; return this; }");
|
||||
T.CheckCall(T.undefined(), T.Val("17 + 6"), T.undefined());
|
||||
}
|
||||
|
||||
|
||||
TEST(ReceiverPatching) {
|
||||
// TODO(turbofan): Note that this test only checks that the function prologue
|
||||
// patches an undefined receiver to the global receiver. If this starts to
|
||||
// fail once we fix the calling protocol, just remove this test.
|
||||
FunctionTester T("(function(a) { return this; })");
|
||||
Handle<JSObject> g(T.function->context()->global_object()->global_proxy());
|
||||
T.CheckCall(g, T.undefined());
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
// 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 "src/v8.h"
|
||||
|
||||
#include "test/cctest/compiler/function-tester.h"
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
|
||||
TEST(Throw) {
|
||||
FunctionTester T("(function(a,b) { if (a) { throw b; } else { return b; }})");
|
||||
|
||||
T.CheckThrows(T.true_value(), T.NewObject("new Error"));
|
||||
T.CheckCall(T.Val(23), T.false_value(), T.Val(23));
|
||||
}
|
||||
|
||||
|
||||
TEST(ThrowSourcePosition) {
|
||||
static const char* src =
|
||||
"(function(a, b) { \n"
|
||||
" if (a == 1) throw 1; \n"
|
||||
" if (a == 2) {throw 2} \n"
|
||||
" if (a == 3) {0;throw 3}\n"
|
||||
" throw 4; \n"
|
||||
"}) ";
|
||||
FunctionTester T(src);
|
||||
v8::Handle<v8::Message> message;
|
||||
|
||||
message = T.CheckThrowsReturnMessage(T.Val(1), T.undefined());
|
||||
CHECK(!message.IsEmpty());
|
||||
CHECK_EQ(2, message->GetLineNumber());
|
||||
CHECK_EQ(40, message->GetStartPosition());
|
||||
|
||||
message = T.CheckThrowsReturnMessage(T.Val(2), T.undefined());
|
||||
CHECK(!message.IsEmpty());
|
||||
CHECK_EQ(3, message->GetLineNumber());
|
||||
CHECK_EQ(67, message->GetStartPosition());
|
||||
|
||||
message = T.CheckThrowsReturnMessage(T.Val(3), T.undefined());
|
||||
CHECK(!message.IsEmpty());
|
||||
CHECK_EQ(4, message->GetLineNumber());
|
||||
CHECK_EQ(95, message->GetStartPosition());
|
||||
}
|
@ -1,524 +0,0 @@
|
||||
// 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 "src/v8.h"
|
||||
|
||||
#include "test/cctest/compiler/function-tester.h"
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
|
||||
TEST(BinopAdd) {
|
||||
FunctionTester T("(function(a,b) { return a + b; })");
|
||||
|
||||
T.CheckCall(3, 1, 2);
|
||||
T.CheckCall(-11, -2, -9);
|
||||
T.CheckCall(-11, -1.5, -9.5);
|
||||
T.CheckCall(T.Val("AB"), T.Val("A"), T.Val("B"));
|
||||
T.CheckCall(T.Val("A11"), T.Val("A"), T.Val(11));
|
||||
T.CheckCall(T.Val("12B"), T.Val(12), T.Val("B"));
|
||||
T.CheckCall(T.Val("38"), T.Val("3"), T.Val("8"));
|
||||
T.CheckCall(T.Val("31"), T.Val("3"), T.NewObject("([1])"));
|
||||
T.CheckCall(T.Val("3[object Object]"), T.Val("3"), T.NewObject("({})"));
|
||||
}
|
||||
|
||||
|
||||
TEST(BinopSubtract) {
|
||||
FunctionTester T("(function(a,b) { return a - b; })");
|
||||
|
||||
T.CheckCall(3, 4, 1);
|
||||
T.CheckCall(3.0, 4.5, 1.5);
|
||||
T.CheckCall(T.Val(-9), T.Val("0"), T.Val(9));
|
||||
T.CheckCall(T.Val(-9), T.Val(0.0), T.Val("9"));
|
||||
T.CheckCall(T.Val(1), T.Val("3"), T.Val("2"));
|
||||
T.CheckCall(T.nan(), T.Val("3"), T.Val("B"));
|
||||
T.CheckCall(T.Val(2), T.Val("3"), T.NewObject("([1])"));
|
||||
T.CheckCall(T.nan(), T.Val("3"), T.NewObject("({})"));
|
||||
}
|
||||
|
||||
|
||||
TEST(BinopMultiply) {
|
||||
FunctionTester T("(function(a,b) { return a * b; })");
|
||||
|
||||
T.CheckCall(6, 3, 2);
|
||||
T.CheckCall(4.5, 2.0, 2.25);
|
||||
T.CheckCall(T.Val(6), T.Val("3"), T.Val(2));
|
||||
T.CheckCall(T.Val(4.5), T.Val(2.0), T.Val("2.25"));
|
||||
T.CheckCall(T.Val(6), T.Val("3"), T.Val("2"));
|
||||
T.CheckCall(T.nan(), T.Val("3"), T.Val("B"));
|
||||
T.CheckCall(T.Val(3), T.Val("3"), T.NewObject("([1])"));
|
||||
T.CheckCall(T.nan(), T.Val("3"), T.NewObject("({})"));
|
||||
}
|
||||
|
||||
|
||||
TEST(BinopDivide) {
|
||||
FunctionTester T("(function(a,b) { return a / b; })");
|
||||
|
||||
T.CheckCall(2, 8, 4);
|
||||
T.CheckCall(2.1, 8.4, 4);
|
||||
T.CheckCall(V8_INFINITY, 8, 0);
|
||||
T.CheckCall(-V8_INFINITY, -8, 0);
|
||||
T.CheckCall(T.infinity(), T.Val(8), T.Val("0"));
|
||||
T.CheckCall(T.minus_infinity(), T.Val("-8"), T.Val(0.0));
|
||||
T.CheckCall(T.Val(1.5), T.Val("3"), T.Val("2"));
|
||||
T.CheckCall(T.nan(), T.Val("3"), T.Val("B"));
|
||||
T.CheckCall(T.Val(1.5), T.Val("3"), T.NewObject("([2])"));
|
||||
T.CheckCall(T.nan(), T.Val("3"), T.NewObject("({})"));
|
||||
}
|
||||
|
||||
|
||||
TEST(BinopModulus) {
|
||||
FunctionTester T("(function(a,b) { return a % b; })");
|
||||
|
||||
T.CheckCall(3, 8, 5);
|
||||
T.CheckCall(T.Val(3), T.Val("8"), T.Val(5));
|
||||
T.CheckCall(T.Val(3), T.Val(8), T.Val("5"));
|
||||
T.CheckCall(T.Val(1), T.Val("3"), T.Val("2"));
|
||||
T.CheckCall(T.nan(), T.Val("3"), T.Val("B"));
|
||||
T.CheckCall(T.Val(1), T.Val("3"), T.NewObject("([2])"));
|
||||
T.CheckCall(T.nan(), T.Val("3"), T.NewObject("({})"));
|
||||
}
|
||||
|
||||
|
||||
TEST(BinopShiftLeft) {
|
||||
FunctionTester T("(function(a,b) { return a << b; })");
|
||||
|
||||
T.CheckCall(4, 2, 1);
|
||||
T.CheckCall(T.Val(4), T.Val("2"), T.Val(1));
|
||||
T.CheckCall(T.Val(4), T.Val(2), T.Val("1"));
|
||||
}
|
||||
|
||||
|
||||
TEST(BinopShiftRight) {
|
||||
FunctionTester T("(function(a,b) { return a >> b; })");
|
||||
|
||||
T.CheckCall(4, 8, 1);
|
||||
T.CheckCall(-4, -8, 1);
|
||||
T.CheckCall(T.Val(4), T.Val("8"), T.Val(1));
|
||||
T.CheckCall(T.Val(4), T.Val(8), T.Val("1"));
|
||||
}
|
||||
|
||||
|
||||
TEST(BinopShiftRightLogical) {
|
||||
FunctionTester T("(function(a,b) { return a >>> b; })");
|
||||
|
||||
T.CheckCall(4, 8, 1);
|
||||
T.CheckCall(0x7ffffffc, -8, 1);
|
||||
T.CheckCall(T.Val(4), T.Val("8"), T.Val(1));
|
||||
T.CheckCall(T.Val(4), T.Val(8), T.Val("1"));
|
||||
}
|
||||
|
||||
|
||||
TEST(BinopAnd) {
|
||||
FunctionTester T("(function(a,b) { return a & b; })");
|
||||
|
||||
T.CheckCall(7, 7, 15);
|
||||
T.CheckCall(7, 15, 7);
|
||||
T.CheckCall(T.Val(7), T.Val("15"), T.Val(7));
|
||||
T.CheckCall(T.Val(7), T.Val(15), T.Val("7"));
|
||||
}
|
||||
|
||||
|
||||
TEST(BinopOr) {
|
||||
FunctionTester T("(function(a,b) { return a | b; })");
|
||||
|
||||
T.CheckCall(6, 4, 2);
|
||||
T.CheckCall(6, 2, 4);
|
||||
T.CheckCall(T.Val(6), T.Val("2"), T.Val(4));
|
||||
T.CheckCall(T.Val(6), T.Val(2), T.Val("4"));
|
||||
}
|
||||
|
||||
|
||||
TEST(BinopXor) {
|
||||
FunctionTester T("(function(a,b) { return a ^ b; })");
|
||||
|
||||
T.CheckCall(7, 15, 8);
|
||||
T.CheckCall(7, 8, 15);
|
||||
T.CheckCall(T.Val(7), T.Val("8"), T.Val(15));
|
||||
T.CheckCall(T.Val(7), T.Val(8), T.Val("15"));
|
||||
}
|
||||
|
||||
|
||||
TEST(BinopStrictEqual) {
|
||||
FunctionTester T("(function(a,b) { return a === b; })");
|
||||
|
||||
T.CheckTrue(7, 7);
|
||||
T.CheckFalse(7, 8);
|
||||
T.CheckTrue(7.1, 7.1);
|
||||
T.CheckFalse(7.1, 8.1);
|
||||
|
||||
T.CheckTrue(T.Val("7.1"), T.Val("7.1"));
|
||||
T.CheckFalse(T.Val(7.1), T.Val("7.1"));
|
||||
T.CheckFalse(T.Val(7), T.undefined());
|
||||
T.CheckFalse(T.undefined(), T.Val(7));
|
||||
|
||||
CompileRun("var o = { desc : 'I am a singleton' }");
|
||||
T.CheckFalse(T.NewObject("([1])"), T.NewObject("([1])"));
|
||||
T.CheckFalse(T.NewObject("({})"), T.NewObject("({})"));
|
||||
T.CheckTrue(T.NewObject("(o)"), T.NewObject("(o)"));
|
||||
}
|
||||
|
||||
|
||||
TEST(BinopEqual) {
|
||||
FunctionTester T("(function(a,b) { return a == b; })");
|
||||
|
||||
T.CheckTrue(7, 7);
|
||||
T.CheckFalse(7, 8);
|
||||
T.CheckTrue(7.1, 7.1);
|
||||
T.CheckFalse(7.1, 8.1);
|
||||
|
||||
T.CheckTrue(T.Val("7.1"), T.Val("7.1"));
|
||||
T.CheckTrue(T.Val(7.1), T.Val("7.1"));
|
||||
|
||||
CompileRun("var o = { desc : 'I am a singleton' }");
|
||||
T.CheckFalse(T.NewObject("([1])"), T.NewObject("([1])"));
|
||||
T.CheckFalse(T.NewObject("({})"), T.NewObject("({})"));
|
||||
T.CheckTrue(T.NewObject("(o)"), T.NewObject("(o)"));
|
||||
}
|
||||
|
||||
|
||||
TEST(BinopNotEqual) {
|
||||
FunctionTester T("(function(a,b) { return a != b; })");
|
||||
|
||||
T.CheckFalse(7, 7);
|
||||
T.CheckTrue(7, 8);
|
||||
T.CheckFalse(7.1, 7.1);
|
||||
T.CheckTrue(7.1, 8.1);
|
||||
|
||||
T.CheckFalse(T.Val("7.1"), T.Val("7.1"));
|
||||
T.CheckFalse(T.Val(7.1), T.Val("7.1"));
|
||||
|
||||
CompileRun("var o = { desc : 'I am a singleton' }");
|
||||
T.CheckTrue(T.NewObject("([1])"), T.NewObject("([1])"));
|
||||
T.CheckTrue(T.NewObject("({})"), T.NewObject("({})"));
|
||||
T.CheckFalse(T.NewObject("(o)"), T.NewObject("(o)"));
|
||||
}
|
||||
|
||||
|
||||
TEST(BinopLessThan) {
|
||||
FunctionTester T("(function(a,b) { return a < b; })");
|
||||
|
||||
T.CheckTrue(7, 8);
|
||||
T.CheckFalse(8, 7);
|
||||
T.CheckTrue(-8.1, -8);
|
||||
T.CheckFalse(-8, -8.1);
|
||||
T.CheckFalse(0.111, 0.111);
|
||||
|
||||
T.CheckFalse(T.Val("7.1"), T.Val("7.1"));
|
||||
T.CheckFalse(T.Val(7.1), T.Val("6.1"));
|
||||
T.CheckFalse(T.Val(7.1), T.Val("7.1"));
|
||||
T.CheckTrue(T.Val(7.1), T.Val("8.1"));
|
||||
}
|
||||
|
||||
|
||||
TEST(BinopLessThanEqual) {
|
||||
FunctionTester T("(function(a,b) { return a <= b; })");
|
||||
|
||||
T.CheckTrue(7, 8);
|
||||
T.CheckFalse(8, 7);
|
||||
T.CheckTrue(-8.1, -8);
|
||||
T.CheckFalse(-8, -8.1);
|
||||
T.CheckTrue(0.111, 0.111);
|
||||
|
||||
T.CheckTrue(T.Val("7.1"), T.Val("7.1"));
|
||||
T.CheckFalse(T.Val(7.1), T.Val("6.1"));
|
||||
T.CheckTrue(T.Val(7.1), T.Val("7.1"));
|
||||
T.CheckTrue(T.Val(7.1), T.Val("8.1"));
|
||||
}
|
||||
|
||||
|
||||
TEST(BinopGreaterThan) {
|
||||
FunctionTester T("(function(a,b) { return a > b; })");
|
||||
|
||||
T.CheckFalse(7, 8);
|
||||
T.CheckTrue(8, 7);
|
||||
T.CheckFalse(-8.1, -8);
|
||||
T.CheckTrue(-8, -8.1);
|
||||
T.CheckFalse(0.111, 0.111);
|
||||
|
||||
T.CheckFalse(T.Val("7.1"), T.Val("7.1"));
|
||||
T.CheckTrue(T.Val(7.1), T.Val("6.1"));
|
||||
T.CheckFalse(T.Val(7.1), T.Val("7.1"));
|
||||
T.CheckFalse(T.Val(7.1), T.Val("8.1"));
|
||||
}
|
||||
|
||||
|
||||
TEST(BinopGreaterThanOrEqual) {
|
||||
FunctionTester T("(function(a,b) { return a >= b; })");
|
||||
|
||||
T.CheckFalse(7, 8);
|
||||
T.CheckTrue(8, 7);
|
||||
T.CheckFalse(-8.1, -8);
|
||||
T.CheckTrue(-8, -8.1);
|
||||
T.CheckTrue(0.111, 0.111);
|
||||
|
||||
T.CheckTrue(T.Val("7.1"), T.Val("7.1"));
|
||||
T.CheckTrue(T.Val(7.1), T.Val("6.1"));
|
||||
T.CheckTrue(T.Val(7.1), T.Val("7.1"));
|
||||
T.CheckFalse(T.Val(7.1), T.Val("8.1"));
|
||||
}
|
||||
|
||||
|
||||
TEST(BinopIn) {
|
||||
FunctionTester T("(function(a,b) { return a in b; })");
|
||||
|
||||
T.CheckTrue(T.Val("x"), T.NewObject("({x:23})"));
|
||||
T.CheckFalse(T.Val("y"), T.NewObject("({x:42})"));
|
||||
T.CheckFalse(T.Val(123), T.NewObject("({x:65})"));
|
||||
T.CheckTrue(T.Val(1), T.NewObject("([1,2,3])"));
|
||||
}
|
||||
|
||||
|
||||
TEST(BinopInstanceOf) {
|
||||
FunctionTester T("(function(a,b) { return a instanceof b; })");
|
||||
|
||||
T.CheckTrue(T.NewObject("(new Number(23))"), T.NewObject("Number"));
|
||||
T.CheckFalse(T.NewObject("(new Number(23))"), T.NewObject("String"));
|
||||
T.CheckFalse(T.NewObject("(new String('a'))"), T.NewObject("Number"));
|
||||
T.CheckTrue(T.NewObject("(new String('b'))"), T.NewObject("String"));
|
||||
T.CheckFalse(T.Val(1), T.NewObject("Number"));
|
||||
T.CheckFalse(T.Val("abc"), T.NewObject("String"));
|
||||
|
||||
CompileRun("var bound = (function() {}).bind(undefined)");
|
||||
T.CheckTrue(T.NewObject("(new bound())"), T.NewObject("bound"));
|
||||
T.CheckTrue(T.NewObject("(new bound())"), T.NewObject("Object"));
|
||||
T.CheckFalse(T.NewObject("(new bound())"), T.NewObject("Number"));
|
||||
}
|
||||
|
||||
|
||||
TEST(UnopNot) {
|
||||
FunctionTester T("(function(a) { return !a; })");
|
||||
|
||||
T.CheckCall(T.true_value(), T.false_value(), T.undefined());
|
||||
T.CheckCall(T.false_value(), T.true_value(), T.undefined());
|
||||
T.CheckCall(T.true_value(), T.Val(0.0), T.undefined());
|
||||
T.CheckCall(T.false_value(), T.Val(123), T.undefined());
|
||||
T.CheckCall(T.false_value(), T.Val("x"), T.undefined());
|
||||
T.CheckCall(T.true_value(), T.undefined(), T.undefined());
|
||||
T.CheckCall(T.true_value(), T.nan(), T.undefined());
|
||||
}
|
||||
|
||||
|
||||
TEST(UnopCountPost) {
|
||||
FunctionTester T("(function(a) { return a++; })");
|
||||
|
||||
T.CheckCall(T.Val(0.0), T.Val(0.0), T.undefined());
|
||||
T.CheckCall(T.Val(2.3), T.Val(2.3), T.undefined());
|
||||
T.CheckCall(T.Val(123), T.Val(123), T.undefined());
|
||||
T.CheckCall(T.Val(7), T.Val("7"), T.undefined());
|
||||
T.CheckCall(T.nan(), T.Val("x"), T.undefined());
|
||||
T.CheckCall(T.nan(), T.undefined(), T.undefined());
|
||||
T.CheckCall(T.Val(1.0), T.true_value(), T.undefined());
|
||||
T.CheckCall(T.Val(0.0), T.false_value(), T.undefined());
|
||||
T.CheckCall(T.nan(), T.nan(), T.undefined());
|
||||
}
|
||||
|
||||
|
||||
TEST(UnopCountPre) {
|
||||
FunctionTester T("(function(a) { return ++a; })");
|
||||
|
||||
T.CheckCall(T.Val(1.0), T.Val(0.0), T.undefined());
|
||||
T.CheckCall(T.Val(3.3), T.Val(2.3), T.undefined());
|
||||
T.CheckCall(T.Val(124), T.Val(123), T.undefined());
|
||||
T.CheckCall(T.Val(8), T.Val("7"), T.undefined());
|
||||
T.CheckCall(T.nan(), T.Val("x"), T.undefined());
|
||||
T.CheckCall(T.nan(), T.undefined(), T.undefined());
|
||||
T.CheckCall(T.Val(2.0), T.true_value(), T.undefined());
|
||||
T.CheckCall(T.Val(1.0), T.false_value(), T.undefined());
|
||||
T.CheckCall(T.nan(), T.nan(), T.undefined());
|
||||
}
|
||||
|
||||
|
||||
TEST(PropertyNamedLoad) {
|
||||
FunctionTester T("(function(a,b) { return a.x; })");
|
||||
|
||||
T.CheckCall(T.Val(23), T.NewObject("({x:23})"), T.undefined());
|
||||
T.CheckCall(T.undefined(), T.NewObject("({y:23})"), T.undefined());
|
||||
}
|
||||
|
||||
|
||||
TEST(PropertyKeyedLoad) {
|
||||
FunctionTester T("(function(a,b) { return a[b]; })");
|
||||
|
||||
T.CheckCall(T.Val(23), T.NewObject("({x:23})"), T.Val("x"));
|
||||
T.CheckCall(T.Val(42), T.NewObject("([23,42,65])"), T.Val(1));
|
||||
T.CheckCall(T.undefined(), T.NewObject("({x:23})"), T.Val("y"));
|
||||
T.CheckCall(T.undefined(), T.NewObject("([23,42,65])"), T.Val(4));
|
||||
}
|
||||
|
||||
|
||||
TEST(PropertyNamedStore) {
|
||||
FunctionTester T("(function(a) { a.x = 7; return a.x; })");
|
||||
|
||||
T.CheckCall(T.Val(7), T.NewObject("({})"), T.undefined());
|
||||
T.CheckCall(T.Val(7), T.NewObject("({x:23})"), T.undefined());
|
||||
}
|
||||
|
||||
|
||||
TEST(PropertyKeyedStore) {
|
||||
FunctionTester T("(function(a,b) { a[b] = 7; return a.x; })");
|
||||
|
||||
T.CheckCall(T.Val(7), T.NewObject("({})"), T.Val("x"));
|
||||
T.CheckCall(T.Val(7), T.NewObject("({x:23})"), T.Val("x"));
|
||||
T.CheckCall(T.Val(9), T.NewObject("({x:9})"), T.Val("y"));
|
||||
}
|
||||
|
||||
|
||||
TEST(PropertyNamedDelete) {
|
||||
FunctionTester T("(function(a) { return delete a.x; })");
|
||||
|
||||
CompileRun("var o = Object.create({}, { x: { value:23 } });");
|
||||
T.CheckTrue(T.NewObject("({x:42})"), T.undefined());
|
||||
T.CheckTrue(T.NewObject("({})"), T.undefined());
|
||||
T.CheckFalse(T.NewObject("(o)"), T.undefined());
|
||||
}
|
||||
|
||||
|
||||
TEST(PropertyKeyedDelete) {
|
||||
FunctionTester T("(function(a, b) { return delete a[b]; })");
|
||||
|
||||
CompileRun("function getX() { return 'x'; }");
|
||||
CompileRun("var o = Object.create({}, { x: { value:23 } });");
|
||||
T.CheckTrue(T.NewObject("({x:42})"), T.Val("x"));
|
||||
T.CheckFalse(T.NewObject("(o)"), T.Val("x"));
|
||||
T.CheckFalse(T.NewObject("(o)"), T.NewObject("({toString:getX})"));
|
||||
}
|
||||
|
||||
|
||||
TEST(GlobalLoad) {
|
||||
FunctionTester T("(function() { return g; })");
|
||||
|
||||
T.CheckThrows(T.undefined(), T.undefined());
|
||||
CompileRun("var g = 23;");
|
||||
T.CheckCall(T.Val(23));
|
||||
}
|
||||
|
||||
|
||||
TEST(GlobalStoreSloppy) {
|
||||
FunctionTester T("(function(a,b) { g = a + b; return g; })");
|
||||
|
||||
T.CheckCall(T.Val(33), T.Val(22), T.Val(11));
|
||||
CompileRun("delete g");
|
||||
CompileRun("const g = 23");
|
||||
T.CheckCall(T.Val(23), T.Val(55), T.Val(44));
|
||||
}
|
||||
|
||||
|
||||
TEST(GlobalStoreStrict) {
|
||||
FunctionTester T("(function(a,b) { 'use strict'; g = a + b; return g; })");
|
||||
|
||||
T.CheckThrows(T.Val(22), T.Val(11));
|
||||
CompileRun("var g = 'a global variable';");
|
||||
T.CheckCall(T.Val(33), T.Val(22), T.Val(11));
|
||||
}
|
||||
|
||||
|
||||
TEST(ContextLoad) {
|
||||
FunctionTester T("(function(a,b) { (function(){a}); return a + b; })");
|
||||
|
||||
T.CheckCall(T.Val(65), T.Val(23), T.Val(42));
|
||||
T.CheckCall(T.Val("ab"), T.Val("a"), T.Val("b"));
|
||||
}
|
||||
|
||||
|
||||
TEST(ContextStore) {
|
||||
FunctionTester T("(function(a,b) { (function(){x}); var x = a; return x; })");
|
||||
|
||||
T.CheckCall(T.Val(23), T.Val(23), T.undefined());
|
||||
T.CheckCall(T.Val("a"), T.Val("a"), T.undefined());
|
||||
}
|
||||
|
||||
|
||||
TEST(LookupLoad) {
|
||||
FunctionTester T("(function(a,b) { with(a) { return x + b; } })");
|
||||
|
||||
T.CheckCall(T.Val(24), T.NewObject("({x:23})"), T.Val(1));
|
||||
T.CheckCall(T.Val(32), T.NewObject("({x:23, b:9})"), T.Val(2));
|
||||
T.CheckCall(T.Val(45), T.NewObject("({__proto__:{x:42}})"), T.Val(3));
|
||||
T.CheckCall(T.Val(69), T.NewObject("({get x() { return 65; }})"), T.Val(4));
|
||||
}
|
||||
|
||||
|
||||
TEST(LookupStore) {
|
||||
FunctionTester T("(function(a,b) { var x; with(a) { x = b; } return x; })");
|
||||
|
||||
T.CheckCall(T.undefined(), T.NewObject("({x:23})"), T.Val(1));
|
||||
T.CheckCall(T.Val(2), T.NewObject("({y:23})"), T.Val(2));
|
||||
T.CheckCall(T.Val(23), T.NewObject("({b:23})"), T.Val(3));
|
||||
T.CheckCall(T.undefined(), T.NewObject("({__proto__:{x:42}})"), T.Val(4));
|
||||
}
|
||||
|
||||
|
||||
TEST(BlockLoadStore) {
|
||||
FLAG_harmony_scoping = true;
|
||||
FunctionTester T("(function(a) { 'use strict'; { let x = a+a; return x; }})");
|
||||
|
||||
T.CheckCall(T.Val(46), T.Val(23));
|
||||
T.CheckCall(T.Val("aa"), T.Val("a"));
|
||||
}
|
||||
|
||||
|
||||
TEST(BlockLoadStoreNested) {
|
||||
FLAG_harmony_scoping = true;
|
||||
const char* src =
|
||||
"(function(a,b) {"
|
||||
"'use strict';"
|
||||
"{ let x = a, y = a;"
|
||||
" { let y = b;"
|
||||
" return x + y;"
|
||||
" }"
|
||||
"}})";
|
||||
FunctionTester T(src);
|
||||
|
||||
T.CheckCall(T.Val(65), T.Val(23), T.Val(42));
|
||||
T.CheckCall(T.Val("ab"), T.Val("a"), T.Val("b"));
|
||||
}
|
||||
|
||||
|
||||
TEST(ObjectLiteralComputed) {
|
||||
FunctionTester T("(function(a,b) { o = { x:a+b }; return o.x; })");
|
||||
|
||||
T.CheckCall(T.Val(65), T.Val(23), T.Val(42));
|
||||
T.CheckCall(T.Val("ab"), T.Val("a"), T.Val("b"));
|
||||
}
|
||||
|
||||
|
||||
TEST(ObjectLiteralNonString) {
|
||||
FunctionTester T("(function(a,b) { o = { 7:a+b }; return o[7]; })");
|
||||
|
||||
T.CheckCall(T.Val(65), T.Val(23), T.Val(42));
|
||||
T.CheckCall(T.Val("ab"), T.Val("a"), T.Val("b"));
|
||||
}
|
||||
|
||||
|
||||
TEST(ObjectLiteralPrototype) {
|
||||
FunctionTester T("(function(a) { o = { __proto__:a }; return o.x; })");
|
||||
|
||||
T.CheckCall(T.Val(23), T.NewObject("({x:23})"), T.undefined());
|
||||
T.CheckCall(T.undefined(), T.NewObject("({y:42})"), T.undefined());
|
||||
}
|
||||
|
||||
|
||||
TEST(ObjectLiteralGetter) {
|
||||
FunctionTester T("(function(a) { o = { get x() {return a} }; return o.x; })");
|
||||
|
||||
T.CheckCall(T.Val(23), T.Val(23), T.undefined());
|
||||
T.CheckCall(T.Val("x"), T.Val("x"), T.undefined());
|
||||
}
|
||||
|
||||
|
||||
TEST(ArrayLiteral) {
|
||||
FunctionTester T("(function(a,b) { o = [1, a + b, 3]; return o[1]; })");
|
||||
|
||||
T.CheckCall(T.Val(65), T.Val(23), T.Val(42));
|
||||
T.CheckCall(T.Val("ab"), T.Val("a"), T.Val("b"));
|
||||
}
|
||||
|
||||
|
||||
TEST(RegExpLiteral) {
|
||||
FunctionTester T("(function(a) { o = /b/; return o.test(a); })");
|
||||
|
||||
T.CheckTrue(T.Val("abc"));
|
||||
T.CheckFalse(T.Val("xyz"));
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,121 +0,0 @@
|
||||
// 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 "src/v8.h"
|
||||
|
||||
#include "test/cctest/compiler/function-tester.h"
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
|
||||
static const char* throws = NULL;
|
||||
|
||||
static const char* load_tests[] = {
|
||||
"var x = a; r = x", "123", "0",
|
||||
"var x = (r = x)", "undefined", "undefined",
|
||||
"var x = (a?1:2); r = x", "1", "2",
|
||||
"const x = a; r = x", "123", "0",
|
||||
"const x = (r = x)", "undefined", "undefined",
|
||||
"const x = (a?3:4); r = x", "3", "4",
|
||||
"'use strict'; const x = a; r = x", "123", "0",
|
||||
"'use strict'; const x = (r = x)", throws, throws,
|
||||
"'use strict'; const x = (a?5:6); r = x", "5", "6",
|
||||
"'use strict'; let x = a; r = x", "123", "0",
|
||||
"'use strict'; let x = (r = x)", throws, throws,
|
||||
"'use strict'; let x = (a?7:8); r = x", "7", "8",
|
||||
NULL};
|
||||
|
||||
static const char* store_tests[] = {
|
||||
"var x = 1; x = a; r = x", "123", "0",
|
||||
"var x = (a?(x=4,2):3); r = x", "2", "3",
|
||||
"var x = (a?4:5); x = a; r = x", "123", "0",
|
||||
"const x = 1; x = a; r = x", "1", "1",
|
||||
"const x = (a?(x=4,2):3); r = x", "2", "3",
|
||||
"const x = (a?4:5); x = a; r = x", "4", "5",
|
||||
// Assignments to 'const' are SyntaxErrors, handled by the parser,
|
||||
// hence we cannot test them here because they are early errors.
|
||||
"'use strict'; let x = 1; x = a; r = x", "123", "0",
|
||||
"'use strict'; let x = (a?(x=4,2):3); r = x", throws, "3",
|
||||
"'use strict'; let x = (a?4:5); x = a; r = x", "123", "0",
|
||||
NULL};
|
||||
|
||||
static const char* bind_tests[] = {
|
||||
"if (a) { const x = a }; r = x;", "123", "undefined",
|
||||
"for (; a > 0; a--) { const x = a }; r = x", "123", "undefined",
|
||||
// Re-initialization of variables other than legacy 'const' is not
|
||||
// possible due to sane variable scoping, hence no tests here.
|
||||
NULL};
|
||||
|
||||
|
||||
static void RunVariableTests(const char* source, const char* tests[]) {
|
||||
FLAG_harmony_scoping = true;
|
||||
EmbeddedVector<char, 512> buffer;
|
||||
|
||||
for (int i = 0; tests[i] != NULL; i += 3) {
|
||||
SNPrintF(buffer, source, tests[i]);
|
||||
PrintF("#%d: %s\n", i / 3, buffer.start());
|
||||
FunctionTester T(buffer.start());
|
||||
|
||||
// Check function with non-falsey parameter.
|
||||
if (tests[i + 1] != throws) {
|
||||
Handle<Object> r = v8::Utils::OpenHandle(*CompileRun(tests[i + 1]));
|
||||
T.CheckCall(r, T.Val(123), T.Val("result"));
|
||||
} else {
|
||||
T.CheckThrows(T.Val(123), T.Val("result"));
|
||||
}
|
||||
|
||||
// Check function with falsey parameter.
|
||||
if (tests[i + 2] != throws) {
|
||||
Handle<Object> r = v8::Utils::OpenHandle(*CompileRun(tests[i + 2]));
|
||||
T.CheckCall(r, T.Val(0.0), T.Val("result"));
|
||||
} else {
|
||||
T.CheckThrows(T.Val(0.0), T.Val("result"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(StackLoadVariables) {
|
||||
const char* source = "(function(a,r) { %s; return r; })";
|
||||
RunVariableTests(source, load_tests);
|
||||
}
|
||||
|
||||
|
||||
TEST(ContextLoadVariables) {
|
||||
const char* source = "(function(a,r) { %s; function f() {x} return r; })";
|
||||
RunVariableTests(source, load_tests);
|
||||
}
|
||||
|
||||
|
||||
TEST(StackStoreVariables) {
|
||||
const char* source = "(function(a,r) { %s; return r; })";
|
||||
RunVariableTests(source, store_tests);
|
||||
}
|
||||
|
||||
|
||||
TEST(ContextStoreVariables) {
|
||||
const char* source = "(function(a,r) { %s; function f() {x} return r; })";
|
||||
RunVariableTests(source, store_tests);
|
||||
}
|
||||
|
||||
|
||||
TEST(StackInitializeVariables) {
|
||||
const char* source = "(function(a,r) { %s; return r; })";
|
||||
RunVariableTests(source, bind_tests);
|
||||
}
|
||||
|
||||
|
||||
TEST(ContextInitializeVariables) {
|
||||
const char* source = "(function(a,r) { %s; function f() {x} return r; })";
|
||||
RunVariableTests(source, bind_tests);
|
||||
}
|
||||
|
||||
|
||||
TEST(SelfReferenceVariable) {
|
||||
FunctionTester T("(function self() { return self; })");
|
||||
|
||||
T.CheckCall(T.function);
|
||||
CompileRun("var self = 'not a function'");
|
||||
T.CheckCall(T.function);
|
||||
}
|
@ -1,159 +0,0 @@
|
||||
// Copyright 2013 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/compiler/common-operator.h"
|
||||
#include "src/compiler/generic-node-inl.h"
|
||||
#include "src/compiler/graph.h"
|
||||
#include "src/compiler/machine-operator.h"
|
||||
#include "src/compiler/node.h"
|
||||
#include "src/compiler/operator.h"
|
||||
#include "src/compiler/schedule.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
|
||||
static SimpleOperator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
|
||||
0, 0, "dummy");
|
||||
|
||||
TEST(TestScheduleAllocation) {
|
||||
HandleAndZoneScope scope;
|
||||
Schedule schedule(scope.main_zone());
|
||||
|
||||
CHECK_NE(NULL, schedule.entry());
|
||||
CHECK_EQ(schedule.entry(), *(schedule.all_blocks().begin()));
|
||||
}
|
||||
|
||||
|
||||
TEST(TestScheduleAddNode) {
|
||||
HandleAndZoneScope scope;
|
||||
Graph graph(scope.main_zone());
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* n1 = graph.NewNode(&dummy_operator);
|
||||
|
||||
Schedule schedule(scope.main_zone());
|
||||
|
||||
BasicBlock* entry = schedule.entry();
|
||||
schedule.AddNode(entry, n0);
|
||||
schedule.AddNode(entry, n1);
|
||||
|
||||
CHECK_EQ(entry, schedule.block(n0));
|
||||
CHECK_EQ(entry, schedule.block(n1));
|
||||
CHECK(schedule.SameBasicBlock(n0, n1));
|
||||
|
||||
Node* n2 = graph.NewNode(&dummy_operator);
|
||||
CHECK_EQ(NULL, schedule.block(n2));
|
||||
}
|
||||
|
||||
|
||||
TEST(TestScheduleAddGoto) {
|
||||
HandleAndZoneScope scope;
|
||||
|
||||
Schedule schedule(scope.main_zone());
|
||||
BasicBlock* entry = schedule.entry();
|
||||
BasicBlock* next = schedule.NewBasicBlock();
|
||||
|
||||
schedule.AddGoto(entry, next);
|
||||
|
||||
CHECK_EQ(0, entry->PredecessorCount());
|
||||
CHECK_EQ(1, entry->SuccessorCount());
|
||||
CHECK_EQ(next, entry->SuccessorAt(0));
|
||||
|
||||
CHECK_EQ(1, next->PredecessorCount());
|
||||
CHECK_EQ(entry, next->PredecessorAt(0));
|
||||
CHECK_EQ(0, next->SuccessorCount());
|
||||
}
|
||||
|
||||
|
||||
TEST(TestScheduleAddBranch) {
|
||||
HandleAndZoneScope scope;
|
||||
Schedule schedule(scope.main_zone());
|
||||
|
||||
BasicBlock* entry = schedule.entry();
|
||||
BasicBlock* tblock = schedule.NewBasicBlock();
|
||||
BasicBlock* fblock = schedule.NewBasicBlock();
|
||||
|
||||
Graph graph(scope.main_zone());
|
||||
CommonOperatorBuilder common(scope.main_zone());
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
Node* b = graph.NewNode(common.Branch(), n0);
|
||||
|
||||
schedule.AddBranch(entry, b, tblock, fblock);
|
||||
|
||||
CHECK_EQ(0, entry->PredecessorCount());
|
||||
CHECK_EQ(2, entry->SuccessorCount());
|
||||
CHECK_EQ(tblock, entry->SuccessorAt(0));
|
||||
CHECK_EQ(fblock, entry->SuccessorAt(1));
|
||||
|
||||
CHECK_EQ(1, tblock->PredecessorCount());
|
||||
CHECK_EQ(entry, tblock->PredecessorAt(0));
|
||||
CHECK_EQ(0, tblock->SuccessorCount());
|
||||
|
||||
CHECK_EQ(1, fblock->PredecessorCount());
|
||||
CHECK_EQ(entry, fblock->PredecessorAt(0));
|
||||
CHECK_EQ(0, fblock->SuccessorCount());
|
||||
}
|
||||
|
||||
|
||||
TEST(TestScheduleAddReturn) {
|
||||
HandleAndZoneScope scope;
|
||||
Schedule schedule(scope.main_zone());
|
||||
Graph graph(scope.main_zone());
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
BasicBlock* entry = schedule.entry();
|
||||
schedule.AddReturn(entry, n0);
|
||||
|
||||
CHECK_EQ(0, entry->PredecessorCount());
|
||||
CHECK_EQ(1, entry->SuccessorCount());
|
||||
CHECK_EQ(schedule.exit(), entry->SuccessorAt(0));
|
||||
}
|
||||
|
||||
|
||||
TEST(TestScheduleAddThrow) {
|
||||
HandleAndZoneScope scope;
|
||||
Schedule schedule(scope.main_zone());
|
||||
Graph graph(scope.main_zone());
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
BasicBlock* entry = schedule.entry();
|
||||
schedule.AddThrow(entry, n0);
|
||||
|
||||
CHECK_EQ(0, entry->PredecessorCount());
|
||||
CHECK_EQ(1, entry->SuccessorCount());
|
||||
CHECK_EQ(schedule.exit(), entry->SuccessorAt(0));
|
||||
}
|
||||
|
||||
|
||||
TEST(TestScheduleAddDeopt) {
|
||||
HandleAndZoneScope scope;
|
||||
Schedule schedule(scope.main_zone());
|
||||
Graph graph(scope.main_zone());
|
||||
Node* n0 = graph.NewNode(&dummy_operator);
|
||||
BasicBlock* entry = schedule.entry();
|
||||
schedule.AddDeoptimize(entry, n0);
|
||||
|
||||
CHECK_EQ(0, entry->PredecessorCount());
|
||||
CHECK_EQ(1, entry->SuccessorCount());
|
||||
CHECK_EQ(schedule.exit(), entry->SuccessorAt(0));
|
||||
}
|
||||
|
||||
|
||||
TEST(BuildMulNodeGraph) {
|
||||
HandleAndZoneScope scope;
|
||||
Schedule schedule(scope.main_zone());
|
||||
Graph graph(scope.main_zone());
|
||||
CommonOperatorBuilder common(scope.main_zone());
|
||||
MachineOperatorBuilder machine(scope.main_zone(), kMachineWord32);
|
||||
|
||||
Node* start = graph.NewNode(common.Start());
|
||||
graph.SetStart(start);
|
||||
Node* param0 = graph.NewNode(common.Parameter(0));
|
||||
Node* param1 = graph.NewNode(common.Parameter(1));
|
||||
|
||||
Node* mul = graph.NewNode(machine.Int32Mul(), param0, param1);
|
||||
Node* ret = graph.NewNode(common.Return(), mul, start);
|
||||
|
||||
USE(ret);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,614 +0,0 @@
|
||||
// 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 <limits>
|
||||
|
||||
#include "src/compiler/control-builders.h"
|
||||
#include "src/compiler/node-properties-inl.h"
|
||||
#include "src/compiler/pipeline.h"
|
||||
#include "src/compiler/simplified-lowering.h"
|
||||
#include "src/compiler/simplified-node-factory.h"
|
||||
#include "src/compiler/typer.h"
|
||||
#include "src/compiler/verifier.h"
|
||||
#include "src/execution.h"
|
||||
#include "src/parser.h"
|
||||
#include "src/rewriter.h"
|
||||
#include "src/scopes.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
#include "test/cctest/compiler/codegen-tester.h"
|
||||
#include "test/cctest/compiler/graph-builder-tester.h"
|
||||
#include "test/cctest/compiler/value-helper.h"
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
|
||||
template <typename ReturnType>
|
||||
class SimplifiedGraphBuilderTester : public GraphBuilderTester<ReturnType> {
|
||||
public:
|
||||
SimplifiedGraphBuilderTester(MachineRepresentation p0 = kMachineLast,
|
||||
MachineRepresentation p1 = kMachineLast,
|
||||
MachineRepresentation p2 = kMachineLast,
|
||||
MachineRepresentation p3 = kMachineLast,
|
||||
MachineRepresentation p4 = kMachineLast)
|
||||
: GraphBuilderTester<ReturnType>(p0, p1, p2, p3, p4) {}
|
||||
|
||||
// Close graph and lower one node.
|
||||
void Lower(Node* node) {
|
||||
this->End();
|
||||
Typer typer(this->zone());
|
||||
CommonOperatorBuilder common(this->zone());
|
||||
SourcePositionTable source_positions(this->graph());
|
||||
JSGraph jsgraph(this->graph(), &common, &typer);
|
||||
SimplifiedLowering lowering(&jsgraph, &source_positions);
|
||||
if (node == NULL) {
|
||||
lowering.LowerAllNodes();
|
||||
} else {
|
||||
lowering.Lower(node);
|
||||
}
|
||||
}
|
||||
|
||||
// Close graph and lower all nodes.
|
||||
void LowerAllNodes() { Lower(NULL); }
|
||||
|
||||
void StoreFloat64(Node* node, double* ptr) {
|
||||
Node* ptr_node = this->PointerConstant(ptr);
|
||||
this->Store(kMachineFloat64, ptr_node, node);
|
||||
}
|
||||
|
||||
Node* LoadInt32(int32_t* ptr) {
|
||||
Node* ptr_node = this->PointerConstant(ptr);
|
||||
return this->Load(kMachineWord32, ptr_node);
|
||||
}
|
||||
|
||||
Node* LoadUint32(uint32_t* ptr) {
|
||||
Node* ptr_node = this->PointerConstant(ptr);
|
||||
return this->Load(kMachineWord32, ptr_node);
|
||||
}
|
||||
|
||||
Node* LoadFloat64(double* ptr) {
|
||||
Node* ptr_node = this->PointerConstant(ptr);
|
||||
return this->Load(kMachineFloat64, ptr_node);
|
||||
}
|
||||
|
||||
Factory* factory() { return this->isolate()->factory(); }
|
||||
Heap* heap() { return this->isolate()->heap(); }
|
||||
};
|
||||
|
||||
|
||||
class SimplifiedGraphBuilderJSTester
|
||||
: public SimplifiedGraphBuilderTester<Object*> {
|
||||
public:
|
||||
SimplifiedGraphBuilderJSTester()
|
||||
: SimplifiedGraphBuilderTester<Object*>(),
|
||||
f_(v8::Utils::OpenHandle(*v8::Handle<v8::Function>::Cast(CompileRun(
|
||||
"(function() { 'use strict'; return 2.7123; })")))),
|
||||
swapped_(false) {
|
||||
set_current_context(HeapConstant(handle(f_->context())));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* CallJS() {
|
||||
if (!swapped_) {
|
||||
Compile();
|
||||
}
|
||||
Handle<Object>* args = NULL;
|
||||
MaybeHandle<Object> result = Execution::Call(
|
||||
isolate(), f_, factory()->undefined_value(), 0, args, false);
|
||||
return T::cast(*result.ToHandleChecked());
|
||||
}
|
||||
|
||||
private:
|
||||
void Compile() {
|
||||
CompilationInfoWithZone info(f_);
|
||||
CHECK(Parser::Parse(&info));
|
||||
StrictMode strict_mode = info.function()->strict_mode();
|
||||
info.SetStrictMode(strict_mode);
|
||||
info.SetOptimizing(BailoutId::None(), Handle<Code>(f_->code()));
|
||||
CHECK(Rewriter::Rewrite(&info));
|
||||
CHECK(Scope::Analyze(&info));
|
||||
CHECK_NE(NULL, info.scope());
|
||||
Pipeline pipeline(&info);
|
||||
Linkage linkage(&info);
|
||||
Handle<Code> code = pipeline.GenerateCodeForMachineGraph(&linkage, graph());
|
||||
CHECK(!code.is_null());
|
||||
f_->ReplaceCode(*code);
|
||||
swapped_ = true;
|
||||
}
|
||||
|
||||
Handle<JSFunction> f_;
|
||||
bool swapped_;
|
||||
};
|
||||
|
||||
|
||||
TEST(RunChangeTaggedToInt32) {
|
||||
SimplifiedGraphBuilderTester<int32_t> t(kMachineTagged);
|
||||
Node* x = t.ChangeTaggedToInt32(t.Parameter(0));
|
||||
t.Return(x);
|
||||
|
||||
t.Lower(x);
|
||||
|
||||
// TODO(titzer): remove me.
|
||||
return;
|
||||
|
||||
FOR_INT32_INPUTS(i) {
|
||||
int32_t input = *i;
|
||||
|
||||
if (Smi::IsValid(input)) {
|
||||
int32_t result = t.Call(Smi::FromInt(input));
|
||||
CHECK_EQ(input, result);
|
||||
}
|
||||
|
||||
{
|
||||
Handle<Object> number = t.factory()->NewNumber(input);
|
||||
int32_t result = t.Call(*number);
|
||||
CHECK_EQ(input, result);
|
||||
}
|
||||
|
||||
{
|
||||
Handle<HeapNumber> number = t.factory()->NewHeapNumber(input);
|
||||
int32_t result = t.Call(*number);
|
||||
CHECK_EQ(input, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(RunChangeTaggedToUint32) {
|
||||
SimplifiedGraphBuilderTester<int32_t> t(kMachineTagged);
|
||||
Node* x = t.ChangeTaggedToUint32(t.Parameter(0));
|
||||
t.Return(x);
|
||||
|
||||
t.Lower(x);
|
||||
|
||||
// TODO(titzer): remove me.
|
||||
return;
|
||||
|
||||
FOR_UINT32_INPUTS(i) {
|
||||
uint32_t input = *i;
|
||||
|
||||
if (Smi::IsValid(input)) {
|
||||
int32_t result = t.Call(Smi::FromInt(input));
|
||||
CHECK_EQ(static_cast<int32_t>(input), result);
|
||||
}
|
||||
|
||||
{
|
||||
Handle<Object> number = t.factory()->NewNumber(input);
|
||||
int32_t result = t.Call(*number);
|
||||
CHECK_EQ(static_cast<int32_t>(input), result);
|
||||
}
|
||||
|
||||
{
|
||||
Handle<HeapNumber> number = t.factory()->NewHeapNumber(input);
|
||||
int32_t result = t.Call(*number);
|
||||
CHECK_EQ(static_cast<int32_t>(input), result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(RunChangeTaggedToFloat64) {
|
||||
SimplifiedGraphBuilderTester<int32_t> t(kMachineTagged);
|
||||
double result;
|
||||
Node* x = t.ChangeTaggedToFloat64(t.Parameter(0));
|
||||
t.StoreFloat64(x, &result);
|
||||
t.Return(t.Int32Constant(0));
|
||||
|
||||
t.Lower(x);
|
||||
|
||||
// TODO(titzer): remove me.
|
||||
return;
|
||||
|
||||
{
|
||||
FOR_INT32_INPUTS(i) {
|
||||
int32_t input = *i;
|
||||
|
||||
if (Smi::IsValid(input)) {
|
||||
t.Call(Smi::FromInt(input));
|
||||
CHECK_EQ(input, static_cast<int32_t>(result));
|
||||
}
|
||||
|
||||
{
|
||||
Handle<Object> number = t.factory()->NewNumber(input);
|
||||
t.Call(*number);
|
||||
CHECK_EQ(input, static_cast<int32_t>(result));
|
||||
}
|
||||
|
||||
{
|
||||
Handle<HeapNumber> number = t.factory()->NewHeapNumber(input);
|
||||
t.Call(*number);
|
||||
CHECK_EQ(input, static_cast<int32_t>(result));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
FOR_FLOAT64_INPUTS(i) {
|
||||
double input = *i;
|
||||
{
|
||||
Handle<Object> number = t.factory()->NewNumber(input);
|
||||
t.Call(*number);
|
||||
CHECK_EQ(input, result);
|
||||
}
|
||||
|
||||
{
|
||||
Handle<HeapNumber> number = t.factory()->NewHeapNumber(input);
|
||||
t.Call(*number);
|
||||
CHECK_EQ(input, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(RunChangeBoolToBit) {
|
||||
SimplifiedGraphBuilderTester<int32_t> t(kMachineTagged);
|
||||
Node* x = t.ChangeBoolToBit(t.Parameter(0));
|
||||
t.Return(x);
|
||||
|
||||
t.Lower(x);
|
||||
|
||||
if (!Pipeline::SupportedTarget()) return;
|
||||
|
||||
{
|
||||
Object* true_obj = t.heap()->true_value();
|
||||
int32_t result = t.Call(true_obj);
|
||||
CHECK_EQ(1, result);
|
||||
}
|
||||
|
||||
{
|
||||
Object* false_obj = t.heap()->false_value();
|
||||
int32_t result = t.Call(false_obj);
|
||||
CHECK_EQ(0, result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(RunChangeBitToBool) {
|
||||
SimplifiedGraphBuilderTester<Object*> t(kMachineTagged);
|
||||
Node* x = t.ChangeBitToBool(t.Parameter(0));
|
||||
t.Return(x);
|
||||
|
||||
t.Lower(x);
|
||||
|
||||
// TODO(titzer): remove me.
|
||||
return;
|
||||
|
||||
{
|
||||
Object* result = t.Call(1);
|
||||
Object* true_obj = t.heap()->true_value();
|
||||
CHECK_EQ(true_obj, result);
|
||||
}
|
||||
|
||||
{
|
||||
Object* result = t.Call(0);
|
||||
Object* false_obj = t.heap()->false_value();
|
||||
CHECK_EQ(false_obj, result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(RunChangeInt32ToTagged) {
|
||||
SimplifiedGraphBuilderJSTester t;
|
||||
int32_t input;
|
||||
Node* load = t.LoadInt32(&input);
|
||||
Node* x = t.ChangeInt32ToTagged(load);
|
||||
t.Return(x);
|
||||
|
||||
t.Lower(x);
|
||||
|
||||
// TODO(titzer): remove me.
|
||||
return;
|
||||
|
||||
|
||||
{
|
||||
FOR_INT32_INPUTS(i) {
|
||||
input = *i;
|
||||
HeapNumber* result = t.CallJS<HeapNumber>();
|
||||
CHECK_EQ(static_cast<double>(input), result->value());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
FOR_INT32_INPUTS(i) {
|
||||
input = *i;
|
||||
SimulateFullSpace(CcTest::heap()->new_space());
|
||||
HeapNumber* result = t.CallJS<HeapNumber>();
|
||||
CHECK_EQ(static_cast<double>(input), result->value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(RunChangeUint32ToTagged) {
|
||||
SimplifiedGraphBuilderJSTester t;
|
||||
uint32_t input;
|
||||
Node* load = t.LoadUint32(&input);
|
||||
Node* x = t.ChangeUint32ToTagged(load);
|
||||
t.Return(x);
|
||||
|
||||
t.Lower(x);
|
||||
|
||||
// TODO(titzer): remove me.
|
||||
return;
|
||||
|
||||
{
|
||||
FOR_UINT32_INPUTS(i) {
|
||||
input = *i;
|
||||
HeapNumber* result = t.CallJS<HeapNumber>();
|
||||
double expected = static_cast<double>(input);
|
||||
CHECK_EQ(expected, result->value());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
FOR_UINT32_INPUTS(i) {
|
||||
input = *i;
|
||||
SimulateFullSpace(CcTest::heap()->new_space());
|
||||
HeapNumber* result = t.CallJS<HeapNumber>();
|
||||
double expected = static_cast<double>(static_cast<uint32_t>(input));
|
||||
CHECK_EQ(expected, result->value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(RunChangeFloat64ToTagged) {
|
||||
SimplifiedGraphBuilderJSTester t;
|
||||
double input;
|
||||
Node* load = t.LoadFloat64(&input);
|
||||
Node* x = t.ChangeFloat64ToTagged(load);
|
||||
t.Return(x);
|
||||
|
||||
t.Lower(x);
|
||||
|
||||
// TODO(titzer): remove me.
|
||||
return;
|
||||
|
||||
{
|
||||
FOR_FLOAT64_INPUTS(i) {
|
||||
input = *i;
|
||||
HeapNumber* result = t.CallJS<HeapNumber>();
|
||||
CHECK_EQ(input, result->value());
|
||||
}
|
||||
}
|
||||
{
|
||||
FOR_FLOAT64_INPUTS(i) {
|
||||
input = *i;
|
||||
SimulateFullSpace(CcTest::heap()->new_space());
|
||||
HeapNumber* result = t.CallJS<HeapNumber>();
|
||||
CHECK_EQ(input, result->value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO(dcarney): find a home for these functions.
|
||||
namespace {
|
||||
|
||||
FieldAccess ForJSObjectMap() {
|
||||
FieldAccess access = {JSObject::kMapOffset, Handle<Name>(), Type::Any(),
|
||||
kMachineTagged};
|
||||
return access;
|
||||
}
|
||||
|
||||
|
||||
FieldAccess ForJSObjectProperties() {
|
||||
FieldAccess access = {JSObject::kPropertiesOffset, Handle<Name>(),
|
||||
Type::Any(), kMachineTagged};
|
||||
return access;
|
||||
}
|
||||
|
||||
|
||||
FieldAccess ForArrayBufferBackingStore() {
|
||||
FieldAccess access = {
|
||||
JSArrayBuffer::kBackingStoreOffset, Handle<Name>(), Type::UntaggedPtr(),
|
||||
MachineOperatorBuilder::pointer_rep(),
|
||||
};
|
||||
return access;
|
||||
}
|
||||
|
||||
|
||||
ElementAccess ForFixedArrayElement() {
|
||||
ElementAccess access = {FixedArray::kHeaderSize, Type::Any(), kMachineTagged};
|
||||
return access;
|
||||
}
|
||||
|
||||
|
||||
ElementAccess ForBackingStoreElement(MachineRepresentation rep) {
|
||||
ElementAccess access = {kNonHeapObjectHeaderSize, Type::Any(), rep};
|
||||
return access;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Create a simple JSObject with a unique map.
|
||||
static Handle<JSObject> TestObject() {
|
||||
static int index = 0;
|
||||
char buffer[50];
|
||||
v8::base::OS::SNPrintF(buffer, 50, "({'a_%d':1})", index++);
|
||||
return Handle<JSObject>::cast(v8::Utils::OpenHandle(*CompileRun(buffer)));
|
||||
}
|
||||
|
||||
|
||||
TEST(RunLoadMap) {
|
||||
SimplifiedGraphBuilderTester<Object*> t(kMachineTagged);
|
||||
FieldAccess access = ForJSObjectMap();
|
||||
Node* load = t.LoadField(access, t.Parameter(0));
|
||||
t.Return(load);
|
||||
|
||||
t.LowerAllNodes();
|
||||
|
||||
if (!Pipeline::SupportedTarget()) return;
|
||||
|
||||
Handle<JSObject> src = TestObject();
|
||||
Handle<Map> src_map(src->map());
|
||||
Object* result = t.Call(*src);
|
||||
CHECK_EQ(*src_map, result);
|
||||
}
|
||||
|
||||
|
||||
TEST(RunStoreMap) {
|
||||
SimplifiedGraphBuilderTester<int32_t> t(kMachineTagged, kMachineTagged);
|
||||
FieldAccess access = ForJSObjectMap();
|
||||
t.StoreField(access, t.Parameter(1), t.Parameter(0));
|
||||
t.Return(t.Int32Constant(0));
|
||||
|
||||
t.LowerAllNodes();
|
||||
|
||||
if (!Pipeline::SupportedTarget()) return;
|
||||
|
||||
Handle<JSObject> src = TestObject();
|
||||
Handle<Map> src_map(src->map());
|
||||
Handle<JSObject> dst = TestObject();
|
||||
CHECK(src->map() != dst->map());
|
||||
t.Call(*src_map, *dst);
|
||||
CHECK(*src_map == dst->map());
|
||||
}
|
||||
|
||||
|
||||
TEST(RunLoadProperties) {
|
||||
SimplifiedGraphBuilderTester<Object*> t(kMachineTagged);
|
||||
FieldAccess access = ForJSObjectProperties();
|
||||
Node* load = t.LoadField(access, t.Parameter(0));
|
||||
t.Return(load);
|
||||
|
||||
t.LowerAllNodes();
|
||||
|
||||
if (!Pipeline::SupportedTarget()) return;
|
||||
|
||||
Handle<JSObject> src = TestObject();
|
||||
Handle<FixedArray> src_props(src->properties());
|
||||
Object* result = t.Call(*src);
|
||||
CHECK_EQ(*src_props, result);
|
||||
}
|
||||
|
||||
|
||||
TEST(RunLoadStoreMap) {
|
||||
SimplifiedGraphBuilderTester<Object*> t(kMachineTagged, kMachineTagged);
|
||||
FieldAccess access = ForJSObjectMap();
|
||||
Node* load = t.LoadField(access, t.Parameter(0));
|
||||
t.StoreField(access, t.Parameter(1), load);
|
||||
t.Return(load);
|
||||
|
||||
t.LowerAllNodes();
|
||||
|
||||
if (!Pipeline::SupportedTarget()) return;
|
||||
|
||||
Handle<JSObject> src = TestObject();
|
||||
Handle<Map> src_map(src->map());
|
||||
Handle<JSObject> dst = TestObject();
|
||||
CHECK(src->map() != dst->map());
|
||||
Object* result = t.Call(*src, *dst);
|
||||
CHECK(result->IsMap());
|
||||
CHECK_EQ(*src_map, result);
|
||||
CHECK(*src_map == dst->map());
|
||||
}
|
||||
|
||||
|
||||
TEST(RunLoadStoreFixedArrayIndex) {
|
||||
SimplifiedGraphBuilderTester<Object*> t(kMachineTagged);
|
||||
ElementAccess access = ForFixedArrayElement();
|
||||
Node* load = t.LoadElement(access, t.Parameter(0), t.Int32Constant(0));
|
||||
t.StoreElement(access, t.Parameter(0), t.Int32Constant(1), load);
|
||||
t.Return(load);
|
||||
|
||||
t.LowerAllNodes();
|
||||
|
||||
if (!Pipeline::SupportedTarget()) return;
|
||||
|
||||
Handle<FixedArray> array = t.factory()->NewFixedArray(2);
|
||||
Handle<JSObject> src = TestObject();
|
||||
Handle<JSObject> dst = TestObject();
|
||||
array->set(0, *src);
|
||||
array->set(1, *dst);
|
||||
Object* result = t.Call(*array);
|
||||
CHECK_EQ(*src, result);
|
||||
CHECK_EQ(*src, array->get(0));
|
||||
CHECK_EQ(*src, array->get(1));
|
||||
}
|
||||
|
||||
|
||||
TEST(RunLoadStoreArrayBuffer) {
|
||||
SimplifiedGraphBuilderTester<int32_t> t(kMachineTagged);
|
||||
const int index = 12;
|
||||
FieldAccess access = ForArrayBufferBackingStore();
|
||||
Node* backing_store = t.LoadField(access, t.Parameter(0));
|
||||
ElementAccess buffer_access = ForBackingStoreElement(kMachineWord8);
|
||||
Node* load =
|
||||
t.LoadElement(buffer_access, backing_store, t.Int32Constant(index));
|
||||
t.StoreElement(buffer_access, backing_store, t.Int32Constant(index + 1),
|
||||
load);
|
||||
t.Return(load);
|
||||
|
||||
t.LowerAllNodes();
|
||||
|
||||
if (!Pipeline::SupportedTarget()) return;
|
||||
|
||||
Handle<JSArrayBuffer> array = t.factory()->NewJSArrayBuffer();
|
||||
const int array_length = 2 * index;
|
||||
Runtime::SetupArrayBufferAllocatingData(t.isolate(), array, array_length);
|
||||
uint8_t* data = reinterpret_cast<uint8_t*>(array->backing_store());
|
||||
for (int i = 0; i < array_length; i++) {
|
||||
data[i] = i;
|
||||
}
|
||||
int32_t result = t.Call(*array);
|
||||
CHECK_EQ(index, result);
|
||||
for (int i = 0; i < array_length; i++) {
|
||||
uint8_t expected = i;
|
||||
if (i == (index + 1)) expected = result;
|
||||
CHECK_EQ(data[i], expected);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(RunCopyFixedArray) {
|
||||
SimplifiedGraphBuilderTester<int32_t> t(kMachineTagged, kMachineTagged);
|
||||
|
||||
const int kArraySize = 15;
|
||||
Node* one = t.Int32Constant(1);
|
||||
Node* index = t.Int32Constant(0);
|
||||
Node* limit = t.Int32Constant(kArraySize);
|
||||
t.environment()->Push(index);
|
||||
{
|
||||
LoopBuilder loop(&t);
|
||||
loop.BeginLoop();
|
||||
// Loop exit condition.
|
||||
index = t.environment()->Top();
|
||||
Node* condition = t.Int32LessThan(index, limit);
|
||||
loop.BreakUnless(condition);
|
||||
// src[index] = dst[index].
|
||||
index = t.environment()->Pop();
|
||||
ElementAccess access = ForFixedArrayElement();
|
||||
Node* src = t.Parameter(0);
|
||||
Node* load = t.LoadElement(access, src, index);
|
||||
Node* dst = t.Parameter(1);
|
||||
t.StoreElement(access, dst, index, load);
|
||||
// index++
|
||||
index = t.Int32Add(index, one);
|
||||
t.environment()->Push(index);
|
||||
// continue.
|
||||
loop.EndBody();
|
||||
loop.EndLoop();
|
||||
}
|
||||
index = t.environment()->Pop();
|
||||
t.Return(index);
|
||||
|
||||
t.LowerAllNodes();
|
||||
|
||||
if (!Pipeline::SupportedTarget()) return;
|
||||
|
||||
Handle<FixedArray> src = t.factory()->NewFixedArray(kArraySize);
|
||||
Handle<FixedArray> src_copy = t.factory()->NewFixedArray(kArraySize);
|
||||
Handle<FixedArray> dst = t.factory()->NewFixedArray(kArraySize);
|
||||
for (int i = 0; i < kArraySize; i++) {
|
||||
src->set(i, *TestObject());
|
||||
src_copy->set(i, src->get(i));
|
||||
dst->set(i, *TestObject());
|
||||
CHECK_NE(src_copy->get(i), dst->get(i));
|
||||
}
|
||||
CHECK_EQ(kArraySize, t.Call(*src, *dst));
|
||||
for (int i = 0; i < kArraySize; i++) {
|
||||
CHECK_EQ(src_copy->get(i), dst->get(i));
|
||||
}
|
||||
}
|
@ -1,666 +0,0 @@
|
||||
// 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 <string>
|
||||
|
||||
#include "src/v8.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
|
||||
#include "src/base/utils/random-number-generator.h"
|
||||
#include "test/cctest/compiler/codegen-tester.h"
|
||||
|
||||
#if V8_TURBOFAN_TARGET
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
|
||||
typedef StructuredMachineAssembler::IfBuilder IfBuilder;
|
||||
typedef StructuredMachineAssembler::LoopBuilder Loop;
|
||||
|
||||
static const int32_t kUninitializedVariableOffset = -1;
|
||||
static const int32_t kUninitializedOutput = -1;
|
||||
static const int32_t kVerifiedOutput = -2;
|
||||
|
||||
static const int32_t kInitalVar = 1013;
|
||||
static const int32_t kConjunctionInc = 1069;
|
||||
static const int32_t kDisjunctionInc = 1151;
|
||||
static const int32_t kThenInc = 1223;
|
||||
static const int32_t kElseInc = 1291;
|
||||
static const int32_t kIfInc = 1373;
|
||||
|
||||
class IfBuilderModel {
|
||||
public:
|
||||
explicit IfBuilderModel(Zone* zone)
|
||||
: zone_(zone),
|
||||
variable_offset_(0),
|
||||
root_(new (zone_) Node(NULL)),
|
||||
current_node_(root_),
|
||||
current_expression_(NULL) {}
|
||||
|
||||
void If() {
|
||||
if (current_node_->else_node != NULL) {
|
||||
current_node_ = current_node_->else_node;
|
||||
} else if (current_node_->then_node != NULL) {
|
||||
current_node_ = current_node_->then_node;
|
||||
}
|
||||
ASSERT(current_expression_ == NULL);
|
||||
current_expression_ = new (zone_) Expression(zone_, NULL);
|
||||
current_node_->condition = current_expression_;
|
||||
}
|
||||
void IfNode() { LastChild()->variable_offset = variable_offset_++; }
|
||||
|
||||
void OpenParen() { current_expression_ = LastChild(); }
|
||||
void CloseParen() { current_expression_ = current_expression_->parent; }
|
||||
|
||||
void And() { NewChild()->conjunction = true; }
|
||||
void Or() { NewChild()->disjunction = true; }
|
||||
|
||||
void Then() {
|
||||
ASSERT(current_expression_ == NULL || current_expression_->parent == NULL);
|
||||
current_expression_ = NULL;
|
||||
ASSERT(current_node_->then_node == NULL);
|
||||
current_node_->then_node = new (zone_) Node(current_node_);
|
||||
}
|
||||
void Else() {
|
||||
ASSERT(current_expression_ == NULL || current_expression_->parent == NULL);
|
||||
current_expression_ = NULL;
|
||||
ASSERT(current_node_->else_node == NULL);
|
||||
current_node_->else_node = new (zone_) Node(current_node_);
|
||||
}
|
||||
void Return() {
|
||||
if (current_node_->else_node != NULL) {
|
||||
current_node_->else_node->returns = true;
|
||||
} else if (current_node_->then_node != NULL) {
|
||||
current_node_->then_node->returns = true;
|
||||
} else {
|
||||
CHECK(false);
|
||||
}
|
||||
}
|
||||
void End() {}
|
||||
|
||||
void Print(std::vector<char>* v) { PrintRecursive(v, root_); }
|
||||
|
||||
struct VerificationState {
|
||||
int32_t* inputs;
|
||||
int32_t* outputs;
|
||||
int32_t var;
|
||||
};
|
||||
|
||||
int32_t Verify(int length, int32_t* inputs, int32_t* outputs) {
|
||||
CHECK_EQ(variable_offset_, length);
|
||||
// Input/Output verification.
|
||||
for (int i = 0; i < length; ++i) {
|
||||
CHECK(inputs[i] == 0 || inputs[i] == 1);
|
||||
CHECK(outputs[i] == kUninitializedOutput || outputs[i] >= 0);
|
||||
}
|
||||
// Do verification.
|
||||
VerificationState state;
|
||||
state.inputs = inputs;
|
||||
state.outputs = outputs;
|
||||
state.var = kInitalVar;
|
||||
VerifyRecursive(root_, &state);
|
||||
// Verify all outputs marked.
|
||||
for (int i = 0; i < length; ++i) {
|
||||
CHECK(outputs[i] == kUninitializedOutput ||
|
||||
outputs[i] == kVerifiedOutput);
|
||||
}
|
||||
return state.var;
|
||||
}
|
||||
|
||||
private:
|
||||
struct Expression;
|
||||
typedef std::vector<Expression*, zone_allocator<Expression*> > Expressions;
|
||||
|
||||
struct Expression : public ZoneObject {
|
||||
Expression(Zone* zone, Expression* p)
|
||||
: variable_offset(kUninitializedVariableOffset),
|
||||
disjunction(false),
|
||||
conjunction(false),
|
||||
parent(p),
|
||||
children(Expressions::allocator_type(zone)) {}
|
||||
int variable_offset;
|
||||
bool disjunction;
|
||||
bool conjunction;
|
||||
Expression* parent;
|
||||
Expressions children;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(Expression);
|
||||
};
|
||||
|
||||
struct Node : public ZoneObject {
|
||||
explicit Node(Node* p)
|
||||
: parent(p),
|
||||
condition(NULL),
|
||||
then_node(NULL),
|
||||
else_node(NULL),
|
||||
returns(false) {}
|
||||
Node* parent;
|
||||
Expression* condition;
|
||||
Node* then_node;
|
||||
Node* else_node;
|
||||
bool returns;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(Node);
|
||||
};
|
||||
|
||||
Expression* LastChild() {
|
||||
if (current_expression_->children.empty()) {
|
||||
current_expression_->children.push_back(
|
||||
new (zone_) Expression(zone_, current_expression_));
|
||||
}
|
||||
return current_expression_->children.back();
|
||||
}
|
||||
|
||||
Expression* NewChild() {
|
||||
Expression* child = new (zone_) Expression(zone_, current_expression_);
|
||||
current_expression_->children.push_back(child);
|
||||
return child;
|
||||
}
|
||||
|
||||
static void PrintRecursive(std::vector<char>* v, Expression* expression) {
|
||||
CHECK(expression != NULL);
|
||||
if (expression->conjunction) {
|
||||
ASSERT(!expression->disjunction);
|
||||
v->push_back('&');
|
||||
} else if (expression->disjunction) {
|
||||
v->push_back('|');
|
||||
}
|
||||
if (expression->variable_offset != kUninitializedVariableOffset) {
|
||||
v->push_back('v');
|
||||
}
|
||||
Expressions& children = expression->children;
|
||||
if (children.empty()) return;
|
||||
v->push_back('(');
|
||||
for (Expressions::iterator i = children.begin(); i != children.end(); ++i) {
|
||||
PrintRecursive(v, *i);
|
||||
}
|
||||
v->push_back(')');
|
||||
}
|
||||
|
||||
static void PrintRecursive(std::vector<char>* v, Node* node) {
|
||||
// Termination condition.
|
||||
if (node->condition == NULL) {
|
||||
CHECK(node->then_node == NULL && node->else_node == NULL);
|
||||
if (node->returns) v->push_back('r');
|
||||
return;
|
||||
}
|
||||
CHECK(!node->returns);
|
||||
v->push_back('i');
|
||||
PrintRecursive(v, node->condition);
|
||||
if (node->then_node != NULL) {
|
||||
v->push_back('t');
|
||||
PrintRecursive(v, node->then_node);
|
||||
}
|
||||
if (node->else_node != NULL) {
|
||||
v->push_back('e');
|
||||
PrintRecursive(v, node->else_node);
|
||||
}
|
||||
}
|
||||
|
||||
static bool VerifyRecursive(Expression* expression,
|
||||
VerificationState* state) {
|
||||
bool result = false;
|
||||
bool first_iteration = true;
|
||||
Expressions& children = expression->children;
|
||||
CHECK(!children.empty());
|
||||
for (Expressions::iterator i = children.begin(); i != children.end(); ++i) {
|
||||
Expression* child = *i;
|
||||
// Short circuit evaluation,
|
||||
// but mixes of &&s and ||s have weird semantics.
|
||||
if ((child->conjunction && !result) || (child->disjunction && result)) {
|
||||
continue;
|
||||
}
|
||||
if (child->conjunction) state->var += kConjunctionInc;
|
||||
if (child->disjunction) state->var += kDisjunctionInc;
|
||||
bool child_result;
|
||||
if (child->variable_offset != kUninitializedVariableOffset) {
|
||||
// Verify output
|
||||
CHECK_EQ(state->var, state->outputs[child->variable_offset]);
|
||||
state->outputs[child->variable_offset] = kVerifiedOutput; // Mark seen.
|
||||
child_result = state->inputs[child->variable_offset];
|
||||
CHECK(child->children.empty());
|
||||
state->var += kIfInc;
|
||||
} else {
|
||||
child_result = VerifyRecursive(child, state);
|
||||
}
|
||||
if (child->conjunction) {
|
||||
result &= child_result;
|
||||
} else if (child->disjunction) {
|
||||
result |= child_result;
|
||||
} else {
|
||||
CHECK(first_iteration);
|
||||
result = child_result;
|
||||
}
|
||||
first_iteration = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void VerifyRecursive(Node* node, VerificationState* state) {
|
||||
if (node->condition == NULL) return;
|
||||
bool result = VerifyRecursive(node->condition, state);
|
||||
if (result) {
|
||||
if (node->then_node) {
|
||||
state->var += kThenInc;
|
||||
return VerifyRecursive(node->then_node, state);
|
||||
}
|
||||
} else {
|
||||
if (node->else_node) {
|
||||
state->var += kElseInc;
|
||||
return VerifyRecursive(node->else_node, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Zone* zone_;
|
||||
int variable_offset_;
|
||||
Node* root_;
|
||||
Node* current_node_;
|
||||
Expression* current_expression_;
|
||||
DISALLOW_COPY_AND_ASSIGN(IfBuilderModel);
|
||||
};
|
||||
|
||||
|
||||
class IfBuilderGenerator : public StructuredMachineAssemblerTester<int32_t> {
|
||||
public:
|
||||
IfBuilderGenerator()
|
||||
: StructuredMachineAssemblerTester(MachineOperatorBuilder::pointer_rep(),
|
||||
MachineOperatorBuilder::pointer_rep()),
|
||||
var_(NewVariable(Int32Constant(kInitalVar))),
|
||||
c_(this),
|
||||
m_(this->zone()),
|
||||
one_(Int32Constant(1)),
|
||||
offset_(0) {}
|
||||
|
||||
static void GenerateExpression(v8::base::RandomNumberGenerator* rng,
|
||||
std::vector<char>* v, int n_vars) {
|
||||
int depth = 1;
|
||||
v->push_back('(');
|
||||
bool need_if = true;
|
||||
bool populated = false;
|
||||
while (n_vars != 0) {
|
||||
if (need_if) {
|
||||
// can nest a paren or do a variable
|
||||
if (rng->NextBool()) {
|
||||
v->push_back('v');
|
||||
n_vars--;
|
||||
need_if = false;
|
||||
populated = true;
|
||||
} else {
|
||||
v->push_back('(');
|
||||
depth++;
|
||||
populated = false;
|
||||
}
|
||||
} else {
|
||||
// can pop, do && or do ||
|
||||
int options = 3;
|
||||
if (depth == 1 || !populated) {
|
||||
options--;
|
||||
}
|
||||
switch (rng->NextInt(options)) {
|
||||
case 0:
|
||||
v->push_back('&');
|
||||
need_if = true;
|
||||
break;
|
||||
case 1:
|
||||
v->push_back('|');
|
||||
need_if = true;
|
||||
break;
|
||||
case 2:
|
||||
v->push_back(')');
|
||||
depth--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
CHECK(!need_if);
|
||||
while (depth != 0) {
|
||||
v->push_back(')');
|
||||
depth--;
|
||||
}
|
||||
}
|
||||
|
||||
static void GenerateIfThenElse(v8::base::RandomNumberGenerator* rng,
|
||||
std::vector<char>* v, int n_ifs,
|
||||
int max_exp_length) {
|
||||
CHECK_GT(n_ifs, 0);
|
||||
CHECK_GT(max_exp_length, 0);
|
||||
bool have_env = true;
|
||||
bool then_done = false;
|
||||
bool else_done = false;
|
||||
bool first_iteration = true;
|
||||
while (n_ifs != 0) {
|
||||
if (have_env) {
|
||||
int options = 3;
|
||||
if (else_done || first_iteration) { // Don't do else or return
|
||||
options -= 2;
|
||||
first_iteration = false;
|
||||
}
|
||||
switch (rng->NextInt(options)) {
|
||||
case 0:
|
||||
v->push_back('i');
|
||||
n_ifs--;
|
||||
have_env = false;
|
||||
GenerateExpression(rng, v, rng->NextInt(max_exp_length) + 1);
|
||||
break;
|
||||
case 1:
|
||||
v->push_back('r');
|
||||
have_env = false;
|
||||
break;
|
||||
case 2:
|
||||
v->push_back('e');
|
||||
else_done = true;
|
||||
then_done = false;
|
||||
break;
|
||||
default:
|
||||
CHECK(false);
|
||||
}
|
||||
} else { // Can only do then or else
|
||||
int options = 2;
|
||||
if (then_done) options--;
|
||||
switch (rng->NextInt(options)) {
|
||||
case 0:
|
||||
v->push_back('e');
|
||||
else_done = true;
|
||||
then_done = false;
|
||||
break;
|
||||
case 1:
|
||||
v->push_back('t');
|
||||
then_done = true;
|
||||
else_done = false;
|
||||
break;
|
||||
default:
|
||||
CHECK(false);
|
||||
}
|
||||
have_env = true;
|
||||
}
|
||||
}
|
||||
// Last instruction must have been an if, can complete it in several ways.
|
||||
int options = 2;
|
||||
if (then_done && !else_done) options++;
|
||||
switch (rng->NextInt(3)) {
|
||||
case 0:
|
||||
// Do nothing.
|
||||
break;
|
||||
case 1:
|
||||
v->push_back('t');
|
||||
switch (rng->NextInt(3)) {
|
||||
case 0:
|
||||
v->push_back('r');
|
||||
break;
|
||||
case 1:
|
||||
v->push_back('e');
|
||||
break;
|
||||
case 2:
|
||||
v->push_back('e');
|
||||
v->push_back('r');
|
||||
break;
|
||||
default:
|
||||
CHECK(false);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
v->push_back('e');
|
||||
if (rng->NextBool()) v->push_back('r');
|
||||
break;
|
||||
default:
|
||||
CHECK(false);
|
||||
}
|
||||
}
|
||||
|
||||
std::string::const_iterator ParseExpression(std::string::const_iterator it,
|
||||
std::string::const_iterator end) {
|
||||
// Prepare for expression.
|
||||
m_.If();
|
||||
c_.If();
|
||||
int depth = 0;
|
||||
for (; it != end; ++it) {
|
||||
switch (*it) {
|
||||
case 'v':
|
||||
m_.IfNode();
|
||||
{
|
||||
Node* offset = Int32Constant(offset_ * 4);
|
||||
Store(kMachineWord32, Parameter(1), offset, var_.Get());
|
||||
var_.Set(Int32Add(var_.Get(), Int32Constant(kIfInc)));
|
||||
c_.If(Load(kMachineWord32, Parameter(0), offset));
|
||||
offset_++;
|
||||
}
|
||||
break;
|
||||
case '&':
|
||||
m_.And();
|
||||
c_.And();
|
||||
var_.Set(Int32Add(var_.Get(), Int32Constant(kConjunctionInc)));
|
||||
break;
|
||||
case '|':
|
||||
m_.Or();
|
||||
c_.Or();
|
||||
var_.Set(Int32Add(var_.Get(), Int32Constant(kDisjunctionInc)));
|
||||
break;
|
||||
case '(':
|
||||
if (depth != 0) {
|
||||
m_.OpenParen();
|
||||
c_.OpenParen();
|
||||
}
|
||||
depth++;
|
||||
break;
|
||||
case ')':
|
||||
depth--;
|
||||
if (depth == 0) return it;
|
||||
m_.CloseParen();
|
||||
c_.CloseParen();
|
||||
break;
|
||||
default:
|
||||
CHECK(false);
|
||||
}
|
||||
}
|
||||
CHECK(false);
|
||||
return it;
|
||||
}
|
||||
|
||||
void ParseIfThenElse(const std::string& str) {
|
||||
int n_vars = 0;
|
||||
for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) {
|
||||
if (*it == 'v') n_vars++;
|
||||
}
|
||||
InitializeConstants(n_vars);
|
||||
for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) {
|
||||
switch (*it) {
|
||||
case 'i': {
|
||||
it++;
|
||||
CHECK(it != str.end());
|
||||
CHECK_EQ('(', *it);
|
||||
it = ParseExpression(it, str.end());
|
||||
CHECK_EQ(')', *it);
|
||||
break;
|
||||
}
|
||||
case 't':
|
||||
m_.Then();
|
||||
c_.Then();
|
||||
var_.Set(Int32Add(var_.Get(), Int32Constant(kThenInc)));
|
||||
break;
|
||||
case 'e':
|
||||
m_.Else();
|
||||
c_.Else();
|
||||
var_.Set(Int32Add(var_.Get(), Int32Constant(kElseInc)));
|
||||
break;
|
||||
case 'r':
|
||||
m_.Return();
|
||||
Return(var_.Get());
|
||||
break;
|
||||
default:
|
||||
CHECK(false);
|
||||
}
|
||||
}
|
||||
m_.End();
|
||||
c_.End();
|
||||
Return(var_.Get());
|
||||
// Compare generated model to parsed version.
|
||||
{
|
||||
std::vector<char> v;
|
||||
m_.Print(&v);
|
||||
std::string m_str(v.begin(), v.end());
|
||||
CHECK(m_str == str);
|
||||
}
|
||||
}
|
||||
|
||||
void ParseExpression(const std::string& str) {
|
||||
CHECK(inputs_.is_empty());
|
||||
std::string wrapped = "i(" + str + ")te";
|
||||
ParseIfThenElse(wrapped);
|
||||
}
|
||||
|
||||
void ParseRandomIfThenElse(v8::base::RandomNumberGenerator* rng, int n_ifs,
|
||||
int n_vars) {
|
||||
std::vector<char> v;
|
||||
GenerateIfThenElse(rng, &v, n_ifs, n_vars);
|
||||
std::string str(v.begin(), v.end());
|
||||
ParseIfThenElse(str);
|
||||
}
|
||||
|
||||
void RunRandom(v8::base::RandomNumberGenerator* rng) {
|
||||
// TODO(dcarney): permute inputs via model.
|
||||
// TODO(dcarney): compute test_cases from n_ifs and n_vars.
|
||||
int test_cases = 100;
|
||||
for (int test = 0; test < test_cases; test++) {
|
||||
Initialize();
|
||||
for (int i = 0; i < offset_; i++) {
|
||||
inputs_[i] = rng->NextBool();
|
||||
}
|
||||
DoCall();
|
||||
}
|
||||
}
|
||||
|
||||
void Run(const std::string& str, int32_t expected) {
|
||||
Initialize();
|
||||
int offset = 0;
|
||||
for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) {
|
||||
switch (*it) {
|
||||
case 't':
|
||||
inputs_[offset++] = 1;
|
||||
break;
|
||||
case 'f':
|
||||
inputs_[offset++] = 0;
|
||||
break;
|
||||
default:
|
||||
CHECK(false);
|
||||
}
|
||||
}
|
||||
CHECK_EQ(offset_, offset);
|
||||
// Call.
|
||||
int32_t result = DoCall();
|
||||
CHECK_EQ(result, expected);
|
||||
}
|
||||
|
||||
private:
|
||||
typedef std::vector<int32_t, zone_allocator<int32_t> > IOVector;
|
||||
|
||||
void InitializeConstants(int n_vars) {
|
||||
CHECK(inputs_.is_empty());
|
||||
inputs_.Reset(new int32_t[n_vars]);
|
||||
outputs_.Reset(new int32_t[n_vars]);
|
||||
}
|
||||
|
||||
void Initialize() {
|
||||
for (int i = 0; i < offset_; i++) {
|
||||
inputs_[i] = 0;
|
||||
outputs_[i] = kUninitializedOutput;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t DoCall() {
|
||||
int32_t result = Call(inputs_.get(), outputs_.get());
|
||||
int32_t expected = m_.Verify(offset_, inputs_.get(), outputs_.get());
|
||||
CHECK_EQ(result, expected);
|
||||
return result;
|
||||
}
|
||||
|
||||
const v8::internal::compiler::Variable var_;
|
||||
IfBuilder c_;
|
||||
IfBuilderModel m_;
|
||||
Node* one_;
|
||||
int32_t offset_;
|
||||
SmartArrayPointer<int32_t> inputs_;
|
||||
SmartArrayPointer<int32_t> outputs_;
|
||||
};
|
||||
|
||||
|
||||
TEST(RunExpressionString) {
|
||||
IfBuilderGenerator m;
|
||||
m.ParseExpression("((v|v)|v)");
|
||||
m.Run("ttt", kInitalVar + 1 * kIfInc + kThenInc);
|
||||
m.Run("ftt", kInitalVar + 2 * kIfInc + kDisjunctionInc + kThenInc);
|
||||
m.Run("fft", kInitalVar + 3 * kIfInc + 2 * kDisjunctionInc + kThenInc);
|
||||
m.Run("fff", kInitalVar + 3 * kIfInc + 2 * kDisjunctionInc + kElseInc);
|
||||
}
|
||||
|
||||
|
||||
TEST(RunExpressionStrings) {
|
||||
const char* strings[] = {
|
||||
"v", "(v)", "((v))", "v|v",
|
||||
"(v|v)", "((v|v))", "v&v", "(v&v)",
|
||||
"((v&v))", "v&(v)", "v&(v|v)", "v&(v|v)&v",
|
||||
"v|(v)", "v|(v&v)", "v|(v&v)|v", "v|(((v)|(v&v)|(v)|v)&(v))|v",
|
||||
};
|
||||
v8::base::RandomNumberGenerator rng;
|
||||
for (size_t i = 0; i < ARRAY_SIZE(strings); i++) {
|
||||
IfBuilderGenerator m;
|
||||
m.ParseExpression(strings[i]);
|
||||
m.RunRandom(&rng);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(RunSimpleIfElseTester) {
|
||||
const char* tests[] = {
|
||||
"i(v)", "i(v)t", "i(v)te",
|
||||
"i(v)er", "i(v)ter", "i(v)ti(v)trei(v)ei(v)ei(v)ei(v)ei(v)ei(v)ei(v)e"};
|
||||
v8::base::RandomNumberGenerator rng;
|
||||
for (size_t i = 0; i < ARRAY_SIZE(tests); ++i) {
|
||||
IfBuilderGenerator m;
|
||||
m.ParseIfThenElse(tests[i]);
|
||||
m.RunRandom(&rng);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(RunRandomExpressions) {
|
||||
v8::base::RandomNumberGenerator rng;
|
||||
for (int n_vars = 1; n_vars < 12; n_vars++) {
|
||||
for (int i = 0; i < n_vars * n_vars + 10; i++) {
|
||||
IfBuilderGenerator m;
|
||||
m.ParseRandomIfThenElse(&rng, 1, n_vars);
|
||||
m.RunRandom(&rng);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(RunRandomIfElse) {
|
||||
v8::base::RandomNumberGenerator rng;
|
||||
for (int n_ifs = 1; n_ifs < 12; n_ifs++) {
|
||||
for (int i = 0; i < n_ifs * n_ifs + 10; i++) {
|
||||
IfBuilderGenerator m;
|
||||
m.ParseRandomIfThenElse(&rng, n_ifs, 1);
|
||||
m.RunRandom(&rng);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(RunRandomIfElseExpressions) {
|
||||
v8::base::RandomNumberGenerator rng;
|
||||
for (int n_vars = 2; n_vars < 6; n_vars++) {
|
||||
for (int n_ifs = 2; n_ifs < 7; n_ifs++) {
|
||||
for (int i = 0; i < n_ifs * n_vars + 10; i++) {
|
||||
IfBuilderGenerator m;
|
||||
m.ParseRandomIfThenElse(&rng, n_ifs, n_vars);
|
||||
m.RunRandom(&rng);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -1,122 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#ifndef V8_CCTEST_COMPILER_VALUE_HELPER_H_
|
||||
#define V8_CCTEST_COMPILER_VALUE_HELPER_H_
|
||||
|
||||
#include "src/compiler/common-operator.h"
|
||||
#include "src/compiler/node.h"
|
||||
#include "src/compiler/node-matchers.h"
|
||||
#include "src/isolate.h"
|
||||
#include "src/objects.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
#include "v8.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
// A collection of utilities related to numerical and heap values, including
|
||||
// example input values of various types, including int32_t, uint32_t, double,
|
||||
// etc.
|
||||
class ValueHelper {
|
||||
public:
|
||||
Isolate* isolate_;
|
||||
|
||||
ValueHelper() : isolate_(CcTest::InitIsolateOnce()) {}
|
||||
|
||||
template <typename T>
|
||||
void CheckConstant(T expected, Node* node) {
|
||||
CHECK_EQ(expected, ValueOf<T>(node->op()));
|
||||
}
|
||||
|
||||
void CheckFloat64Constant(double expected, Node* node) {
|
||||
CHECK_EQ(IrOpcode::kFloat64Constant, node->opcode());
|
||||
CHECK_EQ(expected, ValueOf<double>(node->op()));
|
||||
}
|
||||
|
||||
void CheckNumberConstant(double expected, Node* node) {
|
||||
CHECK_EQ(IrOpcode::kNumberConstant, node->opcode());
|
||||
CHECK_EQ(expected, ValueOf<double>(node->op()));
|
||||
}
|
||||
|
||||
void CheckInt32Constant(int32_t expected, Node* node) {
|
||||
CHECK_EQ(IrOpcode::kInt32Constant, node->opcode());
|
||||
CHECK_EQ(expected, ValueOf<int32_t>(node->op()));
|
||||
}
|
||||
|
||||
void CheckUint32Constant(int32_t expected, Node* node) {
|
||||
CHECK_EQ(IrOpcode::kInt32Constant, node->opcode());
|
||||
CHECK_EQ(expected, ValueOf<uint32_t>(node->op()));
|
||||
}
|
||||
|
||||
void CheckHeapConstant(Object* expected, Node* node) {
|
||||
CHECK_EQ(IrOpcode::kHeapConstant, node->opcode());
|
||||
CHECK_EQ(expected, *ValueOf<Handle<Object> >(node->op()));
|
||||
}
|
||||
|
||||
void CheckTrue(Node* node) {
|
||||
CheckHeapConstant(isolate_->heap()->true_value(), node);
|
||||
}
|
||||
|
||||
void CheckFalse(Node* node) {
|
||||
CheckHeapConstant(isolate_->heap()->false_value(), node);
|
||||
}
|
||||
|
||||
static std::vector<double> float64_vector() {
|
||||
static const double nan = v8::base::OS::nan_value();
|
||||
static const double values[] = {
|
||||
0.125, 0.25, 0.375, 0.5,
|
||||
1.25, -1.75, 2, 5.125,
|
||||
6.25, 0.0, -0.0, 982983.25,
|
||||
888, 2147483647.0, -999.75, 3.1e7,
|
||||
-2e66, 3e-88, -2147483648.0, V8_INFINITY,
|
||||
-V8_INFINITY, nan, 2147483647.375, 2147483647.75,
|
||||
2147483648.0, 2147483648.25, 2147483649.25, -2147483647.0,
|
||||
-2147483647.125, -2147483647.875, -2147483648.25, -2147483649.5};
|
||||
return std::vector<double>(&values[0], &values[ARRAY_SIZE(values)]);
|
||||
}
|
||||
|
||||
static const std::vector<int32_t> int32_vector() {
|
||||
std::vector<uint32_t> values = uint32_vector();
|
||||
return std::vector<int32_t>(values.begin(), values.end());
|
||||
}
|
||||
|
||||
static const std::vector<uint32_t> uint32_vector() {
|
||||
static const uint32_t kValues[] = {
|
||||
0x00000000, 0x00000001, 0xffffffff, 0x1b09788b, 0x04c5fce8, 0xcc0de5bf,
|
||||
0x273a798e, 0x187937a3, 0xece3af83, 0x5495a16b, 0x0b668ecc, 0x11223344,
|
||||
0x0000009e, 0x00000043, 0x0000af73, 0x0000116b, 0x00658ecc, 0x002b3b4c,
|
||||
0x88776655, 0x70000000, 0x07200000, 0x7fffffff, 0x56123761, 0x7fffff00,
|
||||
0x761c4761, 0x80000000, 0x88888888, 0xa0000000, 0xdddddddd, 0xe0000000,
|
||||
0xeeeeeeee, 0xfffffffd, 0xf0000000, 0x007fffff, 0x003fffff, 0x001fffff,
|
||||
0x000fffff, 0x0007ffff, 0x0003ffff, 0x0001ffff, 0x0000ffff, 0x00007fff,
|
||||
0x00003fff, 0x00001fff, 0x00000fff, 0x000007ff, 0x000003ff, 0x000001ff};
|
||||
return std::vector<uint32_t>(&kValues[0], &kValues[ARRAY_SIZE(kValues)]);
|
||||
}
|
||||
|
||||
static const std::vector<double> nan_vector(size_t limit = 0) {
|
||||
static const double nan = v8::base::OS::nan_value();
|
||||
static const double values[] = {-nan, -V8_INFINITY * -0.0,
|
||||
-V8_INFINITY * 0.0, V8_INFINITY * -0.0,
|
||||
V8_INFINITY * 0.0, nan};
|
||||
return std::vector<double>(&values[0], &values[ARRAY_SIZE(values)]);
|
||||
}
|
||||
};
|
||||
|
||||
// Helper macros that can be used in FOR_INT32_INPUTS(i) { ... *i ... }
|
||||
// Watch out, these macros aren't hygenic; they pollute your scope. Thanks STL.
|
||||
#define FOR_INPUTS(ctype, itype, var) \
|
||||
std::vector<ctype> var##_vec = ValueHelper::itype##_vector(); \
|
||||
for (std::vector<ctype>::iterator var = var##_vec.begin(); \
|
||||
var != var##_vec.end(); ++var)
|
||||
|
||||
#define FOR_INT32_INPUTS(var) FOR_INPUTS(int32_t, int32, var)
|
||||
#define FOR_UINT32_INPUTS(var) FOR_INPUTS(uint32_t, uint32, var)
|
||||
#define FOR_FLOAT64_INPUTS(var) FOR_INPUTS(double, float64, var)
|
||||
}
|
||||
}
|
||||
} // namespace v8::internal::compiler
|
||||
|
||||
#endif // V8_CCTEST_COMPILER_VALUE_HELPER_H_
|
Loading…
Reference in New Issue
Block a user