1/* libgcc routines for C-SKY. 2 Copyright (C) 2018-2021 Free Software Foundation, Inc. 3 Contributed by C-SKY Microsystems and Mentor Graphics. 4 5 This file is part of GCC. 6 7 GCC is free software; you can redistribute it and/or modify it 8 under the terms of the GNU General Public License as published by the 9 Free Software Foundation; either version 3, or (at your option) any 10 later version. 11 12 This file is distributed in the hope that it will be useful, but 13 WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 General Public License for more details. 16 17 Under Section 7 of GPL version 3, you are granted additional 18 permissions described in the GCC Runtime Library Exception, version 19 3.1, as published by the Free Software Foundation. 20 21 You should have received a copy of the GNU General Public License and 22 a copy of the GCC Runtime Library Exception along with this program; 23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 24 <http://www.gnu.org/licenses/>. */ 25 26 27/* Use the right prefix for global labels. */ 28#define CONCAT1(a, b) CONCAT2(a, b) 29#define CONCAT2(a, b) a ## b 30#define SYM(x) CONCAT1 (__, x) 31 32#ifndef __CSKYBE__ 33#define xl r0 34#define xh r1 35#define yl r2 36#define yh r3 37#else 38#define xh r0 39#define xl r1 40#define yh r2 41#define yl r3 42#endif 43 44 45#ifdef __ELF__ 46#define TYPE(x) .type SYM (x),@function 47#define SIZE(x) .size SYM (x), . - SYM (x) 48#else 49#define TYPE(x) 50#define SIZE(x) 51#endif 52 53.macro FUNC_START name 54 .text 55 .align 2 56 .globl SYM (\name) 57 TYPE (\name) 58SYM (\name): 59.endm 60 61.macro FUNC_END name 62 SIZE (\name) 63.endm 64 65 66/* Emulate FF1 ("fast find 1") instruction on ck801. 67 Result goes in rx, clobbering ry. */ 68#if defined(__CK801__) 69.macro FF1_M rx, ry 70 movi \rx, 32 7110: 72 cmphsi \ry, 1 73 bf 11f 74 subi \rx, \rx, 1 75 lsri \ry, \ry, 1 76 br 10b 7711: 78.endm 79#else 80.macro FF1_M rx, ry 81 ff1 \rx, \ry 82.endm 83#endif 84 85/* Likewise emulate lslc instruction ("logical left shift to C") on CK801. */ 86#if defined(__CK801__) 87.macro LSLC_M rx 88 cmpne \rx, \rx 89 addc \rx, \rx 90.endm 91#else 92.macro LSLC_M rx 93 lslc \rx 94.endm 95#endif 96 97/* Emulate the abs instruction. */ 98#if defined(__CK802__) 99.macro ABS_M rx 100 btsti \rx, 31 101 bf 10f 102 not \rx 103 addi \rx, 1 10410: 105.endm 106#elif defined(__CK801__) 107.macro ABS_M rx 108 cmplti \rx, 1 109 bf 10f 110 not \rx 111 addi \rx, 1 11210: 113.endm 114#else 115.macro ABS_M rx 116 abs \rx 117.endm 118#endif 119 120/* Emulate the ld.hs ("load signed halfword and extend") instruction 121 on ck801 and ck802. */ 122#if defined(__CK801__) 123.macro LDBS_M rx, ry 124 ld.b \rx, (\ry, 0x0) 125 sextb \rx, \rx 126.endm 127#else 128.macro LDBS_M rx, ry 129 ld.bs \rx, (\ry, 0x0) 130.endm 131#endif 132 133#if defined(__CK801__) 134.macro LDHS_M rx, ry 135 ld.h \rx, (\ry, 0x0) 136 sexth \rx, \rx 137.endm 138#else 139.macro LDHS_M rx, ry 140 ld.hs \rx, (\ry, 0x0) 141.endm 142#endif 143 144 145/* Signed and unsigned div/mod/rem functions. */ 146 147#ifdef L_udivsi3 148FUNC_START udiv32 149FUNC_START udivsi3 150 cmpnei a1, 0 // look for 0 divisor 151 bt 9f 152 trap 3 // divide by 0 1539: 154 // control iterations, skip across high order 0 bits in dividend 155 cmpnei a0, 0 156 bt 8f 157 jmp lr // 0 dividend quick return 1588: 159 push l0 160 movi a2, 1 // a2 is quotient (1 for a sentinel) 161 mov a3, a0 162 FF1_M l0, a3 // figure distance to skip 163 lsl a2, l0 // move the sentinel along (with 0's behind) 164 lsl a0, l0 // and the low 32 bits of numerator 165 166 // FIXME: Is this correct? 167 mov a3, a1 // looking at divisor 168 FF1_M l0, a3 // I can move 32-l0 more bits to left. 169 addi l0, 1 // ok, one short of that... 170 mov a3, a0 171 lsr a3, l0 // bits that came from low order... 172 not l0 // l0 == "32-n" == LEFT distance 173 addi l0, 33 // this is (32-n) 174 lsl a2,l0 // fixes the high 32 (quotient) 175 lsl a0,l0 176 cmpnei a2,0 177 bf 4f // the sentinel went away... 178 179 // run the remaining bits 1801: 181 LSLC_M a0 // 1 bit left shift of a3-a0 182 addc a3, a3 183 cmphs a3, a1 // upper 32 of dividend >= divisor? 184 bf 2f 185 subu a3, a1 // if yes, subtract divisor 1862: 187 addc a2, a2 // shift by 1 and count subtracts 188 bf 1b // if sentinel falls out of quotient, stop 189 1904: 191 mov a0, a2 // return quotient 192 mov a1, a3 // and piggyback the remainder 193 pop l0 194FUNC_END udiv32 195FUNC_END udivsi3 196#endif 197 198#ifdef L_umodsi3 199FUNC_START urem32 200FUNC_START umodsi3 201 cmpnei a1, 0 // look for 0 divisor 202 bt 9f 203 trap 3 // divide by 0 2049: 205 // control iterations, skip across high order 0 bits in dividend 206 cmpnei a0, 0 207 bt 8f 208 jmp lr // 0 dividend quick return 2098: 210 mov a2, a0 211 FF1_M a3, a2 // figure distance to skip 212 movi a2, 1 // a2 is quotient (1 for a sentinel) 213 lsl a2, a3 // move the sentinel along (with 0's behind) 214 lsl a0, a3 // and the low 32 bits of numerator 215 movi a3, 0 216 2171: 218 LSLC_M a0 // 1 bit left shift of a3-a0 219 addc a3, a3 220 cmphs a3, a1 // upper 32 of dividend >= divisor? 221 bf 2f 222 subu a3, a1 // if yes, subtract divisor 2232: 224 addc a2, a2 // shift by 1 and count subtracts 225 bf 1b // if sentinel falls out of quotient, stop 226 2274: 228 mov a0, a3 // and piggyback the remainder 229 jmp lr 230FUNC_END urem32 231FUNC_END umodsi3 232#endif 233 234 235#ifdef L_divsi3 236FUNC_START div32 237FUNC_START divsi3 238 cmpnei a1, 0 // look for 0 divisor 239 bt 9f 240 trap 3 // divide by 0 2419: 242 // control iterations, skip across high order 0 bits in dividend 243 cmpnei a0, 0 244 bt 8f 245 jmp lr // 0 dividend quick return 2468: 247 push l0, l1 248 mov l1, a0 249 xor l1, a1 // calc sign of quotient 250 ABS_M a0 251 ABS_M a1 252 movi a2, 1 // a2 is quotient (1 for a sentinel) 253 mov a3, a0 254 FF1_M l0, a3 // figure distance to skip 255 lsl a2, l0 // move the sentinel along (with 0's behind) 256 lsl a0, l0 // and the low 32 bits of numerator 257 258 // FIXME: is this correct? 259 mov a3, a1 // looking at divisor 260 FF1_M l0, a3 // I can move 32-l0 more bits to left. 261 addi l0, 1 // ok, one short of that... 262 mov a3, a0 263 lsr a3, l0 // bits that came from low order... 264 not l0 // l0 == "32-n" == LEFT distance 265 addi l0, 33 // this is (32-n) 266 lsl a2,l0 // fixes the high 32 (quotient) 267 lsl a0,l0 268 cmpnei a2,0 269 bf 4f // the sentinel went away... 270 271 // run the remaining bits 2721: 273 LSLC_M a0 // 1 bit left shift of a3-a0 274 addc a3, a3 275 cmphs a3, a1 // upper 32 of dividend >= divisor? 276 bf 2f 277 subu a3, a1 // if yes, subtract divisor 2782: 279 addc a2, a2 // shift by 1 and count subtracts 280 bf 1b // if sentinel falls out of quotient, stop 281 2824: 283 mov a0, a2 // return quotient 284 mov a1, a3 // and piggyback the remainder 285 LSLC_M l1 // after adjusting for sign 286 bf 3f 287 not a0 288 addi a0, 1 289 not a1 290 addi a1, 1 2913: 292 pop l0, l1 293FUNC_END div32 294FUNC_END divsi3 295#endif 296 297#ifdef L_modsi3 298FUNC_START rem32 299FUNC_START modsi3 300 push l0 301 cmpnei a1, 0 // look for 0 divisor 302 bt 9f 303 trap 3 // divide by 0 3049: 305 // control iterations, skip across high order 0 bits in dividend 306 cmpnei a0, 0 307 bt 8f 308 pop l0 // 0 dividend quick return 3098: 310 mov l0, a0 311 ABS_M a0 312 ABS_M a1 313 mov a2, a0 314 FF1_M a3, a2 // figure distance to skip 315 movi a2, 1 // a2 is quotient (1 for a sentinel) 316 lsl a2, a3 // move the sentinel along (with 0's behind) 317 lsl a0, a3 // and the low 32 bits of numerator 318 movi a3, 0 319 320 // run the remaining bits 3211: 322 LSLC_M a0 // 1 bit left shift of a3-a0 323 addc a3, a3 324 cmphs a3, a1 // upper 32 of dividend >= divisor? 325 bf 2f 326 subu a3, a1 // if yes, subtract divisor 3272: 328 addc a2, a2 // shift by 1 and count subtracts 329 bf 1b // if sentinel falls out of quotient, stop 330 3314: 332 mov a0, a3 // and piggyback the remainder 333 LSLC_M l0 // after adjusting for sign 334 bf 3f 335 not a0 336 addi a0, 1 3373: 338 pop l0 339FUNC_END rem32 340FUNC_END modsi3 341#endif 342 343/* Unordered comparisons for single and double float. */ 344 345#ifdef L_unordsf2 346FUNC_START unordsf2 347#if defined(__CK801__) 348 subi sp, 4 349 st.w r4, (sp, 0x0) 350 lsli r2, r0, 1 351 lsli r3, r1, 1 352 asri r4, r2, 24 353 not r4 354 cmpnei r4, 0 355 bt 1f 356 lsli r4, r0, 9 357 cmpnei r4, 0 358 bt 3f 3591: 360 asri r4, r3, 24 361 not r4 362 cmpnei r4, 0 363 bt 2f 364 lsli r4, r1, 9 365 cmpnei r4, 0 366 bt 3f 3672: 368 ld.w r4, (sp, 0x0) 369 addi sp, 4 370 movi r0, 0 371 rts 3723: 373 ld.w r4, (sp, 0x0) 374 addi sp, 4 375 movi r0, 1 376 rts 377#elif defined(__CK802__) 378 lsli r2, r0, 1 379 lsli r3, r1, 1 380 asri r2, r2, 24 381 not r13, r2 382 cmpnei r13, 0 383 bt 1f 384 lsli r13, r0, 9 385 cmpnei r13, 0 386 bt 3f 3871: 388 asri r3, r3, 24 389 not r13, r3 390 cmpnei r13, 0 391 bt 2f 392 lsli r13, r1, 9 393 cmpnei r13, 0 394 bt 3f 3952: 396 movi r0, 0 397 rts 3983: 399 movi r0, 1 400 rts 401#else 402 lsli r2, r0, 1 403 lsli r3, r1, 1 404 asri r2, r2, 24 405 not r13, r2 406 bnez r13, 1f 407 lsli r13, r0, 9 408 bnez r13, 3f 4091: 410 asri r3, r3, 24 411 not r13, r3 412 bnez r13, 2f 413 lsli r13, r1, 9 414 bnez r13, 3f 4152: 416 movi r0, 0 417 rts 4183: 419 movi r0, 1 420 rts 421#endif 422FUNC_END unordsf2 423#endif 424 425#ifdef L_unorddf2 426FUNC_START unorddf2 427#if defined(__CK801__) 428 subi sp, 8 429 st.w r4, (sp, 0x0) 430 st.w r5, (sp, 0x4) 431 lsli r4, xh, 1 432 asri r4, r4, 21 433 not r4 434 cmpnei r4, 0 435 bt 1f 436 mov r4, xl 437 lsli r5, xh, 12 438 or r4, r5 439 cmpnei r4, 0 440 bt 3f 4411: 442 lsli r4, yh, 1 443 asri r4, r4, 21 444 not r4 445 cmpnei r4, 0 446 bt 2f 447 mov r4,yl 448 lsli r5, yh, 12 449 or r4, r5 450 cmpnei r4, 0 451 bt 3f 4522: 453 ld.w r4, (sp, 0x0) 454 ld.w r5, (sp, 0x4) 455 addi sp, 8 456 movi r0, 0 457 rts 4583: 459 ld.w r4, (sp, 0x0) 460 ld.w r5, (sp, 0x4) 461 addi sp, 8 462 movi r0, 1 463 rts 464#elif defined(__CK802__) 465 lsli r13, xh, 1 466 asri r13, r13, 21 467 not r13 468 cmpnei r13, 0 469 bt 1f 470 lsli xh, xh, 12 471 or r13, xl, xh 472 cmpnei r13, 0 473 bt 3f 4741: 475 lsli r13, yh, 1 476 asri r13, r13, 21 477 not r13 478 cmpnei r13, 0 479 bt 2f 480 lsli yh, yh, 12 481 or r13, yl, yh 482 cmpnei r13, 0 483 bt 3f 4842: 485 movi r0, 0 486 rts 4873: 488 movi r0, 1 489 rts 490#else 491 lsli r13, xh, 1 492 asri r13, r13, 21 493 not r13 494 bnez r13, 1f 495 lsli xh, xh, 12 496 or r13, xl, xh 497 bnez r13, 3f 4981: 499 lsli r13, yh, 1 500 asri r13, r13, 21 501 not r13 502 bnez r13, 2f 503 lsli yh, yh, 12 504 or r13, yl, yh 505 bnez r13, 3f 5062: 507 movi r0, 0 508 rts 5093: 510 movi r0, 1 511 rts 512#endif 513FUNC_END unorddf2 514#endif 515 516/* When optimizing for size on ck801 and ck802, GCC emits calls to the 517 following helper functions when expanding casesi, instead of emitting 518 the table lookup and jump inline. Note that in these functions the 519 jump is handled by tweaking the value of lr before rts. */ 520#ifdef L_csky_case_sqi 521FUNC_START _gnu_csky_case_sqi 522 subi sp, 4 523 st.w a1, (sp, 0x0) 524 mov a1, lr 525 add a1, a1, a0 526 LDBS_M a1, a1 527 lsli a1, a1, 1 528 add lr, lr, a1 529 ld.w a1, (sp, 0x0) 530 addi sp, 4 531 rts 532FUNC_END _gnu_csky_case_sqi 533#endif 534 535#ifdef L_csky_case_uqi 536FUNC_START _gnu_csky_case_uqi 537 subi sp, 4 538 st.w a1, (sp, 0x0) 539 mov a1, lr 540 add a1, a1, a0 541 ld.b a1, (a1, 0x0) 542 lsli a1, a1, 1 543 add lr, lr, a1 544 ld.w a1, (sp, 0x0) 545 addi sp, 4 546 rts 547FUNC_END _gnu_csky_case_uqi 548#endif 549 550#ifdef L_csky_case_shi 551FUNC_START _gnu_csky_case_shi 552 subi sp, 8 553 st.w a0, (sp, 0x4) 554 st.w a1, (sp, 0x0) 555 mov a1, lr 556 lsli a0, a0, 1 557 add a1, a1, a0 558 LDHS_M a1, a1 559 lsli a1, a1, 1 560 add lr, lr, a1 561 ld.w a0, (sp, 0x4) 562 ld.w a1, (sp, 0x0) 563 addi sp, 8 564 rts 565FUNC_END _gnu_csky_case_shi 566#endif 567 568#ifdef L_csky_case_uhi 569FUNC_START _gnu_csky_case_uhi 570 subi sp, 8 571 st.w a0, (sp, 0x4) 572 st.w a1, (sp, 0x0) 573 mov a1, lr 574 lsli a0, a0, 1 575 add a1, a1, a0 576 ld.h a1, (a1, 0x0) 577 lsli a1, a1, 1 578 add lr, lr, a1 579 ld.w a0, (sp, 0x4) 580 ld.w a1, (sp, 0x0) 581 addi sp, 8 582 rts 583FUNC_END _gnu_csky_case_uhi 584#endif 585 586#ifdef L_csky_case_si 587FUNC_START _gnu_csky_case_si 588 subi sp, 8 589 st.w a0, (sp, 0x4) 590 st.w a1, (sp, 0x0) 591 mov a1, lr 592 addi a1, a1, 2 // Align to word. 593 bclri a1, a1, 1 594 mov lr, a1 595 lsli a0, a0, 2 596 add a1, a1, a0 597 ld.w a0, (a1, 0x0) 598 add lr, lr, a0 599 ld.w a0, (sp, 0x4) 600 ld.w a1, (sp, 0x0) 601 addi sp, 8 602 rts 603FUNC_END _gnu_csky_case_si 604#endif 605 606/* GCC expects that {__eq,__ne,__gt,__ge,__le,__lt}{df2,sf2} 607 will behave as __cmpdf2. So, we stub the implementations to 608 jump on to __cmpdf2 and __cmpsf2. 609 610 All of these short-circuit the return path so that __cmp{sd}f2 611 will go directly back to the caller. */ 612 613.macro COMPARE_DF_JUMP name 614 .import SYM (cmpdf2) 615FUNC_START \name 616 jmpi SYM (cmpdf2) 617FUNC_END \name 618.endm 619 620#ifdef L_eqdf2 621COMPARE_DF_JUMP eqdf2 622#endif /* L_eqdf2 */ 623 624#ifdef L_nedf2 625COMPARE_DF_JUMP nedf2 626#endif /* L_nedf2 */ 627 628#ifdef L_gtdf2 629COMPARE_DF_JUMP gtdf2 630#endif /* L_gtdf2 */ 631 632#ifdef L_gedf2 633COMPARE_DF_JUMP gedf2 634#endif /* L_gedf2 */ 635 636#ifdef L_ltdf2 637COMPARE_DF_JUMP ltdf2 638#endif /* L_ltdf2 */ 639 640#ifdef L_ledf2 641COMPARE_DF_JUMP ledf2 642#endif /* L_ledf2 */ 643 644/* Single-precision floating point stubs. */ 645 646.macro COMPARE_SF_JUMP name 647 .import SYM (cmpsf2) 648FUNC_START \name 649 jmpi SYM (cmpsf2) 650FUNC_END \name 651.endm 652 653#ifdef L_eqsf2 654COMPARE_SF_JUMP eqsf2 655#endif /* L_eqsf2 */ 656 657#ifdef L_nesf2 658COMPARE_SF_JUMP nesf2 659#endif /* L_nesf2 */ 660 661#ifdef L_gtsf2 662COMPARE_SF_JUMP gtsf2 663#endif /* L_gtsf2 */ 664 665#ifdef L_gesf2 666COMPARE_SF_JUMP __gesf2 667#endif /* L_gesf2 */ 668 669#ifdef L_ltsf2 670COMPARE_SF_JUMP __ltsf2 671#endif /* L_ltsf2 */ 672 673#ifdef L_lesf2 674COMPARE_SF_JUMP lesf2 675#endif /* L_lesf2 */ 676