|
|
1.1 ! root 1: /* Convert tree expression to rtl instructions, for GNU compiler. ! 2: Copyright (C) 1987 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 "insn-flags.h" ! 26: #include "insn-codes.h" ! 27: #include "expr.h" ! 28: ! 29: /* If this is nonzero, we do not bother generating VOLATILE ! 30: around volatile memory references, and we are willing to ! 31: output indirect addresses. If cse is to follow, we reject ! 32: indirect addresses so a useful potential cse is generated; ! 33: if it is used only once, instruction combination will produce ! 34: the same indirect address eventually. */ ! 35: int cse_not_expected; ! 36: ! 37: /* Nonzero to generate code for all the subroutines within an ! 38: expression before generating the upper levels of the expression. ! 39: Nowadays this is never zero. */ ! 40: int do_preexpand_calls = 1; ! 41: ! 42: /* Number of units that we should eventually pop off the stack. ! 43: These are the arguments to function calls that have already returned. */ ! 44: int pending_stack_adjust; ! 45: ! 46: /* Total size of arguments already pushed for function calls that ! 47: have not happened yet. Also counts 1 for each level of conditional ! 48: expression that we are inside. When this is nonzero, ! 49: args passed to function calls must be popped right away ! 50: to ensure contiguity of argument lists for future calls. */ ! 51: int current_args_size; ! 52: ! 53: static rtx store_expr (); ! 54: static rtx expand_call (); ! 55: static void gen_call_1 (); ! 56: static rtx compare (); ! 57: static rtx compare1 (); ! 58: static rtx do_store_flag (); ! 59: static void preexpand_calls (); ! 60: ! 61: /* MOVE_RATIO is the number of move instructions that is better than ! 62: a block move. */ ! 63: ! 64: #if defined (HAVE_movstrhi) || defined (HAVE_movstrsi) ! 65: #define MOVE_RATIO 2 ! 66: #else ! 67: #define MOVE_RATIO 6 ! 68: #endif ! 69: ! 70: /* Table indexed by tree code giving 1 if the code is for a ! 71: comparison operation, or anything that is most easily ! 72: computed with a conditional branch. ! 73: ! 74: We include tree.def to give it the proper length. ! 75: The contents thus created are irrelevant. ! 76: The real contents are initialized in init_comparisons. */ ! 77: ! 78: #define DEFTREECODE(SYM, NAME, TYPE, LENGTH) LENGTH, ! 79: ! 80: static char comparison_code[] = { ! 81: #include "tree.def" ! 82: }; ! 83: #undef DEFTREECODE ! 84: ! 85: init_comparisons () ! 86: { ! 87: ! 88: bzero (comparison_code, sizeof comparison_code); ! 89: comparison_code[(int) EQ_EXPR] = 1; ! 90: comparison_code[(int) NE_EXPR] = 1; ! 91: comparison_code[(int) LT_EXPR] = 1; ! 92: comparison_code[(int) GT_EXPR] = 1; ! 93: comparison_code[(int) LE_EXPR] = 1; ! 94: comparison_code[(int) GE_EXPR] = 1; ! 95: } ! 96: ! 97: /* Manage the queue of increment instructions to be output ! 98: for POSTINCREMENT_EXPR expressions, etc. */ ! 99: ! 100: static rtx pending_chain; ! 101: ! 102: /* Queue up to increment (or change) VAR later. BODY says how: ! 103: BODY should be the same thing you would pass to emit_insn ! 104: to increment right away. It will go to emit_insn later on. ! 105: ! 106: The value is a QUEUED expression to be used in place of VAR ! 107: where you want to guarantee the pre-incrementation value of VAR. ! 108: ! 109: When constructing BODY, you should pass VAR through copy_rtx ! 110: each time it is used. If VAR is a MEM, this prevents BODY from ! 111: sharing structure incorrectly with itself or with places that ! 112: explicitly use VAR. */ ! 113: ! 114: static rtx ! 115: enqueue_insn (var, body) ! 116: rtx var, body; ! 117: { ! 118: pending_chain = gen_rtx (QUEUED, GET_MODE (var), ! 119: var, 0, 0, body, pending_chain); ! 120: return pending_chain; ! 121: } ! 122: ! 123: /* Use protect_from_queue to convert a QUEUED expression ! 124: into something that you can put immediately into an instruction. ! 125: If the queued incrementation has not happened yet, ! 126: protect_from_queue returns the variable itself. ! 127: If the incrementation has happened, protect_from_queue returns a temp ! 128: that contains a copy of the old value of the variable. ! 129: ! 130: Any time an rtx which might possibly be a QUEUED is to be put ! 131: into an instruction, it must be passed through protect_from_queue first. ! 132: QUEUED expressions are not meaningful in instructions. ! 133: ! 134: Do not pass a value through protect_from_queue and then hold ! 135: on to it for a while before putting it in an instruction! ! 136: If the queue is flushed in between, incorrect code will result. */ ! 137: ! 138: rtx ! 139: protect_from_queue (x, modify) ! 140: register rtx x; ! 141: int modify; ! 142: { ! 143: register RTX_CODE code = GET_CODE (x); ! 144: if (code != QUEUED) ! 145: { ! 146: /* A special hack for read access to (MEM (QUEUED ...)) ! 147: to facilitate use of autoincrement. ! 148: Make a copy of the contents of the memory location ! 149: rather than a copy of the address. */ ! 150: if (code == MEM && GET_CODE (XEXP (x, 0)) == QUEUED && !modify) ! 151: { ! 152: register rtx y = XEXP (x, 0); ! 153: XEXP (x, 0) = QUEUED_VAR (y); ! 154: if (QUEUED_INSN (y)) ! 155: { ! 156: register rtx temp = gen_reg_rtx (GET_MODE (x)); ! 157: emit_insn_before (gen_move_insn (temp, x), ! 158: QUEUED_INSN (y)); ! 159: return temp; ! 160: } ! 161: return x; ! 162: } ! 163: /* Otherwise, recursively protect the subexpressions of all ! 164: the kinds of rtx's that can contain a QUEUED. */ ! 165: if (code == MEM) ! 166: XEXP (x, 0) = protect_from_queue (XEXP (x, 0), 0); ! 167: else if (code == PLUS || code == MULT) ! 168: { ! 169: XEXP (x, 0) = protect_from_queue (XEXP (x, 0), 0); ! 170: XEXP (x, 1) = protect_from_queue (XEXP (x, 1), 0); ! 171: } ! 172: return x; ! 173: } ! 174: /* If the increment has not happened, use the variable itself. */ ! 175: if (QUEUED_INSN (x) == 0) ! 176: return QUEUED_VAR (x); ! 177: /* If the increment has happened and a pre-increment copy exists, ! 178: use that copy. */ ! 179: if (QUEUED_COPY (x) != 0) ! 180: return QUEUED_COPY (x); ! 181: /* The increment has happened but we haven't set up a pre-increment copy. ! 182: Set one up now, and use it. */ ! 183: QUEUED_COPY (x) = gen_reg_rtx (GET_MODE (QUEUED_VAR (x))); ! 184: emit_insn_before (gen_move_insn (QUEUED_COPY (x), QUEUED_VAR (x)), ! 185: QUEUED_INSN (x)); ! 186: return QUEUED_COPY (x); ! 187: } ! 188: ! 189: /* perform all the pending incrementations. */ ! 190: ! 191: void ! 192: emit_queue () ! 193: { ! 194: register rtx p; ! 195: while (p = pending_chain) ! 196: { ! 197: QUEUED_INSN (p) = emit_insn (QUEUED_BODY (p)); ! 198: pending_chain = QUEUED_NEXT (p); ! 199: } ! 200: } ! 201: ! 202: void ! 203: init_queue () ! 204: { ! 205: if (pending_chain) ! 206: abort (); ! 207: } ! 208: ! 209: /* Copy data from FROM to TO, where the machine modes are not the same. ! 210: Both modes may be integer, or both may be floating. ! 211: UNSIGNEDP should be nonzero if FROM is an unsigned type. ! 212: This causes zero-extension instead of sign-extension. */ ! 213: ! 214: void ! 215: convert_move (to, from, unsignedp) ! 216: register rtx to, from; ! 217: int unsignedp; ! 218: { ! 219: enum machine_mode to_mode = GET_MODE (to); ! 220: enum machine_mode from_mode = GET_MODE (from); ! 221: int to_real = to_mode == SFmode || to_mode == DFmode; ! 222: int from_real = from_mode == SFmode || from_mode == DFmode; ! 223: int extending = (int) to_mode > (int) from_mode; ! 224: ! 225: to = protect_from_queue (to, 1); ! 226: from = protect_from_queue (from, 0); ! 227: ! 228: if (to_real != from_real) ! 229: abort (); ! 230: ! 231: if (to_mode == from_mode || GET_CODE (from) == CONST_INT) ! 232: { ! 233: emit_move_insn (to, from); ! 234: return; ! 235: } ! 236: ! 237: if (to_real) ! 238: { ! 239: #ifdef HAVE_extendsfdf2 ! 240: if (HAVE_extendsfdf2 && extending) ! 241: { ! 242: emit_insn (gen_extendsfdf2 (to, from)); ! 243: return; ! 244: } ! 245: #endif ! 246: #ifdef HAVE_truncdfsf2 ! 247: if (HAVE_truncdfsf2 && ! extending) ! 248: { ! 249: emit_insn (gen_truncdfsf2 (to, from)); ! 250: return; ! 251: } ! 252: #endif ! 253: emit_library_call (gen_rtx (SYMBOL_REF, Pmode, (extending ! 254: ? "extendsfdf2" ! 255: : "truncdfsf2")), ! 256: 1, from, (extending ? SFmode : DFmode)); ! 257: copy_function_value (to); ! 258: return; ! 259: } ! 260: ! 261: if (to_mode == DImode) ! 262: { ! 263: emit_insn (gen_rtx (CLOBBER, VOIDmode, to)); ! 264: ! 265: if (unsignedp) ! 266: { ! 267: convert_move (gen_lowpart (SImode, to), from, unsignedp); ! 268: emit_clr_insn (gen_highpart (SImode, to)); ! 269: } ! 270: #ifdef HAVE_sltsi ! 271: else if (HAVE_sltsi) ! 272: { ! 273: convert_move (gen_lowpart (SImode, to), from, unsignedp); ! 274: emit_insn (gen_sltsi (gen_highpart (SImode, to))); ! 275: } ! 276: #endif ! 277: else ! 278: { ! 279: register rtx label = gen_label_rtx (); ! 280: ! 281: emit_clr_insn (gen_highpart (SImode, to)); ! 282: convert_move (gen_lowpart (SImode, to), from, unsignedp); ! 283: emit_cmp_insn (gen_lowpart (SImode, to), ! 284: gen_rtx (CONST_INT, VOIDmode, 0), ! 285: 0, 0); ! 286: emit_jump_insn (gen_bge (label)); ! 287: expand_unop (SImode, one_cmpl_optab, ! 288: gen_highpart (SImode, to), gen_highpart (SImode, to), ! 289: 1); ! 290: emit_label (label); ! 291: } ! 292: return; ! 293: } ! 294: ! 295: if (from_mode == DImode) ! 296: { ! 297: convert_move (to, gen_lowpart (SImode, from), 0); ! 298: return; ! 299: } ! 300: ! 301: /* Now follow all the conversions between integers ! 302: no more than a word long. */ ! 303: ! 304: if (to_mode == SImode && from_mode == HImode) ! 305: { ! 306: if (unsignedp) ! 307: { ! 308: #ifdef HAVE_zero_extendhisi2 ! 309: if (HAVE_zero_extendhisi2) ! 310: emit_insn (gen_zero_extendhisi2 (to, from)); ! 311: else ! 312: #endif ! 313: abort (); ! 314: } ! 315: else ! 316: { ! 317: #ifdef HAVE_extendhisi2 ! 318: if (HAVE_extendhisi2) ! 319: emit_insn (gen_extendhisi2 (to, from)); ! 320: else ! 321: #endif ! 322: abort (); ! 323: } ! 324: return; ! 325: } ! 326: ! 327: if (to_mode == SImode && from_mode == QImode) ! 328: { ! 329: if (unsignedp) ! 330: { ! 331: #ifdef HAVE_zero_extendqisi2 ! 332: if (HAVE_zero_extendqisi2) ! 333: { ! 334: emit_insn (gen_zero_extendqisi2 (to, from)); ! 335: return; ! 336: } ! 337: #endif ! 338: #if defined (HAVE_zero_extendqihi2) && defined (HAVE_extendhisi2) ! 339: if (HAVE_zero_extendqihi2 && HAVE_extendhisi2) ! 340: { ! 341: register rtx temp = gen_reg_rtx (HImode); ! 342: emit_insn (gen_zero_extendqihi2 (temp, from)); ! 343: emit_insn (gen_extendhisi2 (to, temp)); ! 344: return; ! 345: } ! 346: #endif ! 347: } ! 348: else ! 349: { ! 350: #ifdef HAVE_extendqisi2 ! 351: if (HAVE_extendqisi2) ! 352: { ! 353: emit_insn (gen_extendqisi2 (to, from)); ! 354: return; ! 355: } ! 356: #endif ! 357: #if defined (HAVE_extendqihi2) && defined (HAVE_extendhisi2) ! 358: if (HAVE_extendqihi2 && HAVE_extendhisi2) ! 359: { ! 360: register rtx temp = gen_reg_rtx (HImode); ! 361: emit_insn (gen_extendqihi2 (temp, from)); ! 362: emit_insn (gen_extendhisi2 (to, temp)); ! 363: return; ! 364: } ! 365: #endif ! 366: } ! 367: abort (); ! 368: } ! 369: ! 370: if (to_mode == HImode && from_mode == QImode) ! 371: { ! 372: if (unsignedp) ! 373: { ! 374: #ifdef HAVE_zero_extendqihi2 ! 375: if (HAVE_zero_extendqihi2) ! 376: { ! 377: emit_insn (gen_zero_extendqihi2 (to, from)); ! 378: return; ! 379: } ! 380: #endif ! 381: } ! 382: else ! 383: { ! 384: #ifdef HAVE_extendqihi2 ! 385: if (HAVE_extendqihi2) ! 386: { ! 387: emit_insn (gen_extendqihi2 (to, from)); ! 388: return; ! 389: } ! 390: #endif ! 391: } ! 392: abort (); ! 393: } ! 394: ! 395: /* Now we are truncating an integer to a smaller one. ! 396: If the result is a temporary, we might as well just copy it, ! 397: since only the low-order part of the result needs to be valid ! 398: and it is valid with no change. */ ! 399: ! 400: if (GET_CODE (to) == REG) ! 401: { ! 402: if (GET_CODE (from) == REG) ! 403: { ! 404: emit_move_insn (to, gen_lowpart (GET_MODE (to), from)); ! 405: return; ! 406: } ! 407: #ifndef BYTES_BIG_ENDIAN ! 408: else if (GET_CODE (from) == MEM) ! 409: { ! 410: register rtx addr = XEXP (from, 0); ! 411: GO_IF_LEGITIMATE_ADDRESS (GET_MODE (to), addr, win); ! 412: if (0) ! 413: { ! 414: win: ! 415: emit_move_insn (to, gen_rtx (MEM, GET_MODE (to), addr)); ! 416: return; ! 417: } ! 418: } ! 419: #endif /* not BYTES_BIG_ENDIAN */ ! 420: } ! 421: ! 422: if (from_mode == SImode && to_mode == HImode) ! 423: { ! 424: #ifdef HAVE_truncsihi2 ! 425: if (HAVE_truncsihi2) ! 426: { ! 427: emit_insn (gen_truncsihi2 (to, from)); ! 428: return; ! 429: } ! 430: #endif ! 431: abort (); ! 432: } ! 433: ! 434: if (from_mode == SImode && to_mode == QImode) ! 435: { ! 436: #ifdef HAVE_truncsiqi2 ! 437: if (HAVE_truncsiqi2) ! 438: { ! 439: emit_insn (gen_truncsiqi2 (to, from)); ! 440: return; ! 441: } ! 442: #endif ! 443: abort (); ! 444: } ! 445: ! 446: if (from_mode == HImode && to_mode == QImode) ! 447: { ! 448: #ifdef HAVE_trunchiqi2 ! 449: if (HAVE_trunchiqi2) ! 450: { ! 451: emit_insn (gen_trunchiqi2 (to, from)); ! 452: return; ! 453: } ! 454: #endif ! 455: abort (); ! 456: } ! 457: } ! 458: ! 459: /* Return an rtx for a value that would result ! 460: from converting X to mode MODE. ! 461: Both X and MODE may be floating, or both integer. ! 462: UNSIGNEDP is nonzero if X is an unsigned value. ! 463: This can be done by referring to a part of X in place ! 464: or by copying to a new temporary with conversion. */ ! 465: ! 466: rtx ! 467: convert_to_mode (mode, x, unsignedp) ! 468: enum machine_mode mode; ! 469: rtx x; ! 470: int unsignedp; ! 471: { ! 472: register rtx temp; ! 473: if (mode == GET_MODE (x)) ! 474: return x; ! 475: if (GET_MODE_SIZE (mode) <= GET_MODE_SIZE (GET_MODE (x))) ! 476: return gen_lowpart (mode, x); ! 477: temp = gen_reg_rtx (mode); ! 478: convert_move (temp, x, unsignedp); ! 479: return temp; ! 480: } ! 481: ! 482: /* Generate several move instructions to copy LEN bytes ! 483: from address FROM to address TO. The caller must pass FROM and TO ! 484: through protect_from_queue before calling. ! 485: FROM_VOL and TO_VOL are nonzero if references to ! 486: FROM and TO, respectively, should be marked VOLATILE. ! 487: ALIGN (in bytes) is maximum alignment we can assume. */ ! 488: ! 489: struct move_by_pieces ! 490: { ! 491: rtx to; ! 492: int autinc_to; ! 493: int explicit_inc_to; ! 494: int to_vol; ! 495: rtx from; ! 496: int autinc_from; ! 497: int explicit_inc_from; ! 498: int from_vol; ! 499: int len; ! 500: int offset; ! 501: int reverse; ! 502: }; ! 503: ! 504: static void ! 505: move_by_pieces (to, from, len, align, to_vol, from_vol) ! 506: rtx to, from; ! 507: int len, align; ! 508: int to_vol, from_vol; ! 509: { ! 510: struct move_by_pieces data; ! 511: ! 512: data.offset = 0; ! 513: data.to = to; ! 514: data.from = from; ! 515: data.to_vol = to_vol; ! 516: data.from_vol = from_vol; ! 517: data.autinc_to = (GET_CODE (to) == PRE_INC || GET_CODE (to) == PRE_DEC ! 518: || GET_CODE (to) == POST_INC || GET_CODE (to) == POST_DEC); ! 519: data.autinc_from = (GET_CODE (from) == PRE_INC || GET_CODE (from) == PRE_DEC ! 520: || GET_CODE (from) == POST_INC ! 521: || GET_CODE (from) == POST_DEC); ! 522: ! 523: data.explicit_inc_from = 0; ! 524: data.explicit_inc_to = 0; ! 525: data.reverse = (GET_CODE (to) == PRE_DEC || GET_CODE (to) == POST_DEC); ! 526: if (data.reverse) data.offset = len; ! 527: data.len = len; ! 528: ! 529: /* If copying requires more than two move insns, ! 530: copy addresses to registers (to make displacements shorter) ! 531: and use post-increment if available. */ ! 532: if (!(data.autinc_from && data.autinc_to) ! 533: && move_by_pieces_ninsns (len, align) > 2) ! 534: { ! 535: #ifdef HAVE_PRE_DECREMENT ! 536: if (data.reverse && ! data.autinc_from) ! 537: { ! 538: data.from = copy_to_reg (plus_constant (from, len)); ! 539: data.autinc_from = 1; ! 540: data.explicit_inc_from = -1; ! 541: } ! 542: #endif ! 543: #ifdef HAVE_POST_INCREMENT ! 544: if (! data.autinc_from) ! 545: { ! 546: data.from = copy_to_reg (from); ! 547: data.autinc_from = 1; ! 548: data.explicit_inc_from = 1; ! 549: } ! 550: #endif ! 551: if (!data.autinc_from && CONSTANT_ADDRESS_P (from)) ! 552: data.from = copy_to_reg (from); ! 553: #ifdef HAVE_PRE_DECREMENT ! 554: if (data.reverse && ! data.autinc_to) ! 555: { ! 556: data.to = copy_to_reg (plus_constant (to, len)); ! 557: data.autinc_to = 1; ! 558: data.explicit_inc_to = -1; ! 559: } ! 560: #endif ! 561: #ifdef HAVE_POST_INCREMENT ! 562: if (! data.reverse && ! data.autinc_to) ! 563: { ! 564: data.to = copy_to_reg (to); ! 565: data.autinc_to = 1; ! 566: data.explicit_inc_to = 1; ! 567: } ! 568: #endif ! 569: if (!data.autinc_to && CONSTANT_ADDRESS_P (to)) ! 570: data.to = copy_to_reg (to); ! 571: } ! 572: ! 573: #ifdef STRICT_ALIGNMENT ! 574: if (align > MOVE_MAX) ! 575: align = MOVE_MAX; ! 576: #else ! 577: align = MOVE_MAX; ! 578: #endif ! 579: ! 580: #ifdef HAVE_movti ! 581: if (HAVE_movti && align >= GET_MODE_SIZE (TImode)) ! 582: move_by_pieces_1 (gen_movti, TImode, &data); ! 583: #endif ! 584: #ifdef HAVE_movdi ! 585: if (HAVE_movdi && align >= GET_MODE_SIZE (DImode)) ! 586: move_by_pieces_1 (gen_movdi, DImode, &data); ! 587: #endif ! 588: if (align >= GET_MODE_SIZE (SImode)) ! 589: move_by_pieces_1 (gen_movsi, SImode, &data); ! 590: if (align >= GET_MODE_SIZE (HImode)) ! 591: move_by_pieces_1 (gen_movhi, HImode, &data); ! 592: move_by_pieces_1 (gen_movqi, QImode, &data); ! 593: } ! 594: ! 595: /* Return number of insns required to move L bytes by pieces. ! 596: ALIGN (in bytes) is maximum alignment we can assume. */ ! 597: ! 598: int ! 599: move_by_pieces_ninsns (l, align) ! 600: unsigned int l; ! 601: int align; ! 602: { ! 603: register int n_insns = 0; ! 604: ! 605: #ifdef STRICT_ALIGNMENT ! 606: if (align > MOVE_MAX) ! 607: align = MOVE_MAX; ! 608: #else ! 609: align = MOVE_MAX; ! 610: #endif ! 611: ! 612: #ifdef HAVE_movti ! 613: if (HAVE_movti && align >= GET_MODE_SIZE (TImode)) ! 614: n_insns += l / GET_MODE_SIZE (TImode), l %= GET_MODE_SIZE (TImode); ! 615: #endif ! 616: #ifdef HAVE_movdi ! 617: if (HAVE_movdi && align >= GET_MODE_SIZE (DImode)) ! 618: n_insns += l / GET_MODE_SIZE (DImode), l %= GET_MODE_SIZE (DImode); ! 619: #endif ! 620: if (HAVE_movsi && align >= GET_MODE_SIZE (SImode)) ! 621: n_insns += l / GET_MODE_SIZE (SImode), l %= GET_MODE_SIZE (SImode); ! 622: if (HAVE_movhi && align >= GET_MODE_SIZE (HImode)) ! 623: n_insns += l / GET_MODE_SIZE (HImode), l %= GET_MODE_SIZE (HImode); ! 624: n_insns += l; ! 625: ! 626: return n_insns; ! 627: } ! 628: ! 629: /* Subroutine of move_by_pieces. Move as many bytes as appropriate ! 630: with move instructions for mode MODE. GENFUN is the gen_... function ! 631: to make a move insn for that mode. DATA has all the other info. */ ! 632: ! 633: move_by_pieces_1 (genfun, mode, data) ! 634: rtx (*genfun) (); ! 635: enum machine_mode mode; ! 636: struct move_by_pieces *data; ! 637: { ! 638: register int size = GET_MODE_SIZE (mode); ! 639: register rtx to1, from1; ! 640: ! 641: #define add_offset(FLAG,X) (FLAG ? (X) : plus_constant (X, data->offset)) ! 642: ! 643: while (data->len >= size) ! 644: { ! 645: to1 = gen_rtx (MEM, mode, add_offset (data->autinc_to, data->to)); ! 646: from1 = gen_rtx (MEM, mode, add_offset (data->autinc_from, data->from)); ! 647: ! 648: if (data->to_vol) to1 = gen_rtx (VOLATILE, mode, to1); ! 649: if (data->from_vol) from1 = gen_rtx (VOLATILE, mode, from1); ! 650: ! 651: if (data->reverse) data->offset -= size; ! 652: #ifdef HAVE_PRE_DECREMENT ! 653: if (data->explicit_inc_to < 0) ! 654: emit_insn (gen_sub2_insn (data->to, ! 655: gen_rtx (CONST_INT, VOIDmode, size))); ! 656: if (data->explicit_inc_from < 0) ! 657: emit_insn (gen_sub2_insn (data->from, ! 658: gen_rtx (CONST_INT, VOIDmode, size))); ! 659: #endif ! 660: ! 661: emit_insn (genfun (to1, from1)); ! 662: #ifdef HAVE_POST_INCREMENT ! 663: if (data->explicit_inc_to > 0) ! 664: emit_insn (gen_add2_insn (data->to, ! 665: gen_rtx (CONST_INT, VOIDmode, size))); ! 666: if (data->explicit_inc_from > 0) ! 667: emit_insn (gen_add2_insn (data->from, ! 668: gen_rtx (CONST_INT, VOIDmode, size))); ! 669: #endif ! 670: ! 671: if (! data->reverse) data->offset += size; ! 672: data->len -= size; ! 673: } ! 674: } ! 675: ! 676: /* Emit code to move a block Y to a block X. ! 677: This may be done with string-move instructions, ! 678: with multiple scalar move instructions, or with a library call. ! 679: ! 680: Both X and Y must be MEM rtx's (perhaps inside VOLATILE) ! 681: with mode BLKmode. ! 682: SIZE is an rtx that says how long they are. ! 683: ALIGN is the maximum alignment we can assume they have, ! 684: measured in bytes. */ ! 685: ! 686: static void ! 687: emit_block_move (x, y, size, align) ! 688: rtx x, y; ! 689: rtx size; ! 690: int align; ! 691: { ! 692: ! 693: register int max_step; ! 694: rtx xinner, yinner; ! 695: int xvolatile = 0, yvolatile = 0; ! 696: ! 697: if (GET_MODE (x) != BLKmode) ! 698: abort (); ! 699: ! 700: if (GET_MODE (y) != BLKmode) ! 701: abort (); ! 702: ! 703: x = protect_from_queue (x, 1); ! 704: y = protect_from_queue (y, 0); ! 705: ! 706: xinner = x, yinner = y; ! 707: ! 708: if (GET_CODE (x) == VOLATILE) ! 709: xvolatile = 1, xinner = XEXP (x, 0); ! 710: if (GET_CODE (y) == VOLATILE) ! 711: yvolatile = 1, yinner = XEXP (y, 0); ! 712: ! 713: if (GET_CODE (xinner) != MEM) ! 714: abort (); ! 715: if (GET_CODE (yinner) != MEM) ! 716: abort (); ! 717: if (size == 0) ! 718: abort (); ! 719: ! 720: if (GET_CODE (size) == CONST_INT ! 721: && (move_by_pieces_ninsns ((unsigned) INTVAL (size), align) ! 722: < MOVE_RATIO)) ! 723: move_by_pieces (XEXP (xinner, 0), XEXP (yinner, 0), ! 724: INTVAL (size), align, ! 725: xvolatile, yvolatile); ! 726: else ! 727: { ! 728: #ifdef HAVE_movstrsi ! 729: if (HAVE_movstrsi) ! 730: { ! 731: emit_insn (gen_movstrsi (x, y, size)); ! 732: return; ! 733: } ! 734: #endif ! 735: #ifdef HAVE_movstrhi ! 736: if (HAVE_movstrhi ! 737: && GET_CODE (size) == CONST_INT ! 738: && ((unsigned) INTVAL (size) ! 739: < (1 << (GET_MODE_SIZE (HImode) * BITS_PER_UNIT - 1)))) ! 740: { ! 741: emit_insn (gen_movstrhi (x, y, size)); ! 742: return; ! 743: } ! 744: #endif ! 745: emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "bcopy"), ! 746: 3, XEXP (yinner, 0), Pmode, ! 747: XEXP (xinner, 0), Pmode, ! 748: size, Pmode); ! 749: } ! 750: } ! 751: ! 752: /* Generate code to copy Y into X. ! 753: Both Y and X must have the same mode, except that ! 754: Y can be a constant with VOIDmode. ! 755: This mode cannot be BLKmode; use emit_block_move for that. */ ! 756: ! 757: emit_move_insn (x, y) ! 758: rtx x, y; ! 759: { ! 760: enum machine_mode mode = GET_MODE (x); ! 761: x = protect_from_queue (x, 1); ! 762: y = protect_from_queue (y, 0); ! 763: ! 764: if (mode == BLKmode) ! 765: abort (); ! 766: if (mov_optab[(int) mode].insn_code != CODE_FOR_nothing) ! 767: emit_insn (GEN_FCN (mov_optab[(int) mode].insn_code) (x, y)); ! 768: else if (GET_MODE_SIZE (mode) >= GET_MODE_SIZE (SImode)) ! 769: { ! 770: register int count = GET_MODE_SIZE (mode) / GET_MODE_SIZE (SImode); ! 771: register int i; ! 772: for (i = 0; i < count; i++) ! 773: { ! 774: rtx x1, y1; ! 775: if (GET_CODE (x) == REG) ! 776: x1 = gen_rtx (SUBREG, SImode, x, i); ! 777: else ! 778: x1 = gen_rtx (MEM, SImode, ! 779: memory_address (SImode, ! 780: plus_constant (XEXP (x, 0), ! 781: i * GET_MODE_SIZE (SImode)))); ! 782: if (GET_CODE (y) == REG) ! 783: y1 = gen_rtx (SUBREG, SImode, y, i); ! 784: else ! 785: y1 = gen_rtx (MEM, SImode, ! 786: memory_address (SImode, ! 787: plus_constant (XEXP (y, 0), ! 788: i * GET_MODE_SIZE (SImode)))); ! 789: emit_insn (gen_movsi (protect_from_queue (x1, 1), protect_from_queue (y1, 0))); ! 790: } ! 791: } ! 792: else ! 793: abort (); ! 794: } ! 795: ! 796: /* Pushing data onto the stack. */ ! 797: ! 798: /* Push a block of length SIZE (perhaps variable) ! 799: and return an rtx to address the beginning of the block. ! 800: Note that it is not possible for the value returned to be a QUEUED. */ ! 801: ! 802: static rtx ! 803: push_block (size) ! 804: rtx size; ! 805: { ! 806: register rtx temp; ! 807: anti_adjust_stack (size); ! 808: ! 809: #ifdef STACK_GROWS_DOWNWARD ! 810: temp = gen_rtx (REG, Pmode, STACK_POINTER_REGNUM); ! 811: #else ! 812: temp = gen_rtx (PLUS, Pmode, ! 813: gen_rtx (REG, Pmode, STACK_POINTER_REGNUM), ! 814: size); ! 815: if (GET_CODE (size) != CONST_INT) ! 816: temp = force_operand (temp, 0); ! 817: #endif ! 818: return memory_address (QImode, temp); ! 819: } ! 820: ! 821: static rtx ! 822: gen_push_operand () ! 823: { ! 824: return gen_rtx ( ! 825: #ifdef STACK_GROWS_DOWNWARD ! 826: PRE_DEC, ! 827: #else ! 828: PRE_INC, ! 829: #endif ! 830: Pmode, ! 831: gen_rtx (REG, Pmode, STACK_POINTER_REGNUM)); ! 832: } ! 833: ! 834: /* Generate code to push X onto the stack, assuming it has mode MODE. ! 835: MODE is redundant except when X is a CONST_INT (since they don't ! 836: carry mode info). ! 837: SIZE is an rtx for the size of data to be copied (in bytes), ! 838: needed only if X is BLKmode. ! 839: ALIGN (in bytes) is maximum alignment we can assume. */ ! 840: ! 841: static void ! 842: emit_push_insn (x, mode, size, align) ! 843: register rtx x; ! 844: enum machine_mode mode; ! 845: rtx size; ! 846: int align; ! 847: { ! 848: rtx xinner; ! 849: ! 850: xinner = x = protect_from_queue (x, 0); ! 851: ! 852: if (GET_CODE (x) == VOLATILE) ! 853: xinner = XEXP (x, 0); ! 854: ! 855: if (mode == BLKmode) ! 856: { ! 857: register rtx temp; ! 858: ! 859: if (size == 0) ! 860: abort (); ! 861: ! 862: if (GET_CODE (size) == CONST_INT ! 863: && (move_by_pieces_ninsns ((unsigned) INTVAL (size), align) ! 864: < MOVE_RATIO)) ! 865: move_by_pieces (gen_push_operand (), ! 866: XEXP (xinner, 0), ! 867: INTVAL (size), align, ! 868: 0, GET_CODE (x) == VOLATILE); ! 869: else ! 870: { ! 871: temp = push_block (size); ! 872: #ifdef HAVE_movstrsi ! 873: if (HAVE_movstrsi) ! 874: { ! 875: emit_insn (gen_movstrsi (gen_rtx (MEM, BLKmode, temp), x, size)); ! 876: return; ! 877: } ! 878: #endif ! 879: #ifdef HAVE_movstrhi ! 880: if (HAVE_movstrhi ! 881: && GET_CODE (size) == CONST_INT ! 882: && ((unsigned) INTVAL (size) ! 883: < (1 << (GET_MODE_SIZE (HImode) * BITS_PER_UNIT - 1)))) ! 884: { ! 885: emit_insn (gen_movstrhi (gen_rtx (MEM, BLKmode, temp), ! 886: x, size)); ! 887: return; ! 888: } ! 889: #endif ! 890: /* Correct TEMP so it holds what will be a description of ! 891: the address to copy to, valid after one arg is pushed. */ ! 892: #ifdef STACK_GROWS_DOWNWARD ! 893: temp = plus_constant (temp, GET_MODE_SIZE (Pmode)); ! 894: #else ! 895: temp = plus_constant (temp, - GET_MODE_SIZE (Pmode)); ! 896: #endif ! 897: emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "bcopy"), ! 898: 3, XEXP (xinner, 0), Pmode, ! 899: temp, Pmode, ! 900: size, Pmode); ! 901: } ! 902: } ! 903: else if (mov_optab[(int) mode].insn_code != CODE_FOR_nothing) ! 904: { ! 905: register rtx push = gen_rtx (MEM, mode, gen_push_operand ()); ! 906: emit_insn (GEN_FCN (mov_optab[(int) mode].insn_code) (push, x)); ! 907: } ! 908: else ! 909: abort (); ! 910: } ! 911: ! 912: /* Output a library call to function FUN (a SYMBOL_REF rtx) ! 913: with NARGS different arguments, passed as alternating rtx values ! 914: and machine_modes to convert them to. ! 915: The rtx values should have been passed through protect_from_queue already. */ ! 916: ! 917: /*VARARGS2*/ ! 918: void ! 919: emit_library_call (fun, nargs, a1) ! 920: rtx fun; ! 921: int nargs; ! 922: struct { rtx value; enum machine_mode mode; } a1; ! 923: { ! 924: register int args_size = 0; ! 925: register int argnum; ! 926: #ifndef STACK_GROWS_DOWNWARD ! 927: for (argnum = 0; argnum < nargs; argnum++) ! 928: #else ! 929: for (argnum = nargs - 1; argnum >= 0; argnum--) ! 930: #endif ! 931: { ! 932: register enum machine_mode mode = (&a1)[argnum].mode; ! 933: register rtx val = (&a1)[argnum].value; ! 934: /* Convert the arg value to the mode the library wants. */ ! 935: /* ??? It is wrong to do it here; must do it earlier ! 936: where we know the signedness of the arg. */ ! 937: if (GET_MODE (val) != mode && GET_MODE (val) != VOIDmode) ! 938: { ! 939: val = gen_reg_rtx (mode); ! 940: convert_move (val, (&a1)[argnum].value, 0); ! 941: } ! 942: emit_push_insn (val, mode, 0, 0); ! 943: args_size += GET_MODE_SIZE (mode); ! 944: current_args_size += GET_MODE_SIZE (mode); ! 945: } ! 946: ! 947: emit_queue (); ! 948: gen_call_1 (fun, 0, args_size / GET_MODE_SIZE (SImode), args_size); ! 949: } ! 950: ! 951: /* Expand an assignment that stores the value of FROM into TO. ! 952: Return an rtx for the value of TO. This may contain a QUEUED rtx. */ ! 953: ! 954: rtx ! 955: expand_assignment (to, from) ! 956: tree to, from; ! 957: { ! 958: register rtx to_rtx = 0; ! 959: ! 960: /* Don't crash if the lhs of the assignment was erroneous. */ ! 961: ! 962: if (TREE_CODE (to) == ERROR_MARK) ! 963: return expand_expr (from, 0, VOIDmode, 0); ! 964: ! 965: /* Assignment of a structure component needs special treatment ! 966: if the structure component's rtx is not simply a MEM. */ ! 967: ! 968: if (TREE_CODE (to) == COMPONENT_REF) ! 969: { ! 970: register enum machine_mode mode1 = DECL_MODE (TREE_OPERAND (to, 1)); ! 971: int volstruct = 0; ! 972: ! 973: /* Get the structure as an rtx. */ ! 974: ! 975: to_rtx = expand_expr (TREE_OPERAND (to, 0), 0, VOIDmode, 0); ! 976: ! 977: /* If the structure is in a register or if the component ! 978: is a bit field, we cannot use addressing to access it. ! 979: Use bit-field techniques or SUBREG to store in it. */ ! 980: ! 981: if (mode1 == BImode || GET_CODE (to_rtx) == REG ! 982: || GET_CODE (to_rtx) == SUBREG) ! 983: { ! 984: tree field = TREE_OPERAND (to, 1); ! 985: int bitsize = TREE_INT_CST_LOW (DECL_SIZE (field)) * DECL_SIZE_UNIT (field); ! 986: return store_bit_field (to_rtx, bitsize, DECL_OFFSET (field), ! 987: DECL_MODE (field), ! 988: expand_expr (from, 0, VOIDmode, 0)); ! 989: } ! 990: ! 991: /* Get the address of the structure the component is in. ! 992: Record if structure is volatile. */ ! 993: ! 994: if (GET_CODE (to_rtx) == VOLATILE) ! 995: { ! 996: to_rtx = XEXP (to_rtx, 0); ! 997: volstruct = 1; ! 998: } ! 999: if (GET_CODE (to_rtx) != MEM) ! 1000: abort (); ! 1001: to_rtx = XEXP (to_rtx, 0); ! 1002: ! 1003: /* Now build a reference to just the desired component. */ ! 1004: ! 1005: to_rtx = gen_rtx (MEM, mode1, ! 1006: memory_address (mode1, ! 1007: plus_constant (to_rtx, ! 1008: (DECL_OFFSET ! 1009: (TREE_OPERAND (to, 1)) ! 1010: / BITS_PER_UNIT)))); ! 1011: to_rtx->in_struct = 1; ! 1012: ! 1013: /* Make component volatile if structure is. */ ! 1014: ! 1015: if (! cse_not_expected && volstruct) ! 1016: to_rtx = gen_rtx (VOLATILE, mode1, to_rtx); ! 1017: } ! 1018: ! 1019: /* Arrays in registers also need special treatment. */ ! 1020: ! 1021: if (TREE_CODE (to) == ARRAY_REF) ! 1022: { ! 1023: /* Check to see whether the array is in a register. */ ! 1024: tree array = TREE_OPERAND (TREE_OPERAND (to, 0), 0); ! 1025: register tree temexp; ! 1026: ! 1027: /* Look through any COMPONENT_REFS to the containing struct. ! 1028: Start by taking the array out of the ADDR_EXPR that's operand 0. */ ! 1029: for (temexp = array; ! 1030: TREE_CODE (temexp) == COMPONENT_REF; ! 1031: temexp = TREE_OPERAND (temexp, 0)); ! 1032: ! 1033: if (TREE_CODE (TREE_OPERAND (to, 1)) == INTEGER_CST ! 1034: && TREE_CODE (temexp) == VAR_DECL ! 1035: && DECL_RTL (temexp) != 0 ! 1036: && (GET_CODE (DECL_RTL (temexp)) == REG ! 1037: || GET_CODE (DECL_RTL (temexp)) == SUBREG)) ! 1038: { ! 1039: /* The array or containing struct is a variable in a register ! 1040: and the index is constant. */ ! 1041: int bitsize = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (to))); ! 1042: ! 1043: to_rtx = expand_expr (array, 0, VOIDmode, 0); ! 1044: return store_bit_field (to_rtx, bitsize, ! 1045: TREE_INT_CST_LOW (TREE_OPERAND (to, 1)) * bitsize, ! 1046: TYPE_MODE (TREE_TYPE (to)), ! 1047: expand_expr (from, 0, VOIDmode, 0)); ! 1048: } ! 1049: ! 1050: /* The array is in memory. Generate the tree for *(array+index) ! 1051: and store into that insted. */ ! 1052: ! 1053: to = build_indirect_ref (build_binary_op (PLUS_EXPR, ! 1054: TREE_OPERAND (to, 0), ! 1055: TREE_OPERAND (to, 1))); ! 1056: } ! 1057: ! 1058: /* Ordinary treatment. Expand TO to get a REG or MEM rtx. ! 1059: Don't re-expand if it was expanded already (in COMPONENT_REF case). */ ! 1060: ! 1061: if (to_rtx == 0) ! 1062: to_rtx = expand_expr (to, 0, VOIDmode, 0); ! 1063: ! 1064: /* Compute FROM and store the value in the rtx we got. */ ! 1065: ! 1066: store_expr (from, to_rtx); ! 1067: return to_rtx; ! 1068: } ! 1069: ! 1070: /* Generate code for computing expression EXP, ! 1071: and storing the value into TARGET. Returns TARGET. ! 1072: TARGET may contain a QUEUED rtx. */ ! 1073: ! 1074: static rtx ! 1075: store_expr (exp, target) ! 1076: register tree exp; ! 1077: register rtx target; ! 1078: { ! 1079: register rtx temp = expand_expr (exp, target, GET_MODE (target), 0); ! 1080: if (temp != target && TREE_CODE (exp) != ERROR_MARK) ! 1081: { ! 1082: target = protect_from_queue (target, 1); ! 1083: if (GET_MODE (temp) != GET_MODE (target) ! 1084: && GET_MODE (temp) != VOIDmode) ! 1085: convert_move (target, temp, type_unsigned_p (TREE_TYPE (exp))); ! 1086: else if (GET_MODE (temp) == BLKmode) ! 1087: emit_block_move (target, temp, expr_size (exp), ! 1088: TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT); ! 1089: else ! 1090: emit_move_insn (target, temp); ! 1091: } ! 1092: return target; ! 1093: } ! 1094: ! 1095: /* Given an rtx VALUE that may contain additions and multiplications, ! 1096: return an equivalent value that just refers to a register or memory. ! 1097: This is done by generating instructions to perform the arithmetic ! 1098: and returning a pseudo-register containing the value. */ ! 1099: ! 1100: rtx ! 1101: force_operand (value, target) ! 1102: rtx value, target; ! 1103: { ! 1104: register struct optab *binoptab = 0; ! 1105: register rtx op2 = XEXP (value, 1); ! 1106: /* Use subtarget as the target for operand 0 of a binary operation. */ ! 1107: register rtx subtarget = (target != 0 && GET_CODE (target) == REG ? target : 0); ! 1108: ! 1109: if (GET_CODE (value) == PLUS) ! 1110: binoptab = add_optab; ! 1111: else if (GET_CODE (value) == MINUS) ! 1112: binoptab = sub_optab; ! 1113: else if (GET_CODE (value) == MULT) ! 1114: { ! 1115: if (!CONSTANT_ADDRESS_P (op2) ! 1116: && !(GET_CODE (op2) == REG && op2 != subtarget)) ! 1117: subtarget = 0; ! 1118: return expand_mult (GET_MODE (value), ! 1119: force_operand (XEXP (value, 0), subtarget), ! 1120: force_operand (op2, 0), ! 1121: target, 0); ! 1122: } ! 1123: ! 1124: if (binoptab) ! 1125: { ! 1126: if (!CONSTANT_ADDRESS_P (op2) ! 1127: && !(GET_CODE (op2) == REG && op2 != subtarget)) ! 1128: subtarget = 0; ! 1129: return expand_binop (GET_MODE (value), binoptab, ! 1130: force_operand (XEXP (value, 0), subtarget), ! 1131: force_operand (op2, 0), ! 1132: target, 0, OPTAB_LIB_WIDEN); ! 1133: /* We give UNSIGNEP = 0 to expand_binop ! 1134: because the only operations we are expanding here are signed ones. */ ! 1135: } ! 1136: return value; ! 1137: } ! 1138: ! 1139: /* expand_expr: generate code for computing expression EXP. ! 1140: An rtx for the computed value is returned. ! 1141: ! 1142: The value may be stored in TARGET if TARGET is nonzero. ! 1143: TARGET is just a suggestion; callers must assume that ! 1144: the rtx returned may not be the same as TARGET. ! 1145: ! 1146: If TMODE is not VOIDmode, it suggests generating the ! 1147: result in mode TMODE. But this is done only when convenient. ! 1148: Otherwise, TMODE is ignored and the value generated in its natural mode. ! 1149: TMODE is just a suggestion; callers must assume that ! 1150: the rtx returned may not have mode TMODE. ! 1151: ! 1152: If SUM_OK is nonzero then when EXP is an addition ! 1153: we can return an rtx of the form (MULT (REG ...) (CONST_INT ...)) ! 1154: or a nest of (PLUS ...) and (MINUS ...) where the terms are ! 1155: products as above, or REG or MEM, or constant. ! 1156: If SUM_OK is zero, in such cases we would output mul or add instructions ! 1157: and then return a pseudo reg containing the sum. */ ! 1158: ! 1159: /* Subroutine of expand_expr: ! 1160: return the target to use when recursively expanding ! 1161: the first operand of an arithmetic operation. */ ! 1162: ! 1163: static rtx ! 1164: validate_subtarget (subtarget, otherop) ! 1165: rtx subtarget; ! 1166: tree otherop; ! 1167: { ! 1168: if (TREE_LITERAL (otherop)) ! 1169: return subtarget; ! 1170: if (TREE_CODE (otherop) == VAR_DECL ! 1171: && DECL_RTL (otherop) != subtarget) ! 1172: return subtarget; ! 1173: return 0; ! 1174: } ! 1175: ! 1176: rtx ! 1177: expand_expr (exp, target, tmode, sum_ok) ! 1178: register tree exp; ! 1179: rtx target; ! 1180: enum machine_mode tmode; ! 1181: int sum_ok; ! 1182: { ! 1183: register rtx op0, op1, temp; ! 1184: tree type = TREE_TYPE (exp); ! 1185: register enum machine_mode mode = TYPE_MODE (type); ! 1186: register enum tree_code code = TREE_CODE (exp); ! 1187: struct optab *this_optab; ! 1188: int negate_1; ! 1189: /* Use subtarget as the target for operand 0 of a binary operation. */ ! 1190: rtx subtarget = (target != 0 && GET_CODE (target) == REG ? target : 0); ! 1191: static tree dbg2; ! 1192: dbg2 = exp; ! 1193: ! 1194: /* If will do cse, generate all results into registers ! 1195: since 1) that allows cse to find more things ! 1196: and 2) otherwise cse could produce an insn the machine ! 1197: cannot support. */ ! 1198: ! 1199: if (! cse_not_expected && mode != BLKmode) ! 1200: target = subtarget; ! 1201: ! 1202: switch (code) ! 1203: { ! 1204: case FUNCTION_DECL: ! 1205: case VAR_DECL: ! 1206: temp = DECL_RTL (exp); ! 1207: if (! cse_not_expected && TREE_VOLATILE (exp)) ! 1208: return gen_rtx (VOLATILE, DECL_MODE (exp), temp); ! 1209: else ! 1210: return temp; ! 1211: ! 1212: case PARM_DECL: ! 1213: case RESULT_DECL: ! 1214: if (DECL_RTL (exp) == 0) ! 1215: abort (); ! 1216: if (GET_CODE (DECL_RTL (exp)) == SYMBOL_REF) ! 1217: abort (); ! 1218: return DECL_RTL (exp); ! 1219: ! 1220: case INTEGER_CST: ! 1221: return gen_rtx (CONST_INT, VOIDmode, TREE_INT_CST_LOW (exp)); ! 1222: ! 1223: case CONST_DECL: ! 1224: return expand_expr (DECL_INITIAL (exp), target, VOIDmode, 0); ! 1225: ! 1226: case REAL_CST: ! 1227: if (TREE_CST_RTL (exp)) ! 1228: return TREE_CST_RTL (exp); ! 1229: /* If optimized, generate immediate float ! 1230: which will be turned into memory float if necessary. */ ! 1231: if (!cse_not_expected) ! 1232: return immed_real_const (exp); ! 1233: output_constant_def (exp); ! 1234: return TREE_CST_RTL (exp); ! 1235: ! 1236: case COMPLEX_CST: ! 1237: case STRING_CST: ! 1238: if (TREE_CST_RTL (exp)) ! 1239: return TREE_CST_RTL (exp); ! 1240: output_constant_def (exp); ! 1241: return TREE_CST_RTL (exp); ! 1242: ! 1243: case SAVE_EXPR: ! 1244: if (SAVE_EXPR_RTL (exp) == 0) ! 1245: { ! 1246: SAVE_EXPR_RTL (exp) = gen_reg_rtx (mode); ! 1247: store_expr (TREE_OPERAND (exp, 0), SAVE_EXPR_RTL (exp)); ! 1248: } ! 1249: return SAVE_EXPR_RTL (exp); ! 1250: ! 1251: case INDIRECT_REF: ! 1252: { ! 1253: tree exp1 = TREE_OPERAND (exp, 0); ! 1254: tree exp2; ! 1255: ! 1256: /* A SAVE_EXPR as the address in an INDIRECT_EXPR is generated ! 1257: for *PTR += ANYTHING where PTR is put inside the SAVE_EXPR. ! 1258: This code has the same general effect as simply doing ! 1259: expand_expr on the save expr, except that the expression PTR ! 1260: is computed for use as a memory address. This means different ! 1261: code, suitable for indexing, may be generated. */ ! 1262: if (TREE_CODE (exp1) == SAVE_EXPR ! 1263: && SAVE_EXPR_RTL (exp1) == 0 ! 1264: && TREE_CODE (exp2 = TREE_OPERAND (exp1, 0)) != ERROR_MARK ! 1265: && TYPE_MODE (TREE_TYPE (exp1)) == Pmode ! 1266: && TYPE_MODE (TREE_TYPE (exp2)) == Pmode) ! 1267: { ! 1268: temp = expand_expr (TREE_OPERAND (exp1, 0), 0, VOIDmode, 1); ! 1269: op0 = memory_address (mode, temp); ! 1270: op0 = copy_all_regs (op0); ! 1271: SAVE_EXPR_RTL (exp1) = op0; ! 1272: } ! 1273: else ! 1274: { ! 1275: op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 1); ! 1276: op0 = memory_address (mode, op0); ! 1277: } ! 1278: } ! 1279: temp = gen_rtx (MEM, mode, op0); ! 1280: if (! cse_not_expected && TREE_THIS_VOLATILE (exp)) ! 1281: return gen_rtx (VOLATILE, mode, temp); ! 1282: else ! 1283: return temp; ! 1284: ! 1285: case COMPONENT_REF: ! 1286: { ! 1287: register enum machine_mode mode1 = DECL_MODE (TREE_OPERAND (exp, 1)); ! 1288: int volstruct = 0; ! 1289: tree dbg1 = TREE_OPERAND (exp, 0); /* For debugging */ ! 1290: ! 1291: op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0); ! 1292: if (mode1 == BImode || GET_CODE (op0) == REG ! 1293: || GET_CODE (op0) == SUBREG) ! 1294: { ! 1295: tree field = TREE_OPERAND (exp, 1); ! 1296: int bitsize = TREE_INT_CST_LOW (DECL_SIZE (field)) * DECL_SIZE_UNIT (field); ! 1297: return extract_bit_field (op0, bitsize, DECL_OFFSET (field), ! 1298: type_unsigned_p (TREE_TYPE (field)), ! 1299: target, mode, tmode); ! 1300: } ! 1301: if (tmode != VOIDmode) ! 1302: mode = tmode; ! 1303: /* Get the address of the structure the component is in. */ ! 1304: if (GET_CODE (op0) == VOLATILE) ! 1305: { ! 1306: op0 = XEXP (op0, 0); ! 1307: volstruct = 1; ! 1308: } ! 1309: if (GET_CODE (op0) != MEM) ! 1310: abort (); ! 1311: op0 = XEXP (op0, 0); ! 1312: op0 = gen_rtx (MEM, mode1, ! 1313: memory_address (mode1, ! 1314: plus_constant (op0, ! 1315: (DECL_OFFSET ! 1316: (TREE_OPERAND (exp, 1)) ! 1317: / BITS_PER_UNIT)))); ! 1318: op0->in_struct = 1; ! 1319: if (! cse_not_expected && volstruct) ! 1320: op0 = gen_rtx (VOLATILE, mode1, op0); ! 1321: if (mode == mode1 || mode == BLKmode) ! 1322: return op0; ! 1323: if (target == 0) ! 1324: target = gen_reg_rtx (mode); ! 1325: convert_move (target, op0, type_unsigned_p (TREE_TYPE (TREE_OPERAND (exp, 1)))); ! 1326: return target; ! 1327: } ! 1328: ! 1329: /* ARRAY_REF is used in C for an actual array (not just a pointer) ! 1330: indexed by a constant index. It enables us to avoid taking the ! 1331: address of the array, which may allow a short array (or a struct ! 1332: or union containing one) to go in a register. */ ! 1333: case ARRAY_REF: ! 1334: { ! 1335: /* Check to see whether the array is in a register. */ ! 1336: tree array = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); ! 1337: register tree temexp; ! 1338: ! 1339: /* Look through any COMPONENT_REFS to the containing struct. ! 1340: Start by taking the array out of the ADDR_EXPR that's operand 0. */ ! 1341: for (temexp = array; ! 1342: TREE_CODE (temexp) == COMPONENT_REF; ! 1343: temexp = TREE_OPERAND (temexp, 0)); ! 1344: ! 1345: if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST ! 1346: && TREE_CODE (temexp) == VAR_DECL ! 1347: && DECL_RTL (temexp) != 0 ! 1348: && (GET_CODE (DECL_RTL (temexp)) == REG ! 1349: || GET_CODE (DECL_RTL (temexp)) == SUBREG)) ! 1350: { ! 1351: /* The array or containing struct is a variable in a register ! 1352: and the index is constant. */ ! 1353: int bitsize = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (exp))); ! 1354: ! 1355: op0 = expand_expr (array, 0, VOIDmode, 0); ! 1356: return extract_bit_field (op0, bitsize, ! 1357: TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)) * bitsize, ! 1358: type_unsigned_p (TREE_TYPE (exp)), ! 1359: target, mode, tmode); ! 1360: } ! 1361: ! 1362: /* The array is in memory. Generate the tree for *(array+index) ! 1363: and expand that. */ ! 1364: ! 1365: temexp = build_indirect_ref (build_binary_op (PLUS_EXPR, ! 1366: TREE_OPERAND (exp, 0), ! 1367: TREE_OPERAND (exp, 1))); ! 1368: return expand_expr (temexp, 0, VOIDmode, 0); ! 1369: } ! 1370: ! 1371: /* Intended for a reference to a buffer of a file-object in Pascal. ! 1372: But it's not certain that a special tree code will really be ! 1373: necessary for these. INDIRECT_REF might work for them. */ ! 1374: case BUFFER_REF: ! 1375: abort (); ! 1376: ! 1377: case CALL_EXPR: ! 1378: /* If this call was expanded already by preexpand_calls, ! 1379: just return the result we got. */ ! 1380: if (CALL_EXPR_RTL (exp) != 0) ! 1381: return CALL_EXPR_RTL (exp); ! 1382: return expand_call (exp, target); ! 1383: ! 1384: case NOP_EXPR: ! 1385: case CONVERT_EXPR: ! 1386: if (TREE_CODE (type) == VOID_TYPE) ! 1387: { ! 1388: expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, sum_ok); ! 1389: return const0_rtx; ! 1390: } ! 1391: if (mode == TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))) ! 1392: return expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, sum_ok); ! 1393: op0 = expand_expr (TREE_OPERAND (exp, 0), 0, mode, 0); ! 1394: if (GET_MODE (op0) == mode) ! 1395: return op0; ! 1396: if (target == 0) ! 1397: target = gen_reg_rtx (mode); ! 1398: convert_move (target, op0, type_unsigned_p (TREE_TYPE (TREE_OPERAND (exp, 0)))); ! 1399: return target; ! 1400: ! 1401: case PLUS_EXPR: ! 1402: preexpand_calls (exp); ! 1403: if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST) ! 1404: { ! 1405: op1 = expand_expr (TREE_OPERAND (exp, 1), subtarget, VOIDmode, 1); ! 1406: op1 = plus_constant (op1, TREE_INT_CST_LOW (TREE_OPERAND (exp, 0))); ! 1407: if (sum_ok) ! 1408: return op1; ! 1409: return force_operand (op1, target); ! 1410: } ! 1411: negate_1 = 1; ! 1412: plus_minus: ! 1413: if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST) ! 1414: { ! 1415: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 1); ! 1416: op0 = plus_constant (op0, ! 1417: negate_1 * TREE_INT_CST_LOW (TREE_OPERAND (exp, 1))); ! 1418: if (sum_ok) ! 1419: return op0; ! 1420: return force_operand (op0, target); ! 1421: } ! 1422: this_optab = add_optab; ! 1423: if (!sum_ok) goto binop; ! 1424: subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1)); ! 1425: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 1); ! 1426: op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 1); ! 1427: /* Put a sum last, to simplify what follows. */ ! 1428: #ifdef OLD_INDEXING ! 1429: if (GET_CODE (op1) == MULT) ! 1430: { ! 1431: temp = op0; ! 1432: op0 = op1; ! 1433: op1 = temp; ! 1434: } ! 1435: #endif ! 1436: #ifndef OLD_INDEXING ! 1437: /* Make sure any term that's a sum with a constant comes last. */ ! 1438: if (GET_CODE (op0) == PLUS ! 1439: && CONSTANT_ADDRESS_P (XEXP (op0, 1))) ! 1440: { ! 1441: temp = op0; ! 1442: op0 = op1; ! 1443: op1 = temp; ! 1444: } ! 1445: /* If adding to a sum including a constant, ! 1446: associate it to put the constant outside. */ ! 1447: if (GET_CODE (op1) == PLUS ! 1448: && CONSTANT_ADDRESS_P (XEXP (op1, 1))) ! 1449: { ! 1450: op0 = gen_rtx (PLUS, mode, XEXP (op1, 0), op0); ! 1451: if (GET_CODE (XEXP (op1, 1)) == CONST_INT) ! 1452: return plus_constant (op0, INTVAL (XEXP (op1, 1))); ! 1453: else ! 1454: return gen_rtx (PLUS, mode, op0, XEXP (op1, 1)); ! 1455: } ! 1456: #endif ! 1457: return gen_rtx (PLUS, mode, op0, op1); ! 1458: ! 1459: case MINUS_EXPR: ! 1460: preexpand_calls (exp); ! 1461: if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST) ! 1462: { ! 1463: negate_1 = -1; ! 1464: goto plus_minus; ! 1465: } ! 1466: this_optab = sub_optab; ! 1467: goto binop; ! 1468: ! 1469: case MULT_EXPR: ! 1470: preexpand_calls (exp); ! 1471: /* If first operand is constant, swap them. ! 1472: Thus the following special case checks need only ! 1473: check the second operand. */ ! 1474: if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST) ! 1475: { ! 1476: register tree t1 = TREE_OPERAND (exp, 0); ! 1477: TREE_OPERAND (exp, 0) = TREE_OPERAND (exp, 1); ! 1478: TREE_OPERAND (exp, 1) = t1; ! 1479: } ! 1480: ! 1481: /* Attempt to return something suitable for generating an ! 1482: indexed address, for machines that support that. */ ! 1483: ! 1484: if (sum_ok && TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST) ! 1485: { ! 1486: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); ! 1487: if (GET_CODE (op0) != REG) ! 1488: { ! 1489: temp = gen_reg_rtx (GET_MODE (op0)); ! 1490: emit_move_insn (temp, op0); ! 1491: op0 = temp; ! 1492: } ! 1493: return gen_rtx (MULT, mode, op0, ! 1494: gen_rtx (CONST_INT, VOIDmode, ! 1495: TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)))); ! 1496: } ! 1497: subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1)); ! 1498: /* Check for multiplying things that have been extended ! 1499: from a narrower type. If this machine supports multiplying ! 1500: in that narrower type with a result in the desired type, ! 1501: do it that way, and avoid the explicit type-conversion. */ ! 1502: if (TREE_CODE (TREE_OPERAND (exp, 0)) == NOP_EXPR ! 1503: && TREE_CODE (TREE_TYPE (exp)) == INTEGER_TYPE ! 1504: && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))) ! 1505: < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0)))) ! 1506: && ((TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST ! 1507: && int_fits_type_p (TREE_OPERAND (exp, 1), ! 1508: TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))) ! 1509: || ! 1510: (TREE_CODE (TREE_OPERAND (exp, 1)) == NOP_EXPR ! 1511: && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 1), 0))) ! 1512: == ! 1513: TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))))))) ! 1514: { ! 1515: enum machine_mode innermode ! 1516: = TYPE_MODE (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))); ! 1517: this_optab = (type_unsigned_p (TREE_TYPE (exp)) ! 1518: ? umul_widen_optab : smul_widen_optab); ! 1519: if ((int) innermode + 1 == (int) mode ! 1520: && this_optab[(int) mode].insn_code != CODE_FOR_nothing) ! 1521: { ! 1522: op0 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 0), 0), ! 1523: 0, VOIDmode, 0); ! 1524: if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST) ! 1525: op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0); ! 1526: else ! 1527: op1 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 1), 0), ! 1528: 0, VOIDmode, 0); ! 1529: goto binop2; ! 1530: } ! 1531: } ! 1532: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); ! 1533: op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0); ! 1534: return expand_mult (mode, op0, op1, target, type_unsigned_p (type)); ! 1535: ! 1536: case TRUNC_DIV_EXPR: ! 1537: case FLOOR_DIV_EXPR: ! 1538: case CEIL_DIV_EXPR: ! 1539: case ROUND_DIV_EXPR: ! 1540: preexpand_calls (exp); ! 1541: subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1)); ! 1542: /* Possible optimization: compute the dividend with SUM_OK ! 1543: then if the divisor is constant can optimize the case ! 1544: where some terms of the dividend have coeffs divisible by it. */ ! 1545: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); ! 1546: op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0); ! 1547: return expand_divmod (0, code, mode, op0, op1, target, ! 1548: type_unsigned_p (type)); ! 1549: ! 1550: case RDIV_EXPR: ! 1551: preexpand_calls (exp); ! 1552: this_optab = flodiv_optab; ! 1553: goto binop; ! 1554: ! 1555: case TRUNC_MOD_EXPR: ! 1556: case FLOOR_MOD_EXPR: ! 1557: case CEIL_MOD_EXPR: ! 1558: case ROUND_MOD_EXPR: ! 1559: preexpand_calls (exp); ! 1560: subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1)); ! 1561: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); ! 1562: op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0); ! 1563: return expand_divmod (1, code, mode, op0, op1, target, ! 1564: type_unsigned_p (type)); ! 1565: #if 0 ! 1566: #ifdef HAVE_divmoddisi4 ! 1567: if (GET_MODE (op0) != DImode) ! 1568: { ! 1569: temp = gen_reg_rtx (DImode); ! 1570: convert_move (temp, op0, 0); ! 1571: op0 = temp; ! 1572: if (GET_MODE (op1) != SImode && GET_CODE (op1) != CONST_INT) ! 1573: { ! 1574: temp = gen_reg_rtx (SImode); ! 1575: convert_move (temp, op1, 0); ! 1576: op1 = temp; ! 1577: } ! 1578: temp = gen_reg_rtx (SImode); ! 1579: if (target == 0) ! 1580: target = gen_reg_rtx (SImode); ! 1581: emit_insn (gen_divmoddisi4 (temp, protect_from_queue (op0, 0), ! 1582: protect_from_queue (op1, 0), ! 1583: protect_from_queue (target, 1))); ! 1584: return target; ! 1585: } ! 1586: #endif ! 1587: #endif ! 1588: ! 1589: case FIX_ROUND_EXPR: ! 1590: case FIX_FLOOR_EXPR: ! 1591: case FIX_CEIL_EXPR: ! 1592: abort (); /* Not used for C. */ ! 1593: ! 1594: case FIX_TRUNC_EXPR: ! 1595: op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0); ! 1596: if (target == 0) ! 1597: target = gen_reg_rtx (mode); ! 1598: if (mode == HImode || mode == QImode) ! 1599: { ! 1600: register rtx temp = gen_reg_rtx (SImode); ! 1601: expand_fix (temp, op0); ! 1602: convert_move (target, temp, 0); ! 1603: } ! 1604: else ! 1605: expand_fix (target, op0); ! 1606: return target; ! 1607: ! 1608: case FLOAT_EXPR: ! 1609: op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0); ! 1610: if (target == 0) ! 1611: target = gen_reg_rtx (mode); ! 1612: if (GET_MODE (op0) == HImode ! 1613: || GET_MODE (op0) == QImode) ! 1614: { ! 1615: register rtx temp = gen_reg_rtx (SImode); ! 1616: convert_move (temp, op0, 0); ! 1617: expand_float (target, temp); ! 1618: } ! 1619: else ! 1620: expand_float (target, op0); ! 1621: return target; ! 1622: ! 1623: case NEGATE_EXPR: ! 1624: op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0); ! 1625: temp = expand_unop (mode, neg_optab, op0, target, 0); ! 1626: if (temp == 0) ! 1627: abort (); ! 1628: return temp; ! 1629: ! 1630: case ABS_EXPR: ! 1631: /* First try to do it with a special abs instruction. ! 1632: If that does not win, use conditional jump and negate. */ ! 1633: op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0); ! 1634: temp = expand_unop (mode, abs_optab, op0, target, 0); ! 1635: if (temp != 0) ! 1636: return temp; ! 1637: temp = gen_label_rtx (); ! 1638: if (target == 0 || GET_CODE (target) != REG) ! 1639: target = gen_reg_rtx (GET_MODE (op0)); ! 1640: emit_move_insn (target, op0); ! 1641: emit_tst_insn (target); ! 1642: emit_jump_insn (gen_bge (temp)); ! 1643: op0 = expand_unop (mode, neg_optab, target, target, 0); ! 1644: if (op0 != target) ! 1645: emit_move_insn (target, op0); ! 1646: emit_label (temp); ! 1647: return target; ! 1648: ! 1649: case MAX_EXPR: ! 1650: case MIN_EXPR: ! 1651: op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0); ! 1652: if (target == 0 || GET_CODE (target) != REG || target == op1) ! 1653: target = gen_reg_rtx (GET_MODE (op0)); ! 1654: op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0); ! 1655: if (target != op0) ! 1656: emit_move_insn (target, op0); ! 1657: op0 = gen_label_rtx (); ! 1658: if (code == MAX_EXPR) ! 1659: temp = (type_unsigned_p (TREE_TYPE (TREE_OPERAND (exp, 1))) ! 1660: ? compare1 (target, op1, GEU, LEU, 1) ! 1661: : compare1 (target, op1, GE, LE, 0)); ! 1662: else ! 1663: temp = (type_unsigned_p (TREE_TYPE (TREE_OPERAND (exp, 1))) ! 1664: ? compare1 (target, op1, LEU, GEU, 1) ! 1665: : compare1 (target, op1, LE, GE, 0)); ! 1666: emit_jump_insn (gen_rtx (SET, VOIDmode, pc_rtx, ! 1667: gen_rtx (IF_THEN_ELSE, VOIDmode, ! 1668: temp, ! 1669: gen_rtx (LABEL_REF, VOIDmode, op0), ! 1670: pc_rtx))); ! 1671: emit_move_insn (target, op1); ! 1672: emit_label (temp); ! 1673: return target; ! 1674: ! 1675: /* ??? Can optimize when the operand of this is a bitwise operation, ! 1676: by using a different bitwise operation. */ ! 1677: case BIT_NOT_EXPR: ! 1678: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); ! 1679: temp = expand_unop (mode, one_cmpl_optab, op0, target, 1); ! 1680: if (temp == 0) ! 1681: abort (); ! 1682: return temp; ! 1683: ! 1684: /* ??? Can optimize bitwise operations with one arg constant. ! 1685: Pastel optimizes (a bitwise1 n) bitwise2 (a bitwise3 b) ! 1686: and (a bitwise1 b) bitwise2 b (etc) ! 1687: but that is probably not worth while. */ ! 1688: ! 1689: /* AND_EXPR is for bitwise anding. ! 1690: TRUTH_AND_EXPR is for anding two boolean values ! 1691: when we want in all cases to compute both of them. ! 1692: In general it is fastest to do TRUTH_AND_EXPR by ! 1693: computing both operands as actual zero-or-1 values ! 1694: and then bitwise anding. In cases where there cannot ! 1695: be any side effects, better code would be made by ! 1696: treating TRUTH_AND_EXPR like TRUTH_ANDIF_EXPR; ! 1697: but the question is how to recognize those cases. */ ! 1698: ! 1699: case TRUTH_AND_EXPR: ! 1700: case BIT_AND_EXPR: ! 1701: preexpand_calls (exp); ! 1702: subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1)); ! 1703: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); ! 1704: op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0); ! 1705: return expand_bit_and (mode, op0, op1, target); ! 1706: ! 1707: /* See comment above about TRUTH_AND_EXPR; it applies here too. */ ! 1708: case TRUTH_OR_EXPR: ! 1709: case BIT_IOR_EXPR: ! 1710: preexpand_calls (exp); ! 1711: this_optab = ior_optab; ! 1712: goto binop; ! 1713: ! 1714: case BIT_XOR_EXPR: ! 1715: preexpand_calls (exp); ! 1716: this_optab = xor_optab; ! 1717: goto binop; ! 1718: ! 1719: case LSHIFT_EXPR: ! 1720: case RSHIFT_EXPR: ! 1721: case LROTATE_EXPR: ! 1722: case RROTATE_EXPR: ! 1723: preexpand_calls (exp); ! 1724: subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1)); ! 1725: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); ! 1726: return expand_shift (code, mode, op0, TREE_OPERAND (exp, 1), target, ! 1727: type_unsigned_p (type)); ! 1728: ! 1729: /* ??? cv's were used to effect here to combine additive constants ! 1730: and to determine the answer when only additive constants differ. ! 1731: Also, the addition of one can be handled by changing the condition. */ ! 1732: case LT_EXPR: ! 1733: case LE_EXPR: ! 1734: case GT_EXPR: ! 1735: case GE_EXPR: ! 1736: case EQ_EXPR: ! 1737: case NE_EXPR: ! 1738: preexpand_calls (exp); ! 1739: temp = do_store_flag (exp, target); ! 1740: if (temp != 0) ! 1741: return temp; ! 1742: if (code == NE_EXPR && integer_zerop (TREE_OPERAND (exp, 1))) ! 1743: { ! 1744: /* For foo != 0, load foo, and if it is nonzero load 1 instead. */ ! 1745: temp = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); ! 1746: if (temp != subtarget) ! 1747: temp = copy_to_reg (temp); ! 1748: op1 = gen_label_rtx (); ! 1749: emit_cmp_insn (temp, const0_rtx, 0, type_unsigned_p (type)); ! 1750: emit_jump_insn (gen_beq (op1)); ! 1751: emit_move_insn (temp, const1_rtx); ! 1752: emit_label (op1); ! 1753: return temp; ! 1754: } ! 1755: /* If no set-flag instruction, must generate a conditional ! 1756: store into a temporary variable. Drop through ! 1757: and handle this like && and ||. */ ! 1758: ! 1759: case TRUTH_ANDIF_EXPR: ! 1760: case TRUTH_ORIF_EXPR: ! 1761: temp = gen_reg_rtx (mode); ! 1762: emit_clr_insn (temp); ! 1763: op1 = gen_label_rtx (); ! 1764: jumpifnot (exp, op1); ! 1765: emit_0_to_1_insn (temp); ! 1766: emit_label (op1); ! 1767: return temp; ! 1768: ! 1769: case TRUTH_NOT_EXPR: ! 1770: op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0); ! 1771: /* The parser is careful to generate TRUTH_NOT_EXPR ! 1772: only with operands that are always zero or one. */ ! 1773: temp = expand_binop (mode, xor_optab, op0, ! 1774: gen_rtx (CONST_INT, mode, 1), ! 1775: target, 1, OPTAB_LIB_WIDEN); ! 1776: if (temp == 0) ! 1777: abort (); ! 1778: return temp; ! 1779: ! 1780: case COMPOUND_EXPR: ! 1781: expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0); ! 1782: emit_queue (); ! 1783: return expand_expr (TREE_OPERAND (exp, 1), target, VOIDmode, 0); ! 1784: ! 1785: case COND_EXPR: ! 1786: /* Note that COND_EXPRs whose type is a structure or union ! 1787: are required to be constructed to contain assignments of ! 1788: a temporary variable, so that we can evaluate them here ! 1789: for side effect only. If type is void, we must do likewise. */ ! 1790: op0 = gen_label_rtx (); ! 1791: op1 = gen_label_rtx (); ! 1792: ! 1793: if (mode == BLKmode || mode == VOIDmode) ! 1794: temp = 0; ! 1795: else if (target) ! 1796: temp = target; ! 1797: else ! 1798: temp = gen_reg_rtx (mode); ! 1799: ! 1800: jumpifnot (TREE_OPERAND (exp, 0), op0); ! 1801: current_args_size += 1; ! 1802: if (temp != 0) ! 1803: store_expr (TREE_OPERAND (exp, 1), temp); ! 1804: else ! 1805: expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0); ! 1806: emit_queue (); ! 1807: emit_jump_insn (gen_jump (op1)); ! 1808: emit_barrier (); ! 1809: emit_label (op0); ! 1810: if (temp != 0) ! 1811: store_expr (TREE_OPERAND (exp, 2), temp); ! 1812: else ! 1813: expand_expr (TREE_OPERAND (exp, 2), 0, VOIDmode, 0); ! 1814: emit_queue (); ! 1815: emit_label (op1); ! 1816: current_args_size -= 1; ! 1817: return temp; ! 1818: ! 1819: case MODIFY_EXPR: ! 1820: /* If lhs is complex, expand calls in rhs before computing it. ! 1821: That's so we don't compute a pointer and save it over a call. ! 1822: If lhs is simple, compute it first so we can give it as a ! 1823: target if the rhs is just a call. This avoids an extra temp and copy ! 1824: and that prevents a partial-subsumption which makes bad code. ! 1825: Actually we could treat component_ref's of vars like vars. */ ! 1826: if (TREE_CODE (TREE_OPERAND (exp, 0)) != VAR_DECL) ! 1827: preexpand_calls (exp); ! 1828: temp = expand_assignment (TREE_OPERAND (exp, 0), ! 1829: TREE_OPERAND (exp, 1)); ! 1830: return temp; ! 1831: ! 1832: case PREINCREMENT_EXPR: ! 1833: op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0); ! 1834: op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0); ! 1835: expand_binop (mode, add_optab, copy_rtx (op0), op1, copy_rtx (op0), ! 1836: 0, OPTAB_LIB_WIDEN); ! 1837: return op0; ! 1838: ! 1839: case PREDECREMENT_EXPR: ! 1840: op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0); ! 1841: op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0); ! 1842: expand_binop (mode, sub_optab, copy_rtx (op0), op1, copy_rtx (op0), ! 1843: 0, OPTAB_LIB_WIDEN); ! 1844: return op0; ! 1845: ! 1846: case POSTINCREMENT_EXPR: ! 1847: op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0); ! 1848: op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0); ! 1849: op0 = stabilize (op0); ! 1850: return enqueue_insn (op0, gen_add2_insn (copy_rtx (op0), op1)); ! 1851: ! 1852: case POSTDECREMENT_EXPR: ! 1853: op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0); ! 1854: op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0); ! 1855: op0 = stabilize (op0); ! 1856: return enqueue_insn (op0, gen_sub2_insn (copy_rtx (op0), op1)); ! 1857: ! 1858: case ADDR_EXPR: ! 1859: op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0); ! 1860: if (GET_CODE (op0) == VOLATILE) ! 1861: op0 = XEXP (op0, 0); ! 1862: if (GET_CODE (op0) != MEM) ! 1863: abort (); ! 1864: if (sum_ok) ! 1865: return XEXP (op0, 0); ! 1866: return force_operand (XEXP (op0, 0), target); ! 1867: ! 1868: case ENTRY_VALUE_EXPR: ! 1869: abort (); ! 1870: ! 1871: case ERROR_MARK: ! 1872: return gen_rtx (CONST_INT, (mode != VOIDmode) ? mode : SImode, 0); ! 1873: ! 1874: default: ! 1875: abort (); ! 1876: } ! 1877: ! 1878: /* Here to do an ordinary binary operator, generating an instruction ! 1879: from the optab already placed in `this_optab'. */ ! 1880: binop: ! 1881: /* Detect things like x = y | (a == b) ! 1882: and do them as (x = y), (a == b ? x |= 1 : 0), x. */ ! 1883: /* First, get the comparison or conditional into the second arg. */ ! 1884: if (comparison_code[(int) TREE_CODE (TREE_OPERAND (exp, 0))] ! 1885: || (TREE_CODE (TREE_OPERAND (exp, 0)) == COND_EXPR ! 1886: && (integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 0), 1)) ! 1887: || integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 0), 2))))) ! 1888: { ! 1889: if (this_optab == ior_optab || this_optab == add_optab ! 1890: || this_optab == xor_optab) ! 1891: { ! 1892: tree exch = TREE_OPERAND (exp, 1); ! 1893: TREE_OPERAND (exp, 1) = TREE_OPERAND (exp, 0); ! 1894: TREE_OPERAND (exp, 0) = exch; ! 1895: } ! 1896: } ! 1897: if (comparison_code[(int) TREE_CODE (TREE_OPERAND (exp, 1))] ! 1898: || (TREE_CODE (TREE_OPERAND (exp, 1)) == COND_EXPR ! 1899: && (integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 1), 1)) ! 1900: || integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 1), 2))))) ! 1901: { ! 1902: if (this_optab == ior_optab || this_optab == add_optab ! 1903: || this_optab == xor_optab || this_optab == sub_optab ! 1904: || this_optab == lshl_optab || this_optab == ashl_optab ! 1905: || this_optab == lshr_optab || this_optab == ashr_optab ! 1906: || this_optab == rotl_optab || this_optab == rotr_optab) ! 1907: { ! 1908: tree thenexp, condexp; ! 1909: rtx thenv = 0; ! 1910: ! 1911: if (target == 0) target = gen_reg_rtx (mode); ! 1912: store_expr (TREE_OPERAND (exp, 0), target); ! 1913: op0 = gen_label_rtx (); ! 1914: ! 1915: if (TREE_CODE (TREE_OPERAND (exp, 1)) != COND_EXPR) ! 1916: { ! 1917: do_jump (TREE_OPERAND (exp, 1), op0, 0); ! 1918: thenv = const1_rtx; ! 1919: } ! 1920: else if (integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 1), 2))) ! 1921: { ! 1922: do_jump (TREE_OPERAND (TREE_OPERAND (exp, 1), 0), op0, 0); ! 1923: thenexp = TREE_OPERAND (TREE_OPERAND (exp, 1), 1); ! 1924: } ! 1925: else ! 1926: { ! 1927: do_jump (TREE_OPERAND (TREE_OPERAND (exp, 1), 0), 0, op0); ! 1928: thenexp = TREE_OPERAND (TREE_OPERAND (exp, 1), 2); ! 1929: } ! 1930: ! 1931: if (thenv == 0) ! 1932: thenv = expand_expr (thenexp, 0, VOIDmode, 0); ! 1933: ! 1934: if (this_optab == rotl_optab || this_optab == rotr_optab) ! 1935: temp = expand_binop (mode, this_optab, target, thenv, target, ! 1936: -1, OPTAB_LIB); ! 1937: else if (this_optab == lshl_optab || this_optab == lshr_optab) ! 1938: temp = expand_binop (mode, this_optab, target, thenv, target, ! 1939: 1, OPTAB_LIB_WIDEN); ! 1940: else ! 1941: temp = expand_binop (mode, this_optab, target, thenv, target, ! 1942: 0, OPTAB_LIB_WIDEN); ! 1943: if (target != temp) ! 1944: emit_move_insn (target, temp); ! 1945: ! 1946: emit_label (op0); ! 1947: return target; ! 1948: } ! 1949: } ! 1950: subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1)); ! 1951: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); ! 1952: op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0); ! 1953: binop2: ! 1954: temp = expand_binop (mode, this_optab, op0, op1, target, ! 1955: type_unsigned_p (TREE_TYPE (exp)), OPTAB_LIB_WIDEN); ! 1956: binop1: ! 1957: if (temp == 0) ! 1958: abort (); ! 1959: return temp; ! 1960: } ! 1961: ! 1962: /* Expand all function calls contained within EXP, innermost ones first. ! 1963: But don't look within expressions that have sequence points. ! 1964: For each CALL_EXPR, record the rtx for its value ! 1965: in the CALL_EXPR_RTL field.. */ ! 1966: ! 1967: static void ! 1968: preexpand_calls (exp) ! 1969: tree exp; ! 1970: { ! 1971: register int nops, i; ! 1972: ! 1973: if (! do_preexpand_calls) ! 1974: return; ! 1975: ! 1976: switch (TREE_CODE (exp)) ! 1977: { ! 1978: case CALL_EXPR: ! 1979: if (CALL_EXPR_RTL (exp) == 0) ! 1980: CALL_EXPR_RTL (exp) = expand_call (exp, 0); ! 1981: return; ! 1982: ! 1983: case COMPOUND_EXPR: ! 1984: case COND_EXPR: ! 1985: case TRUTH_ANDIF_EXPR: ! 1986: case TRUTH_ORIF_EXPR: ! 1987: /* If we find one of these, then we can be sure ! 1988: the adjust will be done for it (since it makes jumps). ! 1989: Do it now, so that if this is inside an argument ! 1990: of a function, we don't get the stack adjustment ! 1991: after some other args have already been pushed. */ ! 1992: do_pending_stack_adjust (); ! 1993: return; ! 1994: ! 1995: case SAVE_EXPR: ! 1996: if (SAVE_EXPR_RTL (exp) != 0) ! 1997: return; ! 1998: } ! 1999: ! 2000: nops = tree_code_length[(int) TREE_CODE (exp)]; ! 2001: for (i = 0; i < nops; i++) ! 2002: if (TREE_OPERAND (exp, i) != 0) ! 2003: { ! 2004: register int type = *tree_code_type[(int) TREE_CODE (TREE_OPERAND (exp, i))]; ! 2005: if (type == 'e' || type == 'r') ! 2006: preexpand_calls (TREE_OPERAND (exp, i)); ! 2007: } ! 2008: } ! 2009: ! 2010: /* Generate instructions to call function FUNEXP and pass ! 2011: it the static chain. NARGS is the "number of args", ! 2012: to put in the call instruction on machines that require this. ! 2013: Also generate the code to pop the args after returning, ! 2014: (ARGS_SIZE is size of stuff to pop, in bytes). */ ! 2015: ! 2016: static void ! 2017: gen_call_1 (funexp, context, nargs, args_size) ! 2018: rtx funexp; ! 2019: rtx context; ! 2020: int nargs; ! 2021: int args_size; ! 2022: { ! 2023: funexp = protect_from_queue (funexp, 0); ! 2024: if (context) ! 2025: context = protect_from_queue (context, 0); ! 2026: ! 2027: /* Function variable in language with nested functions. */ ! 2028: if (GET_MODE (funexp) == EPmode) ! 2029: { ! 2030: register rtx reg = gen_rtx (REG, Pmode, STATIC_CHAIN_REGNUM); ! 2031: emit_insn (gen_movsi (reg, gen_highpart (Pmode, funexp))); ! 2032: emit_insn (gen_rtx (USE, VOIDmode, reg)); ! 2033: funexp = memory_address (QImode, gen_lowpart (Pmode, funexp)); ! 2034: emit_call_insn (gen_call (gen_rtx (MEM, QImode, funexp), ! 2035: gen_rtx (CONST_INT, VOIDmode, nargs))); ! 2036: } ! 2037: else ! 2038: { ! 2039: if (context != 0) ! 2040: { ! 2041: /* Unless function variable in C, or top level function constant */ ! 2042: register rtx reg = gen_rtx (REG, Pmode, STATIC_CHAIN_REGNUM); ! 2043: emit_insn (gen_movsi (reg, lookup_static_chain (context))); ! 2044: emit_insn (gen_rtx (USE, VOIDmode, reg)); ! 2045: } ! 2046: emit_call_insn (gen_call (gen_rtx (MEM, QImode, ! 2047: memory_address (QImode, funexp)), ! 2048: gen_rtx (CONST_INT, VOIDmode, nargs))); ! 2049: } ! 2050: /* If returning from the subroutine does not automatically pop the args, ! 2051: we need an instruction to pop them sooner or later. ! 2052: Perhaps do it now; perhaps just record how much space to pop later. */ ! 2053: current_args_size -= args_size; ! 2054: #ifndef RETURN_POPS_ARGS ! 2055: if (args_size != 0) ! 2056: { ! 2057: if (TARGET_DEFER_POP && current_args_size == 0) ! 2058: pending_stack_adjust += args_size; ! 2059: else ! 2060: adjust_stack (gen_rtx (CONST_INT, VOIDmode, args_size)); ! 2061: } ! 2062: #endif ! 2063: } ! 2064: ! 2065: /* At the start of a function, record that we have no previously-pushed ! 2066: arguments waiting to be popped. */ ! 2067: ! 2068: clear_pending_stack_adjust () ! 2069: { ! 2070: pending_stack_adjust = 0; ! 2071: } ! 2072: ! 2073: /* At start of function, initialize. */ ! 2074: clear_current_args_size () ! 2075: { ! 2076: current_args_size = 0; ! 2077: } ! 2078: ! 2079: /* Pop any previously-pushed arguments that have not been popped yet. */ ! 2080: ! 2081: do_pending_stack_adjust () ! 2082: { ! 2083: if (current_args_size == 0) ! 2084: { ! 2085: if (pending_stack_adjust != 0) ! 2086: adjust_stack (gen_rtx (CONST_INT, VOIDmode, pending_stack_adjust)); ! 2087: pending_stack_adjust = 0; ! 2088: } ! 2089: } ! 2090: ! 2091: /* Generate all the code for a function call ! 2092: and return an rtx for its value. ! 2093: Store the value in TARGET (specified as an rtx) if convenient. ! 2094: If the value is stored in TARGET then TARGET is returned. */ ! 2095: ! 2096: static rtx ! 2097: expand_call (exp, target) ! 2098: tree exp; ! 2099: rtx target; ! 2100: { ! 2101: tree actparms = TREE_OPERAND (exp, 1); ! 2102: register tree p; ! 2103: int args_size = 0; ! 2104: register int i; ! 2105: register tree *argvec; ! 2106: int num_actuals; ! 2107: rtx structure_value_addr = 0; ! 2108: ! 2109: /* Don't let pending stack adjusts add up to too much. ! 2110: Also, do all pending adjustments now ! 2111: if there is any chance this might be a call to alloca. */ ! 2112: ! 2113: if (pending_stack_adjust >= 32 ! 2114: || (pending_stack_adjust > 0 ! 2115: && ! 2116: /* Unless it's a call to a specific function that isn't alloca, ! 2117: we must assume it might be alloca. */ ! 2118: !(p = TREE_OPERAND (exp, 0), ! 2119: TREE_CODE (p) == ADDR_EXPR ! 2120: && TREE_CODE (TREE_OPERAND (p, 0)) == FUNCTION_DECL ! 2121: && strcmp (IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (p, 0))), ! 2122: "alloca")))) ! 2123: do_pending_stack_adjust (); ! 2124: ! 2125: if (TYPE_MODE (TREE_TYPE (exp)) == BLKmode) ! 2126: { ! 2127: /* This call returns a big structure. */ ! 2128: if (target) ! 2129: structure_value_addr = XEXP (target, 0); ! 2130: else ! 2131: /* Make room on the stack to hold the value. */ ! 2132: structure_value_addr = get_structure_value_addr (expr_size (exp)); ! 2133: } ! 2134: ! 2135: for (p = actparms, i = 0; p; p = TREE_CHAIN (p)) i++; ! 2136: num_actuals = i; ! 2137: argvec = (tree *) alloca (i * sizeof (tree)); ! 2138: ! 2139: #ifdef STACK_GROWS_DOWNWARD ! 2140: /* In this case, must reverse order of args ! 2141: so that we compute and pust the last arg first. */ ! 2142: for (p = actparms, i = num_actuals - 1; p; p = TREE_CHAIN (p), i--) ! 2143: argvec[i] = p; ! 2144: #else ! 2145: for (p = actparms, i = 0; p; p = TREE_CHAIN (p), i++) ! 2146: argvec[i] = p; ! 2147: #endif ! 2148: ! 2149: for (i = 0; i < num_actuals; i++) ! 2150: { ! 2151: register tree p = argvec[i]; ! 2152: register tree pval = TREE_VALUE (p); ! 2153: ! 2154: /* Push the next argument. Note that it has already been converted ! 2155: if necessary to the type that the called function expects. */ ! 2156: ! 2157: if (TREE_CODE (pval) == ERROR_MARK) ! 2158: ; ! 2159: else if (TYPE_MODE (TREE_TYPE (pval)) != BLKmode) ! 2160: { ! 2161: register int size, used; ! 2162: ! 2163: /* Argument is a scalar. ! 2164: Push it, and if its size is less than the ! 2165: amount of space allocated to it, ! 2166: also bump stack pointer by the additional space. ! 2167: Note that in C the default argument promotions ! 2168: will prevent such mismatches. */ ! 2169: ! 2170: used = size = GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (pval))); ! 2171: /* Compute how much space the push instruction will push. ! 2172: On many machines, pushing a byte will advance the stack ! 2173: pointer by a halfword. */ ! 2174: size = PUSH_ROUNDING (size); ! 2175: /* Compute how much space the argument should get: ! 2176: round up to a multiple of the alignment for arguments. */ ! 2177: used = (((size + PARM_BOUNDARY / BITS_PER_UNIT - 1) ! 2178: / (PARM_BOUNDARY / BITS_PER_UNIT)) ! 2179: * (PARM_BOUNDARY / BITS_PER_UNIT)); ! 2180: ! 2181: #ifdef STACK_GROWS_DOWNWARD ! 2182: if (size != used) ! 2183: anti_adjust_stack (gen_rtx (CONST_INT, VOIDmode, ! 2184: used - size)); ! 2185: #endif ! 2186: ! 2187: emit_push_insn (expand_expr (pval, 0, VOIDmode, 0), ! 2188: TYPE_MODE (TREE_TYPE (pval)), 0, 0); ! 2189: ! 2190: #ifndef STACK_GROWS_DOWNWARD ! 2191: if (size != used) ! 2192: anti_adjust_stack (gen_rtx (CONST_INT, VOIDmode, ! 2193: used - size)); ! 2194: #endif ! 2195: ! 2196: /* Account for the space thus used. */ ! 2197: args_size += used; ! 2198: current_args_size += used; ! 2199: } ! 2200: else ! 2201: { ! 2202: register rtx tem = expand_expr (pval, 0, VOIDmode, 0); ! 2203: register tree size = size_in_bytes (TREE_TYPE (pval)); ! 2204: register tree used; ! 2205: register int excess; ! 2206: ! 2207: /* Pushing a nonscalar. Round its size up to a multiple ! 2208: of the allocation unit for arguments. This part works ! 2209: on variable-size objects since SIZE and USED are rtx's. */ ! 2210: ! 2211: used = convert_units (convert_units (size, BITS_PER_UNIT, PARM_BOUNDARY), ! 2212: PARM_BOUNDARY, BITS_PER_UNIT); ! 2213: ! 2214: if (!TREE_LITERAL (used)) ! 2215: abort (); ! 2216: ! 2217: excess = TREE_INT_CST_LOW (used) - PUSH_ROUNDING (TREE_INT_CST_LOW (size)); ! 2218: ! 2219: #ifdef STACK_GROWS_DOWNWARD ! 2220: if (excess != 0) ! 2221: anti_adjust_stack (gen_rtx (CONST_INT, VOIDmode, excess)); ! 2222: #endif ! 2223: ! 2224: emit_push_insn (tem, TYPE_MODE (TREE_TYPE (pval)), ! 2225: expand_expr (size, 0, VOIDmode, 0), ! 2226: (TYPE_ALIGN (TREE_TYPE (pval)) ! 2227: / BITS_PER_UNIT)); ! 2228: ! 2229: #ifndef STACK_GROWS_DOWNWARD ! 2230: if (excess != 0) ! 2231: anti_adjust_stack (gen_rtx (CONST_INT, VOIDmode, excess)); ! 2232: #endif ! 2233: args_size += TREE_INT_CST_LOW (used); ! 2234: current_args_size += TREE_INT_CST_LOW (used); ! 2235: } ! 2236: } ! 2237: ! 2238: /* Perform postincrements before actually calling the function. */ ! 2239: emit_queue (); ! 2240: ! 2241: /* Pass the function the address in which to return a structure value. */ ! 2242: if (structure_value_addr) ! 2243: { ! 2244: register rtx reg = gen_rtx (REG, Pmode, STRUCT_VALUE_REGNUM); ! 2245: emit_move_insn (reg, structure_value_addr); ! 2246: emit_insn (gen_rtx (USE, VOIDmode, reg)); ! 2247: } ! 2248: ! 2249: gen_call_1 (expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0), ! 2250: /* ??? For Pascal, this must pass a context to get the static chain from ! 2251: in certain cases. */ ! 2252: 0, ! 2253: args_size / GET_MODE_SIZE (SImode), args_size); ! 2254: ! 2255: /* ??? Nothing has been done here to record control flow ! 2256: when contained functions can do nonlocal gotos. */ ! 2257: ! 2258: /* If value type not void, return an rtx for the value. */ ! 2259: ! 2260: if (TYPE_MODE (TREE_TYPE (exp)) == VOIDmode) ! 2261: return 0; ! 2262: ! 2263: if (structure_value_addr) ! 2264: { ! 2265: if (target) ! 2266: return target; ! 2267: return gen_rtx (MEM, BLKmode, structure_value_addr); ! 2268: } ! 2269: ! 2270: if (target && GET_MODE (target) == TYPE_MODE (TREE_TYPE (exp))) ! 2271: { ! 2272: copy_function_value (target); ! 2273: return target; ! 2274: } ! 2275: return function_value (TYPE_MODE (TREE_TYPE (exp))); ! 2276: } ! 2277: ! 2278: /* Expand conditional expressions. */ ! 2279: ! 2280: /* Generate code to evaluate EXP and jump to LABEL if the value is zero. ! 2281: LABEL is an rtx of code CODE_LABEL, in this function and all the ! 2282: functions here. */ ! 2283: ! 2284: jumpifnot (exp, label) ! 2285: tree exp; ! 2286: rtx label; ! 2287: { ! 2288: do_jump (exp, label, 0); ! 2289: } ! 2290: ! 2291: /* Generate code to evaluate EXP and jump to LABEL if the value is nonzero. */ ! 2292: ! 2293: jumpif (exp, label) ! 2294: tree exp; ! 2295: rtx label; ! 2296: { ! 2297: do_jump (exp, 0, label); ! 2298: } ! 2299: ! 2300: /* Generate code to evaluate EXP and jump to IF_FALSE_LABEL if ! 2301: the result is zero, or IF_TRUE_LABEL if the result is one. ! 2302: Either of IF_FALSE_LABEL and IF_TRUE_LABEL may be zero, ! 2303: meaning fall through in that case. ! 2304: ! 2305: This function is responsible for optimizing cases such as ! 2306: &&, || and comparison operators in EXP. */ ! 2307: ! 2308: do_jump (exp, if_false_label, if_true_label) ! 2309: tree exp; ! 2310: rtx if_false_label, if_true_label; ! 2311: { ! 2312: register enum tree_code code = TREE_CODE (exp); ! 2313: /* Some cases need to create a label to jump to ! 2314: in order to properly fall through. ! 2315: These cases set DROP_THROUGH_LABEL nonzero. */ ! 2316: rtx drop_through_label = 0; ! 2317: rtx temp; ! 2318: rtx comparison = 0; ! 2319: ! 2320: emit_queue (); ! 2321: ! 2322: switch (code) ! 2323: { ! 2324: case ERROR_MARK: ! 2325: break; ! 2326: ! 2327: case INTEGER_CST: ! 2328: temp = integer_zerop (exp) ? if_false_label : if_true_label; ! 2329: if (temp) ! 2330: emit_jump (temp); ! 2331: break; ! 2332: ! 2333: case ADDR_EXPR: ! 2334: /* The address of something can never be zero. */ ! 2335: if (if_true_label) ! 2336: emit_jump (if_true_label); ! 2337: break; ! 2338: ! 2339: case NOP_EXPR: ! 2340: do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label); ! 2341: break; ! 2342: ! 2343: case TRUTH_NOT_EXPR: ! 2344: do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label); ! 2345: break; ! 2346: ! 2347: case TRUTH_ANDIF_EXPR: ! 2348: if (if_false_label == 0) ! 2349: if_false_label = drop_through_label = gen_label_rtx (); ! 2350: do_jump (TREE_OPERAND (exp, 0), if_false_label, 0); ! 2351: do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label); ! 2352: break; ! 2353: ! 2354: case TRUTH_ORIF_EXPR: ! 2355: if (if_true_label == 0) ! 2356: if_true_label = drop_through_label = gen_label_rtx (); ! 2357: do_jump (TREE_OPERAND (exp, 0), 0, if_true_label); ! 2358: do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label); ! 2359: break; ! 2360: ! 2361: case COMPOUND_EXPR: ! 2362: expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0); ! 2363: emit_queue (); ! 2364: do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label); ! 2365: break; ! 2366: ! 2367: case COND_EXPR: ! 2368: { ! 2369: register rtx label1 = gen_label_rtx (); ! 2370: drop_through_label = gen_label_rtx (); ! 2371: do_jump (TREE_OPERAND (exp, 0), label1, 0); ! 2372: /* Now the THEN-expression. */ ! 2373: do_jump (TREE_OPERAND (exp, 1), ! 2374: if_false_label ? if_false_label : drop_through_label, ! 2375: if_true_label ? if_true_label : drop_through_label); ! 2376: emit_label (label1); ! 2377: /* Now the ELSE-expression. */ ! 2378: do_jump (TREE_OPERAND (exp, 2), ! 2379: if_false_label ? if_false_label : drop_through_label, ! 2380: if_true_label ? if_true_label : drop_through_label); ! 2381: } ! 2382: break; ! 2383: ! 2384: case EQ_EXPR: ! 2385: comparison = compare (exp, EQ, EQ, EQ, EQ); ! 2386: break; ! 2387: ! 2388: case NE_EXPR: ! 2389: comparison = compare (exp, NE, NE, NE, NE); ! 2390: break; ! 2391: ! 2392: case LT_EXPR: ! 2393: comparison = compare (exp, LT, LTU, GT, GTU); ! 2394: break; ! 2395: ! 2396: case LE_EXPR: ! 2397: comparison = compare (exp, LE, LEU, GE, GEU); ! 2398: break; ! 2399: ! 2400: case GT_EXPR: ! 2401: comparison = compare (exp, GT, GTU, LT, LTU); ! 2402: break; ! 2403: ! 2404: case GE_EXPR: ! 2405: comparison = compare (exp, GE, GEU, LE, LEU); ! 2406: break; ! 2407: ! 2408: default: ! 2409: temp = expand_expr (exp, 0, VOIDmode, 0); ! 2410: do_pending_stack_adjust (); ! 2411: emit_cmp_insn (temp, gen_rtx (CONST_INT, GET_MODE (temp), 0), ! 2412: 0, 0); ! 2413: ! 2414: if (if_true_label) ! 2415: emit_jump_insn (gen_bne (if_true_label)); ! 2416: if (if_false_label) ! 2417: { ! 2418: if (if_true_label) ! 2419: emit_jump (if_false_label); ! 2420: else ! 2421: emit_jump_insn (gen_beq (if_false_label)); ! 2422: } ! 2423: } ! 2424: ! 2425: /* If COMPARISON is nonzero here, it is an rtx that can be substituted ! 2426: straight into a conditional jump instruction as the jump condition. ! 2427: Otherwise, all the work has been done already. */ ! 2428: ! 2429: if (comparison) ! 2430: if (if_true_label) ! 2431: { ! 2432: emit_jump_insn (gen_rtx (SET, VOIDmode, pc_rtx, ! 2433: gen_rtx (IF_THEN_ELSE, VOIDmode, comparison, ! 2434: gen_rtx (LABEL_REF, VOIDmode, ! 2435: if_true_label), ! 2436: pc_rtx))); ! 2437: if (if_false_label) ! 2438: emit_jump (if_false_label); ! 2439: } ! 2440: else if (if_false_label) ! 2441: { ! 2442: emit_jump_insn (gen_rtx (SET, VOIDmode, pc_rtx, ! 2443: gen_rtx (IF_THEN_ELSE, VOIDmode, comparison, ! 2444: pc_rtx, ! 2445: gen_rtx (LABEL_REF, VOIDmode, ! 2446: if_false_label)))); ! 2447: } ! 2448: ! 2449: if (drop_through_label) ! 2450: emit_label (drop_through_label); ! 2451: } ! 2452: ! 2453: /* Generate code for a comparison expression EXP ! 2454: (including code to compute the values to be compared) ! 2455: and set (CC0) according to the result. ! 2456: SIGNED_FORWARD should be the rtx operation for this comparison for ! 2457: signed data; UNSIGNED_FORWARD, likewise for use if data is unsigned. ! 2458: SIGNED_REVERSE and UNSIGNED_REVERSE are used if it is desirable ! 2459: to interchange the operands for the compare instruction. ! 2460: ! 2461: We force a stack adjustment unless there are currently ! 2462: things pushed on the stack that aren't yet used. */ ! 2463: ! 2464: static rtx ! 2465: compare (exp, signed_forward, unsigned_forward, ! 2466: signed_reverse, unsigned_reverse) ! 2467: register tree exp; ! 2468: enum rtx_code signed_forward, unsigned_forward; ! 2469: enum rtx_code signed_reverse, unsigned_reverse; ! 2470: { ! 2471: register rtx op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0); ! 2472: register rtx op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0); ! 2473: register enum machine_mode mode = GET_MODE (op0); ! 2474: int unsignedp; ! 2475: ! 2476: /* If one operand is 0, make it the second one. */ ! 2477: ! 2478: if (op0 == const0_rtx || op0 == fconst0_rtx || op0 == dconst0_rtx) ! 2479: { ! 2480: rtx tem = op0; ! 2481: op0 = op1; ! 2482: op1 = tem; ! 2483: signed_forward = signed_reverse; ! 2484: unsigned_forward = unsigned_reverse; ! 2485: } ! 2486: ! 2487: if (force_mem) ! 2488: { ! 2489: op0 = force_not_mem (op0); ! 2490: op1 = force_not_mem (op1); ! 2491: } ! 2492: ! 2493: do_pending_stack_adjust (); ! 2494: ! 2495: unsignedp = (type_unsigned_p (TREE_TYPE (TREE_OPERAND (exp, 0))) ! 2496: || type_unsigned_p (TREE_TYPE (TREE_OPERAND (exp, 1)))); ! 2497: ! 2498: emit_cmp_insn (op0, op1, ! 2499: (mode == BLKmode) ? expr_size (TREE_OPERAND (exp, 0)) : 0, ! 2500: unsignedp); ! 2501: ! 2502: return gen_rtx ((unsignedp ? unsigned_forward : signed_forward), ! 2503: VOIDmode, cc0_rtx, const0_rtx); ! 2504: } ! 2505: ! 2506: /* Like compare but expects the values to compare as two rtx's. ! 2507: The decision as to signed or unsigned comparison must be made by the caller. ! 2508: BLKmode is not allowed. */ ! 2509: ! 2510: static rtx ! 2511: compare1 (op0, op1, forward_op, reverse_op, unsignedp) ! 2512: register rtx op0, op1; ! 2513: enum rtx_code forward_op, reverse_op; ! 2514: int unsignedp; ! 2515: { ! 2516: register enum machine_mode mode = GET_MODE (op0); ! 2517: ! 2518: /* If one operand is 0, make it the second one. */ ! 2519: ! 2520: if (op0 == const0_rtx || op0 == fconst0_rtx || op0 == dconst0_rtx) ! 2521: { ! 2522: rtx tem = op0; ! 2523: op0 = op1; ! 2524: op1 = tem; ! 2525: forward_op = reverse_op; ! 2526: } ! 2527: ! 2528: if (force_mem) ! 2529: { ! 2530: op0 = force_not_mem (op0); ! 2531: op1 = force_not_mem (op1); ! 2532: } ! 2533: ! 2534: do_pending_stack_adjust (); ! 2535: ! 2536: emit_cmp_insn (op0, op1, 0, unsignedp); ! 2537: ! 2538: return gen_rtx (forward_op, VOIDmode, cc0_rtx, const0_rtx); ! 2539: } ! 2540: ! 2541: /* Generate code to jump to LABEL if OP1 and OP2 are equal. */ ! 2542: ! 2543: void ! 2544: do_jump_if_equal (op1, op2, label) ! 2545: rtx op1, op2, label; ! 2546: { ! 2547: emit_cmp_insn (op1, op2, 0); ! 2548: emit_jump_insn (gen_beq (label)); ! 2549: } ! 2550: ! 2551: /* Generate code to calculate EXP using a store-flag instruction ! 2552: and return an rtx for the result. ! 2553: If TARGET is nonzero, store the result there if convenient. ! 2554: ! 2555: Return zero if there is no suitable set-flag instruction ! 2556: available on this machine. */ ! 2557: ! 2558: static rtx ! 2559: do_store_flag (exp, target) ! 2560: tree exp; ! 2561: rtx target; ! 2562: { ! 2563: register enum tree_code code = TREE_CODE (exp); ! 2564: register rtx comparison = 0; ! 2565: ! 2566: if (target == 0 || GET_MODE (target) != SImode) ! 2567: target = gen_reg_rtx (SImode); ! 2568: ! 2569: switch (code) ! 2570: { ! 2571: #ifdef HAVE_seqsi ! 2572: case EQ_EXPR: ! 2573: if (HAVE_seqsi) ! 2574: comparison = compare (exp, EQ, EQ, EQ, EQ); ! 2575: break; ! 2576: #endif ! 2577: ! 2578: #ifdef HAVE_snesi ! 2579: case NE_EXPR: ! 2580: if (HAVE_snesi) ! 2581: comparison = compare (exp, NE, NE, NE, NE); ! 2582: break; ! 2583: #endif ! 2584: ! 2585: #if defined (HAVE_sltsi) && defined (HAVE_sltusi) && defined (HAVE_sgtsi) && defined (HAVE_sgtusi) ! 2586: case LT_EXPR: ! 2587: if (HAVE_sltsi && HAVE_sltusi && HAVE_sgtsi && HAVE_sgtusi) ! 2588: comparison = compare (exp, LT, LTU, GT, GTU); ! 2589: break; ! 2590: ! 2591: case GT_EXPR: ! 2592: if (HAVE_sltsi && HAVE_sltusi && HAVE_sgtsi && HAVE_sgtusi) ! 2593: comparison = compare (exp, GT, GTU, LT, LTU); ! 2594: break; ! 2595: #endif ! 2596: ! 2597: #if defined (HAVE_slesi) && defined (HAVE_sleusi) && defined (HAVE_sgesi) && defined (HAVE_sgeusi) ! 2598: case LE_EXPR: ! 2599: if (HAVE_slesi && HAVE_sleusi && HAVE_sgesi && HAVE_sgeusi) ! 2600: comparison = compare (exp, LE, LEU, GE, GEU); ! 2601: break; ! 2602: ! 2603: case GE_EXPR: ! 2604: if (HAVE_slesi && HAVE_sleusi && HAVE_sgesi && HAVE_sgeusi) ! 2605: comparison = compare (exp, GE, GEU, LE, LEU); ! 2606: break; ! 2607: #endif ! 2608: } ! 2609: if (comparison == 0) ! 2610: return 0; ! 2611: ! 2612: emit_insn (gen_rtx (SET, VOIDmode, target, comparison)); ! 2613: expand_bit_and (GET_MODE (target), target, const1_rtx, target); ! 2614: return target; ! 2615: } ! 2616: ! 2617: /* Generate a tablejump instruction (used for switch statements). */ ! 2618: ! 2619: #ifdef HAVE_tablejump ! 2620: ! 2621: /* INDEX is the value being switched on, with the lowest value ! 2622: in the table already subtracted. ! 2623: RANGE is the length of the jump table. ! 2624: TABLE_LABEL is a CODE_LABEL rtx for the table itself. ! 2625: DEFAULT_LABEL is a CODE_LABEL rtx to jump to if the ! 2626: index value is out of range. */ ! 2627: ! 2628: void ! 2629: do_tablejump (index, range, table_label, default_label) ! 2630: rtx index, range, table_label, default_label; ! 2631: { ! 2632: register rtx temp; ! 2633: ! 2634: emit_cmp_insn (index, const0_rtx, 0); ! 2635: emit_jump_insn (gen_blt (default_label)); ! 2636: emit_cmp_insn (range, index, 0); ! 2637: emit_jump_insn (gen_blt (default_label)); ! 2638: index = memory_address (CASE_VECTOR_MODE, ! 2639: gen_rtx (PLUS, Pmode, ! 2640: gen_rtx (LABEL_REF, VOIDmode, table_label), ! 2641: gen_rtx (MULT, Pmode, index, ! 2642: gen_rtx (CONST_INT, VOIDmode, ! 2643: GET_MODE_SIZE (CASE_VECTOR_MODE))))); ! 2644: temp = gen_reg_rtx (CASE_VECTOR_MODE); ! 2645: convert_move (temp, gen_rtx (MEM, CASE_VECTOR_MODE, index), 0); ! 2646: ! 2647: emit_jump_insn (gen_tablejump (temp)); ! 2648: } ! 2649: ! 2650: #endif /* HAVE_tablejump */}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.