|
|
1.1 ! root 1: /* Subroutines for insn-output.c for Intel 80386. ! 2: Copyright (C) 1988 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 1, 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: #ifndef FILE ! 21: #include <stdio.h> ! 22: #endif ! 23: ! 24: #define FP_TOP (gen_rtx(REG, DFmode, FIRST_FLOAT_REG)) ! 25: ! 26: #define AT_SP(mode) (gen_rtx (MEM, (mode), stack_pointer_rtx)) ! 27: #define AT_BP(mode) (gen_rtx (MEM, (mode), frame_pointer_rtx)) ! 28: ! 29: #define RET return "" ! 30: ! 31: /* #define RETCOM(X) fprintf (asm_out_file, "%sX fp_pop_level=%d\n", \ ! 32: COMMENT_BEGIN, fp_pop_level); RET */ ! 33: #define RETCOM(X) return "" ! 34: ! 35: #define POP_ONE_FP \ ! 36: { /* fp_pop_level--; */ \ ! 37: fprintf (asm_out_file, "\tfstp %sst (0)\n", RP); } ! 38: ! 39: extern FILE *asm_out_file; ! 40: static char *singlemove_string (); ! 41: static void output_movf (); ! 42: static void replace_float_constant (); ! 43: static int mentions_fp_top (); ! 44: static int call_top_dead_p (); ! 45: static int fp_top_dead_p1 (); ! 46: static rtx via_memory (); ! 47: static void output_asm_insn_double_reg_op (); ! 48: ! 49: /* All output functions must increment or decrement this to indicate ! 50: the net number of pops or pushes which they perform. Note that it won't ! 51: necessarily balance with the optimize running, since we might have ! 52: two different calls with the same pop shared by cross jumping. ! 53: However on optimize the reg dead heuristic seems to work. */ ! 54: ! 55: int fp_pop_level = 0; ! 56: ! 57: static char *hi_reg_name[] = HI_REGISTER_NAMES; ! 58: static char *qi_reg_name[] = QI_REGISTER_NAMES; ! 59: ! 60: /* for fabs, fch, .. where the argument operand[1] must first be moved to ! 61: constraints "=fm" "0" */ ! 62: ! 63: #define FP_CALL1(op) \ ! 64: { if (FP_REG_P (operands[0])) \ ! 65: return op; \ ! 66: output_movf (FP_TOP, operands[1]); \ ! 67: output_asm_insn (op, operands); \ ! 68: /* fp_pop_level--; */ \ ! 69: return "fstp%z0 %0"; } ! 70: ! 71: /* handle case of call where op0/op1 is "=mf" and opn is "mrf" ! 72: eg. fadd */ ! 73: #define FP_CALL(op, rev, n) \ ! 74: return fp_call_internal (op, rev, n, operands, insn); ! 75: ! 76: static char * ! 77: fp_call_internal (op, rev, n, operands, insn) ! 78: char *op; ! 79: char *rev; ! 80: int n; ! 81: rtx *operands; ! 82: rtx insn; ! 83: { ! 84: if (!FP_REG_P (operands[0])) ! 85: { ! 86: /* Here destination is in memory ! 87: and source is in the fp stack. */ ! 88: output_movf (FP_TOP, operands[0]); ! 89: output_asm_insn_double_reg_op (op, rev, insn); ! 90: return "fstp%z0 %0"; ! 91: } ! 92: ! 93: if (FP_REG_P (operands[n])) ! 94: { ! 95: rtx temp = operands[1]; ! 96: char *tem1 = op; ! 97: operands[1] = operands[n]; ! 98: op = rev; ! 99: operands[n] = temp; ! 100: rev = tem1; ! 101: } ! 102: ! 103: if (REG_P (operands[n])) ! 104: { ! 105: rtx xops[2]; ! 106: via_memory (operands[n]); ! 107: operands[n] = AT_SP (GET_MODE (operands[n])); ! 108: xops[0] = stack_pointer_rtx; ! 109: xops[1] = gen_rtx (CONST_INT, VOIDmode, ! 110: GET_MODE_SIZE (GET_MODE (operands[n]))); ! 111: output_asm_insn (op, operands + n); ! 112: output_asm_insn (AS2 (add%L0,%1,%0), xops); ! 113: } ! 114: else ! 115: output_asm_insn (op, operands + n); ! 116: ! 117: RET; ! 118: } ! 119: ! 120: /* Output assembler code to perform insn OP ! 121: with two stack operands, and output on the stack. ! 122: ! 123: REV is the assembler insn that does the same thing but ! 124: effectively interchanges the meanings of the two arguments. ! 125: ! 126: Somewhat counterintuitively, the "first" operand was pushed last. ! 127: ! 128: The output replaces either the top-of-stack or both of the arguments, ! 129: depending on whether the other argument is wanted after this insn. */ ! 130: ! 131: static void ! 132: output_asm_insn_double_reg_op (op, rev, insn) ! 133: char *op; ! 134: char *rev; ! 135: rtx insn; ! 136: { ! 137: fputc ('\t', asm_out_file); ! 138: if (top_dead_p (insn)) ! 139: { ! 140: /* Here we want the "reversed" insn, fsubr or fdivr. ! 141: But there is an assembler bug in all 80386 assemblers ! 142: which exchanges the meanings of fsubr and fsub, and of fdivr and fdiv! ! 143: So use the "unreversed" opcode (which will assemble into ! 144: the "reversed" insn). */ ! 145: rev = op; ! 146: ! 147: while (*rev && *rev != '%') ! 148: fputc (*rev++, asm_out_file); ! 149: /* fp_pop_level--; */ ! 150: ! 151: fprintf (asm_out_file, AS2 (p,%sst,%sst(1)), RP, RP); ! 152: } ! 153: else ! 154: { ! 155: while (*op && *op != '%') ! 156: fputc (*op++, asm_out_file); ! 157: fprintf (asm_out_file,AS2 ( ,%sst(1),%sst), RP, RP); ! 158: } ! 159: putc ('\n', asm_out_file); ! 160: } ! 161: ! 162: /* Moves X to memory location 8 below stack pointer ! 163: and returns an RTX for that memory location. ! 164: X should be a register, in DFmode or SFmode. */ ! 165: ! 166: static rtx ! 167: via_memory (x) ! 168: rtx x; ! 169: { ! 170: if (!REG_P (x)) ! 171: abort (); ! 172: if (GET_MODE (x) == DFmode) ! 173: { ! 174: rtx xops[1]; ! 175: xops[0] = gen_rtx (REG, SImode, REGNO (x) + 1); ! 176: output_asm_insn ("push%L0 %0", xops); ! 177: } ! 178: output_asm_insn ("push%L0 %0", &x); ! 179: } ! 180: ! 181: /* Output an insn to copy the SFmode value in fp0 to OPERAND ! 182: without clobbering fp0. */ ! 183: ! 184: void ! 185: fp_store_sf (target) ! 186: rtx target; ! 187: { ! 188: if (REG_P (target)) ! 189: { ! 190: rtx xoperands[3]; ! 191: xoperands[0] = stack_pointer_rtx; ! 192: xoperands[1] = AT_SP (Pmode); ! 193: xoperands[2] = gen_rtx (CONST_INT, VOIDmode, -4); ! 194: output_asm_insn (AS2 (add%L0,%2,%0), xoperands); ! 195: output_asm_insn ("fst%S0 %1", xoperands); ! 196: output_asm_insn ("pop%L0 %0", &target); ! 197: } ! 198: else if (GET_CODE (target) == MEM) ! 199: output_asm_insn ("fst%S0 %0", &target); ! 200: } ! 201: ! 202: /* Output an insn to pop an SF value from fp0 into TARGET. ! 203: This destroys the value of fp0. */ ! 204: ! 205: void ! 206: fp_pop_sf (target) ! 207: rtx target; ! 208: { ! 209: if (REG_P (target)) ! 210: { ! 211: rtx xoperands[3]; ! 212: xoperands[0] = stack_pointer_rtx; ! 213: xoperands[1] = AT_SP (Pmode); ! 214: xoperands[2] = gen_rtx (CONST_INT, VOIDmode, -4); ! 215: output_asm_insn (AS2 (add%L0,%2,%0), xoperands); ! 216: output_asm_insn ("fstp%S0 %1", xoperands); ! 217: output_asm_insn ("pop%L0 %0", &target); ! 218: /* fp_pop_level--; */ ! 219: } ! 220: else if (GET_CODE (target) == MEM) ! 221: { ! 222: /* fp_pop_level--; */ ! 223: output_asm_insn ("fstp%S0 %0", &target); ! 224: } ! 225: else abort (); ! 226: } ! 227: ! 228: /* Copy the top of the fpu stack into TARGET, without popping. */ ! 229: ! 230: void ! 231: fp_store_df (target) ! 232: rtx target; ! 233: { ! 234: if (REG_P (target)) ! 235: { ! 236: rtx xoperands[4]; ! 237: xoperands[0] = stack_pointer_rtx; ! 238: xoperands[1] = gen_rtx (REG, SImode, REGNO (target) + 1); ! 239: xoperands[2] = AT_SP (Pmode); ! 240: xoperands[3] = gen_rtx (CONST_INT, VOIDmode, -8); ! 241: output_asm_insn (AS2 (add%L0,%3,%0), xoperands); ! 242: output_asm_insn ("fst%Q0 %2", xoperands); ! 243: output_asm_insn ("pop%L0 %0", &target); ! 244: output_asm_insn ("pop%L0 %1", xoperands); ! 245: } ! 246: else if (GET_CODE (target) == MEM) ! 247: output_asm_insn ("fst%Q0 %0", &target); ! 248: } ! 249: ! 250: /* Copy the top of the fpu stack into TARGET, with popping. */ ! 251: ! 252: void ! 253: fp_pop_df (target) ! 254: rtx target; ! 255: { ! 256: if (REG_P (target)) ! 257: { ! 258: rtx xoperands[4]; ! 259: xoperands[0] = stack_pointer_rtx; ! 260: xoperands[1] = gen_rtx (REG, SImode, REGNO (target) + 1); ! 261: xoperands[2] = AT_SP (Pmode); ! 262: xoperands[3] = gen_rtx (CONST_INT, VOIDmode, -8); ! 263: output_asm_insn (AS2 (add%L0,%3,%0), xoperands); ! 264: /* fp_pop_level--; */ ! 265: output_asm_insn ("fstp%Q0 %2", xoperands); ! 266: output_asm_insn ("pop%L0 %0", &target); ! 267: output_asm_insn ("pop%L0 %1", xoperands); ! 268: } ! 269: else if (GET_CODE (target) == MEM) ! 270: { ! 271: /* fp_pop_level--; */ ! 272: output_asm_insn ("fstp%z0 %0", &target); ! 273: } ! 274: } ! 275: ! 276: #if 0 ! 277: /* Pop the fp stack, convert value to integer and store in TARGET. ! 278: TARGET may be memory or register, and may have QI, HI or SImode. */ ! 279: ! 280: void ! 281: fp_pop_int (target) ! 282: rtx target; ! 283: { ! 284: if (REG_P (target) || GET_MODE (target) != SImode) ! 285: { ! 286: rtx xxops[2]; ! 287: xxops[0] = stack_pointer_rtx; ! 288: xxops[1] = gen_rtx (CONST_INT, VOIDmode, 4); ! 289: output_asm_insn (AS2 (sub%L0,%1,%0), xxops); ! 290: xxops[0] = AT_SP (Pmode); ! 291: /* fp_pop_level--; */ ! 292: output_asm_insn ("fistps %0", xxops); ! 293: output_asm_insn ("pop%L0 %0", &target); ! 294: } ! 295: else if (GET_CODE (target) == MEM) ! 296: { ! 297: /* fp_pop_level--; */ ! 298: output_asm_insn ("fistps %0", &target); ! 299: } ! 300: else abort (); ! 301: } ! 302: #endif ! 303: ! 304: /* Push the SFmode value X onto the fpu stack. */ ! 305: ! 306: void ! 307: fp_push_sf (x) ! 308: rtx x; ! 309: { ! 310: /* fp_pop_level++; */ ! 311: if (REG_P (x)) ! 312: { ! 313: rtx xoperands[2]; ! 314: rtx xfops[3]; ! 315: output_asm_insn ("push%L0 %0", &x); ! 316: xfops[0] = AT_SP (Pmode); ! 317: xfops[2] = gen_rtx (CONST_INT, VOIDmode, 4); ! 318: xfops[1] = stack_pointer_rtx; ! 319: output_asm_insn ("fld%S0 %0 \n\tadd%L0 %2,%1", xfops); ! 320: } ! 321: else ! 322: output_asm_insn ("fld%S0 %0", &x); ! 323: } ! 324: ! 325: /* Push the DFmode value X onto the fpu stack. */ ! 326: ! 327: void ! 328: fp_push_df (x) ! 329: rtx x; ! 330: { ! 331: /* fp_pop_level++; */ ! 332: ! 333: if (REG_P (x)) ! 334: { ! 335: rtx xoperands[2]; ! 336: rtx xfops[3]; ! 337: xoperands[0] = x; ! 338: xoperands[1] = gen_rtx (REG, SImode, REGNO (x) + 1); ! 339: output_asm_insn ("push%L0 %1", xoperands); ! 340: output_asm_insn ("push%L0 %0", xoperands); ! 341: xfops[0] = AT_SP (Pmode); ! 342: xfops[2] = gen_rtx (CONST_INT, VOIDmode, 8); ! 343: xfops[1] = stack_pointer_rtx; ! 344: output_asm_insn ("fld%Q0 %0 \n\tadd%L0 %2,%1", xfops); ! 345: } ! 346: else if (GET_CODE (x) == MEM) ! 347: output_asm_insn ("fld%Q0 %0", &x); ! 348: } ! 349: ! 350: static char *output_move_const_single (); ! 351: ! 352: static char * ! 353: singlemove_string (operands) ! 354: rtx *operands; ! 355: { ! 356: rtx x; ! 357: if (GET_CODE (operands[0]) == MEM ! 358: && GET_CODE (x = XEXP (operands[0], 0)) == PRE_DEC) ! 359: { ! 360: if (XEXP (x, 0) != stack_pointer_rtx) ! 361: abort (); ! 362: return "push%L0 %1"; ! 363: } ! 364: else if (GET_CODE (operands[1]) == CONST_DOUBLE) ! 365: { ! 366: return output_move_const_single (operands); ! 367: } ! 368: else if (GET_CODE (operands[0]) == REG || GET_CODE (operands[1]) == REG) ! 369: return AS2 (mov%L0,%1,%0); ! 370: else ! 371: { ! 372: output_asm_insn ("push%L0 %1", operands); ! 373: return "pop%L0 %0"; ! 374: } ! 375: } ! 376: ! 377: /* Return a REG that occurs in ADDR with coefficient 1. ! 378: ADDR can be effectively incremented by incrementing REG. */ ! 379: ! 380: static rtx ! 381: find_addr_reg (addr) ! 382: rtx addr; ! 383: { ! 384: while (GET_CODE (addr) == PLUS) ! 385: { ! 386: if (GET_CODE (XEXP (addr, 0)) == REG) ! 387: addr = XEXP (addr, 0); ! 388: else if (GET_CODE (XEXP (addr, 1)) == REG) ! 389: addr = XEXP (addr, 1); ! 390: else if (CONSTANT_P (XEXP (addr, 0))) ! 391: addr = XEXP (addr, 1); ! 392: else if (CONSTANT_P (XEXP (addr, 1))) ! 393: addr = XEXP (addr, 0); ! 394: else ! 395: abort (); ! 396: } ! 397: if (GET_CODE (addr) == REG) ! 398: return addr; ! 399: abort (); ! 400: } ! 401: ! 402: /* Output an insn to add the constant N to the register X. */ ! 403: ! 404: static void ! 405: asm_add (n, x) ! 406: int n; ! 407: rtx x; ! 408: { ! 409: rtx xops[2]; ! 410: xops[1] = x; ! 411: if (n < 0) ! 412: { ! 413: xops[0] = gen_rtx (CONST_INT, VOIDmode, -n); ! 414: output_asm_insn (AS2 (sub%L0,%0,%1), xops); ! 415: } ! 416: else if (n > 0) ! 417: { ! 418: xops[0] = gen_rtx (CONST_INT, VOIDmode, n); ! 419: output_asm_insn (AS2 (add%L0,%0,%1), xops); ! 420: } ! 421: } ! 422: ! 423: /* Output assembler code to perform a doubleword move insn ! 424: with operands OPERANDS. */ ! 425: ! 426: char * ! 427: output_move_double (operands) ! 428: rtx *operands; ! 429: { ! 430: enum {REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; ! 431: rtx latehalf[2]; ! 432: rtx addreg0 = 0, addreg1 = 0; ! 433: ! 434: /* First classify both operands. */ ! 435: ! 436: if (REG_P (operands[0])) ! 437: optype0 = REGOP; ! 438: else if (offsettable_memref_p (operands[0])) ! 439: optype0 = OFFSOP; ! 440: else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC) ! 441: optype0 = POPOP; ! 442: else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) ! 443: optype0 = PUSHOP; ! 444: else if (GET_CODE (operands[0]) == MEM) ! 445: optype0 = MEMOP; ! 446: else ! 447: optype0 = RNDOP; ! 448: ! 449: if (REG_P (operands[1])) ! 450: optype1 = REGOP; ! 451: else if (CONSTANT_P (operands[1]) ! 452: || GET_CODE (operands[1]) == CONST_DOUBLE) ! 453: optype1 = CNSTOP; ! 454: else if (offsettable_memref_p (operands[1])) ! 455: optype1 = OFFSOP; ! 456: else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC) ! 457: optype1 = POPOP; ! 458: else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) ! 459: optype1 = PUSHOP; ! 460: else if (GET_CODE (operands[1]) == MEM) ! 461: optype1 = MEMOP; ! 462: else ! 463: optype1 = RNDOP; ! 464: ! 465: /* Check for the cases that the operand constraints are not ! 466: supposed to allow to happen. Abort if we get one, ! 467: because generating code for these cases is painful. */ ! 468: ! 469: if (optype0 == RNDOP || optype1 == RNDOP) ! 470: abort (); ! 471: ! 472: /* If one operand is decrementing and one is incrementing ! 473: decrement the former register explicitly ! 474: and change that operand into ordinary indexing. */ ! 475: ! 476: if (optype0 == PUSHOP && optype1 == POPOP) ! 477: { ! 478: operands[0] = XEXP (XEXP (operands[0], 0), 0); ! 479: asm_add (-8, operands[0]); ! 480: operands[0] = gen_rtx (MEM, DImode, operands[0]); ! 481: optype0 = OFFSOP; ! 482: } ! 483: if (optype0 == POPOP && optype1 == PUSHOP) ! 484: { ! 485: operands[1] = XEXP (XEXP (operands[1], 0), 0); ! 486: asm_add (-8, operands[1]); ! 487: operands[1] = gen_rtx (MEM, DImode, operands[1]); ! 488: optype1 = OFFSOP; ! 489: } ! 490: ! 491: /* If an operand is an unoffsettable memory ref, find a register ! 492: we can increment temporarily to make it refer to the second word. */ ! 493: ! 494: if (optype0 == MEMOP) ! 495: addreg0 = find_addr_reg (XEXP (operands[0], 0)); ! 496: ! 497: if (optype1 == MEMOP) ! 498: addreg1 = find_addr_reg (XEXP (operands[1], 0)); ! 499: ! 500: /* Ok, we can do one word at a time. ! 501: Normally we do the low-numbered word first, ! 502: but if either operand is autodecrementing then we ! 503: do the high-numbered word first. ! 504: ! 505: In either case, set up in LATEHALF the operands to use ! 506: for the high-numbered word and in some cases alter the ! 507: operands in OPERANDS to be suitable for the low-numbered word. */ ! 508: ! 509: if (optype0 == REGOP) ! 510: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); ! 511: else if (optype0 == OFFSOP) ! 512: latehalf[0] = adj_offsettable_operand (operands[0], 4); ! 513: else ! 514: latehalf[0] = operands[0]; ! 515: ! 516: if (optype1 == REGOP) ! 517: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); ! 518: else if (optype1 == OFFSOP) ! 519: latehalf[1] = adj_offsettable_operand (operands[1], 4); ! 520: else if (optype1 == CNSTOP) ! 521: { ! 522: if (CONSTANT_P (operands[1])) ! 523: latehalf[1] = const0_rtx; ! 524: else if (GET_CODE (operands[1]) == CONST_DOUBLE) ! 525: { ! 526: latehalf[1] = gen_rtx (CONST_INT, VOIDmode, ! 527: CONST_DOUBLE_HIGH (operands[1])); ! 528: operands[1] = gen_rtx (CONST_INT, VOIDmode, ! 529: CONST_DOUBLE_LOW (operands[1])); ! 530: } ! 531: } ! 532: else ! 533: latehalf[1] = operands[1]; ! 534: ! 535: /* If insn is effectively movd N (sp),-(sp) then we will do the ! 536: high word first. We should use the adjusted operand 1 (which is N+4 (sp)) ! 537: for the low word as well, to compensate for the first decrement of sp. */ ! 538: if (optype0 == PUSHOP ! 539: && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM ! 540: && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1])) ! 541: operands[1] = latehalf[1]; ! 542: ! 543: /* If one or both operands autodecrementing, ! 544: do the two words, high-numbered first. */ ! 545: ! 546: /* Likewise, the first move would clobber the source of the second one, ! 547: do them in the other order. This happens only for registers; ! 548: such overlap can't happen in memory unless the user explicitly ! 549: sets it up, and that is an undefined circumstance. */ ! 550: ! 551: if (optype0 == PUSHOP || optype1 == PUSHOP ! 552: || (optype0 == REGOP && optype1 == REGOP ! 553: && REGNO (operands[0]) == REGNO (latehalf[1]))) ! 554: { ! 555: /* Make any unoffsettable addresses point at high-numbered word. */ ! 556: if (addreg0) ! 557: asm_add (4, addreg0); ! 558: if (addreg1) ! 559: asm_add (4, addreg1); ! 560: ! 561: /* Do that word. */ ! 562: output_asm_insn (singlemove_string (latehalf), latehalf); ! 563: ! 564: /* Undo the adds we just did. */ ! 565: if (addreg0) ! 566: asm_add (-4, addreg0); ! 567: if (addreg1) ! 568: asm_add (-4, addreg1); ! 569: ! 570: /* Do low-numbered word. */ ! 571: return singlemove_string (operands); ! 572: } ! 573: ! 574: /* Normal case: do the two words, low-numbered first. */ ! 575: ! 576: output_asm_insn (singlemove_string (operands), operands); ! 577: ! 578: /* Make any unoffsettable addresses point at high-numbered word. */ ! 579: if (addreg0) ! 580: asm_add (4, addreg0); ! 581: if (addreg1) ! 582: asm_add (4, addreg1); ! 583: ! 584: /* Do that word. */ ! 585: output_asm_insn (singlemove_string (latehalf), latehalf); ! 586: ! 587: /* Undo the adds we just did. */ ! 588: if (addreg0) ! 589: asm_add (-4, addreg0); ! 590: if (addreg1) ! 591: asm_add (-4, addreg1); ! 592: ! 593: return ""; ! 594: } ! 595: ! 596: int ! 597: standard_80387_constant_p (x) ! 598: rtx x; ! 599: { ! 600: union { double d; int i[2];} u; ! 601: register double d; ! 602: u.i[0] = XINT (x, 0); ! 603: u.i[1] = XINT (x, 1); ! 604: d = u.d; ! 605: ! 606: if (d == 0) ! 607: return 1; ! 608: if (d == 1) ! 609: return 2; ! 610: /* Note that on the 80387, other constants, such as pi, ! 611: are much slower to load as standard constants ! 612: than to load from doubles in memory! */ ! 613: ! 614: return 0; ! 615: } ! 616: ! 617: static char * ! 618: output_move_const_double (operands) ! 619: rtx *operands; ! 620: { ! 621: if (FP_REG_P (operands[0])) ! 622: { ! 623: int conval = standard_80387_constant_p (operands[1]); ! 624: ! 625: /* fp_pop_level++; */ ! 626: if (conval == 1) ! 627: return "fldz"; ! 628: if (conval == 2) ! 629: return "fld1"; ! 630: /* fp_pop_level--; */ ! 631: } ! 632: ! 633: output_move_double (operands); ! 634: } ! 635: ! 636: ! 637: static char * ! 638: output_move_const_single (operands) ! 639: rtx *operands; ! 640: { ! 641: if (FP_REG_P (operands[0])) ! 642: { ! 643: int conval = standard_80387_constant_p (operands[1]); ! 644: ! 645: /* fp_pop_level++; */ ! 646: if (conval == 1) ! 647: return "fldz"; ! 648: if (conval == 2) ! 649: return "fld1"; ! 650: /* fp_pop_level--; */ ! 651: } ! 652: if (GET_CODE (operands[1]) == CONST_DOUBLE) ! 653: { ! 654: union { int i[2]; double d;} u1; ! 655: union { int i; float f;} u2; ! 656: u1.i[0] = CONST_DOUBLE_LOW (operands[1]); ! 657: u1.i[1] = CONST_DOUBLE_HIGH (operands[1]); ! 658: u2.f = u1.d; ! 659: operands[1] = gen_rtx (CONST_INT, VOIDmode, u2.i); ! 660: } ! 661: return singlemove_string (operands); ! 662: } ! 663: ! 664: /* Output an insn to move an SF value from FROM to TO. ! 665: The kinds of operands are not restricted ! 666: except that they may not both be in memory. */ ! 667: ! 668: void ! 669: output_movsf (to, from) ! 670: rtx from, to; ! 671: { ! 672: rtx xops[2]; ! 673: xops[0] = to; ! 674: xops[1] = from; ! 675: if (FP_REG_P (from) || FP_REG_P (to)) ! 676: { ! 677: from = xops[1]; ! 678: } ! 679: ! 680: if (FP_REG_P (from)) ! 681: { ! 682: #if 0 ! 683: { ! 684: if (REGNO (from) != REGNO (to)) ! 685: { ! 686: output_asm_insn ("fld%S0 %1 \n\tfstp%S0 %0", xops); ! 687: } ! 688: } ! 689: else ! 690: #endif ! 691: ! 692: if (! FP_REG_P (to)) ! 693: fp_pop_sf (to); ! 694: } ! 695: else if (FP_REG_P (to)) ! 696: fp_push_sf (from); ! 697: else ! 698: output_asm_insn (singlemove_string (xops), xops); ! 699: } ! 700: ! 701: /* Output an insn to move a DF value from FROM to TO. ! 702: The kinds of operands are not restricted ! 703: except that they may not both be in memory. */ ! 704: ! 705: void ! 706: output_movdf (to, from) ! 707: rtx from, to; ! 708: { ! 709: rtx xops[2]; ! 710: xops[0] = to; ! 711: xops[1] = from; ! 712: if (FP_REG_P (from) || FP_REG_P (to)) ! 713: { ! 714: from = xops[1]; ! 715: to = xops[0]; ! 716: } ! 717: if (FP_REG_P (from)) ! 718: { ! 719: #if 0 ! 720: { ! 721: if (REGNO (from) != REGNO (to)) ! 722: abort (); ! 723: /* output_asm_insn ("fld%Q0 %1 \n\t fstp%Q0 %0", xops);*/ ! 724: } ! 725: else ! 726: { ! 727: #endif ! 728: if (! FP_REG_P (to)) ! 729: fp_pop_df (to); ! 730: } ! 731: else if (FP_REG_P (to)) ! 732: fp_push_df (from); ! 733: else ! 734: output_asm_insn (output_move_double (xops), xops); ! 735: } ! 736: ! 737: /* does move of FROM to TO where the mode is the minimum of the ! 738: two */ ! 739: ! 740: static void ! 741: output_movf (to, from) ! 742: rtx to, from; ! 743: { ! 744: if (GET_MODE (from) == SFmode || GET_MODE (to) == SFmode) ! 745: output_movsf (to, from); ! 746: else ! 747: output_movdf (to, from); ! 748: } ! 749: ! 750: /* Return the best assembler insn template ! 751: for moving operands[1] into operands[0] as a fullword. */ ! 752: ! 753: void ! 754: function_prologue (file, size) ! 755: FILE *file; ! 756: int size; ! 757: { ! 758: register int regno; ! 759: int nregs, limit; ! 760: rtx xops[4]; ! 761: extern int frame_pointer_needed; ! 762: ! 763: /* fp_pop_level = 0; */ ! 764: xops[0] = stack_pointer_rtx; ! 765: xops[1] = frame_pointer_rtx; ! 766: xops[2] = gen_rtx (CONST_INT, VOIDmode, size); ! 767: if (frame_pointer_needed) ! 768: { ! 769: output_asm_insn ("push%L0 %1", xops); ! 770: output_asm_insn (AS2 (mov%L0,%0,%1), xops); ! 771: if (size) ! 772: output_asm_insn (AS2 (sub%L0,%2,%0), xops); ! 773: } ! 774: ! 775: /* Note If use enter it is NOT reversed args. ! 776: This one is not reversed from intel!! ! 777: I think enter is slower. Also sdb doesn't like it. ! 778: But if you want it the code is: ! 779: { ! 780: xops[3] = const0_rtx; ! 781: output_asm_insn ("enter %2,%3", xops); ! 782: } ! 783: */ ! 784: nregs = 0; ! 785: limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM); ! 786: for (regno = limit - 1; regno >= 0; regno--) ! 787: if (regs_ever_live[regno] && ! call_used_regs[regno]) ! 788: { ! 789: fprintf (file, "\tpush%s %se%s\n", L_SIZE, RP, hi_reg_name[regno]); ! 790: } ! 791: } ! 792: ! 793: void ! 794: function_epilogue (file, size) ! 795: FILE *file; ! 796: int size; ! 797: { ! 798: register int regno; ! 799: register int nregs, limit; ! 800: int assure_sp_pos; ! 801: extern int frame_pointer_needed; ! 802: extern int current_function_pops_args; ! 803: extern int current_function_args_size; ! 804: limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM); ! 805: nregs = 0; ! 806: ! 807: ! 808: for (regno = (limit -1); regno >= 0; regno--) ! 809: if (regs_ever_live[regno] && ! call_used_regs[regno]) ! 810: nregs++; ! 811: ! 812: /* sp is often unreliable so we must go off the frame pointer, ! 813: */ ! 814: ! 815: if (nregs && frame_pointer_needed) ! 816: { ! 817: rtx xops[2]; ! 818: xops[0] = adj_offsettable_operand (AT_BP (Pmode), ! 819: -size -(nregs*(UNITS_PER_WORD))); ! 820: xops[1] = stack_pointer_rtx; ! 821: output_asm_insn (AS2 (lea%L0,%0,%1), xops); ! 822: } ! 823: for (regno = 0; regno < limit; regno++) ! 824: { ! 825: if (regs_ever_live[regno] && ! call_used_regs[regno]) ! 826: { ! 827: fprintf (file, "\tpop%s ", L_SIZE); ! 828: fprintf (file, "%se%s\n", RP, hi_reg_name[regno]); ! 829: } ! 830: } ! 831: ! 832: if (frame_pointer_needed) ! 833: fprintf (file, "\tleave\n"); ! 834: if (current_function_pops_args && current_function_args_size) ! 835: fprintf (file, "\tret %s%d\n", IP, ! 836: (current_function_args_size ! 837: + (current_function_returns_struct ? 4 : 0))); ! 838: else if (current_function_returns_struct) ! 839: fprintf (file, "\tret %s4\n", IP); ! 840: else ! 841: fprintf (file, "\tret\n"); ! 842: } ! 843: ! 844: int ! 845: hard_regno_mode_ok (regno, mode) ! 846: int regno; ! 847: enum machine_mode mode; ! 848: { ! 849: return ! 850: (regno < 2 ? 1 ! 851: /* Used to reject floating modes here */ ! 852: : regno < 4 ? 1 ! 853: : regno >= 8 ? mode == DFmode || mode == SFmode ! 854: : mode != QImode); ! 855: } ! 856: ! 857: /* Print the name of a register based on its machine mode and number. ! 858: If CODE is 'w', pretend the mode is HImode. */ ! 859: ! 860: #define PRINT_REG(X, CODE, FILE) \ ! 861: do { fprintf (FILE, "%s", RP); \ ! 862: switch ((CODE == 'w' ? 2 : GET_MODE_SIZE (GET_MODE (X)))) \ ! 863: { \ ! 864: case 4: \ ! 865: case 8: \ ! 866: if (!FP_REG_P (X)) fputs ("e", FILE); \ ! 867: case 2: \ ! 868: fputs (hi_reg_name[REGNO (X)], FILE); \ ! 869: break; \ ! 870: case 1: \ ! 871: fputs (qi_reg_name[REGNO (X)], FILE); \ ! 872: } \ ! 873: } while (0) ! 874: ! 875: /* Meaning of CODE: ! 876: f -- float insn (print a CONST_DOUBLE as a float rather than in hex). ! 877: L,W,B,Q,S -- print the opcode suffix for specified size of operand. ! 878: R -- print the prefix for register names. ! 879: z -- print the opcode suffix for the size of the current operand. ! 880: * -- print a star (in certain assembler syntax) ! 881: w -- print the operand as if it's a "word" (HImode) even if it isn't. ! 882: c -- don't print special prefixes before constant operands. ! 883: */ ! 884: ! 885: void ! 886: print_operand (file, x, code) ! 887: FILE *file; ! 888: rtx x; ! 889: int code; ! 890: { ! 891: if (code) ! 892: { ! 893: switch (code) ! 894: { ! 895: case '*': ! 896: if (USE_STAR) ! 897: putc ('*', file); ! 898: return; ! 899: ! 900: case 'L': ! 901: PUT_OP_SIZE (code, 'l', file); ! 902: return; ! 903: ! 904: case 'W': ! 905: PUT_OP_SIZE (code, 'w', file); ! 906: return; ! 907: ! 908: case 'B': ! 909: PUT_OP_SIZE (code, 'b', file); ! 910: return; ! 911: ! 912: case 'Q': ! 913: PUT_OP_SIZE (code, 'l', file); ! 914: return; ! 915: ! 916: case 'S': ! 917: PUT_OP_SIZE (code, 's', file); ! 918: return; ! 919: ! 920: case 'R': ! 921: fprintf (file, "%s", RP); ! 922: return; ! 923: ! 924: case 'z': ! 925: /* this is the size of op from size of operand */ ! 926: switch (GET_MODE_SIZE (GET_MODE (x))) ! 927: { ! 928: case 2: ! 929: PUT_OP_SIZE ('W', 'w', file); ! 930: return; ! 931: case 4: ! 932: if (GET_MODE (x) == SFmode) ! 933: { ! 934: PUT_OP_SIZE ('S', 's', file); ! 935: return; ! 936: } ! 937: else ! 938: PUT_OP_SIZE ('L', 'l', file); ! 939: return; ! 940: case 8: ! 941: if (!FP_REG_P (x)) PUT_OP_SIZE ('Q', 'l', file); ! 942: return; ! 943: case 1: ! 944: PUT_OP_SIZE ('B', 'b', file); ! 945: return; ! 946: } ! 947: } ! 948: } ! 949: if (GET_CODE (x) == REG) ! 950: { ! 951: PRINT_REG (x, code, file); ! 952: } ! 953: else if (GET_CODE (x) == MEM) ! 954: { ! 955: PRINT_PTR (x, file); ! 956: if (CONSTANT_ADDRESS_P (XEXP (x, 0))) ! 957: output_addr_const (file, XEXP (x, 0)); ! 958: else ! 959: output_address (XEXP (x, 0)); ! 960: } ! 961: else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == SFmode) ! 962: { ! 963: union { double d; int i[2]; } u; ! 964: union { float f; int i; } u1; ! 965: u.i[0] = CONST_DOUBLE_LOW (x); ! 966: u.i[1] = CONST_DOUBLE_HIGH (x); ! 967: u1.f = u.d; ! 968: if (code == 'f') ! 969: fprintf (file, "%.22e", u1.f); ! 970: else ! 971: { ! 972: PRINT_IMMED_PREFIX (file); ! 973: fprintf (file, "0x%x", u1.i); ! 974: } ! 975: } ! 976: else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode) ! 977: { ! 978: union { double d; int i[2]; } u; ! 979: u.i[0] = CONST_DOUBLE_LOW (x); ! 980: u.i[1] = CONST_DOUBLE_HIGH (x); ! 981: fprintf (file, "%.22e", u.d); ! 982: } ! 983: else ! 984: { ! 985: if (code != 'c') ! 986: { ! 987: if (GET_CODE (x) == CONST_INT) ! 988: PRINT_IMMED_PREFIX (file); ! 989: else if (GET_CODE (x) == CONST || GET_CODE (x) == SYMBOL_REF) ! 990: PRINT_OFFSET_PREFIX (file); ! 991: } ! 992: output_addr_const (file, x); ! 993: } ! 994: } ! 995: ! 996: /* Print a memory operand whose address is ADDR. */ ! 997: ! 998: void ! 999: print_operand_address (file, addr) ! 1000: FILE *file; ! 1001: register rtx addr; ! 1002: { ! 1003: register rtx reg1, reg2, breg, ireg; ! 1004: rtx offset; ! 1005: ! 1006: switch (GET_CODE (addr)) ! 1007: { ! 1008: case REG: ! 1009: ADDR_BEG (file); ! 1010: fprintf (file, "%se", RP); ! 1011: fputs (hi_reg_name[REGNO (addr)], file); ! 1012: ADDR_END (file); ! 1013: break; ! 1014: ! 1015: case PLUS: ! 1016: reg1 = 0; ! 1017: reg2 = 0; ! 1018: ireg = 0; ! 1019: breg = 0; ! 1020: offset = 0; ! 1021: if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) ! 1022: { ! 1023: offset = XEXP (addr, 0); ! 1024: addr = XEXP (addr, 1); ! 1025: } ! 1026: else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) ! 1027: { ! 1028: offset = XEXP (addr, 1); ! 1029: addr = XEXP (addr, 0); ! 1030: } ! 1031: if (GET_CODE (addr) != PLUS) ; ! 1032: else if (GET_CODE (XEXP (addr, 0)) == MULT) ! 1033: { ! 1034: reg1 = XEXP (addr, 0); ! 1035: addr = XEXP (addr, 1); ! 1036: } ! 1037: else if (GET_CODE (XEXP (addr, 1)) == MULT) ! 1038: { ! 1039: reg1 = XEXP (addr, 1); ! 1040: addr = XEXP (addr, 0); ! 1041: } ! 1042: else if (GET_CODE (XEXP (addr, 0)) == REG) ! 1043: { ! 1044: reg1 = XEXP (addr, 0); ! 1045: addr = XEXP (addr, 1); ! 1046: } ! 1047: else if (GET_CODE (XEXP (addr, 1)) == REG) ! 1048: { ! 1049: reg1 = XEXP (addr, 1); ! 1050: addr = XEXP (addr, 0); ! 1051: } ! 1052: if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT) ! 1053: { ! 1054: if (reg1 == 0) reg1 = addr; ! 1055: else reg2 = addr; ! 1056: addr = 0; ! 1057: } ! 1058: if (offset != 0) ! 1059: { ! 1060: if (addr != 0) abort (); ! 1061: addr = offset; ! 1062: } ! 1063: if ((reg1 && GET_CODE (reg1) == MULT) ! 1064: || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2)))) ! 1065: { ! 1066: breg = reg2; ! 1067: ireg = reg1; ! 1068: } ! 1069: else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1))) ! 1070: { ! 1071: breg = reg1; ! 1072: ireg = reg2; ! 1073: } ! 1074: ! 1075: if (ireg != 0 || breg != 0) ! 1076: { ! 1077: int scale = 1; ! 1078: ! 1079: if (addr != 0) ! 1080: { ! 1081: if (GET_CODE (addr) == LABEL_REF) ! 1082: output_asm_label (addr); ! 1083: else ! 1084: output_addr_const (file, addr); ! 1085: } ! 1086: ! 1087: if (ireg != 0 && GET_CODE (ireg) == MULT) ! 1088: { ! 1089: scale = INTVAL (XEXP (ireg, 1)); ! 1090: ireg = XEXP (ireg, 0); ! 1091: } ! 1092: /* output breg+ireg*scale */ ! 1093: PRINT_B_I_S (breg, ireg, scale, file); ! 1094: break; ! 1095: } ! 1096: ! 1097: default: ! 1098: if (GET_CODE (addr) == CONST_INT ! 1099: && INTVAL (addr) < 0x8000 ! 1100: && INTVAL (addr) >= -0x8000) ! 1101: fprintf (file, "%d", INTVAL (addr)); ! 1102: else ! 1103: output_addr_const (file, addr); ! 1104: } ! 1105: } ! 1106: ! 1107: /* Set the cc_status for the results of an insn whose pattern is EXP. ! 1108: On the 80386, we assume that only test and compare insns, as well ! 1109: as SI, HI, & DI mode ADD, SUB, NEG, AND, IOR, XOR, ASHIFT, LSHIFT, ! 1110: ASHIFTRT, and LSHIFTRT instructions set the condition codes usefully. ! 1111: Also, we assume that jumps and moves don't affect the condition codes. ! 1112: All else, clobbers the condition codes, by assumption. ! 1113: ! 1114: We assume that ALL add, minus, etc. instructions effect the condition ! 1115: codes. This MUST be consistent with i386.md. */ ! 1116: ! 1117: notice_update_cc (exp) ! 1118: rtx exp; ! 1119: { ! 1120: if (GET_CODE (exp) == SET) ! 1121: { ! 1122: /* Jumps do not alter the cc's. */ ! 1123: if (SET_DEST (exp) == pc_rtx) ! 1124: return; ! 1125: /* Moving register or memory into a register: ! 1126: it doesn't alter the cc's, but it might invalidate ! 1127: the RTX's which we remember the cc's came from. ! 1128: (Note that moving a constant 0 or 1 MAY set the cc's). */ ! 1129: if (REG_P (SET_DEST (exp)) ! 1130: && (REG_P (SET_SRC (exp)) || GET_CODE (SET_SRC (exp)) == MEM)) ! 1131: { ! 1132: if (cc_status.value1 ! 1133: && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1)) ! 1134: cc_status.value1 = 0; ! 1135: if (cc_status.value2 ! 1136: && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2)) ! 1137: cc_status.value2 = 0; ! 1138: return; ! 1139: } ! 1140: /* Moving register into memory doesn't alter the cc's. ! 1141: It may invalidate the RTX's which we remember the cc's came from. */ ! 1142: if (GET_CODE (SET_DEST (exp)) == MEM && REG_P (SET_SRC (exp))) ! 1143: { ! 1144: if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM) ! 1145: cc_status.value1 = 0; ! 1146: if (cc_status.value2 && GET_CODE (cc_status.value2) == MEM) ! 1147: cc_status.value2 = 0; ! 1148: return; ! 1149: } ! 1150: /* Function calls clobber the cc's. */ ! 1151: else if (GET_CODE (SET_SRC (exp)) == CALL) ! 1152: { ! 1153: CC_STATUS_INIT; ! 1154: return; ! 1155: } ! 1156: /* Tests and compares set the cc's in predictable ways. */ ! 1157: else if (SET_DEST (exp) == cc0_rtx) ! 1158: { ! 1159: CC_STATUS_INIT; ! 1160: cc_status.value1 = SET_SRC (exp); ! 1161: return; ! 1162: } ! 1163: /* Certain instructions effect the condition codes. */ ! 1164: else if (GET_MODE (SET_SRC (exp)) == SImode ! 1165: || GET_MODE (SET_SRC (exp)) == HImode ! 1166: || GET_MODE (SET_SRC (exp)) == QImode) ! 1167: switch (GET_CODE (SET_SRC (exp))) ! 1168: { ! 1169: case ASHIFTRT: case LSHIFTRT: ! 1170: case ASHIFT: case LSHIFT: ! 1171: /* Shifts on the 386 don't set the condition codes if the ! 1172: shift count is zero. */ ! 1173: if (GET_CODE (XEXP (SET_SRC (exp), 1)) != CONST_INT) ! 1174: { ! 1175: CC_STATUS_INIT; ! 1176: break; ! 1177: } ! 1178: /* We assume that the CONST_INT is non-zero (this rtx would ! 1179: have been deleted if it were zero. */ ! 1180: ! 1181: case PLUS: case MINUS: case NEG: ! 1182: case AND: case IOR: case XOR: ! 1183: cc_status.flags = CC_NO_OVERFLOW; ! 1184: cc_status.value1 = SET_SRC (exp); ! 1185: cc_status.value2 = SET_DEST (exp); ! 1186: break; ! 1187: ! 1188: default: ! 1189: CC_STATUS_INIT; ! 1190: } ! 1191: else ! 1192: { ! 1193: CC_STATUS_INIT; ! 1194: } ! 1195: } ! 1196: else if (GET_CODE (exp) == PARALLEL ! 1197: && GET_CODE (XVECEXP (exp, 0, 0)) == SET) ! 1198: { ! 1199: if (SET_DEST (XVECEXP (exp, 0, 0)) == pc_rtx) ! 1200: return; ! 1201: if (SET_DEST (XVECEXP (exp, 0, 0)) == cc0_rtx) ! 1202: { ! 1203: CC_STATUS_INIT; ! 1204: cc_status.value1 = SET_SRC (XVECEXP (exp, 0, 0)); ! 1205: return; ! 1206: } ! 1207: CC_STATUS_INIT; ! 1208: } ! 1209: else ! 1210: { ! 1211: CC_STATUS_INIT; ! 1212: } ! 1213: } ! 1214: ! 1215: /* Nonzero if the top of the fpu stack dies in this insn. */ ! 1216: ! 1217: int ! 1218: top_dead_p (insn) ! 1219: rtx insn; ! 1220: { ! 1221: extern int optimize; ! 1222: if (optimize) ! 1223: return (find_regno_note (insn, REG_DEAD, FIRST_FLOAT_REG) ! 1224: || find_regno_note (insn, REG_DEAD, FIRST_FLOAT_REG + 1)); ! 1225: ! 1226: if (GET_CODE (insn) == CALL_INSN) ! 1227: return call_top_dead_p (insn); ! 1228: ! 1229: return fp_top_dead_p1 (insn); ! 1230: } ! 1231: ! 1232: /* Following is used after a call_value insn ! 1233: if obey_regdecls there will not be the REG_DEAD notes ! 1234: to go by (there won't be any cross jumping to worry about ! 1235: either), and we depend on seeing if the FP_TOP is used ! 1236: in the next two insn's. Otherwise we depend on the ! 1237: REG_DEAD notes. ! 1238: */ ! 1239: ! 1240: static int ! 1241: call_top_dead_p (insn) ! 1242: rtx insn; ! 1243: { ! 1244: int i; ! 1245: for (i = 0; i < 3; i++) ! 1246: { ! 1247: insn = NEXT_INSN (insn); ! 1248: if (insn == 0) ! 1249: return 1; ! 1250: if (GET_CODE (insn) == NOTE || GET_CODE (insn) == CODE_LABEL) ! 1251: continue; ! 1252: if (GET_CODE (insn) == BARRIER) ! 1253: abort (); ! 1254: if (GET_CODE (PATTERN (insn)) == SET ! 1255: && SET_DEST (PATTERN (insn)) != stack_pointer_rtx) ! 1256: return (!(mentions_fp_top (SET_SRC (PATTERN (insn))))); ! 1257: if (GET_CODE (PATTERN (insn)) == CALL) ! 1258: return 1; ! 1259: if (GET_CODE (PATTERN (insn)) == USE) ! 1260: return (! FP_REG_P (XEXP (PATTERN (insn), 0))); ! 1261: } ! 1262: return 1; ! 1263: } ! 1264: ! 1265: /* Return 1 if current val of fpu top-of-stack appears unused ! 1266: in rest of this basic block. */ ! 1267: ! 1268: static int ! 1269: fp_top_dead_p1 (insn) ! 1270: rtx insn; ! 1271: { ! 1272: for (insn = NEXT_INSN (insn); insn; insn = NEXT_INSN (insn)) ! 1273: { ! 1274: switch (GET_CODE (insn)) ! 1275: { ! 1276: case CALL_INSN: ! 1277: /* Function calls clobber this value, so it's dead. */ ! 1278: case JUMP_INSN: ! 1279: case CODE_LABEL: ! 1280: return 1; ! 1281: ! 1282: case INSN: ! 1283: if (GET_CODE (PATTERN (insn)) == SET) ! 1284: { ! 1285: if ((mentions_fp_top (SET_SRC (PATTERN (insn))))) ! 1286: return 0; ! 1287: else if (FP_REG_P (SET_DEST (PATTERN (insn)))) ! 1288: return 1; ! 1289: } ! 1290: else if (mentions_fp_top (PATTERN (insn))) ! 1291: return 0; ! 1292: break; ! 1293: } ! 1294: } ! 1295: return 1; ! 1296: } ! 1297: ! 1298: /* Return 1 if X involves an FPU register. */ ! 1299: ! 1300: static int ! 1301: mentions_fp_top (x) ! 1302: rtx x; ! 1303: { ! 1304: register RTX_CODE code; ! 1305: ! 1306: code = GET_CODE (x); ! 1307: switch (code) ! 1308: { ! 1309: case LABEL_REF: ! 1310: case SYMBOL_REF: ! 1311: case CONST_INT: ! 1312: case CONST: ! 1313: case CC0: ! 1314: case PC: ! 1315: case CLOBBER: ! 1316: case MEM: ! 1317: return 0; ! 1318: ! 1319: case REG: ! 1320: return FP_REGNO_P (REGNO (x)); ! 1321: } ! 1322: ! 1323: /* Recursively scan the operands of this expression. */ ! 1324: { ! 1325: register char *fmt = GET_RTX_FORMAT (code); ! 1326: register int i; ! 1327: ! 1328: for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) ! 1329: { ! 1330: if (fmt[i] == 'e') ! 1331: { ! 1332: if (mentions_fp_top (XEXP (x, i))) ! 1333: return 1; ! 1334: } ! 1335: if (fmt[i] == 'E') ! 1336: { ! 1337: register int j; ! 1338: for (j = 0; j < XVECLEN (x, i); j++) ! 1339: if (mentions_fp_top (XVECEXP (x, i, j))) ! 1340: return 1; ! 1341: } ! 1342: } ! 1343: } ! 1344: return 0; ! 1345: } ! 1346: ! 1347: /* Some asm-dependent functions. */ ! 1348: ! 1349: #ifdef MASM ! 1350: #include "masm386.c" ! 1351: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.