|
|
1.1 root 1: /* Output routines for GCC for Hitachi Super-H
2: Copyright (C) 1993 Free Software Foundation, Inc.
3:
4: This file is part of GNU CC.
5:
6: GNU CC is free software; you can redistribute it and/or modify
7: it under the terms of the GNU General Public License as published by
8: the Free Software Foundation; either version 2, or (at your option)
9: any later version.
10:
11: GNU CC is distributed in the hope that it will be useful,
12: but WITHOUT ANY WARRANTY; without even the implied warranty of
13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14: GNU General Public License for more details.
15:
16: You should have received a copy of the GNU General Public License
17: along with GNU CC; see the file COPYING. If not, write to
18: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19:
20:
21: /* Contributed by Steve Chamberlain ([email protected]) */
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 "tree.h"
34: #include "output.h"
35: #include "insn-attr.h"
36: #include "flags.h"
37: #include "obstack.h"
38: #include "expr.h"
39:
40:
41: static int add_constant ();
42: int dump_constants ();
43:
44: int current_function_anonymous_args;
45: extern int current_function_pretend_args_size;
46: extern char *version_string;
47: extern int flag_traditional;
48:
49:
50: enum attr_cpu sh_cpu; /* target cpu */
51:
52: /* Global variables for machine-dependent things. */
53:
54: /* Saved operands from the last compare to use when we generate an scc
55: or bcc insn. */
56:
57: rtx sh_compare_op0;
58: rtx sh_compare_op1;
59:
60: /* Provides the class number of the smallest class containing
61: reg number */
62:
63: int regno_reg_class[FIRST_PSEUDO_REGISTER] =
64: {
65: R0_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
66: GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
67: GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
68: GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
69: GENERAL_REGS, PR_REGS, T_REGS, NO_REGS, MAC_REGS,
70: MAC_REGS,
71: };
72:
73: /* Provide reg_class from a letter such as appears in the machine
74: description. */
75:
76: enum reg_class reg_class_from_letter[] =
77: {
78: /* a */ NO_REGS, /* b */ NO_REGS, /* c */ NO_REGS, /* d */ NO_REGS,
79: /* e */ NO_REGS, /* f */ NO_REGS, /* g */ NO_REGS, /* h */ NO_REGS,
80: /* i */ NO_REGS, /* j */ NO_REGS, /* k */ NO_REGS, /* l */ PR_REGS,
81: /* m */ NO_REGS, /* n */ NO_REGS, /* o */ NO_REGS, /* p */ NO_REGS,
82: /* q */ NO_REGS, /* r */ NO_REGS, /* s */ NO_REGS, /* t */ T_REGS,
83: /* u */ NO_REGS, /* v */ NO_REGS, /* w */ NO_REGS, /* x */ MAC_REGS,
84: /* y */ NO_REGS, /* z */ R0_REGS
85: };
86:
87:
88:
89:
90: /* Local label counter, used for constants in the pool and inside
91: pattern branches. */
92:
93: static int lf = 100;
94:
95: /* Used to work out sizes of instructions */
96: static int first_pc;
97: static int pc;
98: #define MAYBE_DUMP_LEVEL 900
99: #define MUST_DUMP_LEVEL 1000
100: static int dumpnext;
101:
102:
103: void
104: push (rn)
105: {
106: emit_insn (gen_push (gen_rtx (REG, SImode, rn)));
107: }
108:
109: void
110: pop (rn)
111: {
112: emit_insn (gen_pop (gen_rtx (REG, SImode, rn)));
113: }
114:
115:
116: /* Adjust the stack and return the number of bytes taken to do it */
117:
118: static void
119: output_stack_adjust (direction, size)
120: int direction;
121: int size;
122: {
123: if (size)
124: {
125: rtx val = GEN_INT (size);
126: rtx insn;
127:
128: if (size > 120)
129: {
130: rtx nval = gen_rtx (REG, SImode, 13);
131: emit_insn (gen_movsi (nval, val));
132: val = nval;
133: }
134:
135: if (direction > 0)
136: insn = gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, val);
137: else
138: insn = gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, val);
139:
140: emit_insn (insn);
141: }
142: }
143:
144:
145:
146: /* Generate code to push the regs specified in the mask, and return
147: the number of bytes the insns take. */
148:
149: static void
150: push_regs (mask)
151: int mask;
152: {
153: int i;
154: int size = 0;
155:
156: for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
157: {
158: if (mask & (1 << i))
159: {
160: push (i);
161: }
162: }
163: }
164:
165:
166: /*
167: Print an instruction which would have gone into a delay slot
168: after an instructiuon, but couldn't because the instruction expanded
169: into a sequence where putting the slot insn at the end wouldn't work.
170: */
171:
172: void
173: print_slot (insn)
174: rtx insn;
175: {
176: final_scan_insn (XVECEXP (insn, 0, 1), asm_out_file, optimize, 0, 1);
177:
178: INSN_DELETED_P (XVECEXP (insn, 0, 1)) = 1;
179: }
180:
181: /* Number of bytes pushed for anonymous args */
182:
183: static int extra_push;
184:
185: /* Work out the registers which need to be saved, both as a mask and a
186: count */
187:
188: int
189: calc_live_regs (count)
190: int *count;
191: {
192: int reg;
193: int live_regs_mask = 0;
194: *count = 0;
195:
196: for (reg = 0; reg < FIRST_PSEUDO_REGISTER; reg++)
197: {
198: if (regs_ever_live[reg] && !call_used_regs[reg])
199: {
200: (*count)++;
201: live_regs_mask |= (1 << reg);
202: }
203: }
204: return live_regs_mask;
205: }
206:
207:
208:
209:
210: static int
211: need_slot (insn)
212: rtx insn;
213: {
214: return (insn && !INSN_ANNULLED_BRANCH_P (XVECEXP (insn, 0, 0)));
215: }
216:
217: /* Print the operand address in x to the stream */
218:
219: void
220: print_operand_address (stream, x)
221: FILE *stream;
222: rtx x;
223: {
224: switch (GET_CODE (x))
225: {
226: case REG:
227: fprintf (stream, "@%s", reg_names[REGNO (x)]);
228: break;
229: case PLUS:
230: {
231: rtx base = XEXP (x, 0);
232: rtx index = XEXP (x, 1);
233:
234: if (GET_CODE (base) != REG)
235: {
236: /* Ensure that BASE is a register (one of them must be). */
237: rtx temp = base;
238: base = index;
239: index = temp;
240: }
241:
242: switch (GET_CODE (index))
243: {
244: case CONST_INT:
245: fprintf (stream, "@(%d,%s)",
246: INTVAL (index),
247: reg_names[REGNO (base)]);
248: break;
249:
250: case REG:
251: fprintf (stream, "@(r0,%s)",
252: reg_names[MAX (REGNO (base), REGNO (index))]);
253:
254: break;
255:
256: default:
257: debug_rtx (x);
258:
259: abort ();
260: }
261: }
262:
263: break;
264: case PRE_DEC:
265: fprintf (stream, "@-%s", reg_names[REGNO (XEXP (x, 0))]);
266: break;
267:
268: case POST_INC:
269: fprintf (stream, "@%s+", reg_names[REGNO (XEXP (x, 0))]);
270: break;
271:
272: default:
273: output_addr_const (stream, x);
274: break;
275: }
276: }
277:
278: /* Print operand x (an rtx) in assembler syntax to file stream
279: according to modifier code.
280:
281: '.' print a .s if insn needs delay slot
282: '*' print a local label
283: '^' increment the local label number
284: '!' dump the constant table
285: '#' output a nop if there is nothing to put in the delay slot
286: 'R' print the next register or memory location along, ie the lsw in
287: a double word value
288: 'O' print a constant without the #
289: 'M' print a constant as its negative
290: 'I' put something into the constant pool and print its label */
291:
292: void
293: print_operand (stream, x, code)
294: FILE *stream;
295: rtx x;
296: int code;
297: {
298: switch (code)
299: {
300:
301:
302: case '.':
303: if (need_slot (final_sequence))
304: fprintf (stream, ".s");
305: break;
306: case '*':
307: fprintf (stream, "LF%d", lf);
308: break;
309: case '!':
310: dump_constants (0);
311: break;
312: case '^':
313: lf++;
314: break;
315:
316: case '#':
317: /* Output a nop if there's nothing in the delay slot */
318: if (dbr_sequence_length () == 0)
319: {
320: fprintf (stream, "\n\tor r0,r0\t!wasted slot");
321: }
322: break;
323: case 'O':
324: fprintf (asm_out_file, "%d", INTVAL (x));
325: break;
326:
327: case 'I':
328: fprintf (asm_out_file, "LK%d", add_constant (x, SImode));
329: break;
330:
331: case 'M':
332: fprintf (asm_out_file, "#%d", -INTVAL (x));
333: break;
334:
335: case 'R':
336: /* Next location along in memory or register*/
337: switch (GET_CODE (x))
338: {
339: case REG:
340: fputs (reg_names[REGNO (x) + 1], (stream));
341: break;
342: case MEM:
343: print_operand_address (stream,
344: XEXP (adj_offsettable_operand (x, 4), 0), 0);
345: break;
346: }
347: break;
348:
349: default:
350: switch (GET_CODE (x))
351: {
352: case REG:
353: fputs (reg_names[REGNO (x)], (stream));
354: break;
355: case MEM:
356: output_address (XEXP (x, 0));
357: break;
358: default:
359: fputc ('#', stream);
360: output_addr_const (stream, x);
361: break;
362:
363: }
364: break;
365: }
366: }
367:
368:
369:
370: /* Define the offset between two registers, one to be eliminated, and
371: the other its replacement, at the start of a routine. */
372:
373: int
374: initial_elimination_offset (from, to)
375: {
376: int regs_saved;
377: int d = calc_live_regs (®s_saved);
378: int total_saved_regs_space = (regs_saved) * 4;
379: int total_auto_space = get_frame_size ();
380:
381:
382: if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
383: {
384: return total_saved_regs_space;
385: }
386:
387: if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
388: {
389: return total_saved_regs_space + total_auto_space;
390: }
391:
392: if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
393: {
394: return total_auto_space;
395: }
396: }
397:
398:
399: /* Prepare operands for a move define_expand; specifically, one of the
400: operands must be in a register. Take this chance to remove
401: addressing modes which can't be coped with very well. */
402:
403: int
404: prepare_move_operands (operands, mode)
405: rtx operands[];
406: enum machine_mode mode;
407: {
408: /* One of the operands has to be a register */
409: if ((!register_operand (operands[0], mode)
410: && !register_operand (operands[1], mode))
411: || GET_CODE (operands[1]) == PLUS)
412: {
413: /* copy the source to a register */
414: operands[1] = copy_to_mode_reg (mode, operands[1]);
415: }
416:
417: /* If we've got a negative index, break it down */
418:
419: if (GET_CODE (operands[0]) == MEM && !reload_in_progress)
420: {
421:
422: rtx inside = XEXP (operands[0], 0);
423: if (GET_CODE (inside) == PLUS)
424: {
425: rtx inside1 = XEXP (inside, 1);
426: if (GET_CODE (inside1) == CONST_INT
427: && INTVAL (inside1) < 0)
428: {
429: /* Catch this now and break it into bits, it will only cause
430: problems later */
431:
432: rtx sub = copy_to_mode_reg (SImode, inside);
433: XEXP (operands[0], 0) = sub;
434: }
435: }
436: }
437: return 0;
438: }
439:
440:
441: /* Prepare the operands for an scc instruction; make sure that the
442: compare has been done. */
443: rtx
444: prepare_scc_operands (code)
445: {
446: if (GET_CODE (sh_compare_op0) != REG
447: || REGNO (sh_compare_op0) != T_REG)
448: {
449: /* First need a compare insn */
450: emit_insn (gen_rtx (SET, SImode,
451: gen_rtx (REG, SImode, T_REG),
452: gen_rtx (code, SImode, sh_compare_op0,
453: sh_compare_op1)));
454: }
455: return gen_rtx (REG, SImode, T_REG);
456: }
457:
458:
459: /* Functions to output assembly */
460:
461: /* Return a sequence of instructions to perform DI or DF move.
462:
463: Since the SH cannot move a DI or DF in one instruction, we have
464: to take care when we see overlapping source and dest registers.
465:
466: */
467: char *
468: output_movedouble (operands, mode)
469: rtx operands[];
470: enum machine_mode mode;
471: {
472: rtx dst = operands[0];
473: rtx src = operands[1];
474: int lowfirst;
475:
476: if (register_operand (dst, mode)
477: && register_operand (src, mode))
478: {
479: if (REGNO (src) == MACH_REG)
480: return "sts mach,%0\n\tsts macl,%R0";
481:
482: /*
483: when mov.d r1,r2 do r2->r3 then r1->r2
484: when mov.d r1,r0 do r1->r0 then r2->r1
485: */
486:
487: if (REGNO (src) + 1 == REGNO (dst))
488: return "mov %1,%0\n\tmov %R1,%R0 ! cr";
489: else
490: return "mov %R1,%R0\n\tmov %1,%0 ";
491:
492: }
493: else if (GET_CODE (src) == CONST_INT)
494: {
495: if (INTVAL (src) < 0)
496: return "mov #-1,%0\n\tmov %1,%R0";
497: else
498: return "mov #0,%0\n\tmov %1,%R0";
499: }
500:
501: else if (GET_CODE (src) == MEM)
502: {
503: int ptrreg1 = -1;
504: int ptrreg2 = -1;
505: int dreg = REGNO (dst);
506: rtx inside = XEXP (src, 0);
507:
508: if (GET_CODE (inside) == REG)
509: {
510: ptrreg1 = REGNO (inside);
511: }
512: else if (GET_CODE (inside) == PLUS)
513: {
514: rtx lhs = XEXP (inside, 0);
515: rtx rhs = XEXP (inside, 1);
516: if (GET_CODE (lhs) == REG)
517: ptrreg1 = REGNO (lhs);
518: if (GET_CODE (rhs) == REG)
519: ptrreg2 = REGNO (rhs);
520: }
521: else
522: abort ();
523:
524:
525: if ((ptrreg1 >= 0 && ptrreg2 >= 0)
526: && (dreg == ptrreg1
527: || dreg == ptrreg2
528: || dreg + 1 == ptrreg1
529: || dreg + 1 == ptrreg2))
530: {
531: /* This move clobbers both index registers,
532: calculate the sum in one register. */
533: fprintf (asm_out_file, " add %s,%s ! special fix\n",
534: reg_names[ptrreg2], reg_names[ptrreg1]);
535:
536: if (dreg == ptrreg1)
537: {
538: /* Copy into dreg+1 first. */
539: fprintf (asm_out_file, " mov.l @(4,%s),%s\n",
540: reg_names[ptrreg1],
541: reg_names[dreg + 1]);
542:
543: fprintf (asm_out_file, " mov.l @(%s),%s\n",
544: reg_names[ptrreg1],
545: reg_names[dreg]);
546: }
547: else
548: {
549: /* Copy into dreg first. */
550: fprintf (asm_out_file, " mov.l @(%s),%s\n",
551: reg_names[ptrreg1],
552: reg_names[dreg]);
553:
554: fprintf (asm_out_file, " mov.l @(4,%s),%s\n",
555: reg_names[ptrreg1],
556: reg_names[dreg + 1]);
557:
558: }
559: warning ("generated complex amode");
560: return "";
561: }
562:
563: /* Work out the safe way to copy */
564: if (dreg == ptrreg1)
565: {
566: /* Copy into the second half first */
567: return "mov.l %R1,%R0\n\tmov.l %1,%0 ! cr";
568: }
569: }
570:
571: return "mov.l %1,%0\n\tmov.l %R1,%R0";
572: }
573:
574: /* Emit assembly to shift reg by k bits */
575:
576: char *
577: output_shift (string, reg, k, code)
578: char *string;
579: rtx reg;
580: rtx k;
581: int code;
582:
583: {
584: int s = INTVAL (k);
585:
586: if (code == ASHIFT && s == 31)
587: {
588: /* Shift left by 31 moving into the t bit, clearing and rotating the other way */
589:
590: fprintf (asm_out_file, "\trotr r%d\n", REGNO (reg));
591: fprintf (asm_out_file, "\tmov #0,r%d\n", REGNO (reg));
592: fprintf (asm_out_file, "\trotcr r%d\n", REGNO (reg));
593: s = 0;
594: }
595:
596: if (code == LSHIFTRT && s == 31)
597: {
598: fprintf (asm_out_file, "\trotl r%d\n", REGNO (reg));
599: fprintf (asm_out_file, "\tmov #0,r%d\n", REGNO (reg));
600: fprintf (asm_out_file, "\trotcl r%d\n", REGNO (reg));
601: s = 0;
602: }
603:
604: while (s)
605: {
606: char *out;
607: int d;
608:
609: if (s >= 16)
610: {
611: d = 16;
612: out = "16";
613: }
614: else if (s >= 8)
615: {
616: d = 8;
617: out = "8";
618: }
619: else if (s >= 2)
620: {
621: d = 2;
622: out = "2";
623: }
624: else
625: {
626: d = 1;
627: out = "";
628: }
629: fprintf (asm_out_file, "\t%s%s\tr%d\n", string, out, REGNO (reg));
630: s -= d;
631: }
632: return "";
633: }
634:
635: /* Return the text of the branch instruction which matches its length
636: attribute.
637:
638: This gets tricky if we have an insn in the delay slot of a branch
639: and the branch needs more than 1 insn to complete.*/
640:
641:
642:
643: char *
644: output_branch (logic, insn)
645: int logic;
646: rtx insn;
647: {
648: extern rtx recog_operand[];
649: int label = lf++;
650: int rn = -1;
651: int need_save;
652:
653: switch (get_attr_length (insn))
654: {
655: case 2:
656: /* Simple branch in range -200..+200 bytes */
657: return logic ? "bt%. %l0" : "bf%. %l0";
658:
659: case 6:
660: /* Branch in range -4000..+4000 bytes */
661: {
662: rtx oldop = recog_operand[0];
663:
664:
665: if (need_slot (final_sequence))
666: {
667: fprintf (asm_out_file, "\tb%c.s\tLF%d\n", logic ? 'f' : 't',
668: label);
669:
670: print_slot (final_sequence);
671: }
672:
673: else
674: {
675: fprintf (asm_out_file, "\tb%c\tLF%d\n", logic ? 'f' : 't',
676: label);
677: }
678: recog_operand[0] = oldop;
679:
680: output_asm_insn ("bra %l0 ! 12 bit cond ", recog_operand);
681: fprintf (asm_out_file, "\tor r0,r0\n");
682: label = dump_constants (label);
683: fprintf (asm_out_file, "LF%d:\n", label);
684: }
685:
686: return "";
687:
688: case 8:
689: /* Branches a long way away */
690: {
691:
692: rtx oldop = recog_operand[0];
693:
694: if (need_slot (final_sequence))
695: {
696: fprintf (asm_out_file, "\tb%c.s\tLF%d\n", logic ? 'f' : 't', label);
697: print_slot (final_sequence);
698:
699: }
700: else
701: {
702: fprintf (asm_out_file, "\tb%c\tLF%d\n", logic ? 'f' : 't', label);
703: }
704:
705: recog_operand[0] = oldop;
706:
707: /* We use r13 as a scratch */
708: need_save = 0;
709: rn = 13;
710:
711: if (need_save)
712: fprintf (asm_out_file, "\tpush r%d\n", rn);
713: fprintf (asm_out_file, "\tmov.l LK%d,r%d\n", add_constant (oldop, SImode), rn);
714: fprintf (asm_out_file, "\tjmp @r%d ! 32 cond \n", rn);
715: if (need_save)
716: fprintf (asm_out_file, "\tpop r%d\n", rn);
717: else
718: fprintf (asm_out_file, "\tor r0,r0\n");
719: fprintf (asm_out_file, "LF%d:\n", label);
720: return "";
721: }
722: }
723: return "bad";
724: }
725:
726:
727: /* Predicates used by the templates */
728:
729: /* Non zero if op is an immediate ok for a byte index */
730:
731: int
732: byte_index_operand (op, mode)
733: rtx op;
734: enum machine_mode mode;
735: {
736: return (GET_CODE (op) == CONST_INT
737: && INTVAL (op) >= 0 && INTVAL (op) <= 15);
738: }
739:
740: /* Non zero if OP is a pop operand */
741:
742: int
743: pop_operand (op, mode)
744: rtx op;
745: enum machine_mode mode;
746: {
747: if (GET_CODE (op) != MEM)
748: return 0;
749:
750: if (GET_MODE (op) != mode)
751: return 0;
752:
753: op = XEXP (op, 0);
754:
755: if (GET_CODE (op) != POST_INC)
756: return 0;
757:
758: return XEXP (op, 0) == stack_pointer_rtx;
759: }
760:
761: /* Non zero if OP is an immediate which can be made from two insns. */
762:
763: int
764: painful_immediate_operand (op, mode)
765: rtx op;
766: enum machine_mode mode;
767: {
768: if (GET_CODE (op) == CONST_INT)
769: {
770: int i = INTVAL (op);
771:
772: if (i > 127 && i < 255)
773: return 1; /* two adds */
774: }
775: return 0;
776: }
777:
778:
779: /* Non zero if OP can be source of a simple move operation. */
780:
781: int
782: general_movsrc_operand (op, mode)
783: rtx op;
784: enum machine_mode mode;
785: {
786: if (GET_CODE (op) == REG
787: || GET_CODE (op) == SUBREG
788: || (GET_CODE (op) == CONST_INT &&
789: CONST_OK_FOR_I (INTVAL (op)))
790: || GET_CODE (op) == MEM)
791: return general_operand (op, mode);
792: return 0;
793: }
794:
795:
796:
797: /* Nonzero if OP is a normal arithmetic register. */
798:
799: int
800: arith_reg_operand (op, mode)
801: rtx op;
802: enum machine_mode mode;
803: {
804: if (register_operand (op, mode))
805: {
806: if (GET_CODE (op) == REG)
807: return REGNO (op) != T_REG;
808: return 1;
809: }
810: return 0;
811: }
812:
813:
814: /* Nonzero if OP is a valid source operand for an arithmetic insn. */
815:
816: int
817: arith_operand (op, mode)
818: rtx op;
819: enum machine_mode mode;
820: {
821: if (register_operand (op, mode))
822: return 1;
823:
824: if (GET_CODE (op) == CONST_INT)
825: {
826: if (CONST_OK_FOR_I (INTVAL (op)))
827: return 1;
828: }
829: return 0;
830: }
831:
832:
833: /* Nonzero if OP is a valid source operand for a logical operation */
834:
835: int
836: logical_operand (op, mode)
837: rtx op;
838: enum machine_mode mode;
839: {
840: if (register_operand (op, mode))
841: return 1;
842:
843: if (GET_CODE (op) == CONST_INT)
844: {
845: if (CONST_OK_FOR_L (INTVAL (op)))
846: return 1;
847: }
848: return 0;
849: }
850:
851: /* Nonzero if p is a valid shift operand for lshr and ashl */
852:
853: int
854: ok_shift_value (p)
855: rtx p;
856: {
857: if (GET_CODE (p) == CONST_INT)
858: {
859: switch (INTVAL (p))
860: {
861: case 1:
862: case 2:
863: case 8:
864: case 16:
865: return 1;
866: default:
867: if (TARGET_FASTCODE)
868: return INTVAL (p) >= 0;
869: }
870: }
871: return 0;
872: }
873:
874: /* Nonzero if the arg is an immediate which has to be loaded from
875: memory */
876:
877: int
878: hard_immediate_operand (op, mode)
879: rtx op;
880: enum machine_mode mode;
881: {
882: if (immediate_operand (op, mode))
883: {
884: if (GET_CODE (op) == CONST_INT
885: && INTVAL (op) >= -128 && INTVAL (op) < 127)
886: return 0;
887: return 1;
888: }
889: return 0;
890: }
891:
892: /* The SH cannot load a large constant into a register, constants have to
893: come from a pc relative load. The reference of a pc relative load
894: instruction must be less than 1k infront of the instruction. This
895: means that we often have to dump a constant inside a function, and
896: generate code to branch around it.
897:
898: It is important to minimize this, since the branches will slow things
899: down and make things bigger.
900:
901: Worst case code looks like:
902:
903: mov.l L1,rn
904: bra L2
905: nop
906: align
907: L1: .long value
908: L2:
909: ..
910:
911: mov.l L3,rn
912: bra L4
913: nop
914: align
915: L3: .long value
916: L4:
917: ..
918:
919: During shorten_branches we notice the instructions which can have a
920: constant table in them, if we see two that are close enough
921: together, we move the constants from the first table to the second
922: table and continue. This process can happen again and again, and
923: in the best case, moves the constant table outside of the function.
924:
925: In the above example, we can tell that L3 is within 1k of L1, so
926: the first move can be shrunk from the 3 insn+constant sequence into
927: just 1 insn, and the constant moved to L3 to make:
928:
929: mov.l L1,rn
930: ..
931: mov.l L3,rn
932: bra L4
933: nop
934: align
935: L3:.long value
936: L4:.long value
937:
938: Then the second move becomes the target for the shortening process.
939:
940: We keep a simple list of all the constants accumulated in the
941: current pool so there are no duplicates in a single table, but
942: they are not factored into the size estimates.
943:
944: */
945:
946: typedef struct
947: {
948: rtx value;
949: int number;
950: enum machine_mode mode;
951: } pool_node;
952:
953: /* The maximum number of constants that can fit into one pool, since
954: the pc relative range is 0...1020 bytes and constants are at least 4
955: bytes long */
956:
957: #define MAX_POOL_SIZE (1020/4)
958: static pool_node pool_vector[MAX_POOL_SIZE];
959: static int pool_size;
960:
961:
962: /* Add a constant to the pool and return its label number. */
963:
964: static int
965: add_constant (x, mode)
966: rtx x;
967: enum machine_mode mode;
968: {
969: int i;
970:
971: /* Start the countdown on the first constant */
972:
973: if (!pool_size)
974: {
975: first_pc = pc;
976: }
977:
978: /* First see if we've already got it */
979:
980: for (i = 0; i < pool_size; i++)
981: {
982:
983: if (x->code == pool_vector[i].value->code
984: && mode == pool_vector[i].mode)
985: {
986: if (x->code == CODE_LABEL)
987: {
988: if (XINT (x, 3) != XINT (pool_vector[i].value, 3))
989: continue;
990: }
991: }
992:
993: if (rtx_equal_p (x, pool_vector[i].value))
994: return pool_vector[i].number;
995: }
996:
997:
998: pool_vector[pool_size].value = x;
999: pool_vector[pool_size].mode = mode;
1000: pool_vector[pool_size].number = lf;
1001: pool_size++;
1002:
1003: return lf++;
1004: }
1005:
1006: /* Nonzero if the insn could take a constant table. */
1007:
1008: static int
1009: has_constant_table (insn)
1010: rtx insn;
1011: {
1012: rtx body;
1013:
1014: if (GET_CODE (insn) == NOTE
1015: || GET_CODE (insn) == BARRIER
1016: || GET_CODE (insn) == CODE_LABEL)
1017: return 0;
1018:
1019: body = PATTERN (insn);
1020: if (GET_CODE (body) == SEQUENCE)
1021: return 0;
1022: if (GET_CODE (body) == ADDR_VEC)
1023: return 0;
1024: if (GET_CODE (body) == USE)
1025: return 0;
1026: if (GET_CODE (body) == CLOBBER)
1027: return 0;
1028: if (get_attr_constneed (insn) == CONSTNEED_YES)
1029: return 1;
1030:
1031: if (GET_CODE (body) == UNSPEC_VOLATILE)
1032: {
1033: return INTVAL (XVECEXP (body, 0, 0)) == 1;
1034: }
1035: return 0;
1036: }
1037:
1038: /* Adjust the length of an instruction.
1039:
1040: We'll look at the previous instruction which holds a constant
1041: table and see if we can move the table to here instead. */
1042:
1043: int target_insn_uid;
1044: int target_insn_smallest_size;
1045:
1046: int target_pc;
1047: int target_insn_range;
1048: int current_pc;
1049: int pool_bytes;
1050:
1051: int last_uid;
1052: int last_pc;
1053:
1054: void
1055: adjust_insn_length (insn, insn_lengths)
1056: rtx insn;
1057: short *insn_lengths;
1058: {
1059: int uid = INSN_UID (insn);
1060: rtx body = PATTERN (insn);
1061:
1062: current_pc += insn_lengths[uid];
1063:
1064:
1065: if (GET_CODE (body) == SEQUENCE)
1066: {
1067: int i;
1068:
1069: for (i = 0; i < XVECLEN (body, 0); i++)
1070: {
1071: adjust_insn_length (XVECEXP (body, 0, i), insn_lengths);
1072: }
1073: }
1074: else
1075: {
1076: if (has_constant_table (insn))
1077: {
1078: if (current_pc >= target_insn_range)
1079: {
1080: /* This instruction is further away from the referencing
1081: instruction than it can reach, so we'll stop accumulating
1082: from that one and start fresh. */
1083: target_pc = current_pc;
1084: target_insn_range = current_pc + MAYBE_DUMP_LEVEL;
1085: }
1086: else
1087: {
1088: /* This instruction is within the reach of the target,
1089: remove the constant table from the target by adjusting
1090: downwards, and increase the size of this one to
1091: compensate. */
1092:
1093:
1094: /* Add the stuff from this insn to what will go in the
1095: growing table. */
1096:
1097: pool_bytes += get_attr_constantsize (insn);
1098:
1099: /* The target shinks to its smallest natural size */
1100: insn_lengths[target_insn_uid] = target_insn_smallest_size;
1101:
1102: /* The current insn grows to be its larger size plust the
1103: table size. */
1104:
1105: insn_lengths[uid] = get_attr_largestsize (insn) + pool_bytes;
1106:
1107: }
1108: /* Current insn becomes the target. */
1109: target_insn_uid = uid;
1110: target_insn_smallest_size = get_attr_smallestsize (insn);
1111:
1112: }
1113: }
1114: }
1115:
1116:
1117:
1118: /* Dump out the pending constant pool.
1119: If label provided then insert an branch in the middle of the table
1120: */
1121:
1122: int
1123: dump_constants (label)
1124: {
1125: int i;
1126: int rlabel = label;
1127: int size = 0;
1128:
1129: if (pool_size)
1130: {
1131: fprintf (asm_out_file, "\n\t! constants - waited %d\n", pc - first_pc);
1132: fprintf (asm_out_file, "\t.align\t2\n");
1133:
1134: for (i = 0; i < pool_size; i++)
1135: {
1136: pool_node *p = pool_vector + i;
1137:
1138: fprintf (asm_out_file, "LK%d:", p->number);
1139: size += GET_MODE_SIZE (p->mode);
1140:
1141: switch (GET_MODE_CLASS (p->mode))
1142: {
1143: case MODE_INT:
1144: case MODE_PARTIAL_INT:
1145: assemble_integer (p->value, GET_MODE_SIZE (p->mode), 1);
1146: break;
1147: case MODE_FLOAT:
1148: {
1149: union real_extract u;
1150: bcopy (&CONST_DOUBLE_LOW (p->value), &u, sizeof u);
1151: assemble_real (u.d, p->mode);
1152: }
1153: }
1154:
1155: /* After 200 bytes of table, stick in another branch */
1156: if (label && size > 200)
1157: {
1158: rlabel = lf++;
1159: fprintf (asm_out_file, "LF%d:\tbra LF%d\n", label, rlabel);
1160: fprintf (asm_out_file, "\tor r0,r0\n");
1161: label = 0;
1162: }
1163:
1164: }
1165: }
1166:
1167: pool_size = 0;
1168: current_pc = 0;
1169: pc = 0;
1170: pool_bytes = 0;
1171:
1172: target_insn_range = 0;
1173: return rlabel;
1174:
1175: }
1176:
1177:
1178: /* Emit the text to load a value from a constant table. */
1179:
1180: char *
1181: output_movepcrel (insn, operands, mode)
1182: rtx insn;
1183: rtx operands[];
1184: enum machine_mode mode;
1185: {
1186: int len = GET_MODE_SIZE (mode);
1187: int rn = REGNO (operands[0]);
1188:
1189: fprintf (asm_out_file, "\tmov.l LK%d,r%d\n",
1190: add_constant (operands[1], mode), rn);
1191:
1192: if (GET_MODE_SIZE (mode) > 4)
1193: {
1194: fprintf (asm_out_file,
1195: "\tmov.l LK%d+4,r%d\n",
1196: add_constant (operands[1], mode),
1197: rn + 1);
1198:
1199: }
1200:
1201: /* This may have been the last move in the function, so nothing
1202: took its constant table, we may be able to move it past the end
1203: of the function (after the rts) if we are careful */
1204:
1205: if (target_insn_uid == INSN_UID (insn)
1206: && current_pc < target_insn_range)
1207: return "";
1208:
1209:
1210: /* If this instruction is as small as it can be, there can be no
1211: constant table attached to it. */
1212: if (get_attr_length (insn) != get_attr_smallestsize (insn))
1213: {
1214: /* This needs a constant table */
1215: fprintf (asm_out_file, "\t!constant table start\n");
1216: fprintf (asm_out_file, "\tbra LF%d\n", lf);
1217: fprintf (asm_out_file, "\tor r0,r0 ! wasted slot\n");
1218: dump_constants (0);
1219: fprintf (asm_out_file, "LF%d:\n", lf++);
1220: fprintf (asm_out_file, "\t!constant table end\n");
1221: }
1222: return "";
1223: }
1224:
1225:
1226: /* Dump out interesting debug info */
1227:
1228: rtx
1229: final_prescan_insn (insn, opvec, noperands)
1230: rtx insn;
1231: rtx *opvec;
1232: int noperands;
1233: {
1234: register rtx body = PATTERN (insn);
1235:
1236: if (target_flags & ISIZE_BIT)
1237: {
1238: extern int *insn_addresses;
1239:
1240: fprintf (asm_out_file, "\n!%04x*\n",
1241: insn_addresses[INSN_UID (insn)] + 0x10);
1242:
1243: fprintf (asm_out_file, "\n!%04x %d %04x len=%d\n",
1244: pc, pool_size, first_pc, get_attr_length (insn));
1245:
1246: if (TARGET_DUMP_RTL)
1247: print_rtl (asm_out_file, body);
1248:
1249:
1250: }
1251:
1252: pc += get_attr_length (insn);
1253: if (pool_size && pc - first_pc > MUST_DUMP_LEVEL)
1254: {
1255: /* For some reason we have not dumped out a constant table, and
1256: we have emitted a lot of code. This can happen if the think
1257: which wants the table is a long conditional branch (which has no
1258: room for a constant table), and there has not been a move
1259: constant anywhere. */
1260: int label = lf++;
1261: fprintf (asm_out_file, "\t!forced constant table\n");
1262: fprintf (asm_out_file, "\tbra LF%d\n", label);
1263: fprintf (asm_out_file, "\tor r0,r0 ! wasted slot\n");
1264: label = dump_constants (label);
1265: fprintf (asm_out_file, "LF%d:\n", label);
1266: fprintf (asm_out_file, "\t!constant table end\n");
1267: }
1268: }
1269:
1270:
1271:
1272: /* Block move stuff stolen from m88k*/
1273:
1274: /* Emit code to perform a block move. Choose the best method.
1275:
1276: OPERANDS[0] is the destination.
1277: OPERANDS[1] is the source.
1278: OPERANDS[2] is the size.
1279: OPERANDS[3] is the alignment safe to use. */
1280:
1281: /* Emit code to perform a block move with an offset sequence of ld/st
1282: instructions (..., ld 0, st 1, ld 1, st 0, ...). SIZE and ALIGN are
1283: known constants. DEST and SRC are registers. OFFSET is the known
1284: starting point for the output pattern. */
1285:
1286: static enum machine_mode mode_from_align[] =
1287: {VOIDmode, QImode, HImode, VOIDmode, SImode,
1288: VOIDmode, VOIDmode, VOIDmode, DImode};
1289: static void
1290:
1291: block_move_sequence (dest, dest_mem, src, src_mem, size, align, offset)
1292: rtx dest, dest_mem;
1293: rtx src, src_mem;
1294: int size;
1295: int align;
1296: int offset;
1297: {
1298: rtx temp[2];
1299: enum machine_mode mode[2];
1300: int amount[2];
1301: int active[2];
1302: int phase = 0;
1303: int next;
1304: int offset_ld = offset;
1305: int offset_st = offset;
1306:
1307: active[0] = active[1] = FALSE;
1308:
1309: /* Establish parameters for the first load and for the second load if
1310: it is known to be the same mode as the first. */
1311: amount[0] = amount[1] = align;
1312:
1313:
1314: mode[0] = mode_from_align[align];
1315:
1316: temp[0] = gen_reg_rtx (mode[0]);
1317: if (size >= 2 * align)
1318: {
1319: mode[1] = mode[0];
1320: temp[1] = gen_reg_rtx (mode[1]);
1321: }
1322:
1323: do
1324: {
1325: rtx srcp, dstp;
1326: next = phase;
1327: phase = !phase;
1328:
1329: if (size > 0)
1330: {
1331: /* Change modes as the sequence tails off. */
1332: if (size < amount[next])
1333: {
1334: amount[next] = (size >= 4 ? 4 : (size >= 2 ? 2 : 1));
1335: mode[next] = mode_from_align[amount[next]];
1336: temp[next] = gen_reg_rtx (mode[next]);
1337: }
1338: size -= amount[next];
1339: srcp = gen_rtx (MEM,
1340: MEM_IN_STRUCT_P (src_mem) ? mode[next] : BLKmode,
1341: gen_rtx (PLUS, Pmode, src,
1342: gen_rtx (CONST_INT, SImode, offset_ld)));
1343: RTX_UNCHANGING_P (srcp) = RTX_UNCHANGING_P (src_mem);
1344: MEM_VOLATILE_P (srcp) = MEM_VOLATILE_P (src_mem);
1345: MEM_IN_STRUCT_P (srcp) = 1;
1346: emit_insn (gen_rtx (SET, VOIDmode, temp[next], srcp));
1347: offset_ld += amount[next];
1348: active[next] = TRUE;
1349: }
1350:
1351: if (active[phase])
1352: {
1353: active[phase] = FALSE;
1354: dstp = gen_rtx (MEM,
1355: MEM_IN_STRUCT_P (dest_mem) ? mode[phase] : BLKmode,
1356: gen_rtx (PLUS, Pmode, dest,
1357: gen_rtx (CONST_INT, SImode, offset_st)));
1358: RTX_UNCHANGING_P (dstp) = RTX_UNCHANGING_P (dest_mem);
1359: MEM_VOLATILE_P (dstp) = MEM_VOLATILE_P (dest_mem);
1360: MEM_IN_STRUCT_P (dstp) = 1;
1361: emit_insn (gen_rtx (SET, VOIDmode, dstp, temp[phase]));
1362: offset_st += amount[phase];
1363: }
1364: }
1365: while (active[next]);
1366: }
1367:
1368: void
1369: expand_block_move (dest_mem, src_mem, operands)
1370: rtx dest_mem;
1371: rtx src_mem;
1372: rtx *operands;
1373: {
1374: int align = INTVAL (operands[3]);
1375: int constp = (GET_CODE (operands[2]) == CONST_INT);
1376: int bytes = (constp ? INTVAL (operands[2]) : 0);
1377:
1378: #if 0
1379: if (constp && bytes <= 0)
1380: return;
1381:
1382: if (align > 4)
1383: align = 4;
1384:
1385: if (constp && bytes <= 3 * align)
1386: block_move_sequence (operands[0], dest_mem, operands[1], src_mem,
1387: bytes, align, 0);
1388:
1389: #if 0
1390: else if (constp && bytes <= best_from_align[target][align])
1391: block_move_no_loop (operands[0], dest_mem, operands[1], src_mem,
1392: bytes, align);
1393:
1394: else if (constp && align == 4 && TARGET_88100)
1395: block_move_loop (operands[0], dest_mem, operands[1], src_mem,
1396: bytes, align);
1397: #endif
1398: else
1399: #endif
1400: {
1401: emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memcpy"), 0,
1402: VOIDmode, 3,
1403: operands[0], Pmode,
1404: operands[1], Pmode,
1405: operands[2], SImode);
1406: }
1407: }
1408:
1409:
1410: override_options ()
1411: {
1412: sh_cpu = CPU_SH0;
1413: if (TARGET_SH1)
1414: sh_cpu = CPU_SH1;
1415: if (TARGET_SH2)
1416: sh_cpu = CPU_SH2;
1417: if (TARGET_SH3)
1418: sh_cpu = CPU_SH3;
1419: }
1420:
1421:
1422: /* Stuff taken from m88k.c */
1423:
1424: /* Output to FILE the start of the assembler file. */
1425:
1426: struct option
1427: {
1428: char *string;
1429: int *variable;
1430: int on_value;
1431: };
1432:
1433: static int
1434: output_option (file, sep, type, name, indent, pos, max)
1435: FILE *file;
1436: char *sep;
1437: char *type;
1438: char *name;
1439: char *indent;
1440: int pos;
1441: int max;
1442: {
1443: if (strlen (sep) + strlen (type) + strlen (name) + pos > max)
1444: {
1445: fprintf (file, indent);
1446: return fprintf (file, "%s%s", type, name);
1447: }
1448: return pos + fprintf (file, "%s%s%s", sep, type, name);
1449: }
1450:
1451: static struct
1452: {
1453: char *name;
1454: int value;
1455: }
1456:
1457: m_options[] = TARGET_SWITCHES;
1458:
1459: static void
1460: output_options (file, f_options, f_len, W_options, W_len,
1461: pos, max, sep, indent, term)
1462: FILE *file;
1463: struct option *f_options;
1464: struct option *W_options;
1465: int f_len, W_len;
1466: int pos;
1467: int max;
1468: char *sep;
1469: char *indent;
1470: char *term;
1471: {
1472: register int j;
1473:
1474:
1475: if (optimize)
1476: pos = output_option (file, sep, "-O", "", indent, pos, max);
1477: if (write_symbols != NO_DEBUG)
1478: pos = output_option (file, sep, "-g", "", indent, pos, max);
1479: if (flag_traditional)
1480: pos = output_option (file, sep, "-traditional", "", indent, pos, max);
1481: if (profile_flag)
1482: pos = output_option (file, sep, "-p", "", indent, pos, max);
1483: if (profile_block_flag)
1484: pos = output_option (file, sep, "-a", "", indent, pos, max);
1485:
1486: for (j = 0; j < f_len; j++)
1487: if (*f_options[j].variable == f_options[j].on_value)
1488: pos = output_option (file, sep, "-f", f_options[j].string,
1489: indent, pos, max);
1490:
1491: for (j = 0; j < W_len; j++)
1492: if (*W_options[j].variable == W_options[j].on_value)
1493: pos = output_option (file, sep, "-W", W_options[j].string,
1494: indent, pos, max);
1495:
1496: for (j = 0; j < sizeof m_options / sizeof m_options[0]; j++)
1497: if (m_options[j].name[0] != '\0'
1498: && m_options[j].value > 0
1499: && ((m_options[j].value & target_flags)
1500: == m_options[j].value))
1501: pos = output_option (file, sep, "-m", m_options[j].name,
1502: indent, pos, max);
1503:
1504:
1505: fprintf (file, term);
1506: }
1507:
1508: void
1509: output_file_start (file, f_options, f_len, W_options, W_len)
1510: FILE *file;
1511: struct option *f_options;
1512: struct option *W_options;
1513: int f_len, W_len;
1514: {
1515: register int pos;
1516:
1517: output_file_directive (file, main_input_filename);
1518:
1519: /* Switch to the data section so that the coffsem symbol and the
1520: gcc2_compiled. symbol aren't in the text section. */
1521: data_section ();
1522:
1523:
1524: pos = fprintf (file, "\n! Hitachi SH cc1 (%s) arguments:", version_string);
1525: output_options (file, f_options, f_len, W_options, W_len,
1526: pos, 75, " ", "\n! ", "\n\n");
1527: }
1528:
1529:
1530: /* Code to generate prologue and epilogue sequences */
1531:
1532: void
1533: sh_expand_prologue ()
1534: {
1535: int live_regs_mask;
1536: int d;
1537:
1538: live_regs_mask = calc_live_regs (&d);
1539:
1540: output_stack_adjust (-1, current_function_pretend_args_size);
1541:
1542: if (current_function_anonymous_args)
1543: {
1544: /* Push arg regs as if they'd been provided by caller in stack */
1545: int i;
1546: for (i = 0; i < NPARM_REGS; i++)
1547: {
1548: int rn = NPARM_REGS + FIRST_PARM_REG - i - 1;
1549: if (i > NPARM_REGS - current_function_args_info)
1550: break;
1551: push (rn);
1552:
1553: extra_push += 4;
1554: }
1555: }
1556:
1557: if (frame_pointer_needed)
1558: {
1559: push_regs (live_regs_mask);
1560: emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx));
1561: }
1562: else
1563: {
1564: push_regs (live_regs_mask);
1565: }
1566:
1567: output_stack_adjust (-1, get_frame_size ());
1568: }
1569:
1570: void
1571: sh_expand_epilogue ()
1572: {
1573: int live_regs_mask;
1574: int d;
1575: int i;
1576:
1577: live_regs_mask = calc_live_regs (&d);
1578:
1579: if (frame_pointer_needed)
1580: {
1581: emit_insn (gen_movsi (stack_pointer_rtx, frame_pointer_rtx));
1582: }
1583: else
1584: {
1585: output_stack_adjust (1, get_frame_size ());
1586: }
1587:
1588:
1589: /* Pop all the registers */
1590: for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
1591: {
1592: int j = (FIRST_PSEUDO_REGISTER - 1) - i;
1593: if (live_regs_mask & (1 << j))
1594: {
1595: pop (j);
1596: }
1597: }
1598: output_stack_adjust (1, extra_push +
1599: current_function_pretend_args_size);
1600:
1601: extra_push = 0;
1602:
1603: current_function_anonymous_args = 0;
1604: }
1605:
1606:
1607: /* Return the cost of a shift */
1608:
1609: int
1610: shiftcosts (RTX)
1611: rtx RTX;
1612: {
1613: /* If shift by a non constant, then this will be expensive. */
1614: if (GET_CODE (XEXP (RTX, 1)) != CONST_INT)
1615: return 20;
1616:
1617: /* otherwise, it will be very cheap if by one of the constants
1618: we can cope with. */
1619: if (CONST_OK_FOR_K (INTVAL (XEXP (RTX, 1))))
1620: return 1;
1621:
1622: /* otherwise it will be several insns. */
1623: return 4;
1624: }
1625:
1626: /* Return the cost of a multiply */
1627: int
1628: multcosts (RTX)
1629: rtx RTX;
1630: {
1631: /* If we we're aiming at small code, then just count the number of
1632: insns in a multiply call sequence, otherwise, count all the insnsn
1633: inside the call. */
1634: if (TARGET_SMALLCODE)
1635: return 3;
1636: return 30;
1637: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.