|
|
1.1 root 1: /* Subroutines for gcc2 for pdp11. 1.1.1.2 ! root 2: Copyright (C) 1994, 1995 Free Software Foundation, Inc. 1.1 root 3: Contributed by Michael K. Gschwind ([email protected]). 4: 5: This file is part of GNU CC. 6: 7: GNU CC is free software; you can redistribute it and/or modify 8: it under the terms of the GNU General Public License as published by 9: the Free Software Foundation; either version 1, or (at your option) 10: any later version. 11: 12: GNU CC is distributed in the hope that it will be useful, 13: but WITHOUT ANY WARRANTY; without even the implied warranty of 14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15: GNU General Public License for more details. 16: 17: You should have received a copy of the GNU General Public License 18: along with GNU CC; see the file COPYING. If not, write to 1.1.1.2 ! root 19: the Free Software Foundation, 59 Temple Place - Suite 330, ! 20: Boston, MA 02111-1307, USA. */ 1.1 root 21: 22: #ifndef FILE 23: #include <stdio.h> 24: #endif 25: #include "config.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 "insn-flags.h" 33: #include "output.h" 34: #include "insn-attr.h" 35: 36: /* 37: #define FPU_REG_P(X) ((X)>=8 && (X)<14) 38: #define CPU_REG_P(X) ((X)>=0 && (X)<8) 39: */ 40: 41: /* this is the current value returned by the macro FIRST_PARM_OFFSET 42: defined in tm.h */ 43: int current_first_parm_offset; 44: 45: /* This is where the condition code register lives. */ 46: /* rtx cc0_reg_rtx; - no longer needed? */ 47: 48: static rtx find_addr_reg (); 49: 50: /* Nonzero if OP is a valid second operand for an arithmetic insn. */ 51: 52: int 53: arith_operand (op, mode) 54: rtx op; 55: enum machine_mode mode; 56: { 57: return (register_operand (op, mode) || GET_CODE (op) == CONST_INT); 58: } 59: 60: int 61: const_immediate_operand (op, mode) 62: rtx op; 63: enum machine_mode mode; 64: { 65: return (GET_CODE (op) == CONST_INT); 66: } 67: 68: int 69: immediate15_operand (op, mode) 70: rtx op; 71: enum machine_mode mode; 72: { 73: return (GET_CODE (op) == CONST_INT && ((INTVAL (op) & 0x8000) == 0x0000)); 74: } 75: 76: int 77: expand_shift_operand (op, mode) 78: rtx op; 79: enum machine_mode mode; 80: { 81: return (GET_CODE (op) == CONST_INT 82: && abs (INTVAL(op)) > 1 83: && abs (INTVAL(op)) <= 4); 84: } 85: 86: /* 87: stream is a stdio stream to output the code to. 88: size is an int: how many units of temporary storage to allocate. 89: Refer to the array `regs_ever_live' to determine which registers 90: to save; `regs_ever_live[I]' is nonzero if register number I 91: is ever used in the function. This macro is responsible for 92: knowing which registers should not be saved even if used. 93: */ 94: 95: void 96: output_function_prologue(stream, size) 97: FILE *stream; 98: int size; 99: { 100: extern char call_used_regs[]; 101: extern int frame_pointer_needed; 102: 103: int fsize = ((size) + 1) & ~1; 104: int regno, nregs, i; 105: int offset = 0; 106: 107: int via_ac = -1; 108: 109: fprintf (stream, "\n\t; /* function prologue %s*/\n", current_function_name); 110: 111: /* if we are outputting code for main, 112: the switch FPU to right mode if TARGET_FPU */ 113: if ( (strcmp ("main", current_function_name) == 0) 114: && TARGET_FPU) 115: { 116: fprintf(stream, "\t;/* switch cpu to double float, single integer */\n"); 117: fprintf(stream, "\tsetd\n"); 118: fprintf(stream, "\tseti\n\n"); 119: } 120: 121: if (frame_pointer_needed) 122: { 123: fprintf(stream, "\tmov fp, -(sp)\n"); 124: fprintf(stream, "\tmov sp, fp\n"); 125: } 126: else 127: { 128: /* DON'T SAVE FP */ 129: } 130: 131: /* make frame */ 132: if (fsize) 133: fprintf (stream, "\tsub $%d, sp\n", fsize); 134: 135: /* save CPU registers */ 136: for (regno = 0; regno < 8; regno++) 137: if (regs_ever_live[regno] && ! call_used_regs[regno]) 138: if (! ((regno == FRAME_POINTER_REGNUM) 139: && frame_pointer_needed)) 140: fprintf (stream, "\tmov %s, -(sp)\n", reg_names[regno]); 141: /* fpu regs saving */ 142: 143: /* via_ac specifies the ac to use for saving ac4, ac5 */ 144: via_ac = -1; 145: 146: for (regno = 8; regno < FIRST_PSEUDO_REGISTER ; regno++) 147: { 148: /* ac0 - ac3 */ 149: if (LOAD_FPU_REG_P(regno) 150: && regs_ever_live[regno] 151: && ! call_used_regs[regno]) 152: { 153: fprintf (stream, "\tfstd %s, -(sp)\n", reg_names[regno]); 154: via_ac = regno; 155: } 156: 157: /* maybe make ac4, ac5 call used regs?? */ 158: /* ac4 - ac5 */ 159: if (NO_LOAD_FPU_REG_P(regno) 160: && regs_ever_live[regno] 161: && ! call_used_regs[regno]) 162: { 163: if (via_ac == -1) 164: abort(); 165: 166: fprintf (stream, "\tfldd %s, %s\n", reg_names[regno], reg_names[via_ac]); 167: fprintf (stream, "\tfstd %s, -(sp)\n", reg_names[via_ac]); 168: } 169: } 170: 171: fprintf (stream, "\t;/* end of prologue */\n\n"); 172: } 173: 174: /* 175: The function epilogue should not depend on the current stack pointer! 176: It should use the frame pointer only. This is mandatory because 177: of alloca; we also take advantage of it to omit stack adjustments 178: before returning. */ 179: 180: /* maybe we can make leaf functions faster by switching to the 181: second register file - this way we don't have to save regs! 182: leaf functions are ~ 50% of all functions (dynamically!) 183: 184: set/clear bit 11 (dec. 2048) of status word for switching register files - 185: but how can we do this? the pdp11/45 manual says bit may only 186: be set (p.24), but not cleared! 187: 188: switching to kernel is probably more expensive, so we'll leave it 189: like this and not use the second set of registers... 190: 191: maybe as option if you want to generate code for kernel mode? */ 192: 193: 194: void 195: output_function_epilogue(stream, size) 196: FILE *stream; 197: int size; 198: { 199: extern char call_used_regs[]; 200: extern int may_call_alloca; 201: 202: int fsize = ((size) + 1) & ~1; 203: int nregs, regno, i, j, k, adjust_fp; 204: 205: int via_ac; 206: 207: fprintf (stream, "\n\t; /*function epilogue */\n"); 208: 209: if (frame_pointer_needed) 210: { 211: /* hope this is safe - m68k does it also .... */ 212: regs_ever_live[FRAME_POINTER_REGNUM] = 0; 213: 214: for (i =7, j = 0 ; i >= 0 ; i--) 215: if (regs_ever_live[i] && ! call_used_regs[i]) 216: j++; 217: 218: /* remember # of pushed bytes for CPU regs */ 219: k = 2*j; 220: 221: for (i =7 ; i >= 0 ; i--) 222: if (regs_ever_live[i] && ! call_used_regs[i]) 223: fprintf(stream, "\tmov %d(fp), %s\n",-fsize-2*j--, reg_names[i]); 224: 225: /* get ACs */ 226: via_ac = FIRST_PSEUDO_REGISTER -1; 227: 228: for (i = FIRST_PSEUDO_REGISTER; i > 7; i--) 229: if (regs_ever_live[i] && ! call_used_regs[i]) 230: { 231: via_ac = i; 232: k += 8; 233: } 234: 235: for (i = FIRST_PSEUDO_REGISTER; i > 7; i--) 236: { 237: if (LOAD_FPU_REG_P(i) 238: && regs_ever_live[i] 239: && ! call_used_regs[i]) 240: { 241: fprintf(stream, "\tfldd %d(fp), %s\n", -fsize-k, reg_names[i]); 242: k -= 8; 243: } 244: 245: if (NO_LOAD_FPU_REG_P(i) 246: && regs_ever_live[i] 247: && ! call_used_regs[i]) 248: { 249: if (! LOAD_FPU_REG_P(via_ac)) 250: abort(); 251: 252: fprintf(stream, "\tfldd %d(fp), %s\n", -fsize-k, reg_names[via_ac]); 253: fprintf(stream, "\tfstd %s, %s\n", reg_names[via_ac], reg_names[i]); 254: k -= 8; 255: } 256: } 257: 258: fprintf(stream, "\tmov fp, sp\n"); 259: fprintf (stream, "\tmov (sp)+, fp\n"); 260: } 261: else 262: { 263: via_ac = FIRST_PSEUDO_REGISTER -1; 264: 265: /* get ACs */ 266: for (i = FIRST_PSEUDO_REGISTER; i > 7; i--) 267: if (regs_ever_live[i] && call_used_regs[i]) 268: via_ac = i; 269: 270: for (i = FIRST_PSEUDO_REGISTER; i > 7; i--) 271: { 272: if (LOAD_FPU_REG_P(i) 273: && regs_ever_live[i] 274: && ! call_used_regs[i]) 275: fprintf(stream, "\tfldd (sp)+, %s\n", reg_names[i]); 276: 277: if (NO_LOAD_FPU_REG_P(i) 278: && regs_ever_live[i] 279: && ! call_used_regs[i]) 280: { 281: if (! LOAD_FPU_REG_P(via_ac)) 282: abort(); 283: 284: fprintf(stream, "\tfldd (sp)+, %s\n", reg_names[via_ac]); 285: fprintf(stream, "\tfstd %s, %s\n", reg_names[via_ac], reg_names[i]); 286: } 287: } 288: 289: for (i=7; i >= 0; i--) 290: if (regs_ever_live[i] && !call_used_regs[i]) 291: fprintf(stream, "\tmov (sp)+, %s\n", reg_names[i]); 292: 293: if (fsize) 294: fprintf((stream), "\tadd $%d, sp\n", fsize); 295: } 296: 297: fprintf (stream, "\trts pc\n"); 298: fprintf (stream, "\t;/* end of epilogue*/\n\n\n"); 299: } 300: 301: /* Return the best assembler insn template 302: for moving operands[1] into operands[0] as a fullword. */ 303: static char * 304: singlemove_string (operands) 305: rtx *operands; 306: { 307: if (operands[1] != const0_rtx) 308: return "mov %1,%0"; 309: 310: return "clr %0"; 311: } 312: 313: 314: /* Output assembler code to perform a doubleword move insn 315: with operands OPERANDS. */ 316: 317: char * 318: output_move_double (operands) 319: rtx *operands; 320: { 321: enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; 322: rtx latehalf[2]; 323: rtx addreg0 = 0, addreg1 = 0; 324: 325: /* First classify both operands. */ 326: 327: if (REG_P (operands[0])) 328: optype0 = REGOP; 329: else if (offsettable_memref_p (operands[0])) 330: optype0 = OFFSOP; 331: else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC) 332: optype0 = POPOP; 333: else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) 334: optype0 = PUSHOP; 335: else if (GET_CODE (operands[0]) == MEM) 336: optype0 = MEMOP; 337: else 338: optype0 = RNDOP; 339: 340: if (REG_P (operands[1])) 341: optype1 = REGOP; 342: else if (CONSTANT_P (operands[1])) 343: #if 0 344: || GET_CODE (operands[1]) == CONST_DOUBLE) 345: #endif 346: optype1 = CNSTOP; 347: else if (offsettable_memref_p (operands[1])) 348: optype1 = OFFSOP; 349: else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC) 350: optype1 = POPOP; 351: else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) 352: optype1 = PUSHOP; 353: else if (GET_CODE (operands[1]) == MEM) 354: optype1 = MEMOP; 355: else 356: optype1 = RNDOP; 357: 358: /* Check for the cases that the operand constraints are not 359: supposed to allow to happen. Abort if we get one, 360: because generating code for these cases is painful. */ 361: 362: if (optype0 == RNDOP || optype1 == RNDOP) 363: abort (); 364: 365: /* If one operand is decrementing and one is incrementing 366: decrement the former register explicitly 367: and change that operand into ordinary indexing. */ 368: 369: if (optype0 == PUSHOP && optype1 == POPOP) 370: { 371: operands[0] = XEXP (XEXP (operands[0], 0), 0); 372: output_asm_insn ("sub $4,%0", operands); 373: operands[0] = gen_rtx (MEM, SImode, operands[0]); 374: optype0 = OFFSOP; 375: } 376: if (optype0 == POPOP && optype1 == PUSHOP) 377: { 378: operands[1] = XEXP (XEXP (operands[1], 0), 0); 379: output_asm_insn ("sub $4,%1", operands); 380: operands[1] = gen_rtx (MEM, SImode, operands[1]); 381: optype1 = OFFSOP; 382: } 383: 384: /* If an operand is an unoffsettable memory ref, find a register 385: we can increment temporarily to make it refer to the second word. */ 386: 387: if (optype0 == MEMOP) 388: addreg0 = find_addr_reg (XEXP (operands[0], 0)); 389: 390: if (optype1 == MEMOP) 391: addreg1 = find_addr_reg (XEXP (operands[1], 0)); 392: 393: /* Ok, we can do one word at a time. 394: Normally we do the low-numbered word first, 395: but if either operand is autodecrementing then we 396: do the high-numbered word first. 397: 398: In either case, set up in LATEHALF the operands to use 399: for the high-numbered word and in some cases alter the 400: operands in OPERANDS to be suitable for the low-numbered word. */ 401: 402: if (optype0 == REGOP) 403: latehalf[0] = gen_rtx (REG, HImode, REGNO (operands[0]) + 1); 404: else if (optype0 == OFFSOP) 405: latehalf[0] = adj_offsettable_operand (operands[0], 2); 406: else 407: latehalf[0] = operands[0]; 408: 409: if (optype1 == REGOP) 410: latehalf[1] = gen_rtx (REG, HImode, REGNO (operands[1]) + 1); 411: else if (optype1 == OFFSOP) 412: latehalf[1] = adj_offsettable_operand (operands[1], 2); 413: else if (optype1 == CNSTOP) 414: { 415: if (CONSTANT_P (operands[1])) 416: { 417: /* now the mess begins, high word is in lower word??? 418: 419: that's what ashc makes me think, but I don't remember :-( */ 420: latehalf[1] = gen_rtx(CONST_INT, VOIDmode, 421: INTVAL(operands[1])>>16); 422: operands[1] = gen_rtx(CONST_INT, VOIDmode, 423: INTVAL(operands[1])&0xff); 424: } 425: else if (GET_CODE (operands[1]) == CONST_DOUBLE) 426: { 427: /* immediate 32 bit values not allowed */ 428: abort(); 429: } 430: } 431: else 432: latehalf[1] = operands[1]; 433: 434: /* If insn is effectively movd N(sp),-(sp) then we will do the 435: high word first. We should use the adjusted operand 1 (which is N+4(sp)) 436: for the low word as well, to compensate for the first decrement of sp. */ 437: if (optype0 == PUSHOP 438: && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM 439: && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1])) 440: operands[1] = latehalf[1]; 441: 442: /* If one or both operands autodecrementing, 443: do the two words, high-numbered first. */ 444: 445: /* Likewise, the first move would clobber the source of the second one, 446: do them in the other order. This happens only for registers; 447: such overlap can't happen in memory unless the user explicitly 448: sets it up, and that is an undefined circumstance. */ 449: 450: if (optype0 == PUSHOP || optype1 == PUSHOP 451: || (optype0 == REGOP && optype1 == REGOP 452: && REGNO (operands[0]) == REGNO (latehalf[1]))) 453: { 454: /* Make any unoffsettable addresses point at high-numbered word. */ 455: if (addreg0) 456: output_asm_insn ("add $2,%0", &addreg0); 457: if (addreg1) 458: output_asm_insn ("add $2,%0", &addreg1); 459: 460: /* Do that word. */ 461: output_asm_insn (singlemove_string (latehalf), latehalf); 462: 463: /* Undo the adds we just did. */ 464: if (addreg0) 465: output_asm_insn ("sub $2,%0", &addreg0); 466: if (addreg1) 467: output_asm_insn ("sub $2,%0", &addreg1); 468: 469: /* Do low-numbered word. */ 470: return singlemove_string (operands); 471: } 472: 473: /* Normal case: do the two words, low-numbered first. */ 474: 475: output_asm_insn (singlemove_string (operands), operands); 476: 477: /* Make any unoffsettable addresses point at high-numbered word. */ 478: if (addreg0) 479: output_asm_insn ("add $2,%0", &addreg0); 480: if (addreg1) 481: output_asm_insn ("add $2,%0", &addreg1); 482: 483: /* Do that word. */ 484: output_asm_insn (singlemove_string (latehalf), latehalf); 485: 486: /* Undo the adds we just did. */ 487: if (addreg0) 488: output_asm_insn ("sub $2,%0", &addreg0); 489: if (addreg1) 490: output_asm_insn ("sub $2,%0", &addreg1); 491: 492: return ""; 493: } 494: /* Output assembler code to perform a quadword move insn 495: with operands OPERANDS. */ 496: 497: char * 498: output_move_quad (operands) 499: rtx *operands; 500: { 501: enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; 502: rtx latehalf[2]; 503: rtx addreg0 = 0, addreg1 = 0; 504: 505: output_asm_insn(";; movdi/df: %1 -> %0", operands); 506: 507: if (REG_P (operands[0])) 508: optype0 = REGOP; 509: else if (offsettable_memref_p (operands[0])) 510: optype0 = OFFSOP; 511: else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC) 512: optype0 = POPOP; 513: else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) 514: optype0 = PUSHOP; 515: else if (GET_CODE (operands[0]) == MEM) 516: optype0 = MEMOP; 517: else 518: optype0 = RNDOP; 519: 520: if (REG_P (operands[1])) 521: optype1 = REGOP; 522: else if (CONSTANT_P (operands[1]) 523: || GET_CODE (operands[1]) == CONST_DOUBLE) 524: optype1 = CNSTOP; 525: else if (offsettable_memref_p (operands[1])) 526: optype1 = OFFSOP; 527: else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC) 528: optype1 = POPOP; 529: else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) 530: optype1 = PUSHOP; 531: else if (GET_CODE (operands[1]) == MEM) 532: optype1 = MEMOP; 533: else 534: optype1 = RNDOP; 535: 536: /* Check for the cases that the operand constraints are not 537: supposed to allow to happen. Abort if we get one, 538: because generating code for these cases is painful. */ 539: 540: if (optype0 == RNDOP || optype1 == RNDOP) 541: abort (); 542: 543: /* check if we move a CPU reg to an FPU reg, or vice versa! */ 544: if (optype0 == REGOP && optype1 == REGOP) 545: /* bogus - 64 bit cannot reside in CPU! */ 546: if (CPU_REG_P(REGNO(operands[0])) 547: || CPU_REG_P (REGNO(operands[1]))) 548: abort(); 549: 550: if (optype0 == REGOP || optype1 == REGOP) 551: { 552: /* check for use of clrd???? 553: if you ever allow ac4 and ac5 (now we require secondary load) 554: you must check whether 555: you want to load into them or store from them - 556: then dump ac0 into $help$ movce ac4/5 to ac0, do the 557: store from ac0, and restore ac0 - if you can find 558: an unused ac[0-3], use that and you save a store and a load!*/ 559: 560: if (FPU_REG_P(REGNO(operands[0]))) 561: { 562: if (GET_CODE(operands[1]) == CONST_DOUBLE) 563: { 564: union { double d; int i[2]; } u; 565: u.i[0] = CONST_DOUBLE_LOW (operands[1]); 566: u.i[1] = CONST_DOUBLE_HIGH (operands[1]); 567: 568: if (u.d == 0.0) 569: return "clrd %0"; 570: } 571: 572: return "ldd %1, %0"; 573: } 574: 575: if (FPU_REG_P(REGNO(operands[1]))) 576: return "std %1, %0"; 577: } 578: 579: /* If one operand is decrementing and one is incrementing 580: decrement the former register explicitly 581: and change that operand into ordinary indexing. */ 582: 583: if (optype0 == PUSHOP && optype1 == POPOP) 584: { 585: operands[0] = XEXP (XEXP (operands[0], 0), 0); 586: output_asm_insn ("sub $8,%0", operands); 587: operands[0] = gen_rtx (MEM, DImode, operands[0]); 588: optype0 = OFFSOP; 589: } 590: if (optype0 == POPOP && optype1 == PUSHOP) 591: { 592: operands[1] = XEXP (XEXP (operands[1], 0), 0); 593: output_asm_insn ("sub $8,%1", operands); 594: operands[1] = gen_rtx (MEM, SImode, operands[1]); 595: optype1 = OFFSOP; 596: } 597: 598: /* If an operand is an unoffsettable memory ref, find a register 599: we can increment temporarily to make it refer to the second word. */ 600: 601: if (optype0 == MEMOP) 602: addreg0 = find_addr_reg (XEXP (operands[0], 0)); 603: 604: if (optype1 == MEMOP) 605: addreg1 = find_addr_reg (XEXP (operands[1], 0)); 606: 607: /* Ok, we can do one word at a time. 608: Normally we do the low-numbered word first, 609: but if either operand is autodecrementing then we 610: do the high-numbered word first. 611: 612: In either case, set up in LATEHALF the operands to use 613: for the high-numbered word and in some cases alter the 614: operands in OPERANDS to be suitable for the low-numbered word. */ 615: 616: if (optype0 == REGOP) 617: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 2); 618: else if (optype0 == OFFSOP) 619: latehalf[0] = adj_offsettable_operand (operands[0], 4); 620: else 621: latehalf[0] = operands[0]; 622: 623: if (optype1 == REGOP) 624: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 2); 625: else if (optype1 == OFFSOP) 626: latehalf[1] = adj_offsettable_operand (operands[1], 4); 627: else if (optype1 == CNSTOP) 628: { 629: if (GET_CODE (operands[1]) == CONST_DOUBLE) 630: { 631: /* floats only. not yet supported! 632: 633: -- compute it into PDP float format, - internally, 634: just use IEEE and ignore possible problems ;-) 635: 636: we might get away with it !!!! */ 637: 638: abort(); 639: 640: #ifndef HOST_WORDS_BIG_ENDIAN 641: latehalf[1] = gen_rtx (CONST_INT, VOIDmode, 642: CONST_DOUBLE_LOW (operands[1])); 643: operands[1] = gen_rtx (CONST_INT, VOIDmode, 644: CONST_DOUBLE_HIGH (operands[1])); 645: #else /* HOST_WORDS_BIG_ENDIAN */ 646: latehalf[1] = gen_rtx (CONST_INT, VOIDmode, 647: CONST_DOUBLE_HIGH (operands[1])); 648: operands[1] = gen_rtx (CONST_INT, VOIDmode, 649: CONST_DOUBLE_LOW (operands[1])); 650: #endif /* HOST_WORDS_BIG_ENDIAN */ 651: } 1.1.1.2 ! root 652: else if (GET_CODE(operands[1]) == CONST_INT) ! 653: { ! 654: latehalf[1] = gen_rtx (CONST_INT, VOIDmode, 0); ! 655: } ! 656: else ! 657: abort(); ! 658: 1.1 root 659: } 660: else 661: latehalf[1] = operands[1]; 662: 663: /* If insn is effectively movd N(sp),-(sp) then we will do the 664: high word first. We should use the adjusted operand 1 (which is N+4(sp)) 665: for the low word as well, to compensate for the first decrement of sp. */ 666: if (optype0 == PUSHOP 667: && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM 668: && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1])) 669: operands[1] = latehalf[1]; 670: 671: /* If one or both operands autodecrementing, 672: do the two words, high-numbered first. */ 673: 674: /* Likewise, the first move would clobber the source of the second one, 675: do them in the other order. This happens only for registers; 676: such overlap can't happen in memory unless the user explicitly 677: sets it up, and that is an undefined circumstance. */ 678: 679: if (optype0 == PUSHOP || optype1 == PUSHOP 680: || (optype0 == REGOP && optype1 == REGOP 681: && REGNO (operands[0]) == REGNO (latehalf[1]))) 682: { 683: /* Make any unoffsettable addresses point at high-numbered word. */ 684: if (addreg0) 685: output_asm_insn ("add $4,%0", &addreg0); 686: if (addreg1) 687: output_asm_insn ("add $4,%0", &addreg1); 688: 689: /* Do that word. */ 690: output_asm_insn(output_move_double(latehalf), latehalf); 691: 692: /* Undo the adds we just did. */ 693: if (addreg0) 694: output_asm_insn ("sub $4,%0", &addreg0); 695: if (addreg1) 696: output_asm_insn ("sub $4,%0", &addreg1); 697: 698: /* Do low-numbered word. */ 699: return output_move_double (operands); 700: } 701: 702: /* Normal case: do the two words, low-numbered first. */ 703: 704: output_asm_insn (output_move_double (operands), operands); 705: 706: /* Make any unoffsettable addresses point at high-numbered word. */ 707: if (addreg0) 708: output_asm_insn ("add $4,%0", &addreg0); 709: if (addreg1) 710: output_asm_insn ("add $4,%0", &addreg1); 711: 712: /* Do that word. */ 713: output_asm_insn (output_move_double (latehalf), latehalf); 714: 715: /* Undo the adds we just did. */ 716: if (addreg0) 717: output_asm_insn ("sub $4,%0", &addreg0); 718: if (addreg1) 719: output_asm_insn ("sub $4,%0", &addreg1); 720: 721: return ""; 722: } 723: 724: 725: /* Return a REG that occurs in ADDR with coefficient 1. 726: ADDR can be effectively incremented by incrementing REG. */ 727: 728: static rtx 729: find_addr_reg (addr) 730: rtx addr; 731: { 732: while (GET_CODE (addr) == PLUS) 733: { 734: if (GET_CODE (XEXP (addr, 0)) == REG) 735: addr = XEXP (addr, 0); 736: if (GET_CODE (XEXP (addr, 1)) == REG) 737: addr = XEXP (addr, 1); 738: if (CONSTANT_P (XEXP (addr, 0))) 739: addr = XEXP (addr, 1); 740: if (CONSTANT_P (XEXP (addr, 1))) 741: addr = XEXP (addr, 0); 742: } 743: if (GET_CODE (addr) == REG) 744: return addr; 745: return 0; 746: } 747: 748: /* Output an ascii string. */ 749: output_ascii (file, p, size) 750: FILE *file; 751: char *p; 752: int size; 753: { 754: int i; 755: 756: fprintf (file, "\t.byte \""); 757: 758: for (i = 0; i < size; i++) 759: { 760: register int c = p[i]; 761: if (c == '\"' || c == '\\') 762: putc ('\\', file); 763: if (c >= ' ' && c < 0177) 764: putc (c, file); 765: else 766: { 767: fprintf (file, "\\%03o", c); 768: /* After an octal-escape, if a digit follows, 769: terminate one string constant and start another. 770: The Vax assembler fails to stop reading the escape 771: after three digits, so this is the only way we 772: can get it to parse the data properly. */ 773: if (i < size - 1 && p[i + 1] >= '0' && p[i + 1] <= '9') 774: fprintf (file, "\"\n\tstring \""); 775: } 776: } 777: fprintf (file, "\"\n"); 778: } 779: 780: 781: /* --- stole from out-vax, needs changes */ 782: 783: print_operand_address (file, addr) 784: FILE *file; 785: register rtx addr; 786: { 787: register rtx reg1, reg2, breg, ireg; 788: rtx offset; 789: 790: retry: 791: 792: switch (GET_CODE (addr)) 793: { 794: case MEM: 795: fprintf (file, "@"); 796: addr = XEXP (addr, 0); 797: goto retry; 798: 799: case REG: 800: fprintf (file, "(%s)", reg_names[REGNO (addr)]); 801: break; 802: 803: case PRE_DEC: 804: fprintf (file, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]); 805: break; 806: 807: case POST_INC: 808: fprintf (file, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]); 809: break; 810: 811: case PLUS: 812: reg1 = 0; reg2 = 0; 813: ireg = 0; breg = 0; 814: offset = 0; 815: if (CONSTANT_ADDRESS_P (XEXP (addr, 0)) 816: || GET_CODE (XEXP (addr, 0)) == MEM) 817: { 818: offset = XEXP (addr, 0); 819: addr = XEXP (addr, 1); 820: } 821: else if (CONSTANT_ADDRESS_P (XEXP (addr, 1)) 822: || GET_CODE (XEXP (addr, 1)) == MEM) 823: { 824: offset = XEXP (addr, 1); 825: addr = XEXP (addr, 0); 826: } 827: if (GET_CODE (addr) != PLUS) 828: ; 829: else if (GET_CODE (XEXP (addr, 0)) == MULT) 830: { 831: reg1 = XEXP (addr, 0); 832: addr = XEXP (addr, 1); 833: } 834: else if (GET_CODE (XEXP (addr, 1)) == MULT) 835: { 836: reg1 = XEXP (addr, 1); 837: addr = XEXP (addr, 0); 838: } 839: else if (GET_CODE (XEXP (addr, 0)) == REG) 840: { 841: reg1 = XEXP (addr, 0); 842: addr = XEXP (addr, 1); 843: } 844: else if (GET_CODE (XEXP (addr, 1)) == REG) 845: { 846: reg1 = XEXP (addr, 1); 847: addr = XEXP (addr, 0); 848: } 849: if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT) 850: { 851: if (reg1 == 0) 852: reg1 = addr; 853: else 854: reg2 = addr; 855: addr = 0; 856: } 857: if (offset != 0) 858: { 859: if (addr != 0) abort (); 860: addr = offset; 861: } 862: if (reg1 != 0 && GET_CODE (reg1) == MULT) 863: { 864: breg = reg2; 865: ireg = reg1; 866: } 867: else if (reg2 != 0 && GET_CODE (reg2) == MULT) 868: { 869: breg = reg1; 870: ireg = reg2; 871: } 872: else if (reg2 != 0 || GET_CODE (addr) == MEM) 873: { 874: breg = reg2; 875: ireg = reg1; 876: } 877: else 878: { 879: breg = reg1; 880: ireg = reg2; 881: } 882: if (addr != 0) 883: output_address (addr); 884: if (breg != 0) 885: { 886: if (GET_CODE (breg) != REG) 887: abort (); 888: fprintf (file, "(%s)", reg_names[REGNO (breg)]); 889: } 890: if (ireg != 0) 891: { 892: if (GET_CODE (ireg) == MULT) 893: ireg = XEXP (ireg, 0); 894: if (GET_CODE (ireg) != REG) 895: abort (); 896: abort(); 897: fprintf (file, "[%s]", reg_names[REGNO (ireg)]); 898: } 899: break; 900: 901: default: 902: output_addr_const (file, addr); 903: } 904: } 905: 906: /* register move costs, indexed by regs */ 907: 908: static int move_costs[N_REG_CLASSES][N_REG_CLASSES] = 909: { 910: /* NO MUL GEN LFPU NLFPU FPU ALL */ 911: 912: /* NO */ { 0, 0, 0, 0, 0, 0, 0}, 913: /* MUL */ { 0, 2, 2, 10, 22, 22, 22}, 914: /* GEN */ { 0, 2, 2, 10, 22, 22, 22}, 915: /* LFPU */ { 0, 10, 10, 2, 2, 2, 10}, 916: /* NLFPU */ { 0, 22, 22, 2, 2, 2, 22}, 917: /* FPU */ { 0, 22, 22, 2, 2, 2, 22}, 918: /* ALL */ { 0, 22, 22, 10, 22, 22, 22} 919: } ; 920: 921: 922: /* -- note that some moves are tremendously expensive, 923: because they require lots of tricks! do we have to 924: charge the costs incurred by secondary reload class 925: -- as we do here with 22 -- or not ? */ 926: 927: int 928: register_move_cost(c1, c2) 929: enum reg_class c1, c2; 930: { 931: return move_costs[(int)c1][(int)c2]; 932: } 933: 934: char * 935: output_jump(pos, neg, length) 936: int length; 937: char *pos, *neg; 938: { 939: static int x = 0; 940: 941: static char buf[1000]; 942: 943: #if 0 944: /* currently we don't need this, because the tstdf and cmpdf 945: copy the condition code immediately, and other float operations are not 946: yet recognized as changing the FCC - if so, then the length-cost of all 947: jump insns increases by one, because we have to potentially copy the 948: FCC! */ 949: if (cc_status.flags & CC_IN_FPU) 950: output_asm_insn("cfcc", NULL); 951: #endif 952: 953: switch (length) 954: { 955: case 1: 956: 957: strcpy(buf, pos); 958: strcat(buf, " %l0"); 959: 960: return buf; 961: 962: case 3: 963: 964: sprintf(buf, "%s JMP_%d\n\tjmp %%l0\nJMP_%d:", neg, x, x); 965: 966: x++; 967: 968: return buf; 969: 970: default: 971: 972: abort(); 973: } 974: 975: } 976: 977: void 978: notice_update_cc_on_set(exp, insn) 979: rtx exp; 980: rtx insn; 981: { 982: if (GET_CODE (SET_DEST (exp)) == CC0) 983: { 984: cc_status.flags = 0; 985: cc_status.value1 = SET_DEST (exp); 986: cc_status.value2 = SET_SRC (exp); 987: 988: /* 989: if (GET_MODE(SET_SRC(exp)) == DFmode) 990: cc_status.flags |= CC_IN_FPU; 991: */ 992: } 993: else if ((GET_CODE (SET_DEST (exp)) == REG 994: || GET_CODE (SET_DEST (exp)) == MEM) 995: && GET_CODE (SET_SRC (exp)) != PC 996: && (GET_MODE (SET_DEST(exp)) == HImode 997: || GET_MODE (SET_DEST(exp)) == QImode) 998: && (GET_CODE (SET_SRC(exp)) == PLUS 999: || GET_CODE (SET_SRC(exp)) == MINUS 1000: || GET_CODE (SET_SRC(exp)) == AND 1001: || GET_CODE (SET_SRC(exp)) == IOR 1002: || GET_CODE (SET_SRC(exp)) == XOR 1003: || GET_CODE (SET_SRC(exp)) == NOT 1004: || GET_CODE (SET_SRC(exp)) == NEG 1005: || GET_CODE (SET_SRC(exp)) == REG 1006: || GET_CODE (SET_SRC(exp)) == MEM)) 1007: { 1008: cc_status.flags = 0; 1009: cc_status.value1 = SET_SRC (exp); 1010: cc_status.value2 = SET_DEST (exp); 1011: 1012: if (cc_status.value1 && GET_CODE (cc_status.value1) == REG 1013: && cc_status.value2 1014: && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2)) 1015: cc_status.value2 = 0; 1016: if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM 1017: && cc_status.value2 1018: && GET_CODE (cc_status.value2) == MEM) 1019: cc_status.value2 = 0; 1020: } 1021: else if (GET_CODE (SET_SRC (exp)) == CALL) 1022: { 1023: CC_STATUS_INIT; 1024: } 1025: else if (GET_CODE (SET_DEST (exp)) == REG) 1026: /* what's this ? */ 1027: { 1028: if ((cc_status.value1 1029: && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1))) 1030: cc_status.value1 = 0; 1031: if ((cc_status.value2 1032: && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2))) 1033: cc_status.value2 = 0; 1034: } 1035: else if (SET_DEST(exp) == pc_rtx) 1036: { 1037: /* jump */ 1038: } 1039: else /* if (GET_CODE (SET_DEST (exp)) == MEM) */ 1040: { 1.1.1.2 ! root 1041: /* the last else is a bit paranoiac, but since nearly all instructions 1.1 root 1042: play with condition codes, it's reasonable! */ 1043: 1044: CC_STATUS_INIT; /* paranoia*/ 1045: } 1046: } 1047: 1048: 1049: int simple_memory_operand(op, mode) 1050: rtx op; 1051: enum machine_mode mode; 1052: { 1053: rtx addr, plus0, plus1; 1054: int offset = 0; 1055: 1056: /* Eliminate non-memory operations */ 1057: if (GET_CODE (op) != MEM) 1058: return FALSE; 1059: 1060: #if 0 1061: /* dword operations really put out 2 instructions, so eliminate them. */ 1062: if (GET_MODE_SIZE (GET_MODE (op)) > (HAVE_64BIT_P () ? 8 : 4)) 1063: return FALSE; 1064: #endif 1065: 1066: /* Decode the address now. */ 1067: 1068: indirection: 1069: 1070: addr = XEXP (op, 0); 1071: 1072: switch (GET_CODE (addr)) 1073: { 1074: case REG: 1075: /* (R0) - no extra cost */ 1076: return 1; 1077: 1078: case PRE_DEC: 1079: case POST_INC: 1080: /* -(R0), (R0)+ - cheap! */ 1081: return 0; 1082: 1083: case MEM: 1084: /* cheap - is encoded in addressing mode info! 1085: 1086: -- except for @(R0), which has to be @0(R0) !!! */ 1087: 1088: if (GET_CODE (XEXP (addr, 0)) == REG) 1089: return 0; 1090: 1091: op=addr; 1092: goto indirection; 1093: 1094: case CONST_INT: 1095: case LABEL_REF: 1096: case CONST: 1097: case SYMBOL_REF: 1098: /* @#address - extra cost */ 1099: return 0; 1100: 1101: case PLUS: 1102: /* X(R0) - extra cost */ 1103: return 0; 1104: } 1105: 1106: return FALSE; 1107: } 1108: 1109: 1110: /* 1111: * output a block move: 1112: * 1113: * operands[0] ... to 1114: * operands[1] ... from 1115: * operands[2] ... length 1116: * operands[3] ... alignment 1117: * operands[4] ... scratch register 1118: */ 1119: 1120: 1121: char * 1122: output_block_move(operands) 1123: rtx *operands; 1124: { 1125: static int count = 0; 1126: char buf[200]; 1127: 1128: if (GET_CODE(operands[2]) == CONST_INT 1129: && TARGET_TIME) 1130: { 1131: if (INTVAL(operands[2]) < 16 1132: && INTVAL(operands[3]) == 1) 1133: { 1134: register int i; 1135: 1136: for (i = 1; i <= INTVAL(operands[2]); i++) 1137: output_asm_insn("movb (%1)+, (%0)+", operands); 1138: 1139: return ""; 1140: } 1141: else if (INTVAL(operands[2]) < 32) 1142: { 1143: register int i; 1144: 1145: for (i = 1; i <= INTVAL(operands[2])/2; i++) 1146: output_asm_insn("mov (%1)+, (%0)+", operands); 1147: 1148: /* may I assume that moved quantity is 1149: multiple of alignment ??? 1150: 1151: I HOPE SO ! 1152: */ 1153: 1154: return ""; 1155: } 1156: 1157: 1158: /* can do other clever things, maybe... */ 1159: } 1160: 1161: if (CONSTANT_P(operands[2]) ) 1162: { 1163: /* just move count to scratch */ 1164: output_asm_insn("mov %2, %4", operands); 1165: } 1166: else 1167: { 1168: /* just clobber the register */ 1169: operands[4] = operands[2]; 1170: } 1171: 1172: 1173: /* switch over alignment */ 1174: switch (INTVAL(operands[3])) 1175: { 1176: case 1: 1177: 1178: /* 1179: x: 1180: movb (%1)+, (%0)+ 1181: 1182: if (TARGET_45) 1183: sob %4,x 1184: else 1185: dec %4 1186: bgt x 1187: 1188: */ 1189: 1190: sprintf(buf, "\nmovestrhi%d:", count); 1191: output_asm_insn(buf, NULL); 1192: 1193: output_asm_insn("movb (%1)+, (%0)+", operands); 1194: 1195: if (TARGET_45) 1196: { 1197: sprintf(buf, "sob %%4, movestrhi%d", count); 1198: output_asm_insn(buf, operands); 1199: } 1200: else 1201: { 1202: output_asm_insn("dec %4", operands); 1203: 1204: sprintf(buf, "bgt movestrhi%d", count); 1205: output_asm_insn(buf, NULL); 1206: } 1207: 1208: count ++; 1209: break; 1210: 1211: case 2: 1212: 1213: /* 1214: asr %4 1215: 1216: x: 1217: 1218: mov (%1)+, (%0)+ 1219: 1220: if (TARGET_45) 1221: sob %4, x 1222: else 1223: dec %4 1224: bgt x 1225: */ 1226: 1227: generate_compact_code: 1228: 1229: output_asm_insn("asr %4", operands); 1230: 1231: sprintf(buf, "\nmovestrhi%d:", count); 1232: output_asm_insn(buf, NULL); 1233: 1234: output_asm_insn("mov (%1)+, (%0)+", operands); 1235: 1236: if (TARGET_45) 1237: { 1238: sprintf(buf, "sob %%4, movestrhi%d", count); 1239: output_asm_insn(buf, operands); 1240: } 1241: else 1242: { 1243: output_asm_insn("dec %4", operands); 1244: 1245: sprintf(buf, "bgt movestrhi%d", count); 1246: output_asm_insn(buf, NULL); 1247: } 1248: 1249: count ++; 1250: break; 1251: 1252: case 4: 1253: 1254: /* 1255: 1256: asr %4 1257: asr %4 1258: 1259: x: 1260: 1261: mov (%1)+, (%0)+ 1262: mov (%1)+, (%0)+ 1263: 1264: if (TARGET_45) 1265: sob %4, x 1266: else 1267: dec %4 1268: bgt x 1269: */ 1270: 1271: if (TARGET_SPACE) 1272: goto generate_compact_code; 1273: 1274: output_asm_insn("asr %4", operands); 1275: output_asm_insn("asr %4", operands); 1276: 1277: sprintf(buf, "\nmovestrhi%d:", count); 1278: output_asm_insn(buf, NULL); 1279: 1280: output_asm_insn("mov (%1)+, (%0)+", operands); 1281: output_asm_insn("mov (%1)+, (%0)+", operands); 1282: 1283: if (TARGET_45) 1284: { 1285: sprintf(buf, "sob %%4, movestrhi%d", count); 1286: output_asm_insn(buf, operands); 1287: } 1288: else 1289: { 1290: output_asm_insn("dec %4", operands); 1291: 1292: sprintf(buf, "bgt movestrhi%d", count); 1293: output_asm_insn(buf, NULL); 1294: } 1295: 1296: count ++; 1297: break; 1298: 1299: default: 1300: 1301: /* 1302: 1303: asr %4 1304: asr %4 1305: asr %4 1306: 1307: x: 1308: 1309: mov (%1)+, (%0)+ 1310: mov (%1)+, (%0)+ 1311: mov (%1)+, (%0)+ 1312: mov (%1)+, (%0)+ 1313: 1314: if (TARGET_45) 1315: sob %4, x 1316: else 1317: dec %4 1318: bgt x 1319: */ 1320: 1321: 1322: if (TARGET_SPACE) 1323: goto generate_compact_code; 1324: 1325: output_asm_insn("asr %4", operands); 1326: output_asm_insn("asr %4", operands); 1327: output_asm_insn("asr %4", operands); 1328: 1329: sprintf(buf, "\nmovestrhi%d:", count); 1330: output_asm_insn(buf, NULL); 1331: 1332: output_asm_insn("mov (%1)+, (%0)+", operands); 1333: output_asm_insn("mov (%1)+, (%0)+", operands); 1334: output_asm_insn("mov (%1)+, (%0)+", operands); 1335: output_asm_insn("mov (%1)+, (%0)+", operands); 1336: 1337: if (TARGET_45) 1338: { 1339: sprintf(buf, "sob %%4, movestrhi%d", count); 1340: output_asm_insn(buf, operands); 1341: } 1342: else 1343: { 1344: output_asm_insn("dec %4", operands); 1345: 1346: sprintf(buf, "bgt movestrhi%d", count); 1347: output_asm_insn(buf, NULL); 1348: } 1349: 1350: count ++; 1351: break; 1352: 1353: ; 1354: 1355: } 1356: 1357: return ""; 1358: } 1359: 1360: /* for future use */ 1361: int 1362: comparison_operator_index(op) 1363: rtx op; 1364: { 1365: switch (GET_CODE(op)) 1366: { 1367: case NE: 1368: return 0; 1369: 1370: case EQ: 1371: return 1; 1372: 1373: case GE: 1374: return 2; 1375: 1376: case GT: 1377: return 3; 1378: 1379: case LE: 1380: return 4; 1381: 1382: case LT: 1383: return 5; 1384: 1385: case GEU: 1386: return 6; 1387: 1388: case GTU: 1389: return 7; 1390: 1391: case LEU: 1392: return 8; 1393: 1394: case LTU: 1395: return 9; 1396: 1397: default: 1398: return -1; 1399: } 1400: } 1401: 1402: /* tests whether the rtx is a comparison operator */ 1403: int 1404: comp_operator (op, mode) 1405: rtx op; 1406: enum machine_mode mode; 1407: { 1408: return comparison_operator_index(op) >= 0; 1409: } 1410: 1411: 1412: int 1413: legitimate_address_p (mode, address) 1414: enum machine_mode mode; 1415: rtx address; 1416: { 1417: /* #define REG_OK_STRICT */ 1418: GO_IF_LEGITIMATE_ADDRESS(mode, address, win); 1419: 1420: return 0; 1421: 1422: win: 1423: return 1; 1424: 1425: /* #undef REG_OK_STRICT */ 1426: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.