|
|
1.1 root 1: /* Subroutines for assembler code output on the NS32000. 1.1.1.3 ! root 2: Copyright (C) 1988, 1994 Free Software Foundation, Inc. 1.1 root 3: 4: This file is part of GNU CC. 5: 6: GNU CC is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU CC is distributed in the hope that it will be useful, 12: but WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14: GNU General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU CC; see the file COPYING. If not, write to 18: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ 19: 20: /* Some output-actions in ns32k.md need these. */ 21: #include <stdio.h> 22: #include "config.h" 23: #include "rtl.h" 24: #include "regs.h" 25: #include "hard-reg-set.h" 26: #include "real.h" 27: #include "insn-config.h" 28: #include "conditions.h" 29: #include "insn-flags.h" 30: #include "output.h" 31: #include "insn-attr.h" 32: 33: #ifdef OSF_OS 34: int ns32k_num_files = 0; 35: #endif 36: 37: void 38: trace (s, s1, s2) 39: char *s, *s1, *s2; 40: { 41: fprintf (stderr, s, s1, s2); 42: } 43: 44: /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. */ 45: 46: int 47: hard_regno_mode_ok (regno, mode) 48: int regno; 49: enum machine_mode mode; 50: { 51: switch (mode) 52: { 53: case QImode: 54: case HImode: 55: case PSImode: 56: case SImode: 57: case PDImode: 58: case VOIDmode: 59: case BLKmode: 60: if (regno < 8 || regno == 16 || regno == 17) 61: return 1; 62: else 63: return 0; 64: 65: case DImode: 66: if (regno < 8 && (regno & 1) == 0) 67: return 1; 68: else 69: return 0; 70: 71: case SFmode: 72: case SCmode: 73: if (TARGET_32081) 74: { 75: if (regno < 16) 76: return 1; 77: else 78: return 0; 79: } 80: else 81: { 82: if (regno < 8) 83: return 1; 84: else 85: return 0; 86: } 87: 88: case DFmode: 89: case DCmode: 90: if ((regno & 1) == 0) 91: { 92: if (TARGET_32081) 93: { 94: if (regno < 16) 95: return 1; 96: else 97: return 0; 98: } 99: else 100: { 101: if (regno < 8) 102: return 1; 103: else 104: return 0; 105: } 106: } 107: else 108: return 0; 109: } 110: 111: /* Used to abort here, but simply saying "no" handles TImode 112: much better. */ 113: return 0; 114: } 115: 116: /* ADDRESS_COST calls this. This function is not optimal 117: for the 32032 & 32332, but it probably is better than 118: the default. */ 119: 120: int 121: calc_address_cost (operand) 122: rtx operand; 123: { 124: int i; 125: int cost = 0; 126: 127: if (GET_CODE (operand) == MEM) 128: cost += 3; 129: if (GET_CODE (operand) == MULT) 130: cost += 2; 131: #if 0 132: if (GET_CODE (operand) == REG) 133: cost += 1; /* not really, but the documentation 134: says different amount of registers 135: shouldn't return the same costs */ 136: #endif 137: switch (GET_CODE (operand)) 138: { 139: case REG: 140: case CONST: 141: case CONST_INT: 142: case CONST_DOUBLE: 143: case SYMBOL_REF: 144: case LABEL_REF: 145: case POST_DEC: 146: case PRE_DEC: 147: break; 148: case MULT: 149: case MEM: 150: case PLUS: 151: for (i = 0; i < GET_RTX_LENGTH (GET_CODE (operand)); i++) 152: { 153: cost += calc_address_cost (XEXP (operand, i)); 154: } 155: default: 156: break; 157: } 158: return cost; 159: } 160: 161: /* Return the register class of a scratch register needed to copy IN into 162: or out of a register in CLASS in MODE. If it can be done directly, 163: NO_REGS is returned. */ 164: 165: enum reg_class 166: secondary_reload_class (class, mode, in) 167: enum reg_class class; 168: enum machine_mode mode; 169: rtx in; 170: { 171: int regno = true_regnum (in); 172: 173: if (regno >= FIRST_PSEUDO_REGISTER) 174: regno = -1; 175: 176: /* We can place anything into GENERAL_REGS and can put GENERAL_REGS 177: into anything. */ 178: if (class == GENERAL_REGS || (regno >= 0 && regno < 8)) 179: return NO_REGS; 180: 181: /* Constants, memory, and FP registers can go into FP registers. */ 182: if ((regno == -1 || (regno >= 8 && regno < 16)) && (class == FLOAT_REGS)) 183: return NO_REGS; 184: 185: #if 0 /* This isn't strictly true (can't move fp to sp or vice versa), 186: so it's cleaner to use PREFERRED_RELOAD_CLASS 187: to make the right things happen. */ 188: if (regno >= 16 && class == GEN_AND_MEM_REGS) 189: return NO_REGS; 190: #endif 191: 192: /* Otherwise, we need GENERAL_REGS. */ 193: return GENERAL_REGS; 194: } 195: /* Generate the rtx that comes from an address expression in the md file */ 196: /* The expression to be build is BASE[INDEX:SCALE]. To recognize this, 197: scale must be converted from an exponent (from ASHIFT) to a 198: multiplier (for MULT). */ 199: rtx 200: gen_indexed_expr (base, index, scale) 201: rtx base, index, scale; 202: { 203: rtx addr; 204: 205: /* This generates an illegal addressing mode, if BASE is 206: fp or sp. This is handled by PRINT_OPERAND_ADDRESS. */ 207: if (GET_CODE (base) != REG && GET_CODE (base) != CONST_INT) 208: base = gen_rtx (MEM, SImode, base); 209: addr = gen_rtx (MULT, SImode, index, 210: gen_rtx (CONST_INT, VOIDmode, 1 << INTVAL (scale))); 211: addr = gen_rtx (PLUS, SImode, base, addr); 212: return addr; 213: } 214: 215: /* Return 1 if OP is a valid operand of mode MODE. This 216: predicate rejects operands which do not have a mode 217: (such as CONST_INT which are VOIDmode). */ 218: int 219: reg_or_mem_operand (op, mode) 220: register rtx op; 221: enum machine_mode mode; 222: { 223: return (GET_MODE (op) == mode 224: && (GET_CODE (op) == REG 225: || GET_CODE (op) == SUBREG 226: || GET_CODE (op) == MEM)); 227: } 228: 229: /* Return the best assembler insn template 230: for moving operands[1] into operands[0] as a fullword. */ 231: 232: static char * 233: singlemove_string (operands) 234: rtx *operands; 235: { 236: if (GET_CODE (operands[1]) == CONST_INT 237: && INTVAL (operands[1]) <= 7 238: && INTVAL (operands[1]) >= -8) 239: return "movqd %1,%0"; 240: return "movd %1,%0"; 241: } 242: 243: char * 244: output_move_double (operands) 245: rtx *operands; 246: { 1.1.1.2 root 247: enum anon1 { REGOP, OFFSOP, PUSHOP, CNSTOP, RNDOP } optype0, optype1; 1.1 root 248: rtx latehalf[2]; 249: 250: /* First classify both operands. */ 251: 252: if (REG_P (operands[0])) 253: optype0 = REGOP; 254: else if (offsettable_memref_p (operands[0])) 255: optype0 = OFFSOP; 256: else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) 1.1.1.2 root 257: optype0 = PUSHOP; 1.1 root 258: else 259: optype0 = RNDOP; 260: 261: if (REG_P (operands[1])) 262: optype1 = REGOP; 1.1.1.3 ! root 263: else if (CONSTANT_P (operands[1]) 1.1 root 264: || GET_CODE (operands[1]) == CONST_DOUBLE) 265: optype1 = CNSTOP; 266: else if (offsettable_memref_p (operands[1])) 267: optype1 = OFFSOP; 268: else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) 1.1.1.2 root 269: optype1 = PUSHOP; 1.1 root 270: else 271: optype1 = RNDOP; 272: 273: /* Check for the cases that the operand constraints are not 274: supposed to allow to happen. Abort if we get one, 275: because generating code for these cases is painful. */ 276: 277: if (optype0 == RNDOP || optype1 == RNDOP) 278: abort (); 279: 280: /* Ok, we can do one word at a time. 281: Normally we do the low-numbered word first, 282: but if either operand is autodecrementing then we 283: do the high-numbered word first. 284: 285: In either case, set up in LATEHALF the operands to use 286: for the high-numbered word and in some cases alter the 287: operands in OPERANDS to be suitable for the low-numbered word. */ 288: 289: if (optype0 == REGOP) 290: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); 291: else if (optype0 == OFFSOP) 292: latehalf[0] = adj_offsettable_operand (operands[0], 4); 293: else 294: latehalf[0] = operands[0]; 295: 296: if (optype1 == REGOP) 297: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); 298: else if (optype1 == OFFSOP) 299: latehalf[1] = adj_offsettable_operand (operands[1], 4); 300: else if (optype1 == CNSTOP) 1.1.1.3 ! root 301: split_double (operands[1], &operands[1], &latehalf[1]); 1.1 root 302: else 303: latehalf[1] = operands[1]; 304: 1.1.1.2 root 305: /* If insn is effectively movd N(sp),tos then we will do the 306: high word first. We should use the adjusted operand 1 (which is N+4(sp)) 307: for the low word as well, to compensate for the first decrement of sp. 308: Given this, it doesn't matter which half we do "first". */ 309: if (optype0 == PUSHOP 310: && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM 311: && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1])) 312: operands[1] = latehalf[1]; 313: 1.1 root 314: /* If one or both operands autodecrementing, 315: do the two words, high-numbered first. */ 1.1.1.2 root 316: else if (optype0 == PUSHOP || optype1 == PUSHOP) 317: { 318: output_asm_insn (singlemove_string (latehalf), latehalf); 319: return singlemove_string (operands); 320: } 321: 322: /* If the first move would clobber the source of the second one, 323: do them in the other order. */ 1.1 root 324: 1.1.1.2 root 325: /* Overlapping registers. */ 326: if (optype0 == REGOP && optype1 == REGOP 327: && REGNO (operands[0]) == REGNO (latehalf[1])) 1.1 root 328: { 1.1.1.2 root 329: /* Do that word. */ 1.1 root 330: output_asm_insn (singlemove_string (latehalf), latehalf); 1.1.1.2 root 331: /* Do low-numbered word. */ 1.1 root 332: return singlemove_string (operands); 333: } 1.1.1.2 root 334: /* Loading into a register which overlaps a register used in the address. */ 335: else if (optype0 == REGOP && optype1 != REGOP 336: && reg_overlap_mentioned_p (operands[0], operands[1])) 337: { 338: if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)) 339: && reg_mentioned_p (latehalf[0], XEXP (operands[1], 0))) 340: { 341: /* If both halves of dest are used in the src memory address, 1.1.1.3 ! root 342: load the destination address into the low reg (operands[0]). 1.1.1.2 root 343: Then it works to load latehalf first. */ 344: rtx xops[2]; 1.1.1.3 ! root 345: xops[0] = XEXP (operands[1], 0); 1.1.1.2 root 346: xops[1] = operands[0]; 1.1.1.3 ! root 347: output_asm_insn ("addr %a0,%1", xops); 1.1.1.2 root 348: operands[1] = gen_rtx (MEM, DImode, operands[0]); 349: latehalf[1] = adj_offsettable_operand (operands[1], 4); 350: /* The first half has the overlap, Do the late half first. */ 351: output_asm_insn (singlemove_string (latehalf), latehalf); 352: /* Then clobber. */ 353: return singlemove_string (operands); 354: } 355: if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))) 356: { 357: /* The first half has the overlap, Do the late half first. */ 358: output_asm_insn (singlemove_string (latehalf), latehalf); 359: /* Then clobber. */ 360: return singlemove_string (operands); 361: } 362: } 1.1 root 363: 1.1.1.2 root 364: /* Normal case. Do the two words, low-numbered first. */ 1.1 root 365: 366: output_asm_insn (singlemove_string (operands), operands); 367: 368: operands[0] = latehalf[0]; 369: operands[1] = latehalf[1]; 370: return singlemove_string (operands); 371: } 372: 373: int 374: check_reg (oper, reg) 375: rtx oper; 376: int reg; 377: { 378: register int i; 379: 380: if (oper == 0) 381: return 0; 382: switch (GET_CODE(oper)) 383: { 384: case REG: 385: return (REGNO(oper) == reg) ? 1 : 0; 386: case MEM: 387: return check_reg(XEXP(oper, 0), reg); 388: case PLUS: 389: case MULT: 390: return check_reg(XEXP(oper, 0), reg) || check_reg(XEXP(oper, 1), reg); 391: } 392: return 0; 393: } 1.1.1.3 ! root 394: ! 395: /* Returns 1 if OP contains a global symbol reference */ ! 396: ! 397: int ! 398: global_symbolic_reference_mentioned_p (op, f) ! 399: rtx op; ! 400: int f; ! 401: { ! 402: register char *fmt; ! 403: register int i; ! 404: ! 405: if (GET_CODE (op) == SYMBOL_REF) ! 406: { ! 407: if (! SYMBOL_REF_FLAG (op)) ! 408: return 1; ! 409: else ! 410: return 0; ! 411: } ! 412: else if (f && GET_CODE (op) != CONST) ! 413: return 0; ! 414: ! 415: fmt = GET_RTX_FORMAT (GET_CODE (op)); ! 416: for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--) ! 417: { ! 418: if (fmt[i] == 'E') ! 419: { ! 420: register int j; ! 421: ! 422: for (j = XVECLEN (op, i) - 1; j >= 0; j--) ! 423: if (global_symbolic_reference_mentioned_p (XVECEXP (op, i, j), 0)) ! 424: return 1; ! 425: } ! 426: else if (fmt[i] == 'e' ! 427: && global_symbolic_reference_mentioned_p (XEXP (op, i), 0)) ! 428: return 1; ! 429: } ! 430: ! 431: return 0; ! 432: } ! 433: 1.1 root 434: 435: /* PRINT_OPERAND is defined to call this function, 436: which is easier to debug than putting all the code in 437: a macro definition in ns32k.h. */ 438: 439: void 440: print_operand (file, x, code) 441: FILE *file; 442: rtx x; 443: char code; 444: { 445: if (code == '$') 446: PUT_IMMEDIATE_PREFIX (file); 447: else if (code == '?') 448: PUT_EXTERNAL_PREFIX (file); 449: else if (GET_CODE (x) == REG) 450: fprintf (file, "%s", reg_names[REGNO (x)]); 451: else if (GET_CODE (x) == MEM) 452: { 453: rtx tmp = XEXP (x, 0); 1.1.1.3 ! root 454: output_address (XEXP (x, 0)); 1.1 root 455: } 1.1.1.3 ! root 456: else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != VOIDmode) 1.1 root 457: { 458: if (GET_MODE (x) == DFmode) 459: { 460: union { double d; int i[2]; } u; 461: u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x); 462: PUT_IMMEDIATE_PREFIX(file); 463: #ifdef SEQUENT_ASM 464: /* Sequent likes it's floating point constants as integers */ 465: fprintf (file, "0Dx%08x%08x", u.i[1], u.i[0]); 466: #else 467: #ifdef ENCORE_ASM 468: fprintf (file, "0f%.20e", u.d); 469: #else 470: fprintf (file, "0d%.20e", u.d); 471: #endif 472: #endif 473: } 474: else 475: { 476: union { double d; int i[2]; } u; 477: u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x); 478: PUT_IMMEDIATE_PREFIX (file); 479: #ifdef SEQUENT_ASM 480: /* We have no way of winning if we can't get the bits 481: for a sequent floating point number. */ 482: #if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT 483: abort (); 484: #endif 485: { 486: union { float f; long l; } uu; 487: uu.f = u.d; 488: fprintf (file, "0Fx%08x", uu.l); 489: } 490: #else 491: fprintf (file, "0f%.20e", u.d); 492: #endif 493: } 494: } 495: else 496: { 497: #ifdef NO_IMMEDIATE_PREFIX_IF_SYMBOLIC 498: if (GET_CODE (x) == CONST_INT) 499: #endif 500: PUT_IMMEDIATE_PREFIX (file); 501: output_addr_const (file, x); 502: } 503: } 504: 505: /* PRINT_OPERAND_ADDRESS is defined to call this function, 506: which is easier to debug than putting all the code in 507: a macro definition in ns32k.h . */ 508: 509: /* Completely rewritten to get this to work with Gas for PC532 Mach. 510: This function didn't work and I just wasn't able (nor very willing) to 511: figure out how it worked. 512: 90-11-25 Tatu Yl|nen <[email protected]> */ 513: 514: print_operand_address (file, addr) 515: register FILE *file; 516: register rtx addr; 517: { 518: static char scales[] = { 'b', 'w', 'd', 0, 'q', }; 519: rtx offset, base, indexexp, tmp; 520: int scale; 1.1.1.3 ! root 521: extern int flag_pic; 1.1 root 522: 523: if (GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == POST_DEC) 524: { 525: fprintf (file, "tos"); 526: return; 527: } 528: 529: offset = NULL; 530: base = NULL; 531: indexexp = NULL; 532: while (addr != NULL) 533: { 534: if (GET_CODE (addr) == PLUS) 535: { 536: if (GET_CODE (XEXP (addr, 0)) == PLUS) 537: { 538: tmp = XEXP (addr, 1); 539: addr = XEXP (addr, 0); 540: } 541: else 542: { 543: tmp = XEXP (addr,0); 544: addr = XEXP (addr,1); 545: } 546: } 547: else 548: { 549: tmp = addr; 550: addr = NULL; 551: } 552: switch (GET_CODE (tmp)) 553: { 554: case PLUS: 555: abort (); 556: case MEM: 557: if (base) 558: { 559: indexexp = base; 560: base = tmp; 561: } 562: else 563: base = tmp; 564: break; 565: case REG: 566: if (REGNO (tmp) < 8) 567: if (base) 568: { 569: indexexp = tmp; 570: } 571: else 572: base = tmp; 573: else 574: if (base) 575: { 576: indexexp = base; 577: base = tmp; 578: } 579: else 580: base = tmp; 581: break; 582: case MULT: 583: indexexp = tmp; 584: break; 1.1.1.3 ! root 585: case SYMBOL_REF: ! 586: if (flag_pic && ! CONSTANT_POOL_ADDRESS_P (tmp) ! 587: && ! SYMBOL_REF_FLAG (tmp)) ! 588: { ! 589: if (base) ! 590: { ! 591: if (indexexp) ! 592: abort (); ! 593: indexexp = base; ! 594: } ! 595: base = tmp; ! 596: break; ! 597: } 1.1 root 598: case CONST: 1.1.1.3 ! root 599: if (flag_pic && GET_CODE (tmp) == CONST) ! 600: { ! 601: rtx sym, off, tmp1; ! 602: tmp1 = XEXP (tmp,0); ! 603: if (GET_CODE (tmp1) != PLUS) ! 604: abort (); ! 605: ! 606: sym = XEXP (tmp1,0); ! 607: if (GET_CODE (sym) != SYMBOL_REF) ! 608: { ! 609: off = sym; ! 610: sym = XEXP (tmp1,1); ! 611: } ! 612: else ! 613: off = XEXP (tmp1,1); ! 614: if (GET_CODE (sym) == SYMBOL_REF) ! 615: { ! 616: if (GET_CODE (off) != CONST_INT) ! 617: abort (); ! 618: ! 619: if (CONSTANT_POOL_ADDRESS_P (sym) ! 620: || SYMBOL_REF_FLAG (sym)) ! 621: { ! 622: SYMBOL_REF_FLAG (tmp) = 1; ! 623: } ! 624: else ! 625: { ! 626: if (base) ! 627: { ! 628: if (indexexp) ! 629: abort (); ! 630: ! 631: indexexp = base; ! 632: } ! 633: ! 634: if (offset != 0) ! 635: abort (); ! 636: ! 637: base = sym; ! 638: offset = off; ! 639: break; ! 640: } ! 641: } ! 642: } 1.1 root 643: case CONST_INT: 644: case LABEL_REF: 645: if (offset) 646: offset = gen_rtx (PLUS, SImode, tmp, offset); 647: else 648: offset = tmp; 649: break; 650: default: 651: abort (); 652: } 653: } 654: if (! offset) 655: offset = const0_rtx; 656: 1.1.1.3 ! root 657: if (base ! 658: #ifndef INDEX_RATHER_THAN_BASE ! 659: && (flag_pic || TARGET_HIMEM) ! 660: && GET_CODE (base) != SYMBOL_REF ! 661: && GET_CODE (offset) != CONST_INT ! 662: #else 1.1 root 663: /* This is a re-implementation of the SEQUENT_ADDRESS_BUG fix. */ 1.1.1.3 ! root 664: #endif ! 665: && !indexexp && GET_CODE (base) == REG 1.1 root 666: && REG_OK_FOR_INDEX_P (base)) 667: { 668: indexexp = base; 1.1.1.3 ! root 669: base = NULL; 1.1 root 670: } 671: 672: /* now, offset, base and indexexp are set */ 1.1.1.3 ! root 673: #ifndef BASE_REG_NEEDED 1.1 root 674: if (! base) 675: { 676: #if defined (PC_RELATIVE) || defined (NO_ABSOLUTE_PREFIX_IF_SYMBOLIC) 677: if (GET_CODE (offset) == CONST_INT) 678: #endif 679: PUT_ABSOLUTE_PREFIX (file); 680: } 1.1.1.3 ! root 681: #endif 1.1 root 682: 683: output_addr_const (file, offset); 684: if (base) /* base can be (REG ...) or (MEM ...) */ 685: switch (GET_CODE (base)) 686: { 687: /* now we must output base. Possible alternatives are: 688: (rN) (REG ...) 689: (sp) (REG ...) 690: (fp) (REG ...) 691: (pc) (REG ...) used for SYMBOL_REF and LABEL_REF, output 692: (disp(fp)) (MEM ...) just before possible [rX:y] 693: (disp(sp)) (MEM ...) 694: (disp(sb)) (MEM ...) 695: */ 696: case REG: 697: fprintf (file, "(%s)", reg_names[REGNO (base)]); 698: break; 1.1.1.3 ! root 699: case SYMBOL_REF: ! 700: if (! flag_pic) ! 701: abort (); ! 702: ! 703: fprintf (file, "("); ! 704: output_addr_const (file, base); ! 705: fprintf (file, "(sb))"); ! 706: break; 1.1 root 707: case MEM: 708: addr = XEXP(base,0); 709: base = NULL; 710: offset = NULL; 711: while (addr != NULL) 712: { 713: if (GET_CODE (addr) == PLUS) 714: { 715: if (GET_CODE (XEXP (addr, 0)) == PLUS) 716: { 717: tmp = XEXP (addr, 1); 718: addr = XEXP (addr, 0); 719: } 720: else 721: { 722: tmp = XEXP (addr, 0); 723: addr = XEXP (addr, 1); 724: } 725: } 726: else 727: { 728: tmp = addr; 729: addr = NULL; 730: } 731: switch (GET_CODE (tmp)) 732: { 733: case REG: 734: base = tmp; 735: break; 736: case CONST: 737: case CONST_INT: 738: case SYMBOL_REF: 739: case LABEL_REF: 740: if (offset) 741: offset = gen_rtx (PLUS, SImode, tmp, offset); 742: else 743: offset = tmp; 744: break; 745: default: 746: abort (); 747: } 748: } 749: if (! offset) 750: offset = const0_rtx; 751: fprintf (file, "("); 752: output_addr_const (file, offset); 753: if (base) 754: fprintf (file, "(%s)", reg_names[REGNO (base)]); 755: else if (TARGET_SB) 756: fprintf (file, "(sb)"); 757: else 758: abort (); 759: fprintf (file, ")"); 760: break; 761: default: 762: abort (); 763: } 764: #ifdef PC_RELATIVE 1.1.1.3 ! root 765: else if (GET_CODE (offset) != CONST_INT) ! 766: fprintf (file, "(pc)"); ! 767: #ifdef BASE_REG_NEEDED ! 768: else if (TARGET_SB) ! 769: fprintf (file, "(sb)"); ! 770: else ! 771: abort (); 1.1 root 772: #endif 1.1.1.3 ! root 773: #endif /* PC_RELATIVE */ ! 774: 1.1 root 775: /* now print index if we have one */ 776: if (indexexp) 777: { 778: if (GET_CODE (indexexp) == MULT) 779: { 780: scale = INTVAL (XEXP (indexexp, 1)) >> 1; 781: indexexp = XEXP (indexexp, 0); 782: } 783: else 784: scale = 0; 785: if (GET_CODE (indexexp) != REG || REGNO (indexexp) >= 8) 786: abort (); 787: 788: #ifdef UTEK_ASM 789: fprintf (file, "[%c`%s]", 790: scales[scale], 791: reg_names[REGNO (indexexp)]); 792: #else 793: fprintf (file, "[%s:%c]", 794: reg_names[REGNO (indexexp)], 795: scales[scale]); 796: #endif 797: } 798: } 799: 800: /* National 32032 shifting is so bad that we can get 801: better performance in many common cases by using other 802: techniques. */ 803: char * 804: output_shift_insn (operands) 805: rtx *operands; 806: { 807: if (GET_CODE (operands[2]) == CONST_INT 808: && INTVAL (operands[2]) > 0 809: && INTVAL (operands[2]) <= 3) 810: if (GET_CODE (operands[0]) == REG) 811: { 812: if (GET_CODE (operands[1]) == REG) 813: { 814: if (REGNO (operands[0]) == REGNO (operands[1])) 815: { 816: if (operands[2] == const1_rtx) 817: return "addd %0,%0"; 818: else if (INTVAL (operands[2]) == 2) 819: return "addd %0,%0\n\taddd %0,%0"; 820: } 821: if (operands[2] == const1_rtx) 822: return "movd %1,%0\n\taddd %0,%0"; 823: 824: operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]); 825: return "addr %a1,%0"; 826: } 827: if (operands[2] == const1_rtx) 828: return "movd %1,%0\n\taddd %0,%0"; 829: } 830: else if (GET_CODE (operands[1]) == REG) 831: { 832: operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]); 833: return "addr %a1,%0"; 834: } 835: else if (INTVAL (operands[2]) == 1 836: && GET_CODE (operands[1]) == MEM 837: && rtx_equal_p (operands [0], operands[1])) 838: { 839: rtx temp = XEXP (operands[1], 0); 840: 841: if (GET_CODE (temp) == REG 842: || (GET_CODE (temp) == PLUS 843: && GET_CODE (XEXP (temp, 0)) == REG 844: && GET_CODE (XEXP (temp, 1)) == CONST_INT)) 845: return "addd %0,%0"; 846: } 847: else return "ashd %2,%0"; 848: return "ashd %2,%0"; 849: } 1.1.1.3 ! root 850: ! 851: char * ! 852: output_move_dconst (n, s) ! 853: int n; ! 854: char *s; ! 855: { ! 856: static char r[32]; ! 857: ! 858: if (n > -9 && n < 8) ! 859: strcpy (r, "movqd "); ! 860: else if (n > 0 && n < 256) ! 861: strcpy (r, "movzbd "); ! 862: else if (n > 0 && n < 65536) ! 863: strcpy (r, "movzwd "); ! 864: else if (n < 0 && n > -129) ! 865: strcpy (r, "movxbd "); ! 866: else if (n < 0 && n > -32769) ! 867: strcpy (r, "movxwd "); ! 868: else ! 869: strcpy (r, "movd "); ! 870: strcat (r, s); ! 871: return r; ! 872: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.