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