odin-blend2d

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

asmjit_test_misc.h (6543B)


      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 #ifndef ASMJIT_TEST_MISC_H_INCLUDED
      7 #define ASMJIT_TEST_MISC_H_INCLUDED
      8 
      9 #include <asmjit/x86.h>
     10 
     11 namespace asmtest {
     12 
     13 using namespace asmjit;
     14 
     15 // Generates a typical alpha blend function that uses SSE2 instruction set.
     16 // This function combines emitting instructions with control flow constructs
     17 // like binding Labels and jumping to them. This should be pretty representative.
     18 template<typename Emitter>
     19 static void generate_sse_alpha_blend_internal(
     20   Emitter& cc,
     21   const x86::Gp& dst, const x86::Gp& src, const x86::Gp& n,
     22   const x86::Gp& gp0,
     23   const x86::Vec& simd0, const x86::Vec& simd1, const x86::Vec& simd2, const x86::Vec& simd3,
     24   const x86::Vec& simd4, const x86::Vec& simd5, const x86::Vec& simd6, const x86::Vec& simd7) {
     25 
     26   x86::Gp i = n;
     27   x86::Gp j = gp0;
     28 
     29   x86::Vec vzero = simd0;
     30   x86::Vec v0080 = simd1;
     31   x86::Vec v0101 = simd2;
     32 
     33   Label L_SmallLoop = cc.new_label();
     34   Label L_SmallEnd  = cc.new_label();
     35   Label L_LargeLoop = cc.new_label();
     36   Label L_LargeEnd  = cc.new_label();
     37   Label L_Done = cc.new_label();
     38 
     39   // Load SIMD Constants.
     40   cc.xorps(vzero, vzero);
     41   cc.mov(gp0.r32(), 0x00800080);
     42   cc.movd(v0080, gp0.r32());
     43   cc.mov(gp0.r32(), 0x01010101);
     44   cc.movd(v0101, gp0.r32());
     45   cc.pshufd(v0080, v0080, x86::shuffle_imm(0, 0, 0, 0));
     46   cc.pshufd(v0101, v0101, x86::shuffle_imm(0, 0, 0, 0));
     47 
     48   // How many pixels have to be processed to make the loop aligned.
     49   cc.xor_(j, j);
     50   cc.sub(j, dst);
     51   cc.and_(j, 15);
     52   cc.shr(j, 2);
     53   cc.jz(L_SmallEnd);
     54 
     55   cc.cmp(j, i);
     56   cc.cmovg(j, i); // j = min(i, j)
     57   cc.sub(i, j);   // i -= j
     58 
     59   // Small loop.
     60   cc.bind(L_SmallLoop);
     61   {
     62     x86::Vec x0 = simd3;
     63     x86::Vec y0 = simd4;
     64     x86::Vec a0 = simd5;
     65 
     66     cc.movd(y0, x86::ptr(src));
     67     cc.movd(x0, x86::ptr(dst));
     68 
     69     cc.pcmpeqb(a0, a0);
     70     cc.pxor(a0, y0);
     71     cc.psrlw(a0, 8);
     72     cc.punpcklbw(x0, vzero);
     73 
     74     cc.pshuflw(a0, a0, x86::shuffle_imm(1, 1, 1, 1));
     75     cc.punpcklbw(y0, vzero);
     76 
     77     cc.pmullw(x0, a0);
     78     cc.paddsw(x0, v0080);
     79     cc.pmulhuw(x0, v0101);
     80 
     81     cc.paddw(x0, y0);
     82     cc.packuswb(x0, x0);
     83 
     84     cc.movd(x86::ptr(dst), x0);
     85 
     86     cc.add(dst, 4);
     87     cc.add(src, 4);
     88 
     89     cc.dec(j);
     90     cc.jnz(L_SmallLoop);
     91   }
     92 
     93   // Second section, prepare for an aligned loop.
     94   cc.bind(L_SmallEnd);
     95 
     96   cc.test(i, i);
     97   cc.mov(j, i);
     98   cc.jz(L_Done);
     99 
    100   cc.and_(j, 3);
    101   cc.shr(i, 2);
    102   cc.jz(L_LargeEnd);
    103 
    104   // Aligned loop.
    105   cc.bind(L_LargeLoop);
    106   {
    107     x86::Vec x0 = simd3;
    108     x86::Vec x1 = simd4;
    109     x86::Vec y0 = simd5;
    110     x86::Vec a0 = simd6;
    111     x86::Vec a1 = simd7;
    112 
    113     cc.movups(y0, x86::ptr(src));
    114     cc.movaps(x0, x86::ptr(dst));
    115 
    116     cc.pcmpeqb(a0, a0);
    117     cc.xorps(a0, y0);
    118     cc.movaps(x1, x0);
    119 
    120     cc.psrlw(a0, 8);
    121     cc.punpcklbw(x0, vzero);
    122 
    123     cc.movaps(a1, a0);
    124     cc.punpcklwd(a0, a0);
    125 
    126     cc.punpckhbw(x1, vzero);
    127     cc.punpckhwd(a1, a1);
    128 
    129     cc.pshufd(a0, a0, x86::shuffle_imm(3, 3, 1, 1));
    130     cc.pshufd(a1, a1, x86::shuffle_imm(3, 3, 1, 1));
    131 
    132     cc.pmullw(x0, a0);
    133     cc.pmullw(x1, a1);
    134 
    135     cc.paddsw(x0, v0080);
    136     cc.paddsw(x1, v0080);
    137 
    138     cc.pmulhuw(x0, v0101);
    139     cc.pmulhuw(x1, v0101);
    140 
    141     cc.add(src, 16);
    142     cc.packuswb(x0, x1);
    143 
    144     cc.paddw(x0, y0);
    145     cc.movaps(x86::ptr(dst), x0);
    146 
    147     cc.add(dst, 16);
    148 
    149     cc.dec(i);
    150     cc.jnz(L_LargeLoop);
    151   }
    152 
    153   cc.bind(L_LargeEnd);
    154   cc.test(j, j);
    155   cc.jnz(L_SmallLoop);
    156 
    157   cc.bind(L_Done);
    158 }
    159 
    160 static void generate_sse_alpha_blend(asmjit::BaseEmitter& emitter, bool emit_prolog_epilog) {
    161   using namespace asmjit::x86;
    162 
    163 #ifndef ASMJIT_NO_COMPILER
    164   if (emitter.is_compiler()) {
    165     Compiler& cc = *emitter.as<Compiler>();
    166 
    167     Gp dst = cc.new_gp_ptr("dst");
    168     Gp src = cc.new_gp_ptr("src");
    169     Gp i = cc.new_gp_ptr("i");
    170     Gp j = cc.new_gp_ptr("j");
    171 
    172     Vec v0 = cc.new_xmm("v0");
    173     Vec v1 = cc.new_xmm("v1");
    174     Vec v2 = cc.new_xmm("v2");
    175     Vec v3 = cc.new_xmm("v3");
    176     Vec v4 = cc.new_xmm("v4");
    177     Vec v5 = cc.new_xmm("v5");
    178     Vec v6 = cc.new_xmm("v6");
    179     Vec v7 = cc.new_xmm("v7");
    180 
    181     FuncNode* func_node = cc.add_func(FuncSignature::build<void, void*, const void*, size_t>());
    182     func_node->set_arg(0, dst);
    183     func_node->set_arg(1, src);
    184     func_node->set_arg(2, i);
    185     generate_sse_alpha_blend_internal(cc, dst, src, i, j, v0, v1, v2, v3, v4, v5, v6, v7);
    186     cc.end_func();
    187 
    188     return;
    189   }
    190 #endif
    191 
    192 #ifndef ASMJIT_NO_BUILDER
    193   if (emitter.is_builder()) {
    194     Builder& cc = *emitter.as<Builder>();
    195 
    196     x86::Gp dst = cc.zax();
    197     x86::Gp src = cc.zcx();
    198     x86::Gp i = cc.zdx();
    199     x86::Gp j = cc.zdi();
    200 
    201     if (emit_prolog_epilog) {
    202       FuncDetail func;
    203       func.init(FuncSignature::build<void, void*, const void*, size_t>(), cc.environment());
    204 
    205       FuncFrame frame;
    206       frame.init(func);
    207       frame.add_dirty_regs(dst, src, i, j);
    208       frame.add_dirty_regs(xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7);
    209 
    210       FuncArgsAssignment args(&func);
    211       args.assign_all(dst, src, i);
    212       args.update_func_frame(frame);
    213       frame.finalize();
    214 
    215       cc.emit_prolog(frame);
    216       cc.emit_args_assignment(frame, args);
    217       generate_sse_alpha_blend_internal(cc, dst, src, i, j, xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7);
    218       cc.emit_epilog(frame);
    219     }
    220     else {
    221       generate_sse_alpha_blend_internal(cc, dst, src, i, j, xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7);
    222     }
    223 
    224     return;
    225   }
    226 #endif
    227 
    228   if (emitter.is_assembler()) {
    229     Assembler& cc = *emitter.as<Assembler>();
    230 
    231     x86::Gp dst = cc.zax();
    232     x86::Gp src = cc.zcx();
    233     x86::Gp i = cc.zdx();
    234     x86::Gp j = cc.zdi();
    235 
    236     if (emit_prolog_epilog) {
    237       FuncDetail func;
    238       func.init(FuncSignature::build<void, void*, const void*, size_t>(), cc.environment());
    239 
    240       FuncFrame frame;
    241       frame.init(func);
    242       frame.add_dirty_regs(dst, src, i, j);
    243       frame.add_dirty_regs(xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7);
    244 
    245       FuncArgsAssignment args(&func);
    246       args.assign_all(dst, src, i);
    247       args.update_func_frame(frame);
    248       frame.finalize();
    249 
    250       cc.emit_prolog(frame);
    251       cc.emit_args_assignment(frame, args);
    252       generate_sse_alpha_blend_internal(cc, dst, src, i, j, xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7);
    253       cc.emit_epilog(frame);
    254     }
    255     else {
    256       generate_sse_alpha_blend_internal(cc, dst, src, i, j, xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7);
    257     }
    258 
    259     return;
    260   }
    261 }
    262 
    263 } // {asmtest}
    264 
    265 #endif // ASMJIT_TEST_MISC_H_INCLUDED