|
|
1.1 root 1: /* Subroutines for insn-output.c for Pyramid 90 Series.
2: Copyright (C) 1989 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 1, 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: /* Some output-actions in pyr.md need these. */
21: #include <stdio.h>
22: extern FILE *asm_out_file;
23: #include "tree.h"
24:
25: /*
26: * Do FUNCTION_ARG.
27: * This cannot be defined as a macro on pyramids, because Pyramid Technology's
28: * C compiler dies on (several equivalent definitions of) this macro.
29: * The only way around this cc bug was to make this a function.
30: * While it would be possible to use a macro version for gcc, it seems
31: * more reliable to have a single version of the code.
32: */
33: void *
34: pyr_function_arg(cum, mode, type, named)
35: CUMULATIVE_ARGS cum;
36: enum machine_mode mode;
37: tree type;
38: {
39: return (void *)(FUNCTION_ARG_HELPER (cum, mode,type,named));
40: }
41:
42: /* Do the hard part of PARAM_SAFE_FOR_REG_P.
43: * This cannot be defined as a macro on pyramids, because Pyramid Technology's
44: * C compiler dies on (several equivalent definitions of) this macro.
45: * The only way around this cc bug was to make this a function.
46: */
47: int
48: inner_param_safe_helper (type)
49: tree type;
50: {
51: return (INNER_PARAM_SAFE_HELPER(type));
52: }
53:
54:
55: /* Return 1 if OP is a non-indexed operand of mode MODE.
56: This is either a register reference, a memory reference,
57: or a constant. In the case of a memory reference, the address
58: is checked to make sure it isn't indexed.
59:
60: Register and memory references must have mode MODE in order to be valid,
61: but some constants have no machine mode and are valid for any mode.
62:
63: If MODE is VOIDmode, OP is checked for validity for whatever mode
64: it has.
65:
66: The main use of this function is as a predicate in match_operand
67: expressions in the machine description.
68:
69: It is useful to compare this with general_operand(). They should
70: be identical except for one line.
71:
72: This function seems necessary because of the non-orthogonality of
73: Pyramid insns.
74: For any 2-operand insn, and any combination of operand modes,
75: if indexing is valid for the isn's second operand, it is invalid
76: for the first operand to be indexed. */
77:
78: extern int volatile_ok;
79:
80: int
81: nonindexed_operand(op, mode)
82: register rtx op;
83: enum machine_mode mode;
84: {
85: register enum rtx_code code = GET_CODE (op);
86: int mode_altering_drug = 0;
87:
88: if (mode == VOIDmode)
89: mode = GET_MODE (op);
90:
91: if (CONSTANT_P (op))
92: return ((GET_MODE (op) == VOIDmode || GET_MODE (op) == mode)
93: && LEGITIMATE_CONSTANT_P (op));
94:
95: /* Except for certain constants with VOIDmode, already checked for,
96: OP's mode must match MODE if MODE specifies a mode. */
97:
98: if (GET_MODE (op) != mode)
99: return 0;
100:
101: while (code == SUBREG)
102: {
103: op = SUBREG_REG (op);
104: code = GET_CODE (op);
105: #if 0
106: /* No longer needed, since (SUBREG (MEM...))
107: will load the MEM into a reload reg in the MEM's own mode. */
108: mode_altering_drug = 1;
109: #endif
110: }
111: if (code == REG)
112: return 1;
113: if (code == CONST_DOUBLE)
114: return LEGITIMATE_CONSTANT_P (op);
115: if (code == MEM)
116: {
117: register rtx y = XEXP (op, 0);
118: if (! volatile_ok && MEM_VOLATILE_P (op))
119: return 0;
120: GO_IF_NONINDEXED_ADDRESS (y, win);
121: }
122: return 0;
123:
124: win:
125: if (mode_altering_drug)
126: return ! mode_dependent_address_p (XEXP (op, 0));
127: return 1;
128: }
129:
130: int
131: has_direct_base (op)
132: rtx op;
133: {
134: if ((GET_CODE (op) == PLUS
135: && (CONSTANT_ADDRESS_P (XEXP (op, 1))
136: || CONSTANT_ADDRESS_P (XEXP (op, 0))))
137: || CONSTANT_ADDRESS_P (op))
138: return 1;
139:
140: return 0;
141: }
142:
143: int
144: has_index (op)
145: rtx op;
146: {
147: if (GET_CODE (op) == PLUS
148: && (GET_CODE (XEXP (op, 0)) == MULT
149: || (GET_CODE (XEXP (op, 1)) == MULT)))
150: return 1;
151: else
152: return 0;
153: }
154:
155: int swap_operands;
156:
157: /* weird_memory_memory -- return 1 if OP1 and OP2 can be compared (or
158: exchanged with xchw) with one instruction. If the operands need to
159: be swapped, set the global variable SWAP_OPERANDS. This function
160: silently assumes that both OP0 and OP1 are valid memory references.
161: */
162:
163: int
164: weird_memory_memory (op0, op1)
165: rtx op0, op1;
166: {
167: int ret;
168: int c;
169: enum rtx_code code0, code1;
170:
171: op0 = XEXP (op0, 0);
172: op1 = XEXP (op1, 0);
173: code0 = GET_CODE (op0);
174: code1 = GET_CODE (op1);
175:
176: swap_operands = 0;
177:
178: if (code1 == REG)
179: {
180: return 1;
181: }
182: if (code0 == REG)
183: {
184: swap_operands = 1;
185: return 1;
186: }
187: if (has_direct_base (op0) && has_direct_base (op1))
188: {
189: if (has_index (op1))
190: {
191: if (has_index (op0))
192: return 0;
193: swap_operands = 1;
194: }
195:
196: return 1;
197: }
198: return 0;
199: }
200:
201: int
202: signed_comparison (x, mode)
203: rtx x;
204: enum machine_mode mode;
205: {
206: enum rtx_code code = GET_CODE (x);
207:
208: return (code == NE || code == EQ || code == GE || code == GT || code == LE
209: || code == LT);
210: }
211:
212: char *
213: output_branch (code)
214: enum rtx_code code;
215: {
216: switch (code)
217: {
218: case NE: return "bne %l4";
219: case EQ: return "beq %l4";
220: case GE: return "bge %l4";
221: case GT: return "bgt %l4";
222: case LE: return "ble %l4";
223: case LT: return "blt %l4";
224: }
225: }
226:
227: char *
228: output_inv_branch (code)
229: enum rtx_code code;
230: {
231: switch (code)
232: {
233: case NE: return "beq %l4";
234: case EQ: return "bne %l4";
235: case GE: return "ble %l4";
236: case GT: return "blt %l4";
237: case LE: return "bge %l4";
238: case LT: return "bgt %l4";
239: }
240: }
241:
242: extern rtx force_reg ();
243: rtx test_op0, test_op1;
244:
245: rtx
246: ensure_extended (op, extop)
247: rtx op;
248: enum rtx_code extop;
249: {
250: if (GET_MODE (op) == HImode || GET_MODE (op) == QImode)
251: op = gen_rtx (extop, SImode, op);
252: op = force_reg (SImode, op);
253: return op;
254: }
255:
256: /* Sign-extend or zero-extend constant X from FROM_MODE to TO_MODE. */
257:
258: rtx
259: extend_const (x, extop, from_mode, to_mode)
260: rtx x;
261: enum rtx_code extop;
262: enum machine_mode from_mode, to_mode;
263: {
264: int val = INTVAL (x);
265: int negative = val & (1 << (GET_MODE_BITSIZE (from_mode) - 1));
266: if (from_mode == to_mode)
267: return x;
268: if (GET_MODE_BITSIZE (from_mode) == HOST_BITS_PER_INT)
269: abort ();
270: if (negative && extop == SIGN_EXTEND)
271: val = val | ((-1) << (GET_MODE_BITSIZE (from_mode)));
272: else
273: val = val & ~((-1) << (GET_MODE_BITSIZE (from_mode)));
274: if (GET_MODE_BITSIZE (to_mode) == HOST_BITS_PER_INT)
275: return gen_rtx (CONST_INT, VOIDmode, val);
276: return gen_rtx (CONST_INT, VOIDmode,
277: val & ~((-1) << (GET_MODE_BITSIZE (to_mode))));
278: }
279:
280: /* Emit rtl for a branch, as well as any delayed (integer) compare insns.
281: The compare insn to perform is determined by the global variables
282: test_op0 and test_op1. */
283:
284: void
285: extend_and_branch (extop)
286: enum rtx_code extop;
287: {
288: rtx op0, op1;
289: enum rtx_code code0, code1;
290:
291: op0 = test_op0, op1 = test_op1;
292: if (op0 == 0)
293: return;
294:
295: code0 = GET_CODE (op0);
296: if (op1 != 0)
297: code1 = GET_CODE (op1);
298: test_op0 = test_op1 = 0;
299:
300: if (op1 == 0)
301: {
302: op0 = ensure_extended (op0, extop);
303: emit_insn (gen_rtx (SET, VOIDmode, cc0_rtx, op0));
304: }
305: else
306: {
307: if (CONSTANT_P (op0) && CONSTANT_P (op1))
308: {
309: op0 = force_reg (SImode, op0);
310: op1 = force_reg (SImode, op1);
311: }
312: else if (extop == ZERO_EXTEND && GET_MODE (op0) == HImode)
313: {
314: /* Pyramids have no unsigned "cmphi" instructions. We need to
315: zero extend unsigned halfwords into temporary registers. */
316: op0 = ensure_extended (op0, extop);
317: op1 = ensure_extended (op1, extop);
318: }
319: else if (CONSTANT_P (op0))
320: {
321: op0 = extend_const (op0, extop, GET_MODE (op1), SImode);
322: op1 = ensure_extended (op1, extop);
323: }
324: else if (CONSTANT_P (op1))
325: {
326: op1 = extend_const (op1, extop, GET_MODE (op0), SImode);
327: op0 = ensure_extended (op0, extop);
328: }
329: else if (code0 == REG && code1 == REG)
330: {
331: /* I could do this case without extension, by using the virtual
332: register address (but that would lose for global regs). */
333: op0 = ensure_extended (op0, extop);
334: op1 = ensure_extended (op1, extop);
335: }
336: else if (code0 == MEM && code1 == MEM)
337: {
338: /* Load into a reg if the address combination can't be handled
339: directly. */
340: if (! weird_memory_memory (op0, op1))
341: op0 = force_reg (GET_MODE (op0), op0);
342: }
343:
344: emit_insn (gen_rtx (SET, VOIDmode, cc0_rtx,
345: gen_rtx (COMPARE, VOIDmode, op0, op1)));
346: }
347: }
348:
349: /* Return non-zero if the two single-word operations with operands[0]
350: and operands[1] for the first single-word operation, and operands[2]
351: and operands[3] for the second single-word operation, is possible to
352: combine to a double word operation.
353:
354: The criterion is whether the operands are in consecutive memory cells,
355: registers, etc. */
356:
357: int
358: movdi_possible (operands)
359: rtx operands[];
360: {
361: int cnst_diff0, cnst_diff1;
362:
363: cnst_diff0 = consecutive_operands (operands[0], operands[2]);
364: if (cnst_diff0 == 0)
365: return 0;
366:
367: cnst_diff1 = consecutive_operands (operands[1], operands[3]);
368: if (cnst_diff0 & cnst_diff1)
369: {
370: if (cnst_diff0 & 1)
371: swap_operands = 0;
372: else
373: swap_operands = 1;
374: return 1;
375: }
376: return 0;
377: }
378:
379: /* Return +1 of OP0 is a consecutive operand to OP1, -1 if OP1 is a
380: consecutive operand to OP0.
381:
382: This function is used to determine if addresses are consecutive,
383: and therefore possible to combine to fewer instructions. */
384:
385: int
386: consecutive_operands (op0, op1)
387: rtx op0, op1;
388: {
389: enum rtx_code code0, code1;
390: int cnst_diff;
391:
392: code0 = GET_CODE (op0);
393: code1 = GET_CODE (op1);
394:
395: if (CONSTANT_P (op0) && CONSTANT_P (op1))
396: {
397: if (op0 == const0_rtx)
398: if (op1 == const0_rtx)
399: return 3;
400: else
401: return 2;
402: if (op1 == const0_rtx)
403: return 1;
404: }
405:
406: if (code0 != code1)
407: return 0;
408:
409: if (code0 == REG)
410: {
411: cnst_diff = REGNO (op0) - REGNO (op1);
412: if (cnst_diff == 1)
413: return 1;
414: else if (cnst_diff == -1)
415: return 2;
416: }
417: else if (code0 == MEM)
418: {
419: cnst_diff = radr_diff (XEXP (op0, 0), XEXP (op1, 0));
420: if (cnst_diff)
421: if (cnst_diff == 4)
422: return 1;
423: else if (cnst_diff == -4)
424: return 2;
425: }
426: return 0;
427: }
428:
429: /* Return the constant difference of the rtx expressions OP0 and OP1,
430: or 0 if the y don't have a constant difference.
431:
432: This function is used to determine if addresses are consecutive,
433: and therefore possible to combine to fewer instructions. */
434:
435: int
436: radr_diff (op0, op1)
437: rtx op0, op1;
438: {
439: enum rtx_code code0, code1;
440: int cnst_diff;
441:
442: code0 = GET_CODE (op0);
443: code1 = GET_CODE (op1);
444:
445: if (code0 != code1)
446: {
447: if (code0 == PLUS)
448: {
449: if (GET_CODE (XEXP (op0, 1)) == CONST_INT
450: && rtx_equal_p (op1, XEXP (op0, 0)))
451: return INTVAL (XEXP (op0, 1));
452: }
453: else if (code1 == PLUS)
454: {
455: if (GET_CODE (XEXP (op1, 1)) == CONST_INT
456: && rtx_equal_p (op0, XEXP (op1, 0)))
457: return -INTVAL (XEXP (op1, 1));
458: }
459: return 0;
460: }
461:
462: if (code0 == CONST_INT)
463: return INTVAL (op0) - INTVAL (op1);
464:
465: if (code0 == PLUS)
466: {
467: cnst_diff = radr_diff (XEXP (op0, 0), XEXP (op1, 0));
468: if (cnst_diff)
469: return (rtx_equal_p (XEXP (op0, 1), XEXP (op1, 1)))
470: ? cnst_diff : 0;
471: cnst_diff = radr_diff (XEXP (op0, 1), XEXP (op1, 1));
472: if (cnst_diff)
473: return (rtx_equal_p (XEXP (op0, 0), XEXP (op1, 0)))
474: ? cnst_diff : 0;
475: }
476:
477: return 0;
478: }
479:
480: int
481: already_sign_extended (insn, from_mode, op)
482: rtx insn;
483: enum machine_mode from_mode;
484: rtx op;
485: {
486: rtx xinsn;
487:
488: return 0;
489:
490: #if 0
491: for (;;)
492: {
493: insn = PREV_INSN (insn);
494: if (insn == 0)
495: return 0;
496: if (GET_CODE (insn) == NOTE)
497: continue;
498: if (GET_CODE (insn) != INSN)
499: return 0;
500: xinsn = PATTERN (insn);
501:
502: if (GET_CODE (xinsn) != SET)
503: return 0;
504:
505: /* Is it another register that is set in this insn? */
506: if (GET_CODE (SET_DEST (xinsn)) != REG
507: || REGNO (SET_DEST (xinsn)) != REGNO (op))
508: continue;
509:
510: if (GET_CODE (SET_SRC (xinsn)) == SIGN_EXTEND
511: || (GET_CODE (SET_SRC (xinsn)) == MEM
512: && GET_MODE (SET_SRC (xinsn)) == from_mode))
513: return 1;
514:
515: /* Is the register modified by another operation? */
516: if (REGNO (SET_DEST (xinsn)) == REGNO (op))
517: return 0;
518: }
519: #endif
520: }
521:
522: char *
523: output_move_double (operands)
524: rtx *operands;
525: {
526: CC_STATUS_INIT;
527: if (GET_CODE (operands[1]) == CONST_DOUBLE)
528: {
529: if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT)
530: {
531: /* In an integer, the low-order word is in CONST_DOUBLE_LOW. */
532: rtx const_op = operands[1];
533: if (CONST_DOUBLE_HIGH (const_op) == 0)
534: {
535: operands[1] = gen_rtx (CONST_INT, VOIDmode,
536: CONST_DOUBLE_LOW (const_op));
537: return "movl %1,%0";
538: }
539: operands[1] = gen_rtx (CONST_INT, VOIDmode,
540: CONST_DOUBLE_HIGH (const_op));
541: output_asm_insn ("movw %1,%0", operands);
542: operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
543: operands[1] = gen_rtx (CONST_INT, VOIDmode,
544: CONST_DOUBLE_LOW (const_op));
545: return "movw %1,%0";
546: }
547: else
548: {
549: /* In a real, the low-address word is in CONST_DOUBLE_LOW. */
550: rtx const_op = operands[1];
551: if (CONST_DOUBLE_LOW (const_op) == 0)
552: {
553: operands[1] = gen_rtx (CONST_INT, VOIDmode,
554: CONST_DOUBLE_HIGH (const_op));
555: return "movl %1,%0";
556: }
557: operands[1] = gen_rtx (CONST_INT, VOIDmode,
558: CONST_DOUBLE_LOW (const_op));
559: output_asm_insn ("movw %1,%0", operands);
560: operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
561: operands[1] = gen_rtx (CONST_INT, VOIDmode,
562: CONST_DOUBLE_HIGH (const_op));
563: return "movw %1,%0";
564: }
565: }
566:
567: return "movl %1,%0";
568: }
569:
570: /* Return non-zero if the code of this rtx pattern is a relop. */
571: int
572: relop (op, mode)
573: rtx op;
574: enum machine_mode mode;
575: {
576: switch (GET_CODE (op))
577: {
578: case EQ:
579: case NE:
580: case LT:
581: case LE:
582: case GE:
583: case GT:
584: case LTU:
585: case LEU:
586: case GEU:
587: case GTU:
588: return 1;
589: }
590: return 0;
591: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.