]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/sh/sh.c
(build_module_descriptor): Don't set DECL_EXTERNAL on
[thirdparty/gcc.git] / gcc / config / sh / sh.c
CommitLineData
bc45ade3 1/* Output routines for GCC for Hitachi Super-H
0d7e008e 2 Copyright (C) 1993, 1994 Free Software Foundation, Inc.
bc45ade3 3
0d7e008e 4 This file is part of GNU CC.
bc45ade3 5
0d7e008e
SC
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.
bc45ade3 10
0d7e008e
SC
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.
bc45ade3 15
0d7e008e
SC
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. */
bc45ade3
SC
19
20
21/* Contributed by Steve Chamberlain (sac@cygnus.com) */
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"
0d7e008e 35
bc45ade3
SC
36#include "insn-attr.h"
37#include "flags.h"
38#include "obstack.h"
39#include "expr.h"
40
0d7e008e 41static rtx add_constant ();
bc45ade3 42
0d7e008e
SC
43int pragma_interrupt;
44int pragma_trapa;
bc45ade3
SC
45
46int current_function_anonymous_args;
47extern int current_function_pretend_args_size;
b9654711
SC
48extern char *version_string;
49extern int flag_traditional;
50
0d7e008e
SC
51static rtx shiftsyms[32];
52struct rtx_def *table_lab;
b9654711 53enum attr_cpu sh_cpu; /* target cpu */
bc45ade3
SC
54
55/* Global variables for machine-dependent things. */
56
57/* Saved operands from the last compare to use when we generate an scc
0d7e008e 58 or bcc insn. */
bc45ade3
SC
59
60rtx sh_compare_op0;
61rtx sh_compare_op1;
62
63/* Provides the class number of the smallest class containing
64 reg number */
65
66int regno_reg_class[FIRST_PSEUDO_REGISTER] =
67{
0d7e008e 68 R0_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
bc45ade3
SC
69 GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
70 GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
71 GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
0d7e008e
SC
72 GENERAL_REGS, PR_REGS, T_REGS, NO_REGS,
73 MAC_REGS, MAC_REGS,
bc45ade3
SC
74};
75
76/* Provide reg_class from a letter such as appears in the machine
77 description. */
78
79enum reg_class reg_class_from_letter[] =
80{
81 /* a */ NO_REGS, /* b */ NO_REGS, /* c */ NO_REGS, /* d */ NO_REGS,
82 /* e */ NO_REGS, /* f */ NO_REGS, /* g */ NO_REGS, /* h */ NO_REGS,
83 /* i */ NO_REGS, /* j */ NO_REGS, /* k */ NO_REGS, /* l */ PR_REGS,
84 /* m */ NO_REGS, /* n */ NO_REGS, /* o */ NO_REGS, /* p */ NO_REGS,
85 /* q */ NO_REGS, /* r */ NO_REGS, /* s */ NO_REGS, /* t */ T_REGS,
86 /* u */ NO_REGS, /* v */ NO_REGS, /* w */ NO_REGS, /* x */ MAC_REGS,
87 /* y */ NO_REGS, /* z */ R0_REGS
88};
89
0d7e008e
SC
90/* Value is 1 if register/mode pair is acceptable on SH. Even
91 registers can hold DIs and DF values. The rest can only hold
92 SI's efficiently */
93
94
95#define REG_ODD \
96 ( (1 << (int) QImode) | (1 << (int) HImode) | (1 << (int) SImode) \
97 | (1 << (int) QFmode) | (1 << (int) HFmode) | (1 << (int) SFmode) \
d3ae8277 98 | (1 << (int) CQImode) | (1 << (int) CHImode)| (1<< (int)DFmode) | (1<<(int)DImode))
bc45ade3 99
0d7e008e 100#define REG_EVEN \
d3ae8277 101 (REG_ODD | (1 << (int) CSImode) | (1 << (int) SCmode))
b9654711 102
0d7e008e 103#define SI_ONLY (1<<(int)SImode)
d3ae8277 104
0d7e008e
SC
105int hard_regno_mode_ok[] =
106{
107 REG_EVEN, REG_ODD, REG_EVEN, REG_ODD,
108 REG_EVEN, REG_ODD, REG_EVEN, REG_ODD,
109 REG_EVEN, REG_ODD, REG_EVEN, REG_ODD,
110 REG_EVEN, REG_ODD, REG_EVEN, REG_ODD,
111 REG, 0, SI_ONLY, SI_ONLY,
112 SI_ONLY, SI_ONLY
113};
b9654711 114
bc45ade3
SC
115/* Local label counter, used for constants in the pool and inside
116 pattern branches. */
a9f71ad8 117static int lf = 100;
bc45ade3 118
0d7e008e
SC
119
120/* Number of bytes pushed for anonymous args, used to pass information
121 between expand_prologue and expand_epilogue. */
122static int extra_push;
123
bc45ade3 124\f
bc45ade3 125
b9654711
SC
126void
127push (rn)
0d7e008e 128 int rn;
bc45ade3 129{
b9654711 130 emit_insn (gen_push (gen_rtx (REG, SImode, rn)));
bc45ade3
SC
131}
132
b9654711
SC
133void
134pop (rn)
bc45ade3 135{
b9654711 136 emit_insn (gen_pop (gen_rtx (REG, SImode, rn)));
bc45ade3
SC
137}
138
139
b9654711 140/* Adjust the stack and return the number of bytes taken to do it */
bc45ade3 141
b9654711 142static void
0d7e008e 143output_stack_adjust (size)
b9654711 144 int size;
bc45ade3 145{
b9654711 146 if (size)
bc45ade3 147 {
b9654711
SC
148 rtx val = GEN_INT (size);
149 rtx insn;
bc45ade3 150
0d7e008e 151 if (!CONST_OK_FOR_I (size))
b9654711 152 {
0d7e008e 153 rtx nval = gen_rtx (REG, SImode, 3);
b9654711
SC
154 emit_insn (gen_movsi (nval, val));
155 val = nval;
156 }
bc45ade3 157
0d7e008e 158 insn = gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, val);
b9654711
SC
159 emit_insn (insn);
160 }
bc45ade3
SC
161}
162
b9654711
SC
163/* Generate code to push the regs specified in the mask, and return
164 the number of bytes the insns take. */
bc45ade3
SC
165
166static void
b9654711
SC
167push_regs (mask)
168 int mask;
bc45ade3
SC
169{
170 int i;
171
b9654711 172 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
bc45ade3 173 {
b9654711 174 if (mask & (1 << i))
bc45ade3 175 {
b9654711 176 push (i);
bc45ade3
SC
177 }
178 }
179}
180
bc45ade3 181
0d7e008e
SC
182/* Print an instruction which would have gone into a delay slot after
183 an instructiuon, but couldn't because the instruction expanded into a
184 sequence where putting the slot insn at the end wouldn't work. */
bc45ade3 185
0d7e008e 186static void
b9654711
SC
187print_slot (insn)
188 rtx insn;
189{
190 final_scan_insn (XVECEXP (insn, 0, 1), asm_out_file, optimize, 0, 1);
bc45ade3 191
b9654711 192 INSN_DELETED_P (XVECEXP (insn, 0, 1)) = 1;
bc45ade3
SC
193}
194
bc45ade3
SC
195
196/* Work out the registers which need to be saved, both as a mask and a
0d7e008e 197 count.
bc45ade3 198
0d7e008e
SC
199 If doing a pragma interrupt function, then push all regs used by the function,
200 and if we call another function (we can tell by looking at PR), make sure that all the
201 regs it clobbers are safe too.
202 */
203static int
204calc_live_regs (count_ptr)
205 int *count_ptr;
bc45ade3
SC
206{
207 int reg;
208 int live_regs_mask = 0;
0d7e008e 209 int count = 0;
bc45ade3
SC
210 for (reg = 0; reg < FIRST_PSEUDO_REGISTER; reg++)
211 {
0d7e008e
SC
212 if (reg == ARG_POINTER_REGNUM)
213 continue;
214 if (reg == T_REG)
215 continue;
216 if (reg == GBR_REG)
217 continue;
218
219 if (pragma_interrupt && !pragma_trapa)
220 {
221 /* Need to save all the regs ever live */
222 if ((regs_ever_live[reg]
223 || (call_used_regs[reg] && regs_ever_live[PR_REG]))
224 && reg != 15)
225 {
226 live_regs_mask |= 1 << reg;
227 count++;
228 }
229 }
230 else if (TARGET_SMALLCALL)
231 {
232 /* Don't need to push anthing, but count the regs which have
233 been pushed by the wrapper */
234 if (call_used_regs[reg])
235 count++;
236 }
237 else
bc45ade3 238 {
0d7e008e
SC
239 /* Only push those regs which are used and need to be saved */
240 if (regs_ever_live[reg] && !call_used_regs[reg])
241 {
242 count++;
243 live_regs_mask |= (1 << reg);
244 }
bc45ade3
SC
245 }
246 }
0d7e008e
SC
247
248
249 *count_ptr = count;
bc45ade3
SC
250 return live_regs_mask;
251}
b9654711 252\f
bc45ade3 253
b9654711
SC
254static int
255need_slot (insn)
256 rtx insn;
bc45ade3 257{
b9654711 258 return (insn && !INSN_ANNULLED_BRANCH_P (XVECEXP (insn, 0, 0)));
bc45ade3 259}
b9654711 260
bc45ade3
SC
261/* Print the operand address in x to the stream */
262
263void
264print_operand_address (stream, x)
265 FILE *stream;
266 rtx x;
267{
268 switch (GET_CODE (x))
269 {
270 case REG:
271 fprintf (stream, "@%s", reg_names[REGNO (x)]);
272 break;
bc45ade3
SC
273 case PLUS:
274 {
275 rtx base = XEXP (x, 0);
276 rtx index = XEXP (x, 1);
277
278 if (GET_CODE (base) != REG)
279 {
280 /* Ensure that BASE is a register (one of them must be). */
281 rtx temp = base;
282 base = index;
283 index = temp;
284 }
285
286 switch (GET_CODE (index))
287 {
288 case CONST_INT:
289 fprintf (stream, "@(%d,%s)",
290 INTVAL (index),
291 reg_names[REGNO (base)]);
292 break;
293
294 case REG:
b9654711
SC
295 fprintf (stream, "@(r0,%s)",
296 reg_names[MAX (REGNO (base), REGNO (index))]);
297
bc45ade3
SC
298 break;
299
300 default:
b9654711
SC
301 debug_rtx (x);
302
bc45ade3
SC
303 abort ();
304 }
305 }
306
307 break;
308 case PRE_DEC:
309 fprintf (stream, "@-%s", reg_names[REGNO (XEXP (x, 0))]);
310 break;
311
312 case POST_INC:
313 fprintf (stream, "@%s+", reg_names[REGNO (XEXP (x, 0))]);
314 break;
315
316 default:
317 output_addr_const (stream, x);
318 break;
319 }
320}
321
322/* Print operand x (an rtx) in assembler syntax to file stream
323 according to modifier code.
324
b9654711
SC
325 '.' print a .s if insn needs delay slot
326 '*' print a local label
327 '^' increment the local label number
328 '!' dump the constant table
329 '#' output a nop if there is nothing to put in the delay slot
d3ae8277 330 '@' print rte or rts depending upon pragma interruptness
b9654711
SC
331 'R' print the next register or memory location along, ie the lsw in
332 a double word value
333 'O' print a constant without the #
334 'M' print a constant as its negative
0d7e008e 335 'N' print insides of a @++ or @-- o */
bc45ade3
SC
336
337void
338print_operand (stream, x, code)
339 FILE *stream;
340 rtx x;
341 int code;
342{
343 switch (code)
344 {
b9654711
SC
345 case '.':
346 if (need_slot (final_sequence))
347 fprintf (stream, ".s");
348 break;
bc45ade3
SC
349 case '*':
350 fprintf (stream, "LF%d", lf);
351 break;
bc45ade3
SC
352 case '^':
353 lf++;
354 break;
d3ae8277
SC
355 case '@':
356 if (pragma_interrupt)
357 fprintf (stream,"rte");
358 else
359 fprintf (stream,"rts");
360 break;
bc45ade3
SC
361 case '#':
362 /* Output a nop if there's nothing in the delay slot */
363 if (dbr_sequence_length () == 0)
364 {
d3ae8277 365 fprintf (stream, "\n\tnop");
bc45ade3
SC
366 }
367 break;
b9654711 368 case 'O':
0d7e008e 369 output_addr_const (stream, x);
bc45ade3 370 break;
b9654711
SC
371 case 'M':
372 fprintf (asm_out_file, "#%d", -INTVAL (x));
373 break;
0d7e008e
SC
374 case 'N':
375 fputs (reg_names[REGNO (XEXP (XEXP (x, 0), 0))], (stream));
376 break;
bc45ade3 377 case 'R':
0d7e008e 378 /* Next location along in memory or register */
bc45ade3
SC
379 switch (GET_CODE (x))
380 {
381 case REG:
382 fputs (reg_names[REGNO (x) + 1], (stream));
383 break;
384 case MEM:
0d7e008e 385 print_operand_address (stream, XEXP (adj_offsettable_operand (x, 4), 0));
bc45ade3
SC
386 break;
387 }
388 break;
bc45ade3
SC
389 default:
390 switch (GET_CODE (x))
391 {
392 case REG:
393 fputs (reg_names[REGNO (x)], (stream));
394 break;
395 case MEM:
396 output_address (XEXP (x, 0));
397 break;
398 default:
399 fputc ('#', stream);
400 output_addr_const (stream, x);
401 break;
bc45ade3
SC
402 }
403 break;
404 }
405}
bc45ade3
SC
406\f
407
0d7e008e
SC
408sextb (x)
409{
410 x &= 0xff;
411 if (x > 127)
412 {
413 x = -256 + x;
414 }
415 return x;
416}
417
b9654711 418
bc45ade3 419
0d7e008e
SC
420/* Take a move with integer constant source in OPERANDS, see if it can be generated by
421 devious shifting. If so, generate the instruction sequence and return 1, otherwise
422 return 0.
423
424 OPERANDS[0] Destination register
425 OPERANDS[1] Source constant
426
427 00000000 00000000 00000000 0NNNNNNNN simple load
428 00000000 00000000 00000000 NNNNNNNN0 load and shift by 1
429 00000000 00000000 0000000N NNNNNNN00 load and shift by 2
430 00000000 00000000 0NNNNNNN 000000000 load and shift by 8
431 00000000 0NNNNNNN 00000000 000000000 load and shift by 16
432 N0000000 00000000 00000000 00NNNNNNN load and rotate right
433
434 11111111 11111111 11111111 1NNNNNNNN simple load
435 11111111 11111111 11111111 NNNNNNNN0 load and shift by 1
436 11111111 11111111 1111111N NNNNNNN00 load and shift by 2
437 11111111 11111111 1NNNNNNN 000000000 load and shift by 8
438 11111111 1NNNNNNN 00000000 000000000 load and shift by 16
439 N1111111 11111111 11111111 11NNNNNNN load and rotate right
440
441 00000000 00000000 00000000 1NNNNNNNN load and zero extend byte
442 00000000 00000000 11111111 1NNNNNNNN load and zero extend word
443
444
445*/
446
447static int
448synth_constant (operands, mode)
449 rtx operands[];
450 enum machine_mode mode;
bc45ade3 451{
0d7e008e
SC
452 rtx dst;
453 int i = INTVAL (operands[1]) & 0xffffffff;
454
d3ae8277 455 if (CONST_OK_FOR_I (i))
0d7e008e 456 return 0;
bc45ade3 457
d3ae8277
SC
458 if (TARGET_CLEN0 && mode != QImode)
459 return 0;
460
461 if (mode != SImode)
462 {
463 if (reload_in_progress)
464 return 0;
465 dst = gen_reg_rtx (SImode);
466 }
467 else
468 {
469 dst = operands[0];
470 }
bc45ade3 471
0d7e008e
SC
472 /* 00000000 00000000 11111111 1NNNNNNNN load and zero extend word */
473 if ((i & 0xffffff80) == 0x0000ff80)
474 {
475 emit_move_insn (dst, GEN_INT (sextb (i)));
476 emit_insn (gen_and_ffff (dst, dst));
477 }
478 /* 00000000 00000000 00000000 1NNNNNNNN load and zero extend byte */
479 else if ((i & 0xffffff80) == 0x00000080)
bc45ade3 480 {
0d7e008e
SC
481 emit_move_insn (dst, GEN_INT (sextb (i)));
482 emit_insn (gen_and_ff (dst, dst));
bc45ade3 483 }
0d7e008e
SC
484 /* 00000000 00000000 00000000 NNNNNNNN0 load and shift by 1
485 11111111 11111111 11111111 NNNNNNNN0 load and shift by 1 */
486 else if ((i & 0xffffff01) == 0
487 || (i & 0xffffff01) == 0xffffff00)
488 {
489 emit_move_insn (dst, GEN_INT (sextb (i >> 1)));
490 emit_insn (gen_ashlsi3_n (dst, dst, GEN_INT (1)));
491 }
492 /* 00000000 00000000 0000000N NNNNNNN00 load and shift by 2
493 11111111 11111111 1111111N NNNNNNN00 load and shift by 2*/
494 else if ((i & 0xfffffe03) == 0
495 || (i & 0xfffffe03) == 0xfffffe00)
496 {
497 emit_move_insn (dst, GEN_INT (sextb (i >> 2)));
498 emit_insn (gen_ashlsi3_n (dst, dst, GEN_INT (2)));
499 }
500 /* 00000000 00000000 0NNNNNNN 000000000 load and shift by 8
501 11111111 11111111 1NNNNNNN 000000000 load and shift by 8 */
bc45ade3 502
0d7e008e
SC
503 else if ((i & 0xffff80ff) == 0
504 || (i & 0xffff80ff) == 0xffff8000)
bc45ade3 505 {
0d7e008e
SC
506 emit_move_insn (dst, GEN_INT (sextb (i >> 8)));
507 emit_insn (gen_ashlsi3_n (dst, dst, GEN_INT (8)));
508 }
509 /* 00000000 0NNNNNNN 00000000 000000000 load and shift by 16
510 11111111 1NNNNNNN 00000000 000000000 load and shift by 16 */
511 else if ((i & 0xff80ffff) == 0
512 || (i & 0xff80ffff) == 0xff80ffff)
513 {
514 emit_move_insn (dst, GEN_INT (sextb (i >> 16)));
515 emit_insn (gen_ashlsi3_n (dst, dst, GEN_INT (16)));
bc45ade3 516 }
0d7e008e
SC
517 /* 00000000 00000000 0NNNNNNN 0NNNNNNNN load shift 8 and add */
518 else if ((i & 0xffff8080) == 0 && TARGET_CLEN3)
519 {
520 emit_move_insn (dst, GEN_INT (sextb (i >> 8)));
521 emit_insn (gen_ashlsi3_n (dst, dst, GEN_INT (8)));
522 emit_insn (gen_addsi3 (dst, dst, GEN_INT (i & 0x7f)));
523 }
524 else
525 return 0;
bc45ade3 526
0d7e008e 527 if (mode != SImode)
bc45ade3 528 {
0d7e008e
SC
529 emit_insn (gen_rtx (SET, VOIDmode, operands[0],
530 gen_rtx (SUBREG, mode, dst, 0)));
531
bc45ade3 532 }
0d7e008e 533 return 1;
bc45ade3
SC
534}
535
bc45ade3 536
0d7e008e
SC
537/* Emit code to perform a block move. Choose the best method.
538
539 OPERANDS[0] is the destination.
540 OPERANDS[1] is the source.
541 OPERANDS[2] is the size.
542 OPERANDS[3] is the alignment safe to use. */
543
544
545int
546expand_block_move (operands)
547 rtx *operands;
548{
549 int align = INTVAL (operands[3]);
550 int constp = (GET_CODE (operands[2]) == CONST_INT);
551 int bytes = (constp ? INTVAL (operands[2]) : 0);
552 enum machine_mode mode;
d3ae8277 553
0d7e008e
SC
554 /* IF odd then fail */
555 if (!constp || bytes <= 0)
556 return 0;
557
d3ae8277
SC
558 /* Don't expand if we'd make the code bigger and we don't want big code */
559
560 if (bytes > 8 && TARGET_SMALLCODE)
561 return 0;
562
0d7e008e
SC
563 switch (align)
564 {
565 case 1:
566 mode = QImode;
567 break;
568 case 2:
569 mode = HImode;
570 break;
571 default:
572 mode = SImode;
573 align = 4;
574 }
d3ae8277 575
0d7e008e
SC
576 if (mode == SImode && constp && bytes < 64 && (bytes % 4 == 0))
577 {
578 char entry[30];
579 tree entry_name;
580 rtx func_addr_rtx;
581 rtx r4 = gen_rtx (REG, SImode, 4);
582 rtx r5 = gen_rtx (REG, SImode, 5);
583 sprintf (entry, "__movstr%s%d", GET_MODE_NAME (mode), bytes);
584 entry_name = get_identifier (entry);
585
586 func_addr_rtx = copy_to_mode_reg (Pmode,
587 gen_rtx (SYMBOL_REF, Pmode, IDENTIFIER_POINTER (entry_name)));
588 emit_insn (gen_move_insn (r4, XEXP (operands[0], 0)));
589 emit_insn (gen_move_insn (r5, XEXP (operands[1], 0)));
590 emit_insn (gen_block_move_real (func_addr_rtx));
591 return 1;
592 }
593 if (mode == SImode && constp && (bytes % 4 == 0))
594 {
595 char entry[30];
596 tree entry_name;
597 rtx func_addr_rtx;
598 int groups;
599 rtx r4 = gen_rtx (REG, SImode, 4);
600 rtx r5 = gen_rtx (REG, SImode, 5);
601 rtx r6 = gen_rtx (REG, SImode, 6);
602 entry_name = get_identifier ("__movstr");
603
604 func_addr_rtx = copy_to_mode_reg (Pmode,
605 gen_rtx (SYMBOL_REF, Pmode,
606 IDENTIFIER_POINTER (entry_name)));
607 emit_insn (gen_move_insn (r4, XEXP (operands[0], 0)));
608 emit_insn (gen_move_insn (r5, XEXP (operands[1], 0)));
609
610 /* r6 controls the size of the move, 16 is decremented from it
611 for each 64 bytes moved, then the -ve bit is used as an index into a
612 list of move instructions like this:
613
614 {
615 do {
616 *dst++ = *src++;
617 *dst++ = *src++;
618 *dst++ = *src++;
619 ..etc.. 16 in all
620 *dst++ = *src++;
621 *dst++ = *src++;
622 size -= 16;
623 } while (size > 0);
624
625 switch (size)
626 {
627 case -15:
628 *dst++ = *src++;
629 case -14:
630 *dst++ = *src++;
631 .. etc.. ;
632 case -2:
633 *dst++ = *src++;
634 case -1:
635 *dst++ = *src++;
636 case 0:
637 ;
638 }
639 }
640
641 eg, a 72 byte move would be set up with size(r6) = 14, for one
642 iteration through the big while loop, and a switch of -2 for the last part */
643
644 {
645 int final_switch = 16 - ((bytes / 4) % 16);
646 int while_loop = ((bytes / 4) / 16 - 1) * 16;
647 emit_insn (gen_move_insn (r6, GEN_INT (while_loop + final_switch)));
648 emit_insn (gen_block_lump_real (func_addr_rtx));
649 return 1;
650 }
651 }
0d7e008e 652
d3ae8277 653 return 0;
0d7e008e
SC
654}
655
bc45ade3 656/* Prepare operands for a move define_expand; specifically, one of the
b9654711
SC
657 operands must be in a register. Take this chance to remove
658 addressing modes which can't be coped with very well. */
bc45ade3 659
b9654711 660int
bc45ade3
SC
661prepare_move_operands (operands, mode)
662 rtx operands[];
663 enum machine_mode mode;
664{
0d7e008e
SC
665 if (!(reload_in_progress || reload_completed)
666 && ((!register_operand (operands[0], mode)
667 && !register_operand (operands[1], mode))
668 || GET_CODE (operands[1]) == PLUS))
bc45ade3
SC
669 {
670 /* copy the source to a register */
671 operands[1] = copy_to_mode_reg (mode, operands[1]);
672 }
0d7e008e
SC
673 if ((mode == DImode || mode == SImode || mode == HImode || mode == QImode)
674 && GET_CODE (operands[1]) == CONST_INT)
b9654711 675 {
0d7e008e
SC
676 return synth_constant (operands, mode);
677 }
678 if (mode == DFmode || mode == DImode)
679 {
680 rtx src = operands[1];
681 rtx dst = operands[0];
682 rtx insns;
b9654711 683
0d7e008e 684 if (src == dst)
b9654711 685 {
0d7e008e
SC
686 emit_insn (gen_rtx (SET, VOIDmode, dst, src));
687 return 1;
688 }
b9654711 689
0d7e008e
SC
690 if (GET_CODE (src) == REG &&
691 REGNO (src) >= FIRST_PSEUDO_REGISTER)
692 return 0;
693
694 if (GET_CODE (dst) == REG &&
695 REGNO (dst) >= FIRST_PSEUDO_REGISTER)
696 return 0;
697
0d7e008e
SC
698 if (push_operand (dst, mode))
699 return 0;
700
701 if (GET_CODE (src) == CONST_DOUBLE)
702 src = force_const_mem (DFmode, src);
703
704 if (reload_in_progress)
705 {
706 if (!(offsettable_memref_p (src) || register_operand (src, mode)))
707 return 0;
708 if (!(offsettable_memref_p (dst) || register_operand (dst,
709 mode)))
710 return 0;
711 }
712 start_sequence ();
713 if (GET_CODE (operands[0]) != REG
714 || !refers_to_regno_p (REGNO (operands[0]), REGNO (operands[0]) + 1, operands[1], 0))
715 {
716 emit_move_insn (operand_subword (dst, 0, 1, mode),
717 operand_subword_force (src, 0, mode));
718 emit_move_insn (operand_subword (dst, 1, 1, mode),
719 operand_subword_force (src, 1, mode));
720 }
721 else
722 {
723 emit_move_insn (operand_subword (dst, 1, 1, mode),
724 operand_subword_force (src, 1, mode));
725 emit_move_insn (operand_subword (dst, 0, 1, mode),
726 operand_subword_force (src, 0, mode));
b9654711 727 }
0d7e008e
SC
728
729 insns = get_insns ();
730 end_sequence ();
731
732 emit_no_conflict_block (insns, dst, src, 0, src);
733 return 1;
b9654711 734 }
0d7e008e 735
b9654711 736 return 0;
bc45ade3
SC
737}
738
bc45ade3
SC
739/* Prepare the operands for an scc instruction; make sure that the
740 compare has been done. */
741rtx
742prepare_scc_operands (code)
743{
b9654711
SC
744 if (GET_CODE (sh_compare_op0) != REG
745 || REGNO (sh_compare_op0) != T_REG)
bc45ade3 746 {
0d7e008e 747 int newcode = code;
bc45ade3 748 /* First need a compare insn */
0d7e008e
SC
749 switch (code)
750 {
751 case NE:
752 newcode = EQ;
753 break;
754 case LT:
755 newcode = GT;
756 break;
757 case LE:
758 newcode = GE;
759 break;
760 case LTU:
761 newcode = GTU;
762 break;
763 case LEU:
764 newcode = GEU;
765 break;
766 }
767 if (newcode != code)
768 {
769 rtx tmp = sh_compare_op0;
770 sh_compare_op0 = sh_compare_op1;
771 sh_compare_op1 = tmp;
772 code = newcode;
773 }
774
775 sh_compare_op0 = force_reg (SImode, sh_compare_op0);
776 emit_insn (gen_rtx (SET, VOIDmode,
bc45ade3 777 gen_rtx (REG, SImode, T_REG),
0d7e008e 778 gen_rtx (code, SImode, sh_compare_op0, sh_compare_op1)));
bc45ade3 779 }
b9654711 780 return gen_rtx (REG, SImode, T_REG);
bc45ade3
SC
781}
782\f
b9654711 783
0d7e008e 784/* Functions to output assembly code. */
bc45ade3 785
b9654711 786/* Return a sequence of instructions to perform DI or DF move.
bc45ade3 787
b9654711
SC
788 Since the SH cannot move a DI or DF in one instruction, we have
789 to take care when we see overlapping source and dest registers.
790
791 */
0d7e008e 792
bc45ade3 793char *
0d7e008e
SC
794output_movedouble (insn, operands, mode)
795 rtx insn;
bc45ade3
SC
796 rtx operands[];
797 enum machine_mode mode;
798{
b9654711
SC
799 rtx dst = operands[0];
800 rtx src = operands[1];
b9654711 801
d3ae8277
SC
802/* fprintf (asm_out_file, "! move double \n");
803 fprintf (asm_out_file, "! pc %04x\n", insn_addresses[INSN_UID (insn)]);*/
0d7e008e
SC
804 if (GET_CODE (dst) == MEM
805 && GET_CODE (XEXP (dst, 0)) == POST_INC)
806 {
807 operands[0] = XEXP (XEXP (dst, 0), 0);
808 return "mov.l %R1,@(4,%0)\n\tmov.l %1,@%0\n\tadd #8,%0";
809 }
b9654711
SC
810 if (register_operand (dst, mode)
811 && register_operand (src, mode))
bc45ade3 812 {
b9654711 813 if (REGNO (src) == MACH_REG)
bc45ade3 814 return "sts mach,%0\n\tsts macl,%R0";
bc45ade3 815
b9654711 816 /*
0d7e008e
SC
817 when mov.d r1,r2 do r2->r3 then r1->r2
818 when mov.d r1,r0 do r1->r0 then r2->r1
819 */
b9654711
SC
820
821 if (REGNO (src) + 1 == REGNO (dst))
0d7e008e 822 return "mov %R1,%R0\n\tmov %1,%0 ! cra";
b9654711 823 else
0d7e008e 824 return "mov %1,%0\n\tmov %R1,%R0 ! crb";
b9654711
SC
825 }
826 else if (GET_CODE (src) == CONST_INT)
bc45ade3 827 {
0d7e008e
SC
828 HOST_WIDE_INT val = INTVAL (src);
829 int rn = REGNO (operands[0]);
830 if (val < 0)
831 {
832 fprintf (asm_out_file, "\tmov #-1,r%d\n", rn);
833 }
bc45ade3 834 else
0d7e008e
SC
835 {
836 fprintf (asm_out_file, "\tmov #0,r%d\n", rn);
837 }
bc45ade3 838
0d7e008e
SC
839 fprintf (asm_out_file, "\tmov #%d,r%d\n", val, rn + 1);
840 return "";
841 }
b9654711 842 else if (GET_CODE (src) == MEM)
bc45ade3 843 {
b9654711
SC
844 int ptrreg1 = -1;
845 int ptrreg2 = -1;
846 int dreg = REGNO (dst);
847 rtx inside = XEXP (src, 0);
bc45ade3
SC
848
849 if (GET_CODE (inside) == REG)
b9654711
SC
850 {
851 ptrreg1 = REGNO (inside);
852 }
bc45ade3
SC
853 else if (GET_CODE (inside) == PLUS)
854 {
855 rtx lhs = XEXP (inside, 0);
856 rtx rhs = XEXP (inside, 1);
857 if (GET_CODE (lhs) == REG)
b9654711
SC
858 ptrreg1 = REGNO (lhs);
859 if (GET_CODE (rhs) == REG)
860 ptrreg2 = REGNO (rhs);
bc45ade3 861 }
0d7e008e
SC
862 else if (GET_CODE (inside) == LABEL_REF)
863 {
864 return "mov.l %1,%0\n\tmov.l %1+4,%R0";
865 }
bc45ade3
SC
866 else
867 abort ();
868
b9654711
SC
869 if ((ptrreg1 >= 0 && ptrreg2 >= 0)
870 && (dreg == ptrreg1
871 || dreg == ptrreg2
872 || dreg + 1 == ptrreg1
873 || dreg + 1 == ptrreg2))
874 {
875 /* This move clobbers both index registers,
876 calculate the sum in one register. */
877 fprintf (asm_out_file, " add %s,%s ! special fix\n",
878 reg_names[ptrreg2], reg_names[ptrreg1]);
879
880 if (dreg == ptrreg1)
881 {
882 /* Copy into dreg+1 first. */
883 fprintf (asm_out_file, " mov.l @(4,%s),%s\n",
884 reg_names[ptrreg1],
885 reg_names[dreg + 1]);
886
887 fprintf (asm_out_file, " mov.l @(%s),%s\n",
888 reg_names[ptrreg1],
889 reg_names[dreg]);
890 }
891 else
892 {
893 /* Copy into dreg first. */
894 fprintf (asm_out_file, " mov.l @(%s),%s\n",
895 reg_names[ptrreg1],
896 reg_names[dreg]);
897
898 fprintf (asm_out_file, " mov.l @(4,%s),%s\n",
899 reg_names[ptrreg1],
900 reg_names[dreg + 1]);
901
902 }
903 warning ("generated complex amode");
904 return "";
905 }
906
907 /* Work out the safe way to copy */
908 if (dreg == ptrreg1)
bc45ade3 909 {
b9654711
SC
910 /* Copy into the second half first */
911 return "mov.l %R1,%R0\n\tmov.l %1,%0 ! cr";
bc45ade3 912 }
bc45ade3
SC
913 }
914
b9654711 915 return "mov.l %1,%0\n\tmov.l %R1,%R0";
bc45ade3
SC
916}
917
918/* Emit assembly to shift reg by k bits */
919
920char *
b9654711 921output_shift (string, reg, k, code)
bc45ade3
SC
922 char *string;
923 rtx reg;
924 rtx k;
b9654711
SC
925 int code;
926
bc45ade3
SC
927{
928 int s = INTVAL (k);
0d7e008e
SC
929 if (s < 0)
930 {
931 s = -s;
932 switch (code)
933 {
934 case LSHIFTRT:
935 case ASHIFTRT:
3841a7f6 936 code = ASHIFT;
0d7e008e
SC
937 break;
938 case ASHIFT:
939 code = ASHIFTRT;
940 break;
0d7e008e
SC
941 default:
942 abort ();
943 }
944 }
b9654711
SC
945 if (code == ASHIFT && s == 31)
946 {
947 /* Shift left by 31 moving into the t bit, clearing and rotating the other way */
948
949 fprintf (asm_out_file, "\trotr r%d\n", REGNO (reg));
950 fprintf (asm_out_file, "\tmov #0,r%d\n", REGNO (reg));
951 fprintf (asm_out_file, "\trotcr r%d\n", REGNO (reg));
952 s = 0;
953 }
954
955 if (code == LSHIFTRT && s == 31)
956 {
957 fprintf (asm_out_file, "\trotl r%d\n", REGNO (reg));
958 fprintf (asm_out_file, "\tmov #0,r%d\n", REGNO (reg));
959 fprintf (asm_out_file, "\trotcl r%d\n", REGNO (reg));
960 s = 0;
961 }
962
bc45ade3
SC
963 while (s)
964 {
965 char *out;
966 int d;
967
968 if (s >= 16)
969 {
970 d = 16;
971 out = "16";
972 }
973 else if (s >= 8)
974 {
975 d = 8;
976 out = "8";
977 }
978 else if (s >= 2)
979 {
980 d = 2;
981 out = "2";
982 }
983 else
984 {
985 d = 1;
986 out = "";
987 }
988 fprintf (asm_out_file, "\t%s%s\tr%d\n", string, out, REGNO (reg));
989 s -= d;
990 }
991 return "";
992}
993
0d7e008e
SC
994
995void
996function_epilogue (stream, size)
997 FILE *stream;
998 int size;
999{
d3ae8277 1000 pragma_interrupt = pragma_trapa = 0;
0d7e008e
SC
1001}
1002
1003
bc45ade3 1004/* Return the text of the branch instruction which matches its length
b9654711
SC
1005 attribute.
1006
1007 This gets tricky if we have an insn in the delay slot of a branch
0d7e008e
SC
1008 and the branch needs more than 1 insn to complete. */
1009
1010int pending_const_table;
1011
1012 /* We can't tell if we need a register as a scratch for the jump
1013 until after branch shortening, and then it's too late to allocate a
1014 register the 'proper' way. These instruction sequences are rare
1015 anyway, so to avoid always using a reg up from our limited set, we'll
1016 grab one when we need one on output. */
1017
1018char *
1019output_far_jump (insn, op)
1020 rtx insn;
1021 rtx op;
1022{
1023 rtx thislab = gen_label_rtx ();
1024
1025 /* See if we can grab a reg from the prev insn */
1026 rtx gotone = 0;
1027 rtx prev = PREV_INSN (insn);
1028 rtx link;
1029
1030 if (dbr_sequence_length ())
1031 {
1032 /* Something to go in what would have been the delay
1033 slot if this had been a short branch. Make sure the
1034 reg we use to generate the branch target address
1035 doesn't conflict */
1036
1037 int i;
1038 rtx vec[2];
1039 vec[0] = thislab;
1040
1041 for (i = 0; i < 8; i++)
1042 {
1043 vec[1] = gen_rtx (REG, SImode, i);
1044 if (!reg_referenced_p (vec[1], PATTERN (XVECEXP (final_sequence, 0, 1))))
1045 break;
1046 }
b9654711 1047
0d7e008e
SC
1048 output_asm_insn ("mov.l %1,@-r15", vec);
1049 output_asm_insn ("mov.l %O0,%1", vec);
1050 print_slot (final_sequence);
1051 output_asm_insn ("jmp @%1 ! 32 xcond", vec);
1052 output_asm_insn ("mov.l @r15+,%1", vec);
1053 }
1054 else
1055 {
1056 output_asm_insn ("mov.l r13,@-r15", 0);
1057 output_asm_insn ("mov.l %O0,r13", &thislab);
1058 output_asm_insn ("jmp @r13 ! 32 zcond", 0);
1059 output_asm_insn ("mov.l @r15+,r13", 0);
1060 }
b9654711 1061
0d7e008e 1062 output_asm_insn (".align 2", 0);
d3ae8277 1063 ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (thislab));
0d7e008e
SC
1064 output_asm_insn (".long %O0", &op);
1065 return "";
1066}
bc45ade3
SC
1067
1068char *
1069output_branch (logic, insn)
1070 int logic;
b9654711 1071 rtx insn;
bc45ade3
SC
1072{
1073 extern rtx recog_operand[];
1074 int label = lf++;
b9654711
SC
1075 int rn = -1;
1076 int need_save;
d3ae8277 1077/* fprintf (asm_out_file, "! pc %04x\n", insn_addresses[INSN_UID (insn)]);*/
b9654711 1078
bc45ade3
SC
1079 switch (get_attr_length (insn))
1080 {
1081 case 2:
1082 /* Simple branch in range -200..+200 bytes */
b9654711 1083 return logic ? "bt%. %l0" : "bf%. %l0";
bc45ade3
SC
1084
1085 case 6:
1086 /* Branch in range -4000..+4000 bytes */
b9654711
SC
1087 {
1088 rtx oldop = recog_operand[0];
1089
1090
1091 if (need_slot (final_sequence))
1092 {
1093 fprintf (asm_out_file, "\tb%c.s\tLF%d\n", logic ? 'f' : 't',
1094 label);
1095
1096 print_slot (final_sequence);
1097 }
1098
1099 else
1100 {
1101 fprintf (asm_out_file, "\tb%c\tLF%d\n", logic ? 'f' : 't',
1102 label);
1103 }
1104 recog_operand[0] = oldop;
1105
1106 output_asm_insn ("bra %l0 ! 12 bit cond ", recog_operand);
1107 fprintf (asm_out_file, "\tor r0,r0\n");
b9654711
SC
1108 fprintf (asm_out_file, "LF%d:\n", label);
1109 }
bc45ade3
SC
1110 return "";
1111
0d7e008e 1112 case 16:
bc45ade3 1113 /* Branches a long way away */
b9654711 1114 {
b9654711
SC
1115 rtx oldop = recog_operand[0];
1116
1117 if (need_slot (final_sequence))
1118 {
1119 fprintf (asm_out_file, "\tb%c.s\tLF%d\n", logic ? 'f' : 't', label);
1120 print_slot (final_sequence);
1121
1122 }
1123 else
1124 {
1125 fprintf (asm_out_file, "\tb%c\tLF%d\n", logic ? 'f' : 't', label);
1126 }
1127
0d7e008e 1128 output_far_jump (insn, oldop);
b9654711
SC
1129 fprintf (asm_out_file, "LF%d:\n", label);
1130 return "";
1131 }
bc45ade3
SC
1132 }
1133 return "bad";
bc45ade3
SC
1134}
1135\f
b9654711 1136
0d7e008e
SC
1137/* The SH cannot load a large constant into a register, constants have to
1138 come from a pc relative load. The reference of a pc relative load
1139 instruction must be less than 1k infront of the instruction. This
1140 means that we often have to dump a constant inside a function, and
1141 generate code to branch around it.
b9654711 1142
0d7e008e
SC
1143 It is important to minimize this, since the branches will slow things
1144 down and make things bigger.
b9654711 1145
0d7e008e 1146 Worst case code looks like:
b9654711 1147
0d7e008e
SC
1148 mov.l L1,rn
1149 bra L2
1150 nop
1151 align
1152 L1: .long value
1153 L2:
1154 ..
bc45ade3 1155
0d7e008e
SC
1156 mov.l L3,rn
1157 bra L4
1158 nop
1159 align
1160 L3: .long value
1161 L4:
1162 ..
bc45ade3 1163
0d7e008e
SC
1164 We fix this by performing a scan before scheduling, which notices which
1165 instructions need to have their operands fetched from the constant table
1166 and builds the table.
bc45ade3 1167
bc45ade3 1168
0d7e008e 1169 The algorithm is:
bc45ade3 1170
0d7e008e
SC
1171 scan, find an instruction which needs a pcrel move. Look forward, find the
1172 last barrier which is within MAX_COUNT bytes of the requirement.
1173 If there isn't one, make one. Process all the instructions between
1174 the find and the barrier.
bc45ade3
SC
1175
1176 In the above example, we can tell that L3 is within 1k of L1, so
1177 the first move can be shrunk from the 3 insn+constant sequence into
1178 just 1 insn, and the constant moved to L3 to make:
1179
0d7e008e 1180 mov.l L1,rn
bc45ade3 1181 ..
0d7e008e
SC
1182 mov.l L3,rn
1183 bra L4
bc45ade3
SC
1184 nop
1185 align
0d7e008e
SC
1186 L3:.long value
1187 L4:.long value
bc45ade3
SC
1188
1189 Then the second move becomes the target for the shortening process.
1190
0d7e008e 1191 */
bc45ade3
SC
1192
1193typedef struct
1194{
0d7e008e
SC
1195 rtx value; /* Value in table */
1196 rtx label; /* Label of value */
1197 enum machine_mode mode; /* Mode of value */
1198}
1199
1200pool_node;
bc45ade3
SC
1201
1202/* The maximum number of constants that can fit into one pool, since
1203 the pc relative range is 0...1020 bytes and constants are at least 4
1204 bytes long */
1205
1206#define MAX_POOL_SIZE (1020/4)
1207static pool_node pool_vector[MAX_POOL_SIZE];
1208static int pool_size;
1209
0d7e008e 1210/* Add a constant to the pool and return its label. */
bc45ade3 1211
0d7e008e 1212static rtx
bc45ade3
SC
1213add_constant (x, mode)
1214 rtx x;
1215 enum machine_mode mode;
1216{
1217 int i;
0d7e008e 1218 rtx lab;
bc45ade3
SC
1219 /* First see if we've already got it */
1220
1221 for (i = 0; i < pool_size; i++)
1222 {
bc45ade3
SC
1223 if (x->code == pool_vector[i].value->code
1224 && mode == pool_vector[i].mode)
1225 {
1226 if (x->code == CODE_LABEL)
1227 {
1228 if (XINT (x, 3) != XINT (pool_vector[i].value, 3))
1229 continue;
1230 }
1231 }
bc45ade3 1232 if (rtx_equal_p (x, pool_vector[i].value))
0d7e008e 1233 return pool_vector[i].label;
bc45ade3 1234 }
b9654711 1235
0d7e008e 1236 /* Need a new one */
bc45ade3
SC
1237
1238 pool_vector[pool_size].value = x;
0d7e008e 1239 lab = gen_label_rtx ();
bc45ade3 1240 pool_vector[pool_size].mode = mode;
0d7e008e 1241 pool_vector[pool_size].label = lab;
bc45ade3 1242 pool_size++;
0d7e008e 1243 return lab;
bc45ade3
SC
1244}
1245
0d7e008e 1246/* Dump out interesting debug info */
bc45ade3 1247
0d7e008e
SC
1248rtx
1249final_prescan_insn (insn, opvec, noperands)
bc45ade3 1250 rtx insn;
0d7e008e
SC
1251 rtx *opvec;
1252 int noperands;
bc45ade3 1253{
0d7e008e 1254 if (target_flags & ISIZE_BIT)
bc45ade3 1255 {
0d7e008e
SC
1256 extern int *insn_addresses;
1257 fprintf (asm_out_file, "\n! at %04x\n",
1258 insn_addresses[INSN_UID (insn)]);
bc45ade3 1259 }
bc45ade3
SC
1260}
1261
bc45ade3 1262
0d7e008e 1263\f
bc45ade3 1264
0d7e008e 1265/* Stuff taken from m88k.c */
b9654711 1266
0d7e008e 1267/* Output to FILE the start of the assembler file. */
bc45ade3 1268
0d7e008e 1269struct option
bc45ade3 1270{
0d7e008e
SC
1271 char *string;
1272 int *variable;
1273 int on_value;
1274};
b9654711 1275
0d7e008e
SC
1276static int
1277output_option (file, sep, type, name, indent, pos, max)
1278 FILE *file;
1279 char *sep;
1280 char *type;
1281 char *name;
1282 char *indent;
1283 int pos;
1284 int max;
1285{
1286 if (strlen (sep) + strlen (type) + strlen (name) + pos > max)
bc45ade3 1287 {
0d7e008e
SC
1288 fprintf (file, indent);
1289 return fprintf (file, "%s%s", type, name);
b9654711 1290 }
0d7e008e
SC
1291 return pos + fprintf (file, "%s%s%s", sep, type, name);
1292}
bc45ade3 1293
0d7e008e
SC
1294static struct
1295{
1296 char *name;
1297 int value;
1298}
bc45ade3 1299
0d7e008e 1300m_options[] = TARGET_SWITCHES;
bc45ade3 1301
0d7e008e
SC
1302static void
1303output_options (file, f_options, f_len, W_options, W_len,
1304 pos, max, sep, indent, term)
1305 FILE *file;
1306 struct option *f_options;
1307 struct option *W_options;
1308 int f_len, W_len;
1309 int pos;
1310 int max;
1311 char *sep;
1312 char *indent;
1313 char *term;
1314{
1315 register int j;
bc45ade3 1316
bc45ade3 1317
0d7e008e
SC
1318 if (optimize)
1319 pos = output_option (file, sep, "-O", "", indent, pos, max);
1320 if (write_symbols != NO_DEBUG)
1321 pos = output_option (file, sep, "-g", "", indent, pos, max);
1322 if (flag_traditional)
1323 pos = output_option (file, sep, "-traditional", "", indent, pos, max);
1324 if (profile_flag)
1325 pos = output_option (file, sep, "-p", "", indent, pos, max);
1326 if (profile_block_flag)
1327 pos = output_option (file, sep, "-a", "", indent, pos, max);
bc45ade3 1328
0d7e008e
SC
1329 for (j = 0; j < f_len; j++)
1330 if (*f_options[j].variable == f_options[j].on_value)
1331 pos = output_option (file, sep, "-f", f_options[j].string,
1332 indent, pos, max);
bc45ade3 1333
0d7e008e
SC
1334 for (j = 0; j < W_len; j++)
1335 if (*W_options[j].variable == W_options[j].on_value)
1336 pos = output_option (file, sep, "-W", W_options[j].string,
1337 indent, pos, max);
bc45ade3 1338
0d7e008e
SC
1339 for (j = 0; j < sizeof m_options / sizeof m_options[0]; j++)
1340 if (m_options[j].name[0] != '\0'
1341 && m_options[j].value > 0
1342 && ((m_options[j].value & target_flags)
1343 == m_options[j].value))
1344 pos = output_option (file, sep, "-m", m_options[j].name,
1345 indent, pos, max);
bc45ade3 1346
bc45ade3 1347
0d7e008e
SC
1348 fprintf (file, term);
1349 fprintf (file, "! %d %d\n", max_count_si, max_count_hi);
1350}
b9654711 1351
0d7e008e
SC
1352void
1353output_file_start (file, f_options, f_len, W_options, W_len)
1354 FILE *file;
1355 struct option *f_options;
1356 struct option *W_options;
1357 int f_len, W_len;
bc45ade3 1358{
0d7e008e 1359 register int pos;
b9654711 1360
0d7e008e 1361 output_file_directive (file, main_input_filename);
b9654711 1362
0d7e008e
SC
1363 /* Switch to the data section so that the coffsem symbol and the
1364 gcc2_compiled. symbol aren't in the text section. */
1365 data_section ();
b9654711 1366
b9654711 1367
d3ae8277 1368 pos = fprintf (file, "\n! Hitachi SH cc1 (%s) (release D-1) arguments:", version_string);
0d7e008e
SC
1369 output_options (file, f_options, f_len, W_options, W_len,
1370 pos, 75, " ", "\n! ", "\n\n");
bc45ade3 1371}
0d7e008e 1372\f
bc45ade3
SC
1373
1374
0d7e008e 1375/* Return the cost of a shift */
bc45ade3 1376
0d7e008e
SC
1377int
1378shiftcosts (RTX)
1379 rtx RTX;
bc45ade3 1380{
0d7e008e
SC
1381 /* If shift by a non constant, then this will be expensive. */
1382 if (GET_CODE (XEXP (RTX, 1)) != CONST_INT)
1383 return 20;
bc45ade3 1384
0d7e008e
SC
1385 /* otherwise, it will be very cheap if by one of the constants
1386 we can cope with. */
1387 if (CONST_OK_FOR_K (INTVAL (XEXP (RTX, 1))))
1388 return 1;
b9654711 1389
0d7e008e
SC
1390 /* otherwise it will be several insns, but we pretend that it will be more than
1391 just the components, so that combine doesn't glue together a load of shifts into
1392 one shift which has to be emitted as a bunch anyway - breaking scheduling */
d3ae8277 1393 return 1;
0d7e008e 1394}
b9654711 1395
0d7e008e
SC
1396int
1397andcosts (RTX)
1398 rtx RTX;
1399{
1400 int i;
1401 if (GET_CODE (XEXP (RTX, 1)) != CONST_INT)
1402 return 2;
1403 i = INTVAL (XEXP (RTX, 1));
1404 /* And can use the extend insns cheaply */
1405 if (i == 0xff || i == 0xffff)
1406 return 2;
1407 /* Any small constant is reasonably cheap - but requires r0 */
1408 if (CONST_OK_FOR_I (i))
1409 return 3;
1410 return 5;
1411}
d3ae8277
SC
1412
1413int howshift (i)
1414int i;
1415{
1416 int total = 0;
1417 while (i > 0)
1418 {
1419 if (i >= 16) {
1420 total++;
1421 i -= 16;
1422 }
1423 else if (i >= 8) {
1424 total++;
1425 i -= 8;
1426 }
1427 else if (i >= 2) {
1428 total++;
1429 i -= 2;
1430 }
1431 else if (i>=1) {
1432 total++;
1433 i--;
1434 }
1435 }
1436 return total;
1437}
1438
0d7e008e
SC
1439/* Return the cost of a multiply */
1440int
1441multcosts (RTX)
1442 rtx RTX;
1443{
d3ae8277
SC
1444 /* If mult by a power of 2 then work out how we'd shift to make it */
1445 int insn_cost;
1446
1447 if (GET_CODE (XEXP (RTX, 1)) == CONST_INT)
1448 {
1449 int i = exact_log2 (INTVAL (XEXP (RTX, 1)));
1450 if (i >= 0)
1451 insn_cost = howshift (i);
1452 else
1453 insn_cost = 100000;
1454 }
0d7e008e 1455 if (TARGET_SH2)
d3ae8277
SC
1456 {
1457 /* We have a mul insn, so we can never take more than the mul and the
1458 read of the mac reg, but count more because of the latency and extra reg
1459 usage */
1460 if (TARGET_SMALLCODE)
1461 return 2;
1462 if (insn_cost > 5)
1463 return 5;
1464 return insn_cost;
1465 }
1466
0d7e008e 1467 /* If we we're aiming at small code, then just count the number of
d3ae8277
SC
1468 insns in a multiply call sequence */
1469
1470 if (TARGET_SMALLCODE)
1471 {
1472 if (insn_cost > 6)
1473 return 6;
1474 return insn_cost;
1475 }
1476
1477 /* Otherwise count all the insns in the routine we'd be calling too */
1478 return 20;
0d7e008e 1479}
b9654711 1480
0d7e008e 1481/* Code to expand a shift */
b9654711 1482
0d7e008e
SC
1483void
1484gen_ashift (type, n, reg)
1485 int type;
1486 int n;
1487 rtx reg;
1488{
1489 switch (type)
bc45ade3 1490 {
0d7e008e
SC
1491 case ASHIFTRT:
1492 emit_insn (gen_ashrsi3_k (reg, reg, GEN_INT (n)));
1493 break;
1494 case LSHIFTRT:
1495 emit_insn (gen_lshrsi3_k (reg, reg, GEN_INT (n)));
1496 break;
1497 case ASHIFT:
1498 if (n == 1)
1499 emit_insn (gen_addsi3 (reg, reg, reg));
1500 else
1501 emit_insn (gen_ashlsi3_k (reg, reg, GEN_INT (n)));
1502 break;
bc45ade3 1503 }
bc45ade3 1504}
bc45ade3 1505
0d7e008e
SC
1506int
1507gen_shifty_op (code, operands)
1508 int code;
1509 rtx *operands;
bc45ade3 1510{
0d7e008e
SC
1511 rtx wrk = gen_reg_rtx (SImode);
1512 rtx t;
1513 char *func;
1514 if (GET_CODE (operands[2]) == CONST_INT)
bc45ade3 1515 {
0d7e008e
SC
1516 int value = INTVAL (operands[2]);
1517 top:
1518 switch (code)
1519 {
1520 case ASHIFTRT:
1521 if (value < 0)
1522 {
1523 code = ASHIFT;
1524 value = -value;
1525 goto top;
1526 }
bc45ade3 1527
0d7e008e 1528 /* Expand a short sequence inline, longer call a magic routine */
d3ae8277 1529 if (value <= 5)
0d7e008e
SC
1530 {
1531 emit_move_insn (wrk, operands[1]);
1532 while (value--)
1533 {
1534 gen_ashift (ASHIFTRT, 1, wrk);
1535 }
1536 emit_move_insn (operands[0], wrk);
1537 return 1;
1538 }
1539 t = gen_reg_rtx (Pmode);
1540 /* Load the value into an arg reg and call a helper */
1541 emit_move_insn (gen_rtx (REG, SImode, 4), operands[1]);
1542 if (!shiftsyms[value])
1543 {
1544 func = xmalloc (18);
1545 sprintf (func, "__ashiftrt_r4_%d", value);
1546 shiftsyms[value] = gen_rtx (SYMBOL_REF, Pmode, func);
1547 }
1548 emit_move_insn (t, shiftsyms[value]);
1549 emit_insn (gen_ashrsi3_n (GEN_INT (value), t));
1550 emit_move_insn (operands[0], gen_rtx (REG, SImode, 4));
1551 return 1;
bc45ade3 1552
0d7e008e
SC
1553 case ASHIFT:
1554 if (value < 0)
1555 {
1556 code = LSHIFTRT;
1557 value = -value;
1558 goto top;
1559 }
1560 /* Fall through */
1561 case LSHIFTRT:
bc45ade3 1562
0d7e008e
SC
1563 if (value < 0)
1564 {
1565 code = ASHIFT;
1566 value = -value;
1567 goto top;
1568 }
a9f71ad8 1569
0d7e008e
SC
1570 emit_move_insn (wrk, operands[1]);
1571 while (value)
1572 {
1573 if (value >= 16)
1574 {
1575 gen_ashift (code, 16, wrk);
1576 value -= 16;
1577 }
1578 else if (value >= 8)
1579 {
1580 gen_ashift (code, 8, wrk);
1581 value -= 8;
1582 }
1583 else if (value >= 2)
1584 {
1585 gen_ashift (code, 2, wrk);
1586 value -= 2;
1587 }
1588 else
1589 {
1590 gen_ashift (code, 1, wrk);
1591 value--;
1592 }
1593 }
1594 emit_move_insn (operands[0], wrk);
1595 return 1;
a9f71ad8 1596
0d7e008e 1597 }
a9f71ad8 1598 }
0d7e008e 1599 return 0;
bc45ade3
SC
1600}
1601
0d7e008e
SC
1602/* Dump out any constants accumulated in the final pass -
1603 which will only be labels */
1604char *
1605output_jump_label_table ()
1606{
1607 int i;
1608 if (pool_size)
1609 {
1610 fprintf (asm_out_file, "\t.align 2\n");
1611 for (i = 0; i < pool_size; i++)
1612 {
1613 pool_node *p = pool_vector + i;
a9f71ad8 1614
0d7e008e
SC
1615 ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (p->label));
1616 output_asm_insn (".long %O0", &p->value);
1617 }
1618 pool_size = 0;
1619 }
b9654711 1620
0d7e008e
SC
1621 return "";
1622}
1623/* Output the literal table */
b9654711 1624
b9654711 1625static void
0d7e008e
SC
1626dump_table (scan)
1627 rtx scan;
b9654711 1628{
0d7e008e
SC
1629 int i;
1630 int pass;
1631 int need_align = 1;
b9654711
SC
1632
1633
0d7e008e 1634 /* Do two passes, first time dump out the HI sized constants */
b9654711 1635
0d7e008e 1636 for (i = 0; i < pool_size; i++)
b9654711 1637 {
0d7e008e
SC
1638 pool_node *p = pool_vector + i;
1639 if (p->mode == HImode)
1640 {
1641 if (need_align)
1642 {
1643 scan = emit_insn_after (gen_align_2 (), scan);
1644 need_align = 0;
1645 }
1646 scan = emit_label_after (p->label, scan);
1647 scan = emit_insn_after (gen_consttable_2 (p->value), scan);
1648 }
b9654711 1649 }
0d7e008e 1650 need_align = 1;
b9654711 1651
0d7e008e 1652 for (i = 0; i < pool_size; i++)
b9654711 1653 {
0d7e008e 1654 pool_node *p = pool_vector + i;
b9654711 1655
0d7e008e 1656 switch (p->mode)
b9654711 1657 {
0d7e008e
SC
1658 case HImode:
1659 break;
1660 case SImode:
1661 if (need_align)
b9654711 1662 {
0d7e008e 1663 need_align = 0;
d3ae8277 1664 scan = emit_label_after (gen_label_rtx (), scan);
0d7e008e 1665 scan = emit_insn_after (gen_align_4 (), scan);
b9654711 1666 }
0d7e008e
SC
1667 scan = emit_label_after (p->label, scan);
1668 scan = emit_insn_after (gen_consttable_4 (p->value), scan);
1669 break;
1670 case DImode:
1671 if (need_align)
1672 {
1673 need_align = 0;
d3ae8277 1674 scan = emit_label_after (gen_label_rtx (), scan);
0d7e008e
SC
1675 scan = emit_insn_after (gen_align_4 (), scan);
1676 }
1677 scan = emit_label_after (p->label, scan);
1678 scan = emit_insn_after (gen_consttable_8 (p->value), scan);
1679 break;
1680 default:
1681 abort ();
1682 break;
b9654711
SC
1683 }
1684 }
b9654711 1685
0d7e008e
SC
1686 scan = emit_insn_after (gen_consttable_end (), scan);
1687 scan = emit_barrier_after (scan);
1688 pool_size = 0;
1689}
b9654711 1690
b9654711 1691
b9654711 1692
0d7e008e
SC
1693/* Non zero if the src operand needs to be fixed up */
1694static
1695int
1696fixit (src, mode)
1697 rtx src;
1698 enum machine_mode mode;
1699{
1700 if (mode == QImode)
1701 return 0; /* QIs never need to be fixed */
1702 if (GET_CODE (src) == CONST)
1703 return 1;
b9654711 1704
0d7e008e 1705 if (GET_CODE (src) == SYMBOL_REF)
b9654711 1706 {
0d7e008e
SC
1707 return 1;
1708 }
1709 if (GET_CODE (src) == CONST_INT)
1710 {
1711 /* All QI insns are ok */
1712 if (mode == QImode)
1713 return 1;
1714 /* The rest may need to be fixed */
1715 return !CONST_OK_FOR_I (INTVAL (src));
b9654711 1716 }
0d7e008e 1717 return 0;
b9654711
SC
1718}
1719
0d7e008e
SC
1720/* Return Non-zero if constant would be an ok source for a
1721 mov.w instead of a mov.l */
1722int
1723hi_const (src)
1724 rtx src;
b9654711 1725{
d3ae8277
SC
1726 if (GET_CODE (src) == CONST
1727 && GET_CODE (XEXP (src, 0)) == SIGN_EXTEND
1728 && GET_CODE (XEXP (XEXP (src, 0), 0)) == SYMBOL_REF)
1729 return 1;
1730
1731 if (TARGET_SHORTADDR
1732 && GET_CODE (src) == SYMBOL_REF)
1733 return 1;
1734
0d7e008e
SC
1735 return (GET_CODE (src) == CONST_INT
1736 && INTVAL (src) >= -32768
1737 && INTVAL (src) <= 32767);
b9654711 1738}
b9654711 1739
0d7e008e
SC
1740/* Find the last barrier less than MAX_COUNT bytes from FROM, or create one.
1741 If an HI move is found, then make sure that MAX_COUNT_HI isn't broken from that one. */
b9654711 1742
0d7e008e
SC
1743static
1744rtx
1745find_barrier (from)
1746 rtx from;
b9654711 1747{
0d7e008e
SC
1748 int count_si = 0;
1749 int count_hi = 0;
1750 int found_hi = 0;
1751 int found_si = 0;
1752 rtx found_barrier = 0;
1753
1754 while (from
1755 && count_si < max_count_si
1756 && count_hi < max_count_hi)
1757 {
1758 int inc;
1759 if (GET_CODE (from) == BARRIER)
1760 {
1761 found_barrier = from;
1762 }
1763 /* Count the length of this insn - we assume that all the pcrelloads
1764 will work out to be only 2 bytes long */
b9654711 1765
0d7e008e
SC
1766 if (GET_CODE (from) == INSN &&
1767 GET_CODE (PATTERN (from)) == SET)
1768 {
1769 rtx src = SET_SRC (PATTERN (from));
1770 if (hi_const (src))
1771 found_hi = 1;
1772 else
1773 found_si = 1;
1774 inc = 2;
1775 }
1776 else
1777 {
1778 inc = get_attr_length (from);
1779 }
1780 if (found_si)
1781 count_si += inc;
1782 if (found_hi)
1783 count_hi += inc;
1784 from = NEXT_INSN (from);
1785 }
1786
1787 if (!found_barrier)
b9654711 1788 {
0d7e008e
SC
1789 /* Insert a jump around the barrier here */
1790 rtx label = gen_label_rtx ();
1791 /* Walk back to be just before any jump */
1792 while (GET_CODE (from) == JUMP_INSN
1793 || GET_CODE (from) == NOTE)
1794 {
1795 from = PREV_INSN (from);
1796 }
1797 from = emit_jump_insn_after (gen_jump (label), from);
1798 JUMP_LABEL (from) = label;
1799 found_barrier = emit_barrier_after (from);
1800 emit_label_after (label, found_barrier);
1801 return found_barrier;
b9654711 1802 }
0d7e008e 1803 return found_barrier;
b9654711
SC
1804}
1805
0d7e008e 1806/* Non zero if the insn is a move instruction which needs to be fixed. */
b9654711 1807
0d7e008e
SC
1808static
1809int
1810broken_move (insn)
1811 rtx insn;
b9654711 1812{
0d7e008e
SC
1813 if (!INSN_DELETED_P (insn)
1814 && GET_CODE (insn) == INSN
1815 && GET_CODE (PATTERN (insn)) == SET)
1816 {
1817 rtx pat = PATTERN (insn);
1818 rtx src = SET_SRC (pat);
1819 rtx dst = SET_DEST (pat);
1820 enum machine_mode mode = GET_MODE (dst);
1821 if (dst == pc_rtx)
1822 return 0;
1823 return fixit (src, mode);
1824 }
1825 return 0;
1826}
b9654711 1827
b9654711 1828
0d7e008e 1829/* Exported to toplev.c
b9654711 1830
0d7e008e
SC
1831 Scan the function looking for move instructions which have to be changed to
1832 pcrel loads and insert the literal tables. */
b9654711 1833
0d7e008e
SC
1834void
1835machine_dependent_reorg (first)
1836 rtx first;
1837{
1838 rtx insn;
1839 int limit;
1840 for (insn = first; insn; insn = NEXT_INSN (insn))
1841 {
1842 if (broken_move (insn))
1843 {
1844 /* This is a broken move instruction, scan ahead looking for
1845 a barrier to stick the constant table behind */
1846 rtx scan;
1847 rtx barrier = find_barrier (insn);
b9654711 1848
0d7e008e
SC
1849 /* Now find all the moves between the points and modify them */
1850 for (scan = insn; scan != barrier; scan = NEXT_INSN (scan))
1851 {
1852 if (broken_move (scan))
1853 {
1854 rtx pat = PATTERN (scan);
1855 rtx src = SET_SRC (pat);
1856 rtx dst = SET_DEST (pat);
1857 enum machine_mode mode = GET_MODE (dst);
1858 rtx lab;
1859 rtx newinsn;
1860 rtx newsrc;
1861 /* This is a broken move instruction, add it to the pool */
1862
1863 if (mode == SImode && hi_const (src))
1864 {
1865 /* This is an HI source, clobber the dest to get the mode right too */
1866 mode = HImode;
d3ae8277
SC
1867 while (GET_CODE (dst) == SUBREG)
1868 dst = SUBREG_REG (dst);
0d7e008e
SC
1869 dst = gen_rtx (REG, HImode, REGNO (dst));
1870 }
1871 lab = add_constant (src, mode);
1872 newsrc = gen_rtx (MEM, mode,
1873 gen_rtx (LABEL_REF, VOIDmode, lab));
1874
1875 /* Build a jump insn wrapper around the move instead
1876 of an ordinary insn, because we want to have room for
1877 the target label rtx in fld[7], which an ordinary
1878 insn doesn't have. */
1879 newinsn = emit_jump_insn_after (gen_rtx (SET, VOIDmode,
1880 dst, newsrc), scan);
1881 JUMP_LABEL (newinsn) = lab;
1882
1883 /* But it's still an ordinary insn */
1884 PUT_CODE (newinsn, INSN);
1885
1886 /* Kill old insn */
1887 delete_insn (scan);
1888 scan = newinsn;
1889 }
1890 }
1891 dump_table (barrier);
1892 }
1893 }
b9654711
SC
1894}
1895
0d7e008e
SC
1896/* Called from the md file, set up the operands of a compare instruction */
1897
1898int
1899from_compare (operands, code)
1900 rtx *operands;
1901 int code;
b9654711 1902{
d3ae8277
SC
1903 if (code != EQ && code != NE)
1904 {
1905 /* Force args into regs, since we can't use constants here */
1906 sh_compare_op0 = force_reg (SImode, sh_compare_op0);
1907 if (sh_compare_op1 != const0_rtx)
1908 sh_compare_op1 = force_reg (SImode, sh_compare_op1);
1909 }
0d7e008e 1910 operands[1] = sh_compare_op0;
d3ae8277 1911 operands[2] = sh_compare_op1;
0d7e008e 1912}
b9654711 1913
0d7e008e 1914/* Non-zero if x is EQ or NE */
b9654711 1915
0d7e008e
SC
1916int
1917equality_operator (x, mode)
1918 rtx x;
1919 enum machine_mode mode;
1920{
1921 enum rtx_code code = GET_CODE (x);
1922 return (code == EQ || code == NE);
1923}
b9654711
SC
1924
1925
0d7e008e
SC
1926/* Framefull frame looks like:
1927
1928 arg-5
1929 arg-4
1930 [ if current_function_anonymous_args
1931 arg-3
1932 arg-2
1933 arg-1
1934 arg-0 ]
1935 saved-fp
1936 saved-r10
1937 saved-r11
1938 saved-r12
1939 saved-pr
1940 local-n
1941 ..
1942 local-1
1943 local-0 <- fp points here
1944
1945
1946 If TARGET_SMALLCALL, then the preserved registers are pushed by a
1947 wrapper before the routine is entered, so the regs are always pushed
1948 and there are two pr's on the stack - the caller and the wrapper.
1949 */
1950
b9654711
SC
1951
1952/* Code to generate prologue and epilogue sequences */
1953
0d7e008e 1954
b9654711
SC
1955void
1956sh_expand_prologue ()
1957{
1958 int live_regs_mask;
1959 int d;
1960
1961 live_regs_mask = calc_live_regs (&d);
1962
0d7e008e
SC
1963 /* We have pretend args if we had an object sent partially in registers
1964 and partially on the stack - eg a large structure */
1965 output_stack_adjust (-current_function_pretend_args_size);
b9654711
SC
1966
1967 if (current_function_anonymous_args)
1968 {
1969 /* Push arg regs as if they'd been provided by caller in stack */
1970 int i;
1971 for (i = 0; i < NPARM_REGS; i++)
1972 {
1973 int rn = NPARM_REGS + FIRST_PARM_REG - i - 1;
1974 if (i > NPARM_REGS - current_function_args_info)
1975 break;
1976 push (rn);
b9654711
SC
1977 extra_push += 4;
1978 }
1979 }
0d7e008e
SC
1980 push_regs (live_regs_mask);
1981 output_stack_adjust (-get_frame_size ());
b9654711
SC
1982
1983 if (frame_pointer_needed)
1984 {
b9654711
SC
1985 emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx));
1986 }
b9654711
SC
1987}
1988
1989void
1990sh_expand_epilogue ()
1991{
1992 int live_regs_mask;
1993 int d;
1994 int i;
1995
1996 live_regs_mask = calc_live_regs (&d);
1997
1998 if (frame_pointer_needed)
1999 {
2000 emit_insn (gen_movsi (stack_pointer_rtx, frame_pointer_rtx));
2001 }
0d7e008e 2002 output_stack_adjust (get_frame_size ());
b9654711
SC
2003
2004 /* Pop all the registers */
0d7e008e 2005
b9654711
SC
2006 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
2007 {
2008 int j = (FIRST_PSEUDO_REGISTER - 1) - i;
2009 if (live_regs_mask & (1 << j))
2010 {
2011 pop (j);
2012 }
2013 }
b9654711 2014
0d7e008e 2015 output_stack_adjust (extra_push + current_function_pretend_args_size);
b9654711 2016
0d7e008e
SC
2017 extra_push = 0;
2018 current_function_pretend_args_size = 0;
b9654711 2019 current_function_anonymous_args = 0;
0d7e008e
SC
2020 for (i = 0; i < 32; i++)
2021 shiftsyms[i] = 0;
d3ae8277 2022
b9654711
SC
2023}
2024
0d7e008e
SC
2025/* Define the offset between two registers, one to be eliminated, and
2026 the other its replacement, at the start of a routine. */
2027
2028int
2029initial_elimination_offset (from, to)
2030{
2031 int regs_saved;
2032 int regs_saved_mask = calc_live_regs (&regs_saved);
2033 int total_saved_regs_space;
2034 int total_auto_space = get_frame_size ();
2035 total_saved_regs_space = (regs_saved) * 4;
b9654711 2036
0d7e008e
SC
2037 if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
2038 {
2039 return total_saved_regs_space + total_auto_space;
2040 }
2041 if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
2042 {
2043 return total_saved_regs_space + total_auto_space;
2044 }
2045 if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
2046 {
2047 /* Initial gap between fp and sp is 0 */
2048 return 0;
2049 }
2050 abort ();
2051}
2052
2053/* Handle machine specific pragmas to be semi-compatible with Hitachi
2054 compiler */
b9654711
SC
2055
2056int
0d7e008e
SC
2057handle_pragma (file)
2058 FILE *file;
b9654711 2059{
0d7e008e
SC
2060 int c;
2061 char pbuf[200];
2062 int psize = 0;
b9654711 2063
0d7e008e
SC
2064 c = getc (file);
2065 while (c == ' ' || c == '\t')
2066 c = getc (file);
2067
2068 if (c == '\n' || c == EOF)
2069 return c;
2070
2071 while (psize < sizeof (pbuf) - 1 && c != '\n')
2072 {
2073 pbuf[psize++] = c;
2074 if (psize == 9 && strncmp (pbuf, "interrupt", 9) == 0)
2075 {
2076 pragma_interrupt = 1;
2077 return;
2078 }
2079 if (psize == 5 && strncmp (pbuf, "trapa", 5) == 0)
2080 {
2081 pragma_interrupt = pragma_trapa = 1;
2082 return;
2083 }
2084 c = getc (file);
2085 }
2086 return c;
2087}
2088\f
2089/* insn expand helpers */
2090
d3ae8277
SC
2091/* Emit insns to perform a call.
2092 If TARGET_SHORTADDR then use a bsr. If TARGET_SMALLCALL, then load the
0d7e008e
SC
2093 target address into r1 and call __saveargs, otherwise
2094 perform the standard call sequence */
2095
2096void
2097expand_acall (isa_retval, operands)
2098 int isa_retval;
2099 rtx *operands;
2100{
2101 rtx call;
2102 rtx ret = operands[0];
2103 rtx call_target = operands[isa_retval + 0];
2104 rtx numargs = operands[isa_retval + 1];
2105
d3ae8277 2106 if (TARGET_BSR)
0d7e008e 2107 {
d3ae8277 2108 call = gen_rtx (CALL, VOIDmode, call_target, numargs);
0d7e008e 2109 }
d3ae8277 2110 else {
0d7e008e 2111
d3ae8277
SC
2112 if (GET_CODE (call_target) == MEM)
2113 {
2114 call_target = force_reg (Pmode,
2115 XEXP (call_target, 0));
2116 }
2117 if (TARGET_SMALLCALL)
2118 {
2119 rtx tmp = gen_reg_rtx (SImode);
2120 rtx r1 = gen_rtx (REG, SImode, 1);
2121 emit_move_insn (tmp, gen_rtx (SYMBOL_REF, SImode, "__saveargs"));
2122 emit_move_insn (r1, call_target);
2123 emit_insn (gen_rtx (USE, VOIDmode, r1));
2124 call_target = tmp;
2125 }
0d7e008e 2126
d3ae8277
SC
2127 call = gen_rtx (CALL, VOIDmode, gen_rtx (MEM, SImode, call_target), numargs);
2128 }
0d7e008e
SC
2129 if (isa_retval)
2130 {
2131 call = gen_rtx (SET, VOIDmode, ret, call);
2132 }
2133
2134 emit_call_insn (gen_rtx (PARALLEL, VOIDmode,
2135 gen_rtvec (2,
2136 call,
d3ae8277 2137 gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 17)))));
0d7e008e
SC
2138
2139}
2140\f
2141
2142/* Predicates used by the templates */
2143
2144
2145/* Returns 1 if OP can be source of a simple move operation.
2146 Same as general_operand, but a LABEL_REF is valid, PRE_DEC is
2147 invalid as are subregs of system registers. */
2148
2149int
2150general_movsrc_operand (op, mode)
2151 rtx op;
2152 enum machine_mode mode;
2153{
2154 /* Any MEM(label_ref) is ok, that's a pcrel load */
2155 if (GET_CODE (op) == MEM &&
2156 GET_CODE (XEXP (op, 0)) == LABEL_REF)
b9654711
SC
2157 return 1;
2158
0d7e008e
SC
2159 /* No predec allowed */
2160
2161 if (GET_CODE (op) == MEM
2162 && GET_CODE (XEXP (op, 0)) == PRE_DEC)
2163 return 0;
2164
2165 if ((mode == QImode || mode == HImode)
2166 && (GET_CODE (op) == SUBREG
2167 && GET_CODE (XEXP (op, 0)) == REG
2168 && system_reg_operand (XEXP (op, 0), mode)))
2169 return 0;
2170
2171 if (GET_CODE (op) == CONST_INT)
2172 {
2173 int i = INTVAL (op);
2174 return CONST_OK_FOR_I (i);
2175 }
2176 return general_operand (op, mode);
b9654711
SC
2177}
2178
0d7e008e
SC
2179
2180/* Returns 1 if OP can be a destination of a move.
2181 Same as general_operand, but no preinc allowed. */
2182
b9654711 2183int
0d7e008e
SC
2184general_movdst_operand (op, mode)
2185 rtx op;
2186 enum machine_mode mode;
b9654711 2187{
0d7e008e 2188 if (GET_CODE (op) == MEM
d3ae8277
SC
2189 && (GET_CODE (XEXP (op, 0)) == PRE_INC
2190 || GET_CODE (XEXP (op, 0)) == POST_INC
2191 || GET_CODE (XEXP (op, 0)) == POST_DEC))
0d7e008e 2192 return 0;
d3ae8277 2193
0d7e008e
SC
2194 return general_operand (op, mode);
2195}
2196
2197
d3ae8277
SC
2198
2199/* Returns 1 if OP is valid destination for a bsr. */
2200
2201int
2202bsr_operand (op, mode)
2203rtx op;
2204enum machine_mode mode;
2205{
2206 if (GET_CODE (op) == SYMBOL_REF)
2207 return 1;
2208 return 0;
2209}
2210
0d7e008e
SC
2211/* Returns 1 if OP is an immediate ok for a byte index. */
2212
2213int
2214byte_index_operand (op, mode)
2215 rtx op;
2216 enum machine_mode mode;
2217{
2218 return (GET_CODE (op) == CONST_INT
2219 && INTVAL (op) >= 0
2220 && INTVAL (op) <= 15);
2221}
2222
2223/* Returns 1 if OP is a pop operand. */
2224
2225int
2226pop_operand (op, mode)
2227 rtx op;
2228 enum machine_mode mode;
2229{
2230 if (GET_CODE (op) != MEM)
2231 return 0;
2232
2233 if (GET_MODE (op) != mode)
2234 return 0;
2235
2236 op = XEXP (op, 0);
2237
2238 if (GET_CODE (op) != POST_INC)
2239 return 0;
2240
2241 return XEXP (op, 0) == stack_pointer_rtx;
2242}
2243
2244
2245/* Returns 1 if OP is a normal arithmetic register. */
2246
2247int
2248arith_reg_operand (op, mode)
2249 rtx op;
2250 enum machine_mode mode;
2251{
2252 if (register_operand (op, mode))
2253 {
2254 if (GET_CODE (op) == REG)
2255 return (REGNO (op) != T_REG
2256 && REGNO (op) != PR_REG);
2257 return 1;
2258 }
2259 return 0;
2260}
2261
2262/* Returns 1 if OP is MACL, MACH or PR. */
2263
2264int
2265system_reg_operand (op, mode)
2266 rtx op;
2267 enum machine_mode mode;
2268{
2269 if (GET_CODE (op) == REG)
2270 {
2271 switch (REGNO (op))
2272 {
2273 case PR_REG:
2274 case MACL_REG:
2275 case MACH_REG:
2276 return 1;
2277 }
2278 }
2279 return 0;
2280}
2281
2282
2283/* Returns 1 if OP is a valid source operand for an arithmetic insn. */
2284
2285int
2286arith_operand (op, mode)
2287 rtx op;
2288 enum machine_mode mode;
2289{
2290 if (arith_reg_operand (op, mode))
2291 return 1;
2292
2293 if (GET_CODE (op) == CONST_INT)
2294 {
2295 if (CONST_OK_FOR_I (INTVAL (op)))
2296 return 1;
2297 }
2298 return 0;
2299}
2300
2301
2302/* Returns 1 if OP is a valid source operand for a logical operation. */
2303
2304int
2305logical_operand (op, mode)
2306 rtx op;
2307 enum machine_mode mode;
2308{
2309 if (arith_reg_operand (op, mode))
2310 return 1;
2311
2312 if (GET_CODE (op) == CONST_INT)
2313 {
2314 if (CONST_OK_FOR_L (INTVAL (op)))
2315 return 1;
2316 }
2317 return 0;
b9654711 2318}
0d7e008e 2319
d3ae8277
SC
2320/* Returns 1 if OP is a valid operand for a MAC instruction,
2321 either a register or indirect memory. For now we don't
2322 try and recognise a mac insn */
2323
2324int
2325mac_operand (op, mode)
2326 rtx op;
2327 enum machine_mode mode;
2328{
2329 if (arith_reg_operand (op, mode))
2330 return 1;
2331#if 0
2332 Turned off till mac is understood
2333 if (GET_CODE (op) == MEM)
2334 return 1;
2335#endif
2336 return 0;
2337}
2338
2339/* Determine where to put an argument to a function.
2340 Value is zero to push the argument on the stack,
2341 or a hard register in which to store the argument.
2342
2343 MODE is the argument's machine mode.
2344 TYPE is the data type of the argument (as a tree).
2345 This is null for libcalls where that information may
2346 not be available.
2347 CUM is a variable of type CUMULATIVE_ARGS which gives info about
2348 the preceding args and about the function being called.
2349 NAMED is nonzero if this argument is a named parameter
2350 (otherwise it is an extra parameter matching an ellipsis). */
2351
2352rtx
2353sh_function_arg (cum, mode, type, named)
2354CUMULATIVE_ARGS cum;
2355enum machine_mode mode;
2356tree type;
2357int named;
2358{
2359 if (named)
2360 {
2361 int rr = (ROUND_REG ((cum), (mode)));
2362
2363 if (rr < NPARM_REGS)
2364 {
2365 return ((((mode) != BLKmode
2366 && ((type)==0 || ! TREE_ADDRESSABLE ((tree)(type)))
2367 && ((type)==0 || (mode) != BLKmode
2368 || (TYPE_ALIGN ((type)) % PARM_BOUNDARY == 0))
2369 ? gen_rtx (REG, (mode),
2370 (FIRST_PARM_REG + rr)): 0)));
2371
2372 }
2373 }
2374 return 0;
2375}
2376
2377/* For an arg passed partly in registers and partly in memory,
2378 this is the number of registers used.
2379 For args passed entirely in registers or entirely in memory, zero.
2380 Any arg that starts in the first 4 regs but won't entirely fit in them
2381 needs partial registers on the SH. */
2382
2383int
2384sh_function_arg_partial_nregs (CUM, MODE, TYPE, NAMED)
2385 CUMULATIVE_ARGS CUM;
2386 enum machine_mode MODE;
2387 tree TYPE;
2388 int NAMED;
2389{
2390 if ((CUM) < NPARM_REGS)
2391 {
2392 if (((TYPE)==0 || ! TREE_ADDRESSABLE ((tree)(TYPE)))
2393 && ((TYPE)==0 || (MODE) != BLKmode
2394 || (TYPE_ALIGN ((TYPE)) % PARM_BOUNDARY == 0))
2395 && ((CUM) + ((MODE) == BLKmode
2396 ? ROUND_ADVANCE (int_size_in_bytes (TYPE))
2397 : ROUND_ADVANCE (GET_MODE_SIZE (MODE))) - NPARM_REGS > 0))
2398 {
2399 return NPARM_REGS - CUM;
2400 }
2401 }
2402 return 0;
2403}
2404