// 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 #include #include "test/cctest/cctest.h" #include "test/cctest/compiler/codegen-tester.h" #include "test/cctest/compiler/value-helper.h" #if V8_TURBOFAN_TARGET using namespace v8::internal; using namespace v8::internal::compiler; typedef RawMachineAssembler::Label MLabel; TEST(RunInt32Add) { RawMachineAssemblerTester m; Node* add = m.Int32Add(m.Int32Constant(0), m.Int32Constant(1)); m.Return(add); CHECK_EQ(1, m.Call()); } static Node* Int32Input(RawMachineAssemblerTester* 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(kMachineWord32, m->PointerConstant(NULL)); default: return NULL; } } TEST(CodeGenInt32Binop) { RawMachineAssemblerTester 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 m(kMachineWord32, kMachineWord32); Node* a = Int32Input(&m, j); Node* b = Int32Input(&m, k); m.Return(m.NewNode(ops[i], a, b)); m.GenerateCode(); } } } } TEST(RunGoto) { RawMachineAssemblerTester 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 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 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 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 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 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 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 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 static void BuildDiamondPhi(RawMachineAssemblerTester* 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 m(kMachineWord32); 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 m(kMachineWord32); 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 m(kMachineWord32); 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 m(kMachineWord32, kMachineWord32, kMachineWord32); 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 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 m(kMachineWord32, kMachineWord32, kMachineWord32); 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 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 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 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 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 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 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 m; int32_t p1 = 0; // loads directly from this location. m.Return(m.LoadFromPointer(&p1, kMachineWord32)); 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 m; int32_t offset = offsets[i]; byte* pointer = reinterpret_cast(&p1) - offset; // generate load [#base + #index] m.Return(m.LoadFromPointer(pointer, kMachineWord32, 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 m; int32_t offset = *i; byte* from = reinterpret_cast(&p1) - offset; byte* to = reinterpret_cast(&p2) - offset; // generate load [#base + #index] Node* load = m.Load(kMachineFloat64, m.PointerConstant(from), m.Int32Constant(offset)); m.Store(kMachineFloat64, 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 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(*i + *j); CHECK_EQ(expected, bt.call(*i, *j)); } } } TEST(RunInt32AddAndWord32SarP) { { RawMachineAssemblerTester m(kMachineWord32, kMachineWord32, kMachineWord32); 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_INPUTS(k) { uint32_t shift = *k & 0x1F; // 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 m(kMachineWord32, kMachineWord32, kMachineWord32); m.Return(m.Int32Add(m.Word32Sar(m.Parameter(0), m.Parameter(1)), m.Parameter(2))); FOR_INT32_INPUTS(i) { FOR_UINT32_INPUTS(j) { FOR_UINT32_INPUTS(k) { uint32_t shift = *j & 0x1F; // 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 m(kMachineWord32, kMachineWord32, kMachineWord32); 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_INPUTS(k) { uint32_t shift = *k & 0x1F; // 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 m(kMachineWord32, kMachineWord32, kMachineWord32); m.Return(m.Int32Add(m.Word32Shl(m.Parameter(0), m.Parameter(1)), m.Parameter(2))); FOR_INT32_INPUTS(i) { FOR_UINT32_INPUTS(j) { FOR_UINT32_INPUTS(k) { uint32_t shift = *j & 0x1F; // 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 m(kMachineWord32, kMachineWord32, kMachineWord32); 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_INPUTS(k) { uint32_t shift = *k & 0x1F; // 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 m(kMachineWord32, kMachineWord32, kMachineWord32); m.Return(m.Int32Add(m.Word32Shr(m.Parameter(0), m.Parameter(1)), m.Parameter(2))); FOR_UINT32_INPUTS(i) { FOR_UINT32_INPUTS(j) { FOR_UINT32_INPUTS(k) { uint32_t shift = *j & 0x1F; // 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 m; Int32BinopTester 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 m; Int32BinopTester 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 m(kMachineWord32); 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) { int32_t expected = (*i + *j) == 0 ? constant : 0 - constant; CHECK_EQ(expected, m.Call(*j)); } } } { FOR_UINT32_INPUTS(i) { RawMachineAssemblerTester m(kMachineWord32); 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) { int32_t expected = (*i + *j) != 0 ? constant : 0 - constant; CHECK_EQ(expected, m.Call(*j)); } } } { RawMachineAssemblerTester m; Operator* shops[] = {m.machine()->Word32Sar(), m.machine()->Word32Shl(), m.machine()->Word32Shr()}; for (size_t n = 0; n < ARRAY_SIZE(shops); n++) { RawMachineAssemblerTester m(kMachineWord32, kMachineWord32, kMachineWord32); 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_INPUTS(k) { uint32_t shift = *k & 0x1F; 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(*j) >> shift; break; } int32_t expected = ((*i + right) == 0) ? constant : 0 - constant; CHECK_EQ(expected, m.Call(*i, *j, shift)); } } } } } } TEST(RunInt32AddInComparison) { { RawMachineAssemblerTester m; Int32BinopTester bt(&m); bt.AddReturn( m.Word32Equal(m.Int32Add(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 m; Int32BinopTester bt(&m); bt.AddReturn( m.Word32Equal(m.Int32Constant(0), m.Int32Add(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 m(kMachineWord32); m.Return(m.Word32Equal(m.Int32Add(m.Int32Constant(*i), m.Parameter(0)), m.Int32Constant(0))); FOR_UINT32_INPUTS(j) { int32_t expected = (*i + *j) == 0; CHECK_EQ(expected, m.Call(*j)); } } } { FOR_UINT32_INPUTS(i) { RawMachineAssemblerTester m(kMachineWord32); m.Return(m.Word32Equal(m.Int32Add(m.Parameter(0), m.Int32Constant(*i)), m.Int32Constant(0))); FOR_UINT32_INPUTS(j) { int32_t expected = (*j + *i) == 0; CHECK_EQ(expected, m.Call(*j)); } } } { RawMachineAssemblerTester m; Operator* shops[] = {m.machine()->Word32Sar(), m.machine()->Word32Shl(), m.machine()->Word32Shr()}; for (size_t n = 0; n < ARRAY_SIZE(shops); n++) { RawMachineAssemblerTester m(kMachineWord32, kMachineWord32, kMachineWord32); 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_INPUTS(k) { uint32_t shift = *k & 0x1F; 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(*j) >> shift; break; } int32_t expected = (*i + right) == 0; CHECK_EQ(expected, m.Call(*i, *j, shift)); } } } } } } TEST(RunInt32SubP) { RawMachineAssemblerTester m; Int32BinopTester bt(&m); m.Return(m.Int32Sub(bt.param0, bt.param1)); FOR_UINT32_INPUTS(i) { FOR_UINT32_INPUTS(j) { // Use uint32_t because signed overflow is UB in C. int expected = static_cast(*i - *j); CHECK_EQ(expected, bt.call(*i, *j)); } } } TEST(RunInt32SubImm) { { FOR_UINT32_INPUTS(i) { RawMachineAssemblerTester m(kMachineWord32); m.Return(m.Int32Sub(m.Int32Constant(*i), m.Parameter(0))); FOR_UINT32_INPUTS(j) { // Use uint32_t because signed overflow is UB in C. int32_t expected = static_cast(*i - *j); CHECK_EQ(expected, m.Call(*j)); } } } { FOR_UINT32_INPUTS(i) { RawMachineAssemblerTester m(kMachineWord32); m.Return(m.Int32Sub(m.Parameter(0), m.Int32Constant(*i))); FOR_UINT32_INPUTS(j) { // Use uint32_t because signed overflow is UB in C. int32_t expected = static_cast(*j - *i); CHECK_EQ(expected, m.Call(*j)); } } } } TEST(RunInt32SubAndWord32SarP) { { RawMachineAssemblerTester m(kMachineWord32, kMachineWord32, kMachineWord32); 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_INPUTS(k) { uint32_t shift = *k & 0x1F; // 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 m(kMachineWord32, kMachineWord32, kMachineWord32); m.Return(m.Int32Sub(m.Word32Sar(m.Parameter(0), m.Parameter(1)), m.Parameter(2))); FOR_INT32_INPUTS(i) { FOR_UINT32_INPUTS(j) { FOR_UINT32_INPUTS(k) { uint32_t shift = *j & 0x1F; // 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(RunInt32SubAndWord32ShlP) { { RawMachineAssemblerTester m(kMachineWord32, kMachineWord32, kMachineWord32); 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_INPUTS(k) { uint32_t shift = *k & 0x1F; // 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 m(kMachineWord32, kMachineWord32, kMachineWord32); m.Return(m.Int32Sub(m.Word32Shl(m.Parameter(0), m.Parameter(1)), m.Parameter(2))); FOR_INT32_INPUTS(i) { FOR_UINT32_INPUTS(j) { FOR_UINT32_INPUTS(k) { uint32_t shift = *j & 0x1F; // 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 m(kMachineWord32, kMachineWord32, kMachineWord32); 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_INPUTS(k) { uint32_t shift = *k & 0x1F; // 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 m(kMachineWord32, kMachineWord32, kMachineWord32); m.Return(m.Int32Sub(m.Word32Shr(m.Parameter(0), m.Parameter(1)), m.Parameter(2))); FOR_UINT32_INPUTS(i) { FOR_UINT32_INPUTS(j) { FOR_UINT32_INPUTS(k) { uint32_t shift = *j & 0x1F; // 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 m; Int32BinopTester 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 m; Int32BinopTester 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 m(kMachineWord32); 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 m(kMachineWord32); 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 m; Operator* shops[] = {m.machine()->Word32Sar(), m.machine()->Word32Shl(), m.machine()->Word32Shr()}; for (size_t n = 0; n < ARRAY_SIZE(shops); n++) { RawMachineAssemblerTester m(kMachineWord32, kMachineWord32, kMachineWord32); 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_INPUTS(k) { uint32_t shift = *k & 0x1F; 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(*j) >> shift; break; } int32_t expected = ((*i - right) == 0) ? constant : 0 - constant; CHECK_EQ(expected, m.Call(*i, *j, shift)); } } } } } } TEST(RunInt32SubInComparison) { { RawMachineAssemblerTester m; Int32BinopTester bt(&m); bt.AddReturn( m.Word32Equal(m.Int32Sub(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 m; Int32BinopTester bt(&m); bt.AddReturn( m.Word32Equal(m.Int32Constant(0), m.Int32Sub(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 m(kMachineWord32); m.Return(m.Word32Equal(m.Int32Sub(m.Int32Constant(*i), m.Parameter(0)), m.Int32Constant(0))); FOR_UINT32_INPUTS(j) { int32_t expected = (*i - *j) == 0; CHECK_EQ(expected, m.Call(*j)); } } } { FOR_UINT32_INPUTS(i) { RawMachineAssemblerTester m(kMachineWord32); m.Return(m.Word32Equal(m.Int32Sub(m.Parameter(0), m.Int32Constant(*i)), m.Int32Constant(0))); FOR_UINT32_INPUTS(j) { int32_t expected = (*j - *i) == 0; CHECK_EQ(expected, m.Call(*j)); } } } { RawMachineAssemblerTester m; Operator* shops[] = {m.machine()->Word32Sar(), m.machine()->Word32Shl(), m.machine()->Word32Shr()}; for (size_t n = 0; n < ARRAY_SIZE(shops); n++) { RawMachineAssemblerTester m(kMachineWord32, kMachineWord32, kMachineWord32); 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_INPUTS(k) { uint32_t shift = *k & 0x1F; 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(*j) >> shift; break; } int32_t expected = (*i - right) == 0; CHECK_EQ(expected, m.Call(*i, *j, shift)); } } } } } } TEST(RunInt32MulP) { { RawMachineAssemblerTester m; Int32BinopTester bt(&m); bt.AddReturn(m.Int32Mul(bt.param0, bt.param1)); FOR_INT32_INPUTS(i) { FOR_INT32_INPUTS(j) { int expected = static_cast(*i * *j); CHECK_EQ(expected, bt.call(*i, *j)); } } } { RawMachineAssemblerTester m; Int32BinopTester bt(&m); bt.AddReturn(m.Int32Mul(bt.param0, bt.param1)); FOR_UINT32_INPUTS(i) { FOR_UINT32_INPUTS(j) { int expected = static_cast(*i * *j); CHECK_EQ(expected, bt.call(*i, *j)); } } } } TEST(RunInt32MulImm) { { FOR_UINT32_INPUTS(i) { RawMachineAssemblerTester m(kMachineWord32); m.Return(m.Int32Mul(m.Int32Constant(*i), m.Parameter(0))); FOR_UINT32_INPUTS(j) { int32_t expected = static_cast(*i * *j); CHECK_EQ(expected, m.Call(*j)); } } } { FOR_UINT32_INPUTS(i) { RawMachineAssemblerTester m(kMachineWord32); m.Return(m.Int32Mul(m.Parameter(0), m.Int32Constant(*i))); FOR_UINT32_INPUTS(j) { int32_t expected = static_cast(*j * *i); CHECK_EQ(expected, m.Call(*j)); } } } } TEST(RunInt32MulAndInt32AddP) { { RawMachineAssemblerTester m(kMachineWord32, kMachineWord32, kMachineWord32); 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(p1 * p2); CHECK_EQ(expected, m.Call(p0, p1, p2)); } } } } { RawMachineAssemblerTester m(kMachineWord32, kMachineWord32, kMachineWord32); 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(p0 * p1) + p2; CHECK_EQ(expected, m.Call(p0, p1, p2)); } } } } { FOR_INT32_INPUTS(i) { RawMachineAssemblerTester 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(p0 * p1); CHECK_EQ(expected, bt.call(p0, p1)); } } } } } TEST(RunInt32MulAndInt32SubP) { { RawMachineAssemblerTester m(kMachineWord32, kMachineWord32, kMachineWord32); 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(p1 * p2); CHECK_EQ(expected, m.Call(p0, p1, p2)); } } } } { FOR_UINT32_INPUTS(i) { RawMachineAssemblerTester 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(p0 * p1); CHECK_EQ(expected, bt.call(p0, p1)); } } } } } TEST(RunInt32DivP) { { RawMachineAssemblerTester 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(p0) != 0x80000000 || p1 != -1)) { int expected = static_cast(p0 / p1); CHECK_EQ(expected, bt.call(p0, p1)); } } } } { RawMachineAssemblerTester 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(p0) != 0x80000000 || p1 != -1)) { int expected = static_cast(p0 + (p0 / p1)); CHECK_EQ(expected, bt.call(p0, p1)); } } } } } TEST(RunInt32UDivP) { { RawMachineAssemblerTester 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(p0 / p1); CHECK_EQ(expected, bt.call(p0, p1)); } } } } { RawMachineAssemblerTester 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(p0 + (p0 / p1)); CHECK_EQ(expected, bt.call(p0, p1)); } } } } } TEST(RunInt32ModP) { { RawMachineAssemblerTester 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(p0) != 0x80000000 || p1 != -1)) { int expected = static_cast(p0 % p1); CHECK_EQ(expected, bt.call(p0, p1)); } } } } { RawMachineAssemblerTester 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(p0) != 0x80000000 || p1 != -1)) { int expected = static_cast(p0 + (p0 % p1)); CHECK_EQ(expected, bt.call(p0, p1)); } } } } } TEST(RunInt32UModP) { { RawMachineAssemblerTester 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(p0 % p1); CHECK_EQ(expected, bt.call(p0, p1)); } } } } { RawMachineAssemblerTester 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(p0 + (p0 % p1)); CHECK_EQ(expected, bt.call(p0, p1)); } } } } } TEST(RunWord32AndP) { { RawMachineAssemblerTester 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 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 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 m; Int32BinopTester 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_EQ(expected, bt.call(*i, *j)); } } } { RawMachineAssemblerTester m; Int32BinopTester 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_EQ(expected, bt.call(*i, *j)); } } } } TEST(RunWord32AndAndWord32ShrP) { { RawMachineAssemblerTester m; Int32BinopTester 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_EQ(expected, bt.call(*i, *j)); } } } { RawMachineAssemblerTester m; Int32BinopTester 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_EQ(expected, bt.call(*i, *j)); } } } } TEST(RunWord32AndAndWord32SarP) { { RawMachineAssemblerTester m; Int32BinopTester bt(&m); bt.AddReturn( m.Word32Sar(bt.param0, m.Word32And(bt.param1, m.Int32Constant(0x1f)))); FOR_INT32_INPUTS(i) { FOR_UINT32_INPUTS(j) { uint32_t expected = *i >> (*j & 0x1f); CHECK_EQ(expected, bt.call(*i, *j)); } } } { RawMachineAssemblerTester m; Int32BinopTester bt(&m); bt.AddReturn( m.Word32Sar(bt.param0, m.Word32And(m.Int32Constant(0x1f), bt.param1))); FOR_INT32_INPUTS(i) { FOR_UINT32_INPUTS(j) { uint32_t expected = *i >> (0x1f & *j); CHECK_EQ(expected, bt.call(*i, *j)); } } } } TEST(RunWord32AndImm) { { FOR_UINT32_INPUTS(i) { RawMachineAssemblerTester m(kMachineWord32); m.Return(m.Word32And(m.Int32Constant(*i), m.Parameter(0))); FOR_UINT32_INPUTS(j) { uint32_t expected = *i & *j; CHECK_EQ(expected, m.Call(*j)); } } } { FOR_UINT32_INPUTS(i) { RawMachineAssemblerTester m(kMachineWord32); m.Return(m.Word32And(m.Int32Constant(*i), m.Word32Not(m.Parameter(0)))); FOR_UINT32_INPUTS(j) { uint32_t expected = *i & ~(*j); CHECK_EQ(expected, m.Call(*j)); } } } } TEST(RunWord32AndInBranch) { static const int constant = 987654321; { RawMachineAssemblerTester m; Int32BinopTester 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 m; Int32BinopTester 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 m(kMachineWord32); 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 m(kMachineWord32); 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 m; Operator* shops[] = {m.machine()->Word32Sar(), m.machine()->Word32Shl(), m.machine()->Word32Shr()}; for (size_t n = 0; n < ARRAY_SIZE(shops); n++) { RawMachineAssemblerTester m(kMachineWord32, kMachineWord32, kMachineWord32); 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_INPUTS(k) { uint32_t shift = *k & 0x1F; 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(*j) >> shift; break; } int32_t expected = ((*i & right) == 0) ? constant : 0 - constant; CHECK_EQ(expected, m.Call(*i, *j, shift)); } } } } } } TEST(RunWord32AndInComparison) { { RawMachineAssemblerTester m; Int32BinopTester bt(&m); bt.AddReturn( m.Word32Equal(m.Word32And(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 m; Int32BinopTester bt(&m); bt.AddReturn( m.Word32Equal(m.Int32Constant(0), m.Word32And(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 m(kMachineWord32); m.Return(m.Word32Equal(m.Word32And(m.Int32Constant(*i), m.Parameter(0)), m.Int32Constant(0))); FOR_UINT32_INPUTS(j) { int32_t expected = (*i & *j) == 0; CHECK_EQ(expected, m.Call(*j)); } } } { FOR_UINT32_INPUTS(i) { RawMachineAssemblerTester m(kMachineWord32); m.Return(m.Word32Equal(m.Word32And(m.Parameter(0), m.Int32Constant(*i)), m.Int32Constant(0))); FOR_UINT32_INPUTS(j) { int32_t expected = (*j & *i) == 0; CHECK_EQ(expected, m.Call(*j)); } } } } TEST(RunWord32OrP) { { RawMachineAssemblerTester m; Int32BinopTester bt(&m); bt.AddReturn(m.Word32Or(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 m; Int32BinopTester 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_EQ(expected, bt.call(*i, *j)); } } } { RawMachineAssemblerTester m; Int32BinopTester 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_EQ(expected, bt.call(*i, *j)); } } } } TEST(RunWord32OrImm) { { FOR_UINT32_INPUTS(i) { RawMachineAssemblerTester m(kMachineWord32); m.Return(m.Word32Or(m.Int32Constant(*i), m.Parameter(0))); FOR_UINT32_INPUTS(j) { uint32_t expected = *i | *j; CHECK_EQ(expected, m.Call(*j)); } } } { FOR_UINT32_INPUTS(i) { RawMachineAssemblerTester m(kMachineWord32); m.Return(m.Word32Or(m.Int32Constant(*i), m.Word32Not(m.Parameter(0)))); FOR_UINT32_INPUTS(j) { uint32_t expected = *i | ~(*j); CHECK_EQ(expected, m.Call(*j)); } } } } TEST(RunWord32OrInBranch) { static const int constant = 987654321; { RawMachineAssemblerTester 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_UINT32_INPUTS(i) { FOR_UINT32_INPUTS(j) { int32_t expected = (*i | *j) == 0 ? constant : 0 - constant; CHECK_EQ(expected, bt.call(*i, *j)); } } } { RawMachineAssemblerTester 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_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 m(kMachineWord32); 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_UINT32_INPUTS(j) { int32_t expected = (*i | *j) == 0 ? constant : 0 - constant; CHECK_EQ(expected, m.Call(*j)); } } } { FOR_UINT32_INPUTS(i) { RawMachineAssemblerTester m(kMachineWord32); 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_UINT32_INPUTS(j) { int32_t expected = (*i | *j) != 0 ? constant : 0 - constant; CHECK_EQ(expected, m.Call(*j)); } } } { RawMachineAssemblerTester m; Operator* shops[] = {m.machine()->Word32Sar(), m.machine()->Word32Shl(), m.machine()->Word32Shr()}; for (size_t n = 0; n < ARRAY_SIZE(shops); n++) { RawMachineAssemblerTester m(kMachineWord32, kMachineWord32, kMachineWord32); 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_INPUTS(k) { uint32_t shift = *k & 0x1F; 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(*j) >> shift; break; } int32_t expected = ((*i | right) == 0) ? constant : 0 - constant; CHECK_EQ(expected, m.Call(*i, *j, shift)); } } } } } } TEST(RunWord32OrInComparison) { { RawMachineAssemblerTester m; Int32BinopTester 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 m; Int32BinopTester 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 m(kMachineWord32); m.Return(m.Word32Equal(m.Word32Or(m.Int32Constant(*i), m.Parameter(0)), m.Int32Constant(0))); FOR_UINT32_INPUTS(j) { int32_t expected = (*i | *j) == 0; CHECK_EQ(expected, m.Call(*j)); } } } { FOR_UINT32_INPUTS(i) { RawMachineAssemblerTester m(kMachineWord32); m.Return(m.Word32Equal(m.Word32Or(m.Parameter(0), m.Int32Constant(*i)), m.Int32Constant(0))); FOR_UINT32_INPUTS(j) { int32_t expected = (*j | *i) == 0; CHECK_EQ(expected, m.Call(*j)); } } } } TEST(RunWord32XorP) { { FOR_UINT32_INPUTS(i) { RawMachineAssemblerTester m(kMachineWord32); m.Return(m.Word32Xor(m.Int32Constant(*i), m.Parameter(0))); FOR_UINT32_INPUTS(j) { uint32_t expected = *i ^ *j; CHECK_EQ(expected, m.Call(*j)); } } } { RawMachineAssemblerTester m; Int32BinopTester bt(&m); bt.AddReturn(m.Word32Xor(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 m; Int32BinopTester bt(&m); bt.AddReturn(m.Word32Xor(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 m; Int32BinopTester bt(&m); bt.AddReturn(m.Word32Xor(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)); } } } { FOR_UINT32_INPUTS(i) { RawMachineAssemblerTester m(kMachineWord32); m.Return(m.Word32Xor(m.Int32Constant(*i), m.Word32Not(m.Parameter(0)))); FOR_UINT32_INPUTS(j) { uint32_t expected = *i ^ ~(*j); CHECK_EQ(expected, m.Call(*j)); } } } } TEST(RunWord32XorInBranch) { static const int constant = 987654321; { RawMachineAssemblerTester m; Int32BinopTester 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) { int32_t expected = (*i ^ *j) == 0 ? constant : 0 - constant; CHECK_EQ(expected, bt.call(*i, *j)); } } } { RawMachineAssemblerTester m; Int32BinopTester 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) { int32_t expected = (*i ^ *j) != 0 ? constant : 0 - constant; CHECK_EQ(expected, bt.call(*i, *j)); } } } { FOR_UINT32_INPUTS(i) { RawMachineAssemblerTester m(kMachineWord32); 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) { int32_t expected = (*i ^ *j) == 0 ? constant : 0 - constant; CHECK_EQ(expected, m.Call(*j)); } } } { FOR_UINT32_INPUTS(i) { RawMachineAssemblerTester m(kMachineWord32); 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) { int32_t expected = (*i ^ *j) != 0 ? constant : 0 - constant; CHECK_EQ(expected, m.Call(*j)); } } } { RawMachineAssemblerTester m; Operator* shops[] = {m.machine()->Word32Sar(), m.machine()->Word32Shl(), m.machine()->Word32Shr()}; for (size_t n = 0; n < ARRAY_SIZE(shops); n++) { RawMachineAssemblerTester m(kMachineWord32, kMachineWord32, kMachineWord32); 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_INPUTS(k) { uint32_t shift = *k & 0x1F; 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(*j) >> shift; break; } int32_t expected = ((*i ^ right) == 0) ? constant : 0 - constant; CHECK_EQ(expected, m.Call(*i, *j, shift)); } } } } } } TEST(RunWord32ShlP) { { FOR_UINT32_INPUTS(i) { uint32_t shift = *i & 0x1F; RawMachineAssemblerTester m(kMachineWord32); m.Return(m.Word32Shl(m.Parameter(0), m.Int32Constant(shift))); FOR_UINT32_INPUTS(j) { uint32_t expected = *j << shift; CHECK_EQ(expected, m.Call(*j)); } } } { RawMachineAssemblerTester m; Int32BinopTester bt(&m); bt.AddReturn(m.Word32Shl(bt.param0, bt.param1)); FOR_UINT32_INPUTS(i) { FOR_UINT32_INPUTS(j) { uint32_t shift = *j & 0x1F; uint32_t expected = *i << shift; CHECK_EQ(expected, bt.call(*i, shift)); } } } } TEST(RunWord32ShrP) { { FOR_UINT32_INPUTS(i) { uint32_t shift = *i & 0x1F; RawMachineAssemblerTester m(kMachineWord32); m.Return(m.Word32Shr(m.Parameter(0), m.Int32Constant(shift))); FOR_UINT32_INPUTS(j) { uint32_t expected = *j >> shift; CHECK_EQ(expected, m.Call(*j)); } } } { RawMachineAssemblerTester m; Int32BinopTester bt(&m); bt.AddReturn(m.Word32Shr(bt.param0, bt.param1)); FOR_UINT32_INPUTS(i) { FOR_UINT32_INPUTS(j) { uint32_t shift = *j & 0x1F; uint32_t expected = *i >> shift; CHECK_EQ(expected, bt.call(*i, shift)); } } CHECK_EQ(0x00010000, bt.call(0x80000000, 15)); } } TEST(RunWord32SarP) { { FOR_INT32_INPUTS(i) { int32_t shift = *i & 0x1F; RawMachineAssemblerTester m(kMachineWord32); 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 m; Int32BinopTester bt(&m); bt.AddReturn(m.Word32Sar(bt.param0, bt.param1)); FOR_INT32_INPUTS(i) { FOR_INT32_INPUTS(j) { int32_t shift = *j & 0x1F; int32_t expected = *i >> shift; CHECK_EQ(expected, bt.call(*i, shift)); } } CHECK_EQ(0xFFFF0000, bt.call(0x80000000, 15)); } } TEST(RunWord32NotP) { RawMachineAssemblerTester m(kMachineWord32); m.Return(m.Word32Not(m.Parameter(0))); FOR_UINT32_INPUTS(i) { int expected = ~(*i); CHECK_EQ(expected, m.Call(*i)); } } TEST(RunInt32NegP) { RawMachineAssemblerTester m(kMachineWord32); m.Return(m.Int32Neg(m.Parameter(0))); FOR_INT32_INPUTS(i) { int expected = -*i; CHECK_EQ(expected, m.Call(*i)); } } TEST(RunWord32EqualAndWord32SarP) { { RawMachineAssemblerTester m(kMachineWord32, kMachineWord32, kMachineWord32); 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_INPUTS(k) { uint32_t shift = *k & 0x1F; int32_t expected = (*i == (*j >> shift)); CHECK_EQ(expected, m.Call(*i, *j, shift)); } } } } { RawMachineAssemblerTester m(kMachineWord32, kMachineWord32, kMachineWord32); m.Return(m.Word32Equal(m.Word32Sar(m.Parameter(0), m.Parameter(1)), m.Parameter(2))); FOR_INT32_INPUTS(i) { FOR_UINT32_INPUTS(j) { FOR_INT32_INPUTS(k) { uint32_t shift = *j & 0x1F; int32_t expected = ((*i >> shift) == *k); CHECK_EQ(expected, m.Call(*i, shift, *k)); } } } } } TEST(RunWord32EqualAndWord32ShlP) { { RawMachineAssemblerTester m(kMachineWord32, kMachineWord32, kMachineWord32); 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_INPUTS(k) { uint32_t shift = *k & 0x1F; int32_t expected = (*i == (*j << shift)); CHECK_EQ(expected, m.Call(*i, *j, shift)); } } } } { RawMachineAssemblerTester m(kMachineWord32, kMachineWord32, kMachineWord32); m.Return(m.Word32Equal(m.Word32Shl(m.Parameter(0), m.Parameter(1)), m.Parameter(2))); FOR_UINT32_INPUTS(i) { FOR_UINT32_INPUTS(j) { FOR_UINT32_INPUTS(k) { uint32_t shift = *j & 0x1F; int32_t expected = ((*i << shift) == *k); CHECK_EQ(expected, m.Call(*i, shift, *k)); } } } } } TEST(RunWord32EqualAndWord32ShrP) { { RawMachineAssemblerTester m(kMachineWord32, kMachineWord32, kMachineWord32); 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_INPUTS(k) { uint32_t shift = *k & 0x1F; int32_t expected = (*i == (*j >> shift)); CHECK_EQ(expected, m.Call(*i, *j, shift)); } } } } { RawMachineAssemblerTester m(kMachineWord32, kMachineWord32, kMachineWord32); m.Return(m.Word32Equal(m.Word32Shr(m.Parameter(0), m.Parameter(1)), m.Parameter(2))); FOR_UINT32_INPUTS(i) { FOR_UINT32_INPUTS(j) { FOR_UINT32_INPUTS(k) { uint32_t shift = *j & 0x1F; int32_t expected = ((*i >> shift) == *k); CHECK_EQ(expected, m.Call(*i, shift, *k)); } } } } } TEST(RunDeadNodes) { for (int i = 0; true; i++) { RawMachineAssemblerTester m(i == 5 ? kMachineWord32 : kMachineLast); 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, kMachineWord32); 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 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++) { RawMachineAssemblerTester m(kMachineWord32, kMachineWord32); 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 static void RunLoadImmIndex(MachineType rep) { const int kNumElems = 3; CType buffer[kNumElems]; // initialize the buffer with raw data. byte* raw = reinterpret_cast(buffer); for (size_t i = 0; i < sizeof(buffer); i++) { raw[i] = static_cast((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 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(m.Call()); CHECK_EQ(expected, actual); printf("XXX\n"); } } } TEST(RunLoadImmIndex) { RunLoadImmIndex(kMachineWord8); RunLoadImmIndex(kMachineWord16); RunLoadImmIndex(kMachineWord32); RunLoadImmIndex(kMachineTagged); // TODO(titzer): test kMachineFloat64 loads // TODO(titzer): test various indexing modes. } template 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(buffer); for (size_t i = 0; i < sizeof(buffer); i++) { raw[i] = static_cast((i + sizeof(buffer)) ^ 0xAA); } RawMachineAssemblerTester 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(kMachineWord8); RunLoadStore(kMachineWord16); RunLoadStore(kMachineWord32); RunLoadStore(kMachineTagged); RunLoadStore(kMachineFloat64); } TEST(RunFloat64Binop) { RawMachineAssemblerTester 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 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(kMachineFloat64, base, zero, binop); m.Return(m.Int32Constant(i + j)); CHECK_EQ(i + j, m.Call()); } } } TEST(RunDeadFloat64Binops) { RawMachineAssemblerTester 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 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 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 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 m; Node* t0 = m.LoadFromPointer(&input, kMachineFloat64); Node* t1 = m.Float64Sub(m.Float64Constant(*i), t0); m.StoreToPointer(&output, kMachineFloat64, 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 m; Node* t0 = m.LoadFromPointer(&input, kMachineFloat64); Node* t1 = m.Float64Sub(t0, m.Float64Constant(*i)); m.StoreToPointer(&output, kMachineFloat64, 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 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 m; Node* a = m.LoadFromPointer(&input_a, kMachineFloat64); Node* b = m.LoadFromPointer(&input_b, kMachineFloat64); Node* c = m.LoadFromPointer(&input_c, kMachineFloat64); m.StoreToPointer(&output, kMachineFloat64, 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 m; Node* a = m.LoadFromPointer(&input_a, kMachineFloat64); Node* b = m.LoadFromPointer(&input_b, kMachineFloat64); Node* c = m.LoadFromPointer(&input_c, kMachineFloat64); m.StoreToPointer(&output, kMachineFloat64, 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 m; Node* a = m.LoadFromPointer(&input_a, kMachineFloat64); Node* b = m.LoadFromPointer(&input_b, kMachineFloat64); Node* c = m.LoadFromPointer(&input_c, kMachineFloat64); m.StoreToPointer(&output, kMachineFloat64, 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 m; Node* t0 = m.LoadFromPointer(&input, kMachineFloat64); Node* t1 = m.Float64Mul(m.Float64Constant(*i), t0); m.StoreToPointer(&output, kMachineFloat64, 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 m; Node* t0 = m.LoadFromPointer(&input, kMachineFloat64); Node* t1 = m.Float64Mul(t0, m.Float64Constant(*i)); m.StoreToPointer(&output, kMachineFloat64, 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 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 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 m; int32_t magic = 0x986234; double result = 0; Node* convert = m.ChangeInt32ToFloat64(m.Int32Constant(magic)); m.Store(kMachineFloat64, m.PointerConstant(&result), m.Int32Constant(0), convert); m.Return(m.Int32Constant(magic)); CHECK_EQ(magic, m.Call()); CHECK_EQ(static_cast(magic), result); } TEST(RunChangeInt32ToFloat64_B) { RawMachineAssemblerTester m(kMachineWord32); double output = 0; Node* convert = m.ChangeInt32ToFloat64(m.Parameter(0)); m.Store(kMachineFloat64, 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(expect), output); } } TEST(RunChangeUint32ToFloat64_B) { RawMachineAssemblerTester m(kMachineWord32); double output = 0; Node* convert = m.ChangeUint32ToFloat64(m.Parameter(0)); m.Store(kMachineFloat64, 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(expect), output); } } TEST(RunChangeFloat64ToInt32_A) { RawMachineAssemblerTester m; int32_t magic = 0x786234; double input = 11.1; int32_t result = 0; m.Store(kMachineWord32, 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(input), result); } TEST(RunChangeFloat64ToInt32_B) { RawMachineAssemblerTester m; double input = 0; int32_t output = 0; Node* load = m.Load(kMachineFloat64, m.PointerConstant(&input), m.Int32Constant(0)); Node* convert = m.ChangeFloat64ToInt32(load); m.Store(kMachineWord32, 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(input); CHECK_EQ(expect, m.Call()); CHECK_EQ(expect, output); } { input = 3 << n; int32_t expect = static_cast(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 m; double input = 0; int32_t output = 0; Node* load = m.Load(kMachineFloat64, m.PointerConstant(&input), m.Int32Constant(0)); Node* convert = m.ChangeFloat64ToUint32(load); m.Store(kMachineWord32, 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(*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(static_cast(input)); CHECK_EQ(expect, m.Call()); CHECK_EQ(expect, output); } { input = 3u << n; int32_t expect = static_cast(static_cast(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 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(kMachineFloat64, m.PointerConstant(&input), m.Int32Constant(i * 8)); } for (int i = 0; i < kNumInputs; i++) { m.Store(kMachineWord32, 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 m; const int magic = 0x88abcda4; m.ChangeFloat64ToInt32(m.Float64Constant(999.78)); m.Return(m.Int32Constant(magic)); CHECK_EQ(magic, m.Call()); } TEST(RunDeadChangeInt32ToFloat64) { RawMachineAssemblerTester m; const int magic = 0x8834abcd; m.ChangeInt32ToFloat64(m.Int32Constant(magic - 6888)); m.Return(m.Int32Constant(magic)); CHECK_EQ(magic, m.Call()); } TEST(RunLoopPhiInduction2) { RawMachineAssemblerTester 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 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(kMachineFloat64, m.PointerConstant(&buffer), m.Int32Constant(0), phi); m.Return(m.Int32Constant(magic)); CHECK_EQ(magic, m.Call()); CHECK_EQ(constant, buffer); } TEST(RunRefDiamond) { RawMachineAssemblerTester m; const int magic = 99644; Handle 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(kMachineTagged, m.PointerConstant(&buffer), m.Int32Constant(0), phi); m.Return(m.Int32Constant(magic)); CHECK_EQ(magic, m.Call()); CHECK(rexpected->SameValue(buffer)); } TEST(RunDoubleRefDiamond) { RawMachineAssemblerTester m; const int magic = 99648; double dbuffer = 0.1; double dconstant = 99.99; Handle 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(kMachineFloat64, m.PointerConstant(&dbuffer), m.Int32Constant(0), dphi); m.Store(kMachineTagged, 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 m; const int magic = 99649; double dbuffer = 0.1; double dconstant = 99.997; Handle 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(kMachineFloat64, m.PointerConstant(&dbuffer), m.Int32Constant(0), dphi2); m.Store(kMachineTagged, 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 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(kMachineFloat64, m.PointerConstant(&buffer), m.Int32Constant(0), phi); m.Return(m.Int32Constant(magic)); CHECK_EQ(magic, m.Call()); } TEST(RunCountToTenAccRaw) { RawMachineAssemblerTester 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 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 m; int32_t inputs[] = {11, 12, 13, 14, 15, 16, 17, 18}; Node* base = m.PointerConstant(inputs); Node* n0 = m.Load(kMachineWord32, base, m.Int32Constant(0 * sizeof(int32_t))); Node* n1 = m.Load(kMachineWord32, base, m.Int32Constant(1 * sizeof(int32_t))); Node* n2 = m.Load(kMachineWord32, base, m.Int32Constant(2 * sizeof(int32_t))); Node* n3 = m.Load(kMachineWord32, base, m.Int32Constant(3 * sizeof(int32_t))); Node* n4 = m.Load(kMachineWord32, base, m.Int32Constant(4 * sizeof(int32_t))); Node* n5 = m.Load(kMachineWord32, base, m.Int32Constant(5 * sizeof(int32_t))); Node* n6 = m.Load(kMachineWord32, base, m.Int32Constant(6 * sizeof(int32_t))); Node* n7 = m.Load(kMachineWord32, 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(reinterpret_cast(&Seven)); RawMachineAssemblerTester 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, kMachineWord32, 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(reinterpret_cast(&UnaryMinus)); RawMachineAssemblerTester m(kMachineWord32); Node* args[] = {m.Parameter(0)}; MachineType arg_types[] = {kMachineWord32}; Node* function = call_direct ? m.PointerConstant(function_address) : m.LoadFromPointer(&function_address, MachineOperatorBuilder::pointer_rep()); m.Return(m.CallC(function, kMachineWord32, 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(reinterpret_cast(&APlusTwoB)); RawMachineAssemblerTester m(kMachineWord32, kMachineWord32); Node* args[] = {m.Parameter(0), m.Parameter(1)}; MachineType arg_types[] = {kMachineWord32, kMachineWord32}; Node* function = call_direct ? m.PointerConstant(function_address) : m.LoadFromPointer(&function_address, MachineOperatorBuilder::pointer_rep()); m.Return(m.CallC(function, kMachineWord32, 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* 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(kMachineFloat64, m->PointerConstant(&buffer[0])) : m->Float64Constant(x); Node* b = load_b ? m->Load(kMachineFloat64, 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 m; int expected = Float64CompareHelper(&m, test, node_type, inputs[input], inputs[input + 1]); CHECK_EQ(expected, m.Call()); } } } } TEST(RunFloat64UnorderedCompare) { RawMachineAssemblerTester 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 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 m; Node* a = m.LoadFromPointer(&input_a, kMachineFloat64); Node* b = m.LoadFromPointer(&input_b, kMachineFloat64); 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 m; Node* a = m.LoadFromPointer(&input_a, kMachineFloat64); Node* b = m.LoadFromPointer(&input_b, kMachineFloat64); 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 static void LoadStoreTruncation() { IntType input; RawMachineAssemblerTester 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::max(); const IntType min = std::numeric_limits::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(); LoadStoreTruncation(); } static void IntPtrCompare(intptr_t left, intptr_t right) { for (int test = 0; test < 7; test++) { RawMachineAssemblerTester 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(left), reinterpret_cast(right))); } } TEST(RunIntPtrCompare) { intptr_t min = std::numeric_limits::min(); intptr_t max = std::numeric_limits::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 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(kMachineWord32, output, m.Load(kMachineWord32, 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]); } } static inline uint32_t rotr32(uint32_t i, uint32_t j) { return (i >> j) | (i << (32 - j)); } TEST(RunTestInt32RotateRightP) { { RawMachineAssemblerTester m; Int32BinopTester bt(&m); bt.AddReturn(m.Word32Or( m.Word32Shr(bt.param0, bt.param1), m.Word32Shl(bt.param0, m.Int32Sub(m.Int32Constant(32), bt.param1)))); bt.Run(ValueHelper::uint32_vector(), ValueHelper::ror_vector(), rotr32); } { RawMachineAssemblerTester m; Int32BinopTester bt(&m); bt.AddReturn(m.Word32Or( m.Word32Shl(bt.param0, m.Int32Sub(m.Int32Constant(32), bt.param1)), m.Word32Shr(bt.param0, bt.param1))); bt.Run(ValueHelper::uint32_vector(), ValueHelper::ror_vector(), rotr32); } } TEST(RunTestInt32RotateRightImm) { FOR_INPUTS(uint32_t, ror, i) { { RawMachineAssemblerTester m(kMachineWord32); Node* value = m.Parameter(0); m.Return(m.Word32Or(m.Word32Shr(value, m.Int32Constant(*i)), m.Word32Shl(value, m.Int32Constant(32 - *i)))); m.Run(ValueHelper::uint32_vector(), std::bind2nd(std::ptr_fun(&rotr32), *i)); } { RawMachineAssemblerTester m(kMachineWord32); Node* value = m.Parameter(0); m.Return(m.Word32Or(m.Word32Shl(value, m.Int32Constant(32 - *i)), m.Word32Shr(value, m.Int32Constant(*i)))); m.Run(ValueHelper::uint32_vector(), std::bind2nd(std::ptr_fun(&rotr32), *i)); } } } TEST(RunSpillLotsOfThings) { static const int kInputSize = 1000; RawMachineAssemblerTester 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], kMachineWord32, 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 m(kMachineWord32, kMachineWord32); 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(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], kMachineWord32, 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 m(kMachineWord32); Isolate* isolate = CcTest::i_isolate(); Handle true_val = isolate->factory()->NewHeapNumber(11.2); Handle 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 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(reinterpret_cast(&Seven)); Node** args = NULL; MachineType* arg_types = NULL; m.CallC(m.PointerConstant(func), kMachineWord32, arg_types, args, 0); } for (int i = 0; i < kInputSize; i++) { m.StoreToPointer(&outputs[i], kMachineWord32, 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(static_cast(x) + static_cast(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(static_cast(x) - static_cast(y)); *val = v; return (((v ^ x) & (v ^ ~y)) >> 31) & 1; } TEST(RunInt32AddWithOverflowP) { int32_t actual_val = -1; RawMachineAssemblerTester 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, kMachineWord32, 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 m(kMachineWord32); 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, kMachineWord32, 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 m(kMachineWord32); 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, kMachineWord32, 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 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, kMachineWord32, 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 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_UINT32_INPUTS(i) { FOR_UINT32_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 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, kMachineWord32, 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 m(kMachineWord32); 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, kMachineWord32, 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 m(kMachineWord32); 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, kMachineWord32, 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 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, kMachineWord32, 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 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_UINT32_INPUTS(i) { FOR_UINT32_INPUTS(j) { int32_t expected; if (ssub_overflow(*i, *j, &expected)) expected = constant; CHECK_EQ(expected, bt.call(*i, *j)); } } } #endif // V8_TURBOFAN_TARGET