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