|
|
1.1 root 1: /* Subroutines for insn-output.c for Motorola 88000. 1.1.1.3 ! root 2: Copyright (C) 1988, 1989, 1990, 1991, 1994 Free Software Foundation, Inc. 1.1 root 3: Contributed by Michael Tiemann ([email protected]) 4: Enhanced by Michael Meissner ([email protected]) 1.1.1.3 ! root 5: Version 2 port by Tom Wood ([email protected]) 1.1 root 6: 7: This file is part of GNU CC. 8: 9: GNU CC is free software; you can redistribute it and/or modify 10: it under the terms of the GNU General Public License as published by 11: the Free Software Foundation; either version 2, or (at your option) 12: any later version. 13: 14: GNU CC is distributed in the hope that it will be useful, 15: but WITHOUT ANY WARRANTY; without even the implied warranty of 16: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17: GNU General Public License for more details. 18: 19: You should have received a copy of the GNU General Public License 20: along with GNU CC; see the file COPYING. If not, write to 21: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ 22: 23: #include <stdio.h> 24: #include <sys/types.h> 25: #include <time.h> 26: #include <ctype.h> 27: 28: #include "assert.h" 29: #include "config.h" 30: #include "rtl.h" 31: #include "regs.h" 32: #include "hard-reg-set.h" 33: #include "real.h" 34: #include "insn-config.h" 35: #include "conditions.h" 36: #include "insn-flags.h" 37: #include "output.h" 38: #include "insn-attr.h" 39: #include "tree.h" 40: #include "c-tree.h" 41: #include "expr.h" 42: #include "flags.h" 43: 44: extern char *version_string; 45: extern time_t time (); 46: extern char *ctime (); 47: extern int flag_traditional; 48: extern FILE *asm_out_file; 49: 1.1.1.3 ! root 50: static char out_rcs_id[] = "$What: <@(#) m88k.c,v 1.8> $"; ! 51: static char tm_rcs_id [] = TM_RCS_ID; 1.1 root 52: 53: char *m88k_pound_sign = ""; /* Either # for SVR4 or empty for SVR3 */ 54: char *m88k_short_data; 55: char *m88k_version; 56: char m88k_volatile_code; 57: 1.1.1.3 ! root 58: unsigned m88k_gp_threshold = 0; 1.1 root 59: int m88k_prologue_done = 0; /* Ln directives can now be emitted */ 60: int m88k_function_number = 0; /* Counter unique to each function */ 61: int m88k_fp_offset = 0; /* offset of frame pointer if used */ 62: int m88k_stack_size = 0; /* size of allocated stack (including frame) */ 63: int m88k_case_index; 64: 65: rtx m88k_compare_reg; /* cmp output pseudo register */ 66: rtx m88k_compare_op0; /* cmpsi operand 0 */ 67: rtx m88k_compare_op1; /* cmpsi operand 1 */ 68: 1.1.1.3 ! root 69: enum processor_type m88k_cpu; /* target cpu */ 1.1 root 70: 71: /* Determine what instructions are needed to manufacture the integer VALUE 72: in the given MODE. */ 73: 74: enum m88k_instruction 75: classify_integer (mode, value) 76: enum machine_mode mode; 77: register int value; 78: { 79: register int mask; 80: 81: if (value == 0) 82: return m88k_zero; 83: else if (SMALL_INTVAL (value)) 84: return m88k_or; 85: else if (SMALL_INTVAL (-value)) 86: return m88k_subu; 87: else if (mode == HImode) 88: return m88k_or_lo16; 89: else if (mode == QImode) 90: return m88k_or_lo8; 91: else if ((value & 0xffff) == 0) 92: return m88k_oru_hi16; 93: else if (integer_ok_for_set (value)) 94: return m88k_set; 95: else 96: return m88k_oru_or; 97: } 98: 99: /* Return the bit number in a compare word corresponding to CONDITION. */ 100: 101: int 102: condition_value (condition) 103: rtx condition; 104: { 105: switch (GET_CODE (condition)) 106: { 107: case EQ: return 2; 108: case NE: return 3; 109: case GT: return 4; 110: case LE: return 5; 111: case LT: return 6; 112: case GE: return 7; 113: case GTU: return 8; 114: case LEU: return 9; 115: case LTU: return 10; 116: case GEU: return 11; 117: default: abort (); 118: } 119: } 120: 121: int 122: integer_ok_for_set (value) 123: register unsigned value; 124: { 125: /* All the "one" bits must be contiguous. If so, MASK + 1 will be 126: a power of two or zero. */ 127: register unsigned mask = (value | (value - 1)); 128: return (value && POWER_OF_2_or_0 (mask + 1)); 129: } 130: 131: char * 132: output_load_const_int (mode, operands) 133: enum machine_mode mode; 134: rtx *operands; 135: { 136: static char *patterns[] = 137: { "or %0,%#r0,0", 138: "or %0,%#r0,%1", 139: "subu %0,%#r0,%n1", 140: "or %0,%#r0,%h1", 141: "or %0,%#r0,%q1", 142: "set %0,%#r0,%s1", 143: "or.u %0,%#r0,%X1", 144: "or.u %0,%#r0,%X1\n\tor %0,%0,%x1", 145: }; 146: 147: if (! REG_P (operands[0]) 148: || GET_CODE (operands[1]) != CONST_INT) 149: abort (); 150: return patterns[classify_integer (mode, INTVAL (operands[1]))]; 151: } 152: 153: /* These next two routines assume that floating point numbers are represented 154: in a manner which is consistent between host and target machines. */ 155: 156: char * 157: output_load_const_float (operands) 158: rtx *operands; 159: { 160: /* These can return 0 under some circumstances when cross-compiling. */ 161: operands[0] = operand_subword (operands[0], 0, 0, SFmode); 162: operands[1] = operand_subword (operands[1], 0, 0, SFmode); 163: 164: return output_load_const_int (SImode, operands); 165: } 166: 167: char * 168: output_load_const_double (operands) 169: rtx *operands; 170: { 171: rtx latehalf[2]; 172: 173: /* These can return zero on some cross-compilers, but there's nothing 174: we can do about it. */ 175: latehalf[0] = operand_subword (operands[0], 1, 0, DFmode); 176: latehalf[1] = operand_subword (operands[1], 1, 0, DFmode); 177: 178: operands[0] = operand_subword (operands[0], 0, 0, DFmode); 179: operands[1] = operand_subword (operands[1], 0, 0, DFmode); 180: 181: output_asm_insn (output_load_const_int (SImode, operands), operands); 182: 183: operands[0] = latehalf[0]; 184: operands[1] = latehalf[1]; 185: 186: return output_load_const_int (SImode, operands); 187: } 188: 189: char * 190: output_load_const_dimode (operands) 191: rtx *operands; 192: { 193: rtx latehalf[2]; 194: 195: latehalf[0] = operand_subword (operands[0], 1, 0, DImode); 196: latehalf[1] = operand_subword (operands[1], 1, 0, DImode); 197: 198: operands[0] = operand_subword (operands[0], 0, 0, DImode); 199: operands[1] = operand_subword (operands[1], 0, 0, DImode); 200: 201: output_asm_insn (output_load_const_int (SImode, operands), operands); 202: 203: operands[0] = latehalf[0]; 204: operands[1] = latehalf[1]; 205: 206: return output_load_const_int (SImode, operands); 207: } 208: 209: /* Emit insns to move operands[1] into operands[0]. 210: 211: Return 1 if we have written out everything that needs to be done to 212: do the move. Otherwise, return 0 and the caller will emit the move 213: normally. 214: 215: SCRATCH if non zero can be used as a scratch register for the move 216: operation. It is provided by a SECONDARY_RELOAD_* macro if needed. */ 217: 218: int 219: emit_move_sequence (operands, mode, scratch) 220: rtx *operands; 221: enum machine_mode mode; 222: rtx scratch; 223: { 224: register rtx operand0 = operands[0]; 225: register rtx operand1 = operands[1]; 226: 1.1.1.3 ! root 227: if (CONSTANT_P (operand1) && flag_pic ! 228: && pic_address_needs_scratch (operand1)) ! 229: operands[1] = operand1 = legitimize_address (1, operand1, 0, 0); ! 230: 1.1 root 231: /* Handle most common case first: storing into a register. */ 232: if (register_operand (operand0, mode)) 233: { 234: if (register_operand (operand1, mode) 235: || (GET_CODE (operand1) == CONST_INT && SMALL_INT (operand1)) 236: || GET_CODE (operand1) == HIGH 237: /* Only `general_operands' can come here, so MEM is ok. */ 238: || GET_CODE (operand1) == MEM) 239: { 240: /* Run this case quickly. */ 241: emit_insn (gen_rtx (SET, VOIDmode, operand0, operand1)); 242: return 1; 243: } 244: } 245: else if (GET_CODE (operand0) == MEM) 246: { 247: if (register_operand (operand1, mode) 248: || (operand1 == const0_rtx && GET_MODE_SIZE (mode) <= UNITS_PER_WORD)) 249: { 250: /* Run this case quickly. */ 251: emit_insn (gen_rtx (SET, VOIDmode, operand0, operand1)); 252: return 1; 253: } 254: if (! reload_in_progress && ! reload_completed) 255: { 256: operands[0] = validize_mem (operand0); 257: operands[1] = operand1 = force_reg (mode, operand1); 258: } 259: } 260: 261: /* Simplify the source if we need to. */ 262: if (GET_CODE (operand1) != HIGH && immediate_operand (operand1, mode)) 263: { 264: if (GET_CODE (operand1) != CONST_INT 265: && GET_CODE (operand1) != CONST_DOUBLE) 266: { 267: rtx temp = ((reload_in_progress || reload_completed) 268: ? operand0 : 0); 269: operands[1] = legitimize_address (flag_pic 270: && symbolic_address_p (operand1), 271: operand1, temp, scratch); 272: if (mode != SImode) 273: operands[1] = gen_rtx (SUBREG, mode, operands[1], 0); 274: } 275: } 276: 277: /* Now have insn-emit do whatever it normally does. */ 278: return 0; 279: } 280: 281: /* Return a legitimate reference for ORIG (either an address or a MEM) 282: using the register REG. If PIC and the address is already 283: position-independent, use ORIG. Newly generated position-independent 284: addresses go into a reg. This is REG if non zero, otherwise we 285: allocate register(s) as necessary. If this is called during reload, 286: and we need a second temp register, then we use SCRATCH, which is 287: provided via the SECONDARY_INPUT_RELOAD_CLASS mechanism. */ 288: 289: struct rtx_def * 290: legitimize_address (pic, orig, reg, scratch) 291: int pic; 292: rtx orig; 293: rtx reg; 294: rtx scratch; 295: { 296: rtx addr = (GET_CODE (orig) == MEM ? XEXP (orig, 0) : orig); 297: rtx new = orig; 298: rtx temp, insn; 299: 300: if (pic) 301: { 302: if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF) 303: { 304: if (reg == 0) 305: { 306: if (reload_in_progress || reload_completed) 307: abort (); 308: else 309: reg = gen_reg_rtx (Pmode); 310: } 311: 312: if (flag_pic == 2) 313: { 314: /* If not during reload, allocate another temp reg here for 315: loading in the address, so that these instructions can be 316: optimized properly. */ 317: temp = ((reload_in_progress || reload_completed) 318: ? reg : gen_reg_rtx (Pmode)); 319: 1.1.1.3 ! root 320: emit_insn (gen_rtx (SET, VOIDmode, temp, ! 321: gen_rtx (HIGH, SImode, ! 322: gen_rtx (UNSPEC, SImode, ! 323: gen_rtvec (1, addr), ! 324: 0)))); ! 325: emit_insn (gen_rtx (SET, VOIDmode, temp, ! 326: gen_rtx (LO_SUM, SImode, temp, ! 327: gen_rtx (UNSPEC, SImode, ! 328: gen_rtvec (1, addr), ! 329: 0)))); 1.1 root 330: addr = temp; 331: } 332: new = gen_rtx (MEM, Pmode, 333: gen_rtx (PLUS, SImode, 334: pic_offset_table_rtx, addr)); 335: current_function_uses_pic_offset_table = 1; 336: RTX_UNCHANGING_P (new) = 1; 337: insn = emit_move_insn (reg, new); 338: /* Put a REG_EQUAL note on this insn, so that it can be optimized 339: by loop. */ 340: REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_EQUAL, orig, 341: REG_NOTES (insn)); 342: new = reg; 343: } 344: else if (GET_CODE (addr) == CONST) 345: { 346: rtx base, offset; 347: 348: if (GET_CODE (XEXP (addr, 0)) == PLUS 349: && XEXP (XEXP (addr, 0), 0) == pic_offset_table_rtx) 350: return orig; 351: 352: if (reg == 0) 353: { 354: if (reload_in_progress || reload_completed) 355: abort (); 356: else 357: reg = gen_reg_rtx (Pmode); 358: } 359: 360: if (GET_CODE (XEXP (addr, 0)) != PLUS) abort (); 361: 362: base = legitimize_address (1, XEXP (XEXP (addr, 0), 0), reg, 0); 363: addr = legitimize_address (1, XEXP (XEXP (addr, 0), 1), 364: base == reg ? 0 : reg, 0); 365: 366: if (GET_CODE (addr) == CONST_INT) 367: { 1.1.1.3 ! root 368: if (ADD_INT (addr)) 1.1 root 369: return plus_constant_for_output (base, INTVAL (addr)); 370: else if (! reload_in_progress && ! reload_completed) 371: addr = force_reg (Pmode, addr); 372: /* We can't create any new registers during reload, so use the 373: SCRATCH reg provided by the reload_insi pattern. */ 374: else if (scratch) 375: { 376: emit_move_insn (scratch, addr); 377: addr = scratch; 378: } 379: else 380: /* If we reach here, then the SECONDARY_INPUT_RELOAD_CLASS 381: macro needs to be adjusted so that a scratch reg is provided 382: for this address. */ 383: abort (); 384: } 385: new = gen_rtx (PLUS, SImode, base, addr); 386: /* Should we set special REG_NOTEs here? */ 387: } 388: } 389: else if (! SHORT_ADDRESS_P (addr, temp)) 390: { 391: if (reg == 0) 392: { 393: if (reload_in_progress || reload_completed) 394: abort (); 395: else 396: reg = gen_reg_rtx (Pmode); 397: } 398: 399: emit_insn (gen_rtx (SET, VOIDmode, 400: reg, gen_rtx (HIGH, SImode, addr))); 401: new = gen_rtx (LO_SUM, SImode, reg, addr); 402: } 403: 404: if (new != orig 405: && GET_CODE (orig) == MEM) 406: { 407: new = gen_rtx (MEM, GET_MODE (orig), new); 408: RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (orig); 409: MEM_VOLATILE_P (new) = MEM_VOLATILE_P (orig); 410: MEM_IN_STRUCT_P (new) = MEM_IN_STRUCT_P (orig); 411: } 412: return new; 413: } 414: 415: /* Support functions for code to emit a block move. There are four methods 416: used to perform the block move: 417: + call memcpy 418: + call the looping library function, e.g. __movstrSI64n8 419: + call a non-looping library function, e.g. __movstrHI15x11 420: + produce an inline sequence of ld/st instructions 421: 422: The parameters below describe the library functions produced by 423: movstr-m88k.sh. */ 424: 425: #define MOVSTR_LOOP 64 /* __movstrSI64n68 .. __movstrSI64n8 */ 426: #define MOVSTR_QI 16 /* __movstrQI16x16 .. __movstrQI16x2 */ 427: #define MOVSTR_HI 48 /* __movstrHI48x48 .. __movstrHI48x4 */ 428: #define MOVSTR_SI 96 /* __movstrSI96x96 .. __movstrSI96x8 */ 429: #define MOVSTR_DI 96 /* __movstrDI96x96 .. __movstrDI96x16 */ 430: #define MOVSTR_ODD_HI 16 /* __movstrHI15x15 .. __movstrHI15x5 */ 431: #define MOVSTR_ODD_SI 48 /* __movstrSI47x47 .. __movstrSI47x11, 432: __movstrSI46x46 .. __movstrSI46x10, 433: __movstrSI45x45 .. __movstrSI45x9 */ 434: #define MOVSTR_ODD_DI 48 /* __movstrDI47x47 .. __movstrDI47x23, 435: __movstrDI46x46 .. __movstrDI46x22, 436: __movstrDI45x45 .. __movstrDI45x21, 437: __movstrDI44x44 .. __movstrDI44x20, 438: __movstrDI43x43 .. __movstrDI43x19, 439: __movstrDI42x42 .. __movstrDI42x18, 440: __movstrDI41x41 .. __movstrDI41x17 */ 441: 442: /* Limits for using the non-looping movstr functions. For the m88100 443: processor, we assume the source and destination are word aligned. 444: The QImode and HImode limits are the break even points where memcpy 445: does just as well and beyond which memcpy does better. For the 446: m88110, we tend to assume double word alignment, but also analyze 447: the word aligned cases. The analysis is complicated because memcpy 448: may use the cache control instructions for better performance. */ 449: 450: #define MOVSTR_QI_LIMIT_88100 13 451: #define MOVSTR_HI_LIMIT_88100 38 452: #define MOVSTR_SI_LIMIT_88100 MOVSTR_SI 453: #define MOVSTR_DI_LIMIT_88100 MOVSTR_SI 454: 455: #define MOVSTR_QI_LIMIT_88000 16 456: #define MOVSTR_HI_LIMIT_88000 38 457: #define MOVSTR_SI_LIMIT_88000 72 458: #define MOVSTR_DI_LIMIT_88000 72 459: 460: #define MOVSTR_QI_LIMIT_88110 16 461: #define MOVSTR_HI_LIMIT_88110 38 462: #define MOVSTR_SI_LIMIT_88110 72 463: #define MOVSTR_DI_LIMIT_88110 72 464: 465: static enum machine_mode mode_from_align[] = 466: {VOIDmode, QImode, HImode, VOIDmode, SImode, 467: VOIDmode, VOIDmode, VOIDmode, DImode}; 468: static int max_from_align[] = {0, MOVSTR_QI, MOVSTR_HI, 0, MOVSTR_SI, 469: 0, 0, 0, MOVSTR_DI}; 470: static int all_from_align[] = {0, MOVSTR_QI, MOVSTR_ODD_HI, 0, MOVSTR_ODD_SI, 471: 0, 0, 0, MOVSTR_ODD_DI}; 472: 473: static int best_from_align[3][9] = 474: {0, MOVSTR_QI_LIMIT_88100, MOVSTR_HI_LIMIT_88100, 0, MOVSTR_SI_LIMIT_88100, 475: 0, 0, 0, MOVSTR_DI_LIMIT_88100, 476: 0, MOVSTR_QI_LIMIT_88110, MOVSTR_HI_LIMIT_88110, 0, MOVSTR_SI_LIMIT_88110, 477: 0, 0, 0, MOVSTR_DI_LIMIT_88110, 478: 0, MOVSTR_QI_LIMIT_88000, MOVSTR_HI_LIMIT_88000, 0, MOVSTR_SI_LIMIT_88000, 479: 0, 0, 0, MOVSTR_DI_LIMIT_88000}; 480: 481: static void block_move_loop (); 482: static void block_move_no_loop (); 483: static void block_move_sequence (); 484: 485: /* Emit code to perform a block move. Choose the best method. 486: 487: OPERANDS[0] is the destination. 488: OPERANDS[1] is the source. 489: OPERANDS[2] is the size. 490: OPERANDS[3] is the alignment safe to use. */ 491: 492: void 493: expand_block_move (dest_mem, src_mem, operands) 494: rtx dest_mem; 495: rtx src_mem; 496: rtx *operands; 497: { 498: int align = INTVAL (operands[3]); 499: int constp = (GET_CODE (operands[2]) == CONST_INT); 500: int bytes = (constp ? INTVAL (operands[2]) : 0); 501: int target = (int) m88k_cpu; 502: 1.1.1.3 ! root 503: assert (PROCESSOR_M88100 == 0); ! 504: assert (PROCESSOR_M88110 == 1); ! 505: assert (PROCESSOR_M88000 == 2); 1.1 root 506: 507: if (constp && bytes <= 0) 508: return; 509: 510: /* Determine machine mode to do move with. */ 511: if (align > 4 && !TARGET_88110) 512: align = 4; 513: else if (align <= 0 || align == 3) 514: abort (); /* block move invalid alignment. */ 515: 516: if (constp && bytes <= 3 * align) 517: block_move_sequence (operands[0], dest_mem, operands[1], src_mem, 518: bytes, align, 0); 519: 520: else if (constp && bytes <= best_from_align[target][align]) 521: block_move_no_loop (operands[0], dest_mem, operands[1], src_mem, 522: bytes, align); 523: 524: else if (constp && align == 4 && TARGET_88100) 525: block_move_loop (operands[0], dest_mem, operands[1], src_mem, 526: bytes, align); 527: 528: else 529: { 530: #ifdef TARGET_MEM_FUNCTIONS 531: emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memcpy"), 0, 532: VOIDmode, 3, 533: operands[0], Pmode, 534: operands[1], Pmode, 535: operands[2], SImode); 536: #else 537: emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "bcopy"), 0, 538: VOIDmode, 3, 539: operands[1], Pmode, 540: operands[0], Pmode, 541: operands[2], SImode); 542: #endif 543: } 544: } 545: 546: /* Emit code to perform a block move by calling a looping movstr library 547: function. SIZE and ALIGN are known constants. DEST and SRC are 548: registers. */ 549: 550: static void 551: block_move_loop (dest, dest_mem, src, src_mem, size, align) 552: rtx dest, dest_mem; 553: rtx src, src_mem; 554: int size; 555: int align; 556: { 557: enum machine_mode mode; 558: int count; 559: int units; 560: int remainder; 561: rtx offset_rtx; 562: rtx value_rtx; 563: char entry[30]; 564: tree entry_name; 565: 566: /* Determine machine mode to do move with. */ 567: if (align != 4) 568: abort (); 569: 570: /* Determine the structure of the loop. */ 571: count = size / MOVSTR_LOOP; 572: units = (size - count * MOVSTR_LOOP) / align; 573: 574: if (units < 2) 575: { 576: count--; 577: units += MOVSTR_LOOP / align; 578: } 579: 580: if (count <= 0) 581: { 582: block_move_no_loop (dest, dest_mem, src, src_mem, size, align); 583: return; 584: } 585: 586: remainder = size - count * MOVSTR_LOOP - units * align; 587: 588: mode = mode_from_align[align]; 589: sprintf (entry, "__movstr%s%dn%d", 590: GET_MODE_NAME (mode), MOVSTR_LOOP, units * align); 591: entry_name = get_identifier (entry); 592: 593: offset_rtx = gen_rtx (CONST_INT, VOIDmode, 594: MOVSTR_LOOP + (1 - units) * align); 595: 596: value_rtx = gen_rtx (MEM, MEM_IN_STRUCT_P (src_mem) ? mode : BLKmode, 597: gen_rtx (PLUS, Pmode, 598: gen_rtx (REG, Pmode, 3), 599: offset_rtx)); 600: RTX_UNCHANGING_P (value_rtx) = RTX_UNCHANGING_P (src_mem); 601: MEM_VOLATILE_P (value_rtx) = MEM_VOLATILE_P (src_mem); 1.1.1.3 ! root 602: MEM_IN_STRUCT_P (value_rtx) = MEM_IN_STRUCT_P (src_mem); 1.1 root 603: 604: emit_insn (gen_call_movstrsi_loop 605: (gen_rtx (SYMBOL_REF, Pmode, IDENTIFIER_POINTER (entry_name)), 606: dest, src, offset_rtx, value_rtx, 607: gen_rtx (REG, mode, ((units & 1) ? 4 : 5)), 608: gen_rtx (CONST_INT, VOIDmode, count))); 609: 610: if (remainder) 611: block_move_sequence (gen_rtx (REG, Pmode, 2), dest_mem, 612: gen_rtx (REG, Pmode, 3), src_mem, 613: remainder, align, MOVSTR_LOOP + align); 614: } 615: 616: /* Emit code to perform a block move by calling a non-looping library 617: function. SIZE and ALIGN are known constants. DEST and SRC are 618: registers. OFFSET is the known starting point for the output pattern. */ 619: 620: static void 621: block_move_no_loop (dest, dest_mem, src, src_mem, size, align) 622: rtx dest, dest_mem; 623: rtx src, src_mem; 624: int size; 625: int align; 626: { 627: enum machine_mode mode = mode_from_align[align]; 628: int units = size / align; 629: int remainder = size - units * align; 630: int most; 631: int value_reg; 632: rtx offset_rtx; 633: rtx value_rtx; 634: char entry[30]; 635: tree entry_name; 636: 637: if (remainder && size <= all_from_align[align]) 638: { 639: most = all_from_align[align] - (align - remainder); 640: remainder = 0; 641: } 642: else 643: { 644: most = max_from_align[align]; 645: } 646: 647: sprintf (entry, "__movstr%s%dx%d", 648: GET_MODE_NAME (mode), most, size - remainder); 649: entry_name = get_identifier (entry); 650: 651: offset_rtx = gen_rtx (CONST_INT, VOIDmode, most - (size - remainder)); 652: 653: value_rtx = gen_rtx (MEM, MEM_IN_STRUCT_P (src_mem) ? mode : BLKmode, 654: gen_rtx (PLUS, Pmode, 655: gen_rtx (REG, Pmode, 3), 656: offset_rtx)); 657: RTX_UNCHANGING_P (value_rtx) = RTX_UNCHANGING_P (src_mem); 658: MEM_VOLATILE_P (value_rtx) = MEM_VOLATILE_P (src_mem); 1.1.1.3 ! root 659: MEM_IN_STRUCT_P (value_rtx) = MEM_IN_STRUCT_P (src_mem); 1.1 root 660: 661: value_reg = ((((most - (size - remainder)) / align) & 1) == 0 662: ? (align == 8 ? 6 : 5) : 4); 663: 664: emit_insn (gen_call_block_move 665: (gen_rtx (SYMBOL_REF, Pmode, IDENTIFIER_POINTER (entry_name)), 666: dest, src, offset_rtx, value_rtx, 667: gen_rtx (REG, mode, value_reg))); 668: 669: if (remainder) 670: block_move_sequence (gen_rtx (REG, Pmode, 2), dest_mem, 671: gen_rtx (REG, Pmode, 3), src_mem, 672: remainder, align, most); 673: } 674: 675: /* Emit code to perform a block move with an offset sequence of ld/st 676: instructions (..., ld 0, st 1, ld 1, st 0, ...). SIZE and ALIGN are 677: known constants. DEST and SRC are registers. OFFSET is the known 678: starting point for the output pattern. */ 679: 680: static void 681: block_move_sequence (dest, dest_mem, src, src_mem, size, align, offset) 682: rtx dest, dest_mem; 683: rtx src, src_mem; 684: int size; 685: int align; 686: int offset; 687: { 688: rtx temp[2]; 689: enum machine_mode mode[2]; 690: int amount[2]; 691: int active[2]; 692: int phase = 0; 693: int next; 694: int offset_ld = offset; 695: int offset_st = offset; 696: 697: active[0] = active[1] = FALSE; 698: 699: /* Establish parameters for the first load and for the second load if 700: it is known to be the same mode as the first. */ 701: amount[0] = amount[1] = align; 702: mode[0] = mode_from_align[align]; 703: temp[0] = gen_reg_rtx (mode[0]); 704: if (size >= 2 * align) 705: { 706: mode[1] = mode[0]; 707: temp[1] = gen_reg_rtx (mode[1]); 708: } 709: 710: do 711: { 712: rtx srcp, dstp; 713: next = phase; 714: phase = !phase; 715: 716: if (size > 0) 717: { 718: /* Change modes as the sequence tails off. */ 719: if (size < amount[next]) 720: { 721: amount[next] = (size >= 4 ? 4 : (size >= 2 ? 2 : 1)); 722: mode[next] = mode_from_align[amount[next]]; 723: temp[next] = gen_reg_rtx (mode[next]); 724: } 725: size -= amount[next]; 726: srcp = gen_rtx (MEM, 727: MEM_IN_STRUCT_P (src_mem) ? mode[next] : BLKmode, 728: gen_rtx (PLUS, Pmode, src, 729: gen_rtx (CONST_INT, SImode, offset_ld))); 730: RTX_UNCHANGING_P (srcp) = RTX_UNCHANGING_P (src_mem); 731: MEM_VOLATILE_P (srcp) = MEM_VOLATILE_P (src_mem); 1.1.1.3 ! root 732: MEM_IN_STRUCT_P (srcp) = MEM_IN_STRUCT_P (src_mem); 1.1 root 733: emit_insn (gen_rtx (SET, VOIDmode, temp[next], srcp)); 734: offset_ld += amount[next]; 735: active[next] = TRUE; 736: } 737: 738: if (active[phase]) 739: { 740: active[phase] = FALSE; 741: dstp = gen_rtx (MEM, 742: MEM_IN_STRUCT_P (dest_mem) ? mode[phase] : BLKmode, 743: gen_rtx (PLUS, Pmode, dest, 744: gen_rtx (CONST_INT, SImode, offset_st))); 745: RTX_UNCHANGING_P (dstp) = RTX_UNCHANGING_P (dest_mem); 746: MEM_VOLATILE_P (dstp) = MEM_VOLATILE_P (dest_mem); 1.1.1.3 ! root 747: MEM_IN_STRUCT_P (dstp) = MEM_IN_STRUCT_P (dest_mem); 1.1 root 748: emit_insn (gen_rtx (SET, VOIDmode, dstp, temp[phase])); 749: offset_st += amount[phase]; 750: } 751: } 752: while (active[next]); 753: } 754: 755: /* Emit the code to do an AND operation. */ 756: 757: char * 758: output_and (operands) 759: rtx operands[]; 760: { 761: unsigned int value; 762: 763: if (REG_P (operands[2])) 764: return "and %0,%1,%2"; 765: 766: value = INTVAL (operands[2]); 767: if (SMALL_INTVAL (value)) 768: return "mask %0,%1,%2"; 769: else if ((value & 0xffff0000) == 0xffff0000) 770: return "and %0,%1,%x2"; 771: else if ((value & 0xffff) == 0xffff) 772: return "and.u %0,%1,%X2"; 773: else if ((value & 0xffff) == 0) 774: return "mask.u %0,%1,%X2"; 775: else if (integer_ok_for_set (~value)) 776: return "clr %0,%1,%S2"; 777: else 778: return "and.u %0,%1,%X2\n\tand %0,%0,%x2"; 779: } 780: 781: /* Emit the code to do an inclusive OR operation. */ 782: 783: char * 784: output_ior (operands) 785: rtx operands[]; 786: { 787: unsigned int value; 788: 789: if (REG_P (operands[2])) 790: return "or %0,%1,%2"; 791: 792: value = INTVAL (operands[2]); 793: if (SMALL_INTVAL (value)) 794: return "or %0,%1,%2"; 795: else if ((value & 0xffff) == 0) 796: return "or.u %0,%1,%X2"; 797: else if (integer_ok_for_set (value)) 798: return "set %0,%1,%s2"; 799: else 800: return "or.u %0,%1,%X2\n\tor %0,%0,%x2"; 801: } 802: 803: /* Emit the instructions for doing an XOR. */ 804: 805: char * 806: output_xor (operands) 807: rtx operands[]; 808: { 809: unsigned int value; 810: 811: if (REG_P (operands[2])) 812: return "xor %0,%1,%2"; 813: 814: value = INTVAL (operands[2]); 815: if (SMALL_INTVAL (value)) 816: return "xor %0,%1,%2"; 817: else if ((value & 0xffff) == 0) 818: return "xor.u %0,%1,%X2"; 819: else 820: return "xor.u %0,%1,%X2\n\txor %0,%0,%x2"; 821: } 822: 823: /* Output a call. Normally this is just bsr or jsr, but this also deals with 824: accomplishing a branch after the call by incrementing r1. This requires 825: that various assembler bugs be accommodated. The 4.30 DG/UX assembler 826: requires that forward references not occur when computing the difference of 827: two labels. The [version?] Motorola assembler computes a word difference. 828: No doubt there's more to come! 829: 830: It would seem the same idea could be used to tail call, but in this case, 831: the epilogue will be non-null. */ 832: 833: static rtx sb_name = 0; 834: static rtx sb_high = 0; 835: static rtx sb_low = 0; 836: 837: char * 838: output_call (operands, addr) 839: rtx operands[]; 840: rtx addr; 841: { 842: operands[0] = addr; 843: if (final_sequence) 844: { 845: rtx jump; 846: rtx seq_insn; 847: 848: /* This can be generalized, but there is currently no need. */ 849: if (XVECLEN (final_sequence, 0) != 2) 850: abort (); 851: 852: /* The address of interior insns is not computed, so use the sequence. */ 853: seq_insn = NEXT_INSN (PREV_INSN (XVECEXP (final_sequence, 0, 0))); 854: jump = XVECEXP (final_sequence, 0, 1); 855: if (GET_CODE (jump) == JUMP_INSN) 856: { 857: rtx low, high; 858: char *last; 859: rtx dest = XEXP (SET_SRC (PATTERN (jump)), 0); 860: int delta = 4 * (insn_addresses[INSN_UID (dest)] 861: - insn_addresses[INSN_UID (seq_insn)] 862: - 2); 863: #if (MONITOR_GCC & 0x2) /* How often do long branches happen? */ 864: if ((unsigned) (delta + 0x8000) >= 0x10000) 865: warning ("Internal gcc monitor: short-branch(%x)", delta); 866: #endif 867: 868: /* Delete the jump. */ 869: PUT_CODE (jump, NOTE); 870: NOTE_LINE_NUMBER (jump) = NOTE_INSN_DELETED; 871: NOTE_SOURCE_FILE (jump) = 0; 872: 873: /* We only do this optimization if -O2, modifying the value of 874: r1 in the delay slot confuses debuggers and profilers on some 875: systems. 876: 877: If we loose, we must use the non-delay form. This is unlikely 878: to ever happen. If it becomes a problem, claim that a call 879: has two delay slots and only the second can be filled with 1.1.1.2 root 880: a jump. 881: 882: The 88110 can lose when a jsr.n r1 is issued and a page fault 883: occurs accessing the delay slot. So don't use jsr.n form when 884: jumping thru r1. 885: */ 1.1 root 886: #ifdef AS_BUG_IMMEDIATE_LABEL /* The assembler restricts immediate values. */ 887: if (optimize < 2 1.1.1.2 root 888: || ! ADD_INTVAL (delta * 2) 1.1 root 889: #else 890: if (optimize < 2 1.1.1.2 root 891: || ! ADD_INTVAL (delta) 1.1 root 892: #endif 1.1.1.2 root 893: || (REG_P (addr) && REGNO (addr) == 1)) 1.1 root 894: { 895: operands[1] = dest; 896: return (REG_P (addr) 897: ? "jsr %0\n\tbr %l1" 898: : (flag_pic 899: ? "bsr %0#plt\n\tbr %l1" 900: : "bsr %0\n\tbr %l1")); 901: } 902: 903: /* Output the short branch form. */ 904: output_asm_insn ((REG_P (addr) 905: ? "jsr.n %0" 906: : (flag_pic ? "bsr.n %0#plt" : "bsr.n %0")), 907: operands); 908: 909: #ifdef USE_GAS 910: last = (delta < 0 911: ? "subu %#r1,%#r1,.-%l0+4" 912: : "addu %#r1,%#r1,%l0-.-4"); 913: operands[0] = dest; 914: #else 915: operands[0] = gen_label_rtx (); 916: operands[1] = gen_label_rtx (); 917: if (delta < 0) 918: { 919: low = dest; 920: high = operands[1]; 921: last = "subu %#r1,%#r1,%l0\n%l1:"; 922: } 923: else 924: { 925: low = operands[1]; 926: high = dest; 927: last = "addu %#r1,%#r1,%l0\n%l1:"; 928: } 929: 930: /* Record the values to be computed later as "def name,high-low". */ 931: sb_name = gen_rtx (EXPR_LIST, VOIDmode, operands[0], sb_name); 932: sb_high = gen_rtx (EXPR_LIST, VOIDmode, high, sb_high); 933: sb_low = gen_rtx (EXPR_LIST, VOIDmode, low, sb_low); 934: #endif /* Don't USE_GAS */ 935: 936: return last; 937: } 938: } 939: return (REG_P (addr) 940: ? "jsr%. %0" 941: : (flag_pic ? "bsr%. %0#plt" : "bsr%. %0")); 942: } 943: 944: static void 945: output_short_branch_defs (stream) 946: FILE *stream; 947: { 948: char name[256], high[256], low[256]; 949: 950: for (; sb_name && sb_high && sb_low; 951: sb_name = XEXP (sb_name, 1), 952: sb_high = XEXP (sb_high, 1), 953: sb_low = XEXP (sb_low, 1)) 954: { 955: ASM_GENERATE_INTERNAL_LABEL 956: (name, "L", CODE_LABEL_NUMBER (XEXP (sb_name, 0))); 957: ASM_GENERATE_INTERNAL_LABEL 958: (high, "L", CODE_LABEL_NUMBER (XEXP (sb_high, 0))); 959: ASM_GENERATE_INTERNAL_LABEL 960: (low, "L", CODE_LABEL_NUMBER (XEXP (sb_low, 0))); 961: /* This will change as the assembler requirements become known. */ 962: fprintf (stream, "\t%s\t %s,%s-%s\n", 963: SET_ASM_OP, &name[1], &high[1], &low[1]); 964: } 965: if (sb_name || sb_high || sb_low) 966: abort (); 967: } 968: 969: /* Return truth value of the statement that this conditional branch is likely 970: to fall through. CONDITION, is the condition that JUMP_INSN is testing. */ 971: 972: int 973: mostly_false_jump (jump_insn, condition) 974: rtx jump_insn, condition; 975: { 976: rtx target_label = JUMP_LABEL (jump_insn); 977: rtx insnt, insnj; 978: 979: /* Much of this isn't computed unless we're optimizing. */ 980: if (optimize == 0) 981: return 0; 982: 983: /* Determine if one path or the other leads to a return. */ 984: for (insnt = NEXT_INSN (target_label); 985: insnt; 986: insnt = NEXT_INSN (insnt)) 987: { 988: if (GET_CODE (insnt) == JUMP_INSN) 989: break; 990: else if (GET_CODE (insnt) == INSN 991: && GET_CODE (PATTERN (insnt)) == SEQUENCE 992: && GET_CODE (XVECEXP (PATTERN (insnt), 0, 0)) == JUMP_INSN) 993: { 994: insnt = XVECEXP (PATTERN (insnt), 0, 0); 995: break; 996: } 997: } 998: if (insnt 999: && (GET_CODE (PATTERN (insnt)) == RETURN 1000: || (GET_CODE (PATTERN (insnt)) == SET 1001: && GET_CODE (SET_SRC (PATTERN (insnt))) == REG 1002: && REGNO (SET_SRC (PATTERN (insnt))) == 1))) 1003: insnt = 0; 1004: 1005: for (insnj = NEXT_INSN (jump_insn); 1006: insnj; 1007: insnj = NEXT_INSN (insnj)) 1008: { 1009: if (GET_CODE (insnj) == JUMP_INSN) 1010: break; 1011: else if (GET_CODE (insnj) == INSN 1012: && GET_CODE (PATTERN (insnj)) == SEQUENCE 1013: && GET_CODE (XVECEXP (PATTERN (insnj), 0, 0)) == JUMP_INSN) 1014: { 1015: insnj = XVECEXP (PATTERN (insnj), 0, 0); 1016: break; 1017: } 1018: } 1019: if (insnj 1020: && (GET_CODE (PATTERN (insnj)) == RETURN 1021: || (GET_CODE (PATTERN (insnj)) == SET 1022: && GET_CODE (SET_SRC (PATTERN (insnj))) == REG 1023: && REGNO (SET_SRC (PATTERN (insnj))) == 1))) 1024: insnj = 0; 1025: 1026: /* Predict to not return. */ 1027: if ((insnt == 0) != (insnj == 0)) 1028: return (insnt == 0); 1029: 1030: /* Predict loops to loop. */ 1031: for (insnt = PREV_INSN (target_label); 1032: insnt && GET_CODE (insnt) == NOTE; 1033: insnt = PREV_INSN (insnt)) 1034: if (NOTE_LINE_NUMBER (insnt) == NOTE_INSN_LOOP_END) 1035: return 1; 1036: else if (NOTE_LINE_NUMBER (insnt) == NOTE_INSN_LOOP_BEG) 1037: return 0; 1038: else if (NOTE_LINE_NUMBER (insnt) == NOTE_INSN_LOOP_CONT) 1039: return 0; 1040: 1041: /* Predict backward branches usually take. */ 1042: if (final_sequence) 1043: insnj = NEXT_INSN (PREV_INSN (XVECEXP (final_sequence, 0, 0))); 1044: else 1045: insnj = jump_insn; 1046: if (insn_addresses[INSN_UID (insnj)] 1047: > insn_addresses[INSN_UID (target_label)]) 1048: return 0; 1049: 1050: /* EQ tests are usually false and NE tests are usually true. Also, 1051: most quantities are positive, so we can make the appropriate guesses 1052: about signed comparisons against zero. Consider unsigned comparisons 1053: to be a range check and assume quantities to be in range. */ 1054: switch (GET_CODE (condition)) 1055: { 1056: case CONST_INT: 1057: /* Unconditional branch. */ 1058: return 0; 1059: case EQ: 1060: return 1; 1061: case NE: 1062: return 0; 1063: case LE: 1064: case LT: 1065: case GEU: 1066: case GTU: /* Must get casesi right at least. */ 1067: if (XEXP (condition, 1) == const0_rtx) 1068: return 1; 1069: break; 1070: case GE: 1071: case GT: 1072: case LEU: 1073: case LTU: 1074: if (XEXP (condition, 1) == const0_rtx) 1075: return 0; 1076: break; 1077: } 1078: 1079: return 0; 1080: } 1081: 1082: /* Return true if the operand is a power of two and is a floating 1083: point type (to optimize division by power of two into multiplication). */ 1084: 1085: int 1086: real_power_of_2_operand (op, mode) 1087: rtx op; 1088: enum machine_mode mode; 1089: { 1090: union { 1091: REAL_VALUE_TYPE d; 1092: int i[sizeof (REAL_VALUE_TYPE) / sizeof (int)]; 1093: struct { /* IEEE double precision format */ 1094: unsigned sign : 1; 1095: unsigned exponent : 11; 1096: unsigned mantissa1 : 20; 1097: unsigned mantissa2; 1098: } s; 1099: struct { /* IEEE double format to quick check */ 1100: unsigned sign : 1; /* if it fits in a float */ 1101: unsigned exponent1 : 4; 1102: unsigned exponent2 : 7; 1103: unsigned mantissa1 : 20; 1104: unsigned mantissa2; 1105: } s2; 1106: } u; 1107: 1108: if (GET_MODE (op) != DFmode && GET_MODE (op) != SFmode) 1109: return 0; 1110: 1111: if (GET_CODE (op) != CONST_DOUBLE) 1112: return 0; 1113: 1114: u.i[0] = CONST_DOUBLE_LOW (op); 1115: u.i[1] = CONST_DOUBLE_HIGH (op); 1116: 1117: if (u.s.mantissa1 != 0 || u.s.mantissa2 != 0 /* not a power of two */ 1118: || u.s.exponent == 0 /* constant 0.0 */ 1119: || u.s.exponent == 0x7ff /* NAN */ 1120: || (u.s2.exponent1 != 0x8 && u.s2.exponent1 != 0x7)) 1121: return 0; /* const won't fit in float */ 1122: 1123: return 1; 1124: } 1125: 1126: /* Make OP legitimate for mode MODE. Currently this only deals with DFmode 1127: operands, putting them in registers and making CONST_DOUBLE values 1128: SFmode where possible. */ 1129: 1130: struct rtx_def * 1131: legitimize_operand (op, mode) 1132: rtx op; 1133: enum machine_mode mode; 1134: { 1135: rtx temp; 1136: union { 1137: union real_extract r; 1138: struct { /* IEEE double precision format */ 1139: unsigned sign : 1; 1140: unsigned exponent : 11; 1141: unsigned mantissa1 : 20; 1142: unsigned mantissa2; 1143: } d; 1144: struct { /* IEEE double format to quick check */ 1145: unsigned sign : 1; /* if it fits in a float */ 1146: unsigned exponent1 : 4; 1147: unsigned exponent2 : 7; 1148: unsigned mantissa1 : 20; 1149: unsigned mantissa2; 1150: } s; 1151: } u; 1152: 1153: if (GET_CODE (op) == REG || mode != DFmode) 1154: return op; 1155: 1156: if (GET_CODE (op) == CONST_DOUBLE) 1157: { 1158: bcopy (&CONST_DOUBLE_LOW (op), &u.r, sizeof u); 1159: if (u.d.exponent != 0x7ff /* NaN */ 1160: && u.d.mantissa2 == 0 /* Mantissa fits */ 1161: && (u.s.exponent1 == 0x8 || u.s.exponent1 == 0x7) /* Exponent fits */ 1162: && (temp = simplify_unary_operation (FLOAT_TRUNCATE, SFmode, 1163: op, mode)) != 0) 1164: return gen_rtx (FLOAT_EXTEND, mode, force_reg (SFmode, temp)); 1165: } 1166: else if (register_operand (op, mode)) 1167: return op; 1168: 1169: return force_reg (mode, op); 1170: } 1171: 1172: /* Return true if OP is a suitable input for a move insn. */ 1173: 1174: int 1175: move_operand (op, mode) 1176: rtx op; 1177: enum machine_mode mode; 1178: { 1179: if (register_operand (op, mode)) 1180: return 1; 1181: if (GET_CODE (op) == CONST_INT) 1182: return (classify_integer (mode, INTVAL (op)) < m88k_oru_hi16); 1183: if (GET_MODE (op) != mode) 1184: return 0; 1185: if (GET_CODE (op) == SUBREG) 1186: op = SUBREG_REG (op); 1187: if (GET_CODE (op) != MEM) 1188: return 0; 1189: 1190: op = XEXP (op, 0); 1191: if (GET_CODE (op) == LO_SUM) 1192: return (REG_P (XEXP (op, 0)) 1193: && symbolic_address_p (XEXP (op, 1))); 1194: return memory_address_p (mode, op); 1195: } 1196: 1197: /* Return true if OP is suitable for a call insn. */ 1198: 1199: int 1200: call_address_operand (op, mode) 1201: rtx op; 1202: enum machine_mode mode; 1203: { 1204: return (REG_P (op) || symbolic_address_p (op)); 1205: } 1206: 1207: /* Returns true if OP is either a symbol reference or a sum of a symbol 1208: reference and a constant. */ 1209: 1210: int 1211: symbolic_address_p (op) 1212: register rtx op; 1213: { 1214: switch (GET_CODE (op)) 1215: { 1216: case SYMBOL_REF: 1217: case LABEL_REF: 1218: return 1; 1219: 1220: case CONST: 1221: op = XEXP (op, 0); 1222: return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF 1223: || GET_CODE (XEXP (op, 0)) == LABEL_REF) 1224: && GET_CODE (XEXP (op, 1)) == CONST_INT); 1225: 1226: default: 1227: return 0; 1228: } 1229: } 1230: 1231: /* Return true if OP is a register or const0_rtx. */ 1232: 1233: int 1234: reg_or_0_operand (op, mode) 1235: rtx op; 1236: enum machine_mode mode; 1237: { 1238: return (op == const0_rtx || register_operand (op, mode)); 1239: } 1240: 1241: /* Nonzero if OP is a valid second operand for an arithmetic insn. */ 1242: 1243: int 1244: arith_operand (op, mode) 1245: rtx op; 1246: enum machine_mode mode; 1247: { 1248: return (register_operand (op, mode) 1249: || (GET_CODE (op) == CONST_INT && SMALL_INT (op))); 1250: } 1251: 1252: /* Return true if OP is a register or 5 bit integer. */ 1253: 1254: int 1255: arith5_operand (op, mode) 1256: rtx op; 1257: enum machine_mode mode; 1258: { 1259: return (register_operand (op, mode) 1260: || (GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 32)); 1261: } 1262: 1263: int 1264: arith32_operand (op, mode) 1265: rtx op; 1266: enum machine_mode mode; 1267: { 1268: return (register_operand (op, mode) || GET_CODE (op) == CONST_INT); 1269: } 1270: 1271: int 1272: arith64_operand (op, mode) 1273: rtx op; 1274: enum machine_mode mode; 1275: { 1276: return (register_operand (op, mode) 1277: || GET_CODE (op) == CONST_INT 1.1.1.3 ! root 1278: || (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == VOIDmode)); 1.1 root 1279: } 1280: 1281: int 1282: int5_operand (op, mode) 1283: rtx op; 1284: enum machine_mode mode; 1285: { 1286: return (GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 32); 1287: } 1288: 1289: int 1290: int32_operand (op, mode) 1291: rtx op; 1292: enum machine_mode mode; 1293: { 1294: return (GET_CODE (op) == CONST_INT); 1295: } 1296: 1297: /* Return true if OP is a register or a valid immediate operand for 1298: addu or subu. */ 1299: 1300: int 1301: add_operand (op, mode) 1302: rtx op; 1303: enum machine_mode mode; 1304: { 1305: return (register_operand (op, mode) 1306: || (GET_CODE (op) == CONST_INT && ADD_INT (op))); 1307: } 1308: 1309: /* Nonzero if this is a bitmask filling the bottom bits, for optimizing and + 1310: shift left combinations into a single mak instruction. */ 1311: 1312: int 1313: mak_mask_p (value) 1314: int value; 1315: { 1316: return (value && POWER_OF_2_or_0 (value + 1)); 1317: } 1318: 1319: int 1320: reg_or_bbx_mask_operand (op, mode) 1321: rtx op; 1322: enum machine_mode mode; 1323: { 1324: int value; 1325: if (register_operand (op, mode)) 1326: return 1; 1327: if (GET_CODE (op) != CONST_INT) 1328: return 0; 1329: 1330: value = INTVAL (op); 1331: if (POWER_OF_2 (value)) 1332: return 1; 1333: 1334: return 0; 1335: } 1336: 1337: /* Return true if OP is valid to use in the context of a floating 1338: point operation. Special case 0.0, since we can use r0. */ 1339: 1340: int 1341: real_or_0_operand (op, mode) 1342: rtx op; 1343: enum machine_mode mode; 1344: { 1345: if (mode != SFmode && mode != DFmode) 1346: return 0; 1347: 1348: return (register_operand (op, mode) 1349: || (GET_CODE (op) == CONST_DOUBLE 1350: && op == CONST0_RTX (mode))); 1351: } 1352: 1.1.1.2 root 1353: /* Return true if OP is valid to use in the context of logic aritmethic 1354: on condition codes. */ 1355: 1356: int 1357: partial_ccmode_register_operand (op, mode) 1358: rtx op; 1359: enum machine_mode mode; 1360: { 1361: return register_operand (op, CCmode) || register_operand (op, CCEVENmode); 1362: } 1363: 1.1 root 1364: /* Return true if OP is a relational operator. */ 1365: 1366: int 1367: relop (op, mode) 1368: rtx op; 1369: enum machine_mode mode; 1370: { 1371: switch (GET_CODE (op)) 1372: { 1373: case EQ: 1374: case NE: 1375: case LT: 1376: case LE: 1377: case GE: 1378: case GT: 1379: case LTU: 1380: case LEU: 1381: case GEU: 1382: case GTU: 1383: return 1; 1384: default: 1385: return 0; 1386: } 1387: } 1388: 1.1.1.2 root 1389: int 1390: even_relop (op, mode) 1391: rtx op; 1392: enum machine_mode mode; 1393: { 1394: switch (GET_CODE (op)) 1395: { 1396: case EQ: 1397: case LT: 1398: case GT: 1399: case LTU: 1400: case GTU: 1401: return 1; 1402: default: 1403: return 0; 1404: } 1405: } 1406: 1407: int 1408: odd_relop (op, mode) 1409: rtx op; 1410: enum machine_mode mode; 1411: { 1412: switch (GET_CODE (op)) 1413: { 1414: case NE: 1415: case LE: 1416: case GE: 1417: case LEU: 1418: case GEU: 1419: return 1; 1420: default: 1421: return 0; 1422: } 1423: } 1424: 1.1 root 1425: /* Return true if OP is a relational operator, and is not an unsigned 1426: relational operator. */ 1427: 1428: int 1429: relop_no_unsigned (op, mode) 1430: rtx op; 1431: enum machine_mode mode; 1432: { 1433: switch (GET_CODE (op)) 1434: { 1435: case EQ: 1436: case NE: 1437: case LT: 1438: case LE: 1439: case GE: 1440: case GT: 1441: /* @@ What is this test doing? Why not use `mode'? */ 1442: if (GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT 1443: || GET_MODE (op) == DImode 1444: || GET_MODE_CLASS (GET_MODE (XEXP (op, 0))) == MODE_FLOAT 1445: || GET_MODE (XEXP (op, 0)) == DImode 1446: || GET_MODE_CLASS (GET_MODE (XEXP (op, 1))) == MODE_FLOAT 1447: || GET_MODE (XEXP (op, 1)) == DImode) 1448: return 0; 1449: return 1; 1450: default: 1451: return 0; 1452: } 1453: } 1454: 1455: /* Return true if the code of this rtx pattern is EQ or NE. */ 1456: 1457: int 1458: equality_op (op, mode) 1459: rtx op; 1460: enum machine_mode mode; 1461: { 1462: return (GET_CODE (op) == EQ || GET_CODE (op) == NE); 1463: } 1464: 1465: /* Return true if the code of this rtx pattern is pc or label_ref. */ 1466: 1467: int 1468: pc_or_label_ref (op, mode) 1469: rtx op; 1470: enum machine_mode mode; 1471: { 1472: return (GET_CODE (op) == PC || GET_CODE (op) == LABEL_REF); 1473: } 1474: 1475: /* Output to FILE the start of the assembler file. */ 1476: 1477: struct option 1478: { 1479: char *string; 1480: int *variable; 1481: int on_value; 1482: }; 1483: 1484: static int 1485: output_option (file, sep, type, name, indent, pos, max) 1486: FILE *file; 1487: char *sep; 1488: char *type; 1489: char *name; 1490: char *indent; 1491: int pos; 1492: int max; 1493: { 1494: if (strlen (sep) + strlen (type) + strlen (name) + pos > max) 1495: { 1496: fprintf (file, indent); 1497: return fprintf (file, "%s%s", type, name); 1498: } 1499: return pos + fprintf (file, "%s%s%s", sep, type, name); 1500: } 1501: 1502: static struct { char *name; int value; } m_options[] = TARGET_SWITCHES; 1503: 1504: static void 1505: output_options (file, f_options, f_len, W_options, W_len, 1506: pos, max, sep, indent, term) 1507: FILE *file; 1508: struct option *f_options; 1509: struct option *W_options; 1510: int f_len, W_len; 1511: int pos; 1512: int max; 1513: char *indent; 1514: char *term; 1515: { 1516: register int j; 1517: 1518: if (optimize) 1519: pos = output_option (file, sep, "-O", "", indent, pos, max); 1520: if (write_symbols != NO_DEBUG) 1521: pos = output_option (file, sep, "-g", "", indent, pos, max); 1522: if (flag_traditional) 1523: pos = output_option (file, sep, "-traditional", "", indent, pos, max); 1524: if (profile_flag) 1525: pos = output_option (file, sep, "-p", "", indent, pos, max); 1526: if (profile_block_flag) 1527: pos = output_option (file, sep, "-a", "", indent, pos, max); 1528: 1529: for (j = 0; j < f_len; j++) 1530: if (*f_options[j].variable == f_options[j].on_value) 1531: pos = output_option (file, sep, "-f", f_options[j].string, 1532: indent, pos, max); 1533: 1534: for (j = 0; j < W_len; j++) 1535: if (*W_options[j].variable == W_options[j].on_value) 1536: pos = output_option (file, sep, "-W", W_options[j].string, 1537: indent, pos, max); 1538: 1539: for (j = 0; j < sizeof m_options / sizeof m_options[0]; j++) 1540: if (m_options[j].name[0] != '\0' 1541: && m_options[j].value > 0 1542: && ((m_options[j].value & target_flags) 1543: == m_options[j].value)) 1544: pos = output_option (file, sep, "-m", m_options[j].name, 1545: indent, pos, max); 1546: 1547: if (m88k_short_data) 1548: pos = output_option (file, sep, "-mshort-data-", m88k_short_data, 1549: indent, pos, max); 1550: 1551: fprintf (file, term); 1552: } 1553: 1554: void 1555: output_file_start (file, f_options, f_len, W_options, W_len) 1556: FILE *file; 1557: struct option *f_options; 1558: struct option *W_options; 1559: int f_len, W_len; 1560: { 1561: register int pos; 1562: 1563: ASM_FIRST_LINE (file); 1564: if (TARGET_88110 1.1.1.3 ! root 1565: && TARGET_SVR4) 1.1 root 1566: fprintf (file, "\t%s\n", REQUIRES_88110_ASM_OP); 1567: output_file_directive (file, main_input_filename); 1568: /* Switch to the data section so that the coffsem symbol and the 1569: gcc2_compiled. symbol aren't in the text section. */ 1570: data_section (); 1571: ASM_COFFSEM (file); 1572: 1573: pos = fprintf (file, "\n; cc1 (%s) arguments:", VERSION_STRING); 1574: output_options (file, f_options, f_len, W_options, W_len, 1575: pos, 75, " ", "\n; ", "\n\n"); 1576: 1577: if (TARGET_IDENTIFY_REVISION) 1578: { 1579: char indent[256]; 1580: 1581: time_t now = time ((time_t *)0); 1582: sprintf (indent, "]\"\n\t%s\t \"@(#)%s [", IDENT_ASM_OP, main_input_filename); 1583: fprintf (file, indent+3); 1584: pos = fprintf (file, "gcc %s, %.24s,", VERSION_STRING, ctime (&now)); 1585: output_options (file, f_options, f_len, W_options, W_len, 1586: pos, 150 - strlen (indent), " ", indent, "]\"\n\n"); 1587: } 1588: } 1589: 1590: /* Output an ascii string. */ 1591: 1592: void 1593: output_ascii (file, opcode, max, p, size) 1594: FILE *file; 1595: char *opcode; 1596: int max; 1597: unsigned char *p; 1598: int size; 1599: { 1600: int i; 1601: int in_escape = 0; 1602: 1603: register int num = 0; 1604: 1605: fprintf (file, "\t%s\t \"", opcode); 1606: for (i = 0; i < size; i++) 1607: { 1608: register int c = p[i]; 1609: 1610: if (num > max) 1611: { 1612: fprintf (file, "\"\n\t%s\t \"", opcode); 1613: num = 0; 1614: } 1615: 1616: if (c == '\"' || c == '\\') 1617: { 1618: escape: 1619: putc ('\\', file); 1620: putc (c, file); 1621: num += 2; 1622: in_escape = 0; 1623: } 1624: else if (in_escape && c >= '0' && c <= '9') 1625: { 1626: /* If a digit follows an octal-escape, the Vax assembler fails 1627: to stop reading the escape after three digits. Continue to 1628: output the values as an octal-escape until a non-digit is 1629: found. */ 1630: fprintf (file, "\\%03o", c); 1631: num += 4; 1632: } 1633: else if (c >= ' ' && c < 0177) 1634: { 1635: putc (c, file); 1636: num++; 1637: in_escape = 0; 1638: } 1639: else 1640: { 1641: switch (c) 1642: { 1643: /* Some assemblers can't handle \a, \v, or \?. */ 1644: case '\t': c = 't'; goto escape; 1645: case '\f': c = 'f'; goto escape; 1646: case '\b': c = 'b'; goto escape; 1647: case '\r': c = 'r'; goto escape; 1648: case '\n': c = 'n'; goto escape; 1649: } 1650: 1651: fprintf (file, "\\%03o", c); 1652: num += 4; 1653: in_escape = 1; 1654: } 1655: } 1656: fprintf (file, "\"\n"); 1657: } 1658: 1659: /* Output a label (allows insn-output.c to be compiled without including 1660: m88k.c or needing to include stdio.h). */ 1661: 1662: void 1663: output_label (label_number) 1664: int label_number; 1665: { 1666: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", label_number); 1667: } 1668: 1669: /* Generate the assembly code for function entry. 1670: 1671: The prologue is responsible for setting up the stack frame, 1672: initializing the frame pointer register, saving registers that must be 1673: saved, and allocating SIZE additional bytes of storage for the 1674: local variables. SIZE is an integer. FILE is a stdio 1675: stream to which the assembler code should be output. 1676: 1677: The label for the beginning of the function need not be output by this 1678: macro. That has already been done when the macro is run. 1679: 1680: To determine which registers to save, the macro can refer to the array 1681: `regs_ever_live': element R is nonzero if hard register 1682: R is used anywhere within the function. This implies the 1683: function prologue should save register R, but not if it is one 1684: of the call-used registers. 1685: 1686: On machines where functions may or may not have frame-pointers, the 1687: function entry code must vary accordingly; it must set up the frame 1688: pointer if one is wanted, and not otherwise. To determine whether a 1689: frame pointer is in wanted, the macro can refer to the variable 1690: `frame_pointer_needed'. The variable's value will be 1 at run 1691: time in a function that needs a frame pointer. 1692: 1693: On machines where an argument may be passed partly in registers and 1694: partly in memory, this macro must examine the variable 1695: `current_function_pretend_args_size', and allocate that many bytes 1696: of uninitialized space on the stack just underneath the first argument 1697: arriving on the stack. (This may not be at the very end of the stack, 1698: if the calling sequence has pushed anything else since pushing the stack 1699: arguments. But usually, on such machines, nothing else has been pushed 1700: yet, because the function prologue itself does all the pushing.) 1701: 1702: If `ACCUMULATE_OUTGOING_ARGS' is defined, the variable 1703: `current_function_outgoing_args_size' contains the size in bytes 1704: required for the outgoing arguments. This macro must add that 1705: amount of uninitialized space to very bottom of the stack. 1706: 1707: The stack frame we use looks like this: 1708: 1709: caller callee 1710: |==============================================| 1711: | caller's frame | 1712: |==============================================| 1713: | [caller's outgoing memory arguments] | 1714: |==============================================| 1715: | caller's outgoing argument area (32 bytes) | 1716: sp -> |==============================================| <- ap 1717: | [local variable space] | 1718: |----------------------------------------------| 1719: | [return address (r1)] | 1720: |----------------------------------------------| 1721: | [previous frame pointer (r30)] | 1722: |==============================================| <- fp 1723: | [preserved registers (r25..r14)] | 1724: |----------------------------------------------| 1725: | [preserved registers (x29..x22)] | 1726: |==============================================| 1727: | [dynamically allocated space (alloca)] | 1728: |==============================================| 1729: | [callee's outgoing memory arguments] | 1730: |==============================================| 1731: | [callee's outgoing argument area (32 bytes)] | 1732: |==============================================| <- sp 1733: 1734: Notes: 1735: 1736: r1 and r30 must be saved if debugging. 1737: 1738: fp (if present) is located two words down from the local 1739: variable space. 1740: */ 1741: 1742: static void emit_add (); 1743: static void preserve_registers (); 1744: static void emit_ldst (); 1745: static void output_tdesc (); 1746: 1747: static int nregs; 1748: static int nxregs; 1749: static char save_regs[FIRST_PSEUDO_REGISTER]; 1750: static int frame_laid_out; 1751: static int frame_size; 1752: static int variable_args_p; 1753: static int epilogue_marked; 1754: static int prologue_marked; 1755: 1756: extern char call_used_regs[]; 1757: extern int current_function_pretend_args_size; 1758: extern int current_function_outgoing_args_size; 1759: extern int frame_pointer_needed; 1760: 1761: #define FIRST_OCS_PRESERVE_REGISTER 14 1762: #define LAST_OCS_PRESERVE_REGISTER 30 1763: 1764: #define FIRST_OCS_EXTENDED_PRESERVE_REGISTER (32 + 22) 1765: #define LAST_OCS_EXTENDED_PRESERVE_REGISTER (32 + 31) 1766: 1767: #define STACK_UNIT_BOUNDARY (STACK_BOUNDARY / BITS_PER_UNIT) 1768: #define ROUND_CALL_BLOCK_SIZE(BYTES) \ 1769: (((BYTES) + (STACK_UNIT_BOUNDARY - 1)) & ~(STACK_UNIT_BOUNDARY - 1)) 1770: 1771: /* Establish the position of the FP relative to the SP. This is done 1772: either during FUNCTION_PROLOGUE or by INITIAL_ELIMINATION_OFFSET. */ 1773: 1774: void 1775: m88k_layout_frame () 1776: { 1777: int regno, sp_size; 1778: 1779: frame_laid_out++; 1780: 1781: bzero ((char *) &save_regs[0], sizeof (save_regs)); 1782: sp_size = nregs = nxregs = 0; 1783: frame_size = get_frame_size (); 1784: 1785: /* Since profiling requires a call, make sure r1 is saved. */ 1786: if (profile_flag || profile_block_flag) 1787: save_regs[1] = 1; 1788: 1789: /* If we are producing debug information, store r1 and r30 where the 1790: debugger wants to find them (r30 at r30+0, r1 at r30+4). Space has 1791: already been reserved for r1/r30 in STARTING_FRAME_OFFSET. */ 1792: if (write_symbols != NO_DEBUG && !TARGET_OCS_FRAME_POSITION) 1793: save_regs[1] = 1; 1794: 1795: /* If there is a call, alloca is used, __builtin_alloca is used, or 1796: a dynamic-sized object is defined, add the 8 additional words 1797: for the callee's argument area. The common denominator is that the 1798: FP is required. may_call_alloca only gets calls to alloca; 1799: current_function_calls_alloca gets alloca and __builtin_alloca. */ 1800: if (regs_ever_live[1] || frame_pointer_needed) 1801: { 1802: save_regs[1] = 1; 1803: sp_size += REG_PARM_STACK_SPACE (0); 1804: } 1805: 1806: /* If we are producing PIC, save the addressing base register and r1. */ 1807: if (flag_pic && current_function_uses_pic_offset_table) 1808: { 1809: save_regs[PIC_OFFSET_TABLE_REGNUM] = 1; 1810: nregs++; 1811: } 1812: 1813: /* If a frame is requested, save the previous FP, and the return 1814: address (r1), so that a traceback can be done without using tdesc 1815: information. Otherwise, simply save the FP if it is used as 1816: a preserve register. */ 1817: if (frame_pointer_needed) 1818: save_regs[FRAME_POINTER_REGNUM] = save_regs[1] = 1; 1819: else if (regs_ever_live[FRAME_POINTER_REGNUM]) 1820: save_regs[FRAME_POINTER_REGNUM] = 1; 1821: 1822: /* Figure out which extended register(s) needs to be saved. */ 1823: for (regno = FIRST_EXTENDED_REGISTER + 1; regno < FIRST_PSEUDO_REGISTER; 1824: regno++) 1825: if (regs_ever_live[regno] && ! call_used_regs[regno]) 1826: { 1827: save_regs[regno] = 1; 1828: nxregs++; 1829: } 1830: 1831: /* Figure out which normal register(s) needs to be saved. */ 1832: for (regno = 2; regno < FRAME_POINTER_REGNUM; regno++) 1833: if (regs_ever_live[regno] && ! call_used_regs[regno]) 1834: { 1835: save_regs[regno] = 1; 1836: nregs++; 1837: } 1838: 1839: /* Achieve greatest use of double memory ops. Either we end up saving 1840: r30 or we use that slot to align the registers we do save. */ 1841: if (nregs >= 2 && save_regs[1] && !save_regs[FRAME_POINTER_REGNUM]) 1842: sp_size += 4; 1843: 1844: nregs += save_regs[1] + save_regs[FRAME_POINTER_REGNUM]; 1845: /* if we need to align extended registers, add a word */ 1846: if (nxregs > 0 && (nregs & 1) != 0) 1847: sp_size +=4; 1848: sp_size += 4 * nregs; 1849: sp_size += 8 * nxregs; 1850: sp_size += current_function_outgoing_args_size; 1851: 1852: /* The first two saved registers are placed above the new frame pointer 1853: if any. In the only case this matters, they are r1 and r30. */ 1854: if (frame_pointer_needed || sp_size) 1855: m88k_fp_offset = ROUND_CALL_BLOCK_SIZE (sp_size - STARTING_FRAME_OFFSET); 1856: else 1857: m88k_fp_offset = -STARTING_FRAME_OFFSET; 1858: m88k_stack_size = m88k_fp_offset + STARTING_FRAME_OFFSET; 1859: 1860: /* First, combine m88k_stack_size and size. If m88k_stack_size is 1861: non-zero, align the frame size to 8 mod 16; otherwise align the 1862: frame size to 0 mod 16. (If stacks are 8 byte aligned, this ends 1863: up as a NOP. */ 1864: { 1865: int need 1866: = ((m88k_stack_size ? STACK_UNIT_BOUNDARY - STARTING_FRAME_OFFSET : 0) 1867: - (frame_size % STACK_UNIT_BOUNDARY)); 1868: if (need) 1869: { 1870: if (need < 0) 1871: need += STACK_UNIT_BOUNDARY; 1872: (void) assign_stack_local (BLKmode, need, BITS_PER_UNIT); 1873: frame_size = get_frame_size (); 1874: } 1875: m88k_stack_size 1876: = ROUND_CALL_BLOCK_SIZE (m88k_stack_size + frame_size 1877: + current_function_pretend_args_size); 1878: } 1879: } 1880: 1881: /* Return true if this function is known to have a null prologue. */ 1882: 1883: int 1884: null_prologue () 1885: { 1886: if (! reload_completed) 1887: return 0; 1888: if (! frame_laid_out) 1889: m88k_layout_frame (); 1890: return (! frame_pointer_needed 1891: && nregs == 0 1892: && nxregs == 0 1893: && m88k_stack_size == 0); 1894: } 1895: 1896: /* Determine if the current function has any references to the arg pointer. 1897: This is done indirectly by examining the DECL_ARGUMENTS' DECL_RTL. 1898: It is OK to return TRUE if there are no references, but FALSE must be 1899: correct. */ 1900: 1901: static int 1902: uses_arg_area_p () 1903: { 1904: register tree parm; 1905: 1906: if (current_function_decl == 0 1907: || current_function_varargs 1908: || variable_args_p) 1909: return 1; 1910: 1911: for (parm = DECL_ARGUMENTS (current_function_decl); 1912: parm; 1913: parm = TREE_CHAIN (parm)) 1914: { 1915: if (DECL_RTL (parm) == 0 1916: || GET_CODE (DECL_RTL (parm)) == MEM) 1917: return 1; 1918: 1919: if (DECL_INCOMING_RTL (parm) == 0 1920: || GET_CODE (DECL_INCOMING_RTL (parm)) == MEM) 1921: return 1; 1922: } 1923: return 0; 1924: } 1925: 1926: void 1927: m88k_begin_prologue (stream, size) 1928: FILE *stream; 1929: int size; 1930: { 1931: m88k_prologue_done = 1; /* it's ok now to put out ln directives */ 1932: } 1933: 1934: void 1935: m88k_end_prologue (stream) 1936: FILE *stream; 1937: { 1938: if (TARGET_OCS_DEBUG_INFO && !prologue_marked) 1939: { 1940: PUT_OCS_FUNCTION_START (stream); 1941: prologue_marked = 1; 1942: 1943: /* If we've already passed the start of the epilogue, say that 1944: it starts here. This marks the function as having a null body, 1945: but at a point where the return address is in a known location. 1946: 1947: Originally, I thought this couldn't happen, but the pic prologue 1948: for leaf functions ends with the instruction that restores the 1949: return address from the temporary register. If the temporary 1950: register is never used, that instruction can float all the way 1951: to the end of the function. */ 1952: if (epilogue_marked) 1953: PUT_OCS_FUNCTION_END (stream); 1954: } 1955: } 1956: 1957: void 1958: m88k_expand_prologue () 1959: { 1960: m88k_layout_frame (); 1961: 1962: if (TARGET_OPTIMIZE_ARG_AREA 1963: && m88k_stack_size 1964: && ! uses_arg_area_p ()) 1965: { 1966: /* The incoming argument area is used for stack space if it is not 1967: used (or if -mno-optimize-arg-area is given). */ 1968: if ((m88k_stack_size -= REG_PARM_STACK_SPACE (0)) < 0) 1969: m88k_stack_size = 0; 1970: } 1971: 1972: if (m88k_stack_size) 1973: emit_add (stack_pointer_rtx, stack_pointer_rtx, -m88k_stack_size); 1974: 1975: if (nregs || nxregs) 1976: preserve_registers (m88k_fp_offset + 4, 1); 1977: 1978: if (frame_pointer_needed) 1979: emit_add (frame_pointer_rtx, stack_pointer_rtx, m88k_fp_offset); 1980: 1981: if (flag_pic && save_regs[PIC_OFFSET_TABLE_REGNUM]) 1982: { 1983: rtx return_reg = gen_rtx (REG, SImode, 1); 1984: rtx label = gen_label_rtx (); 1985: rtx temp_reg; 1986: 1987: if (! save_regs[1]) 1988: { 1989: temp_reg = gen_rtx (REG, SImode, TEMP_REGNUM); 1990: emit_move_insn (temp_reg, return_reg); 1991: } 1992: emit_insn (gen_locate1 (pic_offset_table_rtx, label)); 1993: emit_insn (gen_locate2 (pic_offset_table_rtx, label)); 1994: emit_insn (gen_addsi3 (pic_offset_table_rtx, 1995: pic_offset_table_rtx, return_reg)); 1996: if (! save_regs[1]) 1997: emit_move_insn (return_reg, temp_reg); 1998: } 1999: if (profile_flag || profile_block_flag) 2000: emit_insn (gen_blockage ()); 2001: } 2002: 2003: /* This function generates the assembly code for function exit, 2004: on machines that need it. Args are same as for FUNCTION_PROLOGUE. 2005: 2006: The function epilogue should not depend on the current stack pointer! 2007: It should use the frame pointer only, if there is a frame pointer. 2008: This is mandatory because of alloca; we also take advantage of it to 2009: omit stack adjustments before returning. */ 2010: 2011: void 2012: m88k_begin_epilogue (stream) 2013: FILE *stream; 2014: { 2015: if (TARGET_OCS_DEBUG_INFO && !epilogue_marked && prologue_marked) 2016: { 2017: PUT_OCS_FUNCTION_END (stream); 2018: } 2019: epilogue_marked = 1; 2020: } 2021: 2022: void 2023: m88k_end_epilogue (stream, size) 2024: FILE *stream; 2025: int size; 2026: { 2027: rtx insn = get_last_insn (); 2028: 2029: if (TARGET_OCS_DEBUG_INFO && !epilogue_marked) 2030: PUT_OCS_FUNCTION_END (stream); 2031: 2032: /* If the last insn isn't a BARRIER, we must write a return insn. This 2033: should only happen if the function has no prologe and no body. */ 2034: if (GET_CODE (insn) == NOTE) 2035: insn = prev_nonnote_insn (insn); 2036: if (insn == 0 || GET_CODE (insn) != BARRIER) 2037: fprintf (stream, "\tjmp\t %s\n", reg_names[1]); 2038: 2039: output_short_branch_defs (stream); 2040: 2041: fprintf (stream, "\n"); 2042: 2043: if (TARGET_OCS_DEBUG_INFO) 2044: output_tdesc (stream, m88k_fp_offset + 4); 2045: 2046: m88k_function_number++; 2047: m88k_prologue_done = 0; /* don't put out ln directives */ 2048: variable_args_p = 0; /* has variable args */ 2049: frame_laid_out = 0; 2050: epilogue_marked = 0; 2051: prologue_marked = 0; 2052: } 2053: 2054: void 2055: m88k_expand_epilogue () 2056: { 2057: #if (MONITOR_GCC & 0x4) /* What are interesting prologue/epilogue values? */ 2058: fprintf (stream, "; size = %d, m88k_fp_offset = %d, m88k_stack_size = %d\n", 2059: size, m88k_fp_offset, m88k_stack_size); 2060: #endif 2061: 2062: if (frame_pointer_needed) 2063: emit_add (stack_pointer_rtx, frame_pointer_rtx, -m88k_fp_offset); 2064: 2065: if (nregs || nxregs) 2066: preserve_registers (m88k_fp_offset + 4, 0); 2067: 2068: if (m88k_stack_size) 2069: emit_add (stack_pointer_rtx, stack_pointer_rtx, m88k_stack_size); 2070: } 2071: 2072: /* Emit insns to set DSTREG to SRCREG + AMOUNT during the prologue or 2073: epilogue. */ 2074: 2075: static void 2076: emit_add (dstreg, srcreg, amount) 2077: rtx dstreg; 2078: rtx srcreg; 2079: int amount; 2080: { 2081: rtx incr = gen_rtx (CONST_INT, VOIDmode, abs (amount)); 2082: if (! ADD_INTVAL (amount)) 2083: { 2084: rtx temp = gen_rtx (REG, SImode, TEMP_REGNUM); 2085: emit_move_insn (temp, incr); 2086: incr = temp; 2087: } 2088: emit_insn ((amount < 0 ? gen_subsi3 : gen_addsi3) (dstreg, srcreg, incr)); 2089: } 2090: 2091: /* Save/restore the preserve registers. base is the highest offset from 2092: r31 at which a register is stored. store_p is true if stores are to 2093: be done; otherwise loads. */ 2094: 2095: static void 2096: preserve_registers (base, store_p) 2097: int base; 2098: int store_p; 2099: { 2100: int regno, offset; 2101: struct mem_op { 2102: int regno; 2103: int nregs; 2104: int offset; 2105: } mem_op[FIRST_PSEUDO_REGISTER]; 2106: struct mem_op *mo_ptr = mem_op; 2107: 2108: /* The 88open OCS mandates that preserved registers be stored in 2109: increasing order. For compatibility with current practice, 2110: the order is r1, r30, then the preserve registers. */ 2111: 2112: offset = base; 2113: if (save_regs[1]) 2114: { 2115: /* An extra word is given in this case to make best use of double 2116: memory ops. */ 2117: if (nregs > 2 && !save_regs[FRAME_POINTER_REGNUM]) 2118: offset -= 4; 2119: emit_ldst (store_p, 1, SImode, offset); 2120: offset -= 4; 2121: base = offset; 2122: } 2123: 2124: /* Walk the registers to save recording all single memory operations. */ 2125: for (regno = FRAME_POINTER_REGNUM; regno > 1; regno--) 2126: if (save_regs[regno]) 2127: { 2128: if ((offset & 7) != 4 || (regno & 1) != 1 || !save_regs[regno-1]) 2129: { 2130: mo_ptr->nregs = 1; 2131: mo_ptr->regno = regno; 2132: mo_ptr->offset = offset; 2133: mo_ptr++; 2134: offset -= 4; 2135: } 2136: else 2137: { 2138: regno--; 2139: offset -= 2*4; 2140: } 2141: } 2142: 2143: /* Walk the registers to save recording all double memory operations. 2144: This avoids a delay in the epilogue (ld.d/ld). */ 2145: offset = base; 2146: for (regno = FRAME_POINTER_REGNUM; regno > 1; regno--) 2147: if (save_regs[regno]) 2148: { 2149: if ((offset & 7) != 4 || (regno & 1) != 1 || !save_regs[regno-1]) 2150: { 2151: offset -= 4; 2152: } 2153: else 2154: { 2155: mo_ptr->nregs = 2; 2156: mo_ptr->regno = regno-1; 2157: mo_ptr->offset = offset-4; 2158: mo_ptr++; 2159: regno--; 2160: offset -= 2*4; 2161: } 2162: } 2163: 2164: /* Walk the extended registers to record all memory operations. */ 2165: /* Be sure the offset is double word aligned. */ 2166: offset = (offset - 1) & ~7; 2167: for (regno = FIRST_PSEUDO_REGISTER - 1; regno > FIRST_EXTENDED_REGISTER; 2168: regno--) 2169: if (save_regs[regno]) 2170: { 2171: mo_ptr->nregs = 2; 2172: mo_ptr->regno = regno; 2173: mo_ptr->offset = offset; 2174: mo_ptr++; 2175: offset -= 2*4; 2176: } 2177: 2178: mo_ptr->regno = 0; 2179: 2180: /* Output the memory operations. */ 2181: for (mo_ptr = mem_op; mo_ptr->regno; mo_ptr++) 2182: { 2183: if (mo_ptr->nregs) 2184: emit_ldst (store_p, mo_ptr->regno, 2185: (mo_ptr->nregs > 1 ? DImode : SImode), 2186: mo_ptr->offset); 2187: } 2188: } 2189: 2190: static void 2191: emit_ldst (store_p, regno, mode, offset) 2192: int store_p; 2193: int regno; 2194: enum machine_mode mode; 2195: int offset; 2196: { 2197: rtx reg = gen_rtx (REG, mode, regno); 2198: rtx mem; 2199: 2200: if (SMALL_INTVAL (offset)) 2201: { 2202: mem = gen_rtx (MEM, mode, plus_constant (stack_pointer_rtx, offset)); 2203: } 2204: else 2205: { 2206: /* offset is too large for immediate index must use register */ 2207: 2208: rtx disp = gen_rtx (CONST_INT, VOIDmode, offset); 2209: rtx temp = gen_rtx (REG, SImode, TEMP_REGNUM); 2210: rtx regi = gen_rtx (PLUS, SImode, stack_pointer_rtx, temp); 2211: emit_move_insn (temp, disp); 2212: mem = gen_rtx (MEM, mode, regi); 2213: } 2214: 2215: if (store_p) 2216: emit_move_insn (mem, reg); 2217: else 2218: emit_move_insn (reg, mem); 2219: } 2220: 2221: /* Convert the address expression REG to a CFA offset. */ 2222: 2223: int 2224: m88k_debugger_offset (reg, offset) 2225: register rtx reg; 2226: register int offset; 2227: { 2228: if (GET_CODE (reg) == PLUS) 2229: { 2230: offset = INTVAL (XEXP (reg, 1)); 2231: reg = XEXP (reg, 0); 2232: } 2233: 2234: /* Put the offset in terms of the CFA (arg pointer). */ 2235: if (reg == frame_pointer_rtx) 2236: offset += m88k_fp_offset - m88k_stack_size; 2237: else if (reg == stack_pointer_rtx) 2238: offset -= m88k_stack_size; 2239: else if (reg != arg_pointer_rtx) 2240: { 2241: #if (MONITOR_GCC & 0x10) /* Watch for suspicious symbolic locations. */ 2242: if (! (GET_CODE (reg) == REG 2243: && REGNO (reg) >= FIRST_PSEUDO_REGISTER)) 2244: warning ("Internal gcc error: Can't express symbolic location"); 2245: #endif 2246: return 0; 2247: } 2248: 2249: return offset; 2250: } 2251: 2252: /* Output the 88open OCS proscribed text description information. 2253: The information is: 2254: 0 8: zero 2255: 0 22: info-byte-length (16 or 20 bytes) 2256: 0 2: info-alignment (word 2) 2257: 1 32: info-protocol (version 1 or 2(pic)) 2258: 2 32: starting-address (inclusive, not counting prologue) 2259: 3 32: ending-address (exclusive, not counting epilog) 2260: 4 8: info-variant (version 1 or 3(extended registers)) 2261: 4 17: register-save-mask (from register 14 to 30) 2262: 4 1: zero 2263: 4 1: return-address-info-discriminant 2264: 4 5: frame-address-register 2265: 5 32: frame-address-offset 2266: 6 32: return-address-info 2267: 7 32: register-save-offset 2268: 8 16: extended-register-save-mask (x16 - x31) 2269: 8 16: extended-register-save-offset (WORDS from register-save-offset) */ 2270: 2271: static void 2272: output_tdesc (file, offset) 2273: FILE *file; 2274: int offset; 2275: { 2276: int regno, i, j; 2277: long mask, return_address_info, register_save_offset; 2278: long xmask, xregister_save_offset; 2279: char buf[256]; 2280: 2281: for (mask = 0, i = 0, regno = FIRST_OCS_PRESERVE_REGISTER; 2282: regno <= LAST_OCS_PRESERVE_REGISTER; 2283: regno++) 2284: { 2285: mask <<= 1; 2286: if (save_regs[regno]) 2287: { 2288: mask |= 1; 2289: i++; 2290: } 2291: } 2292: 2293: for (xmask = 0, j = 0, regno = FIRST_OCS_EXTENDED_PRESERVE_REGISTER; 2294: regno <= LAST_OCS_EXTENDED_PRESERVE_REGISTER; 2295: regno++) 2296: { 2297: xmask <<= 1; 2298: if (save_regs[regno]) 2299: { 2300: xmask |= 1; 2301: j++; 2302: } 2303: } 2304: 2305: if (save_regs[1]) 2306: { 2307: if ((nxregs > 0 || nregs > 2) && !save_regs[FRAME_POINTER_REGNUM]) 2308: offset -= 4; 2309: return_address_info = - m88k_stack_size + offset; 2310: register_save_offset = return_address_info - i*4; 2311: } 2312: else 2313: { 2314: return_address_info = 1; 2315: register_save_offset = - m88k_stack_size + offset + 4 - i*4; 2316: } 2317: 2318: xregister_save_offset = - (j * 2 + ((register_save_offset >> 2) & 1)); 2319: 2320: tdesc_section (); 2321: 2322: fprintf (file, "\t%s\t %d,%d", INT_ASM_OP, /* 8:0,22:(20 or 16),2:2 */ 2323: (((xmask != 0) ? 20 : 16) << 2) | 2, 2324: flag_pic ? 2 : 1); 2325: 2326: ASM_GENERATE_INTERNAL_LABEL (buf, OCS_START_PREFIX, m88k_function_number); 2327: fprintf (file, ",%s%s", buf+1, flag_pic ? "#rel" : ""); 2328: ASM_GENERATE_INTERNAL_LABEL (buf, OCS_END_PREFIX, m88k_function_number); 2329: fprintf (file, ",%s%s", buf+1, flag_pic ? "#rel" : ""); 2330: 2331: fprintf (file, ",0x%x,0x%x,0x%x,0x%x", 2332: /* 8:1,17:0x%.3x,1:0,1:%d,5:%d */ 2333: (((xmask ? 3 : 1) << (17+1+1+5)) 2334: | (mask << (1+1+5)) 2335: | ((!!save_regs[1]) << 5) 2336: | (frame_pointer_needed 2337: ? FRAME_POINTER_REGNUM 2338: : STACK_POINTER_REGNUM)), 2339: (m88k_stack_size - (frame_pointer_needed ? m88k_fp_offset : 0)), 2340: return_address_info, 2341: register_save_offset); 2342: if (xmask) 2343: fprintf (file, ",0x%x%04x", xmask, (0xffff & xregister_save_offset)); 2344: fputc ('\n', file); 2345: 2346: text_section (); 2347: } 2348: 2349: /* Output assembler code to FILE to increment profiler label # LABELNO 2350: for profiling a function entry. NAME is the mcount function name 2351: (varies), SAVEP indicates whether the parameter registers need to 2352: be saved and restored. */ 2353: 2354: void 2355: output_function_profiler (file, labelno, name, savep) 2356: FILE *file; 2357: int labelno; 2358: char *name; 2359: int savep; 2360: { 2361: char label[256]; 2362: char dbi[256]; 2363: char *temp = (savep ? reg_names[2] : reg_names[10]); 2364: 2365: /* Remember to update FUNCTION_PROFILER_LENGTH. */ 2366: 2367: if (savep) 2368: { 2369: fprintf (file, "\tsubu\t %s,%s,64\n", reg_names[31], reg_names[31]); 2370: fprintf (file, "\tst.d\t %s,%s,32\n", reg_names[2], reg_names[31]); 2371: fprintf (file, "\tst.d\t %s,%s,40\n", reg_names[4], reg_names[31]); 2372: fprintf (file, "\tst.d\t %s,%s,48\n", reg_names[6], reg_names[31]); 2373: fprintf (file, "\tst.d\t %s,%s,56\n", reg_names[8], reg_names[31]); 2374: } 2375: 2376: ASM_GENERATE_INTERNAL_LABEL (label, "LP", labelno); 2377: if (flag_pic == 2) 2378: { 2379: fprintf (file, "\tor.u\t %s,%s,%shi16(%s#got_rel)\n", 2380: temp, reg_names[0], m88k_pound_sign, &label[1]); 2381: fprintf (file, "\tor\t %s,%s,%slo16(%s#got_rel)\n", 2382: temp, temp, m88k_pound_sign, &label[1]); 2383: sprintf (dbi, "\tld\t %s,%s,%s\n", temp, 2384: reg_names[PIC_OFFSET_TABLE_REGNUM], temp); 2385: } 2386: else if (flag_pic) 2387: { 2388: sprintf (dbi, "\tld\t %s,%s,%s#got_rel\n", temp, 2389: reg_names[PIC_OFFSET_TABLE_REGNUM], &label[1]); 2390: } 2391: else 2392: { 2393: fprintf (file, "\tor.u\t %s,%s,%shi16(%s)\n", 2394: temp, reg_names[0], m88k_pound_sign, &label[1]); 2395: sprintf (dbi, "\tor\t %s,%s,%slo16(%s)\n", 2396: temp, temp, m88k_pound_sign, &label[1]); 2397: } 2398: 2399: if (flag_pic) 2400: fprintf (file, "\tbsr.n\t %s#plt\n", name); 2401: else 2402: fprintf (file, "\tbsr.n\t %s\n", name); 2403: fputs (dbi, file); 2404: 2405: if (savep) 2406: { 2407: fprintf (file, "\tld.d\t %s,%s,32\n", reg_names[2], reg_names[31]); 2408: fprintf (file, "\tld.d\t %s,%s,40\n", reg_names[4], reg_names[31]); 2409: fprintf (file, "\tld.d\t %s,%s,48\n", reg_names[6], reg_names[31]); 2410: fprintf (file, "\tld.d\t %s,%s,56\n", reg_names[8], reg_names[31]); 2411: fprintf (file, "\taddu\t %s,%s,64\n", reg_names[31], reg_names[31]); 2412: } 2413: } 2414: 2415: /* Output assembler code to FILE to initialize basic-block profiling for 2416: the current module. LABELNO is unique to each instance. */ 2417: 2418: void 2419: output_function_block_profiler (file, labelno) 2420: FILE *file; 2421: int labelno; 2422: { 2423: char block[256]; 2424: char label[256]; 2425: 2426: /* Remember to update FUNCTION_BLOCK_PROFILER_LENGTH. */ 2427: 2428: ASM_GENERATE_INTERNAL_LABEL (block, "LPBX", 0); 2429: ASM_GENERATE_INTERNAL_LABEL (label, "LPY", labelno); 2430: 2431: /* @@ Need to deal with PIC. I'm not sure what the requirements are on 2432: register usage, so I used r26/r27 to be safe. */ 2433: fprintf (file, "\tor.u\t %s,%s,%shi16(%s)\n", reg_names[27], reg_names[0], 2434: m88k_pound_sign, &block[1]); 2435: fprintf (file, "\tld\t %s,%s,%slo16(%s)\n", reg_names[26], reg_names[27], 2436: m88k_pound_sign, &block[1]); 2437: fprintf (file, "\tbcnd\t %sne0,%s,%s\n", 2438: m88k_pound_sign, reg_names[26], &label[1]); 2439: fprintf (file, "\tsubu\t %s,%s,64\n", reg_names[31], reg_names[31]); 2440: fprintf (file, "\tst.d\t %s,%s,32\n", reg_names[2], reg_names[31]); 2441: fprintf (file, "\tst.d\t %s,%s,40\n", reg_names[4], reg_names[31]); 2442: fprintf (file, "\tst.d\t %s,%s,48\n", reg_names[6], reg_names[31]); 2443: fprintf (file, "\tst.d\t %s,%s,56\n", reg_names[8], reg_names[31]); 2444: fputs ("\tbsr.n\t ", file); 2445: ASM_OUTPUT_LABELREF (file, "__bb_init_func"); 2446: putc ('\n', file); 2447: fprintf (file, "\tor\t %s,%s,%slo16(%s)\n", reg_names[2], reg_names[27], 2448: m88k_pound_sign, &block[1]); 2449: fprintf (file, "\tld.d\t %s,%s,32\n", reg_names[2], reg_names[31]); 2450: fprintf (file, "\tld.d\t %s,%s,40\n", reg_names[4], reg_names[31]); 2451: fprintf (file, "\tld.d\t %s,%s,48\n", reg_names[6], reg_names[31]); 2452: fprintf (file, "\tld.d\t %s,%s,56\n", reg_names[8], reg_names[31]); 2453: fprintf (file, "\taddu\t %s,%s,64\n", reg_names[31], reg_names[31]); 2454: ASM_OUTPUT_INTERNAL_LABEL (file, "LPY", labelno); 2455: } 2456: 2457: /* Output assembler code to FILE to increment the count associated with 2458: the basic block number BLOCKNO. */ 2459: 2460: void 2461: output_block_profiler (file, blockno) 2462: FILE *file; 2463: int blockno; 2464: { 2465: char block[256]; 2466: 2467: /* Remember to update BLOCK_PROFILER_LENGTH. */ 2468: 2469: ASM_GENERATE_INTERNAL_LABEL (block, "LPBX", 2); 2470: 2471: /* @@ Need to deal with PIC. I'm not sure what the requirements are on 2472: register usage, so I used r26/r27 to be safe. */ 2473: fprintf (file, "\tor.u\t %s,%s,%shi16(%s+%d)\n", reg_names[27], reg_names[0], 2474: m88k_pound_sign, &block[1], 4 * blockno); 2475: fprintf (file, "\tld\t %s,%s,%slo16(%s+%d)\n", reg_names[26], reg_names[27], 2476: m88k_pound_sign, &block[1], 4 * blockno); 2477: fprintf (file, "\taddu\t %s,%s,1\n", reg_names[26], reg_names[26]); 2478: fprintf (file, "\tst\t %s,%s,%slo16(%s+%d)\n", reg_names[26], reg_names[27], 2479: m88k_pound_sign, &block[1], 4 * blockno); 2480: } 2481: 2482: /* Determine whether a function argument is passed in a register, and 2483: which register. 2484: 2485: The arguments are CUM, which summarizes all the previous 2486: arguments; MODE, the machine mode of the argument; TYPE, 2487: the data type of the argument as a tree node or 0 if that is not known 2488: (which happens for C support library functions); and NAMED, 2489: which is 1 for an ordinary argument and 0 for nameless arguments that 2490: correspond to `...' in the called function's prototype. 2491: 2492: The value of the expression should either be a `reg' RTX for the 2493: hard register in which to pass the argument, or zero to pass the 2494: argument on the stack. 2495: 2496: On the m88000 the first eight words of args are normally in registers 2497: and the rest are pushed. Double precision floating point must be 2498: double word aligned (and if in a register, starting on an even 2499: register). Structures and unions which are not 4 byte, and word 2500: aligned are passed in memory rather than registers, even if they 2501: would fit completely in the registers under OCS rules. 2502: 2503: Note that FUNCTION_ARG and FUNCTION_INCOMING_ARG were different. 2504: For structures that are passed in memory, but could have been 2505: passed in registers, we first load the structure into the 2506: register, and then when the last argument is passed, we store 2507: the registers into the stack locations. This fixes some bugs 2508: where GCC did not expect to have register arguments, followed 2509: by stack arguments, followed by register arguments. */ 2510: 2511: struct rtx_def * 2512: m88k_function_arg (args_so_far, mode, type, named) 2513: CUMULATIVE_ARGS args_so_far; 2514: enum machine_mode mode; 2515: tree type; 2516: int named; 2517: { 2518: int bytes, words; 2519: 2520: if (type != 0 /* undo putting struct in register */ 2521: && (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE)) 2522: mode = BLKmode; 2523: 2524: if (mode == BLKmode && TARGET_WARN_PASS_STRUCT) 2525: warning ("argument #%d is a structure", args_so_far + 1); 2526: 2527: if ((args_so_far & 1) != 0 2528: && (mode == DImode || mode == DFmode 2529: || (type != 0 && TYPE_ALIGN (type) > 32))) 2530: args_so_far++; 2531: 2532: #ifdef ESKIT 2533: if (no_reg_params) 2534: return (rtx) 0; /* don't put args in registers */ 2535: #endif 2536: 2537: if (type == 0 && mode == BLKmode) 2538: abort (); /* m88k_function_arg argument `type' is NULL for BLKmode. */ 2539: 2540: bytes = (mode != BLKmode) ? GET_MODE_SIZE (mode) : int_size_in_bytes (type); 2541: words = (bytes + 3) / 4; 2542: 2543: if (args_so_far + words > 8) 2544: return (rtx) 0; /* args have exhausted registers */ 2545: 2546: else if (mode == BLKmode 2547: && (TYPE_ALIGN (type) != BITS_PER_WORD 2548: || bytes != UNITS_PER_WORD)) 2549: return (rtx) 0; 2550: 2551: return gen_rtx (REG, 2552: ((mode == BLKmode) ? TYPE_MODE (type) : mode), 2553: 2 + args_so_far); 2554: } 2555: 2556: /* Do what is necessary for `va_start'. The argument is ignored; 2557: We look at the current function to determine if stdargs or varargs 2558: is used and fill in an initial va_list. A pointer to this constructor 2559: is returned. */ 2560: 2561: struct rtx_def * 2562: m88k_builtin_saveregs (arglist) 2563: tree arglist; 2564: { 2565: rtx block, addr, argsize; 2566: tree fntype = TREE_TYPE (current_function_decl); 2567: int argadj = ((!(TYPE_ARG_TYPES (fntype) != 0 2568: && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) 2569: != void_type_node))) 2570: ? -UNITS_PER_WORD : 0) + UNITS_PER_WORD - 1; 2571: int fixed; 2572: variable_args_p = 1; 2573: 2574: if (CONSTANT_P (current_function_arg_offset_rtx)) 2575: { 2576: fixed = (XINT (current_function_arg_offset_rtx, 0) 2577: + argadj) / UNITS_PER_WORD; 2578: argsize = gen_rtx (CONST_INT, VOIDmode, fixed); 2579: } 2580: else 2581: { 2582: fixed = 0; 2583: argsize = plus_constant (current_function_arg_offset_rtx, argadj); 2584: argsize = expand_shift (RSHIFT_EXPR, Pmode, argsize, 2585: build_int_2 (2, 0), argsize, 0); 2586: } 2587: 2588: /* Allocate the va_list constructor */ 2589: block = assign_stack_local (BLKmode, 3 * UNITS_PER_WORD, BITS_PER_WORD); 2590: RTX_UNCHANGING_P (block) = 1; 2591: RTX_UNCHANGING_P (XEXP (block, 0)) = 1; 2592: 2593: /* Store the argsize as the __va_arg member. */ 2594: emit_move_insn (change_address (block, SImode, XEXP (block, 0)), 2595: argsize); 2596: 2597: /* Store the arg pointer in the __va_stk member. */ 2598: emit_move_insn (change_address (block, Pmode, 2599: plus_constant (XEXP (block, 0), 2600: UNITS_PER_WORD)), 2601: copy_to_reg (virtual_incoming_args_rtx)); 2602: 2603: /* Allocate the register space, and store it as the __va_reg member. */ 2604: addr = assign_stack_local (BLKmode, 8 * UNITS_PER_WORD, -1); 2605: MEM_IN_STRUCT_P (addr) = 1; 2606: RTX_UNCHANGING_P (addr) = 1; 2607: RTX_UNCHANGING_P (XEXP (addr, 0)) = 1; 2608: emit_move_insn (change_address (block, Pmode, 2609: plus_constant (XEXP (block, 0), 2610: 2 * UNITS_PER_WORD)), 2611: copy_to_reg (XEXP (addr, 0))); 2612: 2613: /* Now store the incoming registers. */ 2614: if (fixed < 8) 2615: move_block_from_reg 2616: (2 + fixed, 2617: change_address (addr, Pmode, 2618: plus_constant (XEXP (addr, 0), 2619: fixed * UNITS_PER_WORD)), 1.1.1.3 ! root 2620: 8 - fixed, UNITS_PER_WORD * (8 - fixed)); 1.1 root 2621: 2622: /* Return the address of the va_list constructor, but don't put it in a 2623: register. This fails when not optimizing and produces worse code when 2624: optimizing. */ 2625: return XEXP (block, 0); 2626: } 2627: 2628: /* If cmpsi has not been generated, emit code to do the test. Return the 2629: expression describing the test of operator OP. */ 2630: 2631: rtx 2632: emit_test (op, mode) 2633: enum rtx_code op; 2634: enum machine_mode mode; 2635: { 2636: if (m88k_compare_reg == 0) 2637: emit_insn (gen_test (m88k_compare_op0, m88k_compare_op1)); 2638: return (gen_rtx (op, mode, m88k_compare_reg, const0_rtx)); 2639: } 2640: 2641: /* Determine how to best perform cmpsi/bxx, where cmpsi has a constant 2642: operand. All tests with zero (albeit swapped) and all equality tests 2643: with a constant are done with bcnd. The remaining cases are swapped 2644: as needed. */ 2645: 2646: void 2647: emit_bcnd (op, label) 2648: enum rtx_code op; 2649: rtx label; 2650: { 2651: if (m88k_compare_op1 == const0_rtx) 1.1.1.3 ! root 2652: emit_jump_insn( gen_bcnd ( ! 2653: gen_rtx (op, VOIDmode,m88k_compare_op0, const0_rtx), ! 2654: label)); 1.1 root 2655: else if (m88k_compare_op0 == const0_rtx) 1.1.1.3 ! root 2656: emit_jump_insn( gen_bcnd( ! 2657: gen_rtx( ! 2658: swap_condition (op), ! 2659: VOIDmode, m88k_compare_op1, const0_rtx), ! 2660: label)); 1.1 root 2661: else if (op != EQ && op != NE) 2662: emit_jump_insn (gen_bxx (emit_test (op, VOIDmode), label)); 2663: else 2664: { 2665: rtx zero = gen_reg_rtx (SImode); 2666: rtx reg, constant; 2667: int value; 2668: 2669: if (GET_CODE (m88k_compare_op1) == CONST_INT) 2670: { 2671: reg = force_reg (SImode, m88k_compare_op0); 2672: constant = m88k_compare_op1; 2673: } 2674: else 2675: { 2676: reg = force_reg (SImode, m88k_compare_op1); 2677: constant = m88k_compare_op0; 2678: } 2679: value = INTVAL (constant); 2680: 2681: /* Perform an arithmetic computation to make the compared-to value 2682: zero, but avoid loosing if the bcnd is later changed into sxx. */ 2683: if (SMALL_INTVAL (value)) 2684: emit_jump_insn (gen_bxx (emit_test (op, VOIDmode), label)); 2685: else 2686: { 2687: if (SMALL_INTVAL (-value)) 2688: emit_insn (gen_addsi3 (zero, reg, 2689: gen_rtx (CONST_INT, VOIDmode, -value))); 2690: else 2691: emit_insn (gen_xorsi3 (zero, reg, constant)); 2692: 2693: emit_jump_insn (gen_bcnd (gen_rtx (op, VOIDmode, 2694: zero, const0_rtx), 2695: label)); 2696: } 2697: } 2698: } 2699: 2700: /* Print an operand. Recognize special options, documented below. */ 2701: 2702: void 2703: print_operand (file, x, code) 2704: FILE *file; 2705: rtx x; 2706: char code; 2707: { 2708: enum rtx_code xc = (x ? GET_CODE (x) : UNKNOWN); 2709: register int value = (xc == CONST_INT ? INTVAL (x) : 0); 2710: static int sequencep; 2711: static int reversep; 2712: 2713: if (sequencep) 2714: { 2715: if (code < 'B' || code > 'E') 2716: output_operand_lossage ("%R not followed by %B/C/D/E"); 2717: if (reversep) 2718: xc = reverse_condition (xc); 2719: sequencep = 0; 2720: } 2721: 2722: switch (code) 2723: { 2724: case '*': /* addressing base register for PIC */ 2725: fputs (reg_names[PIC_OFFSET_TABLE_REGNUM], file); return; 2726: 2727: case '#': /* SVR4 pound-sign syntax character (empty if SVR3) */ 2728: fputs (m88k_pound_sign, file); return; 2729: 2730: case 'V': /* Output a serializing instruction as needed if the operand 2731: (assumed to be a MEM) is a volatile load. */ 2732: case 'v': /* ditto for a volatile store. */ 2733: if (MEM_VOLATILE_P (x) && TARGET_SERIALIZE_VOLATILE) 2734: { 2735: /* The m88110 implements two FIFO queues, one for loads and 2736: one for stores. These queues mean that loads complete in 2737: their issue order as do stores. An interaction between the 2738: history buffer and the store reservation station ensures 2739: that a store will not bypass load. Finally, a load will not 2740: bypass store, but only when they reference the same address. 2741: 2742: To avoid this reordering (a load bypassing a store) for 2743: volatile references, a serializing instruction is output. 2744: We choose the fldcr instruction as it does not serialize on 2745: the m88100 so that -m88000 code will not be degraded. 2746: 2747: The mechanism below is completed by having CC_STATUS_INIT set 2748: the code to the unknown value. */ 2749: 1.1.1.2 root 2750: /* 2751: hassey 6/30/93 2752: A problem with 88110 4.1 & 4.2 makes the use of fldcr for 2753: this purpose undesirable. Instead we will use tb1, this will 2754: cause serialization on the 88100 but such is life. 2755: */ 2756: 1.1 root 2757: static rtx last_addr = 0; 2758: if (code == 'V' /* Only need to serialize before a load. */ 2759: && m88k_volatile_code != 'V' /* Loads complete in FIFO order. */ 2760: && !(m88k_volatile_code == 'v' 2761: && GET_CODE (XEXP (x, 0)) == LO_SUM 2762: && rtx_equal_p (XEXP (XEXP (x, 0), 1), last_addr))) 2763: fprintf (file, 1.1.1.2 root 2764: #if 0 1.1 root 2765: #ifdef AS_BUG_FLDCR 2766: "fldcr\t %s,%scr63\n\t", 2767: #else 2768: "fldcr\t %s,%sfcr63\n\t", 2769: #endif 2770: reg_names[0], m88k_pound_sign); 1.1.1.2 root 2771: #else /* 0 */ 2772: "tb1\t 1,%s,0xff\n\t", reg_names[0]); 2773: #endif /* 0 */ 1.1 root 2774: m88k_volatile_code = code; 2775: last_addr = (GET_CODE (XEXP (x, 0)) == LO_SUM 2776: ? XEXP (XEXP (x, 0), 1) : 0); 2777: } 2778: return; 2779: 2780: case 'X': /* print the upper 16 bits... */ 2781: value >>= 16; 2782: case 'x': /* print the lower 16 bits of the integer constant in hex */ 2783: if (xc != CONST_INT) 2784: output_operand_lossage ("invalid %x/X value"); 2785: fprintf (file, "0x%x", value & 0xffff); return; 2786: 2787: case 'H': /* print the low 16 bits of the negated integer constant */ 2788: if (xc != CONST_INT) 2789: output_operand_lossage ("invalid %H value"); 2790: value = -value; 2791: case 'h': /* print the register or low 16 bits of the integer constant */ 2792: if (xc == REG) 2793: goto reg; 2794: if (xc != CONST_INT) 2795: output_operand_lossage ("invalid %h value"); 2796: fprintf (file, "%d", value & 0xffff); 2797: return; 2798: 2799: case 'Q': /* print the low 8 bits of the negated integer constant */ 2800: if (xc != CONST_INT) 2801: output_operand_lossage ("invalid %Q value"); 2802: value = -value; 2803: case 'q': /* print the register or low 8 bits of the integer constant */ 2804: if (xc == REG) 2805: goto reg; 2806: if (xc != CONST_INT) 2807: output_operand_lossage ("invalid %q value"); 2808: fprintf (file, "%d", value & 0xff); 2809: return; 2810: 2811: case 'w': /* print the integer constant (X == 32 ? 0 : 32 - X) */ 2812: if (xc != CONST_INT) 2813: output_operand_lossage ("invalid %o value"); 2814: fprintf (file, "%d", value == 32 ? 0 : 32 - value); 2815: return; 2816: 2817: case 'p': /* print the logarithm of the integer constant */ 2818: if (xc != CONST_INT 2819: || (value = exact_log2 (value)) < 0) 2820: output_operand_lossage ("invalid %p value"); 2821: fprintf (file, "%d", value); 2822: return; 2823: 2824: case 'S': /* compliment the value and then... */ 2825: value = ~value; 2826: case 's': /* print the width and offset values forming the integer 2827: constant with a SET instruction. See integer_ok_for_set. */ 2828: { 2829: register unsigned mask, uval = value; 2830: register int top, bottom; 2831: 2832: if (xc != CONST_INT) 2833: output_operand_lossage ("invalid %s/S value"); 2834: /* All the "one" bits must be contiguous. If so, MASK will be 2835: a power of two or zero. */ 2836: mask = (uval | (uval - 1)) + 1; 2837: if (!(uval && POWER_OF_2_or_0 (mask))) 2838: output_operand_lossage ("invalid %s/S value"); 2839: top = mask ? exact_log2 (mask) : 32; 2840: bottom = exact_log2 (uval & ~(uval - 1)); 2841: fprintf (file,"%d<%d>", top - bottom, bottom); 2842: return; 2843: } 2844: 2845: case 'P': /* print nothing if pc_rtx; output label_ref */ 2846: if (xc == LABEL_REF) 2847: output_addr_const (file, x); 2848: else if (xc != PC) 2849: output_operand_lossage ("invalid %P operand"); 2850: return; 2851: 2852: case 'L': /* print 0 or 1 if operand is label_ref and then... */ 2853: fputc (xc == LABEL_REF ? '1' : '0', file); 2854: case '.': /* print .n if delay slot is used */ 2855: fputs ((final_sequence 2856: && ! INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0))) 2857: ? ".n\t" : "\t", file); 2858: return; 2859: 1.1.1.2 root 2860: case '!': /* Reverse the following condition. */ 2861: sequencep++; 2862: reversep = 1; 2863: return; 1.1 root 2864: case 'R': /* reverse the condition of the next print_operand 2865: if operand is a label_ref. */ 2866: sequencep++; 2867: reversep = (xc == LABEL_REF); 2868: return; 2869: 2870: case 'B': /* bcnd branch values */ 2871: fputs (m88k_pound_sign, file); 2872: switch (xc) 2873: { 2874: case EQ: fputs ("eq0", file); return; 2875: case NE: fputs ("ne0", file); return; 2876: case GT: fputs ("gt0", file); return; 2877: case LE: fputs ("le0", file); return; 2878: case LT: fputs ("lt0", file); return; 2879: case GE: fputs ("ge0", file); return; 2880: default: output_operand_lossage ("invalid %B value"); 2881: } 2882: 2883: case 'C': /* bb0/bb1 branch values for comparisons */ 2884: fputs (m88k_pound_sign, file); 2885: switch (xc) 2886: { 2887: case EQ: fputs ("eq", file); return; 2888: case NE: fputs ("ne", file); return; 2889: case GT: fputs ("gt", file); return; 2890: case LE: fputs ("le", file); return; 2891: case LT: fputs ("lt", file); return; 2892: case GE: fputs ("ge", file); return; 2893: case GTU: fputs ("hi", file); return; 2894: case LEU: fputs ("ls", file); return; 2895: case LTU: fputs ("lo", file); return; 2896: case GEU: fputs ("hs", file); return; 2897: default: output_operand_lossage ("invalid %C value"); 2898: } 2899: 2900: case 'D': /* bcnd branch values for float comparisons */ 2901: switch (xc) 2902: { 2903: case EQ: fputs ("0xa", file); return; 2904: case NE: fputs ("0x5", file); return; 2905: case GT: fputs (m88k_pound_sign, file); 2906: fputs ("gt0", file); return; 2907: case LE: fputs ("0xe", file); return; 2908: case LT: fputs ("0x4", file); return; 2909: case GE: fputs ("0xb", file); return; 2910: default: output_operand_lossage ("invalid %D value"); 2911: } 2912: 2913: case 'E': /* bcnd branch values for special integers */ 2914: switch (xc) 2915: { 2916: case EQ: fputs ("0x8", file); return; 2917: case NE: fputs ("0x7", file); return; 2918: default: output_operand_lossage ("invalid %E value"); 2919: } 2920: 2921: case 'd': /* second register of a two register pair */ 2922: if (xc != REG) 2923: output_operand_lossage ("`%d' operand isn't a register"); 2924: fputs (reg_names[REGNO (x) + 1], file); 2925: return; 2926: 2927: case 'r': /* an immediate 0 should be represented as `r0' */ 2928: if (x == const0_rtx) 2929: { 2930: fputs (reg_names[0], file); 2931: return; 2932: } 2933: else if (xc != REG) 2934: output_operand_lossage ("invalid %r value"); 2935: case 0: 2936: name: 2937: if (xc == REG) 2938: { 2939: reg: 2940: if (REGNO (x) == ARG_POINTER_REGNUM) 2941: output_operand_lossage ("operand is r0"); 2942: else 2943: fputs (reg_names[REGNO (x)], file); 2944: } 2945: else if (xc == PLUS) 2946: output_address (x); 2947: else if (xc == MEM) 2948: output_address (XEXP (x, 0)); 1.1.1.3 ! root 2949: else if (flag_pic && xc == UNSPEC) ! 2950: { ! 2951: output_addr_const (file, XVECEXP (x, 0, 0)); ! 2952: fputs ("#got_rel", file); ! 2953: } 1.1 root 2954: else if (xc == CONST_DOUBLE) 2955: output_operand_lossage ("operand is const_double"); 2956: else 2957: output_addr_const (file, x); 2958: return; 2959: 2960: case 'g': /* append #got_rel as needed */ 2961: if (flag_pic && (xc == SYMBOL_REF || xc == LABEL_REF)) 2962: { 2963: output_addr_const (file, x); 2964: fputs ("#got_rel", file); 2965: return; 2966: } 2967: goto name; 2968: 2969: case 'a': /* (standard), assume operand is an address */ 2970: case 'c': /* (standard), assume operand is an immediate value */ 2971: case 'l': /* (standard), assume operand is a label_ref */ 2972: case 'n': /* (standard), like %c, except negate first */ 2973: default: 2974: output_operand_lossage ("invalid code"); 2975: } 2976: } 2977: 2978: void 2979: print_operand_address (file, addr) 2980: FILE *file; 2981: rtx addr; 2982: { 2983: register rtx reg0, reg1, temp; 2984: 2985: switch (GET_CODE (addr)) 2986: { 2987: case REG: 2988: if (REGNO (addr) == ARG_POINTER_REGNUM) 2989: abort (); 2990: else 2991: fprintf (file, "%s,%s", reg_names[0], reg_names [REGNO (addr)]); 2992: break; 2993: 2994: case LO_SUM: 2995: fprintf (file, "%s,%slo16(", 2996: reg_names[REGNO (XEXP (addr, 0))], m88k_pound_sign); 2997: output_addr_const (file, XEXP (addr, 1)); 2998: fputc (')', file); 2999: break; 3000: 3001: case PLUS: 3002: reg0 = XEXP (addr, 0); 3003: reg1 = XEXP (addr, 1); 3004: if (GET_CODE (reg0) == MULT || GET_CODE (reg0) == CONST_INT) 3005: { 3006: rtx tmp = reg0; 3007: reg0 = reg1; 3008: reg1 = tmp; 3009: } 3010: 3011: if ((REG_P (reg0) && REGNO (reg0) == ARG_POINTER_REGNUM) 3012: || (REG_P (reg1) && REGNO (reg1) == ARG_POINTER_REGNUM)) 3013: abort (); 3014: 3015: else if (REG_P (reg0)) 3016: { 3017: if (REG_P (reg1)) 3018: fprintf (file, "%s,%s", 3019: reg_names [REGNO (reg0)], reg_names [REGNO (reg1)]); 3020: 3021: else if (GET_CODE (reg1) == CONST_INT) 3022: fprintf (file, "%s,%d", 3023: reg_names [REGNO (reg0)], INTVAL (reg1)); 3024: 3025: else if (GET_CODE (reg1) == MULT) 3026: { 3027: rtx mreg = XEXP (reg1, 0); 3028: if (REGNO (mreg) == ARG_POINTER_REGNUM) 3029: abort (); 3030: 3031: fprintf (file, "%s[%s]", reg_names[REGNO (reg0)], 3032: reg_names[REGNO (mreg)]); 3033: } 3034: 3035: else if (GET_CODE (reg1) == ZERO_EXTRACT) 3036: { 3037: fprintf (file, "%s,%slo16(", 3038: reg_names[REGNO (reg0)], m88k_pound_sign); 3039: output_addr_const (file, XEXP (reg1, 0)); 3040: fputc (')', file); 3041: } 3042: 3043: else if (flag_pic) 3044: { 3045: fprintf (file, "%s,", reg_names[REGNO (reg0)]); 3046: output_addr_const (file, reg1); 3047: fputs ("#got_rel", file); 3048: } 3049: else abort (); 3050: } 3051: 3052: else 3053: abort (); 3054: break; 3055: 3056: case MULT: 3057: if (REGNO (XEXP (addr, 0)) == ARG_POINTER_REGNUM) 3058: abort (); 3059: 3060: fprintf (file, "%s[%s]", 3061: reg_names[0], reg_names[REGNO (XEXP (addr, 0))]); 3062: break; 3063: 3064: case CONST_INT: 3065: fprintf (file, "%s,%d", reg_names[0], INTVAL (addr)); 3066: break; 3067: 3068: default: 3069: fprintf (file, "%s,", reg_names[0]); 3070: if (SHORT_ADDRESS_P (addr, temp)) 3071: { 3072: fprintf (file, "%siw16(", m88k_pound_sign); 3073: output_addr_const (file, addr); 3074: fputc (')', file); 3075: } 3076: else 3077: output_addr_const (file, addr); 3078: } 3079: } 1.1.1.3 ! root 3080: ! 3081: /* Return true if X is an address which needs a temporary register when ! 3082: reloaded while generating PIC code. */ ! 3083: ! 3084: int ! 3085: pic_address_needs_scratch (x) ! 3086: rtx x; ! 3087: { ! 3088: /* An address which is a symbolic plus a non SMALL_INT needs a temp reg. */ ! 3089: if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS ! 3090: && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF ! 3091: && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT ! 3092: && ! ADD_INT (XEXP (XEXP (x, 0), 1))) ! 3093: return 1; ! 3094: ! 3095: return 0; ! 3096: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.