xref: /trunk/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/call.s (revision 79670aa18e015d263a20a2826ce53832fcd22063)
1/**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements.  See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership.  The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License.  You may obtain a copy of the License at
10 *
11 *   http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied.  See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22// AArch64 (Apple Silicon, AAPCS64) outgoing-call trampoline for the C++-UNO
23// bridge.  Loads the argument registers from caller-prepared arrays, copies
24// any overflow arguments to the outgoing stack, performs the indirect call,
25// and stores the integer and FP/SIMD return registers back.
26//
27// See AAPCS64_BRIDGE_SPEC.md.  Mach-O assembler syntax; symbols are prefixed
28// with an underscore per the Darwin C ABI.
29//
30// extern "C" void callVirtualFunction(
31//     sal_uInt64  pFunction,     // x0: target C++ virtual method
32//     sal_uInt64  pIndirectRet,  // x1: value for x8 (indirect result ptr), 0 if none
33//     sal_uInt64 *pGPR,          // x2: 8 words  -> x0..x7
34//     double     *pFPR,          // x3: 8 doubles -> d0..d7
35//     sal_uInt64 *pStack,        // x4: overflow-arg words
36//     sal_uInt32  nStackWords,   // x5: number of 8-byte overflow words
37//     sal_uInt64 *pGPRReturn,    // x6: [out] x0,x1
38//     double     *pFPRReturn);   // x7: [out] d0..d3 (HFA up to 4 elements)
39
40    .text
41    .globl _callVirtualFunction
42    .p2align 2
43_callVirtualFunction:
44    .cfi_startproc
45    // prologue: save fp/lr and the callee-saved registers we use
46    stp     x29, x30, [sp, #-16]!
47    stp     x19, x20, [sp, #-16]!
48    stp     x21, x22, [sp, #-16]!
49    stp     x23, x24, [sp, #-16]!
50    mov     x29, sp
51    .cfi_def_cfa x29, 64
52    .cfi_offset x29, -16
53    .cfi_offset x30, -8
54
55    // stash inputs that must survive the call into callee-saved registers
56    mov     x19, x0                     // pFunction
57    mov     x20, x2                     // pGPR
58    mov     x21, x3                     // pFPR
59    mov     x22, x6                     // pGPRReturn
60    mov     x23, x7                     // pFPRReturn
61    mov     x24, x1                     // x8 indirect-result value
62
63    // allocate and copy the outgoing overflow stack arguments.
64    // bytes = ((nStackWords + 1) & ~1) * 8, to keep sp 16-byte aligned.
65    add     x9, x5, #1
66    bic     x9, x9, #1
67    lsl     x9, x9, #3
68    sub     sp, sp, x9
69    mov     x10, #0
70Lcvf_copy:
71    cmp     x10, x5
72    b.ge    Lcvf_copied
73    ldr     x11, [x4, x10, lsl #3]
74    str     x11, [sp, x10, lsl #3]
75    add     x10, x10, #1
76    b       Lcvf_copy
77Lcvf_copied:
78
79    // load the FP/SIMD argument registers d0..d7
80    ldp     d0, d1, [x21, #0]
81    ldp     d2, d3, [x21, #16]
82    ldp     d4, d5, [x21, #32]
83    ldp     d6, d7, [x21, #48]
84
85    // load the GP argument registers x0..x7 and the x8 indirect-result reg
86    mov     x8, x24
87    ldp     x6, x7, [x20, #48]
88    ldp     x4, x5, [x20, #32]
89    ldp     x2, x3, [x20, #16]
90    ldp     x0, x1, [x20, #0]
91
92    // perform the virtual call
93    blr     x19
94
95    // store the return registers
96    str     x0, [x22, #0]
97    str     x1, [x22, #8]
98    str     d0, [x23, #0]
99    str     d1, [x23, #8]
100    str     d2, [x23, #16]
101    str     d3, [x23, #24]
102
103    // epilogue
104    mov     sp, x29
105    ldp     x23, x24, [sp], #16
106    ldp     x21, x22, [sp], #16
107    ldp     x19, x20, [sp], #16
108    ldp     x29, x30, [sp], #16
109    ret
110    .cfi_endproc
111
112// ---------------------------------------------------------------------------
113// privateSnippetExecutor: the incoming (cpp2uno) register-spill executor.
114//
115// Reached by a BR from a per-vtable-slot code snippet (see codeSnippet() in
116// cpp2uno.cxx) with:
117//   x16 = (nVtableOffset << 32) | nFunctionIndex  (low bit 0x80000000 flags a
118//         hidden/indirect return)
119//   x0..x7, d0..d7, x8 = the original incoming arguments (untouched)
120//   sp  = the caller's stack-argument area (overflow)
121//   x30 = return address back into the original C++ caller
122//
123// It spills the argument registers to a save area and calls cpp_vtable_call,
124// then loads the return value back into x0/x1 and d0/d1 (or d0 for fp).
125//
126//   typelib_TypeClass cpp_vtable_call(
127//       sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
128//       void** gpreg, void** fpreg, void** ovrflw,
129//       void* pIndirectReturn, sal_uInt64* pRegisterReturn);
130//
131// Frame (176 bytes): [0]=x29,x30  [16..79]=x0..x7  [80..143]=d0..d7
132//                    [144..175]=return buffer (up to four HFA doubles).
133    .globl _privateSnippetExecutor
134    .p2align 2
135_privateSnippetExecutor:
136    .cfi_startproc
137    mov     x17, sp                     // x17 = ovrflw (incoming stack args)
138    stp     x29, x30, [sp, #-176]!
139    mov     x29, sp
140    .cfi_def_cfa x29, 176
141    .cfi_offset x29, -176
142    .cfi_offset x30, -168
143
144    stp     x0, x1, [sp, #16]           // save GP argument registers x0..x7
145    stp     x2, x3, [sp, #32]
146    stp     x4, x5, [sp, #48]
147    stp     x6, x7, [sp, #64]
148
149    stp     d0, d1, [sp, #80]           // save FP/SIMD argument registers d0..d7
150    stp     d2, d3, [sp, #96]
151    stp     d4, d5, [sp, #112]
152    stp     d6, d7, [sp, #128]
153
154    mov     w0, w16                     // nFunctionIndex (low 32 bits)
155    lsr     x1, x16, #32                // nVtableOffset (high 32 bits)
156    add     x2, sp, #16                 // gpreg
157    add     x3, sp, #80                 // fpreg
158    mov     x4, x17                     // ovrflw
159    mov     x5, x8                      // pIndirectReturn (x8 indirect-result reg)
160    add     x6, sp, #144                // pRegisterReturn (16-byte buffer)
161    bl      _cpp_vtable_call
162
163    cmp     w0, #0x100                   // RETURN_KIND_HFA_FLOAT
164    b.eq    Lpse_hfa_float
165    cmp     w0, #0x101                   // RETURN_KIND_HFA_DOUBLE
166    b.eq    Lpse_hfa_double
167    cmp     w0, #10                     // typelib_TypeClass_FLOAT
168    b.eq    Lpse_float
169    cmp     w0, #11                     // typelib_TypeClass_DOUBLE
170    b.eq    Lpse_float
171    // integer / pointer / <=16B aggregate: load both banks; caller reads the
172    // ones that matter for its return type.
173    ldp     x0, x1, [sp, #144]
174    ldp     d0, d1, [sp, #144]
175    b       Lpse_done
176Lpse_float:
177    ldr     d0, [sp, #144]
178    b       Lpse_done
179Lpse_hfa_float:
180    ldr     s0, [sp, #144]
181    ldr     s1, [sp, #148]
182    ldr     s2, [sp, #152]
183    ldr     s3, [sp, #156]
184    b       Lpse_done
185Lpse_hfa_double:
186    ldp     d0, d1, [sp, #144]
187    ldp     d2, d3, [sp, #160]
188Lpse_done:
189    mov     sp, x29
190    ldp     x29, x30, [sp], #176
191    ret
192    .cfi_endproc
193