|
|
1.1 ! root 1: /* Convert tree expression to rtl instructions, for GNU compiler. ! 2: Copyright (C) 1988 Free Software Foundation, Inc. ! 3: ! 4: This file is part of GNU CC. ! 5: ! 6: GNU CC is distributed in the hope that it will be useful, ! 7: but WITHOUT ANY WARRANTY. No author or distributor ! 8: accepts responsibility to anyone for the consequences of using it ! 9: or for whether it serves any particular purpose or works at all, ! 10: unless he says so in writing. Refer to the GNU CC General Public ! 11: License for full details. ! 12: ! 13: Everyone is granted permission to copy, modify and redistribute ! 14: GNU CC, but only under the conditions described in the ! 15: GNU CC General Public License. A copy of this license is ! 16: supposed to have been given to you along with GNU CC so you ! 17: can know your rights and responsibilities. It should be in a ! 18: file named COPYING. Among other things, the copyright notice ! 19: and this notice must be preserved on all copies. */ ! 20: ! 21: ! 22: #include "config.h" ! 23: #include "rtl.h" ! 24: #include "tree.h" ! 25: #include "flags.h" ! 26: #include "insn-flags.h" ! 27: #include "insn-codes.h" ! 28: #include "expr.h" ! 29: #include "insn-config.h" ! 30: #include "recog.h" ! 31: #include "varargs.h" ! 32: ! 33: /* Decide whether a function's arguments should be processed ! 34: from first to last or from last to first. */ ! 35: ! 36: #ifdef STACK_GROWS_DOWNWARD ! 37: #ifdef PUSH_ROUNDING ! 38: #define PUSH_ARGS_REVERSED /* If it's last to first */ ! 39: #endif ! 40: #endif ! 41: ! 42: /* Like STACK_BOUNDARY but in units of bytes, not bits. */ ! 43: #define STACK_BYTES (STACK_BOUNDARY / BITS_PER_UNIT) ! 44: ! 45: /* If this is nonzero, we do not bother generating VOLATILE ! 46: around volatile memory references, and we are willing to ! 47: output indirect addresses. If cse is to follow, we reject ! 48: indirect addresses so a useful potential cse is generated; ! 49: if it is used only once, instruction combination will produce ! 50: the same indirect address eventually. */ ! 51: int cse_not_expected; ! 52: ! 53: /* Nonzero to generate code for all the subroutines within an ! 54: expression before generating the upper levels of the expression. ! 55: Nowadays this is never zero. */ ! 56: int do_preexpand_calls = 1; ! 57: ! 58: /* Number of units that we should eventually pop off the stack. ! 59: These are the arguments to function calls that have already returned. */ ! 60: int pending_stack_adjust; ! 61: ! 62: /* Total size of arguments already pushed for function calls that ! 63: have not happened yet. Also counts 1 for each level of conditional ! 64: expression that we are inside. When this is nonzero, ! 65: args passed to function calls must be popped right away ! 66: to ensure contiguity of argument lists for future calls. */ ! 67: static int current_args_size; ! 68: ! 69: /* Nonzero means current function may call alloca. */ ! 70: int may_call_alloca; ! 71: ! 72: rtx store_expr (); ! 73: static void store_constructor (); ! 74: static rtx store_field (); ! 75: static rtx expand_call (); ! 76: static void emit_call_1 (); ! 77: static rtx prepare_call_address (); ! 78: static rtx expand_builtin (); ! 79: static rtx compare (); ! 80: static rtx compare_constants (); ! 81: static rtx compare1 (); ! 82: static rtx do_store_flag (); ! 83: static void preexpand_calls (); ! 84: static rtx expand_increment (); ! 85: static void move_by_pieces_1 (); ! 86: static void init_queue (); ! 87: ! 88: void do_pending_stack_adjust (); ! 89: ! 90: /* MOVE_RATIO is the number of move instructions that is better than ! 91: a block move. */ ! 92: ! 93: #if defined (HAVE_movstrhi) || defined (HAVE_movstrsi) ! 94: #define MOVE_RATIO 2 ! 95: #else ! 96: #define MOVE_RATIO 6 ! 97: #endif ! 98: ! 99: /* Table indexed by tree code giving 1 if the code is for a ! 100: comparison operation, or anything that is most easily ! 101: computed with a conditional branch. ! 102: ! 103: We include tree.def to give it the proper length. ! 104: The contents thus created are irrelevant. ! 105: The real contents are initialized in init_comparisons. */ ! 106: ! 107: #define DEFTREECODE(SYM, NAME, TYPE, LENGTH) 0, ! 108: ! 109: static char comparison_code[] = { ! 110: #include "tree.def" ! 111: }; ! 112: #undef DEFTREECODE ! 113: ! 114: /* This is run once per compilation. */ ! 115: ! 116: void ! 117: init_comparisons () ! 118: { ! 119: comparison_code[(int) EQ_EXPR] = 1; ! 120: comparison_code[(int) NE_EXPR] = 1; ! 121: comparison_code[(int) LT_EXPR] = 1; ! 122: comparison_code[(int) GT_EXPR] = 1; ! 123: comparison_code[(int) LE_EXPR] = 1; ! 124: comparison_code[(int) GE_EXPR] = 1; ! 125: } ! 126: ! 127: /* This is run at the start of compiling a function. */ ! 128: ! 129: void ! 130: init_expr () ! 131: { ! 132: init_queue (); ! 133: may_call_alloca = 0; ! 134: } ! 135: ! 136: /* Manage the queue of increment instructions to be output ! 137: for POSTINCREMENT_EXPR expressions, etc. */ ! 138: ! 139: static rtx pending_chain; ! 140: ! 141: /* Queue up to increment (or change) VAR later. BODY says how: ! 142: BODY should be the same thing you would pass to emit_insn ! 143: to increment right away. It will go to emit_insn later on. ! 144: ! 145: The value is a QUEUED expression to be used in place of VAR ! 146: where you want to guarantee the pre-incrementation value of VAR. */ ! 147: ! 148: static rtx ! 149: enqueue_insn (var, body) ! 150: rtx var, body; ! 151: { ! 152: pending_chain = gen_rtx (QUEUED, GET_MODE (var), ! 153: var, 0, 0, body, pending_chain); ! 154: return pending_chain; ! 155: } ! 156: ! 157: /* Use protect_from_queue to convert a QUEUED expression ! 158: into something that you can put immediately into an instruction. ! 159: If the queued incrementation has not happened yet, ! 160: protect_from_queue returns the variable itself. ! 161: If the incrementation has happened, protect_from_queue returns a temp ! 162: that contains a copy of the old value of the variable. ! 163: ! 164: Any time an rtx which might possibly be a QUEUED is to be put ! 165: into an instruction, it must be passed through protect_from_queue first. ! 166: QUEUED expressions are not meaningful in instructions. ! 167: ! 168: Do not pass a value through protect_from_queue and then hold ! 169: on to it for a while before putting it in an instruction! ! 170: If the queue is flushed in between, incorrect code will result. */ ! 171: ! 172: rtx ! 173: protect_from_queue (x, modify) ! 174: register rtx x; ! 175: int modify; ! 176: { ! 177: register RTX_CODE code = GET_CODE (x); ! 178: if (code != QUEUED) ! 179: { ! 180: /* A special hack for read access to (MEM (QUEUED ...)) ! 181: to facilitate use of autoincrement. ! 182: Make a copy of the contents of the memory location ! 183: rather than a copy of the address. */ ! 184: if (code == MEM && GET_CODE (XEXP (x, 0)) == QUEUED && !modify) ! 185: { ! 186: register rtx y = XEXP (x, 0); ! 187: XEXP (x, 0) = QUEUED_VAR (y); ! 188: if (QUEUED_INSN (y)) ! 189: { ! 190: register rtx temp = gen_reg_rtx (GET_MODE (x)); ! 191: emit_insn_before (gen_move_insn (temp, x), ! 192: QUEUED_INSN (y)); ! 193: return temp; ! 194: } ! 195: return x; ! 196: } ! 197: /* Otherwise, recursively protect the subexpressions of all ! 198: the kinds of rtx's that can contain a QUEUED. */ ! 199: if (code == MEM) ! 200: XEXP (x, 0) = protect_from_queue (XEXP (x, 0), 0); ! 201: else if (code == PLUS || code == MULT) ! 202: { ! 203: XEXP (x, 0) = protect_from_queue (XEXP (x, 0), 0); ! 204: XEXP (x, 1) = protect_from_queue (XEXP (x, 1), 0); ! 205: } ! 206: return x; ! 207: } ! 208: /* If the increment has not happened, use the variable itself. */ ! 209: if (QUEUED_INSN (x) == 0) ! 210: return QUEUED_VAR (x); ! 211: /* If the increment has happened and a pre-increment copy exists, ! 212: use that copy. */ ! 213: if (QUEUED_COPY (x) != 0) ! 214: return QUEUED_COPY (x); ! 215: /* The increment has happened but we haven't set up a pre-increment copy. ! 216: Set one up now, and use it. */ ! 217: QUEUED_COPY (x) = gen_reg_rtx (GET_MODE (QUEUED_VAR (x))); ! 218: emit_insn_before (gen_move_insn (QUEUED_COPY (x), QUEUED_VAR (x)), ! 219: QUEUED_INSN (x)); ! 220: return QUEUED_COPY (x); ! 221: } ! 222: ! 223: /* Return nonzero if X contains a QUEUED expression: ! 224: if it contains anything that will be altered by a queued increment. */ ! 225: ! 226: static int ! 227: queued_subexp_p (x) ! 228: rtx x; ! 229: { ! 230: register enum rtx_code code = GET_CODE (x); ! 231: switch (code) ! 232: { ! 233: case QUEUED: ! 234: return 1; ! 235: case MEM: ! 236: return queued_subexp_p (XEXP (x, 0)); ! 237: case MULT: ! 238: case PLUS: ! 239: case MINUS: ! 240: return queued_subexp_p (XEXP (x, 0)) ! 241: || queued_subexp_p (XEXP (x, 1)); ! 242: } ! 243: return 0; ! 244: } ! 245: ! 246: /* Perform all the pending incrementations. */ ! 247: ! 248: void ! 249: emit_queue () ! 250: { ! 251: register rtx p; ! 252: while (p = pending_chain) ! 253: { ! 254: QUEUED_INSN (p) = emit_insn (QUEUED_BODY (p)); ! 255: pending_chain = QUEUED_NEXT (p); ! 256: } ! 257: } ! 258: ! 259: static void ! 260: init_queue () ! 261: { ! 262: if (pending_chain) ! 263: abort (); ! 264: } ! 265: ! 266: /* Copy data from FROM to TO, where the machine modes are not the same. ! 267: Both modes may be integer, or both may be floating. ! 268: UNSIGNEDP should be nonzero if FROM is an unsigned type. ! 269: This causes zero-extension instead of sign-extension. */ ! 270: ! 271: void ! 272: convert_move (to, from, unsignedp) ! 273: register rtx to, from; ! 274: int unsignedp; ! 275: { ! 276: enum machine_mode to_mode = GET_MODE (to); ! 277: enum machine_mode from_mode = GET_MODE (from); ! 278: int to_real = to_mode == SFmode || to_mode == DFmode; ! 279: int from_real = from_mode == SFmode || from_mode == DFmode; ! 280: int extending = (int) to_mode > (int) from_mode; ! 281: ! 282: to = protect_from_queue (to, 1); ! 283: from = protect_from_queue (from, 0); ! 284: ! 285: if (to_real != from_real) ! 286: abort (); ! 287: ! 288: if (to_mode == from_mode ! 289: || (from_mode == VOIDmode && CONSTANT_P (from))) ! 290: { ! 291: emit_move_insn (to, from); ! 292: return; ! 293: } ! 294: ! 295: if (to_real) ! 296: { ! 297: #ifdef HAVE_extendsfdf2 ! 298: if (HAVE_extendsfdf2 && extending) ! 299: { ! 300: emit_unop_insn (CODE_FOR_extendsfdf2, to, from, UNKNOWN); ! 301: return; ! 302: } ! 303: #endif ! 304: #ifdef HAVE_truncdfsf2 ! 305: if (HAVE_truncdfsf2 && ! extending) ! 306: { ! 307: emit_unop_insn (CODE_FOR_truncdfsf2, to, from, UNKNOWN); ! 308: return; ! 309: } ! 310: #endif ! 311: emit_library_call (gen_rtx (SYMBOL_REF, Pmode, (extending ! 312: ? "_extendsfdf2" ! 313: : "_truncdfsf2")), ! 314: GET_MODE (to), 1, ! 315: from, (extending ? SFmode : DFmode)); ! 316: emit_move_insn (to, hard_libcall_value (GET_MODE (to))); ! 317: return; ! 318: } ! 319: ! 320: /* Now both modes are integers. */ ! 321: ! 322: if (to_mode == DImode) ! 323: { ! 324: emit_insn (gen_rtx (CLOBBER, VOIDmode, to)); ! 325: ! 326: if (unsignedp) ! 327: { ! 328: convert_move (gen_lowpart (SImode, to), from, unsignedp); ! 329: emit_clr_insn (gen_highpart (SImode, to)); ! 330: } ! 331: #ifdef HAVE_slt ! 332: else if (HAVE_slt && insn_operand_mode[(int) CODE_FOR_slt][0] == SImode) ! 333: { ! 334: convert_move (gen_lowpart (SImode, to), from, unsignedp); ! 335: emit_insn (gen_slt (gen_highpart (SImode, to))); ! 336: } ! 337: #endif ! 338: else ! 339: { ! 340: register rtx label = gen_label_rtx (); ! 341: ! 342: emit_clr_insn (gen_highpart (SImode, to)); ! 343: convert_move (gen_lowpart (SImode, to), from, unsignedp); ! 344: emit_cmp_insn (gen_lowpart (SImode, to), ! 345: gen_rtx (CONST_INT, VOIDmode, 0), ! 346: 0, 0); ! 347: emit_jump_insn (gen_bge (label)); ! 348: expand_unop (SImode, one_cmpl_optab, ! 349: gen_highpart (SImode, to), gen_highpart (SImode, to), ! 350: 1); ! 351: emit_label (label); ! 352: } ! 353: return; ! 354: } ! 355: ! 356: if (from_mode == DImode) ! 357: { ! 358: convert_move (to, gen_lowpart (SImode, from), 0); ! 359: return; ! 360: } ! 361: ! 362: /* Now follow all the conversions between integers ! 363: no more than a word long. */ ! 364: ! 365: /* For truncation, usually we can just refer to FROM in a narrower mode. */ ! 366: if (GET_MODE_BITSIZE (to_mode) < GET_MODE_BITSIZE (from_mode) ! 367: && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (to_mode), ! 368: GET_MODE_BITSIZE (from_mode)) ! 369: && ((GET_CODE (from) == MEM ! 370: && ! mode_dependent_address_p (XEXP (from, 0))) ! 371: || GET_CODE (from) == REG)) ! 372: { ! 373: emit_move_insn (to, gen_lowpart (to_mode, from)); ! 374: return; ! 375: } ! 376: ! 377: if (to_mode == SImode && from_mode == HImode) ! 378: { ! 379: if (unsignedp) ! 380: { ! 381: #ifdef HAVE_zero_extendhisi2 ! 382: if (HAVE_zero_extendhisi2) ! 383: emit_unop_insn (CODE_FOR_zero_extendhisi2, to, from, ZERO_EXTEND); ! 384: else ! 385: #endif ! 386: abort (); ! 387: } ! 388: else ! 389: { ! 390: #ifdef HAVE_extendhisi2 ! 391: if (HAVE_extendhisi2) ! 392: emit_unop_insn (CODE_FOR_extendhisi2, to, from, SIGN_EXTEND); ! 393: else ! 394: #endif ! 395: abort (); ! 396: } ! 397: return; ! 398: } ! 399: ! 400: if (to_mode == SImode && from_mode == QImode) ! 401: { ! 402: if (unsignedp) ! 403: { ! 404: #ifdef HAVE_zero_extendqisi2 ! 405: if (HAVE_zero_extendqisi2) ! 406: { ! 407: emit_unop_insn (CODE_FOR_zero_extendqisi2, to, from, ZERO_EXTEND); ! 408: return; ! 409: } ! 410: #endif ! 411: #if defined (HAVE_zero_extendqihi2) && defined (HAVE_extendhisi2) ! 412: if (HAVE_zero_extendqihi2 && HAVE_extendhisi2) ! 413: { ! 414: register rtx temp = gen_reg_rtx (HImode); ! 415: emit_unop_insn (CODE_FOR_zero_extendqihi2, temp, from, ZERO_EXTEND); ! 416: emit_unop_insn (CODE_FOR_extendhisi2, to, temp, SIGN_EXTEND); ! 417: return; ! 418: } ! 419: #endif ! 420: } ! 421: else ! 422: { ! 423: #ifdef HAVE_extendqisi2 ! 424: if (HAVE_extendqisi2) ! 425: { ! 426: emit_unop_insn (CODE_FOR_extendqisi2, to, from, SIGN_EXTEND); ! 427: return; ! 428: } ! 429: #endif ! 430: #if defined (HAVE_extendqihi2) && defined (HAVE_extendhisi2) ! 431: if (HAVE_extendqihi2 && HAVE_extendhisi2) ! 432: { ! 433: register rtx temp = gen_reg_rtx (HImode); ! 434: emit_unop_insn (CODE_FOR_extendqihi2, temp, from, SIGN_EXTEND); ! 435: emit_unop_insn (CODE_FOR_extendhisi2, to, temp, SIGN_EXTEND); ! 436: return; ! 437: } ! 438: #endif ! 439: } ! 440: abort (); ! 441: } ! 442: ! 443: if (to_mode == HImode && from_mode == QImode) ! 444: { ! 445: if (unsignedp) ! 446: { ! 447: #ifdef HAVE_zero_extendqihi2 ! 448: if (HAVE_zero_extendqihi2) ! 449: { ! 450: emit_unop_insn (CODE_FOR_zero_extendqihi2, to, from, ZERO_EXTEND); ! 451: return; ! 452: } ! 453: #endif ! 454: } ! 455: else ! 456: { ! 457: #ifdef HAVE_extendqihi2 ! 458: if (HAVE_extendqihi2) ! 459: { ! 460: emit_unop_insn (CODE_FOR_extendqihi2, to, from, SIGN_EXTEND); ! 461: return; ! 462: } ! 463: #endif ! 464: } ! 465: abort (); ! 466: } ! 467: ! 468: /* Now we are truncating an integer to a smaller one. ! 469: If the result is a temporary, we might as well just copy it, ! 470: since only the low-order part of the result needs to be valid ! 471: and it is valid with no change. */ ! 472: ! 473: if (GET_CODE (to) == REG) ! 474: { ! 475: if (GET_CODE (from) == REG) ! 476: { ! 477: emit_move_insn (to, gen_lowpart (GET_MODE (to), from)); ! 478: return; ! 479: } ! 480: else if (GET_CODE (from) == SUBREG) ! 481: { ! 482: from = copy_rtx (from); ! 483: /* This is safe since FROM is not more than one word. */ ! 484: PUT_MODE (from, GET_MODE (to)); ! 485: emit_move_insn (to, from); ! 486: return; ! 487: } ! 488: #ifndef BYTES_BIG_ENDIAN ! 489: else if (GET_CODE (from) == MEM) ! 490: { ! 491: register rtx addr = XEXP (from, 0); ! 492: if (memory_address_p (GET_MODE (to), addr)) ! 493: { ! 494: emit_move_insn (to, gen_rtx (MEM, GET_MODE (to), addr)); ! 495: return; ! 496: } ! 497: } ! 498: #endif /* not BYTES_BIG_ENDIAN */ ! 499: } ! 500: ! 501: if (from_mode == SImode && to_mode == HImode) ! 502: { ! 503: #ifdef HAVE_truncsihi2 ! 504: if (HAVE_truncsihi2) ! 505: { ! 506: emit_unop_insn (CODE_FOR_truncsihi2, to, from, UNKNOWN); ! 507: return; ! 508: } ! 509: #endif ! 510: abort (); ! 511: } ! 512: ! 513: if (from_mode == SImode && to_mode == QImode) ! 514: { ! 515: #ifdef HAVE_truncsiqi2 ! 516: if (HAVE_truncsiqi2) ! 517: { ! 518: emit_unop_insn (CODE_FOR_truncsiqi2, to, from, UNKNOWN); ! 519: return; ! 520: } ! 521: #endif ! 522: abort (); ! 523: } ! 524: ! 525: if (from_mode == HImode && to_mode == QImode) ! 526: { ! 527: #ifdef HAVE_trunchiqi2 ! 528: if (HAVE_trunchiqi2) ! 529: { ! 530: emit_unop_insn (CODE_FOR_trunchiqi2, to, from, UNKNOWN); ! 531: return; ! 532: } ! 533: #endif ! 534: abort (); ! 535: } ! 536: ! 537: /* Mode combination is not recognized. */ ! 538: abort (); ! 539: } ! 540: ! 541: /* Return an rtx for a value that would result ! 542: from converting X to mode MODE. ! 543: Both X and MODE may be floating, or both integer. ! 544: UNSIGNEDP is nonzero if X is an unsigned value. ! 545: This can be done by referring to a part of X in place ! 546: or by copying to a new temporary with conversion. */ ! 547: ! 548: rtx ! 549: convert_to_mode (mode, x, unsignedp) ! 550: enum machine_mode mode; ! 551: rtx x; ! 552: int unsignedp; ! 553: { ! 554: register rtx temp; ! 555: if (mode == GET_MODE (x)) ! 556: return x; ! 557: if (integer_mode_p (mode) ! 558: && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (GET_MODE (x))) ! 559: return gen_lowpart (mode, x); ! 560: temp = gen_reg_rtx (mode); ! 561: convert_move (temp, x, unsignedp); ! 562: return temp; ! 563: } ! 564: ! 565: int ! 566: integer_mode_p (mode) ! 567: enum machine_mode mode; ! 568: { ! 569: return (int) mode > (int) VOIDmode && (int) mode <= (int) TImode; ! 570: } ! 571: ! 572: /* Generate several move instructions to copy LEN bytes ! 573: from block FROM to block TO. (These are MEM rtx's with BLKmode). ! 574: The caller must pass FROM and TO ! 575: through protect_from_queue before calling. ! 576: ALIGN (in bytes) is maximum alignment we can assume. */ ! 577: ! 578: struct move_by_pieces ! 579: { ! 580: rtx to; ! 581: rtx to_addr; ! 582: int autinc_to; ! 583: int explicit_inc_to; ! 584: rtx from; ! 585: rtx from_addr; ! 586: int autinc_from; ! 587: int explicit_inc_from; ! 588: int len; ! 589: int offset; ! 590: int reverse; ! 591: }; ! 592: ! 593: static void ! 594: move_by_pieces (to, from, len, align) ! 595: rtx to, from; ! 596: int len, align; ! 597: { ! 598: struct move_by_pieces data; ! 599: rtx to_addr = XEXP (to, 0), from_addr = XEXP (from, 0); ! 600: ! 601: data.offset = 0; ! 602: data.to_addr = to_addr; ! 603: data.from_addr = from_addr; ! 604: data.to = to; ! 605: data.from = from; ! 606: data.autinc_to ! 607: = (GET_CODE (to_addr) == PRE_INC || GET_CODE (to_addr) == PRE_DEC ! 608: || GET_CODE (to_addr) == POST_INC || GET_CODE (to_addr) == POST_DEC); ! 609: data.autinc_from ! 610: = (GET_CODE (from_addr) == PRE_INC || GET_CODE (from_addr) == PRE_DEC ! 611: || GET_CODE (from_addr) == POST_INC ! 612: || GET_CODE (from_addr) == POST_DEC); ! 613: ! 614: data.explicit_inc_from = 0; ! 615: data.explicit_inc_to = 0; ! 616: data.reverse ! 617: = (GET_CODE (to_addr) == PRE_DEC || GET_CODE (to_addr) == POST_DEC); ! 618: if (data.reverse) data.offset = len; ! 619: data.len = len; ! 620: ! 621: /* If copying requires more than two move insns, ! 622: copy addresses to registers (to make displacements shorter) ! 623: and use post-increment if available. */ ! 624: if (!(data.autinc_from && data.autinc_to) ! 625: && move_by_pieces_ninsns (len, align) > 2) ! 626: { ! 627: #ifdef HAVE_PRE_DECREMENT ! 628: if (data.reverse && ! data.autinc_from) ! 629: { ! 630: data.from_addr = copy_addr_to_reg (plus_constant (from_addr, len)); ! 631: data.autinc_from = 1; ! 632: data.explicit_inc_from = -1; ! 633: } ! 634: #endif ! 635: #ifdef HAVE_POST_INCREMENT ! 636: if (! data.autinc_from) ! 637: { ! 638: data.from_addr = copy_addr_to_reg (from_addr); ! 639: data.autinc_from = 1; ! 640: data.explicit_inc_from = 1; ! 641: } ! 642: #endif ! 643: if (!data.autinc_from && CONSTANT_P (from_addr)) ! 644: data.from_addr = copy_addr_to_reg (from_addr); ! 645: #ifdef HAVE_PRE_DECREMENT ! 646: if (data.reverse && ! data.autinc_to) ! 647: { ! 648: data.to_addr = copy_addr_to_reg (plus_constant (to_addr, len)); ! 649: data.autinc_to = 1; ! 650: data.explicit_inc_to = -1; ! 651: } ! 652: #endif ! 653: #ifdef HAVE_POST_INCREMENT ! 654: if (! data.reverse && ! data.autinc_to) ! 655: { ! 656: data.to_addr = copy_addr_to_reg (to_addr); ! 657: data.autinc_to = 1; ! 658: data.explicit_inc_to = 1; ! 659: } ! 660: #endif ! 661: if (!data.autinc_to && CONSTANT_P (to_addr)) ! 662: data.to_addr = copy_addr_to_reg (to_addr); ! 663: } ! 664: ! 665: #ifdef STRICT_ALIGNMENT ! 666: if (align > MOVE_MAX || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT) ! 667: align = MOVE_MAX; ! 668: #else ! 669: align = MOVE_MAX; ! 670: #endif ! 671: ! 672: #ifdef HAVE_movti ! 673: if (HAVE_movti && align >= GET_MODE_SIZE (TImode)) ! 674: move_by_pieces_1 (gen_movti, TImode, &data); ! 675: #endif ! 676: #ifdef HAVE_movdi ! 677: if (HAVE_movdi && align >= GET_MODE_SIZE (DImode)) ! 678: move_by_pieces_1 (gen_movdi, DImode, &data); ! 679: #endif ! 680: #ifdef HAVE_movsi ! 681: if (align >= GET_MODE_SIZE (SImode)) ! 682: move_by_pieces_1 (gen_movsi, SImode, &data); ! 683: #endif ! 684: #ifdef HAVE_movhi ! 685: if (HAVE_movhi && align >= GET_MODE_SIZE (HImode)) ! 686: move_by_pieces_1 (gen_movhi, HImode, &data); ! 687: #endif ! 688: #ifdef HAVE_movqi ! 689: move_by_pieces_1 (gen_movqi, QImode, &data); ! 690: #else ! 691: movqi instruction required in machine description ! 692: #endif ! 693: } ! 694: ! 695: /* Return number of insns required to move L bytes by pieces. ! 696: ALIGN (in bytes) is maximum alignment we can assume. */ ! 697: ! 698: static int ! 699: move_by_pieces_ninsns (l, align) ! 700: unsigned int l; ! 701: int align; ! 702: { ! 703: register int n_insns = 0; ! 704: ! 705: #ifdef STRICT_ALIGNMENT ! 706: if (align > MOVE_MAX || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT) ! 707: align = MOVE_MAX; ! 708: #else ! 709: align = MOVE_MAX; ! 710: #endif ! 711: ! 712: #ifdef HAVE_movti ! 713: if (HAVE_movti && align >= GET_MODE_SIZE (TImode)) ! 714: n_insns += l / GET_MODE_SIZE (TImode), l %= GET_MODE_SIZE (TImode); ! 715: #endif ! 716: #ifdef HAVE_movdi ! 717: if (HAVE_movdi && align >= GET_MODE_SIZE (DImode)) ! 718: n_insns += l / GET_MODE_SIZE (DImode), l %= GET_MODE_SIZE (DImode); ! 719: #endif ! 720: #ifdef HAVE_movsi ! 721: if (HAVE_movsi && align >= GET_MODE_SIZE (SImode)) ! 722: n_insns += l / GET_MODE_SIZE (SImode), l %= GET_MODE_SIZE (SImode); ! 723: #endif ! 724: #ifdef HAVE_movhi ! 725: if (HAVE_movhi && align >= GET_MODE_SIZE (HImode)) ! 726: n_insns += l / GET_MODE_SIZE (HImode), l %= GET_MODE_SIZE (HImode); ! 727: #endif ! 728: n_insns += l; ! 729: ! 730: return n_insns; ! 731: } ! 732: ! 733: /* Subroutine of move_by_pieces. Move as many bytes as appropriate ! 734: with move instructions for mode MODE. GENFUN is the gen_... function ! 735: to make a move insn for that mode. DATA has all the other info. */ ! 736: ! 737: static void ! 738: move_by_pieces_1 (genfun, mode, data) ! 739: rtx (*genfun) (); ! 740: enum machine_mode mode; ! 741: struct move_by_pieces *data; ! 742: { ! 743: register int size = GET_MODE_SIZE (mode); ! 744: register rtx to1, from1; ! 745: ! 746: #define add_offset(FLAG,X) \ ! 747: (FLAG ? (X) : plus_constant ((X), data->offset)) ! 748: ! 749: while (data->len >= size) ! 750: { ! 751: if (data->reverse) data->offset -= size; ! 752: ! 753: to1 = change_address (data->to, mode, ! 754: add_offset (data->autinc_to, data->to_addr)); ! 755: from1 = change_address (data->from, mode, ! 756: add_offset (data->autinc_from, data->from_addr)); ! 757: ! 758: #ifdef HAVE_PRE_DECREMENT ! 759: if (data->explicit_inc_to < 0) ! 760: emit_insn (gen_sub2_insn (data->to_addr, ! 761: gen_rtx (CONST_INT, VOIDmode, size))); ! 762: if (data->explicit_inc_from < 0) ! 763: emit_insn (gen_sub2_insn (data->from_addr, ! 764: gen_rtx (CONST_INT, VOIDmode, size))); ! 765: #endif ! 766: ! 767: emit_insn (genfun (to1, from1)); ! 768: #ifdef HAVE_POST_INCREMENT ! 769: if (data->explicit_inc_to > 0) ! 770: emit_insn (gen_add2_insn (data->to_addr, ! 771: gen_rtx (CONST_INT, VOIDmode, size))); ! 772: if (data->explicit_inc_from > 0) ! 773: emit_insn (gen_add2_insn (data->from_addr, ! 774: gen_rtx (CONST_INT, VOIDmode, size))); ! 775: #endif ! 776: ! 777: if (! data->reverse) data->offset += size; ! 778: ! 779: data->len -= size; ! 780: } ! 781: } ! 782: ! 783: /* Emit code to move a block Y to a block X. ! 784: This may be done with string-move instructions, ! 785: with multiple scalar move instructions, or with a library call. ! 786: ! 787: Both X and Y must be MEM rtx's (perhaps inside VOLATILE) ! 788: with mode BLKmode. ! 789: SIZE is an rtx that says how long they are. ! 790: ALIGN is the maximum alignment we can assume they have, ! 791: measured in bytes. */ ! 792: ! 793: static void ! 794: emit_block_move (x, y, size, align) ! 795: rtx x, y; ! 796: rtx size; ! 797: int align; ! 798: { ! 799: if (GET_MODE (x) != BLKmode) ! 800: abort (); ! 801: ! 802: if (GET_MODE (y) != BLKmode) ! 803: abort (); ! 804: ! 805: x = protect_from_queue (x, 1); ! 806: y = protect_from_queue (y, 0); ! 807: ! 808: if (GET_CODE (x) != MEM) ! 809: abort (); ! 810: if (GET_CODE (y) != MEM) ! 811: abort (); ! 812: if (size == 0) ! 813: abort (); ! 814: ! 815: if (GET_CODE (size) == CONST_INT ! 816: && (move_by_pieces_ninsns ((unsigned) INTVAL (size), align) ! 817: < MOVE_RATIO)) ! 818: move_by_pieces (x, y, INTVAL (size), align); ! 819: else ! 820: { ! 821: #ifdef HAVE_movstrsi ! 822: if (HAVE_movstrsi) ! 823: { ! 824: emit_insn (gen_movstrsi (x, y, size)); ! 825: return; ! 826: } ! 827: #endif ! 828: #ifdef HAVE_movstrhi ! 829: if (HAVE_movstrhi ! 830: && GET_CODE (size) == CONST_INT ! 831: && ((unsigned) INTVAL (size) ! 832: < (1 << (GET_MODE_SIZE (HImode) * BITS_PER_UNIT - 1)))) ! 833: { ! 834: emit_insn (gen_movstrhi (x, y, size)); ! 835: return; ! 836: } ! 837: #endif ! 838: ! 839: #ifdef TARGET_MEM_FUNCTIONS ! 840: emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memcpy"), ! 841: VOIDmode, 3, XEXP (x, 0), Pmode, ! 842: XEXP (y, 0), Pmode, ! 843: size, Pmode); ! 844: #else ! 845: emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "bcopy"), ! 846: VOIDmode, 3, XEXP (y, 0), Pmode, ! 847: XEXP (x, 0), Pmode, ! 848: size, Pmode); ! 849: #endif ! 850: } ! 851: } ! 852: ! 853: /* Copy all or part of a BLKmode value X into registers starting at REGNO. ! 854: The number of registers to be filled is NREGS. */ ! 855: ! 856: static void ! 857: move_block_to_reg (regno, x, nregs) ! 858: int regno; ! 859: rtx x; ! 860: int nregs; ! 861: { ! 862: int i; ! 863: if (GET_CODE (x) == CONST_DOUBLE && x != dconst0_rtx) ! 864: x = force_const_double_mem (x); ! 865: for (i = 0; i < nregs; i++) ! 866: { ! 867: if (GET_CODE (x) == REG) ! 868: emit_move_insn (gen_rtx (REG, SImode, regno + i), ! 869: gen_rtx (SUBREG, SImode, x, i)); ! 870: else if (x == dconst0_rtx) ! 871: emit_move_insn (gen_rtx (REG, SImode, regno + i), ! 872: const0_rtx); ! 873: else ! 874: emit_move_insn (gen_rtx (REG, SImode, regno + i), ! 875: gen_rtx (MEM, SImode, ! 876: plus_constant (XEXP (x, 0), ! 877: i * GET_MODE_SIZE (SImode)))); ! 878: } ! 879: } ! 880: ! 881: /* Copy all or part of a BLKmode value X out of registers starting at REGNO. ! 882: The number of registers to be filled is NREGS. */ ! 883: ! 884: void ! 885: move_block_from_reg (regno, x, nregs) ! 886: int regno; ! 887: rtx x; ! 888: int nregs; ! 889: { ! 890: int i; ! 891: for (i = 0; i < nregs; i++) ! 892: { ! 893: if (GET_CODE (x) == REG) ! 894: emit_move_insn (gen_rtx (SUBREG, SImode, x, i), ! 895: gen_rtx (REG, SImode, regno + i)); ! 896: else ! 897: emit_move_insn (gen_rtx (MEM, SImode, ! 898: plus_constant (XEXP (x, 0), ! 899: i * GET_MODE_SIZE (SImode))), ! 900: gen_rtx (REG, SImode, regno + i)); ! 901: } ! 902: } ! 903: ! 904: /* Mark NREGS consecutive regs, starting at REGNO, as being live now. */ ! 905: ! 906: static void ! 907: use_regs (regno, nregs) ! 908: int regno; ! 909: int nregs; ! 910: { ! 911: int i; ! 912: for (i = 0; i < nregs; i++) ! 913: emit_insn (gen_rtx (USE, VOIDmode, gen_rtx (REG, SImode, regno + i))); ! 914: } ! 915: ! 916: /* Write zeros through the storage of OBJECT. ! 917: If OBJECT has BLKmode, SIZE is its length in bytes. */ ! 918: ! 919: void ! 920: clear_storage (object, size) ! 921: rtx object; ! 922: int size; ! 923: { ! 924: if (GET_MODE (object) == BLKmode) ! 925: { ! 926: #ifdef TARGET_MEM_FUNCTIONS ! 927: emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memset"), ! 928: VOIDmode, 3, ! 929: XEXP (object, 0), Pmode, const0_rtx, Pmode, ! 930: gen_rtx (CONST_INT, VOIDmode, size), Pmode); ! 931: #else ! 932: emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "bzero"), ! 933: VOIDmode, 2, ! 934: XEXP (object, 0), Pmode, ! 935: gen_rtx (CONST_INT, VOIDmode, size), Pmode); ! 936: #endif ! 937: } ! 938: else ! 939: emit_move_insn (object, const0_rtx, 0); ! 940: } ! 941: ! 942: /* Generate code to copy Y into X. ! 943: Both Y and X must have the same mode, except that ! 944: Y can be a constant with VOIDmode. ! 945: This mode cannot be BLKmode; use emit_block_move for that. ! 946: ! 947: Return the last instruction emitted. */ ! 948: ! 949: rtx ! 950: emit_move_insn (x, y) ! 951: rtx x, y; ! 952: { ! 953: enum machine_mode mode = GET_MODE (x); ! 954: x = protect_from_queue (x, 1); ! 955: y = protect_from_queue (y, 0); ! 956: ! 957: if ((CONSTANT_P (y) || GET_CODE (y) == CONST_DOUBLE) ! 958: && ! LEGITIMATE_CONSTANT_P (y)) ! 959: y = force_const_mem (mode, y); ! 960: ! 961: if (mode == BLKmode) ! 962: abort (); ! 963: if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) ! 964: return ! 965: emit_insn (GEN_FCN (mov_optab->handlers[(int) mode].insn_code) (x, y)); ! 966: #if 0 ! 967: /* It turns out you get much better optimization (in cse and flow) ! 968: if you define movdi and movdf instruction patterns ! 969: even if they must turn into multiple assembler instructions. */ ! 970: else if (GET_MODE_SIZE (mode) >= GET_MODE_SIZE (SImode)) ! 971: { ! 972: register int count = GET_MODE_SIZE (mode) / GET_MODE_SIZE (SImode); ! 973: register int i; ! 974: if (GET_CODE (y) == CONST_DOUBLE && y != dconst0_rtx) ! 975: y = force_const_double_mem (y); ! 976: for (i = 0; i < count; i++) ! 977: { ! 978: rtx x1, y1; ! 979: if (GET_CODE (x) == REG) ! 980: x1 = gen_rtx (SUBREG, SImode, x, i); ! 981: else ! 982: x1 = gen_rtx (MEM, SImode, ! 983: memory_address (SImode, ! 984: plus_constant (XEXP (x, 0), ! 985: i * GET_MODE_SIZE (SImode)))); ! 986: if (GET_CODE (y) == REG) ! 987: y1 = gen_rtx (SUBREG, SImode, y, i); ! 988: else if (y == dconst0_rtx) ! 989: y1 = const0_rtx; ! 990: else ! 991: y1 = gen_rtx (MEM, SImode, ! 992: memory_address (SImode, ! 993: plus_constant (XEXP (y, 0), ! 994: i * GET_MODE_SIZE (SImode)))); ! 995: emit_insn (gen_movsi (protect_from_queue (x1, 1), protect_from_queue (y1, 0))); ! 996: } ! 997: } ! 998: #endif ! 999: else ! 1000: abort (); ! 1001: } ! 1002: ! 1003: /* Pushing data onto the stack. */ ! 1004: ! 1005: /* Push a block of length SIZE (perhaps variable) ! 1006: and return an rtx to address the beginning of the block. ! 1007: Note that it is not possible for the value returned to be a QUEUED. */ ! 1008: ! 1009: static rtx ! 1010: push_block (size) ! 1011: rtx size; ! 1012: { ! 1013: register rtx temp; ! 1014: if (CONSTANT_P (size) || GET_CODE (size) == REG) ! 1015: anti_adjust_stack (size); ! 1016: else ! 1017: anti_adjust_stack (copy_to_mode_reg (Pmode, size)); ! 1018: ! 1019: #ifdef STACK_GROWS_DOWNWARD ! 1020: temp = stack_pointer_rtx; ! 1021: #else ! 1022: temp = gen_rtx (PLUS, Pmode, ! 1023: stack_pointer_rtx, ! 1024: size); ! 1025: if (GET_CODE (size) != CONST_INT) ! 1026: temp = force_operand (temp, 0); ! 1027: #endif ! 1028: return memory_address (QImode, temp); ! 1029: } ! 1030: ! 1031: static rtx ! 1032: gen_push_operand () ! 1033: { ! 1034: return gen_rtx ( ! 1035: #ifdef STACK_GROWS_DOWNWARD ! 1036: PRE_DEC, ! 1037: #else ! 1038: PRE_INC, ! 1039: #endif ! 1040: Pmode, ! 1041: stack_pointer_rtx); ! 1042: } ! 1043: ! 1044: /* Generate code to push X onto the stack, assuming it has mode MODE. ! 1045: MODE is redundant except when X is a CONST_INT (since they don't ! 1046: carry mode info). ! 1047: SIZE is an rtx for the size of data to be copied (in bytes), ! 1048: needed only if X is BLKmode. ! 1049: ALIGN (in bytes) is maximum alignment we can assume. ! 1050: ! 1051: If PARTIAL is nonzero, then copy that many of the first words ! 1052: of X into registers starting with REG, and push the rest of X. ! 1053: The amount of space pushed is decreased by PARTIAL words, ! 1054: rounded *down* to a multiple of PARM_BOUNDARY. ! 1055: REG must be a hard register in this case. ! 1056: ! 1057: EXTRA is the amount in bytes of extra space to leave next to this arg. ! 1058: ! 1059: On a machine that lacks real push insns, ARGS_ADDR is the address of ! 1060: the bottom of the argument block for this call. We use indexing off there ! 1061: to store the arg. On machines with push insns, ARGS_ADDR is 0. ! 1062: ! 1063: ARGS_SO_FAR is the size of args previously pushed for this call. */ ! 1064: ! 1065: static void ! 1066: emit_push_insn (x, mode, size, align, partial, reg, extra, args_addr, args_so_far) ! 1067: register rtx x; ! 1068: enum machine_mode mode; ! 1069: rtx size; ! 1070: int align; ! 1071: int partial; ! 1072: rtx reg; ! 1073: int extra; ! 1074: rtx args_addr; ! 1075: rtx args_so_far; ! 1076: { ! 1077: rtx xinner; ! 1078: ! 1079: xinner = x = protect_from_queue (x, 0); ! 1080: ! 1081: /* If part should go in registers, copy that part ! 1082: into the appropriate registers. */ ! 1083: if (partial > 0) ! 1084: move_block_to_reg (REGNO (reg), x, partial); ! 1085: ! 1086: #ifdef STACK_GROWS_DOWNWARD ! 1087: if (extra && args_addr == 0) ! 1088: anti_adjust_stack (gen_rtx (CONST_INT, VOIDmode, extra)); ! 1089: #endif ! 1090: ! 1091: if (mode == BLKmode) ! 1092: { ! 1093: register rtx temp; ! 1094: int used = partial * UNITS_PER_WORD; ! 1095: int offset = used % (PARM_BOUNDARY / BITS_PER_UNIT); ! 1096: ! 1097: used -= used % (PARM_BOUNDARY / BITS_PER_UNIT); ! 1098: ! 1099: if (size == 0) ! 1100: abort (); ! 1101: ! 1102: if (partial != 0) ! 1103: xinner = change_address (xinner, BLKmode, ! 1104: plus_constant (XEXP (xinner, 0), used)); ! 1105: ! 1106: #ifdef PUSH_ROUNDING ! 1107: /* Do it with several push insns if that doesn't take lots of insns ! 1108: and if there is no difficulty with push insns that skip bytes ! 1109: on the stack for alignment purposes. */ ! 1110: if (args_addr == 0 ! 1111: && GET_CODE (size) == CONST_INT ! 1112: && args_addr == 0 ! 1113: && (move_by_pieces_ninsns ((unsigned) INTVAL (size) - used, align) ! 1114: < MOVE_RATIO) ! 1115: && PUSH_ROUNDING (INTVAL (size)) == INTVAL (size)) ! 1116: move_by_pieces (gen_rtx (MEM, BLKmode, gen_push_operand ()), xinner, ! 1117: INTVAL (size) - used, align); ! 1118: else ! 1119: #endif /* PUSH_ROUNDING */ ! 1120: { ! 1121: /* Otherwise make space on the stack and copy the data ! 1122: to the address of that space. */ ! 1123: ! 1124: /* First deduct part put into registers from the size we need. */ ! 1125: if (partial != 0) ! 1126: { ! 1127: if (GET_CODE (size) == CONST_INT) ! 1128: size = gen_rtx (CONST_INT, VOIDmode, INTVAL (size) - used); ! 1129: else ! 1130: size = expand_binop (GET_MODE (size), sub_optab, size, ! 1131: gen_rtx (CONST_INT, VOIDmode, used), ! 1132: 0, 0, OPTAB_LIB_WIDEN); ! 1133: } ! 1134: ! 1135: /* Get the address of the stack space. */ ! 1136: if (! args_addr) ! 1137: temp = push_block (size); ! 1138: else if (GET_CODE (args_so_far) == CONST_INT) ! 1139: temp = memory_address (BLKmode, ! 1140: plus_constant (args_addr, ! 1141: offset + INTVAL (args_so_far))); ! 1142: else ! 1143: temp = memory_address (BLKmode, ! 1144: plus_constant (gen_rtx (PLUS, Pmode, ! 1145: args_addr, args_so_far), ! 1146: offset)); ! 1147: ! 1148: ! 1149: /* TEMP is the address of the block. Copy the data there. */ ! 1150: if (GET_CODE (size) == CONST_INT ! 1151: && (move_by_pieces_ninsns ((unsigned) INTVAL (size), align) ! 1152: < MOVE_RATIO)) ! 1153: { ! 1154: move_by_pieces (gen_rtx (MEM, BLKmode, temp), xinner, ! 1155: INTVAL (size), align); ! 1156: return; ! 1157: } ! 1158: #ifdef HAVE_movstrsi ! 1159: if (HAVE_movstrsi) ! 1160: { ! 1161: emit_insn (gen_movstrsi (gen_rtx (MEM, BLKmode, temp), x, size)); ! 1162: return; ! 1163: } ! 1164: #endif ! 1165: #ifdef HAVE_movstrhi ! 1166: if (HAVE_movstrhi ! 1167: && GET_CODE (size) == CONST_INT ! 1168: && ((unsigned) INTVAL (size) ! 1169: < (1 << (GET_MODE_SIZE (HImode) * BITS_PER_UNIT - 1)))) ! 1170: { ! 1171: emit_insn (gen_movstrhi (gen_rtx (MEM, BLKmode, temp), ! 1172: x, size)); ! 1173: return; ! 1174: } ! 1175: #endif ! 1176: ! 1177: if (reg_mentioned_p (stack_pointer_rtx, temp)) ! 1178: { ! 1179: /* Correct TEMP so it holds what will be a description of ! 1180: the address to copy to, valid after one arg is pushed. */ ! 1181: #ifdef STACK_GROWS_DOWNWARD ! 1182: temp = plus_constant (temp, GET_MODE_SIZE (Pmode)); ! 1183: #else ! 1184: temp = plus_constant (temp, - GET_MODE_SIZE (Pmode)); ! 1185: #endif ! 1186: } ! 1187: ! 1188: /* Make current_args_size nonzero around the library call ! 1189: to force it to pop the bcopy-arguments right away. */ ! 1190: current_args_size += 1; ! 1191: #ifdef TARGET_MEM_FUNCTIONS ! 1192: emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memcpy"), ! 1193: VOIDmode, 3, temp, Pmode, XEXP (xinner, 0), Pmode, ! 1194: size, Pmode); ! 1195: #else ! 1196: emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "bcopy"), ! 1197: VOIDmode, 3, XEXP (xinner, 0), Pmode, temp, Pmode, ! 1198: size, Pmode); ! 1199: #endif ! 1200: current_args_size -= 1; ! 1201: } ! 1202: } ! 1203: else if (partial > 0) ! 1204: { ! 1205: int size = GET_MODE_SIZE (mode) / UNITS_PER_WORD; ! 1206: int i; ! 1207: int used = partial * UNITS_PER_WORD; ! 1208: /* # words of start of argument ! 1209: that we must make space for but need not store. */ ! 1210: int skip = partial % (PARM_BOUNDARY / BITS_PER_WORD); ! 1211: int args_offset = INTVAL (args_so_far); ! 1212: ! 1213: /* If we make space by pushing it, we might as well push ! 1214: the real data. Otherwise, we can leave SKIP nonzero ! 1215: and leave the space uninitialized. */ ! 1216: if (args_addr == 0) ! 1217: skip = 0; ! 1218: ! 1219: /* Deduct all the rest of PARTIAL words from SIZE in any case. ! 1220: This is space that we don't even allocate in the stack. */ ! 1221: used -= used % (PARM_BOUNDARY / BITS_PER_UNIT); ! 1222: size -= used / UNITS_PER_WORD; ! 1223: ! 1224: if (GET_CODE (x) == CONST_DOUBLE && x != dconst0_rtx) ! 1225: x = force_const_double_mem (x); ! 1226: ! 1227: #ifndef PUSH_ARGS_REVERSED ! 1228: for (i = skip; i < size; i++) ! 1229: #else ! 1230: for (i = size - 1; i >= skip; i--) ! 1231: #endif ! 1232: if (GET_CODE (x) == MEM) ! 1233: emit_push_insn (gen_rtx (MEM, SImode, ! 1234: plus_constant (XEXP (x, 0), ! 1235: i * UNITS_PER_WORD)), ! 1236: SImode, 0, align, 0, 0, 0, args_addr, ! 1237: gen_rtx (CONST_INT, VOIDmode, ! 1238: args_offset + i * UNITS_PER_WORD)); ! 1239: else if (GET_CODE (x) == REG) ! 1240: emit_push_insn (gen_rtx (SUBREG, SImode, x, i), ! 1241: SImode, 0, align, 0, 0, 0, args_addr, ! 1242: gen_rtx (CONST_INT, VOIDmode, ! 1243: args_offset + i * UNITS_PER_WORD)); ! 1244: else if (x == dconst0_rtx) ! 1245: emit_push_insn (const0_rtx, ! 1246: SImode, 0, align, 0, 0, 0, args_addr, ! 1247: gen_rtx (CONST_INT, VOIDmode, ! 1248: args_offset + i * UNITS_PER_WORD)); ! 1249: else ! 1250: abort (); ! 1251: } ! 1252: else ! 1253: { ! 1254: rtx addr; ! 1255: #ifdef PUSH_ROUNDING ! 1256: if (args_addr == 0) ! 1257: addr = gen_push_operand (); ! 1258: else ! 1259: #endif ! 1260: if (GET_CODE (args_so_far) == CONST_INT) ! 1261: addr ! 1262: = memory_address (mode, ! 1263: plus_constant (args_addr, INTVAL (args_so_far))); ! 1264: else ! 1265: addr = memory_address (mode, gen_rtx (PLUS, Pmode, args_addr, ! 1266: args_so_far)); ! 1267: ! 1268: emit_move_insn (gen_rtx (MEM, mode, addr), x); ! 1269: } ! 1270: ! 1271: #ifndef STACK_GROWS_DOWNWARD ! 1272: if (extra && args_addr == 0) ! 1273: anti_adjust_stack (gen_rtx (CONST_INT, VOIDmode, extra)); ! 1274: #endif ! 1275: } ! 1276: ! 1277: /* Output a library call to function FUN (a SYMBOL_REF rtx) ! 1278: for a value of mode OUTMODE ! 1279: with NARGS different arguments, passed as alternating rtx values ! 1280: and machine_modes to convert them to. ! 1281: The rtx values should have been passed through protect_from_queue already. */ ! 1282: ! 1283: void ! 1284: emit_library_call (va_alist) ! 1285: va_dcl ! 1286: { ! 1287: register va_list p; ! 1288: register int args_size = 0; ! 1289: register int argnum; ! 1290: enum machine_mode outmode; ! 1291: int nargs; ! 1292: rtx fun; ! 1293: rtx orgfun; ! 1294: int inc; ! 1295: int count; ! 1296: rtx *regvec; ! 1297: rtx argblock = 0; ! 1298: CUMULATIVE_ARGS args_so_far; ! 1299: struct arg { rtx value; enum machine_mode mode; }; ! 1300: struct arg *argvec; ! 1301: int old_args_size = current_args_size; ! 1302: ! 1303: va_start (p); ! 1304: orgfun = fun = va_arg (p, rtx); ! 1305: outmode = va_arg (p, enum machine_mode); ! 1306: nargs = va_arg (p, int); ! 1307: ! 1308: regvec = (rtx *) alloca (nargs * sizeof (rtx)); ! 1309: ! 1310: /* Copy all the libcall-arguments out of the varargs data ! 1311: and into a vector ARGVEC. */ ! 1312: argvec = (struct arg *) alloca (nargs * sizeof (struct arg)); ! 1313: for (count = 0; count < nargs; count++) ! 1314: { ! 1315: argvec[count].value = va_arg (p, rtx); ! 1316: argvec[count].mode = va_arg (p, enum machine_mode); ! 1317: } ! 1318: va_end (p); ! 1319: ! 1320: /* If we have no actual push instructions, make space for all the args ! 1321: right now. */ ! 1322: #ifndef PUSH_ROUNDING ! 1323: INIT_CUMULATIVE_ARGS (args_so_far, (tree)0); ! 1324: for (count = 0; count < nargs; count++) ! 1325: { ! 1326: register enum machine_mode mode = argvec[count].mode; ! 1327: register rtx reg; ! 1328: register int partial; ! 1329: ! 1330: reg = FUNCTION_ARG (args_so_far, mode, 0, 1); ! 1331: #ifdef FUNCTION_ARG_PARTIAL_NREGS ! 1332: partial = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode, 0, 1); ! 1333: #else ! 1334: partial = 0; ! 1335: #endif ! 1336: if (reg == 0 || partial != 0) ! 1337: args_size += GET_MODE_SIZE (mode); ! 1338: if (partial != 0) ! 1339: args_size -= partial * GET_MODE_SIZE (SImode); ! 1340: FUNCTION_ARG_ADVANCE (args_so_far, mode, 0, 1); ! 1341: } ! 1342: ! 1343: if (args_size != 0) ! 1344: argblock ! 1345: = push_block (round_push (gen_rtx (CONST_INT, VOIDmode, args_size))); ! 1346: #endif ! 1347: ! 1348: INIT_CUMULATIVE_ARGS (args_so_far, (tree)0); ! 1349: ! 1350: #ifdef PUSH_ARGS_REVERSED ! 1351: inc = -1; ! 1352: argnum = nargs - 1; ! 1353: #else ! 1354: inc = 1; ! 1355: argnum = 0; ! 1356: #endif ! 1357: args_size = 0; ! 1358: ! 1359: for (count = 0; count < nargs; count++, argnum += inc) ! 1360: { ! 1361: register enum machine_mode mode = argvec[argnum].mode; ! 1362: register rtx val = argvec[argnum].value; ! 1363: rtx reg; ! 1364: int partial; ! 1365: int arg_size; ! 1366: ! 1367: /* Convert the arg value to the mode the library wants. */ ! 1368: /* ??? It is wrong to do it here; must do it earlier ! 1369: where we know the signedness of the arg. */ ! 1370: if (GET_MODE (val) != mode && GET_MODE (val) != VOIDmode) ! 1371: { ! 1372: val = gen_reg_rtx (mode); ! 1373: convert_move (val, argvec[argnum].value, 0); ! 1374: } ! 1375: reg = FUNCTION_ARG (args_so_far, mode, 0, 1); ! 1376: regvec[argnum] = reg; ! 1377: #ifdef FUNCTION_ARG_PARTIAL_NREGS ! 1378: partial = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode, 0, 1); ! 1379: #else ! 1380: partial = 0; ! 1381: #endif ! 1382: ! 1383: if (reg != 0 && partial == 0) ! 1384: emit_move_insn (reg, val); ! 1385: else ! 1386: emit_push_insn (val, mode, 0, 0, partial, reg, 0, argblock, ! 1387: gen_rtx (CONST_INT, VOIDmode, args_size)); ! 1388: ! 1389: /* Compute size of stack space used by this argument. */ ! 1390: if (reg == 0 || partial != 0) ! 1391: arg_size = GET_MODE_SIZE (mode); ! 1392: else ! 1393: arg_size = 0; ! 1394: if (partial != 0) ! 1395: arg_size ! 1396: -= ((partial * UNITS_PER_WORD) ! 1397: / (PARM_BOUNDARY / BITS_PER_UNIT) ! 1398: * (PARM_BOUNDARY / BITS_PER_UNIT)); ! 1399: ! 1400: args_size += arg_size; ! 1401: current_args_size += arg_size; ! 1402: FUNCTION_ARG_ADVANCE (args_so_far, mode, 0, 1); ! 1403: } ! 1404: ! 1405: emit_queue (); ! 1406: ! 1407: fun = prepare_call_address (fun, 0); ! 1408: ! 1409: /* Any regs containing parms remain in use through the call. ! 1410: ??? This is not quite correct, since it doesn't indicate ! 1411: that they are in use immediately before the call insn. ! 1412: Currently that doesn't matter since explicitly-used regs ! 1413: won't be used for reloading. But if the reloader becomes smarter, ! 1414: this will have to change somehow. */ ! 1415: for (count = 0; count < nargs; count++) ! 1416: if (regvec[count] != 0) ! 1417: emit_insn (gen_rtx (USE, VOIDmode, regvec[count])); ! 1418: ! 1419: #ifdef STACK_BOUNDARY ! 1420: args_size = (args_size + STACK_BYTES - 1) / STACK_BYTES * STACK_BYTES; ! 1421: #endif ! 1422: ! 1423: /* Don't allow popping to be deferred, since then ! 1424: cse'ing of library calls could delete a call and leave the pop. */ ! 1425: current_args_size += 1; ! 1426: emit_call_1 (fun, get_identifier (XSTR (orgfun, 0)), args_size, ! 1427: FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1), ! 1428: outmode != VOIDmode ? hard_libcall_value (outmode) : 0, ! 1429: old_args_size + 1); ! 1430: current_args_size -= 1; ! 1431: } ! 1432: ! 1433: /* Expand an assignment that stores the value of FROM into TO. ! 1434: If WANT_VALUE is nonzero, return an rtx for the value of TO. ! 1435: (This may contain a QUEUED rtx.) ! 1436: Otherwise, the returned value is not meaningful. ! 1437: ! 1438: SUGGEST_REG is no longer actually used. ! 1439: It used to mean, copy the value through a register ! 1440: and return that register, if that is possible. ! 1441: But now we do this if WANT_VALUE. ! 1442: ! 1443: If the value stored is a constant, we return the constant. */ ! 1444: ! 1445: rtx ! 1446: expand_assignment (to, from, want_value, suggest_reg) ! 1447: tree to, from; ! 1448: int want_value; ! 1449: int suggest_reg; ! 1450: { ! 1451: register rtx to_rtx = 0; ! 1452: ! 1453: /* Don't crash if the lhs of the assignment was erroneous. */ ! 1454: ! 1455: if (TREE_CODE (to) == ERROR_MARK) ! 1456: return expand_expr (from, 0, VOIDmode, 0); ! 1457: ! 1458: /* Assignment of a structure component needs special treatment ! 1459: if the structure component's rtx is not simply a MEM. ! 1460: Assignment of an array element at a constant index ! 1461: has the same problem. */ ! 1462: ! 1463: if (TREE_CODE (to) == COMPONENT_REF ! 1464: || (TREE_CODE (to) == ARRAY_REF ! 1465: && TREE_CODE (TREE_OPERAND (to, 1)) == INTEGER_CST ! 1466: && TREE_CODE (TYPE_SIZE (TREE_TYPE (to))) == INTEGER_CST)) ! 1467: { ! 1468: register enum machine_mode mode1; ! 1469: int bitsize; ! 1470: int volstruct = 0; ! 1471: tree tem = to; ! 1472: int bitpos = 0; ! 1473: int unsignedp; ! 1474: ! 1475: if (TREE_CODE (to) == COMPONENT_REF) ! 1476: { ! 1477: tree field = TREE_OPERAND (to, 1); ! 1478: bitsize = TREE_INT_CST_LOW (DECL_SIZE (field)) * DECL_SIZE_UNIT (field); ! 1479: mode1 = DECL_MODE (TREE_OPERAND (to, 1)); ! 1480: unsignedp = TREE_UNSIGNED (field); ! 1481: } ! 1482: else ! 1483: { ! 1484: mode1 = TYPE_MODE (TREE_TYPE (to)); ! 1485: bitsize = GET_MODE_BITSIZE (mode1); ! 1486: unsignedp = TREE_UNSIGNED (TREE_TYPE (to)); ! 1487: } ! 1488: ! 1489: /* Compute cumulative bit-offset for nested component-refs ! 1490: and array-refs, and find the ultimate containing object. */ ! 1491: ! 1492: while (1) ! 1493: { ! 1494: if (TREE_CODE (tem) == COMPONENT_REF) ! 1495: { ! 1496: bitpos += DECL_OFFSET (TREE_OPERAND (tem, 1)); ! 1497: if (TREE_THIS_VOLATILE (tem)) ! 1498: volstruct = 1; ! 1499: } ! 1500: else if (TREE_CODE (tem) == ARRAY_REF ! 1501: && TREE_CODE (TREE_OPERAND (tem, 1)) == INTEGER_CST ! 1502: && TREE_CODE (TYPE_SIZE (TREE_TYPE (tem))) == INTEGER_CST) ! 1503: { ! 1504: bitpos += (TREE_INT_CST_LOW (TREE_OPERAND (tem, 1)) ! 1505: * TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (tem))) ! 1506: * TYPE_SIZE_UNIT (TREE_TYPE (tem))); ! 1507: } ! 1508: else ! 1509: break; ! 1510: tem = TREE_OPERAND (tem, 0); ! 1511: } ! 1512: ! 1513: /* If we are going to use store_bit_field and extract_bit_field, ! 1514: make sure to_rtx will be safe for multiple use. */ ! 1515: if (mode1 == BImode && want_value) ! 1516: tem = stabilize_reference (tem); ! 1517: ! 1518: to_rtx = expand_expr (tem, 0, VOIDmode, 0); ! 1519: ! 1520: return store_field (to_rtx, bitsize, bitpos, mode1, from, ! 1521: want_value ? TYPE_MODE (TREE_TYPE (to)) : VOIDmode, ! 1522: unsignedp); ! 1523: } ! 1524: ! 1525: /* Ordinary treatment. Expand TO to get a REG or MEM rtx. ! 1526: Don't re-expand if it was expanded already (in COMPONENT_REF case). */ ! 1527: ! 1528: if (to_rtx == 0) ! 1529: to_rtx = expand_expr (to, 0, VOIDmode, 0); ! 1530: ! 1531: /* Compute FROM and store the value in the rtx we got. */ ! 1532: ! 1533: return store_expr (from, to_rtx, want_value); ! 1534: } ! 1535: ! 1536: /* Generate code for computing expression EXP, ! 1537: and storing the value into TARGET. ! 1538: Returns TARGET or an equivalent value. ! 1539: TARGET may contain a QUEUED rtx. ! 1540: ! 1541: If SUGGEST_REG is nonzero, copy the value through a register ! 1542: and return that register, if that is possible. ! 1543: ! 1544: If the value stored is a constant, we return the constant. */ ! 1545: ! 1546: rtx ! 1547: store_expr (exp, target, suggest_reg) ! 1548: register tree exp; ! 1549: register rtx target; ! 1550: int suggest_reg; ! 1551: { ! 1552: register rtx temp; ! 1553: int dont_return_target = 0; ! 1554: ! 1555: /* Copying a non-constant CONSTRUCTOR needs special treatment. */ ! 1556: ! 1557: if (TREE_CODE (exp) == CONSTRUCTOR && ! TREE_LITERAL (exp)) ! 1558: { ! 1559: store_constructor (exp, target); ! 1560: return target; ! 1561: } ! 1562: ! 1563: if (suggest_reg && GET_CODE (target) == MEM && GET_MODE (target) != BLKmode) ! 1564: /* If target is in memory and caller wants value in a register instead, ! 1565: arrange that. Pass TARGET as target for expand_expr so that, ! 1566: if EXP is another assignment, SUGGEST_REG will be nonzero for it. ! 1567: We know expand_expr will not use the target in that case. */ ! 1568: { ! 1569: temp = expand_expr (exp, cse_not_expected ? 0 : target, ! 1570: GET_MODE (target), 0); ! 1571: if (GET_MODE (temp) != BLKmode && GET_MODE (temp) != VOIDmode) ! 1572: temp = copy_to_reg (temp); ! 1573: dont_return_target = 1; ! 1574: } ! 1575: else if (queued_subexp_p (target)) ! 1576: /* If target contains a postincrement, it is not safe ! 1577: to use as the returned value. It would access the wrong ! 1578: place by the time the queued increment gets output. ! 1579: So copy the value through a temporary and use that temp ! 1580: as the result. */ ! 1581: { ! 1582: temp = expand_expr (exp, 0, GET_MODE (target), 0); ! 1583: if (GET_MODE (temp) != BLKmode && GET_MODE (temp) != VOIDmode) ! 1584: temp = copy_to_reg (temp); ! 1585: dont_return_target = 1; ! 1586: } ! 1587: else ! 1588: { ! 1589: temp = expand_expr (exp, target, GET_MODE (target), 0); ! 1590: /* DO return TARGET if it's a specified hardware register. ! 1591: expand_return relies on this. */ ! 1592: if (!(target && GET_CODE (target) == REG ! 1593: && REGNO (target) < FIRST_PSEUDO_REGISTER) ! 1594: && (CONSTANT_P (temp) || GET_CODE (temp) == CONST_DOUBLE)) ! 1595: dont_return_target = 1; ! 1596: } ! 1597: ! 1598: /* If value was not generated in the target, store it there. */ ! 1599: ! 1600: if (temp != target && TREE_CODE (exp) != ERROR_MARK) ! 1601: { ! 1602: target = protect_from_queue (target, 1); ! 1603: if (GET_MODE (temp) != GET_MODE (target) ! 1604: && GET_MODE (temp) != VOIDmode) ! 1605: { ! 1606: int unsignedp = TREE_UNSIGNED (TREE_TYPE (exp)); ! 1607: if (dont_return_target) ! 1608: temp = convert_to_mode (GET_MODE (target), temp, unsignedp); ! 1609: else ! 1610: convert_move (target, temp, unsignedp); ! 1611: } ! 1612: ! 1613: else if (GET_MODE (temp) == BLKmode) ! 1614: emit_block_move (target, temp, expr_size (exp), ! 1615: TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT); ! 1616: else ! 1617: emit_move_insn (target, temp); ! 1618: } ! 1619: if (dont_return_target) ! 1620: return temp; ! 1621: return target; ! 1622: } ! 1623: ! 1624: /* Store the value of constructor EXP into the rtx TARGET. ! 1625: TARGET is either a REG or a MEM. */ ! 1626: ! 1627: static void ! 1628: store_constructor (exp, target) ! 1629: tree exp; ! 1630: rtx target; ! 1631: { ! 1632: if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE) ! 1633: { ! 1634: register tree elt; ! 1635: ! 1636: /* If the constructor has fewer fields than the structure, ! 1637: clear the whole structure first. */ ! 1638: ! 1639: if (list_length (CONSTRUCTOR_ELTS (exp)) ! 1640: != list_length (TYPE_FIELDS (TREE_TYPE (exp)))) ! 1641: clear_storage (target, int_size_in_bytes (TREE_TYPE (exp))); ! 1642: else ! 1643: /* Inform later passes that the old value is dead. */ ! 1644: emit_insn (gen_rtx (CLOBBER, VOIDmode, target)); ! 1645: ! 1646: /* Store each element of the constructor into ! 1647: the corresponding field of TARGET. */ ! 1648: ! 1649: for (elt = CONSTRUCTOR_ELTS (exp); elt; elt = TREE_CHAIN (elt)) ! 1650: { ! 1651: register tree field = TREE_PURPOSE (elt); ! 1652: register enum machine_mode mode; ! 1653: int bitsize; ! 1654: int bitpos; ! 1655: int unsignedp; ! 1656: ! 1657: bitsize = TREE_INT_CST_LOW (DECL_SIZE (field)) * DECL_SIZE_UNIT (field); ! 1658: mode = DECL_MODE (field); ! 1659: unsignedp = TREE_UNSIGNED (field); ! 1660: ! 1661: bitpos = DECL_OFFSET (field); ! 1662: ! 1663: store_field (target, bitsize, bitpos, mode, TREE_VALUE (elt), ! 1664: VOIDmode, 0); ! 1665: } ! 1666: } ! 1667: else if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE) ! 1668: { ! 1669: register tree elt; ! 1670: register int i; ! 1671: tree domain = TYPE_DOMAIN (TREE_TYPE (exp)); ! 1672: int minelt = TREE_INT_CST_LOW (TYPE_MIN_VALUE (domain)); ! 1673: int maxelt = TREE_INT_CST_LOW (TYPE_MAX_VALUE (domain)); ! 1674: tree elttype = TREE_TYPE (TREE_TYPE (exp)); ! 1675: ! 1676: /* If the constructor has fewer fields than the structure, ! 1677: clear the whole structure first. */ ! 1678: ! 1679: if (list_length (CONSTRUCTOR_ELTS (exp)) < maxelt - minelt + 1) ! 1680: clear_storage (target, maxelt - minelt + 1); ! 1681: else ! 1682: /* Inform later passes that the old value is dead. */ ! 1683: emit_insn (gen_rtx (CLOBBER, VOIDmode, target)); ! 1684: ! 1685: /* Store each element of the constructor into ! 1686: the corresponding element of TARGET, determined ! 1687: by counting the elements. */ ! 1688: for (elt = CONSTRUCTOR_ELTS (exp), i = 0; ! 1689: elt; ! 1690: elt = TREE_CHAIN (elt), i++) ! 1691: { ! 1692: register enum machine_mode mode; ! 1693: int bitsize; ! 1694: int bitpos; ! 1695: int unsignedp; ! 1696: ! 1697: mode = TYPE_MODE (elttype); ! 1698: bitsize = GET_MODE_BITSIZE (mode); ! 1699: unsignedp = TREE_UNSIGNED (elttype); ! 1700: ! 1701: bitpos = (i * TREE_INT_CST_LOW (TYPE_SIZE (elttype)) ! 1702: * TYPE_SIZE_UNIT (elttype)); ! 1703: ! 1704: store_field (target, bitsize, bitpos, mode, TREE_VALUE (elt), ! 1705: VOIDmode, 0); ! 1706: } ! 1707: } ! 1708: } ! 1709: ! 1710: /* Store the value of EXP (an expression tree) ! 1711: into a subfield of TARGET which has mode MODE and occupies ! 1712: BITSIZE bits, starting BITPOS bits from the start of TARGET. ! 1713: ! 1714: If VALUE_MODE is VOIDmode, return nothing in particular. ! 1715: UNSIGNEDP is not used in this case. ! 1716: ! 1717: Otherwise, return an rtx for the value stored. This rtx ! 1718: has mode VALUE_MODE if that is convenient to do. ! 1719: In this case, UNSIGNEDP must be nonzero if the value is an unsigned type. */ ! 1720: ! 1721: static rtx ! 1722: store_field (target, bitsize, bitpos, mode, exp, value_mode, unsignedp) ! 1723: rtx target; ! 1724: int bitsize, bitpos; ! 1725: enum machine_mode mode; ! 1726: tree exp; ! 1727: enum machine_mode value_mode; ! 1728: int unsignedp; ! 1729: { ! 1730: /* If the structure is in a register or if the component ! 1731: is a bit field, we cannot use addressing to access it. ! 1732: Use bit-field techniques or SUBREG to store in it. */ ! 1733: ! 1734: if (mode == BImode || GET_CODE (target) == REG ! 1735: || GET_CODE (target) == SUBREG) ! 1736: { ! 1737: store_bit_field (target, bitsize, bitpos, ! 1738: mode, ! 1739: expand_expr (exp, 0, VOIDmode, 0)); ! 1740: if (value_mode != VOIDmode) ! 1741: return extract_bit_field (target, bitsize, bitpos, unsignedp, ! 1742: 0, value_mode, 0); ! 1743: return const0_rtx; ! 1744: } ! 1745: else ! 1746: { ! 1747: rtx addr = XEXP (target, 0); ! 1748: rtx to_rtx; ! 1749: ! 1750: /* If a value is wanted, it must be the lhs; ! 1751: so make the address stable for multiple use. */ ! 1752: ! 1753: if (value_mode != VOIDmode && GET_CODE (addr) != REG ! 1754: && ! CONSTANT_ADDRESS_P (addr)) ! 1755: addr = copy_to_reg (addr); ! 1756: ! 1757: /* Now build a reference to just the desired component. */ ! 1758: ! 1759: to_rtx = change_address (target, mode, ! 1760: plus_constant (addr, ! 1761: (bitpos / BITS_PER_UNIT))); ! 1762: to_rtx->in_struct = 1; ! 1763: ! 1764: return store_expr (exp, to_rtx, value_mode != VOIDmode); ! 1765: } ! 1766: } ! 1767: ! 1768: /* Given an rtx VALUE that may contain additions and multiplications, ! 1769: return an equivalent value that just refers to a register or memory. ! 1770: This is done by generating instructions to perform the arithmetic ! 1771: and returning a pseudo-register containing the value. */ ! 1772: ! 1773: rtx ! 1774: force_operand (value, target) ! 1775: rtx value, target; ! 1776: { ! 1777: register optab binoptab = 0; ! 1778: register rtx op2; ! 1779: /* Use subtarget as the target for operand 0 of a binary operation. */ ! 1780: register rtx subtarget = (target != 0 && GET_CODE (target) == REG ? target : 0); ! 1781: ! 1782: if (GET_CODE (value) == PLUS) ! 1783: binoptab = add_optab; ! 1784: else if (GET_CODE (value) == MINUS) ! 1785: binoptab = sub_optab; ! 1786: else if (GET_CODE (value) == MULT) ! 1787: { ! 1788: op2 = XEXP (value, 1); ! 1789: if (!CONSTANT_P (op2) ! 1790: && !(GET_CODE (op2) == REG && op2 != subtarget)) ! 1791: subtarget = 0; ! 1792: return expand_mult (GET_MODE (value), ! 1793: force_operand (XEXP (value, 0), subtarget), ! 1794: force_operand (op2, 0), ! 1795: target, 0); ! 1796: } ! 1797: ! 1798: if (binoptab) ! 1799: { ! 1800: op2 = XEXP (value, 1); ! 1801: if (!CONSTANT_P (op2) ! 1802: && !(GET_CODE (op2) == REG && op2 != subtarget)) ! 1803: subtarget = 0; ! 1804: if (binoptab == sub_optab ! 1805: && GET_CODE (op2) == CONST_INT && INTVAL (op2) < 0) ! 1806: { ! 1807: binoptab = add_optab; ! 1808: op2 = gen_rtx (CONST_INT, VOIDmode, - INTVAL (op2)); ! 1809: } ! 1810: return expand_binop (GET_MODE (value), binoptab, ! 1811: force_operand (XEXP (value, 0), subtarget), ! 1812: force_operand (op2, 0), ! 1813: target, 0, OPTAB_LIB_WIDEN); ! 1814: /* We give UNSIGNEP = 0 to expand_binop ! 1815: because the only operations we are expanding here are signed ones. */ ! 1816: } ! 1817: return value; ! 1818: } ! 1819: ! 1820: /* expand_expr: generate code for computing expression EXP. ! 1821: An rtx for the computed value is returned. ! 1822: ! 1823: The value may be stored in TARGET if TARGET is nonzero. ! 1824: TARGET is just a suggestion; callers must assume that ! 1825: the rtx returned may not be the same as TARGET. ! 1826: ! 1827: If TARGET is CONST0_RTX, it means that the value will be ignored. ! 1828: ! 1829: If TMODE is not VOIDmode, it suggests generating the ! 1830: result in mode TMODE. But this is done only when convenient. ! 1831: Otherwise, TMODE is ignored and the value generated in its natural mode. ! 1832: TMODE is just a suggestion; callers must assume that ! 1833: the rtx returned may not have mode TMODE. ! 1834: ! 1835: If MODIFIER is EXPAND_SUM then when EXP is an addition ! 1836: we can return an rtx of the form (MULT (REG ...) (CONST_INT ...)) ! 1837: or a nest of (PLUS ...) and (MINUS ...) where the terms are ! 1838: products as above, or REG or MEM, or constant. ! 1839: Ordinarily in such cases we would output mul or add instructions ! 1840: and then return a pseudo reg containing the sum. ! 1841: ! 1842: If MODIFIER is EXPAND_CONST_ADDRESS then it is ok to return ! 1843: a MEM rtx whose address is a constant that isn't a legitimate address. */ ! 1844: ! 1845: /* Subroutine of expand_expr: ! 1846: return the target to use when recursively expanding ! 1847: the first operand of an arithmetic operation. */ ! 1848: ! 1849: static rtx ! 1850: validate_subtarget (subtarget, otherop) ! 1851: rtx subtarget; ! 1852: tree otherop; ! 1853: { ! 1854: if (TREE_LITERAL (otherop)) ! 1855: return subtarget; ! 1856: if (TREE_CODE (otherop) == VAR_DECL ! 1857: && DECL_RTL (otherop) != subtarget) ! 1858: return subtarget; ! 1859: return 0; ! 1860: } ! 1861: ! 1862: rtx ! 1863: expand_expr (exp, target, tmode, modifier) ! 1864: register tree exp; ! 1865: rtx target; ! 1866: enum machine_mode tmode; ! 1867: enum expand_modifier modifier; ! 1868: { ! 1869: register rtx op0, op1, temp; ! 1870: tree type = TREE_TYPE (exp); ! 1871: register enum machine_mode mode = TYPE_MODE (type); ! 1872: register enum tree_code code = TREE_CODE (exp); ! 1873: optab this_optab; ! 1874: int negate_1; ! 1875: /* Use subtarget as the target for operand 0 of a binary operation. */ ! 1876: rtx subtarget = (target != 0 && GET_CODE (target) == REG ? target : 0); ! 1877: rtx original_target = target; ! 1878: int ignore = target == const0_rtx; ! 1879: ! 1880: if (ignore) target = 0, original_target = 0; ! 1881: ! 1882: /* If will do cse, generate all results into registers ! 1883: since 1) that allows cse to find more things ! 1884: and 2) otherwise cse could produce an insn the machine ! 1885: cannot support. */ ! 1886: ! 1887: if (! cse_not_expected && mode != BLKmode) ! 1888: target = subtarget; ! 1889: ! 1890: /* No sense saving up arithmetic to be done ! 1891: if it's all in the wrong mode to form part of an address. ! 1892: And force_operand won't know whether to sign-extend or zero-extend. */ ! 1893: ! 1894: if (mode != Pmode && modifier == EXPAND_SUM) ! 1895: modifier = (enum expand_modifier) 0; ! 1896: ! 1897: switch (code) ! 1898: { ! 1899: case FUNCTION_DECL: ! 1900: case VAR_DECL: ! 1901: case PARM_DECL: ! 1902: case RESULT_DECL: ! 1903: if (DECL_RTL (exp) == 0) ! 1904: abort (); ! 1905: if (GET_CODE (DECL_RTL (exp)) == SYMBOL_REF) ! 1906: abort (); ! 1907: if (GET_CODE (DECL_RTL (exp)) == MEM ! 1908: && modifier != EXPAND_CONST_ADDRESS) ! 1909: { ! 1910: /* DECL_RTL probably contains a constant address. ! 1911: On RISC machines where a constant address isn't valid, ! 1912: make some insns to get that address into a register. */ ! 1913: if (!memory_address_p (DECL_MODE (exp), XEXP (DECL_RTL (exp), 0))) ! 1914: return change_address (DECL_RTL (exp), VOIDmode, ! 1915: copy_rtx (XEXP (DECL_RTL (exp), 0))); ! 1916: } ! 1917: return DECL_RTL (exp); ! 1918: ! 1919: case INTEGER_CST: ! 1920: return gen_rtx (CONST_INT, VOIDmode, TREE_INT_CST_LOW (exp)); ! 1921: ! 1922: case CONST_DECL: ! 1923: return expand_expr (DECL_INITIAL (exp), target, VOIDmode, 0); ! 1924: ! 1925: case REAL_CST: ! 1926: if (TREE_CST_RTL (exp)) ! 1927: return TREE_CST_RTL (exp); ! 1928: /* If optimized, generate immediate float ! 1929: which will be turned into memory float if necessary. */ ! 1930: if (!cse_not_expected) ! 1931: return immed_real_const (exp); ! 1932: output_constant_def (exp); ! 1933: return TREE_CST_RTL (exp); ! 1934: ! 1935: case COMPLEX_CST: ! 1936: case STRING_CST: ! 1937: if (TREE_CST_RTL (exp)) ! 1938: return TREE_CST_RTL (exp); ! 1939: output_constant_def (exp); ! 1940: return TREE_CST_RTL (exp); ! 1941: ! 1942: case SAVE_EXPR: ! 1943: if (SAVE_EXPR_RTL (exp) == 0) ! 1944: { ! 1945: SAVE_EXPR_RTL (exp) = gen_reg_rtx (mode); ! 1946: store_expr (TREE_OPERAND (exp, 0), SAVE_EXPR_RTL (exp), 0); ! 1947: } ! 1948: /* Don't let the same rtl node appear in two places. */ ! 1949: return SAVE_EXPR_RTL (exp); ! 1950: ! 1951: case RTL_EXPR: ! 1952: emit_insn (RTL_EXPR_SEQUENCE (exp)); ! 1953: return RTL_EXPR_RTL (exp); ! 1954: ! 1955: case CONSTRUCTOR: ! 1956: /* All elts simple constants => refer to a constant in memory. */ ! 1957: if (TREE_STATIC (exp)) ! 1958: /* For aggregate types with non-BLKmode modes, ! 1959: this should ideally construct a CONST_INT. */ ! 1960: return output_constant_def (exp); ! 1961: ! 1962: if (ignore) ! 1963: { ! 1964: tree elt; ! 1965: for (elt = CONSTRUCTOR_ELTS (exp); elt; elt = TREE_CHAIN (elt)) ! 1966: expand_expr (TREE_VALUE (elt), const0_rtx, VOIDmode, 0); ! 1967: return const0_rtx; ! 1968: } ! 1969: else ! 1970: { ! 1971: if (target == 0) ! 1972: target = gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)), ! 1973: get_structure_value_addr (expr_size (exp))); ! 1974: store_expr (exp, target, 0); ! 1975: return target; ! 1976: } ! 1977: ! 1978: case INDIRECT_REF: ! 1979: { ! 1980: tree exp1 = TREE_OPERAND (exp, 0); ! 1981: tree exp2; ! 1982: ! 1983: /* A SAVE_EXPR as the address in an INDIRECT_EXPR is generated ! 1984: for *PTR += ANYTHING where PTR is put inside the SAVE_EXPR. ! 1985: This code has the same general effect as simply doing ! 1986: expand_expr on the save expr, except that the expression PTR ! 1987: is computed for use as a memory address. This means different ! 1988: code, suitable for indexing, may be generated. */ ! 1989: if (TREE_CODE (exp1) == SAVE_EXPR ! 1990: && SAVE_EXPR_RTL (exp1) == 0 ! 1991: && TREE_CODE (exp2 = TREE_OPERAND (exp1, 0)) != ERROR_MARK ! 1992: && TYPE_MODE (TREE_TYPE (exp1)) == Pmode ! 1993: && TYPE_MODE (TREE_TYPE (exp2)) == Pmode) ! 1994: { ! 1995: temp = expand_expr (TREE_OPERAND (exp1, 0), 0, VOIDmode, EXPAND_SUM); ! 1996: op0 = memory_address (mode, temp); ! 1997: op0 = copy_all_regs (op0); ! 1998: SAVE_EXPR_RTL (exp1) = op0; ! 1999: } ! 2000: else ! 2001: { ! 2002: op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, EXPAND_SUM); ! 2003: op0 = memory_address (mode, op0); ! 2004: } ! 2005: } ! 2006: temp = gen_rtx (MEM, mode, op0); ! 2007: /* If address was computed by addition, ! 2008: mark this as an element of an aggregate. */ ! 2009: if (TREE_CODE (TREE_OPERAND (exp, 0)) == PLUS_EXPR ! 2010: || (TREE_CODE (TREE_OPERAND (exp, 0)) == SAVE_EXPR ! 2011: && TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) == PLUS_EXPR)) ! 2012: temp->in_struct = 1; ! 2013: temp->volatil = TREE_THIS_VOLATILE (exp) | flag_volatile; ! 2014: temp->unchanging = TREE_READONLY (exp); ! 2015: return temp; ! 2016: ! 2017: case ARRAY_REF: ! 2018: if (TREE_CODE (TREE_OPERAND (exp, 1)) != INTEGER_CST ! 2019: || TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) != INTEGER_CST) ! 2020: { ! 2021: /* Nonconstant array index or nonconstant element size. ! 2022: Generate the tree for *(&array+index) and expand that, ! 2023: except do it in a language-independent way ! 2024: and don't complain about non-lvalue arrays. ! 2025: `mark_addressable' should already have been called ! 2026: for any array for which this case will be reached. */ ! 2027: ! 2028: tree array_adr = build (ADDR_EXPR, TYPE_POINTER_TO (type), ! 2029: TREE_OPERAND (exp, 0)); ! 2030: tree index = TREE_OPERAND (exp, 1); ! 2031: tree elt; ! 2032: ! 2033: /* Convert the integer argument to a type the same size as a pointer ! 2034: so the multiply won't overflow spuriously. */ ! 2035: if (TYPE_PRECISION (TREE_TYPE (index)) != POINTER_SIZE) ! 2036: index = convert (type_for_size (POINTER_SIZE, 0), index); ! 2037: ! 2038: /* The array address isn't volatile even if the array is. */ ! 2039: TREE_VOLATILE (array_adr) = 0; ! 2040: ! 2041: elt = build (INDIRECT_REF, type, ! 2042: fold (build (PLUS_EXPR, TYPE_POINTER_TO (type), ! 2043: array_adr, ! 2044: fold (build (MULT_EXPR, ! 2045: TYPE_POINTER_TO (type), ! 2046: index, size_in_bytes (type)))))); ! 2047: ! 2048: return expand_expr (elt, target, tmode, modifier); ! 2049: } ! 2050: /* Treat array-ref with constant index as a component-ref. */ ! 2051: ! 2052: case COMPONENT_REF: ! 2053: { ! 2054: register enum machine_mode mode1; ! 2055: int volstruct = 0; ! 2056: tree dbg1 = TREE_OPERAND (exp, 0); /* For debugging */ ! 2057: int bitsize; ! 2058: tree tem = exp; ! 2059: int bitpos = 0; ! 2060: int unsignedp; ! 2061: ! 2062: if (TREE_CODE (exp) == COMPONENT_REF) ! 2063: { ! 2064: tree field = TREE_OPERAND (exp, 1); ! 2065: bitsize = TREE_INT_CST_LOW (DECL_SIZE (field)) * DECL_SIZE_UNIT (field); ! 2066: mode1 = DECL_MODE (TREE_OPERAND (exp, 1)); ! 2067: unsignedp = TREE_UNSIGNED (field); ! 2068: } ! 2069: else ! 2070: { ! 2071: mode1 = TYPE_MODE (TREE_TYPE (exp)); ! 2072: bitsize = GET_MODE_BITSIZE (mode1); ! 2073: unsignedp = TREE_UNSIGNED (TREE_TYPE (exp)); ! 2074: } ! 2075: ! 2076: /* Compute cumulative bit-offset for nested component-refs ! 2077: and array-refs, and find the ultimate containing object. */ ! 2078: ! 2079: while (1) ! 2080: { ! 2081: if (TREE_CODE (tem) == COMPONENT_REF) ! 2082: { ! 2083: bitpos += DECL_OFFSET (TREE_OPERAND (tem, 1)); ! 2084: if (TREE_THIS_VOLATILE (tem)) ! 2085: volstruct = 1; ! 2086: } ! 2087: else if (TREE_CODE (tem) == ARRAY_REF ! 2088: && TREE_CODE (TREE_OPERAND (tem, 1)) == INTEGER_CST ! 2089: && TREE_CODE (TYPE_SIZE (TREE_TYPE (tem))) == INTEGER_CST) ! 2090: { ! 2091: bitpos += (TREE_INT_CST_LOW (TREE_OPERAND (tem, 1)) ! 2092: * TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (tem))) ! 2093: * TYPE_SIZE_UNIT (TREE_TYPE (tem))); ! 2094: } ! 2095: else ! 2096: break; ! 2097: tem = TREE_OPERAND (tem, 0); ! 2098: } ! 2099: ! 2100: op0 = expand_expr (tem, 0, VOIDmode, ! 2101: (modifier == EXPAND_CONST_ADDRESS ! 2102: ? modifier : EXPAND_NORMAL)); ! 2103: ! 2104: if (mode1 == BImode || GET_CODE (op0) == REG ! 2105: || GET_CODE (op0) == SUBREG) ! 2106: { ! 2107: return extract_bit_field (op0, bitsize, bitpos, unsignedp, ! 2108: target, mode, tmode); ! 2109: } ! 2110: /* Get a reference to just this component. */ ! 2111: if (modifier == EXPAND_CONST_ADDRESS) ! 2112: op0 = gen_rtx (MEM, mode1, plus_constant (XEXP (op0, 0), ! 2113: (bitpos / BITS_PER_UNIT))); ! 2114: else ! 2115: op0 = change_address (op0, mode1, ! 2116: plus_constant (XEXP (op0, 0), ! 2117: (bitpos / BITS_PER_UNIT))); ! 2118: op0->in_struct = 1; ! 2119: op0->volatil = volstruct; ! 2120: /* If OP0 is in the shared structure-value stack slot, ! 2121: and it is not BLKmode, copy it into a register. ! 2122: The shared slot may be clobbered at any time by another call. ! 2123: BLKmode is safe because our caller will either copy the value away ! 2124: or take another component and come back here. */ ! 2125: if (mode != BLKmode ! 2126: && TREE_CODE (TREE_OPERAND (exp, 0)) == CALL_EXPR ! 2127: && TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == BLKmode) ! 2128: op0 = copy_to_reg (op0); ! 2129: if (mode == mode1 || mode1 == BLKmode || mode1 == tmode) ! 2130: return op0; ! 2131: if (target == 0) ! 2132: target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode); ! 2133: convert_move (target, op0, unsignedp); ! 2134: return target; ! 2135: } ! 2136: ! 2137: /* Intended for a reference to a buffer of a file-object in Pascal. ! 2138: But it's not certain that a special tree code will really be ! 2139: necessary for these. INDIRECT_REF might work for them. */ ! 2140: case BUFFER_REF: ! 2141: abort (); ! 2142: ! 2143: case CALL_EXPR: ! 2144: /* Check for a built-in function. */ ! 2145: if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR ! 2146: && TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) == FUNCTION_DECL ! 2147: && DECL_FUNCTION_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))) ! 2148: return expand_builtin (exp, target, subtarget, tmode); ! 2149: /* If this call was expanded already by preexpand_calls, ! 2150: just return the result we got. */ ! 2151: if (CALL_EXPR_RTL (exp) != 0) ! 2152: return CALL_EXPR_RTL (exp); ! 2153: return expand_call (exp, target, ignore); ! 2154: ! 2155: case NOP_EXPR: ! 2156: case CONVERT_EXPR: ! 2157: if (TREE_CODE (type) == VOID_TYPE || ignore) ! 2158: { ! 2159: expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, modifier); ! 2160: return const0_rtx; ! 2161: } ! 2162: if (mode == TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))) ! 2163: return expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, modifier); ! 2164: op0 = expand_expr (TREE_OPERAND (exp, 0), 0, mode, 0); ! 2165: if (GET_MODE (op0) == mode || GET_MODE (op0) == VOIDmode) ! 2166: return op0; ! 2167: if (flag_force_mem && GET_CODE (op0) == MEM) ! 2168: op0 = copy_to_reg (op0); ! 2169: if (target == 0) ! 2170: target = gen_reg_rtx (mode); ! 2171: convert_move (target, op0, TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0)))); ! 2172: return target; ! 2173: ! 2174: case PLUS_EXPR: ! 2175: preexpand_calls (exp); ! 2176: if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST ! 2177: && modifier == EXPAND_SUM) ! 2178: { ! 2179: op1 = expand_expr (TREE_OPERAND (exp, 1), subtarget, VOIDmode, EXPAND_SUM); ! 2180: op1 = plus_constant (op1, TREE_INT_CST_LOW (TREE_OPERAND (exp, 0))); ! 2181: return op1; ! 2182: } ! 2183: negate_1 = 1; ! 2184: plus_minus: ! 2185: if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST ! 2186: && modifier == EXPAND_SUM) ! 2187: { ! 2188: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, EXPAND_SUM); ! 2189: op0 = plus_constant (op0, ! 2190: negate_1 * TREE_INT_CST_LOW (TREE_OPERAND (exp, 1))); ! 2191: return op0; ! 2192: } ! 2193: this_optab = add_optab; ! 2194: if (modifier != EXPAND_SUM) goto binop; ! 2195: subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1)); ! 2196: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, EXPAND_SUM); ! 2197: op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, EXPAND_SUM); ! 2198: /* Put a sum last, to simplify what follows. */ ! 2199: #ifdef OLD_INDEXING ! 2200: if (GET_CODE (op1) == MULT) ! 2201: { ! 2202: temp = op0; ! 2203: op0 = op1; ! 2204: op1 = temp; ! 2205: } ! 2206: #endif ! 2207: #ifndef OLD_INDEXING ! 2208: /* Make sure any term that's a sum with a constant comes last. */ ! 2209: if (GET_CODE (op0) == PLUS ! 2210: && CONSTANT_P (XEXP (op0, 1))) ! 2211: { ! 2212: temp = op0; ! 2213: op0 = op1; ! 2214: op1 = temp; ! 2215: } ! 2216: /* If adding to a sum including a constant, ! 2217: associate it to put the constant outside. */ ! 2218: if (GET_CODE (op1) == PLUS ! 2219: && CONSTANT_P (XEXP (op1, 1))) ! 2220: { ! 2221: op0 = gen_rtx (PLUS, mode, XEXP (op1, 0), op0); ! 2222: if (GET_CODE (XEXP (op1, 1)) == CONST_INT) ! 2223: return plus_constant (op0, INTVAL (XEXP (op1, 1))); ! 2224: else ! 2225: return gen_rtx (PLUS, mode, op0, XEXP (op1, 1)); ! 2226: } ! 2227: #endif ! 2228: return gen_rtx (PLUS, mode, op0, op1); ! 2229: ! 2230: case MINUS_EXPR: ! 2231: preexpand_calls (exp); ! 2232: if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST) ! 2233: { ! 2234: if (modifier == EXPAND_SUM) ! 2235: { ! 2236: negate_1 = -1; ! 2237: goto plus_minus; ! 2238: } ! 2239: subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1)); ! 2240: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); ! 2241: op1 = gen_rtx (CONST_INT, VOIDmode, ! 2242: - TREE_INT_CST_LOW (TREE_OPERAND (exp, 1))); ! 2243: this_optab = add_optab; ! 2244: goto binop2; ! 2245: } ! 2246: this_optab = sub_optab; ! 2247: goto binop; ! 2248: ! 2249: case MULT_EXPR: ! 2250: preexpand_calls (exp); ! 2251: /* If first operand is constant, swap them. ! 2252: Thus the following special case checks need only ! 2253: check the second operand. */ ! 2254: if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST) ! 2255: { ! 2256: register tree t1 = TREE_OPERAND (exp, 0); ! 2257: TREE_OPERAND (exp, 0) = TREE_OPERAND (exp, 1); ! 2258: TREE_OPERAND (exp, 1) = t1; ! 2259: } ! 2260: ! 2261: /* Attempt to return something suitable for generating an ! 2262: indexed address, for machines that support that. */ ! 2263: ! 2264: if (modifier == EXPAND_SUM ! 2265: && TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST) ! 2266: { ! 2267: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, EXPAND_SUM); ! 2268: ! 2269: /* Apply distributive law if OP0 is x+c. */ ! 2270: if (GET_CODE (op0) == PLUS ! 2271: && GET_CODE (XEXP (op0, 1)) == CONST_INT) ! 2272: return gen_rtx (PLUS, mode, ! 2273: gen_rtx (MULT, mode, XEXP (op0, 0), ! 2274: gen_rtx (CONST_INT, VOIDmode, ! 2275: TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)))), ! 2276: gen_rtx (CONST_INT, VOIDmode, ! 2277: (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)) ! 2278: * INTVAL (XEXP (op0, 1))))); ! 2279: ! 2280: if (GET_CODE (op0) != REG) ! 2281: op0 = force_operand (op0, 0); ! 2282: if (GET_CODE (op0) != REG) ! 2283: op0 = copy_to_mode_reg (mode, op0); ! 2284: ! 2285: return gen_rtx (MULT, mode, op0, ! 2286: gen_rtx (CONST_INT, VOIDmode, ! 2287: TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)))); ! 2288: } ! 2289: subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1)); ! 2290: /* Check for multiplying things that have been extended ! 2291: from a narrower type. If this machine supports multiplying ! 2292: in that narrower type with a result in the desired type, ! 2293: do it that way, and avoid the explicit type-conversion. */ ! 2294: if (TREE_CODE (TREE_OPERAND (exp, 0)) == NOP_EXPR ! 2295: && TREE_CODE (TREE_TYPE (exp)) == INTEGER_TYPE ! 2296: && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))) ! 2297: < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0)))) ! 2298: && ((TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST ! 2299: && int_fits_type_p (TREE_OPERAND (exp, 1), ! 2300: TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))) ! 2301: /* Don't use a widening multiply if a shift will do. */ ! 2302: && exact_log2 (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1))) < 0) ! 2303: || ! 2304: (TREE_CODE (TREE_OPERAND (exp, 1)) == NOP_EXPR ! 2305: && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 1), 0))) ! 2306: == ! 2307: TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))) ! 2308: /* If both operands are extended, they must either both ! 2309: be zero-extended or both be sign-extended. */ ! 2310: && (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 1), 0))) ! 2311: == ! 2312: TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))))))) ! 2313: { ! 2314: enum machine_mode innermode ! 2315: = TYPE_MODE (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))); ! 2316: this_optab = (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))) ! 2317: ? umul_widen_optab : smul_widen_optab); ! 2318: if ((int) innermode + 1 == (int) mode ! 2319: && this_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) ! 2320: { ! 2321: op0 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 0), 0), ! 2322: 0, VOIDmode, 0); ! 2323: if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST) ! 2324: op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0); ! 2325: else ! 2326: op1 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 1), 0), ! 2327: 0, VOIDmode, 0); ! 2328: goto binop2; ! 2329: } ! 2330: } ! 2331: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); ! 2332: op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0); ! 2333: return expand_mult (mode, op0, op1, target, TREE_UNSIGNED (type)); ! 2334: ! 2335: case TRUNC_DIV_EXPR: ! 2336: case FLOOR_DIV_EXPR: ! 2337: case CEIL_DIV_EXPR: ! 2338: case ROUND_DIV_EXPR: ! 2339: preexpand_calls (exp); ! 2340: subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1)); ! 2341: /* Possible optimization: compute the dividend with EXPAND_SUM ! 2342: then if the divisor is constant can optimize the case ! 2343: where some terms of the dividend have coeffs divisible by it. */ ! 2344: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); ! 2345: op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0); ! 2346: return expand_divmod (0, code, mode, op0, op1, target, ! 2347: TREE_UNSIGNED (type)); ! 2348: ! 2349: case RDIV_EXPR: ! 2350: preexpand_calls (exp); ! 2351: this_optab = flodiv_optab; ! 2352: goto binop; ! 2353: ! 2354: case TRUNC_MOD_EXPR: ! 2355: case FLOOR_MOD_EXPR: ! 2356: case CEIL_MOD_EXPR: ! 2357: case ROUND_MOD_EXPR: ! 2358: preexpand_calls (exp); ! 2359: subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1)); ! 2360: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); ! 2361: op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0); ! 2362: return expand_divmod (1, code, mode, op0, op1, target, ! 2363: TREE_UNSIGNED (type)); ! 2364: #if 0 ! 2365: #ifdef HAVE_divmoddisi4 ! 2366: if (GET_MODE (op0) != DImode) ! 2367: { ! 2368: temp = gen_reg_rtx (DImode); ! 2369: convert_move (temp, op0, 0); ! 2370: op0 = temp; ! 2371: if (GET_MODE (op1) != SImode && GET_CODE (op1) != CONST_INT) ! 2372: { ! 2373: temp = gen_reg_rtx (SImode); ! 2374: convert_move (temp, op1, 0); ! 2375: op1 = temp; ! 2376: } ! 2377: temp = gen_reg_rtx (SImode); ! 2378: if (target == 0) ! 2379: target = gen_reg_rtx (SImode); ! 2380: emit_insn (gen_divmoddisi4 (temp, protect_from_queue (op0, 0), ! 2381: protect_from_queue (op1, 0), ! 2382: protect_from_queue (target, 1))); ! 2383: return target; ! 2384: } ! 2385: #endif ! 2386: #endif ! 2387: ! 2388: case FIX_ROUND_EXPR: ! 2389: case FIX_FLOOR_EXPR: ! 2390: case FIX_CEIL_EXPR: ! 2391: abort (); /* Not used for C. */ ! 2392: ! 2393: case FIX_TRUNC_EXPR: ! 2394: op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0); ! 2395: if (target == 0) ! 2396: target = gen_reg_rtx (mode); ! 2397: { ! 2398: int unsignedp = TREE_UNSIGNED (TREE_TYPE (exp)); ! 2399: if (mode == HImode || mode == QImode) ! 2400: { ! 2401: register rtx temp = gen_reg_rtx (SImode); ! 2402: expand_fix (temp, op0, unsignedp); ! 2403: convert_move (target, temp, unsignedp); ! 2404: } ! 2405: else ! 2406: expand_fix (target, op0, unsignedp); ! 2407: } ! 2408: return target; ! 2409: ! 2410: case FLOAT_EXPR: ! 2411: op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0); ! 2412: if (target == 0) ! 2413: target = gen_reg_rtx (mode); ! 2414: { ! 2415: int unsignedp = TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))); ! 2416: if (GET_MODE (op0) == HImode ! 2417: || GET_MODE (op0) == QImode) ! 2418: { ! 2419: register rtx temp = gen_reg_rtx (SImode); ! 2420: convert_move (temp, op0, unsignedp); ! 2421: expand_float (target, temp, 0); ! 2422: } ! 2423: else ! 2424: expand_float (target, op0, unsignedp); ! 2425: } ! 2426: return target; ! 2427: ! 2428: case NEGATE_EXPR: ! 2429: op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0); ! 2430: temp = expand_unop (mode, neg_optab, op0, target, 0); ! 2431: if (temp == 0) ! 2432: abort (); ! 2433: return temp; ! 2434: ! 2435: case ABS_EXPR: ! 2436: /* First try to do it with a special abs instruction. ! 2437: If that does not win, use conditional jump and negate. */ ! 2438: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); ! 2439: temp = expand_unop (mode, abs_optab, op0, target, 0); ! 2440: if (temp != 0) ! 2441: return temp; ! 2442: temp = gen_label_rtx (); ! 2443: if (target == 0 || GET_CODE (target) != REG) ! 2444: target = gen_reg_rtx (mode); ! 2445: emit_move_insn (target, op0); ! 2446: emit_cmp_insn (target, ! 2447: expand_expr (convert (TREE_TYPE (exp), integer_zero_node), ! 2448: 0, VOIDmode, 0), ! 2449: 0, 0); ! 2450: emit_jump_insn (gen_bge (temp)); ! 2451: op0 = expand_unop (mode, neg_optab, target, target, 0); ! 2452: if (op0 != target) ! 2453: emit_move_insn (target, op0); ! 2454: emit_label (temp); ! 2455: return target; ! 2456: ! 2457: case MAX_EXPR: ! 2458: case MIN_EXPR: ! 2459: mode = TYPE_MODE (TREE_OPERAND (exp, 1)); ! 2460: op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0); ! 2461: if (target == 0 || GET_CODE (target) != REG || target == op1) ! 2462: target = gen_reg_rtx (mode); ! 2463: op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0); ! 2464: if (target != op0) ! 2465: emit_move_insn (target, op0); ! 2466: op0 = gen_label_rtx (); ! 2467: if (code == MAX_EXPR) ! 2468: temp = (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 1))) ! 2469: ? compare1 (target, op1, GEU, LEU, 1, mode) ! 2470: : compare1 (target, op1, GE, LE, 0, mode)); ! 2471: else ! 2472: temp = (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 1))) ! 2473: ? compare1 (target, op1, LEU, GEU, 1, mode) ! 2474: : compare1 (target, op1, LE, GE, 0, mode)); ! 2475: if (temp == const0_rtx) ! 2476: emit_move_insn (target, op1); ! 2477: else if (temp != const1_rtx) ! 2478: { ! 2479: emit_jump_insn (gen_rtx (SET, VOIDmode, pc_rtx, ! 2480: gen_rtx (IF_THEN_ELSE, VOIDmode, ! 2481: temp, ! 2482: gen_rtx (LABEL_REF, VOIDmode, op0), ! 2483: pc_rtx))); ! 2484: emit_move_insn (target, op1); ! 2485: } ! 2486: emit_label (op0); ! 2487: return target; ! 2488: ! 2489: /* ??? Can optimize when the operand of this is a bitwise operation, ! 2490: by using a different bitwise operation. */ ! 2491: case BIT_NOT_EXPR: ! 2492: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); ! 2493: temp = expand_unop (mode, one_cmpl_optab, op0, target, 1); ! 2494: if (temp == 0) ! 2495: abort (); ! 2496: return temp; ! 2497: ! 2498: case FFS_EXPR: ! 2499: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); ! 2500: temp = expand_unop (mode, ffs_optab, op0, target, 1); ! 2501: if (temp == 0) ! 2502: abort (); ! 2503: return temp; ! 2504: ! 2505: /* ??? Can optimize bitwise operations with one arg constant. ! 2506: Pastel optimizes (a bitwise1 n) bitwise2 (a bitwise3 b) ! 2507: and (a bitwise1 b) bitwise2 b (etc) ! 2508: but that is probably not worth while. */ ! 2509: ! 2510: /* BIT_AND_EXPR is for bitwise anding. ! 2511: TRUTH_AND_EXPR is for anding two boolean values ! 2512: when we want in all cases to compute both of them. ! 2513: In general it is fastest to do TRUTH_AND_EXPR by ! 2514: computing both operands as actual zero-or-1 values ! 2515: and then bitwise anding. In cases where there cannot ! 2516: be any side effects, better code would be made by ! 2517: treating TRUTH_AND_EXPR like TRUTH_ANDIF_EXPR; ! 2518: but the question is how to recognize those cases. */ ! 2519: ! 2520: case TRUTH_AND_EXPR: ! 2521: case BIT_AND_EXPR: ! 2522: preexpand_calls (exp); ! 2523: subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1)); ! 2524: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); ! 2525: op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0); ! 2526: return expand_bit_and (mode, op0, op1, target); ! 2527: ! 2528: /* See comment above about TRUTH_AND_EXPR; it applies here too. */ ! 2529: case TRUTH_OR_EXPR: ! 2530: case BIT_IOR_EXPR: ! 2531: preexpand_calls (exp); ! 2532: this_optab = ior_optab; ! 2533: goto binop; ! 2534: ! 2535: case BIT_XOR_EXPR: ! 2536: preexpand_calls (exp); ! 2537: this_optab = xor_optab; ! 2538: goto binop; ! 2539: ! 2540: case LSHIFT_EXPR: ! 2541: case RSHIFT_EXPR: ! 2542: case LROTATE_EXPR: ! 2543: case RROTATE_EXPR: ! 2544: preexpand_calls (exp); ! 2545: subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1)); ! 2546: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); ! 2547: return expand_shift (code, mode, op0, TREE_OPERAND (exp, 1), target, ! 2548: TREE_UNSIGNED (type)); ! 2549: ! 2550: /* ??? cv's were used to effect here to combine additive constants ! 2551: and to determine the answer when only additive constants differ. ! 2552: Also, the addition of one can be handled by changing the condition. */ ! 2553: case LT_EXPR: ! 2554: case LE_EXPR: ! 2555: case GT_EXPR: ! 2556: case GE_EXPR: ! 2557: case EQ_EXPR: ! 2558: case NE_EXPR: ! 2559: preexpand_calls (exp); ! 2560: temp = do_store_flag (exp, target, mode); ! 2561: if (temp != 0) ! 2562: return temp; ! 2563: /* For foo != 0, load foo, and if it is nonzero load 1 instead. */ ! 2564: if (code == NE_EXPR && integer_zerop (TREE_OPERAND (exp, 1)) ! 2565: && subtarget ! 2566: && (GET_MODE (subtarget) ! 2567: == TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))) ! 2568: { ! 2569: temp = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); ! 2570: if (temp != subtarget) ! 2571: temp = copy_to_reg (temp); ! 2572: op1 = gen_label_rtx (); ! 2573: emit_cmp_insn (temp, const0_rtx, 0, TREE_UNSIGNED (type)); ! 2574: emit_jump_insn (gen_beq (op1)); ! 2575: emit_move_insn (temp, const1_rtx); ! 2576: emit_label (op1); ! 2577: return temp; ! 2578: } ! 2579: /* If no set-flag instruction, must generate a conditional ! 2580: store into a temporary variable. Drop through ! 2581: and handle this like && and ||. */ ! 2582: ! 2583: case TRUTH_ANDIF_EXPR: ! 2584: case TRUTH_ORIF_EXPR: ! 2585: temp = gen_reg_rtx (mode); ! 2586: emit_clr_insn (temp); ! 2587: op1 = gen_label_rtx (); ! 2588: jumpifnot (exp, op1); ! 2589: emit_0_to_1_insn (temp); ! 2590: emit_label (op1); ! 2591: return temp; ! 2592: ! 2593: case TRUTH_NOT_EXPR: ! 2594: op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0); ! 2595: /* The parser is careful to generate TRUTH_NOT_EXPR ! 2596: only with operands that are always zero or one. */ ! 2597: temp = expand_binop (mode, xor_optab, op0, ! 2598: gen_rtx (CONST_INT, mode, 1), ! 2599: target, 1, OPTAB_LIB_WIDEN); ! 2600: if (temp == 0) ! 2601: abort (); ! 2602: return temp; ! 2603: ! 2604: case COMPOUND_EXPR: ! 2605: expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0); ! 2606: emit_queue (); ! 2607: return expand_expr (TREE_OPERAND (exp, 1), target, VOIDmode, 0); ! 2608: ! 2609: case COND_EXPR: ! 2610: /* Note that COND_EXPRs whose type is a structure or union ! 2611: are required to be constructed to contain assignments of ! 2612: a temporary variable, so that we can evaluate them here ! 2613: for side effect only. If type is void, we must do likewise. */ ! 2614: op0 = gen_label_rtx (); ! 2615: op1 = gen_label_rtx (); ! 2616: ! 2617: if (mode == VOIDmode || ignore) ! 2618: temp = 0; ! 2619: else if (target) ! 2620: temp = target; ! 2621: else if (mode == BLKmode) ! 2622: { ! 2623: if (TYPE_SIZE (type) == 0 || ! TREE_LITERAL (TYPE_SIZE (type))) ! 2624: abort (); ! 2625: temp = assign_stack_local (BLKmode, ! 2626: (TREE_INT_CST_LOW (TYPE_SIZE (type)) ! 2627: * TYPE_SIZE_UNIT (type) ! 2628: + BITS_PER_UNIT - 1) ! 2629: / BITS_PER_UNIT); ! 2630: } ! 2631: else ! 2632: temp = gen_reg_rtx (mode); ! 2633: ! 2634: jumpifnot (TREE_OPERAND (exp, 0), op0); ! 2635: current_args_size += 1; ! 2636: if (temp != 0) ! 2637: store_expr (TREE_OPERAND (exp, 1), temp, 0); ! 2638: else ! 2639: expand_expr (TREE_OPERAND (exp, 1), ignore ? const0_rtx : 0, ! 2640: VOIDmode, 0); ! 2641: emit_queue (); ! 2642: emit_jump_insn (gen_jump (op1)); ! 2643: emit_barrier (); ! 2644: emit_label (op0); ! 2645: if (temp != 0) ! 2646: store_expr (TREE_OPERAND (exp, 2), temp, 0); ! 2647: else ! 2648: expand_expr (TREE_OPERAND (exp, 2), ignore ? const0_rtx : 0, ! 2649: VOIDmode, 0); ! 2650: emit_queue (); ! 2651: emit_label (op1); ! 2652: current_args_size -= 1; ! 2653: return temp; ! 2654: ! 2655: case MODIFY_EXPR: ! 2656: /* If lhs is complex, expand calls in rhs before computing it. ! 2657: That's so we don't compute a pointer and save it over a call. ! 2658: If lhs is simple, compute it first so we can give it as a ! 2659: target if the rhs is just a call. This avoids an extra temp and copy ! 2660: and that prevents a partial-subsumption which makes bad code. ! 2661: Actually we could treat component_ref's of vars like vars. */ ! 2662: if (TREE_CODE (TREE_OPERAND (exp, 0)) != VAR_DECL ! 2663: && TREE_CODE (TREE_OPERAND (exp, 0)) != RESULT_DECL ! 2664: && TREE_CODE (TREE_OPERAND (exp, 0)) != PARM_DECL) ! 2665: preexpand_calls (exp); ! 2666: temp = expand_assignment (TREE_OPERAND (exp, 0), ! 2667: TREE_OPERAND (exp, 1), ! 2668: ! ignore, ! 2669: original_target != 0); ! 2670: return temp; ! 2671: ! 2672: case PREINCREMENT_EXPR: ! 2673: case PREDECREMENT_EXPR: ! 2674: return expand_increment (exp, 0); ! 2675: ! 2676: case POSTINCREMENT_EXPR: ! 2677: case POSTDECREMENT_EXPR: ! 2678: return expand_increment (exp, 1); ! 2679: ! 2680: case ADDR_EXPR: ! 2681: op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, ! 2682: EXPAND_CONST_ADDRESS); ! 2683: if (GET_CODE (op0) != MEM) ! 2684: abort (); ! 2685: if (modifier == EXPAND_SUM) ! 2686: return XEXP (op0, 0); ! 2687: op0 = force_operand (XEXP (op0, 0), target); ! 2688: if (flag_force_addr && GET_CODE (op0) != REG) ! 2689: return force_reg (Pmode, op0); ! 2690: return op0; ! 2691: ! 2692: case ENTRY_VALUE_EXPR: ! 2693: abort (); ! 2694: ! 2695: case ERROR_MARK: ! 2696: return const0_rtx; ! 2697: ! 2698: default: ! 2699: abort (); ! 2700: } ! 2701: ! 2702: /* Here to do an ordinary binary operator, generating an instruction ! 2703: from the optab already placed in `this_optab'. */ ! 2704: binop: ! 2705: /* Detect things like x = y | (a == b) ! 2706: and do them as (x = y), (a == b ? x |= 1 : 0), x. */ ! 2707: /* First, get the comparison or conditional into the second arg. */ ! 2708: if (comparison_code[(int) TREE_CODE (TREE_OPERAND (exp, 0))] ! 2709: || (TREE_CODE (TREE_OPERAND (exp, 0)) == COND_EXPR ! 2710: && (integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 0), 1)) ! 2711: || integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 0), 2))))) ! 2712: { ! 2713: if (this_optab == ior_optab || this_optab == add_optab ! 2714: || this_optab == xor_optab) ! 2715: { ! 2716: tree exch = TREE_OPERAND (exp, 1); ! 2717: TREE_OPERAND (exp, 1) = TREE_OPERAND (exp, 0); ! 2718: TREE_OPERAND (exp, 0) = exch; ! 2719: } ! 2720: } ! 2721: /* Optimize X + (Y ? Z : 0) by computing X and maybe adding Z. */ ! 2722: if (comparison_code[(int) TREE_CODE (TREE_OPERAND (exp, 1))] ! 2723: || (TREE_CODE (TREE_OPERAND (exp, 1)) == COND_EXPR ! 2724: && (integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 1), 1)) ! 2725: || integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 1), 2))))) ! 2726: { ! 2727: if (this_optab == ior_optab || this_optab == add_optab ! 2728: || this_optab == xor_optab || this_optab == sub_optab ! 2729: || this_optab == lshl_optab || this_optab == ashl_optab ! 2730: || this_optab == lshr_optab || this_optab == ashr_optab ! 2731: || this_optab == rotl_optab || this_optab == rotr_optab) ! 2732: { ! 2733: tree thenexp; ! 2734: rtx thenv = 0; ! 2735: ! 2736: /* Don't store intermediate results in a fixed register. */ ! 2737: if (target != 0 && GET_CODE (target) == REG ! 2738: && REGNO (target) < FIRST_PSEUDO_REGISTER) ! 2739: target = 0; ! 2740: if (target == 0) target = gen_reg_rtx (mode); ! 2741: ! 2742: /* Compute X into the target. */ ! 2743: store_expr (TREE_OPERAND (exp, 0), target, 0); ! 2744: op0 = gen_label_rtx (); ! 2745: ! 2746: /* If other operand is a comparison COMP, treat it as COMP ? 1 : 0 */ ! 2747: if (TREE_CODE (TREE_OPERAND (exp, 1)) != COND_EXPR) ! 2748: { ! 2749: do_jump (TREE_OPERAND (exp, 1), op0, 0); ! 2750: thenv = const1_rtx; ! 2751: } ! 2752: else if (integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 1), 2))) ! 2753: { ! 2754: do_jump (TREE_OPERAND (TREE_OPERAND (exp, 1), 0), op0, 0); ! 2755: thenexp = TREE_OPERAND (TREE_OPERAND (exp, 1), 1); ! 2756: } ! 2757: else ! 2758: { ! 2759: do_jump (TREE_OPERAND (TREE_OPERAND (exp, 1), 0), 0, op0); ! 2760: thenexp = TREE_OPERAND (TREE_OPERAND (exp, 1), 2); ! 2761: } ! 2762: ! 2763: if (thenv == 0) ! 2764: thenv = expand_expr (thenexp, 0, VOIDmode, 0); ! 2765: ! 2766: /* THENV is now Z, the value to operate on, as an rtx. ! 2767: We have already tested that Y isn't zero, so do the operation. */ ! 2768: ! 2769: if (this_optab == rotl_optab || this_optab == rotr_optab) ! 2770: temp = expand_binop (mode, this_optab, target, thenv, target, ! 2771: -1, OPTAB_LIB); ! 2772: else if (this_optab == lshl_optab || this_optab == lshr_optab) ! 2773: temp = expand_binop (mode, this_optab, target, thenv, target, ! 2774: 1, OPTAB_LIB_WIDEN); ! 2775: else ! 2776: temp = expand_binop (mode, this_optab, target, thenv, target, ! 2777: 0, OPTAB_LIB_WIDEN); ! 2778: if (target != temp) ! 2779: emit_move_insn (target, temp); ! 2780: ! 2781: emit_label (op0); ! 2782: return target; ! 2783: } ! 2784: } ! 2785: subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1)); ! 2786: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); ! 2787: op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0); ! 2788: binop2: ! 2789: temp = expand_binop (mode, this_optab, op0, op1, target, ! 2790: TREE_UNSIGNED (TREE_TYPE (exp)), OPTAB_LIB_WIDEN); ! 2791: binop1: ! 2792: if (temp == 0) ! 2793: abort (); ! 2794: return temp; ! 2795: } ! 2796: ! 2797: /* Expand an expression EXP that calls a built-in function, ! 2798: with result going to TARGET if that's convenient ! 2799: (and in mode MODE if that's convenient). ! 2800: SUBTARGET may be used as the target for computing one of EXP's operands. */ ! 2801: ! 2802: static rtx ! 2803: expand_builtin (exp, target, subtarget, mode) ! 2804: tree exp; ! 2805: rtx target; ! 2806: rtx subtarget; ! 2807: enum machine_mode mode; ! 2808: { ! 2809: tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); ! 2810: tree arglist = TREE_OPERAND (exp, 1); ! 2811: rtx op0; ! 2812: rtx temp; ! 2813: ! 2814: switch (DECL_FUNCTION_CODE (fndecl)) ! 2815: { ! 2816: case BUILT_IN_ABS: ! 2817: case BUILT_IN_LABS: ! 2818: case BUILT_IN_FABS: ! 2819: /* build_function_call changes these into ABS_EXPR. */ ! 2820: abort (); ! 2821: ! 2822: case BUILT_IN_ALLOCA: ! 2823: if (arglist == 0) ! 2824: return const0_rtx; ! 2825: frame_pointer_needed = 1; ! 2826: /* Compute the argument. */ ! 2827: op0 = expand_expr (TREE_VALUE (arglist), 0, VOIDmode, 0); ! 2828: if (! CONSTANT_P (op0)) ! 2829: { ! 2830: op0 = force_reg (GET_MODE (op0), op0); ! 2831: if (GET_MODE (op0) != Pmode) ! 2832: op0 = convert_to_mode (Pmode, op0); ! 2833: } ! 2834: /* Push that much space (rounding it up). */ ! 2835: do_pending_stack_adjust (); ! 2836: anti_adjust_stack (round_push (op0)); ! 2837: /* Return a copy of current stack ptr, in TARGET if possible. */ ! 2838: if (target) ! 2839: emit_move_insn (target, stack_pointer_rtx); ! 2840: else ! 2841: target = copy_to_reg (stack_pointer_rtx); ! 2842: return target; ! 2843: ! 2844: case BUILT_IN_FFS: ! 2845: if (arglist == 0) ! 2846: return const0_rtx; ! 2847: ! 2848: /* Compute the argument. */ ! 2849: op0 = expand_expr (TREE_VALUE (arglist), subtarget, VOIDmode, 0); ! 2850: /* Compute ffs, into TARGET if possible. ! 2851: Set TARGET to wherever the result comes back. */ ! 2852: target = expand_unop (mode, ffs_optab, op0, target, 1); ! 2853: if (target == 0) ! 2854: abort (); ! 2855: return target; ! 2856: ! 2857: default: ! 2858: abort (); ! 2859: } ! 2860: } ! 2861: ! 2862: /* Expand code for a post- or pre- increment or decrement ! 2863: and return the RTX for the result. ! 2864: POST is 1 for postinc/decrements and 0 for preinc/decrements. */ ! 2865: ! 2866: static rtx ! 2867: expand_increment (exp, post) ! 2868: register tree exp; ! 2869: int post; ! 2870: { ! 2871: register rtx op0, op1; ! 2872: register rtx temp; ! 2873: register tree incremented = TREE_OPERAND (exp, 0); ! 2874: optab this_optab = add_optab; ! 2875: int icode; ! 2876: enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp)); ! 2877: int op0_is_copy = 0; ! 2878: ! 2879: /* Stabilize any component ref that might need to be ! 2880: evaluated more than once below. */ ! 2881: if (TREE_CODE (incremented) == COMPONENT_REF ! 2882: && (TREE_CODE (TREE_OPERAND (incremented, 0)) != INDIRECT_REF ! 2883: || DECL_MODE (TREE_OPERAND (exp, 1)) == BImode)) ! 2884: incremented = stabilize_reference (incremented); ! 2885: ! 2886: /* Compute the operands as RTX. ! 2887: Note whether OP0 is the actual lvalue or a copy of it: ! 2888: I believe it is a copy iff it is a register and insns were ! 2889: generated in computing it. */ ! 2890: temp = get_last_insn (); ! 2891: op0 = expand_expr (incremented, 0, VOIDmode, 0); ! 2892: if (temp != get_last_insn ()) ! 2893: op0_is_copy = (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG); ! 2894: op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0); ! 2895: ! 2896: /* Decide whether incrementing or decrementing. */ ! 2897: if (TREE_CODE (exp) == POSTDECREMENT_EXPR ! 2898: || TREE_CODE (exp) == PREDECREMENT_EXPR) ! 2899: this_optab = sub_optab; ! 2900: ! 2901: /* If OP0 is not the actual lvalue, but rather a copy in a register, ! 2902: then we cannot just increment OP0. We must ! 2903: therefore contrive to increment the original value. ! 2904: Then we can return OP0 since it is a copy of the old value. */ ! 2905: if (op0_is_copy) ! 2906: { ! 2907: /* This is the easiest way to increment the value wherever it is. ! 2908: Problems with multiple evaluation of INCREMENTED ! 2909: are prevented because either (1) it is a component_ref, ! 2910: in which case it was stabilized above, or (2) it is an array_ref ! 2911: with constant index in an array in a register, which is ! 2912: safe to reevaluate. */ ! 2913: tree newexp = build ((this_optab == add_optab ! 2914: ? PLUS_EXPR : MINUS_EXPR), ! 2915: TREE_TYPE (exp), ! 2916: incremented, ! 2917: TREE_OPERAND (exp, 1)); ! 2918: temp = expand_assignment (incremented, newexp, ! post, 0); ! 2919: return post ? op0 : temp; ! 2920: } ! 2921: ! 2922: /* Convert decrement by a constant into a negative increment. */ ! 2923: if (this_optab == sub_optab ! 2924: && GET_CODE (op1) == CONST_INT) ! 2925: { ! 2926: op1 = gen_rtx (CONST_INT, VOIDmode, - INTVAL (op1)); ! 2927: this_optab = add_optab; ! 2928: } ! 2929: ! 2930: if (post) ! 2931: { ! 2932: /* We have a true reference to the value in OP0. ! 2933: If there is an insn to add or subtract in this mode, queue it. */ ! 2934: ! 2935: /* I'm not sure this is still necessary. */ ! 2936: op0 = stabilize (op0); ! 2937: ! 2938: icode = (int) this_optab->handlers[(int) mode].insn_code; ! 2939: if (icode != (int) CODE_FOR_nothing ! 2940: /* Make sure that OP0 is valid for operands 0 and 1 ! 2941: of the insn we want to queue. */ ! 2942: && (*insn_operand_predicate[icode][0]) (op0, mode) ! 2943: && (*insn_operand_predicate[icode][1]) (op0, mode)) ! 2944: { ! 2945: if (! (*insn_operand_predicate[icode][2]) (op1, mode)) ! 2946: op1 = force_reg (mode, op1); ! 2947: ! 2948: return enqueue_insn (op0, GEN_FCN (icode) (op0, op0, op1)); ! 2949: } ! 2950: } ! 2951: ! 2952: /* Preincrement, or we can't increment with one simple insn. */ ! 2953: if (post) ! 2954: /* Save a copy of the value before inc or dec, to return it later. */ ! 2955: temp = copy_to_reg (op0); ! 2956: else ! 2957: /* Arrange to return the incremented value. */ ! 2958: temp = op0; ! 2959: ! 2960: /* Increment however we can. */ ! 2961: op1 = expand_binop (mode, this_optab, op0, op1, op0, ! 2962: 0, OPTAB_LIB_WIDEN); ! 2963: /* Make sure the value is stored into OP0. */ ! 2964: if (op1 != op0) ! 2965: emit_move_insn (op0, op1); ! 2966: ! 2967: return temp; ! 2968: } ! 2969: ! 2970: /* Expand all function calls contained within EXP, innermost ones first. ! 2971: But don't look within expressions that have sequence points. ! 2972: For each CALL_EXPR, record the rtx for its value ! 2973: in the CALL_EXPR_RTL field. ! 2974: ! 2975: Calls that return large structures for which a structure return ! 2976: stack slot is needed are not preexpanded. Preexpanding them loses ! 2977: because if more than one were preexpanded they would try to use the ! 2978: same stack slot. */ ! 2979: ! 2980: static void ! 2981: preexpand_calls (exp) ! 2982: tree exp; ! 2983: { ! 2984: register int nops, i; ! 2985: ! 2986: if (! do_preexpand_calls) ! 2987: return; ! 2988: ! 2989: /* Only expressions and references can contain calls. */ ! 2990: ! 2991: if (tree_code_type[(int) TREE_CODE (exp)][0] != 'e' ! 2992: && tree_code_type[(int) TREE_CODE (exp)][0] != 'r') ! 2993: return; ! 2994: ! 2995: switch (TREE_CODE (exp)) ! 2996: { ! 2997: case CALL_EXPR: ! 2998: /* Do nothing to built-in functions. */ ! 2999: if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR ! 3000: && TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) == FUNCTION_DECL ! 3001: && DECL_FUNCTION_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))) ! 3002: return; ! 3003: if (CALL_EXPR_RTL (exp) == 0 ! 3004: && TYPE_MODE (TREE_TYPE (exp)) != BLKmode) ! 3005: CALL_EXPR_RTL (exp) = expand_call (exp, 0, 0); ! 3006: return; ! 3007: ! 3008: case COMPOUND_EXPR: ! 3009: case COND_EXPR: ! 3010: case TRUTH_ANDIF_EXPR: ! 3011: case TRUTH_ORIF_EXPR: ! 3012: /* If we find one of these, then we can be sure ! 3013: the adjust will be done for it (since it makes jumps). ! 3014: Do it now, so that if this is inside an argument ! 3015: of a function, we don't get the stack adjustment ! 3016: after some other args have already been pushed. */ ! 3017: do_pending_stack_adjust (); ! 3018: return; ! 3019: ! 3020: case RTL_EXPR: ! 3021: return; ! 3022: ! 3023: case SAVE_EXPR: ! 3024: if (SAVE_EXPR_RTL (exp) != 0) ! 3025: return; ! 3026: } ! 3027: ! 3028: nops = tree_code_length[(int) TREE_CODE (exp)]; ! 3029: for (i = 0; i < nops; i++) ! 3030: if (TREE_OPERAND (exp, i) != 0) ! 3031: { ! 3032: register int type = *tree_code_type[(int) TREE_CODE (TREE_OPERAND (exp, i))]; ! 3033: if (type == 'e' || type == 'r') ! 3034: preexpand_calls (TREE_OPERAND (exp, i)); ! 3035: } ! 3036: } ! 3037: ! 3038: /* Force FUNEXP into a form suitable for the address of a CALL, ! 3039: and return that as an rtx. Also load the static chain register ! 3040: from either FUNEXP or CONTEXT. */ ! 3041: ! 3042: static rtx ! 3043: prepare_call_address (funexp, context) ! 3044: rtx funexp; ! 3045: rtx context; ! 3046: { ! 3047: funexp = protect_from_queue (funexp, 0); ! 3048: if (context != 0) ! 3049: context = protect_from_queue (context, 0); ! 3050: ! 3051: /* Function variable in language with nested functions. */ ! 3052: if (GET_MODE (funexp) == EPmode) ! 3053: { ! 3054: emit_move_insn (static_chain_rtx, gen_highpart (Pmode, funexp)); ! 3055: funexp = memory_address (FUNCTION_MODE, gen_lowpart (Pmode, funexp)); ! 3056: emit_insn (gen_rtx (USE, VOIDmode, static_chain_rtx)); ! 3057: } ! 3058: else ! 3059: { ! 3060: if (context != 0) ! 3061: /* Unless function variable in C, or top level function constant */ ! 3062: emit_move_insn (static_chain_rtx, lookup_static_chain (context)); ! 3063: ! 3064: /* Make a valid memory address and copy constants thru pseudo-regs, ! 3065: but not for a constant address if -fno-function-cse. */ ! 3066: if (GET_CODE (funexp) != SYMBOL_REF) ! 3067: funexp = memory_address (FUNCTION_MODE, funexp); ! 3068: else ! 3069: { ! 3070: #ifndef NO_FUNCTION_CSE ! 3071: if (! flag_no_function_cse) ! 3072: funexp = copy_to_mode_reg (Pmode, funexp); ! 3073: #endif ! 3074: } ! 3075: ! 3076: if (context != 0) ! 3077: emit_insn (gen_rtx (USE, VOIDmode, static_chain_rtx)); ! 3078: } ! 3079: return funexp; ! 3080: } ! 3081: ! 3082: /* Generate instructions to call function FUNEXP, ! 3083: and optionally pop the results. ! 3084: The CALL_INSN is the first insn generated. ! 3085: ! 3086: FUNTYPE is the data type of the function, or, for a library call, ! 3087: the identifier for the name of the call. This is given to the ! 3088: macro RETURN_POPS_ARGS to determine whether this function pops its own args. ! 3089: ! 3090: STACK_SIZE is the number of bytes of arguments on the stack, ! 3091: rounded up to STACK_BOUNDARY; zero if the size is variable. ! 3092: This is both to put into the call insn and ! 3093: to generate explicit popping code if necessary. ! 3094: ! 3095: NEXT_ARG_REG is the rtx that results from executing ! 3096: FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1) ! 3097: just after all the args have had their registers assigned. ! 3098: This could be whatever you like, but normally it is the first ! 3099: arg-register beyond those used for args in this call, ! 3100: or 0 if all the arg-registers are used in this call. ! 3101: It is passed on to `gen_call' so you can put this info in the call insn. ! 3102: ! 3103: VALREG is a hard register in which a value is returned, ! 3104: or 0 if the call does not return a value. ! 3105: ! 3106: OLD_ARGS_SIZE is the value that `current_args_size' had before ! 3107: the args to this call were processed. ! 3108: We restore `current_args_size' to that value. */ ! 3109: ! 3110: static void ! 3111: emit_call_1 (funexp, funtype, stack_size, next_arg_reg, valreg, old_args_size) ! 3112: rtx funexp; ! 3113: tree funtype; ! 3114: int stack_size; ! 3115: rtx next_arg_reg; ! 3116: rtx valreg; ! 3117: int old_args_size; ! 3118: { ! 3119: rtx stack_size_rtx = gen_rtx (CONST_INT, VOIDmode, stack_size); ! 3120: ! 3121: if (valreg) ! 3122: emit_call_insn (gen_call_value (valreg, ! 3123: gen_rtx (MEM, FUNCTION_MODE, funexp), ! 3124: stack_size_rtx, next_arg_reg)); ! 3125: else ! 3126: emit_call_insn (gen_call (gen_rtx (MEM, FUNCTION_MODE, funexp), ! 3127: stack_size_rtx, next_arg_reg)); ! 3128: ! 3129: current_args_size = old_args_size; ! 3130: ! 3131: /* If returning from the subroutine does not automatically pop the args, ! 3132: we need an instruction to pop them sooner or later. ! 3133: Perhaps do it now; perhaps just record how much space to pop later. */ ! 3134: ! 3135: if (! RETURN_POPS_ARGS (TREE_TYPE (funtype)) ! 3136: && stack_size != 0) ! 3137: { ! 3138: if (flag_defer_pop && current_args_size == 0) ! 3139: pending_stack_adjust += stack_size; ! 3140: else ! 3141: adjust_stack (stack_size_rtx); ! 3142: } ! 3143: } ! 3144: ! 3145: /* At the start of a function, record that we have no previously-pushed ! 3146: arguments waiting to be popped. */ ! 3147: ! 3148: void ! 3149: init_pending_stack_adjust () ! 3150: { ! 3151: pending_stack_adjust = 0; ! 3152: } ! 3153: ! 3154: /* When exiting from function, if safe, clear out any pending stack adjust ! 3155: so the adjustment won't get done. */ ! 3156: ! 3157: void ! 3158: clear_pending_stack_adjust () ! 3159: { ! 3160: #if 0 ! 3161: /* Right now it's never considered safe, because ! 3162: it loses in an inline function. */ ! 3163: #ifdef EXIT_IGNORE_STACK ! 3164: if (!flag_omit_frame_pointer && EXIT_IGNORE_STACK) ! 3165: pending_stack_adjust = 0; ! 3166: #endif ! 3167: #endif ! 3168: } ! 3169: ! 3170: /* At start of function, initialize. */ ! 3171: void ! 3172: clear_current_args_size () ! 3173: { ! 3174: current_args_size = 0; ! 3175: } ! 3176: ! 3177: /* Pop any previously-pushed arguments that have not been popped yet. */ ! 3178: ! 3179: void ! 3180: do_pending_stack_adjust () ! 3181: { ! 3182: if (current_args_size == 0) ! 3183: { ! 3184: if (pending_stack_adjust != 0) ! 3185: adjust_stack (gen_rtx (CONST_INT, VOIDmode, pending_stack_adjust)); ! 3186: pending_stack_adjust = 0; ! 3187: } ! 3188: } ! 3189: ! 3190: /* Generate all the code for a function call ! 3191: and return an rtx for its value. ! 3192: Store the value in TARGET (specified as an rtx) if convenient. ! 3193: If the value is stored in TARGET then TARGET is returned. ! 3194: If IGNORE is nonzero, then we ignore the value of the function call. */ ! 3195: ! 3196: static rtx ! 3197: expand_call (exp, target, ignore) ! 3198: tree exp; ! 3199: rtx target; ! 3200: int ignore; ! 3201: { ! 3202: tree actparms = TREE_OPERAND (exp, 1); ! 3203: tree funtype; ! 3204: rtx funexp; ! 3205: register tree p = TREE_OPERAND (exp, 0); ! 3206: struct args_size args_size; ! 3207: register int i; ! 3208: register tree *argvec; ! 3209: rtx *regvec; ! 3210: rtx *valvec; ! 3211: int *partial; ! 3212: struct args_size *arg_offset; ! 3213: struct args_size *arg_size; ! 3214: int num_actuals; ! 3215: rtx structure_value_addr = 0; ! 3216: tree fndecl = 0; ! 3217: int may_be_alloca; ! 3218: int inc; ! 3219: int is_setjmp; ! 3220: int is_integrable = 0; ! 3221: rtx argblock = 0; ! 3222: CUMULATIVE_ARGS args_so_far; ! 3223: int reg_parm_seen = 0; ! 3224: rtx valreg; ! 3225: rtx old_stack_level; ! 3226: int old_pending_adj; ! 3227: int old_current_args_size = current_args_size; ! 3228: ! 3229: /* Number of named args. Args after this are anonymous ones ! 3230: and they must all go on the stack. */ ! 3231: int n_named_args; ! 3232: ! 3233: args_size.constant = 0; ! 3234: args_size.var = 0; ! 3235: ! 3236: /* See if we can find a DECL-node for the actual function. ! 3237: As a result, decide whether this is a call to an integrable function. */ ! 3238: ! 3239: if (TREE_CODE (p) == ADDR_EXPR) ! 3240: { ! 3241: fndecl = TREE_OPERAND (p, 0); ! 3242: if (TREE_CODE (fndecl) != FUNCTION_DECL) ! 3243: fndecl = 0; ! 3244: else ! 3245: { ! 3246: extern tree current_function_decl; ! 3247: ! 3248: if (fndecl != current_function_decl ! 3249: && DECL_SAVED_INSNS (fndecl)) ! 3250: is_integrable = 1; ! 3251: else ! 3252: /* In case this function later becomes inlineable, ! 3253: record that there was already a non-inline call to it. */ ! 3254: TREE_ADDRESSABLE (fndecl) = 1; ! 3255: } ! 3256: } ! 3257: ! 3258: /* Set up a place to return a structure. */ ! 3259: ! 3260: if (TYPE_MODE (TREE_TYPE (exp)) == BLKmode) ! 3261: { ! 3262: /* This call returns a big structure. */ ! 3263: if (target) ! 3264: structure_value_addr = XEXP (target, 0); ! 3265: else ! 3266: /* Make room on the stack to hold the value. */ ! 3267: structure_value_addr = get_structure_value_addr (expr_size (exp)); ! 3268: } ! 3269: ! 3270: if (is_integrable) ! 3271: { ! 3272: extern int integration_time; ! 3273: extern rtx expand_inline_function (); ! 3274: rtx temp; ! 3275: ! 3276: temp = expand_inline_function (fndecl, actparms, target, ! 3277: ignore, TREE_TYPE (exp), ! 3278: structure_value_addr); ! 3279: ! 3280: /* If the inlining failed for whatever reason, we will just ! 3281: issue a normal call. */ ! 3282: if (temp == (rtx)-1) ! 3283: { ! 3284: warning_with_decl (fndecl, "inlining function `%s' failed, reverting to function call"); ! 3285: } ! 3286: else ! 3287: return temp; ! 3288: } ! 3289: ! 3290: #if 0 ! 3291: /* Unless it's a call to a specific function that isn't alloca, ! 3292: if it has one argument, we must assume it might be alloca. */ ! 3293: ! 3294: may_be_alloca = ! 3295: (!(fndecl != 0 ! 3296: && strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), ! 3297: "alloca")) ! 3298: && actparms != 0 ! 3299: && TREE_CHAIN (actparms) == 0); ! 3300: #else ! 3301: /* We assume that alloca will always be called by name. It ! 3302: makes no sense to pass it as a pointer-to-function to ! 3303: anything that does not understand its behavior. */ ! 3304: may_be_alloca = ! 3305: (fndecl && ! strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "alloca")); ! 3306: #endif ! 3307: ! 3308: /* See if this is a call to a function that can return more than once. */ ! 3309: ! 3310: is_setjmp ! 3311: = (fndecl != 0 ! 3312: && (!strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "setjmp") ! 3313: || !strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "_setjmp"))); ! 3314: ! 3315: if (may_be_alloca) ! 3316: { ! 3317: frame_pointer_needed = 1; ! 3318: may_call_alloca = 1; ! 3319: } ! 3320: ! 3321: /* Don't let pending stack adjusts add up to too much. ! 3322: Also, do all pending adjustments now ! 3323: if there is any chance this might be a call to alloca. */ ! 3324: ! 3325: if (pending_stack_adjust >= 32 ! 3326: || (pending_stack_adjust > 0 && may_be_alloca)) ! 3327: do_pending_stack_adjust (); ! 3328: ! 3329: /* Operand 0 is a pointer-to-function; get the type of the function. */ ! 3330: funtype = TREE_TYPE (TREE_OPERAND (exp, 0)); ! 3331: if (TREE_CODE (funtype) != POINTER_TYPE) ! 3332: abort (); ! 3333: funtype = TREE_TYPE (funtype); ! 3334: ! 3335: /* Count the arguments and set NUM_ACTUALS. */ ! 3336: for (p = actparms, i = 0; p; p = TREE_CHAIN (p)) i++; ! 3337: num_actuals = i; ! 3338: ! 3339: /* Compute number of named args. ! 3340: This may actually be 1 too large, but that happens ! 3341: only in the case when all args are named, so no trouble results. */ ! 3342: if (TYPE_ARG_TYPES (funtype) != 0) ! 3343: n_named_args = list_length (TYPE_ARG_TYPES (funtype)); ! 3344: else ! 3345: /* If we know nothing, treat all args as named. */ ! 3346: n_named_args = num_actuals; ! 3347: ! 3348: /* Make a vector of the args, in the order we want to compute them, ! 3349: and a parallel vector of where we want to put them. ! 3350: regvec[I] is 0 to if should push argvec[I] or else a reg to put it in. ! 3351: valvec[i] is the arg value as an rtx. */ ! 3352: argvec = (tree *) alloca (i * sizeof (tree)); ! 3353: regvec = (rtx *) alloca (i * sizeof (rtx)); ! 3354: valvec = (rtx *) alloca (i * sizeof (rtx)); ! 3355: partial = (int *) alloca (i * sizeof (int)); ! 3356: arg_size = (struct args_size *) alloca (i * sizeof (struct args_size)); ! 3357: arg_offset = (struct args_size *) alloca (i * sizeof (struct args_size)); ! 3358: ! 3359: /* In this loop, we consider args in the order they are written. ! 3360: We fill up argvec from the front of from the back ! 3361: so that the first arg to be pushed ends up at the front. */ ! 3362: ! 3363: #ifdef PUSH_ARGS_REVERSED ! 3364: i = num_actuals - 1, inc = -1; ! 3365: /* In this case, must reverse order of args ! 3366: so that we compute and push the last arg first. */ ! 3367: #else ! 3368: i = 0, inc = 1; ! 3369: #endif ! 3370: ! 3371: INIT_CUMULATIVE_ARGS (args_so_far, funtype); ! 3372: ! 3373: for (p = actparms; p; p = TREE_CHAIN (p), i += inc) ! 3374: { ! 3375: tree type = TREE_TYPE (TREE_VALUE (p)); ! 3376: argvec[i] = p; ! 3377: regvec[i] = 0; ! 3378: valvec[i] = 0; ! 3379: partial[i] = 0; ! 3380: arg_size[i].constant = 0; ! 3381: arg_size[i].var = 0; ! 3382: arg_offset[i] = args_size; ! 3383: ! 3384: if (type == error_mark_node) ! 3385: continue; ! 3386: ! 3387: /* Decide where to pass this arg. */ ! 3388: /* regvec[i] is nonzero if all or part is passed in registers. ! 3389: partial[i] is nonzero if part but not all is passed in registers, ! 3390: and the exact value says how many words are passed in registers. */ ! 3391: ! 3392: if (TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST ! 3393: || args_size.var != 0) ! 3394: { ! 3395: regvec[i] = FUNCTION_ARG (args_so_far, TYPE_MODE (type), type, ! 3396: i < n_named_args); ! 3397: #ifdef FUNCTION_ARG_PARTIAL_NREGS ! 3398: partial[i] = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, ! 3399: TYPE_MODE (type), type, ! 3400: i < n_named_args); ! 3401: #endif ! 3402: } ! 3403: ! 3404: /* Once we see at least one parm that is being passed in a register, ! 3405: precompute that parm and all remaining parms (if they do arithmetic) ! 3406: before loading any of them into their specified registers. ! 3407: That way we don't lose if one of them involves ! 3408: a function call OR a library routine that needs the same regs. */ ! 3409: if (regvec[i] != 0) ! 3410: reg_parm_seen = 1; ! 3411: ! 3412: if (reg_parm_seen) ! 3413: { ! 3414: valvec[i] = expand_expr (TREE_VALUE (p), 0, VOIDmode, 0); ! 3415: if (GET_CODE (valvec[i]) != MEM ! 3416: && ! CONSTANT_P (valvec[i]) ! 3417: && GET_CODE (valvec[i]) != CONST_DOUBLE) ! 3418: valvec[i] = force_reg (TYPE_MODE (type), valvec[i]); ! 3419: } ! 3420: ! 3421: /* Increment ARGS_SO_FAR, which has info about which arg-registers ! 3422: have been used, etc. */ ! 3423: ! 3424: FUNCTION_ARG_ADVANCE (args_so_far, TYPE_MODE (type), type, ! 3425: i < n_named_args); ! 3426: ! 3427: /* Increment ARGS_SIZE, which is the size of all args so far. */ ! 3428: ! 3429: if (regvec[i] != 0 && partial[i] == 0) ! 3430: /* A register-arg doesn't count. */ ! 3431: ; ! 3432: else if (TYPE_MODE (type) != BLKmode) ! 3433: { ! 3434: register int size; ! 3435: ! 3436: size = GET_MODE_SIZE (TYPE_MODE (type)); ! 3437: /* Compute how much space the push instruction will push. ! 3438: On many machines, pushing a byte will advance the stack ! 3439: pointer by a halfword. */ ! 3440: #ifdef PUSH_ROUNDING ! 3441: size = PUSH_ROUNDING (size); ! 3442: #endif ! 3443: /* Compute how much space the argument should get: ! 3444: round up to a multiple of the alignment for arguments. */ ! 3445: arg_size[i].constant ! 3446: = (((size + PARM_BOUNDARY / BITS_PER_UNIT - 1) ! 3447: / (PARM_BOUNDARY / BITS_PER_UNIT)) ! 3448: * (PARM_BOUNDARY / BITS_PER_UNIT)); ! 3449: } ! 3450: else ! 3451: { ! 3452: register tree size = size_in_bytes (type); ! 3453: ! 3454: /* A nonscalar. Round its size up to a multiple ! 3455: of the allocation unit for arguments. */ ! 3456: ! 3457: /* Now round up to multiple of PARM_BOUNDARY bits, ! 3458: then express as number of bytes. */ ! 3459: ADD_PARM_SIZE (arg_size[i], ! 3460: convert_units (convert_units (size, BITS_PER_UNIT, PARM_BOUNDARY), ! 3461: PARM_BOUNDARY, BITS_PER_UNIT)); ! 3462: ! 3463: } ! 3464: /* If a part of the arg was put into registers, ! 3465: don't include that part in the amount pushed. */ ! 3466: arg_size[i].constant ! 3467: -= ((partial[i] * UNITS_PER_WORD) ! 3468: / (PARM_BOUNDARY / BITS_PER_UNIT) ! 3469: * (PARM_BOUNDARY / BITS_PER_UNIT)); ! 3470: ! 3471: args_size.constant += arg_size[i].constant; ! 3472: ! 3473: if (arg_size[i].var) ! 3474: { ! 3475: ADD_PARM_SIZE (args_size, arg_size[i].var); ! 3476: } ! 3477: } ! 3478: ! 3479: /* If we have no actual push instructions, or we need a variable ! 3480: amount of space, make space for all the args right now. ! 3481: In any case, round the needed size up to multiple of STACK_BOUNDARY. */ ! 3482: ! 3483: if (args_size.var != 0) ! 3484: { ! 3485: old_stack_level = copy_to_mode_reg (Pmode, stack_pointer_rtx); ! 3486: old_pending_adj = pending_stack_adjust; ! 3487: argblock = push_block (round_push (ARGS_SIZE_RTX (args_size))); ! 3488: } ! 3489: else if (args_size.constant != 0) ! 3490: { ! 3491: int needed = args_size.constant; ! 3492: ! 3493: #ifdef STACK_BOUNDARY ! 3494: needed = (needed + STACK_BYTES - 1) / STACK_BYTES * STACK_BYTES; ! 3495: args_size.constant = needed; ! 3496: #endif ! 3497: ! 3498: #ifndef PUSH_ROUNDING ! 3499: /* Try to reuse some or all of the pending_stack_adjust ! 3500: to get this space. Maybe we can avoid any pushing. */ ! 3501: if (needed > pending_stack_adjust) ! 3502: { ! 3503: needed -= pending_stack_adjust; ! 3504: pending_stack_adjust = 0; ! 3505: } ! 3506: else ! 3507: { ! 3508: pending_stack_adjust -= needed; ! 3509: needed = 0; ! 3510: } ! 3511: argblock = push_block (gen_rtx (CONST_INT, VOIDmode, needed)); ! 3512: #endif /* no PUSH_ROUNDING */ ! 3513: } ! 3514: ! 3515: /* Get the function to call, in the form of RTL. */ ! 3516: if (fndecl) ! 3517: /* Get a SYMBOL_REF rtx for the function address. */ ! 3518: funexp = XEXP (DECL_RTL (fndecl), 0); ! 3519: else ! 3520: /* Generate an rtx (probably a pseudo-register) for the address. */ ! 3521: funexp = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0); ! 3522: ! 3523: /* Now actually compute the args, and push those that need pushing. */ ! 3524: ! 3525: for (i = 0; i < num_actuals; i++) ! 3526: { ! 3527: register tree p = argvec[i]; ! 3528: register tree pval = TREE_VALUE (p); ! 3529: int used = 0; ! 3530: ! 3531: /* Push the next argument. Note that it has already been converted ! 3532: if necessary to the type that the called function expects. */ ! 3533: ! 3534: if (TREE_CODE (pval) == ERROR_MARK) ! 3535: ; ! 3536: else if (regvec[i] != 0 && partial[i] == 0) ! 3537: { ! 3538: /* Being passed entirely in a register. */ ! 3539: if (valvec[i] != 0) ! 3540: { ! 3541: if (GET_MODE (valvec[i]) == BLKmode) ! 3542: move_block_to_reg (REGNO (regvec[i]), valvec[i], ! 3543: (int_size_in_bytes (TREE_TYPE (pval)) ! 3544: / UNITS_PER_WORD)); ! 3545: else ! 3546: emit_move_insn (regvec[i], valvec[i]); ! 3547: } ! 3548: else ! 3549: store_expr (pval, regvec[i], 0); ! 3550: ! 3551: /* Don't allow anything left on stack from computation ! 3552: of argument to alloca. */ ! 3553: if (may_be_alloca) ! 3554: do_pending_stack_adjust (); ! 3555: } ! 3556: else if (TYPE_MODE (TREE_TYPE (pval)) != BLKmode) ! 3557: { ! 3558: register int size; ! 3559: rtx tem; ! 3560: ! 3561: /* Argument is a scalar, not entirely passed in registers. ! 3562: (If part is passed in registers, partial[I] says how much ! 3563: and emit_push_insn will take care of putting it there.) ! 3564: ! 3565: Push it, and if its size is less than the ! 3566: amount of space allocated to it, ! 3567: also bump stack pointer by the additional space. ! 3568: Note that in C the default argument promotions ! 3569: will prevent such mismatches. */ ! 3570: ! 3571: used = size = GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (pval))); ! 3572: /* Compute how much space the push instruction will push. ! 3573: On many machines, pushing a byte will advance the stack ! 3574: pointer by a halfword. */ ! 3575: #ifdef PUSH_ROUNDING ! 3576: size = PUSH_ROUNDING (size); ! 3577: #endif ! 3578: /* Compute how much space the argument should get: ! 3579: round up to a multiple of the alignment for arguments. */ ! 3580: used = (((size + PARM_BOUNDARY / BITS_PER_UNIT - 1) ! 3581: / (PARM_BOUNDARY / BITS_PER_UNIT)) ! 3582: * (PARM_BOUNDARY / BITS_PER_UNIT)); ! 3583: ! 3584: tem = valvec[i]; ! 3585: if (tem == 0) ! 3586: tem = expand_expr (pval, 0, VOIDmode, 0); ! 3587: ! 3588: /* Don't allow anything left on stack from computation ! 3589: of argument to alloca. */ ! 3590: if (may_be_alloca) ! 3591: do_pending_stack_adjust (); ! 3592: ! 3593: emit_push_insn (tem, TYPE_MODE (TREE_TYPE (pval)), 0, 0, ! 3594: partial[i], regvec[i], used - size, ! 3595: argblock, ARGS_SIZE_RTX (arg_offset[i])); ! 3596: } ! 3597: else ! 3598: { ! 3599: register rtx tem ! 3600: = valvec[i] ? valvec[i] : expand_expr (pval, 0, VOIDmode, 0); ! 3601: register int excess; ! 3602: rtx size_rtx; ! 3603: ! 3604: /* Pushing a nonscalar. ! 3605: If part is passed in registers, partial[I] says how much ! 3606: and emit_push_insn will take care of putting it there. */ ! 3607: ! 3608: /* Round its size up to a multiple ! 3609: of the allocation unit for arguments. */ ! 3610: ! 3611: if (arg_size[i].var != 0) ! 3612: { ! 3613: excess = 0; ! 3614: size_rtx = ARGS_SIZE_RTX (arg_size[i]); ! 3615: } ! 3616: else ! 3617: { ! 3618: register tree size = size_in_bytes (TREE_TYPE (pval)); ! 3619: /* PUSH_ROUNDING has no effect on us, because ! 3620: emit_push_insn for BLKmode is careful to avoid it. */ ! 3621: excess = arg_size[i].constant - TREE_INT_CST_LOW (size); ! 3622: size_rtx = expand_expr (size, 0, VOIDmode, 0); ! 3623: } ! 3624: ! 3625: emit_push_insn (tem, TYPE_MODE (TREE_TYPE (pval)), size_rtx, ! 3626: TYPE_ALIGN (TREE_TYPE (pval)) / BITS_PER_UNIT, ! 3627: partial[i], regvec[i], excess, argblock, ! 3628: ARGS_SIZE_RTX (arg_offset[i])); ! 3629: } ! 3630: ! 3631: /* Account for the stack space thus used. */ ! 3632: ! 3633: ! 3634: current_args_size += arg_size[i].constant; ! 3635: if (arg_size[i].var) ! 3636: current_args_size += 1; ! 3637: } ! 3638: ! 3639: /* Perform postincrements before actually calling the function. */ ! 3640: emit_queue (); ! 3641: ! 3642: /* Pass the function the address in which to return a structure value. */ ! 3643: if (structure_value_addr) ! 3644: emit_move_insn (struct_value_rtx, structure_value_addr); ! 3645: ! 3646: /* All arguments and registers used for the call must be set up by now! */ ! 3647: ! 3648: /* ??? Other languages need a nontrivial second argument (static chain). */ ! 3649: funexp = prepare_call_address (funexp, 0); ! 3650: ! 3651: /* Mark all register-parms as living through the call. ! 3652: ??? This is not quite correct, since it doesn't indicate ! 3653: that they are in use immediately before the call insn. ! 3654: Currently that doesn't matter since explicitly-used regs ! 3655: won't be used for reloading. But if the reloader becomes smarter, ! 3656: this will have to change somehow. */ ! 3657: for (i = 0; i < num_actuals; i++) ! 3658: if (regvec[i] != 0) ! 3659: { ! 3660: if (partial[i] > 0) ! 3661: use_regs (REGNO (regvec[i]), partial[i]); ! 3662: else if (GET_MODE (regvec[i]) == BLKmode) ! 3663: use_regs (REGNO (regvec[i]), ! 3664: (int_size_in_bytes (TREE_TYPE (TREE_VALUE (argvec[i]))) ! 3665: / UNITS_PER_WORD)); ! 3666: else ! 3667: emit_insn (gen_rtx (USE, VOIDmode, regvec[i])); ! 3668: } ! 3669: ! 3670: if (structure_value_addr) ! 3671: emit_insn (gen_rtx (USE, VOIDmode, struct_value_rtx)); ! 3672: ! 3673: /* Figure out the register where the value, if any, will come back. */ ! 3674: valreg = 0; ! 3675: if (TYPE_MODE (TREE_TYPE (exp)) != VOIDmode ! 3676: && TYPE_MODE (TREE_TYPE (exp)) != BLKmode) ! 3677: valreg = hard_function_value (TREE_TYPE (exp), fndecl); ! 3678: ! 3679: /* Generate the actual call instruction. */ ! 3680: emit_call_1 (funexp, funtype, args_size.constant, ! 3681: FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1), ! 3682: valreg, old_current_args_size); ! 3683: ! 3684: /* ??? Nothing has been done here to record control flow ! 3685: when contained functions can do nonlocal gotos. */ ! 3686: ! 3687: /* For calls to `setjmp', etc., inform flow.c it should complain ! 3688: if nonvolatile values are live. */ ! 3689: ! 3690: if (is_setjmp) ! 3691: emit_note (IDENTIFIER_POINTER (DECL_NAME (fndecl)), NOTE_INSN_SETJMP); ! 3692: ! 3693: /* If size of args is variable, restore saved stack-pointer value. */ ! 3694: ! 3695: if (args_size.var != 0) ! 3696: { ! 3697: emit_move_insn (stack_pointer_rtx, old_stack_level); ! 3698: pending_stack_adjust = old_pending_adj; ! 3699: } ! 3700: ! 3701: /* If value type not void, return an rtx for the value. */ ! 3702: ! 3703: if (TYPE_MODE (TREE_TYPE (exp)) == VOIDmode ! 3704: || ignore) ! 3705: return 0; ! 3706: ! 3707: if (structure_value_addr) ! 3708: { ! 3709: if (target) ! 3710: return target; ! 3711: return gen_rtx (MEM, BLKmode, ! 3712: memory_address (BLKmode, structure_value_addr)); ! 3713: } ! 3714: ! 3715: if (target && GET_MODE (target) == TYPE_MODE (TREE_TYPE (exp))) ! 3716: { ! 3717: if (!rtx_equal_p (target, valreg)) ! 3718: emit_move_insn (target, valreg); ! 3719: else ! 3720: /* This tells expand_inline_function to copy valreg to its target. */ ! 3721: emit_insn (gen_rtx (USE, VOIDmode, valreg)); ! 3722: return target; ! 3723: } ! 3724: return copy_to_reg (valreg); ! 3725: } ! 3726: ! 3727: /* Expand conditional expressions. */ ! 3728: ! 3729: /* Generate code to evaluate EXP and jump to LABEL if the value is zero. ! 3730: LABEL is an rtx of code CODE_LABEL, in this function and all the ! 3731: functions here. */ ! 3732: ! 3733: void ! 3734: jumpifnot (exp, label) ! 3735: tree exp; ! 3736: rtx label; ! 3737: { ! 3738: do_jump (exp, label, 0); ! 3739: } ! 3740: ! 3741: /* Generate code to evaluate EXP and jump to LABEL if the value is nonzero. */ ! 3742: ! 3743: void ! 3744: jumpif (exp, label) ! 3745: tree exp; ! 3746: rtx label; ! 3747: { ! 3748: do_jump (exp, 0, label); ! 3749: } ! 3750: ! 3751: /* Generate code to evaluate EXP and jump to IF_FALSE_LABEL if ! 3752: the result is zero, or IF_TRUE_LABEL if the result is one. ! 3753: Either of IF_FALSE_LABEL and IF_TRUE_LABEL may be zero, ! 3754: meaning fall through in that case. ! 3755: ! 3756: This function is responsible for optimizing cases such as ! 3757: &&, || and comparison operators in EXP. */ ! 3758: ! 3759: void ! 3760: do_jump (exp, if_false_label, if_true_label) ! 3761: tree exp; ! 3762: rtx if_false_label, if_true_label; ! 3763: { ! 3764: register enum tree_code code = TREE_CODE (exp); ! 3765: /* Some cases need to create a label to jump to ! 3766: in order to properly fall through. ! 3767: These cases set DROP_THROUGH_LABEL nonzero. */ ! 3768: rtx drop_through_label = 0; ! 3769: rtx temp; ! 3770: rtx comparison = 0; ! 3771: ! 3772: emit_queue (); ! 3773: ! 3774: switch (code) ! 3775: { ! 3776: case ERROR_MARK: ! 3777: break; ! 3778: ! 3779: case INTEGER_CST: ! 3780: temp = integer_zerop (exp) ? if_false_label : if_true_label; ! 3781: if (temp) ! 3782: emit_jump (temp); ! 3783: break; ! 3784: ! 3785: case ADDR_EXPR: ! 3786: /* The address of something can never be zero. */ ! 3787: if (if_true_label) ! 3788: emit_jump (if_true_label); ! 3789: break; ! 3790: ! 3791: case NOP_EXPR: ! 3792: do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label); ! 3793: break; ! 3794: ! 3795: case TRUTH_NOT_EXPR: ! 3796: do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label); ! 3797: break; ! 3798: ! 3799: case TRUTH_ANDIF_EXPR: ! 3800: if (if_false_label == 0) ! 3801: if_false_label = drop_through_label = gen_label_rtx (); ! 3802: do_jump (TREE_OPERAND (exp, 0), if_false_label, 0); ! 3803: do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label); ! 3804: break; ! 3805: ! 3806: case TRUTH_ORIF_EXPR: ! 3807: if (if_true_label == 0) ! 3808: if_true_label = drop_through_label = gen_label_rtx (); ! 3809: do_jump (TREE_OPERAND (exp, 0), 0, if_true_label); ! 3810: do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label); ! 3811: break; ! 3812: ! 3813: case COMPOUND_EXPR: ! 3814: expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0); ! 3815: emit_queue (); ! 3816: do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label); ! 3817: break; ! 3818: ! 3819: case COND_EXPR: ! 3820: { ! 3821: register rtx label1 = gen_label_rtx (); ! 3822: drop_through_label = gen_label_rtx (); ! 3823: do_jump (TREE_OPERAND (exp, 0), label1, 0); ! 3824: /* Now the THEN-expression. */ ! 3825: do_jump (TREE_OPERAND (exp, 1), ! 3826: if_false_label ? if_false_label : drop_through_label, ! 3827: if_true_label ? if_true_label : drop_through_label); ! 3828: emit_label (label1); ! 3829: /* Now the ELSE-expression. */ ! 3830: do_jump (TREE_OPERAND (exp, 2), ! 3831: if_false_label ? if_false_label : drop_through_label, ! 3832: if_true_label ? if_true_label : drop_through_label); ! 3833: } ! 3834: break; ! 3835: ! 3836: case EQ_EXPR: ! 3837: comparison = compare (exp, EQ, EQ, EQ, EQ); ! 3838: break; ! 3839: ! 3840: case NE_EXPR: ! 3841: comparison = compare (exp, NE, NE, NE, NE); ! 3842: break; ! 3843: ! 3844: case LT_EXPR: ! 3845: comparison = compare (exp, LT, LTU, GT, GTU); ! 3846: break; ! 3847: ! 3848: case LE_EXPR: ! 3849: comparison = compare (exp, LE, LEU, GE, GEU); ! 3850: break; ! 3851: ! 3852: case GT_EXPR: ! 3853: comparison = compare (exp, GT, GTU, LT, LTU); ! 3854: break; ! 3855: ! 3856: case GE_EXPR: ! 3857: comparison = compare (exp, GE, GEU, LE, LEU); ! 3858: break; ! 3859: ! 3860: default: ! 3861: temp = expand_expr (exp, 0, VOIDmode, 0); ! 3862: /* Copy to register to avoid generating bad insns by cse ! 3863: from (set (mem ...) (arithop)) (set (cc0) (mem ...)). */ ! 3864: if (!cse_not_expected && GET_CODE (temp) == MEM) ! 3865: temp = copy_to_reg (temp); ! 3866: do_pending_stack_adjust (); ! 3867: { ! 3868: rtx zero; ! 3869: if (GET_MODE (temp) == SFmode) ! 3870: zero = fconst0_rtx; ! 3871: else if (GET_MODE (temp) == DFmode) ! 3872: zero = dconst0_rtx; ! 3873: else ! 3874: zero = const0_rtx; ! 3875: ! 3876: if (GET_CODE (temp) == CONST_INT) ! 3877: comparison = compare_constants (NE, 0, ! 3878: INTVAL (temp), 0, BITS_PER_WORD); ! 3879: else if (GET_MODE (temp) != VOIDmode) ! 3880: comparison = compare1 (temp, zero, NE, NE, 0, GET_MODE (temp)); ! 3881: else ! 3882: abort (); ! 3883: } ! 3884: } ! 3885: ! 3886: /* Do any postincrements in the expression that was tested. */ ! 3887: emit_queue (); ! 3888: ! 3889: /* If COMPARISON is nonzero here, it is an rtx that can be substituted ! 3890: straight into a conditional jump instruction as the jump condition. ! 3891: Otherwise, all the work has been done already. */ ! 3892: ! 3893: if (comparison == const1_rtx) ! 3894: { ! 3895: if (if_true_label) ! 3896: emit_jump (if_true_label); ! 3897: } ! 3898: else if (comparison == const0_rtx) ! 3899: { ! 3900: if (if_false_label) ! 3901: emit_jump (if_false_label); ! 3902: } ! 3903: else if (comparison) ! 3904: { ! 3905: if (if_true_label) ! 3906: { ! 3907: emit_jump_insn (gen_rtx (SET, VOIDmode, pc_rtx, ! 3908: gen_rtx (IF_THEN_ELSE, VOIDmode, comparison, ! 3909: gen_rtx (LABEL_REF, VOIDmode, ! 3910: if_true_label), ! 3911: pc_rtx))); ! 3912: if (if_false_label) ! 3913: emit_jump (if_false_label); ! 3914: } ! 3915: else if (if_false_label) ! 3916: { ! 3917: emit_jump_insn (gen_rtx (SET, VOIDmode, pc_rtx, ! 3918: gen_rtx (IF_THEN_ELSE, VOIDmode, comparison, ! 3919: pc_rtx, ! 3920: gen_rtx (LABEL_REF, VOIDmode, ! 3921: if_false_label)))); ! 3922: } ! 3923: } ! 3924: ! 3925: if (drop_through_label) ! 3926: emit_label (drop_through_label); ! 3927: } ! 3928: ! 3929: /* Compare two integer constant rtx's, OP0 and OP1. ! 3930: The comparison operation is OPERATION. ! 3931: Return an rtx representing the value 1 or 0. ! 3932: WIDTH is the width in bits that is significant. */ ! 3933: ! 3934: static rtx ! 3935: compare_constants (operation, unsignedp, op0, op1, width) ! 3936: enum rtx_code operation; ! 3937: int unsignedp; ! 3938: int op0, op1; ! 3939: int width; ! 3940: { ! 3941: int val; ! 3942: ! 3943: /* Sign-extend or zero-extend the operands to a full word ! 3944: from an initial width of WIDTH bits. */ ! 3945: if (width < HOST_BITS_PER_INT) ! 3946: { ! 3947: op0 &= (1 << width) - 1; ! 3948: op1 &= (1 << width) - 1; ! 3949: ! 3950: if (! unsignedp) ! 3951: { ! 3952: if (op0 & (1 << (width - 1))) ! 3953: op0 |= ((-1) << width); ! 3954: if (op1 & (1 << (width - 1))) ! 3955: op1 |= ((-1) << width); ! 3956: } ! 3957: } ! 3958: ! 3959: switch (operation) ! 3960: { ! 3961: case EQ: ! 3962: val = op0 == op1; ! 3963: break; ! 3964: ! 3965: case NE: ! 3966: val = op0 != op1; ! 3967: break; ! 3968: ! 3969: case GT: ! 3970: case GTU: ! 3971: val = op0 > op1; ! 3972: break; ! 3973: ! 3974: case LT: ! 3975: case LTU: ! 3976: val = op0 < op1; ! 3977: break; ! 3978: ! 3979: case GE: ! 3980: case GEU: ! 3981: val = op0 >= op1; ! 3982: break; ! 3983: ! 3984: case LE: ! 3985: case LEU: ! 3986: val = op0 <= op1; ! 3987: } ! 3988: ! 3989: return val ? const1_rtx : const0_rtx; ! 3990: } ! 3991: ! 3992: /* Generate code for a comparison expression EXP ! 3993: (including code to compute the values to be compared) ! 3994: and set (CC0) according to the result. ! 3995: SIGNED_FORWARD should be the rtx operation for this comparison for ! 3996: signed data; UNSIGNED_FORWARD, likewise for use if data is unsigned. ! 3997: SIGNED_REVERSE and UNSIGNED_REVERSE are used if it is desirable ! 3998: to interchange the operands for the compare instruction. ! 3999: ! 4000: We force a stack adjustment unless there are currently ! 4001: things pushed on the stack that aren't yet used. */ ! 4002: ! 4003: static rtx ! 4004: compare (exp, signed_forward, unsigned_forward, ! 4005: signed_reverse, unsigned_reverse) ! 4006: register tree exp; ! 4007: enum rtx_code signed_forward, unsigned_forward; ! 4008: enum rtx_code signed_reverse, unsigned_reverse; ! 4009: { ! 4010: ! 4011: register rtx op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0); ! 4012: register rtx op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0); ! 4013: register enum machine_mode mode = GET_MODE (op0); ! 4014: int unsignedp; ! 4015: ! 4016: /* If one operand is 0, make it the second one. */ ! 4017: ! 4018: if (op0 == const0_rtx || op0 == fconst0_rtx || op0 == dconst0_rtx) ! 4019: { ! 4020: rtx tem = op0; ! 4021: op0 = op1; ! 4022: op1 = tem; ! 4023: signed_forward = signed_reverse; ! 4024: unsigned_forward = unsigned_reverse; ! 4025: } ! 4026: ! 4027: if (flag_force_mem) ! 4028: { ! 4029: op0 = force_not_mem (op0); ! 4030: op1 = force_not_mem (op1); ! 4031: } ! 4032: ! 4033: do_pending_stack_adjust (); ! 4034: ! 4035: unsignedp = (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))) ! 4036: || TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 1)))); ! 4037: ! 4038: if (GET_CODE (op0) == CONST_INT && GET_CODE (op1) == CONST_INT) ! 4039: return compare_constants (signed_forward, unsignedp, ! 4040: INTVAL (op0), INTVAL (op1), ! 4041: GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))); ! 4042: ! 4043: emit_cmp_insn (op0, op1, ! 4044: (mode == BLKmode) ? expr_size (TREE_OPERAND (exp, 0)) : 0, ! 4045: unsignedp); ! 4046: ! 4047: return gen_rtx ((unsignedp ? unsigned_forward : signed_forward), ! 4048: VOIDmode, cc0_rtx, const0_rtx); ! 4049: } ! 4050: ! 4051: /* Like compare but expects the values to compare as two rtx's. ! 4052: The decision as to signed or unsigned comparison must be made by the caller. ! 4053: BLKmode is not allowed. */ ! 4054: ! 4055: static rtx ! 4056: compare1 (op0, op1, forward_op, reverse_op, unsignedp, mode) ! 4057: register rtx op0, op1; ! 4058: enum rtx_code forward_op, reverse_op; ! 4059: int unsignedp; ! 4060: enum machine_mode mode; ! 4061: { ! 4062: /* If one operand is 0, make it the second one. */ ! 4063: ! 4064: if (op0 == const0_rtx || op0 == fconst0_rtx || op0 == dconst0_rtx) ! 4065: { ! 4066: rtx tem = op0; ! 4067: op0 = op1; ! 4068: op1 = tem; ! 4069: forward_op = reverse_op; ! 4070: } ! 4071: ! 4072: if (flag_force_mem) ! 4073: { ! 4074: op0 = force_not_mem (op0); ! 4075: op1 = force_not_mem (op1); ! 4076: } ! 4077: ! 4078: do_pending_stack_adjust (); ! 4079: ! 4080: if (GET_CODE (op0) == CONST_INT && GET_CODE (op1) == CONST_INT) ! 4081: return compare_constants (forward_op, unsignedp, ! 4082: INTVAL (op0), INTVAL (op1), ! 4083: GET_MODE_BITSIZE (mode)); ! 4084: ! 4085: emit_cmp_insn (op0, op1, 0, unsignedp); ! 4086: ! 4087: return gen_rtx (forward_op, VOIDmode, cc0_rtx, const0_rtx); ! 4088: } ! 4089: ! 4090: /* Generate code to calculate EXP using a store-flag instruction ! 4091: and return an rtx for the result. ! 4092: If TARGET is nonzero, store the result there if convenient. ! 4093: ! 4094: Return zero if there is no suitable set-flag instruction ! 4095: available on this machine. */ ! 4096: ! 4097: static rtx ! 4098: do_store_flag (exp, target, mode) ! 4099: tree exp; ! 4100: rtx target; ! 4101: enum machine_mode mode; ! 4102: { ! 4103: register enum tree_code code = TREE_CODE (exp); ! 4104: register rtx comparison = 0; ! 4105: enum machine_mode compare_mode; ! 4106: ! 4107: switch (code) ! 4108: { ! 4109: #ifdef HAVE_seq ! 4110: case EQ_EXPR: ! 4111: if (HAVE_seq) ! 4112: { ! 4113: comparison = compare (exp, EQ, EQ, EQ, EQ); ! 4114: compare_mode = insn_operand_mode[(int) CODE_FOR_seq][0]; ! 4115: } ! 4116: break; ! 4117: #endif ! 4118: ! 4119: #ifdef HAVE_sne ! 4120: case NE_EXPR: ! 4121: if (HAVE_sne) ! 4122: { ! 4123: comparison = compare (exp, NE, NE, NE, NE); ! 4124: compare_mode = insn_operand_mode[(int) CODE_FOR_sne][0]; ! 4125: } ! 4126: break; ! 4127: #endif ! 4128: ! 4129: #if defined (HAVE_slt) && defined (HAVE_sltu) && defined (HAVE_sgt) && defined (HAVE_sgtu) ! 4130: case LT_EXPR: ! 4131: if (HAVE_slt && HAVE_sltu && HAVE_sgt && HAVE_sgtu) ! 4132: { ! 4133: comparison = compare (exp, LT, LTU, GT, GTU); ! 4134: compare_mode = insn_operand_mode[(int) CODE_FOR_slt][0]; ! 4135: } ! 4136: break; ! 4137: ! 4138: case GT_EXPR: ! 4139: if (HAVE_slt && HAVE_sltu && HAVE_sgt && HAVE_sgtu) ! 4140: { ! 4141: comparison = compare (exp, GT, GTU, LT, LTU); ! 4142: compare_mode = insn_operand_mode[(int) CODE_FOR_slt][0]; ! 4143: } ! 4144: break; ! 4145: #endif ! 4146: ! 4147: #if defined (HAVE_sle) && defined (HAVE_sleu) && defined (HAVE_sge) && defined (HAVE_sgeu) ! 4148: case LE_EXPR: ! 4149: if (HAVE_sle && HAVE_sleu && HAVE_sge && HAVE_sgeu) ! 4150: { ! 4151: comparison = compare (exp, LE, LEU, GE, GEU); ! 4152: compare_mode = insn_operand_mode[(int) CODE_FOR_sle][0]; ! 4153: } ! 4154: break; ! 4155: ! 4156: case GE_EXPR: ! 4157: if (HAVE_sle && HAVE_sleu && HAVE_sge && HAVE_sgeu) ! 4158: { ! 4159: comparison = compare (exp, GE, GEU, LE, LEU); ! 4160: compare_mode = insn_operand_mode[(int) CODE_FOR_sle][0]; ! 4161: } ! 4162: break; ! 4163: #endif ! 4164: } ! 4165: if (comparison == 0) ! 4166: return 0; ! 4167: ! 4168: if (target == 0 || GET_MODE (target) != mode ! 4169: || (mode != compare_mode && GET_CODE (target) != REG)) ! 4170: target = gen_reg_rtx (mode); ! 4171: ! 4172: /* Store the comparison in its proper mode. */ ! 4173: if (GET_MODE (target) != compare_mode) ! 4174: emit_insn (gen_rtx (SET, VOIDmode, ! 4175: gen_rtx (SUBREG, compare_mode, target, 0), ! 4176: comparison)); ! 4177: else ! 4178: emit_insn (gen_rtx (SET, VOIDmode, target, comparison)); ! 4179: ! 4180: #if STORE_FLAG_VALUE != 1 ! 4181: expand_bit_and (mode, target, const1_rtx, target); ! 4182: #endif ! 4183: return target; ! 4184: } ! 4185: ! 4186: /* Generate a tablejump instruction (used for switch statements). */ ! 4187: ! 4188: #ifdef HAVE_tablejump ! 4189: ! 4190: /* INDEX is the value being switched on, with the lowest value ! 4191: in the table already subtracted. ! 4192: RANGE is the length of the jump table. ! 4193: TABLE_LABEL is a CODE_LABEL rtx for the table itself. ! 4194: ! 4195: DEFAULT_LABEL is a CODE_LABEL rtx to jump to if the ! 4196: index value is out of range. */ ! 4197: ! 4198: void ! 4199: do_tablejump (index, range, table_label, default_label) ! 4200: rtx index, range, table_label, default_label; ! 4201: { ! 4202: register rtx temp; ! 4203: ! 4204: emit_cmp_insn (range, index, 0); ! 4205: emit_jump_insn (gen_bltu (default_label)); ! 4206: index = memory_address (CASE_VECTOR_MODE, ! 4207: gen_rtx (PLUS, Pmode, ! 4208: gen_rtx (MULT, Pmode, index, ! 4209: gen_rtx (CONST_INT, VOIDmode, ! 4210: GET_MODE_SIZE (CASE_VECTOR_MODE))), ! 4211: gen_rtx (LABEL_REF, VOIDmode, table_label))); ! 4212: temp = gen_reg_rtx (CASE_VECTOR_MODE); ! 4213: convert_move (temp, gen_rtx (MEM, CASE_VECTOR_MODE, index), 0); ! 4214: ! 4215: emit_jump_insn (gen_tablejump (temp, table_label)); ! 4216: } ! 4217: ! 4218: #endif /* HAVE_tablejump */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.