asmjit_test_unicompiler.cpp (273685B)
1 // This file is part of AsmJit project <https://asmjit.com> 2 // 3 // See <asmjit/core.h> or LICENSE.md for license and copyright information 4 // SPDX-License-Identifier: Zlib 5 6 #include <asmjit/ujit.h> 7 8 #include <algorithm> 9 #include <cmath> 10 #include <limits> 11 12 #include "../commons/asmjitutils.h" 13 #include "../commons/random.h" 14 15 static void print_app_info() noexcept { 16 printf("AsmJit UniCompiler Test Suite v%u.%u.%u [Arch=%s] [Mode=%s]\n\n", 17 unsigned((ASMJIT_LIBRARY_VERSION >> 16) ), 18 unsigned((ASMJIT_LIBRARY_VERSION >> 8) & 0xFF), 19 unsigned((ASMJIT_LIBRARY_VERSION ) & 0xFF), 20 asmjit_arch_as_string(asmjit::Arch::kHost), 21 asmjit_build_type() 22 ); 23 } 24 25 #if !defined(ASMJIT_NO_UJIT) && !defined(ASMJIT_NO_JIT) 26 27 #include "broken.h" 28 29 namespace UniCompilerTests { 30 31 using namespace asmjit; 32 using namespace asmjit::ujit; 33 34 // ujit::UniCompiler - Tests - Constants 35 // ===================================== 36 37 static constexpr uint64_t kRandomSeed = 0x1234u; 38 static constexpr uint32_t kTestIterCount = 1000u; 39 40 static ASMJIT_INLINE_CONSTEXPR uint32_t byte_width_from_vec_width(VecWidth vw) noexcept { 41 return 16u << uint32_t(vw); 42 } 43 44 // ujit::UniCompiler - Tests - MulAdd 45 // ================================== 46 47 #if defined(ASMJIT_UJIT_X86) 48 49 float fadd(float a, float b) noexcept; 50 float fsub(float a, float b) noexcept; 51 float fmul(float a, float b) noexcept; 52 float fdiv(float a, float b) noexcept; 53 float fsqrt(float a) noexcept; 54 float fmadd_nofma_ref(float a, float b, float c) noexcept; 55 float fmadd_fma_ref(float a, float b, float c) noexcept; 56 57 double fadd(double a, double b) noexcept; 58 double fsub(double a, double b) noexcept; 59 double fmul(double a, double b) noexcept; 60 double fdiv(double a, double b) noexcept; 61 double fsqrt(double a) noexcept; 62 double fmadd_nofma_ref(double a, double b, double c) noexcept; 63 double fmadd_fma_ref(double a, double b, double c) noexcept; 64 65 void madd_fma_check_valgrind_bug(const float a[4], const float b[4], const float c[4], float dst[4]) noexcept; 66 67 #else 68 69 static ASMJIT_NOINLINE float fadd(float a, float b) noexcept { return a + b; } 70 static ASMJIT_NOINLINE float fsub(float a, float b) noexcept { return a - b; } 71 static ASMJIT_NOINLINE float fmul(float a, float b) noexcept { return a * b; } 72 static ASMJIT_NOINLINE float fdiv(float a, float b) noexcept { return a / b; } 73 static ASMJIT_NOINLINE float fsqrt(float a) noexcept { return std::sqrt(a); } 74 static ASMJIT_NOINLINE float fmadd_nofma_ref(float a, float b, float c) noexcept { return a * b + c; } 75 static ASMJIT_NOINLINE float fmadd_fma_ref(float a, float b, float c) noexcept { return std::fma(a, b, c); } 76 77 static ASMJIT_NOINLINE double fadd(double a, double b) noexcept { return a + b; } 78 static ASMJIT_NOINLINE double fsub(double a, double b) noexcept { return a - b; } 79 static ASMJIT_NOINLINE double fmul(double a, double b) noexcept { return a * b; } 80 static ASMJIT_NOINLINE double fdiv(double a, double b) noexcept { return a / b; } 81 static ASMJIT_NOINLINE double fsqrt(double a) noexcept { return std::sqrt(a); } 82 static ASMJIT_NOINLINE double fmadd_nofma_ref(double a, double b, double c) noexcept { return fadd(fmul(a, b), c); } 83 static ASMJIT_NOINLINE double fmadd_fma_ref(double a, double b, double c) noexcept { return std::fma(a, b, c); } 84 85 #endif 86 87 static ASMJIT_INLINE float fsign(float a) noexcept { return Support::bit_cast<float>(Support::bit_cast<uint32_t>(a) & (uint32_t(1) << 31)); } 88 static ASMJIT_INLINE double fsign(double a) noexcept { return Support::bit_cast<double>(Support::bit_cast<uint64_t>(a) & (uint64_t(1) << 63)); } 89 90 static ASMJIT_INLINE float fxor(float a, float b) noexcept { return Support::bit_cast<float>(Support::bit_cast<uint32_t>(a) ^ Support::bit_cast<uint32_t>(b)); } 91 static ASMJIT_INLINE double fxor(double a, double b) noexcept { return Support::bit_cast<double>(Support::bit_cast<uint64_t>(a) ^ Support::bit_cast<uint64_t>(b)); } 92 93 // ujit::UniCompiler - Tests - Types 94 // ================================= 95 96 struct Variation { 97 uint32_t value; 98 99 [[nodiscard]] ASMJIT_INLINE_CONSTEXPR bool operator==(uint32_t v) const noexcept { return value == v; } 100 [[nodiscard]] ASMJIT_INLINE_CONSTEXPR bool operator!=(uint32_t v) const noexcept { return value != v; } 101 [[nodiscard]] ASMJIT_INLINE_CONSTEXPR bool operator<=(uint32_t v) const noexcept { return value <= v; } 102 [[nodiscard]] ASMJIT_INLINE_CONSTEXPR bool operator< (uint32_t v) const noexcept { return value < v; } 103 [[nodiscard]] ASMJIT_INLINE_CONSTEXPR bool operator>=(uint32_t v) const noexcept { return value >= v; } 104 [[nodiscard]] ASMJIT_INLINE_CONSTEXPR bool operator> (uint32_t v) const noexcept { return value > v; } 105 }; 106 107 // ujit::UniCompiler - Tests - JIT Function Prototypes 108 // =================================================== 109 110 typedef uint32_t (*TestCondRRFunc)(int32_t a, int32_t b); 111 typedef uint32_t (*TestCondRIFunc)(int32_t a); 112 113 typedef void (*TestMFunc)(void* ptr); 114 typedef uintptr_t (*TestRMFunc)(uintptr_t reg, void* ptr); 115 typedef void (*TestMRFunc)(void* ptr, uintptr_t reg); 116 117 typedef uint32_t (*TestRRFunc)(uint32_t a); 118 typedef uint32_t (*TestRRRFunc)(uint32_t a, uint32_t b); 119 typedef uint32_t (*TestRRIFunc)(uint32_t a); 120 121 typedef void (*TestVVFunc)(void* dst, const void* src); 122 typedef void (*TestVVVFunc)(void* dst, const void* src1, const void* src2); 123 typedef void (*TestVVVVFunc)(void* dst, const void* src1, const void* src2, const void* src3); 124 125 // ujit::UniCompiler - Tests - JIT Context Error Handler 126 // ===================================================== 127 128 class TestErrorHandler : public ErrorHandler { 129 public: 130 TestErrorHandler() noexcept {} 131 ~TestErrorHandler() noexcept override {} 132 133 void handle_error(Error err, const char* message, BaseEmitter* origin) override { 134 Support::maybe_unused(origin); 135 EXPECT_EQ(err, Error::kOk) 136 .message("AsmJit Error: %s", message); 137 } 138 }; 139 // ujit::UniCompiler - Tests - JIT Context for Testing 140 // =================================================== 141 142 class JitContext { 143 public: 144 JitRuntime rt; 145 CpuFeatures features {}; 146 CpuHints cpu_hints {}; 147 148 #if !defined(ASMJIT_NO_LOGGING) 149 StringLogger logger; 150 #endif // !ASMJIT_NO_LOGGING 151 152 TestErrorHandler eh; 153 CodeHolder code; 154 BackendCompiler cc; 155 156 void prepare() noexcept { 157 code.reset(); 158 code.init(rt.environment()); 159 code.set_error_handler(&eh); 160 161 #if !defined(ASMJIT_NO_LOGGING) 162 logger.clear(); 163 code.set_logger(&logger); 164 #endif // !ASMJIT_NO_LOGGING 165 166 code.attach(&cc); 167 cc.add_diagnostic_options(DiagnosticOptions::kRAAnnotate); 168 cc.add_diagnostic_options(DiagnosticOptions::kValidateAssembler); 169 cc.add_diagnostic_options(DiagnosticOptions::kValidateIntermediate); 170 } 171 172 template<typename Fn> 173 Fn finish() { 174 Fn fn; 175 EXPECT_EQ(cc.finalize(), Error::kOk); 176 EXPECT_EQ(rt.add(&fn, &code), Error::kOk); 177 code.reset(); 178 return fn; 179 } 180 181 #if !defined(ASMJIT_NO_LOGGING) 182 const char* logger_content() const noexcept { return logger.data(); } 183 #else 184 const char* logger_content() const noexcept { return "<ASMJIT_NO_LOGGING>"; } 185 #endif 186 }; 187 188 // ujit::UniCompiler - Tests - Conditional Operations - Functions 189 // ============================================================== 190 191 static TestCondRRFunc create_func_cond_rr(JitContext& ctx, UniOpCond op, CondCode cond_code, uint32_t variation) { 192 ctx.prepare(); 193 194 UniCompiler uc(&ctx.cc, ctx.features, ctx.cpu_hints); 195 uc.init_vec_width(VecWidth::k128); 196 197 FuncNode* node = uc.add_func(FuncSignature::build<uint32_t, int32_t, int32_t>()); 198 EXPECT_NOT_NULL(node); 199 200 Gp a = uc.new_gp32("a"); 201 Gp b = uc.new_gp32("b"); 202 Gp result = uc.new_gp32("result"); 203 204 node->set_arg(0, a); 205 node->set_arg(1, b); 206 207 switch (variation) { 208 case 0: { 209 // Test a conditional branch based on the given condition. 210 Label done = uc.new_label(); 211 uc.mov(result, 1); 212 uc.j(done, UniCondition(op, cond_code, a, b)); 213 uc.mov(result, 0); 214 uc.bind(done); 215 break; 216 } 217 218 case 1: { 219 // Test a cmov functionality. 220 Gp true_value = uc.new_gp32("true_value"); 221 uc.mov(result, 0); 222 uc.mov(true_value, 1); 223 uc.cmov(result, true_value, UniCondition(op, cond_code, a, b)); 224 break; 225 } 226 227 case 2: { 228 // Test a select functionality. 229 Gp false_value = uc.new_gp32("false_value"); 230 Gp true_value = uc.new_gp32("true_value"); 231 uc.mov(false_value, 0); 232 uc.mov(true_value, 1); 233 uc.select(result, true_value, false_value, UniCondition(op, cond_code, a, b)); 234 break; 235 } 236 } 237 238 uc.ret(result); 239 uc.end_func(); 240 241 return ctx.finish<TestCondRRFunc>(); 242 } 243 244 static TestCondRIFunc create_func_cond_ri(JitContext& ctx, UniOpCond op, CondCode cond_code, Imm b_imm) { 245 ctx.prepare(); 246 247 UniCompiler uc(&ctx.cc, ctx.features, ctx.cpu_hints); 248 uc.init_vec_width(VecWidth::k128); 249 250 FuncNode* node = uc.add_func(FuncSignature::build<uint32_t, int32_t>()); 251 EXPECT_NOT_NULL(node); 252 253 Gp a = uc.new_gp32("a"); 254 Gp result = uc.new_gp32("result"); 255 Label done = uc.new_label(); 256 257 node->set_arg(0, a); 258 uc.mov(result, 1); 259 uc.j(done, UniCondition(op, cond_code, a, b_imm)); 260 uc.mov(result, 0); 261 uc.bind(done); 262 uc.ret(result); 263 264 uc.end_func(); 265 return ctx.finish<TestCondRIFunc>(); 266 } 267 268 // ujit::UniCompiler - Tests - Conditional Operations - Runner 269 // =========================================================== 270 271 static ASMJIT_NOINLINE void test_conditional_op(JitContext& ctx, UniOpCond op, CondCode cond_code, int32_t a, int32_t b, bool expected) { 272 for (uint32_t variation = 0; variation < 3; variation++) { 273 TestCondRRFunc fn_rr = create_func_cond_rr(ctx, op, cond_code, variation); 274 TestCondRIFunc fn_ri = create_func_cond_ri(ctx, op, cond_code, b); 275 276 uint32_t observed_rr = fn_rr(a, b); 277 EXPECT_EQ(observed_rr, uint32_t(expected)) 278 .message("Operation failed (RR):\n" 279 " Input #1: %d\n" 280 " Input #2: %d\n" 281 " Expected: %d\n" 282 " Observed: %d\n" 283 "Assembly:\n%s", 284 a, 285 b, 286 uint32_t(expected), 287 observed_rr, 288 ctx.logger_content()); 289 290 uint32_t observed_ri = fn_ri(a); 291 EXPECT_EQ(observed_ri, uint32_t(expected)) 292 .message("Operation failed (RI):\n" 293 " Input #1: %d\n" 294 " Input #2: %d\n" 295 " Expected: %d\n" 296 " Observed: %d\n" 297 "Assembly:\n%s", 298 a, 299 b, 300 uint32_t(expected), 301 observed_ri, 302 ctx.logger_content()); 303 304 ctx.rt.reset(); 305 } 306 } 307 308 static ASMJIT_NOINLINE void test_cond_ops(JitContext& ctx) { 309 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kEqual, 0, 0, true); 310 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kEqual, 1, 1, true); 311 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kEqual, 1, 2, false); 312 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kEqual, 100, 31, false); 313 314 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kNotEqual, 0, 0, false); 315 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kNotEqual, 1, 1, false); 316 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kNotEqual, 1, 2, true); 317 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kNotEqual, 100, 31, true); 318 319 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kUnsignedGT, 0, 0, false); 320 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kUnsignedGT, 1, 0, true); 321 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kUnsignedGT, 111111, 0, true); 322 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kUnsignedGT, 111111, 222, true); 323 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kUnsignedGT, 222, 111111, false); 324 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kUnsignedGT, 222, 111, true); 325 326 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kUnsignedGE, 0, 0, true); 327 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kUnsignedGE, 1, 0, true); 328 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kUnsignedGE, 111111, 0, true); 329 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kUnsignedGE, 111111, 111111, true); 330 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kUnsignedGE, 111111, 222, true); 331 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kUnsignedGE, 222, 111111, false); 332 333 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kUnsignedLT, 0, 0, false); 334 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kUnsignedLT, 1, 0, false); 335 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kUnsignedLT, 0, 1, true); 336 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kUnsignedLT, 111111, 0, false); 337 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kUnsignedLT, 111111, 222, false); 338 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kUnsignedLT, 222, 111111, true); 339 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kUnsignedLT, 222, 111, false); 340 341 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kUnsignedLE, 0, 0, true); 342 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kUnsignedLE, 1, 0, false); 343 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kUnsignedLE, 0, 1, true); 344 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kUnsignedLE, 111111, 0, false); 345 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kUnsignedLE, 111111, 222, false); 346 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kUnsignedLE, 222, 111111, true); 347 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kUnsignedLE, 22222, 22222, true); 348 349 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kSignedGT, 0, 0, false); 350 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kSignedGT, 1, 0, true); 351 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kSignedGT, 111111, 0, true); 352 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kSignedGT, 111111, -222, true); 353 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kSignedGT, -222, 111111, false); 354 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kSignedGT, -222, -111, false); 355 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kSignedGT, -111, -1, false); 356 357 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kSignedGE, 0, 0, true); 358 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kSignedGE, 1, 0, true); 359 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kSignedGE, 111111, 0, true); 360 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kSignedGE, 111111, 111111, true); 361 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kSignedGE, 111111, -222, true); 362 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kSignedGE, -222, 111111, false); 363 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kSignedGE, -111, -1, false); 364 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kSignedGE, -111, -111, true); 365 366 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kSignedLT, 0, 0, false); 367 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kSignedLT, 1, 0, false); 368 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kSignedLT, 111111, 0, false); 369 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kSignedLT, 111111, -222, false); 370 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kSignedLT, -222, 111111, true); 371 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kSignedLT, -222, -111, true); 372 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kSignedLT, -111, -1, true); 373 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kSignedLT, -1, -1, false); 374 375 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kSignedLE, 0, 0, true); 376 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kSignedLE, 1, 0, false); 377 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kSignedLE, 111111, 0, false); 378 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kSignedLE, 111111, -222, false); 379 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kSignedLE, -222, 111111, true); 380 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kSignedLE, -222, -111, true); 381 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kSignedLE, -111, -1, true); 382 test_conditional_op(ctx, UniOpCond::kCompare, CondCode::kSignedLE, -1, -1, true); 383 384 test_conditional_op(ctx, UniOpCond::kTest, CondCode::kZero, 0, 0, true); 385 test_conditional_op(ctx, UniOpCond::kTest, CondCode::kZero, 1, 0, true); 386 test_conditional_op(ctx, UniOpCond::kTest, CondCode::kZero, 111111, 0, true); 387 test_conditional_op(ctx, UniOpCond::kTest, CondCode::kZero, 111111, -222, false); 388 test_conditional_op(ctx, UniOpCond::kTest, CondCode::kZero, -222, 111111, false); 389 390 test_conditional_op(ctx, UniOpCond::kTest, CondCode::kNotZero, 0, 0, false); 391 test_conditional_op(ctx, UniOpCond::kTest, CondCode::kNotZero, 1, 0, false); 392 test_conditional_op(ctx, UniOpCond::kTest, CondCode::kNotZero, 111111, 0, false); 393 test_conditional_op(ctx, UniOpCond::kTest, CondCode::kNotZero, 111111, -222, true); 394 test_conditional_op(ctx, UniOpCond::kTest, CondCode::kNotZero, -222, 111111, true); 395 396 test_conditional_op(ctx, UniOpCond::kBitTest, CondCode::kBTZero, int32_t(0x0), 0, true); 397 test_conditional_op(ctx, UniOpCond::kBitTest, CondCode::kBTZero, int32_t(0x1), 0, false); 398 test_conditional_op(ctx, UniOpCond::kBitTest, CondCode::kBTZero, int32_t(0xFF), 7, false); 399 test_conditional_op(ctx, UniOpCond::kBitTest, CondCode::kBTZero, int32_t(0xFF), 9, true); 400 test_conditional_op(ctx, UniOpCond::kBitTest, CondCode::kBTZero, int32_t(0xFFFFFFFF), 31, false); 401 test_conditional_op(ctx, UniOpCond::kBitTest, CondCode::kBTZero, int32_t(0x7FFFFFFF), 31, true); 402 403 test_conditional_op(ctx, UniOpCond::kBitTest, CondCode::kBTNotZero, int32_t(0x0), 0, false); 404 test_conditional_op(ctx, UniOpCond::kBitTest, CondCode::kBTNotZero, int32_t(0x1), 0, true); 405 test_conditional_op(ctx, UniOpCond::kBitTest, CondCode::kBTNotZero, int32_t(0xFF), 7, true); 406 test_conditional_op(ctx, UniOpCond::kBitTest, CondCode::kBTNotZero, int32_t(0xFF), 9, false); 407 test_conditional_op(ctx, UniOpCond::kBitTest, CondCode::kBTNotZero, int32_t(0xFFFFFFFF), 31, true); 408 test_conditional_op(ctx, UniOpCond::kBitTest, CondCode::kBTNotZero, int32_t(0x7FFFFFFF), 31, false); 409 410 test_conditional_op(ctx, UniOpCond::kAssignAnd, CondCode::kZero, int32_t(0x00000000), int32_t(0x00000000), true); 411 test_conditional_op(ctx, UniOpCond::kAssignAnd, CondCode::kZero, int32_t(0x00000001), int32_t(0x00000000), true); 412 test_conditional_op(ctx, UniOpCond::kAssignAnd, CondCode::kZero, int32_t(0x000000FF), int32_t(0x00000000), true); 413 test_conditional_op(ctx, UniOpCond::kAssignAnd, CondCode::kZero, int32_t(0x000000FF), int32_t(0x000000FF), false); 414 test_conditional_op(ctx, UniOpCond::kAssignAnd, CondCode::kZero, int32_t(0xFFFFFFFF), int32_t(0xFF000000), false); 415 test_conditional_op(ctx, UniOpCond::kAssignAnd, CondCode::kZero, int32_t(0x7FFFFFFF), int32_t(0x80000000), true); 416 417 test_conditional_op(ctx, UniOpCond::kAssignAnd, CondCode::kNotZero, int32_t(0x00000000), int32_t(0x00000000), false); 418 test_conditional_op(ctx, UniOpCond::kAssignAnd, CondCode::kNotZero, int32_t(0x00000001), int32_t(0x00000000), false); 419 test_conditional_op(ctx, UniOpCond::kAssignAnd, CondCode::kNotZero, int32_t(0x000000FF), int32_t(0x00000000), false); 420 test_conditional_op(ctx, UniOpCond::kAssignAnd, CondCode::kNotZero, int32_t(0x000000FF), int32_t(0x000000FF), true); 421 test_conditional_op(ctx, UniOpCond::kAssignAnd, CondCode::kNotZero, int32_t(0xFFFFFFFF), int32_t(0xFF000000), true); 422 test_conditional_op(ctx, UniOpCond::kAssignAnd, CondCode::kNotZero, int32_t(0x7FFFFFFF), int32_t(0x80000000), false); 423 424 test_conditional_op(ctx, UniOpCond::kAssignOr, CondCode::kZero, int32_t(0x00000000), int32_t(0x00000000), true); 425 test_conditional_op(ctx, UniOpCond::kAssignOr, CondCode::kZero, int32_t(0x00000001), int32_t(0x00000000), false); 426 test_conditional_op(ctx, UniOpCond::kAssignOr, CondCode::kZero, int32_t(0x000000FF), int32_t(0x00000000), false); 427 test_conditional_op(ctx, UniOpCond::kAssignOr, CondCode::kZero, int32_t(0x000000FF), int32_t(0x000000FF), false); 428 test_conditional_op(ctx, UniOpCond::kAssignOr, CondCode::kZero, int32_t(0xFFFFFFFF), int32_t(0xFF000000), false); 429 test_conditional_op(ctx, UniOpCond::kAssignOr, CondCode::kZero, int32_t(0x7FFFFFFF), int32_t(0x80000000), false); 430 431 test_conditional_op(ctx, UniOpCond::kAssignOr, CondCode::kNotZero, int32_t(0x00000000), int32_t(0x00000000), false); 432 test_conditional_op(ctx, UniOpCond::kAssignOr, CondCode::kNotZero, int32_t(0x00000001), int32_t(0x00000000), true); 433 test_conditional_op(ctx, UniOpCond::kAssignOr, CondCode::kNotZero, int32_t(0x000000FF), int32_t(0x00000000), true); 434 test_conditional_op(ctx, UniOpCond::kAssignOr, CondCode::kNotZero, int32_t(0x000000FF), int32_t(0x000000FF), true); 435 test_conditional_op(ctx, UniOpCond::kAssignOr, CondCode::kNotZero, int32_t(0xFFFFFFFF), int32_t(0xFF000000), true); 436 test_conditional_op(ctx, UniOpCond::kAssignOr, CondCode::kNotZero, int32_t(0x7FFFFFFF), int32_t(0x80000000), true); 437 438 test_conditional_op(ctx, UniOpCond::kAssignXor, CondCode::kZero, int32_t(0x00000000), int32_t(0x00000000), true); 439 test_conditional_op(ctx, UniOpCond::kAssignXor, CondCode::kZero, int32_t(0x00000001), int32_t(0x00000000), false); 440 test_conditional_op(ctx, UniOpCond::kAssignXor, CondCode::kZero, int32_t(0x000000FF), int32_t(0x00000000), false); 441 test_conditional_op(ctx, UniOpCond::kAssignXor, CondCode::kZero, int32_t(0x000000FF), int32_t(0x000000FF), true); 442 test_conditional_op(ctx, UniOpCond::kAssignXor, CondCode::kZero, int32_t(0xFFFFFFFF), int32_t(0xFF000000), false); 443 test_conditional_op(ctx, UniOpCond::kAssignXor, CondCode::kZero, int32_t(0x7FFFFFFF), int32_t(0x80000000), false); 444 445 test_conditional_op(ctx, UniOpCond::kAssignXor, CondCode::kNotZero, int32_t(0x00000000), int32_t(0x00000000), false); 446 test_conditional_op(ctx, UniOpCond::kAssignXor, CondCode::kNotZero, int32_t(0x00000001), int32_t(0x00000000), true); 447 test_conditional_op(ctx, UniOpCond::kAssignXor, CondCode::kNotZero, int32_t(0x000000FF), int32_t(0x00000000), true); 448 test_conditional_op(ctx, UniOpCond::kAssignXor, CondCode::kNotZero, int32_t(0x000000FF), int32_t(0x000000FF), false); 449 test_conditional_op(ctx, UniOpCond::kAssignXor, CondCode::kNotZero, int32_t(0xFFFFFFFF), int32_t(0xFF000000), true); 450 test_conditional_op(ctx, UniOpCond::kAssignXor, CondCode::kNotZero, int32_t(0x7FFFFFFF), int32_t(0x80000000), true); 451 452 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kZero, int32_t(0x00000000), int32_t(0x00000000), true); 453 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kZero, int32_t(0xFF000000), int32_t(0x01000000), true); 454 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kZero, int32_t(0x000000FF), int32_t(0x00000000), false); 455 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kZero, int32_t(0x000000FF), int32_t(0x000000FF), false); 456 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kZero, int32_t(0xFFFFFFFF), int32_t(0xFF000000), false); 457 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kZero, int32_t(0x7FFFFFFF), int32_t(0x80000000), false); 458 459 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kNotZero, int32_t(0x00000000), int32_t(0x00000000), false); 460 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kNotZero, int32_t(0xFF000000), int32_t(0x01000000), false); 461 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kNotZero, int32_t(0x000000FF), int32_t(0x00000000), true); 462 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kNotZero, int32_t(0x000000FF), int32_t(0x000000FF), true); 463 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kNotZero, int32_t(0xFFFFFFFF), int32_t(0xFF000000), true); 464 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kNotZero, int32_t(0x7FFFFFFF), int32_t(0x80000000), true); 465 466 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kCarry, int32_t(0x00000000), int32_t(0x00000000), false); 467 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kCarry, int32_t(0xFF000000), int32_t(0x01000000), true); 468 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kCarry, int32_t(0x000000FF), int32_t(0x00000000), false); 469 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kCarry, int32_t(0x000000FF), int32_t(0x000000FF), false); 470 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kCarry, int32_t(0xFFFFFFFF), int32_t(0xFF000000), true); 471 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kCarry, int32_t(0x7FFFFFFF), int32_t(0x80000000), false); 472 473 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kNotCarry, int32_t(0x00000000), int32_t(0x00000000), true); 474 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kNotCarry, int32_t(0xFF000000), int32_t(0x01000000), false); 475 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kNotCarry, int32_t(0x000000FF), int32_t(0x00000000), true); 476 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kNotCarry, int32_t(0x000000FF), int32_t(0x000000FF), true); 477 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kNotCarry, int32_t(0xFFFFFFFF), int32_t(0xFF000000), false); 478 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kNotCarry, int32_t(0x7FFFFFFF), int32_t(0x80000000), true); 479 480 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kSign, int32_t(0x00000000), int32_t(0x00000000), false); 481 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kSign, int32_t(0xFF000000), int32_t(0x01000000), false); 482 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kSign, int32_t(0x000000FF), int32_t(0x80000000), true); 483 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kSign, int32_t(0x000000FF), int32_t(0x800000FF), true); 484 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kSign, int32_t(0xFFFFFFFF), int32_t(0xFF000000), true); 485 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kSign, int32_t(0x7FFFFFFF), int32_t(0x80000000), true); 486 487 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kNotSign, int32_t(0x00000000), int32_t(0x00000000), true); 488 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kNotSign, int32_t(0xFF000000), int32_t(0x01000000), true); 489 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kNotSign, int32_t(0x000000FF), int32_t(0x80000000), false); 490 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kNotSign, int32_t(0x000000FF), int32_t(0x800000FF), false); 491 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kNotSign, int32_t(0xFFFFFFFF), int32_t(0xFF000000), false); 492 test_conditional_op(ctx, UniOpCond::kAssignAdd, CondCode::kNotSign, int32_t(0x7FFFFFFF), int32_t(0x80000000), false); 493 494 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kZero, int32_t(0x00000000), int32_t(0x00000000), true); 495 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kZero, int32_t(0xFF000000), int32_t(0x01000000), false); 496 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kZero, int32_t(0x000000FF), int32_t(0x00000000), false); 497 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kZero, int32_t(0x000000FF), int32_t(0x000000FF), true); 498 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kZero, int32_t(0xFFFFFFFF), int32_t(0xFF000000), false); 499 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kZero, int32_t(0x7FFFFFFF), int32_t(0x80000000), false); 500 501 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kNotZero, int32_t(0x00000000), int32_t(0x00000000), false); 502 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kNotZero, int32_t(0xFF000000), int32_t(0x01000000), true); 503 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kNotZero, int32_t(0x000000FF), int32_t(0x00000000), true); 504 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kNotZero, int32_t(0x000000FF), int32_t(0x000000FF), false); 505 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kNotZero, int32_t(0xFFFFFFFF), int32_t(0xFF000000), true); 506 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kNotZero, int32_t(0x7FFFFFFF), int32_t(0x80000000), true); 507 508 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kUnsignedLT, int32_t(0x00000000), int32_t(0x00000000), false); 509 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kUnsignedLT, int32_t(0xFF000000), int32_t(0x01000000), false); 510 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kUnsignedLT, int32_t(0x000000FF), int32_t(0x00000000), false); 511 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kUnsignedLT, int32_t(0x000000FF), int32_t(0x000000FF), false); 512 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kUnsignedLT, int32_t(0xFFFFFFFF), int32_t(0xFF000000), false); 513 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kUnsignedLT, int32_t(0x7FFFFFFF), int32_t(0x80000000), true); 514 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kUnsignedLT, int32_t(0x00000111), int32_t(0x0000F0FF), true); 515 516 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kUnsignedGE, int32_t(0x00000000), int32_t(0x00000000), true); 517 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kUnsignedGE, int32_t(0xFF000000), int32_t(0x01000000), true); 518 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kUnsignedGE, int32_t(0x000000FF), int32_t(0x00000000), true); 519 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kUnsignedGE, int32_t(0x000000FF), int32_t(0x000000FF), true); 520 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kUnsignedGE, int32_t(0xFFFFFFFF), int32_t(0xFF000000), true); 521 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kUnsignedGE, int32_t(0x7FFFFFFF), int32_t(0x80000000), false); 522 523 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kSign, int32_t(0x00000000), int32_t(0x00000000), false); 524 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kSign, int32_t(0x00000000), int32_t(0xFFFFFFFF), false); 525 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kSign, int32_t(0x00000000), int32_t(0x00000001), true); 526 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kSign, int32_t(0x00000001), int32_t(0x00000010), true); 527 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kSign, int32_t(0xFFFFFFFF), int32_t(0xFF000000), false); 528 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kSign, int32_t(0x7FFFFFFF), int32_t(0x80000000), true); 529 530 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kNotSign, int32_t(0x00000000), int32_t(0x00000000), true); 531 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kNotSign, int32_t(0x00000000), int32_t(0xFFFFFFFF), true); 532 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kNotSign, int32_t(0x00000000), int32_t(0x00000001), false); 533 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kNotSign, int32_t(0x00000001), int32_t(0x00000010), false); 534 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kNotSign, int32_t(0xFFFFFFFF), int32_t(0xFF000000), true); 535 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kNotSign, int32_t(0x7FFFFFFF), int32_t(0x80000000), false); 536 537 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kUnsignedGT, int32_t(0x00000000), int32_t(0x00000000), false); 538 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kUnsignedGT, int32_t(0xFF000000), int32_t(0x01000000), true); 539 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kUnsignedGT, int32_t(0x000000FF), int32_t(0x00000000), true); 540 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kUnsignedGT, int32_t(0x000000FF), int32_t(0x000000FF), false); 541 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kUnsignedGT, int32_t(0xFFFFFFFF), int32_t(0xFF000000), true); 542 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kUnsignedGT, int32_t(0x7FFFFFFF), int32_t(0x80000000), false); 543 test_conditional_op(ctx, UniOpCond::kAssignSub, CondCode::kUnsignedGT, int32_t(0x00000111), int32_t(0x0000F0FF), false); 544 545 test_conditional_op(ctx, UniOpCond::kAssignShr, CondCode::kZero, int32_t(0x00000000), 1, true); 546 test_conditional_op(ctx, UniOpCond::kAssignShr, CondCode::kZero, int32_t(0x000000FF), 8, true); 547 test_conditional_op(ctx, UniOpCond::kAssignShr, CondCode::kZero, int32_t(0x000000FF), 7, false); 548 test_conditional_op(ctx, UniOpCond::kAssignShr, CondCode::kZero, int32_t(0xFFFFFFFF), 31, false); 549 test_conditional_op(ctx, UniOpCond::kAssignShr, CondCode::kZero, int32_t(0x7FFFFFFF), 31, true); 550 551 test_conditional_op(ctx, UniOpCond::kAssignShr, CondCode::kNotZero, int32_t(0x00000000), 1, false); 552 test_conditional_op(ctx, UniOpCond::kAssignShr, CondCode::kNotZero, int32_t(0x000000FF), 8, false); 553 test_conditional_op(ctx, UniOpCond::kAssignShr, CondCode::kNotZero, int32_t(0x000000FF), 7, true); 554 test_conditional_op(ctx, UniOpCond::kAssignShr, CondCode::kNotZero, int32_t(0xFFFFFFFF), 31, true); 555 test_conditional_op(ctx, UniOpCond::kAssignShr, CondCode::kNotZero, int32_t(0x7FFFFFFF), 31, false); 556 } 557 558 // ujit::UniCompiler - Tests - M Operations - Functions 559 // ==================================================== 560 561 static TestMFunc create_func_m(JitContext& ctx, UniOpM op) { 562 ctx.prepare(); 563 564 UniCompiler uc(&ctx.cc, ctx.features, ctx.cpu_hints); 565 uc.init_vec_width(VecWidth::k128); 566 567 FuncNode* node = uc.add_func(FuncSignature::build<void, void*>()); 568 EXPECT_NOT_NULL(node); 569 570 Gp ptr = uc.new_gpz("ptr"); 571 node->set_arg(0, ptr); 572 uc.emit_m(op, mem_ptr(ptr)); 573 574 uc.end_func(); 575 return ctx.finish<TestMFunc>(); 576 } 577 578 // ujit::UniCompiler - Tests - M Operations - Runner 579 // ================================================= 580 581 static ASMJIT_NOINLINE void test_m_ops(JitContext& ctx) { 582 uint8_t buffer[8]; 583 584 TestMFunc fn_zero_u8 = create_func_m(ctx, UniOpM::kStoreZeroU8); 585 memcpy(buffer, "ABCDEFGH", 8); 586 fn_zero_u8(buffer + 0); 587 EXPECT_EQ(memcmp(buffer, "\0BCDEFGH", 8), 0); 588 fn_zero_u8(buffer + 5); 589 EXPECT_EQ(memcmp(buffer, "\0BCDE\0GH", 8), 0); 590 591 TestMFunc fn_zero_u16 = create_func_m(ctx, UniOpM::kStoreZeroU16); 592 memcpy(buffer, "ABCDEFGH", 8); 593 fn_zero_u16(buffer + 0); 594 EXPECT_EQ(memcmp(buffer, "\0\0CDEFGH", 8), 0); 595 fn_zero_u16(buffer + 4); 596 EXPECT_EQ(memcmp(buffer, "\0\0CD\0\0GH", 8), 0); 597 598 TestMFunc fn_zero_u32 = create_func_m(ctx, UniOpM::kStoreZeroU32); 599 memcpy(buffer, "ABCDEFGH", 8); 600 fn_zero_u32(buffer + 0); 601 EXPECT_EQ(memcmp(buffer, "\0\0\0\0EFGH", 8), 0); 602 fn_zero_u32(buffer + 4); 603 EXPECT_EQ(memcmp(buffer, "\0\0\0\0\0\0\0\0", 8), 0); 604 605 #if ASMJIT_ARCH_BITS >= 64 606 TestMFunc fn_zero_u64 = create_func_m(ctx, UniOpM::kStoreZeroU64); 607 memcpy(buffer, "ABCDEFGH", 8); 608 fn_zero_u64(buffer + 0); 609 EXPECT_EQ(memcmp(buffer, "\0\0\0\0\0\0\0\0", 8), 0); 610 #endif 611 612 TestMFunc fn_zero_reg = create_func_m(ctx, UniOpM::kStoreZeroReg); 613 memcpy(buffer, "ABCDEFGH", 8); 614 fn_zero_reg(buffer + 0); 615 #if ASMJIT_ARCH_BITS >= 64 616 EXPECT_EQ(memcmp(buffer, "\0\0\0\0\0\0\0\0", 8), 0); 617 #else 618 EXPECT_EQ(memcmp(buffer, "\0\0\0\0EFGH", 8), 0); 619 #endif 620 621 ctx.rt.reset(); 622 } 623 624 // ujit::UniCompiler - Tests - RM Operations - Functions 625 // ===================================================== 626 627 static TestRMFunc create_func_rm(JitContext& ctx, UniOpRM op) { 628 ctx.prepare(); 629 630 UniCompiler uc(&ctx.cc, ctx.features, ctx.cpu_hints); 631 uc.init_vec_width(VecWidth::k128); 632 633 FuncNode* node = uc.add_func(FuncSignature::build<uintptr_t, uintptr_t, void*>()); 634 EXPECT_NOT_NULL(node); 635 636 Gp reg = uc.new_gpz("reg"); 637 Gp ptr = uc.new_gpz("ptr"); 638 639 node->set_arg(0, reg); 640 node->set_arg(1, ptr); 641 642 uc.emit_rm(op, reg, mem_ptr(ptr)); 643 uc.ret(reg); 644 645 uc.end_func(); 646 return ctx.finish<TestRMFunc>(); 647 } 648 649 // ujit::UniCompiler - Tests - RM Operations - Runner 650 // ================================================== 651 652 static ASMJIT_NOINLINE void test_rm_ops(JitContext& ctx) { 653 union Mem { 654 uint8_t buffer[8]; 655 uint16_t u8; 656 uint16_t u16; 657 uint32_t u32; 658 uint64_t u64; 659 }; 660 661 Mem mem{}; 662 663 TestRMFunc fn_load_i8 = create_func_rm(ctx, UniOpRM::kLoadI8); 664 mem.u8 = uint8_t(int8_t(6)); 665 EXPECT_EQ(fn_load_i8(0, mem.buffer), uintptr_t(intptr_t(6))); 666 667 mem.u8 = uint8_t(int8_t(-6)); 668 EXPECT_EQ(fn_load_i8(0, mem.buffer), uintptr_t(intptr_t(-6))); 669 670 TestRMFunc fn_load_u8 = create_func_rm(ctx, UniOpRM::kLoadU8); 671 mem.u8 = uint8_t(0x80); 672 EXPECT_EQ(fn_load_u8(0, mem.buffer), 0x80u); 673 674 mem.u8 = uint8_t(0xFF); 675 EXPECT_EQ(fn_load_u8(0, mem.buffer), 0xFFu); 676 677 TestRMFunc fn_load_i16 = create_func_rm(ctx, UniOpRM::kLoadI16); 678 mem.u16 = uint16_t(int16_t(666)); 679 EXPECT_EQ(fn_load_i16(0, mem.buffer), uintptr_t(intptr_t(666))); 680 681 mem.u16 = uint16_t(int16_t(-666)); 682 EXPECT_EQ(fn_load_i16(0, mem.buffer), uintptr_t(intptr_t(-666))); 683 684 TestRMFunc fn_load_u16 = create_func_rm(ctx, UniOpRM::kLoadU16); 685 mem.u16 = uint16_t(0x8000); 686 EXPECT_EQ(fn_load_u16(0, mem.buffer), 0x8000u); 687 688 mem.u16 = uint16_t(0xFEED); 689 EXPECT_EQ(fn_load_u16(0, mem.buffer), 0xFEEDu); 690 691 TestRMFunc fn_load_i32 = create_func_rm(ctx, UniOpRM::kLoadI32); 692 mem.u32 = uint32_t(int32_t(666666)); 693 EXPECT_EQ(fn_load_i32(0, mem.buffer), uintptr_t(intptr_t(666666))); 694 695 mem.u32 = uint32_t(int32_t(-666666)); 696 EXPECT_EQ(fn_load_i32(0, mem.buffer), uintptr_t(intptr_t(-666666))); 697 698 TestRMFunc fn_load_u32 = create_func_rm(ctx, UniOpRM::kLoadU32); 699 mem.u32 = 0x12345678; 700 EXPECT_EQ(fn_load_u32(0, mem.buffer), uint32_t(0x12345678)); 701 702 #if ASMJIT_ARCH_BITS >= 64 703 TestRMFunc fn_load_i64 = create_func_rm(ctx, UniOpRM::kLoadI64); 704 mem.u64 = 0xF123456789ABCDEFu; 705 EXPECT_EQ(fn_load_i64(0, mem.buffer), 0xF123456789ABCDEFu); 706 707 TestRMFunc fn_load_u64 = create_func_rm(ctx, UniOpRM::kLoadU64); 708 mem.u64 = 0xF123456789ABCDEFu; 709 EXPECT_EQ(fn_load_u64(0, mem.buffer), 0xF123456789ABCDEFu); 710 #endif 711 712 TestRMFunc fn_load_reg = create_func_rm(ctx, UniOpRM::kLoadReg); 713 mem.u64 = 0xF123456789ABCDEFu; 714 #if ASMJIT_ARCH_BITS >= 64 715 EXPECT_EQ(fn_load_reg(0, mem.buffer), 0xF123456789ABCDEFu); 716 #else 717 EXPECT_EQ(fn_load_reg(0, mem.buffer), 0x89ABCDEFu); 718 #endif 719 720 TestRMFunc fn_load_merge_u8 = create_func_rm(ctx, UniOpRM::kLoadMergeU8); 721 mem.u8 = uint8_t(0xAA); 722 EXPECT_EQ(fn_load_merge_u8(0x1F2FFF00, mem.buffer), 0x1F2FFFAAu); 723 724 TestRMFunc fn_load_shift_u8 = create_func_rm(ctx, UniOpRM::kLoadShiftU8); 725 mem.u8 = uint8_t(0xAA); 726 EXPECT_EQ(fn_load_shift_u8(0x002FFF00, mem.buffer), 0x2FFF00AAu); 727 728 TestRMFunc fn_load_merge_u16 = create_func_rm(ctx, UniOpRM::kLoadMergeU16); 729 mem.u16 = uint16_t(0xAABB); 730 EXPECT_EQ(fn_load_merge_u16(0x1F2F0000, mem.buffer), 0x1F2FAABBu); 731 732 TestRMFunc fn_load_shift_u16 = create_func_rm(ctx, UniOpRM::kLoadShiftU16); 733 mem.u16 = uint16_t(0xAABB); 734 EXPECT_EQ(fn_load_shift_u16(0x00001F2F, mem.buffer), 0x1F2FAABBu); 735 736 ctx.rt.reset(); 737 } 738 739 // ujit::UniCompiler - Tests - MR Operations - Functions 740 // ===================================================== 741 742 static TestMRFunc create_func_mr(JitContext& ctx, UniOpMR op) { 743 ctx.prepare(); 744 745 UniCompiler uc(&ctx.cc, ctx.features, ctx.cpu_hints); 746 uc.init_vec_width(VecWidth::k128); 747 748 FuncNode* node = uc.add_func(FuncSignature::build<void, void*, uintptr_t>()); 749 EXPECT_NOT_NULL(node); 750 751 Gp ptr = uc.new_gpz("ptr"); 752 Gp reg = uc.new_gpz("reg"); 753 754 node->set_arg(0, ptr); 755 node->set_arg(1, reg); 756 757 uc.emit_mr(op, mem_ptr(ptr), reg); 758 759 uc.end_func(); 760 return ctx.finish<TestMRFunc>(); 761 } 762 763 // ujit::UniCompiler - Tests - MR Operations - Runner 764 // ================================================== 765 766 static ASMJIT_NOINLINE void test_mr_ops(JitContext& ctx) { 767 union Mem { 768 uint8_t buffer[8]; 769 uint16_t u8; 770 uint16_t u16; 771 uint32_t u32; 772 uint64_t u64; 773 }; 774 775 Mem mem{}; 776 777 TestMRFunc fn_store_u8 = create_func_mr(ctx, UniOpMR::kStoreU8); 778 memcpy(mem.buffer, "ABCDEFGH", 8); 779 fn_store_u8(mem.buffer, 0x7A); 780 EXPECT_EQ(memcmp(mem.buffer, "zBCDEFGH", 8), 0); 781 782 TestMRFunc fn_store_u16 = create_func_mr(ctx, UniOpMR::kStoreU16); 783 memcpy(mem.buffer, "ABCDEFGH", 8); 784 fn_store_u16(mem.buffer, 0x7A7A); 785 EXPECT_EQ(memcmp(mem.buffer, "zzCDEFGH", 8), 0); 786 787 TestMRFunc fn_store_u32 = create_func_mr(ctx, UniOpMR::kStoreU32); 788 memcpy(mem.buffer, "ABCDEFGH", 8); 789 fn_store_u32(mem.buffer, 0x7A7A7A7A); 790 EXPECT_EQ(memcmp(mem.buffer, "zzzzEFGH", 8), 0); 791 792 #if ASMJIT_ARCH_BITS >= 64 793 TestMRFunc fn_store_u64 = create_func_mr(ctx, UniOpMR::kStoreU64); 794 memcpy(mem.buffer, "ABCDEFGH", 8); 795 fn_store_u64(mem.buffer, 0x7A7A7A7A7A7A7A7A); 796 EXPECT_EQ(memcmp(mem.buffer, "zzzzzzzz", 8), 0); 797 #endif 798 799 TestMRFunc fn_store_reg = create_func_mr(ctx, UniOpMR::kStoreReg); 800 memcpy(mem.buffer, "ABCDEFGH", 8); 801 #if ASMJIT_ARCH_BITS >= 64 802 fn_store_reg(mem.buffer, 0x7A7A7A7A7A7A7A7A); 803 EXPECT_EQ(memcmp(mem.buffer, "zzzzzzzz", 8), 0); 804 #else 805 fn_store_reg(mem.buffer, 0x7A7A7A7A); 806 EXPECT_EQ(memcmp(mem.buffer, "zzzzEFGH", 8), 0); 807 #endif 808 809 TestMRFunc fn_add_u8 = create_func_mr(ctx, UniOpMR::kAddU8); 810 mem.u64 = 0; 811 mem.u8 = 42; 812 fn_add_u8(mem.buffer, 13); 813 EXPECT_EQ(mem.u8, 55u); 814 EXPECT_EQ(memcmp(mem.buffer + 1, "\0\0\0\0\0\0\0", 7), 0); 815 816 TestMRFunc fn_add_u16 = create_func_mr(ctx, UniOpMR::kAddU16); 817 mem.u64 = 0; 818 mem.u16 = 442; 819 fn_add_u16(mem.buffer, 335); 820 EXPECT_EQ(mem.u16, 777u); 821 EXPECT_EQ(memcmp(mem.buffer + 2, "\0\0\0\0\0\0", 6), 0); 822 823 TestMRFunc fn_add_u32 = create_func_mr(ctx, UniOpMR::kAddU32); 824 mem.u64 = 0; 825 mem.u32 = 442332; 826 fn_add_u32(mem.buffer, 335223); 827 EXPECT_EQ(mem.u32, 777555u); 828 EXPECT_EQ(memcmp(mem.buffer + 4, "\0\0\0\0", 4), 0); 829 830 #if ASMJIT_ARCH_BITS >= 64 831 TestMRFunc fn_add_u64 = create_func_mr(ctx, UniOpMR::kAddU64); 832 mem.u64 = 0xF123456789ABCDEFu; 833 fn_add_u64(mem.buffer, 0x0102030405060708u); 834 EXPECT_EQ(mem.u64, 0xF225486B8EB1D4F7u); 835 #endif 836 837 TestMRFunc fn_add_reg = create_func_mr(ctx, UniOpMR::kAddReg); 838 mem.u64 = 0xFFFFFFFFFFFFFFFF; 839 #if ASMJIT_ARCH_BITS >= 64 840 fn_add_reg(mem.buffer, 1); 841 EXPECT_EQ(mem.u64, 0u); 842 #else 843 mem.u32 = 0x01020304; 844 fn_add_reg(mem.buffer, 0x02030405); 845 EXPECT_EQ(mem.u32, 0x03050709u); 846 EXPECT_EQ(memcmp(mem.buffer + 4, "\xFF\xFF\xFF\xFF", 4), 0); 847 #endif 848 849 ctx.rt.reset(); 850 } 851 852 // ujit::UniCompiler - Tests - RR Operations - Functions 853 // ===================================================== 854 855 static TestRRFunc create_func_rr(JitContext& ctx, UniOpRR op) { 856 ctx.prepare(); 857 858 UniCompiler uc(&ctx.cc, ctx.features, ctx.cpu_hints); 859 uc.init_vec_width(VecWidth::k128); 860 861 FuncNode* node = uc.add_func(FuncSignature::build<uint32_t, uint32_t>()); 862 EXPECT_NOT_NULL(node); 863 864 Gp r = uc.new_gp32("r"); 865 node->set_arg(0, r); 866 uc.emit_2i(op, r, r); 867 uc.ret(r); 868 869 uc.end_func(); 870 return ctx.finish<TestRRFunc>(); 871 } 872 873 // ujit::UniCompiler - Tests - RR Operations - Runner 874 // ================================================== 875 876 static ASMJIT_NOINLINE void test_rr_ops(JitContext& ctx) { 877 TestRRFunc fn_abs = create_func_rr(ctx, UniOpRR::kAbs); 878 EXPECT_EQ(fn_abs(0u), 0u); 879 EXPECT_EQ(fn_abs(1u), 1u); 880 EXPECT_EQ(fn_abs(uint32_t(-1)), 1u); 881 EXPECT_EQ(fn_abs(uint32_t(-333)), 333u); 882 EXPECT_EQ(fn_abs(0x80000000u), 0x80000000u); 883 884 TestRRFunc fn_neg = create_func_rr(ctx, UniOpRR::kNeg); 885 EXPECT_EQ(fn_neg(0u), 0u); 886 EXPECT_EQ(fn_neg(1u), uint32_t(-1)); 887 EXPECT_EQ(fn_neg(uint32_t(-1)), 1u); 888 EXPECT_EQ(fn_neg(uint32_t(-333)), 333u); 889 EXPECT_EQ(fn_neg(333u), uint32_t(-333)); 890 EXPECT_EQ(fn_neg(0x80000000u), 0x80000000u); 891 892 TestRRFunc fn_not = create_func_rr(ctx, UniOpRR::kNot); 893 EXPECT_EQ(fn_not(0u), 0xFFFFFFFFu); 894 EXPECT_EQ(fn_not(1u), 0xFFFFFFFEu); 895 EXPECT_EQ(fn_not(0xFFFFFFFF), 0u); 896 EXPECT_EQ(fn_not(0x12333245), ~0x12333245u); 897 EXPECT_EQ(fn_not(0x80000000u), 0x7FFFFFFFu); 898 899 TestRRFunc fn_bswap32 = create_func_rr(ctx, UniOpRR::kBSwap); 900 EXPECT_EQ(fn_bswap32(0x11223344u), 0x44332211u); 901 EXPECT_EQ(fn_bswap32(0xFFFF0000u), 0x0000FFFFu); 902 EXPECT_EQ(fn_bswap32(0x00000000u), 0x00000000u); 903 904 TestRRFunc fn_clz32 = create_func_rr(ctx, UniOpRR::kCLZ); 905 EXPECT_EQ(fn_clz32(0x80000000u), 0u); 906 EXPECT_EQ(fn_clz32(0x40000000u), 1u); 907 EXPECT_EQ(fn_clz32(0x00800000u), 8u); 908 EXPECT_EQ(fn_clz32(0x00008000u), 16u); 909 EXPECT_EQ(fn_clz32(0x00000080u), 24u); 910 EXPECT_EQ(fn_clz32(0x00000001u), 31u); 911 912 TestRRFunc fn_ctz32 = create_func_rr(ctx, UniOpRR::kCTZ); 913 EXPECT_EQ(fn_ctz32(0x80000000u), 31u); 914 EXPECT_EQ(fn_ctz32(0x40000000u), 30u); 915 EXPECT_EQ(fn_ctz32(0x00800000u), 23u); 916 EXPECT_EQ(fn_ctz32(0x00008000u), 15u); 917 EXPECT_EQ(fn_ctz32(0x00000080u), 7u); 918 EXPECT_EQ(fn_ctz32(0x00000001u), 0u); 919 920 TestRRFunc fn_reflect = create_func_rr(ctx, UniOpRR::kReflect); 921 EXPECT_EQ(fn_reflect(0x00000000u), 0x00000000u); 922 EXPECT_EQ(fn_reflect(0x00FF0000u), 0x00FF0000u); 923 EXPECT_EQ(fn_reflect(0x000000FFu), 0x000000FFu); 924 EXPECT_EQ(fn_reflect(0x80000000u), 0x7FFFFFFFu); 925 EXPECT_EQ(fn_reflect(0xFFFFFFFFu), 0x00000000u); 926 EXPECT_EQ(fn_reflect(0x88FF0000u), 0x7700FFFFu); 927 928 ctx.rt.reset(); 929 } 930 931 // ujit::UniCompiler - Tests - RRR Operations - Functions 932 // ====================================================== 933 934 static TestRRRFunc create_func_rrr(JitContext& ctx, UniOpRRR op) { 935 ctx.prepare(); 936 937 UniCompiler uc(&ctx.cc, ctx.features, ctx.cpu_hints); 938 uc.init_vec_width(VecWidth::k128); 939 940 FuncNode* node = uc.add_func(FuncSignature::build<uint32_t, uint32_t, uint32_t>()); 941 EXPECT_NOT_NULL(node); 942 943 Gp a = uc.new_gp32("a"); 944 Gp b = uc.new_gp32("b"); 945 Gp result = uc.new_gp32("result"); 946 947 node->set_arg(0, a); 948 node->set_arg(1, b); 949 950 uc.emit_3i(op, result, a, b); 951 uc.ret(result); 952 953 uc.end_func(); 954 return ctx.finish<TestRRRFunc>(); 955 } 956 957 static TestRRIFunc create_func_rri(JitContext& ctx, UniOpRRR op, Imm bImm) { 958 ctx.prepare(); 959 960 UniCompiler uc(&ctx.cc, ctx.features, ctx.cpu_hints); 961 uc.init_vec_width(VecWidth::k128); 962 963 FuncNode* node = uc.add_func(FuncSignature::build<uint32_t, uint32_t>()); 964 EXPECT_NOT_NULL(node); 965 966 Gp a = uc.new_gp32("a"); 967 Gp result = uc.new_gp32("result"); 968 969 node->set_arg(0, a); 970 971 uc.emit_3i(op, result, a, bImm); 972 uc.ret(result); 973 974 uc.end_func(); 975 return ctx.finish<TestRRIFunc>(); 976 } 977 978 // ujit::UniCompiler - Tests - RRR Operations - Runner 979 // =================================================== 980 981 static ASMJIT_NOINLINE void test_rrr_op(JitContext& ctx, UniOpRRR op, uint32_t a, uint32_t b, uint32_t expected) { 982 TestRRRFunc fn_rrr = create_func_rrr(ctx, op); 983 uint32_t observed_rrr = fn_rrr(a, b); 984 EXPECT_EQ(observed_rrr, expected) 985 .message("Operation failed (RRR):\n" 986 " Input #1: %d\n" 987 " Input #2: %d\n" 988 " Expected: %d\n" 989 " Observed: %d\n" 990 "Assembly:\n%s", 991 a, 992 b, 993 uint32_t(expected), 994 observed_rrr, 995 ctx.logger_content()); 996 997 TestRRIFunc fn_rri = create_func_rri(ctx, op, Imm(b)); 998 uint32_t observed_rri = fn_rri(a); 999 EXPECT_EQ(observed_rri, expected) 1000 .message("Operation failed (RRI):\n" 1001 " Input #1: %d\n" 1002 " Input #2: %d\n" 1003 " Expected: %d\n" 1004 " Observed: %d\n" 1005 "Assembly:\n%s", 1006 a, 1007 b, 1008 uint32_t(expected), 1009 observed_rri, 1010 ctx.logger_content()); 1011 1012 ctx.rt.reset(); 1013 } 1014 1015 static ASMJIT_NOINLINE void test_rrr_ops(JitContext& ctx) { 1016 test_rrr_op(ctx, UniOpRRR::kAnd, 0u, 0u, 0u); 1017 test_rrr_op(ctx, UniOpRRR::kAnd, 0xFFu, 0x11u, 0x11u); 1018 test_rrr_op(ctx, UniOpRRR::kAnd, 0x11u, 0xFFu, 0x11u); 1019 test_rrr_op(ctx, UniOpRRR::kAnd, 0xFF11u, 0x1111u, 0x1111u); 1020 test_rrr_op(ctx, UniOpRRR::kAnd, 0x1111u, 0xFF11u, 0x1111u); 1021 test_rrr_op(ctx, UniOpRRR::kAnd, 0x0000FFFFu, 0xFFFF0000u, 0u); 1022 test_rrr_op(ctx, UniOpRRR::kAnd, 0xFFFFFFFFu, 0xFFFF0000u, 0xFFFF0000u); 1023 test_rrr_op(ctx, UniOpRRR::kAnd, 0x11111111u, 0x11223344u, 0x11001100u); 1024 1025 test_rrr_op(ctx, UniOpRRR::kOr, 0u, 0u, 0u); 1026 test_rrr_op(ctx, UniOpRRR::kOr, 0xFFu, 0x11u, 0xFFu); 1027 test_rrr_op(ctx, UniOpRRR::kOr, 0x11u, 0xFFu, 0xFFu); 1028 test_rrr_op(ctx, UniOpRRR::kOr, 0xFF11u, 0x1111u, 0xFF11u); 1029 test_rrr_op(ctx, UniOpRRR::kOr, 0x1111u, 0xFF11u, 0xFF11u); 1030 test_rrr_op(ctx, UniOpRRR::kOr, 0x0000FFFFu, 0xFFFF0001u, 0xFFFFFFFFu); 1031 test_rrr_op(ctx, UniOpRRR::kOr, 0xFFFFFFFFu, 0xFF000000u, 0xFFFFFFFFu); 1032 test_rrr_op(ctx, UniOpRRR::kOr, 0x11111111u, 0x00223344u, 0x11333355u); 1033 1034 test_rrr_op(ctx, UniOpRRR::kXor, 0u, 0u, 0u); 1035 test_rrr_op(ctx, UniOpRRR::kXor, 0xFFu, 0x11u, 0xEEu); 1036 test_rrr_op(ctx, UniOpRRR::kXor, 0x11u, 0xFFu, 0xEEu); 1037 test_rrr_op(ctx, UniOpRRR::kXor, 0xFF11u, 0x1111u, 0xEE00u); 1038 test_rrr_op(ctx, UniOpRRR::kXor, 0x1111u, 0xFF11u, 0xEE00u); 1039 test_rrr_op(ctx, UniOpRRR::kXor, 0x0000FFFFu, 0xFFFF0001u, 0xFFFFFFFEu); 1040 test_rrr_op(ctx, UniOpRRR::kXor, 0xFFFFFFFFu, 0xFF000000u, 0x00FFFFFFu); 1041 test_rrr_op(ctx, UniOpRRR::kXor, 0x11111111u, 0x00223344u, 0x11332255u); 1042 1043 test_rrr_op(ctx, UniOpRRR::kBic, 0u, 0u, 0u); 1044 test_rrr_op(ctx, UniOpRRR::kBic, 0xFFu, 0x11u, 0xEEu); 1045 test_rrr_op(ctx, UniOpRRR::kBic, 0x11u, 0xFFu, 0x00u); 1046 test_rrr_op(ctx, UniOpRRR::kBic, 0xFF11u, 0x1111u, 0xEE00u); 1047 test_rrr_op(ctx, UniOpRRR::kBic, 0x1111u, 0xFF11u, 0x0000u); 1048 test_rrr_op(ctx, UniOpRRR::kBic, 0x0000FFFFu, 0xFFFF0000u, 0x0000FFFFu); 1049 test_rrr_op(ctx, UniOpRRR::kBic, 0xFFFFFFFFu, 0xFFFF0000u, 0x0000FFFFu); 1050 test_rrr_op(ctx, UniOpRRR::kBic, 0x11111111u, 0x11223344u, 0x00110011u); 1051 1052 test_rrr_op(ctx, UniOpRRR::kAdd, 0u, 0u, 0u); 1053 test_rrr_op(ctx, UniOpRRR::kAdd, 1u, 2u, 3u); 1054 test_rrr_op(ctx, UniOpRRR::kAdd, 0xFF000000u, 0x00FFFFFFu, 0xFFFFFFFFu); 1055 test_rrr_op(ctx, UniOpRRR::kAdd, 1u, 0xFFFu, 0x1000u); 1056 test_rrr_op(ctx, UniOpRRR::kAdd, 1u, 0xFFF000u, 0xFFF001u); 1057 1058 test_rrr_op(ctx, UniOpRRR::kSub, 1u, 2u, 0xFFFFFFFFu); 1059 1060 test_rrr_op(ctx, UniOpRRR::kMul, 1000u, 999u, 999000u); 1061 test_rrr_op(ctx, UniOpRRR::kMul, 0xFFFFu, 0x00010001u, 0xFFFFFFFFu); 1062 1063 test_rrr_op(ctx, UniOpRRR::kUDiv, 100000u, 1000u, 100u); 1064 1065 test_rrr_op(ctx, UniOpRRR::kUMod, 1999u, 1000u, 999u); 1066 1067 test_rrr_op(ctx, UniOpRRR::kSMin, uint32_t(1111), uint32_t(0), uint32_t(0)); 1068 test_rrr_op(ctx, UniOpRRR::kSMin, uint32_t(-1111), uint32_t(0), uint32_t(-1111)); 1069 test_rrr_op(ctx, UniOpRRR::kSMin, uint32_t(1), uint32_t(22), uint32_t(1)); 1070 test_rrr_op(ctx, UniOpRRR::kSMin, uint32_t(1), uint32_t(0), uint32_t(0)); 1071 test_rrr_op(ctx, UniOpRRR::kSMin, uint32_t(100101033), uint32_t(999), uint32_t(999)); 1072 test_rrr_op(ctx, UniOpRRR::kSMin, uint32_t(100101033), uint32_t(112), uint32_t(112)); 1073 test_rrr_op(ctx, UniOpRRR::kSMin, uint32_t(112), uint32_t(1125532), uint32_t(112)); 1074 test_rrr_op(ctx, UniOpRRR::kSMin, uint32_t(1111), uint32_t(-1), uint32_t(-1)); 1075 test_rrr_op(ctx, UniOpRRR::kSMin, uint32_t(-1111), uint32_t(-1), uint32_t(-1111)); 1076 test_rrr_op(ctx, UniOpRRR::kSMin, uint32_t(-1), uint32_t(-22), uint32_t(-22)); 1077 test_rrr_op(ctx, UniOpRRR::kSMin, uint32_t(-1), uint32_t(-128), uint32_t(-128)); 1078 test_rrr_op(ctx, UniOpRRR::kSMin, uint32_t(-128), uint32_t(-1), uint32_t(-128)); 1079 test_rrr_op(ctx, UniOpRRR::kSMin, uint32_t(-128), uint32_t(9), uint32_t(-128)); 1080 test_rrr_op(ctx, UniOpRRR::kSMin, uint32_t(12444), uint32_t(-1), uint32_t(-1)); 1081 1082 test_rrr_op(ctx, UniOpRRR::kSMax, uint32_t(1), uint32_t(22), uint32_t(22)); 1083 test_rrr_op(ctx, UniOpRRR::kSMax, uint32_t(1), uint32_t(0), uint32_t(1)); 1084 test_rrr_op(ctx, UniOpRRR::kSMax, uint32_t(100101033), uint32_t(999), uint32_t(100101033)); 1085 test_rrr_op(ctx, UniOpRRR::kSMax, uint32_t(100101033), uint32_t(112), uint32_t(100101033)); 1086 test_rrr_op(ctx, UniOpRRR::kSMax, uint32_t(112), uint32_t(1125532), uint32_t(1125532)); 1087 test_rrr_op(ctx, UniOpRRR::kSMax, uint32_t(1111), uint32_t(-1), uint32_t(1111)); 1088 test_rrr_op(ctx, UniOpRRR::kSMax, uint32_t(-1111), uint32_t(-1), uint32_t(-1)); 1089 test_rrr_op(ctx, UniOpRRR::kSMax, uint32_t(-1), uint32_t(-22), uint32_t(-1)); 1090 test_rrr_op(ctx, UniOpRRR::kSMax, uint32_t(-1), uint32_t(-128), uint32_t(-1)); 1091 test_rrr_op(ctx, UniOpRRR::kSMax, uint32_t(-128), uint32_t(-1), uint32_t(-1)); 1092 test_rrr_op(ctx, UniOpRRR::kSMax, uint32_t(-128), uint32_t(9), uint32_t(9)); 1093 test_rrr_op(ctx, UniOpRRR::kSMax, uint32_t(12444), uint32_t(-1), uint32_t(12444)); 1094 1095 test_rrr_op(ctx, UniOpRRR::kUMin, 1, 22, 1); 1096 test_rrr_op(ctx, UniOpRRR::kUMin, 22, 1, 1); 1097 test_rrr_op(ctx, UniOpRRR::kUMin, 1, 255, 1); 1098 test_rrr_op(ctx, UniOpRRR::kUMin, 255, 1, 1); 1099 test_rrr_op(ctx, UniOpRRR::kUMin, 1023, 255, 255); 1100 test_rrr_op(ctx, UniOpRRR::kUMin, 255, 1023, 255); 1101 test_rrr_op(ctx, UniOpRRR::kUMin, 0xFFFFFFFFu, 255, 255); 1102 test_rrr_op(ctx, UniOpRRR::kUMin, 255, 0xFFFFFFFFu, 255); 1103 test_rrr_op(ctx, UniOpRRR::kUMin, 0xFFFFFFFFu, 0xFFFFFF00u, 0xFFFFFF00u); 1104 test_rrr_op(ctx, UniOpRRR::kUMin, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu); 1105 1106 test_rrr_op(ctx, UniOpRRR::kUMax, 1, 22, 22); 1107 test_rrr_op(ctx, UniOpRRR::kUMax, 22, 1, 22); 1108 test_rrr_op(ctx, UniOpRRR::kUMax, 1, 255, 255); 1109 test_rrr_op(ctx, UniOpRRR::kUMax, 255, 1, 255); 1110 test_rrr_op(ctx, UniOpRRR::kUMax, 1023, 255, 1023); 1111 test_rrr_op(ctx, UniOpRRR::kUMax, 255, 1023, 1023); 1112 test_rrr_op(ctx, UniOpRRR::kUMax, 0xFFFFFFFFu, 255, 0xFFFFFFFFu); 1113 test_rrr_op(ctx, UniOpRRR::kUMax, 255, 0xFFFFFFFFu, 0xFFFFFFFFu); 1114 test_rrr_op(ctx, UniOpRRR::kUMax, 0xFFFFFFFFu, 0xFFFFFF00u, 0xFFFFFFFFu); 1115 test_rrr_op(ctx, UniOpRRR::kUMax, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu); 1116 1117 test_rrr_op(ctx, UniOpRRR::kSll, 1u, 1u, 1u << 1); 1118 test_rrr_op(ctx, UniOpRRR::kSll, 1u, 22u, 1u << 22); 1119 test_rrr_op(ctx, UniOpRRR::kSll, 1u, 31u, 1u << 31); 1120 test_rrr_op(ctx, UniOpRRR::kSll, 0x7FFFFFFFu, 1u, 0xFFFFFFFEu); 1121 1122 test_rrr_op(ctx, UniOpRRR::kSrl, 1u, 1u, 1u >> 1); 1123 test_rrr_op(ctx, UniOpRRR::kSrl, 1u, 22u, 1u >> 22); 1124 test_rrr_op(ctx, UniOpRRR::kSrl, 1u, 31u, 1u >> 31); 1125 test_rrr_op(ctx, UniOpRRR::kSrl, 0x7FFFFFFFu, 1u, 0x7FFFFFFFu >> 1); 1126 1127 test_rrr_op(ctx, UniOpRRR::kSra, 1u, 1u, 1u >> 1); 1128 test_rrr_op(ctx, UniOpRRR::kSra, 1u, 22u, 1u >> 22); 1129 test_rrr_op(ctx, UniOpRRR::kSra, 1u, 31u, 1u >> 31); 1130 test_rrr_op(ctx, UniOpRRR::kSra, 0x7FFFFFFFu, 1u, 0x7FFFFFFFu >> 1); 1131 test_rrr_op(ctx, UniOpRRR::kSra, 0xF0000000u, 4u, 0xFF000000u); 1132 test_rrr_op(ctx, UniOpRRR::kSra, 0x80000000u, 31u, 0xFFFFFFFFu); 1133 1134 test_rrr_op(ctx, UniOpRRR::kRol, 0x11223344u, 8u, 0x22334411u); 1135 test_rrr_op(ctx, UniOpRRR::kRol, 0x11223344u, 16u, 0x33441122u); 1136 test_rrr_op(ctx, UniOpRRR::kRol, 0xFCFFDABBu, 1u, 0xF9FFB577u); 1137 1138 test_rrr_op(ctx, UniOpRRR::kRor, 0x11223344u, 8u, 0x44112233u); 1139 test_rrr_op(ctx, UniOpRRR::kRor, 0x11223344u, 16u, 0x33441122u); 1140 test_rrr_op(ctx, UniOpRRR::kRor, 0xF0000000u, 1u, 0x78000000u); 1141 1142 test_rrr_op(ctx, UniOpRRR::kSBound, 0, 244u, 0); 1143 test_rrr_op(ctx, UniOpRRR::kSBound, 42, 244u, 42u); 1144 test_rrr_op(ctx, UniOpRRR::kSBound, 1111, 244u, 244u); 1145 test_rrr_op(ctx, UniOpRRR::kSBound, 9999999, 111244u, 111244u); 1146 test_rrr_op(ctx, UniOpRRR::kSBound, uint32_t(int32_t(-1)), 1000u, 0u); 1147 test_rrr_op(ctx, UniOpRRR::kSBound, uint32_t(INT32_MIN), 100000u, 0u); 1148 test_rrr_op(ctx, UniOpRRR::kSBound, uint32_t(INT32_MAX), 0u, 0u); 1149 test_rrr_op(ctx, UniOpRRR::kSBound, uint32_t(INT32_MAX), 100000u, 100000u); 1150 test_rrr_op(ctx, UniOpRRR::kSBound, uint32_t(INT32_MAX), uint32_t(INT32_MAX), uint32_t(INT32_MAX)); 1151 } 1152 1153 // ujit::UniCompiler - Tests - SIMD - Functions 1154 // ============================================ 1155 1156 // The following variations are supported: 1157 // - 0 - separate destination & source registers 1158 // - 1 - destination register is a source register as well 1159 // - 2 - source is a memory operand 1160 // - 3 - source register is a GP register (only for broadcasts from a GP register, otherwise maps to 0) 1161 static constexpr uint32_t kNumVariationsVV = 3; 1162 static constexpr uint32_t kNumVariationsVV_Broadcast = 4; 1163 1164 static TestVVFunc create_func_vv(JitContext& ctx, VecWidth vw, UniOpVV op, Variation variation = Variation{0}) { 1165 ctx.prepare(); 1166 1167 UniCompiler uc(&ctx.cc, ctx.features, ctx.cpu_hints); 1168 uc.init_vec_width(vw); 1169 1170 FuncNode* node = uc.add_func(FuncSignature::build<void, void*, const void*>()); 1171 EXPECT_NOT_NULL(node); 1172 1173 Gp dst_ptr = uc.new_gpz("dst_ptr"); 1174 Gp src_ptr = uc.new_gpz("src_ptr"); 1175 1176 node->set_arg(0, dst_ptr); 1177 node->set_arg(1, src_ptr); 1178 1179 Vec dst_vec = uc.new_vec_with_width(vw, "dst_vec"); 1180 1181 // There are some instructions that fill the high part of the register, so just zero the destination to make 1182 // sure that we can test this function (that the low part is actually zeroed and doesn't contain garbage). 1183 uc.v_zero_i(dst_vec); 1184 1185 if (variation == 3u && (op == UniOpVV::kBroadcastU8 || 1186 op == UniOpVV::kBroadcastU8Z || 1187 op == UniOpVV::kBroadcastU32 || 1188 op == UniOpVV::kBroadcastU64 || 1189 op == UniOpVV::kBroadcastF32 || 1190 op == UniOpVV::kBroadcastF64)) { 1191 // This is used to test broadcasts from a GP register to a vector register. 1192 Gp src_gp = uc.new_gpz("src_gp"); 1193 1194 switch (op) { 1195 case UniOpVV::kBroadcastU8: 1196 case UniOpVV::kBroadcastU8Z: 1197 uc.load_u8(src_gp, mem_ptr(src_ptr)); 1198 uc.emit_2v(op, dst_vec, src_gp); 1199 break; 1200 1201 case UniOpVV::kBroadcastU16: 1202 case UniOpVV::kBroadcastU16Z: 1203 uc.load_u16(src_gp, mem_ptr(src_ptr)); 1204 uc.emit_2v(op, dst_vec, src_gp); 1205 break; 1206 1207 case UniOpVV::kBroadcastU32: 1208 case UniOpVV::kBroadcastF32: 1209 uc.load_u32(src_gp, mem_ptr(src_ptr)); 1210 uc.emit_2v(op, dst_vec, src_gp); 1211 break; 1212 1213 case UniOpVV::kBroadcastU64: 1214 case UniOpVV::kBroadcastF64: 1215 // Prevent using 64-bit registers on 32-bit architectures (that would fail). 1216 if (uc.is_64bit()) { 1217 uc.load_u64(src_gp, mem_ptr(src_ptr)); 1218 uc.emit_2v(op, dst_vec, src_gp); 1219 } 1220 else { 1221 uc.emit_2v(op, dst_vec, mem_ptr(src_ptr)); 1222 } 1223 break; 1224 1225 default: 1226 ASMJIT_NOT_REACHED(); 1227 } 1228 } 1229 else if (variation == 2u) { 1230 uc.emit_2v(op, dst_vec, mem_ptr(src_ptr)); 1231 } 1232 else if (variation == 1u) { 1233 uc.v_loaduvec(dst_vec, mem_ptr(src_ptr)); 1234 uc.emit_2v(op, dst_vec, dst_vec); 1235 } 1236 else { 1237 Vec src_vec = uc.new_vec_with_width(vw, "src_vec"); 1238 uc.v_loaduvec(src_vec, mem_ptr(src_ptr)); 1239 uc.emit_2v(op, dst_vec, src_vec); 1240 } 1241 1242 uc.v_storeuvec(mem_ptr(dst_ptr), dst_vec); 1243 1244 uc.end_func(); 1245 return ctx.finish<TestVVFunc>(); 1246 } 1247 1248 // The following variations are supported: 1249 // - 0 - separate destination & source registers 1250 // - 1 - destination register is a source register as well 1251 // - 2 - source is a memory operand 1252 static constexpr uint32_t kNumVariationsVVI = 3; 1253 1254 static TestVVFunc create_func_vvi(JitContext& ctx, VecWidth vw, UniOpVVI op, uint32_t imm, Variation variation = Variation{0}) { 1255 ctx.prepare(); 1256 1257 UniCompiler uc(&ctx.cc, ctx.features, ctx.cpu_hints); 1258 uc.init_vec_width(vw); 1259 1260 FuncNode* node = uc.add_func(FuncSignature::build<void, void*, const void*>()); 1261 EXPECT_NOT_NULL(node); 1262 1263 Gp dst_ptr = uc.new_gpz("dst_ptr"); 1264 Gp src_ptr = uc.new_gpz("src_ptr"); 1265 1266 node->set_arg(0, dst_ptr); 1267 node->set_arg(1, src_ptr); 1268 1269 Vec src_vec = uc.new_vec_with_width(vw, "src_vec"); 1270 1271 switch (variation.value) { 1272 default: 1273 case 0: { 1274 // There are some instructions that fill the high part of the register, so just zero the destination to make 1275 // sure that we can test this function (that the low part is actually zeroed and doesn't contain garbage). 1276 Vec dst_vec = uc.new_vec_with_width(vw, "dst_vec"); 1277 uc.v_zero_i(dst_vec); 1278 1279 uc.v_loaduvec(src_vec, mem_ptr(src_ptr)); 1280 uc.emit_2vi(op, dst_vec, src_vec, imm); 1281 uc.v_storeuvec(mem_ptr(dst_ptr), dst_vec); 1282 1283 break; 1284 } 1285 1286 case 1: { 1287 uc.v_loaduvec(src_vec, mem_ptr(src_ptr)); 1288 uc.emit_2vi(op, src_vec, src_vec, imm); 1289 uc.v_storeuvec(mem_ptr(dst_ptr), src_vec); 1290 break; 1291 } 1292 1293 case 2: { 1294 Vec dst_vec = uc.new_vec_with_width(vw, "dst_vec"); 1295 uc.emit_2vi(op, dst_vec, mem_ptr(src_ptr), imm); 1296 uc.v_storeuvec(mem_ptr(dst_ptr), dst_vec); 1297 break; 1298 } 1299 } 1300 1301 uc.end_func(); 1302 return ctx.finish<TestVVFunc>(); 1303 } 1304 1305 // The following variations are supported: 1306 // - 0 - separate destination & source registers 1307 // - 1 - destination register is the same as the first source register 1308 // - 2 - destination register is the same as the second source register 1309 // - 3 - separate destination & source registers, the second source is a memory operand 1310 // - 4 - destination register is the same as the first source register, second source is a memory operand 1311 static constexpr uint32_t kNumVariationsVVV = 5; 1312 1313 static TestVVVFunc create_func_vvv(JitContext& ctx, VecWidth vw, UniOpVVV op, Variation variation = Variation{0}) { 1314 ctx.prepare(); 1315 1316 UniCompiler uc(&ctx.cc, ctx.features, ctx.cpu_hints); 1317 uc.init_vec_width(vw); 1318 1319 FuncNode* node = uc.add_func(FuncSignature::build<void, void*, const void*, const void*>()); 1320 EXPECT_NOT_NULL(node); 1321 1322 Gp dst_ptr = uc.new_gpz("dst_ptr"); 1323 Gp src1_ptr = uc.new_gpz("src1_ptr"); 1324 Gp src2_ptr = uc.new_gpz("src2_ptr"); 1325 1326 node->set_arg(0, dst_ptr); 1327 node->set_arg(1, src1_ptr); 1328 node->set_arg(2, src2_ptr); 1329 1330 Vec src1_vec = uc.new_vec_with_width(vw, "src1_vec"); 1331 Vec src2_vec = uc.new_vec_with_width(vw, "src2_vec"); 1332 1333 switch (variation.value) { 1334 default: 1335 case 0: { 1336 // There are some instructions that fill the high part of the register, so just zero the destination to make 1337 // sure that we can test this function (that the low part is actually zeroed and doesn't contain garbage). 1338 Vec dst_vec = uc.new_vec_with_width(vw, "dst_vec"); 1339 uc.v_zero_i(dst_vec); 1340 1341 uc.v_loaduvec(src1_vec, mem_ptr(src1_ptr)); 1342 uc.v_loaduvec(src2_vec, mem_ptr(src2_ptr)); 1343 uc.emit_3v(op, dst_vec, src1_vec, src2_vec); 1344 uc.v_storeuvec(mem_ptr(dst_ptr), dst_vec); 1345 1346 break; 1347 } 1348 1349 case 1: { 1350 uc.v_loaduvec(src1_vec, mem_ptr(src1_ptr)); 1351 uc.v_loaduvec(src2_vec, mem_ptr(src2_ptr)); 1352 uc.emit_3v(op, src1_vec, src1_vec, src2_vec); 1353 uc.v_storeuvec(mem_ptr(dst_ptr), src1_vec); 1354 1355 break; 1356 } 1357 1358 case 2: { 1359 uc.v_loaduvec(src1_vec, mem_ptr(src1_ptr)); 1360 uc.v_loaduvec(src2_vec, mem_ptr(src2_ptr)); 1361 uc.emit_3v(op, src2_vec, src1_vec, src2_vec); 1362 uc.v_storeuvec(mem_ptr(dst_ptr), src2_vec); 1363 1364 break; 1365 } 1366 1367 case 3: { 1368 Vec dst_vec = uc.new_vec_with_width(vw, "dst_vec"); 1369 uc.v_zero_i(dst_vec); 1370 1371 uc.v_loaduvec(src1_vec, mem_ptr(src1_ptr)); 1372 uc.emit_3v(op, dst_vec, src1_vec, mem_ptr(src2_ptr)); 1373 uc.v_storeuvec(mem_ptr(dst_ptr), dst_vec); 1374 1375 break; 1376 } 1377 1378 case 4: { 1379 uc.v_loaduvec(src1_vec, mem_ptr(src1_ptr)); 1380 uc.emit_3v(op, src1_vec, src1_vec, mem_ptr(src2_ptr)); 1381 uc.v_storeuvec(mem_ptr(dst_ptr), src1_vec); 1382 1383 break; 1384 } 1385 } 1386 1387 uc.end_func(); 1388 return ctx.finish<TestVVVFunc>(); 1389 } 1390 1391 static constexpr uint32_t kNumVariationsVVVI = 5; 1392 1393 static TestVVVFunc create_func_vvvi(JitContext& ctx, VecWidth vw, UniOpVVVI op, uint32_t imm, Variation variation = Variation{0}) { 1394 ctx.prepare(); 1395 1396 UniCompiler uc(&ctx.cc, ctx.features, ctx.cpu_hints); 1397 uc.init_vec_width(vw); 1398 1399 FuncNode* node = uc.add_func(FuncSignature::build<void, void*, const void*, const void*>()); 1400 EXPECT_NOT_NULL(node); 1401 1402 Gp dst_ptr = uc.new_gpz("dst_ptr"); 1403 Gp src1_ptr = uc.new_gpz("src1_ptr"); 1404 Gp src2_ptr = uc.new_gpz("src2_ptr"); 1405 1406 node->set_arg(0, dst_ptr); 1407 node->set_arg(1, src1_ptr); 1408 node->set_arg(2, src2_ptr); 1409 1410 Vec src1_vec = uc.new_vec_with_width(vw, "src1_vec"); 1411 Vec src2_vec = uc.new_vec_with_width(vw, "src2_vec"); 1412 1413 switch (variation.value) { 1414 default: 1415 case 0: { 1416 // There are some instructions that fill the high part of the register, so just zero the destination to make 1417 // sure that we can test this function (that the low part is actually zeroed and doesn't contain garbage). 1418 Vec dst_vec = uc.new_vec_with_width(vw, "dst_vec"); 1419 uc.v_zero_i(dst_vec); 1420 1421 uc.v_loaduvec(src1_vec, mem_ptr(src1_ptr)); 1422 uc.v_loaduvec(src2_vec, mem_ptr(src2_ptr)); 1423 uc.emit_3vi(op, dst_vec, src1_vec, src2_vec, imm); 1424 uc.v_storeuvec(mem_ptr(dst_ptr), dst_vec); 1425 1426 break; 1427 } 1428 1429 case 1: { 1430 uc.v_loaduvec(src1_vec, mem_ptr(src1_ptr)); 1431 uc.v_loaduvec(src2_vec, mem_ptr(src2_ptr)); 1432 uc.emit_3vi(op, src1_vec, src1_vec, src2_vec, imm); 1433 uc.v_storeuvec(mem_ptr(dst_ptr), src1_vec); 1434 1435 break; 1436 } 1437 1438 case 2: { 1439 uc.v_loaduvec(src1_vec, mem_ptr(src1_ptr)); 1440 uc.v_loaduvec(src2_vec, mem_ptr(src2_ptr)); 1441 uc.emit_3vi(op, src2_vec, src1_vec, src2_vec, imm); 1442 uc.v_storeuvec(mem_ptr(dst_ptr), src2_vec); 1443 1444 break; 1445 } 1446 1447 case 3: { 1448 Vec dst_vec = uc.new_vec_with_width(vw, "dst_vec"); 1449 uc.v_zero_i(dst_vec); 1450 1451 uc.v_loaduvec(src1_vec, mem_ptr(src1_ptr)); 1452 uc.emit_3vi(op, dst_vec, src1_vec, mem_ptr(src2_ptr), imm); 1453 uc.v_storeuvec(mem_ptr(dst_ptr), dst_vec); 1454 1455 break; 1456 } 1457 1458 case 4: { 1459 uc.v_loaduvec(src1_vec, mem_ptr(src1_ptr)); 1460 uc.emit_3vi(op, src1_vec, src1_vec, mem_ptr(src2_ptr), imm); 1461 uc.v_storeuvec(mem_ptr(dst_ptr), src1_vec); 1462 1463 break; 1464 } 1465 } 1466 1467 uc.end_func(); 1468 return ctx.finish<TestVVVFunc>(); 1469 } 1470 1471 // The following variations are supported: 1472 // - 0 - separate destination & source registers 1473 // - 1 - destination register is the first source register 1474 // - 2 - destination register is the second source register 1475 // - 3 - destination register is the third source register 1476 static constexpr uint32_t kNumVariationsVVVV = 4; 1477 1478 static TestVVVVFunc create_func_vvvv(JitContext& ctx, VecWidth vw, UniOpVVVV op, Variation variation = Variation{0}) { 1479 ctx.prepare(); 1480 1481 UniCompiler uc(&ctx.cc, ctx.features, ctx.cpu_hints); 1482 uc.init_vec_width(vw); 1483 1484 FuncNode* node = uc.add_func(FuncSignature::build<void, void*, const void*, const void*, const void*>()); 1485 EXPECT_NOT_NULL(node); 1486 1487 Gp dst_ptr = uc.new_gpz("dst_ptr"); 1488 Gp src1_ptr = uc.new_gpz("src1_ptr"); 1489 Gp src2_ptr = uc.new_gpz("src2_ptr"); 1490 Gp src3_ptr = uc.new_gpz("src3_ptr"); 1491 1492 node->set_arg(0, dst_ptr); 1493 node->set_arg(1, src1_ptr); 1494 node->set_arg(2, src2_ptr); 1495 node->set_arg(3, src3_ptr); 1496 1497 Vec src1_vec = uc.new_vec_with_width(vw, "src1_vec"); 1498 Vec src2_vec = uc.new_vec_with_width(vw, "src2_vec"); 1499 Vec src3_vec = uc.new_vec_with_width(vw, "src3_vec"); 1500 1501 uc.v_loaduvec(src1_vec, mem_ptr(src1_ptr)); 1502 uc.v_loaduvec(src2_vec, mem_ptr(src2_ptr)); 1503 uc.v_loaduvec(src3_vec, mem_ptr(src3_ptr)); 1504 1505 switch (variation.value) { 1506 default: 1507 case 0: { 1508 // There are some instructions that fill the high part of the register, so just zero the destination to make 1509 // sure that we can test this function (that the low part is actually zeroed and doesn't contain garbage). 1510 Vec dst_vec = uc.new_vec_with_width(vw, "dst_vec"); 1511 uc.v_zero_i(dst_vec); 1512 1513 uc.emit_4v(op, dst_vec, src1_vec, src2_vec, src3_vec); 1514 uc.v_storeuvec(mem_ptr(dst_ptr), dst_vec); 1515 1516 break; 1517 } 1518 1519 case 1: { 1520 uc.emit_4v(op, src1_vec, src1_vec, src2_vec, src3_vec); 1521 uc.v_storeuvec(mem_ptr(dst_ptr), src1_vec); 1522 1523 break; 1524 } 1525 1526 case 2: { 1527 uc.emit_4v(op, src2_vec, src1_vec, src2_vec, src3_vec); 1528 uc.v_storeuvec(mem_ptr(dst_ptr), src2_vec); 1529 1530 break; 1531 } 1532 1533 case 3: { 1534 uc.emit_4v(op, src3_vec, src1_vec, src2_vec, src3_vec); 1535 uc.v_storeuvec(mem_ptr(dst_ptr), src3_vec); 1536 1537 break; 1538 } 1539 } 1540 1541 uc.end_func(); 1542 return ctx.finish<TestVVVVFunc>(); 1543 } 1544 // ujit::UniCompiler - Tests - SIMD - Vector Overlay 1545 // ================================================= 1546 1547 enum class VecElementType : uint8_t { 1548 kInt8, 1549 kInt16, 1550 kInt32, 1551 kInt64, 1552 kUInt8, 1553 kUInt16, 1554 kUInt32, 1555 kUInt64, 1556 kFloat32, 1557 kFloat64 1558 }; 1559 1560 struct VecOpInfo { 1561 uint32_t _data; 1562 1563 ASMJIT_INLINE_NODEBUG uint32_t count() const noexcept { return _data >> 28; } 1564 1565 ASMJIT_INLINE_NODEBUG VecElementType ret() const noexcept { return VecElementType((_data >> 24) & 0xFu); } 1566 ASMJIT_INLINE_NODEBUG VecElementType arg(uint32_t i) const noexcept { return VecElementType((_data >> (i * 4)) & 0xFu); } 1567 1568 static ASMJIT_INLINE_NODEBUG VecOpInfo make(VecElementType ret, VecElementType arg0) noexcept { 1569 return VecOpInfo{(1u << 28) | (uint32_t(ret) << 24) | uint32_t(arg0)}; 1570 } 1571 1572 static ASMJIT_INLINE_NODEBUG VecOpInfo make(VecElementType ret, VecElementType arg0, VecElementType arg1) noexcept { 1573 return VecOpInfo{(1u << 28) | (uint32_t(ret) << 24) | uint32_t(arg0) | (uint32_t(arg1) << 4)}; 1574 } 1575 1576 static ASMJIT_INLINE_NODEBUG VecOpInfo make(VecElementType ret, VecElementType arg0, VecElementType arg1, VecElementType arg2) noexcept { 1577 return VecOpInfo{(1u << 28) | (uint32_t(ret) << 24) | uint32_t(arg0) | (uint32_t(arg1) << 4) | (uint32_t(arg2) << 8)}; 1578 } 1579 1580 static ASMJIT_INLINE_NODEBUG VecOpInfo make(VecElementType ret, VecElementType arg0, VecElementType arg1, VecElementType arg2, VecElementType arg3) noexcept { 1581 return VecOpInfo{(1u << 28) | (uint32_t(ret) << 24) | uint32_t(arg0) | (uint32_t(arg1) << 4) | (uint32_t(arg2) << 8) | (uint32_t(arg3) << 12)}; 1582 } 1583 }; 1584 1585 template<uint32_t kW> 1586 struct alignas(16) VecOverlay { 1587 union { 1588 int8_t data_i8[kW]; 1589 uint8_t data_u8[kW]; 1590 1591 int16_t data_i16[kW / 2u]; 1592 uint16_t data_u16[kW / 2u]; 1593 1594 int32_t data_i32[kW / 4u]; 1595 uint32_t data_u32[kW / 4u]; 1596 1597 int64_t data_i64[kW / 8u]; 1598 uint64_t data_u64[kW / 8u]; 1599 1600 float data_f32[kW / 4u]; 1601 double data_f64[kW / 8u]; 1602 }; 1603 1604 template<typename T> 1605 ASMJIT_INLINE_NODEBUG T* data() noexcept; 1606 1607 template<typename T> 1608 ASMJIT_INLINE_NODEBUG const T* data() const noexcept; 1609 1610 template<typename T> 1611 ASMJIT_INLINE_NODEBUG T get(size_t index) const noexcept; 1612 1613 template<typename T> 1614 ASMJIT_INLINE_NODEBUG void set(size_t index, const T& value) noexcept; 1615 1616 template<uint32_t kOtherW> 1617 ASMJIT_INLINE_NODEBUG void copy_16b_from(const VecOverlay<kOtherW>& other) noexcept { 1618 data_u64[0] = other.data_u64[0]; 1619 data_u64[1] = other.data_u64[1]; 1620 } 1621 }; 1622 1623 template<typename T> 1624 struct VecAccess; 1625 1626 template<> 1627 struct VecAccess<int8_t> { 1628 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG int8_t* data(VecOverlay<kW>& vec) noexcept { return vec.data_i8; } 1629 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG const int8_t* data(const VecOverlay<kW>& vec) noexcept { return vec.data_i8; } 1630 1631 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG int8_t get(const VecOverlay<kW>& vec, size_t index) noexcept { return vec.data_i8[index]; } 1632 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG void set(VecOverlay<kW>& vec, size_t index, int8_t value) noexcept { vec.data_i8[index] = value; } 1633 }; 1634 1635 template<> 1636 struct VecAccess<int16_t> { 1637 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG int16_t* data(VecOverlay<kW>& vec) noexcept { return vec.data_i16; } 1638 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG const int16_t* data(const VecOverlay<kW>& vec) noexcept { return vec.data_i16; } 1639 1640 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG int16_t get(const VecOverlay<kW>& vec, size_t index) noexcept { return vec.data_i16[index]; } 1641 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG void set(VecOverlay<kW>& vec, size_t index, int16_t value) noexcept { vec.data_i16[index] = value; } 1642 }; 1643 1644 template<> 1645 struct VecAccess<int32_t> { 1646 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG int32_t* data(VecOverlay<kW>& vec) noexcept { return vec.data_i32; } 1647 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG const int32_t* data(const VecOverlay<kW>& vec) noexcept { return vec.data_i32; } 1648 1649 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG int32_t get(const VecOverlay<kW>& vec, size_t index) noexcept { return vec.data_i32[index]; } 1650 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG void set(VecOverlay<kW>& vec, size_t index, int32_t value) noexcept { vec.data_i32[index] = value; } 1651 }; 1652 1653 template<> 1654 struct VecAccess<int64_t> { 1655 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG int64_t* data(VecOverlay<kW>& vec) noexcept { return vec.data_i64; } 1656 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG const int64_t* data(const VecOverlay<kW>& vec) noexcept { return vec.data_i64; } 1657 1658 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG int64_t get(const VecOverlay<kW>& vec, size_t index) noexcept { return vec.data_i64[index]; } 1659 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG void set(VecOverlay<kW>& vec, size_t index, int64_t value) noexcept { vec.data_i64[index] = value; } 1660 }; 1661 1662 template<> 1663 struct VecAccess<uint8_t> { 1664 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG uint8_t* data(VecOverlay<kW>& vec) noexcept { return vec.data_u8; } 1665 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG const uint8_t* data(const VecOverlay<kW>& vec) noexcept { return vec.data_u8; } 1666 1667 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG uint8_t get(const VecOverlay<kW>& vec, size_t index) noexcept { return vec.data_u8[index]; } 1668 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG void set(VecOverlay<kW>& vec, size_t index, uint8_t value) noexcept { vec.data_u8[index] = value; } 1669 }; 1670 1671 template<> 1672 struct VecAccess<uint16_t> { 1673 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG uint16_t* data(VecOverlay<kW>& vec) noexcept { return vec.data_u16; } 1674 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG const uint16_t* data(const VecOverlay<kW>& vec) noexcept { return vec.data_u16; } 1675 1676 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG uint16_t get(const VecOverlay<kW>& vec, size_t index) noexcept { return vec.data_u16[index]; } 1677 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG void set(VecOverlay<kW>& vec, size_t index, uint16_t value) noexcept { vec.data_u16[index] = value; } 1678 }; 1679 1680 template<> 1681 struct VecAccess<uint32_t> { 1682 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG uint32_t* data(VecOverlay<kW>& vec) noexcept { return vec.data_u32; } 1683 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG const uint32_t* data(const VecOverlay<kW>& vec) noexcept { return vec.data_u32; } 1684 1685 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG uint32_t get(const VecOverlay<kW>& vec, size_t index) noexcept { return vec.data_u32[index]; } 1686 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG void set(VecOverlay<kW>& vec, size_t index, uint32_t value) noexcept { vec.data_u32[index] = value; } 1687 }; 1688 1689 template<> 1690 struct VecAccess<uint64_t> { 1691 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG uint64_t* data(VecOverlay<kW>& vec) noexcept { return vec.data_u64; } 1692 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG const uint64_t* data(const VecOverlay<kW>& vec) noexcept { return vec.data_u64; } 1693 1694 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG uint64_t get(const VecOverlay<kW>& vec, size_t index) noexcept { return vec.data_u64[index]; } 1695 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG void set(VecOverlay<kW>& vec, size_t index, uint64_t value) noexcept { vec.data_u64[index] = value; } 1696 }; 1697 1698 template<> 1699 struct VecAccess<float> { 1700 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG float* data(VecOverlay<kW>& vec) noexcept { return vec.data_f32; } 1701 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG const float* data(const VecOverlay<kW>& vec) noexcept { return vec.data_f32; } 1702 1703 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG float get(const VecOverlay<kW>& vec, size_t index) noexcept { return vec.data_f32[index]; } 1704 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG void set(VecOverlay<kW>& vec, size_t index, float value) noexcept { vec.data_f32[index] = value; } 1705 }; 1706 1707 template<> 1708 struct VecAccess<double> { 1709 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG double* data(VecOverlay<kW>& vec) noexcept { return vec.data_f64; } 1710 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG const double* data(const VecOverlay<kW>& vec) noexcept { return vec.data_f64; } 1711 1712 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG double get(const VecOverlay<kW>& vec, size_t index) noexcept { return vec.data_f64[index]; } 1713 template<uint32_t kW> static ASMJIT_INLINE_NODEBUG void set(VecOverlay<kW>& vec, size_t index, double value) noexcept { vec.data_f64[index] = value; } 1714 }; 1715 1716 template<uint32_t kW> 1717 template<typename T> 1718 ASMJIT_INLINE_NODEBUG T* VecOverlay<kW>::data() noexcept { return VecAccess<T>::data(*this); } 1719 1720 template<uint32_t kW> 1721 template<typename T> 1722 ASMJIT_INLINE_NODEBUG const T* VecOverlay<kW>::data() const noexcept { return VecAccess<T>::data(*this); } 1723 1724 template<uint32_t kW> 1725 template<typename T> 1726 ASMJIT_INLINE_NODEBUG T VecOverlay<kW>::get(size_t index) const noexcept { return VecAccess<T>::get(*this, index); } 1727 1728 template<uint32_t kW> 1729 template<typename T> 1730 ASMJIT_INLINE_NODEBUG void VecOverlay<kW>::set(size_t index, const T& value) noexcept { return VecAccess<T>::set(*this, index, value); } 1731 1732 template<typename T> struct TypeNameToString {}; 1733 template<> struct TypeNameToString<int8_t > { static ASMJIT_INLINE_NODEBUG const char* get() noexcept { return "int8"; } }; 1734 template<> struct TypeNameToString<int16_t > { static ASMJIT_INLINE_NODEBUG const char* get() noexcept { return "int16"; } }; 1735 template<> struct TypeNameToString<int32_t > { static ASMJIT_INLINE_NODEBUG const char* get() noexcept { return "int32"; } }; 1736 template<> struct TypeNameToString<int64_t > { static ASMJIT_INLINE_NODEBUG const char* get() noexcept { return "int64"; } }; 1737 template<> struct TypeNameToString<uint8_t > { static ASMJIT_INLINE_NODEBUG const char* get() noexcept { return "uint8"; } }; 1738 template<> struct TypeNameToString<uint16_t> { static ASMJIT_INLINE_NODEBUG const char* get() noexcept { return "uint16"; } }; 1739 template<> struct TypeNameToString<uint32_t> { static ASMJIT_INLINE_NODEBUG const char* get() noexcept { return "uint32"; } }; 1740 template<> struct TypeNameToString<uint64_t> { static ASMJIT_INLINE_NODEBUG const char* get() noexcept { return "uint64"; } }; 1741 template<> struct TypeNameToString<float > { static ASMJIT_INLINE_NODEBUG const char* get() noexcept { return "float32"; } }; 1742 template<> struct TypeNameToString<double > { static ASMJIT_INLINE_NODEBUG const char* get() noexcept { return "float64"; } }; 1743 1744 template<uint32_t kW> 1745 static bool vec_eq(const VecOverlay<kW>& a, const VecOverlay<kW>& b) noexcept { 1746 return memcmp(a.data_u8, b.data_u8, kW) == 0; 1747 } 1748 1749 template<typename T> 1750 static bool float_eq(const T& a, const T& b) noexcept { 1751 return a == b || (std::isnan(a) && std::isnan(b)); 1752 } 1753 1754 template<uint32_t kW> 1755 static bool vec_eq(const VecOverlay<kW>& a, const VecOverlay<kW>& b, VecElementType element_type) noexcept { 1756 if (element_type == VecElementType::kFloat32) { 1757 size_t count = kW / sizeof(float); 1758 for (size_t i = 0; i < count; i++) { 1759 if (!float_eq(a.data_f32[i], b.data_f32[i])) { 1760 return false; 1761 } 1762 } 1763 return true; 1764 } 1765 else if (element_type == VecElementType::kFloat64) { 1766 size_t count = kW / sizeof(double); 1767 for (size_t i = 0; i < count; i++) { 1768 if (!float_eq(a.data_f64[i], b.data_f64[i])) { 1769 return false; 1770 } 1771 } 1772 return true; 1773 } 1774 else { 1775 return vec_eq(a, b); 1776 } 1777 } 1778 1779 template<uint32_t kW> 1780 static ASMJIT_NOINLINE String vec_stringify(const VecOverlay<kW>& vec, VecElementType element_type) noexcept { 1781 String s; 1782 s.append('{'); 1783 1784 switch (element_type) { 1785 case VecElementType::kInt8 : { for (uint32_t i = 0; i < kW ; i++) s.append_format("%s%d" , i == 0 ? "" : ", ", vec.data_i8[i]); break; } 1786 case VecElementType::kInt16 : { for (uint32_t i = 0; i < kW / 2; i++) s.append_format("%s%d" , i == 0 ? "" : ", ", vec.data_i16[i]); break; } 1787 case VecElementType::kInt32 : { for (uint32_t i = 0; i < kW / 4; i++) s.append_format("%s%d" , i == 0 ? "" : ", ", vec.data_i32[i]); break; } 1788 case VecElementType::kInt64 : { for (uint32_t i = 0; i < kW / 8; i++) s.append_format("%s%lld", i == 0 ? "" : ", ", (long long)vec.data_i64[i]); break; } 1789 case VecElementType::kUInt8 : { for (uint32_t i = 0; i < kW ; i++) s.append_format("%s%u" , i == 0 ? "" : ", ", vec.data_u8[i]); break; } 1790 case VecElementType::kUInt16 : { for (uint32_t i = 0; i < kW / 2; i++) s.append_format("%s%u" , i == 0 ? "" : ", ", vec.data_u16[i]); break; } 1791 case VecElementType::kUInt32 : { for (uint32_t i = 0; i < kW / 4; i++) s.append_format("%s%u" , i == 0 ? "" : ", ", vec.data_u32[i]); break; } 1792 case VecElementType::kUInt64 : { for (uint32_t i = 0; i < kW / 8; i++) s.append_format("%s%llu", i == 0 ? "" : ", ", (unsigned long long)vec.data_u64[i]); break; } 1793 case VecElementType::kFloat32: { for (uint32_t i = 0; i < kW / 4; i++) s.append_format("%s%.20f" , i == 0 ? "" : ", ", double(vec.data_f32[i])); break; } 1794 case VecElementType::kFloat64: { for (uint32_t i = 0; i < kW / 8; i++) s.append_format("%s%.20f" , i == 0 ? "" : ", ", double(vec.data_f64[i])); break; } 1795 1796 default: 1797 ASMJIT_NOT_REACHED(); 1798 } 1799 1800 s.append('}'); 1801 return s; 1802 } 1803 1804 // ujit::UniCompiler - Tests - SIMD - Metadata 1805 // =========================================== 1806 1807 static const char* vec_op_name_vv(UniOpVV op) noexcept { 1808 switch (op) { 1809 case UniOpVV::kMov : return "v_mov"; 1810 case UniOpVV::kMovU64 : return "v_mov_u64"; 1811 case UniOpVV::kBroadcastU8Z : return "v_broadcast_u8z"; 1812 case UniOpVV::kBroadcastU16Z : return "v_broadcast_u16z"; 1813 case UniOpVV::kBroadcastU8 : return "v_broadcast_u8"; 1814 case UniOpVV::kBroadcastU16 : return "v_broadcast_u16"; 1815 case UniOpVV::kBroadcastU32 : return "v_broadcast_u32"; 1816 case UniOpVV::kBroadcastU64 : return "v_broadcast_u64"; 1817 case UniOpVV::kBroadcastF32 : return "v_broadcast_f32"; 1818 case UniOpVV::kBroadcastF64 : return "v_broadcast_f64"; 1819 case UniOpVV::kBroadcastV128_U32 : return "v_broadcast_v128_u32"; 1820 case UniOpVV::kBroadcastV128_U64 : return "v_broadcast_v128_u64"; 1821 case UniOpVV::kBroadcastV128_F32 : return "v_broadcast_v128_f32"; 1822 case UniOpVV::kBroadcastV128_F64 : return "v_broadcast_v128_f64"; 1823 case UniOpVV::kBroadcastV256_U32 : return "v_broadcast_v256_u32"; 1824 case UniOpVV::kBroadcastV256_U64 : return "v_broadcast_v256_u64"; 1825 case UniOpVV::kBroadcastV256_F32 : return "v_broadcast_v256_f32"; 1826 case UniOpVV::kBroadcastV256_F64 : return "v_broadcast_v256_f64"; 1827 case UniOpVV::kAbsI8 : return "v_abs_i8"; 1828 case UniOpVV::kAbsI16 : return "v_abs_i16"; 1829 case UniOpVV::kAbsI32 : return "v_abs_i32"; 1830 case UniOpVV::kAbsI64 : return "v_abs_i64"; 1831 case UniOpVV::kNotU32 : return "v_not_u32"; 1832 case UniOpVV::kNotU64 : return "v_not_u64"; 1833 case UniOpVV::kCvtI8LoToI16 : return "v_cvt_i8_lo_to_i16"; 1834 case UniOpVV::kCvtI8HiToI16 : return "v_cvt_i8_hi_to_i16"; 1835 case UniOpVV::kCvtU8LoToU16 : return "v_cvt_u8_lo_to_u16"; 1836 case UniOpVV::kCvtU8HiToU16 : return "v_cvt_u8_hi_to_u16"; 1837 case UniOpVV::kCvtI8ToI32 : return "v_cvt_i8_to_i32"; 1838 case UniOpVV::kCvtU8ToU32 : return "v_cvt_u8_to_u32"; 1839 case UniOpVV::kCvtI16LoToI32 : return "v_cvt_i16_lo_to_i32"; 1840 case UniOpVV::kCvtI16HiToI32 : return "v_cvt_i16_hi_to_i32"; 1841 case UniOpVV::kCvtU16LoToU32 : return "v_cvt_u16_lo_to_u32"; 1842 case UniOpVV::kCvtU16HiToU32 : return "v_cvt_u16_hi_to_u32"; 1843 case UniOpVV::kCvtI32LoToI64 : return "v_cvt_i32_lo_to_i64"; 1844 case UniOpVV::kCvtI32HiToI64 : return "v_cvt_i32_hi_to_i64"; 1845 case UniOpVV::kCvtU32LoToU64 : return "v_cvt_u32_lo_to_u64"; 1846 case UniOpVV::kCvtU32HiToU64 : return "v_cvt_u32_hi_to_u64"; 1847 case UniOpVV::kAbsF32S : return "s_abs_f32"; 1848 case UniOpVV::kAbsF64S : return "s_abs_f64"; 1849 case UniOpVV::kAbsF32 : return "v_abs_f32"; 1850 case UniOpVV::kAbsF64 : return "v_abs_f64"; 1851 case UniOpVV::kNegF32S : return "s_neg_f32"; 1852 case UniOpVV::kNegF64S : return "s_neg_f64"; 1853 case UniOpVV::kNegF32 : return "v_neg_f32"; 1854 case UniOpVV::kNegF64 : return "v_neg_f64"; 1855 case UniOpVV::kNotF32 : return "v_not_f32"; 1856 case UniOpVV::kNotF64 : return "v_not_f64"; 1857 case UniOpVV::kTruncF32S : return "v_trunc_f32s"; 1858 case UniOpVV::kTruncF64S : return "v_trunc_f64s"; 1859 case UniOpVV::kTruncF32 : return "v_trunc_f32"; 1860 case UniOpVV::kTruncF64 : return "v_trunc_f64"; 1861 case UniOpVV::kFloorF32S : return "v_floor_f32s"; 1862 case UniOpVV::kFloorF64S : return "v_floor_f64s"; 1863 case UniOpVV::kFloorF32 : return "v_floor_f32"; 1864 case UniOpVV::kFloorF64 : return "v_floor_f64"; 1865 case UniOpVV::kCeilF32S : return "v_ceil_f32s"; 1866 case UniOpVV::kCeilF64S : return "v_ceil_f64s"; 1867 case UniOpVV::kCeilF32 : return "v_ceil_f32"; 1868 case UniOpVV::kCeilF64 : return "v_ceil_f64"; 1869 case UniOpVV::kRoundEvenF32S : return "v_round_even_f32s"; 1870 case UniOpVV::kRoundEvenF64S : return "v_round_even_f64s"; 1871 case UniOpVV::kRoundEvenF32 : return "v_round_even_f32"; 1872 case UniOpVV::kRoundEvenF64 : return "v_round_even_f64"; 1873 case UniOpVV::kRoundHalfAwayF32S : return "v_round_half_away_f32s"; 1874 case UniOpVV::kRoundHalfAwayF64S : return "v_round_half_away_f64s"; 1875 case UniOpVV::kRoundHalfAwayF32 : return "v_round_half_away_f32"; 1876 case UniOpVV::kRoundHalfAwayF64 : return "v_round_half_away_f64"; 1877 case UniOpVV::kRoundHalfUpF32S : return "v_round_half_up_f32s"; 1878 case UniOpVV::kRoundHalfUpF64S : return "v_round_half_up_f64s"; 1879 case UniOpVV::kRoundHalfUpF32 : return "v_round_half_up_f32"; 1880 case UniOpVV::kRoundHalfUpF64 : return "v_round_half_up_f64"; 1881 case UniOpVV::kRcpF32 : return "v_rcp_f32"; 1882 case UniOpVV::kRcpF64 : return "v_rcp_f64"; 1883 case UniOpVV::kSqrtF32S : return "v_sqrt_f32s"; 1884 case UniOpVV::kSqrtF64S : return "v_sqrt_f64s"; 1885 case UniOpVV::kSqrtF32 : return "v_sqrt_f32"; 1886 case UniOpVV::kSqrtF64 : return "v_sqrt_f64"; 1887 case UniOpVV::kCvtF32ToF64S : return "v_cvt_f32_to_f64s"; 1888 case UniOpVV::kCvtF64ToF32S : return "v_cvt_f64_to_f32s"; 1889 case UniOpVV::kCvtI32ToF32 : return "v_cvt_i32_to_f32"; 1890 case UniOpVV::kCvtF32LoToF64 : return "v_cvt_f32_lo_to_f64"; 1891 case UniOpVV::kCvtF32HiToF64 : return "v_cvt_f32_hi_to_f64"; 1892 case UniOpVV::kCvtF64ToF32Lo : return "v_cvt_f64_to_f32_lo"; 1893 case UniOpVV::kCvtF64ToF32Hi : return "v_cvt_f64_to_f32_hi"; 1894 case UniOpVV::kCvtI32LoToF64 : return "v_cvt_i32_lo_to_f64"; 1895 case UniOpVV::kCvtI32HiToF64 : return "v_cvt_i32_hi_to_f64"; 1896 case UniOpVV::kCvtTruncF32ToI32 : return "v_cvt_trunc_f32_to_i32"; 1897 case UniOpVV::kCvtTruncF64ToI32Lo: return "v_cvt_trunc_f64_to_i32_lo"; 1898 case UniOpVV::kCvtTruncF64ToI32Hi: return "v_cvt_trunc_f64_to_i32_hi"; 1899 case UniOpVV::kCvtRoundF32ToI32 : return "v_cvt_round_f32_to_i32"; 1900 case UniOpVV::kCvtRoundF64ToI32Lo: return "v_cvt_round_f64_to_i32_lo"; 1901 case UniOpVV::kCvtRoundF64ToI32Hi: return "v_cvt_round_f64_to_i32_hi"; 1902 } 1903 1904 ASMJIT_NOT_REACHED(); 1905 } 1906 1907 static VecOpInfo vec_op_info_vv(UniOpVV op) noexcept { 1908 using VE = VecElementType; 1909 1910 switch (op) { 1911 case UniOpVV::kMov : return VecOpInfo::make(VE::kUInt8, VE::kUInt8); 1912 case UniOpVV::kMovU64 : return VecOpInfo::make(VE::kUInt8, VE::kUInt8); 1913 case UniOpVV::kBroadcastU8Z : return VecOpInfo::make(VE::kUInt8, VE::kUInt8); 1914 case UniOpVV::kBroadcastU16Z : return VecOpInfo::make(VE::kUInt16, VE::kUInt16); 1915 case UniOpVV::kBroadcastU8 : return VecOpInfo::make(VE::kUInt8, VE::kUInt8); 1916 case UniOpVV::kBroadcastU16 : return VecOpInfo::make(VE::kUInt16, VE::kUInt16); 1917 case UniOpVV::kBroadcastU32 : return VecOpInfo::make(VE::kUInt32, VE::kUInt32); 1918 case UniOpVV::kBroadcastU64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64); 1919 case UniOpVV::kBroadcastF32 : return VecOpInfo::make(VE::kFloat32, VE::kFloat32); 1920 case UniOpVV::kBroadcastF64 : return VecOpInfo::make(VE::kFloat64, VE::kFloat64); 1921 case UniOpVV::kBroadcastV128_U32 : return VecOpInfo::make(VE::kUInt32, VE::kUInt32); 1922 case UniOpVV::kBroadcastV128_U64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64); 1923 case UniOpVV::kBroadcastV128_F32 : return VecOpInfo::make(VE::kFloat32, VE::kFloat32); 1924 case UniOpVV::kBroadcastV128_F64 : return VecOpInfo::make(VE::kFloat64, VE::kFloat64); 1925 case UniOpVV::kBroadcastV256_U32 : return VecOpInfo::make(VE::kUInt32, VE::kUInt32); 1926 case UniOpVV::kBroadcastV256_U64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64); 1927 case UniOpVV::kBroadcastV256_F32 : return VecOpInfo::make(VE::kFloat32, VE::kFloat32); 1928 case UniOpVV::kBroadcastV256_F64 : return VecOpInfo::make(VE::kFloat64, VE::kFloat64); 1929 case UniOpVV::kAbsI8 : return VecOpInfo::make(VE::kUInt8, VE::kInt8); 1930 case UniOpVV::kAbsI16 : return VecOpInfo::make(VE::kUInt16, VE::kInt16); 1931 case UniOpVV::kAbsI32 : return VecOpInfo::make(VE::kUInt32, VE::kInt32); 1932 case UniOpVV::kAbsI64 : return VecOpInfo::make(VE::kUInt64, VE::kInt64); 1933 case UniOpVV::kNotU32 : return VecOpInfo::make(VE::kUInt32, VE::kInt32); 1934 case UniOpVV::kNotU64 : return VecOpInfo::make(VE::kUInt64, VE::kInt64); 1935 case UniOpVV::kCvtI8LoToI16 : return VecOpInfo::make(VE::kInt16, VE::kInt8); 1936 case UniOpVV::kCvtI8HiToI16 : return VecOpInfo::make(VE::kInt16, VE::kInt8); 1937 case UniOpVV::kCvtU8LoToU16 : return VecOpInfo::make(VE::kUInt16, VE::kUInt8); 1938 case UniOpVV::kCvtU8HiToU16 : return VecOpInfo::make(VE::kUInt16, VE::kUInt8); 1939 case UniOpVV::kCvtI8ToI32 : return VecOpInfo::make(VE::kInt32, VE::kInt8); 1940 case UniOpVV::kCvtU8ToU32 : return VecOpInfo::make(VE::kUInt32, VE::kUInt8); 1941 case UniOpVV::kCvtI16LoToI32 : return VecOpInfo::make(VE::kInt32, VE::kInt16); 1942 case UniOpVV::kCvtI16HiToI32 : return VecOpInfo::make(VE::kInt32, VE::kInt16); 1943 case UniOpVV::kCvtU16LoToU32 : return VecOpInfo::make(VE::kUInt32, VE::kUInt16); 1944 case UniOpVV::kCvtU16HiToU32 : return VecOpInfo::make(VE::kUInt32, VE::kUInt16); 1945 case UniOpVV::kCvtI32LoToI64 : return VecOpInfo::make(VE::kInt64, VE::kInt32); 1946 case UniOpVV::kCvtI32HiToI64 : return VecOpInfo::make(VE::kInt64, VE::kInt32); 1947 case UniOpVV::kCvtU32LoToU64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt32); 1948 case UniOpVV::kCvtU32HiToU64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt32); 1949 case UniOpVV::kAbsF32S : return VecOpInfo::make(VE::kFloat32, VE::kFloat32); 1950 case UniOpVV::kAbsF64S : return VecOpInfo::make(VE::kFloat64, VE::kFloat64); 1951 case UniOpVV::kAbsF32 : return VecOpInfo::make(VE::kFloat32, VE::kFloat32); 1952 case UniOpVV::kAbsF64 : return VecOpInfo::make(VE::kFloat64, VE::kFloat64); 1953 case UniOpVV::kNegF32S : return VecOpInfo::make(VE::kFloat32, VE::kFloat32); 1954 case UniOpVV::kNegF64S : return VecOpInfo::make(VE::kFloat64, VE::kFloat64); 1955 case UniOpVV::kNegF32 : return VecOpInfo::make(VE::kFloat32, VE::kFloat32); 1956 case UniOpVV::kNegF64 : return VecOpInfo::make(VE::kFloat64, VE::kFloat64); 1957 case UniOpVV::kNotF32 : return VecOpInfo::make(VE::kUInt32, VE::kUInt32); 1958 case UniOpVV::kNotF64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64); 1959 case UniOpVV::kTruncF32S : return VecOpInfo::make(VE::kFloat32, VE::kFloat32); 1960 case UniOpVV::kTruncF64S : return VecOpInfo::make(VE::kFloat64, VE::kFloat64); 1961 case UniOpVV::kTruncF32 : return VecOpInfo::make(VE::kFloat32, VE::kFloat32); 1962 case UniOpVV::kTruncF64 : return VecOpInfo::make(VE::kFloat64, VE::kFloat64); 1963 case UniOpVV::kFloorF32S : return VecOpInfo::make(VE::kFloat32, VE::kFloat32); 1964 case UniOpVV::kFloorF64S : return VecOpInfo::make(VE::kFloat64, VE::kFloat64); 1965 case UniOpVV::kFloorF32 : return VecOpInfo::make(VE::kFloat32, VE::kFloat32); 1966 case UniOpVV::kFloorF64 : return VecOpInfo::make(VE::kFloat64, VE::kFloat64); 1967 case UniOpVV::kCeilF32S : return VecOpInfo::make(VE::kFloat32, VE::kFloat32); 1968 case UniOpVV::kCeilF64S : return VecOpInfo::make(VE::kFloat64, VE::kFloat64); 1969 case UniOpVV::kCeilF32 : return VecOpInfo::make(VE::kFloat32, VE::kFloat32); 1970 case UniOpVV::kCeilF64 : return VecOpInfo::make(VE::kFloat64, VE::kFloat64); 1971 case UniOpVV::kRoundEvenF32S : return VecOpInfo::make(VE::kFloat32, VE::kFloat32); 1972 case UniOpVV::kRoundEvenF64S : return VecOpInfo::make(VE::kFloat64, VE::kFloat64); 1973 case UniOpVV::kRoundEvenF32 : return VecOpInfo::make(VE::kFloat32, VE::kFloat32); 1974 case UniOpVV::kRoundEvenF64 : return VecOpInfo::make(VE::kFloat64, VE::kFloat64); 1975 case UniOpVV::kRoundHalfAwayF32S : return VecOpInfo::make(VE::kFloat32, VE::kFloat32); 1976 case UniOpVV::kRoundHalfAwayF64S : return VecOpInfo::make(VE::kFloat64, VE::kFloat64); 1977 case UniOpVV::kRoundHalfAwayF32 : return VecOpInfo::make(VE::kFloat32, VE::kFloat32); 1978 case UniOpVV::kRoundHalfAwayF64 : return VecOpInfo::make(VE::kFloat64, VE::kFloat64); 1979 case UniOpVV::kRoundHalfUpF32S : return VecOpInfo::make(VE::kFloat32, VE::kFloat32); 1980 case UniOpVV::kRoundHalfUpF64S : return VecOpInfo::make(VE::kFloat64, VE::kFloat64); 1981 case UniOpVV::kRoundHalfUpF32 : return VecOpInfo::make(VE::kFloat32, VE::kFloat32); 1982 case UniOpVV::kRoundHalfUpF64 : return VecOpInfo::make(VE::kFloat64, VE::kFloat64); 1983 case UniOpVV::kRcpF32 : return VecOpInfo::make(VE::kFloat32, VE::kFloat32); 1984 case UniOpVV::kRcpF64 : return VecOpInfo::make(VE::kFloat64, VE::kFloat64); 1985 case UniOpVV::kSqrtF32S : return VecOpInfo::make(VE::kFloat32, VE::kFloat32); 1986 case UniOpVV::kSqrtF64S : return VecOpInfo::make(VE::kFloat64, VE::kFloat64); 1987 case UniOpVV::kSqrtF32 : return VecOpInfo::make(VE::kFloat32, VE::kFloat32); 1988 case UniOpVV::kSqrtF64 : return VecOpInfo::make(VE::kFloat64, VE::kFloat64); 1989 case UniOpVV::kCvtF32ToF64S : return VecOpInfo::make(VE::kFloat64, VE::kFloat32); 1990 case UniOpVV::kCvtF64ToF32S : return VecOpInfo::make(VE::kFloat32, VE::kFloat64); 1991 case UniOpVV::kCvtI32ToF32 : return VecOpInfo::make(VE::kFloat32, VE::kInt32); 1992 case UniOpVV::kCvtF32LoToF64 : return VecOpInfo::make(VE::kFloat64, VE::kFloat32); 1993 case UniOpVV::kCvtF32HiToF64 : return VecOpInfo::make(VE::kFloat64, VE::kFloat32); 1994 case UniOpVV::kCvtF64ToF32Lo : return VecOpInfo::make(VE::kFloat32, VE::kFloat64); 1995 case UniOpVV::kCvtF64ToF32Hi : return VecOpInfo::make(VE::kFloat32, VE::kFloat64); 1996 case UniOpVV::kCvtI32LoToF64 : return VecOpInfo::make(VE::kFloat64, VE::kInt32); 1997 case UniOpVV::kCvtI32HiToF64 : return VecOpInfo::make(VE::kFloat64, VE::kInt32); 1998 case UniOpVV::kCvtTruncF32ToI32 : return VecOpInfo::make(VE::kInt32, VE::kFloat32); 1999 case UniOpVV::kCvtTruncF64ToI32Lo: return VecOpInfo::make(VE::kInt32, VE::kFloat64); 2000 case UniOpVV::kCvtTruncF64ToI32Hi: return VecOpInfo::make(VE::kInt32, VE::kFloat64); 2001 case UniOpVV::kCvtRoundF32ToI32 : return VecOpInfo::make(VE::kInt32, VE::kFloat32); 2002 case UniOpVV::kCvtRoundF64ToI32Lo: return VecOpInfo::make(VE::kInt32, VE::kFloat64); 2003 case UniOpVV::kCvtRoundF64ToI32Hi: return VecOpInfo::make(VE::kInt32, VE::kFloat64); 2004 } 2005 2006 ASMJIT_NOT_REACHED(); 2007 } 2008 2009 static const char* vec_op_name_vvi(UniOpVVI op) noexcept { 2010 switch (op) { 2011 case UniOpVVI::kSllU16 : return "v_sll_u16"; 2012 case UniOpVVI::kSllU32 : return "v_sll_u32"; 2013 case UniOpVVI::kSllU64 : return "v_sll_u64"; 2014 case UniOpVVI::kSrlU16 : return "v_srl_u16"; 2015 case UniOpVVI::kSrlU32 : return "v_srl_u32"; 2016 case UniOpVVI::kSrlU64 : return "v_srl_u64"; 2017 case UniOpVVI::kSraI16 : return "v_sra_i16"; 2018 case UniOpVVI::kSraI32 : return "v_sra_i32"; 2019 case UniOpVVI::kSraI64 : return "v_sra_i64"; 2020 case UniOpVVI::kSllbU128 : return "v_sllb_u128"; 2021 case UniOpVVI::kSrlbU128 : return "v_srlb_u128"; 2022 case UniOpVVI::kSwizzleU16x4 : return "v_swizzle_u16x4"; 2023 case UniOpVVI::kSwizzleLoU16x4 : return "v_swizzle_lo_u16x4"; 2024 case UniOpVVI::kSwizzleHiU16x4 : return "v_swizzle_hi_u16x4"; 2025 case UniOpVVI::kSwizzleU32x4 : return "v_swizzle_u32x4"; 2026 case UniOpVVI::kSwizzleU64x2 : return "v_swizzle_u64x2"; 2027 case UniOpVVI::kSwizzleF32x4 : return "v_swizzle_f32x4"; 2028 case UniOpVVI::kSwizzleF64x2 : return "v_swizzle_f64x2"; 2029 case UniOpVVI::kSwizzleU64x4 : return "v_swizzle_u64x4"; 2030 case UniOpVVI::kSwizzleF64x4 : return "v_swizzle_f64x4"; 2031 case UniOpVVI::kExtractV128_I32: return "v_extract_v128_i32"; 2032 case UniOpVVI::kExtractV128_I64: return "v_extract_v128_i64"; 2033 case UniOpVVI::kExtractV128_F32: return "v_extract_v128_f32"; 2034 case UniOpVVI::kExtractV128_F64: return "v_extract_v128_f64"; 2035 case UniOpVVI::kExtractV256_I32: return "v_extract_v256_i32"; 2036 case UniOpVVI::kExtractV256_I64: return "v_extract_v256_i64"; 2037 case UniOpVVI::kExtractV256_F32: return "v_extract_v256_f32"; 2038 case UniOpVVI::kExtractV256_F64: return "v_extract_v256_f64"; 2039 2040 #if defined(ASMJIT_UJIT_AARCH64) 2041 case UniOpVVI::kSrlRndU16 : return "v_srl_rnd_u16"; 2042 case UniOpVVI::kSrlRndU32 : return "v_srl_rnd_u32"; 2043 case UniOpVVI::kSrlRndU64 : return "v_srl_rnd_u64"; 2044 case UniOpVVI::kSrlAccU16 : return "v_srl_acc_u16"; 2045 case UniOpVVI::kSrlAccU32 : return "v_srl_acc_u32"; 2046 case UniOpVVI::kSrlAccU64 : return "v_srl_acc_u64"; 2047 case UniOpVVI::kSrlRndAccU16 : return "v_srl_rnd_acc_u16"; 2048 case UniOpVVI::kSrlRndAccU32 : return "v_srl_rnd_acc_u32"; 2049 case UniOpVVI::kSrlRndAccU64 : return "v_srl_rnd_acc_u64"; 2050 case UniOpVVI::kSrlnLoU16 : return "v_srln_lo_u16"; 2051 case UniOpVVI::kSrlnHiU16 : return "v_srln_hi_u16"; 2052 case UniOpVVI::kSrlnLoU32 : return "v_srln_lo_u32"; 2053 case UniOpVVI::kSrlnHiU32 : return "v_srln_hi_u32"; 2054 case UniOpVVI::kSrlnLoU64 : return "v_srln_lo_u64"; 2055 case UniOpVVI::kSrlnHiU64 : return "v_srln_hi_u64"; 2056 case UniOpVVI::kSrlnRndLoU16 : return "v_srln_rnd_lo_u16"; 2057 case UniOpVVI::kSrlnRndHiU16 : return "v_srln_rnd_hi_u16"; 2058 case UniOpVVI::kSrlnRndLoU32 : return "v_srln_rnd_lo_u32"; 2059 case UniOpVVI::kSrlnRndHiU32 : return "v_srln_rnd_hi_u32"; 2060 case UniOpVVI::kSrlnRndLoU64 : return "v_srln_rnd_lo_u64"; 2061 case UniOpVVI::kSrlnRndHiU64 : return "v_srln_rnd_hi_u64"; 2062 #endif // ASMJIT_UJIT_AARCH64 2063 } 2064 2065 ASMJIT_NOT_REACHED(); 2066 } 2067 2068 static VecOpInfo vec_op_info_vvi(UniOpVVI op) noexcept { 2069 using VE = VecElementType; 2070 2071 switch (op) { 2072 case UniOpVVI::kSllU16 : return VecOpInfo::make(VE::kUInt16 , VE::kUInt16); 2073 case UniOpVVI::kSllU32 : return VecOpInfo::make(VE::kUInt32 , VE::kUInt32); 2074 case UniOpVVI::kSllU64 : return VecOpInfo::make(VE::kUInt64 , VE::kUInt64); 2075 case UniOpVVI::kSrlU16 : return VecOpInfo::make(VE::kUInt16 , VE::kUInt16); 2076 case UniOpVVI::kSrlU32 : return VecOpInfo::make(VE::kUInt32 , VE::kUInt32); 2077 case UniOpVVI::kSrlU64 : return VecOpInfo::make(VE::kUInt64 , VE::kUInt64); 2078 case UniOpVVI::kSraI16 : return VecOpInfo::make(VE::kInt16 , VE::kInt16); 2079 case UniOpVVI::kSraI32 : return VecOpInfo::make(VE::kInt32 , VE::kInt32); 2080 case UniOpVVI::kSraI64 : return VecOpInfo::make(VE::kInt64 , VE::kInt64); 2081 case UniOpVVI::kSllbU128 : return VecOpInfo::make(VE::kUInt8 , VE::kUInt8); 2082 case UniOpVVI::kSrlbU128 : return VecOpInfo::make(VE::kUInt8 , VE::kUInt8); 2083 case UniOpVVI::kSwizzleU16x4 : return VecOpInfo::make(VE::kUInt16 , VE::kUInt16); 2084 case UniOpVVI::kSwizzleLoU16x4 : return VecOpInfo::make(VE::kUInt16 , VE::kUInt16); 2085 case UniOpVVI::kSwizzleHiU16x4 : return VecOpInfo::make(VE::kUInt16 , VE::kUInt16); 2086 case UniOpVVI::kSwizzleU32x4 : return VecOpInfo::make(VE::kUInt32 , VE::kUInt32); 2087 case UniOpVVI::kSwizzleU64x2 : return VecOpInfo::make(VE::kUInt64 , VE::kUInt64); 2088 case UniOpVVI::kSwizzleF32x4 : return VecOpInfo::make(VE::kFloat32, VE::kFloat32); 2089 case UniOpVVI::kSwizzleF64x2 : return VecOpInfo::make(VE::kFloat64, VE::kFloat64); 2090 case UniOpVVI::kSwizzleU64x4 : return VecOpInfo::make(VE::kUInt64 , VE::kUInt64); 2091 case UniOpVVI::kSwizzleF64x4 : return VecOpInfo::make(VE::kFloat64, VE::kFloat64); 2092 case UniOpVVI::kExtractV128_I32: return VecOpInfo::make(VE::kInt32 , VE::kInt32); 2093 case UniOpVVI::kExtractV128_I64: return VecOpInfo::make(VE::kInt64 , VE::kInt64); 2094 case UniOpVVI::kExtractV128_F32: return VecOpInfo::make(VE::kFloat32, VE::kFloat32); 2095 case UniOpVVI::kExtractV128_F64: return VecOpInfo::make(VE::kFloat64, VE::kFloat64); 2096 case UniOpVVI::kExtractV256_I32: return VecOpInfo::make(VE::kUInt32 , VE::kUInt32); 2097 case UniOpVVI::kExtractV256_I64: return VecOpInfo::make(VE::kUInt64 , VE::kUInt64); 2098 case UniOpVVI::kExtractV256_F32: return VecOpInfo::make(VE::kFloat32, VE::kFloat32); 2099 case UniOpVVI::kExtractV256_F64: return VecOpInfo::make(VE::kFloat64, VE::kFloat64); 2100 2101 #if defined(ASMJIT_UJIT_AARCH64) 2102 case UniOpVVI::kSrlRndU16 : return VecOpInfo::make(VE::kUInt16, VE::kUInt16); 2103 case UniOpVVI::kSrlRndU32 : return VecOpInfo::make(VE::kUInt32, VE::kUInt32); 2104 case UniOpVVI::kSrlRndU64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64); 2105 case UniOpVVI::kSrlAccU16 : return VecOpInfo::make(VE::kUInt16, VE::kUInt16); 2106 case UniOpVVI::kSrlAccU32 : return VecOpInfo::make(VE::kUInt32, VE::kUInt32); 2107 case UniOpVVI::kSrlAccU64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64); 2108 case UniOpVVI::kSrlRndAccU16 : return VecOpInfo::make(VE::kUInt16, VE::kUInt16); 2109 case UniOpVVI::kSrlRndAccU32 : return VecOpInfo::make(VE::kUInt32, VE::kUInt32); 2110 case UniOpVVI::kSrlRndAccU64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64); 2111 case UniOpVVI::kSrlnLoU16 : return VecOpInfo::make(VE::kUInt16, VE::kUInt16); 2112 case UniOpVVI::kSrlnHiU16 : return VecOpInfo::make(VE::kUInt32, VE::kUInt32); 2113 case UniOpVVI::kSrlnLoU32 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64); 2114 case UniOpVVI::kSrlnHiU32 : return VecOpInfo::make(VE::kUInt16, VE::kUInt16); 2115 case UniOpVVI::kSrlnLoU64 : return VecOpInfo::make(VE::kUInt32, VE::kUInt32); 2116 case UniOpVVI::kSrlnHiU64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64); 2117 case UniOpVVI::kSrlnRndLoU16 : return VecOpInfo::make(VE::kUInt8 , VE::kUInt16); 2118 case UniOpVVI::kSrlnRndHiU16 : return VecOpInfo::make(VE::kUInt8 , VE::kUInt16); 2119 case UniOpVVI::kSrlnRndLoU32 : return VecOpInfo::make(VE::kUInt16, VE::kUInt32); 2120 case UniOpVVI::kSrlnRndHiU32 : return VecOpInfo::make(VE::kUInt16, VE::kUInt32); 2121 case UniOpVVI::kSrlnRndLoU64 : return VecOpInfo::make(VE::kUInt32, VE::kUInt64); 2122 case UniOpVVI::kSrlnRndHiU64 : return VecOpInfo::make(VE::kUInt32, VE::kUInt64); 2123 #endif // ASMJIT_UJIT_AARCH64 2124 } 2125 2126 ASMJIT_NOT_REACHED(); 2127 } 2128 2129 static const char* vec_op_name_vvv(UniOpVVV op) noexcept { 2130 switch (op) { 2131 case UniOpVVV::kAndU32 : return "v_and_u32"; 2132 case UniOpVVV::kAndU64 : return "v_and_u64"; 2133 case UniOpVVV::kOrU32 : return "v_or_u32"; 2134 case UniOpVVV::kOrU64 : return "v_or_u64"; 2135 case UniOpVVV::kXorU32 : return "v_xor_u32"; 2136 case UniOpVVV::kXorU64 : return "v_xor_u64"; 2137 case UniOpVVV::kAndnU32 : return "v_andn_u32"; 2138 case UniOpVVV::kAndnU64 : return "v_andn_u64"; 2139 case UniOpVVV::kBicU32 : return "v_bic_u32"; 2140 case UniOpVVV::kBicU64 : return "v_bic_u64"; 2141 case UniOpVVV::kAvgrU8 : return "v_avgr_u8"; 2142 case UniOpVVV::kAvgrU16 : return "v_avgr_u16"; 2143 case UniOpVVV::kAddU8 : return "v_add_u8"; 2144 case UniOpVVV::kAddU16 : return "v_add_u16"; 2145 case UniOpVVV::kAddU32 : return "v_add_u32"; 2146 case UniOpVVV::kAddU64 : return "v_add_u64"; 2147 case UniOpVVV::kSubU8 : return "v_sub_u8"; 2148 case UniOpVVV::kSubU16 : return "v_sub_u16"; 2149 case UniOpVVV::kSubU32 : return "v_sub_u32"; 2150 case UniOpVVV::kSubU64 : return "v_sub_u64"; 2151 case UniOpVVV::kAddsI8 : return "v_adds_i8"; 2152 case UniOpVVV::kAddsU8 : return "v_adds_u8"; 2153 case UniOpVVV::kAddsI16 : return "v_adds_i16"; 2154 case UniOpVVV::kAddsU16 : return "v_adds_u16"; 2155 case UniOpVVV::kSubsI8 : return "v_subs_i8"; 2156 case UniOpVVV::kSubsU8 : return "v_subs_u8"; 2157 case UniOpVVV::kSubsI16 : return "v_subs_i16"; 2158 case UniOpVVV::kSubsU16 : return "v_subs_u16"; 2159 case UniOpVVV::kMulU16 : return "v_mul_u16"; 2160 case UniOpVVV::kMulU32 : return "v_mul_u32"; 2161 case UniOpVVV::kMulU64 : return "v_mul_u64"; 2162 case UniOpVVV::kMulhI16 : return "v_mulh_i16"; 2163 case UniOpVVV::kMulhU16 : return "v_mulh_u16"; 2164 case UniOpVVV::kMulU64_LoU32 : return "v_mul_u64_lo_u32"; 2165 case UniOpVVV::kMHAddI16_I32 : return "v_mhadd_i16_i32"; 2166 case UniOpVVV::kMinI8 : return "v_min_i8"; 2167 case UniOpVVV::kMinU8 : return "v_min_u8"; 2168 case UniOpVVV::kMinI16 : return "v_min_i16"; 2169 case UniOpVVV::kMinU16 : return "v_min_u16"; 2170 case UniOpVVV::kMinI32 : return "v_min_i32"; 2171 case UniOpVVV::kMinU32 : return "v_min_u32"; 2172 case UniOpVVV::kMinI64 : return "v_min_i64"; 2173 case UniOpVVV::kMinU64 : return "v_min_u64"; 2174 case UniOpVVV::kMaxI8 : return "v_max_i8"; 2175 case UniOpVVV::kMaxU8 : return "v_max_u8"; 2176 case UniOpVVV::kMaxI16 : return "v_max_i16"; 2177 case UniOpVVV::kMaxU16 : return "v_max_u16"; 2178 case UniOpVVV::kMaxI32 : return "v_max_i32"; 2179 case UniOpVVV::kMaxU32 : return "v_max_u32"; 2180 case UniOpVVV::kMaxI64 : return "v_max_i64"; 2181 case UniOpVVV::kMaxU64 : return "v_max_u64"; 2182 case UniOpVVV::kCmpEqU8 : return "v_cmp_eq_u8"; 2183 case UniOpVVV::kCmpEqU16 : return "v_cmp_eq_u16"; 2184 case UniOpVVV::kCmpEqU32 : return "v_cmp_eq_u32"; 2185 case UniOpVVV::kCmpEqU64 : return "v_cmp_eq_u64"; 2186 case UniOpVVV::kCmpGtI8 : return "v_cmp_gt_i8"; 2187 case UniOpVVV::kCmpGtU8 : return "v_cmp_gt_u8"; 2188 case UniOpVVV::kCmpGtI16 : return "v_cmp_gt_i16"; 2189 case UniOpVVV::kCmpGtU16 : return "v_cmp_gt_u16"; 2190 case UniOpVVV::kCmpGtI32 : return "v_cmp_gt_i32"; 2191 case UniOpVVV::kCmpGtU32 : return "v_cmp_gt_u32"; 2192 case UniOpVVV::kCmpGtI64 : return "v_cmp_gt_i64"; 2193 case UniOpVVV::kCmpGtU64 : return "v_cmp_gt_u64"; 2194 case UniOpVVV::kCmpGeI8 : return "v_cmp_ge_i8"; 2195 case UniOpVVV::kCmpGeU8 : return "v_cmp_ge_u8"; 2196 case UniOpVVV::kCmpGeI16 : return "v_cmp_ge_i16"; 2197 case UniOpVVV::kCmpGeU16 : return "v_cmp_ge_u16"; 2198 case UniOpVVV::kCmpGeI32 : return "v_cmp_ge_i32"; 2199 case UniOpVVV::kCmpGeU32 : return "v_cmp_ge_u32"; 2200 case UniOpVVV::kCmpGeI64 : return "v_cmp_ge_i64"; 2201 case UniOpVVV::kCmpGeU64 : return "v_cmp_ge_u64"; 2202 case UniOpVVV::kCmpLtI8 : return "v_cmp_lt_i8"; 2203 case UniOpVVV::kCmpLtU8 : return "v_cmp_lt_u8"; 2204 case UniOpVVV::kCmpLtI16 : return "v_cmp_lt_i16"; 2205 case UniOpVVV::kCmpLtU16 : return "v_cmp_lt_u16"; 2206 case UniOpVVV::kCmpLtI32 : return "v_cmp_lt_i32"; 2207 case UniOpVVV::kCmpLtU32 : return "v_cmp_lt_u32"; 2208 case UniOpVVV::kCmpLtI64 : return "v_cmp_lt_i64"; 2209 case UniOpVVV::kCmpLtU64 : return "v_cmp_lt_u64"; 2210 case UniOpVVV::kCmpLeI8 : return "v_cmp_le_i8"; 2211 case UniOpVVV::kCmpLeU8 : return "v_cmp_le_u8"; 2212 case UniOpVVV::kCmpLeI16 : return "v_cmp_le_i16"; 2213 case UniOpVVV::kCmpLeU16 : return "v_cmp_le_u16"; 2214 case UniOpVVV::kCmpLeI32 : return "v_cmp_le_i32"; 2215 case UniOpVVV::kCmpLeU32 : return "v_cmp_le_u32"; 2216 case UniOpVVV::kCmpLeI64 : return "v_cmp_le_i64"; 2217 case UniOpVVV::kCmpLeU64 : return "v_cmp_le_u64"; 2218 case UniOpVVV::kAndF32 : return "v_and_f32"; 2219 case UniOpVVV::kAndF64 : return "v_and_f64"; 2220 case UniOpVVV::kOrF32 : return "v_or_f32"; 2221 case UniOpVVV::kOrF64 : return "v_or_f64"; 2222 case UniOpVVV::kXorF32 : return "v_xor_f32"; 2223 case UniOpVVV::kXorF64 : return "v_xor_f64"; 2224 case UniOpVVV::kAndnF32 : return "v_andn_f32"; 2225 case UniOpVVV::kAndnF64 : return "v_andn_f64"; 2226 case UniOpVVV::kBicF32 : return "v_bic_f32"; 2227 case UniOpVVV::kBicF64 : return "v_bic_f64"; 2228 case UniOpVVV::kAddF32S : return "v_add_f32s"; 2229 case UniOpVVV::kAddF64S : return "v_add_f64s"; 2230 case UniOpVVV::kAddF32 : return "v_add_f32"; 2231 case UniOpVVV::kAddF64 : return "v_add_f64"; 2232 case UniOpVVV::kSubF32S : return "v_sub_f32s"; 2233 case UniOpVVV::kSubF64S : return "v_sub_f64s"; 2234 case UniOpVVV::kSubF32 : return "v_sub_f32"; 2235 case UniOpVVV::kSubF64 : return "v_sub_f64"; 2236 case UniOpVVV::kMulF32S : return "v_mul_f32s"; 2237 case UniOpVVV::kMulF64S : return "v_mul_f64s"; 2238 case UniOpVVV::kMulF32 : return "v_mul_f32"; 2239 case UniOpVVV::kMulF64 : return "v_mul_f64"; 2240 case UniOpVVV::kDivF32S : return "v_div_f32s"; 2241 case UniOpVVV::kDivF64S : return "v_div_f64s"; 2242 case UniOpVVV::kDivF32 : return "v_div_f32"; 2243 case UniOpVVV::kDivF64 : return "v_div_f64"; 2244 case UniOpVVV::kModF32S : return "v_mod_f32s"; 2245 case UniOpVVV::kModF64S : return "v_mod_f64s"; 2246 case UniOpVVV::kModF32 : return "v_mod_f32"; 2247 case UniOpVVV::kModF64 : return "v_mod_f64"; 2248 case UniOpVVV::kMinF32S : return "v_min_f32s"; 2249 case UniOpVVV::kMinF64S : return "v_min_f64s"; 2250 case UniOpVVV::kMinF32 : return "v_min_f32"; 2251 case UniOpVVV::kMinF64 : return "v_min_f64"; 2252 case UniOpVVV::kMaxF32S : return "v_max_f32s"; 2253 case UniOpVVV::kMaxF64S : return "v_max_f64s"; 2254 case UniOpVVV::kMaxF32 : return "v_max_f32"; 2255 case UniOpVVV::kMaxF64 : return "v_max_f64"; 2256 case UniOpVVV::kCmpEqF32S : return "v_cmp_eq_f32s"; 2257 case UniOpVVV::kCmpEqF64S : return "v_cmp_eq_f64s"; 2258 case UniOpVVV::kCmpEqF32 : return "v_cmp_eq_f32"; 2259 case UniOpVVV::kCmpEqF64 : return "v_cmp_eq_f64"; 2260 case UniOpVVV::kCmpNeF32S : return "v_cmp_ne_f32s"; 2261 case UniOpVVV::kCmpNeF64S : return "v_cmp_ne_f64s"; 2262 case UniOpVVV::kCmpNeF32 : return "v_cmp_ne_f32"; 2263 case UniOpVVV::kCmpNeF64 : return "v_cmp_ne_f64"; 2264 case UniOpVVV::kCmpGtF32S : return "v_cmp_gt_f32s"; 2265 case UniOpVVV::kCmpGtF64S : return "v_cmp_gt_f64s"; 2266 case UniOpVVV::kCmpGtF32 : return "v_cmp_gt_f32"; 2267 case UniOpVVV::kCmpGtF64 : return "v_cmp_gt_f64"; 2268 case UniOpVVV::kCmpGeF32S : return "v_cmp_ge_f32s"; 2269 case UniOpVVV::kCmpGeF64S : return "v_cmp_ge_f64s"; 2270 case UniOpVVV::kCmpGeF32 : return "v_cmp_ge_f32"; 2271 case UniOpVVV::kCmpGeF64 : return "v_cmp_ge_f64"; 2272 case UniOpVVV::kCmpLtF32S : return "v_cmp_lt_f32s"; 2273 case UniOpVVV::kCmpLtF64S : return "v_cmp_lt_f64s"; 2274 case UniOpVVV::kCmpLtF32 : return "v_cmp_lt_f32"; 2275 case UniOpVVV::kCmpLtF64 : return "v_cmp_lt_f64"; 2276 case UniOpVVV::kCmpLeF32S : return "v_cmp_le_f32s"; 2277 case UniOpVVV::kCmpLeF64S : return "v_cmp_le_f64s"; 2278 case UniOpVVV::kCmpLeF32 : return "v_cmp_le_f32"; 2279 case UniOpVVV::kCmpLeF64 : return "v_cmp_le_f64"; 2280 case UniOpVVV::kCmpOrdF32S : return "v_cmp_ord_f32s"; 2281 case UniOpVVV::kCmpOrdF64S : return "v_cmp_ord_f64s"; 2282 case UniOpVVV::kCmpOrdF32 : return "v_cmp_ord_f32"; 2283 case UniOpVVV::kCmpOrdF64 : return "v_cmp_ord_f64"; 2284 case UniOpVVV::kCmpUnordF32S : return "v_cmp_unord_f32s"; 2285 case UniOpVVV::kCmpUnordF64S : return "v_cmp_unord_f64s"; 2286 case UniOpVVV::kCmpUnordF32 : return "v_cmp_unord_f32"; 2287 case UniOpVVV::kCmpUnordF64 : return "v_cmp_unord_f64"; 2288 case UniOpVVV::kHAddF64 : return "v_hadd_f64"; 2289 case UniOpVVV::kCombineLoHiU64 : return "v_combine_lo_hi_u64"; 2290 case UniOpVVV::kCombineLoHiF64 : return "v_combine_lo_hi_f64"; 2291 case UniOpVVV::kCombineHiLoU64 : return "v_combine_hi_lo_u64"; 2292 case UniOpVVV::kCombineHiLoF64 : return "v_combine_hi_lo_f64"; 2293 case UniOpVVV::kInterleaveLoU8 : return "v_interleave_lo_u8"; 2294 case UniOpVVV::kInterleaveHiU8 : return "v_interleave_hi_u8"; 2295 case UniOpVVV::kInterleaveLoU16: return "v_interleave_lo_u16"; 2296 case UniOpVVV::kInterleaveHiU16: return "v_interleave_hi_u16"; 2297 case UniOpVVV::kInterleaveLoU32: return "v_interleave_lo_u32"; 2298 case UniOpVVV::kInterleaveHiU32: return "v_interleave_hi_u32"; 2299 case UniOpVVV::kInterleaveLoU64: return "v_interleave_lo_u64"; 2300 case UniOpVVV::kInterleaveHiU64: return "v_interleave_hi_u64"; 2301 case UniOpVVV::kInterleaveLoF32: return "v_interleave_lo_f32"; 2302 case UniOpVVV::kInterleaveHiF32: return "v_interleave_hi_f32"; 2303 case UniOpVVV::kInterleaveLoF64: return "v_interleave_lo_f64"; 2304 case UniOpVVV::kInterleaveHiF64: return "v_interleave_hi_f64"; 2305 case UniOpVVV::kPacksI16_I8 : return "v_packs_i16_i8"; 2306 case UniOpVVV::kPacksI16_U8 : return "v_packs_i16_u8"; 2307 case UniOpVVV::kPacksI32_I16 : return "v_packs_i32_i16"; 2308 case UniOpVVV::kPacksI32_U16 : return "v_packs_i32_u16"; 2309 case UniOpVVV::kSwizzlev_U8 : return "v_swizzlev_u8"; 2310 2311 #if defined(ASMJIT_UJIT_AARCH64) 2312 case UniOpVVV::kMulwLoI8 : return "v_mulw_lo_i8"; 2313 case UniOpVVV::kMulwLoU8 : return "v_mulw_lo_u8"; 2314 case UniOpVVV::kMulwHiI8 : return "v_mulw_hi_i8"; 2315 case UniOpVVV::kMulwHiU8 : return "v_mulw_hi_u8"; 2316 case UniOpVVV::kMulwLoI16 : return "v_mulw_lo_i16"; 2317 case UniOpVVV::kMulwLoU16 : return "v_mulw_lo_u16"; 2318 case UniOpVVV::kMulwHiI16 : return "v_mulw_hi_i16"; 2319 case UniOpVVV::kMulwHiU16 : return "v_mulw_hi_u16"; 2320 case UniOpVVV::kMulwLoI32 : return "v_mulw_lo_i32"; 2321 case UniOpVVV::kMulwLoU32 : return "v_mulw_lo_u32"; 2322 case UniOpVVV::kMulwHiI32 : return "v_mulw_hi_i32"; 2323 case UniOpVVV::kMulwHiU32 : return "v_mulw_hi_u32"; 2324 case UniOpVVV::kMAddwLoI8 : return "v_maddw_lo_i8"; 2325 case UniOpVVV::kMAddwLoU8 : return "v_maddw_lo_u8"; 2326 case UniOpVVV::kMAddwHiI8 : return "v_maddw_hi_i8"; 2327 case UniOpVVV::kMAddwHiU8 : return "v_maddw_hi_u8"; 2328 case UniOpVVV::kMAddwLoI16 : return "v_maddw_lo_i16"; 2329 case UniOpVVV::kMAddwLoU16 : return "v_maddw_lo_u16"; 2330 case UniOpVVV::kMAddwHiI16 : return "v_maddw_hi_i16"; 2331 case UniOpVVV::kMAddwHiU16 : return "v_maddw_hi_u16"; 2332 case UniOpVVV::kMAddwLoI32 : return "v_maddw_lo_i32"; 2333 case UniOpVVV::kMAddwLoU32 : return "v_maddw_lo_u32"; 2334 case UniOpVVV::kMAddwHiI32 : return "v_maddw_hi_i32"; 2335 case UniOpVVV::kMAddwHiU32 : return "v_maddw_hi_u32"; 2336 #endif // ASMJIT_UJIT_AARCH64 2337 2338 #if defined(ASMJIT_UJIT_X86) 2339 case UniOpVVV::kPermuteU8 : return "v_permute_u8"; 2340 case UniOpVVV::kPermuteU16 : return "v_permute_u16"; 2341 case UniOpVVV::kPermuteU32 : return "v_permute_u32"; 2342 case UniOpVVV::kPermuteU64 : return "v_permute_u64"; 2343 #endif // ASMJIT_UJIT_X86 2344 } 2345 2346 ASMJIT_NOT_REACHED(); 2347 } 2348 2349 static VecOpInfo vec_op_info_vvv(UniOpVVV op) noexcept { 2350 using VE = VecElementType; 2351 2352 switch (op) { 2353 case UniOpVVV::kAndU32 : return VecOpInfo::make(VE::kUInt32, VE::kUInt32, VE::kUInt32); 2354 case UniOpVVV::kAndU64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64, VE::kUInt64); 2355 case UniOpVVV::kOrU32 : return VecOpInfo::make(VE::kUInt32, VE::kUInt32, VE::kUInt32); 2356 case UniOpVVV::kOrU64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64, VE::kUInt64); 2357 case UniOpVVV::kXorU32 : return VecOpInfo::make(VE::kUInt32, VE::kUInt32, VE::kUInt32); 2358 case UniOpVVV::kXorU64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64, VE::kUInt64); 2359 case UniOpVVV::kAndnU32 : return VecOpInfo::make(VE::kUInt32, VE::kUInt32, VE::kUInt32); 2360 case UniOpVVV::kAndnU64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64, VE::kUInt64); 2361 case UniOpVVV::kBicU32 : return VecOpInfo::make(VE::kUInt32, VE::kUInt32, VE::kUInt32); 2362 case UniOpVVV::kBicU64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64, VE::kUInt64); 2363 case UniOpVVV::kAvgrU8 : return VecOpInfo::make(VE::kUInt8, VE::kUInt8, VE::kUInt8); 2364 case UniOpVVV::kAvgrU16 : return VecOpInfo::make(VE::kUInt16, VE::kUInt16, VE::kUInt16); 2365 case UniOpVVV::kAddU8 : return VecOpInfo::make(VE::kUInt8, VE::kUInt8, VE::kUInt8); 2366 case UniOpVVV::kAddU16 : return VecOpInfo::make(VE::kUInt16, VE::kUInt16, VE::kUInt16); 2367 case UniOpVVV::kAddU32 : return VecOpInfo::make(VE::kUInt32, VE::kUInt32, VE::kUInt32); 2368 case UniOpVVV::kAddU64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64, VE::kUInt64); 2369 case UniOpVVV::kSubU8 : return VecOpInfo::make(VE::kUInt8, VE::kUInt8, VE::kUInt8); 2370 case UniOpVVV::kSubU16 : return VecOpInfo::make(VE::kUInt16, VE::kUInt16, VE::kUInt16); 2371 case UniOpVVV::kSubU32 : return VecOpInfo::make(VE::kUInt32, VE::kUInt32, VE::kUInt32); 2372 case UniOpVVV::kSubU64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64, VE::kUInt64); 2373 case UniOpVVV::kAddsI8 : return VecOpInfo::make(VE::kInt8, VE::kInt8, VE::kInt8); 2374 case UniOpVVV::kAddsU8 : return VecOpInfo::make(VE::kUInt8, VE::kUInt8, VE::kUInt8); 2375 case UniOpVVV::kAddsI16 : return VecOpInfo::make(VE::kInt16, VE::kInt16, VE::kInt16); 2376 case UniOpVVV::kAddsU16 : return VecOpInfo::make(VE::kUInt16, VE::kUInt16, VE::kUInt16); 2377 case UniOpVVV::kSubsI8 : return VecOpInfo::make(VE::kInt8, VE::kInt8, VE::kInt8); 2378 case UniOpVVV::kSubsU8 : return VecOpInfo::make(VE::kUInt8, VE::kUInt8, VE::kUInt8); 2379 case UniOpVVV::kSubsI16 : return VecOpInfo::make(VE::kInt16, VE::kInt16, VE::kInt16); 2380 case UniOpVVV::kSubsU16 : return VecOpInfo::make(VE::kUInt16, VE::kUInt16, VE::kUInt16); 2381 case UniOpVVV::kMulU16 : return VecOpInfo::make(VE::kUInt16, VE::kUInt16, VE::kUInt16); 2382 case UniOpVVV::kMulU32 : return VecOpInfo::make(VE::kUInt32, VE::kUInt32, VE::kUInt32); 2383 case UniOpVVV::kMulU64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64, VE::kUInt64); 2384 case UniOpVVV::kMulhI16 : return VecOpInfo::make(VE::kInt16, VE::kInt16, VE::kInt16); 2385 case UniOpVVV::kMulhU16 : return VecOpInfo::make(VE::kUInt16, VE::kUInt16, VE::kUInt16); 2386 case UniOpVVV::kMulU64_LoU32 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64, VE::kUInt32); 2387 case UniOpVVV::kMHAddI16_I32 : return VecOpInfo::make(VE::kInt32, VE::kInt16, VE::kInt16); 2388 case UniOpVVV::kMinI8 : return VecOpInfo::make(VE::kInt8, VE::kInt8, VE::kInt8); 2389 case UniOpVVV::kMinU8 : return VecOpInfo::make(VE::kUInt8, VE::kUInt8, VE::kUInt8); 2390 case UniOpVVV::kMinI16 : return VecOpInfo::make(VE::kInt16, VE::kInt16, VE::kInt16); 2391 case UniOpVVV::kMinU16 : return VecOpInfo::make(VE::kUInt16, VE::kUInt16, VE::kUInt16); 2392 case UniOpVVV::kMinI32 : return VecOpInfo::make(VE::kInt32, VE::kInt32, VE::kInt32); 2393 case UniOpVVV::kMinU32 : return VecOpInfo::make(VE::kUInt32, VE::kUInt32, VE::kUInt32); 2394 case UniOpVVV::kMinI64 : return VecOpInfo::make(VE::kInt64, VE::kInt64, VE::kInt64); 2395 case UniOpVVV::kMinU64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64, VE::kUInt64); 2396 case UniOpVVV::kMaxI8 : return VecOpInfo::make(VE::kInt8, VE::kInt8, VE::kInt8); 2397 case UniOpVVV::kMaxU8 : return VecOpInfo::make(VE::kUInt8, VE::kUInt8, VE::kUInt8); 2398 case UniOpVVV::kMaxI16 : return VecOpInfo::make(VE::kInt16, VE::kInt16, VE::kInt16); 2399 case UniOpVVV::kMaxU16 : return VecOpInfo::make(VE::kUInt16, VE::kUInt16, VE::kUInt16); 2400 case UniOpVVV::kMaxI32 : return VecOpInfo::make(VE::kInt32, VE::kInt32, VE::kInt32); 2401 case UniOpVVV::kMaxU32 : return VecOpInfo::make(VE::kUInt32, VE::kUInt32, VE::kUInt32); 2402 case UniOpVVV::kMaxI64 : return VecOpInfo::make(VE::kInt64, VE::kInt64, VE::kInt64); 2403 case UniOpVVV::kMaxU64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64, VE::kUInt64); 2404 case UniOpVVV::kCmpEqU8 : return VecOpInfo::make(VE::kUInt8, VE::kUInt8, VE::kUInt8); 2405 case UniOpVVV::kCmpEqU16 : return VecOpInfo::make(VE::kUInt16, VE::kUInt16, VE::kUInt16); 2406 case UniOpVVV::kCmpEqU32 : return VecOpInfo::make(VE::kUInt32, VE::kUInt32, VE::kUInt32); 2407 case UniOpVVV::kCmpEqU64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64, VE::kUInt64); 2408 case UniOpVVV::kCmpGtI8 : return VecOpInfo::make(VE::kInt8, VE::kInt8, VE::kInt8); 2409 case UniOpVVV::kCmpGtU8 : return VecOpInfo::make(VE::kUInt8, VE::kUInt8, VE::kUInt8); 2410 case UniOpVVV::kCmpGtI16 : return VecOpInfo::make(VE::kInt16, VE::kInt16, VE::kInt16); 2411 case UniOpVVV::kCmpGtU16 : return VecOpInfo::make(VE::kUInt16, VE::kUInt16, VE::kUInt16); 2412 case UniOpVVV::kCmpGtI32 : return VecOpInfo::make(VE::kInt32, VE::kInt32, VE::kInt32); 2413 case UniOpVVV::kCmpGtU32 : return VecOpInfo::make(VE::kUInt32, VE::kUInt32, VE::kUInt32); 2414 case UniOpVVV::kCmpGtI64 : return VecOpInfo::make(VE::kInt64, VE::kInt64, VE::kInt64); 2415 case UniOpVVV::kCmpGtU64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64, VE::kUInt64); 2416 case UniOpVVV::kCmpGeI8 : return VecOpInfo::make(VE::kInt8, VE::kInt8, VE::kInt8); 2417 case UniOpVVV::kCmpGeU8 : return VecOpInfo::make(VE::kUInt8, VE::kUInt8, VE::kUInt8); 2418 case UniOpVVV::kCmpGeI16 : return VecOpInfo::make(VE::kInt16, VE::kInt16, VE::kInt16); 2419 case UniOpVVV::kCmpGeU16 : return VecOpInfo::make(VE::kUInt16, VE::kUInt16, VE::kUInt16); 2420 case UniOpVVV::kCmpGeI32 : return VecOpInfo::make(VE::kInt32, VE::kInt32, VE::kInt32); 2421 case UniOpVVV::kCmpGeU32 : return VecOpInfo::make(VE::kUInt32, VE::kUInt32, VE::kUInt32); 2422 case UniOpVVV::kCmpGeI64 : return VecOpInfo::make(VE::kInt64, VE::kInt64, VE::kInt64); 2423 case UniOpVVV::kCmpGeU64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64, VE::kUInt64); 2424 case UniOpVVV::kCmpLtI8 : return VecOpInfo::make(VE::kInt8, VE::kInt8, VE::kInt8); 2425 case UniOpVVV::kCmpLtU8 : return VecOpInfo::make(VE::kUInt8, VE::kUInt8, VE::kUInt8); 2426 case UniOpVVV::kCmpLtI16 : return VecOpInfo::make(VE::kInt16, VE::kInt16, VE::kInt16); 2427 case UniOpVVV::kCmpLtU16 : return VecOpInfo::make(VE::kUInt16, VE::kUInt16, VE::kUInt16); 2428 case UniOpVVV::kCmpLtI32 : return VecOpInfo::make(VE::kInt32, VE::kInt32, VE::kInt32); 2429 case UniOpVVV::kCmpLtU32 : return VecOpInfo::make(VE::kUInt32, VE::kUInt32, VE::kUInt32); 2430 case UniOpVVV::kCmpLtI64 : return VecOpInfo::make(VE::kInt64, VE::kInt64, VE::kInt64); 2431 case UniOpVVV::kCmpLtU64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64, VE::kUInt64); 2432 case UniOpVVV::kCmpLeI8 : return VecOpInfo::make(VE::kInt8, VE::kInt8, VE::kInt8); 2433 case UniOpVVV::kCmpLeU8 : return VecOpInfo::make(VE::kUInt8, VE::kUInt8, VE::kUInt8); 2434 case UniOpVVV::kCmpLeI16 : return VecOpInfo::make(VE::kInt16, VE::kInt16, VE::kInt16); 2435 case UniOpVVV::kCmpLeU16 : return VecOpInfo::make(VE::kUInt16, VE::kUInt16, VE::kUInt16); 2436 case UniOpVVV::kCmpLeI32 : return VecOpInfo::make(VE::kInt32, VE::kInt32, VE::kInt32); 2437 case UniOpVVV::kCmpLeU32 : return VecOpInfo::make(VE::kUInt32, VE::kUInt32, VE::kUInt32); 2438 case UniOpVVV::kCmpLeI64 : return VecOpInfo::make(VE::kInt64, VE::kInt64, VE::kInt64); 2439 case UniOpVVV::kCmpLeU64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64, VE::kUInt64); 2440 case UniOpVVV::kAndF32 : return VecOpInfo::make(VE::kUInt32, VE::kUInt32, VE::kUInt32); 2441 case UniOpVVV::kAndF64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64, VE::kUInt64); 2442 case UniOpVVV::kOrF32 : return VecOpInfo::make(VE::kUInt32, VE::kUInt32, VE::kUInt32); 2443 case UniOpVVV::kOrF64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64, VE::kUInt64); 2444 case UniOpVVV::kXorF32 : return VecOpInfo::make(VE::kUInt32, VE::kUInt32, VE::kUInt32); 2445 case UniOpVVV::kXorF64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64, VE::kUInt64); 2446 case UniOpVVV::kAndnF32 : return VecOpInfo::make(VE::kUInt32, VE::kUInt32, VE::kUInt32); 2447 case UniOpVVV::kAndnF64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64, VE::kUInt64); 2448 case UniOpVVV::kBicF32 : return VecOpInfo::make(VE::kUInt32, VE::kUInt32, VE::kUInt32); 2449 case UniOpVVV::kBicF64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64, VE::kUInt64); 2450 case UniOpVVV::kAddF32S : return VecOpInfo::make(VE::kFloat32, VE::kFloat32, VE::kFloat32); 2451 case UniOpVVV::kAddF64S : return VecOpInfo::make(VE::kFloat64, VE::kFloat64, VE::kFloat64); 2452 case UniOpVVV::kAddF32 : return VecOpInfo::make(VE::kFloat32, VE::kFloat32, VE::kFloat32); 2453 case UniOpVVV::kAddF64 : return VecOpInfo::make(VE::kFloat64, VE::kFloat64, VE::kFloat64); 2454 case UniOpVVV::kSubF32S : return VecOpInfo::make(VE::kFloat32, VE::kFloat32, VE::kFloat32); 2455 case UniOpVVV::kSubF64S : return VecOpInfo::make(VE::kFloat64, VE::kFloat64, VE::kFloat64); 2456 case UniOpVVV::kSubF32 : return VecOpInfo::make(VE::kFloat32, VE::kFloat32, VE::kFloat32); 2457 case UniOpVVV::kSubF64 : return VecOpInfo::make(VE::kFloat64, VE::kFloat64, VE::kFloat64); 2458 case UniOpVVV::kMulF32S : return VecOpInfo::make(VE::kFloat32, VE::kFloat32, VE::kFloat32); 2459 case UniOpVVV::kMulF64S : return VecOpInfo::make(VE::kFloat64, VE::kFloat64, VE::kFloat64); 2460 case UniOpVVV::kMulF32 : return VecOpInfo::make(VE::kFloat32, VE::kFloat32, VE::kFloat32); 2461 case UniOpVVV::kMulF64 : return VecOpInfo::make(VE::kFloat64, VE::kFloat64, VE::kFloat64); 2462 case UniOpVVV::kDivF32S : return VecOpInfo::make(VE::kFloat32, VE::kFloat32, VE::kFloat32); 2463 case UniOpVVV::kDivF64S : return VecOpInfo::make(VE::kFloat64, VE::kFloat64, VE::kFloat64); 2464 case UniOpVVV::kDivF32 : return VecOpInfo::make(VE::kFloat32, VE::kFloat32, VE::kFloat32); 2465 case UniOpVVV::kDivF64 : return VecOpInfo::make(VE::kFloat64, VE::kFloat64, VE::kFloat64); 2466 case UniOpVVV::kModF32S : return VecOpInfo::make(VE::kFloat32, VE::kFloat32, VE::kFloat32); 2467 case UniOpVVV::kModF64S : return VecOpInfo::make(VE::kFloat64, VE::kFloat64, VE::kFloat64); 2468 case UniOpVVV::kModF32 : return VecOpInfo::make(VE::kFloat32, VE::kFloat32, VE::kFloat32); 2469 case UniOpVVV::kModF64 : return VecOpInfo::make(VE::kFloat64, VE::kFloat64, VE::kFloat64); 2470 case UniOpVVV::kMinF32S : return VecOpInfo::make(VE::kFloat32, VE::kFloat32, VE::kFloat32); 2471 case UniOpVVV::kMinF64S : return VecOpInfo::make(VE::kFloat64, VE::kFloat64, VE::kFloat64); 2472 case UniOpVVV::kMinF32 : return VecOpInfo::make(VE::kFloat32, VE::kFloat32, VE::kFloat32); 2473 case UniOpVVV::kMinF64 : return VecOpInfo::make(VE::kFloat64, VE::kFloat64, VE::kFloat64); 2474 case UniOpVVV::kMaxF32S : return VecOpInfo::make(VE::kFloat32, VE::kFloat32, VE::kFloat32); 2475 case UniOpVVV::kMaxF64S : return VecOpInfo::make(VE::kFloat64, VE::kFloat64, VE::kFloat64); 2476 case UniOpVVV::kMaxF32 : return VecOpInfo::make(VE::kFloat32, VE::kFloat32, VE::kFloat32); 2477 case UniOpVVV::kMaxF64 : return VecOpInfo::make(VE::kFloat64, VE::kFloat64, VE::kFloat64); 2478 case UniOpVVV::kCmpEqF32S : return VecOpInfo::make(VE::kUInt32, VE::kFloat32, VE::kFloat32); 2479 case UniOpVVV::kCmpEqF64S : return VecOpInfo::make(VE::kUInt64, VE::kFloat64, VE::kFloat64); 2480 case UniOpVVV::kCmpEqF32 : return VecOpInfo::make(VE::kUInt32, VE::kFloat32, VE::kFloat32); 2481 case UniOpVVV::kCmpEqF64 : return VecOpInfo::make(VE::kUInt64, VE::kFloat64, VE::kFloat64); 2482 case UniOpVVV::kCmpNeF32S : return VecOpInfo::make(VE::kUInt32, VE::kFloat32, VE::kFloat32); 2483 case UniOpVVV::kCmpNeF64S : return VecOpInfo::make(VE::kUInt64, VE::kFloat64, VE::kFloat64); 2484 case UniOpVVV::kCmpNeF32 : return VecOpInfo::make(VE::kUInt32, VE::kFloat32, VE::kFloat32); 2485 case UniOpVVV::kCmpNeF64 : return VecOpInfo::make(VE::kUInt64, VE::kFloat64, VE::kFloat64); 2486 case UniOpVVV::kCmpGtF32S : return VecOpInfo::make(VE::kUInt32, VE::kFloat32, VE::kFloat32); 2487 case UniOpVVV::kCmpGtF64S : return VecOpInfo::make(VE::kUInt64, VE::kFloat64, VE::kFloat64); 2488 case UniOpVVV::kCmpGtF32 : return VecOpInfo::make(VE::kUInt32, VE::kFloat32, VE::kFloat32); 2489 case UniOpVVV::kCmpGtF64 : return VecOpInfo::make(VE::kUInt64, VE::kFloat64, VE::kFloat64); 2490 case UniOpVVV::kCmpGeF32S : return VecOpInfo::make(VE::kUInt32, VE::kFloat32, VE::kFloat32); 2491 case UniOpVVV::kCmpGeF64S : return VecOpInfo::make(VE::kUInt64, VE::kFloat64, VE::kFloat64); 2492 case UniOpVVV::kCmpGeF32 : return VecOpInfo::make(VE::kUInt32, VE::kFloat32, VE::kFloat32); 2493 case UniOpVVV::kCmpGeF64 : return VecOpInfo::make(VE::kUInt64, VE::kFloat64, VE::kFloat64); 2494 case UniOpVVV::kCmpLtF32S : return VecOpInfo::make(VE::kUInt32, VE::kFloat32, VE::kFloat32); 2495 case UniOpVVV::kCmpLtF64S : return VecOpInfo::make(VE::kUInt64, VE::kFloat64, VE::kFloat64); 2496 case UniOpVVV::kCmpLtF32 : return VecOpInfo::make(VE::kUInt32, VE::kFloat32, VE::kFloat32); 2497 case UniOpVVV::kCmpLtF64 : return VecOpInfo::make(VE::kUInt64, VE::kFloat64, VE::kFloat64); 2498 case UniOpVVV::kCmpLeF32S : return VecOpInfo::make(VE::kUInt32, VE::kFloat32, VE::kFloat32); 2499 case UniOpVVV::kCmpLeF64S : return VecOpInfo::make(VE::kUInt64, VE::kFloat64, VE::kFloat64); 2500 case UniOpVVV::kCmpLeF32 : return VecOpInfo::make(VE::kUInt32, VE::kFloat32, VE::kFloat32); 2501 case UniOpVVV::kCmpLeF64 : return VecOpInfo::make(VE::kUInt64, VE::kFloat64, VE::kFloat64); 2502 case UniOpVVV::kCmpOrdF32S : return VecOpInfo::make(VE::kUInt32, VE::kFloat32, VE::kFloat32); 2503 case UniOpVVV::kCmpOrdF64S : return VecOpInfo::make(VE::kUInt64, VE::kFloat64, VE::kFloat64); 2504 case UniOpVVV::kCmpOrdF32 : return VecOpInfo::make(VE::kUInt32, VE::kFloat32, VE::kFloat32); 2505 case UniOpVVV::kCmpOrdF64 : return VecOpInfo::make(VE::kUInt64, VE::kFloat64, VE::kFloat64); 2506 case UniOpVVV::kCmpUnordF32S : return VecOpInfo::make(VE::kUInt32, VE::kFloat32, VE::kFloat32); 2507 case UniOpVVV::kCmpUnordF64S : return VecOpInfo::make(VE::kUInt64, VE::kFloat64, VE::kFloat64); 2508 case UniOpVVV::kCmpUnordF32 : return VecOpInfo::make(VE::kUInt32, VE::kFloat32, VE::kFloat32); 2509 case UniOpVVV::kCmpUnordF64 : return VecOpInfo::make(VE::kUInt64, VE::kFloat64, VE::kFloat64); 2510 case UniOpVVV::kHAddF64 : return VecOpInfo::make(VE::kFloat64, VE::kFloat64, VE::kFloat64); 2511 case UniOpVVV::kCombineLoHiU64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64, VE::kUInt64); 2512 case UniOpVVV::kCombineLoHiF64 : return VecOpInfo::make(VE::kFloat64, VE::kFloat64, VE::kFloat64); 2513 case UniOpVVV::kCombineHiLoU64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64, VE::kUInt64); 2514 case UniOpVVV::kCombineHiLoF64 : return VecOpInfo::make(VE::kFloat64, VE::kFloat64, VE::kFloat64); 2515 case UniOpVVV::kInterleaveLoU8 : return VecOpInfo::make(VE::kUInt8, VE::kUInt8, VE::kUInt8); 2516 case UniOpVVV::kInterleaveHiU8 : return VecOpInfo::make(VE::kUInt8, VE::kUInt8, VE::kUInt8); 2517 case UniOpVVV::kInterleaveLoU16: return VecOpInfo::make(VE::kUInt16, VE::kUInt16, VE::kUInt16); 2518 case UniOpVVV::kInterleaveHiU16: return VecOpInfo::make(VE::kUInt16, VE::kUInt16, VE::kUInt16); 2519 case UniOpVVV::kInterleaveLoU32: return VecOpInfo::make(VE::kUInt32, VE::kUInt32, VE::kUInt32); 2520 case UniOpVVV::kInterleaveHiU32: return VecOpInfo::make(VE::kUInt32, VE::kUInt32, VE::kUInt32); 2521 case UniOpVVV::kInterleaveLoU64: return VecOpInfo::make(VE::kUInt64, VE::kUInt64, VE::kUInt64); 2522 case UniOpVVV::kInterleaveHiU64: return VecOpInfo::make(VE::kUInt64, VE::kUInt64, VE::kUInt64); 2523 case UniOpVVV::kInterleaveLoF32: return VecOpInfo::make(VE::kFloat32, VE::kFloat32, VE::kFloat32); 2524 case UniOpVVV::kInterleaveHiF32: return VecOpInfo::make(VE::kFloat32, VE::kFloat32, VE::kFloat32); 2525 case UniOpVVV::kInterleaveLoF64: return VecOpInfo::make(VE::kFloat64, VE::kFloat64, VE::kFloat64); 2526 case UniOpVVV::kInterleaveHiF64: return VecOpInfo::make(VE::kFloat64, VE::kFloat64, VE::kFloat64); 2527 case UniOpVVV::kPacksI16_I8 : return VecOpInfo::make(VE::kInt8, VE::kInt16, VE::kInt16); 2528 case UniOpVVV::kPacksI16_U8 : return VecOpInfo::make(VE::kUInt8, VE::kInt16, VE::kInt16); 2529 case UniOpVVV::kPacksI32_I16 : return VecOpInfo::make(VE::kInt16, VE::kInt32, VE::kInt32); 2530 case UniOpVVV::kPacksI32_U16 : return VecOpInfo::make(VE::kUInt16, VE::kInt32, VE::kInt32); 2531 case UniOpVVV::kSwizzlev_U8 : return VecOpInfo::make(VE::kUInt8, VE::kUInt8, VE::kUInt8); 2532 2533 #if defined(ASMJIT_UJIT_AARCH64) 2534 case UniOpVVV::kMulwLoI8 : return VecOpInfo::make(VE::kInt16, VE::kInt8, VE::kInt8); 2535 case UniOpVVV::kMulwLoU8 : return VecOpInfo::make(VE::kUInt16, VE::kUInt8, VE::kUInt8); 2536 case UniOpVVV::kMulwHiI8 : return VecOpInfo::make(VE::kInt16, VE::kInt8, VE::kInt8); 2537 case UniOpVVV::kMulwHiU8 : return VecOpInfo::make(VE::kUInt16, VE::kUInt8, VE::kUInt8); 2538 case UniOpVVV::kMulwLoI16 : return VecOpInfo::make(VE::kInt32, VE::kInt16, VE::kInt16); 2539 case UniOpVVV::kMulwLoU16 : return VecOpInfo::make(VE::kUInt32, VE::kUInt16, VE::kUInt16); 2540 case UniOpVVV::kMulwHiI16 : return VecOpInfo::make(VE::kInt32, VE::kInt16, VE::kInt16); 2541 case UniOpVVV::kMulwHiU16 : return VecOpInfo::make(VE::kUInt32, VE::kUInt16, VE::kUInt16); 2542 case UniOpVVV::kMulwLoI32 : return VecOpInfo::make(VE::kInt64, VE::kInt32, VE::kInt32); 2543 case UniOpVVV::kMulwLoU32 : return VecOpInfo::make(VE::kUInt64, VE::kUInt32, VE::kUInt32); 2544 case UniOpVVV::kMulwHiI32 : return VecOpInfo::make(VE::kInt64, VE::kInt32, VE::kInt32); 2545 case UniOpVVV::kMulwHiU32 : return VecOpInfo::make(VE::kUInt64, VE::kUInt32, VE::kUInt32); 2546 case UniOpVVV::kMAddwLoI8 : return VecOpInfo::make(VE::kInt16, VE::kInt8, VE::kInt8); 2547 case UniOpVVV::kMAddwLoU8 : return VecOpInfo::make(VE::kUInt16, VE::kUInt8, VE::kUInt8); 2548 case UniOpVVV::kMAddwHiI8 : return VecOpInfo::make(VE::kInt16, VE::kInt8, VE::kInt8); 2549 case UniOpVVV::kMAddwHiU8 : return VecOpInfo::make(VE::kUInt16, VE::kUInt8, VE::kUInt8); 2550 case UniOpVVV::kMAddwLoI16 : return VecOpInfo::make(VE::kInt32, VE::kInt16, VE::kInt16); 2551 case UniOpVVV::kMAddwLoU16 : return VecOpInfo::make(VE::kUInt32, VE::kUInt16, VE::kUInt16); 2552 case UniOpVVV::kMAddwHiI16 : return VecOpInfo::make(VE::kInt32, VE::kInt16, VE::kInt16); 2553 case UniOpVVV::kMAddwHiU16 : return VecOpInfo::make(VE::kUInt32, VE::kUInt16, VE::kUInt16); 2554 case UniOpVVV::kMAddwLoI32 : return VecOpInfo::make(VE::kInt64, VE::kInt32, VE::kInt32); 2555 case UniOpVVV::kMAddwLoU32 : return VecOpInfo::make(VE::kUInt64, VE::kUInt32, VE::kUInt32); 2556 case UniOpVVV::kMAddwHiI32 : return VecOpInfo::make(VE::kInt64, VE::kInt32, VE::kInt32); 2557 case UniOpVVV::kMAddwHiU32 : return VecOpInfo::make(VE::kUInt64, VE::kUInt32, VE::kUInt32); 2558 #endif // ASMJIT_UJIT_AARCH64 2559 2560 #if defined(ASMJIT_UJIT_X86) 2561 case UniOpVVV::kPermuteU8 : return VecOpInfo::make(VE::kUInt8, VE::kUInt8, VE::kUInt8); 2562 case UniOpVVV::kPermuteU16 : return VecOpInfo::make(VE::kUInt16, VE::kUInt16, VE::kUInt16); 2563 case UniOpVVV::kPermuteU32 : return VecOpInfo::make(VE::kUInt32, VE::kUInt32, VE::kUInt32); 2564 case UniOpVVV::kPermuteU64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64, VE::kUInt64); 2565 #endif // ASMJIT_UJIT_X86 2566 } 2567 2568 ASMJIT_NOT_REACHED(); 2569 } 2570 2571 static const char* vec_op_name_vvvi(UniOpVVVI op) noexcept { 2572 switch (op) { 2573 case UniOpVVVI::kAlignr_U128 : return "v_alignr_u128"; 2574 case UniOpVVVI::kInterleaveShuffleU32x4: return "v_interleave_shuffle_u32x4"; 2575 case UniOpVVVI::kInterleaveShuffleU64x2: return "v_interleave_shuffle_u64x2"; 2576 case UniOpVVVI::kInterleaveShuffleF32x4: return "v_interleave_shuffle_f32x4"; 2577 case UniOpVVVI::kInterleaveShuffleF64x2: return "v_interleave_shuffle_f64x2"; 2578 case UniOpVVVI::kInsertV128_U32 : return "v_insert_v128_u32"; 2579 case UniOpVVVI::kInsertV128_F32 : return "v_insert_v128_f32"; 2580 case UniOpVVVI::kInsertV128_U64 : return "v_insert_v128_u64"; 2581 case UniOpVVVI::kInsertV128_F64 : return "v_insert_v128_f64"; 2582 case UniOpVVVI::kInsertV256_U32 : return "v_insert_v256_u32"; 2583 case UniOpVVVI::kInsertV256_F32 : return "v_insert_v256_f32"; 2584 case UniOpVVVI::kInsertV256_U64 : return "v_insert_v256_u64"; 2585 case UniOpVVVI::kInsertV256_F64 : return "v_insert_v256_f64"; 2586 } 2587 2588 ASMJIT_NOT_REACHED(); 2589 } 2590 2591 static VecOpInfo vec_op_info_vvvi(UniOpVVVI op) noexcept { 2592 using VE = VecElementType; 2593 2594 switch (op) { 2595 case UniOpVVVI::kAlignr_U128 : return VecOpInfo::make(VE::kUInt8, VE::kUInt8, VE::kUInt8); 2596 case UniOpVVVI::kInterleaveShuffleU32x4: return VecOpInfo::make(VE::kUInt32, VE::kUInt32, VE::kUInt32); 2597 case UniOpVVVI::kInterleaveShuffleU64x2: return VecOpInfo::make(VE::kUInt64, VE::kUInt64, VE::kUInt64); 2598 case UniOpVVVI::kInterleaveShuffleF32x4: return VecOpInfo::make(VE::kFloat32, VE::kFloat32, VE::kFloat32); 2599 case UniOpVVVI::kInterleaveShuffleF64x2: return VecOpInfo::make(VE::kFloat64, VE::kFloat64, VE::kFloat64); 2600 case UniOpVVVI::kInsertV128_U32 : return VecOpInfo::make(VE::kUInt32, VE::kUInt32, VE::kUInt32); 2601 case UniOpVVVI::kInsertV128_F32 : return VecOpInfo::make(VE::kFloat32, VE::kFloat32, VE::kFloat32); 2602 case UniOpVVVI::kInsertV128_U64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64, VE::kUInt64); 2603 case UniOpVVVI::kInsertV128_F64 : return VecOpInfo::make(VE::kFloat64, VE::kFloat64, VE::kFloat64); 2604 case UniOpVVVI::kInsertV256_U32 : return VecOpInfo::make(VE::kUInt32, VE::kUInt32, VE::kUInt32); 2605 case UniOpVVVI::kInsertV256_F32 : return VecOpInfo::make(VE::kFloat32, VE::kFloat32, VE::kFloat32); 2606 case UniOpVVVI::kInsertV256_U64 : return VecOpInfo::make(VE::kUInt64, VE::kUInt64, VE::kUInt64); 2607 case UniOpVVVI::kInsertV256_F64 : return VecOpInfo::make(VE::kFloat64, VE::kFloat64, VE::kFloat64); 2608 2609 default: 2610 ASMJIT_NOT_REACHED(); 2611 } 2612 } 2613 2614 static const char* vec_op_name_vvvv(UniOpVVVV op) noexcept { 2615 switch (op) { 2616 case UniOpVVVV::kBlendV_U8: return "v_blendv_u8"; 2617 case UniOpVVVV::kMAddU16 : return "v_madd_u16"; 2618 case UniOpVVVV::kMAddU32 : return "v_madd_u32"; 2619 case UniOpVVVV::kMAddF32S : return "v_madd_f32s"; 2620 case UniOpVVVV::kMAddF64S : return "v_madd_f64s"; 2621 case UniOpVVVV::kMAddF32 : return "v_madd_f32"; 2622 case UniOpVVVV::kMAddF64 : return "v_madd_f64"; 2623 case UniOpVVVV::kMSubF32S : return "v_msub_f32s"; 2624 case UniOpVVVV::kMSubF64S : return "v_msub_f64s"; 2625 case UniOpVVVV::kMSubF32 : return "v_msub_f32"; 2626 case UniOpVVVV::kMSubF64 : return "v_msub_f64"; 2627 case UniOpVVVV::kNMAddF32S: return "v_nmadd_f32s"; 2628 case UniOpVVVV::kNMAddF64S: return "v_nmadd_f64s"; 2629 case UniOpVVVV::kNMAddF32 : return "v_nmadd_f32"; 2630 case UniOpVVVV::kNMAddF64 : return "v_nmadd_f64"; 2631 case UniOpVVVV::kNMSubF32S: return "v_nmsub_f32s"; 2632 case UniOpVVVV::kNMSubF64S: return "v_nmsub_f64s"; 2633 case UniOpVVVV::kNMSubF32 : return "v_nmsub_f32"; 2634 case UniOpVVVV::kNMSubF64 : return "v_nmsub_f64"; 2635 } 2636 2637 ASMJIT_NOT_REACHED(); 2638 } 2639 2640 static VecOpInfo vec_op_info_vvvv(UniOpVVVV op) noexcept { 2641 using VE = VecElementType; 2642 2643 switch (op) { 2644 case UniOpVVVV::kBlendV_U8: return VecOpInfo::make(VE::kUInt8, VE::kUInt8, VE::kUInt8, VE::kUInt8); 2645 case UniOpVVVV::kMAddU16 : return VecOpInfo::make(VE::kUInt16, VE::kUInt16, VE::kUInt16, VE::kUInt16); 2646 case UniOpVVVV::kMAddU32 : return VecOpInfo::make(VE::kUInt32, VE::kUInt32, VE::kUInt32, VE::kUInt32); 2647 case UniOpVVVV::kMAddF32S : return VecOpInfo::make(VE::kFloat32, VE::kFloat32, VE::kFloat32, VE::kFloat32); 2648 case UniOpVVVV::kMAddF64S : return VecOpInfo::make(VE::kFloat64, VE::kFloat64, VE::kFloat64, VE::kFloat64); 2649 case UniOpVVVV::kMAddF32 : return VecOpInfo::make(VE::kFloat32, VE::kFloat32, VE::kFloat32, VE::kFloat32); 2650 case UniOpVVVV::kMAddF64 : return VecOpInfo::make(VE::kFloat64, VE::kFloat64, VE::kFloat64, VE::kFloat64); 2651 case UniOpVVVV::kMSubF32S : return VecOpInfo::make(VE::kFloat32, VE::kFloat32, VE::kFloat32, VE::kFloat32); 2652 case UniOpVVVV::kMSubF64S : return VecOpInfo::make(VE::kFloat64, VE::kFloat64, VE::kFloat64, VE::kFloat64); 2653 case UniOpVVVV::kMSubF32 : return VecOpInfo::make(VE::kFloat32, VE::kFloat32, VE::kFloat32, VE::kFloat32); 2654 case UniOpVVVV::kMSubF64 : return VecOpInfo::make(VE::kFloat64, VE::kFloat64, VE::kFloat64, VE::kFloat64); 2655 case UniOpVVVV::kNMAddF32S: return VecOpInfo::make(VE::kFloat32, VE::kFloat32, VE::kFloat32, VE::kFloat32); 2656 case UniOpVVVV::kNMAddF64S: return VecOpInfo::make(VE::kFloat64, VE::kFloat64, VE::kFloat64, VE::kFloat64); 2657 case UniOpVVVV::kNMAddF32 : return VecOpInfo::make(VE::kFloat32, VE::kFloat32, VE::kFloat32, VE::kFloat32); 2658 case UniOpVVVV::kNMAddF64 : return VecOpInfo::make(VE::kFloat64, VE::kFloat64, VE::kFloat64, VE::kFloat64); 2659 case UniOpVVVV::kNMSubF32S: return VecOpInfo::make(VE::kFloat32, VE::kFloat32, VE::kFloat32, VE::kFloat32); 2660 case UniOpVVVV::kNMSubF64S: return VecOpInfo::make(VE::kFloat64, VE::kFloat64, VE::kFloat64, VE::kFloat64); 2661 case UniOpVVVV::kNMSubF32 : return VecOpInfo::make(VE::kFloat32, VE::kFloat32, VE::kFloat32, VE::kFloat32); 2662 case UniOpVVVV::kNMSubF64 : return VecOpInfo::make(VE::kFloat64, VE::kFloat64, VE::kFloat64, VE::kFloat64); 2663 } 2664 2665 ASMJIT_NOT_REACHED(); 2666 } 2667 2668 // ujit::UniCompiler - Tests - SIMD - Float To Int - Machine Behavior 2669 // ================================================================== 2670 2671 template<FloatToIntOutsideRangeBehavior behavior, typename IntT, typename FloatT> 2672 static ASMJIT_INLINE_NODEBUG int32_t cvt_float_to_int_trunc(const FloatT& x) noexcept { 2673 constexpr IntT min_value = std::numeric_limits<IntT>::lowest(); 2674 constexpr IntT max_value = std::numeric_limits<IntT>::max(); 2675 constexpr IntT zero = IntT(0); 2676 2677 if (std::isnan(x)) { 2678 return behavior == FloatToIntOutsideRangeBehavior::kSmallestValue ? min_value : zero; 2679 } 2680 2681 if (x < FloatT(min_value)) { 2682 return min_value; 2683 } 2684 2685 if (x > FloatT(max_value)) { 2686 return behavior == FloatToIntOutsideRangeBehavior::kSmallestValue ? min_value : max_value; 2687 } 2688 2689 return IntT(x); 2690 } 2691 2692 template<FloatToIntOutsideRangeBehavior behavior, typename IntT, typename FloatT> 2693 static ASMJIT_INLINE_NODEBUG int32_t cvt_float_to_int_round(const FloatT& x) noexcept { 2694 constexpr IntT min_value = std::numeric_limits<IntT>::lowest(); 2695 constexpr IntT max_value = std::numeric_limits<IntT>::max(); 2696 constexpr IntT zero = IntT(0); 2697 2698 if (std::isnan(x)) { 2699 return behavior == FloatToIntOutsideRangeBehavior::kSmallestValue ? min_value : zero; 2700 } 2701 2702 if (x < FloatT(min_value)) { 2703 return min_value; 2704 } 2705 2706 if (x > FloatT(max_value)) { 2707 return behavior == FloatToIntOutsideRangeBehavior::kSmallestValue ? min_value : max_value; 2708 } 2709 2710 return IntT(std::nearbyint(x)); 2711 } 2712 2713 // ujit::UniCompiler - Tests - SIMD - Data Generators & Constraints 2714 // ================================================================ 2715 2716 // Data generator, which is used to fill the content of SIMD registers. 2717 class DataGenInt { 2718 public: 2719 TestUtils::Random rng; 2720 uint32_t step; 2721 2722 struct Float32Data { 2723 uint32_t u32; 2724 float f32; 2725 }; 2726 2727 ASMJIT_INLINE explicit DataGenInt(uint64_t seed) noexcept 2728 : rng(seed), 2729 step(0) {} 2730 2731 ASMJIT_NOINLINE uint64_t next_uint64() noexcept { 2732 if (++step >= 256) { 2733 step = 0; 2734 } 2735 2736 // NOTE: Nothing really elaborate - sometimes we want to test also numbers 2737 // that random number generators won't return often, so we hardcode some. 2738 switch (step) { 2739 case 0: return 0u; 2740 case 1: return 0u; 2741 case 2: return 0u; 2742 case 6: return 1u; 2743 case 7: return 0u; 2744 case 10: return 0u; 2745 case 11: return 0xFFu; 2746 case 15: return 0xFFFFu; 2747 case 17: return 0xFFFFFFFFu; 2748 case 21: return 0xFFFFFFFFFFFFFFFFu; 2749 case 24: return 1u; 2750 case 40: return 0xFFu; 2751 case 55: return 0x8080808080808080u; 2752 case 66: return 0x80000080u; 2753 case 69: return 1u; 2754 case 79: return 0x7F; 2755 case 122: return 0xFFFFu; 2756 case 123: return 0xFFFFu; 2757 case 124: return 0xFFFFu; 2758 case 127: return 1u; 2759 case 130: return 0xFFu; 2760 case 142: return 0x7FFFu; 2761 case 143: return 0x7FFFu; 2762 case 144: return 0u; 2763 case 145: return 0x7FFFu; 2764 default : return rng.next_uint64(); 2765 } 2766 } 2767 2768 ASMJIT_NOINLINE float next_float32() noexcept { 2769 if (++step >= 256) { 2770 step = 0; 2771 } 2772 2773 switch (step) { 2774 case 0: return 0.0f; 2775 case 1: return 0.0f; 2776 case 2: return 0.0f; 2777 case 6: return 1.0f; 2778 case 7: return 0.0f; 2779 case 10: return 0.00001f; 2780 case 11: return 2.0f; 2781 case 12: return -std::numeric_limits<float>::infinity(); 2782 case 15: return 3.0f; 2783 case 17: return 256.0f; 2784 case 21: return 0.5f; 2785 case 23: return std::numeric_limits<float>::quiet_NaN(); 2786 case 24: return 0.25f; 2787 case 27: return std::numeric_limits<float>::quiet_NaN(); 2788 case 29: return std::numeric_limits<float>::infinity(); 2789 case 31: return std::numeric_limits<float>::quiet_NaN(); 2790 case 35: return std::numeric_limits<float>::quiet_NaN(); 2791 case 40: return 5.12323f; 2792 case 45: return -std::numeric_limits<float>::infinity(); 2793 case 55: return 100.5f; 2794 case 66: return 0.1f; 2795 case 69: return 0.2f; 2796 case 79: return 0.3f; 2797 case 89: return -13005961.0f; 2798 case 99: return -std::numeric_limits<float>::infinity(); 2799 case 100: 2800 case 102: 2801 case 104: 2802 case 106: 2803 case 108: return float(rng.next_double()); 2804 case 110: 2805 case 112: 2806 case 114: 2807 case 116: 2808 case 118: return -float(rng.next_double()); 2809 case 122: return 10.3f; 2810 case 123: return 20.3f; 2811 case 124: return -100.3f; 2812 case 127: return 1.3f; 2813 case 130: return std::numeric_limits<float>::quiet_NaN(); 2814 case 135: return -std::numeric_limits<float>::infinity(); 2815 case 142: return 1.0f; 2816 case 143: return 1.5f; 2817 case 144: return 2.0f; 2818 case 145: return std::numeric_limits<float>::infinity(); 2819 case 155: return -1.5f; 2820 case 165: return -0.5f; 2821 case 175: return -1.0f; 2822 case 245: return 2.5f; 2823 2824 default: { 2825 float sign = rng.next_uint32() < 0x7FFFFFF ? 1.0f : -1.0f; 2826 return float(rng.next_double() * double(rng.next_uint32() & 0xFFFFFFu)) * sign; 2827 } 2828 } 2829 } 2830 2831 ASMJIT_NOINLINE double next_float64() noexcept { 2832 if (++step >= 256) { 2833 step = 0; 2834 } 2835 2836 switch (step) { 2837 case 0: return 0.0; 2838 case 1: return 0.0; 2839 case 2: return 0.0; 2840 case 6: return 1.0; 2841 case 7: return 0.0; 2842 case 10: return 0.00001; 2843 case 11: return 2.0; 2844 case 12: return -std::numeric_limits<double>::infinity(); 2845 case 15: return 3.0; 2846 case 17: return 256.0; 2847 case 21: return 0.5; 2848 case 23: return std::numeric_limits<double>::quiet_NaN(); 2849 case 24: return 0.25; 2850 case 27: return std::numeric_limits<double>::quiet_NaN(); 2851 case 29: return std::numeric_limits<double>::infinity(); 2852 case 31: return std::numeric_limits<double>::quiet_NaN(); 2853 case 35: return std::numeric_limits<double>::quiet_NaN(); 2854 case 40: return 5.12323; 2855 case 45: return -std::numeric_limits<double>::infinity(); 2856 case 55: return 100.5; 2857 case 66: return 0.1; 2858 case 69: return 0.2; 2859 case 79: return 0.3; 2860 case 80: return 4503599627370495.5; 2861 case 99: return -std::numeric_limits<double>::infinity(); 2862 case 100: 2863 case 102: 2864 case 104: 2865 case 106: 2866 case 108: return rng.next_double(); 2867 case 110: 2868 case 112: 2869 case 114: 2870 case 116: 2871 case 118: return -rng.next_double(); 2872 case 122: return 10.3; 2873 case 123: return 20.3; 2874 case 124: return -100.3; 2875 case 125: return 4503599627370496.0; 2876 case 127: return 1.3; 2877 case 130: return std::numeric_limits<double>::quiet_NaN(); 2878 case 135: return -std::numeric_limits<double>::infinity(); 2879 case 142: return 1.0; 2880 case 143: return 1.5; 2881 case 144: return 2.0; 2882 case 145: return std::numeric_limits<double>::infinity(); 2883 case 155: return -1.5; 2884 case 165: return -0.5; 2885 case 175: return -1.0; 2886 case 245: return 2.5; 2887 case 248: return -4503599627370495.5; 2888 2889 default: { 2890 double sign = rng.next_uint32() < 0x7FFFFFF ? 1.0 : -1.0; 2891 return double(rng.next_double() * double(rng.next_uint32() & 0x3FFFFFFFu)) * sign; 2892 } 2893 } 2894 } 2895 }; 2896 2897 template<typename T> 2898 struct half_minus_1ulp_const; 2899 2900 template<> struct half_minus_1ulp_const<float> { static inline constexpr float value = 0.49999997f; }; 2901 template<> struct half_minus_1ulp_const<double> { static inline constexpr double value = 0.49999999999999994; }; 2902 2903 // Some SIMD operations are constrained, especially those higher level. So, to successfully test these we 2904 // have to model the constraints in a way that the SIMD instruction we test actually gets the correct input. 2905 // Note that a constraint doesn't have to be always range based, it could be anything. 2906 struct ConstraintNone { 2907 template<uint32_t kW> 2908 static ASMJIT_INLINE_NODEBUG void apply(VecOverlay<kW>& v) noexcept { Support::maybe_unused(v); } 2909 }; 2910 2911 template<typename ElementT, typename Derived> 2912 struct ConstraintBase { 2913 template<uint32_t kW> 2914 static ASMJIT_INLINE void apply(VecOverlay<kW>& v) noexcept { 2915 ElementT* elements = v.template data<ElementT>(); 2916 for (size_t i = 0; i < kW / sizeof(ElementT); i++) { 2917 elements[i] = Derived::apply_one(elements[i]); 2918 } 2919 } 2920 }; 2921 2922 template<uint8_t kMin, uint8_t kMax> 2923 struct ConstraintRangeU8 : public ConstraintBase<uint16_t, ConstraintRangeU8<kMin, kMax>> { 2924 static ASMJIT_INLINE_NODEBUG uint8_t apply_one(uint8_t x) noexcept { return std::clamp(x, kMin, kMax); } 2925 }; 2926 2927 template<uint16_t kMin, uint16_t kMax> 2928 struct ConstraintRangeU16 : public ConstraintBase<uint16_t, ConstraintRangeU16<kMin, kMax>> { 2929 static ASMJIT_INLINE_NODEBUG uint16_t apply_one(uint16_t x) noexcept { return std::clamp(x, kMin, kMax); } 2930 }; 2931 2932 template<uint32_t kMin, uint32_t kMax> 2933 struct ConstraintRangeU32 : public ConstraintBase<uint32_t, ConstraintRangeU32<kMin, kMax>> { 2934 static ASMJIT_INLINE_NODEBUG uint32_t apply_one(uint32_t x) noexcept { return std::clamp(x, kMin, kMax); } 2935 }; 2936 2937 // ujit::UniCompiler - Tests - Generic Operations 2938 // ============================================== 2939 2940 template<typename T> 2941 static ASMJIT_INLINE_NODEBUG std::make_unsigned_t<T> cast_uint(const T& x) noexcept { 2942 return static_cast<std::make_unsigned_t<T>>(x); 2943 } 2944 2945 template<typename T> 2946 static ASMJIT_INLINE_NODEBUG std::make_signed_t<T> cast_int(const T& x) noexcept { 2947 return static_cast<std::make_signed_t<T>>(x); 2948 } 2949 2950 static ASMJIT_INLINE_NODEBUG int8_t saturate_i16_to_i8(int16_t x) noexcept { 2951 return x < int16_t(-128) ? int8_t(-128) : 2952 x > int16_t( 127) ? int8_t( 127) : int8_t(x & 0xFF); 2953 } 2954 2955 static ASMJIT_INLINE_NODEBUG uint8_t saturate_i16_to_u8(int16_t x) noexcept { 2956 return x < int16_t(0x00) ? uint8_t(0x00) : 2957 x > int16_t(0xFF) ? uint8_t(0xFF) : uint8_t(x & 0xFF); 2958 } 2959 2960 static ASMJIT_INLINE_NODEBUG int16_t saturate_i32_to_i16(int32_t x) noexcept { 2961 return x < int32_t(-32768) ? int16_t(-32768) : 2962 x > int32_t( 32767) ? int16_t( 32767) : int16_t(x & 0xFFFF); 2963 } 2964 2965 static ASMJIT_INLINE_NODEBUG uint16_t saturate_i32_to_u16(int32_t x) noexcept { 2966 return x < int32_t(0x0000) ? uint16_t(0x0000) : 2967 x > int32_t(0xFFFF) ? uint16_t(0xFFFF) : uint16_t(x & 0xFFFF); 2968 } 2969 2970 template<typename T, typename Derived> struct op_each_vv { 2971 template<uint32_t kW> 2972 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a) noexcept { 2973 VecOverlay<kW> out{}; 2974 for (uint32_t i = 0; i < kW / sizeof(T); i++) { 2975 out.set(i, Derived::apply_one(a.template get<T>(i))); 2976 } 2977 return out; 2978 } 2979 }; 2980 2981 template<typename T, typename Derived> struct op_each_vvi { 2982 template<uint32_t kW> 2983 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a, uint32_t imm) noexcept { 2984 VecOverlay<kW> out{}; 2985 for (uint32_t i = 0; i < kW / sizeof(T); i++) { 2986 out.set(i, Derived::apply_one(a.template get<T>(i), imm)); 2987 } 2988 return out; 2989 } 2990 }; 2991 2992 template<typename T, typename Derived> struct op_each_vvv { 2993 template<uint32_t kW> 2994 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a, const VecOverlay<kW>& b) noexcept { 2995 VecOverlay<kW> out{}; 2996 for (uint32_t i = 0; i < kW / sizeof(T); i++) { 2997 out.set(i, Derived::apply_one(a.template get<T>(i), b.template get<T>(i))); 2998 } 2999 return out; 3000 } 3001 }; 3002 3003 template<typename T, typename Derived> struct op_each_vvvi { 3004 template<uint32_t kW> 3005 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a, const VecOverlay<kW>& b, uint32_t imm) noexcept { 3006 VecOverlay<kW> out{}; 3007 for (uint32_t i = 0; i < kW / sizeof(T); i++) { 3008 out.set(i, Derived::apply_one(a.template get<T>(i), b.template get<T>(i), imm)); 3009 } 3010 return out; 3011 } 3012 }; 3013 3014 template<typename T, typename Derived> struct op_each_vvvv { 3015 template<uint32_t kW> 3016 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a, const VecOverlay<kW>& b, const VecOverlay<kW>& c) noexcept { 3017 VecOverlay<kW> out{}; 3018 for (uint32_t i = 0; i < kW / sizeof(T); i++) { 3019 out.set(i, Derived::apply_one(a.template get<T>(i), b.template get<T>(i), c.template get<T>(i))); 3020 } 3021 return out; 3022 } 3023 }; 3024 3025 template<ScalarOpBehavior kB, typename T, typename Derived> struct op_scalar_vv { 3026 template<uint32_t kW> 3027 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a) noexcept { 3028 VecOverlay<kW> out {}; 3029 if constexpr (kB == ScalarOpBehavior::kPreservingVec128) { 3030 out.copy_16b_from(a); 3031 } 3032 out.set(0, Derived::apply_one(a.template get<T>(0))); 3033 return out; 3034 } 3035 }; 3036 3037 template<ScalarOpBehavior kB, typename T, typename Derived> struct op_scalar_vvi { 3038 template<uint32_t kW> 3039 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a, uint32_t imm) noexcept { 3040 VecOverlay<kW> out {}; 3041 if constexpr (kB == ScalarOpBehavior::kPreservingVec128) { 3042 out.copy_16b_from(a); 3043 } 3044 out.set(0, Derived::apply_one(a.template get<T>(0), imm)); 3045 return out; 3046 } 3047 }; 3048 3049 template<ScalarOpBehavior kB, typename T, typename Derived> struct op_scalar_vvv { 3050 template<uint32_t kW> 3051 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a, const VecOverlay<kW>& b) noexcept { 3052 VecOverlay<kW> out {}; 3053 if constexpr (kB == ScalarOpBehavior::kPreservingVec128) { 3054 out.copy_16b_from(a); 3055 } 3056 out.set(0, Derived::apply_one(a.template get<T>(0), b.template get<T>(0))); 3057 return out; 3058 } 3059 }; 3060 3061 template<ScalarOpBehavior kB, typename T, typename Derived> struct op_scalar_vvvv { 3062 template<uint32_t kW> 3063 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a, const VecOverlay<kW>& b, const VecOverlay<kW>& c) noexcept { 3064 VecOverlay<kW> out {}; 3065 if constexpr (kB == ScalarOpBehavior::kPreservingVec128) { 3066 out.copy_16b_from(a); 3067 } 3068 out.set(0, Derived::apply_one(a.template get<T>(0), b.template get<T>(0), c.template get<T>(0))); 3069 return out; 3070 } 3071 }; 3072 3073 // ujit::UniCompiler - Tests - Generic Operations - VV 3074 // =================================================== 3075 3076 struct vec_op_mov : public op_each_vv<uint32_t, vec_op_mov> { 3077 static ASMJIT_INLINE_NODEBUG uint32_t apply_one(const uint32_t& a) noexcept { return a; } 3078 }; 3079 3080 struct vec_op_mov_u64 { 3081 template<uint32_t kW> 3082 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a) noexcept { 3083 VecOverlay<kW> out{}; 3084 out.data_u64[0] = a.data_u64[0]; 3085 return out; 3086 } 3087 }; 3088 3089 struct vec_op_broadcast_u8 { 3090 template<uint32_t kW> 3091 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a) noexcept { 3092 VecOverlay<kW> out{}; 3093 for (uint32_t i = 0; i < kW; i++) 3094 out.data_u8[i] = a.data_u8[0]; 3095 return out; 3096 } 3097 }; 3098 3099 struct vec_op_broadcast_u16 { 3100 template<uint32_t kW> 3101 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a) noexcept { 3102 VecOverlay<kW> out{}; 3103 for (uint32_t i = 0; i < kW / 2u; i++) { 3104 out.data_u16[i] = a.data_u16[0]; 3105 } 3106 return out; 3107 } 3108 }; 3109 3110 struct vec_op_broadcast_u32 { 3111 template<uint32_t kW> 3112 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a) noexcept { 3113 VecOverlay<kW> out{}; 3114 for (uint32_t i = 0; i < kW / 4u; i++) { 3115 out.data_u32[i] = a.data_u32[0]; 3116 } 3117 return out; 3118 } 3119 }; 3120 3121 struct vec_op_broadcast_u64 { 3122 template<uint32_t kW> 3123 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a) noexcept { 3124 VecOverlay<kW> out{}; 3125 for (uint32_t i = 0; i < kW / 8u; i++) { 3126 out.data_u64[i] = a.data_u64[0]; 3127 } 3128 return out; 3129 } 3130 }; 3131 3132 struct vec_op_broadcast_u128 { 3133 template<uint32_t kW> 3134 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a) noexcept { 3135 VecOverlay<kW> out{}; 3136 3137 for (uint32_t i = 0; i < kW / 8u; i += 2) { 3138 out.data_u64[i + 0] = a.data_u64[0]; 3139 out.data_u64[i + 1] = a.data_u64[1]; 3140 } 3141 return out; 3142 } 3143 }; 3144 3145 struct vec_op_broadcast_u256 { 3146 template<uint32_t kW> 3147 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a) noexcept { 3148 VecOverlay<kW> out{}; 3149 if constexpr (kW < 32) { 3150 out = a; 3151 } 3152 else { 3153 for (uint32_t i = 0; i < kW / 8u; i += 4) { 3154 out.data_u64[i + 0] = a.data_u64[0]; 3155 out.data_u64[i + 1] = a.data_u64[1]; 3156 out.data_u64[i + 2] = a.data_u64[2]; 3157 out.data_u64[i + 3] = a.data_u64[3]; 3158 } 3159 } 3160 return out; 3161 } 3162 }; 3163 3164 template<typename T> struct vec_op_abs : public op_each_vv<T, vec_op_abs<T>> { 3165 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a) noexcept { return a < 0 ? T(cast_uint(T(0)) - cast_uint(a)) : a; } 3166 }; 3167 3168 template<typename T> struct vec_op_neg : public op_each_vv<T, vec_op_neg<T>> { 3169 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a) noexcept { return T(cast_uint(T(0)) - cast_uint(a)); } 3170 }; 3171 3172 template<typename T> struct vec_op_not : public op_each_vv<T, vec_op_not<T>> { 3173 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a) noexcept { return T(~a); } 3174 }; 3175 3176 struct vec_op_cvt_i8_lo_to_i16 { 3177 template<uint32_t kW> 3178 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a) noexcept { 3179 VecOverlay<kW> out{}; 3180 for (uint32_t off = 0; off < kW; off += 16) { 3181 out.data_i16[off / 2 + 0] = a.data_i8[off / 2 + 0]; 3182 out.data_i16[off / 2 + 1] = a.data_i8[off / 2 + 1]; 3183 out.data_i16[off / 2 + 2] = a.data_i8[off / 2 + 2]; 3184 out.data_i16[off / 2 + 3] = a.data_i8[off / 2 + 3]; 3185 out.data_i16[off / 2 + 4] = a.data_i8[off / 2 + 4]; 3186 out.data_i16[off / 2 + 5] = a.data_i8[off / 2 + 5]; 3187 out.data_i16[off / 2 + 6] = a.data_i8[off / 2 + 6]; 3188 out.data_i16[off / 2 + 7] = a.data_i8[off / 2 + 7]; 3189 } 3190 return out; 3191 } 3192 }; 3193 3194 struct vec_op_cvt_i8_hi_to_i16 { 3195 template<uint32_t kW> 3196 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a) noexcept { 3197 VecOverlay<kW> out{}; 3198 for (uint32_t off = 0; off < kW; off += 16) { 3199 out.data_i16[off / 2 + 0] = a.data_i8[kW / 2 + off / 2 + 0]; 3200 out.data_i16[off / 2 + 1] = a.data_i8[kW / 2 + off / 2 + 1]; 3201 out.data_i16[off / 2 + 2] = a.data_i8[kW / 2 + off / 2 + 2]; 3202 out.data_i16[off / 2 + 3] = a.data_i8[kW / 2 + off / 2 + 3]; 3203 out.data_i16[off / 2 + 4] = a.data_i8[kW / 2 + off / 2 + 4]; 3204 out.data_i16[off / 2 + 5] = a.data_i8[kW / 2 + off / 2 + 5]; 3205 out.data_i16[off / 2 + 6] = a.data_i8[kW / 2 + off / 2 + 6]; 3206 out.data_i16[off / 2 + 7] = a.data_i8[kW / 2 + off / 2 + 7]; 3207 } 3208 return out; 3209 } 3210 }; 3211 3212 struct vec_op_cvt_u8_lo_to_u16 { 3213 template<uint32_t kW> 3214 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a) noexcept { 3215 VecOverlay<kW> out{}; 3216 for (uint32_t off = 0; off < kW; off += 16) { 3217 out.data_u16[off / 2 + 0] = a.data_u8[off / 2 + 0]; 3218 out.data_u16[off / 2 + 1] = a.data_u8[off / 2 + 1]; 3219 out.data_u16[off / 2 + 2] = a.data_u8[off / 2 + 2]; 3220 out.data_u16[off / 2 + 3] = a.data_u8[off / 2 + 3]; 3221 out.data_u16[off / 2 + 4] = a.data_u8[off / 2 + 4]; 3222 out.data_u16[off / 2 + 5] = a.data_u8[off / 2 + 5]; 3223 out.data_u16[off / 2 + 6] = a.data_u8[off / 2 + 6]; 3224 out.data_u16[off / 2 + 7] = a.data_u8[off / 2 + 7]; 3225 } 3226 return out; 3227 } 3228 }; 3229 3230 struct vec_op_cvt_u8_hi_to_u16 { 3231 template<uint32_t kW> 3232 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a) noexcept { 3233 VecOverlay<kW> out{}; 3234 for (uint32_t off = 0; off < kW; off += 16) { 3235 out.data_u16[off / 2 + 0] = a.data_u8[kW / 2 + off / 2 + 0]; 3236 out.data_u16[off / 2 + 1] = a.data_u8[kW / 2 + off / 2 + 1]; 3237 out.data_u16[off / 2 + 2] = a.data_u8[kW / 2 + off / 2 + 2]; 3238 out.data_u16[off / 2 + 3] = a.data_u8[kW / 2 + off / 2 + 3]; 3239 out.data_u16[off / 2 + 4] = a.data_u8[kW / 2 + off / 2 + 4]; 3240 out.data_u16[off / 2 + 5] = a.data_u8[kW / 2 + off / 2 + 5]; 3241 out.data_u16[off / 2 + 6] = a.data_u8[kW / 2 + off / 2 + 6]; 3242 out.data_u16[off / 2 + 7] = a.data_u8[kW / 2 + off / 2 + 7]; 3243 } 3244 return out; 3245 } 3246 }; 3247 3248 struct vec_op_cvt_i8_to_i32 { 3249 template<uint32_t kW> 3250 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a) noexcept { 3251 VecOverlay<kW> out{}; 3252 for (uint32_t off = 0; off < kW; off += 16) { 3253 out.data_i32[off / 4 + 0] = a.data_i8[off / 4 + 0]; 3254 out.data_i32[off / 4 + 1] = a.data_i8[off / 4 + 1]; 3255 out.data_i32[off / 4 + 2] = a.data_i8[off / 4 + 2]; 3256 out.data_i32[off / 4 + 3] = a.data_i8[off / 4 + 3]; 3257 } 3258 return out; 3259 } 3260 }; 3261 3262 struct vec_op_cvt_u8_to_u32 { 3263 template<uint32_t kW> 3264 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a) noexcept { 3265 VecOverlay<kW> out{}; 3266 for (uint32_t off = 0; off < kW; off += 16) { 3267 out.data_u32[off / 4 + 0] = a.data_u8[off / 4 + 0]; 3268 out.data_u32[off / 4 + 1] = a.data_u8[off / 4 + 1]; 3269 out.data_u32[off / 4 + 2] = a.data_u8[off / 4 + 2]; 3270 out.data_u32[off / 4 + 3] = a.data_u8[off / 4 + 3]; 3271 } 3272 return out; 3273 } 3274 }; 3275 3276 struct vec_op_cvt_i16_lo_to_i32 { 3277 template<uint32_t kW> 3278 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a) noexcept { 3279 VecOverlay<kW> out{}; 3280 for (uint32_t off = 0; off < kW; off += 16) { 3281 out.data_i32[off / 4 + 0] = a.data_i16[off / 4 + 0]; 3282 out.data_i32[off / 4 + 1] = a.data_i16[off / 4 + 1]; 3283 out.data_i32[off / 4 + 2] = a.data_i16[off / 4 + 2]; 3284 out.data_i32[off / 4 + 3] = a.data_i16[off / 4 + 3]; 3285 } 3286 return out; 3287 } 3288 }; 3289 3290 struct vec_op_cvt_i16_hi_to_i32 { 3291 template<uint32_t kW> 3292 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a) noexcept { 3293 VecOverlay<kW> out{}; 3294 for (uint32_t off = 0; off < kW; off += 16) { 3295 out.data_i32[off / 4 + 0] = a.data_i16[kW / 4 + off / 4 + 0]; 3296 out.data_i32[off / 4 + 1] = a.data_i16[kW / 4 + off / 4 + 1]; 3297 out.data_i32[off / 4 + 2] = a.data_i16[kW / 4 + off / 4 + 2]; 3298 out.data_i32[off / 4 + 3] = a.data_i16[kW / 4 + off / 4 + 3]; 3299 } 3300 return out; 3301 } 3302 }; 3303 3304 struct vec_op_cvt_u16_lo_to_u32 { 3305 template<uint32_t kW> 3306 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a) noexcept { 3307 VecOverlay<kW> out{}; 3308 for (uint32_t off = 0; off < kW; off += 16) { 3309 out.data_u32[off / 4 + 0] = a.data_u16[off / 4 + 0]; 3310 out.data_u32[off / 4 + 1] = a.data_u16[off / 4 + 1]; 3311 out.data_u32[off / 4 + 2] = a.data_u16[off / 4 + 2]; 3312 out.data_u32[off / 4 + 3] = a.data_u16[off / 4 + 3]; 3313 } 3314 return out; 3315 } 3316 }; 3317 3318 struct vec_op_cvt_u16_hi_to_u32 { 3319 template<uint32_t kW> 3320 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a) noexcept { 3321 VecOverlay<kW> out{}; 3322 for (uint32_t off = 0; off < kW; off += 16) { 3323 out.data_u32[off / 4 + 0] = a.data_u16[kW / 4 + off / 4 + 0]; 3324 out.data_u32[off / 4 + 1] = a.data_u16[kW / 4 + off / 4 + 1]; 3325 out.data_u32[off / 4 + 2] = a.data_u16[kW / 4 + off / 4 + 2]; 3326 out.data_u32[off / 4 + 3] = a.data_u16[kW / 4 + off / 4 + 3]; 3327 } 3328 return out; 3329 } 3330 }; 3331 3332 struct vec_op_cvt_i32_lo_to_i64 { 3333 template<uint32_t kW> 3334 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a) noexcept { 3335 VecOverlay<kW> out{}; 3336 for (uint32_t off = 0; off < kW; off += 16) { 3337 out.data_i64[off / 8 + 0] = a.data_i32[off / 8 + 0]; 3338 out.data_i64[off / 8 + 1] = a.data_i32[off / 8 + 1]; 3339 } 3340 return out; 3341 } 3342 }; 3343 3344 struct vec_op_cvt_i32_hi_to_i64 { 3345 template<uint32_t kW> 3346 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a) noexcept { 3347 VecOverlay<kW> out{}; 3348 for (uint32_t off = 0; off < kW; off += 16) { 3349 out.data_i64[off / 8 + 0] = a.data_i32[kW / 8 + off / 8 + 0]; 3350 out.data_i64[off / 8 + 1] = a.data_i32[kW / 8 + off / 8 + 1]; 3351 } 3352 return out; 3353 } 3354 }; 3355 3356 struct vec_op_cvt_u32_lo_to_u64 { 3357 template<uint32_t kW> 3358 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a) noexcept { 3359 VecOverlay<kW> out{}; 3360 for (uint32_t off = 0; off < kW; off += 16) { 3361 out.data_u64[off / 8 + 0] = a.data_u32[off / 8 + 0]; 3362 out.data_u64[off / 8 + 1] = a.data_u32[off / 8 + 1]; 3363 } 3364 return out; 3365 } 3366 }; 3367 3368 struct vec_op_cvt_u32_hi_to_u64 { 3369 template<uint32_t kW> 3370 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a) noexcept { 3371 VecOverlay<kW> out{}; 3372 for (uint32_t off = 0; off < kW; off += 16) { 3373 out.data_u64[off / 8 + 0] = a.data_u32[kW / 8 + off / 8 + 0]; 3374 out.data_u64[off / 8 + 1] = a.data_u32[kW / 8 + off / 8 + 1]; 3375 } 3376 return out; 3377 } 3378 }; 3379 3380 template<typename T> struct vec_op_fabs : public op_each_vv<T, vec_op_fabs<T>> { 3381 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a) noexcept { return std::fabs(a); } 3382 }; 3383 3384 template<typename T> struct vec_op_trunc : public op_each_vv<T, vec_op_trunc<T>> { 3385 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a) noexcept { return std::trunc(a); } 3386 }; 3387 3388 template<typename T> struct vec_op_floor : public op_each_vv<T, vec_op_floor<T>> { 3389 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a) noexcept { return std::floor(a); } 3390 }; 3391 3392 template<typename T> struct vec_op_ceil : public op_each_vv<T, vec_op_ceil<T>> { 3393 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a) noexcept { return std::ceil(a); } 3394 }; 3395 3396 template<typename T> struct vec_op_round_even : public op_each_vv<T, vec_op_round_even<T>> { 3397 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a) noexcept { return std::nearbyint(a); } 3398 }; 3399 3400 template<typename T> struct vec_op_round_half_away : public op_each_vv<T, vec_op_round_half_away<T>> { 3401 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a) noexcept { return std::trunc(fadd(a, fxor(half_minus_1ulp_const<T>::value, fsign(a)))); } 3402 }; 3403 3404 template<typename T> struct vec_op_round_half_up : public op_each_vv<T, vec_op_round_half_up<T>> { 3405 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a) noexcept { return std::floor(fadd(a, half_minus_1ulp_const<T>::value)); } 3406 }; 3407 3408 template<typename T> struct vec_op_sqrt : public op_each_vv<T, vec_op_sqrt<T>> { 3409 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a) noexcept { return fsqrt(a); } 3410 }; 3411 3412 template<typename T> struct vec_op_rcp : public op_each_vv<T, vec_op_rcp<T>> { 3413 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a) noexcept { return fdiv(T(1), a); } 3414 }; 3415 3416 struct vec_op_cvt_i32_to_f32 { 3417 template<uint32_t kW> 3418 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a) noexcept { 3419 VecOverlay<kW> out{}; 3420 for (uint32_t off = 0; off < kW; off += 16) { 3421 out.data_f32[off / 4 + 0] = float(a.data_i32[off / 4 + 0]); 3422 out.data_f32[off / 4 + 1] = float(a.data_i32[off / 4 + 1]); 3423 out.data_f32[off / 4 + 2] = float(a.data_i32[off / 4 + 2]); 3424 out.data_f32[off / 4 + 3] = float(a.data_i32[off / 4 + 3]); 3425 } 3426 return out; 3427 } 3428 }; 3429 3430 template<bool kHi> 3431 struct vec_op_cvt_f32_to_f64_impl { 3432 template<uint32_t kW> 3433 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a) noexcept { 3434 VecOverlay<kW> out{}; 3435 uint32_t adj = kHi ? kW / 8 : 0u; 3436 for (uint32_t off = 0; off < kW; off += 16) { 3437 out.data_f64[off / 8 + 0] = double(a.data_f32[off / 8 + adj + 0]); 3438 out.data_f64[off / 8 + 1] = double(a.data_f32[off / 8 + adj + 1]); 3439 } 3440 return out; 3441 } 3442 }; 3443 3444 struct vec_op_cvt_f32_lo_to_f64 : public vec_op_cvt_f32_to_f64_impl<false> {}; 3445 struct vec_op_cvt_f32_hi_to_f64 : public vec_op_cvt_f32_to_f64_impl<true> {}; 3446 3447 template<bool kHi> 3448 struct vec_op_cvt_f64_to_f32_impl { 3449 template<uint32_t kW> 3450 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a) noexcept { 3451 VecOverlay<kW> out{}; 3452 uint32_t adj = kHi ? kW / 8 : 0u; 3453 for (uint32_t off = 0; off < kW; off += 16) { 3454 out.data_f32[off / 8 + adj + 0] = float(a.data_f64[off / 8 + 0]); 3455 out.data_f32[off / 8 + adj + 1] = float(a.data_f64[off / 8 + 1]); 3456 } 3457 return out; 3458 } 3459 }; 3460 3461 struct vec_op_cvt_f64_to_f32_lo : public vec_op_cvt_f64_to_f32_impl<false> {}; 3462 struct vec_op_cvt_f64_to_f32_hi : public vec_op_cvt_f64_to_f32_impl<true> {}; 3463 3464 template<bool kHi> 3465 struct vec_op_cvt_i32_to_f64_impl { 3466 template<uint32_t kW> 3467 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a) noexcept { 3468 VecOverlay<kW> out{}; 3469 uint32_t adj = kHi ? kW / 8 : 0u; 3470 for (uint32_t off = 0; off < kW; off += 16) { 3471 out.data_f64[off / 8 + 0] = double(a.data_i32[off / 8 + adj + 0]); 3472 out.data_f64[off / 8 + 1] = double(a.data_i32[off / 8 + adj + 1]); 3473 } 3474 return out; 3475 } 3476 }; 3477 3478 struct vec_op_cvt_i32_lo_to_f64 : public vec_op_cvt_i32_to_f64_impl<false> {}; 3479 struct vec_op_cvt_i32_hi_to_f64 : public vec_op_cvt_i32_to_f64_impl<true> {}; 3480 3481 template<FloatToIntOutsideRangeBehavior behavior> 3482 struct vec_op_cvt_trunc_f32_to_i32 { 3483 template<uint32_t kW> 3484 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a) noexcept { 3485 VecOverlay<kW> out{}; 3486 for (uint32_t off = 0; off < kW; off += 16) { 3487 out.data_i32[off / 4 + 0] = cvt_float_to_int_trunc<behavior, int32_t>(a.data_f32[off / 4 + 0]); 3488 out.data_i32[off / 4 + 1] = cvt_float_to_int_trunc<behavior, int32_t>(a.data_f32[off / 4 + 1]); 3489 out.data_i32[off / 4 + 2] = cvt_float_to_int_trunc<behavior, int32_t>(a.data_f32[off / 4 + 2]); 3490 out.data_i32[off / 4 + 3] = cvt_float_to_int_trunc<behavior, int32_t>(a.data_f32[off / 4 + 3]); 3491 } 3492 return out; 3493 } 3494 }; 3495 3496 template<FloatToIntOutsideRangeBehavior behavior, bool kHi> 3497 struct vec_op_cvt_trunc_f64_to_i32_impl { 3498 template<uint32_t kW> 3499 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a) noexcept { 3500 VecOverlay<kW> out{}; 3501 uint32_t adj = kHi ? kW / 8 : 0u; 3502 for (uint32_t off = 0; off < kW; off += 16) { 3503 out.data_i32[off / 8 + adj + 0] = cvt_float_to_int_trunc<behavior, int32_t>(a.data_f64[off / 8 + 0]); 3504 out.data_i32[off / 8 + adj + 1] = cvt_float_to_int_trunc<behavior, int32_t>(a.data_f64[off / 8 + 1]); 3505 } 3506 return out; 3507 } 3508 }; 3509 3510 template<FloatToIntOutsideRangeBehavior behavior> 3511 struct vec_op_cvt_trunc_f64_to_i32_lo : vec_op_cvt_trunc_f64_to_i32_impl<behavior, false> {}; 3512 3513 template<FloatToIntOutsideRangeBehavior behavior> 3514 struct vec_op_cvt_trunc_f64_to_i32_hi : vec_op_cvt_trunc_f64_to_i32_impl<behavior, true> {}; 3515 3516 template<FloatToIntOutsideRangeBehavior behavior> 3517 struct vec_op_cvt_round_f32_to_i32 { 3518 template<uint32_t kW> 3519 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a) noexcept { 3520 VecOverlay<kW> out{}; 3521 for (uint32_t off = 0; off < kW; off += 16) { 3522 out.data_i32[off / 4 + 0] = cvt_float_to_int_round<behavior, int32_t>(a.data_f32[off / 4 + 0]); 3523 out.data_i32[off / 4 + 1] = cvt_float_to_int_round<behavior, int32_t>(a.data_f32[off / 4 + 1]); 3524 out.data_i32[off / 4 + 2] = cvt_float_to_int_round<behavior, int32_t>(a.data_f32[off / 4 + 2]); 3525 out.data_i32[off / 4 + 3] = cvt_float_to_int_round<behavior, int32_t>(a.data_f32[off / 4 + 3]); 3526 } 3527 return out; 3528 } 3529 }; 3530 3531 template<FloatToIntOutsideRangeBehavior behavior, bool kHi> 3532 struct vec_op_cvt_round_f64_to_i32_impl { 3533 template<uint32_t kW> 3534 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a) noexcept { 3535 VecOverlay<kW> out{}; 3536 uint32_t adj = kHi ? kW / 8 : 0u; 3537 for (uint32_t off = 0; off < kW; off += 16) { 3538 out.data_i32[off / 8 + adj + 0] = cvt_float_to_int_round<behavior, int32_t>(a.data_f64[off / 8 + 0]); 3539 out.data_i32[off / 8 + adj + 1] = cvt_float_to_int_round<behavior, int32_t>(a.data_f64[off / 8 + 1]); 3540 } 3541 return out; 3542 } 3543 }; 3544 3545 template<FloatToIntOutsideRangeBehavior behavior> 3546 struct vec_op_cvt_round_f64_to_i32_lo : vec_op_cvt_round_f64_to_i32_impl<behavior, false> {}; 3547 template<FloatToIntOutsideRangeBehavior behavior> 3548 struct vec_op_cvt_round_f64_to_i32_hi : vec_op_cvt_round_f64_to_i32_impl<behavior, true> {}; 3549 3550 struct scalar_op_cvt_f32_to_f64 { 3551 template<uint32_t kW> 3552 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a) noexcept { 3553 VecOverlay<kW> out{}; 3554 out.data_f64[0] = a.data_f32[0]; 3555 return out; 3556 } 3557 }; 3558 3559 struct scalar_op_cvt_f64_to_f32 { 3560 template<uint32_t kW> 3561 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a) noexcept { 3562 VecOverlay<kW> out{}; 3563 out.data_f32[0] = a.data_f64[0]; 3564 return out; 3565 } 3566 }; 3567 3568 template<ScalarOpBehavior kB, typename T> struct scalar_op_trunc : public op_scalar_vv<kB, T, scalar_op_trunc<kB, T>> { 3569 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a) noexcept { return std::trunc(a); } 3570 }; 3571 3572 template<ScalarOpBehavior kB, typename T> struct scalar_op_floor : public op_scalar_vv<kB, T, scalar_op_floor<kB, T>> { 3573 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a) noexcept { return std::floor(a); } 3574 }; 3575 3576 template<ScalarOpBehavior kB, typename T> struct scalar_op_ceil : public op_scalar_vv<kB, T, scalar_op_ceil<kB, T>> { 3577 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a) noexcept { return std::ceil(a); } 3578 }; 3579 3580 template<ScalarOpBehavior kB, typename T> struct scalar_op_round_even : public op_scalar_vv<kB, T, scalar_op_round_even<kB, T>> { 3581 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a) noexcept { return std::nearbyint(a); } 3582 }; 3583 3584 template<ScalarOpBehavior kB, typename T> struct scalar_op_round_half_away : public op_scalar_vv<kB, T, scalar_op_round_half_away<kB, T>> { 3585 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a) noexcept { return std::trunc(fadd(a, fxor(half_minus_1ulp_const<T>::value, fsign(a)))); } 3586 }; 3587 3588 template<ScalarOpBehavior kB, typename T> struct scalar_op_round_half_up : public op_scalar_vv<kB, T, scalar_op_round_half_up<kB, T>> { 3589 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a) noexcept { return std::floor(fadd(a, half_minus_1ulp_const<T>::value)); } 3590 }; 3591 3592 template<ScalarOpBehavior kB, typename T> struct scalar_op_sqrt : public op_scalar_vv<kB, T, scalar_op_sqrt<kB, T>> { 3593 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a) noexcept { return fsqrt(a); } 3594 }; 3595 3596 // ujit::UniCompiler - Tests - Generic Operations - VVI 3597 // ==================================================== 3598 3599 template<typename T> struct vec_op_slli : public op_each_vvi<T, vec_op_slli<T>> { 3600 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, uint32_t imm) noexcept { return T(cast_uint(a) << imm); } 3601 }; 3602 3603 template<typename T> struct vec_op_srli : public op_each_vvi<T, vec_op_srli<T>> { 3604 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, uint32_t imm) noexcept { return T(cast_uint(a) >> imm); } 3605 }; 3606 3607 template<typename T> struct vec_op_rsrli : public op_each_vvi<T, vec_op_rsrli<T>> { 3608 static ASMJIT_INLINE T apply_one(const T& a, uint32_t imm) noexcept { 3609 T add = T((a & (T(1) << (imm - 1))) != 0); 3610 return T((cast_uint(a) >> imm) + cast_uint(add)); 3611 } 3612 }; 3613 3614 template<typename T> struct vec_op_srai : public op_each_vvi<T, vec_op_srai<T>> { 3615 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, uint32_t imm) noexcept { return T(cast_int(a) >> imm); } 3616 }; 3617 3618 struct vec_op_sllb_u128 { 3619 template<uint32_t kW> 3620 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a, uint32_t imm) noexcept { 3621 VecOverlay<kW> out{}; 3622 for (uint32_t off = 0; off < kW; off += 16) { 3623 for (uint32_t i = 0; i < 16; i++) { 3624 out.data_u8[off + i] = i < imm ? uint8_t(0) : a.data_u8[off + i - imm]; 3625 } 3626 } 3627 return out; 3628 } 3629 }; 3630 3631 struct vec_op_srlb_u128 { 3632 template<uint32_t kW> 3633 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a, uint32_t imm) noexcept { 3634 VecOverlay<kW> out{}; 3635 for (uint32_t off = 0; off < kW; off += 16) { 3636 for (uint32_t i = 0; i < 16; i++) { 3637 out.data_u8[off + i] = i + imm < 16u ? a.data_u8[off + i + imm] : uint8_t(0); 3638 } 3639 } 3640 return out; 3641 } 3642 }; 3643 3644 struct vec_op_swizzle_u16 { 3645 template<uint32_t kW> 3646 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a, uint32_t imm) noexcept { 3647 uint32_t D = (imm >> 24) & 0x3; 3648 uint32_t C = (imm >> 16) & 0x3; 3649 uint32_t B = (imm >> 8) & 0x3; 3650 uint32_t A = (imm >> 0) & 0x3; 3651 3652 VecOverlay<kW> out{}; 3653 for (uint32_t off = 0; off < kW; off += 16) { 3654 out.data_u16[off / 2 + 0] = a.data_u16[off / 2 + 0 + A]; 3655 out.data_u16[off / 2 + 1] = a.data_u16[off / 2 + 0 + B]; 3656 out.data_u16[off / 2 + 2] = a.data_u16[off / 2 + 0 + C]; 3657 out.data_u16[off / 2 + 3] = a.data_u16[off / 2 + 0 + D]; 3658 out.data_u16[off / 2 + 4] = a.data_u16[off / 2 + 4 + A]; 3659 out.data_u16[off / 2 + 5] = a.data_u16[off / 2 + 4 + B]; 3660 out.data_u16[off / 2 + 6] = a.data_u16[off / 2 + 4 + C]; 3661 out.data_u16[off / 2 + 7] = a.data_u16[off / 2 + 4 + D]; 3662 } 3663 return out; 3664 } 3665 }; 3666 3667 struct vec_op_swizzle_lo_u16x4 { 3668 template<uint32_t kW> 3669 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a, uint32_t imm) noexcept { 3670 uint32_t D = (imm >> 24) & 0x3; 3671 uint32_t C = (imm >> 16) & 0x3; 3672 uint32_t B = (imm >> 8) & 0x3; 3673 uint32_t A = (imm >> 0) & 0x3; 3674 3675 VecOverlay<kW> out{}; 3676 for (uint32_t off = 0; off < kW; off += 16) { 3677 out.data_u16[off / 2 + 0] = a.data_u16[off / 2 + A]; 3678 out.data_u16[off / 2 + 1] = a.data_u16[off / 2 + B]; 3679 out.data_u16[off / 2 + 2] = a.data_u16[off / 2 + C]; 3680 out.data_u16[off / 2 + 3] = a.data_u16[off / 2 + D]; 3681 memcpy(out.data_u8 + off + 8, a.data_u8 + off + 8, 8); 3682 } 3683 return out; 3684 } 3685 }; 3686 3687 struct vec_op_swizzle_hi_u16x4 { 3688 template<uint32_t kW> 3689 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a, uint32_t imm) noexcept { 3690 uint32_t D = (imm >> 24) & 0x3; 3691 uint32_t C = (imm >> 16) & 0x3; 3692 uint32_t B = (imm >> 8) & 0x3; 3693 uint32_t A = (imm >> 0) & 0x3; 3694 3695 VecOverlay<kW> out{}; 3696 for (uint32_t off = 0; off < kW; off += 16) { 3697 memcpy(out.data_u8 + off, a.data_u8 + off, 8); 3698 out.data_u16[off / 2 + 4] = a.data_u16[off / 2 + 4 + A]; 3699 out.data_u16[off / 2 + 5] = a.data_u16[off / 2 + 4 + B]; 3700 out.data_u16[off / 2 + 6] = a.data_u16[off / 2 + 4 + C]; 3701 out.data_u16[off / 2 + 7] = a.data_u16[off / 2 + 4 + D]; 3702 } 3703 return out; 3704 } 3705 }; 3706 3707 struct vec_op_swizzle_u32x4 { 3708 template<uint32_t kW> 3709 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a, uint32_t imm) noexcept { 3710 uint32_t D = (imm >> 24) & 0x3; 3711 uint32_t C = (imm >> 16) & 0x3; 3712 uint32_t B = (imm >> 8) & 0x3; 3713 uint32_t A = (imm >> 0) & 0x3; 3714 3715 VecOverlay<kW> out{}; 3716 for (uint32_t off = 0; off < kW; off += 16) { 3717 out.data_u32[off / 4 + 0] = a.data_u32[off / 4 + A]; 3718 out.data_u32[off / 4 + 1] = a.data_u32[off / 4 + B]; 3719 out.data_u32[off / 4 + 2] = a.data_u32[off / 4 + C]; 3720 out.data_u32[off / 4 + 3] = a.data_u32[off / 4 + D]; 3721 } 3722 return out; 3723 } 3724 }; 3725 3726 struct vec_op_swizzle_u64x2 { 3727 template<uint32_t kW> 3728 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a, uint32_t imm) noexcept { 3729 uint32_t B = (imm >> 8) & 0x1; 3730 uint32_t A = (imm >> 0) & 0x1; 3731 3732 VecOverlay<kW> out{}; 3733 for (uint32_t off = 0; off < kW; off += 16) { 3734 out.data_u64[off / 8 + 0] = a.data_u64[off / 8 + A]; 3735 out.data_u64[off / 8 + 1] = a.data_u64[off / 8 + B]; 3736 } 3737 return out; 3738 } 3739 }; 3740 3741 // ujit::UniCompiler - Tests - SIMD - Generic Operations - VVV 3742 // =========================================================== 3743 3744 template<typename T> struct vec_op_and : public op_each_vvv<T, vec_op_and<T>> { 3745 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b) noexcept { return T(a & b); } 3746 }; 3747 3748 template<typename T> struct vec_op_or : public op_each_vvv<T, vec_op_or<T>> { 3749 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b) noexcept { return T(a | b); } 3750 }; 3751 3752 template<typename T> struct vec_op_xor : public op_each_vvv<T, vec_op_xor<T>> { 3753 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b) noexcept { return T(a ^ b); } 3754 }; 3755 3756 template<typename T> struct vec_op_andn : public op_each_vvv<T, vec_op_andn<T>> { 3757 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b) noexcept { return T(~a & b); } 3758 }; 3759 3760 template<typename T> struct vec_op_bic : public op_each_vvv<T, vec_op_bic<T>> { 3761 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b) noexcept { return T(a & ~b); } 3762 }; 3763 3764 template<typename T> struct vec_op_add : public op_each_vvv<T, vec_op_add<T>> { 3765 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b) noexcept { return T(cast_uint(a) + cast_uint(b)); } 3766 }; 3767 3768 template<typename T> struct vec_op_adds : public op_each_vvv<T, vec_op_adds<T>> { 3769 static ASMJIT_INLINE T apply_one(const T& a, const T& b) noexcept { 3770 Support::FastUInt8 of{}; 3771 T result = Support::add_overflow(a, b, &of); 3772 3773 if (!of) { 3774 return result; 3775 } 3776 3777 if constexpr (std::is_unsigned_v<T>) { 3778 return std::numeric_limits<T>::max(); 3779 } 3780 else { 3781 return b > T(0) ? std::numeric_limits<T>::max() : std::numeric_limits<T>::lowest(); 3782 } 3783 } 3784 }; 3785 3786 template<typename T> struct vec_op_sub : public op_each_vvv<T, vec_op_sub<T>> { 3787 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b) noexcept { return T(cast_uint(a) - cast_uint(b)); } 3788 }; 3789 3790 template<typename T> struct vec_op_subs : public op_each_vvv<T, vec_op_subs<T>> { 3791 static ASMJIT_INLINE T apply_one(const T& a, const T& b) noexcept { 3792 Support::FastUInt8 of{}; 3793 T result = Support::sub_overflow(a, b, &of); 3794 3795 if (!of) { 3796 return result; 3797 } 3798 3799 if constexpr (std::is_unsigned_v<T>) { 3800 return std::numeric_limits<T>::lowest(); 3801 } 3802 else { 3803 return b > T(0) ? std::numeric_limits<T>::lowest() : std::numeric_limits<T>::max(); 3804 } 3805 } 3806 }; 3807 3808 template<typename T> struct vec_op_mul : public op_each_vvv<T, vec_op_mul<T>> { 3809 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b) noexcept { return T((uint64_t(a) * uint64_t(b)) & uint64_t(~T(0))); } 3810 }; 3811 3812 template<typename T> struct vec_op_mulhi : public op_each_vvv<T, vec_op_mulhi<T>> { 3813 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b) noexcept { 3814 uint64_t result = uint64_t(int64_t(cast_int(a))) * uint64_t(int64_t(cast_int(b))); 3815 return T(T(result >> (sizeof(T) * 8u)) & T(~T(0))); 3816 } 3817 }; 3818 3819 template<typename T> struct vec_op_mulhu : public op_each_vvv<T, vec_op_mulhu<T>> { 3820 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b) noexcept { 3821 uint64_t result = uint64_t(a) * uint64_t(b); 3822 return T(result >> (sizeof(T) * 8u)) & uint64_t(~T(0)); 3823 } 3824 }; 3825 3826 struct vec_op_mul_u64_lo_u32 : public op_each_vvv<uint64_t, vec_op_mul_u64_lo_u32> { 3827 static ASMJIT_INLINE_NODEBUG uint64_t apply_one(const uint64_t& a, const uint64_t& b) noexcept { 3828 return uint64_t(a) * uint64_t(b & 0xFFFFFFFFu); 3829 } 3830 }; 3831 3832 struct vec_op_mhadd_i16_i32 : public op_each_vvv<uint32_t, vec_op_mhadd_i16_i32> { 3833 static ASMJIT_INLINE_NODEBUG uint32_t apply_one(const uint32_t& a, const uint32_t& b) noexcept { 3834 uint32_t al = uint32_t(int32_t(int16_t(a & 0xFFFF))); 3835 uint32_t ah = uint32_t(int32_t(int16_t(a >> 16))); 3836 3837 uint32_t bl = uint32_t(int32_t(int16_t(b & 0xFFFF))); 3838 uint32_t bh = uint32_t(int32_t(int16_t(b >> 16))); 3839 3840 return al * bl + ah * bh; 3841 } 3842 }; 3843 3844 template<typename T> struct vec_op_madd : public op_each_vvvv<T, vec_op_madd<T>> { 3845 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b, const T& c) noexcept { return T((uint64_t(a) * uint64_t(b) + uint64_t(c)) & uint64_t(~T(0))); } 3846 }; 3847 3848 template<typename T> struct vec_op_min : public op_each_vvv<T, vec_op_min<T>> { 3849 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b) noexcept { return a < b ? a : b; } 3850 }; 3851 3852 template<typename T> struct vec_op_max : public op_each_vvv<T, vec_op_max<T>> { 3853 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b) noexcept { return a > b ? a : b; } 3854 }; 3855 3856 template<typename T> struct vec_op_cmp_eq : public op_each_vvv<T, vec_op_cmp_eq<T>> { 3857 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b) noexcept { return a == b ? Support::bit_ones<T> : T(0); } 3858 }; 3859 3860 template<typename T> struct vec_op_cmp_ne : public op_each_vvv<T, vec_op_cmp_ne<T>> { 3861 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b) noexcept { return a != b ? Support::bit_ones<T> : T(0); } 3862 }; 3863 3864 template<typename T> struct vec_op_cmp_gt : public op_each_vvv<T, vec_op_cmp_gt<T>> { 3865 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b) noexcept { return a > b ? Support::bit_ones<T> : T(0); } 3866 }; 3867 3868 template<typename T> struct vec_op_cmp_ge : public op_each_vvv<T, vec_op_cmp_ge<T>> { 3869 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b) noexcept { return a >= b ? Support::bit_ones<T> : T(0); } 3870 }; 3871 3872 template<typename T> struct vec_op_cmp_lt : public op_each_vvv<T, vec_op_cmp_lt<T>> { 3873 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b) noexcept { return a < b ? Support::bit_ones<T> : T(0); } 3874 }; 3875 3876 template<typename T> struct vec_op_cmp_le : public op_each_vvv<T, vec_op_cmp_le<T>> { 3877 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b) noexcept { return a <= b ? Support::bit_ones<T> : T(0); } 3878 }; 3879 3880 template<ScalarOpBehavior kB, typename T> struct scalar_op_fadd : public op_scalar_vvv<kB, T, scalar_op_fadd<kB, T>> { 3881 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b) noexcept { return fadd(a, b); } 3882 }; 3883 3884 template<ScalarOpBehavior kB, typename T> struct scalar_op_fsub : public op_scalar_vvv<kB, T, scalar_op_fsub<kB, T>> { 3885 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b) noexcept { return fsub(a, b); } 3886 }; 3887 3888 template<ScalarOpBehavior kB, typename T> struct scalar_op_fmul : public op_scalar_vvv<kB, T, scalar_op_fmul<kB, T>> { 3889 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b) noexcept { return fmul(a, b); } 3890 }; 3891 3892 template<ScalarOpBehavior kB, typename T> struct scalar_op_fdiv : public op_scalar_vvv<kB, T, scalar_op_fdiv<kB, T>> { 3893 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b) noexcept { return fdiv(a, b); } 3894 }; 3895 3896 template<ScalarOpBehavior kB, typename T> struct scalar_op_fmin_ternary : public op_scalar_vvv<kB, T, scalar_op_fmin_ternary<kB, T>> { 3897 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b) noexcept { return a < b ? a : b; } 3898 }; 3899 3900 template<ScalarOpBehavior kB, typename T> struct scalar_op_fmax_ternary : public op_scalar_vvv<kB, T, scalar_op_fmax_ternary<kB, T>> { 3901 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b) noexcept { return a > b ? a : b; } 3902 }; 3903 3904 template<ScalarOpBehavior kB, typename T> struct scalar_op_fmin_finite : public op_scalar_vvv<kB, T, scalar_op_fmin_finite<kB, T>> { 3905 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b) noexcept { return std::isnan(a) ? b : std::isnan(b) ? a : Support::min(a, b); } 3906 }; 3907 3908 template<ScalarOpBehavior kB, typename T> struct scalar_op_fmax_finite : public op_scalar_vvv<kB, T, scalar_op_fmax_finite<kB, T>> { 3909 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b) noexcept { return std::isnan(a) ? b : std::isnan(b) ? a : Support::max(a, b); } 3910 }; 3911 3912 template<ScalarOpBehavior kB, typename T> struct scalar_op_fmadd_nofma : public op_scalar_vvvv<kB, T, scalar_op_fmadd_nofma<kB, T>> { 3913 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b, const T& c) noexcept { return fmadd_nofma_ref(a, b, c); } 3914 }; 3915 3916 template<ScalarOpBehavior kB, typename T> struct scalar_op_fmsub_nofma : public op_scalar_vvvv<kB, T, scalar_op_fmsub_nofma<kB, T>> { 3917 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b, const T& c) noexcept { return fmadd_nofma_ref(a, b, -c); } 3918 }; 3919 3920 template<ScalarOpBehavior kB, typename T> struct scalar_op_fnmadd_nofma : public op_scalar_vvvv<kB, T, scalar_op_fnmadd_nofma<kB, T>> { 3921 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b, const T& c) noexcept { return fmadd_nofma_ref(-a, b, c); } 3922 }; 3923 3924 template<ScalarOpBehavior kB, typename T> struct scalar_op_fnmsub_nofma : public op_scalar_vvvv<kB, T, scalar_op_fnmsub_nofma<kB, T>> { 3925 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b, const T& c) noexcept { return fmadd_nofma_ref(-a, b, -c); } 3926 }; 3927 3928 template<ScalarOpBehavior kB, typename T> struct scalar_op_fmadd_fma : public op_scalar_vvvv<kB, T, scalar_op_fmadd_fma<kB, T>> { 3929 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b, const T& c) noexcept { return fmadd_fma_ref(a, b, c); } 3930 }; 3931 3932 template<ScalarOpBehavior kB, typename T> struct scalar_op_fmsub_fma : public op_scalar_vvvv<kB, T, scalar_op_fmsub_fma<kB, T>> { 3933 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b, const T& c) noexcept { return fmadd_fma_ref(a, b, -c); } 3934 }; 3935 3936 template<ScalarOpBehavior kB, typename T> struct scalar_op_fnmadd_fma : public op_scalar_vvvv<kB, T, scalar_op_fnmadd_fma<kB, T>> { 3937 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b, const T& c) noexcept { return fmadd_fma_ref(-a, b, c); } 3938 }; 3939 3940 template<ScalarOpBehavior kB, typename T> struct scalar_op_fnmsub_fma : public op_scalar_vvvv<kB, T, scalar_op_fnmsub_fma<kB, T>> { 3941 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b, const T& c) noexcept { return fmadd_fma_ref(-a, b, -c); } 3942 }; 3943 3944 template<typename T> struct vec_op_fadd : public op_each_vvv<T, vec_op_fadd<T>> { 3945 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b) noexcept { return fadd(a, b); } 3946 }; 3947 3948 template<typename T> struct vec_op_fsub : public op_each_vvv<T, vec_op_fsub<T>> { 3949 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b) noexcept { return fsub(a, b); } 3950 }; 3951 3952 template<typename T> struct vec_op_fmul : public op_each_vvv<T, vec_op_fmul<T>> { 3953 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b) noexcept { return fmul(a, b); } 3954 }; 3955 3956 template<typename T> struct vec_op_fdiv : public op_each_vvv<T, vec_op_fdiv<T>> { 3957 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b) noexcept { return fdiv(a, b); } 3958 }; 3959 3960 template<typename T> struct vec_op_fmin_ternary : public op_each_vvv<T, vec_op_fmin_ternary<T>> { 3961 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b) noexcept { return a < b ? a : b; } 3962 }; 3963 3964 template<typename T> struct vec_op_fmax_ternary : public op_each_vvv<T, vec_op_fmax_ternary<T>> { 3965 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b) noexcept { return a > b ? a : b; } 3966 }; 3967 3968 template<typename T> struct vec_op_fmin_finite : public op_each_vvv<T, vec_op_fmin_finite<T>> { 3969 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b) noexcept { return std::isnan(a) ? b : std::isnan(b) ? a : Support::min(a, b); } 3970 }; 3971 3972 template<typename T> struct vec_op_fmax_finite : public op_each_vvv<T, vec_op_fmax_finite<T>> { 3973 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b) noexcept { return std::isnan(a) ? b : std::isnan(b) ? a : Support::max(a, b); } 3974 }; 3975 3976 template<typename T> struct vec_op_fmadd_nofma : public op_each_vvvv<T, vec_op_fmadd_nofma<T>> { 3977 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b, const T& c) noexcept { return fmadd_nofma_ref(a, b, c); } 3978 }; 3979 3980 template<typename T> struct vec_op_fmsub_nofma : public op_each_vvvv<T, vec_op_fmsub_nofma<T>> { 3981 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b, const T& c) noexcept { return fmadd_nofma_ref(a, b, -c); } 3982 }; 3983 3984 template<typename T> struct vec_op_fnmadd_nofma : public op_each_vvvv<T, vec_op_fnmadd_nofma<T>> { 3985 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b, const T& c) noexcept { return fmadd_nofma_ref(-a, b, c); } 3986 }; 3987 3988 template<typename T> struct vec_op_fnmsub_nofma : public op_each_vvvv<T, vec_op_fnmsub_nofma<T>> { 3989 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b, const T& c) noexcept { return fmadd_nofma_ref(-a, b, -c); } 3990 }; 3991 3992 template<typename T> struct vec_op_fmadd_fma : public op_each_vvvv<T, vec_op_fmadd_fma<T>> { 3993 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b, const T& c) noexcept { return fmadd_fma_ref(a, b, c); } 3994 }; 3995 3996 template<typename T> struct vec_op_fmsub_fma : public op_each_vvvv<T, vec_op_fmsub_fma<T>> { 3997 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b, const T& c) noexcept { return fmadd_fma_ref(a, b, -c); } 3998 }; 3999 4000 template<typename T> struct vec_op_fnmadd_fma : public op_each_vvvv<T, vec_op_fnmadd_fma<T>> { 4001 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b, const T& c) noexcept { return fmadd_fma_ref(-a, b, c); } 4002 }; 4003 4004 template<typename T> struct vec_op_fnmsub_fma : public op_each_vvvv<T, vec_op_fnmsub_fma<T>> { 4005 static ASMJIT_INLINE_NODEBUG T apply_one(const T& a, const T& b, const T& c) noexcept { return fmadd_fma_ref(-a, b, -c); } 4006 }; 4007 4008 template<typename T> 4009 struct cmp_result { 4010 typedef T Result; 4011 4012 static ASMJIT_INLINE_NODEBUG Result make(bool result) noexcept { return result ? Result(~Result(0)) : Result(0); } 4013 }; 4014 4015 template<> 4016 struct cmp_result<float> { 4017 typedef uint32_t Result; 4018 4019 static ASMJIT_INLINE_NODEBUG Result make(bool result) noexcept { return result ? ~Result(0) : Result(0); } 4020 }; 4021 4022 template<> 4023 struct cmp_result<double> { 4024 typedef uint64_t Result; 4025 4026 static ASMJIT_INLINE_NODEBUG Result make(bool result) noexcept { return result ? ~Result(0) : Result(0); } 4027 }; 4028 4029 template<typename T> struct vec_op_fcmpo_eq : public op_each_vvv<T, vec_op_fcmpo_eq<T>> { 4030 static ASMJIT_INLINE_NODEBUG typename cmp_result<T>::Result apply_one(const T& a, const T& b) noexcept { return cmp_result<T>::make(a == b); } 4031 }; 4032 4033 template<typename T> struct vec_op_fcmpu_ne : public op_each_vvv<T, vec_op_fcmpu_ne<T>> { 4034 static ASMJIT_INLINE_NODEBUG typename cmp_result<T>::Result apply_one(const T& a, const T& b) noexcept { return cmp_result<T>::make(!(a == b)); } 4035 }; 4036 4037 template<typename T> struct vec_op_fcmpo_gt : public op_each_vvv<T, vec_op_fcmpo_gt<T>> { 4038 static ASMJIT_INLINE_NODEBUG typename cmp_result<T>::Result apply_one(const T& a, const T& b) noexcept { return cmp_result<T>::make(a > b); } 4039 }; 4040 4041 template<typename T> struct vec_op_fcmpo_ge : public op_each_vvv<T, vec_op_fcmpo_ge<T>> { 4042 static ASMJIT_INLINE_NODEBUG typename cmp_result<T>::Result apply_one(const T& a, const T& b) noexcept { return cmp_result<T>::make(a >= b); } 4043 }; 4044 4045 template<typename T> struct vec_op_fcmpo_lt : public op_each_vvv<T, vec_op_fcmpo_lt<T>> { 4046 static ASMJIT_INLINE_NODEBUG typename cmp_result<T>::Result apply_one(const T& a, const T& b) noexcept { return cmp_result<T>::make(a < b); } 4047 }; 4048 4049 template<typename T> struct vec_op_fcmpo_le : public op_each_vvv<T, vec_op_fcmpo_le<T>> { 4050 static ASMJIT_INLINE_NODEBUG typename cmp_result<T>::Result apply_one(const T& a, const T& b) noexcept { return cmp_result<T>::make(a <= b); } 4051 }; 4052 4053 template<typename T> struct vec_op_fcmp_ord : public op_each_vvv<T, vec_op_fcmp_ord<T>> { 4054 static ASMJIT_INLINE_NODEBUG typename cmp_result<T>::Result apply_one(const T& a, const T& b) noexcept { return cmp_result<T>::make(!std::isnan(a) && !std::isnan(b)); } 4055 }; 4056 4057 template<typename T> struct vec_op_fcmp_unord : public op_each_vvv<T, vec_op_fcmp_unord<T>> { 4058 static ASMJIT_INLINE_NODEBUG typename cmp_result<T>::Result apply_one(const T& a, const T& b) noexcept { return cmp_result<T>::make(std::isnan(a) || std::isnan(b)); } 4059 }; 4060 4061 struct vec_op_hadd_f64 { 4062 template<uint32_t kW> 4063 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a, const VecOverlay<kW>& b) noexcept { 4064 VecOverlay<kW> out{}; 4065 for (uint32_t off = 0; off < kW; off += 16) { 4066 out.data_f64[off / 8 + 0] = a.data_f64[off / 8 + 0] + a.data_f64[off / 8 + 1]; 4067 out.data_f64[off / 8 + 1] = b.data_f64[off / 8 + 0] + b.data_f64[off / 8 + 1]; 4068 } 4069 return out; 4070 } 4071 }; 4072 4073 struct vec_op_combine_lo_hi_u64 { 4074 template<uint32_t kW> 4075 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a, const VecOverlay<kW>& b) noexcept { 4076 VecOverlay<kW> out{}; 4077 for (uint32_t off = 0; off < kW; off += 16) { 4078 out.data_u64[off / 8 + 0] = b.data_u64[off / 8 + 1]; 4079 out.data_u64[off / 8 + 1] = a.data_u64[off / 8 + 0]; 4080 } 4081 return out; 4082 } 4083 }; 4084 4085 struct vec_op_combine_hi_lo_u64 { 4086 template<uint32_t kW> 4087 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a, const VecOverlay<kW>& b) noexcept { 4088 VecOverlay<kW> out{}; 4089 for (uint32_t off = 0; off < kW; off += 16) { 4090 out.data_u64[off / 8 + 0] = b.data_u64[off / 8 + 0]; 4091 out.data_u64[off / 8 + 1] = a.data_u64[off / 8 + 1]; 4092 } 4093 return out; 4094 } 4095 }; 4096 4097 struct vec_op_interleave_lo_u8 { 4098 template<uint32_t kW> 4099 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a, const VecOverlay<kW>& b) noexcept { 4100 VecOverlay<kW> out{}; 4101 for (uint32_t off = 0; off < kW; off += 16) { 4102 for (uint32_t i = 0; i < 8; i++) { 4103 out.data_u8[off + i * 2 + 0] = a.data_u8[off + i]; 4104 out.data_u8[off + i * 2 + 1] = b.data_u8[off + i]; 4105 } 4106 } 4107 return out; 4108 } 4109 }; 4110 4111 struct vec_op_interleave_hi_u8 { 4112 template<uint32_t kW> 4113 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a, const VecOverlay<kW>& b) noexcept { 4114 VecOverlay<kW> out{}; 4115 for (uint32_t off = 0; off < kW; off += 16) { 4116 for (uint32_t i = 0; i < 8; i++) { 4117 out.data_u8[off + i * 2 + 0] = a.data_u8[off + 8 + i]; 4118 out.data_u8[off + i * 2 + 1] = b.data_u8[off + 8 + i]; 4119 } 4120 } 4121 return out; 4122 } 4123 }; 4124 4125 struct vec_op_interleave_lo_u16 { 4126 template<uint32_t kW> 4127 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a, const VecOverlay<kW>& b) noexcept { 4128 VecOverlay<kW> out{}; 4129 for (uint32_t off = 0; off < kW; off += 16) { 4130 for (uint32_t i = 0; i < 4; i++) { 4131 out.data_u16[off / 2 + i * 2 + 0] = a.data_u16[off / 2 + i]; 4132 out.data_u16[off / 2 + i * 2 + 1] = b.data_u16[off / 2 + i]; 4133 } 4134 } 4135 return out; 4136 } 4137 }; 4138 4139 struct vec_op_interleave_hi_u16 { 4140 template<uint32_t kW> 4141 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a, const VecOverlay<kW>& b) noexcept { 4142 VecOverlay<kW> out{}; 4143 for (uint32_t off = 0; off < kW; off += 16) { 4144 for (uint32_t i = 0; i < 4; i++) { 4145 out.data_u16[off / 2 + i * 2 + 0] = a.data_u16[off / 2 + 4 + i]; 4146 out.data_u16[off / 2 + i * 2 + 1] = b.data_u16[off / 2 + 4 + i]; 4147 } 4148 } 4149 return out; 4150 } 4151 }; 4152 4153 struct vec_op_interleave_lo_u32 { 4154 template<uint32_t kW> 4155 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a, const VecOverlay<kW>& b) noexcept { 4156 VecOverlay<kW> out{}; 4157 for (uint32_t off = 0; off < kW; off += 16) { 4158 for (uint32_t i = 0; i < 2; i++) { 4159 out.data_u32[off / 4 + i * 2 + 0] = a.data_u32[off / 4 + i]; 4160 out.data_u32[off / 4 + i * 2 + 1] = b.data_u32[off / 4 + i]; 4161 } 4162 } 4163 return out; 4164 } 4165 }; 4166 4167 struct vec_op_interleave_hi_u32 { 4168 template<uint32_t kW> 4169 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a, const VecOverlay<kW>& b) noexcept { 4170 VecOverlay<kW> out{}; 4171 for (uint32_t off = 0; off < kW; off += 16) { 4172 for (uint32_t i = 0; i < 2; i++) { 4173 out.data_u32[off / 4 + i * 2 + 0] = a.data_u32[off / 4 + 2 + i]; 4174 out.data_u32[off / 4 + i * 2 + 1] = b.data_u32[off / 4 + 2 + i]; 4175 } 4176 } 4177 return out; 4178 } 4179 }; 4180 4181 struct vec_op_interleave_lo_u64 { 4182 template<uint32_t kW> 4183 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a, const VecOverlay<kW>& b) noexcept { 4184 VecOverlay<kW> out{}; 4185 for (uint32_t off = 0; off < kW; off += 16) { 4186 out.data_u64[off / 8 + 0] = a.data_u64[off / 8 + 0]; 4187 out.data_u64[off / 8 + 1] = b.data_u64[off / 8 + 0]; 4188 } 4189 return out; 4190 } 4191 }; 4192 4193 struct vec_op_interleave_hi_u64 { 4194 template<uint32_t kW> 4195 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a, const VecOverlay<kW>& b) noexcept { 4196 VecOverlay<kW> out{}; 4197 for (uint32_t off = 0; off < kW; off += 16) { 4198 out.data_u64[off / 8 + 0] = a.data_u64[off / 8 + 1]; 4199 out.data_u64[off / 8 + 1] = b.data_u64[off / 8 + 1]; 4200 } 4201 return out; 4202 } 4203 }; 4204 4205 // ujit::UniCompiler - Tests - SIMD - Generic Operations - VVVI 4206 // ============================================================ 4207 4208 struct vec_op_alignr_u128 { 4209 template<uint32_t kW> 4210 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a, const VecOverlay<kW>& b, uint32_t imm) noexcept { 4211 VecOverlay<kW> out{}; 4212 for (uint32_t off = 0; off < kW; off += 16) { 4213 for (uint32_t i = 0; i < 16; i++) { 4214 out.data_u8[off + i] = i + imm < 16 ? b.data_u8[off + i + imm] : a.data_u8[off + i + imm - 16]; 4215 } 4216 } 4217 return out; 4218 } 4219 }; 4220 4221 struct vec_op_interleave_shuffle_u32x4 { 4222 template<uint32_t kW> 4223 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a, const VecOverlay<kW>& b, uint32_t imm) noexcept { 4224 uint32_t D = (imm >> 24) & 0x3; 4225 uint32_t C = (imm >> 16) & 0x3; 4226 uint32_t B = (imm >> 8) & 0x3; 4227 uint32_t A = (imm >> 0) & 0x3; 4228 4229 VecOverlay<kW> out{}; 4230 for (uint32_t off = 0; off < kW; off += 16) { 4231 out.data_u32[off / 4 + 0] = a.data_u32[off / 4 + A]; 4232 out.data_u32[off / 4 + 1] = a.data_u32[off / 4 + B]; 4233 out.data_u32[off / 4 + 2] = b.data_u32[off / 4 + C]; 4234 out.data_u32[off / 4 + 3] = b.data_u32[off / 4 + D]; 4235 } 4236 return out; 4237 } 4238 }; 4239 4240 struct vec_op_interleave_shuffle_u64x2 { 4241 template<uint32_t kW> 4242 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a, const VecOverlay<kW>& b, uint32_t imm) noexcept { 4243 uint32_t B = (imm >> 8) & 0x1; 4244 uint32_t A = (imm >> 0) & 0x1; 4245 4246 VecOverlay<kW> out{}; 4247 for (uint32_t off = 0; off < kW; off += 16) { 4248 out.data_u64[off / 8 + 0] = a.data_u64[off / 8 + A]; 4249 out.data_u64[off / 8 + 1] = b.data_u64[off / 8 + B]; 4250 } 4251 return out; 4252 } 4253 }; 4254 4255 struct vec_op_packs_i16_i8 { 4256 template<uint32_t kW> 4257 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a, const VecOverlay<kW>& b) noexcept { 4258 VecOverlay<kW> out{}; 4259 for (uint32_t off = 0; off < kW; off += 16) { 4260 out.data_i8[off + 0] = saturate_i16_to_i8(a.data_i16[off / 2 + 0]); 4261 out.data_i8[off + 1] = saturate_i16_to_i8(a.data_i16[off / 2 + 1]); 4262 out.data_i8[off + 2] = saturate_i16_to_i8(a.data_i16[off / 2 + 2]); 4263 out.data_i8[off + 3] = saturate_i16_to_i8(a.data_i16[off / 2 + 3]); 4264 out.data_i8[off + 4] = saturate_i16_to_i8(a.data_i16[off / 2 + 4]); 4265 out.data_i8[off + 5] = saturate_i16_to_i8(a.data_i16[off / 2 + 5]); 4266 out.data_i8[off + 6] = saturate_i16_to_i8(a.data_i16[off / 2 + 6]); 4267 out.data_i8[off + 7] = saturate_i16_to_i8(a.data_i16[off / 2 + 7]); 4268 out.data_i8[off + 8] = saturate_i16_to_i8(b.data_i16[off / 2 + 0]); 4269 out.data_i8[off + 9] = saturate_i16_to_i8(b.data_i16[off / 2 + 1]); 4270 out.data_i8[off + 10] = saturate_i16_to_i8(b.data_i16[off / 2 + 2]); 4271 out.data_i8[off + 11] = saturate_i16_to_i8(b.data_i16[off / 2 + 3]); 4272 out.data_i8[off + 12] = saturate_i16_to_i8(b.data_i16[off / 2 + 4]); 4273 out.data_i8[off + 13] = saturate_i16_to_i8(b.data_i16[off / 2 + 5]); 4274 out.data_i8[off + 14] = saturate_i16_to_i8(b.data_i16[off / 2 + 6]); 4275 out.data_i8[off + 15] = saturate_i16_to_i8(b.data_i16[off / 2 + 7]); 4276 } 4277 return out; 4278 } 4279 }; 4280 4281 struct vec_op_packs_i16_u8 { 4282 template<uint32_t kW> 4283 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a, const VecOverlay<kW>& b) noexcept { 4284 VecOverlay<kW> out{}; 4285 for (uint32_t off = 0; off < kW; off += 16) { 4286 out.data_u8[off + 0] = saturate_i16_to_u8(a.data_i16[off / 2 + 0]); 4287 out.data_u8[off + 1] = saturate_i16_to_u8(a.data_i16[off / 2 + 1]); 4288 out.data_u8[off + 2] = saturate_i16_to_u8(a.data_i16[off / 2 + 2]); 4289 out.data_u8[off + 3] = saturate_i16_to_u8(a.data_i16[off / 2 + 3]); 4290 out.data_u8[off + 4] = saturate_i16_to_u8(a.data_i16[off / 2 + 4]); 4291 out.data_u8[off + 5] = saturate_i16_to_u8(a.data_i16[off / 2 + 5]); 4292 out.data_u8[off + 6] = saturate_i16_to_u8(a.data_i16[off / 2 + 6]); 4293 out.data_u8[off + 7] = saturate_i16_to_u8(a.data_i16[off / 2 + 7]); 4294 out.data_u8[off + 8] = saturate_i16_to_u8(b.data_i16[off / 2 + 0]); 4295 out.data_u8[off + 9] = saturate_i16_to_u8(b.data_i16[off / 2 + 1]); 4296 out.data_u8[off + 10] = saturate_i16_to_u8(b.data_i16[off / 2 + 2]); 4297 out.data_u8[off + 11] = saturate_i16_to_u8(b.data_i16[off / 2 + 3]); 4298 out.data_u8[off + 12] = saturate_i16_to_u8(b.data_i16[off / 2 + 4]); 4299 out.data_u8[off + 13] = saturate_i16_to_u8(b.data_i16[off / 2 + 5]); 4300 out.data_u8[off + 14] = saturate_i16_to_u8(b.data_i16[off / 2 + 6]); 4301 out.data_u8[off + 15] = saturate_i16_to_u8(b.data_i16[off / 2 + 7]); 4302 } 4303 return out; 4304 } 4305 }; 4306 4307 struct vec_op_packs_i32_i16 { 4308 template<uint32_t kW> 4309 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a, const VecOverlay<kW>& b) noexcept { 4310 VecOverlay<kW> out{}; 4311 for (uint32_t off = 0; off < kW; off += 16) { 4312 out.data_i16[off / 2 + 0] = saturate_i32_to_i16(a.data_i32[off / 4 + 0]); 4313 out.data_i16[off / 2 + 1] = saturate_i32_to_i16(a.data_i32[off / 4 + 1]); 4314 out.data_i16[off / 2 + 2] = saturate_i32_to_i16(a.data_i32[off / 4 + 2]); 4315 out.data_i16[off / 2 + 3] = saturate_i32_to_i16(a.data_i32[off / 4 + 3]); 4316 out.data_i16[off / 2 + 4] = saturate_i32_to_i16(b.data_i32[off / 4 + 0]); 4317 out.data_i16[off / 2 + 5] = saturate_i32_to_i16(b.data_i32[off / 4 + 1]); 4318 out.data_i16[off / 2 + 6] = saturate_i32_to_i16(b.data_i32[off / 4 + 2]); 4319 out.data_i16[off / 2 + 7] = saturate_i32_to_i16(b.data_i32[off / 4 + 3]); 4320 } 4321 return out; 4322 } 4323 }; 4324 4325 struct vec_op_packs_i32_u16 { 4326 template<uint32_t kW> 4327 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a, const VecOverlay<kW>& b) noexcept { 4328 VecOverlay<kW> out{}; 4329 for (uint32_t off = 0; off < kW; off += 16) { 4330 out.data_u16[off / 2 + 0] = saturate_i32_to_u16(a.data_i32[off / 4 + 0]); 4331 out.data_u16[off / 2 + 1] = saturate_i32_to_u16(a.data_i32[off / 4 + 1]); 4332 out.data_u16[off / 2 + 2] = saturate_i32_to_u16(a.data_i32[off / 4 + 2]); 4333 out.data_u16[off / 2 + 3] = saturate_i32_to_u16(a.data_i32[off / 4 + 3]); 4334 out.data_u16[off / 2 + 4] = saturate_i32_to_u16(b.data_i32[off / 4 + 0]); 4335 out.data_u16[off / 2 + 5] = saturate_i32_to_u16(b.data_i32[off / 4 + 1]); 4336 out.data_u16[off / 2 + 6] = saturate_i32_to_u16(b.data_i32[off / 4 + 2]); 4337 out.data_u16[off / 2 + 7] = saturate_i32_to_u16(b.data_i32[off / 4 + 3]); 4338 } 4339 return out; 4340 } 4341 }; 4342 4343 // ujit::UniCompiler - Tests - SIMD - Generic Operations - VVVV 4344 // ============================================================ 4345 4346 struct vec_op_blendv_bits : public op_each_vvvv<uint32_t, vec_op_blendv_bits> { 4347 static ASMJIT_INLINE_NODEBUG uint32_t apply_one(const uint32_t& a, const uint32_t& b, const uint32_t& c) noexcept { return ((a & ~c) | (b & c)); } 4348 }; 4349 4350 struct vec_op_swizzlev_u8 { 4351 template<uint32_t kW> 4352 static ASMJIT_INLINE VecOverlay<kW> apply(const VecOverlay<kW>& a, const VecOverlay<kW>& b) noexcept { 4353 VecOverlay<kW> out{}; 4354 for (uint32_t off = 0; off < kW; off += 16) { 4355 for (uint32_t i = 0; i < 16; i++) { 4356 size_t sel = b.data_u8[off + i] & (0x8F); // 3 bits ignored. 4357 out.data_u8[off + i] = sel & 0x80 ? uint8_t(0) : a.data_u8[off + sel]; 4358 } 4359 } 4360 return out; 4361 } 4362 }; 4363 4364 struct vec_op_div255_u16 : public op_each_vv<uint16_t, vec_op_div255_u16> { 4365 static ASMJIT_INLINE uint16_t apply_one(const uint16_t& a) noexcept { 4366 uint32_t x = a + 0x80u; 4367 return uint16_t((x + (x >> 8)) >> 8); 4368 } 4369 }; 4370 4371 struct vec_op_div65535_u32 : public op_each_vv<uint32_t, vec_op_div65535_u32> { 4372 static ASMJIT_INLINE uint32_t apply_one(const uint32_t& a) noexcept { 4373 uint32_t x = a + 0x8000u; 4374 return uint32_t((x + (x >> 16)) >> 16); 4375 } 4376 }; 4377 4378 // ujit::UniCompiler - Tests - SIMD - Utilities 4379 // ============================================ 4380 4381 template<uint32_t kW> 4382 static void fill_random_bytes(DataGenInt& dg, VecOverlay<kW>& dst) noexcept { 4383 for (uint32_t i = 0; i < kW / 8u; i++) { 4384 dst.data_u64[i] = dg.next_uint64(); 4385 } 4386 } 4387 4388 template<uint32_t kW> 4389 static void fill_random_f32(DataGenInt& dg, VecOverlay<kW>& dst) noexcept { 4390 for (uint32_t i = 0; i < kW / 4u; i++) { 4391 dst.data_f32[i] = dg.next_float32(); 4392 } 4393 } 4394 4395 template<uint32_t kW> 4396 static void fill_random_f64(DataGenInt& dg, VecOverlay<kW>& dst) noexcept { 4397 for (uint32_t i = 0; i < kW / 8u; i++) { 4398 dst.data_f64[i] = dg.next_float64(); 4399 } 4400 } 4401 4402 template<uint32_t kW> 4403 static void fill_random_data(DataGenInt& dg, VecOverlay<kW>& dst, VecElementType element_type) noexcept { 4404 switch (element_type) { 4405 case VecElementType::kFloat32: 4406 fill_random_f32(dg, dst); 4407 break; 4408 4409 case VecElementType::kFloat64: 4410 fill_random_f64(dg, dst); 4411 break; 4412 4413 default: 4414 fill_random_bytes(dg, dst); 4415 break; 4416 } 4417 } 4418 4419 // ujit::UniCompiler - Tests - SIMD - Verification 4420 // =============================================== 4421 4422 template<uint32_t kW> 4423 static ASMJIT_NOINLINE void test_vecop_vv_failed(UniOpVV op, Variation variation, const VecOverlay<kW>& arg0, const VecOverlay<kW>& observed, const VecOverlay<kW>& expected, const char* assembly) noexcept { 4424 VecOpInfo op_info = vec_op_info_vv(op); 4425 4426 String arg0_str = vec_stringify(arg0, op_info.arg(0)); 4427 String observed_str = vec_stringify(observed, op_info.ret()); 4428 String expected_str = vec_stringify(expected, op_info.ret()); 4429 4430 EXPECT(false) 4431 .message("Operation '%s' (variation %u) failed:\n" 4432 " Input #0: %s\n" 4433 " Expected: %s\n" 4434 " Observed: %s\n" 4435 "Assembly:\n%s", 4436 vec_op_name_vv(op), 4437 variation.value, 4438 arg0_str.data(), 4439 expected_str.data(), 4440 observed_str.data(), 4441 assembly); 4442 } 4443 4444 template<uint32_t kW> 4445 static ASMJIT_NOINLINE void test_vecop_vvi_failed(UniOpVVI op, Variation variation, const VecOverlay<kW>& arg0, const VecOverlay<kW>& observed, const VecOverlay<kW>& expected, uint32_t imm, const char* assembly) noexcept { 4446 VecOpInfo op_info = vec_op_info_vvi(op); 4447 4448 String arg0_str = vec_stringify(arg0, op_info.arg(0)); 4449 String observed_str = vec_stringify(observed, op_info.ret()); 4450 String expected_str = vec_stringify(expected, op_info.ret()); 4451 4452 EXPECT(false) 4453 .message("Operation '%s' (variation %u) failed:\n" 4454 " Input #0: %s\n" 4455 " ImmValue: %u (0x%08X)\n" 4456 " Expected: %s\n" 4457 " Observed: %s\n" 4458 "Assembly:\n%s", 4459 vec_op_name_vvi(op), 4460 variation.value, 4461 arg0_str.data(), 4462 imm, imm, 4463 expected_str.data(), 4464 observed_str.data(), 4465 assembly); 4466 } 4467 4468 template<uint32_t kW> 4469 static ASMJIT_NOINLINE void test_vecop_vvv_failed(UniOpVVV op, Variation variation, const VecOverlay<kW>& arg0, const VecOverlay<kW>& arg1, const VecOverlay<kW>& observed, const VecOverlay<kW>& expected, const char* assembly) noexcept { 4470 VecOpInfo op_info = vec_op_info_vvv(op); 4471 4472 String arg0_str = vec_stringify(arg0, op_info.arg(0)); 4473 String arg1_str = vec_stringify(arg1, op_info.arg(1)); 4474 String observed_str = vec_stringify(observed, op_info.ret()); 4475 String expected_str = vec_stringify(expected, op_info.ret()); 4476 4477 EXPECT(false) 4478 .message("Operation '%s' (variation %u) failed:\n" 4479 " Input #0: %s\n" 4480 " Input #1: %s\n" 4481 " Expected: %s\n" 4482 " Observed: %s\n" 4483 "Assembly:\n%s", 4484 vec_op_name_vvv(op), 4485 variation.value, 4486 arg0_str.data(), 4487 arg1_str.data(), 4488 expected_str.data(), 4489 observed_str.data(), 4490 assembly); 4491 } 4492 4493 template<uint32_t kW> 4494 static ASMJIT_NOINLINE void test_vecop_vvvi_failed(UniOpVVVI op, Variation variation, const VecOverlay<kW>& arg0, const VecOverlay<kW>& arg1, const VecOverlay<kW>& observed, const VecOverlay<kW>& expected, uint32_t imm, const char* assembly) noexcept { 4495 VecOpInfo op_info = vec_op_info_vvvi(op); 4496 4497 String arg0_str = vec_stringify(arg0, op_info.arg(0)); 4498 String arg1_str = vec_stringify(arg1, op_info.arg(1)); 4499 String observed_str = vec_stringify(observed, op_info.ret()); 4500 String expected_str = vec_stringify(expected, op_info.ret()); 4501 4502 EXPECT(false) 4503 .message("Operation '%s' (variation %u) failed:\n" 4504 " Input #1: %s\n" 4505 " Input #2: %s\n" 4506 " ImmValue: %u (0x%08X)\n" 4507 " Expected: %s\n" 4508 " Observed: %s\n" 4509 "Assembly:\n%s", 4510 vec_op_name_vvvi(op), 4511 variation.value, 4512 arg0_str.data(), 4513 arg1_str.data(), 4514 imm, imm, 4515 expected_str.data(), 4516 observed_str.data(), 4517 assembly); 4518 } 4519 4520 template<uint32_t kW> 4521 static ASMJIT_NOINLINE void test_vecop_vvvv_failed(UniOpVVVV op, Variation variation, const VecOverlay<kW>& arg0, const VecOverlay<kW>& arg1, const VecOverlay<kW>& arg2, const VecOverlay<kW>& observed, const VecOverlay<kW>& expected, const char* assembly) noexcept { 4522 VecOpInfo op_info = vec_op_info_vvvv(op); 4523 4524 String arg0_str = vec_stringify(arg0, op_info.arg(0)); 4525 String arg1_str = vec_stringify(arg1, op_info.arg(1)); 4526 String arg2_str = vec_stringify(arg2, op_info.arg(2)); 4527 String observed_str = vec_stringify(observed, op_info.ret()); 4528 String expected_str = vec_stringify(expected, op_info.ret()); 4529 4530 EXPECT(false) 4531 .message("Operation '%s' (variation %u) failed\n" 4532 " Input #1: %s\n" 4533 " Input #2: %s\n" 4534 " Input #3: %s\n" 4535 " Expected: %s\n" 4536 " Observed: %s\n" 4537 "Assembly:\n%s", 4538 vec_op_name_vvvv(op), 4539 variation.value, 4540 arg0_str.data(), 4541 arg1_str.data(), 4542 arg2_str.data(), 4543 expected_str.data(), 4544 observed_str.data(), 4545 assembly); 4546 } 4547 4548 // ujit::UniCompiler - Tests - Integer Operations - VV 4549 // =================================================== 4550 4551 template<VecWidth kVecWidth, UniOpVV kOp, typename GenericOp, typename Constraint> 4552 static ASMJIT_NOINLINE void test_vecop_vv_constraint(JitContext& ctx, Variation variation = Variation{0}) { 4553 constexpr uint32_t kW = byte_width_from_vec_width(kVecWidth); 4554 4555 TestVVFunc compiled_apply = create_func_vv(ctx, kVecWidth, kOp, variation); 4556 DataGenInt dg(kRandomSeed); 4557 4558 VecOpInfo op_info = vec_op_info_vv(kOp); 4559 4560 for (uint32_t iter = 0; iter < kTestIterCount; iter++) { 4561 VecOverlay<kW> a {}; 4562 VecOverlay<kW> observed {}; 4563 VecOverlay<kW> expected {}; 4564 4565 fill_random_data(dg, a, op_info.arg(0)); 4566 Constraint::apply(a); 4567 4568 compiled_apply(&observed, &a); 4569 expected = GenericOp::apply(a); 4570 4571 if (!vec_eq(observed, expected, op_info.ret())) { 4572 test_vecop_vv_failed(kOp, variation, a, observed, expected, ctx.logger_content()); 4573 } 4574 } 4575 4576 ctx.rt.release(compiled_apply); 4577 } 4578 4579 template<VecWidth kVecWidth, UniOpVV kOp, typename GenericOp> 4580 static void test_vecop_vv(JitContext& ctx, Variation variation = Variation{0}) { 4581 return test_vecop_vv_constraint<kVecWidth, kOp, GenericOp, ConstraintNone>(ctx, variation); 4582 } 4583 4584 // ujit::UniCompiler - Tests - SIMD - Integer Operations - VVI 4585 // =========================================================== 4586 4587 template<VecWidth kVecWidth, UniOpVVI kOp, typename GenericOp, typename Constraint> 4588 static ASMJIT_NOINLINE void test_vecop_vvi_constraint(JitContext& ctx, uint32_t imm, Variation variation = Variation{0}) { 4589 constexpr uint32_t kW = byte_width_from_vec_width(kVecWidth); 4590 4591 TestVVFunc compiled_apply = create_func_vvi(ctx, kVecWidth, kOp, imm, variation); 4592 DataGenInt dg(kRandomSeed); 4593 4594 VecOpInfo op_info = vec_op_info_vvi(kOp); 4595 4596 for (uint32_t iter = 0; iter < kTestIterCount; iter++) { 4597 VecOverlay<kW> a {}; 4598 VecOverlay<kW> observed {}; 4599 VecOverlay<kW> expected {}; 4600 4601 fill_random_data(dg, a, op_info.arg(0)); 4602 Constraint::apply(a); 4603 4604 compiled_apply(&observed, &a); 4605 expected = GenericOp::apply(a, imm); 4606 4607 if (!vec_eq(observed, expected, op_info.ret())) { 4608 test_vecop_vvi_failed(kOp, variation, a, observed, expected, imm, ctx.logger_content()); 4609 } 4610 } 4611 4612 ctx.rt.release(compiled_apply); 4613 } 4614 4615 template<VecWidth kVecWidth, UniOpVVI kOp, typename GenericOp> 4616 static void test_vecop_vvi(JitContext& ctx, uint32_t imm, Variation variation = Variation{0}) { 4617 return test_vecop_vvi_constraint<kVecWidth, kOp, GenericOp, ConstraintNone>(ctx, imm, variation); 4618 } 4619 4620 // ujit::UniCompiler - Tests - SIMD - Integer Operations - VVV 4621 // =========================================================== 4622 4623 template<VecWidth kVecWidth, UniOpVVV kOp, typename GenericOp, typename Constraint> 4624 static ASMJIT_NOINLINE void test_vecop_vvv_constraint(JitContext& ctx, Variation variation = Variation{0}) { 4625 constexpr uint32_t kW = byte_width_from_vec_width(kVecWidth); 4626 4627 TestVVVFunc compiled_apply = create_func_vvv(ctx, kVecWidth, kOp, variation); 4628 DataGenInt dg(kRandomSeed); 4629 4630 VecOpInfo op_info = vec_op_info_vvv(kOp); 4631 4632 for (uint32_t iter = 0; iter < kTestIterCount; iter++) { 4633 VecOverlay<kW> a {}; 4634 VecOverlay<kW> b {}; 4635 VecOverlay<kW> observed {}; 4636 VecOverlay<kW> expected {}; 4637 4638 fill_random_data(dg, a, op_info.arg(0)); 4639 fill_random_data(dg, b, op_info.arg(1)); 4640 Constraint::apply(a); 4641 Constraint::apply(b); 4642 4643 compiled_apply(&observed, &a, &b); 4644 expected = GenericOp::apply(a, b); 4645 4646 if (!vec_eq(observed, expected, op_info.ret())) { 4647 test_vecop_vvv_failed(kOp, variation, a, b, observed, expected, ctx.logger_content()); 4648 } 4649 } 4650 4651 ctx.rt.release(compiled_apply); 4652 } 4653 4654 template<VecWidth kVecWidth, UniOpVVV kOp, typename GenericOp> 4655 static void test_vecop_vvv(JitContext& ctx, Variation variation = Variation{0}) { 4656 return test_vecop_vvv_constraint<kVecWidth, kOp, GenericOp, ConstraintNone>(ctx, variation); 4657 } 4658 4659 // ujit::UniCompiler - Tests - SIMD - Integer Operations - VVVI 4660 // ============================================================ 4661 4662 template<VecWidth kVecWidth, UniOpVVVI kOp, typename GenericOp, typename Constraint> 4663 static ASMJIT_NOINLINE void test_vecop_vvvi_constraint(JitContext& ctx, uint32_t imm, Variation variation = Variation{0}) { 4664 constexpr uint32_t kW = byte_width_from_vec_width(kVecWidth); 4665 4666 TestVVVFunc compiled_apply = create_func_vvvi(ctx, kVecWidth, kOp, imm, variation); 4667 DataGenInt dg(kRandomSeed); 4668 4669 VecOpInfo op_info = vec_op_info_vvvi(kOp); 4670 4671 for (uint32_t iter = 0; iter < kTestIterCount; iter++) { 4672 VecOverlay<kW> a {}; 4673 VecOverlay<kW> b {}; 4674 VecOverlay<kW> observed {}; 4675 VecOverlay<kW> expected {}; 4676 4677 fill_random_data(dg, a, op_info.arg(0)); 4678 fill_random_data(dg, b, op_info.arg(1)); 4679 Constraint::apply(a); 4680 Constraint::apply(b); 4681 4682 compiled_apply(&observed, &a, &b); 4683 expected = GenericOp::apply(a, b, imm); 4684 4685 if (!vec_eq(observed, expected, op_info.ret())) { 4686 test_vecop_vvvi_failed(kOp, variation, a, b, observed, expected, imm, ctx.logger_content()); 4687 } 4688 } 4689 4690 ctx.rt.release(compiled_apply); 4691 } 4692 4693 template<VecWidth kVecWidth, UniOpVVVI kOp, typename GenericOp> 4694 static void test_vecop_vvvi(JitContext& ctx, uint32_t imm, Variation variation = Variation{0}) { 4695 return test_vecop_vvvi_constraint<kVecWidth, kOp, GenericOp, ConstraintNone>(ctx, imm, variation); 4696 } 4697 4698 // ujit::UniCompiler - Tests - SIMD - Integer Operations - VVVV 4699 // ============================================================ 4700 4701 template<VecWidth kVecWidth, UniOpVVVV kOp, typename GenericOp, typename Constraint> 4702 static ASMJIT_NOINLINE void test_vecop_vvvv_constraint(JitContext& ctx, Variation variation = Variation{0}) { 4703 constexpr uint32_t kW = byte_width_from_vec_width(kVecWidth); 4704 4705 TestVVVVFunc compiled_apply = create_func_vvvv(ctx, kVecWidth, kOp, variation); 4706 DataGenInt dg(kRandomSeed); 4707 4708 VecOpInfo op_info = vec_op_info_vvvv(kOp); 4709 4710 for (uint32_t iter = 0; iter < kTestIterCount; iter++) { 4711 VecOverlay<kW> a {}; 4712 VecOverlay<kW> b {}; 4713 VecOverlay<kW> c {}; 4714 VecOverlay<kW> observed {}; 4715 VecOverlay<kW> expected {}; 4716 4717 fill_random_data(dg, a, op_info.arg(0)); 4718 fill_random_data(dg, b, op_info.arg(1)); 4719 fill_random_data(dg, c, op_info.arg(2)); 4720 Constraint::apply(a); 4721 Constraint::apply(b); 4722 Constraint::apply(c); 4723 4724 compiled_apply(&observed, &a, &b, &c); 4725 expected = GenericOp::apply(a, b, c); 4726 4727 if (!vec_eq(observed, expected, op_info.ret())) { 4728 test_vecop_vvvv_failed(kOp, variation, a, b, c, observed, expected, ctx.logger_content()); 4729 } 4730 } 4731 } 4732 4733 template<VecWidth kVecWidth, UniOpVVVV kOp, typename GenericOp> 4734 static void test_vecop_vvvv(JitContext& ctx, Variation variation = Variation{0}) { 4735 return test_vecop_vvvv_constraint<kVecWidth, kOp, GenericOp, ConstraintNone>(ctx, variation); 4736 } 4737 4738 // ujit::UniCompiler - Tests - SIMD - Runner 4739 // ========================================= 4740 4741 template<VecWidth kVecWidth> 4742 static ASMJIT_NOINLINE void test_simd_ops(JitContext& ctx) { 4743 // We need to know some behaviors in advance so we can select the right test function, 4744 // so create a dummy compiler and extract the necessary information from it. 4745 ScalarOpBehavior scalar_op_behavior {}; 4746 FMAddOpBehavior fmadd_op_behavior {}; 4747 FloatToIntOutsideRangeBehavior float_to_int_behavior {}; 4748 4749 { 4750 ctx.prepare(); 4751 UniCompiler uc(&ctx.cc, ctx.features, ctx.cpu_hints); 4752 4753 scalar_op_behavior = uc.scalar_op_behavior(); 4754 fmadd_op_behavior = uc.fmadd_op_behavior(); 4755 float_to_int_behavior = uc.float_to_int_outside_range_behavior(); 4756 } 4757 4758 bool valgrind_fma_bug = false; 4759 4760 #if defined(ASMJIT_UJIT_X86) 4761 // When running under valgrind there is a bug in its instrumentation of FMA SS/SD instructions. 4762 // Instead of keeping the unaffected elements in the destination register they are cleared instead, 4763 // which would cause test failures. So, detect whether we are running under Valgind that has this 4764 // bug and avoid scalar FMA tests in that case. 4765 if (fmadd_op_behavior != FMAddOpBehavior::kNoFMA) { 4766 float a[4] = { 1, 2, 3, 4 }; 4767 float b[4] = { 2, 4, 8, 1 }; 4768 float c[4] = { 4, 7, 3, 9 }; 4769 4770 float d[4] {}; 4771 madd_fma_check_valgrind_bug(a, b, c, d); 4772 4773 valgrind_fma_bug = d[1] == 0.0f; 4774 } 4775 #endif // ASMJIT_UJIT_X86 4776 4777 INFO(" Testing mov"); 4778 { 4779 test_vecop_vv<kVecWidth, UniOpVV::kMov, vec_op_mov>(ctx); 4780 test_vecop_vv<kVecWidth, UniOpVV::kMovU64, vec_op_mov_u64>(ctx); 4781 } 4782 4783 INFO(" Testing broadcast"); 4784 { 4785 // Test all broadcasts - vector based, GP to vector, and memory to vector. 4786 for (uint32_t v = 0; v < kNumVariationsVV_Broadcast; v++) { 4787 test_vecop_vv<kVecWidth, UniOpVV::kBroadcastU8Z, vec_op_broadcast_u8>(ctx, Variation{v}); 4788 test_vecop_vv<kVecWidth, UniOpVV::kBroadcastU16Z, vec_op_broadcast_u16>(ctx, Variation{v}); 4789 test_vecop_vv<kVecWidth, UniOpVV::kBroadcastU8, vec_op_broadcast_u8>(ctx, Variation{v}); 4790 test_vecop_vv<kVecWidth, UniOpVV::kBroadcastU16, vec_op_broadcast_u16>(ctx, Variation{v}); 4791 test_vecop_vv<kVecWidth, UniOpVV::kBroadcastU32, vec_op_broadcast_u32>(ctx, Variation{v}); 4792 test_vecop_vv<kVecWidth, UniOpVV::kBroadcastU64, vec_op_broadcast_u64>(ctx, Variation{v}); 4793 test_vecop_vv<kVecWidth, UniOpVV::kBroadcastF32, vec_op_broadcast_u32>(ctx, Variation{v}); 4794 test_vecop_vv<kVecWidth, UniOpVV::kBroadcastF64, vec_op_broadcast_u64>(ctx, Variation{v}); 4795 4796 test_vecop_vv<kVecWidth, UniOpVV::kBroadcastV128_U32, vec_op_broadcast_u128>(ctx, Variation{v}); 4797 test_vecop_vv<kVecWidth, UniOpVV::kBroadcastV128_U64, vec_op_broadcast_u128>(ctx, Variation{v}); 4798 test_vecop_vv<kVecWidth, UniOpVV::kBroadcastV128_F32, vec_op_broadcast_u128>(ctx, Variation{v}); 4799 test_vecop_vv<kVecWidth, UniOpVV::kBroadcastV128_F64, vec_op_broadcast_u128>(ctx, Variation{v}); 4800 4801 if constexpr (kVecWidth > VecWidth::k256) { 4802 test_vecop_vv<kVecWidth, UniOpVV::kBroadcastV256_U32, vec_op_broadcast_u256>(ctx, Variation{v}); 4803 test_vecop_vv<kVecWidth, UniOpVV::kBroadcastV256_U64, vec_op_broadcast_u256>(ctx, Variation{v}); 4804 test_vecop_vv<kVecWidth, UniOpVV::kBroadcastV256_F32, vec_op_broadcast_u256>(ctx, Variation{v}); 4805 test_vecop_vv<kVecWidth, UniOpVV::kBroadcastV256_F64, vec_op_broadcast_u256>(ctx, Variation{v}); 4806 } 4807 } 4808 } 4809 4810 INFO(" Testing abs (int)"); 4811 { 4812 for (uint32_t v = 0; v < kNumVariationsVV; v++) { 4813 test_vecop_vv<kVecWidth, UniOpVV::kAbsI8, vec_op_abs<int8_t>>(ctx, Variation{v}); 4814 test_vecop_vv<kVecWidth, UniOpVV::kAbsI16, vec_op_abs<int16_t>>(ctx, Variation{v}); 4815 test_vecop_vv<kVecWidth, UniOpVV::kAbsI32, vec_op_abs<int32_t>>(ctx, Variation{v}); 4816 test_vecop_vv<kVecWidth, UniOpVV::kAbsI64, vec_op_abs<int64_t>>(ctx, Variation{v}); 4817 } 4818 } 4819 4820 INFO(" Testing not (int)"); 4821 { 4822 for (uint32_t v = 0; v < kNumVariationsVV; v++) { 4823 test_vecop_vv<kVecWidth, UniOpVV::kNotU32, vec_op_not<uint32_t>>(ctx, Variation{v}); 4824 test_vecop_vv<kVecWidth, UniOpVV::kNotU64, vec_op_not<uint64_t>>(ctx, Variation{v}); 4825 } 4826 } 4827 4828 INFO(" Testing cvt (int)"); 4829 { 4830 for (uint32_t v = 0; v < kNumVariationsVV; v++) { 4831 test_vecop_vv<kVecWidth, UniOpVV::kCvtI8LoToI16, vec_op_cvt_i8_lo_to_i16>(ctx, Variation{v}); 4832 test_vecop_vv<kVecWidth, UniOpVV::kCvtI8HiToI16, vec_op_cvt_i8_hi_to_i16>(ctx, Variation{v}); 4833 test_vecop_vv<kVecWidth, UniOpVV::kCvtU8LoToU16, vec_op_cvt_u8_lo_to_u16>(ctx, Variation{v}); 4834 test_vecop_vv<kVecWidth, UniOpVV::kCvtU8HiToU16, vec_op_cvt_u8_hi_to_u16>(ctx, Variation{v}); 4835 test_vecop_vv<kVecWidth, UniOpVV::kCvtI8ToI32, vec_op_cvt_i8_to_i32>(ctx, Variation{v}); 4836 test_vecop_vv<kVecWidth, UniOpVV::kCvtU8ToU32, vec_op_cvt_u8_to_u32>(ctx, Variation{v}); 4837 test_vecop_vv<kVecWidth, UniOpVV::kCvtI16LoToI32, vec_op_cvt_i16_lo_to_i32>(ctx, Variation{v}); 4838 test_vecop_vv<kVecWidth, UniOpVV::kCvtI16HiToI32, vec_op_cvt_i16_hi_to_i32>(ctx, Variation{v}); 4839 test_vecop_vv<kVecWidth, UniOpVV::kCvtU16LoToU32, vec_op_cvt_u16_lo_to_u32>(ctx, Variation{v}); 4840 test_vecop_vv<kVecWidth, UniOpVV::kCvtU16HiToU32, vec_op_cvt_u16_hi_to_u32>(ctx, Variation{v}); 4841 test_vecop_vv<kVecWidth, UniOpVV::kCvtI32LoToI64, vec_op_cvt_i32_lo_to_i64>(ctx, Variation{v}); 4842 test_vecop_vv<kVecWidth, UniOpVV::kCvtI32HiToI64, vec_op_cvt_i32_hi_to_i64>(ctx, Variation{v}); 4843 test_vecop_vv<kVecWidth, UniOpVV::kCvtU32LoToU64, vec_op_cvt_u32_lo_to_u64>(ctx, Variation{v}); 4844 test_vecop_vv<kVecWidth, UniOpVV::kCvtU32HiToU64, vec_op_cvt_u32_hi_to_u64>(ctx, Variation{v}); 4845 } 4846 } 4847 4848 INFO(" Testing abs (float)"); 4849 { 4850 for (uint32_t v = 0; v < kNumVariationsVV; v++) { 4851 test_vecop_vv<kVecWidth, UniOpVV::kAbsF32, vec_op_fabs<float>>(ctx, Variation{v}); 4852 test_vecop_vv<kVecWidth, UniOpVV::kAbsF64, vec_op_fabs<double>>(ctx, Variation{v}); 4853 } 4854 } 4855 4856 INFO(" Testing not (float)"); 4857 { 4858 for (uint32_t v = 0; v < kNumVariationsVV; v++) { 4859 test_vecop_vv<kVecWidth, UniOpVV::kNotF32, vec_op_not<uint32_t>>(ctx, Variation{v}); 4860 test_vecop_vv<kVecWidth, UniOpVV::kNotF64, vec_op_not<uint64_t>>(ctx, Variation{v}); 4861 } 4862 } 4863 4864 INFO(" Testing rounding (float)"); 4865 { 4866 for (uint32_t v = 0; v < kNumVariationsVV; v++) { 4867 // Variation 2 means that the source operand is memory, which would ALWAYS zero the rest of the register. 4868 if (scalar_op_behavior == ScalarOpBehavior::kZeroing || v == 2u) { 4869 test_vecop_vv<kVecWidth, UniOpVV::kTruncF32S, scalar_op_trunc<ScalarOpBehavior::kZeroing, float>>(ctx, Variation{v}); 4870 test_vecop_vv<kVecWidth, UniOpVV::kTruncF64S, scalar_op_trunc<ScalarOpBehavior::kZeroing, double>>(ctx, Variation{v}); 4871 test_vecop_vv<kVecWidth, UniOpVV::kFloorF32S, scalar_op_floor<ScalarOpBehavior::kZeroing, float>>(ctx, Variation{v}); 4872 test_vecop_vv<kVecWidth, UniOpVV::kFloorF64S, scalar_op_floor<ScalarOpBehavior::kZeroing, double>>(ctx, Variation{v}); 4873 test_vecop_vv<kVecWidth, UniOpVV::kCeilF32S, scalar_op_ceil<ScalarOpBehavior::kZeroing, float>>(ctx, Variation{v}); 4874 test_vecop_vv<kVecWidth, UniOpVV::kCeilF64S, scalar_op_ceil<ScalarOpBehavior::kZeroing, double>>(ctx, Variation{v}); 4875 test_vecop_vv<kVecWidth, UniOpVV::kRoundEvenF32S, scalar_op_round_even<ScalarOpBehavior::kZeroing, float>>(ctx, Variation{v}); 4876 test_vecop_vv<kVecWidth, UniOpVV::kRoundEvenF64S, scalar_op_round_even<ScalarOpBehavior::kZeroing, double>>(ctx, Variation{v}); 4877 test_vecop_vv<kVecWidth, UniOpVV::kRoundHalfAwayF32S, scalar_op_round_half_away<ScalarOpBehavior::kZeroing, float>>(ctx, Variation{v}); 4878 test_vecop_vv<kVecWidth, UniOpVV::kRoundHalfAwayF64S, scalar_op_round_half_away<ScalarOpBehavior::kZeroing, double>>(ctx, Variation{v}); 4879 test_vecop_vv<kVecWidth, UniOpVV::kRoundHalfUpF32S, scalar_op_round_half_up<ScalarOpBehavior::kZeroing, float>>(ctx, Variation{v}); 4880 test_vecop_vv<kVecWidth, UniOpVV::kRoundHalfUpF64S, scalar_op_round_half_up<ScalarOpBehavior::kZeroing, double>>(ctx, Variation{v}); 4881 } 4882 else { 4883 test_vecop_vv<kVecWidth, UniOpVV::kTruncF32S, scalar_op_trunc<ScalarOpBehavior::kPreservingVec128, float>>(ctx, Variation{v}); 4884 test_vecop_vv<kVecWidth, UniOpVV::kTruncF64S, scalar_op_trunc<ScalarOpBehavior::kPreservingVec128, double>>(ctx, Variation{v}); 4885 test_vecop_vv<kVecWidth, UniOpVV::kFloorF32S, scalar_op_floor<ScalarOpBehavior::kPreservingVec128, float>>(ctx, Variation{v}); 4886 test_vecop_vv<kVecWidth, UniOpVV::kFloorF64S, scalar_op_floor<ScalarOpBehavior::kPreservingVec128, double>>(ctx, Variation{v}); 4887 test_vecop_vv<kVecWidth, UniOpVV::kCeilF32S, scalar_op_ceil<ScalarOpBehavior::kPreservingVec128, float>>(ctx, Variation{v}); 4888 test_vecop_vv<kVecWidth, UniOpVV::kCeilF64S, scalar_op_ceil<ScalarOpBehavior::kPreservingVec128, double>>(ctx, Variation{v}); 4889 test_vecop_vv<kVecWidth, UniOpVV::kRoundEvenF32S, scalar_op_round_even<ScalarOpBehavior::kPreservingVec128, float>>(ctx, Variation{v}); 4890 test_vecop_vv<kVecWidth, UniOpVV::kRoundEvenF64S, scalar_op_round_even<ScalarOpBehavior::kPreservingVec128, double>>(ctx, Variation{v}); 4891 test_vecop_vv<kVecWidth, UniOpVV::kRoundHalfAwayF32S, scalar_op_round_half_away<ScalarOpBehavior::kPreservingVec128, float>>(ctx, Variation{v}); 4892 test_vecop_vv<kVecWidth, UniOpVV::kRoundHalfAwayF64S, scalar_op_round_half_away<ScalarOpBehavior::kPreservingVec128, double>>(ctx, Variation{v}); 4893 test_vecop_vv<kVecWidth, UniOpVV::kRoundHalfUpF32S, scalar_op_round_half_up<ScalarOpBehavior::kPreservingVec128, float>>(ctx, Variation{v}); 4894 test_vecop_vv<kVecWidth, UniOpVV::kRoundHalfUpF64S, scalar_op_round_half_up<ScalarOpBehavior::kPreservingVec128, double>>(ctx, Variation{v}); 4895 } 4896 4897 test_vecop_vv<kVecWidth, UniOpVV::kTruncF32, vec_op_trunc<float>>(ctx, Variation{v}); 4898 test_vecop_vv<kVecWidth, UniOpVV::kTruncF64, vec_op_trunc<double>>(ctx, Variation{v}); 4899 test_vecop_vv<kVecWidth, UniOpVV::kFloorF32, vec_op_floor<float>>(ctx, Variation{v}); 4900 test_vecop_vv<kVecWidth, UniOpVV::kFloorF64, vec_op_floor<double>>(ctx, Variation{v}); 4901 test_vecop_vv<kVecWidth, UniOpVV::kCeilF32, vec_op_ceil<float>>(ctx, Variation{v}); 4902 test_vecop_vv<kVecWidth, UniOpVV::kCeilF64, vec_op_ceil<double>>(ctx, Variation{v}); 4903 test_vecop_vv<kVecWidth, UniOpVV::kRoundEvenF32, vec_op_round_even<float>>(ctx, Variation{v}); 4904 test_vecop_vv<kVecWidth, UniOpVV::kRoundEvenF64, vec_op_round_even<double>>(ctx, Variation{v}); 4905 test_vecop_vv<kVecWidth, UniOpVV::kRoundHalfAwayF32, vec_op_round_half_away<float>>(ctx, Variation{v}); 4906 test_vecop_vv<kVecWidth, UniOpVV::kRoundHalfAwayF64, vec_op_round_half_away<double>>(ctx, Variation{v}); 4907 test_vecop_vv<kVecWidth, UniOpVV::kRoundHalfUpF32, vec_op_round_half_up<float>>(ctx, Variation{v}); 4908 test_vecop_vv<kVecWidth, UniOpVV::kRoundHalfUpF64, vec_op_round_half_up<double>>(ctx, Variation{v}); 4909 } 4910 } 4911 4912 INFO(" Testing rcp (float)"); 4913 { 4914 for (uint32_t v = 0; v < kNumVariationsVV; v++) { 4915 test_vecop_vv<kVecWidth, UniOpVV::kRcpF32, vec_op_rcp<float>>(ctx, Variation{v}); 4916 test_vecop_vv<kVecWidth, UniOpVV::kRcpF64, vec_op_rcp<double>>(ctx, Variation{v}); 4917 } 4918 } 4919 4920 INFO(" Testing sqrt (float)"); 4921 { 4922 if (scalar_op_behavior == ScalarOpBehavior::kZeroing) { 4923 test_vecop_vv<kVecWidth, UniOpVV::kSqrtF32S, scalar_op_sqrt<ScalarOpBehavior::kZeroing, float>>(ctx); 4924 test_vecop_vv<kVecWidth, UniOpVV::kSqrtF64S, scalar_op_sqrt<ScalarOpBehavior::kZeroing, double>>(ctx); 4925 } 4926 else { 4927 test_vecop_vv<kVecWidth, UniOpVV::kSqrtF32S, scalar_op_sqrt<ScalarOpBehavior::kPreservingVec128, float>>(ctx); 4928 test_vecop_vv<kVecWidth, UniOpVV::kSqrtF64S, scalar_op_sqrt<ScalarOpBehavior::kPreservingVec128, double>>(ctx); 4929 } 4930 4931 for (uint32_t v = 0; v < kNumVariationsVV; v++) { 4932 test_vecop_vv<kVecWidth, UniOpVV::kSqrtF32, vec_op_sqrt<float>>(ctx, Variation{v}); 4933 test_vecop_vv<kVecWidth, UniOpVV::kSqrtF64, vec_op_sqrt<double>>(ctx, Variation{v}); 4934 } 4935 } 4936 4937 INFO(" Testing cvt (float)"); 4938 { 4939 for (uint32_t v = 0; v < kNumVariationsVV; v++) { 4940 // TODO: [JIT] Re-enable when the content of the remaining part of the register is formalized. 4941 // test_vecop_vv<kVecWidth, UniOpVV::kCvtF32ToF64S, scalar_op_cvt_f32_to_f64>(ctx); 4942 // test_vecop_vv<kVecWidth, UniOpVV::kCvtF64ToF32S, scalar_op_cvt_f64_to_f32>(ctx); 4943 4944 test_vecop_vv<kVecWidth, UniOpVV::kCvtI32ToF32, vec_op_cvt_i32_to_f32>(ctx, Variation{v}); 4945 test_vecop_vv<kVecWidth, UniOpVV::kCvtF32LoToF64, vec_op_cvt_f32_lo_to_f64>(ctx, Variation{v}); 4946 test_vecop_vv<kVecWidth, UniOpVV::kCvtF32HiToF64, vec_op_cvt_f32_hi_to_f64>(ctx, Variation{v}); 4947 test_vecop_vv<kVecWidth, UniOpVV::kCvtF64ToF32Lo, vec_op_cvt_f64_to_f32_lo>(ctx, Variation{0}); 4948 test_vecop_vv<kVecWidth, UniOpVV::kCvtF64ToF32Hi, vec_op_cvt_f64_to_f32_hi>(ctx, Variation{0}); 4949 test_vecop_vv<kVecWidth, UniOpVV::kCvtI32LoToF64, vec_op_cvt_i32_lo_to_f64>(ctx, Variation{v}); 4950 test_vecop_vv<kVecWidth, UniOpVV::kCvtI32HiToF64, vec_op_cvt_i32_hi_to_f64>(ctx, Variation{v}); 4951 4952 if (float_to_int_behavior == FloatToIntOutsideRangeBehavior::kSmallestValue) { 4953 constexpr FloatToIntOutsideRangeBehavior behavior = FloatToIntOutsideRangeBehavior::kSmallestValue; 4954 test_vecop_vv<kVecWidth, UniOpVV::kCvtTruncF32ToI32, vec_op_cvt_trunc_f32_to_i32<behavior>>(ctx, Variation{v}); 4955 test_vecop_vv<kVecWidth, UniOpVV::kCvtTruncF64ToI32Lo, vec_op_cvt_trunc_f64_to_i32_lo<behavior>>(ctx, Variation{0}); 4956 test_vecop_vv<kVecWidth, UniOpVV::kCvtTruncF64ToI32Hi, vec_op_cvt_trunc_f64_to_i32_hi<behavior>>(ctx, Variation{0}); 4957 test_vecop_vv<kVecWidth, UniOpVV::kCvtRoundF32ToI32, vec_op_cvt_round_f32_to_i32<behavior>>(ctx, Variation{v}); 4958 test_vecop_vv<kVecWidth, UniOpVV::kCvtRoundF64ToI32Lo, vec_op_cvt_round_f64_to_i32_lo<behavior>>(ctx, Variation{0}); 4959 test_vecop_vv<kVecWidth, UniOpVV::kCvtRoundF64ToI32Hi, vec_op_cvt_round_f64_to_i32_hi<behavior>>(ctx, Variation{0}); 4960 } 4961 else { 4962 constexpr FloatToIntOutsideRangeBehavior behavior = FloatToIntOutsideRangeBehavior::kSaturatedValue; 4963 test_vecop_vv<kVecWidth, UniOpVV::kCvtTruncF32ToI32, vec_op_cvt_trunc_f32_to_i32<behavior>>(ctx, Variation{v}); 4964 test_vecop_vv<kVecWidth, UniOpVV::kCvtTruncF64ToI32Lo, vec_op_cvt_trunc_f64_to_i32_lo<behavior>>(ctx, Variation{0}); 4965 test_vecop_vv<kVecWidth, UniOpVV::kCvtTruncF64ToI32Hi, vec_op_cvt_trunc_f64_to_i32_hi<behavior>>(ctx, Variation{0}); 4966 test_vecop_vv<kVecWidth, UniOpVV::kCvtRoundF32ToI32, vec_op_cvt_round_f32_to_i32<behavior>>(ctx, Variation{v}); 4967 test_vecop_vv<kVecWidth, UniOpVV::kCvtRoundF64ToI32Lo, vec_op_cvt_round_f64_to_i32_lo<behavior>>(ctx, Variation{0}); 4968 test_vecop_vv<kVecWidth, UniOpVV::kCvtRoundF64ToI32Hi, vec_op_cvt_round_f64_to_i32_hi<behavior>>(ctx, Variation{0}); 4969 } 4970 } 4971 } 4972 4973 INFO(" Testing bit shift"); 4974 { 4975 for (uint32_t v = 0; v < kNumVariationsVVI; v++) { 4976 /* 4977 for (uint32_t i = 1; i < 8; i++) { 4978 test_vecop_vvi<kVecWidth, UniOpVVI::kSllU8 , vec_op_slli<uint8_t>>(ctx, i, Variation{v}); 4979 test_vecop_vvi<kVecWidth, UniOpVVI::kSrlU8 , vec_op_srli<uint8_t>>(ctx, i, Variation{v}); 4980 test_vecop_vvi<kVecWidth, UniOpVVI::kSraI8 , vec_op_srai<int8_t>>(ctx, i, Variation{v}); 4981 } 4982 */ 4983 for (uint32_t i = 1; i < 16; i++) { 4984 test_vecop_vvi<kVecWidth, UniOpVVI::kSllU16, vec_op_slli<uint16_t>>(ctx, i, Variation{v}); 4985 test_vecop_vvi<kVecWidth, UniOpVVI::kSrlU16, vec_op_srli<uint16_t>>(ctx, i, Variation{v}); 4986 test_vecop_vvi<kVecWidth, UniOpVVI::kSraI16, vec_op_srai<int16_t>>(ctx, i, Variation{v}); 4987 } 4988 4989 for (uint32_t i = 1; i < 32; i++) { 4990 test_vecop_vvi<kVecWidth, UniOpVVI::kSllU32, vec_op_slli<uint32_t>>(ctx, i, Variation{v}); 4991 test_vecop_vvi<kVecWidth, UniOpVVI::kSrlU32, vec_op_srli<uint32_t>>(ctx, i, Variation{v}); 4992 test_vecop_vvi<kVecWidth, UniOpVVI::kSraI32, vec_op_srai<int32_t>>(ctx, i, Variation{v}); 4993 } 4994 4995 for (uint32_t i = 1; i < 64; i++) { 4996 test_vecop_vvi<kVecWidth, UniOpVVI::kSllU64, vec_op_slli<uint64_t>>(ctx, i, Variation{v}); 4997 test_vecop_vvi<kVecWidth, UniOpVVI::kSrlU64, vec_op_srli<uint64_t>>(ctx, i, Variation{v}); 4998 test_vecop_vvi<kVecWidth, UniOpVVI::kSraI64, vec_op_srai<int64_t>>(ctx, i, Variation{v}); 4999 } 5000 } 5001 } 5002 5003 INFO(" Testing sllb_u128 & srlb_u128"); 5004 { 5005 for (uint32_t v = 0; v < kNumVariationsVVI; v++) { 5006 for (uint32_t i = 1; i < 16; i++) { 5007 test_vecop_vvi<kVecWidth, UniOpVVI::kSllbU128, vec_op_sllb_u128>(ctx, i, Variation{v}); 5008 test_vecop_vvi<kVecWidth, UniOpVVI::kSrlbU128, vec_op_srlb_u128>(ctx, i, Variation{v}); 5009 } 5010 } 5011 } 5012 5013 INFO(" Testing swizzle_[lo|hi]_u16x4"); 5014 { 5015 for (uint32_t v = 0; v < kNumVariationsVVI; v++) { 5016 for (uint32_t i = 0; i < 256; i++) { 5017 uint32_t imm = swizzle((i >> 6) & 3, (i >> 4) & 3, (i >> 2) & 3, i & 3).value; 5018 5019 test_vecop_vvi<kVecWidth, UniOpVVI::kSwizzleLoU16x4, vec_op_swizzle_lo_u16x4>(ctx, imm, Variation{v}); 5020 test_vecop_vvi<kVecWidth, UniOpVVI::kSwizzleHiU16x4, vec_op_swizzle_hi_u16x4>(ctx, imm, Variation{v}); 5021 test_vecop_vvi<kVecWidth, UniOpVVI::kSwizzleU16x4, vec_op_swizzle_u16>(ctx, imm, Variation{v}); 5022 } 5023 } 5024 } 5025 5026 INFO(" Testing swizzle_u32x4"); 5027 { 5028 for (uint32_t v = 0; v < kNumVariationsVVI; v++) { 5029 for (uint32_t i = 0; i < 256; i++) { 5030 uint32_t imm = swizzle((i >> 6) & 3, (i >> 4) & 3, (i >> 2) & 3, i & 3).value; 5031 5032 test_vecop_vvi<kVecWidth, UniOpVVI::kSwizzleU32x4, vec_op_swizzle_u32x4>(ctx, imm, Variation{v}); 5033 test_vecop_vvi<kVecWidth, UniOpVVI::kSwizzleF32x4, vec_op_swizzle_u32x4>(ctx, imm, Variation{v}); 5034 } 5035 } 5036 } 5037 5038 INFO(" Testing swizzle_u64x2"); 5039 { 5040 for (uint32_t v = 0; v < kNumVariationsVVI; v++) { 5041 for (uint32_t i = 0; i < 4; i++) { 5042 uint32_t imm = swizzle((i >> 1) & 1, i & 1).value; 5043 test_vecop_vvi<kVecWidth, UniOpVVI::kSwizzleU64x2, vec_op_swizzle_u64x2>(ctx, imm, Variation{v}); 5044 test_vecop_vvi<kVecWidth, UniOpVVI::kSwizzleF64x2, vec_op_swizzle_u64x2>(ctx, imm, Variation{v}); 5045 } 5046 } 5047 } 5048 5049 INFO(" Testing logical (int)"); 5050 { 5051 for (uint32_t v = 0; v < kNumVariationsVVV; v++) { 5052 test_vecop_vvv<kVecWidth, UniOpVVV::kAndU32, vec_op_and<uint32_t>>(ctx, Variation{v}); 5053 test_vecop_vvv<kVecWidth, UniOpVVV::kAndU64, vec_op_and<uint64_t>>(ctx, Variation{v}); 5054 test_vecop_vvv<kVecWidth, UniOpVVV::kOrU32, vec_op_or<uint32_t>>(ctx, Variation{v}); 5055 test_vecop_vvv<kVecWidth, UniOpVVV::kOrU64, vec_op_or<uint64_t>>(ctx, Variation{v}); 5056 test_vecop_vvv<kVecWidth, UniOpVVV::kXorU32, vec_op_xor<uint32_t>>(ctx, Variation{v}); 5057 test_vecop_vvv<kVecWidth, UniOpVVV::kXorU64, vec_op_xor<uint64_t>>(ctx, Variation{v}); 5058 test_vecop_vvv<kVecWidth, UniOpVVV::kAndnU32, vec_op_andn<uint32_t>>(ctx, Variation{v}); 5059 test_vecop_vvv<kVecWidth, UniOpVVV::kAndnU64, vec_op_andn<uint64_t>>(ctx, Variation{v}); 5060 test_vecop_vvv<kVecWidth, UniOpVVV::kBicU32, vec_op_bic<uint32_t>>(ctx, Variation{v}); 5061 test_vecop_vvv<kVecWidth, UniOpVVV::kBicU64, vec_op_bic<uint64_t>>(ctx, Variation{v}); 5062 } 5063 } 5064 5065 INFO(" Testing add / adds (int)"); 5066 { 5067 for (uint32_t v = 0; v < kNumVariationsVVV; v++) { 5068 test_vecop_vvv<kVecWidth, UniOpVVV::kAddU8, vec_op_add<uint8_t>>(ctx, Variation{v}); 5069 test_vecop_vvv<kVecWidth, UniOpVVV::kAddU16, vec_op_add<uint16_t>>(ctx, Variation{v}); 5070 test_vecop_vvv<kVecWidth, UniOpVVV::kAddU32, vec_op_add<uint32_t>>(ctx, Variation{v}); 5071 test_vecop_vvv<kVecWidth, UniOpVVV::kAddU64, vec_op_add<uint64_t>>(ctx, Variation{v}); 5072 test_vecop_vvv<kVecWidth, UniOpVVV::kAddsI8, vec_op_adds<int8_t>>(ctx, Variation{v}); 5073 test_vecop_vvv<kVecWidth, UniOpVVV::kAddsI16, vec_op_adds<int16_t>>(ctx, Variation{v}); 5074 test_vecop_vvv<kVecWidth, UniOpVVV::kAddsU8, vec_op_adds<uint8_t>>(ctx, Variation{v}); 5075 test_vecop_vvv<kVecWidth, UniOpVVV::kAddsU16, vec_op_adds<uint16_t>>(ctx, Variation{v}); 5076 } 5077 } 5078 5079 INFO(" Testing sub / subs (int)"); 5080 { 5081 for (uint32_t v = 0; v < kNumVariationsVVV; v++) { 5082 test_vecop_vvv<kVecWidth, UniOpVVV::kSubU8, vec_op_sub<uint8_t>>(ctx, Variation{v}); 5083 test_vecop_vvv<kVecWidth, UniOpVVV::kSubU16, vec_op_sub<uint16_t>>(ctx, Variation{v}); 5084 test_vecop_vvv<kVecWidth, UniOpVVV::kSubU32, vec_op_sub<uint32_t>>(ctx, Variation{v}); 5085 test_vecop_vvv<kVecWidth, UniOpVVV::kSubU64, vec_op_sub<uint64_t>>(ctx, Variation{v}); 5086 test_vecop_vvv<kVecWidth, UniOpVVV::kSubsI8, vec_op_subs<int8_t>>(ctx, Variation{v}); 5087 test_vecop_vvv<kVecWidth, UniOpVVV::kSubsI16, vec_op_subs<int16_t>>(ctx, Variation{v}); 5088 test_vecop_vvv<kVecWidth, UniOpVVV::kSubsU8, vec_op_subs<uint8_t>>(ctx, Variation{v}); 5089 test_vecop_vvv<kVecWidth, UniOpVVV::kSubsU16, vec_op_subs<uint16_t>>(ctx, Variation{v}); 5090 } 5091 } 5092 5093 INFO(" Testing mul (int)"); 5094 { 5095 for (uint32_t v = 0; v < kNumVariationsVVV; v++) { 5096 test_vecop_vvv<kVecWidth, UniOpVVV::kMulU16, vec_op_mul<uint16_t>>(ctx, Variation{v}); 5097 test_vecop_vvv<kVecWidth, UniOpVVV::kMulU32, vec_op_mul<uint32_t>>(ctx, Variation{v}); 5098 test_vecop_vvv<kVecWidth, UniOpVVV::kMulU64, vec_op_mul<uint64_t>>(ctx, Variation{v}); 5099 test_vecop_vvv<kVecWidth, UniOpVVV::kMulhI16, vec_op_mulhi<int16_t>>(ctx, Variation{v}); 5100 test_vecop_vvv<kVecWidth, UniOpVVV::kMulhU16, vec_op_mulhu<uint16_t>>(ctx, Variation{v}); 5101 test_vecop_vvv<kVecWidth, UniOpVVV::kMulU64_LoU32, vec_op_mul_u64_lo_u32>(ctx, Variation{v}); 5102 } 5103 } 5104 5105 INFO(" Testing mhadd (int)"); 5106 { 5107 for (uint32_t v = 0; v < kNumVariationsVVV; v++) { 5108 test_vecop_vvv<kVecWidth, UniOpVVV::kMHAddI16_I32, vec_op_mhadd_i16_i32>(ctx, Variation{v}); 5109 } 5110 } 5111 5112 INFO(" Testing madd (int)"); 5113 { 5114 for (uint32_t v = 0; v < kNumVariationsVVVV; v++) { 5115 test_vecop_vvvv<kVecWidth, UniOpVVVV::kMAddU16, vec_op_madd<uint16_t>>(ctx, Variation{v}); 5116 test_vecop_vvvv<kVecWidth, UniOpVVVV::kMAddU32, vec_op_madd<uint32_t>>(ctx, Variation{v}); 5117 } 5118 } 5119 5120 INFO(" Testing min / max (int)"); 5121 { 5122 for (uint32_t v = 0; v < kNumVariationsVVV; v++) { 5123 test_vecop_vvv<kVecWidth, UniOpVVV::kMinI8, vec_op_min<int8_t>>(ctx, Variation{v}); 5124 test_vecop_vvv<kVecWidth, UniOpVVV::kMinI16, vec_op_min<int16_t>>(ctx, Variation{v}); 5125 test_vecop_vvv<kVecWidth, UniOpVVV::kMinI32, vec_op_min<int32_t>>(ctx, Variation{v}); 5126 test_vecop_vvv<kVecWidth, UniOpVVV::kMinI64, vec_op_min<int64_t>>(ctx, Variation{v}); 5127 test_vecop_vvv<kVecWidth, UniOpVVV::kMinU8, vec_op_min<uint8_t>>(ctx, Variation{v}); 5128 test_vecop_vvv<kVecWidth, UniOpVVV::kMinU16, vec_op_min<uint16_t>>(ctx, Variation{v}); 5129 test_vecop_vvv<kVecWidth, UniOpVVV::kMinU32, vec_op_min<uint32_t>>(ctx, Variation{v}); 5130 test_vecop_vvv<kVecWidth, UniOpVVV::kMinU64, vec_op_min<uint64_t>>(ctx, Variation{v}); 5131 test_vecop_vvv<kVecWidth, UniOpVVV::kMaxI8, vec_op_max<int8_t>>(ctx, Variation{v}); 5132 test_vecop_vvv<kVecWidth, UniOpVVV::kMaxI16, vec_op_max<int16_t>>(ctx, Variation{v}); 5133 test_vecop_vvv<kVecWidth, UniOpVVV::kMaxI32, vec_op_max<int32_t>>(ctx, Variation{v}); 5134 test_vecop_vvv<kVecWidth, UniOpVVV::kMaxI64, vec_op_max<int64_t>>(ctx, Variation{v}); 5135 test_vecop_vvv<kVecWidth, UniOpVVV::kMaxU8, vec_op_max<uint8_t>>(ctx, Variation{v}); 5136 test_vecop_vvv<kVecWidth, UniOpVVV::kMaxU16, vec_op_max<uint16_t>>(ctx, Variation{v}); 5137 test_vecop_vvv<kVecWidth, UniOpVVV::kMaxU32, vec_op_max<uint32_t>>(ctx, Variation{v}); 5138 test_vecop_vvv<kVecWidth, UniOpVVV::kMaxU64, vec_op_max<uint64_t>>(ctx, Variation{v}); 5139 } 5140 } 5141 5142 INFO(" Testing cmp (int)"); 5143 { 5144 for (uint32_t v = 0; v < kNumVariationsVVV; v++) { 5145 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpEqU8, vec_op_cmp_eq<uint8_t>>(ctx, Variation{v}); 5146 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpEqU16, vec_op_cmp_eq<uint16_t>>(ctx, Variation{v}); 5147 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpEqU32, vec_op_cmp_eq<uint32_t>>(ctx, Variation{v}); 5148 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpEqU64, vec_op_cmp_eq<uint64_t>>(ctx, Variation{v}); 5149 /* 5150 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpNeU8, vec_op_cmp_ne<uint8_t>>(ctx, Variation{v}); 5151 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpNeU16, vec_op_cmp_ne<uint16_t>>(ctx, Variation{v}); 5152 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpNeU32, vec_op_cmp_ne<uint32_t>>(ctx, Variation{v}); 5153 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpNeU64, vec_op_cmp_ne<uint64_t>>(ctx, Variation{v}); 5154 */ 5155 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpGtI8, vec_op_cmp_gt<int8_t>>(ctx, Variation{v}); 5156 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpGtI16, vec_op_cmp_gt<int16_t>>(ctx, Variation{v}); 5157 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpGtI32, vec_op_cmp_gt<int32_t>>(ctx, Variation{v}); 5158 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpGtI64, vec_op_cmp_gt<int64_t>>(ctx, Variation{v}); 5159 5160 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpGtU8, vec_op_cmp_gt<uint8_t>>(ctx, Variation{v}); 5161 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpGtU16, vec_op_cmp_gt<uint16_t>>(ctx, Variation{v}); 5162 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpGtU32, vec_op_cmp_gt<uint32_t>>(ctx, Variation{v}); 5163 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpGtU64, vec_op_cmp_gt<uint64_t>>(ctx, Variation{v}); 5164 5165 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpGeI8, vec_op_cmp_ge<int8_t>>(ctx, Variation{v}); 5166 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpGeI16, vec_op_cmp_ge<int16_t>>(ctx, Variation{v}); 5167 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpGeI32, vec_op_cmp_ge<int32_t>>(ctx, Variation{v}); 5168 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpGeI64, vec_op_cmp_ge<int64_t>>(ctx, Variation{v}); 5169 5170 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpGeU8, vec_op_cmp_ge<uint8_t>>(ctx, Variation{v}); 5171 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpGeU16, vec_op_cmp_ge<uint16_t>>(ctx, Variation{v}); 5172 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpGeU32, vec_op_cmp_ge<uint32_t>>(ctx, Variation{v}); 5173 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpGeU64, vec_op_cmp_ge<uint64_t>>(ctx, Variation{v}); 5174 5175 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpLtI8, vec_op_cmp_lt<int8_t>>(ctx, Variation{v}); 5176 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpLtI16, vec_op_cmp_lt<int16_t>>(ctx, Variation{v}); 5177 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpLtI32, vec_op_cmp_lt<int32_t>>(ctx, Variation{v}); 5178 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpLtI64, vec_op_cmp_lt<int64_t>>(ctx, Variation{v}); 5179 5180 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpLtU8, vec_op_cmp_lt<uint8_t>>(ctx, Variation{v}); 5181 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpLtU16, vec_op_cmp_lt<uint16_t>>(ctx, Variation{v}); 5182 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpLtU32, vec_op_cmp_lt<uint32_t>>(ctx, Variation{v}); 5183 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpLtU64, vec_op_cmp_lt<uint64_t>>(ctx, Variation{v}); 5184 5185 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpLeI8, vec_op_cmp_le<int8_t>>(ctx, Variation{v}); 5186 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpLeI16, vec_op_cmp_le<int16_t>>(ctx, Variation{v}); 5187 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpLeI32, vec_op_cmp_le<int32_t>>(ctx, Variation{v}); 5188 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpLeI64, vec_op_cmp_le<int64_t>>(ctx, Variation{v}); 5189 5190 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpLeU8, vec_op_cmp_le<uint8_t>>(ctx, Variation{v}); 5191 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpLeU16, vec_op_cmp_le<uint16_t>>(ctx, Variation{v}); 5192 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpLeU32, vec_op_cmp_le<uint32_t>>(ctx, Variation{v}); 5193 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpLeU64, vec_op_cmp_le<uint64_t>>(ctx, Variation{v}); 5194 } 5195 } 5196 5197 INFO(" Testing logical (float)"); 5198 { 5199 for (uint32_t v = 0; v < kNumVariationsVVV; v++) { 5200 test_vecop_vvv<kVecWidth, UniOpVVV::kAndF32, vec_op_and<uint32_t>>(ctx, Variation{v}); 5201 test_vecop_vvv<kVecWidth, UniOpVVV::kAndF64, vec_op_and<uint64_t>>(ctx, Variation{v}); 5202 test_vecop_vvv<kVecWidth, UniOpVVV::kOrF32, vec_op_or<uint32_t>>(ctx, Variation{v}); 5203 test_vecop_vvv<kVecWidth, UniOpVVV::kOrF64, vec_op_or<uint64_t>>(ctx, Variation{v}); 5204 test_vecop_vvv<kVecWidth, UniOpVVV::kXorF32, vec_op_xor<uint32_t>>(ctx, Variation{v}); 5205 test_vecop_vvv<kVecWidth, UniOpVVV::kXorF64, vec_op_xor<uint64_t>>(ctx, Variation{v}); 5206 test_vecop_vvv<kVecWidth, UniOpVVV::kAndnF32, vec_op_andn<uint32_t>>(ctx, Variation{v}); 5207 test_vecop_vvv<kVecWidth, UniOpVVV::kAndnF64, vec_op_andn<uint64_t>>(ctx, Variation{v}); 5208 test_vecop_vvv<kVecWidth, UniOpVVV::kBicF32, vec_op_bic<uint32_t>>(ctx, Variation{v}); 5209 test_vecop_vvv<kVecWidth, UniOpVVV::kBicF64, vec_op_bic<uint64_t>>(ctx, Variation{v}); 5210 } 5211 } 5212 5213 INFO(" Testing arithmetic (float)"); 5214 { 5215 if (scalar_op_behavior == ScalarOpBehavior::kZeroing) { 5216 test_vecop_vvv<kVecWidth, UniOpVVV::kAddF32S, scalar_op_fadd<ScalarOpBehavior::kZeroing, float>>(ctx); 5217 test_vecop_vvv<kVecWidth, UniOpVVV::kAddF64S, scalar_op_fadd<ScalarOpBehavior::kZeroing, double>>(ctx); 5218 test_vecop_vvv<kVecWidth, UniOpVVV::kSubF32S, scalar_op_fsub<ScalarOpBehavior::kZeroing, float>>(ctx); 5219 test_vecop_vvv<kVecWidth, UniOpVVV::kSubF64S, scalar_op_fsub<ScalarOpBehavior::kZeroing, double>>(ctx); 5220 test_vecop_vvv<kVecWidth, UniOpVVV::kMulF32S, scalar_op_fmul<ScalarOpBehavior::kZeroing, float>>(ctx); 5221 test_vecop_vvv<kVecWidth, UniOpVVV::kMulF64S, scalar_op_fmul<ScalarOpBehavior::kZeroing, double>>(ctx); 5222 test_vecop_vvv<kVecWidth, UniOpVVV::kDivF32S, scalar_op_fdiv<ScalarOpBehavior::kZeroing, float>>(ctx); 5223 test_vecop_vvv<kVecWidth, UniOpVVV::kDivF64S, scalar_op_fdiv<ScalarOpBehavior::kZeroing, double>>(ctx); 5224 } 5225 else { 5226 test_vecop_vvv<kVecWidth, UniOpVVV::kAddF32S, scalar_op_fadd<ScalarOpBehavior::kPreservingVec128, float>>(ctx); 5227 test_vecop_vvv<kVecWidth, UniOpVVV::kAddF64S, scalar_op_fadd<ScalarOpBehavior::kPreservingVec128, double>>(ctx); 5228 test_vecop_vvv<kVecWidth, UniOpVVV::kSubF32S, scalar_op_fsub<ScalarOpBehavior::kPreservingVec128, float>>(ctx); 5229 test_vecop_vvv<kVecWidth, UniOpVVV::kSubF64S, scalar_op_fsub<ScalarOpBehavior::kPreservingVec128, double>>(ctx); 5230 test_vecop_vvv<kVecWidth, UniOpVVV::kMulF32S, scalar_op_fmul<ScalarOpBehavior::kPreservingVec128, float>>(ctx); 5231 test_vecop_vvv<kVecWidth, UniOpVVV::kMulF64S, scalar_op_fmul<ScalarOpBehavior::kPreservingVec128, double>>(ctx); 5232 test_vecop_vvv<kVecWidth, UniOpVVV::kDivF32S, scalar_op_fdiv<ScalarOpBehavior::kPreservingVec128, float>>(ctx); 5233 test_vecop_vvv<kVecWidth, UniOpVVV::kDivF64S, scalar_op_fdiv<ScalarOpBehavior::kPreservingVec128, double>>(ctx); 5234 } 5235 5236 for (uint32_t v = 0; v < kNumVariationsVVV; v++) { 5237 test_vecop_vvv<kVecWidth, UniOpVVV::kAddF32, vec_op_fadd<float>>(ctx, Variation{v}); 5238 test_vecop_vvv<kVecWidth, UniOpVVV::kAddF64, vec_op_fadd<double>>(ctx, Variation{v}); 5239 test_vecop_vvv<kVecWidth, UniOpVVV::kSubF32, vec_op_fsub<float>>(ctx, Variation{v}); 5240 test_vecop_vvv<kVecWidth, UniOpVVV::kSubF64, vec_op_fsub<double>>(ctx, Variation{v}); 5241 test_vecop_vvv<kVecWidth, UniOpVVV::kMulF32, vec_op_fmul<float>>(ctx, Variation{v}); 5242 test_vecop_vvv<kVecWidth, UniOpVVV::kMulF64, vec_op_fmul<double>>(ctx, Variation{v}); 5243 test_vecop_vvv<kVecWidth, UniOpVVV::kDivF32, vec_op_fdiv<float>>(ctx, Variation{v}); 5244 test_vecop_vvv<kVecWidth, UniOpVVV::kDivF64, vec_op_fdiv<double>>(ctx, Variation{v}); 5245 } 5246 } 5247 5248 if (fmadd_op_behavior == FMAddOpBehavior::kNoFMA) { 5249 INFO(" Testing madd (no-fma) (float)"); 5250 { 5251 if (scalar_op_behavior == ScalarOpBehavior::kZeroing) { 5252 test_vecop_vvvv<kVecWidth, UniOpVVVV::kMAddF32S, scalar_op_fmadd_nofma<ScalarOpBehavior::kZeroing, float>>(ctx, Variation{0}); 5253 test_vecop_vvvv<kVecWidth, UniOpVVVV::kMAddF64S, scalar_op_fmadd_nofma<ScalarOpBehavior::kZeroing, double>>(ctx, Variation{0}); 5254 test_vecop_vvvv<kVecWidth, UniOpVVVV::kMSubF32S, scalar_op_fmsub_nofma<ScalarOpBehavior::kZeroing, float>>(ctx, Variation{0}); 5255 test_vecop_vvvv<kVecWidth, UniOpVVVV::kMSubF64S, scalar_op_fmsub_nofma<ScalarOpBehavior::kZeroing, double>>(ctx, Variation{0}); 5256 test_vecop_vvvv<kVecWidth, UniOpVVVV::kNMAddF32S, scalar_op_fnmadd_nofma<ScalarOpBehavior::kZeroing, float>>(ctx, Variation{0}); 5257 test_vecop_vvvv<kVecWidth, UniOpVVVV::kNMAddF64S, scalar_op_fnmadd_nofma<ScalarOpBehavior::kZeroing, double>>(ctx, Variation{0}); 5258 test_vecop_vvvv<kVecWidth, UniOpVVVV::kNMSubF32S, scalar_op_fnmsub_nofma<ScalarOpBehavior::kZeroing, float>>(ctx, Variation{0}); 5259 test_vecop_vvvv<kVecWidth, UniOpVVVV::kNMSubF64S, scalar_op_fnmsub_nofma<ScalarOpBehavior::kZeroing, double>>(ctx, Variation{0}); 5260 } 5261 else { 5262 test_vecop_vvvv<kVecWidth, UniOpVVVV::kMAddF32S, scalar_op_fmadd_nofma<ScalarOpBehavior::kPreservingVec128, float>>(ctx, Variation{0}); 5263 test_vecop_vvvv<kVecWidth, UniOpVVVV::kMAddF64S, scalar_op_fmadd_nofma<ScalarOpBehavior::kPreservingVec128, double>>(ctx, Variation{0}); 5264 test_vecop_vvvv<kVecWidth, UniOpVVVV::kMSubF32S, scalar_op_fmsub_nofma<ScalarOpBehavior::kPreservingVec128, float>>(ctx, Variation{0}); 5265 test_vecop_vvvv<kVecWidth, UniOpVVVV::kMSubF64S, scalar_op_fmsub_nofma<ScalarOpBehavior::kPreservingVec128, double>>(ctx, Variation{0}); 5266 test_vecop_vvvv<kVecWidth, UniOpVVVV::kNMAddF32S, scalar_op_fnmadd_nofma<ScalarOpBehavior::kPreservingVec128, float>>(ctx, Variation{0}); 5267 test_vecop_vvvv<kVecWidth, UniOpVVVV::kNMAddF64S, scalar_op_fnmadd_nofma<ScalarOpBehavior::kPreservingVec128, double>>(ctx, Variation{0}); 5268 test_vecop_vvvv<kVecWidth, UniOpVVVV::kNMSubF32S, scalar_op_fnmsub_nofma<ScalarOpBehavior::kPreservingVec128, float>>(ctx, Variation{0}); 5269 test_vecop_vvvv<kVecWidth, UniOpVVVV::kNMSubF64S, scalar_op_fnmsub_nofma<ScalarOpBehavior::kPreservingVec128, double>>(ctx, Variation{0}); 5270 } 5271 5272 for (uint32_t v = 0; v < kNumVariationsVVVV; v++) { 5273 test_vecop_vvvv<kVecWidth, UniOpVVVV::kMAddF32, vec_op_fmadd_nofma<float>>(ctx, Variation{v}); 5274 test_vecop_vvvv<kVecWidth, UniOpVVVV::kMAddF64, vec_op_fmadd_nofma<double>>(ctx, Variation{v}); 5275 test_vecop_vvvv<kVecWidth, UniOpVVVV::kMSubF32, vec_op_fmsub_nofma<float>>(ctx, Variation{v}); 5276 test_vecop_vvvv<kVecWidth, UniOpVVVV::kMSubF64, vec_op_fmsub_nofma<double>>(ctx, Variation{v}); 5277 test_vecop_vvvv<kVecWidth, UniOpVVVV::kNMAddF32, vec_op_fnmadd_nofma<float>>(ctx, Variation{v}); 5278 test_vecop_vvvv<kVecWidth, UniOpVVVV::kNMAddF64, vec_op_fnmadd_nofma<double>>(ctx, Variation{v}); 5279 test_vecop_vvvv<kVecWidth, UniOpVVVV::kNMSubF32, vec_op_fnmsub_nofma<float>>(ctx, Variation{v}); 5280 test_vecop_vvvv<kVecWidth, UniOpVVVV::kNMSubF64, vec_op_fnmsub_nofma<double>>(ctx, Variation{v}); 5281 } 5282 } 5283 } 5284 else { 5285 INFO(" Testing madd (fma) (float)"); 5286 { 5287 if (valgrind_fma_bug) { 5288 INFO(" (scalar FMA tests ignored due to a Valgrind bug!)"); 5289 } 5290 else { 5291 if (scalar_op_behavior == ScalarOpBehavior::kZeroing) { 5292 test_vecop_vvvv<kVecWidth, UniOpVVVV::kMAddF32S, scalar_op_fmadd_fma<ScalarOpBehavior::kZeroing, float>>(ctx, Variation{0}); 5293 test_vecop_vvvv<kVecWidth, UniOpVVVV::kMAddF64S, scalar_op_fmadd_fma<ScalarOpBehavior::kZeroing, double>>(ctx, Variation{0}); 5294 test_vecop_vvvv<kVecWidth, UniOpVVVV::kMSubF32S, scalar_op_fmsub_fma<ScalarOpBehavior::kZeroing, float>>(ctx, Variation{0}); 5295 test_vecop_vvvv<kVecWidth, UniOpVVVV::kMSubF64S, scalar_op_fmsub_fma<ScalarOpBehavior::kZeroing, double>>(ctx, Variation{0}); 5296 test_vecop_vvvv<kVecWidth, UniOpVVVV::kNMAddF32S, scalar_op_fnmadd_fma<ScalarOpBehavior::kZeroing, float>>(ctx, Variation{0}); 5297 test_vecop_vvvv<kVecWidth, UniOpVVVV::kNMAddF64S, scalar_op_fnmadd_fma<ScalarOpBehavior::kZeroing, double>>(ctx, Variation{0}); 5298 test_vecop_vvvv<kVecWidth, UniOpVVVV::kNMSubF32S, scalar_op_fnmsub_fma<ScalarOpBehavior::kZeroing, float>>(ctx, Variation{0}); 5299 test_vecop_vvvv<kVecWidth, UniOpVVVV::kNMSubF64S, scalar_op_fnmsub_fma<ScalarOpBehavior::kZeroing, double>>(ctx, Variation{0}); 5300 } 5301 else { 5302 test_vecop_vvvv<kVecWidth, UniOpVVVV::kMAddF32S, scalar_op_fmadd_fma<ScalarOpBehavior::kPreservingVec128, float>>(ctx, Variation{0}); 5303 test_vecop_vvvv<kVecWidth, UniOpVVVV::kMAddF64S, scalar_op_fmadd_fma<ScalarOpBehavior::kPreservingVec128, double>>(ctx, Variation{0}); 5304 test_vecop_vvvv<kVecWidth, UniOpVVVV::kMSubF32S, scalar_op_fmsub_fma<ScalarOpBehavior::kPreservingVec128, float>>(ctx, Variation{0}); 5305 test_vecop_vvvv<kVecWidth, UniOpVVVV::kMSubF64S, scalar_op_fmsub_fma<ScalarOpBehavior::kPreservingVec128, double>>(ctx, Variation{0}); 5306 test_vecop_vvvv<kVecWidth, UniOpVVVV::kNMAddF32S, scalar_op_fnmadd_fma<ScalarOpBehavior::kPreservingVec128, float>>(ctx, Variation{0}); 5307 test_vecop_vvvv<kVecWidth, UniOpVVVV::kNMAddF64S, scalar_op_fnmadd_fma<ScalarOpBehavior::kPreservingVec128, double>>(ctx, Variation{0}); 5308 test_vecop_vvvv<kVecWidth, UniOpVVVV::kNMSubF32S, scalar_op_fnmsub_fma<ScalarOpBehavior::kPreservingVec128, float>>(ctx, Variation{0}); 5309 test_vecop_vvvv<kVecWidth, UniOpVVVV::kNMSubF64S, scalar_op_fnmsub_fma<ScalarOpBehavior::kPreservingVec128, double>>(ctx, Variation{0}); 5310 } 5311 } 5312 5313 for (uint32_t v = 0; v < kNumVariationsVVVV; v++) { 5314 test_vecop_vvvv<kVecWidth, UniOpVVVV::kMAddF32, vec_op_fmadd_fma<float>>(ctx, Variation{v}); 5315 test_vecop_vvvv<kVecWidth, UniOpVVVV::kMAddF64, vec_op_fmadd_fma<double>>(ctx, Variation{v}); 5316 test_vecop_vvvv<kVecWidth, UniOpVVVV::kMSubF32, vec_op_fmsub_fma<float>>(ctx, Variation{v}); 5317 test_vecop_vvvv<kVecWidth, UniOpVVVV::kMSubF64, vec_op_fmsub_fma<double>>(ctx, Variation{v}); 5318 test_vecop_vvvv<kVecWidth, UniOpVVVV::kNMAddF32, vec_op_fnmadd_fma<float>>(ctx, Variation{v}); 5319 test_vecop_vvvv<kVecWidth, UniOpVVVV::kNMAddF64, vec_op_fnmadd_fma<double>>(ctx, Variation{v}); 5320 test_vecop_vvvv<kVecWidth, UniOpVVVV::kNMSubF32, vec_op_fnmsub_fma<float>>(ctx, Variation{v}); 5321 test_vecop_vvvv<kVecWidth, UniOpVVVV::kNMSubF64, vec_op_fnmsub_fma<double>>(ctx, Variation{v}); 5322 } 5323 } 5324 } 5325 5326 INFO(" Testing min / max (float)"); 5327 { 5328 #if defined(ASMJIT_UJIT_X86) 5329 test_vecop_vvv<kVecWidth, UniOpVVV::kMinF32S, scalar_op_fmin_ternary<ScalarOpBehavior::kPreservingVec128, float>>(ctx); 5330 test_vecop_vvv<kVecWidth, UniOpVVV::kMinF64S, scalar_op_fmin_ternary<ScalarOpBehavior::kPreservingVec128, double>>(ctx); 5331 test_vecop_vvv<kVecWidth, UniOpVVV::kMaxF32S, scalar_op_fmax_ternary<ScalarOpBehavior::kPreservingVec128, float>>(ctx); 5332 test_vecop_vvv<kVecWidth, UniOpVVV::kMaxF64S, scalar_op_fmax_ternary<ScalarOpBehavior::kPreservingVec128, double>>(ctx); 5333 5334 for (uint32_t v = 0; v < kNumVariationsVVV; v++) { 5335 test_vecop_vvv<kVecWidth, UniOpVVV::kMinF32, vec_op_fmin_ternary<float>>(ctx, Variation{v}); 5336 test_vecop_vvv<kVecWidth, UniOpVVV::kMinF64, vec_op_fmin_ternary<double>>(ctx, Variation{v}); 5337 test_vecop_vvv<kVecWidth, UniOpVVV::kMaxF32, vec_op_fmax_ternary<float>>(ctx, Variation{v}); 5338 test_vecop_vvv<kVecWidth, UniOpVVV::kMaxF64, vec_op_fmax_ternary<double>>(ctx, Variation{v}); 5339 } 5340 #endif 5341 5342 #if defined(ASMJIT_UJIT_AARCH64) 5343 test_vecop_vvv<kVecWidth, UniOpVVV::kMinF32S, scalar_op_fmin_finite<ScalarOpBehavior::kZeroing, float>>(ctx); 5344 test_vecop_vvv<kVecWidth, UniOpVVV::kMinF64S, scalar_op_fmin_finite<ScalarOpBehavior::kZeroing, double>>(ctx); 5345 test_vecop_vvv<kVecWidth, UniOpVVV::kMaxF32S, scalar_op_fmax_finite<ScalarOpBehavior::kZeroing, float>>(ctx); 5346 test_vecop_vvv<kVecWidth, UniOpVVV::kMaxF64S, scalar_op_fmax_finite<ScalarOpBehavior::kZeroing, double>>(ctx); 5347 5348 for (uint32_t v = 0; v < kNumVariationsVVV; v++) { 5349 test_vecop_vvv<kVecWidth, UniOpVVV::kMinF32, vec_op_fmin_finite<float>>(ctx, Variation{v}); 5350 test_vecop_vvv<kVecWidth, UniOpVVV::kMinF64, vec_op_fmin_finite<double>>(ctx, Variation{v}); 5351 test_vecop_vvv<kVecWidth, UniOpVVV::kMaxF32, vec_op_fmax_finite<float>>(ctx, Variation{v}); 5352 test_vecop_vvv<kVecWidth, UniOpVVV::kMaxF64, vec_op_fmax_finite<double>>(ctx, Variation{v}); 5353 } 5354 #endif 5355 } 5356 5357 INFO(" Testing cmp (float)"); 5358 { 5359 for (uint32_t v = 0; v < kNumVariationsVVV; v++) { 5360 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpEqF32, vec_op_fcmpo_eq<float>>(ctx, Variation{v}); 5361 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpEqF64, vec_op_fcmpo_eq<double>>(ctx, Variation{v}); 5362 5363 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpNeF32, vec_op_fcmpu_ne<float>>(ctx, Variation{v}); 5364 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpNeF64, vec_op_fcmpu_ne<double>>(ctx, Variation{v}); 5365 5366 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpGtF32, vec_op_fcmpo_gt<float>>(ctx, Variation{v}); 5367 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpGtF64, vec_op_fcmpo_gt<double>>(ctx, Variation{v}); 5368 5369 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpGeF32, vec_op_fcmpo_ge<float>>(ctx, Variation{v}); 5370 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpGeF64, vec_op_fcmpo_ge<double>>(ctx, Variation{v}); 5371 5372 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpLtF32, vec_op_fcmpo_lt<float>>(ctx, Variation{v}); 5373 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpLtF64, vec_op_fcmpo_lt<double>>(ctx, Variation{v}); 5374 5375 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpLeF32, vec_op_fcmpo_le<float>>(ctx, Variation{v}); 5376 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpLeF64, vec_op_fcmpo_le<double>>(ctx, Variation{v}); 5377 5378 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpOrdF32, vec_op_fcmp_ord<float>>(ctx, Variation{v}); 5379 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpOrdF64, vec_op_fcmp_ord<double>>(ctx, Variation{v}); 5380 5381 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpUnordF32, vec_op_fcmp_unord<float>>(ctx, Variation{v}); 5382 test_vecop_vvv<kVecWidth, UniOpVVV::kCmpUnordF64, vec_op_fcmp_unord<double>>(ctx, Variation{v}); 5383 } 5384 } 5385 5386 INFO(" Testing hadd (float)"); 5387 { 5388 for (uint32_t v = 0; v < kNumVariationsVVV; v++) { 5389 test_vecop_vvv<kVecWidth, UniOpVVV::kHAddF64, vec_op_hadd_f64>(ctx, Variation{v}); 5390 } 5391 } 5392 5393 INFO(" Testing combine"); 5394 { 5395 for (uint32_t v = 0; v < kNumVariationsVVV; v++) { 5396 test_vecop_vvv<kVecWidth, UniOpVVV::kCombineLoHiU64, vec_op_combine_lo_hi_u64>(ctx, Variation{v}); 5397 test_vecop_vvv<kVecWidth, UniOpVVV::kCombineLoHiF64, vec_op_combine_lo_hi_u64>(ctx, Variation{v}); 5398 test_vecop_vvv<kVecWidth, UniOpVVV::kCombineHiLoU64, vec_op_combine_hi_lo_u64>(ctx, Variation{v}); 5399 test_vecop_vvv<kVecWidth, UniOpVVV::kCombineHiLoF64, vec_op_combine_hi_lo_u64>(ctx, Variation{v}); 5400 } 5401 } 5402 5403 INFO(" Testing interleave"); 5404 { 5405 for (uint32_t v = 0; v < kNumVariationsVVV; v++) { 5406 test_vecop_vvv<kVecWidth, UniOpVVV::kInterleaveLoU8, vec_op_interleave_lo_u8>(ctx, Variation{v}); 5407 test_vecop_vvv<kVecWidth, UniOpVVV::kInterleaveHiU8, vec_op_interleave_hi_u8>(ctx, Variation{v}); 5408 test_vecop_vvv<kVecWidth, UniOpVVV::kInterleaveLoU16, vec_op_interleave_lo_u16>(ctx, Variation{v}); 5409 test_vecop_vvv<kVecWidth, UniOpVVV::kInterleaveHiU16, vec_op_interleave_hi_u16>(ctx, Variation{v}); 5410 test_vecop_vvv<kVecWidth, UniOpVVV::kInterleaveLoU32, vec_op_interleave_lo_u32>(ctx, Variation{v}); 5411 test_vecop_vvv<kVecWidth, UniOpVVV::kInterleaveHiU32, vec_op_interleave_hi_u32>(ctx, Variation{v}); 5412 test_vecop_vvv<kVecWidth, UniOpVVV::kInterleaveLoU64, vec_op_interleave_lo_u64>(ctx, Variation{v}); 5413 test_vecop_vvv<kVecWidth, UniOpVVV::kInterleaveHiU64, vec_op_interleave_hi_u64>(ctx, Variation{v}); 5414 } 5415 } 5416 5417 INFO(" Testing packs"); 5418 { 5419 for (uint32_t v = 0; v < kNumVariationsVVV; v++) { 5420 test_vecop_vvv<kVecWidth, UniOpVVV::kPacksI16_I8, vec_op_packs_i16_i8>(ctx, Variation{v}); 5421 test_vecop_vvv<kVecWidth, UniOpVVV::kPacksI16_U8, vec_op_packs_i16_u8>(ctx, Variation{v}); 5422 test_vecop_vvv<kVecWidth, UniOpVVV::kPacksI32_I16, vec_op_packs_i32_i16>(ctx, Variation{v}); 5423 test_vecop_vvv<kVecWidth, UniOpVVV::kPacksI32_U16, vec_op_packs_i32_u16>(ctx, Variation{v}); 5424 } 5425 } 5426 5427 INFO(" Testing alignr_u128"); 5428 { 5429 for (uint32_t v = 0; v < kNumVariationsVVVI; v++) { 5430 for (uint32_t i = 1; i < 16; i++) { 5431 test_vecop_vvvi<kVecWidth, UniOpVVVI::kAlignr_U128, vec_op_alignr_u128>(ctx, i, Variation{v}); 5432 } 5433 } 5434 } 5435 5436 INFO(" Testing interleave_shuffle"); 5437 { 5438 for (uint32_t v = 0; v < kNumVariationsVVVI; v++) { 5439 for (uint32_t i = 0; i < 256; i++) { 5440 uint32_t imm = swizzle((i >> 6) & 3, (i >> 4) & 3, (i >> 2) & 3, i & 3).value; 5441 5442 test_vecop_vvvi<kVecWidth, UniOpVVVI::kInterleaveShuffleU32x4, vec_op_interleave_shuffle_u32x4>(ctx, imm, Variation{v}); 5443 test_vecop_vvvi<kVecWidth, UniOpVVVI::kInterleaveShuffleF32x4, vec_op_interleave_shuffle_u32x4>(ctx, imm, Variation{v}); 5444 } 5445 5446 for (uint32_t i = 0; i < 4; i++) { 5447 uint32_t imm = swizzle((i >> 1) & 1, i & 1).value; 5448 5449 test_vecop_vvvi<kVecWidth, UniOpVVVI::kInterleaveShuffleU64x2, vec_op_interleave_shuffle_u64x2>(ctx, imm, Variation{v}); 5450 test_vecop_vvvi<kVecWidth, UniOpVVVI::kInterleaveShuffleF64x2, vec_op_interleave_shuffle_u64x2>(ctx, imm, Variation{v}); 5451 } 5452 } 5453 } 5454 } 5455 5456 static void test_gp_ops(JitContext& ctx) { 5457 test_cond_ops(ctx); 5458 test_m_ops(ctx); 5459 test_rm_ops(ctx); 5460 test_mr_ops(ctx); 5461 test_rr_ops(ctx); 5462 test_rrr_ops(ctx); 5463 } 5464 5465 #if defined(ASMJIT_UJIT_X86) 5466 static void dump_feature_list(String& out, const CpuFeatures& features) { 5467 #if !defined(ASMJIT_NO_LOGGING) 5468 CpuFeatures::Iterator it = features.iterator(); 5469 bool first = true; 5470 while (it.has_next()) { 5471 size_t feature_id = it.next(); 5472 if (!first) { 5473 out.append(' '); 5474 } 5475 Formatter::format_feature(out, Arch::kHost, uint32_t(feature_id)); 5476 first = false; 5477 } 5478 #else 5479 Support::maybe_unused(features); 5480 out.append("<ASMJIT_NO_LOGGING>"); 5481 #endif 5482 } 5483 5484 static void test_x86_ops(JitContext& ctx, const CpuFeatures& host_features) { 5485 using Ext = CpuFeatures::X86; 5486 5487 { 5488 String s; 5489 dump_feature_list(s, host_features); 5490 INFO("Available CPU features: %s", s.data()); 5491 } 5492 5493 // Features that must always be available; 5494 CpuFeatures base; 5495 base.add(Ext::kI486, Ext::kCMOV, Ext::kCMPXCHG8B, Ext::kFPU, Ext::kSSE, Ext::kSSE2); 5496 5497 // To verify that JIT implements ALL features with ALL possible CPU flags, we use profiles to select features 5498 // that the JIT compiler will be allowed to use. The features are gradually increased similarly to how new CPU 5499 // generations introduced them. We cannot cover ALL possible CPUs, but that's not even necessary as we test 5500 // individual operations where instructions can be selected on the features available. 5501 5502 // GP variations. 5503 { 5504 CpuFeatures profiles[4] {}; 5505 profiles[0] = base; 5506 5507 profiles[1] = profiles[0]; 5508 profiles[1].add(Ext::kADX, Ext::kBMI); 5509 5510 profiles[2] = profiles[1]; 5511 profiles[2].add(Ext::kBMI2, Ext::kLZCNT, Ext::kMOVBE, Ext::kPOPCNT); 5512 5513 profiles[3] = host_features; 5514 5515 bool first = true; 5516 CpuFeatures last_filtered; 5517 5518 for (const CpuFeatures& profile : profiles) { 5519 CpuFeatures filtered = profile; 5520 5521 for (uint32_t i = 0; i < CpuFeatures::kNumBitWords; i++) { 5522 filtered.data()._bits[i] &= host_features.data()._bits[i]; 5523 } 5524 5525 if (!first && filtered == last_filtered) { 5526 continue; 5527 } 5528 5529 String s; 5530 if (filtered == host_features) { 5531 s.assign("[ALL]"); 5532 } 5533 else { 5534 dump_feature_list(s, filtered); 5535 } 5536 5537 ctx.features = filtered; 5538 5539 INFO("Testing JIT compiler GP ops with [%s]", s.data()); 5540 test_gp_ops(ctx); 5541 5542 first = false; 5543 last_filtered = filtered; 5544 } 5545 } 5546 5547 // SIMD variations covering SSE2+, AVX+, and AVX512+ cases. 5548 { 5549 CpuFeatures profiles[15] {}; 5550 profiles[0] = base; 5551 5552 profiles[1] = profiles[0]; 5553 profiles[1].add(Ext::kSSE3); 5554 5555 profiles[2] = profiles[1]; 5556 profiles[2].add(Ext::kSSSE3); 5557 5558 profiles[3] = profiles[2]; 5559 profiles[3].add(Ext::kSSE4_1); 5560 5561 profiles[4] = profiles[3]; 5562 profiles[4].add(Ext::kSSE4_2, Ext::kADX, Ext::kBMI, Ext::kBMI2, Ext::kLZCNT, Ext::kMOVBE, Ext::kPOPCNT); 5563 5564 profiles[5] = profiles[4]; 5565 profiles[5].add(Ext::kPCLMULQDQ); 5566 5567 profiles[6] = profiles[5]; 5568 profiles[6].add(Ext::kAVX); 5569 5570 profiles[7] = profiles[6]; 5571 profiles[7].add(Ext::kAVX2); 5572 5573 profiles[8] = profiles[7]; 5574 profiles[8].add(Ext::kF16C, Ext::kFMA, Ext::kVAES, Ext::kVPCLMULQDQ); 5575 5576 profiles[9] = profiles[8]; 5577 profiles[9].add(Ext::kAVX_IFMA, Ext::kAVX_NE_CONVERT, Ext::kAVX_VNNI, Ext::kAVX_VNNI_INT8, Ext::kAVX_VNNI_INT16); 5578 5579 // We start deliberately from a profile that doesn't contains AVX_xxx 5580 // extensions as these didn't exist when the first AVX512 CPUs were shipped. 5581 profiles[10] = profiles[8]; 5582 profiles[10].add(Ext::kAVX512_F, Ext::kAVX512_BW, Ext::kAVX512_DQ, Ext::kAVX512_CD, Ext::kAVX512_VL); 5583 5584 profiles[11] = profiles[10]; 5585 profiles[11].add(Ext::kAVX512_IFMA, Ext::kAVX512_VBMI); 5586 5587 profiles[12] = profiles[11]; 5588 profiles[12].add(Ext::kAVX512_BITALG, Ext::kAVX512_VBMI2, Ext::kAVX512_VNNI, Ext::kAVX512_VPOPCNTDQ); 5589 5590 profiles[13] = profiles[12]; 5591 profiles[13].add(Ext::kAVX512_BF16, Ext::kAVX512_FP16); 5592 5593 profiles[14] = host_features; 5594 5595 bool first = true; 5596 CpuFeatures last_filtered; 5597 5598 for (const CpuFeatures& profile : profiles) { 5599 CpuFeatures filtered = profile; 5600 5601 for (uint32_t i = 0; i < CpuFeatures::kNumBitWords; i++) { 5602 filtered.data()._bits[i] &= host_features.data()._bits[i]; 5603 } 5604 5605 if (!first && filtered == last_filtered) { 5606 continue; 5607 } 5608 5609 String s; 5610 if (filtered == host_features) { 5611 s.assign("[ALL]"); 5612 } 5613 else { 5614 dump_feature_list(s, filtered); 5615 } 5616 5617 ctx.features = filtered; 5618 5619 INFO("Testing JIT compiler 128-bit SIMD ops with [%s]", s.data()); 5620 test_simd_ops<VecWidth::k128>(ctx); 5621 5622 if (filtered.x86().has_avx2()) { 5623 INFO("Testing JIT compiler 256-bit SIMD ops with [%s]", s.data()); 5624 test_simd_ops<VecWidth::k256>(ctx); 5625 } 5626 5627 if (filtered.x86().has_avx512_f()) { 5628 INFO("Testing JIT compiler 512-bit SIMD ops with [%s]", s.data()); 5629 test_simd_ops<VecWidth::k512>(ctx); 5630 } 5631 5632 first = false; 5633 last_filtered = filtered; 5634 } 5635 } 5636 } 5637 #endif // ASMJIT_UJIT_X86 5638 5639 #if defined(ASMJIT_UJIT_AARCH64) 5640 static void test_a64_ops(JitContext& ctx, const CpuFeatures& host_features) { 5641 ctx.features = host_features; 5642 5643 test_gp_ops(ctx); 5644 test_simd_ops<VecWidth::k128>(ctx); 5645 } 5646 #endif // ASMJIT_UJIT_AARCH64 5647 5648 } // {UniCompilerTests} 5649 5650 UNIT(unicompiler) { 5651 UniCompilerTests::JitContext ctx; 5652 asmjit::CpuFeatures host_features = asmjit::CpuInfo::host().features(); 5653 5654 #if defined(ASMJIT_UJIT_X86) 5655 UniCompilerTests::test_x86_ops(ctx, host_features); 5656 #elif defined(ASMJIT_UJIT_AARCH64) 5657 UniCompilerTests::test_a64_ops(ctx, host_features); 5658 #endif 5659 } 5660 5661 int main(int argc, const char* argv[]) { 5662 print_app_info(); 5663 return BrokenAPI::run(argc, argv); 5664 } 5665 5666 #else 5667 5668 int main() { 5669 print_app_info(); 5670 printf("!! This test is disabled: <ASMJIT_NO_[U]JIT> or unsuitable arvhitecture !!\n"); 5671 return 0; 5672 } 5673 5674 #endif // !ASMJIT_NO_UJIT && !ASMJIT_NO_JIT