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