FFmpeg
Loading...
Searching...
No Matches
mmiutils.h
Go to the documentation of this file.
1/*
2 * Loongson SIMD utils
3 *
4 * Copyright (c) 2016 Loongson Technology Corporation Limited
5 * Copyright (c) 2016 Zhou Xiaoyong <zhouxiaoyong@loongson.cn>
6 *
7 * This file is part of FFmpeg.
8 *
9 * FFmpeg is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * FFmpeg is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with FFmpeg; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24#ifndef AVUTIL_MIPS_MMIUTILS_H
25#define AVUTIL_MIPS_MMIUTILS_H
26
27#include "config.h"
28
31
32#if !HAVE_LOONGSON_MMI_MNEMONICS
33/* GNU binutils lacks Loongson's names for these MMI instructions */
34__asm__(".macro pxor d, s, t\n\txor \\d, \\s, \\t\n\t.endm\n"
35 ".macro pand d, s, t\n\tand \\d, \\s, \\t\n\t.endm\n"
36 ".macro por d, s, t\n\tor \\d, \\s, \\t\n\t.endm\n"
37 ".macro pnor d, s, t\n\tnor \\d, \\s, \\t\n\t.endm\n"
38 ".macro ssrld d, s, t\n\tdsrl \\d, \\s, \\t\n\t.endm\n"
39 ".macro sslld d, s, t\n\tdsll \\d, \\s, \\t\n\t.endm\n");
40#endif
41
42/*
43 * These were used to define temporary registers for MMI marcos
44 * however now we're using $at. They're theoretically unnecessary
45 * but just leave them here to avoid mess.
46 */
47#define DECLARE_VAR_LOW32
48#define RESTRICT_ASM_LOW32
49#define DECLARE_VAR_ALL64
50#define RESTRICT_ASM_ALL64
51#define DECLARE_VAR_ADDRT
52#define RESTRICT_ASM_ADDRT
53
54#if HAVE_LOONGSON2
55
56#define MMI_LWX(reg, addr, stride, bias) \
57 ".set noat \n\t" \
58 PTR_ADDU "$at, "#addr", "#stride" \n\t" \
59 "lw "#reg", "#bias"($at) \n\t" \
60 ".set at \n\t"
61
62#define MMI_SWX(reg, addr, stride, bias) \
63 ".set noat \n\t" \
64 PTR_ADDU "$at, "#addr", "#stride" \n\t" \
65 "sw "#reg", "#bias"($at) \n\t" \
66 ".set at \n\t"
67
68#define MMI_LDX(reg, addr, stride, bias) \
69 ".set noat \n\t" \
70 PTR_ADDU "$at, "#addr", "#stride" \n\t" \
71 "ld "#reg", "#bias"($at) \n\t" \
72 ".set at \n\t"
73
74#define MMI_SDX(reg, addr, stride, bias) \
75 ".set noat \n\t" \
76 PTR_ADDU "$at, "#addr", "#stride" \n\t" \
77 "sd "#reg", "#bias"($at) \n\t" \
78 ".set at \n\t"
79
80#define MMI_LWC1(fp, addr, bias) \
81 "lwc1 "#fp", "#bias"("#addr") \n\t"
82
83#define MMI_ULWC1(fp, addr, bias) \
84 ".set noat \n\t" \
85 "ulw $at, "#bias"("#addr") \n\t" \
86 "mtc1 $at, "#fp" \n\t" \
87 ".set at \n\t"
88
89#define MMI_LWXC1(fp, addr, stride, bias) \
90 ".set noat \n\t" \
91 PTR_ADDU "$at, "#addr", "#stride" \n\t" \
92 MMI_LWC1(fp, $at, bias) \
93 ".set at \n\t"
94
95#define MMI_SWC1(fp, addr, bias) \
96 "swc1 "#fp", "#bias"("#addr") \n\t"
97
98#define MMI_USWC1(fp, addr, bias) \
99 ".set noat \n\t" \
100 "mfc1 $at, "#fp" \n\t" \
101 "usw $at, "#bias"("#addr") \n\t" \
102 ".set at \n\t"
103
104#define MMI_SWXC1(fp, addr, stride, bias) \
105 ".set noat \n\t" \
106 PTR_ADDU "$at, "#addr", "#stride" \n\t" \
107 MMI_SWC1(fp, $at, bias) \
108 ".set at \n\t"
109
110#define MMI_LDC1(fp, addr, bias) \
111 "ldc1 "#fp", "#bias"("#addr") \n\t"
112
113#define MMI_ULDC1(fp, addr, bias) \
114 ".set noat \n\t" \
115 "uld $at, "#bias"("#addr") \n\t" \
116 "dmtc1 $at, "#fp" \n\t" \
117 ".set at \n\t"
118
119#define MMI_LDXC1(fp, addr, stride, bias) \
120 ".set noat \n\t" \
121 PTR_ADDU "$at, "#addr", "#stride" \n\t" \
122 MMI_LDC1(fp, $at, bias) \
123 ".set at \n\t"
124
125#define MMI_SDC1(fp, addr, bias) \
126 "sdc1 "#fp", "#bias"("#addr") \n\t"
127
128#define MMI_USDC1(fp, addr, bias) \
129 ".set noat \n\t" \
130 "dmfc1 $at, "#fp" \n\t" \
131 "usd $at, "#bias"("#addr") \n\t" \
132 ".set at \n\t"
133
134#define MMI_SDXC1(fp, addr, stride, bias) \
135 ".set noat \n\t" \
136 PTR_ADDU "$at, "#addr", "#stride" \n\t" \
137 MMI_SDC1(fp, $at, bias) \
138 ".set at \n\t"
139
140#define MMI_LQ(reg1, reg2, addr, bias) \
141 "ld "#reg1", "#bias"("#addr") \n\t" \
142 "ld "#reg2", 8+"#bias"("#addr") \n\t"
143
144#define MMI_SQ(reg1, reg2, addr, bias) \
145 "sd "#reg1", "#bias"("#addr") \n\t" \
146 "sd "#reg2", 8+"#bias"("#addr") \n\t"
147
148#define MMI_LQC1(fp1, fp2, addr, bias) \
149 "ldc1 "#fp1", "#bias"("#addr") \n\t" \
150 "ldc1 "#fp2", 8+"#bias"("#addr") \n\t"
151
152#define MMI_SQC1(fp1, fp2, addr, bias) \
153 "sdc1 "#fp1", "#bias"("#addr") \n\t" \
154 "sdc1 "#fp2", 8+"#bias"("#addr") \n\t"
155
156#elif HAVE_LOONGSON3 /* !HAVE_LOONGSON2 */
157
158#define MMI_LWX(reg, addr, stride, bias) \
159 "gslwx "#reg", "#bias"("#addr", "#stride") \n\t"
160
161#define MMI_SWX(reg, addr, stride, bias) \
162 "gsswx "#reg", "#bias"("#addr", "#stride") \n\t"
163
164#define MMI_LDX(reg, addr, stride, bias) \
165 "gsldx "#reg", "#bias"("#addr", "#stride") \n\t"
166
167#define MMI_SDX(reg, addr, stride, bias) \
168 "gssdx "#reg", "#bias"("#addr", "#stride") \n\t"
169
170#define MMI_LWC1(fp, addr, bias) \
171 "lwc1 "#fp", "#bias"("#addr") \n\t"
172
173#if _MIPS_SIM == _ABIO32 /* workaround for 3A2000 gslwlc1 bug */
174
175#define MMI_LWLRC1(fp, addr, bias, off) \
176 ".set noat \n\t" \
177 "lwl $at, "#bias"+"#off"("#addr") \n\t" \
178 "lwr $at, "#bias"("#addr") \n\t" \
179 "mtc1 $at, "#fp" \n\t" \
180 ".set at \n\t"
181
182#else /* _MIPS_SIM != _ABIO32 */
183
184#define DECLARE_VAR_LOW32
185#define RESTRICT_ASM_LOW32
186
187#define MMI_ULWC1(fp, addr, bias) \
188 "gslwlc1 "#fp", 3+"#bias"("#addr") \n\t" \
189 "gslwrc1 "#fp", "#bias"("#addr") \n\t"
190
191#endif /* _MIPS_SIM != _ABIO32 */
192
193#define MMI_LWXC1(fp, addr, stride, bias) \
194 "gslwxc1 "#fp", "#bias"("#addr", "#stride") \n\t"
195
196#define MMI_SWC1(fp, addr, bias) \
197 "swc1 "#fp", "#bias"("#addr") \n\t"
198
199#define MMI_USWC1(fp, addr, bias) \
200 "gsswlc1 "#fp", 3+"#bias"("#addr") \n\t" \
201 "gsswrc1 "#fp", "#bias"("#addr") \n\t"
202
203#define MMI_SWXC1(fp, addr, stride, bias) \
204 "gsswxc1 "#fp", "#bias"("#addr", "#stride") \n\t"
205
206#define MMI_LDC1(fp, addr, bias) \
207 "ldc1 "#fp", "#bias"("#addr") \n\t"
208
209#define MMI_ULDC1(fp, addr, bias) \
210 "gsldlc1 "#fp", 7+"#bias"("#addr") \n\t" \
211 "gsldrc1 "#fp", "#bias"("#addr") \n\t"
212
213#define MMI_LDXC1(fp, addr, stride, bias) \
214 "gsldxc1 "#fp", "#bias"("#addr", "#stride") \n\t"
215
216#define MMI_SDC1(fp, addr, bias) \
217 "sdc1 "#fp", "#bias"("#addr") \n\t"
218
219#define MMI_USDC1(fp, addr, bias) \
220 "gssdlc1 "#fp", 7+"#bias"("#addr") \n\t" \
221 "gssdrc1 "#fp", "#bias"("#addr") \n\t"
222
223#define MMI_SDXC1(fp, addr, stride, bias) \
224 "gssdxc1 "#fp", "#bias"("#addr", "#stride") \n\t"
225
226#define MMI_LQ(reg1, reg2, addr, bias) \
227 "gslq "#reg1", "#reg2", "#bias"("#addr") \n\t"
228
229#define MMI_SQ(reg1, reg2, addr, bias) \
230 "gssq "#reg1", "#reg2", "#bias"("#addr") \n\t"
231
232#define MMI_LQC1(fp1, fp2, addr, bias) \
233 "gslqc1 "#fp1", "#fp2", "#bias"("#addr") \n\t"
234
235#define MMI_SQC1(fp1, fp2, addr, bias) \
236 "gssqc1 "#fp1", "#fp2", "#bias"("#addr") \n\t"
237
238#endif /* HAVE_LOONGSON2 */
239
240/**
241 * Backup saved registers
242 * We're not using compiler's clobber list as it's not smart enough
243 * to take advantage of quad word load/store.
244 */
245#define BACKUP_REG \
246 LOCAL_ALIGNED_16(double, temp_backup_reg, [8]); \
247 if (_MIPS_SIM == _ABI64) \
248 __asm__ volatile ( \
249 MMI_SQC1($f25, $f24, %[temp], 0x00) \
250 MMI_SQC1($f27, $f26, %[temp], 0x10) \
251 MMI_SQC1($f29, $f28, %[temp], 0x20) \
252 MMI_SQC1($f31, $f30, %[temp], 0x30) \
253 : \
254 : [temp]"r"(temp_backup_reg) \
255 : "memory" \
256 ); \
257 else \
258 __asm__ volatile ( \
259 MMI_SQC1($f22, $f20, %[temp], 0x10) \
260 MMI_SQC1($f26, $f24, %[temp], 0x10) \
261 MMI_SQC1($f30, $f28, %[temp], 0x20) \
262 : \
263 : [temp]"r"(temp_backup_reg) \
264 : "memory" \
265 );
266
267/**
268 * recover register
269 */
270#define RECOVER_REG \
271 if (_MIPS_SIM == _ABI64) \
272 __asm__ volatile ( \
273 MMI_LQC1($f25, $f24, %[temp], 0x00) \
274 MMI_LQC1($f27, $f26, %[temp], 0x10) \
275 MMI_LQC1($f29, $f28, %[temp], 0x20) \
276 MMI_LQC1($f31, $f30, %[temp], 0x30) \
277 : \
278 : [temp]"r"(temp_backup_reg) \
279 : "memory" \
280 ); \
281 else \
282 __asm__ volatile ( \
283 MMI_LQC1($f22, $f20, %[temp], 0x10) \
284 MMI_LQC1($f26, $f24, %[temp], 0x10) \
285 MMI_LQC1($f30, $f28, %[temp], 0x20) \
286 : \
287 : [temp]"r"(temp_backup_reg) \
288 : "memory" \
289 );
290
291/**
292 * brief: Transpose 2X2 word packaged data.
293 * fr_i0, fr_i1: src
294 * fr_o0, fr_o1: dst
295 */
296#define TRANSPOSE_2W(fr_i0, fr_i1, fr_o0, fr_o1) \
297 "punpcklwd "#fr_o0", "#fr_i0", "#fr_i1" \n\t" \
298 "punpckhwd "#fr_o1", "#fr_i0", "#fr_i1" \n\t"
299
300/**
301 * brief: Transpose 4X4 half word packaged data.
302 * fr_i0, fr_i1, fr_i2, fr_i3: src & dst
303 * fr_t0, fr_t1, fr_t2, fr_t3: temporary register
304 */
305#define TRANSPOSE_4H(fr_i0, fr_i1, fr_i2, fr_i3, \
306 fr_t0, fr_t1, fr_t2, fr_t3) \
307 "punpcklhw "#fr_t0", "#fr_i0", "#fr_i1" \n\t" \
308 "punpckhhw "#fr_t1", "#fr_i0", "#fr_i1" \n\t" \
309 "punpcklhw "#fr_t2", "#fr_i2", "#fr_i3" \n\t" \
310 "punpckhhw "#fr_t3", "#fr_i2", "#fr_i3" \n\t" \
311 "punpcklwd "#fr_i0", "#fr_t0", "#fr_t2" \n\t" \
312 "punpckhwd "#fr_i1", "#fr_t0", "#fr_t2" \n\t" \
313 "punpcklwd "#fr_i2", "#fr_t1", "#fr_t3" \n\t" \
314 "punpckhwd "#fr_i3", "#fr_t1", "#fr_t3" \n\t"
315
316/**
317 * brief: Transpose 8x8 byte packaged data.
318 * fr_i0~i7: src & dst
319 * fr_t0~t3: temporary register
320 */
321#define TRANSPOSE_8B(fr_i0, fr_i1, fr_i2, fr_i3, fr_i4, fr_i5, \
322 fr_i6, fr_i7, fr_t0, fr_t1, fr_t2, fr_t3) \
323 "punpcklbh "#fr_t0", "#fr_i0", "#fr_i1" \n\t" \
324 "punpckhbh "#fr_t1", "#fr_i0", "#fr_i1" \n\t" \
325 "punpcklbh "#fr_t2", "#fr_i2", "#fr_i3" \n\t" \
326 "punpckhbh "#fr_t3", "#fr_i2", "#fr_i3" \n\t" \
327 "punpcklbh "#fr_i0", "#fr_i4", "#fr_i5" \n\t" \
328 "punpckhbh "#fr_i1", "#fr_i4", "#fr_i5" \n\t" \
329 "punpcklbh "#fr_i2", "#fr_i6", "#fr_i7" \n\t" \
330 "punpckhbh "#fr_i3", "#fr_i6", "#fr_i7" \n\t" \
331 "punpcklhw "#fr_i4", "#fr_t0", "#fr_t2" \n\t" \
332 "punpckhhw "#fr_i5", "#fr_t0", "#fr_t2" \n\t" \
333 "punpcklhw "#fr_i6", "#fr_t1", "#fr_t3" \n\t" \
334 "punpckhhw "#fr_i7", "#fr_t1", "#fr_t3" \n\t" \
335 "punpcklhw "#fr_t0", "#fr_i0", "#fr_i2" \n\t" \
336 "punpckhhw "#fr_t1", "#fr_i0", "#fr_i2" \n\t" \
337 "punpcklhw "#fr_t2", "#fr_i1", "#fr_i3" \n\t" \
338 "punpckhhw "#fr_t3", "#fr_i1", "#fr_i3" \n\t" \
339 "punpcklwd "#fr_i0", "#fr_i4", "#fr_t0" \n\t" \
340 "punpckhwd "#fr_i1", "#fr_i4", "#fr_t0" \n\t" \
341 "punpcklwd "#fr_i2", "#fr_i5", "#fr_t1" \n\t" \
342 "punpckhwd "#fr_i3", "#fr_i5", "#fr_t1" \n\t" \
343 "punpcklwd "#fr_i4", "#fr_i6", "#fr_t2" \n\t" \
344 "punpckhwd "#fr_i5", "#fr_i6", "#fr_t2" \n\t" \
345 "punpcklwd "#fr_i6", "#fr_i7", "#fr_t3" \n\t" \
346 "punpckhwd "#fr_i7", "#fr_i7", "#fr_t3" \n\t"
347
348/**
349 * brief: Parallel SRA for 8 byte packaged data.
350 * fr_i0: src
351 * fr_i1: SRA number(SRAB number + 8)
352 * fr_t0, fr_t1: temporary register
353 * fr_d0: dst
354 */
355#define PSRAB_MMI(fr_i0, fr_i1, fr_t0, fr_t1, fr_d0) \
356 "punpcklbh "#fr_t0", "#fr_t0", "#fr_i0" \n\t" \
357 "punpckhbh "#fr_t1", "#fr_t1", "#fr_i0" \n\t" \
358 "psrah "#fr_t0", "#fr_t0", "#fr_i1" \n\t" \
359 "psrah "#fr_t1", "#fr_t1", "#fr_i1" \n\t" \
360 "packsshb "#fr_d0", "#fr_t0", "#fr_t1" \n\t"
361
362/**
363 * brief: Parallel SRL for 8 byte packaged data.
364 * fr_i0: src
365 * fr_i1: SRL number(SRLB number + 8)
366 * fr_t0, fr_t1: temporary register
367 * fr_d0: dst
368 */
369#define PSRLB_MMI(fr_i0, fr_i1, fr_t0, fr_t1, fr_d0) \
370 "punpcklbh "#fr_t0", "#fr_t0", "#fr_i0" \n\t" \
371 "punpckhbh "#fr_t1", "#fr_t1", "#fr_i0" \n\t" \
372 "psrlh "#fr_t0", "#fr_t0", "#fr_i1" \n\t" \
373 "psrlh "#fr_t1", "#fr_t1", "#fr_i1" \n\t" \
374 "packsshb "#fr_d0", "#fr_t0", "#fr_t1" \n\t"
375
376#define PSRAH_4_MMI(fp1, fp2, fp3, fp4, shift) \
377 "psrah "#fp1", "#fp1", "#shift" \n\t" \
378 "psrah "#fp2", "#fp2", "#shift" \n\t" \
379 "psrah "#fp3", "#fp3", "#shift" \n\t" \
380 "psrah "#fp4", "#fp4", "#shift" \n\t"
381
382#define PSRAH_8_MMI(fp1, fp2, fp3, fp4, fp5, fp6, fp7, fp8, shift) \
383 PSRAH_4_MMI(fp1, fp2, fp3, fp4, shift) \
384 PSRAH_4_MMI(fp5, fp6, fp7, fp8, shift)
385
386/**
387 * brief: (((value) + (1 << ((n) - 1))) >> (n))
388 * fr_i0: src & dst
389 * fr_i1: Operand number
390 * fr_t0, fr_t1: temporary FPR
391 * gr_t0: temporary GPR
392 */
393#define ROUND_POWER_OF_TWO_MMI(fr_i0, fr_i1, fr_t0, fr_t1, gr_t0) \
394 "li "#gr_t0", 0x01 \n\t" \
395 "dmtc1 "#gr_t0", "#fr_t0" \n\t" \
396 "punpcklwd "#fr_t0", "#fr_t0", "#fr_t0" \n\t" \
397 "psubw "#fr_t1", "#fr_i1", "#fr_t0" \n\t" \
398 "psllw "#fr_t1", "#fr_t0", "#fr_t1" \n\t" \
399 "paddw "#fr_i0", "#fr_i0", "#fr_t1" \n\t" \
400 "psraw "#fr_i0", "#fr_i0", "#fr_i1" \n\t"
401
402#endif /* AVUTILS_MIPS_MMIUTILS_H */
MIPS assembly defines from sys/asm.h but rewritten for use with C inline assembly (rather than from w...
__asm__(".macro pxor d, s, t\n\txor \\d, \\s, \\t\n\t.endm\n" ".macro pand d, s, t\n\tand \\d, \\s, \\t\n\t.endm\n" ".macro por d, s, t\n\tor \\d, \\s, \\t\n\t.endm\n" ".macro pnor d, s, t\n\tnor \\d, \\s, \\t\n\t.endm\n" ".macro ssrld d, s, t\n\tdsrl \\d, \\s, \\t\n\t.endm\n" ".macro sslld d, s, t\n\tdsll \\d, \\s, \\t\n\t.endm\n")