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 #include "libavutil/mips/asmdefs.h" 29 30 #if HAVE_LOONGSON2 31 32 #define DECLARE_VAR_LOW32 int32_t low32 33 #define RESTRICT_ASM_LOW32 [low32]"=&r"(low32), 34 #define DECLARE_VAR_ALL64 int64_t all64 35 #define RESTRICT_ASM_ALL64 [all64]"=&r"(all64), 36 #define DECLARE_VAR_ADDRT mips_reg addrt 37 #define RESTRICT_ASM_ADDRT [addrt]"=&r"(addrt), 38 39 #define MMI_LWX(reg, addr, stride, bias) \ 40 PTR_ADDU "%[addrt], "#addr", "#stride" \n\t" \ 41 "lw "#reg", "#bias"(%[addrt]) \n\t" 42 43 #define MMI_SWX(reg, addr, stride, bias) \ 44 PTR_ADDU "%[addrt], "#addr", "#stride" \n\t" \ 45 "sw "#reg", "#bias"(%[addrt]) \n\t" 46 47 #define MMI_LDX(reg, addr, stride, bias) \ 48 PTR_ADDU "%[addrt], "#addr", "#stride" \n\t" \ 49 "ld "#reg", "#bias"(%[addrt]) \n\t" 50 51 #define MMI_SDX(reg, addr, stride, bias) \ 52 PTR_ADDU "%[addrt], "#addr", "#stride" \n\t" \ 53 "sd "#reg", "#bias"(%[addrt]) \n\t" 54 55 #define MMI_LWC1(fp, addr, bias) \ 56 "lwc1 "#fp", "#bias"("#addr") \n\t" 57 58 #define MMI_ULWC1(fp, addr, bias) \ 59 "ulw %[low32], "#bias"("#addr") \n\t" \ 60 "mtc1 %[low32], "#fp" \n\t" 61 62 #define MMI_LWXC1(fp, addr, stride, bias) \ 63 PTR_ADDU "%[addrt], "#addr", "#stride" \n\t" \ 64 MMI_LWC1(fp, %[addrt], bias) 65 66 #define MMI_SWC1(fp, addr, bias) \ 67 "swc1 "#fp", "#bias"("#addr") \n\t" 68 69 #define MMI_USWC1(fp, addr, bias) \ 70 "mfc1 %[low32], "#fp" \n\t" \ 71 "usw %[low32], "#bias"("#addr") \n\t" 72 73 #define MMI_SWXC1(fp, addr, stride, bias) \ 74 PTR_ADDU "%[addrt], "#addr", "#stride" \n\t" \ 75 MMI_SWC1(fp, %[addrt], bias) 76 77 #define MMI_LDC1(fp, addr, bias) \ 78 "ldc1 "#fp", "#bias"("#addr") \n\t" 79 80 #define MMI_ULDC1(fp, addr, bias) \ 81 "uld %[all64], "#bias"("#addr") \n\t" \ 82 "dmtc1 %[all64], "#fp" \n\t" 83 84 #define MMI_LDXC1(fp, addr, stride, bias) \ 85 PTR_ADDU "%[addrt], "#addr", "#stride" \n\t" \ 86 MMI_LDC1(fp, %[addrt], bias) 87 88 #define MMI_SDC1(fp, addr, bias) \ 89 "sdc1 "#fp", "#bias"("#addr") \n\t" 90 91 #define MMI_USDC1(fp, addr, bias) \ 92 "dmfc1 %[all64], "#fp" \n\t" \ 93 "usd %[all64], "#bias"("#addr") \n\t" 94 95 #define MMI_SDXC1(fp, addr, stride, bias) \ 96 PTR_ADDU "%[addrt], "#addr", "#stride" \n\t" \ 97 MMI_SDC1(fp, %[addrt], bias) 98 99 #define MMI_LQ(reg1, reg2, addr, bias) \ 100 "ld "#reg1", "#bias"("#addr") \n\t" \ 101 "ld "#reg2", 8+"#bias"("#addr") \n\t" 102 103 #define MMI_SQ(reg1, reg2, addr, bias) \ 104 "sd "#reg1", "#bias"("#addr") \n\t" \ 105 "sd "#reg2", 8+"#bias"("#addr") \n\t" 106 107 #define MMI_LQC1(fp1, fp2, addr, bias) \ 108 "ldc1 "#fp1", "#bias"("#addr") \n\t" \ 109 "ldc1 "#fp2", 8+"#bias"("#addr") \n\t" 110 111 #define MMI_SQC1(fp1, fp2, addr, bias) \ 112 "sdc1 "#fp1", "#bias"("#addr") \n\t" \ 113 "sdc1 "#fp2", 8+"#bias"("#addr") \n\t" 114 115 #elif HAVE_LOONGSON3 /* !HAVE_LOONGSON2 */ 116 117 #define DECLARE_VAR_ALL64 118 #define RESTRICT_ASM_ALL64 119 #define DECLARE_VAR_ADDRT 120 #define RESTRICT_ASM_ADDRT 121 122 #define MMI_LWX(reg, addr, stride, bias) \ 123 "gslwx "#reg", "#bias"("#addr", "#stride") \n\t" 124 125 #define MMI_SWX(reg, addr, stride, bias) \ 126 "gsswx "#reg", "#bias"("#addr", "#stride") \n\t" 127 128 #define MMI_LDX(reg, addr, stride, bias) \ 129 "gsldx "#reg", "#bias"("#addr", "#stride") \n\t" 130 131 #define MMI_SDX(reg, addr, stride, bias) \ 132 "gssdx "#reg", "#bias"("#addr", "#stride") \n\t" 133 134 #define MMI_LWC1(fp, addr, bias) \ 135 "lwc1 "#fp", "#bias"("#addr") \n\t" 136 137 #if _MIPS_SIM == _ABIO32 /* workaround for 3A2000 gslwlc1 bug */ 138 139 #define DECLARE_VAR_LOW32 int32_t low32 140 #define RESTRICT_ASM_LOW32 [low32]"=&r"(low32), 141 142 #define MMI_ULWC1(fp, addr, bias) \ 143 "ulw %[low32], "#bias"("#addr") \n\t" \ 144 "mtc1 %[low32], "#fp" \n\t" 145 146 #else /* _MIPS_SIM != _ABIO32 */ 147 148 #define DECLARE_VAR_LOW32 149 #define RESTRICT_ASM_LOW32 150 151 #define MMI_ULWC1(fp, addr, bias) \ 152 "gslwlc1 "#fp", 3+"#bias"("#addr") \n\t" \ 153 "gslwrc1 "#fp", "#bias"("#addr") \n\t" 154 155 #endif /* _MIPS_SIM != _ABIO32 */ 156 157 #define MMI_LWXC1(fp, addr, stride, bias) \ 158 "gslwxc1 "#fp", "#bias"("#addr", "#stride") \n\t" 159 160 #define MMI_SWC1(fp, addr, bias) \ 161 "swc1 "#fp", "#bias"("#addr") \n\t" 162 163 #define MMI_USWC1(fp, addr, bias) \ 164 "gsswlc1 "#fp", 3+"#bias"("#addr") \n\t" \ 165 "gsswrc1 "#fp", "#bias"("#addr") \n\t" 166 167 #define MMI_SWXC1(fp, addr, stride, bias) \ 168 "gsswxc1 "#fp", "#bias"("#addr", "#stride") \n\t" 169 170 #define MMI_LDC1(fp, addr, bias) \ 171 "ldc1 "#fp", "#bias"("#addr") \n\t" 172 173 #define MMI_ULDC1(fp, addr, bias) \ 174 "gsldlc1 "#fp", 7+"#bias"("#addr") \n\t" \ 175 "gsldrc1 "#fp", "#bias"("#addr") \n\t" 176 177 #define MMI_LDXC1(fp, addr, stride, bias) \ 178 "gsldxc1 "#fp", "#bias"("#addr", "#stride") \n\t" 179 180 #define MMI_SDC1(fp, addr, bias) \ 181 "sdc1 "#fp", "#bias"("#addr") \n\t" 182 183 #define MMI_USDC1(fp, addr, bias) \ 184 "gssdlc1 "#fp", 7+"#bias"("#addr") \n\t" \ 185 "gssdrc1 "#fp", "#bias"("#addr") \n\t" 186 187 #define MMI_SDXC1(fp, addr, stride, bias) \ 188 "gssdxc1 "#fp", "#bias"("#addr", "#stride") \n\t" 189 190 #define MMI_LQ(reg1, reg2, addr, bias) \ 191 "gslq "#reg1", "#reg2", "#bias"("#addr") \n\t" 192 193 #define MMI_SQ(reg1, reg2, addr, bias) \ 194 "gssq "#reg1", "#reg2", "#bias"("#addr") \n\t" 195 196 #define MMI_LQC1(fp1, fp2, addr, bias) \ 197 "gslqc1 "#fp1", "#fp2", "#bias"("#addr") \n\t" 198 199 #define MMI_SQC1(fp1, fp2, addr, bias) \ 200 "gssqc1 "#fp1", "#fp2", "#bias"("#addr") \n\t" 201 202 #endif /* HAVE_LOONGSON2 */ 203 204 /** 205 * backup register 206 */ 207 #define BACKUP_REG \ 208 LOCAL_ALIGNED_16(double, temp_backup_reg, [8]); \ 209 if (_MIPS_SIM == _ABI64) \ 210 __asm__ volatile ( \ 211 "gssqc1 $f25, $f24, 0x00(%[temp]) \n\t" \ 212 "gssqc1 $f27, $f26, 0x10(%[temp]) \n\t" \ 213 "gssqc1 $f29, $f28, 0x20(%[temp]) \n\t" \ 214 "gssqc1 $f31, $f30, 0x30(%[temp]) \n\t" \ 215 : \ 216 : [temp]"r"(temp_backup_reg) \ 217 : "memory" \ 218 ); \ 219 else \ 220 __asm__ volatile ( \ 221 "gssqc1 $f22, $f20, 0x00(%[temp]) \n\t" \ 222 "gssqc1 $f26, $f24, 0x10(%[temp]) \n\t" \ 223 "gssqc1 $f30, $f28, 0x20(%[temp]) \n\t" \ 224 : \ 225 : [temp]"r"(temp_backup_reg) \ 226 : "memory" \ 227 ); 228 229 /** 230 * recover register 231 */ 232 #define RECOVER_REG \ 233 if (_MIPS_SIM == _ABI64) \ 234 __asm__ volatile ( \ 235 "gslqc1 $f25, $f24, 0x00(%[temp]) \n\t" \ 236 "gslqc1 $f27, $f26, 0x10(%[temp]) \n\t" \ 237 "gslqc1 $f29, $f28, 0x20(%[temp]) \n\t" \ 238 "gslqc1 $f31, $f30, 0x30(%[temp]) \n\t" \ 239 : \ 240 : [temp]"r"(temp_backup_reg) \ 241 : "memory" \ 242 ); \ 243 else \ 244 __asm__ volatile ( \ 245 "gslqc1 $f22, $f20, 0x00(%[temp]) \n\t" \ 246 "gslqc1 $f26, $f24, 0x10(%[temp]) \n\t" \ 247 "gslqc1 $f30, $f28, 0x20(%[temp]) \n\t" \ 248 : \ 249 : [temp]"r"(temp_backup_reg) \ 250 : "memory" \ 251 ); 252 253 /** 254 * brief: Transpose 2X2 word packaged data. 255 * fr_i0, fr_i1: src 256 * fr_o0, fr_o1: dst 257 */ 258 #define TRANSPOSE_2W(fr_i0, fr_i1, fr_o0, fr_o1) \ 259 "punpcklwd "#fr_o0", "#fr_i0", "#fr_i1" \n\t" \ 260 "punpckhwd "#fr_o1", "#fr_i0", "#fr_i1" \n\t" 261 262 /** 263 * brief: Transpose 4X4 half word packaged data. 264 * fr_i0, fr_i1, fr_i2, fr_i3: src & dst 265 * fr_t0, fr_t1, fr_t2, fr_t3: temporary register 266 */ 267 #define TRANSPOSE_4H(fr_i0, fr_i1, fr_i2, fr_i3, \ 268 fr_t0, fr_t1, fr_t2, fr_t3) \ 269 "punpcklhw "#fr_t0", "#fr_i0", "#fr_i1" \n\t" \ 270 "punpckhhw "#fr_t1", "#fr_i0", "#fr_i1" \n\t" \ 271 "punpcklhw "#fr_t2", "#fr_i2", "#fr_i3" \n\t" \ 272 "punpckhhw "#fr_t3", "#fr_i2", "#fr_i3" \n\t" \ 273 "punpcklwd "#fr_i0", "#fr_t0", "#fr_t2" \n\t" \ 274 "punpckhwd "#fr_i1", "#fr_t0", "#fr_t2" \n\t" \ 275 "punpcklwd "#fr_i2", "#fr_t1", "#fr_t3" \n\t" \ 276 "punpckhwd "#fr_i3", "#fr_t1", "#fr_t3" \n\t" 277 278 /** 279 * brief: Transpose 8x8 byte packaged data. 280 * fr_i0~i7: src & dst 281 * fr_t0~t3: temporary register 282 */ 283 #define TRANSPOSE_8B(fr_i0, fr_i1, fr_i2, fr_i3, fr_i4, fr_i5, \ 284 fr_i6, fr_i7, fr_t0, fr_t1, fr_t2, fr_t3) \ 285 "punpcklbh "#fr_t0", "#fr_i0", "#fr_i1" \n\t" \ 286 "punpckhbh "#fr_t1", "#fr_i0", "#fr_i1" \n\t" \ 287 "punpcklbh "#fr_t2", "#fr_i2", "#fr_i3" \n\t" \ 288 "punpckhbh "#fr_t3", "#fr_i2", "#fr_i3" \n\t" \ 289 "punpcklbh "#fr_i0", "#fr_i4", "#fr_i5" \n\t" \ 290 "punpckhbh "#fr_i1", "#fr_i4", "#fr_i5" \n\t" \ 291 "punpcklbh "#fr_i2", "#fr_i6", "#fr_i7" \n\t" \ 292 "punpckhbh "#fr_i3", "#fr_i6", "#fr_i7" \n\t" \ 293 "punpcklhw "#fr_i4", "#fr_t0", "#fr_t2" \n\t" \ 294 "punpckhhw "#fr_i5", "#fr_t0", "#fr_t2" \n\t" \ 295 "punpcklhw "#fr_i6", "#fr_t1", "#fr_t3" \n\t" \ 296 "punpckhhw "#fr_i7", "#fr_t1", "#fr_t3" \n\t" \ 297 "punpcklhw "#fr_t0", "#fr_i0", "#fr_i2" \n\t" \ 298 "punpckhhw "#fr_t1", "#fr_i0", "#fr_i2" \n\t" \ 299 "punpcklhw "#fr_t2", "#fr_i1", "#fr_i3" \n\t" \ 300 "punpckhhw "#fr_t3", "#fr_i1", "#fr_i3" \n\t" \ 301 "punpcklwd "#fr_i0", "#fr_i4", "#fr_t0" \n\t" \ 302 "punpckhwd "#fr_i1", "#fr_i4", "#fr_t0" \n\t" \ 303 "punpcklwd "#fr_i2", "#fr_i5", "#fr_t1" \n\t" \ 304 "punpckhwd "#fr_i3", "#fr_i5", "#fr_t1" \n\t" \ 305 "punpcklwd "#fr_i4", "#fr_i6", "#fr_t2" \n\t" \ 306 "punpckhwd "#fr_i5", "#fr_i6", "#fr_t2" \n\t" \ 307 "punpcklwd "#fr_i6", "#fr_i7", "#fr_t3" \n\t" \ 308 "punpckhwd "#fr_i7", "#fr_i7", "#fr_t3" \n\t" 309 310 /** 311 * brief: Parallel SRA for 8 byte packaged data. 312 * fr_i0: src 313 * fr_i1: SRA number(SRAB number + 8) 314 * fr_t0, fr_t1: temporary register 315 * fr_d0: dst 316 */ 317 #define PSRAB_MMI(fr_i0, fr_i1, fr_t0, fr_t1, fr_d0) \ 318 "punpcklbh "#fr_t0", "#fr_t0", "#fr_i0" \n\t" \ 319 "punpckhbh "#fr_t1", "#fr_t1", "#fr_i0" \n\t" \ 320 "psrah "#fr_t0", "#fr_t0", "#fr_i1" \n\t" \ 321 "psrah "#fr_t1", "#fr_t1", "#fr_i1" \n\t" \ 322 "packsshb "#fr_d0", "#fr_t0", "#fr_t1" \n\t" 323 324 /** 325 * brief: Parallel SRL for 8 byte packaged data. 326 * fr_i0: src 327 * fr_i1: SRL number(SRLB number + 8) 328 * fr_t0, fr_t1: temporary register 329 * fr_d0: dst 330 */ 331 #define PSRLB_MMI(fr_i0, fr_i1, fr_t0, fr_t1, fr_d0) \ 332 "punpcklbh "#fr_t0", "#fr_t0", "#fr_i0" \n\t" \ 333 "punpckhbh "#fr_t1", "#fr_t1", "#fr_i0" \n\t" \ 334 "psrlh "#fr_t0", "#fr_t0", "#fr_i1" \n\t" \ 335 "psrlh "#fr_t1", "#fr_t1", "#fr_i1" \n\t" \ 336 "packsshb "#fr_d0", "#fr_t0", "#fr_t1" \n\t" 337 338 #define PSRAH_4_MMI(fp1, fp2, fp3, fp4, shift) \ 339 "psrah "#fp1", "#fp1", "#shift" \n\t" \ 340 "psrah "#fp2", "#fp2", "#shift" \n\t" \ 341 "psrah "#fp3", "#fp3", "#shift" \n\t" \ 342 "psrah "#fp4", "#fp4", "#shift" \n\t" 343 344 #define PSRAH_8_MMI(fp1, fp2, fp3, fp4, fp5, fp6, fp7, fp8, shift) \ 345 PSRAH_4_MMI(fp1, fp2, fp3, fp4, shift) \ 346 PSRAH_4_MMI(fp5, fp6, fp7, fp8, shift) 347 348 /** 349 * brief: (((value) + (1 << ((n) - 1))) >> (n)) 350 * fr_i0: src & dst 351 * fr_i1: Operand number 352 * fr_t0, fr_t1: temporary FPR 353 * gr_t0: temporary GPR 354 */ 355 #define ROUND_POWER_OF_TWO_MMI(fr_i0, fr_i1, fr_t0, fr_t1, gr_t0) \ 356 "li "#gr_t0", 0x01 \n\t" \ 357 "dmtc1 "#gr_t0", "#fr_t0" \n\t" \ 358 "punpcklwd "#fr_t0", "#fr_t0", "#fr_t0" \n\t" \ 359 "psubw "#fr_t1", "#fr_i1", "#fr_t0" \n\t" \ 360 "psllw "#fr_t1", "#fr_t0", "#fr_t1" \n\t" \ 361 "paddw "#fr_i0", "#fr_i0", "#fr_t1" \n\t" \ 362 "psraw "#fr_i0", "#fr_i0", "#fr_i1" \n\t" 363 364 #endif /* AVUTILS_MIPS_MMIUTILS_H */ 365