Go to the documentation of this file.
27 #define LOOP_VH(s, mask, idx) if (s->use_vh) LOOP(mask, idx)
28 #define LOOP_MASK_VH(s, p, idx) if (s->use_vh) LOOP_MASK(p, idx)
29 #define LOOP_MASK_BWD_VH(s, p, idx) if (s->use_vh) LOOP_MASK_BWD(p, idx)
32 #define CMT(comment) rasm_annotate(r, comment)
33 #define CMTF(fmt, ...) rasm_annotatef(r, (char[128]){0}, 128, fmt, __VA_ARGS__)
38 for (
int i = 0;
i < 4;
i++) {
65 return ((n + 1) >> 1) * 16;
81 i_stp(
r, regs[0], regs[1], sp_pre);
82 for (
unsigned i = 2;
i + 1 < n;
i += 2)
100 i_ldr(
r, regs[0], sp_post);
104 for (
unsigned i = (n & ~1
u) - 2;
i >= 2;
i -= 2)
106 i_ldp(
r, regs[0], regs[1], sp_post);
112 #define MAX_SAVED_REGS 12
118 if (n >= 19 && n <= 30)
119 regs[(*count)++] = gpr;
165 LOOP(imask,
i) {
i_ldr(
r,
s->in_bump[
i], exec_in_bump[
i]);
CMTF(
"in_bump[%u] = exec->in_bump[%u];",
i,
i); }
166 LOOP(omask,
i) {
i_ldr(
r,
s->out_bump[
i], exec_out_bump[
i]);
CMTF(
"out_bump[%u] = exec->out_bump[%u];",
i,
i); }
185 i_mov(
r,
s->bx,
s->bx_start);
CMT(
"bx = bx_start;");
193 i_cmp(
r,
s->bx,
s->bx_end);
CMT(
"if (bx != bx_end)");
194 i_bne(
r, next_block);
CMT(
" goto next_block;");
199 i_bne(
r, next_row);
CMT(
" goto next_row;");
228 if (
p->block_size == 16) {
230 i_dup (
r, dl[0].b8, wtmp);
CMT(
"vl[0].lo = broadcast(tmp);");
232 i_dup (
r, vtmp.
b8, wtmp);
CMT(
"vtmp.lo = broadcast(tmp);");
233 i_ins (
r, dl[0].de[1], vtmp.
de[0]);
CMT(
"vl[0].hi = vtmp.lo;");
234 i_ushl(
r, dl[0].b16, dl[0].b16, shift_vec.
b16);
CMT(
"vl[0] <<= shift_vec;");
235 i_and (
r, dl[0].b16, dl[0].b16, bitmask_vec.
b16);
CMT(
"vl[0] &= bitmask_vec;");
238 i_dup (
r, dl[0].b8, wtmp);
CMT(
"vl[0].lo = broadcast(tmp);");
239 i_ushl(
r, dl[0].b8, dl[0].b8, shift_vec.
b8);
CMT(
"vl[0] <<= shift_vec;");
240 i_and (
r, dl[0].b8, dl[0].b8, bitmask_vec.
b8);
CMT(
"vl[0] &= bitmask_vec;");
253 if (
p->block_size == 8) {
294 switch ((
s->use_vh ? 0x100 : 0) |
s->vec_size) {
320 if (
p->block_size == 8) {
321 i_ushl(
r, sl[0].b8, sl[0].b8, shift_vec.
b8);
CMT(
"vl[0] <<= shift_vec;");
322 i_addv(
r, vtmp0.
b, sl[0].
b8);
CMT(
"vtmp0[0] = add_across(vl[0].lo);");
325 i_ushl(
r, sl[0].b16, sl[0].b16, shift_vec.
b16);
CMT(
"vl[0] <<= shift_vec;");
326 i_addv(
r, vtmp0.
b, sl[0].
b8);
CMT(
"vtmp0[0] = add_across(vl[0].lo);");
327 i_ins (
r, vtmp1.
de[0], sl[0].
de[1]);
CMT(
"vtmp1.lo = vl[0].hi;");
328 i_addv(
r, vtmp1.
b, vtmp1.
b8);
CMT(
"vtmp1[0] = add_across(vtmp1);");
329 i_ins (
r, vtmp0.
be[1], vtmp1.
be[0]);
CMT(
"vtmp0[1] = vtmp1[0];");
342 if (
p->block_size == 8) {
385 switch ((
s->use_vh ? 0x100 : 0) |
s->vec_size) {
408 case sizeof(uint16_t):
412 case sizeof(uint32_t):
427 snprintf(buf,
sizeof(
char[8]),
"vtmp%c", vh ?
'h' :
'l');
429 snprintf(buf,
sizeof(
char[8]),
"v%c[%u]", vh ?
'h' :
'l', n);
432 #define PRINT_SWIZZLE_V(n, vh) print_swizzle_v((char[8]){ 0 }, n, vh)
439 return dst ? regs->
dh[n] : regs->
sh[n];
440 return dst ? regs->
dl[n] : regs->
sl[n];
459 for (
int i = 0;
i <
p->par.move.num_moves;
i++)
478 p->par.pack.pattern[3] +
p->par.pack.pattern[2] +
p->par.pack.pattern[1],
479 p->par.pack.pattern[3] +
p->par.pack.pattern[2],
480 p->par.pack.pattern[3],
519 p->par.pack.pattern[3] +
p->par.pack.pattern[2] +
p->par.pack.pattern[1],
520 p->par.pack.pattern[3] +
p->par.pack.pattern[2],
521 p->par.pack.pattern[3],
533 LOOP (offset_mask,
i) { sl[
i] = dl[
i]; }
537 for (
int i = 0;
i < 4;
i++) {
560 uint8_t
shift =
p->par.shift.amount;
578 uint8_t
shift =
p->par.shift.amount;
606 CMTF(
"%s[%u] = UINT_MAX;", vx_str,
i);
645 size_t src_el_size =
s->el_size;
667 memcpy(sl, dl,
sizeof(sl));
668 memcpy(sh, dh,
sizeof(sh));
671 if (
p->block_size == 8) {
672 if (src_el_size == 1 && dst_el_size > src_el_size) {
675 memcpy(sl, dl,
sizeof(sl));
677 }
else if (src_el_size == 4 && dst_el_size < src_el_size) {
682 memcpy(sl, dl,
sizeof(sl));
683 memcpy(sh, dh,
sizeof(sh));
686 if (src_el_size == 2 && dst_el_size == 4) {
690 memcpy(sl, dl,
sizeof(sl));
691 memcpy(sh, dh,
sizeof(sh));
693 }
else if (src_el_size == 2 && dst_el_size == 1) {
696 memcpy(sl, dl,
sizeof(sl));
700 if (src_el_size == 1 && dst_el_size == 2) {
704 memcpy(sl, dl,
sizeof(sl));
705 memcpy(sh, dh,
sizeof(sh));
706 }
else if (src_el_size == 2 && dst_el_size == 1) {
711 memcpy(sl, dl,
sizeof(sl));
736 size_t src_el_size =
s->el_size;
746 size_t dst_total_size =
p->block_size * dst_el_size;
747 size_t dst_vec_size =
FFMIN(dst_total_size, 16);
750 s->use_vh = (dst_vec_size != dst_total_size);
752 if (src_el_size == 1) {
759 if (dst_el_size == 4) {
853 char cvh = vh_pass ?
'h' :
'l';
855 if (vh_pass && !
s->use_vh)
866 for (
int j = 0; j < 5; j++) {
867 bool is_offset = (j == 0);
868 int src_j = is_offset ? 4 : (j - 1);
873 if (
first && is_offset) {
874 i_dup (
r, dx[
i], vcoeff);
CMTF(
"v%c[%u] = broadcast(offset[%u]);", cvh,
i,
i);
875 }
else if (
first && !is_offset) {
877 i_mov16b(
r, dx[
i], vsrc);
CMTF(
"v%c[%u] = vsrc%c[%u];", cvh,
i, cvh, src_j);
879 i_fmul (
r, dx[
i], vsrc, vcoeff);
CMTF(
"v%c[%u] = vsrc%c[%u] * coeff[%u][%u];", cvh,
i, cvh, src_j,
i, src_j);
887 i_fmla(
r, dx[
i], vsrc, vcoeff);
CMTF(
"v%c[%u] += vsrc%c[%u] * coeff[%u][%u];", cvh,
i, cvh, src_j,
i, src_j);
898 i_fmul(
r, vtmp[src_j], vsrc, vcoeff);
CMTF(
"vtmp[%u] = vsrc%c[%u] * coeff[%u][%u];", src_j, cvh, src_j,
i, src_j);
900 i_fadd(
r, dx[
i], dx[
i], vtmp[src_j]);
CMTF(
"v%c[%u] += vtmp[%u];", cvh,
i, src_j);
902 i_fadd(
r, dx[
i], dx[
i], vsrc);
CMTF(
"v%c[%u] += vsrc%c[%u];", cvh,
i, cvh, src_j);
959 max_offset =
FFMAX(max_offset,
p->par.dither.y_offset[
i]);
960 for (
int y_off = 0; y_off <= max_offset; y_off++) {
962 if (
p->par.dither.y_offset[
i] == y_off)
963 sorted[n_comps++] =
i;
987 const int block_size_log2 = (
p->block_size == 16) ? 4 : 3;
988 const int dither_size_log2 =
p->par.dither.size_log2;
989 const int sizeof_float_log2 = 2;
990 if (dither_size_log2 != block_size_log2) {
991 RasmOp lsb =
IMM(block_size_log2 + sizeof_float_log2);
993 i_ubfiz(
r, tmp1, bx64, lsb,
width);
CMT(
"tmp1 = (bx & ((dither_size / block_size) - 1)) * block_size * sizeof(float);");
994 i_add (
r, ptr, src_ptr, tmp1);
CMT(
"ptr += tmp1;");
1000 for (
int sorted_i = 0; sorted_i < n_comps; sorted_i++) {
1001 int i = sorted[sorted_i];
1002 uint8_t y_off =
p->par.dither.y_offset[
i];
1003 bool do_load = (y_off != last_y_off);
1005 if (last_y_off < 0) {
1007 RasmOp lsb =
IMM(dither_size_log2 + sizeof_float_log2);
1014 i_ubfiz(
r, tmp1, y64, lsb,
width);
CMT(
"tmp1 = (y & (dither_size - 1)) * dither_size * sizeof(float);");
1017 i_ubfiz(
r, tmp1, tmp1, lsb,
width);
CMT(
"tmp1 = (tmp1 & (dither_size - 1)) * dither_size * sizeof(float);");
1019 i_add(
r, ptr, src_ptr, tmp1);
CMT(
"ptr += tmp1;");
1020 }
else if (do_load) {
1026 int delta = (y_off - last_y_off) * (1 << dither_size_log2) *
sizeof(
float);
1027 i_add(
r, ptr, ptr,
IMM(
delta));
CMTF(
"ptr += (y_off[%u] - y_off[%u]) * dither_size * sizeof(float);",
i, prev_i);
1036 i_fadd (
r, dl[
i], sl[
i], dither_vl);
CMTF(
"vl[%u] += vditherl;",
i);
1038 i_fadd(
r, dh[
i], sh[
i], dither_vh);
CMTF(
"vh[%u] += vditherh;",
i);
#define LOOP_MASK_BWD_VH(s, p, idx)
#define LOOP_MASK_BWD(p, idx)
static RasmOp a64op_base(RasmOp op)
#define i_zip1(rctx, op0, op1, op2)
#define i_ld4(rctx, op0, op1)
#define i_mul(rctx, op0, op1, op2)
static RasmOp a64op_w(RasmOp op)
static void clobber_gpr(RasmOp regs[MAX_SAVED_REGS], unsigned *count, RasmOp gpr)
RasmNode * rasm_set_current_node(RasmContext *rctx, RasmNode *node)
#define i_st4(rctx, op0, op1)
#define u(width, name, range_min, range_max)
This helper structure is used to mimic the assembler syntax for vector register modifiers.
RasmNode * rasm_get_current_node(RasmContext *rctx)
#define i_ld3(rctx, op0, op1)
static RasmOp vv_2(RasmOp op0, RasmOp op1)
static void asmgen_op_read_bit(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
static RasmOp vv_3(RasmOp op0, RasmOp op1, RasmOp op2)
#define PRINT_SWIZZLE_V(n, vh)
static void reshape_temp_vectors(SwsAArch64OpRegs *regs, int el_count, int el_size)
#define i_dup(rctx, op0, op1)
#define A64OP_VEC_VIEWS4(op)
#define i_ld2(rctx, op0, op1)
#define i_fmla(rctx, op0, op1, op2)
#define i_rev16(rctx, op0, op1)
static void asmgen_op_write_nibble(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
static void reshape_const_vectors(SwsAArch64OpRegs *regs, int el_count, int el_size)
static const char * print_swizzle_v(char buf[8], int8_t n, uint8_t vh)
#define i_fmin(rctx, op0, op1, op2)
static uint8_t a64op_vec_n(RasmOp op)
#define LOOP_MASK_VH(s, p, idx)
static void asmgen_op_write_bit(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
#define i_st2(rctx, op0, op1)
#define i_st3(rctx, op0, op1)
#define i_ushr(rctx, op0, op1, op2)
Runtime assembler for AArch64.
#define i_addv(rctx, op0, op1)
static void asmgen_op_convert(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
RasmNode * rasm_add_label(RasmContext *rctx, int id)
#define SWS_COMP_ELEMS(N)
#define i_fadd(rctx, op0, op1, op2)
trying all byte sequences megabyte in length and selecting the best looking sequence will yield cases to try But first
static RasmOp a64op_elem(RasmOp op, uint8_t idx)
#define FF_ARRAY_ELEMS(a)
static void asmgen_op_lshift(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
static const int offsets[]
#define i_orr16b(rctx, op0, op1, op2)
#define av_assert0(cond)
assert() equivalent, that is always enabled.
static void asmgen_op_rshift(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
uint8_t SwsCompMask
Bit-mask of components.
static void asmgen_op_swap_bytes(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
#define i_ins(rctx, op0, op1)
static RasmOp v_8b(RasmOp op)
#define i_ldr(rctx, op0, op1)
static void reshape_io_vectors(SwsAArch64OpRegs *regs, int el_count, int el_size)
static RasmOp a64op_make_vec(uint8_t n, uint8_t el_count, uint8_t el_size)
static av_const int ff_sws_pixel_type_size(SwsPixelType type)
static void asmgen_op_write_packed(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
#define i_cmp(rctx, op0, op1)
#define offsetof_exec_out_bump
static void asmgen_op_read_planar(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
#define i_fmul(rctx, op0, op1, op2)
static void asmgen_op_write_packed_n(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, RasmOp *vx)
static RasmOp a64op_post(RasmOp op, int16_t imm)
#define i_umin(rctx, op0, op1, op2)
#define LOOP_VH(s, mask, idx)
#define offsetof_exec_out
static void asmgen_op_clear(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
#define i_add(rctx, op0, op1, op2)
int rasm_new_label(RasmContext *rctx, const char *name)
Allocate a new label ID with the given name.
static void asmgen_op_pack(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
static RasmOp a64op_sp(void)
#define i_uxtl(rctx, op0, op1)
static void linear_pass(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs, bool vh_pass)
static void asmgen_op_min(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
#define LOOP_MASK(p, idx)
static int shift(int a, int b)
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
static unsigned clobbered_gprs(const SwsAArch64Context *s, SwsCompMask imask, SwsCompMask omask, RasmOp regs[MAX_SAVED_REGS])
#define i(width, name, range_min, range_max)
#define i_ldrb(rctx, op0, op1)
#define i_shl(rctx, op0, op1, op2)
#define i_fmax(rctx, op0, op1, op2)
#define i_zip2(rctx, op0, op1, op2)
#define i_fcvtzu(rctx, op0, op1)
static void asmgen_op_read_packed_n(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, RasmOp *vx)
#define i_ucvtf(rctx, op0, op1)
static RasmOp a64op_off(RasmOp op, int16_t imm)
static void asmgen_op_dither(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
#define i_uxtl2(rctx, op0, op1)
AArch64VecViews a64op_vec_views(RasmOp op)
static void asmgen_op_move(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
static void asmgen_op_max(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
static RasmOp vv_4(RasmOp op0, RasmOp op1, RasmOp op2, RasmOp op3)
#define i_lsr(rctx, op0, op1, op2)
static unsigned clobbered_frame_size(unsigned n)
#define i_ldp(rctx, op0, op1, op2)
static void swizzle_emit(SwsAArch64Context *s, SwsAArch64OpRegs *regs, int8_t dst, int8_t src)
RasmOp linear_vcoeff[4][5]
static void asmgen_op_unpack(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
static RasmOp swizzle_a64op(SwsAArch64OpRegs *regs, int8_t n, uint8_t vh, bool dst)
#define i_xtn(rctx, op0, op1)
static void asmgen_op_scale(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
static RasmOp a64op_pre(RasmOp op, int16_t imm)
static void asmgen_op_expand(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
static RasmOp rasm_op_label(int id)
#define i_umax(rctx, op0, op1, op2)
#define offsetof_exec_in
These values will be used by ops_asmgen to access fields inside of SwsOpExec and SwsOpImpl.
#define i_mov16b(rctx, op0, op1)
#define i_str(rctx, op0, op1)
static void asmgen_op_linear(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
#define i_and(rctx, op0, op1, op2)
#define i_ldrh(rctx, op0, op1)
static void asmgen_prologue(SwsAArch64Context *s, const RasmOp *regs, unsigned n)
static void asmgen_process(SwsAArch64Context *s, SwsCompMask imask, SwsCompMask omask)
static RasmOp v_16b(RasmOp op)
#define i_ubfiz(rctx, op0, op1, op2, op3)
IDirect3DDxgiInterfaceAccess _COM_Outptr_ void ** p
static void asmgen_epilogue(SwsAArch64Context *s, const RasmOp *regs, unsigned n)
#define i_orr(rctx, op0, op1, op2)
SwsAArch64OpImplParams describes the parameters for an SwsUOpType operation.
#define i_rev32(rctx, op0, op1)
#define i_stp(rctx, op0, op1, op2)
#define i_movi(rctx, op0, op1)
static void emit_clear(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, RasmOp *vx, RasmOp *vk, int i, const char *vx_str)
static RasmOp a64op_x(RasmOp op)
#define offsetof_exec_in_bump
#define i_and16b(rctx, op0, op1, op2)
static void asmgen_op_write_planar(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
static uint16_t nibble_mask(SwsCompMask mask)
static void asmgen_op_read_nibble(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)
#define i_ushl(rctx, op0, op1, op2)
RasmNode * rasm_add_comment(RasmContext *rctx, const char *comment)
static RasmOp a64op_lr(void)
static uint8_t a64op_gpr_n(RasmOp op)
#define i_mov(rctx, op0, op1)
static RasmOp v_q(RasmOp op)
static void asmgen_op_read_packed(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, SwsAArch64OpRegs *regs)