test-run-wasm.cc 131 KB
Newer Older
1 2 3 4
// Copyright 2015 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.

5
#include <stdint.h>
6 7 8
#include <stdlib.h>
#include <string.h>

9
#include "src/api/api-inl.h"
10
#include "src/base/overflowing-math.h"
11
#include "src/base/platform/elapsed-timer.h"
12
#include "src/codegen/assembler-inl.h"
13
#include "src/utils/utils.h"
14
#include "src/wasm/wasm-opcodes-inl.h"
15 16
#include "test/cctest/cctest.h"
#include "test/cctest/compiler/value-helper.h"
17
#include "test/cctest/wasm/wasm-run-utils.h"
18
#include "test/common/wasm/test-signatures.h"
19
#include "test/common/wasm/wasm-macro-gen.h"
20

21 22 23
namespace v8 {
namespace internal {
namespace wasm {
24
namespace test_run_wasm {
25

26
// for even shorter tests.
27 28 29
#define B1(a) WASM_BLOCK(a)
#define B2(a, b) WASM_BLOCK(a, b)
#define RET(x) x, kExprReturn
30
#define RET_I8(x) WASM_I32V_2(x), kExprReturn
31

32
WASM_EXEC_TEST(Int32Const) {
33
  WasmRunner<int32_t> r(execution_tier);
34 35
  const int32_t kExpectedValue = 0x11223344;
  // return(kExpectedValue)
36
  BUILD(r, WASM_I32V_5(kExpectedValue));
37 38 39
  CHECK_EQ(kExpectedValue, r.Call());
}

40
WASM_EXEC_TEST(Int32Const_many) {
41
  FOR_INT32_INPUTS(i) {
42
    WasmRunner<int32_t> r(execution_tier);
43
    const int32_t kExpectedValue = i;
44
    // return(kExpectedValue)
45
    BUILD(r, WASM_I32V(kExpectedValue));
46 47 48 49
    CHECK_EQ(kExpectedValue, r.Call());
  }
}

50 51
WASM_EXEC_TEST(GraphTrimming) {
  // This WebAssembly code requires graph trimming in the TurboFan compiler.
52
  WasmRunner<int32_t, int32_t> r(execution_tier);
53 54
  BUILD(r, kExprLocalGet, 0, kExprLocalGet, 0, kExprLocalGet, 0, kExprI32RemS,
        kExprI32Eq, kExprLocalGet, 0, kExprI32DivS, kExprUnreachable);
55 56 57
  r.Call(1);
}

58
WASM_EXEC_TEST(Int32Param0) {
59
  WasmRunner<int32_t, int32_t> r(execution_tier);
60
  // return(local[0])
61
  BUILD(r, WASM_LOCAL_GET(0));
62
  FOR_INT32_INPUTS(i) { CHECK_EQ(i, r.Call(i)); }
63 64
}

65
WASM_EXEC_TEST(Int32Param0_fallthru) {
66
  WasmRunner<int32_t, int32_t> r(execution_tier);
67
  // local[0]
68
  BUILD(r, WASM_LOCAL_GET(0));
69
  FOR_INT32_INPUTS(i) { CHECK_EQ(i, r.Call(i)); }
70 71
}

72
WASM_EXEC_TEST(Int32Param1) {
73
  WasmRunner<int32_t, int32_t, int32_t> r(execution_tier);
74
  // local[1]
75
  BUILD(r, WASM_LOCAL_GET(1));
76
  FOR_INT32_INPUTS(i) { CHECK_EQ(i, r.Call(-111, i)); }
77 78
}

79
WASM_EXEC_TEST(Int32Add) {
80
  WasmRunner<int32_t> r(execution_tier);
81
  // 11 + 44
82
  BUILD(r, WASM_I32_ADD(WASM_I32V_1(11), WASM_I32V_1(44)));
83 84 85
  CHECK_EQ(55, r.Call());
}

86
WASM_EXEC_TEST(Int32Add_P) {
87
  WasmRunner<int32_t, int32_t> r(execution_tier);
88
  // p0 + 13
89
  BUILD(r, WASM_I32_ADD(WASM_I32V_1(13), WASM_LOCAL_GET(0)));
90
  FOR_INT32_INPUTS(i) { CHECK_EQ(base::AddWithWraparound(i, 13), r.Call(i)); }
91 92
}

93
WASM_EXEC_TEST(Int32Add_P_fallthru) {
94
  WasmRunner<int32_t, int32_t> r(execution_tier);
95
  // p0 + 13
96
  BUILD(r, WASM_I32_ADD(WASM_I32V_1(13), WASM_LOCAL_GET(0)));
97
  FOR_INT32_INPUTS(i) { CHECK_EQ(base::AddWithWraparound(i, 13), r.Call(i)); }
98 99
}

100
static void RunInt32AddTest(TestExecutionTier execution_tier, const byte* code,
101
                            size_t size) {
102
  TestSignatures sigs;
103
  WasmRunner<int32_t, int32_t, int32_t> r(execution_tier);
104 105
  r.builder().AddSignature(sigs.ii_v());
  r.builder().AddSignature(sigs.iii_v());
106
  r.Build(code, code + size);
107 108
  FOR_INT32_INPUTS(i) {
    FOR_INT32_INPUTS(j) {
109 110 111
      int32_t expected = static_cast<int32_t>(static_cast<uint32_t>(i) +
                                              static_cast<uint32_t>(j));
      CHECK_EQ(expected, r.Call(i, j));
112 113 114 115
    }
  }
}

116 117
WASM_EXEC_TEST(Int32Add_P2) {
  static const byte code[] = {
118
      WASM_I32_ADD(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1))};
119
  RunInt32AddTest(execution_tier, code, sizeof(code));
120 121 122 123
}

WASM_EXEC_TEST(Int32Add_block1) {
  static const byte code[] = {
124
      WASM_BLOCK_X(1, WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)), kExprI32Add};
125
  RunInt32AddTest(execution_tier, code, sizeof(code));
126 127 128 129
}

WASM_EXEC_TEST(Int32Add_block2) {
  static const byte code[] = {
130
      WASM_BLOCK_X(1, WASM_LOCAL_GET(0), WASM_LOCAL_GET(1), kExprBr, DEPTH_0),
131
      kExprI32Add};
132
  RunInt32AddTest(execution_tier, code, sizeof(code));
133 134 135 136
}

WASM_EXEC_TEST(Int32Add_multi_if) {
  static const byte code[] = {
137 138 139
      WASM_IF_ELSE_X(1, WASM_LOCAL_GET(0),
                     WASM_SEQ(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)),
                     WASM_SEQ(WASM_LOCAL_GET(1), WASM_LOCAL_GET(0))),
140
      kExprI32Add};
141
  RunInt32AddTest(execution_tier, code, sizeof(code));
142 143
}

144
WASM_EXEC_TEST(Float32Add) {
145
  WasmRunner<int32_t> r(execution_tier);
146 147 148 149 150 151
  // int(11.5f + 44.5f)
  BUILD(r,
        WASM_I32_SCONVERT_F32(WASM_F32_ADD(WASM_F32(11.5f), WASM_F32(44.5f))));
  CHECK_EQ(56, r.Call());
}

152
WASM_EXEC_TEST(Float64Add) {
153
  WasmRunner<int32_t> r(execution_tier);
154 155 156 157 158
  // return int(13.5d + 43.5d)
  BUILD(r, WASM_I32_SCONVERT_F64(WASM_F64_ADD(WASM_F64(13.5), WASM_F64(43.5))));
  CHECK_EQ(57, r.Call());
}

159 160 161
// clang-format messes up the FOR_INT32_INPUTS macros.
// clang-format off
template<typename ctype>
162
static void TestInt32Binop(TestExecutionTier execution_tier, WasmOpcode opcode,
163 164 165
                           ctype(*expected)(ctype, ctype)) {
  FOR_INT32_INPUTS(i) {
    FOR_INT32_INPUTS(j) {
166
      WasmRunner<ctype> r(execution_tier);
167
      // Apply {opcode} on two constants.
168 169
      BUILD(r, WASM_BINOP(opcode, WASM_I32V(i), WASM_I32V(j)));
      CHECK_EQ(expected(i, j), r.Call());
170
    }
171 172
  }
  {
173
    WasmRunner<ctype, ctype, ctype> r(execution_tier);
174
    // Apply {opcode} on two parameters.
175
    BUILD(r, WASM_BINOP(opcode, WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)));
176 177
    FOR_INT32_INPUTS(i) {
      FOR_INT32_INPUTS(j) {
178
        CHECK_EQ(expected(i, j), r.Call(i, j));
179 180
      }
    }
181 182
  }
}
183
// clang-format on
184

185 186
#define WASM_I32_BINOP_TEST(expr, ctype, expected)                             \
  WASM_EXEC_TEST(I32Binop_##expr) {                                            \
187
    TestInt32Binop<ctype>(execution_tier, kExprI32##expr,                      \
188 189 190
                          [](ctype a, ctype b) -> ctype { return expected; }); \
  }

191 192 193
WASM_I32_BINOP_TEST(Add, int32_t, base::AddWithWraparound(a, b))
WASM_I32_BINOP_TEST(Sub, int32_t, base::SubWithWraparound(a, b))
WASM_I32_BINOP_TEST(Mul, int32_t, base::MulWithWraparound(a, b))
194 195
WASM_I32_BINOP_TEST(DivS, int32_t,
                    (a == kMinInt && b == -1) || b == 0
196
                        ? static_cast<int32_t>(0xDEADBEEF)
197
                        : a / b)
198 199 200
WASM_I32_BINOP_TEST(DivU, uint32_t, b == 0 ? 0xDEADBEEF : a / b)
WASM_I32_BINOP_TEST(RemS, int32_t, b == 0 ? 0xDEADBEEF : b == -1 ? 0 : a % b)
WASM_I32_BINOP_TEST(RemU, uint32_t, b == 0 ? 0xDEADBEEF : a % b)
201 202 203
WASM_I32_BINOP_TEST(And, int32_t, a& b)
WASM_I32_BINOP_TEST(Ior, int32_t, a | b)
WASM_I32_BINOP_TEST(Xor, int32_t, a ^ b)
204
WASM_I32_BINOP_TEST(Shl, int32_t, base::ShlWithWraparound(a, b))
205 206
WASM_I32_BINOP_TEST(ShrU, uint32_t, a >> (b & 0x1F))
WASM_I32_BINOP_TEST(ShrS, int32_t, a >> (b & 0x1F))
207 208
WASM_I32_BINOP_TEST(Ror, uint32_t, (a >> (b & 0x1F)) | (a << ((32 - b) & 0x1F)))
WASM_I32_BINOP_TEST(Rol, uint32_t, (a << (b & 0x1F)) | (a >> ((32 - b) & 0x1F)))
209 210 211 212 213 214 215 216 217 218 219 220
WASM_I32_BINOP_TEST(Eq, int32_t, a == b)
WASM_I32_BINOP_TEST(Ne, int32_t, a != b)
WASM_I32_BINOP_TEST(LtS, int32_t, a < b)
WASM_I32_BINOP_TEST(LeS, int32_t, a <= b)
WASM_I32_BINOP_TEST(LtU, uint32_t, a < b)
WASM_I32_BINOP_TEST(LeU, uint32_t, a <= b)
WASM_I32_BINOP_TEST(GtS, int32_t, a > b)
WASM_I32_BINOP_TEST(GeS, int32_t, a >= b)
WASM_I32_BINOP_TEST(GtU, uint32_t, a > b)
WASM_I32_BINOP_TEST(GeU, uint32_t, a >= b)

#undef WASM_I32_BINOP_TEST
221

222
void TestInt32Unop(TestExecutionTier execution_tier, WasmOpcode opcode,
223
                   int32_t expected, int32_t a) {
224
  {
225
    WasmRunner<int32_t> r(execution_tier);
226
    // return op K
227
    BUILD(r, WASM_UNOP(opcode, WASM_I32V(a)));
228 229 230
    CHECK_EQ(expected, r.Call());
  }
  {
231
    WasmRunner<int32_t, int32_t> r(execution_tier);
232
    // return op a
233
    BUILD(r, WASM_UNOP(opcode, WASM_LOCAL_GET(0)));
234 235 236 237
    CHECK_EQ(expected, r.Call(a));
  }
}

238
WASM_EXEC_TEST(Int32Clz) {
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
  TestInt32Unop(execution_tier, kExprI32Clz, 0, 0x80001000);
  TestInt32Unop(execution_tier, kExprI32Clz, 1, 0x40000500);
  TestInt32Unop(execution_tier, kExprI32Clz, 2, 0x20000300);
  TestInt32Unop(execution_tier, kExprI32Clz, 3, 0x10000003);
  TestInt32Unop(execution_tier, kExprI32Clz, 4, 0x08050000);
  TestInt32Unop(execution_tier, kExprI32Clz, 5, 0x04006000);
  TestInt32Unop(execution_tier, kExprI32Clz, 6, 0x02000000);
  TestInt32Unop(execution_tier, kExprI32Clz, 7, 0x010000A0);
  TestInt32Unop(execution_tier, kExprI32Clz, 8, 0x00800C00);
  TestInt32Unop(execution_tier, kExprI32Clz, 9, 0x00400000);
  TestInt32Unop(execution_tier, kExprI32Clz, 10, 0x0020000D);
  TestInt32Unop(execution_tier, kExprI32Clz, 11, 0x00100F00);
  TestInt32Unop(execution_tier, kExprI32Clz, 12, 0x00080000);
  TestInt32Unop(execution_tier, kExprI32Clz, 13, 0x00041000);
  TestInt32Unop(execution_tier, kExprI32Clz, 14, 0x00020020);
  TestInt32Unop(execution_tier, kExprI32Clz, 15, 0x00010300);
  TestInt32Unop(execution_tier, kExprI32Clz, 16, 0x00008040);
  TestInt32Unop(execution_tier, kExprI32Clz, 17, 0x00004005);
  TestInt32Unop(execution_tier, kExprI32Clz, 18, 0x00002050);
  TestInt32Unop(execution_tier, kExprI32Clz, 19, 0x00001700);
  TestInt32Unop(execution_tier, kExprI32Clz, 20, 0x00000870);
  TestInt32Unop(execution_tier, kExprI32Clz, 21, 0x00000405);
  TestInt32Unop(execution_tier, kExprI32Clz, 22, 0x00000203);
  TestInt32Unop(execution_tier, kExprI32Clz, 23, 0x00000101);
  TestInt32Unop(execution_tier, kExprI32Clz, 24, 0x00000089);
  TestInt32Unop(execution_tier, kExprI32Clz, 25, 0x00000041);
  TestInt32Unop(execution_tier, kExprI32Clz, 26, 0x00000022);
  TestInt32Unop(execution_tier, kExprI32Clz, 27, 0x00000013);
  TestInt32Unop(execution_tier, kExprI32Clz, 28, 0x00000008);
  TestInt32Unop(execution_tier, kExprI32Clz, 29, 0x00000004);
  TestInt32Unop(execution_tier, kExprI32Clz, 30, 0x00000002);
  TestInt32Unop(execution_tier, kExprI32Clz, 31, 0x00000001);
  TestInt32Unop(execution_tier, kExprI32Clz, 32, 0x00000000);
272 273
}

274
WASM_EXEC_TEST(Int32Ctz) {
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
  TestInt32Unop(execution_tier, kExprI32Ctz, 32, 0x00000000);
  TestInt32Unop(execution_tier, kExprI32Ctz, 31, 0x80000000);
  TestInt32Unop(execution_tier, kExprI32Ctz, 30, 0x40000000);
  TestInt32Unop(execution_tier, kExprI32Ctz, 29, 0x20000000);
  TestInt32Unop(execution_tier, kExprI32Ctz, 28, 0x10000000);
  TestInt32Unop(execution_tier, kExprI32Ctz, 27, 0xA8000000);
  TestInt32Unop(execution_tier, kExprI32Ctz, 26, 0xF4000000);
  TestInt32Unop(execution_tier, kExprI32Ctz, 25, 0x62000000);
  TestInt32Unop(execution_tier, kExprI32Ctz, 24, 0x91000000);
  TestInt32Unop(execution_tier, kExprI32Ctz, 23, 0xCD800000);
  TestInt32Unop(execution_tier, kExprI32Ctz, 22, 0x09400000);
  TestInt32Unop(execution_tier, kExprI32Ctz, 21, 0xAF200000);
  TestInt32Unop(execution_tier, kExprI32Ctz, 20, 0xAC100000);
  TestInt32Unop(execution_tier, kExprI32Ctz, 19, 0xE0B80000);
  TestInt32Unop(execution_tier, kExprI32Ctz, 18, 0x9CE40000);
  TestInt32Unop(execution_tier, kExprI32Ctz, 17, 0xC7920000);
  TestInt32Unop(execution_tier, kExprI32Ctz, 16, 0xB8F10000);
  TestInt32Unop(execution_tier, kExprI32Ctz, 15, 0x3B9F8000);
  TestInt32Unop(execution_tier, kExprI32Ctz, 14, 0xDB4C4000);
  TestInt32Unop(execution_tier, kExprI32Ctz, 13, 0xE9A32000);
  TestInt32Unop(execution_tier, kExprI32Ctz, 12, 0xFCA61000);
  TestInt32Unop(execution_tier, kExprI32Ctz, 11, 0x6C8A7800);
  TestInt32Unop(execution_tier, kExprI32Ctz, 10, 0x8CE5A400);
  TestInt32Unop(execution_tier, kExprI32Ctz, 9, 0xCB7D0200);
  TestInt32Unop(execution_tier, kExprI32Ctz, 8, 0xCB4DC100);
  TestInt32Unop(execution_tier, kExprI32Ctz, 7, 0xDFBEC580);
  TestInt32Unop(execution_tier, kExprI32Ctz, 6, 0x27A9DB40);
  TestInt32Unop(execution_tier, kExprI32Ctz, 5, 0xDE3BCB20);
  TestInt32Unop(execution_tier, kExprI32Ctz, 4, 0xD7E8A610);
  TestInt32Unop(execution_tier, kExprI32Ctz, 3, 0x9AFDBC88);
  TestInt32Unop(execution_tier, kExprI32Ctz, 2, 0x9AFDBC84);
  TestInt32Unop(execution_tier, kExprI32Ctz, 1, 0x9AFDBC82);
  TestInt32Unop(execution_tier, kExprI32Ctz, 0, 0x9AFDBC81);
308 309
}

310
WASM_EXEC_TEST(Int32Popcnt) {
311 312 313 314 315
  TestInt32Unop(execution_tier, kExprI32Popcnt, 32, 0xFFFFFFFF);
  TestInt32Unop(execution_tier, kExprI32Popcnt, 0, 0x00000000);
  TestInt32Unop(execution_tier, kExprI32Popcnt, 1, 0x00008000);
  TestInt32Unop(execution_tier, kExprI32Popcnt, 13, 0x12345678);
  TestInt32Unop(execution_tier, kExprI32Popcnt, 19, 0xFEDCBA09);
316 317
}

318
WASM_EXEC_TEST(I32Eqz) {
319 320 321 322 323
  TestInt32Unop(execution_tier, kExprI32Eqz, 0, 1);
  TestInt32Unop(execution_tier, kExprI32Eqz, 0, -1);
  TestInt32Unop(execution_tier, kExprI32Eqz, 0, -827343);
  TestInt32Unop(execution_tier, kExprI32Eqz, 0, 8888888);
  TestInt32Unop(execution_tier, kExprI32Eqz, 1, 0);
324 325
}

326

327
WASM_EXEC_TEST(Int32DivS_trap) {
328
  WasmRunner<int32_t, int32_t, int32_t> r(execution_tier);
329
  BUILD(r, WASM_I32_DIVS(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)));
330
  const int32_t kMin = std::numeric_limits<int32_t>::min();
331 332 333
  CHECK_EQ(0, r.Call(0, 100));
  CHECK_TRAP(r.Call(100, 0));
  CHECK_TRAP(r.Call(-1001, 0));
334 335
  CHECK_TRAP(r.Call(kMin, -1));
  CHECK_TRAP(r.Call(kMin, 0));
336 337
}

338
WASM_EXEC_TEST(Int32RemS_trap) {
339
  WasmRunner<int32_t, int32_t, int32_t> r(execution_tier);
340
  BUILD(r, WASM_I32_REMS(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)));
341
  const int32_t kMin = std::numeric_limits<int32_t>::min();
342
  CHECK_EQ(33, r.Call(133, 100));
343
  CHECK_EQ(0, r.Call(kMin, -1));
344 345
  CHECK_TRAP(r.Call(100, 0));
  CHECK_TRAP(r.Call(-1001, 0));
346
  CHECK_TRAP(r.Call(kMin, 0));
347 348
}

349
WASM_EXEC_TEST(Int32DivU_trap) {
350
  WasmRunner<int32_t, int32_t, int32_t> r(execution_tier);
351
  BUILD(r, WASM_I32_DIVU(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)));
352
  const int32_t kMin = std::numeric_limits<int32_t>::min();
353
  CHECK_EQ(0, r.Call(0, 100));
354
  CHECK_EQ(0, r.Call(kMin, -1));
355 356
  CHECK_TRAP(r.Call(100, 0));
  CHECK_TRAP(r.Call(-1001, 0));
357
  CHECK_TRAP(r.Call(kMin, 0));
358 359
}

360
WASM_EXEC_TEST(Int32RemU_trap) {
361
  WasmRunner<int32_t, int32_t, int32_t> r(execution_tier);
362
  BUILD(r, WASM_I32_REMU(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)));
363
  CHECK_EQ(17, r.Call(217, 100));
364
  const int32_t kMin = std::numeric_limits<int32_t>::min();
365 366
  CHECK_TRAP(r.Call(100, 0));
  CHECK_TRAP(r.Call(-1001, 0));
367 368 369 370
  CHECK_TRAP(r.Call(kMin, 0));
  CHECK_EQ(kMin, r.Call(kMin, -1));
}

371
WASM_EXEC_TEST(Int32DivS_byzero_const) {
372
  for (int8_t denom = -2; denom < 8; ++denom) {
373
    WasmRunner<int32_t, int32_t> r(execution_tier);
374
    BUILD(r, WASM_I32_DIVS(WASM_LOCAL_GET(0), WASM_I32V_1(denom)));
375
    for (int32_t val = -7; val < 8; ++val) {
376 377 378 379 380 381 382 383 384
      if (denom == 0) {
        CHECK_TRAP(r.Call(val));
      } else {
        CHECK_EQ(val / denom, r.Call(val));
      }
    }
  }
}

385
WASM_EXEC_TEST(Int32DivU_byzero_const) {
386
  for (uint32_t denom = 0xFFFFFFFE; denom < 8; ++denom) {
387
    WasmRunner<uint32_t, uint32_t> r(execution_tier);
388
    BUILD(r, WASM_I32_DIVU(WASM_LOCAL_GET(0), WASM_I32V_1(denom)));
389

390
    for (uint32_t val = 0xFFFFFFF0; val < 8; ++val) {
391 392 393 394 395 396 397 398 399
      if (denom == 0) {
        CHECK_TRAP(r.Call(val));
      } else {
        CHECK_EQ(val / denom, r.Call(val));
      }
    }
  }
}

400
WASM_EXEC_TEST(Int32DivS_trap_effect) {
401
  WasmRunner<int32_t, int32_t, int32_t> r(execution_tier);
402
  r.builder().AddMemory(kWasmPageSize);
403

404
  BUILD(r, WASM_IF_ELSE_I(
405
               WASM_LOCAL_GET(0),
406 407
               WASM_I32_DIVS(
                   WASM_BLOCK_I(WASM_STORE_MEM(MachineType::Int8(), WASM_ZERO,
408 409 410
                                               WASM_LOCAL_GET(0)),
                                WASM_LOCAL_GET(0)),
                   WASM_LOCAL_GET(1)),
411 412
               WASM_I32_DIVS(
                   WASM_BLOCK_I(WASM_STORE_MEM(MachineType::Int8(), WASM_ZERO,
413 414 415
                                               WASM_LOCAL_GET(0)),
                                WASM_LOCAL_GET(0)),
                   WASM_LOCAL_GET(1))));
416 417 418 419 420 421
  CHECK_EQ(0, r.Call(0, 100));
  CHECK_TRAP(r.Call(8, 0));
  CHECK_TRAP(r.Call(4, 0));
  CHECK_TRAP(r.Call(0, 0));
}

422
void TestFloat32Binop(TestExecutionTier execution_tier, WasmOpcode opcode,
423
                      int32_t expected, float a, float b) {
424
  {
425
    WasmRunner<int32_t> r(execution_tier);
426 427 428 429 430
    // return K op K
    BUILD(r, WASM_BINOP(opcode, WASM_F32(a), WASM_F32(b)));
    CHECK_EQ(expected, r.Call());
  }
  {
431
    WasmRunner<int32_t, float, float> r(execution_tier);
432
    // return a op b
433
    BUILD(r, WASM_BINOP(opcode, WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)));
434 435
    CHECK_EQ(expected, r.Call(a, b));
  }
436 437
}

438
void TestFloat32BinopWithConvert(TestExecutionTier execution_tier,
439
                                 WasmOpcode opcode, int32_t expected, float a,
440
                                 float b) {
441
  {
442
    WasmRunner<int32_t> r(execution_tier);
443 444 445 446 447 448
    // return int(K op K)
    BUILD(r,
          WASM_I32_SCONVERT_F32(WASM_BINOP(opcode, WASM_F32(a), WASM_F32(b))));
    CHECK_EQ(expected, r.Call());
  }
  {
449
    WasmRunner<int32_t, float, float> r(execution_tier);
450 451
    // return int(a op b)
    BUILD(r, WASM_I32_SCONVERT_F32(
452
                 WASM_BINOP(opcode, WASM_LOCAL_GET(0), WASM_LOCAL_GET(1))));
453 454
    CHECK_EQ(expected, r.Call(a, b));
  }
455 456
}

