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