// 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 "src/compiler/generic-node-inl.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 < arraysize(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 < arraysize(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 < arraysize(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 < arraysize(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 < arraysize(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 < arraysize(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 < arraysize(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 < arraysize(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 < arraysize(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>
static void RunLoadImmIndex(MachineType rep) {
  const int kNumElems = 3;
  Type 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 = m.Call();
      CHECK(expected == actual);
    }
  }
}


TEST(RunLoadImmIndex) {
  RunLoadImmIndex<int8_t>(kMachInt8);
  RunLoadImmIndex<uint8_t>(kMachUint8);
  RunLoadImmIndex<int16_t>(kMachInt16);
  RunLoadImmIndex<uint16_t>(kMachUint16);
  RunLoadImmIndex<int32_t>(kMachInt32);
  RunLoadImmIndex<uint32_t>(kMachUint32);
  RunLoadImmIndex<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(buffer[x] != buffer[y]);
    CHECK_EQ(OK, m.Call());
    CHECK(buffer[x] == buffer[y]);
  }
}


TEST(RunLoadStore) {
  RunLoadStore<int8_t>(kMachInt8);
  RunLoadStore<uint8_t>(kMachUint8);
  RunLoadStore<int16_t>(kMachInt16);
  RunLoadStore<uint16_t>(kMachUint16);
  RunLoadStore<int32_t>(kMachInt32);
  RunLoadStore<uint32_t>(kMachUint32);
  RunLoadStore<void*>(kMachAnyTagged);
  RunLoadStore<float>(kMachFloat32);
  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, kMachPtr);
    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, kMachPtr);
    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, kMachPtr);
    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 < arraysize(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 < arraysize(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(static_cast<IntType>(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(static_cast<IntType>(expected), m.Call());
    CHECK_EQ(static_cast<IntType>(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(kMachPtr, kMachPtr);
    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 < arraysize(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());
    }
  }
}


TEST(RunTruncateFloat64ToInt32P) {
  struct {
    double from;
    double raw;
  } kValues[] = {{0, 0},
                 {0.5, 0},
                 {-0.5, 0},
                 {1.5, 1},
                 {-1.5, -1},
                 {5.5, 5},
                 {-5.0, -5},
                 {v8::base::OS::nan_value(), 0},
                 {std::numeric_limits<double>::infinity(), 0},
                 {-v8::base::OS::nan_value(), 0},
                 {-std::numeric_limits<double>::infinity(), 0},
                 {4.94065645841e-324, 0},
                 {-4.94065645841e-324, 0},
                 {0.9999999999999999, 0},
                 {-0.9999999999999999, 0},
                 {4294967296.0, 0},
                 {-4294967296.0, 0},
                 {9223372036854775000.0, 4294966272.0},
                 {-9223372036854775000.0, -4294966272.0},
                 {4.5036e+15, 372629504},
                 {-4.5036e+15, -372629504},
                 {287524199.5377777, 0x11234567},
                 {-287524199.5377777, -0x11234567},
                 {2300193596.302222, 2300193596.0},
                 {-2300193596.302222, -2300193596.0},
                 {4600387192.604444, 305419896},
                 {-4600387192.604444, -305419896},
                 {4823855600872397.0, 1737075661},
                 {-4823855600872397.0, -1737075661},
                 {4503603922337791.0, -1},
                 {-4503603922337791.0, 1},
                 {4503601774854143.0, 2147483647},
                 {-4503601774854143.0, -2147483647},
                 {9007207844675582.0, -2},
                 {-9007207844675582.0, 2},
                 {2.4178527921507624e+24, -536870912},
                 {-2.4178527921507624e+24, 536870912},
                 {2.417853945072267e+24, -536870912},
                 {-2.417853945072267e+24, 536870912},
                 {4.8357055843015248e+24, -1073741824},
                 {-4.8357055843015248e+24, 1073741824},
                 {4.8357078901445341e+24, -1073741824},
                 {-4.8357078901445341e+24, 1073741824},
                 {2147483647.0, 2147483647.0},
                 {-2147483648.0, -2147483648.0},
                 {9.6714111686030497e+24, -2147483648.0},
                 {-9.6714111686030497e+24, -2147483648.0},
                 {9.6714157802890681e+24, -2147483648.0},
                 {-9.6714157802890681e+24, -2147483648.0},
                 {1.9342813113834065e+25, 2147483648.0},
                 {-1.9342813113834065e+25, 2147483648.0},
                 {3.868562622766813e+25, 0},
                 {-3.868562622766813e+25, 0},
                 {1.7976931348623157e+308, 0},
                 {-1.7976931348623157e+308, 0}};
  double input = -1.0;
  RawMachineAssemblerTester<int32_t> m;
  m.Return(m.TruncateFloat64ToInt32(m.LoadFromPointer(&input, kMachFloat64)));
  for (size_t i = 0; i < arraysize(kValues); ++i) {
    input = kValues[i].from;
    uint64_t expected = static_cast<int64_t>(kValues[i].raw);
    CHECK_EQ(static_cast<int>(expected), m.Call());
  }
}

#endif  // V8_TURBOFAN_TARGET