457 458
void TestFloat32UnopWithConvert(TestExecutionTier execution_tier,
                                WasmOpcode opcode, int32_t expected, float a) {
459
  {
460
    WasmRunner<int32_t> r(execution_tier);
461 462 463 464 465
    // return int(op(K))
    BUILD(r, WASM_I32_SCONVERT_F32(WASM_UNOP(opcode, WASM_F32(a))));
    CHECK_EQ(expected, r.Call());
  }
  {
466
    WasmRunner<int32_t, float> r(execution_tier);
467
    // return int(op(a))
468
    BUILD(r, WASM_I32_SCONVERT_F32(WASM_UNOP(opcode, WASM_LOCAL_GET(0))));
469 470
    CHECK_EQ(expected, r.Call(a));
  }
471 472
}

473
void TestFloat64Binop(TestExecutionTier execution_tier, WasmOpcode opcode,
474
                      int32_t expected, double a, double b) {
475
  {
476
    WasmRunner<int32_t> r(execution_tier);
477 478 479 480 481
    // return K op K
    BUILD(r, WASM_BINOP(opcode, WASM_F64(a), WASM_F64(b)));
    CHECK_EQ(expected, r.Call());
  }
  {
482
    WasmRunner<int32_t, double, double> r(execution_tier);
483
    // return a op b
484
    BUILD(r, WASM_BINOP(opcode, WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)));
485 486
    CHECK_EQ(expected, r.Call(a, b));
  }
487 488
}

489
void TestFloat64BinopWithConvert(TestExecutionTier execution_tier,
490
                                 WasmOpcode opcode, int32_t expected, double a,
491
                                 double b) {
492
  {
493
    WasmRunner<int32_t> r(execution_tier);
494 495 496 497 498 499
    // return int(K op K)
    BUILD(r,
          WASM_I32_SCONVERT_F64(WASM_BINOP(opcode, WASM_F64(a), WASM_F64(b))));
    CHECK_EQ(expected, r.Call());
  }
  {
500
    WasmRunner<int32_t, double, double> r(execution_tier);
501
    BUILD(r, WASM_I32_SCONVERT_F64(
502
                 WASM_BINOP(opcode, WASM_LOCAL_GET(0), WASM_LOCAL_GET(1))));
503 504
    CHECK_EQ(expected, r.Call(a, b));
  }
505 506
}

507 508
void TestFloat64UnopWithConvert(TestExecutionTier execution_tier,
                                WasmOpcode opcode, int32_t expected, double a) {
509
  {
510
    WasmRunner<int32_t> r(execution_tier);
511 512 513 514 515
    // return int(op(K))
    BUILD(r, WASM_I32_SCONVERT_F64(WASM_UNOP(opcode, WASM_F64(a))));
    CHECK_EQ(expected, r.Call());
  }
  {
516
    WasmRunner<int32_t, double> r(execution_tier);
517
    // return int(op(a))
518
    BUILD(r, WASM_I32_SCONVERT_F64(WASM_UNOP(opcode, WASM_LOCAL_GET(0))));
519 520
    CHECK_EQ(expected, r.Call(a));
  }
521 522
}

523
WASM_EXEC_TEST(Float32Binops) {
524 525 526 527 528 529
  TestFloat32Binop(execution_tier, kExprF32Eq, 1, 8.125f, 8.125f);
  TestFloat32Binop(execution_tier, kExprF32Ne, 1, 8.125f, 8.127f);
  TestFloat32Binop(execution_tier, kExprF32Lt, 1, -9.5f, -9.0f);
  TestFloat32Binop(execution_tier, kExprF32Le, 1, -1111.0f, -1111.0f);
  TestFloat32Binop(execution_tier, kExprF32Gt, 1, -9.0f, -9.5f);
  TestFloat32Binop(execution_tier, kExprF32Ge, 1, -1111.0f, -1111.0f);
530

531 532 533 534
  TestFloat32BinopWithConvert(execution_tier, kExprF32Add, 10, 3.5f, 6.5f);
  TestFloat32BinopWithConvert(execution_tier, kExprF32Sub, 2, 44.5f, 42.5f);
  TestFloat32BinopWithConvert(execution_tier, kExprF32Mul, -66, -132.1f, 0.5f);
  TestFloat32BinopWithConvert(execution_tier, kExprF32Div, 11, 22.1f, 2.0f);
535 536
}

537
WASM_EXEC_TEST(Float32Unops) {
538 539 540 541
  TestFloat32UnopWithConvert(execution_tier, kExprF32Abs, 8, 8.125f);
  TestFloat32UnopWithConvert(execution_tier, kExprF32Abs, 9, -9.125f);
  TestFloat32UnopWithConvert(execution_tier, kExprF32Neg, -213, 213.125f);
  TestFloat32UnopWithConvert(execution_tier, kExprF32Sqrt, 12, 144.4f);
542 543
}

544
WASM_EXEC_TEST(Float64Binops) {
545 546 547 548 549 550 551 552 553
  TestFloat64Binop(execution_tier, kExprF64Eq, 1, 16.25, 16.25);
  TestFloat64Binop(execution_tier, kExprF64Ne, 1, 16.25, 16.15);
  TestFloat64Binop(execution_tier, kExprF64Lt, 1, -32.4, 11.7);
  TestFloat64Binop(execution_tier, kExprF64Le, 1, -88.9, -88.9);
  TestFloat64Binop(execution_tier, kExprF64Gt, 1, 11.7, -32.4);
  TestFloat64Binop(execution_tier, kExprF64Ge, 1, -88.9, -88.9);

  TestFloat64BinopWithConvert(execution_tier, kExprF64Add, 100, 43.5, 56.5);
  TestFloat64BinopWithConvert(execution_tier, kExprF64Sub, 200, 12200.1,
554
                              12000.1);
555 556
  TestFloat64BinopWithConvert(execution_tier, kExprF64Mul, -33, 134, -0.25);
  TestFloat64BinopWithConvert(execution_tier, kExprF64Div, -1111, -2222.3, 2);
557 558
}

559
WASM_EXEC_TEST(Float64Unops) {
560 561 562 563
  TestFloat64UnopWithConvert(execution_tier, kExprF64Abs, 108, 108.125);
  TestFloat64UnopWithConvert(execution_tier, kExprF64Abs, 209, -209.125);
  TestFloat64UnopWithConvert(execution_tier, kExprF64Neg, -209, 209.125);
  TestFloat64UnopWithConvert(execution_tier, kExprF64Sqrt, 13, 169.4);
564 565
}

566
WASM_EXEC_TEST(Float32Neg) {
567
  WasmRunner<float, float> r(execution_tier);
568
  BUILD(r, WASM_F32_NEG(WASM_LOCAL_GET(0)));
569

570
  FOR_FLOAT32_INPUTS(i) {
571
    CHECK_EQ(0x80000000, bit_cast<uint32_t>(i) ^ bit_cast<uint32_t>(r.Call(i)));
572
  }
573 574
}

575
WASM_EXEC_TEST(Float64Neg) {
576
  WasmRunner<double, double> r(execution_tier);
577
  BUILD(r, WASM_F64_NEG(WASM_LOCAL_GET(0)));
578

579 580
  FOR_FLOAT64_INPUTS(i) {
    CHECK_EQ(0x8000000000000000,
581
             bit_cast<uint64_t>(i) ^ bit_cast<uint64_t>(r.Call(i)));
582
  }
583 584
}

585
WASM_EXEC_TEST(IfElse_P) {
586
  WasmRunner<int32_t, int32_t> r(execution_tier);
587
  // if (p0) return 11; else return 22;
588
  BUILD(r, WASM_IF_ELSE_I(WASM_LOCAL_GET(0),  // --
589 590
                          WASM_I32V_1(11),    // --
                          WASM_I32V_1(22)));  // --
591
  FOR_INT32_INPUTS(i) {
592 593
    int32_t expected = i ? 11 : 22;
    CHECK_EQ(expected, r.Call(i));
594 595 596
  }
}

597
WASM_EXEC_TEST(If_empty1) {
598
  WasmRunner<uint32_t, uint32_t, uint32_t> r(execution_tier);
599
  BUILD(r, WASM_LOCAL_GET(0), kExprIf, kVoidCode, kExprEnd, WASM_LOCAL_GET(1));
600
  FOR_UINT32_INPUTS(i) { CHECK_EQ(i, r.Call(i - 9, i)); }
601 602
}

603
WASM_EXEC_TEST(IfElse_empty1) {
604
  WasmRunner<uint32_t, uint32_t, uint32_t> r(execution_tier);
605 606
  BUILD(r, WASM_LOCAL_GET(0), kExprIf, kVoidCode, kExprElse, kExprEnd,
        WASM_LOCAL_GET(1));
607
  FOR_UINT32_INPUTS(i) { CHECK_EQ(i, r.Call(i - 8, i)); }
608 609
}

610
WASM_EXEC_TEST(IfElse_empty2) {
611
  WasmRunner<uint32_t, uint32_t, uint32_t> r(execution_tier);
612 613
  BUILD(r, WASM_LOCAL_GET(0), kExprIf, kVoidCode, WASM_NOP, kExprElse, kExprEnd,
        WASM_LOCAL_GET(1));
614
  FOR_UINT32_INPUTS(i) { CHECK_EQ(i, r.Call(i - 7, i)); }
615 616
}

617
WASM_EXEC_TEST(IfElse_empty3) {
618
  WasmRunner<uint32_t, uint32_t, uint32_t> r(execution_tier);
619 620
  BUILD(r, WASM_LOCAL_GET(0), kExprIf, kVoidCode, kExprElse, WASM_NOP, kExprEnd,
        WASM_LOCAL_GET(1));
621
  FOR_UINT32_INPUTS(i) { CHECK_EQ(i, r.Call(i - 6, i)); }
622 623
}

624
WASM_EXEC_TEST(If_chain1) {
625
  WasmRunner<int32_t, int32_t> r(execution_tier);
626
  // if (p0) 13; if (p0) 14; 15
627 628
  BUILD(r, WASM_IF(WASM_LOCAL_GET(0), WASM_NOP),
        WASM_IF(WASM_LOCAL_GET(0), WASM_NOP), WASM_I32V_1(15));
629
  FOR_INT32_INPUTS(i) { CHECK_EQ(15, r.Call(i)); }
630 631
}

632
WASM_EXEC_TEST(If_chain_set) {
633
  WasmRunner<int32_t, int32_t, int32_t> r(execution_tier);
634
  // if (p0) p1 = 73; if (p0) p1 = 74; p1
635 636 637
  BUILD(r, WASM_IF(WASM_LOCAL_GET(0), WASM_LOCAL_SET(1, WASM_I32V_2(73))),
        WASM_IF(WASM_LOCAL_GET(0), WASM_LOCAL_SET(1, WASM_I32V_2(74))),
        WASM_LOCAL_GET(1));
638
  FOR_INT32_INPUTS(i) {
639 640
    int32_t expected = i ? 74 : i;
    CHECK_EQ(expected, r.Call(i, i));
641 642
  }
}
643

644
WASM_EXEC_TEST(IfElse_Unreachable1) {
645
  WasmRunner<int32_t> r(execution_tier);
646
  // 0 ? unreachable : 27
647 648 649
  BUILD(r, WASM_IF_ELSE_I(WASM_ZERO,          // --
                          WASM_UNREACHABLE,   // --
                          WASM_I32V_1(27)));  // --
650 651 652
  CHECK_EQ(27, r.Call());
}

653
WASM_EXEC_TEST(IfElse_Unreachable2) {
654
  WasmRunner<int32_t> r(execution_tier);
655
  // 1 ? 28 : unreachable
656 657
  BUILD(r, WASM_IF_ELSE_I(WASM_I32V_1(1),      // --
                          WASM_I32V_1(28),     // --
658 659 660 661
                          WASM_UNREACHABLE));  // --
  CHECK_EQ(28, r.Call());
}

662
WASM_EXEC_TEST(Return12) {
663
  WasmRunner<int32_t> r(execution_tier);
664

665
  BUILD(r, RET_I8(12));
666 667 668
  CHECK_EQ(12, r.Call());
}

669
WASM_EXEC_TEST(Return17) {
670
  WasmRunner<int32_t> r(execution_tier);
671

672
  BUILD(r, WASM_BLOCK(RET_I8(17)), WASM_ZERO);
673 674 675
  CHECK_EQ(17, r.Call());
}

676
WASM_EXEC_TEST(Return_I32) {
677
  WasmRunner<int32_t, int32_t> r(execution_tier);
678

679
  BUILD(r, RET(WASM_LOCAL_GET(0)));
680

681
  FOR_INT32_INPUTS(i) { CHECK_EQ(i, r.Call(i)); }
682 683
}

684
WASM_EXEC_TEST(Return_F32) {
685
  WasmRunner<float, float> r(execution_tier);
686

687
  BUILD(r, RET(WASM_LOCAL_GET(0)));
688 689

  FOR_FLOAT32_INPUTS(i) {
690
    float expect = i;
691 692 693 694 695 696 697 698 699
    float result = r.Call(expect);
    if (std::isnan(expect)) {
      CHECK(std::isnan(result));
    } else {
      CHECK_EQ(expect, result);
    }
  }
}

700
WASM_EXEC_TEST(Return_F64) {
701
  WasmRunner<double, double> r(execution_tier);
702

703
  BUILD(r, RET(WASM_LOCAL_GET(0)));
704 705

  FOR_FLOAT64_INPUTS(i) {
706
    double expect = i;
707 708 709 710 711 712 713 714 715
    double result = r.Call(expect);
    if (std::isnan(expect)) {
      CHECK(std::isnan(result));
    } else {
      CHECK_EQ(expect, result);
    }
  }
}

716
WASM_EXEC_TEST(Select_float_parameters) {
717
  WasmRunner<float, float, float, int32_t> r(execution_tier);
718
  BUILD(r,
719
        WASM_SELECT(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1), WASM_LOCAL_GET(2)));
720 721 722
  CHECK_FLOAT_EQ(2.0f, r.Call(2.0f, 1.0f, 1));
}

723 724 725 726 727 728 729
WASM_EXEC_TEST(Select_s128_parameters) {
  WasmRunner<int32_t, int32_t> r(execution_tier);
  int32_t* g0 = r.builder().AddGlobal<int32_t>(kWasmS128);
  int32_t* g1 = r.builder().AddGlobal<int32_t>(kWasmS128);
  int32_t* output = r.builder().AddGlobal<int32_t>(kWasmS128);
  // select(v128(0, 1, 2, 3), v128(4, 5, 6, 7), 1) == v128(0, 1, 2, 3)
  for (int i = 0; i < 4; i++) {
730 731
    LANE(g0, i) = i;
    LANE(g1, i) = i + 4;
732 733
  }
  BUILD(r,
734
        WASM_GLOBAL_SET(2, WASM_SELECT(WASM_GLOBAL_GET(0), WASM_GLOBAL_GET(1),
735
                                       WASM_LOCAL_GET(0))),
736 737 738
        WASM_ONE);
  r.Call(1);
  for (int i = 0; i < 4; i++) {
739
    CHECK_EQ(i, LANE(output, i));
740 741 742
  }
}

743
WASM_EXEC_TEST(SelectWithType_float_parameters) {
744
  EXPERIMENTAL_FLAG_SCOPE(reftypes);
745 746
  WasmRunner<float, float, float, int32_t> r(execution_tier);
  BUILD(r,
747
        WASM_SELECT_F(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1), WASM_LOCAL_GET(2)));
748 749 750
  CHECK_FLOAT_EQ(2.0f, r.Call(2.0f, 1.0f, 1));
}

751
WASM_EXEC_TEST(Select) {
752
  WasmRunner<int32_t, int32_t> r(execution_tier);
753
  // return select(11, 22, a);
754
  BUILD(r, WASM_SELECT(WASM_I32V_1(11), WASM_I32V_1(22), WASM_LOCAL_GET(0)));
755
  FOR_INT32_INPUTS(i) {
756 757
    int32_t expected = i ? 11 : 22;
    CHECK_EQ(expected, r.Call(i));
758 759 760
  }
}

761
WASM_EXEC_TEST(SelectWithType) {
762
  EXPERIMENTAL_FLAG_SCOPE(reftypes);
763 764
  WasmRunner<int32_t, int32_t> r(execution_tier);
  // return select(11, 22, a);
765
  BUILD(r, WASM_SELECT_I(WASM_I32V_1(11), WASM_I32V_1(22), WASM_LOCAL_GET(0)));
766 767 768 769 770 771
  FOR_INT32_INPUTS(i) {
    int32_t expected = i ? 11 : 22;
    CHECK_EQ(expected, r.Call(i));
  }
}

772
WASM_EXEC_TEST(Select_strict1) {
773
  WasmRunner<int32_t, int32_t> r(execution_tier);
774
  // select(a=0, a=1, a=2); return a
775 776 777 778 779
  BUILD(r,
        WASM_SELECT(WASM_LOCAL_TEE(0, WASM_ZERO),
                    WASM_LOCAL_TEE(0, WASM_I32V_1(1)),
                    WASM_LOCAL_TEE(0, WASM_I32V_1(2))),
        WASM_DROP, WASM_LOCAL_GET(0));
780
  FOR_INT32_INPUTS(i) { CHECK_EQ(2, r.Call(i)); }
781 782
}

783
WASM_EXEC_TEST(SelectWithType_strict1) {
784
  EXPERIMENTAL_FLAG_SCOPE(reftypes);
785 786 787
  WasmRunner<int32_t, int32_t> r(execution_tier);
  // select(a=0, a=1, a=2); return a
  BUILD(r,
788 789 790 791
        WASM_SELECT_I(WASM_LOCAL_TEE(0, WASM_ZERO),
                      WASM_LOCAL_TEE(0, WASM_I32V_1(1)),
                      WASM_LOCAL_TEE(0, WASM_I32V_1(2))),
        WASM_DROP, WASM_LOCAL_GET(0));
792 793 794
  FOR_INT32_INPUTS(i) { CHECK_EQ(2, r.Call(i)); }
}

795
WASM_EXEC_TEST(Select_strict2) {
796
  WasmRunner<int32_t, int32_t> r(execution_tier);
797 798
  r.AllocateLocal(kWasmI32);
  r.AllocateLocal(kWasmI32);
799
  // select(b=5, c=6, a)
800 801
  BUILD(r, WASM_SELECT(WASM_LOCAL_TEE(1, WASM_I32V_1(5)),
                       WASM_LOCAL_TEE(2, WASM_I32V_1(6)), WASM_LOCAL_GET(0)));
802
  FOR_INT32_INPUTS(i) {
803 804
    int32_t expected = i ? 5 : 6;
    CHECK_EQ(expected, r.Call(i));
805 806 807
  }
}

808
WASM_EXEC_TEST(SelectWithType_strict2) {
809
  EXPERIMENTAL_FLAG_SCOPE(reftypes);
810 811 812 813
  WasmRunner<int32_t, int32_t> r(execution_tier);
  r.AllocateLocal(kWasmI32);
  r.AllocateLocal(kWasmI32);
  // select(b=5, c=6, a)
814 815
  BUILD(r, WASM_SELECT_I(WASM_LOCAL_TEE(1, WASM_I32V_1(5)),
                         WASM_LOCAL_TEE(2, WASM_I32V_1(6)), WASM_LOCAL_GET(0)));
816 817 818 819 820 821
  FOR_INT32_INPUTS(i) {
    int32_t expected = i ? 5 : 6;
    CHECK_EQ(expected, r.Call(i));
  }
}

822
WASM_EXEC_TEST(Select_strict3) {
823
  WasmRunner<int32_t, int32_t> r(execution_tier);
824 825
  r.AllocateLocal(kWasmI32);
  r.AllocateLocal(kWasmI32);
826
  // select(b=5, c=6, a=b)
827 828 829
  BUILD(r, WASM_SELECT(WASM_LOCAL_TEE(1, WASM_I32V_1(5)),
                       WASM_LOCAL_TEE(2, WASM_I32V_1(6)),
                       WASM_LOCAL_TEE(0, WASM_LOCAL_GET(1))));
830 831
  FOR_INT32_INPUTS(i) {
    int32_t expected = 5;
832
    CHECK_EQ(expected, r.Call(i));
833
  }
834 835
}

836
WASM_EXEC_TEST(SelectWithType_strict3) {
837
  EXPERIMENTAL_FLAG_SCOPE(reftypes);
838 839 840 841
  WasmRunner<int32_t, int32_t> r(execution_tier);
  r.AllocateLocal(kWasmI32);
  r.AllocateLocal(kWasmI32);
  // select(b=5, c=6, a=b)
842 843 844
  BUILD(r, WASM_SELECT_I(WASM_LOCAL_TEE(1, WASM_I32V_1(5)),
                         WASM_LOCAL_TEE(2, WASM_I32V_1(6)),
                         WASM_LOCAL_TEE(0, WASM_LOCAL_GET(1))));
845 846 847 848 849 850
  FOR_INT32_INPUTS(i) {
    int32_t expected = 5;
    CHECK_EQ(expected, r.Call(i));
  }
}

851
WASM_EXEC_TEST(BrIf_strict) {
852
  WasmRunner<int32_t, int32_t> r(execution_tier);
853 854
  BUILD(r, WASM_BLOCK_I(WASM_BRV_IF(0, WASM_LOCAL_GET(0),
                                    WASM_LOCAL_TEE(0, WASM_I32V_2(99)))));
855

856
  FOR_INT32_INPUTS(i) { CHECK_EQ(i, r.Call(i)); }
857 858
}

859
WASM_EXEC_TEST(Br_height) {
860
  WasmRunner<int32_t, int32_t> r(execution_tier);
861
  BUILD(r, WASM_BLOCK_I(
862
               WASM_BLOCK(WASM_BRV_IFD(0, WASM_LOCAL_GET(0), WASM_LOCAL_GET(0)),
863 864
                          WASM_RETURN1(WASM_I32V_1(9))),
               WASM_BRV(0, WASM_I32V_1(8))));
865 866 867 868 869 870 871

  for (int32_t i = 0; i < 5; i++) {
    int32_t expected = i != 0 ? 8 : 9;
    CHECK_EQ(expected, r.Call(i));
  }
}

872
WASM_EXEC_TEST(Regression_660262) {
873
  WasmRunner<int32_t> r(execution_tier);
874
  r.builder().AddMemory(kWasmPageSize);
875
  BUILD(r, kExprI32Const, 0x00, kExprI32Const, 0x00, kExprI32LoadMem, 0x00,
876
        0x0F, kExprBrTable, 0x00, 0x80, 0x00);  // entries=0
877 878 879
  r.Call();
}

880
WASM_EXEC_TEST(BrTable0a) {
881
  WasmRunner<int32_t, int32_t> r(execution_tier);
882
  BUILD(r, B1(B1(WASM_BR_TABLE(WASM_LOCAL_GET(0), 0, BR_TARGET(0)))),
883
        WASM_I32V_2(91));
884
  FOR_INT32_INPUTS(i) { CHECK_EQ(91, r.Call(i)); }
885 886
}

887
WASM_EXEC_TEST(BrTable0b) {
888
  WasmRunner<int32_t, int32_t> r(execution_tier);
889
  BUILD(r,
890
        B1(B1(WASM_BR_TABLE(WASM_LOCAL_GET(0), 1, BR_TARGET(0), BR_TARGET(0)))),
891
        WASM_I32V_2(92));
892
  FOR_INT32_INPUTS(i) { CHECK_EQ(92, r.Call(i)); }
893 894
}

895
WASM_EXEC_TEST(BrTable0c) {
896
  WasmRunner<int32_t, int32_t> r(execution_tier);
897 898
  BUILD(
      r,
899
      B1(B2(B1(WASM_BR_TABLE(WASM_LOCAL_GET(0), 1, BR_TARGET(0), BR_TARGET(1))),
900
            RET_I8(76))),
901
      WASM_I32V_2(77));
902
  FOR_INT32_INPUTS(i) {
903 904
    int32_t expected = i == 0 ? 76 : 77;
    CHECK_EQ(expected, r.Call(i));
905 906
  }
}
907

908
WASM_EXEC_TEST(BrTable1) {
909
  WasmRunner<int32_t, int32_t> r(execution_tier);
910
  BUILD(r, B1(WASM_BR_TABLE(WASM_LOCAL_GET(0), 0, BR_TARGET(0))), RET_I8(93));
911
  FOR_INT32_INPUTS(i) { CHECK_EQ(93, r.Call(i)); }
912 913
}

914
WASM_EXEC_TEST(BrTable_loop) {
915
  WasmRunner<int32_t, int32_t> r(execution_tier);
916 917 918 919
  BUILD(r,
        B2(B1(WASM_LOOP(WASM_BR_TABLE(WASM_INC_LOCAL_BYV(0, 1), 2, BR_TARGET(2),
                                      BR_TARGET(1), BR_TARGET(0)))),
           RET_I8(99)),
920
        WASM_I32V_2(98));
921 922 923 924 925 926
  CHECK_EQ(99, r.Call(0));
  CHECK_EQ(98, r.Call(-1));
  CHECK_EQ(98, r.Call(-2));
  CHECK_EQ(98, r.Call(-3));
  CHECK_EQ(98, r.Call(-100));
}
927

928
WASM_EXEC_TEST(BrTable_br) {
929
  WasmRunner<int32_t, int32_t> r(execution_tier);
930
  BUILD(r,
931
        B2(B1(WASM_BR_TABLE(WASM_LOCAL_GET(0), 1, BR_TARGET(1), BR_TARGET(0))),
932
           RET_I8(91)),
933
        WASM_I32V_2(99));
934 935 936 937 938 939
  CHECK_EQ(99, r.Call(0));
  CHECK_EQ(91, r.Call(1));
  CHECK_EQ(91, r.Call(2));
  CHECK_EQ(91, r.Call(3));
}

