190075Sobrien@ libgcc routines for ARM cpu. 290075Sobrien@ Division routines, written by Richard Earnshaw, (rearnsha@armltd.co.uk) 390075Sobrien 4169689Skan/* Copyright 1995, 1996, 1998, 1999, 2000, 2003, 2004, 2005 5132718Skan Free Software Foundation, Inc. 690075Sobrien 790075SobrienThis file is free software; you can redistribute it and/or modify it 890075Sobrienunder the terms of the GNU General Public License as published by the 990075SobrienFree Software Foundation; either version 2, or (at your option) any 1090075Sobrienlater version. 1190075Sobrien 1290075SobrienIn addition to the permissions in the GNU General Public License, the 1390075SobrienFree Software Foundation gives you unlimited permission to link the 1490075Sobriencompiled version of this file into combinations with other programs, 1590075Sobrienand to distribute those combinations without any restriction coming 1690075Sobrienfrom the use of this file. (The General Public License restrictions 1790075Sobriendo apply in other respects; for example, they cover modification of 1890075Sobrienthe file, and distribution when not linked into a combine 1990075Sobrienexecutable.) 2090075Sobrien 2190075SobrienThis file is distributed in the hope that it will be useful, but 2290075SobrienWITHOUT ANY WARRANTY; without even the implied warranty of 2390075SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 2490075SobrienGeneral Public License for more details. 2590075Sobrien 2690075SobrienYou should have received a copy of the GNU General Public License 2790075Sobrienalong with this program; see the file COPYING. If not, write to 28169689Skanthe Free Software Foundation, 51 Franklin Street, Fifth Floor, 29169689SkanBoston, MA 02110-1301, USA. */ 3090075Sobrien/* ------------------------------------------------------------------------ */ 3190075Sobrien 3290075Sobrien/* We need to know what prefix to add to function names. */ 3390075Sobrien 3490075Sobrien#ifndef __USER_LABEL_PREFIX__ 3590075Sobrien#error __USER_LABEL_PREFIX__ not defined 3690075Sobrien#endif 3790075Sobrien 3890075Sobrien/* ANSI concatenation macros. */ 3990075Sobrien 4090075Sobrien#define CONCAT1(a, b) CONCAT2(a, b) 4190075Sobrien#define CONCAT2(a, b) a ## b 4290075Sobrien 4390075Sobrien/* Use the right prefix for global labels. */ 4490075Sobrien 4590075Sobrien#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x) 4690075Sobrien 4790075Sobrien#ifdef __ELF__ 4890075Sobrien#ifdef __thumb__ 4990075Sobrien#define __PLT__ /* Not supported in Thumb assembler (for now). */ 5090075Sobrien#else 5190075Sobrien#define __PLT__ (PLT) 5290075Sobrien#endif 5390075Sobrien#define TYPE(x) .type SYM(x),function 5490075Sobrien#define SIZE(x) .size SYM(x), . - SYM(x) 55132718Skan#define LSYM(x) .x 5690075Sobrien#else 5790075Sobrien#define __PLT__ 5890075Sobrien#define TYPE(x) 5990075Sobrien#define SIZE(x) 60132718Skan#define LSYM(x) x 6190075Sobrien#endif 6290075Sobrien 63169689Skan/* Function end macros. Variants for interworking. */ 6490075Sobrien 65132718Skan@ This selects the minimum architecture level required. 66132718Skan#define __ARM_ARCH__ 3 67132718Skan 68132718Skan#if defined(__ARM_ARCH_3M__) || defined(__ARM_ARCH_4__) \ 69132718Skan || defined(__ARM_ARCH_4T__) 70132718Skan/* We use __ARM_ARCH__ set to 4 here, but in reality it's any processor with 71132718Skan long multiply instructions. That includes v3M. */ 72132718Skan# undef __ARM_ARCH__ 73132718Skan# define __ARM_ARCH__ 4 74132718Skan#endif 75132718Skan 76132718Skan#if defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \ 77169689Skan || defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \ 78169689Skan || defined(__ARM_ARCH_5TEJ__) 79132718Skan# undef __ARM_ARCH__ 80132718Skan# define __ARM_ARCH__ 5 81132718Skan#endif 82132718Skan 83169689Skan#if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \ 84169689Skan || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \ 85169689Skan || defined(__ARM_ARCH_6ZK__) 86169689Skan# undef __ARM_ARCH__ 87169689Skan# define __ARM_ARCH__ 6 88169689Skan#endif 89132718Skan 90169689Skan#ifndef __ARM_ARCH__ 91169689Skan#error Unable to determine architecture. 92169689Skan#endif 93132718Skan 94169689Skan/* How to return from a function call depends on the architecture variant. */ 95132718Skan 96169689Skan#if (__ARM_ARCH__ > 4) || defined(__ARM_ARCH_4T__) 97132718Skan 98132718Skan# define RET bx lr 99132718Skan# define RETc(x) bx##x lr 100132718Skan 101169689Skan/* Special precautions for interworking on armv4t. */ 102169689Skan# if (__ARM_ARCH__ == 4) 103132718Skan 104169689Skan/* Always use bx, not ldr pc. */ 105169689Skan# if (defined(__thumb__) || defined(__THUMB_INTERWORK__)) 106169689Skan# define __INTERWORKING__ 107169689Skan# endif /* __THUMB__ || __THUMB_INTERWORK__ */ 108169689Skan 109169689Skan/* Include thumb stub before arm mode code. */ 110169689Skan# if defined(__thumb__) && !defined(__THUMB_INTERWORK__) 111169689Skan# define __INTERWORKING_STUBS__ 112169689Skan# endif /* __thumb__ && !__THUMB_INTERWORK__ */ 113169689Skan 114169689Skan#endif /* __ARM_ARCH == 4 */ 115169689Skan 116132718Skan#else 117132718Skan 118132718Skan# define RET mov pc, lr 119132718Skan# define RETc(x) mov##x pc, lr 120132718Skan 121132718Skan#endif 122132718Skan 123169689Skan.macro cfi_pop advance, reg, cfa_offset 124169689Skan#ifdef __ELF__ 125169689Skan .pushsection .debug_frame 126169689Skan .byte 0x4 /* DW_CFA_advance_loc4 */ 127169689Skan .4byte \advance 128169689Skan .byte (0xc0 | \reg) /* DW_CFA_restore */ 129169689Skan .byte 0xe /* DW_CFA_def_cfa_offset */ 130169689Skan .uleb128 \cfa_offset 131169689Skan .popsection 132169689Skan#endif 133169689Skan.endm 134169689Skan.macro cfi_push advance, reg, offset, cfa_offset 135169689Skan#ifdef __ELF__ 136169689Skan .pushsection .debug_frame 137169689Skan .byte 0x4 /* DW_CFA_advance_loc4 */ 138169689Skan .4byte \advance 139169689Skan .byte (0x80 | \reg) /* DW_CFA_offset */ 140169689Skan .uleb128 (\offset / -4) 141169689Skan .byte 0xe /* DW_CFA_def_cfa_offset */ 142169689Skan .uleb128 \cfa_offset 143169689Skan .popsection 144169689Skan#endif 145169689Skan.endm 146169689Skan.macro cfi_start start_label, end_label 147169689Skan#ifdef __ELF__ 148169689Skan .pushsection .debug_frame 149169689SkanLSYM(Lstart_frame): 150169689Skan .4byte LSYM(Lend_cie) - LSYM(Lstart_cie) @ Length of CIE 151169689SkanLSYM(Lstart_cie): 152169689Skan .4byte 0xffffffff @ CIE Identifier Tag 153169689Skan .byte 0x1 @ CIE Version 154169689Skan .ascii "\0" @ CIE Augmentation 155169689Skan .uleb128 0x1 @ CIE Code Alignment Factor 156169689Skan .sleb128 -4 @ CIE Data Alignment Factor 157169689Skan .byte 0xe @ CIE RA Column 158169689Skan .byte 0xc @ DW_CFA_def_cfa 159169689Skan .uleb128 0xd 160169689Skan .uleb128 0x0 161169689Skan 162169689Skan .align 2 163169689SkanLSYM(Lend_cie): 164169689Skan .4byte LSYM(Lend_fde)-LSYM(Lstart_fde) @ FDE Length 165169689SkanLSYM(Lstart_fde): 166169689Skan .4byte LSYM(Lstart_frame) @ FDE CIE offset 167169689Skan .4byte \start_label @ FDE initial location 168169689Skan .4byte \end_label-\start_label @ FDE address range 169169689Skan .popsection 170169689Skan#endif 171169689Skan.endm 172169689Skan.macro cfi_end end_label 173169689Skan#ifdef __ELF__ 174169689Skan .pushsection .debug_frame 175169689Skan .align 2 176169689SkanLSYM(Lend_fde): 177169689Skan .popsection 178169689Skan\end_label: 179169689Skan#endif 180169689Skan.endm 181169689Skan 182132718Skan/* Don't pass dirn, it's there just to get token pasting right. */ 183132718Skan 184169689Skan.macro RETLDM regs=, cond=, unwind=, dirn=ia 185169689Skan#if defined (__INTERWORKING__) 186132718Skan .ifc "\regs","" 187169689Skan ldr\cond lr, [sp], #8 188132718Skan .else 189132718Skan ldm\cond\dirn sp!, {\regs, lr} 190132718Skan .endif 191169689Skan .ifnc "\unwind", "" 192169689Skan /* Mark LR as restored. */ 193169689Skan97: cfi_pop 97b - \unwind, 0xe, 0x0 194169689Skan .endif 195132718Skan bx\cond lr 196132718Skan#else 197132718Skan .ifc "\regs","" 198169689Skan ldr\cond pc, [sp], #8 199132718Skan .else 200132718Skan ldm\cond\dirn sp!, {\regs, pc} 201132718Skan .endif 202132718Skan#endif 203132718Skan.endm 204132718Skan 205132718Skan 206169689Skan.macro ARM_LDIV0 name 207169689Skan str lr, [sp, #-8]! 208169689Skan98: cfi_push 98b - __\name, 0xe, -0x8, 0x8 20990075Sobrien bl SYM (__div0) __PLT__ 21090075Sobrien mov r0, #0 @ About as wrong as it could be. 211169689Skan RETLDM unwind=98b 21290075Sobrien.endm 213132718Skan 214132718Skan 215169689Skan.macro THUMB_LDIV0 name 216169689Skan push { r1, lr } 217169689Skan98: cfi_push 98b - __\name, 0xe, -0x4, 0x8 21890075Sobrien bl SYM (__div0) 21990075Sobrien mov r0, #0 @ About as wrong as it could be. 220132718Skan#if defined (__INTERWORKING__) 221169689Skan pop { r1, r2 } 222169689Skan bx r2 223132718Skan#else 224169689Skan pop { r1, pc } 225132718Skan#endif 22690075Sobrien.endm 22790075Sobrien 22890075Sobrien.macro FUNC_END name 229132718Skan SIZE (__\name) 230132718Skan.endm 231132718Skan 232132718Skan.macro DIV_FUNC_END name 233169689Skan cfi_start __\name, LSYM(Lend_div0) 234132718SkanLSYM(Ldiv0): 23590075Sobrien#ifdef __thumb__ 236169689Skan THUMB_LDIV0 \name 23790075Sobrien#else 238169689Skan ARM_LDIV0 \name 23990075Sobrien#endif 240169689Skan cfi_end LSYM(Lend_div0) 241132718Skan FUNC_END \name 24290075Sobrien.endm 24390075Sobrien 24490075Sobrien.macro THUMB_FUNC_START name 24590075Sobrien .globl SYM (\name) 24690075Sobrien TYPE (\name) 24790075Sobrien .thumb_func 24890075SobrienSYM (\name): 24990075Sobrien.endm 25090075Sobrien 25190075Sobrien/* Function start macros. Variants for ARM and Thumb. */ 25290075Sobrien 25390075Sobrien#ifdef __thumb__ 25490075Sobrien#define THUMB_FUNC .thumb_func 25590075Sobrien#define THUMB_CODE .force_thumb 25690075Sobrien#else 25790075Sobrien#define THUMB_FUNC 25890075Sobrien#define THUMB_CODE 25990075Sobrien#endif 26090075Sobrien 26190075Sobrien.macro FUNC_START name 26290075Sobrien .text 26390075Sobrien .globl SYM (__\name) 26490075Sobrien TYPE (__\name) 26590075Sobrien .align 0 26690075Sobrien THUMB_CODE 26790075Sobrien THUMB_FUNC 26890075SobrienSYM (__\name): 26990075Sobrien.endm 270132718Skan 271132718Skan/* Special function that will always be coded in ARM assembly, even if 272132718Skan in Thumb-only compilation. */ 273132718Skan 274169689Skan#if defined(__INTERWORKING_STUBS__) 275132718Skan.macro ARM_FUNC_START name 276132718Skan FUNC_START \name 277132718Skan bx pc 278132718Skan nop 279132718Skan .arm 280169689Skan/* A hook to tell gdb that we've switched to ARM mode. Also used to call 281169689Skan directly from other local arm routines. */ 282169689Skan_L__\name: 283132718Skan.endm 284132718Skan#define EQUIV .thumb_set 285169689Skan/* Branch directly to a function declared with ARM_FUNC_START. 286169689Skan Must be called in arm mode. */ 287169689Skan.macro ARM_CALL name 288169689Skan bl _L__\name 289169689Skan.endm 290132718Skan#else 291132718Skan.macro ARM_FUNC_START name 292132718Skan .text 293132718Skan .globl SYM (__\name) 294132718Skan TYPE (__\name) 295132718Skan .align 0 296132718Skan .arm 297132718SkanSYM (__\name): 298132718Skan.endm 299132718Skan#define EQUIV .set 300169689Skan.macro ARM_CALL name 301169689Skan bl __\name 302169689Skan.endm 303132718Skan#endif 304132718Skan 305169689Skan.macro FUNC_ALIAS new old 306169689Skan .globl SYM (__\new) 307169689Skan#if defined (__thumb__) 308169689Skan .thumb_set SYM (__\new), SYM (__\old) 309169689Skan#else 310169689Skan .set SYM (__\new), SYM (__\old) 311169689Skan#endif 312169689Skan.endm 313169689Skan 314132718Skan.macro ARM_FUNC_ALIAS new old 315132718Skan .globl SYM (__\new) 316132718Skan EQUIV SYM (__\new), SYM (__\old) 317169689Skan#if defined(__INTERWORKING_STUBS__) 318169689Skan .set SYM (_L__\new), SYM (_L__\old) 319169689Skan#endif 320132718Skan.endm 321132718Skan 322132718Skan#ifdef __thumb__ 32390075Sobrien/* Register aliases. */ 32490075Sobrien 32590075Sobrienwork .req r4 @ XXXX is this safe ? 32690075Sobriendividend .req r0 32790075Sobriendivisor .req r1 32890075Sobrienoverdone .req r2 32990075Sobrienresult .req r2 33090075Sobriencurbit .req r3 331132718Skan#endif 332132718Skan#if 0 33390075Sobrienip .req r12 33490075Sobriensp .req r13 33590075Sobrienlr .req r14 33690075Sobrienpc .req r15 337132718Skan#endif 33890075Sobrien 33990075Sobrien/* ------------------------------------------------------------------------ */ 340132718Skan/* Bodies of the division and modulo routines. */ 34190075Sobrien/* ------------------------------------------------------------------------ */ 342132718Skan.macro ARM_DIV_BODY dividend, divisor, result, curbit 343132718Skan 344169689Skan#if __ARM_ARCH__ >= 5 && ! defined (__OPTIMIZE_SIZE__) 345169689Skan 346169689Skan clz \curbit, \dividend 347169689Skan clz \result, \divisor 348169689Skan sub \curbit, \result, \curbit 349169689Skan rsbs \curbit, \curbit, #31 350169689Skan addne \curbit, \curbit, \curbit, lsl #1 351169689Skan mov \result, #0 352169689Skan addne pc, pc, \curbit, lsl #2 353169689Skan nop 354169689Skan .set shift, 32 355169689Skan .rept 32 356169689Skan .set shift, shift - 1 357169689Skan cmp \dividend, \divisor, lsl #shift 358169689Skan adc \result, \result, \result 359169689Skan subcs \dividend, \dividend, \divisor, lsl #shift 360169689Skan .endr 361169689Skan 362169689Skan#else /* __ARM_ARCH__ < 5 || defined (__OPTIMIZE_SIZE__) */ 363132718Skan#if __ARM_ARCH__ >= 5 364132718Skan 365132718Skan clz \curbit, \divisor 366132718Skan clz \result, \dividend 367132718Skan sub \result, \curbit, \result 368132718Skan mov \curbit, #1 369132718Skan mov \divisor, \divisor, lsl \result 370132718Skan mov \curbit, \curbit, lsl \result 371132718Skan mov \result, #0 372132718Skan 373169689Skan#else /* __ARM_ARCH__ < 5 */ 374132718Skan 375132718Skan @ Initially shift the divisor left 3 bits if possible, 376132718Skan @ set curbit accordingly. This allows for curbit to be located 377132718Skan @ at the left end of each 4 bit nibbles in the division loop 378132718Skan @ to save one loop in most cases. 379132718Skan tst \divisor, #0xe0000000 380132718Skan moveq \divisor, \divisor, lsl #3 381132718Skan moveq \curbit, #8 382132718Skan movne \curbit, #1 383132718Skan 38490075Sobrien @ Unless the divisor is very big, shift it up in multiples of 38590075Sobrien @ four bits, since this is the amount of unwinding in the main 38690075Sobrien @ division loop. Continue shifting until the divisor is 38790075Sobrien @ larger than the dividend. 388132718Skan1: cmp \divisor, #0x10000000 389132718Skan cmplo \divisor, \dividend 390132718Skan movlo \divisor, \divisor, lsl #4 391132718Skan movlo \curbit, \curbit, lsl #4 392132718Skan blo 1b 39390075Sobrien 39490075Sobrien @ For very big divisors, we must shift it a bit at a time, or 39590075Sobrien @ we will be in danger of overflowing. 396132718Skan1: cmp \divisor, #0x80000000 397132718Skan cmplo \divisor, \dividend 398132718Skan movlo \divisor, \divisor, lsl #1 399132718Skan movlo \curbit, \curbit, lsl #1 400132718Skan blo 1b 40190075Sobrien 402132718Skan mov \result, #0 403132718Skan 404169689Skan#endif /* __ARM_ARCH__ < 5 */ 405132718Skan 406132718Skan @ Division loop 407132718Skan1: cmp \dividend, \divisor 408132718Skan subhs \dividend, \dividend, \divisor 409132718Skan orrhs \result, \result, \curbit 410132718Skan cmp \dividend, \divisor, lsr #1 411132718Skan subhs \dividend, \dividend, \divisor, lsr #1 412132718Skan orrhs \result, \result, \curbit, lsr #1 413132718Skan cmp \dividend, \divisor, lsr #2 414132718Skan subhs \dividend, \dividend, \divisor, lsr #2 415132718Skan orrhs \result, \result, \curbit, lsr #2 416132718Skan cmp \dividend, \divisor, lsr #3 417132718Skan subhs \dividend, \dividend, \divisor, lsr #3 418132718Skan orrhs \result, \result, \curbit, lsr #3 419132718Skan cmp \dividend, #0 @ Early termination? 420132718Skan movnes \curbit, \curbit, lsr #4 @ No, any more bits to do? 421132718Skan movne \divisor, \divisor, lsr #4 422132718Skan bne 1b 423132718Skan 424169689Skan#endif /* __ARM_ARCH__ < 5 || defined (__OPTIMIZE_SIZE__) */ 425169689Skan 426132718Skan.endm 427132718Skan/* ------------------------------------------------------------------------ */ 428132718Skan.macro ARM_DIV2_ORDER divisor, order 429132718Skan 430132718Skan#if __ARM_ARCH__ >= 5 431132718Skan 432132718Skan clz \order, \divisor 433132718Skan rsb \order, \order, #31 434132718Skan 435132718Skan#else 436132718Skan 437132718Skan cmp \divisor, #(1 << 16) 438132718Skan movhs \divisor, \divisor, lsr #16 439132718Skan movhs \order, #16 440132718Skan movlo \order, #0 441132718Skan 442132718Skan cmp \divisor, #(1 << 8) 443132718Skan movhs \divisor, \divisor, lsr #8 444132718Skan addhs \order, \order, #8 445132718Skan 446132718Skan cmp \divisor, #(1 << 4) 447132718Skan movhs \divisor, \divisor, lsr #4 448132718Skan addhs \order, \order, #4 449132718Skan 450132718Skan cmp \divisor, #(1 << 2) 451132718Skan addhi \order, \order, #3 452132718Skan addls \order, \order, \divisor, lsr #1 453132718Skan 454132718Skan#endif 455132718Skan 456132718Skan.endm 457132718Skan/* ------------------------------------------------------------------------ */ 458132718Skan.macro ARM_MOD_BODY dividend, divisor, order, spare 459132718Skan 460169689Skan#if __ARM_ARCH__ >= 5 && ! defined (__OPTIMIZE_SIZE__) 461169689Skan 462169689Skan clz \order, \divisor 463169689Skan clz \spare, \dividend 464169689Skan sub \order, \order, \spare 465169689Skan rsbs \order, \order, #31 466169689Skan addne pc, pc, \order, lsl #3 467169689Skan nop 468169689Skan .set shift, 32 469169689Skan .rept 32 470169689Skan .set shift, shift - 1 471169689Skan cmp \dividend, \divisor, lsl #shift 472169689Skan subcs \dividend, \dividend, \divisor, lsl #shift 473169689Skan .endr 474169689Skan 475169689Skan#else /* __ARM_ARCH__ < 5 || defined (__OPTIMIZE_SIZE__) */ 476132718Skan#if __ARM_ARCH__ >= 5 477132718Skan 478132718Skan clz \order, \divisor 479132718Skan clz \spare, \dividend 480132718Skan sub \order, \order, \spare 481132718Skan mov \divisor, \divisor, lsl \order 48290075Sobrien 483169689Skan#else /* __ARM_ARCH__ < 5 */ 48490075Sobrien 485132718Skan mov \order, #0 48690075Sobrien 487132718Skan @ Unless the divisor is very big, shift it up in multiples of 488132718Skan @ four bits, since this is the amount of unwinding in the main 489132718Skan @ division loop. Continue shifting until the divisor is 490132718Skan @ larger than the dividend. 491132718Skan1: cmp \divisor, #0x10000000 492132718Skan cmplo \divisor, \dividend 493132718Skan movlo \divisor, \divisor, lsl #4 494132718Skan addlo \order, \order, #4 495132718Skan blo 1b 49690075Sobrien 497132718Skan @ For very big divisors, we must shift it a bit at a time, or 498132718Skan @ we will be in danger of overflowing. 499132718Skan1: cmp \divisor, #0x80000000 500132718Skan cmplo \divisor, \dividend 501132718Skan movlo \divisor, \divisor, lsl #1 502132718Skan addlo \order, \order, #1 503132718Skan blo 1b 504132718Skan 505169689Skan#endif /* __ARM_ARCH__ < 5 */ 506132718Skan 507132718Skan @ Perform all needed substractions to keep only the reminder. 508132718Skan @ Do comparisons in batch of 4 first. 509132718Skan subs \order, \order, #3 @ yes, 3 is intended here 510132718Skan blt 2f 511132718Skan 512132718Skan1: cmp \dividend, \divisor 513132718Skan subhs \dividend, \dividend, \divisor 514132718Skan cmp \dividend, \divisor, lsr #1 515132718Skan subhs \dividend, \dividend, \divisor, lsr #1 516132718Skan cmp \dividend, \divisor, lsr #2 517132718Skan subhs \dividend, \dividend, \divisor, lsr #2 518132718Skan cmp \dividend, \divisor, lsr #3 519132718Skan subhs \dividend, \dividend, \divisor, lsr #3 520132718Skan cmp \dividend, #1 521132718Skan mov \divisor, \divisor, lsr #4 522132718Skan subges \order, \order, #4 523132718Skan bge 1b 524132718Skan 525132718Skan tst \order, #3 526132718Skan teqne \dividend, #0 527132718Skan beq 5f 528132718Skan 529132718Skan @ Either 1, 2 or 3 comparison/substractions are left. 530132718Skan2: cmn \order, #2 531132718Skan blt 4f 532132718Skan beq 3f 533132718Skan cmp \dividend, \divisor 534132718Skan subhs \dividend, \dividend, \divisor 535132718Skan mov \divisor, \divisor, lsr #1 536132718Skan3: cmp \dividend, \divisor 537132718Skan subhs \dividend, \dividend, \divisor 538132718Skan mov \divisor, \divisor, lsr #1 539132718Skan4: cmp \dividend, \divisor 540132718Skan subhs \dividend, \dividend, \divisor 541132718Skan5: 542169689Skan 543169689Skan#endif /* __ARM_ARCH__ < 5 || defined (__OPTIMIZE_SIZE__) */ 544169689Skan 54590075Sobrien.endm 54690075Sobrien/* ------------------------------------------------------------------------ */ 54790075Sobrien.macro THUMB_DIV_MOD_BODY modulo 54890075Sobrien @ Load the constant 0x10000000 into our work register. 54990075Sobrien mov work, #1 55090075Sobrien lsl work, #28 551132718SkanLSYM(Loop1): 55290075Sobrien @ Unless the divisor is very big, shift it up in multiples of 55390075Sobrien @ four bits, since this is the amount of unwinding in the main 55490075Sobrien @ division loop. Continue shifting until the divisor is 55590075Sobrien @ larger than the dividend. 55690075Sobrien cmp divisor, work 557132718Skan bhs LSYM(Lbignum) 55890075Sobrien cmp divisor, dividend 559132718Skan bhs LSYM(Lbignum) 56090075Sobrien lsl divisor, #4 56190075Sobrien lsl curbit, #4 562132718Skan b LSYM(Loop1) 563132718SkanLSYM(Lbignum): 56490075Sobrien @ Set work to 0x80000000 56590075Sobrien lsl work, #3 566132718SkanLSYM(Loop2): 56790075Sobrien @ For very big divisors, we must shift it a bit at a time, or 56890075Sobrien @ we will be in danger of overflowing. 56990075Sobrien cmp divisor, work 570132718Skan bhs LSYM(Loop3) 57190075Sobrien cmp divisor, dividend 572132718Skan bhs LSYM(Loop3) 57390075Sobrien lsl divisor, #1 57490075Sobrien lsl curbit, #1 575132718Skan b LSYM(Loop2) 576132718SkanLSYM(Loop3): 57790075Sobrien @ Test for possible subtractions ... 57890075Sobrien .if \modulo 57990075Sobrien @ ... On the final pass, this may subtract too much from the dividend, 58090075Sobrien @ so keep track of which subtractions are done, we can fix them up 58190075Sobrien @ afterwards. 58290075Sobrien mov overdone, #0 58390075Sobrien cmp dividend, divisor 584132718Skan blo LSYM(Lover1) 58590075Sobrien sub dividend, dividend, divisor 586132718SkanLSYM(Lover1): 58790075Sobrien lsr work, divisor, #1 58890075Sobrien cmp dividend, work 589132718Skan blo LSYM(Lover2) 59090075Sobrien sub dividend, dividend, work 59190075Sobrien mov ip, curbit 59290075Sobrien mov work, #1 59390075Sobrien ror curbit, work 59490075Sobrien orr overdone, curbit 59590075Sobrien mov curbit, ip 596132718SkanLSYM(Lover2): 59790075Sobrien lsr work, divisor, #2 59890075Sobrien cmp dividend, work 599132718Skan blo LSYM(Lover3) 60090075Sobrien sub dividend, dividend, work 60190075Sobrien mov ip, curbit 60290075Sobrien mov work, #2 60390075Sobrien ror curbit, work 60490075Sobrien orr overdone, curbit 60590075Sobrien mov curbit, ip 606132718SkanLSYM(Lover3): 60790075Sobrien lsr work, divisor, #3 60890075Sobrien cmp dividend, work 609132718Skan blo LSYM(Lover4) 61090075Sobrien sub dividend, dividend, work 61190075Sobrien mov ip, curbit 61290075Sobrien mov work, #3 61390075Sobrien ror curbit, work 61490075Sobrien orr overdone, curbit 61590075Sobrien mov curbit, ip 616132718SkanLSYM(Lover4): 61790075Sobrien mov ip, curbit 61890075Sobrien .else 61990075Sobrien @ ... and note which bits are done in the result. On the final pass, 62090075Sobrien @ this may subtract too much from the dividend, but the result will be ok, 62190075Sobrien @ since the "bit" will have been shifted out at the bottom. 62290075Sobrien cmp dividend, divisor 623132718Skan blo LSYM(Lover1) 62490075Sobrien sub dividend, dividend, divisor 62590075Sobrien orr result, result, curbit 626132718SkanLSYM(Lover1): 62790075Sobrien lsr work, divisor, #1 62890075Sobrien cmp dividend, work 629132718Skan blo LSYM(Lover2) 63090075Sobrien sub dividend, dividend, work 63190075Sobrien lsr work, curbit, #1 63290075Sobrien orr result, work 633132718SkanLSYM(Lover2): 63490075Sobrien lsr work, divisor, #2 63590075Sobrien cmp dividend, work 636132718Skan blo LSYM(Lover3) 63790075Sobrien sub dividend, dividend, work 63890075Sobrien lsr work, curbit, #2 63990075Sobrien orr result, work 640132718SkanLSYM(Lover3): 64190075Sobrien lsr work, divisor, #3 64290075Sobrien cmp dividend, work 643132718Skan blo LSYM(Lover4) 64490075Sobrien sub dividend, dividend, work 64590075Sobrien lsr work, curbit, #3 64690075Sobrien orr result, work 647132718SkanLSYM(Lover4): 64890075Sobrien .endif 64990075Sobrien 65090075Sobrien cmp dividend, #0 @ Early termination? 651132718Skan beq LSYM(Lover5) 65290075Sobrien lsr curbit, #4 @ No, any more bits to do? 653132718Skan beq LSYM(Lover5) 65490075Sobrien lsr divisor, #4 655132718Skan b LSYM(Loop3) 656132718SkanLSYM(Lover5): 65790075Sobrien .if \modulo 65890075Sobrien @ Any subtractions that we should not have done will be recorded in 65990075Sobrien @ the top three bits of "overdone". Exactly which were not needed 66090075Sobrien @ are governed by the position of the bit, stored in ip. 66190075Sobrien mov work, #0xe 66290075Sobrien lsl work, #28 66390075Sobrien and overdone, work 664132718Skan beq LSYM(Lgot_result) 66590075Sobrien 66690075Sobrien @ If we terminated early, because dividend became zero, then the 66790075Sobrien @ bit in ip will not be in the bottom nibble, and we should not 66890075Sobrien @ perform the additions below. We must test for this though 66990075Sobrien @ (rather relying upon the TSTs to prevent the additions) since 67090075Sobrien @ the bit in ip could be in the top two bits which might then match 67190075Sobrien @ with one of the smaller RORs. 67290075Sobrien mov curbit, ip 67390075Sobrien mov work, #0x7 67490075Sobrien tst curbit, work 675132718Skan beq LSYM(Lgot_result) 67690075Sobrien 67790075Sobrien mov curbit, ip 67890075Sobrien mov work, #3 67990075Sobrien ror curbit, work 68090075Sobrien tst overdone, curbit 681132718Skan beq LSYM(Lover6) 68290075Sobrien lsr work, divisor, #3 68390075Sobrien add dividend, work 684132718SkanLSYM(Lover6): 68590075Sobrien mov curbit, ip 68690075Sobrien mov work, #2 68790075Sobrien ror curbit, work 68890075Sobrien tst overdone, curbit 689132718Skan beq LSYM(Lover7) 69090075Sobrien lsr work, divisor, #2 69190075Sobrien add dividend, work 692132718SkanLSYM(Lover7): 69390075Sobrien mov curbit, ip 69490075Sobrien mov work, #1 69590075Sobrien ror curbit, work 69690075Sobrien tst overdone, curbit 697132718Skan beq LSYM(Lgot_result) 69890075Sobrien lsr work, divisor, #1 69990075Sobrien add dividend, work 70090075Sobrien .endif 701132718SkanLSYM(Lgot_result): 70290075Sobrien.endm 70390075Sobrien/* ------------------------------------------------------------------------ */ 70490075Sobrien/* Start of the Real Functions */ 70590075Sobrien/* ------------------------------------------------------------------------ */ 70690075Sobrien#ifdef L_udivsi3 70790075Sobrien 70890075Sobrien FUNC_START udivsi3 709169689Skan FUNC_ALIAS aeabi_uidiv udivsi3 71090075Sobrien 71190075Sobrien#ifdef __thumb__ 71290075Sobrien 71390075Sobrien cmp divisor, #0 714132718Skan beq LSYM(Ldiv0) 71590075Sobrien mov curbit, #1 71690075Sobrien mov result, #0 71790075Sobrien 71890075Sobrien push { work } 71990075Sobrien cmp dividend, divisor 720132718Skan blo LSYM(Lgot_result) 72190075Sobrien 72290075Sobrien THUMB_DIV_MOD_BODY 0 72390075Sobrien 72490075Sobrien mov r0, result 72590075Sobrien pop { work } 72690075Sobrien RET 72790075Sobrien 72890075Sobrien#else /* ARM version. */ 729132718Skan 730132718Skan subs r2, r1, #1 731132718Skan RETc(eq) 732132718Skan bcc LSYM(Ldiv0) 733132718Skan cmp r0, r1 734132718Skan bls 11f 735132718Skan tst r1, r2 736132718Skan beq 12f 73790075Sobrien 738132718Skan ARM_DIV_BODY r0, r1, r2, r3 73990075Sobrien 740132718Skan mov r0, r2 74190075Sobrien RET 74290075Sobrien 743132718Skan11: moveq r0, #1 744132718Skan movne r0, #0 745132718Skan RET 746132718Skan 747132718Skan12: ARM_DIV2_ORDER r1, r2 748132718Skan 749132718Skan mov r0, r0, lsr r2 750132718Skan RET 751132718Skan 75290075Sobrien#endif /* ARM version */ 75390075Sobrien 754132718Skan DIV_FUNC_END udivsi3 75590075Sobrien 756169689SkanFUNC_START aeabi_uidivmod 757169689Skan#ifdef __thumb__ 758169689Skan push {r0, r1, lr} 759169689Skan bl SYM(__udivsi3) 760169689Skan POP {r1, r2, r3} 761169689Skan mul r2, r0 762169689Skan sub r1, r1, r2 763169689Skan bx r3 764169689Skan#else 765169689Skan stmfd sp!, { r0, r1, lr } 766169689Skan bl SYM(__udivsi3) 767169689Skan ldmfd sp!, { r1, r2, lr } 768169689Skan mul r3, r2, r0 769169689Skan sub r1, r1, r3 770169689Skan RET 771169689Skan#endif 772169689Skan FUNC_END aeabi_uidivmod 773169689Skan 77490075Sobrien#endif /* L_udivsi3 */ 77590075Sobrien/* ------------------------------------------------------------------------ */ 77690075Sobrien#ifdef L_umodsi3 77790075Sobrien 77890075Sobrien FUNC_START umodsi3 77990075Sobrien 78090075Sobrien#ifdef __thumb__ 78190075Sobrien 78290075Sobrien cmp divisor, #0 783132718Skan beq LSYM(Ldiv0) 78490075Sobrien mov curbit, #1 78590075Sobrien cmp dividend, divisor 786132718Skan bhs LSYM(Lover10) 78790075Sobrien RET 78890075Sobrien 789132718SkanLSYM(Lover10): 79090075Sobrien push { work } 79190075Sobrien 79290075Sobrien THUMB_DIV_MOD_BODY 1 79390075Sobrien 79490075Sobrien pop { work } 79590075Sobrien RET 79690075Sobrien 79790075Sobrien#else /* ARM version. */ 79890075Sobrien 799132718Skan subs r2, r1, #1 @ compare divisor with 1 800132718Skan bcc LSYM(Ldiv0) 801132718Skan cmpne r0, r1 @ compare dividend with divisor 802132718Skan moveq r0, #0 803132718Skan tsthi r1, r2 @ see if divisor is power of 2 804132718Skan andeq r0, r0, r2 805132718Skan RETc(ls) 80690075Sobrien 807132718Skan ARM_MOD_BODY r0, r1, r2, r3 80890075Sobrien 80990075Sobrien RET 81090075Sobrien 81190075Sobrien#endif /* ARM version. */ 81290075Sobrien 813132718Skan DIV_FUNC_END umodsi3 81490075Sobrien 81590075Sobrien#endif /* L_umodsi3 */ 81690075Sobrien/* ------------------------------------------------------------------------ */ 81790075Sobrien#ifdef L_divsi3 81890075Sobrien 81990075Sobrien FUNC_START divsi3 820169689Skan FUNC_ALIAS aeabi_idiv divsi3 82190075Sobrien 82290075Sobrien#ifdef __thumb__ 82390075Sobrien cmp divisor, #0 824132718Skan beq LSYM(Ldiv0) 82590075Sobrien 82690075Sobrien push { work } 82790075Sobrien mov work, dividend 82890075Sobrien eor work, divisor @ Save the sign of the result. 82990075Sobrien mov ip, work 83090075Sobrien mov curbit, #1 83190075Sobrien mov result, #0 83290075Sobrien cmp divisor, #0 833132718Skan bpl LSYM(Lover10) 83490075Sobrien neg divisor, divisor @ Loops below use unsigned. 835132718SkanLSYM(Lover10): 83690075Sobrien cmp dividend, #0 837132718Skan bpl LSYM(Lover11) 83890075Sobrien neg dividend, dividend 839132718SkanLSYM(Lover11): 84090075Sobrien cmp dividend, divisor 841132718Skan blo LSYM(Lgot_result) 84290075Sobrien 84390075Sobrien THUMB_DIV_MOD_BODY 0 84490075Sobrien 84590075Sobrien mov r0, result 84690075Sobrien mov work, ip 84790075Sobrien cmp work, #0 848132718Skan bpl LSYM(Lover12) 84990075Sobrien neg r0, r0 850132718SkanLSYM(Lover12): 85190075Sobrien pop { work } 85290075Sobrien RET 85390075Sobrien 85490075Sobrien#else /* ARM version. */ 85590075Sobrien 856132718Skan cmp r1, #0 857132718Skan eor ip, r0, r1 @ save the sign of the result. 858132718Skan beq LSYM(Ldiv0) 859132718Skan rsbmi r1, r1, #0 @ loops below use unsigned. 860132718Skan subs r2, r1, #1 @ division by 1 or -1 ? 861132718Skan beq 10f 862132718Skan movs r3, r0 863132718Skan rsbmi r3, r0, #0 @ positive dividend value 864132718Skan cmp r3, r1 865132718Skan bls 11f 866132718Skan tst r1, r2 @ divisor is power of 2 ? 867132718Skan beq 12f 86890075Sobrien 869132718Skan ARM_DIV_BODY r3, r1, r0, r2 87090075Sobrien 87190075Sobrien cmp ip, #0 87290075Sobrien rsbmi r0, r0, #0 87390075Sobrien RET 87490075Sobrien 875132718Skan10: teq ip, r0 @ same sign ? 876132718Skan rsbmi r0, r0, #0 877132718Skan RET 878132718Skan 879132718Skan11: movlo r0, #0 880132718Skan moveq r0, ip, asr #31 881132718Skan orreq r0, r0, #1 882132718Skan RET 883132718Skan 884132718Skan12: ARM_DIV2_ORDER r1, r2 885132718Skan 886132718Skan cmp ip, #0 887132718Skan mov r0, r3, lsr r2 888132718Skan rsbmi r0, r0, #0 889132718Skan RET 890132718Skan 89190075Sobrien#endif /* ARM version */ 89290075Sobrien 893132718Skan DIV_FUNC_END divsi3 89490075Sobrien 895169689SkanFUNC_START aeabi_idivmod 896169689Skan#ifdef __thumb__ 897169689Skan push {r0, r1, lr} 898169689Skan bl SYM(__divsi3) 899169689Skan POP {r1, r2, r3} 900169689Skan mul r2, r0 901169689Skan sub r1, r1, r2 902169689Skan bx r3 903169689Skan#else 904169689Skan stmfd sp!, { r0, r1, lr } 905169689Skan bl SYM(__divsi3) 906169689Skan ldmfd sp!, { r1, r2, lr } 907169689Skan mul r3, r2, r0 908169689Skan sub r1, r1, r3 909169689Skan RET 910169689Skan#endif 911169689Skan FUNC_END aeabi_idivmod 912169689Skan 91390075Sobrien#endif /* L_divsi3 */ 91490075Sobrien/* ------------------------------------------------------------------------ */ 91590075Sobrien#ifdef L_modsi3 91690075Sobrien 91790075Sobrien FUNC_START modsi3 91890075Sobrien 91990075Sobrien#ifdef __thumb__ 92090075Sobrien 92190075Sobrien mov curbit, #1 92290075Sobrien cmp divisor, #0 923132718Skan beq LSYM(Ldiv0) 924132718Skan bpl LSYM(Lover10) 92590075Sobrien neg divisor, divisor @ Loops below use unsigned. 926132718SkanLSYM(Lover10): 92790075Sobrien push { work } 92890075Sobrien @ Need to save the sign of the dividend, unfortunately, we need 92990075Sobrien @ work later on. Must do this after saving the original value of 93090075Sobrien @ the work register, because we will pop this value off first. 93190075Sobrien push { dividend } 93290075Sobrien cmp dividend, #0 933132718Skan bpl LSYM(Lover11) 93490075Sobrien neg dividend, dividend 935132718SkanLSYM(Lover11): 93690075Sobrien cmp dividend, divisor 937132718Skan blo LSYM(Lgot_result) 93890075Sobrien 93990075Sobrien THUMB_DIV_MOD_BODY 1 94090075Sobrien 94190075Sobrien pop { work } 94290075Sobrien cmp work, #0 943132718Skan bpl LSYM(Lover12) 94490075Sobrien neg dividend, dividend 945132718SkanLSYM(Lover12): 94690075Sobrien pop { work } 94790075Sobrien RET 94890075Sobrien 94990075Sobrien#else /* ARM version. */ 95090075Sobrien 951132718Skan cmp r1, #0 952132718Skan beq LSYM(Ldiv0) 953132718Skan rsbmi r1, r1, #0 @ loops below use unsigned. 954132718Skan movs ip, r0 @ preserve sign of dividend 955132718Skan rsbmi r0, r0, #0 @ if negative make positive 956132718Skan subs r2, r1, #1 @ compare divisor with 1 957132718Skan cmpne r0, r1 @ compare dividend with divisor 958132718Skan moveq r0, #0 959132718Skan tsthi r1, r2 @ see if divisor is power of 2 960132718Skan andeq r0, r0, r2 961132718Skan bls 10f 96290075Sobrien 963132718Skan ARM_MOD_BODY r0, r1, r2, r3 96490075Sobrien 965132718Skan10: cmp ip, #0 966132718Skan rsbmi r0, r0, #0 96790075Sobrien RET 96890075Sobrien 96990075Sobrien#endif /* ARM version */ 97090075Sobrien 971132718Skan DIV_FUNC_END modsi3 97290075Sobrien 97390075Sobrien#endif /* L_modsi3 */ 97490075Sobrien/* ------------------------------------------------------------------------ */ 97590075Sobrien#ifdef L_dvmd_tls 97690075Sobrien 97790075Sobrien FUNC_START div0 978169689Skan FUNC_ALIAS aeabi_idiv0 div0 979169689Skan FUNC_ALIAS aeabi_ldiv0 div0 98090075Sobrien 98190075Sobrien RET 98290075Sobrien 983132718Skan FUNC_END div0 98490075Sobrien 98590075Sobrien#endif /* L_divmodsi_tools */ 98690075Sobrien/* ------------------------------------------------------------------------ */ 98790075Sobrien#ifdef L_dvmd_lnx 98890075Sobrien@ GNU/Linux division-by zero handler. Used in place of L_dvmd_tls 98990075Sobrien 990169689Skan/* Constant taken from <asm/signal.h>. */ 99190075Sobrien#define SIGFPE 8 99290075Sobrien 993132718Skan .code 32 99490075Sobrien FUNC_START div0 99590075Sobrien 99690075Sobrien stmfd sp!, {r1, lr} 997169689Skan mov r0, #SIGFPE 998169689Skan bl SYM(raise) __PLT__ 999132718Skan RETLDM r1 100090075Sobrien 1001132718Skan FUNC_END div0 100290075Sobrien 100390075Sobrien#endif /* L_dvmd_lnx */ 100490075Sobrien/* ------------------------------------------------------------------------ */ 1005169689Skan/* Dword shift operations. */ 1006169689Skan/* All the following Dword shift variants rely on the fact that 1007169689Skan shft xxx, Reg 1008169689Skan is in fact done as 1009169689Skan shft xxx, (Reg & 255) 1010169689Skan so for Reg value in (32...63) and (-1...-31) we will get zero (in the 1011169689Skan case of logical shifts) or the sign (for asr). */ 1012169689Skan 1013169689Skan#ifdef __ARMEB__ 1014169689Skan#define al r1 1015169689Skan#define ah r0 1016169689Skan#else 1017169689Skan#define al r0 1018169689Skan#define ah r1 1019169689Skan#endif 1020169689Skan 1021169689Skan/* Prevent __aeabi double-word shifts from being produced on SymbianOS. */ 1022169689Skan#ifndef __symbian__ 1023169689Skan 1024169689Skan#ifdef L_lshrdi3 1025169689Skan 1026169689Skan FUNC_START lshrdi3 1027169689Skan FUNC_ALIAS aeabi_llsr lshrdi3 1028169689Skan 1029169689Skan#ifdef __thumb__ 1030169689Skan lsr al, r2 1031169689Skan mov r3, ah 1032169689Skan lsr ah, r2 1033169689Skan mov ip, r3 1034169689Skan sub r2, #32 1035169689Skan lsr r3, r2 1036169689Skan orr al, r3 1037169689Skan neg r2, r2 1038169689Skan mov r3, ip 1039169689Skan lsl r3, r2 1040169689Skan orr al, r3 1041169689Skan RET 1042169689Skan#else 1043169689Skan subs r3, r2, #32 1044169689Skan rsb ip, r2, #32 1045169689Skan movmi al, al, lsr r2 1046169689Skan movpl al, ah, lsr r3 1047169689Skan orrmi al, al, ah, lsl ip 1048169689Skan mov ah, ah, lsr r2 1049169689Skan RET 1050169689Skan#endif 1051169689Skan FUNC_END aeabi_llsr 1052169689Skan FUNC_END lshrdi3 1053169689Skan 1054169689Skan#endif 1055169689Skan 1056169689Skan#ifdef L_ashrdi3 1057169689Skan 1058169689Skan FUNC_START ashrdi3 1059169689Skan FUNC_ALIAS aeabi_lasr ashrdi3 1060169689Skan 1061169689Skan#ifdef __thumb__ 1062169689Skan lsr al, r2 1063169689Skan mov r3, ah 1064169689Skan asr ah, r2 1065169689Skan sub r2, #32 1066169689Skan @ If r2 is negative at this point the following step would OR 1067169689Skan @ the sign bit into all of AL. That's not what we want... 1068169689Skan bmi 1f 1069169689Skan mov ip, r3 1070169689Skan asr r3, r2 1071169689Skan orr al, r3 1072169689Skan mov r3, ip 1073169689Skan1: 1074169689Skan neg r2, r2 1075169689Skan lsl r3, r2 1076169689Skan orr al, r3 1077169689Skan RET 1078169689Skan#else 1079169689Skan subs r3, r2, #32 1080169689Skan rsb ip, r2, #32 1081169689Skan movmi al, al, lsr r2 1082169689Skan movpl al, ah, asr r3 1083169689Skan orrmi al, al, ah, lsl ip 1084169689Skan mov ah, ah, asr r2 1085169689Skan RET 1086169689Skan#endif 1087169689Skan 1088169689Skan FUNC_END aeabi_lasr 1089169689Skan FUNC_END ashrdi3 1090169689Skan 1091169689Skan#endif 1092169689Skan 1093169689Skan#ifdef L_ashldi3 1094169689Skan 1095169689Skan FUNC_START ashldi3 1096169689Skan FUNC_ALIAS aeabi_llsl ashldi3 1097169689Skan 1098169689Skan#ifdef __thumb__ 1099169689Skan lsl ah, r2 1100169689Skan mov r3, al 1101169689Skan lsl al, r2 1102169689Skan mov ip, r3 1103169689Skan sub r2, #32 1104169689Skan lsl r3, r2 1105169689Skan orr ah, r3 1106169689Skan neg r2, r2 1107169689Skan mov r3, ip 1108169689Skan lsr r3, r2 1109169689Skan orr ah, r3 1110169689Skan RET 1111169689Skan#else 1112169689Skan subs r3, r2, #32 1113169689Skan rsb ip, r2, #32 1114169689Skan movmi ah, ah, lsl r2 1115169689Skan movpl ah, al, lsl r3 1116169689Skan orrmi ah, ah, al, lsr ip 1117169689Skan mov al, al, lsl r2 1118169689Skan RET 1119169689Skan#endif 1120169689Skan FUNC_END aeabi_llsl 1121169689Skan FUNC_END ashldi3 1122169689Skan 1123169689Skan#endif 1124169689Skan 1125169689Skan#endif /* __symbian__ */ 1126169689Skan 1127169689Skan/* ------------------------------------------------------------------------ */ 112890075Sobrien/* These next two sections are here despite the fact that they contain Thumb 112990075Sobrien assembler because their presence allows interworked code to be linked even 113090075Sobrien when the GCC library is this one. */ 113190075Sobrien 113290075Sobrien/* Do not build the interworking functions when the target architecture does 113390075Sobrien not support Thumb instructions. (This can be a multilib option). */ 1134169689Skan#if defined __ARM_ARCH_4T__ || defined __ARM_ARCH_5T__\ 1135169689Skan || defined __ARM_ARCH_5TE__ || defined __ARM_ARCH_5TEJ__ \ 1136169689Skan || __ARM_ARCH__ >= 6 113790075Sobrien 1138169689Skan#if defined L_call_via_rX 1139169689Skan 114090075Sobrien/* These labels & instructions are used by the Arm/Thumb interworking code. 114190075Sobrien The address of function to be called is loaded into a register and then 114290075Sobrien one of these labels is called via a BL instruction. This puts the 114390075Sobrien return address into the link register with the bottom bit set, and the 114490075Sobrien code here switches to the correct mode before executing the function. */ 114590075Sobrien 114690075Sobrien .text 114790075Sobrien .align 0 114890075Sobrien .force_thumb 114990075Sobrien 115090075Sobrien.macro call_via register 115190075Sobrien THUMB_FUNC_START _call_via_\register 115290075Sobrien 115390075Sobrien bx \register 115490075Sobrien nop 115590075Sobrien 115690075Sobrien SIZE (_call_via_\register) 115790075Sobrien.endm 115890075Sobrien 115990075Sobrien call_via r0 116090075Sobrien call_via r1 116190075Sobrien call_via r2 116290075Sobrien call_via r3 116390075Sobrien call_via r4 116490075Sobrien call_via r5 116590075Sobrien call_via r6 116690075Sobrien call_via r7 116790075Sobrien call_via r8 116890075Sobrien call_via r9 116990075Sobrien call_via sl 117090075Sobrien call_via fp 117190075Sobrien call_via ip 117290075Sobrien call_via sp 117390075Sobrien call_via lr 117490075Sobrien 117590075Sobrien#endif /* L_call_via_rX */ 117690075Sobrien 1177169689Skan#if defined L_interwork_call_via_rX 1178169689Skan 117990075Sobrien/* These labels & instructions are used by the Arm/Thumb interworking code, 118090075Sobrien when the target address is in an unknown instruction set. The address 118190075Sobrien of function to be called is loaded into a register and then one of these 118290075Sobrien labels is called via a BL instruction. This puts the return address 118390075Sobrien into the link register with the bottom bit set, and the code here 118490075Sobrien switches to the correct mode before executing the function. Unfortunately 118590075Sobrien the target code cannot be relied upon to return via a BX instruction, so 118690075Sobrien instead we have to store the resturn address on the stack and allow the 118790075Sobrien called function to return here instead. Upon return we recover the real 1188169689Skan return address and use a BX to get back to Thumb mode. 1189169689Skan 1190169689Skan There are three variations of this code. The first, 1191169689Skan _interwork_call_via_rN(), will push the return address onto the 1192169689Skan stack and pop it in _arm_return(). It should only be used if all 1193169689Skan arguments are passed in registers. 1194169689Skan 1195169689Skan The second, _interwork_r7_call_via_rN(), instead stores the return 1196169689Skan address at [r7, #-4]. It is the caller's responsibility to ensure 1197169689Skan that this address is valid and contains no useful data. 1198169689Skan 1199169689Skan The third, _interwork_r11_call_via_rN(), works in the same way but 1200169689Skan uses r11 instead of r7. It is useful if the caller does not really 1201169689Skan need a frame pointer. */ 120290075Sobrien 120390075Sobrien .text 120490075Sobrien .align 0 120590075Sobrien 120690075Sobrien .code 32 120790075Sobrien .globl _arm_return 1208169689SkanLSYM(Lstart_arm_return): 1209169689Skan cfi_start LSYM(Lstart_arm_return) LSYM(Lend_arm_return) 1210169689Skan cfi_push 0, 0xe, -0x8, 0x8 1211169689Skan nop @ This nop is for the benefit of debuggers, so that 1212169689Skan @ backtraces will use the correct unwind information. 1213132718Skan_arm_return: 1214169689Skan RETLDM unwind=LSYM(Lstart_arm_return) 1215169689Skan cfi_end LSYM(Lend_arm_return) 121690075Sobrien 1217169689Skan .globl _arm_return_r7 1218169689Skan_arm_return_r7: 1219169689Skan ldr lr, [r7, #-4] 1220169689Skan bx lr 1221169689Skan 1222169689Skan .globl _arm_return_r11 1223169689Skan_arm_return_r11: 1224169689Skan ldr lr, [r11, #-4] 1225169689Skan bx lr 1226169689Skan 1227169689Skan.macro interwork_with_frame frame, register, name, return 1228169689Skan .code 16 1229169689Skan 1230169689Skan THUMB_FUNC_START \name 1231169689Skan 1232169689Skan bx pc 1233169689Skan nop 1234169689Skan 1235169689Skan .code 32 1236169689Skan tst \register, #1 1237169689Skan streq lr, [\frame, #-4] 1238169689Skan adreq lr, _arm_return_\frame 1239169689Skan bx \register 1240169689Skan 1241169689Skan SIZE (\name) 1242169689Skan.endm 1243169689Skan 1244132718Skan.macro interwork register 1245132718Skan .code 16 124690075Sobrien 124790075Sobrien THUMB_FUNC_START _interwork_call_via_\register 124890075Sobrien 1249132718Skan bx pc 125090075Sobrien nop 1251132718Skan 1252132718Skan .code 32 1253132718Skan .globl LSYM(Lchange_\register) 1254132718SkanLSYM(Lchange_\register): 125590075Sobrien tst \register, #1 1256169689Skan streq lr, [sp, #-8]! 125790075Sobrien adreq lr, _arm_return 125890075Sobrien bx \register 125990075Sobrien 126090075Sobrien SIZE (_interwork_call_via_\register) 1261169689Skan 1262169689Skan interwork_with_frame r7,\register,_interwork_r7_call_via_\register 1263169689Skan interwork_with_frame r11,\register,_interwork_r11_call_via_\register 126490075Sobrien.endm 126590075Sobrien 126690075Sobrien interwork r0 126790075Sobrien interwork r1 126890075Sobrien interwork r2 126990075Sobrien interwork r3 127090075Sobrien interwork r4 127190075Sobrien interwork r5 127290075Sobrien interwork r6 127390075Sobrien interwork r7 127490075Sobrien interwork r8 127590075Sobrien interwork r9 127690075Sobrien interwork sl 127790075Sobrien interwork fp 127890075Sobrien interwork ip 127990075Sobrien interwork sp 128090075Sobrien 128190075Sobrien /* The LR case has to be handled a little differently... */ 128290075Sobrien .code 16 128390075Sobrien 128490075Sobrien THUMB_FUNC_START _interwork_call_via_lr 128590075Sobrien 128690075Sobrien bx pc 128790075Sobrien nop 128890075Sobrien 128990075Sobrien .code 32 129090075Sobrien .globl .Lchange_lr 129190075Sobrien.Lchange_lr: 129290075Sobrien tst lr, #1 1293169689Skan stmeqdb r13!, {lr, pc} 129490075Sobrien mov ip, lr 129590075Sobrien adreq lr, _arm_return 129690075Sobrien bx ip 129790075Sobrien 129890075Sobrien SIZE (_interwork_call_via_lr) 129990075Sobrien 130090075Sobrien#endif /* L_interwork_call_via_rX */ 1301169689Skan#endif /* Arch supports thumb. */ 1302132718Skan 1303169689Skan#ifndef __symbian__ 1304132718Skan#include "ieee754-df.S" 1305132718Skan#include "ieee754-sf.S" 1306169689Skan#include "bpabi.S" 1307169689Skan#endif /* __symbian__ */ 1308