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