| OLD | NEW |
| 1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/assembler-inl.h" | 5 #include "test/cctest/wasm/test-wasm-simd-common.h" |
| 6 #include "src/wasm/wasm-macro-gen.h" | |
| 7 #include "test/cctest/cctest.h" | |
| 8 #include "test/cctest/compiler/value-helper.h" | |
| 9 #include "test/cctest/wasm/wasm-run-utils.h" | |
| 10 | 6 |
| 11 using namespace v8::base; | 7 using namespace v8::base; |
| 12 using namespace v8::internal; | 8 using namespace v8::internal; |
| 13 using namespace v8::internal::compiler; | 9 using namespace v8::internal::compiler; |
| 14 using namespace v8::internal::wasm; | 10 using namespace v8::internal::wasm; |
| 15 | 11 |
| 16 namespace { | 12 namespace test_wasm_simd_common { |
| 17 | |
| 18 typedef float (*FloatUnOp)(float); | |
| 19 typedef float (*FloatBinOp)(float, float); | |
| 20 typedef int32_t (*FloatCompareOp)(float, float); | |
| 21 typedef int32_t (*Int32UnOp)(int32_t); | |
| 22 typedef int32_t (*Int32BinOp)(int32_t, int32_t); | |
| 23 typedef int32_t (*Int32ShiftOp)(int32_t, int); | |
| 24 typedef int16_t (*Int16UnOp)(int16_t); | |
| 25 typedef int16_t (*Int16BinOp)(int16_t, int16_t); | |
| 26 typedef int16_t (*Int16ShiftOp)(int16_t, int); | |
| 27 typedef int8_t (*Int8UnOp)(int8_t); | |
| 28 typedef int8_t (*Int8BinOp)(int8_t, int8_t); | |
| 29 typedef int8_t (*Int8ShiftOp)(int8_t, int); | |
| 30 | 13 |
| 31 #if V8_TARGET_ARCH_ARM | 14 #if V8_TARGET_ARCH_ARM |
| 15 namespace { |
| 32 // Floating point specific value functions, only used by ARM so far. | 16 // Floating point specific value functions, only used by ARM so far. |
| 33 int32_t Equal(float a, float b) { return a == b ? 1 : 0; } | 17 int32_t Equal(float a, float b) { return a == b ? 1 : 0; } |
| 34 | 18 |
| 35 int32_t NotEqual(float a, float b) { return a != b ? 1 : 0; } | 19 int32_t NotEqual(float a, float b) { return a != b ? 1 : 0; } |
| 36 #endif // V8_TARGET_ARCH_ARM | |
| 37 | |
| 38 // Generic expected value functions. | |
| 39 template <typename T> | |
| 40 T Negate(T a) { | |
| 41 return -a; | |
| 42 } | 20 } |
| 43 | 21 |
| 44 template <typename T> | 22 WASM_EXEC_TEST(F32x4Splat) { RunF32x4SplatTest(); } |
| 45 T Add(T a, T b) { | |
| 46 return a + b; | |
| 47 } | |
| 48 | 23 |
| 49 template <typename T> | 24 WASM_EXEC_TEST(F32x4ReplaceLane) { RunF32x4ReplaceLaneTest(); } |
| 50 T Sub(T a, T b) { | |
| 51 return a - b; | |
| 52 } | |
| 53 | |
| 54 template <typename T> | |
| 55 T Mul(T a, T b) { | |
| 56 return a * b; | |
| 57 } | |
| 58 | |
| 59 template <typename T> | |
| 60 T Minimum(T a, T b) { | |
| 61 return a <= b ? a : b; | |
| 62 } | |
| 63 | |
| 64 template <typename T> | |
| 65 T Maximum(T a, T b) { | |
| 66 return a >= b ? a : b; | |
| 67 } | |
| 68 | |
| 69 template <typename T> | |
| 70 T UnsignedMinimum(T a, T b) { | |
| 71 using UnsignedT = typename std::make_unsigned<T>::type; | |
| 72 return static_cast<UnsignedT>(a) <= static_cast<UnsignedT>(b) ? a : b; | |
| 73 } | |
| 74 | |
| 75 template <typename T> | |
| 76 T UnsignedMaximum(T a, T b) { | |
| 77 using UnsignedT = typename std::make_unsigned<T>::type; | |
| 78 return static_cast<UnsignedT>(a) >= static_cast<UnsignedT>(b) ? a : b; | |
| 79 } | |
| 80 | |
| 81 template <typename T> | |
| 82 T Equal(T a, T b) { | |
| 83 return a == b ? 1 : 0; | |
| 84 } | |
| 85 | |
| 86 template <typename T> | |
| 87 T NotEqual(T a, T b) { | |
| 88 return a != b ? 1 : 0; | |
| 89 } | |
| 90 | |
| 91 template <typename T> | |
| 92 T Greater(T a, T b) { | |
| 93 return a > b ? 1 : 0; | |
| 94 } | |
| 95 | |
| 96 template <typename T> | |
| 97 T GreaterEqual(T a, T b) { | |
| 98 return a >= b ? 1 : 0; | |
| 99 } | |
| 100 | |
| 101 template <typename T> | |
| 102 T Less(T a, T b) { | |
| 103 return a < b ? 1 : 0; | |
| 104 } | |
| 105 | |
| 106 template <typename T> | |
| 107 T LessEqual(T a, T b) { | |
| 108 return a <= b ? 1 : 0; | |
| 109 } | |
| 110 | |
| 111 template <typename T> | |
| 112 T UnsignedGreater(T a, T b) { | |
| 113 using UnsignedT = typename std::make_unsigned<T>::type; | |
| 114 return static_cast<UnsignedT>(a) > static_cast<UnsignedT>(b) ? 1 : 0; | |
| 115 } | |
| 116 | |
| 117 template <typename T> | |
| 118 T UnsignedGreaterEqual(T a, T b) { | |
| 119 using UnsignedT = typename std::make_unsigned<T>::type; | |
| 120 return static_cast<UnsignedT>(a) >= static_cast<UnsignedT>(b) ? 1 : 0; | |
| 121 } | |
| 122 | |
| 123 template <typename T> | |
| 124 T UnsignedLess(T a, T b) { | |
| 125 using UnsignedT = typename std::make_unsigned<T>::type; | |
| 126 return static_cast<UnsignedT>(a) < static_cast<UnsignedT>(b) ? 1 : 0; | |
| 127 } | |
| 128 | |
| 129 template <typename T> | |
| 130 T UnsignedLessEqual(T a, T b) { | |
| 131 using UnsignedT = typename std::make_unsigned<T>::type; | |
| 132 return static_cast<UnsignedT>(a) <= static_cast<UnsignedT>(b) ? 1 : 0; | |
| 133 } | |
| 134 | |
| 135 template <typename T> | |
| 136 T LogicalShiftLeft(T a, int shift) { | |
| 137 return a << shift; | |
| 138 } | |
| 139 | |
| 140 template <typename T> | |
| 141 T LogicalShiftRight(T a, int shift) { | |
| 142 using UnsignedT = typename std::make_unsigned<T>::type; | |
| 143 return static_cast<UnsignedT>(a) >> shift; | |
| 144 } | |
| 145 | |
| 146 template <typename T> | |
| 147 int64_t Widen(T value) { | |
| 148 static_assert(sizeof(int64_t) > sizeof(T), "T must be int32_t or smaller"); | |
| 149 return static_cast<int64_t>(value); | |
| 150 } | |
| 151 | |
| 152 template <typename T> | |
| 153 int64_t UnsignedWiden(T value) { | |
| 154 static_assert(sizeof(int64_t) > sizeof(T), "T must be int32_t or smaller"); | |
| 155 using UnsignedT = typename std::make_unsigned<T>::type; | |
| 156 return static_cast<int64_t>(static_cast<UnsignedT>(value)); | |
| 157 } | |
| 158 | |
| 159 template <typename T> | |
| 160 T Clamp(int64_t value) { | |
| 161 static_assert(sizeof(int64_t) > sizeof(T), "T must be int32_t or smaller"); | |
| 162 int64_t min = static_cast<int64_t>(std::numeric_limits<T>::min()); | |
| 163 int64_t max = static_cast<int64_t>(std::numeric_limits<T>::max()); | |
| 164 int64_t clamped = std::max(min, std::min(max, value)); | |
| 165 return static_cast<T>(clamped); | |
| 166 } | |
| 167 | |
| 168 template <typename T> | |
| 169 T AddSaturate(T a, T b) { | |
| 170 return Clamp<T>(Widen(a) + Widen(b)); | |
| 171 } | |
| 172 | |
| 173 template <typename T> | |
| 174 T SubSaturate(T a, T b) { | |
| 175 return Clamp<T>(Widen(a) - Widen(b)); | |
| 176 } | |
| 177 | |
| 178 template <typename T> | |
| 179 T UnsignedAddSaturate(T a, T b) { | |
| 180 using UnsignedT = typename std::make_unsigned<T>::type; | |
| 181 return Clamp<UnsignedT>(UnsignedWiden(a) + UnsignedWiden(b)); | |
| 182 } | |
| 183 | |
| 184 template <typename T> | |
| 185 T UnsignedSubSaturate(T a, T b) { | |
| 186 using UnsignedT = typename std::make_unsigned<T>::type; | |
| 187 return Clamp<UnsignedT>(UnsignedWiden(a) - UnsignedWiden(b)); | |
| 188 } | |
| 189 | |
| 190 template <typename T> | |
| 191 T And(T a, T b) { | |
| 192 return a & b; | |
| 193 } | |
| 194 | |
| 195 template <typename T> | |
| 196 T Or(T a, T b) { | |
| 197 return a | b; | |
| 198 } | |
| 199 | |
| 200 template <typename T> | |
| 201 T Xor(T a, T b) { | |
| 202 return a ^ b; | |
| 203 } | |
| 204 | |
| 205 template <typename T> | |
| 206 T Not(T a) { | |
| 207 return ~a; | |
| 208 } | |
| 209 | |
| 210 } // namespace | |
| 211 | |
| 212 // TODO(gdeepti): These are tests using sample values to verify functional | |
| 213 // correctness of opcodes, add more tests for a range of values and macroize | |
| 214 // tests. | |
| 215 | |
| 216 // TODO(bbudge) Figure out how to compare floats in Wasm code that can handle | |
| 217 // NaNs. For now, our tests avoid using NaNs. | |
| 218 #define WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lane_value, lane_index) \ | |
| 219 WASM_IF(WASM_##LANE_TYPE##_NE(WASM_GET_LOCAL(lane_value), \ | |
| 220 WASM_SIMD_##TYPE##_EXTRACT_LANE( \ | |
| 221 lane_index, WASM_GET_LOCAL(value))), \ | |
| 222 WASM_RETURN1(WASM_ZERO)) | |
| 223 | |
| 224 #define WASM_SIMD_CHECK4(TYPE, value, LANE_TYPE, lv0, lv1, lv2, lv3) \ | |
| 225 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv0, 0) \ | |
| 226 , WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv1, 1), \ | |
| 227 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv2, 2), \ | |
| 228 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv3, 3) | |
| 229 | |
| 230 #define WASM_SIMD_CHECK_SPLAT4(TYPE, value, LANE_TYPE, lv) \ | |
| 231 WASM_SIMD_CHECK4(TYPE, value, LANE_TYPE, lv, lv, lv, lv) | |
| 232 | |
| 233 #define WASM_SIMD_CHECK8(TYPE, value, LANE_TYPE, lv0, lv1, lv2, lv3, lv4, lv5, \ | |
| 234 lv6, lv7) \ | |
| 235 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv0, 0) \ | |
| 236 , WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv1, 1), \ | |
| 237 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv2, 2), \ | |
| 238 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv3, 3), \ | |
| 239 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv4, 4), \ | |
| 240 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv5, 5), \ | |
| 241 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv6, 6), \ | |
| 242 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv7, 7) | |
| 243 | |
| 244 #define WASM_SIMD_CHECK_SPLAT8(TYPE, value, LANE_TYPE, lv) \ | |
| 245 WASM_SIMD_CHECK8(TYPE, value, LANE_TYPE, lv, lv, lv, lv, lv, lv, lv, lv) | |
| 246 | |
| 247 #define WASM_SIMD_CHECK16(TYPE, value, LANE_TYPE, lv0, lv1, lv2, lv3, lv4, \ | |
| 248 lv5, lv6, lv7, lv8, lv9, lv10, lv11, lv12, lv13, \ | |
| 249 lv14, lv15) \ | |
| 250 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv0, 0) \ | |
| 251 , WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv1, 1), \ | |
| 252 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv2, 2), \ | |
| 253 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv3, 3), \ | |
| 254 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv4, 4), \ | |
| 255 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv5, 5), \ | |
| 256 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv6, 6), \ | |
| 257 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv7, 7), \ | |
| 258 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv8, 8), \ | |
| 259 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv9, 9), \ | |
| 260 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv10, 10), \ | |
| 261 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv11, 11), \ | |
| 262 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv12, 12), \ | |
| 263 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv13, 13), \ | |
| 264 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv14, 14), \ | |
| 265 WASM_SIMD_CHECK_LANE(TYPE, value, LANE_TYPE, lv15, 15) | |
| 266 | |
| 267 #define WASM_SIMD_CHECK_SPLAT16(TYPE, value, LANE_TYPE, lv) \ | |
| 268 WASM_SIMD_CHECK16(TYPE, value, LANE_TYPE, lv, lv, lv, lv, lv, lv, lv, lv, \ | |
| 269 lv, lv, lv, lv, lv, lv, lv, lv) | |
| 270 | |
| 271 #define WASM_SIMD_CHECK_F32_LANE(TYPE, value, lane_value, lane_index) \ | |
| 272 WASM_IF( \ | |
| 273 WASM_I32_NE(WASM_I32_REINTERPRET_F32(WASM_GET_LOCAL(lane_value)), \ | |
| 274 WASM_I32_REINTERPRET_F32(WASM_SIMD_##TYPE##_EXTRACT_LANE( \ | |
| 275 lane_index, WASM_GET_LOCAL(value)))), \ | |
| 276 WASM_RETURN1(WASM_ZERO)) | |
| 277 | |
| 278 #define WASM_SIMD_CHECK4_F32(TYPE, value, lv0, lv1, lv2, lv3) \ | |
| 279 WASM_SIMD_CHECK_F32_LANE(TYPE, value, lv0, 0) \ | |
| 280 , WASM_SIMD_CHECK_F32_LANE(TYPE, value, lv1, 1), \ | |
| 281 WASM_SIMD_CHECK_F32_LANE(TYPE, value, lv2, 2), \ | |
| 282 WASM_SIMD_CHECK_F32_LANE(TYPE, value, lv3, 3) | |
| 283 | |
| 284 #define WASM_SIMD_CHECK_SPLAT4_F32(TYPE, value, lv) \ | |
| 285 WASM_SIMD_CHECK4_F32(TYPE, value, lv, lv, lv, lv) | |
| 286 | |
| 287 #define TO_BYTE(val) static_cast<byte>(val) | |
| 288 #define WASM_SIMD_OP(op) kSimdPrefix, TO_BYTE(op) | |
| 289 #define WASM_SIMD_SPLAT(Type, x) x, WASM_SIMD_OP(kExpr##Type##Splat) | |
| 290 #define WASM_SIMD_UNOP(op, x) x, WASM_SIMD_OP(op) | |
| 291 #define WASM_SIMD_BINOP(op, x, y) x, y, WASM_SIMD_OP(op) | |
| 292 #define WASM_SIMD_SHIFT_OP(op, shift, x) x, WASM_SIMD_OP(op), TO_BYTE(shift) | |
| 293 #define WASM_SIMD_SELECT(format, x, y, z) \ | |
| 294 x, y, z, WASM_SIMD_OP(kExprS##format##Select) | |
| 295 // Since boolean vectors can't be checked directly, materialize them into | |
| 296 // integer vectors using a Select operation. | |
| 297 #define WASM_SIMD_MATERIALIZE_BOOLS(format, x) \ | |
| 298 x, WASM_SIMD_I##format##_SPLAT(WASM_ONE), \ | |
| 299 WASM_SIMD_I##format##_SPLAT(WASM_ZERO), \ | |
| 300 WASM_SIMD_OP(kExprS##format##Select) | |
| 301 | |
| 302 #define WASM_SIMD_I16x8_SPLAT(x) x, WASM_SIMD_OP(kExprI16x8Splat) | |
| 303 #define WASM_SIMD_I16x8_EXTRACT_LANE(lane, x) \ | |
| 304 x, WASM_SIMD_OP(kExprI16x8ExtractLane), TO_BYTE(lane) | |
| 305 #define WASM_SIMD_I16x8_REPLACE_LANE(lane, x, y) \ | |
| 306 x, y, WASM_SIMD_OP(kExprI16x8ReplaceLane), TO_BYTE(lane) | |
| 307 #define WASM_SIMD_I8x16_SPLAT(x) x, WASM_SIMD_OP(kExprI8x16Splat) | |
| 308 #define WASM_SIMD_I8x16_EXTRACT_LANE(lane, x) \ | |
| 309 x, WASM_SIMD_OP(kExprI8x16ExtractLane), TO_BYTE(lane) | |
| 310 #define WASM_SIMD_I8x16_REPLACE_LANE(lane, x, y) \ | |
| 311 x, y, WASM_SIMD_OP(kExprI8x16ReplaceLane), TO_BYTE(lane) | |
| 312 | |
| 313 #define WASM_SIMD_F32x4_FROM_I32x4(x) x, WASM_SIMD_OP(kExprF32x4SConvertI32x4) | |
| 314 #define WASM_SIMD_F32x4_FROM_U32x4(x) x, WASM_SIMD_OP(kExprF32x4UConvertI32x4) | |
| 315 #define WASM_SIMD_I32x4_FROM_F32x4(x) x, WASM_SIMD_OP(kExprI32x4SConvertF32x4) | |
| 316 #define WASM_SIMD_U32x4_FROM_F32x4(x) x, WASM_SIMD_OP(kExprI32x4UConvertF32x4) | |
| 317 | |
| 318 #if V8_TARGET_ARCH_ARM | |
| 319 WASM_EXEC_TEST(F32x4Splat) { | |
| 320 FLAG_wasm_simd_prototype = true; | |
| 321 | |
| 322 WasmRunner<int32_t, float> r(kExecuteCompiled); | |
| 323 byte lane_val = 0; | |
| 324 byte simd = r.AllocateLocal(kWasmS128); | |
| 325 BUILD(r, | |
| 326 WASM_SET_LOCAL(simd, WASM_SIMD_F32x4_SPLAT(WASM_GET_LOCAL(lane_val))), | |
| 327 WASM_SIMD_CHECK_SPLAT4_F32(F32x4, simd, lane_val), WASM_ONE); | |
| 328 | |
| 329 FOR_FLOAT32_INPUTS(i) { CHECK_EQ(1, r.Call(*i)); } | |
| 330 } | |
| 331 | |
| 332 WASM_EXEC_TEST(F32x4ReplaceLane) { | |
| 333 FLAG_wasm_simd_prototype = true; | |
| 334 WasmRunner<int32_t, float, float> r(kExecuteCompiled); | |
| 335 byte old_val = 0; | |
| 336 byte new_val = 1; | |
| 337 byte simd = r.AllocateLocal(kWasmS128); | |
| 338 BUILD(r, WASM_SET_LOCAL(simd, WASM_SIMD_F32x4_SPLAT(WASM_GET_LOCAL(old_val))), | |
| 339 WASM_SET_LOCAL(simd, | |
| 340 WASM_SIMD_F32x4_REPLACE_LANE(0, WASM_GET_LOCAL(simd), | |
| 341 WASM_GET_LOCAL(new_val))), | |
| 342 WASM_SIMD_CHECK4(F32x4, simd, F32, new_val, old_val, old_val, old_val), | |
| 343 WASM_SET_LOCAL(simd, | |
| 344 WASM_SIMD_F32x4_REPLACE_LANE(1, WASM_GET_LOCAL(simd), | |
| 345 WASM_GET_LOCAL(new_val))), | |
| 346 WASM_SIMD_CHECK4(F32x4, simd, F32, new_val, new_val, old_val, old_val), | |
| 347 WASM_SET_LOCAL(simd, | |
| 348 WASM_SIMD_F32x4_REPLACE_LANE(2, WASM_GET_LOCAL(simd), | |
| 349 WASM_GET_LOCAL(new_val))), | |
| 350 WASM_SIMD_CHECK4(F32x4, simd, F32, new_val, new_val, new_val, old_val), | |
| 351 WASM_SET_LOCAL(simd, | |
| 352 WASM_SIMD_F32x4_REPLACE_LANE(3, WASM_GET_LOCAL(simd), | |
| 353 WASM_GET_LOCAL(new_val))), | |
| 354 WASM_SIMD_CHECK_SPLAT4(F32x4, simd, F32, new_val), WASM_ONE); | |
| 355 | |
| 356 CHECK_EQ(1, r.Call(3.14159, -1.5)); | |
| 357 } | |
| 358 | 25 |
| 359 // Tests both signed and unsigned conversion. | 26 // Tests both signed and unsigned conversion. |
| 360 WASM_EXEC_TEST(F32x4FromInt32x4) { | 27 WASM_EXEC_TEST(F32x4FromInt32x4) { |
| 361 FLAG_wasm_simd_prototype = true; | 28 FLAG_wasm_simd_prototype = true; |
| 362 WasmRunner<int32_t, int32_t, float, float> r(kExecuteCompiled); | 29 WasmRunner<int32_t, int32_t, float, float> r(kExecuteCompiled); |
| 363 byte a = 0; | 30 byte a = 0; |
| 364 byte expected_signed = 1; | 31 byte expected_signed = 1; |
| 365 byte expected_unsigned = 2; | 32 byte expected_unsigned = 2; |
| 366 byte simd0 = r.AllocateLocal(kWasmS128); | 33 byte simd0 = r.AllocateLocal(kWasmS128); |
| 367 byte simd1 = r.AllocateLocal(kWasmS128); | 34 byte simd1 = r.AllocateLocal(kWasmS128); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 391 | 58 |
| 392 FOR_FLOAT32_INPUTS(i) { | 59 FOR_FLOAT32_INPUTS(i) { |
| 393 if (std::isnan(*i)) continue; | 60 if (std::isnan(*i)) continue; |
| 394 CHECK_EQ(1, r.Call(*i, expected_op(*i))); | 61 CHECK_EQ(1, r.Call(*i, expected_op(*i))); |
| 395 } | 62 } |
| 396 } | 63 } |
| 397 | 64 |
| 398 WASM_EXEC_TEST(F32x4Abs) { RunF32x4UnOpTest(kExprF32x4Abs, std::abs); } | 65 WASM_EXEC_TEST(F32x4Abs) { RunF32x4UnOpTest(kExprF32x4Abs, std::abs); } |
| 399 WASM_EXEC_TEST(F32x4Neg) { RunF32x4UnOpTest(kExprF32x4Neg, Negate); } | 66 WASM_EXEC_TEST(F32x4Neg) { RunF32x4UnOpTest(kExprF32x4Neg, Negate); } |
| 400 | 67 |
| 401 void RunF32x4BinOpTest(WasmOpcode simd_op, FloatBinOp expected_op) { | |
| 402 FLAG_wasm_simd_prototype = true; | |
| 403 WasmRunner<int32_t, float, float, float> r(kExecuteCompiled); | |
| 404 byte a = 0; | |
| 405 byte b = 1; | |
| 406 byte expected = 2; | |
| 407 byte simd0 = r.AllocateLocal(kWasmS128); | |
| 408 byte simd1 = r.AllocateLocal(kWasmS128); | |
| 409 BUILD(r, WASM_SET_LOCAL(simd0, WASM_SIMD_F32x4_SPLAT(WASM_GET_LOCAL(a))), | |
| 410 WASM_SET_LOCAL(simd1, WASM_SIMD_F32x4_SPLAT(WASM_GET_LOCAL(b))), | |
| 411 WASM_SET_LOCAL(simd1, WASM_SIMD_BINOP(simd_op, WASM_GET_LOCAL(simd0), | |
| 412 WASM_GET_LOCAL(simd1))), | |
| 413 WASM_SIMD_CHECK_SPLAT4_F32(F32x4, simd1, expected), WASM_ONE); | |
| 414 | |
| 415 FOR_FLOAT32_INPUTS(i) { | |
| 416 if (std::isnan(*i)) continue; | |
| 417 FOR_FLOAT32_INPUTS(j) { | |
| 418 if (std::isnan(*j)) continue; | |
| 419 float expected = expected_op(*i, *j); | |
| 420 // SIMD on some platforms may handle denormalized numbers differently. | |
| 421 // TODO(bbudge) On platforms that flush denorms to zero, test with | |
| 422 // expected == 0. | |
| 423 if (std::fpclassify(expected) == FP_SUBNORMAL) continue; | |
| 424 CHECK_EQ(1, r.Call(*i, *j, expected)); | |
| 425 } | |
| 426 } | |
| 427 } | |
| 428 | |
| 429 WASM_EXEC_TEST(F32x4Add) { RunF32x4BinOpTest(kExprF32x4Add, Add); } | 68 WASM_EXEC_TEST(F32x4Add) { RunF32x4BinOpTest(kExprF32x4Add, Add); } |
| 430 WASM_EXEC_TEST(F32x4Sub) { RunF32x4BinOpTest(kExprF32x4Sub, Sub); } | 69 WASM_EXEC_TEST(F32x4Sub) { RunF32x4BinOpTest(kExprF32x4Sub, Sub); } |
| 431 | 70 |
| 432 void RunF32x4CompareOpTest(WasmOpcode simd_op, FloatCompareOp expected_op) { | 71 void RunF32x4CompareOpTest(WasmOpcode simd_op, FloatCompareOp expected_op) { |
| 433 FLAG_wasm_simd_prototype = true; | 72 FLAG_wasm_simd_prototype = true; |
| 434 WasmRunner<int32_t, float, float, int32_t> r(kExecuteCompiled); | 73 WasmRunner<int32_t, float, float, int32_t> r(kExecuteCompiled); |
| 435 byte a = 0; | 74 byte a = 0; |
| 436 byte b = 1; | 75 byte b = 1; |
| 437 byte expected = 2; | 76 byte expected = 2; |
| 438 byte simd0 = r.AllocateLocal(kWasmS128); | 77 byte simd0 = r.AllocateLocal(kWasmS128); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 454 if (std::fpclassify(*i - *j) == FP_SUBNORMAL) continue; | 93 if (std::fpclassify(*i - *j) == FP_SUBNORMAL) continue; |
| 455 CHECK_EQ(1, r.Call(*i, *j, expected_op(*i, *j))); | 94 CHECK_EQ(1, r.Call(*i, *j, expected_op(*i, *j))); |
| 456 } | 95 } |
| 457 } | 96 } |
| 458 } | 97 } |
| 459 | 98 |
| 460 WASM_EXEC_TEST(F32x4Equal) { RunF32x4CompareOpTest(kExprF32x4Eq, Equal); } | 99 WASM_EXEC_TEST(F32x4Equal) { RunF32x4CompareOpTest(kExprF32x4Eq, Equal); } |
| 461 WASM_EXEC_TEST(F32x4NotEqual) { RunF32x4CompareOpTest(kExprF32x4Ne, NotEqual); } | 100 WASM_EXEC_TEST(F32x4NotEqual) { RunF32x4CompareOpTest(kExprF32x4Ne, NotEqual); } |
| 462 #endif // V8_TARGET_ARCH_ARM | 101 #endif // V8_TARGET_ARCH_ARM |
| 463 | 102 |
| 464 WASM_EXEC_TEST(I32x4Splat) { | 103 WASM_EXEC_TEST(I32x4Splat) { RunI32x4SplatTest(); } |
| 465 FLAG_wasm_simd_prototype = true; | |
| 466 | 104 |
| 467 // Store SIMD value in a local variable, use extract lane to check lane values | 105 WASM_EXEC_TEST(I32x4ReplaceLane) { RunI32x4ReplaceLaneTest(); } |
| 468 // This test is not a test for ExtractLane as Splat does not create | |
| 469 // interesting SIMD values. | |
| 470 // | |
| 471 // SetLocal(1, I32x4Splat(Local(0))); | |
| 472 // For each lane index | |
| 473 // if(Local(0) != I32x4ExtractLane(Local(1), index) | |
| 474 // return 0 | |
| 475 // | |
| 476 // return 1 | |
| 477 WasmRunner<int32_t, int32_t> r(kExecuteCompiled); | |
| 478 byte lane_val = 0; | |
| 479 byte simd = r.AllocateLocal(kWasmS128); | |
| 480 BUILD(r, | |
| 481 WASM_SET_LOCAL(simd, WASM_SIMD_I32x4_SPLAT(WASM_GET_LOCAL(lane_val))), | |
| 482 WASM_SIMD_CHECK_SPLAT4(I32x4, simd, I32, lane_val), WASM_ONE); | |
| 483 | |
| 484 FOR_INT32_INPUTS(i) { CHECK_EQ(1, r.Call(*i)); } | |
| 485 } | |
| 486 | |
| 487 WASM_EXEC_TEST(I32x4ReplaceLane) { | |
| 488 FLAG_wasm_simd_prototype = true; | |
| 489 WasmRunner<int32_t, int32_t, int32_t> r(kExecuteCompiled); | |
| 490 byte old_val = 0; | |
| 491 byte new_val = 1; | |
| 492 byte simd = r.AllocateLocal(kWasmS128); | |
| 493 BUILD(r, WASM_SET_LOCAL(simd, WASM_SIMD_I32x4_SPLAT(WASM_GET_LOCAL(old_val))), | |
| 494 WASM_SET_LOCAL(simd, | |
| 495 WASM_SIMD_I32x4_REPLACE_LANE(0, WASM_GET_LOCAL(simd), | |
| 496 WASM_GET_LOCAL(new_val))), | |
| 497 WASM_SIMD_CHECK4(I32x4, simd, I32, new_val, old_val, old_val, old_val), | |
| 498 WASM_SET_LOCAL(simd, | |
| 499 WASM_SIMD_I32x4_REPLACE_LANE(1, WASM_GET_LOCAL(simd), | |
| 500 WASM_GET_LOCAL(new_val))), | |
| 501 WASM_SIMD_CHECK4(I32x4, simd, I32, new_val, new_val, old_val, old_val), | |
| 502 WASM_SET_LOCAL(simd, | |
| 503 WASM_SIMD_I32x4_REPLACE_LANE(2, WASM_GET_LOCAL(simd), | |
| 504 WASM_GET_LOCAL(new_val))), | |
| 505 WASM_SIMD_CHECK4(I32x4, simd, I32, new_val, new_val, new_val, old_val), | |
| 506 WASM_SET_LOCAL(simd, | |
| 507 WASM_SIMD_I32x4_REPLACE_LANE(3, WASM_GET_LOCAL(simd), | |
| 508 WASM_GET_LOCAL(new_val))), | |
| 509 WASM_SIMD_CHECK_SPLAT4(I32x4, simd, I32, new_val), WASM_ONE); | |
| 510 | |
| 511 CHECK_EQ(1, r.Call(1, 2)); | |
| 512 } | |
| 513 | 106 |
| 514 #if V8_TARGET_ARCH_ARM | 107 #if V8_TARGET_ARCH_ARM |
| 515 | 108 |
| 516 WASM_EXEC_TEST(I16x8Splat) { | 109 WASM_EXEC_TEST(I16x8Splat) { |
| 517 FLAG_wasm_simd_prototype = true; | 110 FLAG_wasm_simd_prototype = true; |
| 518 | 111 |
| 519 WasmRunner<int32_t, int32_t> r(kExecuteCompiled); | 112 WasmRunner<int32_t, int32_t> r(kExecuteCompiled); |
| 520 byte lane_val = 0; | 113 byte lane_val = 0; |
| 521 byte simd = r.AllocateLocal(kWasmS128); | 114 byte simd = r.AllocateLocal(kWasmS128); |
| 522 BUILD(r, | 115 BUILD(r, |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 769 WASM_SIMD_CHECK_SPLAT4(I32x4, simd, I32, expected), WASM_ONE); | 362 WASM_SIMD_CHECK_SPLAT4(I32x4, simd, I32, expected), WASM_ONE); |
| 770 | 363 |
| 771 FOR_INT32_INPUTS(i) { CHECK_EQ(1, r.Call(*i, expected_op(*i))); } | 364 FOR_INT32_INPUTS(i) { CHECK_EQ(1, r.Call(*i, expected_op(*i))); } |
| 772 } | 365 } |
| 773 | 366 |
| 774 WASM_EXEC_TEST(I32x4Neg) { RunI32x4UnOpTest(kExprI32x4Neg, Negate); } | 367 WASM_EXEC_TEST(I32x4Neg) { RunI32x4UnOpTest(kExprI32x4Neg, Negate); } |
| 775 | 368 |
| 776 WASM_EXEC_TEST(S128Not) { RunI32x4UnOpTest(kExprS128Not, Not); } | 369 WASM_EXEC_TEST(S128Not) { RunI32x4UnOpTest(kExprS128Not, Not); } |
| 777 #endif // V8_TARGET_ARCH_ARM | 370 #endif // V8_TARGET_ARCH_ARM |
| 778 | 371 |
| 779 void RunI32x4BinOpTest(WasmOpcode simd_op, Int32BinOp expected_op) { | |
| 780 FLAG_wasm_simd_prototype = true; | |
| 781 WasmRunner<int32_t, int32_t, int32_t, int32_t> r(kExecuteCompiled); | |
| 782 byte a = 0; | |
| 783 byte b = 1; | |
| 784 byte expected = 2; | |
| 785 byte simd0 = r.AllocateLocal(kWasmS128); | |
| 786 byte simd1 = r.AllocateLocal(kWasmS128); | |
| 787 BUILD(r, WASM_SET_LOCAL(simd0, WASM_SIMD_I32x4_SPLAT(WASM_GET_LOCAL(a))), | |
| 788 WASM_SET_LOCAL(simd1, WASM_SIMD_I32x4_SPLAT(WASM_GET_LOCAL(b))), | |
| 789 WASM_SET_LOCAL(simd1, WASM_SIMD_BINOP(simd_op, WASM_GET_LOCAL(simd0), | |
| 790 WASM_GET_LOCAL(simd1))), | |
| 791 WASM_SIMD_CHECK_SPLAT4(I32x4, simd1, I32, expected), WASM_ONE); | |
| 792 | |
| 793 FOR_INT32_INPUTS(i) { | |
| 794 FOR_INT32_INPUTS(j) { CHECK_EQ(1, r.Call(*i, *j, expected_op(*i, *j))); } | |
| 795 } | |
| 796 } | |
| 797 | |
| 798 WASM_EXEC_TEST(I32x4Add) { RunI32x4BinOpTest(kExprI32x4Add, Add); } | 372 WASM_EXEC_TEST(I32x4Add) { RunI32x4BinOpTest(kExprI32x4Add, Add); } |
| 799 | 373 |
| 800 WASM_EXEC_TEST(I32x4Sub) { RunI32x4BinOpTest(kExprI32x4Sub, Sub); } | 374 WASM_EXEC_TEST(I32x4Sub) { RunI32x4BinOpTest(kExprI32x4Sub, Sub); } |
| 801 | 375 |
| 802 #if V8_TARGET_ARCH_ARM | 376 #if V8_TARGET_ARCH_ARM |
| 803 WASM_EXEC_TEST(I32x4Mul) { RunI32x4BinOpTest(kExprI32x4Mul, Mul); } | 377 WASM_EXEC_TEST(I32x4Mul) { RunI32x4BinOpTest(kExprI32x4Mul, Mul); } |
| 804 | 378 |
| 805 WASM_EXEC_TEST(I32x4Min) { RunI32x4BinOpTest(kExprI32x4MinS, Minimum); } | 379 WASM_EXEC_TEST(I32x4Min) { RunI32x4BinOpTest(kExprI32x4MinS, Minimum); } |
| 806 | 380 |
| 807 WASM_EXEC_TEST(I32x4Max) { RunI32x4BinOpTest(kExprI32x4MaxS, Maximum); } | 381 WASM_EXEC_TEST(I32x4Max) { RunI32x4BinOpTest(kExprI32x4MaxS, Maximum); } |
| (...skipping 420 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1228 WASM_SIMD_CHECK_LANE(I##format, mask, I32, val1, 2), \ | 802 WASM_SIMD_CHECK_LANE(I##format, mask, I32, val1, 2), \ |
| 1229 WASM_SIMD_CHECK_LANE(I##format, mask, I32, val2, 3), WASM_ONE); \ | 803 WASM_SIMD_CHECK_LANE(I##format, mask, I32, val2, 3), WASM_ONE); \ |
| 1230 \ | 804 \ |
| 1231 CHECK_EQ(1, r.Call(0x12, 0x34)); \ | 805 CHECK_EQ(1, r.Call(0x12, 0x34)); \ |
| 1232 } | 806 } |
| 1233 | 807 |
| 1234 WASM_SIMD_SELECT_TEST(32x4) | 808 WASM_SIMD_SELECT_TEST(32x4) |
| 1235 WASM_SIMD_SELECT_TEST(16x8) | 809 WASM_SIMD_SELECT_TEST(16x8) |
| 1236 WASM_SIMD_SELECT_TEST(8x16) | 810 WASM_SIMD_SELECT_TEST(8x16) |
| 1237 #endif // V8_TARGET_ARCH_ARM | 811 #endif // V8_TARGET_ARCH_ARM |
| 812 } // namespace test_wasm_simd_common |
| OLD | NEW |