|
|
1.1 root 1: /* Output routines for GCC for ARM/RISCiX.
2: Copyright (C) 1991, 1993 Free Software Foundation, Inc.
3: Contributed by Pieter `Tiggr' Schoenmakers ([email protected])
4: and Martin Simmons (@harleqn.co.uk).
5: More major hacks by Richard Earnshaw ([email protected])
6:
7: This file is part of GNU CC.
8:
9: GNU CC is free software; you can redistribute it and/or modify
10: it under the terms of the GNU General Public License as published by
11: the Free Software Foundation; either version 2, or (at your option)
12: any later version.
13:
14: GNU CC is distributed in the hope that it will be useful,
15: but WITHOUT ANY WARRANTY; without even the implied warranty of
16: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17: GNU General Public License for more details.
18:
19: You should have received a copy of the GNU General Public License
20: along with GNU CC; see the file COPYING. If not, write to
21: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
22:
23: #include <stdio.h>
24: #include "assert.h"
25: #include "config.h"
26: #include "rtl.h"
27: #include "regs.h"
28: #include "hard-reg-set.h"
29: #include "real.h"
30: #include "insn-config.h"
31: #include "conditions.h"
32: #include "insn-flags.h"
33: #include "output.h"
34: #include "insn-attr.h"
35: #include "flags.h"
36: #include "reload.h"
37:
38: /* The maximum number of insns skipped which will be conditionalised if
39: possible. */
40: #define MAX_INSNS_SKIPPED 5
41:
42: /* Some function declarations. */
43: extern FILE *asm_out_file;
44: extern char *output_multi_immediate ();
45: extern char *arm_output_asm_insn ();
46: extern void arm_increase_location ();
47:
48: /* Define the information needed to generate branch insns. This is
49: stored from the compare operation. */
50:
51: rtx arm_compare_op0, arm_compare_op1;
52: int arm_compare_fp;
53:
54: /* What type of cpu are we compiling for? */
55:
56: enum processor_type arm_cpu;
57:
58: /* In case of a PRE_INC, POST_INC, PRE_DEC, POST_DEC memory reference, we
59: must report the mode of the memory reference from PRINT_OPERAND to
60: PRINT_OPERAND_ADDRESS. */
61: int output_memory_reference_mode;
62:
63: /* Nonzero if the prologue must setup `fp'. */
64: int current_function_anonymous_args;
65:
66: /* Location counter of .text segment. */
67: int arm_text_location = 0;
68:
69: /* Set to one if we think that lr is only saved because of subroutine calls,
70: but all of these can be `put after' return insns */
71: int lr_save_eliminated;
72:
73: /* A hash table is used to store text segment labels and their associated
74: offset from the start of the text segment. */
75: struct label_offset
76: {
77: char *name;
78: int offset;
79: struct label_offset *cdr;
80: };
81:
82: #define LABEL_HASH_SIZE 257
83:
84: static struct label_offset *offset_table[LABEL_HASH_SIZE];
85:
86: /* Set to 1 when a return insn is output, this means that the epilogue
87: is not needed. */
88:
89: static int return_used_this_function;
90:
91: /* For an explanation of these variables, see final_prescan_insn below. */
92: int arm_ccfsm_state;
93: int arm_current_cc;
94: rtx arm_target_insn;
95: int arm_target_label;
96:
97: /* Return 1 if it is possible to return using a single instruction */
98:
99: int
100: use_return_insn ()
101: {
102: int regno;
103:
104: if (!reload_completed ||current_function_pretend_args_size
105: || current_function_anonymous_args
106: || (get_frame_size () && !(TARGET_APCS || frame_pointer_needed)))
107: return 0;
108:
109: /* Can't be done if any of the FPU regs are pushed, since this also
110: requires an insn */
111: for (regno = 20; regno < 24; regno++)
112: if (regs_ever_live[regno])
113: return 0;
114:
115: return 1;
116: }
117:
118: /* Return the number of mov instructions needed to get the constant VALUE into
119: a register. */
120:
121: int
122: arm_const_nmoves (value)
123: register int value;
124: {
125: register int i;
126:
127: if (value == 0)
128: return (1);
129: for (i = 0; value; i++, value &= ~0xff)
130: while ((value & 3) == 0)
131: value = (value >> 2) | ((value & 3) << 30);
132: return (i);
133: } /* arm_const_nmoves */
134:
135:
136: /* Return TRUE if int I is a valid immediate ARM constant. */
137:
138: int
139: const_ok_for_arm (i)
140: HOST_WIDE_INT i;
141: {
142: unsigned HOST_WIDE_INT mask = ~0xFF;
143:
144: do
145: {
146: if ((i & mask & (unsigned HOST_WIDE_INT) 0xffffffff) == 0)
147: return(TRUE);
148: mask =
149: (mask << 2) | ((mask & (unsigned HOST_WIDE_INT) 0xffffffff)
150: >> (32 - 2)) | ~((unsigned HOST_WIDE_INT) 0xffffffff);
151: } while (mask != ~0xFF);
152:
153: return (FALSE);
154: } /* const_ok_for_arm */
155:
156: /* This code has been fixed for cross compilation. */
157:
158: static int fpa_consts_inited = 0;
159:
160: char *strings_fpa[8] = {
161: "0.0",
162: "1.0",
163: "2.0",
164: "3.0",
165: "4.0",
166: "5.0",
167: "0.5",
168: "10.0"
169: };
170:
171: static REAL_VALUE_TYPE values_fpa[8];
172:
173: static void
174: init_fpa_table ()
175: {
176: int i;
177: REAL_VALUE_TYPE r;
178:
179: for (i = 0; i < 8; i++)
180: {
181: r = REAL_VALUE_ATOF (strings_fpa[i], DFmode);
182: values_fpa[i] = r;
183: }
184: fpa_consts_inited = 1;
185: }
186:
187: /* Return TRUE if rtx X is a valid immediate FPU constant. */
188:
189: int
190: const_double_rtx_ok_for_fpu (x)
191: rtx x;
192: {
193: REAL_VALUE_TYPE r;
194: int i;
195:
196: if (!fpa_consts_inited)
197: init_fpa_table ();
198:
199: REAL_VALUE_FROM_CONST_DOUBLE (r, x);
200: if (REAL_VALUE_MINUS_ZERO (r))
201: return 0;
202: for (i = 0; i < 8; i++)
203: if (REAL_VALUES_EQUAL (r, values_fpa[i]))
204: return 1;
205: return 0;
206: } /* const_double_rtx_ok_for_fpu */
207:
208: /* Return TRUE if rtx X is a valid immediate FPU constant. */
209:
210: int
211: neg_const_double_rtx_ok_for_fpu (x)
212: rtx x;
213: {
214: REAL_VALUE_TYPE r;
215: int i;
216:
217: if (!fpa_consts_inited)
218: init_fpa_table ();
219:
220: REAL_VALUE_FROM_CONST_DOUBLE (r, x);
221: r = REAL_VALUE_NEGATE (r);
222: if (REAL_VALUE_MINUS_ZERO (r))
223: return 0;
224: for (i = 0; i < 8; i++)
225: if (REAL_VALUES_EQUAL (r, values_fpa[i]))
226: return 1;
227: return 0;
228: } /* neg_const_double_rtx_ok_for_fpu */
229:
230: /* Predicates for `match_operand' and `match_operator'. */
231:
232: /* s_register_operand is the same as register_operand, but it doesn't accept
233: (SUBREG (MEM)...). */
234:
235: int
236: s_register_operand (op, mode)
237: register rtx op;
238: enum machine_mode mode;
239: {
240: if (GET_MODE (op) != mode && mode != VOIDmode)
241: return 0;
242:
243: if (GET_CODE (op) == SUBREG)
244: {
245: op = SUBREG_REG (op);
246: }
247:
248: /* We don't consider registers whose class is NO_REGS
249: to be a register operand. */
250: return (GET_CODE (op) == REG
251: && (REGNO (op) >= FIRST_PSEUDO_REGISTER
252: || REGNO_REG_CLASS (REGNO (op)) != NO_REGS));
253: }
254:
255: /* Return 1 if OP is an item in memory, given that we are in reload. */
256:
257: int
258: reload_memory_operand (op, mode)
259: rtx op;
260: enum machine_mode mode;
261: {
262: int regno = true_regnum (op);
263:
264: return (! CONSTANT_P (op)
265: && (regno == -1
266: || (GET_CODE (op) == REG
267: && REGNO (op) >= FIRST_PSEUDO_REGISTER)));
268: }
269:
270: /* Return TRUE for valid operands for the rhs of an ARM instruction. */
271:
272: int
273: arm_rhs_operand (op, mode)
274: rtx op;
275: enum machine_mode mode;
276: {
277: return (s_register_operand (op, mode)
278: || (GET_CODE (op) == CONST_INT && const_ok_for_arm (INTVAL (op))));
279: } /* arm_rhs_operand */
280:
281: /* Return TRUE for valid operands for the rhs of an ARM instruction, or a load.
282: */
283:
284: int
285: arm_rhsm_operand (op, mode)
286: rtx op;
287: enum machine_mode mode;
288: {
289: return (s_register_operand (op, mode)
290: || (GET_CODE (op) == CONST_INT && const_ok_for_arm (INTVAL (op)))
291: || memory_operand (op, mode));
292: } /* arm_rhs_operand */
293:
294: /* Return TRUE for valid operands for the rhs of an ARM instruction, or if a
295: constant that is valid when negated. */
296:
297: int
298: arm_add_operand (op, mode)
299: rtx op;
300: enum machine_mode mode;
301: {
302: return (s_register_operand (op, mode)
303: || (GET_CODE (op) == CONST_INT
304: && (const_ok_for_arm (INTVAL (op))
305: || const_ok_for_arm (-INTVAL (op)))));
306: } /* arm_rhs_operand */
307:
308: int
309: arm_not_operand (op, mode)
310: rtx op;
311: enum machine_mode mode;
312: {
313: return (s_register_operand (op, mode)
314: || (GET_CODE (op) == CONST_INT
315: && (const_ok_for_arm (INTVAL (op))
316: || const_ok_for_arm (~INTVAL (op)))));
317: } /* arm_rhs_operand */
318:
319: /* Return TRUE for valid operands for the rhs of an FPU instruction. */
320:
321: int
322: fpu_rhs_operand (op, mode)
323: rtx op;
324: enum machine_mode mode;
325: {
326: if (s_register_operand (op, mode))
327: return(TRUE);
328: else if (GET_CODE (op) == CONST_DOUBLE)
329: return (const_double_rtx_ok_for_fpu (op));
330: else return (FALSE);
331: } /* fpu_rhs_operand */
332:
333: int
334: fpu_add_operand (op, mode)
335: rtx op;
336: enum machine_mode mode;
337: {
338: if (s_register_operand (op, mode))
339: return(TRUE);
340: else if (GET_CODE (op) == CONST_DOUBLE)
341: return const_double_rtx_ok_for_fpu (op)
342: || neg_const_double_rtx_ok_for_fpu (op);
343: return (FALSE);
344: }
345:
346: /* Return nonzero if OP is a constant power of two. */
347:
348: int
349: power_of_two_operand (op, mode)
350: rtx op;
351: enum machine_mode mode;
352: {
353: if (GET_CODE (op) == CONST_INT)
354: {
355: int value = INTVAL(op);
356: return (value != 0 && (value & (value-1)) == 0);
357: }
358: return (FALSE);
359: } /* power_of_two_operand */
360:
361: /* Return TRUE for a valid operand of a DImode operation.
362: Either: REG, CONST_DOUBLE or MEM(DImode_address).
363: Note that this disallows MEM(REG+REG), but allows
364: MEM(PRE/POST_INC/DEC(REG)). */
365:
366: int
367: di_operand (op, mode)
368: rtx op;
369: enum machine_mode mode;
370: {
371: if (s_register_operand (op, mode))
372: return (TRUE);
373:
374: switch (GET_CODE (op))
375: {
376: case CONST_DOUBLE:
377: case CONST_INT:
378: return (TRUE);
379: case MEM:
380: return (memory_address_p (DImode, XEXP (op, 0)));
381: default:
382: return (FALSE);
383: }
384: } /* di_operand */
385:
386: /* Return TRUE for valid index operands. */
387:
388: int
389: index_operand (op, mode)
390: rtx op;
391: enum machine_mode mode;
392: {
393: return (s_register_operand(op, mode)
394: || (immediate_operand (op, mode)
395: && INTVAL (op) < 4096 && INTVAL (op) > -4096));
396: } /* index_operand */
397:
398: /* Return TRUE for valid shifts by a constant. This also accepts any
399: power of two on the (somewhat overly relaxed) assumption that the
400: shift operator in this case was a mult. */
401:
402: int
403: const_shift_operand (op, mode)
404: rtx op;
405: enum machine_mode mode;
406: {
407: return (power_of_two_operand (op, mode)
408: || (immediate_operand (op, mode)
409: && (INTVAL (op) < 32 && INTVAL (op) > 0)));
410: } /* const_shift_operand */
411:
412: /* Return TRUE for arithmetic operators which can be combined with a multiply
413: (shift). */
414:
415: int
416: shiftable_operator (x, mode)
417: rtx x;
418: enum machine_mode mode;
419: {
420: if (GET_MODE (x) != mode)
421: return FALSE;
422: else
423: {
424: enum rtx_code code = GET_CODE (x);
425:
426: return (code == PLUS || code == MINUS
427: || code == IOR || code == XOR || code == AND);
428: }
429: } /* shiftable_operator */
430:
431: /* Return TRUE for shift operators. */
432:
433: int
434: shift_operator (x, mode)
435: rtx x;
436: enum machine_mode mode;
437: {
438: if (GET_MODE (x) != mode)
439: return FALSE;
440: else
441: {
442: enum rtx_code code = GET_CODE (x);
443:
444: if (code == MULT)
445: return power_of_two_operand (XEXP (x, 1));
446: return (code == ASHIFT || code == LSHIFT
447: || code == ASHIFTRT || code == LSHIFTRT);
448: }
449: } /* shift_operator */
450:
451: int equality_operator (x, mode)
452: rtx x;
453: enum machine_mode mode;
454: {
455: return (GET_CODE (x) == EQ || GET_CODE (x) == NE);
456: }
457:
458: /* Return TRUE for SMIN SMAX UMIN UMAX operators. */
459:
460: int
461: minmax_operator (x, mode)
462: rtx x;
463: enum machine_mode mode;
464: {
465: enum rtx_code code = GET_CODE (x);
466:
467: if (GET_MODE (x) != mode)
468: return FALSE;
469: return code == SMIN || code == SMAX || code == UMIN || code == UMAX;
470: } /* minmax_operator */
471:
472: /* return TRUE if x is EQ or NE */
473:
474: /* Return TRUE if this is the condition code register, if we aren't given
475: a mode, accept any class CCmode register */
476:
477: int
478: cc_register (x, mode)
479: rtx x;
480: enum machine_mode mode;
481: {
482: if (mode == VOIDmode)
483: {
484: mode = GET_MODE (x);
485: if (GET_MODE_CLASS (mode) != MODE_CC)
486: return FALSE;
487: }
488: if (mode == GET_MODE (x) && GET_CODE (x) == REG && REGNO (x) == 24)
489: return TRUE;
490: return FALSE;
491: }
492:
493: enum rtx_code
494: minmax_code (x)
495: rtx x;
496: {
497: enum rtx_code code = GET_CODE (x);
498:
499: if (code == SMAX)
500: return GE;
501: if (code == SMIN)
502: return LE;
503: if (code == UMIN)
504: return LEU;
505: if (code == UMAX)
506: return GEU;
507: abort ();
508: }
509:
510: /* Return 1 if memory locations are adjacent */
511:
512: adjacent_mem_locations (a, b)
513: rtx a, b;
514: {
515: int val0 = 0, val1 = 0;
516: int reg0, reg1;
517:
518: if ((GET_CODE (XEXP (a, 0)) == REG
519: || (GET_CODE (XEXP (a, 0)) == PLUS
520: && GET_CODE (XEXP (XEXP (a, 0), 1)) == CONST_INT))
521: && (GET_CODE (XEXP (b, 0)) == REG
522: || (GET_CODE (XEXP (b, 0)) == PLUS
523: && GET_CODE (XEXP (XEXP (b, 0), 1)) == CONST_INT)))
524: {
525: if (GET_CODE (XEXP (a, 0)) == PLUS)
526: {
527: reg0 = REGNO (XEXP (XEXP (a, 0), 0));
528: val0 = INTVAL (XEXP (XEXP (a, 0), 1));
529: }
530: else
531: reg0 = REGNO (XEXP (a, 0));
532: if (GET_CODE (XEXP (b, 0)) == PLUS)
533: {
534: reg1 = REGNO (XEXP (XEXP (b, 0), 0));
535: val1 = INTVAL (XEXP (XEXP (b, 0), 1));
536: }
537: else
538: reg1 = REGNO (XEXP (b, 0));
539: return (reg0 == reg1) && ((val1 - val0) == 4 || (val0 - val1) == 4);
540: }
541: return 0;
542: }
543:
544: /* Return 1 if OP is a load multiple operation. It is known to be
545: parallel and the first section will be tested. */
546:
547: load_multiple_operation (op, mode)
548: rtx op;
549: enum machine_mode mode;
550: {
551: int count = XVECLEN (op, 0);
552: int dest_regno;
553: rtx src_addr;
554: int i = 1, base = 0;
555: rtx elt;
556:
557: if (count <= 1
558: || GET_CODE (XVECEXP (op, 0, 0)) != SET)
559: return 0;
560:
561: /* Check to see if this might be a write-back */
562: if (GET_CODE (SET_SRC (elt = XVECEXP (op, 0, 0))) == PLUS)
563: {
564: i++;
565: base = 1;
566:
567: /* Now check it more carefully */
568: if (GET_CODE (SET_DEST (elt)) != REG
569: || GET_CODE (XEXP (SET_SRC (elt), 0)) != REG
570: || REGNO (XEXP (SET_SRC (elt), 0)) != REGNO (SET_DEST (elt))
571: || GET_CODE (XEXP (SET_SRC (elt), 1)) != CONST_INT
572: || INTVAL (XEXP (SET_SRC (elt), 1)) != (count - 2) * 4
573: || GET_CODE (XVECEXP (op, 0, count - 1)) != CLOBBER
574: || GET_CODE (XEXP (XVECEXP (op, 0, count - 1), 0)) != REG
575: || REGNO (XEXP (XVECEXP (op, 0, count - 1), 0))
576: != REGNO (SET_DEST (elt)))
577: return 0;
578: count--;
579: }
580:
581: /* Perform a quick check so we don't blow up below. */
582: if (count <= i
583: || GET_CODE (XVECEXP (op, 0, i - 1)) != SET
584: || GET_CODE (SET_DEST (XVECEXP (op, 0, i - 1))) != REG
585: || GET_CODE (SET_SRC (XVECEXP (op, 0, i - 1))) != MEM)
586: return 0;
587:
588: dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, i - 1)));
589: src_addr = XEXP (SET_SRC (XVECEXP (op, 0, i - 1)), 0);
590:
591: for (; i < count; i++)
592: {
593: rtx elt = XVECEXP (op, 0, i);
594:
595: if (GET_CODE (elt) != SET
596: || GET_CODE (SET_DEST (elt)) != REG
597: || GET_MODE (SET_DEST (elt)) != SImode
598: || REGNO (SET_DEST (elt)) != dest_regno + i - base
599: || GET_CODE (SET_SRC (elt)) != MEM
600: || GET_MODE (SET_SRC (elt)) != SImode
601: || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
602: || ! rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
603: || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
604: || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != (i - base) * 4)
605: return 0;
606: }
607:
608: return 1;
609: }
610:
611: /* Return 1 if OP is a store multiple operation. It is known to be
612: parallel and the first section will be tested. */
613:
614: store_multiple_operation (op, mode)
615: rtx op;
616: enum machine_mode mode;
617: {
618: int count = XVECLEN (op, 0);
619: int src_regno;
620: rtx dest_addr;
621: int i = 1, base = 0;
622: rtx elt;
623:
624: if (count <= 1
625: || GET_CODE (XVECEXP (op, 0, 0)) != SET)
626: return 0;
627:
628: /* Check to see if this might be a write-back */
629: if (GET_CODE (SET_SRC (elt = XVECEXP (op, 0, 0))) == PLUS)
630: {
631: i++;
632: base = 1;
633:
634: /* Now check it more carefully */
635: if (GET_CODE (SET_DEST (elt)) != REG
636: || GET_CODE (XEXP (SET_SRC (elt), 0)) != REG
637: || REGNO (XEXP (SET_SRC (elt), 0)) != REGNO (SET_DEST (elt))
638: || GET_CODE (XEXP (SET_SRC (elt), 1)) != CONST_INT
639: || INTVAL (XEXP (SET_SRC (elt), 1)) != (count - 2) * 4
640: || GET_CODE (XVECEXP (op, 0, count - 1)) != CLOBBER
641: || GET_CODE (XEXP (XVECEXP (op, 0, count - 1), 0)) != REG
642: || REGNO (XEXP (XVECEXP (op, 0, count - 1), 0))
643: != REGNO (SET_DEST (elt)))
644: return 0;
645: count--;
646: }
647:
648: /* Perform a quick check so we don't blow up below. */
649: if (count <= i
650: || GET_CODE (XVECEXP (op, 0, i - 1)) != SET
651: || GET_CODE (SET_DEST (XVECEXP (op, 0, i - 1))) != MEM
652: || GET_CODE (SET_SRC (XVECEXP (op, 0, i - 1))) != REG)
653: return 0;
654:
655: src_regno = REGNO (SET_SRC (XVECEXP (op, 0, i - 1)));
656: dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, i - 1)), 0);
657:
658: for (; i < count; i++)
659: {
660: elt = XVECEXP (op, 0, i);
661:
662: if (GET_CODE (elt) != SET
663: || GET_CODE (SET_SRC (elt)) != REG
664: || GET_MODE (SET_SRC (elt)) != SImode
665: || REGNO (SET_SRC (elt)) != src_regno + i - base
666: || GET_CODE (SET_DEST (elt)) != MEM
667: || GET_MODE (SET_DEST (elt)) != SImode
668: || GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS
669: || ! rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr)
670: || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT
671: || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != (i - base) * 4)
672: return 0;
673: }
674:
675: return 1;
676: }
677:
678: /* Routines for use in generating RTL */
679:
680: rtx arm_gen_load_multiple (base_regno, count, from, up, write_back)
681: int base_regno;
682: int count;
683: rtx from;
684: int up;
685: int write_back;
686: {
687: int i = 0, j;
688: rtx result;
689: int sign = up ? 1 : -1;
690:
691: result = gen_rtx (PARALLEL, VOIDmode,
692: rtvec_alloc (count + (write_back ? 2 : 0)));
693: if (write_back)
694: {
695: XVECEXP (result, 0, 0)
696: = gen_rtx (SET, GET_MODE (from), from,
697: plus_constant (from, count * 4 * sign));
698: i = 1;
699: count++;
700: }
701: for (j = 0; i < count; i++, j++)
702: {
703: XVECEXP (result, 0, i)
704: = gen_rtx (SET, VOIDmode, gen_rtx (REG, SImode, base_regno + j),
705: gen_rtx (MEM, SImode,
706: plus_constant (from, j * 4 * sign)));
707: }
708: if (write_back)
709: XVECEXP (result, 0, i) = gen_rtx (CLOBBER, SImode, from);
710:
711: return result;
712: }
713:
714: rtx arm_gen_store_multiple (base_regno, count, to, up, write_back)
715: int base_regno;
716: int count;
717: rtx to;
718: int up;
719: int write_back;
720: {
721: int i = 0, j;
722: rtx result;
723: int sign = up ? 1 : -1;
724:
725: result = gen_rtx (PARALLEL, VOIDmode,
726: rtvec_alloc (count + (write_back ? 2 : 0)));
727: if (write_back)
728: {
729: XVECEXP (result, 0, 0)
730: = gen_rtx (SET, GET_MODE (to), to,
731: plus_constant (to, count * 4 * sign));
732: i = 1;
733: count++;
734: }
735: for (j = 0; i < count; i++, j++)
736: {
737: XVECEXP (result, 0, i)
738: = gen_rtx (SET, VOIDmode,
739: gen_rtx (MEM, SImode, plus_constant (to, j * 4 * sign)),
740: gen_rtx (REG, SImode, base_regno + j));
741: }
742: if (write_back)
743: XVECEXP (result, 0, i) = gen_rtx (CLOBBER, SImode, to);
744:
745: return result;
746: }
747:
748: /* X and Y are two things to compare using CODE. Emit the compare insn and
749: return the rtx for register 0 in the proper mode. FP means this is a
750: floating point compare: I don't think that it is needed on the arm. */
751:
752: rtx
753: gen_compare_reg (code, x, y, fp)
754: enum rtx_code code;
755: rtx x, y;
756: {
757: enum machine_mode mode = SELECT_CC_MODE (code, x, y);
758: rtx cc_reg = gen_rtx (REG, mode, 24);
759:
760: emit_insn (gen_rtx (SET, VOIDmode, cc_reg,
761: gen_rtx (COMPARE, mode, x, y)));
762:
763: return cc_reg;
764: }
765:
766: arm_reload_out_hi (operands)
767: rtx operands[];
768: {
769: rtx base = find_replacement (&XEXP (operands[0], 0));
770:
771: emit_insn (gen_rtx (SET, VOIDmode,
772: gen_rtx (MEM, QImode, base),
773: gen_rtx (SUBREG, QImode, operands[1], 0)));
774: emit_insn (gen_rtx (SET, VOIDmode, operands[2],
775: gen_rtx (LSHIFTRT, SImode,
776: gen_rtx (SUBREG, SImode, operands[1], 0),
777: GEN_INT (8))));
778: emit_insn (gen_rtx (SET, VOIDmode,
779: gen_rtx (MEM, QImode,
780: plus_constant (base, 1)),
781: gen_rtx (SUBREG, QImode, operands[2], 0)));
782: }
783:
784: /* Check to see if a branch is forwards or backwards. Return TRUE if it
785: is backwards. */
786:
787: int
788: arm_backwards_branch (from, to)
789: int from, to;
790: {
791: return (insn_addresses[to] <= insn_addresses[from]);
792: }
793:
794: /* Check to see if a branch is within the distance that can be done using
795: an arithmetic expression. */
796: int
797: short_branch (from, to)
798: int from, to;
799: {
800: int delta = insn_addresses[from] + 2 - insn_addresses[to];
801:
802: return abs (delta) < 245; /* A small margin for safety */
803: }
804:
805: /* Check to see that the insn isn't the target of the conditionalizing
806: code */
807: int
808: arm_insn_not_targeted (insn)
809: rtx insn;
810: {
811: return insn != arm_target_insn;
812: }
813:
814:
815: /* Routines to output assembly language. */
816:
817: /* fp_immediate_constant
818: if the rtx is the correct value then return the string of the number.
819: In this way we can ensure that valid double constants are generated even
820: when cross compiling. */
821: char *
822: fp_immediate_constant (x)
823: rtx (x);
824: {
825: REAL_VALUE_TYPE r;
826: int i;
827:
828: if (!fpa_consts_inited)
829: init_fpa_table ();
830:
831: REAL_VALUE_FROM_CONST_DOUBLE (r, x);
832: for (i = 0; i < 8; i++)
833: if (REAL_VALUES_EQUAL (r, values_fpa[i]))
834: return strings_fpa[i];
835: abort ();
836: }
837:
838:
839: /* Output the operands of a LDM/STM instruction to STREAM.
840: MASK is the ARM register set mask of which only bits 0-15 are important.
841: INSTR is the possibly suffixed base register. HAT unequals zero if a hat
842: must follow the register list. */
843:
844: void
845: print_multi_reg (stream, instr, mask, hat)
846: FILE *stream;
847: char *instr;
848: int mask, hat;
849: {
850: int i;
851: int not_first = FALSE;
852:
853: fprintf (stream, "\t%s, {", instr);
854: for (i = 0; i < 16; i++)
855: if (mask & (1 << i))
856: {
857: if (not_first)
858: fprintf (stream, ", ");
859: fprintf (stream, "%s", reg_names[i]);
860: not_first = TRUE;
861: }
862: fprintf (stream, "}%s\n", hat ? "^" : "");
863: } /* print_multi_reg */
864:
865: /* Output a 'call' insn. */
866:
867: char *
868: output_call (operands)
869: rtx operands[];
870: {
871: /* Handle calls to lr using ip (which may be clobbered in subr anyway). */
872:
873: if (REGNO (operands[0]) == 14)
874: {
875: operands[0] = gen_rtx (REG, SImode, 12);
876: arm_output_asm_insn ("mov\t%0, lr", operands);
877: }
878: arm_output_asm_insn ("mov\tlr, pc", operands);
879: arm_output_asm_insn ("mov\tpc, %0", operands);
880: return ("");
881: } /* output_call */
882:
883: static int
884: eliminate_lr2ip (x)
885: rtx *x;
886: {
887: int something_changed = 0;
888: rtx x0 = *x;
889: int code = GET_CODE (x0);
890: register int i, j;
891: register char *fmt;
892:
893: switch (code)
894: {
895: case REG:
896: if (REGNO (x0) == 14)
897: {
898: *x = gen_rtx (REG, SImode, 12);
899: return 1;
900: }
901: return 0;
902: default:
903: /* Scan through the sub-elements and change any references there */
904: fmt = GET_RTX_FORMAT (code);
905: for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
906: if (fmt[i] == 'e')
907: something_changed |= eliminate_lr2ip (&XEXP (x0, i));
908: else if (fmt[i] == 'E')
909: for (j = 0; j < XVECLEN (x0, i); j++)
910: something_changed |= eliminate_lr2ip (&XVECEXP (x0, i, j));
911: return something_changed;
912: }
913: }
914:
915: /* Output a 'call' insn that is a reference in memory. */
916:
917: char *
918: output_call_mem (operands)
919: rtx operands[];
920: {
921: operands[0] = copy_rtx (operands[0]); /* Be ultra careful */
922: /* Handle calls using lr by using ip (which may be clobbered in subr anyway).
923: */
924: if (eliminate_lr2ip (&operands[0]))
925: arm_output_asm_insn ("mov\tip, lr", operands);
926: arm_output_asm_insn ("mov\tlr, pc", operands);
927: arm_output_asm_insn ("ldr\tpc, %0", operands);
928: return ("");
929: } /* output_call */
930:
931:
932: /* Output a move from arm registers to an fpu registers.
933: OPERANDS[0] is an fpu register.
934: OPERANDS[1] is the first registers of an arm register pair. */
935:
936: char *
937: output_mov_long_double_fpu_from_arm (operands)
938: rtx operands[];
939: {
940: int arm_reg0 = REGNO (operands[1]);
941: rtx ops[3];
942:
943: if (arm_reg0 == 12)
944: abort();
945: ops[0] = gen_rtx (REG, SImode, arm_reg0);
946: ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0);
947: ops[2] = gen_rtx (REG, SImode, 2 + arm_reg0);
948:
949: arm_output_asm_insn ("stmfd\tsp!, {%0, %1, %2}", ops);
950: arm_output_asm_insn ("ldfe\t%0, [sp], #12", operands);
951: return ("");
952: } /* output_mov_long_double_fpu_from_arm */
953:
954: /* Output a move from an fpu register to arm registers.
955: OPERANDS[0] is the first registers of an arm register pair.
956: OPERANDS[1] is an fpu register. */
957:
958: char *
959: output_mov_long_double_arm_from_fpu (operands)
960: rtx operands[];
961: {
962: int arm_reg0 = REGNO (operands[0]);
963: rtx ops[3];
964:
965: if (arm_reg0 == 12)
966: abort();
967: ops[0] = gen_rtx (REG, SImode, arm_reg0);
968: ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0);
969: ops[2] = gen_rtx (REG, SImode, 2 + arm_reg0);
970:
971: arm_output_asm_insn ("stfe\t%1, [sp, #-12]!", operands);
972: arm_output_asm_insn ("ldmfd\tsp!, {%0, %1, %2}", ops);
973: return("");
974: } /* output_mov_long_double_arm_from_fpu */
975:
976: /* Output a move from arm registers to arm registers of a long double
977: OPERANDS[0] is the destination.
978: OPERANDS[1] is the source. */
979: char *
980: output_mov_long_double_arm_from_arm (operands)
981: rtx operands[];
982: {
983: /* We have to be careful here because the two might overlap */
984: int dest_start = REGNO (operands[0]);
985: int src_start = REGNO (operands[1]);
986: rtx ops[2];
987: int i;
988:
989: if (dest_start < src_start)
990: {
991: for (i = 0; i < 3; i++)
992: {
993: ops[0] = gen_rtx (REG, SImode, dest_start + i);
994: ops[1] = gen_rtx (REG, SImode, src_start + i);
995: arm_output_asm_insn ("mov\t%0, %1", ops);
996: }
997: }
998: else
999: {
1000: for (i = 2; i >= 0; i--)
1001: {
1002: ops[0] = gen_rtx (REG, SImode, dest_start + i);
1003: ops[1] = gen_rtx (REG, SImode, src_start + i);
1004: arm_output_asm_insn ("mov\t%0, %1", ops);
1005: }
1006: }
1007: return "";
1008: }
1009:
1010:
1011: /* Output a move from arm registers to an fpu registers.
1012: OPERANDS[0] is an fpu register.
1013: OPERANDS[1] is the first registers of an arm register pair. */
1014:
1015: char *
1016: output_mov_double_fpu_from_arm (operands)
1017: rtx operands[];
1018: {
1019: int arm_reg0 = REGNO (operands[1]);
1020: rtx ops[2];
1021:
1022: if (arm_reg0 == 12)
1023: abort();
1024: ops[0] = gen_rtx (REG, SImode, arm_reg0);
1025: ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0);
1026: arm_output_asm_insn ("stmfd\tsp!, {%0, %1}", ops);
1027: arm_output_asm_insn ("ldfd\t%0, [sp], #8", operands);
1028: return ("");
1029: } /* output_mov_double_fpu_from_arm */
1030:
1031: /* Output a move from an fpu register to arm registers.
1032: OPERANDS[0] is the first registers of an arm register pair.
1033: OPERANDS[1] is an fpu register. */
1034:
1035: char *
1036: output_mov_double_arm_from_fpu (operands)
1037: rtx operands[];
1038: {
1039: int arm_reg0 = REGNO (operands[0]);
1040: rtx ops[2];
1041:
1042: if (arm_reg0 == 12)
1043: abort();
1044: ops[0] = gen_rtx (REG, SImode, arm_reg0);
1045: ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0);
1046: arm_output_asm_insn ("stfd\t%1, [sp, #-8]!", operands);
1047: arm_output_asm_insn ("ldmfd\tsp!, {%0, %1}", ops);
1048: return("");
1049: } /* output_mov_double_arm_from_fpu */
1050:
1051: /* Output a move between double words.
1052: It must be REG<-REG, REG<-CONST_DOUBLE, REG<-CONST_INT, REG<-MEM
1053: or MEM<-REG and all MEMs must be offsettable addresses. */
1054:
1055: char *
1056: output_move_double (operands)
1057: rtx operands[];
1058: {
1059: enum rtx_code code0 = GET_CODE (operands[0]);
1060: enum rtx_code code1 = GET_CODE (operands[1]);
1061: rtx otherops[2];
1062:
1063: if (code0 == REG)
1064: {
1065: int reg0 = REGNO (operands[0]);
1066:
1067: otherops[0] = gen_rtx (REG, SImode, 1 + reg0);
1068: if (code1 == REG)
1069: {
1070: int reg1 = REGNO (operands[1]);
1071: if (reg1 == 12)
1072: abort();
1073: otherops[1] = gen_rtx (REG, SImode, 1 + reg1);
1074:
1075: /* Ensure the second source is not overwritten */
1076: if (reg0 == 1 + reg1)
1077: {
1078: arm_output_asm_insn("mov\t%0, %1", otherops);
1079: arm_output_asm_insn("mov\t%0, %1", operands);
1080: }
1081: else
1082: {
1083: arm_output_asm_insn("mov\t%0, %1", operands);
1084: arm_output_asm_insn("mov\t%0, %1", otherops);
1085: }
1086: }
1087: else if (code1 == CONST_DOUBLE)
1088: {
1089: otherops[1] = gen_rtx (CONST_INT, VOIDmode,
1090: CONST_DOUBLE_HIGH (operands[1]));
1091: operands[1] = gen_rtx (CONST_INT, VOIDmode,
1092: CONST_DOUBLE_LOW (operands[1]));
1093: output_mov_immediate (operands, FALSE, "");
1094: output_mov_immediate (otherops, FALSE, "");
1095: }
1096: else if (code1 == CONST_INT)
1097: {
1098: otherops[1] = const0_rtx;
1099: /* sign extend the intval into the high-order word */
1100: /* Note: output_mov_immediate may clobber operands[1], so we
1101: put this out first */
1102: if (INTVAL (operands[1]) < 0)
1103: arm_output_asm_insn ("mvn\t%0, %1", otherops);
1104: else
1105: arm_output_asm_insn ("mov\t%0, %1", otherops);
1106: output_mov_immediate (operands, FALSE, "");
1107: }
1108: else if (code1 == MEM)
1109: {
1110: switch (GET_CODE (XEXP (operands[1], 0)))
1111: {
1112: case REG:
1113: /* Handle the simple case where address is [r, #0] more
1114: efficient. */
1115: operands[1] = XEXP (operands[1], 0);
1116: arm_output_asm_insn ("ldmia\t%1, %M0", operands);
1117: break;
1118: case PRE_INC:
1119: operands[1] = XEXP (XEXP (operands[1], 0), 0);
1120: arm_output_asm_insn ("add\t%1, %1, #8", operands);
1121: arm_output_asm_insn ("ldmia\t%1, %M0", operands);
1122: break;
1123: case PRE_DEC:
1124: operands[1] = XEXP (XEXP (operands[1], 0), 0);
1125: arm_output_asm_insn ("sub\t%1, %1, #8", operands);
1126: arm_output_asm_insn ("ldmia\t%1, %M0", operands);
1127: break;
1128: case POST_INC:
1129: operands[1] = XEXP (XEXP (operands[1], 0), 0);
1130: arm_output_asm_insn ("ldmia\t%1!, %M0", operands);
1131: break;
1132: case POST_DEC:
1133: operands[1] = XEXP (XEXP (operands[1], 0), 0);
1134: arm_output_asm_insn ("ldmia\t%1, %M0", operands);
1135: arm_output_asm_insn ("sub\t%1, %1, #8", operands);
1136: break;
1137: default:
1138: otherops[1] = adj_offsettable_operand (operands[1], 4);
1139: /* Take care of overlapping base/data reg. */
1140: if (reg_mentioned_p (operands[0], operands[1]))
1141: {
1142: arm_output_asm_insn ("ldr\t%0, %1", otherops);
1143: arm_output_asm_insn ("ldr\t%0, %1", operands);
1144: }
1145: else
1146: {
1147: arm_output_asm_insn ("ldr\t%0, %1", operands);
1148: arm_output_asm_insn ("ldr\t%0, %1", otherops);
1149: }
1150: }
1151: }
1152: else abort(); /* Constraints should prevent this */
1153: }
1154: else if (code0 == MEM && code1 == REG)
1155: {
1156: if (REGNO (operands[1]) == 12)
1157: abort();
1158: switch (GET_CODE (XEXP (operands[0], 0)))
1159: {
1160: case REG:
1161: operands[0] = XEXP (operands[0], 0);
1162: arm_output_asm_insn ("stmia\t%0, %M1", operands);
1163: break;
1164: case PRE_INC:
1165: operands[0] = XEXP (XEXP (operands[0], 0), 0);
1166: arm_output_asm_insn ("add\t%0, %0, #8", operands);
1167: arm_output_asm_insn ("stmia\t%0, %M1", operands);
1168: break;
1169: case PRE_DEC:
1170: operands[0] = XEXP (XEXP (operands[0], 0), 0);
1171: arm_output_asm_insn ("sub\t%0, %0, #8", operands);
1172: arm_output_asm_insn ("stmia\t%0, %M1", operands);
1173: break;
1174: case POST_INC:
1175: operands[0] = XEXP (XEXP (operands[0], 0), 0);
1176: arm_output_asm_insn ("stmia\t%0!, %M1", operands);
1177: break;
1178: case POST_DEC:
1179: operands[0] = XEXP (XEXP (operands[0], 0), 0);
1180: arm_output_asm_insn ("stmia\t%0, %M1", operands);
1181: arm_output_asm_insn ("sub\t%0, %0, #8", operands);
1182: break;
1183: default:
1184: otherops[0] = adj_offsettable_operand (operands[0], 4);
1185: otherops[1] = gen_rtx (REG, SImode, 1 + REGNO (operands[1]));
1186: arm_output_asm_insn ("str\t%1, %0", operands);
1187: arm_output_asm_insn ("str\t%1, %0", otherops);
1188: }
1189: }
1190: else abort(); /* Constraints should prevent this */
1191:
1192: return("");
1193: } /* output_move_double */
1194:
1195:
1196: /* Output an arbitrary MOV reg, #n.
1197: OPERANDS[0] is a register. OPERANDS[1] is a const_int. */
1198:
1199: char *
1200: output_mov_immediate (operands)
1201: rtx operands[2];
1202: {
1203: int n = INTVAL (operands[1]);
1204: int n_ones = 0;
1205: int i;
1206:
1207: /* Try to use one MOV */
1208:
1209: if (const_ok_for_arm (n))
1210: return (arm_output_asm_insn ("mov\t%0, %1", operands));
1211:
1212: /* Try to use one MVN */
1213:
1214: if (const_ok_for_arm(~n))
1215: {
1216: operands[1] = gen_rtx (CONST_INT, VOIDmode, ~n);
1217: return (arm_output_asm_insn ("mvn\t%0, %1", operands));
1218: }
1219:
1220: /* If all else fails, make it out of ORRs or BICs as appropriate. */
1221:
1222: for (i=0; i < 32; i++)
1223: if (n & 1 << i)
1224: n_ones++;
1225:
1226: if (n_ones > 16) /* Shorter to use MVN with BIC in this case. */
1227: output_multi_immediate(operands, "mvn\t%0, %1", "bic\t%0, %0, %1", 1, ~n);
1228: else
1229: output_multi_immediate(operands, "mov\t%0, %1", "orr\t%0, %0, %1", 1, n);
1230: return("");
1231: } /* output_mov_immediate */
1232:
1233:
1234: /* Output an ADD r, s, #n where n may be too big for one instruction. If
1235: adding zero to one register, output nothing. */
1236:
1237: char *
1238: output_add_immediate (operands)
1239: rtx operands[3];
1240: {
1241: int n = INTVAL (operands[2]);
1242:
1243: if (n != 0 || REGNO (operands[0]) != REGNO (operands[1]))
1244: {
1245: if (n < 0)
1246: output_multi_immediate (operands,
1247: "sub\t%0, %1, %2", "sub\t%0, %0, %2", 2, -n);
1248: else
1249: output_multi_immediate (operands,
1250: "add\t%0, %1, %2", "add\t%0, %0, %2", 2, n);
1251: }
1252: return("");
1253: } /* output_add_immediate */
1254:
1255:
1256: /* Output a multiple immediate operation.
1257: OPERANDS is the vector of operands referred to in the output patterns.
1258: INSTR1 is the output pattern to use for the first constant.
1259: INSTR2 is the output pattern to use for subsequent constants.
1260: IMMED_OP is the index of the constant slot in OPERANDS.
1261: N is the constant value. */
1262:
1263: char *
1264: output_multi_immediate (operands, instr1, instr2, immed_op, n)
1265: rtx operands[];
1266: char *instr1, *instr2;
1267: int immed_op, n;
1268: {
1269: if (n == 0)
1270: {
1271: operands[immed_op] = const0_rtx;
1272: arm_output_asm_insn (instr1, operands); /* Quick and easy output */
1273: }
1274: else
1275: {
1276: int i;
1277: char *instr = instr1;
1278:
1279: /* Note that n is never zero here (which would give no output) */
1280:
1281: for (i = 0; i < 32; i += 2)
1282: {
1283: if (n & (3 << i))
1284: {
1285: operands[immed_op] = gen_rtx (CONST_INT, VOIDmode,
1286: n & (255 << i));
1287: arm_output_asm_insn (instr, operands);
1288: instr = instr2;
1289: i += 6;
1290: }
1291: }
1292: }
1293: return ("");
1294: } /* output_multi_immediate */
1295:
1296:
1297: /* Return the appropriate ARM instruction for the operation code.
1298: The returned result should not be overwritten. OP is the rtx of the
1299: operation. SHIFT_FIRST_ARG is TRUE if the first argument of the operator
1300: was shifted. */
1301:
1302: char *
1303: arithmetic_instr (op, shift_first_arg)
1304: rtx op;
1305: {
1306: switch (GET_CODE(op))
1307: {
1308: case PLUS:
1309: return ("add");
1310: case MINUS:
1311: if (shift_first_arg)
1312: return ("rsb");
1313: else
1314: return ("sub");
1315: case IOR:
1316: return ("orr");
1317: case XOR:
1318: return ("eor");
1319: case AND:
1320: return ("and");
1321: default:
1322: abort();
1323: }
1324: return (""); /* stupid cc */
1325: } /* arithmetic_instr */
1326:
1327:
1328: /* Ensure valid constant shifts and return the appropriate shift mnemonic
1329: for the operation code. The returned result should not be overwritten.
1330: OP is the rtx code of the shift.
1331: SHIFT_PTR points to the shift size operand. */
1332:
1333: char *
1334: shift_instr (op, shift_ptr)
1335: enum rtx_code op;
1336: rtx *shift_ptr;
1337: {
1338: int min_shift = 0;
1339: int max_shift = 31;
1340: char *mnem;
1341:
1342: switch (op)
1343: {
1344: case ASHIFT:
1345: mnem = "asl";
1346: break;
1347: case LSHIFT:
1348: mnem = "lsl";
1349: break;
1350: case ASHIFTRT:
1351: mnem = "asr";
1352: max_shift = 32;
1353: break;
1354: case LSHIFTRT:
1355: mnem = "lsr";
1356: max_shift = 32;
1357: break;
1358: case MULT:
1359: *shift_ptr = gen_rtx (CONST_INT, VOIDmode,
1360: int_log2 (INTVAL (*shift_ptr)));
1361: return ("asl");
1362: default:
1363: abort();
1364: }
1365:
1366: if (GET_CODE (*shift_ptr) == CONST_INT)
1367: {
1368: int shift = INTVAL (*shift_ptr);
1369:
1370: if (shift < min_shift)
1371: *shift_ptr = gen_rtx (CONST_INT, VOIDmode, 0);
1372: else if (shift > max_shift)
1373: *shift_ptr = gen_rtx (CONST_INT, VOIDmode, max_shift);
1374: }
1375: return (mnem);
1376: } /* shift_instr */
1377:
1378:
1379: /* Obtain the shift from the POWER of two. */
1380:
1381: int
1382: int_log2 (power)
1383: unsigned int power;
1384: {
1385: int shift = 0;
1386:
1387: while (((1 << shift) & power) == 0)
1388: {
1389: if (shift > 31)
1390: abort();
1391: shift++;
1392: }
1393: return (shift);
1394: } /* int_log2 */
1395:
1396:
1397: /* Output an arithmetic instruction which may set the condition code.
1398: OPERANDS[0] is the destination register.
1399: OPERANDS[1] is the arithmetic operator expression.
1400: OPERANDS[2] is the left hand argument.
1401: OPERANDS[3] is the right hand argument.
1402: CONST_FIRST_ARG is TRUE if the first argument of the operator was constant.
1403: SET_COND is TRUE when the condition code should be set. */
1404:
1405: char *
1406: output_arithmetic (operands, const_first_arg, set_cond)
1407: rtx operands[4];
1408: int const_first_arg;
1409: int set_cond;
1410: {
1411: char mnemonic[80];
1412: char *instr = arithmetic_instr (operands[1], const_first_arg);
1413:
1414: sprintf (mnemonic, "%s%s\t%%0, %%2, %%3", instr, set_cond ? "s" : "");
1415: return (arm_output_asm_insn (mnemonic, operands));
1416: } /* output_arithmetic */
1417:
1418:
1419: /* Output an arithmetic instruction with a shift.
1420: OPERANDS[0] is the destination register.
1421: OPERANDS[1] is the arithmetic operator expression.
1422: OPERANDS[2] is the unshifted register.
1423: OPERANDS[3] is the shift operator expression.
1424: OPERANDS[4] is the shifted register.
1425: OPERANDS[5] is the shift constant or register.
1426: SHIFT_FIRST_ARG is TRUE if the first argument of the operator was shifted.
1427: SET_COND is TRUE when the condition code should be set. */
1428:
1429: char *
1430: output_arithmetic_with_shift (operands, shift_first_arg, set_cond)
1431: rtx operands[6];
1432: int shift_first_arg;
1433: int set_cond;
1434: {
1435: char mnemonic[80];
1436: char *instr = arithmetic_instr (operands[1], shift_first_arg);
1437: char *condbit = set_cond ? "s" : "";
1438: char *shift = shift_instr (GET_CODE (operands[3]), &operands[5]);
1439:
1440: sprintf (mnemonic, "%s%s\t%%0, %%2, %%4, %s %%5", instr, condbit, shift);
1441: return (arm_output_asm_insn (mnemonic, operands));
1442: } /* output_arithmetic_with_shift */
1443:
1444:
1445: /* Output an arithmetic instruction with a power of two multiplication.
1446: OPERANDS[0] is the destination register.
1447: OPERANDS[1] is the arithmetic operator expression.
1448: OPERANDS[2] is the unmultiplied register.
1449: OPERANDS[3] is the multiplied register.
1450: OPERANDS[4] is the constant multiple (power of two).
1451: SHIFT_FIRST_ARG is TRUE if the first arg of the operator was multiplied. */
1452:
1453: char *
1454: output_arithmetic_with_immediate_multiply (operands, shift_first_arg)
1455: rtx operands[5];
1456: int shift_first_arg;
1457: {
1458: char mnemonic[80];
1459: char *instr = arithmetic_instr (operands[1], shift_first_arg);
1460: int shift = int_log2 (INTVAL (operands[4]));
1461:
1462: sprintf (mnemonic, "%s\t%%0, %%2, %%3, asl#%d", instr, shift);
1463: return (arm_output_asm_insn (mnemonic, operands));
1464: } /* output_arithmetic_with_immediate_multiply */
1465:
1466:
1467: /* Output a move with a shift.
1468: OP is the shift rtx code.
1469: OPERANDS[0] = destination register.
1470: OPERANDS[1] = source register.
1471: OPERANDS[2] = shift constant or register. */
1472:
1473: char *
1474: output_shifted_move (op, operands)
1475: enum rtx_code op;
1476: rtx operands[2];
1477: {
1478: char mnemonic[80];
1479:
1480: if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0)
1481: sprintf (mnemonic, "mov\t%%0, %%1");
1482: else
1483: sprintf (mnemonic, "mov\t%%0, %%1, %s %%2",
1484: shift_instr (op, &operands[2]));
1485: return (arm_output_asm_insn (mnemonic, operands));
1486: } /* output_shifted_move */
1487:
1488: char *
1489: output_shift_compare (operands, neg)
1490: rtx *operands;
1491: int neg;
1492: {
1493: char buf[80];
1494:
1495: if (neg)
1496: sprintf (buf, "cmn\t%%1, %%3, %s %%4", shift_instr (GET_CODE (operands[2]),
1497: &operands[4]));
1498: else
1499: sprintf (buf, "cmp\t%%1, %%3, %s %%4", shift_instr (GET_CODE (operands[2]),
1500: &operands[4]));
1501: return arm_output_asm_insn (buf, operands);
1502: } /* output_shift_compare */
1503:
1504: /* Output a .ascii pseudo-op, keeping track of lengths. This is because
1505: /bin/as is horribly restrictive. */
1506:
1507: void
1508: output_ascii_pseudo_op (stream, p, len)
1509: FILE *stream;
1510: unsigned char *p;
1511: int len;
1512: {
1513: int i;
1514: int len_so_far = 1000;
1515: int chars_so_far = 0;
1516:
1517: for (i = 0; i < len; i++)
1518: {
1519: register int c = p[i];
1520:
1521: if (len_so_far > 50)
1522: {
1523: if (chars_so_far)
1524: fputs ("\"\n", stream);
1525: fputs ("\t.ascii\t\"", stream);
1526: len_so_far = 0;
1527: arm_increase_location (chars_so_far);
1528: chars_so_far = 0;
1529: }
1530:
1531: if (c == '\"' || c == '\\')
1532: {
1533: putc('\\', stream);
1534: len_so_far++;
1535: }
1536: if (c >= ' ' && c < 0177)
1537: {
1538: putc (c, stream);
1539: len_so_far++;
1540: }
1541: else
1542: {
1543: fprintf (stream, "\\%03o", c);
1544: len_so_far +=4;
1545: }
1546: chars_so_far++;
1547: }
1548: fputs ("\"\n", stream);
1549: arm_increase_location (chars_so_far);
1550: } /* output_ascii_pseudo_op */
1551:
1552:
1553: /* Try to determine whether a pattern really clobbers the link register.
1554: This information is useful when peepholing, so that lr need not be pushed
1555: if we combine a call followed by a return.
1556: NOTE: This code does not check for side-effect expressions in a SET_SRC:
1557: such a check should not be needed because these only update an existing
1558: value within a register; the register must still be set elsewhere within
1559: the function. */
1560:
1561: static int
1562: pattern_really_clobbers_lr (x)
1563: rtx x;
1564: {
1565: int i;
1566:
1567: switch (GET_CODE (x))
1568: {
1569: case SET:
1570: switch (GET_CODE (SET_DEST (x)))
1571: {
1572: case REG:
1573: return REGNO (SET_DEST (x)) == 14;
1574: case SUBREG:
1575: if (GET_CODE (XEXP (SET_DEST (x), 0)) == REG)
1576: return REGNO (XEXP (SET_DEST (x), 0)) == 14;
1577: if (GET_CODE (XEXP (SET_DEST (x), 0)) == MEM)
1578: return 0;
1579: abort ();
1580: default:
1581: return 0;
1582: }
1583: case PARALLEL:
1584: for (i = 0; i < XVECLEN (x, 0); i++)
1585: if (pattern_really_clobbers_lr (XVECEXP (x, 0, i)))
1586: return 1;
1587: return 0;
1588: case CLOBBER:
1589: switch (GET_CODE (XEXP (x, 0)))
1590: {
1591: case REG:
1592: return REGNO (XEXP (x, 0)) == 14;
1593: case SUBREG:
1594: if (GET_CODE (XEXP (XEXP (x, 0), 0)) == REG)
1595: return REGNO (XEXP (XEXP (x, 0), 0)) == 14;
1596: abort ();
1597: default:
1598: return 0;
1599: }
1600: case UNSPEC:
1601: return 1;
1602: default:
1603: return 0;
1604: }
1605: }
1606:
1607: static int
1608: function_really_clobbers_lr (first)
1609: rtx first;
1610: {
1611: rtx insn, next;
1612:
1613: for (insn = first; insn; insn = next_nonnote_insn (insn))
1614: {
1615: switch (GET_CODE (insn))
1616: {
1617: case BARRIER:
1618: case NOTE:
1619: case CODE_LABEL:
1620: case JUMP_INSN: /* Jump insns only change the PC (and conds) */
1621: case INLINE_HEADER:
1622: break;
1623: case INSN:
1624: if (pattern_really_clobbers_lr (PATTERN (insn)))
1625: return 1;
1626: break;
1627: case CALL_INSN:
1628: /* Don't yet know how to handle those calls that are not to a
1629: SYMBOL_REF */
1630: if (GET_CODE (PATTERN (insn)) != PARALLEL)
1631: abort ();
1632: switch (GET_CODE (XVECEXP (PATTERN (insn), 0, 0)))
1633: {
1634: case CALL:
1635: if (GET_CODE (XEXP (XEXP (XVECEXP (PATTERN (insn), 0, 0), 0), 0))
1636: != SYMBOL_REF)
1637: return 1;
1638: break;
1639: case SET:
1640: if (GET_CODE (XEXP (XEXP (SET_SRC (XVECEXP (PATTERN (insn),
1641: 0, 0)), 0), 0))
1642: != SYMBOL_REF)
1643: return 1;
1644: break;
1645: default: /* Don't recognize it, be safe */
1646: return 1;
1647: }
1648: /* A call can be made (by peepholing) not to clobber lr iff it is
1649: followed by a return. There may, however, be a use insn iff
1650: we are returning the result of the call.
1651: If we run off the end of the insn chain, then that means the
1652: call was at the end of the function. Unfortunately we don't
1653: have a return insn for the peephole to recognize, so we
1654: must reject this. (Can this be fixed by adding our own insn?) */
1655: if ((next = next_nonnote_insn (insn)) == NULL)
1656: return 1;
1657: if (GET_CODE (next) == INSN && GET_CODE (PATTERN (next)) == USE
1658: && (GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET)
1659: && (REGNO (SET_DEST (XVECEXP (PATTERN (insn), 0, 0)))
1660: == REGNO (XEXP (PATTERN (next), 0))))
1661: if ((next = next_nonnote_insn (next)) == NULL)
1662: return 1;
1663: if (GET_CODE (next) == JUMP_INSN
1664: && GET_CODE (PATTERN (next)) == RETURN)
1665: break;
1666: return 1;
1667: default:
1668: abort ();
1669: }
1670: }
1671: /* We have reached the end of the chain so lr was _not_ clobbered */
1672: return 0;
1673: }
1674:
1675: char *
1676: output_return_instruction (operand, really_return)
1677: rtx operand;
1678: int really_return;
1679: {
1680: char instr[100];
1681: int reg, live_regs = 0;
1682:
1683: if (current_function_calls_alloca && !really_return)
1684: abort();
1685:
1686: for (reg = 4; reg < 10; reg++)
1687: if (regs_ever_live[reg])
1688: live_regs++;
1689:
1690: if (live_regs || (regs_ever_live[14] && !lr_save_eliminated))
1691: live_regs++;
1692:
1693: if (frame_pointer_needed)
1694: live_regs += 4;
1695:
1696: if (live_regs)
1697: {
1698: if (lr_save_eliminated || !regs_ever_live[14])
1699: live_regs++;
1700: if (frame_pointer_needed)
1701: strcpy (instr, "ldm%d0ea\tfp, {");
1702: else
1703: strcpy (instr, "ldm%d0fd\tsp!, {");
1704: for (reg = 4; reg < 10; reg++)
1705: if (regs_ever_live[reg])
1706: {
1707: strcat (instr, reg_names[reg]);
1708: if (--live_regs)
1709: strcat (instr, ", ");
1710: }
1711: if (frame_pointer_needed)
1712: {
1713: strcat (instr, reg_names[11]);
1714: strcat (instr, ", ");
1715: strcat (instr, reg_names[13]);
1716: strcat (instr, ", ");
1717: strcat (instr, really_return ? reg_names[15] : reg_names[14]);
1718: }
1719: else
1720: strcat (instr, really_return ? reg_names[15] : reg_names[14]);
1721: strcat (instr, (TARGET_6 || !really_return) ? "}" : "}^");
1722: arm_output_asm_insn (instr, &operand);
1723: }
1724: else if (really_return)
1725: {
1726: strcpy (instr, TARGET_6 ? "mov%d0\tpc, lr" : "mov%d0s\tpc, lr");
1727: arm_output_asm_insn (instr, &operand);
1728: }
1729: return_used_this_function = 1;
1730: return "";
1731: }
1732:
1733: /* The amount of stack adjustment that happens here, in output_return and in
1734: output_epilogue must be exactly the same as was calculated during reload,
1735: or things will point to the wrong place. The only time we can safely
1736: ignore this constraint is when a function has no arguments on the stack,
1737: no stack frame requirement and no live registers execpt for `lr'. If we
1738: can guarantee that by making all function calls into tail calls and that
1739: lr is not clobbered in any other way, then there is no need to push lr
1740: onto the stack. */
1741:
1742: void
1743: output_prologue (f, frame_size)
1744: FILE *f;
1745: int frame_size;
1746: {
1747: int reg, live_regs_mask = 0, code_size = 0;
1748: rtx operands[3];
1749:
1750: /* Nonzero if we must stuff some register arguments onto the stack as if
1751: they were passed there. */
1752: int store_arg_regs = 0;
1753:
1754: if (arm_ccfsm_state || arm_target_insn)
1755: abort (); /* Sanity check */
1756:
1757: return_used_this_function = 0;
1758: lr_save_eliminated = 0;
1759:
1760: fprintf (f, "\t@ args = %d, pretend = %d, frame = %d\n",
1761: current_function_args_size, current_function_pretend_args_size,
1762: frame_size);
1763: fprintf (f, "\t@ frame_needed = %d, current_function_anonymous_args = %d\n",
1764: frame_pointer_needed, current_function_anonymous_args);
1765:
1766: if (current_function_anonymous_args && current_function_pretend_args_size)
1767: store_arg_regs = 1;
1768:
1769: for (reg = 4; reg < 10; reg++)
1770: if (regs_ever_live[reg])
1771: live_regs_mask |= (1 << reg);
1772:
1773: if (frame_pointer_needed)
1774: {
1775: live_regs_mask |= 0xD800;
1776: fputs ("\tmov\tip, sp\n", f);
1777: code_size += 4;
1778: }
1779: else if (regs_ever_live[14])
1780: {
1781: if (! current_function_args_size
1782: && !function_really_clobbers_lr (get_insns ()))
1783: {
1784: fprintf (f,"\t@ I don't think this function clobbers lr\n");
1785: lr_save_eliminated = 1;
1786: }
1787: else
1788: live_regs_mask |= 0x4000;
1789: }
1790:
1791: /* If CURRENT_FUNCTION_PRETEND_ARGS_SIZE, adjust the stack pointer to make
1792: room. If also STORE_ARG_REGS store the argument registers involved in
1793: the created slot (this is for stdarg and varargs). */
1794: if (current_function_pretend_args_size)
1795: {
1796: if (store_arg_regs)
1797: {
1798: int arg_size, mask = 0;
1799:
1800: assert (current_function_pretend_args_size <= 16);
1801: for (reg = 3, arg_size = current_function_pretend_args_size;
1802: arg_size > 0; reg--, arg_size -= 4)
1803: mask |= (1 << reg);
1804: print_multi_reg (f, "stmfd\tsp!", mask, FALSE);
1805: code_size += 4;
1806: }
1807: else
1808: {
1809: operands[0] = operands[1] = stack_pointer_rtx;
1810: operands[2] = gen_rtx (CONST_INT, VOIDmode,
1811: -current_function_pretend_args_size);
1812: output_add_immediate (operands);
1813: }
1814: }
1815:
1816: if (live_regs_mask)
1817: {
1818: /* if a di mode load/store multiple is used, and the base register
1819: is r3, then r4 can become an ever live register without lr
1820: doing so, in this case we need to push lr as well, or we
1821: will fail to get a proper return. */
1822:
1823: live_regs_mask |= 0x4000;
1824: lr_save_eliminated = 0;
1825: print_multi_reg (f, "stmfd\tsp!", live_regs_mask, FALSE);
1826: code_size += 4;
1827: }
1828:
1829: for (reg = 23; reg > 19; reg--)
1830: if (regs_ever_live[reg])
1831: {
1832: fprintf (f, "\tstfe\t%s, [sp, #-12]!\n", reg_names[reg]);
1833: code_size += 4;
1834: }
1835:
1836: if (frame_pointer_needed)
1837: {
1838: /* Make `fp' point to saved value of `pc'. */
1839:
1840: operands[0] = gen_rtx (REG, SImode, HARD_FRAME_POINTER_REGNUM);
1841: operands[1] = gen_rtx (REG, SImode, 12);
1842: operands[2] = gen_rtx (CONST_INT, VOIDmode,
1843: - (4 + current_function_pretend_args_size));
1844: output_add_immediate (operands);
1845: }
1846:
1847: if (frame_size)
1848: {
1849: operands[0] = operands[1] = stack_pointer_rtx;
1850: operands[2] = gen_rtx (CONST_INT, VOIDmode, -frame_size);
1851: output_add_immediate (operands);
1852: }
1853:
1854: arm_increase_location (code_size);
1855: } /* output_prologue */
1856:
1857:
1858: void
1859: output_epilogue (f, frame_size)
1860: FILE *f;
1861: int frame_size;
1862: {
1863: int reg, live_regs_mask = 0, code_size = 0;
1864: /* If we need this then it will always be at lesat this much */
1865: int floats_offset = 24;
1866: rtx operands[3];
1867:
1868: if (use_return_insn() && return_used_this_function)
1869: {
1870: if (frame_size && !(frame_pointer_needed || TARGET_APCS))
1871: {
1872: abort ();
1873: }
1874: return;
1875: }
1876:
1877: for (reg = 4; reg <= 10; reg++)
1878: if (regs_ever_live[reg])
1879: {
1880: live_regs_mask |= (1 << reg);
1881: floats_offset += 4;
1882: }
1883:
1884:
1885: if (frame_pointer_needed)
1886: {
1887: for (reg = 23; reg >= 20; reg--)
1888: if (regs_ever_live[reg])
1889: {
1890: fprintf (f, "\tldfe\t%s, [fp, #-%d]\n", reg_names[reg],
1891: floats_offset);
1892: floats_offset += 12;
1893: code_size += 4;
1894: }
1895:
1896: live_regs_mask |= 0xA800;
1897: print_multi_reg (f, "ldmea\tfp", live_regs_mask,
1898: TARGET_6 ? FALSE : TRUE);
1899: code_size += 4;
1900: }
1901: else
1902: {
1903: /* Restore stack pointer if necessary. */
1904: if (frame_size)
1905: {
1906: operands[0] = operands[1] = stack_pointer_rtx;
1907: operands[2] = gen_rtx (CONST_INT, VOIDmode, frame_size);
1908: output_add_immediate (operands);
1909: }
1910:
1911: for (reg = 20; reg < 24; reg++)
1912: if (regs_ever_live[reg])
1913: {
1914: fprintf (f, "\tldfe\t%s, [sp], #12\n", reg_names[reg]);
1915: code_size += 4;
1916: }
1917: if (current_function_pretend_args_size == 0 && regs_ever_live[14])
1918: {
1919: print_multi_reg (f, "ldmfd\tsp!", live_regs_mask | 0x8000,
1920: TARGET_6 ? FALSE : TRUE);
1921: code_size += 4;
1922: }
1923: else
1924: {
1925: if (live_regs_mask || regs_ever_live[14])
1926: {
1927: live_regs_mask |= 0x4000;
1928: print_multi_reg (f, "ldmfd\tsp!", live_regs_mask, FALSE);
1929: code_size += 4;
1930: }
1931: if (current_function_pretend_args_size)
1932: {
1933: operands[0] = operands[1] = stack_pointer_rtx;
1934: operands[2] = gen_rtx (CONST_INT, VOIDmode,
1935: current_function_pretend_args_size);
1936: output_add_immediate (operands);
1937: }
1938: fputs (TARGET_6 ? "\tmov\tpc, lr\n" : "\tmovs\tpc, lr\n", f);
1939: code_size += 4;
1940: }
1941: }
1942: arm_increase_location (code_size);
1943: current_function_anonymous_args = 0;
1944: } /* output_epilogue */
1945:
1946: /* Increase the `arm_text_location' by AMOUNT if we're in the text
1947: segment. */
1948:
1949: void
1950: arm_increase_location (amount)
1951: int amount;
1952: {
1953: if (in_text_section ())
1954: arm_text_location += amount;
1955: } /* arm_increase_location */
1956:
1957:
1958: /* Like output_asm_insn (), but also increases the arm_text_location (if in
1959: the .text segment, of course, even though this will always be true).
1960: Returns the empty string. */
1961:
1962: char *
1963: arm_output_asm_insn (template, operands)
1964: char *template;
1965: rtx *operands;
1966: {
1967: extern FILE *asm_out_file;
1968:
1969: output_asm_insn (template, operands);
1970: if (in_text_section ())
1971: arm_text_location += 4;
1972: fflush (asm_out_file);
1973: return ("");
1974: } /* arm_output_asm_insn */
1975:
1976:
1977: /* Output a label definition. If this label is within the .text segment, it
1978: is stored in OFFSET_TABLE, to be used when building `llc' instructions.
1979: Maybe GCC remembers names not starting with a `*' for a long time, but this
1980: is a minority anyway, so we just make a copy. Do not store the leading `*'
1981: if the name starts with one. */
1982:
1983: void
1984: arm_asm_output_label (stream, name)
1985: FILE *stream;
1986: char *name;
1987: {
1988: char *real_name, *s;
1989: struct label_offset *cur;
1990: int hash = 0;
1991:
1992: assemble_name (stream, name);
1993: fputs (":\n", stream);
1994: if (! in_text_section ())
1995: return;
1996:
1997: if (name[0] == '*')
1998: {
1999: real_name = xmalloc (1 + strlen (&name[1]));
2000: strcpy (real_name, &name[1]);
2001: }
2002: else
2003: {
2004: real_name = xmalloc (2 + strlen (name));
2005: strcpy (real_name, "_");
2006: strcat (real_name, name);
2007: }
2008: for (s = real_name; *s; s++)
2009: hash += *s;
2010: hash = hash % LABEL_HASH_SIZE;
2011: cur = (struct label_offset *) xmalloc (sizeof (struct label_offset));
2012: cur->name = real_name;
2013: cur->offset = arm_text_location;
2014: cur->cdr = offset_table[hash];
2015: offset_table[hash] = cur;
2016: } /* arm_asm_output_label */
2017:
2018:
2019: /* Output the instructions needed to perform what Martin's /bin/as called
2020: llc: load an SImode thing from the function's constant pool.
2021:
2022: XXX This could be enhanced in that we do not really need a pointer in the
2023: constant pool pointing to the real thing. If we can address this pointer,
2024: we can also address what it is pointing at, in fact, anything in the text
2025: segment which has been defined already within this .s file. */
2026:
2027: char *
2028: arm_output_llc (operands)
2029: rtx *operands;
2030: {
2031: char *s, *name = XSTR (XEXP (operands[1], 0), 0);
2032: struct label_offset *he;
2033: int hash = 0, conditional = (arm_ccfsm_state == 3 || arm_ccfsm_state == 4);
2034:
2035: if (*name != '*')
2036: abort ();
2037:
2038: for (s = &name[1]; *s; s++)
2039: hash += *s;
2040: hash = hash % LABEL_HASH_SIZE;
2041: he = offset_table[hash];
2042: while (he && strcmp (he->name, &name[1]))
2043: he = he->cdr;
2044:
2045: if (!he)
2046: abort ();
2047:
2048: if (arm_text_location + 8 - he->offset < 4095)
2049: {
2050: fprintf (asm_out_file, "\tldr%s\t%s, [pc, #%s - . - 8]\n",
2051: conditional ? arm_condition_codes[arm_current_cc] : "",
2052: reg_names[REGNO (operands[0])], &name[1]);
2053: arm_increase_location (4);
2054: return ("");
2055: }
2056: else
2057: {
2058: int offset = - (arm_text_location + 8 - he->offset);
2059: char *reg_name = reg_names[REGNO (operands[0])];
2060:
2061: /* ??? This is a hack, assuming the constant pool never is more than
2062: (1 + 255) * 4096 == 1Meg away from the PC. */
2063:
2064: if (offset > 1000000)
2065: abort ();
2066:
2067: fprintf (asm_out_file, "\tsub%s\t%s, pc, #(8 + . - %s) & ~4095\n",
2068: conditional ? arm_condition_codes[arm_current_cc] : "",
2069: reg_name, &name[1]);
2070: fprintf (asm_out_file, "\tldr%s\t%s, [%s, #- ((4 + . - %s) & 4095)]\n",
2071: conditional ? arm_condition_codes[arm_current_cc] : "",
2072: reg_name, reg_name, &name[1]);
2073: arm_increase_location (8);
2074: }
2075: return ("");
2076: } /* arm_output_llc */
2077:
2078: /* output_load_symbol ()
2079: load a symbol that is known to be in the text segment into a register */
2080:
2081: char *
2082: output_load_symbol (operands)
2083: rtx *operands;
2084: {
2085: char *s, *name = XSTR (operands[1], 0);
2086: struct label_offset *he;
2087: int hash = 0;
2088: int offset;
2089:
2090: if (*name != '*')
2091: abort ();
2092:
2093: for (s = &name[1]; *s; s++)
2094: hash += *s;
2095: hash = hash % LABEL_HASH_SIZE;
2096: he = offset_table[hash];
2097: while (he && strcmp (he->name, &name[1]))
2098: he = he->cdr;
2099:
2100: if (!he)
2101: abort ();
2102:
2103: offset = (arm_text_location + 8 - he->offset);
2104: if (offset < 0)
2105: abort ();
2106:
2107: /* If the symbol is word aligned then we might be able to reduce the
2108: number of loads */
2109: if ((offset & 3) == 0)
2110: {
2111: arm_output_asm_insn ("sub\t%0, pc, #(8 + . -%a1) & 1023", operands);
2112: if (offset > 0x3ff)
2113: {
2114: arm_output_asm_insn ("sub\t%0, %0, #(4 + . -%a1) & 261120",
2115: operands);
2116: if (offset > 0x3ffff)
2117: {
2118: arm_output_asm_insn ("sub\t%0, %0, #(. -%a1) & 66846720",
2119: operands);
2120: if (offset > 0x3ffffff)
2121: arm_output_asm_insn ("sub\t%0, %0, #(. - 4 -%a1) & -67108864",
2122: operands);
2123: }
2124: }
2125: }
2126: else
2127: {
2128: arm_output_asm_insn ("sub\t%0, pc, #(8 + . -%a1) & 255", operands);
2129: if (offset > 0x0ff)
2130: {
2131: arm_output_asm_insn ("sub\t%0, %0, #(4 + . -%a1) & 65280", operands);
2132: if (offset > 0x0ffff)
2133: {
2134: arm_output_asm_insn ("sub\t%0, %0, #(. -%a1) & 16711680",
2135: operands);
2136: if (offset > 0x0ffffff)
2137: arm_output_asm_insn ("sub\t%0, %0, #(. - 4 -%a1) & -16777216",
2138: operands);
2139: }
2140: }
2141: }
2142: return "";
2143: }
2144:
2145: /* Output code resembling an .lcomm directive. /bin/as doesn't have this
2146: directive hence this hack, which works by reserving some `.space' in the
2147: bss segment directly.
2148:
2149: XXX This is a severe hack, which is guaranteed NOT to work since it doesn't
2150: define STATIC COMMON space but merely STATIC BSS space. */
2151:
2152: void
2153: output_lcomm_directive (stream, name, size, rounded)
2154: FILE *stream;
2155: char *name;
2156: int size, rounded;
2157: {
2158: fputs ("\n\t.bss\t@ .lcomm\n", stream);
2159: assemble_name (stream, name);
2160: fprintf (stream, ":\t.space\t%d\n", rounded);
2161: if (in_text_section ())
2162: fputs ("\n\t.text\n", stream);
2163: else
2164: fputs ("\n\t.data\n", stream);
2165: } /* output_lcomm_directive */
2166:
2167: /* A finite state machine takes care of noticing whether or not instructions
2168: can be conditionally executed, and thus decrease execution time and code
2169: size by deleting branch instructions. The fsm is controlled by
2170: final_prescan_insn, and controls the actions of ASM_OUTPUT_OPCODE. */
2171:
2172: /* The state of the fsm controlling condition codes are:
2173: 0: normal, do nothing special
2174: 1: make ASM_OUTPUT_OPCODE not output this instruction
2175: 2: make ASM_OUTPUT_OPCODE not output this instruction
2176: 3: make instructions conditional
2177: 4: make instructions conditional
2178:
2179: State transitions (state->state by whom under condition):
2180: 0 -> 1 final_prescan_insn if the `target' is a label
2181: 0 -> 2 final_prescan_insn if the `target' is an unconditional branch
2182: 1 -> 3 ASM_OUTPUT_OPCODE after not having output the conditional branch
2183: 2 -> 4 ASM_OUTPUT_OPCODE after not having output the conditional branch
2184: 3 -> 0 ASM_OUTPUT_INTERNAL_LABEL if the `target' label is reached
2185: (the target label has CODE_LABEL_NUMBER equal to arm_target_label).
2186: 4 -> 0 final_prescan_insn if the `target' unconditional branch is reached
2187: (the target insn is arm_target_insn).
2188:
2189: If the jump clobbers the conditions then we use states 2 and 4.
2190:
2191: A similar thing can be done with conditional return insns.
2192:
2193: XXX In case the `target' is an unconditional branch, this conditionalising
2194: of the instructions always reduces code size, but not always execution
2195: time. But then, I want to reduce the code size to somewhere near what
2196: /bin/cc produces. */
2197:
2198: /* The condition codes of the ARM, and the inverse function. */
2199: char *arm_condition_codes[] =
2200: {
2201: "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
2202: "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"
2203: };
2204:
2205: #define ARM_INVERSE_CONDITION_CODE(X) ((X) ^ 1)
2206:
2207: /* Returns the index of the ARM condition code string in
2208: `arm_condition_codes'. COMPARISON should be an rtx like
2209: `(eq (...) (...))'. */
2210:
2211: int
2212: get_arm_condition_code (comparison)
2213: rtx comparison;
2214: {
2215: switch (GET_CODE (comparison))
2216: {
2217: case NE: return (1);
2218: case EQ: return (0);
2219: case GE: return (10);
2220: case GT: return (12);
2221: case LE: return (13);
2222: case LT: return (11);
2223: case GEU: return (2);
2224: case GTU: return (8);
2225: case LEU: return (9);
2226: case LTU: return (3);
2227: default: abort ();
2228: }
2229: /*NOTREACHED*/
2230: return (42);
2231: } /* get_arm_condition_code */
2232:
2233:
2234: void
2235: final_prescan_insn (insn, opvec, noperands)
2236: rtx insn;
2237: rtx *opvec;
2238: int noperands;
2239: {
2240: /* BODY will hold the body of INSN. */
2241: register rtx body = PATTERN (insn);
2242:
2243: /* This will be 1 if trying to repeat the trick, and things need to be
2244: reversed if it appears to fail. */
2245: int reverse = 0;
2246:
2247: /* JUMP_CLOBBERS will be one implies that the conditions if a branch is
2248: taken are clobbered, even if the rtl suggests otherwise. It also
2249: means that we have to grub around within the jump expression to find
2250: out what the conditions are when the jump isn't taken. */
2251: int jump_clobbers = 0;
2252:
2253: /* If we start with a return insn, we only succeed if we find another one. */
2254: int seeking_return = 0;
2255:
2256: /* START_INSN will hold the insn from where we start looking. This is the
2257: first insn after the following code_label if REVERSE is true. */
2258: rtx start_insn = insn;
2259:
2260: /* If in state 4, check if the target branch is reached, in order to
2261: change back to state 0. */
2262: if (arm_ccfsm_state == 4)
2263: {
2264: if (insn == arm_target_insn)
2265: {
2266: arm_target_insn = NULL;
2267: arm_ccfsm_state = 0;
2268: }
2269: return;
2270: }
2271:
2272: /* If in state 3, it is possible to repeat the trick, if this insn is an
2273: unconditional branch to a label, and immediately following this branch
2274: is the previous target label which is only used once, and the label this
2275: branch jumps to is not too far off. */
2276: if (arm_ccfsm_state == 3)
2277: {
2278: if (simplejump_p (insn))
2279: {
2280: start_insn = next_nonnote_insn (start_insn);
2281: if (GET_CODE (start_insn) == BARRIER)
2282: {
2283: /* XXX Isn't this always a barrier? */
2284: start_insn = next_nonnote_insn (start_insn);
2285: }
2286: if (GET_CODE (start_insn) == CODE_LABEL
2287: && CODE_LABEL_NUMBER (start_insn) == arm_target_label
2288: && LABEL_NUSES (start_insn) == 1)
2289: reverse = TRUE;
2290: else
2291: return;
2292: }
2293: else if (GET_CODE (body) == RETURN)
2294: {
2295: start_insn = next_nonnote_insn (start_insn);
2296: if (GET_CODE (start_insn) == BARRIER)
2297: start_insn = next_nonnote_insn (start_insn);
2298: if (GET_CODE (start_insn) == CODE_LABEL
2299: && CODE_LABEL_NUMBER (start_insn) == arm_target_label
2300: && LABEL_NUSES (start_insn) == 1)
2301: {
2302: reverse = TRUE;
2303: seeking_return = 1;
2304: }
2305: else
2306: return;
2307: }
2308: else
2309: return;
2310: }
2311:
2312: if (arm_ccfsm_state != 0 && !reverse)
2313: abort ();
2314: if (GET_CODE (insn) != JUMP_INSN)
2315: return;
2316:
2317: /* This jump might be paralled with a clobber of the condition codes
2318: the jump should always come first */
2319: if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0) > 0)
2320: body = XVECEXP (body, 0, 0);
2321:
2322: #if 0
2323: /* If this is a conditional return then we don't want to know */
2324: if (GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == PC
2325: && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE
2326: && (GET_CODE (XEXP (SET_SRC (body), 1)) == RETURN
2327: || GET_CODE (XEXP (SET_SRC (body), 2)) == RETURN))
2328: return;
2329: #endif
2330:
2331: if (reverse
2332: || (GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == PC
2333: && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE))
2334: {
2335: int insns_skipped = 0, fail = FALSE, succeed = FALSE;
2336: /* Flag which part of the IF_THEN_ELSE is the LABEL_REF. */
2337: int then_not_else = TRUE;
2338: rtx this_insn = start_insn, label = 0;
2339:
2340: if (get_attr_conds (insn) == CONDS_JUMP_CLOB)
2341: jump_clobbers = 1;
2342:
2343: /* Register the insn jumped to. */
2344: if (reverse)
2345: {
2346: if (!seeking_return)
2347: label = XEXP (SET_SRC (body), 0);
2348: }
2349: else if (GET_CODE (XEXP (SET_SRC (body), 1)) == LABEL_REF)
2350: label = XEXP (XEXP (SET_SRC (body), 1), 0);
2351: else if (GET_CODE (XEXP (SET_SRC (body), 2)) == LABEL_REF)
2352: {
2353: label = XEXP (XEXP (SET_SRC (body), 2), 0);
2354: then_not_else = FALSE;
2355: }
2356: else if (GET_CODE (XEXP (SET_SRC (body), 1)) == RETURN)
2357: seeking_return = 1;
2358: else if (GET_CODE (XEXP (SET_SRC (body), 2)) == RETURN)
2359: {
2360: seeking_return = 1;
2361: then_not_else = FALSE;
2362: }
2363: else
2364: abort ();
2365:
2366: /* See how many insns this branch skips, and what kind of insns. If all
2367: insns are okay, and the label or unconditional branch to the same
2368: label is not too far away, succeed. */
2369: for (insns_skipped = 0;
2370: !fail && !succeed && insns_skipped < MAX_INSNS_SKIPPED;
2371: insns_skipped++)
2372: {
2373: rtx scanbody;
2374:
2375: this_insn = next_nonnote_insn (this_insn);
2376: if (!this_insn)
2377: break;
2378:
2379: scanbody = PATTERN (this_insn);
2380:
2381: switch (GET_CODE (this_insn))
2382: {
2383: case CODE_LABEL:
2384: /* Succeed if it is the target label, otherwise fail since
2385: control falls in from somewhere else. */
2386: if (this_insn == label)
2387: {
2388: if (jump_clobbers)
2389: {
2390: arm_ccfsm_state = 2;
2391: this_insn = next_nonnote_insn (this_insn);
2392: }
2393: else
2394: arm_ccfsm_state = 1;
2395: succeed = TRUE;
2396: }
2397: else
2398: fail = TRUE;
2399: break;
2400:
2401: case BARRIER:
2402: /* Succeed if the following insn is the target label.
2403: Otherwise fail.
2404: If return insns are used then the last insn in a function
2405: will be a barrier. */
2406: this_insn = next_nonnote_insn (this_insn);
2407: if (this_insn && this_insn == label)
2408: {
2409: if (jump_clobbers)
2410: {
2411: arm_ccfsm_state = 2;
2412: this_insn = next_nonnote_insn (this_insn);
2413: }
2414: else
2415: arm_ccfsm_state = 1;
2416: succeed = TRUE;
2417: }
2418: else
2419: fail = TRUE;
2420: break;
2421:
2422: case CALL_INSN:
2423: /* The arm 6xx uses full 32 bit addresses so the cc is not
2424: preserved over calls */
2425: if (TARGET_6)
2426: fail = TRUE;
2427: break;
2428: case JUMP_INSN:
2429: /* If this is an unconditional branch to the same label, succeed.
2430: If it is to another label, do nothing. If it is conditional,
2431: fail. */
2432: /* XXX Probably, the test for the SET and the PC are unnecessary. */
2433:
2434: if (GET_CODE (scanbody) == SET
2435: && GET_CODE (SET_DEST (scanbody)) == PC)
2436: {
2437: if (GET_CODE (SET_SRC (scanbody)) == LABEL_REF
2438: && XEXP (SET_SRC (scanbody), 0) == label && !reverse)
2439: {
2440: arm_ccfsm_state = 2;
2441: succeed = TRUE;
2442: }
2443: else if (GET_CODE (SET_SRC (scanbody)) == IF_THEN_ELSE)
2444: fail = TRUE;
2445: }
2446: else if (GET_CODE (scanbody) == RETURN
2447: && seeking_return)
2448: {
2449: arm_ccfsm_state = 2;
2450: succeed = TRUE;
2451: }
2452: else if (GET_CODE (scanbody) == PARALLEL)
2453: {
2454: switch (get_attr_conds (this_insn))
2455: {
2456: case CONDS_NOCOND:
2457: break;
2458: default:
2459: fail = TRUE;
2460: break;
2461: }
2462: }
2463: break;
2464:
2465: case INSN:
2466: /* Instructions using or affecting the condition codes make it
2467: fail. */
2468: if ((GET_CODE (scanbody) == SET
2469: || GET_CODE (scanbody) == PARALLEL)
2470: && get_attr_conds (this_insn) != CONDS_NOCOND)
2471: fail = TRUE;
2472: break;
2473:
2474: default:
2475: break;
2476: }
2477: }
2478: if (succeed)
2479: {
2480: if ((!seeking_return) && (arm_ccfsm_state == 1 || reverse))
2481: arm_target_label = CODE_LABEL_NUMBER (label);
2482: else if (seeking_return || arm_ccfsm_state == 2)
2483: {
2484: while (this_insn && GET_CODE (PATTERN (this_insn)) == USE)
2485: {
2486: this_insn = next_nonnote_insn (this_insn);
2487: if (this_insn && (GET_CODE (this_insn) == BARRIER
2488: || GET_CODE (this_insn) == CODE_LABEL))
2489: abort ();
2490: }
2491: if (!this_insn)
2492: {
2493: /* Oh, dear! we ran off the end.. give up */
2494: recog (PATTERN (insn), insn, NULL_PTR);
2495: arm_ccfsm_state = 0;
2496: arm_target_insn = NULL;
2497: return;
2498: }
2499: arm_target_insn = this_insn;
2500: }
2501: else
2502: abort ();
2503: if (jump_clobbers)
2504: {
2505: if (reverse)
2506: abort ();
2507: arm_current_cc =
2508: get_arm_condition_code (XEXP (XEXP (XEXP (SET_SRC (body),
2509: 0), 0), 1));
2510: if (GET_CODE (XEXP (XEXP (SET_SRC (body), 0), 0)) == AND)
2511: arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
2512: if (GET_CODE (XEXP (SET_SRC (body), 0)) == NE)
2513: arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
2514: }
2515: else
2516: {
2517: /* If REVERSE is true, ARM_CURRENT_CC needs to be inverted from
2518: what it was. */
2519: if (!reverse)
2520: arm_current_cc = get_arm_condition_code (XEXP (SET_SRC (body),
2521: 0));
2522: }
2523:
2524: if (reverse || then_not_else)
2525: arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
2526: }
2527: /* restore recog_operand (getting the attributes of other insns can
2528: destroy this array, but final.c assumes that it remains intact
2529: accross this call; since the insn has been recognized already we
2530: call recog direct). */
2531: recog (PATTERN (insn), insn, NULL_PTR);
2532: }
2533: } /* final_prescan_insn */
2534:
2535: /* EOF */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.