1 /* Stormy16 target functions.
2 Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
3 Contributed by Red Hat, Inc.
5 This file is part of GNU CC.
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)
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.
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. */
26 #include "hard-reg-set.h"
28 #include "insn-config.h"
29 #include "conditions.h"
30 #include "insn-flags.h"
32 #include "insn-attr.h"
44 #include "target-def.h"
47 static rtx emit_addhi3_postreload PARAMS ((rtx, rtx, rtx));
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;
54 /* Return 1 if this is a LT, GE, LTU, or GEU operator. */
57 stormy16_ineqsi_operator (op, mode)
59 enum machine_mode mode;
61 enum rtx_code code = GET_CODE (op);
63 return ((mode == VOIDmode || GET_MODE (op) == mode)
64 && (code == LT || code == GE || code == LTU || code == GEU));
67 /* Return 1 if this is an EQ or NE operator. */
70 equality_operator (op, mode)
72 enum machine_mode mode;
74 return ((mode == VOIDmode || GET_MODE (op) == mode)
75 && (GET_CODE (op) == EQ || GET_CODE (op) == NE));
78 /* Return 1 if this is a comparison operator but not an EQ or NE operator. */
81 inequality_operator (op, mode)
83 enum machine_mode mode;
85 return comparison_operator (op, mode) && ! equality_operator (op, mode);
88 /* Branches are handled as follows:
90 1. HImode compare-and-branches. The machine supports these
91 natively, so the appropriate pattern is emitted directly.
93 2. SImode EQ and NE. These are emitted as pairs of HImode
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),
103 4. SImode GT, LE, GTU, LEU. These are emitted as a sequence like:
111 /* Emit a branch of kind CODE to location LOC. */
114 stormy16_emit_cbranch (code, loc)
118 rtx op0 = stormy16_compare_op0;
119 rtx op1 = stormy16_compare_op1;
120 rtx condition_rtx, loc_ref, branch, cy_clobber;
122 enum machine_mode mode;
124 mode = GET_MODE (op0);
125 if (mode != HImode && mode != SImode)
129 && (code == GT || code == LE || code == GTU || code == LEU))
131 int unsigned_p = (code == GTU || code == LEU);
132 int gt_p = (code == GT || code == GTU);
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);
145 else if (mode == SImode
146 && (code == NE || code == EQ)
147 && op1 != const0_rtx)
150 int num_words = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
154 lab = gen_label_rtx ();
156 for (i = 0; i < num_words - 1; i++)
158 stormy16_compare_op0 = simplify_gen_subreg (word_mode, op0, mode,
160 stormy16_compare_op1 = simplify_gen_subreg (word_mode, op1, mode,
162 stormy16_emit_cbranch (NE, code == EQ ? lab : loc);
164 stormy16_compare_op0 = simplify_gen_subreg (word_mode, op0, mode,
166 stormy16_compare_op1 = simplify_gen_subreg (word_mode, op1, mode,
168 stormy16_emit_cbranch (code, loc);
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. */
180 tmp = gen_reg_rtx (mode);
181 emit_move_insn (tmp, op0);
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,
191 cy_clobber = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (BImode));
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));
201 sub = gen_rtx_SET (VOIDmode, op0, gen_rtx_MINUS (SImode, op0, op1));
203 sub = gen_rtx_CLOBBER (SImode, op0);
205 vec = gen_rtvec (3, branch, sub, cy_clobber);
208 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec));
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. */
216 stormy16_split_cbranch (mode, label, comparison, dest, carry)
217 enum machine_mode mode;
223 rtx op0 = XEXP (comparison, 0);
224 rtx op1 = XEXP (comparison, 1);
229 stormy16_expand_arith (mode, COMPARE, dest, op0, op1, carry);
230 seq = gen_sequence ();
232 compare = SET_SRC (XVECEXP (PATTERN (XVECEXP (seq, 0, XVECLEN (seq, 0) - 1)),
234 PUT_CODE (XEXP (compare, 0), GET_CODE (comparison));
235 XEXP (compare, 1) = gen_rtx_LABEL_REF (VOIDmode, label);
240 /* Return the string to output a conditional branch to LABEL, which is
241 the operand number of the label.
243 OP is the conditional expression, or NULL for branch-always.
245 REVERSED is non-zero if we should reverse the sense of the comparison.
250 stormy16_output_cbranch_hi (op, label, reversed, insn)
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;
262 const char *template;
263 const char *operands;
272 sprintf (string, "%s %s", ccode, label);
276 code = GET_CODE (op);
278 if (GET_CODE (XEXP (op, 0)) != REG)
280 code = swap_condition (code);
286 /* Work out which way this really branches. */
288 code = reverse_condition (code);
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;
308 template = "b%s %s,.+8 | jmpf %s";
310 template = "b%s %s,%s";
311 sprintf (string, template, ccode, operands, label);
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
320 OP is the conditional expression (OP is never NULL_RTX).
322 REVERSED is non-zero if we should reverse the sense of the comparison.
327 stormy16_output_cbranch_si (op, label, reversed, insn)
333 static char string[64];
334 int need_longbranch = get_attr_length (insn) >= 8;
335 int really_reversed = reversed ^ need_longbranch;
337 const char *template;
341 code = GET_CODE (op);
343 /* Work out which way this really branches. */
345 code = reverse_condition (code);
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;
356 /* The missing codes above should never be generated. */
367 if (GET_CODE (XEXP (op, 0)) != REG)
370 regnum = REGNO (XEXP (op, 0));
371 sprintf (prevop, "or %s,%s", reg_names[regnum], reg_names[regnum+1]);
375 case GE: case LT: case GEU: case LTU:
376 strcpy (prevop, "sbc %2,%3");
384 template = "%s | b%s .+6 | jmpf %s";
386 template = "%s | b%s %s";
387 sprintf (string, template, prevop, ccode, label);
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.
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.
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.
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'.
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.
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.
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
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. */
445 stormy16_secondary_reload_class (class, mode, x)
446 enum reg_class class;
447 enum machine_mode mode;
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))
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))
467 /* Recognise a PLUS that needs the carry register. */
469 stormy16_carry_plus_operand (x, mode)
471 enum machine_mode mode ATTRIBUTE_UNUSED;
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));
480 stormy16_preferred_reload_class (x, class)
481 enum reg_class class;
484 if (class == GENERAL_REGS
485 && GET_CODE (x) == MEM)
491 #define LEGITIMATE_ADDRESS_INTEGER_P(X, OFFSET) \
492 (GET_CODE (X) == CONST_INT \
493 && (unsigned HOST_WIDE_INT) (INTVAL (X) + (OFFSET) + 2048) < 4096)
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))
502 stormy16_legitimate_address_p (mode, x, strict)
503 enum machine_mode mode ATTRIBUTE_UNUSED;
507 if (LEGITIMATE_ADDRESS_CONST_INT_P (x, 0))
510 if (GET_CODE (x) == PLUS
511 && LEGITIMATE_ADDRESS_INTEGER_P (XEXP (x, 1), 0))
514 if (GET_CODE (x) == POST_INC
515 || GET_CODE (x) == PRE_DEC)
518 if (GET_CODE (x) == REG && REGNO_OK_FOR_BASE_P (REGNO (x))
519 && (! strict || REGNO (x) < FIRST_PSEUDO_REGISTER))
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
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.
535 You may assume that ADDR is a valid address for the machine.
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. */
542 stormy16_mode_dependent_address_p (x)
545 if (LEGITIMATE_ADDRESS_CONST_INT_P (x, 0)
546 && ! LEGITIMATE_ADDRESS_CONST_INT_P (x, 6))
549 if (GET_CODE (x) == PLUS
550 && LEGITIMATE_ADDRESS_INTEGER_P (XEXP (x, 1), 0)
551 && ! LEGITIMATE_ADDRESS_INTEGER_P (XEXP (x, 1), 6))
554 if (GET_CODE (x) == PLUS)
557 if (GET_CODE (x) == POST_INC
558 || GET_CODE (x) == PRE_DEC)
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. */
572 stormy16_extra_constraint_p (x, c)
578 /* 'Q' is for pushes. */
580 return (GET_CODE (x) == MEM
581 && GET_CODE (XEXP (x, 0)) == POST_INC
582 && XEXP (XEXP (x, 0), 0) == stack_pointer_rtx);
584 /* 'R' is for pops. */
586 return (GET_CODE (x) == MEM
587 && GET_CODE (XEXP (x, 0)) == PRE_DEC
588 && XEXP (XEXP (x, 0), 0) == stack_pointer_rtx);
590 /* 'S' is for immediate memory addresses. */
592 return (GET_CODE (x) == MEM
593 && GET_CODE (XEXP (x, 0)) == CONST_INT
594 && stormy16_legitimate_address_p (VOIDmode, XEXP (x, 0), 0));
598 /* Not implemented yet. */
601 /* 'U' is for CONST_INT values not between 2 and 15 inclusive,
602 for allocating a scratch register for 32-bit shifts. */
604 return (GET_CODE (x) == CONST_INT
605 && (INTVAL (x) < 2 || INTVAL (x) > 15));
613 short_memory_operand (x, mode)
615 enum machine_mode mode;
617 if (! memory_operand (x, mode))
619 return (GET_CODE (XEXP (x, 0)) != PLUS);
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
626 This function is only called when reload_completed.
630 stormy16_split_move (mode, dest, src)
631 enum machine_mode mode;
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;
643 /* Check initial conditions. */
644 if (! reload_completed
645 || mode == QImode || mode == HImode
646 || ! nonimmediate_operand (dest, mode)
647 || ! general_operand (src, mode))
650 /* This case is not supported below, and shouldn't be generated. */
651 if (GET_CODE (dest) == MEM
652 && GET_CODE (src) == MEM)
655 /* This case is very very bad after reload, so trap it now. */
656 if (GET_CODE (dest) == SUBREG
657 || GET_CODE (src) == SUBREG)
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
666 It's also possible that the copy overlaps so that the direction
670 if (GET_CODE (dest) == MEM)
672 mem_operand = XEXP (dest, 0);
673 dest_modifies = side_effects_p (mem_operand);
674 dest_volatile = MEM_VOLATILE_P (dest);
677 dest = copy_rtx (dest);
678 MEM_VOLATILE_P (dest) = 0;
681 else if (GET_CODE (src) == MEM)
683 mem_operand = XEXP (src, 0);
684 src_modifies = side_effects_p (mem_operand);
685 src_volatile = MEM_VOLATILE_P (src);
688 src = copy_rtx (src);
689 MEM_VOLATILE_P (src) = 0;
693 mem_operand = NULL_RTX;
695 if (mem_operand == NULL_RTX)
697 if (GET_CODE (src) == REG
698 && GET_CODE (dest) == REG
699 && reg_overlap_mentioned_p (dest, src)
700 && REGNO (dest) > REGNO (src))
703 else if (GET_CODE (mem_operand) == PRE_DEC
704 || (GET_CODE (mem_operand) == PLUS
705 && GET_CODE (XEXP (mem_operand, 0)) == PRE_DEC))
707 else if (GET_CODE (src) == MEM
708 && reg_overlap_mentioned_p (dest, src))
711 if (GET_CODE (dest) != REG)
713 regno = REGNO (dest);
715 if (! refers_to_regno_p (regno, regno + num_words, mem_operand, 0))
718 if (refers_to_regno_p (regno, regno + 1, mem_operand, 0))
720 else if (refers_to_regno_p (regno + num_words - 1, regno + num_words,
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
731 end = direction < 0 ? -1 : num_words;
732 for (i = direction < 0 ? num_words - 1 : 0; i != end; i += direction)
736 w_src = gen_rtx_MEM (word_mode, mem_operand);
738 w_src = simplify_gen_subreg (word_mode, src, mode, i * UNITS_PER_WORD);
740 MEM_VOLATILE_P (w_src) = 1;
742 w_dest = gen_rtx_MEM (word_mode, mem_operand);
744 w_dest = simplify_gen_subreg (word_mode, dest, mode,
747 MEM_VOLATILE_P (w_dest) = 1;
749 /* The simplify_subreg calls must always be able to simplify. */
750 if (GET_CODE (w_src) == SUBREG
751 || GET_CODE (w_dest) == SUBREG)
754 emit_insn (gen_rtx_SET (VOIDmode, w_dest, w_src));
758 /* Expander for the 'move' patterns. Emit insns to copy a value of
759 mode MODE from SRC to DEST. */
762 stormy16_expand_move (mode, dest, src)
763 enum machine_mode mode;
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);
777 /* Don't emit something we would immediately split. */
779 && mode != HImode && mode != QImode)
781 stormy16_split_move (mode, dest, src);
785 emit_insn (gen_rtx_SET (VOIDmode, dest, src));
791 The stack is laid out as follows:
795 Register save area (up to 4 words)
796 Argument register save area for stdarg (NUM_ARGUMENT_REGISTERS words)
798 AP-> Return address (two words)
799 9th procedure parameter word
800 10th procedure parameter word
802 last procedure parameter word
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
808 /* A structure to describe the layout. */
809 struct stormy16_stack_layout
811 /* Size of the topmost three items on the stack. */
813 int register_save_size;
814 int stdarg_save_size;
815 /* Sum of the above items. */
817 /* Various offsets. */
818 int first_local_minus_ap;
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)))
829 /* Compute the stack layout. */
830 struct stormy16_stack_layout
831 stormy16_compute_stack_layout ()
833 struct stormy16_stack_layout layout;
835 const int ifun = stormy16_interrupt_function_p ();
837 layout.locals_size = get_frame_size ();
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;
844 if (current_function_varargs || current_function_stdarg)
845 layout.stdarg_save_size = NUM_ARGUMENT_REGISTERS * UNITS_PER_WORD;
847 layout.stdarg_save_size = 0;
849 layout.frame_size = (layout.locals_size
850 + layout.register_save_size
851 + layout.stdarg_save_size);
853 if (current_function_args_size <= 2048 && current_function_args_size != -1)
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;
859 layout.fp_minus_ap = 2048 - current_function_args_size;
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;
871 /* Determine how all the special registers get eliminated. */
873 stormy16_initial_elimination_offset (from, to)
876 struct stormy16_stack_layout layout;
879 layout = stormy16_compute_stack_layout ();
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);
896 emit_addhi3_postreload (dest, src0, src1)
901 rtx set, clobber, insn;
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)));
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.
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. */
919 stormy16_expand_prologue ()
921 struct stormy16_stack_layout layout;
925 rtx mem_fake_push_rtx;
926 const int ifun = stormy16_interrupt_function_p ();
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);
933 layout = stormy16_compute_stack_layout ();
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;
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,
951 /* Push each of the registers to save. */
952 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
953 if (REG_NEEDS_SAVE (regno, ifun))
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,
965 /* It's just possible that the SP here might be what we need for
967 if (frame_pointer_needed && layout.sp_minus_fp == layout.locals_size)
969 insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
970 RTX_FRAME_RELATED_P (insn) = 1;
973 /* Allocate space for local variables. */
974 if (layout.locals_size)
976 insn = emit_addhi3_postreload (stack_pointer_rtx, stack_pointer_rtx,
977 GEN_INT (layout.locals_size));
978 RTX_FRAME_RELATED_P (insn) = 1;
981 /* Set up the frame pointer, if required. */
982 if (frame_pointer_needed && layout.sp_minus_fp != layout.locals_size)
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)
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;
996 /* Do we need an epilogue at all? */
1000 return (reload_completed
1001 && stormy16_compute_stack_layout ().frame_size == 0);
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. */
1012 stormy16_expand_epilogue ()
1014 struct stormy16_stack_layout layout;
1017 const int ifun = stormy16_interrupt_function_p ();
1019 mem_pop_rtx = gen_rtx_PRE_DEC (Pmode, stack_pointer_rtx);
1020 mem_pop_rtx = gen_rtx_MEM (HImode, mem_pop_rtx);
1022 layout = stormy16_compute_stack_layout ();
1024 /* Pop the stack for the locals. */
1025 if (layout.locals_size)
1027 if (frame_pointer_needed && layout.sp_minus_fp == layout.locals_size)
1028 emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx);
1030 emit_addhi3_postreload (stack_pointer_rtx, stack_pointer_rtx,
1031 GEN_INT (- layout.locals_size));
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);
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));
1046 emit_jump_insn (gen_return_internal_interrupt ());
1048 emit_jump_insn (gen_return_internal ());
1052 stormy16_epilogue_uses (regno)
1055 if (reload_completed && call_used_regs[regno])
1057 const int ifun = stormy16_interrupt_function_p ();
1058 return REG_NEEDS_SAVE (regno, ifun);
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.
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
1075 stormy16_function_arg_advance (cum, mode, type, named)
1076 CUMULATIVE_ARGS cum;
1077 enum machine_mode mode;
1079 int named ATTRIBUTE_UNUSED;
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
1084 if (cum < NUM_ARGUMENT_REGISTERS
1085 && cum + STORMY16_WORD_SIZE (type, mode) > NUM_ARGUMENT_REGISTERS)
1086 cum = NUM_ARGUMENT_REGISTERS;
1088 cum += STORMY16_WORD_SIZE (type, mode);
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. */
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;
1104 /* Build the va_list type.
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. */
1113 stormy16_build_va_list ()
1115 tree f_1, f_2, record, type_decl;
1117 record = make_lang_type (RECORD_TYPE);
1118 type_decl = build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record);
1120 f_2 = build_decl (FIELD_DECL, get_identifier ("base"),
1122 f_1 = build_decl (FIELD_DECL, get_identifier ("count"),
1123 unsigned_type_node);
1125 DECL_FIELD_CONTEXT (f_1) = record;
1126 DECL_FIELD_CONTEXT (f_2) = record;
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;
1133 layout_type (record);
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. */
1143 stormy16_expand_builtin_va_start (stdarg_p, valist, nextarg)
1144 int stdarg_p ATTRIBUTE_UNUSED;
1146 rtx nextarg ATTRIBUTE_UNUSED;
1148 tree f_base, f_count;
1152 if (stormy16_interrupt_function_p ())
1153 error ("cannot use va_start in interrupt function");
1155 f_base = TYPE_FIELDS (va_list_type_node);
1156 f_count = TREE_CHAIN (f_base);
1158 base = build (COMPONENT_REF, TREE_TYPE (f_base), valist, f_base);
1159 count = build (COMPONENT_REF, TREE_TYPE (f_count), valist, f_count);
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);
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);
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. */
1177 stormy16_expand_builtin_va_arg (valist, type)
1181 tree f_base, f_count;
1183 rtx count_rtx, addr_rtx, r;
1184 rtx lab_gotaddr, lab_fromstack;
1186 int size, last_reg_count;
1187 tree size_tree, count_plus_size;
1189 f_base = TYPE_FIELDS (va_list_type_node);
1190 f_count = TREE_CHAIN (f_base);
1192 base = build (COMPONENT_REF, TREE_TYPE (f_base), valist, f_base);
1193 count = build (COMPONENT_REF, TREE_TYPE (f_count), valist, f_count);
1195 size = PUSH_ROUNDING (int_size_in_bytes (type));
1196 size_tree = round_up (size_in_bytes (type), UNITS_PER_WORD);
1198 last_reg_count = NUM_ARGUMENT_REGISTERS * UNITS_PER_WORD - size;
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);
1207 t = build (PLUS_EXPR, ptr_type_node, base, count);
1208 r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
1210 emit_move_insn (addr_rtx, r);
1212 emit_jump_insn (gen_jump (lab_gotaddr));
1214 emit_label (lab_fromstack);
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)
1221 rtx lab_notransition = gen_label_rtx ();
1222 emit_cmp_and_jump_insns (count_rtx, GEN_INT (NUM_ARGUMENT_REGISTERS
1224 GEU, const1_rtx, HImode, 1, 1,
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);
1232 emit_label (lab_notransition);
1235 t = build (PLUS_EXPR, sizetype, size_tree,
1236 build_int_2 ((- NUM_ARGUMENT_REGISTERS * UNITS_PER_WORD
1237 + INCOMING_FRAME_SP_OFFSET),
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);
1243 emit_move_insn (addr_rtx, r);
1245 emit_label (lab_gotaddr);
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);
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. */
1260 stormy16_initialize_trampoline (addr, fnaddr, static_chain)
1265 rtx reg_addr = gen_reg_rtx (Pmode);
1266 rtx temp = gen_reg_rtx (HImode);
1267 rtx reg_fnaddr = gen_reg_rtx (HImode);
1270 reg_addr_mem = gen_rtx_MEM (HImode, reg_addr);
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);
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).
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.
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.
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
1308 stormy16_function_value (valtype, func)
1310 tree func ATTRIBUTE_UNUSED;
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);
1318 /* Mark functions with SYMBOL_REF_FLAG. */
1321 stormy16_encode_section_info (decl)
1324 if (TREE_CODE (decl) == FUNCTION_DECL)
1325 SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1;
1328 /* Print a memory address as an operand to reference that memory location. */
1330 stormy16_print_operand_address (file, address)
1334 HOST_WIDE_INT offset;
1335 int pre_dec, post_inc;
1337 /* There are a few easy cases. */
1338 if (GET_CODE (address) == CONST_INT)
1340 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (address) & 0xFFFF);
1344 if (CONSTANT_P (address) || GET_CODE (address) == CODE_LABEL)
1346 output_addr_const (file, address);
1350 /* Otherwise, it's hopefully something of the form
1351 (plus:HI (pre_dec:HI (reg:HI ...)) (const_int ...))
1354 if (GET_CODE (address) == PLUS)
1356 if (GET_CODE (XEXP (address, 1)) != CONST_INT)
1358 offset = INTVAL (XEXP (address, 1));
1359 address = XEXP (address, 0);
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);
1369 if (GET_CODE (address) != REG)
1375 fputs (reg_names [REGNO (address)], file);
1381 fprintf (file, HOST_WIDE_INT_PRINT_DEC, offset);
1386 /* Print an operand to a assembler instruction. */
1388 stormy16_print_operand (file, x, code)
1396 /* There is either one bit set, or one bit clear, in X.
1397 Print it preceded by '#'. */
1399 HOST_WIDE_INT xx, l;
1401 if (GET_CODE (x) == CONST_INT)
1404 output_operand_lossage ("`B' operand is not constant");
1406 l = exact_log2 (xx);
1408 l = exact_log2 (~xx);
1410 output_operand_lossage ("`B' operand has multiple bits set");
1412 fputs (IMMEDIATE_PREFIX, file);
1413 fprintf (file, HOST_WIDE_INT_PRINT_DEC, l);
1418 /* Print the symbol without a surrounding @fptr(). */
1419 if (GET_CODE (x) == SYMBOL_REF)
1420 assemble_name (file, XSTR (x, 0));
1422 stormy16_print_operand_address (file, x);
1427 /* Print the immediate operand less one, preceded by '#'.
1428 For 'O', negate it first. */
1432 if (GET_CODE (x) == CONST_INT)
1435 output_operand_lossage ("`o' operand is not constant");
1440 fputs (IMMEDIATE_PREFIX, file);
1441 fprintf (file, HOST_WIDE_INT_PRINT_DEC, xx - 1);
1446 /* Handled below. */
1450 output_operand_lossage ("stormy16_print_operand: unknown code");
1454 switch (GET_CODE (x))
1457 fputs (reg_names [REGNO (x)], file);
1461 stormy16_print_operand_address (file, XEXP (x, 0));
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);
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.
1487 stormy16_expand_casesi (index, lower_bound, range, table, default_label)
1494 HOST_WIDE_INT range_i = INTVAL (range);
1497 /* This code uses 'br', so it can deal only with tables of size up to
1499 if (range_i >= 8192)
1500 sorry ("switch statement of size %lu entries too large",
1501 (unsigned long) range_i);
1503 index = expand_binop (SImode, sub_optab, index, lower_bound, index, 0,
1505 emit_cmp_and_jump_insns (index, range, GTU, NULL_RTX, SImode, 1,
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));
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.
1517 TODO: it might be nice to output 'br' instructions if they could
1521 stormy16_output_addr_vec (file, label, table)
1523 rtx label ATTRIBUTE_UNUSED;
1528 function_section (current_function_decl);
1530 vlen = XVECLEN (table, 0);
1531 for (idx = 0; idx < vlen; idx++)
1533 fputs ("\tjmpf ", file);
1534 stormy16_print_operand_address (file,
1535 XEXP (XVECEXP (table, 0, idx), 0));
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.
1552 stormy16_expand_call (retval, dest, counter)
1558 enum machine_mode mode;
1560 if (GET_CODE (dest) != MEM)
1562 dest = XEXP (dest, 0);
1564 if (! CONSTANT_P (dest)
1565 && GET_CODE (dest) != REG)
1566 dest = force_reg (Pmode, dest);
1571 mode = GET_MODE (retval);
1573 call = gen_rtx_CALL (mode, gen_rtx_MEM (FUNCTION_MODE, dest),
1576 call = gen_rtx_SET (VOIDmode, retval, call);
1578 if (! CONSTANT_P (dest))
1580 temp = gen_reg_rtx (HImode);
1581 emit_move_insn (temp, const0_rtx);
1586 call = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, call,
1587 gen_rtx_USE (VOIDmode, temp)));
1588 emit_call_insn (call);
1591 /* Expanders for multiword computational operations. */
1593 /* Expander for arithmetic operations; emit insns to compute
1595 (set DEST (CODE:MODE SRC0 SRC1))
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). */
1602 stormy16_expand_arith (mode, code, dest, src0, src1, carry)
1603 enum machine_mode mode;
1610 int num_words = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
1616 rtx zero_reg = gen_reg_rtx (word_mode);
1617 emit_move_insn (zero_reg, src0);
1621 for (i = 0; i < num_words; i++)
1623 rtx w_src0, w_src1, w_dest;
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);
1638 && GET_CODE (w_src1) == CONST_INT && INTVAL (w_src1) == 0)
1642 insn = gen_addchi4 (w_dest, w_src0, w_src1, carry);
1644 insn = gen_addchi5 (w_dest, w_src0, w_src1, carry, carry);
1650 if (code == COMPARE && i == num_words - 1)
1652 rtx branch, sub, clobber, sub_1;
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,
1666 insn = gen_rtx_PARALLEL (VOIDmode,
1667 gen_rtvec (3, branch, sub, clobber));
1671 && GET_CODE (w_src1) == CONST_INT && INTVAL (w_src1) == 0)
1674 insn = gen_subchi4 (w_dest, w_src0, w_src1, carry);
1676 insn = gen_subchi5 (w_dest, w_src0, w_src1, carry, carry);
1682 if (GET_CODE (w_src1) == CONST_INT
1683 && INTVAL (w_src1) == -(code == AND))
1686 insn = gen_rtx_SET (VOIDmode, w_dest, gen_rtx (code, mode,
1691 insn = gen_rtx_SET (VOIDmode, w_dest, gen_rtx_NOT (mode, w_src0));
1703 /* Return 1 if OP is a shift operator. */
1706 shift_operator (op, mode)
1708 enum machine_mode mode ATTRIBUTE_UNUSED;
1710 enum rtx_code code = GET_CODE (op);
1712 return (code == ASHIFT
1714 || code == LSHIFTRT);
1717 /* The shift operations are split at output time for constant values;
1718 variable-width shifts get handed off to a library routine.
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. */
1724 stormy16_output_shift (mode, code, x, size_r, temp)
1725 enum machine_mode mode;
1732 const char *r0, *r1, *rt;
1735 if (GET_CODE (size_r) != CONST_INT
1736 || GET_CODE (x) != REG
1739 size = INTVAL (size_r) & (GET_MODE_BITSIZE (mode) - 1);
1744 r0 = reg_names [REGNO (x)];
1745 r1 = reg_names [REGNO (x) + 1];
1746 rt = reg_names [REGNO (temp)];
1748 /* For shifts of size 1, we can use the rotate instructions. */
1754 sprintf (r, "shl %s,#1 | rlc %s,#1", r0, r1);
1757 sprintf (r, "asr %s,#1 | rrc %s,#1", r1, r0);
1760 sprintf (r, "shr %s,#1 | rrc %s,#1", r1, r0);
1768 /* For large shifts, there are easy special cases. */
1774 sprintf (r, "mov %s,%s | mov %s,#0", r1, r0, r0);
1777 sprintf (r, "mov %s,%s | asr %s,#15", r0, r1, r1);
1780 sprintf (r, "mov %s,%s | mov %s,#0", r0, r1, r1);
1792 sprintf (r, "mov %s,%s | mov %s,#0 | shl %s,#%d",
1793 r1, r0, r0, r1, (int) size - 16);
1796 sprintf (r, "mov %s,%s | asr %s,#15 | asr %s,#%d",
1797 r0, r1, r1, r0, (int) size - 16);
1800 sprintf (r, "mov %s,%s | mov %s,#0 | shr %s,#%d",
1801 r0, r1, r1, r0, (int) size - 16);
1809 /* For the rest, we have to do more work. In particular, we
1810 need a temporary. */
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,
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,
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,
1837 /* Attribute handling. */
1839 /* Return nonzero if the function is an interrupt function. */
1841 stormy16_interrupt_function_p ()
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. */
1851 attributes = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1852 return lookup_attribute ("interrupt", attributes) != NULL_TREE;
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,
1866 stormy16_valid_type_attribute (type, attributes, identifier, args)
1868 tree attributes ATTRIBUTE_UNUSED;
1870 tree args ATTRIBUTE_UNUSED;
1872 if (TREE_CODE (type) != FUNCTION_TYPE)
1875 if (is_attribute_p ("interrupt", identifier))
1881 struct gcc_target targetm = TARGET_INITIALIZER;