1 /* Subroutines for insn-output.c for the Gmicro.
2 Ported by Masanobu Yuhara, Fujitsu Laboratories LTD.
3 (yuhara@flab.fujitsu.co.jp)
5 Copyright (C) 1990, 1991, 1997 Free Software Foundation, Inc.
7 This file is part of GNU CC.
9 GNU CC is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
14 GNU CC is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 Among other things, the copyright
20 notice and this notice must be preserved on all copies.
22 You should have received a copy of the GNU General Public License
23 along with GNU CC; see the file COPYING. If not, write to
24 the Free Software Foundation, 59 Temple Place - Suite 330,
25 Boston, MA 02111-1307, USA. */
32 #include "hard-reg-set.h"
34 #include "insn-config.h"
35 #include "conditions.h"
36 #include "insn-flags.h"
38 #include "insn-attr.h"
40 extern char *rtx_name
[];
42 mypr (s
, a1
, a2
, a3
, a4
, a5
)
44 int a1
, a2
, a3
, a4
, a5
;
46 fprintf (stderr
, s
, a1
, a2
, a3
, a4
, a5
);
53 fprintf (stderr
, "code = %d\n", i
);
55 fprintf (stderr
, "code = %s\n", rtx_name
[i
]);
61 fprintf (stderr
, "myabort");
66 /* This is how to output an ascii string. */
67 /* See ASM_OUTPUT_ASCII in gmicro.h. */
68 output_ascii (file
, p
, size
)
77 fprintf (file
, "\t.sdata ");
79 for (i
= 0; i
< size
; i
++)
82 if (c
>= ' ' && c
< 0x7f)
98 fprintf (file
, "<%d>", c
);
107 /* call this when GET_CODE (index) is MULT. */
108 print_scaled_index (file
, index
)
115 if (GET_CODE (XEXP (index
, 0)) == REG
)
117 ireg
= XEXP (index
, 0);
118 scale
= INTVAL (XEXP (index
, 1));
122 ireg
= XEXP (index
, 1);
123 scale
= INTVAL (XEXP (index
, 0));
126 fprintf (file
, "%s", reg_names
[REGNO (ireg
)]);
128 fprintf (file
, "%s*%d", reg_names
[REGNO (ireg
)], scale
);
132 print_operand_address (file
, addr
)
136 register rtx xtmp0
, xtmp1
, breg
, ixreg
;
143 switch (GET_CODE (addr
))
147 addr
= XEXP (addr
, 0);
151 fprintf (file
, "%s", reg_names
[REGNO (addr
)]);
155 print_scaled_index (file
, addr
);
159 fprintf (file
, "-%s", reg_names
[REGNO (XEXP (addr
, 0))]);
163 fprintf (file
, "%s+", reg_names
[REGNO (XEXP (addr
, 0))]);
167 xtmp0
= XEXP (addr
, 0);
168 xtmp1
= XEXP (addr
, 1);
171 if (CONSTANT_ADDRESS_P (xtmp0
))
176 else if (CONSTANT_ADDRESS_P (xtmp1
))
186 if (REG_CODE_BASE_P (breg
))
189 if (GET_CODE (breg
) == MULT
)
191 if (REG_CODE_INDEX_P (XEXP (breg
, 0)))
193 ixreg
= XEXP (breg
, 0);
194 scale
= INTVAL (XEXP (breg
, 1));
199 ixreg
= XEXP (breg
, 1);
200 scale
= INTVAL (XEXP (breg
, 0));
206 /* GET_CODE (breg) must be PLUS here. */
207 xtmp0
= XEXP (breg
, 0);
208 xtmp1
= XEXP (breg
, 1);
209 if (REG_CODE_BASE_P (xtmp0
))
220 if (GET_CODE (xtmp0
) == MULT
)
222 if (REG_CODE_INDEX_P (XEXP (xtmp0
, 0)))
224 ixreg
= XEXP (xtmp0
, 0);
225 scale
= INTVAL (XEXP (xtmp0
, 1));
229 ixreg
= XEXP (xtmp0
, 1);
230 scale
= INTVAL (XEXP (xtmp0
, 0));
241 if (REG_CODE_BASE_P (xtmp0
))
246 else if (REG_CODE_BASE_P (xtmp1
))
254 if (REG_CODE_INDEX_P (xtmp0
))
260 else if (CONSTANT_ADDRESS_P (xtmp0
))
265 else if (GET_CODE (xtmp0
) == MULT
)
267 if (REG_CODE_INDEX_P (XEXP (xtmp0
, 0)))
269 ixreg
= XEXP (xtmp0
, 0);
270 scale
= INTVAL (XEXP (xtmp0
, 1));
274 ixreg
= XEXP (xtmp0
, 1);
275 scale
= INTVAL (XEXP (xtmp0
, 0));
280 /* GET_CODE (xtmp0) must be PLUS. */
281 xtmp1
= XEXP (xtmp0
, 1);
282 xtmp0
= XEXP (xtmp0
, 0);
284 if (CONSTANT_ADDRESS_P (xtmp0
))
295 if (REG_CODE_INDEX_P (xtmp0
))
300 { /* GET_CODE (xtmp0) must be MULT. */
301 if (REG_CODE_INDEX_P (XEXP (xtmp0
, 0)))
303 ixreg
= XEXP (xtmp0
, 0);
304 scale
= INTVAL (XEXP (xtmp0
, 1));
308 ixreg
= XEXP (xtmp0
, 1);
309 scale
= INTVAL (XEXP (xtmp0
, 0));
315 if (GET_CODE (xtmp0
) == PLUS
)
326 if (REG_CODE_INDEX_P (ixreg
))
330 else if (REG_CODE_INDEX_P (XEXP (ixreg
, 0)))
332 scale
= INTVAL (XEXP (ixreg
, 1));
333 ixreg
= XEXP (ixreg
, 0);
336 { /* was else if with no condition. OK ??? */
337 scale
= INTVAL (XEXP (ixreg
, 0));
338 ixreg
= XEXP (ixreg
, 1);
341 if (REG_CODE_BASE_P (XEXP (xtmp0
, 0)))
343 breg
= XEXP (xtmp0
, 0);
344 offset
= XEXP (xtmp0
, 1);
348 breg
= XEXP (xtmp0
, 1);
349 offset
= XEXP (xtmp0
, 0);
353 if (breg
== 0 && ixreg
== 0)
355 output_address (offset
);
358 else if (ixreg
== 0 && offset
== 0)
360 fprintf (file
, "%s", reg_names
[REGNO (breg
)]);
368 output_addr_const (file
, offset
);
375 fprintf (file
, "%s", reg_names
[REGNO (breg
)]);
382 fprintf (file
, "%s", reg_names
[REGNO (ixreg
)]);
384 fprintf (file
,"*%d", scale
);
392 output_addr_const (file
, addr
);
398 /* Return a REG that occurs in ADDR with coefficient 1.
399 ADDR can be effectively incremented by incrementing REG. */
405 while (GET_CODE (addr
) == PLUS
)
407 if (GET_CODE (XEXP (addr
, 0)) == REG
)
408 addr
= XEXP (addr
, 0);
409 else if (GET_CODE (XEXP (addr
, 1)) == REG
)
410 addr
= XEXP (addr
, 1);
411 else if (GET_CODE (XEXP (addr
, 0)) == PLUS
)
412 addr
= XEXP (addr
, 0);
413 else if (GET_CODE (XEXP (addr
, 1)) == PLUS
)
414 addr
= XEXP (addr
, 1);
416 if (GET_CODE (addr
) == REG
)
422 /* Return the best assembler insn template
423 for moving operands[1] into operands[0] as a fullword. */
426 singlemove_string (operands
)
429 if (FPU_REG_P (operands
[0]) || FPU_REG_P (operands
[1]))
431 if (GREG_P (operands
[0]) || GREG_P (operands
[1]))
433 myabort (101); /* Not Supported yet !! */
437 return "fmov.s %1,%0";
440 return "mov.w %1,%0";
444 /* Output assembler code to perform a doubleword move insn
445 with operands OPERANDS. */
448 output_move_double (operands
)
452 { REGOP
, OFFSOP
, MEMOP
, PUSHOP
, POPOP
, CNSTOP
, RNDOP
}
455 rtx addreg0
= 0, addreg1
= 0;
457 /* First classify both operands. */
459 if (REG_P (operands
[0]))
461 else if (offsettable_memref_p (operands
[0]))
463 else if (GET_CODE (XEXP (operands
[0], 0)) == POST_INC
)
465 else if (GET_CODE (XEXP (operands
[0], 0)) == PRE_DEC
)
467 else if (GET_CODE (operands
[0]) == MEM
)
472 if (REG_P (operands
[1]))
474 else if (CONSTANT_P (operands
[1]))
476 else if (offsettable_memref_p (operands
[1]))
478 else if (GET_CODE (XEXP (operands
[1], 0)) == POST_INC
)
480 else if (GET_CODE (XEXP (operands
[1], 0)) == PRE_DEC
)
482 else if (GET_CODE (operands
[1]) == MEM
)
487 /* Check for the cases that the operand constraints are not
488 supposed to allow to happen. Abort if we get one,
489 because generating code for these cases is painful. */
491 if (optype0
== RNDOP
|| optype1
== RNDOP
)
494 /* If one operand is decrementing and one is incrementing
495 decrement the former register explicitly
496 and change that operand into ordinary indexing. */
498 if (optype0
== PUSHOP
&& optype1
== POPOP
)
500 operands
[0] = XEXP (XEXP (operands
[0], 0), 0);
501 output_asm_insn ("sub.w %#8,%0", operands
);
502 operands
[0] = gen_rtx (MEM
, DImode
, operands
[0]);
505 if (optype0
== POPOP
&& optype1
== PUSHOP
)
507 operands
[1] = XEXP (XEXP (operands
[1], 0), 0);
508 output_asm_insn ("sub.w %#8,%1", operands
);
509 operands
[1] = gen_rtx (MEM
, DImode
, operands
[1]);
513 /* If an operand is an unoffsettable memory ref, find a register
514 we can increment temporarily to make it refer to the second word. */
516 if (optype0
== MEMOP
)
517 addreg0
= find_addr_reg (operands
[0]);
519 if (optype1
== MEMOP
)
520 addreg1
= find_addr_reg (operands
[1]);
522 /* Ok, we can do one word at a time.
523 Normally we do the low-numbered word first,
524 but if either operand is autodecrementing then we
525 do the high-numbered word first.
527 In either case, set up in LATEHALF the operands to use
528 for the high-numbered word and in some cases alter the
529 operands in OPERANDS to be suitable for the low-numbered word. */
531 if (optype0
== REGOP
)
532 latehalf
[0] = gen_rtx (REG
, SImode
, REGNO (operands
[0]) + 1);
533 else if (optype0
== OFFSOP
)
534 latehalf
[0] = adj_offsettable_operand (operands
[0], 4);
536 latehalf
[0] = operands
[0];
538 if (optype1
== REGOP
)
539 latehalf
[1] = gen_rtx (REG
, SImode
, REGNO (operands
[1]) + 1);
540 else if (optype1
== OFFSOP
)
541 latehalf
[1] = adj_offsettable_operand (operands
[1], 4);
542 else if (optype1
== CNSTOP
)
544 if (GET_CODE (operands
[1]) == CONST_DOUBLE
)
545 split_double (operands
[1], &operands
[1], &latehalf
[1]);
546 else if (CONSTANT_P (operands
[1]))
547 latehalf
[1] = const0_rtx
;
550 latehalf
[1] = operands
[1];
552 /* If insn is effectively movd N(sp),-(sp) then we will do the
553 high word first. We should use the adjusted operand 1 (which is N+4(sp))
554 for the low word as well, to compensate for the first decrement of sp. */
555 if (optype0
== PUSHOP
556 && REGNO (XEXP (XEXP (operands
[0], 0), 0)) == STACK_POINTER_REGNUM
557 && reg_overlap_mentioned_p (stack_pointer_rtx
, operands
[1]))
558 operands
[1] = latehalf
[1];
560 /* If one or both operands autodecrementing,
561 do the two words, high-numbered first. */
563 /* Likewise, the first move would clobber the source of the second one,
564 do them in the other order. This happens only for registers;
565 such overlap can't happen in memory unless the user explicitly
566 sets it up, and that is an undefined circumstance. */
568 if (optype0
== PUSHOP
|| optype1
== PUSHOP
569 || (optype0
== REGOP
&& optype1
== REGOP
570 && REGNO (operands
[0]) == REGNO (latehalf
[1])))
572 /* Make any unoffsettable addresses point at high-numbered word. */
574 output_asm_insn ("add.w %#4,%0", &addreg0
);
576 output_asm_insn ("add.w %#4,%0", &addreg1
);
579 output_asm_insn (singlemove_string (latehalf
), latehalf
);
581 /* Undo the adds we just did. */
583 output_asm_insn ("sub.w %#4,%0", &addreg0
);
585 output_asm_insn ("sub.w %#4,%0", &addreg1
);
587 /* Do low-numbered word. */
588 return singlemove_string (operands
);
591 /* Normal case: do the two words, low-numbered first. */
593 output_asm_insn (singlemove_string (operands
), operands
);
595 /* Make any unoffsettable addresses point at high-numbered word. */
597 output_asm_insn ("add.w %#4,%0", &addreg0
);
599 output_asm_insn ("add.w %#4,%0", &addreg1
);
602 output_asm_insn (singlemove_string (latehalf
), latehalf
);
604 /* Undo the adds we just did. */
606 output_asm_insn ("sub.w %#4,%0", &addreg0
);
608 output_asm_insn ("sub.w %#4,%0", &addreg1
);
613 /* Move const_double to floating point register (DF) */
615 output_move_const_double (operands
)
618 int code
= standard_fpu_constant_p (operands
[1]);
620 if (FPU_REG_P (operands
[0]))
626 sprintf (buf
, "fmvr from%d,%%0.d", code
);
631 return "fmov %1,%0.d";
634 else if (GREG_P (operands
[0]))
637 xoperands
[0] = gen_rtx (REG
, SImode
, REGNO (operands
[0]) + 1);
638 xoperands
[1] = GEN_INT (CONST_DOUBLE_HIGH (operands
[1]));
639 output_asm_insn ("mov.w %1,%0", xoperands
);
640 operands
[1] = GEN_INT (CONST_DOUBLE_LOW (operands
[1]));
641 return "mov.w %1,%0";
645 return output_move_double (operands
); /* ?????? */
650 output_move_const_single (operands
)
653 int code
= standard_fpu_constant_p (operands
[1]);
656 if (FPU_REG_P (operands
[0]))
660 sprintf (buf
, "fmvr from%d,%%0.s", code
);
663 return "fmov.s %f1,%0";
666 return "mov.w %f1,%0";
670 /* Return nonzero if X, a CONST_DOUBLE, has a value that we can get
671 from the "fmvr" instruction of the Gmicro FPU.
672 The value, anded with 0xff, gives the code to use in fmovecr
673 to get the desired constant. */
675 u
.i
[0] = CONST_DOUBLE_LOW (x
);
676 u
.i
[1] = CONST_DOUBLE_HIGH (x
);
679 if (d
== 0.0) /* +0.0 */
681 /* Note: there are various other constants available
682 but it is a nuisance to put in their values here. */
683 if (d
== 1.0) /* +1.0 */
687 * Stuff that looks different if it's single or double
689 if (GET_MODE (x
) == SFmode
)
693 if (d
== (S_PI
/ 2.0))
712 if (d
== (D_PI
/ 2.0))
746 /* dest should be operand 0 */
747 /* imm should be operand 1 */
749 extern char *sub_imm_word ();
752 add_imm_word (imm
, dest
, immp
)
756 int is_reg
, short_ok
;
761 *immp
= GEN_INT (-imm
);
762 return sub_imm_word (-imm
, dest
);
766 return "mov:l.w #0,%0";
768 short_ok
= short_format_ok (dest
);
770 if (short_ok
&& imm
<= 8)
771 return "add:q %1,%0.w";
774 return "add:e %1,%0.w";
776 is_reg
= (GET_CODE (dest
) == REG
);
779 return "add:l %1,%0.w";
782 return "add:i %1,%0.w";
784 return "add %1,%0.w";
788 sub_imm_word (imm
, dest
, immp
)
792 int is_reg
, short_ok
;
794 if (imm
< 0 && imm
!= 0x80000000)
796 *immp
= GEN_INT (-imm
);
797 return add_imm_word (-imm
, dest
);
801 return "mov:z.w #0,%0";
803 short_ok
= short_format_ok (dest
);
805 if (short_ok
&& imm
<= 8)
806 return "sub:q %1,%0.w";
809 return "sub:e %1,%0.w";
811 is_reg
= (GET_CODE (dest
) == REG
);
814 return "sub:l %1,%0.w";
817 return "sub:i %1,%0.w";
819 return "sub %1,%0.w";
828 if (GET_CODE (x
) == REG
)
831 if (GET_CODE (x
) == MEM
832 && GET_CODE (XEXP (x
, 0)) == PLUS
)
834 x0
= XEXP (XEXP (x
, 0), 0);
835 x1
= XEXP (XEXP (x
, 0), 1);
836 return ((GET_CODE (x0
) == REG
838 && ((unsigned) (INTVAL (x1
) + 0x8000) < 0x10000))
840 (GET_CODE (x1
) == REG
842 && ((unsigned) (INTVAL (x0
) + 0x8000) < 0x10000)));
848 myoutput_sp_adjust (file
, op
, fsize
)
856 fprintf (file
, "\t%s:q #%d,sp.w\n", op
, fsize
);
857 else if (fsize
< 128)
858 fprintf (file
, "\t%s:e #%d,sp.w\n", op
, fsize
);
860 fprintf (file
, "\t%s:l #%d,sp.w\n", op
, fsize
);
865 mov_imm_word (imm
, dest
)
869 int is_reg
, short_ok
;
872 return "mov:z.w #0,%0";
874 short_ok
= short_format_ok (dest
);
876 if (short_ok
&& imm
> 0 && imm
<= 8)
877 return "mov:q %1,%0.w";
879 if (-128 <= imm
&& imm
< 128)
880 return "mov:e %1,%0.w";
882 is_reg
= (GET_CODE (dest
) == REG
);
885 return "mov:l %1,%0.w";
888 return "mov:i %1,%0.w";
890 return "mov %1,%0.w";
894 cmp_imm_word (imm
, dest
)
898 int is_reg
, short_ok
;
901 return "cmp:z.w #0,%0";
903 short_ok
= short_format_ok (dest
);
905 if (short_ok
&& imm
>0 && imm
<= 8)
906 return "cmp:q %1,%0.w";
908 if (-128 <= imm
&& imm
< 128)
909 return "cmp:e %1,%0.w";
911 is_reg
= (GET_CODE (dest
) == REG
);
914 return "cmp:l %1,%0.w";
917 return "cmp:i %1,%0.w";
919 return "cmp %1,%0.w";
927 return "mov:z.w #0,%-";
929 if (imm
> 0 && imm
<= 8)
930 return "mov:q %1,%-.w";
932 if (-128 <= imm
&& imm
< 128)
933 return "mov:e %1,%-.w";
935 return "mov:g %1,%-.w";
937 /* In some cases, g-format may be better than I format.??
938 return "mov %1,%0.w";
942 my_signed_comp (insn
)
947 my_insn
= NEXT_INSN (insn
);
948 if (GET_CODE (my_insn
) != JUMP_INSN
)
950 fprintf (stderr
, "my_signed_comp: Not Jump_insn ");
951 myabort (GET_CODE (my_insn
));
953 my_insn
= PATTERN (my_insn
);
954 if (GET_CODE (my_insn
) != SET
)
956 fprintf (stderr
, "my_signed_comp: Not Set ");
957 myabort (GET_CODE (my_insn
));
959 my_insn
= SET_SRC (my_insn
);
960 if (GET_CODE (my_insn
) != IF_THEN_ELSE
)
962 fprintf (stderr
, "my_signed_comp: Not if_then_else ");
963 myabort (GET_CODE (my_insn
));
965 switch (GET_CODE (XEXP (my_insn
, 0)))
980 fprintf (stderr
, "my_signed_comp: Not cccc ");
981 myabort (GET_CODE (XEXP (my_insn
, 0)));