940
WASM_EXEC_TEST(BrTable_br2) {
941
  WasmRunner<int32_t, int32_t> r(execution_tier);
942

943 944 945 946 947 948
  BUILD(r,
        B2(B2(B2(B1(WASM_BR_TABLE(WASM_LOCAL_GET(0), 3, BR_TARGET(1),
                                  BR_TARGET(2), BR_TARGET(3), BR_TARGET(0))),
                 RET_I8(85)),
              RET_I8(86)),
           RET_I8(87)),
949
        WASM_I32V_2(88));
950 951 952 953 954 955 956 957
  CHECK_EQ(86, r.Call(0));
  CHECK_EQ(87, r.Call(1));
  CHECK_EQ(88, r.Call(2));
  CHECK_EQ(85, r.Call(3));
  CHECK_EQ(85, r.Call(4));
  CHECK_EQ(85, r.Call(5));
}

958
WASM_EXEC_TEST(BrTable4) {
959 960
  for (int i = 0; i < 4; ++i) {
    for (int t = 0; t < 4; ++t) {
961
      uint32_t cases[] = {0, 1, 2, 3};
962 963
      cases[i] = t;
      byte code[] = {B2(B2(B2(B2(B1(WASM_BR_TABLE(
964
                                     WASM_LOCAL_GET(0), 3, BR_TARGET(cases[0]),
965 966 967 968 969 970
                                     BR_TARGET(cases[1]), BR_TARGET(cases[2]),
                                     BR_TARGET(cases[3]))),
                                 RET_I8(70)),
                              RET_I8(71)),
                           RET_I8(72)),
                        RET_I8(73)),
971
                     WASM_I32V_2(75)};
972

973
      WasmRunner<int32_t, int32_t> r(execution_tier);
974 975
      r.Build(code, code + arraysize(code));

976
      for (int x = -3; x < 50; ++x) {
977 978 979 980
        int index = (x > 3 || x < 0) ? 3 : x;
        int32_t expected = 70 + cases[index];
        CHECK_EQ(expected, r.Call(x));
      }
981 982 983 984
    }
  }
}

985
WASM_EXEC_TEST(BrTable4x4) {
986 987 988 989 990
  for (byte a = 0; a < 4; ++a) {
    for (byte b = 0; b < 4; ++b) {
      for (byte c = 0; c < 4; ++c) {
        for (byte d = 0; d < 4; ++d) {
          for (int i = 0; i < 4; ++i) {
991
            uint32_t cases[] = {a, b, c, d};
992 993
            byte code[] = {
                B2(B2(B2(B2(B1(WASM_BR_TABLE(
994
                                WASM_LOCAL_GET(0), 3, BR_TARGET(cases[0]),
995 996 997 998 999 1000
                                BR_TARGET(cases[1]), BR_TARGET(cases[2]),
                                BR_TARGET(cases[3]))),
                            RET_I8(50)),
                         RET_I8(51)),
                      RET_I8(52)),
                   RET_I8(53)),
1001
                WASM_I32V_2(55)};
1002

1003
            WasmRunner<int32_t, int32_t> r(execution_tier);
1004 1005
            r.Build(code, code + arraysize(code));

1006
            for (int x = -6; x < 47; ++x) {
1007 1008 1009 1010 1011
              int index = (x > 3 || x < 0) ? 3 : x;
              int32_t expected = 50 + cases[index];
              CHECK_EQ(expected, r.Call(x));
            }
          }
1012 1013 1014 1015 1016 1017
        }
      }
    }
  }
}

1018
WASM_EXEC_TEST(BrTable4_fallthru) {
1019
  byte code[] = {
1020
      B2(B2(B2(B2(B1(WASM_BR_TABLE(WASM_LOCAL_GET(0), 3, BR_TARGET(0),
1021 1022 1023 1024 1025
                                   BR_TARGET(1), BR_TARGET(2), BR_TARGET(3))),
                  WASM_INC_LOCAL_BY(1, 1)),
               WASM_INC_LOCAL_BY(1, 2)),
            WASM_INC_LOCAL_BY(1, 4)),
         WASM_INC_LOCAL_BY(1, 8)),
1026
      WASM_LOCAL_GET(1)};
1027

1028
  WasmRunner<int32_t, int32_t, int32_t> r(execution_tier);
1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043
  r.Build(code, code + arraysize(code));

  CHECK_EQ(15, r.Call(0, 0));
  CHECK_EQ(14, r.Call(1, 0));
  CHECK_EQ(12, r.Call(2, 0));
  CHECK_EQ(8, r.Call(3, 0));
  CHECK_EQ(8, r.Call(4, 0));

  CHECK_EQ(115, r.Call(0, 100));
  CHECK_EQ(114, r.Call(1, 100));
  CHECK_EQ(112, r.Call(2, 100));
  CHECK_EQ(108, r.Call(3, 100));
  CHECK_EQ(108, r.Call(4, 100));
}

1044 1045
WASM_EXEC_TEST(BrTable_loop_target) {
  byte code[] = {
1046 1047 1048
      WASM_LOOP_I(WASM_BLOCK(WASM_BR_TABLE(WASM_LOCAL_GET(0), 2, BR_TARGET(0),
                                           BR_TARGET(1), BR_TARGET(1))),
                  WASM_ONE)};
1049

1050
  WasmRunner<int32_t, int32_t> r(execution_tier);
1051 1052 1053 1054 1055
  r.Build(code, code + arraysize(code));

  CHECK_EQ(1, r.Call(0));
}

1056
WASM_EXEC_TEST(F32ReinterpretI32) {
1057
  WasmRunner<int32_t> r(execution_tier);
1058 1059
  int32_t* memory =
      r.builder().AddMemoryElems<int32_t>(kWasmPageSize / sizeof(int32_t));
1060 1061 1062 1063 1064

  BUILD(r, WASM_I32_REINTERPRET_F32(
               WASM_LOAD_MEM(MachineType::Float32(), WASM_ZERO)));

  FOR_INT32_INPUTS(i) {
1065
    int32_t expected = i;
1066
    r.builder().WriteMemory(&memory[0], expected);
1067 1068 1069 1070
    CHECK_EQ(expected, r.Call());
  }
}

1071
WASM_EXEC_TEST(I32ReinterpretF32) {
1072
  WasmRunner<int32_t, int32_t> r(execution_tier);
1073 1074
  int32_t* memory =
      r.builder().AddMemoryElems<int32_t>(kWasmPageSize / sizeof(int32_t));
1075

1076 1077 1078
  BUILD(r,
        WASM_STORE_MEM(MachineType::Float32(), WASM_ZERO,
                       WASM_F32_REINTERPRET_I32(WASM_LOCAL_GET(0))),
1079
        WASM_I32V_2(107));
1080 1081

  FOR_INT32_INPUTS(i) {
1082
    int32_t expected = i;
1083
    CHECK_EQ(107, r.Call(expected));
1084
    CHECK_EQ(expected, r.builder().ReadMemory(&memory[0]));
1085 1086 1087
  }
}

1088 1089 1090
// Do not run this test in a simulator because of signalling NaN issues on ia32.
#ifndef USE_SIMULATOR

1091
WASM_EXEC_TEST(SignallingNanSurvivesI32ReinterpretF32) {
1092
  WasmRunner<int32_t> r(execution_tier);
1093 1094

  BUILD(r, WASM_I32_REINTERPRET_F32(
1095
               WASM_SEQ(kExprF32Const, 0x00, 0x00, 0xA0, 0x7F)));
1096 1097

  // This is a signalling nan.
1098
  CHECK_EQ(0x7FA00000, r.Call());
1099 1100
}

1101 1102
#endif

1103
WASM_EXEC_TEST(LoadMaxUint32Offset) {
1104
  WasmRunner<int32_t> r(execution_tier);
1105
  r.builder().AddMemory(kWasmPageSize);
1106

1107
  BUILD(r, WASM_LOAD_MEM_OFFSET(MachineType::Int32(),  // type
1108
                                U32V_5(0xFFFFFFFF),    // offset
1109
                                WASM_ZERO));           // index
1110 1111 1112 1113

  CHECK_TRAP32(r.Call());
}

1114
WASM_EXEC_TEST(LoadStoreLoad) {
1115
  WasmRunner<int32_t> r(execution_tier);
1116 1117
  int32_t* memory =
      r.builder().AddMemoryElems<int32_t>(kWasmPageSize / sizeof(int32_t));
1118 1119

  BUILD(r, WASM_STORE_MEM(MachineType::Int32(), WASM_ZERO,
1120 1121
                          WASM_LOAD_MEM(MachineType::Int32(), WASM_ZERO)),
        WASM_LOAD_MEM(MachineType::Int32(), WASM_ZERO));
1122 1123

  FOR_INT32_INPUTS(i) {
1124
    int32_t expected = i;
1125
    r.builder().WriteMemory(&memory[0], expected);
1126 1127 1128 1129
    CHECK_EQ(expected, r.Call());
  }
}

1130
WASM_EXEC_TEST(UnalignedFloat32Load) {
1131
  WasmRunner<float> r(execution_tier);
1132
  r.builder().AddMemory(kWasmPageSize);
1133 1134 1135 1136 1137
  BUILD(r, WASM_LOAD_MEM_ALIGNMENT(MachineType::Float32(), WASM_ONE, 2));
  r.Call();
}

WASM_EXEC_TEST(UnalignedFloat64Load) {
1138
  WasmRunner<double> r(execution_tier);
1139
  r.builder().AddMemory(kWasmPageSize);
1140 1141 1142 1143 1144
  BUILD(r, WASM_LOAD_MEM_ALIGNMENT(MachineType::Float64(), WASM_ONE, 3));
  r.Call();
}

WASM_EXEC_TEST(UnalignedInt32Load) {
1145
  WasmRunner<uint32_t> r(execution_tier);
1146
  r.builder().AddMemory(kWasmPageSize);
1147 1148 1149 1150 1151
  BUILD(r, WASM_LOAD_MEM_ALIGNMENT(MachineType::Int32(), WASM_ONE, 2));
  r.Call();
}

WASM_EXEC_TEST(UnalignedInt32Store) {
1152
  WasmRunner<int32_t> r(execution_tier);
1153
  r.builder().AddMemory(kWasmPageSize);
1154 1155 1156 1157 1158 1159 1160
  BUILD(r, WASM_SEQ(WASM_STORE_MEM_ALIGNMENT(MachineType::Int32(), WASM_ONE, 2,
                                             WASM_I32V_1(1)),
                    WASM_I32V_1(12)));
  r.Call();
}

WASM_EXEC_TEST(UnalignedFloat32Store) {
1161
  WasmRunner<int32_t> r(execution_tier);
1162
  r.builder().AddMemory(kWasmPageSize);
1163 1164 1165 1166 1167 1168 1169
  BUILD(r, WASM_SEQ(WASM_STORE_MEM_ALIGNMENT(MachineType::Float32(), WASM_ONE,
                                             2, WASM_F32(1.0)),
                    WASM_I32V_1(12)));
  r.Call();
}

WASM_EXEC_TEST(UnalignedFloat64Store) {
1170
  WasmRunner<int32_t> r(execution_tier);
1171
  r.builder().AddMemory(kWasmPageSize);
1172 1173 1174 1175 1176 1177
  BUILD(r, WASM_SEQ(WASM_STORE_MEM_ALIGNMENT(MachineType::Float64(), WASM_ONE,
                                             3, WASM_F64(1.0)),
                    WASM_I32V_1(12)));
  r.Call();
}

1178
WASM_EXEC_TEST(VoidReturn1) {
1179
  const int32_t kExpected = -414444;
1180
  WasmRunner<int32_t> r(execution_tier);
1181 1182

  // Build the test function.
1183 1184
  WasmFunctionCompiler& test_func = r.NewFunction<void>();
  BUILD(test_func, kExprNop);
1185 1186

  // Build the calling function.
1187 1188
  BUILD(r, WASM_CALL_FUNCTION0(test_func.function_index()),
        WASM_I32V_3(kExpected));
1189

1190
  // Call and check.
1191 1192
  int32_t result = r.Call();
  CHECK_EQ(kExpected, result);
1193 1194
}

1195
WASM_EXEC_TEST(VoidReturn2) {
1196
  const int32_t kExpected = -414444;
1197
  WasmRunner<int32_t> r(execution_tier);
1198

1199
  // Build the test function.
1200 1201
  WasmFunctionCompiler& test_func = r.NewFunction<void>();
  BUILD(test_func, WASM_RETURN0);
1202 1203

  // Build the calling function.
1204 1205
  BUILD(r, WASM_CALL_FUNCTION0(test_func.function_index()),
        WASM_I32V_3(kExpected));
1206

1207
  // Call and check.
1208 1209
  int32_t result = r.Call();
  CHECK_EQ(kExpected, result);
1210 1211
}

1212
WASM_EXEC_TEST(BrEmpty) {
1213
  WasmRunner<int32_t, int32_t> r(execution_tier);
1214
  BUILD(r, WASM_BRV(0, WASM_LOCAL_GET(0)));
1215
  FOR_INT32_INPUTS(i) { CHECK_EQ(i, r.Call(i)); }
1216 1217 1218
}

WASM_EXEC_TEST(BrIfEmpty) {
1219
  WasmRunner<int32_t, int32_t> r(execution_tier);
1220
  BUILD(r, WASM_BRV_IF(0, WASM_LOCAL_GET(0), WASM_LOCAL_GET(0)));
1221
  FOR_INT32_INPUTS(i) { CHECK_EQ(i, r.Call(i)); }
1222 1223
}

1224
WASM_EXEC_TEST(Block_empty) {
1225
  WasmRunner<int32_t, int32_t> r(execution_tier);
1226
  BUILD(r, kExprBlock, kVoidCode, kExprEnd, WASM_LOCAL_GET(0));
1227
  FOR_INT32_INPUTS(i) { CHECK_EQ(i, r.Call(i)); }
1228 1229
}

1230
WASM_EXEC_TEST(Block_empty_br1) {
1231
  WasmRunner<int32_t, int32_t> r(execution_tier);
1232
  BUILD(r, B1(WASM_BR(0)), WASM_LOCAL_GET(0));
1233
  FOR_INT32_INPUTS(i) { CHECK_EQ(i, r.Call(i)); }
1234 1235
}

1236
WASM_EXEC_TEST(Block_empty_brif1) {
1237
  WasmRunner<int32_t, int32_t> r(execution_tier);
1238
  BUILD(r, WASM_BLOCK(WASM_BR_IF(0, WASM_ZERO)), WASM_LOCAL_GET(0));
1239
  FOR_INT32_INPUTS(i) { CHECK_EQ(i, r.Call(i)); }
1240 1241
}

1242
WASM_EXEC_TEST(Block_empty_brif2) {
1243
  WasmRunner<uint32_t, uint32_t, uint32_t> r(execution_tier);
1244
  BUILD(r, WASM_BLOCK(WASM_BR_IF(0, WASM_LOCAL_GET(1))), WASM_LOCAL_GET(0));
1245
  FOR_UINT32_INPUTS(i) { CHECK_EQ(i, r.Call(i, i + 1)); }
1246 1247
}

1248
WASM_EXEC_TEST(Block_i) {
1249
  WasmRunner<int32_t, int32_t> r(execution_tier);
1250
  BUILD(r, WASM_BLOCK_I(WASM_LOCAL_GET(0)));
1251
  FOR_INT32_INPUTS(i) { CHECK_EQ(i, r.Call(i)); }
1252 1253 1254
}

WASM_EXEC_TEST(Block_f) {
1255
  WasmRunner<float, float> r(execution_tier);
1256
  BUILD(r, WASM_BLOCK_F(WASM_LOCAL_GET(0)));
1257
  FOR_FLOAT32_INPUTS(i) { CHECK_FLOAT_EQ(i, r.Call(i)); }
1258 1259 1260
}

WASM_EXEC_TEST(Block_d) {
1261
  WasmRunner<double, double> r(execution_tier);
1262
  BUILD(r, WASM_BLOCK_D(WASM_LOCAL_GET(0)));
1263
  FOR_FLOAT64_INPUTS(i) { CHECK_DOUBLE_EQ(i, r.Call(i)); }
1264 1265
}

1266
WASM_EXEC_TEST(Block_br2) {
1267
  WasmRunner<int32_t, int32_t> r(execution_tier);
1268
  BUILD(r, WASM_BLOCK_I(WASM_BRV(0, WASM_LOCAL_GET(0))));
1269
  FOR_UINT32_INPUTS(i) { CHECK_EQ(i, static_cast<uint32_t>(r.Call(i))); }
1270
}
1271

1272
WASM_EXEC_TEST(Block_If_P) {
1273
  WasmRunner<int32_t, int32_t> r(execution_tier);
1274
  // block { if (p0) break 51; 52; }
1275
  BUILD(r, WASM_BLOCK_I(                               // --
1276
               WASM_IF(WASM_LOCAL_GET(0),              // --
1277 1278
                       WASM_BRV(1, WASM_I32V_1(51))),  // --
               WASM_I32V_1(52)));                      // --
1279
  FOR_INT32_INPUTS(i) {
1280 1281
    int32_t expected = i ? 51 : 52;
    CHECK_EQ(expected, r.Call(i));
1282 1283 1284
  }
}

1285
WASM_EXEC_TEST(Loop_empty) {
1286
  WasmRunner<int32_t, int32_t> r(execution_tier);
1287
  BUILD(r, kExprLoop, kVoidCode, kExprEnd, WASM_LOCAL_GET(0));
1288
  FOR_INT32_INPUTS(i) { CHECK_EQ(i, r.Call(i)); }
1289 1290 1291
}

WASM_EXEC_TEST(Loop_i) {
1292
  WasmRunner<int32_t, int32_t> r(execution_tier);
1293
  BUILD(r, WASM_LOOP_I(WASM_LOCAL_GET(0)));
1294
  FOR_INT32_INPUTS(i) { CHECK_EQ(i, r.Call(i)); }
1295 1296
}

1297
WASM_EXEC_TEST(Loop_f) {
1298
  WasmRunner<float, float> r(execution_tier);
1299
  BUILD(r, WASM_LOOP_F(WASM_LOCAL_GET(0)));
1300
  FOR_FLOAT32_INPUTS(i) { CHECK_FLOAT_EQ(i, r.Call(i)); }
1301 1302 1303
}

WASM_EXEC_TEST(Loop_d) {
1304
  WasmRunner<double, double> r(execution_tier);
1305
  BUILD(r, WASM_LOOP_D(WASM_LOCAL_GET(0)));
1306
  FOR_FLOAT64_INPUTS(i) { CHECK_DOUBLE_EQ(i, r.Call(i)); }
1307 1308
}

1309
WASM_EXEC_TEST(Loop_empty_br1) {
1310
  WasmRunner<int32_t, int32_t> r(execution_tier);
1311
  BUILD(r, B1(WASM_LOOP(WASM_BR(1))), WASM_LOCAL_GET(0));
1312
  FOR_INT32_INPUTS(i) { CHECK_EQ(i, r.Call(i)); }
1313 1314
}

1315
WASM_EXEC_TEST(Loop_empty_brif1) {
1316
  WasmRunner<int32_t, int32_t> r(execution_tier);
1317
  BUILD(r, B1(WASM_LOOP(WASM_BR_IF(1, WASM_ZERO))), WASM_LOCAL_GET(0));
1318
  FOR_INT32_INPUTS(i) { CHECK_EQ(i, r.Call(i)); }
1319 1320
}

1321
WASM_EXEC_TEST(Loop_empty_brif2) {
1322
  WasmRunner<uint32_t, uint32_t, uint32_t> r(execution_tier);
1323
  BUILD(r, WASM_LOOP_I(WASM_BRV_IF(1, WASM_LOCAL_GET(0), WASM_LOCAL_GET(1))));
1324
  FOR_UINT32_INPUTS(i) { CHECK_EQ(i, r.Call(i, i + 1)); }
1325
}
1326

1327
WASM_EXEC_TEST(Loop_empty_brif3) {
1328
  WasmRunner<uint32_t, uint32_t, uint32_t, uint32_t> r(execution_tier);
1329 1330
  BUILD(r, WASM_LOOP(WASM_BRV_IFD(1, WASM_LOCAL_GET(2), WASM_LOCAL_GET(0))),
        WASM_LOCAL_GET(1));
1331 1332
  FOR_UINT32_INPUTS(i) {
    FOR_UINT32_INPUTS(j) {
1333 1334
      CHECK_EQ(i, r.Call(0, i, j));
      CHECK_EQ(j, r.Call(1, i, j));
1335 1336 1337 1338
    }
  }
}

1339
WASM_EXEC_TEST(Block_BrIf_P) {
1340
  WasmRunner<int32_t, int32_t> r(execution_tier);
1341
  BUILD(r, WASM_BLOCK_I(WASM_BRV_IFD(0, WASM_I32V_1(51), WASM_LOCAL_GET(0)),
1342
                        WASM_I32V_1(52)));
1343
  FOR_INT32_INPUTS(i) {
1344 1345
    int32_t expected = i ? 51 : 52;
    CHECK_EQ(expected, r.Call(i));
1346 1347 1348
  }
}

1349
WASM_EXEC_TEST(Block_IfElse_P_assign) {
1350
  WasmRunner<int32_t, int32_t> r(execution_tier);
1351
  // { if (p0) p0 = 71; else p0 = 72; return p0; }
1352
  BUILD(r,                                                 // --
1353 1354 1355 1356
        WASM_IF_ELSE(WASM_LOCAL_GET(0),                    // --
                     WASM_LOCAL_SET(0, WASM_I32V_2(71)),   // --
                     WASM_LOCAL_SET(0, WASM_I32V_2(72))),  // --
        WASM_LOCAL_GET(0));
1357
  FOR_INT32_INPUTS(i) {
1358 1359
    int32_t expected = i ? 71 : 72;
    CHECK_EQ(expected, r.Call(i));
1360 1361 1362
  }
}

1363
WASM_EXEC_TEST(Block_IfElse_P_return) {
1364
  WasmRunner<int32_t, int32_t> r(execution_tier);
1365
  // if (p0) return 81; else return 82;
1366
  BUILD(r,                               // --
1367
        WASM_IF_ELSE(WASM_LOCAL_GET(0),  // --
1368
                     RET_I8(81),         // --
1369 1370
                     RET_I8(82)),        // --
        WASM_ZERO);                      // --
1371
  FOR_INT32_INPUTS(i) {
1372 1373
    int32_t expected = i ? 81 : 82;
    CHECK_EQ(expected, r.Call(i));
1374 1375 1376
  }
}

1377
WASM_EXEC_TEST(Block_If_P_assign) {
1378
  WasmRunner<int32_t, int32_t> r(execution_tier);
1379
  // { if (p0) p0 = 61; p0; }
1380 1381
  BUILD(r, WASM_IF(WASM_LOCAL_GET(0), WASM_LOCAL_SET(0, WASM_I32V_1(61))),
        WASM_LOCAL_GET(0));
1382
  FOR_INT32_INPUTS(i) {
1383 1384
    int32_t expected = i ? 61 : i;
    CHECK_EQ(expected, r.Call(i));
1385 1386 1387
  }
}

1388
WASM_EXEC_TEST(DanglingAssign) {
1389
  WasmRunner<int32_t, int32_t> r(execution_tier);
1390
  // { return 0; p0 = 0; }
1391
  BUILD(r, WASM_BLOCK_I(RET_I8(99), WASM_LOCAL_TEE(0, WASM_ZERO)));
1392 1393 1394
  CHECK_EQ(99, r.Call(1));
}

1395
WASM_EXEC_TEST(ExprIf_P) {
1396
  WasmRunner<int32_t, int32_t> r(execution_tier);
1397
  // p0 ? 11 : 22;
1398
  BUILD(r, WASM_IF_ELSE_I(WASM_LOCAL_GET(0),  // --
1399 1400
                          WASM_I32V_1(11),    // --
                          WASM_I32V_1(22)));  // --
1401
  FOR_INT32_INPUTS(i) {
1402 1403
    int32_t expected = i ? 11 : 22;
    CHECK_EQ(expected, r.Call(i));
1404 1405 1406
  }
}

1407
WASM_EXEC_TEST(CountDown) {
1408
  WasmRunner<int32_t, int32_t> r(execution_tier);
1409 1410 1411 1412 1413 1414
  BUILD(r,
        WASM_LOOP(WASM_IFB(
            WASM_LOCAL_GET(0),
            WASM_LOCAL_SET(0, WASM_I32_SUB(WASM_LOCAL_GET(0), WASM_I32V_1(1))),
            WASM_BR(1))),
        WASM_LOCAL_GET(0));
1415 1416 1417 1418 1419
  CHECK_EQ(0, r.Call(1));
  CHECK_EQ(0, r.Call(10));
  CHECK_EQ(0, r.Call(100));
}

1420
WASM_EXEC_TEST(CountDown_fallthru) {
1421
  WasmRunner<int32_t, int32_t> r(execution_tier);
1422 1423 1424
  BUILD(
      r,
      WASM_LOOP(
1425 1426
          WASM_IF(WASM_NOT(WASM_LOCAL_GET(0)), WASM_BRV(2, WASM_LOCAL_GET(0))),
          WASM_LOCAL_SET(0, WASM_I32_SUB(WASM_LOCAL_GET(0), WASM_I32V_1(1))),
1427
          WASM_CONTINUE(0)),
1428
      WASM_LOCAL_GET(0));
1429 1430 1431 1432 1433
  CHECK_EQ(0, r.Call(1));
  CHECK_EQ(0, r.Call(10));
  CHECK_EQ(0, r.Call(100));
}

1434
WASM_EXEC_TEST(WhileCountDown) {
1435
  WasmRunner<int32_t, int32_t> r(execution_tier);
1436 1437 1438 1439 1440
  BUILD(r,
        WASM_WHILE(
            WASM_LOCAL_GET(0),
            WASM_LOCAL_SET(0, WASM_I32_SUB(WASM_LOCAL_GET(0), WASM_I32V_1(1)))),
        WASM_LOCAL_GET(0));
1441 1442 1443 1444 1445
  CHECK_EQ(0, r.Call(1));
  CHECK_EQ(0, r.Call(10));
  CHECK_EQ(0, r.Call(100));
}

