|
|
1.1 ! root 1: /* Subroutines for insn-output.c for Intel 80386. ! 2: Copyright (C) 1988, 1992 Free Software Foundation, Inc. ! 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: #include <stdio.h> ! 21: #include <setjmp.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: #include "insn-codes.h" ! 33: #include "tree.h" ! 34: #include "flags.h" ! 35: #include "function.h" ! 36: ! 37: #include "machopic.h" ! 38: ! 39: #ifdef EXTRA_CONSTRAINT ! 40: /* If EXTRA_CONSTRAINT is defined, then the 'S' ! 41: constraint in REG_CLASS_FROM_LETTER will no longer work, and various ! 42: asm statements that need 'S' for class SIREG will break. */ ! 43: error EXTRA_CONSTRAINT conflicts with S constraint letter ! 44: /* The previous line used to be #error, but some compilers barf ! 45: even if the conditional was untrue. */ ! 46: #endif ! 47: ! 48: #define AT_BP(mode) (gen_rtx (MEM, (mode), frame_pointer_rtx)) ! 49: ! 50: extern FILE *asm_out_file; ! 51: extern char *strcat (); ! 52: ! 53: char *singlemove_string (); ! 54: char *output_move_const_single (); ! 55: char *output_fp_cc0_set (); ! 56: ! 57: char *hi_reg_name[] = HI_REGISTER_NAMES; ! 58: char *qi_reg_name[] = QI_REGISTER_NAMES; ! 59: char *qi_high_reg_name[] = QI_HIGH_REGISTER_NAMES; ! 60: ! 61: /* Array of the smallest class containing reg number REGNO, indexed by ! 62: REGNO. Used by REGNO_REG_CLASS in i386.h. */ ! 63: ! 64: enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] = ! 65: { ! 66: /* ax, dx, cx, bx */ ! 67: AREG, DREG, CREG, BREG, ! 68: /* si, di, bp, sp */ ! 69: SIREG, DIREG, INDEX_REGS, GENERAL_REGS, ! 70: /* FP registers */ ! 71: FP_TOP_REG, FP_SECOND_REG, FLOAT_REGS, FLOAT_REGS, ! 72: FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, ! 73: /* arg pointer */ ! 74: INDEX_REGS ! 75: }; ! 76: ! 77: /* Test and compare insns in i386.md store the information needed to ! 78: generate branch and scc insns here. */ ! 79: ! 80: struct rtx_def *i386_compare_op0, *i386_compare_op1; ! 81: struct rtx_def *(*i386_compare_gen)(), *(*i386_compare_gen_eq)(); ! 82: ! 83: /* Output an insn whose source is a 386 integer register. SRC is the ! 84: rtx for the register, and TEMPLATE is the op-code template. SRC may ! 85: be either SImode or DImode. ! 86: ! 87: The template will be output with operands[0] as SRC, and operands[1] ! 88: as a pointer to the top of the 386 stack. So a call from floatsidf2 ! 89: would look like this: ! 90: ! 91: output_op_from_reg (operands[1], AS1 (fild%z0,%1)); ! 92: ! 93: where %z0 corresponds to the caller's operands[1], and is used to ! 94: emit the proper size suffix. ! 95: ! 96: ??? Extend this to handle HImode - a 387 can load and store HImode ! 97: values directly. */ ! 98: ! 99: void ! 100: output_op_from_reg (src, template) ! 101: rtx src; ! 102: char *template; ! 103: { ! 104: rtx xops[4]; ! 105: int size = GET_MODE_SIZE (GET_MODE (src)); ! 106: ! 107: xops[0] = src; ! 108: xops[1] = AT_SP (Pmode); ! 109: xops[2] = GEN_INT (size); ! 110: xops[3] = stack_pointer_rtx; ! 111: ! 112: if (size > UNITS_PER_WORD) ! 113: { ! 114: rtx high; ! 115: if (size > 2 * UNITS_PER_WORD) ! 116: { ! 117: high = gen_rtx (REG, SImode, REGNO (src) + 2); ! 118: output_asm_insn (AS1 (push%L0,%0), &high); ! 119: } ! 120: high = gen_rtx (REG, SImode, REGNO (src) + 1); ! 121: output_asm_insn (AS1 (push%L0,%0), &high); ! 122: } ! 123: output_asm_insn (AS1 (push%L0,%0), &src); ! 124: ! 125: output_asm_insn (template, xops); ! 126: ! 127: output_asm_insn (AS2 (add%L3,%2,%3), xops); ! 128: } ! 129: ! 130: /* Output an insn to pop an value from the 387 top-of-stack to 386 ! 131: register DEST. The 387 register stack is popped if DIES is true. If ! 132: the mode of DEST is an integer mode, a `fist' integer store is done, ! 133: otherwise a `fst' float store is done. */ ! 134: ! 135: void ! 136: output_to_reg (dest, dies) ! 137: rtx dest; ! 138: int dies; ! 139: { ! 140: rtx xops[4]; ! 141: int size = GET_MODE_SIZE (GET_MODE (dest)); ! 142: ! 143: xops[0] = AT_SP (Pmode); ! 144: xops[1] = stack_pointer_rtx; ! 145: xops[2] = GEN_INT (size); ! 146: xops[3] = dest; ! 147: ! 148: output_asm_insn (AS2 (sub%L1,%2,%1), xops); ! 149: ! 150: if (GET_MODE_CLASS (GET_MODE (dest)) == MODE_INT) ! 151: { ! 152: if (dies) ! 153: output_asm_insn (AS1 (fistp%z3,%y0), xops); ! 154: else ! 155: output_asm_insn (AS1 (fist%z3,%y0), xops); ! 156: } ! 157: else if (GET_MODE_CLASS (GET_MODE (dest)) == MODE_FLOAT) ! 158: { ! 159: if (dies) ! 160: output_asm_insn (AS1 (fstp%z3,%y0), xops); ! 161: else ! 162: { ! 163: if (GET_MODE (dest) == XFmode) ! 164: { ! 165: output_asm_insn (AS1 (fstp%z3,%y0), xops); ! 166: output_asm_insn (AS1 (fld%z3,%y0), xops); ! 167: } ! 168: else ! 169: output_asm_insn (AS1 (fst%z3,%y0), xops); ! 170: } ! 171: } ! 172: else ! 173: abort (); ! 174: ! 175: output_asm_insn (AS1 (pop%L0,%0), &dest); ! 176: ! 177: if (size > UNITS_PER_WORD) ! 178: { ! 179: dest = gen_rtx (REG, SImode, REGNO (dest) + 1); ! 180: output_asm_insn (AS1 (pop%L0,%0), &dest); ! 181: if (size > 2 * UNITS_PER_WORD) ! 182: { ! 183: dest = gen_rtx (REG, SImode, REGNO (dest) + 1); ! 184: output_asm_insn (AS1 (pop%L0,%0), &dest); ! 185: } ! 186: } ! 187: } ! 188: ! 189: char * ! 190: singlemove_string (operands) ! 191: rtx *operands; ! 192: { ! 193: rtx x; ! 194: if (GET_CODE (operands[0]) == MEM ! 195: && GET_CODE (x = XEXP (operands[0], 0)) == PRE_DEC) ! 196: { ! 197: if (XEXP (x, 0) != stack_pointer_rtx) ! 198: abort (); ! 199: return "push%L1 %1"; ! 200: } ! 201: else if (GET_CODE (operands[1]) == CONST_DOUBLE) ! 202: { ! 203: return output_move_const_single (operands); ! 204: } ! 205: else if (GET_CODE (operands[0]) == REG || GET_CODE (operands[1]) == REG) ! 206: return AS2 (mov%L0,%1,%0); ! 207: else if (CONSTANT_P (operands[1])) ! 208: return AS2 (mov%L0,%1,%0); ! 209: else ! 210: { ! 211: output_asm_insn ("push%L1 %1", operands); ! 212: return "pop%L0 %0"; ! 213: } ! 214: } ! 215: ! 216: /* Return a REG that occurs in ADDR with coefficient 1. ! 217: ADDR can be effectively incremented by incrementing REG. */ ! 218: ! 219: static rtx ! 220: find_addr_reg (addr) ! 221: rtx addr; ! 222: { ! 223: while (GET_CODE (addr) == PLUS) ! 224: { ! 225: if (GET_CODE (XEXP (addr, 0)) == REG) ! 226: addr = XEXP (addr, 0); ! 227: else if (GET_CODE (XEXP (addr, 1)) == REG) ! 228: addr = XEXP (addr, 1); ! 229: else if (CONSTANT_P (XEXP (addr, 0))) ! 230: addr = XEXP (addr, 1); ! 231: else if (CONSTANT_P (XEXP (addr, 1))) ! 232: addr = XEXP (addr, 0); ! 233: else ! 234: abort (); ! 235: } ! 236: if (GET_CODE (addr) == REG) ! 237: return addr; ! 238: abort (); ! 239: } ! 240: ! 241: /* Output an insn to add the constant N to the register X. */ ! 242: ! 243: static void ! 244: asm_add (n, x) ! 245: int n; ! 246: rtx x; ! 247: { ! 248: rtx xops[2]; ! 249: xops[1] = x; ! 250: if (n < 0) ! 251: { ! 252: xops[0] = GEN_INT (-n); ! 253: output_asm_insn (AS2 (sub%L0,%0,%1), xops); ! 254: } ! 255: else if (n > 0) ! 256: { ! 257: xops[0] = GEN_INT (n); ! 258: output_asm_insn (AS2 (add%L0,%0,%1), xops); ! 259: } ! 260: } ! 261: ! 262: /* Output assembler code to perform a doubleword move insn ! 263: with operands OPERANDS. */ ! 264: ! 265: char * ! 266: output_move_double (operands) ! 267: rtx *operands; ! 268: { ! 269: enum {REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; ! 270: rtx latehalf[2]; ! 271: rtx middlehalf[2]; ! 272: rtx xops[2]; ! 273: rtx addreg0 = 0, addreg1 = 0; ! 274: int dest_overlapped_low = 0; ! 275: int size = GET_MODE_SIZE (GET_MODE (operands[1])); ! 276: ! 277: middlehalf[0] = 0; ! 278: middlehalf[1] = 0; ! 279: ! 280: /* First classify both operands. */ ! 281: ! 282: if (REG_P (operands[0])) ! 283: optype0 = REGOP; ! 284: else if (offsettable_memref_p (operands[0])) ! 285: optype0 = OFFSOP; ! 286: else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC) ! 287: optype0 = POPOP; ! 288: else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) ! 289: optype0 = PUSHOP; ! 290: else if (GET_CODE (operands[0]) == MEM) ! 291: optype0 = MEMOP; ! 292: else ! 293: optype0 = RNDOP; ! 294: ! 295: if (REG_P (operands[1])) ! 296: optype1 = REGOP; ! 297: else if (CONSTANT_P (operands[1])) ! 298: optype1 = CNSTOP; ! 299: else if (offsettable_memref_p (operands[1])) ! 300: optype1 = OFFSOP; ! 301: else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC) ! 302: optype1 = POPOP; ! 303: else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) ! 304: optype1 = PUSHOP; ! 305: else if (GET_CODE (operands[1]) == MEM) ! 306: optype1 = MEMOP; ! 307: else ! 308: optype1 = RNDOP; ! 309: ! 310: /* Check for the cases that the operand constraints are not ! 311: supposed to allow to happen. Abort if we get one, ! 312: because generating code for these cases is painful. */ ! 313: ! 314: if (optype0 == RNDOP || optype1 == RNDOP) ! 315: abort (); ! 316: ! 317: /* If one operand is decrementing and one is incrementing ! 318: decrement the former register explicitly ! 319: and change that operand into ordinary indexing. */ ! 320: ! 321: if (optype0 == PUSHOP && optype1 == POPOP) ! 322: { ! 323: /* ??? Can this ever happen on i386? */ ! 324: operands[0] = XEXP (XEXP (operands[0], 0), 0); ! 325: asm_add (-size, operands[0]); ! 326: if (GET_MODE (operands[1]) == XFmode) ! 327: operands[0] = gen_rtx (MEM, XFmode, operands[0]); ! 328: else if (GET_MODE (operands[0]) == DFmode) ! 329: operands[0] = gen_rtx (MEM, DFmode, operands[0]); ! 330: else ! 331: operands[0] = gen_rtx (MEM, DImode, operands[0]); ! 332: optype0 = OFFSOP; ! 333: } ! 334: ! 335: if (optype0 == POPOP && optype1 == PUSHOP) ! 336: { ! 337: /* ??? Can this ever happen on i386? */ ! 338: operands[1] = XEXP (XEXP (operands[1], 0), 0); ! 339: asm_add (-size, operands[1]); ! 340: if (GET_MODE (operands[1]) == XFmode) ! 341: operands[1] = gen_rtx (MEM, XFmode, operands[1]); ! 342: else if (GET_MODE (operands[1]) == DFmode) ! 343: operands[1] = gen_rtx (MEM, DFmode, operands[1]); ! 344: else ! 345: operands[1] = gen_rtx (MEM, DImode, operands[1]); ! 346: optype1 = OFFSOP; ! 347: } ! 348: ! 349: /* If an operand is an unoffsettable memory ref, find a register ! 350: we can increment temporarily to make it refer to the second word. */ ! 351: ! 352: if (optype0 == MEMOP) ! 353: addreg0 = find_addr_reg (XEXP (operands[0], 0)); ! 354: ! 355: if (optype1 == MEMOP) ! 356: addreg1 = find_addr_reg (XEXP (operands[1], 0)); ! 357: ! 358: /* Ok, we can do one word at a time. ! 359: Normally we do the low-numbered word first, ! 360: but if either operand is autodecrementing then we ! 361: do the high-numbered word first. ! 362: ! 363: In either case, set up in LATEHALF the operands to use ! 364: for the high-numbered word and in some cases alter the ! 365: operands in OPERANDS to be suitable for the low-numbered word. */ ! 366: ! 367: if (size == 12) ! 368: { ! 369: if (optype0 == REGOP) ! 370: { ! 371: middlehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); ! 372: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 2); ! 373: } ! 374: else if (optype0 == OFFSOP) ! 375: { ! 376: middlehalf[0] = adj_offsettable_operand (operands[0], 4); ! 377: latehalf[0] = adj_offsettable_operand (operands[0], 8); ! 378: } ! 379: else ! 380: { ! 381: middlehalf[0] = operands[0]; ! 382: latehalf[0] = operands[0]; ! 383: } ! 384: ! 385: if (optype1 == REGOP) ! 386: { ! 387: middlehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); ! 388: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 2); ! 389: } ! 390: else if (optype1 == OFFSOP) ! 391: { ! 392: middlehalf[1] = adj_offsettable_operand (operands[1], 4); ! 393: latehalf[1] = adj_offsettable_operand (operands[1], 8); ! 394: } ! 395: else if (optype1 == CNSTOP) ! 396: { ! 397: if (GET_CODE (operands[1]) == CONST_DOUBLE) ! 398: { ! 399: REAL_VALUE_TYPE r; long l[3]; ! 400: ! 401: REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]); ! 402: REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, l); ! 403: operands[1] = GEN_INT (l[0]); ! 404: middlehalf[1] = GEN_INT (l[1]); ! 405: latehalf[1] = GEN_INT (l[2]); ! 406: } ! 407: else if (CONSTANT_P (operands[1])) ! 408: /* No non-CONST_DOUBLE constant should ever appear here. */ ! 409: abort (); ! 410: } ! 411: else ! 412: { ! 413: middlehalf[1] = operands[1]; ! 414: latehalf[1] = operands[1]; ! 415: } ! 416: } ! 417: else /* size is not 12: */ ! 418: { ! 419: if (optype0 == REGOP) ! 420: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); ! 421: else if (optype0 == OFFSOP) ! 422: latehalf[0] = adj_offsettable_operand (operands[0], 4); ! 423: else ! 424: latehalf[0] = operands[0]; ! 425: ! 426: if (optype1 == REGOP) ! 427: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); ! 428: else if (optype1 == OFFSOP) ! 429: latehalf[1] = adj_offsettable_operand (operands[1], 4); ! 430: else if (optype1 == CNSTOP) ! 431: { ! 432: if (GET_CODE (operands[1]) == CONST_DOUBLE) ! 433: split_double (operands[1], &operands[1], &latehalf[1]); ! 434: else if (CONSTANT_P (operands[1])) ! 435: { ! 436: /* ??? jrv: Can this really happen? A DImode constant ! 437: that isn't a CONST_DOUBLE? */ ! 438: if (GET_CODE (operands[1]) == CONST_INT ! 439: && INTVAL (operands[1]) < 0) ! 440: latehalf[1] = constm1_rtx; ! 441: else ! 442: latehalf[1] = const0_rtx; ! 443: } ! 444: } ! 445: else ! 446: latehalf[1] = operands[1]; ! 447: } ! 448: ! 449: /* If insn is effectively movd N (sp),-(sp) then we will do the ! 450: high word first. We should use the adjusted operand 1 ! 451: (which is N+4 (sp) or N+8 (sp)) ! 452: for the low word and middle word as well, ! 453: to compensate for the first decrement of sp. */ ! 454: if (optype0 == PUSHOP ! 455: && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM ! 456: && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1])) ! 457: middlehalf[1] = operands[1] = latehalf[1]; ! 458: ! 459: /* For (set (reg:DI N) (mem:DI ... (reg:SI N) ...)), ! 460: if the upper part of reg N does not appear in the MEM, arrange to ! 461: emit the move late-half first. Otherwise, compute the MEM address ! 462: into the upper part of N and use that as a pointer to the memory ! 463: operand. */ ! 464: if (optype0 == REGOP ! 465: && (optype1 == OFFSOP || optype1 == MEMOP)) ! 466: { ! 467: if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)) ! 468: && reg_mentioned_p (latehalf[0], XEXP (operands[1], 0))) ! 469: { ! 470: /* If both halves of dest are used in the src memory address, ! 471: compute the address into latehalf of dest. */ ! 472: compadr: ! 473: xops[0] = latehalf[0]; ! 474: xops[1] = XEXP (operands[1], 0); ! 475: output_asm_insn (AS2 (lea%L0,%a1,%0), xops); ! 476: if( GET_MODE (operands[1]) == XFmode ) ! 477: { ! 478: /* abort (); */ ! 479: operands[1] = gen_rtx (MEM, XFmode, latehalf[0]); ! 480: middlehalf[1] = adj_offsettable_operand (operands[1], size-8); ! 481: latehalf[1] = adj_offsettable_operand (operands[1], size-4); ! 482: } ! 483: else ! 484: { ! 485: operands[1] = gen_rtx (MEM, DImode, latehalf[0]); ! 486: latehalf[1] = adj_offsettable_operand (operands[1], size-4); ! 487: } ! 488: } ! 489: else if (size == 12 ! 490: && reg_mentioned_p (middlehalf[0], XEXP (operands[1], 0))) ! 491: { ! 492: /* Check for two regs used by both source and dest. */ ! 493: if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)) ! 494: || reg_mentioned_p (latehalf[0], XEXP (operands[1], 0))) ! 495: goto compadr; ! 496: ! 497: /* JRV says this can't happen: */ ! 498: if (addreg0 || addreg1) ! 499: abort(); ! 500: ! 501: /* Only the middle reg conflicts; simply put it last. */ ! 502: output_asm_insn (singlemove_string (operands), operands); ! 503: output_asm_insn (singlemove_string (latehalf), latehalf); ! 504: output_asm_insn (singlemove_string (middlehalf), middlehalf); ! 505: return ""; ! 506: } ! 507: else if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))) ! 508: /* If the low half of dest is mentioned in the source memory ! 509: address, the arrange to emit the move late half first. */ ! 510: dest_overlapped_low = 1; ! 511: } ! 512: ! 513: /* If one or both operands autodecrementing, ! 514: do the two words, high-numbered first. */ ! 515: ! 516: /* Likewise, the first move would clobber the source of the second one, ! 517: do them in the other order. This happens only for registers; ! 518: such overlap can't happen in memory unless the user explicitly ! 519: sets it up, and that is an undefined circumstance. */ ! 520: ! 521: /* ! 522: if (optype0 == PUSHOP || optype1 == PUSHOP ! 523: || (optype0 == REGOP && optype1 == REGOP ! 524: && REGNO (operands[0]) == REGNO (latehalf[1])) ! 525: || dest_overlapped_low) ! 526: */ ! 527: if (optype0 == PUSHOP || optype1 == PUSHOP ! 528: || (optype0 == REGOP && optype1 == REGOP ! 529: && ((middlehalf[1] && REGNO (operands[0]) == REGNO (middlehalf[1])) ! 530: || REGNO (operands[0]) == REGNO (latehalf[1]))) ! 531: || dest_overlapped_low) ! 532: { ! 533: /* Make any unoffsettable addresses point at high-numbered word. */ ! 534: if (addreg0) ! 535: asm_add (size-4, addreg0); ! 536: if (addreg1) ! 537: asm_add (size-4, addreg1); ! 538: ! 539: /* Do that word. */ ! 540: output_asm_insn (singlemove_string (latehalf), latehalf); ! 541: ! 542: /* Undo the adds we just did. */ ! 543: if (addreg0) ! 544: asm_add (-4, addreg0); ! 545: if (addreg1) ! 546: asm_add (-4, addreg1); ! 547: ! 548: if (size == 12) ! 549: { ! 550: output_asm_insn (singlemove_string (middlehalf), middlehalf); ! 551: if (addreg0) ! 552: asm_add (-4, addreg0); ! 553: if (addreg1) ! 554: asm_add (-4, addreg1); ! 555: } ! 556: ! 557: /* Do low-numbered word. */ ! 558: return singlemove_string (operands); ! 559: } ! 560: ! 561: /* Normal case: do the two words, low-numbered first. */ ! 562: ! 563: output_asm_insn (singlemove_string (operands), operands); ! 564: ! 565: /* Do the middle one of the three words for long double */ ! 566: if (size == 12) ! 567: { ! 568: if (addreg0) ! 569: asm_add (4, addreg0); ! 570: if (addreg1) ! 571: asm_add (4, addreg1); ! 572: ! 573: output_asm_insn (singlemove_string (middlehalf), middlehalf); ! 574: } ! 575: ! 576: /* Make any unoffsettable addresses point at high-numbered word. */ ! 577: if (addreg0) ! 578: asm_add (4, addreg0); ! 579: if (addreg1) ! 580: asm_add (4, addreg1); ! 581: ! 582: /* Do that word. */ ! 583: output_asm_insn (singlemove_string (latehalf), latehalf); ! 584: ! 585: /* Undo the adds we just did. */ ! 586: if (addreg0) ! 587: asm_add (4-size, addreg0); ! 588: if (addreg1) ! 589: asm_add (4-size, addreg1); ! 590: ! 591: return ""; ! 592: } ! 593: ! 594: int ! 595: standard_80387_constant_p (x) ! 596: rtx x; ! 597: { ! 598: #if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC) ! 599: REAL_VALUE_TYPE d; ! 600: jmp_buf handler; ! 601: int is0, is1; ! 602: ! 603: if (setjmp (handler)) ! 604: return 0; ! 605: ! 606: set_float_handler (handler); ! 607: REAL_VALUE_FROM_CONST_DOUBLE (d, x); ! 608: is0 = REAL_VALUES_EQUAL (d, dconst0); ! 609: is1 = REAL_VALUES_EQUAL (d, dconst1); ! 610: set_float_handler (NULL_PTR); ! 611: ! 612: if (is0) ! 613: return 1; ! 614: ! 615: if (is1) ! 616: return 2; ! 617: ! 618: /* Note that on the 80387, other constants, such as pi, ! 619: are much slower to load as standard constants ! 620: than to load from doubles in memory! */ ! 621: #endif ! 622: ! 623: return 0; ! 624: } ! 625: ! 626: char * ! 627: output_move_const_single (operands) ! 628: rtx *operands; ! 629: { ! 630: if (FP_REG_P (operands[0])) ! 631: { ! 632: int conval = standard_80387_constant_p (operands[1]); ! 633: ! 634: if (conval == 1) ! 635: return "fldz"; ! 636: ! 637: if (conval == 2) ! 638: return "fld1"; ! 639: } ! 640: if (GET_CODE (operands[1]) == CONST_DOUBLE) ! 641: { ! 642: REAL_VALUE_TYPE r; long l; ! 643: ! 644: if (GET_MODE (operands[1]) == XFmode) ! 645: abort (); ! 646: ! 647: REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]); ! 648: REAL_VALUE_TO_TARGET_SINGLE (r, l); ! 649: operands[1] = GEN_INT (l); ! 650: } ! 651: return singlemove_string (operands); ! 652: } ! 653: ! 654: /* Returns 1 if OP is either a symbol reference or a sum of a symbol ! 655: reference and a constant. */ ! 656: ! 657: int ! 658: symbolic_operand (op, mode) ! 659: register rtx op; ! 660: enum machine_mode mode; ! 661: { ! 662: switch (GET_CODE (op)) ! 663: { ! 664: case SYMBOL_REF: ! 665: case LABEL_REF: ! 666: return 1; ! 667: case CONST: ! 668: op = XEXP (op, 0); ! 669: return (GET_CODE (op) == SYMBOL_REF ! 670: || ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF ! 671: || GET_CODE (XEXP (op, 0)) == LABEL_REF) ! 672: && GET_CODE (XEXP (op, 1)) == CONST_INT)); ! 673: default: ! 674: return 0; ! 675: } ! 676: } ! 677: ! 678: /* Test for a valid operand for a call instruction. ! 679: Don't allow the arg pointer register or virtual regs ! 680: since they may change into reg + const, which the patterns ! 681: can't handle yet. */ ! 682: ! 683: int ! 684: call_insn_operand (op, mode) ! 685: rtx op; ! 686: enum machine_mode mode; ! 687: { ! 688: if (GET_CODE (op) == MEM ! 689: && ((CONSTANT_ADDRESS_P (XEXP (op, 0)) ! 690: /* This makes a difference for PIC. */ ! 691: && general_operand (XEXP (op, 0), Pmode)) ! 692: || (GET_CODE (XEXP (op, 0)) == REG ! 693: && XEXP (op, 0) != arg_pointer_rtx ! 694: && !(REGNO (XEXP (op, 0)) >= FIRST_PSEUDO_REGISTER ! 695: && REGNO (XEXP (op, 0)) <= LAST_VIRTUAL_REGISTER)))) ! 696: return 1; ! 697: return 0; ! 698: } ! 699: ! 700: /* Like call_insn_operand but allow (mem (symbol_ref ...)) ! 701: even if pic. */ ! 702: ! 703: int ! 704: expander_call_insn_operand (op, mode) ! 705: rtx op; ! 706: enum machine_mode mode; ! 707: { ! 708: if (GET_CODE (op) == MEM ! 709: && (CONSTANT_ADDRESS_P (XEXP (op, 0)) ! 710: || (GET_CODE (XEXP (op, 0)) == REG ! 711: && XEXP (op, 0) != arg_pointer_rtx ! 712: && !(REGNO (XEXP (op, 0)) >= FIRST_PSEUDO_REGISTER ! 713: && REGNO (XEXP (op, 0)) <= LAST_VIRTUAL_REGISTER)))) ! 714: return 1; ! 715: return 0; ! 716: } ! 717: ! 718: /* Returns 1 if OP contains a symbol reference */ ! 719: ! 720: int ! 721: symbolic_reference_mentioned_p (op) ! 722: rtx op; ! 723: { ! 724: register char *fmt; ! 725: register int i; ! 726: ! 727: if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF) ! 728: return 1; ! 729: ! 730: fmt = GET_RTX_FORMAT (GET_CODE (op)); ! 731: for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--) ! 732: { ! 733: if (fmt[i] == 'E') ! 734: { ! 735: register int j; ! 736: ! 737: for (j = XVECLEN (op, i) - 1; j >= 0; j--) ! 738: if (symbolic_reference_mentioned_p (XVECEXP (op, i, j))) ! 739: return 1; ! 740: } ! 741: else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i))) ! 742: return 1; ! 743: } ! 744: ! 745: return 0; ! 746: } ! 747: ! 748: /* Return a legitimate reference for ORIG (an address) using the ! 749: register REG. If REG is 0, a new pseudo is generated. ! 750: ! 751: There are three types of references that must be handled: ! 752: ! 753: 1. Global data references must load the address from the GOT, via ! 754: the PIC reg. An insn is emitted to do this load, and the reg is ! 755: returned. ! 756: ! 757: 2. Static data references must compute the address as an offset ! 758: from the GOT, whose base is in the PIC reg. An insn is emitted to ! 759: compute the address into a reg, and the reg is returned. Static ! 760: data objects have SYMBOL_REF_FLAG set to differentiate them from ! 761: global data objects. ! 762: ! 763: 3. Constant pool addresses must be handled special. They are ! 764: considered legitimate addresses, but only if not used with regs. ! 765: When printed, the output routines know to print the reference with the ! 766: PIC reg, even though the PIC reg doesn't appear in the RTL. ! 767: ! 768: GO_IF_LEGITIMATE_ADDRESS rejects symbolic references unless the PIC ! 769: reg also appears in the address (except for constant pool references, ! 770: noted above). ! 771: ! 772: "switch" statements also require special handling when generating ! 773: PIC code. See comments by the `casesi' insn in i386.md for details. */ ! 774: ! 775: rtx ! 776: legitimize_pic_address (orig, reg) ! 777: rtx orig; ! 778: rtx reg; ! 779: { ! 780: rtx addr = orig; ! 781: rtx new = orig; ! 782: ! 783: #ifdef MACHO_PIC ! 784: if (reg == 0) ! 785: reg = gen_reg_rtx (Pmode); ! 786: return machopic_legitimize_pic_address (orig, GET_MODE (orig), reg); ! 787: #endif ! 788: ! 789: if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF) ! 790: { ! 791: if (GET_CODE (addr) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (addr)) ! 792: reg = new = orig; ! 793: else ! 794: { ! 795: if (reg == 0) ! 796: reg = gen_reg_rtx (Pmode); ! 797: ! 798: if (GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_FLAG (addr)) ! 799: new = gen_rtx (PLUS, Pmode, pic_offset_table_rtx, orig); ! 800: else ! 801: new = gen_rtx (MEM, Pmode, ! 802: gen_rtx (PLUS, Pmode, ! 803: pic_offset_table_rtx, orig)); ! 804: ! 805: emit_move_insn (reg, new); ! 806: } ! 807: current_function_uses_pic_offset_table = 1; ! 808: return reg; ! 809: } ! 810: else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS) ! 811: { ! 812: rtx base; ! 813: ! 814: if (GET_CODE (addr) == CONST) ! 815: { ! 816: addr = XEXP (addr, 0); ! 817: if (GET_CODE (addr) != PLUS) ! 818: abort (); ! 819: } ! 820: ! 821: if (XEXP (addr, 0) == pic_offset_table_rtx) ! 822: return orig; ! 823: ! 824: if (reg == 0) ! 825: reg = gen_reg_rtx (Pmode); ! 826: ! 827: base = legitimize_pic_address (XEXP (addr, 0), reg); ! 828: addr = legitimize_pic_address (XEXP (addr, 1), ! 829: base == reg ? NULL_RTX : reg); ! 830: ! 831: if (GET_CODE (addr) == CONST_INT) ! 832: return plus_constant (base, INTVAL (addr)); ! 833: ! 834: if (GET_CODE (addr) == PLUS && CONSTANT_P (XEXP (addr, 1))) ! 835: { ! 836: base = gen_rtx (PLUS, Pmode, base, XEXP (addr, 0)); ! 837: addr = XEXP (addr, 1); ! 838: } ! 839: return gen_rtx (PLUS, Pmode, base, addr); ! 840: } ! 841: return new; ! 842: } ! 843: ! 844: /* Emit insns to move operands[1] into operands[0]. */ ! 845: ! 846: void ! 847: emit_pic_move (operands, mode) ! 848: rtx *operands; ! 849: enum machine_mode mode; ! 850: { ! 851: rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode); ! 852: ! 853: #ifdef MACHO_PIC ! 854: if (MACHOPIC_PURE) ! 855: { ! 856: operands[1] = machopic_indirect_data_reference (operands[1], temp); ! 857: operands[1] = machopic_legitimize_pic_address (operands[1], mode, ! 858: temp == operands[1] ? 0 : temp); ! 859: } ! 860: else if (MACHOPIC_INDIRECT) ! 861: { ! 862: operands[1] = machopic_indirect_data_reference (operands[1], 0); ! 863: } ! 864: #else ! 865: if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1])) ! 866: operands[1] = (rtx) force_reg (SImode, operands[1]); ! 867: else if (SYMBOLIC_CONST (operands[1])) ! 868: operands[1] = legitimize_pic_address (operands[1], temp); ! 869: #endif ! 870: } ! 871: ! 872: /* This function generates the assembly code for function entry. ! 873: FILE is an stdio stream to output the code to. ! 874: SIZE is an int: how many units of temporary storage to allocate. */ ! 875: ! 876: void ! 877: function_prologue (file, size) ! 878: FILE *file; ! 879: int size; ! 880: { ! 881: register int regno; ! 882: int limit; ! 883: rtx xops[4]; ! 884: int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table ! 885: || current_function_uses_const_pool); ! 886: ! 887: xops[0] = stack_pointer_rtx; ! 888: xops[1] = frame_pointer_rtx; ! 889: xops[2] = GEN_INT (size); ! 890: if (frame_pointer_needed) ! 891: { ! 892: output_asm_insn ("push%L1 %1", xops); ! 893: output_asm_insn (AS2 (mov%L0,%0,%1), xops); ! 894: } ! 895: ! 896: if (size) ! 897: output_asm_insn (AS2 (sub%L0,%2,%0), xops); ! 898: ! 899: /* Note If use enter it is NOT reversed args. ! 900: This one is not reversed from intel!! ! 901: I think enter is slower. Also sdb doesn't like it. ! 902: But if you want it the code is: ! 903: { ! 904: xops[3] = const0_rtx; ! 905: output_asm_insn ("enter %2,%3", xops); ! 906: } ! 907: */ ! 908: limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM); ! 909: for (regno = limit - 1; regno >= 0; regno--) ! 910: if ((regs_ever_live[regno] && ! call_used_regs[regno]) ! 911: || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) ! 912: { ! 913: xops[0] = gen_rtx (REG, SImode, regno); ! 914: output_asm_insn ("push%L0 %0", xops); ! 915: } ! 916: ! 917: if (pic_reg_used) ! 918: { ! 919: xops[0] = pic_offset_table_rtx; ! 920: xops[1] = (rtx) gen_label_rtx (); ! 921: ! 922: output_asm_insn (AS1 (call,%P1), xops); ! 923: ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (xops[1])); ! 924: #ifdef MACHO_PIC ! 925: assemble_name (file, machopic_function_base_name ()); ! 926: asm_fprintf (file, ":\n"); ! 927: #endif ! 928: output_asm_insn (AS1 (pop%L0,%0), xops); ! 929: #ifndef MACHO_PIC ! 930: output_asm_insn ("addl $_GLOBAL_OFFSET_TABLE_+[.-%P1],%0", xops); ! 931: #endif ! 932: } ! 933: } ! 934: ! 935: /* Return 1 if it is appropriate to emit `ret' instructions in the ! 936: body of a function. Do this only if the epilogue is simple, needing a ! 937: couple of insns. Prior to reloading, we can't tell how many registers ! 938: must be saved, so return 0 then. ! 939: ! 940: If NON_SAVING_SETJMP is defined and true, then it is not possible ! 941: for the epilogue to be simple, so return 0. This is a special case ! 942: since NON_SAVING_SETJMP will not cause regs_ever_live to change until ! 943: final, but jump_optimize may need to know sooner if a `return' is OK. */ ! 944: ! 945: int ! 946: simple_386_epilogue () ! 947: { ! 948: int regno; ! 949: int nregs = 0; ! 950: int reglimit = (frame_pointer_needed ! 951: ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM); ! 952: int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table ! 953: || current_function_uses_const_pool); ! 954: ! 955: #ifdef NON_SAVING_SETJMP ! 956: if (NON_SAVING_SETJMP && current_function_calls_setjmp) ! 957: return 0; ! 958: #endif ! 959: ! 960: if (! reload_completed) ! 961: return 0; ! 962: ! 963: for (regno = reglimit - 1; regno >= 0; regno--) ! 964: if ((regs_ever_live[regno] && ! call_used_regs[regno]) ! 965: || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) ! 966: nregs++; ! 967: ! 968: return nregs == 0 || ! frame_pointer_needed; ! 969: } ! 970: ! 971: /* This function generates the assembly code for function exit. ! 972: FILE is an stdio stream to output the code to. ! 973: SIZE is an int: how many units of temporary storage to deallocate. */ ! 974: ! 975: void ! 976: function_epilogue (file, size) ! 977: FILE *file; ! 978: int size; ! 979: { ! 980: register int regno; ! 981: register int nregs, limit; ! 982: int offset; ! 983: rtx xops[3]; ! 984: int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table ! 985: || current_function_uses_const_pool); ! 986: ! 987: /* Compute the number of registers to pop */ ! 988: ! 989: limit = (frame_pointer_needed ! 990: ? FRAME_POINTER_REGNUM ! 991: : STACK_POINTER_REGNUM); ! 992: ! 993: nregs = 0; ! 994: ! 995: for (regno = limit - 1; regno >= 0; regno--) ! 996: if ((regs_ever_live[regno] && ! call_used_regs[regno]) ! 997: || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) ! 998: nregs++; ! 999: ! 1000: /* sp is often unreliable so we must go off the frame pointer, ! 1001: */ ! 1002: ! 1003: /* In reality, we may not care if sp is unreliable, because we can ! 1004: restore the register relative to the frame pointer. In theory, ! 1005: since each move is the same speed as a pop, and we don't need the ! 1006: leal, this is faster. For now restore multiple registers the old ! 1007: way. */ ! 1008: ! 1009: offset = -size - (nregs * UNITS_PER_WORD); ! 1010: ! 1011: xops[2] = stack_pointer_rtx; ! 1012: ! 1013: if (nregs > 1 || ! frame_pointer_needed) ! 1014: { ! 1015: if (frame_pointer_needed) ! 1016: { ! 1017: xops[0] = adj_offsettable_operand (AT_BP (Pmode), offset); ! 1018: output_asm_insn (AS2 (lea%L2,%0,%2), xops); ! 1019: } ! 1020: ! 1021: for (regno = 0; regno < limit; regno++) ! 1022: if ((regs_ever_live[regno] && ! call_used_regs[regno]) ! 1023: || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) ! 1024: { ! 1025: xops[0] = gen_rtx (REG, SImode, regno); ! 1026: output_asm_insn ("pop%L0 %0", xops); ! 1027: } ! 1028: } ! 1029: else ! 1030: for (regno = 0; regno < limit; regno++) ! 1031: if ((regs_ever_live[regno] && ! call_used_regs[regno]) ! 1032: || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) ! 1033: { ! 1034: xops[0] = gen_rtx (REG, SImode, regno); ! 1035: xops[1] = adj_offsettable_operand (AT_BP (Pmode), offset); ! 1036: output_asm_insn (AS2 (mov%L0,%1,%0), xops); ! 1037: offset += 4; ! 1038: } ! 1039: ! 1040: if (frame_pointer_needed) ! 1041: { ! 1042: /* On i486, mov & pop is faster than "leave". */ ! 1043: ! 1044: if (TARGET_486) ! 1045: { ! 1046: xops[0] = frame_pointer_rtx; ! 1047: output_asm_insn (AS2 (mov%L2,%0,%2), xops); ! 1048: output_asm_insn ("pop%L0 %0", xops); ! 1049: } ! 1050: else ! 1051: output_asm_insn ("leave", xops); ! 1052: } ! 1053: else if (size) ! 1054: { ! 1055: /* If there is no frame pointer, we must still release the frame. */ ! 1056: ! 1057: xops[0] = GEN_INT (size); ! 1058: output_asm_insn (AS2 (add%L2,%0,%2), xops); ! 1059: } ! 1060: ! 1061: if (current_function_pops_args && current_function_args_size) ! 1062: { ! 1063: xops[1] = GEN_INT (current_function_pops_args); ! 1064: ! 1065: /* i386 can only pop 32K bytes (maybe 64K? Is it signed?). If ! 1066: asked to pop more, pop return address, do explicit add, and jump ! 1067: indirectly to the caller. */ ! 1068: ! 1069: if (current_function_pops_args >= 32768) ! 1070: { ! 1071: /* ??? Which register to use here? */ ! 1072: xops[0] = gen_rtx (REG, SImode, 2); ! 1073: output_asm_insn ("pop%L0 %0", xops); ! 1074: output_asm_insn (AS2 (add%L2,%1,%2), xops); ! 1075: output_asm_insn ("jmp %*%0", xops); ! 1076: } ! 1077: else ! 1078: output_asm_insn ("ret %1", xops); ! 1079: } ! 1080: else ! 1081: output_asm_insn ("ret", xops); ! 1082: } ! 1083: ! 1084: /* Print an integer constant expression in assembler syntax. Addition ! 1085: and subtraction are the only arithmetic that may appear in these ! 1086: expressions. FILE is the stdio stream to write to, X is the rtx, and ! 1087: CODE is the operand print code from the output string. */ ! 1088: ! 1089: static void ! 1090: output_pic_addr_const (file, x, code) ! 1091: FILE *file; ! 1092: rtx x; ! 1093: int code; ! 1094: { ! 1095: char buf[256]; ! 1096: ! 1097: switch (GET_CODE (x)) ! 1098: { ! 1099: case PC: ! 1100: if (flag_pic) ! 1101: putc ('.', file); ! 1102: else ! 1103: abort (); ! 1104: break; ! 1105: ! 1106: case SYMBOL_REF: ! 1107: case LABEL_REF: ! 1108: if (GET_CODE (x) == SYMBOL_REF) ! 1109: assemble_name (file, XSTR (x, 0)); ! 1110: else ! 1111: { ! 1112: ASM_GENERATE_INTERNAL_LABEL (buf, "L", ! 1113: CODE_LABEL_NUMBER (XEXP (x, 0))); ! 1114: assemble_name (asm_out_file, buf); ! 1115: } ! 1116: ! 1117: #ifndef MACHO_PIC ! 1118: if (GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x)) ! 1119: fprintf (file, "@GOTOFF(%%ebx)"); ! 1120: else if (code == 'P') ! 1121: fprintf (file, "@PLT"); ! 1122: else if (GET_CODE (x) == LABEL_REF || ! SYMBOL_REF_FLAG (x)) ! 1123: fprintf (file, "@GOT"); ! 1124: else ! 1125: fprintf (file, "@GOTOFF"); ! 1126: #endif ! 1127: ! 1128: break; ! 1129: ! 1130: case CODE_LABEL: ! 1131: ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x)); ! 1132: assemble_name (asm_out_file, buf); ! 1133: break; ! 1134: ! 1135: case CONST_INT: ! 1136: fprintf (file, "%d", INTVAL (x)); ! 1137: break; ! 1138: ! 1139: case CONST: ! 1140: /* This used to output parentheses around the expression, ! 1141: but that does not work on the 386 (either ATT or BSD assembler). */ ! 1142: output_pic_addr_const (file, XEXP (x, 0), code); ! 1143: break; ! 1144: ! 1145: case CONST_DOUBLE: ! 1146: if (GET_MODE (x) == VOIDmode) ! 1147: { ! 1148: /* We can use %d if the number is <32 bits and positive. */ ! 1149: if (CONST_DOUBLE_HIGH (x) || CONST_DOUBLE_LOW (x) < 0) ! 1150: fprintf (file, "0x%x%08x", ! 1151: CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x)); ! 1152: else ! 1153: fprintf (file, "%d", CONST_DOUBLE_LOW (x)); ! 1154: } ! 1155: else ! 1156: /* We can't handle floating point constants; ! 1157: PRINT_OPERAND must handle them. */ ! 1158: output_operand_lossage ("floating constant misused"); ! 1159: break; ! 1160: ! 1161: case PLUS: ! 1162: /* Some assemblers need integer constants to appear last (eg masm). */ ! 1163: if (GET_CODE (XEXP (x, 0)) == CONST_INT) ! 1164: { ! 1165: output_pic_addr_const (file, XEXP (x, 1), code); ! 1166: if (INTVAL (XEXP (x, 0)) >= 0) ! 1167: fprintf (file, "+"); ! 1168: output_pic_addr_const (file, XEXP (x, 0), code); ! 1169: } ! 1170: else ! 1171: { ! 1172: output_pic_addr_const (file, XEXP (x, 0), code); ! 1173: if (INTVAL (XEXP (x, 1)) >= 0) ! 1174: fprintf (file, "+"); ! 1175: output_pic_addr_const (file, XEXP (x, 1), code); ! 1176: } ! 1177: break; ! 1178: ! 1179: case MINUS: ! 1180: output_pic_addr_const (file, XEXP (x, 0), code); ! 1181: fprintf (file, "-"); ! 1182: output_pic_addr_const (file, XEXP (x, 1), code); ! 1183: break; ! 1184: ! 1185: default: ! 1186: output_operand_lossage ("invalid expression as operand"); ! 1187: } ! 1188: } ! 1189: ! 1190: /* Meaning of CODE: ! 1191: f -- float insn (print a CONST_DOUBLE as a float rather than in hex). ! 1192: D,L,W,B,Q,S -- print the opcode suffix for specified size of operand. ! 1193: R -- print the prefix for register names. ! 1194: z -- print the opcode suffix for the size of the current operand. ! 1195: * -- print a star (in certain assembler syntax) ! 1196: w -- print the operand as if it's a "word" (HImode) even if it isn't. ! 1197: c -- don't print special prefixes before constant operands. ! 1198: */ ! 1199: ! 1200: void ! 1201: print_operand (file, x, code) ! 1202: FILE *file; ! 1203: rtx x; ! 1204: int code; ! 1205: { ! 1206: if (code) ! 1207: { ! 1208: switch (code) ! 1209: { ! 1210: case '*': ! 1211: if (USE_STAR) ! 1212: putc ('*', file); ! 1213: return; ! 1214: ! 1215: case 'L': ! 1216: PUT_OP_SIZE (code, 'l', file); ! 1217: return; ! 1218: ! 1219: case 'W': ! 1220: PUT_OP_SIZE (code, 'w', file); ! 1221: return; ! 1222: ! 1223: case 'B': ! 1224: PUT_OP_SIZE (code, 'b', file); ! 1225: return; ! 1226: ! 1227: case 'Q': ! 1228: PUT_OP_SIZE (code, 'l', file); ! 1229: return; ! 1230: ! 1231: case 'S': ! 1232: PUT_OP_SIZE (code, 's', file); ! 1233: return; ! 1234: ! 1235: case 'T': ! 1236: PUT_OP_SIZE (code, 't', file); ! 1237: return; ! 1238: ! 1239: case 'z': ! 1240: /* 387 opcodes don't get size suffixes if the operands are ! 1241: registers. */ ! 1242: ! 1243: if (STACK_REG_P (x)) ! 1244: return; ! 1245: ! 1246: /* this is the size of op from size of operand */ ! 1247: switch (GET_MODE_SIZE (GET_MODE (x))) ! 1248: { ! 1249: case 1: ! 1250: PUT_OP_SIZE ('B', 'b', file); ! 1251: return; ! 1252: ! 1253: case 2: ! 1254: PUT_OP_SIZE ('W', 'w', file); ! 1255: return; ! 1256: ! 1257: case 4: ! 1258: if (GET_MODE (x) == SFmode) ! 1259: { ! 1260: PUT_OP_SIZE ('S', 's', file); ! 1261: return; ! 1262: } ! 1263: else ! 1264: PUT_OP_SIZE ('L', 'l', file); ! 1265: return; ! 1266: ! 1267: case 12: ! 1268: PUT_OP_SIZE ('T', 't', file); ! 1269: return; ! 1270: ! 1271: case 8: ! 1272: if (GET_MODE_CLASS (GET_MODE (x)) == MODE_INT) ! 1273: { ! 1274: #ifdef GAS_MNEMONICS ! 1275: PUT_OP_SIZE ('Q', 'q', file); ! 1276: return; ! 1277: #else ! 1278: PUT_OP_SIZE ('Q', 'l', file); /* Fall through */ ! 1279: #endif ! 1280: } ! 1281: ! 1282: PUT_OP_SIZE ('Q', 'l', file); ! 1283: return; ! 1284: } ! 1285: ! 1286: case 'b': ! 1287: case 'w': ! 1288: case 'k': ! 1289: case 'h': ! 1290: case 'y': ! 1291: case 'P': ! 1292: break; ! 1293: ! 1294: default: ! 1295: { ! 1296: char str[50]; ! 1297: ! 1298: sprintf (str, "invalid operand code `%c'", code); ! 1299: output_operand_lossage (str); ! 1300: } ! 1301: } ! 1302: } ! 1303: if (GET_CODE (x) == REG) ! 1304: { ! 1305: PRINT_REG (x, code, file); ! 1306: } ! 1307: else if (GET_CODE (x) == MEM) ! 1308: { ! 1309: PRINT_PTR (x, file); ! 1310: if (CONSTANT_ADDRESS_P (XEXP (x, 0))) ! 1311: { ! 1312: if (flag_pic) ! 1313: output_pic_addr_const (file, XEXP (x, 0), code); ! 1314: else ! 1315: output_addr_const (file, XEXP (x, 0)); ! 1316: } ! 1317: else ! 1318: output_address (XEXP (x, 0)); ! 1319: } ! 1320: else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == SFmode) ! 1321: { ! 1322: REAL_VALUE_TYPE r; long l; ! 1323: REAL_VALUE_FROM_CONST_DOUBLE (r, x); ! 1324: REAL_VALUE_TO_TARGET_SINGLE (r, l); ! 1325: PRINT_IMMED_PREFIX (file); ! 1326: fprintf (file, "0x%x", l); ! 1327: } ! 1328: /* These float cases don't actually occur as immediate operands. */ ! 1329: else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode) ! 1330: { ! 1331: REAL_VALUE_TYPE r; char dstr[30]; ! 1332: REAL_VALUE_FROM_CONST_DOUBLE (r, x); ! 1333: REAL_VALUE_TO_DECIMAL (r, "%.22e", dstr); ! 1334: fprintf (file, "%s", dstr); ! 1335: } ! 1336: else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == XFmode) ! 1337: { ! 1338: REAL_VALUE_TYPE r; char dstr[30]; ! 1339: REAL_VALUE_FROM_CONST_DOUBLE (r, x); ! 1340: REAL_VALUE_TO_DECIMAL (r, "%.22e", dstr); ! 1341: fprintf (file, "%s", dstr); ! 1342: } ! 1343: else ! 1344: { ! 1345: if (code != 'P') ! 1346: { ! 1347: if (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE) ! 1348: PRINT_IMMED_PREFIX (file); ! 1349: else if (GET_CODE (x) == CONST || GET_CODE (x) == SYMBOL_REF ! 1350: || GET_CODE (x) == LABEL_REF) ! 1351: PRINT_OFFSET_PREFIX (file); ! 1352: } ! 1353: if (flag_pic) ! 1354: output_pic_addr_const (file, x, code); ! 1355: else ! 1356: output_addr_const (file, x); ! 1357: } ! 1358: } ! 1359: ! 1360: /* Print a memory operand whose address is ADDR. */ ! 1361: ! 1362: void ! 1363: print_operand_address (file, addr) ! 1364: FILE *file; ! 1365: register rtx addr; ! 1366: { ! 1367: register rtx reg1, reg2, breg, ireg; ! 1368: rtx offset; ! 1369: ! 1370: switch (GET_CODE (addr)) ! 1371: { ! 1372: case REG: ! 1373: ADDR_BEG (file); ! 1374: fprintf (file, "%se", RP); ! 1375: fputs (hi_reg_name[REGNO (addr)], file); ! 1376: ADDR_END (file); ! 1377: break; ! 1378: ! 1379: case PLUS: ! 1380: reg1 = 0; ! 1381: reg2 = 0; ! 1382: ireg = 0; ! 1383: breg = 0; ! 1384: offset = 0; ! 1385: if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) ! 1386: { ! 1387: offset = XEXP (addr, 0); ! 1388: addr = XEXP (addr, 1); ! 1389: } ! 1390: else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) ! 1391: { ! 1392: offset = XEXP (addr, 1); ! 1393: addr = XEXP (addr, 0); ! 1394: } ! 1395: if (GET_CODE (addr) != PLUS) ; ! 1396: else if (GET_CODE (XEXP (addr, 0)) == MULT) ! 1397: { ! 1398: reg1 = XEXP (addr, 0); ! 1399: addr = XEXP (addr, 1); ! 1400: } ! 1401: else if (GET_CODE (XEXP (addr, 1)) == MULT) ! 1402: { ! 1403: reg1 = XEXP (addr, 1); ! 1404: addr = XEXP (addr, 0); ! 1405: } ! 1406: else if (GET_CODE (XEXP (addr, 0)) == REG) ! 1407: { ! 1408: reg1 = XEXP (addr, 0); ! 1409: addr = XEXP (addr, 1); ! 1410: } ! 1411: else if (GET_CODE (XEXP (addr, 1)) == REG) ! 1412: { ! 1413: reg1 = XEXP (addr, 1); ! 1414: addr = XEXP (addr, 0); ! 1415: } ! 1416: if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT) ! 1417: { ! 1418: if (reg1 == 0) reg1 = addr; ! 1419: else reg2 = addr; ! 1420: addr = 0; ! 1421: } ! 1422: if (offset != 0) ! 1423: { ! 1424: if (addr != 0) abort (); ! 1425: addr = offset; ! 1426: } ! 1427: if ((reg1 && GET_CODE (reg1) == MULT) ! 1428: || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2)))) ! 1429: { ! 1430: breg = reg2; ! 1431: ireg = reg1; ! 1432: } ! 1433: else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1))) ! 1434: { ! 1435: breg = reg1; ! 1436: ireg = reg2; ! 1437: } ! 1438: ! 1439: if (ireg != 0 || breg != 0) ! 1440: { ! 1441: int scale = 1; ! 1442: ! 1443: if (addr != 0) ! 1444: { ! 1445: if (GET_CODE (addr) == LABEL_REF) ! 1446: output_asm_label (addr); ! 1447: else ! 1448: { ! 1449: if (flag_pic) ! 1450: output_pic_addr_const (file, addr, 0); ! 1451: else ! 1452: output_addr_const (file, addr); ! 1453: } ! 1454: } ! 1455: ! 1456: if (ireg != 0 && GET_CODE (ireg) == MULT) ! 1457: { ! 1458: scale = INTVAL (XEXP (ireg, 1)); ! 1459: ireg = XEXP (ireg, 0); ! 1460: } ! 1461: ! 1462: /* The stack pointer can only appear as a base register, ! 1463: never an index register, so exchange the regs if it is wrong. */ ! 1464: ! 1465: if (scale == 1 && ireg && REGNO (ireg) == STACK_POINTER_REGNUM) ! 1466: { ! 1467: rtx tmp; ! 1468: ! 1469: tmp = breg; ! 1470: breg = ireg; ! 1471: ireg = tmp; ! 1472: } ! 1473: ! 1474: /* output breg+ireg*scale */ ! 1475: PRINT_B_I_S (breg, ireg, scale, file); ! 1476: break; ! 1477: } ! 1478: ! 1479: case MULT: ! 1480: { ! 1481: int scale; ! 1482: if (GET_CODE (XEXP (addr, 0)) == CONST_INT) ! 1483: { ! 1484: scale = INTVAL (XEXP (addr, 0)); ! 1485: ireg = XEXP (addr, 1); ! 1486: } ! 1487: else ! 1488: { ! 1489: scale = INTVAL (XEXP (addr, 1)); ! 1490: ireg = XEXP (addr, 0); ! 1491: } ! 1492: output_addr_const (file, const0_rtx); ! 1493: PRINT_B_I_S ((rtx) 0, ireg, scale, file); ! 1494: } ! 1495: break; ! 1496: ! 1497: default: ! 1498: if (GET_CODE (addr) == CONST_INT ! 1499: && INTVAL (addr) < 0x8000 ! 1500: && INTVAL (addr) >= -0x8000) ! 1501: fprintf (file, "%d", INTVAL (addr)); ! 1502: else ! 1503: { ! 1504: if (flag_pic) ! 1505: output_pic_addr_const (file, addr, 0); ! 1506: else ! 1507: output_addr_const (file, addr); ! 1508: } ! 1509: } ! 1510: } ! 1511: ! 1512: /* Set the cc_status for the results of an insn whose pattern is EXP. ! 1513: On the 80386, we assume that only test and compare insns, as well ! 1514: as SI, HI, & DI mode ADD, SUB, NEG, AND, IOR, XOR, ASHIFT, LSHIFT, ! 1515: ASHIFTRT, and LSHIFTRT instructions set the condition codes usefully. ! 1516: Also, we assume that jumps, moves and sCOND don't affect the condition ! 1517: codes. All else clobbers the condition codes, by assumption. ! 1518: ! 1519: We assume that ALL integer add, minus, etc. instructions effect the ! 1520: condition codes. This MUST be consistent with i386.md. ! 1521: ! 1522: We don't record any float test or compare - the redundant test & ! 1523: compare check in final.c does not handle stack-like regs correctly. */ ! 1524: ! 1525: void ! 1526: notice_update_cc (exp) ! 1527: rtx exp; ! 1528: { ! 1529: if (GET_CODE (exp) == SET) ! 1530: { ! 1531: /* Jumps do not alter the cc's. */ ! 1532: if (SET_DEST (exp) == pc_rtx) ! 1533: return; ! 1534: /* Moving register or memory into a register: ! 1535: it doesn't alter the cc's, but it might invalidate ! 1536: the RTX's which we remember the cc's came from. ! 1537: (Note that moving a constant 0 or 1 MAY set the cc's). */ ! 1538: if (REG_P (SET_DEST (exp)) ! 1539: && (REG_P (SET_SRC (exp)) || GET_CODE (SET_SRC (exp)) == MEM ! 1540: || GET_RTX_CLASS (GET_CODE (SET_SRC (exp))) == '<')) ! 1541: { ! 1542: if (cc_status.value1 ! 1543: && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1)) ! 1544: cc_status.value1 = 0; ! 1545: if (cc_status.value2 ! 1546: && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2)) ! 1547: cc_status.value2 = 0; ! 1548: return; ! 1549: } ! 1550: /* Moving register into memory doesn't alter the cc's. ! 1551: It may invalidate the RTX's which we remember the cc's came from. */ ! 1552: if (GET_CODE (SET_DEST (exp)) == MEM ! 1553: && (REG_P (SET_SRC (exp)) ! 1554: || GET_RTX_CLASS (GET_CODE (SET_SRC (exp))) == '<')) ! 1555: { ! 1556: if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM) ! 1557: cc_status.value1 = 0; ! 1558: if (cc_status.value2 && GET_CODE (cc_status.value2) == MEM) ! 1559: cc_status.value2 = 0; ! 1560: return; ! 1561: } ! 1562: /* Function calls clobber the cc's. */ ! 1563: else if (GET_CODE (SET_SRC (exp)) == CALL) ! 1564: { ! 1565: CC_STATUS_INIT; ! 1566: return; ! 1567: } ! 1568: /* Tests and compares set the cc's in predictable ways. */ ! 1569: else if (SET_DEST (exp) == cc0_rtx) ! 1570: { ! 1571: CC_STATUS_INIT; ! 1572: cc_status.value1 = SET_SRC (exp); ! 1573: return; ! 1574: } ! 1575: /* Certain instructions effect the condition codes. */ ! 1576: else if (GET_MODE (SET_SRC (exp)) == SImode ! 1577: || GET_MODE (SET_SRC (exp)) == HImode ! 1578: || GET_MODE (SET_SRC (exp)) == QImode) ! 1579: switch (GET_CODE (SET_SRC (exp))) ! 1580: { ! 1581: case ASHIFTRT: case LSHIFTRT: ! 1582: case ASHIFT: case LSHIFT: ! 1583: /* Shifts on the 386 don't set the condition codes if the ! 1584: shift count is zero. */ ! 1585: if (GET_CODE (XEXP (SET_SRC (exp), 1)) != CONST_INT) ! 1586: { ! 1587: CC_STATUS_INIT; ! 1588: break; ! 1589: } ! 1590: /* We assume that the CONST_INT is non-zero (this rtx would ! 1591: have been deleted if it were zero. */ ! 1592: ! 1593: case PLUS: case MINUS: case NEG: ! 1594: case AND: case IOR: case XOR: ! 1595: cc_status.flags = CC_NO_OVERFLOW; ! 1596: cc_status.value1 = SET_SRC (exp); ! 1597: cc_status.value2 = SET_DEST (exp); ! 1598: break; ! 1599: ! 1600: default: ! 1601: CC_STATUS_INIT; ! 1602: } ! 1603: else ! 1604: { ! 1605: CC_STATUS_INIT; ! 1606: } ! 1607: } ! 1608: else if (GET_CODE (exp) == PARALLEL ! 1609: && GET_CODE (XVECEXP (exp, 0, 0)) == SET) ! 1610: { ! 1611: if (SET_DEST (XVECEXP (exp, 0, 0)) == pc_rtx) ! 1612: return; ! 1613: if (SET_DEST (XVECEXP (exp, 0, 0)) == cc0_rtx) ! 1614: { ! 1615: CC_STATUS_INIT; ! 1616: if (stack_regs_mentioned_p (SET_SRC (XVECEXP (exp, 0, 0)))) ! 1617: cc_status.flags |= CC_IN_80387; ! 1618: else ! 1619: cc_status.value1 = SET_SRC (XVECEXP (exp, 0, 0)); ! 1620: return; ! 1621: } ! 1622: CC_STATUS_INIT; ! 1623: } ! 1624: else ! 1625: { ! 1626: CC_STATUS_INIT; ! 1627: } ! 1628: } ! 1629: ! 1630: /* Split one or more DImode RTL references into pairs of SImode ! 1631: references. The RTL can be REG, offsettable MEM, integer constant, or ! 1632: CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to ! 1633: split and "num" is its length. lo_half and hi_half are output arrays ! 1634: that parallel "operands". */ ! 1635: ! 1636: void ! 1637: split_di (operands, num, lo_half, hi_half) ! 1638: rtx operands[]; ! 1639: int num; ! 1640: rtx lo_half[], hi_half[]; ! 1641: { ! 1642: while (num--) ! 1643: { ! 1644: if (GET_CODE (operands[num]) == REG) ! 1645: { ! 1646: lo_half[num] = gen_rtx (REG, SImode, REGNO (operands[num])); ! 1647: hi_half[num] = gen_rtx (REG, SImode, REGNO (operands[num]) + 1); ! 1648: } ! 1649: else if (CONSTANT_P (operands[num])) ! 1650: { ! 1651: split_double (operands[num], &lo_half[num], &hi_half[num]); ! 1652: } ! 1653: else if (offsettable_memref_p (operands[num])) ! 1654: { ! 1655: lo_half[num] = operands[num]; ! 1656: hi_half[num] = adj_offsettable_operand (operands[num], 4); ! 1657: } ! 1658: else ! 1659: abort(); ! 1660: } ! 1661: } ! 1662: ! 1663: /* Return 1 if this is a valid binary operation on a 387. ! 1664: OP is the expression matched, and MODE is its mode. */ ! 1665: ! 1666: int ! 1667: binary_387_op (op, mode) ! 1668: register rtx op; ! 1669: enum machine_mode mode; ! 1670: { ! 1671: if (mode != VOIDmode && mode != GET_MODE (op)) ! 1672: return 0; ! 1673: ! 1674: switch (GET_CODE (op)) ! 1675: { ! 1676: case PLUS: ! 1677: case MINUS: ! 1678: case MULT: ! 1679: case DIV: ! 1680: return GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT; ! 1681: ! 1682: default: ! 1683: return 0; ! 1684: } ! 1685: } ! 1686: ! 1687: /* Return 1 if this is a valid conversion operation on a 387. ! 1688: OP is the expression matched, and MODE is its mode. */ ! 1689: ! 1690: int ! 1691: convert_387_op (op, mode) ! 1692: register rtx op; ! 1693: enum machine_mode mode; ! 1694: { ! 1695: if (mode != VOIDmode && mode != GET_MODE (op)) ! 1696: return 0; ! 1697: ! 1698: switch (GET_CODE (op)) ! 1699: { ! 1700: case FLOAT: ! 1701: return GET_MODE (XEXP (op, 0)) == SImode; ! 1702: ! 1703: case FLOAT_EXTEND: ! 1704: return ((mode == DFmode && GET_MODE (XEXP (op, 0)) == SFmode) ! 1705: || (mode == XFmode && GET_MODE (XEXP (op, 0)) == DFmode) ! 1706: || (mode == XFmode && GET_MODE (XEXP (op, 0)) == SFmode)); ! 1707: ! 1708: default: ! 1709: return 0; ! 1710: } ! 1711: } ! 1712: ! 1713: /* Return 1 if this is a valid shift or rotate operation on a 386. ! 1714: OP is the expression matched, and MODE is its mode. */ ! 1715: ! 1716: int ! 1717: shift_op (op, mode) ! 1718: register rtx op; ! 1719: enum machine_mode mode; ! 1720: { ! 1721: rtx operand = XEXP (op, 0); ! 1722: ! 1723: if (mode != VOIDmode && mode != GET_MODE (op)) ! 1724: return 0; ! 1725: ! 1726: if (GET_MODE (operand) != GET_MODE (op) ! 1727: || GET_MODE_CLASS (GET_MODE (op)) != MODE_INT) ! 1728: return 0; ! 1729: ! 1730: return (GET_CODE (op) == ASHIFT ! 1731: || GET_CODE (op) == ASHIFTRT ! 1732: || GET_CODE (op) == LSHIFTRT ! 1733: || GET_CODE (op) == ROTATE ! 1734: || GET_CODE (op) == ROTATERT); ! 1735: } ! 1736: ! 1737: /* Return 1 if OP is COMPARE rtx with mode VOIDmode. ! 1738: MODE is not used. */ ! 1739: ! 1740: int ! 1741: VOIDmode_compare_op (op, mode) ! 1742: register rtx op; ! 1743: enum machine_mode mode; ! 1744: { ! 1745: return GET_CODE (op) == COMPARE && GET_MODE (op) == VOIDmode; ! 1746: } ! 1747: ! 1748: /* Output code to perform a 387 binary operation in INSN, one of PLUS, ! 1749: MINUS, MULT or DIV. OPERANDS are the insn operands, where operands[3] ! 1750: is the expression of the binary operation. The output may either be ! 1751: emitted here, or returned to the caller, like all output_* functions. ! 1752: ! 1753: There is no guarantee that the operands are the same mode, as they ! 1754: might be within FLOAT or FLOAT_EXTEND expressions. */ ! 1755: ! 1756: char * ! 1757: output_387_binary_op (insn, operands) ! 1758: rtx insn; ! 1759: rtx *operands; ! 1760: { ! 1761: rtx temp; ! 1762: char *base_op; ! 1763: static char buf[100]; ! 1764: ! 1765: switch (GET_CODE (operands[3])) ! 1766: { ! 1767: case PLUS: ! 1768: if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT ! 1769: || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT) ! 1770: base_op = "fiadd"; ! 1771: else ! 1772: base_op = "fadd"; ! 1773: break; ! 1774: ! 1775: case MINUS: ! 1776: if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT ! 1777: || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT) ! 1778: base_op = "fisub"; ! 1779: else ! 1780: base_op = "fsub"; ! 1781: break; ! 1782: ! 1783: case MULT: ! 1784: if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT ! 1785: || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT) ! 1786: base_op = "fimul"; ! 1787: else ! 1788: base_op = "fmul"; ! 1789: break; ! 1790: ! 1791: case DIV: ! 1792: if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT ! 1793: || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT) ! 1794: base_op = "fidiv"; ! 1795: else ! 1796: base_op = "fdiv"; ! 1797: break; ! 1798: ! 1799: default: ! 1800: abort (); ! 1801: } ! 1802: ! 1803: strcpy (buf, base_op); ! 1804: ! 1805: switch (GET_CODE (operands[3])) ! 1806: { ! 1807: case MULT: ! 1808: case PLUS: ! 1809: if (REG_P (operands[2]) && REGNO (operands[0]) == REGNO (operands[2])) ! 1810: { ! 1811: temp = operands[2]; ! 1812: operands[2] = operands[1]; ! 1813: operands[1] = temp; ! 1814: } ! 1815: ! 1816: if (GET_CODE (operands[2]) == MEM) ! 1817: return strcat (buf, AS1 (%z2,%2)); ! 1818: ! 1819: if (NON_STACK_REG_P (operands[1])) ! 1820: { ! 1821: output_op_from_reg (operands[1], strcat (buf, AS1 (%z0,%1))); ! 1822: RET; ! 1823: } ! 1824: else if (NON_STACK_REG_P (operands[2])) ! 1825: { ! 1826: output_op_from_reg (operands[2], strcat (buf, AS1 (%z0,%1))); ! 1827: RET; ! 1828: } ! 1829: ! 1830: if (find_regno_note (insn, REG_DEAD, REGNO (operands[2]))) ! 1831: return strcat (buf, AS2 (p,%2,%0)); ! 1832: ! 1833: if (STACK_TOP_P (operands[0])) ! 1834: return strcat (buf, AS2 (,%y2,%0)); ! 1835: else ! 1836: return strcat (buf, AS2 (,%2,%0)); ! 1837: ! 1838: case MINUS: ! 1839: case DIV: ! 1840: if (GET_CODE (operands[1]) == MEM) ! 1841: return strcat (buf, AS1 (r%z1,%1)); ! 1842: ! 1843: if (GET_CODE (operands[2]) == MEM) ! 1844: return strcat (buf, AS1 (%z2,%2)); ! 1845: ! 1846: if (NON_STACK_REG_P (operands[1])) ! 1847: { ! 1848: output_op_from_reg (operands[1], strcat (buf, AS1 (r%z0,%1))); ! 1849: RET; ! 1850: } ! 1851: else if (NON_STACK_REG_P (operands[2])) ! 1852: { ! 1853: output_op_from_reg (operands[2], strcat (buf, AS1 (%z0,%1))); ! 1854: RET; ! 1855: } ! 1856: ! 1857: if (! STACK_REG_P (operands[1]) || ! STACK_REG_P (operands[2])) ! 1858: abort (); ! 1859: ! 1860: if (find_regno_note (insn, REG_DEAD, REGNO (operands[2]))) ! 1861: return strcat (buf, AS2 (rp,%2,%0)); ! 1862: ! 1863: if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) ! 1864: return strcat (buf, AS2 (p,%1,%0)); ! 1865: ! 1866: if (STACK_TOP_P (operands[0])) ! 1867: { ! 1868: if (STACK_TOP_P (operands[1])) ! 1869: return strcat (buf, AS2 (,%y2,%0)); ! 1870: else ! 1871: return strcat (buf, AS2 (r,%y1,%0)); ! 1872: } ! 1873: else if (STACK_TOP_P (operands[1])) ! 1874: return strcat (buf, AS2 (,%1,%0)); ! 1875: else ! 1876: return strcat (buf, AS2 (r,%2,%0)); ! 1877: ! 1878: default: ! 1879: abort (); ! 1880: } ! 1881: } ! 1882: ! 1883: /* Output code for INSN to convert a float to a signed int. OPERANDS ! 1884: are the insn operands. The output may be SFmode or DFmode and the ! 1885: input operand may be SImode or DImode. As a special case, make sure ! 1886: that the 387 stack top dies if the output mode is DImode, because the ! 1887: hardware requires this. */ ! 1888: ! 1889: char * ! 1890: output_fix_trunc (insn, operands) ! 1891: rtx insn; ! 1892: rtx *operands; ! 1893: { ! 1894: int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; ! 1895: rtx xops[2]; ! 1896: ! 1897: if (! STACK_TOP_P (operands[1]) || ! 1898: (GET_MODE (operands[0]) == DImode && ! stack_top_dies)) ! 1899: abort (); ! 1900: ! 1901: xops[0] = GEN_INT (12); ! 1902: xops[1] = operands[4]; ! 1903: ! 1904: output_asm_insn (AS1 (fnstc%W2,%2), operands); ! 1905: output_asm_insn (AS2 (mov%L2,%2,%4), operands); ! 1906: output_asm_insn (AS2 (mov%B1,%0,%h1), xops); ! 1907: output_asm_insn (AS2 (mov%L4,%4,%3), operands); ! 1908: output_asm_insn (AS1 (fldc%W3,%3), operands); ! 1909: ! 1910: if (NON_STACK_REG_P (operands[0])) ! 1911: output_to_reg (operands[0], stack_top_dies); ! 1912: else if (GET_CODE (operands[0]) == MEM) ! 1913: { ! 1914: if (stack_top_dies) ! 1915: output_asm_insn (AS1 (fistp%z0,%0), operands); ! 1916: else ! 1917: output_asm_insn (AS1 (fist%z0,%0), operands); ! 1918: } ! 1919: else ! 1920: abort (); ! 1921: ! 1922: return AS1 (fldc%W2,%2); ! 1923: } ! 1924: ! 1925: /* Output code for INSN to compare OPERANDS. The two operands might ! 1926: not have the same mode: one might be within a FLOAT or FLOAT_EXTEND ! 1927: expression. If the compare is in mode CCFPEQmode, use an opcode that ! 1928: will not fault if a qNaN is present. */ ! 1929: ! 1930: char * ! 1931: output_float_compare (insn, operands) ! 1932: rtx insn; ! 1933: rtx *operands; ! 1934: { ! 1935: int stack_top_dies; ! 1936: rtx body = XVECEXP (PATTERN (insn), 0, 0); ! 1937: int unordered_compare = GET_MODE (SET_SRC (body)) == CCFPEQmode; ! 1938: ! 1939: if (! STACK_TOP_P (operands[0])) ! 1940: abort (); ! 1941: ! 1942: stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; ! 1943: ! 1944: if (STACK_REG_P (operands[1]) ! 1945: && stack_top_dies ! 1946: && find_regno_note (insn, REG_DEAD, REGNO (operands[1])) ! 1947: && REGNO (operands[1]) != FIRST_STACK_REG) ! 1948: { ! 1949: /* If both the top of the 387 stack dies, and the other operand ! 1950: is also a stack register that dies, then this must be a ! 1951: `fcompp' float compare */ ! 1952: ! 1953: if (unordered_compare) ! 1954: output_asm_insn ("fucompp", operands); ! 1955: else ! 1956: output_asm_insn ("fcompp", operands); ! 1957: } ! 1958: else ! 1959: { ! 1960: static char buf[100]; ! 1961: ! 1962: /* Decide if this is the integer or float compare opcode, or the ! 1963: unordered float compare. */ ! 1964: ! 1965: if (unordered_compare) ! 1966: strcpy (buf, "fucom"); ! 1967: else if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_FLOAT) ! 1968: strcpy (buf, "fcom"); ! 1969: else ! 1970: strcpy (buf, "ficom"); ! 1971: ! 1972: /* Modify the opcode if the 387 stack is to be popped. */ ! 1973: ! 1974: if (stack_top_dies) ! 1975: strcat (buf, "p"); ! 1976: ! 1977: if (NON_STACK_REG_P (operands[1])) ! 1978: output_op_from_reg (operands[1], strcat (buf, AS1 (%z0,%1))); ! 1979: else ! 1980: output_asm_insn (strcat (buf, AS1 (%z1,%y1)), operands); ! 1981: } ! 1982: ! 1983: /* Now retrieve the condition code. */ ! 1984: ! 1985: return output_fp_cc0_set (insn); ! 1986: } ! 1987: ! 1988: /* Output opcodes to transfer the results of FP compare or test INSN ! 1989: from the FPU to the CPU flags. If TARGET_IEEE_FP, ensure that if the ! 1990: result of the compare or test is unordered, no comparison operator ! 1991: succeeds except NE. Return an output template, if any. */ ! 1992: ! 1993: char * ! 1994: output_fp_cc0_set (insn) ! 1995: rtx insn; ! 1996: { ! 1997: rtx xops[3]; ! 1998: rtx unordered_label; ! 1999: rtx next; ! 2000: enum rtx_code code; ! 2001: ! 2002: next = next_cc0_user (insn); ! 2003: ! 2004: /* a fpcc_switch instruction may have been inserted ! 2005: here. In that case, we need to actually output that ! 2006: insn before we do the comparison below. */ ! 2007: if (next == NULL_RTX && flag_fppc) ! 2008: { ! 2009: next = next_nonnote_insn (insn); ! 2010: ! 2011: if (next && GET_CODE (next) == INSN ! 2012: && INSN_CODE (next) == CODE_FOR_fppc_switch) ! 2013: { ! 2014: /* output the fppc_switch insn in `next' here! */ ! 2015: /* ! 2016: xops[0] = XVECEXP (PATTERN (next), 0, 0); ! 2017: if (insn_template [CODE_FOR_fppc_switch]) ! 2018: { ! 2019: output_asm_insn (insn_template[CODE_FOR_fppc_switch], xops); ! 2020: } ! 2021: else ! 2022: abort (); ! 2023: */ ! 2024: next = next_cc0_user (next); ! 2025: } ! 2026: } ! 2027: ! 2028: xops[0] = gen_rtx (REG, HImode, 0); ! 2029: output_asm_insn (AS1 (fnsts%W0,%0), xops); ! 2030: ! 2031: if (! TARGET_IEEE_FP) ! 2032: return "sahf"; ! 2033: ! 2034: if (next == NULL_RTX) ! 2035: abort (); ! 2036: ! 2037: if (GET_CODE (next) == JUMP_INSN ! 2038: && GET_CODE (PATTERN (next)) == SET ! 2039: && SET_DEST (PATTERN (next)) == pc_rtx ! 2040: && GET_CODE (SET_SRC (PATTERN (next))) == IF_THEN_ELSE) ! 2041: { ! 2042: code = GET_CODE (XEXP (SET_SRC (PATTERN (next)), 0)); ! 2043: } ! 2044: else if (GET_CODE (PATTERN (next)) == SET) ! 2045: { ! 2046: code = GET_CODE (SET_SRC (PATTERN (next))); ! 2047: } ! 2048: else ! 2049: abort (); ! 2050: ! 2051: xops[0] = gen_rtx (REG, QImode, 0); ! 2052: ! 2053: switch (code) ! 2054: { ! 2055: case GT: ! 2056: xops[1] = GEN_INT (0x45); ! 2057: output_asm_insn (AS2 (and%B0,%1,%h0), xops); ! 2058: /* je label */ ! 2059: break; ! 2060: ! 2061: case LT: ! 2062: xops[1] = GEN_INT (0x45); ! 2063: xops[2] = GEN_INT (0x01); ! 2064: output_asm_insn (AS2 (and%B0,%1,%h0), xops); ! 2065: output_asm_insn (AS2 (cmp%B0,%2,%h0), xops); ! 2066: /* je label */ ! 2067: break; ! 2068: ! 2069: case GE: ! 2070: xops[1] = GEN_INT (0x05); ! 2071: output_asm_insn (AS2 (and%B0,%1,%h0), xops); ! 2072: /* je label */ ! 2073: break; ! 2074: ! 2075: case LE: ! 2076: xops[1] = GEN_INT (0x45); ! 2077: xops[2] = GEN_INT (0x40); ! 2078: output_asm_insn (AS2 (and%B0,%1,%h0), xops); ! 2079: output_asm_insn (AS1 (dec%B0,%h0), xops); ! 2080: output_asm_insn (AS2 (cmp%B0,%2,%h0), xops); ! 2081: /* jb label */ ! 2082: break; ! 2083: ! 2084: case EQ: ! 2085: xops[1] = GEN_INT (0x45); ! 2086: xops[2] = GEN_INT (0x40); ! 2087: output_asm_insn (AS2 (and%B0,%1,%h0), xops); ! 2088: output_asm_insn (AS2 (cmp%B0,%2,%h0), xops); ! 2089: /* je label */ ! 2090: break; ! 2091: ! 2092: case NE: ! 2093: xops[1] = GEN_INT (0x44); ! 2094: xops[2] = GEN_INT (0x40); ! 2095: output_asm_insn (AS2 (and%B0,%1,%h0), xops); ! 2096: output_asm_insn (AS2 (xor%B0,%2,%h0), xops); ! 2097: /* jne label */ ! 2098: break; ! 2099: ! 2100: case GTU: ! 2101: case LTU: ! 2102: case GEU: ! 2103: case LEU: ! 2104: default: ! 2105: abort (); ! 2106: } ! 2107: RET; ! 2108: } ! 2109: ! 2110: #define MAX_386_STACK_LOCALS 2 ! 2111: ! 2112: static rtx i386_stack_locals[(int) MAX_MACHINE_MODE][MAX_386_STACK_LOCALS]; ! 2113: ! 2114: /* Define the structure for the machine field in struct function. */ ! 2115: struct machine_function ! 2116: { ! 2117: rtx i386_stack_locals[(int) MAX_MACHINE_MODE][MAX_386_STACK_LOCALS]; ! 2118: }; ! 2119: ! 2120: /* Functions to save and restore i386_stack_locals. ! 2121: These will be called, via pointer variables, ! 2122: from push_function_context and pop_function_context. */ ! 2123: ! 2124: void ! 2125: save_386_machine_status (p) ! 2126: struct function *p; ! 2127: { ! 2128: p->machine = (struct machine_function *) xmalloc (sizeof i386_stack_locals); ! 2129: bcopy (i386_stack_locals, p->machine->i386_stack_locals, ! 2130: sizeof i386_stack_locals); ! 2131: } ! 2132: ! 2133: void ! 2134: restore_386_machine_status (p) ! 2135: struct function *p; ! 2136: { ! 2137: bcopy (p->machine->i386_stack_locals, i386_stack_locals, ! 2138: sizeof i386_stack_locals); ! 2139: free (p->machine); ! 2140: } ! 2141: ! 2142: /* Clear stack slot assignments remembered from previous functions. ! 2143: This is called from INIT_EXPANDERS once before RTL is emitted for each ! 2144: function. */ ! 2145: ! 2146: void ! 2147: clear_386_stack_locals () ! 2148: { ! 2149: enum machine_mode mode; ! 2150: int n; ! 2151: ! 2152: for (mode = VOIDmode; (int) mode < (int) MAX_MACHINE_MODE; ! 2153: mode = (enum machine_mode) ((int) mode + 1)) ! 2154: for (n = 0; n < MAX_386_STACK_LOCALS; n++) ! 2155: i386_stack_locals[(int) mode][n] = NULL_RTX; ! 2156: ! 2157: /* Arrange to save and restore i386_stack_locals around nested functions. */ ! 2158: save_machine_status = save_386_machine_status; ! 2159: restore_machine_status = restore_386_machine_status; ! 2160: } ! 2161: ! 2162: /* Return a MEM corresponding to a stack slot with mode MODE. ! 2163: Allocate a new slot if necessary. ! 2164: ! 2165: The RTL for a function can have several slots available: N is ! 2166: which slot to use. */ ! 2167: ! 2168: rtx ! 2169: assign_386_stack_local (mode, n) ! 2170: enum machine_mode mode; ! 2171: int n; ! 2172: { ! 2173: if (n < 0 || n >= MAX_386_STACK_LOCALS) ! 2174: abort (); ! 2175: ! 2176: if (i386_stack_locals[(int) mode][n] == NULL_RTX) ! 2177: i386_stack_locals[(int) mode][n] ! 2178: = assign_stack_local (mode, GET_MODE_SIZE (mode), 0); ! 2179: ! 2180: return i386_stack_locals[(int) mode][n]; ! 2181: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.