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