Annotation of GNUtools/cc/fsf-optabs.c, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.