|
|
1.1 root 1: /* Output routines for GCC for ARM/RISCiX. 1.1.1.3 ! root 2: Copyright (C) 1991, 1993, 1994 Free Software Foundation, Inc. 1.1 root 3: Contributed by Pieter `Tiggr' Schoenmakers ([email protected]) 4: and Martin Simmons (@harleqn.co.uk). 1.1.1.2 root 5: More major hacks by Richard Earnshaw ([email protected]) 1.1 root 6: 7: This file is part of GNU CC. 8: 9: GNU CC is free software; you can redistribute it and/or modify 10: it under the terms of the GNU General Public License as published by 11: the Free Software Foundation; either version 2, or (at your option) 12: any later version. 13: 14: GNU CC is distributed in the hope that it will be useful, 15: but WITHOUT ANY WARRANTY; without even the implied warranty of 16: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17: GNU General Public License for more details. 18: 19: You should have received a copy of the GNU General Public License 20: along with GNU CC; see the file COPYING. If not, write to 21: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ 1.1.1.2 root 22: 1.1 root 23: #include <stdio.h> 1.1.1.3 ! root 24: #include <string.h> 1.1 root 25: #include "assert.h" 26: #include "config.h" 27: #include "rtl.h" 28: #include "regs.h" 29: #include "hard-reg-set.h" 30: #include "real.h" 31: #include "insn-config.h" 32: #include "conditions.h" 33: #include "insn-flags.h" 34: #include "output.h" 35: #include "insn-attr.h" 36: #include "flags.h" 1.1.1.2 root 37: #include "reload.h" 1.1.1.3 ! root 38: #include "tree.h" ! 39: #include "expr.h" 1.1 root 40: 41: /* The maximum number of insns skipped which will be conditionalised if 42: possible. */ 43: #define MAX_INSNS_SKIPPED 5 44: 45: /* Some function declarations. */ 46: extern FILE *asm_out_file; 47: extern char *output_multi_immediate (); 48: extern void arm_increase_location (); 49: 1.1.1.3 ! root 50: HOST_WIDE_INT int_log2 PROTO ((HOST_WIDE_INT)); ! 51: static int get_prologue_size PROTO ((void)); ! 52: 1.1.1.2 root 53: /* Define the information needed to generate branch insns. This is 54: stored from the compare operation. */ 55: 56: rtx arm_compare_op0, arm_compare_op1; 57: int arm_compare_fp; 58: 59: /* What type of cpu are we compiling for? */ 60: enum processor_type arm_cpu; 61: 1.1.1.3 ! root 62: /* Waht type of floating point are we compiling for? */ ! 63: enum floating_point_type arm_fpu; ! 64: 1.1 root 65: /* In case of a PRE_INC, POST_INC, PRE_DEC, POST_DEC memory reference, we 66: must report the mode of the memory reference from PRINT_OPERAND to 67: PRINT_OPERAND_ADDRESS. */ 1.1.1.3 ! root 68: enum machine_mode output_memory_reference_mode; 1.1 root 69: 70: /* Nonzero if the prologue must setup `fp'. */ 71: int current_function_anonymous_args; 72: 73: /* Location counter of .text segment. */ 74: int arm_text_location = 0; 75: 1.1.1.2 root 76: /* Set to one if we think that lr is only saved because of subroutine calls, 77: but all of these can be `put after' return insns */ 78: int lr_save_eliminated; 79: 1.1 root 80: /* A hash table is used to store text segment labels and their associated 81: offset from the start of the text segment. */ 82: struct label_offset 83: { 84: char *name; 85: int offset; 86: struct label_offset *cdr; 87: }; 88: 89: #define LABEL_HASH_SIZE 257 90: 91: static struct label_offset *offset_table[LABEL_HASH_SIZE]; 92: 1.1.1.2 root 93: /* Set to 1 when a return insn is output, this means that the epilogue 94: is not needed. */ 95: 96: static int return_used_this_function; 97: 1.1 root 98: /* For an explanation of these variables, see final_prescan_insn below. */ 99: int arm_ccfsm_state; 100: int arm_current_cc; 101: rtx arm_target_insn; 102: int arm_target_label; 1.1.1.3 ! root 103: ! 104: /* The condition codes of the ARM, and the inverse function. */ ! 105: char *arm_condition_codes[] = ! 106: { ! 107: "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", ! 108: "hi", "ls", "ge", "lt", "gt", "le", "al", "nv" ! 109: }; ! 110: ! 111: #define ARM_INVERSE_CONDITION_CODE(X) ((X) ^ 1) 1.1 root 112: 1.1.1.2 root 113: /* Return 1 if it is possible to return using a single instruction */ 114: 115: int 116: use_return_insn () 117: { 118: int regno; 119: 120: if (!reload_completed ||current_function_pretend_args_size 121: || current_function_anonymous_args 122: || (get_frame_size () && !(TARGET_APCS || frame_pointer_needed))) 123: return 0; 124: 125: /* Can't be done if any of the FPU regs are pushed, since this also 126: requires an insn */ 127: for (regno = 20; regno < 24; regno++) 128: if (regs_ever_live[regno]) 129: return 0; 130: 131: return 1; 132: } 133: 1.1 root 134: /* Return TRUE if int I is a valid immediate ARM constant. */ 135: 136: int 137: const_ok_for_arm (i) 1.1.1.2 root 138: HOST_WIDE_INT i; 1.1 root 139: { 1.1.1.2 root 140: unsigned HOST_WIDE_INT mask = ~0xFF; 1.1 root 141: 1.1.1.3 ! root 142: /* Fast return for 0 and powers of 2 */ ! 143: if ((i & (i - 1)) == 0) ! 144: return TRUE; ! 145: 1.1 root 146: do 147: { 1.1.1.2 root 148: if ((i & mask & (unsigned HOST_WIDE_INT) 0xffffffff) == 0) 1.1.1.3 ! root 149: return TRUE; 1.1.1.2 root 150: mask = 151: (mask << 2) | ((mask & (unsigned HOST_WIDE_INT) 0xffffffff) 152: >> (32 - 2)) | ~((unsigned HOST_WIDE_INT) 0xffffffff); 1.1 root 153: } while (mask != ~0xFF); 154: 1.1.1.3 ! root 155: return FALSE; ! 156: } ! 157: ! 158: /* Return true if I is a valid constant for the operation CODE. */ ! 159: int ! 160: const_ok_for_op (i, code, mode) ! 161: HOST_WIDE_INT i; ! 162: enum rtx_code code; ! 163: enum machine_mode mode; ! 164: { ! 165: if (const_ok_for_arm (i)) ! 166: return 1; ! 167: ! 168: switch (code) ! 169: { ! 170: case PLUS: ! 171: return const_ok_for_arm (ARM_SIGN_EXTEND (-i)); ! 172: ! 173: case MINUS: /* Should only occur with (MINUS I reg) => rsb */ ! 174: case XOR: ! 175: case IOR: ! 176: return 0; ! 177: ! 178: case AND: ! 179: return const_ok_for_arm (ARM_SIGN_EXTEND (~i)); ! 180: ! 181: default: ! 182: abort (); ! 183: } ! 184: } ! 185: ! 186: /* Emit a sequence of insns to handle a large constant. ! 187: CODE is the code of the operation required, it can be any of SET, PLUS, ! 188: IOR, AND, XOR, MINUS; ! 189: MODE is the mode in which the operation is being performed; ! 190: VAL is the integer to operate on; ! 191: SOURCE is the other operand (a register, or a null-pointer for SET); ! 192: SUBTARGETS means it is safe to create scratch registers if that will ! 193: either produce a simpler sequence, or we will want to cse the values. */ ! 194: ! 195: int ! 196: arm_split_constant (code, mode, val, target, source, subtargets) ! 197: enum rtx_code code; ! 198: enum machine_mode mode; ! 199: HOST_WIDE_INT val; ! 200: rtx target; ! 201: rtx source; ! 202: int subtargets; ! 203: { ! 204: int can_add = 0; ! 205: int can_invert = 0; ! 206: int can_negate = 0; ! 207: int can_negate_initial = 0; ! 208: int can_shift = 0; ! 209: int i; ! 210: int num_bits_set = 0; ! 211: int set_sign_bit_copies = 0; ! 212: int clear_sign_bit_copies = 0; ! 213: int clear_zero_bit_copies = 0; ! 214: int set_zero_bit_copies = 0; ! 215: int insns = 0; ! 216: rtx new_src; ! 217: unsigned HOST_WIDE_INT temp1, temp2; ! 218: unsigned HOST_WIDE_INT remainder = val & 0xffffffff; ! 219: ! 220: /* find out which operations are safe for a given CODE. Also do a quick ! 221: check for degenerate cases; these can occur when DImode operations ! 222: are split. */ ! 223: switch (code) ! 224: { ! 225: case SET: ! 226: can_invert = 1; ! 227: can_shift = 1; ! 228: can_negate = 1; ! 229: break; ! 230: ! 231: case PLUS: ! 232: can_negate = 1; ! 233: can_negate_initial = 1; ! 234: break; ! 235: ! 236: case IOR: ! 237: if (remainder == 0xffffffff) ! 238: { ! 239: emit_insn (gen_rtx (SET, VOIDmode, target, ! 240: GEN_INT (ARM_SIGN_EXTEND (val)))); ! 241: return 1; ! 242: } ! 243: if (remainder == 0) ! 244: { ! 245: if (reload_completed && rtx_equal_p (target, source)) ! 246: return 0; ! 247: emit_insn (gen_rtx (SET, VOIDmode, target, source)); ! 248: return 1; ! 249: } ! 250: break; ! 251: ! 252: case AND: ! 253: if (remainder == 0) ! 254: { ! 255: emit_insn (gen_rtx (SET, VOIDmode, target, const0_rtx)); ! 256: return 1; ! 257: } ! 258: if (remainder == 0xffffffff) ! 259: { ! 260: if (reload_completed && rtx_equal_p (target, source)) ! 261: return 0; ! 262: emit_insn (gen_rtx (SET, VOIDmode, target, source)); ! 263: return 1; ! 264: } ! 265: can_invert = 1; ! 266: break; ! 267: ! 268: case XOR: ! 269: if (remainder == 0) ! 270: { ! 271: if (reload_completed && rtx_equal_p (target, source)) ! 272: return 0; ! 273: emit_insn (gen_rtx (SET, VOIDmode, target, source)); ! 274: return 1; ! 275: } ! 276: if (remainder == 0xffffffff) ! 277: { ! 278: emit_insn (gen_rtx (SET, VOIDmode, target, ! 279: gen_rtx (NOT, mode, source))); ! 280: return 1; ! 281: } ! 282: ! 283: /* We don't know how to handle this yet below. */ ! 284: abort (); ! 285: ! 286: case MINUS: ! 287: /* We treat MINUS as (val - source), since (source - val) is always ! 288: passed as (source + (-val)). */ ! 289: if (remainder == 0) ! 290: { ! 291: emit_insn (gen_rtx (SET, VOIDmode, target, ! 292: gen_rtx (NEG, mode, source))); ! 293: return 1; ! 294: } ! 295: if (const_ok_for_arm (val)) ! 296: { ! 297: emit_insn (gen_rtx (SET, VOIDmode, target, ! 298: gen_rtx (MINUS, mode, GEN_INT (val), source))); ! 299: return 1; ! 300: } ! 301: can_negate = 1; ! 302: ! 303: break; ! 304: ! 305: default: ! 306: abort (); ! 307: } ! 308: ! 309: /* If we can do it in one insn get out quickly */ ! 310: if (const_ok_for_arm (val) ! 311: || (can_negate_initial && const_ok_for_arm (-val)) ! 312: || (can_invert && const_ok_for_arm (~val))) ! 313: { ! 314: emit_insn (gen_rtx (SET, VOIDmode, target, ! 315: (source ? gen_rtx (code, mode, source, ! 316: GEN_INT (val)) : GEN_INT (val)))); ! 317: return 1; ! 318: } ! 319: ! 320: ! 321: /* Calculate a few attributes that may be useful for specific ! 322: optimizations. */ ! 323: ! 324: for (i = 31; i >= 0; i--) ! 325: { ! 326: if ((remainder & (1 << i)) == 0) ! 327: clear_sign_bit_copies++; ! 328: else ! 329: break; ! 330: } ! 331: ! 332: for (i = 31; i >= 0; i--) ! 333: { ! 334: if ((remainder & (1 << i)) != 0) ! 335: set_sign_bit_copies++; ! 336: else ! 337: break; ! 338: } ! 339: ! 340: for (i = 0; i <= 31; i++) ! 341: { ! 342: if ((remainder & (1 << i)) == 0) ! 343: clear_zero_bit_copies++; ! 344: else ! 345: break; ! 346: } ! 347: ! 348: for (i = 0; i <= 31; i++) ! 349: { ! 350: if ((remainder & (1 << i)) != 0) ! 351: set_zero_bit_copies++; ! 352: else ! 353: break; ! 354: } ! 355: ! 356: switch (code) ! 357: { ! 358: case SET: ! 359: /* See if we can do this by sign_extending a constant that is known ! 360: to be negative. This is a good, way of doing it, since the shift ! 361: may well merge into a subsequent insn. */ ! 362: if (set_sign_bit_copies > 1) ! 363: { ! 364: if (const_ok_for_arm ! 365: (temp1 = ARM_SIGN_EXTEND (remainder ! 366: << (set_sign_bit_copies - 1)))) ! 367: { ! 368: new_src = subtargets ? gen_reg_rtx (mode) : target; ! 369: emit_insn (gen_rtx (SET, VOIDmode, new_src, GEN_INT (temp1))); ! 370: emit_insn (gen_ashrsi3 (target, new_src, ! 371: GEN_INT (set_sign_bit_copies - 1))); ! 372: return 2; ! 373: } ! 374: /* For an inverted constant, we will need to set the low bits, ! 375: these will be shifted out of harm's way. */ ! 376: temp1 |= (1 << (set_sign_bit_copies - 1)) - 1; ! 377: if (const_ok_for_arm (~temp1)) ! 378: { ! 379: new_src = subtargets ? gen_reg_rtx (mode) : target; ! 380: emit_insn (gen_rtx (SET, VOIDmode, new_src, GEN_INT (temp1))); ! 381: emit_insn (gen_ashrsi3 (target, new_src, ! 382: GEN_INT (set_sign_bit_copies - 1))); ! 383: return 2; ! 384: } ! 385: } ! 386: ! 387: /* See if we can generate this by setting the bottom (or the top) ! 388: 16 bits, and then shifting these into the other half of the ! 389: word. We only look for the simplest cases, to do more would cost ! 390: too much. Be careful, however, not to generate this when the ! 391: alternative would take fewer insns. */ ! 392: if (val & 0xffff0000) ! 393: { ! 394: temp1 = remainder & 0xffff0000; ! 395: temp2 = remainder & 0x0000ffff; ! 396: ! 397: /* Overlaps outside this range are best done using other methods. */ ! 398: for (i = 9; i < 24; i++) ! 399: { ! 400: if ((((temp2 | (temp2 << i)) & 0xffffffff) == remainder) ! 401: && ! const_ok_for_arm (temp2)) ! 402: { ! 403: insns ! 404: = arm_split_constant (code, mode, temp2, ! 405: (new_src ! 406: = subtargets ? gen_reg_rtx (mode) ! 407: : target), ! 408: source, subtargets); ! 409: source = new_src; ! 410: emit_insn (gen_rtx (SET, VOIDmode, target, ! 411: gen_rtx (IOR, mode, ! 412: gen_rtx (ASHIFT, mode, source, ! 413: GEN_INT (i)), ! 414: source))); ! 415: return insns + 1; ! 416: } ! 417: } ! 418: ! 419: /* Don't duplicate cases already considered. */ ! 420: for (i = 17; i < 24; i++) ! 421: { ! 422: if (((temp1 | (temp1 >> i)) == remainder) ! 423: && ! const_ok_for_arm (temp1)) ! 424: { ! 425: insns ! 426: = arm_split_constant (code, mode, temp1, ! 427: (new_src ! 428: = subtargets ? gen_reg_rtx (mode) ! 429: : target), ! 430: source, subtargets); ! 431: source = new_src; ! 432: emit_insn (gen_rtx (SET, VOIDmode, target, ! 433: gen_rtx (IOR, mode, ! 434: gen_rtx (LSHIFTRT, mode, source, ! 435: GEN_INT (i)), ! 436: source))); ! 437: return insns + 1; ! 438: } ! 439: } ! 440: } ! 441: break; ! 442: ! 443: case IOR: ! 444: case XOR: ! 445: /* If we have IOR or XOR, and the inverse of the constant can be loaded ! 446: in a single instruction, and we can find a temporary to put it in, ! 447: then this can be done in two instructions instead of 3-4. */ ! 448: if (subtargets ! 449: || (reload_completed && ! reg_mentioned_p (target, source))) ! 450: { ! 451: if (const_ok_for_arm (ARM_SIGN_EXTEND (~ val))) ! 452: { ! 453: rtx sub = subtargets ? gen_reg_rtx (mode) : target; ! 454: ! 455: emit_insn (gen_rtx (SET, VOIDmode, sub, ! 456: GEN_INT (ARM_SIGN_EXTEND (~ val)))); ! 457: emit_insn (gen_rtx (SET, VOIDmode, target, ! 458: gen_rtx (code, mode, source, sub))); ! 459: return 2; ! 460: } ! 461: } ! 462: ! 463: if (code == XOR) ! 464: break; ! 465: ! 466: if (set_sign_bit_copies > 8 ! 467: && (val & (-1 << (32 - set_sign_bit_copies))) == val) ! 468: { ! 469: rtx sub = subtargets ? gen_reg_rtx (mode) : target; ! 470: rtx shift = GEN_INT (set_sign_bit_copies); ! 471: ! 472: emit_insn (gen_rtx (SET, VOIDmode, sub, ! 473: gen_rtx (NOT, mode, ! 474: gen_rtx (ASHIFT, mode, source, ! 475: shift)))); ! 476: emit_insn (gen_rtx (SET, VOIDmode, target, ! 477: gen_rtx (NOT, mode, ! 478: gen_rtx (LSHIFTRT, mode, sub, ! 479: shift)))); ! 480: return 2; ! 481: } ! 482: ! 483: if (set_zero_bit_copies > 8 ! 484: && (remainder & ((1 << set_zero_bit_copies) - 1)) == remainder) ! 485: { ! 486: rtx sub = subtargets ? gen_reg_rtx (mode) : target; ! 487: rtx shift = GEN_INT (set_zero_bit_copies); ! 488: ! 489: emit_insn (gen_rtx (SET, VOIDmode, sub, ! 490: gen_rtx (NOT, mode, ! 491: gen_rtx (LSHIFTRT, mode, source, ! 492: shift)))); ! 493: emit_insn (gen_rtx (SET, VOIDmode, target, ! 494: gen_rtx (NOT, mode, ! 495: gen_rtx (ASHIFT, mode, sub, ! 496: shift)))); ! 497: return 2; ! 498: } ! 499: ! 500: if (const_ok_for_arm (temp1 = ARM_SIGN_EXTEND (~ val))) ! 501: { ! 502: rtx sub = subtargets ? gen_reg_rtx (mode) : target; ! 503: emit_insn (gen_rtx (SET, VOIDmode, sub, ! 504: gen_rtx (NOT, mode, source))); ! 505: source = sub; ! 506: if (subtargets) ! 507: sub = gen_reg_rtx (mode); ! 508: emit_insn (gen_rtx (SET, VOIDmode, sub, ! 509: gen_rtx (AND, mode, source, GEN_INT (temp1)))); ! 510: emit_insn (gen_rtx (SET, VOIDmode, target, ! 511: gen_rtx (NOT, mode, sub))); ! 512: return 3; ! 513: } ! 514: break; ! 515: ! 516: case AND: ! 517: /* See if two shifts will do 2 or more insn's worth of work. */ ! 518: if (clear_sign_bit_copies >= 16 && clear_sign_bit_copies < 24) ! 519: { ! 520: HOST_WIDE_INT shift_mask = ((0xffffffff ! 521: << (32 - clear_sign_bit_copies)) ! 522: & 0xffffffff); ! 523: rtx new_source; ! 524: rtx shift = GEN_INT (clear_sign_bit_copies); ! 525: ! 526: if ((remainder | shift_mask) != 0xffffffff) ! 527: { ! 528: new_source = subtargets ? gen_reg_rtx (mode) : target; ! 529: insns = arm_split_constant (AND, mode, remainder | shift_mask, ! 530: new_source, source, subtargets); ! 531: source = new_source; ! 532: } ! 533: ! 534: new_source = subtargets ? gen_reg_rtx (mode) : target; ! 535: emit_insn (gen_ashlsi3 (new_source, source, shift)); ! 536: emit_insn (gen_lshrsi3 (target, new_source, shift)); ! 537: return insns + 2; ! 538: } ! 539: ! 540: if (clear_zero_bit_copies >= 16 && clear_zero_bit_copies < 24) ! 541: { ! 542: HOST_WIDE_INT shift_mask = (1 << clear_zero_bit_copies) - 1; ! 543: rtx new_source; ! 544: rtx shift = GEN_INT (clear_zero_bit_copies); ! 545: ! 546: if ((remainder | shift_mask) != 0xffffffff) ! 547: { ! 548: new_source = subtargets ? gen_reg_rtx (mode) : target; ! 549: insns = arm_split_constant (AND, mode, remainder | shift_mask, ! 550: new_source, source, subtargets); ! 551: source = new_source; ! 552: } ! 553: ! 554: new_source = subtargets ? gen_reg_rtx (mode) : target; ! 555: emit_insn (gen_lshrsi3 (new_source, source, shift)); ! 556: emit_insn (gen_ashlsi3 (target, new_source, shift)); ! 557: return insns + 2; ! 558: } ! 559: ! 560: break; ! 561: ! 562: default: ! 563: break; ! 564: } ! 565: ! 566: for (i = 0; i < 32; i++) ! 567: if (remainder & (1 << i)) ! 568: num_bits_set++; ! 569: ! 570: if (code == AND || (can_invert && num_bits_set > 16)) ! 571: remainder = (~remainder) & 0xffffffff; ! 572: else if (code == PLUS && num_bits_set > 16) ! 573: remainder = (-remainder) & 0xffffffff; ! 574: else ! 575: { ! 576: can_invert = 0; ! 577: can_negate = 0; ! 578: } ! 579: ! 580: /* Now try and find a way of doing the job in either two or three ! 581: instructions. ! 582: We start by looking for the largest block of zeros that are aligned on ! 583: a 2-bit boundary, we then fill up the temps, wrapping around to the ! 584: top of the word when we drop off the bottom. ! 585: In the worst case this code should produce no more than four insns. */ ! 586: { ! 587: int best_start = 0; ! 588: int best_consecutive_zeros = 0; ! 589: ! 590: for (i = 0; i < 32; i += 2) ! 591: { ! 592: int consecutive_zeros = 0; ! 593: ! 594: if (! (remainder & (3 << i))) ! 595: { ! 596: while ((i < 32) && ! (remainder & (3 << i))) ! 597: { ! 598: consecutive_zeros += 2; ! 599: i += 2; ! 600: } ! 601: if (consecutive_zeros > best_consecutive_zeros) ! 602: { ! 603: best_consecutive_zeros = consecutive_zeros; ! 604: best_start = i - consecutive_zeros; ! 605: } ! 606: i -= 2; ! 607: } ! 608: } ! 609: ! 610: /* Now start emitting the insns, starting with the one with the highest ! 611: bit set: we do this so that the smallest number will be emitted last; ! 612: this is more likely to be combinable with addressing insns. */ ! 613: i = best_start; ! 614: do ! 615: { ! 616: int end; ! 617: ! 618: if (i <= 0) ! 619: i += 32; ! 620: if (remainder & (3 << (i - 2))) ! 621: { ! 622: end = i - 8; ! 623: if (end < 0) ! 624: end += 32; ! 625: temp1 = remainder & ((0x0ff << end) ! 626: | ((i < end) ? (0xff >> (32 - end)) : 0)); ! 627: remainder &= ~temp1; ! 628: ! 629: if (code == SET) ! 630: { ! 631: emit_insn (gen_rtx (SET, VOIDmode, ! 632: new_src = (subtargets ? gen_reg_rtx (mode) ! 633: : target), ! 634: GEN_INT (can_invert ? ~temp1 : temp1))); ! 635: can_invert = 0; ! 636: code = PLUS; ! 637: } ! 638: else if (code == MINUS) ! 639: { ! 640: emit_insn (gen_rtx (SET, VOIDmode, ! 641: new_src = (subtargets ? gen_reg_rtx (mode) ! 642: : target), ! 643: gen_rtx (code, mode, GEN_INT (temp1), ! 644: source))); ! 645: code = PLUS; ! 646: } ! 647: else ! 648: { ! 649: emit_insn (gen_rtx (SET, VOIDmode, ! 650: new_src = remainder ? (subtargets ! 651: ? gen_reg_rtx (mode) ! 652: : target) : target, ! 653: gen_rtx (code, mode, source, ! 654: GEN_INT (can_invert ? ~temp1 ! 655: : (can_negate ! 656: ? -temp1 : temp1))))); ! 657: } ! 658: ! 659: insns++; ! 660: source = new_src; ! 661: i -= 6; ! 662: } ! 663: i -= 2; ! 664: } while (remainder); ! 665: } ! 666: return insns; ! 667: } ! 668: ! 669: #define REG_OR_SUBREG_REG(X) \ ! 670: (GET_CODE (X) == REG \ ! 671: || (GET_CODE (X) == SUBREG && GET_CODE (SUBREG_REG (X)) == REG)) ! 672: ! 673: #define REG_OR_SUBREG_RTX(X) \ ! 674: (GET_CODE (X) == REG ? (X) : SUBREG_REG (X)) ! 675: ! 676: #define ARM_FRAME_RTX(X) \ ! 677: ((X) == frame_pointer_rtx || (X) == stack_pointer_rtx \ ! 678: || (X) == arg_pointer_rtx) ! 679: ! 680: int ! 681: arm_rtx_costs (x, code, outer_code) ! 682: rtx x; ! 683: enum rtx_code code, outer_code; ! 684: { ! 685: enum machine_mode mode = GET_MODE (x); ! 686: enum rtx_code subcode; ! 687: int extra_cost; ! 688: ! 689: switch (code) ! 690: { ! 691: case MEM: ! 692: /* Memory costs quite a lot for the first word, but subsequent words ! 693: load at the equivalent of a single insn each. */ ! 694: return (10 + 4 * ((GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD) ! 695: + (CONSTANT_POOL_ADDRESS_P (x) ? 4 : 0)); ! 696: ! 697: case DIV: ! 698: case MOD: ! 699: return 100; ! 700: ! 701: case ROTATE: ! 702: if (mode == SImode && GET_CODE (XEXP (x, 1)) == REG) ! 703: return 4; ! 704: /* Fall through */ ! 705: case ROTATERT: ! 706: if (mode != SImode) ! 707: return 8; ! 708: /* Fall through */ ! 709: case ASHIFT: case LSHIFTRT: case ASHIFTRT: ! 710: if (mode == DImode) ! 711: return (8 + (GET_CODE (XEXP (x, 1)) == CONST_INT ? 0 : 8) ! 712: + ((GET_CODE (XEXP (x, 0)) == REG ! 713: || (GET_CODE (XEXP (x, 0)) == SUBREG ! 714: && GET_CODE (SUBREG_REG (XEXP (x, 0))) == REG)) ! 715: ? 0 : 8)); ! 716: return (1 + ((GET_CODE (XEXP (x, 0)) == REG ! 717: || (GET_CODE (XEXP (x, 0)) == SUBREG ! 718: && GET_CODE (SUBREG_REG (XEXP (x, 0))) == REG)) ! 719: ? 0 : 4) ! 720: + ((GET_CODE (XEXP (x, 1)) == REG ! 721: || (GET_CODE (XEXP (x, 1)) == SUBREG ! 722: && GET_CODE (SUBREG_REG (XEXP (x, 1))) == REG) ! 723: || (GET_CODE (XEXP (x, 1)) == CONST_INT)) ! 724: ? 0 : 4)); ! 725: ! 726: case MINUS: ! 727: if (mode == DImode) ! 728: return (4 + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 8) ! 729: + ((REG_OR_SUBREG_REG (XEXP (x, 0)) ! 730: || (GET_CODE (XEXP (x, 0)) == CONST_INT ! 731: && const_ok_for_arm (INTVAL (XEXP (x, 0))))) ! 732: ? 0 : 8)); ! 733: ! 734: if (GET_MODE_CLASS (mode) == MODE_FLOAT) ! 735: return (2 + ((REG_OR_SUBREG_REG (XEXP (x, 1)) ! 736: || (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE ! 737: && const_double_rtx_ok_for_fpu (XEXP (x, 1)))) ! 738: ? 0 : 8) ! 739: + ((REG_OR_SUBREG_REG (XEXP (x, 0)) ! 740: || (GET_CODE (XEXP (x, 0)) == CONST_DOUBLE ! 741: && const_double_rtx_ok_for_fpu (XEXP (x, 0)))) ! 742: ? 0 : 8)); ! 743: ! 744: if (((GET_CODE (XEXP (x, 0)) == CONST_INT ! 745: && const_ok_for_arm (INTVAL (XEXP (x, 0))) ! 746: && REG_OR_SUBREG_REG (XEXP (x, 1)))) ! 747: || (((subcode = GET_CODE (XEXP (x, 1))) == ASHIFT ! 748: || subcode == ASHIFTRT || subcode == LSHIFTRT ! 749: || subcode == ROTATE || subcode == ROTATERT ! 750: || (subcode == MULT ! 751: && GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT ! 752: && ((INTVAL (XEXP (XEXP (x, 1), 1)) & ! 753: (INTVAL (XEXP (XEXP (x, 1), 1)) - 1)) == 0))) ! 754: && REG_OR_SUBREG_REG (XEXP (XEXP (x, 1), 0)) ! 755: && (REG_OR_SUBREG_REG (XEXP (XEXP (x, 1), 1)) ! 756: || GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT) ! 757: && REG_OR_SUBREG_REG (XEXP (x, 0)))) ! 758: return 1; ! 759: /* Fall through */ ! 760: ! 761: case PLUS: ! 762: if (GET_MODE_CLASS (mode) == MODE_FLOAT) ! 763: return (2 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 8) ! 764: + ((REG_OR_SUBREG_REG (XEXP (x, 1)) ! 765: || (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE ! 766: && const_double_rtx_ok_for_fpu (XEXP (x, 1)))) ! 767: ? 0 : 8)); ! 768: ! 769: /* Fall through */ ! 770: case AND: case XOR: case IOR: ! 771: extra_cost = 0; ! 772: ! 773: /* Normally the frame registers will be spilt into reg+const during ! 774: reload, so it is a bad idea to combine them with other instructions, ! 775: since then they might not be moved outside of loops. As a compromise ! 776: we allow integration with ops that have a constant as their second ! 777: operand. */ ! 778: if ((REG_OR_SUBREG_REG (XEXP (x, 0)) ! 779: && ARM_FRAME_RTX (REG_OR_SUBREG_RTX (XEXP (x, 0))) ! 780: && GET_CODE (XEXP (x, 1)) != CONST_INT) ! 781: || (REG_OR_SUBREG_REG (XEXP (x, 0)) ! 782: && ARM_FRAME_RTX (REG_OR_SUBREG_RTX (XEXP (x, 0))))) ! 783: extra_cost = 4; ! 784: ! 785: if (mode == DImode) ! 786: return (4 + extra_cost + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 8) ! 787: + ((REG_OR_SUBREG_REG (XEXP (x, 1)) ! 788: || (GET_CODE (XEXP (x, 1)) == CONST_INT ! 789: && const_ok_for_op (INTVAL (XEXP (x, 1)), code, mode))) ! 790: ? 0 : 8)); ! 791: ! 792: if (REG_OR_SUBREG_REG (XEXP (x, 0))) ! 793: return (1 + (GET_CODE (XEXP (x, 1)) == CONST_INT ? 0 : extra_cost) ! 794: + ((REG_OR_SUBREG_REG (XEXP (x, 1)) ! 795: || (GET_CODE (XEXP (x, 1)) == CONST_INT ! 796: && const_ok_for_op (INTVAL (XEXP (x, 1)), code, mode))) ! 797: ? 0 : 4)); ! 798: ! 799: else if (REG_OR_SUBREG_REG (XEXP (x, 1))) ! 800: return (1 + extra_cost ! 801: + ((((subcode = GET_CODE (XEXP (x, 0))) == ASHIFT ! 802: || subcode == LSHIFTRT || subcode == ASHIFTRT ! 803: || subcode == ROTATE || subcode == ROTATERT ! 804: || (subcode == MULT ! 805: && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT ! 806: && ((INTVAL (XEXP (XEXP (x, 0), 1)) & ! 807: (INTVAL (XEXP (XEXP (x, 0), 1)) - 1)) == 0)) ! 808: && (REG_OR_SUBREG_REG (XEXP (XEXP (x, 0), 0))) ! 809: && ((REG_OR_SUBREG_REG (XEXP (XEXP (x, 0), 1))) ! 810: || GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT))) ! 811: ? 0 : 4)); ! 812: ! 813: return 8; ! 814: ! 815: case MULT: ! 816: if (GET_MODE_CLASS (mode) == MODE_FLOAT ! 817: || mode == DImode) ! 818: return 30; ! 819: ! 820: if (GET_CODE (XEXP (x, 1)) == CONST_INT) ! 821: { ! 822: HOST_WIDE_INT i = INTVAL (XEXP (x, 1)) & 0xffffffff; ! 823: int add_cost = const_ok_for_arm (i) ? 4 : 8; ! 824: int j; ! 825: ! 826: /* This will need adjusting for ARM's with fast multiplies */ ! 827: for (j = 0; i && j < 32; j += 2) ! 828: { ! 829: i &= ~(3 << j); ! 830: add_cost += 2; ! 831: } ! 832: ! 833: return add_cost; ! 834: } ! 835: ! 836: return (30 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4) ! 837: + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 4)); ! 838: ! 839: case NEG: ! 840: if (GET_MODE_CLASS (mode) == MODE_FLOAT) ! 841: return 4 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 6); ! 842: /* Fall through */ ! 843: case NOT: ! 844: if (mode == DImode) ! 845: return 4 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4); ! 846: ! 847: return 1 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4); ! 848: ! 849: case IF_THEN_ELSE: ! 850: if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC) ! 851: return 14; ! 852: return 2; ! 853: ! 854: case COMPARE: ! 855: return 1; ! 856: ! 857: case ABS: ! 858: return 4 + (mode == DImode ? 4 : 0); ! 859: ! 860: case SIGN_EXTEND: ! 861: if (GET_MODE (XEXP (x, 0)) == QImode) ! 862: return (4 + (mode == DImode ? 4 : 0) ! 863: + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0)); ! 864: /* Fall through */ ! 865: case ZERO_EXTEND: ! 866: switch (GET_MODE (XEXP (x, 0))) ! 867: { ! 868: case QImode: ! 869: return (1 + (mode == DImode ? 4 : 0) ! 870: + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0)); ! 871: ! 872: case HImode: ! 873: return (4 + (mode == DImode ? 4 : 0) ! 874: + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0)); ! 875: ! 876: case SImode: ! 877: return (1 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0)); ! 878: } ! 879: abort (); 1.1 root 880: 1.1.1.3 ! root 881: default: ! 882: return 99; ! 883: } ! 884: } ! 885: 1.1.1.2 root 886: /* This code has been fixed for cross compilation. */ 887: 888: static int fpa_consts_inited = 0; 889: 890: char *strings_fpa[8] = { 891: "0.0", 892: "1.0", 893: "2.0", 894: "3.0", 895: "4.0", 896: "5.0", 897: "0.5", 898: "10.0" 899: }; 900: 901: static REAL_VALUE_TYPE values_fpa[8]; 902: 903: static void 904: init_fpa_table () 905: { 906: int i; 907: REAL_VALUE_TYPE r; 908: 909: for (i = 0; i < 8; i++) 910: { 911: r = REAL_VALUE_ATOF (strings_fpa[i], DFmode); 912: values_fpa[i] = r; 913: } 1.1.1.3 ! root 914: 1.1.1.2 root 915: fpa_consts_inited = 1; 916: } 917: 1.1 root 918: /* Return TRUE if rtx X is a valid immediate FPU constant. */ 919: 920: int 921: const_double_rtx_ok_for_fpu (x) 922: rtx x; 923: { 1.1.1.2 root 924: REAL_VALUE_TYPE r; 925: int i; 926: 927: if (!fpa_consts_inited) 928: init_fpa_table (); 929: 930: REAL_VALUE_FROM_CONST_DOUBLE (r, x); 931: if (REAL_VALUE_MINUS_ZERO (r)) 932: return 0; 1.1.1.3 ! root 933: 1.1.1.2 root 934: for (i = 0; i < 8; i++) 935: if (REAL_VALUES_EQUAL (r, values_fpa[i])) 936: return 1; 1.1.1.3 ! root 937: 1.1.1.2 root 938: return 0; 1.1.1.3 ! root 939: } 1.1.1.2 root 940: 941: /* Return TRUE if rtx X is a valid immediate FPU constant. */ 942: 943: int 944: neg_const_double_rtx_ok_for_fpu (x) 945: rtx x; 946: { 947: REAL_VALUE_TYPE r; 948: int i; 949: 950: if (!fpa_consts_inited) 951: init_fpa_table (); 952: 953: REAL_VALUE_FROM_CONST_DOUBLE (r, x); 954: r = REAL_VALUE_NEGATE (r); 955: if (REAL_VALUE_MINUS_ZERO (r)) 956: return 0; 1.1.1.3 ! root 957: 1.1.1.2 root 958: for (i = 0; i < 8; i++) 959: if (REAL_VALUES_EQUAL (r, values_fpa[i])) 960: return 1; 1.1.1.3 ! root 961: 1.1.1.2 root 962: return 0; 1.1.1.3 ! root 963: } 1.1 root 964: 965: /* Predicates for `match_operand' and `match_operator'. */ 966: 1.1.1.2 root 967: /* s_register_operand is the same as register_operand, but it doesn't accept 968: (SUBREG (MEM)...). */ 969: 970: int 971: s_register_operand (op, mode) 972: register rtx op; 973: enum machine_mode mode; 974: { 975: if (GET_MODE (op) != mode && mode != VOIDmode) 976: return 0; 977: 978: if (GET_CODE (op) == SUBREG) 1.1.1.3 ! root 979: op = SUBREG_REG (op); ! 980: ! 981: /* We don't consider registers whose class is NO_REGS ! 982: to be a register operand. */ ! 983: return (GET_CODE (op) == REG ! 984: && (REGNO (op) >= FIRST_PSEUDO_REGISTER ! 985: || REGNO_REG_CLASS (REGNO (op)) != NO_REGS)); ! 986: } ! 987: ! 988: /* Only accept reg, subreg(reg), const_int. */ ! 989: ! 990: int ! 991: reg_or_int_operand (op, mode) ! 992: register rtx op; ! 993: enum machine_mode mode; ! 994: { ! 995: if (GET_CODE (op) == CONST_INT) ! 996: return 1; ! 997: ! 998: if (GET_MODE (op) != mode && mode != VOIDmode) ! 999: return 0; ! 1000: ! 1001: if (GET_CODE (op) == SUBREG) ! 1002: op = SUBREG_REG (op); 1.1.1.2 root 1003: 1004: /* We don't consider registers whose class is NO_REGS 1005: to be a register operand. */ 1006: return (GET_CODE (op) == REG 1007: && (REGNO (op) >= FIRST_PSEUDO_REGISTER 1008: || REGNO_REG_CLASS (REGNO (op)) != NO_REGS)); 1009: } 1010: 1011: /* Return 1 if OP is an item in memory, given that we are in reload. */ 1012: 1013: int 1014: reload_memory_operand (op, mode) 1015: rtx op; 1016: enum machine_mode mode; 1017: { 1018: int regno = true_regnum (op); 1019: 1020: return (! CONSTANT_P (op) 1021: && (regno == -1 1022: || (GET_CODE (op) == REG 1023: && REGNO (op) >= FIRST_PSEUDO_REGISTER))); 1024: } 1025: 1.1 root 1026: /* Return TRUE for valid operands for the rhs of an ARM instruction. */ 1027: 1028: int 1029: arm_rhs_operand (op, mode) 1030: rtx op; 1031: enum machine_mode mode; 1032: { 1.1.1.2 root 1033: return (s_register_operand (op, mode) 1.1 root 1034: || (GET_CODE (op) == CONST_INT && const_ok_for_arm (INTVAL (op)))); 1.1.1.3 ! root 1035: } 1.1 root 1036: 1.1.1.2 root 1037: /* Return TRUE for valid operands for the rhs of an ARM instruction, or a load. 1038: */ 1039: 1040: int 1041: arm_rhsm_operand (op, mode) 1042: rtx op; 1043: enum machine_mode mode; 1044: { 1045: return (s_register_operand (op, mode) 1046: || (GET_CODE (op) == CONST_INT && const_ok_for_arm (INTVAL (op))) 1047: || memory_operand (op, mode)); 1.1.1.3 ! root 1048: } 1.1.1.2 root 1049: 1050: /* Return TRUE for valid operands for the rhs of an ARM instruction, or if a 1051: constant that is valid when negated. */ 1052: 1053: int 1054: arm_add_operand (op, mode) 1055: rtx op; 1056: enum machine_mode mode; 1057: { 1058: return (s_register_operand (op, mode) 1059: || (GET_CODE (op) == CONST_INT 1060: && (const_ok_for_arm (INTVAL (op)) 1061: || const_ok_for_arm (-INTVAL (op))))); 1.1.1.3 ! root 1062: } 1.1.1.2 root 1063: 1064: int 1065: arm_not_operand (op, mode) 1066: rtx op; 1067: enum machine_mode mode; 1068: { 1069: return (s_register_operand (op, mode) 1070: || (GET_CODE (op) == CONST_INT 1071: && (const_ok_for_arm (INTVAL (op)) 1072: || const_ok_for_arm (~INTVAL (op))))); 1.1.1.3 ! root 1073: } 1.1.1.2 root 1074: 1.1 root 1075: /* Return TRUE for valid operands for the rhs of an FPU instruction. */ 1076: 1077: int 1078: fpu_rhs_operand (op, mode) 1079: rtx op; 1080: enum machine_mode mode; 1081: { 1.1.1.2 root 1082: if (s_register_operand (op, mode)) 1.1.1.3 ! root 1083: return TRUE; 1.1 root 1084: else if (GET_CODE (op) == CONST_DOUBLE) 1085: return (const_double_rtx_ok_for_fpu (op)); 1.1.1.3 ! root 1086: ! 1087: return FALSE; ! 1088: } 1.1 root 1089: 1.1.1.2 root 1090: int 1091: fpu_add_operand (op, mode) 1092: rtx op; 1093: enum machine_mode mode; 1094: { 1095: if (s_register_operand (op, mode)) 1.1.1.3 ! root 1096: return TRUE; 1.1.1.2 root 1097: else if (GET_CODE (op) == CONST_DOUBLE) 1.1.1.3 ! root 1098: return (const_double_rtx_ok_for_fpu (op) ! 1099: || neg_const_double_rtx_ok_for_fpu (op)); ! 1100: ! 1101: return FALSE; 1.1.1.2 root 1102: } 1103: 1.1 root 1104: /* Return nonzero if OP is a constant power of two. */ 1105: 1106: int 1107: power_of_two_operand (op, mode) 1108: rtx op; 1109: enum machine_mode mode; 1110: { 1111: if (GET_CODE (op) == CONST_INT) 1112: { 1.1.1.3 ! root 1113: HOST_WIDE_INT value = INTVAL(op); ! 1114: return value != 0 && (value & (value - 1)) == 0; 1.1 root 1115: } 1.1.1.3 ! root 1116: return FALSE; ! 1117: } 1.1 root 1118: 1119: /* Return TRUE for a valid operand of a DImode operation. 1.1.1.2 root 1120: Either: REG, CONST_DOUBLE or MEM(DImode_address). 1121: Note that this disallows MEM(REG+REG), but allows 1122: MEM(PRE/POST_INC/DEC(REG)). */ 1.1 root 1123: 1124: int 1125: di_operand (op, mode) 1126: rtx op; 1127: enum machine_mode mode; 1128: { 1.1.1.2 root 1129: if (s_register_operand (op, mode)) 1.1.1.3 ! root 1130: return TRUE; 1.1 root 1131: 1132: switch (GET_CODE (op)) 1133: { 1134: case CONST_DOUBLE: 1135: case CONST_INT: 1.1.1.3 ! root 1136: return TRUE; ! 1137: 1.1 root 1138: case MEM: 1.1.1.3 ! root 1139: return memory_address_p (DImode, XEXP (op, 0)); ! 1140: 1.1 root 1141: default: 1.1.1.3 ! root 1142: return FALSE; 1.1 root 1143: } 1.1.1.3 ! root 1144: } 1.1 root 1145: 1146: /* Return TRUE for valid index operands. */ 1147: 1148: int 1149: index_operand (op, mode) 1150: rtx op; 1151: enum machine_mode mode; 1152: { 1.1.1.2 root 1153: return (s_register_operand(op, mode) 1154: || (immediate_operand (op, mode) 1155: && INTVAL (op) < 4096 && INTVAL (op) > -4096)); 1.1.1.3 ! root 1156: } 1.1 root 1157: 1.1.1.2 root 1158: /* Return TRUE for valid shifts by a constant. This also accepts any 1159: power of two on the (somewhat overly relaxed) assumption that the 1160: shift operator in this case was a mult. */ 1161: 1162: int 1163: const_shift_operand (op, mode) 1164: rtx op; 1165: enum machine_mode mode; 1166: { 1167: return (power_of_two_operand (op, mode) 1168: || (immediate_operand (op, mode) 1169: && (INTVAL (op) < 32 && INTVAL (op) > 0))); 1.1.1.3 ! root 1170: } 1.1.1.2 root 1171: 1.1 root 1172: /* Return TRUE for arithmetic operators which can be combined with a multiply 1173: (shift). */ 1174: 1175: int 1176: shiftable_operator (x, mode) 1177: rtx x; 1178: enum machine_mode mode; 1179: { 1180: if (GET_MODE (x) != mode) 1181: return FALSE; 1182: else 1183: { 1184: enum rtx_code code = GET_CODE (x); 1185: 1186: return (code == PLUS || code == MINUS 1187: || code == IOR || code == XOR || code == AND); 1188: } 1.1.1.3 ! root 1189: } 1.1 root 1190: 1191: /* Return TRUE for shift operators. */ 1192: 1193: int 1194: shift_operator (x, mode) 1195: rtx x; 1196: enum machine_mode mode; 1197: { 1198: if (GET_MODE (x) != mode) 1199: return FALSE; 1200: else 1201: { 1202: enum rtx_code code = GET_CODE (x); 1203: 1.1.1.2 root 1204: if (code == MULT) 1205: return power_of_two_operand (XEXP (x, 1)); 1.1.1.3 ! root 1206: ! 1207: return (code == ASHIFT || code == ASHIFTRT || code == LSHIFTRT ! 1208: || code == ROTATERT); 1.1 root 1209: } 1.1.1.3 ! root 1210: } 1.1.1.2 root 1211: 1212: int equality_operator (x, mode) 1.1.1.3 ! root 1213: rtx x; ! 1214: enum machine_mode mode; 1.1.1.2 root 1215: { 1.1.1.3 ! root 1216: return GET_CODE (x) == EQ || GET_CODE (x) == NE; 1.1.1.2 root 1217: } 1218: 1219: /* Return TRUE for SMIN SMAX UMIN UMAX operators. */ 1220: 1221: int 1222: minmax_operator (x, mode) 1223: rtx x; 1224: enum machine_mode mode; 1225: { 1226: enum rtx_code code = GET_CODE (x); 1227: 1228: if (GET_MODE (x) != mode) 1229: return FALSE; 1.1.1.3 ! root 1230: 1.1.1.2 root 1231: return code == SMIN || code == SMAX || code == UMIN || code == UMAX; 1.1.1.3 ! root 1232: } ! 1233: ! 1234: /* return TRUE if x is EQ or NE */ ! 1235: ! 1236: /* Return TRUE if this is the condition code register, if we aren't given ! 1237: a mode, accept any class CCmode register */ ! 1238: ! 1239: int ! 1240: cc_register (x, mode) ! 1241: rtx x; ! 1242: enum machine_mode mode; ! 1243: { ! 1244: if (mode == VOIDmode) ! 1245: { ! 1246: mode = GET_MODE (x); ! 1247: if (GET_MODE_CLASS (mode) != MODE_CC) ! 1248: return FALSE; ! 1249: } ! 1250: ! 1251: if (mode == GET_MODE (x) && GET_CODE (x) == REG && REGNO (x) == 24) ! 1252: return TRUE; 1.1.1.2 root 1253: 1.1.1.3 ! root 1254: return FALSE; ! 1255: } 1.1.1.2 root 1256: 1257: /* Return TRUE if this is the condition code register, if we aren't given 1.1.1.3 ! root 1258: a mode, accept any mode in class CC_MODE that is reversible */ 1.1.1.2 root 1259: 1260: int 1.1.1.3 ! root 1261: reversible_cc_register (x, mode) ! 1262: rtx x; ! 1263: enum machine_mode mode; 1.1.1.2 root 1264: { 1265: if (mode == VOIDmode) 1266: { 1267: mode = GET_MODE (x); 1.1.1.3 ! root 1268: if (GET_MODE_CLASS (mode) != MODE_CC ! 1269: && GET_CODE (x) == REG && REGNO (x) == 24) ! 1270: abort (); ! 1271: if (GET_MODE_CLASS (mode) != MODE_CC ! 1272: || (! flag_fast_math && ! REVERSIBLE_CC_MODE (mode))) 1.1.1.2 root 1273: return FALSE; 1274: } 1.1.1.3 ! root 1275: 1.1.1.2 root 1276: if (mode == GET_MODE (x) && GET_CODE (x) == REG && REGNO (x) == 24) 1277: return TRUE; 1.1.1.3 ! root 1278: 1.1.1.2 root 1279: return FALSE; 1280: } 1.1.1.3 ! root 1281: 1.1.1.2 root 1282: enum rtx_code 1283: minmax_code (x) 1.1.1.3 ! root 1284: rtx x; 1.1.1.2 root 1285: { 1286: enum rtx_code code = GET_CODE (x); 1287: 1288: if (code == SMAX) 1289: return GE; 1.1.1.3 ! root 1290: else if (code == SMIN) 1.1.1.2 root 1291: return LE; 1.1.1.3 ! root 1292: else if (code == UMIN) 1.1.1.2 root 1293: return LEU; 1.1.1.3 ! root 1294: else if (code == UMAX) 1.1.1.2 root 1295: return GEU; 1.1.1.3 ! root 1296: 1.1.1.2 root 1297: abort (); 1298: } 1299: 1300: /* Return 1 if memory locations are adjacent */ 1301: 1.1.1.3 ! root 1302: int 1.1.1.2 root 1303: adjacent_mem_locations (a, b) 1304: rtx a, b; 1305: { 1306: int val0 = 0, val1 = 0; 1307: int reg0, reg1; 1308: 1309: if ((GET_CODE (XEXP (a, 0)) == REG 1310: || (GET_CODE (XEXP (a, 0)) == PLUS 1311: && GET_CODE (XEXP (XEXP (a, 0), 1)) == CONST_INT)) 1312: && (GET_CODE (XEXP (b, 0)) == REG 1313: || (GET_CODE (XEXP (b, 0)) == PLUS 1314: && GET_CODE (XEXP (XEXP (b, 0), 1)) == CONST_INT))) 1315: { 1316: if (GET_CODE (XEXP (a, 0)) == PLUS) 1317: { 1318: reg0 = REGNO (XEXP (XEXP (a, 0), 0)); 1319: val0 = INTVAL (XEXP (XEXP (a, 0), 1)); 1320: } 1321: else 1322: reg0 = REGNO (XEXP (a, 0)); 1323: if (GET_CODE (XEXP (b, 0)) == PLUS) 1324: { 1325: reg1 = REGNO (XEXP (XEXP (b, 0), 0)); 1326: val1 = INTVAL (XEXP (XEXP (b, 0), 1)); 1327: } 1328: else 1329: reg1 = REGNO (XEXP (b, 0)); 1330: return (reg0 == reg1) && ((val1 - val0) == 4 || (val0 - val1) == 4); 1331: } 1332: return 0; 1333: } 1334: 1335: /* Return 1 if OP is a load multiple operation. It is known to be 1336: parallel and the first section will be tested. */ 1337: 1.1.1.3 ! root 1338: int 1.1.1.2 root 1339: load_multiple_operation (op, mode) 1340: rtx op; 1341: enum machine_mode mode; 1342: { 1.1.1.3 ! root 1343: HOST_WIDE_INT count = XVECLEN (op, 0); 1.1.1.2 root 1344: int dest_regno; 1345: rtx src_addr; 1.1.1.3 ! root 1346: HOST_WIDE_INT i = 1, base = 0; 1.1.1.2 root 1347: rtx elt; 1348: 1349: if (count <= 1 1350: || GET_CODE (XVECEXP (op, 0, 0)) != SET) 1351: return 0; 1352: 1353: /* Check to see if this might be a write-back */ 1354: if (GET_CODE (SET_SRC (elt = XVECEXP (op, 0, 0))) == PLUS) 1355: { 1356: i++; 1357: base = 1; 1358: 1359: /* Now check it more carefully */ 1360: if (GET_CODE (SET_DEST (elt)) != REG 1361: || GET_CODE (XEXP (SET_SRC (elt), 0)) != REG 1362: || REGNO (XEXP (SET_SRC (elt), 0)) != REGNO (SET_DEST (elt)) 1363: || GET_CODE (XEXP (SET_SRC (elt), 1)) != CONST_INT 1364: || INTVAL (XEXP (SET_SRC (elt), 1)) != (count - 2) * 4 1365: || GET_CODE (XVECEXP (op, 0, count - 1)) != CLOBBER 1366: || GET_CODE (XEXP (XVECEXP (op, 0, count - 1), 0)) != REG 1367: || REGNO (XEXP (XVECEXP (op, 0, count - 1), 0)) 1368: != REGNO (SET_DEST (elt))) 1369: return 0; 1.1.1.3 ! root 1370: 1.1.1.2 root 1371: count--; 1372: } 1373: 1374: /* Perform a quick check so we don't blow up below. */ 1375: if (count <= i 1376: || GET_CODE (XVECEXP (op, 0, i - 1)) != SET 1377: || GET_CODE (SET_DEST (XVECEXP (op, 0, i - 1))) != REG 1378: || GET_CODE (SET_SRC (XVECEXP (op, 0, i - 1))) != MEM) 1379: return 0; 1380: 1381: dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, i - 1))); 1382: src_addr = XEXP (SET_SRC (XVECEXP (op, 0, i - 1)), 0); 1383: 1384: for (; i < count; i++) 1385: { 1386: rtx elt = XVECEXP (op, 0, i); 1387: 1388: if (GET_CODE (elt) != SET 1389: || GET_CODE (SET_DEST (elt)) != REG 1390: || GET_MODE (SET_DEST (elt)) != SImode 1391: || REGNO (SET_DEST (elt)) != dest_regno + i - base 1392: || GET_CODE (SET_SRC (elt)) != MEM 1393: || GET_MODE (SET_SRC (elt)) != SImode 1394: || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS 1395: || ! rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr) 1396: || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT 1397: || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != (i - base) * 4) 1398: return 0; 1399: } 1400: 1401: return 1; 1402: } 1403: 1404: /* Return 1 if OP is a store multiple operation. It is known to be 1405: parallel and the first section will be tested. */ 1406: 1.1.1.3 ! root 1407: int 1.1.1.2 root 1408: store_multiple_operation (op, mode) 1409: rtx op; 1410: enum machine_mode mode; 1411: { 1.1.1.3 ! root 1412: HOST_WIDE_INT count = XVECLEN (op, 0); 1.1.1.2 root 1413: int src_regno; 1414: rtx dest_addr; 1.1.1.3 ! root 1415: HOST_WIDE_INT i = 1, base = 0; 1.1.1.2 root 1416: rtx elt; 1417: 1418: if (count <= 1 1419: || GET_CODE (XVECEXP (op, 0, 0)) != SET) 1420: return 0; 1421: 1422: /* Check to see if this might be a write-back */ 1423: if (GET_CODE (SET_SRC (elt = XVECEXP (op, 0, 0))) == PLUS) 1424: { 1425: i++; 1426: base = 1; 1427: 1428: /* Now check it more carefully */ 1429: if (GET_CODE (SET_DEST (elt)) != REG 1430: || GET_CODE (XEXP (SET_SRC (elt), 0)) != REG 1431: || REGNO (XEXP (SET_SRC (elt), 0)) != REGNO (SET_DEST (elt)) 1432: || GET_CODE (XEXP (SET_SRC (elt), 1)) != CONST_INT 1433: || INTVAL (XEXP (SET_SRC (elt), 1)) != (count - 2) * 4 1434: || GET_CODE (XVECEXP (op, 0, count - 1)) != CLOBBER 1435: || GET_CODE (XEXP (XVECEXP (op, 0, count - 1), 0)) != REG 1436: || REGNO (XEXP (XVECEXP (op, 0, count - 1), 0)) 1437: != REGNO (SET_DEST (elt))) 1438: return 0; 1.1.1.3 ! root 1439: 1.1.1.2 root 1440: count--; 1441: } 1442: 1443: /* Perform a quick check so we don't blow up below. */ 1444: if (count <= i 1445: || GET_CODE (XVECEXP (op, 0, i - 1)) != SET 1446: || GET_CODE (SET_DEST (XVECEXP (op, 0, i - 1))) != MEM 1447: || GET_CODE (SET_SRC (XVECEXP (op, 0, i - 1))) != REG) 1448: return 0; 1449: 1450: src_regno = REGNO (SET_SRC (XVECEXP (op, 0, i - 1))); 1451: dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, i - 1)), 0); 1452: 1453: for (; i < count; i++) 1454: { 1455: elt = XVECEXP (op, 0, i); 1456: 1457: if (GET_CODE (elt) != SET 1458: || GET_CODE (SET_SRC (elt)) != REG 1459: || GET_MODE (SET_SRC (elt)) != SImode 1460: || REGNO (SET_SRC (elt)) != src_regno + i - base 1461: || GET_CODE (SET_DEST (elt)) != MEM 1462: || GET_MODE (SET_DEST (elt)) != SImode 1463: || GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS 1464: || ! rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr) 1465: || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT 1466: || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != (i - base) * 4) 1467: return 0; 1468: } 1469: 1470: return 1; 1471: } 1.1.1.3 ! root 1472: ! 1473: int ! 1474: multi_register_push (op, mode) ! 1475: rtx op; ! 1476: enum machine_mode mode; ! 1477: { ! 1478: if (GET_CODE (op) != PARALLEL ! 1479: || (GET_CODE (XVECEXP (op, 0, 0)) != SET) ! 1480: || (GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != UNSPEC) ! 1481: || (XINT (SET_SRC (XVECEXP (op, 0, 0)), 1) != 2)) ! 1482: return 0; ! 1483: ! 1484: return 1; ! 1485: } ! 1486: ! 1487: ! 1488: /* Routines for use with attributes */ ! 1489: ! 1490: int ! 1491: const_pool_offset (symbol) ! 1492: rtx symbol; ! 1493: { ! 1494: return get_pool_offset (symbol) - get_pool_size () - get_prologue_size (); ! 1495: } 1.1.1.2 root 1496: 1497: /* Routines for use in generating RTL */ 1498: 1.1.1.3 ! root 1499: rtx ! 1500: arm_gen_load_multiple (base_regno, count, from, up, write_back) 1.1.1.2 root 1501: int base_regno; 1502: int count; 1503: rtx from; 1504: int up; 1505: int write_back; 1506: { 1507: int i = 0, j; 1508: rtx result; 1509: int sign = up ? 1 : -1; 1510: 1511: result = gen_rtx (PARALLEL, VOIDmode, 1512: rtvec_alloc (count + (write_back ? 2 : 0))); 1513: if (write_back) 1.1.1.3 ! root 1514: { 1.1.1.2 root 1515: XVECEXP (result, 0, 0) 1.1.1.3 ! root 1516: = gen_rtx (SET, GET_MODE (from), from, ! 1517: plus_constant (from, count * 4 * sign)); 1.1.1.2 root 1518: i = 1; 1519: count++; 1.1.1.3 ! root 1520: } ! 1521: 1.1.1.2 root 1522: for (j = 0; i < count; i++, j++) 1.1.1.3 ! root 1523: { 1.1.1.2 root 1524: XVECEXP (result, 0, i) 1.1.1.3 ! root 1525: = gen_rtx (SET, VOIDmode, gen_rtx (REG, SImode, base_regno + j), ! 1526: gen_rtx (MEM, SImode, ! 1527: plus_constant (from, j * 4 * sign))); ! 1528: } ! 1529: 1.1.1.2 root 1530: if (write_back) 1531: XVECEXP (result, 0, i) = gen_rtx (CLOBBER, SImode, from); 1532: 1533: return result; 1534: } 1535: 1.1.1.3 ! root 1536: rtx ! 1537: arm_gen_store_multiple (base_regno, count, to, up, write_back) 1.1.1.2 root 1538: int base_regno; 1539: int count; 1540: rtx to; 1541: int up; 1542: int write_back; 1543: { 1544: int i = 0, j; 1545: rtx result; 1546: int sign = up ? 1 : -1; 1547: 1548: result = gen_rtx (PARALLEL, VOIDmode, 1549: rtvec_alloc (count + (write_back ? 2 : 0))); 1550: if (write_back) 1.1.1.3 ! root 1551: { 1.1.1.2 root 1552: XVECEXP (result, 0, 0) 1.1.1.3 ! root 1553: = gen_rtx (SET, GET_MODE (to), to, ! 1554: plus_constant (to, count * 4 * sign)); 1.1.1.2 root 1555: i = 1; 1556: count++; 1.1.1.3 ! root 1557: } ! 1558: 1.1.1.2 root 1559: for (j = 0; i < count; i++, j++) 1.1.1.3 ! root 1560: { 1.1.1.2 root 1561: XVECEXP (result, 0, i) 1.1.1.3 ! root 1562: = gen_rtx (SET, VOIDmode, ! 1563: gen_rtx (MEM, SImode, plus_constant (to, j * 4 * sign)), ! 1564: gen_rtx (REG, SImode, base_regno + j)); ! 1565: } ! 1566: 1.1.1.2 root 1567: if (write_back) 1568: XVECEXP (result, 0, i) = gen_rtx (CLOBBER, SImode, to); 1569: 1570: return result; 1571: } 1572: 1.1.1.3 ! root 1573: int ! 1574: arm_gen_movstrqi (operands) ! 1575: rtx *operands; ! 1576: { ! 1577: HOST_WIDE_INT in_words_to_go, out_words_to_go, last_bytes; ! 1578: int i, r; ! 1579: rtx const_sxteen = gen_rtx (CONST_INT, SImode, 16); ! 1580: rtx src, dst; ! 1581: rtx st_src, st_dst, end_src, end_dst, fin_src, fin_dst; ! 1582: rtx part_bytes_reg = NULL; ! 1583: extern int optimize; ! 1584: ! 1585: if (GET_CODE (operands[2]) != CONST_INT ! 1586: || GET_CODE (operands[3]) != CONST_INT ! 1587: || INTVAL (operands[2]) > 64 ! 1588: || INTVAL (operands[3]) & 3) ! 1589: return 0; ! 1590: ! 1591: st_dst = XEXP (operands[0], 0); ! 1592: st_src = XEXP (operands[1], 0); ! 1593: fin_dst = dst = copy_to_mode_reg (SImode, st_dst); ! 1594: fin_src = src = copy_to_mode_reg (SImode, st_src); ! 1595: ! 1596: in_words_to_go = (INTVAL (operands[2]) + 3) / 4; ! 1597: out_words_to_go = INTVAL (operands[2]) / 4; ! 1598: last_bytes = INTVAL (operands[2]) & 3; ! 1599: ! 1600: if (out_words_to_go != in_words_to_go && ((in_words_to_go - 1) & 3) != 0) ! 1601: part_bytes_reg = gen_rtx (REG, SImode, (in_words_to_go - 1) & 3); ! 1602: ! 1603: for (i = 0; in_words_to_go >= 2; i+=4) ! 1604: { ! 1605: emit_insn (arm_gen_load_multiple (0, (in_words_to_go > 4 ! 1606: ? 4 : in_words_to_go), ! 1607: src, TRUE, TRUE)); ! 1608: if (out_words_to_go) ! 1609: { ! 1610: if (out_words_to_go != 1) ! 1611: emit_insn (arm_gen_store_multiple (0, (out_words_to_go > 4 ! 1612: ? 4 : out_words_to_go), ! 1613: dst, TRUE, TRUE)); ! 1614: else ! 1615: { ! 1616: emit_move_insn (gen_rtx (MEM, SImode, dst), ! 1617: gen_rtx (REG, SImode, 0)); ! 1618: emit_insn (gen_addsi3 (dst, dst, GEN_INT (4))); ! 1619: } ! 1620: } ! 1621: ! 1622: in_words_to_go -= in_words_to_go < 4 ? in_words_to_go : 4; ! 1623: out_words_to_go -= out_words_to_go < 4 ? out_words_to_go : 4; ! 1624: } ! 1625: ! 1626: /* OUT_WORDS_TO_GO will be zero here if there are byte stores to do. */ ! 1627: if (out_words_to_go) ! 1628: { ! 1629: rtx sreg; ! 1630: ! 1631: emit_move_insn (sreg = gen_reg_rtx (SImode), gen_rtx (MEM, SImode, src)); ! 1632: emit_move_insn (fin_src = gen_reg_rtx (SImode), plus_constant (src, 4)); ! 1633: emit_move_insn (gen_rtx (MEM, SImode, dst), sreg); ! 1634: emit_move_insn (fin_dst = gen_reg_rtx (SImode), plus_constant (dst, 4)); ! 1635: in_words_to_go--; ! 1636: ! 1637: if (in_words_to_go) /* Sanity check */ ! 1638: abort (); ! 1639: } ! 1640: ! 1641: if (in_words_to_go) ! 1642: { ! 1643: if (in_words_to_go < 0) ! 1644: abort (); ! 1645: ! 1646: part_bytes_reg = copy_to_mode_reg (SImode, gen_rtx (MEM, SImode, src)); ! 1647: emit_insn (gen_addsi3 (src, src, GEN_INT (4))); ! 1648: } ! 1649: ! 1650: if (BYTES_BIG_ENDIAN && last_bytes) ! 1651: { ! 1652: rtx tmp = gen_reg_rtx (SImode); ! 1653: ! 1654: if (part_bytes_reg == NULL) ! 1655: abort (); ! 1656: ! 1657: /* The bytes we want are in the top end of the word */ ! 1658: emit_insn (gen_lshrsi3 (tmp, part_bytes_reg, ! 1659: GEN_INT (8 * (4 - last_bytes)))); ! 1660: part_bytes_reg = tmp; ! 1661: ! 1662: while (last_bytes) ! 1663: { ! 1664: emit_move_insn (gen_rtx (MEM, QImode, ! 1665: plus_constant (dst, last_bytes - 1)), ! 1666: gen_rtx (SUBREG, QImode, part_bytes_reg, 0)); ! 1667: if (--last_bytes) ! 1668: { ! 1669: tmp = gen_reg_rtx (SImode); ! 1670: emit_insn (gen_lshrsi3 (tmp, part_bytes_reg, GEN_INT (8))); ! 1671: part_bytes_reg = tmp; ! 1672: } ! 1673: } ! 1674: ! 1675: } ! 1676: else ! 1677: { ! 1678: while (last_bytes) ! 1679: { ! 1680: if (part_bytes_reg == NULL) ! 1681: abort (); ! 1682: ! 1683: emit_move_insn (gen_rtx (MEM, QImode, dst), ! 1684: gen_rtx (SUBREG, QImode, part_bytes_reg, 0)); ! 1685: emit_insn (gen_addsi3 (dst, dst, const1_rtx)); ! 1686: if (--last_bytes) ! 1687: { ! 1688: rtx tmp = gen_reg_rtx (SImode); ! 1689: emit_insn (gen_lshrsi3 (tmp, part_bytes_reg, GEN_INT (8))); ! 1690: part_bytes_reg = tmp; ! 1691: } ! 1692: } ! 1693: } ! 1694: ! 1695: return 1; ! 1696: } ! 1697: 1.1.1.2 root 1698: /* X and Y are two things to compare using CODE. Emit the compare insn and 1699: return the rtx for register 0 in the proper mode. FP means this is a 1700: floating point compare: I don't think that it is needed on the arm. */ 1701: 1702: rtx 1703: gen_compare_reg (code, x, y, fp) 1704: enum rtx_code code; 1705: rtx x, y; 1706: { 1707: enum machine_mode mode = SELECT_CC_MODE (code, x, y); 1708: rtx cc_reg = gen_rtx (REG, mode, 24); 1709: 1710: emit_insn (gen_rtx (SET, VOIDmode, cc_reg, 1711: gen_rtx (COMPARE, mode, x, y))); 1712: 1713: return cc_reg; 1714: } 1715: 1.1.1.3 ! root 1716: void ! 1717: arm_reload_in_hi (operands) ! 1718: rtx *operands; ! 1719: { ! 1720: rtx base = find_replacement (&XEXP (operands[1], 0)); ! 1721: ! 1722: emit_insn (gen_zero_extendqisi2 (operands[2], gen_rtx (MEM, QImode, base))); ! 1723: emit_insn (gen_zero_extendqisi2 (gen_rtx (SUBREG, SImode, operands[0], 0), ! 1724: gen_rtx (MEM, QImode, ! 1725: plus_constant (base, 1)))); ! 1726: if (BYTES_BIG_ENDIAN) ! 1727: emit_insn (gen_rtx (SET, VOIDmode, gen_rtx (SUBREG, SImode, ! 1728: operands[0], 0), ! 1729: gen_rtx (IOR, SImode, ! 1730: gen_rtx (ASHIFT, SImode, ! 1731: gen_rtx (SUBREG, SImode, ! 1732: operands[0], 0), ! 1733: GEN_INT (8)), ! 1734: operands[2]))); ! 1735: else ! 1736: emit_insn (gen_rtx (SET, VOIDmode, gen_rtx (SUBREG, SImode, ! 1737: operands[0], 0), ! 1738: gen_rtx (IOR, SImode, ! 1739: gen_rtx (ASHIFT, SImode, ! 1740: operands[2], ! 1741: GEN_INT (8)), ! 1742: gen_rtx (SUBREG, SImode, operands[0], 0)))); ! 1743: } ! 1744: ! 1745: void 1.1.1.2 root 1746: arm_reload_out_hi (operands) 1.1.1.3 ! root 1747: rtx *operands; 1.1.1.2 root 1748: { 1749: rtx base = find_replacement (&XEXP (operands[0], 0)); 1750: 1.1.1.3 ! root 1751: if (BYTES_BIG_ENDIAN) ! 1752: { ! 1753: emit_insn (gen_movqi (gen_rtx (MEM, QImode, plus_constant (base, 1)), ! 1754: gen_rtx (SUBREG, QImode, operands[1], 0))); ! 1755: emit_insn (gen_lshrsi3 (operands[2], ! 1756: gen_rtx (SUBREG, SImode, operands[1], 0), ! 1757: GEN_INT (8))); ! 1758: emit_insn (gen_movqi (gen_rtx (MEM, QImode, base), ! 1759: gen_rtx (SUBREG, QImode, operands[2], 0))); ! 1760: } ! 1761: else ! 1762: { ! 1763: emit_insn (gen_movqi (gen_rtx (MEM, QImode, base), ! 1764: gen_rtx (SUBREG, QImode, operands[1], 0))); ! 1765: emit_insn (gen_lshrsi3 (operands[2], ! 1766: gen_rtx (SUBREG, SImode, operands[1], 0), ! 1767: GEN_INT (8))); ! 1768: emit_insn (gen_movqi (gen_rtx (MEM, QImode, plus_constant (base, 1)), ! 1769: gen_rtx (SUBREG, QImode, operands[2], 0))); ! 1770: } 1.1.1.2 root 1771: } 1772: 1773: /* Check to see if a branch is forwards or backwards. Return TRUE if it 1774: is backwards. */ 1775: 1776: int 1777: arm_backwards_branch (from, to) 1.1.1.3 ! root 1778: int from, to; 1.1.1.2 root 1779: { 1.1.1.3 ! root 1780: return insn_addresses[to] <= insn_addresses[from]; 1.1.1.2 root 1781: } 1782: 1783: /* Check to see if a branch is within the distance that can be done using 1784: an arithmetic expression. */ 1785: int 1786: short_branch (from, to) 1.1.1.3 ! root 1787: int from, to; 1.1.1.2 root 1788: { 1.1.1.3 ! root 1789: int delta = insn_addresses[from] + 8 - insn_addresses[to]; 1.1.1.2 root 1790: 1.1.1.3 ! root 1791: return abs (delta) < 980; /* A small margin for safety */ 1.1.1.2 root 1792: } 1793: 1794: /* Check to see that the insn isn't the target of the conditionalizing 1795: code */ 1796: int 1797: arm_insn_not_targeted (insn) 1.1.1.3 ! root 1798: rtx insn; 1.1.1.2 root 1799: { 1800: return insn != arm_target_insn; 1801: } 1802: 1.1 root 1803: 1804: /* Routines to output assembly language. */ 1805: 1.1.1.3 ! root 1806: /* If the rtx is the correct value then return the string of the number. 1.1.1.2 root 1807: In this way we can ensure that valid double constants are generated even 1808: when cross compiling. */ 1809: char * 1810: fp_immediate_constant (x) 1.1.1.3 ! root 1811: rtx x; 1.1.1.2 root 1812: { 1813: REAL_VALUE_TYPE r; 1814: int i; 1815: 1816: if (!fpa_consts_inited) 1817: init_fpa_table (); 1818: 1819: REAL_VALUE_FROM_CONST_DOUBLE (r, x); 1820: for (i = 0; i < 8; i++) 1821: if (REAL_VALUES_EQUAL (r, values_fpa[i])) 1822: return strings_fpa[i]; 1.1.1.3 ! root 1823: 1.1.1.2 root 1824: abort (); 1825: } 1826: 1.1.1.3 ! root 1827: /* As for fp_immediate_constant, but value is passed directly, not in rtx. */ ! 1828: static char * ! 1829: fp_const_from_val (r) ! 1830: REAL_VALUE_TYPE *r; ! 1831: { ! 1832: int i; ! 1833: ! 1834: if (! fpa_consts_inited) ! 1835: init_fpa_table (); ! 1836: ! 1837: for (i = 0; i < 8; i++) ! 1838: if (REAL_VALUES_EQUAL (*r, values_fpa[i])) ! 1839: return strings_fpa[i]; ! 1840: ! 1841: abort (); ! 1842: } 1.1.1.2 root 1843: 1.1 root 1844: /* Output the operands of a LDM/STM instruction to STREAM. 1845: MASK is the ARM register set mask of which only bits 0-15 are important. 1846: INSTR is the possibly suffixed base register. HAT unequals zero if a hat 1847: must follow the register list. */ 1848: 1849: void 1850: print_multi_reg (stream, instr, mask, hat) 1851: FILE *stream; 1852: char *instr; 1853: int mask, hat; 1854: { 1855: int i; 1856: int not_first = FALSE; 1857: 1.1.1.3 ! root 1858: fputc ('\t', stream); ! 1859: fprintf (stream, instr, ARM_REG_PREFIX); ! 1860: fputs (", {", stream); 1.1 root 1861: for (i = 0; i < 16; i++) 1862: if (mask & (1 << i)) 1863: { 1864: if (not_first) 1865: fprintf (stream, ", "); 1.1.1.3 ! root 1866: fprintf (stream, "%s%s", ARM_REG_PREFIX, reg_names[i]); 1.1 root 1867: not_first = TRUE; 1868: } 1.1.1.3 ! root 1869: 1.1 root 1870: fprintf (stream, "}%s\n", hat ? "^" : ""); 1.1.1.3 ! root 1871: } 1.1 root 1872: 1873: /* Output a 'call' insn. */ 1874: 1875: char * 1876: output_call (operands) 1.1.1.3 ! root 1877: rtx *operands; 1.1 root 1878: { 1879: /* Handle calls to lr using ip (which may be clobbered in subr anyway). */ 1880: 1881: if (REGNO (operands[0]) == 14) 1882: { 1883: operands[0] = gen_rtx (REG, SImode, 12); 1.1.1.3 ! root 1884: output_asm_insn ("mov%?\t%0, %|lr", operands); 1.1 root 1885: } 1.1.1.3 ! root 1886: output_asm_insn ("mov%?\t%|lr, %|pc", operands); ! 1887: output_asm_insn ("mov%?\t%|pc, %0", operands); ! 1888: return ""; ! 1889: } 1.1 root 1890: 1.1.1.2 root 1891: static int 1892: eliminate_lr2ip (x) 1.1.1.3 ! root 1893: rtx *x; 1.1.1.2 root 1894: { 1895: int something_changed = 0; 1896: rtx x0 = *x; 1897: int code = GET_CODE (x0); 1898: register int i, j; 1899: register char *fmt; 1900: 1901: switch (code) 1902: { 1903: case REG: 1904: if (REGNO (x0) == 14) 1905: { 1906: *x = gen_rtx (REG, SImode, 12); 1907: return 1; 1908: } 1909: return 0; 1910: default: 1911: /* Scan through the sub-elements and change any references there */ 1912: fmt = GET_RTX_FORMAT (code); 1913: for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) 1914: if (fmt[i] == 'e') 1915: something_changed |= eliminate_lr2ip (&XEXP (x0, i)); 1916: else if (fmt[i] == 'E') 1917: for (j = 0; j < XVECLEN (x0, i); j++) 1918: something_changed |= eliminate_lr2ip (&XVECEXP (x0, i, j)); 1919: return something_changed; 1920: } 1921: } 1922: 1923: /* Output a 'call' insn that is a reference in memory. */ 1924: 1925: char * 1926: output_call_mem (operands) 1.1.1.3 ! root 1927: rtx *operands; 1.1.1.2 root 1928: { 1929: operands[0] = copy_rtx (operands[0]); /* Be ultra careful */ 1930: /* Handle calls using lr by using ip (which may be clobbered in subr anyway). 1931: */ 1932: if (eliminate_lr2ip (&operands[0])) 1.1.1.3 ! root 1933: output_asm_insn ("mov%?\t%|ip, %|lr", operands); ! 1934: ! 1935: output_asm_insn ("mov%?\t%|lr, %|pc", operands); ! 1936: output_asm_insn ("ldr%?\t%|pc, %0", operands); ! 1937: return ""; ! 1938: } 1.1.1.2 root 1939: 1940: 1941: /* Output a move from arm registers to an fpu registers. 1942: OPERANDS[0] is an fpu register. 1943: OPERANDS[1] is the first registers of an arm register pair. */ 1944: 1945: char * 1946: output_mov_long_double_fpu_from_arm (operands) 1.1.1.3 ! root 1947: rtx *operands; 1.1.1.2 root 1948: { 1949: int arm_reg0 = REGNO (operands[1]); 1950: rtx ops[3]; 1951: 1952: if (arm_reg0 == 12) 1953: abort(); 1.1.1.3 ! root 1954: 1.1.1.2 root 1955: ops[0] = gen_rtx (REG, SImode, arm_reg0); 1956: ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0); 1957: ops[2] = gen_rtx (REG, SImode, 2 + arm_reg0); 1958: 1.1.1.3 ! root 1959: output_asm_insn ("stm%?fd\t%|sp!, {%0, %1, %2}", ops); ! 1960: output_asm_insn ("ldf%?e\t%0, [%|sp], #12", operands); ! 1961: return ""; ! 1962: } 1.1.1.2 root 1963: 1964: /* Output a move from an fpu register to arm registers. 1965: OPERANDS[0] is the first registers of an arm register pair. 1966: OPERANDS[1] is an fpu register. */ 1967: 1968: char * 1969: output_mov_long_double_arm_from_fpu (operands) 1.1.1.3 ! root 1970: rtx *operands; 1.1.1.2 root 1971: { 1972: int arm_reg0 = REGNO (operands[0]); 1973: rtx ops[3]; 1974: 1975: if (arm_reg0 == 12) 1976: abort(); 1.1.1.3 ! root 1977: 1.1.1.2 root 1978: ops[0] = gen_rtx (REG, SImode, arm_reg0); 1979: ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0); 1980: ops[2] = gen_rtx (REG, SImode, 2 + arm_reg0); 1981: 1.1.1.3 ! root 1982: output_asm_insn ("stf%?e\t%1, [%|sp, #-12]!", operands); ! 1983: output_asm_insn ("ldm%?fd\t%|sp!, {%0, %1, %2}", ops); ! 1984: return ""; ! 1985: } 1.1.1.2 root 1986: 1987: /* Output a move from arm registers to arm registers of a long double 1988: OPERANDS[0] is the destination. 1989: OPERANDS[1] is the source. */ 1990: char * 1991: output_mov_long_double_arm_from_arm (operands) 1.1.1.3 ! root 1992: rtx *operands; 1.1.1.2 root 1993: { 1994: /* We have to be careful here because the two might overlap */ 1995: int dest_start = REGNO (operands[0]); 1996: int src_start = REGNO (operands[1]); 1997: rtx ops[2]; 1998: int i; 1999: 2000: if (dest_start < src_start) 2001: { 2002: for (i = 0; i < 3; i++) 2003: { 2004: ops[0] = gen_rtx (REG, SImode, dest_start + i); 2005: ops[1] = gen_rtx (REG, SImode, src_start + i); 1.1.1.3 ! root 2006: output_asm_insn ("mov%?\t%0, %1", ops); 1.1.1.2 root 2007: } 2008: } 2009: else 2010: { 2011: for (i = 2; i >= 0; i--) 2012: { 2013: ops[0] = gen_rtx (REG, SImode, dest_start + i); 2014: ops[1] = gen_rtx (REG, SImode, src_start + i); 1.1.1.3 ! root 2015: output_asm_insn ("mov%?\t%0, %1", ops); 1.1.1.2 root 2016: } 2017: } 1.1.1.3 ! root 2018: 1.1.1.2 root 2019: return ""; 2020: } 2021: 2022: 1.1 root 2023: /* Output a move from arm registers to an fpu registers. 2024: OPERANDS[0] is an fpu register. 2025: OPERANDS[1] is the first registers of an arm register pair. */ 2026: 2027: char * 2028: output_mov_double_fpu_from_arm (operands) 1.1.1.3 ! root 2029: rtx *operands; 1.1 root 2030: { 2031: int arm_reg0 = REGNO (operands[1]); 2032: rtx ops[2]; 2033: 2034: if (arm_reg0 == 12) 2035: abort(); 2036: ops[0] = gen_rtx (REG, SImode, arm_reg0); 2037: ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0); 1.1.1.3 ! root 2038: output_asm_insn ("stm%?fd\t%|sp!, {%0, %1}", ops); ! 2039: output_asm_insn ("ldf%?d\t%0, [%|sp], #8", operands); ! 2040: return ""; ! 2041: } 1.1 root 2042: 2043: /* Output a move from an fpu register to arm registers. 2044: OPERANDS[0] is the first registers of an arm register pair. 2045: OPERANDS[1] is an fpu register. */ 2046: 2047: char * 2048: output_mov_double_arm_from_fpu (operands) 1.1.1.3 ! root 2049: rtx *operands; 1.1 root 2050: { 2051: int arm_reg0 = REGNO (operands[0]); 2052: rtx ops[2]; 2053: 2054: if (arm_reg0 == 12) 2055: abort(); 1.1.1.3 ! root 2056: 1.1 root 2057: ops[0] = gen_rtx (REG, SImode, arm_reg0); 2058: ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0); 1.1.1.3 ! root 2059: output_asm_insn ("stf%?d\t%1, [%|sp, #-8]!", operands); ! 2060: output_asm_insn ("ldm%?fd\t%|sp!, {%0, %1}", ops); ! 2061: return ""; ! 2062: } 1.1 root 2063: 2064: /* Output a move between double words. 2065: It must be REG<-REG, REG<-CONST_DOUBLE, REG<-CONST_INT, REG<-MEM 2066: or MEM<-REG and all MEMs must be offsettable addresses. */ 2067: 2068: char * 2069: output_move_double (operands) 1.1.1.3 ! root 2070: rtx *operands; 1.1 root 2071: { 2072: enum rtx_code code0 = GET_CODE (operands[0]); 2073: enum rtx_code code1 = GET_CODE (operands[1]); 2074: rtx otherops[2]; 2075: 2076: if (code0 == REG) 2077: { 2078: int reg0 = REGNO (operands[0]); 2079: 2080: otherops[0] = gen_rtx (REG, SImode, 1 + reg0); 2081: if (code1 == REG) 2082: { 2083: int reg1 = REGNO (operands[1]); 2084: if (reg1 == 12) 2085: abort(); 1.1.1.3 ! root 2086: 1.1 root 2087: otherops[1] = gen_rtx (REG, SImode, 1 + reg1); 2088: 2089: /* Ensure the second source is not overwritten */ 2090: if (reg0 == 1 + reg1) 2091: { 1.1.1.3 ! root 2092: output_asm_insn("mov%?\t%0, %1", otherops); ! 2093: output_asm_insn("mov%?\t%0, %1", operands); 1.1 root 2094: } 2095: else 2096: { 1.1.1.3 ! root 2097: output_asm_insn("mov%?\t%0, %1", operands); ! 2098: output_asm_insn("mov%?\t%0, %1", otherops); 1.1 root 2099: } 2100: } 2101: else if (code1 == CONST_DOUBLE) 2102: { 2103: otherops[1] = gen_rtx (CONST_INT, VOIDmode, 2104: CONST_DOUBLE_HIGH (operands[1])); 2105: operands[1] = gen_rtx (CONST_INT, VOIDmode, 2106: CONST_DOUBLE_LOW (operands[1])); 1.1.1.2 root 2107: output_mov_immediate (operands, FALSE, ""); 2108: output_mov_immediate (otherops, FALSE, ""); 1.1 root 2109: } 2110: else if (code1 == CONST_INT) 2111: { 2112: otherops[1] = const0_rtx; 1.1.1.2 root 2113: /* sign extend the intval into the high-order word */ 2114: /* Note: output_mov_immediate may clobber operands[1], so we 2115: put this out first */ 2116: if (INTVAL (operands[1]) < 0) 1.1.1.3 ! root 2117: output_asm_insn ("mvn%?\t%0, %1", otherops); 1.1.1.2 root 2118: else 1.1.1.3 ! root 2119: output_asm_insn ("mov%?\t%0, %1", otherops); 1.1.1.2 root 2120: output_mov_immediate (operands, FALSE, ""); 1.1 root 2121: } 2122: else if (code1 == MEM) 2123: { 1.1.1.2 root 2124: switch (GET_CODE (XEXP (operands[1], 0))) 1.1 root 2125: { 1.1.1.2 root 2126: case REG: 1.1 root 2127: /* Handle the simple case where address is [r, #0] more 2128: efficient. */ 1.1.1.3 ! root 2129: output_asm_insn ("ldm%?ia\t%m1, %M0", operands); 1.1.1.2 root 2130: break; 2131: case PRE_INC: 1.1.1.3 ! root 2132: output_asm_insn ("add%?\t%m1, %m1, #8", operands); ! 2133: output_asm_insn ("ldm%?ia\t%m1, %M0", operands); 1.1.1.2 root 2134: break; 2135: case PRE_DEC: 1.1.1.3 ! root 2136: output_asm_insn ("sub%?\t%m1, %m1, #8", operands); ! 2137: output_asm_insn ("ldm%?ia\t%m1, %M0", operands); 1.1.1.2 root 2138: break; 2139: case POST_INC: 1.1.1.3 ! root 2140: output_asm_insn ("ldm%?ia\t%m1!, %M0", operands); 1.1.1.2 root 2141: break; 2142: case POST_DEC: 1.1.1.3 ! root 2143: output_asm_insn ("ldm%?ia\t%m1, %M0", operands); ! 2144: output_asm_insn ("sub%?\t%m1, %m1, #8", operands); 1.1.1.2 root 2145: break; 2146: default: 1.1 root 2147: otherops[1] = adj_offsettable_operand (operands[1], 4); 2148: /* Take care of overlapping base/data reg. */ 2149: if (reg_mentioned_p (operands[0], operands[1])) 2150: { 1.1.1.3 ! root 2151: output_asm_insn ("ldr%?\t%0, %1", otherops); ! 2152: output_asm_insn ("ldr%?\t%0, %1", operands); 1.1 root 2153: } 2154: else 2155: { 1.1.1.3 ! root 2156: output_asm_insn ("ldr%?\t%0, %1", operands); ! 2157: output_asm_insn ("ldr%?\t%0, %1", otherops); 1.1 root 2158: } 2159: } 2160: } 2161: else abort(); /* Constraints should prevent this */ 2162: } 2163: else if (code0 == MEM && code1 == REG) 2164: { 2165: if (REGNO (operands[1]) == 12) 2166: abort(); 1.1.1.2 root 2167: switch (GET_CODE (XEXP (operands[0], 0))) 2168: { 2169: case REG: 1.1.1.3 ! root 2170: output_asm_insn ("stm%?ia\t%m0, %M1", operands); 1.1.1.2 root 2171: break; 2172: case PRE_INC: 1.1.1.3 ! root 2173: output_asm_insn ("add%?\t%m0, %m0, #8", operands); ! 2174: output_asm_insn ("stm%?ia\t%m0, %M1", operands); 1.1.1.2 root 2175: break; 2176: case PRE_DEC: 1.1.1.3 ! root 2177: output_asm_insn ("sub%?\t%m0, %m0, #8", operands); ! 2178: output_asm_insn ("stm%?ia\t%m0, %M1", operands); 1.1.1.2 root 2179: break; 2180: case POST_INC: 1.1.1.3 ! root 2181: output_asm_insn ("stm%?ia\t%m0!, %M1", operands); 1.1.1.2 root 2182: break; 2183: case POST_DEC: 1.1.1.3 ! root 2184: output_asm_insn ("stm%?ia\t%m0, %M1", operands); ! 2185: output_asm_insn ("sub%?\t%m0, %m0, #8", operands); 1.1.1.2 root 2186: break; 2187: default: 1.1 root 2188: otherops[0] = adj_offsettable_operand (operands[0], 4); 2189: otherops[1] = gen_rtx (REG, SImode, 1 + REGNO (operands[1])); 1.1.1.3 ! root 2190: output_asm_insn ("str%?\t%1, %0", operands); ! 2191: output_asm_insn ("str%?\t%1, %0", otherops); 1.1 root 2192: } 2193: } 2194: else abort(); /* Constraints should prevent this */ 2195: 1.1.1.3 ! root 2196: return ""; ! 2197: } 1.1 root 2198: 2199: 2200: /* Output an arbitrary MOV reg, #n. 2201: OPERANDS[0] is a register. OPERANDS[1] is a const_int. */ 2202: 2203: char * 2204: output_mov_immediate (operands) 1.1.1.3 ! root 2205: rtx *operands; 1.1 root 2206: { 1.1.1.3 ! root 2207: HOST_WIDE_INT n = INTVAL (operands[1]); 1.1 root 2208: int n_ones = 0; 2209: int i; 2210: 2211: /* Try to use one MOV */ 2212: if (const_ok_for_arm (n)) 1.1.1.3 ! root 2213: { ! 2214: output_asm_insn ("mov%?\t%0, %1", operands); ! 2215: return ""; ! 2216: } 1.1 root 2217: 2218: /* Try to use one MVN */ 1.1.1.3 ! root 2219: if (const_ok_for_arm (~n)) 1.1 root 2220: { 1.1.1.3 ! root 2221: operands[1] = GEN_INT (~n); ! 2222: output_asm_insn ("mvn%?\t%0, %1", operands); ! 2223: return ""; 1.1 root 2224: } 2225: 2226: /* If all else fails, make it out of ORRs or BICs as appropriate. */ 2227: 2228: for (i=0; i < 32; i++) 2229: if (n & 1 << i) 2230: n_ones++; 2231: 2232: if (n_ones > 16) /* Shorter to use MVN with BIC in this case. */ 1.1.1.3 ! root 2233: output_multi_immediate(operands, "mvn%?\t%0, %1", "bic%?\t%0, %0, %1", 1, ! 2234: ~n); 1.1 root 2235: else 1.1.1.3 ! root 2236: output_multi_immediate(operands, "mov%?\t%0, %1", "orr%?\t%0, %0, %1", 1, ! 2237: n); ! 2238: ! 2239: return ""; ! 2240: } 1.1 root 2241: 2242: 2243: /* Output an ADD r, s, #n where n may be too big for one instruction. If 2244: adding zero to one register, output nothing. */ 2245: 2246: char * 2247: output_add_immediate (operands) 1.1.1.3 ! root 2248: rtx *operands; 1.1 root 2249: { 1.1.1.3 ! root 2250: HOST_WIDE_INT n = INTVAL (operands[2]); 1.1 root 2251: 2252: if (n != 0 || REGNO (operands[0]) != REGNO (operands[1])) 2253: { 2254: if (n < 0) 2255: output_multi_immediate (operands, 1.1.1.3 ! root 2256: "sub%?\t%0, %1, %2", "sub%?\t%0, %0, %2", 2, ! 2257: -n); 1.1 root 2258: else 2259: output_multi_immediate (operands, 1.1.1.3 ! root 2260: "add%?\t%0, %1, %2", "add%?\t%0, %0, %2", 2, ! 2261: n); 1.1 root 2262: } 2263: 1.1.1.3 ! root 2264: return ""; ! 2265: } 1.1 root 2266: 2267: /* Output a multiple immediate operation. 2268: OPERANDS is the vector of operands referred to in the output patterns. 2269: INSTR1 is the output pattern to use for the first constant. 2270: INSTR2 is the output pattern to use for subsequent constants. 2271: IMMED_OP is the index of the constant slot in OPERANDS. 2272: N is the constant value. */ 2273: 2274: char * 2275: output_multi_immediate (operands, instr1, instr2, immed_op, n) 1.1.1.3 ! root 2276: rtx *operands; 1.1 root 2277: char *instr1, *instr2; 1.1.1.3 ! root 2278: int immed_op; ! 2279: HOST_WIDE_INT n; 1.1 root 2280: { 1.1.1.3 ! root 2281: #if HOST_BITS_PER_WIDE_INT > 32 ! 2282: n &= 0xffffffff; ! 2283: #endif ! 2284: 1.1 root 2285: if (n == 0) 2286: { 2287: operands[immed_op] = const0_rtx; 1.1.1.3 ! root 2288: output_asm_insn (instr1, operands); /* Quick and easy output */ 1.1 root 2289: } 2290: else 2291: { 2292: int i; 2293: char *instr = instr1; 2294: 2295: /* Note that n is never zero here (which would give no output) */ 2296: for (i = 0; i < 32; i += 2) 2297: { 2298: if (n & (3 << i)) 2299: { 1.1.1.3 ! root 2300: operands[immed_op] = GEN_INT (n & (255 << i)); ! 2301: output_asm_insn (instr, operands); 1.1 root 2302: instr = instr2; 2303: i += 6; 2304: } 2305: } 2306: } 1.1.1.3 ! root 2307: return ""; ! 2308: } 1.1 root 2309: 2310: 2311: /* Return the appropriate ARM instruction for the operation code. 2312: The returned result should not be overwritten. OP is the rtx of the 2313: operation. SHIFT_FIRST_ARG is TRUE if the first argument of the operator 2314: was shifted. */ 2315: 2316: char * 2317: arithmetic_instr (op, shift_first_arg) 2318: rtx op; 1.1.1.3 ! root 2319: int shift_first_arg; 1.1 root 2320: { 1.1.1.3 ! root 2321: switch (GET_CODE (op)) 1.1 root 2322: { 2323: case PLUS: 1.1.1.3 ! root 2324: return "add"; ! 2325: 1.1 root 2326: case MINUS: 1.1.1.3 ! root 2327: return shift_first_arg ? "rsb" : "sub"; ! 2328: 1.1 root 2329: case IOR: 1.1.1.3 ! root 2330: return "orr"; ! 2331: 1.1 root 2332: case XOR: 1.1.1.3 ! root 2333: return "eor"; ! 2334: 1.1 root 2335: case AND: 1.1.1.3 ! root 2336: return "and"; ! 2337: 1.1 root 2338: default: 1.1.1.3 ! root 2339: abort (); 1.1 root 2340: } 1.1.1.3 ! root 2341: } 1.1 root 2342: 2343: 2344: /* Ensure valid constant shifts and return the appropriate shift mnemonic 2345: for the operation code. The returned result should not be overwritten. 2346: OP is the rtx code of the shift. 1.1.1.3 ! root 2347: On exit, *AMOUNTP will be -1 if the shift is by a register, or a constant ! 2348: shift. */ 1.1 root 2349: 1.1.1.3 ! root 2350: static char * ! 2351: shift_op (op, amountp) ! 2352: rtx op; ! 2353: HOST_WIDE_INT *amountp; 1.1 root 2354: { 2355: char *mnem; 1.1.1.3 ! root 2356: enum rtx_code code = GET_CODE (op); 1.1 root 2357: 1.1.1.3 ! root 2358: if (GET_CODE (XEXP (op, 1)) == REG || GET_CODE (XEXP (op, 1)) == SUBREG) ! 2359: *amountp = -1; ! 2360: else if (GET_CODE (XEXP (op, 1)) == CONST_INT) ! 2361: *amountp = INTVAL (XEXP (op, 1)); ! 2362: else ! 2363: abort (); ! 2364: ! 2365: switch (code) 1.1 root 2366: { 2367: case ASHIFT: 2368: mnem = "asl"; 2369: break; 1.1.1.3 ! root 2370: 1.1 root 2371: case ASHIFTRT: 2372: mnem = "asr"; 2373: break; 1.1.1.3 ! root 2374: 1.1 root 2375: case LSHIFTRT: 2376: mnem = "lsr"; 2377: break; 1.1.1.3 ! root 2378: ! 2379: case ROTATERT: ! 2380: mnem = "ror"; ! 2381: break; ! 2382: 1.1.1.2 root 2383: case MULT: 1.1.1.3 ! root 2384: /* We never have to worry about the amount being other than a ! 2385: power of 2, since this case can never be reloaded from a reg. */ ! 2386: if (*amountp != -1) ! 2387: *amountp = int_log2 (*amountp); ! 2388: else ! 2389: abort (); ! 2390: return "asl"; ! 2391: 1.1 root 2392: default: 1.1.1.3 ! root 2393: abort (); 1.1 root 2394: } 2395: 1.1.1.3 ! root 2396: if (*amountp != -1) 1.1 root 2397: { 1.1.1.3 ! root 2398: /* This is not 100% correct, but follows from the desire to merge ! 2399: multiplication by a power of 2 with the recognizer for a ! 2400: shift. >=32 is not a valid shift for "asl", so we must try and ! 2401: output a shift that produces the correct arithmetical result. ! 2402: Using lsr #32 is idendical except for the fact that the carry bit ! 2403: is not set correctly if we set the flags; but we never use the ! 2404: carry bit from such an operation, so we can ignore that. */ ! 2405: if (code == ROTATERT) ! 2406: *amountp &= 31; /* Rotate is just modulo 32 */ ! 2407: else if (*amountp != (*amountp & 31)) ! 2408: { ! 2409: if (code == ASHIFT) ! 2410: mnem = "lsr"; ! 2411: *amountp = 32; ! 2412: } 1.1 root 2413: 1.1.1.3 ! root 2414: /* Shifts of 0 are no-ops. */ ! 2415: if (*amountp == 0) ! 2416: return NULL; ! 2417: } ! 2418: ! 2419: return mnem; ! 2420: } 1.1 root 2421: 2422: 2423: /* Obtain the shift from the POWER of two. */ 2424: 1.1.1.3 ! root 2425: HOST_WIDE_INT 1.1 root 2426: int_log2 (power) 1.1.1.3 ! root 2427: HOST_WIDE_INT power; 1.1 root 2428: { 1.1.1.3 ! root 2429: HOST_WIDE_INT shift = 0; 1.1 root 2430: 2431: while (((1 << shift) & power) == 0) 2432: { 2433: if (shift > 31) 1.1.1.3 ! root 2434: abort (); 1.1 root 2435: shift++; 2436: } 2437: 1.1.1.3 ! root 2438: return shift; ! 2439: } 1.1 root 2440: 2441: /* Output a .ascii pseudo-op, keeping track of lengths. This is because 2442: /bin/as is horribly restrictive. */ 2443: 2444: void 2445: output_ascii_pseudo_op (stream, p, len) 2446: FILE *stream; 1.1.1.2 root 2447: unsigned char *p; 1.1 root 2448: int len; 2449: { 2450: int i; 2451: int len_so_far = 1000; 2452: int chars_so_far = 0; 2453: 2454: for (i = 0; i < len; i++) 2455: { 2456: register int c = p[i]; 2457: 2458: if (len_so_far > 50) 2459: { 2460: if (chars_so_far) 2461: fputs ("\"\n", stream); 2462: fputs ("\t.ascii\t\"", stream); 2463: len_so_far = 0; 2464: arm_increase_location (chars_so_far); 2465: chars_so_far = 0; 2466: } 2467: 2468: if (c == '\"' || c == '\\') 2469: { 2470: putc('\\', stream); 2471: len_so_far++; 2472: } 1.1.1.3 ! root 2473: 1.1 root 2474: if (c >= ' ' && c < 0177) 2475: { 2476: putc (c, stream); 2477: len_so_far++; 2478: } 2479: else 2480: { 2481: fprintf (stream, "\\%03o", c); 2482: len_so_far +=4; 2483: } 1.1.1.3 ! root 2484: 1.1 root 2485: chars_so_far++; 2486: } 1.1.1.3 ! root 2487: 1.1 root 2488: fputs ("\"\n", stream); 2489: arm_increase_location (chars_so_far); 1.1.1.3 ! root 2490: } 1.1 root 2491: 1.1.1.2 root 2492: 2493: /* Try to determine whether a pattern really clobbers the link register. 2494: This information is useful when peepholing, so that lr need not be pushed 2495: if we combine a call followed by a return. 2496: NOTE: This code does not check for side-effect expressions in a SET_SRC: 2497: such a check should not be needed because these only update an existing 2498: value within a register; the register must still be set elsewhere within 2499: the function. */ 2500: 2501: static int 2502: pattern_really_clobbers_lr (x) 1.1.1.3 ! root 2503: rtx x; 1.1.1.2 root 2504: { 2505: int i; 2506: 2507: switch (GET_CODE (x)) 2508: { 2509: case SET: 2510: switch (GET_CODE (SET_DEST (x))) 2511: { 2512: case REG: 2513: return REGNO (SET_DEST (x)) == 14; 1.1.1.3 ! root 2514: 1.1.1.2 root 2515: case SUBREG: 2516: if (GET_CODE (XEXP (SET_DEST (x), 0)) == REG) 2517: return REGNO (XEXP (SET_DEST (x), 0)) == 14; 1.1.1.3 ! root 2518: 1.1.1.2 root 2519: if (GET_CODE (XEXP (SET_DEST (x), 0)) == MEM) 2520: return 0; 2521: abort (); 1.1.1.3 ! root 2522: 1.1.1.2 root 2523: default: 2524: return 0; 2525: } 1.1.1.3 ! root 2526: 1.1.1.2 root 2527: case PARALLEL: 2528: for (i = 0; i < XVECLEN (x, 0); i++) 2529: if (pattern_really_clobbers_lr (XVECEXP (x, 0, i))) 2530: return 1; 2531: return 0; 1.1.1.3 ! root 2532: 1.1.1.2 root 2533: case CLOBBER: 2534: switch (GET_CODE (XEXP (x, 0))) 2535: { 2536: case REG: 2537: return REGNO (XEXP (x, 0)) == 14; 1.1.1.3 ! root 2538: 1.1.1.2 root 2539: case SUBREG: 2540: if (GET_CODE (XEXP (XEXP (x, 0), 0)) == REG) 2541: return REGNO (XEXP (XEXP (x, 0), 0)) == 14; 2542: abort (); 1.1.1.3 ! root 2543: 1.1.1.2 root 2544: default: 2545: return 0; 2546: } 1.1.1.3 ! root 2547: 1.1.1.2 root 2548: case UNSPEC: 2549: return 1; 1.1.1.3 ! root 2550: 1.1.1.2 root 2551: default: 2552: return 0; 2553: } 2554: } 2555: 2556: static int 2557: function_really_clobbers_lr (first) 1.1.1.3 ! root 2558: rtx first; 1.1.1.2 root 2559: { 2560: rtx insn, next; 2561: 2562: for (insn = first; insn; insn = next_nonnote_insn (insn)) 2563: { 2564: switch (GET_CODE (insn)) 2565: { 2566: case BARRIER: 2567: case NOTE: 2568: case CODE_LABEL: 2569: case JUMP_INSN: /* Jump insns only change the PC (and conds) */ 2570: case INLINE_HEADER: 2571: break; 1.1.1.3 ! root 2572: 1.1.1.2 root 2573: case INSN: 2574: if (pattern_really_clobbers_lr (PATTERN (insn))) 2575: return 1; 2576: break; 1.1.1.3 ! root 2577: 1.1.1.2 root 2578: case CALL_INSN: 2579: /* Don't yet know how to handle those calls that are not to a 2580: SYMBOL_REF */ 2581: if (GET_CODE (PATTERN (insn)) != PARALLEL) 2582: abort (); 1.1.1.3 ! root 2583: 1.1.1.2 root 2584: switch (GET_CODE (XVECEXP (PATTERN (insn), 0, 0))) 2585: { 2586: case CALL: 2587: if (GET_CODE (XEXP (XEXP (XVECEXP (PATTERN (insn), 0, 0), 0), 0)) 2588: != SYMBOL_REF) 2589: return 1; 2590: break; 1.1.1.3 ! root 2591: 1.1.1.2 root 2592: case SET: 2593: if (GET_CODE (XEXP (XEXP (SET_SRC (XVECEXP (PATTERN (insn), 2594: 0, 0)), 0), 0)) 2595: != SYMBOL_REF) 2596: return 1; 2597: break; 1.1.1.3 ! root 2598: 1.1.1.2 root 2599: default: /* Don't recognize it, be safe */ 2600: return 1; 2601: } 1.1.1.3 ! root 2602: 1.1.1.2 root 2603: /* A call can be made (by peepholing) not to clobber lr iff it is 2604: followed by a return. There may, however, be a use insn iff 2605: we are returning the result of the call. 2606: If we run off the end of the insn chain, then that means the 2607: call was at the end of the function. Unfortunately we don't 2608: have a return insn for the peephole to recognize, so we 2609: must reject this. (Can this be fixed by adding our own insn?) */ 2610: if ((next = next_nonnote_insn (insn)) == NULL) 2611: return 1; 1.1.1.3 ! root 2612: 1.1.1.2 root 2613: if (GET_CODE (next) == INSN && GET_CODE (PATTERN (next)) == USE 2614: && (GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET) 2615: && (REGNO (SET_DEST (XVECEXP (PATTERN (insn), 0, 0))) 2616: == REGNO (XEXP (PATTERN (next), 0)))) 2617: if ((next = next_nonnote_insn (next)) == NULL) 2618: return 1; 1.1.1.3 ! root 2619: 1.1.1.2 root 2620: if (GET_CODE (next) == JUMP_INSN 2621: && GET_CODE (PATTERN (next)) == RETURN) 2622: break; 2623: return 1; 1.1.1.3 ! root 2624: 1.1.1.2 root 2625: default: 2626: abort (); 2627: } 2628: } 1.1.1.3 ! root 2629: 1.1.1.2 root 2630: /* We have reached the end of the chain so lr was _not_ clobbered */ 2631: return 0; 2632: } 2633: 2634: char * 2635: output_return_instruction (operand, really_return) 1.1.1.3 ! root 2636: rtx operand; ! 2637: int really_return; 1.1.1.2 root 2638: { 2639: char instr[100]; 2640: int reg, live_regs = 0; 1.1.1.3 ! root 2641: int volatile_func = (optimize > 0 ! 2642: && TREE_THIS_VOLATILE (current_function_decl)); ! 2643: ! 2644: return_used_this_function = 1; 1.1.1.2 root 2645: 1.1.1.3 ! root 2646: if (volatile_func) ! 2647: { ! 2648: rtx ops[2]; ! 2649: /* If this function was declared non-returning, and we have found a tail ! 2650: call, then we have to trust that the called function won't return. */ ! 2651: if (! really_return) ! 2652: return ""; ! 2653: ! 2654: /* Otherwise, trap an attempted return by aborting. */ ! 2655: ops[0] = operand; ! 2656: ops[1] = gen_rtx (SYMBOL_REF, Pmode, "abort"); ! 2657: output_asm_insn ("bl%d0\t%a1", ops); ! 2658: return ""; ! 2659: } ! 2660: ! 2661: if (current_function_calls_alloca && ! really_return) 1.1.1.2 root 2662: abort(); 2663: 1.1.1.3 ! root 2664: for (reg = 0; reg <= 10; reg++) ! 2665: if (regs_ever_live[reg] && ! call_used_regs[reg]) 1.1.1.2 root 2666: live_regs++; 2667: 1.1.1.3 ! root 2668: if (live_regs || (regs_ever_live[14] && ! lr_save_eliminated)) 1.1.1.2 root 2669: live_regs++; 2670: 2671: if (frame_pointer_needed) 2672: live_regs += 4; 2673: 2674: if (live_regs) 2675: { 1.1.1.3 ! root 2676: if (lr_save_eliminated || ! regs_ever_live[14]) 1.1.1.2 root 2677: live_regs++; 1.1.1.3 ! root 2678: 1.1.1.2 root 2679: if (frame_pointer_needed) 1.1.1.3 ! root 2680: strcpy (instr, "ldm%?%d0ea\t%|fp, {"); 1.1.1.2 root 2681: else 1.1.1.3 ! root 2682: strcpy (instr, "ldm%?%d0fd\t%|sp!, {"); ! 2683: ! 2684: for (reg = 0; reg <= 10; reg++) ! 2685: if (regs_ever_live[reg] && ! call_used_regs[reg]) 1.1.1.2 root 2686: { 1.1.1.3 ! root 2687: strcat (instr, "%|"); 1.1.1.2 root 2688: strcat (instr, reg_names[reg]); 2689: if (--live_regs) 2690: strcat (instr, ", "); 2691: } 1.1.1.3 ! root 2692: 1.1.1.2 root 2693: if (frame_pointer_needed) 2694: { 1.1.1.3 ! root 2695: strcat (instr, "%|"); 1.1.1.2 root 2696: strcat (instr, reg_names[11]); 2697: strcat (instr, ", "); 1.1.1.3 ! root 2698: strcat (instr, "%|"); 1.1.1.2 root 2699: strcat (instr, reg_names[13]); 2700: strcat (instr, ", "); 1.1.1.3 ! root 2701: strcat (instr, "%|"); 1.1.1.2 root 2702: strcat (instr, really_return ? reg_names[15] : reg_names[14]); 2703: } 2704: else 1.1.1.3 ! root 2705: { ! 2706: strcat (instr, "%|"); ! 2707: strcat (instr, really_return ? reg_names[15] : reg_names[14]); ! 2708: } 1.1.1.2 root 2709: strcat (instr, (TARGET_6 || !really_return) ? "}" : "}^"); 1.1.1.3 ! root 2710: output_asm_insn (instr, &operand); 1.1.1.2 root 2711: } 2712: else if (really_return) 2713: { 1.1.1.3 ! root 2714: strcpy (instr, ! 2715: TARGET_6 ? "mov%?%d0\t%|pc, lr" : "mov%?%d0s\t%|pc, %|lr"); ! 2716: output_asm_insn (instr, &operand); 1.1.1.2 root 2717: } 1.1.1.3 ! root 2718: 1.1.1.2 root 2719: return ""; 2720: } 2721: 1.1.1.3 ! root 2722: int ! 2723: arm_volatile_func () ! 2724: { ! 2725: return (optimize > 0 && TREE_THIS_VOLATILE (current_function_decl)); ! 2726: } ! 2727: ! 2728: /* Return the size of the prologue. It's not too bad if we slightly ! 2729: over-estimate. */ ! 2730: ! 2731: static int ! 2732: get_prologue_size () ! 2733: { ! 2734: return profile_flag ? 12 : 0; ! 2735: } ! 2736: 1.1.1.2 root 2737: /* The amount of stack adjustment that happens here, in output_return and in 2738: output_epilogue must be exactly the same as was calculated during reload, 2739: or things will point to the wrong place. The only time we can safely 2740: ignore this constraint is when a function has no arguments on the stack, 2741: no stack frame requirement and no live registers execpt for `lr'. If we 2742: can guarantee that by making all function calls into tail calls and that 2743: lr is not clobbered in any other way, then there is no need to push lr 2744: onto the stack. */ 2745: 1.1 root 2746: void 1.1.1.3 ! root 2747: output_func_prologue (f, frame_size) 1.1 root 2748: FILE *f; 2749: int frame_size; 2750: { 1.1.1.3 ! root 2751: int reg, live_regs_mask = 0; 1.1 root 2752: rtx operands[3]; 1.1.1.3 ! root 2753: int volatile_func = (optimize > 0 ! 2754: && TREE_THIS_VOLATILE (current_function_decl)); 1.1 root 2755: 2756: /* Nonzero if we must stuff some register arguments onto the stack as if 2757: they were passed there. */ 2758: int store_arg_regs = 0; 2759: 1.1.1.2 root 2760: if (arm_ccfsm_state || arm_target_insn) 2761: abort (); /* Sanity check */ 2762: 2763: return_used_this_function = 0; 2764: lr_save_eliminated = 0; 2765: 1.1.1.3 ! root 2766: fprintf (f, "\t%c args = %d, pretend = %d, frame = %d\n", ! 2767: ARM_COMMENT_CHAR, current_function_args_size, ! 2768: current_function_pretend_args_size, frame_size); ! 2769: fprintf (f, "\t%c frame_needed = %d, current_function_anonymous_args = %d\n", ! 2770: ARM_COMMENT_CHAR, frame_pointer_needed, ! 2771: current_function_anonymous_args); ! 2772: ! 2773: if (volatile_func) ! 2774: fprintf (f, "\t%c Volatile function.\n", ARM_COMMENT_CHAR); 1.1 root 2775: 2776: if (current_function_anonymous_args && current_function_pretend_args_size) 2777: store_arg_regs = 1; 2778: 1.1.1.3 ! root 2779: for (reg = 0; reg <= 10; reg++) ! 2780: if (regs_ever_live[reg] && ! call_used_regs[reg]) 1.1 root 2781: live_regs_mask |= (1 << reg); 2782: 1.1.1.2 root 2783: if (frame_pointer_needed) 1.1.1.3 ! root 2784: live_regs_mask |= 0xD800; 1.1 root 2785: else if (regs_ever_live[14]) 1.1.1.2 root 2786: { 2787: if (! current_function_args_size 1.1.1.3 ! root 2788: && ! function_really_clobbers_lr (get_insns ())) ! 2789: lr_save_eliminated = 1; 1.1.1.2 root 2790: else 2791: live_regs_mask |= 0x4000; 2792: } 1.1 root 2793: 2794: if (live_regs_mask) 2795: { 1.1.1.2 root 2796: /* if a di mode load/store multiple is used, and the base register 2797: is r3, then r4 can become an ever live register without lr 2798: doing so, in this case we need to push lr as well, or we 2799: will fail to get a proper return. */ 2800: 2801: live_regs_mask |= 0x4000; 2802: lr_save_eliminated = 0; 1.1 root 2803: 2804: } 2805: 1.1.1.3 ! root 2806: if (lr_save_eliminated) ! 2807: fprintf (f,"\t%c I don't think this function clobbers lr\n", ! 2808: ARM_COMMENT_CHAR); ! 2809: } 1.1 root 2810: 2811: 2812: void 1.1.1.3 ! root 2813: output_func_epilogue (f, frame_size) 1.1 root 2814: FILE *f; 2815: int frame_size; 2816: { 1.1.1.2 root 2817: int reg, live_regs_mask = 0, code_size = 0; 2818: /* If we need this then it will always be at lesat this much */ 2819: int floats_offset = 24; 1.1 root 2820: rtx operands[3]; 1.1.1.3 ! root 2821: int volatile_func = (optimize > 0 ! 2822: && TREE_THIS_VOLATILE (current_function_decl)); 1.1 root 2823: 1.1.1.2 root 2824: if (use_return_insn() && return_used_this_function) 1.1 root 2825: { 1.1.1.2 root 2826: if (frame_size && !(frame_pointer_needed || TARGET_APCS)) 2827: { 2828: abort (); 2829: } 1.1.1.3 ! root 2830: goto epilogue_done; ! 2831: } ! 2832: ! 2833: /* A volatile function should never return. Call abort. */ ! 2834: if (volatile_func) ! 2835: { ! 2836: rtx op = gen_rtx (SYMBOL_REF, Pmode, "abort"); ! 2837: output_asm_insn ("bl\t%a0", &op); ! 2838: code_size = 4; ! 2839: goto epilogue_done; 1.1 root 2840: } 2841: 1.1.1.3 ! root 2842: for (reg = 0; reg <= 10; reg++) ! 2843: if (regs_ever_live[reg] && ! call_used_regs[reg]) 1.1 root 2844: { 1.1.1.2 root 2845: live_regs_mask |= (1 << reg); 2846: floats_offset += 4; 1.1 root 2847: } 2848: 1.1.1.2 root 2849: if (frame_pointer_needed) 1.1 root 2850: { 1.1.1.3 ! root 2851: for (reg = 23; reg > 15; reg--) ! 2852: if (regs_ever_live[reg] && ! call_used_regs[reg]) 1.1.1.2 root 2853: { 1.1.1.3 ! root 2854: fprintf (f, "\tldfe\t%s%s, [%sfp, #-%d]\n", ARM_REG_PREFIX, ! 2855: reg_names[reg], ARM_REG_PREFIX, floats_offset); 1.1.1.2 root 2856: floats_offset += 12; 2857: code_size += 4; 2858: } 2859: 2860: live_regs_mask |= 0xA800; 1.1.1.3 ! root 2861: print_multi_reg (f, "ldmea\t%sfp", live_regs_mask, 1.1.1.2 root 2862: TARGET_6 ? FALSE : TRUE); 1.1 root 2863: code_size += 4; 2864: } 2865: else 2866: { 2867: /* Restore stack pointer if necessary. */ 2868: if (frame_size) 2869: { 2870: operands[0] = operands[1] = stack_pointer_rtx; 2871: operands[2] = gen_rtx (CONST_INT, VOIDmode, frame_size); 2872: output_add_immediate (operands); 2873: } 2874: 1.1.1.3 ! root 2875: for (reg = 16; reg < 24; reg++) ! 2876: if (regs_ever_live[reg] && ! call_used_regs[reg]) 1.1.1.2 root 2877: { 1.1.1.3 ! root 2878: fprintf (f, "\tldfe\t%s%s, [%ssp], #12\n", ARM_REG_PREFIX, ! 2879: reg_names[reg], ARM_REG_PREFIX); 1.1.1.2 root 2880: code_size += 4; 2881: } 1.1 root 2882: if (current_function_pretend_args_size == 0 && regs_ever_live[14]) 2883: { 1.1.1.3 ! root 2884: print_multi_reg (f, "ldmfd\t%ssp!", live_regs_mask | 0x8000, 1.1.1.2 root 2885: TARGET_6 ? FALSE : TRUE); 1.1 root 2886: code_size += 4; 2887: } 2888: else 2889: { 1.1.1.2 root 2890: if (live_regs_mask || regs_ever_live[14]) 1.1 root 2891: { 1.1.1.2 root 2892: live_regs_mask |= 0x4000; 1.1.1.3 ! root 2893: print_multi_reg (f, "ldmfd\t%ssp!", live_regs_mask, FALSE); 1.1 root 2894: code_size += 4; 2895: } 2896: if (current_function_pretend_args_size) 2897: { 2898: operands[0] = operands[1] = stack_pointer_rtx; 2899: operands[2] = gen_rtx (CONST_INT, VOIDmode, 2900: current_function_pretend_args_size); 2901: output_add_immediate (operands); 2902: } 1.1.1.3 ! root 2903: fprintf (f, ! 2904: TARGET_6 ? "\tmov\t%spc, %slr\n" : "\tmovs\t%spc, %slr\n", ! 2905: ARM_REG_PREFIX, ARM_REG_PREFIX, f); 1.1 root 2906: code_size += 4; 2907: } 2908: } 1.1.1.3 ! root 2909: ! 2910: epilogue_done: ! 2911: ! 2912: /* insn_addresses isn't allocated when not optimizing */ ! 2913: ! 2914: if (optimize > 0) ! 2915: arm_increase_location (code_size ! 2916: + insn_addresses[INSN_UID (get_last_insn ())] ! 2917: + get_prologue_size ()); ! 2918: 1.1 root 2919: current_function_anonymous_args = 0; 1.1.1.3 ! root 2920: } ! 2921: ! 2922: static void ! 2923: emit_multi_reg_push (mask) ! 2924: int mask; ! 2925: { ! 2926: int num_regs = 0; ! 2927: int i, j; ! 2928: rtx par; ! 2929: ! 2930: for (i = 0; i < 16; i++) ! 2931: if (mask & (1 << i)) ! 2932: num_regs++; ! 2933: ! 2934: if (num_regs == 0 || num_regs > 16) ! 2935: abort (); ! 2936: ! 2937: par = gen_rtx (PARALLEL, VOIDmode, rtvec_alloc (num_regs)); ! 2938: ! 2939: for (i = 0; i < 16; i++) ! 2940: { ! 2941: if (mask & (1 << i)) ! 2942: { ! 2943: XVECEXP (par, 0, 0) ! 2944: = gen_rtx (SET, VOIDmode, gen_rtx (MEM, BLKmode, ! 2945: gen_rtx (PRE_DEC, BLKmode, ! 2946: stack_pointer_rtx)), ! 2947: gen_rtx (UNSPEC, BLKmode, ! 2948: gen_rtvec (1, gen_rtx (REG, SImode, i)), ! 2949: 2)); ! 2950: break; ! 2951: } ! 2952: } ! 2953: ! 2954: for (j = 1, i++; j < num_regs; i++) ! 2955: { ! 2956: if (mask & (1 << i)) ! 2957: { ! 2958: XVECEXP (par, 0, j) ! 2959: = gen_rtx (USE, VOIDmode, gen_rtx (REG, SImode, i)); ! 2960: j++; ! 2961: } ! 2962: } ! 2963: emit_insn (par); ! 2964: } ! 2965: ! 2966: void ! 2967: arm_expand_prologue () ! 2968: { ! 2969: int reg; ! 2970: rtx amount = GEN_INT (- get_frame_size ()); ! 2971: rtx push_insn; ! 2972: int num_regs; ! 2973: int live_regs_mask = 0; ! 2974: int store_arg_regs = 0; ! 2975: int volatile_func = (optimize > 0 ! 2976: && TREE_THIS_VOLATILE (current_function_decl)); ! 2977: ! 2978: if (current_function_anonymous_args && current_function_pretend_args_size) ! 2979: store_arg_regs = 1; ! 2980: ! 2981: if (! volatile_func) ! 2982: for (reg = 0; reg <= 10; reg++) ! 2983: if (regs_ever_live[reg] && ! call_used_regs[reg]) ! 2984: live_regs_mask |= 1 << reg; ! 2985: ! 2986: if (! volatile_func && regs_ever_live[14]) ! 2987: live_regs_mask |= 0x4000; ! 2988: ! 2989: if (frame_pointer_needed) ! 2990: { ! 2991: live_regs_mask |= 0xD800; ! 2992: emit_insn (gen_movsi (gen_rtx (REG, SImode, 12), ! 2993: stack_pointer_rtx)); ! 2994: } ! 2995: ! 2996: if (current_function_pretend_args_size) ! 2997: { ! 2998: if (store_arg_regs) ! 2999: emit_multi_reg_push ((0xf0 >> (current_function_pretend_args_size / 4)) ! 3000: & 0xf); ! 3001: else ! 3002: emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, ! 3003: GEN_INT (-current_function_pretend_args_size))); ! 3004: } ! 3005: ! 3006: if (live_regs_mask) ! 3007: { ! 3008: /* If we have to push any regs, then we must push lr as well, or ! 3009: we won't get a propper return. */ ! 3010: live_regs_mask |= 0x4000; ! 3011: emit_multi_reg_push (live_regs_mask); ! 3012: } ! 3013: ! 3014: /* For now the integer regs are still pushed in output_func_epilogue (). */ ! 3015: ! 3016: if (! volatile_func) ! 3017: for (reg = 23; reg > 15; reg--) ! 3018: if (regs_ever_live[reg] && ! call_used_regs[reg]) ! 3019: emit_insn (gen_rtx (SET, VOIDmode, ! 3020: gen_rtx (MEM, XFmode, ! 3021: gen_rtx (PRE_DEC, XFmode, ! 3022: stack_pointer_rtx)), ! 3023: gen_rtx (REG, XFmode, reg))); ! 3024: ! 3025: if (frame_pointer_needed) ! 3026: emit_insn (gen_addsi3 (hard_frame_pointer_rtx, gen_rtx (REG, SImode, 12), ! 3027: (GEN_INT ! 3028: (-(4 + current_function_pretend_args_size))))); ! 3029: ! 3030: if (amount != const0_rtx) ! 3031: { ! 3032: emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, amount)); ! 3033: emit_insn (gen_rtx (CLOBBER, VOIDmode, ! 3034: gen_rtx (MEM, BLKmode, stack_pointer_rtx))); ! 3035: } ! 3036: ! 3037: /* If we are profiling, make sure no instructions are scheduled before ! 3038: the call to mcount. */ ! 3039: if (profile_flag || profile_block_flag) ! 3040: emit_insn (gen_blockage ()); ! 3041: } ! 3042: 1.1 root 3043: 1.1.1.3 ! root 3044: /* If CODE is 'd', then the X is a condition operand and the instruction ! 3045: should only be executed if the condition is true. ! 3046: if CODE is 'D', then the X is a condition operand and the instruciton ! 3047: should only be executed if the condition is false: however, if the mode ! 3048: of the comparison is CCFPEmode, then always execute the instruction -- we ! 3049: do this because in these circumstances !GE does not necessarily imply LT; ! 3050: in these cases the instruction pattern will take care to make sure that ! 3051: an instruction containing %d will follow, thereby undoing the effects of ! 3052: doing this instrucion unconditionally. ! 3053: If CODE is 'N' then X is a floating point operand that must be negated ! 3054: before output. ! 3055: If CODE is 'B' then output a bitwise inverted value of X (a const int). ! 3056: If X is a REG and CODE is `M', output a ldm/stm style multi-reg. */ ! 3057: ! 3058: void ! 3059: arm_print_operand (stream, x, code) ! 3060: FILE *stream; ! 3061: rtx x; ! 3062: int code; ! 3063: { ! 3064: switch (code) ! 3065: { ! 3066: case '@': ! 3067: fputc (ARM_COMMENT_CHAR, stream); ! 3068: return; ! 3069: ! 3070: case '|': ! 3071: fputs (ARM_REG_PREFIX, stream); ! 3072: return; ! 3073: ! 3074: case '?': ! 3075: if (arm_ccfsm_state == 3 || arm_ccfsm_state == 4) ! 3076: fputs (arm_condition_codes[arm_current_cc], stream); ! 3077: return; ! 3078: ! 3079: case 'N': ! 3080: { ! 3081: REAL_VALUE_TYPE r; ! 3082: REAL_VALUE_FROM_CONST_DOUBLE (r, x); ! 3083: r = REAL_VALUE_NEGATE (r); ! 3084: fprintf (stream, "%s", fp_const_from_val (&r)); ! 3085: } ! 3086: return; ! 3087: ! 3088: case 'B': ! 3089: if (GET_CODE (x) == CONST_INT) ! 3090: fprintf (stream, ! 3091: #if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT ! 3092: "%d", ! 3093: #else ! 3094: "%ld", ! 3095: #endif ! 3096: ARM_SIGN_EXTEND (~ INTVAL (x))); ! 3097: else ! 3098: { ! 3099: putc ('~', stream); ! 3100: output_addr_const (stream, x); ! 3101: } ! 3102: return; ! 3103: ! 3104: case 'i': ! 3105: fprintf (stream, "%s", arithmetic_instr (x, 1)); ! 3106: return; ! 3107: ! 3108: case 'I': ! 3109: fprintf (stream, "%s", arithmetic_instr (x, 0)); ! 3110: return; ! 3111: ! 3112: case 'S': ! 3113: { ! 3114: HOST_WIDE_INT val; ! 3115: char *shift = shift_op (x, &val); ! 3116: ! 3117: if (shift) ! 3118: { ! 3119: fprintf (stream, ", %s ", shift_op (x, &val)); ! 3120: if (val == -1) ! 3121: arm_print_operand (stream, XEXP (x, 1), 0); ! 3122: else ! 3123: fprintf (stream, ! 3124: #if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT ! 3125: "#%d", ! 3126: #else ! 3127: "#%ld", ! 3128: #endif ! 3129: val); ! 3130: } ! 3131: } ! 3132: return; ! 3133: ! 3134: case 'R': ! 3135: if (REGNO (x) > 15) ! 3136: abort (); ! 3137: fputs (ARM_REG_PREFIX, stream); ! 3138: fputs (reg_names[REGNO (x) + 1], stream); ! 3139: return; ! 3140: ! 3141: case 'm': ! 3142: fputs (ARM_REG_PREFIX, stream); ! 3143: if (GET_CODE (XEXP (x, 0)) == REG) ! 3144: fputs (reg_names[REGNO (XEXP (x, 0))], stream); ! 3145: else ! 3146: fputs (reg_names[REGNO (XEXP (XEXP (x, 0), 0))], stream); ! 3147: return; ! 3148: ! 3149: case 'M': ! 3150: fprintf (stream, "{%s%s-%s%s}", ARM_REG_PREFIX, reg_names[REGNO (x)], ! 3151: ARM_REG_PREFIX, reg_names[REGNO (x) - 1 ! 3152: + ((GET_MODE_SIZE (GET_MODE (x)) ! 3153: + GET_MODE_SIZE (SImode) - 1) ! 3154: / GET_MODE_SIZE (SImode))]); ! 3155: return; ! 3156: ! 3157: case 'd': ! 3158: if (x) ! 3159: fputs (arm_condition_codes[get_arm_condition_code (x)], ! 3160: stream); ! 3161: return; ! 3162: ! 3163: case 'D': ! 3164: if (x && (flag_fast_math ! 3165: || GET_CODE (x) == EQ || GET_CODE (x) == NE ! 3166: || (GET_MODE (XEXP (x, 0)) != CCFPEmode ! 3167: && (GET_MODE_CLASS (GET_MODE (XEXP (x, 0))) ! 3168: != MODE_FLOAT)))) ! 3169: fputs (arm_condition_codes[ARM_INVERSE_CONDITION_CODE ! 3170: (get_arm_condition_code (x))], ! 3171: stream); ! 3172: return; ! 3173: ! 3174: default: ! 3175: if (x == 0) ! 3176: abort (); ! 3177: ! 3178: if (GET_CODE (x) == REG) ! 3179: { ! 3180: fputs (ARM_REG_PREFIX, stream); ! 3181: fputs (reg_names[REGNO (x)], stream); ! 3182: } ! 3183: else if (GET_CODE (x) == MEM) ! 3184: { ! 3185: output_memory_reference_mode = GET_MODE (x); ! 3186: output_address (XEXP (x, 0)); ! 3187: } ! 3188: else if (GET_CODE (x) == CONST_DOUBLE) ! 3189: fprintf (stream, "#%s", fp_immediate_constant (x)); ! 3190: else if (GET_CODE (x) == NEG) ! 3191: abort (); /* This should never happen now. */ ! 3192: else ! 3193: { ! 3194: fputc ('#', stream); ! 3195: output_addr_const (stream, x); ! 3196: } ! 3197: } ! 3198: } ! 3199: 1.1 root 3200: /* Increase the `arm_text_location' by AMOUNT if we're in the text 3201: segment. */ 3202: 3203: void 3204: arm_increase_location (amount) 3205: int amount; 3206: { 3207: if (in_text_section ()) 3208: arm_text_location += amount; 1.1.1.3 ! root 3209: } 1.1 root 3210: 3211: 3212: /* Output a label definition. If this label is within the .text segment, it 3213: is stored in OFFSET_TABLE, to be used when building `llc' instructions. 3214: Maybe GCC remembers names not starting with a `*' for a long time, but this 3215: is a minority anyway, so we just make a copy. Do not store the leading `*' 3216: if the name starts with one. */ 3217: 3218: void 3219: arm_asm_output_label (stream, name) 3220: FILE *stream; 3221: char *name; 3222: { 3223: char *real_name, *s; 3224: struct label_offset *cur; 3225: int hash = 0; 3226: 3227: assemble_name (stream, name); 3228: fputs (":\n", stream); 3229: if (! in_text_section ()) 3230: return; 3231: 3232: if (name[0] == '*') 3233: { 3234: real_name = xmalloc (1 + strlen (&name[1])); 3235: strcpy (real_name, &name[1]); 3236: } 3237: else 3238: { 3239: real_name = xmalloc (2 + strlen (name)); 3240: strcpy (real_name, "_"); 3241: strcat (real_name, name); 3242: } 3243: for (s = real_name; *s; s++) 3244: hash += *s; 1.1.1.3 ! root 3245: 1.1 root 3246: hash = hash % LABEL_HASH_SIZE; 3247: cur = (struct label_offset *) xmalloc (sizeof (struct label_offset)); 3248: cur->name = real_name; 3249: cur->offset = arm_text_location; 3250: cur->cdr = offset_table[hash]; 3251: offset_table[hash] = cur; 1.1.1.3 ! root 3252: } 1.1 root 3253: 1.1.1.3 ! root 3254: /* Load a symbol that is known to be in the text segment into a register. ! 3255: This should never be called when not optimizing. */ 1.1 root 3256: 3257: char * 1.1.1.3 ! root 3258: output_load_symbol (insn, operands) ! 3259: rtx insn; 1.1 root 3260: rtx *operands; 3261: { 1.1.1.3 ! root 3262: char *s; ! 3263: char *name = XSTR (operands[1], 0); 1.1.1.2 root 3264: struct label_offset *he; 3265: int hash = 0; 3266: int offset; 1.1.1.3 ! root 3267: unsigned int mask, never_mask = 0xffffffff; ! 3268: int shift, inst; ! 3269: char buffer[100]; ! 3270: ! 3271: if (optimize == 0 || *name != '*') 1.1.1.2 root 3272: abort (); 3273: 3274: for (s = &name[1]; *s; s++) 3275: hash += *s; 1.1.1.3 ! root 3276: 1.1.1.2 root 3277: hash = hash % LABEL_HASH_SIZE; 3278: he = offset_table[hash]; 3279: while (he && strcmp (he->name, &name[1])) 3280: he = he->cdr; 3281: 3282: if (!he) 3283: abort (); 3284: 1.1.1.3 ! root 3285: offset = (arm_text_location + insn_addresses[INSN_UID (insn)] ! 3286: + get_prologue_size () + 8 - he->offset); 1.1.1.2 root 3287: if (offset < 0) 3288: abort (); 3289: 1.1.1.3 ! root 3290: /* When generating the instructions, we never mask out the bits that we ! 3291: think will be always zero, then if a mistake has occured somewhere, the ! 3292: assembler will spot it and generate an error. */ ! 3293: 1.1.1.2 root 3294: /* If the symbol is word aligned then we might be able to reduce the 1.1.1.3 ! root 3295: number of loads. */ ! 3296: shift = ((offset & 3) == 0) ? 2 : 0; ! 3297: ! 3298: /* Clear the bits from NEVER_MASK that will be orred in with the individual ! 3299: instructions. */ ! 3300: for (; shift < 32; shift += 8) 1.1.1.2 root 3301: { 1.1.1.3 ! root 3302: mask = 0xff << shift; ! 3303: if ((offset & mask) || ((unsigned) offset) > mask) ! 3304: never_mask &= ~mask; 1.1.1.2 root 3305: } 1.1.1.3 ! root 3306: ! 3307: inst = 8; ! 3308: mask = 0xff << (shift - 32); ! 3309: ! 3310: while (mask && (never_mask & mask) == 0) 1.1.1.2 root 3311: { 1.1.1.3 ! root 3312: if (inst == 8) ! 3313: { ! 3314: strcpy (buffer, "sub%?\t%0, %|pc, #(8 + . -%a1)"); ! 3315: if ((never_mask | mask) != 0xffffffff) ! 3316: sprintf (buffer + strlen (buffer), " & 0x%x", mask | never_mask); ! 3317: } ! 3318: else ! 3319: sprintf (buffer, "sub%%?\t%%0, %%0, #(%d + . -%%a1) & 0x%x", ! 3320: inst, mask | never_mask); ! 3321: ! 3322: output_asm_insn (buffer, operands); ! 3323: mask <<= 8; ! 3324: inst -= 4; 1.1.1.2 root 3325: } 1.1.1.3 ! root 3326: 1.1.1.2 root 3327: return ""; 3328: } 1.1 root 3329: 3330: /* Output code resembling an .lcomm directive. /bin/as doesn't have this 3331: directive hence this hack, which works by reserving some `.space' in the 3332: bss segment directly. 3333: 3334: XXX This is a severe hack, which is guaranteed NOT to work since it doesn't 3335: define STATIC COMMON space but merely STATIC BSS space. */ 3336: 3337: void 3338: output_lcomm_directive (stream, name, size, rounded) 3339: FILE *stream; 3340: char *name; 3341: int size, rounded; 3342: { 1.1.1.3 ! root 3343: fprintf (stream, "\n\t.bss\t%c .lcomm\n", ARM_COMMENT_CHAR); 1.1 root 3344: assemble_name (stream, name); 3345: fprintf (stream, ":\t.space\t%d\n", rounded); 3346: if (in_text_section ()) 3347: fputs ("\n\t.text\n", stream); 3348: else 3349: fputs ("\n\t.data\n", stream); 1.1.1.3 ! root 3350: } 1.1 root 3351: 3352: /* A finite state machine takes care of noticing whether or not instructions 3353: can be conditionally executed, and thus decrease execution time and code 3354: size by deleting branch instructions. The fsm is controlled by 3355: final_prescan_insn, and controls the actions of ASM_OUTPUT_OPCODE. */ 3356: 3357: /* The state of the fsm controlling condition codes are: 3358: 0: normal, do nothing special 3359: 1: make ASM_OUTPUT_OPCODE not output this instruction 3360: 2: make ASM_OUTPUT_OPCODE not output this instruction 3361: 3: make instructions conditional 3362: 4: make instructions conditional 3363: 3364: State transitions (state->state by whom under condition): 3365: 0 -> 1 final_prescan_insn if the `target' is a label 3366: 0 -> 2 final_prescan_insn if the `target' is an unconditional branch 3367: 1 -> 3 ASM_OUTPUT_OPCODE after not having output the conditional branch 3368: 2 -> 4 ASM_OUTPUT_OPCODE after not having output the conditional branch 3369: 3 -> 0 ASM_OUTPUT_INTERNAL_LABEL if the `target' label is reached 3370: (the target label has CODE_LABEL_NUMBER equal to arm_target_label). 3371: 4 -> 0 final_prescan_insn if the `target' unconditional branch is reached 3372: (the target insn is arm_target_insn). 3373: 1.1.1.2 root 3374: If the jump clobbers the conditions then we use states 2 and 4. 3375: 3376: A similar thing can be done with conditional return insns. 3377: 1.1 root 3378: XXX In case the `target' is an unconditional branch, this conditionalising 3379: of the instructions always reduces code size, but not always execution 3380: time. But then, I want to reduce the code size to somewhere near what 3381: /bin/cc produces. */ 3382: 3383: /* Returns the index of the ARM condition code string in 3384: `arm_condition_codes'. COMPARISON should be an rtx like 3385: `(eq (...) (...))'. */ 3386: 3387: int 3388: get_arm_condition_code (comparison) 3389: rtx comparison; 3390: { 3391: switch (GET_CODE (comparison)) 3392: { 3393: case NE: return (1); 3394: case EQ: return (0); 3395: case GE: return (10); 3396: case GT: return (12); 3397: case LE: return (13); 3398: case LT: return (11); 3399: case GEU: return (2); 3400: case GTU: return (8); 3401: case LEU: return (9); 3402: case LTU: return (3); 3403: default: abort (); 3404: } 3405: /*NOTREACHED*/ 3406: return (42); 1.1.1.3 ! root 3407: } 1.1 root 3408: 3409: 3410: void 3411: final_prescan_insn (insn, opvec, noperands) 3412: rtx insn; 3413: rtx *opvec; 3414: int noperands; 3415: { 3416: /* BODY will hold the body of INSN. */ 3417: register rtx body = PATTERN (insn); 3418: 3419: /* This will be 1 if trying to repeat the trick, and things need to be 3420: reversed if it appears to fail. */ 3421: int reverse = 0; 3422: 1.1.1.2 root 3423: /* JUMP_CLOBBERS will be one implies that the conditions if a branch is 3424: taken are clobbered, even if the rtl suggests otherwise. It also 3425: means that we have to grub around within the jump expression to find 3426: out what the conditions are when the jump isn't taken. */ 3427: int jump_clobbers = 0; 3428: 3429: /* If we start with a return insn, we only succeed if we find another one. */ 3430: int seeking_return = 0; 3431: 1.1 root 3432: /* START_INSN will hold the insn from where we start looking. This is the 3433: first insn after the following code_label if REVERSE is true. */ 3434: rtx start_insn = insn; 3435: 3436: /* If in state 4, check if the target branch is reached, in order to 3437: change back to state 0. */ 3438: if (arm_ccfsm_state == 4) 3439: { 3440: if (insn == arm_target_insn) 1.1.1.2 root 3441: { 3442: arm_target_insn = NULL; 1.1 root 3443: arm_ccfsm_state = 0; 1.1.1.2 root 3444: } 1.1 root 3445: return; 3446: } 3447: 3448: /* If in state 3, it is possible to repeat the trick, if this insn is an 3449: unconditional branch to a label, and immediately following this branch 3450: is the previous target label which is only used once, and the label this 3451: branch jumps to is not too far off. */ 3452: if (arm_ccfsm_state == 3) 3453: { 3454: if (simplejump_p (insn)) 3455: { 3456: start_insn = next_nonnote_insn (start_insn); 3457: if (GET_CODE (start_insn) == BARRIER) 3458: { 3459: /* XXX Isn't this always a barrier? */ 3460: start_insn = next_nonnote_insn (start_insn); 3461: } 3462: if (GET_CODE (start_insn) == CODE_LABEL 3463: && CODE_LABEL_NUMBER (start_insn) == arm_target_label 3464: && LABEL_NUSES (start_insn) == 1) 3465: reverse = TRUE; 3466: else 3467: return; 3468: } 1.1.1.2 root 3469: else if (GET_CODE (body) == RETURN) 3470: { 3471: start_insn = next_nonnote_insn (start_insn); 3472: if (GET_CODE (start_insn) == BARRIER) 3473: start_insn = next_nonnote_insn (start_insn); 3474: if (GET_CODE (start_insn) == CODE_LABEL 3475: && CODE_LABEL_NUMBER (start_insn) == arm_target_label 3476: && LABEL_NUSES (start_insn) == 1) 3477: { 3478: reverse = TRUE; 3479: seeking_return = 1; 3480: } 3481: else 3482: return; 3483: } 1.1 root 3484: else 3485: return; 3486: } 3487: 3488: if (arm_ccfsm_state != 0 && !reverse) 3489: abort (); 3490: if (GET_CODE (insn) != JUMP_INSN) 3491: return; 3492: 1.1.1.2 root 3493: /* This jump might be paralled with a clobber of the condition codes 3494: the jump should always come first */ 3495: if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0) > 0) 3496: body = XVECEXP (body, 0, 0); 3497: 3498: #if 0 3499: /* If this is a conditional return then we don't want to know */ 3500: if (GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == PC 3501: && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE 3502: && (GET_CODE (XEXP (SET_SRC (body), 1)) == RETURN 3503: || GET_CODE (XEXP (SET_SRC (body), 2)) == RETURN)) 3504: return; 3505: #endif 3506: 1.1 root 3507: if (reverse 3508: || (GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == PC 3509: && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE)) 3510: { 3511: int insns_skipped = 0, fail = FALSE, succeed = FALSE; 3512: /* Flag which part of the IF_THEN_ELSE is the LABEL_REF. */ 3513: int then_not_else = TRUE; 1.1.1.2 root 3514: rtx this_insn = start_insn, label = 0; 1.1 root 3515: 1.1.1.2 root 3516: if (get_attr_conds (insn) == CONDS_JUMP_CLOB) 1.1.1.3 ! root 3517: { ! 3518: /* The code below is wrong for these, and I haven't time to ! 3519: fix it now. So we just do the safe thing and return. This ! 3520: whole function needs re-writing anyway. */ ! 3521: jump_clobbers = 1; ! 3522: return; ! 3523: } 1.1.1.2 root 3524: 1.1 root 3525: /* Register the insn jumped to. */ 3526: if (reverse) 1.1.1.2 root 3527: { 3528: if (!seeking_return) 3529: label = XEXP (SET_SRC (body), 0); 3530: } 1.1 root 3531: else if (GET_CODE (XEXP (SET_SRC (body), 1)) == LABEL_REF) 3532: label = XEXP (XEXP (SET_SRC (body), 1), 0); 3533: else if (GET_CODE (XEXP (SET_SRC (body), 2)) == LABEL_REF) 3534: { 3535: label = XEXP (XEXP (SET_SRC (body), 2), 0); 3536: then_not_else = FALSE; 3537: } 1.1.1.2 root 3538: else if (GET_CODE (XEXP (SET_SRC (body), 1)) == RETURN) 3539: seeking_return = 1; 3540: else if (GET_CODE (XEXP (SET_SRC (body), 2)) == RETURN) 3541: { 3542: seeking_return = 1; 3543: then_not_else = FALSE; 3544: } 1.1 root 3545: else 3546: abort (); 3547: 3548: /* See how many insns this branch skips, and what kind of insns. If all 3549: insns are okay, and the label or unconditional branch to the same 3550: label is not too far away, succeed. */ 3551: for (insns_skipped = 0; 3552: !fail && !succeed && insns_skipped < MAX_INSNS_SKIPPED; 3553: insns_skipped++) 3554: { 3555: rtx scanbody; 3556: 3557: this_insn = next_nonnote_insn (this_insn); 3558: if (!this_insn) 3559: break; 3560: 3561: scanbody = PATTERN (this_insn); 3562: 3563: switch (GET_CODE (this_insn)) 3564: { 3565: case CODE_LABEL: 3566: /* Succeed if it is the target label, otherwise fail since 3567: control falls in from somewhere else. */ 3568: if (this_insn == label) 3569: { 1.1.1.2 root 3570: if (jump_clobbers) 3571: { 3572: arm_ccfsm_state = 2; 3573: this_insn = next_nonnote_insn (this_insn); 3574: } 3575: else 3576: arm_ccfsm_state = 1; 1.1 root 3577: succeed = TRUE; 3578: } 3579: else 3580: fail = TRUE; 3581: break; 3582: 1.1.1.2 root 3583: case BARRIER: 1.1 root 3584: /* Succeed if the following insn is the target label. 1.1.1.2 root 3585: Otherwise fail. 3586: If return insns are used then the last insn in a function 3587: will be a barrier. */ 1.1 root 3588: this_insn = next_nonnote_insn (this_insn); 1.1.1.2 root 3589: if (this_insn && this_insn == label) 1.1 root 3590: { 1.1.1.2 root 3591: if (jump_clobbers) 3592: { 3593: arm_ccfsm_state = 2; 3594: this_insn = next_nonnote_insn (this_insn); 3595: } 3596: else 3597: arm_ccfsm_state = 1; 1.1 root 3598: succeed = TRUE; 3599: } 3600: else 3601: fail = TRUE; 3602: break; 3603: 1.1.1.2 root 3604: case CALL_INSN: 3605: /* The arm 6xx uses full 32 bit addresses so the cc is not 3606: preserved over calls */ 3607: if (TARGET_6) 3608: fail = TRUE; 3609: break; 1.1 root 3610: case JUMP_INSN: 3611: /* If this is an unconditional branch to the same label, succeed. 3612: If it is to another label, do nothing. If it is conditional, 3613: fail. */ 3614: /* XXX Probably, the test for the SET and the PC are unnecessary. */ 3615: 1.1.1.2 root 3616: if (GET_CODE (scanbody) == SET 3617: && GET_CODE (SET_DEST (scanbody)) == PC) 1.1 root 3618: { 3619: if (GET_CODE (SET_SRC (scanbody)) == LABEL_REF 3620: && XEXP (SET_SRC (scanbody), 0) == label && !reverse) 3621: { 3622: arm_ccfsm_state = 2; 3623: succeed = TRUE; 3624: } 3625: else if (GET_CODE (SET_SRC (scanbody)) == IF_THEN_ELSE) 3626: fail = TRUE; 3627: } 1.1.1.2 root 3628: else if (GET_CODE (scanbody) == RETURN 3629: && seeking_return) 3630: { 3631: arm_ccfsm_state = 2; 3632: succeed = TRUE; 3633: } 3634: else if (GET_CODE (scanbody) == PARALLEL) 3635: { 3636: switch (get_attr_conds (this_insn)) 3637: { 3638: case CONDS_NOCOND: 3639: break; 3640: default: 3641: fail = TRUE; 3642: break; 3643: } 3644: } 1.1 root 3645: break; 3646: 3647: case INSN: 1.1.1.2 root 3648: /* Instructions using or affecting the condition codes make it 3649: fail. */ 3650: if ((GET_CODE (scanbody) == SET 3651: || GET_CODE (scanbody) == PARALLEL) 3652: && get_attr_conds (this_insn) != CONDS_NOCOND) 1.1 root 3653: fail = TRUE; 3654: break; 3655: 3656: default: 3657: break; 3658: } 3659: } 3660: if (succeed) 3661: { 1.1.1.2 root 3662: if ((!seeking_return) && (arm_ccfsm_state == 1 || reverse)) 1.1 root 3663: arm_target_label = CODE_LABEL_NUMBER (label); 1.1.1.2 root 3664: else if (seeking_return || arm_ccfsm_state == 2) 3665: { 3666: while (this_insn && GET_CODE (PATTERN (this_insn)) == USE) 3667: { 3668: this_insn = next_nonnote_insn (this_insn); 3669: if (this_insn && (GET_CODE (this_insn) == BARRIER 3670: || GET_CODE (this_insn) == CODE_LABEL)) 3671: abort (); 3672: } 3673: if (!this_insn) 3674: { 3675: /* Oh, dear! we ran off the end.. give up */ 3676: recog (PATTERN (insn), insn, NULL_PTR); 3677: arm_ccfsm_state = 0; 3678: arm_target_insn = NULL; 3679: return; 3680: } 3681: arm_target_insn = this_insn; 3682: } 1.1 root 3683: else 3684: abort (); 1.1.1.2 root 3685: if (jump_clobbers) 3686: { 3687: if (reverse) 3688: abort (); 3689: arm_current_cc = 3690: get_arm_condition_code (XEXP (XEXP (XEXP (SET_SRC (body), 3691: 0), 0), 1)); 3692: if (GET_CODE (XEXP (XEXP (SET_SRC (body), 0), 0)) == AND) 3693: arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc); 3694: if (GET_CODE (XEXP (SET_SRC (body), 0)) == NE) 3695: arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc); 3696: } 3697: else 3698: { 3699: /* If REVERSE is true, ARM_CURRENT_CC needs to be inverted from 3700: what it was. */ 3701: if (!reverse) 3702: arm_current_cc = get_arm_condition_code (XEXP (SET_SRC (body), 3703: 0)); 3704: } 1.1 root 3705: 3706: if (reverse || then_not_else) 3707: arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc); 3708: } 1.1.1.2 root 3709: /* restore recog_operand (getting the attributes of other insns can 3710: destroy this array, but final.c assumes that it remains intact 3711: accross this call; since the insn has been recognized already we 3712: call recog direct). */ 3713: recog (PATTERN (insn), insn, NULL_PTR); 1.1 root 3714: } 1.1.1.3 ! root 3715: } 1.1 root 3716: 3717: /* EOF */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.