|
|
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 ();
1.1.1.2 ! root 42: int dump_constants ();
1.1 root 43:
44: int current_function_anonymous_args;
45: extern int current_function_pretend_args_size;
1.1.1.2 ! root 46: extern char *version_string;
! 47: extern int flag_traditional;
! 48:
! 49:
! 50: enum attr_cpu sh_cpu; /* target cpu */
1.1 root 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:
1.1.1.2 ! root 88:
! 89:
1.1 root 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:
1.1.1.2 ! root 103: void
! 104: push (rn)
1.1 root 105: {
1.1.1.2 ! root 106: emit_insn (gen_push (gen_rtx (REG, SImode, rn)));
1.1 root 107: }
108:
1.1.1.2 ! root 109: void
! 110: pop (rn)
1.1 root 111: {
1.1.1.2 ! root 112: emit_insn (gen_pop (gen_rtx (REG, SImode, rn)));
1.1 root 113: }
114:
115:
1.1.1.2 ! root 116: /* Adjust the stack and return the number of bytes taken to do it */
1.1 root 117:
1.1.1.2 ! root 118: static void
! 119: output_stack_adjust (direction, size)
! 120: int direction;
! 121: int size;
1.1 root 122: {
1.1.1.2 ! root 123: if (size)
1.1 root 124: {
1.1.1.2 ! root 125: rtx val = GEN_INT (size);
! 126: rtx insn;
1.1 root 127:
1.1.1.2 ! root 128: if (size > 120)
! 129: {
! 130: rtx nval = gen_rtx (REG, SImode, 13);
! 131: emit_insn (gen_movsi (nval, val));
! 132: val = nval;
! 133: }
1.1 root 134:
1.1.1.2 ! root 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);
1.1 root 139:
1.1.1.2 ! root 140: emit_insn (insn);
! 141: }
1.1 root 142: }
143:
144:
145:
1.1.1.2 ! root 146: /* Generate code to push the regs specified in the mask, and return
! 147: the number of bytes the insns take. */
1.1 root 148:
149: static void
1.1.1.2 ! root 150: push_regs (mask)
! 151: int mask;
1.1 root 152: {
153: int i;
1.1.1.2 ! root 154: int size = 0;
1.1 root 155:
1.1.1.2 ! root 156: for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
1.1 root 157: {
1.1.1.2 ! root 158: if (mask & (1 << i))
1.1 root 159: {
1.1.1.2 ! root 160: push (i);
1.1 root 161: }
162: }
163: }
164:
165:
1.1.1.2 ! root 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: */
1.1 root 171:
1.1.1.2 ! root 172: void
! 173: print_slot (insn)
! 174: rtx insn;
! 175: {
! 176: final_scan_insn (XVECEXP (insn, 0, 1), asm_out_file, optimize, 0, 1);
1.1 root 177:
1.1.1.2 ! root 178: INSN_DELETED_P (XVECEXP (insn, 0, 1)) = 1;
1.1 root 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: }
1.1.1.2 ! root 206:
1.1 root 207:
208:
209:
1.1.1.2 ! root 210: static int
! 211: need_slot (insn)
! 212: rtx insn;
1.1 root 213: {
1.1.1.2 ! root 214: return (insn && !INSN_ANNULLED_BRANCH_P (XVECEXP (insn, 0, 0)));
1.1 root 215: }
1.1.1.2 ! root 216:
1.1 root 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:
1.1.1.2 ! root 251: fprintf (stream, "@(r0,%s)",
! 252: reg_names[MAX (REGNO (base), REGNO (index))]);
! 253:
1.1 root 254: break;
255:
256: default:
1.1.1.2 ! root 257: debug_rtx (x);
! 258:
1.1 root 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:
1.1.1.2 ! root 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 */
1.1 root 291:
292: void
293: print_operand (stream, x, code)
294: FILE *stream;
295: rtx x;
296: int code;
297: {
298: switch (code)
299: {
1.1.1.2 ! root 300:
! 301:
! 302: case '.':
! 303: if (need_slot (final_sequence))
! 304: fprintf (stream, ".s");
! 305: break;
1.1 root 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;
1.1.1.2 ! root 323: case 'O':
! 324: fprintf (asm_out_file, "%d", INTVAL (x));
! 325: break;
1.1 root 326:
327: case 'I':
328: fprintf (asm_out_file, "LK%d", add_constant (x, SImode));
329: break;
330:
1.1.1.2 ! root 331: case 'M':
! 332: fprintf (asm_out_file, "#%d", -INTVAL (x));
! 333: break;
! 334:
1.1 root 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:
1.1.1.2 ! root 369:
! 370: /* Define the offset between two registers, one to be eliminated, and
1.1 root 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);
1.1.1.2 ! root 378: int total_saved_regs_space = (regs_saved) * 4;
1.1 root 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
1.1.1.2 ! root 400: operands must be in a register. Take this chance to remove
! 401: addressing modes which can't be coped with very well. */
1.1 root 402:
1.1.1.2 ! root 403: int
1.1 root 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))
1.1.1.2 ! root 411: || GET_CODE (operands[1]) == PLUS)
1.1 root 412: {
413: /* copy the source to a register */
414: operands[1] = copy_to_mode_reg (mode, operands[1]);
415: }
1.1.1.2 ! root 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;
1.1 root 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: {
1.1.1.2 ! root 446: if (GET_CODE (sh_compare_op0) != REG
! 447: || REGNO (sh_compare_op0) != T_REG)
1.1 root 448: {
449: /* First need a compare insn */
1.1.1.2 ! root 450: emit_insn (gen_rtx (SET, SImode,
1.1 root 451: gen_rtx (REG, SImode, T_REG),
452: gen_rtx (code, SImode, sh_compare_op0,
453: sh_compare_op1)));
454: }
1.1.1.2 ! root 455: return gen_rtx (REG, SImode, T_REG);
1.1 root 456: }
457:
1.1.1.2 ! root 458:
1.1 root 459: /* Functions to output assembly */
460:
1.1.1.2 ! root 461: /* Return a sequence of instructions to perform DI or DF move.
1.1 root 462:
1.1.1.2 ! root 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: */
1.1 root 467: char *
468: output_movedouble (operands, mode)
469: rtx operands[];
470: enum machine_mode mode;
471: {
1.1.1.2 ! root 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))
1.1 root 478: {
1.1.1.2 ! root 479: if (REGNO (src) == MACH_REG)
1.1 root 480: return "sts mach,%0\n\tsts macl,%R0";
481:
1.1.1.2 ! root 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)
1.1 root 494: {
1.1.1.2 ! root 495: if (INTVAL (src) < 0)
1.1 root 496: return "mov #-1,%0\n\tmov %1,%R0";
497: else
498: return "mov #0,%0\n\tmov %1,%R0";
499: }
500:
1.1.1.2 ! root 501: else if (GET_CODE (src) == MEM)
1.1 root 502: {
1.1.1.2 ! root 503: int ptrreg1 = -1;
! 504: int ptrreg2 = -1;
! 505: int dreg = REGNO (dst);
! 506: rtx inside = XEXP (src, 0);
1.1 root 507:
508: if (GET_CODE (inside) == REG)
1.1.1.2 ! root 509: {
! 510: ptrreg1 = REGNO (inside);
! 511: }
1.1 root 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)
1.1.1.2 ! root 517: ptrreg1 = REGNO (lhs);
! 518: if (GET_CODE (rhs) == REG)
! 519: ptrreg2 = REGNO (rhs);
1.1 root 520: }
521: else
522: abort ();
523:
1.1.1.2 ! root 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)
1.1 root 565: {
1.1.1.2 ! root 566: /* Copy into the second half first */
! 567: return "mov.l %R1,%R0\n\tmov.l %1,%0 ! cr";
1.1 root 568: }
569: }
570:
1.1.1.2 ! root 571: return "mov.l %1,%0\n\tmov.l %R1,%R0";
1.1 root 572: }
573:
574: /* Emit assembly to shift reg by k bits */
575:
576: char *
1.1.1.2 ! root 577: output_shift (string, reg, k, code)
1.1 root 578: char *string;
579: rtx reg;
580: rtx k;
1.1.1.2 ! root 581: int code;
! 582:
1.1 root 583: {
584: int s = INTVAL (k);
1.1.1.2 ! root 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:
1.1 root 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
1.1.1.2 ! root 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:
1.1 root 642:
643: char *
644: output_branch (logic, insn)
645: int logic;
1.1.1.2 ! root 646: rtx insn;
1.1 root 647: {
648: extern rtx recog_operand[];
649: int label = lf++;
1.1.1.2 ! root 650: int rn = -1;
! 651: int need_save;
! 652:
1.1 root 653: switch (get_attr_length (insn))
654: {
655: case 2:
656: /* Simple branch in range -200..+200 bytes */
1.1.1.2 ! root 657: return logic ? "bt%. %l0" : "bf%. %l0";
1.1 root 658:
659: case 6:
660: /* Branch in range -4000..+4000 bytes */
1.1.1.2 ! root 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: }
1.1 root 685:
686: return "";
1.1.1.2 ! root 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: }
1.1 root 722: }
723: return "bad";
724: }
725:
1.1.1.2 ! root 726:
1.1 root 727: /* Predicates used by the templates */
728:
1.1.1.2 ! root 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:
1.1 root 797: /* Nonzero if OP is a normal arithmetic register. */
798:
799: int
1.1.1.2 ! root 800: arith_reg_operand (op, mode)
1.1 root 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:
1.1.1.2 ! root 813:
1.1 root 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)
1.1.1.2 ! root 868: return INTVAL (p) >= 0;
1.1 root 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: }
1.1.1.2 ! root 996:
1.1 root 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;
1.1.1.2 ! root 1049: int pool_bytes;
! 1050:
! 1051: int last_uid;
! 1052: int last_pc;
1.1 root 1053:
1054: void
1055: adjust_insn_length (insn, insn_lengths)
1056: rtx insn;
1057: short *insn_lengths;
1058: {
1059: int uid = INSN_UID (insn);
1.1.1.2 ! root 1060: rtx body = PATTERN (insn);
1.1 root 1061:
1062: current_pc += insn_lengths[uid];
1063:
1.1.1.2 ! root 1064:
! 1065: if (GET_CODE (body) == SEQUENCE)
1.1 root 1066: {
1.1.1.2 ! root 1067: int i;
! 1068:
! 1069: for (i = 0; i < XVECLEN (body, 0); i++)
1.1 root 1070: {
1.1.1.2 ! root 1071: adjust_insn_length (XVECEXP (body, 0, i), insn_lengths);
1.1 root 1072: }
1.1.1.2 ! root 1073: }
! 1074: else
! 1075: {
! 1076: if (has_constant_table (insn))
1.1 root 1077: {
1.1.1.2 ! root 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. */
1.1 root 1092:
1093:
1.1.1.2 ! root 1094: /* Add the stuff from this insn to what will go in the
! 1095: growing table. */
1.1 root 1096:
1.1.1.2 ! root 1097: pool_bytes += get_attr_constantsize (insn);
1.1 root 1098:
1.1.1.2 ! root 1099: /* The target shinks to its smallest natural size */
! 1100: insn_lengths[target_insn_uid] = target_insn_smallest_size;
1.1 root 1101:
1.1.1.2 ! root 1102: /* The current insn grows to be its larger size plust the
! 1103: table size. */
1.1 root 1104:
1.1.1.2 ! root 1105: insn_lengths[uid] = get_attr_largestsize (insn) + pool_bytes;
1.1 root 1106:
1.1.1.2 ! root 1107: }
! 1108: /* Current insn becomes the target. */
! 1109: target_insn_uid = uid;
! 1110: target_insn_smallest_size = get_attr_smallestsize (insn);
1.1 root 1111:
1.1.1.2 ! root 1112: }
1.1 root 1113: }
1114: }
1115:
1116:
1117:
1.1.1.2 ! root 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
1.1 root 1123: dump_constants (label)
1124: {
1125: int i;
1126: int rlabel = label;
1127: int size = 0;
1.1.1.2 ! root 1128:
! 1129: if (pool_size)
1.1 root 1130: {
1131: fprintf (asm_out_file, "\n\t! constants - waited %d\n", pc - first_pc);
1132: fprintf (asm_out_file, "\t.align\t2\n");
1.1.1.2 ! root 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:
1.1 root 1164: }
1165: }
1.1.1.2 ! root 1166:
1.1 root 1167: pool_size = 0;
1168: current_pc = 0;
1.1.1.2 ! root 1169: pc = 0;
! 1170: pool_bytes = 0;
! 1171:
1.1 root 1172: target_insn_range = 0;
1173: return rlabel;
1.1.1.2 ! root 1174:
1.1 root 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:
1.1.1.2 ! root 1192: if (GET_MODE_SIZE (mode) > 4)
1.1 root 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:
1.1.1.2 ! root 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
1.1 root 1211: constant table attached to it. */
1.1.1.2 ! root 1212: if (get_attr_length (insn) != get_attr_smallestsize (insn))
1.1 root 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:
1.1.1.2 ! root 1228: rtx
1.1 root 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:
1.1.1.2 ! root 1252: pc += get_attr_length (insn);
1.1 root 1253: if (pool_size && pc - first_pc > MUST_DUMP_LEVEL)
1254: {
1.1.1.2 ! root 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. */
1.1 root 1260: int label = lf++;
1.1.1.2 ! root 1261: fprintf (asm_out_file, "\t!forced constant table\n");
1.1 root 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:
1.1.1.2 ! root 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.