OSDN Git Service

* config/stormy16/stormy16.c (stormy16_expand_epilogue): Use
[pf3gnuchains/gcc-fork.git] / gcc / config / stormy16 / stormy16.c
1 /* Stormy16 target functions.
2    Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
3    Contributed by Red Hat, Inc.
4
5 This file is part of GNU CC.
6
7 GNU CC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 GNU CC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU CC; see the file COPYING.  If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.  */
21
22 #include "config.h"
23 #include "system.h"
24 #include "rtl.h"
25 #include "regs.h"
26 #include "hard-reg-set.h"
27 #include "real.h"
28 #include "insn-config.h"
29 #include "conditions.h"
30 #include "insn-flags.h"
31 #include "output.h"
32 #include "insn-attr.h"
33 #include "flags.h"
34 #include "recog.h"
35 #include "toplev.h"
36 #include "obstack.h"
37 #include "tree.h"
38 #include "expr.h"
39 #include "optabs.h"
40 #include "output.h"
41 #include "except.h"
42 #include "function.h"
43 #include "target.h"
44 #include "target-def.h"
45 #include "tm_p.h"
46
47 static rtx emit_addhi3_postreload PARAMS ((rtx, rtx, rtx));
48
49 /* Define the information needed to generate branch and scc insns.  This is
50    stored from the compare operation.  */
51 struct rtx_def * stormy16_compare_op0;
52 struct rtx_def * stormy16_compare_op1;
53
54 /* Return 1 if this is a LT, GE, LTU, or GEU operator.  */
55
56 int
57 stormy16_ineqsi_operator (op, mode)
58     register rtx op;
59     enum machine_mode mode;
60 {
61   enum rtx_code code = GET_CODE (op);
62   
63   return ((mode == VOIDmode || GET_MODE (op) == mode)
64           && (code == LT || code == GE || code == LTU || code == GEU));
65 }
66
67 /* Return 1 if this is an EQ or NE operator.  */
68
69 int
70 equality_operator (op, mode)
71     register rtx op;
72     enum machine_mode mode;
73 {
74   return ((mode == VOIDmode || GET_MODE (op) == mode)
75           && (GET_CODE (op) == EQ || GET_CODE (op) == NE));
76 }
77
78 /* Return 1 if this is a comparison operator but not an EQ or NE operator.  */
79
80 int
81 inequality_operator (op, mode)
82     register rtx op;
83     enum machine_mode mode;
84 {
85   return comparison_operator (op, mode) && ! equality_operator (op, mode);
86 }
87
88 /* Branches are handled as follows:
89
90    1. HImode compare-and-branches.  The machine supports these
91       natively, so the appropriate pattern is emitted directly.
92
93    2. SImode EQ and NE.  These are emitted as pairs of HImode
94       compare-and-branches.      
95
96    3. SImode LT, GE, LTU and GEU.  These are emitted as a sequence
97       of a SImode subtract followed by a branch (not a compare-and-branch),
98       like this:
99       sub
100       sbc
101       blt
102
103    4. SImode GT, LE, GTU, LEU.  These are emitted as a sequence like:
104       sub
105       sbc
106       blt
107       or
108       bne
109 */
110
111 /* Emit a branch of kind CODE to location LOC.  */
112
113 void
114 stormy16_emit_cbranch (code, loc)
115      enum rtx_code code;
116      rtx loc;
117 {
118   rtx op0 = stormy16_compare_op0;
119   rtx op1 = stormy16_compare_op1;
120   rtx condition_rtx, loc_ref, branch, cy_clobber;
121   rtvec vec;
122   enum machine_mode mode;
123   
124   mode = GET_MODE (op0);
125   if (mode != HImode && mode != SImode)
126     abort ();
127
128   if (mode == SImode
129       && (code == GT || code == LE || code == GTU || code == LEU))
130     {
131       int unsigned_p = (code == GTU || code == LEU);
132       int gt_p = (code == GT || code == GTU);
133       rtx lab;
134       
135       if (gt_p)
136         lab = gen_label_rtx ();
137       stormy16_emit_cbranch (unsigned_p ? LTU : LT, gt_p ? lab : loc);
138       /* This should be generated as a comparison against the temporary
139          created by the previous insn, but reload can't handle that.  */
140       stormy16_emit_cbranch (gt_p ? NE : EQ, loc);
141       if (gt_p)
142         emit_label (lab);
143       return;
144     }
145   else if (mode == SImode 
146            && (code == NE || code == EQ)
147            && op1 != const0_rtx)
148     {
149       rtx lab;
150       int num_words = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
151       int i;
152       
153       if (code == EQ)
154         lab = gen_label_rtx ();
155       
156       for (i = 0; i < num_words - 1; i++)
157         {
158           stormy16_compare_op0 = simplify_gen_subreg (word_mode, op0, mode, 
159                                                       i * UNITS_PER_WORD);
160           stormy16_compare_op1 = simplify_gen_subreg (word_mode, op1, mode, 
161                                                       i * UNITS_PER_WORD);
162           stormy16_emit_cbranch (NE, code == EQ ? lab : loc);
163         }
164       stormy16_compare_op0 = simplify_gen_subreg (word_mode, op0, mode, 
165                                                   i * UNITS_PER_WORD);
166       stormy16_compare_op1 = simplify_gen_subreg (word_mode, op1, mode, 
167                                                   i * UNITS_PER_WORD);
168       stormy16_emit_cbranch (code, loc);
169
170       if (code == EQ)
171         emit_label (lab);
172       return;
173     }
174
175   /* We can't allow reload to try to generate any reload after a branch,
176      so when some register must match we must make the temporary ourselves.  */
177   if (mode != HImode)
178     {
179       rtx tmp;
180       tmp = gen_reg_rtx (mode);
181       emit_move_insn (tmp, op0);
182       op0 = tmp;
183     }
184
185   condition_rtx = gen_rtx (code, mode, op0, op1);
186   loc_ref = gen_rtx_LABEL_REF (VOIDmode, loc);
187   branch = gen_rtx_SET (VOIDmode, pc_rtx,
188                         gen_rtx_IF_THEN_ELSE (VOIDmode, condition_rtx,
189                                               loc_ref, pc_rtx));
190
191   cy_clobber = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (BImode));
192
193   if (mode == HImode)
194     vec = gen_rtvec (2, branch, cy_clobber);
195   else if (code == NE || code == EQ)
196     vec = gen_rtvec (2, branch, gen_rtx_CLOBBER (VOIDmode, op0));
197   else
198     {
199       rtx sub;
200 #if 0
201       sub = gen_rtx_SET (VOIDmode, op0, gen_rtx_MINUS (SImode, op0, op1));
202 #else
203       sub = gen_rtx_CLOBBER (SImode, op0);
204 #endif
205       vec = gen_rtvec (3, branch, sub, cy_clobber);
206     }
207
208   emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec));
209 }
210
211 /* Take a SImode conditional branch, one of GT/LE/GTU/LEU, and split
212    the arithmetic operation.  Most of the work is done by
213    stormy16_expand_arith.  */
214
215 void
216 stormy16_split_cbranch (mode, label, comparison, dest, carry)
217      enum machine_mode mode;
218      rtx label;
219      rtx comparison;
220      rtx dest;
221      rtx carry;
222 {
223   rtx op0 = XEXP (comparison, 0);
224   rtx op1 = XEXP (comparison, 1);
225   rtx seq;
226   rtx compare;
227   
228   start_sequence ();
229   stormy16_expand_arith (mode, COMPARE, dest, op0, op1, carry);
230   seq = gen_sequence ();
231   end_sequence ();
232   compare = SET_SRC (XVECEXP (PATTERN (XVECEXP (seq, 0, XVECLEN (seq, 0) - 1)),
233                               0, 0));
234   PUT_CODE (XEXP (compare, 0), GET_CODE (comparison));
235   XEXP (compare, 1) = gen_rtx_LABEL_REF (VOIDmode, label);
236   emit_insn (seq);
237 }
238
239
240 /* Return the string to output a conditional branch to LABEL, which is
241    the operand number of the label.
242
243    OP is the conditional expression, or NULL for branch-always.
244
245    REVERSED is non-zero if we should reverse the sense of the comparison.
246
247    INSN is the insn.  */
248
249 char *
250 stormy16_output_cbranch_hi (op, label, reversed, insn)
251      rtx op;
252      const char * label;
253      int reversed;
254      rtx insn;
255 {
256   static char string[64];
257   int need_longbranch = (op != NULL_RTX
258                          ? get_attr_length (insn) == 8
259                          : get_attr_length (insn) == 4);
260   int really_reversed = reversed ^ need_longbranch;
261   const char *ccode;
262   const char *template;
263   const char *operands;
264   enum rtx_code code;
265   
266   if (! op)
267     {
268       if (need_longbranch)
269         ccode = "jmpf";
270       else
271         ccode = "br";
272       sprintf (string, "%s %s", ccode, label);
273       return string;
274     }
275
276   code = GET_CODE (op);
277
278   if (GET_CODE (XEXP (op, 0)) != REG)
279     {
280       code = swap_condition (code);
281       operands = "%3,%2";
282     }
283   else
284       operands = "%2,%3";
285
286   /* Work out which way this really branches.  */
287   if (really_reversed)
288     code = reverse_condition (code);
289
290   switch (code)
291     {
292     case EQ:   ccode = "z";   break;
293     case NE:   ccode = "nz";  break;
294     case GE:   ccode = "ge";  break;
295     case LT:   ccode = "lt";  break;
296     case GT:   ccode = "gt";  break;
297     case LE:   ccode = "le";  break;
298     case GEU:  ccode = "nc";  break;
299     case LTU:  ccode = "c";   break;
300     case GTU:  ccode = "hi";  break;
301     case LEU:  ccode = "ls";  break;
302       
303     default:
304       abort ();
305     }
306
307   if (need_longbranch)
308     template = "b%s %s,.+8 | jmpf %s";
309   else
310     template = "b%s %s,%s";
311   sprintf (string, template, ccode, operands, label);
312   
313   return string;
314 }
315
316 /* Return the string to output a conditional branch to LABEL, which is
317    the operand number of the label, but suitable for the tail of a
318    SImode branch.
319
320    OP is the conditional expression (OP is never NULL_RTX).
321
322    REVERSED is non-zero if we should reverse the sense of the comparison.
323
324    INSN is the insn.  */
325
326 char *
327 stormy16_output_cbranch_si (op, label, reversed, insn)
328      rtx op;
329      const char * label;
330      int reversed;
331      rtx insn;
332 {
333   static char string[64];
334   int need_longbranch = get_attr_length (insn) >= 8;
335   int really_reversed = reversed ^ need_longbranch;
336   const char *ccode;
337   const char *template;
338   char prevop[16];
339   enum rtx_code code;
340   
341   code = GET_CODE (op);
342
343   /* Work out which way this really branches.  */
344   if (really_reversed)
345     code = reverse_condition (code);
346
347   switch (code)
348     {
349     case EQ:   ccode = "z";   break;
350     case NE:   ccode = "nz";  break;
351     case GE:   ccode = "ge";  break;
352     case LT:   ccode = "lt";  break;
353     case GEU:  ccode = "nc";  break;
354     case LTU:  ccode = "c";   break;
355
356       /* The missing codes above should never be generated.  */
357     default:
358       abort ();
359     }
360
361   switch (code)
362     {
363     case EQ: case NE:
364       {
365         int regnum;
366         
367         if (GET_CODE (XEXP (op, 0)) != REG)
368           abort ();
369       
370         regnum = REGNO (XEXP (op, 0));
371         sprintf (prevop, "or %s,%s", reg_names[regnum], reg_names[regnum+1]);
372       }
373       break;
374
375     case GE: case LT: case GEU: case LTU:
376       strcpy (prevop, "sbc %2,%3");
377       break;
378
379     default:
380       abort ();
381     }
382
383   if (need_longbranch)
384     template = "%s | b%s .+6 | jmpf %s";
385   else
386     template = "%s | b%s %s";
387   sprintf (string, template, prevop, ccode, label);
388   
389   return string;
390 }
391 \f
392 /* Many machines have some registers that cannot be copied directly to or from
393    memory or even from other types of registers.  An example is the `MQ'
394    register, which on most machines, can only be copied to or from general
395    registers, but not memory.  Some machines allow copying all registers to and
396    from memory, but require a scratch register for stores to some memory
397    locations (e.g., those with symbolic address on the RT, and those with
398    certain symbolic address on the Sparc when compiling PIC).  In some cases,
399    both an intermediate and a scratch register are required.
400
401    You should define these macros to indicate to the reload phase that it may
402    need to allocate at least one register for a reload in addition to the
403    register to contain the data.  Specifically, if copying X to a register
404    CLASS in MODE requires an intermediate register, you should define
405    `SECONDARY_INPUT_RELOAD_CLASS' to return the largest register class all of
406    whose registers can be used as intermediate registers or scratch registers.
407
408    If copying a register CLASS in MODE to X requires an intermediate or scratch
409    register, `SECONDARY_OUTPUT_RELOAD_CLASS' should be defined to return the
410    largest register class required.  If the requirements for input and output
411    reloads are the same, the macro `SECONDARY_RELOAD_CLASS' should be used
412    instead of defining both macros identically.
413
414    The values returned by these macros are often `GENERAL_REGS'.  Return
415    `NO_REGS' if no spare register is needed; i.e., if X can be directly copied
416    to or from a register of CLASS in MODE without requiring a scratch register.
417    Do not define this macro if it would always return `NO_REGS'.
418
419    If a scratch register is required (either with or without an intermediate
420    register), you should define patterns for `reload_inM' or `reload_outM', as
421    required..  These patterns, which will normally be implemented with a
422    `define_expand', should be similar to the `movM' patterns, except that
423    operand 2 is the scratch register.
424
425    Define constraints for the reload register and scratch register that contain
426    a single register class.  If the original reload register (whose class is
427    CLASS) can meet the constraint given in the pattern, the value returned by
428    these macros is used for the class of the scratch register.  Otherwise, two
429    additional reload registers are required.  Their classes are obtained from
430    the constraints in the insn pattern.
431
432    X might be a pseudo-register or a `subreg' of a pseudo-register, which could
433    either be in a hard register or in memory.  Use `true_regnum' to find out;
434    it will return -1 if the pseudo is in memory and the hard register number if
435    it is in a register.
436
437    These macros should not be used in the case where a particular class of
438    registers can only be copied to memory and not to another class of
439    registers.  In that case, secondary reload registers are not needed and
440    would not be helpful.  Instead, a stack location must be used to perform the
441    copy and the `movM' pattern should use memory as a intermediate storage.
442    This case often occurs between floating-point and general registers.  */
443
444 enum reg_class
445 stormy16_secondary_reload_class (class, mode, x)
446      enum reg_class class;
447      enum machine_mode mode;
448      rtx x;
449 {
450   /* This chip has the interesting property that only the first eight
451      registers can be moved to/from memory.  */
452   if ((GET_CODE (x) == MEM
453        || ((GET_CODE (x) == SUBREG || GET_CODE (x) == REG)
454            && (true_regnum (x) == -1
455                || true_regnum (x) >= FIRST_PSEUDO_REGISTER)))
456       && ! reg_class_subset_p (class, EIGHT_REGS))
457     return EIGHT_REGS;
458
459   /* When reloading a PLUS, the carry register will be required
460      unless the inc or dec instructions can be used.  */
461   if (stormy16_carry_plus_operand (x, mode))
462     return CARRY_REGS;
463
464   return NO_REGS;
465 }
466
467 /* Recognise a PLUS that needs the carry register.  */
468 int
469 stormy16_carry_plus_operand (x, mode)
470      rtx x;
471      enum machine_mode mode ATTRIBUTE_UNUSED;
472 {
473   return (GET_CODE (x) == PLUS
474           && GET_CODE (XEXP (x, 1)) == CONST_INT
475           && (INTVAL (XEXP (x, 1)) < -4 || INTVAL (XEXP (x, 1)) > 4));
476 }
477
478
479 enum reg_class
480 stormy16_preferred_reload_class (x, class)
481      enum reg_class class;
482      rtx x;
483 {
484   if (class == GENERAL_REGS
485       && GET_CODE (x) == MEM)
486     return EIGHT_REGS;
487
488   return class;
489 }
490
491 #define LEGITIMATE_ADDRESS_INTEGER_P(X, OFFSET)                         \
492  (GET_CODE (X) == CONST_INT                                             \
493   && (unsigned HOST_WIDE_INT) (INTVAL (X) + (OFFSET) + 2048) < 4096)
494
495 #define LEGITIMATE_ADDRESS_CONST_INT_P(X, OFFSET)                        \
496  (GET_CODE (X) == CONST_INT                                              \
497   && INTVAL (X) + (OFFSET) >= 0                                          \
498   && INTVAL (X) + (OFFSET) < 0x8000                                      \
499   && (INTVAL (X) + (OFFSET) < 0x100 || INTVAL (X) + (OFFSET) >= 0x7F00))
500
501 int
502 stormy16_legitimate_address_p (mode, x, strict)
503      enum machine_mode mode ATTRIBUTE_UNUSED;
504      rtx x;
505      int strict;
506 {
507   if (LEGITIMATE_ADDRESS_CONST_INT_P (x, 0))
508     return 1;
509
510   if (GET_CODE (x) == PLUS
511       && LEGITIMATE_ADDRESS_INTEGER_P (XEXP (x, 1), 0))
512     x = XEXP (x, 0);
513   
514   if (GET_CODE (x) == POST_INC
515       || GET_CODE (x) == PRE_DEC)
516     x = XEXP (x, 0);
517   
518   if (GET_CODE (x) == REG && REGNO_OK_FOR_BASE_P (REGNO (x))
519       && (! strict || REGNO (x) < FIRST_PSEUDO_REGISTER))
520     return 1;
521   
522   return 0;
523 }
524
525 /* Return nonzero if memory address X (an RTX) can have different
526    meanings depending on the machine mode of the memory reference it
527    is used for or if the address is valid for some modes but not
528    others.
529
530    Autoincrement and autodecrement addresses typically have mode-dependent
531    effects because the amount of the increment or decrement is the size of the
532    operand being addressed.  Some machines have other mode-dependent addresses.
533    Many RISC machines have no mode-dependent addresses.
534
535    You may assume that ADDR is a valid address for the machine.  
536    
537    On this chip, this is true if the address is valid with an offset
538    of 0 but not of 6, because in that case it cannot be used as an
539    address for DImode or DFmode, or if the address is a post-increment
540    or pre-decrement address.  */
541 int
542 stormy16_mode_dependent_address_p (x)
543      rtx x;
544 {
545   if (LEGITIMATE_ADDRESS_CONST_INT_P (x, 0)
546       && ! LEGITIMATE_ADDRESS_CONST_INT_P (x, 6))
547     return 1;
548   
549   if (GET_CODE (x) == PLUS
550       && LEGITIMATE_ADDRESS_INTEGER_P (XEXP (x, 1), 0)
551       && ! LEGITIMATE_ADDRESS_INTEGER_P (XEXP (x, 1), 6))
552     return 1;
553
554   if (GET_CODE (x) == PLUS)
555     x = XEXP (x, 0);
556
557   if (GET_CODE (x) == POST_INC
558       || GET_CODE (x) == PRE_DEC)
559     return 1;
560
561   return 0;
562 }
563
564 /* A C expression that defines the optional machine-dependent constraint
565    letters (`Q', `R', `S', `T', `U') that can be used to segregate specific
566    types of operands, usually memory references, for the target machine.
567    Normally this macro will not be defined.  If it is required for a particular
568    target machine, it should return 1 if VALUE corresponds to the operand type
569    represented by the constraint letter C.  If C is not defined as an extra
570    constraint, the value returned should be 0 regardless of VALUE.  */
571 int
572 stormy16_extra_constraint_p (x, c)
573      rtx x;
574      int c;
575 {
576   switch (c)
577     {
578       /* 'Q' is for pushes.  */
579     case 'Q':
580       return (GET_CODE (x) == MEM
581               && GET_CODE (XEXP (x, 0)) == POST_INC
582               && XEXP (XEXP (x, 0), 0) == stack_pointer_rtx);
583
584       /* 'R' is for pops.  */
585     case 'R':
586       return (GET_CODE (x) == MEM
587               && GET_CODE (XEXP (x, 0)) == PRE_DEC
588               && XEXP (XEXP (x, 0), 0) == stack_pointer_rtx);
589
590       /* 'S' is for immediate memory addresses.  */
591     case 'S':
592       return (GET_CODE (x) == MEM
593               && GET_CODE (XEXP (x, 0)) == CONST_INT
594               && stormy16_legitimate_address_p (VOIDmode, XEXP (x, 0), 0));
595
596       /* 'T' is for Rx.  */
597     case 'T':
598       /* Not implemented yet.  */
599       return 0;
600
601       /* 'U' is for CONST_INT values not between 2 and 15 inclusive,
602          for allocating a scratch register for 32-bit shifts.  */
603     case 'U':
604       return (GET_CODE (x) == CONST_INT
605               && (INTVAL (x) < 2 || INTVAL (x) > 15));
606
607     default:
608       return 0;
609     }
610 }
611
612 int
613 short_memory_operand (x, mode)
614      rtx x;
615      enum machine_mode mode;
616 {
617   if (! memory_operand (x, mode))
618     return 0;
619   return (GET_CODE (XEXP (x, 0)) != PLUS);
620 }
621
622 /* Splitter for the 'move' patterns, for modes not directly implemeted
623    by hardware.  Emit insns to copy a value of mode MODE from SRC to
624    DEST.
625
626    This function is only called when reload_completed.
627    */
628
629 void 
630 stormy16_split_move (mode, dest, src)
631      enum machine_mode mode;
632      rtx dest;
633      rtx src;
634 {
635   int num_words = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
636   int direction, end, i;
637   int src_modifies = 0;
638   int dest_modifies = 0;
639   int src_volatile = 0;
640   int dest_volatile = 0;
641   rtx mem_operand;
642   
643   /* Check initial conditions.  */
644   if (! reload_completed
645       || mode == QImode || mode == HImode
646       || ! nonimmediate_operand (dest, mode)
647       || ! general_operand (src, mode))
648     abort ();
649
650   /* This case is not supported below, and shouldn't be generated.  */
651   if (GET_CODE (dest) == MEM
652       && GET_CODE (src) == MEM)
653     abort ();
654
655   /* This case is very very bad after reload, so trap it now.  */
656   if (GET_CODE (dest) == SUBREG
657       || GET_CODE (src) == SUBREG)
658     abort ();
659
660   /* The general idea is to copy by words, offsetting the source and
661      destination.  Normally the least-significant word will be copied
662      first, but for pre-dec operations it's better to copy the 
663      most-significant word first.  Only one operand can be a pre-dec
664      or post-inc operand.  
665
666      It's also possible that the copy overlaps so that the direction
667      must be reversed.  */
668   direction = 1;
669   
670   if (GET_CODE (dest) == MEM)
671     {
672       mem_operand = XEXP (dest, 0);
673       dest_modifies = side_effects_p (mem_operand);
674       dest_volatile = MEM_VOLATILE_P (dest);
675       if (dest_volatile)
676         {
677           dest = copy_rtx (dest);
678           MEM_VOLATILE_P (dest) = 0;
679         }
680     }
681   else if (GET_CODE (src) == MEM)
682     {
683       mem_operand = XEXP (src, 0);
684       src_modifies = side_effects_p (mem_operand);
685       src_volatile = MEM_VOLATILE_P (src);
686       if (src_volatile)
687         {
688           src = copy_rtx (src);
689           MEM_VOLATILE_P (src) = 0;
690         }
691     }
692   else
693     mem_operand = NULL_RTX;
694
695   if (mem_operand == NULL_RTX)
696     {
697       if (GET_CODE (src) == REG
698           && GET_CODE (dest) == REG
699           && reg_overlap_mentioned_p (dest, src)
700           && REGNO (dest) > REGNO (src))
701         direction = -1;
702     }
703   else if (GET_CODE (mem_operand) == PRE_DEC
704       || (GET_CODE (mem_operand) == PLUS 
705           && GET_CODE (XEXP (mem_operand, 0)) == PRE_DEC))
706     direction = -1;
707   else if (GET_CODE (src) == MEM
708            && reg_overlap_mentioned_p (dest, src))
709     {
710       int regno;
711       if (GET_CODE (dest) != REG)
712         abort ();
713       regno = REGNO (dest);
714       
715       if (! refers_to_regno_p (regno, regno + num_words, mem_operand, 0))
716         abort ();
717       
718       if (refers_to_regno_p (regno, regno + 1, mem_operand, 0))
719         direction = -1;
720       else if (refers_to_regno_p (regno + num_words - 1, regno + num_words,
721                                   mem_operand, 0))
722         direction = 1;
723       else
724         /* This means something like
725            (set (reg:DI r0) (mem:DI (reg:HI r1)))
726            which we'd need to support by doing the set of the second word
727            last.  */
728         abort ();
729     }
730
731   end = direction < 0 ? -1 : num_words;
732   for (i = direction < 0 ? num_words - 1 : 0; i != end; i += direction)
733     {
734       rtx w_src, w_dest;
735       if (src_modifies)
736         w_src = gen_rtx_MEM (word_mode, mem_operand);
737       else
738         w_src = simplify_gen_subreg (word_mode, src, mode, i * UNITS_PER_WORD);
739       if (src_volatile)
740         MEM_VOLATILE_P (w_src) = 1;
741       if (dest_modifies)
742         w_dest = gen_rtx_MEM (word_mode, mem_operand);
743       else
744         w_dest = simplify_gen_subreg (word_mode, dest, mode, 
745                                       i * UNITS_PER_WORD);
746       if (dest_volatile)
747         MEM_VOLATILE_P (w_dest) = 1;
748       
749       /* The simplify_subreg calls must always be able to simplify.  */
750       if (GET_CODE (w_src) == SUBREG
751           || GET_CODE (w_dest) == SUBREG)
752         abort ();
753       
754       emit_insn (gen_rtx_SET (VOIDmode, w_dest, w_src));
755     }
756 }
757
758 /* Expander for the 'move' patterns.  Emit insns to copy a value of
759    mode MODE from SRC to DEST.  */
760
761 void 
762 stormy16_expand_move (mode, dest, src)
763      enum machine_mode mode;
764      rtx dest;
765      rtx src;
766 {
767   /* There are only limited immediate-to-memory move instructions.  */
768   if (! reload_in_progress
769       && ! reload_completed
770       && GET_CODE (dest) == MEM
771       && (GET_CODE (XEXP (dest, 0)) != CONST_INT
772           || ! stormy16_legitimate_address_p (mode, XEXP (dest, 0), 0))
773       && GET_CODE (src) != REG
774       && GET_CODE (src) != SUBREG)
775     src = copy_to_mode_reg (mode, src);
776
777   /* Don't emit something we would immediately split.  */
778   if (reload_completed
779       && mode != HImode && mode != QImode)
780     {
781       stormy16_split_move (mode, dest, src);
782       return;
783     }
784   
785   emit_insn (gen_rtx_SET (VOIDmode, dest, src));
786 }
787
788 \f
789 /* Stack Layout:
790
791    The stack is laid out as follows:
792
793 SP->
794 FP->    Local variables
795         Register save area (up to 4 words)
796         Argument register save area for stdarg (NUM_ARGUMENT_REGISTERS words)
797
798 AP->    Return address (two words)
799         9th procedure parameter word
800         10th procedure parameter word
801         ...
802         last procedure parameter word
803
804   The frame pointer location is tuned to make it most likely that all
805   parameters and local variables can be accessed using a load-indexed
806   instruction.  */
807
808 /* A structure to describe the layout.  */
809 struct stormy16_stack_layout
810 {
811   /* Size of the topmost three items on the stack.  */
812   int locals_size;
813   int register_save_size;
814   int stdarg_save_size;
815   /* Sum of the above items.  */
816   int frame_size;
817   /* Various offsets.  */
818   int first_local_minus_ap;
819   int sp_minus_fp;
820   int fp_minus_ap;
821 };
822
823 /* Does REGNO need to be saved?  */
824 #define REG_NEEDS_SAVE(REGNUM, IFUN)                                    \
825   ((regs_ever_live[REGNUM] && ! call_used_regs[REGNUM])                 \
826    || (IFUN && ! fixed_regs[REGNUM] && call_used_regs[REGNUM]           \
827        && (regs_ever_live[REGNUM] || ! current_function_is_leaf)))
828
829 /* Compute the stack layout.  */
830 struct stormy16_stack_layout 
831 stormy16_compute_stack_layout ()
832 {
833   struct stormy16_stack_layout layout;
834   int regno;
835   const int ifun = stormy16_interrupt_function_p ();
836
837   layout.locals_size = get_frame_size ();
838   
839   layout.register_save_size = 0;
840   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
841     if (REG_NEEDS_SAVE (regno, ifun))
842       layout.register_save_size += UNITS_PER_WORD;
843   
844   if (current_function_varargs || current_function_stdarg)
845     layout.stdarg_save_size = NUM_ARGUMENT_REGISTERS * UNITS_PER_WORD;
846   else
847     layout.stdarg_save_size = 0;
848   
849   layout.frame_size = (layout.locals_size 
850                        + layout.register_save_size 
851                        + layout.stdarg_save_size);
852   
853   if (current_function_args_size <= 2048 && current_function_args_size != -1)
854     {
855       if (layout.frame_size + INCOMING_FRAME_SP_OFFSET 
856           + current_function_args_size <= 2048)
857         layout.fp_minus_ap = layout.frame_size + INCOMING_FRAME_SP_OFFSET;
858       else
859         layout.fp_minus_ap = 2048 - current_function_args_size;
860     }
861   else
862     layout.fp_minus_ap = (layout.stdarg_save_size 
863                           + layout.register_save_size
864                           + INCOMING_FRAME_SP_OFFSET);
865   layout.sp_minus_fp = (layout.frame_size + INCOMING_FRAME_SP_OFFSET 
866                         - layout.fp_minus_ap);
867   layout.first_local_minus_ap = layout.sp_minus_fp - layout.locals_size;
868   return layout;
869 }
870
871 /* Determine how all the special registers get eliminated.  */
872 int
873 stormy16_initial_elimination_offset (from, to)
874      int from, to;
875 {
876   struct stormy16_stack_layout layout;
877   int result;
878   
879   layout = stormy16_compute_stack_layout ();
880
881   if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
882     result = layout.sp_minus_fp - layout.locals_size;
883   else if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
884     result = -layout.locals_size;
885   else if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
886     result = -layout.fp_minus_ap;
887   else if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
888     result = -(layout.sp_minus_fp + layout.fp_minus_ap);
889   else
890     abort ();
891
892   return result;
893 }
894
895 static rtx
896 emit_addhi3_postreload (dest, src0, src1)
897      rtx dest;
898      rtx src0;
899      rtx src1;
900 {
901   rtx set, clobber, insn;
902   
903   set = gen_rtx_SET (VOIDmode, dest, gen_rtx_PLUS (HImode, src0, src1));
904   clobber = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (BImode, 16));
905   insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, set, clobber)));
906   return insn;
907 }
908
909 /* Called after register allocation to add any instructions needed for the
910    prologue.  Using a prologue insn is favored compared to putting all of the
911    instructions in the FUNCTION_PROLOGUE macro, since it allows the scheduler
912    to intermix instructions with the saves of the caller saved registers.  In
913    some cases, it might be necessary to emit a barrier instruction as the last
914    insn to prevent such scheduling.
915
916    Also any insns generated here should have RTX_FRAME_RELATED_P(insn) = 1
917    so that the debug info generation code can handle them properly.  */
918 void
919 stormy16_expand_prologue ()
920 {
921   struct stormy16_stack_layout layout;
922   int regno;
923   rtx insn;
924   rtx mem_push_rtx;
925   rtx mem_fake_push_rtx;
926   const int ifun = stormy16_interrupt_function_p ();
927   
928   mem_push_rtx = gen_rtx_POST_INC (Pmode, stack_pointer_rtx);
929   mem_push_rtx = gen_rtx_MEM (HImode, mem_push_rtx);
930   mem_fake_push_rtx = gen_rtx_PRE_INC (Pmode, stack_pointer_rtx);
931   mem_fake_push_rtx = gen_rtx_MEM (HImode, mem_fake_push_rtx);
932     
933   layout = stormy16_compute_stack_layout ();
934
935   /* Save the argument registers if necessary.  */
936   if (layout.stdarg_save_size)
937     for (regno = FIRST_ARGUMENT_REGISTER; 
938          regno < FIRST_ARGUMENT_REGISTER + NUM_ARGUMENT_REGISTERS;
939          regno++)
940       {
941         rtx reg = gen_rtx_REG (HImode, regno);
942         insn = emit_move_insn (mem_push_rtx, reg);
943         RTX_FRAME_RELATED_P (insn) = 1;
944         REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
945                                               gen_rtx_SET (VOIDmode,
946                                                            mem_fake_push_rtx,
947                                                            reg),
948                                               REG_NOTES (insn));
949       }
950   
951   /* Push each of the registers to save.  */
952   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
953     if (REG_NEEDS_SAVE (regno, ifun))
954       {
955         rtx reg = gen_rtx_REG (HImode, regno);
956         insn = emit_move_insn (mem_push_rtx, reg);
957         RTX_FRAME_RELATED_P (insn) = 1;
958         REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
959                                               gen_rtx_SET (VOIDmode,
960                                                            mem_fake_push_rtx,
961                                                            reg),
962                                               REG_NOTES (insn));
963       }
964
965   /* It's just possible that the SP here might be what we need for
966      the new FP... */
967   if (frame_pointer_needed && layout.sp_minus_fp == layout.locals_size)
968     {
969       insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
970       RTX_FRAME_RELATED_P (insn) = 1;
971     }
972
973   /* Allocate space for local variables.  */
974   if (layout.locals_size)
975     {
976       insn = emit_addhi3_postreload (stack_pointer_rtx, stack_pointer_rtx,
977                                      GEN_INT (layout.locals_size));
978       RTX_FRAME_RELATED_P (insn) = 1;
979     }
980
981   /* Set up the frame pointer, if required.  */
982   if (frame_pointer_needed && layout.sp_minus_fp != layout.locals_size)
983     {
984       insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
985       RTX_FRAME_RELATED_P (insn) = 1;
986       if (layout.sp_minus_fp)
987         {
988           insn = emit_addhi3_postreload (hard_frame_pointer_rtx,
989                                          hard_frame_pointer_rtx,
990                                          GEN_INT (-layout.sp_minus_fp));
991           RTX_FRAME_RELATED_P (insn) = 1;
992         }
993     }
994 }
995
996 /* Do we need an epilogue at all?  */
997 int
998 direct_return ()
999 {
1000   return (reload_completed 
1001           && stormy16_compute_stack_layout ().frame_size == 0);
1002 }
1003
1004 /* Called after register allocation to add any instructions needed for the
1005    epilogue.  Using a epilogue insn is favored compared to putting all of the
1006    instructions in the FUNCTION_PROLOGUE macro, since it allows the scheduler
1007    to intermix instructions with the saves of the caller saved registers.  In
1008    some cases, it might be necessary to emit a barrier instruction as the last
1009    insn to prevent such scheduling.  */
1010
1011 void
1012 stormy16_expand_epilogue ()
1013 {
1014   struct stormy16_stack_layout layout;
1015   rtx mem_pop_rtx;
1016   int regno;
1017   const int ifun = stormy16_interrupt_function_p ();
1018   
1019   mem_pop_rtx = gen_rtx_PRE_DEC (Pmode, stack_pointer_rtx);
1020   mem_pop_rtx = gen_rtx_MEM (HImode, mem_pop_rtx);
1021   
1022   layout = stormy16_compute_stack_layout ();
1023
1024   /* Pop the stack for the locals.  */
1025   if (layout.locals_size)
1026     {
1027       if (frame_pointer_needed && layout.sp_minus_fp == layout.locals_size)
1028         emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx);
1029       else
1030         emit_addhi3_postreload (stack_pointer_rtx, stack_pointer_rtx,
1031                                 GEN_INT (- layout.locals_size));
1032     }
1033
1034   /* Restore any call-saved registers.  */
1035   for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--)
1036     if (REG_NEEDS_SAVE (regno, ifun))
1037       emit_move_insn (gen_rtx_REG (HImode, regno), mem_pop_rtx);
1038   
1039   /* Pop the stack for the stdarg save area.  */
1040   if (layout.stdarg_save_size)
1041     emit_addhi3_postreload (stack_pointer_rtx, stack_pointer_rtx,
1042                             GEN_INT (- layout.stdarg_save_size));
1043
1044   /* Return.  */
1045   if (ifun)
1046     emit_jump_insn (gen_return_internal_interrupt ());
1047   else
1048     emit_jump_insn (gen_return_internal ());
1049 }
1050
1051 int
1052 stormy16_epilogue_uses (regno)
1053      int regno;
1054 {
1055   if (reload_completed && call_used_regs[regno])
1056     {
1057       const int ifun = stormy16_interrupt_function_p ();
1058       return REG_NEEDS_SAVE (regno, ifun);
1059     }
1060   return 0;
1061 }
1062 \f
1063 /* Return an updated summarizer variable CUM to advance past an
1064    argument in the argument list.  The values MODE, TYPE and NAMED
1065    describe that argument.  Once this is done, the variable CUM is
1066    suitable for analyzing the *following* argument with
1067    `FUNCTION_ARG', etc.
1068
1069    This function need not do anything if the argument in question was
1070    passed on the stack.  The compiler knows how to track the amount of
1071    stack space used for arguments without any special help.  However,
1072    it makes life easier for stormy16_build_va_list if it does update
1073    the word count.  */
1074 CUMULATIVE_ARGS
1075 stormy16_function_arg_advance (cum, mode, type, named)
1076      CUMULATIVE_ARGS cum;
1077      enum machine_mode mode;
1078      tree type;
1079      int named ATTRIBUTE_UNUSED;
1080 {
1081   /* If an argument would otherwise be passed partially in registers,
1082      and partially on the stack, the whole of it is passed on the
1083      stack.  */
1084   if (cum < NUM_ARGUMENT_REGISTERS
1085       && cum + STORMY16_WORD_SIZE (type, mode) > NUM_ARGUMENT_REGISTERS)
1086     cum = NUM_ARGUMENT_REGISTERS;
1087   
1088   cum += STORMY16_WORD_SIZE (type, mode);
1089   
1090   return cum;
1091 }
1092
1093 /* Do any needed setup for a variadic function.  CUM has not been updated
1094    for the last named argument which has type TYPE and mode MODE.  */
1095 void
1096 stormy16_setup_incoming_varargs (cum, int_mode, type, pretend_size)
1097      CUMULATIVE_ARGS cum ATTRIBUTE_UNUSED;
1098      int             int_mode ATTRIBUTE_UNUSED;
1099      tree            type ATTRIBUTE_UNUSED;
1100      int *           pretend_size ATTRIBUTE_UNUSED;
1101 {
1102 }
1103
1104 /* Build the va_list type.
1105
1106    For this chip, va_list is a record containing a counter and a pointer.
1107    The counter is of type 'int' and indicates how many bytes
1108    have been used to date.  The pointer indicates the stack position
1109    for arguments that have not been passed in registers.  
1110    To keep the layout nice, the pointer is first in the structure.  */
1111
1112 tree
1113 stormy16_build_va_list ()
1114 {
1115   tree f_1, f_2, record, type_decl;
1116
1117   record = make_lang_type (RECORD_TYPE);
1118   type_decl = build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record);
1119
1120   f_2 = build_decl (FIELD_DECL, get_identifier ("base"),
1121                       ptr_type_node);
1122   f_1 = build_decl (FIELD_DECL, get_identifier ("count"), 
1123                       unsigned_type_node);
1124
1125   DECL_FIELD_CONTEXT (f_1) = record;
1126   DECL_FIELD_CONTEXT (f_2) = record;
1127
1128   TREE_CHAIN (record) = type_decl;
1129   TYPE_NAME (record) = type_decl;
1130   TYPE_FIELDS (record) = f_1;
1131   TREE_CHAIN (f_1) = f_2;
1132
1133   layout_type (record);
1134
1135   return record;
1136 }
1137
1138 /* Implement the stdarg/varargs va_start macro.  STDARG_P is non-zero if this
1139    is stdarg.h instead of varargs.h.  VALIST is the tree of the va_list
1140    variable to initialize.  NEXTARG is the machine independent notion of the
1141    'next' argument after the variable arguments.  */
1142 void
1143 stormy16_expand_builtin_va_start (stdarg_p, valist, nextarg)
1144      int stdarg_p ATTRIBUTE_UNUSED;
1145      tree valist;
1146      rtx nextarg ATTRIBUTE_UNUSED;
1147 {
1148   tree f_base, f_count;
1149   tree base, count;
1150   tree t;
1151
1152   if (stormy16_interrupt_function_p ())
1153     error ("cannot use va_start in interrupt function");
1154   
1155   f_base = TYPE_FIELDS (va_list_type_node);
1156   f_count = TREE_CHAIN (f_base);
1157   
1158   base = build (COMPONENT_REF, TREE_TYPE (f_base), valist, f_base);
1159   count = build (COMPONENT_REF, TREE_TYPE (f_count), valist, f_count);
1160
1161   t = make_tree (TREE_TYPE (base), virtual_incoming_args_rtx);
1162   t = build (PLUS_EXPR, TREE_TYPE (base), t, 
1163              build_int_2 (INCOMING_FRAME_SP_OFFSET, 0));
1164   t = build (MODIFY_EXPR, TREE_TYPE (base), base, t);
1165   TREE_SIDE_EFFECTS (t) = 1;
1166   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1167
1168   t = build (MODIFY_EXPR, TREE_TYPE (count), count, 
1169              build_int_2 (current_function_args_info * UNITS_PER_WORD, 0));
1170   TREE_SIDE_EFFECTS (t) = 1;
1171   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1172 }
1173
1174 /* Implement the stdarg/varargs va_arg macro.  VALIST is the variable
1175    of type va_list as a tree, TYPE is the type passed to va_arg.  */
1176 rtx
1177 stormy16_expand_builtin_va_arg (valist, type)
1178      tree valist;
1179      tree type;
1180 {
1181   tree f_base, f_count;
1182   tree base, count;
1183   rtx count_rtx, addr_rtx, r;
1184   rtx lab_gotaddr, lab_fromstack;
1185   tree t;
1186   int size, last_reg_count;
1187   tree size_tree, count_plus_size;
1188   
1189   f_base = TYPE_FIELDS (va_list_type_node);
1190   f_count = TREE_CHAIN (f_base);
1191   
1192   base = build (COMPONENT_REF, TREE_TYPE (f_base), valist, f_base);
1193   count = build (COMPONENT_REF, TREE_TYPE (f_count), valist, f_count);
1194
1195   size = PUSH_ROUNDING (int_size_in_bytes (type));
1196   size_tree = round_up (size_in_bytes (type), UNITS_PER_WORD);
1197   
1198   last_reg_count = NUM_ARGUMENT_REGISTERS * UNITS_PER_WORD - size;
1199
1200   count_rtx = expand_expr (count, NULL_RTX, HImode, EXPAND_NORMAL);
1201   lab_gotaddr = gen_label_rtx ();
1202   lab_fromstack = gen_label_rtx ();
1203   addr_rtx = gen_reg_rtx (Pmode);
1204   emit_cmp_and_jump_insns (count_rtx, GEN_INT (last_reg_count),
1205                           GTU, const1_rtx, HImode, 1, 1, lab_fromstack);
1206   
1207   t = build (PLUS_EXPR, ptr_type_node, base, count);
1208   r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
1209   if (r != addr_rtx)
1210     emit_move_insn (addr_rtx, r);
1211
1212   emit_jump_insn (gen_jump (lab_gotaddr));
1213   emit_barrier ();
1214   emit_label (lab_fromstack);
1215   
1216   /* Arguments larger than a word might need to skip over some
1217      registers, since arguments are either passed entirely in
1218      registers or entirely on the stack.  */
1219   if (size > 2 || size < 0)
1220     {
1221       rtx lab_notransition = gen_label_rtx ();
1222       emit_cmp_and_jump_insns (count_rtx, GEN_INT (NUM_ARGUMENT_REGISTERS 
1223                                                    * UNITS_PER_WORD),
1224                                GEU, const1_rtx, HImode, 1, 1, 
1225                                lab_notransition);
1226       
1227       t = build (MODIFY_EXPR, TREE_TYPE (count), count, 
1228                  build_int_2 (NUM_ARGUMENT_REGISTERS * UNITS_PER_WORD, 0));
1229       TREE_SIDE_EFFECTS (t) = 1;
1230       expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1231       
1232       emit_label (lab_notransition);
1233     }
1234
1235   t = build (PLUS_EXPR, sizetype, size_tree,
1236              build_int_2 ((- NUM_ARGUMENT_REGISTERS * UNITS_PER_WORD
1237                            + INCOMING_FRAME_SP_OFFSET),
1238                           -1));
1239   t = build (PLUS_EXPR, TREE_TYPE (count), count, fold (t));
1240   t = build (MINUS_EXPR, TREE_TYPE (base), base, t);
1241   r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
1242   if (r != addr_rtx)
1243     emit_move_insn (addr_rtx, r);
1244              
1245   emit_label (lab_gotaddr);
1246
1247   count_plus_size = build (PLUS_EXPR, TREE_TYPE (count), count, size_tree);
1248   t = build (MODIFY_EXPR, TREE_TYPE (count), count, count_plus_size);
1249   TREE_SIDE_EFFECTS (t) = 1;
1250   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1251
1252   return addr_rtx;
1253 }
1254
1255 /* Initialize the variable parts of a trampoline.  ADDR is an RTX for
1256    the address of the trampoline; FNADDR is an RTX for the address of
1257    the nested function; STATIC_CHAIN is an RTX for the static chain
1258    value that should be passed to the function when it is called.  */
1259 void
1260 stormy16_initialize_trampoline (addr, fnaddr, static_chain)
1261      rtx addr;
1262      rtx fnaddr;
1263      rtx static_chain;
1264 {
1265   rtx reg_addr = gen_reg_rtx (Pmode);
1266   rtx temp = gen_reg_rtx (HImode);
1267   rtx reg_fnaddr = gen_reg_rtx (HImode);
1268   rtx reg_addr_mem;
1269
1270   reg_addr_mem = gen_rtx_MEM (HImode, reg_addr);
1271     
1272   emit_move_insn (reg_addr, addr);
1273   emit_move_insn (temp, GEN_INT (0x3130 | STATIC_CHAIN_REGNUM));
1274   emit_move_insn (reg_addr_mem, temp);
1275   emit_insn (gen_addhi3 (reg_addr, reg_addr, const2_rtx));
1276   emit_move_insn (temp, static_chain);
1277   emit_move_insn (reg_addr_mem, temp);
1278   emit_insn (gen_addhi3 (reg_addr, reg_addr, const2_rtx));
1279   emit_move_insn (reg_fnaddr, fnaddr);
1280   emit_move_insn (temp, reg_fnaddr);
1281   emit_insn (gen_andhi3 (temp, temp, GEN_INT (0xFF)));
1282   emit_insn (gen_iorhi3 (temp, temp, GEN_INT (0x0200)));
1283   emit_move_insn (reg_addr_mem, temp);
1284   emit_insn (gen_addhi3 (reg_addr, reg_addr, const2_rtx));
1285   emit_insn (gen_lshrhi3 (reg_fnaddr, reg_fnaddr, GEN_INT (8)));
1286   emit_move_insn (reg_addr_mem, reg_fnaddr);
1287 }
1288
1289 /* Create an RTX representing the place where a function returns a
1290    value of data type VALTYPE.  VALTYPE is a tree node representing a
1291    data type.  Write `TYPE_MODE (VALTYPE)' to get the machine mode
1292    used to represent that type.  On many machines, only the mode is
1293    relevant.  (Actually, on most machines, scalar values are returned
1294    in the same place regardless of mode).
1295
1296    If `PROMOTE_FUNCTION_RETURN' is defined, you must apply the same promotion
1297    rules specified in `PROMOTE_MODE' if VALTYPE is a scalar type.
1298
1299    If the precise function being called is known, FUNC is a tree node
1300    (`FUNCTION_DECL') for it; otherwise, FUNC is a null pointer.  This makes it
1301    possible to use a different value-returning convention for specific
1302    functions when all their calls are known.
1303
1304    `FUNCTION_VALUE' is not used for return vales with aggregate data types,
1305    because these are returned in another way.  See `STRUCT_VALUE_REGNUM' and
1306    related macros.  */
1307 rtx
1308 stormy16_function_value (valtype, func)
1309      tree valtype;
1310      tree func ATTRIBUTE_UNUSED;
1311 {
1312   enum machine_mode mode;
1313   mode = TYPE_MODE (valtype);
1314   PROMOTE_MODE (mode, 0, valtype);
1315   return gen_rtx_REG (mode, RETURN_VALUE_REGNUM);
1316 }
1317
1318 /* Mark functions with SYMBOL_REF_FLAG.  */
1319
1320 void
1321 stormy16_encode_section_info (decl)
1322      tree decl;
1323 {
1324   if (TREE_CODE (decl) == FUNCTION_DECL)
1325     SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1;
1326 }
1327 \f
1328 /* Print a memory address as an operand to reference that memory location.  */
1329 void
1330 stormy16_print_operand_address (file, address)
1331      FILE * file;
1332      rtx    address;
1333 {
1334   HOST_WIDE_INT offset;
1335   int pre_dec, post_inc;
1336
1337   /* There are a few easy cases.  */
1338   if (GET_CODE (address) == CONST_INT)
1339     {
1340       fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (address) & 0xFFFF);
1341       return;
1342     }
1343   
1344   if (CONSTANT_P (address) || GET_CODE (address) == CODE_LABEL)
1345     {
1346       output_addr_const (file, address);
1347       return;
1348     }
1349   
1350   /* Otherwise, it's hopefully something of the form 
1351      (plus:HI (pre_dec:HI (reg:HI ...)) (const_int ...))
1352   */
1353
1354   if (GET_CODE (address) == PLUS)
1355     {
1356       if (GET_CODE (XEXP (address, 1)) != CONST_INT)
1357         abort ();
1358       offset = INTVAL (XEXP (address, 1));
1359       address = XEXP (address, 0);
1360     }
1361   else
1362     offset = 0;
1363
1364   pre_dec = (GET_CODE (address) == PRE_DEC);
1365   post_inc = (GET_CODE (address) == POST_INC);
1366   if (pre_dec || post_inc)
1367     address = XEXP (address, 0);
1368   
1369   if (GET_CODE (address) != REG)
1370     abort ();
1371
1372   fputc ('(', file);
1373   if (pre_dec)
1374     fputs ("--", file);
1375   fputs (reg_names [REGNO (address)], file);
1376   if (post_inc)
1377     fputs ("++", file);
1378   if (offset != 0)
1379     {
1380       fputc (',', file);
1381       fprintf (file, HOST_WIDE_INT_PRINT_DEC, offset);
1382     }
1383   fputc (')', file);
1384 }
1385
1386 /* Print an operand to a assembler instruction.  */
1387 void
1388 stormy16_print_operand (file, x, code)
1389      FILE * file;
1390      rtx    x;
1391      int    code;
1392 {
1393   switch (code)
1394     {
1395     case 'B':
1396         /* There is either one bit set, or one bit clear, in X.
1397            Print it preceded by '#'.  */
1398       {
1399         HOST_WIDE_INT xx, l;
1400
1401         if (GET_CODE (x) == CONST_INT)
1402           xx = INTVAL (x);
1403         else
1404           output_operand_lossage ("`B' operand is not constant");
1405         
1406         l = exact_log2 (xx);
1407         if (l == -1)
1408           l = exact_log2 (~xx);
1409         if (l == -1)
1410           output_operand_lossage ("`B' operand has multiple bits set");
1411         
1412         fputs (IMMEDIATE_PREFIX, file);
1413         fprintf (file, HOST_WIDE_INT_PRINT_DEC, l);
1414         return;
1415       }
1416
1417     case 'C':
1418       /* Print the symbol without a surrounding @fptr().  */
1419       if (GET_CODE (x) == SYMBOL_REF)
1420         assemble_name (file, XSTR (x, 0));
1421       else
1422         stormy16_print_operand_address (file, x);
1423       return;
1424
1425     case 'o':
1426     case 'O':
1427       /* Print the immediate operand less one, preceded by '#'.  
1428          For 'O', negate it first.  */
1429       {
1430         HOST_WIDE_INT xx;
1431         
1432         if (GET_CODE (x) == CONST_INT)
1433           xx = INTVAL (x);
1434         else
1435           output_operand_lossage ("`o' operand is not constant");
1436         
1437         if (code == 'O')
1438           xx = -xx;
1439         
1440         fputs (IMMEDIATE_PREFIX, file);
1441         fprintf (file, HOST_WIDE_INT_PRINT_DEC, xx - 1);
1442         return;
1443       }
1444
1445     case 0:
1446       /* Handled below.  */
1447       break;
1448       
1449     default:
1450       output_operand_lossage ("stormy16_print_operand: unknown code");
1451       return;
1452     }
1453
1454   switch (GET_CODE (x))
1455     {
1456     case REG:
1457       fputs (reg_names [REGNO (x)], file);
1458       break;
1459
1460     case MEM:
1461       stormy16_print_operand_address (file, XEXP (x, 0));
1462       break;
1463
1464     default:
1465       /* Some kind of constant or label; an immediate operand,
1466          so prefix it with '#' for the assembler.  */
1467       fputs (IMMEDIATE_PREFIX, file);
1468       output_addr_const (file, x);
1469       break;
1470     }
1471
1472   return;
1473 }
1474
1475 \f
1476 /* Expander for the `casesi' pattern.
1477    INDEX is the index of the switch statement.
1478    LOWER_BOUND is a CONST_INT that is the value of INDEX corresponding
1479      to the first table entry.
1480    RANGE is the number of table entries.
1481    TABLE is an ADDR_VEC that is the jump table.
1482    DEFAULT_LABEL is the address to branch to if INDEX is outside the
1483      range LOWER_BOUND to LOWER_BOUND+RANGE-1.
1484 */
1485
1486 void 
1487 stormy16_expand_casesi (index, lower_bound, range, table, default_label)
1488      rtx index;
1489      rtx lower_bound;
1490      rtx range;
1491      rtx table;
1492      rtx default_label;
1493 {
1494   HOST_WIDE_INT range_i = INTVAL (range);
1495   rtx int_index;
1496
1497   /* This code uses 'br', so it can deal only with tables of size up to
1498      8192 entries.  */
1499   if (range_i >= 8192)
1500     sorry ("switch statement of size %lu entries too large", 
1501            (unsigned long) range_i);
1502
1503   index = expand_binop (SImode, sub_optab, index, lower_bound, index, 0,
1504                         OPTAB_LIB_WIDEN);
1505   emit_cmp_and_jump_insns (index, range, GTU, NULL_RTX, SImode, 1,
1506                            0, default_label);
1507   int_index = gen_lowpart_common (HImode, index);
1508   emit_insn (gen_ashlhi3 (int_index, int_index, GEN_INT (2)));
1509   emit_jump_insn (gen_tablejump_pcrel (int_index, table));
1510 }
1511
1512 /* Output an ADDR_VEC.  It is output as a sequence of 'jmpf'
1513    instructions, without label or alignment or any other special
1514    constructs.  We know that the previous instruction will be the
1515    `tablejump_pcrel' output above.
1516
1517    TODO: it might be nice to output 'br' instructions if they could
1518    all reach.  */
1519
1520 void
1521 stormy16_output_addr_vec (file, label, table)
1522      FILE *file;
1523      rtx label ATTRIBUTE_UNUSED;
1524      rtx table;
1525
1526   int vlen, idx;
1527   
1528   function_section (current_function_decl);
1529
1530   vlen = XVECLEN (table, 0);
1531   for (idx = 0; idx < vlen; idx++)
1532     {
1533       fputs ("\tjmpf ", file);
1534       stormy16_print_operand_address (file, 
1535                                       XEXP (XVECEXP (table, 0, idx), 0));
1536       fputc ('\n', file);
1537     }
1538 }
1539
1540 \f
1541 /* Expander for the `call' patterns.
1542    INDEX is the index of the switch statement.
1543    LOWER_BOUND is a CONST_INT that is the value of INDEX corresponding
1544      to the first table entry.
1545    RANGE is the number of table entries.
1546    TABLE is an ADDR_VEC that is the jump table.
1547    DEFAULT_LABEL is the address to branch to if INDEX is outside the
1548      range LOWER_BOUND to LOWER_BOUND+RANGE-1.
1549 */
1550
1551 void 
1552 stormy16_expand_call (retval, dest, counter)
1553      rtx retval;
1554      rtx dest;
1555      rtx counter;
1556 {
1557   rtx call, temp;
1558   enum machine_mode mode;
1559
1560   if (GET_CODE (dest) != MEM)
1561     abort ();
1562   dest = XEXP (dest, 0);
1563
1564   if (! CONSTANT_P (dest)
1565       && GET_CODE (dest) != REG)
1566     dest = force_reg (Pmode, dest);
1567   
1568   if (retval == NULL)
1569     mode = VOIDmode;
1570   else
1571     mode = GET_MODE (retval);
1572
1573   call = gen_rtx_CALL (mode, gen_rtx_MEM (FUNCTION_MODE, dest),
1574                        counter);
1575   if (retval)
1576     call = gen_rtx_SET (VOIDmode, retval, call);
1577   
1578   if (! CONSTANT_P (dest))
1579     {
1580       temp = gen_reg_rtx (HImode);
1581       emit_move_insn (temp, const0_rtx);
1582     }
1583   else
1584     temp = const0_rtx;
1585   
1586   call = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, call, 
1587                                                 gen_rtx_USE (VOIDmode, temp)));
1588   emit_call_insn (call);
1589 }
1590 \f
1591 /* Expanders for multiword computational operations.  */
1592
1593 /* Expander for arithmetic operations; emit insns to compute
1594
1595    (set DEST (CODE:MODE SRC0 SRC1))
1596    
1597    using CARRY as a temporary.  When CODE is COMPARE, a branch
1598    template is generated (this saves duplicating code in
1599    stormy16_split_cbranch).  */
1600
1601 void 
1602 stormy16_expand_arith (mode, code, dest, src0, src1, carry)
1603      enum machine_mode mode;
1604      enum rtx_code code;
1605      rtx dest;
1606      rtx src0;
1607      rtx src1;
1608      rtx carry;
1609 {
1610   int num_words = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
1611   int i;
1612   int firstloop = 1;
1613
1614   if (code == NEG)
1615     {
1616       rtx zero_reg = gen_reg_rtx (word_mode);
1617       emit_move_insn (zero_reg, src0);
1618       src0 = zero_reg;
1619     }
1620   
1621   for (i = 0; i < num_words; i++)
1622     {
1623       rtx w_src0, w_src1, w_dest;
1624       rtx insn;
1625       
1626       if (code == NEG)
1627         w_src0 = src0;
1628       else
1629         w_src0 = simplify_gen_subreg (word_mode, src0, mode, 
1630                                       i * UNITS_PER_WORD);
1631       w_src1 = simplify_gen_subreg (word_mode, src1, mode, i * UNITS_PER_WORD);
1632       w_dest = simplify_gen_subreg (word_mode, dest, mode, i * UNITS_PER_WORD);
1633
1634       switch (code)
1635         {
1636         case PLUS:
1637           if (firstloop
1638               && GET_CODE (w_src1) == CONST_INT && INTVAL (w_src1) == 0)
1639             continue;
1640           
1641           if (firstloop)
1642             insn = gen_addchi4 (w_dest, w_src0, w_src1, carry);
1643           else
1644             insn = gen_addchi5 (w_dest, w_src0, w_src1, carry, carry);
1645           break;
1646
1647         case NEG:
1648         case MINUS:
1649         case COMPARE:
1650           if (code == COMPARE && i == num_words - 1)
1651             {
1652               rtx branch, sub, clobber, sub_1;
1653               
1654               sub_1 = gen_rtx_MINUS (HImode, w_src0, 
1655                                      gen_rtx_ZERO_EXTEND (HImode, carry));
1656               sub = gen_rtx_SET (VOIDmode, w_dest,
1657                                  gen_rtx_MINUS (HImode, sub_1, w_src1));
1658               clobber = gen_rtx_CLOBBER (VOIDmode, carry);
1659               branch = gen_rtx_SET (VOIDmode, pc_rtx,
1660                                     gen_rtx_IF_THEN_ELSE (VOIDmode,
1661                                                           gen_rtx_EQ (HImode,
1662                                                                       sub_1,
1663                                                                       w_src1),
1664                                                           pc_rtx,
1665                                                           pc_rtx));
1666               insn = gen_rtx_PARALLEL (VOIDmode,
1667                                        gen_rtvec (3, branch, sub, clobber));
1668             }
1669           else if (firstloop
1670                    && code != COMPARE
1671                    && GET_CODE (w_src1) == CONST_INT && INTVAL (w_src1) == 0)
1672             continue;
1673           else if (firstloop)
1674             insn = gen_subchi4 (w_dest, w_src0, w_src1, carry);
1675           else
1676             insn = gen_subchi5 (w_dest, w_src0, w_src1, carry, carry);
1677           break;
1678
1679         case IOR:
1680         case XOR:
1681         case AND:
1682           if (GET_CODE (w_src1) == CONST_INT 
1683               && INTVAL (w_src1) == -(code == AND))
1684             continue;
1685           
1686           insn = gen_rtx_SET (VOIDmode, w_dest, gen_rtx (code, mode,
1687                                                          w_src0, w_src1));
1688           break;
1689
1690         case NOT:
1691           insn = gen_rtx_SET (VOIDmode, w_dest, gen_rtx_NOT (mode, w_src0));
1692           break;
1693
1694         default:
1695           abort ();
1696         }
1697       
1698       firstloop = 0;
1699       emit (insn);
1700     }
1701 }
1702
1703 /* Return 1 if OP is a shift operator.  */
1704
1705 int
1706 shift_operator (op, mode)
1707      register rtx op;
1708      enum machine_mode mode ATTRIBUTE_UNUSED;
1709 {
1710   enum rtx_code code = GET_CODE (op);
1711
1712   return (code == ASHIFT
1713           || code == ASHIFTRT
1714           || code == LSHIFTRT);
1715 }
1716
1717 /* The shift operations are split at output time for constant values;
1718    variable-width shifts get handed off to a library routine.  
1719
1720    Generate an output string to do (set X (CODE:MODE X SIZE_R))
1721    SIZE_R will be a CONST_INT, X will be a hard register.  */
1722
1723 const char * 
1724 stormy16_output_shift (mode, code, x, size_r, temp)
1725      enum machine_mode mode;
1726      enum rtx_code code;
1727      rtx x;
1728      rtx size_r;
1729      rtx temp;
1730 {
1731   HOST_WIDE_INT size;
1732   const char *r0, *r1, *rt;
1733   static char r[64];
1734
1735   if (GET_CODE (size_r) != CONST_INT
1736       || GET_CODE (x) != REG
1737       || mode != SImode)
1738     abort ();
1739   size = INTVAL (size_r) & (GET_MODE_BITSIZE (mode) - 1);
1740
1741   if (size == 0)
1742     return "";
1743
1744   r0 = reg_names [REGNO (x)];
1745   r1 = reg_names [REGNO (x) + 1];
1746   rt = reg_names [REGNO (temp)];
1747
1748   /* For shifts of size 1, we can use the rotate instructions.  */
1749   if (size == 1)
1750     {
1751       switch (code)
1752         {
1753         case ASHIFT:
1754           sprintf (r, "shl %s,#1 | rlc %s,#1", r0, r1);
1755           break;
1756         case ASHIFTRT:
1757           sprintf (r, "asr %s,#1 | rrc %s,#1", r1, r0);
1758           break;
1759         case LSHIFTRT:
1760           sprintf (r, "shr %s,#1 | rrc %s,#1", r1, r0);
1761           break;
1762         default:
1763           abort ();
1764         }
1765       return r;
1766     }
1767   
1768   /* For large shifts, there are easy special cases.  */
1769   if (size == 16)
1770     {
1771       switch (code)
1772         {
1773         case ASHIFT:
1774           sprintf (r, "mov %s,%s | mov %s,#0", r1, r0, r0);
1775           break;
1776         case ASHIFTRT:
1777           sprintf (r, "mov %s,%s | asr %s,#15", r0, r1, r1);
1778           break;
1779         case LSHIFTRT:
1780           sprintf (r, "mov %s,%s | mov %s,#0", r0, r1, r1);
1781           break;
1782         default:
1783           abort ();
1784         }
1785       return r;
1786     }
1787   if (size > 16)
1788     {
1789       switch (code)
1790         {
1791         case ASHIFT:
1792           sprintf (r, "mov %s,%s | mov %s,#0 | shl %s,#%d", 
1793                    r1, r0, r0, r1, (int) size - 16);
1794           break;
1795         case ASHIFTRT:
1796           sprintf (r, "mov %s,%s | asr %s,#15 | asr %s,#%d", 
1797                    r0, r1, r1, r0, (int) size - 16);
1798           break;
1799         case LSHIFTRT:
1800           sprintf (r, "mov %s,%s | mov %s,#0 | shr %s,#%d", 
1801                    r0, r1, r1, r0, (int) size - 16);
1802           break;
1803         default:
1804           abort ();
1805         }
1806       return r;
1807     }
1808
1809   /* For the rest, we have to do more work.  In particular, we
1810      need a temporary.  */
1811   switch (code)
1812     {
1813     case ASHIFT:
1814       sprintf (r, 
1815                "mov %s,%s | shl %s,#%d | shl %s,#%d | shr %s,#%d | or %s,%s", 
1816                rt, r0, r0, (int) size, r1, (int) size, rt, (int) 16-size,
1817                r1, rt);
1818       break;
1819     case ASHIFTRT:
1820       sprintf (r, 
1821                "mov %s,%s | asr %s,#%d | shr %s,#%d | shl %s,#%d | or %s,%s", 
1822                rt, r1, r1, (int) size, r0, (int) size, rt, (int) 16-size,
1823                r0, rt);
1824       break;
1825     case LSHIFTRT:
1826       sprintf (r, 
1827                "mov %s,%s | shr %s,#%d | shr %s,#%d | shl %s,#%d | or %s,%s", 
1828                rt, r1, r1, (int) size, r0, (int) size, rt, (int) 16-size,
1829                r0, rt);
1830       break;
1831     default:
1832       abort ();
1833     }
1834   return r;
1835 }
1836 \f
1837 /* Attribute handling.  */
1838
1839 /* Return nonzero if the function is an interrupt function.  */
1840 int
1841 stormy16_interrupt_function_p ()
1842 {
1843   tree attributes;
1844   
1845   /* The dwarf2 mechanism asks for INCOMING_FRAME_SP_OFFSET before
1846      any functions are declared, which is demonstrably wrong, but
1847      it is worked around here.  FIXME.  */
1848   if (!cfun)
1849     return 0;
1850
1851   attributes = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1852   return lookup_attribute ("interrupt", attributes) != NULL_TREE;
1853 }
1854
1855 /* If defined, a C function which returns nonzero if IDENTIFIER
1856    with arguments ARGS is a valid machine specific attribute for TYPE.
1857    The attributes in ATTRIBUTES have previously been assigned to TYPE.  */
1858 #undef TARGET_VALID_TYPE_ATTRIBUTE
1859 #define TARGET_VALID_TYPE_ATTRIBUTE stormy16_valid_type_attribute
1860 static int stormy16_valid_type_attribute PARAMS ((tree TYPE,
1861                                                   tree ATTRIBUTES,
1862                                                   tree IDENTIFIER,
1863                                                   tree ARGS));
1864
1865 static int
1866 stormy16_valid_type_attribute (type, attributes, identifier, args)
1867      tree type;
1868      tree attributes ATTRIBUTE_UNUSED;
1869      tree identifier;
1870      tree args ATTRIBUTE_UNUSED;
1871 {
1872   if (TREE_CODE (type) != FUNCTION_TYPE)
1873     return 0;
1874   
1875   if (is_attribute_p ("interrupt", identifier))
1876     return 1;
1877
1878   return 0;
1879 }
1880 \f
1881 struct gcc_target targetm = TARGET_INITIALIZER;