odin-blend2d

Odin bindings to Blend2D
Log | Files | Refs | README | LICENSE

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