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:
mstarzinger@chromium.org 2014-07-30 14:23:52 +00:00
parent 20d6798293
commit 2c328e94f9
43 changed files with 0 additions and 19491 deletions

View File

@ -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_

View File

@ -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

View File

@ -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_

View File

@ -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_

View File

@ -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

View File

@ -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_

View File

@ -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_

View File

@ -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_

View File

@ -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

View File

@ -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_

View File

@ -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

View File

@ -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)));
}

View File

@ -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());
}
}
}

View File

@ -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));
}

View File

@ -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());
}
}
}

View File

@ -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());
}

View File

@ -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));
}
}
}
}
}

View File

@ -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.
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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));
}
}

View File

@ -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());
}

View File

@ -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));
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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));
}

View File

@ -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"));
}

View File

@ -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());
}

View File

@ -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());
}

View File

@ -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());
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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));
}
}

View File

@ -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

View File

@ -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_