1446
WASM_EXEC_TEST(Loop_if_break1) {
1447
  WasmRunner<int32_t, int32_t, int32_t> r(execution_tier);
1448 1449 1450 1451
  BUILD(r,
        WASM_LOOP(WASM_IF(WASM_LOCAL_GET(0), WASM_BRV(2, WASM_LOCAL_GET(1))),
                  WASM_LOCAL_SET(0, WASM_I32V_2(99))),
        WASM_LOCAL_GET(0));
1452 1453 1454 1455
  CHECK_EQ(99, r.Call(0, 11));
  CHECK_EQ(65, r.Call(3, 65));
  CHECK_EQ(10001, r.Call(10000, 10001));
  CHECK_EQ(-29, r.Call(-28, -29));
1456 1457
}

1458
WASM_EXEC_TEST(Loop_if_break2) {
1459
  WasmRunner<int32_t, int32_t, int32_t> r(execution_tier);
1460 1461 1462 1463
  BUILD(r,
        WASM_LOOP(WASM_BRV_IF(1, WASM_LOCAL_GET(1), WASM_LOCAL_GET(0)),
                  WASM_DROP, WASM_LOCAL_SET(0, WASM_I32V_2(99))),
        WASM_LOCAL_GET(0));
1464 1465 1466 1467
  CHECK_EQ(99, r.Call(0, 33));
  CHECK_EQ(3, r.Call(1, 3));
  CHECK_EQ(10000, r.Call(99, 10000));
  CHECK_EQ(-29, r.Call(-11, -29));
1468 1469
}

1470
WASM_EXEC_TEST(Loop_if_break_fallthru) {
1471
  WasmRunner<int32_t, int32_t> r(execution_tier);
1472 1473 1474 1475
  BUILD(r,
        B1(WASM_LOOP(WASM_IF(WASM_LOCAL_GET(0), WASM_BR(2)),
                     WASM_LOCAL_SET(0, WASM_I32V_2(93)))),
        WASM_LOCAL_GET(0));
1476 1477 1478 1479 1480 1481
  CHECK_EQ(93, r.Call(0));
  CHECK_EQ(3, r.Call(3));
  CHECK_EQ(10001, r.Call(10001));
  CHECK_EQ(-22, r.Call(-22));
}

1482
WASM_EXEC_TEST(Loop_if_break_fallthru2) {
1483
  WasmRunner<int32_t, int32_t> r(execution_tier);
1484 1485 1486 1487
  BUILD(r,
        B1(B1(WASM_LOOP(WASM_IF(WASM_LOCAL_GET(0), WASM_BR(2)),
                        WASM_LOCAL_SET(0, WASM_I32V_2(93))))),
        WASM_LOCAL_GET(0));
1488 1489 1490 1491 1492 1493
  CHECK_EQ(93, r.Call(0));
  CHECK_EQ(3, r.Call(3));
  CHECK_EQ(10001, r.Call(10001));
  CHECK_EQ(-22, r.Call(-22));
}

1494
WASM_EXEC_TEST(IfBreak1) {
1495
  WasmRunner<int32_t, int32_t> r(execution_tier);
1496
  BUILD(r, WASM_IF(WASM_LOCAL_GET(0), WASM_SEQ(WASM_BR(0), WASM_UNREACHABLE)),
1497
        WASM_I32V_2(91));
1498 1499 1500 1501 1502
  CHECK_EQ(91, r.Call(0));
  CHECK_EQ(91, r.Call(1));
  CHECK_EQ(91, r.Call(-8734));
}

1503
WASM_EXEC_TEST(IfBreak2) {
1504
  WasmRunner<int32_t, int32_t> r(execution_tier);
1505
  BUILD(r, WASM_IF(WASM_LOCAL_GET(0), WASM_SEQ(WASM_BR(0), RET_I8(77))),
1506
        WASM_I32V_2(81));
1507 1508 1509 1510
  CHECK_EQ(81, r.Call(0));
  CHECK_EQ(81, r.Call(1));
  CHECK_EQ(81, r.Call(-8734));
}
1511

1512
WASM_EXEC_TEST(LoadMemI32) {
1513
  WasmRunner<int32_t, int32_t> r(execution_tier);
1514 1515
  int32_t* memory =
      r.builder().AddMemoryElems<int32_t>(kWasmPageSize / sizeof(int32_t));
1516
  r.builder().RandomizeMemory(1111);
1517

1518
  BUILD(r, WASM_LOAD_MEM(MachineType::Int32(), WASM_ZERO));
1519

1520
  r.builder().WriteMemory(&memory[0], 99999999);
1521 1522
  CHECK_EQ(99999999, r.Call(0));

1523
  r.builder().WriteMemory(&memory[0], 88888888);
1524 1525
  CHECK_EQ(88888888, r.Call(0));

1526
  r.builder().WriteMemory(&memory[0], 77777777);
1527 1528 1529
  CHECK_EQ(77777777, r.Call(0));
}

1530
WASM_EXEC_TEST(LoadMemI32_alignment) {
1531
  for (byte alignment = 0; alignment <= 2; ++alignment) {
1532
    WasmRunner<int32_t, int32_t> r(execution_tier);
1533 1534
    int32_t* memory =
        r.builder().AddMemoryElems<int32_t>(kWasmPageSize / sizeof(int32_t));
1535
    r.builder().RandomizeMemory(1111);
1536 1537

    BUILD(r,
1538
          WASM_LOAD_MEM_ALIGNMENT(MachineType::Int32(), WASM_ZERO, alignment));
1539

1540 1541
    r.builder().WriteMemory(&memory[0], 0x1A2B3C4D);
    CHECK_EQ(0x1A2B3C4D, r.Call(0));
1542

1543 1544
    r.builder().WriteMemory(&memory[0], 0x5E6F7A8B);
    CHECK_EQ(0x5E6F7A8B, r.Call(0));
1545

1546 1547
    r.builder().WriteMemory(&memory[0], 0x7CA0B1C2);
    CHECK_EQ(0x7CA0B1C2, r.Call(0));
1548 1549 1550
  }
}

1551
WASM_EXEC_TEST(LoadMemI32_oob) {
1552
  WasmRunner<int32_t, uint32_t> r(execution_tier);
1553 1554
  int32_t* memory =
      r.builder().AddMemoryElems<int32_t>(kWasmPageSize / sizeof(int32_t));
1555
  r.builder().RandomizeMemory(1111);
1556

1557
  BUILD(r, WASM_LOAD_MEM(MachineType::Int32(), WASM_LOCAL_GET(0)));
1558

1559
  r.builder().WriteMemory(&memory[0], 88888888);
1560
  CHECK_EQ(88888888, r.Call(0u));
1561 1562
  for (uint32_t offset = kWasmPageSize - 3; offset < kWasmPageSize + 40;
       ++offset) {
1563 1564 1565
    CHECK_TRAP(r.Call(offset));
  }

1566
  for (uint32_t offset = 0x80000000; offset < 0x80000010; ++offset) {
1567 1568 1569 1570
    CHECK_TRAP(r.Call(offset));
  }
}

1571
WASM_EXEC_TEST(LoadMem_offset_oob) {
1572 1573 1574 1575 1576 1577
  static const MachineType machineTypes[] = {
      MachineType::Int8(),   MachineType::Uint8(),  MachineType::Int16(),
      MachineType::Uint16(), MachineType::Int32(),  MachineType::Uint32(),
      MachineType::Int64(),  MachineType::Uint64(), MachineType::Float32(),
      MachineType::Float64()};

1578 1579
  constexpr size_t num_bytes = kWasmPageSize;

1580
  for (size_t m = 0; m < arraysize(machineTypes); ++m) {
1581
    WasmRunner<int32_t, uint32_t> r(execution_tier);
1582
    r.builder().AddMemoryElems<byte>(num_bytes);
1583
    r.builder().RandomizeMemory(1116 + static_cast<int>(m));
1584

1585
    constexpr byte offset = 8;
1586
    uint32_t boundary = num_bytes - offset - machineTypes[m].MemSize();
1587

1588
    BUILD(r, WASM_LOAD_MEM_OFFSET(machineTypes[m], offset, WASM_LOCAL_GET(0)),
1589
          WASM_DROP, WASM_ZERO);
1590 1591 1592

    CHECK_EQ(0, r.Call(boundary));  // in bounds.

1593
    for (uint32_t offset = boundary + 1; offset < boundary + 19; ++offset) {
1594 1595 1596 1597 1598
      CHECK_TRAP(r.Call(offset));  // out of bounds.
    }
  }
}

1599
WASM_EXEC_TEST(LoadMemI32_offset) {
1600
  WasmRunner<int32_t, int32_t> r(execution_tier);
1601 1602
  int32_t* memory =
      r.builder().AddMemoryElems<int32_t>(kWasmPageSize / sizeof(int32_t));
1603
  r.builder().RandomizeMemory(1111);
1604

1605
  BUILD(r, WASM_LOAD_MEM_OFFSET(MachineType::Int32(), 4, WASM_LOCAL_GET(0)));
1606

1607 1608 1609 1610
  r.builder().WriteMemory(&memory[0], 66666666);
  r.builder().WriteMemory(&memory[1], 77777777);
  r.builder().WriteMemory(&memory[2], 88888888);
  r.builder().WriteMemory(&memory[3], 99999999);
1611 1612 1613 1614
  CHECK_EQ(77777777, r.Call(0));
  CHECK_EQ(88888888, r.Call(4));
  CHECK_EQ(99999999, r.Call(8));

1615 1616 1617 1618
  r.builder().WriteMemory(&memory[0], 11111111);
  r.builder().WriteMemory(&memory[1], 22222222);
  r.builder().WriteMemory(&memory[2], 33333333);
  r.builder().WriteMemory(&memory[3], 44444444);
1619 1620 1621 1622 1623
  CHECK_EQ(22222222, r.Call(0));
  CHECK_EQ(33333333, r.Call(4));
  CHECK_EQ(44444444, r.Call(8));
}

1624
WASM_EXEC_TEST(LoadMemI32_const_oob_misaligned) {
1625 1626 1627
  // This test accesses memory starting at kRunwayLength bytes before the end of
  // the memory until a few bytes beyond.
  constexpr byte kRunwayLength = 12;
1628
  // TODO(titzer): Fix misaligned accesses on MIPS and re-enable.
1629 1630 1631
  for (byte offset = 0; offset < kRunwayLength + 5; ++offset) {
    for (uint32_t index = kWasmPageSize - kRunwayLength;
         index < kWasmPageSize + 5; ++index) {
1632
      WasmRunner<int32_t> r(execution_tier);
1633
      r.builder().AddMemoryElems<byte>(kWasmPageSize);
1634
      r.builder().RandomizeMemory();
1635

1636
      BUILD(r, WASM_LOAD_MEM_OFFSET(MachineType::Int32(), offset,
1637
                                    WASM_I32V_3(index)));
1638

1639
      if (offset + index + sizeof(int32_t) <= kWasmPageSize) {
1640
        CHECK_EQ(r.builder().raw_val_at<int32_t>(offset + index), r.Call());
1641 1642 1643 1644 1645 1646 1647
      } else {
        CHECK_TRAP(r.Call());
      }
    }
  }
}

1648
WASM_EXEC_TEST(LoadMemI32_const_oob) {
1649 1650 1651 1652 1653 1654
  // This test accesses memory starting at kRunwayLength bytes before the end of
  // the memory until a few bytes beyond.
  constexpr byte kRunwayLength = 24;
  for (byte offset = 0; offset < kRunwayLength + 5; offset += 4) {
    for (uint32_t index = kWasmPageSize - kRunwayLength;
         index < kWasmPageSize + 5; index += 4) {
1655
      WasmRunner<int32_t> r(execution_tier);
1656
      r.builder().AddMemoryElems<byte>(kWasmPageSize);
1657
      r.builder().RandomizeMemory();
1658

1659
      BUILD(r, WASM_LOAD_MEM_OFFSET(MachineType::Int32(), offset,
1660
                                    WASM_I32V_3(index)));
1661

1662
      if (offset + index + sizeof(int32_t) <= kWasmPageSize) {
1663
        CHECK_EQ(r.builder().raw_val_at<int32_t>(offset + index), r.Call());
1664 1665 1666 1667 1668 1669 1670
      } else {
        CHECK_TRAP(r.Call());
      }
    }
  }
}

1671
WASM_EXEC_TEST(StoreMemI32_alignment) {
1672 1673
  const int32_t kWritten = 0x12345678;

1674
  for (byte i = 0; i <= 2; ++i) {
1675
    WasmRunner<int32_t, int32_t> r(execution_tier);
1676 1677
    int32_t* memory =
        r.builder().AddMemoryElems<int32_t>(kWasmPageSize / sizeof(int32_t));
1678 1679 1680 1681
    BUILD(r,
          WASM_STORE_MEM_ALIGNMENT(MachineType::Int32(), WASM_ZERO, i,
                                   WASM_LOCAL_GET(0)),
          WASM_LOCAL_GET(0));
1682
    r.builder().RandomizeMemory(1111);
1683 1684 1685
    memory[0] = 0;

    CHECK_EQ(kWritten, r.Call(kWritten));
1686
    CHECK_EQ(kWritten, r.builder().ReadMemory(&memory[0]));
1687 1688 1689
  }
}

1690
WASM_EXEC_TEST(StoreMemI32_offset) {
1691
  WasmRunner<int32_t, int32_t> r(execution_tier);
1692 1693
  int32_t* memory =
      r.builder().AddMemoryElems<int32_t>(kWasmPageSize / sizeof(int32_t));
1694
  const int32_t kWritten = 0xAABBCCDD;
1695

1696 1697 1698
  BUILD(r,
        WASM_STORE_MEM_OFFSET(MachineType::Int32(), 4, WASM_LOCAL_GET(0),
                              WASM_I32V_5(kWritten)),
1699
        WASM_I32V_5(kWritten));
1700

1701
  for (int i = 0; i < 2; ++i) {
1702 1703 1704 1705 1706
    r.builder().RandomizeMemory(1111);
    r.builder().WriteMemory(&memory[0], 66666666);
    r.builder().WriteMemory(&memory[1], 77777777);
    r.builder().WriteMemory(&memory[2], 88888888);
    r.builder().WriteMemory(&memory[3], 99999999);
1707
    CHECK_EQ(kWritten, r.Call(i * 4));
1708 1709 1710 1711
    CHECK_EQ(66666666, r.builder().ReadMemory(&memory[0]));
    CHECK_EQ(i == 0 ? kWritten : 77777777, r.builder().ReadMemory(&memory[1]));
    CHECK_EQ(i == 1 ? kWritten : 88888888, r.builder().ReadMemory(&memory[2]));
    CHECK_EQ(i == 2 ? kWritten : 99999999, r.builder().ReadMemory(&memory[3]));
1712 1713 1714
  }
}

1715
WASM_EXEC_TEST(StoreMem_offset_oob) {
1716
  // 64-bit cases are handled in test-run-wasm-64.cc
1717 1718 1719 1720
  static const MachineType machineTypes[] = {
      MachineType::Int8(),    MachineType::Uint8(),  MachineType::Int16(),
      MachineType::Uint16(),  MachineType::Int32(),  MachineType::Uint32(),
      MachineType::Float32(), MachineType::Float64()};
1721

1722 1723
  constexpr size_t num_bytes = kWasmPageSize;

1724
  for (size_t m = 0; m < arraysize(machineTypes); ++m) {
1725
    WasmRunner<int32_t, uint32_t> r(execution_tier);
1726
    byte* memory = r.builder().AddMemoryElems<byte>(num_bytes);
1727

1728
    r.builder().RandomizeMemory(1119 + static_cast<int>(m));
1729

1730 1731 1732
    BUILD(r,
          WASM_STORE_MEM_OFFSET(machineTypes[m], 8, WASM_LOCAL_GET(0),
                                WASM_LOAD_MEM(machineTypes[m], WASM_ZERO)),
1733 1734
          WASM_ZERO);

1735
    byte memsize = machineTypes[m].MemSize();
1736
    uint32_t boundary = num_bytes - 8 - memsize;
1737 1738 1739
    CHECK_EQ(0, r.Call(boundary));  // in bounds.
    CHECK_EQ(0, memcmp(&memory[0], &memory[8 + boundary], memsize));

1740
    for (uint32_t offset = boundary + 1; offset < boundary + 19; ++offset) {
1741 1742 1743 1744 1745
      CHECK_TRAP(r.Call(offset));  // out of bounds.
    }
  }
}

1746 1747 1748 1749 1750 1751 1752 1753
WASM_EXEC_TEST(Store_i32_narrowed) {
  constexpr byte kOpcodes[] = {kExprI32StoreMem8, kExprI32StoreMem16,
                               kExprI32StoreMem};
  int stored_size_in_bytes = 0;
  for (auto opcode : kOpcodes) {
    stored_size_in_bytes = std::max(1, stored_size_in_bytes * 2);
    constexpr int kBytes = 24;
    uint8_t expected_memory[kBytes] = {0};
1754
    WasmRunner<int32_t, int32_t, int32_t> r(execution_tier);
1755
    uint8_t* memory = r.builder().AddMemoryElems<uint8_t>(kWasmPageSize);
1756 1757
    constexpr uint32_t kPattern = 0x12345678;

1758 1759
    BUILD(r, WASM_LOCAL_GET(0),                 // index
          WASM_LOCAL_GET(1),                    // value
1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775
          opcode, ZERO_ALIGNMENT, ZERO_OFFSET,  // store
          WASM_ZERO);                           // return value

    for (int i = 0; i <= kBytes - stored_size_in_bytes; ++i) {
      uint32_t pattern = base::bits::RotateLeft32(kPattern, i % 32);
      r.Call(i, pattern);
      for (int b = 0; b < stored_size_in_bytes; ++b) {
        expected_memory[i + b] = static_cast<uint8_t>(pattern >> (b * 8));
      }
      for (int w = 0; w < kBytes; ++w) {
        CHECK_EQ(expected_memory[w], memory[w]);
      }
    }
  }
}

1776
WASM_EXEC_TEST(LoadMemI32_P) {
1777
  const int kNumElems = 8;
1778
  WasmRunner<int32_t, int32_t> r(execution_tier);
1779 1780
  int32_t* memory =
      r.builder().AddMemoryElems<int32_t>(kWasmPageSize / sizeof(int32_t));
1781
  r.builder().RandomizeMemory(2222);
1782

1783
  BUILD(r, WASM_LOAD_MEM(MachineType::Int32(), WASM_LOCAL_GET(0)));
1784

1785
  for (int i = 0; i < kNumElems; ++i) {
1786
    CHECK_EQ(r.builder().ReadMemory(&memory[i]), r.Call(i * 4));
1787 1788 1789
  }
}

1790
WASM_EXEC_TEST(MemI32_Sum) {
1791
  const int kNumElems = 20;
1792
  WasmRunner<uint32_t, int32_t> r(execution_tier);
1793 1794
  uint32_t* memory =
      r.builder().AddMemoryElems<uint32_t>(kWasmPageSize / sizeof(int32_t));
1795
  const byte kSum = r.AllocateLocal(kWasmI32);
1796

1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807
  BUILD(
      r,
      WASM_WHILE(
          WASM_LOCAL_GET(0),
          WASM_BLOCK(WASM_LOCAL_SET(
                         kSum, WASM_I32_ADD(WASM_LOCAL_GET(kSum),
                                            WASM_LOAD_MEM(MachineType::Int32(),
                                                          WASM_LOCAL_GET(0)))),
                     WASM_LOCAL_SET(
                         0, WASM_I32_SUB(WASM_LOCAL_GET(0), WASM_I32V_1(4))))),
      WASM_LOCAL_GET(1));
1808 1809

  // Run 4 trials.
1810
  for (int i = 0; i < 3; ++i) {
1811
    r.builder().RandomizeMemory(i * 33);
1812
    uint32_t expected = 0;
1813
    for (size_t j = kNumElems - 1; j > 0; --j) {
1814
      expected += r.builder().ReadMemory(&memory[j]);
1815
    }
1816
    uint32_t result = r.Call(4 * (kNumElems - 1));
1817 1818 1819 1820
    CHECK_EQ(expected, result);
  }
}

1821
WASM_EXEC_TEST(CheckMachIntsZero) {
1822
  const int kNumElems = 55;
1823
  WasmRunner<uint32_t, int32_t> r(execution_tier);
1824
  r.builder().AddMemoryElems<uint32_t>(kWasmPageSize / sizeof(uint32_t));
1825

1826
  BUILD(r,                               // --
1827
        /**/ kExprLoop, kVoidCode,       // --
1828
        /*  */ kExprLocalGet, 0,         // --
1829
        /*  */ kExprIf, kVoidCode,       // --
1830
        /*    */ kExprLocalGet, 0,       // --
1831
        /*    */ kExprI32LoadMem, 0, 0,  // --
1832
        /*    */ kExprIf, kVoidCode,     // --
1833
        /*      */ kExprI32Const, 127,   // --
1834 1835
        /*      */ kExprReturn,          // --
        /*    */ kExprEnd,               // --
1836
        /*    */ kExprLocalGet, 0,       // --
1837
        /*    */ kExprI32Const, 4,       // --
1838
        /*    */ kExprI32Sub,            // --
1839
        /*    */ kExprLocalTee, 0,       // --
1840 1841 1842
        /*    */ kExprBr, DEPTH_0,       // --
        /*  */ kExprEnd,                 // --
        /**/ kExprEnd,                   // --
1843
        /**/ kExprI32Const, 0);          // --
1844

1845
  r.builder().BlankMemory();
1846
  CHECK_EQ(0, r.Call((kNumElems - 1) * 4));
1847 1848
}

1849
WASM_EXEC_TEST(MemF32_Sum) {
1850
  const int kSize = 5;
1851
  WasmRunner<int32_t, int32_t> r(execution_tier);
1852
  r.builder().AddMemoryElems<float>(kWasmPageSize / sizeof(float));
1853 1854 1855 1856 1857 1858
  float* buffer = r.builder().raw_mem_start<float>();
  r.builder().WriteMemory(&buffer[0], -99.25f);
  r.builder().WriteMemory(&buffer[1], -888.25f);
  r.builder().WriteMemory(&buffer[2], -77.25f);
  r.builder().WriteMemory(&buffer[3], 66666.25f);
  r.builder().WriteMemory(&buffer[4], 5555.25f);
1859
  const byte kSum = r.AllocateLocal(kWasmF32);
1860

1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872
  BUILD(r,
        WASM_WHILE(
            WASM_LOCAL_GET(0),
            WASM_BLOCK(
                WASM_LOCAL_SET(
                    kSum, WASM_F32_ADD(WASM_LOCAL_GET(kSum),
                                       WASM_LOAD_MEM(MachineType::Float32(),
                                                     WASM_LOCAL_GET(0)))),
                WASM_LOCAL_SET(
                    0, WASM_I32_SUB(WASM_LOCAL_GET(0), WASM_I32V_1(4))))),
        WASM_STORE_MEM(MachineType::Float32(), WASM_ZERO, WASM_LOCAL_GET(kSum)),
        WASM_LOCAL_GET(0));
1873 1874

  CHECK_EQ(0, r.Call(4 * (kSize - 1)));
1875 1876
  CHECK_NE(-99.25f, r.builder().ReadMemory(&buffer[0]));
  CHECK_EQ(71256.0f, r.builder().ReadMemory(&buffer[0]));
1877 1878 1879
}

template <typename T>
1880 1881 1882
T GenerateAndRunFold(TestExecutionTier execution_tier, WasmOpcode binop,
                     T* buffer, uint32_t size, ValueType astType,
                     MachineType memType) {
1883
  WasmRunner<int32_t, int32_t> r(execution_tier);
1884 1885
  T* memory = r.builder().AddMemoryElems<T>(static_cast<uint32_t>(
      RoundUp(size * sizeof(T), kWasmPageSize) / sizeof(sizeof(T))));
1886
  for (uint32_t i = 0; i < size; ++i) {
1887
    r.builder().WriteMemory(&memory[i], buffer[i]);
1888
  }
1889
  const byte kAccum = r.AllocateLocal(astType);
1890

1891
  BUILD(
1892
      r, WASM_LOCAL_SET(kAccum, WASM_LOAD_MEM(memType, WASM_ZERO)),
1893
      WASM_WHILE(
1894 1895
          WASM_LOCAL_GET(0),
          WASM_BLOCK(WASM_LOCAL_SET(
1896
                         kAccum,
1897 1898 1899
                         WASM_BINOP(binop, WASM_LOCAL_GET(kAccum),
                                    WASM_LOAD_MEM(memType, WASM_LOCAL_GET(0)))),
                     WASM_LOCAL_SET(0, WASM_I32_SUB(WASM_LOCAL_GET(0),
1900
                                                    WASM_I32V_1(sizeof(T)))))),
1901 1902
      WASM_STORE_MEM(memType, WASM_ZERO, WASM_LOCAL_GET(kAccum)),
      WASM_LOCAL_GET(0));
1903
  r.Call(static_cast<int>(sizeof(T) * (size - 1)));
1904
  return r.builder().ReadMemory(&memory[0]);
1905 1906
}

1907
WASM_EXEC_TEST(MemF64_Mul) {
1908 1909
  const size_t kSize = 6;
  double buffer[kSize] = {1, 2, 2, 2, 2, 2};
1910
  double result =
1911
      GenerateAndRunFold<double>(execution_tier, kExprF64Mul, buffer, kSize,
1912
                                 kWasmF64, MachineType::Float64());
1913
  CHECK_EQ(32, result);
1914 1915
}

1916
WASM_EXEC_TEST(Build_Wasm_Infinite_Loop) {
1917
  WasmRunner<int32_t, int32_t> r(execution_tier);
1918
  // Only build the graph and compile, don't run.
1919
  BUILD(r, WASM_INFINITE_LOOP, WASM_ZERO);
1920 1921
}

