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