Fix typos (missing closing parentheses)
[official-gcc.git] / gcc / config / ip2k / ip2k.c
blob7216ff2e335b74ad113e37792789b00b1b399d14
1 /* Subroutines used for code generation on Ubicom IP2022
2 Communications Controller.
3 Copyright (C) 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
4 Contributed by Red Hat, Inc and Ubicom, Inc.
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
13 GCC is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING. If not, write to
20 the Free Software Foundation, 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA. */
23 #include "config.h"
24 #include "system.h"
25 #include "coretypes.h"
26 #include "tm.h"
27 #include "rtl.h"
28 #include "regs.h"
29 #include "hard-reg-set.h"
30 #include "real.h"
31 #include "insn-config.h"
32 #include "conditions.h"
33 #include "insn-flags.h"
34 #include "output.h"
35 #include "insn-attr.h"
36 #include "insn-addr.h"
37 #include "flags.h"
38 #include "reload.h"
39 #include "tree.h"
40 #include "expr.h"
41 #include "optabs.h"
42 #include "toplev.h"
43 #include "obstack.h"
44 #include "function.h"
45 #include "recog.h"
46 #include "tm_p.h"
47 #include "target.h"
48 #include "target-def.h"
49 #include "basic-block.h"
51 /* There are problems with 'frame_pointer_needed'. If we force it
52 on, we either end up not eliminating uses of FP, which results in
53 SPILL register failures or we may end up with calculation errors in
54 the stack offsets. Isolate the decision process into a simple macro. */
55 #define CHAIN_FRAMES (frame_pointer_needed || FRAME_POINTER_REQUIRED)
57 static int ip2k_naked_function_p (tree);
58 #ifdef IP2K_MD_REORG_PASS
59 static void mdr_resequence_xy_yx (rtx);
60 static void mdr_pres_replace_and_recurse (rtx, rtx, rtx);
61 static void mdr_propagate_reg_equivs_sequence (rtx, rtx, rtx);
62 static void mdr_propagate_reg_equivs (rtx);
63 static int track_dp_reload (rtx , rtx *, int , int);
64 static void mdr_try_dp_reload_elim (rtx);
65 static void mdr_try_move_dp_reload (rtx);
66 static void mdr_try_move_pushes (rtx);
67 static void mdr_try_propagate_clr_sequence (rtx, unsigned int);
68 static void mdr_try_propagate_clr (rtx);
69 static void mdr_try_propagate_move_sequence (rtx, rtx, rtx);
70 static void mdr_try_propagate_move (rtx);
71 static void mdr_try_remove_redundant_insns (rtx);
72 static int track_w_reload (rtx, rtx *, int , int);
73 static void mdr_try_wreg_elim (rtx);
74 #endif /* IP2K_MD_REORG_PASS */
75 static void ip2k_reorg (void);
76 static int ip2k_check_can_adjust_stack_ref (rtx, int);
77 static void ip2k_adjust_stack_ref (rtx *, int);
78 static int ip2k_xexp_not_uses_reg_for_mem (rtx, unsigned int);
79 static tree ip2k_handle_progmem_attribute (tree *, tree, tree, int, bool *);
80 static tree ip2k_handle_fndecl_attribute (tree *, tree, tree, int, bool *);
81 static bool ip2k_rtx_costs (rtx, int, int, int *);
82 static int ip2k_address_cost (rtx);
83 static void ip2k_init_libfuncs (void);
84 static bool ip2k_return_in_memory (tree, tree);
85 static void ip2k_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode,
86 tree, int *, int);
88 const struct attribute_spec ip2k_attribute_table[];
91 /* Initialize the GCC target structure. */
92 #undef TARGET_ASM_ALIGNED_HI_OP
93 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
95 #undef TARGET_ASM_FUNCTION_PROLOGUE
96 #define TARGET_ASM_FUNCTION_PROLOGUE function_prologue
98 #undef TARGET_ASM_FUNCTION_EPILOGUE
99 #define TARGET_ASM_FUNCTION_EPILOGUE function_epilogue
101 #undef TARGET_ASM_UNIQUE_SECTION
102 #define TARGET_ASM_UNIQUE_SECTION unique_section
104 #undef TARGET_ATTRIBUTE_TABLE
105 #define TARGET_ATTRIBUTE_TABLE ip2k_attribute_table
107 #undef TARGET_RTX_COSTS
108 #define TARGET_RTX_COSTS ip2k_rtx_costs
109 #undef TARGET_ADDRESS_COST
110 #define TARGET_ADDRESS_COST ip2k_address_cost
112 #undef TARGET_MACHINE_DEPENDENT_REORG
113 #define TARGET_MACHINE_DEPENDENT_REORG ip2k_reorg
115 #undef TARGET_INIT_LIBFUNCS
116 #define TARGET_INIT_LIBFUNCS ip2k_init_libfuncs
118 #undef TARGET_RETURN_IN_MEMORY
119 #define TARGET_RETURN_IN_MEMORY ip2k_return_in_memory
121 #undef TARGET_SETUP_INCOMING_VARARGS
122 #define TARGET_SETUP_INCOMING_VARARGS ip2k_setup_incoming_varargs
124 struct gcc_target targetm = TARGET_INITIALIZER;
126 /* Prologue/Epilogue size in words. */
127 static int prologue_size;
128 static int epilogue_size;
130 /* compare and test instructions for the IP2K are materialized by
131 the conditional branch that uses them. This is because conditional
132 branches are skips over unconditional branches. */
133 rtx ip2k_compare_operands[3]; /* Additional operands for condition code. */
134 int ip2k_test_flag; /* Indicates Z, WREG contain condition code
135 information. */
137 /* Some ip2k patterns push a byte onto the stack and then access
138 SP-relative addresses. Since reload doesn't know about these
139 pushes, we must track them internally with a %< (push) or %> (pop)
140 indicator. */
141 static int ip2k_stack_delta;
143 /* Track if or how far our ip2k reorganization pass has run. */
144 int ip2k_reorg_in_progress = 0;
145 int ip2k_reorg_completed = 0;
146 int ip2k_reorg_split_dimode = 0;
147 int ip2k_reorg_split_simode = 0;
148 int ip2k_reorg_split_himode = 0;
149 int ip2k_reorg_split_qimode = 0;
150 int ip2k_reorg_merge_qimode = 0;
152 /* Set up local allocation order. */
154 void
155 ip2k_init_local_alloc (int *rao)
157 static const int alloc_order[] = REG_ALLOC_ORDER;
159 memcpy (rao, alloc_order, sizeof (alloc_order));
162 /* Returns the number of bytes of arguments automatically
163 popped when returning from a subroutine call.
164 FUNDECL is the declaration node of the function (as a tree),
165 FUNTYPE is the data type of the function (as a tree),
166 or for a library call it is an identifier node for the subroutine name.
167 SIZE is the number of bytes of arguments passed on the stack. */
170 ip2k_return_pops_args (tree fundecl ATTRIBUTE_UNUSED, tree funtype, int size)
172 if (TREE_CODE (funtype) == IDENTIFIER_NODE)
173 return size;
175 if (TYPE_ARG_TYPES (funtype) == NULL_TREE
176 || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype))) == void_type_node))
177 return size;
179 return 0;
182 /* Return nonzero if FUNC is a naked function. */
184 static int
185 ip2k_naked_function_p (tree func)
187 tree a;
189 if (TREE_CODE (func) != FUNCTION_DECL)
190 abort ();
192 a = lookup_attribute ("naked", DECL_ATTRIBUTES (func));
193 return a != NULL_TREE;
196 /* Output function prologue. */
197 void
198 function_prologue (FILE *file, HOST_WIDE_INT size)
200 int leaf_func_p;
201 int main_p;
202 int reg;
203 rtx operands[2];
205 prologue_size = epilogue_size = 0;
207 if (ip2k_naked_function_p (current_function_decl))
209 fprintf (file, "/* prologue: naked */\n");
210 return;
213 leaf_func_p = leaf_function_p ();
214 main_p = MAIN_NAME_P (DECL_NAME (current_function_decl));
216 /* For now, we compute all these facts about the function, but don't
217 take any action based on the information. */
219 prologue_size = 0;
220 fprintf (file, "/* prologue: frame size=" HOST_WIDE_INT_PRINT_DEC " */\n",
221 size);
223 /* Unless we're a leaf we need to save the return PC. */
225 if (! leaf_func_p)
227 OUT_AS1 (push, calll);
228 OUT_AS1 (push, callh);
229 prologue_size += 4;
232 /* We need to save the old FP and set the new FP pointing at the
233 stack location where the old one is saved. Note that because of
234 post-decrement addressing, the SP is off-by-one after the
235 push, so we harvest the SP address BEFORE we push the MSBs of
236 the FP. */
237 if (CHAIN_FRAMES)
239 OUT_AS1 (push, REG_FP+1); /* Save old LSBs. */
240 OUT_AS2 (mov, w, spl);
241 OUT_AS2 (mov, REG_FP+1, w); /* SPL -> FPL */
243 OUT_AS2 (mov, w, sph); /* Freeze SP MSBs */
244 OUT_AS1 (push, REG_FP); /* Save old MSBs */
245 OUT_AS2 (mov, REG_FP, w); /* SPH -> FPH */
246 prologue_size += 12;
249 for (reg = (CHAIN_FRAMES) ? (REG_FP - 1) : (REG_FP + 1);
250 reg > 0; --reg)
252 if (regs_ever_live[reg] && ! call_used_regs[reg])
254 fprintf (file, "\t" AS1 (push,%s) "\n", reg_names[reg]);
255 prologue_size += 2;
259 if (size)
261 operands[0] = GEN_INT (size);
263 switch (size & 0xff)
265 case 0:
266 break;
267 case 1:
268 OUT_AS1 (dec, spl);
269 prologue_size += 2;
270 break;
271 default:
272 OUT_AS2 (mov, w, %L0);
273 OUT_AS2 (sub, spl, w);
274 prologue_size += 4;
277 switch (size & 0xff00)
279 case 0:
280 break;
281 case 0x100:
282 OUT_AS1 (dec, sph);
283 prologue_size += 2;
284 break;
285 default:
286 if ((size & 0xff) != ((size >> 8) & 0xff))
287 OUT_AS2 (mov, w, %H0); /* Otherwise W has value we want. */
288 OUT_AS2 (sub, sph, w);
289 prologue_size += 4;
293 /* XXX - change this to use the carry-propagating subtract trick. */
294 if (flag_stack_check)
296 OUT_AS2 (mov, w, sph);
297 OUT_AS2 (cmp, w, #%%hi8data(_end));
298 OUT_AS1 (sc, ); /* C == 0 -> hi8(edata) < sph */
299 OUT_AS1 (page, 1f);
300 OUT_AS1 (jmp, 1f);
301 OUT_AS1 (sz, ); /* Z == 1 -> look at low byte */
302 OUT_AS1 (page,0f);
303 OUT_AS1 (jmp,0f); /* sp < edata, so raise stack fault */
304 OUT_AS2 (mov, w, spl);
305 OUT_AS2 (cmp, w, #%%lo8data(_end));
306 OUT_AS1 (sc,); /* C==1 -> lo8(edata) >= spl */
307 OUT_AS1 (page,1f);
308 OUT_AS1 (jmp,1f);
309 OUT_AS1 (0:,);
310 output_asm_insn ("push\t$ff", operands);
311 OUT_AS1 (system,);
312 OUT_AS1 (1:, );
313 prologue_size += 30;
317 /* Output function epilogue. */
318 void
319 function_epilogue (FILE *file, HOST_WIDE_INT size)
321 int leaf_func_p;
322 int reg,savelimit;
323 rtx operands[2]; /* Dummy used by OUT_ASn */
324 int args_locals_size = current_function_args_size;
325 int saved_regs_p = 0;
326 int need_ret = 1;
328 /* Use this opportunity to reset the reorg flags! */
329 ip2k_reorg_in_progress = 0;
330 ip2k_reorg_completed = 0;
331 ip2k_reorg_split_dimode = 0;
332 ip2k_reorg_split_simode = 0;
333 ip2k_reorg_split_himode = 0;
334 ip2k_reorg_split_qimode = 0;
335 ip2k_reorg_merge_qimode = 0;
337 if (ip2k_naked_function_p (current_function_decl))
339 fprintf (file, "/* epilogue: naked */\n");
340 return;
343 leaf_func_p = leaf_function_p ();
344 epilogue_size = 0;
345 fprintf (file, "/* epilogue: frame size=" HOST_WIDE_INT_PRINT_DEC " */\n",
346 size);
348 savelimit = (CHAIN_FRAMES) ? REG_FP : (REG_FP + 2);
349 for (reg = 0; reg < savelimit; reg++)
350 if (regs_ever_live[reg] && ! call_used_regs[reg])
352 saved_regs_p = 1;
353 break;
356 if (size)
358 if (leaf_func_p && !CHAIN_FRAMES && !saved_regs_p
359 && current_function_pops_args)
360 args_locals_size = current_function_args_size + size;
361 else
363 operands[0] = GEN_INT (size);
365 switch (size & 0xff)
367 default:
368 OUT_AS2 (mov, w, %L0);
369 OUT_AS2 (add, spl, w);
370 epilogue_size += 4;
371 /* fall-through */
372 case 0:
373 break;
374 case 1:
375 OUT_AS1 (inc, spl);
376 epilogue_size += 2;
379 switch (size & 0xff00)
381 default:
382 if ((size & 0xff) != ((size >> 8) & 0xff))
383 OUT_AS2 (mov, w, %H0);
384 OUT_AS2 (add, sph, w);
385 epilogue_size += 4;
386 /* fall-through */
387 case 0:
388 break;
389 case 0x100:
390 OUT_AS1 (inc, sph);
391 epilogue_size += 2;
396 for (reg = 0; reg < savelimit; reg++)
398 if (regs_ever_live[reg] && ! call_used_regs[reg])
400 fprintf (file, "\t" AS1 (pop,%s) "\n", reg_names[reg]);
401 prologue_size += 2;
405 if (CHAIN_FRAMES
406 && ! (current_function_pops_args
407 && current_function_args_size >= 2
408 && current_function_args_size < 0x100))
410 OUT_AS1 (pop, REG_FP);
411 OUT_AS1 (pop, REG_FP+1);
412 epilogue_size += 4;
415 if (! leaf_func_p)
417 if (current_function_pops_args
418 && current_function_args_size >= 2
419 && current_function_args_size < 0x100)
421 if (current_function_args_size == 2)
423 if (CHAIN_FRAMES)
425 OUT_AS1 (page, __fp_pop2_args_ret);
426 OUT_AS1 (jmp, __fp_pop2_args_ret);
428 else
430 OUT_AS1 (page, __pop2_args_ret);
431 OUT_AS1 (jmp, __pop2_args_ret);
433 epilogue_size += 4;
435 else
437 operands[0] = GEN_INT (current_function_args_size);
438 OUT_AS2 (mov, w, %L0);
439 if (CHAIN_FRAMES)
441 OUT_AS1 (page, __fp_pop_args_ret);
442 OUT_AS1 (jmp, __fp_pop_args_ret);
444 else
446 OUT_AS1 (page, __pop_args_ret);
447 OUT_AS1 (jmp, __pop_args_ret);
449 epilogue_size += 6;
451 need_ret = 0;
453 else
455 OUT_AS1 (pop, callh);
456 OUT_AS1 (pop, calll);
457 epilogue_size += 4;
460 else
462 if (current_function_pops_args
463 && args_locals_size >= 2
464 && args_locals_size < 0x100)
466 if (args_locals_size == 2)
468 if (CHAIN_FRAMES)
470 OUT_AS1 (page, __leaf_fp_pop2_args_ret);
471 OUT_AS1 (jmp, __leaf_fp_pop2_args_ret);
472 epilogue_size += 4;
473 need_ret = 0;
476 else
478 operands[0] = GEN_INT (args_locals_size);
479 if (CHAIN_FRAMES)
481 OUT_AS2 (mov, w, %L0);
482 OUT_AS1 (page, __leaf_fp_pop_args_ret);
483 OUT_AS1 (jmp, __leaf_fp_pop_args_ret);
484 epilogue_size += 6;
485 need_ret = 0;
491 if (current_function_pops_args && args_locals_size && need_ret)
493 operands[0] = GEN_INT (args_locals_size);
495 switch (args_locals_size & 0xff)
497 default:
498 OUT_AS2 (mov, w, %L0);
499 OUT_AS2 (add, spl, w);
500 epilogue_size += 4;
501 /* fall-through */
503 case 0:
504 break;
506 case 1:
507 OUT_AS1 (inc, spl);
508 epilogue_size += 2;
511 switch (args_locals_size & 0xff00)
513 default:
514 if ((args_locals_size & 0xff) != ((args_locals_size >> 8) & 0xff))
515 OUT_AS2 (mov, w, %H0);
516 OUT_AS2 (add, sph, w);
517 epilogue_size += 4;
518 /* fall-through */
520 case 0:
521 break;
523 case 0x100:
524 OUT_AS1 (inc, sph);
525 epilogue_size += 2;
529 if (need_ret)
531 OUT_AS1 (ret,);
532 epilogue_size += 2;
535 fprintf (file, "/* epilogue end (size=%d) */\n", epilogue_size);
538 /* Return the difference between the registers after the function
539 prologue.
541 Stack Frame grows down:
543 ARGUMENTS
544 <------ AP ($102:$103)
545 RETURN PC (unless leaf function)
546 SAVEDFP (if needed)
547 <------ FP [HARD_FRAME_POINTER] ($FD:$FE)
548 SAVED REGS
549 <------ VFP [$100:$101]
550 STACK ALLOCATION
551 <------ SP ($6:$7) */
553 ip2k_init_elim_offset (int from, int to)
555 int leaf_func_p = leaf_function_p ();
556 int no_saved_pc = leaf_func_p
557 || ip2k_naked_function_p (current_function_decl);
558 int offset;
559 int reg;
560 int reglimit;
562 if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
563 return get_frame_size () + 1;
565 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
566 return (CHAIN_FRAMES ? 2 : 0) + (no_saved_pc ? 0 : 2);
568 /* Count all the registers we had to preserve. */
570 reglimit = CHAIN_FRAMES ? REG_FP : (REG_FP + 2);
571 for (offset = 0,reg = 0; reg < reglimit; ++reg)
573 if ((regs_ever_live[reg] && ! call_used_regs[reg]))
575 ++offset;
579 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
580 return -offset;
582 if (from == HARD_FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
583 /* Add in the stack-local variables. */
584 return offset + get_frame_size () + 1;
586 if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
587 /* Add stack-locals plus saved FP and PC. */
588 return offset + get_frame_size () + 1
589 + (CHAIN_FRAMES ? 2 : 0) + (no_saved_pc ? 0 : 2);
591 abort (); /* Unanticipated elimination. */
594 /* Return nonzero if X (an RTX) is a legitimate memory address on the target
595 machine for a memory operand of mode MODE. */
598 legitimate_address_p (enum machine_mode mode, rtx x, int strict)
600 int off;
602 if (GET_CODE (x) == SUBREG)
603 x = SUBREG_REG (x);
605 switch (GET_CODE (x))
607 case REG:
608 /* IP allows indirection without offset - only okay if
609 we don't require access to multiple bytes. */
610 if (REGNO (x) == REG_IP)
611 return (GET_MODE_SIZE (mode) == 1) ? 'R' : 0;
613 /* We can indirect through DP or SP register. */
614 if (strict ? REG_OK_FOR_BASE_STRICT_P (x)
615 : REG_OK_FOR_BASE_NOSTRICT_P (x))
616 return 'S';
617 break;
619 case PLUS:
620 /* Offsets from DP or SP are legal in the range 0..127 */
622 rtx op1, op2;
624 op1 = XEXP (x, 0);
625 op2 = XEXP (x, 1);
627 if (REG_P (op2) && ! REG_P (op1))
629 rtx tmp = op1;
630 op1 = op2;
631 op2 = tmp;
634 /* Don't let anything but R+I through.. */
635 if (! REG_P (op1)
636 || REG_P (op2)
637 || GET_CODE (op2) != CONST_INT)
638 return 0;
640 switch (REGNO (op1))
642 case REG_DP: /* only 0..127 displacement */
643 case REG_SP:
644 off = 2 * GET_MODE_SIZE (mode);
645 if (! off)
646 off = 1;
648 if (INTVAL (op2) < 0 || INTVAL (op2) > (128 - off))
649 return 0; /* Positive must be small enough that after
650 splitting all pieces are addressed. */
651 return 'S'; /* Safe displacement. */
653 case REG_IP:
654 if (GET_MODE_SIZE (mode) <= 1 && INTVAL (op2) == 0)
655 return (GET_MODE_SIZE (mode) == 1) ? 'R' : 0;
656 return 0;
658 case REG_AP:
659 case REG_FP:
660 case REG_VFP:
661 default:
662 if (strict || ! REG_OK_FOR_BASE_NOSTRICT_P (op1))
663 return 0; /* Allow until reload. */
665 return 'S';
668 break;
670 case CONST:
671 case SYMBOL_REF:
672 /* We always allow references to things in code space. */
673 return is_regfile_address (x) ? 0 : 'C';
675 case LABEL_REF:
676 return 'L';
678 default:
679 return 0;
682 return 0;
685 /* Is ADDR mode dependent? */
687 ip2k_mode_dependent_address (rtx addr)
689 switch (GET_CODE (addr))
691 case POST_INC:
692 case POST_DEC:
693 case PRE_INC:
694 case PRE_DEC:
695 return 1;
697 case REG:
698 return (REGNO (addr) == REG_IP); /* Can't do IP displaced addresses. */
700 default:
701 return 0; /* Assume no dependency. */
705 /* Attempts to replace X with a valid
706 memory address for an operand of mode MODE. */
709 legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
710 enum machine_mode mode ATTRIBUTE_UNUSED, rtx scratch)
712 rtx reg;
714 /* You might think that we could split up a symbolic address by
715 adding the HIGH 8 bits and doing a displacement off the dp. But
716 because we only have 7 bits of offset, that doesn't actually
717 help. So only constant displacements are likely to obtain an
718 advantage. */
720 if (GET_CODE (x) == PLUS && REG_P (XEXP (x, 0))
721 && GET_CODE (XEXP (x, 1)) == CONST_INT
722 && ! CONST_OK_FOR_LETTER_P (INTVAL (XEXP (x, 1)), 'K'))
724 int offset = INTVAL (XEXP (x, 1));
726 reg = scratch ? scratch : gen_reg_rtx (Pmode);
728 emit_insn (gen_rtx_SET (VOIDmode, reg,
729 gen_rtx_PLUS (Pmode, XEXP (x, 0),
730 GEN_INT (offset & 0xffc0))));
731 x = gen_rtx_PLUS (Pmode, reg, GEN_INT (offset & 0x3f));
734 return x; /* We don't have any other tricks. */
737 /* Determine if X is a 'data' address or a code address. All static
738 data and stack variables reside in data memory. Only code is believed
739 to be in PRAM or FLASH. */
741 is_regfile_address (rtx x)
743 while (1)
744 switch (GET_CODE (x))
746 case SYMBOL_REF:
747 return ! SYMBOL_REF_FUNCTION_P (x); /* Declared as function. */
748 case CONST:
749 case PLUS:
750 x = XEXP (x, 0);
751 break;
752 case CONST_INT:
753 case REG:
754 case SUBREG:
755 return 1;
756 case LABEL_REF:
757 return 0;
758 default:
759 return 0;
762 return 0;
765 /* Output ADDR to FILE as address. */
767 void
768 print_operand_address (FILE *file, rtx addr)
770 switch (GET_CODE (addr))
772 case SUBREG:
773 addr = alter_subreg (&addr);
774 /* fall-through */
776 case REG:
777 fprintf (file, "(%s)",
778 REGNO (addr) == REG_DP ? "DP"
779 : REGNO (addr) == REG_SP ? "SP"
780 : REGNO (addr) == REG_IP ? "IP"
781 : REGNO (addr) == REG_VFP ? "VFP" /* Should never see this */
782 : REGNO (addr) == REG_AP ? "AP" /* or this, either. */
783 : reg_names[REGNO (addr)]);
784 break;
786 case PRE_DEC:
787 case POST_INC:
788 abort ();
789 break;
791 case CONST:
792 addr = XEXP (addr, 0);
793 print_operand_address (file, XEXP (addr, 0));
794 fprintf (file, "+");
795 print_operand_address (file, XEXP (addr, 1));
796 return;
798 case LO_SUM:
799 if (is_regfile_address (XEXP (addr, 1)))
800 fprintf (file, "%%lo8data(");
801 else
802 fprintf (file, "%%lo8insn(");
803 print_operand_address (file, XEXP (addr, 1));
804 fprintf (file, ")");
805 print_operand_address (file, XEXP (addr, 0));
806 break;
808 case PLUS: /* Ought to be stack or dp references. */
809 if (XEXP (addr, 1) == const0_rtx
810 && GET_CODE (XEXP (addr, 0)) == PLUS)
812 print_operand_address (file, XEXP (addr, 0));
813 return;
816 if (! REG_P (XEXP (addr, 0)) || REGNO (XEXP (addr, 0)) != REG_IP)
817 print_operand_address (file, XEXP (addr, 1)); /* const */
818 print_operand_address (file, XEXP (addr, 0)); /* (reg) */
819 break;
821 case HIGH:
822 if (is_regfile_address (XEXP (addr, 0)))
823 fprintf (file, "%%hi8data(");
824 else
825 fprintf (file, "%%hi8insn(");
826 output_addr_const (file, XEXP (addr, 0));
827 fprintf (file, ")");
828 break;
830 default:
831 output_addr_const (file, addr);
836 /* Output X as assembler operand to file FILE. */
838 void
839 print_operand (FILE *file, rtx x, int code)
841 int abcd = 0;
842 unsigned long value;
844 switch (code)
846 case '<': /* Push */
847 ip2k_stack_delta++;
848 return;
850 case '>': /* Pop */
851 ip2k_stack_delta--;
852 return;
854 case 'A':
855 case 'B':
856 case 'C':
857 case 'D':
858 abcd = code - 'A';
859 break;
861 case 'H':
862 abcd = 0;
863 break;
865 case 'L':
866 abcd = 1;
867 break;
869 case 'S':
870 case 'T':
871 case 'U':
872 case 'V':
873 case 'W':
874 case 'X':
875 case 'Y':
876 case 'Z':
877 abcd = code - 'S';
879 default:
880 break;
883 if (ip2k_short_operand (x, GET_MODE (x))
884 && ip2k_address_uses_reg_p (x, REG_SP))
885 /* An SP-relative address needs to account for interior stack
886 pushes that reload didn't know about when it calculated the
887 stack offset. */
888 abcd += ip2k_stack_delta;
890 switch (GET_CODE (x))
892 case SUBREG:
893 x = alter_subreg (&x);
894 /* fall-through */
896 case REG:
897 fprintf (file, reg_names[true_regnum (x) + abcd]);
898 break;
900 case CONST_INT:
901 switch (code)
903 case 'x':
904 fprintf (file, "$%x", (int)(INTVAL (x) & 0xffff));
905 break;
907 case 'b':
908 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x)); /* bit selector */
909 break;
911 case 'e': /* "1 << n" - e.g. "exp" */
912 fprintf (file, "#%d", 1 << INTVAL (x));
913 break;
915 case 'A':
916 case 'B':
917 case 'C':
918 case 'D':
919 value = INTVAL (x);
920 value >>= 8 * (3 - abcd);
921 value &= 0xff;
923 fprintf (file, "#%ld", value);
924 break;
926 case 'H':
927 fprintf (file, "#%d", (int)((INTVAL (x) >> 8) & 0xff));
928 break;
930 case 'L':
931 fprintf (file, "#%d", (int)(INTVAL (x) & 0xff));
932 break;
934 case 'S':
935 case 'T':
936 case 'U':
937 case 'V':
938 case 'W':
939 case 'X':
940 case 'Y':
941 case 'Z':
942 value = ((unsigned long long)INTVAL (x)) >> (8 * (7 - abcd)) & 0xff;
943 fprintf (file, "#%ld", value);
944 break;
946 default:
947 fprintf (file, "#" HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
949 break;
951 case SYMBOL_REF:
952 case LABEL_REF:
953 case CODE_LABEL:
954 case CONST:
955 switch (code)
957 case 'A':
958 case 'B':
959 case 'C':
960 case 'D':
961 case 'S':
962 case 'T':
963 case 'U':
964 case 'V':
965 case 'W':
966 case 'X':
967 case 'Y':
968 case 'Z':
969 abort (); /* Probably an error. */
970 break;
972 case 'H':
973 fprintf (file, "#%s(",
974 is_regfile_address (x) ? "%hi8data"
975 : "%hi8insn");
976 print_operand_address (file, x);
977 fputc (')', file);
978 break;
980 case 'L':
981 fprintf (file, "#%s(",
982 is_regfile_address (x) ? "%lo8data"
983 : "%lo8insn");
984 print_operand_address (file, x);
985 fputc (')', file);
986 break;
988 default:
989 print_operand_address (file, x);
991 break;
993 case MEM:
995 rtx addr = XEXP (x, 0);
997 if (GET_CODE (addr) == SUBREG)
998 addr = alter_subreg (&x);
1000 if (CONSTANT_P (addr) && abcd)
1002 fputc ('(', file);
1003 print_operand_address (file, addr);
1004 fprintf (file, ")+%d", abcd);
1006 else if (abcd)
1008 switch (GET_CODE (addr))
1010 case PLUS:
1011 abcd += INTVAL (XEXP (addr, 1));
1013 /* Worry about (plus (plus (reg DP) (const_int 10))
1014 (const_int 0)) */
1015 if (GET_CODE (XEXP (addr, 0)) == PLUS)
1017 addr = XEXP (addr, 0);
1018 abcd += INTVAL (XEXP (addr, 1));
1021 fprintf (file, "%d", abcd);
1022 print_operand_address (file, XEXP (addr, 0));
1023 break;
1025 case REG:
1026 default:
1027 fprintf (file, "%d", abcd);
1028 print_operand_address (file, addr);
1031 else if (GET_CODE (addr) == REG
1032 && (REGNO (addr) == REG_DP || REGNO (addr) == REG_SP))
1034 fprintf (file, "0");
1035 print_operand_address (file, addr);
1037 else
1038 print_operand_address (file, addr);
1040 break;
1042 case CONST_DOUBLE:
1043 /* Is this an integer or a floating point value? */
1044 if (GET_MODE (x) == VOIDmode)
1046 switch (code)
1048 case 'S':
1049 case 'T':
1050 case 'U':
1051 case 'V':
1052 value = CONST_DOUBLE_HIGH (x);
1053 value >>= 8 * (3 - abcd);
1054 value &= 0xff;
1056 fprintf (file, "#%ld", value);
1057 break;
1059 case 'W':
1060 case 'X':
1061 case 'Y':
1062 case 'Z':
1063 value = CONST_DOUBLE_LOW (x);
1064 value >>= 8 * (7 - abcd);
1065 value &= 0xff;
1067 fprintf (file, "#%ld", value);
1068 break;
1072 else
1074 REAL_VALUE_TYPE rv;
1076 REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
1077 REAL_VALUE_TO_TARGET_SINGLE (rv, value);
1078 fprintf (file, "0x%lx", value);
1080 break;
1082 default:
1083 fatal_insn ("bad operand", x);
1087 /* Remember the operands for the compare. */
1088 const char *
1089 ip2k_set_compare (rtx x, rtx y)
1091 ip2k_compare_operands[0] = x;
1092 ip2k_compare_operands[1] = y;
1093 return "";
1096 /* Emit the code for sCOND instructions. */
1097 const char *
1098 ip2k_gen_sCOND (rtx insn ATTRIBUTE_UNUSED, enum rtx_code code, rtx dest)
1100 #define operands ip2k_compare_operands
1101 enum machine_mode mode;
1103 operands[2] = dest;
1105 mode = GET_MODE (operands[0]);
1106 if ((mode != QImode) && (mode != HImode)
1107 && (mode != SImode) && (mode != DImode))
1108 mode = GET_MODE (operands[1]);
1110 /* We have a fast path for a specific type of QImode compare. We ought
1111 to extend this for larger cases too but that wins less frequently and
1112 introduces a lot of complexity. */
1113 if (mode == QImode
1114 && !rtx_equal_p (operands[0], operands[2])
1115 && !rtx_equal_p (operands[1], operands[2])
1116 && (! REG_P (operands[2])
1117 || (ip2k_xexp_not_uses_reg_p (operands[0], REGNO (operands[2]), 1)
1118 && ip2k_xexp_not_uses_reg_p (operands[1],
1119 REGNO (operands[2]), 1))))
1121 OUT_AS1 (clr, %2);
1122 if (immediate_operand (operands[1], QImode)
1123 && ((INTVAL (operands[1]) & 0xff) == 0xff))
1125 if (code == EQ)
1126 OUT_AS2 (incsnz, w, %0);
1127 else
1128 OUT_AS2 (incsz, w, %0);
1130 else if (immediate_operand (operands[1], QImode)
1131 && ((INTVAL (operands[1]) & 0xff) == 0x01))
1133 if (code == EQ)
1134 OUT_AS2 (decsnz, w, %0);
1135 else
1136 OUT_AS2 (decsz, w, %0);
1138 else if (ip2k_compare_operands[1] == const0_rtx)
1140 OUT_AS2 (mov, w, %0);
1141 if (code == EQ)
1142 OUT_AS1 (snz,);
1143 else
1144 OUT_AS1 (sz,);
1146 else
1148 OUT_AS2 (mov, w, %0);
1149 if (code == EQ)
1150 OUT_AS2 (csne, w, %1);
1151 else
1152 OUT_AS2 (cse, w, %1);
1154 OUT_AS1 (inc, %2);
1156 else
1158 if (ip2k_compare_operands[1] == const0_rtx)
1160 switch (mode)
1162 case QImode:
1163 OUT_AS2 (mov, w, %0);
1164 break;
1166 case HImode:
1167 OUT_AS2 (mov, w, %H0);
1168 OUT_AS2 (or, w, %L0);
1169 break;
1171 case SImode:
1172 OUT_AS2 (mov, w, %A0);
1173 OUT_AS2 (or, w, %B0);
1174 OUT_AS2 (or, w, %C0);
1175 OUT_AS2 (or, w, %D0);
1176 break;
1178 case DImode:
1179 OUT_AS2 (mov, w, %S0);
1180 OUT_AS2 (or, w, %T0);
1181 OUT_AS2 (or, w, %U0);
1182 OUT_AS2 (or, w, %V0);
1183 OUT_AS2 (or, w, %W0);
1184 OUT_AS2 (or, w, %X0);
1185 OUT_AS2 (or, w, %Y0);
1186 OUT_AS2 (or, w, %Z0);
1187 break;
1189 default:
1190 abort ();
1193 else
1195 switch (mode)
1197 case QImode:
1198 OUT_AS2 (mov, w, %1);
1199 OUT_AS2 (cmp, w, %0);
1200 break;
1202 case HImode:
1203 OUT_AS2 (mov, w, %H1);
1204 OUT_AS2 (cmp, w, %H0);
1205 OUT_AS1 (sz,);
1206 OUT_AS1 (page, 2f);
1207 OUT_AS1 (jmp, 2f);
1208 OUT_AS2 (mov, w, %L1);
1209 OUT_AS2 (cmp, w, %L0);
1210 OUT_AS1 (2:,);
1211 break;
1213 case SImode:
1214 if (code == EQ)
1216 OUT_AS2 (mov, w, #1);
1217 OUT_AS2 (mov, mulh, w);
1219 else
1220 OUT_AS1 (clr, mulh);
1221 OUT_AS2 (mov, w, %A1);
1222 OUT_AS2 (cse, w, %A0);
1223 OUT_AS1 (page, 2f);
1224 OUT_AS1 (jmp, 2f);
1225 OUT_AS2 (mov, w, %B1);
1226 OUT_AS2 (cse, w, %B0);
1227 OUT_AS1 (page, 2f);
1228 OUT_AS1 (jmp, 2f);
1229 OUT_AS2 (mov, w, %C1);
1230 OUT_AS2 (cse, w, %C0);
1231 OUT_AS1 (page, 2f);
1232 OUT_AS1 (jmp, 2f);
1233 OUT_AS2 (mov, w, %D1);
1234 OUT_AS2 (cse, w, %D0);
1235 OUT_AS1 (2:,);
1236 if (code == EQ)
1237 OUT_AS1 (dec, mulh);
1238 else
1239 OUT_AS1 (inc, mulh);
1240 OUT_AS2 (mov, w, mulh);
1241 OUT_AS2 (mov, %2, w);
1242 return "";
1244 case DImode:
1245 if (code == EQ)
1247 OUT_AS2 (mov, w, #1);
1248 OUT_AS2 (mov, mulh, w);
1250 else
1251 OUT_AS1 (clr, mulh);
1252 OUT_AS2 (mov, w, %S1);
1253 OUT_AS2 (cse, w, %S0);
1254 OUT_AS1 (page, 2f);
1255 OUT_AS1 (jmp, 2f);
1256 OUT_AS2 (mov, w, %T1);
1257 OUT_AS2 (cse, w, %T0);
1258 OUT_AS1 (page, 2f);
1259 OUT_AS1 (jmp, 2f);
1260 OUT_AS2 (mov, w, %U1);
1261 OUT_AS2 (cse, w, %U0);
1262 OUT_AS1 (page, 2f);
1263 OUT_AS1 (jmp, 2f);
1264 OUT_AS2 (mov, w, %V1);
1265 OUT_AS2 (cse, w, %V0);
1266 OUT_AS1 (page, 2f);
1267 OUT_AS1 (jmp, 2f);
1268 OUT_AS2 (mov, w, %W1);
1269 OUT_AS2 (cse, w, %W0);
1270 OUT_AS1 (page, 2f);
1271 OUT_AS1 (jmp, 2f);
1272 OUT_AS2 (mov, w, %X1);
1273 OUT_AS2 (cse, w, %X0);
1274 OUT_AS1 (page, 2f);
1275 OUT_AS1 (jmp, 2f);
1276 OUT_AS2 (mov, w, %Y1);
1277 OUT_AS2 (cse, w, %Y0);
1278 OUT_AS1 (page, 2f);
1279 OUT_AS1 (jmp, 2f);
1280 OUT_AS2 (mov, w, %Z1);
1281 OUT_AS2 (cse, w, %Z0);
1282 OUT_AS1 (2:,);
1283 if (code == EQ)
1284 OUT_AS1 (dec, mulh);
1285 else
1286 OUT_AS1 (inc, mulh);
1287 OUT_AS2 (mov, w, mulh);
1288 OUT_AS2 (mov, %2, w);
1289 return "";
1291 default:
1292 abort ();
1295 OUT_AS2 (mov, w, #0);
1296 if (code == EQ)
1297 OUT_AS1 (snz,);
1298 else
1299 OUT_AS1 (sz,);
1300 OUT_AS1 (inc, wreg);
1301 OUT_AS2 (mov, %2, w);
1304 return "";
1305 #undef operands
1308 const char *
1309 ip2k_gen_signed_comp_branch (rtx insn, enum rtx_code code, rtx label)
1311 #define operands ip2k_compare_operands
1312 enum machine_mode mode;
1313 int can_use_skip = 0;
1314 rtx ninsn;
1316 operands[2] = label;
1318 mode = GET_MODE (operands[0]);
1319 if ((mode != QImode) && (mode != HImode)
1320 && (mode != SImode) && (mode != DImode))
1321 mode = GET_MODE (operands[1]);
1323 /* Look for situations where we can just skip the next instruction instead
1324 of skipping and then branching! */
1325 ninsn = next_real_insn (insn);
1326 if (ninsn
1327 && (recog_memoized (ninsn) >= 0)
1328 && get_attr_skip (ninsn) == SKIP_YES)
1330 rtx skip_tgt = next_nonnote_insn (next_real_insn (insn));
1332 /* The first situation is where the target of the jump is one insn
1333 after the jump insn and the insn being jumped is only one machine
1334 opcode long. */
1335 if (label == skip_tgt)
1336 can_use_skip = 1;
1337 else
1339 /* If our skip target is in fact a code label then we ignore the
1340 label and move onto the next useful instruction. Nothing we do
1341 here has any effect on the use of skipping instructions. */
1342 if (GET_CODE (skip_tgt) == CODE_LABEL)
1343 skip_tgt = next_nonnote_insn (skip_tgt);
1345 /* The second situation is where we have something of the form:
1347 test_condition
1348 skip_conditional
1349 page/jump label
1351 optional_label (this may or may not exist):
1352 skippable_insn
1353 page/jump label
1355 In this case we can eliminate the first "page/jump label". */
1356 if (GET_CODE (skip_tgt) == JUMP_INSN)
1358 rtx set = single_set (skip_tgt);
1359 if (GET_CODE (XEXP (set, 0)) == PC
1360 && GET_CODE (XEXP (set, 1)) == LABEL_REF
1361 && label == JUMP_LABEL (skip_tgt))
1362 can_use_skip = 2;
1367 /* gcc is a little braindead and does some rather stateful things while
1368 inspecting attributes - we have to put this state back to what it's
1369 supposed to be. */
1370 extract_constrain_insn_cached (insn);
1372 if (ip2k_compare_operands[1] == const0_rtx) /* These are easier. */
1374 switch (code)
1376 case LT:
1377 if (can_use_skip)
1379 OUT_AS2 (sb, %0, 7);
1381 else
1383 OUT_AS2 (snb, %0, 7);
1384 OUT_AS1 (page, %2);
1385 OUT_AS1 (jmp, %2);
1387 break;
1389 case GT:
1390 switch (mode)
1392 case DImode:
1393 OUT_AS2 (rl, w, %S0);
1394 OUT_AS2 (mov, w, %S0);
1395 OUT_AS2 (or, w, %T0);
1396 OUT_AS2 (or, w, %U0);
1397 OUT_AS2 (or, w, %V0);
1398 OUT_AS2 (or, w, %W0);
1399 OUT_AS2 (or, w, %X0);
1400 OUT_AS2 (or, w, %Y0);
1401 OUT_AS2 (or, w, %Z0);
1402 OUT_AS1 (snz, );
1403 OUT_AS2 (setb, status, 0);
1404 OUT_AS2 (sb, status, 0);
1405 OUT_AS1 (page, %2);
1406 OUT_AS1 (jmp, %2);
1407 break;
1409 case SImode:
1410 OUT_AS2 (rl, w, %A0);
1411 OUT_AS2 (mov, w, %A0);
1412 OUT_AS2 (or, w, %B0);
1413 OUT_AS2 (or, w, %C0);
1414 OUT_AS2 (or, w, %D0);
1415 OUT_AS1 (snz, );
1416 OUT_AS2 (setb, status, 0);
1417 OUT_AS2 (sb, status, 0);
1418 OUT_AS1 (page, %2);
1419 OUT_AS1 (jmp, %2);
1420 break;
1422 case HImode:
1423 OUT_AS2 (rl, w, %H0);
1424 OUT_AS2 (mov, w, %H0);
1425 OUT_AS2 (or, w, %L0);
1426 OUT_AS1 (snz, );
1427 OUT_AS2 (setb, status, 0);
1428 OUT_AS2 (sb, status, 0);
1429 OUT_AS1 (page, %2);
1430 OUT_AS1 (jmp, %2);
1431 break;
1433 case QImode:
1434 OUT_AS2 (mov, w, %0); /* Will just do "sb w, 7". */
1435 OUT_AS1 (snz, );
1436 OUT_AS2 (setb, wreg, 7);
1437 OUT_AS2 (sb, wreg, 7);
1438 OUT_AS1 (page, %2);
1439 OUT_AS1 (jmp, %2);
1440 break;
1442 default:
1443 abort ();
1445 break;
1447 case LE:
1448 switch (mode)
1450 case DImode:
1451 OUT_AS2 (mov, w, %S0);
1452 OUT_AS2 (or, w, %T0);
1453 OUT_AS2 (or, w, %U0);
1454 OUT_AS2 (or, w, %V0);
1455 OUT_AS2 (or, w, %W0);
1456 OUT_AS2 (or, w, %X0);
1457 OUT_AS2 (or, w, %Y0);
1458 OUT_AS2 (or, w, %Z0); /* Z is correct. */
1459 OUT_AS1 (sz, );
1460 OUT_AS2 (snb, %S0, 7);
1461 OUT_AS1 (page, %2);
1462 OUT_AS1 (jmp, %2);
1463 break;
1465 case SImode:
1466 OUT_AS2 (mov, w, %A0);
1467 OUT_AS2 (or, w, %B0);
1468 OUT_AS2 (or, w, %C0);
1469 OUT_AS2 (or, w, %D0); /* Z is correct. */
1470 OUT_AS1 (sz, );
1471 OUT_AS2 (snb, %A0, 7);
1472 OUT_AS1 (page, %2);
1473 OUT_AS1 (jmp, %2);
1474 break;
1476 case HImode:
1477 OUT_AS2 (mov, w, %H0);
1478 OUT_AS2 (or, w, %L0);
1479 OUT_AS1 (sz, );
1480 OUT_AS2 (snb, %H0, 7);
1481 OUT_AS1 (page, %2);
1482 OUT_AS1 (jmp, %2);
1483 break;
1485 case QImode:
1486 OUT_AS2 (mov, w, %0); /* Will just do "sb w, 7". */
1487 OUT_AS1 (sz, );
1488 OUT_AS2 (snb, wreg, 7);
1489 OUT_AS1 (page, %2);
1490 OUT_AS1 (jmp, %2);
1491 break;
1493 default:
1494 abort ();
1496 break;
1498 case GE:
1499 if (can_use_skip)
1501 OUT_AS2 (snb, %0, 7);
1503 else
1505 OUT_AS2 (sb, %0, 7);
1506 OUT_AS1 (page, %2);
1507 OUT_AS1 (jmp, %2);
1509 break;
1511 default:
1512 abort ();
1514 return "";
1517 /* signed compares are out of line because we can't get
1518 the hardware to compute the overflow for us. */
1520 switch (mode)
1522 case QImode:
1523 OUT_AS1 (push, %1%<);
1524 OUT_AS1 (push, %0%>);
1525 OUT_AS1 (page, __cmpqi2);
1526 OUT_AS1 (call, __cmpqi2);
1527 break;
1529 case HImode:
1530 OUT_AS1 (push, %L1%<);
1531 OUT_AS1 (push, %H1%<);
1532 OUT_AS1 (push, %L0%<);
1533 OUT_AS1 (push, %H0%>%>%>);
1534 OUT_AS1 (page, __cmphi2);
1535 OUT_AS1 (call, __cmphi2);
1536 break;
1538 case SImode:
1539 OUT_AS1 (push, %D1%<);
1540 OUT_AS1 (push, %C1%<);
1541 OUT_AS1 (push, %B1%<);
1542 OUT_AS1 (push, %A1%<);
1543 OUT_AS1 (push, %D0%<);
1544 OUT_AS1 (push, %C0%<);
1545 OUT_AS1 (push, %B0%<);
1546 OUT_AS1 (push, %A0%>%>%>%>%>%>%>);
1547 OUT_AS1 (page, __cmpsi2);
1548 OUT_AS1 (call, __cmpsi2);
1549 break;
1551 case DImode:
1552 if (GET_CODE (operands[0]) == MEM
1553 && true_regnum (XEXP (operands[0], 0)) == REG_DP)
1555 OUT_AS1 (push, %Z1%<);
1556 OUT_AS1 (push, %Y1%<);
1557 OUT_AS1 (push, %X1%<);
1558 OUT_AS1 (push, %W1%<);
1559 OUT_AS1 (push, %V1%<);
1560 OUT_AS1 (push, %U1%<);
1561 OUT_AS1 (push, %T1%<);
1562 OUT_AS1 (push, %S1%>%>%>%>%>%>%>);
1563 OUT_AS1 (page, __cmpdi2_dp);
1564 OUT_AS1 (call, __cmpdi2_dp);
1566 else
1568 OUT_AS1 (push, %Z1%<);
1569 OUT_AS1 (push, %Y1%<);
1570 OUT_AS1 (push, %X1%<);
1571 OUT_AS1 (push, %W1%<);
1572 OUT_AS1 (push, %V1%<);
1573 OUT_AS1 (push, %U1%<);
1574 OUT_AS1 (push, %T1%<);
1575 OUT_AS1 (push, %S1%<);
1576 OUT_AS1 (push, %Z0%<);
1577 OUT_AS1 (push, %Y0%<);
1578 OUT_AS1 (push, %X0%<);
1579 OUT_AS1 (push, %W0%<);
1580 OUT_AS1 (push, %V0%<);
1581 OUT_AS1 (push, %U0%<);
1582 OUT_AS1 (push, %T0%<);
1583 OUT_AS1 (push, %S0%>%>%>%>%>%>%>%>%>%>%>%>%>%>%>);
1584 OUT_AS1 (page, __cmpdi2);
1585 OUT_AS1 (call, __cmpdi2);
1587 break;
1589 default:
1590 abort ();
1593 switch (code)
1595 case LT:
1596 if (can_use_skip)
1598 OUT_AS2 (cse, w, #0);
1600 else
1602 OUT_AS2 (csne, w, #0);
1603 OUT_AS1 (page, %2);
1604 OUT_AS1 (jmp, %2);
1606 break;
1608 case GT:
1609 if (can_use_skip)
1611 OUT_AS2 (cse, w, #2);
1613 else
1615 OUT_AS2 (csne, w, #2);
1616 OUT_AS1 (page, %2);
1617 OUT_AS1 (jmp, %2);
1619 break;
1621 case LE:
1622 if (can_use_skip)
1624 OUT_AS2 (snb, wreg, 1);
1626 else
1628 OUT_AS2 (sb, wreg, 1);
1629 OUT_AS1 (page, %2);
1630 OUT_AS1 (jmp, %2);
1632 break;
1634 case GE:
1635 if (can_use_skip)
1637 OUT_AS2 (csne, w, #0);
1639 else
1641 OUT_AS2 (cse, w, #0);
1642 OUT_AS1 (page, %2);
1643 OUT_AS1 (jmp, %2);
1645 break;
1647 default:
1648 abort ();
1650 return "";
1651 #undef operands
1654 const char *
1655 ip2k_gen_unsigned_comp_branch (rtx insn, enum rtx_code code, rtx label)
1657 #define operands ip2k_compare_operands
1658 enum machine_mode mode;
1659 int imm_sub = 0;
1660 int imm_cmp = 0;
1661 int can_use_skip = 0;
1662 rtx ninsn;
1663 HOST_WIDE_INT const_low;
1664 HOST_WIDE_INT const_high;
1666 operands[2] = label;
1668 mode = GET_MODE (operands[0]);
1669 if ((mode != QImode) && (mode != HImode) && (mode != SImode)
1670 && (mode != DImode))
1672 mode = GET_MODE (operands[1]);
1675 /* Look for situations where we can just skip the next instruction instead
1676 of skipping and then branching! */
1677 ninsn = next_real_insn (insn);
1678 if (ninsn
1679 && (recog_memoized (ninsn) >= 0)
1680 && get_attr_skip (ninsn) == SKIP_YES)
1682 rtx skip_tgt = next_nonnote_insn (next_real_insn (insn));
1684 /* The first situation is where the target of the jump is one insn
1685 after the jump insn and the insn being jumped is only one machine
1686 opcode long. */
1687 if (label == skip_tgt)
1688 can_use_skip = 1;
1689 else
1691 /* If our skip target is in fact a code label then we ignore the
1692 label and move onto the next useful instruction. Nothing we do
1693 here has any effect on the use of skipping instructions. */
1694 if (GET_CODE (skip_tgt) == CODE_LABEL)
1695 skip_tgt = next_nonnote_insn (skip_tgt);
1697 /* The second situation is where we have something of the form:
1699 test_condition
1700 skip_conditional
1701 page/jump label
1703 optional_label (this may or may not exist):
1704 skippable_insn
1705 page/jump label
1707 In this case we can eliminate the first "page/jump label". */
1708 if (GET_CODE (skip_tgt) == JUMP_INSN)
1710 rtx set = single_set (skip_tgt);
1711 if (GET_CODE (XEXP (set, 0)) == PC
1712 && GET_CODE (XEXP (set, 1)) == LABEL_REF
1713 && label == JUMP_LABEL (skip_tgt))
1714 can_use_skip = 2;
1719 /* gcc is a little braindead and does some rather stateful things while
1720 inspecting attributes - we have to put this state back to what it's
1721 supposed to be. */
1722 extract_constrain_insn_cached (insn);
1724 if (ip2k_compare_operands[1] == const0_rtx)
1726 switch (code)
1728 case LEU:
1729 code = EQ; /* Nothing is LTU 0. */
1730 goto zero;
1732 case GTU:
1733 code = NE; /* Anything nonzero is GTU. */
1734 /* fall-through */
1736 case EQ:
1737 case NE: /* Test all the bits, result in
1738 Z AND WREG. */
1739 zero:
1740 switch (mode)
1742 case DImode:
1743 OUT_AS2 (mov, w, %S0);
1744 OUT_AS2 (or, w, %T0);
1745 OUT_AS2 (or, w, %U0);
1746 OUT_AS2 (or, w, %V0);
1747 OUT_AS2 (or, w, %W0);
1748 OUT_AS2 (or, w, %X0);
1749 OUT_AS2 (or, w, %Y0);
1750 OUT_AS2 (or, w, %Z0);
1751 break;
1753 case SImode:
1754 OUT_AS2 (mov, w, %A0);
1755 OUT_AS2 (or, w, %B0);
1756 OUT_AS2 (or, w, %C0);
1757 OUT_AS2 (or, w, %D0);
1758 break;
1760 case HImode:
1761 OUT_AS2 (mov, w, %H0);
1762 OUT_AS2 (or, w, %L0);
1763 break;
1765 case QImode:
1766 OUT_AS2 (mov, w, %0);
1767 break;
1769 default:
1770 abort ();
1773 if (can_use_skip)
1775 if (code == EQ)
1776 OUT_AS1 (sz, );
1777 else
1778 OUT_AS1 (snz, );
1780 else
1782 if (code == EQ)
1783 OUT_AS1 (snz,);
1784 else
1785 OUT_AS1 (sz,);
1786 OUT_AS1 (page, %2);
1787 OUT_AS1 (jmp, %2);
1789 break;
1791 case GEU:
1792 /* Always succeed. */
1793 OUT_AS1 (page, %2);
1794 OUT_AS1 (jmp, %2);
1795 break;
1797 case LTU:
1798 /* Always fail. */
1799 break;
1801 default:
1802 abort ();
1804 return "";
1807 /* Look at whether we have a constant as one of our operands. If we do
1808 and it's in the position that we use to subtract from during our
1809 normal optimized comparison concept then we have to shuffle things
1810 around! */
1811 if (mode != QImode)
1813 if ((immediate_operand (operands[1], GET_MODE (operands[1]))
1814 && ((code == LEU) || (code == GTU)))
1815 || (immediate_operand (operands[0], GET_MODE (operands[0]))
1816 && ((code == LTU) || (code == GEU))))
1818 imm_sub = 1;
1822 /* Same as above - look if we have a constant that we can compare
1823 for equality or non-equality. If we know this then we can look
1824 for common value eliminations. Note that we want to ensure that
1825 any immediate value is operand 1 to simplify the code later! */
1826 if ((code == EQ) || (code == NE))
1828 imm_cmp = immediate_operand (operands[1], GET_MODE (operands[1]));
1829 if (! imm_cmp)
1831 imm_cmp = immediate_operand (operands[0], GET_MODE (operands[0]));
1832 if (imm_cmp)
1834 rtx tmp = operands[1];
1835 operands[1] = operands[0];
1836 operands[0] = tmp;
1841 switch (mode)
1843 case QImode:
1844 switch (code)
1846 case EQ:
1847 if (imm_cmp && ((INTVAL (operands[1]) & 0xff) == 0xff))
1848 OUT_AS2 (incsnz, w, %0);
1849 else if (imm_cmp && ((INTVAL (operands[1]) & 0xff) == 0x01))
1850 OUT_AS2 (decsnz, w, %0);
1851 else
1853 OUT_AS2 (mov, w, %1);
1854 OUT_AS2 (csne, w, %0);
1856 OUT_AS1 (page, %2);
1857 OUT_AS1 (jmp, %2);
1858 break;
1860 case NE:
1861 if (imm_cmp && ((INTVAL (operands[1]) & 0xff) == 0xff))
1862 OUT_AS2 (incsz, w, %0);
1863 else if (imm_cmp && ((INTVAL (operands[1]) & 0xff) == 0x01))
1864 OUT_AS2 (decsz, w, %0);
1865 else
1867 OUT_AS2 (mov, w, %1);
1868 OUT_AS2 (cse, w, %0);
1870 OUT_AS1 (page, %2);
1871 OUT_AS1 (jmp, %2);
1872 break;
1874 case GTU:
1875 OUT_AS2 (mov, w, %0);
1876 OUT_AS2 (cmp, w, %1);
1877 OUT_AS1 (sc,);
1878 OUT_AS1 (page, %2);
1879 OUT_AS1 (jmp, %2);
1880 break;
1882 case GEU:
1883 OUT_AS2 (mov, w, %1);
1884 OUT_AS2 (cmp, w, %0);
1885 OUT_AS1 (snc,);
1886 OUT_AS1 (page, %2);
1887 OUT_AS1 (jmp, %2);
1888 break;
1890 case LTU:
1891 OUT_AS2 (mov, w, %1);
1892 OUT_AS2 (cmp, w, %0);
1893 OUT_AS1 (sc,);
1894 OUT_AS1 (page, %2);
1895 OUT_AS1 (jmp, %2);
1896 break;
1898 case LEU:
1899 OUT_AS2 (mov, w, %0);
1900 OUT_AS2 (cmp, w, %1);
1901 OUT_AS1 (snc,);
1902 OUT_AS1 (page, %2);
1903 OUT_AS1 (jmp, %2);
1904 break;
1906 default:
1907 abort ();
1909 break;
1911 case HImode:
1912 switch (code)
1914 case EQ:
1916 unsigned char h = 0, l = 1;
1918 if (imm_cmp)
1920 h = (INTVAL (operands[1]) >> 8) & 0xff;
1921 l = INTVAL (operands[1]) & 0xff;
1923 if ((h == 0xff) && (l == 0xff))
1925 /* We should be able to do the following, but the
1926 IP2k simulator doesn't like it and we get a load
1927 of failures in gcc-c-torture. */
1928 OUT_AS2 (incsnz, w, %L0);
1929 OUT_AS2 (incsz, w, %H0);
1930 /* OUT_AS1 (skip,); Should have this */
1931 OUT_AS1 (page, 1f);/* Shouldn't need this! */
1932 OUT_AS1 (jmp, 1f); /* Shouldn't need this either. */
1933 OUT_AS1 (page, %2);
1934 OUT_AS1 (jmp, %2);
1935 OUT_AS1 (1:,);
1936 break;
1938 else if (h == 0)
1940 if (l == 1)
1941 OUT_AS2 (dec, w, %L0);
1942 else
1944 OUT_AS2 (mov, w, %L0);
1945 OUT_AS2 (sub, w, %L1);
1947 OUT_AS2 (or, w, %H0);
1948 OUT_AS1 (snz,);
1949 OUT_AS1 (page, %2);
1950 OUT_AS1 (jmp, %2);
1951 break;
1953 else if (l == 0)
1955 if (h == 1)
1956 OUT_AS2 (dec, w, %H0);
1957 else
1959 OUT_AS2 (mov, w, %H0);
1960 OUT_AS2 (sub, w, %H1);
1962 OUT_AS2 (or, w, %L0);
1963 OUT_AS1 (snz,);
1964 OUT_AS1 (page, %2);
1965 OUT_AS1 (jmp, %2);
1966 break;
1970 OUT_AS2 (mov, w, %H1);
1971 OUT_AS2 (cse, w, %H0);
1972 OUT_AS1 (page, 2f);
1973 OUT_AS1 (jmp, 2f);
1974 if (! imm_cmp || (h != l))
1975 OUT_AS2 (mov, w, %L1);
1976 OUT_AS2 (csne, w, %L0);
1977 OUT_AS1 (page, %2);
1978 OUT_AS1 (jmp, %2);
1979 OUT_AS1 (2:,);
1981 break;
1983 case NE:
1985 unsigned char h = 0, l = 1;
1987 if (imm_cmp)
1989 h = (INTVAL (operands[1]) >> 8) & 0xff;
1990 l = INTVAL (operands[1]) & 0xff;
1992 if ((h == 0xff) && (l == 0xff))
1994 OUT_AS2 (incsnz, w, %L0);
1995 OUT_AS2 (incsz, w, %H0);
1996 OUT_AS1 (page, %2);
1997 OUT_AS1 (jmp, %2);
1998 break;
2000 else if (h == 0)
2002 if (l == 1)
2003 OUT_AS2 (dec, w, %L0);
2004 else
2006 OUT_AS2 (mov, w, %L0);
2007 OUT_AS2 (sub, w, %L1);
2009 OUT_AS2 (or, w, %H0);
2010 OUT_AS1 (sz,);
2011 OUT_AS1 (page, %2);
2012 OUT_AS1 (jmp, %2);
2013 break;
2015 else if (l == 0)
2017 if (h == 1)
2018 OUT_AS2 (dec, w, %H0);
2019 else
2021 OUT_AS2 (mov, w, %H0);
2022 OUT_AS2 (sub, w, %H1);
2024 OUT_AS2 (or, w, %L0);
2025 OUT_AS1 (sz,);
2026 OUT_AS1 (page, %2);
2027 OUT_AS1 (jmp, %2);
2028 break;
2032 OUT_AS2 (mov, w, %H1);
2033 if (imm_cmp && (h == l))
2035 OUT_AS2 (csne, w, %H0);
2036 OUT_AS2 (cse, w, %L0);
2038 else
2040 OUT_AS2 (cse, w, %H0);
2041 OUT_AS1 (page, %2);
2042 OUT_AS1 (jmp, %2);
2043 OUT_AS2 (mov, w, %L1);
2044 OUT_AS2 (cse, w, %L0);
2046 OUT_AS1 (page, %2);
2047 OUT_AS1 (jmp, %2);
2049 break;
2051 case GTU:
2052 if (imm_sub)
2054 /* > 0xffff never succeeds! */
2055 if ((INTVAL (operands[1]) & 0xffff) != 0xffff)
2057 operands[3] = GEN_INT (INTVAL (operands[1]) + 1);
2058 OUT_AS2 (mov, w, %L3);
2059 OUT_AS2 (sub, w, %L0);
2060 OUT_AS2 (mov, w, %H3);
2061 OUT_AS2 (subc, w, %H0);
2062 OUT_AS1 (snc,);
2063 OUT_AS1 (page, %2);
2064 OUT_AS1 (jmp, %2);
2067 else
2069 OUT_AS2 (mov, w, %L0);
2070 OUT_AS2 (sub, w, %L1);
2071 OUT_AS2 (mov, w, %H0);
2072 OUT_AS2 (subc, w, %H1);
2073 OUT_AS1 (sc,);
2074 OUT_AS1 (page, %2);
2075 OUT_AS1 (jmp, %2);
2077 break;
2079 case GEU:
2080 if (imm_sub)
2082 if (INTVAL (operands[0]) == 0)
2084 OUT_AS2 (mov, w, %H1);
2085 OUT_AS2 (or, w, %L1);
2086 OUT_AS1 (snz,);
2087 OUT_AS1 (page, %2);
2088 OUT_AS1 (jmp, %2);
2090 else
2092 operands[3] = GEN_INT (INTVAL (operands[0]) - 1);
2093 OUT_AS2 (mov, w, %L3);
2094 OUT_AS2 (sub, w, %L1);
2095 OUT_AS2 (mov, w, %H3);
2096 OUT_AS2 (subc, w, %H1);
2097 OUT_AS1 (sc,);
2098 OUT_AS1 (page, %2);
2099 OUT_AS1 (jmp, %2);
2102 else
2104 OUT_AS2 (mov, w, %L1);
2105 OUT_AS2 (sub, w, %L0);
2106 OUT_AS2 (mov, w, %H1);
2107 OUT_AS2 (subc, w, %H0);
2108 OUT_AS1 (snc,);
2109 OUT_AS1 (page, %2);
2110 OUT_AS1 (jmp, %2);
2112 break;
2114 case LTU:
2115 if (imm_sub)
2117 if (INTVAL (operands[0]) == 0)
2119 OUT_AS2 (mov, w, %H1);
2120 OUT_AS2 (or, w, %L1);
2121 OUT_AS1 (sz,);
2122 OUT_AS1 (page, %2);
2123 OUT_AS1 (jmp, %2);
2125 else
2127 operands[3] = GEN_INT (INTVAL (operands[0]) - 1);
2128 OUT_AS2 (mov, w, %L3);
2129 OUT_AS2 (sub, w, %L1);
2130 OUT_AS2 (mov, w, %H3);
2131 OUT_AS2 (subc, w, %H1);
2132 OUT_AS1 (snc,);
2133 OUT_AS1 (page, %2);
2134 OUT_AS1 (jmp, %2);
2137 else
2139 OUT_AS2 (mov, w, %L1);
2140 OUT_AS2 (sub, w, %L0);
2141 OUT_AS2 (mov, w, %H1);
2142 OUT_AS2 (subc, w, %H0);
2143 OUT_AS1 (sc,);
2144 OUT_AS1 (page, %2);
2145 OUT_AS1 (jmp, %2);
2147 break;
2149 case LEU:
2150 if (imm_sub)
2152 if ((INTVAL (operands[1]) & 0xffff) == 0xffff)
2154 /* <= 0xffff always succeeds. */
2155 OUT_AS1 (page, %2);
2156 OUT_AS1 (jmp, %2);
2158 else
2160 operands[3] = GEN_INT (INTVAL (operands[1]) + 1);
2161 OUT_AS2 (mov, w, %L3);
2162 OUT_AS2 (sub, w, %L0);
2163 OUT_AS2 (mov, w, %H3);
2164 OUT_AS2 (subc, w, %H0);
2165 OUT_AS1 (sc,);
2166 OUT_AS1 (page, %2);
2167 OUT_AS1 (jmp, %2);
2170 else
2172 OUT_AS2 (mov, w, %L0);
2173 OUT_AS2 (sub, w, %L1);
2174 OUT_AS2 (mov, w, %H0);
2175 OUT_AS2 (subc, w, %H1);
2176 OUT_AS1 (snc,);
2177 OUT_AS1 (page, %2);
2178 OUT_AS1 (jmp, %2);
2180 break;
2182 default:
2183 abort ();
2185 break;
2187 case SImode:
2188 switch (code)
2190 case EQ:
2192 unsigned char a = 0, b = 1, c = 2, d = 3;
2194 if (imm_cmp)
2196 a = (INTVAL (operands[1]) >> 24) & 0xff;
2197 b = (INTVAL (operands[1]) >> 16) & 0xff;
2198 c = (INTVAL (operands[1]) >> 8) & 0xff;
2199 d = INTVAL (operands[1]) & 0xff;
2202 OUT_AS2 (mov, w, %A1);
2203 if (imm_cmp && (b == a))
2205 OUT_AS2 (csne, w, %A0);
2206 OUT_AS2 (cse, w, %B0);
2208 else
2210 OUT_AS2 (cse, w, %A0);
2211 OUT_AS1 (page, 2f);
2212 OUT_AS1 (jmp, 2f);
2213 OUT_AS2 (mov, w, %B1);
2214 OUT_AS2 (cse, w, %B0);
2216 OUT_AS1 (page, 2f);
2217 OUT_AS1 (jmp, 2f);
2218 if (! imm_cmp || (c != b))
2219 OUT_AS2 (mov, w, %C1);
2220 OUT_AS2 (cse, w, %C0);
2221 OUT_AS1 (page, 2f);
2222 OUT_AS1 (jmp, 2f);
2223 if (! imm_cmp || (d != c))
2224 OUT_AS2 (mov, w, %D1);
2225 OUT_AS2 (csne, w, %D0);
2226 OUT_AS1 (page, %2);
2227 OUT_AS1 (jmp, %2);
2228 OUT_AS1 (2:,);
2230 break;
2232 case NE:
2234 unsigned char a = 0, b = 1, c = 2, d = 3;
2236 if (imm_cmp)
2238 a = (INTVAL (operands[1]) >> 24) & 0xff;
2239 b = (INTVAL (operands[1]) >> 16) & 0xff;
2240 c = (INTVAL (operands[1]) >> 8) & 0xff;
2241 d = INTVAL (operands[1]) & 0xff;
2244 OUT_AS2 (mov, w, %A1);
2245 if (imm_cmp && (b == a))
2247 OUT_AS2 (csne, w, %A0);
2248 OUT_AS2 (cse, w, %B0);
2250 else
2252 OUT_AS2 (cse, w, %A0);
2253 OUT_AS1 (page, %2);
2254 OUT_AS1 (jmp, %2);
2255 OUT_AS2 (mov, w, %B1);
2256 OUT_AS2 (cse, w, %B0);
2258 OUT_AS1 (page, %2);
2259 OUT_AS1 (jmp, %2);
2260 if (! imm_cmp || (c != b))
2261 OUT_AS2 (mov, w, %C1);
2262 if (imm_cmp && (d == c))
2264 OUT_AS2 (csne, w, %C0);
2265 OUT_AS2 (cse, w, %D0);
2267 else
2269 OUT_AS2 (cse, w, %C0);
2270 OUT_AS1 (page, %2);
2271 OUT_AS1 (jmp, %2);
2272 OUT_AS2 (mov, w, %D1);
2273 OUT_AS2 (cse, w, %D0);
2275 OUT_AS1 (page, %2);
2276 OUT_AS1 (jmp, %2);
2278 break;
2280 case GTU:
2281 if (imm_sub)
2283 /* > 0xffffffff never succeeds! */
2284 if ((unsigned HOST_WIDE_INT)(INTVAL (operands[1]) & 0xffffffff)
2285 != 0xffffffff)
2287 operands[3] = GEN_INT (INTVAL (operands[1]) + 1);
2288 OUT_AS2 (mov, w, %D3);
2289 OUT_AS2 (sub, w, %D0);
2290 OUT_AS2 (mov, w, %C3);
2291 OUT_AS2 (subc, w, %C0);
2292 OUT_AS2 (mov, w, %B3);
2293 OUT_AS2 (subc, w, %B0);
2294 OUT_AS2 (mov, w, %A3);
2295 OUT_AS2 (subc, w, %A0);
2296 OUT_AS1 (snc,);
2297 OUT_AS1 (page, %2);
2298 OUT_AS1 (jmp, %2);
2301 else
2303 OUT_AS2 (mov, w, %D0);
2304 OUT_AS2 (sub, w, %D1);
2305 OUT_AS2 (mov, w, %C0);
2306 OUT_AS2 (subc, w, %C1);
2307 OUT_AS2 (mov, w, %B0);
2308 OUT_AS2 (subc, w, %B1);
2309 OUT_AS2 (mov, w, %A0);
2310 OUT_AS2 (subc, w, %A1);
2311 OUT_AS1 (sc,);
2312 OUT_AS1 (page, %2);
2313 OUT_AS1 (jmp, %2);
2315 break;
2317 case GEU:
2318 if (imm_sub)
2320 if (INTVAL (operands[0]) == 0)
2322 OUT_AS2 (mov, w, %A1);
2323 OUT_AS2 (or, w, %B1);
2324 OUT_AS2 (or, w, %C1);
2325 OUT_AS2 (or, w, %D1);
2326 OUT_AS1 (snz,);
2327 OUT_AS1 (page, %2);
2328 OUT_AS1 (jmp, %2);
2330 else
2332 operands[3] = GEN_INT (INTVAL (operands[0]) - 1);
2333 OUT_AS2 (mov, w, %D3);
2334 OUT_AS2 (sub, w, %D1);
2335 OUT_AS2 (mov, w, %C3);
2336 OUT_AS2 (subc, w, %C1);
2337 OUT_AS2 (mov, w, %B3);
2338 OUT_AS2 (subc, w, %B1);
2339 OUT_AS2 (mov, w, %A3);
2340 OUT_AS2 (subc, w, %A1);
2341 OUT_AS1 (sc,);
2342 OUT_AS1 (page, %2);
2343 OUT_AS1 (jmp, %2);
2346 else
2348 OUT_AS2 (mov, w, %D1);
2349 OUT_AS2 (sub, w, %D0);
2350 OUT_AS2 (mov, w, %C1);
2351 OUT_AS2 (subc, w, %C0);
2352 OUT_AS2 (mov, w, %B1);
2353 OUT_AS2 (subc, w, %B0);
2354 OUT_AS2 (mov, w, %A1);
2355 OUT_AS2 (subc, w, %A0);
2356 OUT_AS1 (snc,);
2357 OUT_AS1 (page, %2);
2358 OUT_AS1 (jmp, %2);
2360 break;
2362 case LTU:
2363 if (imm_sub)
2365 if (INTVAL (operands[0]) == 0)
2367 OUT_AS2 (mov, w, %A1);
2368 OUT_AS2 (or, w, %B1);
2369 OUT_AS2 (or, w, %C1);
2370 OUT_AS2 (or, w, %D1);
2371 OUT_AS1 (sz,);
2372 OUT_AS1 (page, %2);
2373 OUT_AS1 (jmp, %2);
2375 else
2377 operands[3] = GEN_INT (INTVAL (operands[0]) - 1);
2378 OUT_AS2 (mov, w, %D3);
2379 OUT_AS2 (sub, w, %D1);
2380 OUT_AS2 (mov, w, %C3);
2381 OUT_AS2 (subc, w, %C1);
2382 OUT_AS2 (mov, w, %B3);
2383 OUT_AS2 (subc, w, %B1);
2384 OUT_AS2 (mov, w, %A3);
2385 OUT_AS2 (subc, w, %A1);
2386 OUT_AS1 (snc,);
2387 OUT_AS1 (page, %2);
2388 OUT_AS1 (jmp, %2);
2391 else
2393 OUT_AS2 (mov, w, %D1);
2394 OUT_AS2 (sub, w, %D0);
2395 OUT_AS2 (mov, w, %C1);
2396 OUT_AS2 (subc, w, %C0);
2397 OUT_AS2 (mov, w, %B1);
2398 OUT_AS2 (subc, w, %B0);
2399 OUT_AS2 (mov, w, %A1);
2400 OUT_AS2 (subc, w, %A0);
2401 OUT_AS1 (sc,);
2402 OUT_AS1 (page, %2);
2403 OUT_AS1 (jmp, %2);
2405 break;
2407 case LEU:
2408 if (imm_sub)
2410 if ((unsigned HOST_WIDE_INT)(INTVAL (operands[1]) & 0xffffffff)
2411 == 0xffffffff)
2413 /* <= 0xffffffff always succeeds. */
2414 OUT_AS1 (page, %2);
2415 OUT_AS1 (jmp, %2);
2417 else
2419 operands[3] = GEN_INT (INTVAL (operands[1]) + 1);
2420 OUT_AS2 (mov, w, %D3);
2421 OUT_AS2 (sub, w, %D0);
2422 OUT_AS2 (mov, w, %C3);
2423 OUT_AS2 (subc, w, %C0);
2424 OUT_AS2 (mov, w, %B3);
2425 OUT_AS2 (subc, w, %B0);
2426 OUT_AS2 (mov, w, %A3);
2427 OUT_AS2 (subc, w, %A0);
2428 OUT_AS1 (sc,);
2429 OUT_AS1 (page, %2);
2430 OUT_AS1 (jmp, %2);
2433 else
2435 OUT_AS2 (mov, w, %D0);
2436 OUT_AS2 (sub, w, %D1);
2437 OUT_AS2 (mov, w, %C0);
2438 OUT_AS2 (subc, w, %C1);
2439 OUT_AS2 (mov, w, %B0);
2440 OUT_AS2 (subc, w, %B1);
2441 OUT_AS2 (mov, w, %A0);
2442 OUT_AS2 (subc, w, %A1);
2443 OUT_AS1 (snc,);
2444 OUT_AS1 (page, %2);
2445 OUT_AS1 (jmp, %2);
2447 break;
2449 default:
2450 abort ();
2452 break;
2454 case DImode:
2455 if (GET_CODE (operands[1]) == CONST_INT)
2457 const_low = INTVAL (operands[1]);
2458 const_high = (const_low >= 0) - 1;
2460 else if (GET_CODE (operands[1]) == CONST_DOUBLE)
2462 const_low = CONST_DOUBLE_LOW (operands[1]);
2463 const_high = CONST_DOUBLE_HIGH (operands[1]);
2465 switch (code)
2467 case EQ:
2469 unsigned char s = 0, t = 1, u = 2, v = 3;
2470 unsigned char w = 4, x = 5, y = 6, z = 7;
2471 if (optimize_size)
2473 if (GET_CODE (operands[0]) == MEM
2474 && true_regnum (XEXP (operands[0], 0)) == REG_DP)
2476 OUT_AS1 (push, %Z1%<);
2477 OUT_AS1 (push, %Y1%<);
2478 OUT_AS1 (push, %X1%<);
2479 OUT_AS1 (push, %W1%<);
2480 OUT_AS1 (push, %V1%<);
2481 OUT_AS1 (push, %U1%<);
2482 OUT_AS1 (push, %T1%<);
2483 OUT_AS1 (push, %S1%>%>%>%>%>%>%>);
2484 OUT_AS1 (page, __cmpdi2_dp);
2485 OUT_AS1 (call, __cmpdi2_dp);
2486 OUT_AS2 (csne, w, #1);
2487 OUT_AS1 (page, %2);
2488 OUT_AS1 (jmp, %2);
2490 else
2492 OUT_AS1 (push, %Z1%<);
2493 OUT_AS1 (push, %Y1%<);
2494 OUT_AS1 (push, %X1%<);
2495 OUT_AS1 (push, %W1%<);
2496 OUT_AS1 (push, %V1%<);
2497 OUT_AS1 (push, %U1%<);
2498 OUT_AS1 (push, %T1%<);
2499 OUT_AS1 (push, %S1%<);
2500 OUT_AS1 (push, %Z0%<);
2501 OUT_AS1 (push, %Y0%<);
2502 OUT_AS1 (push, %X0%<);
2503 OUT_AS1 (push, %W0%<);
2504 OUT_AS1 (push, %V0%<);
2505 OUT_AS1 (push, %U0%<);
2506 OUT_AS1 (push, %T0%<);
2507 OUT_AS1 (push, %S0%>%>%>%>%>%>%>%>%>%>%>%>%>%>%>);
2508 OUT_AS1 (page, __cmpdi2);
2509 OUT_AS1 (call, __cmpdi2);
2510 OUT_AS2 (csne, w, #1);
2511 OUT_AS1 (page, %2);
2512 OUT_AS1 (jmp, %2);
2515 else
2517 if (imm_cmp)
2519 s = (const_high >> 24) & 0xff;
2520 t = (const_high >> 16) & 0xff;
2521 u = (const_high >> 8) & 0xff;
2522 v = const_high & 0xff;
2523 w = (const_low >> 24) & 0xff;
2524 x = (const_low >> 16) & 0xff;
2525 y = (const_low >> 8) & 0xff;
2526 z = const_low & 0xff;
2529 OUT_AS2 (mov, w, %S1);
2530 if (imm_cmp && (s == t))
2532 OUT_AS2 (csne, w, %S0);
2533 OUT_AS2 (cse, w, %T0);
2535 else
2537 OUT_AS2 (cse, w, %S0);
2538 OUT_AS1 (page, 2f);
2539 OUT_AS1 (jmp, 2f);
2540 OUT_AS2 (mov, w, %T1);
2541 OUT_AS2 (cse, w, %T0);
2543 OUT_AS1 (page, 2f);
2544 OUT_AS1 (jmp, 2f);
2546 OUT_AS2 (mov, w, %U1);
2547 if (imm_cmp && (u == v))
2549 OUT_AS2 (csne, w, %U0);
2550 OUT_AS2 (cse, w, %V0);
2552 else
2554 OUT_AS2 (cse, w, %U0);
2555 OUT_AS1 (page, 2f);
2556 OUT_AS1 (jmp, 2f);
2557 OUT_AS2 (mov, w, %V1);
2558 OUT_AS2 (cse, w, %V0);
2560 OUT_AS1 (page, 2f);
2561 OUT_AS1 (jmp, 2f);
2563 OUT_AS2 (mov, w, %W1);
2564 if (imm_cmp && (w == x))
2566 OUT_AS2 (csne, w, %W0);
2567 OUT_AS2 (cse, w, %X0);
2569 else
2571 OUT_AS2 (cse, w, %W0);
2572 OUT_AS1 (page, 2f);
2573 OUT_AS1 (jmp, 2f);
2574 OUT_AS2 (mov, w, %X1);
2575 OUT_AS2 (cse, w, %X0);
2577 OUT_AS1 (page, 2f);
2578 OUT_AS1 (jmp, 2f);
2580 if (! imm_cmp || (x != y))
2581 OUT_AS2 (mov, w, %Y1);
2582 OUT_AS2 (cse, w, %Y0);
2583 OUT_AS1 (page, 2f);
2584 OUT_AS1 (jmp, 2f);
2585 if (! imm_cmp || (z != y))
2586 OUT_AS2 (mov, w, %Z1);
2587 OUT_AS2 (csne, w, %Z0);
2588 OUT_AS1 (page, %2);
2589 OUT_AS1 (jmp, %2);
2590 OUT_AS1 (2:,);
2593 break;
2595 case NE:
2597 unsigned char s = 0, t = 1, u = 2, v = 3;
2598 unsigned char w = 4, x = 5, y = 6, z = 7;
2600 if (optimize_size)
2602 if (GET_CODE (operands[0]) == MEM
2603 && true_regnum (XEXP (operands[0], 0)) == REG_DP)
2605 OUT_AS1 (push, %Z1%<);
2606 OUT_AS1 (push, %Y1%<);
2607 OUT_AS1 (push, %X1%<);
2608 OUT_AS1 (push, %W1%<);
2609 OUT_AS1 (push, %V1%<);
2610 OUT_AS1 (push, %U1%<);
2611 OUT_AS1 (push, %T1%<);
2612 OUT_AS1 (push, %S1%>%>%>%>%>%>%>);
2613 OUT_AS1 (page, __cmpdi2_dp);
2614 OUT_AS1 (call, __cmpdi2_dp);
2615 OUT_AS2 (cse, w, #1);
2616 OUT_AS1 (page, %2);
2617 OUT_AS1 (jmp, %2);
2619 else
2621 OUT_AS1 (push, %Z1%<);
2622 OUT_AS1 (push, %Y1%<);
2623 OUT_AS1 (push, %X1%<);
2624 OUT_AS1 (push, %W1%<);
2625 OUT_AS1 (push, %V1%<);
2626 OUT_AS1 (push, %U1%<);
2627 OUT_AS1 (push, %T1%<);
2628 OUT_AS1 (push, %S1%<);
2629 OUT_AS1 (push, %Z0%<);
2630 OUT_AS1 (push, %Y0%<);
2631 OUT_AS1 (push, %X0%<);
2632 OUT_AS1 (push, %W0%<);
2633 OUT_AS1 (push, %V0%<);
2634 OUT_AS1 (push, %U0%<);
2635 OUT_AS1 (push, %T0%<);
2636 OUT_AS1 (push, %S0%>%>%>%>%>%>%>%>%>%>%>%>%>%>%>);
2637 OUT_AS1 (page, __cmpdi2);
2638 OUT_AS1 (call, __cmpdi2);
2639 OUT_AS2 (cse, w, #1);
2640 OUT_AS1 (page, %2);
2641 OUT_AS1 (jmp, %2);
2644 else
2646 if (imm_cmp)
2648 s = (const_high >> 24) & 0xff;
2649 t = (const_high >> 16) & 0xff;
2650 u = (const_high >> 8) & 0xff;
2651 v = const_high & 0xff;
2652 w = (const_low >> 24) & 0xff;
2653 x = (const_low >> 16) & 0xff;
2654 y = (const_low >> 8) & 0xff;
2655 z = const_low & 0xff;
2658 OUT_AS2 (mov, w, %S1);
2659 if (imm_cmp && (s == t))
2661 OUT_AS2 (csne, w, %S0);
2662 OUT_AS2 (cse, w, %T0);
2664 else
2666 OUT_AS2 (cse, w, %S0);
2667 OUT_AS1 (page, %2);
2668 OUT_AS1 (jmp, %2);
2669 OUT_AS2 (mov, w, %T1);
2670 OUT_AS2 (cse, w, %T0);
2672 OUT_AS1 (page, %2);
2673 OUT_AS1 (jmp, %2);
2675 OUT_AS2 (mov, w, %U1);
2676 if (imm_cmp && (u == v))
2678 OUT_AS2 (csne, w, %U0);
2679 OUT_AS2 (cse, w, %V0);
2681 else
2683 OUT_AS2 (cse, w, %U0);
2684 OUT_AS1 (page, %2);
2685 OUT_AS1 (jmp, %2);
2686 OUT_AS2 (mov, w, %V1);
2687 OUT_AS2 (cse, w, %V0);
2689 OUT_AS1 (page, %2);
2690 OUT_AS1 (jmp, %2);
2692 OUT_AS2 (mov, w, %W1);
2693 if (imm_cmp && (w == x))
2695 OUT_AS2 (csne, w, %W0);
2696 OUT_AS2 (cse, w, %X0);
2698 else
2700 OUT_AS2 (cse, w, %W0);
2701 OUT_AS1 (page, %2);
2702 OUT_AS1 (jmp, %2);
2703 OUT_AS2 (mov, w, %X1);
2704 OUT_AS2 (cse, w, %X0);
2706 OUT_AS1 (page, %2);
2707 OUT_AS1 (jmp, %2);
2709 if (! imm_cmp || (y != x))
2710 OUT_AS2 (mov, w, %Y1);
2711 if (imm_cmp && (z == y))
2713 OUT_AS2 (csne, w, %Y0);
2714 OUT_AS2 (cse, w, %Z0);
2716 else
2718 OUT_AS2 (cse, w, %Y0);
2719 OUT_AS1 (page, %2);
2720 OUT_AS1 (jmp, %2);
2721 OUT_AS2 (mov, w, %Z1);
2722 OUT_AS2 (cse, w, %Z0);
2724 OUT_AS1 (page, %2);
2725 OUT_AS1 (jmp, %2);
2728 break;
2730 case GTU:
2731 if (imm_sub)
2733 /* > 0xffffffffffffffff never succeeds! */
2734 if (((const_high & 0xffffffff) != 0xffffffff)
2735 || ((const_low & 0xffffffff) != 0xffffffff))
2737 operands[3] = GEN_INT (const_low + 1);
2738 operands[4] = GEN_INT (const_high
2739 + (INTVAL (operands[3]) ? 0 : 1));
2740 OUT_AS2 (mov, w, %D3);
2741 OUT_AS2 (sub, w, %Z0);
2742 OUT_AS2 (mov, w, %C3);
2743 OUT_AS2 (subc, w, %Y0);
2744 OUT_AS2 (mov, w, %B3);
2745 OUT_AS2 (subc, w, %X0);
2746 OUT_AS2 (mov, w, %A3);
2747 OUT_AS2 (subc, w, %W0);
2748 OUT_AS2 (mov, w, %D4);
2749 OUT_AS2 (subc, w, %V0);
2750 OUT_AS2 (mov, w, %C4);
2751 OUT_AS2 (subc, w, %U0);
2752 OUT_AS2 (mov, w, %B4);
2753 OUT_AS2 (subc, w, %T0);
2754 OUT_AS2 (mov, w, %A4);
2755 OUT_AS2 (subc, w, %S0);
2756 OUT_AS1 (snc,);
2757 OUT_AS1 (page, %2);
2758 OUT_AS1 (jmp, %2);
2761 else
2763 OUT_AS2 (mov, w, %Z0);
2764 OUT_AS2 (sub, w, %Z1);
2765 OUT_AS2 (mov, w, %Y0);
2766 OUT_AS2 (subc, w, %Y1);
2767 OUT_AS2 (mov, w, %X0);
2768 OUT_AS2 (subc, w, %X1);
2769 OUT_AS2 (mov, w, %W0);
2770 OUT_AS2 (subc, w, %W1);
2771 OUT_AS2 (mov, w, %V0);
2772 OUT_AS2 (subc, w, %V1);
2773 OUT_AS2 (mov, w, %U0);
2774 OUT_AS2 (subc, w, %U1);
2775 OUT_AS2 (mov, w, %T0);
2776 OUT_AS2 (subc, w, %T1);
2777 OUT_AS2 (mov, w, %S0);
2778 OUT_AS2 (subc, w, %S1);
2779 OUT_AS1 (sc,);
2780 OUT_AS1 (page, %2);
2781 OUT_AS1 (jmp, %2);
2783 break;
2785 case GEU:
2786 if (imm_sub)
2788 HOST_WIDE_INT const_low0;
2789 HOST_WIDE_INT const_high0;
2791 if (GET_CODE (operands[0]) == CONST_INT)
2793 const_low0 = INTVAL (operands[0]);
2794 const_high0 = (const_low >= 0) - 1;
2796 else if (GET_CODE (operands[0]) == CONST_DOUBLE)
2798 const_low0 = CONST_DOUBLE_LOW (operands[0]);
2799 const_high0 = CONST_DOUBLE_HIGH (operands[0]);
2802 if (const_high0 == 0 && const_low0 == 0)
2804 OUT_AS2 (mov, w, %S1);
2805 OUT_AS2 (or, w, %T1);
2806 OUT_AS2 (or, w, %U1);
2807 OUT_AS2 (or, w, %V1);
2808 OUT_AS2 (or, w, %W1);
2809 OUT_AS2 (or, w, %X1);
2810 OUT_AS2 (or, w, %Y1);
2811 OUT_AS2 (or, w, %Z1);
2812 OUT_AS1 (snz,);
2813 OUT_AS1 (page, %2);
2814 OUT_AS1 (jmp, %2);
2816 else
2818 operands[3] = GEN_INT (const_low0 - 1);
2819 operands[4] = GEN_INT (const_high0 - (const_low0 ? 1 : 0));
2820 OUT_AS2 (mov, w, %D3);
2821 OUT_AS2 (sub, w, %Z1);
2822 OUT_AS2 (mov, w, %C3);
2823 OUT_AS2 (subc, w, %Y1);
2824 OUT_AS2 (mov, w, %B3);
2825 OUT_AS2 (subc, w, %X1);
2826 OUT_AS2 (mov, w, %A3);
2827 OUT_AS2 (subc, w, %W1);
2828 OUT_AS2 (mov, w, %D4);
2829 OUT_AS2 (subc, w, %V1);
2830 OUT_AS2 (mov, w, %C4);
2831 OUT_AS2 (subc, w, %U1);
2832 OUT_AS2 (mov, w, %B4);
2833 OUT_AS2 (subc, w, %T1);
2834 OUT_AS2 (mov, w, %A4);
2835 OUT_AS2 (subc, w, %S1);
2836 OUT_AS1 (sc,);
2837 OUT_AS1 (page, %2);
2838 OUT_AS1 (jmp, %2);
2841 else
2843 OUT_AS2 (mov, w, %Z1);
2844 OUT_AS2 (sub, w, %Z0);
2845 OUT_AS2 (mov, w, %Y1);
2846 OUT_AS2 (subc, w, %Y0);
2847 OUT_AS2 (mov, w, %X1);
2848 OUT_AS2 (subc, w, %X0);
2849 OUT_AS2 (mov, w, %W1);
2850 OUT_AS2 (subc, w, %W0);
2851 OUT_AS2 (mov, w, %V1);
2852 OUT_AS2 (subc, w, %V0);
2853 OUT_AS2 (mov, w, %U1);
2854 OUT_AS2 (subc, w, %U0);
2855 OUT_AS2 (mov, w, %T1);
2856 OUT_AS2 (subc, w, %T0);
2857 OUT_AS2 (mov, w, %S1);
2858 OUT_AS2 (subc, w, %S0);
2859 OUT_AS1 (snc,);
2860 OUT_AS1 (page, %2);
2861 OUT_AS1 (jmp, %2);
2863 break;
2865 case LTU:
2866 if (imm_sub)
2868 HOST_WIDE_INT const_low0;
2869 HOST_WIDE_INT const_high0;
2871 if (GET_CODE (operands[0]) == CONST_INT)
2873 const_low0 = INTVAL (operands[0]);
2874 const_high0 = (const_low >= 0) - 1;
2876 else if (GET_CODE (operands[0]) == CONST_DOUBLE)
2878 const_low0 = CONST_DOUBLE_LOW (operands[0]);
2879 const_high0 = CONST_DOUBLE_HIGH (operands[0]);
2882 if (const_high0 == 0 && const_low0 == 0)
2884 OUT_AS2 (mov, w, %S1);
2885 OUT_AS2 (or, w, %T1);
2886 OUT_AS2 (or, w, %U1);
2887 OUT_AS2 (or, w, %V1);
2888 OUT_AS2 (or, w, %W1);
2889 OUT_AS2 (or, w, %X1);
2890 OUT_AS2 (or, w, %Y1);
2891 OUT_AS2 (or, w, %Z1);
2892 OUT_AS1 (sz,);
2893 OUT_AS1 (page, %2);
2894 OUT_AS1 (jmp, %2);
2896 else
2898 operands[3] = GEN_INT (const_low0 - 1);
2899 operands[4] = GEN_INT (const_high0 - (const_low0 ? 1 : 0));
2900 OUT_AS2 (mov, w, %D3);
2901 OUT_AS2 (sub, w, %Z1);
2902 OUT_AS2 (mov, w, %C3);
2903 OUT_AS2 (subc, w, %Y1);
2904 OUT_AS2 (mov, w, %B3);
2905 OUT_AS2 (subc, w, %X1);
2906 OUT_AS2 (mov, w, %A3);
2907 OUT_AS2 (subc, w, %W1);
2908 OUT_AS2 (mov, w, %D4);
2909 OUT_AS2 (subc, w, %V1);
2910 OUT_AS2 (mov, w, %C4);
2911 OUT_AS2 (subc, w, %U1);
2912 OUT_AS2 (mov, w, %B4);
2913 OUT_AS2 (subc, w, %T1);
2914 OUT_AS2 (mov, w, %A4);
2915 OUT_AS2 (subc, w, %S1);
2916 OUT_AS1 (snc,);
2917 OUT_AS1 (page, %2);
2918 OUT_AS1 (jmp, %2);
2921 else
2923 OUT_AS2 (mov, w, %Z1);
2924 OUT_AS2 (sub, w, %Z0);
2925 OUT_AS2 (mov, w, %Y1);
2926 OUT_AS2 (subc, w, %Y0);
2927 OUT_AS2 (mov, w, %X1);
2928 OUT_AS2 (subc, w, %X0);
2929 OUT_AS2 (mov, w, %W1);
2930 OUT_AS2 (subc, w, %W0);
2931 OUT_AS2 (mov, w, %V1);
2932 OUT_AS2 (subc, w, %V0);
2933 OUT_AS2 (mov, w, %U1);
2934 OUT_AS2 (subc, w, %U0);
2935 OUT_AS2 (mov, w, %T1);
2936 OUT_AS2 (subc, w, %T0);
2937 OUT_AS2 (mov, w, %S1);
2938 OUT_AS2 (subc, w, %S0);
2939 OUT_AS1 (sc,);
2940 OUT_AS1 (page, %2);
2941 OUT_AS1 (jmp, %2);
2943 break;
2945 case LEU:
2946 if (imm_sub)
2948 if (((const_high & 0xffffffff) == 0xffffffff)
2949 && ((const_low & 0xffffffff) == 0xffffffff))
2951 /* <= 0xffffffffffffffff always succeeds. */
2952 OUT_AS1 (page, %2);
2953 OUT_AS1 (jmp, %2);
2955 else
2957 operands[3] = GEN_INT (const_low + 1);
2958 operands[4] = GEN_INT (const_high
2959 + (INTVAL (operands[3]) ? 0 : 1));
2960 OUT_AS2 (mov, w, %D3);
2961 OUT_AS2 (sub, w, %Z0);
2962 OUT_AS2 (mov, w, %C3);
2963 OUT_AS2 (subc, w, %Y0);
2964 OUT_AS2 (mov, w, %B3);
2965 OUT_AS2 (subc, w, %X0);
2966 OUT_AS2 (mov, w, %A3);
2967 OUT_AS2 (subc, w, %W0);
2968 OUT_AS2 (mov, w, %D4);
2969 OUT_AS2 (subc, w, %V0);
2970 OUT_AS2 (mov, w, %C4);
2971 OUT_AS2 (subc, w, %U0);
2972 OUT_AS2 (mov, w, %B4);
2973 OUT_AS2 (subc, w, %T0);
2974 OUT_AS2 (mov, w, %A4);
2975 OUT_AS2 (subc, w, %S0);
2976 OUT_AS1 (sc,);
2977 OUT_AS1 (page, %2);
2978 OUT_AS1 (jmp, %2);
2981 else
2983 OUT_AS2 (mov, w, %Z0);
2984 OUT_AS2 (sub, w, %Z1);
2985 OUT_AS2 (mov, w, %Y0);
2986 OUT_AS2 (subc, w, %Y1);
2987 OUT_AS2 (mov, w, %X0);
2988 OUT_AS2 (subc, w, %X1);
2989 OUT_AS2 (mov, w, %W0);
2990 OUT_AS2 (subc, w, %W1);
2991 OUT_AS2 (mov, w, %V0);
2992 OUT_AS2 (subc, w, %V1);
2993 OUT_AS2 (mov, w, %U0);
2994 OUT_AS2 (subc, w, %U1);
2995 OUT_AS2 (mov, w, %T0);
2996 OUT_AS2 (subc, w, %T1);
2997 OUT_AS2 (mov, w, %S0);
2998 OUT_AS2 (subc, w, %S1);
2999 OUT_AS1 (snc,);
3000 OUT_AS1 (page, %2);
3001 OUT_AS1 (jmp, %2);
3003 break;
3005 default:
3006 abort ();
3008 break;
3010 default:
3011 abort ();
3013 #undef operands
3014 return "";
3017 /* Output rtx VALUE as .byte to file FILE. */
3019 void
3020 asm_output_char (FILE *file, rtx value)
3022 fprintf (file, "\t.byte ");
3023 output_addr_const (file, value);
3024 fprintf (file, "\n");
3028 /* Output VALUE as .byte to file FILE. */
3030 void
3031 asm_output_byte (FILE *file, int value)
3033 fprintf (file, "\t.byte 0x%x\n",value & 0xff);
3037 /* Output rtx VALUE as .word to file FILE. */
3039 void
3040 asm_output_short (FILE *file, rtx value)
3042 fprintf (file, "\t.word ");
3043 output_addr_const (file, (value));
3044 fprintf (file, "\n");
3048 /* Output real N to file FILE. */
3050 void
3051 asm_output_float (FILE *file, REAL_VALUE_TYPE n)
3053 long val;
3054 char dstr[100];
3056 REAL_VALUE_TO_TARGET_SINGLE (n, val);
3057 real_to_decimal (dstr, &n, sizeof (dstr), 0, 1);
3059 fprintf (file, "\t.long 0x%08lx\t/* %s */\n", val, dstr);
3062 /* Sets section name for declaration DECL. */
3064 void
3065 unique_section (tree decl, int reloc ATTRIBUTE_UNUSED)
3067 int len;
3068 const char *name;
3069 char *string;
3070 const char *prefix;
3071 name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
3072 /* Strip off any encoding in name. */
3073 name = (* targetm.strip_name_encoding) (name);
3075 if (TREE_CODE (decl) == FUNCTION_DECL)
3077 if (flag_function_sections)
3078 prefix = ".text.";
3079 else
3080 prefix = ".text";
3082 else
3083 abort ();
3085 if (flag_function_sections)
3087 len = strlen (name) + strlen (prefix);
3088 string = alloca (len + 1);
3089 sprintf (string, "%s%s", prefix, name);
3090 DECL_SECTION_NAME (decl) = build_string (len, string);
3094 /* Return value is nonzero if pseudos that have been
3095 assigned to registers of class CLASS would likely be spilled
3096 because registers of CLASS are needed for spill registers. */
3098 enum reg_class
3099 class_likely_spilled_p (int c)
3101 return (c == IP_REGS
3102 || c == IPL_REGS
3103 || c == IPH_REGS
3104 || c == DP_SP_REGS
3105 || c == SP_REGS
3106 || c == DP_REGS
3107 || c == DPL_REGS
3108 || c == DPH_REGS
3109 || c == PTR_REGS);
3112 /* Valid attributes:
3113 progmem - put data to program memory;
3114 naked - don't generate function prologue/epilogue and `ret' command.
3116 Only `progmem' attribute valid for type. */
3118 const struct attribute_spec ip2k_attribute_table[] =
3120 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
3121 { "progmem", 0, 0, false, false, false, ip2k_handle_progmem_attribute },
3122 { "naked", 0, 0, true, false, false, ip2k_handle_fndecl_attribute },
3123 { NULL, 0, 0, false, false, false, NULL }
3126 /* Handle a "progmem" attribute; arguments as in
3127 struct attribute_spec.handler. */
3128 static tree
3129 ip2k_handle_progmem_attribute (tree *node, tree name,
3130 tree args ATTRIBUTE_UNUSED,
3131 int flags ATTRIBUTE_UNUSED,
3132 bool *no_add_attrs)
3134 if (DECL_P (*node))
3136 if (TREE_CODE (*node) == TYPE_DECL)
3138 /* This is really a decl attribute, not a type attribute,
3139 but try to handle it for GCC 3.0 backwards compatibility. */
3141 tree type = TREE_TYPE (*node);
3142 tree attr = tree_cons (name, args, TYPE_ATTRIBUTES (type));
3143 tree newtype = build_type_attribute_variant (type, attr);
3145 TYPE_MAIN_VARIANT (newtype) = TYPE_MAIN_VARIANT (type);
3146 TREE_TYPE (*node) = newtype;
3147 *no_add_attrs = true;
3149 else if (TREE_STATIC (*node) || DECL_EXTERNAL (*node))
3151 if (DECL_INITIAL (*node) == NULL_TREE && !DECL_EXTERNAL (*node))
3153 warning ("only initialized variables can be placed into "
3154 "program memory area");
3155 *no_add_attrs = true;
3158 else
3160 warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
3161 *no_add_attrs = true;
3165 return NULL_TREE;
3168 /* Handle an attribute requiring a FUNCTION_DECL; arguments as in
3169 struct attribute_spec.handler. */
3170 static tree
3171 ip2k_handle_fndecl_attribute (tree *node, tree name,
3172 tree args ATTRIBUTE_UNUSED,
3173 int flags ATTRIBUTE_UNUSED,
3174 bool *no_add_attrs)
3176 if (TREE_CODE (*node) != FUNCTION_DECL)
3178 warning ("`%s' attribute only applies to functions",
3179 IDENTIFIER_POINTER (name));
3180 *no_add_attrs = true;
3183 return NULL_TREE;
3186 /* Cost functions. */
3188 /* Compute a (partial) cost for rtx X. Return true if the complete
3189 cost has been computed, and false if subexpressions should be
3190 scanned. In either case, *TOTAL contains the cost result. */
3192 static bool
3193 ip2k_rtx_costs (rtx x, int code, int outer_code, int *total)
3195 enum machine_mode mode = GET_MODE (x);
3196 int extra_cost = 0;
3198 switch (code)
3200 case CONST_INT:
3201 case CONST_DOUBLE:
3202 case LABEL_REF:
3203 *total = 0;
3204 return true;
3205 case CONST:
3206 case SYMBOL_REF:
3207 *total = 8;
3208 return true;
3210 case MEM:
3211 *total = ip2k_address_cost (XEXP (x, 0));
3212 return true;
3214 case ROTATE:
3215 case ROTATERT:
3216 case ASHIFT:
3217 case LSHIFTRT:
3218 case ASHIFTRT:
3219 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
3221 int val = INTVAL (XEXP (x, 1));
3222 int cost;
3224 /* Shift by const instructions are proportional to
3225 the shift count modulus 8. Note that we increase the mode
3226 size multiplier by 1 to account for clearing the carry flag. */
3227 cost = COSTS_N_INSNS (abs (val) % 8);
3228 cost += rtx_cost (XEXP (x, 0), code);
3229 cost *= (GET_MODE_SIZE (mode) + 1);
3231 /* Sign-preserving shifts require 2 extra instructions. */
3232 if (code == ASHIFT)
3233 cost += COSTS_N_INSNS (2);
3235 *total = cost;
3236 return true;
3238 *total = rtx_cost (XEXP (x, 0), code);
3239 *total += COSTS_N_INSNS (GET_MODE_SIZE (mode) * 8);
3240 return true;
3242 case MINUS:
3243 case PLUS:
3244 case AND:
3245 case XOR:
3246 case IOR:
3247 *total = COSTS_N_INSNS (GET_MODE_SIZE (mode) * 3);
3248 return false;
3250 case MOD:
3251 case DIV:
3252 if (mode == QImode)
3253 *total = COSTS_N_INSNS (20);
3254 else if (mode == HImode)
3255 *total = COSTS_N_INSNS (60);
3256 else if (mode == SImode)
3257 *total = COSTS_N_INSNS (180);
3258 else
3259 *total = COSTS_N_INSNS (540);
3260 return true;
3262 case MULT:
3263 /* These costs are OK, but should really handle subtle cases
3264 where we're using sign or zero extended args as these are
3265 *much* cheaper than those given below! */
3266 if (mode == QImode)
3267 *total = COSTS_N_INSNS (4);
3268 else if (mode == HImode)
3269 *total = COSTS_N_INSNS (12);
3270 else if (mode == SImode)
3271 *total = COSTS_N_INSNS (36);
3272 else
3273 *total = COSTS_N_INSNS (108);
3274 return true;
3276 case NEG:
3277 case SIGN_EXTEND:
3278 extra_cost = COSTS_N_INSNS (GET_MODE_SIZE (mode));
3280 /* Fall through. */
3281 case NOT:
3282 case COMPARE:
3283 case ABS:
3284 *total = extra_cost + COSTS_N_INSNS (GET_MODE_SIZE (mode) * 2);
3285 return false;
3287 case TRUNCATE:
3288 case ZERO_EXTEND:
3289 if (outer_code == SET)
3291 *total = COSTS_N_INSNS (GET_MODE_SIZE (mode) * 3 / 2);
3292 return false;
3294 else
3296 *total = -(COSTS_N_INSNS (GET_MODE_SIZE (mode)) / 2);
3297 return true;
3300 case IF_THEN_ELSE:
3301 *total = rtx_cost (XEXP (x, 0), code) + COSTS_N_INSNS (2);
3302 return true;
3304 case EQ:
3305 case NE:
3306 case LTU:
3307 case GTU:
3308 case LEU:
3309 case GEU:
3310 case LT:
3311 case GT:
3312 case LE:
3313 case GE:
3314 *total = 0;
3315 return false;
3317 default:
3318 *total = COSTS_N_INSNS (4);
3319 return true;
3323 /* Calculate the cost of a memory address. */
3325 static int
3326 ip2k_address_cost (rtx x)
3328 switch (legitimate_address_p (VOIDmode, x, 0))
3330 case 'S': /* Very low cost - (IP), (SP+N) or (DP+N) */
3331 return 8;
3333 case 'R': /* Indirected through IP. */
3334 return 8;
3336 case 'L': /* Label references. */
3337 return 0;
3339 case 'C': /* Constants and symbol references. */
3340 return 4;
3342 default:
3343 return 1000; /* Must reload. */
3347 /* As part of the machine-dependent reorg we look for opcode sequences where
3348 we do some operation and then move the results back to one of the original
3349 source operands. With working on the source operand directly is probably
3350 much cheaper and the move from this to the original source operand will be
3351 no more expensive than the original move. */
3353 #ifdef IP2K_MD_REORG_PASS
3354 static void
3355 mdr_resequence_xy_yx (first_insn)
3356 rtx first_insn;
3358 rtx insn;
3360 for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
3362 rtx set;
3364 if (GET_CODE (insn) != INSN)
3365 continue;
3367 set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
3368 if (set == NULL_RTX)
3369 continue;
3371 /* Look for operations that tend to be very cheap to run when the source
3372 * and dest args are the same because the IP2022 has opcodes that can
3373 operate on the source directly. If we have to spill through the W
3374 register then we've possibly not got a good case for doing this. */
3375 if ((GET_CODE (XEXP (set, 0)) == REG
3376 || GET_CODE (XEXP (set, 0)) == MEM)
3377 && (GET_CODE (XEXP (set, 1)) == ASHIFT
3378 || GET_CODE (XEXP (set, 1)) == ASHIFTRT
3379 || GET_CODE (XEXP (set, 1)) == LSHIFTRT
3380 || GET_CODE (XEXP (set, 1)) == XOR
3381 || GET_CODE (XEXP (set, 1)) == IOR
3382 || GET_CODE (XEXP (set, 1)) == AND
3383 || GET_CODE (XEXP (set, 1)) == PLUS
3384 || GET_CODE (XEXP (set, 1)) == MINUS
3385 || GET_CODE (XEXP (set, 1)) == MULT))
3387 rtx set2;
3388 rtx next_insn;
3390 next_insn = next_nonnote_insn (insn);
3391 if (! next_insn)
3392 continue;
3394 if (GET_CODE (next_insn) != INSN)
3395 continue;
3397 set2 = ((GET_CODE (PATTERN (next_insn)) == SET)
3398 ? PATTERN (next_insn) : NULL_RTX);
3399 if (set2 == NULL_RTX)
3400 continue;
3402 if ((GET_CODE (XEXP (XEXP (set, 1), 0)) == REG
3403 || GET_CODE (XEXP (XEXP (set, 1), 0)) == MEM)
3404 && rtx_equal_p (XEXP (set2, 0), XEXP (XEXP (set, 1), 0))
3405 && rtx_equal_p (XEXP (set2, 1), XEXP (set, 0)))
3407 rtx next2_insn;
3408 rtx b_insn;
3410 b_insn = gen_rtx_SET (VOIDmode,
3411 XEXP (XEXP (set, 1), 0),
3412 gen_rtx_fmt_ee (GET_CODE (XEXP (set, 1)),
3413 GET_MODE (XEXP (set, 0)),
3414 XEXP (XEXP (set, 1), 0),
3415 XEXP (XEXP (set, 1), 1)));
3417 emit_insn_before (b_insn, insn);
3418 b_insn = gen_rtx_SET (GET_MODE (XEXP (set, 0)), XEXP (set, 0),
3419 XEXP (XEXP (set, 1), 0));
3420 next2_insn = emit_insn_before (b_insn, insn);
3421 delete_insn (insn);
3422 delete_insn (next_insn);
3423 insn = next2_insn;
3424 continue;
3427 /* Having tried with one operand of the expression, now, if
3428 appropriate, try to do the same thing with the second operand.
3429 Of course there are fewer operations that can match here
3430 because they must be commutative. */
3431 if (GET_RTX_CLASS (GET_CODE (XEXP (set, 1))) == RTX_COMM_ARITH
3432 && (GET_CODE (XEXP (XEXP (set, 1), 1)) == REG
3433 || GET_CODE (XEXP (XEXP (set, 1), 1)) == MEM)
3434 && rtx_equal_p (XEXP (set2, 0), XEXP (XEXP (set, 1), 1))
3435 && rtx_equal_p (XEXP (set2, 1), XEXP (set, 0)))
3437 rtx rtx_ee;
3438 rtx next2_insn;
3439 int swap_args;
3441 /* Try to ensure that we put things in a canonical form. */
3442 swap_args = (GET_CODE (XEXP (XEXP (set, 1), 0)) == REG
3443 || GET_CODE (XEXP (XEXP (set, 1), 0)) == MEM);
3444 rtx_ee = gen_rtx_fmt_ee (GET_CODE (XEXP (set, 1)),
3445 GET_MODE (XEXP (set, 0)),
3446 XEXP (XEXP (set, 1), swap_args ? 1 : 0),
3447 XEXP (XEXP (set, 1),
3448 swap_args ? 0 : 1));
3450 emit_insn_before (gen_rtx_SET (VOIDmode,
3451 XEXP (XEXP (set, 1), 1),
3452 rtx_ee),
3453 insn);
3454 next2_insn = emit_insn_before (gen_rtx_SET
3455 (GET_MODE (XEXP (set, 0)),
3456 XEXP (set, 0),
3457 XEXP (XEXP (set, 1), 1)),
3458 insn);
3459 delete_insn (insn);
3460 delete_insn (next_insn);
3461 insn = next2_insn;
3467 /* Replace and recurse until we've tried QImode pieces! */
3469 static void
3470 mdr_pres_replace_and_recurse (orig, with, insn)
3471 rtx orig;
3472 rtx with;
3473 rtx insn;
3475 enum machine_mode new_mode;
3477 validate_replace_rtx (orig, with, insn);
3479 switch (GET_MODE (orig))
3481 case DImode:
3482 case DFmode:
3483 new_mode = SImode;
3484 break;
3486 case SImode:
3487 case SFmode:
3488 new_mode = HImode;
3489 break;
3491 case HImode:
3492 new_mode = QImode;
3493 break;
3495 default:
3496 return;
3499 mdr_pres_replace_and_recurse (ip2k_get_low_half (orig, new_mode),
3500 ip2k_get_low_half (with, new_mode),
3501 insn);
3502 mdr_pres_replace_and_recurse (ip2k_get_high_half (orig, new_mode),
3503 ip2k_get_high_half (with, new_mode),
3504 insn);
3507 /* Assist the following function, mdr_propagate_reg_equivs(). */
3509 static void
3510 mdr_propagate_reg_equivs_sequence (first_insn, orig, equiv)
3511 rtx first_insn;
3512 rtx orig;
3513 rtx equiv;
3515 rtx try_insn;
3516 rtx try_equiv = equiv;
3518 /* First scan the RTL looking for anything else that might clobber what
3519 we're doing. If we find anything then we can't do the replacement. */
3520 for (try_insn = next_nonnote_insn (first_insn);
3521 try_insn; try_insn = next_nonnote_insn (try_insn))
3523 rtx pattern;
3525 if (GET_CODE (try_insn) != JUMP_INSN && GET_CODE (try_insn) != INSN)
3526 continue;
3528 pattern = PATTERN (try_insn);
3529 if (GET_CODE (pattern) == PARALLEL)
3531 int j;
3533 for (j = 0; j < XVECLEN (pattern, 0); j++)
3535 rtx px = XVECEXP (pattern, 0, j);
3537 if (GET_CODE (px) == SET)
3538 if (! ip2k_composite_xexp_not_uses_reg_p (XEXP (px, 0),
3539 REGNO (orig),
3540 GET_MODE_SIZE (GET_MODE (orig))))
3541 return;
3544 else if (GET_CODE (pattern) == SET)
3546 if (! ip2k_composite_xexp_not_uses_reg_p (XEXP (pattern, 0),
3547 REGNO (orig),
3548 GET_MODE_SIZE (GET_MODE (orig))))
3549 return;
3553 /* Once we've decided that we're safe to do the replacement then make the
3554 changes. */
3555 for (try_insn = next_nonnote_insn (first_insn); try_insn;
3556 try_insn = next_nonnote_insn (try_insn))
3558 rtx set;
3559 rtx new_equiv = NULL_RTX;
3561 if (GET_CODE (try_insn) != JUMP_INSN && GET_CODE (try_insn) != INSN)
3563 try_equiv = equiv;
3564 continue;
3567 set = ((GET_CODE (PATTERN (try_insn)) == SET)
3568 ? PATTERN (try_insn) : NULL_RTX);
3569 if (set == NULL_RTX)
3570 continue;
3572 /* We look for a special case of "push" operations screwing our
3573 register equivalence when it's based on a stack slot. We can
3574 track this one and replace the old equivalence expression with
3575 a new one. */
3576 if (GET_CODE (XEXP (set, 0)) == MEM
3577 && GET_CODE (XEXP (XEXP (set, 0), 0)) == POST_DEC
3578 && REG_P (XEXP (XEXP (XEXP (set, 0), 0), 0))
3579 && REGNO (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG_SP)
3581 /* XXX - need to ensure that we can track this without going
3582 out of range! */
3583 HOST_WIDE_INT disp = (INTVAL (XEXP (XEXP (try_equiv, 0), 1))
3584 + GET_MODE_SIZE (GET_MODE (XEXP (set, 0))));
3585 new_equiv = gen_rtx_MEM (GET_MODE (try_equiv),
3586 gen_rtx_PLUS (Pmode,
3587 gen_rtx_REG (HImode, REG_SP),
3588 GEN_INT (disp)));
3591 /* The replacement process is somewhat complicated by the fact that we
3592 might be dealing with what were originally subregs and thus we have
3593 to replace parts of our original expression! */
3594 mdr_pres_replace_and_recurse (orig, try_equiv, try_insn);
3596 if (new_equiv != NULL_RTX)
3597 try_equiv = new_equiv;
3601 /* Try propagating register equivalences forwards. It may be that we can
3602 replace a register use with an equivalent expression that already
3603 holds the same value and thus allow one or more register loads to
3604 be eliminated. */
3606 static void
3607 mdr_propagate_reg_equivs (first_insn)
3608 rtx first_insn;
3610 rtx insn;
3611 rtx set;
3613 for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
3615 if (GET_CODE (insn) != INSN)
3616 continue;
3618 set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
3619 if (set == NULL_RTX)
3620 continue;
3622 /* Have we found a stack slot equivalence for a register? */
3623 if (REG_P (XEXP (set, 0))
3624 && REGNO (XEXP (set, 0)) >= 0x88
3625 && GET_CODE (XEXP (set, 1)) == MEM
3626 && GET_CODE (XEXP (XEXP (set, 1), 0)) == PLUS
3627 && REG_P (XEXP (XEXP (XEXP (set, 1), 0), 0))
3628 && REGNO (XEXP (XEXP (XEXP (set, 1), 0), 0)) == REG_SP
3629 && find_reg_note (insn, REG_EQUIV, NULL_RTX))
3631 mdr_propagate_reg_equivs_sequence (insn, XEXP (set, 0),
3632 XEXP (set, 1));
3637 /* Structure used to track jump targets. */
3639 struct dpre_jump_targets
3641 int target; /* Is this a jump target? */
3642 int reach_count; /* Number of ways we can reach this insn. */
3643 int touch_count; /* Number of times we've touched this
3644 insns during scanning. */
3645 rtx dp_equiv; /* DP-equivalence at this point. */
3648 struct dpre_jump_targets *ip2k_dpre_jump_targets;
3650 /* DP equivalence tracking used within DP reload elimination. */
3652 static int
3653 track_dp_reload (insn, dp_current, dp_current_ok, modifying)
3654 rtx insn;
3655 rtx *dp_current;
3656 int dp_current_ok;
3657 int modifying;
3659 rtx set;
3661 if (GET_CODE (insn) != INSN)
3663 *dp_current = NULL_RTX;
3664 return 1;
3667 set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
3668 if (set == NULL_RTX)
3670 *dp_current = NULL_RTX;
3671 return 1;
3674 /* If we're pushing a PLUS or MINUS then it's a win if we can replace
3675 an expression for which DP is equivalent with DP. This happens
3676 surprisingly often when we pass a pointer to a structure embedded
3677 within another structure. */
3678 if (*dp_current != NULL_RTX
3679 && GET_CODE (XEXP (set, 0)) == MEM
3680 && GET_CODE (XEXP (XEXP (set, 0), 0)) == POST_DEC
3681 && GET_CODE (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG
3682 && REGNO (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG_SP
3683 && (GET_CODE (XEXP (set, 1)) == PLUS
3684 || GET_CODE (XEXP (set, 1)) == MINUS)
3685 && GET_CODE (*dp_current) != SYMBOL_REF
3686 && GET_CODE (*dp_current) != LABEL_REF
3687 && GET_CODE (*dp_current) != CONST)
3689 if (modifying)
3690 validate_replace_rtx (*dp_current, gen_rtx_REG (HImode, REG_DP), insn);
3693 /* Look for DP being modified. If it is, see if it's being changed
3694 to what it already is! */
3695 if (GET_CODE (XEXP (set, 0)) == REG
3696 && REGNO (XEXP (set, 0)) == REG_DP
3697 && GET_MODE (XEXP (set, 0)) == HImode)
3699 /* If this is an equivalence we can delete the new set operation. */
3700 if (*dp_current != NULL_RTX
3701 && rtx_equal_p (XEXP (set, 1), *dp_current))
3703 if (modifying)
3704 delete_insn (insn);
3706 else
3708 /* If we've not found an equivalence we can look for a special
3709 case where an operand of the expression that sets DP is
3710 already equivalent to DP and in that circumstance we simplify
3711 by replacing that expression with DP. */
3712 if (*dp_current != NULL_RTX
3713 && GET_CODE (*dp_current) != SYMBOL_REF
3714 && GET_CODE (*dp_current) != LABEL_REF
3715 && GET_CODE (*dp_current) != CONST
3716 && modifying)
3717 validate_replace_rtx (*dp_current, XEXP (set, 0), insn);
3719 /* Assuming that we're not loading DP from something that uses DP
3720 itself then we mark the new equivalence for DP. If we did match
3721 DP then we can't re-use this one. */
3722 if (ip2k_xexp_not_uses_reg_p (XEXP (set, 1), REG_DP, 2))
3724 *dp_current = XEXP (set, 1);
3725 return 1;
3727 else
3729 *dp_current = NULL_RTX;
3730 return 1;
3734 else if (GET_CODE (XEXP (set, 0)) == REG
3735 && (REGNO (XEXP (set, 0)) == REG_DPL
3736 || REGNO (XEXP (set, 0)) == REG_DPH))
3738 /* If we clobber part of DP then we've clobbered any equivalences! */
3739 *dp_current = NULL_RTX;
3740 return 1;
3742 else if (! ip2k_xexp_not_uses_reg_p (XEXP (set, 0), REG_SP, 2)
3743 && *dp_current != NULL_RTX
3744 && !ip2k_xexp_not_uses_reg_p (*dp_current, REG_SP, 2))
3746 /* We look for a special case of "push" operations screwing up the
3747 setting of DP when it's based on the stack. We can track this one
3748 and replace the old expression for DP with a new one. */
3749 if (GET_CODE (XEXP (set, 0)) == MEM
3750 && GET_CODE (XEXP (XEXP (set, 0), 0)) == POST_DEC
3751 && GET_CODE (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG
3752 && REGNO (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG_SP
3753 && GET_CODE (*dp_current) == MEM
3754 && GET_CODE (XEXP (*dp_current, 0)) == PLUS)
3756 /* XXX - need to ensure that we can track this without going
3757 out of range! */
3758 HOST_WIDE_INT disp = (INTVAL (XEXP (XEXP (*dp_current, 0), 1))
3759 + GET_MODE_SIZE (GET_MODE (XEXP (set, 0))));
3760 *dp_current = gen_rtx_MEM (HImode,
3761 gen_rtx_PLUS (Pmode,
3762 gen_rtx_REG (HImode, REG_SP),
3763 GEN_INT (disp)));
3764 return 1;
3767 /* Now we look for writes to the stack. We can determine if these will
3768 affect the equivalence we're tracking for DP and if not then we can
3769 keep tracking it. */
3770 if (GET_CODE (XEXP (set, 0)) == MEM
3771 && GET_CODE (*dp_current) == MEM)
3773 /* Look at the SP offsets and look for any overlaps. */
3774 int dp_cur_sp_offs = INTVAL (XEXP (XEXP (*dp_current, 0), 1));
3775 int set_sp_offs = INTVAL (XEXP (XEXP (XEXP (set, 0), 0), 1));
3777 if (abs (dp_cur_sp_offs - set_sp_offs) < 2)
3779 *dp_current = NULL_RTX;
3780 return 1;
3784 else if (GET_CODE (XEXP (set, 0)) == REG
3785 && *dp_current != NULL_RTX
3786 && !ip2k_xexp_not_uses_reg_p (*dp_current, REGNO (XEXP (set, 0)),
3787 GET_MODE_SIZE (GET_MODE (XEXP (set,
3788 0)))))
3790 /* If we've just clobbered all or part of a register reference that we
3791 were sharing for DP then we can't share it any more! */
3792 *dp_current = NULL_RTX;
3795 return dp_current_ok;
3798 /* As part of the machine-dependent reorg we scan loads and reloads of
3799 DP to see where any are redundant. This does happens because we
3800 are able to subsequently transform things in interesting ways. Sometimes
3801 gcc also does unnecessary reloads too so we try to eliminate these too. */
3803 static void
3804 mdr_try_dp_reload_elim (first_insn)
3805 rtx first_insn;
3807 rtx insn;
3808 struct dpre_jump_targets *djt;
3809 rtx dp_current;
3810 int incomplete_scan;
3811 int last_incomplete_scan;
3813 ip2k_dpre_jump_targets
3814 = (struct dpre_jump_targets *) xcalloc (get_max_uid (),
3815 sizeof (struct dpre_jump_targets));
3817 /* First we scan to build up a list of all CODE_LABEL insns and we work out
3818 how many different ways we can reach them. */
3819 for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
3821 if (GET_CODE (insn) == CODE_LABEL)
3823 djt = &ip2k_dpre_jump_targets[INSN_UID (insn)];
3824 djt->target = 1;
3825 djt->reach_count = LABEL_NUSES (insn);
3826 djt->touch_count = 0;
3827 djt->dp_equiv = NULL_RTX;
3828 if (! prev_nonnote_insn (insn)
3829 || (prev_nonnote_insn (insn)
3830 && GET_CODE (prev_nonnote_insn (insn)) != BARRIER))
3831 djt->reach_count++;
3835 /* Next we scan all of the ways of reaching the code labels to see
3836 what the DP register is equivalent to as we reach them. If we find
3837 that they're the same then we keep noting the matched value. We
3838 iterate around this until we reach a convergence on DP equivalences
3839 at all code labels - we have to be very careful not to be too
3840 optimistic! */
3841 incomplete_scan = -1;
3844 int dp_current_ok = 0;
3845 last_incomplete_scan = incomplete_scan;
3846 dp_current = NULL_RTX;
3848 for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
3850 /* If we have a code label then we need to see if we already know
3851 what the equivalence is at this point. If we do then we use it
3852 immediately, but if we don't then we have a special case to track
3853 when we hit a fallthrough-edge (label with no barrier preceding
3854 it). Any other accesses to the label must be from jump insns
3855 and so they're handled elsewhere. */
3856 if (GET_CODE (insn) == CODE_LABEL)
3858 djt = &ip2k_dpre_jump_targets[INSN_UID (insn)];
3860 /* If we're fully characterized the use the equivalence. */
3861 if (djt->touch_count == djt->reach_count)
3863 dp_current = djt->dp_equiv;
3864 dp_current_ok = 1;
3865 continue;
3868 /* If we have a known equivalence for DP as we reach the
3869 fallthrough-edge then track this into the code label. */
3870 if (dp_current_ok
3871 && (! prev_nonnote_insn (insn)
3872 || (prev_nonnote_insn (insn)
3873 && GET_CODE (prev_nonnote_insn (insn)) != BARRIER)))
3875 if (djt->touch_count == 0)
3876 djt->dp_equiv = dp_current;
3878 if (djt->touch_count < djt->reach_count)
3880 djt->touch_count++;
3881 if (! rtx_equal_p (djt->dp_equiv, dp_current))
3883 /* When we definitely know that we can't form an
3884 equivalence for DP here we must clobber anything
3885 that we'd started to track too. */
3886 djt->dp_equiv = NULL_RTX;
3887 dp_current = NULL_RTX;
3888 dp_current_ok = 1;
3893 /* If we've not completely characterized this code label then
3894 be cautious and assume that we don't know what DP is
3895 equivalent to. */
3896 if (djt->touch_count < djt->reach_count)
3898 dp_current = NULL_RTX;
3899 dp_current_ok = 0;
3902 continue;
3905 /* If we've hit a jump insn then we look for either an address
3906 vector (jump table) or for jump label references. */
3907 if (GET_CODE (insn) == JUMP_INSN)
3909 /* Don't attempt to track here if we don't have a known
3910 equivalence for DP at this point. */
3911 if (dp_current_ok)
3913 rtx pat = PATTERN (insn);
3914 if (GET_CODE (pat) == ADDR_VEC)
3916 int i;
3917 int len = XVECLEN (pat, 0);
3919 for (i = 0; i < len; i++)
3921 rtx vec_insn = XEXP (XVECEXP (pat, 0, i), 0);
3922 djt = &ip2k_dpre_jump_targets [INSN_UID (vec_insn)];
3924 if (djt->touch_count == 0)
3925 djt->dp_equiv = dp_current;
3927 if (djt->touch_count < djt->reach_count)
3929 djt->touch_count++;
3930 if (! rtx_equal_p (djt->dp_equiv, dp_current))
3931 djt->dp_equiv = NULL_RTX;
3935 else if (JUMP_LABEL (insn))
3937 rtx j_insn = JUMP_LABEL (insn);
3938 djt = &ip2k_dpre_jump_targets[INSN_UID (j_insn)];
3940 if (djt->touch_count == 0)
3941 djt->dp_equiv = dp_current;
3943 if (djt->touch_count < djt->reach_count)
3945 djt->touch_count++;
3946 if (! rtx_equal_p (djt->dp_equiv, dp_current))
3947 djt->dp_equiv = NULL_RTX;
3952 continue;
3955 /* Anything other than a code labal or jump arrives here.
3956 We try and track DP, but sometimes we might not be able to. */
3957 dp_current_ok = track_dp_reload (insn, &dp_current,
3958 dp_current_ok, 0);
3961 /* When we're looking to see if we've finished we count the number of
3962 paths through the code labels where we weren't able to definitively
3963 track DP.
3964 This number is used to see if we're converging on a solution.
3965 If this hits zero then we've fully converged, but if this stays the
3966 same as last time then we probably can't make any further
3967 progress. */
3968 incomplete_scan = 0;
3969 for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
3971 if (GET_CODE (insn) == CODE_LABEL)
3973 djt = &ip2k_dpre_jump_targets[INSN_UID (insn)];
3974 if (djt->touch_count != djt->reach_count)
3976 incomplete_scan += (djt->reach_count - djt->touch_count);
3977 djt->dp_equiv = NULL_RTX;
3978 djt->touch_count = 0;
3983 while (incomplete_scan && incomplete_scan != last_incomplete_scan);
3985 /* Finally we scan the whole function and run DP elimination. When we hit
3986 a CODE_LABEL we pick up any stored equivalence since we now know that
3987 every path to this point entered with DP holding the same thing! If
3988 we subsequently have a reload that matches then we can eliminate it. */
3989 dp_current = NULL_RTX;
3990 for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
3992 if (GET_CODE (insn) == JUMP_INSN)
3993 continue;
3995 if (GET_CODE (insn) == CODE_LABEL)
3997 djt = &ip2k_dpre_jump_targets[INSN_UID (insn)];
3998 dp_current = djt->dp_equiv;
3999 continue;
4002 track_dp_reload (insn, &dp_current, 1, 1);
4005 free (ip2k_dpre_jump_targets);
4008 /* As part of the machine-dependent reorg we look for reloads of DP
4009 that we can move to earlier points within the file.
4010 Moving these out of the way allows more peepholes to match. */
4012 static void
4013 mdr_try_move_dp_reload (first_insn)
4014 rtx first_insn;
4016 rtx insn;
4017 rtx set;
4018 rtx orig_first;
4020 /* Don't try to match the first instruction because we can't move it
4021 anyway. */
4022 orig_first = first_insn;
4023 first_insn = next_nonnote_insn (first_insn);
4025 for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
4027 if (GET_CODE (insn) != INSN)
4028 continue;
4030 set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
4031 if (set == NULL_RTX)
4032 continue;
4034 /* Look for DP being loaded. When we find this we start a rewind
4035 scan looking for possible positions to move this to. */
4036 if (GET_CODE (XEXP (set, 0)) == REG
4037 && REGNO (XEXP (set, 0)) == REG_DP
4038 && GET_MODE (XEXP (set, 0)) == HImode)
4040 int try_again;
4041 rtx try_insn = insn;
4045 rtx rewind;
4046 rtx check;
4048 try_again = 0;
4050 /* For now we do the *really* simple version of things and only
4051 attempt to move the load of DP if it's very safe to do so. */
4052 rewind = prev_nonnote_insn (try_insn);
4053 if (rewind != orig_first && rewind != NULL_RTX
4054 && GET_CODE (rewind) == INSN)
4056 check = ((GET_CODE (PATTERN (rewind)) == SET)
4057 ? PATTERN (rewind) : NULL_RTX);
4058 if (check != NULL_RTX
4059 && ip2k_composite_xexp_not_uses_cc0_p (XEXP (check, 0))
4060 && ip2k_composite_xexp_not_uses_cc0_p (XEXP (check, 1)))
4062 if (GET_CODE (XEXP (check, 0)) == REG
4063 && REGNO (XEXP (check, 0)) != REG_DPH
4064 && REGNO (XEXP (check, 0)) != REG_DPL
4065 && (ip2k_composite_xexp_not_uses_reg_p
4066 (XEXP (check, 1), REG_DP, 2))
4067 && (ip2k_composite_xexp_not_uses_reg_p
4068 (XEXP (set, 1),
4069 REGNO (XEXP (check, 0)),
4070 GET_MODE_SIZE (GET_MODE (XEXP (check, 0))))))
4072 emit_insn_before (set, rewind);
4073 if (try_insn == insn)
4074 insn = prev_nonnote_insn (insn);
4075 delete_insn (try_insn);
4076 try_insn = prev_nonnote_insn (rewind);
4077 try_again = 1;
4079 else if (GET_CODE (XEXP (set, 1)) == REG
4080 && ip2k_composite_xexp_not_uses_reg_p (XEXP (check, 1), REG_DP, 2)
4081 && ip2k_composite_xexp_not_uses_reg_p (XEXP (check, 0), REG_DP, 2)
4082 && ip2k_composite_xexp_not_uses_reg_p (XEXP (check, 0), REGNO (XEXP (set, 1)),
4083 GET_MODE_SIZE (GET_MODE (XEXP (set, 1)))))
4085 emit_insn_before (set, rewind);
4086 if (try_insn == insn)
4087 insn = prev_nonnote_insn (insn);
4088 delete_insn (try_insn);
4089 try_insn = prev_nonnote_insn (rewind);
4090 try_again = 1;
4095 while (try_again && try_insn);
4099 #endif /* IP2K_MD_REORG_PASS */
4101 /* Look to see if the expression, x, can have any stack references offset by
4102 a fixed constant, offset. If it definitely can then returns nonzero. */
4104 static int
4105 ip2k_check_can_adjust_stack_ref (rtx x, int offset)
4107 if (ARITHMETIC_P (x))
4108 return (ip2k_check_can_adjust_stack_ref (XEXP (x, 0), offset)
4109 && ip2k_check_can_adjust_stack_ref (XEXP (x, 1), offset));
4111 if (UNARY_P (x))
4112 return ip2k_check_can_adjust_stack_ref (XEXP (x, 0), offset);
4114 switch (GET_CODE (x))
4116 case REG:
4117 return (REGNO (x) != REG_SPH && REGNO (x) != REG_SPL);
4119 case MEM:
4120 if (GET_CODE (XEXP (x, 0)) != PLUS)
4121 return 1;
4123 if (GET_CODE (XEXP (XEXP (x, 0), 0)) != REG)
4124 return 1;
4126 if (REGNO (XEXP (XEXP (x, 0), 0)) != REG_SP)
4127 return 1;
4129 /* We can't allow this if the adjustment will create an
4130 invalid address. */
4131 return (INTVAL (XEXP (XEXP (x, 0), 1))
4132 + offset <= (128 - 2 * GET_MODE_SIZE (GET_MODE (x))));
4134 case CONST:
4135 case CONST_INT:
4136 case CONST_DOUBLE:
4137 case SYMBOL_REF:
4138 case LABEL_REF:
4139 return 1;
4141 default:
4142 return 0;
4146 /* Adjusts all of the stack references in the expression pointed to by x by
4147 a fixed offset. */
4149 static void
4150 ip2k_adjust_stack_ref (rtx *x, int offset)
4152 if (ARITHMETIC_P (*x))
4154 ip2k_adjust_stack_ref (&XEXP (*x, 0), offset);
4155 ip2k_adjust_stack_ref (&XEXP (*x, 1), offset);
4156 return;
4159 if (UNARY_P (*x))
4161 ip2k_adjust_stack_ref (&XEXP (*x, 0), offset);
4162 return;
4165 switch (GET_CODE (*x))
4167 case MEM:
4168 if (GET_CODE (XEXP (*x, 0)) != PLUS)
4169 return;
4171 if (GET_CODE (XEXP (XEXP (*x, 0), 0)) != REG)
4172 return;
4174 if (REGNO (XEXP (XEXP (*x, 0), 0)) != REG_SP)
4175 return;
4177 *x = copy_rtx (*x);
4178 XEXP (XEXP (*x, 0), 1) = GEN_INT (INTVAL (XEXP (XEXP (*x, 0), 1))
4179 + offset);
4180 break;
4182 default:
4183 break;
4187 #ifdef IP2K_MD_REORG_PASS
4188 /* As part of the machine-dependent reorg we look to move push instructions
4189 to earlier points within the file. Moving these out of the way allows more
4190 peepholes to match. */
4192 static void
4193 mdr_try_move_pushes (first_insn)
4194 rtx first_insn;
4196 rtx insn;
4197 rtx set;
4198 rtx orig_first;
4200 /* Don't try to match the first instruction because we can't move
4201 it anyway. */
4202 orig_first = first_insn;
4203 first_insn = next_nonnote_insn (first_insn);
4205 for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
4207 if (GET_CODE (insn) != INSN)
4208 continue;
4210 set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
4211 if (set == NULL_RTX)
4212 continue;
4214 /* Have we found a push instruction? */
4215 if (GET_CODE (XEXP (set, 0)) == MEM
4216 && GET_CODE (XEXP (XEXP (set, 0), 0)) == POST_DEC
4217 && GET_CODE (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG
4218 && REGNO (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG_SP
4219 && GET_CODE (XEXP (set, 1)) == REG)
4221 rtx try_insn = insn;
4222 unsigned int regno = REGNO (XEXP (set, 1));
4223 int reg_range = GET_MODE_SIZE (GET_MODE (XEXP (set, 1)));
4225 while (1)
4227 rtx rewind;
4228 rtx check;
4230 rewind = prev_nonnote_insn (try_insn);
4231 if (rewind == orig_first || rewind == NULL_RTX
4232 || GET_CODE (rewind) != INSN)
4233 break;
4235 check = (GET_CODE (PATTERN (rewind)) == SET) ? PATTERN (rewind) : NULL_RTX;
4236 if (check == NULL_RTX)
4237 break;
4239 if (! ip2k_check_can_adjust_stack_ref (XEXP (check, 0),
4240 reg_range)
4241 || ! ip2k_check_can_adjust_stack_ref (XEXP (check, 1),
4242 reg_range))
4243 break;
4245 /* If we've hit another push instruction we can't go any
4246 further. */
4247 if (GET_CODE (XEXP (check, 0)) == MEM
4248 && GET_CODE (XEXP (XEXP (check, 0), 0)) == POST_DEC
4249 && GET_CODE (XEXP (XEXP (XEXP (check, 0), 0), 0)) == REG
4250 && REGNO (XEXP (XEXP (XEXP (check, 0), 0), 0)) == REG_SP)
4251 break;
4253 /* If this is a register move then check that it doesn't clobber
4254 SP or any part of the instruction we're trying to move. */
4255 if (GET_CODE (XEXP (check, 0)) == REG)
4257 unsigned int check_reg = REGNO (XEXP (check, 0));
4258 int check_reg_range = GET_MODE_SIZE (GET_MODE (XEXP (check,
4259 0)));
4261 /* If we have a special case where what we want to push is
4262 being loaded by this "clobbering" insn then we can just
4263 push what is being used to load us and then do the load.
4264 This may seem a little odd, but we may subsequently be
4265 able to merge the load with another instruction as it
4266 may only be used once now! Note though that we
4267 specifically don't try this if the expression being
4268 loaded is an HImode MEM using IP. */
4269 if (check_reg == regno
4270 && check_reg_range == reg_range
4271 && ((GET_CODE (XEXP (check, 1)) == REG
4272 || (GET_CODE (XEXP (check, 1)) == MEM
4273 && (GET_MODE (XEXP (check, 1)) != HImode
4274 || ip2k_xexp_not_uses_reg_for_mem (XEXP (check, 1), REG_IP))))))
4276 switch (check_reg_range)
4278 case 1:
4279 emit_insn_before (gen_movqi (XEXP (set, 0),
4280 XEXP (check, 1)),
4281 rewind);
4282 delete_insn (try_insn);
4283 break;
4285 case 2:
4286 emit_insn_before (gen_movhi (XEXP (set, 0),
4287 XEXP (check, 1)),
4288 rewind);
4289 delete_insn (try_insn);
4290 break;
4292 case 4:
4293 emit_insn_before (gen_movsi (XEXP (set, 0),
4294 XEXP (check, 1)),
4295 rewind);
4296 delete_insn (try_insn);
4297 break;
4299 case 8:
4300 emit_insn_before (gen_movdi (XEXP (set, 0),
4301 XEXP (check, 1)),
4302 rewind);
4303 delete_insn (try_insn);
4304 break;
4307 ip2k_adjust_stack_ref (&XEXP (check, 0), reg_range);
4308 ip2k_adjust_stack_ref (&XEXP (check, 1), reg_range);
4309 try_insn = prev_nonnote_insn (rewind);
4310 /* XXX - should be a continue? */
4311 break;
4314 if ((check_reg == REG_SPL)
4315 || (check_reg == REG_SPH)
4316 || (((regno <= check_reg)
4317 && (regno + reg_range - 1) >= check_reg)
4318 || ((regno <= (check_reg + check_reg_range - 1))
4319 && ((regno + reg_range - 1)
4320 >= (check_reg + check_reg_range - 1)))))
4321 break;
4324 emit_insn_before (set, rewind);
4325 delete_insn (try_insn);
4326 ip2k_adjust_stack_ref (&XEXP (check, 0), reg_range);
4327 ip2k_adjust_stack_ref (&XEXP (check, 1), reg_range);
4328 try_insn = prev_nonnote_insn (rewind);
4334 /* Assist the following function, mdr_try_propagate_clr(). */
4336 static void
4337 mdr_try_propagate_clr_sequence (first_insn, regno)
4338 rtx first_insn;
4339 unsigned int regno;
4341 rtx try_insn;
4343 for (try_insn = next_nonnote_insn (first_insn); try_insn;
4344 try_insn = next_nonnote_insn (try_insn))
4346 rtx new_insn = NULL_RTX;
4347 rtx set2;
4349 if (GET_CODE (try_insn) == JUMP_INSN)
4350 continue;
4352 if (GET_CODE (try_insn) != INSN)
4353 break;
4355 set2 = ((GET_CODE (PATTERN (try_insn)) == SET)
4356 ? PATTERN (try_insn) : NULL_RTX);
4357 if (set2 == NULL_RTX)
4358 continue;
4360 if (GET_CODE (XEXP (set2, 1)) == AND
4361 && ((GET_CODE (XEXP (XEXP (set2, 1), 0)) == REG
4362 && REGNO (XEXP (XEXP (set2, 1), 0)) == regno)
4363 || (GET_CODE (XEXP (XEXP (set2, 1), 1)) == REG
4364 && REGNO (XEXP (XEXP (set2, 1), 1)) == regno)))
4366 rtx remove_insn = try_insn;
4367 try_insn = emit_insn_before (gen_rtx_SET (QImode, XEXP (set2, 0),
4368 const0_rtx), try_insn);
4369 delete_insn (remove_insn);
4371 else if (GET_CODE (XEXP (set2, 1)) == IOR
4372 && GET_CODE (XEXP (XEXP (set2, 1), 0)) == REG
4373 && REGNO (XEXP (XEXP (set2, 1), 0)) == regno)
4375 rtx remove_insn = try_insn;
4376 try_insn = emit_insn_before (gen_rtx_SET (QImode, XEXP (set2, 0),
4377 XEXP (XEXP (set2, 1), 1)),
4378 try_insn);
4379 delete_insn (remove_insn);
4381 else if (GET_CODE (XEXP (set2, 1)) == IOR
4382 && GET_CODE (XEXP (XEXP (set2, 1), 1)) == REG
4383 && REGNO (XEXP (XEXP (set2, 1), 1)) == regno)
4385 rtx remove_insn = try_insn;
4386 try_insn = emit_insn_before (gen_rtx_SET (QImode, XEXP (set2, 0),
4387 XEXP (XEXP (set2, 1), 0)),
4388 try_insn);
4389 delete_insn (remove_insn);
4391 else if (GET_CODE (XEXP (set2, 1)) == XOR
4392 && GET_CODE (XEXP (XEXP (set2, 1), 0)) == REG
4393 && REGNO (XEXP (XEXP (set2, 1), 0)) == regno)
4395 rtx remove_insn = try_insn;
4396 try_insn = emit_insn_before (gen_rtx_SET (QImode, XEXP (set2, 0),
4397 XEXP (XEXP (set2, 1), 1)),
4398 try_insn);
4399 delete_insn (remove_insn);
4401 else if (GET_CODE (XEXP (set2, 1)) == XOR
4402 && GET_CODE (XEXP (XEXP (set2, 1), 1)) == REG
4403 && REGNO (XEXP (XEXP (set2, 1), 1)) == regno)
4405 rtx remove_insn = try_insn;
4406 try_insn = emit_insn_before (gen_rtx_SET (QImode, XEXP (set2, 0),
4407 XEXP (XEXP (set2, 1), 0)),
4408 try_insn);
4409 delete_insn (remove_insn);
4412 if (GET_CODE (XEXP (set2, 0)) == REG)
4414 int reg2_range = GET_MODE_SIZE (GET_MODE (XEXP (set2, 0)));
4415 unsigned int regno2 = REGNO (XEXP (set2, 0));
4417 if (reg2_range == 1
4418 && regno == regno2
4419 && GET_CODE (XEXP (set2, 1)) == CONST_INT)
4421 int iv = INTVAL (XEXP (set2, 1));
4422 if (iv == 0xff)
4423 iv = -1;
4424 if (iv == 1 || iv == -1)
4426 new_insn = gen_rtx_SET (QImode, XEXP (set2, 0),
4427 gen_rtx_PLUS (QImode, XEXP (set2, 0),
4428 GEN_INT (iv)));
4429 new_insn = emit_insn_before (new_insn, try_insn);
4430 delete_insn (try_insn);
4431 try_insn = new_insn;
4433 break;
4436 if ((regno >= regno2) && (regno <= regno2 + reg2_range - 1))
4437 break;
4439 if (GET_CODE (XEXP (set2, 1)) == REG
4440 && REGNO (XEXP (set2, 1)) == regno)
4442 new_insn = emit_insn_before (gen_rtx_SET (QImode,
4443 XEXP (set2, 0),
4444 const0_rtx),
4445 try_insn);
4446 delete_insn (try_insn);
4447 try_insn = new_insn;
4451 if (GET_CODE (XEXP (set2, 0)) == CC0)
4453 if (GET_CODE (XEXP (set2, 1)) == REG
4454 && GET_MODE_SIZE (GET_MODE (XEXP (set2, 1))) == 2
4455 && REGNO (XEXP (set2, 1)) == regno)
4457 new_insn = gen_rtx_SET (VOIDmode, gen_rtx_CC0 (VOIDmode),
4458 gen_rtx_REG(QImode, regno + 1));
4459 new_insn = emit_insn_before (new_insn, try_insn);
4461 else if (GET_CODE (XEXP (set2, 1)) == COMPARE
4462 && GET_CODE (XEXP (XEXP (set2, 1), 0)) == REG
4463 && GET_MODE_SIZE (GET_MODE (XEXP (XEXP (set2, 1), 0))) == 2
4464 && REGNO (XEXP (XEXP (set2, 1), 0)) == regno
4465 && GET_CODE (XEXP (XEXP (set2, 1), 1)) == CONST_INT
4466 && INTVAL (XEXP (XEXP (set2, 1), 1)) >= 0
4467 && INTVAL (XEXP (XEXP (set2, 1), 1)) < 256)
4469 new_insn = gen_rtx_SET (VOIDmode, cc0_rtx,
4470 gen_rtx_COMPARE(QImode,
4471 gen_rtx_REG (QImode,
4472 regno + 1),
4473 XEXP (XEXP (set2, 1),
4474 1)));
4475 new_insn = emit_insn_before (new_insn, try_insn);
4478 /* If we have inserted a replacement for a CC0 setter operation
4479 then we need to delete the old one. */
4480 if (new_insn != NULL_RTX)
4482 delete_insn (try_insn);
4483 try_insn = new_insn;
4485 /* Now as we know that we have just done an unsigned compare
4486 (remember we were zero-extended by the clr!) we also know
4487 that we don't need a signed jump insn. If we find that
4488 our next isns is a signed jump then make it unsigned! */
4489 if (GET_CODE (next_nonnote_insn (try_insn)) == JUMP_INSN)
4491 rtx set3;
4493 try_insn = next_nonnote_insn (try_insn);
4494 set3 = ((GET_CODE (PATTERN (try_insn)) == SET)
4495 ? PATTERN (try_insn) : NULL_RTX);
4496 if (set3 == NULL_RTX)
4497 continue;
4499 /* If we discover that our jump target is only accessible
4500 from here then we can continue our "clr" propagation to
4501 it too! */
4502 if (LABEL_NUSES (JUMP_LABEL (try_insn)) == 1)
4503 mdr_try_propagate_clr_sequence (JUMP_LABEL (try_insn),
4504 regno);
4506 if (GET_CODE (XEXP (set3, 0)) == PC
4507 && GET_CODE (XEXP (set3, 1)) == IF_THEN_ELSE
4508 && (GET_CODE (XEXP (XEXP (set3, 1), 0)) == GT
4509 || GET_CODE (XEXP (XEXP (set3, 1), 0)) == GE
4510 || GET_CODE (XEXP (XEXP (set3, 1), 0)) == LT
4511 || GET_CODE (XEXP (XEXP (set3, 1), 0)) == LE)
4512 && GET_CODE (XEXP (XEXP (XEXP (set3, 1), 0), 0)) == CC0
4513 && (GET_CODE (XEXP (XEXP (XEXP (set3, 1), 0), 1))
4514 == CONST_INT)
4515 && GET_CODE (XEXP (XEXP (set3, 1), 1)) == LABEL_REF
4516 && GET_CODE (XEXP (XEXP (set3, 1), 2)) == PC)
4518 enum rtx_code code;
4519 rtx new_if;
4520 rtx cmp;
4522 /* Replace our old conditional jump with a new one that
4523 does the unsigned form of what was previously a
4524 signed comparison. */
4525 code = GET_CODE (XEXP (XEXP (set3, 1), 0));
4526 cmp = gen_rtx_fmt_ee ((code == GT
4527 ? GTU
4528 : (code == GE
4529 ? GEU
4530 : (code == LT ? LTU : LEU))),
4531 VOIDmode,
4532 XEXP (XEXP (XEXP (set3, 1), 0), 0),
4533 XEXP (XEXP (XEXP (set3, 1), 0),
4534 1));
4535 new_if
4536 = gen_rtx_SET (GET_MODE (set3),
4537 pc_rtx,
4538 gen_rtx_IF_THEN_ELSE
4539 (GET_MODE (XEXP (set3, 1)), cmp,
4540 XEXP (XEXP (set3, 1), 1),
4541 XEXP (XEXP (set3, 1), 2)));
4542 new_insn = emit_jump_insn_before (new_if, try_insn);
4543 LABEL_NUSES (JUMP_LABEL (try_insn))++;
4544 delete_insn (try_insn);
4545 try_insn = new_insn;
4550 else if (GET_CODE (XEXP (set2, 1)) == PLUS
4551 && GET_CODE (XEXP (XEXP (set2, 1), 0)) == REG
4552 && GET_MODE_SIZE (GET_MODE (XEXP (XEXP (set2, 1), 0))) == 2
4553 && REGNO (XEXP (XEXP (set2, 1), 0)) == regno
4554 && (GET_CODE (XEXP (XEXP (set2, 1), 1)) == REG
4555 || GET_CODE (XEXP (XEXP (set2, 1), 1)) == MEM
4556 || GET_CODE (XEXP (XEXP (set2, 1), 1)) == CONST_INT
4557 || GET_CODE (XEXP (XEXP (set2, 1), 1)) == CONST
4558 || GET_CODE (XEXP (XEXP (set2, 1), 1)) == SYMBOL_REF))
4560 rtx extend = gen_rtx_ZERO_EXTEND (HImode,
4561 gen_rtx_REG (QImode, regno + 1));
4562 new_insn = gen_rtx_SET (HImode, XEXP (set2, 0),
4563 gen_rtx_PLUS (HImode, extend,
4564 XEXP (XEXP (set2, 1), 1)));
4565 new_insn = emit_insn_before (new_insn, try_insn);
4566 delete_insn (try_insn);
4567 try_insn = new_insn;
4569 else if (GET_CODE (XEXP (set2, 1)) == PLUS
4570 && GET_CODE (XEXP (XEXP (set2, 1), 1)) == REG
4571 && GET_MODE_SIZE (GET_MODE (XEXP (XEXP (set2, 1), 1))) == 2
4572 && REGNO (XEXP (XEXP (set2, 1), 1)) == regno
4573 && (GET_CODE (XEXP (XEXP (set2, 1), 0)) == REG
4574 || GET_CODE (XEXP (XEXP (set2, 1), 0)) == MEM
4575 || GET_CODE (XEXP (XEXP (set2, 1), 0)) == CONST_INT
4576 || GET_CODE (XEXP (XEXP (set2, 1), 0)) == CONST
4577 || GET_CODE (XEXP (XEXP (set2, 1), 0)) == SYMBOL_REF))
4579 rtx t_src = gen_rtx_PLUS (HImode,
4580 gen_rtx_ZERO_EXTEND (HImode,
4581 gen_rtx_REG (QImode,
4582 regno
4583 + 1)),
4584 XEXP (XEXP (set2, 1), 0));
4585 new_insn = emit_insn_before (gen_rtx_SET (HImode, XEXP (set2, 0),
4586 t_src),
4587 try_insn);
4588 delete_insn (try_insn);
4589 try_insn = new_insn;
4594 /* One of the things that can quite often happen with an 8-bit CPU is that
4595 we end up clearing the MSByte of a 16-bit value. Unfortunately, all too
4596 often gcc doesn't have any way to realize that only half of the value is
4597 useful and ends up doing more work than it should. We scan for such
4598 occurrences here, track them and reduce compare operations to a smaller
4599 size where possible.
4601 Note that this is somewhat different to move propagation as we may
4602 actually change some instruction patterns when we're doing this whereas
4603 move propagation is just about doing a search and replace. */
4605 static void
4606 mdr_try_propagate_clr (first_insn)
4607 rtx first_insn;
4609 rtx insn;
4610 rtx set;
4612 for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
4614 if (GET_CODE (insn) != INSN)
4615 continue;
4617 set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
4618 if (set == NULL_RTX)
4619 continue;
4621 /* Have we found a "clr" instruction? */
4622 if (GET_CODE (XEXP (set, 0)) == REG
4623 && GET_CODE (XEXP (set, 1)) == CONST_INT
4624 && GET_MODE_SIZE (GET_MODE (XEXP (set, 0))) == 1
4625 && INTVAL (XEXP (set, 1)) == 0)
4627 mdr_try_propagate_clr_sequence (insn, REGNO (XEXP (set, 0)));
4631 #endif /* IP2K_MD_REORG_PASS */
4633 /* Look to see if the expression, x, does not make any memory references
4634 via the specified register. This is very conservative and only returns
4635 nonzero if we definitely don't have such a memory ref. */
4637 static int
4638 ip2k_xexp_not_uses_reg_for_mem (rtx x, unsigned int regno)
4640 if (regno & 1)
4641 regno &= 0xfffffffe;
4643 switch (GET_CODE (x))
4645 case REG:
4646 return 1;
4648 case MEM:
4649 if ((GET_CODE (XEXP (x, 0)) == PLUS
4650 && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
4651 && REGNO (XEXP (XEXP (x, 0), 0)) == regno)
4652 || (GET_CODE (XEXP (x, 0)) == REG
4653 && REGNO (XEXP (x, 0)) == regno))
4654 return 0;
4655 else
4656 return 1;
4658 case CONST:
4659 case CONST_INT:
4660 case CONST_DOUBLE:
4661 case SYMBOL_REF:
4662 case LABEL_REF:
4663 case CC0:
4664 case PC:
4665 return 1;
4667 default:
4668 if (GET_RTX_CLASS (GET_CODE (x)) == RTX_BITFIELD_OPS)
4669 return (ip2k_xexp_not_uses_reg_for_mem (XEXP (x, 0), regno)
4670 && ip2k_xexp_not_uses_reg_for_mem (XEXP (x, 1), regno)
4671 && ip2k_xexp_not_uses_reg_for_mem (XEXP (x, 2), regno));
4673 if (BINARY_P (x))
4674 return (ip2k_xexp_not_uses_reg_for_mem (XEXP (x, 0), regno)
4675 && ip2k_xexp_not_uses_reg_for_mem (XEXP (x, 1), regno));
4677 if (UNARY_P (x)
4678 || GET_RTX_CLASS (GET_CODE (x)) == '3')
4679 return ip2k_xexp_not_uses_reg_for_mem (XEXP (x, 0), regno);
4681 return 0;
4685 #ifdef IP2K_MD_REORG_PASS
4686 /* Assist the following function, mdr_try_propagate_move(). */
4688 static void
4689 mdr_try_propagate_move_sequence (first_insn, orig, equiv)
4690 rtx first_insn;
4691 rtx orig;
4692 rtx equiv;
4694 rtx try_insn;
4696 for (try_insn = next_nonnote_insn (first_insn); try_insn;
4697 try_insn = next_nonnote_insn (try_insn))
4699 rtx set;
4700 int range;
4701 rtx new_equiv = NULL_RTX;
4703 if (GET_CODE (try_insn) != JUMP_INSN && GET_CODE (try_insn) != INSN)
4704 break;
4706 set = single_set (try_insn);
4707 if (set == NULL_RTX)
4708 break;
4710 range = MAX (GET_MODE_SIZE (GET_MODE (equiv)),
4711 GET_MODE_SIZE (GET_MODE (XEXP (set, 0))));
4713 if (GET_CODE (equiv) == REG
4714 && REGNO (equiv) == REG_W
4715 && (recog_memoized (try_insn) < 0
4716 || get_attr_clobberw (try_insn) != CLOBBERW_NO)
4717 && (! (GET_CODE (XEXP (set, 0)) == REG
4718 && REGNO (XEXP (set, 0)) == REG_W
4719 && rtx_equal_p (XEXP (set, 1), orig))))
4720 break;
4721 else if (GET_CODE (XEXP (set, 0)) == REG
4722 && (REGNO (XEXP (set, 0)) == REG_SP
4723 || ! ip2k_xexp_not_uses_reg_p (equiv, REGNO (XEXP (set, 0)),
4724 range)
4725 || ! ip2k_xexp_not_uses_reg_p (orig, REGNO (XEXP (set, 0)),
4726 range))
4727 && ! rtx_equal_p (equiv, XEXP (set, 0))
4728 && ! rtx_equal_p (orig, XEXP (set, 0)))
4729 break;
4730 else if (GET_CODE (orig) == REG
4731 && (REGNO (orig) == REG_IPL
4732 || REGNO (orig) == REG_IPH
4733 || REGNO (orig) == REG_DPL
4734 || REGNO (orig) == REG_DPH)
4735 && (! ip2k_xexp_not_uses_reg_for_mem (XEXP (set, 0),
4736 REGNO (orig))
4737 || ! ip2k_xexp_not_uses_reg_for_mem (XEXP (set, 1),
4738 REGNO (orig))))
4739 break;
4740 else if (GET_CODE (XEXP (set, 0)) == MEM
4741 && GET_CODE (equiv) == MEM)
4743 if (! ip2k_xexp_not_uses_reg_p (equiv, REG_SP, 2))
4745 if (! ip2k_xexp_not_uses_reg_p (XEXP (set, 0), REG_SP, 2))
4747 /* We look for a special case of "push" operations screwing
4748 our register equivalence when it's based on a stack slot.
4749 We can track this one and replace the old equivalence
4750 expression with a new one. */
4751 if (GET_CODE (XEXP (XEXP (set, 0), 0)) == POST_DEC
4752 && GET_CODE (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG
4753 && REGNO (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG_SP
4754 && GET_CODE (XEXP (equiv, 0)) == PLUS
4755 && REGNO (XEXP (XEXP (equiv, 0), 0)) == REG_SP)
4757 int md_size = GET_MODE_SIZE (GET_MODE (XEXP (set, 0)));
4758 int new_sp_offs = INTVAL (XEXP (XEXP (equiv, 0), 1))
4759 + md_size;
4761 /* Don't allow an invalid stack pointer offset to be
4762 created. */
4763 if (new_sp_offs > (128 - 2 * md_size))
4764 break;
4766 new_equiv
4767 = gen_rtx_MEM (GET_MODE (equiv),
4768 gen_rtx_PLUS (Pmode,
4769 gen_rtx_REG (HImode ,
4770 REG_SP),
4771 GEN_INT (new_sp_offs)));
4773 else if (! rtx_equal_p (equiv, XEXP (set, 0)))
4775 /* Look at the SP offsets and look for any overlaps. */
4776 int equiv_offs = GET_CODE (XEXP (equiv, 0)) == PLUS
4777 ? INTVAL (XEXP (XEXP (equiv, 0), 1))
4778 : 0;
4779 int set_offs
4780 = (GET_CODE (XEXP (XEXP (set, 0), 0)) == PLUS
4781 ? INTVAL (XEXP (XEXP (XEXP (set, 0), 0), 1))
4782 : 0);
4784 if (abs (equiv_offs - set_offs) < range)
4785 break;
4790 if (! ip2k_xexp_not_uses_reg_p (equiv, REG_IP, 2))
4791 break;
4793 if (! ip2k_xexp_not_uses_reg_p (XEXP (set, 0), REG_DP, 2)
4794 && ! ip2k_xexp_not_uses_reg_p (equiv, REG_DP, 2)
4795 && ! rtx_equal_p (equiv, XEXP (set, 0)))
4797 /* Look at the DP offsets and look for any overlaps. */
4798 int equiv_offs = GET_CODE (XEXP (equiv, 0)) == PLUS
4799 ? INTVAL (XEXP (XEXP (equiv, 0), 1))
4800 : 0;
4801 int set_offs = GET_CODE (XEXP (XEXP (set, 0), 0)) == PLUS
4802 ? INTVAL (XEXP (XEXP (XEXP (set, 0), 0), 1))
4803 : 0;
4805 if (abs (equiv_offs - set_offs) < range)
4806 break;
4810 validate_replace_rtx_subexp (orig, equiv, try_insn, &XEXP (set, 1));
4812 if (rtx_equal_p (equiv, XEXP (set, 0))
4813 || rtx_equal_p (orig, XEXP (set, 0)))
4814 break;
4816 if (new_equiv != NULL_RTX)
4817 equiv = new_equiv;
4821 /* Try propagating move instructions forwards. It may be that we can
4822 replace a register use with an equivalent expression that already
4823 holds the same value and thus allow one or more register loads to
4824 be eliminated. */
4826 static void
4827 mdr_try_propagate_move (first_insn)
4828 rtx first_insn;
4830 rtx insn;
4831 rtx set;
4833 for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
4835 if (GET_CODE (insn) != INSN)
4836 continue;
4838 set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
4839 if (set == NULL_RTX)
4840 continue;
4842 /* Have we found a simple move instruction? */
4843 if (GET_CODE (XEXP (set, 0)) == REG
4844 && (REGNO (XEXP (set, 0)) >= 0x80
4845 || REGNO (XEXP (set, 0)) == REG_DPL
4846 || REGNO (XEXP (set, 0)) == REG_DPH
4847 || REGNO (XEXP (set, 0)) == REG_IPL
4848 || REGNO (XEXP (set, 0)) == REG_IPH)
4849 && ((GET_CODE (XEXP (set, 1)) == REG
4850 && REGNO (XEXP (set, 1)) != REG_SP
4851 && ip2k_xexp_not_uses_reg_p (XEXP (set, 0),
4852 REGNO (XEXP (set, 1)),
4853 GET_MODE_SIZE (GET_MODE (XEXP (set,
4854 0)))))
4855 || (GET_CODE (XEXP (set, 1)) == MEM
4856 && (ip2k_xexp_not_uses_reg_p (XEXP (set, 1), REG_IP, 2)
4857 || GET_MODE (XEXP (set, 1)) == QImode)
4858 && ((REGNO (XEXP (set, 0)) != REG_DPH
4859 && REGNO (XEXP (set, 0)) != REG_DPL)
4860 || ip2k_xexp_not_uses_reg_p (XEXP (set, 1), REG_DP, 2)))
4861 || (GET_CODE (XEXP (set, 1)) == CONST_INT
4862 && (GET_MODE (XEXP (set, 0)) != QImode
4863 || INTVAL (XEXP (set, 1)) != 0))
4864 || GET_CODE (XEXP (set, 1)) == CONST_DOUBLE
4865 || GET_CODE (XEXP (set, 1)) == CONST
4866 || GET_CODE (XEXP (set, 1)) == SYMBOL_REF))
4868 mdr_try_propagate_move_sequence (insn, XEXP (set, 0), XEXP (set, 1));
4873 /* Try to remove redundant instructions. */
4875 static void
4876 mdr_try_remove_redundant_insns (first_insn)
4877 rtx first_insn;
4879 rtx insn;
4881 for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
4883 rtx set;
4884 enum machine_mode mode;
4885 int md_size;
4886 HOST_WIDE_INT pattern;
4887 int i;
4889 if (GET_CODE (insn) != INSN)
4890 continue;
4892 if (GET_CODE (PATTERN (insn)) == CONST_INT)
4894 /* We've found a dummy expression. */
4895 rtx remove_insn = insn;
4896 insn = prev_nonnote_insn (insn);
4897 delete_insn (remove_insn);
4898 continue;
4901 set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
4902 if (set == NULL_RTX)
4903 continue;
4905 mode = GET_MODE (XEXP (set, 0));
4906 md_size = GET_MODE_SIZE (mode);
4907 if ((md_size < 1) || (md_size > 4))
4908 continue;
4910 pattern = 0;
4911 for (i = 0; i < md_size; i++)
4913 pattern <<= 8;
4914 pattern |= 0xff;
4917 if ((GET_CODE (XEXP (set, 1)) == AND
4918 && GET_CODE (XEXP (XEXP (set, 1), 1)) == CONST_INT
4919 && INTVAL (XEXP (XEXP (set, 1), 1)) == pattern)
4920 || ((GET_CODE (XEXP (set, 1)) == IOR
4921 || GET_CODE (XEXP (set, 1)) == XOR)
4922 && GET_CODE (XEXP (XEXP (set, 1), 1)) == CONST_INT
4923 && INTVAL (XEXP (XEXP (set, 1), 1)) == 0x00))
4925 /* We've found an AND with all 1's, an XOR with all 0's or an
4926 IOR with 0's. */
4927 rtx remove_insn = insn;
4929 /* Is it completely redundant or should it become a move insn? */
4930 if (! rtx_equal_p (XEXP (set, 0), XEXP (XEXP (set, 1), 0)))
4932 emit_insn_before (gen_rtx_SET (mode,
4933 XEXP (set, 0),
4934 XEXP (XEXP (set, 1), 0)),
4935 insn);
4938 insn = prev_nonnote_insn(insn);
4939 delete_insn (remove_insn);
4941 else if (GET_CODE (XEXP (set, 1)) == AND
4942 && GET_CODE (XEXP (XEXP (set, 1), 1)) == CONST_INT
4943 && INTVAL (XEXP (XEXP (set, 1), 1)) == 0)
4945 /* We've found an AND with all 0's. */
4946 rtx remove_insn = insn;
4947 insn = emit_insn_before (gen_rtx_SET (mode,
4948 XEXP (set, 0),
4949 XEXP (XEXP (set, 1), 1)),
4950 insn);
4951 delete_insn (remove_insn);
4956 /* Structure used to track jump targets. */
4958 struct we_jump_targets
4960 int target; /* Is this a jump target? */
4961 int reach_count; /* Number of ways we can reach this insn. */
4962 int touch_count; /* Number of times we've touched this insn
4963 during scanning. */
4964 rtx w_equiv; /* WREG-equivalence at this point. */
4967 struct we_jump_targets *ip2k_we_jump_targets;
4969 /* WREG equivalence tracking used within DP reload elimination. */
4971 static int
4972 track_w_reload (insn, w_current, w_current_ok, modifying)
4973 rtx insn;
4974 rtx *w_current;
4975 int w_current_ok;
4976 int modifying;
4978 rtx set;
4980 if (GET_CODE (insn) != INSN)
4982 *w_current = NULL_RTX;
4983 return 1;
4986 set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
4987 if (set == NULL_RTX)
4989 *w_current = NULL_RTX;
4990 return 1;
4993 /* Look for W being modified. If it is, see if it's being changed
4994 to what it already is! */
4995 if (GET_CODE (XEXP (set, 0)) == REG
4996 && REGNO (XEXP (set, 0)) == REG_W
4997 && GET_MODE (XEXP (set, 0)) == QImode)
4999 /* If this is an equivalence we can delete the new set operation. */
5000 if (*w_current != NULL_RTX
5001 && rtx_equal_p (XEXP (set, 1), *w_current))
5003 if (modifying)
5004 delete_insn (insn);
5006 else
5008 *w_current = XEXP (set, 1);
5009 return 1;
5012 else if (recog_memoized (insn) < 0
5013 || get_attr_clobberw (insn) != CLOBBERW_NO)
5015 /* If we clobber W then we've clobbered any equivalences ! */
5016 *w_current = NULL_RTX;
5017 return 1;
5019 else if (! ip2k_xexp_not_uses_reg_p (XEXP (set, 0), REG_SP, 2)
5020 && *w_current != NULL_RTX
5021 && !ip2k_xexp_not_uses_reg_p (*w_current, REG_SP, 2))
5023 /* We look for a special case of "push" operations screwing up the
5024 setting of DP when it's based on the stack. We can track this one
5025 and replace the old expression for DP with a new one. */
5026 if (GET_CODE (XEXP (set, 0)) == MEM
5027 && GET_CODE (XEXP (XEXP (set, 0), 0)) == POST_DEC
5028 && GET_CODE (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG
5029 && REGNO (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG_SP
5030 && GET_CODE (*w_current) == MEM
5031 && GET_CODE (XEXP (*w_current, 0)) == PLUS)
5033 /* XXX - need to ensure that we can track this without going
5034 out of range! */
5035 rtx val = GEN_INT (INTVAL (XEXP (XEXP (*w_current, 0), 1))
5036 + GET_MODE_SIZE (GET_MODE (XEXP (set, 0))));
5037 *w_current
5038 = gen_rtx_MEM (HImode, gen_rtx_PLUS (Pmode,
5039 gen_rtx_REG(HImode, REG_SP),
5040 val));
5041 return 1;
5044 else if (GET_CODE (XEXP (set, 0)) == REG
5045 && *w_current != NULL_RTX
5046 && !ip2k_xexp_not_uses_reg_p (*w_current, REGNO (XEXP (set, 0)),
5047 GET_MODE_SIZE (GET_MODE (XEXP (set
5048 , 0)))))
5050 /* If we've just clobbered all or part of a register reference that we
5051 were sharing for W then we can't share it any more! */
5052 *w_current = NULL_RTX;
5055 return w_current_ok;
5058 /* As part of the machine-dependent reorg we scan moves into w and track them
5059 to see where any are redundant. */
5061 static void
5062 mdr_try_wreg_elim (first_insn)
5063 rtx first_insn;
5065 rtx insn;
5066 struct we_jump_targets *wjt;
5067 rtx w_current;
5068 int incomplete_scan;
5069 int last_incomplete_scan;
5071 ip2k_we_jump_targets
5072 = (struct we_jump_targets *) xcalloc (get_max_uid (),
5073 sizeof (struct we_jump_targets));
5075 /* First we scan to build up a list of all CODE_LABEL insns and we work out
5076 how many different ways we can reach them. */
5077 for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
5079 if (GET_CODE (insn) == CODE_LABEL)
5081 wjt = &ip2k_we_jump_targets[INSN_UID (insn)];
5082 wjt->target = 1;
5083 wjt->reach_count = LABEL_NUSES (insn);
5084 wjt->touch_count = 0;
5085 wjt->w_equiv = NULL_RTX;
5086 if (! prev_nonnote_insn (insn)
5087 || (prev_nonnote_insn (insn)
5088 && GET_CODE (prev_nonnote_insn (insn)) != BARRIER))
5089 wjt->reach_count++;
5093 /* Next we scan all of the ways of reaching the code labels to see
5094 what the WREG register is equivalent to as we reach them. If we find
5095 that they're the same then we keep noting the matched value. We
5096 iterate around this until we reach a convergence on WREG equivalences
5097 at all code labels - we have to be very careful not to be too
5098 optimistic! */
5099 incomplete_scan = -1;
5102 int w_current_ok = 0;
5103 last_incomplete_scan = incomplete_scan;
5104 w_current = NULL_RTX;
5106 for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
5108 /* If we have a code label then we need to see if we already know
5109 what the equivalence is at this point. If we do then we use it
5110 immediately, but if we don't then we have a special case to track
5111 when we hit a fallthrough-edge (label with no barrier preceding
5112 it). Any other accesses to the label must be from jump insns
5113 and so they're handled elsewhere. */
5114 if (GET_CODE (insn) == CODE_LABEL)
5116 wjt = &ip2k_we_jump_targets[INSN_UID (insn)];
5118 /* If we're fully characterized the use the equivalence. */
5119 if (wjt->touch_count == wjt->reach_count)
5121 w_current = wjt->w_equiv;
5122 w_current_ok = 1;
5123 continue;
5126 /* If we have a known equivalence for WREG as we reach the
5127 fallthrough-edge then track this into the code label. */
5128 if (w_current_ok
5129 && (! prev_nonnote_insn (insn)
5130 || (prev_nonnote_insn (insn)
5131 && GET_CODE (prev_nonnote_insn (insn)) != BARRIER)))
5133 if (wjt->touch_count == 0)
5134 wjt->w_equiv = w_current;
5136 if (wjt->touch_count < wjt->reach_count)
5138 wjt->touch_count++;
5139 if (! rtx_equal_p (wjt->w_equiv, w_current))
5141 /* When we definitely know that we can't form an
5142 equivalence for WREG here we must clobber anything
5143 that we'd started to track too. */
5144 wjt->w_equiv = NULL_RTX;
5145 w_current = NULL_RTX;
5146 w_current_ok = 1;
5151 /* If we've not completely characterized this code label then
5152 be cautious and assume that we don't know what WREG is
5153 equivalent to. */
5154 if (wjt->touch_count < wjt->reach_count)
5156 w_current = NULL_RTX;
5157 w_current_ok = 0;
5160 continue;
5163 /* If we've hit a jump insn then we look for either an address
5164 vector (jump table) or for jump label references. */
5165 if (GET_CODE (insn) == JUMP_INSN)
5167 /* Don't attempt to track here if we don't have a known
5168 equivalence for WREG at this point. */
5169 if (w_current_ok)
5171 if (JUMP_LABEL (insn))
5174 = &ip2k_we_jump_targets[INSN_UID (JUMP_LABEL (insn))];
5176 if (wjt->touch_count == 0)
5177 wjt->w_equiv = w_current;
5179 if (wjt->touch_count < wjt->reach_count)
5181 wjt->touch_count++;
5182 if (! rtx_equal_p (wjt->w_equiv, w_current))
5183 wjt->w_equiv = NULL_RTX;
5188 continue;
5191 /* Anything other than a code labal or jump arrives here. We try and
5192 track WREG, but sometimes we might not be able to. */
5193 w_current_ok = track_w_reload (insn, &w_current, w_current_ok, 0);
5196 /* When we're looking to see if we've finished we count the number of
5197 paths through the code labels where we weren't able to definitively
5198 track WREG. This number is used to see if we're converging on a
5199 solution.
5200 If this hits zero then we've fully converged, but if this stays the
5201 same as last time then we probably can't make any further
5202 progress. */
5203 incomplete_scan = 0;
5204 for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
5206 if (GET_CODE (insn) == CODE_LABEL)
5208 wjt = &ip2k_we_jump_targets[INSN_UID (insn)];
5209 if (wjt->touch_count != wjt->reach_count)
5211 incomplete_scan += (wjt->reach_count - wjt->touch_count);
5212 wjt->w_equiv = NULL_RTX;
5213 wjt->touch_count = 0;
5218 while (incomplete_scan && incomplete_scan != last_incomplete_scan);
5220 /* Finally we scan the whole function and run WREG elimination. When we hit
5221 a CODE_LABEL we pick up any stored equivalence since we now know that
5222 every path to this point entered with WREG holding the same thing! If
5223 we subsequently have a reload that matches then we can eliminate it. */
5224 w_current = NULL_RTX;
5225 for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
5227 if (GET_CODE (insn) == JUMP_INSN)
5228 continue;
5230 if (GET_CODE (insn) == CODE_LABEL)
5232 wjt = &ip2k_we_jump_targets[INSN_UID (insn)];
5233 w_current = wjt->w_equiv;
5234 continue;
5237 track_w_reload (insn, &w_current, 1, 1);
5240 free (ip2k_we_jump_targets);
5242 #endif /* IP2K_MD_REORG_PASS */
5244 /* We perform a lot of untangling of the RTL within the reorg pass since
5245 the IP2k requires some really bizarre (and really undesireable) things
5246 to happen in order to guarantee not aborting. This pass causes several
5247 earlier passes to be re-run as it progressively transforms things,
5248 making the subsequent runs continue to win. */
5250 static void
5251 ip2k_reorg (void)
5253 #ifdef IP2K_MD_REORG_PASS
5254 rtx first_insn, insn, set;
5255 #endif
5257 CC_STATUS_INIT;
5259 if (optimize == 0)
5261 ip2k_reorg_completed = 1;
5262 ip2k_reorg_split_dimode = 1;
5263 ip2k_reorg_split_simode = 1;
5264 ip2k_reorg_split_himode = 1;
5265 ip2k_reorg_split_qimode = 1;
5266 ip2k_reorg_merge_qimode = 1;
5267 return;
5269 #ifndef IP2K_MD_REORG_PASS
5270 ip2k_reorg_completed = 1;
5271 ip2k_reorg_split_dimode = 1;
5272 ip2k_reorg_split_simode = 1;
5273 ip2k_reorg_split_himode = 1;
5274 ip2k_reorg_split_qimode = 1;
5275 ip2k_reorg_merge_qimode = 1;
5276 #else
5277 /* All optimizations below must be debugged and enabled one by one.
5278 All of them commented now because of abort in GCC core. */
5280 ip2k_reorg_in_progress = 1;
5282 first_insn = get_insns ();
5284 /* Look for size effects of earlier optimizations - in particular look for
5285 situations where we're saying "use" a register on one hand but immediately
5286 tagging it as "REG_DEAD" at the same time! Seems like a bug in core-gcc
5287 somewhere really but this is what we have to live with! */
5288 for (insn = first_insn; insn; insn = NEXT_INSN (insn))
5290 rtx body;
5292 if (GET_CODE (insn) == CODE_LABEL
5293 || GET_CODE (insn) == NOTE
5294 || GET_CODE (insn) == BARRIER)
5295 continue;
5297 if (!INSN_P (insn))
5298 continue;
5300 body = PATTERN (insn);
5301 if (GET_CODE (body) == USE)
5302 if (GET_CODE (XEXP (body, 0)) == REG)
5304 int reg;
5306 reg = REGNO (XEXP (body, 0));
5307 if (find_regno_note (insn, REG_DEAD, reg))
5309 delete_insn (insn);
5314 /* There's a good chance that since we last did CSE that we've rearranged
5315 things in such a way that another go will win. Do so now! */
5316 reload_cse_regs (first_insn);
5317 find_basic_blocks (first_insn, max_reg_num (), 0);
5318 life_analysis (0, PROP_REG_INFO | PROP_DEATH_NOTES);
5320 /* Look for where absurd things are happening with DP. */
5321 mdr_try_dp_reload_elim (first_insn);
5323 ip2k_reorg_in_progress = 0;
5324 ip2k_reorg_completed = 1;
5326 split_all_insns (0);
5328 reload_cse_regs (first_insn);
5329 find_basic_blocks (first_insn, max_reg_num (), 0);
5330 life_analysis (0, PROP_REG_INFO | PROP_DEATH_NOTES);
5331 if (flag_peephole2)
5332 peephole2_optimize (NULL);
5334 mdr_resequence_xy_yx (first_insn);
5335 mdr_propagate_reg_equivs (first_insn);
5337 /* Look for redundant set instructions. These can occur when we split
5338 instruction patterns and end up with the second half merging with
5339 or being replaced by something that clobbers the first half. */
5340 for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
5342 if (GET_CODE (insn) == INSN)
5344 set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
5345 if ((set != NULL_RTX)
5346 && (GET_CODE (XEXP (set, 0)) == REG)
5347 && (GET_MODE (XEXP (set, 0)) == QImode)
5348 && (find_regno_note (insn, REG_UNUSED, REGNO (XEXP (set, 0)))))
5349 delete_insn (insn);
5353 mdr_try_move_dp_reload (first_insn);
5354 mdr_try_move_pushes (first_insn);
5356 find_basic_blocks (first_insn, max_reg_num (), 0);
5357 life_analysis (0, PROP_FINAL);
5359 mdr_try_propagate_move (first_insn);
5360 mdr_resequence_xy_yx (first_insn);
5362 ip2k_reorg_split_dimode = 1;
5363 split_all_insns (0);
5365 mdr_try_remove_redundant_insns (first_insn);
5367 mdr_try_propagate_move (first_insn);
5369 reload_cse_regs (first_insn);
5370 find_basic_blocks (first_insn, max_reg_num (), 0);
5371 life_analysis (0, PROP_FINAL);
5372 if (flag_peephole2)
5373 peephole2_optimize (NULL);
5375 mdr_try_propagate_move (first_insn);
5377 find_basic_blocks (first_insn, max_reg_num (), 0);
5378 life_analysis (0, PROP_FINAL);
5380 ip2k_reorg_split_simode = 1;
5381 split_all_insns (0);
5383 mdr_try_remove_redundant_insns (first_insn);
5385 mdr_try_propagate_move (first_insn);
5387 reload_cse_regs (first_insn);
5388 find_basic_blocks (first_insn, max_reg_num (), 0);
5389 life_analysis (0, PROP_FINAL);
5390 if (flag_peephole2)
5391 peephole2_optimize (NULL);
5393 mdr_try_propagate_move (first_insn);
5395 find_basic_blocks (first_insn, max_reg_num (), 0);
5396 life_analysis (0, PROP_FINAL);
5398 ip2k_reorg_split_himode = 1;
5399 ip2k_reorg_merge_qimode = 1;
5400 split_all_insns (0);
5402 mdr_try_remove_redundant_insns (first_insn);
5403 mdr_try_propagate_clr (first_insn);
5404 mdr_try_propagate_move (first_insn);
5406 mdr_try_dp_reload_elim (first_insn);
5407 mdr_try_move_dp_reload (first_insn);
5409 rebuild_jump_labels (first_insn);
5411 /* Call to jump_optimize (...) was here, but now I removed it. */
5413 find_basic_blocks (first_insn, max_reg_num (), 0);
5414 life_analysis (0, PROP_FINAL);
5415 if (flag_peephole2)
5416 peephole2_optimize (NULL);
5418 mdr_try_propagate_move (first_insn);
5420 find_basic_blocks (first_insn, max_reg_num (), 0);
5421 life_analysis (0, PROP_FINAL);
5422 mdr_try_remove_redundant_insns (first_insn);
5424 mdr_try_propagate_clr (first_insn);
5425 mdr_try_propagate_move (first_insn);
5427 find_basic_blocks (first_insn, max_reg_num (), 0);
5428 life_analysis (0, PROP_FINAL);
5430 ip2k_reorg_split_qimode = 1;
5431 split_all_insns (0);
5433 mdr_try_wreg_elim (first_insn);
5434 mdr_try_propagate_move (first_insn);
5436 find_basic_blocks (first_insn, max_reg_num (), 0);
5437 life_analysis (0, PROP_FINAL);
5438 #endif
5441 static void
5442 ip2k_init_libfuncs (void)
5444 set_optab_libfunc (smul_optab, SImode, "_mulsi3");
5445 set_optab_libfunc (smul_optab, DImode, "_muldi3");
5446 set_optab_libfunc (cmp_optab, HImode, "_cmphi2");
5447 set_optab_libfunc (cmp_optab, SImode, "_cmpsi2");
5450 /* Returns a bit position if mask contains only a single bit. Returns -1 if
5451 there were zero or more than one set bits. */
5453 find_one_set_bit_p (HOST_WIDE_INT mask)
5455 int i;
5456 unsigned HOST_WIDE_INT n = mask;
5457 for (i = 0; i < 32; i++)
5459 if (n & 0x80000000UL)
5461 if (n & 0x7fffffffUL)
5462 return -1;
5463 else
5464 return 31 - i;
5466 n <<= 1;
5468 return -1;
5471 /* Returns a bit position if mask contains only a single clear bit.
5472 Returns -1 if there were zero or more than one clear bits. */
5474 find_one_clear_bit_p (HOST_WIDE_INT mask)
5476 int i;
5477 unsigned HOST_WIDE_INT n = mask;
5478 for (i = 0; i < 32; i++)
5480 if ((n & 0x80000000UL) == 0UL)
5482 if ((n & 0x7fffffffUL) != 0x7fffffffUL)
5483 return -1;
5484 else
5485 return 31 - i;
5487 n <<= 1;
5488 n |= 1;
5490 return -1;
5494 /* Split a move into two smaller pieces.
5495 MODE indicates the reduced mode. OPERANDS[0] is the original destination
5496 OPERANDS[1] is the original src. The new destinations are
5497 OPERANDS[2] and OPERANDS[4], while the new sources are OPERANDS[3]
5498 and OPERANDS[5]. */
5500 void
5501 ip2k_split_words (enum machine_mode nmode, enum machine_mode omode,
5502 rtx *operands)
5504 rtx dl, dh; /* src/dest pieces. */
5505 rtx sl, sh;
5506 int move_high_first = 0; /* Assume no overlap. */
5507 int pushflag = 0;
5509 switch (GET_CODE (operands[0])) /* DEST */
5511 case SUBREG:
5512 case REG:
5513 if ((GET_CODE (operands[1]) == REG
5514 || GET_CODE (operands[1]) == SUBREG)
5515 && (true_regnum (operands[0]) <= true_regnum (operands[1])
5516 || (true_regnum (operands[1])
5517 + GET_MODE_SIZE (omode) - 1 < true_regnum (operands[0]))))
5518 move_high_first = 1;
5520 if (GET_CODE (operands[0]) == SUBREG)
5522 dl = simplify_gen_subreg (nmode, operands[0], omode,
5523 GET_MODE_SIZE (nmode));
5524 dh = simplify_gen_subreg (nmode, operands[0], omode, 0);
5526 else if (GET_CODE (operands[0]) == REG && ! IS_PSEUDO_P (operands[0]))
5528 int r = REGNO (operands[0]);
5529 dh = gen_rtx_REG (nmode, r);
5530 dl = gen_rtx_REG (nmode, r + HARD_REGNO_NREGS (r, nmode));
5532 else
5534 dh = gen_rtx_SUBREG (nmode, operands[0], 0);
5535 dl = gen_rtx_SUBREG (nmode, operands[0], GET_MODE_SIZE (nmode));
5537 break;
5539 case MEM:
5540 switch (GET_CODE (XEXP (operands[0], 0)))
5542 case POST_INC:
5543 abort ();
5544 case POST_DEC:
5545 dl = dh = gen_rtx_MEM (nmode, XEXP (operands[0], 0));
5546 pushflag = 1;
5547 break;
5548 default:
5549 dl = change_address (operands[0], nmode,
5550 plus_constant (XEXP (operands[0], 0),
5551 GET_MODE_SIZE (nmode)));
5552 dh = gen_rtx_MEM (nmode, XEXP (operands[0], 0));
5554 break;
5555 default:
5556 abort ();
5559 switch (GET_CODE (operands[1]))
5561 case REG:
5562 if (! IS_PSEUDO_P (operands[1]))
5564 int r = REGNO (operands[1]);
5566 sh = gen_rtx_REG (nmode, r);
5567 sl = gen_rtx_REG (nmode, r + HARD_REGNO_NREGS (r, nmode));
5569 else
5571 sh = gen_rtx_SUBREG (nmode, operands[1], 0);
5572 sl = gen_rtx_SUBREG (nmode, operands[1], GET_MODE_SIZE (nmode));
5574 break;
5576 case CONST_DOUBLE:
5577 if (operands[1] == const0_rtx)
5578 sh = sl = const0_rtx;
5579 else
5581 if (GET_MODE (operands[0]) != DImode)
5583 REAL_VALUE_TYPE rv;
5584 long value;
5586 REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
5587 REAL_VALUE_TO_TARGET_SINGLE (rv, value);
5589 sh = gen_int_mode ((value >> 16) & 0xffff, nmode);
5590 sl = gen_int_mode (value & 0xffff, nmode);
5592 else
5594 sh = gen_int_mode (CONST_DOUBLE_HIGH (operands[1]), nmode);
5595 sl = gen_int_mode (CONST_DOUBLE_LOW (operands[1]), nmode);
5598 break;
5600 case CONST_INT:
5601 if (operands[1] == const0_rtx)
5602 sh = sl = const0_rtx;
5603 else
5605 int val = INTVAL (operands[1]);
5606 int vl, vh;
5608 switch (nmode)
5610 case QImode:
5611 vh = (val >> 8) & 0xff;
5612 vl = val & 0xff;
5613 break;
5615 case HImode:
5616 vh = (val >> 16) & 0xffff;
5617 vl = val & 0xffff;
5618 break;
5620 case SImode:
5621 if (val < 0) /* sign extend */
5622 vh = -1;
5623 else
5624 vh = 0;
5625 vl = val; /* Give low 32 bits back. */
5626 break;
5628 default:
5629 abort ();
5632 sl = gen_int_mode (vl, nmode);
5633 sh = gen_int_mode (vh, nmode);
5635 break;
5637 case SUBREG:
5638 sl = simplify_gen_subreg (nmode, operands[1], omode,
5639 GET_MODE_SIZE (nmode));
5640 sh = simplify_gen_subreg (nmode, operands[1], omode, 0);
5641 break;
5643 case MEM:
5644 switch (GET_CODE (XEXP (operands[1], 0)))
5646 case POST_DEC:
5647 case POST_INC:
5648 abort ();
5649 break;
5651 default:
5652 /* Worry about splitting stack pushes. */
5653 if (pushflag && ip2k_address_uses_reg_p (operands[1], REG_SP))
5654 sl = sh = change_address (operands[1], nmode,
5655 plus_constant (XEXP (operands[1], 0),
5656 GET_MODE_SIZE (nmode)));
5657 else
5659 sl = change_address (operands[1], nmode,
5660 plus_constant (XEXP (operands[1], 0),
5661 GET_MODE_SIZE (nmode)));
5662 sh = gen_rtx_MEM (nmode, XEXP (operands[1], 0));
5665 break;
5667 default:
5668 abort ();
5671 if (move_high_first)
5673 operands[2] = dh;
5674 operands[3] = sh;
5675 operands[4] = dl;
5676 operands[5] = sl;
5678 else
5680 operands[2] = dl;
5681 operands[3] = sl;
5682 operands[4] = dh;
5683 operands[5] = sh;
5685 return;
5688 /* Get the low half of an operand. */
5690 ip2k_get_low_half (rtx x, enum machine_mode mode)
5692 switch (GET_CODE (x))
5694 case REG:
5695 if (! IS_PSEUDO_P (x))
5697 unsigned int r = REGNO (x);
5699 return gen_rtx_REG (mode, r + HARD_REGNO_NREGS (r, mode));
5701 else
5703 return gen_rtx_SUBREG (mode, x, GET_MODE_SIZE (mode));
5705 break;
5707 case CONST_DOUBLE:
5708 if (x == const0_rtx)
5709 return const0_rtx;
5710 else
5712 if (mode != SImode)
5714 REAL_VALUE_TYPE rv;
5715 long value;
5717 REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
5718 REAL_VALUE_TO_TARGET_SINGLE (rv, value);
5720 return gen_int_mode (value & 0xffff, mode);
5722 else
5723 return gen_int_mode (CONST_DOUBLE_LOW (x), mode);
5725 break;
5727 case CONST_INT:
5728 if (x == const0_rtx)
5729 return const0_rtx;
5730 else
5732 int val = INTVAL (x);
5733 int vl, vh;
5735 switch (mode)
5737 case QImode:
5738 vh = (val >> 8) & 0xff;
5739 vl = val & 0xff;
5740 break;
5742 case HImode:
5743 vh = (val >> 16) & 0xffff;
5744 vl = val & 0xffff;
5745 break;
5747 case SImode:
5748 if (val < 0) /* sign extend */
5749 vh = -1;
5750 else
5751 vh = 0;
5752 vl = val; /* Give low 32 bits back. */
5753 break;
5755 default:
5756 abort ();
5759 return gen_int_mode (vl, mode);
5761 break;
5763 case SUBREG:
5764 return simplify_gen_subreg (mode, x, GET_MODE (x), GET_MODE_SIZE (mode));
5766 case MEM:
5767 switch (GET_CODE (XEXP (x, 0)))
5769 case POST_DEC:
5770 case POST_INC:
5771 abort ();
5772 break;
5774 default:
5775 return change_address (x, mode,
5776 plus_constant (XEXP (x, 0),
5777 GET_MODE_SIZE (mode)));
5779 break;
5781 default:
5782 abort ();
5784 return NULL_RTX;
5787 /* Get the high half of an operand. */
5789 ip2k_get_high_half (rtx x, enum machine_mode mode)
5791 switch (GET_CODE (x))
5793 case REG:
5794 if (! IS_PSEUDO_P (x))
5796 unsigned int r = REGNO (x);
5798 return gen_rtx_REG (mode, r);
5800 else
5802 return gen_rtx_SUBREG (mode, x, 0);
5804 break;
5806 case CONST_DOUBLE:
5807 if (x == const0_rtx)
5808 return const0_rtx;
5809 else
5811 if (mode != SImode)
5813 REAL_VALUE_TYPE rv;
5814 long value;
5816 REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
5817 REAL_VALUE_TO_TARGET_SINGLE (rv, value);
5819 return gen_int_mode ((value >> 16) & 0xffff, mode);
5821 else
5822 return gen_int_mode (CONST_DOUBLE_HIGH (x), mode);
5824 break;
5826 case CONST_INT:
5827 if (x == const0_rtx)
5828 return const0_rtx;
5829 else
5831 int val = INTVAL (x);
5832 int vl, vh;
5834 switch (mode)
5836 case QImode:
5837 vh = (val >> 8) & 0xff;
5838 vl = val & 0xff;
5839 break;
5841 case HImode:
5842 vh = (val >> 16) & 0xffff;
5843 vl = val & 0xffff;
5844 break;
5846 case SImode:
5847 if (val < 0) /* sign extend */
5848 vh = -1;
5849 else
5850 vh = 0;
5851 vl = val; /* Give low 32 bits back. */
5852 break;
5854 default:
5855 abort ();
5858 return gen_int_mode (vh, mode);
5860 break;
5862 case SUBREG:
5863 return simplify_gen_subreg (mode, x, GET_MODE (x), 0);
5864 break;
5866 case MEM:
5867 switch (GET_CODE (XEXP (x, 0)))
5869 case POST_DEC:
5870 case POST_INC:
5871 abort ();
5872 break;
5874 default:
5875 return change_address (x, mode, plus_constant (XEXP (x, 0), 0));
5877 break;
5879 default:
5880 abort ();
5882 return NULL_RTX;
5885 /* Does address X use register R. Only valid for REG_SP, REG_DP, REG_IP
5886 or REG_FP. */
5889 ip2k_address_uses_reg_p (rtx x, unsigned int r)
5891 if (GET_CODE (x) != MEM)
5892 return 0;
5894 x = XEXP (x, 0);
5896 while (1)
5897 switch (GET_CODE (x))
5899 case POST_DEC:
5900 case POST_INC:
5901 case PRE_DEC:
5902 case PRE_INC:
5903 x = XEXP (x, 0);
5904 break;
5906 case PLUS:
5907 if (ip2k_address_uses_reg_p (XEXP (x, 1), r))
5908 return 1;
5910 x = XEXP (x, 0);
5911 break;
5913 case SUBREG:
5914 /* Ignore subwords. */
5915 x = SUBREG_REG (x);
5916 break;
5918 case REG:
5919 /* Have to consider that r might be LSB of a pointer reg. */
5920 return ((REGNO (x) == r) || (REGNO (x) == (r - 1))) ? 1 : 0;
5922 case MEM:
5923 /* We might be looking at a (mem:BLK (mem (...))) */
5924 x = XEXP (x, 0);
5925 break;
5927 default:
5928 return 0;
5932 /* Does the queried XEXP not use a particular register? If we're certain
5933 that it doesn't then we return TRUE otherwise we assume FALSE. */
5936 ip2k_xexp_not_uses_reg_p (rtx x, unsigned int r, int rsz)
5938 switch (GET_CODE (x))
5940 case REG:
5942 int msz = GET_MODE_SIZE (GET_MODE (x));
5944 return (((REGNO (x) + msz - 1) < r)
5945 || (REGNO (x) > (r + rsz - 1)));
5948 case MEM:
5949 return !ip2k_address_uses_reg_p (x, r);
5951 case LABEL_REF:
5952 case SYMBOL_REF:
5953 case CONST:
5954 case CONST_INT:
5955 case CONST_DOUBLE:
5956 case CC0:
5957 case PC:
5958 return 1;
5960 default:
5961 return 0;
5965 /* Does the queried XEXP not use a particular register? If we're certain
5966 that it doesn't then we return TRUE otherwise we assume FALSE. */
5969 ip2k_composite_xexp_not_uses_reg_p (rtx x, unsigned int r, int rsz)
5971 if (GET_RTX_CLASS (GET_CODE (x)) == RTX_BITFIELD_OPS)
5972 return (ip2k_composite_xexp_not_uses_reg_p (XEXP (x, 0), r, rsz)
5973 && ip2k_composite_xexp_not_uses_reg_p (XEXP (x, 1), r, rsz)
5974 && ip2k_composite_xexp_not_uses_reg_p (XEXP (x, 2), r, rsz));
5976 if (BINARY_P (x))
5977 return (ip2k_composite_xexp_not_uses_reg_p (XEXP (x, 0), r, rsz)
5978 && ip2k_composite_xexp_not_uses_reg_p (XEXP (x, 1), r, rsz));
5980 if (UNARY_P (x)
5981 || GET_RTX_CLASS (GET_CODE (x)) == RTX_TERNARY)
5982 return ip2k_composite_xexp_not_uses_reg_p (XEXP (x, 0), r, rsz);
5984 return ip2k_xexp_not_uses_reg_p (x, r, rsz);
5987 /* Does the queried XEXP not use CC0? If we're certain that
5988 it doesn't then we return TRUE otherwise we assume FALSE. */
5991 ip2k_composite_xexp_not_uses_cc0_p (rtx x)
5993 if (GET_RTX_CLASS (GET_CODE (x)) == RTX_BITFIELD_OPS)
5994 return (ip2k_composite_xexp_not_uses_cc0_p (XEXP (x, 0))
5995 && ip2k_composite_xexp_not_uses_cc0_p (XEXP (x, 1))
5996 && ip2k_composite_xexp_not_uses_cc0_p (XEXP (x, 2)));
5998 if (BINARY_P (x))
5999 return (ip2k_composite_xexp_not_uses_cc0_p (XEXP (x, 0))
6000 && ip2k_composite_xexp_not_uses_cc0_p (XEXP (x, 1)));
6002 if (UNARY_P (x)
6003 || GET_RTX_CLASS (GET_CODE (x)) == RTX_TERNARY)
6004 return ip2k_composite_xexp_not_uses_cc0_p (XEXP (x, 0));
6006 return GET_CODE (x) != CC0;
6010 ip2k_split_dest_operand (rtx x, enum machine_mode mode)
6012 return nonimmediate_operand (x, mode) || push_operand (x, mode);
6016 ip2k_nonptr_operand (rtx x, enum machine_mode mode)
6018 return register_operand (x, mode) && !ip2k_ptr_operand (x, mode);
6021 /* Is X a reference to IP or DP or SP? */
6024 ip2k_ptr_operand (rtx x, enum machine_mode mode)
6027 if (GET_CODE (x) == SUBREG)
6028 x = SUBREG_REG (x);
6030 return (REG_P (x)
6031 && (mode == HImode || mode == VOIDmode)
6032 && (REGNO (x) == REG_IP
6033 || REGNO (x) == REG_DP
6034 || REGNO (x) == REG_SP));
6038 ip2k_sp_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
6041 return REG_P (x) && REGNO (x) == REG_SP;
6045 ip2k_ip_operand (rtx x, enum machine_mode mode)
6048 if (GET_CODE (x) != MEM)
6049 return 0;
6051 x = XEXP (x, 0);
6053 if (GET_CODE (x) == PLUS && XEXP (x, 1) == const0_rtx)
6054 x = XEXP (x, 0);
6056 if (! REG_P (x))
6057 return 0;
6059 if (GET_MODE_SIZE (mode) > 1)
6060 return 0; /* Can't access offset bytes. */
6062 return REGNO (x) == REG_IP;
6065 /* Is X a memory address suitable for SP or DP relative addressing? */
6067 ip2k_short_operand (rtx x, enum machine_mode mode)
6069 int r;
6070 unsigned int offs = 0;
6072 if (! memory_operand (x, mode))
6073 return 0; /* Got to be a memory address. */
6075 x = XEXP (x, 0);
6076 switch (GET_CODE (x))
6078 default:
6079 return 0;
6081 case PLUS:
6082 if (! REG_P (XEXP (x, 0))
6083 || GET_CODE (XEXP (x, 1)) != CONST_INT)
6084 return 0;
6086 offs = INTVAL (XEXP (x, 1));
6088 if (128 <= offs)
6089 return 0;
6091 x = XEXP (x, 0);
6093 /* fall through */
6095 case REG:
6096 if (IS_PSEUDO_P (x))
6097 return 0; /* Optimistic - doesn't work. */
6099 r = REGNO (x);
6101 /* For 'S' constraint, we presume that no IP adjustment
6102 simulation is performed - so only QI mode allows IP to be a
6103 short offset address. All other IP references must be
6104 handled by 'R' constraints. */
6105 if (r == REG_IP && offs == 0 && GET_MODE_SIZE (mode) <= 1)
6106 return 1;
6108 return (r == REG_SP || r == REG_DP);
6113 ip2k_nonsp_reg_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
6115 if (GET_CODE (x) == SUBREG)
6116 x = SUBREG_REG (x);
6118 return (REG_P (x) && REGNO (x) != REG_SP);
6122 ip2k_gen_operand (rtx x, enum machine_mode mode)
6124 return ip2k_short_operand (x, mode)
6125 || (GET_CODE (x) == SUBREG
6126 && REG_P (SUBREG_REG (x)))
6127 || (ip2k_nonsp_reg_operand (x, mode));
6131 ip2k_extra_constraint (rtx x, int c)
6133 switch (c)
6135 case 'S': /* Allow offset in stack frame... */
6136 return ip2k_short_operand (x, GET_MODE (x));
6138 case 'R':
6139 return ip2k_ip_operand (x, GET_MODE (x));
6141 case 'T': /* Constant int or .data address. */
6142 return CONSTANT_P (x) && is_regfile_address (x);
6144 default:
6145 return 0;
6150 ip2k_unary_operator (rtx op, enum machine_mode mode)
6152 return ((mode == VOIDmode || GET_MODE (op) == mode)
6153 && UNARY_P (op));
6157 ip2k_binary_operator (rtx op, enum machine_mode mode)
6159 return ((mode == VOIDmode || GET_MODE (op) == mode)
6160 && ARITHMETIC_P (op));
6164 ip2k_symbol_ref_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
6166 /* We define an IP2k symbol ref to be either a direct reference or one
6167 with a constant offset. */
6168 return (GET_CODE (op) == SYMBOL_REF)
6169 || (GET_CODE (op) == CONST
6170 && GET_CODE (XEXP (op, 0)) == PLUS
6171 && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF);
6175 ip2k_signed_comparison_operator (rtx op, enum machine_mode mode)
6177 return (comparison_operator (op, mode)
6178 && signed_condition (GET_CODE (op)) == GET_CODE (op));
6182 ip2k_unsigned_comparison_operator (rtx op, enum machine_mode mode)
6184 return (comparison_operator (op, mode)
6185 && unsigned_condition (GET_CODE (op)) == GET_CODE (op));
6188 /* Worker function for TARGET_RETURN_IN_MEMORY. */
6190 static bool
6191 ip2k_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
6193 if (TYPE_MODE (type) == BLKmode)
6195 HOST_WIDE_INT size = int_size_in_bytes (type);
6196 return (size == -1 || size > 8);
6198 else
6199 return false;
6202 /* Worker function for TARGET_SETUP_INCOMING_VARARGS. */
6204 static void
6205 ip2k_setup_incoming_varargs (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED,
6206 enum machine_mode mode ATTRIBUTE_UNUSED,
6207 tree type ATTRIBUTE_UNUSED,
6208 int *pretend_arg_size,
6209 int second_time ATTRIBUTE_UNUSED)
6211 *pretend_arg_size = 0;