|
|
1.1.1.3 root 1: /* Subroutines for insn-output.c for Intel X86. 1.1.1.4 ! root 2: Copyright (C) 1988, 1992, 1994, 1995 Free Software Foundation, Inc. 1.1 root 3: 4: This file is part of GNU CC. 5: 6: GNU CC is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU CC is distributed in the hope that it will be useful, 12: but WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14: GNU General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU CC; see the file COPYING. If not, write to 1.1.1.4 ! root 18: the Free Software Foundation, 59 Temple Place - Suite 330, ! 19: Boston, MA 02111-1307, USA. */ 1.1 root 20: 21: #include <stdio.h> 22: #include <setjmp.h> 1.1.1.4 ! root 23: #include <ctype.h> 1.1 root 24: #include "config.h" 25: #include "rtl.h" 26: #include "regs.h" 27: #include "hard-reg-set.h" 28: #include "real.h" 29: #include "insn-config.h" 30: #include "conditions.h" 31: #include "insn-flags.h" 32: #include "output.h" 33: #include "insn-attr.h" 34: #include "tree.h" 35: #include "flags.h" 1.1.1.2 root 36: #include "function.h" 1.1 root 37: 38: #ifdef EXTRA_CONSTRAINT 39: /* If EXTRA_CONSTRAINT is defined, then the 'S' 40: constraint in REG_CLASS_FROM_LETTER will no longer work, and various 41: asm statements that need 'S' for class SIREG will break. */ 42: error EXTRA_CONSTRAINT conflicts with S constraint letter 43: /* The previous line used to be #error, but some compilers barf 44: even if the conditional was untrue. */ 45: #endif 46: 47: #define AT_BP(mode) (gen_rtx (MEM, (mode), frame_pointer_rtx)) 48: 49: extern FILE *asm_out_file; 50: extern char *strcat (); 51: 52: char *singlemove_string (); 53: char *output_move_const_single (); 54: char *output_fp_cc0_set (); 55: 56: char *hi_reg_name[] = HI_REGISTER_NAMES; 57: char *qi_reg_name[] = QI_REGISTER_NAMES; 58: char *qi_high_reg_name[] = QI_HIGH_REGISTER_NAMES; 59: 60: /* Array of the smallest class containing reg number REGNO, indexed by 61: REGNO. Used by REGNO_REG_CLASS in i386.h. */ 62: 63: enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] = 64: { 65: /* ax, dx, cx, bx */ 66: AREG, DREG, CREG, BREG, 67: /* si, di, bp, sp */ 68: SIREG, DIREG, INDEX_REGS, GENERAL_REGS, 69: /* FP registers */ 70: FP_TOP_REG, FP_SECOND_REG, FLOAT_REGS, FLOAT_REGS, 71: FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, 72: /* arg pointer */ 73: INDEX_REGS 74: }; 75: 76: /* Test and compare insns in i386.md store the information needed to 77: generate branch and scc insns here. */ 78: 1.1.1.3 root 79: struct rtx_def *i386_compare_op0 = NULL_RTX; 80: struct rtx_def *i386_compare_op1 = NULL_RTX; 1.1 root 81: struct rtx_def *(*i386_compare_gen)(), *(*i386_compare_gen_eq)(); 1.1.1.3 root 82: 83: /* Register allocation order */ 1.1.1.4 ! root 84: char *i386_reg_alloc_order; 1.1.1.3 root 85: static char regs_allocated[FIRST_PSEUDO_REGISTER]; 86: 1.1.1.4 ! root 87: /* # of registers to use to pass arguments. */ ! 88: char *i386_regparm_string; /* # registers to use to pass args */ ! 89: int i386_regparm; /* i386_regparm_string as a number */ ! 90: ! 91: /* Alignment to use for loops and jumps */ ! 92: char *i386_align_loops_string; /* power of two alignment for loops */ ! 93: char *i386_align_jumps_string; /* power of two alignment for non-loop jumps */ ! 94: char *i386_align_funcs_string; /* power of two alignment for functions */ ! 95: ! 96: int i386_align_loops; /* power of two alignment for loops */ ! 97: int i386_align_jumps; /* power of two alignment for non-loop jumps */ ! 98: int i386_align_funcs; /* power of two alignment for functions */ ! 99: 1.1.1.3 root 100: 101: /* Sometimes certain combinations of command options do not make 102: sense on a particular target machine. You can define a macro 103: `OVERRIDE_OPTIONS' to take account of this. This macro, if 104: defined, is executed once just after all the command options have 105: been parsed. 106: 107: Don't use this macro to turn on various extra optimizations for 108: `-O'. That is what `OPTIMIZATION_OPTIONS' is for. */ 109: 110: void 111: override_options () 112: { 113: int ch, i, regno; 1.1.1.4 ! root 114: char *p; ! 115: int def_align; 1.1.1.3 root 116: 117: #ifdef SUBTARGET_OVERRIDE_OPTIONS 118: SUBTARGET_OVERRIDE_OPTIONS; 119: #endif 120: 121: /* Validate registers in register allocation order */ 122: if (i386_reg_alloc_order) 123: { 124: for (i = 0; (ch = i386_reg_alloc_order[i]) != '\0'; i++) 125: { 126: switch (ch) 127: { 128: case 'a': regno = 0; break; 129: case 'd': regno = 1; break; 130: case 'c': regno = 2; break; 131: case 'b': regno = 3; break; 132: case 'S': regno = 4; break; 133: case 'D': regno = 5; break; 134: case 'B': regno = 6; break; 135: 136: default: fatal ("Register '%c' is unknown", ch); 137: } 138: 139: if (regs_allocated[regno]) 140: fatal ("Register '%c' was already specified in the allocation order", ch); 141: 142: regs_allocated[regno] = 1; 143: } 144: } 1.1.1.4 ! root 145: ! 146: /* Validate -mregparm= value */ ! 147: if (i386_regparm_string) ! 148: { ! 149: i386_regparm = atoi (i386_regparm_string); ! 150: if (i386_regparm < 0 || i386_regparm > REGPARM_MAX) ! 151: fatal ("-mregparm=%d is not between 0 and %d", i386_regparm, REGPARM_MAX); ! 152: } ! 153: ! 154: def_align = (TARGET_386) ? 2 : 4; ! 155: ! 156: /* Validate -malign-loops= value, or provide default */ ! 157: if (i386_align_loops_string) ! 158: { ! 159: i386_align_loops = atoi (i386_align_loops_string); ! 160: if (i386_align_loops < 0 || i386_align_loops > MAX_CODE_ALIGN) ! 161: fatal ("-malign-loops=%d is not between 0 and %d", ! 162: i386_align_loops, MAX_CODE_ALIGN); ! 163: } ! 164: else ! 165: i386_align_loops = 2; ! 166: ! 167: /* Validate -malign-jumps= value, or provide default */ ! 168: if (i386_align_jumps_string) ! 169: { ! 170: i386_align_jumps = atoi (i386_align_jumps_string); ! 171: if (i386_align_jumps < 0 || i386_align_jumps > MAX_CODE_ALIGN) ! 172: fatal ("-malign-jumps=%d is not between 0 and %d", ! 173: i386_align_jumps, MAX_CODE_ALIGN); ! 174: } ! 175: else ! 176: i386_align_jumps = def_align; ! 177: ! 178: /* Validate -malign-functions= value, or provide default */ ! 179: if (i386_align_funcs_string) ! 180: { ! 181: i386_align_funcs = atoi (i386_align_funcs_string); ! 182: if (i386_align_funcs < 0 || i386_align_funcs > MAX_CODE_ALIGN) ! 183: fatal ("-malign-functions=%d is not between 0 and %d", ! 184: i386_align_funcs, MAX_CODE_ALIGN); ! 185: } ! 186: else ! 187: i386_align_funcs = def_align; 1.1.1.3 root 188: } 189: 190: /* A C statement (sans semicolon) to choose the order in which to 191: allocate hard registers for pseudo-registers local to a basic 192: block. 193: 194: Store the desired register order in the array `reg_alloc_order'. 195: Element 0 should be the register to allocate first; element 1, the 196: next register; and so on. 197: 198: The macro body should not assume anything about the contents of 199: `reg_alloc_order' before execution of the macro. 200: 201: On most machines, it is not necessary to define this macro. */ 202: 203: void 204: order_regs_for_local_alloc () 205: { 206: int i, ch, order, regno; 207: 208: /* User specified the register allocation order */ 209: if (i386_reg_alloc_order) 210: { 211: for (i = order = 0; (ch = i386_reg_alloc_order[i]) != '\0'; i++) 212: { 213: switch (ch) 214: { 215: case 'a': regno = 0; break; 216: case 'd': regno = 1; break; 217: case 'c': regno = 2; break; 218: case 'b': regno = 3; break; 219: case 'S': regno = 4; break; 220: case 'D': regno = 5; break; 221: case 'B': regno = 6; break; 222: } 223: 224: reg_alloc_order[order++] = regno; 225: } 226: 227: for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) 228: { 229: if (!regs_allocated[i]) 230: reg_alloc_order[order++] = i; 231: } 232: } 233: 234: /* If users did not specify a register allocation order, favor eax 235: normally except if DImode variables are used, in which case 236: favor edx before eax, which seems to cause less spill register 237: not found messages. */ 238: else 239: { 240: rtx insn; 241: 242: for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) 243: reg_alloc_order[i] = i; 244: 245: if (optimize) 246: { 247: int use_dca = FALSE; 248: 249: for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) 250: { 251: if (GET_CODE (insn) == INSN) 252: { 253: rtx set = NULL_RTX; 254: rtx pattern = PATTERN (insn); 255: 256: if (GET_CODE (pattern) == SET) 257: set = pattern; 258: 259: else if ((GET_CODE (pattern) == PARALLEL 260: || GET_CODE (pattern) == SEQUENCE) 261: && GET_CODE (XVECEXP (pattern, 0, 0)) == SET) 262: set = XVECEXP (pattern, 0, 0); 263: 264: if (set && GET_MODE (SET_SRC (set)) == DImode) 265: { 266: use_dca = TRUE; 267: break; 268: } 269: } 270: } 271: 272: if (use_dca) 273: { 274: reg_alloc_order[0] = 1; /* edx */ 275: reg_alloc_order[1] = 2; /* ecx */ 276: reg_alloc_order[2] = 0; /* eax */ 277: } 278: } 279: } 280: } 281: 1.1 root 282: 1.1.1.4 ! root 283: /* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific ! 284: attribute for DECL. The attributes in ATTRIBUTES have previously been ! 285: assigned to DECL. */ ! 286: ! 287: int ! 288: i386_valid_decl_attribute_p (decl, attributes, identifier, args) ! 289: tree decl; ! 290: tree attributes; ! 291: tree identifier; ! 292: tree args; ! 293: { ! 294: return 0; ! 295: } ! 296: ! 297: /* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific ! 298: attribute for TYPE. The attributes in ATTRIBUTES have previously been ! 299: assigned to TYPE. */ ! 300: ! 301: int ! 302: i386_valid_type_attribute_p (type, attributes, identifier, args) ! 303: tree type; ! 304: tree attributes; ! 305: tree identifier; ! 306: tree args; ! 307: { ! 308: if (TREE_CODE (type) != FUNCTION_TYPE ! 309: && TREE_CODE (type) != FIELD_DECL ! 310: && TREE_CODE (type) != TYPE_DECL) ! 311: return 0; ! 312: ! 313: /* Stdcall attribute says callee is responsible for popping arguments ! 314: if they are not variable. */ ! 315: if (is_attribute_p ("stdcall", identifier)) ! 316: return (args == NULL_TREE); ! 317: ! 318: /* Cdecl attribute says the callee is a normal C declaration */ ! 319: if (is_attribute_p ("cdecl", identifier)) ! 320: return (args == NULL_TREE); ! 321: ! 322: /* Regparm attribute specifies how many integer arguments are to be ! 323: passed in registers */ ! 324: if (is_attribute_p ("regparm", identifier)) ! 325: { ! 326: tree cst; ! 327: ! 328: if (!args || TREE_CODE (args) != TREE_LIST ! 329: || TREE_CHAIN (args) != NULL_TREE ! 330: || TREE_VALUE (args) == NULL_TREE) ! 331: return 0; ! 332: ! 333: cst = TREE_VALUE (args); ! 334: if (TREE_CODE (cst) != INTEGER_CST) ! 335: return 0; ! 336: ! 337: if (TREE_INT_CST_HIGH (cst) != 0 ! 338: || TREE_INT_CST_LOW (cst) < 0 ! 339: || TREE_INT_CST_LOW (cst) > REGPARM_MAX) ! 340: return 0; ! 341: ! 342: return 1; ! 343: } ! 344: ! 345: return 0; ! 346: } ! 347: ! 348: /* Return 0 if the attributes for two types are incompatible, 1 if they ! 349: are compatible, and 2 if they are nearly compatible (which causes a ! 350: warning to be generated). */ ! 351: ! 352: int ! 353: i386_comp_type_attributes (type1, type2) ! 354: tree type1; ! 355: tree type2; ! 356: { ! 357: return 1; ! 358: } ! 359: ! 360: ! 361: /* Value is the number of bytes of arguments automatically ! 362: popped when returning from a subroutine call. ! 363: FUNDECL is the declaration node of the function (as a tree), ! 364: FUNTYPE is the data type of the function (as a tree), ! 365: or for a library call it is an identifier node for the subroutine name. ! 366: SIZE is the number of bytes of arguments passed on the stack. ! 367: ! 368: On the 80386, the RTD insn may be used to pop them if the number ! 369: of args is fixed, but if the number is variable then the caller ! 370: must pop them all. RTD can't be used for library calls now ! 371: because the library is compiled with the Unix compiler. ! 372: Use of RTD is a selectable option, since it is incompatible with ! 373: standard Unix calling sequences. If the option is not selected, ! 374: the caller must always pop the args. ! 375: ! 376: The attribute stdcall is equivalent to RTD on a per module basis. */ ! 377: ! 378: int ! 379: i386_return_pops_args (fundecl, funtype, size) ! 380: tree fundecl; ! 381: tree funtype; ! 382: int size; ! 383: { ! 384: int rtd = TARGET_RTD; ! 385: ! 386: if (TREE_CODE (funtype) == IDENTIFIER_NODE) ! 387: return 0; ! 388: ! 389: /* Cdecl functions override -mrtd, and never pop the stack */ ! 390: if (lookup_attribute ("cdecl", TYPE_ATTRIBUTES (funtype))) ! 391: return 0; ! 392: ! 393: /* Stdcall functions will pop the stack if not variable args */ ! 394: if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype))) ! 395: rtd = 1; ! 396: ! 397: if (rtd) ! 398: { ! 399: if (TYPE_ARG_TYPES (funtype) == NULL_TREE ! 400: || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype))) == void_type_node)) ! 401: return size; ! 402: ! 403: if (aggregate_value_p (TREE_TYPE (funtype))) ! 404: return GET_MODE_SIZE (Pmode); ! 405: } ! 406: ! 407: return 0; ! 408: } ! 409: ! 410: ! 411: /* Argument support functions. */ ! 412: ! 413: /* Initialize a variable CUM of type CUMULATIVE_ARGS ! 414: for a call to a function whose data type is FNTYPE. ! 415: For a library call, FNTYPE is 0. */ ! 416: ! 417: void ! 418: init_cumulative_args (cum, fntype, libname) ! 419: CUMULATIVE_ARGS *cum; /* argument info to initialize */ ! 420: tree fntype; /* tree ptr for function decl */ ! 421: rtx libname; /* SYMBOL_REF of library name or 0 */ ! 422: { ! 423: static CUMULATIVE_ARGS zero_cum; ! 424: tree param, next_param; ! 425: ! 426: if (TARGET_DEBUG_ARG) ! 427: { ! 428: fprintf (stderr, "\ninit_cumulative_args ("); ! 429: if (fntype) ! 430: { ! 431: tree ret_type = TREE_TYPE (fntype); ! 432: fprintf (stderr, "fntype code = %s, ret code = %s", ! 433: tree_code_name[ (int)TREE_CODE (fntype) ], ! 434: tree_code_name[ (int)TREE_CODE (ret_type) ]); ! 435: } ! 436: else ! 437: fprintf (stderr, "no fntype"); ! 438: ! 439: if (libname) ! 440: fprintf (stderr, ", libname = %s", XSTR (libname, 0)); ! 441: } ! 442: ! 443: *cum = zero_cum; ! 444: ! 445: /* Set up the number of registers to use for passing arguments. */ ! 446: cum->nregs = i386_regparm; ! 447: if (fntype) ! 448: { ! 449: tree attr = lookup_attribute ("regparm", TYPE_ATTRIBUTES (fntype)); ! 450: if (attr) ! 451: cum->nregs = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (attr))); ! 452: } ! 453: ! 454: /* Determine if this function has variable arguments. This is ! 455: indicated by the last argument being 'void_type_mode' if there ! 456: are no variable arguments. If there are variable arguments, then ! 457: we won't pass anything in registers */ ! 458: ! 459: if (cum->nregs) ! 460: { ! 461: for (param = (fntype) ? TYPE_ARG_TYPES (fntype) : 0; ! 462: param != (tree)0; ! 463: param = next_param) ! 464: { ! 465: next_param = TREE_CHAIN (param); ! 466: if (next_param == (tree)0 && TREE_VALUE (param) != void_type_node) ! 467: cum->nregs = 0; ! 468: } ! 469: } ! 470: ! 471: if (TARGET_DEBUG_ARG) ! 472: fprintf (stderr, ", nregs=%d )\n", cum->nregs); ! 473: ! 474: return; ! 475: } ! 476: ! 477: /* Update the data in CUM to advance over an argument ! 478: of mode MODE and data type TYPE. ! 479: (TYPE is null for libcalls where that information may not be available.) */ ! 480: ! 481: void ! 482: function_arg_advance (cum, mode, type, named) ! 483: CUMULATIVE_ARGS *cum; /* current arg information */ ! 484: enum machine_mode mode; /* current arg mode */ ! 485: tree type; /* type of the argument or 0 if lib support */ ! 486: int named; /* whether or not the argument was named */ ! 487: { ! 488: int bytes = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode); ! 489: int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD; ! 490: ! 491: if (TARGET_DEBUG_ARG) ! 492: fprintf (stderr, ! 493: "function_adv( size=%d, words=%2d, nregs=%d, mode=%4s, named=%d )\n\n", ! 494: words, cum->words, cum->nregs, GET_MODE_NAME (mode), named); ! 495: ! 496: cum->words += words; ! 497: cum->nregs -= words; ! 498: cum->regno += words; ! 499: ! 500: if (cum->nregs <= 0) ! 501: { ! 502: cum->nregs = 0; ! 503: cum->regno = 0; ! 504: } ! 505: ! 506: return; ! 507: } ! 508: ! 509: /* Define where to put the arguments to a function. ! 510: Value is zero to push the argument on the stack, ! 511: or a hard register in which to store the argument. ! 512: ! 513: MODE is the argument's machine mode. ! 514: TYPE is the data type of the argument (as a tree). ! 515: This is null for libcalls where that information may ! 516: not be available. ! 517: CUM is a variable of type CUMULATIVE_ARGS which gives info about ! 518: the preceding args and about the function being called. ! 519: NAMED is nonzero if this argument is a named parameter ! 520: (otherwise it is an extra parameter matching an ellipsis). */ ! 521: ! 522: struct rtx_def * ! 523: function_arg (cum, mode, type, named) ! 524: CUMULATIVE_ARGS *cum; /* current arg information */ ! 525: enum machine_mode mode; /* current arg mode */ ! 526: tree type; /* type of the argument or 0 if lib support */ ! 527: int named; /* != 0 for normal args, == 0 for ... args */ ! 528: { ! 529: rtx ret = NULL_RTX; ! 530: int bytes = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode); ! 531: int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD; ! 532: ! 533: switch (mode) ! 534: { ! 535: default: /* for now, pass fp/complex values on the stack */ ! 536: break; ! 537: ! 538: case BLKmode: ! 539: case DImode: ! 540: case SImode: ! 541: case HImode: ! 542: case QImode: ! 543: if (words <= cum->nregs) ! 544: ret = gen_rtx (REG, mode, cum->regno); ! 545: break; ! 546: } ! 547: ! 548: if (TARGET_DEBUG_ARG) ! 549: { ! 550: fprintf (stderr, ! 551: "function_arg( size=%d, words=%2d, nregs=%d, mode=%4s, named=%d", ! 552: words, cum->words, cum->nregs, GET_MODE_NAME (mode), named); ! 553: ! 554: if (ret) ! 555: fprintf (stderr, ", reg=%%e%s", reg_names[ REGNO(ret) ]); ! 556: else ! 557: fprintf (stderr, ", stack"); ! 558: ! 559: fprintf (stderr, " )\n"); ! 560: } ! 561: ! 562: return ret; ! 563: } ! 564: ! 565: /* For an arg passed partly in registers and partly in memory, ! 566: this is the number of registers used. ! 567: For args passed entirely in registers or entirely in memory, zero. */ ! 568: ! 569: int ! 570: function_arg_partial_nregs (cum, mode, type, named) ! 571: CUMULATIVE_ARGS *cum; /* current arg information */ ! 572: enum machine_mode mode; /* current arg mode */ ! 573: tree type; /* type of the argument or 0 if lib support */ ! 574: int named; /* != 0 for normal args, == 0 for ... args */ ! 575: { ! 576: return 0; ! 577: } ! 578: ! 579: 1.1 root 580: /* Output an insn whose source is a 386 integer register. SRC is the 581: rtx for the register, and TEMPLATE is the op-code template. SRC may 582: be either SImode or DImode. 583: 584: The template will be output with operands[0] as SRC, and operands[1] 585: as a pointer to the top of the 386 stack. So a call from floatsidf2 586: would look like this: 587: 588: output_op_from_reg (operands[1], AS1 (fild%z0,%1)); 589: 590: where %z0 corresponds to the caller's operands[1], and is used to 591: emit the proper size suffix. 592: 593: ??? Extend this to handle HImode - a 387 can load and store HImode 594: values directly. */ 595: 596: void 597: output_op_from_reg (src, template) 598: rtx src; 599: char *template; 600: { 601: rtx xops[4]; 1.1.1.2 root 602: int size = GET_MODE_SIZE (GET_MODE (src)); 1.1 root 603: 604: xops[0] = src; 605: xops[1] = AT_SP (Pmode); 1.1.1.2 root 606: xops[2] = GEN_INT (size); 1.1 root 607: xops[3] = stack_pointer_rtx; 608: 1.1.1.2 root 609: if (size > UNITS_PER_WORD) 1.1 root 610: { 1.1.1.2 root 611: rtx high; 612: if (size > 2 * UNITS_PER_WORD) 613: { 614: high = gen_rtx (REG, SImode, REGNO (src) + 2); 615: output_asm_insn (AS1 (push%L0,%0), &high); 616: } 617: high = gen_rtx (REG, SImode, REGNO (src) + 1); 1.1 root 618: output_asm_insn (AS1 (push%L0,%0), &high); 619: } 620: output_asm_insn (AS1 (push%L0,%0), &src); 621: 622: output_asm_insn (template, xops); 623: 624: output_asm_insn (AS2 (add%L3,%2,%3), xops); 625: } 626: 627: /* Output an insn to pop an value from the 387 top-of-stack to 386 628: register DEST. The 387 register stack is popped if DIES is true. If 629: the mode of DEST is an integer mode, a `fist' integer store is done, 630: otherwise a `fst' float store is done. */ 631: 632: void 633: output_to_reg (dest, dies) 634: rtx dest; 635: int dies; 636: { 637: rtx xops[4]; 1.1.1.2 root 638: int size = GET_MODE_SIZE (GET_MODE (dest)); 1.1 root 639: 640: xops[0] = AT_SP (Pmode); 641: xops[1] = stack_pointer_rtx; 1.1.1.2 root 642: xops[2] = GEN_INT (size); 1.1 root 643: xops[3] = dest; 644: 645: output_asm_insn (AS2 (sub%L1,%2,%1), xops); 646: 647: if (GET_MODE_CLASS (GET_MODE (dest)) == MODE_INT) 648: { 649: if (dies) 650: output_asm_insn (AS1 (fistp%z3,%y0), xops); 651: else 652: output_asm_insn (AS1 (fist%z3,%y0), xops); 653: } 654: else if (GET_MODE_CLASS (GET_MODE (dest)) == MODE_FLOAT) 655: { 656: if (dies) 657: output_asm_insn (AS1 (fstp%z3,%y0), xops); 658: else 1.1.1.2 root 659: { 660: if (GET_MODE (dest) == XFmode) 661: { 662: output_asm_insn (AS1 (fstp%z3,%y0), xops); 663: output_asm_insn (AS1 (fld%z3,%y0), xops); 664: } 665: else 666: output_asm_insn (AS1 (fst%z3,%y0), xops); 667: } 1.1 root 668: } 669: else 670: abort (); 671: 672: output_asm_insn (AS1 (pop%L0,%0), &dest); 673: 1.1.1.2 root 674: if (size > UNITS_PER_WORD) 1.1 root 675: { 676: dest = gen_rtx (REG, SImode, REGNO (dest) + 1); 677: output_asm_insn (AS1 (pop%L0,%0), &dest); 1.1.1.2 root 678: if (size > 2 * UNITS_PER_WORD) 679: { 680: dest = gen_rtx (REG, SImode, REGNO (dest) + 1); 681: output_asm_insn (AS1 (pop%L0,%0), &dest); 682: } 1.1 root 683: } 684: } 685: 686: char * 687: singlemove_string (operands) 688: rtx *operands; 689: { 690: rtx x; 691: if (GET_CODE (operands[0]) == MEM 692: && GET_CODE (x = XEXP (operands[0], 0)) == PRE_DEC) 693: { 694: if (XEXP (x, 0) != stack_pointer_rtx) 695: abort (); 696: return "push%L1 %1"; 697: } 698: else if (GET_CODE (operands[1]) == CONST_DOUBLE) 699: { 700: return output_move_const_single (operands); 701: } 702: else if (GET_CODE (operands[0]) == REG || GET_CODE (operands[1]) == REG) 703: return AS2 (mov%L0,%1,%0); 704: else if (CONSTANT_P (operands[1])) 705: return AS2 (mov%L0,%1,%0); 706: else 707: { 708: output_asm_insn ("push%L1 %1", operands); 709: return "pop%L0 %0"; 710: } 711: } 712: 713: /* Return a REG that occurs in ADDR with coefficient 1. 714: ADDR can be effectively incremented by incrementing REG. */ 715: 716: static rtx 717: find_addr_reg (addr) 718: rtx addr; 719: { 720: while (GET_CODE (addr) == PLUS) 721: { 722: if (GET_CODE (XEXP (addr, 0)) == REG) 723: addr = XEXP (addr, 0); 724: else if (GET_CODE (XEXP (addr, 1)) == REG) 725: addr = XEXP (addr, 1); 726: else if (CONSTANT_P (XEXP (addr, 0))) 727: addr = XEXP (addr, 1); 728: else if (CONSTANT_P (XEXP (addr, 1))) 729: addr = XEXP (addr, 0); 730: else 731: abort (); 732: } 733: if (GET_CODE (addr) == REG) 734: return addr; 735: abort (); 736: } 737: 1.1.1.3 root 738: 1.1 root 739: /* Output an insn to add the constant N to the register X. */ 740: 741: static void 742: asm_add (n, x) 743: int n; 744: rtx x; 745: { 746: rtx xops[2]; 1.1.1.3 root 747: xops[0] = x; 748: 749: if (n == -1) 750: output_asm_insn (AS1 (dec%L0,%0), xops); 751: else if (n == 1) 752: output_asm_insn (AS1 (inc%L0,%0), xops); 753: else if (n < 0) 1.1 root 754: { 1.1.1.3 root 755: xops[1] = GEN_INT (-n); 756: output_asm_insn (AS2 (sub%L0,%1,%0), xops); 1.1 root 757: } 758: else if (n > 0) 759: { 1.1.1.3 root 760: xops[1] = GEN_INT (n); 761: output_asm_insn (AS2 (add%L0,%1,%0), xops); 1.1 root 762: } 763: } 764: 1.1.1.3 root 765: 1.1 root 766: /* Output assembler code to perform a doubleword move insn 767: with operands OPERANDS. */ 768: 769: char * 770: output_move_double (operands) 771: rtx *operands; 772: { 773: enum {REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; 774: rtx latehalf[2]; 1.1.1.2 root 775: rtx middlehalf[2]; 776: rtx xops[2]; 1.1 root 777: rtx addreg0 = 0, addreg1 = 0; 778: int dest_overlapped_low = 0; 1.1.1.4 ! root 779: int size = GET_MODE_SIZE (GET_MODE (operands[0])); 1.1.1.2 root 780: 781: middlehalf[0] = 0; 782: middlehalf[1] = 0; 1.1 root 783: 784: /* First classify both operands. */ 785: 786: if (REG_P (operands[0])) 787: optype0 = REGOP; 788: else if (offsettable_memref_p (operands[0])) 789: optype0 = OFFSOP; 790: else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC) 791: optype0 = POPOP; 792: else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) 793: optype0 = PUSHOP; 794: else if (GET_CODE (operands[0]) == MEM) 795: optype0 = MEMOP; 796: else 797: optype0 = RNDOP; 798: 799: if (REG_P (operands[1])) 800: optype1 = REGOP; 801: else if (CONSTANT_P (operands[1])) 802: optype1 = CNSTOP; 803: else if (offsettable_memref_p (operands[1])) 804: optype1 = OFFSOP; 805: else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC) 806: optype1 = POPOP; 807: else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) 808: optype1 = PUSHOP; 809: else if (GET_CODE (operands[1]) == MEM) 810: optype1 = MEMOP; 811: else 812: optype1 = RNDOP; 813: 814: /* Check for the cases that the operand constraints are not 815: supposed to allow to happen. Abort if we get one, 816: because generating code for these cases is painful. */ 817: 818: if (optype0 == RNDOP || optype1 == RNDOP) 819: abort (); 820: 821: /* If one operand is decrementing and one is incrementing 822: decrement the former register explicitly 823: and change that operand into ordinary indexing. */ 824: 825: if (optype0 == PUSHOP && optype1 == POPOP) 826: { 1.1.1.2 root 827: /* ??? Can this ever happen on i386? */ 1.1 root 828: operands[0] = XEXP (XEXP (operands[0], 0), 0); 1.1.1.2 root 829: asm_add (-size, operands[0]); 830: if (GET_MODE (operands[1]) == XFmode) 831: operands[0] = gen_rtx (MEM, XFmode, operands[0]); 832: else if (GET_MODE (operands[0]) == DFmode) 833: operands[0] = gen_rtx (MEM, DFmode, operands[0]); 834: else 835: operands[0] = gen_rtx (MEM, DImode, operands[0]); 1.1 root 836: optype0 = OFFSOP; 837: } 1.1.1.2 root 838: 1.1 root 839: if (optype0 == POPOP && optype1 == PUSHOP) 840: { 1.1.1.2 root 841: /* ??? Can this ever happen on i386? */ 1.1 root 842: operands[1] = XEXP (XEXP (operands[1], 0), 0); 1.1.1.2 root 843: asm_add (-size, operands[1]); 844: if (GET_MODE (operands[1]) == XFmode) 845: operands[1] = gen_rtx (MEM, XFmode, operands[1]); 846: else if (GET_MODE (operands[1]) == DFmode) 847: operands[1] = gen_rtx (MEM, DFmode, operands[1]); 848: else 849: operands[1] = gen_rtx (MEM, DImode, operands[1]); 1.1 root 850: optype1 = OFFSOP; 851: } 852: 853: /* If an operand is an unoffsettable memory ref, find a register 854: we can increment temporarily to make it refer to the second word. */ 855: 856: if (optype0 == MEMOP) 857: addreg0 = find_addr_reg (XEXP (operands[0], 0)); 858: 859: if (optype1 == MEMOP) 860: addreg1 = find_addr_reg (XEXP (operands[1], 0)); 861: 862: /* Ok, we can do one word at a time. 863: Normally we do the low-numbered word first, 864: but if either operand is autodecrementing then we 865: do the high-numbered word first. 866: 867: In either case, set up in LATEHALF the operands to use 868: for the high-numbered word and in some cases alter the 869: operands in OPERANDS to be suitable for the low-numbered word. */ 870: 1.1.1.2 root 871: if (size == 12) 872: { 873: if (optype0 == REGOP) 874: { 875: middlehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); 876: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 2); 877: } 878: else if (optype0 == OFFSOP) 879: { 880: middlehalf[0] = adj_offsettable_operand (operands[0], 4); 881: latehalf[0] = adj_offsettable_operand (operands[0], 8); 882: } 883: else 884: { 885: middlehalf[0] = operands[0]; 886: latehalf[0] = operands[0]; 887: } 888: 889: if (optype1 == REGOP) 890: { 891: middlehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); 892: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 2); 893: } 894: else if (optype1 == OFFSOP) 895: { 896: middlehalf[1] = adj_offsettable_operand (operands[1], 4); 897: latehalf[1] = adj_offsettable_operand (operands[1], 8); 898: } 899: else if (optype1 == CNSTOP) 900: { 901: if (GET_CODE (operands[1]) == CONST_DOUBLE) 902: { 903: REAL_VALUE_TYPE r; long l[3]; 1.1 root 904: 1.1.1.2 root 905: REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]); 906: REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, l); 907: operands[1] = GEN_INT (l[0]); 908: middlehalf[1] = GEN_INT (l[1]); 909: latehalf[1] = GEN_INT (l[2]); 910: } 911: else if (CONSTANT_P (operands[1])) 912: /* No non-CONST_DOUBLE constant should ever appear here. */ 913: abort (); 914: } 915: else 1.1 root 916: { 1.1.1.2 root 917: middlehalf[1] = operands[1]; 918: latehalf[1] = operands[1]; 1.1 root 919: } 920: } 1.1.1.2 root 921: else /* size is not 12: */ 922: { 923: if (optype0 == REGOP) 924: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); 925: else if (optype0 == OFFSOP) 926: latehalf[0] = adj_offsettable_operand (operands[0], 4); 927: else 928: latehalf[0] = operands[0]; 929: 930: if (optype1 == REGOP) 931: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); 932: else if (optype1 == OFFSOP) 933: latehalf[1] = adj_offsettable_operand (operands[1], 4); 934: else if (optype1 == CNSTOP) 1.1.1.4 ! root 935: split_double (operands[1], &operands[1], &latehalf[1]); 1.1.1.2 root 936: else 937: latehalf[1] = operands[1]; 938: } 1.1 root 939: 940: /* If insn is effectively movd N (sp),-(sp) then we will do the 1.1.1.2 root 941: high word first. We should use the adjusted operand 1 942: (which is N+4 (sp) or N+8 (sp)) 943: for the low word and middle word as well, 944: to compensate for the first decrement of sp. */ 1.1 root 945: if (optype0 == PUSHOP 946: && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM 947: && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1])) 1.1.1.2 root 948: middlehalf[1] = operands[1] = latehalf[1]; 1.1 root 949: 950: /* For (set (reg:DI N) (mem:DI ... (reg:SI N) ...)), 951: if the upper part of reg N does not appear in the MEM, arrange to 952: emit the move late-half first. Otherwise, compute the MEM address 953: into the upper part of N and use that as a pointer to the memory 954: operand. */ 955: if (optype0 == REGOP 956: && (optype1 == OFFSOP || optype1 == MEMOP)) 957: { 958: if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)) 959: && reg_mentioned_p (latehalf[0], XEXP (operands[1], 0))) 960: { 961: /* If both halves of dest are used in the src memory address, 962: compute the address into latehalf of dest. */ 1.1.1.2 root 963: compadr: 1.1 root 964: xops[0] = latehalf[0]; 965: xops[1] = XEXP (operands[1], 0); 966: output_asm_insn (AS2 (lea%L0,%a1,%0), xops); 1.1.1.2 root 967: if( GET_MODE (operands[1]) == XFmode ) 968: { 969: /* abort (); */ 970: operands[1] = gen_rtx (MEM, XFmode, latehalf[0]); 971: middlehalf[1] = adj_offsettable_operand (operands[1], size-8); 972: latehalf[1] = adj_offsettable_operand (operands[1], size-4); 973: } 974: else 975: { 976: operands[1] = gen_rtx (MEM, DImode, latehalf[0]); 977: latehalf[1] = adj_offsettable_operand (operands[1], size-4); 978: } 979: } 980: else if (size == 12 981: && reg_mentioned_p (middlehalf[0], XEXP (operands[1], 0))) 982: { 983: /* Check for two regs used by both source and dest. */ 984: if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)) 985: || reg_mentioned_p (latehalf[0], XEXP (operands[1], 0))) 986: goto compadr; 987: 988: /* JRV says this can't happen: */ 989: if (addreg0 || addreg1) 990: abort(); 991: 992: /* Only the middle reg conflicts; simply put it last. */ 993: output_asm_insn (singlemove_string (operands), operands); 994: output_asm_insn (singlemove_string (latehalf), latehalf); 995: output_asm_insn (singlemove_string (middlehalf), middlehalf); 996: return ""; 1.1 root 997: } 998: else if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))) 999: /* If the low half of dest is mentioned in the source memory 1000: address, the arrange to emit the move late half first. */ 1001: dest_overlapped_low = 1; 1002: } 1003: 1004: /* If one or both operands autodecrementing, 1005: do the two words, high-numbered first. */ 1006: 1007: /* Likewise, the first move would clobber the source of the second one, 1008: do them in the other order. This happens only for registers; 1009: such overlap can't happen in memory unless the user explicitly 1010: sets it up, and that is an undefined circumstance. */ 1011: 1.1.1.2 root 1012: /* 1.1 root 1013: if (optype0 == PUSHOP || optype1 == PUSHOP 1014: || (optype0 == REGOP && optype1 == REGOP 1015: && REGNO (operands[0]) == REGNO (latehalf[1])) 1016: || dest_overlapped_low) 1.1.1.2 root 1017: */ 1018: if (optype0 == PUSHOP || optype1 == PUSHOP 1019: || (optype0 == REGOP && optype1 == REGOP 1020: && ((middlehalf[1] && REGNO (operands[0]) == REGNO (middlehalf[1])) 1021: || REGNO (operands[0]) == REGNO (latehalf[1]))) 1022: || dest_overlapped_low) 1.1 root 1023: { 1024: /* Make any unoffsettable addresses point at high-numbered word. */ 1025: if (addreg0) 1.1.1.2 root 1026: asm_add (size-4, addreg0); 1.1 root 1027: if (addreg1) 1.1.1.2 root 1028: asm_add (size-4, addreg1); 1.1 root 1029: 1030: /* Do that word. */ 1031: output_asm_insn (singlemove_string (latehalf), latehalf); 1032: 1033: /* Undo the adds we just did. */ 1034: if (addreg0) 1035: asm_add (-4, addreg0); 1036: if (addreg1) 1037: asm_add (-4, addreg1); 1038: 1.1.1.2 root 1039: if (size == 12) 1040: { 1041: output_asm_insn (singlemove_string (middlehalf), middlehalf); 1042: if (addreg0) 1043: asm_add (-4, addreg0); 1044: if (addreg1) 1045: asm_add (-4, addreg1); 1046: } 1047: 1.1 root 1048: /* Do low-numbered word. */ 1049: return singlemove_string (operands); 1050: } 1051: 1052: /* Normal case: do the two words, low-numbered first. */ 1053: 1054: output_asm_insn (singlemove_string (operands), operands); 1055: 1.1.1.2 root 1056: /* Do the middle one of the three words for long double */ 1057: if (size == 12) 1058: { 1059: if (addreg0) 1060: asm_add (4, addreg0); 1061: if (addreg1) 1062: asm_add (4, addreg1); 1063: 1064: output_asm_insn (singlemove_string (middlehalf), middlehalf); 1065: } 1066: 1.1 root 1067: /* Make any unoffsettable addresses point at high-numbered word. */ 1068: if (addreg0) 1069: asm_add (4, addreg0); 1070: if (addreg1) 1071: asm_add (4, addreg1); 1072: 1073: /* Do that word. */ 1074: output_asm_insn (singlemove_string (latehalf), latehalf); 1075: 1076: /* Undo the adds we just did. */ 1077: if (addreg0) 1.1.1.2 root 1078: asm_add (4-size, addreg0); 1.1 root 1079: if (addreg1) 1.1.1.2 root 1080: asm_add (4-size, addreg1); 1.1 root 1081: 1082: return ""; 1083: } 1.1.1.3 root 1084: 1085: 1086: #define MAX_TMPS 2 /* max temporary registers used */ 1087: 1088: /* Output the appropriate code to move push memory on the stack */ 1089: 1090: char * 1091: output_move_pushmem (operands, insn, length, tmp_start, n_operands) 1092: rtx operands[]; 1093: rtx insn; 1094: int length; 1095: int tmp_start; 1096: int n_operands; 1097: { 1098: 1099: struct { 1100: char *load; 1101: char *push; 1102: rtx xops[2]; 1103: } tmp_info[MAX_TMPS]; 1104: 1105: rtx src = operands[1]; 1106: int max_tmps = 0; 1107: int offset = 0; 1108: int stack_p = reg_overlap_mentioned_p (stack_pointer_rtx, src); 1109: int stack_offset = 0; 1110: int i, num_tmps; 1111: rtx xops[1]; 1112: 1113: if (!offsettable_memref_p (src)) 1114: fatal_insn ("Source is not offsettable", insn); 1115: 1116: if ((length & 3) != 0) 1117: fatal_insn ("Pushing non-word aligned size", insn); 1118: 1119: /* Figure out which temporary registers we have available */ 1120: for (i = tmp_start; i < n_operands; i++) 1121: { 1122: if (GET_CODE (operands[i]) == REG) 1123: { 1124: if (reg_overlap_mentioned_p (operands[i], src)) 1125: continue; 1126: 1127: tmp_info[ max_tmps++ ].xops[1] = operands[i]; 1128: if (max_tmps == MAX_TMPS) 1129: break; 1130: } 1131: } 1132: 1133: if (max_tmps == 0) 1134: for (offset = length - 4; offset >= 0; offset -= 4) 1135: { 1136: xops[0] = adj_offsettable_operand (src, offset + stack_offset); 1137: output_asm_insn (AS1(push%L0,%0), xops); 1138: if (stack_p) 1139: stack_offset += 4; 1140: } 1141: 1142: else 1143: for (offset = length - 4; offset >= 0; ) 1144: { 1145: for (num_tmps = 0; num_tmps < max_tmps && offset >= 0; num_tmps++) 1146: { 1147: tmp_info[num_tmps].load = AS2(mov%L0,%0,%1); 1148: tmp_info[num_tmps].push = AS1(push%L0,%1); 1149: tmp_info[num_tmps].xops[0] = adj_offsettable_operand (src, offset + stack_offset); 1150: offset -= 4; 1151: } 1152: 1153: for (i = 0; i < num_tmps; i++) 1154: output_asm_insn (tmp_info[i].load, tmp_info[i].xops); 1155: 1156: for (i = 0; i < num_tmps; i++) 1157: output_asm_insn (tmp_info[i].push, tmp_info[i].xops); 1158: 1159: if (stack_p) 1160: stack_offset += 4*num_tmps; 1161: } 1162: 1163: return ""; 1164: } 1165: 1166: 1167: 1168: /* Output the appropriate code to move data between two memory locations */ 1169: 1170: char * 1171: output_move_memory (operands, insn, length, tmp_start, n_operands) 1172: rtx operands[]; 1173: rtx insn; 1174: int length; 1175: int tmp_start; 1176: int n_operands; 1177: { 1178: struct { 1179: char *load; 1180: char *store; 1181: rtx xops[3]; 1182: } tmp_info[MAX_TMPS]; 1183: 1184: rtx dest = operands[0]; 1185: rtx src = operands[1]; 1186: rtx qi_tmp = NULL_RTX; 1187: int max_tmps = 0; 1188: int offset = 0; 1189: int i, num_tmps; 1190: rtx xops[3]; 1191: 1192: if (GET_CODE (dest) == MEM 1193: && GET_CODE (XEXP (dest, 0)) == PRE_INC 1194: && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx) 1195: return output_move_pushmem (operands, insn, length, tmp_start, n_operands); 1196: 1197: if (!offsettable_memref_p (src)) 1198: fatal_insn ("Source is not offsettable", insn); 1199: 1200: if (!offsettable_memref_p (dest)) 1201: fatal_insn ("Destination is not offsettable", insn); 1202: 1203: /* Figure out which temporary registers we have available */ 1204: for (i = tmp_start; i < n_operands; i++) 1205: { 1206: if (GET_CODE (operands[i]) == REG) 1207: { 1208: if ((length & 1) != 0 && !qi_tmp && QI_REG_P (operands[i])) 1209: qi_tmp = operands[i]; 1210: 1211: if (reg_overlap_mentioned_p (operands[i], dest)) 1212: fatal_insn ("Temporary register overlaps the destination", insn); 1213: 1214: if (reg_overlap_mentioned_p (operands[i], src)) 1215: fatal_insn ("Temporary register overlaps the source", insn); 1216: 1217: tmp_info[ max_tmps++ ].xops[2] = operands[i]; 1218: if (max_tmps == MAX_TMPS) 1219: break; 1220: } 1221: } 1222: 1223: if (max_tmps == 0) 1224: fatal_insn ("No scratch registers were found to do memory->memory moves", insn); 1225: 1226: if ((length & 1) != 0) 1227: { 1228: if (!qi_tmp) 1229: fatal_insn ("No byte register found when moving odd # of bytes.", insn); 1230: } 1231: 1232: while (length > 1) 1233: { 1234: for (num_tmps = 0; num_tmps < max_tmps; num_tmps++) 1235: { 1236: if (length >= 4) 1237: { 1238: tmp_info[num_tmps].load = AS2(mov%L0,%1,%2); 1239: tmp_info[num_tmps].store = AS2(mov%L0,%2,%0); 1240: tmp_info[num_tmps].xops[0] = adj_offsettable_operand (dest, offset); 1241: tmp_info[num_tmps].xops[1] = adj_offsettable_operand (src, offset); 1242: offset += 4; 1243: length -= 4; 1244: } 1245: else if (length >= 2) 1246: { 1247: tmp_info[num_tmps].load = AS2(mov%W0,%1,%2); 1248: tmp_info[num_tmps].store = AS2(mov%W0,%2,%0); 1249: tmp_info[num_tmps].xops[0] = adj_offsettable_operand (dest, offset); 1250: tmp_info[num_tmps].xops[1] = adj_offsettable_operand (src, offset); 1251: offset += 2; 1252: length -= 2; 1253: } 1254: else 1255: break; 1256: } 1257: 1258: for (i = 0; i < num_tmps; i++) 1259: output_asm_insn (tmp_info[i].load, tmp_info[i].xops); 1260: 1261: for (i = 0; i < num_tmps; i++) 1262: output_asm_insn (tmp_info[i].store, tmp_info[i].xops); 1263: } 1264: 1265: if (length == 1) 1266: { 1267: xops[0] = adj_offsettable_operand (dest, offset); 1268: xops[1] = adj_offsettable_operand (src, offset); 1269: xops[2] = qi_tmp; 1270: output_asm_insn (AS2(mov%B0,%1,%2), xops); 1271: output_asm_insn (AS2(mov%B0,%2,%0), xops); 1272: } 1273: 1274: return ""; 1275: } 1276: 1.1 root 1277: 1278: int 1279: standard_80387_constant_p (x) 1280: rtx x; 1281: { 1282: #if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC) 1283: REAL_VALUE_TYPE d; 1284: jmp_buf handler; 1285: int is0, is1; 1286: 1287: if (setjmp (handler)) 1288: return 0; 1289: 1290: set_float_handler (handler); 1291: REAL_VALUE_FROM_CONST_DOUBLE (d, x); 1292: is0 = REAL_VALUES_EQUAL (d, dconst0); 1293: is1 = REAL_VALUES_EQUAL (d, dconst1); 1294: set_float_handler (NULL_PTR); 1295: 1296: if (is0) 1297: return 1; 1298: 1299: if (is1) 1300: return 2; 1301: 1302: /* Note that on the 80387, other constants, such as pi, 1303: are much slower to load as standard constants 1304: than to load from doubles in memory! */ 1305: #endif 1306: 1307: return 0; 1308: } 1309: 1310: char * 1311: output_move_const_single (operands) 1312: rtx *operands; 1313: { 1314: if (FP_REG_P (operands[0])) 1315: { 1316: int conval = standard_80387_constant_p (operands[1]); 1317: 1318: if (conval == 1) 1319: return "fldz"; 1320: 1321: if (conval == 2) 1322: return "fld1"; 1323: } 1324: if (GET_CODE (operands[1]) == CONST_DOUBLE) 1325: { 1.1.1.2 root 1326: REAL_VALUE_TYPE r; long l; 1327: 1328: if (GET_MODE (operands[1]) == XFmode) 1329: abort (); 1330: 1331: REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]); 1332: REAL_VALUE_TO_TARGET_SINGLE (r, l); 1333: operands[1] = GEN_INT (l); 1.1 root 1334: } 1335: return singlemove_string (operands); 1336: } 1337: 1338: /* Returns 1 if OP is either a symbol reference or a sum of a symbol 1339: reference and a constant. */ 1340: 1341: int 1342: symbolic_operand (op, mode) 1343: register rtx op; 1344: enum machine_mode mode; 1345: { 1346: switch (GET_CODE (op)) 1347: { 1348: case SYMBOL_REF: 1349: case LABEL_REF: 1350: return 1; 1351: case CONST: 1352: op = XEXP (op, 0); 1353: return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF 1354: || GET_CODE (XEXP (op, 0)) == LABEL_REF) 1355: && GET_CODE (XEXP (op, 1)) == CONST_INT); 1356: default: 1357: return 0; 1358: } 1359: } 1360: 1361: /* Test for a valid operand for a call instruction. 1362: Don't allow the arg pointer register or virtual regs 1363: since they may change into reg + const, which the patterns 1364: can't handle yet. */ 1365: 1366: int 1367: call_insn_operand (op, mode) 1368: rtx op; 1369: enum machine_mode mode; 1370: { 1371: if (GET_CODE (op) == MEM 1372: && ((CONSTANT_ADDRESS_P (XEXP (op, 0)) 1373: /* This makes a difference for PIC. */ 1374: && general_operand (XEXP (op, 0), Pmode)) 1375: || (GET_CODE (XEXP (op, 0)) == REG 1376: && XEXP (op, 0) != arg_pointer_rtx 1377: && !(REGNO (XEXP (op, 0)) >= FIRST_PSEUDO_REGISTER 1378: && REGNO (XEXP (op, 0)) <= LAST_VIRTUAL_REGISTER)))) 1379: return 1; 1380: return 0; 1381: } 1382: 1383: /* Like call_insn_operand but allow (mem (symbol_ref ...)) 1384: even if pic. */ 1385: 1386: int 1387: expander_call_insn_operand (op, mode) 1388: rtx op; 1389: enum machine_mode mode; 1390: { 1391: if (GET_CODE (op) == MEM 1392: && (CONSTANT_ADDRESS_P (XEXP (op, 0)) 1393: || (GET_CODE (XEXP (op, 0)) == REG 1394: && XEXP (op, 0) != arg_pointer_rtx 1395: && !(REGNO (XEXP (op, 0)) >= FIRST_PSEUDO_REGISTER 1396: && REGNO (XEXP (op, 0)) <= LAST_VIRTUAL_REGISTER)))) 1397: return 1; 1398: return 0; 1399: } 1.1.1.4 ! root 1400: ! 1401: /* Return 1 if OP is a comparison operator that can use the condition code ! 1402: generated by an arithmetic operation. */ ! 1403: ! 1404: int ! 1405: arithmetic_comparison_operator (op, mode) ! 1406: register rtx op; ! 1407: enum machine_mode mode; ! 1408: { ! 1409: enum rtx_code code; ! 1410: ! 1411: if (mode != VOIDmode && mode != GET_MODE (op)) ! 1412: return 0; ! 1413: code = GET_CODE (op); ! 1414: if (GET_RTX_CLASS (code) != '<') ! 1415: return 0; ! 1416: ! 1417: return (code != GT && code != LE); ! 1418: } 1.1 root 1419: 1420: /* Returns 1 if OP contains a symbol reference */ 1421: 1422: int 1423: symbolic_reference_mentioned_p (op) 1424: rtx op; 1425: { 1426: register char *fmt; 1427: register int i; 1428: 1429: if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF) 1430: return 1; 1431: 1432: fmt = GET_RTX_FORMAT (GET_CODE (op)); 1433: for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--) 1434: { 1435: if (fmt[i] == 'E') 1436: { 1437: register int j; 1438: 1439: for (j = XVECLEN (op, i) - 1; j >= 0; j--) 1440: if (symbolic_reference_mentioned_p (XVECEXP (op, i, j))) 1441: return 1; 1442: } 1443: else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i))) 1444: return 1; 1445: } 1446: 1447: return 0; 1448: } 1449: 1450: /* This function generates the assembly code for function entry. 1451: FILE is an stdio stream to output the code to. 1452: SIZE is an int: how many units of temporary storage to allocate. */ 1453: 1454: void 1455: function_prologue (file, size) 1456: FILE *file; 1457: int size; 1458: { 1459: register int regno; 1460: int limit; 1461: rtx xops[4]; 1462: int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table 1463: || current_function_uses_const_pool); 1464: 1465: xops[0] = stack_pointer_rtx; 1466: xops[1] = frame_pointer_rtx; 1467: xops[2] = GEN_INT (size); 1468: if (frame_pointer_needed) 1469: { 1470: output_asm_insn ("push%L1 %1", xops); 1471: output_asm_insn (AS2 (mov%L0,%0,%1), xops); 1472: } 1473: 1474: if (size) 1475: output_asm_insn (AS2 (sub%L0,%2,%0), xops); 1476: 1477: /* Note If use enter it is NOT reversed args. 1478: This one is not reversed from intel!! 1479: I think enter is slower. Also sdb doesn't like it. 1480: But if you want it the code is: 1481: { 1482: xops[3] = const0_rtx; 1483: output_asm_insn ("enter %2,%3", xops); 1484: } 1485: */ 1486: limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM); 1487: for (regno = limit - 1; regno >= 0; regno--) 1488: if ((regs_ever_live[regno] && ! call_used_regs[regno]) 1489: || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) 1490: { 1491: xops[0] = gen_rtx (REG, SImode, regno); 1492: output_asm_insn ("push%L0 %0", xops); 1493: } 1494: 1495: if (pic_reg_used) 1496: { 1497: xops[0] = pic_offset_table_rtx; 1498: xops[1] = (rtx) gen_label_rtx (); 1499: 1500: output_asm_insn (AS1 (call,%P1), xops); 1501: ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (xops[1])); 1502: output_asm_insn (AS1 (pop%L0,%0), xops); 1503: output_asm_insn ("addl $_GLOBAL_OFFSET_TABLE_+[.-%P1],%0", xops); 1504: } 1505: } 1506: 1507: /* Return 1 if it is appropriate to emit `ret' instructions in the 1508: body of a function. Do this only if the epilogue is simple, needing a 1509: couple of insns. Prior to reloading, we can't tell how many registers 1510: must be saved, so return 0 then. 1511: 1512: If NON_SAVING_SETJMP is defined and true, then it is not possible 1513: for the epilogue to be simple, so return 0. This is a special case 1514: since NON_SAVING_SETJMP will not cause regs_ever_live to change until 1515: final, but jump_optimize may need to know sooner if a `return' is OK. */ 1516: 1517: int 1518: simple_386_epilogue () 1519: { 1520: int regno; 1521: int nregs = 0; 1522: int reglimit = (frame_pointer_needed 1523: ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM); 1524: int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table 1525: || current_function_uses_const_pool); 1526: 1527: #ifdef NON_SAVING_SETJMP 1528: if (NON_SAVING_SETJMP && current_function_calls_setjmp) 1529: return 0; 1530: #endif 1531: 1532: if (! reload_completed) 1533: return 0; 1534: 1535: for (regno = reglimit - 1; regno >= 0; regno--) 1536: if ((regs_ever_live[regno] && ! call_used_regs[regno]) 1537: || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) 1538: nregs++; 1539: 1540: return nregs == 0 || ! frame_pointer_needed; 1541: } 1542: 1.1.1.3 root 1543: 1.1 root 1544: /* This function generates the assembly code for function exit. 1545: FILE is an stdio stream to output the code to. 1546: SIZE is an int: how many units of temporary storage to deallocate. */ 1547: 1548: void 1549: function_epilogue (file, size) 1550: FILE *file; 1551: int size; 1552: { 1553: register int regno; 1554: register int nregs, limit; 1555: int offset; 1556: rtx xops[3]; 1557: int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table 1558: || current_function_uses_const_pool); 1559: 1560: /* Compute the number of registers to pop */ 1561: 1562: limit = (frame_pointer_needed 1563: ? FRAME_POINTER_REGNUM 1564: : STACK_POINTER_REGNUM); 1565: 1566: nregs = 0; 1567: 1568: for (regno = limit - 1; regno >= 0; regno--) 1569: if ((regs_ever_live[regno] && ! call_used_regs[regno]) 1570: || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) 1571: nregs++; 1572: 1573: /* sp is often unreliable so we must go off the frame pointer, 1574: */ 1575: 1576: /* In reality, we may not care if sp is unreliable, because we can 1577: restore the register relative to the frame pointer. In theory, 1578: since each move is the same speed as a pop, and we don't need the 1579: leal, this is faster. For now restore multiple registers the old 1580: way. */ 1581: 1582: offset = -size - (nregs * UNITS_PER_WORD); 1583: 1584: xops[2] = stack_pointer_rtx; 1585: 1586: if (nregs > 1 || ! frame_pointer_needed) 1587: { 1588: if (frame_pointer_needed) 1589: { 1590: xops[0] = adj_offsettable_operand (AT_BP (Pmode), offset); 1591: output_asm_insn (AS2 (lea%L2,%0,%2), xops); 1592: } 1593: 1594: for (regno = 0; regno < limit; regno++) 1595: if ((regs_ever_live[regno] && ! call_used_regs[regno]) 1596: || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) 1597: { 1598: xops[0] = gen_rtx (REG, SImode, regno); 1599: output_asm_insn ("pop%L0 %0", xops); 1600: } 1601: } 1602: else 1603: for (regno = 0; regno < limit; regno++) 1604: if ((regs_ever_live[regno] && ! call_used_regs[regno]) 1605: || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) 1606: { 1607: xops[0] = gen_rtx (REG, SImode, regno); 1608: xops[1] = adj_offsettable_operand (AT_BP (Pmode), offset); 1609: output_asm_insn (AS2 (mov%L0,%1,%0), xops); 1610: offset += 4; 1611: } 1612: 1613: if (frame_pointer_needed) 1614: { 1615: /* On i486, mov & pop is faster than "leave". */ 1616: 1.1.1.3 root 1617: if (!TARGET_386) 1.1 root 1618: { 1619: xops[0] = frame_pointer_rtx; 1620: output_asm_insn (AS2 (mov%L2,%0,%2), xops); 1621: output_asm_insn ("pop%L0 %0", xops); 1622: } 1623: else 1624: output_asm_insn ("leave", xops); 1625: } 1626: else if (size) 1627: { 1628: /* If there is no frame pointer, we must still release the frame. */ 1629: 1630: xops[0] = GEN_INT (size); 1631: output_asm_insn (AS2 (add%L2,%0,%2), xops); 1632: } 1633: 1634: if (current_function_pops_args && current_function_args_size) 1635: { 1636: xops[1] = GEN_INT (current_function_pops_args); 1637: 1638: /* i386 can only pop 32K bytes (maybe 64K? Is it signed?). If 1639: asked to pop more, pop return address, do explicit add, and jump 1640: indirectly to the caller. */ 1641: 1642: if (current_function_pops_args >= 32768) 1643: { 1644: /* ??? Which register to use here? */ 1645: xops[0] = gen_rtx (REG, SImode, 2); 1646: output_asm_insn ("pop%L0 %0", xops); 1647: output_asm_insn (AS2 (add%L2,%1,%2), xops); 1648: output_asm_insn ("jmp %*%0", xops); 1649: } 1650: else 1651: output_asm_insn ("ret %1", xops); 1652: } 1653: else 1654: output_asm_insn ("ret", xops); 1655: } 1.1.1.3 root 1656: 1.1 root 1657: 1.1.1.3 root 1658: /* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression 1659: that is a valid memory address for an instruction. 1660: The MODE argument is the machine mode for the MEM expression 1661: that wants to use this address. 1662: 1663: On x86, legitimate addresses are: 1664: base movl (base),reg 1665: displacement movl disp,reg 1666: base + displacement movl disp(base),reg 1667: index + base movl (base,index),reg 1668: (index + base) + displacement movl disp(base,index),reg 1669: index*scale movl (,index,scale),reg 1670: index*scale + disp movl disp(,index,scale),reg 1671: index*scale + base movl (base,index,scale),reg 1672: (index*scale + base) + disp movl disp(base,index,scale),reg 1673: 1674: In each case, scale can be 1, 2, 4, 8. */ 1675: 1676: /* This is exactly the same as print_operand_addr, except that 1677: it recognizes addresses instead of printing them. 1678: 1679: It only recognizes address in canonical form. LEGITIMIZE_ADDRESS should 1680: convert common non-canonical forms to canonical form so that they will 1681: be recognized. */ 1682: 1683: #define ADDR_INVALID(msg,insn) \ 1684: do { \ 1685: if (TARGET_DEBUG_ADDR) \ 1686: { \ 1687: fprintf (stderr, msg); \ 1688: debug_rtx (insn); \ 1689: } \ 1690: } while (0) 1.1 root 1691: 1.1.1.3 root 1692: int 1693: legitimate_address_p (mode, addr, strict) 1694: enum machine_mode mode; 1695: register rtx addr; 1696: int strict; 1697: { 1698: rtx base = NULL_RTX; 1699: rtx indx = NULL_RTX; 1700: rtx scale = NULL_RTX; 1701: rtx disp = NULL_RTX; 1702: 1703: if (TARGET_DEBUG_ADDR) 1704: { 1705: fprintf (stderr, 1706: "\n==========\nGO_IF_LEGITIMATE_ADDRESS, mode = %s, strict = %d\n", 1707: GET_MODE_NAME (mode), strict); 1708: 1709: debug_rtx (addr); 1710: } 1711: 1712: if (GET_CODE (addr) == REG || GET_CODE (addr) == SUBREG) 1713: base = addr; /* base reg */ 1714: 1715: else if (GET_CODE (addr) == PLUS) 1716: { 1717: rtx op0 = XEXP (addr, 0); 1718: rtx op1 = XEXP (addr, 1); 1719: enum rtx_code code0 = GET_CODE (op0); 1720: enum rtx_code code1 = GET_CODE (op1); 1721: 1722: if (code0 == REG || code0 == SUBREG) 1723: { 1724: if (code1 == REG || code1 == SUBREG) 1725: { 1726: indx = op0; /* index + base */ 1727: base = op1; 1728: } 1729: 1730: else 1731: { 1732: base = op0; /* base + displacement */ 1733: disp = op1; 1734: } 1735: } 1736: 1737: else if (code0 == MULT) 1738: { 1739: indx = XEXP (op0, 0); 1740: scale = XEXP (op0, 1); 1741: 1742: if (code1 == REG || code1 == SUBREG) 1743: base = op1; /* index*scale + base */ 1744: 1745: else 1746: disp = op1; /* index*scale + disp */ 1747: } 1748: 1749: else if (code0 == PLUS && GET_CODE (XEXP (op0, 0)) == MULT) 1750: { 1751: indx = XEXP (XEXP (op0, 0), 0); /* index*scale + base + disp */ 1752: scale = XEXP (XEXP (op0, 0), 1); 1753: base = XEXP (op0, 1); 1754: disp = op1; 1755: } 1756: 1757: else if (code0 == PLUS) 1758: { 1759: indx = XEXP (op0, 0); /* index + base + disp */ 1760: base = XEXP (op0, 1); 1761: disp = op1; 1762: } 1763: 1764: else 1765: { 1766: ADDR_INVALID ("PLUS subcode is not valid.\n", op0); 1767: return FALSE; 1768: } 1769: } 1770: 1771: else if (GET_CODE (addr) == MULT) 1772: { 1773: indx = XEXP (addr, 0); /* index*scale */ 1774: scale = XEXP (addr, 1); 1775: } 1776: 1777: else 1778: disp = addr; /* displacement */ 1779: 1780: /* Allow arg pointer and stack pointer as index if there is not scaling */ 1781: if (base && indx && !scale 1782: && (indx == arg_pointer_rtx || indx == stack_pointer_rtx)) 1783: { 1784: rtx tmp = base; 1785: base = indx; 1786: indx = tmp; 1787: } 1788: 1789: /* Validate base register */ 1790: /* Don't allow SUBREG's here, it can lead to spill failures when the base 1791: is one word out of a two word structure, which is represented internally 1792: as a DImode int. */ 1793: if (base) 1794: { 1795: if (GET_CODE (base) != REG) 1796: { 1797: ADDR_INVALID ("Base is not a register.\n", base); 1798: return FALSE; 1799: } 1800: 1801: if ((strict && !REG_OK_FOR_BASE_STRICT_P (base)) 1802: || (!strict && !REG_OK_FOR_BASE_NONSTRICT_P (base))) 1803: { 1804: ADDR_INVALID ("Base is not valid.\n", base); 1805: return FALSE; 1806: } 1807: } 1808: 1809: /* Validate index register */ 1810: /* Don't allow SUBREG's here, it can lead to spill failures when the index 1811: is one word out of a two word structure, which is represented internally 1812: as a DImode int. */ 1813: if (indx) 1814: { 1815: if (GET_CODE (indx) != REG) 1816: { 1817: ADDR_INVALID ("Index is not a register.\n", indx); 1818: return FALSE; 1819: } 1820: 1821: if ((strict && !REG_OK_FOR_INDEX_STRICT_P (indx)) 1822: || (!strict && !REG_OK_FOR_INDEX_NONSTRICT_P (indx))) 1823: { 1824: ADDR_INVALID ("Index is not valid.\n", indx); 1825: return FALSE; 1826: } 1827: } 1828: else if (scale) 1.1.1.4 ! root 1829: abort (); /* scale w/o index invalid */ 1.1.1.3 root 1830: 1831: /* Validate scale factor */ 1832: if (scale) 1833: { 1834: HOST_WIDE_INT value; 1835: 1836: if (GET_CODE (scale) != CONST_INT) 1837: { 1838: ADDR_INVALID ("Scale is not valid.\n", scale); 1839: return FALSE; 1840: } 1841: 1842: value = INTVAL (scale); 1843: if (value != 1 && value != 2 && value != 4 && value != 8) 1844: { 1845: ADDR_INVALID ("Scale is not a good multiplier.\n", scale); 1846: return FALSE; 1847: } 1848: } 1849: 1850: /* Validate displacement */ 1851: if (disp) 1852: { 1853: if (!CONSTANT_ADDRESS_P (disp)) 1854: { 1855: ADDR_INVALID ("Displacement is not valid.\n", disp); 1856: return FALSE; 1857: } 1858: 1859: if (GET_CODE (disp) == CONST_DOUBLE) 1860: { 1861: ADDR_INVALID ("Displacement is a const_double.\n", disp); 1862: return FALSE; 1863: } 1864: 1865: if (flag_pic && SYMBOLIC_CONST (disp) && base != pic_offset_table_rtx 1866: && (indx != pic_offset_table_rtx || scale != NULL_RTX)) 1867: { 1868: ADDR_INVALID ("Displacement is an invalid pic reference.\n", disp); 1869: return FALSE; 1870: } 1871: 1872: if (HALF_PIC_P () && HALF_PIC_ADDRESS_P (disp) 1873: && (base != NULL_RTX || indx != NULL_RTX)) 1874: { 1875: ADDR_INVALID ("Displacement is an invalid half-pic reference.\n", disp); 1876: return FALSE; 1877: } 1878: } 1879: 1880: if (TARGET_DEBUG_ADDR) 1881: fprintf (stderr, "Address is valid.\n"); 1882: 1883: /* Everything looks valid, return true */ 1884: return TRUE; 1885: } 1886: 1887: 1888: /* Return a legitimate reference for ORIG (an address) using the 1889: register REG. If REG is 0, a new pseudo is generated. 1890: 1891: There are three types of references that must be handled: 1892: 1893: 1. Global data references must load the address from the GOT, via 1894: the PIC reg. An insn is emitted to do this load, and the reg is 1895: returned. 1896: 1897: 2. Static data references must compute the address as an offset 1898: from the GOT, whose base is in the PIC reg. An insn is emitted to 1899: compute the address into a reg, and the reg is returned. Static 1900: data objects have SYMBOL_REF_FLAG set to differentiate them from 1901: global data objects. 1902: 1903: 3. Constant pool addresses must be handled special. They are 1904: considered legitimate addresses, but only if not used with regs. 1905: When printed, the output routines know to print the reference with the 1906: PIC reg, even though the PIC reg doesn't appear in the RTL. 1907: 1908: GO_IF_LEGITIMATE_ADDRESS rejects symbolic references unless the PIC 1909: reg also appears in the address (except for constant pool references, 1910: noted above). 1911: 1912: "switch" statements also require special handling when generating 1913: PIC code. See comments by the `casesi' insn in i386.md for details. */ 1914: 1915: rtx 1916: legitimize_pic_address (orig, reg) 1917: rtx orig; 1918: rtx reg; 1919: { 1920: rtx addr = orig; 1921: rtx new = orig; 1922: 1923: if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF) 1924: { 1925: if (GET_CODE (addr) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (addr)) 1926: reg = new = orig; 1927: else 1928: { 1929: if (reg == 0) 1930: reg = gen_reg_rtx (Pmode); 1931: 1932: if ((GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_FLAG (addr)) 1933: || GET_CODE (addr) == LABEL_REF) 1934: new = gen_rtx (PLUS, Pmode, pic_offset_table_rtx, orig); 1935: else 1936: new = gen_rtx (MEM, Pmode, 1937: gen_rtx (PLUS, Pmode, 1938: pic_offset_table_rtx, orig)); 1939: 1940: emit_move_insn (reg, new); 1941: } 1942: current_function_uses_pic_offset_table = 1; 1943: return reg; 1944: } 1945: else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS) 1946: { 1947: rtx base; 1948: 1949: if (GET_CODE (addr) == CONST) 1950: { 1951: addr = XEXP (addr, 0); 1952: if (GET_CODE (addr) != PLUS) 1953: abort (); 1954: } 1955: 1956: if (XEXP (addr, 0) == pic_offset_table_rtx) 1957: return orig; 1958: 1959: if (reg == 0) 1960: reg = gen_reg_rtx (Pmode); 1961: 1962: base = legitimize_pic_address (XEXP (addr, 0), reg); 1963: addr = legitimize_pic_address (XEXP (addr, 1), 1964: base == reg ? NULL_RTX : reg); 1965: 1966: if (GET_CODE (addr) == CONST_INT) 1967: return plus_constant (base, INTVAL (addr)); 1968: 1969: if (GET_CODE (addr) == PLUS && CONSTANT_P (XEXP (addr, 1))) 1970: { 1971: base = gen_rtx (PLUS, Pmode, base, XEXP (addr, 0)); 1972: addr = XEXP (addr, 1); 1973: } 1974: return gen_rtx (PLUS, Pmode, base, addr); 1975: } 1976: return new; 1977: } 1978: 1979: 1980: /* Emit insns to move operands[1] into operands[0]. */ 1981: 1982: void 1983: emit_pic_move (operands, mode) 1984: rtx *operands; 1985: enum machine_mode mode; 1986: { 1987: rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode); 1988: 1989: if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1])) 1990: operands[1] = (rtx) force_reg (SImode, operands[1]); 1991: else 1992: operands[1] = legitimize_pic_address (operands[1], temp); 1993: } 1994: 1995: 1996: /* Try machine-dependent ways of modifying an illegitimate address 1997: to be legitimate. If we find one, return the new, valid address. 1998: This macro is used in only one place: `memory_address' in explow.c. 1999: 2000: OLDX is the address as it was before break_out_memory_refs was called. 2001: In some cases it is useful to look at this to decide what needs to be done. 2002: 2003: MODE and WIN are passed so that this macro can use 2004: GO_IF_LEGITIMATE_ADDRESS. 2005: 2006: It is always safe for this macro to do nothing. It exists to recognize 2007: opportunities to optimize the output. 2008: 2009: For the 80386, we handle X+REG by loading X into a register R and 2010: using R+REG. R will go in a general reg and indexing will be used. 2011: However, if REG is a broken-out memory address or multiplication, 2012: nothing needs to be done because REG can certainly go in a general reg. 2013: 2014: When -fpic is used, special handling is needed for symbolic references. 2015: See comments by legitimize_pic_address in i386.c for details. */ 2016: 2017: rtx 2018: legitimize_address (x, oldx, mode) 2019: register rtx x; 2020: register rtx oldx; 2021: enum machine_mode mode; 2022: { 2023: int changed = 0; 2024: unsigned log; 2025: 2026: if (TARGET_DEBUG_ADDR) 2027: { 2028: fprintf (stderr, "\n==========\nLEGITIMIZE_ADDRESS, mode = %s\n", GET_MODE_NAME (mode)); 2029: debug_rtx (x); 2030: } 2031: 2032: if (flag_pic && SYMBOLIC_CONST (x)) 2033: return legitimize_pic_address (x, 0); 2034: 2035: /* Canonicalize shifts by 0, 1, 2, 3 into multiply */ 2036: if (GET_CODE (x) == ASHIFT 2037: && GET_CODE (XEXP (x, 1)) == CONST_INT 2038: && (log = (unsigned)exact_log2 (INTVAL (XEXP (x, 1)))) < 4) 2039: { 2040: changed = 1; 2041: x = gen_rtx (MULT, Pmode, 2042: force_reg (Pmode, XEXP (x, 0)), 2043: GEN_INT (1 << log)); 2044: } 2045: 2046: if (GET_CODE (x) == PLUS) 2047: { 2048: /* Canonicalize shifts by 0, 1, 2, 3 into multiply */ 2049: if (GET_CODE (XEXP (x, 0)) == ASHIFT 2050: && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT 2051: && (log = (unsigned)exact_log2 (INTVAL (XEXP (XEXP (x, 0), 1)))) < 4) 2052: { 2053: changed = 1; 2054: XEXP (x, 0) = gen_rtx (MULT, Pmode, 2055: force_reg (Pmode, XEXP (XEXP (x, 0), 0)), 2056: GEN_INT (1 << log)); 2057: } 2058: 2059: if (GET_CODE (XEXP (x, 1)) == ASHIFT 2060: && GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT 2061: && (log = (unsigned)exact_log2 (INTVAL (XEXP (XEXP (x, 1), 1)))) < 4) 2062: { 2063: changed = 1; 2064: XEXP (x, 1) = gen_rtx (MULT, Pmode, 2065: force_reg (Pmode, XEXP (XEXP (x, 1), 0)), 2066: GEN_INT (1 << log)); 2067: } 2068: 2069: /* Put multiply first if it isn't already */ 2070: if (GET_CODE (XEXP (x, 1)) == MULT) 2071: { 2072: rtx tmp = XEXP (x, 0); 2073: XEXP (x, 0) = XEXP (x, 1); 2074: XEXP (x, 1) = tmp; 2075: changed = 1; 2076: } 2077: 2078: /* Canonicalize (plus (mult (reg) (const)) (plus (reg) (const))) 2079: into (plus (plus (mult (reg) (const)) (reg)) (const)). This can be 2080: created by virtual register instantiation, register elimination, and 2081: similar optimizations. */ 2082: if (GET_CODE (XEXP (x, 0)) == MULT && GET_CODE (XEXP (x, 1)) == PLUS) 2083: { 2084: changed = 1; 2085: x = gen_rtx (PLUS, Pmode, 2086: gen_rtx (PLUS, Pmode, XEXP (x, 0), XEXP (XEXP (x, 1), 0)), 2087: XEXP (XEXP (x, 1), 1)); 2088: } 2089: 2090: /* Canonicalize (plus (plus (mult (reg) (const)) (plus (reg) (const))) const) 2091: into (plus (plus (mult (reg) (const)) (reg)) (const)). */ 2092: else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == PLUS 2093: && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT 2094: && GET_CODE (XEXP (XEXP (x, 0), 1)) == PLUS 2095: && CONSTANT_P (XEXP (x, 1))) 2096: { 2097: rtx constant, other; 2098: 2099: if (GET_CODE (XEXP (x, 1)) == CONST_INT) 2100: { 2101: constant = XEXP (x, 1); 2102: other = XEXP (XEXP (XEXP (x, 0), 1), 1); 2103: } 2104: else if (GET_CODE (XEXP (XEXP (XEXP (x, 0), 1), 1)) == CONST_INT) 2105: { 2106: constant = XEXP (XEXP (XEXP (x, 0), 1), 1); 2107: other = XEXP (x, 1); 2108: } 2109: else 2110: constant = 0; 2111: 2112: if (constant) 2113: { 2114: changed = 1; 2115: x = gen_rtx (PLUS, Pmode, 2116: gen_rtx (PLUS, Pmode, XEXP (XEXP (x, 0), 0), 2117: XEXP (XEXP (XEXP (x, 0), 1), 0)), 2118: plus_constant (other, INTVAL (constant))); 2119: } 2120: } 2121: 2122: if (changed && legitimate_address_p (mode, x, FALSE)) 2123: return x; 2124: 2125: if (GET_CODE (XEXP (x, 0)) == MULT) 2126: { 2127: changed = 1; 2128: XEXP (x, 0) = force_operand (XEXP (x, 0), 0); 2129: } 2130: 2131: if (GET_CODE (XEXP (x, 1)) == MULT) 2132: { 2133: changed = 1; 2134: XEXP (x, 1) = force_operand (XEXP (x, 1), 0); 2135: } 2136: 2137: if (changed 2138: && GET_CODE (XEXP (x, 1)) == REG 2139: && GET_CODE (XEXP (x, 0)) == REG) 2140: return x; 2141: 2142: if (flag_pic && SYMBOLIC_CONST (XEXP (x, 1))) 2143: { 2144: changed = 1; 2145: x = legitimize_pic_address (x, 0); 2146: } 2147: 2148: if (changed && legitimate_address_p (mode, x, FALSE)) 2149: return x; 2150: 2151: if (GET_CODE (XEXP (x, 0)) == REG) 2152: { 2153: register rtx temp = gen_reg_rtx (Pmode); 2154: register rtx val = force_operand (XEXP (x, 1), temp); 2155: if (val != temp) 2156: emit_move_insn (temp, val); 2157: 2158: XEXP (x, 1) = temp; 2159: return x; 2160: } 2161: 2162: else if (GET_CODE (XEXP (x, 1)) == REG) 2163: { 2164: register rtx temp = gen_reg_rtx (Pmode); 2165: register rtx val = force_operand (XEXP (x, 0), temp); 2166: if (val != temp) 2167: emit_move_insn (temp, val); 2168: 2169: XEXP (x, 0) = temp; 2170: return x; 2171: } 2172: } 2173: 2174: return x; 2175: } 2176: 2177: 2178: /* Print an integer constant expression in assembler syntax. Addition 2179: and subtraction are the only arithmetic that may appear in these 2180: expressions. FILE is the stdio stream to write to, X is the rtx, and 2181: CODE is the operand print code from the output string. */ 2182: 2183: static void 2184: output_pic_addr_const (file, x, code) 2185: FILE *file; 2186: rtx x; 2187: int code; 2188: { 2189: char buf[256]; 1.1 root 2190: 2191: switch (GET_CODE (x)) 2192: { 2193: case PC: 2194: if (flag_pic) 2195: putc ('.', file); 2196: else 2197: abort (); 2198: break; 2199: 2200: case SYMBOL_REF: 2201: case LABEL_REF: 2202: if (GET_CODE (x) == SYMBOL_REF) 2203: assemble_name (file, XSTR (x, 0)); 2204: else 2205: { 2206: ASM_GENERATE_INTERNAL_LABEL (buf, "L", 2207: CODE_LABEL_NUMBER (XEXP (x, 0))); 2208: assemble_name (asm_out_file, buf); 2209: } 2210: 2211: if (GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x)) 2212: fprintf (file, "@GOTOFF(%%ebx)"); 2213: else if (code == 'P') 2214: fprintf (file, "@PLT"); 1.1.1.3 root 2215: else if (GET_CODE (x) == LABEL_REF) 2216: fprintf (file, "@GOTOFF"); 2217: else if (! SYMBOL_REF_FLAG (x)) 1.1 root 2218: fprintf (file, "@GOT"); 2219: else 2220: fprintf (file, "@GOTOFF"); 2221: 2222: break; 2223: 2224: case CODE_LABEL: 2225: ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x)); 2226: assemble_name (asm_out_file, buf); 2227: break; 2228: 2229: case CONST_INT: 2230: fprintf (file, "%d", INTVAL (x)); 2231: break; 2232: 2233: case CONST: 2234: /* This used to output parentheses around the expression, 2235: but that does not work on the 386 (either ATT or BSD assembler). */ 2236: output_pic_addr_const (file, XEXP (x, 0), code); 2237: break; 2238: 2239: case CONST_DOUBLE: 2240: if (GET_MODE (x) == VOIDmode) 2241: { 2242: /* We can use %d if the number is <32 bits and positive. */ 2243: if (CONST_DOUBLE_HIGH (x) || CONST_DOUBLE_LOW (x) < 0) 2244: fprintf (file, "0x%x%08x", 2245: CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x)); 2246: else 2247: fprintf (file, "%d", CONST_DOUBLE_LOW (x)); 2248: } 2249: else 2250: /* We can't handle floating point constants; 2251: PRINT_OPERAND must handle them. */ 2252: output_operand_lossage ("floating constant misused"); 2253: break; 2254: 2255: case PLUS: 2256: /* Some assemblers need integer constants to appear last (eg masm). */ 2257: if (GET_CODE (XEXP (x, 0)) == CONST_INT) 2258: { 2259: output_pic_addr_const (file, XEXP (x, 1), code); 2260: if (INTVAL (XEXP (x, 0)) >= 0) 2261: fprintf (file, "+"); 2262: output_pic_addr_const (file, XEXP (x, 0), code); 2263: } 2264: else 2265: { 2266: output_pic_addr_const (file, XEXP (x, 0), code); 2267: if (INTVAL (XEXP (x, 1)) >= 0) 2268: fprintf (file, "+"); 2269: output_pic_addr_const (file, XEXP (x, 1), code); 2270: } 2271: break; 2272: 2273: case MINUS: 2274: output_pic_addr_const (file, XEXP (x, 0), code); 2275: fprintf (file, "-"); 2276: output_pic_addr_const (file, XEXP (x, 1), code); 2277: break; 2278: 2279: default: 2280: output_operand_lossage ("invalid expression as operand"); 2281: } 2282: } 2283: 2284: /* Meaning of CODE: 2285: f -- float insn (print a CONST_DOUBLE as a float rather than in hex). 2286: D,L,W,B,Q,S -- print the opcode suffix for specified size of operand. 2287: R -- print the prefix for register names. 2288: z -- print the opcode suffix for the size of the current operand. 2289: * -- print a star (in certain assembler syntax) 2290: w -- print the operand as if it's a "word" (HImode) even if it isn't. 2291: c -- don't print special prefixes before constant operands. 1.1.1.4 ! root 2292: J -- print the appropriate jump operand. 1.1 root 2293: */ 2294: 2295: void 2296: print_operand (file, x, code) 2297: FILE *file; 2298: rtx x; 2299: int code; 2300: { 2301: if (code) 2302: { 2303: switch (code) 2304: { 2305: case '*': 2306: if (USE_STAR) 2307: putc ('*', file); 2308: return; 2309: 2310: case 'L': 2311: PUT_OP_SIZE (code, 'l', file); 2312: return; 2313: 2314: case 'W': 2315: PUT_OP_SIZE (code, 'w', file); 2316: return; 2317: 2318: case 'B': 2319: PUT_OP_SIZE (code, 'b', file); 2320: return; 2321: 2322: case 'Q': 2323: PUT_OP_SIZE (code, 'l', file); 2324: return; 2325: 2326: case 'S': 2327: PUT_OP_SIZE (code, 's', file); 2328: return; 2329: 1.1.1.2 root 2330: case 'T': 2331: PUT_OP_SIZE (code, 't', file); 2332: return; 2333: 1.1 root 2334: case 'z': 2335: /* 387 opcodes don't get size suffixes if the operands are 2336: registers. */ 2337: 2338: if (STACK_REG_P (x)) 2339: return; 2340: 2341: /* this is the size of op from size of operand */ 2342: switch (GET_MODE_SIZE (GET_MODE (x))) 2343: { 2344: case 1: 2345: PUT_OP_SIZE ('B', 'b', file); 2346: return; 2347: 2348: case 2: 2349: PUT_OP_SIZE ('W', 'w', file); 2350: return; 2351: 2352: case 4: 2353: if (GET_MODE (x) == SFmode) 2354: { 2355: PUT_OP_SIZE ('S', 's', file); 2356: return; 2357: } 2358: else 2359: PUT_OP_SIZE ('L', 'l', file); 2360: return; 2361: 1.1.1.2 root 2362: case 12: 2363: PUT_OP_SIZE ('T', 't', file); 2364: return; 2365: 1.1 root 2366: case 8: 2367: if (GET_MODE_CLASS (GET_MODE (x)) == MODE_INT) 2368: { 2369: #ifdef GAS_MNEMONICS 2370: PUT_OP_SIZE ('Q', 'q', file); 2371: return; 2372: #else 2373: PUT_OP_SIZE ('Q', 'l', file); /* Fall through */ 2374: #endif 2375: } 2376: 2377: PUT_OP_SIZE ('Q', 'l', file); 2378: return; 2379: } 2380: 2381: case 'b': 2382: case 'w': 2383: case 'k': 2384: case 'h': 2385: case 'y': 2386: case 'P': 2387: break; 2388: 1.1.1.4 ! root 2389: case 'J': ! 2390: switch (GET_CODE (x)) ! 2391: { ! 2392: /* These conditions are appropriate for testing the result ! 2393: of an arithmetic operation, not for a compare operation. ! 2394: Cases GE, LT assume CC_NO_OVERFLOW true. All cases assume ! 2395: CC_Z_IN_NOT_C false and not floating point. */ ! 2396: case NE: fputs ("jne", file); return; ! 2397: case EQ: fputs ("je", file); return; ! 2398: case GE: fputs ("jns", file); return; ! 2399: case LT: fputs ("js", file); return; ! 2400: case GEU: fputs ("jmp", file); return; ! 2401: case GTU: fputs ("jne", file); return; ! 2402: case LEU: fputs ("je", file); return; ! 2403: case LTU: fputs ("#branch never", file); return; ! 2404: ! 2405: /* no matching branches for GT nor LE */ ! 2406: } ! 2407: abort (); ! 2408: 1.1 root 2409: default: 2410: { 2411: char str[50]; 2412: 2413: sprintf (str, "invalid operand code `%c'", code); 2414: output_operand_lossage (str); 2415: } 2416: } 2417: } 2418: if (GET_CODE (x) == REG) 2419: { 2420: PRINT_REG (x, code, file); 2421: } 2422: else if (GET_CODE (x) == MEM) 2423: { 2424: PRINT_PTR (x, file); 2425: if (CONSTANT_ADDRESS_P (XEXP (x, 0))) 2426: { 2427: if (flag_pic) 2428: output_pic_addr_const (file, XEXP (x, 0), code); 2429: else 2430: output_addr_const (file, XEXP (x, 0)); 2431: } 2432: else 2433: output_address (XEXP (x, 0)); 2434: } 2435: else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == SFmode) 2436: { 1.1.1.2 root 2437: REAL_VALUE_TYPE r; long l; 2438: REAL_VALUE_FROM_CONST_DOUBLE (r, x); 2439: REAL_VALUE_TO_TARGET_SINGLE (r, l); 1.1 root 2440: PRINT_IMMED_PREFIX (file); 1.1.1.2 root 2441: fprintf (file, "0x%x", l); 1.1 root 2442: } 1.1.1.2 root 2443: /* These float cases don't actually occur as immediate operands. */ 2444: else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode) 1.1 root 2445: { 1.1.1.2 root 2446: REAL_VALUE_TYPE r; char dstr[30]; 2447: REAL_VALUE_FROM_CONST_DOUBLE (r, x); 2448: REAL_VALUE_TO_DECIMAL (r, "%.22e", dstr); 2449: fprintf (file, "%s", dstr); 2450: } 2451: else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == XFmode) 2452: { 2453: REAL_VALUE_TYPE r; char dstr[30]; 2454: REAL_VALUE_FROM_CONST_DOUBLE (r, x); 2455: REAL_VALUE_TO_DECIMAL (r, "%.22e", dstr); 2456: fprintf (file, "%s", dstr); 1.1 root 2457: } 2458: else 2459: { 2460: if (code != 'P') 2461: { 2462: if (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE) 2463: PRINT_IMMED_PREFIX (file); 2464: else if (GET_CODE (x) == CONST || GET_CODE (x) == SYMBOL_REF 2465: || GET_CODE (x) == LABEL_REF) 2466: PRINT_OFFSET_PREFIX (file); 2467: } 2468: if (flag_pic) 2469: output_pic_addr_const (file, x, code); 2470: else 2471: output_addr_const (file, x); 2472: } 2473: } 2474: 2475: /* Print a memory operand whose address is ADDR. */ 2476: 2477: void 2478: print_operand_address (file, addr) 2479: FILE *file; 2480: register rtx addr; 2481: { 2482: register rtx reg1, reg2, breg, ireg; 2483: rtx offset; 2484: 2485: switch (GET_CODE (addr)) 2486: { 2487: case REG: 2488: ADDR_BEG (file); 2489: fprintf (file, "%se", RP); 2490: fputs (hi_reg_name[REGNO (addr)], file); 2491: ADDR_END (file); 2492: break; 2493: 2494: case PLUS: 2495: reg1 = 0; 2496: reg2 = 0; 2497: ireg = 0; 2498: breg = 0; 2499: offset = 0; 2500: if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) 2501: { 2502: offset = XEXP (addr, 0); 2503: addr = XEXP (addr, 1); 2504: } 2505: else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) 2506: { 2507: offset = XEXP (addr, 1); 2508: addr = XEXP (addr, 0); 2509: } 2510: if (GET_CODE (addr) != PLUS) ; 2511: else if (GET_CODE (XEXP (addr, 0)) == MULT) 2512: { 2513: reg1 = XEXP (addr, 0); 2514: addr = XEXP (addr, 1); 2515: } 2516: else if (GET_CODE (XEXP (addr, 1)) == MULT) 2517: { 2518: reg1 = XEXP (addr, 1); 2519: addr = XEXP (addr, 0); 2520: } 2521: else if (GET_CODE (XEXP (addr, 0)) == REG) 2522: { 2523: reg1 = XEXP (addr, 0); 2524: addr = XEXP (addr, 1); 2525: } 2526: else if (GET_CODE (XEXP (addr, 1)) == REG) 2527: { 2528: reg1 = XEXP (addr, 1); 2529: addr = XEXP (addr, 0); 2530: } 2531: if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT) 2532: { 2533: if (reg1 == 0) reg1 = addr; 2534: else reg2 = addr; 2535: addr = 0; 2536: } 2537: if (offset != 0) 2538: { 2539: if (addr != 0) abort (); 2540: addr = offset; 2541: } 2542: if ((reg1 && GET_CODE (reg1) == MULT) 2543: || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2)))) 2544: { 2545: breg = reg2; 2546: ireg = reg1; 2547: } 2548: else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1))) 2549: { 2550: breg = reg1; 2551: ireg = reg2; 2552: } 2553: 2554: if (ireg != 0 || breg != 0) 2555: { 2556: int scale = 1; 2557: 2558: if (addr != 0) 2559: { 1.1.1.3 root 2560: if (flag_pic) 2561: output_pic_addr_const (file, addr, 0); 2562: 2563: else if (GET_CODE (addr) == LABEL_REF) 1.1 root 2564: output_asm_label (addr); 1.1.1.3 root 2565: 1.1 root 2566: else 1.1.1.3 root 2567: output_addr_const (file, addr); 1.1 root 2568: } 2569: 2570: if (ireg != 0 && GET_CODE (ireg) == MULT) 2571: { 2572: scale = INTVAL (XEXP (ireg, 1)); 2573: ireg = XEXP (ireg, 0); 2574: } 2575: 2576: /* The stack pointer can only appear as a base register, 2577: never an index register, so exchange the regs if it is wrong. */ 2578: 2579: if (scale == 1 && ireg && REGNO (ireg) == STACK_POINTER_REGNUM) 2580: { 2581: rtx tmp; 2582: 2583: tmp = breg; 2584: breg = ireg; 2585: ireg = tmp; 2586: } 2587: 2588: /* output breg+ireg*scale */ 2589: PRINT_B_I_S (breg, ireg, scale, file); 2590: break; 2591: } 2592: 2593: case MULT: 2594: { 2595: int scale; 2596: if (GET_CODE (XEXP (addr, 0)) == CONST_INT) 2597: { 2598: scale = INTVAL (XEXP (addr, 0)); 2599: ireg = XEXP (addr, 1); 2600: } 2601: else 2602: { 2603: scale = INTVAL (XEXP (addr, 1)); 2604: ireg = XEXP (addr, 0); 2605: } 2606: output_addr_const (file, const0_rtx); 2607: PRINT_B_I_S ((rtx) 0, ireg, scale, file); 2608: } 2609: break; 2610: 2611: default: 2612: if (GET_CODE (addr) == CONST_INT 2613: && INTVAL (addr) < 0x8000 2614: && INTVAL (addr) >= -0x8000) 2615: fprintf (file, "%d", INTVAL (addr)); 2616: else 2617: { 2618: if (flag_pic) 2619: output_pic_addr_const (file, addr, 0); 2620: else 2621: output_addr_const (file, addr); 2622: } 2623: } 2624: } 2625: 2626: /* Set the cc_status for the results of an insn whose pattern is EXP. 2627: On the 80386, we assume that only test and compare insns, as well 1.1.1.3 root 2628: as SI, HI, & DI mode ADD, SUB, NEG, AND, IOR, XOR, ASHIFT, 1.1 root 2629: ASHIFTRT, and LSHIFTRT instructions set the condition codes usefully. 2630: Also, we assume that jumps, moves and sCOND don't affect the condition 2631: codes. All else clobbers the condition codes, by assumption. 2632: 2633: We assume that ALL integer add, minus, etc. instructions effect the 2634: condition codes. This MUST be consistent with i386.md. 2635: 2636: We don't record any float test or compare - the redundant test & 2637: compare check in final.c does not handle stack-like regs correctly. */ 2638: 2639: void 2640: notice_update_cc (exp) 2641: rtx exp; 2642: { 2643: if (GET_CODE (exp) == SET) 2644: { 2645: /* Jumps do not alter the cc's. */ 2646: if (SET_DEST (exp) == pc_rtx) 2647: return; 2648: /* Moving register or memory into a register: 2649: it doesn't alter the cc's, but it might invalidate 2650: the RTX's which we remember the cc's came from. 2651: (Note that moving a constant 0 or 1 MAY set the cc's). */ 2652: if (REG_P (SET_DEST (exp)) 2653: && (REG_P (SET_SRC (exp)) || GET_CODE (SET_SRC (exp)) == MEM 2654: || GET_RTX_CLASS (GET_CODE (SET_SRC (exp))) == '<')) 2655: { 2656: if (cc_status.value1 2657: && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1)) 2658: cc_status.value1 = 0; 2659: if (cc_status.value2 2660: && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2)) 2661: cc_status.value2 = 0; 2662: return; 2663: } 2664: /* Moving register into memory doesn't alter the cc's. 2665: It may invalidate the RTX's which we remember the cc's came from. */ 2666: if (GET_CODE (SET_DEST (exp)) == MEM 2667: && (REG_P (SET_SRC (exp)) 2668: || GET_RTX_CLASS (GET_CODE (SET_SRC (exp))) == '<')) 2669: { 2670: if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM) 2671: cc_status.value1 = 0; 2672: if (cc_status.value2 && GET_CODE (cc_status.value2) == MEM) 2673: cc_status.value2 = 0; 2674: return; 2675: } 2676: /* Function calls clobber the cc's. */ 2677: else if (GET_CODE (SET_SRC (exp)) == CALL) 2678: { 2679: CC_STATUS_INIT; 2680: return; 2681: } 2682: /* Tests and compares set the cc's in predictable ways. */ 2683: else if (SET_DEST (exp) == cc0_rtx) 2684: { 2685: CC_STATUS_INIT; 2686: cc_status.value1 = SET_SRC (exp); 2687: return; 2688: } 2689: /* Certain instructions effect the condition codes. */ 2690: else if (GET_MODE (SET_SRC (exp)) == SImode 2691: || GET_MODE (SET_SRC (exp)) == HImode 2692: || GET_MODE (SET_SRC (exp)) == QImode) 2693: switch (GET_CODE (SET_SRC (exp))) 2694: { 2695: case ASHIFTRT: case LSHIFTRT: 1.1.1.3 root 2696: case ASHIFT: 1.1 root 2697: /* Shifts on the 386 don't set the condition codes if the 2698: shift count is zero. */ 2699: if (GET_CODE (XEXP (SET_SRC (exp), 1)) != CONST_INT) 2700: { 2701: CC_STATUS_INIT; 2702: break; 2703: } 2704: /* We assume that the CONST_INT is non-zero (this rtx would 2705: have been deleted if it were zero. */ 2706: 2707: case PLUS: case MINUS: case NEG: 2708: case AND: case IOR: case XOR: 2709: cc_status.flags = CC_NO_OVERFLOW; 2710: cc_status.value1 = SET_SRC (exp); 2711: cc_status.value2 = SET_DEST (exp); 2712: break; 2713: 2714: default: 2715: CC_STATUS_INIT; 2716: } 2717: else 2718: { 2719: CC_STATUS_INIT; 2720: } 2721: } 2722: else if (GET_CODE (exp) == PARALLEL 2723: && GET_CODE (XVECEXP (exp, 0, 0)) == SET) 2724: { 2725: if (SET_DEST (XVECEXP (exp, 0, 0)) == pc_rtx) 2726: return; 2727: if (SET_DEST (XVECEXP (exp, 0, 0)) == cc0_rtx) 2728: { 2729: CC_STATUS_INIT; 2730: if (stack_regs_mentioned_p (SET_SRC (XVECEXP (exp, 0, 0)))) 2731: cc_status.flags |= CC_IN_80387; 2732: else 2733: cc_status.value1 = SET_SRC (XVECEXP (exp, 0, 0)); 2734: return; 2735: } 2736: CC_STATUS_INIT; 2737: } 2738: else 2739: { 2740: CC_STATUS_INIT; 2741: } 2742: } 2743: 2744: /* Split one or more DImode RTL references into pairs of SImode 2745: references. The RTL can be REG, offsettable MEM, integer constant, or 2746: CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to 2747: split and "num" is its length. lo_half and hi_half are output arrays 2748: that parallel "operands". */ 2749: 2750: void 2751: split_di (operands, num, lo_half, hi_half) 2752: rtx operands[]; 2753: int num; 2754: rtx lo_half[], hi_half[]; 2755: { 2756: while (num--) 2757: { 2758: if (GET_CODE (operands[num]) == REG) 2759: { 2760: lo_half[num] = gen_rtx (REG, SImode, REGNO (operands[num])); 2761: hi_half[num] = gen_rtx (REG, SImode, REGNO (operands[num]) + 1); 2762: } 2763: else if (CONSTANT_P (operands[num])) 2764: { 2765: split_double (operands[num], &lo_half[num], &hi_half[num]); 2766: } 2767: else if (offsettable_memref_p (operands[num])) 2768: { 2769: lo_half[num] = operands[num]; 2770: hi_half[num] = adj_offsettable_operand (operands[num], 4); 2771: } 2772: else 2773: abort(); 2774: } 2775: } 2776: 2777: /* Return 1 if this is a valid binary operation on a 387. 2778: OP is the expression matched, and MODE is its mode. */ 2779: 2780: int 2781: binary_387_op (op, mode) 2782: register rtx op; 2783: enum machine_mode mode; 2784: { 2785: if (mode != VOIDmode && mode != GET_MODE (op)) 2786: return 0; 2787: 2788: switch (GET_CODE (op)) 2789: { 2790: case PLUS: 2791: case MINUS: 2792: case MULT: 2793: case DIV: 2794: return GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT; 2795: 2796: default: 2797: return 0; 2798: } 2799: } 2800: 1.1.1.3 root 2801: 1.1 root 2802: /* Return 1 if this is a valid shift or rotate operation on a 386. 2803: OP is the expression matched, and MODE is its mode. */ 2804: 2805: int 2806: shift_op (op, mode) 2807: register rtx op; 2808: enum machine_mode mode; 2809: { 2810: rtx operand = XEXP (op, 0); 2811: 2812: if (mode != VOIDmode && mode != GET_MODE (op)) 2813: return 0; 2814: 2815: if (GET_MODE (operand) != GET_MODE (op) 2816: || GET_MODE_CLASS (GET_MODE (op)) != MODE_INT) 2817: return 0; 2818: 2819: return (GET_CODE (op) == ASHIFT 2820: || GET_CODE (op) == ASHIFTRT 2821: || GET_CODE (op) == LSHIFTRT 2822: || GET_CODE (op) == ROTATE 2823: || GET_CODE (op) == ROTATERT); 2824: } 2825: 2826: /* Return 1 if OP is COMPARE rtx with mode VOIDmode. 2827: MODE is not used. */ 2828: 2829: int 2830: VOIDmode_compare_op (op, mode) 2831: register rtx op; 2832: enum machine_mode mode; 2833: { 2834: return GET_CODE (op) == COMPARE && GET_MODE (op) == VOIDmode; 2835: } 2836: 2837: /* Output code to perform a 387 binary operation in INSN, one of PLUS, 2838: MINUS, MULT or DIV. OPERANDS are the insn operands, where operands[3] 2839: is the expression of the binary operation. The output may either be 2840: emitted here, or returned to the caller, like all output_* functions. 2841: 2842: There is no guarantee that the operands are the same mode, as they 2843: might be within FLOAT or FLOAT_EXTEND expressions. */ 2844: 2845: char * 2846: output_387_binary_op (insn, operands) 2847: rtx insn; 2848: rtx *operands; 2849: { 2850: rtx temp; 2851: char *base_op; 2852: static char buf[100]; 2853: 2854: switch (GET_CODE (operands[3])) 2855: { 2856: case PLUS: 2857: if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT 2858: || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT) 2859: base_op = "fiadd"; 2860: else 2861: base_op = "fadd"; 2862: break; 2863: 2864: case MINUS: 2865: if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT 2866: || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT) 2867: base_op = "fisub"; 2868: else 2869: base_op = "fsub"; 2870: break; 2871: 2872: case MULT: 2873: if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT 2874: || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT) 2875: base_op = "fimul"; 2876: else 2877: base_op = "fmul"; 2878: break; 2879: 2880: case DIV: 2881: if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT 2882: || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT) 2883: base_op = "fidiv"; 2884: else 2885: base_op = "fdiv"; 2886: break; 2887: 2888: default: 2889: abort (); 2890: } 2891: 2892: strcpy (buf, base_op); 2893: 2894: switch (GET_CODE (operands[3])) 2895: { 2896: case MULT: 2897: case PLUS: 2898: if (REG_P (operands[2]) && REGNO (operands[0]) == REGNO (operands[2])) 2899: { 2900: temp = operands[2]; 2901: operands[2] = operands[1]; 2902: operands[1] = temp; 2903: } 2904: 2905: if (GET_CODE (operands[2]) == MEM) 2906: return strcat (buf, AS1 (%z2,%2)); 2907: 2908: if (NON_STACK_REG_P (operands[1])) 2909: { 2910: output_op_from_reg (operands[1], strcat (buf, AS1 (%z0,%1))); 2911: RET; 2912: } 2913: else if (NON_STACK_REG_P (operands[2])) 2914: { 2915: output_op_from_reg (operands[2], strcat (buf, AS1 (%z0,%1))); 2916: RET; 2917: } 2918: 2919: if (find_regno_note (insn, REG_DEAD, REGNO (operands[2]))) 2920: return strcat (buf, AS2 (p,%2,%0)); 2921: 2922: if (STACK_TOP_P (operands[0])) 1.1.1.3 root 2923: return strcat (buf, AS2C (%y2,%0)); 1.1 root 2924: else 1.1.1.3 root 2925: return strcat (buf, AS2C (%2,%0)); 1.1 root 2926: 2927: case MINUS: 2928: case DIV: 2929: if (GET_CODE (operands[1]) == MEM) 2930: return strcat (buf, AS1 (r%z1,%1)); 2931: 2932: if (GET_CODE (operands[2]) == MEM) 2933: return strcat (buf, AS1 (%z2,%2)); 2934: 2935: if (NON_STACK_REG_P (operands[1])) 2936: { 2937: output_op_from_reg (operands[1], strcat (buf, AS1 (r%z0,%1))); 2938: RET; 2939: } 2940: else if (NON_STACK_REG_P (operands[2])) 2941: { 2942: output_op_from_reg (operands[2], strcat (buf, AS1 (%z0,%1))); 2943: RET; 2944: } 2945: 2946: if (! STACK_REG_P (operands[1]) || ! STACK_REG_P (operands[2])) 2947: abort (); 2948: 2949: if (find_regno_note (insn, REG_DEAD, REGNO (operands[2]))) 2950: return strcat (buf, AS2 (rp,%2,%0)); 2951: 2952: if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) 2953: return strcat (buf, AS2 (p,%1,%0)); 2954: 2955: if (STACK_TOP_P (operands[0])) 2956: { 2957: if (STACK_TOP_P (operands[1])) 1.1.1.3 root 2958: return strcat (buf, AS2C (%y2,%0)); 1.1 root 2959: else 2960: return strcat (buf, AS2 (r,%y1,%0)); 2961: } 2962: else if (STACK_TOP_P (operands[1])) 1.1.1.3 root 2963: return strcat (buf, AS2C (%1,%0)); 1.1 root 2964: else 2965: return strcat (buf, AS2 (r,%2,%0)); 2966: 2967: default: 2968: abort (); 2969: } 2970: } 2971: 2972: /* Output code for INSN to convert a float to a signed int. OPERANDS 2973: are the insn operands. The output may be SFmode or DFmode and the 2974: input operand may be SImode or DImode. As a special case, make sure 2975: that the 387 stack top dies if the output mode is DImode, because the 2976: hardware requires this. */ 2977: 2978: char * 2979: output_fix_trunc (insn, operands) 2980: rtx insn; 2981: rtx *operands; 2982: { 2983: int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; 2984: rtx xops[2]; 2985: 2986: if (! STACK_TOP_P (operands[1]) || 2987: (GET_MODE (operands[0]) == DImode && ! stack_top_dies)) 2988: abort (); 2989: 2990: xops[0] = GEN_INT (12); 2991: xops[1] = operands[4]; 2992: 2993: output_asm_insn (AS1 (fnstc%W2,%2), operands); 2994: output_asm_insn (AS2 (mov%L2,%2,%4), operands); 2995: output_asm_insn (AS2 (mov%B1,%0,%h1), xops); 2996: output_asm_insn (AS2 (mov%L4,%4,%3), operands); 2997: output_asm_insn (AS1 (fldc%W3,%3), operands); 2998: 2999: if (NON_STACK_REG_P (operands[0])) 3000: output_to_reg (operands[0], stack_top_dies); 3001: else if (GET_CODE (operands[0]) == MEM) 3002: { 3003: if (stack_top_dies) 3004: output_asm_insn (AS1 (fistp%z0,%0), operands); 3005: else 3006: output_asm_insn (AS1 (fist%z0,%0), operands); 3007: } 3008: else 3009: abort (); 3010: 3011: return AS1 (fldc%W2,%2); 3012: } 3013: 3014: /* Output code for INSN to compare OPERANDS. The two operands might 3015: not have the same mode: one might be within a FLOAT or FLOAT_EXTEND 3016: expression. If the compare is in mode CCFPEQmode, use an opcode that 3017: will not fault if a qNaN is present. */ 3018: 3019: char * 3020: output_float_compare (insn, operands) 3021: rtx insn; 3022: rtx *operands; 3023: { 3024: int stack_top_dies; 3025: rtx body = XVECEXP (PATTERN (insn), 0, 0); 3026: int unordered_compare = GET_MODE (SET_SRC (body)) == CCFPEQmode; 3027: 3028: if (! STACK_TOP_P (operands[0])) 3029: abort (); 3030: 3031: stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; 3032: 3033: if (STACK_REG_P (operands[1]) 3034: && stack_top_dies 3035: && find_regno_note (insn, REG_DEAD, REGNO (operands[1])) 3036: && REGNO (operands[1]) != FIRST_STACK_REG) 3037: { 3038: /* If both the top of the 387 stack dies, and the other operand 3039: is also a stack register that dies, then this must be a 3040: `fcompp' float compare */ 3041: 3042: if (unordered_compare) 3043: output_asm_insn ("fucompp", operands); 3044: else 3045: output_asm_insn ("fcompp", operands); 3046: } 3047: else 3048: { 3049: static char buf[100]; 3050: 3051: /* Decide if this is the integer or float compare opcode, or the 3052: unordered float compare. */ 3053: 3054: if (unordered_compare) 3055: strcpy (buf, "fucom"); 3056: else if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_FLOAT) 3057: strcpy (buf, "fcom"); 3058: else 3059: strcpy (buf, "ficom"); 3060: 3061: /* Modify the opcode if the 387 stack is to be popped. */ 3062: 3063: if (stack_top_dies) 3064: strcat (buf, "p"); 3065: 3066: if (NON_STACK_REG_P (operands[1])) 3067: output_op_from_reg (operands[1], strcat (buf, AS1 (%z0,%1))); 3068: else 3069: output_asm_insn (strcat (buf, AS1 (%z1,%y1)), operands); 3070: } 3071: 3072: /* Now retrieve the condition code. */ 3073: 3074: return output_fp_cc0_set (insn); 3075: } 3076: 3077: /* Output opcodes to transfer the results of FP compare or test INSN 3078: from the FPU to the CPU flags. If TARGET_IEEE_FP, ensure that if the 3079: result of the compare or test is unordered, no comparison operator 3080: succeeds except NE. Return an output template, if any. */ 3081: 3082: char * 3083: output_fp_cc0_set (insn) 3084: rtx insn; 3085: { 3086: rtx xops[3]; 3087: rtx unordered_label; 3088: rtx next; 3089: enum rtx_code code; 3090: 3091: xops[0] = gen_rtx (REG, HImode, 0); 3092: output_asm_insn (AS1 (fnsts%W0,%0), xops); 3093: 3094: if (! TARGET_IEEE_FP) 3095: return "sahf"; 3096: 3097: next = next_cc0_user (insn); 3098: if (next == NULL_RTX) 3099: abort (); 3100: 3101: if (GET_CODE (next) == JUMP_INSN 3102: && GET_CODE (PATTERN (next)) == SET 3103: && SET_DEST (PATTERN (next)) == pc_rtx 3104: && GET_CODE (SET_SRC (PATTERN (next))) == IF_THEN_ELSE) 3105: { 3106: code = GET_CODE (XEXP (SET_SRC (PATTERN (next)), 0)); 3107: } 3108: else if (GET_CODE (PATTERN (next)) == SET) 3109: { 3110: code = GET_CODE (SET_SRC (PATTERN (next))); 3111: } 3112: else 3113: abort (); 3114: 3115: xops[0] = gen_rtx (REG, QImode, 0); 3116: 3117: switch (code) 3118: { 3119: case GT: 3120: xops[1] = GEN_INT (0x45); 3121: output_asm_insn (AS2 (and%B0,%1,%h0), xops); 3122: /* je label */ 3123: break; 3124: 3125: case LT: 3126: xops[1] = GEN_INT (0x45); 3127: xops[2] = GEN_INT (0x01); 3128: output_asm_insn (AS2 (and%B0,%1,%h0), xops); 3129: output_asm_insn (AS2 (cmp%B0,%2,%h0), xops); 3130: /* je label */ 3131: break; 3132: 3133: case GE: 3134: xops[1] = GEN_INT (0x05); 3135: output_asm_insn (AS2 (and%B0,%1,%h0), xops); 3136: /* je label */ 3137: break; 3138: 3139: case LE: 3140: xops[1] = GEN_INT (0x45); 3141: xops[2] = GEN_INT (0x40); 3142: output_asm_insn (AS2 (and%B0,%1,%h0), xops); 3143: output_asm_insn (AS1 (dec%B0,%h0), xops); 3144: output_asm_insn (AS2 (cmp%B0,%2,%h0), xops); 3145: /* jb label */ 3146: break; 3147: 3148: case EQ: 3149: xops[1] = GEN_INT (0x45); 3150: xops[2] = GEN_INT (0x40); 3151: output_asm_insn (AS2 (and%B0,%1,%h0), xops); 3152: output_asm_insn (AS2 (cmp%B0,%2,%h0), xops); 3153: /* je label */ 3154: break; 3155: 3156: case NE: 3157: xops[1] = GEN_INT (0x44); 3158: xops[2] = GEN_INT (0x40); 3159: output_asm_insn (AS2 (and%B0,%1,%h0), xops); 3160: output_asm_insn (AS2 (xor%B0,%2,%h0), xops); 3161: /* jne label */ 3162: break; 3163: 3164: case GTU: 3165: case LTU: 3166: case GEU: 3167: case LEU: 3168: default: 3169: abort (); 3170: } 3171: RET; 3172: } 3173: 3174: #define MAX_386_STACK_LOCALS 2 3175: 3176: static rtx i386_stack_locals[(int) MAX_MACHINE_MODE][MAX_386_STACK_LOCALS]; 3177: 1.1.1.2 root 3178: /* Define the structure for the machine field in struct function. */ 3179: struct machine_function 3180: { 3181: rtx i386_stack_locals[(int) MAX_MACHINE_MODE][MAX_386_STACK_LOCALS]; 3182: }; 3183: 3184: /* Functions to save and restore i386_stack_locals. 3185: These will be called, via pointer variables, 3186: from push_function_context and pop_function_context. */ 3187: 3188: void 3189: save_386_machine_status (p) 3190: struct function *p; 3191: { 3192: p->machine = (struct machine_function *) xmalloc (sizeof i386_stack_locals); 1.1.1.3 root 3193: bcopy ((char *) i386_stack_locals, (char *) p->machine->i386_stack_locals, 1.1.1.2 root 3194: sizeof i386_stack_locals); 3195: } 3196: 3197: void 3198: restore_386_machine_status (p) 3199: struct function *p; 3200: { 1.1.1.3 root 3201: bcopy ((char *) p->machine->i386_stack_locals, (char *) i386_stack_locals, 1.1.1.2 root 3202: sizeof i386_stack_locals); 3203: free (p->machine); 3204: } 3205: 1.1 root 3206: /* Clear stack slot assignments remembered from previous functions. 3207: This is called from INIT_EXPANDERS once before RTL is emitted for each 1.1.1.2 root 3208: function. */ 1.1 root 3209: 3210: void 3211: clear_386_stack_locals () 3212: { 3213: enum machine_mode mode; 3214: int n; 3215: 3216: for (mode = VOIDmode; (int) mode < (int) MAX_MACHINE_MODE; 3217: mode = (enum machine_mode) ((int) mode + 1)) 3218: for (n = 0; n < MAX_386_STACK_LOCALS; n++) 3219: i386_stack_locals[(int) mode][n] = NULL_RTX; 1.1.1.2 root 3220: 3221: /* Arrange to save and restore i386_stack_locals around nested functions. */ 3222: save_machine_status = save_386_machine_status; 3223: restore_machine_status = restore_386_machine_status; 1.1 root 3224: } 3225: 3226: /* Return a MEM corresponding to a stack slot with mode MODE. 3227: Allocate a new slot if necessary. 3228: 3229: The RTL for a function can have several slots available: N is 3230: which slot to use. */ 3231: 3232: rtx 3233: assign_386_stack_local (mode, n) 3234: enum machine_mode mode; 3235: int n; 3236: { 3237: if (n < 0 || n >= MAX_386_STACK_LOCALS) 3238: abort (); 3239: 3240: if (i386_stack_locals[(int) mode][n] == NULL_RTX) 3241: i386_stack_locals[(int) mode][n] 3242: = assign_stack_local (mode, GET_MODE_SIZE (mode), 0); 3243: 3244: return i386_stack_locals[(int) mode][n]; 3245: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.