1/* Subroutines for gcc2 for pdp11. 2 Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2001, 2004, 2005, 3 2006, 2007, 2008, 2009 Free Software Foundation, Inc. 4 Contributed by Michael K. Gschwind (mike@vlsivie.tuwien.ac.at). 5 6This file is part of GCC. 7 8GCC is free software; you can redistribute it and/or modify 9it under the terms of the GNU General Public License as published by 10the Free Software Foundation; either version 3, or (at your option) 11any later version. 12 13GCC is distributed in the hope that it will be useful, 14but WITHOUT ANY WARRANTY; without even the implied warranty of 15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16GNU General Public License for more details. 17 18You should have received a copy of the GNU General Public License 19along with GCC; see the file COPYING3. If not see 20<http://www.gnu.org/licenses/>. */ 21 22#include "config.h" 23#include "system.h" 24#include "coretypes.h" 25#include "tm.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 "function.h" 33#include "output.h" 34#include "insn-attr.h" 35#include "flags.h" 36#include "recog.h" 37#include "tree.h" 38#include "expr.h" 39#include "toplev.h" 40#include "tm_p.h" 41#include "target.h" 42#include "target-def.h" 43#include "df.h" 44 45/* 46#define FPU_REG_P(X) ((X)>=8 && (X)<14) 47#define CPU_REG_P(X) ((X)>=0 && (X)<8) 48*/ 49 50/* this is the current value returned by the macro FIRST_PARM_OFFSET 51 defined in tm.h */ 52int current_first_parm_offset; 53 54/* Routines to encode/decode pdp11 floats */ 55static void encode_pdp11_f (const struct real_format *fmt, 56 long *, const REAL_VALUE_TYPE *); 57static void decode_pdp11_f (const struct real_format *, 58 REAL_VALUE_TYPE *, const long *); 59static void encode_pdp11_d (const struct real_format *fmt, 60 long *, const REAL_VALUE_TYPE *); 61static void decode_pdp11_d (const struct real_format *, 62 REAL_VALUE_TYPE *, const long *); 63 64/* These two are taken from the corresponding vax descriptors 65 in real.c, changing only the encode/decode routine pointers. */ 66const struct real_format pdp11_f_format = 67 { 68 encode_pdp11_f, 69 decode_pdp11_f, 70 2, 71 1, 72 24, 73 24, 74 -127, 75 127, 76 15, 77 false, 78 false, 79 false, 80 false, 81 false, 82 false, 83 false, 84 false 85 }; 86 87const struct real_format pdp11_d_format = 88 { 89 encode_pdp11_d, 90 decode_pdp11_d, 91 2, 92 1, 93 56, 94 56, 95 -127, 96 127, 97 15, 98 false, 99 false, 100 false, 101 false, 102 false, 103 false, 104 false, 105 false 106 }; 107 108static void 109encode_pdp11_f (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf, 110 const REAL_VALUE_TYPE *r) 111{ 112 (*vax_f_format.encode) (fmt, buf, r); 113 buf[0] = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16); 114} 115 116static void 117decode_pdp11_f (const struct real_format *fmt ATTRIBUTE_UNUSED, 118 REAL_VALUE_TYPE *r, const long *buf) 119{ 120 long tbuf; 121 tbuf = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16); 122 (*vax_f_format.decode) (fmt, r, &tbuf); 123} 124 125static void 126encode_pdp11_d (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf, 127 const REAL_VALUE_TYPE *r) 128{ 129 (*vax_d_format.encode) (fmt, buf, r); 130 buf[0] = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16); 131 buf[1] = ((buf[1] >> 16) & 0xffff) | ((buf[1] & 0xffff) << 16); 132} 133 134static void 135decode_pdp11_d (const struct real_format *fmt ATTRIBUTE_UNUSED, 136 REAL_VALUE_TYPE *r, const long *buf) 137{ 138 long tbuf[2]; 139 tbuf[0] = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16); 140 tbuf[1] = ((buf[1] >> 16) & 0xffff) | ((buf[1] & 0xffff) << 16); 141 (*vax_d_format.decode) (fmt, r, tbuf); 142} 143 144/* This is where the condition code register lives. */ 145/* rtx cc0_reg_rtx; - no longer needed? */ 146 147static bool pdp11_handle_option (size_t, const char *, int); 148static rtx find_addr_reg (rtx); 149static const char *singlemove_string (rtx *); 150static bool pdp11_assemble_integer (rtx, unsigned int, int); 151static void pdp11_output_function_prologue (FILE *, HOST_WIDE_INT); 152static void pdp11_output_function_epilogue (FILE *, HOST_WIDE_INT); 153static bool pdp11_rtx_costs (rtx, int, int, int *, bool); 154static bool pdp11_return_in_memory (const_tree, const_tree); 155static void pdp11_trampoline_init (rtx, tree, rtx); 156 157/* Initialize the GCC target structure. */ 158#undef TARGET_ASM_BYTE_OP 159#define TARGET_ASM_BYTE_OP NULL 160#undef TARGET_ASM_ALIGNED_HI_OP 161#define TARGET_ASM_ALIGNED_HI_OP NULL 162#undef TARGET_ASM_ALIGNED_SI_OP 163#define TARGET_ASM_ALIGNED_SI_OP NULL 164#undef TARGET_ASM_INTEGER 165#define TARGET_ASM_INTEGER pdp11_assemble_integer 166 167#undef TARGET_ASM_FUNCTION_PROLOGUE 168#define TARGET_ASM_FUNCTION_PROLOGUE pdp11_output_function_prologue 169#undef TARGET_ASM_FUNCTION_EPILOGUE 170#define TARGET_ASM_FUNCTION_EPILOGUE pdp11_output_function_epilogue 171 172#undef TARGET_ASM_OPEN_PAREN 173#define TARGET_ASM_OPEN_PAREN "[" 174#undef TARGET_ASM_CLOSE_PAREN 175#define TARGET_ASM_CLOSE_PAREN "]" 176 177#undef TARGET_DEFAULT_TARGET_FLAGS 178#define TARGET_DEFAULT_TARGET_FLAGS \ 179 (MASK_FPU | MASK_45 | MASK_ABSHI_BUILTIN | TARGET_UNIX_ASM_DEFAULT) 180#undef TARGET_HANDLE_OPTION 181#define TARGET_HANDLE_OPTION pdp11_handle_option 182 183#undef TARGET_RTX_COSTS 184#define TARGET_RTX_COSTS pdp11_rtx_costs 185 186#undef TARGET_RETURN_IN_MEMORY 187#define TARGET_RETURN_IN_MEMORY pdp11_return_in_memory 188 189#undef TARGET_TRAMPOLINE_INIT 190#define TARGET_TRAMPOLINE_INIT pdp11_trampoline_init 191 192struct gcc_target targetm = TARGET_INITIALIZER; 193 194/* Implement TARGET_HANDLE_OPTION. */ 195 196static bool 197pdp11_handle_option (size_t code, const char *arg ATTRIBUTE_UNUSED, 198 int value ATTRIBUTE_UNUSED) 199{ 200 switch (code) 201 { 202 case OPT_m10: 203 target_flags &= ~(MASK_40 | MASK_45); 204 return true; 205 206 default: 207 return true; 208 } 209} 210 211/* Nonzero if OP is a valid second operand for an arithmetic insn. */ 212 213int 214arith_operand (rtx op, enum machine_mode mode) 215{ 216 return (register_operand (op, mode) || GET_CODE (op) == CONST_INT); 217} 218 219int 220const_immediate_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) 221{ 222 return (GET_CODE (op) == CONST_INT); 223} 224 225int 226immediate15_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) 227{ 228 return (GET_CODE (op) == CONST_INT && ((INTVAL (op) & 0x8000) == 0x0000)); 229} 230 231int 232expand_shift_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) 233{ 234 return (GET_CODE (op) == CONST_INT 235 && abs (INTVAL(op)) > 1 236 && abs (INTVAL(op)) <= 4); 237} 238 239/* 240 stream is a stdio stream to output the code to. 241 size is an int: how many units of temporary storage to allocate. 242 Refer to the array `regs_ever_live' to determine which registers 243 to save; `regs_ever_live[I]' is nonzero if register number I 244 is ever used in the function. This macro is responsible for 245 knowing which registers should not be saved even if used. 246*/ 247 248static void 249pdp11_output_function_prologue (FILE *stream, HOST_WIDE_INT size) 250{ 251 HOST_WIDE_INT fsize = ((size) + 1) & ~1; 252 int regno; 253 int via_ac = -1; 254 255 fprintf (stream, 256 "\n\t; /* function prologue %s*/\n", 257 current_function_name ()); 258 259 /* if we are outputting code for main, 260 the switch FPU to right mode if TARGET_FPU */ 261 if (MAIN_NAME_P (DECL_NAME (current_function_decl)) && TARGET_FPU) 262 { 263 fprintf(stream, 264 "\t;/* switch cpu to double float, single integer */\n"); 265 fprintf(stream, "\tsetd\n"); 266 fprintf(stream, "\tseti\n\n"); 267 } 268 269 if (frame_pointer_needed) 270 { 271 fprintf(stream, "\tmov r5, -(sp)\n"); 272 fprintf(stream, "\tmov sp, r5\n"); 273 } 274 else 275 { 276 /* DON'T SAVE FP */ 277 } 278 279 /* make frame */ 280 if (fsize) 281 asm_fprintf (stream, "\tsub $%#wo, sp\n", fsize); 282 283 /* save CPU registers */ 284 for (regno = 0; regno < 8; regno++) 285 if (df_regs_ever_live_p (regno) && ! call_used_regs[regno]) 286 if (! ((regno == FRAME_POINTER_REGNUM) 287 && frame_pointer_needed)) 288 fprintf (stream, "\tmov %s, -(sp)\n", reg_names[regno]); 289 /* fpu regs saving */ 290 291 /* via_ac specifies the ac to use for saving ac4, ac5 */ 292 via_ac = -1; 293 294 for (regno = 8; regno < FIRST_PSEUDO_REGISTER ; regno++) 295 { 296 /* ac0 - ac3 */ 297 if (LOAD_FPU_REG_P(regno) 298 && df_regs_ever_live_p (regno) 299 && ! call_used_regs[regno]) 300 { 301 fprintf (stream, "\tstd %s, -(sp)\n", reg_names[regno]); 302 via_ac = regno; 303 } 304 305 /* maybe make ac4, ac5 call used regs?? */ 306 /* ac4 - ac5 */ 307 if (NO_LOAD_FPU_REG_P(regno) 308 && df_regs_ever_live_p (regno) 309 && ! call_used_regs[regno]) 310 { 311 gcc_assert (via_ac != -1); 312 fprintf (stream, "\tldd %s, %s\n", 313 reg_names[regno], reg_names[via_ac]); 314 fprintf (stream, "\tstd %s, -(sp)\n", reg_names[via_ac]); 315 } 316 } 317 318 fprintf (stream, "\t;/* end of prologue */\n\n"); 319} 320 321/* 322 The function epilogue should not depend on the current stack pointer! 323 It should use the frame pointer only. This is mandatory because 324 of alloca; we also take advantage of it to omit stack adjustments 325 before returning. */ 326 327/* maybe we can make leaf functions faster by switching to the 328 second register file - this way we don't have to save regs! 329 leaf functions are ~ 50% of all functions (dynamically!) 330 331 set/clear bit 11 (dec. 2048) of status word for switching register files - 332 but how can we do this? the pdp11/45 manual says bit may only 333 be set (p.24), but not cleared! 334 335 switching to kernel is probably more expensive, so we'll leave it 336 like this and not use the second set of registers... 337 338 maybe as option if you want to generate code for kernel mode? */ 339 340static void 341pdp11_output_function_epilogue (FILE *stream, HOST_WIDE_INT size) 342{ 343 HOST_WIDE_INT fsize = ((size) + 1) & ~1; 344 int i, j, k; 345 346 int via_ac; 347 348 fprintf (stream, "\n\t; /*function epilogue */\n"); 349 350 if (frame_pointer_needed) 351 { 352 /* hope this is safe - m68k does it also .... */ 353 df_set_regs_ever_live (FRAME_POINTER_REGNUM, false); 354 355 for (i =7, j = 0 ; i >= 0 ; i--) 356 if (df_regs_ever_live_p (i) && ! call_used_regs[i]) 357 j++; 358 359 /* remember # of pushed bytes for CPU regs */ 360 k = 2*j; 361 362 /* change fp -> r5 due to the compile error on libgcc2.c */ 363 for (i =7 ; i >= 0 ; i--) 364 if (df_regs_ever_live_p (i) && ! call_used_regs[i]) 365 fprintf(stream, "\tmov %#" HOST_WIDE_INT_PRINT "o(r5), %s\n", 366 (-fsize-2*j--)&0xffff, reg_names[i]); 367 368 /* get ACs */ 369 via_ac = FIRST_PSEUDO_REGISTER -1; 370 371 for (i = FIRST_PSEUDO_REGISTER; i > 7; i--) 372 if (df_regs_ever_live_p (i) && ! call_used_regs[i]) 373 { 374 via_ac = i; 375 k += 8; 376 } 377 378 for (i = FIRST_PSEUDO_REGISTER; i > 7; i--) 379 { 380 if (LOAD_FPU_REG_P(i) 381 && df_regs_ever_live_p (i) 382 && ! call_used_regs[i]) 383 { 384 fprintf(stream, "\tldd %#" HOST_WIDE_INT_PRINT "o(r5), %s\n", 385 (-fsize-k)&0xffff, reg_names[i]); 386 k -= 8; 387 } 388 389 if (NO_LOAD_FPU_REG_P(i) 390 && df_regs_ever_live_p (i) 391 && ! call_used_regs[i]) 392 { 393 gcc_assert (LOAD_FPU_REG_P(via_ac)); 394 395 fprintf(stream, "\tldd %#" HOST_WIDE_INT_PRINT "o(r5), %s\n", 396 (-fsize-k)&0xffff, reg_names[via_ac]); 397 fprintf(stream, "\tstd %s, %s\n", reg_names[via_ac], reg_names[i]); 398 k -= 8; 399 } 400 } 401 402 fprintf(stream, "\tmov r5, sp\n"); 403 fprintf (stream, "\tmov (sp)+, r5\n"); 404 } 405 else 406 { 407 via_ac = FIRST_PSEUDO_REGISTER -1; 408 409 /* get ACs */ 410 for (i = FIRST_PSEUDO_REGISTER; i > 7; i--) 411 if (df_regs_ever_live_p (i) && call_used_regs[i]) 412 via_ac = i; 413 414 for (i = FIRST_PSEUDO_REGISTER; i > 7; i--) 415 { 416 if (LOAD_FPU_REG_P(i) 417 && df_regs_ever_live_p (i) 418 && ! call_used_regs[i]) 419 fprintf(stream, "\tldd (sp)+, %s\n", reg_names[i]); 420 421 if (NO_LOAD_FPU_REG_P(i) 422 && df_regs_ever_live_p (i) 423 && ! call_used_regs[i]) 424 { 425 gcc_assert (LOAD_FPU_REG_P(via_ac)); 426 427 fprintf(stream, "\tldd (sp)+, %s\n", reg_names[via_ac]); 428 fprintf(stream, "\tstd %s, %s\n", reg_names[via_ac], reg_names[i]); 429 } 430 } 431 432 for (i=7; i >= 0; i--) 433 if (df_regs_ever_live_p (i) && !call_used_regs[i]) 434 fprintf(stream, "\tmov (sp)+, %s\n", reg_names[i]); 435 436 if (fsize) 437 fprintf((stream), "\tadd $%#" HOST_WIDE_INT_PRINT "o, sp\n", 438 (fsize)&0xffff); 439 } 440 441 fprintf (stream, "\trts pc\n"); 442 fprintf (stream, "\t;/* end of epilogue*/\n\n\n"); 443} 444 445/* Return the best assembler insn template 446 for moving operands[1] into operands[0] as a fullword. */ 447static const char * 448singlemove_string (rtx *operands) 449{ 450 if (operands[1] != const0_rtx) 451 return "mov %1,%0"; 452 453 return "clr %0"; 454} 455 456 457/* Output assembler code to perform a doubleword move insn 458 with operands OPERANDS. */ 459 460const char * 461output_move_double (rtx *operands) 462{ 463 enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; 464 rtx latehalf[2]; 465 rtx addreg0 = 0, addreg1 = 0; 466 467 /* First classify both operands. */ 468 469 if (REG_P (operands[0])) 470 optype0 = REGOP; 471 else if (offsettable_memref_p (operands[0])) 472 optype0 = OFFSOP; 473 else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC) 474 optype0 = POPOP; 475 else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) 476 optype0 = PUSHOP; 477 else if (GET_CODE (operands[0]) == MEM) 478 optype0 = MEMOP; 479 else 480 optype0 = RNDOP; 481 482 if (REG_P (operands[1])) 483 optype1 = REGOP; 484 else if (CONSTANT_P (operands[1]) 485#if 0 486 || GET_CODE (operands[1]) == CONST_DOUBLE 487#endif 488 ) 489 optype1 = CNSTOP; 490 else if (offsettable_memref_p (operands[1])) 491 optype1 = OFFSOP; 492 else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC) 493 optype1 = POPOP; 494 else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) 495 optype1 = PUSHOP; 496 else if (GET_CODE (operands[1]) == MEM) 497 optype1 = MEMOP; 498 else 499 optype1 = RNDOP; 500 501 /* Check for the cases that the operand constraints are not 502 supposed to allow to happen. Abort if we get one, 503 because generating code for these cases is painful. */ 504 505 gcc_assert (optype0 != RNDOP && optype1 != RNDOP); 506 507 /* If one operand is decrementing and one is incrementing 508 decrement the former register explicitly 509 and change that operand into ordinary indexing. */ 510 511 if (optype0 == PUSHOP && optype1 == POPOP) 512 { 513 operands[0] = XEXP (XEXP (operands[0], 0), 0); 514 output_asm_insn ("sub $4,%0", operands); 515 operands[0] = gen_rtx_MEM (SImode, operands[0]); 516 optype0 = OFFSOP; 517 } 518 if (optype0 == POPOP && optype1 == PUSHOP) 519 { 520 operands[1] = XEXP (XEXP (operands[1], 0), 0); 521 output_asm_insn ("sub $4,%1", operands); 522 operands[1] = gen_rtx_MEM (SImode, operands[1]); 523 optype1 = OFFSOP; 524 } 525 526 /* If an operand is an unoffsettable memory ref, find a register 527 we can increment temporarily to make it refer to the second word. */ 528 529 if (optype0 == MEMOP) 530 addreg0 = find_addr_reg (XEXP (operands[0], 0)); 531 532 if (optype1 == MEMOP) 533 addreg1 = find_addr_reg (XEXP (operands[1], 0)); 534 535 /* Ok, we can do one word at a time. 536 Normally we do the low-numbered word first, 537 but if either operand is autodecrementing then we 538 do the high-numbered word first. 539 540 In either case, set up in LATEHALF the operands to use 541 for the high-numbered word and in some cases alter the 542 operands in OPERANDS to be suitable for the low-numbered word. */ 543 544 if (optype0 == REGOP) 545 latehalf[0] = gen_rtx_REG (HImode, REGNO (operands[0]) + 1); 546 else if (optype0 == OFFSOP) 547 latehalf[0] = adjust_address (operands[0], HImode, 2); 548 else 549 latehalf[0] = operands[0]; 550 551 if (optype1 == REGOP) 552 latehalf[1] = gen_rtx_REG (HImode, REGNO (operands[1]) + 1); 553 else if (optype1 == OFFSOP) 554 latehalf[1] = adjust_address (operands[1], HImode, 2); 555 else if (optype1 == CNSTOP) 556 { 557 if (CONSTANT_P (operands[1])) 558 { 559 /* now the mess begins, high word is in lower word??? 560 561 that's what ashc makes me think, but I don't remember :-( */ 562 latehalf[1] = GEN_INT (INTVAL(operands[1]) >> 16); 563 operands[1] = GEN_INT (INTVAL(operands[1]) & 0xff); 564 } 565 else 566 /* immediate 32-bit values not allowed */ 567 gcc_assert (GET_CODE (operands[1]) != CONST_DOUBLE); 568 } 569 else 570 latehalf[1] = operands[1]; 571 572 /* If insn is effectively movd N(sp),-(sp) then we will do the 573 high word first. We should use the adjusted operand 1 (which is N+4(sp)) 574 for the low word as well, to compensate for the first decrement of sp. */ 575 if (optype0 == PUSHOP 576 && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM 577 && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1])) 578 operands[1] = latehalf[1]; 579 580 /* If one or both operands autodecrementing, 581 do the two words, high-numbered first. */ 582 583 /* Likewise, the first move would clobber the source of the second one, 584 do them in the other order. This happens only for registers; 585 such overlap can't happen in memory unless the user explicitly 586 sets it up, and that is an undefined circumstance. */ 587 588 if (optype0 == PUSHOP || optype1 == PUSHOP 589 || (optype0 == REGOP && optype1 == REGOP 590 && REGNO (operands[0]) == REGNO (latehalf[1]))) 591 { 592 /* Make any unoffsettable addresses point at high-numbered word. */ 593 if (addreg0) 594 output_asm_insn ("add $2,%0", &addreg0); 595 if (addreg1) 596 output_asm_insn ("add $2,%0", &addreg1); 597 598 /* Do that word. */ 599 output_asm_insn (singlemove_string (latehalf), latehalf); 600 601 /* Undo the adds we just did. */ 602 if (addreg0) 603 output_asm_insn ("sub $2,%0", &addreg0); 604 if (addreg1) 605 output_asm_insn ("sub $2,%0", &addreg1); 606 607 /* Do low-numbered word. */ 608 return singlemove_string (operands); 609 } 610 611 /* Normal case: do the two words, low-numbered first. */ 612 613 output_asm_insn (singlemove_string (operands), operands); 614 615 /* Make any unoffsettable addresses point at high-numbered word. */ 616 if (addreg0) 617 output_asm_insn ("add $2,%0", &addreg0); 618 if (addreg1) 619 output_asm_insn ("add $2,%0", &addreg1); 620 621 /* Do that word. */ 622 output_asm_insn (singlemove_string (latehalf), latehalf); 623 624 /* Undo the adds we just did. */ 625 if (addreg0) 626 output_asm_insn ("sub $2,%0", &addreg0); 627 if (addreg1) 628 output_asm_insn ("sub $2,%0", &addreg1); 629 630 return ""; 631} 632/* Output assembler code to perform a quadword move insn 633 with operands OPERANDS. */ 634 635const char * 636output_move_quad (rtx *operands) 637{ 638 enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; 639 rtx latehalf[2]; 640 rtx addreg0 = 0, addreg1 = 0; 641 642 output_asm_insn(";/* movdi/df: %1 -> %0 */", operands); 643 644 if (REG_P (operands[0])) 645 optype0 = REGOP; 646 else if (offsettable_memref_p (operands[0])) 647 optype0 = OFFSOP; 648 else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC) 649 optype0 = POPOP; 650 else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) 651 optype0 = PUSHOP; 652 else if (GET_CODE (operands[0]) == MEM) 653 optype0 = MEMOP; 654 else 655 optype0 = RNDOP; 656 657 if (REG_P (operands[1])) 658 optype1 = REGOP; 659 else if (CONSTANT_P (operands[1]) 660 || GET_CODE (operands[1]) == CONST_DOUBLE) 661 optype1 = CNSTOP; 662 else if (offsettable_memref_p (operands[1])) 663 optype1 = OFFSOP; 664 else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC) 665 optype1 = POPOP; 666 else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) 667 optype1 = PUSHOP; 668 else if (GET_CODE (operands[1]) == MEM) 669 optype1 = MEMOP; 670 else 671 optype1 = RNDOP; 672 673 /* Check for the cases that the operand constraints are not 674 supposed to allow to happen. Abort if we get one, 675 because generating code for these cases is painful. */ 676 677 gcc_assert (optype0 != RNDOP && optype1 != RNDOP); 678 679 /* check if we move a CPU reg to an FPU reg, or vice versa! */ 680 if (optype0 == REGOP && optype1 == REGOP) 681 /* bogus - 64 bit cannot reside in CPU! */ 682 gcc_assert (!CPU_REG_P(REGNO(operands[0])) 683 && !CPU_REG_P (REGNO(operands[1]))); 684 685 if (optype0 == REGOP || optype1 == REGOP) 686 { 687 /* check for use of clrd???? 688 if you ever allow ac4 and ac5 (now we require secondary load) 689 you must check whether 690 you want to load into them or store from them - 691 then dump ac0 into $help$ movce ac4/5 to ac0, do the 692 store from ac0, and restore ac0 - if you can find 693 an unused ac[0-3], use that and you save a store and a load!*/ 694 695 if (FPU_REG_P(REGNO(operands[0]))) 696 { 697 if (GET_CODE(operands[1]) == CONST_DOUBLE) 698 { 699 REAL_VALUE_TYPE r; 700 REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]); 701 702 if (REAL_VALUES_EQUAL (r, dconst0)) 703 return "{clrd|clrf} %0"; 704 } 705 706 return "{ldd|movf} %1, %0"; 707 } 708 709 if (FPU_REG_P(REGNO(operands[1]))) 710 return "{std|movf} %1, %0"; 711 } 712 713 /* If one operand is decrementing and one is incrementing 714 decrement the former register explicitly 715 and change that operand into ordinary indexing. */ 716 717 if (optype0 == PUSHOP && optype1 == POPOP) 718 { 719 operands[0] = XEXP (XEXP (operands[0], 0), 0); 720 output_asm_insn ("sub $8,%0", operands); 721 operands[0] = gen_rtx_MEM (DImode, operands[0]); 722 optype0 = OFFSOP; 723 } 724 if (optype0 == POPOP && optype1 == PUSHOP) 725 { 726 operands[1] = XEXP (XEXP (operands[1], 0), 0); 727 output_asm_insn ("sub $8,%1", operands); 728 operands[1] = gen_rtx_MEM (SImode, operands[1]); 729 optype1 = OFFSOP; 730 } 731 732 /* If an operand is an unoffsettable memory ref, find a register 733 we can increment temporarily to make it refer to the second word. */ 734 735 if (optype0 == MEMOP) 736 addreg0 = find_addr_reg (XEXP (operands[0], 0)); 737 738 if (optype1 == MEMOP) 739 addreg1 = find_addr_reg (XEXP (operands[1], 0)); 740 741 /* Ok, we can do one word at a time. 742 Normally we do the low-numbered word first, 743 but if either operand is autodecrementing then we 744 do the high-numbered word first. 745 746 In either case, set up in LATEHALF the operands to use 747 for the high-numbered word and in some cases alter the 748 operands in OPERANDS to be suitable for the low-numbered word. */ 749 750 if (optype0 == REGOP) 751 latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 2); 752 else if (optype0 == OFFSOP) 753 latehalf[0] = adjust_address (operands[0], SImode, 4); 754 else 755 latehalf[0] = operands[0]; 756 757 if (optype1 == REGOP) 758 latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 2); 759 else if (optype1 == OFFSOP) 760 latehalf[1] = adjust_address (operands[1], SImode, 4); 761 else if (optype1 == CNSTOP) 762 { 763 if (GET_CODE (operands[1]) == CONST_DOUBLE) 764 { 765 REAL_VALUE_TYPE r; 766 long dval[2]; 767 REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]); 768 REAL_VALUE_TO_TARGET_DOUBLE (r, dval); 769 latehalf[1] = GEN_INT (dval[1]); 770 operands[1] = GEN_INT (dval[0]); 771 } 772 else if (GET_CODE(operands[1]) == CONST_INT) 773 { 774 latehalf[1] = const0_rtx; 775 } 776 else 777 gcc_unreachable (); 778 } 779 else 780 latehalf[1] = operands[1]; 781 782 /* If insn is effectively movd N(sp),-(sp) then we will do the 783 high word first. We should use the adjusted operand 1 (which is N+4(sp)) 784 for the low word as well, to compensate for the first decrement of sp. */ 785 if (optype0 == PUSHOP 786 && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM 787 && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1])) 788 operands[1] = latehalf[1]; 789 790 /* If one or both operands autodecrementing, 791 do the two words, high-numbered first. */ 792 793 /* Likewise, the first move would clobber the source of the second one, 794 do them in the other order. This happens only for registers; 795 such overlap can't happen in memory unless the user explicitly 796 sets it up, and that is an undefined circumstance. */ 797 798 if (optype0 == PUSHOP || optype1 == PUSHOP 799 || (optype0 == REGOP && optype1 == REGOP 800 && REGNO (operands[0]) == REGNO (latehalf[1]))) 801 { 802 /* Make any unoffsettable addresses point at high-numbered word. */ 803 if (addreg0) 804 output_asm_insn ("add $4,%0", &addreg0); 805 if (addreg1) 806 output_asm_insn ("add $4,%0", &addreg1); 807 808 /* Do that word. */ 809 output_asm_insn(output_move_double(latehalf), latehalf); 810 811 /* Undo the adds we just did. */ 812 if (addreg0) 813 output_asm_insn ("sub $4,%0", &addreg0); 814 if (addreg1) 815 output_asm_insn ("sub $4,%0", &addreg1); 816 817 /* Do low-numbered word. */ 818 return output_move_double (operands); 819 } 820 821 /* Normal case: do the two words, low-numbered first. */ 822 823 output_asm_insn (output_move_double (operands), operands); 824 825 /* Make any unoffsettable addresses point at high-numbered word. */ 826 if (addreg0) 827 output_asm_insn ("add $4,%0", &addreg0); 828 if (addreg1) 829 output_asm_insn ("add $4,%0", &addreg1); 830 831 /* Do that word. */ 832 output_asm_insn (output_move_double (latehalf), latehalf); 833 834 /* Undo the adds we just did. */ 835 if (addreg0) 836 output_asm_insn ("sub $4,%0", &addreg0); 837 if (addreg1) 838 output_asm_insn ("sub $4,%0", &addreg1); 839 840 return ""; 841} 842 843 844/* Return a REG that occurs in ADDR with coefficient 1. 845 ADDR can be effectively incremented by incrementing REG. */ 846 847static rtx 848find_addr_reg (rtx addr) 849{ 850 while (GET_CODE (addr) == PLUS) 851 { 852 if (GET_CODE (XEXP (addr, 0)) == REG) 853 addr = XEXP (addr, 0); 854 if (GET_CODE (XEXP (addr, 1)) == REG) 855 addr = XEXP (addr, 1); 856 if (CONSTANT_P (XEXP (addr, 0))) 857 addr = XEXP (addr, 1); 858 if (CONSTANT_P (XEXP (addr, 1))) 859 addr = XEXP (addr, 0); 860 } 861 if (GET_CODE (addr) == REG) 862 return addr; 863 return 0; 864} 865 866/* Output an ascii string. */ 867void 868output_ascii (FILE *file, const char *p, int size) 869{ 870 int i; 871 872 /* This used to output .byte "string", which doesn't work with the UNIX 873 assembler and I think not with DEC ones either. */ 874 fprintf (file, "\t.byte "); 875 876 for (i = 0; i < size; i++) 877 { 878 register int c = p[i]; 879 if (c < 0) 880 c += 256; 881 fprintf (file, "%#o", c); 882 if (i < size - 1) 883 putc (',', file); 884 } 885 putc ('\n', file); 886} 887 888 889/* --- stole from out-vax, needs changes */ 890 891void 892print_operand_address (FILE *file, register rtx addr) 893{ 894 register rtx reg1, reg2, breg, ireg; 895 rtx offset; 896 897 retry: 898 899 switch (GET_CODE (addr)) 900 { 901 case MEM: 902 if (TARGET_UNIX_ASM) 903 fprintf (file, "*"); 904 else 905 fprintf (file, "@"); 906 addr = XEXP (addr, 0); 907 goto retry; 908 909 case REG: 910 fprintf (file, "(%s)", reg_names[REGNO (addr)]); 911 break; 912 913 case PRE_MODIFY: 914 case PRE_DEC: 915 fprintf (file, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]); 916 break; 917 918 case POST_MODIFY: 919 case POST_INC: 920 fprintf (file, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]); 921 break; 922 923 case PLUS: 924 reg1 = 0; reg2 = 0; 925 ireg = 0; breg = 0; 926 offset = 0; 927 if (CONSTANT_ADDRESS_P (XEXP (addr, 0)) 928 || GET_CODE (XEXP (addr, 0)) == MEM) 929 { 930 offset = XEXP (addr, 0); 931 addr = XEXP (addr, 1); 932 } 933 else if (CONSTANT_ADDRESS_P (XEXP (addr, 1)) 934 || GET_CODE (XEXP (addr, 1)) == MEM) 935 { 936 offset = XEXP (addr, 1); 937 addr = XEXP (addr, 0); 938 } 939 if (GET_CODE (addr) != PLUS) 940 ; 941 else if (GET_CODE (XEXP (addr, 0)) == MULT) 942 { 943 reg1 = XEXP (addr, 0); 944 addr = XEXP (addr, 1); 945 } 946 else if (GET_CODE (XEXP (addr, 1)) == MULT) 947 { 948 reg1 = XEXP (addr, 1); 949 addr = XEXP (addr, 0); 950 } 951 else if (GET_CODE (XEXP (addr, 0)) == REG) 952 { 953 reg1 = XEXP (addr, 0); 954 addr = XEXP (addr, 1); 955 } 956 else if (GET_CODE (XEXP (addr, 1)) == REG) 957 { 958 reg1 = XEXP (addr, 1); 959 addr = XEXP (addr, 0); 960 } 961 if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT) 962 { 963 if (reg1 == 0) 964 reg1 = addr; 965 else 966 reg2 = addr; 967 addr = 0; 968 } 969 if (offset != 0) 970 { 971 gcc_assert (addr == 0); 972 addr = offset; 973 } 974 if (reg1 != 0 && GET_CODE (reg1) == MULT) 975 { 976 breg = reg2; 977 ireg = reg1; 978 } 979 else if (reg2 != 0 && GET_CODE (reg2) == MULT) 980 { 981 breg = reg1; 982 ireg = reg2; 983 } 984 else if (reg2 != 0 || GET_CODE (addr) == MEM) 985 { 986 breg = reg2; 987 ireg = reg1; 988 } 989 else 990 { 991 breg = reg1; 992 ireg = reg2; 993 } 994 if (addr != 0) 995 output_address (addr); 996 if (breg != 0) 997 { 998 gcc_assert (GET_CODE (breg) == REG); 999 fprintf (file, "(%s)", reg_names[REGNO (breg)]); 1000 } 1001 if (ireg != 0) 1002 { 1003 if (GET_CODE (ireg) == MULT) 1004 ireg = XEXP (ireg, 0); 1005 gcc_assert (GET_CODE (ireg) == REG); 1006 gcc_unreachable(); /* ??? */ 1007 fprintf (file, "[%s]", reg_names[REGNO (ireg)]); 1008 } 1009 break; 1010 1011 default: 1012 output_addr_const_pdp11 (file, addr); 1013 } 1014} 1015 1016/* Target hook to assemble integer objects. We need to use the 1017 pdp-specific version of output_addr_const. */ 1018 1019static bool 1020pdp11_assemble_integer (rtx x, unsigned int size, int aligned_p) 1021{ 1022 if (aligned_p) 1023 switch (size) 1024 { 1025 case 1: 1026 fprintf (asm_out_file, "\t.byte\t"); 1027 output_addr_const_pdp11 (asm_out_file, x); 1028 fprintf (asm_out_file, " /* char */\n"); 1029 return true; 1030 1031 case 2: 1032 fprintf (asm_out_file, TARGET_UNIX_ASM ? "\t" : "\t.word\t"); 1033 output_addr_const_pdp11 (asm_out_file, x); 1034 fprintf (asm_out_file, " /* short */\n"); 1035 return true; 1036 } 1037 return default_assemble_integer (x, size, aligned_p); 1038} 1039 1040 1041/* register move costs, indexed by regs */ 1042 1043static const int move_costs[N_REG_CLASSES][N_REG_CLASSES] = 1044{ 1045 /* NO MUL GEN LFPU NLFPU FPU ALL */ 1046 1047/* NO */ { 0, 0, 0, 0, 0, 0, 0}, 1048/* MUL */ { 0, 2, 2, 10, 22, 22, 22}, 1049/* GEN */ { 0, 2, 2, 10, 22, 22, 22}, 1050/* LFPU */ { 0, 10, 10, 2, 2, 2, 10}, 1051/* NLFPU */ { 0, 22, 22, 2, 2, 2, 22}, 1052/* FPU */ { 0, 22, 22, 2, 2, 2, 22}, 1053/* ALL */ { 0, 22, 22, 10, 22, 22, 22} 1054} ; 1055 1056 1057/* -- note that some moves are tremendously expensive, 1058 because they require lots of tricks! do we have to 1059 charge the costs incurred by secondary reload class 1060 -- as we do here with 22 -- or not ? */ 1061 1062int 1063register_move_cost(enum reg_class c1, enum reg_class c2) 1064{ 1065 return move_costs[(int)c1][(int)c2]; 1066} 1067 1068static bool 1069pdp11_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total, 1070 bool speed ATTRIBUTE_UNUSED) 1071{ 1072 switch (code) 1073 { 1074 case CONST_INT: 1075 if (INTVAL (x) == 0 || INTVAL (x) == -1 || INTVAL (x) == 1) 1076 { 1077 *total = 0; 1078 return true; 1079 } 1080 /* FALLTHRU */ 1081 1082 case CONST: 1083 case LABEL_REF: 1084 case SYMBOL_REF: 1085 /* Twice as expensive as REG. */ 1086 *total = 2; 1087 return true; 1088 1089 case CONST_DOUBLE: 1090 /* Twice (or 4 times) as expensive as 16 bit. */ 1091 *total = 4; 1092 return true; 1093 1094 case MULT: 1095 /* ??? There is something wrong in MULT because MULT is not 1096 as cheap as total = 2 even if we can shift! */ 1097 /* If optimizing for size make mult etc cheap, but not 1, so when 1098 in doubt the faster insn is chosen. */ 1099 if (optimize_size) 1100 *total = COSTS_N_INSNS (2); 1101 else 1102 *total = COSTS_N_INSNS (11); 1103 return false; 1104 1105 case DIV: 1106 if (optimize_size) 1107 *total = COSTS_N_INSNS (2); 1108 else 1109 *total = COSTS_N_INSNS (25); 1110 return false; 1111 1112 case MOD: 1113 if (optimize_size) 1114 *total = COSTS_N_INSNS (2); 1115 else 1116 *total = COSTS_N_INSNS (26); 1117 return false; 1118 1119 case ABS: 1120 /* Equivalent to length, so same for optimize_size. */ 1121 *total = COSTS_N_INSNS (3); 1122 return false; 1123 1124 case ZERO_EXTEND: 1125 /* Only used for qi->hi. */ 1126 *total = COSTS_N_INSNS (1); 1127 return false; 1128 1129 case SIGN_EXTEND: 1130 if (GET_MODE (x) == HImode) 1131 *total = COSTS_N_INSNS (1); 1132 else if (GET_MODE (x) == SImode) 1133 *total = COSTS_N_INSNS (6); 1134 else 1135 *total = COSTS_N_INSNS (2); 1136 return false; 1137 1138 case ASHIFT: 1139 case LSHIFTRT: 1140 case ASHIFTRT: 1141 if (optimize_size) 1142 *total = COSTS_N_INSNS (1); 1143 else if (GET_MODE (x) == QImode) 1144 { 1145 if (GET_CODE (XEXP (x, 1)) != CONST_INT) 1146 *total = COSTS_N_INSNS (8); /* worst case */ 1147 else 1148 *total = COSTS_N_INSNS (INTVAL (XEXP (x, 1))); 1149 } 1150 else if (GET_MODE (x) == HImode) 1151 { 1152 if (GET_CODE (XEXP (x, 1)) == CONST_INT) 1153 { 1154 if (abs (INTVAL (XEXP (x, 1))) == 1) 1155 *total = COSTS_N_INSNS (1); 1156 else 1157 *total = COSTS_N_INSNS (2.5 + 0.5 * INTVAL (XEXP (x, 1))); 1158 } 1159 else 1160 *total = COSTS_N_INSNS (10); /* worst case */ 1161 } 1162 else if (GET_MODE (x) == SImode) 1163 { 1164 if (GET_CODE (XEXP (x, 1)) == CONST_INT) 1165 *total = COSTS_N_INSNS (2.5 + 0.5 * INTVAL (XEXP (x, 1))); 1166 else /* worst case */ 1167 *total = COSTS_N_INSNS (18); 1168 } 1169 return false; 1170 1171 default: 1172 return false; 1173 } 1174} 1175 1176const char * 1177output_jump (enum rtx_code code, int inv, int length) 1178{ 1179 static int x = 0; 1180 1181 static char buf[1000]; 1182 const char *pos, *neg; 1183 1184 switch (code) 1185 { 1186 case EQ: pos = "beq", neg = "bne"; break; 1187 case NE: pos = "bne", neg = "beq"; break; 1188 case GT: pos = "bgt", neg = "ble"; break; 1189 case GTU: pos = "bhi", neg = "blos"; break; 1190 case LT: pos = "blt", neg = "bge"; break; 1191 case LTU: pos = "blo", neg = "bhis"; break; 1192 case GE: pos = "bge", neg = "blt"; break; 1193 case GEU: pos = "bhis", neg = "blo"; break; 1194 case LE: pos = "ble", neg = "bgt"; break; 1195 case LEU: pos = "blos", neg = "bhi"; break; 1196 default: gcc_unreachable (); 1197 } 1198 1199#if 0 1200/* currently we don't need this, because the tstdf and cmpdf 1201 copy the condition code immediately, and other float operations are not 1202 yet recognized as changing the FCC - if so, then the length-cost of all 1203 jump insns increases by one, because we have to potentially copy the 1204 FCC! */ 1205 if (cc_status.flags & CC_IN_FPU) 1206 output_asm_insn("cfcc", NULL); 1207#endif 1208 1209 switch (length) 1210 { 1211 case 1: 1212 1213 sprintf(buf, "%s %%l1", inv ? neg : pos); 1214 1215 return buf; 1216 1217 case 3: 1218 1219 sprintf(buf, "%s JMP_%d\n\tjmp %%l1\nJMP_%d:", inv ? pos : neg, x, x); 1220 1221 x++; 1222 1223 return buf; 1224 1225 default: 1226 1227 gcc_unreachable (); 1228 } 1229 1230} 1231 1232void 1233notice_update_cc_on_set(rtx exp, rtx insn ATTRIBUTE_UNUSED) 1234{ 1235 if (GET_CODE (SET_DEST (exp)) == CC0) 1236 { 1237 cc_status.flags = 0; 1238 cc_status.value1 = SET_DEST (exp); 1239 cc_status.value2 = SET_SRC (exp); 1240 1241/* 1242 if (GET_MODE(SET_SRC(exp)) == DFmode) 1243 cc_status.flags |= CC_IN_FPU; 1244*/ 1245 } 1246 else if ((GET_CODE (SET_DEST (exp)) == REG 1247 || GET_CODE (SET_DEST (exp)) == MEM) 1248 && GET_CODE (SET_SRC (exp)) != PC 1249 && (GET_MODE (SET_DEST(exp)) == HImode 1250 || GET_MODE (SET_DEST(exp)) == QImode) 1251 && (GET_CODE (SET_SRC(exp)) == PLUS 1252 || GET_CODE (SET_SRC(exp)) == MINUS 1253 || GET_CODE (SET_SRC(exp)) == AND 1254 || GET_CODE (SET_SRC(exp)) == IOR 1255 || GET_CODE (SET_SRC(exp)) == XOR 1256 || GET_CODE (SET_SRC(exp)) == NOT 1257 || GET_CODE (SET_SRC(exp)) == NEG 1258 || GET_CODE (SET_SRC(exp)) == REG 1259 || GET_CODE (SET_SRC(exp)) == MEM)) 1260 { 1261 cc_status.flags = 0; 1262 cc_status.value1 = SET_SRC (exp); 1263 cc_status.value2 = SET_DEST (exp); 1264 1265 if (cc_status.value1 && GET_CODE (cc_status.value1) == REG 1266 && cc_status.value2 1267 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2)) 1268 cc_status.value2 = 0; 1269 if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM 1270 && cc_status.value2 1271 && GET_CODE (cc_status.value2) == MEM) 1272 cc_status.value2 = 0; 1273 } 1274 else if (GET_CODE (SET_SRC (exp)) == CALL) 1275 { 1276 CC_STATUS_INIT; 1277 } 1278 else if (GET_CODE (SET_DEST (exp)) == REG) 1279 /* what's this ? */ 1280 { 1281 if ((cc_status.value1 1282 && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1))) 1283 cc_status.value1 = 0; 1284 if ((cc_status.value2 1285 && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2))) 1286 cc_status.value2 = 0; 1287 } 1288 else if (SET_DEST(exp) == pc_rtx) 1289 { 1290 /* jump */ 1291 } 1292 else /* if (GET_CODE (SET_DEST (exp)) == MEM) */ 1293 { 1294 /* the last else is a bit paranoiac, but since nearly all instructions 1295 play with condition codes, it's reasonable! */ 1296 1297 CC_STATUS_INIT; /* paranoia*/ 1298 } 1299} 1300 1301 1302int 1303simple_memory_operand(rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) 1304{ 1305 rtx addr; 1306 1307 /* Eliminate non-memory operations */ 1308 if (GET_CODE (op) != MEM) 1309 return FALSE; 1310 1311#if 0 1312 /* dword operations really put out 2 instructions, so eliminate them. */ 1313 if (GET_MODE_SIZE (GET_MODE (op)) > (HAVE_64BIT_P () ? 8 : 4)) 1314 return FALSE; 1315#endif 1316 1317 /* Decode the address now. */ 1318 1319 indirection: 1320 1321 addr = XEXP (op, 0); 1322 1323 switch (GET_CODE (addr)) 1324 { 1325 case REG: 1326 /* (R0) - no extra cost */ 1327 return 1; 1328 1329 case PRE_DEC: 1330 case POST_INC: 1331 /* -(R0), (R0)+ - cheap! */ 1332 return 0; 1333 1334 case MEM: 1335 /* cheap - is encoded in addressing mode info! 1336 1337 -- except for @(R0), which has to be @0(R0) !!! */ 1338 1339 if (GET_CODE (XEXP (addr, 0)) == REG) 1340 return 0; 1341 1342 op=addr; 1343 goto indirection; 1344 1345 case CONST_INT: 1346 case LABEL_REF: 1347 case CONST: 1348 case SYMBOL_REF: 1349 /* @#address - extra cost */ 1350 return 0; 1351 1352 case PLUS: 1353 /* X(R0) - extra cost */ 1354 return 0; 1355 1356 default: 1357 break; 1358 } 1359 1360 return FALSE; 1361} 1362 1363 1364/* 1365 * output a block move: 1366 * 1367 * operands[0] ... to 1368 * operands[1] ... from 1369 * operands[2] ... length 1370 * operands[3] ... alignment 1371 * operands[4] ... scratch register 1372 */ 1373 1374 1375const char * 1376output_block_move(rtx *operands) 1377{ 1378 static int count = 0; 1379 char buf[200]; 1380 1381 if (GET_CODE(operands[2]) == CONST_INT 1382 && ! optimize_size) 1383 { 1384 if (INTVAL(operands[2]) < 16 1385 && INTVAL(operands[3]) == 1) 1386 { 1387 register int i; 1388 1389 for (i = 1; i <= INTVAL(operands[2]); i++) 1390 output_asm_insn("movb (%1)+, (%0)+", operands); 1391 1392 return ""; 1393 } 1394 else if (INTVAL(operands[2]) < 32) 1395 { 1396 register int i; 1397 1398 for (i = 1; i <= INTVAL(operands[2])/2; i++) 1399 output_asm_insn("mov (%1)+, (%0)+", operands); 1400 1401 /* may I assume that moved quantity is 1402 multiple of alignment ??? 1403 1404 I HOPE SO ! 1405 */ 1406 1407 return ""; 1408 } 1409 1410 1411 /* can do other clever things, maybe... */ 1412 } 1413 1414 if (CONSTANT_P(operands[2]) ) 1415 { 1416 /* just move count to scratch */ 1417 output_asm_insn("mov %2, %4", operands); 1418 } 1419 else 1420 { 1421 /* just clobber the register */ 1422 operands[4] = operands[2]; 1423 } 1424 1425 1426 /* switch over alignment */ 1427 switch (INTVAL(operands[3])) 1428 { 1429 case 1: 1430 1431 /* 1432 x: 1433 movb (%1)+, (%0)+ 1434 1435 if (TARGET_45) 1436 sob %4,x 1437 else 1438 dec %4 1439 bgt x 1440 1441 */ 1442 1443 sprintf(buf, "\nmovestrhi%d:", count); 1444 output_asm_insn(buf, NULL); 1445 1446 output_asm_insn("movb (%1)+, (%0)+", operands); 1447 1448 if (TARGET_45) 1449 { 1450 sprintf(buf, "sob %%4, movestrhi%d", count); 1451 output_asm_insn(buf, operands); 1452 } 1453 else 1454 { 1455 output_asm_insn("dec %4", operands); 1456 1457 sprintf(buf, "bgt movestrhi%d", count); 1458 output_asm_insn(buf, NULL); 1459 } 1460 1461 count ++; 1462 break; 1463 1464 case 2: 1465 1466 /* 1467 asr %4 1468 1469 x: 1470 1471 mov (%1)+, (%0)+ 1472 1473 if (TARGET_45) 1474 sob %4, x 1475 else 1476 dec %4 1477 bgt x 1478 */ 1479 1480 generate_compact_code: 1481 1482 output_asm_insn("asr %4", operands); 1483 1484 sprintf(buf, "\nmovestrhi%d:", count); 1485 output_asm_insn(buf, NULL); 1486 1487 output_asm_insn("mov (%1)+, (%0)+", operands); 1488 1489 if (TARGET_45) 1490 { 1491 sprintf(buf, "sob %%4, movestrhi%d", count); 1492 output_asm_insn(buf, operands); 1493 } 1494 else 1495 { 1496 output_asm_insn("dec %4", operands); 1497 1498 sprintf(buf, "bgt movestrhi%d", count); 1499 output_asm_insn(buf, NULL); 1500 } 1501 1502 count ++; 1503 break; 1504 1505 case 4: 1506 1507 /* 1508 1509 asr %4 1510 asr %4 1511 1512 x: 1513 1514 mov (%1)+, (%0)+ 1515 mov (%1)+, (%0)+ 1516 1517 if (TARGET_45) 1518 sob %4, x 1519 else 1520 dec %4 1521 bgt x 1522 */ 1523 1524 if (optimize_size) 1525 goto generate_compact_code; 1526 1527 output_asm_insn("asr %4", operands); 1528 output_asm_insn("asr %4", operands); 1529 1530 sprintf(buf, "\nmovestrhi%d:", count); 1531 output_asm_insn(buf, NULL); 1532 1533 output_asm_insn("mov (%1)+, (%0)+", operands); 1534 output_asm_insn("mov (%1)+, (%0)+", operands); 1535 1536 if (TARGET_45) 1537 { 1538 sprintf(buf, "sob %%4, movestrhi%d", count); 1539 output_asm_insn(buf, operands); 1540 } 1541 else 1542 { 1543 output_asm_insn("dec %4", operands); 1544 1545 sprintf(buf, "bgt movestrhi%d", count); 1546 output_asm_insn(buf, NULL); 1547 } 1548 1549 count ++; 1550 break; 1551 1552 default: 1553 1554 /* 1555 1556 asr %4 1557 asr %4 1558 asr %4 1559 1560 x: 1561 1562 mov (%1)+, (%0)+ 1563 mov (%1)+, (%0)+ 1564 mov (%1)+, (%0)+ 1565 mov (%1)+, (%0)+ 1566 1567 if (TARGET_45) 1568 sob %4, x 1569 else 1570 dec %4 1571 bgt x 1572 */ 1573 1574 1575 if (optimize_size) 1576 goto generate_compact_code; 1577 1578 output_asm_insn("asr %4", operands); 1579 output_asm_insn("asr %4", operands); 1580 output_asm_insn("asr %4", operands); 1581 1582 sprintf(buf, "\nmovestrhi%d:", count); 1583 output_asm_insn(buf, NULL); 1584 1585 output_asm_insn("mov (%1)+, (%0)+", operands); 1586 output_asm_insn("mov (%1)+, (%0)+", operands); 1587 output_asm_insn("mov (%1)+, (%0)+", operands); 1588 output_asm_insn("mov (%1)+, (%0)+", operands); 1589 1590 if (TARGET_45) 1591 { 1592 sprintf(buf, "sob %%4, movestrhi%d", count); 1593 output_asm_insn(buf, operands); 1594 } 1595 else 1596 { 1597 output_asm_insn("dec %4", operands); 1598 1599 sprintf(buf, "bgt movestrhi%d", count); 1600 output_asm_insn(buf, NULL); 1601 } 1602 1603 count ++; 1604 break; 1605 1606 ; 1607 1608 } 1609 1610 return ""; 1611} 1612 1613/* This function checks whether a real value can be encoded as 1614 a literal, i.e., addressing mode 27. In that mode, real values 1615 are one word values, so the remaining 48 bits have to be zero. */ 1616int 1617legitimate_const_double_p (rtx address) 1618{ 1619 REAL_VALUE_TYPE r; 1620 long sval[2]; 1621 REAL_VALUE_FROM_CONST_DOUBLE (r, address); 1622 REAL_VALUE_TO_TARGET_DOUBLE (r, sval); 1623 if ((sval[0] & 0xffff) == 0 && sval[1] == 0) 1624 return 1; 1625 return 0; 1626} 1627 1628/* A copy of output_addr_const modified for pdp11 expression syntax. 1629 output_addr_const also gets called for %cDIGIT and %nDIGIT, which we don't 1630 use, and for debugging output, which we don't support with this port either. 1631 So this copy should get called whenever needed. 1632*/ 1633void 1634output_addr_const_pdp11 (FILE *file, rtx x) 1635{ 1636 char buf[256]; 1637 1638 restart: 1639 switch (GET_CODE (x)) 1640 { 1641 case PC: 1642 gcc_assert (flag_pic); 1643 putc ('.', file); 1644 break; 1645 1646 case SYMBOL_REF: 1647 assemble_name (file, XSTR (x, 0)); 1648 break; 1649 1650 case LABEL_REF: 1651 ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0))); 1652 assemble_name (file, buf); 1653 break; 1654 1655 case CODE_LABEL: 1656 ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x)); 1657 assemble_name (file, buf); 1658 break; 1659 1660 case CONST_INT: 1661 /* Should we check for constants which are too big? Maybe cutting 1662 them off to 16 bits is OK? */ 1663 fprintf (file, "%#ho", (unsigned short) INTVAL (x)); 1664 break; 1665 1666 case CONST: 1667 /* This used to output parentheses around the expression, 1668 but that does not work on the 386 (either ATT or BSD assembler). */ 1669 output_addr_const_pdp11 (file, XEXP (x, 0)); 1670 break; 1671 1672 case CONST_DOUBLE: 1673 if (GET_MODE (x) == VOIDmode) 1674 { 1675 /* We can use %o if the number is one word and positive. */ 1676 gcc_assert (!CONST_DOUBLE_HIGH (x)); 1677 fprintf (file, "%#ho", (unsigned short) CONST_DOUBLE_LOW (x)); 1678 } 1679 else 1680 /* We can't handle floating point constants; 1681 PRINT_OPERAND must handle them. */ 1682 output_operand_lossage ("floating constant misused"); 1683 break; 1684 1685 case PLUS: 1686 /* Some assemblers need integer constants to appear last (e.g. masm). */ 1687 if (GET_CODE (XEXP (x, 0)) == CONST_INT) 1688 { 1689 output_addr_const_pdp11 (file, XEXP (x, 1)); 1690 if (INTVAL (XEXP (x, 0)) >= 0) 1691 fprintf (file, "+"); 1692 output_addr_const_pdp11 (file, XEXP (x, 0)); 1693 } 1694 else 1695 { 1696 output_addr_const_pdp11 (file, XEXP (x, 0)); 1697 if (INTVAL (XEXP (x, 1)) >= 0) 1698 fprintf (file, "+"); 1699 output_addr_const_pdp11 (file, XEXP (x, 1)); 1700 } 1701 break; 1702 1703 case MINUS: 1704 /* Avoid outputting things like x-x or x+5-x, 1705 since some assemblers can't handle that. */ 1706 x = simplify_subtraction (x); 1707 if (GET_CODE (x) != MINUS) 1708 goto restart; 1709 1710 output_addr_const_pdp11 (file, XEXP (x, 0)); 1711 fprintf (file, "-"); 1712 if (GET_CODE (XEXP (x, 1)) == CONST_INT 1713 && INTVAL (XEXP (x, 1)) < 0) 1714 { 1715 fprintf (file, targetm.asm_out.open_paren); 1716 output_addr_const_pdp11 (file, XEXP (x, 1)); 1717 fprintf (file, targetm.asm_out.close_paren); 1718 } 1719 else 1720 output_addr_const_pdp11 (file, XEXP (x, 1)); 1721 break; 1722 1723 case ZERO_EXTEND: 1724 case SIGN_EXTEND: 1725 output_addr_const_pdp11 (file, XEXP (x, 0)); 1726 break; 1727 1728 default: 1729 output_operand_lossage ("invalid expression as operand"); 1730 } 1731} 1732 1733/* Worker function for TARGET_RETURN_IN_MEMORY. */ 1734 1735static bool 1736pdp11_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED) 1737{ 1738 /* Should probably return DImode and DFmode in memory, lest 1739 we fill up all regs! 1740 1741 have to, else we crash - exception: maybe return result in 1742 ac0 if DFmode and FPU present - compatibility problem with 1743 libraries for non-floating point.... */ 1744 return (TYPE_MODE (type) == DImode 1745 || (TYPE_MODE (type) == DFmode && ! TARGET_AC0)); 1746} 1747 1748/* Worker function for TARGET_TRAMPOLINE_INIT. 1749 1750 trampoline - how should i do it in separate i+d ? 1751 have some allocate_trampoline magic??? 1752 1753 the following should work for shared I/D: 1754 1755 MV #STATIC, $4 0x940Y 0x0000 <- STATIC; Y = STATIC_CHAIN_REGNUM 1756 JMP FUNCTION 0x0058 0x0000 <- FUNCTION 1757*/ 1758 1759static void 1760pdp11_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) 1761{ 1762 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0); 1763 rtx mem; 1764 1765 gcc_assert (!TARGET_SPLIT); 1766 1767 mem = adjust_address (m_tramp, HImode, 0); 1768 emit_move_insn (mem, GEN_INT (0x9400+STATIC_CHAIN_REGNUM)); 1769 mem = adjust_address (m_tramp, HImode, 2); 1770 emit_move_insn (mem, chain_value); 1771 mem = adjust_address (m_tramp, HImode, 4); 1772 emit_move_insn (mem, GEN_INT (0x0058)); 1773 emit_move_insn (mem, fnaddr); 1774} 1775