1922
WASM_EXEC_TEST(Build_Wasm_Infinite_Loop_effect) {
1923
  WasmRunner<int32_t, int32_t> r(execution_tier);
1924
  r.builder().AddMemory(kWasmPageSize);
1925 1926

  // Only build the graph and compile, don't run.
1927 1928
  BUILD(r, WASM_LOOP(WASM_LOAD_MEM(MachineType::Int32(), WASM_ZERO), WASM_DROP),
        WASM_ZERO);
1929 1930
}

1931
WASM_EXEC_TEST(Unreachable0a) {
1932
  WasmRunner<int32_t, int32_t> r(execution_tier);
1933
  BUILD(r, WASM_BLOCK_I(WASM_BRV(0, WASM_I32V_1(9)), RET(WASM_LOCAL_GET(0))));
1934 1935 1936 1937
  CHECK_EQ(9, r.Call(0));
  CHECK_EQ(9, r.Call(1));
}

1938
WASM_EXEC_TEST(Unreachable0b) {
1939
  WasmRunner<int32_t, int32_t> r(execution_tier);
1940
  BUILD(r, WASM_BLOCK_I(WASM_BRV(0, WASM_I32V_1(7)), WASM_UNREACHABLE));
1941 1942 1943 1944
  CHECK_EQ(7, r.Call(0));
  CHECK_EQ(7, r.Call(1));
}

1945
WASM_COMPILED_EXEC_TEST(Build_Wasm_Unreachable1) {
1946
  WasmRunner<int32_t, int32_t> r(execution_tier);
1947 1948 1949
  BUILD(r, WASM_UNREACHABLE);
}

1950
WASM_COMPILED_EXEC_TEST(Build_Wasm_Unreachable2) {
1951
  WasmRunner<int32_t, int32_t> r(execution_tier);
1952 1953 1954
  BUILD(r, WASM_UNREACHABLE, WASM_UNREACHABLE);
}

1955
WASM_COMPILED_EXEC_TEST(Build_Wasm_Unreachable3) {
1956
  WasmRunner<int32_t, int32_t> r(execution_tier);
1957 1958 1959
  BUILD(r, WASM_UNREACHABLE, WASM_UNREACHABLE, WASM_UNREACHABLE);
}

1960
WASM_COMPILED_EXEC_TEST(Build_Wasm_UnreachableIf1) {
1961
  WasmRunner<int32_t, int32_t> r(execution_tier);
1962
  BUILD(r, WASM_UNREACHABLE,
1963
        WASM_IF(WASM_LOCAL_GET(0), WASM_SEQ(WASM_LOCAL_GET(0), WASM_DROP)),
1964
        WASM_ZERO);
1965 1966
}

1967
WASM_COMPILED_EXEC_TEST(Build_Wasm_UnreachableIf2) {
1968
  WasmRunner<int32_t, int32_t> r(execution_tier);
1969
  BUILD(r, WASM_UNREACHABLE,
1970
        WASM_IF_ELSE_I(WASM_LOCAL_GET(0), WASM_LOCAL_GET(0), WASM_UNREACHABLE));
1971 1972
}

1973
WASM_EXEC_TEST(Unreachable_Load) {
1974
  WasmRunner<int32_t, int32_t> r(execution_tier);
1975
  r.builder().AddMemory(kWasmPageSize);
1976 1977
  BUILD(r, WASM_BLOCK_I(WASM_BRV(0, WASM_LOCAL_GET(0)),
                        WASM_LOAD_MEM(MachineType::Int8(), WASM_LOCAL_GET(0))));
1978 1979 1980 1981
  CHECK_EQ(11, r.Call(11));
  CHECK_EQ(21, r.Call(21));
}

1982
WASM_EXEC_TEST(BrV_Fallthrough) {
1983
  WasmRunner<int32_t> r(execution_tier);
1984 1985 1986 1987 1988
  BUILD(r, WASM_BLOCK_I(WASM_BLOCK(WASM_BRV(1, WASM_I32V_1(42))),
                        WASM_I32V_1(22)));
  CHECK_EQ(42, r.Call());
}

1989
WASM_EXEC_TEST(Infinite_Loop_not_taken1) {
1990
  WasmRunner<int32_t, int32_t> r(execution_tier);
1991
  BUILD(r, WASM_IF(WASM_LOCAL_GET(0), WASM_INFINITE_LOOP), WASM_I32V_1(45));
1992 1993 1994 1995
  // Run the code, but don't go into the infinite loop.
  CHECK_EQ(45, r.Call(0));
}

1996
WASM_EXEC_TEST(Infinite_Loop_not_taken2) {
1997
  WasmRunner<int32_t, int32_t> r(execution_tier);
1998
  BUILD(r, WASM_BLOCK_I(
1999
               WASM_IF_ELSE(WASM_LOCAL_GET(0), WASM_BRV(1, WASM_I32V_1(45)),
2000 2001
                            WASM_INFINITE_LOOP),
               WASM_ZERO));
2002 2003 2004 2005
  // Run the code, but don't go into the infinite loop.
  CHECK_EQ(45, r.Call(1));
}

2006
WASM_EXEC_TEST(Infinite_Loop_not_taken2_brif) {
2007
  WasmRunner<int32_t, int32_t> r(execution_tier);
2008
  BUILD(r, WASM_BLOCK_I(WASM_BRV_IF(0, WASM_I32V_1(45), WASM_LOCAL_GET(0)),
2009
                        WASM_INFINITE_LOOP));
2010 2011 2012 2013
  // Run the code, but don't go into the infinite loop.
  CHECK_EQ(45, r.Call(1));
}

2014 2015
static void TestBuildGraphForSimpleExpression(WasmOpcode opcode) {
  Isolate* isolate = CcTest::InitIsolateOnce();
2016
  Zone zone(isolate->allocator(), ZONE_NAME, kCompressGraphZone);
2017
  HandleScope scope(isolate);
2018 2019 2020
  // TODO(ahaas): Enable this test for externref opcodes when code generation
  // for them is implemented.
  if (WasmOpcodes::IsExternRefOpcode(opcode)) return;
2021
  // Enable all optional operators.
2022 2023 2024 2025 2026 2027 2028
  compiler::CommonOperatorBuilder common(&zone);
  compiler::MachineOperatorBuilder machine(
      &zone, MachineType::PointerRepresentation(),
      compiler::MachineOperatorBuilder::kAllOptionalOps);
  compiler::Graph graph(&zone);
  compiler::JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr,
                            &machine);
2029
  const FunctionSig* sig = WasmOpcodes::Signature(opcode);
2030

2031
  if (sig->parameter_count() == 1) {
2032
    byte code[] = {WASM_NO_LOCALS, kExprLocalGet, 0, static_cast<byte>(opcode),
2033
                   WASM_END};
2034
    TestBuildingGraph(&zone, &jsgraph, nullptr, sig, nullptr, code,
2035
                      code + arraysize(code));
2036
  } else {
2037
    CHECK_EQ(2, sig->parameter_count());
2038
    byte code[] = {WASM_NO_LOCALS,
2039
                   kExprLocalGet,
2040
                   0,
2041
                   kExprLocalGet,
2042 2043 2044
                   1,
                   static_cast<byte>(opcode),
                   WASM_END};
2045
    TestBuildingGraph(&zone, &jsgraph, nullptr, sig, nullptr, code,
2046
                      code + arraysize(code));
2047
  }
2048 2049 2050 2051
}

TEST(Build_Wasm_SimpleExprs) {
// Test that the decoder can build a graph for all supported simple expressions.
2052 2053
#define GRAPH_BUILD_TEST(name, opcode, sig) \
  TestBuildGraphForSimpleExpression(kExpr##name);
2054 2055 2056 2057 2058 2059

  FOREACH_SIMPLE_OPCODE(GRAPH_BUILD_TEST);

#undef GRAPH_BUILD_TEST
}

2060
WASM_EXEC_TEST(Int32LoadInt8_signext) {
2061
  WasmRunner<int32_t, int32_t> r(execution_tier);
2062
  const int kNumElems = kWasmPageSize;
2063 2064
  int8_t* memory = r.builder().AddMemoryElems<int8_t>(kNumElems);
  r.builder().RandomizeMemory();
2065
  memory[0] = -1;
2066
  BUILD(r, WASM_LOAD_MEM(MachineType::Int8(), WASM_LOCAL_GET(0)));
2067

2068 2069
  for (int i = 0; i < kNumElems; ++i) {
    CHECK_EQ(memory[i], r.Call(i));
2070 2071 2072
  }
}

2073
WASM_EXEC_TEST(Int32LoadInt8_zeroext) {
2074
  WasmRunner<int32_t, int32_t> r(execution_tier);
2075
  const int kNumElems = kWasmPageSize;
2076 2077
  byte* memory = r.builder().AddMemory(kNumElems);
  r.builder().RandomizeMemory(77);
2078
  memory[0] = 255;
2079
  BUILD(r, WASM_LOAD_MEM(MachineType::Uint8(), WASM_LOCAL_GET(0)));
2080

2081 2082
  for (int i = 0; i < kNumElems; ++i) {
    CHECK_EQ(memory[i], r.Call(i));
2083 2084 2085
  }
}

2086
WASM_EXEC_TEST(Int32LoadInt16_signext) {
2087
  WasmRunner<int32_t, int32_t> r(execution_tier);
2088
  const int kNumBytes = kWasmPageSize;
2089 2090
  byte* memory = r.builder().AddMemory(kNumBytes);
  r.builder().RandomizeMemory(888);
2091
  memory[1] = 200;
2092
  BUILD(r, WASM_LOAD_MEM(MachineType::Int16(), WASM_LOCAL_GET(0)));
2093

2094
  for (int i = 0; i < kNumBytes; i += 2) {
2095
    int32_t expected = static_cast<int16_t>(memory[i] | (memory[i + 1] << 8));
2096
    CHECK_EQ(expected, r.Call(i));
2097 2098 2099
  }
}

2100
WASM_EXEC_TEST(Int32LoadInt16_zeroext) {
2101
  WasmRunner<int32_t, int32_t> r(execution_tier);
2102
  const int kNumBytes = kWasmPageSize;
2103 2104
  byte* memory = r.builder().AddMemory(kNumBytes);
  r.builder().RandomizeMemory(9999);
2105
  memory[1] = 204;
2106
  BUILD(r, WASM_LOAD_MEM(MachineType::Uint16(), WASM_LOCAL_GET(0)));
2107

2108
  for (int i = 0; i < kNumBytes; i += 2) {
2109
    int32_t expected = memory[i] | (memory[i + 1] << 8);
2110
    CHECK_EQ(expected, r.Call(i));
2111 2112 2113
  }
}

2114
WASM_EXEC_TEST(Int32Global) {
2115
  WasmRunner<int32_t, int32_t> r(execution_tier);
2116
  int32_t* global = r.builder().AddGlobal<int32_t>();
2117
  // global = global + p0
2118
  BUILD(r,
2119
        WASM_GLOBAL_SET(0, WASM_I32_ADD(WASM_GLOBAL_GET(0), WASM_LOCAL_GET(0))),
2120
        WASM_ZERO);
2121

2122
  *global = 116;
2123
  for (int i = 9; i < 444444; i += 111111) {
2124
    int32_t expected = *global + i;
2125
    r.Call(i);
2126
    CHECK_EQ(expected, *global);
2127 2128 2129
  }
}

2130
WASM_EXEC_TEST(Int32Globals_DontAlias) {
2131
  const int kNumGlobals = 3;
2132
  for (int g = 0; g < kNumGlobals; ++g) {
2133
    // global = global + p0
2134
    WasmRunner<int32_t, int32_t> r(execution_tier);
2135 2136 2137
    int32_t* globals[] = {r.builder().AddGlobal<int32_t>(),
                          r.builder().AddGlobal<int32_t>(),
                          r.builder().AddGlobal<int32_t>()};
2138

2139 2140
    BUILD(
        r,
2141 2142
        WASM_GLOBAL_SET(g, WASM_I32_ADD(WASM_GLOBAL_GET(g), WASM_LOCAL_GET(0))),
        WASM_GLOBAL_GET(g));
2143 2144

    // Check that reading/writing global number {g} doesn't alter the others.
2145
    *(globals[g]) = 116 * g;
2146 2147
    int32_t before[kNumGlobals];
    for (int i = 9; i < 444444; i += 111113) {
2148 2149
      int32_t sum = *(globals[g]) + i;
      for (int j = 0; j < kNumGlobals; ++j) before[j] = *(globals[j]);
2150 2151
      int32_t result = r.Call(i);
      CHECK_EQ(sum, result);
2152
      for (int j = 0; j < kNumGlobals; ++j) {
2153
        int32_t expected = j == g ? sum : before[j];
2154
        CHECK_EQ(expected, *(globals[j]));
2155 2156 2157 2158 2159
      }
    }
  }
}

2160
WASM_EXEC_TEST(Float32Global) {
2161
  WasmRunner<int32_t, int32_t> r(execution_tier);
2162
  float* global = r.builder().AddGlobal<float>();
2163
  // global = global + p0
2164
  BUILD(r,
2165 2166
        WASM_GLOBAL_SET(0,
                        WASM_F32_ADD(WASM_GLOBAL_GET(0),
2167
                                     WASM_F32_SCONVERT_I32(WASM_LOCAL_GET(0)))),
2168
        WASM_ZERO);
2169

2170
  *global = 1.25;
2171
  for (int i = 9; i < 4444; i += 1111) {
2172
    volatile float expected = *global + i;
2173
    r.Call(i);
2174
    CHECK_EQ(expected, *global);
2175 2176 2177
  }
}

2178
WASM_EXEC_TEST(Float64Global) {
2179
  WasmRunner<int32_t, int32_t> r(execution_tier);
2180
  double* global = r.builder().AddGlobal<double>();
2181
  // global = global + p0
2182
  BUILD(r,
2183 2184
        WASM_GLOBAL_SET(0,
                        WASM_F64_ADD(WASM_GLOBAL_GET(0),
2185
                                     WASM_F64_SCONVERT_I32(WASM_LOCAL_GET(0)))),
2186
        WASM_ZERO);
2187

2188
  *global = 1.25;
2189
  for (int i = 9; i < 4444; i += 1111) {
2190
    volatile double expected = *global + i;
2191
    r.Call(i);
2192
    CHECK_EQ(expected, *global);
2193 2194 2195
  }
}

2196
WASM_EXEC_TEST(MixedGlobals) {
2197
  WasmRunner<int32_t, int32_t> r(execution_tier);
2198

2199
  int32_t* unused = r.builder().AddGlobal<int32_t>();
2200
  byte* memory = r.builder().AddMemory(kWasmPageSize);
2201

2202 2203 2204 2205
  int32_t* var_int32 = r.builder().AddGlobal<int32_t>();
  uint32_t* var_uint32 = r.builder().AddGlobal<uint32_t>();
  float* var_float = r.builder().AddGlobal<float>();
  double* var_double = r.builder().AddGlobal<double>();
2206

2207 2208 2209 2210
  BUILD(r, WASM_GLOBAL_SET(1, WASM_LOAD_MEM(MachineType::Int32(), WASM_ZERO)),
        WASM_GLOBAL_SET(2, WASM_LOAD_MEM(MachineType::Uint32(), WASM_ZERO)),
        WASM_GLOBAL_SET(3, WASM_LOAD_MEM(MachineType::Float32(), WASM_ZERO)),
        WASM_GLOBAL_SET(4, WASM_LOAD_MEM(MachineType::Float64(), WASM_ZERO)),
2211
        WASM_ZERO);
2212

2213 2214
  memory[0] = 0xAA;
  memory[1] = 0xCC;
2215
  memory[2] = 0x55;
2216
  memory[3] = 0xEE;
2217 2218 2219 2220 2221 2222
  memory[4] = 0x33;
  memory[5] = 0x22;
  memory[6] = 0x11;
  memory[7] = 0x99;
  r.Call(1);

2223 2224 2225 2226
  CHECK_EQ(static_cast<int32_t>(0xEE55CCAA), *var_int32);
  CHECK_EQ(static_cast<uint32_t>(0xEE55CCAA), *var_uint32);
  CHECK_EQ(bit_cast<float>(0xEE55CCAA), *var_float);
  CHECK_EQ(bit_cast<double>(0x99112233EE55CCAAULL), *var_double);
2227 2228 2229 2230

  USE(unused);
}

2231
WASM_EXEC_TEST(CallEmpty) {
2232
  const int32_t kExpected = -414444;
2233
  WasmRunner<int32_t> r(execution_tier);
2234

2235
  // Build the target function.
2236 2237
  WasmFunctionCompiler& target_func = r.NewFunction<int>();
  BUILD(target_func, WASM_I32V_3(kExpected));
2238 2239

  // Build the calling function.
2240
  BUILD(r, WASM_CALL_FUNCTION0(target_func.function_index()));
2241 2242 2243 2244 2245

  int32_t result = r.Call();
  CHECK_EQ(kExpected, result);
}

2246
WASM_EXEC_TEST(CallF32StackParameter) {
2247
  WasmRunner<float> r(execution_tier);
2248

2249
  // Build the target function.
2250 2251
  ValueType param_types[20];
  for (int i = 0; i < 20; ++i) param_types[i] = kWasmF32;
2252
  FunctionSig sig(1, 19, param_types);
2253
  WasmFunctionCompiler& t = r.NewFunction(&sig);
2254
  BUILD(t, WASM_LOCAL_GET(17));
2255 2256

  // Build the calling function.
2257
  BUILD(r, WASM_CALL_FUNCTION(
2258 2259
               t.function_index(), WASM_F32(1.0f), WASM_F32(2.0f),
               WASM_F32(4.0f), WASM_F32(8.0f), WASM_F32(16.0f), WASM_F32(32.0f),
2260 2261 2262 2263 2264 2265 2266 2267 2268
               WASM_F32(64.0f), WASM_F32(128.0f), WASM_F32(256.0f),
               WASM_F32(1.5f), WASM_F32(2.5f), WASM_F32(4.5f), WASM_F32(8.5f),
               WASM_F32(16.5f), WASM_F32(32.5f), WASM_F32(64.5f),
               WASM_F32(128.5f), WASM_F32(256.5f), WASM_F32(512.5f)));

  float result = r.Call();
  CHECK_EQ(256.5f, result);
}

2269
WASM_EXEC_TEST(CallF64StackParameter) {
2270
  WasmRunner<double> r(execution_tier);
2271

2272
  // Build the target function.
2273 2274
  ValueType param_types[20];
  for (int i = 0; i < 20; ++i) param_types[i] = kWasmF64;
2275
  FunctionSig sig(1, 19, param_types);
2276
  WasmFunctionCompiler& t = r.NewFunction(&sig);
2277
  BUILD(t, WASM_LOCAL_GET(17));
2278 2279

  // Build the calling function.
2280
  BUILD(r, WASM_CALL_FUNCTION(t.function_index(), WASM_F64(1.0), WASM_F64(2.0),
2281 2282 2283 2284 2285 2286
                              WASM_F64(4.0), WASM_F64(8.0), WASM_F64(16.0),
                              WASM_F64(32.0), WASM_F64(64.0), WASM_F64(128.0),
                              WASM_F64(256.0), WASM_F64(1.5), WASM_F64(2.5),
                              WASM_F64(4.5), WASM_F64(8.5), WASM_F64(16.5),
                              WASM_F64(32.5), WASM_F64(64.5), WASM_F64(128.5),
                              WASM_F64(256.5), WASM_F64(512.5)));
2287 2288 2289 2290 2291

  float result = r.Call();
  CHECK_EQ(256.5, result);
}

2292
WASM_EXEC_TEST(CallVoid) {
2293
  WasmRunner<int32_t> r(execution_tier);
2294

2295 2296
  const byte kMemOffset = 8;
  const int32_t kElemNum = kMemOffset / sizeof(int32_t);
2297
  const int32_t kExpected = 414444;
2298 2299
  // Build the target function.
  TestSignatures sigs;
2300 2301
  int32_t* memory =
      r.builder().AddMemoryElems<int32_t>(kWasmPageSize / sizeof(int32_t));
2302
  r.builder().RandomizeMemory();
2303
  WasmFunctionCompiler& t = r.NewFunction(sigs.v_v());
2304
  BUILD(t, WASM_STORE_MEM(MachineType::Int32(), WASM_I32V_1(kMemOffset),
2305
                          WASM_I32V_3(kExpected)));
2306 2307

  // Build the calling function.
2308
  BUILD(r, WASM_CALL_FUNCTION0(t.function_index()),
2309
        WASM_LOAD_MEM(MachineType::Int32(), WASM_I32V_1(kMemOffset)));
2310 2311 2312

  int32_t result = r.Call();
  CHECK_EQ(kExpected, result);
2313
  CHECK_EQ(static_cast<int64_t>(kExpected),
2314
           static_cast<int64_t>(r.builder().ReadMemory(&memory[kElemNum])));
2315 2316
}

2317
WASM_EXEC_TEST(Call_Int32Add) {
2318
  WasmRunner<int32_t, int32_t, int32_t> r(execution_tier);
2319

2320
  // Build the target function.
2321
  WasmFunctionCompiler& t = r.NewFunction<int32_t, int32_t, int32_t>();
2322
  BUILD(t, WASM_I32_ADD(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)));
2323 2324

  // Build the caller function.
2325 2326
  BUILD(r, WASM_CALL_FUNCTION(t.function_index(), WASM_LOCAL_GET(0),
                              WASM_LOCAL_GET(1)));
2327 2328 2329

  FOR_INT32_INPUTS(i) {
    FOR_INT32_INPUTS(j) {
2330 2331 2332
      int32_t expected = static_cast<int32_t>(static_cast<uint32_t>(i) +
                                              static_cast<uint32_t>(j));
      CHECK_EQ(expected, r.Call(i, j));
2333 2334 2335 2336
    }
  }
}

2337
WASM_EXEC_TEST(Call_Float32Sub) {
2338
  WasmRunner<float, float, float> r(execution_tier);
2339 2340

  // Build the target function.
2341
  WasmFunctionCompiler& target_func = r.NewFunction<float, float, float>();
2342
  BUILD(target_func, WASM_F32_SUB(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)));
2343

2344
  // Build the caller function.
2345 2346
  BUILD(r, WASM_CALL_FUNCTION(target_func.function_index(), WASM_LOCAL_GET(0),
                              WASM_LOCAL_GET(1)));
2347 2348

  FOR_FLOAT32_INPUTS(i) {
2349
    FOR_FLOAT32_INPUTS(j) { CHECK_FLOAT_EQ(i - j, r.Call(i, j)); }
2350 2351 2352
  }
}

2353
WASM_EXEC_TEST(Call_Float64Sub) {
2354
  WasmRunner<int32_t> r(execution_tier);
2355 2356
  double* memory =
      r.builder().AddMemoryElems<double>(kWasmPageSize / sizeof(double));
2357

2358 2359
  BUILD(r, WASM_STORE_MEM(
               MachineType::Float64(), WASM_ZERO,
2360 2361 2362 2363
               WASM_F64_SUB(
                   WASM_LOAD_MEM(MachineType::Float64(), WASM_ZERO),
                   WASM_LOAD_MEM(MachineType::Float64(), WASM_I32V_1(8)))),
        WASM_I32V_2(107));
2364 2365 2366

  FOR_FLOAT64_INPUTS(i) {
    FOR_FLOAT64_INPUTS(j) {
2367 2368 2369
      r.builder().WriteMemory(&memory[0], i);
      r.builder().WriteMemory(&memory[1], j);
      double expected = i - j;
2370
      CHECK_EQ(107, r.Call());
2371

2372
      if (expected != expected) {
2373 2374
        CHECK(r.builder().ReadMemory(&memory[0]) !=
              r.builder().ReadMemory(&memory[0]));
2375
      } else {
2376
        CHECK_EQ(expected, r.builder().ReadMemory(&memory[0]));
2377 2378 2379 2380 2381
      }
    }
  }
}

2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401
template <typename T>
static T factorial(T v) {
  T expected = 1;
  for (T i = v; i > 1; i--) {
    expected *= i;
  }
  return expected;
}

template <typename T>
static T sum_1_to_n(T v) {
  return v * (v + 1) / 2;
}

// We use unsigned arithmetic because of ubsan validation.
WASM_EXEC_TEST(Regular_Factorial) {
  WasmRunner<uint32_t, uint32_t> r(execution_tier);

  WasmFunctionCompiler& fact_aux_fn =
      r.NewFunction<uint32_t, uint32_t, uint32_t>("fact_aux");
2402
  BUILD(r, WASM_CALL_FUNCTION(fact_aux_fn.function_index(), WASM_LOCAL_GET(0),
2403 2404 2405 2406
                              WASM_I32V(1)));

  BUILD(fact_aux_fn,
        WASM_IF_ELSE_I(
2407
            WASM_I32_LES(WASM_LOCAL_GET(0), WASM_I32V(1)), WASM_LOCAL_GET(1),
2408 2409
            WASM_CALL_FUNCTION(
                fact_aux_fn.function_index(),
2410 2411
                WASM_I32_SUB(WASM_LOCAL_GET(0), WASM_I32V(1)),
                WASM_I32_MUL(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)))));
2412 2413 2414 2415 2416 2417 2418 2419

  uint32_t test_values[] = {1, 2, 5, 10, 20};

  for (uint32_t v : test_values) {
    CHECK_EQ(factorial(v), r.Call(v));
  }
}

2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443
namespace {
// TODO(cleanup): Define in cctest.h and re-use where appropriate.
class IsolateScope {
 public:
  IsolateScope() {
    v8::Isolate::CreateParams create_params;
    create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
    isolate_ = v8::Isolate::New(create_params);
    isolate_->Enter();
  }

  ~IsolateScope() {
    isolate_->Exit();
    isolate_->Dispose();
  }

  v8::Isolate* isolate() { return isolate_; }
  Isolate* i_isolate() { return reinterpret_cast<Isolate*>(isolate_); }

