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