1cabdff1aSopenharmony_ci/****************************************************************************
2cabdff1aSopenharmony_ci * Assembly testing and benchmarking tool
3cabdff1aSopenharmony_ci * Copyright (c) 2015 Martin Storsjo
4cabdff1aSopenharmony_ci * Copyright (c) 2015 Janne Grunau
5cabdff1aSopenharmony_ci *
6cabdff1aSopenharmony_ci * This file is part of FFmpeg.
7cabdff1aSopenharmony_ci *
8cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or modify
9cabdff1aSopenharmony_ci * it under the terms of the GNU General Public License as published by
10cabdff1aSopenharmony_ci * the Free Software Foundation; either version 2 of the License, or
11cabdff1aSopenharmony_ci * (at your option) any later version.
12cabdff1aSopenharmony_ci *
13cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
14cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
15cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16cabdff1aSopenharmony_ci * GNU General Public License for more details.
17cabdff1aSopenharmony_ci *
18cabdff1aSopenharmony_ci * You should have received a copy of the GNU General Public License
19cabdff1aSopenharmony_ci * along with this program; if not, write to the Free Software
20cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111, USA.
21cabdff1aSopenharmony_ci *****************************************************************************/
22cabdff1aSopenharmony_ci
23cabdff1aSopenharmony_ci#include "libavutil/arm/asm.S"
24cabdff1aSopenharmony_ci
25cabdff1aSopenharmony_ci/* override fpu so that NEON instructions are rejected */
26cabdff1aSopenharmony_ci#if HAVE_VFP
27cabdff1aSopenharmony_ciFPU     .fpu            vfp
28cabdff1aSopenharmony_ciELF     .eabi_attribute 10, 0           @ suppress Tag_FP_arch
29cabdff1aSopenharmony_ci#endif
30cabdff1aSopenharmony_ci
31cabdff1aSopenharmony_ciconst register_init, align=3
32cabdff1aSopenharmony_ci        .quad 0x21f86d66c8ca00ce
33cabdff1aSopenharmony_ci        .quad 0x75b6ba21077c48ad
34cabdff1aSopenharmony_ci        .quad 0xed56bb2dcb3c7736
35cabdff1aSopenharmony_ci        .quad 0x8bda43d3fd1a7e06
36cabdff1aSopenharmony_ci        .quad 0xb64a9c9e5d318408
37cabdff1aSopenharmony_ci        .quad 0xdf9a54b303f1d3a3
38cabdff1aSopenharmony_ci        .quad 0x4a75479abd64e097
39cabdff1aSopenharmony_ci        .quad 0x249214109d5d1c88
40cabdff1aSopenharmony_ciendconst
41cabdff1aSopenharmony_ci
42cabdff1aSopenharmony_ciconst error_message_fpscr
43cabdff1aSopenharmony_ci        .asciz "failed to preserve register FPSCR, changed bits: %x"
44cabdff1aSopenharmony_cierror_message_gpr:
45cabdff1aSopenharmony_ci        .asciz "failed to preserve register r%d"
46cabdff1aSopenharmony_cierror_message_vfp:
47cabdff1aSopenharmony_ci        .asciz "failed to preserve register d%d"
48cabdff1aSopenharmony_cierror_message_stack:
49cabdff1aSopenharmony_ci        .asciz "failed to preserve stack"
50cabdff1aSopenharmony_ciendconst
51cabdff1aSopenharmony_ci
52cabdff1aSopenharmony_ci@ max number of args used by any asm function.
53cabdff1aSopenharmony_ci#define MAX_ARGS 15
54cabdff1aSopenharmony_ci
55cabdff1aSopenharmony_ci#define ARG_STACK 4*(MAX_ARGS - 4)
56cabdff1aSopenharmony_ci
57cabdff1aSopenharmony_ci@ Align the used stack space to 8 to preserve the stack alignment.
58cabdff1aSopenharmony_ci@ +8 for stack canary reference.
59cabdff1aSopenharmony_ci#define ARG_STACK_A (((ARG_STACK + pushed + 7) & ~7) - pushed + 8)
60cabdff1aSopenharmony_ci
61cabdff1aSopenharmony_ci.macro clobbercheck variant
62cabdff1aSopenharmony_ci.equ pushed, 4*9
63cabdff1aSopenharmony_cifunction checkasm_checked_call_\variant, export=1
64cabdff1aSopenharmony_ci        push            {r4-r11, lr}
65cabdff1aSopenharmony_ci.ifc \variant, vfp
66cabdff1aSopenharmony_ci        vpush           {d8-d15}
67cabdff1aSopenharmony_ci        fmrx            r4,  FPSCR
68cabdff1aSopenharmony_ci        push            {r4}
69cabdff1aSopenharmony_ci.equ pushed, pushed + 16*4 + 4
70cabdff1aSopenharmony_ci.endif
71cabdff1aSopenharmony_ci
72cabdff1aSopenharmony_ci        movrel          r12, register_init
73cabdff1aSopenharmony_ci.ifc \variant, vfp
74cabdff1aSopenharmony_ci        vldm            r12, {d8-d15}
75cabdff1aSopenharmony_ci.endif
76cabdff1aSopenharmony_ci        ldm             r12, {r4-r11}
77cabdff1aSopenharmony_ci
78cabdff1aSopenharmony_ci        sub             sp,  sp,  #ARG_STACK_A
79cabdff1aSopenharmony_ci.equ pos, 0
80cabdff1aSopenharmony_ci.rept MAX_ARGS-4
81cabdff1aSopenharmony_ci        ldr             r12, [sp, #ARG_STACK_A + pushed + 8 + pos]
82cabdff1aSopenharmony_ci        str             r12, [sp, #pos]
83cabdff1aSopenharmony_ci.equ pos, pos + 4
84cabdff1aSopenharmony_ci.endr
85cabdff1aSopenharmony_ci
86cabdff1aSopenharmony_ci        @ For stack overflows, the callee is free to overwrite the parameters
87cabdff1aSopenharmony_ci        @ that were passed on the stack (if any), so we can only check after
88cabdff1aSopenharmony_ci        @ that point. First figure out how many parameters the function
89cabdff1aSopenharmony_ci        @ really took on the stack:
90cabdff1aSopenharmony_ci        ldr             r12, [sp, #ARG_STACK_A + pushed + 8 + 4*(MAX_ARGS-4)]
91cabdff1aSopenharmony_ci        @ Load the first non-parameter value from the stack, that should be
92cabdff1aSopenharmony_ci        @ left untouched by the function. Store a copy of it inverted, so that
93cabdff1aSopenharmony_ci        @ e.g. overwriting everything with zero would be noticed.
94cabdff1aSopenharmony_ci        ldr             r12, [sp, r12, lsl #2]
95cabdff1aSopenharmony_ci        mvn             r12, r12
96cabdff1aSopenharmony_ci        str             r12, [sp, #ARG_STACK_A - 4]
97cabdff1aSopenharmony_ci
98cabdff1aSopenharmony_ci        mov             r12, r0
99cabdff1aSopenharmony_ci        mov             r0,  r2
100cabdff1aSopenharmony_ci        mov             r1,  r3
101cabdff1aSopenharmony_ci        ldrd            r2,  r3,  [sp, #ARG_STACK_A + pushed]
102cabdff1aSopenharmony_ci        @ Call the target function
103cabdff1aSopenharmony_ci        blx             r12
104cabdff1aSopenharmony_ci
105cabdff1aSopenharmony_ci        @ Load the number of stack parameters, stack canary and its reference
106cabdff1aSopenharmony_ci        ldr             r12, [sp, #ARG_STACK_A + pushed + 8 + 4*(MAX_ARGS-4)]
107cabdff1aSopenharmony_ci        ldr             r2,  [sp, r12, lsl #2]
108cabdff1aSopenharmony_ci        ldr             r3,  [sp, #ARG_STACK_A - 4]
109cabdff1aSopenharmony_ci
110cabdff1aSopenharmony_ci        add             sp,  sp,  #ARG_STACK_A
111cabdff1aSopenharmony_ci        push            {r0, r1}
112cabdff1aSopenharmony_ci
113cabdff1aSopenharmony_ci        mvn             r3,  r3
114cabdff1aSopenharmony_ci        cmp             r2,  r3
115cabdff1aSopenharmony_ci        bne             5f
116cabdff1aSopenharmony_ci
117cabdff1aSopenharmony_ci        movrel          r12, register_init
118cabdff1aSopenharmony_ci.ifc \variant, vfp
119cabdff1aSopenharmony_ci.macro check_reg_vfp, dreg, offset
120cabdff1aSopenharmony_ci        ldrd            r2,  r3,  [r12, #8 * (\offset)]
121cabdff1aSopenharmony_ci        vmov            r0,  lr,  \dreg
122cabdff1aSopenharmony_ci        eor             r2,  r2,  r0
123cabdff1aSopenharmony_ci        eor             r3,  r3,  lr
124cabdff1aSopenharmony_ci        orrs            r2,  r2,  r3
125cabdff1aSopenharmony_ci        bne             4f
126cabdff1aSopenharmony_ci.endm
127cabdff1aSopenharmony_ci
128cabdff1aSopenharmony_ci.irp n, 8, 9, 10, 11, 12, 13, 14, 15
129cabdff1aSopenharmony_ci        @ keep track of the checked double/SIMD register
130cabdff1aSopenharmony_ci        mov             r1,  #\n
131cabdff1aSopenharmony_ci        check_reg_vfp   d\n, \n-8
132cabdff1aSopenharmony_ci.endr
133cabdff1aSopenharmony_ci.purgem check_reg_vfp
134cabdff1aSopenharmony_ci
135cabdff1aSopenharmony_ci        fmrx            r1,  FPSCR
136cabdff1aSopenharmony_ci        ldr             r3,  [sp, #8]
137cabdff1aSopenharmony_ci        eor             r1,  r1,  r3
138cabdff1aSopenharmony_ci        @ Ignore changes in bits 0-4 and 7
139cabdff1aSopenharmony_ci        bic             r1,  r1,  #0x9f
140cabdff1aSopenharmony_ci        @ Ignore changes in the topmost 5 bits
141cabdff1aSopenharmony_ci        bics            r1,  r1,  #0xf8000000
142cabdff1aSopenharmony_ci        bne             3f
143cabdff1aSopenharmony_ci.endif
144cabdff1aSopenharmony_ci
145cabdff1aSopenharmony_ci        @ keep track of the checked GPR
146cabdff1aSopenharmony_ci        mov             r1,  #4
147cabdff1aSopenharmony_ci.macro check_reg reg1, reg2=
148cabdff1aSopenharmony_ci        ldrd            r2,  r3,  [r12], #8
149cabdff1aSopenharmony_ci        eors            r2,  r2,  \reg1
150cabdff1aSopenharmony_ci        bne             2f
151cabdff1aSopenharmony_ci        add             r1,  r1,  #1
152cabdff1aSopenharmony_ci.ifnb \reg2
153cabdff1aSopenharmony_ci        eors            r3,  r3,  \reg2
154cabdff1aSopenharmony_ci        bne             2f
155cabdff1aSopenharmony_ci.endif
156cabdff1aSopenharmony_ci        add             r1,  r1,  #1
157cabdff1aSopenharmony_ci.endm
158cabdff1aSopenharmony_ci        check_reg       r4,  r5
159cabdff1aSopenharmony_ci        check_reg       r6,  r7
160cabdff1aSopenharmony_ci@ r9 is a volatile register in the ios ABI
161cabdff1aSopenharmony_ci#ifdef __APPLE__
162cabdff1aSopenharmony_ci        check_reg       r8
163cabdff1aSopenharmony_ci#else
164cabdff1aSopenharmony_ci        check_reg       r8,  r9
165cabdff1aSopenharmony_ci#endif
166cabdff1aSopenharmony_ci        check_reg       r10, r11
167cabdff1aSopenharmony_ci.purgem check_reg
168cabdff1aSopenharmony_ci
169cabdff1aSopenharmony_ci        b               0f
170cabdff1aSopenharmony_ci5:
171cabdff1aSopenharmony_ci        movrel          r0, error_message_stack
172cabdff1aSopenharmony_ci        b               1f
173cabdff1aSopenharmony_ci4:
174cabdff1aSopenharmony_ci        movrel          r0, error_message_vfp
175cabdff1aSopenharmony_ci        b               1f
176cabdff1aSopenharmony_ci3:
177cabdff1aSopenharmony_ci        movrel          r0, error_message_fpscr
178cabdff1aSopenharmony_ci        b               1f
179cabdff1aSopenharmony_ci2:
180cabdff1aSopenharmony_ci        movrel          r0, error_message_gpr
181cabdff1aSopenharmony_ci1:
182cabdff1aSopenharmony_ci        bl              X(checkasm_fail_func)
183cabdff1aSopenharmony_ci0:
184cabdff1aSopenharmony_ci        pop             {r0, r1}
185cabdff1aSopenharmony_ci.ifc \variant, vfp
186cabdff1aSopenharmony_ci        pop             {r2}
187cabdff1aSopenharmony_ci        fmxr            FPSCR, r2
188cabdff1aSopenharmony_ci        vpop            {d8-d15}
189cabdff1aSopenharmony_ci.endif
190cabdff1aSopenharmony_ci        pop             {r4-r11, pc}
191cabdff1aSopenharmony_ciendfunc
192cabdff1aSopenharmony_ci.endm
193cabdff1aSopenharmony_ci
194cabdff1aSopenharmony_ci#if HAVE_VFP || HAVE_NEON
195cabdff1aSopenharmony_ciclobbercheck vfp
196cabdff1aSopenharmony_ci#endif
197cabdff1aSopenharmony_ciclobbercheck novfp
198