|
|
1.1 root 1: /* Convert tree expression to rtl instructions, for GNU compiler.
2: Copyright (C) 1987 Free Software Foundation, Inc.
3:
4: This file is part of GNU CC.
5:
6: GNU CC is distributed in the hope that it will be useful,
7: but WITHOUT ANY WARRANTY. No author or distributor
8: accepts responsibility to anyone for the consequences of using it
9: or for whether it serves any particular purpose or works at all,
10: unless he says so in writing. Refer to the GNU CC General Public
11: License for full details.
12:
13: Everyone is granted permission to copy, modify and redistribute
14: GNU CC, but only under the conditions described in the
15: GNU CC General Public License. A copy of this license is
16: supposed to have been given to you along with GNU CC so you
17: can know your rights and responsibilities. It should be in a
18: file named COPYING. Among other things, the copyright notice
19: and this notice must be preserved on all copies. */
20:
21:
22: #include "config.h"
23: #include "rtl.h"
24: #include "tree.h"
25: #include "insn-flags.h"
26: #include "insn-codes.h"
27: #include "expr.h"
28:
29: /* If this is nonzero, we do not bother generating VOLATILE
30: around volatile memory references, and we are willing to
31: output indirect addresses. If cse is to follow, we reject
32: indirect addresses so a useful potential cse is generated;
33: if it is used only once, instruction combination will produce
34: the same indirect address eventually. */
35: int cse_not_expected;
36:
37: /* Nonzero to generate code for all the subroutines within an
38: expression before generating the upper levels of the expression.
39: Nowadays this is never zero. */
40: int do_preexpand_calls = 1;
41:
42: /* Number of units that we should eventually pop off the stack.
43: These are the arguments to function calls that have already returned. */
44: int pending_stack_adjust;
45:
46: /* Total size of arguments already pushed for function calls that
47: have not happened yet. Also counts 1 for each level of conditional
48: expression that we are inside. When this is nonzero,
49: args passed to function calls must be popped right away
50: to ensure contiguity of argument lists for future calls. */
51: int current_args_size;
52:
53: static rtx store_expr ();
54: static rtx expand_call ();
55: static void gen_call_1 ();
56: static rtx compare ();
57: static rtx compare1 ();
58: static rtx do_store_flag ();
59: static void preexpand_calls ();
60:
61: /* MOVE_RATIO is the number of move instructions that is better than
62: a block move. */
63:
64: #if defined (HAVE_movstrhi) || defined (HAVE_movstrsi)
65: #define MOVE_RATIO 2
66: #else
67: #define MOVE_RATIO 6
68: #endif
69:
70: /* Table indexed by tree code giving 1 if the code is for a
71: comparison operation, or anything that is most easily
72: computed with a conditional branch.
73:
74: We include tree.def to give it the proper length.
75: The contents thus created are irrelevant.
76: The real contents are initialized in init_comparisons. */
77:
78: #define DEFTREECODE(SYM, NAME, TYPE, LENGTH) LENGTH,
79:
80: static char comparison_code[] = {
81: #include "tree.def"
82: };
83: #undef DEFTREECODE
84:
85: init_comparisons ()
86: {
87:
88: bzero (comparison_code, sizeof comparison_code);
89: comparison_code[(int) EQ_EXPR] = 1;
90: comparison_code[(int) NE_EXPR] = 1;
91: comparison_code[(int) LT_EXPR] = 1;
92: comparison_code[(int) GT_EXPR] = 1;
93: comparison_code[(int) LE_EXPR] = 1;
94: comparison_code[(int) GE_EXPR] = 1;
95: }
96:
97: /* Manage the queue of increment instructions to be output
98: for POSTINCREMENT_EXPR expressions, etc. */
99:
100: static rtx pending_chain;
101:
102: /* Queue up to increment (or change) VAR later. BODY says how:
103: BODY should be the same thing you would pass to emit_insn
104: to increment right away. It will go to emit_insn later on.
105:
106: The value is a QUEUED expression to be used in place of VAR
107: where you want to guarantee the pre-incrementation value of VAR.
108:
109: When constructing BODY, you should pass VAR through copy_rtx
110: each time it is used. If VAR is a MEM, this prevents BODY from
111: sharing structure incorrectly with itself or with places that
112: explicitly use VAR. */
113:
114: static rtx
115: enqueue_insn (var, body)
116: rtx var, body;
117: {
118: pending_chain = gen_rtx (QUEUED, GET_MODE (var),
119: var, 0, 0, body, pending_chain);
120: return pending_chain;
121: }
122:
123: /* Use protect_from_queue to convert a QUEUED expression
124: into something that you can put immediately into an instruction.
125: If the queued incrementation has not happened yet,
126: protect_from_queue returns the variable itself.
127: If the incrementation has happened, protect_from_queue returns a temp
128: that contains a copy of the old value of the variable.
129:
130: Any time an rtx which might possibly be a QUEUED is to be put
131: into an instruction, it must be passed through protect_from_queue first.
132: QUEUED expressions are not meaningful in instructions.
133:
134: Do not pass a value through protect_from_queue and then hold
135: on to it for a while before putting it in an instruction!
136: If the queue is flushed in between, incorrect code will result. */
137:
138: rtx
139: protect_from_queue (x, modify)
140: register rtx x;
141: int modify;
142: {
143: register RTX_CODE code = GET_CODE (x);
144: if (code != QUEUED)
145: {
146: /* A special hack for read access to (MEM (QUEUED ...))
147: to facilitate use of autoincrement.
148: Make a copy of the contents of the memory location
149: rather than a copy of the address. */
150: if (code == MEM && GET_CODE (XEXP (x, 0)) == QUEUED && !modify)
151: {
152: register rtx y = XEXP (x, 0);
153: XEXP (x, 0) = QUEUED_VAR (y);
154: if (QUEUED_INSN (y))
155: {
156: register rtx temp = gen_reg_rtx (GET_MODE (x));
157: emit_insn_before (gen_move_insn (temp, x),
158: QUEUED_INSN (y));
159: return temp;
160: }
161: return x;
162: }
163: /* Otherwise, recursively protect the subexpressions of all
164: the kinds of rtx's that can contain a QUEUED. */
165: if (code == MEM)
166: XEXP (x, 0) = protect_from_queue (XEXP (x, 0), 0);
167: else if (code == PLUS || code == MULT)
168: {
169: XEXP (x, 0) = protect_from_queue (XEXP (x, 0), 0);
170: XEXP (x, 1) = protect_from_queue (XEXP (x, 1), 0);
171: }
172: return x;
173: }
174: /* If the increment has not happened, use the variable itself. */
175: if (QUEUED_INSN (x) == 0)
176: return QUEUED_VAR (x);
177: /* If the increment has happened and a pre-increment copy exists,
178: use that copy. */
179: if (QUEUED_COPY (x) != 0)
180: return QUEUED_COPY (x);
181: /* The increment has happened but we haven't set up a pre-increment copy.
182: Set one up now, and use it. */
183: QUEUED_COPY (x) = gen_reg_rtx (GET_MODE (QUEUED_VAR (x)));
184: emit_insn_before (gen_move_insn (QUEUED_COPY (x), QUEUED_VAR (x)),
185: QUEUED_INSN (x));
186: return QUEUED_COPY (x);
187: }
188:
189: /* perform all the pending incrementations. */
190:
191: void
192: emit_queue ()
193: {
194: register rtx p;
195: while (p = pending_chain)
196: {
197: QUEUED_INSN (p) = emit_insn (QUEUED_BODY (p));
198: pending_chain = QUEUED_NEXT (p);
199: }
200: }
201:
202: void
203: init_queue ()
204: {
205: if (pending_chain)
206: abort ();
207: }
208:
209: /* Copy data from FROM to TO, where the machine modes are not the same.
210: Both modes may be integer, or both may be floating.
211: UNSIGNEDP should be nonzero if FROM is an unsigned type.
212: This causes zero-extension instead of sign-extension. */
213:
214: void
215: convert_move (to, from, unsignedp)
216: register rtx to, from;
217: int unsignedp;
218: {
219: enum machine_mode to_mode = GET_MODE (to);
220: enum machine_mode from_mode = GET_MODE (from);
221: int to_real = to_mode == SFmode || to_mode == DFmode;
222: int from_real = from_mode == SFmode || from_mode == DFmode;
223: int extending = (int) to_mode > (int) from_mode;
224:
225: to = protect_from_queue (to, 1);
226: from = protect_from_queue (from, 0);
227:
228: if (to_real != from_real)
229: abort ();
230:
231: if (to_mode == from_mode || GET_CODE (from) == CONST_INT)
232: {
233: emit_move_insn (to, from);
234: return;
235: }
236:
237: if (to_real)
238: {
239: #ifdef HAVE_extendsfdf2
240: if (HAVE_extendsfdf2 && extending)
241: {
242: emit_insn (gen_extendsfdf2 (to, from));
243: return;
244: }
245: #endif
246: #ifdef HAVE_truncdfsf2
247: if (HAVE_truncdfsf2 && ! extending)
248: {
249: emit_insn (gen_truncdfsf2 (to, from));
250: return;
251: }
252: #endif
253: emit_library_call (gen_rtx (SYMBOL_REF, Pmode, (extending
254: ? "extendsfdf2"
255: : "truncdfsf2")),
256: 1, from, (extending ? SFmode : DFmode));
257: copy_function_value (to);
258: return;
259: }
260:
261: if (to_mode == DImode)
262: {
263: emit_insn (gen_rtx (CLOBBER, VOIDmode, to));
264:
265: if (unsignedp)
266: {
267: convert_move (gen_lowpart (SImode, to), from, unsignedp);
268: emit_clr_insn (gen_highpart (SImode, to));
269: }
270: #ifdef HAVE_sltsi
271: else if (HAVE_sltsi)
272: {
273: convert_move (gen_lowpart (SImode, to), from, unsignedp);
274: emit_insn (gen_sltsi (gen_highpart (SImode, to)));
275: }
276: #endif
277: else
278: {
279: register rtx label = gen_label_rtx ();
280:
281: emit_clr_insn (gen_highpart (SImode, to));
282: convert_move (gen_lowpart (SImode, to), from, unsignedp);
283: emit_cmp_insn (gen_lowpart (SImode, to),
284: gen_rtx (CONST_INT, VOIDmode, 0),
285: 0, 0);
286: emit_jump_insn (gen_bge (label));
287: expand_unop (SImode, one_cmpl_optab,
288: gen_highpart (SImode, to), gen_highpart (SImode, to),
289: 1);
290: emit_label (label);
291: }
292: return;
293: }
294:
295: if (from_mode == DImode)
296: {
297: convert_move (to, gen_lowpart (SImode, from), 0);
298: return;
299: }
300:
301: /* Now follow all the conversions between integers
302: no more than a word long. */
303:
304: if (to_mode == SImode && from_mode == HImode)
305: {
306: if (unsignedp)
307: {
308: #ifdef HAVE_zero_extendhisi2
309: if (HAVE_zero_extendhisi2)
310: emit_insn (gen_zero_extendhisi2 (to, from));
311: else
312: #endif
313: abort ();
314: }
315: else
316: {
317: #ifdef HAVE_extendhisi2
318: if (HAVE_extendhisi2)
319: emit_insn (gen_extendhisi2 (to, from));
320: else
321: #endif
322: abort ();
323: }
324: return;
325: }
326:
327: if (to_mode == SImode && from_mode == QImode)
328: {
329: if (unsignedp)
330: {
331: #ifdef HAVE_zero_extendqisi2
332: if (HAVE_zero_extendqisi2)
333: {
334: emit_insn (gen_zero_extendqisi2 (to, from));
335: return;
336: }
337: #endif
338: #if defined (HAVE_zero_extendqihi2) && defined (HAVE_extendhisi2)
339: if (HAVE_zero_extendqihi2 && HAVE_extendhisi2)
340: {
341: register rtx temp = gen_reg_rtx (HImode);
342: emit_insn (gen_zero_extendqihi2 (temp, from));
343: emit_insn (gen_extendhisi2 (to, temp));
344: return;
345: }
346: #endif
347: }
348: else
349: {
350: #ifdef HAVE_extendqisi2
351: if (HAVE_extendqisi2)
352: {
353: emit_insn (gen_extendqisi2 (to, from));
354: return;
355: }
356: #endif
357: #if defined (HAVE_extendqihi2) && defined (HAVE_extendhisi2)
358: if (HAVE_extendqihi2 && HAVE_extendhisi2)
359: {
360: register rtx temp = gen_reg_rtx (HImode);
361: emit_insn (gen_extendqihi2 (temp, from));
362: emit_insn (gen_extendhisi2 (to, temp));
363: return;
364: }
365: #endif
366: }
367: abort ();
368: }
369:
370: if (to_mode == HImode && from_mode == QImode)
371: {
372: if (unsignedp)
373: {
374: #ifdef HAVE_zero_extendqihi2
375: if (HAVE_zero_extendqihi2)
376: {
377: emit_insn (gen_zero_extendqihi2 (to, from));
378: return;
379: }
380: #endif
381: }
382: else
383: {
384: #ifdef HAVE_extendqihi2
385: if (HAVE_extendqihi2)
386: {
387: emit_insn (gen_extendqihi2 (to, from));
388: return;
389: }
390: #endif
391: }
392: abort ();
393: }
394:
395: /* Now we are truncating an integer to a smaller one.
396: If the result is a temporary, we might as well just copy it,
397: since only the low-order part of the result needs to be valid
398: and it is valid with no change. */
399:
400: if (GET_CODE (to) == REG)
401: {
402: if (GET_CODE (from) == REG)
403: {
404: emit_move_insn (to, gen_lowpart (GET_MODE (to), from));
405: return;
406: }
407: #ifndef BYTES_BIG_ENDIAN
408: else if (GET_CODE (from) == MEM)
409: {
410: register rtx addr = XEXP (from, 0);
411: GO_IF_LEGITIMATE_ADDRESS (GET_MODE (to), addr, win);
412: if (0)
413: {
414: win:
415: emit_move_insn (to, gen_rtx (MEM, GET_MODE (to), addr));
416: return;
417: }
418: }
419: #endif /* not BYTES_BIG_ENDIAN */
420: }
421:
422: if (from_mode == SImode && to_mode == HImode)
423: {
424: #ifdef HAVE_truncsihi2
425: if (HAVE_truncsihi2)
426: {
427: emit_insn (gen_truncsihi2 (to, from));
428: return;
429: }
430: #endif
431: abort ();
432: }
433:
434: if (from_mode == SImode && to_mode == QImode)
435: {
436: #ifdef HAVE_truncsiqi2
437: if (HAVE_truncsiqi2)
438: {
439: emit_insn (gen_truncsiqi2 (to, from));
440: return;
441: }
442: #endif
443: abort ();
444: }
445:
446: if (from_mode == HImode && to_mode == QImode)
447: {
448: #ifdef HAVE_trunchiqi2
449: if (HAVE_trunchiqi2)
450: {
451: emit_insn (gen_trunchiqi2 (to, from));
452: return;
453: }
454: #endif
455: abort ();
456: }
457: }
458:
459: /* Return an rtx for a value that would result
460: from converting X to mode MODE.
461: Both X and MODE may be floating, or both integer.
462: UNSIGNEDP is nonzero if X is an unsigned value.
463: This can be done by referring to a part of X in place
464: or by copying to a new temporary with conversion. */
465:
466: rtx
467: convert_to_mode (mode, x, unsignedp)
468: enum machine_mode mode;
469: rtx x;
470: int unsignedp;
471: {
472: register rtx temp;
473: if (mode == GET_MODE (x))
474: return x;
475: if (GET_MODE_SIZE (mode) <= GET_MODE_SIZE (GET_MODE (x)))
476: return gen_lowpart (mode, x);
477: temp = gen_reg_rtx (mode);
478: convert_move (temp, x, unsignedp);
479: return temp;
480: }
481:
482: /* Generate several move instructions to copy LEN bytes
483: from address FROM to address TO. The caller must pass FROM and TO
484: through protect_from_queue before calling.
485: FROM_VOL and TO_VOL are nonzero if references to
486: FROM and TO, respectively, should be marked VOLATILE.
487: ALIGN (in bytes) is maximum alignment we can assume. */
488:
489: struct move_by_pieces
490: {
491: rtx to;
492: int autinc_to;
493: int explicit_inc_to;
494: int to_vol;
495: rtx from;
496: int autinc_from;
497: int explicit_inc_from;
498: int from_vol;
499: int len;
500: int offset;
501: int reverse;
502: };
503:
504: static void
505: move_by_pieces (to, from, len, align, to_vol, from_vol)
506: rtx to, from;
507: int len, align;
508: int to_vol, from_vol;
509: {
510: struct move_by_pieces data;
511:
512: data.offset = 0;
513: data.to = to;
514: data.from = from;
515: data.to_vol = to_vol;
516: data.from_vol = from_vol;
517: data.autinc_to = (GET_CODE (to) == PRE_INC || GET_CODE (to) == PRE_DEC
518: || GET_CODE (to) == POST_INC || GET_CODE (to) == POST_DEC);
519: data.autinc_from = (GET_CODE (from) == PRE_INC || GET_CODE (from) == PRE_DEC
520: || GET_CODE (from) == POST_INC
521: || GET_CODE (from) == POST_DEC);
522:
523: data.explicit_inc_from = 0;
524: data.explicit_inc_to = 0;
525: data.reverse = (GET_CODE (to) == PRE_DEC || GET_CODE (to) == POST_DEC);
526: if (data.reverse) data.offset = len;
527: data.len = len;
528:
529: /* If copying requires more than two move insns,
530: copy addresses to registers (to make displacements shorter)
531: and use post-increment if available. */
532: if (!(data.autinc_from && data.autinc_to)
533: && move_by_pieces_ninsns (len, align) > 2)
534: {
535: #ifdef HAVE_PRE_DECREMENT
536: if (data.reverse && ! data.autinc_from)
537: {
538: data.from = copy_to_reg (plus_constant (from, len));
539: data.autinc_from = 1;
540: data.explicit_inc_from = -1;
541: }
542: #endif
543: #ifdef HAVE_POST_INCREMENT
544: if (! data.autinc_from)
545: {
546: data.from = copy_to_reg (from);
547: data.autinc_from = 1;
548: data.explicit_inc_from = 1;
549: }
550: #endif
551: if (!data.autinc_from && CONSTANT_ADDRESS_P (from))
552: data.from = copy_to_reg (from);
553: #ifdef HAVE_PRE_DECREMENT
554: if (data.reverse && ! data.autinc_to)
555: {
556: data.to = copy_to_reg (plus_constant (to, len));
557: data.autinc_to = 1;
558: data.explicit_inc_to = -1;
559: }
560: #endif
561: #ifdef HAVE_POST_INCREMENT
562: if (! data.reverse && ! data.autinc_to)
563: {
564: data.to = copy_to_reg (to);
565: data.autinc_to = 1;
566: data.explicit_inc_to = 1;
567: }
568: #endif
569: if (!data.autinc_to && CONSTANT_ADDRESS_P (to))
570: data.to = copy_to_reg (to);
571: }
572:
573: #ifdef STRICT_ALIGNMENT
574: if (align > MOVE_MAX)
575: align = MOVE_MAX;
576: #else
577: align = MOVE_MAX;
578: #endif
579:
580: #ifdef HAVE_movti
581: if (HAVE_movti && align >= GET_MODE_SIZE (TImode))
582: move_by_pieces_1 (gen_movti, TImode, &data);
583: #endif
584: #ifdef HAVE_movdi
585: if (HAVE_movdi && align >= GET_MODE_SIZE (DImode))
586: move_by_pieces_1 (gen_movdi, DImode, &data);
587: #endif
588: if (align >= GET_MODE_SIZE (SImode))
589: move_by_pieces_1 (gen_movsi, SImode, &data);
590: if (align >= GET_MODE_SIZE (HImode))
591: move_by_pieces_1 (gen_movhi, HImode, &data);
592: move_by_pieces_1 (gen_movqi, QImode, &data);
593: }
594:
595: /* Return number of insns required to move L bytes by pieces.
596: ALIGN (in bytes) is maximum alignment we can assume. */
597:
598: int
599: move_by_pieces_ninsns (l, align)
600: unsigned int l;
601: int align;
602: {
603: register int n_insns = 0;
604:
605: #ifdef STRICT_ALIGNMENT
606: if (align > MOVE_MAX)
607: align = MOVE_MAX;
608: #else
609: align = MOVE_MAX;
610: #endif
611:
612: #ifdef HAVE_movti
613: if (HAVE_movti && align >= GET_MODE_SIZE (TImode))
614: n_insns += l / GET_MODE_SIZE (TImode), l %= GET_MODE_SIZE (TImode);
615: #endif
616: #ifdef HAVE_movdi
617: if (HAVE_movdi && align >= GET_MODE_SIZE (DImode))
618: n_insns += l / GET_MODE_SIZE (DImode), l %= GET_MODE_SIZE (DImode);
619: #endif
620: if (HAVE_movsi && align >= GET_MODE_SIZE (SImode))
621: n_insns += l / GET_MODE_SIZE (SImode), l %= GET_MODE_SIZE (SImode);
622: if (HAVE_movhi && align >= GET_MODE_SIZE (HImode))
623: n_insns += l / GET_MODE_SIZE (HImode), l %= GET_MODE_SIZE (HImode);
624: n_insns += l;
625:
626: return n_insns;
627: }
628:
629: /* Subroutine of move_by_pieces. Move as many bytes as appropriate
630: with move instructions for mode MODE. GENFUN is the gen_... function
631: to make a move insn for that mode. DATA has all the other info. */
632:
633: move_by_pieces_1 (genfun, mode, data)
634: rtx (*genfun) ();
635: enum machine_mode mode;
636: struct move_by_pieces *data;
637: {
638: register int size = GET_MODE_SIZE (mode);
639: register rtx to1, from1;
640:
641: #define add_offset(FLAG,X) (FLAG ? (X) : plus_constant (X, data->offset))
642:
643: while (data->len >= size)
644: {
645: to1 = gen_rtx (MEM, mode, add_offset (data->autinc_to, data->to));
646: from1 = gen_rtx (MEM, mode, add_offset (data->autinc_from, data->from));
647:
648: if (data->to_vol) to1 = gen_rtx (VOLATILE, mode, to1);
649: if (data->from_vol) from1 = gen_rtx (VOLATILE, mode, from1);
650:
651: if (data->reverse) data->offset -= size;
652: #ifdef HAVE_PRE_DECREMENT
653: if (data->explicit_inc_to < 0)
654: emit_insn (gen_sub2_insn (data->to,
655: gen_rtx (CONST_INT, VOIDmode, size)));
656: if (data->explicit_inc_from < 0)
657: emit_insn (gen_sub2_insn (data->from,
658: gen_rtx (CONST_INT, VOIDmode, size)));
659: #endif
660:
661: emit_insn (genfun (to1, from1));
662: #ifdef HAVE_POST_INCREMENT
663: if (data->explicit_inc_to > 0)
664: emit_insn (gen_add2_insn (data->to,
665: gen_rtx (CONST_INT, VOIDmode, size)));
666: if (data->explicit_inc_from > 0)
667: emit_insn (gen_add2_insn (data->from,
668: gen_rtx (CONST_INT, VOIDmode, size)));
669: #endif
670:
671: if (! data->reverse) data->offset += size;
672: data->len -= size;
673: }
674: }
675:
676: /* Emit code to move a block Y to a block X.
677: This may be done with string-move instructions,
678: with multiple scalar move instructions, or with a library call.
679:
680: Both X and Y must be MEM rtx's (perhaps inside VOLATILE)
681: with mode BLKmode.
682: SIZE is an rtx that says how long they are.
683: ALIGN is the maximum alignment we can assume they have,
684: measured in bytes. */
685:
686: static void
687: emit_block_move (x, y, size, align)
688: rtx x, y;
689: rtx size;
690: int align;
691: {
692:
693: register int max_step;
694: rtx xinner, yinner;
695: int xvolatile = 0, yvolatile = 0;
696:
697: if (GET_MODE (x) != BLKmode)
698: abort ();
699:
700: if (GET_MODE (y) != BLKmode)
701: abort ();
702:
703: x = protect_from_queue (x, 1);
704: y = protect_from_queue (y, 0);
705:
706: xinner = x, yinner = y;
707:
708: if (GET_CODE (x) == VOLATILE)
709: xvolatile = 1, xinner = XEXP (x, 0);
710: if (GET_CODE (y) == VOLATILE)
711: yvolatile = 1, yinner = XEXP (y, 0);
712:
713: if (GET_CODE (xinner) != MEM)
714: abort ();
715: if (GET_CODE (yinner) != MEM)
716: abort ();
717: if (size == 0)
718: abort ();
719:
720: if (GET_CODE (size) == CONST_INT
721: && (move_by_pieces_ninsns ((unsigned) INTVAL (size), align)
722: < MOVE_RATIO))
723: move_by_pieces (XEXP (xinner, 0), XEXP (yinner, 0),
724: INTVAL (size), align,
725: xvolatile, yvolatile);
726: else
727: {
728: #ifdef HAVE_movstrsi
729: if (HAVE_movstrsi)
730: {
731: emit_insn (gen_movstrsi (x, y, size));
732: return;
733: }
734: #endif
735: #ifdef HAVE_movstrhi
736: if (HAVE_movstrhi
737: && GET_CODE (size) == CONST_INT
738: && ((unsigned) INTVAL (size)
739: < (1 << (GET_MODE_SIZE (HImode) * BITS_PER_UNIT - 1))))
740: {
741: emit_insn (gen_movstrhi (x, y, size));
742: return;
743: }
744: #endif
745: emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "bcopy"),
746: 3, XEXP (yinner, 0), Pmode,
747: XEXP (xinner, 0), Pmode,
748: size, Pmode);
749: }
750: }
751:
752: /* Generate code to copy Y into X.
753: Both Y and X must have the same mode, except that
754: Y can be a constant with VOIDmode.
755: This mode cannot be BLKmode; use emit_block_move for that. */
756:
757: emit_move_insn (x, y)
758: rtx x, y;
759: {
760: enum machine_mode mode = GET_MODE (x);
761: x = protect_from_queue (x, 1);
762: y = protect_from_queue (y, 0);
763:
764: if (mode == BLKmode)
765: abort ();
766: if (mov_optab[(int) mode].insn_code != CODE_FOR_nothing)
767: emit_insn (GEN_FCN (mov_optab[(int) mode].insn_code) (x, y));
768: else if (GET_MODE_SIZE (mode) >= GET_MODE_SIZE (SImode))
769: {
770: register int count = GET_MODE_SIZE (mode) / GET_MODE_SIZE (SImode);
771: register int i;
772: for (i = 0; i < count; i++)
773: {
774: rtx x1, y1;
775: if (GET_CODE (x) == REG)
776: x1 = gen_rtx (SUBREG, SImode, x, i);
777: else
778: x1 = gen_rtx (MEM, SImode,
779: memory_address (SImode,
780: plus_constant (XEXP (x, 0),
781: i * GET_MODE_SIZE (SImode))));
782: if (GET_CODE (y) == REG)
783: y1 = gen_rtx (SUBREG, SImode, y, i);
784: else
785: y1 = gen_rtx (MEM, SImode,
786: memory_address (SImode,
787: plus_constant (XEXP (y, 0),
788: i * GET_MODE_SIZE (SImode))));
789: emit_insn (gen_movsi (protect_from_queue (x1, 1), protect_from_queue (y1, 0)));
790: }
791: }
792: else
793: abort ();
794: }
795:
796: /* Pushing data onto the stack. */
797:
798: /* Push a block of length SIZE (perhaps variable)
799: and return an rtx to address the beginning of the block.
800: Note that it is not possible for the value returned to be a QUEUED. */
801:
802: static rtx
803: push_block (size)
804: rtx size;
805: {
806: register rtx temp;
807: anti_adjust_stack (size);
808:
809: #ifdef STACK_GROWS_DOWNWARD
810: temp = gen_rtx (REG, Pmode, STACK_POINTER_REGNUM);
811: #else
812: temp = gen_rtx (PLUS, Pmode,
813: gen_rtx (REG, Pmode, STACK_POINTER_REGNUM),
814: size);
815: if (GET_CODE (size) != CONST_INT)
816: temp = force_operand (temp, 0);
817: #endif
818: return memory_address (QImode, temp);
819: }
820:
821: static rtx
822: gen_push_operand ()
823: {
824: return gen_rtx (
825: #ifdef STACK_GROWS_DOWNWARD
826: PRE_DEC,
827: #else
828: PRE_INC,
829: #endif
830: Pmode,
831: gen_rtx (REG, Pmode, STACK_POINTER_REGNUM));
832: }
833:
834: /* Generate code to push X onto the stack, assuming it has mode MODE.
835: MODE is redundant except when X is a CONST_INT (since they don't
836: carry mode info).
837: SIZE is an rtx for the size of data to be copied (in bytes),
838: needed only if X is BLKmode.
839: ALIGN (in bytes) is maximum alignment we can assume. */
840:
841: static void
842: emit_push_insn (x, mode, size, align)
843: register rtx x;
844: enum machine_mode mode;
845: rtx size;
846: int align;
847: {
848: rtx xinner;
849:
850: xinner = x = protect_from_queue (x, 0);
851:
852: if (GET_CODE (x) == VOLATILE)
853: xinner = XEXP (x, 0);
854:
855: if (mode == BLKmode)
856: {
857: register rtx temp;
858:
859: if (size == 0)
860: abort ();
861:
862: if (GET_CODE (size) == CONST_INT
863: && (move_by_pieces_ninsns ((unsigned) INTVAL (size), align)
864: < MOVE_RATIO))
865: move_by_pieces (gen_push_operand (),
866: XEXP (xinner, 0),
867: INTVAL (size), align,
868: 0, GET_CODE (x) == VOLATILE);
869: else
870: {
871: temp = push_block (size);
872: #ifdef HAVE_movstrsi
873: if (HAVE_movstrsi)
874: {
875: emit_insn (gen_movstrsi (gen_rtx (MEM, BLKmode, temp), x, size));
876: return;
877: }
878: #endif
879: #ifdef HAVE_movstrhi
880: if (HAVE_movstrhi
881: && GET_CODE (size) == CONST_INT
882: && ((unsigned) INTVAL (size)
883: < (1 << (GET_MODE_SIZE (HImode) * BITS_PER_UNIT - 1))))
884: {
885: emit_insn (gen_movstrhi (gen_rtx (MEM, BLKmode, temp),
886: x, size));
887: return;
888: }
889: #endif
890: /* Correct TEMP so it holds what will be a description of
891: the address to copy to, valid after one arg is pushed. */
892: #ifdef STACK_GROWS_DOWNWARD
893: temp = plus_constant (temp, GET_MODE_SIZE (Pmode));
894: #else
895: temp = plus_constant (temp, - GET_MODE_SIZE (Pmode));
896: #endif
897: emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "bcopy"),
898: 3, XEXP (xinner, 0), Pmode,
899: temp, Pmode,
900: size, Pmode);
901: }
902: }
903: else if (mov_optab[(int) mode].insn_code != CODE_FOR_nothing)
904: {
905: register rtx push = gen_rtx (MEM, mode, gen_push_operand ());
906: emit_insn (GEN_FCN (mov_optab[(int) mode].insn_code) (push, x));
907: }
908: else
909: abort ();
910: }
911:
912: /* Output a library call to function FUN (a SYMBOL_REF rtx)
913: with NARGS different arguments, passed as alternating rtx values
914: and machine_modes to convert them to.
915: The rtx values should have been passed through protect_from_queue already. */
916:
917: /*VARARGS2*/
918: void
919: emit_library_call (fun, nargs, a1)
920: rtx fun;
921: int nargs;
922: struct { rtx value; enum machine_mode mode; } a1;
923: {
924: register int args_size = 0;
925: register int argnum;
926: #ifndef STACK_GROWS_DOWNWARD
927: for (argnum = 0; argnum < nargs; argnum++)
928: #else
929: for (argnum = nargs - 1; argnum >= 0; argnum--)
930: #endif
931: {
932: register enum machine_mode mode = (&a1)[argnum].mode;
933: register rtx val = (&a1)[argnum].value;
934: /* Convert the arg value to the mode the library wants. */
935: /* ??? It is wrong to do it here; must do it earlier
936: where we know the signedness of the arg. */
937: if (GET_MODE (val) != mode && GET_MODE (val) != VOIDmode)
938: {
939: val = gen_reg_rtx (mode);
940: convert_move (val, (&a1)[argnum].value, 0);
941: }
942: emit_push_insn (val, mode, 0, 0);
943: args_size += GET_MODE_SIZE (mode);
944: current_args_size += GET_MODE_SIZE (mode);
945: }
946:
947: emit_queue ();
948: gen_call_1 (fun, 0, args_size / GET_MODE_SIZE (SImode), args_size);
949: }
950:
951: /* Expand an assignment that stores the value of FROM into TO.
952: Return an rtx for the value of TO. This may contain a QUEUED rtx. */
953:
954: rtx
955: expand_assignment (to, from)
956: tree to, from;
957: {
958: register rtx to_rtx = 0;
959:
960: /* Don't crash if the lhs of the assignment was erroneous. */
961:
962: if (TREE_CODE (to) == ERROR_MARK)
963: return expand_expr (from, 0, VOIDmode, 0);
964:
965: /* Assignment of a structure component needs special treatment
966: if the structure component's rtx is not simply a MEM. */
967:
968: if (TREE_CODE (to) == COMPONENT_REF)
969: {
970: register enum machine_mode mode1 = DECL_MODE (TREE_OPERAND (to, 1));
971: int volstruct = 0;
972:
973: /* Get the structure as an rtx. */
974:
975: to_rtx = expand_expr (TREE_OPERAND (to, 0), 0, VOIDmode, 0);
976:
977: /* If the structure is in a register or if the component
978: is a bit field, we cannot use addressing to access it.
979: Use bit-field techniques or SUBREG to store in it. */
980:
981: if (mode1 == BImode || GET_CODE (to_rtx) == REG
982: || GET_CODE (to_rtx) == SUBREG)
983: {
984: tree field = TREE_OPERAND (to, 1);
985: int bitsize = TREE_INT_CST_LOW (DECL_SIZE (field)) * DECL_SIZE_UNIT (field);
986: return store_bit_field (to_rtx, bitsize, DECL_OFFSET (field),
987: DECL_MODE (field),
988: expand_expr (from, 0, VOIDmode, 0));
989: }
990:
991: /* Get the address of the structure the component is in.
992: Record if structure is volatile. */
993:
994: if (GET_CODE (to_rtx) == VOLATILE)
995: {
996: to_rtx = XEXP (to_rtx, 0);
997: volstruct = 1;
998: }
999: if (GET_CODE (to_rtx) != MEM)
1000: abort ();
1001: to_rtx = XEXP (to_rtx, 0);
1002:
1003: /* Now build a reference to just the desired component. */
1004:
1005: to_rtx = gen_rtx (MEM, mode1,
1006: memory_address (mode1,
1007: plus_constant (to_rtx,
1008: (DECL_OFFSET
1009: (TREE_OPERAND (to, 1))
1010: / BITS_PER_UNIT))));
1011: to_rtx->in_struct = 1;
1012:
1013: /* Make component volatile if structure is. */
1014:
1015: if (! cse_not_expected && volstruct)
1016: to_rtx = gen_rtx (VOLATILE, mode1, to_rtx);
1017: }
1018:
1019: /* Arrays in registers also need special treatment. */
1020:
1021: if (TREE_CODE (to) == ARRAY_REF)
1022: {
1023: /* Check to see whether the array is in a register. */
1024: tree array = TREE_OPERAND (TREE_OPERAND (to, 0), 0);
1025: register tree temexp;
1026:
1027: /* Look through any COMPONENT_REFS to the containing struct.
1028: Start by taking the array out of the ADDR_EXPR that's operand 0. */
1029: for (temexp = array;
1030: TREE_CODE (temexp) == COMPONENT_REF;
1031: temexp = TREE_OPERAND (temexp, 0));
1032:
1033: if (TREE_CODE (TREE_OPERAND (to, 1)) == INTEGER_CST
1034: && TREE_CODE (temexp) == VAR_DECL
1035: && DECL_RTL (temexp) != 0
1036: && (GET_CODE (DECL_RTL (temexp)) == REG
1037: || GET_CODE (DECL_RTL (temexp)) == SUBREG))
1038: {
1039: /* The array or containing struct is a variable in a register
1040: and the index is constant. */
1041: int bitsize = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (to)));
1042:
1043: to_rtx = expand_expr (array, 0, VOIDmode, 0);
1044: return store_bit_field (to_rtx, bitsize,
1045: TREE_INT_CST_LOW (TREE_OPERAND (to, 1)) * bitsize,
1046: TYPE_MODE (TREE_TYPE (to)),
1047: expand_expr (from, 0, VOIDmode, 0));
1048: }
1049:
1050: /* The array is in memory. Generate the tree for *(array+index)
1051: and store into that insted. */
1052:
1053: to = build_indirect_ref (build_binary_op (PLUS_EXPR,
1054: TREE_OPERAND (to, 0),
1055: TREE_OPERAND (to, 1)));
1056: }
1057:
1058: /* Ordinary treatment. Expand TO to get a REG or MEM rtx.
1059: Don't re-expand if it was expanded already (in COMPONENT_REF case). */
1060:
1061: if (to_rtx == 0)
1062: to_rtx = expand_expr (to, 0, VOIDmode, 0);
1063:
1064: /* Compute FROM and store the value in the rtx we got. */
1065:
1066: store_expr (from, to_rtx);
1067: return to_rtx;
1068: }
1069:
1070: /* Generate code for computing expression EXP,
1071: and storing the value into TARGET. Returns TARGET.
1072: TARGET may contain a QUEUED rtx. */
1073:
1074: static rtx
1075: store_expr (exp, target)
1076: register tree exp;
1077: register rtx target;
1078: {
1079: register rtx temp = expand_expr (exp, target, GET_MODE (target), 0);
1080: if (temp != target && TREE_CODE (exp) != ERROR_MARK)
1081: {
1082: target = protect_from_queue (target, 1);
1083: if (GET_MODE (temp) != GET_MODE (target)
1084: && GET_MODE (temp) != VOIDmode)
1085: convert_move (target, temp, type_unsigned_p (TREE_TYPE (exp)));
1086: else if (GET_MODE (temp) == BLKmode)
1087: emit_block_move (target, temp, expr_size (exp),
1088: TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
1089: else
1090: emit_move_insn (target, temp);
1091: }
1092: return target;
1093: }
1094:
1095: /* Given an rtx VALUE that may contain additions and multiplications,
1096: return an equivalent value that just refers to a register or memory.
1097: This is done by generating instructions to perform the arithmetic
1098: and returning a pseudo-register containing the value. */
1099:
1100: rtx
1101: force_operand (value, target)
1102: rtx value, target;
1103: {
1104: register struct optab *binoptab = 0;
1105: register rtx op2 = XEXP (value, 1);
1106: /* Use subtarget as the target for operand 0 of a binary operation. */
1107: register rtx subtarget = (target != 0 && GET_CODE (target) == REG ? target : 0);
1108:
1109: if (GET_CODE (value) == PLUS)
1110: binoptab = add_optab;
1111: else if (GET_CODE (value) == MINUS)
1112: binoptab = sub_optab;
1113: else if (GET_CODE (value) == MULT)
1114: {
1115: if (!CONSTANT_ADDRESS_P (op2)
1116: && !(GET_CODE (op2) == REG && op2 != subtarget))
1117: subtarget = 0;
1118: return expand_mult (GET_MODE (value),
1119: force_operand (XEXP (value, 0), subtarget),
1120: force_operand (op2, 0),
1121: target, 0);
1122: }
1123:
1124: if (binoptab)
1125: {
1126: if (!CONSTANT_ADDRESS_P (op2)
1127: && !(GET_CODE (op2) == REG && op2 != subtarget))
1128: subtarget = 0;
1129: return expand_binop (GET_MODE (value), binoptab,
1130: force_operand (XEXP (value, 0), subtarget),
1131: force_operand (op2, 0),
1132: target, 0, OPTAB_LIB_WIDEN);
1133: /* We give UNSIGNEP = 0 to expand_binop
1134: because the only operations we are expanding here are signed ones. */
1135: }
1136: return value;
1137: }
1138:
1139: /* expand_expr: generate code for computing expression EXP.
1140: An rtx for the computed value is returned.
1141:
1142: The value may be stored in TARGET if TARGET is nonzero.
1143: TARGET is just a suggestion; callers must assume that
1144: the rtx returned may not be the same as TARGET.
1145:
1146: If TMODE is not VOIDmode, it suggests generating the
1147: result in mode TMODE. But this is done only when convenient.
1148: Otherwise, TMODE is ignored and the value generated in its natural mode.
1149: TMODE is just a suggestion; callers must assume that
1150: the rtx returned may not have mode TMODE.
1151:
1152: If SUM_OK is nonzero then when EXP is an addition
1153: we can return an rtx of the form (MULT (REG ...) (CONST_INT ...))
1154: or a nest of (PLUS ...) and (MINUS ...) where the terms are
1155: products as above, or REG or MEM, or constant.
1156: If SUM_OK is zero, in such cases we would output mul or add instructions
1157: and then return a pseudo reg containing the sum. */
1158:
1159: /* Subroutine of expand_expr:
1160: return the target to use when recursively expanding
1161: the first operand of an arithmetic operation. */
1162:
1163: static rtx
1164: validate_subtarget (subtarget, otherop)
1165: rtx subtarget;
1166: tree otherop;
1167: {
1168: if (TREE_LITERAL (otherop))
1169: return subtarget;
1170: if (TREE_CODE (otherop) == VAR_DECL
1171: && DECL_RTL (otherop) != subtarget)
1172: return subtarget;
1173: return 0;
1174: }
1175:
1176: rtx
1177: expand_expr (exp, target, tmode, sum_ok)
1178: register tree exp;
1179: rtx target;
1180: enum machine_mode tmode;
1181: int sum_ok;
1182: {
1183: register rtx op0, op1, temp;
1184: tree type = TREE_TYPE (exp);
1185: register enum machine_mode mode = TYPE_MODE (type);
1186: register enum tree_code code = TREE_CODE (exp);
1187: struct optab *this_optab;
1188: int negate_1;
1189: /* Use subtarget as the target for operand 0 of a binary operation. */
1190: rtx subtarget = (target != 0 && GET_CODE (target) == REG ? target : 0);
1191: static tree dbg2;
1192: dbg2 = exp;
1193:
1194: /* If will do cse, generate all results into registers
1195: since 1) that allows cse to find more things
1196: and 2) otherwise cse could produce an insn the machine
1197: cannot support. */
1198:
1199: if (! cse_not_expected && mode != BLKmode)
1200: target = subtarget;
1201:
1202: switch (code)
1203: {
1204: case FUNCTION_DECL:
1205: case VAR_DECL:
1206: temp = DECL_RTL (exp);
1207: if (! cse_not_expected && TREE_VOLATILE (exp))
1208: return gen_rtx (VOLATILE, DECL_MODE (exp), temp);
1209: else
1210: return temp;
1211:
1212: case PARM_DECL:
1213: case RESULT_DECL:
1214: if (DECL_RTL (exp) == 0)
1215: abort ();
1216: if (GET_CODE (DECL_RTL (exp)) == SYMBOL_REF)
1217: abort ();
1218: return DECL_RTL (exp);
1219:
1220: case INTEGER_CST:
1221: return gen_rtx (CONST_INT, VOIDmode, TREE_INT_CST_LOW (exp));
1222:
1223: case CONST_DECL:
1224: return expand_expr (DECL_INITIAL (exp), target, VOIDmode, 0);
1225:
1226: case REAL_CST:
1227: if (TREE_CST_RTL (exp))
1228: return TREE_CST_RTL (exp);
1229: /* If optimized, generate immediate float
1230: which will be turned into memory float if necessary. */
1231: if (!cse_not_expected)
1232: return immed_real_const (exp);
1233: output_constant_def (exp);
1234: return TREE_CST_RTL (exp);
1235:
1236: case COMPLEX_CST:
1237: case STRING_CST:
1238: if (TREE_CST_RTL (exp))
1239: return TREE_CST_RTL (exp);
1240: output_constant_def (exp);
1241: return TREE_CST_RTL (exp);
1242:
1243: case SAVE_EXPR:
1244: if (SAVE_EXPR_RTL (exp) == 0)
1245: {
1246: SAVE_EXPR_RTL (exp) = gen_reg_rtx (mode);
1247: store_expr (TREE_OPERAND (exp, 0), SAVE_EXPR_RTL (exp));
1248: }
1249: return SAVE_EXPR_RTL (exp);
1250:
1251: case INDIRECT_REF:
1252: {
1253: tree exp1 = TREE_OPERAND (exp, 0);
1254: tree exp2;
1255:
1256: /* A SAVE_EXPR as the address in an INDIRECT_EXPR is generated
1257: for *PTR += ANYTHING where PTR is put inside the SAVE_EXPR.
1258: This code has the same general effect as simply doing
1259: expand_expr on the save expr, except that the expression PTR
1260: is computed for use as a memory address. This means different
1261: code, suitable for indexing, may be generated. */
1262: if (TREE_CODE (exp1) == SAVE_EXPR
1263: && SAVE_EXPR_RTL (exp1) == 0
1264: && TREE_CODE (exp2 = TREE_OPERAND (exp1, 0)) != ERROR_MARK
1265: && TYPE_MODE (TREE_TYPE (exp1)) == Pmode
1266: && TYPE_MODE (TREE_TYPE (exp2)) == Pmode)
1267: {
1268: temp = expand_expr (TREE_OPERAND (exp1, 0), 0, VOIDmode, 1);
1269: op0 = memory_address (mode, temp);
1270: op0 = copy_all_regs (op0);
1271: SAVE_EXPR_RTL (exp1) = op0;
1272: }
1273: else
1274: {
1275: op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 1);
1276: op0 = memory_address (mode, op0);
1277: }
1278: }
1279: temp = gen_rtx (MEM, mode, op0);
1280: if (! cse_not_expected && TREE_THIS_VOLATILE (exp))
1281: return gen_rtx (VOLATILE, mode, temp);
1282: else
1283: return temp;
1284:
1285: case COMPONENT_REF:
1286: {
1287: register enum machine_mode mode1 = DECL_MODE (TREE_OPERAND (exp, 1));
1288: int volstruct = 0;
1289: tree dbg1 = TREE_OPERAND (exp, 0); /* For debugging */
1290:
1291: op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
1292: if (mode1 == BImode || GET_CODE (op0) == REG
1293: || GET_CODE (op0) == SUBREG)
1294: {
1295: tree field = TREE_OPERAND (exp, 1);
1296: int bitsize = TREE_INT_CST_LOW (DECL_SIZE (field)) * DECL_SIZE_UNIT (field);
1297: return extract_bit_field (op0, bitsize, DECL_OFFSET (field),
1298: type_unsigned_p (TREE_TYPE (field)),
1299: target, mode, tmode);
1300: }
1301: if (tmode != VOIDmode)
1302: mode = tmode;
1303: /* Get the address of the structure the component is in. */
1304: if (GET_CODE (op0) == VOLATILE)
1305: {
1306: op0 = XEXP (op0, 0);
1307: volstruct = 1;
1308: }
1309: if (GET_CODE (op0) != MEM)
1310: abort ();
1311: op0 = XEXP (op0, 0);
1312: op0 = gen_rtx (MEM, mode1,
1313: memory_address (mode1,
1314: plus_constant (op0,
1315: (DECL_OFFSET
1316: (TREE_OPERAND (exp, 1))
1317: / BITS_PER_UNIT))));
1318: op0->in_struct = 1;
1319: if (! cse_not_expected && volstruct)
1320: op0 = gen_rtx (VOLATILE, mode1, op0);
1321: if (mode == mode1 || mode == BLKmode)
1322: return op0;
1323: if (target == 0)
1324: target = gen_reg_rtx (mode);
1325: convert_move (target, op0, type_unsigned_p (TREE_TYPE (TREE_OPERAND (exp, 1))));
1326: return target;
1327: }
1328:
1329: /* ARRAY_REF is used in C for an actual array (not just a pointer)
1330: indexed by a constant index. It enables us to avoid taking the
1331: address of the array, which may allow a short array (or a struct
1332: or union containing one) to go in a register. */
1333: case ARRAY_REF:
1334: {
1335: /* Check to see whether the array is in a register. */
1336: tree array = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
1337: register tree temexp;
1338:
1339: /* Look through any COMPONENT_REFS to the containing struct.
1340: Start by taking the array out of the ADDR_EXPR that's operand 0. */
1341: for (temexp = array;
1342: TREE_CODE (temexp) == COMPONENT_REF;
1343: temexp = TREE_OPERAND (temexp, 0));
1344:
1345: if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
1346: && TREE_CODE (temexp) == VAR_DECL
1347: && DECL_RTL (temexp) != 0
1348: && (GET_CODE (DECL_RTL (temexp)) == REG
1349: || GET_CODE (DECL_RTL (temexp)) == SUBREG))
1350: {
1351: /* The array or containing struct is a variable in a register
1352: and the index is constant. */
1353: int bitsize = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (exp)));
1354:
1355: op0 = expand_expr (array, 0, VOIDmode, 0);
1356: return extract_bit_field (op0, bitsize,
1357: TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)) * bitsize,
1358: type_unsigned_p (TREE_TYPE (exp)),
1359: target, mode, tmode);
1360: }
1361:
1362: /* The array is in memory. Generate the tree for *(array+index)
1363: and expand that. */
1364:
1365: temexp = build_indirect_ref (build_binary_op (PLUS_EXPR,
1366: TREE_OPERAND (exp, 0),
1367: TREE_OPERAND (exp, 1)));
1368: return expand_expr (temexp, 0, VOIDmode, 0);
1369: }
1370:
1371: /* Intended for a reference to a buffer of a file-object in Pascal.
1372: But it's not certain that a special tree code will really be
1373: necessary for these. INDIRECT_REF might work for them. */
1374: case BUFFER_REF:
1375: abort ();
1376:
1377: case CALL_EXPR:
1378: /* If this call was expanded already by preexpand_calls,
1379: just return the result we got. */
1380: if (CALL_EXPR_RTL (exp) != 0)
1381: return CALL_EXPR_RTL (exp);
1382: return expand_call (exp, target);
1383:
1384: case NOP_EXPR:
1385: case CONVERT_EXPR:
1386: if (TREE_CODE (type) == VOID_TYPE)
1387: {
1388: expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, sum_ok);
1389: return const0_rtx;
1390: }
1391: if (mode == TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
1392: return expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, sum_ok);
1393: op0 = expand_expr (TREE_OPERAND (exp, 0), 0, mode, 0);
1394: if (GET_MODE (op0) == mode)
1395: return op0;
1396: if (target == 0)
1397: target = gen_reg_rtx (mode);
1398: convert_move (target, op0, type_unsigned_p (TREE_TYPE (TREE_OPERAND (exp, 0))));
1399: return target;
1400:
1401: case PLUS_EXPR:
1402: preexpand_calls (exp);
1403: if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST)
1404: {
1405: op1 = expand_expr (TREE_OPERAND (exp, 1), subtarget, VOIDmode, 1);
1406: op1 = plus_constant (op1, TREE_INT_CST_LOW (TREE_OPERAND (exp, 0)));
1407: if (sum_ok)
1408: return op1;
1409: return force_operand (op1, target);
1410: }
1411: negate_1 = 1;
1412: plus_minus:
1413: if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
1414: {
1415: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 1);
1416: op0 = plus_constant (op0,
1417: negate_1 * TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)));
1418: if (sum_ok)
1419: return op0;
1420: return force_operand (op0, target);
1421: }
1422: this_optab = add_optab;
1423: if (!sum_ok) goto binop;
1424: subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1));
1425: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 1);
1426: op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 1);
1427: /* Put a sum last, to simplify what follows. */
1428: #ifdef OLD_INDEXING
1429: if (GET_CODE (op1) == MULT)
1430: {
1431: temp = op0;
1432: op0 = op1;
1433: op1 = temp;
1434: }
1435: #endif
1436: #ifndef OLD_INDEXING
1437: /* Make sure any term that's a sum with a constant comes last. */
1438: if (GET_CODE (op0) == PLUS
1439: && CONSTANT_ADDRESS_P (XEXP (op0, 1)))
1440: {
1441: temp = op0;
1442: op0 = op1;
1443: op1 = temp;
1444: }
1445: /* If adding to a sum including a constant,
1446: associate it to put the constant outside. */
1447: if (GET_CODE (op1) == PLUS
1448: && CONSTANT_ADDRESS_P (XEXP (op1, 1)))
1449: {
1450: op0 = gen_rtx (PLUS, mode, XEXP (op1, 0), op0);
1451: if (GET_CODE (XEXP (op1, 1)) == CONST_INT)
1452: return plus_constant (op0, INTVAL (XEXP (op1, 1)));
1453: else
1454: return gen_rtx (PLUS, mode, op0, XEXP (op1, 1));
1455: }
1456: #endif
1457: return gen_rtx (PLUS, mode, op0, op1);
1458:
1459: case MINUS_EXPR:
1460: preexpand_calls (exp);
1461: if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
1462: {
1463: negate_1 = -1;
1464: goto plus_minus;
1465: }
1466: this_optab = sub_optab;
1467: goto binop;
1468:
1469: case MULT_EXPR:
1470: preexpand_calls (exp);
1471: /* If first operand is constant, swap them.
1472: Thus the following special case checks need only
1473: check the second operand. */
1474: if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST)
1475: {
1476: register tree t1 = TREE_OPERAND (exp, 0);
1477: TREE_OPERAND (exp, 0) = TREE_OPERAND (exp, 1);
1478: TREE_OPERAND (exp, 1) = t1;
1479: }
1480:
1481: /* Attempt to return something suitable for generating an
1482: indexed address, for machines that support that. */
1483:
1484: if (sum_ok && TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
1485: {
1486: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
1487: if (GET_CODE (op0) != REG)
1488: {
1489: temp = gen_reg_rtx (GET_MODE (op0));
1490: emit_move_insn (temp, op0);
1491: op0 = temp;
1492: }
1493: return gen_rtx (MULT, mode, op0,
1494: gen_rtx (CONST_INT, VOIDmode,
1495: TREE_INT_CST_LOW (TREE_OPERAND (exp, 1))));
1496: }
1497: subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1));
1498: /* Check for multiplying things that have been extended
1499: from a narrower type. If this machine supports multiplying
1500: in that narrower type with a result in the desired type,
1501: do it that way, and avoid the explicit type-conversion. */
1502: if (TREE_CODE (TREE_OPERAND (exp, 0)) == NOP_EXPR
1503: && TREE_CODE (TREE_TYPE (exp)) == INTEGER_TYPE
1504: && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
1505: < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0))))
1506: && ((TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
1507: && int_fits_type_p (TREE_OPERAND (exp, 1),
1508: TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))))
1509: ||
1510: (TREE_CODE (TREE_OPERAND (exp, 1)) == NOP_EXPR
1511: && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 1), 0)))
1512: ==
1513: TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))))))
1514: {
1515: enum machine_mode innermode
1516: = TYPE_MODE (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)));
1517: this_optab = (type_unsigned_p (TREE_TYPE (exp))
1518: ? umul_widen_optab : smul_widen_optab);
1519: if ((int) innermode + 1 == (int) mode
1520: && this_optab[(int) mode].insn_code != CODE_FOR_nothing)
1521: {
1522: op0 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
1523: 0, VOIDmode, 0);
1524: if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
1525: op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
1526: else
1527: op1 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 1), 0),
1528: 0, VOIDmode, 0);
1529: goto binop2;
1530: }
1531: }
1532: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
1533: op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
1534: return expand_mult (mode, op0, op1, target, type_unsigned_p (type));
1535:
1536: case TRUNC_DIV_EXPR:
1537: case FLOOR_DIV_EXPR:
1538: case CEIL_DIV_EXPR:
1539: case ROUND_DIV_EXPR:
1540: preexpand_calls (exp);
1541: subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1));
1542: /* Possible optimization: compute the dividend with SUM_OK
1543: then if the divisor is constant can optimize the case
1544: where some terms of the dividend have coeffs divisible by it. */
1545: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
1546: op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
1547: return expand_divmod (0, code, mode, op0, op1, target,
1548: type_unsigned_p (type));
1549:
1550: case RDIV_EXPR:
1551: preexpand_calls (exp);
1552: this_optab = flodiv_optab;
1553: goto binop;
1554:
1555: case TRUNC_MOD_EXPR:
1556: case FLOOR_MOD_EXPR:
1557: case CEIL_MOD_EXPR:
1558: case ROUND_MOD_EXPR:
1559: preexpand_calls (exp);
1560: subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1));
1561: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
1562: op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
1563: return expand_divmod (1, code, mode, op0, op1, target,
1564: type_unsigned_p (type));
1565: #if 0
1566: #ifdef HAVE_divmoddisi4
1567: if (GET_MODE (op0) != DImode)
1568: {
1569: temp = gen_reg_rtx (DImode);
1570: convert_move (temp, op0, 0);
1571: op0 = temp;
1572: if (GET_MODE (op1) != SImode && GET_CODE (op1) != CONST_INT)
1573: {
1574: temp = gen_reg_rtx (SImode);
1575: convert_move (temp, op1, 0);
1576: op1 = temp;
1577: }
1578: temp = gen_reg_rtx (SImode);
1579: if (target == 0)
1580: target = gen_reg_rtx (SImode);
1581: emit_insn (gen_divmoddisi4 (temp, protect_from_queue (op0, 0),
1582: protect_from_queue (op1, 0),
1583: protect_from_queue (target, 1)));
1584: return target;
1585: }
1586: #endif
1587: #endif
1588:
1589: case FIX_ROUND_EXPR:
1590: case FIX_FLOOR_EXPR:
1591: case FIX_CEIL_EXPR:
1592: abort (); /* Not used for C. */
1593:
1594: case FIX_TRUNC_EXPR:
1595: op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
1596: if (target == 0)
1597: target = gen_reg_rtx (mode);
1598: if (mode == HImode || mode == QImode)
1599: {
1600: register rtx temp = gen_reg_rtx (SImode);
1601: expand_fix (temp, op0);
1602: convert_move (target, temp, 0);
1603: }
1604: else
1605: expand_fix (target, op0);
1606: return target;
1607:
1608: case FLOAT_EXPR:
1609: op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
1610: if (target == 0)
1611: target = gen_reg_rtx (mode);
1612: if (GET_MODE (op0) == HImode
1613: || GET_MODE (op0) == QImode)
1614: {
1615: register rtx temp = gen_reg_rtx (SImode);
1616: convert_move (temp, op0, 0);
1617: expand_float (target, temp);
1618: }
1619: else
1620: expand_float (target, op0);
1621: return target;
1622:
1623: case NEGATE_EXPR:
1624: op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0);
1625: temp = expand_unop (mode, neg_optab, op0, target, 0);
1626: if (temp == 0)
1627: abort ();
1628: return temp;
1629:
1630: case ABS_EXPR:
1631: /* First try to do it with a special abs instruction.
1632: If that does not win, use conditional jump and negate. */
1633: op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0);
1634: temp = expand_unop (mode, abs_optab, op0, target, 0);
1635: if (temp != 0)
1636: return temp;
1637: temp = gen_label_rtx ();
1638: if (target == 0 || GET_CODE (target) != REG)
1639: target = gen_reg_rtx (GET_MODE (op0));
1640: emit_move_insn (target, op0);
1641: emit_tst_insn (target);
1642: emit_jump_insn (gen_bge (temp));
1643: op0 = expand_unop (mode, neg_optab, target, target, 0);
1644: if (op0 != target)
1645: emit_move_insn (target, op0);
1646: emit_label (temp);
1647: return target;
1648:
1649: case MAX_EXPR:
1650: case MIN_EXPR:
1651: op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
1652: if (target == 0 || GET_CODE (target) != REG || target == op1)
1653: target = gen_reg_rtx (GET_MODE (op0));
1654: op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0);
1655: if (target != op0)
1656: emit_move_insn (target, op0);
1657: op0 = gen_label_rtx ();
1658: if (code == MAX_EXPR)
1659: temp = (type_unsigned_p (TREE_TYPE (TREE_OPERAND (exp, 1)))
1660: ? compare1 (target, op1, GEU, LEU, 1)
1661: : compare1 (target, op1, GE, LE, 0));
1662: else
1663: temp = (type_unsigned_p (TREE_TYPE (TREE_OPERAND (exp, 1)))
1664: ? compare1 (target, op1, LEU, GEU, 1)
1665: : compare1 (target, op1, LE, GE, 0));
1666: emit_jump_insn (gen_rtx (SET, VOIDmode, pc_rtx,
1667: gen_rtx (IF_THEN_ELSE, VOIDmode,
1668: temp,
1669: gen_rtx (LABEL_REF, VOIDmode, op0),
1670: pc_rtx)));
1671: emit_move_insn (target, op1);
1672: emit_label (temp);
1673: return target;
1674:
1675: /* ??? Can optimize when the operand of this is a bitwise operation,
1676: by using a different bitwise operation. */
1677: case BIT_NOT_EXPR:
1678: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
1679: temp = expand_unop (mode, one_cmpl_optab, op0, target, 1);
1680: if (temp == 0)
1681: abort ();
1682: return temp;
1683:
1684: /* ??? Can optimize bitwise operations with one arg constant.
1685: Pastel optimizes (a bitwise1 n) bitwise2 (a bitwise3 b)
1686: and (a bitwise1 b) bitwise2 b (etc)
1687: but that is probably not worth while. */
1688:
1689: /* AND_EXPR is for bitwise anding.
1690: TRUTH_AND_EXPR is for anding two boolean values
1691: when we want in all cases to compute both of them.
1692: In general it is fastest to do TRUTH_AND_EXPR by
1693: computing both operands as actual zero-or-1 values
1694: and then bitwise anding. In cases where there cannot
1695: be any side effects, better code would be made by
1696: treating TRUTH_AND_EXPR like TRUTH_ANDIF_EXPR;
1697: but the question is how to recognize those cases. */
1698:
1699: case TRUTH_AND_EXPR:
1700: case BIT_AND_EXPR:
1701: preexpand_calls (exp);
1702: subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1));
1703: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
1704: op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
1705: return expand_bit_and (mode, op0, op1, target);
1706:
1707: /* See comment above about TRUTH_AND_EXPR; it applies here too. */
1708: case TRUTH_OR_EXPR:
1709: case BIT_IOR_EXPR:
1710: preexpand_calls (exp);
1711: this_optab = ior_optab;
1712: goto binop;
1713:
1714: case BIT_XOR_EXPR:
1715: preexpand_calls (exp);
1716: this_optab = xor_optab;
1717: goto binop;
1718:
1719: case LSHIFT_EXPR:
1720: case RSHIFT_EXPR:
1721: case LROTATE_EXPR:
1722: case RROTATE_EXPR:
1723: preexpand_calls (exp);
1724: subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1));
1725: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
1726: return expand_shift (code, mode, op0, TREE_OPERAND (exp, 1), target,
1727: type_unsigned_p (type));
1728:
1729: /* ??? cv's were used to effect here to combine additive constants
1730: and to determine the answer when only additive constants differ.
1731: Also, the addition of one can be handled by changing the condition. */
1732: case LT_EXPR:
1733: case LE_EXPR:
1734: case GT_EXPR:
1735: case GE_EXPR:
1736: case EQ_EXPR:
1737: case NE_EXPR:
1738: preexpand_calls (exp);
1739: temp = do_store_flag (exp, target);
1740: if (temp != 0)
1741: return temp;
1742: if (code == NE_EXPR && integer_zerop (TREE_OPERAND (exp, 1)))
1743: {
1744: /* For foo != 0, load foo, and if it is nonzero load 1 instead. */
1745: temp = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
1746: if (temp != subtarget)
1747: temp = copy_to_reg (temp);
1748: op1 = gen_label_rtx ();
1749: emit_cmp_insn (temp, const0_rtx, 0, type_unsigned_p (type));
1750: emit_jump_insn (gen_beq (op1));
1751: emit_move_insn (temp, const1_rtx);
1752: emit_label (op1);
1753: return temp;
1754: }
1755: /* If no set-flag instruction, must generate a conditional
1756: store into a temporary variable. Drop through
1757: and handle this like && and ||. */
1758:
1759: case TRUTH_ANDIF_EXPR:
1760: case TRUTH_ORIF_EXPR:
1761: temp = gen_reg_rtx (mode);
1762: emit_clr_insn (temp);
1763: op1 = gen_label_rtx ();
1764: jumpifnot (exp, op1);
1765: emit_0_to_1_insn (temp);
1766: emit_label (op1);
1767: return temp;
1768:
1769: case TRUTH_NOT_EXPR:
1770: op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0);
1771: /* The parser is careful to generate TRUTH_NOT_EXPR
1772: only with operands that are always zero or one. */
1773: temp = expand_binop (mode, xor_optab, op0,
1774: gen_rtx (CONST_INT, mode, 1),
1775: target, 1, OPTAB_LIB_WIDEN);
1776: if (temp == 0)
1777: abort ();
1778: return temp;
1779:
1780: case COMPOUND_EXPR:
1781: expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
1782: emit_queue ();
1783: return expand_expr (TREE_OPERAND (exp, 1), target, VOIDmode, 0);
1784:
1785: case COND_EXPR:
1786: /* Note that COND_EXPRs whose type is a structure or union
1787: are required to be constructed to contain assignments of
1788: a temporary variable, so that we can evaluate them here
1789: for side effect only. If type is void, we must do likewise. */
1790: op0 = gen_label_rtx ();
1791: op1 = gen_label_rtx ();
1792:
1793: if (mode == BLKmode || mode == VOIDmode)
1794: temp = 0;
1795: else if (target)
1796: temp = target;
1797: else
1798: temp = gen_reg_rtx (mode);
1799:
1800: jumpifnot (TREE_OPERAND (exp, 0), op0);
1801: current_args_size += 1;
1802: if (temp != 0)
1803: store_expr (TREE_OPERAND (exp, 1), temp);
1804: else
1805: expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
1806: emit_queue ();
1807: emit_jump_insn (gen_jump (op1));
1808: emit_barrier ();
1809: emit_label (op0);
1810: if (temp != 0)
1811: store_expr (TREE_OPERAND (exp, 2), temp);
1812: else
1813: expand_expr (TREE_OPERAND (exp, 2), 0, VOIDmode, 0);
1814: emit_queue ();
1815: emit_label (op1);
1816: current_args_size -= 1;
1817: return temp;
1818:
1819: case MODIFY_EXPR:
1820: /* If lhs is complex, expand calls in rhs before computing it.
1821: That's so we don't compute a pointer and save it over a call.
1822: If lhs is simple, compute it first so we can give it as a
1823: target if the rhs is just a call. This avoids an extra temp and copy
1824: and that prevents a partial-subsumption which makes bad code.
1825: Actually we could treat component_ref's of vars like vars. */
1826: if (TREE_CODE (TREE_OPERAND (exp, 0)) != VAR_DECL)
1827: preexpand_calls (exp);
1828: temp = expand_assignment (TREE_OPERAND (exp, 0),
1829: TREE_OPERAND (exp, 1));
1830: return temp;
1831:
1832: case PREINCREMENT_EXPR:
1833: op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
1834: op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
1835: expand_binop (mode, add_optab, copy_rtx (op0), op1, copy_rtx (op0),
1836: 0, OPTAB_LIB_WIDEN);
1837: return op0;
1838:
1839: case PREDECREMENT_EXPR:
1840: op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
1841: op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
1842: expand_binop (mode, sub_optab, copy_rtx (op0), op1, copy_rtx (op0),
1843: 0, OPTAB_LIB_WIDEN);
1844: return op0;
1845:
1846: case POSTINCREMENT_EXPR:
1847: op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
1848: op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
1849: op0 = stabilize (op0);
1850: return enqueue_insn (op0, gen_add2_insn (copy_rtx (op0), op1));
1851:
1852: case POSTDECREMENT_EXPR:
1853: op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
1854: op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
1855: op0 = stabilize (op0);
1856: return enqueue_insn (op0, gen_sub2_insn (copy_rtx (op0), op1));
1857:
1858: case ADDR_EXPR:
1859: op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
1860: if (GET_CODE (op0) == VOLATILE)
1861: op0 = XEXP (op0, 0);
1862: if (GET_CODE (op0) != MEM)
1863: abort ();
1864: if (sum_ok)
1865: return XEXP (op0, 0);
1866: return force_operand (XEXP (op0, 0), target);
1867:
1868: case ENTRY_VALUE_EXPR:
1869: abort ();
1870:
1871: case ERROR_MARK:
1872: return gen_rtx (CONST_INT, (mode != VOIDmode) ? mode : SImode, 0);
1873:
1874: default:
1875: abort ();
1876: }
1877:
1878: /* Here to do an ordinary binary operator, generating an instruction
1879: from the optab already placed in `this_optab'. */
1880: binop:
1881: /* Detect things like x = y | (a == b)
1882: and do them as (x = y), (a == b ? x |= 1 : 0), x. */
1883: /* First, get the comparison or conditional into the second arg. */
1884: if (comparison_code[(int) TREE_CODE (TREE_OPERAND (exp, 0))]
1885: || (TREE_CODE (TREE_OPERAND (exp, 0)) == COND_EXPR
1886: && (integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 0), 1))
1887: || integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 0), 2)))))
1888: {
1889: if (this_optab == ior_optab || this_optab == add_optab
1890: || this_optab == xor_optab)
1891: {
1892: tree exch = TREE_OPERAND (exp, 1);
1893: TREE_OPERAND (exp, 1) = TREE_OPERAND (exp, 0);
1894: TREE_OPERAND (exp, 0) = exch;
1895: }
1896: }
1897: if (comparison_code[(int) TREE_CODE (TREE_OPERAND (exp, 1))]
1898: || (TREE_CODE (TREE_OPERAND (exp, 1)) == COND_EXPR
1899: && (integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 1), 1))
1900: || integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 1), 2)))))
1901: {
1902: if (this_optab == ior_optab || this_optab == add_optab
1903: || this_optab == xor_optab || this_optab == sub_optab
1904: || this_optab == lshl_optab || this_optab == ashl_optab
1905: || this_optab == lshr_optab || this_optab == ashr_optab
1906: || this_optab == rotl_optab || this_optab == rotr_optab)
1907: {
1908: tree thenexp, condexp;
1909: rtx thenv = 0;
1910:
1911: if (target == 0) target = gen_reg_rtx (mode);
1912: store_expr (TREE_OPERAND (exp, 0), target);
1913: op0 = gen_label_rtx ();
1914:
1915: if (TREE_CODE (TREE_OPERAND (exp, 1)) != COND_EXPR)
1916: {
1917: do_jump (TREE_OPERAND (exp, 1), op0, 0);
1918: thenv = const1_rtx;
1919: }
1920: else if (integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 1), 2)))
1921: {
1922: do_jump (TREE_OPERAND (TREE_OPERAND (exp, 1), 0), op0, 0);
1923: thenexp = TREE_OPERAND (TREE_OPERAND (exp, 1), 1);
1924: }
1925: else
1926: {
1927: do_jump (TREE_OPERAND (TREE_OPERAND (exp, 1), 0), 0, op0);
1928: thenexp = TREE_OPERAND (TREE_OPERAND (exp, 1), 2);
1929: }
1930:
1931: if (thenv == 0)
1932: thenv = expand_expr (thenexp, 0, VOIDmode, 0);
1933:
1934: if (this_optab == rotl_optab || this_optab == rotr_optab)
1935: temp = expand_binop (mode, this_optab, target, thenv, target,
1936: -1, OPTAB_LIB);
1937: else if (this_optab == lshl_optab || this_optab == lshr_optab)
1938: temp = expand_binop (mode, this_optab, target, thenv, target,
1939: 1, OPTAB_LIB_WIDEN);
1940: else
1941: temp = expand_binop (mode, this_optab, target, thenv, target,
1942: 0, OPTAB_LIB_WIDEN);
1943: if (target != temp)
1944: emit_move_insn (target, temp);
1945:
1946: emit_label (op0);
1947: return target;
1948: }
1949: }
1950: subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1));
1951: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
1952: op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
1953: binop2:
1954: temp = expand_binop (mode, this_optab, op0, op1, target,
1955: type_unsigned_p (TREE_TYPE (exp)), OPTAB_LIB_WIDEN);
1956: binop1:
1957: if (temp == 0)
1958: abort ();
1959: return temp;
1960: }
1961:
1962: /* Expand all function calls contained within EXP, innermost ones first.
1963: But don't look within expressions that have sequence points.
1964: For each CALL_EXPR, record the rtx for its value
1965: in the CALL_EXPR_RTL field.. */
1966:
1967: static void
1968: preexpand_calls (exp)
1969: tree exp;
1970: {
1971: register int nops, i;
1972:
1973: if (! do_preexpand_calls)
1974: return;
1975:
1976: switch (TREE_CODE (exp))
1977: {
1978: case CALL_EXPR:
1979: if (CALL_EXPR_RTL (exp) == 0)
1980: CALL_EXPR_RTL (exp) = expand_call (exp, 0);
1981: return;
1982:
1983: case COMPOUND_EXPR:
1984: case COND_EXPR:
1985: case TRUTH_ANDIF_EXPR:
1986: case TRUTH_ORIF_EXPR:
1987: /* If we find one of these, then we can be sure
1988: the adjust will be done for it (since it makes jumps).
1989: Do it now, so that if this is inside an argument
1990: of a function, we don't get the stack adjustment
1991: after some other args have already been pushed. */
1992: do_pending_stack_adjust ();
1993: return;
1994:
1995: case SAVE_EXPR:
1996: if (SAVE_EXPR_RTL (exp) != 0)
1997: return;
1998: }
1999:
2000: nops = tree_code_length[(int) TREE_CODE (exp)];
2001: for (i = 0; i < nops; i++)
2002: if (TREE_OPERAND (exp, i) != 0)
2003: {
2004: register int type = *tree_code_type[(int) TREE_CODE (TREE_OPERAND (exp, i))];
2005: if (type == 'e' || type == 'r')
2006: preexpand_calls (TREE_OPERAND (exp, i));
2007: }
2008: }
2009:
2010: /* Generate instructions to call function FUNEXP and pass
2011: it the static chain. NARGS is the "number of args",
2012: to put in the call instruction on machines that require this.
2013: Also generate the code to pop the args after returning,
2014: (ARGS_SIZE is size of stuff to pop, in bytes). */
2015:
2016: static void
2017: gen_call_1 (funexp, context, nargs, args_size)
2018: rtx funexp;
2019: rtx context;
2020: int nargs;
2021: int args_size;
2022: {
2023: funexp = protect_from_queue (funexp, 0);
2024: if (context)
2025: context = protect_from_queue (context, 0);
2026:
2027: /* Function variable in language with nested functions. */
2028: if (GET_MODE (funexp) == EPmode)
2029: {
2030: register rtx reg = gen_rtx (REG, Pmode, STATIC_CHAIN_REGNUM);
2031: emit_insn (gen_movsi (reg, gen_highpart (Pmode, funexp)));
2032: emit_insn (gen_rtx (USE, VOIDmode, reg));
2033: funexp = memory_address (QImode, gen_lowpart (Pmode, funexp));
2034: emit_call_insn (gen_call (gen_rtx (MEM, QImode, funexp),
2035: gen_rtx (CONST_INT, VOIDmode, nargs)));
2036: }
2037: else
2038: {
2039: if (context != 0)
2040: {
2041: /* Unless function variable in C, or top level function constant */
2042: register rtx reg = gen_rtx (REG, Pmode, STATIC_CHAIN_REGNUM);
2043: emit_insn (gen_movsi (reg, lookup_static_chain (context)));
2044: emit_insn (gen_rtx (USE, VOIDmode, reg));
2045: }
2046: emit_call_insn (gen_call (gen_rtx (MEM, QImode,
2047: memory_address (QImode, funexp)),
2048: gen_rtx (CONST_INT, VOIDmode, nargs)));
2049: }
2050: /* If returning from the subroutine does not automatically pop the args,
2051: we need an instruction to pop them sooner or later.
2052: Perhaps do it now; perhaps just record how much space to pop later. */
2053: current_args_size -= args_size;
2054: #ifndef RETURN_POPS_ARGS
2055: if (args_size != 0)
2056: {
2057: if (TARGET_DEFER_POP && current_args_size == 0)
2058: pending_stack_adjust += args_size;
2059: else
2060: adjust_stack (gen_rtx (CONST_INT, VOIDmode, args_size));
2061: }
2062: #endif
2063: }
2064:
2065: /* At the start of a function, record that we have no previously-pushed
2066: arguments waiting to be popped. */
2067:
2068: clear_pending_stack_adjust ()
2069: {
2070: pending_stack_adjust = 0;
2071: }
2072:
2073: /* At start of function, initialize. */
2074: clear_current_args_size ()
2075: {
2076: current_args_size = 0;
2077: }
2078:
2079: /* Pop any previously-pushed arguments that have not been popped yet. */
2080:
2081: do_pending_stack_adjust ()
2082: {
2083: if (current_args_size == 0)
2084: {
2085: if (pending_stack_adjust != 0)
2086: adjust_stack (gen_rtx (CONST_INT, VOIDmode, pending_stack_adjust));
2087: pending_stack_adjust = 0;
2088: }
2089: }
2090:
2091: /* Generate all the code for a function call
2092: and return an rtx for its value.
2093: Store the value in TARGET (specified as an rtx) if convenient.
2094: If the value is stored in TARGET then TARGET is returned. */
2095:
2096: static rtx
2097: expand_call (exp, target)
2098: tree exp;
2099: rtx target;
2100: {
2101: tree actparms = TREE_OPERAND (exp, 1);
2102: register tree p;
2103: int args_size = 0;
2104: register int i;
2105: register tree *argvec;
2106: int num_actuals;
2107: rtx structure_value_addr = 0;
2108:
2109: /* Don't let pending stack adjusts add up to too much.
2110: Also, do all pending adjustments now
2111: if there is any chance this might be a call to alloca. */
2112:
2113: if (pending_stack_adjust >= 32
2114: || (pending_stack_adjust > 0
2115: &&
2116: /* Unless it's a call to a specific function that isn't alloca,
2117: we must assume it might be alloca. */
2118: !(p = TREE_OPERAND (exp, 0),
2119: TREE_CODE (p) == ADDR_EXPR
2120: && TREE_CODE (TREE_OPERAND (p, 0)) == FUNCTION_DECL
2121: && strcmp (IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (p, 0))),
2122: "alloca"))))
2123: do_pending_stack_adjust ();
2124:
2125: if (TYPE_MODE (TREE_TYPE (exp)) == BLKmode)
2126: {
2127: /* This call returns a big structure. */
2128: if (target)
2129: structure_value_addr = XEXP (target, 0);
2130: else
2131: /* Make room on the stack to hold the value. */
2132: structure_value_addr = get_structure_value_addr (expr_size (exp));
2133: }
2134:
2135: for (p = actparms, i = 0; p; p = TREE_CHAIN (p)) i++;
2136: num_actuals = i;
2137: argvec = (tree *) alloca (i * sizeof (tree));
2138:
2139: #ifdef STACK_GROWS_DOWNWARD
2140: /* In this case, must reverse order of args
2141: so that we compute and pust the last arg first. */
2142: for (p = actparms, i = num_actuals - 1; p; p = TREE_CHAIN (p), i--)
2143: argvec[i] = p;
2144: #else
2145: for (p = actparms, i = 0; p; p = TREE_CHAIN (p), i++)
2146: argvec[i] = p;
2147: #endif
2148:
2149: for (i = 0; i < num_actuals; i++)
2150: {
2151: register tree p = argvec[i];
2152: register tree pval = TREE_VALUE (p);
2153:
2154: /* Push the next argument. Note that it has already been converted
2155: if necessary to the type that the called function expects. */
2156:
2157: if (TREE_CODE (pval) == ERROR_MARK)
2158: ;
2159: else if (TYPE_MODE (TREE_TYPE (pval)) != BLKmode)
2160: {
2161: register int size, used;
2162:
2163: /* Argument is a scalar.
2164: Push it, and if its size is less than the
2165: amount of space allocated to it,
2166: also bump stack pointer by the additional space.
2167: Note that in C the default argument promotions
2168: will prevent such mismatches. */
2169:
2170: used = size = GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (pval)));
2171: /* Compute how much space the push instruction will push.
2172: On many machines, pushing a byte will advance the stack
2173: pointer by a halfword. */
2174: size = PUSH_ROUNDING (size);
2175: /* Compute how much space the argument should get:
2176: round up to a multiple of the alignment for arguments. */
2177: used = (((size + PARM_BOUNDARY / BITS_PER_UNIT - 1)
2178: / (PARM_BOUNDARY / BITS_PER_UNIT))
2179: * (PARM_BOUNDARY / BITS_PER_UNIT));
2180:
2181: #ifdef STACK_GROWS_DOWNWARD
2182: if (size != used)
2183: anti_adjust_stack (gen_rtx (CONST_INT, VOIDmode,
2184: used - size));
2185: #endif
2186:
2187: emit_push_insn (expand_expr (pval, 0, VOIDmode, 0),
2188: TYPE_MODE (TREE_TYPE (pval)), 0, 0);
2189:
2190: #ifndef STACK_GROWS_DOWNWARD
2191: if (size != used)
2192: anti_adjust_stack (gen_rtx (CONST_INT, VOIDmode,
2193: used - size));
2194: #endif
2195:
2196: /* Account for the space thus used. */
2197: args_size += used;
2198: current_args_size += used;
2199: }
2200: else
2201: {
2202: register rtx tem = expand_expr (pval, 0, VOIDmode, 0);
2203: register tree size = size_in_bytes (TREE_TYPE (pval));
2204: register tree used;
2205: register int excess;
2206:
2207: /* Pushing a nonscalar. Round its size up to a multiple
2208: of the allocation unit for arguments. This part works
2209: on variable-size objects since SIZE and USED are rtx's. */
2210:
2211: used = convert_units (convert_units (size, BITS_PER_UNIT, PARM_BOUNDARY),
2212: PARM_BOUNDARY, BITS_PER_UNIT);
2213:
2214: if (!TREE_LITERAL (used))
2215: abort ();
2216:
2217: excess = TREE_INT_CST_LOW (used) - PUSH_ROUNDING (TREE_INT_CST_LOW (size));
2218:
2219: #ifdef STACK_GROWS_DOWNWARD
2220: if (excess != 0)
2221: anti_adjust_stack (gen_rtx (CONST_INT, VOIDmode, excess));
2222: #endif
2223:
2224: emit_push_insn (tem, TYPE_MODE (TREE_TYPE (pval)),
2225: expand_expr (size, 0, VOIDmode, 0),
2226: (TYPE_ALIGN (TREE_TYPE (pval))
2227: / BITS_PER_UNIT));
2228:
2229: #ifndef STACK_GROWS_DOWNWARD
2230: if (excess != 0)
2231: anti_adjust_stack (gen_rtx (CONST_INT, VOIDmode, excess));
2232: #endif
2233: args_size += TREE_INT_CST_LOW (used);
2234: current_args_size += TREE_INT_CST_LOW (used);
2235: }
2236: }
2237:
2238: /* Perform postincrements before actually calling the function. */
2239: emit_queue ();
2240:
2241: /* Pass the function the address in which to return a structure value. */
2242: if (structure_value_addr)
2243: {
2244: register rtx reg = gen_rtx (REG, Pmode, STRUCT_VALUE_REGNUM);
2245: emit_move_insn (reg, structure_value_addr);
2246: emit_insn (gen_rtx (USE, VOIDmode, reg));
2247: }
2248:
2249: gen_call_1 (expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0),
2250: /* ??? For Pascal, this must pass a context to get the static chain from
2251: in certain cases. */
2252: 0,
2253: args_size / GET_MODE_SIZE (SImode), args_size);
2254:
2255: /* ??? Nothing has been done here to record control flow
2256: when contained functions can do nonlocal gotos. */
2257:
2258: /* If value type not void, return an rtx for the value. */
2259:
2260: if (TYPE_MODE (TREE_TYPE (exp)) == VOIDmode)
2261: return 0;
2262:
2263: if (structure_value_addr)
2264: {
2265: if (target)
2266: return target;
2267: return gen_rtx (MEM, BLKmode, structure_value_addr);
2268: }
2269:
2270: if (target && GET_MODE (target) == TYPE_MODE (TREE_TYPE (exp)))
2271: {
2272: copy_function_value (target);
2273: return target;
2274: }
2275: return function_value (TYPE_MODE (TREE_TYPE (exp)));
2276: }
2277:
2278: /* Expand conditional expressions. */
2279:
2280: /* Generate code to evaluate EXP and jump to LABEL if the value is zero.
2281: LABEL is an rtx of code CODE_LABEL, in this function and all the
2282: functions here. */
2283:
2284: jumpifnot (exp, label)
2285: tree exp;
2286: rtx label;
2287: {
2288: do_jump (exp, label, 0);
2289: }
2290:
2291: /* Generate code to evaluate EXP and jump to LABEL if the value is nonzero. */
2292:
2293: jumpif (exp, label)
2294: tree exp;
2295: rtx label;
2296: {
2297: do_jump (exp, 0, label);
2298: }
2299:
2300: /* Generate code to evaluate EXP and jump to IF_FALSE_LABEL if
2301: the result is zero, or IF_TRUE_LABEL if the result is one.
2302: Either of IF_FALSE_LABEL and IF_TRUE_LABEL may be zero,
2303: meaning fall through in that case.
2304:
2305: This function is responsible for optimizing cases such as
2306: &&, || and comparison operators in EXP. */
2307:
2308: do_jump (exp, if_false_label, if_true_label)
2309: tree exp;
2310: rtx if_false_label, if_true_label;
2311: {
2312: register enum tree_code code = TREE_CODE (exp);
2313: /* Some cases need to create a label to jump to
2314: in order to properly fall through.
2315: These cases set DROP_THROUGH_LABEL nonzero. */
2316: rtx drop_through_label = 0;
2317: rtx temp;
2318: rtx comparison = 0;
2319:
2320: emit_queue ();
2321:
2322: switch (code)
2323: {
2324: case ERROR_MARK:
2325: break;
2326:
2327: case INTEGER_CST:
2328: temp = integer_zerop (exp) ? if_false_label : if_true_label;
2329: if (temp)
2330: emit_jump (temp);
2331: break;
2332:
2333: case ADDR_EXPR:
2334: /* The address of something can never be zero. */
2335: if (if_true_label)
2336: emit_jump (if_true_label);
2337: break;
2338:
2339: case NOP_EXPR:
2340: do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
2341: break;
2342:
2343: case TRUTH_NOT_EXPR:
2344: do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label);
2345: break;
2346:
2347: case TRUTH_ANDIF_EXPR:
2348: if (if_false_label == 0)
2349: if_false_label = drop_through_label = gen_label_rtx ();
2350: do_jump (TREE_OPERAND (exp, 0), if_false_label, 0);
2351: do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
2352: break;
2353:
2354: case TRUTH_ORIF_EXPR:
2355: if (if_true_label == 0)
2356: if_true_label = drop_through_label = gen_label_rtx ();
2357: do_jump (TREE_OPERAND (exp, 0), 0, if_true_label);
2358: do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
2359: break;
2360:
2361: case COMPOUND_EXPR:
2362: expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
2363: emit_queue ();
2364: do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
2365: break;
2366:
2367: case COND_EXPR:
2368: {
2369: register rtx label1 = gen_label_rtx ();
2370: drop_through_label = gen_label_rtx ();
2371: do_jump (TREE_OPERAND (exp, 0), label1, 0);
2372: /* Now the THEN-expression. */
2373: do_jump (TREE_OPERAND (exp, 1),
2374: if_false_label ? if_false_label : drop_through_label,
2375: if_true_label ? if_true_label : drop_through_label);
2376: emit_label (label1);
2377: /* Now the ELSE-expression. */
2378: do_jump (TREE_OPERAND (exp, 2),
2379: if_false_label ? if_false_label : drop_through_label,
2380: if_true_label ? if_true_label : drop_through_label);
2381: }
2382: break;
2383:
2384: case EQ_EXPR:
2385: comparison = compare (exp, EQ, EQ, EQ, EQ);
2386: break;
2387:
2388: case NE_EXPR:
2389: comparison = compare (exp, NE, NE, NE, NE);
2390: break;
2391:
2392: case LT_EXPR:
2393: comparison = compare (exp, LT, LTU, GT, GTU);
2394: break;
2395:
2396: case LE_EXPR:
2397: comparison = compare (exp, LE, LEU, GE, GEU);
2398: break;
2399:
2400: case GT_EXPR:
2401: comparison = compare (exp, GT, GTU, LT, LTU);
2402: break;
2403:
2404: case GE_EXPR:
2405: comparison = compare (exp, GE, GEU, LE, LEU);
2406: break;
2407:
2408: default:
2409: temp = expand_expr (exp, 0, VOIDmode, 0);
2410: do_pending_stack_adjust ();
2411: emit_cmp_insn (temp, gen_rtx (CONST_INT, GET_MODE (temp), 0),
2412: 0, 0);
2413:
2414: if (if_true_label)
2415: emit_jump_insn (gen_bne (if_true_label));
2416: if (if_false_label)
2417: {
2418: if (if_true_label)
2419: emit_jump (if_false_label);
2420: else
2421: emit_jump_insn (gen_beq (if_false_label));
2422: }
2423: }
2424:
2425: /* If COMPARISON is nonzero here, it is an rtx that can be substituted
2426: straight into a conditional jump instruction as the jump condition.
2427: Otherwise, all the work has been done already. */
2428:
2429: if (comparison)
2430: if (if_true_label)
2431: {
2432: emit_jump_insn (gen_rtx (SET, VOIDmode, pc_rtx,
2433: gen_rtx (IF_THEN_ELSE, VOIDmode, comparison,
2434: gen_rtx (LABEL_REF, VOIDmode,
2435: if_true_label),
2436: pc_rtx)));
2437: if (if_false_label)
2438: emit_jump (if_false_label);
2439: }
2440: else if (if_false_label)
2441: {
2442: emit_jump_insn (gen_rtx (SET, VOIDmode, pc_rtx,
2443: gen_rtx (IF_THEN_ELSE, VOIDmode, comparison,
2444: pc_rtx,
2445: gen_rtx (LABEL_REF, VOIDmode,
2446: if_false_label))));
2447: }
2448:
2449: if (drop_through_label)
2450: emit_label (drop_through_label);
2451: }
2452:
2453: /* Generate code for a comparison expression EXP
2454: (including code to compute the values to be compared)
2455: and set (CC0) according to the result.
2456: SIGNED_FORWARD should be the rtx operation for this comparison for
2457: signed data; UNSIGNED_FORWARD, likewise for use if data is unsigned.
2458: SIGNED_REVERSE and UNSIGNED_REVERSE are used if it is desirable
2459: to interchange the operands for the compare instruction.
2460:
2461: We force a stack adjustment unless there are currently
2462: things pushed on the stack that aren't yet used. */
2463:
2464: static rtx
2465: compare (exp, signed_forward, unsigned_forward,
2466: signed_reverse, unsigned_reverse)
2467: register tree exp;
2468: enum rtx_code signed_forward, unsigned_forward;
2469: enum rtx_code signed_reverse, unsigned_reverse;
2470: {
2471: register rtx op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
2472: register rtx op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
2473: register enum machine_mode mode = GET_MODE (op0);
2474: int unsignedp;
2475:
2476: /* If one operand is 0, make it the second one. */
2477:
2478: if (op0 == const0_rtx || op0 == fconst0_rtx || op0 == dconst0_rtx)
2479: {
2480: rtx tem = op0;
2481: op0 = op1;
2482: op1 = tem;
2483: signed_forward = signed_reverse;
2484: unsigned_forward = unsigned_reverse;
2485: }
2486:
2487: if (force_mem)
2488: {
2489: op0 = force_not_mem (op0);
2490: op1 = force_not_mem (op1);
2491: }
2492:
2493: do_pending_stack_adjust ();
2494:
2495: unsignedp = (type_unsigned_p (TREE_TYPE (TREE_OPERAND (exp, 0)))
2496: || type_unsigned_p (TREE_TYPE (TREE_OPERAND (exp, 1))));
2497:
2498: emit_cmp_insn (op0, op1,
2499: (mode == BLKmode) ? expr_size (TREE_OPERAND (exp, 0)) : 0,
2500: unsignedp);
2501:
2502: return gen_rtx ((unsignedp ? unsigned_forward : signed_forward),
2503: VOIDmode, cc0_rtx, const0_rtx);
2504: }
2505:
2506: /* Like compare but expects the values to compare as two rtx's.
2507: The decision as to signed or unsigned comparison must be made by the caller.
2508: BLKmode is not allowed. */
2509:
2510: static rtx
2511: compare1 (op0, op1, forward_op, reverse_op, unsignedp)
2512: register rtx op0, op1;
2513: enum rtx_code forward_op, reverse_op;
2514: int unsignedp;
2515: {
2516: register enum machine_mode mode = GET_MODE (op0);
2517:
2518: /* If one operand is 0, make it the second one. */
2519:
2520: if (op0 == const0_rtx || op0 == fconst0_rtx || op0 == dconst0_rtx)
2521: {
2522: rtx tem = op0;
2523: op0 = op1;
2524: op1 = tem;
2525: forward_op = reverse_op;
2526: }
2527:
2528: if (force_mem)
2529: {
2530: op0 = force_not_mem (op0);
2531: op1 = force_not_mem (op1);
2532: }
2533:
2534: do_pending_stack_adjust ();
2535:
2536: emit_cmp_insn (op0, op1, 0, unsignedp);
2537:
2538: return gen_rtx (forward_op, VOIDmode, cc0_rtx, const0_rtx);
2539: }
2540:
2541: /* Generate code to jump to LABEL if OP1 and OP2 are equal. */
2542:
2543: void
2544: do_jump_if_equal (op1, op2, label)
2545: rtx op1, op2, label;
2546: {
2547: emit_cmp_insn (op1, op2, 0);
2548: emit_jump_insn (gen_beq (label));
2549: }
2550:
2551: /* Generate code to calculate EXP using a store-flag instruction
2552: and return an rtx for the result.
2553: If TARGET is nonzero, store the result there if convenient.
2554:
2555: Return zero if there is no suitable set-flag instruction
2556: available on this machine. */
2557:
2558: static rtx
2559: do_store_flag (exp, target)
2560: tree exp;
2561: rtx target;
2562: {
2563: register enum tree_code code = TREE_CODE (exp);
2564: register rtx comparison = 0;
2565:
2566: if (target == 0 || GET_MODE (target) != SImode)
2567: target = gen_reg_rtx (SImode);
2568:
2569: switch (code)
2570: {
2571: #ifdef HAVE_seqsi
2572: case EQ_EXPR:
2573: if (HAVE_seqsi)
2574: comparison = compare (exp, EQ, EQ, EQ, EQ);
2575: break;
2576: #endif
2577:
2578: #ifdef HAVE_snesi
2579: case NE_EXPR:
2580: if (HAVE_snesi)
2581: comparison = compare (exp, NE, NE, NE, NE);
2582: break;
2583: #endif
2584:
2585: #if defined (HAVE_sltsi) && defined (HAVE_sltusi) && defined (HAVE_sgtsi) && defined (HAVE_sgtusi)
2586: case LT_EXPR:
2587: if (HAVE_sltsi && HAVE_sltusi && HAVE_sgtsi && HAVE_sgtusi)
2588: comparison = compare (exp, LT, LTU, GT, GTU);
2589: break;
2590:
2591: case GT_EXPR:
2592: if (HAVE_sltsi && HAVE_sltusi && HAVE_sgtsi && HAVE_sgtusi)
2593: comparison = compare (exp, GT, GTU, LT, LTU);
2594: break;
2595: #endif
2596:
2597: #if defined (HAVE_slesi) && defined (HAVE_sleusi) && defined (HAVE_sgesi) && defined (HAVE_sgeusi)
2598: case LE_EXPR:
2599: if (HAVE_slesi && HAVE_sleusi && HAVE_sgesi && HAVE_sgeusi)
2600: comparison = compare (exp, LE, LEU, GE, GEU);
2601: break;
2602:
2603: case GE_EXPR:
2604: if (HAVE_slesi && HAVE_sleusi && HAVE_sgesi && HAVE_sgeusi)
2605: comparison = compare (exp, GE, GEU, LE, LEU);
2606: break;
2607: #endif
2608: }
2609: if (comparison == 0)
2610: return 0;
2611:
2612: emit_insn (gen_rtx (SET, VOIDmode, target, comparison));
2613: expand_bit_and (GET_MODE (target), target, const1_rtx, target);
2614: return target;
2615: }
2616:
2617: /* Generate a tablejump instruction (used for switch statements). */
2618:
2619: #ifdef HAVE_tablejump
2620:
2621: /* INDEX is the value being switched on, with the lowest value
2622: in the table already subtracted.
2623: RANGE is the length of the jump table.
2624: TABLE_LABEL is a CODE_LABEL rtx for the table itself.
2625: DEFAULT_LABEL is a CODE_LABEL rtx to jump to if the
2626: index value is out of range. */
2627:
2628: void
2629: do_tablejump (index, range, table_label, default_label)
2630: rtx index, range, table_label, default_label;
2631: {
2632: register rtx temp;
2633:
2634: emit_cmp_insn (index, const0_rtx, 0);
2635: emit_jump_insn (gen_blt (default_label));
2636: emit_cmp_insn (range, index, 0);
2637: emit_jump_insn (gen_blt (default_label));
2638: index = memory_address (CASE_VECTOR_MODE,
2639: gen_rtx (PLUS, Pmode,
2640: gen_rtx (LABEL_REF, VOIDmode, table_label),
2641: gen_rtx (MULT, Pmode, index,
2642: gen_rtx (CONST_INT, VOIDmode,
2643: GET_MODE_SIZE (CASE_VECTOR_MODE)))));
2644: temp = gen_reg_rtx (CASE_VECTOR_MODE);
2645: convert_move (temp, gen_rtx (MEM, CASE_VECTOR_MODE, index), 0);
2646:
2647: emit_jump_insn (gen_tablejump (temp));
2648: }
2649:
2650: #endif /* HAVE_tablejump */}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.