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