 private:
  v8::Isolate* isolate_;
};
}  // namespace

2444 2445 2446 2447 2448 2449
// Tail-recursive variation on factorial:
// fact(N) => f(N,1).
//
// f(N,X) where N=<1 => X
// f(N,X) => f(N-1,X*N).

2450
UNINITIALIZED_WASM_EXEC_TEST(ReturnCall_Factorial) {
2451 2452 2453 2454
  EXPERIMENTAL_FLAG_SCOPE(return_call);
  // Run in bounded amount of stack - 8kb.
  FlagScope<int32_t> stack_size(&v8::internal::FLAG_stack_size, 8);

2455 2456 2457 2458
  IsolateScope isolate_scope;
  LocalContext current(isolate_scope.isolate());

  WasmRunner<uint32_t, uint32_t> r(execution_tier, nullptr, "main",
2459
                                   kRuntimeExceptionSupport, kMemory32,
2460
                                   isolate_scope.i_isolate());
2461 2462 2463 2464

  WasmFunctionCompiler& fact_aux_fn =
      r.NewFunction<uint32_t, uint32_t, uint32_t>("fact_aux");
  BUILD(r, WASM_RETURN_CALL_FUNCTION(fact_aux_fn.function_index(),
2465
                                     WASM_LOCAL_GET(0), WASM_I32V(1)));
2466 2467 2468

  BUILD(fact_aux_fn,
        WASM_IF_ELSE_I(
2469
            WASM_I32_LES(WASM_LOCAL_GET(0), WASM_I32V(1)), WASM_LOCAL_GET(1),
2470 2471
            WASM_RETURN_CALL_FUNCTION(
                fact_aux_fn.function_index(),
2472 2473
                WASM_I32_SUB(WASM_LOCAL_GET(0), WASM_I32V(1)),
                WASM_I32_MUL(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)))));
2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487

  uint32_t test_values[] = {1, 2, 5, 10, 20, 2000};

  for (uint32_t v : test_values) {
    CHECK_EQ(factorial<uint32_t>(v), r.Call(v));
  }
}

// Mutually recursive factorial mixing it up
// f(0,X)=>X
// f(N,X) => g(X*N,N-1)
// g(X,0) => X.
// g(X,N) => f(N-1,X*N).

2488
UNINITIALIZED_WASM_EXEC_TEST(ReturnCall_MutualFactorial) {
2489 2490 2491 2492
  EXPERIMENTAL_FLAG_SCOPE(return_call);
  // Run in bounded amount of stack - 8kb.
  FlagScope<int32_t> stack_size(&v8::internal::FLAG_stack_size, 8);

2493 2494 2495 2496
  IsolateScope isolate_scope;
  LocalContext current(isolate_scope.isolate());

  WasmRunner<uint32_t, uint32_t> r(execution_tier, nullptr, "main",
2497
                                   kRuntimeExceptionSupport, kMemory32,
2498
                                   isolate_scope.i_isolate());
2499 2500 2501 2502

  WasmFunctionCompiler& f_fn = r.NewFunction<uint32_t, uint32_t, uint32_t>("f");
  WasmFunctionCompiler& g_fn = r.NewFunction<uint32_t, uint32_t, uint32_t>("g");

2503
  BUILD(r, WASM_RETURN_CALL_FUNCTION(f_fn.function_index(), WASM_LOCAL_GET(0),
2504 2505 2506
                                     WASM_I32V(1)));

  BUILD(f_fn,
2507 2508
        WASM_IF_ELSE_I(WASM_I32_LES(WASM_LOCAL_GET(0), WASM_I32V(1)),
                       WASM_LOCAL_GET(1),
2509 2510
                       WASM_RETURN_CALL_FUNCTION(
                           g_fn.function_index(),
2511 2512
                           WASM_I32_MUL(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)),
                           WASM_I32_SUB(WASM_LOCAL_GET(0), WASM_I32V(1)))));
2513 2514 2515

  BUILD(g_fn,
        WASM_IF_ELSE_I(
2516
            WASM_I32_LES(WASM_LOCAL_GET(1), WASM_I32V(1)), WASM_LOCAL_GET(0),
2517 2518
            WASM_RETURN_CALL_FUNCTION(
                f_fn.function_index(),
2519 2520
                WASM_I32_SUB(WASM_LOCAL_GET(1), WASM_I32V(1)),
                WASM_I32_MUL(WASM_LOCAL_GET(1), WASM_LOCAL_GET(0)))));
2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534

  uint32_t test_values[] = {1, 2, 5, 10, 20, 2000};

  for (uint32_t v : test_values) {
    CHECK_EQ(factorial(v), r.Call(v));
  }
}

// Indirect variant of factorial. Pass the function ID as an argument:
// fact(N) => f(N,1,f).
//
// f(N,X,_) where N=<1 => X
// f(N,X,F) => F(N-1,X*N,F).

2535
UNINITIALIZED_WASM_EXEC_TEST(ReturnCall_IndirectFactorial) {
2536 2537 2538 2539
  EXPERIMENTAL_FLAG_SCOPE(return_call);
  // Run in bounded amount of stack - 8kb.
  FlagScope<int32_t> stack_size(&v8::internal::FLAG_stack_size, 8);

2540 2541 2542 2543
  IsolateScope isolate_scope;
  LocalContext current(isolate_scope.isolate());

  WasmRunner<uint32_t, uint32_t> r(execution_tier, nullptr, "main",
2544
                                   kRuntimeExceptionSupport, kMemory32,
2545
                                   isolate_scope.i_isolate());
2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561

  TestSignatures sigs;

  WasmFunctionCompiler& f_ind_fn = r.NewFunction(sigs.i_iii(), "f_ind");
  uint32_t sig_index = r.builder().AddSignature(sigs.i_iii());
  f_ind_fn.SetSigIndex(sig_index);

  // Function table.
  uint16_t indirect_function_table[] = {
      static_cast<uint16_t>(f_ind_fn.function_index())};
  const int f_ind_index = 0;

  r.builder().AddIndirectFunctionTable(indirect_function_table,
                                       arraysize(indirect_function_table));

  BUILD(r,
2562
        WASM_RETURN_CALL_FUNCTION(f_ind_fn.function_index(), WASM_LOCAL_GET(0),
2563 2564 2565
                                  WASM_I32V(1), WASM_I32V(f_ind_index)));

  BUILD(f_ind_fn,
2566
        WASM_IF_ELSE_I(
2567
            WASM_I32_LES(WASM_LOCAL_GET(0), WASM_I32V(1)), WASM_LOCAL_GET(1),
2568
            WASM_RETURN_CALL_INDIRECT(
2569 2570 2571
                sig_index, WASM_I32_SUB(WASM_LOCAL_GET(0), WASM_I32V(1)),
                WASM_I32_MUL(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)),
                WASM_LOCAL_GET(2), WASM_LOCAL_GET(2))));
2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583

  uint32_t test_values[] = {1, 2, 5, 10, 10000};

  for (uint32_t v : test_values) {
    CHECK_EQ(factorial(v), r.Call(v));
  }
}

// This is 'more stable' (does not degenerate so quickly) than factorial
// sum(N,k) where N<1 =>k.
// sum(N,k) => sum(N-1,k+N).

2584
UNINITIALIZED_WASM_EXEC_TEST(ReturnCall_Sum) {
2585 2586 2587 2588
  EXPERIMENTAL_FLAG_SCOPE(return_call);
  // Run in bounded amount of stack - 8kb.
  FlagScope<int32_t> stack_size(&v8::internal::FLAG_stack_size, 8);

2589 2590 2591 2592
  IsolateScope isolate_scope;
  LocalContext current(isolate_scope.isolate());

  WasmRunner<int32_t, int32_t> r(execution_tier, nullptr, "main",
2593
                                 kRuntimeExceptionSupport, kMemory32,
2594
                                 isolate_scope.i_isolate());
2595 2596 2597 2598
  TestSignatures sigs;

  WasmFunctionCompiler& sum_aux_fn = r.NewFunction(sigs.i_ii(), "sum_aux");
  BUILD(r, WASM_RETURN_CALL_FUNCTION(sum_aux_fn.function_index(),
2599
                                     WASM_LOCAL_GET(0), WASM_I32V(0)));
2600 2601 2602

  BUILD(sum_aux_fn,
        WASM_IF_ELSE_I(
2603
            WASM_I32_LTS(WASM_LOCAL_GET(0), WASM_I32V(1)), WASM_LOCAL_GET(1),
2604 2605
            WASM_RETURN_CALL_FUNCTION(
                sum_aux_fn.function_index(),
2606 2607
                WASM_I32_SUB(WASM_LOCAL_GET(0), WASM_I32V(1)),
                WASM_I32_ADD(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)))));
2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625

  int32_t test_values[] = {1, 2, 5, 10, 1000};

  for (int32_t v : test_values) {
    CHECK_EQ(sum_1_to_n(v), r.Call(v));
  }
}

// 'Bouncing' mutual recursive sum with different #s of arguments
// b1(N,k) where N<1 =>k.
// b1(N,k) => b2(N-1,N,k+N).

// b2(N,_,k) where N<1 =>k.
// b2(N,l,k) => b3(N-1,N,l,k+N).

// b3(N,_,_,k) where N<1 =>k.
// b3(N,_,_,k) => b1(N-1,k+N).

2626
UNINITIALIZED_WASM_EXEC_TEST(ReturnCall_Bounce_Sum) {
2627 2628 2629 2630
  EXPERIMENTAL_FLAG_SCOPE(return_call);
  // Run in bounded amount of stack - 8kb.
  FlagScope<int32_t> stack_size(&v8::internal::FLAG_stack_size, 8);

2631 2632 2633 2634
  IsolateScope isolate_scope;
  LocalContext current(isolate_scope.isolate());

  WasmRunner<int32_t, int32_t> r(execution_tier, nullptr, "main",
2635
                                 kRuntimeExceptionSupport, kMemory32,
2636
                                 isolate_scope.i_isolate());
2637 2638 2639 2640 2641 2642 2643
  TestSignatures sigs;

  WasmFunctionCompiler& b1_fn = r.NewFunction(sigs.i_ii(), "b1");
  WasmFunctionCompiler& b2_fn = r.NewFunction(sigs.i_iii(), "b2");
  WasmFunctionCompiler& b3_fn =
      r.NewFunction<int32_t, int32_t, int32_t, int32_t, int32_t>("b3");

2644
  BUILD(r, WASM_RETURN_CALL_FUNCTION(b1_fn.function_index(), WASM_LOCAL_GET(0),
2645 2646 2647 2648 2649
                                     WASM_I32V(0)));

  BUILD(
      b1_fn,
      WASM_IF_ELSE_I(
2650
          WASM_I32_LTS(WASM_LOCAL_GET(0), WASM_I32V(1)), WASM_LOCAL_GET(1),
2651 2652
          WASM_RETURN_CALL_FUNCTION(
              b2_fn.function_index(),
2653 2654
              WASM_I32_SUB(WASM_LOCAL_GET(0), WASM_I32V(1)), WASM_LOCAL_GET(0),
              WASM_I32_ADD(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)))));
2655 2656 2657

  BUILD(b2_fn,
        WASM_IF_ELSE_I(
2658
            WASM_I32_LTS(WASM_LOCAL_GET(0), WASM_I32V(1)), WASM_LOCAL_GET(2),
2659 2660
            WASM_RETURN_CALL_FUNCTION(
                b3_fn.function_index(),
2661 2662 2663
                WASM_I32_SUB(WASM_LOCAL_GET(0), WASM_I32V(1)),
                WASM_LOCAL_GET(0), WASM_LOCAL_GET(1),
                WASM_I32_ADD(WASM_LOCAL_GET(0), WASM_LOCAL_GET(2)))));
2664 2665 2666

  BUILD(b3_fn,
        WASM_IF_ELSE_I(
2667
            WASM_I32_LTS(WASM_LOCAL_GET(0), WASM_I32V(1)), WASM_LOCAL_GET(3),
2668 2669
            WASM_RETURN_CALL_FUNCTION(
                b1_fn.function_index(),
2670 2671
                WASM_I32_SUB(WASM_LOCAL_GET(0), WASM_I32V(1)),
                WASM_I32_ADD(WASM_LOCAL_GET(0), WASM_LOCAL_GET(3)))));
2672 2673 2674 2675 2676 2677 2678 2679

  int32_t test_values[] = {1, 2, 5, 10, 1000};

  for (int32_t v : test_values) {
    CHECK_EQ(sum_1_to_n(v), r.Call(v));
  }
}

2680 2681 2682
#define ADD_CODE(vec, ...)                                              \
  do {                                                                  \
    byte __buf[] = {__VA_ARGS__};                                       \
2683
    for (size_t i = 0; i < sizeof(__buf); ++i) vec.push_back(__buf[i]); \
2684 2685
  } while (false)

2686
static void Run_WasmMixedCall_N(TestExecutionTier execution_tier, int start) {
2687 2688 2689 2690
  const int kExpected = 6333;
  const int kElemSize = 8;
  TestSignatures sigs;

2691
  // 64-bit cases handled in test-run-wasm-64.cc.
2692 2693 2694 2695 2696 2697 2698
  static MachineType mixed[] = {
      MachineType::Int32(),   MachineType::Float32(), MachineType::Float64(),
      MachineType::Float32(), MachineType::Int32(),   MachineType::Float64(),
      MachineType::Float32(), MachineType::Float64(), MachineType::Int32(),
      MachineType::Int32(),   MachineType::Int32()};

  int num_params = static_cast<int>(arraysize(mixed)) - start;
2699
  for (int which = 0; which < num_params; ++which) {
2700
    v8::internal::AccountingAllocator allocator;
2701
    Zone zone(&allocator, ZONE_NAME);
2702
    WasmRunner<int32_t> r(execution_tier);
2703
    r.builder().AddMemory(kWasmPageSize);
2704 2705 2706 2707 2708 2709 2710
    MachineType* memtypes = &mixed[start];
    MachineType result = memtypes[which];

    // =========================================================================
    // Build the selector function.
    // =========================================================================
    FunctionSig::Builder b(&zone, 1, num_params);
2711
    b.AddReturn(ValueType::For(result));
2712
    for (int i = 0; i < num_params; ++i) {
2713
      b.AddParam(ValueType::For(memtypes[i]));
2714
    }
2715
    WasmFunctionCompiler& t = r.NewFunction(b.Build());
2716
    BUILD(t, WASM_LOCAL_GET(which));
2717 2718 2719 2720

    // =========================================================================
    // Build the calling function.
    // =========================================================================
2721
    std::vector<byte> code;
2722 2723

    // Load the arguments.
2724
    for (int i = 0; i < num_params; ++i) {
2725
      int offset = (i + 1) * kElemSize;
2726
      ADD_CODE(code, WASM_LOAD_MEM(memtypes[i], WASM_I32V_2(offset)));
2727 2728
    }

2729
    // Call the selector function.
2730
    ADD_CODE(code, WASM_CALL_FUNCTION0(t.function_index()));
2731

2732
    // Store the result in a local.
2733
    byte local_index = r.AllocateLocal(ValueType::For(result));
2734
    ADD_CODE(code, kExprLocalSet, local_index);
2735

2736
    // Store the result in memory.
2737
    ADD_CODE(code,
2738
             WASM_STORE_MEM(result, WASM_ZERO, WASM_LOCAL_GET(local_index)));
2739 2740

    // Return the expected value.
2741
    ADD_CODE(code, WASM_I32V_2(kExpected));
2742 2743

    r.Build(&code[0], &code[0] + code.size());
2744

2745
    // Run the code.
2746
    for (int t = 0; t < 10; ++t) {
2747
      r.builder().RandomizeMemory();
2748 2749
      CHECK_EQ(kExpected, r.Call());

2750
      int size = result.MemSize();
2751
      for (int i = 0; i < size; ++i) {
2752
        int base = (which + 1) * kElemSize;
2753 2754
        byte expected = r.builder().raw_mem_at<byte>(base + i);
        byte result = r.builder().raw_mem_at<byte>(i);
2755 2756 2757 2758 2759 2760
        CHECK_EQ(expected, result);
      }
    }
  }
}

2761 2762 2763 2764
WASM_EXEC_TEST(MixedCall_0) { Run_WasmMixedCall_N(execution_tier, 0); }
WASM_EXEC_TEST(MixedCall_1) { Run_WasmMixedCall_N(execution_tier, 1); }
WASM_EXEC_TEST(MixedCall_2) { Run_WasmMixedCall_N(execution_tier, 2); }
WASM_EXEC_TEST(MixedCall_3) { Run_WasmMixedCall_N(execution_tier, 3); }
2765

2766
WASM_EXEC_TEST(AddCall) {
2767
  WasmRunner<int32_t, int32_t> r(execution_tier);
2768
  WasmFunctionCompiler& t1 = r.NewFunction<int32_t, int32_t, int32_t>();
2769
  BUILD(t1, WASM_I32_ADD(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)));
2770

2771
  byte local = r.AllocateLocal(kWasmI32);
2772
  BUILD(r, WASM_LOCAL_SET(local, WASM_I32V_2(99)),
2773
        WASM_I32_ADD(
2774 2775 2776 2777
            WASM_CALL_FUNCTION(t1.function_index(), WASM_LOCAL_GET(0),
                               WASM_LOCAL_GET(0)),
            WASM_CALL_FUNCTION(t1.function_index(), WASM_LOCAL_GET(local),
                               WASM_LOCAL_GET(local))));
2778 2779 2780 2781 2782

  CHECK_EQ(198, r.Call(0));
  CHECK_EQ(200, r.Call(1));
  CHECK_EQ(100, r.Call(-49));
}
2783

2784
WASM_EXEC_TEST(MultiReturnSub) {
2785
  WasmRunner<int32_t, int32_t, int32_t> r(execution_tier);
2786

2787
  ValueType storage[] = {kWasmI32, kWasmI32, kWasmI32, kWasmI32};
2788
  FunctionSig sig_ii_ii(2, 2, storage);
2789
  WasmFunctionCompiler& t1 = r.NewFunction(&sig_ii_ii);
2790
  BUILD(t1, WASM_LOCAL_GET(1), WASM_LOCAL_GET(0));
2791

2792
  BUILD(r, WASM_LOCAL_GET(0), WASM_LOCAL_GET(1),
2793
        WASM_CALL_FUNCTION0(t1.function_index()), kExprI32Sub);
2794 2795 2796

  FOR_INT32_INPUTS(i) {
    FOR_INT32_INPUTS(j) {
2797 2798 2799
      int32_t expected = static_cast<int32_t>(static_cast<uint32_t>(j) -
                                              static_cast<uint32_t>(i));
      CHECK_EQ(expected, r.Call(i, j));
2800 2801 2802 2803 2804
    }
  }
}

template <typename T>
2805
void RunMultiReturnSelect(TestExecutionTier execution_tier, const T* inputs) {
2806
  ValueType type = ValueType::For(MachineTypeForC<T>());
2807
  ValueType storage[] = {type, type, type, type, type, type};
2808 2809 2810 2811 2812 2813 2814
  const size_t kNumReturns = 2;
  const size_t kNumParams = arraysize(storage) - kNumReturns;
  FunctionSig sig(kNumReturns, kNumParams, storage);

  for (size_t i = 0; i < kNumParams; i++) {
    for (size_t j = 0; j < kNumParams; j++) {
      for (int k = 0; k < 2; k++) {
2815
        WasmRunner<T, T, T, T, T> r(execution_tier);
2816
        WasmFunctionCompiler& r1 = r.NewFunction(&sig);
2817

2818
        BUILD(r1, WASM_LOCAL_GET(i), WASM_LOCAL_GET(j));
2819 2820

        if (k == 0) {
2821 2822 2823 2824
          BUILD(r,
                WASM_CALL_FUNCTION(r1.function_index(), WASM_LOCAL_GET(0),
                                   WASM_LOCAL_GET(1), WASM_LOCAL_GET(2),
                                   WASM_LOCAL_GET(3)),
2825 2826
                WASM_DROP);
        } else {
2827
          BUILD(r,
2828 2829 2830 2831
                WASM_CALL_FUNCTION(r1.function_index(), WASM_LOCAL_GET(0),
                                   WASM_LOCAL_GET(1), WASM_LOCAL_GET(2),
                                   WASM_LOCAL_GET(3)),
                kExprLocalSet, 0, WASM_DROP, WASM_LOCAL_GET(0));
2832 2833 2834
        }

        T expected = inputs[k == 0 ? i : j];
2835
        CHECK_EQ(expected, r.Call(inputs[0], inputs[1], inputs[2], inputs[3]));
2836 2837 2838 2839 2840 2841 2842
      }
    }
  }
}

WASM_EXEC_TEST(MultiReturnSelect_i32) {
  static const int32_t inputs[] = {3333333, 4444444, -55555555, -7777777};
2843
  RunMultiReturnSelect<int32_t>(execution_tier, inputs);
2844 2845 2846 2847
}

WASM_EXEC_TEST(MultiReturnSelect_f32) {
  static const float inputs[] = {33.33333f, 444.4444f, -55555.555f, -77777.77f};
2848
  RunMultiReturnSelect<float>(execution_tier, inputs);
2849 2850 2851 2852 2853 2854 2855
}

WASM_EXEC_TEST(MultiReturnSelect_i64) {
#if !V8_TARGET_ARCH_32_BIT || V8_TARGET_ARCH_X64
  // TODO(titzer): implement int64-lowering for multiple return values
  static const int64_t inputs[] = {33333338888, 44444446666, -555555553333,
                                   -77777771111};
2856
  RunMultiReturnSelect<int64_t>(execution_tier, inputs);
2857 2858 2859 2860 2861
#endif
}

WASM_EXEC_TEST(MultiReturnSelect_f64) {
  static const double inputs[] = {3.333333, 44444.44, -55.555555, -7777.777};
2862
  RunMultiReturnSelect<double>(execution_tier, inputs);
2863 2864
}

2865
WASM_EXEC_TEST(ExprBlock2a) {
2866
  WasmRunner<int32_t, int32_t> r(execution_tier);
2867
  BUILD(r, WASM_BLOCK_I(WASM_IF(WASM_LOCAL_GET(0), WASM_BRV(1, WASM_I32V_1(1))),
2868
                        WASM_I32V_1(1)));
2869 2870 2871 2872
  CHECK_EQ(1, r.Call(0));
  CHECK_EQ(1, r.Call(1));
}

2873
WASM_EXEC_TEST(ExprBlock2b) {
2874
  WasmRunner<int32_t, int32_t> r(execution_tier);
2875
  BUILD(r, WASM_BLOCK_I(WASM_IF(WASM_LOCAL_GET(0), WASM_BRV(1, WASM_I32V_1(1))),
2876
                        WASM_I32V_1(2)));
2877 2878 2879 2880
  CHECK_EQ(2, r.Call(0));
  CHECK_EQ(1, r.Call(1));
}

2881
WASM_EXEC_TEST(ExprBlock2c) {
2882
  WasmRunner<int32_t, int32_t> r(execution_tier);
2883
  BUILD(r, WASM_BLOCK_I(WASM_BRV_IFD(0, WASM_I32V_1(1), WASM_LOCAL_GET(0)),
2884
                        WASM_I32V_1(1)));
2885 2886 2887 2888
  CHECK_EQ(1, r.Call(0));
  CHECK_EQ(1, r.Call(1));
}

2889
WASM_EXEC_TEST(ExprBlock2d) {
2890
  WasmRunner<int32_t, int32_t> r(execution_tier);
2891
  BUILD(r, WASM_BLOCK_I(WASM_BRV_IFD(0, WASM_I32V_1(1), WASM_LOCAL_GET(0)),
2892
                        WASM_I32V_1(2)));
2893 2894 2895 2896
  CHECK_EQ(2, r.Call(0));
  CHECK_EQ(1, r.Call(1));
}

2897
WASM_EXEC_TEST(ExprBlock_ManualSwitch) {
2898
  WasmRunner<int32_t, int32_t> r(execution_tier);
2899
  BUILD(r, WASM_BLOCK_I(WASM_IF(WASM_I32_EQ(WASM_LOCAL_GET(0), WASM_I32V_1(1)),
2900
                                WASM_BRV(1, WASM_I32V_1(11))),
2901
                        WASM_IF(WASM_I32_EQ(WASM_LOCAL_GET(0), WASM_I32V_1(2)),
2902
                                WASM_BRV(1, WASM_I32V_1(12))),
2903
                        WASM_IF(WASM_I32_EQ(WASM_LOCAL_GET(0), WASM_I32V_1(3)),
2904
                                WASM_BRV(1, WASM_I32V_1(13))),
2905
                        WASM_IF(WASM_I32_EQ(WASM_LOCAL_GET(0), WASM_I32V_1(4)),
2906
                                WASM_BRV(1, WASM_I32V_1(14))),
2907
                        WASM_IF(WASM_I32_EQ(WASM_LOCAL_GET(0), WASM_I32V_1(5)),
2908 2909
                                WASM_BRV(1, WASM_I32V_1(15))),
                        WASM_I32V_2(99)));
2910 2911 2912 2913 2914 2915 2916 2917 2918
  CHECK_EQ(99, r.Call(0));
  CHECK_EQ(11, r.Call(1));
  CHECK_EQ(12, r.Call(2));
  CHECK_EQ(13, r.Call(3));
  CHECK_EQ(14, r.Call(4));
  CHECK_EQ(15, r.Call(5));
  CHECK_EQ(99, r.Call(6));
}

