|
|
1.1 ! root 1: /* Expand the basic unary and binary arithmetic operations, for GNU compiler. ! 2: Copyright (C) 1987, 1988, 1992, 1993, 1994 Free Software Foundation, Inc. ! 3: ! 4: This file is part of GNU CC. ! 5: ! 6: GNU CC is free software; you can redistribute it and/or modify ! 7: it under the terms of the GNU General Public License as published by ! 8: the Free Software Foundation; either version 2, or (at your option) ! 9: any later version. ! 10: ! 11: GNU CC is distributed in the hope that it will be useful, ! 12: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 14: GNU General Public License for more details. ! 15: ! 16: You should have received a copy of the GNU General Public License ! 17: along with GNU CC; see the file COPYING. If not, write to ! 18: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ! 19: ! 20: ! 21: #include "config.h" ! 22: #include "rtl.h" ! 23: #include "tree.h" ! 24: #include "flags.h" ! 25: #include "insn-flags.h" ! 26: #include "insn-codes.h" ! 27: #include "expr.h" ! 28: #include "insn-config.h" ! 29: #include "recog.h" ! 30: #include "reload.h" ! 31: #include <ctype.h> ! 32: ! 33: /* Each optab contains info on how this target machine ! 34: can perform a particular operation ! 35: for all sizes and kinds of operands. ! 36: ! 37: The operation to be performed is often specified ! 38: by passing one of these optabs as an argument. ! 39: ! 40: See expr.h for documentation of these optabs. */ ! 41: ! 42: optab add_optab; ! 43: optab sub_optab; ! 44: optab smul_optab; ! 45: optab smul_widen_optab; ! 46: optab umul_widen_optab; ! 47: optab sdiv_optab; ! 48: optab sdivmod_optab; ! 49: optab udiv_optab; ! 50: optab udivmod_optab; ! 51: optab smod_optab; ! 52: optab umod_optab; ! 53: optab flodiv_optab; ! 54: optab ftrunc_optab; ! 55: optab and_optab; ! 56: optab ior_optab; ! 57: optab xor_optab; ! 58: optab ashl_optab; ! 59: optab lshr_optab; ! 60: optab ashr_optab; ! 61: optab rotl_optab; ! 62: optab rotr_optab; ! 63: optab smin_optab; ! 64: optab smax_optab; ! 65: optab umin_optab; ! 66: optab umax_optab; ! 67: ! 68: optab mov_optab; ! 69: optab movstrict_optab; ! 70: ! 71: optab neg_optab; ! 72: optab abs_optab; ! 73: optab one_cmpl_optab; ! 74: optab ffs_optab; ! 75: optab sqrt_optab; ! 76: optab sin_optab; ! 77: optab cos_optab; ! 78: ! 79: optab cmp_optab; ! 80: optab ucmp_optab; /* Used only for libcalls for unsigned comparisons. */ ! 81: optab tst_optab; ! 82: ! 83: optab strlen_optab; ! 84: ! 85: /* Tables of patterns for extending one integer mode to another. */ ! 86: enum insn_code extendtab[MAX_MACHINE_MODE][MAX_MACHINE_MODE][2]; ! 87: ! 88: /* Tables of patterns for converting between fixed and floating point. */ ! 89: enum insn_code fixtab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2]; ! 90: enum insn_code fixtrunctab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2]; ! 91: enum insn_code floattab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2]; ! 92: ! 93: /* Contains the optab used for each rtx code. */ ! 94: optab code_to_optab[NUM_RTX_CODE + 1]; ! 95: ! 96: /* SYMBOL_REF rtx's for the library functions that are called ! 97: implicitly and not via optabs. */ ! 98: ! 99: rtx extendsfdf2_libfunc; ! 100: rtx extendsfxf2_libfunc; ! 101: rtx extendsftf2_libfunc; ! 102: rtx extenddfxf2_libfunc; ! 103: rtx extenddftf2_libfunc; ! 104: ! 105: rtx truncdfsf2_libfunc; ! 106: rtx truncxfsf2_libfunc; ! 107: rtx trunctfsf2_libfunc; ! 108: rtx truncxfdf2_libfunc; ! 109: rtx trunctfdf2_libfunc; ! 110: ! 111: rtx memcpy_libfunc; ! 112: rtx bcopy_libfunc; ! 113: rtx memcmp_libfunc; ! 114: rtx bcmp_libfunc; ! 115: rtx memset_libfunc; ! 116: rtx bzero_libfunc; ! 117: ! 118: rtx eqsf2_libfunc; ! 119: rtx nesf2_libfunc; ! 120: rtx gtsf2_libfunc; ! 121: rtx gesf2_libfunc; ! 122: rtx ltsf2_libfunc; ! 123: rtx lesf2_libfunc; ! 124: ! 125: rtx eqdf2_libfunc; ! 126: rtx nedf2_libfunc; ! 127: rtx gtdf2_libfunc; ! 128: rtx gedf2_libfunc; ! 129: rtx ltdf2_libfunc; ! 130: rtx ledf2_libfunc; ! 131: ! 132: rtx eqxf2_libfunc; ! 133: rtx nexf2_libfunc; ! 134: rtx gtxf2_libfunc; ! 135: rtx gexf2_libfunc; ! 136: rtx ltxf2_libfunc; ! 137: rtx lexf2_libfunc; ! 138: ! 139: rtx eqtf2_libfunc; ! 140: rtx netf2_libfunc; ! 141: rtx gttf2_libfunc; ! 142: rtx getf2_libfunc; ! 143: rtx lttf2_libfunc; ! 144: rtx letf2_libfunc; ! 145: ! 146: rtx floatsisf_libfunc; ! 147: rtx floatdisf_libfunc; ! 148: rtx floattisf_libfunc; ! 149: ! 150: rtx floatsidf_libfunc; ! 151: rtx floatdidf_libfunc; ! 152: rtx floattidf_libfunc; ! 153: ! 154: rtx floatsixf_libfunc; ! 155: rtx floatdixf_libfunc; ! 156: rtx floattixf_libfunc; ! 157: ! 158: rtx floatsitf_libfunc; ! 159: rtx floatditf_libfunc; ! 160: rtx floattitf_libfunc; ! 161: ! 162: rtx fixsfsi_libfunc; ! 163: rtx fixsfdi_libfunc; ! 164: rtx fixsfti_libfunc; ! 165: ! 166: rtx fixdfsi_libfunc; ! 167: rtx fixdfdi_libfunc; ! 168: rtx fixdfti_libfunc; ! 169: ! 170: rtx fixxfsi_libfunc; ! 171: rtx fixxfdi_libfunc; ! 172: rtx fixxfti_libfunc; ! 173: ! 174: rtx fixtfsi_libfunc; ! 175: rtx fixtfdi_libfunc; ! 176: rtx fixtfti_libfunc; ! 177: ! 178: rtx fixunssfsi_libfunc; ! 179: rtx fixunssfdi_libfunc; ! 180: rtx fixunssfti_libfunc; ! 181: ! 182: rtx fixunsdfsi_libfunc; ! 183: rtx fixunsdfdi_libfunc; ! 184: rtx fixunsdfti_libfunc; ! 185: ! 186: rtx fixunsxfsi_libfunc; ! 187: rtx fixunsxfdi_libfunc; ! 188: rtx fixunsxfti_libfunc; ! 189: ! 190: rtx fixunstfsi_libfunc; ! 191: rtx fixunstfdi_libfunc; ! 192: rtx fixunstfti_libfunc; ! 193: ! 194: /* Indexed by the rtx-code for a conditional (eg. EQ, LT,...) ! 195: gives the gen_function to make a branch to test that condition. */ ! 196: ! 197: rtxfun bcc_gen_fctn[NUM_RTX_CODE]; ! 198: ! 199: /* Indexed by the rtx-code for a conditional (eg. EQ, LT,...) ! 200: gives the insn code to make a store-condition insn ! 201: to test that condition. */ ! 202: ! 203: enum insn_code setcc_gen_code[NUM_RTX_CODE]; ! 204: ! 205: static int add_equal_note PROTO((rtx, rtx, enum rtx_code, rtx, rtx)); ! 206: static rtx widen_operand PROTO((rtx, enum machine_mode, ! 207: enum machine_mode, int, int)); ! 208: static enum insn_code can_fix_p PROTO((enum machine_mode, enum machine_mode, ! 209: int, int *)); ! 210: static enum insn_code can_float_p PROTO((enum machine_mode, enum machine_mode, ! 211: int)); ! 212: static rtx ftruncify PROTO((rtx)); ! 213: static optab init_optab PROTO((enum rtx_code)); ! 214: static void init_libfuncs PROTO((optab, int, int, char *, int)); ! 215: static void init_integral_libfuncs PROTO((optab, char *, int)); ! 216: static void init_floating_libfuncs PROTO((optab, char *, int)); ! 217: static void init_complex_libfuncs PROTO((optab, char *, int)); ! 218: ! 219: /* Add a REG_EQUAL note to the last insn in SEQ. TARGET is being set to ! 220: the result of operation CODE applied to OP0 (and OP1 if it is a binary ! 221: operation). ! 222: ! 223: If the last insn does not set TARGET, don't do anything, but return 1. ! 224: ! 225: If a previous insn sets TARGET and TARGET is one of OP0 or OP1, ! 226: don't add the REG_EQUAL note but return 0. Our caller can then try ! 227: again, ensuring that TARGET is not one of the operands. */ ! 228: ! 229: static int ! 230: add_equal_note (seq, target, code, op0, op1) ! 231: rtx seq; ! 232: rtx target; ! 233: enum rtx_code code; ! 234: rtx op0, op1; ! 235: { ! 236: rtx set; ! 237: int i; ! 238: rtx note; ! 239: ! 240: if ((GET_RTX_CLASS (code) != '1' && GET_RTX_CLASS (code) != '2' ! 241: && GET_RTX_CLASS (code) != 'c' && GET_RTX_CLASS (code) != '<') ! 242: || GET_CODE (seq) != SEQUENCE ! 243: || (set = single_set (XVECEXP (seq, 0, XVECLEN (seq, 0) - 1))) == 0 ! 244: || GET_CODE (target) == ZERO_EXTRACT ! 245: || (! rtx_equal_p (SET_DEST (set), target) ! 246: /* For a STRICT_LOW_PART, the REG_NOTE applies to what is inside the ! 247: SUBREG. */ ! 248: && (GET_CODE (SET_DEST (set)) != STRICT_LOW_PART ! 249: || ! rtx_equal_p (SUBREG_REG (XEXP (SET_DEST (set), 0)), ! 250: target)))) ! 251: return 1; ! 252: ! 253: /* If TARGET is in OP0 or OP1, check if anything in SEQ sets TARGET ! 254: besides the last insn. */ ! 255: if (reg_overlap_mentioned_p (target, op0) ! 256: || (op1 && reg_overlap_mentioned_p (target, op1))) ! 257: for (i = XVECLEN (seq, 0) - 2; i >= 0; i--) ! 258: if (reg_set_p (target, XVECEXP (seq, 0, i))) ! 259: return 0; ! 260: ! 261: if (GET_RTX_CLASS (code) == '1') ! 262: note = gen_rtx (code, GET_MODE (target), copy_rtx (op0)); ! 263: else ! 264: note = gen_rtx (code, GET_MODE (target), copy_rtx (op0), copy_rtx (op1)); ! 265: ! 266: REG_NOTES (XVECEXP (seq, 0, XVECLEN (seq, 0) - 1)) ! 267: = gen_rtx (EXPR_LIST, REG_EQUAL, note, ! 268: REG_NOTES (XVECEXP (seq, 0, XVECLEN (seq, 0) - 1))); ! 269: ! 270: return 1; ! 271: } ! 272: ! 273: /* Widen OP to MODE and return the rtx for the widened operand. UNSIGNEDP ! 274: says whether OP is signed or unsigned. NO_EXTEND is nonzero if we need ! 275: not actually do a sign-extend or zero-extend, but can leave the ! 276: higher-order bits of the result rtx undefined, for example, in the case ! 277: of logical operations, but not right shifts. */ ! 278: ! 279: static rtx ! 280: widen_operand (op, mode, oldmode, unsignedp, no_extend) ! 281: rtx op; ! 282: enum machine_mode mode, oldmode; ! 283: int unsignedp; ! 284: int no_extend; ! 285: { ! 286: rtx result; ! 287: ! 288: /* If we must extend do so. If OP is either a constant or a SUBREG ! 289: for a promoted object, also extend since it will be more efficient to ! 290: do so. */ ! 291: if (! no_extend ! 292: || GET_MODE (op) == VOIDmode ! 293: || (GET_CODE (op) == SUBREG && SUBREG_PROMOTED_VAR_P (op))) ! 294: return convert_modes (mode, oldmode, op, unsignedp); ! 295: ! 296: /* If MODE is no wider than a single word, we return a paradoxical ! 297: SUBREG. */ ! 298: if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD) ! 299: return gen_rtx (SUBREG, mode, force_reg (GET_MODE (op), op), 0); ! 300: ! 301: /* Otherwise, get an object of MODE, clobber it, and set the low-order ! 302: part to OP. */ ! 303: ! 304: result = gen_reg_rtx (mode); ! 305: emit_insn (gen_rtx (CLOBBER, VOIDmode, result)); ! 306: emit_move_insn (gen_lowpart (GET_MODE (op), result), op); ! 307: return result; ! 308: } ! 309: ! 310: /* Generate code to perform an operation specified by BINOPTAB ! 311: on operands OP0 and OP1, with result having machine-mode MODE. ! 312: ! 313: UNSIGNEDP is for the case where we have to widen the operands ! 314: to perform the operation. It says to use zero-extension. ! 315: ! 316: If TARGET is nonzero, the value ! 317: is generated there, if it is convenient to do so. ! 318: In all cases an rtx is returned for the locus of the value; ! 319: this may or may not be TARGET. */ ! 320: ! 321: rtx ! 322: expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods) ! 323: enum machine_mode mode; ! 324: optab binoptab; ! 325: rtx op0, op1; ! 326: rtx target; ! 327: int unsignedp; ! 328: enum optab_methods methods; ! 329: { ! 330: enum mode_class class; ! 331: enum machine_mode wider_mode; ! 332: register rtx temp; ! 333: int commutative_op = 0; ! 334: int shift_op = (binoptab->code == ASHIFT ! 335: || binoptab->code == ASHIFTRT ! 336: || binoptab->code == LSHIFTRT ! 337: || binoptab->code == ROTATE ! 338: || binoptab->code == ROTATERT); ! 339: rtx entry_last = get_last_insn (); ! 340: rtx last; ! 341: ! 342: class = GET_MODE_CLASS (mode); ! 343: ! 344: op0 = protect_from_queue (op0, 0); ! 345: op1 = protect_from_queue (op1, 0); ! 346: if (target) ! 347: target = protect_from_queue (target, 1); ! 348: ! 349: if (flag_force_mem) ! 350: { ! 351: op0 = force_not_mem (op0); ! 352: op1 = force_not_mem (op1); ! 353: } ! 354: ! 355: /* If subtracting an integer constant, convert this into an addition of ! 356: the negated constant. */ ! 357: ! 358: if (binoptab == sub_optab && GET_CODE (op1) == CONST_INT) ! 359: { ! 360: op1 = negate_rtx (mode, op1); ! 361: binoptab = add_optab; ! 362: } ! 363: ! 364: /* If we are inside an appropriately-short loop and one operand is an ! 365: expensive constant, force it into a register. */ ! 366: if (CONSTANT_P (op0) && preserve_subexpressions_p () ! 367: && rtx_cost (op0, binoptab->code) > 2) ! 368: op0 = force_reg (mode, op0); ! 369: ! 370: if (CONSTANT_P (op1) && preserve_subexpressions_p () ! 371: && rtx_cost (op1, binoptab->code) > 2) ! 372: op1 = force_reg (shift_op ? word_mode : mode, op1); ! 373: ! 374: /* Record where to delete back to if we backtrack. */ ! 375: last = get_last_insn (); ! 376: ! 377: /* If operation is commutative, ! 378: try to make the first operand a register. ! 379: Even better, try to make it the same as the target. ! 380: Also try to make the last operand a constant. */ ! 381: if (GET_RTX_CLASS (binoptab->code) == 'c' ! 382: || binoptab == smul_widen_optab ! 383: || binoptab == umul_widen_optab) ! 384: { ! 385: commutative_op = 1; ! 386: ! 387: if (((target == 0 || GET_CODE (target) == REG) ! 388: ? ((GET_CODE (op1) == REG ! 389: && GET_CODE (op0) != REG) ! 390: || target == op1) ! 391: : rtx_equal_p (op1, target)) ! 392: || GET_CODE (op0) == CONST_INT) ! 393: { ! 394: temp = op1; ! 395: op1 = op0; ! 396: op0 = temp; ! 397: } ! 398: } ! 399: ! 400: /* If we can do it with a three-operand insn, do so. */ ! 401: ! 402: if (methods != OPTAB_MUST_WIDEN ! 403: && binoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing) ! 404: { ! 405: int icode = (int) binoptab->handlers[(int) mode].insn_code; ! 406: enum machine_mode mode0 = insn_operand_mode[icode][1]; ! 407: enum machine_mode mode1 = insn_operand_mode[icode][2]; ! 408: rtx pat; ! 409: rtx xop0 = op0, xop1 = op1; ! 410: ! 411: if (target) ! 412: temp = target; ! 413: else ! 414: temp = gen_reg_rtx (mode); ! 415: ! 416: /* If it is a commutative operator and the modes would match ! 417: if we would swap the operands, we can save the conversions. */ ! 418: if (commutative_op) ! 419: { ! 420: if (GET_MODE (op0) != mode0 && GET_MODE (op1) != mode1 ! 421: && GET_MODE (op0) == mode1 && GET_MODE (op1) == mode0) ! 422: { ! 423: register rtx tmp; ! 424: ! 425: tmp = op0; op0 = op1; op1 = tmp; ! 426: tmp = xop0; xop0 = xop1; xop1 = tmp; ! 427: } ! 428: } ! 429: ! 430: /* In case the insn wants input operands in modes different from ! 431: the result, convert the operands. */ ! 432: ! 433: if (GET_MODE (op0) != VOIDmode ! 434: && GET_MODE (op0) != mode0) ! 435: xop0 = convert_to_mode (mode0, xop0, unsignedp); ! 436: ! 437: if (GET_MODE (xop1) != VOIDmode ! 438: && GET_MODE (xop1) != mode1) ! 439: xop1 = convert_to_mode (mode1, xop1, unsignedp); ! 440: ! 441: /* Now, if insn's predicates don't allow our operands, put them into ! 442: pseudo regs. */ ! 443: ! 444: if (! (*insn_operand_predicate[icode][1]) (xop0, mode0)) ! 445: xop0 = copy_to_mode_reg (mode0, xop0); ! 446: ! 447: if (! (*insn_operand_predicate[icode][2]) (xop1, mode1)) ! 448: xop1 = copy_to_mode_reg (mode1, xop1); ! 449: ! 450: if (! (*insn_operand_predicate[icode][0]) (temp, mode)) ! 451: temp = gen_reg_rtx (mode); ! 452: ! 453: pat = GEN_FCN (icode) (temp, xop0, xop1); ! 454: if (pat) ! 455: { ! 456: /* If PAT is a multi-insn sequence, try to add an appropriate ! 457: REG_EQUAL note to it. If we can't because TEMP conflicts with an ! 458: operand, call ourselves again, this time without a target. */ ! 459: if (GET_CODE (pat) == SEQUENCE ! 460: && ! add_equal_note (pat, temp, binoptab->code, xop0, xop1)) ! 461: { ! 462: delete_insns_since (last); ! 463: return expand_binop (mode, binoptab, op0, op1, NULL_RTX, ! 464: unsignedp, methods); ! 465: } ! 466: ! 467: emit_insn (pat); ! 468: return temp; ! 469: } ! 470: else ! 471: delete_insns_since (last); ! 472: } ! 473: ! 474: /* If this is a multiply, see if we can do a widening operation that ! 475: takes operands of this mode and makes a wider mode. */ ! 476: ! 477: if (binoptab == smul_optab && GET_MODE_WIDER_MODE (mode) != VOIDmode ! 478: && (((unsignedp ? umul_widen_optab : smul_widen_optab) ! 479: ->handlers[(int) GET_MODE_WIDER_MODE (mode)].insn_code) ! 480: != CODE_FOR_nothing)) ! 481: { ! 482: temp = expand_binop (GET_MODE_WIDER_MODE (mode), ! 483: unsignedp ? umul_widen_optab : smul_widen_optab, ! 484: op0, op1, 0, unsignedp, OPTAB_DIRECT); ! 485: ! 486: if (GET_MODE_CLASS (mode) == MODE_INT) ! 487: return gen_lowpart (mode, temp); ! 488: else ! 489: return convert_to_mode (mode, temp, unsignedp); ! 490: } ! 491: ! 492: /* Look for a wider mode of the same class for which we think we ! 493: can open-code the operation. Check for a widening multiply at the ! 494: wider mode as well. */ ! 495: ! 496: if ((class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT) ! 497: && methods != OPTAB_DIRECT && methods != OPTAB_LIB) ! 498: for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode; ! 499: wider_mode = GET_MODE_WIDER_MODE (wider_mode)) ! 500: { ! 501: if (binoptab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing ! 502: || (binoptab == smul_optab ! 503: && GET_MODE_WIDER_MODE (wider_mode) != VOIDmode ! 504: && (((unsignedp ? umul_widen_optab : smul_widen_optab) ! 505: ->handlers[(int) GET_MODE_WIDER_MODE (wider_mode)].insn_code) ! 506: != CODE_FOR_nothing))) ! 507: { ! 508: rtx xop0 = op0, xop1 = op1; ! 509: int no_extend = 0; ! 510: ! 511: /* For certain integer operations, we need not actually extend ! 512: the narrow operands, as long as we will truncate ! 513: the results to the same narrowness. */ ! 514: ! 515: if ((binoptab == ior_optab || binoptab == and_optab ! 516: || binoptab == xor_optab ! 517: || binoptab == add_optab || binoptab == sub_optab ! 518: || binoptab == smul_optab || binoptab == ashl_optab) ! 519: && class == MODE_INT) ! 520: no_extend = 1; ! 521: ! 522: xop0 = widen_operand (xop0, wider_mode, mode, unsignedp, no_extend); ! 523: ! 524: /* The second operand of a shift must always be extended. */ ! 525: xop1 = widen_operand (xop1, wider_mode, mode, unsignedp, ! 526: no_extend && binoptab != ashl_optab); ! 527: ! 528: temp = expand_binop (wider_mode, binoptab, xop0, xop1, NULL_RTX, ! 529: unsignedp, OPTAB_DIRECT); ! 530: if (temp) ! 531: { ! 532: if (class != MODE_INT) ! 533: { ! 534: if (target == 0) ! 535: target = gen_reg_rtx (mode); ! 536: convert_move (target, temp, 0); ! 537: return target; ! 538: } ! 539: else ! 540: return gen_lowpart (mode, temp); ! 541: } ! 542: else ! 543: delete_insns_since (last); ! 544: } ! 545: } ! 546: ! 547: /* These can be done a word at a time. */ ! 548: if ((binoptab == and_optab || binoptab == ior_optab || binoptab == xor_optab) ! 549: && class == MODE_INT ! 550: && GET_MODE_SIZE (mode) > UNITS_PER_WORD ! 551: && binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing) ! 552: { ! 553: int i; ! 554: rtx insns; ! 555: rtx equiv_value; ! 556: ! 557: /* If TARGET is the same as one of the operands, the REG_EQUAL note ! 558: won't be accurate, so use a new target. */ ! 559: if (target == 0 || target == op0 || target == op1) ! 560: target = gen_reg_rtx (mode); ! 561: ! 562: start_sequence (); ! 563: ! 564: /* Do the actual arithmetic. */ ! 565: for (i = 0; i < GET_MODE_BITSIZE (mode) / BITS_PER_WORD; i++) ! 566: { ! 567: rtx target_piece = operand_subword (target, i, 1, mode); ! 568: rtx x = expand_binop (word_mode, binoptab, ! 569: operand_subword_force (op0, i, mode), ! 570: operand_subword_force (op1, i, mode), ! 571: target_piece, unsignedp, methods); ! 572: if (target_piece != x) ! 573: emit_move_insn (target_piece, x); ! 574: } ! 575: ! 576: insns = get_insns (); ! 577: end_sequence (); ! 578: ! 579: if (binoptab->code != UNKNOWN) ! 580: equiv_value ! 581: = gen_rtx (binoptab->code, mode, copy_rtx (op0), copy_rtx (op1)); ! 582: else ! 583: equiv_value = 0; ! 584: ! 585: emit_no_conflict_block (insns, target, op0, op1, equiv_value); ! 586: return target; ! 587: } ! 588: ! 589: /* Synthesize double word shifts from single word shifts. */ ! 590: if ((binoptab == lshr_optab || binoptab == ashl_optab ! 591: || binoptab == ashr_optab) ! 592: && class == MODE_INT ! 593: && GET_CODE (op1) == CONST_INT ! 594: && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD ! 595: && binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing ! 596: && ashl_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing ! 597: && lshr_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing) ! 598: { ! 599: rtx insns, equiv_value; ! 600: rtx into_target, outof_target; ! 601: rtx into_input, outof_input; ! 602: int shift_count, left_shift, outof_word; ! 603: ! 604: /* If TARGET is the same as one of the operands, the REG_EQUAL note ! 605: won't be accurate, so use a new target. */ ! 606: if (target == 0 || target == op0 || target == op1) ! 607: target = gen_reg_rtx (mode); ! 608: ! 609: start_sequence (); ! 610: ! 611: shift_count = INTVAL (op1); ! 612: ! 613: /* OUTOF_* is the word we are shifting bits away from, and ! 614: INTO_* is the word that we are shifting bits towards, thus ! 615: they differ depending on the direction of the shift and ! 616: WORDS_BIG_ENDIAN. */ ! 617: ! 618: left_shift = binoptab == ashl_optab; ! 619: outof_word = left_shift ^ ! WORDS_BIG_ENDIAN; ! 620: ! 621: outof_target = operand_subword (target, outof_word, 1, mode); ! 622: into_target = operand_subword (target, 1 - outof_word, 1, mode); ! 623: ! 624: outof_input = operand_subword_force (op0, outof_word, mode); ! 625: into_input = operand_subword_force (op0, 1 - outof_word, mode); ! 626: ! 627: if (shift_count >= BITS_PER_WORD) ! 628: { ! 629: emit_move_insn (into_target, ! 630: expand_binop (word_mode, binoptab, ! 631: outof_input, ! 632: GEN_INT (shift_count - BITS_PER_WORD), ! 633: into_target, unsignedp, methods)); ! 634: ! 635: /* For a signed right shift, we must fill the word we are shifting ! 636: out of with copies of the sign bit. Otherwise it is zeroed. */ ! 637: if (binoptab != ashr_optab) ! 638: emit_move_insn (outof_target, CONST0_RTX (word_mode)); ! 639: else ! 640: emit_move_insn (outof_target, ! 641: expand_binop (word_mode, binoptab, ! 642: outof_input, ! 643: GEN_INT (BITS_PER_WORD - 1), ! 644: outof_target, unsignedp, methods)); ! 645: } ! 646: else ! 647: { ! 648: rtx carries, into_temp; ! 649: optab reverse_unsigned_shift, unsigned_shift; ! 650: ! 651: /* For a shift of less then BITS_PER_WORD, to compute the carry, ! 652: we must do a logical shift in the opposite direction of the ! 653: desired shift. */ ! 654: ! 655: reverse_unsigned_shift = (left_shift ? lshr_optab : ashl_optab); ! 656: ! 657: /* For a shift of less than BITS_PER_WORD, to compute the word ! 658: shifted towards, we need to unsigned shift the orig value of ! 659: that word. */ ! 660: ! 661: unsigned_shift = (left_shift ? ashl_optab : lshr_optab); ! 662: ! 663: carries = expand_binop (word_mode, reverse_unsigned_shift, ! 664: outof_input, ! 665: GEN_INT (BITS_PER_WORD - shift_count), ! 666: 0, unsignedp, methods); ! 667: ! 668: emit_move_insn (outof_target, ! 669: expand_binop (word_mode, binoptab, ! 670: outof_input, ! 671: op1, outof_target, unsignedp, methods)); ! 672: into_temp = expand_binop (word_mode, unsigned_shift, ! 673: into_input, ! 674: op1, 0, unsignedp, methods); ! 675: ! 676: emit_move_insn (into_target, ! 677: expand_binop (word_mode, ior_optab, ! 678: carries, into_temp, ! 679: into_target, unsignedp, methods)); ! 680: } ! 681: ! 682: insns = get_insns (); ! 683: end_sequence (); ! 684: ! 685: if (binoptab->code != UNKNOWN) ! 686: equiv_value = gen_rtx (binoptab->code, mode, op0, op1); ! 687: else ! 688: equiv_value = 0; ! 689: ! 690: emit_no_conflict_block (insns, target, op0, op1, equiv_value); ! 691: return target; ! 692: } ! 693: ! 694: /* Synthesize double word rotates from single word shifts. */ ! 695: if ((binoptab == rotl_optab || binoptab == rotr_optab) ! 696: && class == MODE_INT ! 697: && GET_CODE (op1) == CONST_INT ! 698: && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD ! 699: && ashl_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing ! 700: && lshr_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing) ! 701: { ! 702: rtx insns, equiv_value; ! 703: rtx into_target, outof_target; ! 704: rtx into_input, outof_input; ! 705: int shift_count, left_shift, outof_word; ! 706: ! 707: /* If TARGET is the same as one of the operands, the REG_EQUAL note ! 708: won't be accurate, so use a new target. */ ! 709: if (target == 0 || target == op0 || target == op1) ! 710: target = gen_reg_rtx (mode); ! 711: ! 712: start_sequence (); ! 713: ! 714: shift_count = INTVAL (op1); ! 715: ! 716: /* OUTOF_* is the word we are shifting bits away from, and ! 717: INTO_* is the word that we are shifting bits towards, thus ! 718: they differ depending on the direction of the shift and ! 719: WORDS_BIG_ENDIAN. */ ! 720: ! 721: left_shift = (binoptab == rotl_optab); ! 722: outof_word = left_shift ^ ! WORDS_BIG_ENDIAN; ! 723: ! 724: outof_target = operand_subword (target, outof_word, 1, mode); ! 725: into_target = operand_subword (target, 1 - outof_word, 1, mode); ! 726: ! 727: outof_input = operand_subword_force (op0, outof_word, mode); ! 728: into_input = operand_subword_force (op0, 1 - outof_word, mode); ! 729: ! 730: if (shift_count == BITS_PER_WORD) ! 731: { ! 732: /* This is just a word swap. */ ! 733: emit_move_insn (outof_target, into_input); ! 734: emit_move_insn (into_target, outof_input); ! 735: } ! 736: else ! 737: { ! 738: rtx into_temp1, into_temp2, outof_temp1, outof_temp2; ! 739: rtx first_shift_count, second_shift_count; ! 740: optab reverse_unsigned_shift, unsigned_shift; ! 741: ! 742: reverse_unsigned_shift = (left_shift ^ (shift_count < BITS_PER_WORD) ! 743: ? lshr_optab : ashl_optab); ! 744: ! 745: unsigned_shift = (left_shift ^ (shift_count < BITS_PER_WORD) ! 746: ? ashl_optab : lshr_optab); ! 747: ! 748: if (shift_count > BITS_PER_WORD) ! 749: { ! 750: first_shift_count = GEN_INT (shift_count - BITS_PER_WORD); ! 751: second_shift_count = GEN_INT (2*BITS_PER_WORD - shift_count); ! 752: } ! 753: else ! 754: { ! 755: first_shift_count = GEN_INT (BITS_PER_WORD - shift_count); ! 756: second_shift_count = GEN_INT (shift_count); ! 757: } ! 758: ! 759: into_temp1 = expand_binop (word_mode, unsigned_shift, ! 760: outof_input, first_shift_count, ! 761: 0, unsignedp, methods); ! 762: into_temp2 = expand_binop (word_mode, reverse_unsigned_shift, ! 763: into_input, second_shift_count, ! 764: into_target, unsignedp, methods); ! 765: emit_move_insn (into_target, ! 766: expand_binop (word_mode, ior_optab, ! 767: into_temp1, into_temp2, ! 768: into_target, unsignedp, methods)); ! 769: ! 770: outof_temp1 = expand_binop (word_mode, unsigned_shift, ! 771: into_input, first_shift_count, ! 772: 0, unsignedp, methods); ! 773: outof_temp2 = expand_binop (word_mode, reverse_unsigned_shift, ! 774: outof_input, second_shift_count, ! 775: outof_target, unsignedp, methods); ! 776: emit_move_insn (outof_target, ! 777: expand_binop (word_mode, ior_optab, ! 778: outof_temp1, outof_temp2, ! 779: outof_target, unsignedp, methods)); ! 780: } ! 781: ! 782: insns = get_insns (); ! 783: end_sequence (); ! 784: ! 785: if (binoptab->code != UNKNOWN) ! 786: equiv_value = gen_rtx (binoptab->code, mode, op0, op1); ! 787: else ! 788: equiv_value = 0; ! 789: ! 790: /* We can't make this a no conflict block if this is a word swap, ! 791: because the word swap case fails if the input and output values ! 792: are in the same register. */ ! 793: if (shift_count != BITS_PER_WORD) ! 794: emit_no_conflict_block (insns, target, op0, op1, equiv_value); ! 795: else ! 796: emit_insns (insns); ! 797: return target; ! 798: } ! 799: ! 800: /* These can be done a word at a time by propagating carries. */ ! 801: if ((binoptab == add_optab || binoptab == sub_optab) ! 802: && class == MODE_INT ! 803: && GET_MODE_SIZE (mode) >= 2 * UNITS_PER_WORD ! 804: && binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing) ! 805: { ! 806: int i; ! 807: rtx carry_tmp = gen_reg_rtx (word_mode); ! 808: optab otheroptab = binoptab == add_optab ? sub_optab : add_optab; ! 809: int nwords = GET_MODE_BITSIZE (mode) / BITS_PER_WORD; ! 810: rtx carry_in, carry_out; ! 811: rtx xop0, xop1; ! 812: ! 813: /* We can handle either a 1 or -1 value for the carry. If STORE_FLAG ! 814: value is one of those, use it. Otherwise, use 1 since it is the ! 815: one easiest to get. */ ! 816: #if STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1 ! 817: int normalizep = STORE_FLAG_VALUE; ! 818: #else ! 819: int normalizep = 1; ! 820: #endif ! 821: ! 822: /* Prepare the operands. */ ! 823: xop0 = force_reg (mode, op0); ! 824: xop1 = force_reg (mode, op1); ! 825: ! 826: if (target == 0 || GET_CODE (target) != REG ! 827: || target == xop0 || target == xop1) ! 828: target = gen_reg_rtx (mode); ! 829: ! 830: /* Indicate for flow that the entire target reg is being set. */ ! 831: if (GET_CODE (target) == REG) ! 832: emit_insn (gen_rtx (CLOBBER, VOIDmode, target)); ! 833: ! 834: /* Do the actual arithmetic. */ ! 835: for (i = 0; i < nwords; i++) ! 836: { ! 837: int index = (WORDS_BIG_ENDIAN ? nwords - i - 1 : i); ! 838: rtx target_piece = operand_subword (target, index, 1, mode); ! 839: rtx op0_piece = operand_subword_force (xop0, index, mode); ! 840: rtx op1_piece = operand_subword_force (xop1, index, mode); ! 841: rtx x; ! 842: ! 843: /* Main add/subtract of the input operands. */ ! 844: x = expand_binop (word_mode, binoptab, ! 845: op0_piece, op1_piece, ! 846: target_piece, unsignedp, methods); ! 847: if (x == 0) ! 848: break; ! 849: ! 850: if (i + 1 < nwords) ! 851: { ! 852: /* Store carry from main add/subtract. */ ! 853: carry_out = gen_reg_rtx (word_mode); ! 854: carry_out = emit_store_flag (carry_out, ! 855: binoptab == add_optab ? LTU : GTU, ! 856: x, op0_piece, ! 857: word_mode, 1, normalizep); ! 858: if (!carry_out) ! 859: break; ! 860: } ! 861: ! 862: if (i > 0) ! 863: { ! 864: /* Add/subtract previous carry to main result. */ ! 865: x = expand_binop (word_mode, ! 866: normalizep == 1 ? binoptab : otheroptab, ! 867: x, carry_in, ! 868: target_piece, 1, methods); ! 869: if (target_piece != x) ! 870: emit_move_insn (target_piece, x); ! 871: ! 872: if (i + 1 < nwords) ! 873: { ! 874: /* THIS CODE HAS NOT BEEN TESTED. */ ! 875: /* Get out carry from adding/subtracting carry in. */ ! 876: carry_tmp = emit_store_flag (carry_tmp, ! 877: binoptab == add_optab ! 878: ? LTU : GTU, ! 879: x, carry_in, ! 880: word_mode, 1, normalizep); ! 881: /* Logical-ior the two poss. carry together. */ ! 882: carry_out = expand_binop (word_mode, ior_optab, ! 883: carry_out, carry_tmp, ! 884: carry_out, 0, methods); ! 885: if (!carry_out) ! 886: break; ! 887: } ! 888: } ! 889: ! 890: carry_in = carry_out; ! 891: } ! 892: ! 893: if (i == GET_MODE_BITSIZE (mode) / BITS_PER_WORD) ! 894: { ! 895: rtx temp; ! 896: ! 897: temp = emit_move_insn (target, target); ! 898: REG_NOTES (temp) = gen_rtx (EXPR_LIST, REG_EQUAL, ! 899: gen_rtx (binoptab->code, mode, ! 900: copy_rtx (xop0), ! 901: copy_rtx (xop1)), ! 902: REG_NOTES (temp)); ! 903: return target; ! 904: } ! 905: else ! 906: delete_insns_since (last); ! 907: } ! 908: ! 909: /* If we want to multiply two two-word values and have normal and widening ! 910: multiplies of single-word values, we can do this with three smaller ! 911: multiplications. Note that we do not make a REG_NO_CONFLICT block here ! 912: because we are not operating on one word at a time. ! 913: ! 914: The multiplication proceeds as follows: ! 915: _______________________ ! 916: [__op0_high_|__op0_low__] ! 917: _______________________ ! 918: * [__op1_high_|__op1_low__] ! 919: _______________________________________________ ! 920: _______________________ ! 921: (1) [__op0_low__*__op1_low__] ! 922: _______________________ ! 923: (2a) [__op0_low__*__op1_high_] ! 924: _______________________ ! 925: (2b) [__op0_high_*__op1_low__] ! 926: _______________________ ! 927: (3) [__op0_high_*__op1_high_] ! 928: ! 929: ! 930: This gives a 4-word result. Since we are only interested in the ! 931: lower 2 words, partial result (3) and the upper words of (2a) and ! 932: (2b) don't need to be calculated. Hence (2a) and (2b) can be ! 933: calculated using non-widening multiplication. ! 934: ! 935: (1), however, needs to be calculated with an unsigned widening ! 936: multiplication. If this operation is not directly supported we ! 937: try using a signed widening multiplication and adjust the result. ! 938: This adjustment works as follows: ! 939: ! 940: If both operands are positive then no adjustment is needed. ! 941: ! 942: If the operands have different signs, for example op0_low < 0 and ! 943: op1_low >= 0, the instruction treats the most significant bit of ! 944: op0_low as a sign bit instead of a bit with significance ! 945: 2**(BITS_PER_WORD-1), i.e. the instruction multiplies op1_low ! 946: with 2**BITS_PER_WORD - op0_low, and two's complements the ! 947: result. Conclusion: We need to add op1_low * 2**BITS_PER_WORD to ! 948: the result. ! 949: ! 950: Similarly, if both operands are negative, we need to add ! 951: (op0_low + op1_low) * 2**BITS_PER_WORD. ! 952: ! 953: We use a trick to adjust quickly. We logically shift op0_low right ! 954: (op1_low) BITS_PER_WORD-1 steps to get 0 or 1, and add this to ! 955: op0_high (op1_high) before it is used to calculate 2b (2a). If no ! 956: logical shift exists, we do an arithmetic right shift and subtract ! 957: the 0 or -1. */ ! 958: ! 959: if (binoptab == smul_optab ! 960: && class == MODE_INT ! 961: && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD ! 962: && smul_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing ! 963: && add_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing ! 964: && ((umul_widen_optab->handlers[(int) mode].insn_code ! 965: != CODE_FOR_nothing) ! 966: || (smul_widen_optab->handlers[(int) mode].insn_code ! 967: != CODE_FOR_nothing))) ! 968: { ! 969: int low = (WORDS_BIG_ENDIAN ? 1 : 0); ! 970: int high = (WORDS_BIG_ENDIAN ? 0 : 1); ! 971: rtx op0_high = operand_subword_force (op0, high, mode); ! 972: rtx op0_low = operand_subword_force (op0, low, mode); ! 973: rtx op1_high = operand_subword_force (op1, high, mode); ! 974: rtx op1_low = operand_subword_force (op1, low, mode); ! 975: rtx product = 0; ! 976: rtx op0_xhigh; ! 977: rtx op1_xhigh; ! 978: ! 979: /* If the target is the same as one of the inputs, don't use it. This ! 980: prevents problems with the REG_EQUAL note. */ ! 981: if (target == op0 || target == op1) ! 982: target = 0; ! 983: ! 984: /* Multiply the two lower words to get a double-word product. ! 985: If unsigned widening multiplication is available, use that; ! 986: otherwise use the signed form and compensate. */ ! 987: ! 988: if (umul_widen_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) ! 989: { ! 990: product = expand_binop (mode, umul_widen_optab, op0_low, op1_low, ! 991: target, 1, OPTAB_DIRECT); ! 992: ! 993: /* If we didn't succeed, delete everything we did so far. */ ! 994: if (product == 0) ! 995: delete_insns_since (last); ! 996: else ! 997: op0_xhigh = op0_high, op1_xhigh = op1_high; ! 998: } ! 999: ! 1000: if (product == 0 ! 1001: && smul_widen_optab->handlers[(int) mode].insn_code ! 1002: != CODE_FOR_nothing) ! 1003: { ! 1004: rtx wordm1 = GEN_INT (BITS_PER_WORD - 1); ! 1005: product = expand_binop (mode, smul_widen_optab, op0_low, op1_low, ! 1006: target, 1, OPTAB_DIRECT); ! 1007: op0_xhigh = expand_binop (word_mode, lshr_optab, op0_low, wordm1, ! 1008: NULL_RTX, 1, OPTAB_DIRECT); ! 1009: if (op0_xhigh) ! 1010: op0_xhigh = expand_binop (word_mode, add_optab, op0_high, ! 1011: op0_xhigh, op0_xhigh, 0, OPTAB_DIRECT); ! 1012: else ! 1013: { ! 1014: op0_xhigh = expand_binop (word_mode, ashr_optab, op0_low, wordm1, ! 1015: NULL_RTX, 0, OPTAB_DIRECT); ! 1016: if (op0_xhigh) ! 1017: op0_xhigh = expand_binop (word_mode, sub_optab, op0_high, ! 1018: op0_xhigh, op0_xhigh, 0, ! 1019: OPTAB_DIRECT); ! 1020: } ! 1021: ! 1022: op1_xhigh = expand_binop (word_mode, lshr_optab, op1_low, wordm1, ! 1023: NULL_RTX, 1, OPTAB_DIRECT); ! 1024: if (op1_xhigh) ! 1025: op1_xhigh = expand_binop (word_mode, add_optab, op1_high, ! 1026: op1_xhigh, op1_xhigh, 0, OPTAB_DIRECT); ! 1027: else ! 1028: { ! 1029: op1_xhigh = expand_binop (word_mode, ashr_optab, op1_low, wordm1, ! 1030: NULL_RTX, 0, OPTAB_DIRECT); ! 1031: if (op1_xhigh) ! 1032: op1_xhigh = expand_binop (word_mode, sub_optab, op1_high, ! 1033: op1_xhigh, op1_xhigh, 0, ! 1034: OPTAB_DIRECT); ! 1035: } ! 1036: } ! 1037: ! 1038: /* If we have been able to directly compute the product of the ! 1039: low-order words of the operands and perform any required adjustments ! 1040: of the operands, we proceed by trying two more multiplications ! 1041: and then computing the appropriate sum. ! 1042: ! 1043: We have checked above that the required addition is provided. ! 1044: Full-word addition will normally always succeed, especially if ! 1045: it is provided at all, so we don't worry about its failure. The ! 1046: multiplication may well fail, however, so we do handle that. */ ! 1047: ! 1048: if (product && op0_xhigh && op1_xhigh) ! 1049: { ! 1050: rtx product_piece; ! 1051: rtx product_high = operand_subword (product, high, 1, mode); ! 1052: rtx temp = expand_binop (word_mode, binoptab, op0_low, op1_xhigh, ! 1053: NULL_RTX, 0, OPTAB_DIRECT); ! 1054: ! 1055: if (temp) ! 1056: { ! 1057: product_piece = expand_binop (word_mode, add_optab, temp, ! 1058: product_high, product_high, ! 1059: 0, OPTAB_LIB_WIDEN); ! 1060: if (product_piece != product_high) ! 1061: emit_move_insn (product_high, product_piece); ! 1062: ! 1063: temp = expand_binop (word_mode, binoptab, op1_low, op0_xhigh, ! 1064: NULL_RTX, 0, OPTAB_DIRECT); ! 1065: ! 1066: product_piece = expand_binop (word_mode, add_optab, temp, ! 1067: product_high, product_high, ! 1068: 0, OPTAB_LIB_WIDEN); ! 1069: if (product_piece != product_high) ! 1070: emit_move_insn (product_high, product_piece); ! 1071: ! 1072: temp = emit_move_insn (product, product); ! 1073: REG_NOTES (temp) = gen_rtx (EXPR_LIST, REG_EQUAL, ! 1074: gen_rtx (MULT, mode, copy_rtx (op0), ! 1075: copy_rtx (op1)), ! 1076: REG_NOTES (temp)); ! 1077: ! 1078: return product; ! 1079: } ! 1080: } ! 1081: ! 1082: /* If we get here, we couldn't do it for some reason even though we ! 1083: originally thought we could. Delete anything we've emitted in ! 1084: trying to do it. */ ! 1085: ! 1086: delete_insns_since (last); ! 1087: } ! 1088: ! 1089: /* We need to open-code the complex type operations: '+, -, * and /' */ ! 1090: ! 1091: /* At this point we allow operations between two similar complex ! 1092: numbers, and also if one of the operands is not a complex number ! 1093: but rather of MODE_FLOAT or MODE_INT. However, the caller ! 1094: must make sure that the MODE of the non-complex operand matches ! 1095: the SUBMODE of the complex operand. */ ! 1096: ! 1097: if (class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT) ! 1098: { ! 1099: rtx real0 = (rtx) 0; ! 1100: rtx imag0 = (rtx) 0; ! 1101: rtx real1 = (rtx) 0; ! 1102: rtx imag1 = (rtx) 0; ! 1103: rtx realr; ! 1104: rtx imagr; ! 1105: rtx res; ! 1106: rtx seq; ! 1107: rtx equiv_value; ! 1108: ! 1109: /* Find the correct mode for the real and imaginary parts */ ! 1110: enum machine_mode submode ! 1111: = mode_for_size (GET_MODE_UNIT_SIZE (mode) * BITS_PER_UNIT, ! 1112: class == MODE_COMPLEX_INT ? MODE_INT : MODE_FLOAT, ! 1113: 0); ! 1114: ! 1115: if (submode == BLKmode) ! 1116: abort (); ! 1117: ! 1118: if (! target) ! 1119: target = gen_reg_rtx (mode); ! 1120: ! 1121: start_sequence (); ! 1122: ! 1123: realr = gen_realpart (submode, target); ! 1124: imagr = gen_imagpart (submode, target); ! 1125: ! 1126: if (GET_MODE (op0) == mode) ! 1127: { ! 1128: real0 = gen_realpart (submode, op0); ! 1129: imag0 = gen_imagpart (submode, op0); ! 1130: } ! 1131: else ! 1132: real0 = op0; ! 1133: ! 1134: if (GET_MODE (op1) == mode) ! 1135: { ! 1136: real1 = gen_realpart (submode, op1); ! 1137: imag1 = gen_imagpart (submode, op1); ! 1138: } ! 1139: else ! 1140: real1 = op1; ! 1141: ! 1142: if (! real0 || ! real1 || ! (imag0 || imag1)) ! 1143: abort (); ! 1144: ! 1145: switch (binoptab->code) ! 1146: { ! 1147: case PLUS: ! 1148: /* (a+ib) + (c+id) = (a+c) + i(b+d) */ ! 1149: case MINUS: ! 1150: /* (a+ib) - (c+id) = (a-c) + i(b-d) */ ! 1151: res = expand_binop (submode, binoptab, real0, real1, ! 1152: realr, unsignedp, methods); ! 1153: if (res != realr) ! 1154: emit_move_insn (realr, res); ! 1155: ! 1156: if (imag0 && imag1) ! 1157: res = expand_binop (submode, binoptab, imag0, imag1, ! 1158: imagr, unsignedp, methods); ! 1159: else if (imag0) ! 1160: res = imag0; ! 1161: else if (binoptab->code == MINUS) ! 1162: res = expand_unop (submode, neg_optab, imag1, imagr, unsignedp); ! 1163: else ! 1164: res = imag1; ! 1165: ! 1166: if (res != imagr) ! 1167: emit_move_insn (imagr, res); ! 1168: break; ! 1169: ! 1170: case MULT: ! 1171: /* (a+ib) * (c+id) = (ac-bd) + i(ad+cb) */ ! 1172: ! 1173: if (imag0 && imag1) ! 1174: { ! 1175: /* Don't fetch these from memory more than once. */ ! 1176: real0 = force_reg (submode, real0); ! 1177: real1 = force_reg (submode, real1); ! 1178: imag0 = force_reg (submode, imag0); ! 1179: imag1 = force_reg (submode, imag1); ! 1180: ! 1181: res = expand_binop (submode, sub_optab, ! 1182: expand_binop (submode, binoptab, real0, ! 1183: real1, 0, unsignedp, methods), ! 1184: expand_binop (submode, binoptab, imag0, ! 1185: imag1, 0, unsignedp, methods), ! 1186: realr, unsignedp, methods); ! 1187: ! 1188: if (res != realr) ! 1189: emit_move_insn (realr, res); ! 1190: ! 1191: res = expand_binop (submode, add_optab, ! 1192: expand_binop (submode, binoptab, ! 1193: real0, imag1, ! 1194: 0, unsignedp, methods), ! 1195: expand_binop (submode, binoptab, ! 1196: real1, imag0, ! 1197: 0, unsignedp, methods), ! 1198: imagr, unsignedp, methods); ! 1199: if (res != imagr) ! 1200: emit_move_insn (imagr, res); ! 1201: } ! 1202: else ! 1203: { ! 1204: /* Don't fetch these from memory more than once. */ ! 1205: real0 = force_reg (submode, real0); ! 1206: real1 = force_reg (submode, real1); ! 1207: ! 1208: res = expand_binop (submode, binoptab, real0, real1, ! 1209: realr, unsignedp, methods); ! 1210: if (res != realr) ! 1211: emit_move_insn (realr, res); ! 1212: ! 1213: if (imag0) ! 1214: res = expand_binop (submode, binoptab, ! 1215: real1, imag0, imagr, unsignedp, methods); ! 1216: else ! 1217: res = expand_binop (submode, binoptab, ! 1218: real0, imag1, imagr, unsignedp, methods); ! 1219: if (res != imagr) ! 1220: emit_move_insn (imagr, res); ! 1221: } ! 1222: break; ! 1223: ! 1224: case DIV: ! 1225: /* (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd)) */ ! 1226: ! 1227: if (! imag1) ! 1228: { /* (a+ib) / (c+i0) = (a/c) + i(b/c) */ ! 1229: ! 1230: /* Don't fetch these from memory more than once. */ ! 1231: real1 = force_reg (submode, real1); ! 1232: ! 1233: /* Simply divide the real and imaginary parts by `c' */ ! 1234: if (class == MODE_COMPLEX_FLOAT) ! 1235: res = expand_binop (submode, binoptab, real0, real1, ! 1236: realr, unsignedp, methods); ! 1237: else ! 1238: res = expand_divmod (0, TRUNC_DIV_EXPR, submode, ! 1239: real0, real1, realr, unsignedp); ! 1240: ! 1241: if (res != realr) ! 1242: emit_move_insn (realr, res); ! 1243: ! 1244: if (class == MODE_COMPLEX_FLOAT) ! 1245: res = expand_binop (submode, binoptab, imag0, real1, ! 1246: imagr, unsignedp, methods); ! 1247: else ! 1248: res = expand_divmod (0, TRUNC_DIV_EXPR, submode, ! 1249: imag0, real1, imagr, unsignedp); ! 1250: ! 1251: if (res != imagr) ! 1252: emit_move_insn (imagr, res); ! 1253: } ! 1254: else /* Divisor is of complex type */ ! 1255: { /* X/(a+ib) */ ! 1256: ! 1257: rtx divisor; ! 1258: rtx real_t; ! 1259: rtx imag_t; ! 1260: rtx lhs, rhs; ! 1261: ! 1262: /* Don't fetch these from memory more than once. */ ! 1263: real0 = force_reg (submode, real0); ! 1264: real1 = force_reg (submode, real1); ! 1265: if (imag0) ! 1266: imag0 = force_reg (submode, imag0); ! 1267: imag1 = force_reg (submode, imag1); ! 1268: ! 1269: /* Divisor: c*c + d*d */ ! 1270: divisor = expand_binop (submode, add_optab, ! 1271: expand_binop (submode, smul_optab, ! 1272: real1, real1, ! 1273: 0, unsignedp, methods), ! 1274: expand_binop (submode, smul_optab, ! 1275: imag1, imag1, ! 1276: 0, unsignedp, methods), ! 1277: 0, unsignedp, methods); ! 1278: ! 1279: if (! imag0) /* ((a)(c-id))/divisor */ ! 1280: { /* (a+i0) / (c+id) = (ac/(cc+dd)) + i(-ad/(cc+dd)) */ ! 1281: /* Calculate the dividend */ ! 1282: real_t = expand_binop (submode, smul_optab, real0, real1, ! 1283: 0, unsignedp, methods); ! 1284: ! 1285: imag_t ! 1286: = expand_unop (submode, neg_optab, ! 1287: expand_binop (submode, smul_optab, real0, ! 1288: imag1, 0, unsignedp, methods), ! 1289: 0, unsignedp); ! 1290: } ! 1291: else /* ((a+ib)(c-id))/divider */ ! 1292: { ! 1293: /* Calculate the dividend */ ! 1294: real_t = expand_binop (submode, add_optab, ! 1295: expand_binop (submode, smul_optab, ! 1296: real0, real1, ! 1297: 0, unsignedp, methods), ! 1298: expand_binop (submode, smul_optab, ! 1299: imag0, imag1, ! 1300: 0, unsignedp, methods), ! 1301: 0, unsignedp, methods); ! 1302: ! 1303: imag_t = expand_binop (submode, sub_optab, ! 1304: expand_binop (submode, smul_optab, ! 1305: imag0, real1, ! 1306: 0, unsignedp, methods), ! 1307: expand_binop (submode, smul_optab, ! 1308: real0, imag1, ! 1309: 0, unsignedp, methods), ! 1310: 0, unsignedp, methods); ! 1311: ! 1312: } ! 1313: ! 1314: if (class == MODE_COMPLEX_FLOAT) ! 1315: res = expand_binop (submode, binoptab, real_t, divisor, ! 1316: realr, unsignedp, methods); ! 1317: else ! 1318: res = expand_divmod (0, TRUNC_DIV_EXPR, submode, ! 1319: real_t, divisor, realr, unsignedp); ! 1320: ! 1321: if (res != realr) ! 1322: emit_move_insn (realr, res); ! 1323: ! 1324: if (class == MODE_COMPLEX_FLOAT) ! 1325: res = expand_binop (submode, binoptab, imag_t, divisor, ! 1326: imagr, unsignedp, methods); ! 1327: else ! 1328: res = expand_divmod (0, TRUNC_DIV_EXPR, submode, ! 1329: imag_t, divisor, imagr, unsignedp); ! 1330: ! 1331: if (res != imagr) ! 1332: emit_move_insn (imagr, res); ! 1333: } ! 1334: break; ! 1335: ! 1336: default: ! 1337: abort (); ! 1338: } ! 1339: ! 1340: seq = get_insns (); ! 1341: end_sequence (); ! 1342: ! 1343: if (binoptab->code != UNKNOWN) ! 1344: equiv_value ! 1345: = gen_rtx (binoptab->code, mode, copy_rtx (op0), copy_rtx (op1)); ! 1346: else ! 1347: equiv_value = 0; ! 1348: ! 1349: emit_no_conflict_block (seq, target, op0, op1, equiv_value); ! 1350: ! 1351: return target; ! 1352: } ! 1353: ! 1354: /* It can't be open-coded in this mode. ! 1355: Use a library call if one is available and caller says that's ok. */ ! 1356: ! 1357: if (binoptab->handlers[(int) mode].libfunc ! 1358: && (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN)) ! 1359: { ! 1360: rtx insns; ! 1361: rtx funexp = binoptab->handlers[(int) mode].libfunc; ! 1362: rtx op1x = op1; ! 1363: enum machine_mode op1_mode = mode; ! 1364: rtx value; ! 1365: ! 1366: start_sequence (); ! 1367: ! 1368: if (shift_op) ! 1369: { ! 1370: op1_mode = word_mode; ! 1371: /* Specify unsigned here, ! 1372: since negative shift counts are meaningless. */ ! 1373: op1x = convert_to_mode (word_mode, op1, 1); ! 1374: } ! 1375: ! 1376: /* Pass 1 for NO_QUEUE so we don't lose any increments ! 1377: if the libcall is cse'd or moved. */ ! 1378: value = emit_library_call_value (binoptab->handlers[(int) mode].libfunc, ! 1379: NULL_RTX, 1, mode, 2, ! 1380: op0, mode, op1x, op1_mode); ! 1381: ! 1382: insns = get_insns (); ! 1383: end_sequence (); ! 1384: ! 1385: target = gen_reg_rtx (mode); ! 1386: emit_libcall_block (insns, target, value, ! 1387: gen_rtx (binoptab->code, mode, op0, op1)); ! 1388: ! 1389: return target; ! 1390: } ! 1391: ! 1392: delete_insns_since (last); ! 1393: ! 1394: /* It can't be done in this mode. Can we do it in a wider mode? */ ! 1395: ! 1396: if (! (methods == OPTAB_WIDEN || methods == OPTAB_LIB_WIDEN ! 1397: || methods == OPTAB_MUST_WIDEN)) ! 1398: { ! 1399: /* Caller says, don't even try. */ ! 1400: delete_insns_since (entry_last); ! 1401: return 0; ! 1402: } ! 1403: ! 1404: /* Compute the value of METHODS to pass to recursive calls. ! 1405: Don't allow widening to be tried recursively. */ ! 1406: ! 1407: methods = (methods == OPTAB_LIB_WIDEN ? OPTAB_LIB : OPTAB_DIRECT); ! 1408: ! 1409: /* Look for a wider mode of the same class for which it appears we can do ! 1410: the operation. */ ! 1411: ! 1412: if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT) ! 1413: { ! 1414: for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode; ! 1415: wider_mode = GET_MODE_WIDER_MODE (wider_mode)) ! 1416: { ! 1417: if ((binoptab->handlers[(int) wider_mode].insn_code ! 1418: != CODE_FOR_nothing) ! 1419: || (methods == OPTAB_LIB ! 1420: && binoptab->handlers[(int) wider_mode].libfunc)) ! 1421: { ! 1422: rtx xop0 = op0, xop1 = op1; ! 1423: int no_extend = 0; ! 1424: ! 1425: /* For certain integer operations, we need not actually extend ! 1426: the narrow operands, as long as we will truncate ! 1427: the results to the same narrowness. */ ! 1428: ! 1429: if ((binoptab == ior_optab || binoptab == and_optab ! 1430: || binoptab == xor_optab ! 1431: || binoptab == add_optab || binoptab == sub_optab ! 1432: || binoptab == smul_optab || binoptab == ashl_optab) ! 1433: && class == MODE_INT) ! 1434: no_extend = 1; ! 1435: ! 1436: xop0 = widen_operand (xop0, wider_mode, mode, ! 1437: unsignedp, no_extend); ! 1438: ! 1439: /* The second operand of a shift must always be extended. */ ! 1440: xop1 = widen_operand (xop1, wider_mode, mode, unsignedp, ! 1441: no_extend && binoptab != ashl_optab); ! 1442: ! 1443: temp = expand_binop (wider_mode, binoptab, xop0, xop1, NULL_RTX, ! 1444: unsignedp, methods); ! 1445: if (temp) ! 1446: { ! 1447: if (class != MODE_INT) ! 1448: { ! 1449: if (target == 0) ! 1450: target = gen_reg_rtx (mode); ! 1451: convert_move (target, temp, 0); ! 1452: return target; ! 1453: } ! 1454: else ! 1455: return gen_lowpart (mode, temp); ! 1456: } ! 1457: else ! 1458: delete_insns_since (last); ! 1459: } ! 1460: } ! 1461: } ! 1462: ! 1463: delete_insns_since (entry_last); ! 1464: return 0; ! 1465: } ! 1466: ! 1467: /* Expand a binary operator which has both signed and unsigned forms. ! 1468: UOPTAB is the optab for unsigned operations, and SOPTAB is for ! 1469: signed operations. ! 1470: ! 1471: If we widen unsigned operands, we may use a signed wider operation instead ! 1472: of an unsigned wider operation, since the result would be the same. */ ! 1473: ! 1474: rtx ! 1475: sign_expand_binop (mode, uoptab, soptab, op0, op1, target, unsignedp, methods) ! 1476: enum machine_mode mode; ! 1477: optab uoptab, soptab; ! 1478: rtx op0, op1, target; ! 1479: int unsignedp; ! 1480: enum optab_methods methods; ! 1481: { ! 1482: register rtx temp; ! 1483: optab direct_optab = unsignedp ? uoptab : soptab; ! 1484: struct optab wide_soptab; ! 1485: ! 1486: /* Do it without widening, if possible. */ ! 1487: temp = expand_binop (mode, direct_optab, op0, op1, target, ! 1488: unsignedp, OPTAB_DIRECT); ! 1489: if (temp || methods == OPTAB_DIRECT) ! 1490: return temp; ! 1491: ! 1492: /* Try widening to a signed int. Make a fake signed optab that ! 1493: hides any signed insn for direct use. */ ! 1494: wide_soptab = *soptab; ! 1495: wide_soptab.handlers[(int) mode].insn_code = CODE_FOR_nothing; ! 1496: wide_soptab.handlers[(int) mode].libfunc = 0; ! 1497: ! 1498: temp = expand_binop (mode, &wide_soptab, op0, op1, target, ! 1499: unsignedp, OPTAB_WIDEN); ! 1500: ! 1501: /* For unsigned operands, try widening to an unsigned int. */ ! 1502: if (temp == 0 && unsignedp) ! 1503: temp = expand_binop (mode, uoptab, op0, op1, target, ! 1504: unsignedp, OPTAB_WIDEN); ! 1505: if (temp || methods == OPTAB_WIDEN) ! 1506: return temp; ! 1507: ! 1508: /* Use the right width lib call if that exists. */ ! 1509: temp = expand_binop (mode, direct_optab, op0, op1, target, unsignedp, OPTAB_LIB); ! 1510: if (temp || methods == OPTAB_LIB) ! 1511: return temp; ! 1512: ! 1513: /* Must widen and use a lib call, use either signed or unsigned. */ ! 1514: temp = expand_binop (mode, &wide_soptab, op0, op1, target, ! 1515: unsignedp, methods); ! 1516: if (temp != 0) ! 1517: return temp; ! 1518: if (unsignedp) ! 1519: return expand_binop (mode, uoptab, op0, op1, target, ! 1520: unsignedp, methods); ! 1521: return 0; ! 1522: } ! 1523: ! 1524: /* Generate code to perform an operation specified by BINOPTAB ! 1525: on operands OP0 and OP1, with two results to TARG1 and TARG2. ! 1526: We assume that the order of the operands for the instruction ! 1527: is TARG0, OP0, OP1, TARG1, which would fit a pattern like ! 1528: [(set TARG0 (operate OP0 OP1)) (set TARG1 (operate ...))]. ! 1529: ! 1530: Either TARG0 or TARG1 may be zero, but what that means is that ! 1531: that result is not actually wanted. We will generate it into ! 1532: a dummy pseudo-reg and discard it. They may not both be zero. ! 1533: ! 1534: Returns 1 if this operation can be performed; 0 if not. */ ! 1535: ! 1536: int ! 1537: expand_twoval_binop (binoptab, op0, op1, targ0, targ1, unsignedp) ! 1538: optab binoptab; ! 1539: rtx op0, op1; ! 1540: rtx targ0, targ1; ! 1541: int unsignedp; ! 1542: { ! 1543: enum machine_mode mode = GET_MODE (targ0 ? targ0 : targ1); ! 1544: enum mode_class class; ! 1545: enum machine_mode wider_mode; ! 1546: rtx entry_last = get_last_insn (); ! 1547: rtx last; ! 1548: ! 1549: class = GET_MODE_CLASS (mode); ! 1550: ! 1551: op0 = protect_from_queue (op0, 0); ! 1552: op1 = protect_from_queue (op1, 0); ! 1553: ! 1554: if (flag_force_mem) ! 1555: { ! 1556: op0 = force_not_mem (op0); ! 1557: op1 = force_not_mem (op1); ! 1558: } ! 1559: ! 1560: /* If we are inside an appropriately-short loop and one operand is an ! 1561: expensive constant, force it into a register. */ ! 1562: if (CONSTANT_P (op0) && preserve_subexpressions_p () ! 1563: && rtx_cost (op0, binoptab->code) > 2) ! 1564: op0 = force_reg (mode, op0); ! 1565: ! 1566: if (CONSTANT_P (op1) && preserve_subexpressions_p () ! 1567: && rtx_cost (op1, binoptab->code) > 2) ! 1568: op1 = force_reg (mode, op1); ! 1569: ! 1570: if (targ0) ! 1571: targ0 = protect_from_queue (targ0, 1); ! 1572: else ! 1573: targ0 = gen_reg_rtx (mode); ! 1574: if (targ1) ! 1575: targ1 = protect_from_queue (targ1, 1); ! 1576: else ! 1577: targ1 = gen_reg_rtx (mode); ! 1578: ! 1579: /* Record where to go back to if we fail. */ ! 1580: last = get_last_insn (); ! 1581: ! 1582: if (binoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing) ! 1583: { ! 1584: int icode = (int) binoptab->handlers[(int) mode].insn_code; ! 1585: enum machine_mode mode0 = insn_operand_mode[icode][1]; ! 1586: enum machine_mode mode1 = insn_operand_mode[icode][2]; ! 1587: rtx pat; ! 1588: rtx xop0 = op0, xop1 = op1; ! 1589: ! 1590: /* In case this insn wants input operands in modes different from the ! 1591: result, convert the operands. */ ! 1592: if (GET_MODE (op0) != VOIDmode && GET_MODE (op0) != mode0) ! 1593: xop0 = convert_to_mode (mode0, xop0, unsignedp); ! 1594: ! 1595: if (GET_MODE (op1) != VOIDmode && GET_MODE (op1) != mode1) ! 1596: xop1 = convert_to_mode (mode1, xop1, unsignedp); ! 1597: ! 1598: /* Now, if insn doesn't accept these operands, put them into pseudos. */ ! 1599: if (! (*insn_operand_predicate[icode][1]) (xop0, mode0)) ! 1600: xop0 = copy_to_mode_reg (mode0, xop0); ! 1601: ! 1602: if (! (*insn_operand_predicate[icode][2]) (xop1, mode1)) ! 1603: xop1 = copy_to_mode_reg (mode1, xop1); ! 1604: ! 1605: /* We could handle this, but we should always be called with a pseudo ! 1606: for our targets and all insns should take them as outputs. */ ! 1607: if (! (*insn_operand_predicate[icode][0]) (targ0, mode) ! 1608: || ! (*insn_operand_predicate[icode][3]) (targ1, mode)) ! 1609: abort (); ! 1610: ! 1611: pat = GEN_FCN (icode) (targ0, xop0, xop1, targ1); ! 1612: if (pat) ! 1613: { ! 1614: emit_insn (pat); ! 1615: return 1; ! 1616: } ! 1617: else ! 1618: delete_insns_since (last); ! 1619: } ! 1620: ! 1621: /* It can't be done in this mode. Can we do it in a wider mode? */ ! 1622: ! 1623: if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT) ! 1624: { ! 1625: for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode; ! 1626: wider_mode = GET_MODE_WIDER_MODE (wider_mode)) ! 1627: { ! 1628: if (binoptab->handlers[(int) wider_mode].insn_code ! 1629: != CODE_FOR_nothing) ! 1630: { ! 1631: register rtx t0 = gen_reg_rtx (wider_mode); ! 1632: register rtx t1 = gen_reg_rtx (wider_mode); ! 1633: ! 1634: if (expand_twoval_binop (binoptab, ! 1635: convert_modes (wider_mode, mode, op0, ! 1636: unsignedp), ! 1637: convert_modes (wider_mode, mode, op1, ! 1638: unsignedp), ! 1639: t0, t1, unsignedp)) ! 1640: { ! 1641: convert_move (targ0, t0, unsignedp); ! 1642: convert_move (targ1, t1, unsignedp); ! 1643: return 1; ! 1644: } ! 1645: else ! 1646: delete_insns_since (last); ! 1647: } ! 1648: } ! 1649: } ! 1650: ! 1651: delete_insns_since (entry_last); ! 1652: return 0; ! 1653: } ! 1654: ! 1655: /* Generate code to perform an operation specified by UNOPTAB ! 1656: on operand OP0, with result having machine-mode MODE. ! 1657: ! 1658: UNSIGNEDP is for the case where we have to widen the operands ! 1659: to perform the operation. It says to use zero-extension. ! 1660: ! 1661: If TARGET is nonzero, the value ! 1662: is generated there, if it is convenient to do so. ! 1663: In all cases an rtx is returned for the locus of the value; ! 1664: this may or may not be TARGET. */ ! 1665: ! 1666: rtx ! 1667: expand_unop (mode, unoptab, op0, target, unsignedp) ! 1668: enum machine_mode mode; ! 1669: optab unoptab; ! 1670: rtx op0; ! 1671: rtx target; ! 1672: int unsignedp; ! 1673: { ! 1674: enum mode_class class; ! 1675: enum machine_mode wider_mode; ! 1676: register rtx temp; ! 1677: rtx last = get_last_insn (); ! 1678: rtx pat; ! 1679: ! 1680: class = GET_MODE_CLASS (mode); ! 1681: ! 1682: op0 = protect_from_queue (op0, 0); ! 1683: ! 1684: if (flag_force_mem) ! 1685: { ! 1686: op0 = force_not_mem (op0); ! 1687: } ! 1688: ! 1689: if (target) ! 1690: target = protect_from_queue (target, 1); ! 1691: ! 1692: if (unoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing) ! 1693: { ! 1694: int icode = (int) unoptab->handlers[(int) mode].insn_code; ! 1695: enum machine_mode mode0 = insn_operand_mode[icode][1]; ! 1696: rtx xop0 = op0; ! 1697: ! 1698: if (target) ! 1699: temp = target; ! 1700: else ! 1701: temp = gen_reg_rtx (mode); ! 1702: ! 1703: if (GET_MODE (xop0) != VOIDmode ! 1704: && GET_MODE (xop0) != mode0) ! 1705: xop0 = convert_to_mode (mode0, xop0, unsignedp); ! 1706: ! 1707: /* Now, if insn doesn't accept our operand, put it into a pseudo. */ ! 1708: ! 1709: if (! (*insn_operand_predicate[icode][1]) (xop0, mode0)) ! 1710: xop0 = copy_to_mode_reg (mode0, xop0); ! 1711: ! 1712: if (! (*insn_operand_predicate[icode][0]) (temp, mode)) ! 1713: temp = gen_reg_rtx (mode); ! 1714: ! 1715: pat = GEN_FCN (icode) (temp, xop0); ! 1716: if (pat) ! 1717: { ! 1718: if (GET_CODE (pat) == SEQUENCE ! 1719: && ! add_equal_note (pat, temp, unoptab->code, xop0, NULL_RTX)) ! 1720: { ! 1721: delete_insns_since (last); ! 1722: return expand_unop (mode, unoptab, op0, NULL_RTX, unsignedp); ! 1723: } ! 1724: ! 1725: emit_insn (pat); ! 1726: ! 1727: return temp; ! 1728: } ! 1729: else ! 1730: delete_insns_since (last); ! 1731: } ! 1732: ! 1733: /* It can't be done in this mode. Can we open-code it in a wider mode? */ ! 1734: ! 1735: if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT) ! 1736: for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode; ! 1737: wider_mode = GET_MODE_WIDER_MODE (wider_mode)) ! 1738: { ! 1739: if (unoptab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing) ! 1740: { ! 1741: rtx xop0 = op0; ! 1742: ! 1743: /* For certain operations, we need not actually extend ! 1744: the narrow operand, as long as we will truncate the ! 1745: results to the same narrowness. */ ! 1746: ! 1747: xop0 = widen_operand (xop0, wider_mode, mode, unsignedp, ! 1748: (unoptab == neg_optab ! 1749: || unoptab == one_cmpl_optab) ! 1750: && class == MODE_INT); ! 1751: ! 1752: temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX, ! 1753: unsignedp); ! 1754: ! 1755: if (temp) ! 1756: { ! 1757: if (class != MODE_INT) ! 1758: { ! 1759: if (target == 0) ! 1760: target = gen_reg_rtx (mode); ! 1761: convert_move (target, temp, 0); ! 1762: return target; ! 1763: } ! 1764: else ! 1765: return gen_lowpart (mode, temp); ! 1766: } ! 1767: else ! 1768: delete_insns_since (last); ! 1769: } ! 1770: } ! 1771: ! 1772: /* These can be done a word at a time. */ ! 1773: if (unoptab == one_cmpl_optab ! 1774: && class == MODE_INT ! 1775: && GET_MODE_SIZE (mode) > UNITS_PER_WORD ! 1776: && unoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing) ! 1777: { ! 1778: int i; ! 1779: rtx insns; ! 1780: ! 1781: if (target == 0 || target == op0) ! 1782: target = gen_reg_rtx (mode); ! 1783: ! 1784: start_sequence (); ! 1785: ! 1786: /* Do the actual arithmetic. */ ! 1787: for (i = 0; i < GET_MODE_BITSIZE (mode) / BITS_PER_WORD; i++) ! 1788: { ! 1789: rtx target_piece = operand_subword (target, i, 1, mode); ! 1790: rtx x = expand_unop (word_mode, unoptab, ! 1791: operand_subword_force (op0, i, mode), ! 1792: target_piece, unsignedp); ! 1793: if (target_piece != x) ! 1794: emit_move_insn (target_piece, x); ! 1795: } ! 1796: ! 1797: insns = get_insns (); ! 1798: end_sequence (); ! 1799: ! 1800: emit_no_conflict_block (insns, target, op0, NULL_RTX, ! 1801: gen_rtx (unoptab->code, mode, copy_rtx (op0))); ! 1802: return target; ! 1803: } ! 1804: ! 1805: /* Open-code the complex negation operation. */ ! 1806: else if (unoptab == neg_optab ! 1807: && (class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT)) ! 1808: { ! 1809: rtx target_piece; ! 1810: rtx x; ! 1811: rtx seq; ! 1812: ! 1813: /* Find the correct mode for the real and imaginary parts */ ! 1814: enum machine_mode submode ! 1815: = mode_for_size (GET_MODE_UNIT_SIZE (mode) * BITS_PER_UNIT, ! 1816: class == MODE_COMPLEX_INT ? MODE_INT : MODE_FLOAT, ! 1817: 0); ! 1818: ! 1819: if (submode == BLKmode) ! 1820: abort (); ! 1821: ! 1822: if (target == 0) ! 1823: target = gen_reg_rtx (mode); ! 1824: ! 1825: start_sequence (); ! 1826: ! 1827: target_piece = gen_imagpart (submode, target); ! 1828: x = expand_unop (submode, unoptab, ! 1829: gen_imagpart (submode, op0), ! 1830: target_piece, unsignedp); ! 1831: if (target_piece != x) ! 1832: emit_move_insn (target_piece, x); ! 1833: ! 1834: target_piece = gen_realpart (submode, target); ! 1835: x = expand_unop (submode, unoptab, ! 1836: gen_realpart (submode, op0), ! 1837: target_piece, unsignedp); ! 1838: if (target_piece != x) ! 1839: emit_move_insn (target_piece, x); ! 1840: ! 1841: seq = get_insns (); ! 1842: end_sequence (); ! 1843: ! 1844: emit_no_conflict_block (seq, target, op0, 0, ! 1845: gen_rtx (unoptab->code, mode, copy_rtx (op0))); ! 1846: return target; ! 1847: } ! 1848: ! 1849: /* Now try a library call in this mode. */ ! 1850: if (unoptab->handlers[(int) mode].libfunc) ! 1851: { ! 1852: rtx insns; ! 1853: rtx funexp = unoptab->handlers[(int) mode].libfunc; ! 1854: rtx value; ! 1855: ! 1856: start_sequence (); ! 1857: ! 1858: /* Pass 1 for NO_QUEUE so we don't lose any increments ! 1859: if the libcall is cse'd or moved. */ ! 1860: value = emit_library_call_value (unoptab->handlers[(int) mode].libfunc, ! 1861: NULL_RTX, 1, mode, 1, op0, mode); ! 1862: insns = get_insns (); ! 1863: end_sequence (); ! 1864: ! 1865: target = gen_reg_rtx (mode); ! 1866: emit_libcall_block (insns, target, value, ! 1867: gen_rtx (unoptab->code, mode, op0)); ! 1868: ! 1869: return target; ! 1870: } ! 1871: ! 1872: /* It can't be done in this mode. Can we do it in a wider mode? */ ! 1873: ! 1874: if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT) ! 1875: { ! 1876: for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode; ! 1877: wider_mode = GET_MODE_WIDER_MODE (wider_mode)) ! 1878: { ! 1879: if ((unoptab->handlers[(int) wider_mode].insn_code ! 1880: != CODE_FOR_nothing) ! 1881: || unoptab->handlers[(int) wider_mode].libfunc) ! 1882: { ! 1883: rtx xop0 = op0; ! 1884: ! 1885: /* For certain operations, we need not actually extend ! 1886: the narrow operand, as long as we will truncate the ! 1887: results to the same narrowness. */ ! 1888: ! 1889: xop0 = widen_operand (xop0, wider_mode, mode, unsignedp, ! 1890: (unoptab == neg_optab ! 1891: || unoptab == one_cmpl_optab) ! 1892: && class == MODE_INT); ! 1893: ! 1894: temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX, ! 1895: unsignedp); ! 1896: ! 1897: if (temp) ! 1898: { ! 1899: if (class != MODE_INT) ! 1900: { ! 1901: if (target == 0) ! 1902: target = gen_reg_rtx (mode); ! 1903: convert_move (target, temp, 0); ! 1904: return target; ! 1905: } ! 1906: else ! 1907: return gen_lowpart (mode, temp); ! 1908: } ! 1909: else ! 1910: delete_insns_since (last); ! 1911: } ! 1912: } ! 1913: } ! 1914: ! 1915: return 0; ! 1916: } ! 1917: ! 1918: /* Emit code to compute the absolute value of OP0, with result to ! 1919: TARGET if convenient. (TARGET may be 0.) The return value says ! 1920: where the result actually is to be found. ! 1921: ! 1922: MODE is the mode of the operand; the mode of the result is ! 1923: different but can be deduced from MODE. ! 1924: ! 1925: UNSIGNEDP is relevant for complex integer modes. */ ! 1926: ! 1927: rtx ! 1928: expand_complex_abs (mode, op0, target, unsignedp) ! 1929: enum machine_mode mode; ! 1930: rtx op0; ! 1931: rtx target; ! 1932: int unsignedp; ! 1933: { ! 1934: enum mode_class class = GET_MODE_CLASS (mode); ! 1935: enum machine_mode wider_mode; ! 1936: register rtx temp; ! 1937: rtx entry_last = get_last_insn (); ! 1938: rtx last; ! 1939: rtx pat; ! 1940: ! 1941: /* Find the correct mode for the real and imaginary parts. */ ! 1942: enum machine_mode submode ! 1943: = mode_for_size (GET_MODE_UNIT_SIZE (mode) * BITS_PER_UNIT, ! 1944: class == MODE_COMPLEX_INT ? MODE_INT : MODE_FLOAT, ! 1945: 0); ! 1946: ! 1947: if (submode == BLKmode) ! 1948: abort (); ! 1949: ! 1950: op0 = protect_from_queue (op0, 0); ! 1951: ! 1952: if (flag_force_mem) ! 1953: { ! 1954: op0 = force_not_mem (op0); ! 1955: } ! 1956: ! 1957: last = get_last_insn (); ! 1958: ! 1959: if (target) ! 1960: target = protect_from_queue (target, 1); ! 1961: ! 1962: if (abs_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) ! 1963: { ! 1964: int icode = (int) abs_optab->handlers[(int) mode].insn_code; ! 1965: enum machine_mode mode0 = insn_operand_mode[icode][1]; ! 1966: rtx xop0 = op0; ! 1967: ! 1968: if (target) ! 1969: temp = target; ! 1970: else ! 1971: temp = gen_reg_rtx (submode); ! 1972: ! 1973: if (GET_MODE (xop0) != VOIDmode ! 1974: && GET_MODE (xop0) != mode0) ! 1975: xop0 = convert_to_mode (mode0, xop0, unsignedp); ! 1976: ! 1977: /* Now, if insn doesn't accept our operand, put it into a pseudo. */ ! 1978: ! 1979: if (! (*insn_operand_predicate[icode][1]) (xop0, mode0)) ! 1980: xop0 = copy_to_mode_reg (mode0, xop0); ! 1981: ! 1982: if (! (*insn_operand_predicate[icode][0]) (temp, submode)) ! 1983: temp = gen_reg_rtx (submode); ! 1984: ! 1985: pat = GEN_FCN (icode) (temp, xop0); ! 1986: if (pat) ! 1987: { ! 1988: if (GET_CODE (pat) == SEQUENCE ! 1989: && ! add_equal_note (pat, temp, abs_optab->code, xop0, NULL_RTX)) ! 1990: { ! 1991: delete_insns_since (last); ! 1992: return expand_unop (mode, abs_optab, op0, NULL_RTX, unsignedp); ! 1993: } ! 1994: ! 1995: emit_insn (pat); ! 1996: ! 1997: return temp; ! 1998: } ! 1999: else ! 2000: delete_insns_since (last); ! 2001: } ! 2002: ! 2003: /* It can't be done in this mode. Can we open-code it in a wider mode? */ ! 2004: ! 2005: for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode; ! 2006: wider_mode = GET_MODE_WIDER_MODE (wider_mode)) ! 2007: { ! 2008: if (abs_optab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing) ! 2009: { ! 2010: rtx xop0 = op0; ! 2011: ! 2012: xop0 = convert_modes (wider_mode, mode, xop0, unsignedp); ! 2013: temp = expand_complex_abs (wider_mode, xop0, NULL_RTX, unsignedp); ! 2014: ! 2015: if (temp) ! 2016: { ! 2017: if (class != MODE_COMPLEX_INT) ! 2018: { ! 2019: if (target == 0) ! 2020: target = gen_reg_rtx (submode); ! 2021: convert_move (target, temp, 0); ! 2022: return target; ! 2023: } ! 2024: else ! 2025: return gen_lowpart (submode, temp); ! 2026: } ! 2027: else ! 2028: delete_insns_since (last); ! 2029: } ! 2030: } ! 2031: ! 2032: /* Open-code the complex absolute-value operation ! 2033: if we can open-code sqrt. Otherwise it's not worth while. */ ! 2034: if (sqrt_optab->handlers[(int) submode].insn_code != CODE_FOR_nothing) ! 2035: { ! 2036: rtx real, imag, total; ! 2037: ! 2038: real = gen_realpart (submode, op0); ! 2039: imag = gen_imagpart (submode, op0); ! 2040: ! 2041: /* Square both parts. */ ! 2042: real = expand_mult (submode, real, real, NULL_RTX, 0); ! 2043: imag = expand_mult (submode, imag, imag, NULL_RTX, 0); ! 2044: ! 2045: /* Sum the parts. */ ! 2046: total = expand_binop (submode, add_optab, real, imag, 0, ! 2047: 0, OPTAB_LIB_WIDEN); ! 2048: ! 2049: /* Get sqrt in TARGET. Set TARGET to where the result is. */ ! 2050: target = expand_unop (submode, sqrt_optab, total, target, 0); ! 2051: if (target == 0) ! 2052: delete_insns_since (last); ! 2053: else ! 2054: return target; ! 2055: } ! 2056: ! 2057: /* Now try a library call in this mode. */ ! 2058: if (abs_optab->handlers[(int) mode].libfunc) ! 2059: { ! 2060: rtx insns; ! 2061: rtx funexp = abs_optab->handlers[(int) mode].libfunc; ! 2062: rtx value; ! 2063: ! 2064: start_sequence (); ! 2065: ! 2066: /* Pass 1 for NO_QUEUE so we don't lose any increments ! 2067: if the libcall is cse'd or moved. */ ! 2068: value = emit_library_call_value (abs_optab->handlers[(int) mode].libfunc, ! 2069: NULL_RTX, 1, submode, 1, op0, mode); ! 2070: insns = get_insns (); ! 2071: end_sequence (); ! 2072: ! 2073: target = gen_reg_rtx (submode); ! 2074: emit_libcall_block (insns, target, value, ! 2075: gen_rtx (abs_optab->code, mode, op0)); ! 2076: ! 2077: return target; ! 2078: } ! 2079: ! 2080: /* It can't be done in this mode. Can we do it in a wider mode? */ ! 2081: ! 2082: for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode; ! 2083: wider_mode = GET_MODE_WIDER_MODE (wider_mode)) ! 2084: { ! 2085: if ((abs_optab->handlers[(int) wider_mode].insn_code ! 2086: != CODE_FOR_nothing) ! 2087: || abs_optab->handlers[(int) wider_mode].libfunc) ! 2088: { ! 2089: rtx xop0 = op0; ! 2090: ! 2091: xop0 = convert_modes (wider_mode, mode, xop0, unsignedp); ! 2092: ! 2093: temp = expand_complex_abs (wider_mode, xop0, NULL_RTX, unsignedp); ! 2094: ! 2095: if (temp) ! 2096: { ! 2097: if (class != MODE_COMPLEX_INT) ! 2098: { ! 2099: if (target == 0) ! 2100: target = gen_reg_rtx (submode); ! 2101: convert_move (target, temp, 0); ! 2102: return target; ! 2103: } ! 2104: else ! 2105: return gen_lowpart (submode, temp); ! 2106: } ! 2107: else ! 2108: delete_insns_since (last); ! 2109: } ! 2110: } ! 2111: ! 2112: delete_insns_since (entry_last); ! 2113: return 0; ! 2114: } ! 2115: ! 2116: /* Generate an instruction whose insn-code is INSN_CODE, ! 2117: with two operands: an output TARGET and an input OP0. ! 2118: TARGET *must* be nonzero, and the output is always stored there. ! 2119: CODE is an rtx code such that (CODE OP0) is an rtx that describes ! 2120: the value that is stored into TARGET. */ ! 2121: ! 2122: void ! 2123: emit_unop_insn (icode, target, op0, code) ! 2124: int icode; ! 2125: rtx target; ! 2126: rtx op0; ! 2127: enum rtx_code code; ! 2128: { ! 2129: register rtx temp; ! 2130: enum machine_mode mode0 = insn_operand_mode[icode][1]; ! 2131: rtx pat; ! 2132: ! 2133: temp = target = protect_from_queue (target, 1); ! 2134: ! 2135: op0 = protect_from_queue (op0, 0); ! 2136: ! 2137: if (flag_force_mem) ! 2138: op0 = force_not_mem (op0); ! 2139: ! 2140: /* Now, if insn does not accept our operands, put them into pseudos. */ ! 2141: ! 2142: if (! (*insn_operand_predicate[icode][1]) (op0, mode0)) ! 2143: op0 = copy_to_mode_reg (mode0, op0); ! 2144: ! 2145: if (! (*insn_operand_predicate[icode][0]) (temp, GET_MODE (temp)) ! 2146: || (flag_force_mem && GET_CODE (temp) == MEM)) ! 2147: temp = gen_reg_rtx (GET_MODE (temp)); ! 2148: ! 2149: pat = GEN_FCN (icode) (temp, op0); ! 2150: ! 2151: if (GET_CODE (pat) == SEQUENCE && code != UNKNOWN) ! 2152: add_equal_note (pat, temp, code, op0, NULL_RTX); ! 2153: ! 2154: emit_insn (pat); ! 2155: ! 2156: if (temp != target) ! 2157: emit_move_insn (target, temp); ! 2158: } ! 2159: ! 2160: /* Emit code to perform a series of operations on a multi-word quantity, one ! 2161: word at a time. ! 2162: ! 2163: Such a block is preceded by a CLOBBER of the output, consists of multiple ! 2164: insns, each setting one word of the output, and followed by a SET copying ! 2165: the output to itself. ! 2166: ! 2167: Each of the insns setting words of the output receives a REG_NO_CONFLICT ! 2168: note indicating that it doesn't conflict with the (also multi-word) ! 2169: inputs. The entire block is surrounded by REG_LIBCALL and REG_RETVAL ! 2170: notes. ! 2171: ! 2172: INSNS is a block of code generated to perform the operation, not including ! 2173: the CLOBBER and final copy. All insns that compute intermediate values ! 2174: are first emitted, followed by the block as described above. Only ! 2175: INSNs are allowed in the block; no library calls or jumps may be ! 2176: present. ! 2177: ! 2178: TARGET, OP0, and OP1 are the output and inputs of the operations, ! 2179: respectively. OP1 may be zero for a unary operation. ! 2180: ! 2181: EQUIV, if non-zero, is an expression to be placed into a REG_EQUAL note ! 2182: on the last insn. ! 2183: ! 2184: If TARGET is not a register, INSNS is simply emitted with no special ! 2185: processing. ! 2186: ! 2187: The final insn emitted is returned. */ ! 2188: ! 2189: rtx ! 2190: emit_no_conflict_block (insns, target, op0, op1, equiv) ! 2191: rtx insns; ! 2192: rtx target; ! 2193: rtx op0, op1; ! 2194: rtx equiv; ! 2195: { ! 2196: rtx prev, next, first, last, insn; ! 2197: ! 2198: if (GET_CODE (target) != REG || reload_in_progress) ! 2199: return emit_insns (insns); ! 2200: ! 2201: /* First emit all insns that do not store into words of the output and remove ! 2202: these from the list. */ ! 2203: for (insn = insns; insn; insn = next) ! 2204: { ! 2205: rtx set = 0; ! 2206: int i; ! 2207: ! 2208: next = NEXT_INSN (insn); ! 2209: ! 2210: if (GET_CODE (insn) != INSN) ! 2211: abort (); ! 2212: ! 2213: if (GET_CODE (PATTERN (insn)) == SET) ! 2214: set = PATTERN (insn); ! 2215: else if (GET_CODE (PATTERN (insn)) == PARALLEL) ! 2216: { ! 2217: for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++) ! 2218: if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET) ! 2219: { ! 2220: set = XVECEXP (PATTERN (insn), 0, i); ! 2221: break; ! 2222: } ! 2223: } ! 2224: ! 2225: if (set == 0) ! 2226: abort (); ! 2227: ! 2228: if (! reg_overlap_mentioned_p (target, SET_DEST (set))) ! 2229: { ! 2230: if (PREV_INSN (insn)) ! 2231: NEXT_INSN (PREV_INSN (insn)) = next; ! 2232: else ! 2233: insns = next; ! 2234: ! 2235: if (next) ! 2236: PREV_INSN (next) = PREV_INSN (insn); ! 2237: ! 2238: add_insn (insn); ! 2239: } ! 2240: } ! 2241: ! 2242: prev = get_last_insn (); ! 2243: ! 2244: /* Now write the CLOBBER of the output, followed by the setting of each ! 2245: of the words, followed by the final copy. */ ! 2246: if (target != op0 && target != op1) ! 2247: emit_insn (gen_rtx (CLOBBER, VOIDmode, target)); ! 2248: ! 2249: for (insn = insns; insn; insn = next) ! 2250: { ! 2251: next = NEXT_INSN (insn); ! 2252: add_insn (insn); ! 2253: ! 2254: if (op1 && GET_CODE (op1) == REG) ! 2255: REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_NO_CONFLICT, op1, ! 2256: REG_NOTES (insn)); ! 2257: ! 2258: if (op0 && GET_CODE (op0) == REG) ! 2259: REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_NO_CONFLICT, op0, ! 2260: REG_NOTES (insn)); ! 2261: } ! 2262: ! 2263: if (mov_optab->handlers[(int) GET_MODE (target)].insn_code ! 2264: != CODE_FOR_nothing) ! 2265: { ! 2266: last = emit_move_insn (target, target); ! 2267: if (equiv) ! 2268: REG_NOTES (last) ! 2269: = gen_rtx (EXPR_LIST, REG_EQUAL, equiv, REG_NOTES (last)); ! 2270: } ! 2271: else ! 2272: last = get_last_insn (); ! 2273: ! 2274: if (prev == 0) ! 2275: first = get_insns (); ! 2276: else ! 2277: first = NEXT_INSN (prev); ! 2278: ! 2279: /* Encapsulate the block so it gets manipulated as a unit. */ ! 2280: REG_NOTES (first) = gen_rtx (INSN_LIST, REG_LIBCALL, last, ! 2281: REG_NOTES (first)); ! 2282: REG_NOTES (last) = gen_rtx (INSN_LIST, REG_RETVAL, first, REG_NOTES (last)); ! 2283: ! 2284: return last; ! 2285: } ! 2286: ! 2287: /* Emit code to make a call to a constant function or a library call. ! 2288: ! 2289: INSNS is a list containing all insns emitted in the call. ! 2290: These insns leave the result in RESULT. Our block is to copy RESULT ! 2291: to TARGET, which is logically equivalent to EQUIV. ! 2292: ! 2293: We first emit any insns that set a pseudo on the assumption that these are ! 2294: loading constants into registers; doing so allows them to be safely cse'ed ! 2295: between blocks. Then we emit all the other insns in the block, followed by ! 2296: an insn to move RESULT to TARGET. This last insn will have a REQ_EQUAL ! 2297: note with an operand of EQUIV. ! 2298: ! 2299: Moving assignments to pseudos outside of the block is done to improve ! 2300: the generated code, but is not required to generate correct code, ! 2301: hence being unable to move an assignment is not grounds for not making ! 2302: a libcall block. There are two reasons why it is safe to leave these ! 2303: insns inside the block: First, we know that these pseudos cannot be ! 2304: used in generated RTL outside the block since they are created for ! 2305: temporary purposes within the block. Second, CSE will not record the ! 2306: values of anything set inside a libcall block, so we know they must ! 2307: be dead at the end of the block. ! 2308: ! 2309: Except for the first group of insns (the ones setting pseudos), the ! 2310: block is delimited by REG_RETVAL and REG_LIBCALL notes. */ ! 2311: ! 2312: void ! 2313: emit_libcall_block (insns, target, result, equiv) ! 2314: rtx insns; ! 2315: rtx target; ! 2316: rtx result; ! 2317: rtx equiv; ! 2318: { ! 2319: rtx prev, next, first, last, insn; ! 2320: ! 2321: /* First emit all insns that set pseudos. Remove them from the list as ! 2322: we go. Avoid insns that set pseudos which were referenced in previous ! 2323: insns. These can be generated by move_by_pieces, for example, ! 2324: to update an address. Similarly, avoid insns that reference things ! 2325: set in previous insns. */ ! 2326: ! 2327: for (insn = insns; insn; insn = next) ! 2328: { ! 2329: rtx set = single_set (insn); ! 2330: ! 2331: next = NEXT_INSN (insn); ! 2332: ! 2333: if (set != 0 && GET_CODE (SET_DEST (set)) == REG ! 2334: && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER ! 2335: && (insn == insns ! 2336: || (! reg_mentioned_p (SET_DEST (set), PATTERN (insns)) ! 2337: && ! reg_used_between_p (SET_DEST (set), insns, insn) ! 2338: && ! modified_in_p (SET_SRC (set), insns) ! 2339: && ! modified_between_p (SET_SRC (set), insns, insn)))) ! 2340: { ! 2341: if (PREV_INSN (insn)) ! 2342: NEXT_INSN (PREV_INSN (insn)) = next; ! 2343: else ! 2344: insns = next; ! 2345: ! 2346: if (next) ! 2347: PREV_INSN (next) = PREV_INSN (insn); ! 2348: ! 2349: add_insn (insn); ! 2350: } ! 2351: } ! 2352: ! 2353: prev = get_last_insn (); ! 2354: ! 2355: /* Write the remaining insns followed by the final copy. */ ! 2356: ! 2357: for (insn = insns; insn; insn = next) ! 2358: { ! 2359: next = NEXT_INSN (insn); ! 2360: ! 2361: add_insn (insn); ! 2362: } ! 2363: ! 2364: last = emit_move_insn (target, result); ! 2365: REG_NOTES (last) = gen_rtx (EXPR_LIST, ! 2366: REG_EQUAL, copy_rtx (equiv), REG_NOTES (last)); ! 2367: ! 2368: if (prev == 0) ! 2369: first = get_insns (); ! 2370: else ! 2371: first = NEXT_INSN (prev); ! 2372: ! 2373: /* Encapsulate the block so it gets manipulated as a unit. */ ! 2374: REG_NOTES (first) = gen_rtx (INSN_LIST, REG_LIBCALL, last, ! 2375: REG_NOTES (first)); ! 2376: REG_NOTES (last) = gen_rtx (INSN_LIST, REG_RETVAL, first, REG_NOTES (last)); ! 2377: } ! 2378: ! 2379: /* Generate code to store zero in X. */ ! 2380: ! 2381: void ! 2382: emit_clr_insn (x) ! 2383: rtx x; ! 2384: { ! 2385: emit_move_insn (x, const0_rtx); ! 2386: } ! 2387: ! 2388: /* Generate code to store 1 in X ! 2389: assuming it contains zero beforehand. */ ! 2390: ! 2391: void ! 2392: emit_0_to_1_insn (x) ! 2393: rtx x; ! 2394: { ! 2395: emit_move_insn (x, const1_rtx); ! 2396: } ! 2397: ! 2398: /* Generate code to compare X with Y ! 2399: so that the condition codes are set. ! 2400: ! 2401: MODE is the mode of the inputs (in case they are const_int). ! 2402: UNSIGNEDP nonzero says that X and Y are unsigned; ! 2403: this matters if they need to be widened. ! 2404: ! 2405: If they have mode BLKmode, then SIZE specifies the size of both X and Y, ! 2406: and ALIGN specifies the known shared alignment of X and Y. ! 2407: ! 2408: COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.). ! 2409: It is ignored for fixed-point and block comparisons; ! 2410: it is used only for floating-point comparisons. */ ! 2411: ! 2412: void ! 2413: emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align) ! 2414: rtx x, y; ! 2415: enum rtx_code comparison; ! 2416: rtx size; ! 2417: enum machine_mode mode; ! 2418: int unsignedp; ! 2419: int align; ! 2420: { ! 2421: enum mode_class class; ! 2422: enum machine_mode wider_mode; ! 2423: ! 2424: class = GET_MODE_CLASS (mode); ! 2425: ! 2426: /* They could both be VOIDmode if both args are immediate constants, ! 2427: but we should fold that at an earlier stage. ! 2428: With no special code here, this will call abort, ! 2429: reminding the programmer to implement such folding. */ ! 2430: ! 2431: if (mode != BLKmode && flag_force_mem) ! 2432: { ! 2433: x = force_not_mem (x); ! 2434: y = force_not_mem (y); ! 2435: } ! 2436: ! 2437: /* If we are inside an appropriately-short loop and one operand is an ! 2438: expensive constant, force it into a register. */ ! 2439: if (CONSTANT_P (x) && preserve_subexpressions_p () && rtx_cost (x, COMPARE) > 2) ! 2440: x = force_reg (mode, x); ! 2441: ! 2442: if (CONSTANT_P (y) && preserve_subexpressions_p () && rtx_cost (y, COMPARE) > 2) ! 2443: y = force_reg (mode, y); ! 2444: ! 2445: /* Don't let both operands fail to indicate the mode. */ ! 2446: if (GET_MODE (x) == VOIDmode && GET_MODE (y) == VOIDmode) ! 2447: x = force_reg (mode, x); ! 2448: ! 2449: /* Handle all BLKmode compares. */ ! 2450: ! 2451: if (mode == BLKmode) ! 2452: { ! 2453: emit_queue (); ! 2454: x = protect_from_queue (x, 0); ! 2455: y = protect_from_queue (y, 0); ! 2456: ! 2457: if (size == 0) ! 2458: abort (); ! 2459: #ifdef HAVE_cmpstrqi ! 2460: if (HAVE_cmpstrqi ! 2461: && GET_CODE (size) == CONST_INT ! 2462: && INTVAL (size) < (1 << GET_MODE_BITSIZE (QImode))) ! 2463: { ! 2464: enum machine_mode result_mode ! 2465: = insn_operand_mode[(int) CODE_FOR_cmpstrqi][0]; ! 2466: rtx result = gen_reg_rtx (result_mode); ! 2467: emit_insn (gen_cmpstrqi (result, x, y, size, GEN_INT (align))); ! 2468: emit_cmp_insn (result, const0_rtx, comparison, NULL_RTX, ! 2469: result_mode, 0, 0); ! 2470: } ! 2471: else ! 2472: #endif ! 2473: #ifdef HAVE_cmpstrhi ! 2474: if (HAVE_cmpstrhi ! 2475: && GET_CODE (size) == CONST_INT ! 2476: && INTVAL (size) < (1 << GET_MODE_BITSIZE (HImode))) ! 2477: { ! 2478: enum machine_mode result_mode ! 2479: = insn_operand_mode[(int) CODE_FOR_cmpstrhi][0]; ! 2480: rtx result = gen_reg_rtx (result_mode); ! 2481: emit_insn (gen_cmpstrhi (result, x, y, size, GEN_INT (align))); ! 2482: emit_cmp_insn (result, const0_rtx, comparison, NULL_RTX, ! 2483: result_mode, 0, 0); ! 2484: } ! 2485: else ! 2486: #endif ! 2487: #ifdef HAVE_cmpstrsi ! 2488: if (HAVE_cmpstrsi) ! 2489: { ! 2490: enum machine_mode result_mode ! 2491: = insn_operand_mode[(int) CODE_FOR_cmpstrsi][0]; ! 2492: rtx result = gen_reg_rtx (result_mode); ! 2493: size = protect_from_queue (size, 0); ! 2494: emit_insn (gen_cmpstrsi (result, x, y, ! 2495: convert_to_mode (SImode, size, 1), ! 2496: GEN_INT (align))); ! 2497: emit_cmp_insn (result, const0_rtx, comparison, NULL_RTX, ! 2498: result_mode, 0, 0); ! 2499: } ! 2500: else ! 2501: #endif ! 2502: { ! 2503: #ifdef TARGET_MEM_FUNCTIONS ! 2504: emit_library_call (memcmp_libfunc, 0, ! 2505: TYPE_MODE (integer_type_node), 3, ! 2506: XEXP (x, 0), Pmode, XEXP (y, 0), Pmode, ! 2507: size, Pmode); ! 2508: #else ! 2509: emit_library_call (bcmp_libfunc, 0, ! 2510: TYPE_MODE (integer_type_node), 3, ! 2511: XEXP (x, 0), Pmode, XEXP (y, 0), Pmode, ! 2512: size, Pmode); ! 2513: #endif ! 2514: emit_cmp_insn (hard_libcall_value (TYPE_MODE (integer_type_node)), ! 2515: const0_rtx, comparison, NULL_RTX, ! 2516: TYPE_MODE (integer_type_node), 0, 0); ! 2517: } ! 2518: return; ! 2519: } ! 2520: ! 2521: /* Handle some compares against zero. */ ! 2522: ! 2523: if (y == CONST0_RTX (mode) ! 2524: && tst_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) ! 2525: { ! 2526: int icode = (int) tst_optab->handlers[(int) mode].insn_code; ! 2527: ! 2528: emit_queue (); ! 2529: x = protect_from_queue (x, 0); ! 2530: y = protect_from_queue (y, 0); ! 2531: ! 2532: /* Now, if insn does accept these operands, put them into pseudos. */ ! 2533: if (! (*insn_operand_predicate[icode][0]) ! 2534: (x, insn_operand_mode[icode][0])) ! 2535: x = copy_to_mode_reg (insn_operand_mode[icode][0], x); ! 2536: ! 2537: emit_insn (GEN_FCN (icode) (x)); ! 2538: return; ! 2539: } ! 2540: ! 2541: /* Handle compares for which there is a directly suitable insn. */ ! 2542: ! 2543: if (cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) ! 2544: { ! 2545: int icode = (int) cmp_optab->handlers[(int) mode].insn_code; ! 2546: ! 2547: emit_queue (); ! 2548: x = protect_from_queue (x, 0); ! 2549: y = protect_from_queue (y, 0); ! 2550: ! 2551: /* Now, if insn doesn't accept these operands, put them into pseudos. */ ! 2552: if (! (*insn_operand_predicate[icode][0]) ! 2553: (x, insn_operand_mode[icode][0])) ! 2554: x = copy_to_mode_reg (insn_operand_mode[icode][0], x); ! 2555: ! 2556: if (! (*insn_operand_predicate[icode][1]) ! 2557: (y, insn_operand_mode[icode][1])) ! 2558: y = copy_to_mode_reg (insn_operand_mode[icode][1], y); ! 2559: ! 2560: emit_insn (GEN_FCN (icode) (x, y)); ! 2561: return; ! 2562: } ! 2563: ! 2564: /* Try widening if we can find a direct insn that way. */ ! 2565: ! 2566: if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT) ! 2567: { ! 2568: for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode; ! 2569: wider_mode = GET_MODE_WIDER_MODE (wider_mode)) ! 2570: { ! 2571: if (cmp_optab->handlers[(int) wider_mode].insn_code ! 2572: != CODE_FOR_nothing) ! 2573: { ! 2574: x = protect_from_queue (x, 0); ! 2575: y = protect_from_queue (y, 0); ! 2576: x = convert_modes (wider_mode, mode, x, unsignedp); ! 2577: y = convert_modes (wider_mode, mode, y, unsignedp); ! 2578: emit_cmp_insn (x, y, comparison, NULL_RTX, ! 2579: wider_mode, unsignedp, align); ! 2580: return; ! 2581: } ! 2582: } ! 2583: } ! 2584: ! 2585: /* Handle a lib call just for the mode we are using. */ ! 2586: ! 2587: if (cmp_optab->handlers[(int) mode].libfunc ! 2588: && class != MODE_FLOAT) ! 2589: { ! 2590: rtx libfunc = cmp_optab->handlers[(int) mode].libfunc; ! 2591: /* If we want unsigned, and this mode has a distinct unsigned ! 2592: comparison routine, use that. */ ! 2593: if (unsignedp && ucmp_optab->handlers[(int) mode].libfunc) ! 2594: libfunc = ucmp_optab->handlers[(int) mode].libfunc; ! 2595: ! 2596: emit_library_call (libfunc, 1, ! 2597: word_mode, 2, x, mode, y, mode); ! 2598: ! 2599: /* Integer comparison returns a result that must be compared against 1, ! 2600: so that even if we do an unsigned compare afterward, ! 2601: there is still a value that can represent the result "less than". */ ! 2602: ! 2603: emit_cmp_insn (hard_libcall_value (word_mode), const1_rtx, ! 2604: comparison, NULL_RTX, word_mode, unsignedp, 0); ! 2605: return; ! 2606: } ! 2607: ! 2608: if (class == MODE_FLOAT) ! 2609: emit_float_lib_cmp (x, y, comparison); ! 2610: ! 2611: else ! 2612: abort (); ! 2613: } ! 2614: ! 2615: /* Nonzero if a compare of mode MODE can be done straightforwardly ! 2616: (without splitting it into pieces). */ ! 2617: ! 2618: int ! 2619: can_compare_p (mode) ! 2620: enum machine_mode mode; ! 2621: { ! 2622: do ! 2623: { ! 2624: if (cmp_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing) ! 2625: return 1; ! 2626: mode = GET_MODE_WIDER_MODE (mode); ! 2627: } while (mode != VOIDmode); ! 2628: ! 2629: return 0; ! 2630: } ! 2631: ! 2632: /* Emit a library call comparison between floating point X and Y. ! 2633: COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.). */ ! 2634: ! 2635: void ! 2636: emit_float_lib_cmp (x, y, comparison) ! 2637: rtx x, y; ! 2638: enum rtx_code comparison; ! 2639: { ! 2640: enum machine_mode mode = GET_MODE (x); ! 2641: rtx libfunc = 0; ! 2642: ! 2643: if (mode == SFmode) ! 2644: switch (comparison) ! 2645: { ! 2646: case EQ: ! 2647: libfunc = eqsf2_libfunc; ! 2648: break; ! 2649: ! 2650: case NE: ! 2651: libfunc = nesf2_libfunc; ! 2652: break; ! 2653: ! 2654: case GT: ! 2655: libfunc = gtsf2_libfunc; ! 2656: break; ! 2657: ! 2658: case GE: ! 2659: libfunc = gesf2_libfunc; ! 2660: break; ! 2661: ! 2662: case LT: ! 2663: libfunc = ltsf2_libfunc; ! 2664: break; ! 2665: ! 2666: case LE: ! 2667: libfunc = lesf2_libfunc; ! 2668: break; ! 2669: } ! 2670: else if (mode == DFmode) ! 2671: switch (comparison) ! 2672: { ! 2673: case EQ: ! 2674: libfunc = eqdf2_libfunc; ! 2675: break; ! 2676: ! 2677: case NE: ! 2678: libfunc = nedf2_libfunc; ! 2679: break; ! 2680: ! 2681: case GT: ! 2682: libfunc = gtdf2_libfunc; ! 2683: break; ! 2684: ! 2685: case GE: ! 2686: libfunc = gedf2_libfunc; ! 2687: break; ! 2688: ! 2689: case LT: ! 2690: libfunc = ltdf2_libfunc; ! 2691: break; ! 2692: ! 2693: case LE: ! 2694: libfunc = ledf2_libfunc; ! 2695: break; ! 2696: } ! 2697: else if (mode == XFmode) ! 2698: switch (comparison) ! 2699: { ! 2700: case EQ: ! 2701: libfunc = eqxf2_libfunc; ! 2702: break; ! 2703: ! 2704: case NE: ! 2705: libfunc = nexf2_libfunc; ! 2706: break; ! 2707: ! 2708: case GT: ! 2709: libfunc = gtxf2_libfunc; ! 2710: break; ! 2711: ! 2712: case GE: ! 2713: libfunc = gexf2_libfunc; ! 2714: break; ! 2715: ! 2716: case LT: ! 2717: libfunc = ltxf2_libfunc; ! 2718: break; ! 2719: ! 2720: case LE: ! 2721: libfunc = lexf2_libfunc; ! 2722: break; ! 2723: } ! 2724: else if (mode == TFmode) ! 2725: switch (comparison) ! 2726: { ! 2727: case EQ: ! 2728: libfunc = eqtf2_libfunc; ! 2729: break; ! 2730: ! 2731: case NE: ! 2732: libfunc = netf2_libfunc; ! 2733: break; ! 2734: ! 2735: case GT: ! 2736: libfunc = gttf2_libfunc; ! 2737: break; ! 2738: ! 2739: case GE: ! 2740: libfunc = getf2_libfunc; ! 2741: break; ! 2742: ! 2743: case LT: ! 2744: libfunc = lttf2_libfunc; ! 2745: break; ! 2746: ! 2747: case LE: ! 2748: libfunc = letf2_libfunc; ! 2749: break; ! 2750: } ! 2751: else ! 2752: { ! 2753: enum machine_mode wider_mode; ! 2754: ! 2755: for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode; ! 2756: wider_mode = GET_MODE_WIDER_MODE (wider_mode)) ! 2757: { ! 2758: if ((cmp_optab->handlers[(int) wider_mode].insn_code ! 2759: != CODE_FOR_nothing) ! 2760: || (cmp_optab->handlers[(int) wider_mode].libfunc != 0)) ! 2761: { ! 2762: x = protect_from_queue (x, 0); ! 2763: y = protect_from_queue (y, 0); ! 2764: x = convert_to_mode (wider_mode, x, 0); ! 2765: y = convert_to_mode (wider_mode, y, 0); ! 2766: emit_float_lib_cmp (x, y, comparison); ! 2767: return; ! 2768: } ! 2769: } ! 2770: abort (); ! 2771: } ! 2772: ! 2773: if (libfunc == 0) ! 2774: abort (); ! 2775: ! 2776: emit_library_call (libfunc, 1, ! 2777: word_mode, 2, x, mode, y, mode); ! 2778: ! 2779: emit_cmp_insn (hard_libcall_value (word_mode), const0_rtx, comparison, ! 2780: NULL_RTX, word_mode, 0, 0); ! 2781: } ! 2782: ! 2783: /* Generate code to indirectly jump to a location given in the rtx LOC. */ ! 2784: ! 2785: void ! 2786: emit_indirect_jump (loc) ! 2787: rtx loc; ! 2788: { ! 2789: if (! ((*insn_operand_predicate[(int)CODE_FOR_indirect_jump][0]) ! 2790: (loc, Pmode))) ! 2791: loc = copy_to_mode_reg (Pmode, loc); ! 2792: ! 2793: emit_jump_insn (gen_indirect_jump (loc)); ! 2794: emit_barrier (); ! 2795: } ! 2796: ! 2797: /* These three functions generate an insn body and return it ! 2798: rather than emitting the insn. ! 2799: ! 2800: They do not protect from queued increments, ! 2801: because they may be used 1) in protect_from_queue itself ! 2802: and 2) in other passes where there is no queue. */ ! 2803: ! 2804: /* Generate and return an insn body to add Y to X. */ ! 2805: ! 2806: rtx ! 2807: gen_add2_insn (x, y) ! 2808: rtx x, y; ! 2809: { ! 2810: int icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code; ! 2811: ! 2812: if (! (*insn_operand_predicate[icode][0]) (x, insn_operand_mode[icode][0]) ! 2813: || ! (*insn_operand_predicate[icode][1]) (x, insn_operand_mode[icode][1]) ! 2814: || ! (*insn_operand_predicate[icode][2]) (y, insn_operand_mode[icode][2])) ! 2815: abort (); ! 2816: ! 2817: return (GEN_FCN (icode) (x, x, y)); ! 2818: } ! 2819: ! 2820: int ! 2821: have_add2_insn (mode) ! 2822: enum machine_mode mode; ! 2823: { ! 2824: return add_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing; ! 2825: } ! 2826: ! 2827: /* Generate and return an insn body to subtract Y from X. */ ! 2828: ! 2829: rtx ! 2830: gen_sub2_insn (x, y) ! 2831: rtx x, y; ! 2832: { ! 2833: int icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code; ! 2834: ! 2835: if (! (*insn_operand_predicate[icode][0]) (x, insn_operand_mode[icode][0]) ! 2836: || ! (*insn_operand_predicate[icode][1]) (x, insn_operand_mode[icode][1]) ! 2837: || ! (*insn_operand_predicate[icode][2]) (y, insn_operand_mode[icode][2])) ! 2838: abort (); ! 2839: ! 2840: return (GEN_FCN (icode) (x, x, y)); ! 2841: } ! 2842: ! 2843: int ! 2844: have_sub2_insn (mode) ! 2845: enum machine_mode mode; ! 2846: { ! 2847: return sub_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing; ! 2848: } ! 2849: ! 2850: /* Generate the body of an instruction to copy Y into X. ! 2851: It may be a SEQUENCE, if one insn isn't enough. */ ! 2852: ! 2853: rtx ! 2854: gen_move_insn (x, y) ! 2855: rtx x, y; ! 2856: { ! 2857: register enum machine_mode mode = GET_MODE (x); ! 2858: enum insn_code insn_code; ! 2859: rtx seq; ! 2860: ! 2861: if (mode == VOIDmode) ! 2862: mode = GET_MODE (y); ! 2863: ! 2864: insn_code = mov_optab->handlers[(int) mode].insn_code; ! 2865: ! 2866: /* Handle MODE_CC modes: If we don't have a special move insn for this mode, ! 2867: find a mode to do it in. If we have a movcc, use it. Otherwise, ! 2868: find the MODE_INT mode of the same width. */ ! 2869: ! 2870: if (GET_MODE_CLASS (mode) == MODE_CC && insn_code == CODE_FOR_nothing) ! 2871: { ! 2872: enum machine_mode tmode = VOIDmode; ! 2873: rtx x1 = x, y1 = y; ! 2874: ! 2875: if (mode != CCmode ! 2876: && mov_optab->handlers[(int) CCmode].insn_code != CODE_FOR_nothing) ! 2877: tmode = CCmode; ! 2878: else ! 2879: for (tmode = QImode; tmode != VOIDmode; ! 2880: tmode = GET_MODE_WIDER_MODE (tmode)) ! 2881: if (GET_MODE_SIZE (tmode) == GET_MODE_SIZE (mode)) ! 2882: break; ! 2883: ! 2884: if (tmode == VOIDmode) ! 2885: abort (); ! 2886: ! 2887: /* Get X and Y in TMODE. We can't use gen_lowpart here because it ! 2888: may call change_address which is not appropriate if we were ! 2889: called when a reload was in progress. We don't have to worry ! 2890: about changing the address since the size in bytes is supposed to ! 2891: be the same. Copy the MEM to change the mode and move any ! 2892: substitutions from the old MEM to the new one. */ ! 2893: ! 2894: if (reload_in_progress) ! 2895: { ! 2896: x = gen_lowpart_common (tmode, x1); ! 2897: if (x == 0 && GET_CODE (x1) == MEM) ! 2898: { ! 2899: x = gen_rtx (MEM, tmode, XEXP (x1, 0)); ! 2900: RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (x1); ! 2901: MEM_IN_STRUCT_P (x) = MEM_IN_STRUCT_P (x1); ! 2902: MEM_VOLATILE_P (x) = MEM_VOLATILE_P (x1); ! 2903: copy_replacements (x1, x); ! 2904: } ! 2905: ! 2906: y = gen_lowpart_common (tmode, y1); ! 2907: if (y == 0 && GET_CODE (y1) == MEM) ! 2908: { ! 2909: y = gen_rtx (MEM, tmode, XEXP (y1, 0)); ! 2910: RTX_UNCHANGING_P (y) = RTX_UNCHANGING_P (y1); ! 2911: MEM_IN_STRUCT_P (y) = MEM_IN_STRUCT_P (y1); ! 2912: MEM_VOLATILE_P (y) = MEM_VOLATILE_P (y1); ! 2913: copy_replacements (y1, y); ! 2914: } ! 2915: } ! 2916: else ! 2917: { ! 2918: x = gen_lowpart (tmode, x); ! 2919: y = gen_lowpart (tmode, y); ! 2920: } ! 2921: ! 2922: insn_code = mov_optab->handlers[(int) tmode].insn_code; ! 2923: return (GEN_FCN (insn_code) (x, y)); ! 2924: } ! 2925: ! 2926: start_sequence (); ! 2927: emit_move_insn_1 (x, y); ! 2928: seq = gen_sequence (); ! 2929: end_sequence (); ! 2930: return seq; ! 2931: } ! 2932: ! 2933: /* Return the insn code used to extend FROM_MODE to TO_MODE. ! 2934: UNSIGNEDP specifies zero-extension instead of sign-extension. If ! 2935: no such operation exists, CODE_FOR_nothing will be returned. */ ! 2936: ! 2937: enum insn_code ! 2938: can_extend_p (to_mode, from_mode, unsignedp) ! 2939: enum machine_mode to_mode, from_mode; ! 2940: int unsignedp; ! 2941: { ! 2942: return extendtab[(int) to_mode][(int) from_mode][unsignedp]; ! 2943: } ! 2944: ! 2945: /* Generate the body of an insn to extend Y (with mode MFROM) ! 2946: into X (with mode MTO). Do zero-extension if UNSIGNEDP is nonzero. */ ! 2947: ! 2948: rtx ! 2949: gen_extend_insn (x, y, mto, mfrom, unsignedp) ! 2950: rtx x, y; ! 2951: enum machine_mode mto, mfrom; ! 2952: int unsignedp; ! 2953: { ! 2954: return (GEN_FCN (extendtab[(int) mto][(int) mfrom][unsignedp]) (x, y)); ! 2955: } ! 2956: ! 2957: /* can_fix_p and can_float_p say whether the target machine ! 2958: can directly convert a given fixed point type to ! 2959: a given floating point type, or vice versa. ! 2960: The returned value is the CODE_FOR_... value to use, ! 2961: or CODE_FOR_nothing if these modes cannot be directly converted. ! 2962: ! 2963: *TRUNCP_PTR is set to 1 if it is necessary to output ! 2964: an explicit FTRUNC insn before the fix insn; otherwise 0. */ ! 2965: ! 2966: static enum insn_code ! 2967: can_fix_p (fixmode, fltmode, unsignedp, truncp_ptr) ! 2968: enum machine_mode fltmode, fixmode; ! 2969: int unsignedp; ! 2970: int *truncp_ptr; ! 2971: { ! 2972: *truncp_ptr = 0; ! 2973: if (fixtrunctab[(int) fltmode][(int) fixmode][unsignedp] != CODE_FOR_nothing) ! 2974: return fixtrunctab[(int) fltmode][(int) fixmode][unsignedp]; ! 2975: ! 2976: if (ftrunc_optab->handlers[(int) fltmode].insn_code != CODE_FOR_nothing) ! 2977: { ! 2978: *truncp_ptr = 1; ! 2979: return fixtab[(int) fltmode][(int) fixmode][unsignedp]; ! 2980: } ! 2981: return CODE_FOR_nothing; ! 2982: } ! 2983: ! 2984: static enum insn_code ! 2985: can_float_p (fltmode, fixmode, unsignedp) ! 2986: enum machine_mode fixmode, fltmode; ! 2987: int unsignedp; ! 2988: { ! 2989: return floattab[(int) fltmode][(int) fixmode][unsignedp]; ! 2990: } ! 2991: ! 2992: /* Generate code to convert FROM to floating point ! 2993: and store in TO. FROM must be fixed point and not VOIDmode. ! 2994: UNSIGNEDP nonzero means regard FROM as unsigned. ! 2995: Normally this is done by correcting the final value ! 2996: if it is negative. */ ! 2997: ! 2998: void ! 2999: expand_float (to, from, unsignedp) ! 3000: rtx to, from; ! 3001: int unsignedp; ! 3002: { ! 3003: enum insn_code icode; ! 3004: register rtx target = to; ! 3005: enum machine_mode fmode, imode; ! 3006: ! 3007: /* Crash now, because we won't be able to decide which mode to use. */ ! 3008: if (GET_MODE (from) == VOIDmode) ! 3009: abort (); ! 3010: ! 3011: /* Look for an insn to do the conversion. Do it in the specified ! 3012: modes if possible; otherwise convert either input, output or both to ! 3013: wider mode. If the integer mode is wider than the mode of FROM, ! 3014: we can do the conversion signed even if the input is unsigned. */ ! 3015: ! 3016: for (imode = GET_MODE (from); imode != VOIDmode; ! 3017: imode = GET_MODE_WIDER_MODE (imode)) ! 3018: for (fmode = GET_MODE (to); fmode != VOIDmode; ! 3019: fmode = GET_MODE_WIDER_MODE (fmode)) ! 3020: { ! 3021: int doing_unsigned = unsignedp; ! 3022: ! 3023: icode = can_float_p (fmode, imode, unsignedp); ! 3024: if (icode == CODE_FOR_nothing && imode != GET_MODE (from) && unsignedp) ! 3025: icode = can_float_p (fmode, imode, 0), doing_unsigned = 0; ! 3026: ! 3027: if (icode != CODE_FOR_nothing) ! 3028: { ! 3029: to = protect_from_queue (to, 1); ! 3030: from = protect_from_queue (from, 0); ! 3031: ! 3032: if (imode != GET_MODE (from)) ! 3033: from = convert_to_mode (imode, from, unsignedp); ! 3034: ! 3035: if (fmode != GET_MODE (to)) ! 3036: target = gen_reg_rtx (fmode); ! 3037: ! 3038: emit_unop_insn (icode, target, from, ! 3039: doing_unsigned ? UNSIGNED_FLOAT : FLOAT); ! 3040: ! 3041: if (target != to) ! 3042: convert_move (to, target, 0); ! 3043: return; ! 3044: } ! 3045: } ! 3046: ! 3047: #if !defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC) ! 3048: ! 3049: /* Unsigned integer, and no way to convert directly. ! 3050: Convert as signed, then conditionally adjust the result. */ ! 3051: if (unsignedp) ! 3052: { ! 3053: rtx label = gen_label_rtx (); ! 3054: rtx temp; ! 3055: REAL_VALUE_TYPE offset; ! 3056: ! 3057: emit_queue (); ! 3058: ! 3059: to = protect_from_queue (to, 1); ! 3060: from = protect_from_queue (from, 0); ! 3061: ! 3062: if (flag_force_mem) ! 3063: from = force_not_mem (from); ! 3064: ! 3065: /* Look for a usable floating mode FMODE wider than the source and at ! 3066: least as wide as the target. Using FMODE will avoid rounding woes ! 3067: with unsigned values greater than the signed maximum value. */ ! 3068: for (fmode = GET_MODE (to); fmode != VOIDmode; ! 3069: fmode = GET_MODE_WIDER_MODE (fmode)) ! 3070: if (GET_MODE_BITSIZE (GET_MODE (from)) < GET_MODE_BITSIZE (fmode) ! 3071: && can_float_p (fmode, GET_MODE (from), 0) != CODE_FOR_nothing) ! 3072: break; ! 3073: if (fmode == VOIDmode) ! 3074: { ! 3075: /* There is no such mode. Pretend the target is wide enough. ! 3076: This may cause rounding problems, unfortunately. */ ! 3077: fmode = GET_MODE (to); ! 3078: } ! 3079: ! 3080: /* If we are about to do some arithmetic to correct for an ! 3081: unsigned operand, do it in a pseudo-register. */ ! 3082: ! 3083: if (GET_MODE (to) != fmode ! 3084: || GET_CODE (to) != REG || REGNO (to) <= LAST_VIRTUAL_REGISTER) ! 3085: target = gen_reg_rtx (fmode); ! 3086: ! 3087: /* Convert as signed integer to floating. */ ! 3088: expand_float (target, from, 0); ! 3089: ! 3090: /* If FROM is negative (and therefore TO is negative), ! 3091: correct its value by 2**bitwidth. */ ! 3092: ! 3093: do_pending_stack_adjust (); ! 3094: emit_cmp_insn (from, const0_rtx, GE, NULL_RTX, GET_MODE (from), 0, 0); ! 3095: emit_jump_insn (gen_bge (label)); ! 3096: /* On SCO 3.2.1, ldexp rejects values outside [0.5, 1). ! 3097: Rather than setting up a dconst_dot_5, let's hope SCO ! 3098: fixes the bug. */ ! 3099: offset = REAL_VALUE_LDEXP (dconst1, GET_MODE_BITSIZE (GET_MODE (from))); ! 3100: temp = expand_binop (fmode, add_optab, target, ! 3101: immed_real_const_1 (offset, fmode), ! 3102: target, 0, OPTAB_LIB_WIDEN); ! 3103: if (temp != target) ! 3104: emit_move_insn (target, temp); ! 3105: do_pending_stack_adjust (); ! 3106: emit_label (label); ! 3107: } ! 3108: else ! 3109: #endif ! 3110: ! 3111: /* No hardware instruction available; call a library rotine to convert from ! 3112: SImode, DImode, or TImode into SFmode, DFmode, XFmode, or TFmode. */ ! 3113: { ! 3114: rtx libfcn; ! 3115: rtx insns; ! 3116: rtx value; ! 3117: ! 3118: to = protect_from_queue (to, 1); ! 3119: from = protect_from_queue (from, 0); ! 3120: ! 3121: if (GET_MODE_SIZE (GET_MODE (from)) < GET_MODE_SIZE (SImode)) ! 3122: from = convert_to_mode (SImode, from, unsignedp); ! 3123: ! 3124: if (flag_force_mem) ! 3125: from = force_not_mem (from); ! 3126: ! 3127: if (GET_MODE (to) == SFmode) ! 3128: { ! 3129: if (GET_MODE (from) == SImode) ! 3130: libfcn = floatsisf_libfunc; ! 3131: else if (GET_MODE (from) == DImode) ! 3132: libfcn = floatdisf_libfunc; ! 3133: else if (GET_MODE (from) == TImode) ! 3134: libfcn = floattisf_libfunc; ! 3135: else ! 3136: abort (); ! 3137: } ! 3138: else if (GET_MODE (to) == DFmode) ! 3139: { ! 3140: if (GET_MODE (from) == SImode) ! 3141: libfcn = floatsidf_libfunc; ! 3142: else if (GET_MODE (from) == DImode) ! 3143: libfcn = floatdidf_libfunc; ! 3144: else if (GET_MODE (from) == TImode) ! 3145: libfcn = floattidf_libfunc; ! 3146: else ! 3147: abort (); ! 3148: } ! 3149: else if (GET_MODE (to) == XFmode) ! 3150: { ! 3151: if (GET_MODE (from) == SImode) ! 3152: libfcn = floatsixf_libfunc; ! 3153: else if (GET_MODE (from) == DImode) ! 3154: libfcn = floatdixf_libfunc; ! 3155: else if (GET_MODE (from) == TImode) ! 3156: libfcn = floattixf_libfunc; ! 3157: else ! 3158: abort (); ! 3159: } ! 3160: else if (GET_MODE (to) == TFmode) ! 3161: { ! 3162: if (GET_MODE (from) == SImode) ! 3163: libfcn = floatsitf_libfunc; ! 3164: else if (GET_MODE (from) == DImode) ! 3165: libfcn = floatditf_libfunc; ! 3166: else if (GET_MODE (from) == TImode) ! 3167: libfcn = floattitf_libfunc; ! 3168: else ! 3169: abort (); ! 3170: } ! 3171: else ! 3172: abort (); ! 3173: ! 3174: start_sequence (); ! 3175: ! 3176: value = emit_library_call_value (libfcn, NULL_RTX, 1, ! 3177: GET_MODE (to), ! 3178: 1, from, GET_MODE (from)); ! 3179: insns = get_insns (); ! 3180: end_sequence (); ! 3181: ! 3182: emit_libcall_block (insns, target, value, ! 3183: gen_rtx (FLOAT, GET_MODE (to), from)); ! 3184: } ! 3185: ! 3186: /* Copy result to requested destination ! 3187: if we have been computing in a temp location. */ ! 3188: ! 3189: if (target != to) ! 3190: { ! 3191: if (GET_MODE (target) == GET_MODE (to)) ! 3192: emit_move_insn (to, target); ! 3193: else ! 3194: convert_move (to, target, 0); ! 3195: } ! 3196: } ! 3197: ! 3198: /* expand_fix: generate code to convert FROM to fixed point ! 3199: and store in TO. FROM must be floating point. */ ! 3200: ! 3201: static rtx ! 3202: ftruncify (x) ! 3203: rtx x; ! 3204: { ! 3205: rtx temp = gen_reg_rtx (GET_MODE (x)); ! 3206: return expand_unop (GET_MODE (x), ftrunc_optab, x, temp, 0); ! 3207: } ! 3208: ! 3209: void ! 3210: expand_fix (to, from, unsignedp) ! 3211: register rtx to, from; ! 3212: int unsignedp; ! 3213: { ! 3214: enum insn_code icode; ! 3215: register rtx target = to; ! 3216: enum machine_mode fmode, imode; ! 3217: int must_trunc = 0; ! 3218: rtx libfcn = 0; ! 3219: ! 3220: /* We first try to find a pair of modes, one real and one integer, at ! 3221: least as wide as FROM and TO, respectively, in which we can open-code ! 3222: this conversion. If the integer mode is wider than the mode of TO, ! 3223: we can do the conversion either signed or unsigned. */ ! 3224: ! 3225: for (imode = GET_MODE (to); imode != VOIDmode; ! 3226: imode = GET_MODE_WIDER_MODE (imode)) ! 3227: for (fmode = GET_MODE (from); fmode != VOIDmode; ! 3228: fmode = GET_MODE_WIDER_MODE (fmode)) ! 3229: { ! 3230: int doing_unsigned = unsignedp; ! 3231: ! 3232: icode = can_fix_p (imode, fmode, unsignedp, &must_trunc); ! 3233: if (icode == CODE_FOR_nothing && imode != GET_MODE (to) && unsignedp) ! 3234: icode = can_fix_p (imode, fmode, 0, &must_trunc), doing_unsigned = 0; ! 3235: ! 3236: if (icode != CODE_FOR_nothing) ! 3237: { ! 3238: to = protect_from_queue (to, 1); ! 3239: from = protect_from_queue (from, 0); ! 3240: ! 3241: if (fmode != GET_MODE (from)) ! 3242: from = convert_to_mode (fmode, from, 0); ! 3243: ! 3244: if (must_trunc) ! 3245: from = ftruncify (from); ! 3246: ! 3247: if (imode != GET_MODE (to)) ! 3248: target = gen_reg_rtx (imode); ! 3249: ! 3250: emit_unop_insn (icode, target, from, ! 3251: doing_unsigned ? UNSIGNED_FIX : FIX); ! 3252: if (target != to) ! 3253: convert_move (to, target, unsignedp); ! 3254: return; ! 3255: } ! 3256: } ! 3257: ! 3258: #if !defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC) ! 3259: /* For an unsigned conversion, there is one more way to do it. ! 3260: If we have a signed conversion, we generate code that compares ! 3261: the real value to the largest representable positive number. If if ! 3262: is smaller, the conversion is done normally. Otherwise, subtract ! 3263: one plus the highest signed number, convert, and add it back. ! 3264: ! 3265: We only need to check all real modes, since we know we didn't find ! 3266: anything with a wider integer mode. */ ! 3267: ! 3268: if (unsignedp && GET_MODE_BITSIZE (GET_MODE (to)) <= HOST_BITS_PER_WIDE_INT) ! 3269: for (fmode = GET_MODE (from); fmode != VOIDmode; ! 3270: fmode = GET_MODE_WIDER_MODE (fmode)) ! 3271: /* Make sure we won't lose significant bits doing this. */ ! 3272: if (GET_MODE_BITSIZE (fmode) > GET_MODE_BITSIZE (GET_MODE (to)) ! 3273: && CODE_FOR_nothing != can_fix_p (GET_MODE (to), fmode, 0, ! 3274: &must_trunc)) ! 3275: { ! 3276: int bitsize; ! 3277: REAL_VALUE_TYPE offset; ! 3278: rtx limit, lab1, lab2, insn; ! 3279: ! 3280: bitsize = GET_MODE_BITSIZE (GET_MODE (to)); ! 3281: offset = REAL_VALUE_LDEXP (dconst1, bitsize - 1); ! 3282: limit = immed_real_const_1 (offset, fmode); ! 3283: lab1 = gen_label_rtx (); ! 3284: lab2 = gen_label_rtx (); ! 3285: ! 3286: emit_queue (); ! 3287: to = protect_from_queue (to, 1); ! 3288: from = protect_from_queue (from, 0); ! 3289: ! 3290: if (flag_force_mem) ! 3291: from = force_not_mem (from); ! 3292: ! 3293: if (fmode != GET_MODE (from)) ! 3294: from = convert_to_mode (fmode, from, 0); ! 3295: ! 3296: /* See if we need to do the subtraction. */ ! 3297: do_pending_stack_adjust (); ! 3298: emit_cmp_insn (from, limit, GE, NULL_RTX, GET_MODE (from), 0, 0); ! 3299: emit_jump_insn (gen_bge (lab1)); ! 3300: ! 3301: /* If not, do the signed "fix" and branch around fixup code. */ ! 3302: expand_fix (to, from, 0); ! 3303: emit_jump_insn (gen_jump (lab2)); ! 3304: emit_barrier (); ! 3305: ! 3306: /* Otherwise, subtract 2**(N-1), convert to signed number, ! 3307: then add 2**(N-1). Do the addition using XOR since this ! 3308: will often generate better code. */ ! 3309: emit_label (lab1); ! 3310: target = expand_binop (GET_MODE (from), sub_optab, from, limit, ! 3311: NULL_RTX, 0, OPTAB_LIB_WIDEN); ! 3312: expand_fix (to, target, 0); ! 3313: target = expand_binop (GET_MODE (to), xor_optab, to, ! 3314: GEN_INT ((HOST_WIDE_INT) 1 << (bitsize - 1)), ! 3315: to, 1, OPTAB_LIB_WIDEN); ! 3316: ! 3317: if (target != to) ! 3318: emit_move_insn (to, target); ! 3319: ! 3320: emit_label (lab2); ! 3321: ! 3322: /* Make a place for a REG_NOTE and add it. */ ! 3323: insn = emit_move_insn (to, to); ! 3324: REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_EQUAL, ! 3325: gen_rtx (UNSIGNED_FIX, GET_MODE (to), ! 3326: copy_rtx (from)), ! 3327: REG_NOTES (insn)); ! 3328: ! 3329: return; ! 3330: } ! 3331: #endif ! 3332: ! 3333: /* We can't do it with an insn, so use a library call. But first ensure ! 3334: that the mode of TO is at least as wide as SImode, since those are the ! 3335: only library calls we know about. */ ! 3336: ! 3337: if (GET_MODE_SIZE (GET_MODE (to)) < GET_MODE_SIZE (SImode)) ! 3338: { ! 3339: target = gen_reg_rtx (SImode); ! 3340: ! 3341: expand_fix (target, from, unsignedp); ! 3342: } ! 3343: else if (GET_MODE (from) == SFmode) ! 3344: { ! 3345: if (GET_MODE (to) == SImode) ! 3346: libfcn = unsignedp ? fixunssfsi_libfunc : fixsfsi_libfunc; ! 3347: else if (GET_MODE (to) == DImode) ! 3348: libfcn = unsignedp ? fixunssfdi_libfunc : fixsfdi_libfunc; ! 3349: else if (GET_MODE (to) == TImode) ! 3350: libfcn = unsignedp ? fixunssfti_libfunc : fixsfti_libfunc; ! 3351: else ! 3352: abort (); ! 3353: } ! 3354: else if (GET_MODE (from) == DFmode) ! 3355: { ! 3356: if (GET_MODE (to) == SImode) ! 3357: libfcn = unsignedp ? fixunsdfsi_libfunc : fixdfsi_libfunc; ! 3358: else if (GET_MODE (to) == DImode) ! 3359: libfcn = unsignedp ? fixunsdfdi_libfunc : fixdfdi_libfunc; ! 3360: else if (GET_MODE (to) == TImode) ! 3361: libfcn = unsignedp ? fixunsdfti_libfunc : fixdfti_libfunc; ! 3362: else ! 3363: abort (); ! 3364: } ! 3365: else if (GET_MODE (from) == XFmode) ! 3366: { ! 3367: if (GET_MODE (to) == SImode) ! 3368: libfcn = unsignedp ? fixunsxfsi_libfunc : fixxfsi_libfunc; ! 3369: else if (GET_MODE (to) == DImode) ! 3370: libfcn = unsignedp ? fixunsxfdi_libfunc : fixxfdi_libfunc; ! 3371: else if (GET_MODE (to) == TImode) ! 3372: libfcn = unsignedp ? fixunsxfti_libfunc : fixxfti_libfunc; ! 3373: else ! 3374: abort (); ! 3375: } ! 3376: else if (GET_MODE (from) == TFmode) ! 3377: { ! 3378: if (GET_MODE (to) == SImode) ! 3379: libfcn = unsignedp ? fixunstfsi_libfunc : fixtfsi_libfunc; ! 3380: else if (GET_MODE (to) == DImode) ! 3381: libfcn = unsignedp ? fixunstfdi_libfunc : fixtfdi_libfunc; ! 3382: else if (GET_MODE (to) == TImode) ! 3383: libfcn = unsignedp ? fixunstfti_libfunc : fixtfti_libfunc; ! 3384: else ! 3385: abort (); ! 3386: } ! 3387: else ! 3388: abort (); ! 3389: ! 3390: if (libfcn) ! 3391: { ! 3392: rtx insns; ! 3393: ! 3394: to = protect_from_queue (to, 1); ! 3395: from = protect_from_queue (from, 0); ! 3396: ! 3397: if (flag_force_mem) ! 3398: from = force_not_mem (from); ! 3399: ! 3400: start_sequence (); ! 3401: ! 3402: emit_library_call (libfcn, 1, GET_MODE (to), 1, from, GET_MODE (from)); ! 3403: insns = get_insns (); ! 3404: end_sequence (); ! 3405: ! 3406: emit_libcall_block (insns, target, hard_libcall_value (GET_MODE (to)), ! 3407: gen_rtx (unsignedp ? FIX : UNSIGNED_FIX, ! 3408: GET_MODE (to), from)); ! 3409: } ! 3410: ! 3411: if (GET_MODE (to) == GET_MODE (target)) ! 3412: emit_move_insn (to, target); ! 3413: else ! 3414: convert_move (to, target, 0); ! 3415: } ! 3416: ! 3417: static optab ! 3418: init_optab (code) ! 3419: enum rtx_code code; ! 3420: { ! 3421: int i; ! 3422: optab op = (optab) xmalloc (sizeof (struct optab)); ! 3423: op->code = code; ! 3424: for (i = 0; i < NUM_MACHINE_MODES; i++) ! 3425: { ! 3426: op->handlers[i].insn_code = CODE_FOR_nothing; ! 3427: op->handlers[i].libfunc = 0; ! 3428: } ! 3429: ! 3430: if (code != UNKNOWN) ! 3431: code_to_optab[(int) code] = op; ! 3432: ! 3433: return op; ! 3434: } ! 3435: ! 3436: /* Initialize the libfunc fields of an entire group of entries in some ! 3437: optab. Each entry is set equal to a string consisting of a leading ! 3438: pair of underscores followed by a generic operation name followed by ! 3439: a mode name (downshifted to lower case) followed by a single character ! 3440: representing the number of operands for the given operation (which is ! 3441: usually one of the characters '2', '3', or '4'). ! 3442: ! 3443: OPTABLE is the table in which libfunc fields are to be initialized. ! 3444: FIRST_MODE is the first machine mode index in the given optab to ! 3445: initialize. ! 3446: LAST_MODE is the last machine mode index in the given optab to ! 3447: initialize. ! 3448: OPNAME is the generic (string) name of the operation. ! 3449: SUFFIX is the character which specifies the number of operands for ! 3450: the given generic operation. ! 3451: */ ! 3452: ! 3453: static void ! 3454: init_libfuncs (optable, first_mode, last_mode, opname, suffix) ! 3455: register optab optable; ! 3456: register int first_mode; ! 3457: register int last_mode; ! 3458: register char *opname; ! 3459: register char suffix; ! 3460: { ! 3461: register int mode; ! 3462: register unsigned opname_len = strlen (opname); ! 3463: ! 3464: for (mode = first_mode; (int) mode <= (int) last_mode; ! 3465: mode = (enum machine_mode) ((int) mode + 1)) ! 3466: { ! 3467: register char *mname = mode_name[(int) mode]; ! 3468: register unsigned mname_len = strlen (mname); ! 3469: register char *libfunc_name ! 3470: = (char *) xmalloc (2 + opname_len + mname_len + 1 + 1); ! 3471: register char *p; ! 3472: register char *q; ! 3473: ! 3474: p = libfunc_name; ! 3475: *p++ = '_'; ! 3476: *p++ = '_'; ! 3477: for (q = opname; *q; ) ! 3478: *p++ = *q++; ! 3479: for (q = mname; *q; q++) ! 3480: *p++ = tolower (*q); ! 3481: *p++ = suffix; ! 3482: *p++ = '\0'; ! 3483: optable->handlers[(int) mode].libfunc ! 3484: = gen_rtx (SYMBOL_REF, Pmode, libfunc_name); ! 3485: } ! 3486: } ! 3487: ! 3488: /* Initialize the libfunc fields of an entire group of entries in some ! 3489: optab which correspond to all integer mode operations. The parameters ! 3490: have the same meaning as similarly named ones for the `init_libfuncs' ! 3491: routine. (See above). */ ! 3492: ! 3493: static void ! 3494: init_integral_libfuncs (optable, opname, suffix) ! 3495: register optab optable; ! 3496: register char *opname; ! 3497: register char suffix; ! 3498: { ! 3499: init_libfuncs (optable, SImode, TImode, opname, suffix); ! 3500: } ! 3501: ! 3502: /* Initialize the libfunc fields of an entire group of entries in some ! 3503: optab which correspond to all real mode operations. The parameters ! 3504: have the same meaning as similarly named ones for the `init_libfuncs' ! 3505: routine. (See above). */ ! 3506: ! 3507: static void ! 3508: init_floating_libfuncs (optable, opname, suffix) ! 3509: register optab optable; ! 3510: register char *opname; ! 3511: register char suffix; ! 3512: { ! 3513: init_libfuncs (optable, SFmode, TFmode, opname, suffix); ! 3514: } ! 3515: ! 3516: /* Initialize the libfunc fields of an entire group of entries in some ! 3517: optab which correspond to all complex floating modes. The parameters ! 3518: have the same meaning as similarly named ones for the `init_libfuncs' ! 3519: routine. (See above). */ ! 3520: ! 3521: static void ! 3522: init_complex_libfuncs (optable, opname, suffix) ! 3523: register optab optable; ! 3524: register char *opname; ! 3525: register char suffix; ! 3526: { ! 3527: init_libfuncs (optable, SCmode, TCmode, opname, suffix); ! 3528: } ! 3529: ! 3530: /* Call this once to initialize the contents of the optabs ! 3531: appropriately for the current target machine. */ ! 3532: ! 3533: void ! 3534: init_optabs () ! 3535: { ! 3536: int i, j; ! 3537: enum insn_code *p; ! 3538: ! 3539: /* Start by initializing all tables to contain CODE_FOR_nothing. */ ! 3540: ! 3541: for (p = fixtab[0][0]; ! 3542: p < fixtab[0][0] + sizeof fixtab / sizeof (fixtab[0][0][0]); ! 3543: p++) ! 3544: *p = CODE_FOR_nothing; ! 3545: ! 3546: for (p = fixtrunctab[0][0]; ! 3547: p < fixtrunctab[0][0] + sizeof fixtrunctab / sizeof (fixtrunctab[0][0][0]); ! 3548: p++) ! 3549: *p = CODE_FOR_nothing; ! 3550: ! 3551: for (p = floattab[0][0]; ! 3552: p < floattab[0][0] + sizeof floattab / sizeof (floattab[0][0][0]); ! 3553: p++) ! 3554: *p = CODE_FOR_nothing; ! 3555: ! 3556: for (p = extendtab[0][0]; ! 3557: p < extendtab[0][0] + sizeof extendtab / sizeof extendtab[0][0][0]; ! 3558: p++) ! 3559: *p = CODE_FOR_nothing; ! 3560: ! 3561: for (i = 0; i < NUM_RTX_CODE; i++) ! 3562: setcc_gen_code[i] = CODE_FOR_nothing; ! 3563: ! 3564: add_optab = init_optab (PLUS); ! 3565: sub_optab = init_optab (MINUS); ! 3566: smul_optab = init_optab (MULT); ! 3567: smul_widen_optab = init_optab (UNKNOWN); ! 3568: umul_widen_optab = init_optab (UNKNOWN); ! 3569: sdiv_optab = init_optab (DIV); ! 3570: sdivmod_optab = init_optab (UNKNOWN); ! 3571: udiv_optab = init_optab (UDIV); ! 3572: udivmod_optab = init_optab (UNKNOWN); ! 3573: smod_optab = init_optab (MOD); ! 3574: umod_optab = init_optab (UMOD); ! 3575: flodiv_optab = init_optab (DIV); ! 3576: ftrunc_optab = init_optab (UNKNOWN); ! 3577: and_optab = init_optab (AND); ! 3578: ior_optab = init_optab (IOR); ! 3579: xor_optab = init_optab (XOR); ! 3580: ashl_optab = init_optab (ASHIFT); ! 3581: ashr_optab = init_optab (ASHIFTRT); ! 3582: lshr_optab = init_optab (LSHIFTRT); ! 3583: rotl_optab = init_optab (ROTATE); ! 3584: rotr_optab = init_optab (ROTATERT); ! 3585: smin_optab = init_optab (SMIN); ! 3586: smax_optab = init_optab (SMAX); ! 3587: umin_optab = init_optab (UMIN); ! 3588: umax_optab = init_optab (UMAX); ! 3589: mov_optab = init_optab (UNKNOWN); ! 3590: movstrict_optab = init_optab (UNKNOWN); ! 3591: cmp_optab = init_optab (UNKNOWN); ! 3592: ucmp_optab = init_optab (UNKNOWN); ! 3593: tst_optab = init_optab (UNKNOWN); ! 3594: neg_optab = init_optab (NEG); ! 3595: abs_optab = init_optab (ABS); ! 3596: one_cmpl_optab = init_optab (NOT); ! 3597: ffs_optab = init_optab (FFS); ! 3598: sqrt_optab = init_optab (SQRT); ! 3599: sin_optab = init_optab (UNKNOWN); ! 3600: cos_optab = init_optab (UNKNOWN); ! 3601: strlen_optab = init_optab (UNKNOWN); ! 3602: ! 3603: for (i = 0; i < NUM_MACHINE_MODES; i++) ! 3604: { ! 3605: movstr_optab[i] = CODE_FOR_nothing; ! 3606: ! 3607: #ifdef HAVE_SECONDARY_RELOADS ! 3608: reload_in_optab[i] = reload_out_optab[i] = CODE_FOR_nothing; ! 3609: #endif ! 3610: } ! 3611: ! 3612: /* Fill in the optabs with the insns we support. */ ! 3613: init_all_optabs (); ! 3614: ! 3615: #ifdef FIXUNS_TRUNC_LIKE_FIX_TRUNC ! 3616: /* This flag says the same insns that convert to a signed fixnum ! 3617: also convert validly to an unsigned one. */ ! 3618: for (i = 0; i < NUM_MACHINE_MODES; i++) ! 3619: for (j = 0; j < NUM_MACHINE_MODES; j++) ! 3620: fixtrunctab[i][j][1] = fixtrunctab[i][j][0]; ! 3621: #endif ! 3622: ! 3623: #ifdef EXTRA_CC_MODES ! 3624: init_mov_optab (); ! 3625: #endif ! 3626: ! 3627: /* Initialize the optabs with the names of the library functions. */ ! 3628: init_integral_libfuncs (add_optab, "add", '3'); ! 3629: init_floating_libfuncs (add_optab, "add", '3'); ! 3630: init_integral_libfuncs (sub_optab, "sub", '3'); ! 3631: init_floating_libfuncs (sub_optab, "sub", '3'); ! 3632: init_integral_libfuncs (smul_optab, "mul", '3'); ! 3633: init_floating_libfuncs (smul_optab, "mul", '3'); ! 3634: init_integral_libfuncs (sdiv_optab, "div", '3'); ! 3635: init_integral_libfuncs (udiv_optab, "udiv", '3'); ! 3636: init_integral_libfuncs (sdivmod_optab, "divmod", '4'); ! 3637: init_integral_libfuncs (udivmod_optab, "udivmod", '4'); ! 3638: init_integral_libfuncs (smod_optab, "mod", '3'); ! 3639: init_integral_libfuncs (umod_optab, "umod", '3'); ! 3640: init_floating_libfuncs (flodiv_optab, "div", '3'); ! 3641: init_floating_libfuncs (ftrunc_optab, "ftrunc", '2'); ! 3642: init_integral_libfuncs (and_optab, "and", '3'); ! 3643: init_integral_libfuncs (ior_optab, "ior", '3'); ! 3644: init_integral_libfuncs (xor_optab, "xor", '3'); ! 3645: init_integral_libfuncs (ashl_optab, "ashl", '3'); ! 3646: init_integral_libfuncs (ashr_optab, "ashr", '3'); ! 3647: init_integral_libfuncs (lshr_optab, "lshr", '3'); ! 3648: init_integral_libfuncs (rotl_optab, "rotl", '3'); ! 3649: init_integral_libfuncs (rotr_optab, "rotr", '3'); ! 3650: init_integral_libfuncs (smin_optab, "min", '3'); ! 3651: init_floating_libfuncs (smin_optab, "min", '3'); ! 3652: init_integral_libfuncs (smax_optab, "max", '3'); ! 3653: init_floating_libfuncs (smax_optab, "max", '3'); ! 3654: init_integral_libfuncs (umin_optab, "umin", '3'); ! 3655: init_integral_libfuncs (umax_optab, "umax", '3'); ! 3656: init_integral_libfuncs (neg_optab, "neg", '2'); ! 3657: init_floating_libfuncs (neg_optab, "neg", '2'); ! 3658: init_integral_libfuncs (one_cmpl_optab, "one_cmpl", '2'); ! 3659: init_integral_libfuncs (ffs_optab, "ffs", '2'); ! 3660: ! 3661: /* Comparison libcalls for integers MUST come in pairs, signed/unsigned. */ ! 3662: init_integral_libfuncs (cmp_optab, "cmp", '2'); ! 3663: init_integral_libfuncs (ucmp_optab, "ucmp", '2'); ! 3664: init_floating_libfuncs (cmp_optab, "cmp", '2'); ! 3665: ! 3666: #ifdef MULSI3_LIBCALL ! 3667: smul_optab->handlers[(int) SImode].libfunc ! 3668: = gen_rtx (SYMBOL_REF, Pmode, MULSI3_LIBCALL); ! 3669: #endif ! 3670: #ifdef MULDI3_LIBCALL ! 3671: smul_optab->handlers[(int) DImode].libfunc ! 3672: = gen_rtx (SYMBOL_REF, Pmode, MULDI3_LIBCALL); ! 3673: #endif ! 3674: #ifdef MULTI3_LIBCALL ! 3675: smul_optab->handlers[(int) TImode].libfunc ! 3676: = gen_rtx (SYMBOL_REF, Pmode, MULTI3_LIBCALL); ! 3677: #endif ! 3678: ! 3679: #ifdef DIVSI3_LIBCALL ! 3680: sdiv_optab->handlers[(int) SImode].libfunc ! 3681: = gen_rtx (SYMBOL_REF, Pmode, DIVSI3_LIBCALL); ! 3682: #endif ! 3683: #ifdef DIVDI3_LIBCALL ! 3684: sdiv_optab->handlers[(int) DImode].libfunc ! 3685: = gen_rtx (SYMBOL_REF, Pmode, DIVDI3_LIBCALL); ! 3686: #endif ! 3687: #ifdef DIVTI3_LIBCALL ! 3688: sdiv_optab->handlers[(int) TImode].libfunc ! 3689: = gen_rtx (SYMBOL_REF, Pmode, DIVTI3_LIBCALL); ! 3690: #endif ! 3691: ! 3692: #ifdef UDIVSI3_LIBCALL ! 3693: udiv_optab->handlers[(int) SImode].libfunc ! 3694: = gen_rtx (SYMBOL_REF, Pmode, UDIVSI3_LIBCALL); ! 3695: #endif ! 3696: #ifdef UDIVDI3_LIBCALL ! 3697: udiv_optab->handlers[(int) DImode].libfunc ! 3698: = gen_rtx (SYMBOL_REF, Pmode, UDIVDI3_LIBCALL); ! 3699: #endif ! 3700: #ifdef UDIVTI3_LIBCALL ! 3701: udiv_optab->handlers[(int) TImode].libfunc ! 3702: = gen_rtx (SYMBOL_REF, Pmode, UDIVTI3_LIBCALL); ! 3703: #endif ! 3704: ! 3705: ! 3706: #ifdef MODSI3_LIBCALL ! 3707: smod_optab->handlers[(int) SImode].libfunc ! 3708: = gen_rtx (SYMBOL_REF, Pmode, MODSI3_LIBCALL); ! 3709: #endif ! 3710: #ifdef MODDI3_LIBCALL ! 3711: smod_optab->handlers[(int) DImode].libfunc ! 3712: = gen_rtx (SYMBOL_REF, Pmode, MODDI3_LIBCALL); ! 3713: #endif ! 3714: #ifdef MODTI3_LIBCALL ! 3715: smod_optab->handlers[(int) TImode].libfunc ! 3716: = gen_rtx (SYMBOL_REF, Pmode, MODTI3_LIBCALL); ! 3717: #endif ! 3718: ! 3719: ! 3720: #ifdef UMODSI3_LIBCALL ! 3721: umod_optab->handlers[(int) SImode].libfunc ! 3722: = gen_rtx (SYMBOL_REF, Pmode, UMODSI3_LIBCALL); ! 3723: #endif ! 3724: #ifdef UMODDI3_LIBCALL ! 3725: umod_optab->handlers[(int) DImode].libfunc ! 3726: = gen_rtx (SYMBOL_REF, Pmode, UMODDI3_LIBCALL); ! 3727: #endif ! 3728: #ifdef UMODTI3_LIBCALL ! 3729: umod_optab->handlers[(int) TImode].libfunc ! 3730: = gen_rtx (SYMBOL_REF, Pmode, UMODTI3_LIBCALL); ! 3731: #endif ! 3732: ! 3733: /* Define library calls for quad FP instructions */ ! 3734: #ifdef ADDTF3_LIBCALL ! 3735: add_optab->handlers[(int) TFmode].libfunc ! 3736: = gen_rtx (SYMBOL_REF, Pmode, ADDTF3_LIBCALL); ! 3737: #endif ! 3738: #ifdef SUBTF3_LIBCALL ! 3739: sub_optab->handlers[(int) TFmode].libfunc ! 3740: = gen_rtx (SYMBOL_REF, Pmode, SUBTF3_LIBCALL); ! 3741: #endif ! 3742: #ifdef MULTF3_LIBCALL ! 3743: smul_optab->handlers[(int) TFmode].libfunc ! 3744: = gen_rtx (SYMBOL_REF, Pmode, MULTF3_LIBCALL); ! 3745: #endif ! 3746: #ifdef DIVTF3_LIBCALL ! 3747: flodiv_optab->handlers[(int) TFmode].libfunc ! 3748: = gen_rtx (SYMBOL_REF, Pmode, DIVTF3_LIBCALL); ! 3749: #endif ! 3750: #ifdef SQRTTF2_LIBCALL ! 3751: sqrt_optab->handlers[(int) TFmode].libfunc ! 3752: = gen_rtx (SYMBOL_REF, Pmode, SQRTTF2_LIBCALL); ! 3753: #endif ! 3754: ! 3755: /* Use cabs for DC complex abs, since systems generally have cabs. ! 3756: Don't define any libcall for SCmode, so that cabs will be used. */ ! 3757: abs_optab->handlers[(int) DCmode].libfunc ! 3758: = gen_rtx (SYMBOL_REF, Pmode, "cabs"); ! 3759: ! 3760: /* The ffs function operates on `int'. */ ! 3761: #ifndef INT_TYPE_SIZE ! 3762: #define INT_TYPE_SIZE BITS_PER_WORD ! 3763: #endif ! 3764: ffs_optab->handlers[(int) mode_for_size (INT_TYPE_SIZE, MODE_INT, 0)] .libfunc ! 3765: = gen_rtx (SYMBOL_REF, Pmode, "ffs"); ! 3766: ! 3767: extendsfdf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__extendsfdf2"); ! 3768: extendsfxf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__extendsfxf2"); ! 3769: extendsftf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__extendsftf2"); ! 3770: extenddfxf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__extenddfxf2"); ! 3771: extenddftf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__extenddftf2"); ! 3772: ! 3773: truncdfsf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__truncdfsf2"); ! 3774: truncxfsf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__truncxfsf2"); ! 3775: trunctfsf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__trunctfsf2"); ! 3776: truncxfdf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__truncxfdf2"); ! 3777: trunctfdf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__trunctfdf2"); ! 3778: ! 3779: memcpy_libfunc = gen_rtx (SYMBOL_REF, Pmode, "memcpy"); ! 3780: bcopy_libfunc = gen_rtx (SYMBOL_REF, Pmode, "bcopy"); ! 3781: memcmp_libfunc = gen_rtx (SYMBOL_REF, Pmode, "memcmp"); ! 3782: bcmp_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gcc_bcmp"); ! 3783: memset_libfunc = gen_rtx (SYMBOL_REF, Pmode, "memset"); ! 3784: bzero_libfunc = gen_rtx (SYMBOL_REF, Pmode, "bzero"); ! 3785: ! 3786: eqsf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__eqsf2"); ! 3787: nesf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__nesf2"); ! 3788: gtsf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gtsf2"); ! 3789: gesf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gesf2"); ! 3790: ltsf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__ltsf2"); ! 3791: lesf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__lesf2"); ! 3792: ! 3793: eqdf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__eqdf2"); ! 3794: nedf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__nedf2"); ! 3795: gtdf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gtdf2"); ! 3796: gedf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gedf2"); ! 3797: ltdf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__ltdf2"); ! 3798: ledf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__ledf2"); ! 3799: ! 3800: eqxf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__eqxf2"); ! 3801: nexf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__nexf2"); ! 3802: gtxf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gtxf2"); ! 3803: gexf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gexf2"); ! 3804: ltxf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__ltxf2"); ! 3805: lexf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__lexf2"); ! 3806: ! 3807: eqtf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__eqtf2"); ! 3808: netf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__netf2"); ! 3809: gttf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gttf2"); ! 3810: getf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__getf2"); ! 3811: lttf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__lttf2"); ! 3812: letf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__letf2"); ! 3813: ! 3814: /* Define library calls for quad FP instructions */ ! 3815: #ifdef EQTF2_LIBCALL ! 3816: eqtf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, EQTF2_LIBCALL); ! 3817: #endif ! 3818: #ifdef NETF2_LIBCALL ! 3819: netf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, NETF2_LIBCALL); ! 3820: #endif ! 3821: #ifdef GTTF2_LIBCALL ! 3822: gttf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, GTTF2_LIBCALL); ! 3823: #endif ! 3824: #ifdef GETF2_LIBCALL ! 3825: getf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, GETF2_LIBCALL); ! 3826: #endif ! 3827: #ifdef LTTF2_LIBCALL ! 3828: lttf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, LTTF2_LIBCALL); ! 3829: #endif ! 3830: #ifdef LETF2_LIBCALL ! 3831: letf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, LETF2_LIBCALL); ! 3832: #endif ! 3833: ! 3834: floatsisf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floatsisf"); ! 3835: floatdisf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floatdisf"); ! 3836: floattisf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floattisf"); ! 3837: ! 3838: floatsidf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floatsidf"); ! 3839: floatdidf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floatdidf"); ! 3840: floattidf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floattidf"); ! 3841: ! 3842: floatsixf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floatsixf"); ! 3843: floatdixf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floatdixf"); ! 3844: floattixf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floattixf"); ! 3845: ! 3846: floatsitf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floatsitf"); ! 3847: floatditf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floatditf"); ! 3848: floattitf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floattitf"); ! 3849: ! 3850: fixsfsi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixsfsi"); ! 3851: fixsfdi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixsfdi"); ! 3852: fixsfti_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixsfti"); ! 3853: ! 3854: fixdfsi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixdfsi"); ! 3855: fixdfdi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixdfdi"); ! 3856: fixdfti_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixdfti"); ! 3857: ! 3858: fixxfsi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixxfsi"); ! 3859: fixxfdi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixxfdi"); ! 3860: fixxfti_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixxfti"); ! 3861: ! 3862: fixtfsi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixtfsi"); ! 3863: fixtfdi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixtfdi"); ! 3864: fixtfti_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixtfti"); ! 3865: ! 3866: fixunssfsi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunssfsi"); ! 3867: fixunssfdi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunssfdi"); ! 3868: fixunssfti_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunssfti"); ! 3869: ! 3870: fixunsdfsi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunsdfsi"); ! 3871: fixunsdfdi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunsdfdi"); ! 3872: fixunsdfti_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunsdfti"); ! 3873: ! 3874: fixunsxfsi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunsxfsi"); ! 3875: fixunsxfdi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunsxfdi"); ! 3876: fixunsxfti_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunsxfti"); ! 3877: ! 3878: fixunstfsi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunstfsi"); ! 3879: fixunstfdi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunstfdi"); ! 3880: fixunstfti_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunstfti"); ! 3881: ! 3882: /* Define library calls for quad FP instructions */ ! 3883: #ifdef TRUNCTFSF2_LIBCALL ! 3884: trunctfsf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, TRUNCTFSF2_LIBCALL); ! 3885: #endif ! 3886: #ifdef TRUNCTFDF2_LIBCALL ! 3887: trunctfdf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, TRUNCTFDF2_LIBCALL); ! 3888: #endif ! 3889: #ifdef EXTENDSFTF2_LIBCALL ! 3890: extendsftf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, EXTENDSFTF2_LIBCALL); ! 3891: #endif ! 3892: #ifdef EXTENDDFTF2_LIBCALL ! 3893: extenddftf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, EXTENDDFTF2_LIBCALL); ! 3894: #endif ! 3895: #ifdef FLOATSITF2_LIBCALL ! 3896: floatsitf_libfunc = gen_rtx (SYMBOL_REF, Pmode, FLOATSITF2_LIBCALL); ! 3897: #endif ! 3898: #ifdef FIX_TRUNCTFSI2_LIBCALL ! 3899: fixtfsi_libfunc = gen_rtx (SYMBOL_REF, Pmode, FIX_TRUNCTFSI2_LIBCALL); ! 3900: #endif ! 3901: #ifdef FIXUNS_TRUNCTFSI2_LIBCALL ! 3902: fixunstfsi_libfunc = gen_rtx (SYMBOL_REF, Pmode, FIXUNS_TRUNCTFSI2_LIBCALL); ! 3903: #endif ! 3904: } ! 3905: ! 3906: #ifdef BROKEN_LDEXP ! 3907: ! 3908: /* SCO 3.2 apparently has a broken ldexp. */ ! 3909: ! 3910: double ! 3911: ldexp(x,n) ! 3912: double x; ! 3913: int n; ! 3914: { ! 3915: if (n > 0) ! 3916: while (n--) ! 3917: x *= 2; ! 3918: ! 3919: return x; ! 3920: } ! 3921: #endif /* BROKEN_LDEXP */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.