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