2919
WASM_EXEC_TEST(ExprBlock_ManualSwitch_brif) {
2920
  WasmRunner<int32_t, int32_t> r(execution_tier);
2921 2922
  BUILD(r, WASM_BLOCK_I(
               WASM_BRV_IFD(0, WASM_I32V_1(11),
2923
                            WASM_I32_EQ(WASM_LOCAL_GET(0), WASM_I32V_1(1))),
2924
               WASM_BRV_IFD(0, WASM_I32V_1(12),
2925
                            WASM_I32_EQ(WASM_LOCAL_GET(0), WASM_I32V_1(2))),
2926
               WASM_BRV_IFD(0, WASM_I32V_1(13),
2927
                            WASM_I32_EQ(WASM_LOCAL_GET(0), WASM_I32V_1(3))),
2928
               WASM_BRV_IFD(0, WASM_I32V_1(14),
2929
                            WASM_I32_EQ(WASM_LOCAL_GET(0), WASM_I32V_1(4))),
2930
               WASM_BRV_IFD(0, WASM_I32V_1(15),
2931
                            WASM_I32_EQ(WASM_LOCAL_GET(0), WASM_I32V_1(5))),
2932
               WASM_I32V_2(99)));
2933 2934 2935 2936 2937 2938 2939 2940 2941
  CHECK_EQ(99, r.Call(0));
  CHECK_EQ(11, r.Call(1));
  CHECK_EQ(12, r.Call(2));
  CHECK_EQ(13, r.Call(3));
  CHECK_EQ(14, r.Call(4));
  CHECK_EQ(15, r.Call(5));
  CHECK_EQ(99, r.Call(6));
}

2942
WASM_EXEC_TEST(If_nested) {
2943
  WasmRunner<int32_t, int32_t, int32_t> r(execution_tier);
2944

2945 2946 2947
  BUILD(
      r,
      WASM_IF_ELSE_I(
2948 2949 2950
          WASM_LOCAL_GET(0),
          WASM_IF_ELSE_I(WASM_LOCAL_GET(1), WASM_I32V_1(11), WASM_I32V_1(12)),
          WASM_IF_ELSE_I(WASM_LOCAL_GET(1), WASM_I32V_1(13), WASM_I32V_1(14))));
2951 2952 2953 2954 2955 2956 2957

  CHECK_EQ(11, r.Call(1, 1));
  CHECK_EQ(12, r.Call(1, 0));
  CHECK_EQ(13, r.Call(0, 1));
  CHECK_EQ(14, r.Call(0, 0));
}

2958
WASM_EXEC_TEST(ExprBlock_if) {
2959
  WasmRunner<int32_t, int32_t> r(execution_tier);
2960

2961
  BUILD(r, WASM_BLOCK_I(WASM_IF_ELSE_I(WASM_LOCAL_GET(0),
2962 2963
                                       WASM_BRV(0, WASM_I32V_1(11)),
                                       WASM_BRV(1, WASM_I32V_1(14)))));
2964 2965 2966 2967 2968

  CHECK_EQ(11, r.Call(1));
  CHECK_EQ(14, r.Call(0));
}

2969
WASM_EXEC_TEST(ExprBlock_nested_ifs) {
2970
  WasmRunner<int32_t, int32_t, int32_t> r(execution_tier);
2971

2972
  BUILD(r, WASM_BLOCK_I(WASM_IF_ELSE_I(
2973 2974
               WASM_LOCAL_GET(0),
               WASM_IF_ELSE_I(WASM_LOCAL_GET(1), WASM_BRV(0, WASM_I32V_1(11)),
2975
                              WASM_BRV(1, WASM_I32V_1(12))),
2976
               WASM_IF_ELSE_I(WASM_LOCAL_GET(1), WASM_BRV(0, WASM_I32V_1(13)),
2977
                              WASM_BRV(1, WASM_I32V_1(14))))));
2978 2979 2980 2981 2982 2983 2984

  CHECK_EQ(11, r.Call(1, 1));
  CHECK_EQ(12, r.Call(1, 0));
  CHECK_EQ(13, r.Call(0, 1));
  CHECK_EQ(14, r.Call(0, 0));
}

2985
WASM_EXEC_TEST(SimpleCallIndirect) {
2986
  TestSignatures sigs;
2987
  WasmRunner<int32_t, int32_t> r(execution_tier);
2988

2989
  WasmFunctionCompiler& t1 = r.NewFunction(sigs.i_ii());
2990
  BUILD(t1, WASM_I32_ADD(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)));
2991
  t1.SetSigIndex(1);
2992

2993
  WasmFunctionCompiler& t2 = r.NewFunction(sigs.i_ii());
2994
  BUILD(t2, WASM_I32_SUB(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)));
2995
  t2.SetSigIndex(1);
2996 2997

  // Signature table.
2998 2999 3000
  r.builder().AddSignature(sigs.f_ff());
  r.builder().AddSignature(sigs.i_ii());
  r.builder().AddSignature(sigs.d_dd());
3001 3002

  // Function table.
3003 3004 3005
  uint16_t indirect_function_table[] = {
      static_cast<uint16_t>(t1.function_index()),
      static_cast<uint16_t>(t2.function_index())};
3006 3007
  r.builder().AddIndirectFunctionTable(indirect_function_table,
                                       arraysize(indirect_function_table));
3008

3009
  // Build the caller function.
3010
  BUILD(r, WASM_CALL_INDIRECT(1, WASM_I32V_2(66), WASM_I32V_1(22),
3011
                              WASM_LOCAL_GET(0)));
3012 3013 3014 3015 3016 3017

  CHECK_EQ(88, r.Call(0));
  CHECK_EQ(44, r.Call(1));
  CHECK_TRAP(r.Call(2));
}

3018
WASM_EXEC_TEST(MultipleCallIndirect) {
3019
  TestSignatures sigs;
3020
  WasmRunner<int32_t, int32_t, int32_t, int32_t> r(execution_tier);
3021

3022
  WasmFunctionCompiler& t1 = r.NewFunction(sigs.i_ii());
3023
  BUILD(t1, WASM_I32_ADD(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)));
3024
  t1.SetSigIndex(1);
3025

3026
  WasmFunctionCompiler& t2 = r.NewFunction(sigs.i_ii());
3027
  BUILD(t2, WASM_I32_SUB(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)));
3028
  t2.SetSigIndex(1);
3029 3030

  // Signature table.
3031 3032 3033
  r.builder().AddSignature(sigs.f_ff());
  r.builder().AddSignature(sigs.i_ii());
  r.builder().AddSignature(sigs.d_dd());
3034 3035

  // Function table.
3036 3037 3038
  uint16_t indirect_function_table[] = {
      static_cast<uint16_t>(t1.function_index()),
      static_cast<uint16_t>(t2.function_index())};
3039 3040
  r.builder().AddIndirectFunctionTable(indirect_function_table,
                                       arraysize(indirect_function_table));
3041 3042

  // Build the caller function.
3043
  BUILD(r,
3044 3045 3046 3047
        WASM_I32_ADD(WASM_CALL_INDIRECT(1, WASM_LOCAL_GET(1), WASM_LOCAL_GET(2),
                                        WASM_LOCAL_GET(0)),
                     WASM_CALL_INDIRECT(1, WASM_LOCAL_GET(2), WASM_LOCAL_GET(0),
                                        WASM_LOCAL_GET(1))));
3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059

  CHECK_EQ(5, r.Call(0, 1, 2));
  CHECK_EQ(19, r.Call(0, 1, 9));
  CHECK_EQ(1, r.Call(1, 0, 2));
  CHECK_EQ(1, r.Call(1, 0, 9));

  CHECK_TRAP(r.Call(0, 2, 1));
  CHECK_TRAP(r.Call(1, 2, 0));
  CHECK_TRAP(r.Call(2, 0, 1));
  CHECK_TRAP(r.Call(2, 1, 0));
}

3060
WASM_EXEC_TEST(CallIndirect_EmptyTable) {
3061
  TestSignatures sigs;
3062
  WasmRunner<int32_t, int32_t> r(execution_tier);
3063 3064

  // One function.
3065
  WasmFunctionCompiler& t1 = r.NewFunction(sigs.i_ii());
3066
  BUILD(t1, WASM_I32_ADD(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)));
3067
  t1.SetSigIndex(1);
3068 3069

  // Signature table.
3070 3071 3072
  r.builder().AddSignature(sigs.f_ff());
  r.builder().AddSignature(sigs.i_ii());
  r.builder().AddIndirectFunctionTable(nullptr, 0);
3073

3074
  // Build the caller function.
3075
  BUILD(r, WASM_CALL_INDIRECT(1, WASM_I32V_2(66), WASM_I32V_1(22),
3076
                              WASM_LOCAL_GET(0)));
3077 3078 3079 3080 3081 3082

  CHECK_TRAP(r.Call(0));
  CHECK_TRAP(r.Call(1));
  CHECK_TRAP(r.Call(2));
}

3083
WASM_EXEC_TEST(CallIndirect_canonical) {
3084
  TestSignatures sigs;
3085
  WasmRunner<int32_t, int32_t> r(execution_tier);
3086

3087
  WasmFunctionCompiler& t1 = r.NewFunction(sigs.i_ii());
3088
  BUILD(t1, WASM_I32_ADD(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)));
3089
  t1.SetSigIndex(0);
3090

3091
  WasmFunctionCompiler& t2 = r.NewFunction(sigs.i_ii());
3092
  BUILD(t2, WASM_I32_SUB(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)));
3093
  t2.SetSigIndex(1);
3094

3095
  WasmFunctionCompiler& t3 = r.NewFunction(sigs.f_ff());
3096
  BUILD(t3, WASM_F32_SUB(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)));
3097
  t3.SetSigIndex(2);
3098 3099

  // Signature table.
3100 3101 3102
  r.builder().AddSignature(sigs.i_ii());
  r.builder().AddSignature(sigs.i_ii());
  r.builder().AddSignature(sigs.f_ff());
3103 3104 3105 3106 3107 3108 3109

  // Function table.
  uint16_t i1 = static_cast<uint16_t>(t1.function_index());
  uint16_t i2 = static_cast<uint16_t>(t2.function_index());
  uint16_t i3 = static_cast<uint16_t>(t3.function_index());
  uint16_t indirect_function_table[] = {i1, i2, i3, i1, i2};

3110 3111
  r.builder().AddIndirectFunctionTable(indirect_function_table,
                                       arraysize(indirect_function_table));
3112

3113
  // Build the caller function.
3114
  BUILD(r, WASM_CALL_INDIRECT(1, WASM_I32V_2(77), WASM_I32V_1(11),
3115
                              WASM_LOCAL_GET(0)));
3116 3117 3118 3119 3120 3121 3122 3123 3124

  CHECK_EQ(88, r.Call(0));
  CHECK_EQ(66, r.Call(1));
  CHECK_TRAP(r.Call(2));
  CHECK_EQ(88, r.Call(3));
  CHECK_EQ(66, r.Call(4));
  CHECK_TRAP(r.Call(5));
}

3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164
WASM_EXEC_TEST(Regress_PushReturns) {
  ValueType kSigTypes[] = {kWasmI32, kWasmI32, kWasmI32, kWasmI32,
                           kWasmI32, kWasmI32, kWasmI32, kWasmI32,
                           kWasmI32, kWasmI32, kWasmI32, kWasmI32};
  FunctionSig sig(12, 0, kSigTypes);
  WasmRunner<int32_t> r(execution_tier);

  WasmFunctionCompiler& f1 = r.NewFunction(&sig);
  BUILD(f1, WASM_I32V(1), WASM_I32V(2), WASM_I32V(3), WASM_I32V(4),
        WASM_I32V(5), WASM_I32V(6), WASM_I32V(7), WASM_I32V(8), WASM_I32V(9),
        WASM_I32V(10), WASM_I32V(11), WASM_I32V(12));

  BUILD(r, WASM_CALL_FUNCTION0(f1.function_index()), WASM_DROP, WASM_DROP,
        WASM_DROP, WASM_DROP, WASM_DROP, WASM_DROP, WASM_DROP, WASM_DROP,
        WASM_DROP, WASM_DROP, WASM_DROP);
  CHECK_EQ(1, r.Call());
}

WASM_EXEC_TEST(Regress_EnsureArguments) {
  ValueType kSigTypes[] = {kWasmI32, kWasmI32, kWasmI32, kWasmI32,
                           kWasmI32, kWasmI32, kWasmI32, kWasmI32,
                           kWasmI32, kWasmI32, kWasmI32, kWasmI32};
  FunctionSig sig(0, 12, kSigTypes);
  WasmRunner<int32_t> r(execution_tier);

  WasmFunctionCompiler& f2 = r.NewFunction(&sig);
  BUILD(f2, kExprReturn);

  BUILD(r, WASM_I32V(42), kExprReturn,
        WASM_CALL_FUNCTION(f2.function_index(), WASM_I32V(1)));
  CHECK_EQ(42, r.Call());
}

WASM_EXEC_TEST(Regress_PushControl) {
  WasmRunner<int32_t> r(execution_tier);
  BUILD(r, WASM_I32V(42),
        WASM_IF(WASM_I32V(0), WASM_UNREACHABLE, kExprIf, kVoidCode, kExprEnd));
  CHECK_EQ(42, r.Call());
}

3165
WASM_EXEC_TEST(F32Floor) {
3166
  WasmRunner<float, float> r(execution_tier);
3167
  BUILD(r, WASM_F32_FLOOR(WASM_LOCAL_GET(0)));
3168

3169
  FOR_FLOAT32_INPUTS(i) { CHECK_FLOAT_EQ(floorf(i), r.Call(i)); }
3170 3171
}

3172
WASM_EXEC_TEST(F32Ceil) {
3173
  WasmRunner<float, float> r(execution_tier);
3174
  BUILD(r, WASM_F32_CEIL(WASM_LOCAL_GET(0)));
3175

3176
  FOR_FLOAT32_INPUTS(i) { CHECK_FLOAT_EQ(ceilf(i), r.Call(i)); }
3177 3178
}

3179
WASM_EXEC_TEST(F32Trunc) {
3180
  WasmRunner<float, float> r(execution_tier);
3181
  BUILD(r, WASM_F32_TRUNC(WASM_LOCAL_GET(0)));
3182

3183
  FOR_FLOAT32_INPUTS(i) { CHECK_FLOAT_EQ(truncf(i), r.Call(i)); }
3184
}
3185

3186
WASM_EXEC_TEST(F32NearestInt) {
3187
  WasmRunner<float, float> r(execution_tier);
3188
  BUILD(r, WASM_F32_NEARESTINT(WASM_LOCAL_GET(0)));
3189

3190
  FOR_FLOAT32_INPUTS(i) { CHECK_FLOAT_EQ(nearbyintf(i), r.Call(i)); }
3191 3192
}

3193
WASM_EXEC_TEST(F64Floor) {
3194
  WasmRunner<double, double> r(execution_tier);
3195
  BUILD(r, WASM_F64_FLOOR(WASM_LOCAL_GET(0)));
3196

3197
  FOR_FLOAT64_INPUTS(i) { CHECK_DOUBLE_EQ(floor(i), r.Call(i)); }
3198 3199
}

3200
WASM_EXEC_TEST(F64Ceil) {
3201
  WasmRunner<double, double> r(execution_tier);
3202
  BUILD(r, WASM_F64_CEIL(WASM_LOCAL_GET(0)));
3203

3204
  FOR_FLOAT64_INPUTS(i) { CHECK_DOUBLE_EQ(ceil(i), r.Call(i)); }
3205 3206
}

3207
WASM_EXEC_TEST(F64Trunc) {
3208
  WasmRunner<double, double> r(execution_tier);
3209
  BUILD(r, WASM_F64_TRUNC(WASM_LOCAL_GET(0)));
3210

3211
  FOR_FLOAT64_INPUTS(i) { CHECK_DOUBLE_EQ(trunc(i), r.Call(i)); }
3212 3213
}

3214
WASM_EXEC_TEST(F64NearestInt) {
3215
  WasmRunner<double, double> r(execution_tier);
3216
  BUILD(r, WASM_F64_NEARESTINT(WASM_LOCAL_GET(0)));
3217

3218
  FOR_FLOAT64_INPUTS(i) { CHECK_DOUBLE_EQ(nearbyint(i), r.Call(i)); }
3219
}
3220

3221
WASM_EXEC_TEST(F32Min) {
3222
  WasmRunner<float, float, float> r(execution_tier);
3223
  BUILD(r, WASM_F32_MIN(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)));
3224 3225

  FOR_FLOAT32_INPUTS(i) {
3226
    FOR_FLOAT32_INPUTS(j) { CHECK_DOUBLE_EQ(JSMin(i, j), r.Call(i, j)); }
3227 3228 3229
  }
}

3230 3231
WASM_EXEC_TEST(F32MinSameValue) {
  WasmRunner<float, float> r(execution_tier);
3232
  BUILD(r, WASM_F32_MIN(WASM_LOCAL_GET(0), WASM_LOCAL_GET(0)));
3233 3234 3235 3236
  float result = r.Call(5.0f);
  CHECK_FLOAT_EQ(5.0f, result);
}

3237
WASM_EXEC_TEST(F64Min) {
3238
  WasmRunner<double, double, double> r(execution_tier);
3239
  BUILD(r, WASM_F64_MIN(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)));
3240 3241

  FOR_FLOAT64_INPUTS(i) {
3242
    FOR_FLOAT64_INPUTS(j) { CHECK_DOUBLE_EQ(JSMin(i, j), r.Call(i, j)); }
3243 3244 3245
  }
}

3246 3247
WASM_EXEC_TEST(F64MinSameValue) {
  WasmRunner<double, double> r(execution_tier);
3248
  BUILD(r, WASM_F64_MIN(WASM_LOCAL_GET(0), WASM_LOCAL_GET(0)));
3249 3250 3251 3252
  double result = r.Call(5.0);
  CHECK_DOUBLE_EQ(5.0, result);
}

3253
WASM_EXEC_TEST(F32Max) {
3254
  WasmRunner<float, float, float> r(execution_tier);
3255
  BUILD(r, WASM_F32_MAX(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)));
3256 3257

  FOR_FLOAT32_INPUTS(i) {
3258
    FOR_FLOAT32_INPUTS(j) { CHECK_FLOAT_EQ(JSMax(i, j), r.Call(i, j)); }
3259 3260 3261
  }
}

3262 3263
WASM_EXEC_TEST(F32MaxSameValue) {
  WasmRunner<float, float> r(execution_tier);
3264
  BUILD(r, WASM_F32_MAX(WASM_LOCAL_GET(0), WASM_LOCAL_GET(0)));
3265 3266 3267 3268
  float result = r.Call(5.0f);
  CHECK_FLOAT_EQ(5.0f, result);
}

3269
WASM_EXEC_TEST(F64Max) {
3270
  WasmRunner<double, double, double> r(execution_tier);
3271
  BUILD(r, WASM_F64_MAX(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)));
3272 3273 3274

  FOR_FLOAT64_INPUTS(i) {
    FOR_FLOAT64_INPUTS(j) {
3275 3276
      double result = r.Call(i, j);
      CHECK_DOUBLE_EQ(JSMax(i, j), result);
3277 3278 3279 3280
    }
  }
}

3281 3282
WASM_EXEC_TEST(F64MaxSameValue) {
  WasmRunner<double, double> r(execution_tier);
3283
  BUILD(r, WASM_F64_MAX(WASM_LOCAL_GET(0), WASM_LOCAL_GET(0)));
3284 3285 3286 3287
  double result = r.Call(5.0);
  CHECK_DOUBLE_EQ(5.0, result);
}

3288
WASM_EXEC_TEST(I32SConvertF32) {
3289
  WasmRunner<int32_t, float> r(execution_tier);
3290
  BUILD(r, WASM_I32_SCONVERT_F32(WASM_LOCAL_GET(0)));
3291 3292

  FOR_FLOAT32_INPUTS(i) {
3293 3294
    if (is_inbounds<int32_t>(i)) {
      CHECK_EQ(static_cast<int32_t>(i), r.Call(i));
3295
    } else {
3296
      CHECK_TRAP32(r.Call(i));
3297 3298 3299 3300
    }
  }
}

3301
WASM_EXEC_TEST(I32SConvertSatF32) {
3302
  WasmRunner<int32_t, float> r(execution_tier);
3303
  BUILD(r, WASM_I32_SCONVERT_SAT_F32(WASM_LOCAL_GET(0)));
3304 3305

  FOR_FLOAT32_INPUTS(i) {
3306
    int32_t expected =
3307 3308 3309 3310 3311 3312
        is_inbounds<int32_t>(i)
            ? static_cast<int32_t>(i)
            : std::isnan(i) ? 0
                            : i < 0.0 ? std::numeric_limits<int32_t>::min()
                                      : std::numeric_limits<int32_t>::max();
    int32_t found = r.Call(i);
3313
    CHECK_EQ(expected, found);
3314 3315 3316
  }
}

3317
WASM_EXEC_TEST(I32SConvertF64) {
3318
  WasmRunner<int32_t, double> r(execution_tier);
3319
  BUILD(r, WASM_I32_SCONVERT_F64(WASM_LOCAL_GET(0)));
3320 3321

  FOR_FLOAT64_INPUTS(i) {
3322 3323
    if (is_inbounds<int32_t>(i)) {
      CHECK_EQ(static_cast<int32_t>(i), r.Call(i));
3324
    } else {
3325
      CHECK_TRAP32(r.Call(i));
3326 3327 3328 3329
    }
  }
}

3330
WASM_EXEC_TEST(I32SConvertSatF64) {
3331
  WasmRunner<int32_t, double> r(execution_tier);
3332
  BUILD(r, WASM_I32_SCONVERT_SAT_F64(WASM_LOCAL_GET(0)));
3333 3334
  FOR_FLOAT64_INPUTS(i) {
    int32_t expected =
3335 3336 3337 3338 3339 3340
        is_inbounds<int32_t>(i)
            ? static_cast<int32_t>(i)
            : std::isnan(i) ? 0
                            : i < 0.0 ? std::numeric_limits<int32_t>::min()
                                      : std::numeric_limits<int32_t>::max();
    int32_t found = r.Call(i);
3341 3342 3343 3344
    CHECK_EQ(expected, found);
  }
}

3345
WASM_EXEC_TEST(I32UConvertF32) {
3346
  WasmRunner<uint32_t, float> r(execution_tier);
3347
  BUILD(r, WASM_I32_UCONVERT_F32(WASM_LOCAL_GET(0)));
3348
  FOR_FLOAT32_INPUTS(i) {
3349 3350
    if (is_inbounds<uint32_t>(i)) {
      CHECK_EQ(static_cast<uint32_t>(i), r.Call(i));
3351
    } else {
3352
      CHECK_TRAP32(r.Call(i));
3353 3354 3355 3356
    }
  }
}

3357
WASM_EXEC_TEST(I32UConvertSatF32) {
3358
  WasmRunner<uint32_t, float> r(execution_tier);
3359
  BUILD(r, WASM_I32_UCONVERT_SAT_F32(WASM_LOCAL_GET(0)));
3360 3361
  FOR_FLOAT32_INPUTS(i) {
    int32_t expected =
3362 3363 3364 3365 3366 3367
        is_inbounds<uint32_t>(i)
            ? static_cast<uint32_t>(i)
            : std::isnan(i) ? 0
                            : i < 0.0 ? std::numeric_limits<uint32_t>::min()
                                      : std::numeric_limits<uint32_t>::max();
    int32_t found = r.Call(i);
3368 3369 3370 3371
    CHECK_EQ(expected, found);
  }
}

3372
WASM_EXEC_TEST(I32UConvertF64) {
3373
  WasmRunner<uint32_t, double> r(execution_tier);
3374
  BUILD(r, WASM_I32_UCONVERT_F64(WASM_LOCAL_GET(0)));
3375
  FOR_FLOAT64_INPUTS(i) {
3376 3377
    if (is_inbounds<uint32_t>(i)) {
      CHECK_EQ(static_cast<uint32_t>(i), r.Call(i));
3378
    } else {
3379
      CHECK_TRAP32(r.Call(i));
3380 3381 3382 3383
    }
  }
}

3384
WASM_EXEC_TEST(I32UConvertSatF64) {
3385
  WasmRunner<uint32_t, double> r(execution_tier);
3386
  BUILD(r, WASM_I32_UCONVERT_SAT_F64(WASM_LOCAL_GET(0)));
3387 3388
  FOR_FLOAT64_INPUTS(i) {
    int32_t expected =
3389 3390 3391 3392 3393 3394
        is_inbounds<uint32_t>(i)
            ? static_cast<uint32_t>(i)
            : std::isnan(i) ? 0
                            : i < 0.0 ? std::numeric_limits<uint32_t>::min()
                                      : std::numeric_limits<uint32_t>::max();
    int32_t found = r.Call(i);
3395 3396 3397 3398
    CHECK_EQ(expected, found);
  }
}

3399
WASM_EXEC_TEST(F64CopySign) {
3400
  WasmRunner<double, double, double> r(execution_tier);
3401
  BUILD(r, WASM_F64_COPYSIGN(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)));
3402 3403

  FOR_FLOAT64_INPUTS(i) {
3404
    FOR_FLOAT64_INPUTS(j) { CHECK_DOUBLE_EQ(copysign(i, j), r.Call(i, j)); }
3405 3406 3407
  }
}

3408
WASM_EXEC_TEST(F32CopySign) {
3409
  WasmRunner<float, float, float> r(execution_tier);
3410
  BUILD(r, WASM_F32_COPYSIGN(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)));
3411 3412

  FOR_FLOAT32_INPUTS(i) {
3413
    FOR_FLOAT32_INPUTS(j) { CHECK_FLOAT_EQ(copysignf(i, j), r.Call(i, j)); }
3414 3415
  }
}
3416

3417
static void CompileCallIndirectMany(TestExecutionTier tier, ValueType param) {
3418 3419 3420
  // Make sure we don't run out of registers when compiling indirect calls
  // with many many parameters.
  TestSignatures sigs;
3421
  for (byte num_params = 0; num_params < 40; ++num_params) {
3422
    WasmRunner<void> r(tier);
3423
    FunctionSig* sig = sigs.many(r.zone(), kWasmVoid, param, num_params);
3424

3425 3426 3427
    r.builder().AddSignature(sig);
    r.builder().AddSignature(sig);
    r.builder().AddIndirectFunctionTable(nullptr, 0);
3428

3429
    WasmFunctionCompiler& t = r.NewFunction(sig);
3430 3431

    std::vector<byte> code;
3432
    for (byte p = 0; p < num_params; ++p) {
3433
      ADD_CODE(code, kExprLocalGet, p);
3434
    }
3435
    ADD_CODE(code, kExprI32Const, 0);
3436
    ADD_CODE(code, kExprCallIndirect, 1, TABLE_ZERO);
3437 3438 3439 3440 3441

    t.Build(&code[0], &code[0] + code.size());
  }
}

