|
|
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>
1.1.1.2 ! root 22:
1.1 root 23: extern FILE *asm_out_file;
24: #include "tree.h"
25:
26: /*
27: * Do FUNCTION_ARG.
28: * This cannot be defined as a macro on pyramids, because Pyramid Technology's
29: * C compiler dies on (several equivalent definitions of) this macro.
30: * The only way around this cc bug was to make this a function.
31: * While it would be possible to use a macro version for gcc, it seems
32: * more reliable to have a single version of the code.
33: */
34: void *
35: pyr_function_arg(cum, mode, type, named)
36: CUMULATIVE_ARGS cum;
37: enum machine_mode mode;
38: tree type;
39: {
40: return (void *)(FUNCTION_ARG_HELPER (cum, mode,type,named));
41: }
42:
43: /* Do the hard part of PARAM_SAFE_FOR_REG_P.
44: * This cannot be defined as a macro on pyramids, because Pyramid Technology's
45: * C compiler dies on (several equivalent definitions of) this macro.
46: * The only way around this cc bug was to make this a function.
47: */
48: int
49: inner_param_safe_helper (type)
50: tree type;
51: {
52: return (INNER_PARAM_SAFE_HELPER(type));
53: }
54:
55:
56: /* Return 1 if OP is a non-indexed operand of mode MODE.
57: This is either a register reference, a memory reference,
58: or a constant. In the case of a memory reference, the address
59: is checked to make sure it isn't indexed.
60:
61: Register and memory references must have mode MODE in order to be valid,
62: but some constants have no machine mode and are valid for any mode.
63:
64: If MODE is VOIDmode, OP is checked for validity for whatever mode
65: it has.
66:
67: The main use of this function is as a predicate in match_operand
68: expressions in the machine description.
69:
70: It is useful to compare this with general_operand(). They should
71: be identical except for one line.
72:
73: This function seems necessary because of the non-orthogonality of
74: Pyramid insns.
75: For any 2-operand insn, and any combination of operand modes,
76: if indexing is valid for the isn's second operand, it is invalid
77: for the first operand to be indexed. */
78:
79: extern int volatile_ok;
80:
81: int
82: nonindexed_operand(op, mode)
83: register rtx op;
84: enum machine_mode mode;
85: {
1.1.1.2 ! root 86: register RTX_CODE code = GET_CODE (op);
1.1 root 87: int mode_altering_drug = 0;
88:
89: if (mode == VOIDmode)
90: mode = GET_MODE (op);
91:
92: if (CONSTANT_P (op))
93: return ((GET_MODE (op) == VOIDmode || GET_MODE (op) == mode)
94: && LEGITIMATE_CONSTANT_P (op));
95:
96: /* Except for certain constants with VOIDmode, already checked for,
97: OP's mode must match MODE if MODE specifies a mode. */
98:
99: if (GET_MODE (op) != mode)
100: return 0;
101:
102: while (code == SUBREG)
103: {
104: op = SUBREG_REG (op);
105: code = GET_CODE (op);
106: #if 0
107: /* No longer needed, since (SUBREG (MEM...))
108: will load the MEM into a reload reg in the MEM's own mode. */
109: mode_altering_drug = 1;
110: #endif
111: }
112: if (code == REG)
113: return 1;
114: if (code == CONST_DOUBLE)
115: return LEGITIMATE_CONSTANT_P (op);
116: if (code == MEM)
117: {
118: register rtx y = XEXP (op, 0);
119: if (! volatile_ok && MEM_VOLATILE_P (op))
120: return 0;
121: GO_IF_NONINDEXED_ADDRESS (y, win);
122: }
123: return 0;
124:
125: win:
126: if (mode_altering_drug)
127: return ! mode_dependent_address_p (XEXP (op, 0));
128: return 1;
129: }
130:
1.1.1.2 ! root 131: /* Return non-zero if the rtx OP has an immediate component. An
! 132: immediate component or additive term equal to zero is rejected
! 133: due to assembler problems. */
! 134:
1.1 root 135: int
136: has_direct_base (op)
137: rtx op;
138: {
1.1.1.2 ! root 139: if ((CONSTANT_ADDRESS_P (op)
! 140: && op != const0_rtx)
! 141: || (GET_CODE (op) == PLUS
! 142: && ((CONSTANT_ADDRESS_P (XEXP (op, 1))
! 143: && XEXP (op, 1) != const0_rtx)
! 144: || (CONSTANT_ADDRESS_P (XEXP (op, 0))
! 145: && XEXP (op, 0) != const0_rtx))))
1.1 root 146: return 1;
147:
148: return 0;
149: }
150:
151: int
152: has_index (op)
153: rtx op;
154: {
155: if (GET_CODE (op) == PLUS
156: && (GET_CODE (XEXP (op, 0)) == MULT
157: || (GET_CODE (XEXP (op, 1)) == MULT)))
158: return 1;
159: else
160: return 0;
161: }
162:
163: int swap_operands;
164:
165: /* weird_memory_memory -- return 1 if OP1 and OP2 can be compared (or
166: exchanged with xchw) with one instruction. If the operands need to
167: be swapped, set the global variable SWAP_OPERANDS. This function
168: silently assumes that both OP0 and OP1 are valid memory references.
169: */
170:
171: int
172: weird_memory_memory (op0, op1)
173: rtx op0, op1;
174: {
175: int ret;
176: int c;
1.1.1.2 ! root 177: RTX_CODE code0, code1;
1.1 root 178:
179: op0 = XEXP (op0, 0);
180: op1 = XEXP (op1, 0);
181: code0 = GET_CODE (op0);
182: code1 = GET_CODE (op1);
183:
184: swap_operands = 0;
185:
1.1.1.2 ! root 186: if (code1 == REG || code1 == SUBREG)
1.1 root 187: {
188: return 1;
189: }
1.1.1.2 ! root 190: if (code0 == REG || code0 == SUBREG)
1.1 root 191: {
192: swap_operands = 1;
193: return 1;
194: }
195: if (has_direct_base (op0) && has_direct_base (op1))
196: {
197: if (has_index (op1))
198: {
199: if (has_index (op0))
200: return 0;
201: swap_operands = 1;
202: }
203:
204: return 1;
205: }
206: return 0;
207: }
208:
209: int
210: signed_comparison (x, mode)
211: rtx x;
212: enum machine_mode mode;
213: {
1.1.1.2 ! root 214: return ! TRULY_UNSIGNED_COMPARE_P (GET_CODE (x));
1.1 root 215: }
216:
217: extern rtx force_reg ();
218: rtx test_op0, test_op1;
1.1.1.2 ! root 219: enum machine_mode test_mode;
1.1 root 220:
221: /* Sign-extend or zero-extend constant X from FROM_MODE to TO_MODE. */
222:
223: rtx
224: extend_const (x, extop, from_mode, to_mode)
225: rtx x;
1.1.1.2 ! root 226: RTX_CODE extop;
1.1 root 227: enum machine_mode from_mode, to_mode;
228: {
1.1.1.2 ! root 229: int val;
! 230: int negative;
1.1 root 231: if (from_mode == to_mode)
232: return x;
1.1.1.2 ! root 233: if (GET_CODE (x) != CONST_INT)
! 234: abort ();
! 235: val = INTVAL (x);
! 236: negative = val & (1 << (GET_MODE_BITSIZE (from_mode) - 1));
1.1 root 237: if (GET_MODE_BITSIZE (from_mode) == HOST_BITS_PER_INT)
238: abort ();
239: if (negative && extop == SIGN_EXTEND)
240: val = val | ((-1) << (GET_MODE_BITSIZE (from_mode)));
241: else
242: val = val & ~((-1) << (GET_MODE_BITSIZE (from_mode)));
243: if (GET_MODE_BITSIZE (to_mode) == HOST_BITS_PER_INT)
244: return gen_rtx (CONST_INT, VOIDmode, val);
245: return gen_rtx (CONST_INT, VOIDmode,
246: val & ~((-1) << (GET_MODE_BITSIZE (to_mode))));
247: }
248:
1.1.1.2 ! root 249: rtx
! 250: ensure_extended (op, extop, from_mode)
! 251: rtx op;
! 252: RTX_CODE extop;
! 253: enum machine_mode from_mode;
! 254: {
! 255: if (GET_CODE (op) == CONST_INT)
! 256: return extend_const (op, extop, from_mode, SImode);
! 257: else
! 258: return force_reg (SImode, gen_rtx (extop, SImode, op));
! 259: }
! 260:
1.1 root 261: /* Emit rtl for a branch, as well as any delayed (integer) compare insns.
262: The compare insn to perform is determined by the global variables
263: test_op0 and test_op1. */
264:
265: void
266: extend_and_branch (extop)
1.1.1.2 ! root 267: RTX_CODE extop;
1.1 root 268: {
269: rtx op0, op1;
1.1.1.2 ! root 270: RTX_CODE code0, code1;
1.1 root 271:
272: op0 = test_op0, op1 = test_op1;
273: if (op0 == 0)
274: return;
275:
276: code0 = GET_CODE (op0);
277: if (op1 != 0)
278: code1 = GET_CODE (op1);
279: test_op0 = test_op1 = 0;
280:
281: if (op1 == 0)
282: {
1.1.1.2 ! root 283: op0 = ensure_extended (op0, extop, test_mode);
1.1 root 284: emit_insn (gen_rtx (SET, VOIDmode, cc0_rtx, op0));
285: }
286: else
287: {
288: if (CONSTANT_P (op0) && CONSTANT_P (op1))
289: {
1.1.1.2 ! root 290: op0 = ensure_extended (op0, extop, test_mode);
! 291: op1 = ensure_extended (op1, extop, test_mode);
1.1 root 292: }
1.1.1.2 ! root 293: else if (extop == ZERO_EXTEND && test_mode == HImode)
1.1 root 294: {
295: /* Pyramids have no unsigned "cmphi" instructions. We need to
296: zero extend unsigned halfwords into temporary registers. */
1.1.1.2 ! root 297: op0 = ensure_extended (op0, extop, test_mode);
! 298: op1 = ensure_extended (op1, extop, test_mode);
1.1 root 299: }
300: else if (CONSTANT_P (op0))
301: {
1.1.1.2 ! root 302: op0 = ensure_extended (op0, extop, test_mode);
! 303: op1 = ensure_extended (op1, extop, test_mode);
1.1 root 304: }
305: else if (CONSTANT_P (op1))
306: {
1.1.1.2 ! root 307: op1 = ensure_extended (op1, extop, test_mode);
! 308: op0 = ensure_extended (op0, extop, test_mode);
1.1 root 309: }
1.1.1.2 ! root 310: else if ((code0 == REG || code0 == SUBREG)
! 311: && (code1 == REG || code1 == SUBREG))
1.1 root 312: {
313: /* I could do this case without extension, by using the virtual
314: register address (but that would lose for global regs). */
1.1.1.2 ! root 315: op0 = ensure_extended (op0, extop, test_mode);
! 316: op1 = ensure_extended (op1, extop, test_mode);
1.1 root 317: }
318: else if (code0 == MEM && code1 == MEM)
319: {
320: /* Load into a reg if the address combination can't be handled
321: directly. */
322: if (! weird_memory_memory (op0, op1))
1.1.1.2 ! root 323: op0 = force_reg (test_mode, op0);
1.1 root 324: }
325:
326: emit_insn (gen_rtx (SET, VOIDmode, cc0_rtx,
327: gen_rtx (COMPARE, VOIDmode, op0, op1)));
328: }
329: }
330:
1.1.1.2 ! root 331: /* Return non-zero if the two single-word moves with operands[0]
! 332: and operands[1] for the first single-word move, and operands[2]
! 333: and operands[3] for the second single-word move, is possible to
! 334: combine to a double word move.
1.1 root 335:
336: The criterion is whether the operands are in consecutive memory cells,
337: registers, etc. */
338:
339: int
340: movdi_possible (operands)
341: rtx operands[];
342: {
343: int cnst_diff0, cnst_diff1;
1.1.1.2 ! root 344: RTX_CODE code0 = GET_CODE (operands[0]);
! 345: RTX_CODE code1 = GET_CODE (operands[1]);
! 346:
! 347: /* Don't dare to combine (possibly overlapping) memory -> memory moves. */
! 348: /* It would be possible to detect the cases where we dare, by using
! 349: constant_diff (operands[0], operands[1])!!! */
! 350: if (code0 == MEM && code1 == MEM)
! 351: return 0;
1.1 root 352:
353: cnst_diff0 = consecutive_operands (operands[0], operands[2]);
354: if (cnst_diff0 == 0)
355: return 0;
356:
357: cnst_diff1 = consecutive_operands (operands[1], operands[3]);
1.1.1.2 ! root 358: if (cnst_diff1 == 0)
! 359: return 0;
! 360:
1.1 root 361: if (cnst_diff0 & cnst_diff1)
362: {
1.1.1.2 ! root 363: /* The source and destination operands are consecutive. */
! 364:
! 365: /* If the first move writes into the source of the second move,
! 366: we cannot combine. */
! 367: if ((code0 == REG
! 368: && reg_overlap_mentioned_p (operands[0], operands[3]))
! 369: || (code0 == SUBREG
! 370: && subreg_overlap_mentioned_p (operands[0], operands[3])))
! 371: return 0;
! 372:
1.1 root 373: if (cnst_diff0 & 1)
1.1.1.2 ! root 374: /* operands[0],[1] has higher addresses than operands[2],[3]. */
1.1 root 375: swap_operands = 0;
376: else
1.1.1.2 ! root 377: /* operands[0],[1] has lower addresses than operands[2],[3]. */
1.1 root 378: swap_operands = 1;
379: return 1;
380: }
381: return 0;
382: }
383:
1.1.1.2 ! root 384: /* Like reg_overlap_mentioned_p, but accepts a subreg rtx instead
! 385: of a reg. */
! 386:
! 387: int
! 388: subreg_overlap_mentioned_p (subreg, x)
! 389: rtx subreg, x;
! 390: {
! 391: rtx reg = SUBREG_REG (subreg);
! 392: int regno = REGNO (reg) + SUBREG_WORD (subreg);
! 393: int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (subreg));
! 394: return refers_to_regno_p (regno, endregno, x, 0);
! 395: }
! 396:
! 397: /* Return 1 if OP0 is a consecutive operand to OP1, 2 if OP1 is a
1.1 root 398: consecutive operand to OP0.
399:
400: This function is used to determine if addresses are consecutive,
401: and therefore possible to combine to fewer instructions. */
402:
403: int
404: consecutive_operands (op0, op1)
405: rtx op0, op1;
406: {
1.1.1.2 ! root 407: RTX_CODE code0, code1;
1.1 root 408: int cnst_diff;
1.1.1.2 ! root 409: int regno_off0, regno_off1;
1.1 root 410:
411: code0 = GET_CODE (op0);
412: code1 = GET_CODE (op1);
413:
1.1.1.2 ! root 414: regno_off0 = 0;
! 415: if (code0 == SUBREG)
1.1 root 416: {
1.1.1.2 ! root 417: if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0))) <= UNITS_PER_WORD)
! 418: return 0;
! 419: regno_off0 = SUBREG_WORD (op0);
! 420: op0 = SUBREG_REG (op0);
! 421: code0 = REG;
! 422: }
! 423:
! 424: regno_off1 = 0;
! 425: if (code1 == SUBREG)
! 426: {
! 427: if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1))) <= UNITS_PER_WORD)
! 428: return 0;
! 429: regno_off1 = SUBREG_WORD (op1);
! 430: op1 = SUBREG_REG (op1);
! 431: code1 = REG;
1.1 root 432: }
433:
434: if (code0 != code1)
435: return 0;
436:
1.1.1.2 ! root 437: switch (code0)
1.1 root 438: {
1.1.1.2 ! root 439: case CONST_INT:
! 440: /* Cannot permit any symbolic constants, even if the consecutive
! 441: operand is 0, since a movl really performs sign extension. */
! 442: if (code1 != CONST_INT)
! 443: return 0;
! 444: if ((INTVAL (op0) == 0 && INTVAL (op1) == 0)
! 445: || (INTVAL (op0) == -1 && INTVAL (op1) == -1))
! 446: return 3;
! 447: if ((INTVAL (op0) == 0 && INTVAL (op1) > 0)
! 448: || (INTVAL (op0) == -1 && INTVAL (op1) < 0))
! 449: return 2;
! 450: if ((INTVAL (op1) == 0 && INTVAL (op0) > 0)
! 451: || (INTVAL (op1) == -1 && INTVAL (op0) < 0))
1.1 root 452: return 1;
1.1.1.2 ! root 453: break;
! 454:
! 455: case REG:
! 456: regno_off0 = REGNO (op0) + regno_off0;
! 457: regno_off1 = REGNO (op1) + regno_off1;
! 458:
! 459: cnst_diff = regno_off0 - regno_off1;
! 460: if (cnst_diff == 1)
! 461: {
! 462: /* movl with the highest numbered parameter (local) register as
! 463: source or destination, doesn't wrap to the lowest numbered local
! 464: (temporary) register. */
! 465:
! 466: if (regno_off0 % 16 != 0)
! 467: return 1;
! 468: else
! 469: return 0;
! 470: }
1.1 root 471: else if (cnst_diff == -1)
1.1.1.2 ! root 472: {
! 473: if (regno_off1 % 16 != 0)
! 474: return 2;
! 475: else
! 476: return 0;
! 477: }
! 478: break;
! 479:
! 480: case MEM:
! 481: op0 = XEXP (op0, 0);
! 482: op1 = XEXP (op1, 0);
! 483: if (GET_CODE (op0) == CONST)
! 484: op0 = XEXP (op0, 0);
! 485: if (GET_CODE (op1) == CONST)
! 486: op1 = XEXP (op1, 0);
! 487:
! 488: cnst_diff = constant_diff (op0, op1);
1.1 root 489: if (cnst_diff)
1.1.1.2 ! root 490: {
! 491: if (cnst_diff == 4)
! 492: return 1;
! 493: else if (cnst_diff == -4)
! 494: return 2;
! 495: }
! 496: break;
1.1 root 497: }
498: return 0;
499: }
500:
501: /* Return the constant difference of the rtx expressions OP0 and OP1,
1.1.1.2 ! root 502: or 0 if they don't have a constant difference.
1.1 root 503:
504: This function is used to determine if addresses are consecutive,
505: and therefore possible to combine to fewer instructions. */
506:
507: int
1.1.1.2 ! root 508: constant_diff (op0, op1)
1.1 root 509: rtx op0, op1;
510: {
1.1.1.2 ! root 511: RTX_CODE code0, code1;
1.1 root 512: int cnst_diff;
513:
514: code0 = GET_CODE (op0);
515: code1 = GET_CODE (op1);
516:
517: if (code0 != code1)
518: {
519: if (code0 == PLUS)
520: {
521: if (GET_CODE (XEXP (op0, 1)) == CONST_INT
522: && rtx_equal_p (op1, XEXP (op0, 0)))
523: return INTVAL (XEXP (op0, 1));
524: }
525: else if (code1 == PLUS)
526: {
527: if (GET_CODE (XEXP (op1, 1)) == CONST_INT
528: && rtx_equal_p (op0, XEXP (op1, 0)))
529: return -INTVAL (XEXP (op1, 1));
530: }
531: return 0;
532: }
533:
534: if (code0 == CONST_INT)
535: return INTVAL (op0) - INTVAL (op1);
536:
537: if (code0 == PLUS)
538: {
1.1.1.2 ! root 539: cnst_diff = constant_diff (XEXP (op0, 0), XEXP (op1, 0));
1.1 root 540: if (cnst_diff)
541: return (rtx_equal_p (XEXP (op0, 1), XEXP (op1, 1)))
542: ? cnst_diff : 0;
1.1.1.2 ! root 543: cnst_diff = constant_diff (XEXP (op0, 1), XEXP (op1, 1));
1.1 root 544: if (cnst_diff)
545: return (rtx_equal_p (XEXP (op0, 0), XEXP (op1, 0)))
546: ? cnst_diff : 0;
547: }
548:
549: return 0;
550: }
551:
552: int
553: already_sign_extended (insn, from_mode, op)
554: rtx insn;
555: enum machine_mode from_mode;
556: rtx op;
557: {
1.1.1.2 ! root 558: rtx xinsn, xdest, xsrc;
1.1 root 559:
560: for (;;)
561: {
562: insn = PREV_INSN (insn);
563: if (insn == 0)
564: return 0;
1.1.1.2 ! root 565: if (GET_CODE (insn) == NOTE || GET_CODE (insn) == JUMP_INSN)
! 566: continue;
! 567: if (GET_CODE (insn) == CALL_INSN && ! call_used_regs[REGNO (op)])
1.1 root 568: continue;
569: if (GET_CODE (insn) != INSN)
570: return 0;
571: xinsn = PATTERN (insn);
572:
573: if (GET_CODE (xinsn) != SET)
574: return 0;
575:
1.1.1.2 ! root 576: xdest = SET_DEST (xinsn);
! 577: xsrc = SET_SRC (xinsn);
! 578:
! 579: if (GET_CODE (xdest) == SUBREG)
! 580: abort ();
! 581:
! 582: if ( ! REG_P (xdest))
1.1 root 583: continue;
584:
1.1.1.2 ! root 585: if (REGNO (op) == REGNO (xdest)
! 586: && ((GET_CODE (xsrc) == SIGN_EXTEND
! 587: && GET_MODE (XEXP (xsrc, 0)) == from_mode)
! 588: || (GET_CODE (xsrc) == MEM
! 589: && GET_MODE (xsrc) == from_mode)))
1.1 root 590: return 1;
591:
1.1.1.2 ! root 592: /* The register is modified by another operation. */
! 593: if (reg_overlap_mentioned_p (xdest, op))
1.1 root 594: return 0;
595: }
596: }
597:
598: char *
599: output_move_double (operands)
600: rtx *operands;
601: {
602: if (GET_CODE (operands[1]) == CONST_DOUBLE)
603: {
604: if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT)
605: {
606: /* In an integer, the low-order word is in CONST_DOUBLE_LOW. */
607: rtx const_op = operands[1];
1.1.1.2 ! root 608: if ((CONST_DOUBLE_HIGH (const_op) == 0
! 609: && CONST_DOUBLE_LOW (const_op) >= 0)
! 610: || (CONST_DOUBLE_HIGH (const_op) == -1
! 611: && CONST_DOUBLE_LOW (const_op) < 0))
1.1 root 612: {
613: operands[1] = gen_rtx (CONST_INT, VOIDmode,
614: CONST_DOUBLE_LOW (const_op));
615: return "movl %1,%0";
616: }
617: operands[1] = gen_rtx (CONST_INT, VOIDmode,
618: CONST_DOUBLE_HIGH (const_op));
619: output_asm_insn ("movw %1,%0", operands);
620: operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
621: operands[1] = gen_rtx (CONST_INT, VOIDmode,
622: CONST_DOUBLE_LOW (const_op));
623: return "movw %1,%0";
624: }
625: else
626: {
627: /* In a real, the low-address word is in CONST_DOUBLE_LOW. */
628: rtx const_op = operands[1];
1.1.1.2 ! root 629: if ((CONST_DOUBLE_LOW (const_op) == 0
! 630: && CONST_DOUBLE_HIGH (const_op) >= 0)
! 631: || (CONST_DOUBLE_LOW (const_op) == -1
! 632: && CONST_DOUBLE_HIGH (const_op) < 0))
1.1 root 633: {
634: operands[1] = gen_rtx (CONST_INT, VOIDmode,
635: CONST_DOUBLE_HIGH (const_op));
636: return "movl %1,%0";
637: }
638: operands[1] = gen_rtx (CONST_INT, VOIDmode,
639: CONST_DOUBLE_LOW (const_op));
640: output_asm_insn ("movw %1,%0", operands);
641: operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
642: operands[1] = gen_rtx (CONST_INT, VOIDmode,
643: CONST_DOUBLE_HIGH (const_op));
644: return "movw %1,%0";
645: }
646: }
647:
648: return "movl %1,%0";
649: }
650:
1.1.1.2 ! root 651: /* Output a shift insns, after having reduced integer arguments to
! 652: avoid as warnings. */
! 653:
! 654: char *
! 655: output_shift (pattern, op2, mod)
! 656: char *pattern;
! 657: rtx op2;
! 658: int mod;
! 659: {
! 660: if (GET_CODE (op2) == CONST_INT)
! 661: {
! 662: int cnt = INTVAL (op2) % mod;
! 663: if (cnt == 0)
! 664: {
! 665: cc_status = cc_prev_status;
! 666: return "";
! 667: }
! 668: op2 = gen_rtx (CONST_INT, VOIDmode, cnt);
! 669: }
! 670: return pattern;
! 671: }
! 672:
1.1 root 673: /* Return non-zero if the code of this rtx pattern is a relop. */
1.1.1.2 ! root 674:
1.1 root 675: int
676: relop (op, mode)
677: rtx op;
678: enum machine_mode mode;
679: {
680: switch (GET_CODE (op))
681: {
682: case EQ:
683: case NE:
684: case LT:
685: case LE:
686: case GE:
687: case GT:
688: case LTU:
689: case LEU:
690: case GEU:
691: case GTU:
692: return 1;
693: }
694: return 0;
695: }
1.1.1.2 ! root 696:
! 697: void
! 698: notice_update_cc (EXP, INSN)
! 699: rtx EXP, INSN;
! 700: {
! 701: switch (GET_CODE (EXP))
! 702: {
! 703: case SET:
! 704: switch (GET_CODE (SET_DEST (EXP)))
! 705: {
! 706: case CC0:
! 707: cc_status.mdep = 0;
! 708: cc_status.flags = 0;
! 709: cc_status.value1 = 0;
! 710: cc_status.value2 = SET_SRC (EXP);
! 711: break;
! 712:
! 713: case PC:
! 714: break;
! 715:
! 716: case REG:
! 717: switch (GET_CODE (SET_SRC (EXP)))
! 718: {
! 719: case CALL:
! 720: goto call;
! 721: case MEM:
! 722: if (GET_MODE (SET_SRC (EXP)) == QImode
! 723: || GET_MODE (SET_SRC (EXP)) == HImode)
! 724: {
! 725: cc_status.mdep = 0;
! 726: cc_status.flags = CC_NO_OVERFLOW;
! 727: cc_status.value1 = SET_DEST (EXP);
! 728: cc_status.value2 = SET_SRC (EXP);
! 729: break;
! 730: }
! 731: /* else: Fall through. */
! 732: case CONST_INT:
! 733: case SYMBOL_REF:
! 734: case LABEL_REF:
! 735: case CONST:
! 736: case CONST_DOUBLE:
! 737: case REG:
! 738: if (cc_status.value1
! 739: && reg_overlap_mentioned_p (SET_DEST (EXP),
! 740: cc_status.value1))
! 741: cc_status.value1 = 0;
! 742: if (cc_status.value2
! 743: && reg_overlap_mentioned_p (SET_DEST (EXP),
! 744: cc_status.value2))
! 745: cc_status.value2 = 0;
! 746: break;
! 747:
! 748: case UDIV:
! 749: case UMOD:
! 750: cc_status.mdep = CC_VALID_FOR_UNSIGNED;
! 751: cc_status.flags = CC_NO_OVERFLOW;
! 752: cc_status.value1 = SET_DEST (EXP);
! 753: cc_status.value2 = SET_SRC (EXP);
! 754: break;
! 755: default:
! 756: cc_status.mdep = 0;
! 757: cc_status.flags = CC_NO_OVERFLOW;
! 758: cc_status.value1 = SET_DEST (EXP);
! 759: cc_status.value2 = SET_SRC (EXP);
! 760: break;
! 761: }
! 762: break;
! 763:
! 764: case MEM:
! 765: switch (GET_CODE (SET_SRC (EXP)))
! 766: {
! 767: case REG:
! 768: if (GET_MODE (SET_SRC (EXP)) == QImode
! 769: || GET_MODE (SET_SRC (EXP)) == HImode)
! 770: {
! 771: cc_status.flags = CC_NO_OVERFLOW;
! 772: cc_status.value1 = SET_DEST (EXP);
! 773: cc_status.value2 = SET_SRC (EXP);
! 774: cc_status.mdep = 0;
! 775: break;
! 776: }
! 777: /* else: Fall through. */
! 778: case CONST_INT:
! 779: case SYMBOL_REF:
! 780: case LABEL_REF:
! 781: case CONST:
! 782: case CONST_DOUBLE:
! 783: case MEM:
! 784: /* Need to forget cc_status about memory positions each
! 785: time a memory store is made, even if the memory store
! 786: insns in question doesn't modify the condition codes. */
! 787: if (cc_status.value1 &&
! 788: GET_CODE (cc_status.value1) == MEM)
! 789: cc_status.value1 = 0;
! 790: if (cc_status.value2 &&
! 791: GET_CODE (cc_status.value2) == MEM)
! 792: cc_status.value2 = 0;
! 793: break;
! 794: case SIGN_EXTEND:
! 795: case FLOAT_EXTEND:
! 796: case FLOAT_TRUNCATE:
! 797: case FLOAT:
! 798: case FIX:
! 799: cc_status.flags = CC_NO_OVERFLOW;
! 800: cc_status.value1 = SET_DEST (EXP);
! 801: cc_status.value2 = SET_SRC (EXP);
! 802: cc_status.mdep = 0;
! 803: break;
! 804:
! 805: default:
! 806: abort ();
! 807: }
! 808: break;
! 809:
! 810: default:
! 811: abort ();
! 812: }
! 813: break;
! 814:
! 815: case CALL:
! 816: call:
! 817: CC_STATUS_INIT;
! 818: break;
! 819: /* Do calls preserve the condition codes? (At least forget
! 820: cc_status expressions if they refer to registers
! 821: not preserved across calls. Also forget expressions
! 822: about memory contents.) */
! 823: if (cc_status.value1
! 824: && (refers_to_regno_p (PYR_TREG (0), PYR_TREG (15),
! 825: cc_status.value1, 0)
! 826: || GET_CODE (cc_status.value1) == MEM))
! 827: cc_status.value1 = 0;
! 828: if (cc_status.value2
! 829: && (refers_to_regno_p (PYR_TREG (0), PYR_TREG (15),
! 830: cc_status.value2, 0)
! 831: || GET_CODE (cc_status.value2) == MEM))
! 832: cc_status.value2 = 0;
! 833: break;
! 834:
! 835: default:
! 836: CC_STATUS_INIT;
! 837: }
! 838: }
! 839:
! 840: void
! 841: forget_cc_if_dependent (op)
! 842: rtx op;
! 843: {
! 844: cc_status = cc_prev_status;
! 845: if (cc_status.value1 && reg_overlap_mentioned_p (op, cc_status.value1))
! 846: cc_status.value1 = 0;
! 847: if (cc_status.value2 && reg_overlap_mentioned_p (op, cc_status.value2))
! 848: cc_status.value2 = 0;
! 849: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.