v8/test/cctest/compiler/test-run-machops.cc
bmeurer@chromium.org cf51230881 [turbofan] Add proper conversion operators for int32<->int64.
This affects arm64 and x64. Note that we do not yet optimize
these conversions. Later we will add support for merging these
conversion operators into other operations during instruction
selection.

TEST=cctest,compiler-unittests
R=jarin@chromium.org

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23184 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
2014-08-19 08:48:41 +00:00

4249 lines
116 KiB
C++

// 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 <functional>
#include <limits>
#include "src/base/bits.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::base;
#define CHECK_UINT32_EQ(x, y) \
CHECK_EQ(static_cast<int32_t>(x), static_cast<int32_t>(y))
using namespace v8::internal;
using namespace v8::internal::compiler;
typedef RawMachineAssembler::Label MLabel;
TEST(RunInt32Add) {
RawMachineAssemblerTester<int32_t> m;
Node* add = m.Int32Add(m.Int32Constant(0), m.Int32Constant(1));
m.Return(add);
CHECK_EQ(1, m.Call());
}
static Node* Int32Input(RawMachineAssemblerTester<int32_t>* m, int index) {
switch (index) {
case 0:
return m->Parameter(0);
case 1:
return m->Parameter(1);
case 2:
return m->Int32Constant(0);
case 3:
return m->Int32Constant(1);
case 4:
return m->Int32Constant(-1);
case 5:
return m->Int32Constant(0xff);
case 6:
return m->Int32Constant(0x01234567);
case 7:
return m->Load(kMachInt32, m->PointerConstant(NULL));
default:
return NULL;
}
}
TEST(CodeGenInt32Binop) {
RawMachineAssemblerTester<void> m;
Operator* ops[] = {
m.machine()->Word32And(), m.machine()->Word32Or(),
m.machine()->Word32Xor(), m.machine()->Word32Shl(),
m.machine()->Word32Shr(), m.machine()->Word32Sar(),
m.machine()->Word32Equal(), m.machine()->Int32Add(),
m.machine()->Int32Sub(), m.machine()->Int32Mul(),
m.machine()->Int32Div(), m.machine()->Int32UDiv(),
m.machine()->Int32Mod(), m.machine()->Int32UMod(),
m.machine()->Int32LessThan(), m.machine()->Int32LessThanOrEqual(),
m.machine()->Uint32LessThan(), m.machine()->Uint32LessThanOrEqual(),
NULL};
for (int i = 0; ops[i] != NULL; i++) {
for (int j = 0; j < 8; j++) {
for (int k = 0; k < 8; k++) {
RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32);
Node* a = Int32Input(&m, j);
Node* b = Int32Input(&m, k);
m.Return(m.NewNode(ops[i], a, b));
m.GenerateCode();
}
}
}
}
TEST(RunGoto) {
RawMachineAssemblerTester<int32_t> m;
int constant = 99999;
MLabel next;
m.Goto(&next);
m.Bind(&next);
m.Return(m.Int32Constant(constant));
CHECK_EQ(constant, m.Call());
}
TEST(RunGotoMultiple) {
RawMachineAssemblerTester<int32_t> m;
int constant = 9999977;
MLabel labels[10];
for (size_t i = 0; i < ARRAY_SIZE(labels); i++) {
m.Goto(&labels[i]);
m.Bind(&labels[i]);
}
m.Return(m.Int32Constant(constant));
CHECK_EQ(constant, m.Call());
}
TEST(RunBranch) {
RawMachineAssemblerTester<int32_t> m;
int constant = 999777;
MLabel blocka, blockb;
m.Branch(m.Int32Constant(0), &blocka, &blockb);
m.Bind(&blocka);
m.Return(m.Int32Constant(0 - constant));
m.Bind(&blockb);
m.Return(m.Int32Constant(constant));
CHECK_EQ(constant, m.Call());
}
TEST(RunRedundantBranch1) {
RawMachineAssemblerTester<int32_t> m;
int constant = 944777;
MLabel blocka;
m.Branch(m.Int32Constant(0), &blocka, &blocka);
m.Bind(&blocka);
m.Return(m.Int32Constant(constant));
CHECK_EQ(constant, m.Call());
}
TEST(RunRedundantBranch2) {
RawMachineAssemblerTester<int32_t> m;
int constant = 955777;
MLabel blocka, blockb;
m.Branch(m.Int32Constant(0), &blocka, &blocka);
m.Bind(&blockb);
m.Goto(&blocka);
m.Bind(&blocka);
m.Return(m.Int32Constant(constant));
CHECK_EQ(constant, m.Call());
}
TEST(RunRedundantBranch3) {
RawMachineAssemblerTester<int32_t> m;
int constant = 966777;
MLabel blocka, blockb, blockc;
m.Branch(m.Int32Constant(0), &blocka, &blockc);
m.Bind(&blocka);
m.Branch(m.Int32Constant(0), &blockb, &blockb);
m.Bind(&blockc);
m.Goto(&blockb);
m.Bind(&blockb);
m.Return(m.Int32Constant(constant));
CHECK_EQ(constant, m.Call());
}
TEST(RunDiamond2) {
RawMachineAssemblerTester<int32_t> m;
int constant = 995666;
MLabel blocka, blockb, end;
m.Branch(m.Int32Constant(0), &blocka, &blockb);
m.Bind(&blocka);
m.Goto(&end);
m.Bind(&blockb);
m.Goto(&end);
m.Bind(&end);
m.Return(m.Int32Constant(constant));
CHECK_EQ(constant, m.Call());
}
TEST(RunLoop) {
RawMachineAssemblerTester<int32_t> m;
int constant = 999555;
MLabel header, body, exit;
m.Goto(&header);
m.Bind(&header);
m.Branch(m.Int32Constant(0), &body, &exit);
m.Bind(&body);
m.Goto(&header);
m.Bind(&exit);
m.Return(m.Int32Constant(constant));
CHECK_EQ(constant, m.Call());
}
template <typename R>
static void BuildDiamondPhi(RawMachineAssemblerTester<R>* m, Node* cond_node,
Node* true_node, Node* false_node) {
MLabel blocka, blockb;
MLabel* end = m->Exit();
m->Branch(cond_node, &blocka, &blockb);
m->Bind(&blocka);
m->Goto(end);
m->Bind(&blockb);
m->Goto(end);
m->Bind(end);
Node* phi = m->Phi(true_node, false_node);
m->Return(phi);
}
TEST(RunDiamondPhiConst) {
RawMachineAssemblerTester<int32_t> m(kMachInt32);
int false_val = 0xFF666;
int true_val = 0x00DDD;
Node* true_node = m.Int32Constant(true_val);
Node* false_node = m.Int32Constant(false_val);
BuildDiamondPhi(&m, m.Parameter(0), true_node, false_node);
CHECK_EQ(false_val, m.Call(0));
CHECK_EQ(true_val, m.Call(1));
}
TEST(RunDiamondPhiNumber) {
RawMachineAssemblerTester<Object*> m(kMachInt32);
double false_val = -11.1;
double true_val = 200.1;
Node* true_node = m.NumberConstant(true_val);
Node* false_node = m.NumberConstant(false_val);
BuildDiamondPhi(&m, m.Parameter(0), true_node, false_node);
m.CheckNumber(false_val, m.Call(0));
m.CheckNumber(true_val, m.Call(1));
}
TEST(RunDiamondPhiString) {
RawMachineAssemblerTester<Object*> m(kMachInt32);
const char* false_val = "false";
const char* true_val = "true";
Node* true_node = m.StringConstant(true_val);
Node* false_node = m.StringConstant(false_val);
BuildDiamondPhi(&m, m.Parameter(0), true_node, false_node);
m.CheckString(false_val, m.Call(0));
m.CheckString(true_val, m.Call(1));
}
TEST(RunDiamondPhiParam) {
RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32, kMachInt32);
BuildDiamondPhi(&m, m.Parameter(0), m.Parameter(1), m.Parameter(2));
int32_t c1 = 0x260cb75a;
int32_t c2 = 0xcd3e9c8b;
int result = m.Call(0, c1, c2);
CHECK_EQ(c2, result);
result = m.Call(1, c1, c2);
CHECK_EQ(c1, result);
}
TEST(RunLoopPhiConst) {
RawMachineAssemblerTester<int32_t> m;
int true_val = 0x44000;
int false_val = 0x00888;
Node* cond_node = m.Int32Constant(0);
Node* true_node = m.Int32Constant(true_val);
Node* false_node = m.Int32Constant(false_val);
// x = false_val; while(false) { x = true_val; } return x;
MLabel body, header;
MLabel* end = m.Exit();
m.Goto(&header);
m.Bind(&header);
Node* phi = m.Phi(false_node, true_node);
m.Branch(cond_node, &body, end);
m.Bind(&body);
m.Goto(&header);
m.Bind(end);
m.Return(phi);
CHECK_EQ(false_val, m.Call());
}
TEST(RunLoopPhiParam) {
RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32, kMachInt32);
MLabel blocka, blockb;
MLabel* end = m.Exit();
m.Goto(&blocka);
m.Bind(&blocka);
Node* phi = m.Phi(m.Parameter(1), m.Parameter(2));
Node* cond = m.Phi(m.Parameter(0), m.Int32Constant(0));
m.Branch(cond, &blockb, end);
m.Bind(&blockb);
m.Goto(&blocka);
m.Bind(end);
m.Return(phi);
int32_t c1 = 0xa81903b4;
int32_t c2 = 0x5a1207da;
int result = m.Call(0, c1, c2);
CHECK_EQ(c1, result);
result = m.Call(1, c1, c2);
CHECK_EQ(c2, result);
}
TEST(RunLoopPhiInduction) {
RawMachineAssemblerTester<int32_t> m;
int false_val = 0x10777;
// x = false_val; while(false) { x++; } return x;
MLabel header, body;
MLabel* end = m.Exit();
Node* false_node = m.Int32Constant(false_val);
m.Goto(&header);
m.Bind(&header);
Node* phi = m.Phi(false_node, false_node);
m.Branch(m.Int32Constant(0), &body, end);
m.Bind(&body);
Node* add = m.Int32Add(phi, m.Int32Constant(1));
phi->ReplaceInput(1, add);
m.Goto(&header);
m.Bind(end);
m.Return(phi);
CHECK_EQ(false_val, m.Call());
}
TEST(RunLoopIncrement) {
RawMachineAssemblerTester<int32_t> m;
Int32BinopTester bt(&m);
// x = 0; while(x ^ param) { x++; } return x;
MLabel header, body;
MLabel* end = m.Exit();
Node* zero = m.Int32Constant(0);
m.Goto(&header);
m.Bind(&header);
Node* phi = m.Phi(zero, zero);
m.Branch(m.WordXor(phi, bt.param0), &body, end);
m.Bind(&body);
phi->ReplaceInput(1, m.Int32Add(phi, m.Int32Constant(1)));
m.Goto(&header);
m.Bind(end);
bt.AddReturn(phi);
CHECK_EQ(11, bt.call(11, 0));
CHECK_EQ(110, bt.call(110, 0));
CHECK_EQ(176, bt.call(176, 0));
}
TEST(RunLoopIncrement2) {
RawMachineAssemblerTester<int32_t> m;
Int32BinopTester bt(&m);
// x = 0; while(x < param) { x++; } return x;
MLabel header, body;
MLabel* end = m.Exit();
Node* zero = m.Int32Constant(0);
m.Goto(&header);
m.Bind(&header);
Node* phi = m.Phi(zero, zero);
m.Branch(m.Int32LessThan(phi, bt.param0), &body, end);
m.Bind(&body);
phi->ReplaceInput(1, m.Int32Add(phi, m.Int32Constant(1)));
m.Goto(&header);
m.Bind(end);
bt.AddReturn(phi);
CHECK_EQ(11, bt.call(11, 0));
CHECK_EQ(110, bt.call(110, 0));
CHECK_EQ(176, bt.call(176, 0));
CHECK_EQ(0, bt.call(-200, 0));
}
TEST(RunLoopIncrement3) {
RawMachineAssemblerTester<int32_t> m;
Int32BinopTester bt(&m);
// x = 0; while(x < param) { x++; } return x;
MLabel header, body;
MLabel* end = m.Exit();
Node* zero = m.Int32Constant(0);
m.Goto(&header);
m.Bind(&header);
Node* phi = m.Phi(zero, zero);
m.Branch(m.Uint32LessThan(phi, bt.param0), &body, end);
m.Bind(&body);
phi->ReplaceInput(1, m.Int32Add(phi, m.Int32Constant(1)));
m.Goto(&header);
m.Bind(end);
bt.AddReturn(phi);
CHECK_EQ(11, bt.call(11, 0));
CHECK_EQ(110, bt.call(110, 0));
CHECK_EQ(176, bt.call(176, 0));
CHECK_EQ(200, bt.call(200, 0));
}
TEST(RunLoopDecrement) {
RawMachineAssemblerTester<int32_t> m;
Int32BinopTester bt(&m);
// x = param; while(x) { x--; } return x;
MLabel header, body;
MLabel* end = m.Exit();
m.Goto(&header);
m.Bind(&header);
Node* phi = m.Phi(bt.param0, m.Int32Constant(0));
m.Branch(phi, &body, end);
m.Bind(&body);
phi->ReplaceInput(1, m.Int32Sub(phi, m.Int32Constant(1)));
m.Goto(&header);
m.Bind(end);
bt.AddReturn(phi);
CHECK_EQ(0, bt.call(11, 0));
CHECK_EQ(0, bt.call(110, 0));
CHECK_EQ(0, bt.call(197, 0));
}
TEST(RunLoopIncrementFloat64) {
RawMachineAssemblerTester<int32_t> m;
// x = -3.0; while(x < 10) { x = x + 0.5; } return (int) x;
MLabel header, body;
MLabel* end = m.Exit();
Node* minus_3 = m.Float64Constant(-3.0);
Node* ten = m.Float64Constant(10.0);
m.Goto(&header);
m.Bind(&header);
Node* phi = m.Phi(minus_3, ten);
m.Branch(m.Float64LessThan(phi, ten), &body, end);
m.Bind(&body);
phi->ReplaceInput(1, m.Float64Add(phi, m.Float64Constant(0.5)));
m.Goto(&header);
m.Bind(end);
m.Return(m.ChangeFloat64ToInt32(phi));
CHECK_EQ(10, m.Call());
}
TEST(RunLoadInt32) {
RawMachineAssemblerTester<int32_t> m;
int32_t p1 = 0; // loads directly from this location.
m.Return(m.LoadFromPointer(&p1, kMachInt32));
FOR_INT32_INPUTS(i) {
p1 = *i;
CHECK_EQ(p1, m.Call());
}
}
TEST(RunLoadInt32Offset) {
int32_t p1 = 0; // loads directly from this location.
int32_t offsets[] = {-2000000, -100, -101, 1, 3,
7, 120, 2000, 2000000000, 0xff};
for (size_t i = 0; i < ARRAY_SIZE(offsets); i++) {
RawMachineAssemblerTester<int32_t> m;
int32_t offset = offsets[i];
byte* pointer = reinterpret_cast<byte*>(&p1) - offset;
// generate load [#base + #index]
m.Return(m.LoadFromPointer(pointer, kMachInt32, offset));
FOR_INT32_INPUTS(j) {
p1 = *j;
CHECK_EQ(p1, m.Call());
}
}
}
TEST(RunLoadStoreFloat64Offset) {
double p1 = 0; // loads directly from this location.
double p2 = 0; // and stores directly into this location.
FOR_INT32_INPUTS(i) {
int32_t magic = 0x2342aabb + *i * 3;
RawMachineAssemblerTester<int32_t> m;
int32_t offset = *i;
byte* from = reinterpret_cast<byte*>(&p1) - offset;
byte* to = reinterpret_cast<byte*>(&p2) - offset;
// generate load [#base + #index]
Node* load =
m.Load(kMachFloat64, m.PointerConstant(from), m.Int32Constant(offset));
m.Store(kMachFloat64, m.PointerConstant(to), m.Int32Constant(offset), load);
m.Return(m.Int32Constant(magic));
FOR_FLOAT64_INPUTS(j) {
p1 = *j;
p2 = *j - 5;
CHECK_EQ(magic, m.Call());
CHECK_EQ(p1, p2);
}
}
}
TEST(RunInt32AddP) {
RawMachineAssemblerTester<int32_t> m;
Int32BinopTester bt(&m);
bt.AddReturn(m.Int32Add(bt.param0, bt.param1));
FOR_INT32_INPUTS(i) {
FOR_INT32_INPUTS(j) {
// Use uint32_t because signed overflow is UB in C.
int expected = static_cast<int32_t>(*i + *j);
CHECK_EQ(expected, bt.call(*i, *j));
}
}
}
TEST(RunInt32AddAndWord32SarP) {
{
RawMachineAssemblerTester<int32_t> m(kMachUint32, kMachInt32, kMachUint32);
m.Return(m.Int32Add(m.Parameter(0),
m.Word32Sar(m.Parameter(1), m.Parameter(2))));
FOR_UINT32_INPUTS(i) {
FOR_INT32_INPUTS(j) {
FOR_UINT32_SHIFTS(shift) {
// Use uint32_t because signed overflow is UB in C.
int32_t expected = *i + (*j >> shift);
CHECK_EQ(expected, m.Call(*i, *j, shift));
}
}
}
}
{
RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachUint32, kMachUint32);
m.Return(m.Int32Add(m.Word32Sar(m.Parameter(0), m.Parameter(1)),
m.Parameter(2)));
FOR_INT32_INPUTS(i) {
FOR_UINT32_SHIFTS(shift) {
FOR_UINT32_INPUTS(k) {
// Use uint32_t because signed overflow is UB in C.
int32_t expected = (*i >> shift) + *k;
CHECK_EQ(expected, m.Call(*i, shift, *k));
}
}
}
}
}
TEST(RunInt32AddAndWord32ShlP) {
{
RawMachineAssemblerTester<int32_t> m(kMachUint32, kMachInt32, kMachUint32);
m.Return(m.Int32Add(m.Parameter(0),
m.Word32Shl(m.Parameter(1), m.Parameter(2))));
FOR_UINT32_INPUTS(i) {
FOR_INT32_INPUTS(j) {
FOR_UINT32_SHIFTS(shift) {
// Use uint32_t because signed overflow is UB in C.
int32_t expected = *i + (*j << shift);
CHECK_EQ(expected, m.Call(*i, *j, shift));
}
}
}
}
{
RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachUint32, kMachUint32);
m.Return(m.Int32Add(m.Word32Shl(m.Parameter(0), m.Parameter(1)),
m.Parameter(2)));
FOR_INT32_INPUTS(i) {
FOR_UINT32_SHIFTS(shift) {
FOR_UINT32_INPUTS(k) {
// Use uint32_t because signed overflow is UB in C.
int32_t expected = (*i << shift) + *k;
CHECK_EQ(expected, m.Call(*i, shift, *k));
}
}
}
}
}
TEST(RunInt32AddAndWord32ShrP) {
{
RawMachineAssemblerTester<int32_t> m(kMachUint32, kMachUint32, kMachUint32);
m.Return(m.Int32Add(m.Parameter(0),
m.Word32Shr(m.Parameter(1), m.Parameter(2))));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
FOR_UINT32_SHIFTS(shift) {
// Use uint32_t because signed overflow is UB in C.
int32_t expected = *i + (*j >> shift);
CHECK_EQ(expected, m.Call(*i, *j, shift));
}
}
}
}
{
RawMachineAssemblerTester<int32_t> m(kMachUint32, kMachUint32, kMachUint32);
m.Return(m.Int32Add(m.Word32Shr(m.Parameter(0), m.Parameter(1)),
m.Parameter(2)));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_SHIFTS(shift) {
FOR_UINT32_INPUTS(k) {
// Use uint32_t because signed overflow is UB in C.
int32_t expected = (*i >> shift) + *k;
CHECK_EQ(expected, m.Call(*i, shift, *k));
}
}
}
}
}
TEST(RunInt32AddInBranch) {
static const int32_t constant = 987654321;
{
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
MLabel blocka, blockb;
m.Branch(
m.Word32Equal(m.Int32Add(bt.param0, bt.param1), m.Int32Constant(0)),
&blocka, &blockb);
m.Bind(&blocka);
bt.AddReturn(m.Int32Constant(constant));
m.Bind(&blockb);
bt.AddReturn(m.Int32Constant(0 - constant));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
int32_t expected = (*i + *j) == 0 ? constant : 0 - constant;
CHECK_EQ(expected, bt.call(*i, *j));
}
}
}
{
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
MLabel blocka, blockb;
m.Branch(
m.Word32NotEqual(m.Int32Add(bt.param0, bt.param1), m.Int32Constant(0)),
&blocka, &blockb);
m.Bind(&blocka);
bt.AddReturn(m.Int32Constant(constant));
m.Bind(&blockb);
bt.AddReturn(m.Int32Constant(0 - constant));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
int32_t expected = (*i + *j) != 0 ? constant : 0 - constant;
CHECK_EQ(expected, bt.call(*i, *j));
}
}
}
{
FOR_UINT32_INPUTS(i) {
RawMachineAssemblerTester<uint32_t> m(kMachUint32);
MLabel blocka, blockb;
m.Branch(m.Word32Equal(m.Int32Add(m.Int32Constant(*i), m.Parameter(0)),
m.Int32Constant(0)),
&blocka, &blockb);
m.Bind(&blocka);
m.Return(m.Int32Constant(constant));
m.Bind(&blockb);
m.Return(m.Int32Constant(0 - constant));
FOR_UINT32_INPUTS(j) {
uint32_t expected = (*i + *j) == 0 ? constant : 0 - constant;
CHECK_UINT32_EQ(expected, m.Call(*j));
}
}
}
{
FOR_UINT32_INPUTS(i) {
RawMachineAssemblerTester<uint32_t> m(kMachUint32);
MLabel blocka, blockb;
m.Branch(m.Word32NotEqual(m.Int32Add(m.Int32Constant(*i), m.Parameter(0)),
m.Int32Constant(0)),
&blocka, &blockb);
m.Bind(&blocka);
m.Return(m.Int32Constant(constant));
m.Bind(&blockb);
m.Return(m.Int32Constant(0 - constant));
FOR_UINT32_INPUTS(j) {
uint32_t expected = (*i + *j) != 0 ? constant : 0 - constant;
CHECK_UINT32_EQ(expected, m.Call(*j));
}
}
}
{
RawMachineAssemblerTester<void> m;
Operator* shops[] = {m.machine()->Word32Sar(), m.machine()->Word32Shl(),
m.machine()->Word32Shr()};
for (size_t n = 0; n < ARRAY_SIZE(shops); n++) {
RawMachineAssemblerTester<int32_t> m(kMachUint32, kMachInt32,
kMachUint32);
MLabel blocka, blockb;
m.Branch(m.Word32Equal(m.Int32Add(m.Parameter(0),
m.NewNode(shops[n], m.Parameter(1),
m.Parameter(2))),
m.Int32Constant(0)),
&blocka, &blockb);
m.Bind(&blocka);
m.Return(m.Int32Constant(constant));
m.Bind(&blockb);
m.Return(m.Int32Constant(0 - constant));
FOR_UINT32_INPUTS(i) {
FOR_INT32_INPUTS(j) {
FOR_UINT32_SHIFTS(shift) {
int32_t right;
switch (shops[n]->opcode()) {
default:
UNREACHABLE();
case IrOpcode::kWord32Sar:
right = *j >> shift;
break;
case IrOpcode::kWord32Shl:
right = *j << shift;
break;
case IrOpcode::kWord32Shr:
right = static_cast<uint32_t>(*j) >> shift;
break;
}
int32_t expected = ((*i + right) == 0) ? constant : 0 - constant;
CHECK_EQ(expected, m.Call(*i, *j, shift));
}
}
}
}
}
}
TEST(RunInt32AddInComparison) {
{
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
bt.AddReturn(
m.Word32Equal(m.Int32Add(bt.param0, bt.param1), m.Int32Constant(0)));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
uint32_t expected = (*i + *j) == 0;
CHECK_UINT32_EQ(expected, bt.call(*i, *j));
}
}
}
{
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
bt.AddReturn(
m.Word32Equal(m.Int32Constant(0), m.Int32Add(bt.param0, bt.param1)));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
uint32_t expected = (*i + *j) == 0;
CHECK_UINT32_EQ(expected, bt.call(*i, *j));
}
}
}
{
FOR_UINT32_INPUTS(i) {
RawMachineAssemblerTester<uint32_t> m(kMachUint32);
m.Return(m.Word32Equal(m.Int32Add(m.Int32Constant(*i), m.Parameter(0)),
m.Int32Constant(0)));
FOR_UINT32_INPUTS(j) {
uint32_t expected = (*i + *j) == 0;
CHECK_UINT32_EQ(expected, m.Call(*j));
}
}
}
{
FOR_UINT32_INPUTS(i) {
RawMachineAssemblerTester<uint32_t> m(kMachUint32);
m.Return(m.Word32Equal(m.Int32Add(m.Parameter(0), m.Int32Constant(*i)),
m.Int32Constant(0)));
FOR_UINT32_INPUTS(j) {
uint32_t expected = (*j + *i) == 0;
CHECK_UINT32_EQ(expected, m.Call(*j));
}
}
}
{
RawMachineAssemblerTester<void> m;
Operator* shops[] = {m.machine()->Word32Sar(), m.machine()->Word32Shl(),
m.machine()->Word32Shr()};
for (size_t n = 0; n < ARRAY_SIZE(shops); n++) {
RawMachineAssemblerTester<int32_t> m(kMachUint32, kMachInt32,
kMachUint32);
m.Return(m.Word32Equal(
m.Int32Add(m.Parameter(0),
m.NewNode(shops[n], m.Parameter(1), m.Parameter(2))),
m.Int32Constant(0)));
FOR_UINT32_INPUTS(i) {
FOR_INT32_INPUTS(j) {
FOR_UINT32_SHIFTS(shift) {
int32_t right;
switch (shops[n]->opcode()) {
default:
UNREACHABLE();
case IrOpcode::kWord32Sar:
right = *j >> shift;
break;
case IrOpcode::kWord32Shl:
right = *j << shift;
break;
case IrOpcode::kWord32Shr:
right = static_cast<uint32_t>(*j) >> shift;
break;
}
int32_t expected = (*i + right) == 0;
CHECK_EQ(expected, m.Call(*i, *j, shift));
}
}
}
}
}
}
TEST(RunInt32SubP) {
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
m.Return(m.Int32Sub(bt.param0, bt.param1));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
uint32_t expected = static_cast<int32_t>(*i - *j);
CHECK_UINT32_EQ(expected, bt.call(*i, *j));
}
}
}
TEST(RunInt32SubImm) {
{
FOR_UINT32_INPUTS(i) {
RawMachineAssemblerTester<uint32_t> m(kMachUint32);
m.Return(m.Int32Sub(m.Int32Constant(*i), m.Parameter(0)));
FOR_UINT32_INPUTS(j) {
uint32_t expected = *i - *j;
CHECK_UINT32_EQ(expected, m.Call(*j));
}
}
}
{
FOR_UINT32_INPUTS(i) {
RawMachineAssemblerTester<uint32_t> m(kMachUint32);
m.Return(m.Int32Sub(m.Parameter(0), m.Int32Constant(*i)));
FOR_UINT32_INPUTS(j) {
uint32_t expected = *j - *i;
CHECK_UINT32_EQ(expected, m.Call(*j));
}
}
}
}
TEST(RunInt32SubAndWord32SarP) {
{
RawMachineAssemblerTester<int32_t> m(kMachUint32, kMachInt32, kMachUint32);
m.Return(m.Int32Sub(m.Parameter(0),
m.Word32Sar(m.Parameter(1), m.Parameter(2))));
FOR_UINT32_INPUTS(i) {
FOR_INT32_INPUTS(j) {
FOR_UINT32_SHIFTS(shift) {
int32_t expected = *i - (*j >> shift);
CHECK_EQ(expected, m.Call(*i, *j, shift));
}
}
}
}
{
RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachUint32, kMachUint32);
m.Return(m.Int32Sub(m.Word32Sar(m.Parameter(0), m.Parameter(1)),
m.Parameter(2)));
FOR_INT32_INPUTS(i) {
FOR_UINT32_SHIFTS(shift) {
FOR_UINT32_INPUTS(k) {
int32_t expected = (*i >> shift) - *k;
CHECK_EQ(expected, m.Call(*i, shift, *k));
}
}
}
}
}
TEST(RunInt32SubAndWord32ShlP) {
{
RawMachineAssemblerTester<int32_t> m(kMachUint32, kMachInt32, kMachUint32);
m.Return(m.Int32Sub(m.Parameter(0),
m.Word32Shl(m.Parameter(1), m.Parameter(2))));
FOR_UINT32_INPUTS(i) {
FOR_INT32_INPUTS(j) {
FOR_UINT32_SHIFTS(shift) {
int32_t expected = *i - (*j << shift);
CHECK_EQ(expected, m.Call(*i, *j, shift));
}
}
}
}
{
RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachUint32, kMachUint32);
m.Return(m.Int32Sub(m.Word32Shl(m.Parameter(0), m.Parameter(1)),
m.Parameter(2)));
FOR_INT32_INPUTS(i) {
FOR_UINT32_SHIFTS(shift) {
FOR_UINT32_INPUTS(k) {
// Use uint32_t because signed overflow is UB in C.
int32_t expected = (*i << shift) - *k;
CHECK_EQ(expected, m.Call(*i, shift, *k));
}
}
}
}
}
TEST(RunInt32SubAndWord32ShrP) {
{
RawMachineAssemblerTester<uint32_t> m(kMachUint32, kMachUint32,
kMachUint32);
m.Return(m.Int32Sub(m.Parameter(0),
m.Word32Shr(m.Parameter(1), m.Parameter(2))));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
FOR_UINT32_SHIFTS(shift) {
// Use uint32_t because signed overflow is UB in C.
int32_t expected = *i - (*j >> shift);
CHECK_UINT32_EQ(expected, m.Call(*i, *j, shift));
}
}
}
}
{
RawMachineAssemblerTester<uint32_t> m(kMachUint32, kMachUint32,
kMachUint32);
m.Return(m.Int32Sub(m.Word32Shr(m.Parameter(0), m.Parameter(1)),
m.Parameter(2)));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_SHIFTS(shift) {
FOR_UINT32_INPUTS(k) {
// Use uint32_t because signed overflow is UB in C.
int32_t expected = (*i >> shift) - *k;
CHECK_EQ(expected, m.Call(*i, shift, *k));
}
}
}
}
}
TEST(RunInt32SubInBranch) {
static const int constant = 987654321;
{
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
MLabel blocka, blockb;
m.Branch(
m.Word32Equal(m.Int32Sub(bt.param0, bt.param1), m.Int32Constant(0)),
&blocka, &blockb);
m.Bind(&blocka);
bt.AddReturn(m.Int32Constant(constant));
m.Bind(&blockb);
bt.AddReturn(m.Int32Constant(0 - constant));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
int32_t expected = (*i - *j) == 0 ? constant : 0 - constant;
CHECK_EQ(expected, bt.call(*i, *j));
}
}
}
{
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
MLabel blocka, blockb;
m.Branch(
m.Word32NotEqual(m.Int32Sub(bt.param0, bt.param1), m.Int32Constant(0)),
&blocka, &blockb);
m.Bind(&blocka);
bt.AddReturn(m.Int32Constant(constant));
m.Bind(&blockb);
bt.AddReturn(m.Int32Constant(0 - constant));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
int32_t expected = (*i - *j) != 0 ? constant : 0 - constant;
CHECK_EQ(expected, bt.call(*i, *j));
}
}
}
{
FOR_UINT32_INPUTS(i) {
RawMachineAssemblerTester<uint32_t> m(kMachUint32);
MLabel blocka, blockb;
m.Branch(m.Word32Equal(m.Int32Sub(m.Int32Constant(*i), m.Parameter(0)),
m.Int32Constant(0)),
&blocka, &blockb);
m.Bind(&blocka);
m.Return(m.Int32Constant(constant));
m.Bind(&blockb);
m.Return(m.Int32Constant(0 - constant));
FOR_UINT32_INPUTS(j) {
int32_t expected = (*i - *j) == 0 ? constant : 0 - constant;
CHECK_EQ(expected, m.Call(*j));
}
}
}
{
FOR_UINT32_INPUTS(i) {
RawMachineAssemblerTester<int32_t> m(kMachUint32);
MLabel blocka, blockb;
m.Branch(m.Word32NotEqual(m.Int32Sub(m.Int32Constant(*i), m.Parameter(0)),
m.Int32Constant(0)),
&blocka, &blockb);
m.Bind(&blocka);
m.Return(m.Int32Constant(constant));
m.Bind(&blockb);
m.Return(m.Int32Constant(0 - constant));
FOR_UINT32_INPUTS(j) {
int32_t expected = (*i - *j) != 0 ? constant : 0 - constant;
CHECK_EQ(expected, m.Call(*j));
}
}
}
{
RawMachineAssemblerTester<void> m;
Operator* shops[] = {m.machine()->Word32Sar(), m.machine()->Word32Shl(),
m.machine()->Word32Shr()};
for (size_t n = 0; n < ARRAY_SIZE(shops); n++) {
RawMachineAssemblerTester<int32_t> m(kMachUint32, kMachInt32,
kMachUint32);
MLabel blocka, blockb;
m.Branch(m.Word32Equal(m.Int32Sub(m.Parameter(0),
m.NewNode(shops[n], m.Parameter(1),
m.Parameter(2))),
m.Int32Constant(0)),
&blocka, &blockb);
m.Bind(&blocka);
m.Return(m.Int32Constant(constant));
m.Bind(&blockb);
m.Return(m.Int32Constant(0 - constant));
FOR_UINT32_INPUTS(i) {
FOR_INT32_INPUTS(j) {
FOR_UINT32_SHIFTS(shift) {
int32_t right;
switch (shops[n]->opcode()) {
default:
UNREACHABLE();
case IrOpcode::kWord32Sar:
right = *j >> shift;
break;
case IrOpcode::kWord32Shl:
right = *j << shift;
break;
case IrOpcode::kWord32Shr:
right = static_cast<uint32_t>(*j) >> shift;
break;
}
int32_t expected = ((*i - right) == 0) ? constant : 0 - constant;
CHECK_EQ(expected, m.Call(*i, *j, shift));
}
}
}
}
}
}
TEST(RunInt32SubInComparison) {
{
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
bt.AddReturn(
m.Word32Equal(m.Int32Sub(bt.param0, bt.param1), m.Int32Constant(0)));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
uint32_t expected = (*i - *j) == 0;
CHECK_UINT32_EQ(expected, bt.call(*i, *j));
}
}
}
{
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
bt.AddReturn(
m.Word32Equal(m.Int32Constant(0), m.Int32Sub(bt.param0, bt.param1)));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
uint32_t expected = (*i - *j) == 0;
CHECK_UINT32_EQ(expected, bt.call(*i, *j));
}
}
}
{
FOR_UINT32_INPUTS(i) {
RawMachineAssemblerTester<uint32_t> m(kMachUint32);
m.Return(m.Word32Equal(m.Int32Sub(m.Int32Constant(*i), m.Parameter(0)),
m.Int32Constant(0)));
FOR_UINT32_INPUTS(j) {
uint32_t expected = (*i - *j) == 0;
CHECK_UINT32_EQ(expected, m.Call(*j));
}
}
}
{
FOR_UINT32_INPUTS(i) {
RawMachineAssemblerTester<uint32_t> m(kMachUint32);
m.Return(m.Word32Equal(m.Int32Sub(m.Parameter(0), m.Int32Constant(*i)),
m.Int32Constant(0)));
FOR_UINT32_INPUTS(j) {
uint32_t expected = (*j - *i) == 0;
CHECK_UINT32_EQ(expected, m.Call(*j));
}
}
}
{
RawMachineAssemblerTester<void> m;
Operator* shops[] = {m.machine()->Word32Sar(), m.machine()->Word32Shl(),
m.machine()->Word32Shr()};
for (size_t n = 0; n < ARRAY_SIZE(shops); n++) {
RawMachineAssemblerTester<int32_t> m(kMachUint32, kMachInt32,
kMachUint32);
m.Return(m.Word32Equal(
m.Int32Sub(m.Parameter(0),
m.NewNode(shops[n], m.Parameter(1), m.Parameter(2))),
m.Int32Constant(0)));
FOR_UINT32_INPUTS(i) {
FOR_INT32_INPUTS(j) {
FOR_UINT32_SHIFTS(shift) {
int32_t right;
switch (shops[n]->opcode()) {
default:
UNREACHABLE();
case IrOpcode::kWord32Sar:
right = *j >> shift;
break;
case IrOpcode::kWord32Shl:
right = *j << shift;
break;
case IrOpcode::kWord32Shr:
right = static_cast<uint32_t>(*j) >> shift;
break;
}
int32_t expected = (*i - right) == 0;
CHECK_EQ(expected, m.Call(*i, *j, shift));
}
}
}
}
}
}
TEST(RunInt32MulP) {
{
RawMachineAssemblerTester<int32_t> m;
Int32BinopTester bt(&m);
bt.AddReturn(m.Int32Mul(bt.param0, bt.param1));
FOR_INT32_INPUTS(i) {
FOR_INT32_INPUTS(j) {
int expected = static_cast<int32_t>(*i * *j);
CHECK_EQ(expected, bt.call(*i, *j));
}
}
}
{
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
bt.AddReturn(m.Int32Mul(bt.param0, bt.param1));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
uint32_t expected = *i * *j;
CHECK_UINT32_EQ(expected, bt.call(*i, *j));
}
}
}
}
TEST(RunInt32MulImm) {
{
FOR_UINT32_INPUTS(i) {
RawMachineAssemblerTester<uint32_t> m(kMachUint32);
m.Return(m.Int32Mul(m.Int32Constant(*i), m.Parameter(0)));
FOR_UINT32_INPUTS(j) {
uint32_t expected = *i * *j;
CHECK_UINT32_EQ(expected, m.Call(*j));
}
}
}
{
FOR_UINT32_INPUTS(i) {
RawMachineAssemblerTester<uint32_t> m(kMachUint32);
m.Return(m.Int32Mul(m.Parameter(0), m.Int32Constant(*i)));
FOR_UINT32_INPUTS(j) {
uint32_t expected = *j * *i;
CHECK_UINT32_EQ(expected, m.Call(*j));
}
}
}
}
TEST(RunInt32MulAndInt32AddP) {
{
RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32, kMachInt32);
m.Return(
m.Int32Add(m.Parameter(0), m.Int32Mul(m.Parameter(1), m.Parameter(2))));
FOR_INT32_INPUTS(i) {
FOR_INT32_INPUTS(j) {
FOR_INT32_INPUTS(k) {
int32_t p0 = *i;
int32_t p1 = *j;
int32_t p2 = *k;
int expected = p0 + static_cast<int32_t>(p1 * p2);
CHECK_EQ(expected, m.Call(p0, p1, p2));
}
}
}
}
{
RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32, kMachInt32);
m.Return(
m.Int32Add(m.Int32Mul(m.Parameter(0), m.Parameter(1)), m.Parameter(2)));
FOR_INT32_INPUTS(i) {
FOR_INT32_INPUTS(j) {
FOR_INT32_INPUTS(k) {
int32_t p0 = *i;
int32_t p1 = *j;
int32_t p2 = *k;
int expected = static_cast<int32_t>(p0 * p1) + p2;
CHECK_EQ(expected, m.Call(p0, p1, p2));
}
}
}
}
{
FOR_INT32_INPUTS(i) {
RawMachineAssemblerTester<int32_t> m;
Int32BinopTester bt(&m);
bt.AddReturn(
m.Int32Add(m.Int32Constant(*i), m.Int32Mul(bt.param0, bt.param1)));
FOR_INT32_INPUTS(j) {
FOR_INT32_INPUTS(k) {
int32_t p0 = *j;
int32_t p1 = *k;
int expected = *i + static_cast<int32_t>(p0 * p1);
CHECK_EQ(expected, bt.call(p0, p1));
}
}
}
}
}
TEST(RunInt32MulAndInt32SubP) {
{
RawMachineAssemblerTester<int32_t> m(kMachUint32, kMachInt32, kMachInt32);
m.Return(
m.Int32Sub(m.Parameter(0), m.Int32Mul(m.Parameter(1), m.Parameter(2))));
FOR_UINT32_INPUTS(i) {
FOR_INT32_INPUTS(j) {
FOR_INT32_INPUTS(k) {
uint32_t p0 = *i;
int32_t p1 = *j;
int32_t p2 = *k;
// Use uint32_t because signed overflow is UB in C.
int expected = p0 - static_cast<uint32_t>(p1 * p2);
CHECK_EQ(expected, m.Call(p0, p1, p2));
}
}
}
}
{
FOR_UINT32_INPUTS(i) {
RawMachineAssemblerTester<int32_t> m;
Int32BinopTester bt(&m);
bt.AddReturn(
m.Int32Sub(m.Int32Constant(*i), m.Int32Mul(bt.param0, bt.param1)));
FOR_INT32_INPUTS(j) {
FOR_INT32_INPUTS(k) {
int32_t p0 = *j;
int32_t p1 = *k;
// Use uint32_t because signed overflow is UB in C.
int expected = *i - static_cast<uint32_t>(p0 * p1);
CHECK_EQ(expected, bt.call(p0, p1));
}
}
}
}
}
TEST(RunInt32DivP) {
{
RawMachineAssemblerTester<int32_t> m;
Int32BinopTester bt(&m);
bt.AddReturn(m.Int32Div(bt.param0, bt.param1));
FOR_INT32_INPUTS(i) {
FOR_INT32_INPUTS(j) {
int p0 = *i;
int p1 = *j;
if (p1 != 0 && (static_cast<uint32_t>(p0) != 0x80000000 || p1 != -1)) {
int expected = static_cast<int32_t>(p0 / p1);
CHECK_EQ(expected, bt.call(p0, p1));
}
}
}
}
{
RawMachineAssemblerTester<int32_t> m;
Int32BinopTester bt(&m);
bt.AddReturn(m.Int32Add(bt.param0, m.Int32Div(bt.param0, bt.param1)));
FOR_INT32_INPUTS(i) {
FOR_INT32_INPUTS(j) {
int p0 = *i;
int p1 = *j;
if (p1 != 0 && (static_cast<uint32_t>(p0) != 0x80000000 || p1 != -1)) {
int expected = static_cast<int32_t>(p0 + (p0 / p1));
CHECK_EQ(expected, bt.call(p0, p1));
}
}
}
}
}
TEST(RunInt32UDivP) {
{
RawMachineAssemblerTester<int32_t> m;
Int32BinopTester bt(&m);
bt.AddReturn(m.Int32UDiv(bt.param0, bt.param1));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
uint32_t p0 = *i;
uint32_t p1 = *j;
if (p1 != 0) {
uint32_t expected = static_cast<uint32_t>(p0 / p1);
CHECK_EQ(expected, bt.call(p0, p1));
}
}
}
}
{
RawMachineAssemblerTester<int32_t> m;
Int32BinopTester bt(&m);
bt.AddReturn(m.Int32Add(bt.param0, m.Int32UDiv(bt.param0, bt.param1)));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
uint32_t p0 = *i;
uint32_t p1 = *j;
if (p1 != 0) {
uint32_t expected = static_cast<uint32_t>(p0 + (p0 / p1));
CHECK_EQ(expected, bt.call(p0, p1));
}
}
}
}
}
TEST(RunInt32ModP) {
{
RawMachineAssemblerTester<int32_t> m;
Int32BinopTester bt(&m);
bt.AddReturn(m.Int32Mod(bt.param0, bt.param1));
FOR_INT32_INPUTS(i) {
FOR_INT32_INPUTS(j) {
int p0 = *i;
int p1 = *j;
if (p1 != 0 && (static_cast<uint32_t>(p0) != 0x80000000 || p1 != -1)) {
int expected = static_cast<int32_t>(p0 % p1);
CHECK_EQ(expected, bt.call(p0, p1));
}
}
}
}
{
RawMachineAssemblerTester<int32_t> m;
Int32BinopTester bt(&m);
bt.AddReturn(m.Int32Add(bt.param0, m.Int32Mod(bt.param0, bt.param1)));
FOR_INT32_INPUTS(i) {
FOR_INT32_INPUTS(j) {
int p0 = *i;
int p1 = *j;
if (p1 != 0 && (static_cast<uint32_t>(p0) != 0x80000000 || p1 != -1)) {
int expected = static_cast<int32_t>(p0 + (p0 % p1));
CHECK_EQ(expected, bt.call(p0, p1));
}
}
}
}
}
TEST(RunInt32UModP) {
{
RawMachineAssemblerTester<int32_t> m;
Int32BinopTester bt(&m);
bt.AddReturn(m.Int32UMod(bt.param0, bt.param1));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
uint32_t p0 = *i;
uint32_t p1 = *j;
if (p1 != 0) {
uint32_t expected = static_cast<uint32_t>(p0 % p1);
CHECK_EQ(expected, bt.call(p0, p1));
}
}
}
}
{
RawMachineAssemblerTester<int32_t> m;
Int32BinopTester bt(&m);
bt.AddReturn(m.Int32Add(bt.param0, m.Int32UMod(bt.param0, bt.param1)));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
uint32_t p0 = *i;
uint32_t p1 = *j;
if (p1 != 0) {
uint32_t expected = static_cast<uint32_t>(p0 + (p0 % p1));
CHECK_EQ(expected, bt.call(p0, p1));
}
}
}
}
}
TEST(RunWord32AndP) {
{
RawMachineAssemblerTester<int32_t> m;
Int32BinopTester bt(&m);
bt.AddReturn(m.Word32And(bt.param0, bt.param1));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
uint32_t expected = *i & *j;
CHECK_EQ(expected, bt.call(*i, *j));
}
}
}
{
RawMachineAssemblerTester<int32_t> m;
Int32BinopTester bt(&m);
bt.AddReturn(m.Word32And(bt.param0, m.Word32Not(bt.param1)));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
uint32_t expected = *i & ~(*j);
CHECK_EQ(expected, bt.call(*i, *j));
}
}
}
{
RawMachineAssemblerTester<int32_t> m;
Int32BinopTester bt(&m);
bt.AddReturn(m.Word32And(m.Word32Not(bt.param0), bt.param1));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
uint32_t expected = ~(*i) & *j;
CHECK_EQ(expected, bt.call(*i, *j));
}
}
}
}
TEST(RunWord32AndAndWord32ShlP) {
{
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
bt.AddReturn(
m.Word32Shl(bt.param0, m.Word32And(bt.param1, m.Int32Constant(0x1f))));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
uint32_t expected = *i << (*j & 0x1f);
CHECK_UINT32_EQ(expected, bt.call(*i, *j));
}
}
}
{
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
bt.AddReturn(
m.Word32Shl(bt.param0, m.Word32And(m.Int32Constant(0x1f), bt.param1)));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
uint32_t expected = *i << (0x1f & *j);
CHECK_UINT32_EQ(expected, bt.call(*i, *j));
}
}
}
}
TEST(RunWord32AndAndWord32ShrP) {
{
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
bt.AddReturn(
m.Word32Shr(bt.param0, m.Word32And(bt.param1, m.Int32Constant(0x1f))));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
uint32_t expected = *i >> (*j & 0x1f);
CHECK_UINT32_EQ(expected, bt.call(*i, *j));
}
}
}
{
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
bt.AddReturn(
m.Word32Shr(bt.param0, m.Word32And(m.Int32Constant(0x1f), bt.param1)));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
uint32_t expected = *i >> (0x1f & *j);
CHECK_UINT32_EQ(expected, bt.call(*i, *j));
}
}
}
}
TEST(RunWord32AndAndWord32SarP) {
{
RawMachineAssemblerTester<int32_t> m;
Int32BinopTester bt(&m);
bt.AddReturn(
m.Word32Sar(bt.param0, m.Word32And(bt.param1, m.Int32Constant(0x1f))));
FOR_INT32_INPUTS(i) {
FOR_INT32_INPUTS(j) {
int32_t expected = *i >> (*j & 0x1f);
CHECK_EQ(expected, bt.call(*i, *j));
}
}
}
{
RawMachineAssemblerTester<int32_t> m;
Int32BinopTester bt(&m);
bt.AddReturn(
m.Word32Sar(bt.param0, m.Word32And(m.Int32Constant(0x1f), bt.param1)));
FOR_INT32_INPUTS(i) {
FOR_INT32_INPUTS(j) {
uint32_t expected = *i >> (0x1f & *j);
CHECK_EQ(expected, bt.call(*i, *j));
}
}
}
}
TEST(RunWord32AndImm) {
{
FOR_UINT32_INPUTS(i) {
RawMachineAssemblerTester<uint32_t> m(kMachUint32);
m.Return(m.Word32And(m.Int32Constant(*i), m.Parameter(0)));
FOR_UINT32_INPUTS(j) {
uint32_t expected = *i & *j;
CHECK_UINT32_EQ(expected, m.Call(*j));
}
}
}
{
FOR_UINT32_INPUTS(i) {
RawMachineAssemblerTester<uint32_t> m(kMachUint32);
m.Return(m.Word32And(m.Int32Constant(*i), m.Word32Not(m.Parameter(0))));
FOR_UINT32_INPUTS(j) {
uint32_t expected = *i & ~(*j);
CHECK_UINT32_EQ(expected, m.Call(*j));
}
}
}
}
TEST(RunWord32AndInBranch) {
static const int constant = 987654321;
{
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
MLabel blocka, blockb;
m.Branch(
m.Word32Equal(m.Word32And(bt.param0, bt.param1), m.Int32Constant(0)),
&blocka, &blockb);
m.Bind(&blocka);
bt.AddReturn(m.Int32Constant(constant));
m.Bind(&blockb);
bt.AddReturn(m.Int32Constant(0 - constant));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
int32_t expected = (*i & *j) == 0 ? constant : 0 - constant;
CHECK_EQ(expected, bt.call(*i, *j));
}
}
}
{
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
MLabel blocka, blockb;
m.Branch(
m.Word32NotEqual(m.Word32And(bt.param0, bt.param1), m.Int32Constant(0)),
&blocka, &blockb);
m.Bind(&blocka);
bt.AddReturn(m.Int32Constant(constant));
m.Bind(&blockb);
bt.AddReturn(m.Int32Constant(0 - constant));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
int32_t expected = (*i & *j) != 0 ? constant : 0 - constant;
CHECK_EQ(expected, bt.call(*i, *j));
}
}
}
{
FOR_UINT32_INPUTS(i) {
RawMachineAssemblerTester<int32_t> m(kMachUint32);
MLabel blocka, blockb;
m.Branch(m.Word32Equal(m.Word32And(m.Int32Constant(*i), m.Parameter(0)),
m.Int32Constant(0)),
&blocka, &blockb);
m.Bind(&blocka);
m.Return(m.Int32Constant(constant));
m.Bind(&blockb);
m.Return(m.Int32Constant(0 - constant));
FOR_UINT32_INPUTS(j) {
int32_t expected = (*i & *j) == 0 ? constant : 0 - constant;
CHECK_EQ(expected, m.Call(*j));
}
}
}
{
FOR_UINT32_INPUTS(i) {
RawMachineAssemblerTester<int32_t> m(kMachUint32);
MLabel blocka, blockb;
m.Branch(
m.Word32NotEqual(m.Word32And(m.Int32Constant(*i), m.Parameter(0)),
m.Int32Constant(0)),
&blocka, &blockb);
m.Bind(&blocka);
m.Return(m.Int32Constant(constant));
m.Bind(&blockb);
m.Return(m.Int32Constant(0 - constant));
FOR_UINT32_INPUTS(j) {
int32_t expected = (*i & *j) != 0 ? constant : 0 - constant;
CHECK_EQ(expected, m.Call(*j));
}
}
}
{
RawMachineAssemblerTester<void> m;
Operator* shops[] = {m.machine()->Word32Sar(), m.machine()->Word32Shl(),
m.machine()->Word32Shr()};
for (size_t n = 0; n < ARRAY_SIZE(shops); n++) {
RawMachineAssemblerTester<int32_t> m(kMachUint32, kMachInt32,
kMachUint32);
MLabel blocka, blockb;
m.Branch(m.Word32Equal(m.Word32And(m.Parameter(0),
m.NewNode(shops[n], m.Parameter(1),
m.Parameter(2))),
m.Int32Constant(0)),
&blocka, &blockb);
m.Bind(&blocka);
m.Return(m.Int32Constant(constant));
m.Bind(&blockb);
m.Return(m.Int32Constant(0 - constant));
FOR_UINT32_INPUTS(i) {
FOR_INT32_INPUTS(j) {
FOR_UINT32_SHIFTS(shift) {
int32_t right;
switch (shops[n]->opcode()) {
default:
UNREACHABLE();
case IrOpcode::kWord32Sar:
right = *j >> shift;
break;
case IrOpcode::kWord32Shl:
right = *j << shift;
break;
case IrOpcode::kWord32Shr:
right = static_cast<uint32_t>(*j) >> shift;
break;
}
int32_t expected = ((*i & right) == 0) ? constant : 0 - constant;
CHECK_EQ(expected, m.Call(*i, *j, shift));
}
}
}
}
}
}
TEST(RunWord32AndInComparison) {
{
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
bt.AddReturn(
m.Word32Equal(m.Word32And(bt.param0, bt.param1), m.Int32Constant(0)));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
uint32_t expected = (*i & *j) == 0;
CHECK_UINT32_EQ(expected, bt.call(*i, *j));
}
}
}
{
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
bt.AddReturn(
m.Word32Equal(m.Int32Constant(0), m.Word32And(bt.param0, bt.param1)));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
uint32_t expected = (*i & *j) == 0;
CHECK_UINT32_EQ(expected, bt.call(*i, *j));
}
}
}
{
FOR_UINT32_INPUTS(i) {
RawMachineAssemblerTester<uint32_t> m(kMachUint32);
m.Return(m.Word32Equal(m.Word32And(m.Int32Constant(*i), m.Parameter(0)),
m.Int32Constant(0)));
FOR_UINT32_INPUTS(j) {
uint32_t expected = (*i & *j) == 0;
CHECK_UINT32_EQ(expected, m.Call(*j));
}
}
}
{
FOR_UINT32_INPUTS(i) {
RawMachineAssemblerTester<uint32_t> m(kMachUint32);
m.Return(m.Word32Equal(m.Word32And(m.Parameter(0), m.Int32Constant(*i)),
m.Int32Constant(0)));
FOR_UINT32_INPUTS(j) {
uint32_t expected = (*j & *i) == 0;
CHECK_UINT32_EQ(expected, m.Call(*j));
}
}
}
}
TEST(RunWord32OrP) {
{
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
bt.AddReturn(m.Word32Or(bt.param0, bt.param1));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
uint32_t expected = *i | *j;
CHECK_UINT32_EQ(expected, bt.call(*i, *j));
}
}
}
{
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
bt.AddReturn(m.Word32Or(bt.param0, m.Word32Not(bt.param1)));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
uint32_t expected = *i | ~(*j);
CHECK_UINT32_EQ(expected, bt.call(*i, *j));
}
}
}
{
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
bt.AddReturn(m.Word32Or(m.Word32Not(bt.param0), bt.param1));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
uint32_t expected = ~(*i) | *j;
CHECK_UINT32_EQ(expected, bt.call(*i, *j));
}
}
}
}
TEST(RunWord32OrImm) {
{
FOR_UINT32_INPUTS(i) {
RawMachineAssemblerTester<uint32_t> m(kMachUint32);
m.Return(m.Word32Or(m.Int32Constant(*i), m.Parameter(0)));
FOR_UINT32_INPUTS(j) {
uint32_t expected = *i | *j;
CHECK_UINT32_EQ(expected, m.Call(*j));
}
}
}
{
FOR_UINT32_INPUTS(i) {
RawMachineAssemblerTester<uint32_t> m(kMachUint32);
m.Return(m.Word32Or(m.Int32Constant(*i), m.Word32Not(m.Parameter(0))));
FOR_UINT32_INPUTS(j) {
uint32_t expected = *i | ~(*j);
CHECK_UINT32_EQ(expected, m.Call(*j));
}
}
}
}
TEST(RunWord32OrInBranch) {
static const int constant = 987654321;
{
RawMachineAssemblerTester<int32_t> m;
Int32BinopTester bt(&m);
MLabel blocka, blockb;
m.Branch(
m.Word32Equal(m.Word32Or(bt.param0, bt.param1), m.Int32Constant(0)),
&blocka, &blockb);
m.Bind(&blocka);
bt.AddReturn(m.Int32Constant(constant));
m.Bind(&blockb);
bt.AddReturn(m.Int32Constant(0 - constant));
FOR_INT32_INPUTS(i) {
FOR_INT32_INPUTS(j) {
int32_t expected = (*i | *j) == 0 ? constant : 0 - constant;
CHECK_EQ(expected, bt.call(*i, *j));
}
}
}
{
RawMachineAssemblerTester<int32_t> m;
Int32BinopTester bt(&m);
MLabel blocka, blockb;
m.Branch(
m.Word32NotEqual(m.Word32Or(bt.param0, bt.param1), m.Int32Constant(0)),
&blocka, &blockb);
m.Bind(&blocka);
bt.AddReturn(m.Int32Constant(constant));
m.Bind(&blockb);
bt.AddReturn(m.Int32Constant(0 - constant));
FOR_INT32_INPUTS(i) {
FOR_INT32_INPUTS(j) {
int32_t expected = (*i | *j) != 0 ? constant : 0 - constant;
CHECK_EQ(expected, bt.call(*i, *j));
}
}
}
{
FOR_INT32_INPUTS(i) {
RawMachineAssemblerTester<int32_t> m(kMachInt32);
MLabel blocka, blockb;
m.Branch(m.Word32Equal(m.Word32Or(m.Int32Constant(*i), m.Parameter(0)),
m.Int32Constant(0)),
&blocka, &blockb);
m.Bind(&blocka);
m.Return(m.Int32Constant(constant));
m.Bind(&blockb);
m.Return(m.Int32Constant(0 - constant));
FOR_INT32_INPUTS(j) {
int32_t expected = (*i | *j) == 0 ? constant : 0 - constant;
CHECK_EQ(expected, m.Call(*j));
}
}
}
{
FOR_INT32_INPUTS(i) {
RawMachineAssemblerTester<int32_t> m(kMachInt32);
MLabel blocka, blockb;
m.Branch(m.Word32NotEqual(m.Word32Or(m.Int32Constant(*i), m.Parameter(0)),
m.Int32Constant(0)),
&blocka, &blockb);
m.Bind(&blocka);
m.Return(m.Int32Constant(constant));
m.Bind(&blockb);
m.Return(m.Int32Constant(0 - constant));
FOR_INT32_INPUTS(j) {
int32_t expected = (*i | *j) != 0 ? constant : 0 - constant;
CHECK_EQ(expected, m.Call(*j));
}
}
}
{
RawMachineAssemblerTester<void> m;
Operator* shops[] = {m.machine()->Word32Sar(), m.machine()->Word32Shl(),
m.machine()->Word32Shr()};
for (size_t n = 0; n < ARRAY_SIZE(shops); n++) {
RawMachineAssemblerTester<int32_t> m(kMachUint32, kMachInt32,
kMachUint32);
MLabel blocka, blockb;
m.Branch(m.Word32Equal(m.Word32Or(m.Parameter(0),
m.NewNode(shops[n], m.Parameter(1),
m.Parameter(2))),
m.Int32Constant(0)),
&blocka, &blockb);
m.Bind(&blocka);
m.Return(m.Int32Constant(constant));
m.Bind(&blockb);
m.Return(m.Int32Constant(0 - constant));
FOR_UINT32_INPUTS(i) {
FOR_INT32_INPUTS(j) {
FOR_UINT32_SHIFTS(shift) {
int32_t right;
switch (shops[n]->opcode()) {
default:
UNREACHABLE();
case IrOpcode::kWord32Sar:
right = *j >> shift;
break;
case IrOpcode::kWord32Shl:
right = *j << shift;
break;
case IrOpcode::kWord32Shr:
right = static_cast<uint32_t>(*j) >> shift;
break;
}
int32_t expected = ((*i | right) == 0) ? constant : 0 - constant;
CHECK_EQ(expected, m.Call(*i, *j, shift));
}
}
}
}
}
}
TEST(RunWord32OrInComparison) {
{
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
bt.AddReturn(
m.Word32Equal(m.Word32Or(bt.param0, bt.param1), m.Int32Constant(0)));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
int32_t expected = (*i | *j) == 0;
CHECK_EQ(expected, bt.call(*i, *j));
}
}
}
{
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
bt.AddReturn(
m.Word32Equal(m.Int32Constant(0), m.Word32Or(bt.param0, bt.param1)));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
int32_t expected = (*i | *j) == 0;
CHECK_EQ(expected, bt.call(*i, *j));
}
}
}
{
FOR_UINT32_INPUTS(i) {
RawMachineAssemblerTester<uint32_t> m(kMachUint32);
m.Return(m.Word32Equal(m.Word32Or(m.Int32Constant(*i), m.Parameter(0)),
m.Int32Constant(0)));
FOR_UINT32_INPUTS(j) {
uint32_t expected = (*i | *j) == 0;
CHECK_UINT32_EQ(expected, m.Call(*j));
}
}
}
{
FOR_UINT32_INPUTS(i) {
RawMachineAssemblerTester<uint32_t> m(kMachUint32);
m.Return(m.Word32Equal(m.Word32Or(m.Parameter(0), m.Int32Constant(*i)),
m.Int32Constant(0)));
FOR_UINT32_INPUTS(j) {
uint32_t expected = (*j | *i) == 0;
CHECK_UINT32_EQ(expected, m.Call(*j));
}
}
}
}
TEST(RunWord32XorP) {
{
FOR_UINT32_INPUTS(i) {
RawMachineAssemblerTester<int32_t> m(kMachUint32);
m.Return(m.Word32Xor(m.Int32Constant(*i), m.Parameter(0)));
FOR_UINT32_INPUTS(j) {
uint32_t expected = *i ^ *j;
CHECK_UINT32_EQ(expected, m.Call(*j));
}
}
}
{
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
bt.AddReturn(m.Word32Xor(bt.param0, bt.param1));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
int32_t expected = *i ^ *j;
CHECK_UINT32_EQ(expected, bt.call(*i, *j));
}
}
}
{
RawMachineAssemblerTester<int32_t> m;
Int32BinopTester bt(&m);
bt.AddReturn(m.Word32Xor(bt.param0, m.Word32Not(bt.param1)));
FOR_INT32_INPUTS(i) {
FOR_INT32_INPUTS(j) {
int32_t expected = *i ^ ~(*j);
CHECK_EQ(expected, bt.call(*i, *j));
}
}
}
{
RawMachineAssemblerTester<int32_t> m;
Int32BinopTester bt(&m);
bt.AddReturn(m.Word32Xor(m.Word32Not(bt.param0), bt.param1));
FOR_INT32_INPUTS(i) {
FOR_INT32_INPUTS(j) {
int32_t expected = ~(*i) ^ *j;
CHECK_EQ(expected, bt.call(*i, *j));
}
}
}
{
FOR_UINT32_INPUTS(i) {
RawMachineAssemblerTester<uint32_t> m(kMachUint32);
m.Return(m.Word32Xor(m.Int32Constant(*i), m.Word32Not(m.Parameter(0))));
FOR_UINT32_INPUTS(j) {
uint32_t expected = *i ^ ~(*j);
CHECK_UINT32_EQ(expected, m.Call(*j));
}
}
}
}
TEST(RunWord32XorInBranch) {
static const uint32_t constant = 987654321;
{
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
MLabel blocka, blockb;
m.Branch(
m.Word32Equal(m.Word32Xor(bt.param0, bt.param1), m.Int32Constant(0)),
&blocka, &blockb);
m.Bind(&blocka);
bt.AddReturn(m.Int32Constant(constant));
m.Bind(&blockb);
bt.AddReturn(m.Int32Constant(0 - constant));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
uint32_t expected = (*i ^ *j) == 0 ? constant : 0 - constant;
CHECK_UINT32_EQ(expected, bt.call(*i, *j));
}
}
}
{
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
MLabel blocka, blockb;
m.Branch(
m.Word32NotEqual(m.Word32Xor(bt.param0, bt.param1), m.Int32Constant(0)),
&blocka, &blockb);
m.Bind(&blocka);
bt.AddReturn(m.Int32Constant(constant));
m.Bind(&blockb);
bt.AddReturn(m.Int32Constant(0 - constant));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
uint32_t expected = (*i ^ *j) != 0 ? constant : 0 - constant;
CHECK_UINT32_EQ(expected, bt.call(*i, *j));
}
}
}
{
FOR_UINT32_INPUTS(i) {
RawMachineAssemblerTester<uint32_t> m(kMachUint32);
MLabel blocka, blockb;
m.Branch(m.Word32Equal(m.Word32Xor(m.Int32Constant(*i), m.Parameter(0)),
m.Int32Constant(0)),
&blocka, &blockb);
m.Bind(&blocka);
m.Return(m.Int32Constant(constant));
m.Bind(&blockb);
m.Return(m.Int32Constant(0 - constant));
FOR_UINT32_INPUTS(j) {
uint32_t expected = (*i ^ *j) == 0 ? constant : 0 - constant;
CHECK_UINT32_EQ(expected, m.Call(*j));
}
}
}
{
FOR_UINT32_INPUTS(i) {
RawMachineAssemblerTester<uint32_t> m(kMachUint32);
MLabel blocka, blockb;
m.Branch(
m.Word32NotEqual(m.Word32Xor(m.Int32Constant(*i), m.Parameter(0)),
m.Int32Constant(0)),
&blocka, &blockb);
m.Bind(&blocka);
m.Return(m.Int32Constant(constant));
m.Bind(&blockb);
m.Return(m.Int32Constant(0 - constant));
FOR_UINT32_INPUTS(j) {
uint32_t expected = (*i ^ *j) != 0 ? constant : 0 - constant;
CHECK_UINT32_EQ(expected, m.Call(*j));
}
}
}
{
RawMachineAssemblerTester<void> m;
Operator* shops[] = {m.machine()->Word32Sar(), m.machine()->Word32Shl(),
m.machine()->Word32Shr()};
for (size_t n = 0; n < ARRAY_SIZE(shops); n++) {
RawMachineAssemblerTester<int32_t> m(kMachUint32, kMachInt32,
kMachUint32);
MLabel blocka, blockb;
m.Branch(m.Word32Equal(m.Word32Xor(m.Parameter(0),
m.NewNode(shops[n], m.Parameter(1),
m.Parameter(2))),
m.Int32Constant(0)),
&blocka, &blockb);
m.Bind(&blocka);
m.Return(m.Int32Constant(constant));
m.Bind(&blockb);
m.Return(m.Int32Constant(0 - constant));
FOR_UINT32_INPUTS(i) {
FOR_INT32_INPUTS(j) {
FOR_UINT32_SHIFTS(shift) {
int32_t right;
switch (shops[n]->opcode()) {
default:
UNREACHABLE();
case IrOpcode::kWord32Sar:
right = *j >> shift;
break;
case IrOpcode::kWord32Shl:
right = *j << shift;
break;
case IrOpcode::kWord32Shr:
right = static_cast<uint32_t>(*j) >> shift;
break;
}
int32_t expected = ((*i ^ right) == 0) ? constant : 0 - constant;
CHECK_EQ(expected, m.Call(*i, *j, shift));
}
}
}
}
}
}
TEST(RunWord32ShlP) {
{
FOR_UINT32_SHIFTS(shift) {
RawMachineAssemblerTester<uint32_t> m(kMachUint32);
m.Return(m.Word32Shl(m.Parameter(0), m.Int32Constant(shift)));
FOR_UINT32_INPUTS(j) {
uint32_t expected = *j << shift;
CHECK_UINT32_EQ(expected, m.Call(*j));
}
}
}
{
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
bt.AddReturn(m.Word32Shl(bt.param0, bt.param1));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_SHIFTS(shift) {
uint32_t expected = *i << shift;
CHECK_UINT32_EQ(expected, bt.call(*i, shift));
}
}
}
}
TEST(RunWord32ShlInComparison) {
{
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
bt.AddReturn(
m.Word32Equal(m.Word32Shl(bt.param0, bt.param1), m.Int32Constant(0)));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_SHIFTS(shift) {
uint32_t expected = 0 == (*i << shift);
CHECK_UINT32_EQ(expected, bt.call(*i, shift));
}
}
}
{
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
bt.AddReturn(
m.Word32Equal(m.Int32Constant(0), m.Word32Shl(bt.param0, bt.param1)));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_SHIFTS(shift) {
uint32_t expected = 0 == (*i << shift);
CHECK_UINT32_EQ(expected, bt.call(*i, shift));
}
}
}
{
FOR_UINT32_SHIFTS(shift) {
RawMachineAssemblerTester<int32_t> m(kMachUint32);
m.Return(
m.Word32Equal(m.Int32Constant(0),
m.Word32Shl(m.Parameter(0), m.Int32Constant(shift))));
FOR_UINT32_INPUTS(i) {
uint32_t expected = 0 == (*i << shift);
CHECK_UINT32_EQ(expected, m.Call(*i));
}
}
}
{
FOR_UINT32_SHIFTS(shift) {
RawMachineAssemblerTester<int32_t> m(kMachUint32);
m.Return(
m.Word32Equal(m.Word32Shl(m.Parameter(0), m.Int32Constant(shift)),
m.Int32Constant(0)));
FOR_UINT32_INPUTS(i) {
uint32_t expected = 0 == (*i << shift);
CHECK_UINT32_EQ(expected, m.Call(*i));
}
}
}
}
TEST(RunWord32ShrP) {
{
FOR_UINT32_SHIFTS(shift) {
RawMachineAssemblerTester<uint32_t> m(kMachUint32);
m.Return(m.Word32Shr(m.Parameter(0), m.Int32Constant(shift)));
FOR_UINT32_INPUTS(j) {
uint32_t expected = *j >> shift;
CHECK_UINT32_EQ(expected, m.Call(*j));
}
}
}
{
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
bt.AddReturn(m.Word32Shr(bt.param0, bt.param1));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_SHIFTS(shift) {
uint32_t expected = *i >> shift;
CHECK_UINT32_EQ(expected, bt.call(*i, shift));
}
}
CHECK_EQ(0x00010000, bt.call(0x80000000, 15));
}
}
TEST(RunWord32ShrInComparison) {
{
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
bt.AddReturn(
m.Word32Equal(m.Word32Shr(bt.param0, bt.param1), m.Int32Constant(0)));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_SHIFTS(shift) {
uint32_t expected = 0 == (*i >> shift);
CHECK_UINT32_EQ(expected, bt.call(*i, shift));
}
}
}
{
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
bt.AddReturn(
m.Word32Equal(m.Int32Constant(0), m.Word32Shr(bt.param0, bt.param1)));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_SHIFTS(shift) {
uint32_t expected = 0 == (*i >> shift);
CHECK_UINT32_EQ(expected, bt.call(*i, shift));
}
}
}
{
FOR_UINT32_SHIFTS(shift) {
RawMachineAssemblerTester<int32_t> m(kMachUint32);
m.Return(
m.Word32Equal(m.Int32Constant(0),
m.Word32Shr(m.Parameter(0), m.Int32Constant(shift))));
FOR_UINT32_INPUTS(i) {
uint32_t expected = 0 == (*i >> shift);
CHECK_UINT32_EQ(expected, m.Call(*i));
}
}
}
{
FOR_UINT32_SHIFTS(shift) {
RawMachineAssemblerTester<int32_t> m(kMachUint32);
m.Return(
m.Word32Equal(m.Word32Shr(m.Parameter(0), m.Int32Constant(shift)),
m.Int32Constant(0)));
FOR_UINT32_INPUTS(i) {
uint32_t expected = 0 == (*i >> shift);
CHECK_UINT32_EQ(expected, m.Call(*i));
}
}
}
}
TEST(RunWord32SarP) {
{
FOR_INT32_SHIFTS(shift) {
RawMachineAssemblerTester<int32_t> m(kMachInt32);
m.Return(m.Word32Sar(m.Parameter(0), m.Int32Constant(shift)));
FOR_INT32_INPUTS(j) {
int32_t expected = *j >> shift;
CHECK_EQ(expected, m.Call(*j));
}
}
}
{
RawMachineAssemblerTester<int32_t> m;
Int32BinopTester bt(&m);
bt.AddReturn(m.Word32Sar(bt.param0, bt.param1));
FOR_INT32_INPUTS(i) {
FOR_INT32_SHIFTS(shift) {
int32_t expected = *i >> shift;
CHECK_EQ(expected, bt.call(*i, shift));
}
}
CHECK_EQ(0xFFFF0000, bt.call(0x80000000, 15));
}
}
TEST(RunWord32SarInComparison) {
{
RawMachineAssemblerTester<int32_t> m;
Int32BinopTester bt(&m);
bt.AddReturn(
m.Word32Equal(m.Word32Sar(bt.param0, bt.param1), m.Int32Constant(0)));
FOR_INT32_INPUTS(i) {
FOR_INT32_SHIFTS(shift) {
int32_t expected = 0 == (*i >> shift);
CHECK_EQ(expected, bt.call(*i, shift));
}
}
}
{
RawMachineAssemblerTester<int32_t> m;
Int32BinopTester bt(&m);
bt.AddReturn(
m.Word32Equal(m.Int32Constant(0), m.Word32Sar(bt.param0, bt.param1)));
FOR_INT32_INPUTS(i) {
FOR_INT32_SHIFTS(shift) {
int32_t expected = 0 == (*i >> shift);
CHECK_EQ(expected, bt.call(*i, shift));
}
}
}
{
FOR_INT32_SHIFTS(shift) {
RawMachineAssemblerTester<int32_t> m(kMachInt32);
m.Return(
m.Word32Equal(m.Int32Constant(0),
m.Word32Sar(m.Parameter(0), m.Int32Constant(shift))));
FOR_INT32_INPUTS(i) {
int32_t expected = 0 == (*i >> shift);
CHECK_EQ(expected, m.Call(*i));
}
}
}
{
FOR_INT32_SHIFTS(shift) {
RawMachineAssemblerTester<int32_t> m(kMachInt32);
m.Return(
m.Word32Equal(m.Word32Sar(m.Parameter(0), m.Int32Constant(shift)),
m.Int32Constant(0)));
FOR_INT32_INPUTS(i) {
uint32_t expected = 0 == (*i >> shift);
CHECK_EQ(expected, m.Call(*i));
}
}
}
}
TEST(RunWord32RorP) {
{
FOR_UINT32_SHIFTS(shift) {
RawMachineAssemblerTester<int32_t> m(kMachUint32);
m.Return(m.Word32Ror(m.Parameter(0), m.Int32Constant(shift)));
FOR_UINT32_INPUTS(j) {
int32_t expected = bits::RotateRight32(*j, shift);
CHECK_EQ(expected, m.Call(*j));
}
}
}
{
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
bt.AddReturn(m.Word32Ror(bt.param0, bt.param1));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_SHIFTS(shift) {
uint32_t expected = bits::RotateRight32(*i, shift);
CHECK_UINT32_EQ(expected, bt.call(*i, shift));
}
}
}
}
TEST(RunWord32RorInComparison) {
{
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
bt.AddReturn(
m.Word32Equal(m.Word32Ror(bt.param0, bt.param1), m.Int32Constant(0)));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_SHIFTS(shift) {
uint32_t expected = 0 == bits::RotateRight32(*i, shift);
CHECK_UINT32_EQ(expected, bt.call(*i, shift));
}
}
}
{
RawMachineAssemblerTester<int32_t> m;
Uint32BinopTester bt(&m);
bt.AddReturn(
m.Word32Equal(m.Int32Constant(0), m.Word32Ror(bt.param0, bt.param1)));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_SHIFTS(shift) {
uint32_t expected = 0 == bits::RotateRight32(*i, shift);
CHECK_UINT32_EQ(expected, bt.call(*i, shift));
}
}
}
{
FOR_UINT32_SHIFTS(shift) {
RawMachineAssemblerTester<int32_t> m(kMachUint32);
m.Return(
m.Word32Equal(m.Int32Constant(0),
m.Word32Ror(m.Parameter(0), m.Int32Constant(shift))));
FOR_UINT32_INPUTS(i) {
uint32_t expected = 0 == bits::RotateRight32(*i, shift);
CHECK_UINT32_EQ(expected, m.Call(*i));
}
}
}
{
FOR_UINT32_SHIFTS(shift) {
RawMachineAssemblerTester<int32_t> m(kMachUint32);
m.Return(
m.Word32Equal(m.Word32Ror(m.Parameter(0), m.Int32Constant(shift)),
m.Int32Constant(0)));
FOR_UINT32_INPUTS(i) {
uint32_t expected = 0 == bits::RotateRight32(*i, shift);
CHECK_UINT32_EQ(expected, m.Call(*i));
}
}
}
}
TEST(RunWord32NotP) {
RawMachineAssemblerTester<int32_t> m(kMachInt32);
m.Return(m.Word32Not(m.Parameter(0)));
FOR_INT32_INPUTS(i) {
int expected = ~(*i);
CHECK_EQ(expected, m.Call(*i));
}
}
TEST(RunInt32NegP) {
RawMachineAssemblerTester<int32_t> m(kMachInt32);
m.Return(m.Int32Neg(m.Parameter(0)));
FOR_INT32_INPUTS(i) {
int expected = -*i;
CHECK_EQ(expected, m.Call(*i));
}
}
TEST(RunWord32EqualAndWord32SarP) {
{
RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32, kMachUint32);
m.Return(m.Word32Equal(m.Parameter(0),
m.Word32Sar(m.Parameter(1), m.Parameter(2))));
FOR_INT32_INPUTS(i) {
FOR_INT32_INPUTS(j) {
FOR_UINT32_SHIFTS(shift) {
int32_t expected = (*i == (*j >> shift));
CHECK_EQ(expected, m.Call(*i, *j, shift));
}
}
}
}
{
RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachUint32, kMachInt32);
m.Return(m.Word32Equal(m.Word32Sar(m.Parameter(0), m.Parameter(1)),
m.Parameter(2)));
FOR_INT32_INPUTS(i) {
FOR_UINT32_SHIFTS(shift) {
FOR_INT32_INPUTS(k) {
int32_t expected = ((*i >> shift) == *k);
CHECK_EQ(expected, m.Call(*i, shift, *k));
}
}
}
}
}
TEST(RunWord32EqualAndWord32ShlP) {
{
RawMachineAssemblerTester<int32_t> m(kMachUint32, kMachUint32, kMachUint32);
m.Return(m.Word32Equal(m.Parameter(0),
m.Word32Shl(m.Parameter(1), m.Parameter(2))));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
FOR_UINT32_SHIFTS(shift) {
int32_t expected = (*i == (*j << shift));
CHECK_EQ(expected, m.Call(*i, *j, shift));
}
}
}
}
{
RawMachineAssemblerTester<int32_t> m(kMachUint32, kMachUint32, kMachUint32);
m.Return(m.Word32Equal(m.Word32Shl(m.Parameter(0), m.Parameter(1)),
m.Parameter(2)));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_SHIFTS(shift) {
FOR_UINT32_INPUTS(k) {
int32_t expected = ((*i << shift) == *k);
CHECK_EQ(expected, m.Call(*i, shift, *k));
}
}
}
}
}
TEST(RunWord32EqualAndWord32ShrP) {
{
RawMachineAssemblerTester<int32_t> m(kMachUint32, kMachUint32, kMachUint32);
m.Return(m.Word32Equal(m.Parameter(0),
m.Word32Shr(m.Parameter(1), m.Parameter(2))));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
FOR_UINT32_SHIFTS(shift) {
int32_t expected = (*i == (*j >> shift));
CHECK_EQ(expected, m.Call(*i, *j, shift));
}
}
}
}
{
RawMachineAssemblerTester<int32_t> m(kMachUint32, kMachUint32, kMachUint32);
m.Return(m.Word32Equal(m.Word32Shr(m.Parameter(0), m.Parameter(1)),
m.Parameter(2)));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_SHIFTS(shift) {
FOR_UINT32_INPUTS(k) {
int32_t expected = ((*i >> shift) == *k);
CHECK_EQ(expected, m.Call(*i, shift, *k));
}
}
}
}
}
TEST(RunDeadNodes) {
for (int i = 0; true; i++) {
RawMachineAssemblerTester<int32_t> m(i == 5 ? kMachInt32 : kMachNone);
int constant = 0x55 + i;
switch (i) {
case 0:
m.Int32Constant(44);
break;
case 1:
m.StringConstant("unused");
break;
case 2:
m.NumberConstant(11.1);
break;
case 3:
m.PointerConstant(&constant);
break;
case 4:
m.LoadFromPointer(&constant, kMachInt32);
break;
case 5:
m.Parameter(0);
break;
default:
return;
}
m.Return(m.Int32Constant(constant));
if (i != 5) {
CHECK_EQ(constant, m.Call());
} else {
CHECK_EQ(constant, m.Call(0));
}
}
}
TEST(RunDeadInt32Binops) {
RawMachineAssemblerTester<int32_t> m;
Operator* ops[] = {
m.machine()->Word32And(), m.machine()->Word32Or(),
m.machine()->Word32Xor(), m.machine()->Word32Shl(),
m.machine()->Word32Shr(), m.machine()->Word32Sar(),
m.machine()->Word32Ror(), m.machine()->Word32Equal(),
m.machine()->Int32Add(), m.machine()->Int32Sub(),
m.machine()->Int32Mul(), m.machine()->Int32Div(),
m.machine()->Int32UDiv(), m.machine()->Int32Mod(),
m.machine()->Int32UMod(), m.machine()->Int32LessThan(),
m.machine()->Int32LessThanOrEqual(), m.machine()->Uint32LessThan(),
m.machine()->Uint32LessThanOrEqual(), NULL};
for (int i = 0; ops[i] != NULL; i++) {
RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32);
int constant = 0x55555 + i;
m.NewNode(ops[i], m.Parameter(0), m.Parameter(1));
m.Return(m.Int32Constant(constant));
CHECK_EQ(constant, m.Call(1, 1));
}
}
template <typename Type, typename CType>
static void RunLoadImmIndex(MachineType rep) {
const int kNumElems = 3;
CType buffer[kNumElems];
// initialize the buffer with raw data.
byte* raw = reinterpret_cast<byte*>(buffer);
for (size_t i = 0; i < sizeof(buffer); i++) {
raw[i] = static_cast<byte>((i + sizeof(buffer)) ^ 0xAA);
}
// Test with various large and small offsets.
for (int offset = -1; offset <= 200000; offset *= -5) {
for (int i = 0; i < kNumElems; i++) {
RawMachineAssemblerTester<Type> m;
Node* base = m.PointerConstant(buffer - offset);
Node* index = m.Int32Constant((offset + i) * sizeof(buffer[0]));
m.Return(m.Load(rep, base, index));
Type expected = buffer[i];
Type actual = static_cast<CType>(m.Call());
CHECK_EQ(expected, actual);
printf("XXX\n");
}
}
}
TEST(RunLoadImmIndex) {
RunLoadImmIndex<int8_t, uint8_t>(kMachInt8);
RunLoadImmIndex<int16_t, uint16_t>(kMachInt16);
RunLoadImmIndex<int32_t, uint32_t>(kMachInt32);
RunLoadImmIndex<int32_t*, int32_t*>(kMachAnyTagged);
// TODO(titzer): test kRepBit loads
// TODO(titzer): test kMachFloat64 loads
// TODO(titzer): test various indexing modes.
}
template <typename CType>
static void RunLoadStore(MachineType rep) {
const int kNumElems = 4;
CType buffer[kNumElems];
for (int32_t x = 0; x < kNumElems; x++) {
int32_t y = kNumElems - x - 1;
// initialize the buffer with raw data.
byte* raw = reinterpret_cast<byte*>(buffer);
for (size_t i = 0; i < sizeof(buffer); i++) {
raw[i] = static_cast<byte>((i + sizeof(buffer)) ^ 0xAA);
}
RawMachineAssemblerTester<int32_t> m;
int32_t OK = 0x29000 + x;
Node* base = m.PointerConstant(buffer);
Node* index0 = m.Int32Constant(x * sizeof(buffer[0]));
Node* load = m.Load(rep, base, index0);
Node* index1 = m.Int32Constant(y * sizeof(buffer[0]));
m.Store(rep, base, index1, load);
m.Return(m.Int32Constant(OK));
CHECK_NE(buffer[x], buffer[y]);
CHECK_EQ(OK, m.Call());
CHECK_EQ(buffer[x], buffer[y]);
}
}
TEST(RunLoadStore) {
RunLoadStore<int8_t>(kMachInt8);
RunLoadStore<int16_t>(kMachInt16);
RunLoadStore<int32_t>(kMachInt32);
RunLoadStore<void*>(kMachAnyTagged);
RunLoadStore<double>(kMachFloat64);
}
TEST(RunFloat64Binop) {
RawMachineAssemblerTester<int32_t> m;
double result;
Operator* ops[] = {m.machine()->Float64Add(), m.machine()->Float64Sub(),
m.machine()->Float64Mul(), m.machine()->Float64Div(),
m.machine()->Float64Mod(), NULL};
double inf = V8_INFINITY;
Operator* inputs[] = {
m.common()->Float64Constant(0), m.common()->Float64Constant(1),
m.common()->Float64Constant(1), m.common()->Float64Constant(0),
m.common()->Float64Constant(0), m.common()->Float64Constant(-1),
m.common()->Float64Constant(-1), m.common()->Float64Constant(0),
m.common()->Float64Constant(0.22), m.common()->Float64Constant(-1.22),
m.common()->Float64Constant(-1.22), m.common()->Float64Constant(0.22),
m.common()->Float64Constant(inf), m.common()->Float64Constant(0.22),
m.common()->Float64Constant(inf), m.common()->Float64Constant(-inf),
NULL};
for (int i = 0; ops[i] != NULL; i++) {
for (int j = 0; inputs[j] != NULL; j += 2) {
RawMachineAssemblerTester<int32_t> m;
Node* a = m.NewNode(inputs[j]);
Node* b = m.NewNode(inputs[j + 1]);
Node* binop = m.NewNode(ops[i], a, b);
Node* base = m.PointerConstant(&result);
Node* zero = m.Int32Constant(0);
m.Store(kMachFloat64, base, zero, binop);
m.Return(m.Int32Constant(i + j));
CHECK_EQ(i + j, m.Call());
}
}
}
TEST(RunDeadFloat64Binops) {
RawMachineAssemblerTester<int32_t> m;
Operator* ops[] = {m.machine()->Float64Add(), m.machine()->Float64Sub(),
m.machine()->Float64Mul(), m.machine()->Float64Div(),
m.machine()->Float64Mod(), NULL};
for (int i = 0; ops[i] != NULL; i++) {
RawMachineAssemblerTester<int32_t> m;
int constant = 0x53355 + i;
m.NewNode(ops[i], m.Float64Constant(0.1), m.Float64Constant(1.11));
m.Return(m.Int32Constant(constant));
CHECK_EQ(constant, m.Call());
}
}
TEST(RunFloat64AddP) {
RawMachineAssemblerTester<int32_t> m;
Float64BinopTester bt(&m);
bt.AddReturn(m.Float64Add(bt.param0, bt.param1));
FOR_FLOAT64_INPUTS(pl) {
FOR_FLOAT64_INPUTS(pr) {
double expected = *pl + *pr;
CHECK_EQ(expected, bt.call(*pl, *pr));
}
}
}
TEST(RunFloat64SubP) {
RawMachineAssemblerTester<int32_t> m;
Float64BinopTester bt(&m);
bt.AddReturn(m.Float64Sub(bt.param0, bt.param1));
FOR_FLOAT64_INPUTS(pl) {
FOR_FLOAT64_INPUTS(pr) {
double expected = *pl - *pr;
CHECK_EQ(expected, bt.call(*pl, *pr));
}
}
}
TEST(RunFloat64SubImm1) {
double input = 0.0;
double output = 0.0;
FOR_FLOAT64_INPUTS(i) {
RawMachineAssemblerTester<int32_t> m;
Node* t0 = m.LoadFromPointer(&input, kMachFloat64);
Node* t1 = m.Float64Sub(m.Float64Constant(*i), t0);
m.StoreToPointer(&output, kMachFloat64, t1);
m.Return(m.Int32Constant(0));
FOR_FLOAT64_INPUTS(j) {
input = *j;
double expected = *i - input;
CHECK_EQ(0, m.Call());
CHECK_EQ(expected, output);
}
}
}
TEST(RunFloat64SubImm2) {
double input = 0.0;
double output = 0.0;
FOR_FLOAT64_INPUTS(i) {
RawMachineAssemblerTester<int32_t> m;
Node* t0 = m.LoadFromPointer(&input, kMachFloat64);
Node* t1 = m.Float64Sub(t0, m.Float64Constant(*i));
m.StoreToPointer(&output, kMachFloat64, t1);
m.Return(m.Int32Constant(0));
FOR_FLOAT64_INPUTS(j) {
input = *j;
double expected = input - *i;
CHECK_EQ(0, m.Call());
CHECK_EQ(expected, output);
}
}
}
TEST(RunFloat64MulP) {
RawMachineAssemblerTester<int32_t> m;
Float64BinopTester bt(&m);
bt.AddReturn(m.Float64Mul(bt.param0, bt.param1));
FOR_FLOAT64_INPUTS(pl) {
FOR_FLOAT64_INPUTS(pr) {
double expected = *pl * *pr;
CHECK_EQ(expected, bt.call(*pl, *pr));
}
}
}
TEST(RunFloat64MulAndFloat64AddP) {
double input_a = 0.0;
double input_b = 0.0;
double input_c = 0.0;
double output = 0.0;
{
RawMachineAssemblerTester<int32_t> m;
Node* a = m.LoadFromPointer(&input_a, kMachFloat64);
Node* b = m.LoadFromPointer(&input_b, kMachFloat64);
Node* c = m.LoadFromPointer(&input_c, kMachFloat64);
m.StoreToPointer(&output, kMachFloat64,
m.Float64Add(m.Float64Mul(a, b), c));
m.Return(m.Int32Constant(0));
FOR_FLOAT64_INPUTS(i) {
FOR_FLOAT64_INPUTS(j) {
FOR_FLOAT64_INPUTS(k) {
input_a = *i;
input_b = *j;
input_c = *k;
volatile double temp = input_a * input_b;
volatile double expected = temp + input_c;
CHECK_EQ(0, m.Call());
CHECK_EQ(expected, output);
}
}
}
}
{
RawMachineAssemblerTester<int32_t> m;
Node* a = m.LoadFromPointer(&input_a, kMachFloat64);
Node* b = m.LoadFromPointer(&input_b, kMachFloat64);
Node* c = m.LoadFromPointer(&input_c, kMachFloat64);
m.StoreToPointer(&output, kMachFloat64,
m.Float64Add(a, m.Float64Mul(b, c)));
m.Return(m.Int32Constant(0));
FOR_FLOAT64_INPUTS(i) {
FOR_FLOAT64_INPUTS(j) {
FOR_FLOAT64_INPUTS(k) {
input_a = *i;
input_b = *j;
input_c = *k;
volatile double temp = input_b * input_c;
volatile double expected = input_a + temp;
CHECK_EQ(0, m.Call());
CHECK_EQ(expected, output);
}
}
}
}
}
TEST(RunFloat64MulAndFloat64SubP) {
double input_a = 0.0;
double input_b = 0.0;
double input_c = 0.0;
double output = 0.0;
RawMachineAssemblerTester<int32_t> m;
Node* a = m.LoadFromPointer(&input_a, kMachFloat64);
Node* b = m.LoadFromPointer(&input_b, kMachFloat64);
Node* c = m.LoadFromPointer(&input_c, kMachFloat64);
m.StoreToPointer(&output, kMachFloat64, m.Float64Sub(a, m.Float64Mul(b, c)));
m.Return(m.Int32Constant(0));
FOR_FLOAT64_INPUTS(i) {
FOR_FLOAT64_INPUTS(j) {
FOR_FLOAT64_INPUTS(k) {
input_a = *i;
input_b = *j;
input_c = *k;
volatile double temp = input_b * input_c;
volatile double expected = input_a - temp;
CHECK_EQ(0, m.Call());
CHECK_EQ(expected, output);
}
}
}
}
TEST(RunFloat64MulImm) {
double input = 0.0;
double output = 0.0;
{
FOR_FLOAT64_INPUTS(i) {
RawMachineAssemblerTester<int32_t> m;
Node* t0 = m.LoadFromPointer(&input, kMachFloat64);
Node* t1 = m.Float64Mul(m.Float64Constant(*i), t0);
m.StoreToPointer(&output, kMachFloat64, t1);
m.Return(m.Int32Constant(0));
FOR_FLOAT64_INPUTS(j) {
input = *j;
double expected = *i * input;
CHECK_EQ(0, m.Call());
CHECK_EQ(expected, output);
}
}
}
{
FOR_FLOAT64_INPUTS(i) {
RawMachineAssemblerTester<int32_t> m;
Node* t0 = m.LoadFromPointer(&input, kMachFloat64);
Node* t1 = m.Float64Mul(t0, m.Float64Constant(*i));
m.StoreToPointer(&output, kMachFloat64, t1);
m.Return(m.Int32Constant(0));
FOR_FLOAT64_INPUTS(j) {
input = *j;
double expected = input * *i;
CHECK_EQ(0, m.Call());
CHECK_EQ(expected, output);
}
}
}
}
TEST(RunFloat64DivP) {
RawMachineAssemblerTester<int32_t> m;
Float64BinopTester bt(&m);
bt.AddReturn(m.Float64Div(bt.param0, bt.param1));
FOR_FLOAT64_INPUTS(pl) {
FOR_FLOAT64_INPUTS(pr) {
double expected = *pl / *pr;
CHECK_EQ(expected, bt.call(*pl, *pr));
}
}
}
TEST(RunFloat64ModP) {
RawMachineAssemblerTester<int32_t> m;
Float64BinopTester bt(&m);
bt.AddReturn(m.Float64Mod(bt.param0, bt.param1));
FOR_FLOAT64_INPUTS(i) {
FOR_FLOAT64_INPUTS(j) {
double expected = modulo(*i, *j);
double found = bt.call(*i, *j);
CHECK_EQ(expected, found);
}
}
}
TEST(RunChangeInt32ToFloat64_A) {
RawMachineAssemblerTester<int32_t> m;
int32_t magic = 0x986234;
double result = 0;
Node* convert = m.ChangeInt32ToFloat64(m.Int32Constant(magic));
m.Store(kMachFloat64, m.PointerConstant(&result), m.Int32Constant(0),
convert);
m.Return(m.Int32Constant(magic));
CHECK_EQ(magic, m.Call());
CHECK_EQ(static_cast<double>(magic), result);
}
TEST(RunChangeInt32ToFloat64_B) {
RawMachineAssemblerTester<int32_t> m(kMachInt32);
double output = 0;
Node* convert = m.ChangeInt32ToFloat64(m.Parameter(0));
m.Store(kMachFloat64, m.PointerConstant(&output), m.Int32Constant(0),
convert);
m.Return(m.Parameter(0));
FOR_INT32_INPUTS(i) {
int32_t expect = *i;
CHECK_EQ(expect, m.Call(expect));
CHECK_EQ(static_cast<double>(expect), output);
}
}
TEST(RunChangeUint32ToFloat64_B) {
RawMachineAssemblerTester<int32_t> m(kMachUint32);
double output = 0;
Node* convert = m.ChangeUint32ToFloat64(m.Parameter(0));
m.Store(kMachFloat64, m.PointerConstant(&output), m.Int32Constant(0),
convert);
m.Return(m.Parameter(0));
FOR_UINT32_INPUTS(i) {
uint32_t expect = *i;
CHECK_EQ(expect, m.Call(expect));
CHECK_EQ(static_cast<double>(expect), output);
}
}
TEST(RunChangeFloat64ToInt32_A) {
RawMachineAssemblerTester<int32_t> m;
int32_t magic = 0x786234;
double input = 11.1;
int32_t result = 0;
m.Store(kMachInt32, m.PointerConstant(&result), m.Int32Constant(0),
m.ChangeFloat64ToInt32(m.Float64Constant(input)));
m.Return(m.Int32Constant(magic));
CHECK_EQ(magic, m.Call());
CHECK_EQ(static_cast<int32_t>(input), result);
}
TEST(RunChangeFloat64ToInt32_B) {
RawMachineAssemblerTester<int32_t> m;
double input = 0;
int32_t output = 0;
Node* load =
m.Load(kMachFloat64, m.PointerConstant(&input), m.Int32Constant(0));
Node* convert = m.ChangeFloat64ToInt32(load);
m.Store(kMachInt32, m.PointerConstant(&output), m.Int32Constant(0), convert);
m.Return(convert);
{
FOR_INT32_INPUTS(i) {
input = *i;
int32_t expect = *i;
CHECK_EQ(expect, m.Call());
CHECK_EQ(expect, output);
}
}
// Check various powers of 2.
for (int32_t n = 1; n < 31; ++n) {
{
input = 1 << n;
int32_t expect = static_cast<int32_t>(input);
CHECK_EQ(expect, m.Call());
CHECK_EQ(expect, output);
}
{
input = 3 << n;
int32_t expect = static_cast<int32_t>(input);
CHECK_EQ(expect, m.Call());
CHECK_EQ(expect, output);
}
}
// Note we don't check fractional inputs, because these Convert operators
// really should be Change operators.
}
TEST(RunChangeFloat64ToUint32_B) {
RawMachineAssemblerTester<int32_t> m;
double input = 0;
int32_t output = 0;
Node* load =
m.Load(kMachFloat64, m.PointerConstant(&input), m.Int32Constant(0));
Node* convert = m.ChangeFloat64ToUint32(load);
m.Store(kMachInt32, m.PointerConstant(&output), m.Int32Constant(0), convert);
m.Return(convert);
{
FOR_UINT32_INPUTS(i) {
input = *i;
// TODO(titzer): add a CheckEqualsHelper overload for uint32_t.
int32_t expect = static_cast<int32_t>(*i);
CHECK_EQ(expect, m.Call());
CHECK_EQ(expect, output);
}
}
// Check various powers of 2.
for (int32_t n = 1; n < 31; ++n) {
{
input = 1u << n;
int32_t expect = static_cast<int32_t>(static_cast<uint32_t>(input));
CHECK_EQ(expect, m.Call());
CHECK_EQ(expect, output);
}
{
input = 3u << n;
int32_t expect = static_cast<int32_t>(static_cast<uint32_t>(input));
CHECK_EQ(expect, m.Call());
CHECK_EQ(expect, output);
}
}
// Note we don't check fractional inputs, because these Convert operators
// really should be Change operators.
}
TEST(RunChangeFloat64ToInt32_spilled) {
RawMachineAssemblerTester<int32_t> m;
const int kNumInputs = 32;
int32_t magic = 0x786234;
double input[kNumInputs];
int32_t result[kNumInputs];
Node* input_node[kNumInputs];
for (int i = 0; i < kNumInputs; i++) {
input_node[i] =
m.Load(kMachFloat64, m.PointerConstant(&input), m.Int32Constant(i * 8));
}
for (int i = 0; i < kNumInputs; i++) {
m.Store(kMachInt32, m.PointerConstant(&result), m.Int32Constant(i * 4),
m.ChangeFloat64ToInt32(input_node[i]));
}
m.Return(m.Int32Constant(magic));
for (int i = 0; i < kNumInputs; i++) {
input[i] = 100.9 + i;
}
CHECK_EQ(magic, m.Call());
for (int i = 0; i < kNumInputs; i++) {
CHECK_EQ(result[i], 100 + i);
}
}
TEST(RunDeadChangeFloat64ToInt32) {
RawMachineAssemblerTester<int32_t> m;
const int magic = 0x88abcda4;
m.ChangeFloat64ToInt32(m.Float64Constant(999.78));
m.Return(m.Int32Constant(magic));
CHECK_EQ(magic, m.Call());
}
TEST(RunDeadChangeInt32ToFloat64) {
RawMachineAssemblerTester<int32_t> m;
const int magic = 0x8834abcd;
m.ChangeInt32ToFloat64(m.Int32Constant(magic - 6888));
m.Return(m.Int32Constant(magic));
CHECK_EQ(magic, m.Call());
}
TEST(RunLoopPhiInduction2) {
RawMachineAssemblerTester<int32_t> m;
int false_val = 0x10777;
// x = false_val; while(false) { x++; } return x;
MLabel header, body, end;
Node* false_node = m.Int32Constant(false_val);
m.Goto(&header);
m.Bind(&header);
Node* phi = m.Phi(false_node, false_node);
m.Branch(m.Int32Constant(0), &body, &end);
m.Bind(&body);
Node* add = m.Int32Add(phi, m.Int32Constant(1));
phi->ReplaceInput(1, add);
m.Goto(&header);
m.Bind(&end);
m.Return(phi);
CHECK_EQ(false_val, m.Call());
}
TEST(RunDoubleDiamond) {
RawMachineAssemblerTester<int32_t> m;
const int magic = 99645;
double buffer = 0.1;
double constant = 99.99;
MLabel blocka, blockb, end;
Node* k1 = m.Float64Constant(constant);
Node* k2 = m.Float64Constant(0 - constant);
m.Branch(m.Int32Constant(0), &blocka, &blockb);
m.Bind(&blocka);
m.Goto(&end);
m.Bind(&blockb);
m.Goto(&end);
m.Bind(&end);
Node* phi = m.Phi(k2, k1);
m.Store(kMachFloat64, m.PointerConstant(&buffer), m.Int32Constant(0), phi);
m.Return(m.Int32Constant(magic));
CHECK_EQ(magic, m.Call());
CHECK_EQ(constant, buffer);
}
TEST(RunRefDiamond) {
RawMachineAssemblerTester<int32_t> m;
const int magic = 99644;
Handle<String> rexpected =
CcTest::i_isolate()->factory()->InternalizeUtf8String("A");
String* buffer;
MLabel blocka, blockb, end;
Node* k1 = m.StringConstant("A");
Node* k2 = m.StringConstant("B");
m.Branch(m.Int32Constant(0), &blocka, &blockb);
m.Bind(&blocka);
m.Goto(&end);
m.Bind(&blockb);
m.Goto(&end);
m.Bind(&end);
Node* phi = m.Phi(k2, k1);
m.Store(kMachAnyTagged, m.PointerConstant(&buffer), m.Int32Constant(0), phi);
m.Return(m.Int32Constant(magic));
CHECK_EQ(magic, m.Call());
CHECK(rexpected->SameValue(buffer));
}
TEST(RunDoubleRefDiamond) {
RawMachineAssemblerTester<int32_t> m;
const int magic = 99648;
double dbuffer = 0.1;
double dconstant = 99.99;
Handle<String> rexpected =
CcTest::i_isolate()->factory()->InternalizeUtf8String("AX");
String* rbuffer;
MLabel blocka, blockb, end;
Node* d1 = m.Float64Constant(dconstant);
Node* d2 = m.Float64Constant(0 - dconstant);
Node* r1 = m.StringConstant("AX");
Node* r2 = m.StringConstant("BX");
m.Branch(m.Int32Constant(0), &blocka, &blockb);
m.Bind(&blocka);
m.Goto(&end);
m.Bind(&blockb);
m.Goto(&end);
m.Bind(&end);
Node* dphi = m.Phi(d2, d1);
Node* rphi = m.Phi(r2, r1);
m.Store(kMachFloat64, m.PointerConstant(&dbuffer), m.Int32Constant(0), dphi);
m.Store(kMachAnyTagged, m.PointerConstant(&rbuffer), m.Int32Constant(0),
rphi);
m.Return(m.Int32Constant(magic));
CHECK_EQ(magic, m.Call());
CHECK_EQ(dconstant, dbuffer);
CHECK(rexpected->SameValue(rbuffer));
}
TEST(RunDoubleRefDoubleDiamond) {
RawMachineAssemblerTester<int32_t> m;
const int magic = 99649;
double dbuffer = 0.1;
double dconstant = 99.997;
Handle<String> rexpected =
CcTest::i_isolate()->factory()->InternalizeUtf8String("AD");
String* rbuffer;
MLabel blocka, blockb, mid, blockd, blocke, end;
Node* d1 = m.Float64Constant(dconstant);
Node* d2 = m.Float64Constant(0 - dconstant);
Node* r1 = m.StringConstant("AD");
Node* r2 = m.StringConstant("BD");
m.Branch(m.Int32Constant(0), &blocka, &blockb);
m.Bind(&blocka);
m.Goto(&mid);
m.Bind(&blockb);
m.Goto(&mid);
m.Bind(&mid);
Node* dphi1 = m.Phi(d2, d1);
Node* rphi1 = m.Phi(r2, r1);
m.Branch(m.Int32Constant(0), &blockd, &blocke);
m.Bind(&blockd);
m.Goto(&end);
m.Bind(&blocke);
m.Goto(&end);
m.Bind(&end);
Node* dphi2 = m.Phi(d1, dphi1);
Node* rphi2 = m.Phi(r1, rphi1);
m.Store(kMachFloat64, m.PointerConstant(&dbuffer), m.Int32Constant(0), dphi2);
m.Store(kMachAnyTagged, m.PointerConstant(&rbuffer), m.Int32Constant(0),
rphi2);
m.Return(m.Int32Constant(magic));
CHECK_EQ(magic, m.Call());
CHECK_EQ(dconstant, dbuffer);
CHECK(rexpected->SameValue(rbuffer));
}
TEST(RunDoubleLoopPhi) {
RawMachineAssemblerTester<int32_t> m;
MLabel header, body, end;
int magic = 99773;
double buffer = 0.99;
double dconstant = 777.1;
Node* zero = m.Int32Constant(0);
Node* dk = m.Float64Constant(dconstant);
m.Goto(&header);
m.Bind(&header);
Node* phi = m.Phi(dk, dk);
phi->ReplaceInput(1, phi);
m.Branch(zero, &body, &end);
m.Bind(&body);
m.Goto(&header);
m.Bind(&end);
m.Store(kMachFloat64, m.PointerConstant(&buffer), m.Int32Constant(0), phi);
m.Return(m.Int32Constant(magic));
CHECK_EQ(magic, m.Call());
}
TEST(RunCountToTenAccRaw) {
RawMachineAssemblerTester<int32_t> m;
Node* zero = m.Int32Constant(0);
Node* ten = m.Int32Constant(10);
Node* one = m.Int32Constant(1);
MLabel header, body, body_cont, end;
m.Goto(&header);
m.Bind(&header);
Node* i = m.Phi(zero, zero);
Node* j = m.Phi(zero, zero);
m.Goto(&body);
m.Bind(&body);
Node* next_i = m.Int32Add(i, one);
Node* next_j = m.Int32Add(j, one);
m.Branch(m.Word32Equal(next_i, ten), &end, &body_cont);
m.Bind(&body_cont);
i->ReplaceInput(1, next_i);
j->ReplaceInput(1, next_j);
m.Goto(&header);
m.Bind(&end);
m.Return(ten);
CHECK_EQ(10, m.Call());
}
TEST(RunCountToTenAccRaw2) {
RawMachineAssemblerTester<int32_t> m;
Node* zero = m.Int32Constant(0);
Node* ten = m.Int32Constant(10);
Node* one = m.Int32Constant(1);
MLabel header, body, body_cont, end;
m.Goto(&header);
m.Bind(&header);
Node* i = m.Phi(zero, zero);
Node* j = m.Phi(zero, zero);
Node* k = m.Phi(zero, zero);
m.Goto(&body);
m.Bind(&body);
Node* next_i = m.Int32Add(i, one);
Node* next_j = m.Int32Add(j, one);
Node* next_k = m.Int32Add(j, one);
m.Branch(m.Word32Equal(next_i, ten), &end, &body_cont);
m.Bind(&body_cont);
i->ReplaceInput(1, next_i);
j->ReplaceInput(1, next_j);
k->ReplaceInput(1, next_k);
m.Goto(&header);
m.Bind(&end);
m.Return(ten);
CHECK_EQ(10, m.Call());
}
TEST(RunAddTree) {
RawMachineAssemblerTester<int32_t> m;
int32_t inputs[] = {11, 12, 13, 14, 15, 16, 17, 18};
Node* base = m.PointerConstant(inputs);
Node* n0 = m.Load(kMachInt32, base, m.Int32Constant(0 * sizeof(int32_t)));
Node* n1 = m.Load(kMachInt32, base, m.Int32Constant(1 * sizeof(int32_t)));
Node* n2 = m.Load(kMachInt32, base, m.Int32Constant(2 * sizeof(int32_t)));
Node* n3 = m.Load(kMachInt32, base, m.Int32Constant(3 * sizeof(int32_t)));
Node* n4 = m.Load(kMachInt32, base, m.Int32Constant(4 * sizeof(int32_t)));
Node* n5 = m.Load(kMachInt32, base, m.Int32Constant(5 * sizeof(int32_t)));
Node* n6 = m.Load(kMachInt32, base, m.Int32Constant(6 * sizeof(int32_t)));
Node* n7 = m.Load(kMachInt32, base, m.Int32Constant(7 * sizeof(int32_t)));
Node* i1 = m.Int32Add(n0, n1);
Node* i2 = m.Int32Add(n2, n3);
Node* i3 = m.Int32Add(n4, n5);
Node* i4 = m.Int32Add(n6, n7);
Node* i5 = m.Int32Add(i1, i2);
Node* i6 = m.Int32Add(i3, i4);
Node* i7 = m.Int32Add(i5, i6);
m.Return(i7);
CHECK_EQ(116, m.Call());
}
#if MACHINE_ASSEMBLER_SUPPORTS_CALL_C
static int Seven() { return 7; }
static int UnaryMinus(int a) { return -a; }
static int APlusTwoB(int a, int b) { return a + 2 * b; }
TEST(RunCallSeven) {
for (int i = 0; i < 2; i++) {
bool call_direct = i == 0;
void* function_address =
reinterpret_cast<void*>(reinterpret_cast<intptr_t>(&Seven));
RawMachineAssemblerTester<int32_t> m;
Node** args = NULL;
MachineType* arg_types = NULL;
Node* function =
call_direct ? m.PointerConstant(function_address)
: m.LoadFromPointer(&function_address,
MachineOperatorBuilder::pointer_rep());
m.Return(m.CallC(function, kMachInt32, arg_types, args, 0));
CHECK_EQ(7, m.Call());
}
}
TEST(RunCallUnaryMinus) {
for (int i = 0; i < 2; i++) {
bool call_direct = i == 0;
void* function_address =
reinterpret_cast<void*>(reinterpret_cast<intptr_t>(&UnaryMinus));
RawMachineAssemblerTester<int32_t> m(kMachInt32);
Node* args[] = {m.Parameter(0)};
MachineType arg_types[] = {kMachInt32};
Node* function =
call_direct ? m.PointerConstant(function_address)
: m.LoadFromPointer(&function_address,
MachineOperatorBuilder::pointer_rep());
m.Return(m.CallC(function, kMachInt32, arg_types, args, 1));
FOR_INT32_INPUTS(i) {
int a = *i;
CHECK_EQ(-a, m.Call(a));
}
}
}
TEST(RunCallAPlusTwoB) {
for (int i = 0; i < 2; i++) {
bool call_direct = i == 0;
void* function_address =
reinterpret_cast<void*>(reinterpret_cast<intptr_t>(&APlusTwoB));
RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32);
Node* args[] = {m.Parameter(0), m.Parameter(1)};
MachineType arg_types[] = {kMachInt32, kMachInt32};
Node* function =
call_direct ? m.PointerConstant(function_address)
: m.LoadFromPointer(&function_address,
MachineOperatorBuilder::pointer_rep());
m.Return(m.CallC(function, kMachInt32, arg_types, args, 2));
FOR_INT32_INPUTS(i) {
FOR_INT32_INPUTS(j) {
int a = *i;
int b = *j;
int result = m.Call(a, b);
CHECK_EQ(a + 2 * b, result);
}
}
}
}
#endif // MACHINE_ASSEMBLER_SUPPORTS_CALL_C
static const int kFloat64CompareHelperTestCases = 15;
static const int kFloat64CompareHelperNodeType = 4;
static int Float64CompareHelper(RawMachineAssemblerTester<int32_t>* m,
int test_case, int node_type, double x,
double y) {
static double buffer[2];
buffer[0] = x;
buffer[1] = y;
CHECK(0 <= test_case && test_case < kFloat64CompareHelperTestCases);
CHECK(0 <= node_type && node_type < kFloat64CompareHelperNodeType);
CHECK(x < y);
bool load_a = node_type / 2 == 1;
bool load_b = node_type % 2 == 1;
Node* a = load_a ? m->Load(kMachFloat64, m->PointerConstant(&buffer[0]))
: m->Float64Constant(x);
Node* b = load_b ? m->Load(kMachFloat64, m->PointerConstant(&buffer[1]))
: m->Float64Constant(y);
Node* cmp = NULL;
bool expected = false;
switch (test_case) {
// Equal tests.
case 0:
cmp = m->Float64Equal(a, b);
expected = false;
break;
case 1:
cmp = m->Float64Equal(a, a);
expected = true;
break;
// LessThan tests.
case 2:
cmp = m->Float64LessThan(a, b);
expected = true;
break;
case 3:
cmp = m->Float64LessThan(b, a);
expected = false;
break;
case 4:
cmp = m->Float64LessThan(a, a);
expected = false;
break;
// LessThanOrEqual tests.
case 5:
cmp = m->Float64LessThanOrEqual(a, b);
expected = true;
break;
case 6:
cmp = m->Float64LessThanOrEqual(b, a);
expected = false;
break;
case 7:
cmp = m->Float64LessThanOrEqual(a, a);
expected = true;
break;
// NotEqual tests.
case 8:
cmp = m->Float64NotEqual(a, b);
expected = true;
break;
case 9:
cmp = m->Float64NotEqual(b, a);
expected = true;
break;
case 10:
cmp = m->Float64NotEqual(a, a);
expected = false;
break;
// GreaterThan tests.
case 11:
cmp = m->Float64GreaterThan(a, a);
expected = false;
break;
case 12:
cmp = m->Float64GreaterThan(a, b);
expected = false;
break;
// GreaterThanOrEqual tests.
case 13:
cmp = m->Float64GreaterThanOrEqual(a, a);
expected = true;
break;
case 14:
cmp = m->Float64GreaterThanOrEqual(b, a);
expected = true;
break;
default:
UNREACHABLE();
}
m->Return(cmp);
return expected;
}
TEST(RunFloat64Compare) {
double inf = V8_INFINITY;
// All pairs (a1, a2) are of the form a1 < a2.
double inputs[] = {0.0, 1.0, -1.0, 0.22, -1.22, 0.22,
-inf, 0.22, 0.22, inf, -inf, inf};
for (int test = 0; test < kFloat64CompareHelperTestCases; test++) {
for (int node_type = 0; node_type < kFloat64CompareHelperNodeType;
node_type++) {
for (size_t input = 0; input < ARRAY_SIZE(inputs); input += 2) {
RawMachineAssemblerTester<int32_t> m;
int expected = Float64CompareHelper(&m, test, node_type, inputs[input],
inputs[input + 1]);
CHECK_EQ(expected, m.Call());
}
}
}
}
TEST(RunFloat64UnorderedCompare) {
RawMachineAssemblerTester<int32_t> m;
Operator* operators[] = {m.machine()->Float64Equal(),
m.machine()->Float64LessThan(),
m.machine()->Float64LessThanOrEqual()};
double nan = v8::base::OS::nan_value();
FOR_FLOAT64_INPUTS(i) {
for (size_t o = 0; o < ARRAY_SIZE(operators); ++o) {
for (int j = 0; j < 2; j++) {
RawMachineAssemblerTester<int32_t> m;
Node* a = m.Float64Constant(*i);
Node* b = m.Float64Constant(nan);
if (j == 1) std::swap(a, b);
m.Return(m.NewNode(operators[o], a, b));
CHECK_EQ(0, m.Call());
}
}
}
}
TEST(RunFloat64Equal) {
double input_a = 0.0;
double input_b = 0.0;
RawMachineAssemblerTester<int32_t> m;
Node* a = m.LoadFromPointer(&input_a, kMachFloat64);
Node* b = m.LoadFromPointer(&input_b, kMachFloat64);
m.Return(m.Float64Equal(a, b));
CompareWrapper cmp(IrOpcode::kFloat64Equal);
FOR_FLOAT64_INPUTS(pl) {
FOR_FLOAT64_INPUTS(pr) {
input_a = *pl;
input_b = *pr;
int32_t expected = cmp.Float64Compare(input_a, input_b) ? 1 : 0;
CHECK_EQ(expected, m.Call());
}
}
}
TEST(RunFloat64LessThan) {
double input_a = 0.0;
double input_b = 0.0;
RawMachineAssemblerTester<int32_t> m;
Node* a = m.LoadFromPointer(&input_a, kMachFloat64);
Node* b = m.LoadFromPointer(&input_b, kMachFloat64);
m.Return(m.Float64LessThan(a, b));
CompareWrapper cmp(IrOpcode::kFloat64LessThan);
FOR_FLOAT64_INPUTS(pl) {
FOR_FLOAT64_INPUTS(pr) {
input_a = *pl;
input_b = *pr;
int32_t expected = cmp.Float64Compare(input_a, input_b) ? 1 : 0;
CHECK_EQ(expected, m.Call());
}
}
}
template <typename IntType, MachineType kRepresentation>
static void LoadStoreTruncation() {
IntType input;
RawMachineAssemblerTester<int32_t> m;
Node* a = m.LoadFromPointer(&input, kRepresentation);
Node* ap1 = m.Int32Add(a, m.Int32Constant(1));
m.StoreToPointer(&input, kRepresentation, ap1);
m.Return(ap1);
const IntType max = std::numeric_limits<IntType>::max();
const IntType min = std::numeric_limits<IntType>::min();
// Test upper bound.
input = max;
CHECK_EQ(max + 1, m.Call());
CHECK_EQ(min, input);
// Test lower bound.
input = min;
CHECK_EQ(max + 2, m.Call());
CHECK_EQ(min + 1, input);
// Test all one byte values that are not one byte bounds.
for (int i = -127; i < 127; i++) {
input = i;
int expected = i >= 0 ? i + 1 : max + (i - min) + 2;
CHECK_EQ(expected, m.Call());
CHECK_EQ(i + 1, input);
}
}
TEST(RunLoadStoreTruncation) {
LoadStoreTruncation<int8_t, kMachInt8>();
LoadStoreTruncation<int16_t, kMachInt16>();
}
static void IntPtrCompare(intptr_t left, intptr_t right) {
for (int test = 0; test < 7; test++) {
RawMachineAssemblerTester<bool> m(MachineOperatorBuilder::pointer_rep(),
MachineOperatorBuilder::pointer_rep());
Node* p0 = m.Parameter(0);
Node* p1 = m.Parameter(1);
Node* res = NULL;
bool expected = false;
switch (test) {
case 0:
res = m.IntPtrLessThan(p0, p1);
expected = true;
break;
case 1:
res = m.IntPtrLessThanOrEqual(p0, p1);
expected = true;
break;
case 2:
res = m.IntPtrEqual(p0, p1);
expected = false;
break;
case 3:
res = m.IntPtrGreaterThanOrEqual(p0, p1);
expected = false;
break;
case 4:
res = m.IntPtrGreaterThan(p0, p1);
expected = false;
break;
case 5:
res = m.IntPtrEqual(p0, p0);
expected = true;
break;
case 6:
res = m.IntPtrNotEqual(p0, p1);
expected = true;
break;
default:
UNREACHABLE();
break;
}
m.Return(res);
CHECK_EQ(expected, m.Call(reinterpret_cast<int32_t*>(left),
reinterpret_cast<int32_t*>(right)));
}
}
TEST(RunIntPtrCompare) {
intptr_t min = std::numeric_limits<intptr_t>::min();
intptr_t max = std::numeric_limits<intptr_t>::max();
// An ascending chain of intptr_t
intptr_t inputs[] = {min, min / 2, -1, 0, 1, max / 2, max};
for (size_t i = 0; i < ARRAY_SIZE(inputs) - 1; i++) {
IntPtrCompare(inputs[i], inputs[i + 1]);
}
}
TEST(RunTestIntPtrArithmetic) {
static const int kInputSize = 10;
int32_t inputs[kInputSize];
int32_t outputs[kInputSize];
for (int i = 0; i < kInputSize; i++) {
inputs[i] = i;
outputs[i] = -1;
}
RawMachineAssemblerTester<int32_t*> m;
Node* input = m.PointerConstant(&inputs[0]);
Node* output = m.PointerConstant(&outputs[kInputSize - 1]);
Node* elem_size = m.ConvertInt32ToIntPtr(m.Int32Constant(sizeof(inputs[0])));
for (int i = 0; i < kInputSize; i++) {
m.Store(kMachInt32, output, m.Load(kMachInt32, input));
input = m.IntPtrAdd(input, elem_size);
output = m.IntPtrSub(output, elem_size);
}
m.Return(input);
CHECK_EQ(&inputs[kInputSize], m.Call());
for (int i = 0; i < kInputSize; i++) {
CHECK_EQ(i, inputs[i]);
CHECK_EQ(kInputSize - i - 1, outputs[i]);
}
}
TEST(RunSpillLotsOfThings) {
static const int kInputSize = 1000;
RawMachineAssemblerTester<void> m;
Node* accs[kInputSize];
int32_t outputs[kInputSize];
Node* one = m.Int32Constant(1);
Node* acc = one;
for (int i = 0; i < kInputSize; i++) {
acc = m.Int32Add(acc, one);
accs[i] = acc;
}
for (int i = 0; i < kInputSize; i++) {
m.StoreToPointer(&outputs[i], kMachInt32, accs[i]);
}
m.Return(one);
m.Call();
for (int i = 0; i < kInputSize; i++) {
CHECK_EQ(outputs[i], i + 2);
}
}
TEST(RunSpillConstantsAndParameters) {
static const int kInputSize = 1000;
static const int32_t kBase = 987;
RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32);
int32_t outputs[kInputSize];
Node* csts[kInputSize];
Node* accs[kInputSize];
Node* acc = m.Int32Constant(0);
for (int i = 0; i < kInputSize; i++) {
csts[i] = m.Int32Constant(static_cast<int32_t>(kBase + i));
}
for (int i = 0; i < kInputSize; i++) {
acc = m.Int32Add(acc, csts[i]);
accs[i] = acc;
}
for (int i = 0; i < kInputSize; i++) {
m.StoreToPointer(&outputs[i], kMachInt32, accs[i]);
}
m.Return(m.Int32Add(acc, m.Int32Add(m.Parameter(0), m.Parameter(1))));
FOR_INT32_INPUTS(i) {
FOR_INT32_INPUTS(j) {
int32_t expected = *i + *j;
for (int k = 0; k < kInputSize; k++) {
expected += kBase + k;
}
CHECK_EQ(expected, m.Call(*i, *j));
expected = 0;
for (int k = 0; k < kInputSize; k++) {
expected += kBase + k;
CHECK_EQ(expected, outputs[k]);
}
}
}
}
TEST(RunNewSpaceConstantsInPhi) {
RawMachineAssemblerTester<Object*> m(kMachInt32);
Isolate* isolate = CcTest::i_isolate();
Handle<HeapNumber> true_val = isolate->factory()->NewHeapNumber(11.2);
Handle<HeapNumber> false_val = isolate->factory()->NewHeapNumber(11.3);
Node* true_node = m.HeapConstant(true_val);
Node* false_node = m.HeapConstant(false_val);
MLabel blocka, blockb, end;
m.Branch(m.Parameter(0), &blocka, &blockb);
m.Bind(&blocka);
m.Goto(&end);
m.Bind(&blockb);
m.Goto(&end);
m.Bind(&end);
Node* phi = m.Phi(true_node, false_node);
m.Return(phi);
CHECK_EQ(*false_val, m.Call(0));
CHECK_EQ(*true_val, m.Call(1));
}
#if MACHINE_ASSEMBLER_SUPPORTS_CALL_C
TEST(RunSpillLotsOfThingsWithCall) {
static const int kInputSize = 1000;
RawMachineAssemblerTester<void> m;
Node* accs[kInputSize];
int32_t outputs[kInputSize];
Node* one = m.Int32Constant(1);
Node* acc = one;
for (int i = 0; i < kInputSize; i++) {
acc = m.Int32Add(acc, one);
accs[i] = acc;
}
// If the spill slot computation is wrong, it might load from the c frame
{
void* func = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(&Seven));
Node** args = NULL;
MachineType* arg_types = NULL;
m.CallC(m.PointerConstant(func), kMachInt32, arg_types, args, 0);
}
for (int i = 0; i < kInputSize; i++) {
m.StoreToPointer(&outputs[i], kMachInt32, accs[i]);
}
m.Return(one);
m.Call();
for (int i = 0; i < kInputSize; i++) {
CHECK_EQ(outputs[i], i + 2);
}
}
#endif // MACHINE_ASSEMBLER_SUPPORTS_CALL_C
static bool sadd_overflow(int32_t x, int32_t y, int32_t* val) {
int32_t v =
static_cast<int32_t>(static_cast<uint32_t>(x) + static_cast<uint32_t>(y));
*val = v;
return (((v ^ x) & (v ^ y)) >> 31) & 1;
}
static bool ssub_overflow(int32_t x, int32_t y, int32_t* val) {
int32_t v =
static_cast<int32_t>(static_cast<uint32_t>(x) - static_cast<uint32_t>(y));
*val = v;
return (((v ^ x) & (v ^ ~y)) >> 31) & 1;
}
TEST(RunInt32AddWithOverflowP) {
int32_t actual_val = -1;
RawMachineAssemblerTester<int32_t> m;
Int32BinopTester bt(&m);
Node* add = m.Int32AddWithOverflow(bt.param0, bt.param1);
Node* val = m.Projection(0, add);
Node* ovf = m.Projection(1, add);
m.StoreToPointer(&actual_val, kMachInt32, val);
bt.AddReturn(ovf);
FOR_INT32_INPUTS(i) {
FOR_INT32_INPUTS(j) {
int32_t expected_val;
int expected_ovf = sadd_overflow(*i, *j, &expected_val);
CHECK_EQ(expected_ovf, bt.call(*i, *j));
CHECK_EQ(expected_val, actual_val);
}
}
}
TEST(RunInt32AddWithOverflowImm) {
int32_t actual_val = -1, expected_val = 0;
FOR_INT32_INPUTS(i) {
{
RawMachineAssemblerTester<int32_t> m(kMachInt32);
Node* add = m.Int32AddWithOverflow(m.Int32Constant(*i), m.Parameter(0));
Node* val = m.Projection(0, add);
Node* ovf = m.Projection(1, add);
m.StoreToPointer(&actual_val, kMachInt32, val);
m.Return(ovf);
FOR_INT32_INPUTS(j) {
int expected_ovf = sadd_overflow(*i, *j, &expected_val);
CHECK_EQ(expected_ovf, m.Call(*j));
CHECK_EQ(expected_val, actual_val);
}
}
{
RawMachineAssemblerTester<int32_t> m(kMachInt32);
Node* add = m.Int32AddWithOverflow(m.Parameter(0), m.Int32Constant(*i));
Node* val = m.Projection(0, add);
Node* ovf = m.Projection(1, add);
m.StoreToPointer(&actual_val, kMachInt32, val);
m.Return(ovf);
FOR_INT32_INPUTS(j) {
int expected_ovf = sadd_overflow(*i, *j, &expected_val);
CHECK_EQ(expected_ovf, m.Call(*j));
CHECK_EQ(expected_val, actual_val);
}
}
FOR_INT32_INPUTS(j) {
RawMachineAssemblerTester<int32_t> m;
Node* add =
m.Int32AddWithOverflow(m.Int32Constant(*i), m.Int32Constant(*j));
Node* val = m.Projection(0, add);
Node* ovf = m.Projection(1, add);
m.StoreToPointer(&actual_val, kMachInt32, val);
m.Return(ovf);
int expected_ovf = sadd_overflow(*i, *j, &expected_val);
CHECK_EQ(expected_ovf, m.Call());
CHECK_EQ(expected_val, actual_val);
}
}
}
TEST(RunInt32AddWithOverflowInBranchP) {
int constant = 911777;
MLabel blocka, blockb;
RawMachineAssemblerTester<int32_t> m;
Int32BinopTester bt(&m);
Node* add = m.Int32AddWithOverflow(bt.param0, bt.param1);
Node* ovf = m.Projection(1, add);
m.Branch(ovf, &blocka, &blockb);
m.Bind(&blocka);
bt.AddReturn(m.Int32Constant(constant));
m.Bind(&blockb);
Node* val = m.Projection(0, add);
bt.AddReturn(val);
FOR_INT32_INPUTS(i) {
FOR_INT32_INPUTS(j) {
int32_t expected;
if (sadd_overflow(*i, *j, &expected)) expected = constant;
CHECK_EQ(expected, bt.call(*i, *j));
}
}
}
TEST(RunInt32SubWithOverflowP) {
int32_t actual_val = -1;
RawMachineAssemblerTester<int32_t> m;
Int32BinopTester bt(&m);
Node* add = m.Int32SubWithOverflow(bt.param0, bt.param1);
Node* val = m.Projection(0, add);
Node* ovf = m.Projection(1, add);
m.StoreToPointer(&actual_val, kMachInt32, val);
bt.AddReturn(ovf);
FOR_INT32_INPUTS(i) {
FOR_INT32_INPUTS(j) {
int32_t expected_val;
int expected_ovf = ssub_overflow(*i, *j, &expected_val);
CHECK_EQ(expected_ovf, bt.call(*i, *j));
CHECK_EQ(expected_val, actual_val);
}
}
}
TEST(RunInt32SubWithOverflowImm) {
int32_t actual_val = -1, expected_val = 0;
FOR_INT32_INPUTS(i) {
{
RawMachineAssemblerTester<int32_t> m(kMachInt32);
Node* add = m.Int32SubWithOverflow(m.Int32Constant(*i), m.Parameter(0));
Node* val = m.Projection(0, add);
Node* ovf = m.Projection(1, add);
m.StoreToPointer(&actual_val, kMachInt32, val);
m.Return(ovf);
FOR_INT32_INPUTS(j) {
int expected_ovf = ssub_overflow(*i, *j, &expected_val);
CHECK_EQ(expected_ovf, m.Call(*j));
CHECK_EQ(expected_val, actual_val);
}
}
{
RawMachineAssemblerTester<int32_t> m(kMachInt32);
Node* add = m.Int32SubWithOverflow(m.Parameter(0), m.Int32Constant(*i));
Node* val = m.Projection(0, add);
Node* ovf = m.Projection(1, add);
m.StoreToPointer(&actual_val, kMachInt32, val);
m.Return(ovf);
FOR_INT32_INPUTS(j) {
int expected_ovf = ssub_overflow(*j, *i, &expected_val);
CHECK_EQ(expected_ovf, m.Call(*j));
CHECK_EQ(expected_val, actual_val);
}
}
FOR_INT32_INPUTS(j) {
RawMachineAssemblerTester<int32_t> m;
Node* add =
m.Int32SubWithOverflow(m.Int32Constant(*i), m.Int32Constant(*j));
Node* val = m.Projection(0, add);
Node* ovf = m.Projection(1, add);
m.StoreToPointer(&actual_val, kMachInt32, val);
m.Return(ovf);
int expected_ovf = ssub_overflow(*i, *j, &expected_val);
CHECK_EQ(expected_ovf, m.Call());
CHECK_EQ(expected_val, actual_val);
}
}
}
TEST(RunInt32SubWithOverflowInBranchP) {
int constant = 911999;
MLabel blocka, blockb;
RawMachineAssemblerTester<int32_t> m;
Int32BinopTester bt(&m);
Node* sub = m.Int32SubWithOverflow(bt.param0, bt.param1);
Node* ovf = m.Projection(1, sub);
m.Branch(ovf, &blocka, &blockb);
m.Bind(&blocka);
bt.AddReturn(m.Int32Constant(constant));
m.Bind(&blockb);
Node* val = m.Projection(0, sub);
bt.AddReturn(val);
FOR_INT32_INPUTS(i) {
FOR_INT32_INPUTS(j) {
int32_t expected;
if (ssub_overflow(*i, *j, &expected)) expected = constant;
CHECK_EQ(expected, bt.call(*i, *j));
}
}
}
TEST(RunChangeInt32ToInt64P) {
if (kPointerSize < 8) return;
int64_t actual = -1;
RawMachineAssemblerTester<int32_t> m(kMachInt32);
m.StoreToPointer(&actual, kMachInt64, m.ChangeInt32ToInt64(m.Parameter(0)));
m.Return(m.Int32Constant(0));
FOR_INT32_INPUTS(i) {
int64_t expected = *i;
CHECK_EQ(0, m.Call(*i));
CHECK_EQ(expected, actual);
}
}
TEST(RunChangeUint32ToUint64P) {
if (kPointerSize < 8) return;
int64_t actual = -1;
RawMachineAssemblerTester<int32_t> m(kMachUint32);
m.StoreToPointer(&actual, kMachUint64,
m.ChangeUint32ToUint64(m.Parameter(0)));
m.Return(m.Int32Constant(0));
FOR_UINT32_INPUTS(i) {
int64_t expected = static_cast<uint64_t>(*i);
CHECK_EQ(0, m.Call(*i));
CHECK_EQ(expected, actual);
}
}
TEST(RunTruncateInt64ToInt32P) {
if (kPointerSize < 8) return;
int64_t expected = -1;
RawMachineAssemblerTester<int32_t> m;
m.Return(m.TruncateInt64ToInt32(m.LoadFromPointer(&expected, kMachInt64)));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
expected = (static_cast<uint64_t>(*j) << 32) | *i;
CHECK_UINT32_EQ(expected, m.Call());
}
}
}
#endif // V8_TURBOFAN_TARGET