3442
WASM_COMPILED_EXEC_TEST(Compile_Wasm_CallIndirect_Many_i32) {
3443
  CompileCallIndirectMany(execution_tier, kWasmI32);
3444
}
3445

3446
WASM_COMPILED_EXEC_TEST(Compile_Wasm_CallIndirect_Many_f32) {
3447
  CompileCallIndirectMany(execution_tier, kWasmF32);
3448
}
3449

3450
WASM_COMPILED_EXEC_TEST(Compile_Wasm_CallIndirect_Many_f64) {
3451
  CompileCallIndirectMany(execution_tier, kWasmF64);
3452
}
3453

3454
WASM_EXEC_TEST(Int32RemS_dead) {
3455
  WasmRunner<int32_t, int32_t, int32_t> r(execution_tier);
3456
  BUILD(r, WASM_I32_REMS(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)), WASM_DROP,
3457
        WASM_ZERO);
3458 3459 3460 3461 3462 3463 3464 3465
  const int32_t kMin = std::numeric_limits<int32_t>::min();
  CHECK_EQ(0, r.Call(133, 100));
  CHECK_EQ(0, r.Call(kMin, -1));
  CHECK_EQ(0, r.Call(0, 1));
  CHECK_TRAP(r.Call(100, 0));
  CHECK_TRAP(r.Call(-1001, 0));
  CHECK_TRAP(r.Call(kMin, 0));
}
3466 3467

WASM_EXEC_TEST(BrToLoopWithValue) {
3468
  WasmRunner<int32_t, int32_t, int32_t> r(execution_tier);
3469 3470 3471
  // Subtracts <1> times 3 from <0> and returns the result.
  BUILD(r,
        // loop i32
3472
        kExprLoop, kI32Code,
3473
        // decrement <0> by 3.
3474
        WASM_LOCAL_SET(0, WASM_I32_SUB(WASM_LOCAL_GET(0), WASM_I32V_1(3))),
3475
        // decrement <1> by 1.
3476
        WASM_LOCAL_SET(1, WASM_I32_SUB(WASM_LOCAL_GET(1), WASM_ONE)),
3477
        // load return value <0>, br_if will drop if if the branch is taken.
3478
        WASM_LOCAL_GET(0),
3479
        // continue loop if <1> is != 0.
3480
        WASM_BR_IF(0, WASM_LOCAL_GET(1)),
3481 3482 3483 3484 3485 3486 3487
        // end of loop, value loaded above is the return value.
        kExprEnd);
  CHECK_EQ(12, r.Call(27, 5));
}

WASM_EXEC_TEST(BrToLoopWithoutValue) {
  // This was broken in the interpreter, see http://crbug.com/715454
3488
  WasmRunner<int32_t, int32_t> r(execution_tier);
3489
  BUILD(
3490
      r, kExprLoop, kI32Code,                                        // loop i32
3491 3492
      WASM_LOCAL_SET(0, WASM_I32_SUB(WASM_LOCAL_GET(0), WASM_ONE)),  // dec <0>
      WASM_BR_IF(0, WASM_LOCAL_GET(0)),  // br_if <0> != 0
3493 3494 3495 3496
      kExprUnreachable,                  // unreachable
      kExprEnd);                         // end
  CHECK_TRAP32(r.Call(2));
}
3497 3498

WASM_EXEC_TEST(LoopsWithValues) {
3499
  WasmRunner<int32_t> r(execution_tier);
3500 3501 3502
  BUILD(r, WASM_LOOP_I(WASM_LOOP_I(WASM_ONE), WASM_ONE, kExprI32Add));
  CHECK_EQ(2, r.Call());
}
3503 3504

WASM_EXEC_TEST(InvalidStackAfterUnreachable) {
3505
  WasmRunner<int32_t> r(execution_tier);
3506 3507 3508 3509 3510
  BUILD(r, kExprUnreachable, kExprI32Add);
  CHECK_TRAP32(r.Call());
}

WASM_EXEC_TEST(InvalidStackAfterBr) {
3511
  WasmRunner<int32_t> r(execution_tier);
3512 3513 3514 3515 3516
  BUILD(r, WASM_BRV(0, WASM_I32V_1(27)), kExprI32Add);
  CHECK_EQ(27, r.Call());
}

WASM_EXEC_TEST(InvalidStackAfterReturn) {
3517
  WasmRunner<int32_t> r(execution_tier);
3518 3519 3520 3521 3522
  BUILD(r, WASM_RETURN1(WASM_I32V_1(17)), kExprI32Add);
  CHECK_EQ(17, r.Call());
}

WASM_EXEC_TEST(BranchOverUnreachableCode) {
3523
  WasmRunner<int32_t> r(execution_tier);
3524 3525 3526 3527 3528 3529 3530 3531 3532
  BUILD(r,
        // Start a block which breaks in the middle (hence unreachable code
        // afterwards) and continue execution after this block.
        WASM_BLOCK_I(WASM_BRV(0, WASM_I32V_1(17)), kExprI32Add),
        // Add one to the 17 returned from the block.
        WASM_ONE, kExprI32Add);
  CHECK_EQ(18, r.Call());
}

3533
WASM_EXEC_TEST(BranchOverUnreachableCodeInLoop0) {
3534
  WasmRunner<int32_t> r(execution_tier);
3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547
  BUILD(r,
        WASM_BLOCK_I(
            // Start a loop which breaks in the middle (hence unreachable code
            // afterwards) and continue execution after this loop.
            // This should validate even though there is no value on the stack
            // at the end of the loop.
            WASM_LOOP_I(WASM_BRV(1, WASM_I32V_1(17)))),
        // Add one to the 17 returned from the block.
        WASM_ONE, kExprI32Add);
  CHECK_EQ(18, r.Call());
}

WASM_EXEC_TEST(BranchOverUnreachableCodeInLoop1) {
3548
  WasmRunner<int32_t> r(execution_tier);
3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560
  BUILD(r,
        WASM_BLOCK_I(
            // Start a loop which breaks in the middle (hence unreachable code
            // afterwards) and continue execution after this loop.
            // Even though unreachable, the loop leaves one value on the stack.
            WASM_LOOP_I(WASM_BRV(1, WASM_I32V_1(17)), WASM_ONE)),
        // Add one to the 17 returned from the block.
        WASM_ONE, kExprI32Add);
  CHECK_EQ(18, r.Call());
}

WASM_EXEC_TEST(BranchOverUnreachableCodeInLoop2) {
3561
  WasmRunner<int32_t> r(execution_tier);
3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573
  BUILD(r,
        WASM_BLOCK_I(
            // Start a loop which breaks in the middle (hence unreachable code
            // afterwards) and continue execution after this loop.
            // The unreachable code is allowed to pop non-existing values off
            // the stack and push back the result.
            WASM_LOOP_I(WASM_BRV(1, WASM_I32V_1(17)), kExprI32Add)),
        // Add one to the 17 returned from the block.
        WASM_ONE, kExprI32Add);
  CHECK_EQ(18, r.Call());
}

3574
WASM_EXEC_TEST(BlockInsideUnreachable) {
3575
  WasmRunner<int32_t> r(execution_tier);
3576 3577 3578 3579 3580
  BUILD(r, WASM_RETURN1(WASM_I32V_1(17)), WASM_BLOCK(WASM_BR(0)));
  CHECK_EQ(17, r.Call());
}

WASM_EXEC_TEST(IfInsideUnreachable) {
3581
  WasmRunner<int32_t> r(execution_tier);
3582 3583 3584 3585 3586
  BUILD(
      r, WASM_RETURN1(WASM_I32V_1(17)),
      WASM_IF_ELSE_I(WASM_ONE, WASM_BRV(0, WASM_ONE), WASM_RETURN1(WASM_ONE)));
  CHECK_EQ(17, r.Call());
}
3587

3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610
WASM_EXEC_TEST(IndirectNull) {
  WasmRunner<int32_t> r(execution_tier);
  FunctionSig sig(1, 0, &kWasmI32);
  byte sig_index = r.builder().AddSignature(&sig);
  r.builder().AddIndirectFunctionTable(nullptr, 1);

  BUILD(r, WASM_CALL_INDIRECT(sig_index, WASM_I32V(0)));

  CHECK_TRAP(r.Call());
}

WASM_EXEC_TEST(IndirectNullTyped) {
  WasmRunner<int32_t> r(execution_tier);
  FunctionSig sig(1, 0, &kWasmI32);
  byte sig_index = r.builder().AddSignature(&sig);
  r.builder().AddIndirectFunctionTable(nullptr, 1,
                                       ValueType::Ref(sig_index, kNullable));

  BUILD(r, WASM_CALL_INDIRECT(sig_index, WASM_I32V(0)));

  CHECK_TRAP(r.Call());
}

3611 3612 3613
// This test targets binops in Liftoff.
// Initialize a number of local variables to force them into different
// registers, then perform a binary operation on two of the locals.
3614 3615
// Afterwards, write back all locals to memory, to check that their value was
// not overwritten.
3616
template <typename ctype>
3617
void BinOpOnDifferentRegisters(
3618
    TestExecutionTier execution_tier, ValueType type,
3619
    base::Vector<const ctype> inputs, WasmOpcode opcode,
3620
    std::function<ctype(ctype, ctype, bool*)> expect_fn) {
3621 3622 3623 3624 3625 3626 3627 3628
  static constexpr int kMaxNumLocals = 8;
  for (int num_locals = 1; num_locals < kMaxNumLocals; ++num_locals) {
    // {init_locals_code} is shared by all code generated in the loop below.
    std::vector<byte> init_locals_code;
    // Load from memory into the locals.
    for (int i = 0; i < num_locals; ++i) {
      ADD_CODE(
          init_locals_code,
3629
          WASM_LOCAL_SET(i, WASM_LOAD_MEM(type.machine_type(),
3630 3631
                                          WASM_I32V_2(sizeof(ctype) * i))));
    }
3632 3633 3634 3635 3636
    // {write_locals_code} is shared by all code generated in the loop below.
    std::vector<byte> write_locals_code;
    // Write locals back into memory, shifted by one element to the right.
    for (int i = 0; i < num_locals; ++i) {
      ADD_CODE(write_locals_code,
3637
               WASM_STORE_MEM(type.machine_type(),
3638
                              WASM_I32V_2(sizeof(ctype) * (i + 1)),
3639
                              WASM_LOCAL_GET(i)));
3640
    }
3641 3642
    for (int lhs = 0; lhs < num_locals; ++lhs) {
      for (int rhs = 0; rhs < num_locals; ++rhs) {
3643
        WasmRunner<int32_t> r(execution_tier);
3644 3645
        ctype* memory =
            r.builder().AddMemoryElems<ctype>(kWasmPageSize / sizeof(ctype));
3646 3647 3648 3649 3650
        for (int i = 0; i < num_locals; ++i) {
          r.AllocateLocal(type);
        }
        std::vector<byte> code(init_locals_code);
        ADD_CODE(code,
3651
                 // Store the result of the binary operation at memory[0].
3652
                 WASM_STORE_MEM(type.machine_type(), WASM_ZERO,
3653 3654
                                WASM_BINOP(opcode, WASM_LOCAL_GET(lhs),
                                           WASM_LOCAL_GET(rhs))),
3655 3656
                 // Return 0.
                 WASM_ZERO);
3657 3658
        code.insert(code.end(), write_locals_code.begin(),
                    write_locals_code.end());
3659 3660 3661 3662
        r.Build(code.data(), code.data() + code.size());
        for (ctype lhs_value : inputs) {
          for (ctype rhs_value : inputs) {
            if (lhs == rhs) lhs_value = rhs_value;
3663 3664 3665 3666
            for (int i = 0; i < num_locals; ++i) {
              ctype value =
                  i == lhs ? lhs_value
                           : i == rhs ? rhs_value : static_cast<ctype>(i + 47);
3667
              WriteLittleEndianValue<ctype>(&memory[i], value);
3668 3669 3670 3671 3672 3673 3674
            }
            bool trap = false;
            int64_t expect = expect_fn(lhs_value, rhs_value, &trap);
            if (trap) {
              CHECK_TRAP(r.Call());
              continue;
            }
3675
            CHECK_EQ(0, r.Call());
3676
            CHECK_EQ(expect, ReadLittleEndianValue<ctype>(&memory[0]));
3677 3678 3679 3680
            for (int i = 0; i < num_locals; ++i) {
              ctype value =
                  i == lhs ? lhs_value
                           : i == rhs ? rhs_value : static_cast<ctype>(i + 47);
3681
              CHECK_EQ(value, ReadLittleEndianValue<ctype>(&memory[i + 1]));
3682
            }
3683 3684 3685 3686 3687 3688 3689 3690 3691
          }
        }
      }
    }
  }
}

// Keep this list small, the BinOpOnDifferentRegisters test is running long
// enough already.
3692 3693
static constexpr int32_t kSome32BitInputs[] = {
    0, 1, -1, 31, static_cast<int32_t>(0xff112233)};
3694
static constexpr int64_t kSome64BitInputs[] = {
3695
    0, 1, -1, 31, 63, 0x100000000, static_cast<int64_t>(0xff11223344556677)};
3696 3697 3698

WASM_EXEC_TEST(I32AddOnDifferentRegisters) {
  BinOpOnDifferentRegisters<int32_t>(
3699 3700
      execution_tier, kWasmI32, base::ArrayVector(kSome32BitInputs),
      kExprI32Add,
3701
      [](int32_t lhs, int32_t rhs, bool* trap) { return lhs + rhs; });
3702 3703 3704 3705
}

WASM_EXEC_TEST(I32SubOnDifferentRegisters) {
  BinOpOnDifferentRegisters<int32_t>(
3706 3707
      execution_tier, kWasmI32, base::ArrayVector(kSome32BitInputs),
      kExprI32Sub,
3708
      [](int32_t lhs, int32_t rhs, bool* trap) { return lhs - rhs; });
3709 3710 3711
}

WASM_EXEC_TEST(I32MulOnDifferentRegisters) {
3712 3713 3714 3715 3716
  BinOpOnDifferentRegisters<int32_t>(
      execution_tier, kWasmI32, base::ArrayVector(kSome32BitInputs),
      kExprI32Mul, [](int32_t lhs, int32_t rhs, bool* trap) {
        return base::MulWithWraparound(lhs, rhs);
      });
3717 3718 3719
}

WASM_EXEC_TEST(I32ShlOnDifferentRegisters) {
3720 3721 3722 3723 3724
  BinOpOnDifferentRegisters<int32_t>(
      execution_tier, kWasmI32, base::ArrayVector(kSome32BitInputs),
      kExprI32Shl, [](int32_t lhs, int32_t rhs, bool* trap) {
        return base::ShlWithWraparound(lhs, rhs);
      });
3725 3726 3727 3728
}

WASM_EXEC_TEST(I32ShrSOnDifferentRegisters) {
  BinOpOnDifferentRegisters<int32_t>(
3729 3730
      execution_tier, kWasmI32, base::ArrayVector(kSome32BitInputs),
      kExprI32ShrS,
3731
      [](int32_t lhs, int32_t rhs, bool* trap) { return lhs >> (rhs & 31); });
3732 3733 3734 3735
}

WASM_EXEC_TEST(I32ShrUOnDifferentRegisters) {
  BinOpOnDifferentRegisters<int32_t>(
3736 3737
      execution_tier, kWasmI32, base::ArrayVector(kSome32BitInputs),
      kExprI32ShrU, [](int32_t lhs, int32_t rhs, bool* trap) {
3738 3739 3740 3741
        return static_cast<uint32_t>(lhs) >> (rhs & 31);
      });
}

3742 3743
WASM_EXEC_TEST(I32DivSOnDifferentRegisters) {
  BinOpOnDifferentRegisters<int32_t>(
3744 3745
      execution_tier, kWasmI32, base::ArrayVector(kSome32BitInputs),
      kExprI32DivS, [](int32_t lhs, int32_t rhs, bool* trap) {
3746 3747 3748 3749 3750 3751 3752
        *trap = rhs == 0;
        return *trap ? 0 : lhs / rhs;
      });
}

WASM_EXEC_TEST(I32DivUOnDifferentRegisters) {
  BinOpOnDifferentRegisters<int32_t>(
3753 3754
      execution_tier, kWasmI32, base::ArrayVector(kSome32BitInputs),
      kExprI32DivU, [](uint32_t lhs, uint32_t rhs, bool* trap) {
3755 3756 3757 3758 3759 3760 3761
        *trap = rhs == 0;
        return *trap ? 0 : lhs / rhs;
      });
}

WASM_EXEC_TEST(I32RemSOnDifferentRegisters) {
  BinOpOnDifferentRegisters<int32_t>(
3762 3763
      execution_tier, kWasmI32, base::ArrayVector(kSome32BitInputs),
      kExprI32RemS, [](int32_t lhs, int32_t rhs, bool* trap) {
3764 3765 3766 3767 3768 3769 3770
        *trap = rhs == 0;
        return *trap || rhs == -1 ? 0 : lhs % rhs;
      });
}

WASM_EXEC_TEST(I32RemUOnDifferentRegisters) {
  BinOpOnDifferentRegisters<int32_t>(
3771 3772
      execution_tier, kWasmI32, base::ArrayVector(kSome32BitInputs),
      kExprI32RemU, [](uint32_t lhs, uint32_t rhs, bool* trap) {
3773 3774 3775 3776 3777
        *trap = rhs == 0;
        return *trap ? 0 : lhs % rhs;
      });
}

3778 3779
WASM_EXEC_TEST(I64AddOnDifferentRegisters) {
  BinOpOnDifferentRegisters<int64_t>(
3780 3781
      execution_tier, kWasmI64, base::ArrayVector(kSome64BitInputs),
      kExprI64Add,
3782
      [](int64_t lhs, int64_t rhs, bool* trap) { return lhs + rhs; });
3783 3784 3785 3786
}

WASM_EXEC_TEST(I64SubOnDifferentRegisters) {
  BinOpOnDifferentRegisters<int64_t>(
3787 3788
      execution_tier, kWasmI64, base::ArrayVector(kSome64BitInputs),
      kExprI64Sub,
3789
      [](int64_t lhs, int64_t rhs, bool* trap) { return lhs - rhs; });
3790 3791 3792
}

WASM_EXEC_TEST(I64MulOnDifferentRegisters) {
3793 3794 3795 3796 3797
  BinOpOnDifferentRegisters<int64_t>(
      execution_tier, kWasmI64, base::ArrayVector(kSome64BitInputs),
      kExprI64Mul, [](int64_t lhs, int64_t rhs, bool* trap) {
        return base::MulWithWraparound(lhs, rhs);
      });
3798 3799 3800
}

WASM_EXEC_TEST(I64ShlOnDifferentRegisters) {
3801 3802 3803 3804 3805
  BinOpOnDifferentRegisters<int64_t>(
      execution_tier, kWasmI64, base::ArrayVector(kSome64BitInputs),
      kExprI64Shl, [](int64_t lhs, int64_t rhs, bool* trap) {
        return base::ShlWithWraparound(lhs, rhs);
      });
3806 3807 3808 3809
}

WASM_EXEC_TEST(I64ShrSOnDifferentRegisters) {
  BinOpOnDifferentRegisters<int64_t>(
3810 3811
      execution_tier, kWasmI64, base::ArrayVector(kSome64BitInputs),
      kExprI64ShrS,
3812
      [](int64_t lhs, int64_t rhs, bool* trap) { return lhs >> (rhs & 63); });
3813 3814 3815 3816
}

WASM_EXEC_TEST(I64ShrUOnDifferentRegisters) {
  BinOpOnDifferentRegisters<int64_t>(
3817 3818
      execution_tier, kWasmI64, base::ArrayVector(kSome64BitInputs),
      kExprI64ShrU, [](int64_t lhs, int64_t rhs, bool* trap) {
3819 3820 3821 3822
        return static_cast<uint64_t>(lhs) >> (rhs & 63);
      });
}

3823 3824
WASM_EXEC_TEST(I64DivSOnDifferentRegisters) {
  BinOpOnDifferentRegisters<int64_t>(
3825 3826
      execution_tier, kWasmI64, base::ArrayVector(kSome64BitInputs),
      kExprI64DivS, [](int64_t lhs, int64_t rhs, bool* trap) {
3827 3828 3829 3830 3831 3832 3833 3834
        *trap = rhs == 0 ||
                (rhs == -1 && lhs == std::numeric_limits<int64_t>::min());
        return *trap ? 0 : lhs / rhs;
      });
}

WASM_EXEC_TEST(I64DivUOnDifferentRegisters) {
  BinOpOnDifferentRegisters<int64_t>(
3835 3836
      execution_tier, kWasmI64, base::ArrayVector(kSome64BitInputs),
      kExprI64DivU, [](uint64_t lhs, uint64_t rhs, bool* trap) {
3837 3838 3839 3840 3841 3842 3843
        *trap = rhs == 0;
        return *trap ? 0 : lhs / rhs;
      });
}

WASM_EXEC_TEST(I64RemSOnDifferentRegisters) {
  BinOpOnDifferentRegisters<int64_t>(
3844 3845
      execution_tier, kWasmI64, base::ArrayVector(kSome64BitInputs),
      kExprI64RemS, [](int64_t lhs, int64_t rhs, bool* trap) {
3846 3847 3848 3849 3850 3851 3852
        *trap = rhs == 0;
        return *trap || rhs == -1 ? 0 : lhs % rhs;
      });
}

WASM_EXEC_TEST(I64RemUOnDifferentRegisters) {
  BinOpOnDifferentRegisters<int64_t>(
3853 3854
      execution_tier, kWasmI64, base::ArrayVector(kSome64BitInputs),
      kExprI64RemU, [](uint64_t lhs, uint64_t rhs, bool* trap) {
3855 3856 3857 3858 3859
        *trap = rhs == 0;
        return *trap ? 0 : lhs % rhs;
      });
}

3860
TEST(Liftoff_tier_up) {
3861
  WasmRunner<int32_t, int32_t, int32_t> r(TestExecutionTier::kLiftoff);
3862 3863

  WasmFunctionCompiler& add = r.NewFunction<int32_t, int32_t, int32_t>("add");
3864
  BUILD(add, WASM_I32_ADD(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)));
3865 3866

  WasmFunctionCompiler& sub = r.NewFunction<int32_t, int32_t, int32_t>("sub");
3867
  BUILD(sub, WASM_I32_SUB(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)));
3868 3869

  // Create the main function, which shall call {add}.
3870 3871
  BUILD(r, WASM_CALL_FUNCTION(add.function_index(), WASM_LOCAL_GET(0),
                              WASM_LOCAL_GET(1)));
3872 3873

  NativeModule* native_module =
3874
      r.builder().instance_object()->module_object().native_module();
3875 3876

  // This test only works if we managed to compile with Liftoff.
3877
  if (native_module->GetCode(add.function_index())->is_liftoff()) {
3878 3879 3880 3881 3882 3883 3884
    // First run should execute {add}.
    CHECK_EQ(18, r.Call(11, 7));

    // Now make a copy of the {sub} function, and add it to the native module at
    // the index of {add}.
    CodeDesc desc;
    memset(&desc, 0, sizeof(CodeDesc));
3885
    WasmCode* sub_code = native_module->GetCode(sub.function_index());
3886 3887
    size_t sub_size = sub_code->instructions().size();
    std::unique_ptr<byte[]> buffer(new byte[sub_code->instructions().size()]);
3888
    memcpy(buffer.get(), sub_code->instructions().begin(), sub_size);
3889 3890
    desc.buffer = buffer.get();
    desc.instr_size = static_cast<int>(sub_size);
3891 3892 3893
    std::unique_ptr<WasmCode> new_code = native_module->AddCode(
        add.function_index(), desc, 0, 0, {}, {}, WasmCode::kFunction,
        ExecutionTier::kTurbofan, kNoDebugging);
3894
    native_module->PublishCode(std::move(new_code));
3895 3896 3897

    // Second run should now execute {sub}.
    CHECK_EQ(4, r.Call(11, 7));
3898 3899 3900
  }
}

3901
TEST(Regression_1085507) {
3902
  WasmRunner<int32_t> r(TestExecutionTier::kInterpreter);
3903 3904
  TestSignatures sigs;
  uint32_t sig_v_i = r.builder().AddSignature(sigs.v_i());
3905
  BUILD(r, WASM_I32V_1(0), kExprIf, kVoidCode, WASM_UNREACHABLE,
3906 3907 3908
        WASM_BLOCK_X(sig_v_i, kExprDrop), kExprElse, kExprEnd, WASM_I32V_1(0));
}

3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920
TEST(Regression_1185323_1185492) {
  WasmRunner<int32_t> r(TestExecutionTier::kInterpreter);
  r.builder().AddIndirectFunctionTable(nullptr, 1);
  BUILD(r, WASM_I32V_1(0),
        // Use a long leb128 encoding of kExprTableSize instruction.
        // This exercises a bug in the interpreter which tries to read the
        // immediate at pc+2 (it should be pc+4).
        kNumericPrefix, 0x90, 0x80, 0x00, 0x00,  // table.size 0.
        WASM_UNREACHABLE, kExprTableSet, 0x00);  // Hits a DCHECK if reached.
  r.Call();
}

3921 3922 3923 3924 3925 3926
#undef B1
#undef B2
#undef RET
#undef RET_I8
#undef ADD_CODE

3927
}  // namespace test_run_wasm
3928 3929 3930
}  // namespace wasm
}  // namespace internal
}  // namespace v8