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