[memprof] Upgrade a unit test to MemProf Version 3 (#117063)
[llvm-project.git] / openmp / runtime / src / z_Linux_asm.S
blobcc5344cdd124a707bcc15615ab1716cf4bde8630
1 //  z_Linux_asm.S:  - microtasking routines specifically
2 //                    written for Intel platforms running Linux* OS
4 //
5 ////===----------------------------------------------------------------------===//
6 ////
7 //// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
8 //// See https://llvm.org/LICENSE.txt for license information.
9 //// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
10 ////
11 ////===----------------------------------------------------------------------===//
14 // -----------------------------------------------------------------------
15 // macros
16 // -----------------------------------------------------------------------
18 #include "kmp_config.h"
20 #if KMP_ARCH_X86 || KMP_ARCH_X86_64
22 # if KMP_MIC
23 // the 'delay r16/r32/r64' should be used instead of the 'pause'.
24 // The delay operation has the effect of removing the current thread from
25 // the round-robin HT mechanism, and therefore speeds up the issue rate of
26 // the other threads on the same core.
28 // A value of 0 works fine for <= 2 threads per core, but causes the EPCC
29 // barrier time to increase greatly for 3 or more threads per core.
31 // A value of 100 works pretty well for up to 4 threads per core, but isn't
32 // quite as fast as 0 for 2 threads per core.
34 // We need to check what happens for oversubscription / > 4 threads per core.
35 // It is possible that we need to pass the delay value in as a parameter
36 // that the caller determines based on the total # threads / # cores.
38 //.macro pause_op
39 //      mov    $100, %rax
40 //      delay  %rax
41 //.endm
42 # else
43 #  define pause_op   .byte 0xf3,0x90
44 # endif // KMP_MIC
46 # if KMP_OS_DARWIN
47 #  define KMP_PREFIX_UNDERSCORE(x) _##x  // extra underscore for OS X* symbols
48 #  define KMP_LABEL(x) L_##x             // form the name of label
49 .macro KMP_CFI_DEF_OFFSET
50 .endmacro
51 .macro KMP_CFI_OFFSET
52 .endmacro
53 .macro KMP_CFI_REGISTER
54 .endmacro
55 .macro KMP_CFI_DEF
56 .endmacro
57 .macro ALIGN
58         .align $0
59 .endmacro
60 .macro DEBUG_INFO
61 /* Not sure what .size does in icc, not sure if we need to do something
62    similar for OS X*.
64 .endmacro
65 .macro PROC
66         ALIGN  4
67         .globl KMP_PREFIX_UNDERSCORE($0)
68 KMP_PREFIX_UNDERSCORE($0):
69 .endmacro
70 # else // KMP_OS_DARWIN
71 #  define KMP_PREFIX_UNDERSCORE(x) x //no extra underscore for Linux* OS symbols
72 // Format labels so that they don't override function names in gdb's backtraces
73 // MIC assembler doesn't accept .L syntax, the L works fine there (as well as
74 // on OS X*)
75 # if KMP_MIC
76 #  define KMP_LABEL(x) L_##x          // local label
77 # else
78 #  define KMP_LABEL(x) .L_##x         // local label hidden from backtraces
79 # endif // KMP_MIC
80 .macro ALIGN size
81         .align 1<<(\size)
82 .endm
83 .macro DEBUG_INFO proc
84         .cfi_endproc
85 // Not sure why we need .type and .size for the functions
86         .align 16
87         .type  \proc,@function
88         .size  \proc,.-\proc
89 .endm
90 .macro PROC proc
91         ALIGN  4
92         .globl KMP_PREFIX_UNDERSCORE(\proc)
93 KMP_PREFIX_UNDERSCORE(\proc):
94         .cfi_startproc
95 .endm
96 .macro KMP_CFI_DEF_OFFSET sz
97         .cfi_def_cfa_offset     \sz
98 .endm
99 .macro KMP_CFI_OFFSET reg, sz
100         .cfi_offset     \reg,\sz
101 .endm
102 .macro KMP_CFI_REGISTER reg
103         .cfi_def_cfa_register   \reg
104 .endm
105 .macro KMP_CFI_DEF reg, sz
106         .cfi_def_cfa    \reg,\sz
107 .endm
108 # endif // KMP_OS_DARWIN
109 #endif // KMP_ARCH_X86 || KMP_ARCH_x86_64
111 #if (KMP_OS_LINUX || KMP_OS_DARWIN || KMP_OS_WINDOWS) && (KMP_ARCH_AARCH64 || KMP_ARCH_AARCH64_32 || KMP_ARCH_ARM)
113 # if KMP_OS_DARWIN
114 #  define KMP_PREFIX_UNDERSCORE(x) _##x  // extra underscore for OS X* symbols
115 #  define KMP_LABEL(x) L_##x             // form the name of label
117 .macro ALIGN
118         .align $0
119 .endmacro
121 .macro DEBUG_INFO
122 /* Not sure what .size does in icc, not sure if we need to do something
123    similar for OS X*.
125 .endmacro
127 .macro PROC
128         ALIGN  4
129         .globl KMP_PREFIX_UNDERSCORE($0)
130 KMP_PREFIX_UNDERSCORE($0):
131 .endmacro
132 # elif KMP_OS_WINDOWS
133 #  define KMP_PREFIX_UNDERSCORE(x) x  // no extra underscore for Windows/ARM64 symbols
134 // Format labels so that they don't override function names in gdb's backtraces
135 #  define KMP_LABEL(x) .L_##x         // local label hidden from backtraces
137 .macro ALIGN size
138         .align 1<<(\size)
139 .endm
141 .macro DEBUG_INFO proc
142         ALIGN 2
143 .endm
145 .macro PROC proc
146         ALIGN 2
147         .globl KMP_PREFIX_UNDERSCORE(\proc)
148 KMP_PREFIX_UNDERSCORE(\proc):
149 .endm
150 # else // KMP_OS_DARWIN || KMP_OS_WINDOWS
151 #  define KMP_PREFIX_UNDERSCORE(x) x  // no extra underscore for Linux* OS symbols
152 // Format labels so that they don't override function names in gdb's backtraces
153 #  define KMP_LABEL(x) .L_##x         // local label hidden from backtraces
155 .macro ALIGN size
156         .align 1<<(\size)
157 .endm
159 .macro DEBUG_INFO proc
160         .cfi_endproc
161 // Not sure why we need .type and .size for the functions
162         ALIGN 2
163 #if KMP_ARCH_ARM
164         .type  \proc,%function
165 #else
166         .type  \proc,@function
167 #endif
168         .size  \proc,.-\proc
169 .endm
171 .macro PROC proc
172         ALIGN 2
173         .globl KMP_PREFIX_UNDERSCORE(\proc)
174 KMP_PREFIX_UNDERSCORE(\proc):
175         .cfi_startproc
176 .endm
177 # endif // KMP_OS_DARWIN
179 # if KMP_OS_LINUX
180 // BTI and PAC gnu property note
181 #  define NT_GNU_PROPERTY_TYPE_0 5
182 #  define GNU_PROPERTY_AARCH64_FEATURE_1_AND 0xc0000000
183 #  define GNU_PROPERTY_AARCH64_FEATURE_1_BTI 1
184 #  define GNU_PROPERTY_AARCH64_FEATURE_1_PAC 2
186 #  define GNU_PROPERTY(type, value)                                            \
187   .pushsection .note.gnu.property, "a";                                        \
188   .p2align 3;                                                                  \
189   .word 4;                                                                     \
190   .word 16;                                                                    \
191   .word NT_GNU_PROPERTY_TYPE_0;                                                \
192   .asciz "GNU";                                                                \
193   .word type;                                                                  \
194   .word 4;                                                                     \
195   .word value;                                                                 \
196   .word 0;                                                                     \
197   .popsection
198 # endif
200 # if defined(__ARM_FEATURE_BTI_DEFAULT)
201 #  define BTI_FLAG GNU_PROPERTY_AARCH64_FEATURE_1_BTI
202 # else
203 #  define BTI_FLAG 0
204 # endif
205 # if __ARM_FEATURE_PAC_DEFAULT & 3
206 #  define PAC_FLAG GNU_PROPERTY_AARCH64_FEATURE_1_PAC
207 # else
208 #  define PAC_FLAG 0
209 # endif
211 # if (BTI_FLAG | PAC_FLAG) != 0
212 #  if PAC_FLAG != 0
213 #   define PACBTI_C hint #25
214 #   define PACBTI_RET hint #29
215 #  else
216 #   define PACBTI_C hint #34
217 #   define PACBTI_RET
218 #  endif
219 #  define GNU_PROPERTY_BTI_PAC \
220     GNU_PROPERTY(GNU_PROPERTY_AARCH64_FEATURE_1_AND, BTI_FLAG | PAC_FLAG)
221 # else
222 #  define PACBTI_C
223 #  define PACBTI_RET
224 #  define GNU_PROPERTY_BTI_PAC
225 # endif
226 #endif // (KMP_OS_LINUX || KMP_OS_DARWIN || KMP_OS_WINDOWS) && (KMP_ARCH_AARCH64 || KMP_ARCH_AARCH64_32 || KMP_ARCH_ARM)
228 .macro COMMON name, size, align_power
229 #if KMP_OS_DARWIN
230         .comm \name, \size
231 #elif KMP_OS_WINDOWS
232         .comm \name, \size, \align_power
233 #else // !KMP_OS_DARWIN && !KMP_OS_WINDOWS
234         .comm \name, \size, (1<<(\align_power))
235 #endif
236 .endm
238 // -----------------------------------------------------------------------
239 // data
240 // -----------------------------------------------------------------------
242 #ifdef KMP_GOMP_COMPAT
244 // Support for unnamed common blocks.
246 // Because the symbol ".gomp_critical_user_" contains a ".", we have to
247 // put this stuff in assembly.
249 # if KMP_ARCH_X86
250 #  if KMP_OS_DARWIN
251         .data
252         .comm .gomp_critical_user_,32
253         .data
254         .globl ___kmp_unnamed_critical_addr
255 ___kmp_unnamed_critical_addr:
256         .long .gomp_critical_user_
257 #  else /* Linux* OS */
258         .data
259         .comm .gomp_critical_user_,32,8
260         .data
261         ALIGN 4
262         .global __kmp_unnamed_critical_addr
263 __kmp_unnamed_critical_addr:
264         .4byte .gomp_critical_user_
265         .type __kmp_unnamed_critical_addr,@object
266         .size __kmp_unnamed_critical_addr,4
267 #  endif /* KMP_OS_DARWIN */
268 # endif /* KMP_ARCH_X86 */
270 # if KMP_ARCH_X86_64
271 #  if KMP_OS_DARWIN
272         .data
273         .comm .gomp_critical_user_,32
274         .data
275         .globl ___kmp_unnamed_critical_addr
276 ___kmp_unnamed_critical_addr:
277         .quad .gomp_critical_user_
278 #  else /* Linux* OS */
279         .data
280         .comm .gomp_critical_user_,32,8
281         .data
282         ALIGN 8
283         .global __kmp_unnamed_critical_addr
284 __kmp_unnamed_critical_addr:
285         .8byte .gomp_critical_user_
286         .type __kmp_unnamed_critical_addr,@object
287         .size __kmp_unnamed_critical_addr,8
288 #  endif /* KMP_OS_DARWIN */
289 # endif /* KMP_ARCH_X86_64 */
291 #endif /* KMP_GOMP_COMPAT */
294 #if KMP_ARCH_X86 && !KMP_ARCH_PPC64
296 // -----------------------------------------------------------------------
297 // microtasking routines specifically written for IA-32 architecture
298 // running Linux* OS
299 // -----------------------------------------------------------------------
301         .ident "Intel Corporation"
302         .data
303         ALIGN 4
304 // void
305 // __kmp_x86_pause( void );
307         .text
308         PROC  __kmp_x86_pause
310         pause_op
311         ret
313         DEBUG_INFO __kmp_x86_pause
315 # if !KMP_ASM_INTRINS
317 //------------------------------------------------------------------------
318 // kmp_int32
319 // __kmp_test_then_add32( volatile kmp_int32 *p, kmp_int32 d );
321         PROC      __kmp_test_then_add32
323         movl      4(%esp), %ecx
324         movl      8(%esp), %eax
325         lock
326         xaddl     %eax,(%ecx)
327         ret
329         DEBUG_INFO __kmp_test_then_add32
331 //------------------------------------------------------------------------
332 // FUNCTION __kmp_xchg_fixed8
334 // kmp_int32
335 // __kmp_xchg_fixed8( volatile kmp_int8 *p, kmp_int8 d );
337 // parameters:
338 //      p:      4(%esp)
339 //      d:      8(%esp)
341 // return:      %al
342         PROC  __kmp_xchg_fixed8
344         movl      4(%esp), %ecx    // "p"
345         movb      8(%esp), %al  // "d"
347         lock
348         xchgb     %al,(%ecx)
349         ret
351         DEBUG_INFO __kmp_xchg_fixed8
354 //------------------------------------------------------------------------
355 // FUNCTION __kmp_xchg_fixed16
357 // kmp_int16
358 // __kmp_xchg_fixed16( volatile kmp_int16 *p, kmp_int16 d );
360 // parameters:
361 //      p:      4(%esp)
362 //      d:      8(%esp)
363 // return:     %ax
364         PROC  __kmp_xchg_fixed16
366         movl      4(%esp), %ecx    // "p"
367         movw      8(%esp), %ax  // "d"
369         lock
370         xchgw     %ax,(%ecx)
371         ret
373         DEBUG_INFO __kmp_xchg_fixed16
376 //------------------------------------------------------------------------
377 // FUNCTION __kmp_xchg_fixed32
379 // kmp_int32
380 // __kmp_xchg_fixed32( volatile kmp_int32 *p, kmp_int32 d );
382 // parameters:
383 //      p:      4(%esp)
384 //      d:      8(%esp)
386 // return:      %eax
387         PROC  __kmp_xchg_fixed32
389         movl      4(%esp), %ecx    // "p"
390         movl      8(%esp), %eax // "d"
392         lock
393         xchgl     %eax,(%ecx)
394         ret
396         DEBUG_INFO __kmp_xchg_fixed32
399 // kmp_int8
400 // __kmp_compare_and_store8( volatile kmp_int8 *p, kmp_int8 cv, kmp_int8 sv );
401         PROC  __kmp_compare_and_store8
403         movl      4(%esp), %ecx
404         movb      8(%esp), %al
405         movb      12(%esp), %dl
406         lock
407         cmpxchgb  %dl,(%ecx)
408         sete      %al           // if %al == (%ecx) set %al = 1 else set %al = 0
409         and       $1, %eax      // sign extend previous instruction
410         ret
412         DEBUG_INFO __kmp_compare_and_store8
414 // kmp_int16
415 // __kmp_compare_and_store16(volatile kmp_int16 *p, kmp_int16 cv, kmp_int16 sv);
416         PROC  __kmp_compare_and_store16
418         movl      4(%esp), %ecx
419         movw      8(%esp), %ax
420         movw      12(%esp), %dx
421         lock
422         cmpxchgw  %dx,(%ecx)
423         sete      %al           // if %ax == (%ecx) set %al = 1 else set %al = 0
424         and       $1, %eax      // sign extend previous instruction
425         ret
427         DEBUG_INFO __kmp_compare_and_store16
429 // kmp_int32
430 // __kmp_compare_and_store32(volatile kmp_int32 *p, kmp_int32 cv, kmp_int32 sv);
431         PROC  __kmp_compare_and_store32
433         movl      4(%esp), %ecx
434         movl      8(%esp), %eax
435         movl      12(%esp), %edx
436         lock
437         cmpxchgl  %edx,(%ecx)
438         sete      %al          // if %eax == (%ecx) set %al = 1 else set %al = 0
439         and       $1, %eax     // sign extend previous instruction
440         ret
442         DEBUG_INFO __kmp_compare_and_store32
444 // kmp_int32
445 // __kmp_compare_and_store64(volatile kmp_int64 *p, kmp_int64 cv, kmp_int64 s );
446         PROC  __kmp_compare_and_store64
448         pushl     %ebp
449         movl      %esp, %ebp
450         pushl     %ebx
451         pushl     %edi
452         movl      8(%ebp), %edi
453         movl      12(%ebp), %eax        // "cv" low order word
454         movl      16(%ebp), %edx        // "cv" high order word
455         movl      20(%ebp), %ebx        // "sv" low order word
456         movl      24(%ebp), %ecx        // "sv" high order word
457         lock
458         cmpxchg8b (%edi)
459         sete      %al      // if %edx:eax == (%edi) set %al = 1 else set %al = 0
460         and       $1, %eax // sign extend previous instruction
461         popl      %edi
462         popl      %ebx
463         movl      %ebp, %esp
464         popl      %ebp
465         ret
467         DEBUG_INFO __kmp_compare_and_store64
469 // kmp_int8
470 // __kmp_compare_and_store_ret8(volatile kmp_int8 *p, kmp_int8 cv, kmp_int8 sv);
471         PROC  __kmp_compare_and_store_ret8
473         movl      4(%esp), %ecx
474         movb      8(%esp), %al
475         movb      12(%esp), %dl
476         lock
477         cmpxchgb  %dl,(%ecx)
478         ret
480         DEBUG_INFO __kmp_compare_and_store_ret8
482 // kmp_int16
483 // __kmp_compare_and_store_ret16(volatile kmp_int16 *p, kmp_int16 cv,
484 //                               kmp_int16 sv);
485         PROC  __kmp_compare_and_store_ret16
487         movl      4(%esp), %ecx
488         movw      8(%esp), %ax
489         movw      12(%esp), %dx
490         lock
491         cmpxchgw  %dx,(%ecx)
492         ret
494         DEBUG_INFO __kmp_compare_and_store_ret16
496 // kmp_int32
497 // __kmp_compare_and_store_ret32(volatile kmp_int32 *p, kmp_int32 cv,
498 //                               kmp_int32 sv);
499         PROC  __kmp_compare_and_store_ret32
501         movl      4(%esp), %ecx
502         movl      8(%esp), %eax
503         movl      12(%esp), %edx
504         lock
505         cmpxchgl  %edx,(%ecx)
506         ret
508         DEBUG_INFO __kmp_compare_and_store_ret32
510 // kmp_int64
511 // __kmp_compare_and_store_ret64(volatile kmp_int64 *p, kmp_int64 cv,
512 //                               kmp_int64 sv);
513         PROC  __kmp_compare_and_store_ret64
515         pushl     %ebp
516         movl      %esp, %ebp
517         pushl     %ebx
518         pushl     %edi
519         movl      8(%ebp), %edi
520         movl      12(%ebp), %eax        // "cv" low order word
521         movl      16(%ebp), %edx        // "cv" high order word
522         movl      20(%ebp), %ebx        // "sv" low order word
523         movl      24(%ebp), %ecx        // "sv" high order word
524         lock
525         cmpxchg8b (%edi)
526         popl      %edi
527         popl      %ebx
528         movl      %ebp, %esp
529         popl      %ebp
530         ret
532         DEBUG_INFO __kmp_compare_and_store_ret64
535 //------------------------------------------------------------------------
536 // FUNCTION __kmp_xchg_real32
538 // kmp_real32
539 // __kmp_xchg_real32( volatile kmp_real32 *addr, kmp_real32 data );
541 // parameters:
542 //      addr:   4(%esp)
543 //      data:   8(%esp)
545 // return:      %eax
546         PROC  __kmp_xchg_real32
548         pushl   %ebp
549         movl    %esp, %ebp
550         subl    $4, %esp
551         pushl   %esi
553         movl    4(%ebp), %esi
554         flds    (%esi)
555                         // load <addr>
556         fsts    -4(%ebp)
557                         // store old value
559         movl    8(%ebp), %eax
561         lock
562         xchgl   %eax, (%esi)
564         flds    -4(%ebp)
565                         // return old value
567         popl    %esi
568         movl    %ebp, %esp
569         popl    %ebp
570         ret
572         DEBUG_INFO __kmp_xchg_real32
574 # endif /* !KMP_ASM_INTRINS */
576 //------------------------------------------------------------------------
577 // int
578 // __kmp_invoke_microtask( void (*pkfn) (int gtid, int tid, ...),
579 //                         int gtid, int tid,
580 //                         int argc, void *p_argv[]
581 // #if OMPT_SUPPORT
582 //                         ,
583 //                         void **exit_frame_ptr
584 // #endif
585 //                       ) {
586 // #if OMPT_SUPPORT
587 //   *exit_frame_ptr = OMPT_GET_FRAME_ADDRESS(0);
588 // #endif
590 //   (*pkfn)( & gtid, & tid, argv[0], ... );
591 //   return 1;
592 // }
594 // -- Begin __kmp_invoke_microtask
595 // mark_begin;
596         PROC  __kmp_invoke_microtask
598         pushl %ebp
599         KMP_CFI_DEF_OFFSET 8
600         KMP_CFI_OFFSET ebp,-8
601         movl %esp,%ebp          // establish the base pointer for this routine.
602         KMP_CFI_REGISTER ebp
603         subl $8,%esp            // allocate space for two local variables.
604                                 // These varibales are:
605                                 //      argv: -4(%ebp)
606                                 //      temp: -8(%ebp)
607                                 //
608         pushl %ebx              // save %ebx to use during this routine
609                                 //
610 #if OMPT_SUPPORT
611         movl 28(%ebp),%ebx      // get exit_frame address
612         movl %ebp,(%ebx)        // save exit_frame
613 #endif
615         movl 20(%ebp),%ebx      // Stack alignment - # args
616         addl $2,%ebx            // #args +2  Always pass at least 2 args (gtid and tid)
617         shll $2,%ebx            // Number of bytes used on stack: (#args+2)*4
618         movl %esp,%eax          //
619         subl %ebx,%eax          // %esp-((#args+2)*4) -> %eax -- without mods, stack ptr would be this
620         movl %eax,%ebx          // Save to %ebx
621         andl $0xFFFFFF80,%eax   // mask off 7 bits
622         subl %eax,%ebx          // Amount to subtract from %esp
623         subl %ebx,%esp          // Prepare the stack ptr --
624                                 //   now it will be aligned on 128-byte boundary at the call
626         movl 24(%ebp),%eax      // copy from p_argv[]
627         movl %eax,-4(%ebp)      // into the local variable *argv.
629         movl 20(%ebp),%ebx      // argc is 20(%ebp)
630         shll $2,%ebx
632 KMP_LABEL(invoke_2):
633         cmpl $0,%ebx
634         jg  KMP_LABEL(invoke_4)
635         jmp KMP_LABEL(invoke_3)
636         ALIGN 2
637 KMP_LABEL(invoke_4):
638         movl -4(%ebp),%eax
639         subl $4,%ebx                    // decrement argc.
640         addl %ebx,%eax                  // index into argv.
641         movl (%eax),%edx
642         pushl %edx
644         jmp KMP_LABEL(invoke_2)
645         ALIGN 2
646 KMP_LABEL(invoke_3):
647         leal 16(%ebp),%eax              // push & tid
648         pushl %eax
650         leal 12(%ebp),%eax              // push & gtid
651         pushl %eax
653         movl 8(%ebp),%ebx
654         call *%ebx                      // call (*pkfn)();
656         movl $1,%eax                    // return 1;
658         movl -12(%ebp),%ebx             // restore %ebx
659         leave
660         KMP_CFI_DEF esp,4
661         ret
663         DEBUG_INFO __kmp_invoke_microtask
664 // -- End  __kmp_invoke_microtask
667 // kmp_uint64
668 // __kmp_hardware_timestamp(void)
669         PROC  __kmp_hardware_timestamp
670         rdtsc
671         ret
673         DEBUG_INFO __kmp_hardware_timestamp
674 // -- End  __kmp_hardware_timestamp
676 #endif /* KMP_ARCH_X86 */
679 #if KMP_ARCH_X86_64
681 // -----------------------------------------------------------------------
682 // microtasking routines specifically written for IA-32 architecture and
683 // Intel(R) 64 running Linux* OS
684 // -----------------------------------------------------------------------
686 // -- Machine type P
687 // mark_description "Intel Corporation";
688         .ident "Intel Corporation"
689 // --   .file "z_Linux_asm.S"
690         .data
691         ALIGN 4
693 // To prevent getting our code into .data section .text added to every routine
694 // definition for x86_64.
695 //------------------------------------------------------------------------
696 # if !KMP_ASM_INTRINS
698 //------------------------------------------------------------------------
699 // FUNCTION __kmp_test_then_add32
701 // kmp_int32
702 // __kmp_test_then_add32( volatile kmp_int32 *p, kmp_int32 d );
704 // parameters:
705 //      p:      %rdi
706 //      d:      %esi
708 // return:      %eax
709         .text
710         PROC  __kmp_test_then_add32
712         movl      %esi, %eax    // "d"
713         lock
714         xaddl     %eax,(%rdi)
715         ret
717         DEBUG_INFO __kmp_test_then_add32
720 //------------------------------------------------------------------------
721 // FUNCTION __kmp_test_then_add64
723 // kmp_int64
724 // __kmp_test_then_add64( volatile kmp_int64 *p, kmp_int64 d );
726 // parameters:
727 //      p:      %rdi
728 //      d:      %rsi
729 //      return: %rax
730         .text
731         PROC  __kmp_test_then_add64
733         movq      %rsi, %rax    // "d"
734         lock
735         xaddq     %rax,(%rdi)
736         ret
738         DEBUG_INFO __kmp_test_then_add64
741 //------------------------------------------------------------------------
742 // FUNCTION __kmp_xchg_fixed8
744 // kmp_int32
745 // __kmp_xchg_fixed8( volatile kmp_int8 *p, kmp_int8 d );
747 // parameters:
748 //      p:      %rdi
749 //      d:      %sil
751 // return:      %al
752         .text
753         PROC  __kmp_xchg_fixed8
755         movb      %sil, %al     // "d"
757         lock
758         xchgb     %al,(%rdi)
759         ret
761         DEBUG_INFO __kmp_xchg_fixed8
764 //------------------------------------------------------------------------
765 // FUNCTION __kmp_xchg_fixed16
767 // kmp_int16
768 // __kmp_xchg_fixed16( volatile kmp_int16 *p, kmp_int16 d );
770 // parameters:
771 //      p:      %rdi
772 //      d:      %si
773 // return:     %ax
774         .text
775         PROC  __kmp_xchg_fixed16
777         movw      %si, %ax      // "d"
779         lock
780         xchgw     %ax,(%rdi)
781         ret
783         DEBUG_INFO __kmp_xchg_fixed16
786 //------------------------------------------------------------------------
787 // FUNCTION __kmp_xchg_fixed32
789 // kmp_int32
790 // __kmp_xchg_fixed32( volatile kmp_int32 *p, kmp_int32 d );
792 // parameters:
793 //      p:      %rdi
794 //      d:      %esi
796 // return:      %eax
797         .text
798         PROC  __kmp_xchg_fixed32
800         movl      %esi, %eax    // "d"
802         lock
803         xchgl     %eax,(%rdi)
804         ret
806         DEBUG_INFO __kmp_xchg_fixed32
809 //------------------------------------------------------------------------
810 // FUNCTION __kmp_xchg_fixed64
812 // kmp_int64
813 // __kmp_xchg_fixed64( volatile kmp_int64 *p, kmp_int64 d );
815 // parameters:
816 //      p:      %rdi
817 //      d:      %rsi
818 // return:      %rax
819         .text
820         PROC  __kmp_xchg_fixed64
822         movq      %rsi, %rax    // "d"
824         lock
825         xchgq     %rax,(%rdi)
826         ret
828         DEBUG_INFO __kmp_xchg_fixed64
831 //------------------------------------------------------------------------
832 // FUNCTION __kmp_compare_and_store8
834 // kmp_int8
835 // __kmp_compare_and_store8( volatile kmp_int8 *p, kmp_int8 cv, kmp_int8 sv );
837 // parameters:
838 //      p:      %rdi
839 //      cv:     %esi
840 //      sv:     %edx
842 // return:      %eax
843         .text
844         PROC  __kmp_compare_and_store8
846         movb      %sil, %al     // "cv"
847         lock
848         cmpxchgb  %dl,(%rdi)
849         sete      %al           // if %al == (%rdi) set %al = 1 else set %al = 0
850         andq      $1, %rax      // sign extend previous instruction for return value
851         ret
853         DEBUG_INFO __kmp_compare_and_store8
856 //------------------------------------------------------------------------
857 // FUNCTION __kmp_compare_and_store16
859 // kmp_int16
860 // __kmp_compare_and_store16( volatile kmp_int16 *p, kmp_int16 cv, kmp_int16 sv );
862 // parameters:
863 //      p:      %rdi
864 //      cv:     %si
865 //      sv:     %dx
867 // return:      %eax
868         .text
869         PROC  __kmp_compare_and_store16
871         movw      %si, %ax      // "cv"
872         lock
873         cmpxchgw  %dx,(%rdi)
874         sete      %al           // if %ax == (%rdi) set %al = 1 else set %al = 0
875         andq      $1, %rax      // sign extend previous instruction for return value
876         ret
878         DEBUG_INFO __kmp_compare_and_store16
881 //------------------------------------------------------------------------
882 // FUNCTION __kmp_compare_and_store32
884 // kmp_int32
885 // __kmp_compare_and_store32( volatile kmp_int32 *p, kmp_int32 cv, kmp_int32 sv );
887 // parameters:
888 //      p:      %rdi
889 //      cv:     %esi
890 //      sv:     %edx
892 // return:      %eax
893         .text
894         PROC  __kmp_compare_and_store32
896         movl      %esi, %eax    // "cv"
897         lock
898         cmpxchgl  %edx,(%rdi)
899         sete      %al           // if %eax == (%rdi) set %al = 1 else set %al = 0
900         andq      $1, %rax      // sign extend previous instruction for return value
901         ret
903         DEBUG_INFO __kmp_compare_and_store32
906 //------------------------------------------------------------------------
907 // FUNCTION __kmp_compare_and_store64
909 // kmp_int32
910 // __kmp_compare_and_store64( volatile kmp_int64 *p, kmp_int64 cv, kmp_int64 sv );
912 // parameters:
913 //      p:      %rdi
914 //      cv:     %rsi
915 //      sv:     %rdx
916 //      return: %eax
917         .text
918         PROC  __kmp_compare_and_store64
920         movq      %rsi, %rax    // "cv"
921         lock
922         cmpxchgq  %rdx,(%rdi)
923         sete      %al           // if %rax == (%rdi) set %al = 1 else set %al = 0
924         andq      $1, %rax      // sign extend previous instruction for return value
925         ret
927         DEBUG_INFO __kmp_compare_and_store64
929 //------------------------------------------------------------------------
930 // FUNCTION __kmp_compare_and_store_ret8
932 // kmp_int8
933 // __kmp_compare_and_store_ret8( volatile kmp_int8 *p, kmp_int8 cv, kmp_int8 sv );
935 // parameters:
936 //      p:      %rdi
937 //      cv:     %esi
938 //      sv:     %edx
940 // return:      %eax
941         .text
942         PROC  __kmp_compare_and_store_ret8
944         movb      %sil, %al     // "cv"
945         lock
946         cmpxchgb  %dl,(%rdi)
947         ret
949         DEBUG_INFO __kmp_compare_and_store_ret8
952 //------------------------------------------------------------------------
953 // FUNCTION __kmp_compare_and_store_ret16
955 // kmp_int16
956 // __kmp_compare_and_store16_ret( volatile kmp_int16 *p, kmp_int16 cv, kmp_int16 sv );
958 // parameters:
959 //      p:      %rdi
960 //      cv:     %si
961 //      sv:     %dx
963 // return:      %eax
964         .text
965         PROC  __kmp_compare_and_store_ret16
967         movw      %si, %ax      // "cv"
968         lock
969         cmpxchgw  %dx,(%rdi)
970         ret
972         DEBUG_INFO __kmp_compare_and_store_ret16
975 //------------------------------------------------------------------------
976 // FUNCTION __kmp_compare_and_store_ret32
978 // kmp_int32
979 // __kmp_compare_and_store_ret32( volatile kmp_int32 *p, kmp_int32 cv, kmp_int32 sv );
981 // parameters:
982 //      p:      %rdi
983 //      cv:     %esi
984 //      sv:     %edx
986 // return:      %eax
987         .text
988         PROC  __kmp_compare_and_store_ret32
990         movl      %esi, %eax    // "cv"
991         lock
992         cmpxchgl  %edx,(%rdi)
993         ret
995         DEBUG_INFO __kmp_compare_and_store_ret32
998 //------------------------------------------------------------------------
999 // FUNCTION __kmp_compare_and_store_ret64
1001 // kmp_int64
1002 // __kmp_compare_and_store_ret64( volatile kmp_int64 *p, kmp_int64 cv, kmp_int64 sv );
1004 // parameters:
1005 //      p:      %rdi
1006 //      cv:     %rsi
1007 //      sv:     %rdx
1008 //      return: %eax
1009         .text
1010         PROC  __kmp_compare_and_store_ret64
1012         movq      %rsi, %rax    // "cv"
1013         lock
1014         cmpxchgq  %rdx,(%rdi)
1015         ret
1017         DEBUG_INFO __kmp_compare_and_store_ret64
1019 # endif /* !KMP_ASM_INTRINS */
1022 # if !KMP_MIC
1024 # if !KMP_ASM_INTRINS
1026 //------------------------------------------------------------------------
1027 // FUNCTION __kmp_xchg_real32
1029 // kmp_real32
1030 // __kmp_xchg_real32( volatile kmp_real32 *addr, kmp_real32 data );
1032 // parameters:
1033 //      addr:   %rdi
1034 //      data:   %xmm0 (lower 4 bytes)
1036 // return:      %xmm0 (lower 4 bytes)
1037         .text
1038         PROC  __kmp_xchg_real32
1040         movd    %xmm0, %eax     // load "data" to eax
1042          lock
1043          xchgl %eax, (%rdi)
1045         movd    %eax, %xmm0     // load old value into return register
1047         ret
1049         DEBUG_INFO __kmp_xchg_real32
1052 //------------------------------------------------------------------------
1053 // FUNCTION __kmp_xchg_real64
1055 // kmp_real64
1056 // __kmp_xchg_real64( volatile kmp_real64 *addr, kmp_real64 data );
1058 // parameters:
1059 //      addr:   %rdi
1060 //      data:   %xmm0 (lower 8 bytes)
1061 //      return: %xmm0 (lower 8 bytes)
1062         .text
1063         PROC  __kmp_xchg_real64
1065         movd    %xmm0, %rax     // load "data" to rax
1067          lock
1068         xchgq  %rax, (%rdi)
1070         movd    %rax, %xmm0     // load old value into return register
1071         ret
1073         DEBUG_INFO __kmp_xchg_real64
1076 # endif /* !KMP_MIC */
1078 # endif /* !KMP_ASM_INTRINS */
1080 //------------------------------------------------------------------------
1081 // int
1082 // __kmp_invoke_microtask( void (*pkfn) (int gtid, int tid, ...),
1083 //                         int gtid, int tid,
1084 //                         int argc, void *p_argv[]
1085 // #if OMPT_SUPPORT
1086 //                         ,
1087 //                         void **exit_frame_ptr
1088 // #endif
1089 //                       ) {
1090 // #if OMPT_SUPPORT
1091 //   *exit_frame_ptr = OMPT_GET_FRAME_ADDRESS(0);
1092 // #endif
1094 //   (*pkfn)( & gtid, & tid, argv[0], ... );
1095 //   return 1;
1096 // }
1098 // note: at call to pkfn must have %rsp 128-byte aligned for compiler
1100 // parameters:
1101 //      %rdi:   pkfn
1102 //      %esi:   gtid
1103 //      %edx:   tid
1104 //      %ecx:   argc
1105 //      %r8:    p_argv
1106 //      %r9:    &exit_frame
1108 // locals:
1109 //      __gtid: gtid parm pushed on stack so can pass &gtid to pkfn
1110 //      __tid:  tid parm pushed on stack so can pass &tid to pkfn
1112 // reg temps:
1113 //      %rax:   used all over the place
1114 //      %rdx:   used in stack pointer alignment calculation
1115 //      %r11:   used to traverse p_argv array
1116 //      %rsi:   used as temporary for stack parameters
1117 //              used as temporary for number of pkfn parms to push
1118 //      %rbx:   used to hold pkfn address, and zero constant, callee-save
1120 // return:      %eax    (always 1/TRUE)
1121 __gtid = -16
1122 __tid = -24
1124 // -- Begin __kmp_invoke_microtask
1125 // mark_begin;
1126         .text
1127         PROC  __kmp_invoke_microtask
1129         pushq   %rbp            // save base pointer
1130         KMP_CFI_DEF_OFFSET 16
1131         KMP_CFI_OFFSET rbp,-16
1132         movq    %rsp,%rbp       // establish the base pointer for this routine.
1133         KMP_CFI_REGISTER rbp
1135 #if OMPT_SUPPORT
1136         movq    %rbp, (%r9)     // save exit_frame
1137 #endif
1139         pushq   %rbx            // %rbx is callee-saved register
1140         pushq   %rsi            // Put gtid on stack so can pass &tgid to pkfn
1141         pushq   %rdx            // Put tid on stack so can pass &tid to pkfn
1143         movq    %rcx, %rax      // Stack alignment calculation begins; argc -> %rax
1144         movq    $0, %rbx        // constant for cmovs later
1145         subq    $4, %rax        // subtract four args passed in registers to pkfn
1146 #if KMP_MIC
1147         js      KMP_LABEL(kmp_0)        // jump to movq
1148         jmp     KMP_LABEL(kmp_0_exit)   // jump ahead
1149 KMP_LABEL(kmp_0):
1150         movq    %rbx, %rax      // zero negative value in %rax <- max(0, argc-4)
1151 KMP_LABEL(kmp_0_exit):
1152 #else
1153         cmovsq  %rbx, %rax      // zero negative value in %rax <- max(0, argc-4)
1154 #endif // KMP_MIC
1156         movq    %rax, %rsi      // save max(0, argc-4) -> %rsi for later
1157         shlq    $3, %rax        // Number of bytes used on stack: max(0, argc-4)*8
1159         movq    %rsp, %rdx      //
1160         subq    %rax, %rdx      // %rsp-(max(0,argc-4)*8) -> %rdx --
1161                                 // without align, stack ptr would be this
1162         movq    %rdx, %rax      // Save to %rax
1164         andq    $0xFFFFFFFFFFFFFF80, %rax  // mask off lower 7 bits (128 bytes align)
1165         subq    %rax, %rdx      // Amount to subtract from %rsp
1166         subq    %rdx, %rsp      // Prepare the stack ptr --
1167                                 // now %rsp will align to 128-byte boundary at call site
1169                                 // setup pkfn parameter reg and stack
1170         movq    %rcx, %rax      // argc -> %rax
1171         cmpq    $0, %rsi
1172         je      KMP_LABEL(kmp_invoke_pass_parms)        // jump ahead if no parms to push
1173         shlq    $3, %rcx        // argc*8 -> %rcx
1174         movq    %r8, %rdx       // p_argv -> %rdx
1175         addq    %rcx, %rdx      // &p_argv[argc] -> %rdx
1177         movq    %rsi, %rcx      // max (0, argc-4) -> %rcx
1179 KMP_LABEL(kmp_invoke_push_parms):
1180         // push nth - 7th parms to pkfn on stack
1181         subq    $8, %rdx        // decrement p_argv pointer to previous parm
1182         movq    (%rdx), %rsi    // p_argv[%rcx-1] -> %rsi
1183         pushq   %rsi            // push p_argv[%rcx-1] onto stack (reverse order)
1184         subl    $1, %ecx
1186 // C69570: "X86_64_RELOC_BRANCH not supported" error at linking on mac_32e
1187 //              if the name of the label that is an operand of this jecxz starts with a dot (".");
1188 //         Apple's linker does not support 1-byte length relocation;
1189 //         Resolution: replace all .labelX entries with L_labelX.
1191         jecxz   KMP_LABEL(kmp_invoke_pass_parms)  // stop when four p_argv[] parms left
1192         jmp     KMP_LABEL(kmp_invoke_push_parms)
1193         ALIGN 3
1194 KMP_LABEL(kmp_invoke_pass_parms):       // put 1st - 6th parms to pkfn in registers.
1195                                 // order here is important to avoid trashing
1196                                 // registers used for both input and output parms!
1197         movq    %rdi, %rbx      // pkfn -> %rbx
1198         leaq    __gtid(%rbp), %rdi // &gtid -> %rdi (store 1st parm to pkfn)
1199         leaq    __tid(%rbp), %rsi  // &tid -> %rsi (store 2nd parm to pkfn)
1200         // Check if argc is 0
1201         cmpq $0, %rax
1202         je KMP_LABEL(kmp_no_args) // Jump ahead
1204         movq    %r8, %r11       // p_argv -> %r11
1206 #if KMP_MIC
1207         cmpq    $4, %rax        // argc >= 4?
1208         jns     KMP_LABEL(kmp_4)        // jump to movq
1209         jmp     KMP_LABEL(kmp_4_exit)   // jump ahead
1210 KMP_LABEL(kmp_4):
1211         movq    24(%r11), %r9   // p_argv[3] -> %r9 (store 6th parm to pkfn)
1212 KMP_LABEL(kmp_4_exit):
1214         cmpq    $3, %rax        // argc >= 3?
1215         jns     KMP_LABEL(kmp_3)        // jump to movq
1216         jmp     KMP_LABEL(kmp_3_exit)   // jump ahead
1217 KMP_LABEL(kmp_3):
1218         movq    16(%r11), %r8   // p_argv[2] -> %r8 (store 5th parm to pkfn)
1219 KMP_LABEL(kmp_3_exit):
1221         cmpq    $2, %rax        // argc >= 2?
1222         jns     KMP_LABEL(kmp_2)        // jump to movq
1223         jmp     KMP_LABEL(kmp_2_exit)   // jump ahead
1224 KMP_LABEL(kmp_2):
1225         movq    8(%r11), %rcx   // p_argv[1] -> %rcx (store 4th parm to pkfn)
1226 KMP_LABEL(kmp_2_exit):
1228         cmpq    $1, %rax        // argc >= 1?
1229         jns     KMP_LABEL(kmp_1)        // jump to movq
1230         jmp     KMP_LABEL(kmp_1_exit)   // jump ahead
1231 KMP_LABEL(kmp_1):
1232         movq    (%r11), %rdx    // p_argv[0] -> %rdx (store 3rd parm to pkfn)
1233 KMP_LABEL(kmp_1_exit):
1234 #else
1235         cmpq    $4, %rax        // argc >= 4?
1236         cmovnsq 24(%r11), %r9   // p_argv[3] -> %r9 (store 6th parm to pkfn)
1238         cmpq    $3, %rax        // argc >= 3?
1239         cmovnsq 16(%r11), %r8   // p_argv[2] -> %r8 (store 5th parm to pkfn)
1241         cmpq    $2, %rax        // argc >= 2?
1242         cmovnsq 8(%r11), %rcx   // p_argv[1] -> %rcx (store 4th parm to pkfn)
1244         cmpq    $1, %rax        // argc >= 1?
1245         cmovnsq (%r11), %rdx    // p_argv[0] -> %rdx (store 3rd parm to pkfn)
1246 #endif // KMP_MIC
1248 KMP_LABEL(kmp_no_args):
1249         call    *%rbx           // call (*pkfn)();
1250         movq    $1, %rax        // move 1 into return register;
1252         movq    -8(%rbp), %rbx  // restore %rbx using %rbp since %rsp was modified
1253         movq    %rbp, %rsp      // restore stack pointer
1254         popq    %rbp            // restore frame pointer
1255         KMP_CFI_DEF rsp,8
1256         ret
1258         DEBUG_INFO __kmp_invoke_microtask
1259 // -- End  __kmp_invoke_microtask
1261 // kmp_uint64
1262 // __kmp_hardware_timestamp(void)
1263         .text
1264         PROC  __kmp_hardware_timestamp
1265         rdtsc
1266         shlq    $32, %rdx
1267         orq     %rdx, %rax
1268         ret
1270         DEBUG_INFO __kmp_hardware_timestamp
1271 // -- End  __kmp_hardware_timestamp
1273 //------------------------------------------------------------------------
1274 // FUNCTION __kmp_bsr32
1276 // int
1277 // __kmp_bsr32( int );
1278         .text
1279         PROC  __kmp_bsr32
1281         bsr    %edi,%eax
1282         ret
1284         DEBUG_INFO __kmp_bsr32
1286 // -----------------------------------------------------------------------
1287 #endif /* KMP_ARCH_X86_64 */
1289 // '
1290 #if (KMP_OS_LINUX || KMP_OS_DARWIN || KMP_OS_WINDOWS) && (KMP_ARCH_AARCH64 || KMP_ARCH_AARCH64_32)
1292 //------------------------------------------------------------------------
1293 // int
1294 // __kmp_invoke_microtask( void (*pkfn) (int gtid, int tid, ...),
1295 //                         int gtid, int tid,
1296 //                         int argc, void *p_argv[]
1297 // #if OMPT_SUPPORT
1298 //                         ,
1299 //                         void **exit_frame_ptr
1300 // #endif
1301 //                       ) {
1302 // #if OMPT_SUPPORT
1303 //   *exit_frame_ptr = OMPT_GET_FRAME_ADDRESS(0);
1304 // #endif
1306 //   (*pkfn)( & gtid, & tid, argv[0], ... );
1308 // // FIXME: This is done at call-site and can be removed here.
1309 // #if OMPT_SUPPORT
1310 //   *exit_frame_ptr = 0;
1311 // #endif
1313 //   return 1;
1314 // }
1316 // parameters:
1317 //      x0:     pkfn
1318 //      w1:     gtid
1319 //      w2:     tid
1320 //      w3:     argc
1321 //      x4:     p_argv
1322 //      x5:     &exit_frame
1324 // locals:
1325 //      __gtid: gtid parm pushed on stack so can pass &gtid to pkfn
1326 //      __tid:  tid parm pushed on stack so can pass &tid to pkfn
1328 // reg temps:
1329 //       x8:    used to hold pkfn address
1330 //       w9:    used as temporary for number of pkfn parms
1331 //      x10:    used to traverse p_argv array
1332 //      x11:    used as temporary for stack placement calculation
1333 //      x12:    used as temporary for stack parameters
1334 //      x19:    used to preserve exit_frame_ptr, callee-save
1336 // return:      w0      (always 1/TRUE)
1339 __gtid = 4
1340 __tid = 8
1342 // -- Begin __kmp_invoke_microtask
1343 // mark_begin;
1344         .text
1345         PROC __kmp_invoke_microtask
1346         PACBTI_C
1348         stp     x29, x30, [sp, #-16]!
1349 # if OMPT_SUPPORT
1350         stp     x19, x20, [sp, #-16]!
1351 # endif
1352         mov     x29, sp
1354         orr     w9, wzr, #1
1355         add     w9, w9, w3, lsr #1
1356         sub     sp, sp, w9, uxtw #4
1357         mov     x11, sp
1359         mov     x8, x0
1360         str     w1, [x29, #-__gtid]
1361         str     w2, [x29, #-__tid]
1362         mov     w9, w3
1363         mov     x10, x4
1364 # if OMPT_SUPPORT
1365         mov     x19, x5
1366         str     x29, [x19]
1367 # endif
1369         sub     x0, x29, #__gtid
1370         sub     x1, x29, #__tid
1372         cbz     w9, KMP_LABEL(kmp_1)
1373         ldr     x2, [x10]
1375         sub     w9, w9, #1
1376         cbz     w9, KMP_LABEL(kmp_1)
1377         ldr     x3, [x10, #8]!
1379         sub     w9, w9, #1
1380         cbz     w9, KMP_LABEL(kmp_1)
1381         ldr     x4, [x10, #8]!
1383         sub     w9, w9, #1
1384         cbz     w9, KMP_LABEL(kmp_1)
1385         ldr     x5, [x10, #8]!
1387         sub     w9, w9, #1
1388         cbz     w9, KMP_LABEL(kmp_1)
1389         ldr     x6, [x10, #8]!
1391         sub     w9, w9, #1
1392         cbz     w9, KMP_LABEL(kmp_1)
1393         ldr     x7, [x10, #8]!
1395 KMP_LABEL(kmp_0):
1396         sub     w9, w9, #1
1397         cbz     w9, KMP_LABEL(kmp_1)
1398         ldr     x12, [x10, #8]!
1399         str     x12, [x11], #8
1400         b       KMP_LABEL(kmp_0)
1401 KMP_LABEL(kmp_1):
1402         blr     x8
1403         orr     w0, wzr, #1
1404         mov     sp, x29
1405 # if OMPT_SUPPORT
1406         str     xzr, [x19]
1407         ldp     x19, x20, [sp], #16
1408 # endif
1409         ldp     x29, x30, [sp], #16
1410         PACBTI_RET
1411         ret
1413         DEBUG_INFO __kmp_invoke_microtask
1414 // -- End  __kmp_invoke_microtask
1416 #endif /* (KMP_OS_LINUX || KMP_OS_DARWIN || KMP_OS_WINDOWS) && (KMP_ARCH_AARCH64 || KMP_ARCH_AARCH64_32) */
1418 #if (KMP_OS_LINUX || KMP_OS_DARWIN || KMP_OS_WINDOWS) && KMP_ARCH_ARM
1420 //------------------------------------------------------------------------
1421 // int
1422 // __kmp_invoke_microtask( void (*pkfn) (int gtid, int tid, ...),
1423 //                         int gtid, int tid,
1424 //                         int argc, void *p_argv[]
1425 // #if OMPT_SUPPORT
1426 //                         ,
1427 //                         void **exit_frame_ptr
1428 // #endif
1429 //                       ) {
1430 // #if OMPT_SUPPORT
1431 //   *exit_frame_ptr = OMPT_GET_FRAME_ADDRESS(0);
1432 // #endif
1434 //   (*pkfn)( & gtid, & tid, argv[0], ... );
1436 // // FIXME: This is done at call-site and can be removed here.
1437 // #if OMPT_SUPPORT
1438 //   *exit_frame_ptr = 0;
1439 // #endif
1441 //   return 1;
1442 // }
1444 // parameters:
1445 //      r0:     pkfn
1446 //      r1:     gtid
1447 //      r2:     tid
1448 //      r3:     argc
1449 //      r4(stack):      p_argv
1450 //      r5(stack):      &exit_frame
1452 // locals:
1453 //      __gtid: gtid parm pushed on stack so can pass &gtid to pkfn
1454 //      __tid:  tid parm pushed on stack so can pass &tid to pkfn
1456 // reg temps:
1457 //       r4:    used to hold pkfn address
1458 //       r5:    used as temporary for number of pkfn parms
1459 //       r6:    used to traverse p_argv array
1460 //       r7:    frame pointer (in some configurations)
1461 //       r8:    used as temporary for stack placement calculation
1462 //              and as pointer to base of callee saved area
1463 //       r9:    used as temporary for stack parameters
1464 //      r10:    used to preserve exit_frame_ptr, callee-save
1465 //      r11:    frame pointer (in some configurations)
1467 // return:      r0      (always 1/TRUE)
1470 __gtid = 4
1471 __tid = 8
1473 // -- Begin __kmp_invoke_microtask
1474 // mark_begin;
1475         .text
1476         PROC __kmp_invoke_microtask
1478         // Pushing one extra register (r3) to keep the stack aligned
1479         // for when we call pkfn below
1480         push    {r3-r11,lr}
1481         // Load p_argv and &exit_frame
1482         ldr     r4, [sp, #10*4]
1483 # if OMPT_SUPPORT
1484         ldr     r5, [sp, #11*4]
1485 # endif
1487 # if KMP_OS_DARWIN || (defined(__thumb__) && !KMP_OS_WINDOWS)
1488 # define FP r7
1489 # define FPOFF 4*4
1490 #else
1491 # define FP r11
1492 # define FPOFF 8*4
1493 #endif
1494         add     FP, sp, #FPOFF
1495 # if OMPT_SUPPORT
1496         mov     r10, r5
1497         str     FP, [r10]
1498 # endif
1499         mov     r8, sp
1501         // Calculate how much stack to allocate, in increments of 8 bytes.
1502         // We strictly need 4*(argc-2) bytes (2 arguments are passed in
1503         // registers) but allocate 4*argc for simplicity (to avoid needing
1504         // to handle the argc<2 cases). We align the number of bytes
1505         // allocated to 8 bytes, to keep the stack aligned. (Since we
1506         // already allocate more than enough, it's ok to round down
1507         // instead of up for the alignment.) We allocate another extra
1508         // 8 bytes for gtid and tid.
1509         mov     r5, #1
1510         add     r5, r5, r3, lsr #1
1511         sub     sp, sp, r5, lsl #3
1513         str     r1, [r8, #-__gtid]
1514         str     r2, [r8, #-__tid]
1515         mov     r5, r3
1516         mov     r6, r4
1517         mov     r4, r0
1519         // Prepare the first 2 parameters to pkfn - pointers to gtid and tid
1520         // in our stack frame.
1521         sub     r0, r8, #__gtid
1522         sub     r1, r8, #__tid
1524         mov     r8, sp
1526         // Load p_argv[0] and p_argv[1] into r2 and r3, if argc >= 1/2
1527         cmp     r5, #0
1528         beq     KMP_LABEL(kmp_1)
1529         ldr     r2, [r6]
1531         subs    r5, r5, #1
1532         beq     KMP_LABEL(kmp_1)
1533         ldr     r3, [r6, #4]!
1535         // Loop, loading the rest of p_argv and writing the elements on the
1536         // stack.
1537 KMP_LABEL(kmp_0):
1538         subs    r5, r5, #1
1539         beq     KMP_LABEL(kmp_1)
1540         ldr     r12, [r6, #4]!
1541         str     r12, [r8], #4
1542         b       KMP_LABEL(kmp_0)
1543 KMP_LABEL(kmp_1):
1544         blx     r4
1545         mov     r0, #1
1547         sub     r4, FP, #FPOFF
1548         mov     sp, r4
1549 # undef FP
1550 # undef FPOFF
1552 # if OMPT_SUPPORT
1553         mov     r1, #0
1554         str     r1, [r10]
1555 # endif
1556         pop     {r3-r11,pc}
1558         DEBUG_INFO __kmp_invoke_microtask
1559 // -- End  __kmp_invoke_microtask
1561 #endif /* (KMP_OS_LINUX || KMP_OS_DARWIN || KMP_OS_WINDOWS) && KMP_ARCH_ARM */
1563 #if KMP_ARCH_PPC64
1565 //------------------------------------------------------------------------
1566 // int
1567 // __kmp_invoke_microtask( void (*pkfn) (int gtid, int tid, ...),
1568 //                         int gtid, int tid,
1569 //                         int argc, void *p_argv[]
1570 // #if OMPT_SUPPORT
1571 //                         ,
1572 //                         void **exit_frame_ptr
1573 // #endif
1574 //                       ) {
1575 // #if OMPT_SUPPORT
1576 //   *exit_frame_ptr = OMPT_GET_FRAME_ADDRESS(0);
1577 // #endif
1579 //   (*pkfn)( & gtid, & tid, argv[0], ... );
1581 // // FIXME: This is done at call-site and can be removed here.
1582 // #if OMPT_SUPPORT
1583 //   *exit_frame_ptr = 0;
1584 // #endif
1586 //   return 1;
1587 // }
1589 // parameters:
1590 //      r3:     pkfn
1591 //      r4:     gtid
1592 //      r5:     tid
1593 //      r6:     argc
1594 //      r7:     p_argv
1595 //      r8:     &exit_frame
1597 // return:      r3      (always 1/TRUE)
1599         .text
1600 # if KMP_ARCH_PPC64_ELFv2
1601         .abiversion 2
1602 # endif
1603         .globl  __kmp_invoke_microtask
1605 # if KMP_ARCH_PPC64_ELFv2
1606         .p2align        4
1607 # else
1608         .p2align        2
1609 # endif
1611         .type   __kmp_invoke_microtask,@function
1613 # if KMP_ARCH_PPC64_ELFv2
1614 __kmp_invoke_microtask:
1615 .Lfunc_begin0:
1616 .Lfunc_gep0:
1617         addis 2, 12, .TOC.-.Lfunc_gep0@ha
1618         addi 2, 2, .TOC.-.Lfunc_gep0@l
1619 .Lfunc_lep0:
1620         .localentry     __kmp_invoke_microtask, .Lfunc_lep0-.Lfunc_gep0
1621 # else
1622         .section        .opd,"aw",@progbits
1623 __kmp_invoke_microtask:
1624         .p2align        3
1625         .quad   .Lfunc_begin0
1626         .quad   .TOC.@tocbase
1627         .quad   0
1628         .text
1629 .Lfunc_begin0:
1630 # endif
1632 // -- Begin __kmp_invoke_microtask
1633 // mark_begin;
1635 // We need to allocate a stack frame large enough to hold all of the parameters
1636 // on the stack for the microtask plus what this function needs. That's 48
1637 // bytes under the ELFv1 ABI (32 bytes under ELFv2), plus 8*(2 + argc) for the
1638 // parameters to the microtask, plus 8 bytes to store the values of r4 and r5,
1639 // and 8 bytes to store r31. With OMP-T support, we need an additional 8 bytes
1640 // to save r30 to hold a copy of r8.
1642         .cfi_startproc
1643         mflr 0
1644         std 31, -8(1)
1645         std 0, 16(1)
1647 // This is unusual because normally we'd set r31 equal to r1 after the stack
1648 // frame is established. In this case, however, we need to dynamically compute
1649 // the stack frame size, and so we keep a direct copy of r1 to access our
1650 // register save areas and restore the r1 value before returning.
1651         mr 31, 1
1652         .cfi_def_cfa_register r31
1653         .cfi_offset r31, -8
1654         .cfi_offset lr, 16
1656 // Compute the size necessary for the local stack frame.
1657 # if KMP_ARCH_PPC64_ELFv2
1658         li 12, 72
1659 # else
1660         li 12, 88
1661 # endif
1662         sldi 0, 6, 3
1663         add 12, 0, 12
1664         neg 12, 12
1666 // We need to make sure that the stack frame stays aligned (to 16 bytes).
1667         li 0, -16
1668         and 12, 0, 12
1670 // Establish the local stack frame.
1671         stdux 1, 1, 12
1673 # if OMPT_SUPPORT
1674         .cfi_offset r30, -16
1675         std 30, -16(31)
1676         std 1, 0(8)
1677         mr 30, 8
1678 # endif
1680 // Store gtid and tid to the stack because they're passed by reference to the microtask.
1681         stw 4, -20(31)
1682         stw 5, -24(31)
1684         mr 12, 6
1685         mr 4, 7
1687         cmpwi 0, 12, 1
1688         blt      0, .Lcall
1690         ld 5, 0(4)
1692         cmpwi 0, 12, 2
1693         blt      0, .Lcall
1695         ld 6, 8(4)
1697         cmpwi 0, 12, 3
1698         blt      0, .Lcall
1700         ld 7, 16(4)
1702         cmpwi 0, 12, 4
1703         blt      0, .Lcall
1705         ld 8, 24(4)
1707         cmpwi 0, 12, 5
1708         blt      0, .Lcall
1710         ld 9, 32(4)
1712         cmpwi 0, 12, 6
1713         blt      0, .Lcall
1715         ld 10, 40(4)
1717         cmpwi 0, 12, 7
1718         blt      0, .Lcall
1720 // There are more than 6 microtask parameters, so we need to store the
1721 // remainder to the stack.
1722         addi 12, 12, -6
1723         mtctr 12
1725 // These are set to 8 bytes before the first desired store address (we're using
1726 // pre-increment loads and stores in the loop below). The parameter save area
1727 // for the microtask begins 48 + 8*8 == 112 bytes above r1 for ELFv1 and
1728 // 32 + 8*8 == 96 bytes above r1 for ELFv2.
1729         addi 4, 4, 40
1730 # if KMP_ARCH_PPC64_ELFv2
1731         addi 12, 1, 88
1732 # else
1733         addi 12, 1, 104
1734 # endif
1736 .Lnext:
1737         ldu 0, 8(4)
1738         stdu 0, 8(12)
1739         bdnz .Lnext
1741 .Lcall:
1742 # if KMP_ARCH_PPC64_ELFv2
1743         std 2, 24(1)
1744         mr 12, 3
1745 #else
1746         std 2, 40(1)
1747 // For ELFv1, we need to load the actual function address from the function descriptor.
1748         ld 12, 0(3)
1749         ld 2, 8(3)
1750         ld 11, 16(3)
1751 #endif
1753         addi 3, 31, -20
1754         addi 4, 31, -24
1756         mtctr 12
1757         bctrl
1758 # if KMP_ARCH_PPC64_ELFv2
1759         ld 2, 24(1)
1760 # else
1761         ld 2, 40(1)
1762 # endif
1764 # if OMPT_SUPPORT
1765         li 3, 0
1766         std 3, 0(30)
1767 # endif
1769         li 3, 1
1771 # if OMPT_SUPPORT
1772         ld 30, -16(31)
1773 # endif
1775         mr 1, 31
1776         ld 0, 16(1)
1777         ld 31, -8(1)
1778         mtlr 0
1779         blr
1781         .long   0
1782         .quad   0
1783 .Lfunc_end0:
1784         .size   __kmp_invoke_microtask, .Lfunc_end0-.Lfunc_begin0
1785         .cfi_endproc
1787 // -- End  __kmp_invoke_microtask
1789 #endif /* KMP_ARCH_PPC64 */
1791 #if KMP_ARCH_RISCV64
1793 //------------------------------------------------------------------------
1795 // typedef void (*microtask_t)(int *gtid, int *tid, ...);
1797 // int __kmp_invoke_microtask(microtask_t pkfn, int gtid, int tid, int argc,
1798 //                            void *p_argv[]
1799 // #if OMPT_SUPPORT
1800 //                            ,
1801 //                            void **exit_frame_ptr
1802 // #endif
1803 //                            ) {
1804 // #if OMPT_SUPPORT
1805 //   *exit_frame_ptr = OMPT_GET_FRAME_ADDRESS(0);
1806 // #endif
1808 //   (*pkfn)(&gtid, &tid, argv[0], ...);
1810 //   return 1;
1811 // }
1813 // Parameters:
1814 //   a0: pkfn
1815 //   a1: gtid
1816 //   a2: tid
1817 //   a3: argc
1818 //   a4: p_argv
1819 //   a5: exit_frame_ptr
1821 // Locals:
1822 //   __gtid: gtid param pushed on stack so can pass &gtid to pkfn
1823 //   __tid: tid param pushed on stack so can pass &tid to pkfn
1825 // Temp. registers:
1827 //  t0: used to calculate the dynamic stack size / used to hold pkfn address
1828 //  t1: used as temporary for stack placement calculation
1829 //  t2: used as temporary for stack arguments
1830 //  t3: used as temporary for number of remaining pkfn parms
1831 //  t4: used to traverse p_argv array
1833 // return: a0 (always 1/TRUE)
1836 __gtid = -20
1837 __tid = -24
1839 // -- Begin __kmp_invoke_microtask
1840 // mark_begin;
1841         .text
1842         .globl  __kmp_invoke_microtask
1843         .p2align        1
1844         .type   __kmp_invoke_microtask,@function
1845 __kmp_invoke_microtask:
1846         .cfi_startproc
1848         // First, save ra and fp
1849         addi    sp, sp, -16
1850         sd      ra, 8(sp)
1851         sd      fp, 0(sp)
1852         addi    fp, sp, 16
1853         .cfi_def_cfa    fp, 0
1854         .cfi_offset     ra, -8
1855         .cfi_offset     fp, -16
1857         // Compute the dynamic stack size:
1858         //
1859         // - We need 8 bytes for storing 'gtid' and 'tid', so we can pass them by
1860         //   reference
1861         // - We need 8 bytes for each argument that cannot be passed to the 'pkfn'
1862         //   function by register. Given that we have 8 of such registers (a[0-7])
1863         //   and two + 'argc' arguments (consider &gtid and &tid), we need to
1864         //   reserve max(0, argc - 6)*8 extra bytes
1865         //
1866         // The total number of bytes is then max(0, argc - 6)*8 + 8
1868         // Compute max(0, argc - 6) using the following bithack:
1869         // max(0, x) = x - (x & (x >> 31)), where x := argc - 6
1870         // Source: http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax
1871         addi    t0, a3, -6
1872         srai    t1, t0, 31
1873         and     t1, t0, t1
1874         sub     t0, t0, t1
1876         addi    t0, t0, 1
1878         slli    t0, t0, 3
1879         sub     sp, sp, t0
1881         // Align the stack to 16 bytes
1882         andi    sp, sp, -16
1884         mv      t0, a0
1885         mv      t3, a3
1886         mv      t4, a4
1888 #if OMPT_SUPPORT
1889         // Save frame pointer into exit_frame
1890         sd      fp, 0(a5)
1891 #endif
1893         // Prepare arguments for the pkfn function (first 8 using a0-a7 registers)
1895         sw      a1, __gtid(fp)
1896         sw      a2, __tid(fp)
1898         addi    a0, fp, __gtid
1899         addi    a1, fp, __tid
1901         beqz    t3, .L_kmp_3
1902         ld      a2, 0(t4)
1904         addi    t3, t3, -1
1905         beqz    t3, .L_kmp_3
1906         ld      a3, 8(t4)
1908         addi    t3, t3, -1
1909         beqz    t3, .L_kmp_3
1910         ld      a4, 16(t4)
1912         addi    t3, t3, -1
1913         beqz    t3, .L_kmp_3
1914         ld      a5, 24(t4)
1916         addi    t3, t3, -1
1917         beqz    t3, .L_kmp_3
1918         ld      a6, 32(t4)
1920         addi    t3, t3, -1
1921         beqz    t3, .L_kmp_3
1922         ld      a7, 40(t4)
1924         // Prepare any additional argument passed through the stack
1925         addi    t4, t4, 48
1926         mv      t1, sp
1927         j .L_kmp_2
1928 .L_kmp_1:
1929         ld      t2, 0(t4)
1930         sd      t2, 0(t1)
1931         addi    t4, t4, 8
1932         addi    t1, t1, 8
1933 .L_kmp_2:
1934         addi    t3, t3, -1
1935         bnez    t3, .L_kmp_1
1937 .L_kmp_3:
1938         // Call pkfn function
1939         jalr    t0
1941         // Restore stack and return
1943         addi    a0, zero, 1
1945         addi    sp, fp, -16
1946         ld      fp, 0(sp)
1947         ld      ra, 8(sp)
1948         addi    sp, sp, 16
1949         ret
1950 .Lfunc_end0:
1951         .size   __kmp_invoke_microtask, .Lfunc_end0-__kmp_invoke_microtask
1952         .cfi_endproc
1954 // -- End  __kmp_invoke_microtask
1956 #endif /* KMP_ARCH_RISCV64 */
1958 #if KMP_ARCH_LOONGARCH64
1960 //------------------------------------------------------------------------
1962 // typedef void (*microtask_t)(int *gtid, int *tid, ...);
1964 // int __kmp_invoke_microtask(microtask_t pkfn, int gtid, int tid, int argc,
1965 //                            void *p_argv[]
1966 // #if OMPT_SUPPORT
1967 //                            ,
1968 //                            void **exit_frame_ptr
1969 // #endif
1970 //                            ) {
1971 // #if OMPT_SUPPORT
1972 //   *exit_frame_ptr = OMPT_GET_FRAME_ADDRESS(0);
1973 // #endif
1975 //   (*pkfn)(&gtid, &tid, argv[0], ...);
1977 //   return 1;
1978 // }
1980 // Parameters:
1981 //   a0: pkfn
1982 //   a1: gtid
1983 //   a2: tid
1984 //   a3: argc
1985 //   a4: p_argv
1986 //   a5: exit_frame_ptr
1988 // Locals:
1989 //   __gtid: gtid param pushed on stack so can pass &gtid to pkfn
1990 //   __tid: tid param pushed on stack so can pass &tid to pkfn
1992 // Temp registers:
1994 //  t0: used to calculate the dynamic stack size / used to hold pkfn address
1995 //  t1: used as temporary for stack placement calculation
1996 //  t2: used as temporary for stack arguments
1997 //  t3: used as temporary for number of remaining pkfn parms
1998 //  t4: used to traverse p_argv array
2000 // return: a0 (always 1/TRUE)
2003 // -- Begin __kmp_invoke_microtask
2004 // mark_begin;
2005         .text
2006         .globl  __kmp_invoke_microtask
2007         .p2align        2
2008         .type   __kmp_invoke_microtask,@function
2009 __kmp_invoke_microtask:
2010         .cfi_startproc
2012         // First, save ra and fp
2013         addi.d  $sp, $sp, -16
2014         st.d    $ra, $sp, 8
2015         st.d    $fp, $sp, 0
2016         addi.d  $fp, $sp, 16
2017         .cfi_def_cfa    22, 0
2018         .cfi_offset     1, -8
2019         .cfi_offset     22, -16
2021         // Compute the dynamic stack size:
2022         //
2023         // - We need 8 bytes for storing 'gtid' and 'tid', so we can pass them by
2024         //   reference
2025         // - We need 8 bytes for each argument that cannot be passed to the 'pkfn'
2026         //   function by register. Given that we have 8 of such registers (a[0-7])
2027         //   and two + 'argc' arguments (consider &gtid and &tid), we need to
2028         //   reserve max(0, argc - 6)*8 extra bytes
2029         //
2030         // The total number of bytes is then max(0, argc - 6)*8 + 8
2032         addi.d  $t0, $a3, -6
2033         slt  $t1, $t0, $zero
2034         masknez  $t0, $t0, $t1
2035         addi.d  $t0, $t0, 1
2036         slli.d  $t0, $t0, 3
2037         sub.d   $sp, $sp, $t0
2039         // Align the stack to 16 bytes
2040         bstrins.d $sp, $zero, 3, 0
2042         move    $t0, $a0
2043         move    $t3, $a3
2044         move    $t4, $a4
2046 #if OMPT_SUPPORT
2047         // Save frame pointer into exit_frame
2048         st.d    $fp, $a5, 0
2049 #endif
2051         // Prepare arguments for the pkfn function (first 8 using a0-a7 registers)
2053         st.w    $a1, $fp, -20
2054         st.w    $a2, $fp, -24
2056         addi.d  $a0, $fp, -20
2057         addi.d  $a1, $fp, -24
2059         beqz    $t3, .L_kmp_3
2060         ld.d    $a2, $t4, 0
2062         addi.d  $t3, $t3, -1
2063         beqz    $t3, .L_kmp_3
2064         ld.d    $a3, $t4, 8
2066         addi.d  $t3, $t3, -1
2067         beqz    $t3, .L_kmp_3
2068         ld.d    $a4, $t4, 16
2070         addi.d  $t3, $t3, -1
2071         beqz    $t3, .L_kmp_3
2072         ld.d    $a5, $t4, 24
2074         addi.d  $t3, $t3, -1
2075         beqz    $t3, .L_kmp_3
2076         ld.d    $a6, $t4, 32
2078         addi.d  $t3, $t3, -1
2079         beqz    $t3, .L_kmp_3
2080         ld.d    $a7, $t4, 40
2082         // Prepare any additional argument passed through the stack
2083         addi.d  $t4, $t4, 48
2084         move    $t1, $sp
2085         b .L_kmp_2
2086 .L_kmp_1:
2087         ld.d    $t2, $t4, 0
2088         st.d    $t2, $t1, 0
2089         addi.d  $t4, $t4, 8
2090         addi.d  $t1, $t1, 8
2091 .L_kmp_2:
2092         addi.d  $t3, $t3, -1
2093         bnez    $t3, .L_kmp_1
2095 .L_kmp_3:
2096         // Call pkfn function
2097         jirl    $ra, $t0, 0
2099         // Restore stack and return
2101         addi.d  $a0, $zero, 1
2103         addi.d  $sp, $fp, -16
2104         ld.d    $fp, $sp, 0
2105         ld.d    $ra, $sp, 8
2106         addi.d  $sp, $sp, 16
2107         jr $ra
2108 .Lfunc_end0:
2109         .size   __kmp_invoke_microtask, .Lfunc_end0-__kmp_invoke_microtask
2110         .cfi_endproc
2112 // -- End  __kmp_invoke_microtask
2114 #endif /* KMP_ARCH_LOONGARCH64 */
2116 #if KMP_ARCH_VE
2118 //------------------------------------------------------------------------
2120 // typedef void (*microtask_t)(int *gtid, int *tid, ...);
2122 // int __kmp_invoke_microtask(microtask_t pkfn, int gtid, int tid, int argc,
2123 //                            void *p_argv[]
2124 // #if OMPT_SUPPORT
2125 //                            ,
2126 //                            void **exit_frame_ptr
2127 // #endif
2128 //                            ) {
2129 // #if OMPT_SUPPORT
2130 //   *exit_frame_ptr = OMPT_GET_FRAME_ADDRESS(0);
2131 // #endif
2133 //   (*pkfn)(&gtid, &tid, argv[0], ...);
2135 //   return 1;
2136 // }
2138 // Parameters:
2139 //   s0: pkfn
2140 //   s1: gtid
2141 //   s2: tid
2142 //   s3: argc
2143 //   s4: p_argv
2144 //   s5: exit_frame_ptr
2146 // Locals:
2147 //   __gtid: gtid param pushed on stack so can pass &gtid to pkfn
2148 //   __tid: tid param pushed on stack so can pass &tid to pkfn
2150 // Temp. registers:
2152 //  s34: used to calculate the dynamic stack size
2153 //  s35: used as temporary for stack placement calculation
2154 //  s36: used as temporary for stack arguments
2155 //  s37: used as temporary for number of remaining pkfn parms
2156 //  s38: used to traverse p_argv array
2158 // return: s0 (always 1/TRUE)
2161 __gtid = -4
2162 __tid = -8
2164 // -- Begin __kmp_invoke_microtask
2165 // mark_begin;
2166         .text
2167         .globl  __kmp_invoke_microtask
2168         // A function requires 8 bytes align.
2169         .p2align        3
2170         .type   __kmp_invoke_microtask,@function
2171 __kmp_invoke_microtask:
2172         .cfi_startproc
2174         // First, save fp and lr.  VE stores them at caller stack frame.
2175         st      %fp, 0(, %sp)
2176         st      %lr, 8(, %sp)
2177         or      %fp, 0, %sp
2178         .cfi_def_cfa    %fp, 0
2179         .cfi_offset     %lr, 8
2180         .cfi_offset     %fp, 0
2182         // Compute the dynamic stack size:
2183         //
2184         // - We need 8 bytes for storing 'gtid' and 'tid', so we can pass them
2185         //   by reference
2186         // - We need 8 bytes for whole arguments.  We have two + 'argc'
2187         //   arguments (condider &gtid and &tid).  We need to reserve
2188         //   (argc + 2) * 8 bytes.
2189         // - We need 176 bytes for RSA and others
2190         //
2191         // The total number of bytes is then (argc + 2) * 8 + 8 + 176.
2192         //
2193         // |------------------------------|
2194         // | return address of callee     | 8(%fp)
2195         // |------------------------------|
2196         // | frame pointer of callee      | 0(%fp)
2197         // |------------------------------| <------------------ %fp
2198         // | __tid / __gtid               | -8(%fp) / -4(%fp)
2199         // |------------------------------|
2200         // | argc+2 for arguments         | 176(%sp)
2201         // |------------------------------|
2202         // | RSA                          |
2203         // |------------------------------|
2204         // | return address               |
2205         // |------------------------------|
2206         // | frame pointer                |
2207         // |------------------------------| <------------------ %sp
2209         adds.w.sx       %s34, 2, %s3
2210         sll     %s34, %s34, 3
2211         lea     %s34, 184(, %s34)
2212         subs.l  %sp, %sp, %s34
2214         // Align the stack to 16 bytes.
2215         and     %sp, -16, %sp
2217         // Save pkfn.
2218         or      %s12, 0, %s0
2220         // Call host to allocate stack if it is necessary.
2221         brge.l  %sp, %sl, .L_kmp_pass
2222         ld      %s61, 24(, %tp)
2223         lea     %s63, 0x13b
2224         shm.l   %s63, 0(%s61)
2225         shm.l   %sl, 8(%s61)
2226         shm.l   %sp, 16(%s61)
2227         monc
2229 .L_kmp_pass:
2230         lea     %s35, 176(, %sp)
2231         adds.w.sx       %s37, 0, %s3
2232         or      %s38, 0, %s4
2234 #if OMPT_SUPPORT
2235         // Save frame pointer into exit_frame.
2236         st      %fp, 0(%s5)
2237 #endif
2239         // Prepare arguments for the pkfn function (first 8 using s0-s7
2240         // registers, but need to store stack also because of varargs).
2242         stl     %s1, __gtid(%fp)
2243         stl     %s2, __tid(%fp)
2245         adds.l  %s0, __gtid, %fp
2246         st      %s0, 0(, %s35)
2247         adds.l  %s1, __tid, %fp
2248         st      %s1, 8(, %s35)
2250         breq.l  0, %s37, .L_kmp_call
2251         ld      %s2, 0(, %s38)
2252         st      %s2, 16(, %s35)
2254         breq.l  1, %s37, .L_kmp_call
2255         ld      %s3, 8(, %s38)
2256         st      %s3, 24(, %s35)
2258         breq.l  2, %s37, .L_kmp_call
2259         ld      %s4, 16(, %s38)
2260         st      %s4, 32(, %s35)
2262         breq.l  3, %s37, .L_kmp_call
2263         ld      %s5, 24(, %s38)
2264         st      %s5, 40(, %s35)
2266         breq.l  4, %s37, .L_kmp_call
2267         ld      %s6, 32(, %s38)
2268         st      %s6, 48(, %s35)
2270         breq.l  5, %s37, .L_kmp_call
2271         ld      %s7, 40(, %s38)
2272         st      %s7, 56(, %s35)
2274         breq.l  6, %s37, .L_kmp_call
2276         // Prepare any additional argument passed through the stack.
2277         adds.l  %s37, -6, %s37
2278         lea     %s38, 48(, %s38)
2279         lea     %s35, 64(, %s35)
2280 .L_kmp_loop:
2281         ld      %s36, 0(, %s38)
2282         st      %s36, 0(, %s35)
2283         adds.l  %s37, -1, %s37
2284         adds.l  %s38, 8, %s38
2285         adds.l  %s35, 8, %s35
2286         brne.l  0, %s37, .L_kmp_loop
2288 .L_kmp_call:
2289         // Call pkfn function.
2290         bsic    %lr, (, %s12)
2292         // Return value.
2293         lea     %s0, 1
2295         // Restore stack and return.
2296         or      %sp, 0, %fp
2297         ld      %lr, 8(, %sp)
2298         ld      %fp, 0(, %sp)
2299         b.l.t   (, %lr)
2300 .Lfunc_end0:
2301         .size   __kmp_invoke_microtask, .Lfunc_end0-__kmp_invoke_microtask
2302         .cfi_endproc
2304 // -- End  __kmp_invoke_microtask
2306 #endif /* KMP_ARCH_VE */
2308 #if KMP_ARCH_S390X
2310 //------------------------------------------------------------------------
2312 // typedef void (*microtask_t)(int *gtid, int *tid, ...);
2314 // int __kmp_invoke_microtask(microtask_t pkfn, int gtid, int tid, int argc,
2315 //                            void *p_argv[]
2316 // #if OMPT_SUPPORT
2317 //                            ,
2318 //                            void **exit_frame_ptr
2319 // #endif
2320 //                            ) {
2321 // #if OMPT_SUPPORT
2322 //   *exit_frame_ptr = OMPT_GET_FRAME_ADDRESS(0);
2323 // #endif
2325 //   (*pkfn)(&gtid, &tid, argv[0], ...);
2327 //   return 1;
2328 // }
2330 // Parameters:
2331 //   r2: pkfn
2332 //   r3: gtid
2333 //   r4: tid
2334 //   r5: argc
2335 //   r6: p_argv
2336 //   SP+160: exit_frame_ptr
2338 // Locals:
2339 //   __gtid: gtid param pushed on stack so can pass &gtid to pkfn
2340 //   __tid: tid param pushed on stack so can pass &tid to pkfn
2342 // Temp. registers:
2344 //  r0: used to fetch argv slots
2345 //  r7: used as temporary for number of remaining pkfn parms
2346 //  r8: argv
2347 //  r9: pkfn
2348 //  r10: stack size
2349 //  r11: previous fp
2350 //  r12: stack parameter area
2351 //  r13: argv slot
2353 // return: r2 (always 1/TRUE)
2356 // -- Begin __kmp_invoke_microtask
2357 // mark_begin;
2358         .text
2359         .globl  __kmp_invoke_microtask
2360         .p2align        1
2361         .type   __kmp_invoke_microtask,@function
2362 __kmp_invoke_microtask:
2363         .cfi_startproc
2365         stmg    %r6,%r14,48(%r15)
2366         .cfi_offset %r6, -112
2367         .cfi_offset %r7, -104
2368         .cfi_offset %r8, -96
2369         .cfi_offset %r9, -88
2370         .cfi_offset %r10, -80
2371         .cfi_offset %r11, -72
2372         .cfi_offset %r12, -64
2373         .cfi_offset %r13, -56
2374         .cfi_offset %r14, -48
2375         .cfi_offset %r15, -40
2376         lgr     %r11,%r15
2377         .cfi_def_cfa %r11, 160
2379         // Compute the dynamic stack size:
2380         //
2381         // - We need 8 bytes for storing 'gtid' and 'tid', so we can pass them by
2382         //   reference
2383         // - We need 8 bytes for each argument that cannot be passed to the 'pkfn'
2384         //   function by register. Given that we have 5 of such registers (r[2-6])
2385         //   and two + 'argc' arguments (consider &gtid and &tid), we need to
2386         //   reserve max(0, argc - 3)*8 extra bytes
2387         //
2388         // The total number of bytes is then max(0, argc - 3)*8 + 8
2390         lgr     %r10,%r5
2391         aghi    %r10,-2
2392         jnm     0f
2393         lghi    %r10,0
2395         sllg    %r10,%r10,3
2396         lgr     %r12,%r10
2397         aghi    %r10,176
2398         sgr     %r15,%r10
2399         agr     %r12,%r15
2400         stg     %r11,0(%r15)
2402         lgr     %r9,%r2                 // pkfn
2404 #if OMPT_SUPPORT
2405         // Save frame pointer into exit_frame
2406         lg      %r8,160(%r11)
2407         stg     %r11,0(%r8)
2408 #endif
2410         // Prepare arguments for the pkfn function (first 5 using r2-r6 registers)
2412         stg     %r3,160(%r12)
2413         la      %r2,164(%r12)           // gid
2414         stg     %r4,168(%r12)           
2415         la      %r3,172(%r12)           // tid
2416         lgr     %r8,%r6                 // argv
2418         // If argc > 0
2419         ltgr    %r7,%r5
2420         jz      1f
2422         lg      %r4,0(%r8)              // argv[0]
2423         aghi    %r7,-1
2424         jz      1f
2426         // If argc > 1
2427         lg      %r5,8(%r8)              // argv[1]
2428         aghi    %r7,-1
2429         jz      1f
2431         // If argc > 2
2432         lg      %r6,16(%r8)             // argv[2]
2433         aghi    %r7,-1
2434         jz      1f
2436         lghi    %r13,0                  // Index [n]
2438         lg      %r0,24(%r13,%r8)        // argv[2+n]
2439         stg     %r0,160(%r13,%r15)      // parm[2+n]
2440         aghi    %r13,8                  // Next
2441         aghi    %r7,-1
2442         jnz     2b
2445         basr    %r14,%r9                // Call pkfn
2447         // Restore stack and return
2449         lgr     %r15,%r11
2450         lmg     %r6,%r14,48(%r15)
2451         lghi    %r2,1
2452         br      %r14
2453 .Lfunc_end0:
2454         .size   __kmp_invoke_microtask, .Lfunc_end0-__kmp_invoke_microtask
2455         .cfi_endproc
2457 // -- End  __kmp_invoke_microtask
2459 #endif /* KMP_ARCH_S390X */
2461 #if KMP_ARCH_ARM || KMP_ARCH_MIPS || KMP_ARCH_AARCH64_32
2462 #ifndef KMP_PREFIX_UNDERSCORE
2463 # define KMP_PREFIX_UNDERSCORE(x) x
2464 #endif
2465     .data
2466     COMMON .gomp_critical_user_, 32, 3
2467     .data
2468     .align 4
2469     .global KMP_PREFIX_UNDERSCORE(__kmp_unnamed_critical_addr)
2470 KMP_PREFIX_UNDERSCORE(__kmp_unnamed_critical_addr):
2471     .4byte .gomp_critical_user_
2472 #ifdef __ELF__
2473     .size KMP_PREFIX_UNDERSCORE(__kmp_unnamed_critical_addr),4
2474 #endif
2475 #endif /* KMP_ARCH_ARM || KMP_ARCH_MIPS || KMP_ARCH_AARCH64_32 */
2477 #if KMP_ARCH_PPC64 || KMP_ARCH_AARCH64 || KMP_ARCH_MIPS64 ||                   \
2478     KMP_ARCH_RISCV64 || KMP_ARCH_LOONGARCH64 || KMP_ARCH_VE ||                 \
2479     KMP_ARCH_S390X
2480 #ifndef KMP_PREFIX_UNDERSCORE
2481 # define KMP_PREFIX_UNDERSCORE(x) x
2482 #endif
2483     .data
2484     COMMON .gomp_critical_user_, 32, 3
2485     .data
2486     .align 8
2487     .global KMP_PREFIX_UNDERSCORE(__kmp_unnamed_critical_addr)
2488 KMP_PREFIX_UNDERSCORE(__kmp_unnamed_critical_addr):
2489     .8byte .gomp_critical_user_
2490 #ifdef __ELF__
2491     .size KMP_PREFIX_UNDERSCORE(__kmp_unnamed_critical_addr),8
2492 #endif
2493 #endif /* KMP_ARCH_PPC64 || KMP_ARCH_AARCH64 || KMP_ARCH_MIPS64 ||
2494           KMP_ARCH_RISCV64 || KMP_ARCH_LOONGARCH64 || KMP_ARCH_VE || 
2495           KMP_ARCH_S390X */
2497 #if KMP_OS_LINUX
2498 # if KMP_ARCH_ARM || KMP_ARCH_AARCH64
2499 .section .note.GNU-stack,"",%progbits
2500 # elif !KMP_ARCH_WASM
2501 .section .note.GNU-stack,"",@progbits
2502 # endif
2503 #endif
2505 #if KMP_OS_LINUX && (KMP_ARCH_AARCH64 || KMP_ARCH_AARCH64_32)
2506 GNU_PROPERTY_BTI_PAC
2507 #endif